LArSoft  v06_85_00
Liquid Argon Software toolkit - http://larsoft.org/
SimWireT962_module.cc
Go to the documentation of this file.
1 //
3 // SimWireT962 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 SIMWIRET962_H
12 #define SIMWIRET962_H
13 
14 extern "C" {
15 #include <sys/types.h>
16 #include <sys/stat.h>
17 }
18 
19 // LArSoft includes
27 #include "lardataobj/RawData/raw.h"
31 
32 // ROOT includes
33 #include <TMath.h>
34 #include <TH1D.h>
35 #include <TFile.h>
36 #include "TComplex.h"
37 #include "TString.h"
38 #include "TH2.h"
39 
40 // C++ includes
41 #include <vector>
42 #include <string>
43 #include <algorithm>
44 #include <sstream>
45 #include <fstream>
46 #include <bitset>
47 
48 // Framework includes
52 #include "fhiclcpp/ParameterSet.h"
58 #include "cetlib/search_path.h"
59 #include "cetlib_except/exception.h"
60 
61 // art extensions
63 
64 #include "CLHEP/Random/RandFlat.h"
65 #include "CLHEP/Random/RandGaussQ.h"
66 
67 namespace art {
68  class Event;
69  class ParameterSet;
70 }
71 
72 namespace geo { class Geometry; }
73 
75 namespace detsim {
76 
77  // Base class for creation of raw signals on wires.
78  class SimWireT962 : public art::EDProducer {
79 
80  public:
81 
82  explicit SimWireT962(fhicl::ParameterSet const& pset);
83  virtual ~SimWireT962();
84 
85  // read/write access to event
86  void produce (art::Event& evt);
87  void beginJob();
88  void endJob();
89  void reconfigure(fhicl::ParameterSet const& p);
90  void beginRun(art::Run& run);
91 
92  private:
93 
94  void ConvoluteResponseFunctions();
95 
96  void SetFieldResponse();
97  void SetElectResponse();
98 
99  void GenNoise(std::vector<float>& array);
100 
102  std::string fDriftEModuleLabel;
103  std::string fResponseFile;
105 
106  double fNoiseFact;
107  double fNoiseWidth;
108  double fLowCutoff;
109  int fNTicks;
111  double fSampleRate;
113  double fInd3DCorrection;
115  double fColFieldRespAmp;
118  std::vector<double> fShapeTimeConst;
120  unsigned int fNElectResp;
121 
122  std::vector<double> fColFieldResponse;
123  std::vector<double> fIndFieldResponse;
124  std::vector<TComplex> fColShape;
125  std::vector<TComplex> fIndShape;
126  std::vector<double> fChargeWork;
127  std::vector<double> fElectResponse;
128  std::vector< std::vector<float> > fNoise;
129 
132  TH1D* fElectResp;
135  TH1D* fNoiseDist;
136 
137  }; // class SimWireT962
138 
139 }
140 
141 namespace detsim{
142 
143  //-------------------------------------------------
144  SimWireT962::SimWireT962(fhicl::ParameterSet const& pset)
145  {
146  this->reconfigure(pset);
147 
148  produces< std::vector<raw::RawDigit> >();
149 
150  fCompression = raw::kNone;
151  std::string compression(pset.get< std::string >("CompressionType"));
152  if(compression.compare("Huffman") == 0) fCompression = raw::kHuffman;
153 
154  // create a default random engine; obtain the random seed from NuRandomService,
155  // unless overridden in configuration with key "Seed"
157  ->createEngine(*this, pset, "Seed");
158  }
159 
160  //-------------------------------------------------
161  SimWireT962::~SimWireT962()
162  {
163  fColFieldResponse.clear();
164  fIndFieldResponse.clear();
165  fColShape.clear();
166  fIndShape.clear();
167  fChargeWork.clear();
168  fElectResponse.clear();
169 
170  for(unsigned int i = 0; i < fNoise.size(); ++i) fNoise[i].clear();
171  fNoise.clear();
172 
173  }
174 
175  //-------------------------------------------------
176  void SimWireT962::reconfigure(fhicl::ParameterSet const& p)
177  {
178  fResponseSet = false;
179  cet::search_path sp("FW_SEARCH_PATH");
180  if( !sp.find_file(p.get<std::string>("ResponseFile"), fResponseFile) )
181  throw cet::exception("SimWireT962") << "Unable to find electronics response file in\n"
182  << sp.to_string()
183  << "\n bailing ungracefully.\n";
184 
185  fDriftEModuleLabel= p.get< std::string >("DriftEModuleLabel");
186  fNoiseFact = p.get< double >("NoiseFact");
187  fNoiseWidth = p.get< double >("NoiseWidth");
188  fLowCutoff = p.get< double >("LowCutoff");
189  fNFieldBins = p.get< int >("FieldBins");
190  fCol3DCorrection = p.get< double >("Col3DCorrection");
191  fInd3DCorrection = p.get< double >("Ind3DCorrection");
192  fColFieldRespAmp = p.get< double >("ColFieldRespAmp");
193  fIndFieldRespAmp = p.get< double >("IndFieldRespAmp");
194  fShapeTimeConst = p.get< std::vector<double> >("ShapeTimeConst");
195 
196 
197  const detinfo::DetectorProperties* detprop = lar::providerFrom<detinfo::DetectorPropertiesService>();
198  fSampleRate = detprop->SamplingRate();
199  fTriggerOffset = detprop->TriggerOffset();
200 
201  return;
202  }
203 
204  //-------------------------------------------------
206  {
207  // get access to the TFile service
209 
210  fNoiseDist = tfs->make<TH1D>("Noise", ";Noise (ADC);", 1000, -10., 10.);
211 
213  fNTicks = fFFT->FFTSize();
214  fChargeWork.resize(fNTicks, 0.);
215 
217  fNoise.resize(geo->Nchannels());
218  // GenNoise() will further resize each channel's
219  // fNoise vector to fNTicks long.
220 
221  for(unsigned int p = 0; p < geo->Nchannels(); ++p){
222 
223  GenNoise(fNoise[p]);
224  for(int i = 0; i < fNTicks; ++i){
225  fNoiseDist->Fill(fNoise[p][i]);
226  }
227  }// end loop over wires
228 
229 
230 
231 
232 
233  return;
234 
235  }
236 
237  //-----------------------------------------------
238  void SimWireT962::beginRun(art::Run& /* run */)
239  {
240  // set field response and electronics response, then convolute them
241  SetFieldResponse();
242  SetElectResponse();
243  ConvoluteResponseFunctions();
244 
245  }
246 
247  //-------------------------------------------------
248  void SimWireT962::endJob()
249  {
250  }
251 
252  //-------------------------------------------------
253  void SimWireT962::produce(art::Event& evt)
254  {
255  //std::cout << "in SimWireT962::produce " << std::endl;
256  const detinfo::DetectorClocks* ts = lar::providerFrom<detinfo::DetectorClocksService>();
257 
258  // get the geometry to be able to figure out signal types and chan -> plane mappings
260  unsigned int signalSize = fNTicks/2;
261  // vectors for working
262  std::vector<short> adcvec(signalSize, 0);
263 
264  std::vector<const sim::SimChannel*> chanHandle;
265  evt.getView(fDriftEModuleLabel,chanHandle);
266 
267  // make a vector of const sim::SimChannel* that has same number
268  // of entries as the number of channels in the detector
269  // and set the entries for the channels that have signal on them
270  // using the chanHandle
271  std::vector<const sim::SimChannel*> channels(geo->Nchannels());
272  for(size_t c = 0; c < chanHandle.size(); ++c){
273  channels[chanHandle[c]->Channel()] = chanHandle[c];
274  }
275 
276  // make an unique_ptr of sim::SimDigits that allows ownership of the produced
277  // digits to be transferred to the art::Event after the put statement below
278  std::unique_ptr< std::vector<raw::RawDigit> > digcol(new std::vector<raw::RawDigit>);
279 
280  unsigned int chan = 0;
281  fChargeWork.clear();
282  fChargeWork.resize(fNTicks, 0.);
283 
285 
286  // Add all channels
288  CLHEP::HepRandomEngine &engine = rng->getEngine();
289  CLHEP::RandFlat flat(engine);
290 
292  for(chan = 0; chan < geo->Nchannels(); chan++) {
293 
294  fChargeWork.clear();
295  fChargeWork.resize(fNTicks, 0.);
296 
297  if( channels[chan] ){
298  // get the sim::SimChannel for this channel
299  const sim::SimChannel* sc = channels[chan];
300 
301  // loop over the tdcs and grab the number of electrons for each
302  for(size_t t = 0; t < fChargeWork.size(); ++t){
303  int tdc = ts->TPCTick2TDC(t);
304  if (tdc < 0) continue;
305  if (tdc >= int(fChargeWork.size())) continue;
306  fChargeWork[t] = sc->Charge(tdc);
307  }
308 
309  // Convolve charge with appropriate response function
310  if(geo->SignalType(chan) == geo::kInduction)
311  fFFT->Convolute(fChargeWork,fIndShape);
312  else fFFT->Convolute(fChargeWork,fColShape);
313  }
314 
315  // noise was already generated for each wire in the event
316  // raw digit vec is already in channel order
317  // pick a new "noise channel" for every channel - this makes sure
318  // the noise has the right coherent characteristics to be on one channel
319  int noisechan = TMath::Nint(flat.fire()*(1.*(fNoise.size()-1)+0.1));
320  for(unsigned int i = 0; i < signalSize; ++i){
321  adcvec[i] = (short)TMath::Nint(fNoise[noisechan][i] + fChargeWork[i]);
322  }
323 
324  // compress the adc vector using the desired compression scheme,
325  // if raw::kNone is selected nothing happens to adcvec
326  // This shrinks adcvec, if fCompression is not kNone.
327 
328 
329  raw::Compress(adcvec, fCompression);
330 
331  raw::RawDigit rd(chan, signalSize, adcvec, fCompression);
332  // Then, resize adcvec back to full length!
333  adcvec.clear();
334  adcvec.resize(signalSize,0.0);
335  // add this digit to the collection
336  digcol->push_back(rd);
337  }// end loop over channels
338 
339  evt.put(std::move(digcol));
340 
341  return;
342  }
343 
344  //-------------------------------------------------
345  void SimWireT962::ConvoluteResponseFunctions()
346  {
347  std::vector<double> col(fNTicks, 0.);
348  std::vector<double> ind(fNTicks, 0.);
349 
350  unsigned int mxbin = TMath::Min(fNTicks, (int)fNElectResp + fNFieldBins);
351 
352  double sumCol = 0.;
353  double sumInd = 0.;
354 
355  for(unsigned int i = 1; i < mxbin; ++i){
356  sumCol = 0.;
357  sumInd = 0.;
358  for(unsigned int j = 0; j < (unsigned int)fNFieldBins; ++j){
359  unsigned int k = i - j;
360  if(k == 0) break;
361  sumCol += fElectResponse[k]*fColFieldResponse[j];
362  sumInd += fElectResponse[k]*fIndFieldResponse[j];
363  }
364  col[i] = sumCol;
365  ind[i] = sumInd;
366 
367  }//end loop over bins;
368 
369  // pad out the rest of the vector with 0.
370  ind.resize(fNTicks, 0.);
371  col.resize(fNTicks, 0.);
372 
373  // write the shapes out to a file
375  fColTimeShape = tfs->make<TH1D>("ConvolutedCollection",";ticks; Electronics#timesCollection",fNTicks,0,fNTicks);
376  fIndTimeShape = tfs->make<TH1D>("ConvolutedInduction",";ticks; Electronics#timesInduction",fNTicks,0,fNTicks);
377 
378  fIndShape.resize(fNTicks/2+1);
379  fColShape.resize(fNTicks/2+1);
380 
381  // do the FFT of the shapes
382  std::vector<double> delta(fNTicks);
383  delta[0] = 1.0;
384  delta[fNTicks-1]=1.0;
385 
387  fFFT->AlignedSum(ind,delta,false);
388  fFFT->AlignedSum(col,delta,false);
389  fFFT->DoFFT(ind, fIndShape);
390  fFFT->DoFFT(col, fColShape);
391 
392  // check that you did the right thing
393  for(unsigned int i = 0; i < ind.size(); ++i){
394  fColTimeShape->Fill(i, col[i]);
395  fIndTimeShape->Fill(i, ind[i]);
396  }
397 
398  fColTimeShape->Write();
399  fIndTimeShape->Write();
400 
401 
402  return;
403  }
404 
405  //-------------------------------------------------
406  void SimWireT962::GenNoise(std::vector<float>& noise)
407  {
409  CLHEP::HepRandomEngine &engine = rng->getEngine();
410  CLHEP::RandFlat flat(engine);
411 
412  noise.clear();
413  noise.resize(fNTicks, 0.);
414  std::vector<TComplex> noiseFrequency(fNTicks/2+1, 0.);
415 
416  double pval = 0.;
417  double lofilter = 0.;
418  double phase = 0.;
419  double rnd[2] = {0.};
420 
421  // width of frequencyBin in kHz
422  double binWidth = 1.0/(fNTicks*fSampleRate*1.0e-6);
423  for(int i=0; i< fNTicks/2+1; ++i){
424  // exponential noise spectrum
425  pval = fNoiseFact*exp(-(double)i*binWidth/fNoiseWidth);
426  // low frequency cutoff
427  lofilter = 1.0/(1.0+exp(-(i-fLowCutoff/binWidth)/0.5));
428  // randomize 10%
429  flat.fireArray(2,rnd,0,1);
430  pval *= lofilter*(0.9+0.2*rnd[0]);
431  // random pahse angle
432  phase = rnd[1]*2.*TMath::Pi();
433 
434  TComplex tc(pval*cos(phase),pval*sin(phase));
435  noiseFrequency[i] += tc;
436  }
437 
438  // inverse FFT MCSignal
440  fFFT->DoInvFFT(noiseFrequency, noise);
441 
442  noiseFrequency.clear();
443 
444  // multiply each noise value by fNTicks as the InvFFT
445  // divides each bin by fNTicks assuming that a forward FFT
446  // has already been done.
447  for(unsigned int i = 0; i < noise.size(); ++i) noise[i] *= 1.*fNTicks;
448 
449  return;
450  }
451 
452  //-------------------------------------------------
453  void SimWireT962::SetFieldResponse()
454  {
455 
457 
458  double xyz1[3] = {0.};
459  double xyz2[3] = {0.};
460  double xyzl[3] = {0.};
461  // should always have at least 2 planes
462  geo->Plane(0).LocalToWorld(xyzl, xyz1);
463  geo->Plane(1).LocalToWorld(xyzl, xyz2);
464 
465  // this assumes all planes are equidistant from each other,
466  // probably not a bad assumption
467  double pitch = xyz2[0] - xyz1[0];
468 
469  fColFieldResponse.resize(fNFieldBins, 0.);
470  fIndFieldResponse.resize(fNFieldBins, 0.);
471 
472  // set the response for the collection plane first
473  // the first entry is 0
474 
475  // write out the response functions to the file
476  // get access to the TFile service
478  fIndFieldResp = tfs->make<TH1D>("InductionFieldResponse",";t (ns);Induction Response",fNTicks,0,fNTicks);
479  fColFieldResp = tfs->make<TH1D>("CollectionFieldResponse",";t (ns);Collection Response",fNTicks,0,fNTicks);
480  const detinfo::DetectorProperties* detprop = lar::providerFrom<detinfo::DetectorPropertiesService>();
481  double driftvelocity=detprop->DriftVelocity(detprop->Efield(),detprop->Temperature())/1000.;
482  int nbinc = TMath::Nint(fCol3DCorrection*(std::abs(pitch))/(driftvelocity*fSampleRate));
483 
484  double integral = 0.;
485  for(int i = 1; i < nbinc; ++i){
486  fColFieldResponse[i] = fColFieldResponse[i-1] + 1.0;
487  integral += fColFieldResponse[i];
488  }
489 
490  for(int i = 0; i < nbinc; ++i){
491  fColFieldResponse[i] *= fColFieldRespAmp/integral;
492  fColFieldResp->Fill(i, fColFieldResponse[i]);
493  }
494 
496 
497  int nbini = TMath::Nint(fInd3DCorrection*(std::abs(pitch))/(driftvelocity*fSampleRate));//KP
498  for(int i = 0; i < nbini; ++i){
499  fIndFieldResponse[i] = fIndFieldRespAmp/(1.*nbini);
500  fIndFieldResponse[nbini+i] = -fIndFieldRespAmp/(1.*nbini);
501 
502  fIndFieldResp->Fill(i, fIndFieldResponse[i]);
503  fIndFieldResp->Fill(nbini+i, fIndFieldResponse[nbini+i]);
504 
505  }
506 
507  fColFieldResp->Write();
508  fIndFieldResp->Write();
509 
510  return;
511  }
512 
513  //-------------------------------------------------
514  void SimWireT962::SetElectResponse()
515  {
516 
518 
519  fElectResponse.resize(fNTicks, 0.);
520  std::vector<double> time(fNTicks,0.);
521 
522  TFile inFile(fResponseFile.c_str(),"READ");
523  if(inFile.IsZombie()){
524  throw cet::exception("SimWireT962") << "Cannot open response file" << fResponseFile << "\n";
525  }
526 
527  TH1D * shape = (TH1D*)inFile.Get("shape");
528  int ctr = 0;
529  double integral = 0.;
530  double holder = 0;
531 
532  while(ctr < fNTicks){
533  holder = shape->GetBinContent(ctr+1);
534  fElectResponse[ctr] = holder;
535  time[ctr] = ctr*fSampleRate;
536  if(holder> 0.){
537  integral += holder;
538  }
539 
540  ++ctr;
541  }//end loop over input
542 
543  for(unsigned int i = 0; i < fElectResponse.size(); ++i)
544  fElectResponse[i] /= integral;
545 
546  fNElectResp = fElectResponse.size();
547 
548  // write the response out to a file
550  fElectResp = tfs->make<TH1D>("ElectronicsResponse",";t (ns);Electronics Response",fNElectResp,0,fNElectResp);
551  for(unsigned int i = 0; i < fNElectResp; ++i){
552  fElectResp->Fill(i, fElectResponse[i]);
553  }
554 
555  fElectResp->Write();
556 
557  return;
558  }
559 
560 }
561 
562 namespace detsim{
563 
565 
566 }
567 
568 #endif // SIMWIRET962_H
Huffman Encoding.
Definition: RawTypes.h:10
unsigned int fNElectResp
number of entries from response to use
double fSampleRate
sampling rate in ns
TH1D * fIndFieldResp
response function for the field @ induction 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 > fColFieldResponse
response function for the field @ collection plane
Encapsulate the construction of a single cyostat.
std::vector< TComplex > fColShape
response function for the field @ collection plane
intermediate_table::iterator iterator
TH1D * fNoiseDist
distribution of noise counts
Detector simulation of raw signals on wires.
std::vector< std::vector< float > > fNoise
noise on each channel for each time
Definition of basic raw digits.
void DoFFT(std::vector< T > &input, std::vector< TComplex > &output)
Definition: LArFFT.h:97
no compression
Definition: RawTypes.h:9
raw::Compress_t fCompression
compression type to use
Definition: Run.h:30
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
int fTriggerOffset
(units of ticks) time of expected neutrino event
std::size_t getView(std::string const &moduleLabel, std::string const &productInstanceName, std::vector< ELEMENT const * > &result) const
Definition: DataViewImpl.h:474
base_engine_t & getEngine() const
std::string fResponseFile
response file for induction planes
int FFTSize() const
Definition: LArFFT.h:69
std::vector< double > fShapeTimeConst
time constants for exponential shaping
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
int fNTicks
number of ticks of the clock
void beginJob()
Definition: Breakpoints.cc:14
Signal from induction planes.
Definition: geo_types.h:92
std::string fDriftEModuleLabel
module making the ionization electrons
double Charge(TDC_t tdc) const
Returns the total number of ionization electrons on this channel in the specified TDC...
Definition: SimChannel.cxx:132
int fNFieldBins
number of bins for field response
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
std::vector< double > fElectResponse
response function for the electronics
double fIndFieldRespAmp
amplitude of response to field
void Convolute(std::vector< T > &input, std::vector< T > &respFunc)
Definition: LArFFT.h:172
bool fResponseSet
flag of whether to set the response functions or not
An art service to assist in the distribution of guaranteed unique seeds to all engines within an art ...
double fLowCutoff
low frequency filter cutoff (kHz)
Conversion of times between different formats and references.
TH1D * fColTimeShape
convoluted shape for field x electronics @ col plane
T * make(ARGS...args) const
std::vector< double > fChargeWork
virtual double TPCTick2TDC(double tick) const =0
Converts a TPC time tick into a electronics time tick.
Encapsulate the construction of a single detector plane.
TH1D * fColFieldResp
response function for the field @ collection 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
std::vector< double > fIndFieldResponse
response function for the field @ induction plane
object containing MC truth information necessary for making RawDigits and doing back tracking ...
HLT enums.
void Compress(std::vector< short > &adc, raw::Compress_t compress)
Compresses a raw data buffer.
Definition: raw.cxx:20
TH1D * fIndTimeShape
convoluted shape for field x electronics @ ind plane
Namespace collecting geometry-related classes utilities.
Tools and modules for checking out the basics of the Monte Carlo.
double fNoiseWidth
exponential noise width (kHz)
void LocalToWorld(const double *plane, double *world) const
Transform point from local plane frame to world frame.
Definition: PlaneGeo.h:1124
double fNoiseFact
noise scale factor
art framework interface to geometry description
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33
vec_iX clear()
Encapsulate the construction of a single detector plane.
TH1D * fElectResp
response function for the electronics