SignalShapingServiceDUNEDPhase_service.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 /// \file SignalShapingServiceDUNEDPhase_service.cc
3 /// \author vgalymov@ipnl.in2p3.fr
4 ////////////////////////////////////////////////////////////////////////
5 
7 
11 #include "cetlib_except/exception.h"
17 #include "larcore/CoreUtils/ServiceUtil.h" // lar::providerFrom()
18 #include "TSpline.h"
19 
20 //#include "TFile.h"
21 
22 //----------------------------------------------------------------------
23 // Constructor.
25  art::ActivityRegistry& /* reg */)
26  : fInit(false)
27 {
28  reconfigure(pset);
29 }
30 
31 
32 //----------------------------------------------------------------------
33 // Destructor.
35 {}
36 
37 
38 //----------------------------------------------------------------------
39 // Reconfigure method.
41 {
42  // Reset initialization flag.
43  fInit = false;
44 
45  // Reset kernels.
47 
48  // Fetch fcl parameters for normal 3m view
49  fAreaNorm = pset.get<double>("AreaNorm");
50  fADCpermV = pset.get<double>("ADCpermV");
51  fAmpENC = pset.get<double>("AmpENC");
52  fDeconNorm = pset.get<double>("DeconNorm");
53  fRespSamplingPeriod = pset.get<double>("RespSamplingPeriod");
54  fShapeFunc = pset.get<std::string>("ShapeFunc");
55 
56  fColShapeFunc = new TF1("fColShapeFunc", fShapeFunc.c_str());
57  std::vector<double> params = pset.get<std::vector<double>>("ShapeFuncParams");
58  for( unsigned i=0;i<params.size();++i ){
59  //std::cout<<i<<" "<<params[i]<<std::endl;
60  fColShapeFunc->SetParameter(i, params[i]);
61  }
62 
63  // now check if there is anything specific for 3x1x1 1m view
65  fHave1mView = (pset.has_key("AreaNorm1m") || pset.has_key( "ShapeFunc1m" ));
66  fAreaNorm1m = pset.get<double>("AreaNorm1m", fAreaNorm);
68  std::vector<double> params1 = params;
69  if( pset.has_key( "ShapeFunc1m" ) )
70  {
71  fShapeFunc1m = pset.get<std::string>("ShapeFunc1m");
72  params1 = pset.get<std::vector<double>>("ShapeFuncParams1m");
73  }
74  fColShapeFunc1m = new TF1("fColShapeFunc1m", fShapeFunc1m.c_str());
75  for( unsigned i=0;i<params1.size();++i ){
76  //std::cout<<i<<" "<<params1[i]<<std::endl;
77  fColShapeFunc1m->SetParameter(i, params1[i]);
78  }
79 
80  //
81  mf::LogInfo("SignalShapingServiceDUNEDPhase") << " Area normalization : "<<fAreaNorm << " ADC x us\n"
82  << " Shape function : "<<fShapeFunc << "\n"
83  << " Decon normalization : "<<fDeconNorm <<"\n"
84  << " Response sampling period : "<< fRespSamplingPeriod<<" us \n"
85  << " Noise : "<<fAmpENC<<" electrons\n"
86  << " ADC per mV : "<<fADCpermV;
87 
88  if( fHave1mView )
89  mf::LogInfo("SignalShapingServiceDUNEDPhase") << " Parameters for 1m view :\n"
90  << " Area normalization : "<<fAreaNorm1m << " ADC x us\n"
91  << " Shape function : "<<fShapeFunc1m;
92 
93 
94 
95  // Construct parameterized collection filter function.
96  mf::LogInfo("SignalShapingServiceDUNE") << "Getting Field response from .fcl file"; //<<< to be changed if we keep the harcoded function
97  fAddFieldFunction = pset.get<bool>("AddFieldFunction");
98  std::string colField = pset.get<std::string>("ColFieldFunction");
99  std::vector<double> colFieldParams =
100  pset.get<std::vector<double> >("ColFieldFunctionParams");
101  fColFieldFunc = new TF1("colFieldFunction", colField.c_str());
102  for(unsigned int i=0; i<colFieldParams.size(); ++i)
103  fColFieldFunc->SetParameter(i, colFieldParams[i]);
104 
105  mf::LogInfo("SignalShapingServiceDUNE") << "Getting Filter from .fcl file";
106  std::string colFilt = pset.get<std::string>("ColFilter");
107  std::vector<double> colFiltParams =
108  pset.get<std::vector<double> >("ColFilterParams");
109  fColFilterFunc = new TF1("colFilter", colFilt.c_str());
110  for(unsigned int i=0; i<colFiltParams.size(); ++i)
111  fColFilterFunc->SetParameter(i, colFiltParams[i]);
112  fColFieldRespAmp = pset.get<double>("ColFieldRespAmp");
113 
114  init();
115 }
116 
117 //----------------------------------------------------------------------
118 // Accessor for single-plane signal shaper.
119 const util::SignalShaping&
121 {
122  if(!fInit)
123  init();
124 
125  if( !fHave1mView ) return fColSignalShaping;
126 
127  //
128  auto const* geom = lar::providerFrom<geo::Geometry>();
129  std::vector<geo::WireID> Wires = geom->ChannelToWire(channel);
130 
131  double wirestartpoint[3];
132  double wireendpoint[3];
133  geom->WireEndPoints(Wires[0],wirestartpoint,wireendpoint);
134  double wirelength = sqrt(pow(wirestartpoint[0]-wireendpoint[0],2) + pow(wirestartpoint[1]-wireendpoint[1],2) + pow(wirestartpoint[2]-wireendpoint[2],2));
135 
136  if((int)wirelength == 300)
137  return fColSignalShaping;
138  else if((int)wirelength == 100)
139  return fColSignalShaping1m;
140  else
141  throw cet::exception("SignalShapingServiceDUNEDPhase")
142  << "unexpected signal type " << geom->SignalType(channel)
143  << " for channel #" << channel << "\n";
144 /*
145  switch (geom->SignalType(channel)) {
146  case geo::kCollection:
147  return fColSignalShaping; //always collections in DP detector
148  default:
149  throw cet::exception("SignalShapingServiceDUNEDPhase")
150  << "unexpected signal type " << geom->SignalType(channel)
151  << " for channel #" << channel << "\n";
152  } // switch
153 */
154 } // util::SignalShapingServiceDUNEDPhase::SignalShaping()
155 
156 //----------------------------------------------------------------------
157 // Initialization method.
158 // Here we do initialization that can't be done in the constructor.
159 // All public methods should ensure that this method is called as necessary.
161 {
162  if( fInit ) return;
163 
164  fInit = true;
165 
166  // Lazy initialization is problematic wrt multi-threading. For this
167  // case, the best we can do is use the global data as provided by
168  // the detector-clocks service.
169  auto const clockData = art::ServiceHandle<detinfo::DetectorClocksService const>()->DataForJob();
170 
171  //
173  // noise in ADC
174  fAmpENCADC = fAmpENC * 1.60217657e-4 * fPulseHeight * fADCpermV;
175  MF_LOG_DEBUG("SignalShapingDUNEDPhase") << "Pulse height in mV 3m view : "<<fPulseHeight;
176  MF_LOG_DEBUG("SignalShapingDUNEDPhase") << "Noise in ADC : "<<fAmpENCADC;
177  // rebin to appropriate sampling rate of readout
179 
180  // 3x1x1 1m view
182  MF_LOG_DEBUG("SignalShapingDUNEDPhase") << "Pulse height in mV 1m view : "<<fPulseHeight1m;
183  // rebin to appropriate sampling rate of readout
185 
186 
187  // Calculate field and electronics response functions.
188  if(fAddFieldFunction){
189  std::vector<double> fresp;
190  SetFieldResponse( fresp );
193  }
194 
195  //
196  // Calculate filter functions.
197  SetFilters(clockData);
198 
199  // Configure deconvolution kernels.
204 }
205 
206 //-----Give Gain Settings to SimWire-----//
208 {
209  //
210  if( !fHave1mView ) return fPulseHeight;
211 
212  //
213  double gain = 0;
215  std::vector<geo::WireID> Wires = geom->ChannelToWire(channel);
216  double wirestartpoint[3];
217  double wireendpoint[3];
218  geom->WireEndPoints(Wires[0],wirestartpoint,wireendpoint);
219  double wirelength = sqrt(pow(wirestartpoint[0]-wireendpoint[0],2) + pow(wirestartpoint[1]-wireendpoint[1],2) + pow(wirestartpoint[2]-wireendpoint[2],2));
220 
221  if((int)wirelength == 300)
222  gain = fPulseHeight;
223  else if((int)wirelength == 100)
224  gain = fPulseHeight1m;
225  else
226  throw cet::exception("SignalShapingServiceDUNEDPhase")<< "can't determine"
227  << " View\n";
228  return gain;
229 }
230 
231 // area normalization factor should be in (ADC x us) / fC
233 {
234  //
235  if( !fHave1mView ) return fAreaNorm;
236 
237  //
238  double gain = 0;
240  std::vector<geo::WireID> Wires = geom->ChannelToWire(channel);
241  double wirestartpoint[3];
242  double wireendpoint[3];
243  geom->WireEndPoints(Wires[0],wirestartpoint,wireendpoint);
244  double wirelength = sqrt(pow(wirestartpoint[0]-wireendpoint[0],2) + pow(wirestartpoint[1]-wireendpoint[1],2) + pow(wirestartpoint[2]-wireendpoint[2],2));
245 
246  if((int)wirelength == 300)
247  gain = fAreaNorm;
248  else if((int)wirelength == 100)
249  gain = fAreaNorm1m;
250  else
251  throw cet::exception("SignalShapingServiceDUNEDPhase")<< "can't determine"
252  << " View\n";
253  return gain;
254 }
255 
256 
257 //-----Give Shaping time to SimWire-----//
259 {
260  //art::ServiceHandle<geo::Geometry> geom;
261  //geo::View_t view = geom->View(channel);
262 
263  return 0.0; //not sure what this does in simwire
264 }
265 
267 {
268  return fAmpENCADC;
269 }
270 
272 {
273  return fAmpENC / fDeconNorm; //expected ENC
274 }
275 
276 
277 
278 //----------------------------------------------------------------------
279 // Calculate field response. Maybe implemented at some point
281 {
282  // set the response for the collection plane first
283  // the first entry is 0
284 
285  //double integral = 0;
287  MF_LOG_DEBUG("SignalShapingDUNEDPhase") << "Setting DUNEDPhase field response function...";
288 
289  int nticks = fft->FFTSize();
290  std::vector<double> time(nticks,0.);
291  fresp.resize(nticks, 0.);
292 
293  double integral =0;
294  for(size_t i = 0; i < fresp.size(); ++i)
295  {
296  //convert time to microseconds, to match response function definition
297  time[i] = (1.*i)*fRespSamplingPeriod*1e-3;
298  fresp[i] = FieldResponse(time[i]);
299  integral +=fresp[i];
300  }// end loop over time buckets
301 
302  //insert normalization
303  for(size_t i = 0; i < fresp.size(); ++i)
304  fresp[i] *= fColFieldRespAmp/integral;
305 
306  MF_LOG_DEBUG("SignalShapingDUNEDPhase") << " Done.";
307 
308  return;
309 }
310 
311 //----------------------------------------------------------------------
312 // Calculate electronics response
314  util::SignalShaping &sig,
315  double areanorm )
316 {
317  MF_LOG_DEBUG("SignalShapingDUNEDPhase") << "Setting DUNEDPhase electronics response function...";
319  int nticks = fft->FFTSize();
320  std::vector<double> resp(nticks, 0.);
321 
322  // convert to us
323  double dt = fRespSamplingPeriod * 1.0E-3;
324  double max = 0.;
325  double sum = 0.;
326  for( auto i=0;i<nticks; ++i )
327  {
328  double t = i*dt;
329  double v = fshape->Eval( t );
330  if( t == 0 || v != v || v < 0 ) v = 0;
331 
332  if( v > max ) max = v;
333  sum += v;
334  resp[i] = v;
335  }
336 
337  //
338  double norm = areanorm / (sum * dt);
339  double pheight = norm * max / fADCpermV;
340  //normalize to 1e charge before the convolution
341  for(auto& element : resp)
342  {
343  element *= norm * 1.60217657e-4; // per fC -> per electron
344  }
345 
346  MF_LOG_DEBUG("SignalShapingDUNEDPhase") << "Area norm "<<areanorm<<" -> norm "<<norm <<"\n"
347  << "Pulse height "<<pheight;
348 
349  //
350  sig.AddResponseFunction(resp);
351 
352  // Configure convolution kernels.
353  sig.save_response();
354  sig.set_normflag(false);
355 
356  MF_LOG_DEBUG("SignalShapingDUNEDPhase") << " Done.";
357 
358  return pheight;
359 }
360 
361 //----------------------------------------------------------------------
362 // (Re)sample electronics (+field?) response
364  util::SignalShaping &sig )
365 {
366  // Get services
368 
369  // Operation permitted only if output of rebinning has a larger bin size
370  if( fRespSamplingPeriod > sampling_rate(clockData) )
371  throw cet::exception(__FUNCTION__) << "\033[93m"
372  << "Invalid operation: cannot rebin to a more finely binned vector!"
373  << "\033[00m" << std::endl;
374 
375 
376  if( fRespSamplingPeriod == sampling_rate(clockData) ) //nothing to do
377  {
378  return;
379  }
380 
381  //
382  // make a new response vector with different time sampling
383 
384  const std::vector<double>* pResp = &(sig.Response_save());
385  int nticks_input = pResp->size();
386 
387  //old sampling time vector
388  std::vector<double> InputTime(nticks_input, 0. );
389  std::vector<double> InputResp(nticks_input, 0. );
390  for ( int itime = 0; itime < nticks_input; itime++ )
391  {
392  InputResp[itime] = (*pResp)[itime];
393  InputTime[itime] = (1.*itime) * fRespSamplingPeriod; // in ns
394  }
395 
396  // build a spline for interpolation
397  TSpline3 ispl("ispl", &InputTime[0], &InputResp[0], nticks_input);
398 
399 
400  //
401  // default number of time ticks
402  int nticks = fft->FFTSize();
403 
404  // resampling vectors
405  std::vector<double> SamplingResp( nticks , 0. );
406  double dt = sampling_rate(clockData);
407  double maxtime = InputTime.back();
408  //
409  for ( int itime = 0; itime < nticks; itime++ )
410  {
411  double t = itime * dt; // in ns
412  // don't go past max t value from old response
413  if(t > maxtime) break;
414  SamplingResp[itime] = ispl.Eval(t);
415  }
416 
417  sig.AddResponseFunction( SamplingResp, true );
418  return;
419 }
420 
421 
422 //----------------------------------------------------------------------
423 // Calculate filter functions.
425 {
426  // Get services.
428 
429  double ts = sampling_rate(clockData); // should return in ns
430  int nsize = fft->FFTSize();
431  int nhalf = nsize / 2;
432  fColFilterFunc->SetRange(0, double(nhalf));
433 
434  //
435  // Calculate collection filter.
436 
437  // the frequency step is given by fMhz/nsamples
438  double df = 1.0/(ts*1.0E-3 * nsize);
439  fColFilter.resize(nhalf+1);
440  for(int i=0; i<=nhalf; ++i)
441  {
442  //double freq = 400. * i / (ts * nhalf); // Cycles / microsecond.
443  double freq = i * df;
444  double f = fColFilterFunc->Eval(freq);
445  fColFilter[i] = TComplex(f, 0.);
446  }
447 
448  return;
449 }
450 
451 //----------------------------------------------------------------------
452 // Field response function (Harcoded, but it shouldn't)
454 {
455  /*
456  //Studies for the Slow component function
457  //reaad parameters from configuration
458  double fWidth = fParArray[0]; //Fast component time width
459  double fHeight = fParArray[1]; //Qfast/Qextract
460  double fNorm = fParArray[2]; //Qextract/Qall
461  double fTau = fParArray[3]; //Trapping time slow component
462  double f1=0;
463  double f2=0;
464  if(tval_us >= 0 && tval_us < fWidth) {f1 = 1/fWidth;}
465 
466  //f1 = (1/fWidth)*exp(-tval_us/fWidth);
467  //f1 = TMath::Gaus(0, fWidth, true);
468  //f1 = 1;
469  f2 = (1/fTau)*exp(-tval_us/fTau);
470  return fNorm*(fHeight*f1+(1-fHeight)*f2); //normalized field response
471  */
472  return fColFieldFunc->Eval(tval_us);
473 }
474 
475 //
477  return fDeconNorm;
478 }
479 
480 //
482  return SignalShaping(0).Response().size();
483 }
484 
485 // n/a
487  return std::vector<DoubleVec>();
488 }
489 
490 
491 // n/a
494  unsigned int const channel) const {
495  return 0;
496 }
497 
500  unsigned int channel, FloatVector& func) const {
501  return Convolute<float>(channel, func);
502 }
503 
506  unsigned int channel, DoubleVector& func) const {
507  return Convolute<double>(channel, func);
508 }
509 
512  unsigned int channel, FloatVector& func) const {
513  return Deconvolute<float>(channel, func);
514 }
515 
518  unsigned int channel, DoubleVector& func) const {
519  return Deconvolute<double>(channel, func);
520 }
521 
522 
523 namespace util {
524 
526 
527 }
void set_normflag(bool flag)
const std::vector< double > & Response_save() const
Definition: SignalShaping.h:78
Namespace for general, non-LArSoft-specific utilities.
void SetFilters(detinfo::DetectorClocksData const &clockData)
std::string string
Definition: nybbler.cc:12
MaybeLogger_< ELseverityLevel::ELsev_info, false > LogInfo
const std::vector< double > & Response() const
Definition: SignalShaping.h:77
std::vector< float > FloatVector
constexpr T pow(T x)
Definition: pow.h:72
double fAmpENC
noise in num of electrons used where???
void AddResponseFunction(const std::vector< double > &resp, bool ResetResponse=false)
std::vector< geo::WireID > ChannelToWire(raw::ChannelID_t const channel) const
Returns a list of wires connected to the specified TPC channel.
double fRespSamplingPeriod
Sampling period for response in ns.
uint8_t channel
Definition: CRTFragment.hh:201
double GetAreaNorm(unsigned int const channel) const
double GetDeconNoise(Channel channel) const override
void SetResponseSampling(detinfo::DetectorClocksData const &clockData, util::SignalShaping &sig)
art framework interface to geometry description
double fPulseHeight1m
pulse amtplitide in mV per fC
int FFTSize() const
Definition: LArFFT.h:69
const double e
void CalculateDeconvKernel() const
bool fAddFieldFunction
Enable the filed function.
T get(std::string const &key) const
Definition: ParameterSet.h:271
double GetShapingTime(Channel channel) const override
std::vector< DoubleVec > GetNoiseFactVec() const override
void Convolute(unsigned int channel, std::vector< T > &func) const
const util::SignalShaping & SignalShaping(unsigned int channel) const override
bool has_key(std::string const &key) const
static int max(int a, int b)
Service to provide DUNE dual-phase signal shaping for simulation (convolution) and reconstruction (de...
auto norm(Vector const &v)
Return norm of the specified vector.
TF1 * fColFieldFunc
Parameterized collection field function.
#define DEFINE_ART_SERVICE(svc)
int FieldResponseTOffset(detinfo::DetectorClocksData const &clockData, unsigned int const channel) const override
Encapsulate the construction of a single detector plane.
std::vector< double > DoubleVector
Contains all timing reference information for the detector.
#define MF_LOG_DEBUG(id)
def func()
Definition: docstring.py:7
void WireEndPoints(geo::WireID const &wireid, double *xyzStart, double *xyzEnd) const
Fills two arrays with the coordinates of the wire end points.
double SetElectResponse(const TF1 *fshape, util::SignalShaping &sig, double areanorm)
double fColFieldRespAmp
amplitude of response to field
SignalShapingServiceDUNEDPhase(const fhicl::ParameterSet &pset, art::ActivityRegistry &reg)
double sampling_rate(DetectorClocksData const &data)
Returns the period of the TPC readout electronics clock.
double fAreaNorm1m
in units (ADC x us) / fC for 1m strips
void AddFilterFunction(const std::vector< TComplex > &filt)
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33
QTextStream & endl(QTextStream &s)
Encapsulate the construction of a single detector plane.
void Deconvolute(unsigned int channel, std::vector< T > &func) const