All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
SimWire_module.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // SimWire class designed to simulate signal on a wire in the TPC
4 //
5 // katori@fnal.gov
6 //
7 // - Revised to use sim::RawDigit instead of rawdata::RawDigit, and to
8 // - save the electron clusters associated with each digit.
9 //
10 // mwang@fnal.gov (2/04/21)
11 //
12 // - Revised field response functions with quadratic and sinusoidal for
13 // collection and induction planes, respectively
14 // - Updated electronics response with uBooNE spice-based model
15 // - Included more realistic noise models:
16 // (a) modified uBooNE model -> "ModUBooNE" in fcl
17 // (b) ArgoNeuT data driven model -> "ArgoNeuT" in fcl
18 // - Included following distributions for fluctuating magnitude of
19 // noise frequency components:
20 // (a) simple modified Poisson -> "SimplePoisson" in fcl
21 // (b) weighted Poisson from ArgoNeuT DDN -> "WeightedPoisson" in fcl
22 // - Included choice for generating unique noise in each channel for
23 // each event
24 // - Updated ConvoluteResponseFunctions() to do things in same fashion
25 // as in a typical SignalShapingXXX service for a particular XXX
26 // experiment
27 //
28 ////////////////////////////////////////////////////////////////////////
29 
30 // ROOT includes
31 #include "TComplex.h"
32 #include "TMath.h"
33 
34 // C++ includes
35 #include <algorithm>
36 #include <memory>
37 #include <string>
38 #include <utility>
39 #include <vector>
40 
41 // Framework includes
42 #include "art/Framework/Core/EDProducer.h"
43 #include "art/Framework/Core/ModuleMacros.h"
44 #include "art/Framework/Principal/Event.h"
45 #include "art/Framework/Services/Registry/ServiceHandle.h"
46 #include "art_root_io/TFileService.h"
47 #include "messagefacility/MessageLogger/MessageLogger.h"
48 #include "fhiclcpp/ParameterSet.h"
49 #include "cetlib_except/exception.h"
50 
51 // art extensions
52 #include "nurandom/RandomUtils/NuRandomService.h"
53 
54 #include "CLHEP/Random/RandFlat.h"
55 
56 // LArSoft includes
63 #include "lardataobj/RawData/raw.h"
65 
66 // Detector simulation of raw signals on wires
67 namespace detsim {
68 
69  class SimWire : public art::EDProducer {
70  public:
71  explicit SimWire(fhicl::ParameterSet const& pset);
72 
73  private:
74  void produce(art::Event& evt) override;
75  void beginJob() override;
76 
77  void ConvoluteResponseFunctions(); ///< convolute electronics and field response
78 
79  void SetFieldResponse(); ///< response of wires to field
80  void SetElectResponse(); ///< response of electronics
81 
82  void GenNoise(std::vector<float>& array, CLHEP::HepRandomEngine& engine);
83 
84  std::string fDriftEModuleLabel; ///< module making the ionization electrons
85  raw::Compress_t fCompression; ///< compression type to use
86 
87  int fNTicks; ///< number of ticks of the clock
88  double fSampleRate; ///< sampling rate in ns
89  unsigned int fNSamplesReadout; ///< number of ADC readout samples in 1 readout frame
90  double fCol3DCorrection; ///< correction factor to account for 3D path of
91  ///< electrons thru wires
92  double fInd3DCorrection; ///< correction factor to account for 3D path of
93  ///< electrons thru wires
94  unsigned int fNElectResp; ///< number of entries from response to use
95  double fInputFieldRespSamplingPeriod; ///< Sampling period in the input field response.
96  double fShapeTimeConst; ///< time constants for exponential shaping
97  double fADCPerPCAtLowestASICGain; ///< ADCs/pC at lowest gain setting of 4.7 mV/fC
98  double fASICGainInMVPerFC; ///< actual gain setting used in mV/fC
99  int fNoiseNchToSim; ///< number of noise channels to generate
100  std::string fNoiseModelChoice; ///< choice for noise model
101  std::string fNoiseFluctChoice; ///< choice for noise freq component mag fluctuations
102 
103  std::vector<int> fFieldRespTOffset; ///< field response time offset in ticks
104  std::vector<int> fCalibRespTOffset; ///< calib response time offset in ticks
105  std::vector<float> fColFieldParams; ///< collection plane field function parameterization
106  std::vector<float> fIndFieldParams; ///< induction plane field function parameterization
107  std::vector<double> fColFieldResponse; ///< response function for the field @ collection plane
108  std::vector<double> fIndFieldResponse; ///< response function for the field @ induction plane
109  std::vector<TComplex> fColShape; ///< response function for the field @ collection plane
110  std::vector<TComplex> fIndShape; ///< response function for the field @ induction plane
111  std::vector<double> fElectResponse; ///< response function for the electronics
112  std::vector<std::vector<float>> fNoise; ///< noise on each channel for each time
113  std::vector<double> fNoiseModelPar; ///< noise model params
114  std::vector<double> fNoiseFluctPar; ///< Poisson noise fluctuations params
115 
116  TH1D* fIndFieldResp; ///< response function for the field @ induction plane
117  TH1D* fColFieldResp; ///< response function for the field @ collection plane
118  TH1D* fElectResp; ///< response function for the electronics
119  TH1D* fColTimeShape; ///< convoluted shape for field x electronics @ col plane
120  TH1D* fIndTimeShape; ///< convoluted shape for field x electronics @ ind plane
121  TH1D* fNoiseDist; ///< distribution of noise counts
122  TF1* fNoiseFluct; ///< Poisson dist for fluctuations in magnitude of noise freq components
123 
124  CLHEP::HepRandomEngine& fEngine; ///< Random-number engine owned by art
125  }; // class SimWire
126 
127 }
128 
129 namespace detsim {
130 
131  //-------------------------------------------------
132  SimWire::SimWire(fhicl::ParameterSet const& pset)
133  : EDProducer{pset}
134  , fDriftEModuleLabel{pset.get<std::string>("DriftEModuleLabel")}
135  , fCompression{pset.get<std::string>("CompressionType") == "Huffman" ? raw::kHuffman :
136  raw::kNone}
137  , fCol3DCorrection{pset.get<double>("Col3DCorrection")}
138  , fInd3DCorrection{pset.get<double>("Ind3DCorrection")}
139  , fInputFieldRespSamplingPeriod{pset.get<double>("InputFieldRespSamplingPeriod")}
140  , fShapeTimeConst{pset.get<double>("ShapeTimeConst")}
141  , fADCPerPCAtLowestASICGain{pset.get<double>("ADCPerPCAtLowestASICGain")}
142  , fASICGainInMVPerFC{pset.get<double>("ASICGainInMVPerFC")}
143  , fNoiseNchToSim{pset.get<int>("NoiseNchToSim")}
144  , fNoiseModelChoice{pset.get<std::string>("NoiseModelChoice")}
145  , fNoiseFluctChoice{pset.get<std::string>("NoiseFluctChoice")}
146  , fFieldRespTOffset{pset.get<std::vector<int>>("FieldRespTOffset")}
147  , fCalibRespTOffset{pset.get<std::vector<int>>("CalibRespTOffset")}
148  , fColFieldParams{pset.get<std::vector<float>>("ColFieldParams")}
149  , fIndFieldParams{pset.get<std::vector<float>>("IndFieldParams")}
150  , fNoiseModelPar{pset.get<std::vector<double>>("NoiseModelPar")}
151  , fNoiseFluctPar{pset.get<std::vector<double>>("NoiseFluctPar")}
152  // create a default random engine; obtain the random seed from NuRandomService,
153  // unless overridden in configuration with key "Seed"
154  , fEngine(art::ServiceHandle<rndm::NuRandomService> {}->createEngine(*this, pset, "Seed"))
155  {
156  auto const clockData = art::ServiceHandle<detinfo::DetectorClocksService const>()->DataForJob();
157  auto const detProp =
158  art::ServiceHandle<detinfo::DetectorPropertiesService const>()->DataForJob(clockData);
160  fNSamplesReadout = detProp.NumberTimeSamples();
161 
162  MF_LOG_WARNING("SimWire") << "SimWire is an example module that works for the "
163  << "MicroBooNE detector. Each experiment should implement "
164  << "its own version of this module to simulate electronics "
165  << "response.";
166 
167  produces<std::vector<raw::RawDigit>>();
168  }
169 
170  //-------------------------------------------------
171  void
173  {
174  // ... get access to the TFile service
175  art::ServiceHandle<art::TFileService const> tfs;
176 
177  fNoiseDist = tfs->make<TH1D>("Noise", ";Noise (ADC);", 1000, -10., 10.);
178 
179  art::ServiceHandle<util::LArFFT const> fFFT;
180  fNTicks = fFFT->FFTSize();
181 
182  // ... Poisson dist function for fluctuating magnitude of noise frequency component
183  if ( fNoiseFluctChoice == "SimplePoisson" ) {
184  // .. simple modified Poisson with (x-1)! in denominator
185  double params[1];
186  fNoiseFluct = new TF1("_poisson", "[0]**(x) * exp(-[0]) / ROOT::Math::tgamma(x)", 0, 5.);
187  params[0] = fNoiseFluctPar[0]; // Poisson mean
188  fNoiseFluct->SetParameters(params);
189  } else if ( fNoiseFluctChoice == "WeightedPoisson" ) {
190  // .. weighted Poisson in ArgoNeuT DDN model
191  double params[3];
192  fNoiseFluct = new TF1("_poisson", "[0]*pow([1]/[2], x/[2])*exp(-[1]/[2])/ROOT::Math::tgamma(x/[2]+1.)", 0, 5.);
193  params[0] = fNoiseFluctPar[0];
194  params[1] = fNoiseFluctPar[1];
195  params[2] = fNoiseFluctPar[2];
196  fNoiseFluct->SetParameters(params);
197  } else {
198  throw cet::exception("SimWire::beginJob") << fNoiseFluctChoice
199  << " is an unknown noise fluctuation choice" << std::endl;
200  }
201 
202  // ... generate the noise in advance depending on value of fNoiseNchToSim:
203  // positive - generate N=fNoiseNchToSim channels & randomly pick from pool when adding to signal
204  // zero - no noise
205  // negative - generate unique noise for each channel for each event
206  if (fNoiseNchToSim>0) {
207  if (fNoiseNchToSim>10000) {
208  throw cet::exception("SimWire::beginJob") << fNoiseNchToSim
209  << " noise channels requested exceeds 10000" << std::endl;
210  }
211  fNoise.resize(fNoiseNchToSim);
212  for (unsigned int p = 0; p < fNoise.size(); ++p) {
214  for (int i = 0; i < fNTicks; ++i) {
215  fNoiseDist->Fill(fNoise[p][i]);
216  }
217  }
218  }
219 
220 
221  // ... set field response and electronics response, then convolute them
225  }
226 
227  //-------------------------------------------------
228  void
229  SimWire::produce(art::Event& evt)
230  {
231 
232  art::ServiceHandle<geo::Geometry const> geo;
233 
234  // ... generate unique noise for each channel in each event
235  if (fNoiseNchToSim<0) {
236  fNoise.clear();
237  fNoise.resize(geo->Nchannels());
238  for(unsigned int p = 0; p < geo->Nchannels(); ++p){
240  }
241  }
242 
243  // ... make a vector of const sim::SimChannel* that has same number
244  // of entries as the number of channels in the detector
245  // and set the entries for the channels that have signal on them
246  // using the chanHandle
247  std::vector<const sim::SimChannel*> chanHandle;
248  evt.getView(fDriftEModuleLabel,chanHandle);
249 
250  std::vector<const sim::SimChannel*> channels(geo->Nchannels());
251  for(size_t c = 0; c < chanHandle.size(); ++c){
252  channels[chanHandle[c]->Channel()] = chanHandle[c];
253  }
254 
255  // ... make an unique_ptr of sim::SimDigits that allows ownership of the produced
256  // digits to be transferred to the art::Event after the put statement below
257  auto digcol = std::make_unique<std::vector<raw::RawDigit>>();
258 
259  art::ServiceHandle<util::LArFFT> fFFT;
260 
261  // ... Add all channels
262  CLHEP::RandFlat flat(fEngine);
263 
264  std::map<int,double>::iterator mapIter;
265  for(unsigned int chan = 0; chan < geo->Nchannels(); chan++) {
266 
267  std::vector<short> adcvec(fNTicks, 0);
268  std::vector<double> fChargeWork(fNTicks, 0.);
269 
270  if( channels[chan] ){
271 
272  // .. get the sim::SimChannel for this channel
273  const sim::SimChannel* sc = channels[chan];
274 
275  // .. loop over the tdcs and grab the number of electrons for each
276  for(int t = 0; t < fNTicks; ++t)
277  fChargeWork[t] = sc->Charge(t);
278 
279  int time_offset = 0;
280 
281  // .. Convolve charge with appropriate response function
282  if(geo->SignalType(chan) == geo::kInduction){
283  fFFT->Convolute(fChargeWork,fIndShape);
284  time_offset = fFieldRespTOffset[1]+fCalibRespTOffset[1];
285  } else {
286  fFFT->Convolute(fChargeWork,fColShape);
287  time_offset = fFieldRespTOffset[0]+fCalibRespTOffset[0];
288  }
289 
290  // .. Apply field response offset
291  std::vector<int> temp;
292  if (time_offset <=0){
293  temp.assign(fChargeWork.begin(),fChargeWork.begin()-time_offset);
294  fChargeWork.erase(fChargeWork.begin(),fChargeWork.begin()-time_offset);
295  fChargeWork.insert(fChargeWork.end(),temp.begin(),temp.end());
296  }else{
297  temp.assign(fChargeWork.end()-time_offset,fChargeWork.end());
298  fChargeWork.erase(fChargeWork.end()-time_offset,fChargeWork.end());
299  fChargeWork.insert(fChargeWork.begin(),temp.begin(),temp.end());
300  }
301 
302  }
303 
304  // ... Add noise to signal depending on value of fNoiseNchToSim
305  if(fNoiseNchToSim!=0){
306  int noisechan = chan;
307  if(fNoiseNchToSim>0){
308  noisechan = TMath::Nint(flat.fire()*(1.*(fNoise.size()-1)+0.1));
309  }
310  for(int i = 0; i < fNTicks; ++i){
311  adcvec[i] = (short)TMath::Nint(fNoise[noisechan][i] + fChargeWork[i]);
312  }
313  } else {
314  for(int i = 0; i < fNTicks; ++i){
315  adcvec[i] = (short)TMath::Nint(fChargeWork[i]);
316  }
317  }
318 
319  adcvec.resize(fNSamplesReadout);
320 
321  // ... compress the adc vector using the desired compression scheme,
322  // if raw::kNone is selected nothing happens to adcvec
323  // This shrinks adcvec, if fCompression is not kNone.
324  raw::Compress(adcvec, fCompression);
325 
326  // ... add this digit to the collection
327  digcol->emplace_back(chan, fNTicks, move(adcvec), fCompression);
328 
329  }//end loop over channels
330 
331  evt.put(std::move(digcol));
332 
333  return;
334  }
335 
336  //-------------------------------------------------
337  void
339  {
340  double tick, ticks, peak;
341 
342  std::vector<double> col(fNTicks, 0.);
343  std::vector<double> ind(fNTicks, 0.);
344  std::vector<TComplex> kern(fNTicks/2 + 1);
345  std::vector<double> delta(fNTicks, 0.);
346 
347  art::ServiceHandle<util::LArFFT> fFFT;
348 
349  // ... do collection plane
350  fColShape.resize(fNTicks/2+1);
351  fFFT->DoFFT(fElectResponse, fColShape);
352 
353  fFFT->DoFFT(fColFieldResponse, kern);
354  for(unsigned int i=0; i<kern.size(); ++i)
355  fColShape[i] *= kern[i];
356 
357  fFFT->DoInvFFT(fColShape, col);
358 
359  delta[0] = 1.0;
360  peak = fFFT->PeakCorrelation(delta, col);
361  tick = 0.;
362  ticks = tick - peak;
363  fFFT->ShiftData(fColShape, ticks);
364  fFFT->DoInvFFT(fColShape, col);
365 
366  // ... do induction plane
367  fIndShape.resize(fNTicks/2+1);
368  fFFT->DoFFT(fElectResponse, fIndShape);
369 
370  kern.clear();
371  kern.resize(fNTicks/2 + 1);
372  fFFT->DoFFT(fIndFieldResponse, kern);
373  for(unsigned int i=0; i<kern.size(); ++i)
374  fIndShape[i] *= kern[i];
375 
376  fFFT->DoInvFFT(fIndShape, ind);
377 
378  delta.resize(0);
379  delta.resize(fNTicks,0);
380  delta[0] = 1.0;
381  peak = fFFT->PeakCorrelation(delta, ind);
382  tick = 0.;
383  ticks = tick - peak;
384  fFFT->ShiftData(fIndShape, ticks);
385  fFFT->DoInvFFT(fIndShape, ind);
386 
387  // ... write the time-domain shapes out to a file
388  art::ServiceHandle<art::TFileService const> tfs;
389  fColTimeShape = tfs->make<TH1D>(
390  "ConvolutedCollection",";ticks; Electronics#timesCollection",fNTicks,0,fNTicks);
391  fIndTimeShape = tfs->make<TH1D>(
392  "ConvolutedInduction",";ticks; Electronics#timesInduction",fNTicks,0,fNTicks);
393 
394  // ... check that you did the right thing
395  for(unsigned int i = 0; i < ind.size(); ++i){
396  fColTimeShape->Fill(i, col[i]);
397  fIndTimeShape->Fill(i, ind[i]);
398  }
399 
400  fColTimeShape->Write();
401  fIndTimeShape->Write();
402 
403  }
404 
405  //-------------------------------------------------
406  void
407  SimWire::GenNoise(std::vector<float>& noise, CLHEP::HepRandomEngine& engine)
408  {
409  CLHEP::RandFlat flat(engine);
410 
411  noise.clear();
412  noise.resize(fNTicks, 0.);
413  std::vector<TComplex> noiseFrequency(fNTicks/2+1, 0.); // noise in frequency space
414 
415  double pval = 0.;
416  double phase = 0.;
417  double rnd[2] = {0.};
418 
419  // .. width of frequencyBin in kHz
420  double binWidth = 1.0/(fNTicks*fSampleRate*1.0e-6);
421 
422  for (int i=0; i< fNTicks/2+1; ++i) {
423 
424  double x=(i+0.5)*binWidth;
425 
426  if ( fNoiseModelChoice == "Legacy" ) {
427  // ... Legacy exponential model kept here for reference:
428  // par[0]=NoiseFact, par[1]=NoiseWidth, par[2]=LowCutoff, par[3-7]=0
429  // example parameter values for fcl: NoiseModelPar:[ 1.32e-1,120,7.5,0,0,0,0,0 ]
430  pval = fNoiseModelPar[0] * exp(-(double)i * binWidth / fNoiseModelPar[1]);
431  double lofilter = 1.0 / (1.0 + exp(-(i - fNoiseModelPar[2] / binWidth) / 0.5));
432  flat.fireArray(1, rnd, 0, 1);
433  pval *= lofilter * (0.9 + 0.2 * rnd[0]);
434  } else if ( fNoiseModelChoice == "ModUBooNE" ) {
435  // ... Modified uBooNE model with additive exp to account for low freq region:
436  // example parameter values for fcl: NoiseModelPar:[
437  // 4450.,-530.,280.,110.,
438  // -0.85,18.,0.064,74. ]
439  pval = fNoiseModelPar[0]*exp(-0.5*pow((x-fNoiseModelPar[1])/fNoiseModelPar[2],2))
440  *exp(-0.5*pow(x/fNoiseModelPar[3],fNoiseModelPar[4]))
442  double randomizer = fNoiseFluct->GetRandom();
443  pval = pval * randomizer/fNTicks;
444  } else if ( fNoiseModelChoice == "ArgoNeuT" ) {
445  // ... ArgoNeuT data driven model:
446  // In fcl set parameters to: NoiseModelPar:[
447  // 5000,-5.52058e2,2.81587e2,-5.66561e1,
448  // 4.10817e1,1.76284e1,1e-1,5.97838e1 ]
449  pval = fNoiseModelPar[0]*exp(-0.5*pow((x-fNoiseModelPar[1])/fNoiseModelPar[2],2))
450  *((fNoiseModelPar[3]/(x+fNoiseModelPar[4]))+1)
452  double randomizer = fNoiseFluct->GetRandom();
453  pval = pval * randomizer/fNTicks;
454  } else {
455  throw cet::exception("SimWire::GenNoise") << fNoiseModelChoice
456  << " is an unknown choice for the noise model" << std::endl;
457  }
458 
459  flat.fireArray(1,rnd,0,1);
460  phase = rnd[0]*2.*TMath::Pi();
461 
462  TComplex tc(pval*cos(phase),pval*sin(phase));
463  noiseFrequency[i] += tc;
464  }
465 
466  // .. inverse FFT MCSignal
467  art::ServiceHandle<util::LArFFT> fFFT;
468  fFFT->DoInvFFT(noiseFrequency, noise);
469 
470  noiseFrequency.clear();
471 
472  // .. multiply each noise value by fNTicks as the InvFFT
473  // divides each bin by fNTicks assuming that a forward FFT
474  // has already been done.
475  for (unsigned int i = 0; i < noise.size(); ++i)
476  noise[i] *= 1. * fNTicks;
477  }
478 
479  //-------------------------------------------------
480  void
482  {
483 
484  // ... Files to write the response functions to
485  art::ServiceHandle<art::TFileService const> tfs;
486  fIndFieldResp = tfs->make<TH1D>("InductionFieldResponse",";t (ns);Induction Response",fNTicks,0,fNTicks);
487  fColFieldResp = tfs->make<TH1D>("CollectionFieldResponse",";t (ns);Collection Response",fNTicks,0,fNTicks);
488 
489  fColFieldResponse.resize(fNTicks, 0.);
490  fIndFieldResponse.resize(fNTicks, 0.);
491 
492  // ... First set response for collection plane
493  int nbinc = fColFieldParams[0];
494 
495  double integral = 0.;
496  for (int i = 1; i < nbinc; ++i) {
497  fColFieldResponse[i] = i * i;
498  integral += fColFieldResponse[i];
499  }
500 
501  for (int i = 0; i < nbinc; ++i) {
502  fColFieldResponse[i] *= fColFieldParams[1]/integral;
503  fColFieldResp->Fill(i, fColFieldResponse[i]);
504  }
505 
506  // ... Now set response for induction plane
507  int nbini = fIndFieldParams[0];
508  unsigned short lastbini = 2 * nbini;
509 
510  integral = 0;
511  for (unsigned short i = 0; i < lastbini; ++i) {
512  double ang = i * TMath::Pi() / nbini;
513  fIndFieldResponse[i] = sin(ang);
514  if (fIndFieldResponse[i] > 0) {
515  integral += fIndFieldResponse[i];
516  } else {
517  fIndFieldResponse[i] *= fIndFieldParams[2]; // scale the negative lobe by 10% (from ArgoNeuT)
518  }
519  }
520  ++lastbini;
521 
522  for (unsigned short i = 0; i < lastbini; ++i) {
523  fIndFieldResponse[i] *= fIndFieldParams[1]/integral;
524  fIndFieldResp->Fill(i, fIndFieldResponse[i]);
525  }
526 
527  // ... Save the field responses
528  fColFieldResp->Write();
529  fIndFieldResp->Write();
530  }
531 
532  //-------------------------------------------------
533  void
535  {
536  fElectResponse.resize(fNTicks, 0.);
537  std::vector<double> time(fNTicks,0.);
538 
539  // ... Gain and shaping time variables from fcl file:
540  double Ao = 1.0;
541  double To = fShapeTimeConst; //peaking time
542 
543  // ... this is actually sampling time, in ns
544  mf::LogInfo("SimWire::SetElectResponse") << "Check sampling intervals: "
545  << fInputFieldRespSamplingPeriod << " ns"
546  << "Check number of samples: " << fNTicks;
547 
548  // ... The following sets the microboone electronics response function in
549  // time-space. Function comes from BNL SPICE simulation of DUNE35t
550  // electronics. SPICE gives the electronics transfer function in
551  // frequency-space. The inverse laplace transform of that function
552  // (in time-space) was calculated in Mathematica and is what is being
553  // used below. Parameters Ao and To are cumulative gain/timing parameters
554  // from the full (ASIC->Intermediate amp->Receiver->ADC) electronics chain.
555  // They have been adjusted to make the SPICE simulation to match the
556  // actual electronics response. Default params are Ao=1.4, To=0.5us.
557  double max = 0;
558 
559  for (size_t i = 0; i < fElectResponse.size(); ++i) {
560 
561  // ... convert time to microseconds, to match fElectResponse[i] definition
562  time[i] = (1.*i)*fInputFieldRespSamplingPeriod *1e-3;
563  fElectResponse[i] =
564  4.31054*exp(-2.94809*time[i]/To)*Ao - 2.6202*exp(-2.82833*time[i]/To)*cos(1.19361*time[i]/To)*Ao
565  -2.6202*exp(-2.82833*time[i]/To)*cos(1.19361*time[i]/To)*cos(2.38722*time[i]/To)*Ao
566  +0.464924*exp(-2.40318*time[i]/To)*cos(2.5928*time[i]/To)*Ao
567  +0.464924*exp(-2.40318*time[i]/To)*cos(2.5928*time[i]/To)*cos(5.18561*time[i]/To)*Ao
568  +0.762456*exp(-2.82833*time[i]/To)*sin(1.19361*time[i]/To)*Ao
569  -0.762456*exp(-2.82833*time[i]/To)*cos(2.38722*time[i]/To)*sin(1.19361*time[i]/To)*Ao
570  +0.762456*exp(-2.82833*time[i]/To)*cos(1.19361*time[i]/To)*sin(2.38722*time[i]/To)*Ao
571  -2.6202*exp(-2.82833*time[i]/To)*sin(1.19361*time[i]/To)*sin(2.38722*time[i]/To)*Ao
572  -0.327684*exp(-2.40318*time[i]/To)*sin(2.5928*time[i]/To)*Ao +
573  +0.327684*exp(-2.40318*time[i]/To)*cos(5.18561*time[i]/To)*sin(2.5928*time[i]/To)*Ao
574  -0.327684*exp(-2.40318*time[i]/To)*cos(2.5928*time[i]/To)*sin(5.18561*time[i]/To)*Ao
575  +0.464924*exp(-2.40318*time[i]/To)*sin(2.5928*time[i]/To)*sin(5.18561*time[i]/To)*Ao;
576 
577  if (fElectResponse[i] > max) max = fElectResponse[i];
578 
579  }// end loop over time buckets
580 
581  // ... "normalize" fElectResponse[i], before the convolution
582 
583  for (auto& element : fElectResponse) {
584  element /= max;
585  element *= fADCPerPCAtLowestASICGain * 1.60217657e-7;
586  element *= fASICGainInMVPerFC / 4.7; // relative to lowest gain setting of 4.7 mV/fC
587  }
588 
589  fNElectResp = fElectResponse.size();
590 
591  // ... write the response out to a file
592 
593  art::ServiceHandle<art::TFileService const> tfs;
594  fElectResp = tfs->make<TH1D>(
595  "ElectronicsResponse",";t (ns);Electronics Response",fNElectResp,0,fNElectResp);
596  for (unsigned int i = 0; i < fNElectResp; ++i) {
597  fElectResp->Fill(i, fElectResponse[i]);
598  }
599 
600  fElectResp->Write();
601  }
602 
603 }
604 
605 DEFINE_ART_MODULE(detsim::SimWire)
Huffman Encoding.
Definition: RawTypes.h:10
unsigned int fNSamplesReadout
number of ADC readout samples in 1 readout frame
std::string fNoiseModelChoice
choice for noise model
std::vector< TComplex > fColShape
response function for the field @ collection plane
enum raw::_compress Compress_t
std::vector< float > fIndFieldParams
induction plane field function parameterization
Energy deposited on a readout channel by simulated tracks.
Definition: SimChannel.h:145
std::vector< double > fElectResponse
response function for the electronics
TF1 * fNoiseFluct
Poisson dist for fluctuations in magnitude of noise freq components.
process_name opflash particleana ie x
TH1D * fColTimeShape
convoluted shape for field x electronics @ col plane
std::string fDriftEModuleLabel
module making the ionization electrons
int fNoiseNchToSim
number of noise channels to generate
void SetElectResponse()
response of electronics
double fADCPerPCAtLowestASICGain
ADCs/pC at lowest gain setting of 4.7 mV/fC.
pdgs p
Definition: selectors.fcl:22
unsigned int fNElectResp
number of entries from response to use
TH1D * fNoiseDist
distribution of noise counts
std::string fNoiseFluctChoice
choice for noise freq component mag fluctuations
Definition of basic raw digits.
raw::Compress_t fCompression
compression type to use
double fShapeTimeConst
time constants for exponential shaping
std::vector< std::vector< float > > fNoise
noise on each channel for each time
double fInputFieldRespSamplingPeriod
Sampling period in the input field response.
tick ticks
Alias for common language habits.
Definition: electronics.h:78
no compression
Definition: RawTypes.h:9
std::vector< float > fColFieldParams
collection plane field function parameterization
std::vector< int > fCalibRespTOffset
calib response time offset in ticks
std::vector< double > fIndFieldResponse
response function for the field @ induction plane
void GenNoise(std::vector< float > &array, CLHEP::HepRandomEngine &engine)
then echo ***************************************echo array
Definition: find_fhicl.sh:28
Signal from induction planes.
Definition: geo_types.h:145
std::vector< double > fColFieldResponse
response function for the field @ collection plane
double Charge(TDC_t tdc) const
Returns the total number of ionization electrons on this channel in the specified TDC...
Definition: SimChannel.cxx:138
std::vector< TComplex > fIndShape
response function for the field @ induction plane
std::vector< double > fNoiseFluctPar
Poisson noise fluctuations params.
MF_LOG_WARNING("SimWire")<< "SimWire is an example module that works for the "<< "MicroBooNE detector. Each experiment should implement "<< "its own version of this module to simulate electronics "<< "response."
void produce(art::Event &evt) override
Collect all the RawData header files together.
fEngine(art::ServiceHandle< rndm::NuRandomService >() ->createEngine(*this, pset,"Seed"))
tick_as<> tick
Tick number, represented by std::ptrdiff_t.
Definition: electronics.h:75
void ConvoluteResponseFunctions()
convolute electronics and field response
double fSampleRate
sampling rate in ns
void SetFieldResponse()
response of wires to field
SimWire(fhicl::ParameterSet const &pset)
TH1D * fIndFieldResp
response function for the field @ induction plane
int fNTicks
number of ticks of the clock
TH1D * fIndTimeShape
convoluted shape for field x electronics @ ind plane
std::vector< int > fFieldRespTOffset
field response time offset in ticks
Encapsulate the construction of a single detector plane.
double fASICGainInMVPerFC
actual gain setting used in mV/fC
object containing MC truth information necessary for making RawDigits and doing back tracking ...
do i e
TH1D * fElectResp
response function for the electronics
void Compress(std::vector< short > &adc, raw::Compress_t compress)
Compresses a raw data buffer.
Definition: raw.cxx:19
art::ServiceHandle< art::TFileService > tfs
TCEvent evt
Definition: DataStructs.cxx:8
CLHEP::HepRandomEngine & fEngine
Random-number engine owned by art.
double sampling_rate(DetectorClocksData const &data)
Returns the period of the TPC readout electronics clock.
TH1D * fColFieldResp
response function for the field @ collection plane
std::vector< double > fNoiseModelPar
noise model params
art framework interface to geometry description
auto const detProp
void beginJob() override