ROOT logo
// $Id: ODECrawler.cxx 2171 2009-03-30 16:43:12Z matevz $

#include "ODECrawler.h"
#include "ODECrawler.c7"

#include <TMath.h>


//==============================================================================
// ODECrawlerMaster
//==============================================================================

//______________________________________________________________________________
//
// Abstract base class for glass that provides:
// a) ODE order
// b) initial conditions
// c) derivatives

ClassImp(ODECrawlerMaster);


//==============================================================================
// ODECrawler
//==============================================================================

//______________________________________________________________________________
//
// ODE integrator built upon adaptive step 4th order runge-kutta.
// X corresponds to time (scalar).
// Y corresponds to state vector at a given time.
// Final state can be obtained from mY.
// Works in double precision.
//
// No good way for permanent storage or broadcasting of results yet.
//
// Trajectory is stored in ODEstorage object with at least mStoreDx
// between consequtive points.
// Maximum of mStoreMax intermediate points are stored.
// If mStoreMax = 0 no results are stored.
// If mStoreMax < 0 all points are stored (default).
//
// Example glass Moonraker. Macro moonraker.C.
//________________________________________________________________________

ClassImp(ODECrawler);

void ODECrawler::_init()
{
  hTINY = 1e-30; hSAFETY = 0.9; hPGROW = -0.2; hPSHRNK = -0.25; hERRCON = 1.89e-4;
  hTrueMaster = 0;
  hCrawling   = false;

  mGuessesOK = mGuessesBad = mStored = 0;
  mMaxSteps  = 1000000; mStoreDx = 0.001; mStoreMax = -1;
  mStorage   = 0;
  mAcc = 1e-8; mH1 = 1e-2; mHmin = 1e-18;
  mX1 = 0; mX2 = 0;
}

ODECrawler::~ODECrawler()
{
  delete mStorage;
}

/**************************************************************************/

void ODECrawler::AdvanceXLimits(Double_t delta_x)
{
  // Advance x limits forward, so that X1 becomes X2 and new integration
  // interval is delta_x.
  // If delta_x is 0, length of the interval is preserved.

  if (delta_x == 0) delta_x = mX2 - mX1;
  mX1  = mX2;
  mX2 += delta_x;
}

void ODECrawler::SetStorage(ODEStorage* s)
{
  delete mStorage;
  mStorage = s;
}

void ODECrawler::DetachStorage()
{
  mStorage = 0;
}

ODEStorage* ODECrawler::SwapStorage(ODEStorage* s)
{
  ODEStorage* old = s;
  mStorage = s;
  return old;
}

/**************************************************************************/

void ODECrawler::init_integration(Bool_t call_ode_start)
{
  // Initialize storage arrays, clear integration state.
  // If call_ode_start is true, call ODEStart() in master to get
  // initial parameters.
  // hTrueMaster must be set.

  mN = hTrueMaster->ODEOrder();
  if (mY.GetNoElements() != mN)
    mY.ResizeTo(mN);

  if (mStoreMax != 0)
  {
    if (mStorage == 0)
    {
      mStorage = new ODEStorageD(mN);
    }
    else if (mStorage->Order() != mN)
    {
      mStorage->ResetOrder(mN);
    }
    else
    {
      mStorage->Reset();
    }
  }

  mGuessesOK = mGuessesBad = mStored = 0;

  if (call_ode_start)
    hTrueMaster->ODEStart(mY, mX1, mX2);
}

Int_t
ODECrawler::Rkqs(TVectorD& y, TVectorD& dydx, Double_t& x, Double_t htry,
		 TVectorD& yscal, Double_t& h_last, Double_t& h_next)
{
  static const Exc_t _eh("ODECrawler::Rkqs ");

  Double_t errmax, htemp, xnew;

  TVectorD yerr(mN), y_buf(mN);
  Double_t h = htry;
  while (true)
  {
    Rkck(y, dydx, x, h, y_buf, yerr);
    errmax = 0.0;
    for (Int_t i = 0; i < mN; ++i)
      errmax = TMath::Max(errmax, TMath::Abs(yerr(i)/yscal(i)));
    errmax /= mAcc;
    if (errmax <= 1.0) break;
    htemp = hSAFETY*h*TMath::Power(errmax, hPSHRNK);
    h = (h >= 0) ? TMath::Max(htemp, 0.1*h) : TMath::Min(htemp, 0.1*h);
    xnew = x + h;
    if (xnew == x)
    {
      throw(_eh + GForm("stepsize underflow, errmax=%f.", errmax));
    }
  }
  if (errmax > hERRCON)
    h_next = hSAFETY*h*TMath::Power(errmax, hPGROW);
  else
    h_next = 5.0*h;
  x += (h_last = h);
  y = y_buf;
  return 0;
}

