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

QualityControlCashKarpMover.cpp

Go to the documentation of this file.
00001 // QualityControlCashKarpMover.cpp: implementation of the QualityControlCashKarpMover class.
00002 //
00004 
00005 #include "QualityControlCashKarpMover.h"
00006 
00008 // Parameters for 5th order step
00010 
00011 const double CQualityControlCashKarpMover::m_scdA[6] = {
00012         0.0, 0.2, 0.3, 0.6, 1.0, 0.875  };
00013 
00014 const double CQualityControlCashKarpMover::m_scdB[6][5] = {
00015                 { 0.0,                 0.0,                  0.0,                        0.0,                           0.0                     },
00016                 { 1.0/5.0,                 0.0,              0.0,                        0.0,                           0.0                     },
00017                 { 3.0/40.0,                9.0/40.0,     0.0,                    0.0,                           0.0                     },
00018                 { 3.0/10.0,               -9.0/10.0,     6.0/5.0,            0.0,                               0.0                     },
00019                 {-11.0/54.0,       5.0/2.0,         -70.0/27.0,      35.0/27.0,                 0.0                     },
00020                 { 1631.0/55296.0,  175.0/512.0,  575.0/13824.0,  44275.0/110592.0,  253.0/4096.0}  };
00021 
00022 const double CQualityControlCashKarpMover::m_scdC[6] = {
00023         37.0/378.0, 0.0, 250.0/621.0, 125.0/594.0, 0.0, 512.0/1771.0 };
00024 
00025 const double CQualityControlCashKarpMover::m_scdCStar[6] = {            
00026         2825.0/27648.0, 0.0, 18575.0/48384.0, 13525.0/55296.0, 277.0/14336.0, 0.25  };
00027 
00028 const double CQualityControlCashKarpMover::m_scdERRCON = 1.89e-04;
00029 
00030 const double CQualityControlCashKarpMover::m_scdPGROW = -0.2;
00031 
00032 const double CQualityControlCashKarpMover::m_scdPSHRINK = -0.25;
00033 
00034 const double CQualityControlCashKarpMover::m_scdSAFETY = 0.9;
00035 
00036 const double CQualityControlCashKarpMover::m_scdTINY = 1.0e-30;
00037 
00039 // Construction/Destruction
00041 
00042 CQualityControlCashKarpMover::CQualityControlCashKarpMover(double frequency, double stepSize, double eps)
00043 :CDifferentialEquationMover(frequency,stepSize)
00044 {
00045         m_dLastStep = stepSize;
00046         m_dNextStep = stepSize;
00047         m_dInitialStepSize = stepSize;
00048         m_dEps = eps;
00049 }
00050 
00051 CQualityControlCashKarpMover::~CQualityControlCashKarpMover()
00052 
00053 {
00054         
00055 }
00056 
00057 
00058 void CQualityControlCashKarpMover::Move(double xInitial, double xFinal, ReactionNetwork *pReactionNetwork)
00059 {
00060         int i;
00061         // do a couple of checks on the integration interval
00062         double xInterval = xFinal-xInitial;
00063         // set the member pointer equal to the pointer passed in
00064         m_pReactionNetwork = pReactionNetwork;
00065         // if there's no moving to be done and xI = xF = integer, take data there
00066         if(this->MoveTimeIsZero(xInterval)) 
00067         {
00068                 if(xInitial > (int) xInitial)
00069                 {
00070                 }
00071                 else
00072                 {
00073                         m_iCount = (int) xInitial;
00074                         m_iCount++;
00075                         Notify();
00076                 }
00077                 // take a data point 
00078                 return;
00079         }
00080         if(m_dInitialStepSize > xInterval) {m_dInitialStepSize = xInterval;}
00081 
00082         m_dTime = xInitial;
00083         double nextTime;
00084         // set up the count variable
00085         m_iCount = (int) xInitial;
00086         m_iCount++;
00087         nextTime = m_iCount;
00088 
00089         m_dStepSize = m_dInitialStepSize;
00090         m_dLastStep = m_dInitialStepSize;
00091         m_dNextStep = m_dInitialStepSize;
00092         
00093         int nChem = m_pReactionNetwork->GetNumberOfChemicals();
00094         double *chem = new double[nChem];
00095         double *dChemdt = new double[nChem];
00096         m_pdScale = new double[nChem];
00097         m_pdError = new double[nChem];
00098 
00099         // fill chem[] with starting chemical concentrations
00100         for(i = 0; i < nChem; i++)
00101         {
00102                 chem[i] = m_pReactionNetwork->GetChemical(i)->GetAmount();
00103         }
00104 
00105         while(m_dTime < xFinal)
00106         {
00107                 // run until xFinal or nextTime (nextTime might be > xFinal)
00108                 while( m_dTime < __min(xFinal,nextTime) )
00109                 {
00110                         // get initial derivatives
00111                         ComputeDerivatives(chem,dChemdt);
00112                         // compute scaling vector
00113                         // __max is to ensure chemicals that start at ~ 0 don't get
00114                         // huge scaling factors, which screws up the stepper
00115                         for(i = 0; i < nChem; i++)
00116                         {
00117                                 m_pdScale[i] = fabs(chem[i]) + fabs(m_dStepSize*dChemdt[i]) + m_scdTINY;
00118                         }
00119                         
00120                         // don't run over - nextTime might be > xFinal
00121                         if( (((m_dTime + m_dNextStep) - nextTime) > 0.0) || (((m_dTime + m_dNextStep) - xFinal) > 0.0) )        
00122                         {
00123                                 m_dNextStep = __min(nextTime-m_dTime,xFinal-m_dTime);
00124                         }
00125 
00126                         // call the stepper
00127                         Stepper(nChem,chem,dChemdt);
00128 
00129                         
00130                         // ensure synchrony with chem and network
00131                         for(int i = 0; i < nChem; i++)
00132                         {
00133                                 m_pReactionNetwork->GetChemical(i)->SetAmount(chem[i]);
00134                         }
00135                         
00136                         // record largest/smallest/numsteps info
00137                         if(m_dLastStep < this->GetMinStepSize()) {this->SetMinStepSize(m_dLastStep);}
00138                         if(m_dLastStep > this->GetMaxStepSize()) {this->SetMaxStepSize(m_dLastStep);}
00139                         this->IncrementTotalSteps();
00140                 }
00141                 
00142                 if(m_dTime == nextTime)
00143                 {
00144                         m_iCount++;
00145                         Notify();
00146                         nextTime += 1.0;
00147                 }
00148         }
00149 
00150         delete [] chem;
00151         delete [] dChemdt;
00152         delete [] m_pdScale;
00153         delete [] m_pdError;
00154 }
00155 
00157 // The stepper adjusts the stepsize according to the error and takes
00158 // a single 5th order Cash-Karp step
00160 
00161 void CQualityControlCashKarpMover::Stepper(int nRHS, double *y, double *dydt)
00162 {
00163         int i;
00164         double *yTemp = new double[nRHS];
00165         double maxError;
00166         
00167         m_dStepSize = m_dNextStep;
00168 
00169         while(1)
00170         {
00171                 for(i = 0; i < nRHS; i++)
00172                 {
00173                         yTemp[i] = y[i];
00174                 }
00175                 
00176                 // try a step
00177                 CashKarpStep(nRHS,yTemp,dydt);
00178                 // evaluate accuracy
00179                 maxError = 0.0;
00180                 for(i = 0; i < nRHS; i++)
00181                 {
00182                         maxError = __max(maxError,fabs(m_pdError[i]/m_pdScale[i]));
00183                 }
00184                 maxError = maxError/m_dEps;
00185 
00186                 // step successful; break out
00187                 if(maxError <= 1.0) {break;}
00188                 // step unsuccessful, make stepsize smaller
00189                 double tempStep = m_scdSAFETY*m_dStepSize*pow(maxError,m_scdPSHRINK);
00190                 
00191                 if(m_dStepSize >= 0.0)
00192                 {
00193                         m_dStepSize = __max(tempStep,0.1*m_dStepSize);
00194                 }
00195                 else
00196                 {
00197                         m_dStepSize = __min(tempStep,0.1*m_dStepSize);
00198                 }
00199                 if((m_dTime + m_dStepSize) == m_dTime)
00200                 {
00201                         // step extremely tiny, should throw an exception
00202                         cout << "Stepsize too small in QualityControlCashKarpMover::Stepper()" << endl;
00203                         exit(1);
00204                 }
00205         }
00206         // we accepted the step, so m_dLastStep gets updated
00207         m_dLastStep = m_dStepSize;
00208         if(maxError > m_scdERRCON) 
00209         {
00210                 m_dNextStep = m_scdSAFETY*m_dStepSize*pow(maxError,m_scdPGROW);
00211         }
00212         else 
00213         {
00214                 m_dNextStep = 5.0*m_dStepSize;
00215         }
00216         // increment m_dTime
00217         m_dTime += m_dLastStep;
00218         // accept the solution
00219         for(int i = 0; i < nRHS; i++)
00220         {
00221                 y[i] = yTemp[i];
00222         }
00223 
00224         delete [] yTemp;
00225 }
00226 
00228 // Takes one 5th order Runge-Kutta-Fehlberg step using parameters 
00229 // from Cash and Karp.  The new solution is returned in y[].  The 
00230 // error in the solution is estimated as the difference between 4th
00231 // and 5th order methods.
00233 
00234 void CQualityControlCashKarpMover::CashKarpStep(int nRHS, double *y, double *dydt)
00235 {
00236         int i;
00237         double *dy2 = new double[nRHS];
00238         double *dy3 = new double[nRHS];
00239         double *dy4 = new double[nRHS];
00240         double *dy5 = new double[nRHS];
00241         double *dy6 = new double[nRHS];
00242         double *yTemp = new double[nRHS];
00243 
00244         // first step
00245         for(i = 0; i < nRHS; i++)
00246         {
00247                 yTemp[i] = y[i] + m_scdB[1][0]*m_dStepSize*dydt[i];
00248         }
00249         ComputeDerivatives(yTemp,dy2);
00250         
00251         // second step
00252         for(i = 0; i < nRHS; i++)
00253         {
00254                 yTemp[i] = y[i] + m_dStepSize*(m_scdB[2][0]*dydt[i] + m_scdB[2][1]*dy2[i]);
00255         }
00256         ComputeDerivatives(yTemp,dy3);
00257 
00258         // third step
00259         for(i = 0; i < nRHS; i++)
00260         {
00261                 yTemp[i] = y[i] + m_dStepSize*(m_scdB[3][0]*dydt[i] + m_scdB[3][1]*dy2[i] + m_scdB[3][2]*dy3[i]);
00262         }
00263         ComputeDerivatives(yTemp,dy4);
00264 
00265         // fourth step
00266         for(i = 0; i < nRHS; i++)
00267         {
00268                 yTemp[i] = y[i] + m_dStepSize*(m_scdB[4][0]*dydt[i] + m_scdB[4][1]*dy2[i] + m_scdB[4][2]*dy3[i] + m_scdB[4][3]*dy4[i]);
00269         }
00270         ComputeDerivatives(yTemp,dy5);
00271 
00272         // fifth step
00273         for(i = 0; i < nRHS; i++)
00274         {
00275                 yTemp[i] = y[i] + m_dStepSize*(m_scdB[5][0]*dydt[i] + m_scdB[5][1]*dy2[i] + m_scdB[5][2]*dy3[i] + m_scdB[5][3]*dy4[i] + m_scdB[5][4]*dy5[i]);
00276         }
00277         ComputeDerivatives(yTemp,dy6);
00278 
00279         // form new solution and estimate error
00280         // error estimate is the difference between 4th and 5th order methods
00281         for(i = 0; i < nRHS; i++)
00282         {
00283                 y[i] = y[i] + m_dStepSize*(m_scdC[0]*dydt[i] + m_scdC[2]*dy3[i] + m_scdC[3]*dy4[i] + m_scdC[5]*dy6[i]);
00284                 // this form of the calculation is to try to minimize roundoff error
00285                 double temp1 = m_dStepSize*(m_scdC[0] - m_scdCStar[0])*dydt[i];
00286                 double temp2 = m_dStepSize*(m_scdC[2] - m_scdCStar[2])*dy3[i];
00287                 double temp3 = m_dStepSize*(m_scdC[3] - m_scdCStar[3])*dy4[i];
00288                 double temp4 = m_dStepSize*(m_scdC[4] - m_scdCStar[4])*dy5[i];
00289                 double temp5 = m_dStepSize*(m_scdC[5] - m_scdCStar[5])*dy6[i];
00290                 m_pdError[i] = temp1 + temp2 + temp3 + temp4 + temp5;
00291         }
00292         
00293 
00294         delete [] dy2;
00295         delete [] dy3;
00296         delete [] dy4;
00297         delete [] dy5;
00298         delete [] dy6;
00299         delete [] yTemp;
00300 }

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