Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

NmOdeInt.cxx

Go to the documentation of this file.
00001 
00002 // $Id: NmOdeInt.cxx,v 1.4 2005/03/03 21:48:29 musser Exp $
00003 //
00004 // A class to implement the integrations of ordinary differential
00005 // equations.
00006 //
00007 // messier@huhepl.harvard.edu
00009 #include "NumericalMethods/NmOdeInt.h"
00010 #include <cassert>
00011 #include <cmath>
00012 #include "MessageService/MsgService.h"
00013 #include "NumericalMethods/NmOdeDerivFunc.h"
00014 #include "NumericalMethods/NmOdeStepperRKCK.h"
00015 CVSID("$Id: NmOdeInt.cxx,v 1.4 2005/03/03 21:48:29 musser Exp $");
00016 
00017 //......................................................................
00018 
00019 NmOdeInt::NmOdeInt() :
00020   fXstart(0.0),
00021   fXend(0.0),
00022   fNvar(0),     // added by RWH
00023   fYstart(0),
00024   fYend(0),
00025   fYscale(0),
00026   fNmaxSteps(10000),
00027   fNok(0),
00028   fNbad(0),
00029   fEps(1.0e-6),
00030   fStepSize(0.0),
00031   fMinStepSize(0.0),
00032   fDerivs(0),
00033   fStepper(new NmOdeStepperRKCK), // Delete in d'ctor
00034   fDefaultStepper(true),
00035   fUseDefaultScales(true)
00036 { }
00037 
00038 //......................................................................
00039 
00040 NmOdeInt::NmOdeInt(const double* y1, 
00041                    int n, 
00042                    double x1, 
00043                    double x2,
00044                    double acc, 
00045                    double step, 
00046                    double minStep,
00047                    NmOdeDerivFunc& f) :
00048   fXstart(x1),
00049   fXend(x2),
00050   fNvar(n),
00051   fYstart(new double[fNvar]), // delete in d'ctor
00052   fYend(  new double[fNvar]), // delete in d'ctor
00053   fYscale(new double[fNvar]), // delete in d'ctor
00054   fNmaxSteps(10000),
00055   fNok(0),
00056   fNbad(0),
00057   fEps(acc),
00058   fStepSize(step),
00059   fMinStepSize(minStep),
00060   fDerivs(&f),
00061   fStepper(new NmOdeStepperRKCK), // delete in d'ctor
00062   fDefaultStepper(true),
00063   fUseDefaultScales(true)
00064 {
00065 //======================================================================
00066 // Purpose: Build the class to perform the intergral
00067 //
00068 // Inputs: y1 - vector of initial dependent variable values
00069 //          n - size of y1 vector, 
00070 //         x1 - lower integration limit
00071 //         x2 - upper integration limit
00072 //        acc - fractional accurancy requested 
00073 //       step - initial guess at a good step size for the interval
00074 //    minStep - smallest step allowed on the interval
00075 //          f - functor used to compute derivatives
00076 //======================================================================
00077   // Initialize the start and end variable vectors
00078   for (int i=0; i<fNvar; ++i) {
00079     fYstart[i] = y1[i];
00080     fYend[i]   = 0.0;
00081   }
00082 }
00083 
00084 //......................................................................
00085 
00086 NmOdeInt::~NmOdeInt() 
00087 {
00088 //======================================================================
00089 // Purpose: Free memory allocated by class
00090 //======================================================================
00091   delete []fYstart; fYstart = 0;
00092   delete []fYend;   fYend = 0;
00093   delete []fYscale; fYscale = 0;
00094   if (fDefaultStepper) { delete fStepper; fStepper = 0; }
00095 }
00096 
00097 //......................................................................
00098 
00099 void NmOdeInt::SetMaxSteps(int n) 
00100 {
00101 //======================================================================
00102 // Purpose: Set the maximum number of step to attempt in the interval
00103 //======================================================================
00104   assert(n>1);
00105   fNmaxSteps = n;
00106 }
00107 
00108 //......................................................................
00109 
00110 void NmOdeInt::SetNvar(int n) 
00111 {
00112 //======================================================================
00113 // Purpose: Change the size of the vector of dependent variables
00114 //======================================================================
00115   assert(n>0);
00116   // If the initial and final states have been allocated, delete them
00117   if (fYstart) { delete []fYstart; fYstart = 0; }
00118   if (fYend)   { delete []fYend;   fYend   = 0; }
00119   if (fYscale) { delete []fYscale; fYscale = 0; }
00120   fNvar = n;
00121   fYstart = new double[fNvar];
00122   fYend   = new double[fNvar];
00123   fYscale = new double[fNvar];
00124 }
00125 
00126 //......................................................................
00127 
00128 void NmOdeInt::SetInitialCondition(const double* y) 
00129 {
00130 //======================================================================
00131 // Purpose: Set the starting values for the dependent variables
00132 //
00133 // Inputs: y - the vector of variable values
00134 //======================================================================
00135   assert(fNvar>0);
00136   for (int i=0; i<fNvar; ++i) fYstart[i] = y[i];
00137 }
00138 
00139 //......................................................................
00140 
00141 void NmOdeInt::SetScales(const double* s) 
00142 {
00143 //======================================================================
00144 // Purpose: Set the typical sizes of the dependent variables
00145 //
00146 // Inputs: s - vector of typical sizes for the dependent variables
00147 //======================================================================
00148   assert(fNvar>0);
00149   for (int i=0; i<fNvar; ++i) fYscale[i] = s[i];
00150   fUseDefaultScales = false;
00151 }
00152 
00153 //......................................................................
00154 
00155 void NmOdeInt::SetStepper(NmOdeStepper& s) 
00156 {
00157 //======================================================================
00158 // Purpose: Change the stepper class to use to perform the integral
00159 //
00160 // Inputs: s - the new stepper to use
00161 //======================================================================
00162   if (fStepper && fDefaultStepper) { 
00163     delete fStepper; 
00164     fStepper = 0; 
00165   }
00166   fDefaultStepper = false; // No longer the owner of the stepper
00167   fStepper = &s;
00168 }
00169 
00170 //......................................................................
00171 
00172 bool NmOdeInt::Integrate(double* yFinal) 
00173 {
00174 //======================================================================
00175 // Purpose: Perform the integral
00176 //
00177 // Output: yFinal - the final values of the dependent variables
00178 //
00179 // Returns: true  - success
00180 //          false - failure
00181 //======================================================================
00182   register int nstp; // Loop variable
00183   register int i;    // Loop variable
00184 //unused:  double xSave;
00185   double x;
00186   double hNext;
00187   double hDid;
00188   double h;
00189   double*    y = new double[fNvar]; 
00190   double* dydx = new double[fNvar];
00191   static const double tiny = 1.0e-30;
00192 
00193   // Check and set initial conditions and provide some defaults
00194   fNok = fNbad = 0;
00195   if (fEps == 0.0) fEps = 1.0e-4;
00196   if (fStepSize == 0.0) 
00197     fStepSize = sqrt(fEps)*fabs(fXstart-fXend);
00198   
00199   x = fXstart;
00200   if (fXend>fXstart) h =  fStepSize;
00201   else               h = -fStepSize;
00202 
00203   for (i=0; i<fNvar; ++i) y[i] = fYstart[i];
00204   for (nstp = 0; nstp<fNmaxSteps; ++nstp) {
00205     (*fDerivs)(x,y,dydx);
00206     
00207     // Set the scale for the variables
00208     if (fUseDefaultScales) {
00209       for (i=0; i<fNvar; ++i) {
00210         fYscale[i] = fabs(y[i])+fabs(dydx[i]*h)+tiny;
00211       }
00212     }
00213     
00214     // Check if step size over shoots end point
00215     if ((x+h-fXend)*(x+h-fXstart) > 0.0) h = fXend-x;
00216     // Take the step
00217     fStepper->Step(y, dydx, fNvar, &x, h, fEps, fYscale, 
00218                    &hDid, &hNext, *fDerivs);
00219     if (hDid == h) fNok++;
00220     else           fNbad++;
00221     
00222     // Check if we're done
00223     if (this->Done(x,y)) {
00224       // Finish up, free memory, and return
00225       for (i=0; i<fNvar; ++i) {
00226         yFinal[i] = fYend[i] = y[i];
00227       }
00228       delete []y;    y = 0;    // deallocate temporary arrays
00229       delete []dydx; dydx = 0; // deallocate temporary arrays
00230 
00231       return true;
00232     }
00233     if (fabs(hNext)<=fMinStepSize) {
00234       MSG("Nm",Msg::kWarning) << 
00235         "Step size too small (" << hNext<< "<" << fMinStepSize << "\n";
00236       h = fMinStepSize;
00237     }
00238     else {
00239       h = hNext;
00240     }
00241   }
00242   // Only get here when we've exceeded the max. number of steps
00243   for (i=0; i<fNvar; ++i) {
00244     yFinal[i] = fYend[i] = y[i];
00245   }
00246   delete []y;    y = 0;    // deallocate temporary arrays
00247   delete []dydx; dydx = 0; // deallocate temporary arrays
00248   MSG("Nm",Msg::kError) 
00249     << "Maximum number of steps ("<< fNmaxSteps <<") exceeded\n";
00250   return false;
00251 }
00252 
00253 //......................................................................
00254 
00255 bool NmOdeInt::Done(double x, const double* y) 
00256 {
00257 //======================================================================
00258 // Purpose: Test if the integral is complete
00259 //
00260 // Inputs: x - value of integration variable
00261 //       y - values of dependent variables
00262 //
00263 // Returns: true  - done
00264 //          false - not done
00265 //======================================================================
00266   return ((x-fXend)*(fXend-fXstart)>=0.0);
00267 }
00268 

Generated on Mon Feb 15 11:07:05 2010 for loon by  doxygen 1.3.9.1