ROOT logo
// $Id: ODECrawler.cxx 2481 2011-06-19 06:05:23Z matevz $

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

#include <TMath.h>

#include <gsl/gsl_errno.h>
#include <gsl/gsl_odeiv.h>

//==============================================================================
// GSL -> OdeCrawlerMaster wrappers
//==============================================================================

namespace
{
  int ode_crawler_der_foo(double t, const double y[], double dydt[], void* ud)
  {
    ((ODECrawlerMaster*)ud)->ODEDerivatives(t, y, dydt);
    return GSL_SUCCESS;
  }

  int ode_crawler_jac_foo(double t, const double y[], double* dfdy, double dfdt[], void* ud)
  {
    ((ODECrawlerMaster*)ud)->ODEJacobian(t, y, dfdy, dfdt);
    return GSL_SUCCESS;
  }
}


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

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

ClassImp(ODECrawlerMaster);


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

//______________________________________________________________________________
//
// ODE integrator using adaptive step functions from GSL.
// 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.
//
// 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).
// Start and end points (at x1 and x2) are always stored, unless mStoreMax=0.
//
// Example glass Moonraker. Macro moonraker.C.
//________________________________________________________________________

ClassImp(ODECrawler);

void ODECrawler::_init()
{
  m_true_master = 0;
  m_crawling    = false;

  m_gsl_system  = new gsl_odeiv_system;
  m_gsl_system->function = ode_crawler_der_foo;
  m_gsl_system->jacobian = ode_crawler_jac_foo;

  m_gsl_evolve  = 0;
  m_gsl_control = 0;
  m_gsl_step    = 0;

  mStepOK = mStepChanged = mStored = 0;
  mMaxSteps  = 1000000; mStoreDx = 0.001; mStoreMax = -1;
  mStorage   = 0;
  mEpsAbs    = 0; mEpsRel = 1e-8; mFacVal = 1; mFacDer = 0;
  mH1 = 1e-2; mHmin = 1e-18; mH = 0; bStoreH = true;
  mStepFunc = SF_RKF45; mPrevStepFunc = (StepFunc_e) -1;
  mX1 = mX2 = 0;
}

ODECrawler::ODECrawler(const Text_t* n, const Text_t* t) :
  ZGlass(n,t)
{
  _init();
}

ODECrawler::~ODECrawler()
{
  delete mStorage;

  _gsl_free();
  delete m_gsl_system;
}

//==============================================================================

const gsl_odeiv_step_type* ODECrawler::s_get_step_func(ODECrawler::StepFunc_e sf)
{
  switch (sf)
  {
    case SF_RK2:    return gsl_odeiv_step_rk2;
    case SF_RK4:    return gsl_odeiv_step_rk4;
    case SF_RKF45:  return gsl_odeiv_step_rkf45;
    case SF_RKCK:   return gsl_odeiv_step_rkck;
    case SF_RK8PD:  return gsl_odeiv_step_rk8pd;
    case SF_RK2Imp: return gsl_odeiv_step_rk2imp;
    case SF_RK4Imp: return gsl_odeiv_step_rk4imp;
    case SF_BSImp:  return gsl_odeiv_step_bsimp;
    case SF_Gear1:  return gsl_odeiv_step_gear1;
    case SF_Gear2:  return gsl_odeiv_step_gear2;
    default:        return 0;
  }
}

void ODECrawler::_gsl_alloc()
{
  m_gsl_system->dimension = mN;
  m_gsl_system->params    = m_true_master;

  m_gsl_step    = gsl_odeiv_step_alloc(s_get_step_func(mStepFunc), mN);
  m_gsl_control = gsl_odeiv_control_standard_new(mEpsAbs, mEpsRel, mFacVal, mFacDer);
  m_gsl_evolve  = gsl_odeiv_evolve_alloc(mN);
}

void ODECrawler::_gsl_free()
{
  gsl_odeiv_evolve_free(m_gsl_evolve);
  gsl_odeiv_control_free(m_gsl_control);
  gsl_odeiv_step_free(m_gsl_step);
}

//==============================================================================

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.
  // m_true_master must be set.

  mN = m_true_master->ODEOrder();

  if ((Int_t) mY.size() != mN || mStepFunc != mPrevStepFunc)
  {
    mY.resize(mN);
    _gsl_free();
    _gsl_alloc();
  }
  else
  {
    gsl_odeiv_control_init(m_gsl_control, mEpsAbs, mEpsRel, mFacVal, mFacDer);
    gsl_odeiv_evolve_reset(m_gsl_evolve);
  }

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

  mStepOK = mStepChanged = mStored = 0;

  if (call_ode_start)
    m_true_master->ODEStart(&mY[0], mX1, mX2);
}

//------------------------------------------------------------------------------

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;
  Double_t xsav = 0;

  x = mX1;
  h = TMath::Sign((bStoreH && mH != 0) ? mH : mH1, mX2 - mX1);

  if (mStoreMax != 0)
  {
    mStorage->AddEntry(x, &mY[0]);
    ++mStored;
    xsav = x;
  }

  Int_t n_step = 0;

  while (x != mX2)
  {
    if (++n_step > mMaxSteps)
    {
      throw _eh + GForm("Too many steps, MaxSteps=%d.", mMaxSteps);
    }

    h_last = h;

    int err = gsl_odeiv_evolve_apply(m_gsl_evolve, m_gsl_control, m_gsl_step,
				     m_gsl_system, &x, mX2, &h,
				     &mY[0]);
    if (err != GSL_SUCCESS)
    {
      throw _eh + GForm("gsl error %d: %s", err, gsl_strerror(err));
    }

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

    if (h_last == h)
      ++mStepOK;
    else
      ++mStepChanged;

    if (TMath::Abs(h) <= mHmin)
    {
      throw _eh + GForm("Step size too small, h=%g.", h);
    }
  }

  if (mStoreMax != 0)
  {
    mStorage->AddEntry(x, &mY[0]);
    ++mStored;
  }

  mH = bStoreH ? TMath::Abs(h) : 0;
}

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

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 (m_crawling)
      throw _eh + "already crawling.";

    assert_odemaster(_eh);

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

    m_crawling = true;
  }

  Exc_t exc_p;
  try
  {
    init_integration(call_ode_start);
    Integrate();
  }
  catch (Exc_t& exc)
  {
    exc_p = exc;
  }

  {
    GLensReadHolder rdlock(this);

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

  if (!exc_p.IsNull()) throw exc_p;
}

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

Double_t* ODECrawler::RawYArray()
{
  return &mY[0];
}
 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
 ODECrawler.cxx:326
 ODECrawler.cxx:327
 ODECrawler.cxx:328
 ODECrawler.cxx:329
 ODECrawler.cxx:330
 ODECrawler.cxx:331
 ODECrawler.cxx:332
 ODECrawler.cxx:333
 ODECrawler.cxx:334
 ODECrawler.cxx:335
 ODECrawler.cxx:336
 ODECrawler.cxx:337
 ODECrawler.cxx:338
 ODECrawler.cxx:339
 ODECrawler.cxx:340
 ODECrawler.cxx:341
 ODECrawler.cxx:342
 ODECrawler.cxx:343
 ODECrawler.cxx:344