CMS 3D CMS Logo

InterpolatedPulse.h
Go to the documentation of this file.
1 #ifndef CondFormats_HcalObjects_InterpolatedPulse_h_
2 #define CondFormats_HcalObjects_InterpolatedPulse_h_
3 
4 #include <cassert>
6 
7 #include "boost/serialization/access.hpp"
8 #include "boost/serialization/version.hpp"
9 
10 template<unsigned MaxLen>
12 {
13  template <unsigned Len2> friend class InterpolatedPulse;
14 
15 public:
16  // Would normally do "static const" but genreflex has problems for it
17  enum {maxlen = MaxLen};
18 
19  // Default constructor creates a pulse which is zero everywhere
21  : tmin_(0.0), width_(1.0), length_(2U)
22  {
23  zeroOut();
24  }
25 
26  // Constructor from a single integer creates a pulse with the given
27  // number of discrete steps which is zero everywhere
28  inline explicit InterpolatedPulse(const unsigned len)
29  : tmin_(0.0), width_(1.0), length_(len)
30  {
31  if (length_ < 2 || length_ > MaxLen) throw cms::Exception(
32  "In InterpolatedPulse constructor: invalid length");
33  zeroOut();
34  }
35 
36  inline InterpolatedPulse(const double tmin, const double tmax,
37  const unsigned len)
38  : tmin_(tmin), width_(tmax - tmin), length_(len)
39  {
40  if (length_ < 2 || length_ > MaxLen) throw cms::Exception(
41  "In InterpolatedPulse constructor: invalid length");
42  if (width_ <= 0.0) throw cms::Exception(
43  "In InterpolatedPulse constructor: invalid pulse width");
44  zeroOut();
45  }
46 
47  template <typename Real>
48  inline InterpolatedPulse(const double tmin, const double tmax,
49  const Real* values, const unsigned len)
50  : tmin_(tmin), width_(tmax - tmin)
51  {
52  if (width_ <= 0.0) throw cms::Exception(
53  "In InterpolatedPulse constructor: invalid pulse width");
54  setShape(values, len);
55  }
56 
57  // Efficient copy constructor. Do not copy undefined values.
59  : tmin_(r.tmin_), width_(r.width_), length_(r.length_)
60  {
61  double* buf = &pulse_[0];
62  const double* rbuf = &r.pulse_[0];
63  for (unsigned i=0; i<length_; ++i)
64  *buf++ = *rbuf++;
65  }
66 
67  // Converting copy constructor
68  template <unsigned Len2>
70  : tmin_(r.tmin_), width_(r.width_), length_(r.length_)
71  {
72  if (length_ > MaxLen) throw cms::Exception(
73  "In InterpolatedPulse copy constructor: buffer is not long enough");
74  double* buf = &pulse_[0];
75  const double* rbuf = &r.pulse_[0];
76  for (unsigned i=0; i<length_; ++i)
77  *buf++ = *rbuf++;
78  }
79 
80  // Efficient assignment operator
82  {
83  if (this != &r)
84  {
85  tmin_ = r.tmin_;
86  width_ = r.width_;
87  length_ = r.length_;
88  double* buf = &pulse_[0];
89  const double* rbuf = &r.pulse_[0];
90  for (unsigned i=0; i<length_; ++i)
91  *buf++ = *rbuf++;
92  }
93  return *this;
94  }
95 
96  // Converting assignment operator
97  template <unsigned Len2>
99  {
100  if (r.length_ > MaxLen) throw cms::Exception(
101  "In InterpolatedPulse::operator=: buffer is not long enough");
102  tmin_ = r.tmin_;
103  width_ = r.width_;
104  length_ = r.length_;
105  double* buf = &pulse_[0];
106  const double* rbuf = &r.pulse_[0];
107  for (unsigned i=0; i<length_; ++i)
108  *buf++ = *rbuf++;
109  return *this;
110  }
111 
112  template <typename Real>
113  inline void setShape(const Real* values, const unsigned len)
114  {
115  if (len < 2 || len > MaxLen) throw cms::Exception(
116  "In InterpolatedPulse::setShape: invalid length");
117  assert(values);
118  length_ = len;
119  double* buf = &pulse_[0];
120  for (unsigned i=0; i<len; ++i)
121  *buf++ = *values++;
122  }
123 
124  // Zero out the signal
125  inline void zeroOut()
126  {
127  for (unsigned i=0; i<length_; ++i)
128  pulse_[i] = 0.0;
129  }
130 
131  // Simple inspectors
132  inline const double* getPulse() const {return &pulse_[0];}
133  inline unsigned getLength() const {return length_;}
134  inline double getStartTime() const {return tmin_;}
135  inline double getStopTime() const {return tmin_ + width_;}
136  inline double getPulseWidth() const {return width_;}
137  inline double getTimeStep() const {return width_/(length_ - 1U);}
138 
139  // Simple modifiers
140  inline void setStartTime(const double newStartTime)
141  {tmin_ = newStartTime;}
142 
143  inline void setPulseWidth(const double newWidth)
144  {
145  if (newWidth <= 0.0) throw cms::Exception(
146  "In InterpolatedPulse::setPulseWidth: invalid pulse width");
147  width_ = newWidth;
148  }
149 
150  // Get the pulse value at the given time using linear interpolation
151  inline double operator()(const double t) const
152  {
153  const volatile double tmax = tmin_ + width_;
154  if (t < tmin_ || t > tmax)
155  return 0.0;
156  const unsigned lm1 = length_ - 1U;
157  const double step = width_/lm1;
158  const double nSteps = (t - tmin_)/step;
159  unsigned nbelow = nSteps;
160  unsigned nabove = nbelow + 1;
161  if (nabove > lm1)
162  {
163  nabove = lm1;
164  nbelow = nabove - 1U;
165  }
166  const double delta = nSteps - nbelow;
167  return pulse_[nbelow]*(1.0 - delta) + pulse_[nabove]*delta;
168  }
169 
170  inline double derivative(const double t) const
171  {
172  const volatile double tmax = tmin_ + width_;
173  if (t < tmin_ || t > tmax)
174  return 0.0;
175  const unsigned lm1 = length_ - 1U;
176  const double step = width_/lm1;
177  const double nSteps = (t - tmin_)/step;
178  unsigned nbelow = nSteps;
179  unsigned nabove = nbelow + 1;
180  if (nabove > lm1)
181  {
182  nabove = lm1;
183  nbelow = nabove - 1U;
184  }
185  const double delta = nSteps - nbelow;
186  if ((nbelow == 0U && delta <= 0.5) || (nabove == lm1 && delta >= 0.5))
187  return (pulse_[nabove] - pulse_[nbelow])/step;
188  else if (delta >= 0.5)
189  {
190  const double lower = pulse_[nabove] - pulse_[nbelow];
191  const double upper = pulse_[nabove+1U] - pulse_[nabove];
192  return (upper*(delta - 0.5) + lower*(1.5 - delta))/step;
193  }
194  else
195  {
196  const double lower = pulse_[nbelow] - pulse_[nbelow-1U];
197  const double upper = pulse_[nabove] - pulse_[nbelow];
198  return (lower*(0.5 - delta) + upper*(0.5 + delta))/step;
199  }
200  }
201 
202  inline double secondDerivative(const double t) const
203  {
204  const volatile double tmax = tmin_ + width_;
205  if (t < tmin_ || t > tmax || length_ < 3U)
206  return 0.0;
207  const unsigned lm1 = length_ - 1U;
208  const double step = width_/lm1;
209  const double stepSq = step*step;
210  const double nSteps = (t - tmin_)/step;
211  unsigned nbelow = nSteps;
212  unsigned nabove = nbelow + 1;
213  if (nabove > lm1)
214  {
215  nabove = lm1;
216  nbelow = nabove - 1U;
217  }
218 
219  if (nbelow == 0U)
220  {
221  // The first interval
222  return (pulse_[2] - 2.0*pulse_[1] + pulse_[0])/stepSq;
223  }
224  else if (nabove == lm1)
225  {
226  // The last interval
227  return (pulse_[lm1] - 2.0*pulse_[lm1-1U] + pulse_[lm1-2U])/stepSq;
228  }
229  else
230  {
231  // One of the middle intervals
232  const double lower = pulse_[nbelow-1U] - 2.0*pulse_[nbelow] + pulse_[nabove];
233  const double upper = pulse_[nbelow] - 2.0*pulse_[nabove] + pulse_[nabove+1U];
234  const double delta = nSteps - nbelow;
235  return (lower*(1.0 - delta) + upper*delta)/stepSq;
236  }
237  }
238 
239  inline InterpolatedPulse& operator*=(const double scale)
240  {
241  if (scale != 1.0)
242  {
243  double* buf = &pulse_[0];
244  for (unsigned i=0; i<length_; ++i)
245  *buf++ *= scale;
246  }
247  return *this;
248  }
249 
250  // Add another pulse to this one. Note that addition of another pulse
251  // will not change the start time or the width of _this_ pulse. The
252  // added pulse will be truncated as needed.
253  template <unsigned Len2>
255  {
256  const double step = width_/(length_ - 1U);
257  for (unsigned i=0; i<length_; ++i)
258  pulse_[i] += r(tmin_ + i*step);
259  return *this;
260  }
261 
262  template <unsigned Len2>
263  inline bool operator==(const InterpolatedPulse<Len2>& r) const
264  {
265  if (!(tmin_ == r.tmin_ && width_ == r.width_ && length_ == r.length_))
266  return false;
267  const double* buf = &pulse_[0];
268  const double* rbuf = &r.pulse_[0];
269  for (unsigned i=0; i<length_; ++i)
270  if (*buf++ != *rbuf++)
271  return false;
272  return true;
273  }
274 
275  template <unsigned Len2>
276  inline bool operator!=(const InterpolatedPulse<Len2>& r) const
277  {return !(*this == r);}
278 
279  // Simple trapezoidal integration
280  inline double getIntegral() const
281  {
282  const double* buf = &pulse_[0];
283  long double sum = buf[0]/2.0;
284  const unsigned nIntervals = length_ - 1U;
285  for (unsigned i=1U; i<nIntervals; ++i)
286  sum += buf[i];
287  sum += buf[nIntervals]/2.0;
288  return sum*width_/nIntervals;
289  }
290 
291  inline void setIntegral(const double newValue)
292  {
293  const double integ = this->getIntegral();
294  if (integ == 0.0) throw cms::Exception(
295  "In InterpolatedPulse::setIntegral division by zero");
296  *this *= (newValue/integ);
297  }
298 
299  inline double getPeakValue() const
300  {
301  const double* buf = &pulse_[0];
302  double peak = buf[0];
303  for (unsigned i=1U; i<length_; ++i)
304  if (buf[i] > peak)
305  peak = buf[i];
306  return peak;
307  }
308 
309  inline void setPeakValue(const double newValue)
310  {
311  const double peak = this->getPeakValue();
312  if (peak == 0.0) throw cms::Exception(
313  "In InterpolatedPulse::setPeakValue: division by zero");
314  *this *= (newValue/peak);
315  }
316 
317 private:
318  double pulse_[MaxLen];
319  double tmin_;
320  double width_;
321  unsigned length_;
322 
323  friend class boost::serialization::access;
324 
325  template<class Archive>
326  inline void serialize(Archive & ar, unsigned /* version */)
327  {
328  ar & tmin_ & width_ & length_;
329 
330  // In case we are reading, it may be useful to verify
331  // that the length is reasonable
332  if (length_ > MaxLen) throw cms::Exception(
333  "In InterpolatedPulse::serialize: buffer is not long enough");
334 
335  for (unsigned i=0; i<length_; ++i)
336  ar & pulse_[i];
337  }
338 };
339 
340 // boost serialization version number for this template
341 namespace boost {
342  namespace serialization {
343  template<unsigned MaxLen>
344  struct version<InterpolatedPulse<MaxLen> >
345  {
346  BOOST_STATIC_CONSTANT(int, value = 1);
347  };
348  }
349 }
350 
351 #endif // CondFormats_HcalObjects_InterpolatedPulse_h_
dbl * delta
Definition: mlp_gen.cc:36
bool operator!=(const InterpolatedPulse< Len2 > &r) const
Definition: CLHEP.h:16
void setStartTime(const double newStartTime)
void serialize(Archive &ar, unsigned)
double pulse_[MaxLen]
double getIntegral() const
double secondDerivative(const double t) const
InterpolatedPulse & operator+=(const InterpolatedPulse< Len2 > &r)
void setShape(const Real *values, const unsigned len)
InterpolatedPulse(const double tmin, const double tmax, const unsigned len)
InterpolatedPulse(const double tmin, const double tmax, const Real *values, const unsigned len)
const double * getPulse() const
double getPeakValue() const
InterpolatedPulse & operator=(const InterpolatedPulse< Len2 > &r)
double operator()(const double t) const
Definition: value.py:1
double getStartTime() const
InterpolatedPulse(const InterpolatedPulse< Len2 > &r)
double getStopTime() const
static const double tmax[3]
double Real
InterpolatedPulse & operator=(const InterpolatedPulse &r)
bool operator==(const InterpolatedPulse< Len2 > &r) const
double getTimeStep() const
double getPulseWidth() const
InterpolatedPulse(const InterpolatedPulse &r)
InterpolatedPulse & operator*=(const double scale)
unsigned getLength() const
void setPeakValue(const double newValue)
step
Definition: StallMonitor.cc:94
double derivative(const double t) const
void setPulseWidth(const double newWidth)
void setIntegral(const double newValue)
InterpolatedPulse(const unsigned len)