All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ElectronicsResponse_tool.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 /// \file ElectronicsResponse.cc
3 /// \author T. Usher
4 ////////////////////////////////////////////////////////////////////////
5 
6 #include <cmath>
7 #include "IElectronicsResponse.h"
8 #include "art/Utilities/ToolMacros.h"
9 #include "art/Utilities/make_tool.h"
10 #include "art_root_io/TFileService.h"
11 #include "messagefacility/MessageLogger/MessageLogger.h"
12 #include "cetlib_except/exception.h"
14 #include "icarus_signal_processing/Filters/ICARUSFFT.h"
15 
16 #include "TProfile.h"
17 
18 #include <fstream>
19 #include <numeric> // std::accumulate
20 
21 namespace icarus_tool
22 {
23 
25 {
26 public:
27  explicit ElectronicsResponse(const fhicl::ParameterSet& pset);
28 
30 
31  void configure(const fhicl::ParameterSet& pset) override;
32  void setResponse(size_t numBins, double binWidth) override;
33  void outputHistograms(art::TFileDirectory&) const override;
34 
35  size_t getPlane() const override {return fPlane;}
36  double getFCperADCMicroS() const override {return fFCperADCMicroS;}
37  double getASICShapingTime() const override {return fASICShapingTime;}
40 
41 private:
42  // Member variables from the fhicl file
43  size_t fPlane;
47 
48  // Keep track of the bin width (for histograms)
49  double fBinWidth;
50 
51  // Container for the electronics response "function"
53 
54  // And a container for the FFT of the above
56 
57  // Keep track of the FFT
58  std::unique_ptr<icarus_signal_processing::ICARUSFFT<double>> fFFT; ///< Object to handle thread safe FFT
59 };
60 
61 //----------------------------------------------------------------------
62 // Constructor.
63 ElectronicsResponse::ElectronicsResponse(const fhicl::ParameterSet& pset) :
64  fBinWidth(0.),
65  fFFT(nullptr)
66 {
67  configure(pset);
68 }
69 
70 void ElectronicsResponse::configure(const fhicl::ParameterSet& pset)
71 {
72  // Start by recovering the parameters
73  fPlane = pset.get<size_t>("Plane");
74  fFCperADCMicroS = pset.get<double>("FCperADCMicroS");
75  fASICShapingTime = pset.get<double>("ASICShapingTime");
76  fADCPerPCAtLowestASICGain = pset.get<double>("ADCPerPCAtLowestASICGain");
77 
78  return;
79 }
80 
81 void ElectronicsResponse::setResponse(size_t numBins, double binWidth)
82 {
83  // The input binWidth is in nanoseconds, we need to convert to microseconds to match the
84  // parameters for the electronics response which are given in us
85  double timeCorrect = 1.e-3;
86 
87  fBinWidth = binWidth * timeCorrect;
88 
89  fElectronicsResponseVec.resize(numBins, 0.);
90 
91  // Check that we have initialized our FFT object
92  if (!fFFT) fFFT = std::make_unique<icarus_signal_processing::ICARUSFFT<double>>(numBins);
93 
94  // This note from Filippo:
95  // The following sets the ICARUS electronics response function in
96  // time-space. Function comes from BNL SPICE simulation of ICARUS
97  // electronics. SPICE gives the electronics transfer function in
98  // frequency-space. The inverse laplace transform of that function
99  // (in time-space) was calculated in Mathematica and is what is being
100  // used below. Parameters Ao and To are cumulative gain/timing parameters
101  // from the full (ASIC->Intermediate amp->Receiver->ADC) electronics chain.
102  // They have been adjusted to make the SPICE simulation to match the
103  // actual electronics response. Default params are Ao=1.4, To=0.5us.
104 
105  for(size_t timeIdx = 0; timeIdx < numBins; timeIdx++)
106  {
107  double funcArg = double(timeIdx) * fBinWidth / fASICShapingTime;
108 
109  fElectronicsResponseVec[timeIdx] = funcArg * exp(-funcArg);
110  }
111 
112  // normalize fElectResponse[i], before the convolution
113  // Put in overall normalization in a pedantic way:
114  // first put in the pulse area per eleectron at the lowest gain setting,
115  // then normalize by the actual ASIC gain setting used.
116  // This code is executed only during initialization of service,
117  // so don't worry about code inefficiencies here.
118  // double last_integral=0;
119  // double last_max=0;
120 
121  // ICARUS Normalization are the following
122  // Field response is normalized to 1 electron. Shaping function written as (t/tau)*exp(-t/tau) is normalized to 1
123  // From test pulse measurement with FLIC@CERN we have 0.027 fC/(ADC*us)
124  // Therefore 0.027*6242 electrons/(ADC*us)
125 
126  // The below scales the response by 1./FCperADCMicroS... but this gets taken out in the normalization
127  std::transform(fElectronicsResponseVec.begin(),fElectronicsResponseVec.end(),fElectronicsResponseVec.begin(),std::bind(std::divides<double>(),std::placeholders::_1,fFCperADCMicroS));
128 
129  //double respIntegral = fBinWidth * std::accumulate(fElectronicsResponseVec.begin(),fElectronicsResponseVec.end(),0.);
130  double respIntegral = std::accumulate(fElectronicsResponseVec.begin(),fElectronicsResponseVec.end(),0.);
131 
132  std::transform(fElectronicsResponseVec.begin(),fElectronicsResponseVec.end(),fElectronicsResponseVec.begin(),std::bind(std::divides<double>(),std::placeholders::_1,respIntegral));
133 
134  // Resize and pad with zeroes
135  fElectronicsResponseFFTVec.resize(fElectronicsResponseVec.size(),std::complex<double>(0.,0.));
136 
138 
139  return;
140 }
141 
142 void ElectronicsResponse::outputHistograms(art::TFileDirectory& histDir) const
143 {
144  // It is assumed that the input TFileDirectory has been set up to group histograms into a common
145  // folder at the calling routine's level. Here we create one more level of indirection to keep
146  // histograms made by this tool separate.
147  std::string dirName = "ElectronicsPlane_" + std::to_string(fPlane);
148 
149  art::TFileDirectory dir = histDir.mkdir(dirName.c_str());
150 
151  std::string histName = "ElectronicsResponse_" + std::to_string(fPlane);
152 
153  double hiEdge = fElectronicsResponseVec.size() * fBinWidth;
154 
155  TProfile* hist = dir.make<TProfile>(histName.c_str(), "Response;Time(us)", fElectronicsResponseVec.size(), 0., hiEdge);
156 
157  for(size_t idx = 0; idx < fElectronicsResponseVec.size(); idx++) hist->Fill(idx * fBinWidth, fElectronicsResponseVec.at(idx), 1.);
158 
159  // Get the FFT of the response
160  icarusutil::TimeVec powerVec;
161 
162  fFFT->getFFTPower(fElectronicsResponseVec, powerVec);
163 
164  // Now we can plot this...
165  double maxFreq = 0.5 / fBinWidth; // binWidth will be in us, maxFreq will be units of MHz
166  double freqWidth = maxFreq / powerVec.size();
167 
168  histName = "FFT_" + histName;
169 
170  TProfile* fftHist = dir.make<TProfile>(histName.c_str(), "Electronics FFT; Frequency(MHz)", powerVec.size(), 0., maxFreq);
171 
172  for(size_t idx = 0; idx < powerVec.size(); idx++)
173  {
174  float bin = (idx + 0.5) * freqWidth;
175 
176  fftHist->Fill(bin, powerVec.at(idx), 1.);
177  }
178 
179  return;
180 }
181 
182 DEFINE_ART_CLASS_TOOL(ElectronicsResponse)
183 }
icarusutil::FrequencyVec fElectronicsResponseFFTVec
static constexpr Sample_t transform(Sample_t sample)
std::vector< ComplexVal > FrequencyVec
constexpr details::BinObj< T > bin(T value)
Returns a wrapper to print the specified data in binary format.
void setResponse(size_t numBins, double binWidth) override
ElectronicsResponse(const fhicl::ParameterSet &pset)
void configure(const fhicl::ParameterSet &pset) override
std::vector< SigProcPrecision > TimeVec
const icarusutil::FrequencyVec & getResponseFFTVec() const override
tuple dir
Definition: dropbox.py:28
const icarusutil::TimeVec & getResponseVec() const override
std::string to_string(WindowPattern const &pattern)
This is the interface class for a tool to handle the electronics response.
std::unique_ptr< icarus_signal_processing::ICARUSFFT< double > > fFFT
Object to handle thread safe FFT.
void outputHistograms(art::TFileDirectory &) const override