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