MdCounterSimulator.cc
Go to the documentation of this file.
1 #include "MdCounterSimulator.h"
2 
3 #include <evt/Event.h>
4 //
5 #include <sevt/SEvent.h>
6 #include <sevt/Station.h>
7 #include <sevt/StationTriggerData.h>
8 #include <sevt/StationSimData.h>
9 #include <sdet/SDetector.h>
10 //
11 #include <mdet/MDetector.h>
12 #include <mdet/Counter.h>
13 #include <mdet/Module.h>
14 #include <mdet/Scintillator.h>
15 #include <mdet/Fiber.h>
16 #include <mdet/PMT.h>
17 #include <mdet/FrontEnd.h>
18 #include <mdet/Pixel.h>
19 #include <mdet/SiPMArray.h>
20 #include <mdet/FrontEndSiPM.h>
21 #include <mdet/SiPM.h>
22 #include <mdet/ChannelSiPM.h>
23 //
24 #include <mevt/MEvent.h>
25 #include <mevt/Counter.h>
26 #include <mevt/Module.h>
27 #include <mevt/Scintillator.h>
28 #include <mevt/ScintillatorSimData.h>
29 //
30 #include <utl/Particle.h>
31 #include <utl/PhysicalConstants.h>
32 #include <utl/Trace.h>
33 #include <utl/RandomEngine.h>
34 #include <utl/FFTDataContainer.h>
35 #include <utl/AugerUnits.h>
36 #include <utl/MathConstants.h>
37 #include <utl/ConsecutiveEnumFactory.h>
38 #include <utl/Branch.h>
39 #include <utl/ConfigUtils.h>
40 #include <utl/TimeStamp.h>
41 #include <utl/TimeInterval.h>
42 #include <utl/TabularStream.h>
43 #include <utl/Segment.h>
44 #include <utl/Plane.h>
45 #include <utl/Point.h>
46 #include <utl/GeometryUtilities.h>
47 //
48 #include <fwk/CentralConfig.h>
49 #include <fwk/RandomEngineRegistry.h>
50 //
51 #include <CLHEP/Random/RandFlat.h>
52 //
53 #include <cfloat>
54 #include <algorithm>
55 #include <vector>
56 #include <iostream>
57 // "Standardaly" this is _the_ place for endl and so (see http://www.research.att.com/~bs/3rd_issues.html):
58 #include <iomanip>
59 #include <sstream>
60 #include <string>
61 //
62 #include <boost/algorithm/minmax_element.hpp>
63 #include <boost/tokenizer.hpp>
64 //
65 #include <TF1.h>
66 #include <TCanvas.h>
67 #include <TGraph.h>
68 #include <TGaxis.h>
69 #include <TVector.h>
70 #include <TAxis.h>
71 #include <TLegend.h>
72 #include <TH1.h>
73 #include <TH2.h>
74 #include <TMath.h>
75 #include <TROOT.h>
76 #include <TStyle.h>
77 
78 
79 namespace {
80 
84 class Tag {
85  public:
87  template<class Component>
88  Tag(const std::string& prefix, const Component& c) {
89  const mdet::Module& mod = GetModule(c);
90  const mdet::Counter& ctr = mod.GetCounter();
91  fStream << prefix << '_'
92  << ctr.GetId() << '_'
93  << mod.GetId() << '_'
94  << c.GetId() << '_'; // at least we're always putting the run number.
95  }
97  template<class S>
98  Tag& operator()(const S& s) {
99  fStream << s;
100  return *this;
101  }
103  const std::stringstream& sstr() const {
104  return fStream;
105  }
106  private:
108  const mdet::Module& GetModule(const mdet::Pixel& p) const {
109  return GetModule(p.GetPMT());
110  }
112  const mdet::Module& GetModule(const mdet::Channel& c) const {
113  return GetModule(c.GetFrontEnd());
114  }
116  const mdet::Module& GetModule(const mdet::SiPM& s) const {
117  return GetModule(s.GetSiPMArray());
118  }
120  const mdet::Module& GetModule(const mdet::ChannelSiPM& c) const {
121  return GetModule(c.GetFrontEnd());
122  }
123 
125  template<class Component>
126  const mdet::Module& GetModule(const Component& c) const {
127  return c.GetModule();
128  }
130  std::stringstream fStream;
131 };
132 
137 template<class T1, class T2>
138 struct CanCopy {
139  static void Constraints(T1 a, T2 b) {
140  T2 c = a;
141  b = a;
142  }
143  CanCopy() {
144  void(*p)(T1,T2) = Constraints;
145  ((void)p); // unused on purpose, avoid warnings.
146  }
147 };
148 
152 template<class StringContainer>
153 void PrintPlots(const TCanvas& c, const StringContainer& sc, const Tag& t)
154 {
155  // Constrain the container to contain strings.
156  // We do this after Stroustrup's FAQ answer
157  // "Why can't I define constraints for my template parameters?"
158  // http://www.research.att.com/~bs/bs_faq2.html#constraints
159  // Using Boost's library may be too much.
160  typedef typename StringContainer::value_type S;
161  CanCopy<S, std::string>(); // trigger the check.
162  const std::string& n = t.sstr().str();
163  for (typename StringContainer::const_iterator i = sc.begin(), e = sc.end(); i != e; ++i)
164  c.Print((n + *i).c_str());
165 }
166 
202 template<typename T>
203 struct OwnerVector : public std::vector<T*> {
204  void operator()(const T * const t) const {
205  delete t;
206  }
207  ~OwnerVector() {
208  typedef typename OwnerVector<T>::const_iterator It;
209  typedef const OwnerVector<T>& ConstRef;
210  // for_each works with copies by default, but we don't want
211  // to mess around making copies of this vector (specially when
212  // destroying the copies would lead to a double delete!)
213  std::for_each<It,ConstRef>(this->begin(), this->end(), *this);
214  }
215 };
216 
217 
218 /*
219  * Several wrapping helper functors.
220  */
221 
223 template<class Container>
224 struct TotalPulseFunctor {
225  TotalPulseFunctor(const Container& pulses, double ux, double uy) :
226  fPulses(pulses), fUnitX(ux), fUnitY(uy), fAbs(false) { }
227  double operator()(double t) const {
228  double totalSignal = 0;
229  // We accumulate the signal of all the pulses...
230  for (typename Container::const_iterator p = fPulses.begin(), e = fPulses.end(); p != e; ++p)
231  totalSignal += p->TimeSpaceEvaluate(t);
232  if (fAbs)
233  totalSignal = std::abs(totalSignal);
234  return totalSignal;
235  }
236  double operator()(double *x, double * /*p*/) const {
237  // For plottin', with units.
238  return (*this)(x[0] * fUnitX) / fUnitY;
239  }
240  const Container& fPulses;//Love the abstraction.
241  double fUnitX;
242  double fUnitY;
243  bool fAbs;
244 };
245 
247 template<class Functor>
248 struct ProxyFunctor {
249  ProxyFunctor(const Functor& func, double ux, double uy) :
250  fFunctor(func), fUnitX(ux), fUnitY(uy) {}
251  double operator()(double *x, double * /*p*/) const {
252  return fFunctor(x[0] * fUnitX) / fUnitY;
253  }
254  const Functor& fFunctor;
255  double fUnitX;
256  double fUnitY;
257 };
258 
260 struct PulseFunctor {
261  PulseFunctor(const mdet::Pixel::SPE& spe, double ux, double uy) :
262  fPulse(&spe), fUnitX(ux), fUnitY(uy) {}
263  //overload for sipm
264  PulseFunctor(const mdet::SiPM::PE& pe, double ux, double uy) :
265  fPhotoEquivalent(&pe), fUnitX(ux), fUnitY(uy) {}
266  double operator()(double *x, double * /*p*/) const {
267  return fPulse->TimeSpaceEvaluate(x[0] * fUnitX) / fUnitY;
268  }
269  const mdet::Pixel::SPE * fPulse;
270  const mdet::SiPM::PE * fPhotoEquivalent;
271  double fUnitX;
272  double fUnitY;
273 };
274 
276 struct ThresholdFunctor {
277  ThresholdFunctor(double t, double uy) :
278  fThreshold(t), fUnitY(uy) {}
279  double operator()(double * x = 0, double *p = 0) const {
280  // Since the variables are not used, a warning may be issued,
281  // but in the other hand they serve as placeholders for the default value so cannot
282  // be commented out: cast to void to "use them". Note the cast in functional style
283  // cannot be used: void(x) is taken as a new declaration.
284  ((void)x);
285  ((void)p);
286  //
287  // No need for unit in x.
288  return fThreshold / fUnitY;
289  }
290  double fThreshold;
291  double fUnitY;
292 };
293 
295 struct TGraphFunctor {
296  TGraphFunctor(const TGraph& g) : fGraph(g) {}
297  double operator()(double *x, double * /*p*/) const {
298  return fGraph.Eval(x[0]);
299  }
300  const TGraph& fGraph;
301 };
302 
304 struct DerivativeFunctor {
305  DerivativeFunctor(const TF1& f, double s = 1.0) : fF1(f), fScale(s) { }
306  double operator()(double *x, double * /*p*/) const {
307  return fScale * fF1.Derivative(x[0]);
308  }
309  const TF1& fF1;
310  double fScale;
311 };
312 
314 template<class T>
315 struct TraceFunctor {
316  TraceFunctor(const T& t, double m, double ux, double uy) :
317  fTrace(t), fMinTime(m), fUnitX(ux), fUnitY(uy), fBinning(t.GetBinning()), fAbs(false) {}
318  double operator()(double *x, double * /*p*/) const {
319  return ((*this)(x[0] * fUnitX)) / fUnitY;
320  }
321  double operator()(double t) const {
322  // Do range checking since when running the operator gets called with
323  // out of range values, and so we may access non-owned memory.
324  double timeOffset = t - fMinTime;
325  if (timeOffset < 0)
326  return 0;
327  double maxOffset = fTrace.GetSize() * fBinning;
328  if (timeOffset > maxOffset)
329  return 0;
330  // We're in range, do a linear interpolation:
331  typedef typename T::SizeType Size;
332  /*
333  * From the C++ standard ISO/IEC 14882:
334  * 4.9) Floating-integral conversions
335  * "An rvalue of a floating point type can be converted to an
336  * rvalue of an integer type. The conversion truncates;
337  * that is, the fractional part is discarded."
338  */
339  Size leftBin = static_cast<Size>(timeOffset / fBinning);
340  Size rightBin = leftBin + 1;
341  double leftOffset = fBinning * leftBin;
342  double rightOffset = fBinning * rightBin;
343  double leftValue = fTrace[ leftBin ];
344  double rightValue = fTrace[ rightBin ];
345  double res = leftValue + (rightValue-leftValue) * (timeOffset - leftOffset) / (rightOffset - leftOffset);
346  if (fAbs)
347  res = std::abs(res);
348  return res;
349  }
350  const T& fTrace;
351  double fMinTime;
352  double fUnitX;
353  double fUnitY;
354  double fBinning;
355  bool fAbs;
356 };
357 
358 }
359 
360 using namespace fwk;
361 
362 namespace MdCounterSimulatorAG {
363 
364 const char* const
365 MdCounterSimulator::kSimulationTypeTags[] = { "FromMEvent", "FromMEventSimulatedScint"};
366 
367 const char* const
368 MdCounterSimulator::kIntegratorSimulationTypeTags[] = { "StepByStep", "Simplified"};
369 
370 MdCounterSimulator::MdCounterSimulator() :
371  fRunNumber(1)
372 {
373 }
374 
376 {
377 }
378 
381 {
382  // Configuration reading.
383  utl::Branch config = fwk::CentralConfig::GetInstance()->GetTopBranch("MdCounterSimulator");
384  fLog.Configure(config);
385  // Override defaults:
391  fUnits.Configure(config);
393  // Load the different file extensions
394  std::string exts; // Load a raw string from configuration, and the fill the actual field.
395  // XXX Check because VManager has, in fact, a GetData(list<string>) or vector<string>, which
396  // ends calling >> upon a istringstream. And the use of a tokenizer is toooo-java like.
397  LoadConfig(config, "plotFileExtensions", exts, ".eps .root");
398  typedef boost::char_separator<std::string::value_type> Sep;
399  typedef boost::tokenizer<Sep> Tokenizer;
400  Sep sep(" "); // separate with spaces
401  Tokenizer tokens(exts, sep);
402  fPlotFileExtensions.insert(fPlotFileExtensions.begin(), tokens.begin(), tokens.end());
404  // Load the allowed particle types.
405  // Load the defaults in a local variable...
406  std::vector<ParticleType> particleTypesDefault;
407  /*
408  * particleTypesDefault.push_back(utl::Particle::eElectron);
409  * particleTypesDefault.push_back(utl::Particle::eMuon);
410  */
411  // particleTypesDefault.insert(utl::Particle::eTau);
412  // XXX Use a local variable of a type present in VManager,
413  // and then pass the loaded data into the actual field.
414  std::vector<ParticleType> particleTypes;
415  LoadConfig(config, "allowedParticleTypes", particleTypes, particleTypesDefault);
416  // Fill the actual field...
417  fAllowedParticleTypes.insert(particleTypes.begin(), particleTypes.end());
418  if (!fAllowedParticleTypes.size())
419  fLog("No particle types indicated: allowing'em all", 1);
421  // Load the kind of simulation to be performed.
422  std::string tag;
423  LoadConfig(config, "simType", tag, kSimulationTypeTags[0]);
425  LoadConfig(config, "forcedSDTrigger", fForcedSDTrigger, false);
426  LoadConfig(config, "nRepetitions", fNRepetitions, 10);
427  LoadConfig(config, "nBinsHistograms", fNBinsHistograms, 100);
428  LoadConfig(config, "minSPE", fMinSPE, 1);
429  LoadConfig(config, "maxSPE", fMaxSPE, 5);
430  LoadConfig(config, "stepSPE", fStepSPE, 1);
431  LoadConfig(config, "nDiscretization", fNDiscretization, 2048);
432  LoadConfig(config, "numPlotPoints", fNumPlotPoints, 500);
433  LoadConfig(config, "ignoreCrossTalk", fIgnoreCrossTalk, false);
434  LoadConfig(config, "pulseFilename", fPulseFilename, "");
435  LoadConfig(config, "nPulseSamples", fNPulseSamples, 500);
436  LoadConfig(config, "pulseSampleWindow", fPulseSampleWindow, 200 * fUnits.GetTimeUnit());
437  LoadConfig(config, "generateSPEPulseOutput", fGenerateSPEPulseOutput, false);
438  LoadConfig(config, "generatePreFETotalPulseOutput", fGeneratePreFETotalPulseOutput, false);
439  LoadConfig(config, "generatePostFETotalPulseOutput", fGeneratePostFETotalPulseOutput, false);
440  LoadConfig(config, "integratorSimType", tag, kIntegratorSimulationTypeTags[1]);
442  LoadConfig(config, "includeBaseLineFluctuationIntegrator", fIncludeBaseLineFluctuationIntegrator, false);
443  LoadConfig(config, "injectNoiseBinary", fInjectNoiseBinary, false);
444  // Check if a filename was loaded.
445  if (! fPulseFilename.empty())
446  fPulseFile.open(fPulseFilename.c_str());
447  // Plot variables:
448  LoadConfig(config, "togglePlotchannelPulses", fTogglePlotchannelPulses, false);
449  LoadConfig(config, "toggleOutcome", fToggleOutcome, false);
450  LoadConfig(config, "toggleInputOutput", fToggleInputOutput, false);
451  LoadConfig(config, "toggleTransferAmpResponse", fToggleTransferAmpResponse, false);
452  LoadConfig(config, "toggleTransferPhaseResponse", fToggleTransferPhaseResponse, false);
453  LoadConfig(config, "toggleDelay", fToggleDelay, false);
454  LoadConfig(config, "toggleFftPriorAmp", fToggleFftPriorAmp, false);
455  LoadConfig(config, "togglePlotFftPostAmp", fTogglePlotFftPostAmp, false);
456  // Now configure the defaults according the simulation type:
457  switch (fSimType) {
458  case eFromMEvent:
460  fPlotChannelPulses = true;
461  fPlotOutcome = true;
462  fPlotInputOutput = true;
465  fPlotDelay = true;
466  fPlotFftPriorAmp = true;
467  fPlotFftPostAmp = true;
468  break;
469  }
470  // Now apply the toggle:
473  if (fToggleOutcome)
475  if (fToggleInputOutput)
481  if (fToggleDelay)
483  if (fToggleFftPriorAmp)
488  Style_t font=102;
489  Float_t fsize=0.03;
490  Option_t *axis="XYZ";
491  Float_t margin = 0.15;
492  fStyle = new TStyle;
493  //Canvas style
494  fStyle->SetCanvasBorderMode(0);
495  fStyle->SetCanvasColor(0);
496  //Axis style
497  fStyle->SetTickLength( 0.01, "XYZ" );
498  fStyle->SetLabelFont( font , axis);
499  fStyle->SetLabelSize( fsize, axis);
500  fStyle->SetLabelOffset( 0.005, axis);
501  fStyle->SetTitleFont( font , axis);
502  fStyle->SetTitleSize( fsize, axis);
503  fStyle->SetTitleOffset( 1.0, axis);
504  fStyle->SetTitleXOffset( 1.5 );
505  fStyle->SetTitleYOffset( 2.5 );
506  fStyle->SetTitleAlign( 22 );
507  fStyle->SetTitleBorderSize( 0 );
508  fStyle->SetTitleColor( 1, axis );
509  fStyle->SetTitleFillColor( 0 );
510  fStyle->SetTitleH( 0 );
511  fStyle->SetTitleW( 0 );
512  fStyle->SetTitleX( 0.5 );
513  fStyle->SetTitleY( 1-margin/2 );
514  fStyle->SetTitleTextColor( kBlue );
515  //fStyle->SetTitlePS(const char* pstitle);
516  //fStyle->SetTitleStyle(Style_t style = 1001);
517  //fStyle->SetTitleXSize(Float_t size = 0.02);
518  //fStyle->SetTitleYSize(Float_t size = 0.02);
519  fStyle->SetPalette(1,0);
520  fStyle->SetStatColor(0);
521  //Pad style
522  fStyle->SetPadBottomMargin(margin);
523  fStyle->SetPadLeftMargin (margin);
524  fStyle->SetPadRightMargin (margin);
525  fStyle->SetPadTopMargin (margin);
526  fStyle->SetPadBorderMode( 0 );
527  fStyle->SetPadBorderSize( 0 );
528  fStyle->SetPadColor( 0 );
529  fStyle->SetPadGridX(false);
530  fStyle->SetPadGridY(false);
531  fStyle->SetPadTickX(true);
532  fStyle->SetPadTickY(false);
533  //Frame style
534  fStyle->SetFrameBorderMode( 0 );
535  fStyle->SetFrameBorderSize( 0 );
536  fStyle->SetFrameFillColor( 0 );
537  fStyle->SetFrameFillStyle( 1 );
538  fStyle->SetFrameLineColor( 0 );
539  fStyle->SetFrameLineStyle( 0 );
540  fStyle->SetFrameLineWidth( 0 );
542  return eSuccess;
543 }
544 
547 {
548  VModule::ResultFlag r = eFailure; // default.
549 
550  fStyle->cd();
551  // While loading the type, it's checked to match one of the enums.
552  switch (fSimType) {
553  case eFromMEvent:
554  r = RunFromMEvent(event);
555  break;
558  break;
559  }
560  ++fRunNumber;
561  return r;
562 }
563 
566 {
567  INFO("RunFromMEvent");
568  if (event.HasMEvent()) {
569  mevt::MEvent& me = event.GetMEvent();
570  const utl::TimeStamp& mEventTime = me.GetHeader().GetTime();
571  fLog("The event time for simulation ", 2)(mEventTime);
572  const mdet::MDetector& detector = det::Detector::GetInstance().GetMDetector();
573  for (mevt::MEvent::CounterIterator ic = me.CountersBegin(), ec = me.CountersEnd(); ic != ec; ++ic) {
574  const mdet::Counter& counter = detector.GetCounter(ic->GetId());
575  for (mevt::Counter::ModuleIterator im = ic->ModulesBegin(), em = ic->ModulesEnd(); im != em; ++im) {
576  const mdet::Module& module = counter.GetModule(im->GetId());
577  // Index with pixel id, unique on a module level, so no need of multi indexes.
578  // We keep these so as to have together all the pulses within a module
579  // , as they are related due to cross talk.
580  SignalsMap signalsMap;
581  for (mevt::Module::ScintillatorIterator is = im->ScintillatorsBegin(), es = im->ScintillatorsEnd();
582  is != es; ++is) {
583  if (is->HasSimData()) {
584  const mdet::Scintillator& scint = module.GetScintillator(is->GetId());
585  //passing a const and a nonconst version of ScintillatorSimData, should be reorganized
586  // Should be nonconst if you are going the write in the object. No need to pass twice the same object (???)
587  VModule::ResultFlag f = SimulatePulses(scint, is->GetSimData(), is->GetSimData(), signalsMap);
588  // Check status and do early return if so...
589  if (f != eSuccess)
590  return f;
591  }
592  }
593  // On a module level we simulate the electronics.
594  VModule::ResultFlag f = SimulateElectronics(*im, module, signalsMap, mEventTime);
595 
596  if (f != eSuccess)
597  return f;
598  }
599  }
600  } else {
601  INFO("Event without MEvent: nothing to be done.");
602  }
603  return eSuccess;
604 }
605 
606 
607 /*********************************************************************************
608  * *
609  * This method generate the PMT/SiPM pulses for the arriving photons *
610  * simulated in G4StationSimulator (loaded in ScintillatorSimData::PhotonTimes) *
611  * and runs the electronics simulation. *
612  * Replaces the RunFromMEvent method which first creates the photons with and *
613  * the optic fiber curve parametrization in the G4109 code. *
614  * *
615  ********************************************************************************/
618 {
619  INFO("RunFromMEventScintillatorSimulated");
620  if (event.HasMEvent()) {
621  mevt::MEvent& me = event.GetMEvent();
622  double T1 = 0;
623  const utl::TimeStamp& mEventTime = event.GetSEvent().GetHeader().GetTime();
624  fLog("The event time for SiPM-simulation ", 2)(mEventTime);
625  const mdet::MDetector& detector = det::Detector::GetInstance().GetMDetector();
626  for (mevt::MEvent::CounterIterator ic = me.CountersBegin(), ec = me.CountersEnd(); ic != ec; ++ic) {
627  const mdet::Counter& counter = detector.GetCounter(ic->GetId());
628  int triggerFound = GetTriggerTimeFromSD(event, counter, ic, T1);
630  //Check trigger condition in WCD
631  if (triggerFound) {
632  std::cout << "SD trigger found for counter " << ic->GetId() << " at T1 " << T1/utl::ns << "ns " << std::endl;
633  std::cout << "Trigger is T" << triggerFound << "\n";
634  ic->SetT1(T1);
635  } else if( fForcedSDTrigger) {
636  std::cout << "XXX NO SD trigger found for counter " << ic->GetId() << " but used anyway" << std::endl;
637  ic->SetT1(T1);
638  } else {
639  std::cout << "XXX NO SD trigger found for counter " << ic->GetId() << std::endl;
640  ic->SetRejected("SD associated un-triggered");
641  continue;//do not go into modules of a non-triggered WCD
642  }
644  for (mevt::Counter::ModuleIterator im = ic->ModulesBegin(), em = ic->ModulesEnd(); im != em; ++im) {
645  //Make all modules in the MEvent structure
646  im->SetCandidate();
647  const mdet::Module& module = counter.GetModule(im->GetId());
648  SignalsMap signalsMap;
649  for (mevt::Module::ScintillatorIterator is = im->ScintillatorsBegin(), es = im->ScintillatorsEnd();
650  is != es; ++is) {
651  if (is->HasSimData()) {
652  const mdet::Scintillator& scint = module.GetScintillator(is->GetId());
653  mevt::ScintillatorSimData& simData = is->GetSimData();
654 
655  int nroPhotons = 0;
656  for (mevt::ScintillatorSimData::ConstPhotonTimeIterator photon = simData.PhotonTimesBegin(), lastPhoton = simData.PhotonTimesEnd();
657  photon != lastPhoton; ++photon) {
658 
659  const double delay = simData.GetPhotonTime(*photon);
660  int finalPixId;
661  bool isSiPM = module.IsSiPM();
662  if(!isSiPM){
663  const mdet::Pixel& pixel = module.GetPixelFor(scint);
664  mdet::Pixel::SPE spe = pixel.MakeSPEAt(delay);
665 
666  if (fIgnoreCrossTalk) {
667  finalPixId = pixel.GetId();
668  } else {
669  const mdet::Pixel& dst = pixel.GetPMT().ComputePulseDestination(pixel);
670  finalPixId = dst.GetId();
671  }
672 
673  signalsMap[ finalPixId ].fPulses.push_back(spe);
674  simData.AddSPEPulse(spe.GetMu(), spe.GetSigma(), spe.GetAmplitude(), finalPixId);
675 
676  }else{
677  const mdet::SiPM& sipm = module.GetSiPMFor(scint);
678  mdet::SiPM::PE pe = sipm.MakePEAt(delay);
679  nroPhotons++;
680  finalPixId = sipm.GetId();
681 
682  signalsMap[ finalPixId ].fSiPMPulses.push_back(pe);
683  simData.AddPEPulse(pe.GetStartTime(), pe.GetAmplitude1(), pe.GetAmplitude2(), pe.GetAmplitude3(),
684  pe.GetRiseTime(), pe.GetFallTime1(), pe.GetFallTime2(), pe.GetFallTime3(), finalPixId);
685 
686  }
687  }
688  //cout << "Nro Photons in pixel " << module.GetSiPMFor(scint).GetId() << " " << nroPhotons << endl;
689  }
690  }
691 
692  VModule::ResultFlag f = SimulateElectronics(*im, module, signalsMap, mEventTime);
693  if (f != eSuccess)
694  return f;
695  }
696  }
697  } else {
698  INFO("Event without MEvent: nothing to be done.");
699  }
700  return eSuccess;
701 }
702 
705  const mevt::ScintillatorSimData& ssd,
706  mevt::ScintillatorSimData& ssd_nonconst,
707  SignalsMap& sm)
708 {
709 
710  const mdet::Module& module = scint.GetModule();
711  bool isSiPM = module.IsSiPM();
712  //fLog("Simulating pulses for", 1)(scint.GetIdMessage())(".");
713  // Store only if there will be any signal, at least due to this source.
714 
715  if (ssd.HasAnalogicTrace()) {
716  if(!isSiPM){
717  const mdet::Pixel& pixel = module.GetPixelFor(scint);
718  sm[ pixel.GetId() ].fScintSimData = &ssd;
719  }else{
720  const mdet::SiPM& sipm = module.GetSiPMFor(scint);
721  sm[ sipm.GetId() ].fScintSimData = &ssd;
722  }
723  }
724  // To show information at the particle level.
725  const unsigned int particleTabLogLevel = 3;
726  std::unique_ptr<utl::TabularStream> particleTab;
727  if (fLog.GetLevel() >= particleTabLogLevel) {
728  Init(particleTab, 8);
729  *particleTab << utl::hline
730  << "# hit" << utl::endc // 1
731  << "id hit scint" << utl::endc // 2
732  << "spe number" << utl::endc // 3
733  << "depth (" << fUnits.GetLengthName() << ")" << utl::endc // 4
734  << "track (" << fUnits.GetLengthName() << ")" << utl::endc // 5
735  << "total path (" << fUnits.GetLengthName() << ")" << utl::endc // 6
736  << "in-scint path (" << fUnits.GetLengthName() << ")" << utl::endc // 7
737  << "on-manifold path (" << fUnits.GetLengthName() << ")" << utl::endr // 8
738  << utl::hline;
739  }
740  // To show information at the spe level.
741  const unsigned int speTabLogLevel = 4;
742  std::unique_ptr<utl::TabularStream> speTab;
743  if (fLog.GetLevel() >= speTabLogLevel) {
744  Init(speTab, 9);
745  *speTab << utl::hline
746  << "# hit" << utl::endc // 1
747  << "# spe" << utl::endc // 2
748  << "path delay (" << fUnits.GetTimeName() << ")" << utl::endc // 3
749  << "particle delay (" << fUnits.GetTimeName() << ")" << utl::endc // 4
750  << "fiber delay (" << fUnits.GetTimeName() << ")" << utl::endc // 5
751  << "scint delay (" << fUnits.GetTimeName() << ")" << utl::endc // 6
752  << "total delay (" << fUnits.GetTimeName() << ")" << utl::endc // 7
753  << "source pix" << utl::endc // 8
754  << "end pix" << utl::endr // 9
755  << utl::hline;
756  }
757  unsigned int nHit = 0;
759  i != sse || fLog("", 2); ++i) {
760  // ...the log puts the newline.
761  const utl::Particle& particle = *i;
762 
763  /*
764  * Filter through the allowed particles, see the declaration for fAllowedParticles
765  * for more comments.
766  * If the allowed particles set is empty, then we take that as a wildcard that means
767  * to allow every particle.
768  */
769  if (!fAllowedParticleTypes.size() || fAllowedParticleTypes.count(particle.GetType())) {
770  // Construct a line assuming rectilinear propagation of the particle.
771  const utl::Line particlePath(particle.GetPosition(), particle.GetDirection());
772  // If put in the simulation data for this particular scintillator, the
773  // particle should intersect it; despite that it doesn't hurt to check
774  // that it actually does.
775  if (scint.IntersectedBy(particlePath)) {
776  fLog(".", 2); // hit shown with a period...
777  ++nHit; // count the hit...
778  const mdet::Fiber& fiber = module.GetFiberFor(scint);
779 
780  // Construct the track inside the scintillator:
781  // the origin is the incidence point.
782  const utl::Segment track = scint.ComputeIntersectionWith(particlePath);
783  const utl::Point hitPoint(track.GetBegin());
784  const unsigned int hitLogLevel = 33;
785  if (fLog.GetLevel() >= hitLogLevel) {
786  fLog("Track begin in scint", hitLogLevel)
787  ("x")(track.GetBegin().GetX(scint.GetLocalCoordinateSystem()) / fUnits.GetLengthUnit())
789  ("y")(track.GetBegin().GetY(scint.GetLocalCoordinateSystem()) / fUnits.GetLengthUnit())
791  ("z")(track.GetBegin().GetZ(scint.GetLocalCoordinateSystem()) / fUnits.GetLengthUnit())
792  (fUnits.GetLengthName());
793  fLog("Track end in scint", hitLogLevel)
794  ("x")(track.GetEnd().GetX(scint.GetLocalCoordinateSystem()) / fUnits.GetLengthUnit())
796  ("y")(track.GetEnd().GetY(scint.GetLocalCoordinateSystem()) / fUnits.GetLengthUnit())
798  ("z")(track.GetEnd().GetZ(scint.GetLocalCoordinateSystem()) / fUnits.GetLengthUnit())
799  (fUnits.GetLengthName());
800  }
801  // Distance inside scintillator.
802  const double trackLen = track.GetLength();
803  /*
804  * Distance to PMT:
805  * We take as the impinging point the middle of the track vector,
806  * and then compute this longitudinal distance along the fiber/scint.
807  * We only care about 1-D distance to the start of the Fiber in the scint.
808  *
809  * The distance along the scint is in the y direction; and in the fiber is
810  * in the x direction.
811  */
812  //So move the initial point half-way: this our reference point.
813  const utl::Point trackMiddle = track.GetBegin() + (trackLen / 2) * track.GetDirection();
814  // Now compute a plane perpendicular to the fiber.
815  const utl::Plane targetPlane(utl::Point(0, 0, 0, fiber.GetLocalCoordinateSystem()),
816  utl::Vector(1, 0, 0, fiber.GetLocalCoordinateSystem()));
817  // Now the on-scintillator distance is the distance of the middle point, to the plane,
818  // so we are neglecting the components perpendicular to the fiber (ie we only care of the
819  // distance along the fiber).
820  const double onScint = utl::Distance(trackMiddle, targetPlane);
821  // We can take this length from the actual detector, or use the override value.
822  const double onManifold = fiber.GetOnManifoldLength();
823  // The on-scint len + on-manifold until reaching the PMT.
824  const double pathLen = onScint + onManifold;
825  /*
826  * This particle generated this number of SPEs:
827  * Note that all the energy is taken as parameter for the computation of the n spe, which
828  * ends up meaning that all the energy is deposited in the scintillator (remember that
829  * the fiber is used for the computation because it's the one related to the meaning of
830  * attenuation (in the sense of propagation along a direction), tough also the scintillator
831  * is relevant.
832  */
833  //#warning "ENERGY DEPOSITED BY THE PARTICLE IS NOW PASSED in the WEIGHT field (a la MARTA :-))" NO!
834  //--> This attribute must be changed (or create a new one). There is no need whatsoever to do things like this, not funny.
835  //General comment: when you get the option to do things right or wrong, always choose right.
836  unsigned int nSPE = fiber.ComputeSPENumber(pathLen, trackLen, particle.GetWeight());
837 
838  if (fLog.GetLevel() >= particleTabLogLevel) {
839  // Compute the depth where the particle hit the scintillator:
840  const double hitDepth = module.GetDepth(hitPoint);
841  *particleTab << nHit << utl::endc
842  << scint.GetId() << utl::endc
843  << nSPE << utl::endc
844  << fLog << hitDepth / fUnits.GetLengthUnit() << utl::endc
845  << fLog << trackLen / fUnits.GetLengthUnit() << utl::endc
846  << fLog << pathLen / fUnits.GetLengthUnit() << utl::endc
847  << fLog << onScint / fUnits.GetLengthUnit() << utl::endc
848  << fLog << onManifold / fUnits.GetLengthUnit() << utl::endr;
849  }
850  // These are the same for every spe:
851  const double pathDelay = pathLen * fiber.GetRefractionIndex() / utl::kSpeedOfLight;
852  // Now the arrival time (see also RunFromMEvent).
853  const double particleDelay = particle.GetTime().GetInterval();
854 
855  for (unsigned int n = 0; n < nSPE; ++n) {
856  // Geometrical propagation...
857  double delay = pathDelay;
858  // In-fiber decay delay...
859  const double fiberDelay = fiber.ComputeDecayDelay();
860  delay += fiberDelay;
861  // and in-scint decay delay...
862  const double scintDelay = scint.ComputeDecayDelay();
863  delay += scintDelay;
864  // and the particle arrival time.
865  delay += particleDelay;
866 
867  int finalPixId;
868  if(!isSiPM){
869  const mdet::Pixel& pixel = module.GetPixelFor(scint);
870  mdet::Pixel::SPE spe = pixel.MakeSPEAt(delay);
871 
872  /*
873  * Compute the final destination taking into account (eventually)
874  * the crosstalk from the PMT.
875  */
876  if (fIgnoreCrossTalk) {
877  finalPixId = pixel.GetId();
878  } else {
879  // Now determine the actual final pix, due to crosstalk.
880  const mdet::Pixel& dst = pixel.GetPMT().ComputePulseDestination(pixel);
881  finalPixId = dst.GetId();
882  }
883  //signal map is only used inside this Module
884  sm[ finalPixId ].fPulses.push_back(spe);
885  //save pulse information also in MEvent, duplicating of fPulses structure in MEvent and locally should be removed in the future..
886  ssd_nonconst.AddSPEPulse(spe.GetMu(), spe.GetSigma(), spe.GetAmplitude(), finalPixId);
887 
888  }else{
889  const mdet::SiPM& sipm = module.GetSiPMFor(scint);
890  mdet::SiPM::PE pe = sipm.MakePEAt(delay);
891  finalPixId = sipm.GetId();
892 
893  //signal map is only used inside this Module
894  sm[ finalPixId ].fSiPMPulses.push_back(pe);
895  //save pulse information also in MEvent, duplicating of fPulses structure in MEvent and locally should be removed in the future..
896  ssd_nonconst.AddPEPulse(pe.GetStartTime(), pe.GetAmplitude1(), pe.GetAmplitude2(), pe.GetAmplitude2(),
897  pe.GetRiseTime(), pe.GetFallTime1(), pe.GetFallTime2(), pe.GetFallTime3(), finalPixId);
898 
899 
900  }
901 
902  if (fLog.GetLevel() >= speTabLogLevel){
903  *speTab << nHit << utl::endc
904  << fLog << (n+1) << utl::endc
905  << fLog << pathDelay / fUnits.GetTimeUnit() << utl::endc
906  << fLog << particleDelay / fUnits.GetTimeUnit() << utl::endc
907  << fLog << fiberDelay / fUnits.GetTimeUnit() << utl::endc
908  << fLog << scintDelay / fUnits.GetTimeUnit() << utl::endc
909  << fLog << delay / fUnits.GetTimeUnit() << utl::endc
910  // << fLog << sipm.GetId() << utl::endc
911  << finalPixId << utl::endr;
912  }
913  } // SPE loop
914  // A line for each group.
915  if (fLog.GetLevel() >= speTabLogLevel)
916  (*speTab) << utl::hline;
917  } else {
918  // Intersection check: Warn if no intersection.
919  fLog("Particle missing the scintillator after hit", 1)(nHit);
920  }
921  } // Particle type check
922  }
923 
924  // Information for the particles...
925  if (fLog.GetLevel() >= particleTabLogLevel) {
926  *particleTab << utl::hline;
927  fLog("Impinging particles information:", particleTabLogLevel);
928  fLog(particleTab->Str(), particleTabLogLevel);
929  }
930  // Information for the particles...
931  if (fLog.GetLevel() >= speTabLogLevel){
932  // No need as of the hline from each group.
933  // *speTab << utl::hline;
934  fLog("Generated spe information:", speTabLogLevel);
935  fLog(speTab->Str(), speTabLogLevel);
936  }
937  return eSuccess;
938 }
939 
940 void
942  const SignalInformation& si,
943  utl::TraceB& trace,
944  double& span,
945  const utl::TimeInterval& traceStart,
946  const utl::TimeStamp& eventTime)
947 
948 {
949  //fLog("Processing pulses for channel", 1)(channel.GetId());
950  const mdet::FrontEnd& frontEnd = channel.GetFrontEnd();
951  // TODO No Jitter by now: so a constant sample rate.
952  const double sRate = frontEnd.GetMeanSampleRatePeriod();
953  // Clear the trace:
954  trace.ClearTrace();
955  //
956  // Set the appropiate binning equal to the (mean) sample rate.
957  // Even in the case of having jitter, this would be the value because
958  // the digital trace has no information of time, we just supose that that's
959  // the period.
960  trace.SetBinning(sRate);
961  fLog("Cleaning trace and setting a binning of", 2)(sRate / fUnits.GetTimeUnit())(fUnits.GetTimeName());
962  const unsigned int nBinsTrace = frontEnd.GetPreT1BufferLength() + frontEnd.GetPostT1BufferLength();
963  fLog("Trace size", 2)(nBinsTrace);
964  bool isAnalogicTrace = si.fScintSimData && si.fScintSimData->HasAnalogicTrace();
965  if (si.fPulses.empty() && ! isAnalogicTrace) {
966  fLog("No pulses and other sim data found for channel", 1)(channel.GetId());
967  // No pulses...so not a single 1 in the boolean trace...
968  for (unsigned int i = 0; i < nBinsTrace; ++i)
969  trace.PushBack(false);
970  span = 0; // No pulse, no span.
971  return; // done.
972  }
973  // First we determine the maximum extent of signal.
974  // Init with the first so as to have something to compare with...
975  // Now we are considering two cases times span before and after FrontEnd (see later also).
976  double minTimePreFE = std::numeric_limits<double>::max();
977  double maxTimePreFE = -std::numeric_limits<double>::max();
978  std::unique_ptr<utl::TabularStream> spanTable;
979  const unsigned int pulseSpanLogLevel = 3;
980  if (fLog.GetLevel() >= pulseSpanLogLevel) {
981  Init(spanTable, 3);
982  *spanTable << utl::hline
983  << "# spe" << utl::endc // 1
984  << "min (" << fUnits.GetTimeName() << ")" << utl::endc // 2
985  << "max (" << fUnits.GetTimeName() << ")" << utl::endr;// 3
986  }
987  unsigned int nSPE = 0; // only used when logging to the table...
988  for (PulseContainer::const_iterator p = si.fPulses.begin(), e = si.fPulses.end(); p != e; ++p) {
989  minTimePreFE = std::min(minTimePreFE, p->LowerLimit());
990  maxTimePreFE = std::max(maxTimePreFE, p->UpperLimit());
991  if (fLog.GetLevel() >= (pulseSpanLogLevel+1)) { // 4 each one, 1 more needed
992  *spanTable << utl::hline
993  << ++nSPE << utl::endc
994  << fLog << p->LowerLimit() / fUnits.GetTimeUnit() << utl::endc
995  << fLog << p->UpperLimit() / fUnits.GetTimeUnit() << utl::endr;
996  }
997  }
998  // May not be used if !isAnalogicTrace, put it here to have greater scope.
999  double analogicTraceStartTime = 0;
1000  double analogicTraceEndTime = 0;
1001  if (isAnalogicTrace) {
1002  analogicTraceStartTime = (si.fScintSimData->GetAnalogicTraceStartTime() - eventTime).GetInterval();
1003  analogicTraceEndTime = analogicTraceStartTime + si.fScintSimData->GetAnalogicTrace().GetSize() *
1005  minTimePreFE = std::min(minTimePreFE, analogicTraceStartTime);
1006  maxTimePreFE = std::max(maxTimePreFE, analogicTraceEndTime);
1007  }
1008  // The span covers both the range of pulses as well that of the analogic trace.
1009  const double pulseTimeSpan = maxTimePreFE - minTimePreFE;
1010  if (fLog.GetLevel() >= pulseSpanLogLevel) {
1011  *spanTable << utl::hline
1012  << "all" << utl::endc
1013  << fLog << minTimePreFE / fUnits.GetTimeUnit() << utl::endc
1014  << fLog << maxTimePreFE / fUnits.GetTimeUnit() << utl::endr
1015  << utl::hline;
1016  fLog("SPE pulses and other signals span:", pulseSpanLogLevel);
1017  fLog(spanTable->Str(), pulseSpanLogLevel);
1018  }
1019  // The pulses start, so take then into account...
1020  TotalPulseFunctor<PulseContainer> totalPulsePreFrontEnd(si.fPulses,
1021  fUnits.GetTimeUnit(),
1023  fLog("Applying FFT...", 3);
1025  // Nyquist zone: first.
1026  // Discretization of total pulse (so to perform FFT).
1027  double binning = pulseTimeSpan / fNDiscretization;
1028  TimeTrace& timeTrace = fft.GetTimeSeries();
1029  fLog("Time discretization binning ", 4)(binning / fUnits.GetTimeUnit())(fUnits.GetTimeName());
1030  timeTrace.SetBinning(binning);
1031  fLog("Discretizing total pulses. Number of samples:", 3, false);
1032  // Fill the time series...
1033  for (unsigned int i = 0; i < fNDiscretization || fLog(i, 3)('.'); ++i) {
1034  double time = minTimePreFE + i * binning;
1035  double value = totalPulsePreFrontEnd(time);
1036  if (isAnalogicTrace) {
1037  // Interpolation logic.
1038  if (analogicTraceStartTime <= time && time <= analogicTraceEndTime) {
1039  // TODO More complex interpolation.
1040  double delta = time - analogicTraceStartTime;
1041  delta /= si.fScintSimData->GetAnalogicTrace().GetBinning();
1043  value += si.fScintSimData->GetAnalogicTrace()[index];
1044  }
1045  }
1046  fft.GetTimeSeries().PushBack(value);
1047  }
1048  // Now apply the circuit transfer function:
1049  // calling GetFrequencySpectrum triggers the update...
1050  fLog("Applying transfer function in frequency spectrum.", 3);
1051  FrequencyTrace& freqTrace = fft.GetFrequencySpectrum();
1052  const FrequencyTrace::SizeType nFreq = fft.GetConstFrequencySpectrum().GetSize();
1053  const double freqBinning = fft.GetConstFrequencySpectrum().GetBinning();
1054  TVectorD freqArray(nFreq);
1055  TVectorD ampArray(nFreq);
1056  TVectorD phaArray(nFreq);
1057  TVectorD preFFT(nFreq);
1058  TVectorD postFFT(nFreq);
1059  fLog("Generating frequency response.", 3);
1060  const unsigned int tabFFTLogLevel = 4;
1061  std::unique_ptr<utl::TabularStream> tabFFT;
1062  if (fLog.GetLevel() >= tabFFTLogLevel) {
1063  Init(tabFFT, 4);
1064  *tabFFT << utl::hline
1065  << "Size" << utl::endc //1
1066  << "Binning (" << fUnits.GetFrequencyName() << ")" << utl::endc //2
1067  << "1st freq (" << fUnits.GetFrequencyName() << ")" << utl::endc //3
1068  << "Last freq (" << fUnits.GetFrequencyName() << ")" << utl::endr //4
1069  << nFreq << utl::endc // 1
1070  << fLog << (freqBinning / fUnits.GetFrequencyUnit()) << utl::endc // 2
1071  << fLog << (fft.GetFrequencyOfBin(0) / fUnits.GetFrequencyUnit()) << utl::endc // 3
1072  << fLog << (fft.GetFrequencyOfBin(nFreq - 1) / fUnits.GetFrequencyUnit()) << utl::endr // 4
1073  << utl::hline;
1074  fLog(tabFFT->Str(), tabFFTLogLevel);
1075  }
1076  for (FrequencyTrace::SizeType freqBin = 0; freqBin < nFreq; ++freqBin) {
1077  double freq = fft.GetFrequencyOfBin(freqBin);
1078  double preAmp = std::abs(freqTrace[ freqBin ]) / fUnits.GetElectricCurrentUnit();
1079  // This has resistance units..
1080  std::complex<double> c = channel.ComputeTransfer(freq);
1081  // Apply the transfer: now we have voltage...
1082  freqTrace[ freqBin ] *= c;
1083  // For plottin....
1084  double amp = std::abs(c) / fUnits.GetElectricResistanceUnit();
1085  double pha = std::arg(c) / fUnits.GetAngleUnit();
1086  freqArray(freqBin) = freq / fUnits.GetFrequencyUnit();
1087  ampArray(freqBin) = amp;
1088  phaArray(freqBin) = pha;
1089  preFFT(freqBin) = preAmp;
1090  postFFT(freqBin) = std::abs(freqTrace[ freqBin ]) / fUnits.GetElectricPotentialUnit();
1091  }
1092  fLog("Obtaining the amplified pulses in time-space...", 3);
1093  // Refresh back the time series: now we have the pulse widenned.
1094  const TimeTrace& totalPulsePostFrontEndTrace = fft.GetConstTimeSeries();
1095  /*
1096  * Is it correct to keep minTime and maxTime calculated prior front end?
1097  * 1st, we're not doing that anymore:
1098  *
1099  * a) Actually it isn't strictly so well; because the transfer function
1100  * has a non negligible phase effect: so it causes a shift in the output pulse.
1101  * Now, if the boundaries taken for the original pulse are quite far, it seems that
1102  * there's no actual problem.
1103  * If the limits, fall short with respect to the imposed shift, then the output pulse
1104  * may slip back entering from the other side of the axis as a periodicity effect due
1105  * to the transformation.
1106  *
1107  * b) In fact, in the real-life device there's an overall ~ 13 ns delay between the input and
1108  * output which is not being taken into account by now: ie we have only partially
1109  * described the real transfer function of the device.
1110  *
1111  * c) With the shift we're are taking into account b).
1112  */
1113  // Total analog pulse after the front-end, it also suffers a time shift
1114  // that rigidly shifts the total pulse:
1115  double shift = channel.ComputeSignalShift();
1116  fLog("Signal shift time", 3)(shift / fUnits.GetTimeUnit())(fUnits.GetTimeName())('.');
1117  // so the limits get shifted: compute new values, so to keep the original.
1118  const double minTimePostFE = minTimePreFE + shift;
1119  const double maxTimePostFE = maxTimePreFE + shift;
1120  // Note that here minTime is taken to be the reference start time, not
1121  // the "left" time window limit.
1122  TraceFunctor<TimeTrace> totalPulsePostFrontEnd(totalPulsePostFrontEndTrace,
1123  minTimePostFE,
1124  fUnits.GetTimeUnit(),
1126  // Discrimination
1127  fLog("Creating discriminator object.", 3);
1128  const mdet::Channel::Discriminator discriminator = channel.MakeDiscriminator(
1129  totalPulsePostFrontEnd,
1130  minTimePostFE,
1131  maxTimePostFE);
1132  // Loggin' of the times when the input reaches the threshold:
1133  // ie the roots of the equation threhols == input.
1134  const unsigned int rootLogLevel = 4;
1135  if (fLog.GetLevel() >= rootLogLevel) {
1137  ItRoot b = discriminator.AtThresholdBegin();
1138  ItRoot e = discriminator.AtThresholdEnd();
1139  if (b == e)
1140  fLog("Incoming pulse never at threshold level.", rootLogLevel);
1141  fLog("Incoming pulse at threshold level at ", rootLogLevel, false);
1142  for (ItRoot i = b; i != e; ++i) {
1143  fLog(*i / fUnits.GetTimeUnit(), rootLogLevel, false)(fUnits.GetTimeName())(' ');
1144  }
1145  fLog(".", rootLogLevel);
1146  }
1147  // Sampling
1148  fLog("Creating sampler object.", 3);
1149  mdet::FrontEnd::Sampler sampler = frontEnd.MakeSampler();
1150  /*
1151  * Note that we restrict the sampling to the maximun trace size according to buffer lenghts:
1152  * - First there's a all-false sampling trace segment, until reaching the zone of pulses,
1153  * - then the region with pulses,
1154  * - and lastly the trace is filled up with falses, until the max size is reached.
1155  */
1156  std::vector<double> sampleTimes;
1157  // sampleTimes.reserve(nBinsTrace);
1158  fLog("Sampling pulses.", 3);
1159  const double startTime = traceStart.GetInterval();
1160  const double stopTime = startTime +
1161  sRate * (frontEnd.GetPreT1BufferLength() + frontEnd.GetPostT1BufferLength());
1162  /*
1163  * XXX We could avoid everything if we can detect that there's no signal
1164  * inside the window frame defined by the trace.
1165  */
1166  // This is correct: we compare now with the updated minTime, which is the one
1167  // taken for the output signal.
1168  if (startTime < minTimePostFE) {
1169  // See inner body of the following loop (then condition).
1170  fLog("Samples false in the range", 4)
1171  (startTime / fUnits.GetTimeUnit())(fUnits.GetTimeName())
1172  ("to")
1173  (minTimePostFE / fUnits.GetTimeUnit())(fUnits.GetTimeName())
1174  ("as no signal in it.");
1175  }
1176  fLog("Samples:", 4);
1177  // The trace is empty: size is zero, so we start inserting values 'till t
1178  // he size gets _equal_ to the desired number of bins in the trace.
1179  // So when it's equal: don't eventer the for, cause one more will be added.
1180  for (double sampleTime = startTime; trace.GetSize() < nBinsTrace || fLog('\n', 4)(sampleTime);
1181  sampleTime += sRate) {
1182  //
1183  bool s;
1184  if (sampleTime < minTimePostFE || maxTimePostFE < sampleTime) {
1185  // If we are outside the time range where we have signal, then
1186  // take false as the certain sampled value.
1187  // See prev & next if condition and messages.
1188  s = false;
1189  } else {
1190  double o = discriminator(sampleTime);
1191  s = sampler(o);
1192  // Only log the relevant part:
1193  fLog(s, 4, false)('@')(sampleTime / fUnits.GetTimeUnit())(fUnits.GetTimeName())('|');
1194  }
1195  trace.PushBack(s);
1196  sampleTimes.push_back(sampleTime);
1197  }
1198  if (maxTimePostFE < stopTime) {
1199  // See inner body of the previous loop (then condition).
1200  fLog("Samples false in the range ", 4)
1201  (maxTimePostFE / fUnits.GetTimeUnit())(fUnits.GetTimeName())
1202  ("to")
1203  (stopTime / fUnits.GetTimeUnit())(fUnits.GetTimeName())
1204  ("as no signal in it.");
1205  }
1206  span = discriminator.GetOverThresholdTimeSpan();
1208  // PLOTS
1210  // If there are no extensions, then no plot will be performed at last:
1211  // so simply skip all this stuff.
1212  // On the other hand, every plot has an own flag to decide if it's
1213  // printed or not. Note that the flags are only used to do or not
1214  // the final print: ie all the logic is performed anyway, and just
1215  // the print may be avoided. This comes because in some cases there
1216  // dependencies between the variables used in different cases.
1217  //
1218  // But, if we are sampling the pulses, we need these stuff anyway.
1219  //
1220  if (fPlotFileExtensions.empty() &&
1224  return;
1225  // XXX Backing up the previous canvas may be needed (global variable)?
1226  fLog("Generating plots.", 3);
1227  // The canvas...
1228  std::stringstream canvasName;
1229  canvasName << "c"
1230  << channel.GetFrontEnd().GetModule().GetCounter().GetId() << "_"
1231  << channel.GetFrontEnd().GetModule().GetId() << "_"
1232  << channel.GetId();
1233  TCanvas canvas(canvasName.str().c_str() ,"Total SPE pulses", 200, 10, 700, 500);
1234  canvas.SetTickx();
1235  canvas.SetTicky();
1236  canvas.SetBorderMode(0);
1237  canvas.SetFillColor(0);
1238  canvas.SetFrameBorderMode(0);
1239  //canvas.SetGridx();
1240  //canvas.SetGridy();
1241 
1242  // The function for the total pulse prior front-end:
1243  std::stringstream totalPulseNamePre;
1244  totalPulseNamePre << "totalPulsePre_"
1245  << channel.GetFrontEnd().GetModule().GetCounter().GetId() << "_"
1246  << channel.GetFrontEnd().GetModule().GetId() << "_"
1247  << channel.GetId();
1248  TF1 totalPulseFunPre(totalPulseNamePre.str().c_str(),
1249  & totalPulsePreFrontEnd,
1250  minTimePreFE / fUnits.GetTimeUnit(),
1251  maxTimePreFE / fUnits.GetTimeUnit(),
1252  1, "");
1253  totalPulseFunPre.SetLineColor(kRed);
1254  totalPulseFunPre.SetLineWidth(2);
1255  totalPulseFunPre.SetLineStyle(1); // lines
1256  totalPulseFunPre.SetNpx(fNumPlotPoints);
1257  totalPulseFunPre.SetFillColor(canvas.GetFillColor()); // avoid a bounding box in the le
1258  totalPulseFunPre.Draw("X+");
1259  //
1260  // The individual pulses:
1261  unsigned int nPulse = 0;
1262  // Containers that own the pointers.
1263  OwnerVector<PulseFunctor> pFunctors;
1264  OwnerVector<TF1> pFunctions;
1265  pFunctors.reserve(si.fPulses.size());
1266  pFunctions.reserve(si.fPulses.size());
1267  for (PulseContainer::const_iterator p = si.fPulses.begin(), pe = si.fPulses.end(); p != pe; ++p) {
1268  PulseFunctor* pulse = new PulseFunctor(*p, fUnits.GetTimeUnit(), fUnits.GetElectricCurrentUnit());
1269  std::stringstream pulseName;
1270  pulseName << "pulse_" << nPulse++ << "_"
1271  << channel.GetFrontEnd().GetModule().GetCounter().GetId() << "_"
1272  << channel.GetFrontEnd().GetModule().GetId() << "_"
1273  << channel.GetId();
1274  TF1* pulseFun = new TF1(pulseName.str().c_str(),
1275  pulse, minTimePreFE / fUnits.GetTimeUnit(),
1276  maxTimePreFE / fUnits.GetTimeUnit(),
1277  1, "");
1278  pulseFun->SetLineColor(kBlack);
1279  pulseFun->SetLineWidth(1);
1280  pulseFun->SetLineStyle(2); // lines
1281  pulseFun->SetNpx(fNumPlotPoints);
1282  pulseFun->Draw("same");
1283  pFunctors.push_back(pulse);
1284  pFunctions.push_back(pulseFun);
1286  std::stringstream s;
1287  s << "spe " << nPulse << " " << channel.GetIdMessage();
1288  Dump(*pulseFun, s.str());
1289  }
1290  }
1291  totalPulseFunPre.SetTitle("SPEs");
1292  totalPulseFunPre.GetXaxis()->SetTitle(("Time (" + fUnits.GetTimeName() + ")").c_str());
1293  totalPulseFunPre.GetYaxis()->SetTitle(("Current (" + fUnits.GetElectricCurrentName() + ")").c_str());
1294  canvas.Update();
1296  std::stringstream s;
1297  s << "total_pre " << channel.GetIdMessage();
1298  Dump(totalPulseFunPre, s.str());
1299  }
1300  if (fPlotChannelPulses)
1301  PrintPlots(canvas, fPlotFileExtensions, Tag("channelPulses", channel)(fRunNumber));
1302  // ...and after the front-end pulse in voltage.
1303  fLog("Generating after-front-end total pulse.", 3);
1304  canvas.Clear();
1305  //
1306  const float rightMargin = 0.2;
1307  canvas.cd();
1308  TPad pad1("pad1", "", 0, 0, 1, 1);
1309  pad1.SetFrameBorderMode(0);
1310  pad1.SetFillColor(0);
1311  pad1.SetRightMargin(rightMargin);
1312  //pad1.SetGridx();
1313  //pad1.SetGridy();
1314  pad1.Draw();
1315  pad1.cd();
1316  /*
1317  **************************************************
1318  * XXX Plot the other signals prior the front-end.
1319  **************************************************
1320  */
1321  //
1322  // Total pulse after the front-end.
1323  fLog("Total pulse.", 3);
1324  std::stringstream totalPulseNamePost;
1325  totalPulseNamePost << "totalPulsePost_"
1326  << channel.GetFrontEnd().GetModule().GetCounter().GetId() << "_"
1327  << channel.GetFrontEnd().GetModule().GetId() << "_"
1328  << channel.GetId();
1329  TF1 totalPulseFunPost(totalPulseNamePost.str().c_str(),
1330  & totalPulsePostFrontEnd,
1331  minTimePostFE / fUnits.GetTimeUnit(),
1332  maxTimePostFE / fUnits.GetTimeUnit(),
1333  1, "");
1334  totalPulseFunPost.SetLineColor(kBlack);
1335  totalPulseFunPost.SetLineWidth(2);
1336  totalPulseFunPost.SetLineStyle(1); // long dashed lines
1337  totalPulseFunPost.SetFillColor(canvas.GetFillColor()); // avoid a bounding box in the le
1338  totalPulseFunPost.SetNpx(fNumPlotPoints);
1339  totalPulseFunPost.GetYaxis()->SetTitleOffset(1.2);
1340  totalPulseFunPost.Draw();
1341  //
1342  // Threshold (on top of the previous):
1343  fLog("Discrimination level [", 3)
1345  ThresholdFunctor thresFunctor(channel.GetThreshold(), fUnits.GetElectricPotentialUnit());
1346  TF1 thresFun("Discrimination level",
1347  & thresFunctor,
1348  minTimePostFE / fUnits.GetTimeUnit(),
1349  maxTimePostFE / fUnits.GetTimeUnit(),
1350  0, "");
1351  thresFun.SetLineColor(kBlack);
1352  thresFun.SetLineStyle(2);
1353  thresFun.SetLineWidth(1); //
1354  thresFun.SetNpx(fNumPlotPoints);
1355  thresFun.SetFillColor(canvas.GetFillColor()); // avoid a bounding box in the le
1356  thresFun.Draw("same");
1357  //
1358  // Discriminator output
1359  fLog("Discriminator output.", 3);
1360  canvas.cd();
1361  TPad pad2("pad2", "", 0, 0, 1, 1);
1362  pad2.SetRightMargin(rightMargin);
1363  pad2.SetFillStyle(0);
1364  pad2.SetFillColor(0);
1365  pad2.SetFrameFillStyle(4000);
1366  pad2.SetFrameBorderMode(0);
1367  pad2.SetFrameFillColor(0);
1368  pad2.Draw();
1369  pad2.cd();
1370  ProxyFunctor<mdet::Channel::Discriminator> discriminatorFunctor(
1371  discriminator, fUnits.GetTimeUnit(), fUnits.GetElectricPotentialUnit());
1372  TF1 discrimFun("Discriminator output",
1373  & discriminatorFunctor,
1374  minTimePostFE / fUnits.GetTimeUnit(),
1375  maxTimePostFE / fUnits.GetTimeUnit(),
1376  1, "");
1377  discrimFun.SetLineColor(kBlue);
1378  discrimFun.SetNpx(fNumPlotPoints);
1379  discrimFun.SetLineStyle(2); //
1380  discrimFun.SetLineWidth(1); //
1381  discrimFun.SetFillColor(canvas.GetFillColor()); // avoid a bounding box in the legend.
1382  // The output is fundamentally two valued (it's a discrimination): few divisions.
1383  discrimFun.GetYaxis()->SetNdivisions(4);
1384  // Increase the distance.
1385  discrimFun.GetYaxis()->SetTitleOffset(1.4);
1386  /*
1387  // XXX
1388  // Attempt: the grid is shown according the main ticks in the left axis, it would
1389  // be nice to have the grid matching the main ticks of both axis.
1390  //
1391  // Force the axis range:
1392  // discrimFun.GetHistogram()->SetMinimum(discrimFun.GetMinimum()); // to the minimum..
1393  // Use static_cast instead of C-style cast for primitive type unsigned int since it has a compound
1394  // name, so "unsigned int(a)" needs to be written as "(unsigned int)(a)": I prefer static_cast.
1395  unsigned int nIntDigits =
1396  static_cast<unsigned int>(TMath::Log10(totalPulseFunPost.GetHistogram()->GetMaximum()));
1397  double spacing = TMath::Power(10, nIntDigits);
1398  double grossRange = spacing *
1399  static_cast<unsigned int>(totalPulseFunPost.GetHistogram()->GetMaximum() / spacing);
1400  unsigned int axisMult = static_cast<unsigned int>(discrimFun.GetMaximum() / grossRange) + 1;
1401  std::cout << "FACT=" << nIntDigits << std::endl;
1402  std::cout << "FACT=" << spacing << std::endl;
1403  std::cout << "FACT=" << grossRange << std::endl;
1404  std::cout << "FACT=" << axisMult << std::endl;
1405  discrimFun.GetHistogram()->SetMaximum(axisMult * spacing);
1406  */
1407  // y on the right.
1408  discrimFun.Draw("Y+");
1409  // Hide x labels (once drawn)
1410  discrimFun.GetXaxis()->SetLabelSize(0);
1411  // Alternative A:
1412  // The samples equal to true are drawn at half the total function maximum.
1413  // const double trueLevel = totalPulseFun.GetMaximum(minTime, maxTime) / 2;
1414  // Alternative B(rian):
1415  // Put the trues over the threshold evaluating thresFunctor
1416  // Alternative C:
1417  // Having now an analog discriminator out, makes more to put the values
1418  // in the maximum of it.
1419  const double trueLevel = discrimFun.GetMaximum();
1420  // The samples.
1421  TVectorD samplesArray(nBinsTrace);
1422  // fLog("Samples: number of samples", 3)(nBinsTrace)(", number of times")(sampleTimes.size());
1423  // Draw the true samples with the same units as the drawn funcs.
1424  for (unsigned int i = 0; i < nBinsTrace; ++i)
1425  samplesArray[i] = trace[i] ? trueLevel : 0;
1426  // Samples
1427  /*
1428  * Regarding the to-C-array conversion implemented with the construct
1429  * &v[0] you have to see:
1430  * 6.2.3 - "Using Vectors as Ordinary Arrays" from
1431  * "The C++ Standard Library, The: A Tutorial and Reference"
1432  * by Nicolai M. Josuttis
1433  * Publisher: Addison Wesley
1434  *
1435  * and
1436  *
1437  * "C++ Standard Library Defect Report List"
1438  * (http://std.dkuug.dk/jtc1/sc22/wg21/docs/lwg-defects.html)
1439  * 69. Must elements of a vector be contiguous?
1440  * Section: 23.2.4 [lib.vector] Status: TC Submitter: Andrew Koenig Date: 29 Jul 1998
1441  *
1442  */
1443  TVectorD sampleTimes_vec;
1444  sampleTimes_vec.Use(sampleTimes.size(),&(sampleTimes[0]));
1445  TGraph samples(sampleTimes_vec, samplesArray);
1446  samples.SetMarkerColor(kRed);
1447  samples.SetMarkerStyle(kFullSquare);
1448  samples.SetFillStyle(0); // hollow
1449  samples.SetFillColor(canvas.GetFillColor()); // avoid a bounding box in the legend.
1450  samples.SetLineColor(canvas.GetFillColor()); // avoid the line in the legend.
1451  samples.Draw("P");
1452  // Axis labels.
1453  totalPulseFunPost.GetXaxis()->SetTitle(("Time (" + fUnits.GetTimeName() + ")").c_str());
1454  totalPulseFunPost.GetYaxis()->SetTitle(
1455  ("Front-end output voltage (" + fUnits.GetElectricPotentialName() + ")").c_str());
1456  discrimFun.GetYaxis()->SetTitle(
1457  ("Discriminator output voltage (" + fUnits.GetElectricPotentialName() + ")").c_str());
1458  // Legend...
1459  canvas.cd(); // to make the legend's coordinates relative to the main pad.
1460  //TLegend leg(0.02 + 1.0 - rightMargin, 0.02, 0.18 + 1.0 - rightMargin, 0.30);
1461  //TLegend leg(0.02 + 1.0 - rightMargin, 0.02, 0.18 + 1.0 - rightMargin, 0.30);
1462  TLegend leg;
1463  leg.SetNColumns( 3 );
1464  leg.SetEntrySeparation( 0.8 );
1465  //leg.SetX1NDC( fStyle->GetPadLeftMargin() );
1466  //leg.SetX2NDC( 1 - fStyle->GetPadRightMargin() );
1467  leg.SetX1NDC( 0 );
1468  leg.SetX2NDC( 1 );
1469  leg.SetY1NDC( 1 - fStyle->GetPadTopMargin() );
1470  leg.SetY2NDC( 1 );
1471  leg.SetBorderSize( 0 );
1472  leg.SetTextFont( fStyle->GetTitleFont() );
1473  leg.SetTextSize( fStyle->GetTitleSize()+0.01 );
1474  //leg.AddEntry(&thresFun, thresFun.GetName());
1475  leg.AddEntry(&totalPulseFunPost, "Analogical pulse","L");
1476  leg.AddEntry(&discrimFun, "Discriminator pulse", "L");
1477  leg.AddEntry(&samples, "Digital samples", "P");
1478  leg.SetFillColor(canvas.GetFillColor());
1479  leg.Draw();
1480  canvas.Update();
1482  std::stringstream s;
1483  s << "total_post " << channel.GetIdMessage();
1484  Dump(totalPulseFunPost, s.str());
1485  }
1486  if (fPlotOutcome)
1487  PrintPlots(canvas, fPlotFileExtensions, Tag("outcome", channel)(fRunNumber));
1488  //
1489  // Input / output comparison
1490  totalPulsePreFrontEnd.fAbs = true;
1491  totalPulsePostFrontEnd.fAbs = true;
1492  // Due to shift, and since we are plotting them overlapped here,
1493  // some commons begin/end values have to be calculated (if not two non-overlapping
1494  // x axis may be shown).
1495  const double minTimeMin = std::min(minTimePreFE, minTimePostFE) / fUnits.GetTimeUnit();
1496  const double maxTimeMax = std::max(maxTimePreFE, maxTimePostFE) / fUnits.GetTimeUnit();
1497  fLog("Generating input/output comparison plot.", 3);
1498  canvas.Clear();
1499  TPad pad3("pad3", "", 0, 0, 1, 1);
1500  pad3.SetFillColor(0);
1501  pad3.SetTickx();
1502  //pad3.SetGridx();
1503  //pad3.SetGridy();
1504  pad3.Draw();
1505  pad3.cd();
1506  //
1507  // New title:
1508  totalPulseFunPre.SetTitle("I/O");
1509  totalPulseFunPre.SetRange(minTimeMin, maxTimeMax);
1510  totalPulseFunPre.GetXaxis()->SetTitle(("Time (" + fUnits.GetTimeName() + ")").c_str());
1511  totalPulseFunPre.GetYaxis()->SetTitle(
1512  ("Current amplitude (" + fUnits.GetElectricCurrentName() + ")").c_str());
1513  totalPulseFunPre.Draw();
1514  TPad pad4("pad4", "", 0, 0, 1, 1);
1515  pad4.SetFillStyle(0);
1516  pad4.SetFillColor(0);
1517  pad4.SetFrameFillStyle(4000);
1518  pad4.SetFrameBorderMode(0);
1519  pad4.SetFrameFillColor(0);
1520  pad4.Draw();
1521  pad4.cd();
1522  totalPulseFunPost.SetRange(minTimeMin, maxTimeMax);
1523  totalPulseFunPost.GetYaxis()->SetTitle(
1524  ("Front-end output voltage amplitude (" + fUnits.GetElectricPotentialName() + ")").c_str());
1525  totalPulseFunPost.Draw("Y+");//X+ to put axis on top also.
1526  canvas.Update();
1527  if (fPlotInputOutput)
1528  PrintPlots(canvas, fPlotFileExtensions, Tag("input_output", channel)(fRunNumber));
1529  //
1530  // Transfer function (amplitude):
1531  fLog("Generating frequency response plots.", 3);
1532  canvas.Clear();
1533  canvas.SetLogx();
1534  canvas.SetLogy();
1535  TGraph ampFreqResponse(freqArray, ampArray);
1536  ampFreqResponse.SetMarkerStyle(21);
1537  ampFreqResponse.Draw("AP");
1538  ampFreqResponse.SetTitle("Front-end transfer function amplitude response");
1539  ampFreqResponse.GetXaxis()->SetTitle(("Frequency (" + fUnits.GetFrequencyName() + ")").c_str());
1540  ampFreqResponse.GetYaxis()->SetTitle(
1541  ("Amplitude (" + fUnits.GetElectricResistanceName() + ")").c_str());
1542  canvas.Update();
1544  PrintPlots(canvas, fPlotFileExtensions, Tag("transferAmpResponse", channel)(fRunNumber));
1545  //
1546  // Transfer function (phase):
1547  canvas.Clear();
1548  canvas.SetLogx();
1549  canvas.SetLogy(kFALSE);
1550  TGraph phaFreqResponse(freqArray, phaArray);
1551  phaFreqResponse.SetMarkerStyle(21);
1552  phaFreqResponse.Draw("AP");
1553  phaFreqResponse.SetTitle("Front-end transfer function phase response");
1554  phaFreqResponse.GetXaxis()->SetTitle(("Frequency (" + fUnits.GetFrequencyName() + ")").c_str());
1555  phaFreqResponse.GetYaxis()->SetTitle(("Phase (" + fUnits.GetAngleName() + ")").c_str());
1556  canvas.Update();
1558  PrintPlots(canvas, fPlotFileExtensions, Tag("transferPhaseResponse", channel)(fRunNumber));
1559  //
1560  // Delay.
1561  if (phaFreqResponse.GetN() > 1) {
1562  canvas.Clear();
1563  TGraphFunctor phaFreRespFunctor(phaFreqResponse);
1564  const double bFreq = phaFreqResponse.GetX()[0];
1565  const double eFreq = phaFreqResponse.GetX()[phaFreqResponse.GetN() - 1];
1566  TF1 phaFreqRespTF1("Phase", &phaFreRespFunctor, bFreq, eFreq, 1, "");
1567  phaFreqRespTF1.SetNpx(fNumPlotPoints);
1568  phaFreqRespTF1.SetLineStyle(2); // long dash-dot
1569  // The group delay is Gd = - d Phase / d w
1570  double factor = -1.0; // So put the sign.
1571  factor /= utl::kTwoPi; // the former data is in terms of f (w = 2 pi f).
1572  // Now, since we are computing a derivative against f, the units will be time; but
1573  // not necesarily the common time unit used in the module: it will be the inverse
1574  // of the chosen frequency unit. So apply the conversion factor:
1575  // 1) now we have back in time units the values (since the data was divided by the
1576  // freq unit, as this comes from the TGraph used to plot). We have to divide because
1577  // the factor entered as
1578  // d Phase / d ( f / fu)
1579  // that's the derivative against f scaled by the unit fu, so fu entered multiplying,
1580  // so we divide to get the value in Auger-units.
1581  factor /= fUnits.GetFrequencyUnit() ;
1582  // 2) now we divide by the desired unit to express the final value in the desired units
1583  // of time.
1584  factor /= fUnits.GetTimeUnit();
1585  DerivativeFunctor derivative(phaFreqRespTF1, factor);
1586  TF1 delayRespTF1("Delay", &derivative, bFreq, eFreq, 1, "");
1587  delayRespTF1.SetNpx(fNumPlotPoints);
1588  delayRespTF1.SetLineStyle(1); // short dash
1589  TPad pad5("pad5", "", 0, 0, 1, 1);
1590  pad5.SetFillColor(0);
1591  pad5.SetFrameBorderMode(0);
1592  //pad5.SetGridx();
1593  //pad5.SetGridy();
1594  pad5.SetLogx(kTRUE);
1595  pad5.SetLogy(kFALSE);
1596  pad5.Draw();
1597  pad5.cd();
1598  phaFreqRespTF1.Draw();
1599  TPad pad6("pad6", "", 0, 0, 1, 1);
1600  pad6.SetFillStyle(0);
1601  pad6.SetFillColor(0);
1602  pad6.SetFrameFillStyle(4000);
1603  pad6.SetFrameBorderMode(0);
1604  pad6.SetFrameFillColor(0);
1605  pad6.SetLogx(kTRUE);
1606  pad6.SetLogy(kFALSE);
1607  pad6.Draw();
1608  pad6.cd();
1609  delayRespTF1.Draw("Y+");
1610  phaFreqRespTF1.SetTitle("Phase and group delay");
1611  phaFreqRespTF1.GetXaxis()->SetTitle(("Frequency (" + fUnits.GetFrequencyName() + ")").c_str());
1612  phaFreqRespTF1.GetYaxis()->SetTitle(("Phase (" + fUnits.GetAngleName() + ")").c_str());
1613  delayRespTF1.GetYaxis()->SetTitle(("Time (" + fUnits.GetTimeName() + ")").c_str());
1614  TLegend leg(0.65, 0.70, 0.85, 0.9);
1615  leg.AddEntry(&phaFreqRespTF1, "Phase response");
1616  leg.AddEntry(&delayRespTF1, "Group delay");
1617  leg.Draw();
1618  canvas.Update();
1619  if (fPlotDelay)
1620  PrintPlots(canvas, fPlotFileExtensions, Tag("delay", channel)(fRunNumber));
1621  }
1622  //
1623  // FFT amplitude plot prior front-end.
1624  canvas.Clear();
1625  canvas.SetLogx();
1626  canvas.SetLogy();
1627  TGraph fftPlotPre(freqArray, preFFT);
1628  fftPlotPre.SetMarkerStyle(21);
1629  fftPlotPre.SetMarkerColor(kBlue);
1630  fftPlotPre.Draw("AP");
1631  fftPlotPre.SetTitle("Fourier amplitude spectrum prior front-end");
1632  fftPlotPre.GetXaxis()->SetTitle(("Frequency (" + fUnits.GetFrequencyName() + ")").c_str());
1633  fftPlotPre.GetYaxis()->SetTitle(("Current (" + fUnits.GetElectricCurrentName() + ")").c_str());
1634  canvas.Update();
1635  if (fPlotFftPriorAmp)
1636  PrintPlots(canvas, fPlotFileExtensions, Tag("fftPriorAmp", channel)(fRunNumber));
1637  //
1638  // FFT amplitude plot after front-end.
1639  canvas.Clear();
1640  canvas.SetLogx();
1641  canvas.SetLogy();
1642  TGraph fftPlotPost(freqArray, postFFT);
1643  fftPlotPost.SetMarkerStyle(21);
1644  fftPlotPost.SetMarkerColor(kRed);
1645  fftPlotPost.Draw("AP");
1646  fftPlotPost.SetTitle("Fourier amplitude spectrum after front-end.");
1647  fftPlotPost.GetXaxis()->SetTitle(("Frequency (" + fUnits.GetFrequencyName() + ")").c_str());
1648  fftPlotPost.GetYaxis()->SetTitle(("Voltage (" + fUnits.GetElectricPotentialName() + ")").c_str());
1649  canvas.Update();
1650  if (fPlotFftPostAmp)
1651  PrintPlots(canvas, fPlotFileExtensions, Tag("fftPostAmp", channel)(fRunNumber));
1652 }
1653 
1654 /*
1655  * Over-load for the SiPM simulations.
1656  *
1657  * We tried to make this code as similar as possible as it was for the PMTs.
1658  * However, the PMT method is quite a mess (> 700 lines!), and the code is way over-commented.
1659  *
1660  * Examples:
1661  *
1662  * "return; // done." (line 843)
1663  * ---------------------------------
1664  * // Clear the trace: (line 825)
1665  * trace.ClearTrace();
1666  *
1667  * We are breaking the SiPM code in new methods that can (and should!) be used by the PMTs.
1668  * Still, we are not touching the PMT code. At this point, either the PMT code is removed or someone
1669  * should re-write it.
1670  *
1671  * */
1672 void
1674  const SignalInformation& si,
1675  utl::TraceB& trace,
1676  utl::TraceD& traceAnalogical,
1677  double& span,
1678  const utl::TimeInterval& traceStart,
1679  double& minTimePreFE,
1680  double& maxTimePreFE,
1681  double& analogicTraceStartTime,
1682  double& analogicTraceEndTime)
1683 {
1684 
1685  const mdet::FrontEndSiPM& frontEnd = channel.GetFrontEnd();
1686 
1687  const double sRate = frontEnd.GetMeanSampleRatePeriod();
1688  trace.ClearTrace();
1689  traceAnalogical.ClearTrace();
1690  trace.SetBinning(sRate);
1691 
1692  fLog("Cleaning trace and setting a binning of", 2)(sRate / fUnits.GetTimeUnit())(fUnits.GetTimeName());
1693  const unsigned int nBinsTrace = frontEnd.GetPreT1BufferLength() + frontEnd.GetPostT1BufferLength();
1694  fLog("Trace size", 2)(nBinsTrace);
1695 
1696  bool isAnalogicTrace = si.fScintSimData && si.fScintSimData->HasAnalogicTrace();
1697  if (si.fSiPMPulses.empty() && ! isAnalogicTrace) {
1698  fLog("No pulses and other sim data found for channel", 1)(channel.GetId());
1699  for (unsigned int i = 0; i < nBinsTrace; ++i)
1700  trace.PushBack(false);
1701  span = 0;
1702  return;
1703  }
1704 
1705  /************************
1706  * Get trace timing *
1707  ************************/
1708  const double pulseTimeSpan = maxTimePreFE-minTimePreFE;
1709 
1710 
1711  /*****************************
1712  * Apply CITIROC Transfer *
1713  *****************************/
1714  TimeTrace totalPulsePostFrontEndTrace;
1715  TimeTrace totalPulsePostDiscriminatorTrace;
1716 
1717  ApplyCITIROCTransfer(channel, si, pulseTimeSpan, minTimePreFE, analogicTraceStartTime, analogicTraceEndTime,
1718  totalPulsePostFrontEndTrace, totalPulsePostDiscriminatorTrace, traceAnalogical);
1719 
1720 
1721  /*****************************
1722  * FPGA Sampling and plots *
1723  *****************************/
1724  SampleTrace(minTimePreFE, maxTimePreFE, pulseTimeSpan / fNDiscretization, frontEnd, traceStart, totalPulsePostDiscriminatorTrace, trace);
1725 
1726  PlotChannel(traceStart.GetInterval(), minTimePreFE, pulseTimeSpan / fNDiscretization, channel, traceAnalogical,
1727  totalPulsePostFrontEndTrace, totalPulsePostDiscriminatorTrace, trace);
1728 
1729 }
1730 
1731 /********************************************
1732  * *
1733  * Trace Timing *
1734  * *
1735  ********************************************/
1736 
1737 double
1738 MdCounterSimulator::GetPulseTimeSpan(const SignalInformation& si, const utl::TimeStamp& eventTime, double& minTimePreFE, double& maxTimePreFE,
1739  double& analogicTraceStartTime, double& analogicTraceEndTime){
1740 
1741  bool isAnalogicTrace = si.fScintSimData && si.fScintSimData->HasAnalogicTrace();
1742 
1743  minTimePreFE = std::numeric_limits<double>::max();
1744  maxTimePreFE = -std::numeric_limits<double>::max();
1745  analogicTraceStartTime = 0;
1746  analogicTraceEndTime = 0;
1747 
1748  std::unique_ptr<utl::TabularStream> spanTable;
1749  const unsigned int pulseSpanLogLevel = 3;
1750  if (fLog.GetLevel() >= pulseSpanLogLevel) {
1751  Init(spanTable, 3);
1752  *spanTable << utl::hline
1753  << "# pe" << utl::endc // 1
1754  << "min (" << fUnits.GetTimeName() << ")" << utl::endc // 2
1755  << "max (" << fUnits.GetTimeName() << ")" << utl::endr;// 3
1756  }
1757  unsigned int nPE = 0;
1758  for (SiPMPulseContainer::const_iterator p = si.fSiPMPulses.begin(), e = si.fSiPMPulses.end(); p != e; ++p) {
1759  minTimePreFE = std::min(minTimePreFE, p->LowerLimit());
1760  maxTimePreFE = std::max(maxTimePreFE, p->UpperLimit());
1761  if (fLog.GetLevel() >= (pulseSpanLogLevel+1)) {
1762  *spanTable << utl::hline
1763  << ++nPE << utl::endc
1764  << fLog << p->LowerLimit() / fUnits.GetTimeUnit() << utl::endc
1765  << fLog << p->UpperLimit() / fUnits.GetTimeUnit() << utl::endr;
1766  }
1767  }
1768 
1769  if (isAnalogicTrace) {
1770  analogicTraceStartTime = (si.fScintSimData->GetAnalogicTraceStartTime() - eventTime).GetInterval();
1771  analogicTraceEndTime = analogicTraceStartTime + si.fScintSimData->GetAnalogicTrace().GetSize() *
1773  minTimePreFE = std::min(minTimePreFE, analogicTraceStartTime);
1774  maxTimePreFE = std::max(maxTimePreFE, analogicTraceEndTime);
1775  }
1776  // The span covers both the range of pulses as well that of the analogic trace.
1777  const double pulseTimeSpan = maxTimePreFE - minTimePreFE;
1778  if (fLog.GetLevel() >= pulseSpanLogLevel) {
1779  *spanTable << utl::hline
1780  << "all" << utl::endc
1781  << fLog << minTimePreFE / fUnits.GetTimeUnit() << utl::endc
1782  << fLog << maxTimePreFE / fUnits.GetTimeUnit() << utl::endr
1783  << utl::hline;
1784  fLog("PE pulses and other signals span:", pulseSpanLogLevel);
1785  fLog(spanTable->Str(), pulseSpanLogLevel);
1786  }
1787  return pulseTimeSpan;
1788 }
1789 
1790 /********************************************
1791  * *
1792  * CITIROC Transfer *
1793  * *
1794  ********************************************/
1795 
1796 void
1797 MdCounterSimulator::ApplyCITIROCTransfer(const mdet::ChannelSiPM& channel, const SignalInformation& si, const double pulseTimeSpan, double minTimePreFE,
1798  double analogicTraceStartTime, double analogicTraceEndTime, TimeTrace& totalPulsePostFrontEndTrace,
1799  TimeTrace& totalPulsePostDiscriminatorTrace, utl::TraceD& traceAnalogical){
1800 
1801  TotalPulseFunctor<SiPMPulseContainer> totalPulsePreFrontEnd(si.fSiPMPulses,
1802  fUnits.GetTimeUnit(),
1804  bool isAnalogicTrace = si.fScintSimData && si.fScintSimData->HasAnalogicTrace();
1805 
1806  fLog("Applying FFT...", 3);
1807 
1808  /**************************************************
1809  * First transform the trace into Fourier space *
1810  **************************************************/
1811 
1813 
1814  double binning = pulseTimeSpan / fNDiscretization;
1815  TimeTrace& timeTrace = fft.GetTimeSeries();
1816  fLog("Time discretization binning ", 4)(binning / fUnits.GetTimeUnit())(fUnits.GetTimeName());
1817  timeTrace.SetBinning(binning);
1818  fLog("Discretizing total pulses. Number of samples:", 3, false);
1819 
1820  for (unsigned int i = 0; i < fNDiscretization || fLog(i, 3)('.'); ++i) {
1821  double time = minTimePreFE + i * binning;
1822  double value = totalPulsePreFrontEnd(time);
1823  if (isAnalogicTrace) {
1824 
1825  if (analogicTraceStartTime <= time && time <= analogicTraceEndTime) {
1826 
1827  double delta = time - analogicTraceStartTime;
1828  delta /= si.fScintSimData->GetAnalogicTrace().GetBinning();
1830  value += si.fScintSimData->GetAnalogicTrace()[index];
1831  }
1832  }
1833  fft.GetTimeSeries().PushBack(value);
1834  traceAnalogical.PushBack(value); //Already prepare the Input trace for the integrator
1835  }
1836 
1837  /**************************************************
1838  * Apply pre-amplifier and fast shaper transfer *
1839  **************************************************/
1840 
1841  fLog("Applying transfer function in frequency spectrum.", 3);
1842  FrequencyTrace& freqTrace = fft.GetFrequencySpectrum();
1843  const FrequencyTrace::SizeType nFreq = fft.GetConstFrequencySpectrum().GetSize();
1844  const double freqBinning = fft.GetConstFrequencySpectrum().GetBinning();
1845 
1846  fLog("Generating frequency response.", 3);
1847  const unsigned int tabFFTLogLevel = 4;
1848  std::unique_ptr<utl::TabularStream> tabFFT;
1849  if (fLog.GetLevel() >= tabFFTLogLevel) {
1850  Init(tabFFT, 4);
1851  *tabFFT << utl::hline
1852  << "Size" << utl::endc //1
1853  << "Binning (" << fUnits.GetFrequencyName() << ")" << utl::endc //2
1854  << "1st freq (" << fUnits.GetFrequencyName() << ")" << utl::endc //3
1855  << "Last freq (" << fUnits.GetFrequencyName() << ")" << utl::endr //4
1856  << nFreq << utl::endc // 1
1857  << fLog << (freqBinning / fUnits.GetFrequencyUnit()) << utl::endc // 2
1858  << fLog << (fft.GetFrequencyOfBin(0) / fUnits.GetFrequencyUnit()) << utl::endc // 3
1859  << fLog << (fft.GetFrequencyOfBin(nFreq - 1) / fUnits.GetFrequencyUnit()) << utl::endr // 4
1860  << utl::hline;
1861  fLog(tabFFT->Str(), tabFFTLogLevel);
1862  }
1863  for (FrequencyTrace::SizeType freqBin = 0; freqBin < nFreq; ++freqBin) {
1864  double freq = fft.GetFrequencyOfBin(freqBin) / fUnits.GetFrequencyUnit();//From GHz(ns) to MHz
1865  std::complex<double> c = channel.ComputeTransfer(freq);
1866  freqTrace[ freqBin ] *= c;
1867 
1868  }
1869  fLog("Obtaining the amplified pulses in time-space...", 3);
1870  totalPulsePostFrontEndTrace = fft.GetTimeSeries();
1871 
1872  /**************************************************
1873  * Simulate discriminator response *
1874  **************************************************/
1875 
1876  const TimeTrace::SizeType nTime = totalPulsePostFrontEndTrace.GetSize();
1877  for (TimeTrace::SizeType timeBin = 0; timeBin < nTime; ++timeBin) {
1878  double discriminatorOuput = channel.ComputeDiscriminator(totalPulsePostFrontEndTrace[timeBin], binning);
1879  totalPulsePostDiscriminatorTrace.PushBack(discriminatorOuput);
1880  }
1881 }
1882 
1883 /************************************
1884  * *
1885  * FPGA Sampling *
1886  * *
1887  ************************************/
1888 
1889 void
1890 MdCounterSimulator::SampleTrace(double minTimePostFE, double maxTimePostFE, double binning, const mdet::FrontEndSiPM& frontEnd,
1891  const utl::TimeInterval& traceStart, TimeTrace& totalPulsePostDiscriminatorTrace, utl::TraceB& trace){
1892 
1893  fLog("Creating sampler object.", 3);
1894  mdet::FrontEndSiPM::Sampler sampler = frontEnd.MakeSampler();
1895  const double sRate = frontEnd.GetMeanSampleRatePeriod();
1896  const unsigned int nBinsTrace = frontEnd.GetPreT1BufferLength() + frontEnd.GetPostT1BufferLength();
1897 
1898  std::vector<double> sampleTimes;
1899  // sampleTimes.reserve(nBinsTrace);
1900  fLog("Sampling pulses.", 3);
1901  const double startTime = traceStart.GetInterval();
1902  const double stopTime = startTime +
1903  sRate * (frontEnd.GetPreT1BufferLength() + frontEnd.GetPostT1BufferLength());
1904 
1905  if (startTime < minTimePostFE) {
1906  fLog("Samples false in the range", 4)
1907  (startTime / fUnits.GetTimeUnit())(fUnits.GetTimeName())
1908  ("to")
1909  (minTimePostFE / fUnits.GetTimeUnit())(fUnits.GetTimeName())
1910  ("as no signal in it.");
1911  }
1912  fLog("Samples:", 4);
1913 
1914  for (double sampleTime = startTime; trace.GetSize() < nBinsTrace || fLog('\n', 4)(sampleTime);
1915  sampleTime += sRate) {
1916 
1917  bool s;
1918  if (sampleTime < minTimePostFE || maxTimePostFE < sampleTime) {
1919  s = false;
1920  } else {
1921  int bin = (int)((sampleTime-minTimePostFE)/binning);
1922  double o = totalPulsePostDiscriminatorTrace[bin];
1923  s = sampler(o);
1924  // Only log the relevant part:
1925  fLog(s, 4, false)('@')(sampleTime / fUnits.GetTimeUnit())(fUnits.GetTimeName())('|');
1926  }
1927  trace.PushBack(s);
1928  sampleTimes.push_back(sampleTime);
1929  }
1930 
1931  if (maxTimePostFE < stopTime) {
1932  // See inner body of the previous loop (then condition).
1933  fLog("Samples false in the range ", 4)
1934  (maxTimePostFE / fUnits.GetTimeUnit())(fUnits.GetTimeName())
1935  ("to")
1936  (stopTime / fUnits.GetTimeUnit())(fUnits.GetTimeName())
1937  ("as no signal in it.");
1938  }
1939 
1940 }
1941 
1942 void
1944 
1945  const mdet::FrontEndSiPM& frontEnd = module.GetFrontEndSiPM();
1946  short bin = frontEnd.GetInjectDigitalNoiseBin();
1947  if(bin>=0){
1948 
1949  unsigned short width = frontEnd.GetInjectDigitalNoiseWidth();
1950  unsigned short channelId = frontEnd.GetInjectDigitalNoiseChannel();
1951  if(evtModule.HasChannel(channelId)){
1952  mevt::Channel& channel = evtModule.GetChannel(channelId);
1953  if (!channel.HasTrace())
1954  channel.MakeTrace();
1955  utl::TraceB& trace = channel.GetTrace();
1956  unsigned short limit = std::min(width+bin, (int)trace.GetSize());
1957 
1958  for(short i = bin; i<limit; i++){
1959  trace[i] = true;
1960  }
1961  }
1962  }
1963 
1964 }
1965 
1966 void
1967 MdCounterSimulator::PlotChannel(const double traceStartTime, const double minTimePreFE, const double binning, const mdet::ChannelSiPM& channel,
1968  utl::TraceD& traceAnalogical, TimeTrace& totalPulsePostFrontEndTrace, TimeTrace& totalPulsePostDiscriminatorTrace, utl::TraceB& trace){
1969 
1970  if (fPlotFileExtensions.empty() &&
1974  return;
1975 
1976  TVectorD analogicalTime(traceAnalogical.GetSize());
1977  TVectorD traceAnalogicalVec(traceAnalogical.GetSize());
1978  TVectorD totalPulsePostFrontEndVec(traceAnalogical.GetSize());
1979  TVectorD totalPulsePostDiscriminatorVec(traceAnalogical.GetSize());
1980 
1981 
1982  TVectorD digitalTime(trace.GetSize());
1983  TVectorD traceFPGA(trace.GetSize());
1984 
1985  const double sRate = channel.GetFrontEnd().GetMeanSampleRatePeriod();
1986  const double discriminatorHiLevel = 3.0;//channel.GetDiscriminatorHiLevel();
1987 
1988  for(unsigned int i=0; i<traceAnalogical.GetSize(); i++){
1989  analogicalTime[i] = (i*binning + minTimePreFE);
1990  traceAnalogicalVec[i] = -1*traceAnalogical[i]; //Invert only for visual purpose.
1991  totalPulsePostFrontEndVec[i] = totalPulsePostFrontEndTrace[i];
1992  totalPulsePostDiscriminatorVec[i] = totalPulsePostDiscriminatorTrace[i];
1993  }
1994 
1995  for(unsigned int i=0; i<trace.GetSize(); i++){
1996  digitalTime[i] = (i*sRate + traceStartTime);
1997  traceFPGA[i] = ((double)trace[i]*discriminatorHiLevel);//rescale
1998  }
1999 
2000 
2001  fLog("Generating plots.", 3);
2002  // The canvas...
2003  std::stringstream canvasName;
2004  canvasName << "c"
2005  << channel.GetFrontEnd().GetModule().GetCounter().GetId() << "_"
2006  << channel.GetFrontEnd().GetModule().GetId() << "_"
2007  << channel.GetId();
2008  TCanvas canvas(canvasName.str().c_str() ,"Channel Output", 200, 10, 700, 500);
2009  canvas.SetTickx();
2010  canvas.SetTicky();
2011  canvas.SetBorderMode(0);
2012  canvas.SetFillColor(0);
2013  canvas.SetFrameBorderMode(0);
2014  //canvas.SetGridx();
2015  //canvas.SetGridy();
2016 
2017  TGraph totalPulsePrePlot(analogicalTime, traceAnalogicalVec);
2018  totalPulsePrePlot.SetLineWidth(3);
2019  totalPulsePrePlot.SetLineColor(kBlue);
2020 
2021  TGraph pulsePostFrontEndPlot(analogicalTime, totalPulsePostFrontEndVec);
2022  pulsePostFrontEndPlot.SetLineWidth(3);
2023  pulsePostFrontEndPlot.SetLineColor(kOrange);
2024 
2025  TGraph pulsePostDiscriminatorPlot(analogicalTime, totalPulsePostDiscriminatorVec);
2026  pulsePostDiscriminatorPlot.SetLineWidth(3);
2027  pulsePostDiscriminatorPlot.SetLineColor(kBlack);
2028 
2029  TGraph pulsePostFPGAPlot(digitalTime, traceFPGA);
2030  pulsePostFPGAPlot.SetMarkerColor(kRed);
2031  pulsePostFPGAPlot.SetMarkerStyle(29);
2032  pulsePostFPGAPlot.SetMarkerSize(1.2);
2033 
2034  pulsePostFPGAPlot.GetXaxis()->SetTitle(("Time (" + fUnits.GetTimeName() + ")").c_str());
2035  pulsePostFPGAPlot.GetYaxis()->SetTitle(("Voltage (" + fUnits.GetElectricPotentialName() + ")").c_str());
2036  canvas.Update();
2037  canvas.cd();
2038 
2039  pulsePostFPGAPlot.Draw("AP");
2040  pulsePostFrontEndPlot.Draw("SAME");
2041  totalPulsePrePlot.Draw("SAME");
2042  pulsePostDiscriminatorPlot.Draw("SAME");
2043 
2044  TLegend leg;
2045  leg.SetNColumns( 3 );
2046  leg.SetEntrySeparation( 0.8 );
2047  //leg.SetX1NDC( fStyle->GetPadLeftMargin() );
2048  //leg.SetX2NDC( 1 - fStyle->GetPadRightMargin() );
2049  leg.SetX1NDC( 0 );
2050  leg.SetX2NDC( 1 );
2051  leg.SetY1NDC( 1 - fStyle->GetPadTopMargin() );
2052  leg.SetY2NDC( 1 );
2053  leg.SetBorderSize( 0 );
2054  leg.SetTextFont( fStyle->GetTitleFont() );
2055  leg.SetTextSize( fStyle->GetTitleSize()+0.01 );
2056  //leg.AddEntry(&thresFun, thresFun.GetName());
2057  leg.AddEntry(&totalPulsePrePlot, "SiPM pulse","L");
2058  leg.AddEntry(&pulsePostFrontEndPlot, "Fast Shaper output", "L");
2059  leg.AddEntry(&pulsePostDiscriminatorPlot, "Discriminator output", "L");
2060  leg.AddEntry(&pulsePostFPGAPlot, "FPGA samples", "P");
2061  leg.SetFillColor(canvas.GetFillColor());
2062  leg.Draw();
2063  canvas.Update();
2064 
2065  /* std::stringstream outputName;
2066  outputName << "./output/output_"
2067  << channel.GetFrontEnd().GetModule().GetCounter().GetId() << "_"
2068  << channel.GetFrontEnd().GetModule().GetId() << "_"
2069  << channel.GetId()
2070  << ".root";
2071 
2072 
2073  canvas.SaveAs(outputName.str().c_str());*/
2074  if (fPlotOutcome)
2075  PrintPlots(canvas, fPlotFileExtensions, Tag("outcome", channel)(fRunNumber));
2076 
2077 }
2078 
2079 /*
2080  *
2081  *Simulate the Integrator electronics. 1 run per module
2082  *
2083  * */
2084 void
2086  std::vector<utl::TraceD> analogicalTraces,
2087  utl::TraceUSI& traceIntegratorA,
2088  utl::TraceUSI& traceIntegratorB,
2089  const utl::TimeInterval& traceStart,
2090  double& minTimePreFE,
2091  double& maxTimePreFE)
2092 {
2093 
2094  const mdet::BackEndSiPM& backEnd = module.GetBackEndSiPM();
2095  const mdet::FrontEndSiPM& frontEnd = module.GetFrontEndSiPM();
2096 
2097  const double sRateCounter = frontEnd.GetMeanSampleRatePeriod();
2098  const double sRateIntegrator = frontEnd.GetSampleTimeADC();
2099  traceIntegratorA.ClearTrace();
2100  traceIntegratorB.ClearTrace();
2101  traceIntegratorA.SetBinning(sRateIntegrator);
2102  traceIntegratorB.SetBinning(sRateIntegrator);
2103  fLog("Cleaning Integrator Traces and setting a binning of", 2)(sRateIntegrator / fUnits.GetTimeUnit())(fUnits.GetTimeName());
2104  const unsigned int nBinsTrace = (frontEnd.GetPreT1BufferLength() + frontEnd.GetPostT1BufferLength())*sRateCounter/sRateIntegrator;
2105  fLog("Trace size", 2)(nBinsTrace);
2106  if (analogicalTraces.empty()) {
2107  fLog("No pulses data for this module", 2)(module.GetId());
2108  for (unsigned int i = 0; i < nBinsTrace; ++i){
2109  traceIntegratorA.PushBack(0);
2110  traceIntegratorB.PushBack(0);
2111  }
2112  return;
2113  }
2114  for(unsigned int i = 0; i<analogicalTraces.size(); i++){
2115  if(analogicalTraces[i].GetSize() != fNDiscretization){
2116  fLog("Channel traces are corrupted", 1)(module.GetId());
2117  return;
2118  }
2119  }
2120 
2121 // const double pulseTimeSpan = maxTimePreFE-minTimePreFE;
2122 
2123 
2124  /**********************************************
2125  * Apply Transfer from first adder to ADC *
2126  **********************************************/
2127  TimeTrace traceAfterADCLowGain;
2128  TimeTrace traceAfterADCHighGain;
2129  TVectorD totalAnalogicalInput(fNDiscretization);
2130 
2132  ApplyBackEndTransfer(backEnd, maxTimePreFE, minTimePreFE, traceAfterADCLowGain, traceAfterADCHighGain, totalAnalogicalInput, analogicalTraces);
2133  }else{
2134  ApplyBackEndTransferWStepSaturation(backEnd, maxTimePreFE, minTimePreFE, traceAfterADCLowGain, traceAfterADCHighGain, totalAnalogicalInput, analogicalTraces);
2135 
2136  }
2137  /*****************************
2138  * ADC Sampling and plots *
2139  *****************************/
2140  SampleTraceADC(minTimePreFE, maxTimePreFE, frontEnd, traceStart, traceAfterADCLowGain, traceAfterADCHighGain, traceIntegratorA, traceIntegratorB);
2141  PlotIntegrator(traceStart.GetInterval(), minTimePreFE, (maxTimePreFE-minTimePreFE) / fNDiscretization,
2142  frontEnd, totalAnalogicalInput, traceAfterADCLowGain, traceAfterADCHighGain, traceIntegratorA, traceIntegratorB);
2143  //PlotIntegrator(traceStart.GetInterval(), minTimePreFE, (maxTimePreFE-minTimePreFE) / fNDiscretization, frontEnd, totalAnalogicalInput, traceAfterADCLowGain, traceAfterADCHighGain);
2144 }
2145 
2146 
2147 /****************************************************************************
2148  * *
2149  * Integrator BackEnd Transfer Apply intermediate steps saturation *
2150  * *
2151  ****************************************************************************/
2152 
2153 void
2154 MdCounterSimulator::ApplyBackEndTransferWStepSaturation(const mdet::BackEndSiPM& backEnd, const double maxTimePreFE, const double minTimePreFE,
2155  TimeTrace& traceAfterADCLowGain, TimeTrace& traceAfterADCHighGain, TVectorD& totalAnalogicalInput, const std::vector<utl::TraceD> analogicalTraces){
2156 
2157  fLog("Applying FFT Integrator...", 3);
2158 
2159  /****************************************************************************
2160  * First add every 16 channels and transform the trace into Fourier space *
2161  ****************************************************************************/
2162 
2163  double binning = (maxTimePreFE-minTimePreFE) / fNDiscretization;
2164  const double numberOfChannelsToGroup = backEnd.GetNumberOfChannelsToGroup();
2165  int nroChannels = analogicalTraces.size();
2166  double nroOfAdders = nroChannels/numberOfChannelsToGroup;
2167 
2168  std::vector<TimeTrace> tracesPostFirstAdder;
2169  for (int adder = 0; adder < nroOfAdders; adder++) { //4
2170 
2171  int fromChannel = adder*numberOfChannelsToGroup;
2172  int toChannel = (adder+1)*numberOfChannelsToGroup;
2173  toChannel = std::min(toChannel, nroChannels);
2174  fLog("Adding pulses. From/To channel:", 3)(fromChannel)(toChannel);
2175 
2177  fLog("Time discretization binning ", 4)(binning / fUnits.GetTimeUnit())(fUnits.GetTimeName());
2178  fft.GetTimeSeries().SetBinning(binning);
2179 
2180  for (unsigned int i = 0; i < fNDiscretization; ++i) {
2181  double value = 0;
2182  //not efficient, but there are not that many iterations.
2183  for (int channel = fromChannel; channel < toChannel; channel++) { //16
2184  value += analogicalTraces[channel][i];
2185  }
2186  fft.GetTimeSeries().PushBack(value);
2187  totalAnalogicalInput[i] += value;
2188  }
2189 
2190  ApplyTransferBlock(fft, backEnd, backEnd.eFirstAdder);
2191 
2192  fLog("Obtaining the amplified pulses in time-space...", 3);
2193  tracesPostFirstAdder.push_back(fft.GetTimeSeries());
2194  }
2195 
2197  fft.GetTimeSeries().SetBinning(binning);
2198  for(unsigned int i = 0; i<fNDiscretization; i++){
2199  double value = 0;
2200  for(unsigned int adder = 0; adder < tracesPostFirstAdder.size(); adder++){
2201  value += backEnd.ApplySaturation(tracesPostFirstAdder[adder][i],backEnd.eFirstAdder);
2202  }
2203  fft.GetTimeSeries().PushBack(value);
2204  }
2205 
2206  /************************************
2207  * Second Adder *
2208  ************************************/
2209  ApplyTransferBlock(fft, backEnd, backEnd.eSecondAdder);
2210  TimeTrace& tracePreLGChannel = fft.GetTimeSeries();
2211 
2213  fftHGChannel.GetTimeSeries().SetBinning(binning);
2214  TimeTrace& tracePreHGChannel = fftHGChannel.GetTimeSeries();
2215 
2216  for(unsigned int i = 0; i<fNDiscretization; i++){
2217 
2218  tracePreLGChannel[i] = backEnd.ApplySaturation(tracePreLGChannel[i],backEnd.eSecondAdder);
2219  tracePreHGChannel.PushBack(tracePreLGChannel[i]);
2220  }
2221 
2222  /********************************************************
2223  * Amplification (low and high gain) and ADC *
2224  *******************************************************/
2225 
2226  //ApplyTransferBlock(fft, backEnd, backEnd.eLowGainAmplifier);
2227  //ApplyTransferBlock(fftHGChannel, backEnd, backEnd.eHighGainAmplifier);
2228 
2229  for(unsigned int i = 0; i<fNDiscretization; i++){
2230  /*fft.GetTimeSeries()[i] = backEnd.ApplySaturation(fft.GetTimeSeries()[i],backEnd.eLowGainAmplifier);
2231  fftHGChannel.GetTimeSeries()[i] = backEnd.ApplySaturation(fftHGChannel.GetTimeSeries()[i],backEnd.eHighGainAmplifier);*/
2232  traceAfterADCLowGain.PushBack(backEnd.ApplySaturation(fft.GetTimeSeries()[i],backEnd.eLowGainAmplifier));
2233  traceAfterADCHighGain.PushBack(backEnd.ApplySaturation(fftHGChannel.GetTimeSeries()[i],backEnd.eHighGainAmplifier));
2234  }
2235 
2236  ApplyTransferBlock(fft, backEnd, backEnd.eADC);
2237  ApplyTransferBlock(fftHGChannel, backEnd, backEnd.eADC);
2238  for(unsigned int i = 0; i<fNDiscretization; i++){
2239  traceAfterADCLowGain.PushBack(backEnd.ApplySaturation(fft.GetTimeSeries()[i],backEnd.eADC));
2240  traceAfterADCHighGain.PushBack(backEnd.ApplySaturation(fftHGChannel.GetTimeSeries()[i],backEnd.eADC));
2241  }
2242 }
2243 
2244 /************************************************************************************
2245  * *
2246  * Integrator BackEnd Transfer Apply transfer and saturation of all blocks *
2247  * *
2248  ************************************************************************************/
2249 
2250 void
2251 MdCounterSimulator::ApplyBackEndTransfer(const mdet::BackEndSiPM& backEnd, const double maxTimePreFE, const double minTimePreFE,
2252  TimeTrace& traceAfterADCLowGain, TimeTrace& traceAfterADCHighGain, TVectorD& totalAnalogicalInput, const std::vector<utl::TraceD> analogicalTraces){
2253  fLog("Applying FFT Integrator...", 3);
2254 
2255  /****************************************************************************
2256  * First add every channel and transform the trace into Fourier space *
2257  ****************************************************************************/
2258 
2259  double binning = (maxTimePreFE-minTimePreFE) / fNDiscretization;
2260  int nroChannels = analogicalTraces.size();
2261 
2263  fLog("Time discretization binning ", 4)(binning / fUnits.GetTimeUnit())(fUnits.GetTimeName());
2264  fft.GetTimeSeries().SetBinning(binning);
2265 
2266  for (unsigned int i = 0; i < fNDiscretization; ++i) {
2267  double value = 0;
2268  //not efficient, but there are not that many iterations.
2269  for (int channel = 0; channel < nroChannels; channel++) {
2270  value += analogicalTraces[channel][i];
2271  }
2272  fft.GetTimeSeries().PushBack(value);
2273  totalAnalogicalInput[i] += value;
2274  }
2275  /********************************************************
2276  * 1st and 2nd adders *
2277  *******************************************************/
2278 
2279  /*ApplyTransferBlock(fft, backEnd, backEnd.eFirstAdder);
2280  end_time = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
2281  std::cout << "Apply second adder " << std::ctime(&end_time);
2282  ApplyTransferBlock(fft, backEnd, backEnd.eSecondAdder);*/
2283 
2285  ApplyTransferBlocks(fft, fftHG, backEnd);
2286  TimeTrace& tracePreLGChannel = fft.GetTimeSeries();
2287  TimeTrace& tracePreHGChannel = fftHG.GetTimeSeries();
2288 
2289  for(unsigned int i = 0; i<fNDiscretization; i++){
2290  traceAfterADCLowGain.PushBack(backEnd.ApplySaturation(tracePreLGChannel[i],backEnd.eLowGainAmplifier));
2291  traceAfterADCHighGain.PushBack(backEnd.ApplySaturation(tracePreHGChannel[i],backEnd.eHighGainAmplifier));
2292  }
2293 }
2294 
2295 void
2297  const mdet::BackEndSiPM& backEnd, BackEndSiPM::TransferStep step){
2298 
2299 
2300  /********************************************************
2301  * ApplyfirstAddertransferandchecksaturation*
2302  ********************************************************/
2303 
2304  fLog("Applying transfer function in frequency space.",3);
2305  FrequencyTrace& freqTrace = fft.GetFrequencySpectrum();
2306  const FrequencyTrace::SizeType nFreq = fft.GetConstFrequencySpectrum().GetSize();
2307  const double freqBinning = fft.GetConstFrequencySpectrum().GetBinning();
2308 
2309  fLog("Generating frequency response.",3);
2310  const unsigned int tabFFTLogLevel = 4;
2311  std::unique_ptr<utl::TabularStream> tabFFT;
2312  if(fLog.GetLevel() >= tabFFTLogLevel){
2313  Init(tabFFT,4);
2314  *tabFFT<<utl::hline
2315  <<"Size"<<utl::endc//1
2316  <<"Binning("<<fUnits.GetFrequencyName()<<")"<<utl::endc//2
2317  <<"1st freq("<<fUnits.GetFrequencyName()<<")"<<utl::endc//3
2318  <<"Last freq("<<fUnits.GetFrequencyName()<<")"<<utl::endr//4
2319  <<nFreq<<utl::endc//1
2320  <<fLog<<(freqBinning/fUnits.GetFrequencyUnit())<<utl::endc//2
2321  <<fLog<<(fft.GetFrequencyOfBin(0)/fUnits.GetFrequencyUnit())<<utl::endc//3
2322  <<fLog<<(fft.GetFrequencyOfBin(nFreq-1)/fUnits.GetFrequencyUnit())<<utl::endr//4
2323  <<utl::hline;
2324  fLog(tabFFT->Str(),tabFFTLogLevel);
2325  }
2326  for(FrequencyTrace::SizeType freqBin=0; freqBin<nFreq; ++freqBin){
2327  double freq = fft.GetFrequencyOfBin(freqBin) / fUnits.GetFrequencyUnit();//To MHz
2328  //double preAmp= std::abs(freqTrace[freqBin])/fUnits.GetElectricCurrentUnit();
2329  std::complex<double> c = backEnd.ComputeTransfer(freq, step);
2330  //const std::complex<double> intervention(-5,0);
2331  freqTrace[freqBin] *= c;
2332  }
2333 
2334 }
2335 
2336 void
2339  const mdet::BackEndSiPM& backEnd){
2340 
2341 
2342  /********************************************************
2343  * ApplyfirstAddertransferandchecksaturation*
2344  ********************************************************/
2345 
2346  fLog("Applying transfer function in frequency space.",3);
2347  FrequencyTrace& freqTrace = fft.GetFrequencySpectrum();
2348  FrequencyTrace& freqTraceHG = fftHG.GetFrequencySpectrum();
2349  const FrequencyTrace::SizeType nFreq = fft.GetConstFrequencySpectrum().GetSize();
2350  const double freqBinning = fft.GetConstFrequencySpectrum().GetBinning();
2351  freqTraceHG.SetBinning(freqBinning);
2352 
2353  fLog("Generating frequency response.",3);
2354  const unsigned int tabFFTLogLevel = 4;
2355  std::unique_ptr<utl::TabularStream> tabFFT;
2356  if(fLog.GetLevel() >= tabFFTLogLevel){
2357  Init(tabFFT,4);
2358  *tabFFT<<utl::hline
2359  <<"Size"<<utl::endc//1
2360  <<"Binning("<<fUnits.GetFrequencyName()<<")"<<utl::endc//2
2361  <<"1st freq("<<fUnits.GetFrequencyName()<<")"<<utl::endc//3
2362  <<"Last freq("<<fUnits.GetFrequencyName()<<")"<<utl::endr//4
2363  <<nFreq<<utl::endc//1
2364  <<fLog<<(freqBinning/fUnits.GetFrequencyUnit())<<utl::endc//2
2365  <<fLog<<(fft.GetFrequencyOfBin(0)/fUnits.GetFrequencyUnit())<<utl::endc//3
2366  <<fLog<<(fft.GetFrequencyOfBin(nFreq-1)/fUnits.GetFrequencyUnit())<<utl::endr//4
2367  <<utl::hline;
2368  fLog(tabFFT->Str(),tabFFTLogLevel);
2369  }
2370  for(FrequencyTrace::SizeType freqBin=0; freqBin<nFreq; ++freqBin){
2371  double freq = fft.GetFrequencyOfBin(freqBin) / fUnits.GetFrequencyUnit();//To MHz
2372 
2373  std::complex<double> cLG = backEnd.ComputeTransfer(freq, backEnd.eSimplifiedLG);
2374  std::complex<double> cHG = backEnd.ComputeTransfer(freq, backEnd.eSimplifiedHG);
2375  freqTraceHG.PushBack(freqTrace[freqBin]*cHG);
2376  freqTrace[freqBin] *= cLG;
2377  }
2378 
2379 }
2380 
2381 /************************************
2382  * *
2383  * ADC Sampling *
2384  * *
2385  ************************************/
2386 void
2387 MdCounterSimulator::SampleTraceADC(const double minTimePostFE, const double maxTimePostFE, const mdet::FrontEndSiPM& frontEnd,
2388  const utl::TimeInterval& traceStart, TimeTrace& traceAfterADCLowGain, TimeTrace& traceAfterADCHighGain,
2389  utl::TraceUSI& traceIntegratorA, utl::TraceUSI& traceIntegratorB){
2390 
2391  const double delayBinaryADC = frontEnd.GetDelayBinaryADC();
2392  const double sRate = frontEnd.GetSampleTimeADC();
2393  const unsigned int nBinsTrace = (int)((frontEnd.GetPreT1BufferLength() + frontEnd.GetPostT1BufferLength())*frontEnd.GetMeanSampleRatePeriod()/sRate);
2394  const double binning = (maxTimePostFE-minTimePostFE)/fNDiscretization;
2395 
2396  // sampleTimes.reserve(nBinsTrace);
2397  fLog("Sampling pulses.", 3);
2398  const double startTime = traceStart.GetInterval();
2399  const double stopTime = startTime + sRate * nBinsTrace;
2400 
2401  if (startTime + delayBinaryADC < minTimePostFE) {
2402  fLog("Samples false in the range", 4)
2403  (startTime / fUnits.GetTimeUnit())(fUnits.GetTimeName())
2404  ("to")
2405  (minTimePostFE / fUnits.GetTimeUnit())(fUnits.GetTimeName())
2406  ("as no signal in it.");
2407  }
2408  fLog("Samples:", 4);
2409 
2410  double chargeLG = 0.0;
2411  double chargeHG = 0.0;
2412  unsigned short offsetLG = frontEnd.GetADCCounts(frontEnd.GetModule().GetBackEndSiPM().GetLowGainAmplifierOffset());
2413  unsigned short offsetHG = frontEnd.GetADCCounts(frontEnd.GetModule().GetBackEndSiPM().GetHighGainAmplifierOffset());
2414  for (double sampleTime = startTime; traceIntegratorA.GetSize() < nBinsTrace || fLog('\n', 4)(sampleTime);
2415  sampleTime += sRate) {
2416 
2417  unsigned short adcLG;
2418  unsigned short adcHG;
2419  //Introduce delay between counter and integrator
2420  if (sampleTime < minTimePostFE + delayBinaryADC || maxTimePostFE + delayBinaryADC < sampleTime) {
2421  adcLG = offsetLG;
2422  adcHG = offsetHG;
2423  } else {
2424 
2425  int bin = (int)((sampleTime-minTimePostFE-delayBinaryADC)/binning);
2426  double signal1 = traceAfterADCLowGain[bin];
2427  double signal2 = traceAfterADCHighGain[bin];
2428  adcLG = frontEnd.GetADCCounts(signal1);
2429  adcHG = frontEnd.GetADCCounts(signal2);
2430  chargeLG += adcLG-offsetLG;
2431  chargeHG += adcHG-offsetHG;
2432 
2433  // Only log the relevant part:
2434  fLog(adcLG, 4, false)('@')(sampleTime / fUnits.GetTimeUnit())(fUnits.GetTimeName())('|');
2435  fLog(adcHG, 4, false)('@')(sampleTime / fUnits.GetTimeUnit())(fUnits.GetTimeName())('|');
2436  }
2438  adcLG += frontEnd.GetADCBaseLineFluctuationLG();
2439  adcHG += frontEnd.GetADCBaseLineFluctuationHG();
2440  }
2441  traceIntegratorA.PushBack(adcLG);
2442  traceIntegratorB.PushBack(adcHG);
2443  }
2444  if (maxTimePostFE < stopTime) {
2445  // See inner body of the previous loop (then condition).
2446  fLog("Samples false in the range ", 4)
2447  (maxTimePostFE / fUnits.GetTimeUnit())(fUnits.GetTimeName())
2448  ("to")
2449  (stopTime / fUnits.GetTimeUnit())(fUnits.GetTimeName())
2450  ("as no signal in it.");
2451  }
2452 
2453 }
2454 
2455 void
2456 MdCounterSimulator::PlotIntegrator(const double traceStartTime, const double minTimePreFE, const double binning, const mdet::FrontEndSiPM& frontEnd,
2457 // TVectorD& traceAnalogical, TimeTrace& traceIntegratorAAmplifier, TimeTrace& traceIntegratorBAmplifier){
2458  TVectorD& traceAnalogical, TimeTrace& traceIntegratorAAmplifier, TimeTrace& traceIntegratorBAmplifier,
2459  utl::TraceUSI& traceIntegratorA, utl::TraceUSI& traceIntegratorB){
2460 
2461  if (fPlotFileExtensions.empty() &&
2464  return;
2465 
2466  TVectorD traceIntegratorAVec(traceIntegratorA.GetSize());
2467  TVectorD traceIntegratorBVec(traceIntegratorB.GetSize());
2468  TVectorD traceIntegratorAVecAnalog(traceIntegratorAAmplifier.GetSize());
2469  TVectorD traceIntegratorBVecAnalog(traceIntegratorBAmplifier.GetSize());
2470  TVectorD analogicalTime(traceAnalogical.GetNoElements());
2471  TVectorD digitalTime(traceIntegratorA.GetSize());
2472 
2473  const double sRate = frontEnd.GetSampleTimeADC();
2474 
2475  for(int i=0; i<traceAnalogical.GetNoElements(); i++){
2476  analogicalTime[i] = (i*binning + minTimePreFE);
2477  traceIntegratorAVecAnalog[i] = (double)traceIntegratorAAmplifier[i];
2478  traceIntegratorBVecAnalog[i] = (double)traceIntegratorBAmplifier[i];
2479  }
2480 
2481  for(unsigned int i=0; i<traceIntegratorA.GetSize(); i++){
2482  digitalTime[i] = (i*sRate + traceStartTime);
2483  traceIntegratorAVec[i] = ((double)traceIntegratorA[i]);
2484  traceIntegratorBVec[i] = ((double)traceIntegratorB[i]);
2485  }
2486 
2487 
2488  fLog("Generating plots.", 3);
2489  // The canvas...
2490  std::stringstream canvasName;
2491  canvasName << "c"
2492  << frontEnd.GetModule().GetCounter().GetId() << "_"
2493  << frontEnd.GetModule().GetId();
2494 
2495  TCanvas canvas(canvasName.str().c_str() ,"Integrator", 200, 10, 700, 500);
2496  canvas.SetTickx();
2497  canvas.SetTicky();
2498  canvas.SetBorderMode(0);
2499  canvas.SetFillColor(0);
2500  canvas.SetFrameBorderMode(0);
2501  //canvas.SetGridx();
2502  //canvas.SetGridy();
2503 
2504  TGraph inputSiPM(analogicalTime, traceAnalogical);
2505  inputSiPM.SetLineWidth(3);
2506  inputSiPM.SetLineColor(kBlue);
2507 
2508  TGraph traceIntegratorAPlot(digitalTime, traceIntegratorAVec);
2509  traceIntegratorAPlot.SetLineWidth(3);
2510  traceIntegratorAPlot.SetLineColor(kRed);
2511  traceIntegratorAPlot.SetMarkerStyle(31);
2512 
2513  TGraph traceIntegratorBPlot(digitalTime, traceIntegratorBVec);
2514  traceIntegratorBPlot.SetLineWidth(3);
2515  traceIntegratorBPlot.SetLineColor(kOrange);
2516  traceIntegratorBPlot.SetMarkerStyle(31);
2517 
2518  TGraph traceIntegratorAAnalogPlot(analogicalTime, traceIntegratorAVecAnalog);
2519  traceIntegratorAAnalogPlot.SetLineWidth(3);
2520  traceIntegratorAAnalogPlot.SetLineColor(kRed);
2521  traceIntegratorAAnalogPlot.SetMarkerStyle(31);
2522 
2523  TGraph traceIntegratorBAnalogPlot(analogicalTime, traceIntegratorBVecAnalog);
2524  traceIntegratorBAnalogPlot.SetLineWidth(3);
2525  traceIntegratorBAnalogPlot.SetLineColor(kOrange);
2526  traceIntegratorBAnalogPlot.SetMarkerStyle(31);
2527 
2528  traceIntegratorBPlot.GetXaxis()->SetTitle(("Time (" + fUnits.GetTimeName() + ")").c_str());
2529  traceIntegratorBPlot.GetYaxis()->SetTitle("Signal (ADC Counts)");
2530  canvas.Update();
2531  canvas.cd();
2532 
2533  traceIntegratorBPlot.Draw("APL");
2534  traceIntegratorAPlot.Draw("SAMEPL");
2535  inputSiPM.Draw("SAME");
2536  traceIntegratorAAnalogPlot.Draw("SAME");
2537  traceIntegratorBAnalogPlot.Draw("SAME");
2538 
2539  TLegend leg;
2540  leg.SetNColumns( 3 );
2541  leg.SetEntrySeparation( 0.8 );
2542  //leg.SetX1NDC( fStyle->GetPadLeftMargin() );
2543  //leg.SetX2NDC( 1 - fStyle->GetPadRightMargin() );
2544  leg.SetX1NDC( 0 );
2545  leg.SetX2NDC( 1 );
2546  leg.SetY1NDC( 1 - fStyle->GetPadTopMargin() );
2547  leg.SetY2NDC( 1 );
2548  leg.SetBorderSize( 0 );
2549  leg.SetTextFont( fStyle->GetTitleFont() );
2550  leg.SetTextSize( fStyle->GetTitleSize()+0.01 );
2551  //leg.AddEntry(&thresFun, thresFun.GetName());
2552  leg.AddEntry(&inputSiPM, "SiPM input","L");
2553  leg.AddEntry(&traceIntegratorAPlot, "ADC LG", "L");
2554  leg.AddEntry(&traceIntegratorBPlot, "ADC HG", "L");
2555  leg.SetFillColor(canvas.GetFillColor());
2556  leg.Draw();
2557  canvas.Update();
2558 
2559  /* std::stringstream outputName;
2560  outputName << "./output/Integretor_"
2561  << frontEnd.GetModule().GetCounter().GetId() << "_"
2562  << frontEnd.GetModule().GetId() << ".root";
2563 
2564  canvas.SaveAs(outputName.str().c_str());*/
2565  if (fPlotOutcome)
2566  PrintPlots(canvas, fPlotFileExtensions, Tag("outcomeIntegrator", frontEnd)(fRunNumber));
2567 
2568 }
2569 
2570 
2571 
2574  mevt::Module& evtModule,
2575  const mdet::Module& module,
2576  const SignalsMap& sm,
2577  const utl::TimeStamp& eventTime)
2578 {
2579 
2580  bool isSiPM = module.IsSiPM();
2581  if(!isSiPM){
2582  for (SignalsMap::const_iterator i = sm.begin(), fpe = sm.end(); i != fpe; ++i) {
2583  SignalsMap::key_type pixelId = i->first;
2584 
2585  /*
2586  * If not present, make it: originally a warning was emited, but because the timestart
2587  * is already set at this point, then that warning was emited.
2588  */
2589 
2590  const mdet::Channel& channel = module.GetChannelFor(module.GetPixel(pixelId));
2591  if (! evtModule.HasChannel(channel.GetId()))
2592  evtModule.MakeChannel(channel.GetId());
2593 
2594  fLog("Simulating PMT-electronic channel:", 2)(channel.GetId())("...");
2595  mevt::Channel& evtChannel = evtModule.GetChannel(channel.GetId());
2596  if (!evtChannel.HasTrace())
2597  evtChannel.MakeTrace();
2598  utl::TraceB& trace = evtChannel.GetTrace();
2599  double span;
2600  // The last parameter defines the trace start: the interval is calculated between
2601  // the reference time of the event, and the registered time for the trace start.
2602  // Note that the particles' GetTime (which return an interval) is assumed to
2603  // return the interval with respect to the event time.
2604  const utl::TimeStamp& start = evtChannel.GetTraceStartTime();
2605  fLog("Trace start at", 3)(start)("...");
2606  ProcessPulses(channel, i->second, trace, span, start - eventTime, eventTime);
2607  fLog("Total analog particle pulse over-threshold time span", 3)
2608  (span / fUnits.GetTimeUnit())(fUnits.GetTimeName())('.');
2609  }
2610 
2611  } else {
2612 
2613  /*As the integrator add ups the 64 traces, It is not a good idea to have different binnings. There are two ways to
2614  go. Either I first determine the binning for all traces and process the counter and integrator
2615  with this binning. Or we process first the counter, and then the integrator (which means re evaluating all the PE functions)
2616  I beleive the first option is less consuming.*/
2617 
2618  std::vector<utl::TraceD> analogicalTraces;
2619  double minTimePreFE;
2620  double maxTimePreFE;
2621  double analogicTraceStartTime;
2622  double analogicTraceEndTime;
2623  utl::TimeStamp startTimeTrace;
2624 
2625  for (SignalsMap::const_iterator i = sm.begin(), fpe = sm.end(); i != fpe; ++i) {
2626  double minTimeSignal;
2627  double maxTimeSignal;
2628  double analogicTraceStartTimePEs;
2629  double analogicTraceEndTimePEs;
2630  GetPulseTimeSpan(i->second, eventTime, minTimeSignal , maxTimeSignal , analogicTraceStartTimePEs , analogicTraceEndTimePEs);
2631  minTimePreFE = std::min(minTimePreFE, minTimeSignal);
2632  maxTimePreFE = std::max(maxTimePreFE, maxTimeSignal);
2633  analogicTraceStartTime = std::min(analogicTraceStartTime, analogicTraceStartTimePEs);
2634  analogicTraceEndTime = std::max(analogicTraceEndTime, analogicTraceEndTimePEs);
2635  }
2636 
2637  for (SignalsMap::const_iterator i = sm.begin(), fpe = sm.end(); i != fpe; ++i) {
2638  SignalsMap::key_type pixelId = i->first;
2639  const mdet::ChannelSiPM& channel = module.GetChannelSiPMFor(module.GetSiPM(pixelId));
2640  if (! evtModule.HasChannel(channel.GetId()))
2641  evtModule.MakeChannel(channel.GetId());
2642 
2643  fLog("Simulating SiPM-electronic channel:", 2)(channel.GetId())("...");
2644  mevt::Channel& evtChannel = evtModule.GetChannel(channel.GetId());
2645  if (!evtChannel.HasTrace())
2646  evtChannel.MakeTrace();
2647  utl::TraceB& trace = evtChannel.GetTrace();
2648  utl::TraceD traceAnalogical; //check if i don't need a pointer here
2649 
2650  double span;
2651 
2652  const utl::TimeStamp start = evtChannel.GetTraceStartTime();
2653  startTimeTrace = start;
2654  fLog("Trace start at", 3)(start)("...");
2655  ProcessPulses(channel, i->second, trace, traceAnalogical, span, start - eventTime, minTimePreFE, maxTimePreFE, analogicTraceStartTime, analogicTraceEndTime);
2656 
2657  fLog("Total analog particle pulse over-threshold time span", 2)
2658  (span / fUnits.GetTimeUnit())(fUnits.GetTimeName())('.');
2659 
2660  analogicalTraces.push_back(traceAnalogical);
2661  }
2662 
2663 
2664  if(fInjectNoiseBinary)
2665  InjectDigitalNoise(module, evtModule);
2666  /*
2667  * The integrator analysis could be in the ProcessPulses method.
2668  *
2669  * However, this method is already a mess, so, I am creating a new one for the sake of clarity (and mine).
2670  *
2671  * ProcessPulse works at the level of channel, while ProcessPulsesIntegrator
2672  * works at the level of Module.
2673  *
2674  * */
2675  if(analogicalTraces.size()>0){
2676 
2677  if (!evtModule.HasIntegratorATrace())
2678  evtModule.MakeIntegratorATrace();
2679 
2680  if (!evtModule.HasIntegratorBTrace())
2681  evtModule.MakeIntegratorBTrace();
2682  utl::TraceUSI& traceIntegratorA = evtModule.GetIntegratorATrace();
2683  utl::TraceUSI& traceIntegratorB = evtModule.GetIntegratorBTrace();
2684 
2685 
2686  fLog("Generating integrator traces", 2);
2687  ProcessPulsesIntegrator(module, analogicalTraces, traceIntegratorA, traceIntegratorB, startTimeTrace - eventTime, minTimePreFE, maxTimePreFE);
2688  }
2689 
2690  }
2691  return eSuccess;
2692 }
2693 
2696 {
2697  return eSuccess;
2698 }
2699 
2700 int
2702 {
2703  if (!event.HasSEvent()) {
2704  ERROR("SEvent does not exist.");
2705  return 0;
2706  }
2707  sevt::SEvent& sEvent = event.GetSEvent();
2708 
2709  int partnerId = cmDet.GetAssociatedTankId();
2710 
2711  if (!sEvent.HasStation(partnerId)) {
2712  std::ostringstream message;
2713  message << "partner station with id " << partnerId << "was not found in SEvent\n";
2714  WARNING(message);
2715  return 0;
2716  }
2717 
2718  sevt::Station& sStation = sEvent.GetStation(partnerId);
2719  const sdet::Station& detStation = det::Detector::GetInstance().GetSDetector().GetStation(sStation);
2720 
2721  if (!sStation.HasSimData())
2722  return 0;
2723 
2724  int ret = 0;
2725  sevt::StationSimData& sSimData = sStation.GetSimData();
2726  utl::TimeStamp firstT1Sd;
2727 
2728  for (sevt::StationSimData::TriggerTimeIterator it = sSimData.TriggerTimesBegin(); it != sSimData.TriggerTimesEnd(); ++it) {
2729 
2730  if (it == sSimData.TriggerTimesBegin())
2731  firstT1Sd = *it;
2732 
2733  utl::TimeStamp trigTime = *it;
2734  const sevt::StationTriggerData& trig = sSimData.GetTriggerData(trigTime);
2735  std::cout << "IsT1 " << trig.IsT1() << " - " << "IsT2 " << trig.IsT2() << std::endl;
2736 
2737  if (!(trig.IsT2() || trig.IsT1()))
2738  continue;
2739 
2740  ret = 1;
2741  if (trig.IsT2())
2742  ret = 2;
2743 
2744  if (trigTime < firstT1Sd) {
2745  std::cout << "There is a previous trigger\n";
2746  firstT1Sd = trigTime;
2747  }
2748  std::cout << "Trigger time: " << trigTime << std::endl;
2749  std::cout << "Algorithm: " << trig.GetAlgorithmName() << std::endl;
2750 
2751  } // end loop on TriggerTimeIterator
2752 
2753  if (!ret && !fForcedSDTrigger)
2754  return 0;
2755 
2756  //utl::TimeStamp eventTime = event.GetMEvent().GetHeader().GetTime();
2757  utl::TimeStamp eventTime = event.GetSEvent().GetHeader().GetTime();
2758  utl::TimeInterval shift;
2759  utl::TimeStamp TstartTrace;
2760 
2761  //avoids break if forced WCD trigger (set T1 time stamp as event time)
2762  if ( fForcedSDTrigger )
2763  firstT1Sd = eventTime;
2764  else
2765  //see sdet::StationTriggerAlgorithm.h and TankTriggerSimulator.cc
2766  shift = utl::TimeInterval((detStation.GetFADCTraceLength() - detStation.GetLatchBin())*detStation.GetFADCBinSize());
2767 
2768  TstartTrace = firstT1Sd - shift;
2769  //Time interval from Eventime to TstartTrace
2770  T1 = TstartTrace - eventTime;
2771  std::cout << "eventTime " << eventTime << std::endl;
2772  std::cout << "T1 " << T1 << std::endl;
2773  std::cout << "firstT1Sd " << firstT1Sd << std::endl;
2774  std::cout << "TstartTrace " << TstartTrace << std::endl;
2775  std::cout << "shift " << shift << std::endl;
2776 
2777  for (mevt::Counter::ModuleIterator mIt = cIt->ModulesBegin(), em = cIt->ModulesEnd();
2778  mIt != em; ++mIt) {
2779 
2780  const int mId = mIt->GetId();
2781  const mdet::Module & mmDet = cmDet.GetModule(mId);
2782  //If SiPM prepares to iterate over module channels (mdet)
2784  const mdet::FrontEndSiPM& frontEnd = mmDet.GetFrontEndSiPM();
2785  const double sRate = frontEnd.GetMeanSampleRatePeriod();
2786  const double preT1BufferLength = frontEnd.GetPreT1BufferLength();
2787  const double postT1BufferLength = frontEnd.GetPostT1BufferLength();
2788 
2789  //shift the position of the T1 to the circular md-buffer (preT1BufferLength)
2790  utl::TimeInterval timeShiftpre (sRate*preT1BufferLength );
2791  utl::TimeInterval timeShiftpost(sRate*postT1BufferLength);
2792 
2793  for (chIt ch = frontEnd.ChannelsBegin(), ec = frontEnd.ChannelsEnd(); ch != ec; ++ch) {
2794  if (!mIt->HasChannel(ch->GetId()))
2795  mIt->MakeChannel(ch->GetId());
2796 
2797  // Compute the trace start wrt the station trigger T1 GPS time
2798  const utl::TimeStamp traceStart = eventTime + utl::TimeInterval(T1) - timeShiftpre;
2799  mIt->GetChannel(ch->GetId()).SetTraceStartTime(traceStart);
2800  } // end for channel loop
2801  }//end loop on modules
2802  return ret;
2803 }
2804 
2805 void
2806 MdCounterSimulator::Dump(const TF1& fun, const std::string& suffix)
2807 {
2808  double min;
2809  double max;
2810  fun.GetRange(min, max);
2811  // Temporal step for the case when the whole pulse is sampled.
2812  const double stepWhole = (max - min) / fNPulseSamples;
2813  // Temporal step for the case when a fixed time window is sampled.
2814  const double stepWindow = fPulseSampleWindow / fNPulseSamples;
2815  for (unsigned int i = 0; i < fNPulseSamples; ++i) {
2816  double xWhole = min + i * stepWhole;
2817  double xWindow = min + i * stepWindow;
2818  fPulseFile << fRunNumber << '\t'
2819  << suffix << '\t'
2820  << xWhole << '\t'
2821  << fun.Eval(xWhole) << '\t'
2822  << xWindow << '\t'
2823  << fun.Eval(xWindow)
2824  << std::endl;
2825  }
2826  /*
2827  * Also separate each batch with a blank, which can be handy for plotting with something like
2828  * GNUPlot, which consideres white lines to mark the ending of data series.
2829  */
2830  fPulseFile << std::endl;
2831 }
2832 
2833 void
2834 MdCounterSimulator::Init(std::unique_ptr<utl::TabularStream>& pt, unsigned int nCol)
2835  const
2836 {
2837  std::stringstream fmt;
2838  for(unsigned int i = 0; i < nCol; ++i)
2839  fmt << "|r";
2840  fmt << "|";
2841  pt.reset(new utl::TabularStream(fmt.str()));
2842  /*
2843  * At last this call doesn't work as expected
2844  * because it only ends applying to the
2845  * current column.
2846  */
2847  fLog.ApplyConfigurationOn(*pt);
2848 }
2849 
2850 }
2851 
const Point & GetEnd() const
Return the final point.
Definition: Segment.h:39
AtThresholdConstIterator AtThresholdBegin() const
Begin iterator over times.
unsigned int fStepSPE
Step size for spe iteration.
virtual void InjectDigitalNoise(const mdet::Module &module, mevt::Module &evtModule)
const BackEndSiPM & GetBackEndSiPM() const
virtual VModule::ResultFlag SimulatePulses(const mdet::Scintillator &scint, const mevt::ScintillatorSimData &ssd, mevt::ScintillatorSimData &ssd_nonconst, SignalsMap &sm)
Perform the simulation given the particles in the scintillator.
double GetAmplitude2() const
Definition: SiPM.h:118
Station Level Simulated Data
void MakeChannel(const int cId)
Definition: MEvent/Module.h:97
constexpr double milli
Definition: AugerUnits.h:66
const std::string & GetElectricResistanceName() const
Definition: UnitsConfig.h:89
const Module & GetModule(const int mId) const
Retrieve by id a constant module.
utl::TimeStamp GetTraceStartTime() const
Return the timestamp associated with the start of the trace. The timestamp of the first bin of the tr...
CounterConstIterator CountersBegin() const
Definition: MEvent.h:49
virtual void ApplyCITIROCTransfer(const mdet::ChannelSiPM &channel, const SignalInformation &si, const double pulseTimeSpan, double minTimePreFE, double analogicTraceStartTime, double analogicTraceEndTime, TimeTrace &totalPulsePostFrontEndTrace, TimeTrace &totalPulsePostDiscriminatorTrace, utl::TraceD &traceAnalogical)
const Pixel & GetPixel(int pId) const
Point object.
Definition: Point.h:32
bool IntersectedBy(const utl::Line &line) const
Answers if line crosses the body of the Scintillator.
const Counter & GetCounter() const
The parent counter.
boost::indirect_iterator< InternalConstParticleIterator, const utl::Particle & > ConstParticleIterator
bool HasStation(const int stationId) const
Check whether station exists.
Definition: SEvent.cc:81
double GetSampleTimeADC() const
ADC Sample Time and delay.
Definition: FrontEndSiPM.cc:90
unsigned int fNBinsHistograms
Number of bins for histograms.
utl::MessageLoggerConfig fLog
Output messages handler.
const TimeInterval & GetTime() const
Arrival time delay at the ground.
Definition: Particle.h:122
double GetFallTime3() const
Definition: SiPM.h:138
bool HasMEvent() const
Detector description interface for Station-related data.
Report success to RunController.
Definition: VModule.h:62
double GetHighGainAmplifierOffset() const
Definition: BackEndSiPM.cc:352
bool HasIntegratorBTrace() const
static EnumType Create(const int k)
int version of the overloaded creation method.
double ComputeDiscriminator(double signal, double deltaTime) const
Definition: ChannelSiPM.cc:159
double GetLengthUnit() const
Definition: UnitsConfig.h:121
double GetFallTime2() const
Definition: SiPM.h:134
unsigned int ComputeSPENumber(double x, double l, double e) const
Computes a number of SPE given the impinging distance, the length of the track and the energy of the ...
Definition: Fiber.cc:227
ChannelGroup::ConstIterator ChannelConstIterator
Convenience typedef for const iterator over the contained mdet::Channel instances.
Definition: FrontEndSiPM.h:82
unsigned int fNDiscretization
Discretization over the continuous functions.
int freq
Definition: dump1090.h:244
static const char *const kSimulationTypeTags[]
Tags for the types of simulation.
short GetInjectDigitalNoiseBin() const
virtual void SampleTraceADC(const double minTimePostFE, const double maxTimePostFE, const mdet::FrontEndSiPM &frontEnd, const utl::TimeInterval &traceStart, TimeTrace &traceAfterADCLowGain, TimeTrace &traceAfterADCHighGain, utl::TraceUSI &traceIntegratorA, utl::TraceUSI &traceIntegratorB)
Interface class to access to the SD part of an event.
Definition: SEvent.h:39
Describes a particle for Simulation.
Definition: Particle.h:26
unsigned short GetADCBaseLineFluctuationLG() const
Noise injection for binary and ADC channels.
virtual void SampleTrace(double minTimePostFE, double maxTimePostFE, double binning, const mdet::FrontEndSiPM &frontEnd, const utl::TimeInterval &traceStart, TimeTrace &totalPulsePostDiscriminatorTrace, utl::TraceB &trace)
double GetFallTime1() const
Definition: SiPM.h:130
double ApplySaturation(double value, TransferStep step) const
Definition: BackEndSiPM.cc:485
int GetTriggerTimeFromSD(evt::Event &, const mdet::Counter &, mevt::MEvent::CounterIterator, double &)
Retrieve T1 time from associated SD tank.
void AddSPEPulse(const double mu, const double sigma, const double amplitude, const int destPixelId)
const std::string & GetLengthName() const
Definition: UnitsConfig.h:95
double fPulseSampleWindow
Define the length of the window within which the pulse is sampled.
unsigned int fNumPlotPoints
Number of points to be used in plotting (theoretically) continuous functions.
bool fIncludeBaseLineFluctuationIntegrator
To simulate baseline fluctuation in the integrator output.
unsigned int fRunNumber
Tracks the number of runs.
double GetAngleUnit() const
Definition: UnitsConfig.h:110
const FrontEndSiPM & GetFrontEnd() const
The shared common-to-all-ChannelSiPMs electronic frontend of this ChannelSiPM.
Definition: ChannelSiPM.h:42
bool is(const double a, const double b)
Definition: testlib.cc:113
unsigned int GetPostT1BufferLength() const
Number of bins of the post-T1 buffer.
Definition: FrontEnd.cc:65
PhotonTimeContainer::const_iterator ConstPhotonTimeIterator
utl::CoordinateSystemPtr GetLocalCoordinateSystem() const
Local system based on position and configured rotations.
unsigned short GetInjectDigitalNoiseWidth() const
virtual void ApplyBackEndTransfer(const mdet::BackEndSiPM &backEnd, const double maxTimePreFE, const double minTimePreFE, TimeTrace &traceAfterADCLowGain, TimeTrace &traceAfterADCHighGain, TVectorD &totalAnalogicalInput, const std::vector< utl::TraceD > traceAnalogical)
double GetBinning() const
size of one slot
Definition: Trace.h:138
virtual void ApplyBackEndTransferWStepSaturation(const mdet::BackEndSiPM &backEnd, const double maxTimePreFE, const double minTimePreFE, TimeTrace &traceAfterADCLowGain, TimeTrace &traceAfterADCHighGain, TVectorD &totalAnalogicalInput, const std::vector< utl::TraceD > traceAnalogical)
const Fiber & GetFiberFor(const Component &c) const
Linking between fibers, scintillators, channels and pixels.
#define INFO(message)
Macro for logging informational messages.
Definition: ErrorLogger.h:161
double ComputeSignalShift() const
Computes a signal shift value according this Channel&#39;s characteristics (and, particularly, to the distribution of these values).
const Channel & GetChannelFor(const Component &c) const
Returns the associated mdet::Channel.
std::complex< double > ComputeTransfer(double freq, TransferStep step) const
Definition: BackEndSiPM.cc:455
double GetDelayBinaryADC() const
Helper class encapsulating the discriminator response logic.
PE pulse.
Definition: SiPM.h:74
const FrontEnd & GetFrontEnd() const
The shared common-to-all-channels electronic frontend of this channel.
bool fGeneratePreFETotalPulseOutput
To include the total pulse prior front-end in the output file.
Electronic front-end for the modules.
Definition: FrontEnd.h:33
virtual void PlotChannel(const double traceStartTime, const double minTimePreFE, const double binning, const mdet::ChannelSiPM &channel, utl::TraceD &traceAnalogical, TimeTrace &totalPulsePostFrontEndTrace, TimeTrace &totalPulsePostDiscriminatorTrace, utl::TraceB &trace)
Eletronic channel.
VModule::ResultFlag RunFromMEventScintillatorSimulated(evt::Event &e)
unsigned int GetPreT1BufferLength() const
Number of bins of the (cyclic) pre-T1 buffer.
Definition: FrontEnd.cc:57
Encapsulates the sampling logic.
Definition: FrontEndSiPM.h:53
Sampler MakeSampler() const
Create a new sampler object.
utl::TraceB & GetTrace()
const std::string & GetAlgorithmName() const
double GetStartTime() const
Definition: SiPM.h:110
VModule::ResultFlag Run(evt::Event &e)
Run: invoked once per event.
std::map< int, SignalInformation > SignalsMap
Map associating the information with IDs (meant to be from pixel&#39;s).
unsigned int fMinSPE
Minimum number of spe (inclusive).
Detector associated to muon detector hierarchy.
Definition: MDetector.h:32
double Distance(const Line &line1, const Line &line2)
void SetElectricCurrentDefault(const double unit, const std::string &name)
Definition: UnitsConfig.cc:99
double GetLength() const
Return the length of the segment (ie the distance between begin and end).
Definition: Segment.h:45
Electronic front-end for the modules.
Definition: FrontEndSiPM.h:35
double GetLowGainAmplifierOffset() const
Definition: BackEndSiPM.cc:269
A TimeStamp holds GPS second and nanosecond for some event.
Definition: TimeStamp.h:110
const SiPMArray & GetSiPMArray() const
Definition: SiPM.h:47
Eletronic ChannelSiPM.
Definition: ChannelSiPM.h:33
utl::TraceD & GetAnalogicTrace()
Return the trace of current pulse signal prior to the electronic amplification stage.
Actual muon-sensitive objects.
std::string fPulseFilename
Pulse output file filename.
std::vector< std::string > fPlotFileExtensions
File extensions for plots (dot included).
bool fInjectNoiseBinary
To inject noise in binary traces.
Sampler MakeSampler() const
Create a new sampler object.
Definition: FrontEnd.cc:138
sevt::StationTriggerData & GetTriggerData(const utl::TimeStamp &time)
Get simulated TriggerData.
const SiPM & GetSiPM(const int pId) const
#define max(a, b)
Class representing a document branch.
Definition: Branch.h:107
short GetNumberOfChannelsToGroup() const
Definition: BackEndSiPM.cc:423
utl::TimeStamp GetTime() const
Definition: MEvent/Header.h:22
class to hold data at Station level
ChannelConstIterator ChannelsBegin() const
Begin iterator over the contained channels.
Definition: FrontEndSiPM.h:87
constexpr double s
Definition: AugerUnits.h:163
const SiPM & GetSiPMFor(const Component &c) const
Returns the associated mdet::SiPM.
Module level event data.
Definition: MEvent/Module.h:41
const Pixel & ComputePulseDestination(const Pixel &src) const
Computes a destination pixel according to crosstalk effect.
bool HasSimData() const
Check whether station simulated data exists.
Class describing a Plane object.
Definition: Plane.h:17
C< F > & GetFrequencySpectrum()
read out the frequency spectrum (write access)
utl::UnitsConfig fUnits
Units configuration.
double GetX(const CoordinateSystemPtr &coordinateSystem) const
Definition: BasicVector.h:206
unsigned int fNRepetitions
Repetitions for in-module loop.
std::vector< double >::size_type SizeType
Definition: Trace.h:58
const PMT & GetPMT() const
bool fForcedSDTrigger
Ignore WCD trigger condition.
static int delay
Definition: XbAlgo.cc:20
void Configure(const utl::Branch &config)
Configure units (values and defaults) given a branch.
Definition: UnitsConfig.cc:395
std::complex< double > ComputeTransfer(double freq) const
Computes the circuit transfer function at the given frequency.
double GetRiseTime() const
Definition: SiPM.h:126
virtual void PlotIntegrator(const double traceStartTime, const double minTimePreFE, const double binning, const mdet::FrontEndSiPM &frontEnd, TVectorD &traceAnalogical, TimeTrace &traceIntegratorAAmplifier, TimeTrace &traceIntegratorBAmplifier, utl::TraceUSI &traceIntegratorA, utl::TraceUSI &traceIntegratorB)
double abs(const SVector< n, T > &v)
virtual void ProcessPulses(const mdet::Channel &c, const SignalInformation &signalInfo, utl::TraceB &trace, double &span, const utl::TimeInterval &traceStart, const utl::TimeStamp &eventTime)
Process: analyze, electronic simulation and sampling.
virtual void ApplyTransferBlock(utl::FFTDataContainer< utl::Trace, TimeTrace::ValueType, FrequencyTrace::ValueType > &fft, const mdet::BackEndSiPM &backEnd, BackEndSiPM::TransferStep step)
double GetMeanSampleRatePeriod() const
Mean electronic sample rate period.
Definition: FrontEnd.cc:43
VModule::ResultFlag Finish()
Finish: invoked at end of the run (NOT end of the event)
Encapsulates the sampling logic.
Definition: FrontEnd.h:51
const unsigned int & GetLevel() const
Retrieve (read-only) the current level of verbosity.
const EndRow endr
decltype(std::begin(boost::adaptors::keys(TriggerGPSMap()))) typedef TriggerTimeIterator
const Point & GetBegin() const
Return the initial point.
Definition: Segment.h:36
void SetLengthDefault(const double unit, const std::string &name)
Definition: UnitsConfig.cc:155
Array of Scintillator.
#define S
Channel & GetChannel(const int cId)
Definition: MEvent/Module.h:95
constexpr double kTwoPi
Definition: MathConstants.h:27
int GetLatchBin() const
virtual double GetPulseTimeSpan(const SignalInformation &si, const utl::TimeStamp &eventTime, double &minTimePreFE, double &maxTimePreFE, double &analogicTraceStartTime, double &analogicTraceEndTime)
double GetSigma() const
C< T > & GetTimeSeries()
read out the time series (write access)
double GetAmplitude() const
void Configure(const Branch &config)
int GetAssociatedTankId() const
Retrieve the id of the associated surface tank.
double GetMeanSampleRatePeriod() const
Mean electronic sample rate period.
Definition: FrontEndSiPM.cc:53
constexpr double megahertz
Definition: AugerUnits.h:155
void SetTraceStartTime(mevt::Counter::ModuleIterator mIt, const FrontEndType &frontEnd, const utl::TimeStamp &eventTime, const double &deltaLatch)
constexpr double g
Definition: AugerUnits.h:200
unsigned int GetPreT1BufferLength() const
Number of bins of the (cyclic) pre-T1 buffer.
Definition: FrontEndSiPM.cc:61
double GetElectricCurrentUnit() const
Definition: UnitsConfig.h:113
class to format data in tabular form
SizeType GetSize() const
Definition: Trace.h:156
IntegratorSimulationType fIntegratorSimType
Type of integrator simulation. Step by step simulates the complete transfer functions and applies sat...
std::complex< double > ComputeTransfer(double freq) const
Computes the circuit transfer function at the given frequency.
Definition: ChannelSiPM.cc:116
void SetFrequencyDefault(const double unit, const std::string &name)
Definition: UnitsConfig.cc:134
s<< "id="<< GetId()<< " [";for(It i=GetIdsMap().begin(), e=GetIdsMap().end();i!=e;++i) s<< " "<< i-> first<< "="<< i-> second
#define WARNING(message)
Macro for logging warning messages.
Definition: ErrorLogger.h:163
double GetElectricPotentialUnit() const
Definition: UnitsConfig.h:114
const Pixel & GetPixelFor(const Component &c) const
Returns the associated mdet::Pixel.
unsigned int GetPostT1BufferLength() const
Number of bins of the post-T1 buffer.
Definition: FrontEndSiPM.cc:69
utl::TraceUSI & GetIntegratorATrace()
bool HasIntegratorATrace() const
bool HasChannel(const int cId) const
Definition: MEvent/Module.h:98
void MakeIntegratorATrace()
void SetTimeDefault(const double unit, const std::string &name)
Definition: UnitsConfig.cc:218
virtual void ApplyTransferBlocks(utl::FFTDataContainer< utl::Trace, TimeTrace::ValueType, FrequencyTrace::ValueType > &fft, utl::FFTDataContainer< utl::Trace, TimeTrace::ValueType, FrequencyTrace::ValueType > &fftHG, const mdet::BackEndSiPM &backEnd)
InternalModuleCollection::ComponentIterator ModuleIterator
TriggerTimeIterator TriggerTimesBegin() const
Beginning of simulated local trigger times list.
RawRootsContainer::const_iterator AtThresholdConstIterator
Iterator over the times when the input signal reaches the threshold level.
Station & GetStation(const int stationId)
retrieve station by id throw utl::NonExistentComponentException if n.a.
Definition: SEvent.h:116
const mevt::ScintillatorSimData * fScintSimData
Simulation information for the scint.
bool fIgnoreCrossTalk
Ignore cross-talk effects.
double GetInterval() const
Get the time interval as a double (in Auger base units)
Definition: TimeInterval.h:69
Root detector of the muon detector hierarchy.
VModule::ResultFlag Init()
Initialize: invoked at beginning of run (NOT beginning of event)
const std::string & GetElectricCurrentName() const
Definition: UnitsConfig.h:87
PMT pixel.
static const char *const kIntegratorSimulationTypeTags[]
Tags for the types of integrator simulation.
void SetBinning(const double binning)
Definition: Trace.h:139
double GetY(const CoordinateSystemPtr &coordinateSystem) const
Definition: BasicVector.h:209
constexpr double kSpeedOfLight
Template class for a data container that offers and takes both time series and corresponding frequenc...
Scintillator level simulation data.
A TimeInterval is used to represent time elapsed between two events.
Definition: TimeInterval.h:43
double GetMu() const
ResultFlag
Flag returned by module methods to the RunController.
Definition: VModule.h:60
VModule::ResultFlag RunFromMEvent(evt::Event &e)
Run for the eFromEvent enumeration.
double GetWeight() const
Particle weight (assigned by shower generator thinning algorithms)
Definition: Particle.h:126
double GetFADCBinSize() const
void AddPEPulse(const double t0, const double a1, const double a2, const double a3, const double timeRise, const double timeFall1, const double timeFall2, const double timeFall3, const int destPixelId)
std::set< ParticleType > fAllowedParticleTypes
Particle types that are considered to generate signal, if empty then every kind of particle is allowe...
InternalCounterCollection::ComponentIterator CounterIterator
Definition: MEvent.h:31
utl::Segment ComputeIntersectionWith(const utl::Line &line) const
Computes the intersection of line within the Scintillator.
double GetPhotonTime(const PhotonTime &photon) const
double GetOverThresholdTimeSpan() const
Return the total time span over the discrimination threshold.
static CentralConfig * GetInstance()
Use this the first time you get an instance of central configuration.
unsigned short GetADCCounts(double value) const
constexpr double volt
Definition: AugerUnits.h:229
Template class for a FADC data or calibrated data container. Use the typedefs (TraceD, TraceI, etc.) defined in Trace-fwd.h.
Definition: Trace-fwd.h:19
Station Trigger Data description
double GetElectricResistanceUnit() const
Definition: UnitsConfig.h:115
AtThresholdConstIterator AtThresholdEnd() const
End iterator over times.
const FrontEndSiPM & GetFrontEndSiPM() const
PulseContainer fPulses
Collection of SPE/PE pulses.
const Module & GetModule() const
Retrieve the parent mdet::Module.
void SetElectricPotentialDefault(const double unit, const std::string &name)
Definition: UnitsConfig.cc:106
constexpr double cm
Definition: AugerUnits.h:117
struct particle_info particle[80]
Channel level event data.
InternalScintillatorCollection::ComponentIterator ScintillatorIterator
double GetDepth() const
The depth of the origin of the module. This quantity is positive for an underground module...
void LoadConfig(const utl::Branch &b, const std::string &tag, T1 &var, const T2 &defaultValue)
Helper method to load a particular configuration parameter.
Definition: ConfigUtils.h:35
Vector object.
Definition: Vector.h:30
Eletronic BackEndSiPM.
Definition: BackEndSiPM.h:37
int GetType() const
Definition: Particle.h:101
TriggerTimeIterator TriggerTimesEnd() const
End of simulated local trigger times list.
const std::string & GetTimeName() const
Definition: UnitsConfig.h:104
const Point & GetPosition() const
Position of the particle.
Definition: Particle.h:110
Report failure to RunController, causing RunController to terminate execution.
Definition: VModule.h:64
CounterConstIterator CountersEnd() const
Definition: MEvent.h:52
constexpr double ampere
Definition: AugerUnits.h:221
std::ofstream fPulseFile
Associated stream.
SimulationType fSimType
Type of simulation.
PE MakePEAt(double t) const
Constructs an PE according to this SiPM characteristics.
Definition: SiPM.cc:169
unsigned int GetFADCTraceLength() const
double ComputeDecayDelay() const
Computes a delay due to decay process.
Definition: Fiber.cc:116
sevt::StationSimData & GetSimData()
Get simulated data at station level.
constexpr double ns
Definition: AugerUnits.h:162
void MakeIntegratorBTrace()
const std::string & GetFrequencyName() const
Definition: UnitsConfig.h:92
double ComputeDecayDelay() const
Computes a delay due to decay process.
int GetId() const
The id of this component.
unsigned int fMaxSPE
Maximum number of spe (inclusive).
double GetAmplitude1() const
Definition: SiPM.h:114
bool fGeneratePostFETotalPulseOutput
To include the total pulse after front-end in the output file.
bool IsSiPM() const
unsigned int fNPulseSamples
Number of samples to use in the output files for pulses.
virtual VModule::ResultFlag SimulateElectronics(mevt::Module &evtModule, const mdet::Module &module, const SignalsMap &sm, const utl::TimeStamp &eventTime)
Peform the simulation of the electronics response.
const std::string & GetElectricPotentialName() const
Definition: UnitsConfig.h:88
double GetTimeUnit() const
Definition: UnitsConfig.h:130
utl::TraceUSI & GetIntegratorBTrace()
double GetAmplitude3() const
Definition: SiPM.h:122
double GetZ(const CoordinateSystemPtr &coordinateSystem) const
Definition: BasicVector.h:212
const Module & GetModule() const
The module to which this FrontEnd belongs.
Definition: FrontEnd.cc:36
Optical mdet::Fiber used to conect mdet::Scintillator to mdet::Pixel.
Definition: Fiber.h:54
bool HasTrace() const
double mod(const double d, const double periode)
const Scintillator & GetScintillator(int sId) const
Direct accesor by id.
Header & GetHeader()
Definition: MEvent.h:65
unsigned short GetADCBaseLineFluctuationHG() const
const Counter & GetCounter(int id) const
Retrieve Counter by id.
Definition: MDetector.h:68
void PushBack(const T &value)
Insert a single value at the end.
Definition: Trace.h:119
const Module & GetModule() const
The module to which this FrontEndSiPM belongs.
Definition: FrontEndSiPM.cc:46
#define ERROR(message)
Macro for logging error messages.
Definition: ErrorLogger.h:165
constexpr double m
Definition: AugerUnits.h:121
double GetFrequencyUnit() const
Definition: UnitsConfig.h:118
const Vector & GetDirection() const
Unit vector giving particle direction.
Definition: Particle.h:114
SPE MakeSPEAt(const double t) const
Constructs an SPE according to this pixel&#39;s characteristics.
const std::string & GetAngleName() const
Definition: UnitsConfig.h:84
const HLine hline('-')
double GetThreshold() const
Discrimination threshold.
const EndColumn endc
Root of the Muon event hierarchy.
Definition: MEvent.h:25
bool fGenerateSPEPulseOutput
To include individual pulses samples in the output file.
bool HasSEvent() const
ChannelConstIterator ChannelsEnd() const
End iterator over the contained channels.
Definition: FrontEndSiPM.h:93
const ChannelSiPM & GetChannelSiPMFor(const Component &c) const
Returns the associated mdet::ChannelSiPM.
utl::Branch GetTopBranch(const std::string &id)
Get top branch for moduleConfigLink with given id (XML files)
virtual void ProcessPulsesIntegrator(const mdet::Module &module, std::vector< utl::TraceD > analogicalTraces, utl::TraceUSI &traceIntegratorA, utl::TraceUSI &traceIntegratorB, const utl::TimeInterval &traceStart, double &minTimePreFE, double &maxTimePreFE)
const Vector & GetDirection() const
Return the (normalized) direction vector.
Definition: Segment.h:42
Definition: Line.h:17
double GetRefractionIndex() const
The refraction (or refractive) index of the fiber.
Definition: Fiber.cc:102
unsigned short GetInjectDigitalNoiseChannel() const
Simple struct to store signal information in containers.
double GetOnManifoldLength() const
The length of the fiber along the path that joins the scintillator to its pixel on the PMT...
Definition: Fiber.cc:65
A segment joins two points.
Definition: Segment.h:18
void Dump(const TF1 &fun, const std::string &suffix)
Helper to dump a TF1 to the configured file.

, generated on Tue Sep 26 2023.