00001
00002
00003
00004
00005
00006
00007
00009 #include "NumericalMethods/NmOdeInt.h"
00010 #include <cassert>
00011 #include <cmath>
00012 #include "MessageService/MsgService.h"
00013 #include "NumericalMethods/NmOdeDerivFunc.h"
00014 #include "NumericalMethods/NmOdeStepperRKCK.h"
00015 CVSID("$Id: NmOdeInt.cxx,v 1.4 2005/03/03 21:48:29 musser Exp $");
00016
00017
00018
00019 NmOdeInt::NmOdeInt() :
00020 fXstart(0.0),
00021 fXend(0.0),
00022 fNvar(0),
00023 fYstart(0),
00024 fYend(0),
00025 fYscale(0),
00026 fNmaxSteps(10000),
00027 fNok(0),
00028 fNbad(0),
00029 fEps(1.0e-6),
00030 fStepSize(0.0),
00031 fMinStepSize(0.0),
00032 fDerivs(0),
00033 fStepper(new NmOdeStepperRKCK),
00034 fDefaultStepper(true),
00035 fUseDefaultScales(true)
00036 { }
00037
00038
00039
00040 NmOdeInt::NmOdeInt(const double* y1,
00041 int n,
00042 double x1,
00043 double x2,
00044 double acc,
00045 double step,
00046 double minStep,
00047 NmOdeDerivFunc& f) :
00048 fXstart(x1),
00049 fXend(x2),
00050 fNvar(n),
00051 fYstart(new double[fNvar]),
00052 fYend( new double[fNvar]),
00053 fYscale(new double[fNvar]),
00054 fNmaxSteps(10000),
00055 fNok(0),
00056 fNbad(0),
00057 fEps(acc),
00058 fStepSize(step),
00059 fMinStepSize(minStep),
00060 fDerivs(&f),
00061 fStepper(new NmOdeStepperRKCK),
00062 fDefaultStepper(true),
00063 fUseDefaultScales(true)
00064 {
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078 for (int i=0; i<fNvar; ++i) {
00079 fYstart[i] = y1[i];
00080 fYend[i] = 0.0;
00081 }
00082 }
00083
00084
00085
00086 NmOdeInt::~NmOdeInt()
00087 {
00088
00089
00090
00091 delete []fYstart; fYstart = 0;
00092 delete []fYend; fYend = 0;
00093 delete []fYscale; fYscale = 0;
00094 if (fDefaultStepper) { delete fStepper; fStepper = 0; }
00095 }
00096
00097
00098
00099 void NmOdeInt::SetMaxSteps(int n)
00100 {
00101
00102
00103
00104 assert(n>1);
00105 fNmaxSteps = n;
00106 }
00107
00108
00109
00110 void NmOdeInt::SetNvar(int n)
00111 {
00112
00113
00114
00115 assert(n>0);
00116
00117 if (fYstart) { delete []fYstart; fYstart = 0; }
00118 if (fYend) { delete []fYend; fYend = 0; }
00119 if (fYscale) { delete []fYscale; fYscale = 0; }
00120 fNvar = n;
00121 fYstart = new double[fNvar];
00122 fYend = new double[fNvar];
00123 fYscale = new double[fNvar];
00124 }
00125
00126
00127
00128 void NmOdeInt::SetInitialCondition(const double* y)
00129 {
00130
00131
00132
00133
00134
00135 assert(fNvar>0);
00136 for (int i=0; i<fNvar; ++i) fYstart[i] = y[i];
00137 }
00138
00139
00140
00141 void NmOdeInt::SetScales(const double* s)
00142 {
00143
00144
00145
00146
00147
00148 assert(fNvar>0);
00149 for (int i=0; i<fNvar; ++i) fYscale[i] = s[i];
00150 fUseDefaultScales = false;
00151 }
00152
00153
00154
00155 void NmOdeInt::SetStepper(NmOdeStepper& s)
00156 {
00157
00158
00159
00160
00161
00162 if (fStepper && fDefaultStepper) {
00163 delete fStepper;
00164 fStepper = 0;
00165 }
00166 fDefaultStepper = false;
00167 fStepper = &s;
00168 }
00169
00170
00171
00172 bool NmOdeInt::Integrate(double* yFinal)
00173 {
00174
00175
00176
00177
00178
00179
00180
00181
00182 register int nstp;
00183 register int i;
00184
00185 double x;
00186 double hNext;
00187 double hDid;
00188 double h;
00189 double* y = new double[fNvar];
00190 double* dydx = new double[fNvar];
00191 static const double tiny = 1.0e-30;
00192
00193
00194 fNok = fNbad = 0;
00195 if (fEps == 0.0) fEps = 1.0e-4;
00196 if (fStepSize == 0.0)
00197 fStepSize = sqrt(fEps)*fabs(fXstart-fXend);
00198
00199 x = fXstart;
00200 if (fXend>fXstart) h = fStepSize;
00201 else h = -fStepSize;
00202
00203 for (i=0; i<fNvar; ++i) y[i] = fYstart[i];
00204 for (nstp = 0; nstp<fNmaxSteps; ++nstp) {
00205 (*fDerivs)(x,y,dydx);
00206
00207
00208 if (fUseDefaultScales) {
00209 for (i=0; i<fNvar; ++i) {
00210 fYscale[i] = fabs(y[i])+fabs(dydx[i]*h)+tiny;
00211 }
00212 }
00213
00214
00215 if ((x+h-fXend)*(x+h-fXstart) > 0.0) h = fXend-x;
00216
00217 fStepper->Step(y, dydx, fNvar, &x, h, fEps, fYscale,
00218 &hDid, &hNext, *fDerivs);
00219 if (hDid == h) fNok++;
00220 else fNbad++;
00221
00222
00223 if (this->Done(x,y)) {
00224
00225 for (i=0; i<fNvar; ++i) {
00226 yFinal[i] = fYend[i] = y[i];
00227 }
00228 delete []y; y = 0;
00229 delete []dydx; dydx = 0;
00230
00231 return true;
00232 }
00233 if (fabs(hNext)<=fMinStepSize) {
00234 MSG("Nm",Msg::kWarning) <<
00235 "Step size too small (" << hNext<< "<" << fMinStepSize << "\n";
00236 h = fMinStepSize;
00237 }
00238 else {
00239 h = hNext;
00240 }
00241 }
00242
00243 for (i=0; i<fNvar; ++i) {
00244 yFinal[i] = fYend[i] = y[i];
00245 }
00246 delete []y; y = 0;
00247 delete []dydx; dydx = 0;
00248 MSG("Nm",Msg::kError)
00249 << "Maximum number of steps ("<< fNmaxSteps <<") exceeded\n";
00250 return false;
00251 }
00252
00253
00254
00255 bool NmOdeInt::Done(double x, const double* y)
00256 {
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266 return ((x-fXend)*(fXend-fXstart)>=0.0);
00267 }
00268