CMS 3D CMS Logo

DoublePadeDelay.h
Go to the documentation of this file.
1 #ifndef CalibCalorimetry_HcalAlgos_DoublePadeDelay_h_
2 #define CalibCalorimetry_HcalAlgos_DoublePadeDelay_h_
3 
4 #include <cassert>
5 #include <algorithm>
6 
8 
9 //
10 // Two differential equations using the Pade delay scheme. The control
11 // equation and the output equation are coupled only via the timing
12 // parameter of the output equation (this timing is determined by the
13 // control output). In this particular model, there is no feedback from
14 // the output into the control.
15 //
16 template<class ODE1, class ODE2, class DelayTimeModel1, class DelayTimeModel2>
18 {
19 public:
20  inline DoublePadeDelay(const unsigned padeRow1, const unsigned padeColumn1,
21  const unsigned padeRow2, const unsigned padeColumn2)
22  : ode1_(padeRow1, padeColumn1), ode2_(padeRow2, padeColumn2)
23  {
24  validate();
25  }
26 
27  inline DoublePadeDelay(const unsigned padeRow1, const unsigned padeColumn1,
28  const unsigned padeRow2, const unsigned padeColumn2,
30  : AbsElectronicODERHS(pulse),
31  ode1_(padeRow1, padeColumn1),
32  ode2_(padeRow2, padeColumn2)
33  {
34  validate();
35  }
36 
37  inline virtual DoublePadeDelay* clone() const
38  {return new DoublePadeDelay(*this);}
39 
40  inline virtual void calc(const double t,
41  const double* x, const unsigned lenX,
42  double* derivative)
43  {
44  if (!allParametersSet()) throw cms::Exception(
45  "In DoublePadeDelay::calc: timing and/or ODE parameters not set");
46 
47  // The input signal
48  const double currentIn = inputPulse_(t);
49 
50  // The output signal
51  const double currentOut = x[outputNode()];
52 
53  // Numbers of parameters used by the member objects
54  const unsigned npTau1 = tau1_.nParameters();
55  const unsigned npOde1 = ode1_.nParameters();
56  const unsigned npTau2 = tau2_.nParameters();
57  const unsigned npOde2 = ode2_.nParameters();
58 
59  // Parameters for this code.
60  // Order of parameters in the overall parameter set is:
61  // parameters for tau1, then for ode1, then tau2, then ode2,
62  // then parameters of this code.
63  const double* pstart = &params_[npTau1 + npOde1 + npTau2 + npOde2];
64  const double* pars = pstart;
65  const double ctlGainOut = *pars++;
66  const double inGainOut = *pars++;
67  const double outGainOut = *pars++;
68  assert(thisCodeNumPars == static_cast<unsigned>(pars - pstart));
69 
70  // Save a little bit of time by not calculating the input
71  // signal derivatives in case they will not be needed
72  const unsigned row = std::max(ode1_.getPadeRow(), ode2_.getPadeRow());
73  const double dIdt = row ? inputPulse_.derivative(t) : 0.0;
74  const double d2Id2t = row > 1U ? inputPulse_.secondDerivative(t) : 0.0;
75 
76  // Set the timing parameters of the control circuit
77  unsigned firstPar = npTau1 + npOde1;
78  const double tau2 = tau2_(currentIn, &params_[firstPar], npTau2);
79 
80  // Set the ODE parameters for the control circuit
81  firstPar += npTau2;
82  if (npOde2)
83  ode2_.setParameters(&params_[firstPar], npOde2);
84 
85  // Run the control circuit
86  const unsigned ctrlNode = controlNode();
87  double control;
88  if (ctrlNode < AbsElectronicODERHS::invalidNode)
89  {
90  // The control circuit solves an ODE
91  control = x[ctrlNode];
92  ode2_.calculate(tau2, currentIn, dIdt, d2Id2t,
93  x, lenX, ctrlNode, derivative);
94  }
95  else
96  {
97  // The control circuit does not solve an ODE.
98  // Instead, it drives its output directly.
99  ode2_.calculate(tau2, currentIn, dIdt, d2Id2t,
100  0, 0U, 0U, &control);
101  }
102 
103  // Timing parameter for the output circuit (the preamp)
104  const double vtau = ctlGainOut*control +
105  inGainOut*currentIn +
106  outGainOut*currentOut;
107  const double tau = tau1_(vtau, &params_[0], npTau1);
108 
109  // ODE parameters for the output circuit
110  if (npOde1)
111  ode1_.setParameters(&params_[npTau1], npOde1);
112 
113  // Run the output circuit
114  ode1_.calculate(tau, currentIn, dIdt, d2Id2t, x, lenX, 0U, derivative);
115  }
116 
117  inline unsigned numberOfNodes() const
118  {return ode1_.getPadeColumn() + ode2_.getPadeColumn();}
119 
120  inline unsigned nParameters() const
121  {
122  const unsigned npTau1 = tau1_.nParameters();
123  const unsigned npOde1 = ode1_.nParameters();
124  const unsigned npTau2 = tau2_.nParameters();
125  const unsigned npOde2 = ode2_.nParameters();
126  return npTau1 + npOde1 + npTau2 + npOde2 + thisCodeNumPars;
127  }
128 
129  inline unsigned outputNode() const {return 0U;}
130 
131  // The second ODE is the one for control. It's output node
132  // is the control node.
133  inline unsigned controlNode() const
134  {
135  if (ode2_.getPadeColumn())
136  // ode2 has a real output node
137  return ode1_.getPadeColumn();
138  else
139  // ode2 does not have a real output node
141  }
142 
143 private:
144  static const unsigned thisCodeNumPars = 3U;
145 
146  inline void validate() const
147  {
148  // Basically, we need to avoid the situation in which
149  // we need to solve the differential equation for the control
150  // circuit but do not need to solve the differential equation
151  // for the preamp. It this case we will not have a good way
152  // to pass the preamp output to the simulator. The simplest
153  // way to ensure correctness of the whole procedure is to require
154  // that the preamp must always be modeled by an ODE. Indeed,
155  // one will almost surely need to represent it by at least
156  // a low-pass filter.
157  if (!ode1_.getPadeColumn()) throw cms::Exception(
158  "In DoublePadeDelay::validate: the output "
159  "circuit must be modeled by an ODE");
160  }
161 
162  ODE1 ode1_;
163  ODE2 ode2_;
164  DelayTimeModel1 tau1_;
165  DelayTimeModel2 tau2_;
166 };
167 
168 #endif // CalibCalorimetry_HcalAlgos_DoublePadeDelay_h_
unsigned nParameters() const
DoublePadeDelay(const unsigned padeRow1, const unsigned padeColumn1, const unsigned padeRow2, const unsigned padeColumn2, const HcalInterpolatedPulse &pulse)
DelayTimeModel2 tau2_
static const unsigned invalidNode
Derivative< X, A >::type derivative(const A &_)
Definition: Derivative.h:18
std::vector< double > params_
unsigned numberOfNodes() const
double secondDerivative(const double t) const
unsigned controlNode() const
DoublePadeDelay(const unsigned padeRow1, const unsigned padeColumn1, const unsigned padeRow2, const unsigned padeColumn2)
void validate() const
DelayTimeModel1 tau1_
unsigned outputNode() const
double pulse(double x, double y, double z, double t)
static const unsigned thisCodeNumPars
HcalInterpolatedPulse inputPulse_
bool allParametersSet() const
virtual void calc(const double t, const double *x, const unsigned lenX, double *derivative)
virtual DoublePadeDelay * clone() const
double derivative(const double t) const