9 #include <beast/csi/geometry/CsiGeometryPar.h>
10 #include <beast/csi/modules/CsIDigitizerModule.h>
11 #include <beast/csi/dataobjects/CsiDigiHit.h>
12 #include <beast/csi/dataobjects/CsiSimHit.h>
13 #include <beast/csi/dataobjects/CsiHit.h>
14 #include <framework/dataobjects/EventMetaData.h>
15 #include <framework/datastore/StoreObjPtr.h>
21 #include <framework/core/RandomNumbers.h>
25 #define PI 3.14159265358979323846
43 m_aDigiHit("CsiDigiHits"),
44 m_calibConstants(16, 5),
45 m_noiseLevels(16, 0.25e-3),
55 setDescription(
"Digitizer for the BEAST CsI system");
58 addParam(
"Resolution", m_Resolution,
"Resolution (in mV) of the ACD", 4.8828e-4);
59 addParam(
"SampleRate", m_SampleRate,
"Sample rate (in samples/sec) of the ADC", 250e6);
60 addParam(
"nWaveforms", m_nWaveforms,
"Number of waveforms to save. 0: none, -1: all ", 0);
63 CsIDigitizerModule::~CsIDigitizerModule()
67 void CsIDigitizerModule::initialize()
70 B2DEBUG(100,
"Initializing ");
73 m_aSimHit.isRequired();
74 m_aDigiHit.registerInDataStore();
77 m_dt = 1e9 / m_SampleRate;
82 for (uint i = 0; i != m_LY.size(); ++i) {
92 for (
int i = 8; i < 16; i++) {
98 void CsIDigitizerModule::beginRun()
103 void CsIDigitizerModule::event()
106 int m_currentEventNumber = eventMetaDataPtr->getEvent();
108 B2DEBUG(80,
"Digitingevent " << m_currentEventNumber);
111 if (m_aSimHit.getEntries() > 0) {
112 int hitNum = m_aSimHit.getEntries();
117 for (
int i = 0 ; i < 16 ; i++) {
118 m_SimHitTimes[i].clear();
119 m_SimHitEdeps[i].clear();
123 B2DEBUG(150,
"Looping over CsISimHits");
124 for (
int i = 0; i < hitNum; i++) {
137 double localPos = (15. - (hitPos - cellPos) *
141 double propagTime = m_SampleRate *
142 (0.0600 * localPos + (tof / CLHEP::ns)) * 1E-9;
145 m_SimHitTimes[m_cellID].push_back(propagTime);
146 m_SimHitEdeps[m_cellID].push_back(edep);
161 for (
int iCh = 0; iCh < 16; iCh++) {
163 int n = m_SimHitTimes[iCh].size();
167 B2DEBUG(140,
"Generating Time signal");
169 m_TrueEdep = genTimeSignal(&tempSignal, m_SimHitEdeps[iCh], m_SimHitTimes[iCh], iCh, m_dt, m_nSamples,
false);
172 B2DEBUG(140,
"Launching Charge integration");
173 bool recordWaveform =
false;
174 if ((m_nWaveforms == -1) || (m_nWFcounter < m_nWaveforms)) {
176 recordWaveform =
true;
177 B2DEBUG(80,
"Recording WF");
179 uint16_t max = doChargeIntegration(tempSignal, 128, &m_Baseline, &m_Charge, &m_Time, &m_Waveform,
180 &m_DPPCIBits, 5, 1.2e4, 1e4, 1e3, recordWaveform);
183 m_aDigiHit.appendNew();
184 m_hitNum = m_aDigiHit.getEntries() - 1;
185 m_aDigiHit[m_hitNum]->setCellId(iCh);
186 m_aDigiHit[m_hitNum]->setCharge(m_Charge);
187 m_aDigiHit[m_hitNum]->setTime(m_Time);
188 m_aDigiHit[m_hitNum]->setBaseline(m_Baseline);
189 m_aDigiHit[m_hitNum]->setTrueEdep(m_TrueEdep);
191 m_aDigiHit[m_hitNum]->setMaxVal(max);
193 m_aDigiHit[m_hitNum]->setWaveform(&m_Waveform);
194 m_aDigiHit[m_hitNum]->setStatusBits(&m_DPPCIBits);
202 void CsIDigitizerModule::endRun()
206 void CsIDigitizerModule::terminate()
210 uint16_t CsIDigitizerModule::doChargeIntegration(
Signal _u,
int _NsamBL, uint16_t* _BSL, uint32_t* _Q,
211 uint32_t* _t, vector<uint16_t>* _Waveform,
212 vector<uint8_t>* _DPPCIBits,
int _Treshold,
213 double _TriggerHoldoff,
double _GateWidth,
214 double _GateOffset,
bool _recordTraces)
217 B2DEBUG(80,
"Arguments: " << &_u <<
", " << _NsamBL <<
", " << _BSL <<
", " << _Q <<
", " << _t
218 <<
", " << _Waveform <<
", " << _Treshold <<
", " << _TriggerHoldoff <<
", " << _GateWidth
219 <<
", " << _GateOffset <<
", " << _recordTraces);
221 vector<int> x = doDigitization(_u, m_Resolution);
225 TH1I h_trigger(
"h_trigger",
"Trigger", nSam, 0, nSam - 1);
226 TH1I h_gate(
"h_gate",
"Gate", nSam, 0, nSam - 1);
227 TH1I h_holdoff(
"h_holdoff",
"Holdoff", nSam, 0, nSam - 1);
228 TH1I h_baseline(
"h_baseline",
"Baseline", nSam, 0, nSam - 1);
229 TH1I h_charge(
"h_charge",
"Charge", nSam, 0, nSam - 1);
230 TH1F h_signal(
"h_signal",
"Continous signal", nSam, 0, nSam - 1);
231 TH1I h_digsig(
"h_digsig",
"Digital signal", nSam, 0, nSam - 1);
234 int max_gated = (int) floor(_GateWidth / m_dt);
235 int gate_offset = (int) floor(_GateOffset / m_dt);
236 int max_holdoff = (int) floor(_TriggerHoldoff / m_dt);
244 bool holdoff =
false;
246 bool trigger =
false;
250 int iFirstTrigger = 0;
251 list<int> baselineBuffer;
252 vector<int>::iterator it;
256 const double invMaxNavgBL = 1.0 / _NsamBL;
259 _Waveform->resize(nSam, 0);
260 _DPPCIBits->resize(nSam, 0);
262 B2DEBUG(140,
"Scanning vector: all should have nSam=" << nSam);
266 for (it = x.begin(); (it != x.end()); ++it, ++i) {
271 _Waveform->at(i) = *it;
272 _DPPCIBits->at(i) = trigger + (gate << 1) + (holdoff << 2) + (stop << 3);
276 h_trigger.Fill(i, (
int) trigger) ;
277 h_gate.Fill(i, (
int) gate) ;
278 h_holdoff.Fill(i, (
int) holdoff) ;
279 h_baseline.Fill(i, baseline) ;
280 h_charge.Fill(i, charge) ;
281 h_digsig.Fill(i, *it) ;
282 h_signal.Fill(i, _u.at(i)) ;
285 if (!gate && !holdoff) {
287 baselineBuffer.push_back(*it);
290 if ((i + 1) > _NsamBL) {
291 baselineBuffer.pop_front();
292 invNavgBL = invMaxNavgBL;
294 invNavgBL = (1.0 / i);
298 for (list<int>::iterator itbl = baselineBuffer.begin(); itbl != baselineBuffer.end(); ++itbl)
299 tempBaseline += (
float) * itbl;
301 tempBaseline *= invNavgBL;
303 baseline = (int) round(tempBaseline);
305 trigger = (*it - baseline) > _Treshold;
308 if (trigger && !iFirstTrigger)
314 charge += (*(it - gate_offset) - baseline);
326 holdoff = trigger || (holdoff && (n_holdoff < max_holdoff));
327 gate = trigger || (gate && (n_gated < max_gated));
329 stop = iFirstTrigger && !gate && !holdoff;
334 *_t = (uint)(iFirstTrigger + 2.0 * (gRandom->Rndm() - 0.5));
336 if (not(_recordTraces)) {
367 vector<int> CsIDigitizerModule::doDigitization(
Signal _v,
double _LSB)
369 vector<int> output(_v.size(), 0);
370 double invLSB = 1.0 / _LSB;
373 for (Signal::iterator it = _v.begin() ; it != _v.end(); ++it, ++i) {
374 output.at(i) = (int) round(*it * invLSB);
380 double CsIDigitizerModule::genTimeSignal(
Signal* _output,
Signal _energies,
Signal _times,
int _iChannel,
int _dt,
int _nsam,
384 double invdt = 1.0 / _dt;
388 double sumEnergies = 0.0;
390 for (Signal::iterator it = _times.begin() ; it != _times.end(); ++it) {
398 Signal edepos(_nsam, 0.0);
401 int ioffset = floor(_nsam * 0.25);
402 B2DEBUG(150,
"Filling edepos vector. Container length is " << _nsam);
404 for (Signal::iterator it = _times.begin() ; it != _times.end(); ++it, ++i) {
405 sumEnergies += _energies.at(i);
407 int timeIndex = ((int)(*it - t0) * invdt + ioffset);
408 if ((timeIndex - 1) > (int) edepos.size()) {
409 B2WARNING(
" genTimeSignal: TimeIndex greater than length of signal container. Skipping deposit of " << _energies.at(i) <<
"GeV");
411 edepos.at(timeIndex) += _energies.at(i);
415 B2DEBUG(80,
"Generating time responses for channel " << _iChannel);
416 B2DEBUG(80,
" Fast time constant " << m_tFast[_iChannel]);
417 B2DEBUG(80,
" Slow time constant " << m_tSlow[_iChannel]);
423 Signal Qcathode = firstOrderResponse((1 - m_tRatio[_iChannel]) * m_LY[_iChannel] * m_LCE[_iChannel] * m_PmtQE[_iChannel], edepos, 0,
424 _dt, m_tSlow[_iChannel], 0.0);
427 if (m_tRatio[_iChannel]) {
428 Signal QcathodeF = firstOrderResponse(m_tRatio[_iChannel] * m_LY[_iChannel] * m_LCE[_iChannel] * m_PmtQE[_iChannel], edepos, 0, _dt,
429 m_tFast[_iChannel], 0.0);
432 for (Signal::iterator it = Qcathode.begin() ; it != Qcathode.end(); ++it, ++j)
433 *it += QcathodeF.at(j);
436 Signal Vanode = firstOrderResponse(1.602e-10 * m_Zl * invdt * m_PmtGain[_iChannel], Qcathode, 0, _dt, m_tRisePMT, m_tTransitPMT);
439 B2DEBUG(150,
"Adding noise. Container length is " << Vanode.size());
440 addNoise(&Vanode, m_noiseLevels[_iChannel], 5e-3 * gRandom->Rndm() + 1e-2);
446 for (i = 1; i < _nsam; i++)
447 t.at(i) = t.at(i - 1) + _dt;
449 TGraph gPlot1(_nsam, &t[0], &edepos[0]);
450 gPlot1.SaveAs(
"EdeposOut.root");
452 TGraph gPlot2(_nsam, &t[0], &Qcathode[0]);
453 gPlot2.SaveAs(
"QOut.root");
455 TGraph gPlot3(_nsam, &t[0], &Vanode[0]);
456 gPlot3.SaveAs(
"VOut.root");
465 int CsIDigitizerModule::addNoise(
Signal* y,
double _rms,
double _offset)
467 for (Signal::iterator it = y->begin() ; it != y->end(); ++it)
468 *it += _offset + gRandom->Gaus(0, _rms);
491 Signal CsIDigitizerModule::firstOrderResponse(
double _gain,
Signal _u,
double _y0,
double _dt,
double _tau,
double _delay)
494 B2DEBUG(80,
"Generating 1st order response with arguments");
495 B2DEBUG(80,
" _gain: " << _gain);
496 B2DEBUG(80,
" length(_u): " << _u.size());
497 B2DEBUG(80,
" _y0: " << _y0);
498 B2DEBUG(80,
" _dt: " << _dt);
499 B2DEBUG(80,
" _tau: " << _tau);
500 B2DEBUG(80,
" _delay: " << _delay);
511 static const double invSix = 1.0 / 6.0;
512 double invtau = 1.0 / _tau;
516 int n_delay = (int) round(_delay / _dt);
517 Signal::iterator it = _u.begin();
518 double _u_0 = _u.front();
519 _u.insert(it , n_delay, _u_0);
523 for (
int i = 0, j = 0; i < (n - 1); i++) {
525 k[0] = f(i , _u[i], _u[j], y[i] , invtau);
526 k[1] = f(i + 0.5, _u[i], _u[j], y[i] + 0.5 * _dt * k[0], invtau);
527 k[2] = f(i + 0.5, _u[i], _u[j], y[i] + 0.5 * _dt * k[1], invtau);
528 k[3] = f(j , _u[i], _u[j], y[i] + _dt * k[2], invtau);
530 y.push_back(y[i] + _dt * invSix * (k[0] + 2 * k[1] + 2 * k[2] + k[3]));
536 for (Signal::iterator it2 = y.begin() ; it2 != y.end(); ++it2)
544 double CsIDigitizerModule::f(
double fi,
double u_i,
double u_j,
double y,
double invtau)
547 double u = u_i * (fi - floor(fi)) + u_j * (ceil(fi) - fi);
549 return u - invtau * y;
ClassCsiSimHit - Geant4 simulated hits in CsI crystals in BEAST.
int getCellId() const
Get Cell ID.
double getFlightTime() const
Get Flight time from IP.
double getEnergyDep() const
Get Deposit energy.
TVector3 getPosition() const
Get Position.
Type-safe access to single objects in the data store.
Digitizer for the BEAST CsI system.
The Class for CSI Geometry Parameters.
void Print(const int cid, int debuglevel=80)
Print crystal information.
TVector3 GetOrientationTV3(int cid)
Get the orientation of the crystal in a root TVector3.
TVector3 GetPositionTV3(int cid)
Get the position of the crystal in a root TVector3.
#define REG_MODULE(moduleName)
Register the given module (without 'Module' suffix) with the framework.
std::vector< double > Signal
Designed to hold a "continuous" (in time and amplitude) signal
Abstract base class for different kinds of events.