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

StiffBulirschStoerMover.cpp

Go to the documentation of this file.
00001 #include "StiffBulirschStoerMover.h"
00002 
00003 const double CStiffBulirschStoerMover::m_scdTINY = 1.0e-30;
00004 
00005 const int CStiffBulirschStoerMover::m_sciKMAXX = 7;
00006 
00007 // this needs to be KMAXX+1
00008 const int CStiffBulirschStoerMover::m_sciIMAXX = 8;
00009 
00010 const double CStiffBulirschStoerMover::m_scdSAFE1 = 0.25;
00011 
00012 const double CStiffBulirschStoerMover::m_scdSAFE2 = 0.7;
00013 
00014 const double CStiffBulirschStoerMover::m_scdREDMAX = 1.0e-05;
00015 
00016 const double CStiffBulirschStoerMover::m_scdREDMIN = 0.7;
00017 
00018 const double CStiffBulirschStoerMover::m_scdSCALMX = 0.1;
00019 
00020 CStiffBulirschStoerMover::CStiffBulirschStoerMover(double frequency, double stepSize, double eps)
00021 :CDifferentialEquationMover(frequency,stepSize)
00022 {
00023         m_dLastStep = stepSize;
00024         m_dNextStep = stepSize;
00025         m_dInitialStepSize = stepSize;
00026         m_dEps = eps;
00027 }
00028 
00029 CStiffBulirschStoerMover::~CStiffBulirschStoerMover(void)
00030 {
00031 }
00032 
00033 void CStiffBulirschStoerMover::Move(double xInitial, double xFinal, ReactionNetwork *pReactionNetwork)
00034 {
00035         int i;
00036         // do a couple of checks on the integration interval
00037         double xInterval = xFinal-xInitial;
00038         // set the member pointer equal to the pointer passed in
00039         m_pReactionNetwork = pReactionNetwork;
00040         // if there's no moving to be done and xI = xF = integer, take data there
00041         if(this->MoveTimeIsZero(xInterval)) 
00042         {
00043                 if(xInitial > (int) xInitial)
00044                 {
00045                 }
00046                 else
00047                 {
00048                         m_iCount = (int) xInitial;
00049                         m_iCount++;
00050                         Notify();
00051                 }
00052                 // take a data point 
00053                 return;
00054         }
00055         if(m_dInitialStepSize > xInterval) {m_dInitialStepSize = xInterval;}
00056 
00057         m_dTime = xInitial;
00058         double nextTime;
00059         // set up the count variable
00060         m_iCount = (int) xInitial;
00061         m_iCount++;
00062         nextTime = m_iCount;
00063 
00064         m_dStepSize = m_dInitialStepSize;
00065         m_dLastStep = m_dInitialStepSize;
00066         m_dNextStep = m_dInitialStepSize;
00067         
00068         int nChem = m_pReactionNetwork->GetNumberOfChemicals();
00069         double *chem = new double[nChem];
00070         double *dChemdt = new double[nChem];
00071         m_pdScale = new double[nChem];
00072         m_pdError = new double[nChem];
00073 
00074         // fill chem[] with starting chemical concentrations
00075         for(i = 0; i < nChem; i++)
00076         {
00077                 chem[i] = m_pReactionNetwork->GetChemical(i)->GetAmount();
00078         }
00079 
00080         while(m_dTime < xFinal)
00081         {
00082                 // run until xFinal or nextTime (nextTime might be > xFinal)
00083                 while( m_dTime < __min(xFinal,nextTime) )
00084                 {
00085                         // get initial derivatives
00086                         ComputeDerivatives(chem,dChemdt);
00087                         // compute scaling vector
00088                         // __max is to ensure chemicals that start at ~ 0 don't get
00089                         // huge scaling factors, which screws up the stepper
00090                         for(i = 0; i < nChem; i++)
00091                         {
00092                                 //m_pdScale[i] = fabs(chem[i]) + fabs(m_dStepSize*dChemdt[i]) + m_scdTINY;
00093                                 m_pdScale[i] = __max(1.0,fabs(chem[i]));
00094                         }
00095                         
00096                         // don't run over - nextTime might be > xFinal
00097                         if( (((m_dTime + m_dNextStep) - nextTime) > 0.0) || (((m_dTime + m_dNextStep) - xFinal) > 0.0) )        
00098                         {
00099                                 m_dNextStep = __min(nextTime-m_dTime,xFinal-m_dTime);
00100                         }
00101 
00102                         // call the stepper
00103                         StiffBSStep(nChem,chem,dChemdt);
00104 
00105                         // ensure synchrony with chem and network
00106                         for(int i = 0; i < nChem; i++)
00107                         {
00108                                 m_pReactionNetwork->GetChemical(i)->SetAmount(chem[i]);
00109                         }
00110                         
00111                         // record largest/smallest/numsteps info
00112                         if(m_dLastStep < this->GetMinStepSize()) {this->SetMinStepSize(m_dLastStep);}
00113                         if(m_dLastStep > this->GetMaxStepSize()) {this->SetMaxStepSize(m_dLastStep);}
00114                         this->IncrementTotalSteps();
00115                 }
00116                 
00117                 if(m_dTime == nextTime)
00118                 {
00119                         m_iCount++;
00120                         Notify();
00121                         nextTime += 1.0;
00122                 }
00123         }
00124 
00125         delete [] chem;
00126         delete [] dChemdt;
00127         delete [] m_pdScale;
00128         delete [] m_pdError;
00129 }
00130 
00131 
00132 void CStiffBulirschStoerMover::StiffBSStep(int nRHS, double *y, double *dydt)
00133 {
00134         int i,iq,k,kk,km;
00135         int first = 1;
00136         int kmax,kopt;
00137         int nvold = -1;
00138         double epsold = -1.0;
00139         double xnew;
00140         double eps1,errmax,fact,red,scale,work,wrkmin,xest;
00141         int reduct = 0;
00142         bool exitflag = false;
00143 
00144         m_dStepSize = m_dNextStep;
00145 
00146         // memory allocation
00147         double *a = new double[m_sciIMAXX];
00148         double **alf = new double *[m_sciKMAXX];
00149         alf[0] = new double[(m_sciKMAXX )*(m_sciKMAXX)];
00150         for(i = 1; i < m_sciKMAXX; i++)
00151         {
00152                 alf[i] = &(alf[0][i*(m_sciKMAXX)]);
00153         }
00154         int *nseq = new int[m_sciIMAXX];
00155         
00156         // step sequence
00157         nseq[0] = 2;
00158         nseq[1] = 6;
00159         nseq[2] = 10;
00160         nseq[3] = 14;
00161         nseq[4] = 22;
00162         nseq[5] = 34;
00163         nseq[6] = 50;
00164         nseq[7] = 70;
00165 
00166         double **d = new double *[nRHS];
00167         d[0] = new double[nRHS*(m_sciKMAXX)];
00168         for(i = 1; i < nRHS; i++)
00169         {
00170                 d[i] = &(d[0][i*m_sciKMAXX]);
00171         }
00172         double **dfdy = new double *[nRHS];
00173         dfdy[0] = new double[nRHS*nRHS];
00174         for(i = 1; i < nRHS; i++)
00175         {
00176                 dfdy[i] = &(dfdy[0][i*nRHS]);
00177         }
00178         double *x = new double[m_sciKMAXX];
00179         double *yerr = new double[nRHS];
00180         double *ysav = new double[nRHS];
00181         double *yseq = new double[nRHS];
00182 
00183         m_dStepSize = m_dNextStep;
00184 
00185         if(m_dEps != epsold || nRHS != nvold) // Reinitialize if either have changed
00186         {
00187                 m_dNextStep = xnew = -1.0e29;
00188                 eps1 = m_scdSAFE1*m_dEps;
00189                 // compute work coefficients A_k
00190                 a[0] = nseq[0] + 1;
00191                 for(k = 0; k < m_sciKMAXX; k++)
00192                 {
00193                         a[k+1] = a[k]*nseq[k+1];
00194                 }
00195                 
00196                 // compute alpha(k,q)
00197                 for(iq = 1; iq < m_sciKMAXX; iq++)
00198                 {
00199                         for(k = 0; k < iq; k++)
00200                         {
00201                                 double exponent = (a[k+1]-a[iq+1])/((a[iq+1] - a[0] + 1.0)*(2*k+3));
00202                                 alf[k][iq] = pow(eps1,exponent);
00203                         }
00204                 } // end iq loop
00205                 
00206                 epsold = m_dEps;
00207                 nvold = nRHS;
00208                 
00209                 // add cost of Jacobian calculations to work coefficients
00210                 a[0] += nRHS;
00211                 for(k = 0; k < m_sciKMAXX; k++)
00212                 {
00213                         a[k+1] = a[k] + nseq[k+1];
00214                 }
00215 
00216                 // determine optimal row number for convergence
00217                 for(kopt = 1; kopt < m_sciKMAXX - 1; kopt++)
00218                 {
00219                         if(a[kopt+1] > a[kopt]*alf[kopt-1][kopt])
00220                         {
00221                                 break;
00222                         }
00223                 }
00224                 kmax = kopt;
00225 
00226         } // end eps != epsold || nv != nvold if
00227 
00228         // save starting values
00229         for(i = 0; i < nRHS; i++)
00230         {
00231                 ysav[i] = y[i];
00232         }
00233         // evaluate the jacobian (at the starting point)
00234         this->ComputeJacobian(y,dfdy);
00235         // make sure derivs are current
00236         this->ComputeDerivatives(y,dydt);
00237 
00238         // a new stepsize or integration; reestablish the order window
00239         if(m_dTime != xnew || m_dStepSize != m_dNextStep)
00240         {
00241                 first = 1;
00242                 kopt = kmax;
00243         }
00244         reduct = 0;
00245         for(;;)
00246         {
00247                 // evaluate the sequence of modified midpoint integrations
00248                 for(k = 0; k <= kmax; k++)
00249                 {
00250                         xnew = m_dTime + m_dStepSize;
00251                         // XXX debug
00252                         //cout << "m_dTime = " << m_dTime << ", m_dStepSize = " << m_dStepSize << ", nstep = " << nseq[k] << endl;
00253                         //cin.get();
00254                         if(xnew == m_dTime) {cout << "ERROR : Step size underflow in CStiffBulirschStoerMover::StiffBSStep()" << endl;}
00255                         this->SemiImplicitMidpoint(nRHS,ysav,dydt,dfdy,nseq[k],yseq);
00256                         xest = (m_dStepSize/nseq[k])*(m_dStepSize/nseq[k]);
00257                         this->PolynomialExtrapolation(nRHS,k,xest,yseq,y,yerr,x,d);
00258                         if(k != 0)
00259                         {
00260                                 errmax = m_scdTINY;
00261                                 for(i = 0; i < nRHS; i++)
00262                                 {
00263                                         errmax = __max(errmax,fabs(yerr[i]/m_pdScale[i]));
00264                                 }
00265                                 errmax = errmax/m_dEps;
00266                                 km = k-1;
00267                                 m_pdError[km] = pow(errmax/m_scdSAFE1,1.0/(2*km + 3));
00268                         }
00269                         if(k != 0 && (k >= kopt-1 || first))
00270                         {
00271                                 if(errmax < 1.0)
00272                                 {
00273                                         exitflag = true;
00274                                         break;
00275                                 }
00276                                 if(k == kmax || k == kopt+1)
00277                                 {
00278                                         red = m_scdSAFE2/m_pdError[km];
00279                                         break;
00280                                 }
00281                                 else if(k == kopt && alf[kopt-1][kopt] < m_pdError[km])
00282                                 {
00283                                         red = 1.0/m_pdError[km];
00284                                         break;
00285                                 }
00286                                 else if(kopt == kmax && alf[km][kmax-1] < m_pdError[km])
00287                                 {
00288                                         red = alf[km][kmax-1]*m_scdSAFE2/m_pdError[km];
00289                                         break;
00290                                 }
00291                                 else if(alf[km][kopt] < m_pdError[km])
00292                                 {
00293                                         red = alf[km][kopt-1]/m_pdError[km];
00294                                         break;
00295                                 }
00296                         }
00297                 }
00298                 if(exitflag) {break;}
00299                 red = __min(red,m_scdREDMIN);
00300                 red = __max(red,m_scdREDMAX);
00301                 m_dStepSize = m_dStepSize*red;
00302                 reduct = 1;
00303 
00304         }
00305         m_dTime = xnew;
00306         m_dLastStep = m_dStepSize;
00307         first = 0;
00308         wrkmin = 1.0e35;
00309         for(kk = 0; kk <= km; kk++)
00310         {
00311                 fact = __max(m_pdError[kk],m_scdSCALMX);
00312                 work = fact*a[kk+1];
00313                 if(work < wrkmin)
00314                 {
00315                         scale = fact;
00316                         wrkmin = work;
00317                         kopt = kk+1;
00318                 }
00319         }
00320         m_dNextStep = m_dStepSize/scale;
00321         if(kopt >= k && kopt != kmax && !reduct)
00322         {
00323                 fact = __max(scale/alf[kopt-1][kopt],m_scdSCALMX);
00324                 if(a[kopt+1]*fact <= wrkmin)
00325                 {
00326                         m_dNextStep = m_dStepSize/fact;
00327                         kopt++;
00328                 }
00329         }
00330 
00331         // deletes
00332         delete [] nseq;
00333         delete [] a;
00334         delete [] alf[0];
00335         delete [] alf;
00336         delete [] d[0];
00337         delete [] d;
00338         delete [] x;
00339         delete [] yerr;
00340         delete [] ysav;
00341         delete [] yseq;
00342         delete [] dfdy[0];
00343         delete [] dfdy;
00344 }
00345 
00346 
00347 void CStiffBulirschStoerMover::SemiImplicitMidpoint(int nRHS, double *y, double *dydt, double **dfdy, int nStep, double *yout)
00348 {
00349         int i,j,nn;
00350         double h,x;
00351 
00352         // memory allocation
00353         double **a = new double *[nRHS];
00354         a[0] = new double[nRHS*nRHS];
00355         for(i = 1; i < nRHS; i++)
00356         {
00357                 a[i] = &(a[0][i*nRHS]);
00358         }
00359         double *del = new double[nRHS];
00360         double *ytemp = new double[nRHS];
00361 
00362         h = m_dStepSize/nStep;
00363 
00364         // set up the 1 - hf' matrix
00365         for(i = 0; i < nRHS; i++)
00366         {
00367                 for(j = 0; j < nRHS; j++)
00368                 {
00369                         a[i][j] = -h*dfdy[i][j];
00370                 }
00371                 ++a[i][i];
00372         }
00373         // set up right hand side for first step, use yout[] for temp. storage
00374         for(i = 0; i < nRHS;i++)
00375         {
00376                 yout[i] = h*dydt[i];
00377         }
00378         // LU backsubstitution with yout as the rhs
00379         this->LUSolveLinearSystem(nRHS,a,yout);
00380         // first step
00381         for(i = 0; i < nRHS; i++)
00382         {
00383                 ytemp[i] = y[i] + (del[i] = yout[i]);
00384         }
00385         x = m_dTime + h;
00386         // use yout[] for temporary derivative storage
00387         this->ComputeDerivatives(ytemp,yout);
00388         // general step
00389         for(nn = 2; nn <= nStep; nn++)
00390         {
00391                 for(i = 0; i < nRHS; i++)
00392                 {
00393                         yout[i] = h*yout[i] - del[i];
00394                 }
00395                 // Do LU Backsubstitution
00396                 this->LUSolveLinearSystem(nRHS,a,yout);
00397                 for(i = 0; i < nRHS; i++)
00398                 {
00399                         ytemp[i] += (del[i] += 2.0*yout[i]);
00400                 }
00401                 x += h;
00402                 this->ComputeDerivatives(ytemp,yout);
00403         }
00404         // set up RHS for last step
00405         for(i = 0; i < nRHS; i++)
00406         {
00407                 yout[i] = h*yout[i] - del[i];
00408         }
00409         // Do LU backsubstitution
00410         this->LUSolveLinearSystem(nRHS,a,yout);
00411         // take last step
00412         for(i = 0; i < nRHS; i++)
00413         {
00414                 yout[i] += ytemp[i];
00415         }
00416 
00417         delete [] a[0];
00418         delete [] a;
00419         delete [] del;
00420         delete [] ytemp;
00421 }
00422 
00423 void CStiffBulirschStoerMover::PolynomialExtrapolation(int nRHS, int iest, double xest, double *yest, double *yz, double *dy, double *x, double **d)
00424 {
00425         int k1,j;
00426         double q,f2,f1,delta;
00427 
00428         double *c = new double[nRHS];
00429         x[iest] = xest;
00430         for(j = 0; j < nRHS; j++)
00431         {
00432                 dy[j] = yz[j] = yest[j];
00433         }
00434         // store first estimate in first column
00435         if(iest == 0)
00436         {
00437                 for(j = 0; j < nRHS; j++)
00438                 {
00439                         d[j][0] = yest[j];
00440                 }
00441         }
00442         else
00443         {
00444                 for(j = 0; j < nRHS; j++)
00445                 {
00446                         c[j] = yest[j];
00447                 }
00448                 for(k1 = 0; k1 < iest; k1++)
00449                 {
00450                         delta = 1.0/(x[iest-k1-1] - xest);
00451                         f1 = xest*delta;
00452                         f2 = x[iest-k1-1]*delta;
00453                         for(j = 0; j < nRHS; j++)
00454                         {
00455                                 q = d[j][k1];
00456                                 d[j][k1] = dy[j];
00457                                 delta = c[j] - q;
00458                                 dy[j] = f1*delta;
00459                                 c[j] = f2*delta;
00460                                 yz[j] += dy[j];
00461                         }
00462                 }
00463                 for(j = 0; j < nRHS; j++)
00464                 {
00465                         d[j][iest] = dy[j];
00466                 }
00467         }
00468         delete [] c;
00469 }
00470 
00471 void CStiffBulirschStoerMover::LUSolveLinearSystem(int nRHS, double **a, double *b)
00472 {
00473         /*
00474         // XXX debug
00475         for(int ii = 0; ii < nRHS; ii++)
00476         {
00477                 for(int jj = 0; jj < nRHS; jj++)
00478                 {
00479                         cout << a[ii][jj] << "    " << endl;
00480                 }
00481                 cout << endl;
00482         }
00483         cin.get();
00484         */
00485         // we're giving the LAPACK routine the upper triangle (though it doesn't matter)
00486         char UPLO = 'U';
00487         char TRANS = 'N';
00488         // can check for correct factorization
00489         int INFO=0; 
00490         // order of A
00491         int N = nRHS;
00492         int M = nRHS;
00493         
00494         // need to be >= max(1,N);
00495         int LDA = nRHS;
00496         int LDB = nRHS;
00497         // only one right hand side
00498         int NRHS  = 1;
00499 
00500         // allocate temporary storage space
00501         double *B = new double[nRHS];
00502 
00503         // LU DECOMPOSITION & SOLUTION (LAPACK)
00504         // copy alpha and beta appropriately
00505         double *A = new double[nRHS*nRHS];
00506         int *IPIV = new int[nRHS];
00507         int counter = 0;
00508         for(int j = 0; j < nRHS; j++)
00509         {
00510                 B[j] = b[j];
00511                 for(int i = 0; i < nRHS; i++)
00512                 {
00513                         A[counter] = a[i][j];
00514                         counter++;
00515                 }
00516         }
00517         
00518         // LU decompose
00519         DGETRF(&M,&N,A,&LDA,IPIV,&INFO);
00520         if(INFO > 0)
00521         {
00522                 cout << "Matrix singularity suspected - StiffBulirschStoerMover::LUSolveLinearSystem failed . . . " << endl;
00523         }
00524         else
00525         {
00526                 DGETRS(&TRANS,&N,&NRHS,A,&LDA,IPIV,B,&LDB,&INFO);
00527                 // copy back the solution
00528                 for(int i = 0; i < nRHS; i++)
00529                 {
00530                         b[i] = B[i];
00531                 }
00532         }
00533 
00534                 
00535         delete [] A;
00536         delete [] B;
00537         delete [] IPIV;
00538 }

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