LArSoft  v06_85_00
Liquid Argon Software toolkit - http://larsoft.org/
SimWire_module.cc
Go to the documentation of this file.
1 //
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 //
11 #ifndef SIMWIRE_H
12 #define SIMWIRE_H
13 
14 extern "C" {
15 #include <sys/types.h>
16 #include <sys/stat.h>
17 }
18 
19 // ROOT includes
20 #include <TMath.h>
21 #include <TH1D.h>
22 #include <TFile.h>
23 #include "TComplex.h"
24 #include "TString.h"
25 #include "TH2.h"
26 
27 // C++ includes
28 #include <algorithm>
29 #include <sstream>
30 #include <fstream>
31 #include <bitset>
32 #include <vector>
33 #include <string>
34 
35 
36 // Framework includes
39 #include "fhiclcpp/ParameterSet.h"
46 #include "cetlib/search_path.h"
47 
48 // art extensions
50 
51 #include "CLHEP/Random/RandFlat.h"
52 #include "CLHEP/Random/RandGaussQ.h"
53 
54 // LArSoft includes
62 #include "lardataobj/RawData/raw.h"
65 
66 namespace art {
67  class Event;
68  class ParameterSet;
69 }
70 
71 namespace geo { class Geometry; }
72 
74 namespace detsim {
75 
76  // Base class for creation of raw signals on wires.
77  class SimWire : public art::EDProducer {
78 
79  public:
80 
81  explicit SimWire(fhicl::ParameterSet const& pset);
82  virtual ~SimWire();
83 
84  // read/write access to event
85  void produce (art::Event& evt);
86  void beginJob();
87  void endJob();
88  void reconfigure(fhicl::ParameterSet const& p);
89 
90  private:
91 
92  void ConvoluteResponseFunctions();
93 
94  void SetFieldResponse();
95  void SetElectResponse();
96 
97  void GenNoise(std::vector<float>& array);
98 
99  bool fResponseSet;
100  std::string fDriftEModuleLabel;
101  std::string fResponseFile;
103 
104  double fNoiseFact;
105  double fNoiseWidth;
106  double fLowCutoff;
107  int fNTicks;
109  double fSampleRate;
110  unsigned int fNSamplesReadout;
112  double fInd3DCorrection;
114  double fColFieldRespAmp;
117  std::vector<double> fShapeTimeConst;
119  unsigned int fNElectResp;
120 
121  std::vector<double> fColFieldResponse;
122  std::vector<double> fIndFieldResponse;
123  std::vector<TComplex> fColShape;
124  std::vector<TComplex> fIndShape;
125  std::vector<double> fChargeWork;
126  std::vector<double> fElectResponse;
127  std::vector< std::vector<float> > fNoise;
128 
131  TH1D* fElectResp;
134  TH1D* fNoiseDist;
135 
136  }; // class SimWire
137 
138 }
139 
140 namespace detsim{
141 
142  //-------------------------------------------------
143  SimWire::SimWire(fhicl::ParameterSet const& pset)
144  {
145  this->reconfigure(pset);
146 
147  produces< std::vector<raw::RawDigit> >();
148 
149  fCompression = raw::kNone;
150  std::string compression(pset.get< std::string >("CompressionType"));
151  if(compression.compare("Huffman") == 0) fCompression = raw::kHuffman;
152 
153  // create a default random engine; obtain the random seed from NuRandomService,
154  // unless overridden in configuration with key "Seed"
156  ->createEngine(*this, pset, "Seed");
157  }
158 
159  //-------------------------------------------------
160  SimWire::~SimWire()
161  {
162  fColFieldResponse.clear();
163  fIndFieldResponse.clear();
164  fColShape.clear();
165  fIndShape.clear();
166  fChargeWork.clear();
167  fElectResponse.clear();
168 
169  for(unsigned int i = 0; i < fNoise.size(); ++i) fNoise[i].clear();
170  fNoise.clear();
171 
172  LOG_WARNING("SimWire") << "SimWire is an example module that works for the "
173  << "MicroBooNE detector. Each experiment should implement "
174  << "its own version of this module to simulate electronics "
175  << "response.";
176 
177  }
178 
179  //-------------------------------------------------
180  void SimWire::reconfigure(fhicl::ParameterSet const& p)
181  {
182  std::string fResponseFile = p.get<std::string>("ResponseFile", "");
183 
184  fResponseSet = !fResponseFile.empty();
185  if (fResponseSet) {
186  cet::search_path sp("FW_SEARCH_PATH");
187  sp.find_file(p.get<std::string>("ResponseFile"), fResponseFile);
188  }
189  else fResponseFile.clear();
190  fDriftEModuleLabel= p.get< std::string >("DriftEModuleLabel");
191  fNoiseFact = p.get< double >("NoiseFact");
192  fNoiseWidth = p.get< double >("NoiseWidth");
193  fLowCutoff = p.get< double >("LowCutoff");
194  fNFieldBins = p.get< int >("FieldBins");
195  fCol3DCorrection = p.get< double >("Col3DCorrection");
196  fInd3DCorrection = p.get< double >("Ind3DCorrection");
197  fColFieldRespAmp = p.get< double >("ColFieldRespAmp");
198  fIndFieldRespAmp = p.get< double >("IndFieldRespAmp");
199  fShapeTimeConst = p.get< std::vector<double> >("ShapeTimeConst");
200 
201  const detinfo::DetectorProperties* detprop = lar::providerFrom<detinfo::DetectorPropertiesService>();
202  fSampleRate = detprop->SamplingRate();
203  fTriggerOffset = detprop->TriggerOffset();
204  fNSamplesReadout = detprop->NumberTimeSamples();
205 
206  return;
207  }
208 
209  //-------------------------------------------------
211  {
212  // get access to the TFile service
214 
215  fNoiseDist = tfs->make<TH1D>("Noise", ";Noise (ADC);", 1000, -10., 10.);
216 
218  fNTicks = fFFT->FFTSize();
219  fChargeWork.resize(fNTicks, 0.);
220 
221  // Note the magic 100 here. Argo and uBooNe use NChannels.
222  fNoise.resize(100);
223  // GenNoise() will further resize each channel's
224  // fNoise vector to fNTicks long.
225 
226  for(int p = 0; p < 100; ++p){
227  GenNoise(fNoise[p]);
228  for(int i = 0; i < fNTicks; ++i){
229  fNoiseDist->Fill(fNoise[p][i]);
230  }
231  }//end loop over wires
232 
234  SetFieldResponse();
235  SetElectResponse();
236  ConvoluteResponseFunctions();
237 
238 
239  return;
240 
241  }
242 
243  //-------------------------------------------------
244  void SimWire::endJob()
245  {
246  }
247 
248  //-------------------------------------------------
249  void SimWire::produce(art::Event& evt)
250  {
251 
252  //std::cout << "in SimWire::produce " << std::endl;
253 
254  // get the geometry to be able to figure out signal types and chan -> plane mappings
256  unsigned int signalSize = fNTicks;
257  // vectors for working
258  std::vector<short> adcvec(signalSize, 0);
259 
260  std::vector<const sim::SimChannel*> chanHandle;
261  evt.getView(fDriftEModuleLabel,chanHandle);
262 
263  // make a vector of const sim::SimChannel* that has same number
264  // of entries as the number of channels in the detector
265  // and set the entries for the channels that have signal on them
266  // using the chanHandle
267  std::vector<const sim::SimChannel*> channels(geo->Nchannels());
268  for(size_t c = 0; c < chanHandle.size(); ++c){
269  channels[chanHandle[c]->Channel()] = chanHandle[c];
270  }
271 
272  // make an unique_ptr of sim::SimDigits that allows ownership of the produced
273  // digits to be transferred to the art::Event after the put statement below
274  std::unique_ptr< std::vector<raw::RawDigit> > digcol(new std::vector<raw::RawDigit>);
275 
276  unsigned int chan = 0;
277  fChargeWork.clear();
278  fChargeWork.resize(fNTicks, 0.);
279 
281 
282  // Add all channels
284  CLHEP::HepRandomEngine &engine = rng->getEngine();
285  CLHEP::RandFlat flat(engine);
286 
288  for(chan = 0; chan < geo->Nchannels(); chan++) {
289  // std::cout << "on channel " << chan << std::endl;
290 
291  fChargeWork.clear();
292  fChargeWork.resize(fNTicks, 0.);
293 
294  if( channels[chan] ){
295 
296  // get the sim::SimChannel for this channel
297  const sim::SimChannel* sc = channels[chan];
298 
299  // loop over the tdcs and grab the number of electrons for each
300  for(size_t t = 0; t < fChargeWork.size(); ++t)
301  fChargeWork[t] = sc->Charge(t);
302 
303  //Convolve charge with appropriate response function
304  if(geo->SignalType(chan) == geo::kInduction)
305  fFFT->Convolute(fChargeWork,fIndShape);
306  else fFFT->Convolute(fChargeWork,fColShape);
307  }
308 
309  // noise was already generated for each wire in the event
310  // raw digit vec is already in channel order
311  // pick a new "noise channel" for every channel - this makes sure
312  // the noise has the right coherent characteristics to be on one channel
313  int noisechan = TMath::Nint(flat.fire()*(1.*(fNoise.size()-1)+0.1));
314  for(unsigned int i = 0; i < signalSize; ++i){
315  adcvec[i] = (short)TMath::Nint(fNoise[noisechan][i] + fChargeWork[i]);
316  }
317  adcvec.resize(fNSamplesReadout);
318 
319  // compress the adc vector using the desired compression scheme,
320  // if raw::kNone is selected nothing happens to adcvec
321  // This shrinks adcvec, if fCompression is not kNone.
322 
323  raw::Compress(adcvec, fCompression);
324 
325  raw::RawDigit rd(chan, signalSize, adcvec, fCompression);
326  // Then, resize adcvec back to full length!
327  adcvec.clear();
328  adcvec.resize(signalSize,0.0);
329 
330  // add this digit to the collection
331  digcol->push_back(rd);
332  }//end loop over channels
333 
334  evt.put(std::move(digcol));
335 
336  return;
337  }
338 
339  //-------------------------------------------------
340  void SimWire::ConvoluteResponseFunctions()
341  {
342  std::vector<double> col(fNTicks, 0.);
343  std::vector<double> ind(fNTicks, 0.);
344 
345  unsigned int mxbin = TMath::Min(fNTicks, (int)fNElectResp + fNFieldBins);
346 
347  double sumCol = 0.;
348  double sumInd = 0.;
349 
350  for(unsigned int i = 1; i < mxbin; ++i){
351  sumCol = 0.;
352  sumInd = 0.;
353  for(unsigned int j = 0; j < (unsigned int)fNFieldBins; ++j){
354  unsigned int k = i - j;
355  if(k == 0) break;
356  sumCol += fElectResponse[k]*fColFieldResponse[j];
357  sumInd += fElectResponse[k]*fIndFieldResponse[j];
358  }
359  col[i] = sumCol;
360  ind[i] = sumInd;
361 
362  }//end loop over bins;
363 
365  ind.resize(fNTicks, 0.);
366  col.resize(fNTicks, 0.);
367 
368  // write the shapes out to a file
370  fColTimeShape = tfs->make<TH1D>("ConvolutedCollection",";ticks; Electronics#timesCollection",fNTicks,0,fNTicks);
371  fIndTimeShape = tfs->make<TH1D>("ConvolutedInduction",";ticks; Electronics#timesInduction",fNTicks,0,fNTicks);
372 
373  fIndShape.resize(fNTicks/2+1);
374  fColShape.resize(fNTicks/2+1);
375 
377  std::vector<double> delta(fNTicks);
378  delta[0] = 1.0;
379  delta[fNTicks-1]=1.0;
380 
382  fFFT->AlignedSum(ind,delta,false);
383  fFFT->AlignedSum(col,delta,false);
384  fFFT->DoFFT(ind, fIndShape);
385  fFFT->DoFFT(col, fColShape);
386 
388  for(unsigned int i = 0; i < ind.size(); ++i){
389  fColTimeShape->Fill(i, col[i]);
390  fIndTimeShape->Fill(i, ind[i]);
391  }
392 
393  fColTimeShape->Write();
394  fIndTimeShape->Write();
395 
396 
397  return;
398  }
399 
400  //-------------------------------------------------
401  void SimWire::GenNoise(std::vector<float>& noise)
402  {
404  CLHEP::HepRandomEngine &engine = rng->getEngine();
405  CLHEP::RandFlat flat(engine);
406 
407  noise.clear();
408  noise.resize(fNTicks, 0.);
409  std::vector<TComplex> noiseFrequency(fNTicks/2+1, 0.);
410 
411  double pval = 0.;
412  double lofilter = 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  for(int i=0; i< fNTicks/2+1; ++i){
419  //exponential noise spectrum
420  pval = fNoiseFact*exp(-(double)i*binWidth/fNoiseWidth);
421  //low frequency cutoff
422  lofilter = 1.0/(1.0+exp(-(i-fLowCutoff/binWidth)/0.5));
423  //randomize 10%
424  flat.fireArray(2,rnd,0,1);
425  pval *= lofilter*(0.9+0.2*rnd[0]);
426  //random pahse angle
427  phase = rnd[1]*2.*TMath::Pi();
428 
429  TComplex tc(pval*cos(phase),pval*sin(phase));
430  noiseFrequency[i] += tc;
431  }
432 
433  //std::cout << "filled noise freq" << std::endl;
434 
435  //inverse FFT MCSignal
437  fFFT->DoInvFFT(noiseFrequency, noise);
438 
439  noiseFrequency.clear();
440 
444  for(unsigned int i = 0; i < noise.size(); ++i) noise[i] *= 1.*fNTicks;
445 
446  return;
447  }
448 
449  //-------------------------------------------------
450  void SimWire::SetFieldResponse()
451  {
452 
453  // std::cerr << "SetFieldResponse" << std::endl;
454 
456 
457  double xyz1[3] = {0.};
458  double xyz2[3] = {0.};
459  double xyzl[3] = {0.};
461  geo->Plane(0).LocalToWorld(xyzl, xyz1);
462  geo->Plane(1).LocalToWorld(xyzl, xyz2);
463 
466  double pitch = xyz2[0] - xyz1[0];
467 
468  fColFieldResponse.resize(fNFieldBins, 0.);
469  fIndFieldResponse.resize(fNFieldBins, 0.);
470 
473 
474  // write out the response functions to the file
475  // get access to the TFile service
477  fIndFieldResp = tfs->make<TH1D>("InductionFieldResponse",";t (ns);Induction Response",fNTicks,0,fNTicks);
478  fColFieldResp = tfs->make<TH1D>("CollectionFieldResponse",";t (ns);Collection Response",fNTicks,0,fNTicks);
479  const detinfo::DetectorProperties* detprop = lar::providerFrom<detinfo::DetectorPropertiesService>();
480  double driftvelocity=detprop->DriftVelocity(detprop->Efield(),detprop->Temperature())/1000.;
481  int nbinc = TMath::Nint(fCol3DCorrection*(std::abs(pitch))/(driftvelocity*fSampleRate));
482 
483  double integral = 0.;
484  for(int i = 1; i < nbinc; ++i){
485  fColFieldResponse[i] = fColFieldResponse[i-1] + 1.0;
486  integral += fColFieldResponse[i];
487  }
488 
489  for(int i = 0; i < nbinc; ++i){
490  fColFieldResponse[i] *= fColFieldRespAmp/integral;
491  fColFieldResp->Fill(i, fColFieldResponse[i]);
492  }
493 
495 
496  int nbini = TMath::Nint(fInd3DCorrection*(std::abs(pitch))/(driftvelocity*fSampleRate));//KP
497  for(int i = 0; i < nbini; ++i){
498  fIndFieldResponse[i] = fIndFieldRespAmp/(1.*nbini);
499  fIndFieldResponse[nbini+i] = -fIndFieldRespAmp/(1.*nbini);
500 
501  fIndFieldResp->Fill(i, fIndFieldResponse[i]);
502  fIndFieldResp->Fill(nbini+i, fIndFieldResponse[nbini+i]);
503 
504  }
505 
506  fColFieldResp->Write();
507  fIndFieldResp->Write();
508 
509  return;
510  }
511 
512  //-------------------------------------------------
513  void SimWire::SetElectResponse()
514  {
515 
516  // std::cerr << "SetElectResponse" << std::endl;
517 
519 
520  fElectResponse.resize(fNTicks, 0.);
521  std::vector<double> time(fNTicks,0.);
522 
523  double norm = fShapeTimeConst[1]*TMath::Pi();
524  norm /= sin(fShapeTimeConst[1]*TMath::Pi()/fShapeTimeConst[0])/fSampleRate;
525 
526  double peak = 0.;
527 
528  for(int i = 0; i < fNTicks; ++i){
529  time[i] = (1.*i - 0.33333*fNTicks)*fSampleRate;
530 
531  // The 120000 is an arbitrary scaling to get displays for microboone
532  fElectResponse[i] = 120000.0*exp(-time[i]/fShapeTimeConst[0])/(1. + exp(-time[i]/fShapeTimeConst[1]))/norm;
533 
534  if(fElectResponse[i] > peak){
535  peak = fElectResponse[i];
536  }
537  }
538 
540  peak *= 0.01;
541  std::vector<double>::iterator eitr = fElectResponse.begin();
542  std::vector<double>::iterator titr = time.begin();
543  while(eitr != fElectResponse.end()){
544  if(*eitr < peak){
545  fElectResponse.erase(eitr);
546  time.erase(titr);
547 
548  }
549  else{
550  ++eitr;
551  ++titr;
552  }
553  }//end loop to remove low response values
554 
555  fNElectResp = fElectResponse.size();
556 
557  // write the response out to a file
559  fElectResp = tfs->make<TH1D>("ElectronicsResponse",";t (ns);Electronics Response",fNElectResp,0,fNElectResp);
560  for(unsigned int i = 0; i < fNElectResp; ++i){
561  //mf::LogInfo("SimWire") <<"checking ElectResponse: i= "<< i << " time[i]= " << time[i] << " fElectResponse[i]= " << fElectResponse[i];
562  fElectResp->Fill(i, fElectResponse[i]);
563  }
564 
565  fElectResp->Write();
566 
567  return;
568  }
569 
570 }
571 
572 namespace detsim{
573 
575 
576 }
577 
578 #endif // SIMWIRE_H
579 
580 
Huffman Encoding.
Definition: RawTypes.h:10
double fIndFieldRespAmp
amplitude of response to field
unsigned int fNSamplesReadout
number of ADC readout samples in 1 readout frame
std::vector< TComplex > fColShape
response function for the field @ collection plane
enum raw::_compress Compress_t
PlaneGeo const & Plane(unsigned int const p, unsigned int const tpc=0, unsigned int const cstat=0) const
Returns the specified wire.
Collection of charge vs time digitized from a single readout channel.
Definition: RawDigit.h:68
Energy deposited on a readout channel by simulated tracks.
Definition: SimChannel.h:143
std::vector< double > fElectResponse
response function for the electronics
Encapsulate the construction of a single cyostat.
TH1D * fColTimeShape
convoluted shape for field x electronics @ col plane
std::string fDriftEModuleLabel
module making the ionization electrons
intermediate_table::iterator iterator
unsigned int fNElectResp
number of entries from response to use
TH1D * fNoiseDist
distribution of noise counts
Detector simulation of raw signals on wires.
Definition of basic raw digits.
raw::Compress_t fCompression
compression type to use
void DoFFT(std::vector< T > &input, std::vector< TComplex > &output)
Definition: LArFFT.h:97
SigType_t SignalType(geo::PlaneID const &pid) const
Returns the type of signal on the channels of specified TPC plane.
no compression
Definition: RawTypes.h:9
int fTriggerOffset
(units of ticks) time of expected neutrino event
void DoInvFFT(std::vector< TComplex > &input, std::vector< T > &output)
Definition: LArFFT.h:119
unsigned int Nchannels() const
Returns the number of TPC readout channels in the detector.
unsigned int noise()
Definition: chem4.cc:265
ProductID put(std::unique_ptr< PROD > &&product)
Definition: Event.h:102
std::size_t getView(std::string const &moduleLabel, std::string const &productInstanceName, std::vector< ELEMENT const * > &result) const
Definition: DataViewImpl.h:474
bool fResponseSet
flag of whether to set the response functions or not
std::vector< double > fIndFieldResponse
response function for the field @ induction plane
base_engine_t & getEngine() const
int FFTSize() const
Definition: LArFFT.h:69
std::vector< double > fChargeWork
auto array(Array const &a)
Returns a manipulator which will print the specified array.
Definition: DumpUtils.h:228
#define DEFINE_ART_MODULE(klass)
Definition: ModuleMacros.h:42
void beginJob()
Definition: Breakpoints.cc:14
Signal from induction planes.
Definition: geo_types.h:92
std::vector< double > fColFieldResponse
response function for the field @ collection plane
std::vector< std::vector< float > > fNoise
noise on each channel for each time
double Charge(TDC_t tdc) const
Returns the total number of ionization electrons on this channel in the specified TDC...
Definition: SimChannel.cxx:132
std::vector< TComplex > fIndShape
response function for the field @ induction plane
Collect all the RawData header files together.
T get(std::string const &key) const
Definition: ParameterSet.h:231
Int_t col[ntarg]
Definition: Style.C:29
void Convolute(std::vector< T > &input, std::vector< T > &respFunc)
Definition: LArFFT.h:172
double fSampleRate
sampling rate in ns
An art service to assist in the distribution of guaranteed unique seeds to all engines within an art ...
#define LOG_WARNING(category)
double fLowCutoff
low frequency filter cutoff (kHz)
TH1D * fIndFieldResp
response function for the field @ induction plane
int fNTicks
number of ticks of the clock
std::string fResponseFile
response file for induction planes
T * make(ARGS...args) const
TH1D * fIndTimeShape
convoluted shape for field x electronics @ ind plane
Float_t norm
Encapsulate the construction of a single detector plane.
void AlignedSum(std::vector< T > &input, std::vector< T > &output, bool add=true)
Definition: LArFFT.h:243
virtual double DriftVelocity(double efield=0., double temperature=0.) const =0
double fNoiseWidth
exponential noise width (kHz)
object containing MC truth information necessary for making RawDigits and doing back tracking ...
TH1D * fElectResp
response function for the electronics
HLT enums.
void Compress(std::vector< short > &adc, raw::Compress_t compress)
Compresses a raw data buffer.
Definition: raw.cxx:20
int fNFieldBins
number of bins for field response
double fNoiseFact
noise scale factor
Namespace collecting geometry-related classes utilities.
TH1D * fColFieldResp
response function for the field @ collection plane
std::vector< double > fShapeTimeConst
time constants for exponential shaping
Tools and modules for checking out the basics of the Monte Carlo.
void LocalToWorld(const double *plane, double *world) const
Transform point from local plane frame to world frame.
Definition: PlaneGeo.h:1124
art framework interface to geometry description
vec_iX clear()
Encapsulate the construction of a single detector plane.