⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rke.c

📁 su 的源代码库
💻 C
字号:
/* Copyright (c) Colorado School of Mines, 2006.*//* All rights reserved.                       */#include "par.h"#include "rke.h"/*********************** self documentation **********************//************************************************************************RKE - integrate a system of n-first order ordinary differential equations      from a given time to a target time using the Runge Kutta method,      enhanced the the error checking algorithm created by R. England (1969).*************************************************************************Credits :Ordinary differential equation solver, Runge-Kutta-England technique.Made available for SU by the author's permission, 1 Sept 2006.Copyright 1988: Fran鏾is Pinard <pinard@iro.umontreal.ca>, 1988.*************************************************************************Reference: England, R. (1969), Error estimates for Runge-Kutta type solutions tosystems of ordinary differential equations,The Computer Journal, Volume 12, Issue 2, pp. 166-170Abstract:Means of estimating the truncation error of Runge-Kutta type methods are considered. A number of existing processes have various disadvantages, giving a valid estimate only for certain types of equation. The conditions are stated for a process to give a valid estimate when applied to a general system of differential equations, and a number of fifth order estimates are proposed for a fourth order Runge-Kutta type method. Some numerical tests are applied to these processes, which suggest their superiority over Merson's process. *************************************************************************Author: Fran鏾is Pinard <pinard@iro.umontreal.ca>, 1988.Modified: John Stockwell, Center for Wave Phenomena (CWP),	  Colorado School of Mines (CSM), August 2004, for	  integration into the CWP/SU Seismic Unix package. Some 	  stylistic changes were made, and some SU routines were          incorporated into the modified code.*************************************************************************//**************** end self doc ********************************//* Initialize a new system of equations. */rke_variablesrke_init (int number, int (*routine)())	/*************************************************************************rke_init - initiate a newly allocated reentrancy block for RKE routines.**************************************************************************Input:number		Number of simultaneous equationsroutine		function representing system of equations being solved **************************************************************************Author:	Fran鏾is Pinard <pinard@iro.umontreal.ca>, 1988.***************************************************************************/{	rke_variables var;	var = (rke_variables) malloc (sizeof (struct struct_rke_variables));	var->n_equations = number;	var->eval_routine = routine;	var->minimum_step = RKE_STEP_MIN;	var->maximum_step = RKE_STEP_MAX;	var->current_step = 1.0;	var->error_slope = RKE_ERR_SLOPE_INIT; 	var->error_bias = RKE_ERR_BIAS_INIT;	var->accepted_steps = 0;	var->rejected_steps = 0;	return var;}/* Terminate a set of equations. */voidrke_term(rke_variables var)/**************************************************************************rke_term - terminate a set of equations in a call to RKE routines***************************************************************************Author:	Fran鏾is Pinard <pinard@iro.umontreal.ca>, 1988.***************************************************************************//* Reentrency block */{	free (var);}/* Main routine of the module, ODE solver. *//* Perform a consistent move of time in the system. */int				/* !0 if success */rke_solve (rke_variables var, double *time,		double *variables,double aimed_time)/***************************************************************************rke_variables var		 Reentrency blockdouble *time			 Current value of timedouble variables[]		 Current variablesdouble aimed_time		 Value of time which is aimed for****************************************************************************Author:	Fran鏾is Pinard <pinard@iro.umontreal.ca>, 1988.***************************************************************************/{	double whole_step;		/* Signed integration step size */	double quarter_step;		/* 0.25 * whole_step */	double half_step;		/* 0.50 * whole_step */	double three_quarter_step;	/* 0.75 * whole_step */	double estimated_error;	/* Error as estimated by England method */	double allowable_error;	/* Maximum error that user permits */	int within_tolerance;	/* Allowable error has not been passed */	int all_errors_small;	/* All errors within 2% of tolerances */	int length_of_array;	/* Length of temporary arrays, is bytes */	int k;			/* Index in various arrays */	double *dp=NULL, *vt=NULL, *v=NULL, *d=NULL;	double *a1=NULL, *a2=NULL, *a3=NULL, *a4=NULL;	double *a5=NULL, *a6=NULL, *a7=NULL;	/* Allocate the work arrays. */	length_of_array = var->n_equations * sizeof (double);	dp = (double *) ealloc1double (length_of_array);	vt = (double *) ealloc1double (length_of_array);	v	= (double *) ealloc1double (length_of_array);	d	= (double *) ealloc1double (length_of_array);	a1 = (double *) ealloc1double (length_of_array);	a2 = (double *) ealloc1double (length_of_array);	a3 = (double *) ealloc1double (length_of_array);	a4 = (double *) ealloc1double (length_of_array);	a5 = (double *) ealloc1double (length_of_array);	a6 = (double *) ealloc1double (length_of_array);	a7 = (double *) ealloc1double (length_of_array);	/* The integration will continue if a minimum step could bring the	 * system closer to the time that is aimed for, even if we have to	 * overshoot it a little.         */	while (2 * fabs(aimed_time - *time) > var->minimum_step) {		/* Evaluate initial step size and direction. */		if((whole_step = aimed_time - *time) > 0.0) {			if(whole_step > var->current_step)				whole_step = var->current_step;		} else {			if(whole_step < - var->current_step)				whole_step = - var->current_step;		}		/* Evaluate initial differentials. */		if(! (*var->eval_routine) (*time, variables, dp))						return 0;		/* Loop integrating at this time point until integration 		 * error is within tolerances.	In any case, adjust 		 * integration step size.		 */		do {	 		/* Calculate various step sizes. */			quarter_step = 0.25 * whole_step;			half_step = quarter_step + quarter_step;			three_quarter_step = half_step + quarter_step;			/* Perform a partial computation for one step of			 * Runge-Kutta 4th order integration, as far as			 * necessary to chain it to England method for 			 * estimating integration errors.			 */			for(k=0; k<var->n_equations; ++k) {				a1[k] = half_step * dp[k];				v[k] = variables[k] + 0.5*a1[k];			}			if(!(*var->eval_routine)				(*time + quarter_step, v, d)) return 0;			for(k=0; k< var->n_equations; ++k) {				a2[k] = half_step * d[k];				v[k] = variables[k] + 0.25 * (a1[k] + a2[k]);			}			if(! (*var->eval_routine)					(*time + quarter_step, v, d)) return 0;			for(k=0; k< var->n_equations; ++k) {				a3[k] = half_step * d[k];				v[k] = variables[k] + (-a2[k] + a3[k] + a3[k]);			}			if(! (*var->eval_routine)				(*time + half_step, v, d)) return 0;			for(k=0; k< var->n_equations; ++k) {				a4[k] = half_step * d[k];				vt[k] = variables[k]					+ (a1[k] + 4.0*a3[k] + a4[k])/6.0;			}			if(! (*var->eval_routine)				(*time + half_step, vt, d)) return 0;			for(k=0; k< var->n_equations; ++k) {				a5[k] = half_step * d[k];				v[k] = vt[k] + 0.5*a5[k];			}			if(! (*var->eval_routine)				(*time + three_quarter_step, v, d)) return 0;			for(k=0; k< var->n_equations; ++k) {				a6[k] = half_step * d[k];				v[k] = vt[k] + 0.25*(a5[k] + a6[k]);			}			if(! (*var->eval_routine)				(*time + three_quarter_step, v, d)) return 0;			for(k=0; k< var->n_equations; ++k) {				a7[k] = half_step * d[k];				v[k] = variables[k]					+ (-a1[k] - 96.0*a2[k] 						+ 92.0*a3[k] - 121.0*a4[k]						+ 144.0*a5[k] + 6.0*a6[k] 						- 12.0*a7[k])/6.0;			}			/* Perform England error analysis 			 *  on partial integration.			 */			if(!(*var->eval_routine)				(*time + whole_step, v, d)) return 0;			within_tolerance = 1;			all_errors_small = 1;			for(k=0; k< var->n_equations; ++k) {				estimated_error = fabs((-a1[k]								+ 4.0*a3[k]							+ 17.0*a4[k]							- 23.0*a5[k]							+ 4.0*a7[k] 							- half_step*d[k])/90.0);				allowable_error = fabs(whole_step)							*(var->error_slope*fabs (vt[k]) + var->error_bias);				if(estimated_error > allowable_error) {					within_tolerance = 0;					break;				} else if(estimated_error>0.02*allowable_error){						all_errors_small = 0;				}			}		if(within_tolerance) {			++var->accepted_steps;			/* Complete the Runge-Kutta step and return values. */			for(k=0; k< var->n_equations; ++k) {				v[k] = vt[k] + (-a6[k] + a7[k] + a7[k]);			}			if(!(*var->eval_routine)				(*time + whole_step, v, d)) return 0;			*time+=whole_step;			for(k=0; k<var->n_equations; ++k) {				variables[k] = vt[k] 						+ (a5[k] + 4.0*a7[k] 							+ half_step*d[k])/ 6.0;			}			/* Increment step size if desirable. */			if(all_errors_small				&& fabs(whole_step) == var->current_step) {			  if(2 * var->current_step > var->maximum_step) {				  var->current_step = var->maximum_step;			  } else { 				var->current_step *= 2;			  }			}		} else {			++var->rejected_steps;			/* Decrement step size if possible. */			if (fabs (whole_step) > var->minimum_step) {                  		if (var->current_step < 2 * var->minimum_step)                    		  var->current_step = var->minimum_step;                  		else                    		  var->current_step *= 0.5;                  		if (aimed_time > *time)                    		  whole_step = var->current_step;                  		else                    		  whole_step = - var->current_step;                	} else {                		return 0;       /* Convergence failed */			}            	}		} while (!within_tolerance);	}	return 1;			/* Convergence succeeded */	}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -