All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
BeamGateInfoFromTracks_module.cc
Go to the documentation of this file.
1 /**
2  * @file BeamGateInfoFromTracks_module.cc
3  * @brief Writes a collection of sim::BeamGateInfo from track times.
4  * @author Gianluca Petrillo (petrillo@slac.stanford.edu)
5  * @date November 22, 2021
6  */
7 
8 // LArSoft libraries
12 #include "lardataalg/DetectorInfo/DetectorTimingTypes.h" // simulation_time
13 #include "lardataalg/Utilities/intervals_fhicl.h" // nanoseconds from FHiCL
14 #include "lardataalg/Utilities/quantities/spacetime.h" // nanoseconds, ...
20 
21 // framework libraries
22 #include "art/Framework/Core/SharedProducer.h"
23 #include "art/Framework/Core/ModuleMacros.h"
24 #include "art/Framework/Principal/Event.h"
25 #include "art/Persistency/Common/PtrMaker.h"
26 #include "canvas/Persistency/Common/FindOneP.h"
27 #include "canvas/Persistency/Common/Assns.h"
28 #include "canvas/Persistency/Common/Ptr.h"
29 #include "canvas/Utilities/InputTag.h"
30 #include "canvas/Utilities/Exception.h"
31 #include "cetlib_except/exception.h"
32 #include "messagefacility/MessageLogger/MessageLogger.h"
33 #include "fhiclcpp/types/Atom.h"
34 
35 // C/C++ standard libraries
36 #include <vector>
37 #include <string>
38 #include <memory> // std::make_unique()
39 #include <utility> // std::move()
40 
41 
42 //------------------------------------------------------------------------------
43 namespace icarus::trigger { class BeamGateInfoFromTracks; }
44 
45 /**
46  * @brief Writes a set collection of beam gates into each event.
47  *
48  * This module writes a list of `sim::BeamGateInfo` based on the time associated
49  * to a selection of reconstructed tracks.
50  *
51  * It may be used as input to modules which require to operate on beam gates,
52  * to select time(s) around the reconstructed (and selected) tracks.
53  *
54  *
55  * Input data products
56  * ====================
57  *
58  * This module acts on a _selection_ of tracks, which implies that the input is
59  * a set of _pointers_ to tracks rather than to an actual track collection.
60  * For each track, an associated time is required.
61  *
62  * * `std::vector<art::Ptr<recob::PFParticle>>` (tag from `T0selProducer`):
63  * list of the selected particles to be considered
64  * * `art::Assns<anab::T0, recob::PFParticle>` (tag from `T0Producer`):
65  * association between particles and their time, which must include all
66  * pointers to the tracks listed in `T0selProducer`: each of those particles
67  * must be associated with exactly one `anab::T0`. The time convention is
68  * described in @ref icarus_BeamGateInfoFromTracks_times "its own section".
69  *
70  *
71  * Output data products
72  * =====================
73  *
74  * * `std::vector<sim::BeamGateInfo>`: a collection of as many
75  * `sim::BeamGateInfo` as the `BeamGates` configuration parameter entries,
76  * with the content from them.
77  * * `art::Assns<sim::BeamGateInfo, recob::PFParticle>`: courtesy association
78  * between the selected particle and its gate, in the same order as the
79  * gates in their data product.
80  * * `art::Assns<sim::BeamGateInfo, anab::T0>`: courtesy association between
81  * the particle time and its gate, in the same order as the gates in their
82  * data product.
83  *
84  *
85  * Configuration parameters
86  * =========================
87  *
88  * A terse online description of the parameters is printed by running
89  * `lar --print-description BeamGateInfoFromTracks`.
90  *
91  * * `T0selProducer` (input tag, mandatory): the list of pointers to the
92  * particles to be considered.
93  * * `T0Producer` (input tag, mandatory): the association of particles with
94  * their times.
95  * * `GateStartOffset` (time string, mandatory): the time of the opening of
96  * the gate with respect to the time of the particle; a positive offset means
97  * that the gate starts _after_ the time of the particle.
98  * * `GateEndOffset` (time string, mandatory): the time of the closing of
99  * the gate with respect to the time of the particle.
100  * * `GateType` (string, default: "unknown"): type of the gates being written;
101  * see online description for the configuration keys representing the values
102  * of `sim::GateType`.
103  * * `LogCategory` (string, default: `BeamGateInfoFromTracks`): name of the
104  * output stream category for console messages (managed by MessageFacility
105  * library).
106  *
107  *
108  * @note Time strings are strings with a value and its mandatory unit. For
109  * example, 5.5 microseconds are expressed as `"5.5 us"` or `"5500 ns"`.
110  *
111  * Time scales
112  * ============
113  *
114  * @anchor icarus_BeamGateInfoFromTracks_times
115  *
116  * This module was introduced as a mean to determine the proper time intervals
117  * when to apply a trigger simulation.
118  * It is evident that for this use case a precise result requires the timing
119  * of the gates carefully aligned with the timing of the PMT.
120  * (the convention is that the PMT waveforms have a timestamp in the
121  * @ref DetectorClocksOpticalElectronicsTime "electronics time reference").
122  *
123  * The time of the gates created by this module is offered as
124  * `sim::BeamGateInfo`; LArSoft prescribes it to be be specified in nanoseconds
125  * and in @ref DetectorClocksSimulationTime "simulation time reference").
126  * Designed for simulation, this time scale refers to the opening of the beam
127  * gate (or its surrogate definition in samples with no beam to be gated).
128  * Or so is my understanding of it.
129  *
130  * The input `anab::T0`, on the other end, as produced by the Pandora pattern
131  * recognition algorithm, and ultimately relative to the trigger time. In a
132  * perfectly aligned setup, this is equivalent to the trigger time in real data.
133  *
134  * The output of this module attempts to adhere to that convention, and it
135  * defines the gate boundaries with respect to the beam gate time.
136  *
137  */
138 class icarus::trigger::BeamGateInfoFromTracks: public art::SharedProducer {
139 
140  public:
141 
143 
144  // --- BEGIN Configuration ---------------------------------------------------
145  struct Config {
146 
147  using Name = fhicl::Name;
148  using Comment = fhicl::Comment;
149 
150  enum class GateType_t { // we need to translate enum into a strong type
152  , kBNB = sim::kBNB
153  , kNuMI = sim::kNuMI
154  };
155 
156  /// Selector for `Type` parameter.
158 
159 
160  fhicl::Atom<art::InputTag> T0selProducer {
161  Name("T0selProducer"),
162  Comment
163  ("tag of the selected particles (as a collection of art::Ptr)")
164  // mandatory
165  };
166 
167  fhicl::Atom<art::InputTag> T0Producer {
168  Name("T0Producer"),
169  Comment("tag of the input track time (t0) information")
170  // mandatory
171  };
172 
173 
174  fhicl::Atom<nanoseconds> GateStartOffset {
175  Name("GateStartOffset"),
176  Comment("offset from time track to gate start")
177  };
178 
179  fhicl::Atom<nanoseconds> GateEndOffset {
180  Name("GateEndOffset"),
181  Comment("offset from time track to gate end")
182  };
183 
184  fhicl::Atom<std::string> GateType {
185  Name("GateType"),
186  Comment("beam gate type: " + GateTypeSelector.optionListString()),
188  };
189 
190 
191  fhicl::Atom<std::string> LogCategory {
192  Name("LogCategory"),
193  Comment("name of the category used for the output"),
194  "BeamGateInfoFromTracks" // default
195  };
196 
197 
199  {
200  try {
201  return static_cast<sim::BeamType_t>
203  }
205  {
206  throw art::Exception(art::errors::Configuration)
207  << "Invalid value for '" << GateType.name()
208  << "' parameter: '" << e.label() << "'; valid options: "
209  << GateTypeSelector.optionListString() << ".\n";
210  }
211  } // getGateType()
212 
213 
214  }; // struct Config
215 
216  using Parameters = art::SharedProducer::Table<Config>;
217 
218  // --- END Configuration -----------------------------------------------------
219 
220 
221  // --- BEGIN Constructors ----------------------------------------------------
222 
223  explicit BeamGateInfoFromTracks
224  (Parameters const& config, art::ProcessingFrame const&);
225 
226  // --- END Constructors ------------------------------------------------------
227 
228 
229  // --- BEGIN Framework hooks -------------------------------------------------
230 
231  /// Fills the plots. Also extracts the information to fill them with.
232  virtual void produce(art::Event& event, art::ProcessingFrame const&) override;
233 
234  // --- END Framework hooks ---------------------------------------------------
235 
236 
237  private:
238 
239  // --- BEGIN Configuration variables -----------------------------------------
240 
241  art::InputTag const fT0selProducer; ///< Input particles.
242  art::InputTag const fT0Producer; ///< Input particle/time associations.
243 
244  /// Offset of gate start from particle time.
246  nanoseconds const fGateDuration; ///< Width of the gate being created.
247 
248  sim::BeamType_t const fBeamGateType; ///< Type of gate saved.
249 
250  /// Message facility stream category for output.
251  std::string const fLogCategory;
252 
253  // --- END Configuration variables -------------------------------------------
254 
255 
256 }; // class icarus::trigger::BeamGateInfoFromTracks
257 
258 
259 //------------------------------------------------------------------------------
260 //--- Implementation
261 //------------------------------------------------------------------------------
262 namespace {
263 
264  template <typename T>
265  std::unique_ptr<T> moveToUniquePtr(T& data)
266  { return std::make_unique<T>(std::move(data)); }
267 
268 } // local namespace
269 
270 
271 //------------------------------------------------------------------------------
272 namespace icarus::trigger {
273 
276  {
277  { GateType_t::kUnknown, "unknown" }
278  , { GateType_t::kBNB, "BNB" }
279  , { GateType_t::kNuMI, "NuMI" }
280  };
281 
282 } // namespace icarus::trigger
283 
284 
285 //------------------------------------------------------------------------------
287  (Parameters const& config, art::ProcessingFrame const&)
288  : art::SharedProducer(config)
289  // configuration
290  , fT0selProducer(config().T0selProducer())
291  , fT0Producer(config().T0Producer())
292  , fGateStartOffset(config().GateStartOffset())
293  , fGateDuration(config().GateEndOffset() - fGateStartOffset)
294  , fBeamGateType(config().getGateType())
295  , fLogCategory(config().LogCategory())
296 {
297 
298  async<art::InEvent>();
299 
300  //
301  // output data declaration
302  //
303  produces<std::vector<sim::BeamGateInfo>>();
304  produces<art::Assns<sim::BeamGateInfo, recob::PFParticle>>();
305  produces<art::Assns<sim::BeamGateInfo, anab::T0>>();
306 
307  //
308  // configuration report (short)
309  //
310  auto const& beamType
311  = Config::GateTypeSelector.get(Config::GateType_t(fBeamGateType));
312 
313  mf::LogInfo{ fLogCategory }
314  << "Configuration:"
315  << "\n - particle selection: '" << fT0selProducer.encode() << '\''
316  << "\n - associated times: '" << fT0Producer.encode() << '\''
317  << "\n - gate around particle time: " << fGateStartOffset
318  << " -- " << (fGateStartOffset+fGateDuration)
319  << " (" << fGateDuration << "; gate type: \"" << beamType.name()
320  << "\" [#" << fBeamGateType << "])"
321  ;
322 
323 } // icarus::trigger::BeamGateInfoFromTracks::BeamGateInfoFromTracks()
324 
325 
326 //------------------------------------------------------------------------------
328  (art::Event& event, art::ProcessingFrame const&)
329 {
330 
331  //
332  // fetch input
333  //
334  auto const& particles
335  = event.getProduct<std::vector<art::Ptr<recob::PFParticle>>>(fT0selProducer);
336 
337  mf::LogDebug(fLogCategory)
338  << "Writing gates for " << particles.size() << " particles.";
339 
340  art::FindOneP<anab::T0> const particleT0(particles, event, fT0Producer);
341 
343  art::ServiceHandle<detinfo::DetectorClocksService const>()->DataFor(event)
344  };
345 
346  // add this offset to a time vs. trigger to make it vs. beam gate
347  nanoseconds const triggerToBeamGate
348  = detTimings.TriggerTime() - detTimings.BeamGateTime();
349 
350  //
351  // create the content
352  //
353  std::vector<sim::BeamGateInfo> gates;
354  art::Assns<sim::BeamGateInfo, recob::PFParticle> gateToParticle;
355  art::Assns<sim::BeamGateInfo, anab::T0> gateToTime;
356 
357  art::PtrMaker<sim::BeamGateInfo> const makeGatePtr { event };
358 
359  for (auto const& [ iParticle, particlePtr ]: util::enumerate(particles)) {
360 
361  art::Ptr<anab::T0> const t0Ptr = particleT0.at(iParticle);
362  if (t0Ptr.isNull()) {
363  art::Exception e { art::errors::NotFound };
364  e << "Selected track #" << iParticle << " (";
365  if (particlePtr) e << "ID=" << particlePtr->Self() << ", ";
366  e << "#" << particlePtr.key()
367  << " in its collection) has no associated time."
368  ;
369  throw e << '\n';
370  } // if no T0
371 
372  // t0 is stored in trigger time
374  { util::quantities::points::nanosecond(t0Ptr->Time()) };
375 
376  // 1DetectorTimings1 does not handle the beam gate time when converting to
377  // simulation time, so I need to explicitly add the difference
379  = detTimings.toSimulationTime(t0 + triggerToBeamGate + fGateStartOffset);
380 
381  // time conversion is currently redundant here, left as documentation
382  sim::BeamGateInfo gate {
383  gateStart.value() // start
384  , fGateDuration.convertInto<nanoseconds>().value() // width
385  , fBeamGateType // type
386  };
387 
388  {
389  mf::LogTrace log{ fLogCategory };
390  log << "Gate for selected track #" << iParticle << " (";
391  if (particlePtr) log << "ID=" << particlePtr->Self() << ", ";
392  log << "#" << particlePtr.key()
393  << " in its collection): time = " << t0 << " => "
394  << gate.Start() << " -- " << (gate.Start() + gate.Width())
395  << " ns (" << gate.Width() << " ns)"
396  ;
397  }
398 
399  gates.push_back(std::move(gate));
400 
401  art::Ptr<sim::BeamGateInfo> gatePtr { makeGatePtr(gates.size() - 1) };
402  gateToParticle.addSingle(gatePtr, particlePtr);
403  gateToTime.addSingle(gatePtr, t0Ptr);
404 
405  } // for
406 
407  //
408  // store output
409  //
410  event.put(moveToUniquePtr(gates));
411  event.put(moveToUniquePtr(gateToParticle));
412  event.put(moveToUniquePtr(gateToTime));
413 
414 } // icarus::trigger::BeamGateInfoFromTracks::produce()
415 
416 
417 //------------------------------------------------------------------------------
419 
420 
421 //------------------------------------------------------------------------------
sim::BeamType_t const fBeamGateType
Type of gate saved.
Helper to select an string option among a set of allowed choices.
Definition of util::enumerate().
nanoseconds const fGateDuration
Width of the gate being created.
art::InputTag const fT0selProducer
Input particles.
Option_t const & parse(std::string const &label) const
Returns the option matching the specified label.
static util::MultipleChoiceSelection< GateType_t > const GateTypeSelector
Selector for Type parameter.
std::string optionListString(std::string const &sep=", ") const
Returns a string with the (main) name of all options.
Unknown beam type.
Definition: BeamTypes.h:10
auto enumerate(Iterables &&...iterables)
Range-for loop helper tracking the number of iteration.
Definition: enumerate.h:69
NuMI.
Definition: BeamTypes.h:12
Interface to detinfo::DetectorClocks.
Writes a set collection of beam gates into each event.
fDetProps &fDetProps fDetProps &fDetProps fLogCategory
timescale_traits< TriggerTimeCategory >::time_point_t trigger_time
A point in time on the trigger time scale.
Option_t const & get(Choices_t value) const
Returns the specified option.
BeamGateInfoFromTracks(Parameters const &config, art::ProcessingFrame const &)
timescale_traits< SimulationTimeCategory >::time_point_t simulation_time
A point in time on the simulation time scale.
BEGIN_PROLOG vertical distance to the surface Name
An interval (duration, length, distance) between two quantity points.
Definition: intervals.h:114
std::string name() const
Returns the name of the option (i.e. the main label).
nanoseconds_as<> nanoseconds
Type of time interval stored in nanoseconds, in double precision.
Definition: spacetime.h:270
Utilities to read interval and point quantity FHiCL configuration.
BNB.
Definition: BeamTypes.h:11
art::SharedProducer::Table< Config > Parameters
Dimensioned variables representing space or time quantities.
A class exposing an upgraded interface of detinfo::DetectorClocksData.
Data types for detinfo::DetectorTimings.
do i e
nanosecond_as<> nanosecond
Type of time point stored in nanoseconds, in double precision.
Definition: spacetime.h:339
std::string const fLogCategory
Message facility stream category for output.
temporary value
fDetProps &fDetProps fDetProps &fDetProps detTimings
nanoseconds const fGateStartOffset
Offset of gate start from particle time.
virtual void produce(art::Event &event, art::ProcessingFrame const &) override
Fills the plots. Also extracts the information to fill them with.
BeamType_t
Defines category of beams to be stored in sim::BeamGateInfo.
Definition: BeamTypes.h:9
art::InputTag const fT0Producer
Input particle/time associations.
Choices_t value() const
Returns a copy of the value of the option.