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