00001
00002
00004
00005 #include "QualityControlRungeKuttaMover.h"
00006
00007
00008 const double CQualityControlRungeKuttaMover::m_scdERRCON = 6.0e-4;
00009
00010 const double CQualityControlRungeKuttaMover::m_scdFCOR = 0.06666;
00011
00012 const double CQualityControlRungeKuttaMover::m_scdPGROW = -0.2;
00013
00014 const double CQualityControlRungeKuttaMover::m_scdPSHRINK = -0.25;
00015
00016 const double CQualityControlRungeKuttaMover::m_scdSAFETY = 0.9;
00017
00018 const double CQualityControlRungeKuttaMover::m_scdTINY = 1.0e-30;
00019
00020
00022
00024
00025 CQualityControlRungeKuttaMover::CQualityControlRungeKuttaMover(double frequency, double stepSize, double eps)
00026 :CRK4Mover(frequency, stepSize)
00027 {
00028 this->m_dEps = eps;
00029 m_dLastStep = stepSize;
00030 m_dNextStep = stepSize;
00031 m_dInitialStepSize = stepSize;
00032 }
00033
00034 CQualityControlRungeKuttaMover::~CQualityControlRungeKuttaMover()
00035 {
00036
00037 }
00038
00039 void CQualityControlRungeKuttaMover::ResetStepSize()
00040 {
00041 this->m_dInitialStepSize = m_dDefaultStepSize;
00042 }
00043
00044 double CQualityControlRungeKuttaMover::GetStepSize() const
00045 {
00046 return m_dInitialStepSize;
00047 }
00048
00049 void CQualityControlRungeKuttaMover::SetStepSize(double newSize)
00050 {
00051 this->m_dInitialStepSize = newSize;
00052 }
00053
00054 void CQualityControlRungeKuttaMover::Move(double xInitial, double xFinal, ReactionNetwork *pReactionNetwork)
00055 {
00056
00057 double xInterval = xFinal-xInitial;
00058 if(this->MoveTimeIsZero(xInterval)) {return;}
00059 if(m_dInitialStepSize > xInterval) {m_dInitialStepSize = xInterval;}
00060
00061 double increment;
00062 if(xInterval < 1.0){increment = xInterval;}
00063 else{increment = 1.0;}
00064
00065
00066 m_pReactionNetwork = pReactionNetwork;
00067 m_dTime = xInitial;
00068
00069 m_iCount = (int) xInitial;
00070
00071 m_dStepSize = m_dLastStep = m_dNextStep = m_dInitialStepSize;
00072 double nextTime = m_dTime;
00073 int nChem = m_pReactionNetwork->GetNumberOfChemicals();
00074 double *chem = new double[nChem];
00075 double *dChemdt = new double[nChem];
00076 m_pdScale = new double[nChem];
00077 double minStep = 0.1*m_dStepSize;
00078
00079 for (int cNum = 0; cNum < nChem; cNum++)
00080 {
00081 chem[cNum] = m_pReactionNetwork->GetChemical(cNum)->GetAmount();
00082 }
00083
00084 while(m_dTime < xFinal)
00085 {
00086 while(m_dTime < nextTime)
00087 {
00088 ComputeDerivatives(chem,dChemdt);
00089
00090 for (int i = 0; i < nChem; i++)
00091 {
00092 double scal1 = fabs(chem[i]) + fabs(dChemdt[i]*m_dNextStep) + m_scdTINY;
00093 double scal2 = 1.0;
00094 if(scal1 > scal2)
00095 {
00096 m_pdScale[i] = scal1;
00097 }
00098 else
00099 {
00100 m_pdScale[i] = scal2;
00101 }
00102 }
00103 if( ((m_dTime + m_dNextStep) - nextTime) > 0.0 )
00104 {
00105 m_dNextStep = nextTime-m_dTime;
00106 }
00107
00108
00109 Stepper(nChem,chem,dChemdt);
00110
00111 }
00112
00113 for (int cNum = 0; cNum < nChem; cNum++)
00114 {
00115 m_pReactionNetwork->GetChemical(cNum)->SetAmount(chem[cNum]);
00116 }
00117
00118 m_iCount++;
00119 Notify();
00120 nextTime += increment;
00121 }
00122
00123 delete [] chem;
00124 delete [] dChemdt;
00125 delete [] m_pdScale;
00126 }
00127
00129
00130
00131
00133
00134 void CQualityControlRungeKuttaMover::Stepper(int nRHS, double *y, double *dydt)
00135 {
00136 int i;
00137 double maxError;
00138
00139 double *dydtTemp1 = new double[nRHS];
00140 double *dydtTemp2 = new double[nRHS];
00141 double *yTemp1 = new double[nRHS];
00142 double *yTemp2 = new double[nRHS];
00143
00144 m_dStepSize = m_dNextStep;
00145
00146 while(1)
00147 {
00148 for(i = 0; i < nRHS; i++)
00149 {
00150 yTemp1[i] = y[i];
00151 yTemp2[i] = y[i];
00152 dydtTemp1[i] = dydt[i];
00153 dydtTemp2[i] = dydt[i];
00154 }
00155
00156 m_dStepSize = 0.5*m_dStepSize;
00157 FourthOrderStep(nRHS,yTemp1,dydtTemp1);
00158 ComputeDerivatives(yTemp1,dydtTemp1);
00159 FourthOrderStep(nRHS,yTemp1,dydtTemp1);
00160
00161
00162 m_dStepSize = 2.0*m_dStepSize;
00163
00164 if ((m_dTime + m_dStepSize) == m_dTime)
00165 {
00166
00167 cout << "Step size too small in routine RKQC" << endl;
00168 exit(1);
00169 }
00170
00171 FourthOrderStep(nRHS,yTemp2,dydtTemp2);
00172
00173 maxError = 0.0;
00174 for (i = 0; i < nRHS; i++)
00175 {
00176 yTemp2[i] = yTemp1[i] - yTemp2[i];
00177 double temp = fabs(yTemp2[i]/m_pdScale[i]);
00178 if(maxError < temp)
00179 {
00180 maxError = temp;
00181 }
00182 }
00183 maxError = maxError/m_dEps;
00184 if(maxError <= 1.0)
00185 {
00186 m_dLastStep = m_dStepSize;
00187 if(maxError > m_scdERRCON)
00188 {
00189 m_dNextStep = m_scdSAFETY*m_dStepSize*pow(maxError,m_scdPGROW);
00190 }
00191 else
00192 {
00193 m_dNextStep = 4.0*m_dStepSize;
00194 }
00195 break;
00196 }
00197
00198 m_dStepSize=m_scdSAFETY*m_dStepSize*pow(maxError,m_scdPSHRINK);
00199 }
00200
00201
00202
00203 m_dTime += m_dLastStep;
00204
00205 for(int i = 0; i < nRHS; i++)
00206 {
00207 y[i] = yTemp1[i] + yTemp2[i]*m_scdFCOR;
00208 }
00209
00210
00211
00212 delete [] yTemp1;
00213 delete [] yTemp2;
00214 delete [] dydtTemp1;
00215 delete [] dydtTemp2;
00216 }
00217