Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

QualityControlRK2TMover.cpp

Go to the documentation of this file.
00001 // QualityControlRK2TMover.cpp: implementation of the QualityControlRK2TMover class.
00002 //
00004 
00005 #include "QualityControlRK2TMover.h"
00006 
00008 // Variable stepsize RK routine - this one is for the second order 
00009 // trapezoidal step, but changing a few names and deriving the class
00010 // from a different base mover makes it a different order routine. 
00011 // A factory (design pattern) is the more elegant way to have the 
00012 // same hierarchy with less code bloat, but I'm not going to bother
00013 // with that now. Error is computed by taking the step all at once or 
00014 // in two half steps and computing the difference in the answer.
00015 //                                                                                              K.S.B., 3/20/01
00017 
00018 // NOTE - ERRCON is essentially the error tolerance; this routine
00019 // is not designed to be terribly accurate (it's only 2nd order 
00020 // anyway) 
00021 const double CQualityControlRK2TMover::m_scdERRCON = 1.0e-3;
00022 
00023 const double CQualityControlRK2TMover::m_scdFCOR = 0.06666;
00024 
00025 const double CQualityControlRK2TMover::m_scdPGROW = -0.2;
00026 
00027 const double CQualityControlRK2TMover::m_scdPSHRINK = -0.25;
00028 
00029 const double CQualityControlRK2TMover::m_scdSAFETY = 0.9;
00030 
00031 const double CQualityControlRK2TMover::m_scdTINY = 1.0e-30;
00032 
00033 
00035 // Construction/Destruction
00037 
00038 CQualityControlRK2TMover::CQualityControlRK2TMover(double frequency, double stepSize, double eps) 
00039 :CRK2TMover(frequency, stepSize)
00040 {
00041         this->m_dEps = eps;
00042         m_dLastStep = stepSize;
00043         m_dNextStep = stepSize;
00044         m_dInitialStepSize = stepSize;  // Each "move" starts with initialStepSize
00045 }
00046 
00047 CQualityControlRK2TMover::~CQualityControlRK2TMover()
00048 {
00049 
00050 }
00051 
00052 void CQualityControlRK2TMover::Move(double xInitial, double xFinal, ReactionNetwork *pReactionNetwork)
00053 {
00054         // do a couple of checks on the integration interval
00055         double xInterval = xFinal-xInitial;
00056         if(m_dInitialStepSize > xInterval) {m_dInitialStepSize = xInterval;}
00057         if(this->MoveTimeIsZero(xInterval)) {return;}
00058         this->SetMinStepSize(xInterval);
00059         this->SetMaxStepSize(0.0);
00060         m_iTotalStepsTaken = 0;
00061 
00062         // set the member pointer to the network pointer passed in
00063         m_pReactionNetwork = pReactionNetwork;
00064         m_dTime = xInitial;
00065         // may be unsafe if xInitial has a fractional part!
00066         m_iCount = (int) xInitial;
00067         
00068         m_dStepSize = m_dLastStep = m_dNextStep = m_dInitialStepSize;
00069         double nextTime = m_dTime;
00070         int nChem = m_pReactionNetwork->GetNumberOfChemicals();
00071         double *chem = new double[nChem];
00072         double *dChemdt = new double[nChem];
00073         m_pdScale = new double[nChem];
00074 
00075         for (int cNum = 0; cNum < nChem; cNum++)
00076         {
00077                 chem[cNum] = m_pReactionNetwork->GetChemical(cNum)->GetAmount();
00078         }       
00079 
00080         while(m_dTime < xFinal)
00081         {
00082                 while(m_dTime < nextTime)
00083                 {
00084                         ComputeDerivatives(chem,dChemdt);                               
00085                 
00086                         for (int i = 0; i < nChem; i++)
00087                         {
00088                                 double scal1 = fabs(chem[i]) + fabs(dChemdt[i]*m_dNextStep) + m_scdTINY;
00089                                 double scal2 = 1.0;
00090                                 if(scal1 > scal2)
00091                                 {
00092                                         m_pdScale[i] = scal1;
00093                                 }
00094                                 else
00095                                 {
00096                                         m_pdScale[i] = scal2;
00097                                 }
00098                         }
00099                         if( ((m_dTime + m_dNextStep) - nextTime) > 0.0 )        
00100                         {
00101                                 m_dNextStep = nextTime-m_dTime;
00102                         }
00103 
00104                         // take a step
00105                         try
00106                         {
00107                                 Stepper(nChem,chem,dChemdt);    
00108                         }
00109                         catch(std::runtime_error error)
00110                         {
00111                                 cout << error.what() << endl;
00112                         }
00113                         
00114                         // record largest/smallest/numsteps info
00115                         if(m_dLastStep < this->GetMinStepSize()) {this->SetMinStepSize(m_dLastStep);}
00116                         if(m_dLastStep > this->GetMaxStepSize()) {this->SetMaxStepSize(m_dLastStep);}
00117                         this->IncrementTotalSteps();
00118 
00119                 }
00120                 // ensure synchrony with chem and network
00121                 for (int cNum = 0; cNum < nChem; cNum++)
00122                 {
00123                         m_pReactionNetwork->GetChemical(cNum)->SetAmount(chem[cNum]);
00124                 }
00125                 
00126                 m_iCount++;
00127                 Notify();
00128                 nextTime += 1.0;
00129         }
00130         
00131         delete [] chem;
00132         delete [] dChemdt;
00133         delete [] m_pdScale;
00134 }
00135 
00137 // Takes one quality-controlled Runge-Kutta step.  
00138 // The output (new concentrations after the move) are stored in 
00139 // y[] on exit. 
00141 
00142 void CQualityControlRK2TMover::Stepper(int nRHS, double *y, double *dydt)
00143 {
00144         int i;
00145         double maxError;
00146         
00147         double *dydtTemp1 = new double[nRHS];
00148         double *dydtTemp2 = new double[nRHS];
00149         double *yTemp1 = new double[nRHS];
00150         double *yTemp2 = new double[nRHS];
00151 
00152         m_dStepSize = m_dNextStep;
00153 
00154         while(1)
00155         {
00156                 for(i = 0; i < nRHS; i++)
00157                 {
00158                         yTemp1[i] = y[i];
00159                         yTemp2[i] = y[i];
00160                         dydtTemp1[i] = dydt[i];
00161                         dydtTemp2[i] = dydt[i];
00162                 }
00163                 // cut stepSize in half and take two mini-steps
00164                 m_dStepSize = 0.5*m_dStepSize;
00165                 RungeKuttaStep(nRHS,yTemp1,dydtTemp1);
00166                 RungeKuttaStep(nRHS,yTemp1,dydtTemp1);
00167                 
00168                 // undo halving of stepSize
00169                 m_dStepSize = 2.0*m_dStepSize;
00170 
00171                 if ((m_dTime + m_dStepSize) == m_dTime) 
00172                 {
00173                         // need to throw exception
00174                         cout << "Step size too small in routine RKQC" << endl;
00175                         exit(1);
00176                 }
00177                 
00178                 RungeKuttaStep(nRHS,yTemp2,dydtTemp2);
00179                 
00180                 maxError = 0.0;
00181                 for (i = 0; i < nRHS; i++)
00182                 {       
00183                         yTemp2[i] = yTemp1[i] - yTemp2[i];
00184                         double temp = fabs(yTemp2[i]/m_pdScale[i]);
00185                         if(maxError < temp) 
00186                         {
00187                                 maxError = temp;
00188                         }
00189                 }
00190                 maxError = maxError/m_dEps;
00191                 if(maxError <= 1.0)
00192                 {
00193                         m_dLastStep = m_dStepSize;
00194                         if(maxError > m_scdERRCON)
00195                         {
00196                                 m_dNextStep = m_scdSAFETY*m_dStepSize*pow(maxError,m_scdPGROW);
00197                         }
00198                         else
00199                         {
00200                                 m_dNextStep = 4.0*m_dStepSize;
00201                         }
00202                         break;
00203                 }
00204 
00205                 m_dStepSize=m_scdSAFETY*m_dStepSize*pow(maxError,m_scdPSHRINK);
00206         }
00207 
00208         // break out of while loop; step accepted
00209         
00210         m_dTime += m_dLastStep;
00211 
00212         for(int i = 0; i < nRHS; i++)
00213         {
00214                 y[i] = yTemp1[i] + yTemp2[i]*m_scdFCOR;
00215         }
00216         
00217         // free memory
00218 
00219         delete [] yTemp1;
00220         delete [] yTemp2;
00221         delete [] dydtTemp1;
00222         delete [] dydtTemp2;
00223 }
00224 

Generated on Mon Nov 3 09:38:09 2003 by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002