/**************************************************************************/

void ODECrawler::Rkck(TVectorD& y, TVectorD& dydx, Double_t x, Double_t h,
                      TVectorD& yout, TVectorD& yerr)
{
  static const Double_t
    a2  = 0.2, a3 = 0.3, a4 = 0.6, a5 = 1.0, a6 = 0.875;
  static const Double_t
    b21 =  0.2,           b31 =  3.0/40.0,         b32 =  9.0/40.0,
    b41 =  0.3,           b42 = -0.9,              b43 =  1.2,
    b51 = -11.0/54.0,     b52 =  2.5,              b53 = -70.0/27.0,
    b54 =  35.0/27.0,     b61 =  1631.0/55296.0,   b62 =  175.0/512.0,
    b63 =  575.0/13824.0, b64 =  44275.0/110592.0, b65 =  253.0/4096.0;
  static const Double_t
    c1 = 37.0/378.0,  c3 = 250.0/621.0,
    c4 = 125.0/594.0, c6 = 512.0/1771.0;
  static const Double_t
    dc1 = c1 - 2825.0/27648.0,  dc3 = c3 - 18575.0/48384.0,
    dc4 = c4 - 13525.0/55296.0, dc6 = c6 - 0.25,
    dc5 = -277.0/14336.0;

  TVectorD der2(mN), der3(mN), der4(mN), der5(mN), der6(mN), y_buf(mN);

  for (Int_t i = 0; i < mN; ++i)
    y_buf(i) = y(i) + b21*h*dydx(i);
  hTrueMaster->ODEDerivatives(x + a2*h, y_buf, der2);

  for (Int_t i = 0; i < mN; ++i)
    y_buf(i) = y(i) + h*(b31*dydx(i) + b32*der2(i));
  hTrueMaster->ODEDerivatives(x + a3*h, y_buf, der3);

  for (Int_t i = 0; i < mN; ++i)
    y_buf(i) = y(i) + h*(b41*dydx(i) + b42*der2(i) + b43*der3(i));
  hTrueMaster->ODEDerivatives(x + a4*h, y_buf, der4);

  for (Int_t i = 0; i < mN; ++i)
    y_buf(i) = y(i) + h*(b51*dydx(i) + b52*der2(i) + b53*der3(i) + b54*der4(i));
  hTrueMaster->ODEDerivatives(x + a5*h, y_buf, der5);

  for (Int_t i = 0; i < mN; ++i)
    y_buf(i) = y(i) + h*(b61*dydx(i) + b62*der2(i) + b63*der3(i) + b64*der4(i) + b65*der5(i));
  hTrueMaster->ODEDerivatives(x + a6*h, y_buf, der6);

  for (Int_t i = 0; i < mN; ++i)
    yout(i) = y(i) + h*(c1*dydx(i) + c3*der3(i) + c4*der4(i) + c6*der6(i));

  for (Int_t i = 0; i < mN; ++i)
    yerr(i) = h*(dc1*dydx(i) + dc3*der3(i) + dc4*der4(i) + dc5*der5(i) + dc6*der6(i));
}

/**************************************************************************/

void ODECrawler::Integrate()
{
  // Integrate ODE with derivatives provided by mODEMaster from X1 to X2.

  static const Exc_t _eh("ODECrawler::Integrate ");

  Double_t x, h, h_last, h_next;
  Double_t xsav = 0;

  x = mX1;
  h = TMath::Sign(mH1, mX2-mX1);
  TVectorD y(mY);
  TVectorD yscal(mN), dydx(mN);
  if (mStoreMax != 0) xsav = x - 2*mStoreDx;
  for (Int_t nstp = 0; nstp < mMaxSteps; ++nstp)
  {
    hTrueMaster->ODEDerivatives(x, y, dydx);
    for (Int_t i = 0; i < mN; ++i)
    {
      yscal(i) = TMath::Abs(y(i)) + TMath::Abs(dydx(i)*h) + hTINY;
    }

    if (mStoreMax < 0 ||
        (mStoreMax > 0 && mStored < mStoreMax - 1 &&
         TMath::Abs(x - xsav) > TMath::Abs(mStoreDx)))
    {
      mStorage->AddEntry(x, y.GetMatrixArray());
      ++mStored;
      xsav = x;
    }

    if ((x + h - mX2)*(x + h - mX1) > 0) h = mX2 - x;

    if (Rkqs(y, dydx, x, h, yscal, h_last, h_next)) return;

    if (h_last == h)
      ++mGuessesOK;
    else
      ++mGuessesBad;

    if ((x - mX2)*(mX2 - mX1) >= 0)
    {
      mY = y;
      if (mStoreMax != 0)
      {
        mStorage->AddEntry(x, y.GetMatrixArray());
	++mStored;
      }
      return;
    }
    if (TMath::Abs(h_next) <= mHmin)
    {
      throw (_eh + GForm("Step size too small, h_next=%g.", h_next));
    }
    h = h_next;
  }
  throw (_eh + GForm("Too many steps, MaxSteps=%d.", mMaxSteps));
}

