00001
00002
00004
00005 #include "RK2ExplicitEulerHybridMover.h"
00006
00008
00009
00010
00011
00012
00014
00016
00017
00019
00020 const double CRK2ExplicitEulerHybridMover::m_scdAlpha=0.74;
00021
00023
00025
00026 CRK2ExplicitEulerHybridMover::CRK2ExplicitEulerHybridMover(double tolerance, double stepSize)
00027 :CDifferentialEquationMover(1.0, stepSize)
00028 {
00029 m_dEps = tolerance;
00030 }
00031
00032 CRK2ExplicitEulerHybridMover::~CRK2ExplicitEulerHybridMover()
00033 {
00034
00035 }
00036
00037 void CRK2ExplicitEulerHybridMover::Move(double xInitial, double xFinal, ReactionNetwork *pReactionNetwork)
00038 {
00039
00040 double xInterval = xFinal-xInitial;
00041 if(this->MoveTimeIsZero(xInterval)) {return;}
00042 if(m_dStepSize > xInterval) {m_dStepSize = xInterval;}
00043
00044
00045 this->m_pReactionNetwork = pReactionNetwork;
00046 m_dTime = xInitial;
00047
00048 m_iCount = (int) xInitial;
00049 double nextTime = m_dTime;
00050
00051 int nChem = m_pReactionNetwork->GetNumberOfChemicals();
00052 double *chem = new double[nChem];
00053 double *dChemdt = new double[nChem];
00054 m_pdLocalError = new double[nChem];
00055
00056
00057 for(int cNum = 0; cNum < nChem; cNum++)
00058 {
00059 chem[cNum] = m_pReactionNetwork->GetChemical(cNum)->GetAmount();
00060 }
00061
00062 while(m_dTime < xFinal)
00063 {
00064 while(m_dTime < nextTime)
00065 {
00066
00067 if((m_dTime + m_dStepSize) == m_dTime)
00068 {
00069 cout << "ERROR: Stepsize too small in RK2/Euler mover." << endl;
00070 exit(1);
00071 }
00072
00073 if( ((m_dTime + m_dStepSize) - nextTime) > 0.0)
00074 {
00075 m_dStepSize = nextTime - m_dTime;
00076 }
00077
00078
00079 HybridStep(nChem,chem,dChemdt);
00080 m_dTime += m_dStepSize;
00081
00082 m_dStepSize = m_dStepSize*SetStepScale(nChem);
00083 }
00084
00085 for (int cNum = 0; cNum < nChem; cNum++)
00086 {
00087 m_pReactionNetwork->GetChemical(cNum)->SetAmount(chem[cNum]);
00088 }
00089
00090 m_iCount++;
00091 Notify();
00092 nextTime += 1.0;
00093 }
00094
00095 delete [] chem;
00096 delete [] dChemdt;
00097 delete [] m_pdLocalError;
00098 }
00099
00100 void CRK2ExplicitEulerHybridMover::HybridStep(int nRHS, double *y, double *dydt)
00101 {
00102 int i;
00103 double *yEuler = new double[nRHS];
00104 double *yRK2 = new double[nRHS];
00105 double *dydtx = new double[nRHS];
00106 double *dydtxph = new double[nRHS];
00107
00108 double halfStep = 0.5*m_dStepSize;
00109
00110
00111 ComputeDerivatives(y,dydtx);
00112 for(i = 0; i < nRHS; i++)
00113 {
00114 yEuler[i] = y[i] + m_dStepSize*dydtx[i];
00115 }
00116
00117
00118 ComputeDerivatives(yEuler,dydtxph);
00119 for(i = 0; i < nRHS; i++)
00120 {
00121 yRK2[i] = y[i] + halfStep*(dydtx[i] + dydtxph[i]);
00122 }
00123
00124
00125
00126 for(i = 0; i < nRHS; i++)
00127 {
00128 y[i] = m_scdAlpha*yEuler[i] + (1 - m_scdAlpha)*yRK2[i];
00129 m_pdLocalError[i] = (y[i] - yRK2[i])/y[i];
00130 }
00131
00132
00133 delete [] yEuler;
00134 delete [] yRK2;
00135 delete [] dydtx;
00136 delete [] dydtxph;
00137
00138 }
00139
00141
00142
00144
00145
00146 double CRK2ExplicitEulerHybridMover::SetStepScale(int nRHS)
00147 {
00148 double maxErr = 0.0;
00149 for(int i = 0; i < nRHS; i++)
00150 {
00151 double absLocalError = fabs(m_pdLocalError[i]);
00152 if(absLocalError > maxErr) { maxErr = absLocalError;}
00153 }
00154
00155 return sqrt(m_dEps/maxErr);
00156 }