geo_types_fhicl.h
Go to the documentation of this file.
1 /**
2  * @file larcoreobj/SimpleTypesAndConstants/geo_types_fhicl.h
3  * @brief Utilities for using geometry IDs in FHiCL validated configuration.
4  * @author Gianluca Petrillo (petrillo@slac.stanford.edu)
5  * @date November 25, 2019
6  *
7  * This library is header-only.
8  */
9 
10 #ifndef LARCOREOBJ_SIMPLETYPESANDCONSTANTS_GEO_TYPES_FHICL_H
11 #define LARCOREOBJ_SIMPLETYPESANDCONSTANTS_GEO_TYPES_FHICL_H
12 
13 
14 // LArSoft libraries
16 
17 // support libraries
19 #include "fhiclcpp/types/Table.h"
23 #include "fhiclcpp/types/Atom.h"
24 
25 // C/C++ standard libraries
26 #include <vector>
27 #include <optional>
28 #include <cstddef> // std::size_t
29 
30 
31 /// FHiCL objects representing geometry classes as configuration parameters.
32 namespace geo::fhicl {
33 
34  // --- BEGIN -- Validated configuration parameters for geometry ID objects ---
35  /**
36  * @name Validated configuration parameters for geometry ID objects
37  *
38  * These data types can be used in a class for validated FHiCL configuration.
39  * They are implemented as configuration tables (`fhicl::Table`) of a
40  * configuration structure containing one parameter (`fhicl::Atom`) per index
41  * in the ID. They do _not_ support default values, but optional parameters
42  * may be used as a workaround.
43  * Unfortunately, they do not exactly follow the usage pattern of the standard
44  * FHiCL objects, and helper functions are provided to facilitate their use:
45  * * simple IDs _do_ support the standard usage pattern, except that they do
46  * not support default values; it is nevertheless safer to use
47  * `geo::fhicl::readID()`;
48  * * optional IDs are better read with `geo::fhicl::readOptionalID()`, which
49  * returns a `std::optional` object;
50  * * ID sequences are better read with `geo::fhicl::readIDsequence()`, which
51  * returns a STL vector of IDs;
52  * * optional ID sequences are better read with
53  * `geo::fhicl::readOptionalIDsequence()`, which returns a `std::optional`
54  * object containing a STL vector of IDs.
55  *
56  * In addition, a _unified interface_ is provided and recommended (see below).
57  *
58  * An ID described data member can be specified as a table with the same
59  * syntax as the standard printout of the IDs, e.g. `{ C:1 T:3 P:2 }`
60  * for the plane `C:1 T:3 P:2`.
61  * Example:
62  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
63  * struct Config {
64  *
65  * geo::fhicl::PlaneIDsequence Planes {
66  * fhicl::Name("Planes"),
67  * fhicl::Comment("anode planes to process")
68  * };
69  *
70  * geo::fhicl::OptionalPlaneID ReferencePlane {
71  * fhicl::Name("ReferencePlane"),
72  * fhicl::Comment("reference anode plane (first one by default)")
73  * };
74  *
75  * }; // struct Config
76  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
77  * which can be configured as:
78  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
79  * Planes: [
80  * { C:0 T:1 P:0 },
81  * { C:0 T:1 P:1 },
82  * { C:0 T:1 P:2 }
83  * ]
84  * ReferencePlane: { C:0 T:1 P:2 }
85  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
86  * and read as:
87  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
88  * void readParams(art::EDProducer::Table<Config> const& config) {
89  *
90  * std::vector<geo::PlaneID> const planes
91  * = geo::fhicl::readIDsequence(config().Planes);
92  * if (planes.empty()) {
93  * throw art::Exception(art::errors::Configuration)
94  * << "At least one plane is needed.\n";
95  * }
96  *
97  * geo::PlaneID const refPlane
98  * = geo::fhicl::readOptionalID(config().ReferencePlane)
99  * .value_or(planes.front())
100  * ;
101  *
102  * } // readParams()
103  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
104  *
105  * As mentioned above, currently default values are not supported.
106  * The workaround is to use the "optional" version of the objects.
107  * Utilities are provided to read them: the function
108  * `geo::fhicl::readOptionalID()` reading a single optional ID was illustrated
109  * in the previous example, while for optional sequences of IDs the following
110  * usage pattern is suppported via `geo::fhicl::readOptionalIDsequence()`:
111  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
112  * struct Config {
113  *
114  * geo::fhicl::OptionalPlaneIDsequence Planes {
115  * fhicl::Name("Planes"),
116  * fhicl::Comment("anode planes to process (omit or empty processes all)")
117  * };
118  *
119  * }; // struct Config
120  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
121  * reading as:
122  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
123  * void readParams(art::EDProducer::Table<Config> const& config) {
124  *
125  * std::vector<geo::PlaneID> planes
126  * = geo::fhicl::readOptionalIDsequence(config().Planes, {});
127  *
128  * } // readParams()
129  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
130  * Note however that the default value will not show in the regular
131  * `lar --print-description` output.
132  *
133  *
134  * Unified interface
135  * ==================
136  *
137  * A "unified" interface is provided to read all the ID parameters with the
138  * same syntax. Given a parameter (`configPar`) to read, the syntax is:
139  * * `readParameter(configPar)` to read the parameter
140  * * if the parameter is optional, a `std::optional` object wrapping the
141  * parameter value (if any) is returned
142  * * if the parameter is a sequence, the value is stored in a
143  * `std::vector` object (otherwise just in an object with the proper ID
144  * type)
145  * * `readParameter(configPar, defValue)` to read the parameter (which must
146  * be optional) and return directly the value of the parameter, if
147  * specified, or a default value otherwise.
148  *
149  * A (long) example follows, showing how to read the wire ID parameters of
150  * this configuration:
151  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
152  * struct Config {
153  *
154  * geo::fhicl::WireID Wire { fhicl::Name("Wire") };
155  *
156  * geo::fhicl::OptionalWireID MaybeWire { fhicl::Name("MaybeWire") };
157  *
158  * geo::fhicl::WireIDsequence Wires { fhicl::Name("Wires") };
159  *
160  * geo::fhicl::OptionalWireIDsequence MaybeWires { fhicl::Name("MaybeWires") };
161  *
162  * }; // struct Config
163  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
164  * Here is how the unified interface reads them (the optional ones are read
165  * twice to show reading with and without default values):
166  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
167  * void readParameters(fhicl::Table<Config> const& config) {
168  *
169  * ID_t const defaultID { 1U, 5U, 0U, 9U };
170  *
171  * std::vector<ID_t> const defaultIDs
172  * ({ ID_t{ 1U, 5U, 0U, 4U }, ID_t{ 1U, 5U, 0U, 3U } });
173  *
174  * // id11 is `geo::WireID`:
175  * auto id11 = geo::fhicl::readParameter(config().Wire);
176  *
177  * // id21 is `std::optional<geo::WireID>`
178  * auto id21 = geo::fhicl::readParameter(config().MaybeWire);
179  *
180  * // id22 is `geo::WireID`
181  * auto id22 = geo::fhicl::readParameter(config().MaybeWire, defaultID);
182  *
183  * // id31 is `std::vector<geo::WireID>`
184  * auto id31 = geo::fhicl::readParameter(config().Wires);
185  *
186  * // id41 is `std::optional<std::vector<geo::WireID>>`
187  * auto id41 = geo::fhicl::readParameter(config().MaybeWires);
188  *
189  * // id42 is `std::vector<geo::WireID>`
190  * auto id42 = geo::fhicl::readParameter(config().MaybeWires, defaultIDs);
191  *
192  * }
193  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
194  *
195  */
196  /// @{
197 
198  //@{
199  /**
200  * @brief Traits for ID parameter objects
201  * @tparam IDparam the ID parameter object
202  *
203  * This set offers the following traits:
204  * * `type`: type of parameter (same as `IDparam`)
205  * * `ID_t`: type of ID read by the parameter
206  * * `isOptional` (boolean): whether the parameter is optional
207  * * `isAtom` (boolean): whether the parameter reads a single ID
208  * * `isSequence` (boolean): whether the parameter reads a sequence of ID's
209  *
210  * The trait class is defined only for the supported parameter types.
211  */
212  template <typename IDparam>
214  //@}
215 
216  //@{
217  /// Type of ID of the specified ID FHiCL parameter object/
218  template <typename IDparam>
220  //@}
221 
222 
223  // --- BEGIN -- Generic ID infrastructure ------------------------------------
224  /// Helper class holding the ID validity flag.
225  struct ValidIDConfig {
226 
228  ::fhicl::Name("isValid"),
229  ::fhicl::Comment("whether the ID is valid"),
230  true
231  };
232 
233  bool valid() const { return isValid(); }
234 
235  }; // struct ValidIDConfig
236 
237 
238  /// Type of ID configuration structure (requires specialization)
239  template <typename IDtype>
240  struct IDConfig;
241 
242  /// Member type of validated ID parameter.
243  template <typename IDtype>
245 
246  /// Member type of optional validated ID parameter.
247  template <typename IDtype>
249 
250  /// Member type of sequence of ID parameters.
251  template <typename IDtype>
253 
254  /// Member type of optional sequence of ID parameters.
255  template <typename IDtype>
257 
258  // --- END -- Generic ID infrastructure --------------------------------------
259 
260 
261  // --- BEGIN -- Cryostat ID --------------------------------------------------
262  /// Configuration structure for validated `geo::CryostatID` parameter.
263  template <>
265  using ID_t = geo::CryostatID; ///< Type read by this configuration.
266 
268  ::fhicl::Name("C"),
269  ::fhicl::Comment("cryostat number"),
270  [this](){ return valid(); }
271  };
272 
273  ID_t ID() const { return !valid()? ID_t{}: ID_t{ C() }; }
274  operator ID_t() const { return ID(); }
275 
276  }; // struct IDConfig<geo::CryostatID>
277 
278  /// Member type of validated `geo::CryostatID` parameter.
280 
281  /// Member type of optional validated `geo::CryostatID` parameter.
283 
284  /// Member type of sequence of `geo::CryostatID` parameters.
286 
287  /// Member type of optional sequence of `geo::CryostatID` parameters.
289 
290  // --- END -- Cryostat ID ----------------------------------------------------
291 
292 
293  // --- BEGIN -- TPC ID -------------------------------------------------------
294  /// Configuration structure for validated `geo::TPCID` parameter.
295  template <>
296  struct IDConfig<geo::TPCID>: public IDConfig<geo::CryostatID> {
297  using ID_t = geo::TPCID; ///< Type read by this configuration.
298 
300  ::fhicl::Name("T"),
301  ::fhicl::Comment("TPC number within the cryostat"),
302  [this](){ return valid(); }
303  };
304 
305  ID_t ID() const
306  { return !valid()? ID_t{}: ID_t{ IDConfig<geo::CryostatID>::ID(), T() }; }
307  operator ID_t() const { return ID(); }
308  }; // struct IDConfig<geo::TPCID>
309 
310  /// Member type of validated `geo::TPCID` parameter.
312 
313  /// Member type of optional validated `geo::TPCID` parameter.
315 
316  /// Member type of sequence of `geo::TPCID` parameters.
318 
319  /// Member type of optional sequence of `geo::TPCID` parameters.
321 
322  // --- END -- TPC ID ---------------------------------------------------------
323 
324 
325  // --- BEGIN -- Optical detector ID ------------------------------------------
326  /// Configuration structure for validated `geo::OpDetID` parameter.
327  template <>
328  struct IDConfig<geo::OpDetID>: public IDConfig<geo::CryostatID> {
329  using ID_t = geo::OpDetID; ///< Type read by this configuration.
330 
332  ::fhicl::Name("O"),
333  ::fhicl::Comment("Optical detector number within the cryostat"),
334  [this](){ return valid(); }
335  };
336 
337  ID_t ID() const
338  { return !valid()? ID_t{}: ID_t{ IDConfig<geo::CryostatID>::ID(), O() }; }
339  operator ID_t() const { return ID(); }
340  }; // struct IDConfig<geo::OpDetID>
341 
342  /// Member type of validated `geo::OpDetID` parameter.
344 
345  /// Member type of optional validated `geo::OpDetID` parameter.
347 
348  /// Member type of sequence of `geo::OpDetID` parameters.
350 
351  /// Member type of optional sequence of `geo::OpDetID` parameters.
353 
354  // --- END -- Optical detector ID --------------------------------------------
355 
356 
357  // --- BEGIN -- Plane ID -----------------------------------------------------
358  /// Configuration structure for validated `geo::PlaneID` parameter.
359  template <>
360  struct IDConfig<geo::PlaneID>: public IDConfig<geo::TPCID> {
361  using ID_t = geo::PlaneID; ///< Type read by this configuration.
362 
364  ::fhicl::Name("P"),
365  ::fhicl::Comment("Plane number within the TPC"),
366  [this](){ return valid(); }
367  };
368 
369  ID_t ID() const
370  { return !valid()? ID_t{}: ID_t{ IDConfig<geo::TPCID>::ID(), P() }; }
371  operator ID_t() const { return ID(); }
372  }; // struct IDConfig<geo::PlaneID>
373 
374  /// Member type of validated `geo::PlaneID` parameter.
376 
377  /// Member type of optional validated `geo::PlaneID` parameter.
379 
380  /// Member type of sequence of `geo::PlaneID` parameters.
382 
383  /// Member type of optional sequence of `geo::PlaneID` parameters.
385 
386  // --- END -- Plane ID -------------------------------------------------------
387 
388 
389  // --- BEGIN -- Wire ID ------------------------------------------------------
390  /// Configuration structure for validated `geo::PlaneID` parameter.
391  template <>
392  struct IDConfig<geo::WireID>: public IDConfig<geo::PlaneID> {
393  using ID_t = geo::WireID; ///< Type read by this configuration.
394 
396  ::fhicl::Name("W"),
397  ::fhicl::Comment("Wire number within the plane"),
398  [this](){ return valid(); }
399  };
400 
401  ID_t ID() const
402  { return !valid()? ID_t{}: ID_t{ IDConfig<geo::PlaneID>::ID(), W() }; }
403  operator ID_t() const { return ID(); }
404  }; // struct IDConfig<geo::WireID>
405 
406  /// Member type of validated `geo::WireID` parameter.
408 
409  /// Member type of optional validated `geo::WireID` parameter.
411 
412  /// Member type of sequence of `geo::WireID` parameters.
414 
415  /// Member type of optional sequence of `geo::WireID` parameters.
417 
418  // --- END -- Wire ID --------------------------------------------------------
419 
420 
421  // --- BEGIN -- ID parsing ---------------------------------------------------
422 
423  //@{
424  /**
425  * @brief Returns an ID extracted from the specified ID atom.
426  * @tparam SrcID type of the ID read by the FHiCL parameter
427  * @tparam ID type of the returned ID (default: same as `SrcID`)
428  * @param atom the ID atom parameter to convert
429  * @return an `ID` object converted from `atom`
430  *
431  * This function is trivial and provided mostly for uniformity of interface.
432  * In the standard usage is equivalent to using the `atom` directly:
433  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
434  * struct Config {
435  *
436  * geo::fhicl::TPCID TPC { fhicl::Name("TPC"), fhicl::Comment("TPC") };
437  *
438  * };
439  *
440  * void newInterface(art::EDProducer::Table<Config> const& config) {
441  *
442  * geo::TPCID const tpcid = geo::fhicl::readID(config().TPC);
443  *
444  * // ...
445  * }
446  *
447  * void classicInterface(art::EDProducer::Table<Config> const& config) {
448  *
449  * geo::TPCID const tpcid = config().TPC();
450  *
451  * // ...
452  * }
453  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
454  * has `newInterface()` and `classicInterface()` completely equivalent.
455  * Note however that because of inplementation details, `config().TPC()`
456  * (classic interface) _does not_ return a `geo::TPCID` object, but a
457  * different, implementation dependent object that is converted upon
458  * assignment. This implies that the following variables may have different
459  * types, and the new interface is the one guaranteeing the right type:
460  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
461  * auto tpcidNew = geo::fhicl::readID(config().TPC); // type is geo::TPCID
462  * auto tpcidClassic = config().TPC(); // type is implementation dependent
463  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
464  *
465  * @note The additional template parameter `ID` is provided as an added bonus
466  * to choose which type to convert the configuration parameters into,
467  * and it's not enforced to be a ID type at all.
468  */
469  template <typename SrcID, typename ID = SrcID>
470  ID readID(IDparameter<SrcID> const& atom);
471 
472  template <typename SrcID, typename ID = SrcID>
474  { return readID<SrcID, ID>(atom); }
475  //@}
476 
477 
478  //@{
479  /**
480  * @brief Returns an ID extracted from the specified optional ID atom.
481  * @tparam SrcID type of the ID read by the FHiCL parameter
482  * @tparam ID type of the returned ID (default: same as `SrcID`)
483  * @param atom the optional ID atom parameter to convert
484  * @return an `ID` object converted from `atom`, or no value if omitted
485  *
486  * The return type of this function is of type `std::optional`.
487  * This function returns the value of the specified FHiCL optional atom
488  * (`fhicl::OptionalAtom`). If the parameter was omitted, no value is
489  * returned.
490  *
491  * Example of usage: the configuration object `Config` and the data member to
492  * store the configuration parameter value are defined in a class as:
493  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
494  * struct Config {
495  *
496  * geo::fhicl::OptionalTPCID refTPC
497  * { fhicl::Name("refTPC"), fhicl::Comment("reference TPC") };
498  *
499  * };
500  *
501  * std::optional<geo::TPCID> fRefTPC;
502  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
503  * The constructor of that class should have an entry in the initializer list
504  * like:
505  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
506  * fRefTPC(geo::fhicl::readOptionalID(config().RefTPC))
507  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
508  * (note that the argument is just `config().RefTPC`, not
509  * `config().RefTPC()`).
510  *
511  * @note The additional template parameter `ID` is provided as an added bonus
512  * to choose which type to convert the configuration parameters into,
513  * and it's not enforced to be a ID type at all.
514  */
515  template <typename SrcID, typename ID = SrcID>
516  std::optional<ID> readOptionalID(OptionalID<SrcID> const& atom);
517 
518  template <typename SrcID, typename ID = SrcID>
519  std::optional<ID> readParameter(OptionalID<SrcID> const& atom)
520  { return readOptionalID<SrcID, ID>(atom); }
521  //@}
522 
523 
524  //@{
525  /**
526  * @brief Returns an ID extracted from the specified optional ID atom.
527  * @tparam SrcID type of the ID read by the FHiCL parameter
528  * @tparam ID type of the returned ID (default: same as `SrcID`)
529  * @param atom the optional ID atom parameter to convert
530  * @param defValue a value to use if the parameter was omitted
531  * @return an `ID` object converted from `atom`, or `defValue` if omitted
532  *
533  * This function returns the value of the specified FHiCL optional atom
534  * (`fhicl::OptionalAtom`). If the parameter was omitted, the `defValue` is
535  * copied or moved depending on the function.
536  *
537  * Example of usage: the configuration object `Config` and the data member to
538  * store the configuration parameter value are defined in a class as:
539  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
540  * struct Config {
541  *
542  * geo::fhicl::OptionalTPCID refTPC
543  * { fhicl::Name("refTPC"), fhicl::Comment("reference TPC") };
544  *
545  * };
546  *
547  * std::optional<geo::TPCID> fRefTPC;
548  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
549  * The constructor of that class should have an entry in the initializer list
550  * like:
551  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
552  * fRefTPC(geo::fhicl::readOptionalID(config().RefTPC, { 0U, 0U }))
553  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
554  * will set `fRefTPC` to `C:0 T:0` TPC ID if `refTPC` was omitted from the
555  * configuration (note that the argument is just `config().RefTPC`, not
556  * `config().RefTPC()`).
557  *
558  * @note The additional template parameter `ID` is provided as an added bonus
559  * to choose which type to convert the configuration parameters into,
560  * and it's not enforced to be a ID type at all.
561  */
562  template <typename SrcID, typename ID = SrcID>
563  ID readOptionalID(OptionalID<SrcID> const& atom, ID const& defValue);
564 
565  template <typename SrcID, typename ID = SrcID>
566  ID readOptionalID(OptionalID<SrcID> const& atom, ID&& defValue);
567 
568  template <typename SrcID, typename ID = SrcID>
569  ID readParameter(OptionalID<SrcID> const& atom, ID const& defValue)
570  { return readOptionalID<SrcID, ID>(atom, defValue); }
571 
572  template <typename SrcID, typename ID = SrcID>
573  ID readParameter(OptionalID<SrcID> const& atom, ID&& defValue)
574  { return readOptionalID<SrcID, ID>(atom, std::move(defValue)); }
575  //@}
576 
577 
578  //@{
579  /**
580  * @brief Returns a vector of IDs extracted from the specified ID sequence.
581  * @tparam SrcID type of the ID read by the FHiCL parameter
582  * @tparam ID type of the returned ID (default: same as `SrcID`)
583  * @param seq the sequence of ID parameters to convert
584  * @return a STL vector of `ID` objects converted from `seq` parameter values
585  *
586  * This function returns the value of the specified FHiCL sequence object
587  * (`fhicl::Sequence`). It supports both fixed and variable size sequences,
588  * but it always returns a STL vector as a result.
589  *
590  * Example of usage: the configuration object `Config` and the data member to
591  * store the configuration parameter value are defined in a class as:
592  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
593  * struct Config {
594  *
595  * geo::fhicl::TPCIDsequence TPCs
596  * { fhicl::Name("TPCs"), fhicl::Comment("selected TPCs") };
597  *
598  * };
599  *
600  * std::vector<geo::TPCID> fTPCs;
601  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
602  * The constructor of that class should have an entry in the initializer list
603  * like:
604  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
605  * fTPCs(geo::fhicl::readIDsequence(config().TPCs))
606  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
607  * (note that the argument is just `config().TPCs`, not `config().TPCs()`).
608  *
609  * @note The additional template parameter `ID` is provided as an added bonus
610  * to choose which type to convert the configuration parameters into,
611  * and it's not enforced to be a ID type at all.
612  */
613  template <typename SrcID, typename ID = SrcID>
614  std::vector<ID> readIDsequence(IDsequence<SrcID> const& seq);
615 
616  template <typename SrcID, typename ID = SrcID>
617  std::vector<ID> readParameter(IDsequence<SrcID> const& seq)
618  { return readIDsequence<SrcID, ID>(seq); }
619  //@}
620 
621  //@{
622  /**
623  * @brief Returns a vector of IDs extracted from the specified optional ID
624  * sequence.
625  * @tparam SrcID type of the ID read by the FHiCL parameter
626  * @tparam ID type of the returned ID (default: same as `SrcID`)
627  * @param seq the optional sequence of ID parameters to convert
628  * @return an optional collection containing a STL vector of `ID` objects
629  * converted from `seq` parameter values, or no value if the parameter
630  * was omitted
631  *
632  * This function returns the value of the specified FHiCL optional sequence
633  * object (`fhicl::OptionalSequence`). It supports both fixed and variable
634  * size optional sequences, but it always returns an optional STL vector as a
635  * result.
636  *
637  * Example of usage: the configuration object `Config` and the data member to
638  * store the configuration parameter value are defined in a class as:
639  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
640  * struct Config {
641  *
642  * geo::fhicl::OptionalTPCIDsequence TPCs
643  * { fhicl::Name("TPCs"), fhicl::Comment("selected TPCs") };
644  *
645  * };
646  *
647  * std::optional<std::vector<geo::TPCID>> fTPCs;
648  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
649  * The constructor of that class should have an entry in the initializer list
650  * like:
651  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
652  * fTPCs(geo::fhicl::readIDsequence(config().TPCs))
653  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
654  * (note that the argument is just `config().TPCs`, not `config().TPCs()`).
655  * If instead a "default value" needs to be provided, the data member is
656  * simply:
657  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
658  * std::vector<geo::TPCID> fTPCs;
659  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
660  * and the value can be assigned via the standard `std::optional` interface:
661  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
662  * fTPCs(geo::fhicl::readIDsequence(config().TPCs).value_or(std::vector<geo::TPCID>{}))
663  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
664  * (in this case the default value is an empty collection of TPC IDs) or using
665  * a different overload of `readOptionalIDsequence()`:
666  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
667  * fTPCs(geo::fhicl::readIDsequence(config().TPCs, {}))
668  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
669  *
670  *
671  * @note The additional template parameter `ID` is provided as an added bonus
672  * to choose which type to convert the configuration parameters into,
673  * and it's not enforced to be a ID type at all.
674  */
675  template <typename SrcID, typename ID = SrcID>
676  std::optional<std::vector<ID>> readOptionalIDsequence
677  (OptionalIDsequence<SrcID> const& seq);
678 
679  template <typename SrcID, typename ID = SrcID>
680  std::optional<std::vector<ID>> readParameter
682  { return readOptionalIDsequence<SrcID, ID>(seq); }
683  //@}
684 
685  //@{
686  /**
687  * @brief Returns a vector of IDs extracted from the specified optional ID
688  * sequence, or a default value.
689  * @tparam SrcID type of the ID read by the FHiCL parameter
690  * @tparam ID type of the returned ID (default: same as `SrcID`)
691  * @param seq the optional sequence of ID parameters to convert
692  * @param defValue value to be returned if the optional parameter was omitted
693  * @return a collection containing a STL vector of `ID` objects
694  * converted either from `seq` parameter values or from `defValue`
695  *
696  * This function is based on `readOptionalIDsequence(IDsequence const&)`.
697  * The operating mode is the same, but if the value is not available from
698  * the parameters, a copy of `defValue` is returned, or `defValue` content
699  * is moved into the returned value.
700  */
701  template <typename SrcID, typename ID = SrcID>
702  std::vector<ID> readOptionalIDsequence
703  (OptionalIDsequence<SrcID> const& seq, std::vector<ID> const& defValue);
704 
705  template <typename SrcID, typename ID = SrcID>
706  std::vector<ID> readOptionalIDsequence
707  (OptionalIDsequence<SrcID> const& seq, std::vector<ID>&& defValue);
708 
709  template <typename SrcID, typename ID = SrcID>
710  std::vector<ID> readParameter
711  (OptionalIDsequence<SrcID> const& seq, std::vector<ID> const& defValue)
712  { return readOptionalIDsequence<SrcID, ID>(seq, defValue); }
713 
714  template <typename SrcID, typename ID = SrcID>
715  std::vector<ID> readParameter
716  (OptionalIDsequence<SrcID> const& seq, std::vector<ID>&& defValue)
717  { return readOptionalIDsequence<SrcID, ID>(seq, std::move(defValue)); }
718 
719  //@}
720 
721  // --- END -- ID parsing -----------------------------------------------------
722 
723 
724  /// @}
725  // --- END -- Validated configuration parameters for geometry ID objects -----
726 
727 } // namespace geo::fhicl
728 
729 
730 // -----------------------------------------------------------------------------
731 // --- template implementation
732 // -----------------------------------------------------------------------------
733 // --- definition of the traits
734 // ---
735 template <typename ID>
737 
738  using type = IDparameter<ID>; ///< Type of parameter.
739 
740  using ID_t = typename type::ID_t; ///< Type of ID read.
741 
742  static constexpr bool isOptional = false; ///< Whether it is optional.
743 
744  static constexpr bool isAtom = true; ///< Whether it is a single value.
745 
746  static constexpr bool isSequence = false; ///< Whether it is a sequence.
747 
748 }; // geo::fhicl::IDparameterTraits<geo::fhicl::IDparameter<ID>>
749 
750 
751 template <typename ID>
753  : geo::fhicl::IDparameterTraits<geo::fhicl::IDparameter<ID>>
754 {
755  // override:
756  static constexpr bool isOptional = true; ///< Whether it is optional.
757 }; // geo::fhicl::IDparameterTraits<geo::fhicl::OptionalID<ID>>
758 
759 
760 template <typename ID>
762  : geo::fhicl::IDparameterTraits<geo::fhicl::IDparameter<ID>>
763 {
764  // override:
765  static constexpr bool isAtom = false; ///< Whether it is a single value.
766  static constexpr bool isSequence = true; ///< Whether it is a sequence.
767 }; // geo::fhicl::IDparameterTraits<geo::fhicl::IDsequence<ID>>
768 
769 
770 template <typename ID>
772  : geo::fhicl::IDparameterTraits<geo::fhicl::IDsequence<ID>>
773 {
774  // override:
775  static constexpr bool isOptional = true; ///< Whether it is optional.
776 }; // geo::fhicl::IDparameterTraits<geo::fhicl::OptionalIDsequence<ID>>
777 
778 
779 // -----------------------------------------------------------------------------
780 template <typename SrcID, typename ID /* = SrcID */>
782  return atom(); // conversions happen as needed (if possible)
783 } // geo::fhicl::readID()
784 
785 
786 // -----------------------------------------------------------------------------
787 template <typename SrcID, typename ID /* = SrcID */>
788 std::optional<ID> geo::fhicl::readOptionalID(OptionalID<SrcID> const& atom) {
789  using ID_t = ID;
790 
792  return atom(cs)? std::make_optional<ID_t>(cs.ID()): std::nullopt;
793 } // geo::fhicl::readOptionalID()
794 
795 
796 // -----------------------------------------------------------------------------
797 template <typename SrcID, typename ID /* = SrcID */>
798 ID geo::fhicl::readOptionalID(OptionalID<SrcID> const& atom, ID const& defValue)
799  { return readOptionalID(atom).value_or(defValue); }
800 
801 
802 // -----------------------------------------------------------------------------
803 template <typename SrcID, typename ID /* = SrcID */>
805  { return readOptionalID(atom).value_or(std::move(defValue)); }
806 
807 
808 // -----------------------------------------------------------------------------
809 template <typename SrcID, typename ID /* = SrcID */>
810 std::vector<ID> geo::fhicl::readIDsequence(IDsequence<SrcID> const& seq) {
811  using ID_t = ID;
812 
813  std::vector<ID_t> IDs;
814  std::size_t const n = seq.size();
815  IDs.reserve(n);
816  for (std::size_t i = 0; i < n; ++i)
817  IDs.push_back(seq(i)); // seq(i) is TPCIDConfig
818  return IDs;
819 } // geo::fhicl::readIDsequence()
820 
821 
822 // -----------------------------------------------------------------------------
823 template <typename SrcID, typename ID /* = SrcID */>
824 std::optional<std::vector<ID>> geo::fhicl::readOptionalIDsequence
826 {
827  using values_t = std::vector<ID>;
828 
830  if (!seq(values)) return std::nullopt;
831 
832  values_t IDs;
833  IDs.reserve(values.size());
834  std::copy(values.begin(), values.end(), std::back_inserter(IDs));
835  return { std::move(IDs) };
836 
837 } // geo::fhicl::readOptionalIDsequence()
838 
839 
840 // -----------------------------------------------------------------------------
841 template <typename SrcID, typename ID /* = SrcID */>
843  (OptionalIDsequence<SrcID> const& seq, std::vector<ID> const& defValue)
844 {
845  // making sure `paramValue` is not a r-value; not sure whether it is necessary
846  auto paramValue = readOptionalIDsequence(seq);
847  return paramValue.value_or(defValue);
848 } // geo::fhicl::readOptionalIDsequence(std::vector const&)
849 
850 
851 // -----------------------------------------------------------------------------
852 template <typename SrcID, typename ID /* = SrcID */>
854  (OptionalIDsequence<SrcID> const& seq, std::vector<ID>&& defValue)
855 {
856  return readOptionalIDsequence(seq).value_or(std::move(defValue));
857 } // geo::fhicl::readOptionalIDsequence(std::vector const&)
858 
859 
860 // -----------------------------------------------------------------------------
861 
862 
863 #endif // LARCOREOBJ_SIMPLETYPESANDCONSTANTS_GEO_TYPES_FHICL_H
864 
IDparameter< geo::OpDetID > OpDetID
Member type of validated geo::OpDetID parameter.
IDparameter< geo::CryostatID > CryostatID
Member type of validated geo::CryostatID parameter.
std::size_t size() const noexcept
Definition: SequenceBase.h:33
std::vector< ID > readIDsequence(IDsequence< SrcID > const &seq)
Returns a vector of IDs extracted from the specified ID sequence.
std::array< tt::return_type< T >, N > value_type
unsigned int ID
Traits for ID parameter objects.
ChannelGroupService::Name Name
std::pair< float, std::string > P
Helper class holding the ID validity flag.
ID readID(IDparameter< SrcID > const &atom)
Returns an ID extracted from the specified ID atom.
IDparameter< geo::PlaneID > PlaneID
Member type of validated geo::PlaneID parameter.
IDparameter< geo::WireID > WireID
Member type of validated geo::WireID parameter.
std::optional< ID > readOptionalID(OptionalID< SrcID > const &atom)
Returns an ID extracted from the specified optional ID atom.
std::void_t< T > n
def move(depos, offset)
Definition: depos.py:107
std::optional< std::vector< ID > > readOptionalIDsequence(OptionalIDsequence< SrcID > const &seq)
Returns a vector of IDs extracted from the specified optional ID sequence.
Q_UINT16 values[128]
Type of ID configuration structure (requires specialization)
Definition of data types for geometry description.
FHiCL objects representing geometry classes as configuration parameters.
#define Comment
::fhicl::Atom< bool > isValid
T copy(T const &v)
IDparameter< geo::TPCID > TPCID
Member type of validated geo::TPCID parameter.
const char * cs
LArSoft geometry interface.
Definition: ChannelGeo.h:16
ID readParameter(IDparameter< SrcID > const &atom)
typename IDparameterTraits< IDparam >::ID_t IDof
Type of ID of the specified ID FHiCL parameter object/.
The data type to uniquely identify a cryostat.
Definition: geo_types.h:190