CMS 3D CMS Logo

QIE8Simulator.cc
Go to the documentation of this file.
1 #include <cmath>
2 #include <cfloat>
3 
5 
7  : preampOutputCut_(-1.0e100), inputGain_(1.0),
8  outputGain_(1.0), runCount_(0),
9  chargeNode_(AbsElectronicODERHS::invalidNode),
10  integrateToGetCharge_(false),
11  useCubic_(false)
12 {
13 }
14 
16  const unsigned chargeNode,
17  const bool interpolateCubic,
18  const double preampOutputCut,
19  const double inputGain,
20  const double outputGain)
21  : solver_(model),
22  preampOutputCut_(preampOutputCut),
23  inputGain_(inputGain),
24  outputGain_(outputGain),
25  runCount_(0),
26  chargeNode_(chargeNode),
27  useCubic_(interpolateCubic)
28 {
29  if (chargeNode >= AbsElectronicODERHS::invalidNode)
30  throw cms::Exception(
31  "In QIE8Simulator constructor: invalid charge collection node");
32  integrateToGetCharge_ = chargeNode == model.outputNode();
33  validateGain();
35 }
36 
37 unsigned QIE8Simulator::run(const double dt, const double tstop,
38  const double tDigitize,
39  double* TS, const unsigned lenTS)
40 {
42  throw cms::Exception(
43  "In QIE8Simulator::run: preamp model is not set");
44 
45  // Check arguments for validity
46  if (dt <= 0.0) throw cms::Exception(
47  "In QIE8Simulator::run: invalid time step");
48 
49  if (tstop < dt) throw cms::Exception(
50  "In QIE8Simulator::run: invalid stopping time");
51 
52  if (lenTS && tDigitize < 0.0) throw cms::Exception(
53  "In QIE8Simulator::run: can't digitize at t < 0");
54 
55  // Determine the number of time steps
56  const double dsteps = tstop/dt;
57  unsigned n = dsteps;
58  if (dsteps != static_cast<double>(n))
59  ++n;
60  if (n >= maxlen)
61  n = maxlen - 1;
62 
63  // Run the simulation
65  const unsigned numNodes = rhs.numberOfNodes();
66  if (numNodes)
67  {
68  assert(initialConditions_.size() == numNodes);
69  solver_.run(&initialConditions_[0], numNodes, dt, n);
70  }
71  else
72  {
73  // Special situation: the simulation does not
74  // need to solve any ODE. Instead, it will fill
75  // out the output directly.
76  if (!(integrateToGetCharge_ && chargeNode_ == 0U))
77  throw cms::Exception("In QIE8Simulator::run: "
78  "invalid mode of operation");
79  const unsigned runLen = n + 1U;
80  if (historyBuffer_.size() < runLen)
81  historyBuffer_.resize(runLen);
82  double* hbuf = &historyBuffer_[0];
83  for (unsigned istep=0; istep<runLen; ++istep, ++hbuf)
84  rhs.calc(istep*dt, 0, 0U, hbuf);
85  solver_.setHistory(dt, &historyBuffer_[0], 1U, runLen);
86  }
87 
88  // Truncate the preamp output if this will affect subsequent results
89  if (integrateToGetCharge_ && preampOutputCut_ > -0.9e100)
91 
92  // Digitize the accumulated charge
93  unsigned filled = 0;
94  if (lenTS)
95  {
96  assert(TS);
97  const double lastTStop = solver_.lastMaxT();
98  const double tsWidth = this->adcTSWidth();
99  double oldCharge = getCharge(tDigitize);
100  for (unsigned its=0; its<lenTS; ++its)
101  {
102  const double t0 = tDigitize + its*tsWidth;
103  if (t0 < lastTStop)
104  {
105  double t1 = t0 + tsWidth;
106  if (t1 > lastTStop)
107  t1 = lastTStop;
108  else
109  ++filled;
110  const double q = getCharge(t1);
111  TS[its] = (q - oldCharge)*outputGain_;
112  oldCharge = q;
113  }
114  else
115  TS[its] = 0.0;
116  }
117  }
118  ++runCount_;
119  return filled;
120 }
121 
122 double QIE8Simulator::preampOutput(const double t) const
123 {
124  if (!runCount_) throw cms::Exception(
125  "In QIE8Simulator::preampOutput: please run the simulation first");
126  const unsigned preampNode = getRHS().outputNode();
127  if (preampNode >= AbsElectronicODERHS::invalidNode)
128  return 0.0;
129  else
131  preampNode, t, useCubic_);
132 }
133 
134 double QIE8Simulator::controlOutput(const double t) const
135 {
136  if (!runCount_) throw cms::Exception(
137  "In QIE8Simulator::controlOutput: please run the simulation first");
138  const unsigned controlNode = getRHS().controlNode();
139  if (controlNode >= AbsElectronicODERHS::invalidNode)
140  return 0.0;
141  else
142  return solver_.interpolateCoordinate(controlNode, t, useCubic_);
143 }
144 
146 {
147  if (!runCount_) throw cms::Exception(
148  "In QIE8Simulator::preampPeakTime: please run the simulation first");
149  const unsigned preampNode = getRHS().outputNode();
150  if (preampNode >= AbsElectronicODERHS::invalidNode) throw cms::Exception(
151  "In QIE8Simulator::preampPeakTime: no preamp node in the circuit");
152  return solver_.getPeakTime(preampNode);
153 }
154 
156  const double* values, const unsigned sz)
157 {
158  const unsigned nExpected = getRHS().numberOfNodes();
159  if (sz != nExpected) throw cms::Exception(
160  "In QIE8Simulator::setInitialConditions: unexpected number "
161  "of initial conditions");
162  assert(sz == initialConditions_.size());
163  if (sz)
164  {
165  double* c = &initialConditions_[0];
166  for (unsigned i=0; i<sz; ++i)
167  *c++ = *values++;
168  }
169 }
170 
172  const unsigned chargeNode,
173  const bool useCubicInterpolation)
174 {
175  if (chargeNode >= AbsElectronicODERHS::invalidNode)
176  throw cms::Exception(
177  "In QIE8Simulator::setRHS invalid charge collection node");
178  solver_.setRHS(rhs);
179  chargeNode_ = chargeNode;
180  integrateToGetCharge_ = chargeNode == rhs.outputNode();
181  useCubic_ = useCubicInterpolation;
183 }
184 
186 {
187  const unsigned sz = getRHS().numberOfNodes();
188  if (initialConditions_.size() != sz)
189  initialConditions_.resize(sz);
190  if (sz)
191  {
192  double* c = &initialConditions_[0];
193  for (unsigned i=0; i<sz; ++i)
194  *c++ = 0.0;
195  }
196 }
197 
199 {
200  if (inputGain_ <= 0.0) throw cms::Exception(
201  "In QIE8Simulator::validateGain: invalid input gain");
202 }
203 
205 {
206  if (!runCount_) throw cms::Exception(
207  "In QIE8Simulator::lastStopTime: please run the simulation first");
208  return solver_.lastMaxT();
209 }
210 
211 double QIE8Simulator::totalIntegratedCharge(const double t) const
212 {
213  if (!runCount_) throw cms::Exception(
214  "In QIE8Simulator::totalIntegratedCharge: "
215  "please run the simulation first");
216  return outputGain_*getCharge(t);
217 }
double preampPeakTime() const
float dt
Definition: AMPTWrapper.h:126
int i
Definition: DBlmapReader.cc:9
virtual unsigned numberOfNodes() const =0
static const unsigned invalidNode
std::vector< double > initialConditions_
unsigned chargeNode_
double preampOutputCut_
double totalIntegratedCharge(double t) const
bool integrateToGetCharge_
double lastStopTime() const
virtual unsigned outputNode() const =0
unsigned long runCount_
static double adcTSWidth()
std::vector< double > historyBuffer_
void setInitialConditions(const double *values, const unsigned len)
double getPeakTime(unsigned which) const
virtual unsigned controlNode() const
const AbsElectronicODERHS & getRHS() const
Definition: QIE8Simulator.h:31
void validateGain() const
void setRHS(const AbsODERHS &rhs)
virtual void calc(double t, const double *x, unsigned lenX, double *derivative)=0
void setRHS(const AbsElectronicODERHS &rhs, unsigned chargeNode, bool interpolateCubic=false)
AbsElectronicODERHS & modifiableRHS()
double getCharge(const double t) const
double interpolateCoordinate(unsigned which, double t, bool cubic=false) const
void run(const double *initialConditions, unsigned lenConditions, double dt, unsigned nSteps)
double outputGain_
double preampOutput(double t) const
void truncateCoordinate(unsigned which, double minValue, double maxValue)
unsigned run(double dt, double tstop, double tDigitize, double *TS, unsigned lenTS)
void zeroInitialConditions()
void setHistory(double dt, const double *data, unsigned dim, unsigned runLen)
static const unsigned maxlen
Definition: QIE8Simulator.h:14
double controlOutput(double t) const