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