00001 #include "StiffBulirschStoerMover.h"
00002
00003 const double CStiffBulirschStoerMover::m_scdTINY = 1.0e-30;
00004
00005 const int CStiffBulirschStoerMover::m_sciKMAXX = 7;
00006
00007
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
00037 double xInterval = xFinal-xInitial;
00038
00039 m_pReactionNetwork = pReactionNetwork;
00040
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
00053 return;
00054 }
00055 if(m_dInitialStepSize > xInterval) {m_dInitialStepSize = xInterval;}
00056
00057 m_dTime = xInitial;
00058 double nextTime;
00059
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
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
00083 while( m_dTime < __min(xFinal,nextTime) )
00084 {
00085
00086 ComputeDerivatives(chem,dChemdt);
00087
00088
00089
00090 for(i = 0; i < nChem; i++)
00091 {
00092
00093 m_pdScale[i] = __max(1.0,fabs(chem[i]));
00094 }
00095
00096
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
00103 StiffBSStep(nChem,chem,dChemdt);
00104
00105
00106 for(int i = 0; i < nChem; i++)
00107 {
00108 m_pReactionNetwork->GetChemical(i)->SetAmount(chem[i]);
00109 }
00110
00111
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
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
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)
00186 {
00187 m_dNextStep = xnew = -1.0e29;
00188 eps1 = m_scdSAFE1*m_dEps;
00189
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
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 }
00205
00206 epsold = m_dEps;
00207 nvold = nRHS;
00208
00209
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
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 }
00227
00228
00229 for(i = 0; i < nRHS; i++)
00230 {
00231 ysav[i] = y[i];
00232 }
00233
00234 this->ComputeJacobian(y,dfdy);
00235
00236 this->ComputeDerivatives(y,dydt);
00237
00238
00239 if(m_dTime != xnew || m_dStepSize != m_dNextStep)
00240 {
00241 first = 1;
00242 kopt = kmax;
00243 }
00244 reduct = 0;
00245 for(;;)
00246 {
00247
00248 for(k = 0; k <= kmax; k++)
00249 {
00250 xnew = m_dTime + m_dStepSize;
00251
00252
00253
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
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
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
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
00374 for(i = 0; i < nRHS;i++)
00375 {
00376 yout[i] = h*dydt[i];
00377 }
00378
00379 this->LUSolveLinearSystem(nRHS,a,yout);
00380
00381 for(i = 0; i < nRHS; i++)
00382 {
00383 ytemp[i] = y[i] + (del[i] = yout[i]);
00384 }
00385 x = m_dTime + h;
00386
00387 this->ComputeDerivatives(ytemp,yout);
00388
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
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
00405 for(i = 0; i < nRHS; i++)
00406 {
00407 yout[i] = h*yout[i] - del[i];
00408 }
00409
00410 this->LUSolveLinearSystem(nRHS,a,yout);
00411
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
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
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486 char UPLO = 'U';
00487 char TRANS = 'N';
00488
00489 int INFO=0;
00490
00491 int N = nRHS;
00492 int M = nRHS;
00493
00494
00495 int LDA = nRHS;
00496 int LDB = nRHS;
00497
00498 int NRHS = 1;
00499
00500
00501 double *B = new double[nRHS];
00502
00503
00504
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
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
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 }