/**************************************************************************/

void ODECrawler::Crawl(Bool_t call_ode_start)
{
  // Integrate with given master / parameters.
  // If called via a MIR it is executed in a broadcasted detached thread.
  //
  // The object is locked for the duration of the execution.

  static const Exc_t _eh("ODECrawler::Crawl ");

  {
    GLensReadHolder rdlock(this);

    if (hCrawling)
      throw(_eh + "already crawling.");

    assert_odemaster(_eh);

    hTrueMaster = dynamic_cast<ODECrawlerMaster*>(*mODEMaster);
    if (!hTrueMaster)
      throw(_eh + "master not an ODECrawlerMaster.");

    hCrawling = true;
  }

  init_integration(call_ode_start);
  Integrate();

  {
    GLensReadHolder rdlock(this);

    hCrawling = false;
    Stamp(FID());
  }
}

void ODECrawler::ChangeOrderInPlace(Int_t order)
{
  mN = order;
  if (mY.GetNoElements() != mN)
    mY.ResizeTo(mN);
}

Double_t* ODECrawler::RawYArray()
{
  return mY.GetMatrixArray();
}
 ODECrawler.cxx:1
 ODECrawler.cxx:2
 ODECrawler.cxx:3
 ODECrawler.cxx:4
 ODECrawler.cxx:5
 ODECrawler.cxx:6
 ODECrawler.cxx:7
 ODECrawler.cxx:8
 ODECrawler.cxx:9
 ODECrawler.cxx:10
 ODECrawler.cxx:11
 ODECrawler.cxx:12
 ODECrawler.cxx:13
 ODECrawler.cxx:14
 ODECrawler.cxx:15
 ODECrawler.cxx:16
 ODECrawler.cxx:17
 ODECrawler.cxx:18
 ODECrawler.cxx:19
 ODECrawler.cxx:20
 ODECrawler.cxx:21
 ODECrawler.cxx:22
 ODECrawler.cxx:23
 ODECrawler.cxx:24
 ODECrawler.cxx:25
 ODECrawler.cxx:26
 ODECrawler.cxx:27
 ODECrawler.cxx:28
 ODECrawler.cxx:29
 ODECrawler.cxx:30
 ODECrawler.cxx:31
 ODECrawler.cxx:32
 ODECrawler.cxx:33
 ODECrawler.cxx:34
 ODECrawler.cxx:35
 ODECrawler.cxx:36
 ODECrawler.cxx:37
 ODECrawler.cxx:38
 ODECrawler.cxx:39
 ODECrawler.cxx:40
 ODECrawler.cxx:41
 ODECrawler.cxx:42
 ODECrawler.cxx:43
 ODECrawler.cxx:44
 ODECrawler.cxx:45
 ODECrawler.cxx:46
 ODECrawler.cxx:47
 ODECrawler.cxx:48
 ODECrawler.cxx:49
 ODECrawler.cxx:50
 ODECrawler.cxx:51
 ODECrawler.cxx:52
 ODECrawler.cxx:53
 ODECrawler.cxx:54
 ODECrawler.cxx:55
 ODECrawler.cxx:56
 ODECrawler.cxx:57
 ODECrawler.cxx:58
 ODECrawler.cxx:59
 ODECrawler.cxx:60
 ODECrawler.cxx:61
 ODECrawler.cxx:62
 ODECrawler.cxx:63
 ODECrawler.cxx:64
 ODECrawler.cxx:65
 ODECrawler.cxx:66
 ODECrawler.cxx:67
 ODECrawler.cxx:68
 ODECrawler.cxx:69
 ODECrawler.cxx:70
 ODECrawler.cxx:71
 ODECrawler.cxx:72
 ODECrawler.cxx:73
 ODECrawler.cxx:74
 ODECrawler.cxx:75
 ODECrawler.cxx:76
 ODECrawler.cxx:77
 ODECrawler.cxx:78
 ODECrawler.cxx:79
 ODECrawler.cxx:80
 ODECrawler.cxx:81
 ODECrawler.cxx:82
 ODECrawler.cxx:83
 ODECrawler.cxx:84
 ODECrawler.cxx:85
 ODECrawler.cxx:86
 ODECrawler.cxx:87
 ODECrawler.cxx:88
 ODECrawler.cxx:89
 ODECrawler.cxx:90
 ODECrawler.cxx:91
 ODECrawler.cxx:92
 ODECrawler.cxx:93
 ODECrawler.cxx:94
 ODECrawler.cxx:95
 ODECrawler.cxx:96
 ODECrawler.cxx:97
 ODECrawler.cxx:98
 ODECrawler.cxx:99
 ODECrawler.cxx:100
 ODECrawler.cxx:101
 ODECrawler.cxx:102
 ODECrawler.cxx:103
 ODECrawler.cxx:104
 ODECrawler.cxx:105
 ODECrawler.cxx:106
 ODECrawler.cxx:107
 ODECrawler.cxx:108
 ODECrawler.cxx:109
 ODECrawler.cxx:110
 ODECrawler.cxx:111
 ODECrawler.cxx:112
 ODECrawler.cxx:113
 ODECrawler.cxx:114
 ODECrawler.cxx:115
 ODECrawler.cxx:116
 ODECrawler.cxx:117
 ODECrawler.cxx:118
 ODECrawler.cxx:119
 ODECrawler.cxx:120
 ODECrawler.cxx:121
 ODECrawler.cxx:122
 ODECrawler.cxx:123
 ODECrawler.cxx:124
 ODECrawler.cxx:125
 ODECrawler.cxx:126
 ODECrawler.cxx:127
 ODECrawler.cxx:128
 ODECrawler.cxx:129
 ODECrawler.cxx:130
 ODECrawler.cxx:131
 ODECrawler.cxx:132
 ODECrawler.cxx:133
 ODECrawler.cxx:134
 ODECrawler.cxx:135
 ODECrawler.cxx:136
 ODECrawler.cxx:137
 ODECrawler.cxx:138
 ODECrawler.cxx:139
 ODECrawler.cxx:140
 ODECrawler.cxx:141
 ODECrawler.cxx:142
 ODECrawler.cxx:143
 ODECrawler.cxx:144
 ODECrawler.cxx:145
 ODECrawler.cxx:146
 ODECrawler.cxx:147
 ODECrawler.cxx:148
 ODECrawler.cxx:149
 ODECrawler.cxx:150
 ODECrawler.cxx:151
 ODECrawler.cxx:152
 ODECrawler.cxx:153
 ODECrawler.cxx:154
 ODECrawler.cxx:155
 ODECrawler.cxx:156
 ODECrawler.cxx:157
 ODECrawler.cxx:158
 ODECrawler.cxx:159
 ODECrawler.cxx:160
 ODECrawler.cxx:161
 ODECrawler.cxx:162
 ODECrawler.cxx:163
 ODECrawler.cxx:164
 ODECrawler.cxx:165
 ODECrawler.cxx:166
 ODECrawler.cxx:167
 ODECrawler.cxx:168
 ODECrawler.cxx:169
 ODECrawler.cxx:170
 ODECrawler.cxx:171
 ODECrawler.cxx:172
 ODECrawler.cxx:173
 ODECrawler.cxx:174
 ODECrawler.cxx:175
 ODECrawler.cxx:176
 ODECrawler.cxx:177
 ODECrawler.cxx:178
 ODECrawler.cxx:179
 ODECrawler.cxx:180
 ODECrawler.cxx:181
 ODECrawler.cxx:182
 ODECrawler.cxx:183
 ODECrawler.cxx:184
 ODECrawler.cxx:185
 ODECrawler.cxx:186
 ODECrawler.cxx:187
 ODECrawler.cxx:188
 ODECrawler.cxx:189
 ODECrawler.cxx:190
 ODECrawler.cxx:191
 ODECrawler.cxx:192
 ODECrawler.cxx:193
 ODECrawler.cxx:194
 ODECrawler.cxx:195
 ODECrawler.cxx:196
 ODECrawler.cxx:197
 ODECrawler.cxx:198
 ODECrawler.cxx:199
 ODECrawler.cxx:200
 ODECrawler.cxx:201
 ODECrawler.cxx:202
 ODECrawler.cxx:203
 ODECrawler.cxx:204
 ODECrawler.cxx:205
 ODECrawler.cxx:206
 ODECrawler.cxx:207
 ODECrawler.cxx:208
 ODECrawler.cxx:209
 ODECrawler.cxx:210
 ODECrawler.cxx:211
 ODECrawler.cxx:212
 ODECrawler.cxx:213
 ODECrawler.cxx:214
 ODECrawler.cxx:215
 ODECrawler.cxx:216
 ODECrawler.cxx:217
 ODECrawler.cxx:218
 ODECrawler.cxx:219
 ODECrawler.cxx:220
 ODECrawler.cxx:221
 ODECrawler.cxx:222
 ODECrawler.cxx:223
 ODECrawler.cxx:224
 ODECrawler.cxx:225
 ODECrawler.cxx:226
 ODECrawler.cxx:227
 ODECrawler.cxx:228
 ODECrawler.cxx:229
 ODECrawler.cxx:230
 ODECrawler.cxx:231
 ODECrawler.cxx:232
 ODECrawler.cxx:233
 ODECrawler.cxx:234
 ODECrawler.cxx:235
 ODECrawler.cxx:236
 ODECrawler.cxx:237
 ODECrawler.cxx:238
 ODECrawler.cxx:239
 ODECrawler.cxx:240
 ODECrawler.cxx:241
 ODECrawler.cxx:242
 ODECrawler.cxx:243
 ODECrawler.cxx:244
 ODECrawler.cxx:245
 ODECrawler.cxx:246
 ODECrawler.cxx:247
 ODECrawler.cxx:248
 ODECrawler.cxx:249
 ODECrawler.cxx:250
 ODECrawler.cxx:251
 ODECrawler.cxx:252
 ODECrawler.cxx:253
 ODECrawler.cxx:254
 ODECrawler.cxx:255
 ODECrawler.cxx:256
 ODECrawler.cxx:257
 ODECrawler.cxx:258
 ODECrawler.cxx:259
 ODECrawler.cxx:260
 ODECrawler.cxx:261
 ODECrawler.cxx:262
 ODECrawler.cxx:263
 ODECrawler.cxx:264
 ODECrawler.cxx:265
 ODECrawler.cxx:266
 ODECrawler.cxx:267
 ODECrawler.cxx:268
 ODECrawler.cxx:269
 ODECrawler.cxx:270
 ODECrawler.cxx:271
 ODECrawler.cxx:272
 ODECrawler.cxx:273
 ODECrawler.cxx:274
 ODECrawler.cxx:275
 ODECrawler.cxx:276
 ODECrawler.cxx:277
 ODECrawler.cxx:278
 ODECrawler.cxx:279
 ODECrawler.cxx:280
 ODECrawler.cxx:281
 ODECrawler.cxx:282
 ODECrawler.cxx:283
 ODECrawler.cxx:284
 ODECrawler.cxx:285
 ODECrawler.cxx:286
 ODECrawler.cxx:287
 ODECrawler.cxx:288
 ODECrawler.cxx:289
 ODECrawler.cxx:290
 ODECrawler.cxx:291
 ODECrawler.cxx:292
 ODECrawler.cxx:293
 ODECrawler.cxx:294
 ODECrawler.cxx:295
 ODECrawler.cxx:296
 ODECrawler.cxx:297
 ODECrawler.cxx:298
 ODECrawler.cxx:299
 ODECrawler.cxx:300
 ODECrawler.cxx:301
 ODECrawler.cxx:302
 ODECrawler.cxx:303
 ODECrawler.cxx:304
 ODECrawler.cxx:305
 ODECrawler.cxx:306
 ODECrawler.cxx:307
 ODECrawler.cxx:308
 ODECrawler.cxx:309
 ODECrawler.cxx:310
 ODECrawler.cxx:311
 ODECrawler.cxx:312
 ODECrawler.cxx:313
 ODECrawler.cxx:314
 ODECrawler.cxx:315
 ODECrawler.cxx:316
 ODECrawler.cxx:317
 ODECrawler.cxx:318
 ODECrawler.cxx:319
 ODECrawler.cxx:320
 ODECrawler.cxx:321
 ODECrawler.cxx:322
 ODECrawler.cxx:323
 ODECrawler.cxx:324
 ODECrawler.cxx:325