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

RK2ExplicitEulerHybridMover.cpp

Go to the documentation of this file.
00001 // RK2ExplicitEulerHybridMover.cpp: implementation of the CRK2ExplicitEulerHybridMover class.
00002 //
00004 
00005 #include "RK2ExplicitEulerHybridMover.h"
00006 
00008 // The details of this algorithm are described in Ashour and Hanna, 
00009 // Computers chem. Engng., 14 (3), 267 (1990).  It is good for 
00010 // moderately stiff problems at "sloppy tolerance."  It avoids the 
00011 // memory and heavy operation count of most implicit solvers (it does
00012 // not even use the Jacobian).  As coded, the method is second order.
00014 
00016 // Static member Alpha giving combination of explicit Euler step and
00017 // RK2 step - don't fool with this unless you know what you're doing!
00019 
00020 const double CRK2ExplicitEulerHybridMover::m_scdAlpha=0.74;
00021 
00023 // Construction/Destruction
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         // do a couple of checks on the integration interval
00040         double xInterval = xFinal-xInitial;
00041         if(this->MoveTimeIsZero(xInterval)) {return;}
00042         if(m_dStepSize > xInterval) {m_dStepSize = xInterval;}
00043 
00044         // set the member pointer to the network pointer passed in
00045         this->m_pReactionNetwork = pReactionNetwork;
00046         m_dTime = xInitial;
00047         // may be unsafe if xInitial has a fractional part!
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         // set up local chemical array
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                         // make sure the stepsize isn't too small
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                         // don't run over time
00073                         if( ((m_dTime + m_dStepSize) - nextTime) > 0.0)
00074                         {
00075                                 m_dStepSize = nextTime - m_dTime;
00076                         }
00077                 
00078                         // take a step
00079                         HybridStep(nChem,chem,dChemdt);
00080                         m_dTime += m_dStepSize;
00081                         // adjust the stepsize
00082                         m_dStepSize = m_dStepSize*SetStepScale(nChem);
00083                 }
00084                 // ensure synchrony with chem and network
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         // take a 1st order Euler step
00111         ComputeDerivatives(y,dydtx);
00112         for(i = 0; i < nRHS; i++)
00113         {
00114                 yEuler[i] = y[i] + m_dStepSize*dydtx[i];
00115         }
00116         
00117         // now take a 2nd order RK step using yEuler
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         // weighted average to get the answer, and simulatneously compute the local
00125         // error
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         // free memory
00133         delete [] yEuler;
00134         delete [] yRK2;
00135         delete [] dydtx;
00136         delete [] dydtxph;
00137 
00138 }
00139 
00141 //      The multiplicative factor for the next stepsize is
00142 //                      beta = sqrt(tolerance/max_i(m_pdLocalError));
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 }

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