Algorithm class for the full simulation of PMT channels. More...
#include <PMTsimulationAlg.h>
Classes | |
struct | ConfigurationParameters_t |
Type holding all configuration parameters for this algorithm. More... | |
class | GainFluctuator |
class | TimeToTickAndSubtickConverter |
Functor to convert tick point into a tick number and a subsample index. More... | |
Public Types | |
using | microseconds = util::quantities::microsecond |
using | nanoseconds = util::quantities::nanosecond |
using | hertz = util::quantities::hertz |
using | megahertz = util::quantities::megahertz |
using | picocoulomb = util::quantities::picocoulomb |
using | tick = util::quantities::tick |
using | ADCcount = DiscretePhotoelectronPulse::ADCcount |
using | time_interval = detinfo::timescales::time_interval |
using | optical_tick = detinfo::timescales::optical_tick |
Public Member Functions | |
PMTsimulationAlg (ConfigurationParameters_t const &config) | |
Constructor. More... | |
std::tuple< std::vector < raw::OpDetWaveform > , std::optional < sim::SimPhotons > > | simulate (sim::SimPhotons const &photons, sim::SimPhotonsLite const &lite_photons) |
Returns the waveforms originating from simulated photons. More... | |
template<typename Stream > | |
void | printConfiguration (Stream &&out, std::string indent="") const |
Prints the configuration into the specified output stream. More... | |
Private Types | |
using | OpDetWaveformMaker_t = icarus::opdet::OpDetWaveformMakerClass< ADCcount > |
using | Waveform_t = OpDetWaveformMaker_t::WaveformData_t |
Type internally used for storing waveforms. More... | |
using | WaveformValue_t = ADCcount::value_t |
Numeric type in waveforms. More... | |
using | PulseSampling_t = DiscretePhotoelectronPulse::Subsample_t |
Type of sampled pulse shape: sequence of samples, one per tick. More... | |
using | NoiseAdderFunc_t = void(PMTsimulationAlg::*)(Waveform_t &) const |
Type of member function to add electronics noise. More... | |
Private Member Functions | |
auto | makeGainFluctuator () const |
Returns a configured gain fluctuator object. More... | |
Waveform_t | CreateFullWaveform (sim::SimPhotons const &photons, sim::SimPhotonsLite const &lite_photons, std::optional< sim::SimPhotons > &photons_used) const |
Creates raw::OpDetWaveform objects from simulated photoelectrons. More... | |
std::vector< raw::OpDetWaveform > | CreateFixedSizeOpDetWaveforms (raw::Channel_t opChannel, Waveform_t const &waveform) const |
Creates raw::OpDetWaveform objects from a waveform data. More... | |
template<typename Combine > | |
void | AddPulseShape (PulseSampling_t const &pulse, Waveform_t &wave, tick const time_bin, Combine combination) const |
Adds a pulse to a waveform, starting at a given tick. More... | |
void | AddPhotoelectrons (PulseSampling_t const &pulse, Waveform_t &wave, tick const time_bin, WaveformValue_t const n) const |
Adds a number of pulses to a waveform, starting at a given tick. More... | |
void | AddNoise (Waveform_t &wave) const |
void | AddNoise_faster (Waveform_t &wave) const |
Same as AddNoise() but using an alternative generator. More... | |
void | AddDarkNoise (Waveform_t &wave) const |
std::vector< optical_tick > | FindTriggers (Waveform_t const &wvfm) const |
Ticks in the specified waveform where some signal activity starts. More... | |
std::vector< optical_tick > | CreateBeamGateTriggers () const |
Generate periodic interest points regardless the actual activity. More... | |
bool | KicksPhotoelectron () const |
Returns a random response whether a photon generates a photoelectron. More... | |
std::pair< ADCcount, ADCcount > | saturationRange () const |
Returns the ADC range allowed for photoelectron saturation. More... | |
void | ApplySaturation (Waveform_t &waveform, std::pair< ADCcount, ADCcount > const &range) const |
void | ApplySaturation (Waveform_t &waveform) const |
Applies the configured photoelectron saturation on the waveform . More... | |
Static Private Member Functions | |
static void | ClipWaveform (Waveform_t &waveform, ADCcount min, ADCcount max) |
Forces waveform ADC within the min to max range (max included). More... | |
Private Attributes | |
ConfigurationParameters_t | fParams |
Complete algorithm configuration. More... | |
double | fQE |
PMT quantum efficiency. More... | |
megahertz | fSampling |
Wave sampling frequency [MHz]. More... | |
std::size_t | fNsamples |
Samples per waveform. More... | |
DiscretePhotoelectronPulse | wsp |
NoiseAdderFunc_t const | fNoiseAdder |
Single photon pulse (sampled). More... | |
Static Private Attributes | |
static util::FastAndPoorGauss< 32768U, float > const | fFastGauss |
Algorithm class for the full simulation of PMT channels.
The algorithm creates simulated PMT waveforms as read out by ICARUS, including the generation of trigger primitives. Contributions to the waveforms include:
The algorithm processes an optical channel at a time, independently and uncorrelated from the other channels. For each channel, multiple waveforms may be generated according to the readout parameters.
Photons are read from sim::SimPhotons
data objects, each one pertaining a single optical detector channel. Each photon on the channel is assumed to have successfully reached the external surface of the photocathode, with the wavelength shifter. Depending on the upstream simulation, and in particular on the photon visibility library settings, the photon might have also already passed the wavelength shifting and even triggered the conversion to a detectable photoelectron.
Quantum efficiency is simulated to determine if each photon converts into a photoelectron on the internal side of the photocathode. The target quantum efficiency is specified via the QE
configuration parameter. It is assumed that some level of quantum efficiency has already been simulated upstream: more precisely, that the quantum efficiency already applied is in the amount returned by detinfo::LArProperties::ScintPreScale()
. Therefore:
detinfo::LArProperties::ScintPreScale()
to the value in QE
QE
must not exceed detinfo::LArProperties::ScintPreScale()
QE
larger than the one applied upstream (detinfo::LArProperties::ScintPreScale()
), a warning message is printed, and no change to quantum efficiency is performedNote that if the upstream code has not applied any quantum efficiency, the configuration should give a detinfo::LArProperties::ScintPreScale()
of 1.0.
For each converting photon, a photoelectron is added to the channel by placing a template waveform shape into the channel waveform.
The timestamp of each waveform is based on the same scale as the trigger time, as defined by detinfo::DetectorClocks::TriggerTime()
. On that scale, the timestamp pins down the time of the first sample of the waveform. Note that this is typically earlier than when the actual signal starts. More precisely, the signal is defined to start at an interest point (see FindTriggers()
for their definition), and the waveform starts (at tick #0) earlier than that by a fraction PreTrigFraction
of the readout window size ReadoutWindowSize
(both are configuration parameters of the algorithm), allowing for that amount of pre-trigger data.
The configuration parameter TriggerOffsetPMT
describes how much earlier than the trigger time the optical readout has started. Note that if an interest point (see above) happens early after optical readout has started, there might be not enough data to fill the pre-trigger data. In such case, the interest point will just be located earlier than usual within the final waveform. This situation may be caused for example by asynchronous physics events like scintillation light from cosmic rays or radioactive decay of the detector materials, or from a fluctuation of the noise.
The response of the PMT to a single photoelectron is passed to the algorithm as a full blown function of type SinglePhotonResponseFunc_t
. The function needs to be valid for the lifetime of the algorithm, since the algorithm refers to without owning it, and it is expected not to change during that time. See icarus::opdet::SimPMTIcarus
To account for gain fluctuations, that shape is considered to correspond to a nominal gain (PMTspecs.gain
configuration parameter), which is then fluctuated to obtain the effective gain. This feature can be disabled by setting configuration parameter FluctuateGain
to false
. The approximation used here is that the fluctuation is entirely due to the first stage of multiplication. The gain on the first stage is described as a random variable with Poisson distribution around the mean gain. The gain on a single photoelectron at the first stage is, in fact, an integral number in each case. The time spread of the signal may be increased by the difference in time of the different branches of the multiplication avalanche. Therefore, increasing or decreasing the number of branches, as it is done by changing the gain of the first stage, the time evolution of the signal will also be likewise affected. At this time we do not take this aspect into account in the simulation. For the nominal settings of a Hamamatsu 5912 photomultiplier (gain 10 ^7^, high multiplication on the first stage) the gain at the first stage is around 20, causing a fluctuation of about 20%. If the multiplication were equally distributed across the stages, that fluctuation would be almost 45%.
The first stage gain is computed by icarus::opdet::PMTsimulationAlg::ConfigurationParameters_t::PMTspecs_t::multiplicationStageGain()
.
Dark noise, i.e. the noise originating by "spontaneous" emission of a photoelectron in the photocathode without any external stimulation, is simulated by randomly extracting the time such emission happens. Each emission causes a photoelectron template waveform to be added at the extracted time. The rate of dark noise emission is set by configuration with DarkNoiseRate
parameter.
Electronics noise is described by Gaussian fluctuations of a given standard deviation, controlled by the configuration parameter AmpNoise
. No noise correlation is simulated neither in time nor in space.
PMT specifications are used to evaluate the variance of the gain. The details of the calculation are documented in icarus::opdet::PMTsimulationAlg::ConfigurationParameters_t::PMTspecs_t::multiplicationStageGain()
.
The available parameters include:
gain
(default: 1e7
): the nominal gain of the PMT; this is just a reference value.voltageDistribution
is a sequence of values, one for each stage of the multiplication chain of the PMT. Each number represents the relative size of the resistance that determines the fall of the potential on that stage. Only the stages that contribute to the gain need to be included. The absolute value of each element is inconsequential. For example, a 10-stage PMT with the first stage having twice the resistance of all the other would be represented by the setting [ 2, 1, 1, 1, 1, 1, 1, 1, 1, 1 ]
.dynodeK
(default: 0.75
) represents the dependence of the gain of a stage on the potential drop: (with the gain for stage , the drop of potential of that stage and the parameter set by dynodeK
.Three independent random engines are currently used in the simulation:
This section needs completion.
The algorithm is serviceable immediately after construction. Construction relies on a custom parameter data structure.
An utility, PMTsimulationAlgMaker
, splits the set up in two parts:
This is supposed to make the creation of the filling of parameter structure and the creation of the algorithm easier. At that point, a single sim::SimPhotons
can be processed (simulate()
) at a time, or multiple at the same time (see the multithreading notes below).
The function used to describe the single particle response is customizable and it must in fact be specified by the caller, since there is no default form. The function must implement the PulseFunction_t
interface.
The algorithm processes one channel at a time, and it does not depend on event-level information; therefore, the same algorithm object can be used to process many events in sequence. On the other hand, multithreading is impaired by the random number generation, in the sense that multithreading will break reproducibility if the random engine is not magically thread-resistant.
If the set up is event-dependent, then this object can't be used for multiple events at the same time. There is no global state, so at least different instances of the algorithm can be run at the same time. In fact, the creation of an algorithm is expected to take negligible time compared to its run time on a single event, and it is conceivable to create a new algorithm instance for each event.
Definition at line 341 of file PMTsimulationAlg.h.
Definition at line 350 of file PMTsimulationAlg.h.
Definition at line 346 of file PMTsimulationAlg.h.
Definition at line 347 of file PMTsimulationAlg.h.
Definition at line 344 of file PMTsimulationAlg.h.
Definition at line 345 of file PMTsimulationAlg.h.
|
private |
Type of member function to add electronics noise.
Definition at line 531 of file PMTsimulationAlg.h.
|
private |
Definition at line 521 of file PMTsimulationAlg.h.
Definition at line 353 of file PMTsimulationAlg.h.
Definition at line 348 of file PMTsimulationAlg.h.
|
private |
Type of sampled pulse shape: sequence of samples, one per tick.
Definition at line 528 of file PMTsimulationAlg.h.
Definition at line 349 of file PMTsimulationAlg.h.
Definition at line 352 of file PMTsimulationAlg.h.
Type internally used for storing waveforms.
Definition at line 524 of file PMTsimulationAlg.h.
|
private |
Numeric type in waveforms.
Definition at line 525 of file PMTsimulationAlg.h.
icarus::opdet::PMTsimulationAlg::PMTsimulationAlg | ( | ConfigurationParameters_t const & | config | ) |
Constructor.
Definition at line 102 of file PMTsimulationAlg.cxx.
|
private |
Definition at line 595 of file PMTsimulationAlg.cxx.
|
private |
Definition at line 558 of file PMTsimulationAlg.cxx.
|
private |
Same as AddNoise()
but using an alternative generator.
Definition at line 571 of file PMTsimulationAlg.cxx.
|
private |
Adds a number of pulses to a waveform, starting at a given tick.
pulse | the sampling to add, scaled, to the waveform |
wave | the waveform the pulses will be added to |
time_bin | the tick of the waveform where the pulses start being added |
n | the number of pulses added (it may be fractional) |
All the samples of pulse
are scaled by the factor n
and then added to the sampling waveform wave
, starting from the time_bin
sample of this waveform.
The pulse
samples are a sequence of ADC counts describing the single photoelectron pulse shape. The waveform is also a sequence of samples representing a optical detector channel digitized waveform, starting at tick #0.
Definition at line 517 of file PMTsimulationAlg.cxx.
|
private |
Adds a pulse to a waveform, starting at a given tick.
Combine | binary operation combining two ADC counts into one |
pulse | the sampling to add to the waveform |
wave | the waveform the pulse will be added to |
time_bin | the tick of the waveform where the pulse starts |
combination | how to combine the pulse and the waveform |
This is the internal implementation of AddPhotoelectrons()
.
The combination
functor behaves as a binary function taking the existing wave
sample and the sample from the pulse
at the same time and returning their combination as a new sample value.
Definition at line 538 of file PMTsimulationAlg.cxx.
|
private |
Applies the configured photoelectron saturation on the waveform
, only if the saturation is cutting into the digitisation range
.
Definition at line 681 of file PMTsimulationAlg.cxx.
|
private |
Applies the configured photoelectron saturation on the waveform
.
Definition at line 668 of file PMTsimulationAlg.cxx.
|
staticprivate |
Forces waveform
ADC within the min
to max
range (max
included).
Definition at line 700 of file PMTsimulationAlg.cxx.
|
private |
Generate periodic interest points regardless the actual activity.
FindTriggers()
This methods emits a list of interest points according to the algorithm configuration. More precisely, if CreateBeamGateTriggers
is configured true
, BeamGateTriggerNReps
interest points are generated at BeamGateTriggerRepPeriod
intervals, starting from the beam gate time as defined by detinfo::DetectorClocks::BeamGateTime()
.
See FindTriggers()
for the meaning of "interest point".
0
happens at a time defined by triggerOffsetPMT
configuration parameter after the trigger (but since the value of that parameter is expected to be negative, tick 0
effectively happens before the trigger). Definition at line 341 of file PMTsimulationAlg.cxx.
|
private |
Creates raw::OpDetWaveform
objects from a waveform data.
opChannel | number of optical detector channel the data belongs to |
waveform | the waveform data |
raw::OpDetWaveform
The waveform data is a sequence of samples on the optical detector channel, starting at the beginning of the optical time clock, that is set by the algorithm configuration as the global hardware trigger time (configured in detinfo::DetectorClocks
) and an offset. It may be obtained from CreateFullWaveform()
.
Multiple waveforms may be returned for a single channel, since a form of zero suppression is applied by the simulated hardware. The waveforms are guaranteed to be non-overlapping, non-contiguous and sorted with increasing timestamp.
The procedure attempts to mimic the working mode of CAEN V1730B boards as described on page 32 of the manual "UM2792_V1730_V1725_rev2.pdf" in SBN DocDB 15024.
In the board readout language, the "trigger" is the per-channel information that the signal on the channel has passed the threshold.
It is critical to understand the details of the generation of the triggers. At the time of writing, the algorithm in FindTriggers()
emits a trigger every time the signal passes from under threshold to beyond threshold. Assuming that the threshold is at less than one photoelectron, this kind of behavior implies that every scintillation photons arriving on the tail of the first (large?) signal will add a new waveform in tail. It is not clear what happens if two more triggers happen while the window from the first trigger is still open.
The assumptions in the code include:
The fixed duration of the waveform if the sum of pre- and post-trigger window length. If during this window another trigger is emitted, a new window will follow the current one and it will be long enough to contain all the post-trigger data.
Definition at line 409 of file PMTsimulationAlg.cxx.
|
private |
Creates raw::OpDetWaveform
objects from simulated photoelectrons.
photons | the simulated list of photoelectrons |
photons_used | (output) list of used photoelectrons |
raw::OpDetWaveform
objectsThis function performs the digitization of a optical detector channel which is collecting the photoelectrons in the photons
list.
The photoelectrons are already screened for quantum efficiency: all of them are considered for use. It is still possible, if a reduction of the quantum efficiency is requested, that some of them are discarded.
The photons_used
output argument is constructed and filled only if the configuration of the algorithm requires the creation of a list of used photons.
Definition at line 185 of file PMTsimulationAlg.cxx.
|
private |
Ticks in the specified waveform where some signal activity starts.
CreateBeamGateTriggers()
We define an "interest point" a time when some activity in the waveform is considered interesting enough to be recorded. This method returns a list of interest points, in the form of the index they are located at in the waveform wvfm
.
In general (but with the exception noted below), a time becomes an interest point if the sample recorded at that time is above the threshold set by the configuration parameter ThresholdADC
.
These interest points are local readout triggers that drive zero suppression on the optical readout channel and that are not necessarily causing any level of event trigger.
This method also adds the mandatory beam gate interest points as explained in CreateBeamGateTriggers()
documentation. These are additional interest points that are added independently of whether there is actual interesting activity in there.
Definition at line 368 of file PMTsimulationAlg.cxx.
|
private |
Returns a random response whether a photon generates a photoelectron.
Definition at line 512 of file PMTsimulationAlg.cxx.
|
private |
Returns a configured gain fluctuator object.
Definition at line 169 of file PMTsimulationAlg.cxx.
void icarus::opdet::PMTsimulationAlg::printConfiguration | ( | Stream && | out, |
std::string | indent = "" |
||
) | const |
Prints the configuration into the specified output stream.
Definition at line 1064 of file PMTsimulationAlg.h.
|
private |
Returns the ADC range allowed for photoelectron saturation.
Definition at line 653 of file PMTsimulationAlg.cxx.
std::tuple< std::vector< raw::OpDetWaveform >, std::optional< sim::SimPhotons > > icarus::opdet::PMTsimulationAlg::simulate | ( | sim::SimPhotons const & | photons, |
sim::SimPhotonsLite const & | lite_photons | ||
) |
Returns the waveforms originating from simulated photons.
photons | all the photons simulated to land on the channel |
Due to threshold readout, a single channel may result in multiple waveforms, which are all on the same channel but disjunct in time.
The second element of the return value is optional and filled only if the trackSelectedPhotons
configuration parameter is set to true
. In that case, the returned sim::SimPhotons
contains a copy of each of the photons
contributing to any of the waveforms.
Definition at line 153 of file PMTsimulationAlg.cxx.
|
staticprivate |
Definition at line 589 of file PMTsimulationAlg.h.
|
private |
Single photon pulse (sampled).
Selected electronics noise method. Transformation uniform to Gaussian for electronics noise.
Definition at line 586 of file PMTsimulationAlg.h.
|
private |
Samples per waveform.
Definition at line 582 of file PMTsimulationAlg.h.
|
private |
Complete algorithm configuration.
Definition at line 578 of file PMTsimulationAlg.h.
|
private |
PMT quantum efficiency.
Definition at line 580 of file PMTsimulationAlg.h.
|
private |
Wave sampling frequency [MHz].
Definition at line 581 of file PMTsimulationAlg.h.
|
private |
Definition at line 584 of file PMTsimulationAlg.h.