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