GeometryIDmapper.h
Go to the documentation of this file.
1 /**
2  * @file larcorealg/Geometry/GeometryIDmapper.h
3  * @brief Mapping between geometry/readout ID and flat index.
4  * @author Gianluca Petrillo (petrillo@fnal.gov)
5  * @date October 26, 2019
6  * @ingroup Geometry
7  *
8  * This is a header-only library.
9  */
10 
11 #ifndef LARCOREALG_GEOMETRY_GEOMETRYIDMAPPER_H
12 #define LARCOREALG_GEOMETRY_GEOMETRYIDMAPPER_H
13 
14 // LArSoft libraries
16 
17 // C/C++ standard libraries
18 #include <array>
19 #include <initializer_list>
20 #include <algorithm> // std::copy()
21 #include <type_traits> // std::index_sequence
22 #include <cstdlib> // std::size_t
23 #include <cassert>
24 
25 
26 namespace geo {
27 
28  template <typename IDType, typename Index = std::size_t>
29  class GeoIDmapper;
30 
31  template <typename Index = std::size_t>
32  class TPCIDmapper;
33 
34  template <typename Index = std::size_t>
36 
37  // ---------------------------------------------------------------------------
38  namespace details {
39 
40  /// Returns a STL array of size `N` filled with `values` from the argument.
41  template <std::size_t N, typename T>
42  auto initializerListToArray(std::initializer_list<T> values);
43 
44  } // namespace details
45  // ---------------------------------------------------------------------------
46 
47 } // namespace geo
48 
49 
50 // --- BEGIN Geometry ID mappers -----------------------------------------------
51 /// @name Geometry ID mappers
52 /// @ingroup Geometry
53 /// @{
54 
55 /**
56  * @brief Class managing the mapping between geometry/readout ID and flat index.
57  * @tparam IDType the geometry or readout ID to be managed
58  * @tparam Index (default: `std::size_t`) type of flat index
59  *
60  * This class maps multi-level ID's (e.g. `geo::WireID`, `readout::TPCsetID`)
61  * into a single linear index.
62  *
63  * The current implementation guarantees that the indices are ordered like their
64  * respective IDs, and that there are no gaps so that each index up to `size()`
65  * (excluded) corresponds to a "valid" ID.
66  * The range of valid IDs is a hyperbox so that all elements of a certain level
67  * have the same number of sub-elements (for examples, all planes have the same
68  * number of wires, all valid from the mapping point of view).
69  *
70  * Note that this mapping is typically not suitable for channel mapping, since
71  * usually planes with different wire orientations may have different number of
72  * wires, making some of the indices that are valid from the point of view of
73  * this ID mapping invalid in that they match wires that do not exist and should
74  * not be assigned a channel number.
75  */
76 template <typename IDType, typename Index /* = std::size_t */>
77 class geo::GeoIDmapper {
78 
79  public:
80 
81  using ID_t = IDType; ///< Type used as ID for this mapping.
82  using index_type = Index; ///< Type of flat index.
83 
84 
85  /**
86  * @brief Default constructor: all dimensions empty.
87  * @see `resize()`
88  *
89  * The indexer must be resized before being of any use.
90  */
91  GeoIDmapper();
92 
93  /**
94  * @brief Prepares the indexer.
95  * @param dims number of elements on all levels of the mapping
96  * @see `resize()`
97  *
98  * The size of each dimension is specified by the corresponding number,
99  * starting from the size of the outer dimension (cryostat).
100  */
101  GeoIDmapper(std::initializer_list<unsigned int> dims);
102 
103 
104  // --- BEGIN Indexer status query --------------------------------------------
105  /// @name Indexer status query
106  /// @{
107 
108  /// Returns the number of elements in the mapping.
109  index_type size() const;
110 
111  /// Returns whether the mapping has no elements (`false` by assumptions).
112  bool empty() const;
113 
114  /// Dimensions of the `Level` dimension of this mapping.
115  template <std::size_t Level>
116  unsigned int dimSize() const;
117 
118  /// Dimensions of the ID of this mapping.
119  static constexpr unsigned int dimensions();
120 
121  /// Returns whether this mapping hosts data for the specified ID.
122  template <typename GeoID = ID_t>
123  bool hasElement(GeoID const& id) const;
124 
125  /// Returns the ID of the first element with `GeoID` type.
126  template <typename GeoID = ID_t>
127  GeoID firstID() const;
128 
129  /// Returns the ID of the last covered element with `GeoID` type.
130  template <typename GeoID = ID_t>
131  GeoID lastID() const;
132 
133  /// @}
134  // --- END Indexer status query ----------------------------------------------
135 
136 
137  // --- BEGIN Mapping transformations -----------------------------------------
138  /// @name Mapping transformations
139  /// @{
140 
141  /// Returns the linear index corresponding to the specified ID.
142  index_type index(ID_t const& id) const;
143 
144  /// Returns the ID corresponding to the specified linear `index`.
145  ID_t ID(index_type const index) const;
146 
147  /// Returns the linear index corresponding to the specified ID.
148  index_type operator() (ID_t const& id) const;
149 
150  /// Returns the ID corresponding to the specified linear `index`.
151  ID_t operator() (index_type const index) const;
152 
153  /// @}
154  // --- END Mapping transformations -------------------------------------------
155 
156 
157  // --- BEGIN Mapping modification --------------------------------------------
158  /// @name Mapping modification
159  /// @{
160 
161  /**
162  * @brief Resizes the mapping to accommodate the specified dimension sizes.
163  * @param dims number of elements on all levels of the mapping
164  * @see `resizeAs()`
165  *
166  * The size of each dimension is specified by the corresponding number,
167  * starting from the size of the outer dimension (cryostat).
168  */
169  void resize(std::initializer_list<unsigned int> dims);
170 
171  /**
172  * @brief Resizes the mapping to reflect the one from another mapping.
173  * @param other ID mapping to take dimensions from
174  *
175  * The size of each dimension is taken by the matching one in `other`.
176  */
177  template <typename OIDType, typename OIndex>
178  void resizeAs(geo::GeoIDmapper<OIDType, OIndex> const& other);
179 
180 
181  /**
182  * @brief Sets all dimension sizes to `0`.
183  * @see `resize()`
184  *
185  * The mapping needs to be resized before it is useful again.
186  */
187  void clear();
188 
189 
190  /// @}
191  // --- END Mapping modification ----------------------------------------------
192 
193 
194  private:
195  ///< Type of dimension sizes.
196  using Dimensions_t = std::array<unsigned int, dimensions()>;
197 
198  /// Number of maximum entries per ID level.
199  Dimensions_t fN = zeroDimensions();
200 
201 
202  template <std::size_t Level, typename GeoID>
203  index_type indexLevel(GeoID const& id) const;
204 
205  /**
206  * @brief Fills the specified ID with its index.
207  * @tparam Level the level of the index to fill (`0` for cryostat level, etc._
208  * @tparam GeoID type of ID to be filled
209  * @param id the ID to be filled
210  * @param index the index corresponding to the ID
211  * @see `indexLevel()`, `index()`
212  *
213  * Fills the specified ID with its index. This can be considered the inverse
214  * operation of the `index()` method.
215  * The `index` argument is local to the level to be filled, e.g. for cryostats
216  * it goes from `0` to the number of cryostats.
217  */
218  template <std::size_t Level, typename GeoID>
219  void fillID(GeoID& id, index_type index) const;
220 
221  /// Returns whether all levels of `id` up to `Level` are within range.
222  template <std::size_t Level, typename GeoID>
223  bool hasElementLevel(GeoID const& id) const;
224 
225  /// Computes the expected size of this mapping.
226  index_type computeSize() const;
227 
228 
229  /// Implementation for `resizeAs()`.
230  template<typename OIDType, typename OIndex, std::size_t... Indices>
231  void resizeAsImpl(
233  std::index_sequence<Indices...>
234  );
235 
236  /// Returns the number of elements at the specified `Level`.
237  /// @param dimSizes the sizes of each of the levels
238  template <std::size_t Level, typename Dims>
239  static index_type sizeLevel(Dims const& dimSizes);
240 
241  /// Initializer with zero size for each of the dimensions.
243  { Dimensions_t dims; dims.fill(0); return dims; }
244 
245  /// Returns whether the specified value is between `0` and the upper limit.
246  template <typename Value, typename Upper>
247  static bool bounded(Value v, Upper upper)
248  { return (v >= 0) && (static_cast<index_type>(v) < upper); }
249 
250 }; // class geo::GeoIDmapper<>
251 
252 
253 /** ****************************************************************************
254  * @brief Mapping for TPC identifiers.
255  * @tparam Index (default: `std::size_t`) type of flat index
256  * @see `geo::GeoIDmapper`
257  *
258  * A customized version of `geo::GeoIDmapper` offering TPC ID-specific
259  * interface.
260  */
261 template <typename Index /* = std::size_t */>
262 class geo::TPCIDmapper: public geo::GeoIDmapper<geo::TPCID, Index> {
263 
264  /// Base class.
266 
267  public:
268 
269  // import types
270  using ID_t = typename BaseMapper_t::ID_t;
272 
273 
274  // import all constructors from `geo::GeoIDmapper`
275  using BaseMapper_t::BaseMapper_t;
276 
277  /**
278  * @brief Prepares the mapping with the specified sizes.
279  * @param nCryo number of cryostats
280  * @param nTPCs number of TPCs per cryostat
281  *
282  * The mapping is sized to map `nCryo` cryostats, each with `nTPCs` TPCs.
283  */
284  TPCIDmapper(unsigned int nCryo, unsigned int nTPCs)
285  : BaseMapper_t({ nCryo, nTPCs })
286  {}
287 
288 
289  // --- BEGIN Mapping modification --------------------------------------------
290  /// @name Mapping modification
291  /// @{
292 
293  using BaseMapper_t::resize;
294 
295  /**
296  * @brief Prepares the mapping for the specified sizes.
297  * @param nCryo number of cryostats
298  * @param nTPCs number of TPCs
299  * @see `resizeAs()`
300  *
301  * The mapping is sized to map `nCryo` cryostats, each with `nTPCs` TPCs.
302  */
303  void resize(unsigned int nCryo, unsigned int nTPCs)
304  { BaseMapper_t::resize({ nCryo, nTPCs }); }
305 
306  /// @}
307  // --- END Mapping modification ----------------------------------------------
308 
309 
310  // --- BEGIN Mapping status query --------------------------------------------
311  /// @name Mapping status query
312  /// @{
313 
314  /// Returns whether this mapping covers the specified cryostat.
315  bool hasCryostat(geo::CryostatID const& cryoid) const
316  { return BaseMapper_t::hasElement(cryoid); }
317 
318  /// Returns whether this mapping covers the specified TPC.
319  bool hasTPC(geo::TPCID const& tpcid) const
320  { return BaseMapper_t::hasElement(tpcid); }
321 
322  /// @}
323  // --- END Mapping status query ----------------------------------------------
324 
325 }; // geo::TPCIDmapper<>
326 
327 
328 /** ****************************************************************************
329  * @brief Mapping for sensitive plane identifiers.
330  * @tparam Index (default: `std::size_t`) type of flat index
331  * @see `geo::GeoIDmapper`
332  *
333  * A customized version of `geo::GeoIDmapper` offering
334  * sensitive plane ID-specific interface.
335  */
336 template <typename Index /* = std::size_t */>
337 class geo::PlaneIDmapper: public geo::GeoIDmapper<geo::PlaneID, Index> {
338 
339  /// Base class.
341 
342  public:
343 
344  // import types
345  using ID_t = typename BaseMapper_t::ID_t;
347 
348 
349  // import all constructors from `geo::GeoIDmapper`
350  using BaseMapper_t::BaseMapper_t;
351 
352  /**
353  * @brief Prepares the mapping with the specified sizes.
354  * @param nCryo number of cryostats
355  * @param nTPCs number of TPCs per cryostat
356  * @param nPlanes number of planes per TPC
357  *
358  * The mapping is sized to map `nCryo` cryostats, each with `nTPCs` TPCs,
359  * each one with `nPlanes` wire planes.
360  */
361  PlaneIDmapper(unsigned int nCryo, unsigned int nTPCs, unsigned int nPlanes)
362  : BaseMapper_t({ nCryo, nTPCs, nPlanes })
363  {}
364 
365 
366  // --- BEGIN Mapping modification --------------------------------------------
367  /// @name Mapping modification
368  /// @{
369 
370  using BaseMapper_t::resize;
371 
372  /**
373  * @brief Prepares the mapping for the specified sizes.
374  * @param nCryo number of cryostats
375  * @param nTPCs number of TPCs
376  * @param nPlanes number of planes per TPC
377  * @see `resizeAs()`
378  *
379  * The mapping is sized to map `nCryo` cryostats, each with `nTPCs` TPCs,
380  * each one with `nPlanes` wire planes.
381  */
382  void resize(unsigned int nCryo, unsigned int nTPCs, unsigned int nPlanes)
383  { BaseMapper_t::resize({ nCryo, nTPCs, nPlanes }); }
384 
385  /// @}
386  // --- END Mapping modification ----------------------------------------------
387 
388 
389  // --- BEGIN Mapping status query --------------------------------------------
390  /// @name Mapping status query
391  /// @{
392 
393  /// Returns whether this mapping covers the specified cryostat.
394  bool hasCryostat(geo::CryostatID const& cryoid) const
395  { return BaseMapper_t::hasElement(cryoid); }
396 
397  /// Returns whether this mapping covers the specified TPC.
398  bool hasTPC(geo::TPCID const& tpcid) const
399  { return BaseMapper_t::hasElement(tpcid); }
400 
401  /// Returns whether this mapping covers the specified plane.
402  bool hasPlane(geo::PlaneID const& planeid) const
403  { return BaseMapper_t::hasElement(planeid); }
404 
405  /// @}
406  // --- END Mapping status query ----------------------------------------------
407 
408 }; // geo::PlaneIDmapper<>
409 
410 
411 /// @}
412 // --- END Geometry ID mappers -------------------------------------------------
413 //------------------------------------------------------------------------------
414 
415 
416 
417 //------------------------------------------------------------------------------
418 //--- Template implementation
419 //------------------------------------------------------------------------------
420 template <std::size_t N, typename T>
421 auto geo::details::initializerListToArray(std::initializer_list<T> values) {
422  std::array<T, N> data;
423  std::copy(values.begin(), values.end(), data.begin());
424  return data;
425 } // geo::details::initializerListToArray()
426 
427 
428 //------------------------------------------------------------------------------
429 //--- geo::GeoIDmapper
430 //------------------------------------------------------------------------------
431 template <typename IDType, typename Index>
433 {
434  fN.fill(0U);
435 }
436 
437 
438 //------------------------------------------------------------------------------
439 template <typename IDType, typename Index>
441  (std::initializer_list<unsigned int> dims)
443 {
444  assert(dims.size() == dimensions()); // can't be static
445 }
446 
447 
448 //------------------------------------------------------------------------------
449 template <typename IDType, typename Index>
451  { return computeSize(); }
452 
453 
454 //------------------------------------------------------------------------------
455 template <typename IDType, typename Index>
457  { return size() == index_type{ 0 }; }
458 
459 
460 //------------------------------------------------------------------------------
461 template <typename IDType, typename Index>
462 template <std::size_t Level>
464  if constexpr (Level >= dimensions()) return 0U; // technically it would be 1...
465  else return fN[Level];
466 } // geo::GeoIDmapper<>::dimSize()
467 
468 
469 //------------------------------------------------------------------------------
470 template <typename IDType, typename Index>
472  { return IDType::Level + 1; }
473 
474 
475 //------------------------------------------------------------------------------
476 template <typename IDType, typename Index>
477 template <typename GeoID>
479  { return hasElementLevel<GeoID::Level>(id); }
480 
481 
482 //------------------------------------------------------------------------------
483 template <typename IDType, typename Index>
484 template <typename GeoID /* = ID_t */>
486  if constexpr (GeoID::Level == 0) return GeoID(0U);
487  else return GeoID(firstID<typename GeoID::ParentID_t>(), 0U);
488 } // geo::GeoIDmapper<>::firstID()
489 
490 
491 //------------------------------------------------------------------------------
492 template <typename IDType, typename Index>
493 template <typename GeoID /* = ID_t */>
495  if constexpr (GeoID::Level == 0) return GeoID(fN[GeoID::Level] - 1U);
496  else
497  return GeoID(lastID<typename GeoID::ParentID_t>(), fN[GeoID::Level] - 1U);
498 } // geo::GeoIDmapper<>::lastID()
499 
500 
501 //------------------------------------------------------------------------------
502 template <typename IDType, typename Index>
504  { return indexLevel<ID_t::Level>(id); }
505 
506 
507 //------------------------------------------------------------------------------
508 template <typename IDType, typename Index>
510 {
511  ID_t ID;
512  fillID<ID_t::Level>(ID, index);
513  return ID;
514 } // geo::GeoIDmapper<>::ID()
515 
516 
517 //------------------------------------------------------------------------------
518 template <typename IDType, typename Index>
520  -> index_type
521  { return index(id); }
522 
523 
524 //------------------------------------------------------------------------------
525 template <typename IDType, typename Index>
527  -> ID_t
528  { return ID(index); }
529 
530 
531 //------------------------------------------------------------------------------
532 template <typename IDType, typename Index>
534  (std::initializer_list<unsigned int> dims)
535 {
536  fN = details::initializerListToArray<dimensions()>(dims);
537 } // geo::GeoIDmapper<>::resize()
538 
539 
540 //------------------------------------------------------------------------------
541 template <typename IDType, typename Index>
542 template <typename OIDType, typename OIndex>
545 {
546  resizeAsImpl(other, std::make_index_sequence<dimensions()>{});
547 } // geo::GeoIDmapper<>::resizeAs()
548 
549 
550 //------------------------------------------------------------------------------
551 template <typename IDType, typename Index>
553  fN.fill(0U);
554 } // geo::GeoIDmapper<>::clear()
555 
556 
557 //------------------------------------------------------------------------------
558 template <typename IDType, typename Index>
559 template <std::size_t Level, typename GeoID>
561  -> index_type
562 {
563  if constexpr (Level == 0) return id.template getIndex<0U>();
564  else {
565  return
566  indexLevel<(Level-1U)>(id) * fN[Level] + id.template getIndex<Level>();
567  }
568 } // geo::GeoIDmapper<>::indexLevel()
569 
570 
571 //------------------------------------------------------------------------------
572 template <typename IDType, typename Index>
573 template <std::size_t Level, typename GeoID>
575 {
576  if constexpr (Level == 0) {
577  id.template writeIndex<0U>() = index;
578  id.setValidity(index < fN[0U]);
579  }
580  else {
581  id.template writeIndex<Level>() = index % fN[Level];
582  fillID<(Level-1U)>(id, index / fN[Level]);
583  }
584 } // geo::GeoIDmapper<>::fillID()
585 
586 
587 //------------------------------------------------------------------------------
588 template <typename IDType, typename Index>
589 template <std::size_t Level, typename GeoID>
591 {
592  if (!bounded(id.template getIndex<Level>(), fN[Level])) return false;
593  if constexpr (Level == 0U) return true;
594  else return hasElementLevel<(Level-1U)>(id);
595 } // geo::GeoIDmapper<>::hasElementLevel()
596 
597 
598 //------------------------------------------------------------------------------
599 template <typename IDType, typename Index>
601  { return sizeLevel<0U>(fN); }
602 
603 
604 //------------------------------------------------------------------------------
605 template <typename IDType, typename Index>
606 template<typename OIDType, typename OIndex, std::size_t... Indices>
609  std::index_sequence<Indices...>
610  )
611 {
612  // Clang 5.0.1 does not understand `other.dimensions()` is constexpr
614  "Can't resize a deeper mapping to a shallower one.");
615  resize({ other.template dimSize<Indices>()... });
616 } // geo::GeoIDmapper<>::resizeAsImpl()
617 
618 
619 //------------------------------------------------------------------------------
620 template <typename IDType, typename Index>
621 template <std::size_t Level, typename Dims>
623  -> index_type
624 {
625  if constexpr (Level >= dimensions()) return 1U;
626  else return sizeLevel<(Level+1U)>(dimSizes) * dimSizes[Level];
627 } // geo::GeoIDmapper<>::sizeLevel()
628 
629 
630 //------------------------------------------------------------------------------
631 
632 
633 #endif // LARCOREALG_GEOMETRY_GEOMETRYIDMAPPER_H
bool hasTPC(geo::TPCID const &tpcid) const
Returns whether this mapping covers the specified TPC.
void fillID(GeoID &id, index_type index) const
Fills the specified ID with its index.
void resize(unsigned int nCryo, unsigned int nTPCs)
Prepares the mapping for the specified sizes.
ID_t ID(index_type const index) const
Returns the ID corresponding to the specified linear index.
bool hasElementLevel(GeoID const &id) const
Returns whether all levels of id up to Level are within range.
bool hasCryostat(geo::CryostatID const &cryoid) const
Returns whether this mapping covers the specified cryostat.
index_type size() const
Returns the number of elements in the mapping.
unsigned int ID
index_type operator()(ID_t const &id) const
Returns the linear index corresponding to the specified ID.
void resizeAs(geo::GeoIDmapper< OIDType, OIndex > const &other)
Resizes the mapping to reflect the one from another mapping.
void resizeAsImpl(geo::GeoIDmapper< OIDType, OIndex > const &other, std::index_sequence< Indices... >)
Implementation for resizeAs().
GeoID firstID() const
Returns the ID of the first element with GeoID type.
The data type to uniquely identify a Plane.
Definition: geo_types.h:472
void resize(unsigned int nCryo, unsigned int nTPCs, unsigned int nPlanes)
Prepares the mapping for the specified sizes.
Level
Definition: Level.h:13
static bool bounded(Value v, Upper upper)
Returns whether the specified value is between 0 and the upper limit.
index_type computeSize() const
Computes the expected size of this mapping.
unsigned int Index
PlaneIDmapper(unsigned int nCryo, unsigned int nTPCs, unsigned int nPlanes)
Prepares the mapping with the specified sizes.
index_type indexLevel(GeoID const &id) const
void resize(Vector< T > &vec1, Index n1, const V &val)
bool hasCryostat(geo::CryostatID const &cryoid) const
Returns whether this mapping covers the specified cryostat.
decltype(auto) constexpr size(T &&obj)
ADL-aware version of std::size.
Definition: StdUtils.h:92
static index_type sizeLevel(Dims const &dimSizes)
static constexpr unsigned int dimensions()
Dimensions of the ID of this mapping.
TPCIDmapper(unsigned int nCryo, unsigned int nTPCs)
Prepares the mapping with the specified sizes.
unsigned int dimSize() const
Dimensions of the Level dimension of this mapping.
Q_UINT16 values[128]
auto initializerListToArray(std::initializer_list< T > values)
Returns a STL array of size N filled with values from the argument.
The data type to uniquely identify a TPC.
Definition: geo_types.h:386
GeoIDmapper()
Default constructor: all dimensions empty.
Definition of data types for geometry description.
Mapping for TPC identifiers.
GeoID lastID() const
Returns the ID of the last covered element with GeoID type.
bool hasElement(GeoID const &id) const
Returns whether this mapping hosts data for the specified ID.
bool empty() const
Returns whether the mapping has no elements (false by assumptions).
std::array< unsigned int, dimensions()> Dimensions_t
< Type of dimension sizes.
IDType ID_t
Type used as ID for this mapping.
static Dimensions_t zeroDimensions()
Initializer with zero size for each of the dimensions.
Index index_type
Type of flat index.
T copy(T const &v)
void resize(std::initializer_list< unsigned int > dims)
Resizes the mapping to accommodate the specified dimension sizes.
vector< vector< double > > clear
Mapping for sensitive plane identifiers.
index_type index(ID_t const &id) const
Returns the linear index corresponding to the specified ID.
bool hasPlane(geo::PlaneID const &planeid) const
Returns whether this mapping covers the specified plane.
LArSoft geometry interface.
Definition: ChannelGeo.h:16
bool hasTPC(geo::TPCID const &tpcid) const
Returns whether this mapping covers the specified TPC.
decltype(auto) constexpr empty(T &&obj)
ADL-aware version of std::empty.
Definition: StdUtils.h:97
The data type to uniquely identify a cryostat.
Definition: geo_types.h:190
void clear()
Sets all dimension sizes to 0.
Class managing the mapping between geometry/readout ID and flat index.