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

, generated on Tue Sep 26 2023.