All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
AsymExpPulseFunctionTool_tool.cc
Go to the documentation of this file.
1 /**
2  * @file icaruscode/PMT/AsymExpPulseFunctionTool_tool.cc
3  * @brief Toolization of `icarus::opdet::AsymExpPulseFunction<nanosecond>`.
4  * @author Gianluca Petrillo (petrillo@slac.stanford.edu)
5  * @date March 17, 2020
6  * @see `icaruscode/PMT/Algorithms/AsymExpPulseFunction.h`
7  *
8  * This is an implementation of tool interface
9  * `icarus::opdet::SinglePhotonPulseFunctionTool`.
10  */
11 
12 
13 // ICARUS libraries
16 
17 // LArSoft libraries
19 #include "lardataalg/Utilities/quantities_fhicl.h" // nanoseconds from FHiCL
20 
21 // framework libraries
22 #include "art/Utilities/ToolConfigTable.h"
23 #include "art/Utilities/ToolMacros.h"
24 #include "canvas/Utilities/Exception.h"
25 
26 // framework libraries
27 #include "fhiclcpp/types/OptionalAtom.h"
28 #include "fhiclcpp/types/Atom.h"
29 
30 // C/C++ standard libraries
31 #include <memory> // std::unique_ptr()
32 #include <cmath> // std::exp(), std::log()
33 #include <cassert>
34 
35 
36 //------------------------------------------------------------------------------
37 namespace icarus::opdet { struct AsymExpPulseFunctionTool; }
38 /**
39  * @brief Creates a `AsymExpPulseFunction` pulse shape.
40  * @see `icarus::opdet::SinglePhotonPulseFunctionTool`
41  *
42  * This tool creates a `icarus::opdet::AsymExpPulseFunction<nanosecond>`
43  * function to describe a R5912 PMT pulse.
44  *
45  * See `icarus::opdet::AsymExpPulseFunction` for the details of the function.
46  *
47  *
48  * Configuration
49  * --------------
50  *
51  * Run `lar --print-description AsymExpPulseFunctionTool` (or read `Config`
52  * data structure) for a short explanation of the meaning of the parameters.
53  *
54  * In addition, note that the actual amplitude in ADC counts of the pulse is
55  * composed as the product of the amplitude in charge (`PeakCharge`) and
56  * the charge-to-ADC conversion factor (`ADC`).
57  * The latter can be considered as the product of the circuitry impedance
58  * (transforming the charge into a voltage) and the digitization conversion
59  * (full digitizer range divided by the largest output value).
60  *
61  * Finally, note that it is also possible to specify the amplitude of the
62  * function in terms of PMT gain (`Gain` parameter) instead of current
63  * (`PeakAmplitude`), in which case the peak current will be calculated to
64  * have a correct total charge.
65  */
68 {
69 
70  /// Configuration parameters.
71  struct Config {
72 
73  using Name = fhicl::Name;
74  using Comment = fhicl::Comment;
75 
76  fhicl::Atom<nanoseconds> TransitTime {
77  Name("TransitTime"),
78  Comment("peak time from the beginning of the waveform [ns]")
79  // mandatory
80  };
81  // TODO add milliampere to `electromagnetism.h`
82  fhicl::OptionalAtom<float> PeakCurrent {
83  Name("PeakCurrent"),
84  Comment("measured charge current at peak [mA]")
85  };
86  fhicl::OptionalAtom<float> Gain {
87  Name("Gain"),
88  Comment("PMT amplification gain factor")
89  };
90 
91  fhicl::Atom<nanoseconds> RaiseTimeConstant {
92  Name("RaiseTimeConstant"),
93  Comment("raise time constant (exponential raise) [ns]")
94  // mandatory
95  };
96  fhicl::Atom<nanoseconds> FallTimeConstant {
97  Name("FallTimeConstant"),
98  Comment("fall time constant (exponential fall) [ns]")
99  // mandatory
100  };
101  fhicl::Atom<float> ADC {
102  Name("ADC"),
103  Comment("Current-to-ADC conversion factor [ADC counts/mA]")
104  // mandatory
105  };
106 
107  }; // struct Config
108 
109 
110  /// Tool parameter configuration.
111  using Parameters = art::ToolConfigTable<Config>;
112 
113  /// Constructor: sets the configuration.
115  : fPulseFunction(makePulseFunction(config())) {}
116 
117 
118  private:
119 
120  // --- BEGIN -- Virtual interface --------------------------------------------
121 
122  /// Returns the function that was created at construction time.
123  virtual std::unique_ptr<PulseFunction_t> doGetPulseFunction() override
124  { return std::move(fPulseFunction); }
125 
126  // --- END -- Virtual interface ----------------------------------------------
127 
128  /// Function stored while waiting to be delivered.
129  std::unique_ptr<PulseFunction_t> fPulseFunction;
130 
131 
132  /// Creates and returns a pulse function with the specified configuration.
133  static std::unique_ptr<PulseFunction_t> makePulseFunction
134  (Config const& config);
135 
136  /// Computes the peak current value out of the shape and gain parameters [mA].
137  static float peakCurrentFromGain
138  (float gain, nanoseconds raiseTau, nanoseconds fallTau);
139 
140 }; // icarus::opdet::AsymExpPulseFunctionTool
141 
142 
143 //------------------------------------------------------------------------------
144 //--- icarus::opdet::AsymExpPulseFunctionTool implementation
145 //------------------------------------------------------------------------------
147  (Config const& config) -> std::unique_ptr<PulseFunction_t>
148 {
149 
151  using ADCcount = MyFunction_t::ADCcount;
152 
153  // FIXME milliampere not available yet in `electromagnetism.h`
154  double peakCurrent;
155  if (config.Gain().has_value()) { // peak current from gain
156  if (config.PeakCurrent().has_value()) {
157  throw art::Exception(art::errors::Configuration)
158  << "AsymExpPulseFunctionTool: Only one configuration parameter out of '"
159  << config.PeakCurrent.name() << "' (set as " << (*config.PeakCurrent())
160  << ") and '" << config.Gain.name() << "' (set as " << (*config.Gain())
161  << ") can be specified at once!\n";
162  }
163  peakCurrent = peakCurrentFromGain(
164  *config.Gain(), // gain
165  config.RaiseTimeConstant(), // raiseTau
166  config.FallTimeConstant() // fallTau
167  );
168  }
169  else { // peak current directly specified
170  if (!config.PeakCurrent().has_value()) {
171  throw art::Exception(art::errors::Configuration)
172  << "AsymExpPulseFunctionTool: either configuration parameter '"
173  << config.PeakCurrent.name() << "' or '" << config.Gain.name()
174  << "' must be specified!\n";
175  }
176  peakCurrent = *config.PeakCurrent();
177  }
178 
179  return std::make_unique<MyFunction_t>(
180  // amplitude is a charge, so we have to twist the arm of the constructor to
181  // accept it as ADC count (`value()` makes `peakCurrent` lose its unit)
182 // ADCcount(config.ADC() * config.peakCurrent.value()), // amplitude
183  ADCcount(config.ADC() * peakCurrent), // amplitude
184  config.TransitTime(), // peakTime
185  config.RaiseTimeConstant(), // raiseTau
186  config.FallTimeConstant() // fallTau
187  );
188 
189 } // icarus::opdet::AsymExpPulseFunctionTool::makePulseFunction()
190 
191 
192 //------------------------------------------------------------------------------
194  (float gain, nanoseconds raiseTau, nanoseconds fallTau)
195 {
196  static constexpr double electronCharge = -1.602176634e-7; // picocoulomb
197 
198  nanoseconds const dTau = fallTau - raiseTau; // expected positive
199  float const tauRatioLog = std::log(raiseTau / fallTau); // expected negative
200 
201  return gain * electronCharge / dTau.value() * (
202  std::exp(raiseTau / dTau * tauRatioLog)
203  - std::exp(fallTau / dTau * tauRatioLog)
204  );
205 
206 } // icarus::opdet::AsymExpPulseFunctionTool::peakCurrentFromGain()
207 
208 
209 //------------------------------------------------------------------------------
210 DEFINE_ART_CLASS_TOOL(icarus::opdet::AsymExpPulseFunctionTool)
211 
212 
213 //------------------------------------------------------------------------------
214 
art::ToolConfigTable< Config > Parameters
Tool parameter configuration.
AsymExpPulseFunctionTool(Parameters const &config)
Constructor: sets the configuration.
static std::unique_ptr< PulseFunction_t > makePulseFunction(Config const &config)
Creates and returns a pulse function with the specified configuration.
virtual std::unique_ptr< PulseFunction_t > doGetPulseFunction() override
Returns the function that was created at construction time.
Dimensioned variables representing electromagnetic quantities.
constexpr value_t value() const
Returns the value of the quantity.
Definition: quantities.h:609
Tool to create a pulse function for PMT single photon response.
Creates a PhotoelectronPulseFunction pulse shape.
Utilities to read and write quantities in FHiCL configuration.
A value measured in the specified unit.
Definition: quantities.h:566
Pulse from one photoelectron as sum of two exponential functions.
BEGIN_PROLOG vertical distance to the surface Name
Describes the waveform from a single photoelectron.
Creates a AsymExpPulseFunction pulse shape.
std::unique_ptr< PulseFunction_t > fPulseFunction
Function stored while waiting to be delivered.
static float peakCurrentFromGain(float gain, nanoseconds raiseTau, nanoseconds fallTau)
Computes the peak current value out of the shape and gain parameters [mA].