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

📄 rkf45.c

📁 Runge-Kutta-Fehlberg method
💻 C
📖 第 1 页 / 共 4 页
字号:
//      NEQN, Y(1:NEQN), T, TOUT, RELERR, ABSERR, FLAG.//      In particular, T should initially be the starting point for integration,//      Y should be the value of the initial conditions, and FLAG should //      normally be +1.////    Normally, the user only sets the value of FLAG before the first call, and//    thereafter, the program manages the value.  On the first call, FLAG should//    normally be +1 (or -1 for single step mode.)  On normal return, FLAG will//    have been reset by the program to the value of 2 (or -2 in single //    step mode), and the user can continue to call the routine with that //    value of FLAG.////    (When the input magnitude of FLAG is 1, this indicates to the program //    that it is necessary to do some initialization work.  An input magnitude//    of 2 lets the program know that that initialization can be skipped, //    and that useful information was computed earlier.)////    The routine returns with all the information needed to continue//    the integration.  If the integration reached TOUT, the user need only//    define a new TOUT and call again.  In the one-step integrator//    mode, returning with FLAG = -2, the user must keep in mind that //    each step taken is in the direction of the current TOUT.  Upon //    reaching TOUT, indicated by the output value of FLAG switching to 2,//    the user must define a new TOUT and reset FLAG to -2 to continue //    in the one-step integrator mode.////    In some cases, an error or difficulty occurs during a call.  In that case,//    the output value of FLAG is used to indicate that there is a problem//    that the user must address.  These values include:////    * 3, integration was not completed because the input value of RELERR, the //      relative error tolerance, was too small.  RELERR has been increased //      appropriately for continuing.  If the user accepts the output value of//      RELERR, then simply reset FLAG to 2 and continue.////    * 4, integration was not completed because more than MAXNFE derivative //      evaluations were needed.  This is approximately (MAXNFE/6) steps.//      The user may continue by simply calling again.  The function counter //      will be reset to 0, and another MAXNFE function evaluations are allowed.////    * 5, integration was not completed because the solution vanished, //      making a pure relative error test impossible.  The user must use //      a non-zero ABSERR to continue.  Using the one-step integration mode //      for one step is a good way to proceed.////    * 6, integration was not completed because the requested accuracy //      could not be achieved, even using the smallest allowable stepsize. //      The user must increase the error tolerances ABSERR or RELERR before//      continuing.  It is also necessary to reset FLAG to 2 (or -2 when //      the one-step integration mode is being used).  The occurrence of //      FLAG = 6 indicates a trouble spot.  The solution is changing //      rapidly, or a singularity may be present.  It often is inadvisable //      to continue.////    * 7, it is likely that this routine is inefficient for solving//      this problem.  Too much output is restricting the natural stepsize//      choice.  The user should use the one-step integration mode with //      the stepsize determined by the code.  If the user insists upon //      continuing the integration, reset FLAG to 2 before calling //      again.  Otherwise, execution will be terminated.////    * 8, invalid input parameters, indicates one of the following://      NEQN <= 0;//      T = TOUT and |FLAG| /= 1;//      RELERR < 0 or ABSERR < 0;//      FLAG == 0  or FLAG < -2 or 8 < FLAG.////  Modified:////    27 March 2004////  Author:////    H A Watts and L F Shampine,//    Sandia Laboratories,//    Albuquerque, New Mexico.////  Reference:////    E. Fehlberg,//    Low-order Classical Runge-Kutta Formulas with Stepsize Control,//    NASA Technical Report R-315.////    L F Shampine, H A Watts, S Davenport,//    Solving Non-stiff Ordinary Differential Equations - The State of the Art,//    SIAM Review,//    Volume 18, pages 376-411, 1976.////  Parameters:////    Input, external F, a user-supplied subroutine to evaluate the//    derivatives Y'(T), of the form:////      void f ( double t, double y[], double yp[] )////    Input, int NEQN, the number of equations to be integrated.////    Input/output, double Y[NEQN], the current solution vector at T.////    Input/output, double YP[NEQN], the derivative of the current solution //    vector at T.  The user should not set or alter this information!////    Input/output, double *T, the current value of the independent variable.////    Input, double TOUT, the output point at which solution is desired.  //    TOUT = T is allowed on the first call only, in which case the routine//    returns with FLAG = 2 if continuation is possible.////    Input, double *RELERR, ABSERR, the relative and absolute error tolerances//    for the local error test.  At each step the code requires://      abs ( local error ) <= RELERR * abs ( Y ) + ABSERR//    for each component of the local error and the solution vector Y.//    RELERR cannot be "too small".  If the routine believes RELERR has been//    set too small, it will reset RELERR to an acceptable value and return//    immediately for user action.////    Input, int FLAG, indicator for status of integration. On the first call, //    set FLAG to +1 for normal use, or to -1 for single step mode.  On //    subsequent continuation steps, FLAG should be +2, or -2 for single //    step mode.////    Output, int RKF45_D, indicator for status of integration.  A value of 2 //    or -2 indicates normal progress, while any other value indicates a //    problem that should be addressed.//{# define MAXNFE 3000  static double abserr_save = -1.0E+00;  double ae;  double dt;  double ee;  double eeoet;  double eps;  double esttol;  double et;  double *f1;  double *f2;  double *f3;  double *f4;  double *f5;  static int flag_save = -1000;  static double h = -1.0E+00;  bool hfaild;  double hmin;  int i;  static int init = -1000;  int k;  static int kflag = -1000;  static int kop = -1;  int mflag;  static int nfe = -1;  bool output;  double relerr_min;  static double relerr_save = -1.0E+00;  static double remin = 1.0E-12;  double s;  double scale;  double tol;  double toln;  double ypk;////  Check the input parameters.//  eps = d_epsilon ( );  if ( neqn < 1 )  {    return 8;  }  if ( (*relerr) < 0.0E+00 )  {    return 8;  }  if ( abserr < 0.0E+00 )  {    return 8;  }  if ( flag == 0 || 8 < flag  || flag < -2 )  {    return 8;  }  mflag = abs ( flag );////  Is this a continuation call?//  if ( mflag != 1 )  {    if ( *t == tout && kflag != 3 )    {      return 8;    }////  FLAG = -2 or +2://    if ( mflag == 2 )    {      if ( kflag == 3 )      {        flag = flag_save;        mflag = abs ( flag );      }      else if ( init == 0 )      {        flag = flag_save;      }      else if ( kflag == 4 )      {        nfe = 0;      }      else if ( kflag == 5 && abserr == 0.0E+00 )      {        exit ( 1 );      }      else if ( kflag == 6 && (*relerr) <= relerr_save && abserr <= abserr_save )      {        exit ( 1 );      }    }////  FLAG = 3, 4, 5, 6, 7 or 8.//    else    {      if ( flag == 3 )      {        flag = flag_save;        if ( kflag == 3 )        {          mflag = abs ( flag );        }      }      else if ( flag == 4 )      {        nfe = 0;        flag = flag_save;        if ( kflag == 3 )        {          mflag = abs ( flag );        }      }      else if ( flag == 5 && 0.0E+00 < abserr )      {        flag = flag_save;        if ( kflag == 3 )        {          mflag = abs ( flag );        }      }////  Integration cannot be continued because the user did not respond to//  the instructions pertaining to FLAG = 5, 6, 7 or 8.//      else      {        exit ( 1 );      }    }  }////  Save the input value of FLAG.  //  Set the continuation flag KFLAG for subsequent input checking.//  flag_save = flag;  kflag = 0;////  Save RELERR and ABSERR for checking input on subsequent calls.//  relerr_save = (*relerr);  abserr_save = abserr;////  Restrict the relative error tolerance to be at least ////    2*EPS+REMIN ////  to avoid limiting precision difficulties arising from impossible //  accuracy requests.//  relerr_min = 2.0E+00 * d_epsilon ( ) + remin;////  Is the relative error tolerance too small?//  if ( (*relerr) < relerr_min )  {    (*relerr) = relerr_min;    kflag = 3;    return 3;  }  dt = tout - *t;////  Initialization:////  Set the initialization completion indicator, INIT;//  set the indicator for too many output points, KOP;//  evaluate the initial derivatives//  set the counter for function evaluations, NFE;//  estimate the starting stepsize.//  f1 = new double[neqn];  f2 = new double[neqn];  f3 = new double[neqn];  f4 = new double[neqn];  f5 = new double[neqn];  if ( mflag == 1 )  {    init = 0;    kop = 0;    f ( *t, y, yp );    nfe = 1;    if ( *t == tout )    {      return 2;    }  }  if ( init == 0 )  {    init = 1;    h = fabs ( dt );    toln = 0.0E+00;    for ( k = 0; k < neqn; k++ )    {      tol = (*relerr) * fabs ( y[k] ) + abserr;      if ( 0.0E+00 < tol )      {        toln = tol;        ypk = fabs ( yp[k] );        if ( tol < ypk * pow ( h, 5 ) )        {          h = pow ( ( tol / ypk ), 0.2E+00 );        }      }    }    if ( toln <= 0.0E+00 )    {      h = 0.0E+00;    }    h = d_max ( h, 26.0E+00 * eps * d_max ( fabs ( *t ), fabs ( dt ) ) );    if ( flag < 0 )    {      flag_save = -2;    }    else    {      flag_save = 2;    }  }////  Set stepsize for integration in the direction from T to TOUT.//  h =  d_sign ( dt ) * fabs ( h );////  Test to see if too may output points are being requested.//  if ( 2.0E+00 * fabs ( dt ) <= fabs ( h ) )  {    kop = kop + 1;  }////  Unnecessary frequency of output.//  if ( kop == 100 )  {    kop = 0;    delete [] f1;    delete [] f2;    delete [] f3;    delete [] f4;    delete [] f5;    return 7;  }////  If we are too close to the output point, then simply extrapolate and return.//  if ( fabs ( dt ) <= 26.0E+00 * eps * fabs ( *t ) )  {    *t = tout;    for ( i = 0; i < neqn; i++ )    {      y[i] = y[i] + dt * yp[i];    }    f ( *t, y, yp );    nfe = nfe + 1;    delete [] f1;    delete [] f2;    delete [] f3;    delete [] f4;    delete [] f5;    return 2;  }////  Initialize the output point indicator.//  output = false;////  To avoid premature underflow in the error tolerance function,//  scale the error tolerances.//  scale = 2.0E+00 / (*relerr);  ae = scale * abserr;////  Step by step integration.//  for ( ; ; )  {    hfaild = false;////  Set the smallest allowable stepsize.//    hmin = 26.0E+00 * eps * fabs ( *t );////  Adjust the stepsize if necessary to hit the output point.////  Look ahead two steps to avoid drastic changes in the stepsize and//  thus lessen the impact of output points on the code.//    dt = tout - *t;    if ( 2.0E+00 * fabs ( h ) <= fabs ( dt ) )    {    }    else////  Will the next successful step complete the integration to the output point?//    {      if ( fabs ( dt ) <= fabs ( h ) )      {        output = true;        h = dt;      }      else      {        h = 0.5E+00 * dt;      }    }////  Here begins the core integrator for taking a single step.////  The tolerances have been scaled to avoid premature underflow in//  computing the error tolerance function ET.//  To avoid problems with zero crossings, relative error is measured//  using the average of the magnitudes of the solution at the//  beginning and end of a step.//  The error estimate formula has been grouped to control loss of//  significance.////  To distinguish the various arguments, H is not permitted//  to become smaller than 26 units of roundoff in T.//  Practical limits on the change in the stepsize are enforced to//  smooth the stepsize selection process and to avoid excessive//  chattering on problems having discontinuities.//  To prevent unnecessary failures, the code uses 9/10 the stepsize//  it estimates will succeed.////  After a step failure, the stepsize is not allowed to increase for//  the next attempted step.  This makes the code more efficient on//  problems having discontinuities and more effective in general//  since local extrapolation is being used and extra caution seems//  warranted.////  Test the number of derivative function evaluations.//  If okay, try to advance the integration from T to T+H.//    for ( ; ; )    {////  Have we done too much work?//      if ( MAXNFE < nfe )      {        kflag = 4;        delete [] f1;        delete [] f2;        delete [] f3;        delete [] f4;        delete [] f5;        return 4;      }//

⌨️ 快捷键说明

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