00001
00002
00004
00005 #include "QualityControlRK2TMover.h"
00006
00008
00009
00010
00011
00012
00013
00014
00015
00017
00018
00019
00020
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
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;
00045 }
00046
00047 CQualityControlRK2TMover::~CQualityControlRK2TMover()
00048 {
00049
00050 }
00051
00052 void CQualityControlRK2TMover::Move(double xInitial, double xFinal, ReactionNetwork *pReactionNetwork)
00053 {
00054
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
00063 m_pReactionNetwork = pReactionNetwork;
00064 m_dTime = xInitial;
00065
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
00105 try
00106 {
00107 Stepper(nChem,chem,dChemdt);
00108 }
00109 catch(std::runtime_error error)
00110 {
00111 cout << error.what() << endl;
00112 }
00113
00114
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
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
00138
00139
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
00164 m_dStepSize = 0.5*m_dStepSize;
00165 RungeKuttaStep(nRHS,yTemp1,dydtTemp1);
00166 RungeKuttaStep(nRHS,yTemp1,dydtTemp1);
00167
00168
00169 m_dStepSize = 2.0*m_dStepSize;
00170
00171 if ((m_dTime + m_dStepSize) == m_dTime)
00172 {
00173
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
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
00218
00219 delete [] yTemp1;
00220 delete [] yTemp2;
00221 delete [] dydtTemp1;
00222 delete [] dydtTemp2;
00223 }
00224