CMS 3D CMS Logo

ConstantStepOdeSolver.cc
Go to the documentation of this file.
1 #include <cassert>
2 
4 
5 inline static double interpolateLinear(const double x, const double f0,
6  const double f1)
7 {
8  return f0*(1.0 - x) + f1*x;
9 }
10 
11 double ConstantStepOdeSolver::getPeakTime(const unsigned which) const
12 {
13  if (which >= dim_) throw cms::Exception(
14  "In ConstantStepOdeSolver::getPeakTime: index out of range");
15  if (runLen_ < 3) throw cms::Exception(
16  "In ConstantStepOdeSolver::getPeakTime: not enough data");
17 
18  const double* hbuf = &historyBuffer_[which];
19  double maxval = hbuf[0];
20  unsigned maxind = 0;
21  for (unsigned i=1; i<runLen_; ++i)
22  if (hbuf[dim_*i] > maxval)
23  {
24  maxval = hbuf[dim_*i];
25  maxind = i;
26  }
27  if (maxind == 0U)
28  return 0.0;
29  if (maxind == runLen_-1U)
30  return dt_*maxind;
31  const double l = hbuf[dim_*(maxind - 1U)];
32  const double r = hbuf[dim_*(maxind + 1U)];
33  if (l < maxval || r < maxval)
34  return dt_*(maxind + (l - r)/2.0/(l + r - 2.0*maxval));
35  else
36  return dt_*maxind;
37 }
38 
40  const unsigned which, const unsigned idx) const
41 {
42  if (which >= dim_ || idx >= runLen_) throw cms::Exception(
43  "In ConstantStepOdeSolver::getIntegrated: index out of range");
44  if (lastIntegrated_ != which)
45  (const_cast<ConstantStepOdeSolver*>(this))->integrateCoordinate(which);
46  return chargeBuffer_[idx];
47 }
48 
50 {
51  if (runLen_ < 4) throw cms::Exception(
52  "In ConstantStepOdeSolver::integrateCoordinate: not enough data");
53  if (chargeBuffer_.size() < runLen_)
54  chargeBuffer_.resize(runLen_);
55  double* integ = &chargeBuffer_[0];
56  const double* coord = &historyBuffer_[which];
57 
58  integ[0] = 0.0;
59  integ[1] = coord[dim_*0]*(3.0/8.0) +
60  coord[dim_*1]*(19.0/24.0) +
61  coord[dim_*2]*(-5.0/24.0) +
62  coord[dim_*3]*(1.0/24.0);
63  long double sum = integ[1];
64  const unsigned rlenm1 = runLen_ - 1U;
65  for (unsigned i=2; i<rlenm1; ++i)
66  {
67  sum += (coord[dim_*(i-2U)]*(-1.0/24.0) +
68  coord[dim_*(i-1U)]*(13.0/24.0) +
69  coord[dim_*i] *(13.0/24.0) +
70  coord[dim_*(i+1U)]*(-1.0/24.0));
71  integ[i] = sum;
72  }
73  sum += (coord[dim_*rlenm1] *(3.0/8.0) +
74  coord[dim_*(rlenm1-1U)]*(19.0/24.0) +
75  coord[dim_*(rlenm1-2U)]*(-5.0/24.0) +
76  coord[dim_*(rlenm1-3U)]*(1.0/24.0));
77  integ[rlenm1] = sum;
78  if (dt_ != 1.0)
79  for (unsigned i=1; i<runLen_; ++i)
80  integ[i] *= dt_;
82 }
83 
85  const double dt,
86  const bool cubic) const
87 {
88  os << "# " << this->methodName() << '\n';
89  if (dim_ && runLen_)
90  {
91  if (dt == dt_)
92  {
93  for (unsigned ipt=0; ipt<runLen_; ++ipt)
94  {
95  os << getTime(ipt);
96  for (unsigned which=0; which<dim_; ++which)
97  os << ' ' << getCoordinate(which, ipt);
98  os << '\n';
99  }
100  }
101  else
102  {
103  const double tmax = lastMaxT();
104  for (unsigned i=0; ; ++i)
105  {
106  const double t = i*dt;
107  if (t > tmax)
108  break;
109  os << t;
110  for (unsigned which=0; which<dim_; ++which)
111  os << ' ' << interpolateCoordinate(which, t, cubic);
112  os << '\n';
113  }
114  }
115  }
116 }
117 
119  const unsigned which,
120  const double dt,
121  const bool cubic) const
122 {
123  os << "# " << this->methodName() << '\n';
124  if (dim_ && runLen_)
125  {
126  if (dt == dt_)
127  {
128  for (unsigned ipt=0; ipt<runLen_; ++ipt)
129  os << getTime(ipt) << ' ' << getIntegrated(which, ipt) << '\n';
130  }
131  else
132  {
133  const double tmax = lastMaxT();
134  for (unsigned i=0; ; ++i)
135  {
136  const double t = i*dt;
137  if (t > tmax)
138  break;
139  os << t << ' ' << interpolateIntegrated(which, t, cubic) << '\n';
140  }
141  }
142  }
143 }
144 
146  : rhs_(nullptr),
147  dt_(r.dt_),
148  dim_(r.dim_),
149  runLen_(r.runLen_),
153 {
154  if (r.rhs_)
155  rhs_ = r.rhs_->clone();
156 }
157 
159  const ConstantStepOdeSolver& r)
160 {
161  if (this != &r)
162  {
163  delete rhs_; rhs_ = nullptr;
164  dt_ = r.dt_;
165  dim_ = r.dim_;
166  runLen_ = r.runLen_;
170  if (r.rhs_)
171  rhs_ = r.rhs_->clone();
172  }
173  return *this;
174 }
175 
177  const double minValue,
178  const double maxValue)
179 {
180  if (which >= dim_) throw cms::Exception(
181  "In ConstantStepOdeSolver::truncateCoordinate: index out of range");
182  if (minValue > maxValue) throw cms::Exception(
183  "In ConstantStepOdeSolver::truncateCoordinate: invalid truncation range");
184 
185  double* buf = &historyBuffer_[which];
186  for (unsigned i=0; i<runLen_; ++i)
187  {
188  if (buf[dim_*i] < minValue)
189  buf[dim_*i] = minValue;
190  else if (buf[dim_*i] > maxValue)
191  buf[dim_*i] = maxValue;
192  }
193 }
194 
196  const unsigned which, const double t, const bool cubic) const
197 {
198  if (which >= dim_) throw cms::Exception(
199  "In ConstantStepOdeSolver::interpolateCoordinate: index out of range");
200  if (runLen_ < 2U || (cubic && runLen_ < 4U)) throw cms::Exception(
201  "In ConstantStepOdeSolver::interpolateCoordinate: not enough data");
202  const double maxt = runLen_ ? dt_*(runLen_-1U) : 0.0;
203  if (t < 0.0 || t > maxt) throw cms::Exception(
204  "In ConstantStepOdeSolver::interpolateCoordinate: time out of range");
205 
206  const double* arr = &historyBuffer_[0];
207  if (t == 0.0)
208  return arr[which];
209  else if (t == maxt)
210  return arr[which + dim_*(runLen_-1U)];
211 
212  // Translate time into timestep units
213  const double tSteps = t/dt_;
214  unsigned nLow = tSteps;
215  if (nLow >= runLen_ - 1)
216  nLow = runLen_ - 2;
217  double x = tSteps - nLow;
218 
219  if (cubic)
220  {
221  unsigned i0 = 0;
222  if (nLow == runLen_ - 2)
223  {
224  i0 = nLow - 2U;
225  x += 2.0;
226  }
227  else if (nLow)
228  {
229  i0 = nLow - 1U;
230  x += 1.0;
231  }
232  const double* base = arr + (which + dim_*i0);
233  return interpolateLinear(x*(3.0 - x)/2.0,
234  interpolateLinear(x/3.0, base[0], base[dim_*3]),
235  interpolateLinear(x-1.0, base[dim_], base[dim_*2]));
236  }
237  else
238  return interpolateLinear(x, arr[which+dim_*nLow], arr[which+dim_*(nLow+1U)]);
239 }
240 
242  const unsigned which, const double t, const bool cubic) const
243 {
244  if (which >= dim_) throw cms::Exception(
245  "In ConstantStepOdeSolver::interpolateIntegrated: index out of range");
246  if (runLen_ < 2U || (cubic && runLen_ < 4U)) throw cms::Exception(
247  "In ConstantStepOdeSolver::interpolateIntegrated: not enough data");
248  const double maxt = runLen_ ? dt_*(runLen_-1U) : 0.0;
249  if (t < 0.0 || t > maxt) throw cms::Exception(
250  "In ConstantStepOdeSolver::interpolateIntegrated: time out of range");
251  if (lastIntegrated_ != which)
252  (const_cast<ConstantStepOdeSolver*>(this))->integrateCoordinate(which);
253 
254  const double* buf = &chargeBuffer_[0];
255  if (t == 0.0)
256  return buf[0];
257  else if (t == maxt)
258  return buf[runLen_-1U];
259 
260  // Translate time into timestep units
261  const double tSteps = t/dt_;
262  unsigned nLow = tSteps;
263  if (nLow >= runLen_ - 1)
264  nLow = runLen_ - 2;
265  double x = tSteps - nLow;
266 
267  if (cubic)
268  {
269  unsigned i0 = 0;
270  if (nLow == runLen_ - 2)
271  {
272  i0 = nLow - 2U;
273  x += 2.0;
274  }
275  else if (nLow)
276  {
277  i0 = nLow - 1U;
278  x += 1.0;
279  }
280  const double* base = buf + i0;
281  return interpolateLinear(x*(3.0 - x)/2.0,
282  interpolateLinear(x/3.0, base[0], base[3]),
283  interpolateLinear(x-1.0, base[1], base[2]));
284  }
285  else
286  return interpolateLinear(x, buf[nLow], buf[nLow+1U]);
287 }
288 
289 void ConstantStepOdeSolver::setHistory(const double dt, const double* data,
290  const unsigned dim, const unsigned runLen)
291 {
292  const unsigned len = dim*runLen;
293  if (!len)
294  return;
295  if (dt <= 0.0) throw cms::Exception(
296  "In ConstantStepOdeSolver::setHistory: can not run backwards in time");
297  assert(data);
298  const unsigned sz = dim*(runLen + 1U);
299  if (historyBuffer_.size() < sz)
300  historyBuffer_.resize(sz);
301  dt_ = dt;
302  dim_ = dim;
303  runLen_ = runLen;
305  double* arr = &historyBuffer_[0];
306  for (unsigned i=0; i<len; ++i)
307  *arr++ = *data++;
308  for (unsigned i=0; i<dim; ++i)
309  *arr++ = 0.0;
310 }
311 
312 void ConstantStepOdeSolver::run(const double* initialConditions,
313  const unsigned lenInitialConditions,
314  const double dt, const unsigned nSteps)
315 {
316  if (!nSteps || !lenInitialConditions)
317  return;
318  if (!rhs_) throw cms::Exception(
319  "In ConstantStepOdeSolver::run: ODE right hand side has not been set");
320  if (dt <= 0.0) throw cms::Exception(
321  "In ConstantStepOdeSolver::run: can not run backwards in time");
322  assert(initialConditions);
323  dt_ = dt;
324  dim_ = lenInitialConditions;
326  runLen_ = nSteps + 1U;
327  const unsigned sz = (runLen_+1U)*dim_;
328  if (historyBuffer_.size() < sz)
329  historyBuffer_.resize(sz);
330  double* arr = &historyBuffer_[0];
331  for (unsigned i=0; i<lenInitialConditions; ++i)
332  arr[i] = initialConditions[i];
333  double* stepBuffer = arr + runLen_*dim_;
334 
335  for (unsigned i = 0; i < nSteps; ++i, arr += lenInitialConditions)
336  {
337  const double t = i*dt;
338  this->step(t, dt, arr, lenInitialConditions, stepBuffer);
339  double* next = arr + lenInitialConditions;
340  for (unsigned i=0; i<lenInitialConditions; ++i)
341  next[i] = arr[i] + stepBuffer[i];
342  }
343 }
344 
345 void EulerOdeSolver::step(const double t, const double dt,
346  const double* x, const unsigned lenX,
347  double* coordIncrement) const
348 {
349  rhs_->calc(t, x, lenX, coordIncrement);
350  for (unsigned i=0; i<lenX; ++i)
351  coordIncrement[i] *= dt;
352 }
353 
354 void RK2::step(const double t, const double dt,
355  const double* x, const unsigned lenX,
356  double* coordIncrement) const
357 {
358  const double halfstep = dt/2.0;
359  if (buf_.size() < lenX)
360  buf_.resize(lenX);
361  double* midpoint = &buf_[0];
362  rhs_->calc(t, x, lenX, midpoint);
363  for (unsigned i=0; i<lenX; ++i)
364  {
365  midpoint[i] *= halfstep;
366  midpoint[i] += x[i];
367  }
368  rhs_->calc(t + halfstep, midpoint, lenX, coordIncrement);
369  for (unsigned i=0; i<lenX; ++i)
370  coordIncrement[i] *= dt;
371 }
372 
373 void RK4::step(const double t, const double dt,
374  const double* x, const unsigned lenX,
375  double* coordIncrement) const
376 {
377  const double halfstep = dt/2.0;
378  if (buf_.size() < 4*lenX)
379  buf_.resize(4*lenX);
380  double* k1x = &buf_[0];
381  double* k2x = k1x + lenX;
382  double* k3x = k2x + lenX;
383  double* k4x = k3x + lenX;
384  rhs_->calc(t, x, lenX, k1x);
385  for (unsigned i=0; i<lenX; ++i)
386  coordIncrement[i] = x[i] + halfstep*k1x[i];
387  rhs_->calc(t + halfstep, coordIncrement, lenX, k2x);
388  for (unsigned i=0; i<lenX; ++i)
389  coordIncrement[i] = x[i] + halfstep*k2x[i];
390  rhs_->calc(t + halfstep, coordIncrement, lenX, k3x);
391  for (unsigned i=0; i<lenX; ++i)
392  coordIncrement[i] = x[i] + dt*k3x[i];
393  rhs_->calc(t + dt, coordIncrement, lenX, k4x);
394  for (unsigned i=0; i<lenX; ++i)
395  coordIncrement[i] = dt/6.0*(k1x[i] + 2.0*(k2x[i] + k3x[i]) + k4x[i]);
396 }
static double interpolateLinear(const double x, const double f0, const double f1)
double getCoordinate(const unsigned which, const unsigned idx) const
float dt
Definition: AMPTWrapper.h:126
double interpolateIntegrated(unsigned which, double t, bool cubic=false) const
double getTime(const unsigned idx) const
#define nullptr
void step(double t, double dt, const double *x, unsigned lenX, double *coordIncrement) const override
std::vector< double > chargeBuffer_
virtual AbsODERHS * clone() const =0
double getPeakTime(unsigned which) const
void step(double t, double dt, const double *x, unsigned lenX, double *coordIncrement) const override
double getIntegrated(unsigned which, unsigned idx) const
void writeIntegrated(std::ostream &os, unsigned which, double dt, bool cubic=false) const
base
Make Sure CMSSW is Setup ##.
void integrateCoordinate(const unsigned which)
virtual void calc(double t, const double *x, unsigned lenX, double *derivative)=0
static const double tmax[3]
ConstantStepOdeSolver & operator=(const ConstantStepOdeSolver &r)
double interpolateCoordinate(unsigned which, double t, bool cubic=false) const
std::vector< double > historyBuffer_
void run(const double *initialConditions, unsigned lenConditions, double dt, unsigned nSteps)
void step(double t, double dt, const double *x, unsigned lenX, double *coordIncrement) const override
char data[epos_bytes_allocation]
Definition: EPOS_Wrapper.h:82
void truncateCoordinate(unsigned which, double minValue, double maxValue)
virtual const char * methodName() const =0
def which(cmd)
Definition: eostools.py:335
void writeHistory(std::ostream &os, double dt, bool cubic=false) const
void setHistory(double dt, const double *data, unsigned dim, unsigned runLen)
virtual void step(double t, double dt, const double *x, unsigned lenX, double *coordIncrement) const =0