All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
DigiArapucaSBNDAlg.cc
Go to the documentation of this file.
2 
3 //------------------------------------------------------------------------------
4 //--- opdet::simarapucasbndAlg implementation
5 //------------------------------------------------------------------------------
6 
7 namespace opdet {
8 
10  : fParams{config}
11  , fSampling(fParams.frequency/ 1000.) //in GHz to cancel with ns
12  , fSampling_Daphne(fParams.frequency_Daphne/ 1000.) //in GHz to cancel with ns
13  , fXArapucaVUVEff(fParams.XArapucaVUVEff / fParams.larProp->ScintPreScale())
14  , fXArapucaVISEff(fParams.XArapucaVISEff / fParams.larProp->ScintPreScale())
15  , fADCSaturation(fParams.Baseline + fParams.Saturation * fParams.ADC * fParams.MeanAmplitude)
16  , fEngine(fParams.engine)
17  , fFlatGen(*fEngine)
18  , fPoissonQGen(*fEngine)
19  , fGaussQGen(*fEngine)
20  , fExponentialGen(*fEngine)
21  {
22 
23  if(fXArapucaVUVEff > 1.0001 || fXArapucaVISEff > 1.0001)
24  mf::LogWarning("DigiArapucaSBNDAlg")
25  << "Quantum efficiency set in fhicl file "
26  << fParams.XArapucaVUVEff << " or " << fParams.XArapucaVISEff
27  << " seems to be too large!\n"
28  << "Final QE must be equal to or smaller than the scintillation "
29  << "pre scale applied at simulation time.\n"
30  << "Please check this number (ScintPreScale): "
31  << fParams.larProp->ScintPreScale();
32 
33  std::string fname;
34  cet::search_path sp("FW_SEARCH_PATH");
35  sp.find_file(fParams.ArapucaDataFile, fname);
36  TFile* file = TFile::Open(fname.c_str(), "READ");
37  //Note: TPB time now implemented at digitization module for both coated pmts and (x)arapucas
38  //OpDetSim/digi_arapuca_sbnd.root updated in sbnd_data (now including the TPB times vector)
39 
40  // TPB emission time histogram for visible (x)arapucas
41  std::vector<double>* timeTPB_p;
42  file->GetObject("timeTPB", timeTPB_p);
43  fTimeTPB = std::make_unique<CLHEP::RandGeneral>
44  (*fEngine, timeTPB_p->data(), timeTPB_p->size());
45 
46  std::vector<double>* TimeXArapucaVUV_p;
47  file->GetObject("TimeXArapucaVUV", TimeXArapucaVUV_p);
48  fTimeXArapucaVUV = std::make_unique<CLHEP::RandGeneral>
49  (*fEngine, TimeXArapucaVUV_p->data(), TimeXArapucaVUV_p->size());
50 
51  size_t pulseSize = fParams.PulseLength * fSampling;
52  fWaveformSP.resize(pulseSize);
53 
54  size_t pulseSize_Daphne = fParams.PulseLength * fSampling_Daphne;
55  fWaveformSP_Daphne.resize(pulseSize_Daphne);
56 
57  if(fParams.ArapucaSinglePEmodel) {
58  mf::LogDebug("DigiArapucaSBNDAlg") << " using testbench pe response";
59  TFile* file = TFile::Open(fname.c_str(), "READ");
60  std::vector<double>* SinglePEVec_40ftCable_Daphne;
61  std::vector<double>* SinglePEVec_40ftCable_Apsaia;
62  file->GetObject("SinglePEVec_40ftCable_Apsaia", SinglePEVec_40ftCable_Apsaia);
63  file->GetObject("SinglePEVec_40ftCable_Daphne", SinglePEVec_40ftCable_Daphne);
64  fWaveformSP = *SinglePEVec_40ftCable_Apsaia;
65  fWaveformSP_Daphne = *SinglePEVec_40ftCable_Daphne;
66  }
67  else{
68  mf::LogDebug("DigiArapucaSBNDAlg") << " using ideal pe response";
69  Pulse1PE(fWaveformSP,fSampling);
70  Pulse1PE(fWaveformSP_Daphne,fSampling_Daphne);
71  }
72  file->Close();
73  } // end constructor
74 
76 
77 
79  int ch,
80  sim::SimPhotons const& simphotons,
81  std::vector<short unsigned int>& waveform,
82  std::string pdtype,
83  bool is_daphne,
84  double start_time,
85  unsigned n_samples)
86  {
87  std::vector<double> waves(n_samples, fParams.Baseline);
88  CreatePDWaveform(simphotons, start_time, waves, pdtype,is_daphne);
89  waveform = std::vector<short unsigned int> (waves.begin(), waves.end());
90  }
91 
92 
94  int ch,
95  sim::SimPhotonsLite const& litesimphotons,
96  std::vector<short unsigned int>& waveform,
97  std::string pdtype,
98  bool is_daphne,
99  double start_time,
100  unsigned n_samples)
101  {
102  std::vector<double> waves(n_samples, fParams.Baseline);
103  std::map<int, int> const& photonMap = litesimphotons.DetectedPhotons;
104  CreatePDWaveformLite(photonMap, start_time, waves, pdtype,is_daphne);
105  // std::ofstream ofs("True_PE.log",std::ofstream::out | std::ofstream::app);
106  // ofs<<ch<<"\t"<<P_truth<<std::endl;
107  // ofs.close();
108  // P_truth=0;
109  waveform = std::vector<short unsigned int> (waves.begin(), waves.end());
110  }
111 
112 
114  sim::SimPhotons const& simphotons,
115  double t_min,
116  std::vector<double>& wave,
117  std::string pdtype,
118  bool is_daphne)
119  {
120  int nCT = 1;
121  if(pdtype == "xarapuca_vuv") {
122  for(size_t i = 0; i < simphotons.size(); i++) {
123  if(fFlatGen.fire(1.0) < fXArapucaVUVEff) {
124  double tphoton = (fTimeXArapucaVUV->fire()) + simphotons[i].Time - t_min;
125  if(tphoton < 0.) continue; // discard if it didn't made it to the acquisition
126  if(fParams.CrossTalk > 0.0 && fFlatGen.fire(1.0) < fParams.CrossTalk) nCT = 2;
127  else nCT = 1;
128  size_t timeBin = (is_daphne) ? std::floor(tphoton * fSampling_Daphne) : std::floor(tphoton * fSampling);
129  if(timeBin < wave.size()) {
130  if (!is_daphne) {AddSPE(timeBin, wave, fWaveformSP, nCT);
131  }
132  else{ AddSPE(timeBin, wave, fWaveformSP_Daphne, nCT);}
133  }
134  }
135  }
136  }
137  else if(pdtype == "xarapuca_vis") {
138  for(size_t i = 0; i < simphotons.size(); i++) {
139  if(fFlatGen.fire(1.0) < fXArapucaVISEff) {
140  double tphoton = fExponentialGen.fire(fParams.DecayTXArapucaVIS) + simphotons[i].Time - t_min + fTimeTPB->fire();
141  if(tphoton < 0.) continue; // discard if it didn't made it to the acquisition
142  if(fParams.CrossTalk > 0.0 && fFlatGen.fire(1.0) < fParams.CrossTalk) nCT = 2;
143  else nCT = 1;
144  size_t timeBin = (is_daphne) ? std::floor(tphoton * fSampling_Daphne) : std::floor(tphoton * fSampling);
145  if(timeBin < wave.size()) {
146  if (!is_daphne) {AddSPE(timeBin, wave, fWaveformSP, nCT);
147  }
148  else{ AddSPE(timeBin, wave, fWaveformSP_Daphne, nCT);
149  }
150  }
151  }
152  }
153  }
154  else{
155  throw cet::exception("DigiARAPUCASBNDAlg") << "Wrong pdtype: " << pdtype << std::endl;
156  }
157  if(fParams.BaselineRMS > 0.0) AddLineNoise(wave);
158  if(fParams.DarkNoiseRate > 0.0)
159  {
160  if (!is_daphne) AddDarkNoise(wave,fWaveformSP);
161  else AddDarkNoise(wave,fWaveformSP_Daphne);
162  }
163  CreateSaturation(wave);
164  }
165 
166 
168  std::map<int, int> const& photonMap,
169  double t_min,
170  std::vector<double>& wave,
171  std::string pdtype,
172  bool is_daphne)
173  {
174  if(pdtype == "xarapuca_vuv"){
175  SinglePDWaveformCreatorLite(fXArapucaVUVEff, fTimeXArapucaVUV, wave, photonMap, t_min,is_daphne);
176  }
177  else if(pdtype == "xarapuca_vis"){
178  // creating the waveforms for xarapuca_vis is different than the rest
179  // so there's an overload for that which lacks the timeHisto
180  SinglePDWaveformCreatorLite(fXArapucaVISEff, wave, photonMap, t_min,is_daphne);
181  }
182  else{
183  throw cet::exception("DigiARAPUCASBNDAlg") << "Wrong pdtype: " << pdtype << std::endl;
184  }
185  if(fParams.BaselineRMS > 0.0) AddLineNoise(wave);
186  if(fParams.DarkNoiseRate > 0.0)
187  {
188  if (!is_daphne) AddDarkNoise(wave,fWaveformSP);
189  else AddDarkNoise(wave,fWaveformSP_Daphne);
190  }
191 
192  CreateSaturation(wave);
193  }
194 
195 
197  double effT,
198  std::unique_ptr<CLHEP::RandGeneral>& timeHisto,
199  std::vector<double>& wave,
200  std::map<int, int> const& photonMap,
201  double const& t_min,
202  bool is_daphne
203  )
204  {
205  // TODO: check that this new approach of not using the last
206  // (1-accepted_photons) doesn't introduce some bias
207  double meanPhotons;
208  size_t acceptedPhotons;
209  double tphoton;
210  for (auto const& photonMember : photonMap) {
211  // TODO: check that this new approach of not using the last
212  // (1-accepted_photons) doesn't introduce some bias
213  meanPhotons = photonMember.second*effT;
214  acceptedPhotons = fPoissonQGen.fire(meanPhotons);
215  for(size_t i = 0; i < acceptedPhotons; i++) {
216  tphoton = timeHisto->fire();
217  tphoton += photonMember.first - t_min;
218  if(tphoton < 0.) continue; // discard if it didn't made it to the acquisition
219  int nCT=1;
220  if(fParams.CrossTalk > 0.0 &&
221  fFlatGen.fire(1.0) < fParams.CrossTalk) nCT = 2;
222  size_t timeBin = (is_daphne) ? std::floor(tphoton * fSampling_Daphne) : std::floor(tphoton * fSampling);
223  if(timeBin < wave.size()) {
224  // P_truth=P_truth+nCT;
225  if (!is_daphne) {AddSPE(timeBin, wave, fWaveformSP, nCT);
226  }
227  else{ AddSPE(timeBin, wave, fWaveformSP_Daphne, nCT);}
228  }
229  }
230  }
231  }
232 
233 
235  double effT,
236  std::vector<double>& wave,
237  std::map<int, int> const& photonMap,
238  double const& t_min,
239  bool is_daphne
240  )
241  {
242  double meanPhotons;
243  size_t acceptedPhotons;
244  double tphoton;
245  int nCT;
246  for (auto const& photonMember : photonMap) {
247  // TODO: check that this new approach of not using the last
248  // (1-accepted_photons) doesn't introduce some bias
249  meanPhotons = photonMember.second*effT;
250  acceptedPhotons = fPoissonQGen.fire(meanPhotons);
251  for(size_t i = 0; i < acceptedPhotons; i++) {
252  tphoton = fExponentialGen.fire(fParams.DecayTXArapucaVIS);
253  tphoton += photonMember.first - t_min + fTimeTPB->fire();
254  if(tphoton < 0.) continue; // discard if it didn't made it to the acquisition
255  if(fParams.CrossTalk > 0.0 && fFlatGen.fire(1.0) < fParams.CrossTalk) nCT = 2;
256  else nCT = 1;
257  size_t timeBin = (is_daphne) ? std::floor(tphoton * fSampling_Daphne) : std::floor(tphoton * fSampling);
258  if(timeBin < wave.size()) {
259  // P_truth=P_truth+nCT;
260  if (!is_daphne) {AddSPE(timeBin, wave, fWaveformSP, nCT);
261  }
262  else{ AddSPE(timeBin, wave, fWaveformSP_Daphne, nCT);}
263  }
264  }
265  }
266  }
267 
268  //Ideal single pulse waveform, same shape for both electronics (not realistic: different capacitances, ...)
269  void DigiArapucaSBNDAlg::Pulse1PE(std::vector<double>& fWaveformSP, const double sampling)//TODO: use only one Pulse1PE functions for both electronics ~rodrigoa
270  {
271  double constT1 = fParams.ADC * fParams.MeanAmplitude;
272  for(size_t i = 0; i<fWaveformSP.size(); i++) {
273  double time = static_cast<double>(i) / sampling;
274  if (time < fParams.PeakTime) fWaveformSP[i] = constT1 * std::exp((time - fParams.PeakTime) / fParams.RiseTime);
275  else fWaveformSP[i] = constT1 * std::exp(-(time - fParams.PeakTime) / fParams.FallTime);
276  }
277  }
278 
280  const size_t time_bin,
281  std::vector<double>& wave,
282  const std::vector<double>& fWaveformSP,
283  const int nphotons) //adding single pulse //TODO: use only one function, use pulsize and fWaveformSP as arguments instead ~rodrigoa
284  {
285  // if(time_bin > wave.size()) return;
286  size_t max = time_bin + fWaveformSP.size() < wave.size() ? time_bin + fWaveformSP.size() : wave.size();
287  auto min_it = std::next(wave.begin(), time_bin);
288  auto max_it = std::next(wave.begin(), max);
289 
290  double nphotons_aux= nphotons;
291  if(fParams.MakeAmpFluctuations) nphotons_aux = fGaussQGen.fire(nphotons, std::sqrt(nphotons) * fParams.AmpFluctuation);
292 
293  std::transform(min_it, max_it,
294  fWaveformSP.begin(), min_it,
295  [nphotons_aux](double w, double ws) -> double {
296  return w + ws*nphotons_aux ; });
297  }
298 
299  void DigiArapucaSBNDAlg::CreateSaturation(std::vector<double>& wave)
300  {
301  std::replace_if(wave.begin(), wave.end(),
302  [&](auto w){return w > fADCSaturation;}, fADCSaturation);
303  }
304 
305 
306  void DigiArapucaSBNDAlg::AddLineNoise(std::vector< double >& wave)
307  {
308  // TODO: after running the profiler I can see that this is where
309  // most cycles are being used. Potentially some improvement could
310  // be achieved with the below code but the array dynamic allocation
311  // is not helping. The function would need to have it passed.
312  // ~icaza
313  //
314  // double *array = new double[wave.size()]();
315  // CLHEP::RandGaussQ::shootArray(fEngine, wave.size(), array, 0, fParams.BaselineRMS);
316  // for(size_t i = 0; i<wave.size(); i++) {
317  // wave[i] += array[i];
318  // }
319  // delete array;
320  //
321  std::transform(wave.begin(), wave.end(), wave.begin(),
322  [this](double w) -> double {
323  return w + fGaussQGen.fire(0., fParams.BaselineRMS) ; });
324  }
325 
326 
327  void DigiArapucaSBNDAlg::AddDarkNoise(std::vector<double>& wave,std::vector<double>& WaveformSP)
328  {
329  int nCT;
330  // Multiply by 10^9 since fDarkNoiseRate is in Hz (conversion from s to ns)
331  double mean = 1000000000.0 / fParams.DarkNoiseRate;
332  double darkNoiseTime = fExponentialGen.fire(mean);
333  while(darkNoiseTime < wave.size()) {
334  size_t timeBin = std::round(darkNoiseTime);
335  if(fParams.CrossTalk > 0.0 && fFlatGen.fire(1.0) < fParams.CrossTalk) nCT = 2;
336  else nCT = 1;
337  if(timeBin < wave.size()) AddSPE(timeBin, wave, WaveformSP, nCT);
338  // Find next time to add dark noise
339  darkNoiseTime += fExponentialGen.fire(mean);
340  }//while
341  }
342 
343 
345  {
346  double t_min = 1e15;
347  for(size_t i = 0; i < simphotons.size(); i++) {
348  if(simphotons[i].Time < t_min) t_min = simphotons[i].Time;
349  }
350  return t_min;
351  }
352 
353 
354  double DigiArapucaSBNDAlg::FindMinimumTimeLite(std::map<int, int> const& photonMap)
355  {
356  for (auto const& mapMember : photonMap) {
357  if(mapMember.second != 0) return (double)mapMember.first;
358  }
359  return 1e5;
360  }
361 
362 
363  // -----------------------------------------------------------------------------
364  // // --- opdet::DigiArapucaSBNDAlgMaker
365  // // -----------------------------------------------------------------------------
367  (Config const& config)
368  {
369  // settings
370  fBaseConfig.ADC = config.voltageToADC();
371  fBaseConfig.Baseline = config.baseline();
372  fBaseConfig.Saturation = config.saturation();
373  fBaseConfig.XArapucaVUVEff = config.xArapucaVUVEff();
374  fBaseConfig.XArapucaVISEff = config.xArapucaVISEff();
375  fBaseConfig.RiseTime = config.riseTime();
376  fBaseConfig.FallTime = config.fallTime();
377  fBaseConfig.MeanAmplitude = config.meanAmplitude();
378  fBaseConfig.DarkNoiseRate = config.darkNoiseRate();
379  fBaseConfig.BaselineRMS = config.baselineRMS();
380  fBaseConfig.CrossTalk = config.crossTalk();
381  fBaseConfig.PulseLength = config.pulseLength();
382  fBaseConfig.PeakTime = config.peakTime();
383  fBaseConfig.DecayTXArapucaVIS = config.decayTXArapucaVIS();
384  fBaseConfig.ArapucaDataFile = config.arapucaDataFile();
385  fBaseConfig.ArapucaSinglePEmodel = config.ArapucasinglePEmodel();
386  fBaseConfig.frequency_Daphne = config.DaphneFrequency();
387  fBaseConfig.MakeAmpFluctuations = config.makeAmpFluctuations();
388  fBaseConfig.AmpFluctuation = config.ampFluctuation();
389  }
390 
391  std::unique_ptr<DigiArapucaSBNDAlg> DigiArapucaSBNDAlgMaker::operator()(
392  detinfo::LArProperties const& larProp,
393  detinfo::DetectorClocksData const& clockData,
394  CLHEP::HepRandomEngine* engine
395  ) const
396  {
397  // set the configuration
398  auto params = fBaseConfig;
399 
400  // set up parameters
401  params.larProp = &larProp;
402  params.frequency = clockData.OpticalClock().Frequency();
403  params.frequency_Daphne = fBaseConfig.frequency_Daphne; //Mhz
404  params.engine = engine;
405 
406  return std::make_unique<DigiArapucaSBNDAlg>(params);
407  } // DigiArapucaSBNDAlgMaker::create()
408 
409 }
double FindMinimumTime(sim::SimPhotons const &simphotons)
std::vector< double > fWaveformSP_Daphne
string fname
Definition: demo.py:5
static constexpr Sample_t transform(Sample_t sample)
void AddDarkNoise(std::vector< double > &wave, std::vector< double > &WaveformSP)
* file
Definition: file_to_url.sh:69
void AddLineNoise(std::vector< double > &wave)
DigiArapucaSBNDAlg::ConfigurationParameters_t fBaseConfig
Part of the configuration learned from configuration files.
std::map< int, int > DetectedPhotons
Number of photons detected at each given time: time tick -&gt; photons.
Definition: SimPhotons.h:117
std::unique_ptr< CLHEP::RandGeneral > fTimeXArapucaVUV
CLHEP::RandExponential fExponentialGen
std::vector< double > fWaveformSP
void ConstructWaveformLite(int ch, sim::SimPhotonsLite const &litesimphotons, std::vector< short unsigned int > &waveform, std::string pdtype, bool is_daphne, double start_time, unsigned n_samples)
fEngine(art::ServiceHandle< rndm::NuRandomService >() ->createEngine(*this, pset,"Seed"))
void AddSPE(size_t time_bin, std::vector< double > &wave, const std::vector< double > &fWaveformSP, int nphotons)
std::unique_ptr< CLHEP::RandGeneral > fTimeTPB
ElecClock const & OpticalClock() const noexcept
Borrow a const Optical clock with time set to Trigger time [us].
detinfo::LArProperties const * larProp
LarProperties service provider.
std::unique_ptr< DigiArapucaSBNDAlg > operator()(detinfo::LArProperties const &larProp, detinfo::DetectorClocksData const &clockData, CLHEP::HepRandomEngine *engine) const
void CreateSaturation(std::vector< double > &wave)
DigiArapucaSBNDAlgMaker(Config const &config)
double mean(const std::vector< short > &wf, size_t start, size_t nsample)
Definition: UtilFunc.cxx:13
Collection of photons which recorded on one channel.
Definition: SimPhotons.h:136
Compact representation of photons on a channel.
Definition: SimPhotons.h:103
then echo fcl sbnd_project sbnd_project sbnd_project sbnd_project production production start_time
void CreatePDWaveform(sim::SimPhotons const &SimPhotons, double t_min, std::vector< double > &wave, std::string pdtype, bool is_daphne)
CLHEP::RandPoissonQ fPoissonQGen
void CreatePDWaveformLite(std::map< int, int > const &photonMap, double t_min, std::vector< double > &wave, std::string pdtype, bool is_daphne)
Contains all timing reference information for the detector.
DigiArapucaSBNDAlg(ConfigurationParameters_t const &config)
void Pulse1PE(std::vector< double > &wave, const double sampling)
constexpr double Frequency() const
Frequency in MHz.
Definition: ElecClock.h:191
const ConfigurationParameters_t fParams
double frequency_Daphne
Optical-clock frequency for daphne readouts.
void ConstructWaveform(int ch, sim::SimPhotons const &simphotons, std::vector< short unsigned int > &waveform, std::string pdtype, bool is_daphne, double start_time, unsigned n_samples)
void SinglePDWaveformCreatorLite(double effT, std::unique_ptr< CLHEP::RandGeneral > &timeHisto, std::vector< double > &wave, std::map< int, int > const &photonMap, double const &t_min, bool is_daphne)
fhicl::Atom< std::string > arapucaDataFile
double FindMinimumTimeLite(std::map< int, int > const &photonMap)