All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
SignalShapingServiceSBND_service.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 /// \file SignalShapingServiceSBND_service.cc
3 /// \author H. Greenlee (adapted to LArIAT by A. Szelc)
4 ////////////////////////////////////////////////////////////////////////
5 
7 #include "art/Framework/Services/Registry/ServiceHandle.h"
8 #include "art/Framework/Services/Registry/ServiceDefinitionMacros.h"
9 #include "messagefacility/MessageLogger/MessageLogger.h"
10 #include "cetlib_except/exception.h"
17 #include "TFile.h"
18 
19 //----------------------------------------------------------------------
20 // Constructor.
22  art::ActivityRegistry& /* reg */)
23  : fInit(false)
24 {
25  reconfigure(pset);
26 }
27 
28 
29 //----------------------------------------------------------------------
30 // Destructor.
32 {}
33 
34 
35 //----------------------------------------------------------------------
36 // Reconfigure method.
37 void util::SignalShapingServiceSBND::reconfigure(const fhicl::ParameterSet& pset)
38 {
39  // Reset initialization flag.
40 
41  fInit = false;
42 
43  // Reset kernels.
44 
45  fColSignalShaping.Reset();
46  fIndUSignalShaping.Reset();
47  fIndVSignalShaping.Reset();
48 
49  // Fetch fcl parameters.
50 
51  fDeconNorm = pset.get<double>("DeconNorm");
52  fADCPerPCAtLowestASICGain = pset.get<double>("ADCPerPCAtLowestASICGain");
53  fASICGainInMVPerFC = pset.get<std::vector<double> >("ASICGainInMVPerFC");
54 
55  fNFieldBins = pset.get<int>("FieldBins");
56  fCol3DCorrection = pset.get<double>("Col3DCorrection");
57  fInd3DCorrection = pset.get<double>("Ind3DCorrection");
58  fColFieldRespAmp = pset.get<double>("ColFieldRespAmp");
59  fIndUFieldRespAmp = pset.get<double>("IndUFieldRespAmp");
60  fIndVFieldRespAmp = pset.get<double>("IndVFieldRespAmp");
61  fShapeTimeConst = pset.get<std::vector<double> >("ShapeTimeConst");
62  fNoiseFactVec = pset.get<std::vector<DoubleVec> >("NoiseFactVec");
63 
64  fInputFieldRespSamplingPeriod = pset.get<double>("InputFieldRespSamplingPeriod");
65  fFieldResponseTOffset = pset.get<std::vector<double> >("FieldResponseTOffset");
66 
67  fUseFunctionFieldShape= pset.get<bool>("UseFunctionFieldShape");
68  fUseSimpleFieldShape = pset.get<bool>("UseSimpleFieldShape");
69  fUseHistogramFieldShape = pset.get<bool>("UseHistogramFieldShape");
70 
71  if(fUseSimpleFieldShape) {
72  fNFieldBins = 300;
73  }
74  fGetFilterFromHisto= pset.get<bool>("GetFilterFromHisto");
75 
76  // Construct parameterized collection filter function.
77  if(!fGetFilterFromHisto) {
78 
79  mf::LogInfo("SignalShapingServiceSBND") << "Getting Filter from .fcl file" ;
80  std::string colFilt = pset.get<std::string>("ColFilter");
81  std::vector<double> colFiltParams = pset.get<std::vector<double> >("ColFilterParams");
82  fColFilterFunc = new TF1("colFilter", colFilt.c_str());
83  for(unsigned int i=0; i<colFiltParams.size(); ++i)
84  fColFilterFunc->SetParameter(i, colFiltParams[i]);
85 
86  // Construct parameterized induction filter function.
87 
88  std::string indUFilt = pset.get<std::string>("IndUFilter");
89  std::vector<double> indUFiltParams = pset.get<std::vector<double> >("IndUFilterParams");
90  fIndUFilterFunc = new TF1("indUFilter", indUFilt.c_str());
91  for(unsigned int i=0; i<indUFiltParams.size(); ++i)
92  fIndUFilterFunc->SetParameter(i, indUFiltParams[i]);
93 
94  std::string indVFilt = pset.get<std::string>("IndVFilter");
95  std::vector<double> indVFiltParams = pset.get<std::vector<double> >("IndVFilterParams");
96  fIndVFilterFunc = new TF1("indVFilter", indVFilt.c_str());
97  for(unsigned int i=0; i<indVFiltParams.size(); ++i)
98  fIndVFilterFunc->SetParameter(i, indVFiltParams[i]);
99  } else {
100  constexpr unsigned int NPlanes = 3;
101 
102  std::string histoname = pset.get<std::string>("FilterHistoName");
103  mf::LogInfo("SignalShapingServiceSBND") << " using filter from .root file " ;
104 
105  // constructor decides if initialized value is a path or an environment variable
106  std::string fname;
107  cet::search_path sp("FW_SEARCH_PATH");
108  auto requestedFilterFunctionPath = pset.get<std::string>("FilterFunctionFname");
109  if (!sp.find_file(requestedFilterFunctionPath, fname)) {
110  throw art::Exception(art::errors::Configuration)
111  << "Filter function file '" << requestedFilterFunctionPath
112  << "' not found in FW_SEARCH_PATH";
113  }
114 
115  TFile in(fname.c_str(), "READ");
116  if (!in.IsOpen()) {
117  throw cet::exception("SignalShapingServiceSBND")
118  << "Can't open filter function file '" << fname << "'!\n";
119  }
120  mf::LogInfo("SignalShapingServiceSBND")
121  << "Reading filter histograms from '" << fname << "'";
122  for(unsigned int i = 0; i < NPlanes; ++i) {
123  auto pHist = dynamic_cast<TH1*>(in.Get(Form(histoname.c_str(),i)));
124  if (!pHist) {
125  // this happens also if there is an object but it's not a TH1
126  throw cet::exception("SignalShapingServiceSBND")
127  << "Can't find filter histogram '" << histoname << "' for plane #" << i
128  << " in '" << fname << "'!\n";
129  }
130  pHist->SetDirectory(nullptr); // detach the histogram from its source file
131  fFilterHist[i] = pHist;
132  }
133  in.Close();
134  }
135 
136  /////////////////////////////////////
137  if(fUseFunctionFieldShape) {
138 
139  std::string colField = pset.get<std::string>("ColFieldShape");
140  std::vector<double> colFieldParams = pset.get<std::vector<double> >("ColFieldParams");
141  fColFieldFunc = new TF1("colField", colField.c_str());
142  for(unsigned int i=0; i<colFieldParams.size(); ++i)
143  fColFieldFunc->SetParameter(i, colFieldParams[i]);
144 
145  // Construct parameterized induction filter function.
146 
147  std::string indUField = pset.get<std::string>("IndUFieldShape");
148  std::vector<double> indUFieldParams = pset.get<std::vector<double> >("IndUFieldParams");
149  fIndUFieldFunc = new TF1("indUField", indUField.c_str());
150  for(unsigned int i=0; i<indUFieldParams.size(); ++i)
151  fIndUFieldFunc->SetParameter(i, indUFieldParams[i]);
152  // Warning, last parameter needs to be multiplied by the FFTSize, in current version of the code,
153 
154  std::string indVField = pset.get<std::string>("IndVFieldShape");
155  std::vector<double> indVFieldParams = pset.get<std::vector<double> >("IndVFieldParams");
156  fIndVFieldFunc = new TF1("indVField", indVField.c_str());
157  for(unsigned int i=0; i<indVFieldParams.size(); ++i)
158  fIndVFieldFunc->SetParameter(i, indVFieldParams[i]);
159  // Warning, last parameter needs to be multiplied by the FFTSize, in current version of the code,
160 
161  } else if (fUseHistogramFieldShape){
162  constexpr unsigned int NPlanes = 3;
163 
164  //constructor decides if initialized value is a path or an environment variable
165  std::string fname;
166  cet::search_path sp("FW_SEARCH_PATH");
167  auto requestedFieldResponsePath = pset.get<std::string>("FieldResponseFname");
168  if (!sp.find_file(requestedFieldResponsePath, fname)) {
169  throw art::Exception(art::errors::Configuration)
170  << "Field response file '" << requestedFieldResponsePath
171  << "' not found in FW_SEARCH_PATH";
172  }
173  std::string histoname = pset.get<std::string>("FieldResponseHistoName");
174 
175  mf::LogInfo("SignalShapingServiceSBND")
176  << "Using the field response provided from '" << fname
177  << "' (histograms '" << histoname << "_*')";
178 
179  TFile fin(fname.c_str(), "READ");
180  if ( !fin.IsOpen() ) {
181  throw cet::exception("SignalShapingServiceSBND")
182  << "Could not find the field response file '" << fname << "'!\n";
183  }
184 
185  const std::string iPlane[3] = {"U", "V", "Y"};
186 
187  for(unsigned int i = 0; i < NPlanes; ++i) {
188  std::string PlaneHistoName = histoname + "_" + iPlane[i];
189  MF_LOG_DEBUG("SignalShapingServiceSBND")
190  << "Field Response " << i << ": " << PlaneHistoName;
191 
192  auto pHist = dynamic_cast<TH1*>(fin.Get(PlaneHistoName.c_str()));
193  if (!pHist) {
194  throw cet::exception("SignalShapingServiceSBND")
195  << "Could not find the field response histogram '" << PlaneHistoName
196  << "' in file '" << fname << "'\n";
197  }
198  if (pHist->GetNbinsX() > fNFieldBins) {
199  throw art::Exception( art::errors::Configuration ) << "FieldBins (" << fNFieldBins
200  << ") should always be larger than or equal to the number of the bins in the input histogram ("
201  << pHist->GetNbinsX() << " in '" << PlaneHistoName << "')!\n";
202  }
203  pHist->SetDirectory(nullptr); // detach the histogram from his source file
204 
205  fFieldResponseHist[i] = pHist;
206  MF_LOG_DEBUG("SignalShapingServiceSBND")
207  << "RESPONSE HISTOGRAM " << iPlane[i] << ": " << pHist->GetEntries() << " entries in "
208  << pHist->GetNbinsX() << " bins (" << pHist->GetBinLowEdge(1)
209  << " to " << pHist->GetBinLowEdge(pHist->GetNbinsX() + 1);
210  }
211 
212  fin.Close();
213  }
214 
215 }
216 
217 
218 //----------------------------------------------------------------------
219 // Accessor for single-plane signal shaper.
220 const util::SignalShaping&
222 {
223  if(!fInit)
224  init();
225 
226  // art::ServiceHandle<geo::Geometry> geom;
227 
228  // Figure out plane type.
229  // we need to distiguish the U and V planes
230  geo::View_t view = GetView(channel);
231 
232  // Return appropriate shaper.
233  //geo::SigType_t sigtype = geom->SignalType(channel);
234 
235  if (view == geo::kU)
236  return fIndUSignalShaping;
237  else if (view == geo::kV)
238  return fIndVSignalShaping;
239  else if (view == geo::kZ)
240  return fColSignalShaping;
241  else
242  throw cet::exception("SignalShapingServiceSBND")<< "1 can't determine"
243  << " SignalType\n";
244 
245 
246  return fColSignalShaping;
247 }
248 
249 //---Give Gain Settings to SimWire ---//
250 double util::SignalShapingServiceSBND::GetASICGain(unsigned int const channel) const
251 {
252  // we need to distiguish the U and V planes
253  geo::View_t view = GetView(channel);
254 
255  double gain = 0.0;
256  if(view == geo::kU)
257  gain = fASICGainInMVPerFC.at(0);
258  else if(view == geo::kV)
259  gain = fASICGainInMVPerFC.at(1);
260  else if(view == geo::kZ)
261  gain = fASICGainInMVPerFC.at(2);
262  else
263  throw cet::exception("SignalShapingServiceSBND")<< "2 can't determine"
264  << " SignalType\n";
265  return gain;
266 }
267 
268 // //---Give Shaping time Settings to SimWire ---//
269 // double util::SignalShapingServiceSBND::GetShapingTime(unsigned int const channel) const
270 // {
271 // // we need to distiguish the U and V planes
272 // geo::View_t view = GetView(channel);
273 
274 // double shaping_time = 0;
275 // if(view == geo::kU)
276 // shaping_time = fShapeTimeConst.at(0);
277 // if(view == geo::kV)
278 // shaping_time = fShapeTimeConst.at(1);
279 // else if(view == geo::kZ)
280 // shaping_time = fShapeTimeConst.at(2);
281 // else
282 // throw cet::exception("SignalShapingServiceSBND")<< "3 can't determine"
283 // << " SignalType\n";
284 // return shaping_time;
285 // }
286 
287 double util::SignalShapingServiceSBND::GetRawNoise(unsigned int const channel) const
288 {
289  unsigned int plane;
290 // art::ServiceHandle<geo::Geometry> geom;
291  //geo::SigType_t sigtype = geom->SignalType(channel);
292 
293  // we need to distiguish the U and V planes
294  geo::View_t view = GetView(channel);
295 
296  if(view == geo::kU)
297  plane = 0;
298  else if(view == geo::kV)
299  plane = 1;
300  else if(view == geo::kZ)
301  plane = 2;
302  else
303  throw cet::exception("SignalShapingServiceSBND")<< "4 can't determine"
304  << " SignalType\n";
305 
306  double shapingtime = fShapeTimeConst.at(plane);
307  double gain = fASICGainInMVPerFC.at(plane);
308  int temp;
309  if (shapingtime == 0.5){
310  temp = 0;
311  }else if (shapingtime == 1.0){
312  temp = 1;
313  }else if (shapingtime == 2.0){
314  temp = 2;
315  }else{
316  temp = 3;
317  }
318  double rawNoise;
319 
320  auto tempNoise = fNoiseFactVec.at(plane);
321  rawNoise = tempNoise.at(temp);
322 
323  rawNoise *= gain/4.7;
324  return rawNoise;
325 }
326 
327 double util::SignalShapingServiceSBND::GetDeconNoise(unsigned int const channel) const
328 {
329  unsigned int plane;
330 // art::ServiceHandle<geo::Geometry> geom;
331  //geo::SigType_t sigtype = geom->SignalType(channel);
332 
333  // we need to distiguish the U and V planes
334  geo::View_t view = GetView(channel);
335 
336  if(view == geo::kU)
337  plane = 0;
338  else if(view == geo::kV)
339  plane = 1;
340  else if(view == geo::kZ)
341  plane = 2;
342  else
343  throw cet::exception("SignalShapingServiceSBND")<< "5 can't determine"
344  << " SignalType\n";
345 
346  double shapingtime = fShapeTimeConst.at(plane);
347  int temp;
348  if (shapingtime == 0.5){
349  temp = 0;
350  }else if (shapingtime == 1.0){
351  temp = 1;
352  }else if (shapingtime == 2.0){
353  temp = 2;
354  }else{
355  temp = 3;
356  }
357  double deconNoise;
358 
359  auto tempNoise = fNoiseFactVec.at(plane);
360  deconNoise = tempNoise.at(temp);
361 
362  // replaced 2000 with fADCPerPCAtLowestASICGain/4.7 because 2000 V/ADC is specific to MicroBooNE
363  deconNoise = deconNoise /4096.*(fADCPerPCAtLowestASICGain/4.7/4.7) *6.241*1000/fDeconNorm;
364  return deconNoise;
365 }
366 
367 
368 
369 //----------------------------------------------------------------------
370 // Initialization method.
371 // Here we do initialization that can't be done in the constructor.
372 // All public methods should ensure that this method is called as necessary.
374 {
375  if(!fInit) {
376  fInit = true;
377 
378  // Do microboone-specific configuration of SignalShaping by providing
379  // microboone response and filter functions.
380 
381  // Calculate field and electronics response functions.
382 
383  SetFieldResponse();
384  SetElectResponse(fShapeTimeConst.at(2),fASICGainInMVPerFC.at(2));
385 
386  // Configure convolution kernels.
387 
388  fColSignalShaping.AddResponseFunction(fColFieldResponse);
389  fColSignalShaping.AddResponseFunction(fElectResponse);
390  fColSignalShaping.save_response();
391  fColSignalShaping.set_normflag(false);
392  //fColSignalShaping.SetPeakResponseTime(0.);
393 
394  SetElectResponse(fShapeTimeConst.at(0),fASICGainInMVPerFC.at(0));
395 
396  fIndUSignalShaping.AddResponseFunction(fIndUFieldResponse);
397  fIndUSignalShaping.AddResponseFunction(fElectResponse);
398  fIndUSignalShaping.save_response();
399  fIndUSignalShaping.set_normflag(false);
400  //fIndUSignalShaping.SetPeakResponseTime(0.);
401 
402  SetElectResponse(fShapeTimeConst.at(1),fASICGainInMVPerFC.at(1));
403 
404  fIndVSignalShaping.AddResponseFunction(fIndVFieldResponse);
405  fIndVSignalShaping.AddResponseFunction(fElectResponse);
406  fIndVSignalShaping.save_response();
407  fIndVSignalShaping.set_normflag(false);
408  //fIndVSignalShaping.SetPeakResponseTime(0.);
409 
410  SetResponseSampling();
411 
412  // Calculate filter functions.
413 
414  SetFilters();
415 
416  // Configure deconvolution kernels.
417 
418  fColSignalShaping.AddFilterFunction(fColFilter);
419  fColSignalShaping.CalculateDeconvKernel();
420 
421  fIndUSignalShaping.AddFilterFunction(fIndUFilter);
422  fIndUSignalShaping.CalculateDeconvKernel();
423 
424  fIndVSignalShaping.AddFilterFunction(fIndVFilter);
425  fIndVSignalShaping.CalculateDeconvKernel();
426  }
427 }
428 
429 
430 //----------------------------------------------------------------------
431 // Calculate microboone field response.
433 {
434  // Get services.
435 
436  art::ServiceHandle<geo::Geometry> geo;
437  auto const clockData = art::ServiceHandle<detinfo::DetectorClocksService const>()->DataForJob();
438  auto const detProp = art::ServiceHandle<detinfo::DetectorPropertiesService const>()->DataForJob(clockData);
439 
440  // Get plane pitch.
441 
442  double xyz1[3] = {0.};
443  double xyz2[3] = {0.};
444  double xyzl[3] = {0.};
445  // should always have at least 2 planes
446  geo->Plane(0).LocalToWorld(xyzl, xyz1);
447  geo->Plane(1).LocalToWorld(xyzl, xyz2);
448 
449  // this assumes all planes are equidistant from each other,
450  // probably not a bad assumption
451  double pitch = xyz2[0] - xyz1[0]; ///in cm
452 
453  fColFieldResponse.resize(fNFieldBins, 0.);
454  fIndUFieldResponse.resize(fNFieldBins, 0.);
455  fIndVFieldResponse.resize(fNFieldBins, 0.);
456 
457  // set the response for the collection plane first
458  // the first entry is 0
459 
460  double driftvelocity=detProp.DriftVelocity()/1000.;
461  double integral = 0.;
462  ////////////////////////////////////////////////////
463  if(fUseFunctionFieldShape) {
464 
465  art::ServiceHandle<util::LArFFT> fft;
466  int signalSize = fft->FFTSize();
467  std::vector<double> ramp(signalSize);
468  // TComplex kernBin;
469  // int size = signalSize/2;
470  // int bin=0;
471  //std::vector<TComplex> freqSig(size+1);
472  std::vector<double> bipolar(signalSize);
473 
474  fColFieldResponse.resize(signalSize, 0.);
475  fIndUFieldResponse.resize(signalSize, 0.);
476  fIndVFieldResponse.resize(signalSize, 0.);
477 
478  // Hardcoding. Bad. Temporary hopefully.
479  fIndUFieldFunc->SetParameter(4,fIndUFieldFunc->GetParameter(4)*signalSize);
480  fIndVFieldFunc->SetParameter(4,fIndVFieldFunc->GetParameter(4)*signalSize);
481 
482  for(int i = 0; i < signalSize; i++) {
483  ramp[i]=fColFieldFunc->Eval(i);
484  fColFieldResponse[i]=ramp[i];
485  integral += fColFieldResponse[i];
486  // rampc->Fill(i,ramp[i]);
487  bipolar[i]=fIndUFieldFunc->Eval(i);
488  fIndUFieldResponse[i]=bipolar[i];
489  bipolar[i]=fIndVFieldFunc->Eval(i);
490  fIndVFieldResponse[i]=bipolar[i];
491  // bipol->Fill(i,bipolar[i]);
492  }
493 
494  for(int i = 0; i < signalSize; ++i){
495  fColFieldResponse[i] *= fColFieldRespAmp/integral;
496  }
497 
498  //this might be not necessary if the function definition is not defined in the middle of the signal range
499  fft->ShiftData(fIndUFieldResponse,signalSize/2.0);
500  fft->ShiftData(fIndVFieldResponse,signalSize/2.0);
501 
502  }else if (fUseHistogramFieldShape){
503  //Ticks in nanoseconds
504  //Calculate the normalization of the collection plane
505 
506  for(int ibin=1; ibin<=fFieldResponseHist[2]->GetNbinsX(); ibin++)
507  integral += fFieldResponseHist[2]->GetBinContent(ibin);
508 
509  //Induction U Plane
510  for(int ibin=1; ibin<=fFieldResponseHist[0]->GetNbinsX(); ibin++)
511  fIndUFieldResponse[ibin-1] = fIndUFieldRespAmp*fFieldResponseHist[0]->GetBinContent(ibin)/integral;
512 
513  //Induction V Plane
514  for(int ibin=1; ibin<=fFieldResponseHist[1]->GetNbinsX(); ibin++)
515  fIndVFieldResponse[ibin-1] = fIndVFieldRespAmp*fFieldResponseHist[1]->GetBinContent(ibin)/integral;
516 
517  //Collection Plane
518  for(int ibin=1; ibin<=fFieldResponseHist[2]->GetNbinsX(); ibin++)
519  fColFieldResponse[ibin-1] = fColFieldRespAmp*fFieldResponseHist[2]->GetBinContent(ibin)/integral;
520 
521  } else if (fUseSimpleFieldShape) {
522 
523  mf::LogInfo("SignalShapingServiceSBND") << " using try-2 hard-coded field shapes " ;
524 
525  const int nbincPlane = 16;
526  double cPlaneResponse[nbincPlane] = {
527  0, 0, 0, 0.02620087336, 0.02620087336,
528  0.04366812227, 0.1310043668, 0.1659388646, 0.1397379913, 0.3711790393,
529  0.06550218341, 0.0480349345, -0.01310043668, -0.004366812227, 0,
530  0
531  };
532 
533  for(int i = 1; i < nbincPlane; ++i){
534  fColFieldResponse[i] = cPlaneResponse[i];
535  integral += fColFieldResponse[i];
536  }
537 
538  for(int i = 0; i < nbincPlane; ++i){
539  //fColFieldResponse[i] *= fColFieldRespAmp/integral;
540  fColFieldResponse[i] /= integral;
541  }
542 
543  //const int nbiniOld = 6;
544  const int nbinuPlane = 228;
545  // now induction plane 0 ("U")
546  // this response function has a very long (first) positive lobe, ~ 100 usec
547  // So for starters, we us the single-lobe filter
548 
549  double uPlaneResponse[nbinuPlane] = {
550  0, 0.0001881008778, 0.0003762017556, 0.0005643026334, 0.0007524035112,
551  0.000940504389, 0.001128605267, 0.001316706145, 0.001504807022, 0.0016929079,
552  0.001881008778, 0.002069109656, 0.002257210534, 0.002445311411, 0.002633412289,
553  0.002821513167, 0.003009614045, 0.003197714923, 0.0033858158, 0.003573916678,
554  0.003762017556, 0.003950118434, 0.004138219312, 0.004326320189, 0.004514421067,
555  0.004702521945, 0.004890622823, 0.005078723701, 0.005266824579, 0.005454925456,
556  0.005643026334, 0.005831127212, 0.00601922809, 0.006207328968, 0.006395429845,
557  0.006583530723, 0.006771631601, 0.006959732479, 0.007147833357, 0.007335934234,
558  0.007524035112, 0.00771213599, 0.007900236868, 0.008088337746, 0.008276438623,
559  0.008464539501, 0.008652640379, 0.008840741257, 0.009028842135, 0.009216943012,
560  0.00940504389, 0.009593144768, 0.009781245646, 0.009969346524, 0.0101574474,
561  0.01053554828, 0.01053364916, 0.01072175003, 0.01090985091, 0.01109795179,
562  0.01128605267, 0.01147415355, 0.01166225442, 0.0118503553, 0.01203845618,
563  0.01222655706, 0.01241465794, 0.01260275881, 0.01279085969, 0.01297896057,
564  0.01316706145, 0.01335516232, 0.0135432632, 0.01373136408, 0.01391946496,
565  0.01410756584, 0.01429566671, 0.01448376759, 0.01467186847, 0.01485996935,
566  0.01504807022, 0.0152361711, 0.01542427198, 0.01561237286, 0.01580047374,
567  0.01598857461, 0.01617667549, 0.01636477637, 0.01655287725, 0.01674097812,
568  0.016929079, 0.01711717988, 0.01730528076, 0.01749338164, 0.01768148251,
569  0.01786958339, 0.01805768427, 0.01824578515, 0.01843388602, 0.0186219869,
570  0.01881008778, 0.01899818866, 0.01918628954, 0.01937439041, 0.01956249129,
571  0.01975059217, 0.01993869305, 0.02012679393, 0.0203148948, 0.02050299568,
572  0.02069109656, 0.02087919744, 0.02106729831, 0.02125539919, 0.02144350007,
573  0.02163160095, 0.02181970183, 0.0220078027, 0.02219590358, 0.02238400446,
574  0.02257210534, 0.02302354744, 0.02347498955, 0.02392643166, 0.02437787376,
575  0.02482931587, 0.02528075798, 0.02573220008, 0.02618364219, 0.0266350843,
576  0.0270865264, 0.02753796851, 0.02798941062, 0.02844085272, 0.02889229483,
577  0.02934373694, 0.02979517904, 0.03024662115, 0.03069806326, 0.03114950536,
578  0.03160094747, 0.0321652501, 0.03272955274, 0.03329385537, 0.033858158,
579  0.03442246064, 0.03498676327, 0.0355510659, 0.03611536854, 0.03667967117,
580  0.03724397381, 0.03780827644, 0.03837257907, 0.03893688171, 0.03950118434,
581  0.04006548697, 0.04062978961, 0.04119409224, 0.04175839487, 0.04232269751,
582  0.04288700014, 0.0435641633, 0.04424132646, 0.04491848962, 0.04559565278,
583  0.04627281594, 0.0469499791, 0.04762714226, 0.04830430542, 0.04898146858,
584  0.04965863174, 0.0503357949, 0.05101295806, 0.05169012122, 0.05236728438,
585  0.05304444754, 0.0537216107, 0.05439877386, 0.05507593702, 0.05575310018,
586  0.05643026334, 0.0572579072, 0.05808555107, 0.05891319493, 0.05974083879,
587  0.06056848265, 0.06139612652, 0.06222377038, 0.06305141424, 0.0638790581,
588  0.06470670196, 0.06553434583, 0.06636198969, 0.06718963355, 0.06801727741,
589  0.06884492128, 0.06967256514, 0.070500209, 0.07132785286, 0.07215549673,
590  0.07298314059, 0.07305838094, 0.07313362129, 0.07320886164, 0.07328410199,
591  0.07335934234, 0.07524035112, 0.07524035112, 0.07524035112, 0.07524035112,
592  0.07524035112, 0.07524035112, 0.07524035112, 0.07565835307, 0.06688031211,
593  -1.508982036, -1.401197605, -1.293413174, -0.5748502994, -0.3233532934,
594  -0.2694610778, -0.2694610778, -0.1796407186, -0.1437125749, -0.03592814371,
595  0, 0, 0
596  };
597 
598  for(int i = 0; i < nbinuPlane; ++i){
599  //fIndUFieldResponse[i] = fIndUFieldRespAmp*uPlaneResponse[i]/(nbiniOld);
600  fIndUFieldResponse[i] = uPlaneResponse[i]/integral;
601  }
602 
603  const int nbinvPlane = 20;
604  double vPlaneResponse[nbinvPlane] = {
605  0, 0, 0.01090909091, 0.01090909091, 0.01090909091,
606  0.02181818182, 0.03272727273, 0.7636363636, 2.018181818, 2.04,
607  1.090909091, -1.03861518, -1.757656458, -1.757656458, -1.118508655,
608  -0.2396804261, -0.07989347537, -0.007989347537, 0, 0
609  };
610 
611  for (int i = 0; i < nbinvPlane; ++i) {
612  //fIndVFieldResponse[i] = vPlaneResponse[i]*fIndVFieldRespAmp/(nbiniOld);
613  fIndVFieldResponse[i] = vPlaneResponse[i]/integral;
614  }
615 
616  } else {
617 
618  //////////////////////////////////////////////////
619  mf::LogInfo("SignalShapingServiceSBND") << " using the old field shape " ;
620  int nbinc = TMath::Nint(fCol3DCorrection*(std::abs(pitch))/(driftvelocity*sampling_rate(clockData))); ///number of bins //KP
621 
622  double integral = 0.;
623  for(int i = 1; i < nbinc; ++i){
624  fColFieldResponse[i] = fColFieldResponse[i-1] + 1.0;
625  integral += fColFieldResponse[i];
626  }
627 
628  for(int i = 0; i < nbinc; ++i){
629  fColFieldResponse[i] *= fColFieldRespAmp/integral;
630  }
631 
632  // now the induction plane
633 
634  int nbini = TMath::Nint(fInd3DCorrection*(std::abs(pitch))/(driftvelocity*sampling_rate(clockData)));//KP
635  for(int i = 0; i < nbini; ++i){
636  fIndUFieldResponse[i] = fIndUFieldRespAmp/(1.*nbini);
637  fIndUFieldResponse[nbini+i] = -fIndUFieldRespAmp/(1.*nbini);
638  }
639 
640  for(int i = 0; i < nbini; ++i){
641  fIndVFieldResponse[i] = fIndVFieldRespAmp/(1.*nbini);
642  fIndVFieldResponse[nbini+i] = -fIndVFieldRespAmp/(1.*nbini);
643  }
644 
645  }
646 
647  return;
648 }
649 
650 
651 //----------------------------------------------------------------------
652 // Calculate microboone field response.
653 void util::SignalShapingServiceSBND::SetElectResponse(double shapingtime, double gain)
654 {
655  // Get services.
656 
657  art::ServiceHandle<geo::Geometry> geo;
658  art::ServiceHandle<util::LArFFT> fft;
659 
660  MF_LOG_DEBUG("SignalShapingSBND") << "Setting SBND electronics response function...";
661 
662  int nticks = fft->FFTSize();
663  fElectResponse.resize(nticks, 0.);
664  std::vector<double> time(nticks,0.);
665 
666  //Gain and shaping time variables from fcl file:
667  double Ao = 1.0; //gain
668  double To = shapingtime; //peaking time
669 
670  // this is actually sampling time, in ns
671  // mf::LogInfo("SignalShapingSBND") << "Check sampling intervals: "
672  // << fSampleRate << " ns"
673  // << "Check number of samples: " << fNTicks;
674 
675  // The following sets the microboone electronics response function in
676  // time-space. Function comes from BNL SPICE simulation of SBND
677  // electronics. SPICE gives the electronics transfer function in
678  // frequency-space. The inverse laplace transform of that function
679  // (in time-space) was calculated in Mathematica and is what is being
680  // used below. Parameters Ao and To are cumulative gain/timing parameters
681  // from the full (ASIC->Intermediate amp->Receiver->ADC) electronics chain.
682  // They have been adjusted to make the SPICE simulation to match the
683  // actual electronics response. Default params are Ao=1.4, To=0.5us.
684  double max=0.;
685 
686  for(size_t i = 0; i < fElectResponse.size(); ++i){
687 
688  //convert time to microseconds, to match fElectResponse[i] definition
689  time[i] = (1.*i)*fInputFieldRespSamplingPeriod*1e-3;
690  fElectResponse[i] =
691  4.31054*exp(-2.94809*time[i]/To)*Ao - 2.6202*exp(-2.82833*time[i]/To)*cos(1.19361*time[i]/To)*Ao
692  -2.6202*exp(-2.82833*time[i]/To)*cos(1.19361*time[i]/To)*cos(2.38722*time[i]/To)*Ao
693  +0.464924*exp(-2.40318*time[i]/To)*cos(2.5928*time[i]/To)*Ao
694  +0.464924*exp(-2.40318*time[i]/To)*cos(2.5928*time[i]/To)*cos(5.18561*time[i]/To)*Ao
695  +0.762456*exp(-2.82833*time[i]/To)*sin(1.19361*time[i]/To)*Ao
696  -0.762456*exp(-2.82833*time[i]/To)*cos(2.38722*time[i]/To)*sin(1.19361*time[i]/To)*Ao
697  +0.762456*exp(-2.82833*time[i]/To)*cos(1.19361*time[i]/To)*sin(2.38722*time[i]/To)*Ao
698  -2.6202*exp(-2.82833*time[i]/To)*sin(1.19361*time[i]/To)*sin(2.38722*time[i]/To)*Ao
699  -0.327684*exp(-2.40318*time[i]/To)*sin(2.5928*time[i]/To)*Ao +
700  +0.327684*exp(-2.40318*time[i]/To)*cos(5.18561*time[i]/To)*sin(2.5928*time[i]/To)*Ao
701  -0.327684*exp(-2.40318*time[i]/To)*cos(2.5928*time[i]/To)*sin(5.18561*time[i]/To)*Ao
702  +0.464924*exp(-2.40318*time[i]/To)*sin(2.5928*time[i]/To)*sin(5.18561*time[i]/To)*Ao;
703 
704  if(fElectResponse[i] > max) max = fElectResponse[i];
705  }// end loop over time buckets
706 
707  MF_LOG_DEBUG("SignalShapingSBND") << " Done.";
708 
709  // normalize fElectResponse[i], before the convolution
710  // Put in overall normalization in a pedantic way:
711  // first put in the pulse area per eleectron at the lowest gain setting,
712  // then normalize by the actual ASIC gain setting used.
713  // This code is executed only during initialization of service,
714  // so don't worry about code inefficiencies here.
715  for(auto& element : fElectResponse){
716  element /= max;
717  element *= fADCPerPCAtLowestASICGain*1.60217657e-7;
718  element *= gain/4.7;
719  }
720 
721  return;
722 
723 }
724 
725 
726 //----------------------------------------------------------------------
727 // Calculate microboone filter functions.
729 {
730  // Get services.
731 
732  art::ServiceHandle<util::LArFFT> fft;
733  auto const clockData = art::ServiceHandle<detinfo::DetectorClocksService const>()->DataForJob();
734 
735  double ts = sampling_rate(clockData);
736  int n = fft->FFTSize() / 2;
737 
738  // Calculate collection filter.
739 
740  fColFilter.resize(n+1);
741  fIndUFilter.resize(n+1);
742  fIndVFilter.resize(n+1);
743 
744  if(!fGetFilterFromHisto)
745  {
746  fColFilterFunc->SetRange(0, double(n));
747 
748  for(int i=0; i<=n; ++i) {
749  double freq = 500. * i / (ts * n); // Cycles / microsecond.
750  double f = fColFilterFunc->Eval(freq);
751  fColFilter[i] = TComplex(f, 0.);
752  }
753 
754 
755  // Calculate induction filters.
756 
757  fIndUFilterFunc->SetRange(0, double(n));
758 
759  for(int i=0; i<=n; ++i) {
760  double freq = 500. * i / (ts * n); // Cycles / microsecond.
761  double f = fIndUFilterFunc->Eval(freq);
762  fIndUFilter[i] = TComplex(f, 0.);
763  }
764 
765  fIndVFilterFunc->SetRange(0, double(n));
766 
767  for(int i=0; i<=n; ++i) {
768  double freq = 500. * i / (ts * n); // Cycles / microsecond.
769  double f = fIndVFilterFunc->Eval(freq);
770  fIndVFilter[i] = TComplex(f, 0.);
771  }
772 
773  }
774  else
775  {
776 
777  for(int i=0; i<=n; ++i) {
778  double f = fFilterHist[2]->GetBinContent(i); // hardcoded plane numbers. Bad. To change later.
779  fColFilter[i] = TComplex(f, 0.);
780  double g = fFilterHist[1]->GetBinContent(i);
781  fIndVFilter[i] = TComplex(g, 0.);
782  double h = fFilterHist[0]->GetBinContent(i);
783  fIndUFilter[i] = TComplex(h, 0.);
784 
785  }
786  }
787 
788  fIndUSignalShaping.AddFilterFunction(fIndUFilter);
789  fIndVSignalShaping.AddFilterFunction(fIndVFilter);
790  fColSignalShaping.AddFilterFunction(fColFilter);
791 
792 }
793 
794 //---------------------------------------------------------------
795 // Sample SBND response (the convoluted field and electronics
796 // response)
798 {
799  //Get services
800  art::ServiceHandle<geo::Geometry> geo;
801  art::ServiceHandle<util::LArFFT> fft;
802  auto const clockData = art::ServiceHandle<detinfo::DetectorClocksService const>()->DataForJob();
803 
804  //Operations permitted only if output of rebinning has a larger bin size
805  if( fInputFieldRespSamplingPeriod > sampling_rate(clockData) )
806  throw cet::exception("SignalShapingServiceSBND") << "\033[93m"
807  << "Invalid operation: cannot rebin to a more finely binned vector!"
808  << "\033[00m" << std::endl;
809 
810  int nticks = fft->FFTSize();
811  std::vector<double> SamplingTime(nticks,0.);
812  for(int itime = 0; itime < nticks; itime++) {
813  SamplingTime[itime] = (1.*itime) * sampling_rate(clockData);
814  }
815 
816  //Sampling
817  for(int iplane = 0; iplane <= 2; iplane++) {
818  const std::vector<double>* pResp;
819  switch( iplane ) {
820  case 0: pResp = &(fIndUSignalShaping.Response_save()); break;
821  case 1: pResp = &(fIndVSignalShaping.Response_save()); break;
822  default: pResp = &(fColSignalShaping.Response_save()); break;
823  }
824 
825  std::vector<double> SamplingResp(nticks, 0.);
826 
827  int nticks_input = pResp->size();
828  std::vector<double> InputTime(nticks_input, 0.);
829  for(int itime = 0; itime < nticks_input; itime++) {
830  InputTime[itime] = (1.*itime) * fInputFieldRespSamplingPeriod;
831  }
832 
833  /*
834  Much more sophisticated approach using a linear (trapezoidal) interpolation
835  current deafult!
836  */
837  int SamplingCount = 0;
838  for(int itime = 0; itime < nticks; itime++) {
839  int low = -1, up = -1;
840  for(int jtime = 0; jtime < nticks; jtime++) {
841  if(InputTime[jtime] == SamplingTime[itime]) {
842  SamplingResp[itime] = (*pResp)[jtime];
843  SamplingCount++;
844  break;
845  } else if(InputTime[jtime] > SamplingTime[itime]) {
846  low = jtime - 1;
847  up = jtime;
848  SamplingResp[itime] = (*pResp)[low] + (SamplingTime[itime] - InputTime[low]) * ( (*pResp)[up] - (*pResp)[low]) / (InputTime[up] - InputTime[low] );
849  SamplingCount++;
850  break;
851  } else {
852  SamplingResp[itime] = 0;
853  }
854  }// for(int jtime = 0; jtime < nticks; jtime++)
855 
856  }// for(int itime = 0; itime < nticks; itime++)
857 
858  SamplingResp.resize(SamplingCount, 0.);
859 
860  switch( iplane ) {
861  case 0: fIndUSignalShaping.AddResponseFunction(SamplingResp, true); break;
862  case 1: fIndVSignalShaping.AddResponseFunction(SamplingResp, true);; break;
863  default: fColSignalShaping.AddResponseFunction(SamplingResp, true);; break;
864  }
865 
866  }// for(int iplane = 0; iplane < 2; iplane++)
867 
868  return;
869 }
870 
872  unsigned int const channel) const
873 {
874  //art::ServiceHandle<geo::Geometry> geom;
875  geo::View_t view = GetView(channel);
876 
877  double time_offset = 0;
878  if(view == geo::kU)
879  time_offset = fFieldResponseTOffset.at(0);
880  else if(view == geo::kV)
881  time_offset = fFieldResponseTOffset.at(1);
882  else if(view == geo::kZ)
883  time_offset = fFieldResponseTOffset.at(2);
884  else
885  throw cet::exception("SignalShapingServiceSBND")<< "6 can't determine"
886  << " SignalType\n";
887 // std::cout << "TIME OFFSET" << time_offset << " " << view << std::endl;
888 
889  auto tpc_clock = clockData.TPCClock();
890  return tpc_clock.Ticks(time_offset/1.e3);
891 }
892 
894  art::ServiceHandle<geo::Geometry> geom;
895  geo::View_t view = geom->View(chan);
896 
897  // TEMPORARY BUG FIX (7/23/2021, v09_26_00): With geometry v2, LArSoft is mixing
898  // up the view assignments for the U and V planes in TPC0, but not TPC1, resulting
899  // in the wrong signal shapes being used. To work around this, we explicitly assign
900  // the view based on the plane number for the two induction planes. -wforeman
901  std::vector<geo::WireID> wires = geom->ChannelToWire(chan);
902  if( wires.size() ) {
903  if ( wires[0].Plane == 0 ) view = geo::kU;
904  else if ( wires[0].Plane == 1 ) view = geo::kV;
905  }
906 
907  return view;
908 }
909 
910 
911 namespace util {
912 
913  DEFINE_ART_SERVICE(SignalShapingServiceSBND)
914 
915 }
double GetDeconNoise(unsigned int const channel) const
BEGIN_PROLOG true icarus_rawdigitfilter FilterTools FilterPlane1 Plane
string fname
Definition: demo.py:5
ElecClock const & TPCClock() const noexcept
Borrow a const TPC clock with time set to Trigger time [us].
enum geo::_plane_proj View_t
Enumerate the possible plane projections.
Planes which measure V.
Definition: geo_types.h:130
Planes which measure Z direction.
Definition: geo_types.h:132
double GetRawNoise(unsigned int const channel) const
void SetElectResponse(double shapingtime, double gain)
constexpr int Ticks() const noexcept
Current clock tick (that is, the number of tick Time() falls in).
Definition: ElecClock.h:205
BEGIN_PROLOG g
standard_dbscan3dalg useful for diagnostics hits not in a line will not be clustered on on only for track like only for track like on on the smaller the less shower like tracks low
while getopts h
T abs(T value)
Planes which measure U.
Definition: geo_types.h:129
Service to provide microboone-specific signal shaping for simulation (convolution) and reconstruction...
const util::SignalShaping & SignalShaping(unsigned int channel) const
double GetASICGain(unsigned int const channel) const
SignalShapingServiceSBND(const fhicl::ParameterSet &pset, art::ActivityRegistry &reg)
Encapsulate the construction of a single detector plane.
if &&[-z"$BASH_VERSION"] then echo Attempting to switch to bash bash shellSwitch exit fi &&["$1"= 'shellSwitch'] shift declare a IncludeDirectives for Dir in
Contains all timing reference information for the detector.
do i e
int FieldResponseTOffset(detinfo::DetectorClocksData const &clockData, unsigned int const channel) const
geo::View_t GetView(unsigned int chan) const
double sampling_rate(DetectorClocksData const &data)
Returns the period of the TPC readout electronics clock.
art framework interface to geometry description
auto const detProp
Encapsulate the construction of a single detector plane.
void reconfigure(const fhicl::ParameterSet &pset)