Partitions.h
Go to the documentation of this file.
1 /**
2  * @file Partitions.h
3  * @brief Classes describing partition of an area with associated data.
4  * @author Gianluca Petrillo (petrillo@fnal.gov)
5  * @date July 13, 2017
6  *
7  * This is used by `geo::DriftPartitions` to describe the partition of a plane
8  * across TPCs.
9  */
10 
11 #ifndef LARCOREALG_GEOMETRY_PARTITIONS_H
12 #define LARCOREALG_GEOMETRY_PARTITIONS_H
13 
14 // LArSoft libraries
15 #include "larcorealg/Geometry/SimpleGeo.h" // lar::util::simple_geo::Rectangle
16 #include "larcorealg/CoreUtils/DebugUtils.h" // lar::debug::demangle(), ...
17 
18 // C/C++ standard libraries
19 #include <algorithm> // std::upper_bound()
20 #include <vector>
21 #include <string>
22 #include <sstream>
23 #include <iterator> // std::next(), ...
24 #include <memory> // std::unique_ptr<>
25 #include <utility> // std::move(), std::forward()
26 #include <type_traits> // std::declval(), std::true_type...
27 #include <cassert>
28 #include <cstdlib> // std::size_t
29 
30 
31 namespace geo {
32 
33  /// Partition-related utilities.
34  namespace part {
35 
36 
37  //-------------------------------------------------------------------------
38  /// A basic interface for objects owning an area.
39  class AreaOwner {
40 
41  public:
42  /// Type of area covered by the partition.
44 
45  /// Type of pointer to Area_t data member of type Range_t.
47 
48  /// Constructor: sets the covered area and no subpartitions.
49  AreaOwner(Area_t const& area): myArea(area) {}
50 
51  /// Returns whether the specified point is covered by this object.
52  bool contains(double w, double d) const
53  { return area().contains(w, d); }
54 
55  /// Returns the covered area.
56  Area_t const& area() const { return myArea; }
57 
58  /// Output the owned area into an output stream.
59  template <typename Stream>
60  void dumpArea(Stream&& out) const { std::forward<Stream>(out) << area(); }
61 
62  private:
63  Area_t myArea; ///< Covered area.
64 
65  }; // class AreaOwner
66 
67 
68  namespace details {
69 
70  /// Ordering class to sort partition by specified range (lower boundary).
71  template <AreaOwner::AreaRangeMember_t Range>
73 
74  } // namespace details
75 
76  //*************************************************************************
77  //*** Fundamental classes
78  //-------------------------------------------------------------------------
79 
80  /**
81  * @brief Class providing custom dump for data contained in the partition.
82  * @tparam Data the type of data in the partition
83  *
84  * This data type is expected to do its printout in a constructor with
85  * signature:
86  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
87  * template <typename Stream>
88  * PartitionDataDescriber(
89  * Stream&& out, Data const* data,
90  * std::string indent = "", std::string firstIndent = ""
91  * );
92  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
93  * This class provides a terse, non-specific dump of any datum.
94  * Specializations are expected for specific data types.
95  */
96  template <typename Data>
98  /// Constructor; see `describePartitionData()` for argument description.
99  template <typename Stream>
101  Stream&& out, Data const* data,
102  std::string indent = "", std::string firstIndent = ""
103  );
104  }; // struct PartitionDataDescriber<>
105 
106  /**
107  * @brief Describes a data object for `Partition::describe()` method.
108  * @tparam Stream type of output stream
109  * @tparam Data type of data to be described
110  * @param out output stream
111  * @param data pointer to the data to be described
112  * @param indent indentation string applied to all lines except the first
113  * @param firstIndent special indentation string for the first line
114  *
115  * The description of the data pointed by `data` is printed into the
116  * output stream `out`. The first line of the output is indented with
117  * `firstIndent` string (by default: no indent), while all the others are
118  * indented with the string `indent` (by default, also no indent).
119  * The last output line is _not_ ended by a end-of-line character.
120  *
121  * This function relies on `PartitionDataDescriber` template class, that
122  * should be specialized to customize the printout of known data types.
123  */
124  template <typename Stream, typename Data>
126  Stream&& out, Data const* data,
127  std::string indent = "", std::string firstIndent = ""
128  );
129 
130 
131  //--------------------------------------------------------------------------
132  /**
133  * @brief Non-template definitions and data for `Partition` class hierarchy.
134  *
135  * The partition base class provides a common non-templated ground for all
136  * `Partition` hierarchies.
137  * The class defines an area that the partition cover, as a rectangle.
138  * The dimensions of this rectangle, called "width" and "depth", don't have
139  * to match any axis from any 3D coordinate system.
140  *
141  */
142  class PartitionBase: public AreaOwner {
143 
144  public:
145  // imported types
148 
149  /// Constructor: sets the covered area and no subpartitions.
150  PartitionBase(Area_t const& area): AreaOwner(area) {}
151 
152  protected:
153 
154  /// Returns a description of the partition area.
155  std::string describeArea
156  (std::string indent, std::string firstIndent) const;
157 
158  }; // class PartitionBase
159 
160 
161  //--------------------------------------------------------------------------
162  /**
163  * @brief Base element of a partitioned structure.
164  * @tparam Data type of data contained in the partition
165  *
166  * An area partition is represented by a hierarchy of partition objects,
167  * each one containing a non-owning pointer to the data pertaining its area.
168  *
169  * The partition classes all derive from this `Partition` class, which
170  * provides access to the data, the area definition and a few utility
171  * functions:
172  *
173  * * mainly for debugging purposes, the hierarchy can be dumped into a
174  * stream by the `describe()` method
175  * * method `walk()` applies a specified operation to all the partitions
176  * in the hierarchy, in an undefined order
177  * * method `atPoint()` returns the data of the partition covering the
178  * specified location
179  *
180  * The hierarchy is such that a partition object (`Partition`) knows or can
181  * find of all the subpartitions it contains, but it does not have any
182  * knowledge of the partition containing it (if any).
183  *
184  * The partition classes do not provide algorithms to establish their
185  * relations.
186  */
187  template <typename Data>
188  class Partition: public PartitionBase {
189 
190  public:
191  using Data_t = Data; ///< Type of data stored in the partition.
192  using Partition_t = Partition<Data>; ///< This type.
193  using Area_t = PartitionBase::Area_t; ///< Type of area.
194 
195  /// Type of list of subpartitions. It needs to preserve polymorphism.
196  using Subpartitions_t = std::vector<std::unique_ptr<Partition_t const>>;
197 
198  /// Constructor: sets the covered area and no subpartitions.
199  Partition(Area_t const& area): PartitionBase(area) {}
200 
201  /// Destructor (default, virtual).
202  virtual ~Partition() = default;
203 
204  /// Returns the datum directly stored (nullptr if none).
205  virtual Data_t* data() const { return nullptr; }
206 
207  /**
208  * @brief Returns the (sub)partition including the specified coordinates.
209  * @param w width coordinate of the point
210  * @param d depth coordinate of the point
211  * @return a pointer to the partition, or `nullptr` if none
212  *
213  * This method returns a pointer to the datum associated to the area the
214  * specified point (`w`, `d`) belongs to.
215  * The area is searched for among all the included partitions.
216  */
217  virtual Data_t* atPoint(double w, double d) const = 0;
218 
219  /// Returns a description of the partition.
221  (std::string indent, std::string firstIndent) const
222  { return doDescribe(indent, firstIndent); }
223 
224  /// Returns a description of the partition.
225  std::string describe(std::string indent = "") const
226  { return describe(indent, indent); }
227 
228  /**
229  * @brief Applies `pred` to all partitions.
230  * @tparam Pred a predicate type
231  * @param pred the predicate to be applied
232  *
233  * The predicate `pred` is applied to this partition first, and then to
234  * all subpartitions in no specified order.
235  *
236  * The predicate is any object behaving like a unary function of
237  * signature:
238  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp}
239  * void predicate(Partition<Data> const& part);
240  * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
241  * If the predicate returns a value, that value is ignored.
242  * The predicate is forwarded while "walking" through the partitions.
243  *
244  */
245  template <typename Pred>
246  void walk(Pred&& pred) const { walk(this, pred); }
247 
248  /// Returns the number of subparts in the partition (0 if simple element).
249  std::size_t nParts() const { return parts().size(); }
250 
251  protected:
252 
253  static Subpartitions_t const NoSubparts; ///< Subpartitions (if any).
254 
255  /// Returns a list of all subpartitions.
256  virtual Subpartitions_t const& parts() const { return NoSubparts; }
257 
258  /// Returns a description of the partition.
259  virtual std::string doDescribe
260  (std::string indent, std::string firstIndent) const
261  { return PartitionBase::describeArea(indent, firstIndent); }
262 
263  /// Applies `pred` to start partition first, and then to all
264  /// subpartitions.
265  template <typename Pred>
266  static void walk(Partition_t const* start, Pred&& pred);
267 
268  }; // class Partition<>
269 
270  //**************************************************************************
271  //*** Partition class hierarchy
272  //--------------------------------------------------------------------------
273  /// Partition also containing data directly.
274  template <typename Data>
275  class PartitionWithData: public Partition<Data> {
276 
277  public:
278  using Base_t = Partition<Data>; ///< Base class.
279  using Partition_t = Partition<Data>; ///< Base type of the partition.
280  using Data_t = typename Partition_t::Data_t; ///< Type of contained data.
281  using Area_t = typename Partition_t::Area_t; ///< Type of covered area.
282 
283  /// Constructor: sets the covered area and the contained datum
285  : Base_t(area), myData(myData)
286  {}
287 
288  /// Returns the datum directly stored (nullptr if none).
289  virtual Data_t* data() const override { return myData; }
290 
291  /// Returns stored datum only if point is covered, `nullptr` otherwise.
292  virtual Data_t* atPoint(double w, double d) const override
293  { return Base_t::contains(w, d)? myData: nullptr; }
294 
295  private:
296  Data_t* myData; ///< The contained datum.
297 
298  /// Returns a description of the partition.
299  virtual std::string doDescribe
300  (std::string indent, std::string firstIndent) const override;
301 
302  }; // class PartitionWithData
303 
304 
305  //--------------------------------------------------------------------------
306  /// Unpartitioned element ("leaf") of a partitioned area.
307  template <typename Data>
308  class PartitionElement: public PartitionWithData<Data> {
309 
310  public:
311  using Base_t = PartitionWithData<Data>; ///< Base class.
312 
313  // Import constructors
314  using Base_t::Base_t;
315 
316  }; // class PartitionElement
317 
318 
319  //--------------------------------------------------------------------------
320  /// Partition divided in subpartitions (abstract).
321  template <typename Data>
322  class PartitionContainer: public PartitionWithData<Data> {
323 
324  public:
325  using Base_t = PartitionWithData<Data>; ///< Base class.
326  using Partition_t = Partition<Data>; ///< Base type of the partition.
327 
328  // inherited types
329  using Data_t = typename Partition_t::Data_t;
330  using Area_t = typename Partition_t::Area_t;
332 
333  /// Returns stored datum only if point is covered, `nullptr` otherwise.
334  virtual Data_t* atPoint(double w, double d) const override;
335 
336  protected:
337  Subpartitions_t myParts; ///< List of subpartitions.
338 
339  /// Returns the number of contained subpartitions.
340  std::size_t size() const { return parts().size(); }
341 
342  /// Returns a list of the subpartitions owned.
343  virtual Subpartitions_t const& parts() const override { return myParts; }
344 
345  /**
346  * @brief Constructor: sets the partition.
347  * @param area overall area covered
348  * @param subpartitions list of subpartitions (pointers)
349  * @param defData datum to be returned for points not covered by
350  * subpartitions
351  *
352  * The subpartitions will be moved from the argument.
353  *
354  * It is required and assumed that the subpartitions do not overlap and
355  * that the points covered by them are a subset of `area`.
356  * Neither of theses requirements is checked.
357  */
359  Area_t const& area,
360  Subpartitions_t&& subpartitions,
361  Data_t* defData = nullptr
362  )
363  : Base_t(area, defData), myParts(std::move(subpartitions))
364  {}
365 
366  /// Returns the only partition which could contain the specified width.
367  virtual Partition_t const* findPart(double w, double d) const = 0;
368 
369  /// Describes this and each of the subpartitions.
370  virtual std::string doDescribe
371  (std::string indent, std::string firstIndent) const override;
372 
373  /// Introduction to the description of the subpartitions.
374  virtual std::string describeIntro() const;
375 
376  }; // class PartitionContainer<>
377 
378 
379  //--------------------------------------------------------------------------
380  /**
381  * @brief Partition of area sorted across a dimension.
382  * @tparam Data type of data contained in the partition
383  * @tparam Sorter type of functor providing comparison of partitions
384  *
385  * The sorter is a functor containing comparison functions. It must be
386  * compatible with both `std::sort()` and `std::lower_bound()` functions.
387  * The former requirement implies that the sorter can compare two constant
388  * pointers to partitions. The latter also implies that the sorter can
389  * compare a constant pointer to partition to a "key" (a real number), and
390  * vice versa. The meaning of this comparison is not prescribed; existing
391  * implementations interpret that value as a width or depth coordinate.
392  *
393  * A copy of the sorter is kept in this partition.
394  */
395  template <typename Data, typename Sorter>
396  class SortedPartition: public PartitionContainer<Data> {
397 
398  public:
399  using Base_t = PartitionContainer<Data>; ///< Base class.
400  using Partition_t = Partition<Data>; ///< Base type of the partition.
401  using Sorter_t = Sorter; ///< Type of sorter being used.
402 
403  // inherited data types
404  using Data_t = typename Partition_t::Data_t;
405  using Area_t = typename Partition_t::Area_t;
407 
408  /**
409  * @brief Constructor: sets the partition.
410  * @param area overall area covered
411  * @param subpartitions list of subpartitions (pointers)
412  * @param defData datum to be returned for points not covered by
413  * subpartitions
414  * @param sorter instance of the sorter to be used
415  *
416  * The subpartitions will be moved from the argument and will be sorted
417  * using the comparison contained in the `sorter`.
418  * Note that this will invalidate existing pointers to the sub-partitions.
419  *
420  * It is required and assumed that the subpartitions do not overlap and
421  * that the points covered by them are a subset of `area`.
422  * Neither of theses requirements is checked.
423  */
425  Area_t const& area,
426  Subpartitions_t&& subpartitions,
427  Data_t* defData = nullptr,
428  Sorter_t sorter = {}
429  )
430  : Base_t(area, std::move(subpartitions), defData), sorter(sorter)
431  { initParts(); }
432 
433  protected:
434 
435  Sorter_t sorter; ///< Object used for sorting and binary search.
436 
437  /// Returns the only partition which could contain the specified `key`.
438  Partition_t const* findPartWithKey(double key) const;
439 
440  /// Performs initialization on the specified subpartition list.
441  void initParts();
442 
443  }; // class SortedPartition<>
444 
445 
446  //--------------------------------------------------------------------------
447  /// Partition of area along a area range dimension (width or depth).
448  template<typename Data, PartitionBase::AreaRangeMember_t Range>
450  <Data, details::PartitionSorterByAreaRangeLower<Range>>
451  {
452  public:
453  /// Base class.
454  using Base_t = SortedPartition
456  using Base_t::Base_t; // import inherited constructors
457 
458  }; // class PartitionSortedByRange
459 
460 
461  //--------------------------------------------------------------------------
462  /// Partition of area along the depth dimension.
463  template <typename Data>
465  : public PartitionSortedByRange<Data, &PartitionBase::Area_t::depth>
466  {
467  public:
468  /// Base class.
469  using Base_t
471 
472  using Base_t::Base_t; // import inherited constructors
473 
474  /// Returns the only partition which could contain the specified depth.
475  virtual typename Base_t::Partition_t const* findPart
476  (double /* w */, double d) const override
477  { return Base_t::findPartWithKey(d); }
478 
479  private:
480 
481  virtual std::string describeIntro() const override;
482 
483  }; // class DepthPartition
484 
485 
486  //--------------------------------------------------------------------------
487  /// Partition of area along the width dimension.
488  template <typename Data>
490  : public PartitionSortedByRange<Data, &PartitionBase::Area_t::width>
491  {
492  public:
493  /// Base class.
494  using Base_t
496 
497  using Base_t::Base_t; // inherited constructors
498 
499  /// Returns the only partition which could contain the specified depth.
500  virtual typename Base_t::Partition_t const* findPart
501  (double w, double /* d */) const override
502  { return Base_t::findPartWithKey(w); }
503 
504  private:
505 
506  virtual std::string describeIntro() const override;
507 
508  }; // class WidthPartition
509 
510 
511  //--------------------------------------------------------------------------
512  /// A container of partitions organised in a width/depth rectangular grid.
513  template <typename Data>
514  class GridPartition: public PartitionContainer<Data> {
515  public:
516  using Partition_t = Partition<Data>; ///< Base type of the partition.
517  using Base_t = PartitionContainer<Data>; ///< Base class.
518 
519  // Inherited types
520  using Data_t = typename Partition_t::Data_t; ///< Type of contained data.
521  using Area_t = typename Partition_t::Area_t; ///< Type of covered area.
523 
524  /**
525  * @brief Creates a partition with a grid of subpartitions.
526  * @param area total area covered by this partition
527  * @param subpartitions all subpartitions, row by row
528  * @param nDepthPartitions number of partitions on depth direction ("rows")
529  * @param nWidthPartitions number of partitions on width direction ("columns")
530  * @param defData partition data for areas not covered by subpartitions
531  *
532  * The content of the collection of subpartitions is stolen.
533  * The subpartitions in that collection are expected to be organized by row:
534  * (0;0), (0,1), (0,2)... where the first index spans `nDepthPartitions`
535  * values and the second one spans `nWidthPartitions` values.
536  *
537  */
539  Area_t const& area,
540  Subpartitions_t&& subpartitions,
541  unsigned int nDepthPartitions, unsigned int nWidthPartitions,
542  Data_t* defData = nullptr
543  );
544 
545  /// Constructor: autodetects `nWidthPartitions` from number of
546  /// subpartitions.
548  Area_t const& area,
549  Subpartitions_t&& subpartitions,
550  unsigned int nDepthPartitions, Data_t* defData = nullptr
551  );
552 
553 
554  private:
555  std::vector<double> widthSeps; ///< Separators for width dimension.
556  std::vector<double> depthSeps; ///< Separators for depth dimension.
557 
558  /// Number of partitions on width direction.
559  std::size_t nWidthParts() const { return widthSeps.size(); }
560  ///< Number of partitions on depth direction.
561  std::size_t nDepthParts() const { return depthSeps.size(); }
562 
563  auto part(std::size_t iDepth, std::size_t iWidth) ->decltype(auto)
564  { return Base_t::parts()[iDepth * nWidthParts() + iWidth]; }
565  auto part(std::size_t iDepth, std::size_t iWidth) const ->decltype(auto)
566  { return Base_t::parts()[iDepth * nWidthParts() + iWidth]; }
567 
568  /// Returns the only partition which could contain the specified depth.
569  virtual Partition_t const* findPart(double w, double d) const override;
570 
571  /// Computes and returns width separation levels proper for `widthSeps`.
572  std::vector<double> computeWidthSeps
573  (unsigned int nD, unsigned int nW) const;
574  /// Computes and returns width separation levels proper for `depthSeps`.
575  std::vector<double> computeDepthSeps
576  (unsigned int nD, unsigned int nW) const;
577 
578  /// Prints the information about the partition grid.
579  virtual std::string doDescribe
580  (std::string indent, std::string firstIndent) const override;
581 
582  template<
584  typename BeginIter, typename EndIter
585  >
586  static std::vector<double> detectSeparators(
587  BeginIter b, EndIter e,
588  std::size_t const nGroups,
589  std::size_t const startDelta,
590  std::size_t const stride
591  );
592 
593  }; // class GridPartition<>
594 
595 
596  //--------------------------------------------------------------------------
597 
598  } // namespace part
599 } // namespace geo
600 
601 
602 //******************************************************************************
603 //*** inline implementation
604 //******************************************************************************
606  (std::string, std::string firstIndent) const
607 {
608  std::ostringstream sstr;
609  sstr << firstIndent << "partition covers ";
610  dumpArea(sstr);
611  return sstr.str();
612 } // geo::part::PartitionBase::describeArea()
613 
614 
615 //******************************************************************************
616 //*** template implementation
617 //******************************************************************************
618 
619 namespace geo {
620  namespace part {
621  namespace details {
622 
623  //------------------------------------------------------------------------
624  //--- some metaprogramming utilities
625  //------------------------------------------------------------------------
626  /// Trait type evaluating true if `T` is derived from `PartitionBase`.
627  template <typename T, typename = void>
628  struct is_partition_type: public std::false_type {};
629 
630  template <typename Part>
632  <
633  Part,
634  std::enable_if_t
635  <std::is_base_of<PartitionBase, std::decay_t<Part>>::value>
636  >
637  : public std::true_type
638  {};
639 
640  /// Constant true if `T` is derived from `PartitionBase`.
641  template <typename T>
643 
644 
645  //------------------------------------------------------------------------
646  /// Trait type evaluating true if `T` is pointer to some `PartitionBase`.
647  template <typename, typename = void>
648  struct is_partition_ptr: public std::false_type {};
649 
650  template <typename PartPtr>
652  <
653  PartPtr,
654  std::enable_if_t
655  <is_partition_type_v<decltype(*std::declval<PartPtr>())>>
656  >
657  : public std::true_type
658  {};
659 
660  /// Constant true if `T` is pointer to some `PartitionBase`.
661  template <typename T>
663 
664 
665  //------------------------------------------------------------------------
666  /// Trait type evaluating true if `T` is iterator to some `PartitionBase`.
667  template <typename, typename = void>
668  struct is_partition_ptr_iterator: public std::false_type {};
669 
670  template <typename Iter>
672  <
673  Iter,
674  std::enable_if_t
675  <is_partition_ptr_v<std::decay_t<typename Iter::value_type>>>
676  >
677  : public std::true_type
678  {};
679 
680 
681  //------------------------------------------------------------------------
682  //--- Sorting objects
683  //------------------------------------------------------------------------
684  /// Class extracting the lower bound of the specified range of an area.
685  template <AreaOwner::AreaRangeMember_t Range>
687  static constexpr auto range = Range;
689 
690  double operator() (double lower) const { return lower; }
691  double operator() (Area_t::Range_t const& r) const
692  { return (*this)(r.lower); }
693  double operator() (Area_t const& area) const
694  { return (*this)(area.*range); }
695  double operator() (AreaOwner const& area) const
696  { return (*this)(area.area()); }
697  double operator() (AreaOwner const* ptr) const
698  { return (*this)(*ptr); }
699 
700  }; // struct RangeLowerBoundExtractor<>
701 
702 
703  //------------------------------------------------------------------------
704  /// Class extracting the lower bound of the specified range of a partition
705  /// area.
706  template <PartitionBase::AreaRangeMember_t Range>
708  : public RangeLowerBoundExtractor<Range>
709  {
711  using Area_t = typename Base_t::Area_t;
712 
713  using Partition_t = PartitionBase; ///< Base type of the partition.
714 
715  using Base_t::operator(); // import inherited versions
716 
717  auto operator()(Partition_t const& part)
718  { return Base_t::operator()(part.area()); }
719  template <
720  typename PartPtr,
722  >
723  auto operator()(PartPtr const& part)
724  { return operator()(*part); }
725 
726  }; // struct PartitionRangeLowerBoundExtractor<>
727 
728 
729  //------------------------------------------------------------------------
730  template <PartitionBase::AreaRangeMember_t Range>
733 
735 
736  static constexpr auto range = Range;
737 
738  template <typename T>
739  static auto key(T const& obj) { return KeyExtractor_t()(obj); }
740 
741  /// Type of sorting key. In short: `double`.
742  using Key_t = decltype(Sorter_t::key(std::declval<PartitionBase>()));
743 
744  static Key_t key(Key_t k) { return k; } // shortcut
745  static bool sortKey(Key_t a, Key_t b) { return a < b; }
746 
747  template <typename A, typename B>
748  bool operator() (A const& a, B const& b) const
749  { return sortKey(key(a), key(b)); }
750 
751  }; // struct PartitionSorterByAreaRangeLower
752 
753 
754  //------------------------------------------------------------------------
755 
756  } // namespace details
757  } // namespace part
758 } // namespace geo
759 
760 
761 //------------------------------------------------------------------------------
762 //--- partition data description
763 //---
764 
765 template <typename Data>
766 template <typename Stream>
768  Stream&& out, Data const* data,
769  std::string indent /* = "" */, std::string firstIndent /* = "" */
770  )
771 {
772  out << firstIndent;
773  std::string typeName = lar::debug::demangle<Data>();
774  if (data) {
775  out << typeName << "[" << ((void*) data) << "]";
776  }
777  else {
778  out << "no '" << typeName << "' data";
779  }
780 } // geo::part::PartitionDataDescriber::PartitionDataDescriber()
781 
782 
783 template <typename Stream, typename Data>
785  Stream&& out, Data const* data,
786  std::string indent /* = "" */, std::string firstIndent /* = "" */
787  )
788 {
790  (std::forward<Stream>(out), data, indent, firstIndent);
791 } // geo::part::describePartitionData()
792 
793 
794 //------------------------------------------------------------------------------
795 //--- geo::part::Partition
796 //---
797 template <typename Data>
800 
801 //------------------------------------------------------------------------------
802 template <typename Data>
803 template <typename Pred>
805  if (!start) return;
806  pred(*start);
807 
808  // recursive implementation
809  for (auto const& subPart: start->parts())
810  subPart->walk(std::forward<Pred>(pred));
811 
812 } // geo::part::Partition<Data>::walk()
813 
814 
815 //------------------------------------------------------------------------------
816 //--- geo::part::PartitionWithData
817 //---
818 template <typename Data>
820  (std::string indent, std::string firstIndent) const
821 {
822  std::string msg = Base_t::doDescribe(indent, firstIndent);
823  if (data()) {
824  std::ostringstream sstr;
825  sstr << ": ";
826  describePartitionData(sstr, data(), indent);
827  msg += sstr.str();
828  }
829  else {
830  msg += " (no data)";
831  }
832  return msg;
833 } // geo::part::PartitionWithData<Data>::doDescribe()
834 
835 
836 //------------------------------------------------------------------------------
837 //--- geo::part::PartitionContainer
838 //---
839 //------------------------------------------------------------------------------
840 template <typename Data>
841 auto geo::part::PartitionContainer<Data>::atPoint(double w, double d) const
842  -> Data_t*
843 {
844  if (!Base_t::contains(w, d)) return nullptr; // not our point at all
845  // it's ours; see if it belongs to a subpart
846  auto part = findPart(w, d);
847  return part? part->atPoint(w, d): Base_t::data();
848 } // geo::part::PartitionContainer<Data>::atPoint()
849 
850 
851 //------------------------------------------------------------------------------
852 template <typename Data>
854  (std::string indent, std::string firstIndent) const
855 {
856  std::string msg = firstIndent + describeIntro();
857  if (Base_t::data()) {
858  std::ostringstream sstr;
859  sstr << ", and ";
860  describePartitionData(sstr, Base_t::data(), indent, "");
861  msg += sstr.str();
862  }
863 
864  for (auto const& part: parts()) {
865  msg += "\n" + indent + " * ";
866  msg += part->describe(indent + " ", "");
867  }
868 
869  return msg;
870 } // geo::part::PartitionContainer<Data>::doDescribe()
871 
872 
873 //------------------------------------------------------------------------------
874 template <typename Data>
876  return std::to_string(parts().size()) + " subpartitions";
877 } // geo::part::PartitionContainer<Data>::describeIntro()
878 
879 
880 //------------------------------------------------------------------------------
881 //--- geo::part::SortedPartition
882 //---
883 template <typename Data, typename Sorter>
885  -> Partition_t const*
886 {
887  auto pbegin = Base_t::parts().cbegin();
888  auto iPart = std::upper_bound(pbegin, Base_t::parts().cend(), key, sorter);
889  return (iPart == pbegin)? nullptr: (--iPart)->get();
890 } // geo::part::SortedPartition<>::findPartWithKey()
891 
892 
893 //------------------------------------------------------------------------------
894 template <typename Data, typename Sorter>
896  /*
897  * Initialization tasks:
898  * - ensure that the parts are sorted by increasing depth
899  *
900  */
901  std::sort(Base_t::myParts.begin(), Base_t::myParts.end(), sorter);
902 
903 } // geo::part::SortedPartition<>::initParts()
904 
905 
906 //------------------------------------------------------------------------------
907 //--- geo::part::DepthPartition
908 //---
909 template <typename Data>
911  std::ostringstream sstr;
912  sstr
913  << Base_t::size() << " partitions along depth covering " << Base_t::area();
914  return sstr.str();
915 } // geo::part::DepthPartition<Data>::describeIntro()
916 
917 
918 //------------------------------------------------------------------------------
919 //--- geo::part::WidthPartition
920 //---
921 template <typename Data>
923  std::ostringstream sstr;
924  sstr
925  << Base_t::size() << " partitions along width covering " << Base_t::area();
926  return sstr.str();
927 } // geo::part::WidthPartition<Data>::describeIntro()
928 
929 
930 //------------------------------------------------------------------------------
931 //--- geo::part::GridPartition
932 //---
933 template <typename Data>
935  Area_t const& area,
936  Subpartitions_t&& subpartitions,
937  unsigned int nDepthPartitions, unsigned int nWidthPartitions,
938  Data_t* defData /* = nullptr */
939  )
940  : Base_t(area, std::move(subpartitions), defData)
941  , widthSeps(computeWidthSeps(nDepthPartitions, nWidthPartitions))
942  , depthSeps(computeDepthSeps(nDepthPartitions, nWidthPartitions))
943 {
944  assert(nWidthPartitions * nDepthPartitions == Base_t::size());
945 } // geo::part::GridPartition<Data>::GridPartition()
946 
947 
948 template <typename Data>
950  Area_t const& area,
951  Subpartitions_t&& subpartitions,
952  unsigned int nDepthPartitions, Data_t* defData /* = nullptr */
953  )
954  : GridPartition(
955  area, std::move(subpartitions), nDepthPartitions,
956  (nDepthPartitions? subpartitions.size()/nDepthPartitions: 0),
957  defData
958  )
959  {}
960 
961 
962 //------------------------------------------------------------------------------
963 template <typename Data>
965  (std::string indent, std::string firstIndent) const
966 {
967  std::ostringstream sstr;
968  sstr << firstIndent << Base_t::describeIntro()
969  << " in a (WxD) = " << nWidthParts() << " x " << nDepthParts() << " grid";
970  if (Base_t::data()) {
971  sstr << ", and ";
972  describePartitionData(sstr, Base_t::data(), indent, "");
973  }
974  for (std::size_t iDepth = 0; iDepth < nDepthParts(); ++iDepth) {
975  for (std::size_t iWidth = 0; iWidth < nWidthParts(); ++iWidth) {
976  sstr << "\n" << indent << " [" << iDepth << "][" << iWidth << "] "
977  << part(iDepth, iWidth)->describe(indent + " ", "");
978  } // for width
979  } // for depth
980 
981  return sstr.str();
982 } // geo::part::GridPartition<Data>::doDescribe()
983 
984 
985 //------------------------------------------------------------------------------
986 template <typename Data>
987 auto geo::part::GridPartition<Data>::findPart(double w, double d) const
988  -> Partition_t const*
989 {
990  auto const iWidth = std::upper_bound(widthSeps.cbegin(), widthSeps.cend(), w);
991  if (iWidth == widthSeps.cbegin()) return nullptr;
992  auto const iDepth = std::upper_bound(depthSeps.cbegin(), depthSeps.cend(), d);
993  if (iDepth == depthSeps.cbegin()) return nullptr;
994  return part(
995  std::distance(depthSeps.cbegin(), iDepth) - 1U,
996  std::distance(widthSeps.cbegin(), iWidth) - 1U
997  ).get();
998 } // geo::part::GridPartition<Data>::findPart()
999 
1000 
1001 //------------------------------------------------------------------------------
1002 template <typename Data>
1004  (unsigned int, unsigned int nW) const
1005 {
1006  return detectSeparators<&Area_t::width>
1007  (Base_t::parts().cbegin(), Base_t::parts().cend(), nW, 1U, nW);
1008 } // geo::part::GridPartition<Data>::computeWidthSeps()
1009 
1010 
1011 template <typename Data>
1013  (unsigned int nD, unsigned int nW) const
1014 {
1015  return detectSeparators<&Area_t::depth>
1016  (Base_t::parts().cbegin(), Base_t::parts().cend(), nD, nW, 1U);
1017 } // geo::part::GridPartition<Data>::computeDepthSeps()
1018 
1019 
1020 template <typename Data>
1021 template<
1023  typename BeginIter, typename EndIter
1024  >
1026  BeginIter b, EndIter e,
1027  std::size_t const nGroups,
1028  std::size_t const startDelta,
1029  std::size_t const stride
1030 ) {
1031  /*
1032  * The iterators are better be random access.
1033  * The range [b,e[ is considered to be a 2D table stored row after row.
1034  * This function can operate on rows or columns, given the proper arguments.
1035  *
1036  * The full range is split in nGroups "groups" (e.g. rows or columns).
1037  * Each group g starts at the element g x startDelta.
1038  * All members of that group are stride elements far from each other.
1039  *
1040  * Be the table of size (d x w).
1041  * To process data row by row:
1042  * - the group is a row
1043  * - the number of groups is the number of rows: nGroups = d
1044  * - each group will have (d x w)/nGroups = w elements
1045  * - the start offset is the number of group times the size of it:
1046  * startDelta = w
1047  * - the elements are contiguous: stride = 1
1048  *
1049  * To process data column by column:
1050  * - the group is a column
1051  * - the number of groups is the number of columns: nGroups = w
1052  * - each group will have (d x w)/nGroups = d elements
1053  * - the start offset matches the number of group: startDelta = 1
1054  * - the elements are separated by a full row: stride = w
1055  *
1056  */
1057  // the separator is on the lower bound of selected range of the partition area
1058 
1060  "Begin iterator does not point to a pointer to partition type");
1061 
1063 
1064  std::size_t const nParts = std::distance(b, e);
1065  std::size_t const nPartsInGroup = nParts / nGroups;
1066 
1067  auto const part
1068  = [b](std::size_t index){ return std::next(b, index)->get(); };
1069 
1070  std::vector<double> seps(nGroups);
1071  for (size_t g = 0; g < nGroups; ++g) {
1072 
1073  double& sep = seps[g];
1074 
1075  // indices of an element in the previous and next group, respectively
1076  std::size_t index = g * startDelta;
1077  sep = lowerBound(part(index));
1078 
1079  std::size_t const iend = index + nPartsInGroup * stride;
1080  while ((index += stride) < iend) {
1081  double const l = lowerBound(part(index));
1082  if (sep > l) sep = l;
1083  } // while (element)
1084 
1085  } // while (groups)
1086  return seps;
1087 } // geo::part::GridPartition<Data>::detectSeparators()
1088 
1089 
1090 //******************************************************************************
1091 
1092 #endif // LARCOREALG_GEOMETRY_PARTITIONS_H
Partition_t const * findPartWithKey(double key) const
Returns the only partition which could contain the specified key.
Definition: Partitions.h:884
end
while True: pbar.update(maxval-len(onlies[E][S])) #print iS, "/", len(onlies[E][S]) found = False for...
AreaOwner(Area_t const &area)
Constructor: sets the covered area and no subpartitions.
Definition: Partitions.h:49
Trait type evaluating true if T is iterator to some PartitionBase.
Definition: Partitions.h:668
PartitionBase(Area_t const &area)
Constructor: sets the covered area and no subpartitions.
Definition: Partitions.h:150
PartitionContainer(Area_t const &area, Subpartitions_t &&subpartitions, Data_t *defData=nullptr)
Constructor: sets the partition.
Definition: Partitions.h:358
A basic interface for objects owning an area.
Definition: Partitions.h:39
void describePartitionData(Stream &&out, Data const *data, std::string indent="", std::string firstIndent="")
Describes a data object for Partition::describe() method.
Definition: Partitions.h:784
auto part(std::size_t iDepth, std::size_t iWidth) const -> decltype(auto)
Definition: Partitions.h:565
std::vector< double > computeDepthSeps(unsigned int nD, unsigned int nW) const
Computes and returns width separation levels proper for depthSeps.
Definition: Partitions.h:1013
constexpr bool is_partition_type_v
Constant true if T is derived from PartitionBase.
Definition: Partitions.h:642
AreaOwner::Area_t Area_t
Definition: Partitions.h:146
decltype(auto) constexpr cend(T &&obj)
ADL-aware version of std::cend.
Definition: StdUtils.h:87
static constexpr double g
Definition: Units.h:144
Partition of area along the width dimension.
Definition: Partitions.h:489
void msg(const char *fmt,...)
Definition: message.cpp:107
virtual std::string doDescribe(std::string indent, std::string firstIndent) const override
Describes this and each of the subpartitions.
Definition: Partitions.h:854
void initParts()
Performs initialization on the specified subpartition list.
Definition: Partitions.h:895
std::string string
Definition: nybbler.cc:12
virtual Data_t * atPoint(double w, double d) const override
Returns stored datum only if point is covered, nullptr otherwise.
Definition: Partitions.h:841
bool contains(Data_t w, Data_t d) const
Returns whether the specified point is in the area.
Definition: SimpleGeo.h:408
STL namespace.
Class providing custom dump for data contained in the partition.
Definition: Partitions.h:97
std::vector< double > depthSeps
Separators for depth dimension.
Definition: Partitions.h:556
virtual Data_t * data() const
Returns the datum directly stored (nullptr if none).
Definition: Partitions.h:205
Ordering class to sort partition by specified range (lower boundary).
Definition: Partitions.h:72
Functions to help debugging by instrumenting code.
static QStrList * l
Definition: config.cpp:1044
std::vector< double > widthSeps
Separators for width dimension.
Definition: Partitions.h:555
AreaOwner::AreaRangeMember_t AreaRangeMember_t
Definition: Partitions.h:147
bool contains(double w, double d) const
Returns whether the specified point is covered by this object.
Definition: Partitions.h:52
std::vector< double > computeWidthSeps(unsigned int nD, unsigned int nW) const
Computes and returns width separation levels proper for widthSeps.
Definition: Partitions.h:1004
std::string describe(std::string indent="") const
Returns a description of the partition.
Definition: Partitions.h:225
Partition(Area_t const &area)
Constructor: sets the covered area and no subpartitions.
Definition: Partitions.h:199
Trait type evaluating true if T is derived from PartitionBase.
Definition: Partitions.h:628
Non-template definitions and data for Partition class hierarchy.
Definition: Partitions.h:142
decltype(auto) constexpr size(T &&obj)
ADL-aware version of std::size.
Definition: StdUtils.h:92
std::vector< std::unique_ptr< Partition_t const >> Subpartitions_t
Type of list of subpartitions. It needs to preserve polymorphism.
Definition: Partitions.h:196
Base element of a partitioned structure.
Definition: Partitions.h:188
virtual Subpartitions_t const & parts() const
Returns a list of all subpartitions.
Definition: Partitions.h:256
Partition of area along the depth dimension.
Definition: Partitions.h:464
Area_t myArea
Covered area.
Definition: Partitions.h:63
const double e
std::string describe(cet::exempt_ptr< fhicl::ConfigurationTable const > pb, std::string const &prefix)
Definition: describe.cc:6
def key(type, name=None)
Definition: graph.py:13
const double a
def move(depos, offset)
Definition: depos.py:107
virtual std::string doDescribe(std::string indent, std::string firstIndent) const override
Returns a description of the partition.
Definition: Partitions.h:820
Partition of area along a area range dimension (width or depth).
Definition: Partitions.h:449
lar::util::simple_geo::Rectangle< double > Area_t
Type of area covered by the partition.
Definition: Partitions.h:43
def walk(top, topdown=True)
Area_t const & area() const
Returns the covered area.
Definition: Partitions.h:56
PartitionWithData(Area_t const &area, Data_t *myData)
Constructor: sets the covered area and the contained datum.
Definition: Partitions.h:284
std::size_t size() const
Returns the number of contained subpartitions.
Definition: Partitions.h:340
void walk(Pred &&pred) const
Applies pred to all partitions.
Definition: Partitions.h:246
virtual Subpartitions_t const & parts() const override
Returns a list of the subpartitions owned.
Definition: Partitions.h:343
double distance(double x1, double y1, double z1, double x2, double y2, double z2)
virtual Partition_t const * findPart(double w, double d) const override
Returns the only partition which could contain the specified depth.
Definition: Partitions.h:987
Sorter Sorter_t
Type of sorter being used.
Definition: Partitions.h:401
Range< Data_t > Range_t
Type for dimension boundaries.
Definition: SimpleGeo.h:391
static Subpartitions_t const NoSubparts
Subpartitions (if any).
Definition: Partitions.h:253
Subpartitions_t myParts
List of subpartitions.
Definition: Partitions.h:337
Data_t * myData
The contained datum.
Definition: Partitions.h:296
void dumpArea(Stream &&out) const
Output the owned area into an output stream.
Definition: Partitions.h:60
Class extracting the lower bound of the specified range of an area.
Definition: Partitions.h:686
std::size_t nWidthParts() const
Number of partitions on width direction.
Definition: Partitions.h:559
virtual Data_t * data() const override
Returns the datum directly stored (nullptr if none).
Definition: Partitions.h:289
virtual Data_t * atPoint(double w, double d) const override
Returns stored datum only if point is covered, nullptr otherwise.
Definition: Partitions.h:292
Fw2dFFT::Data Data
Unpartitioned element ("leaf") of a partitioned area.
Definition: Partitions.h:308
Partition divided in subpartitions (abstract).
Definition: Partitions.h:322
decltype(Sorter_t::key(std::declval< PartitionBase >())) Key_t
Type of sorting key. In short: double.
Definition: Partitions.h:742
auto part(std::size_t iDepth, std::size_t iWidth) -> decltype(auto)
Definition: Partitions.h:563
SortedPartition(Area_t const &area, Subpartitions_t &&subpartitions, Data_t *defData=nullptr, Sorter_t sorter={})
Constructor: sets the partition.
Definition: Partitions.h:424
constexpr bool is_partition_ptr_v
Constant true if T is pointer to some PartitionBase.
Definition: Partitions.h:662
Sorter_t sorter
Object used for sorting and binary search.
Definition: Partitions.h:435
static std::vector< double > detectSeparators(BeginIter b, EndIter e, std::size_t const nGroups, std::size_t const startDelta, std::size_t const stride)
Definition: Partitions.h:1025
Some simple functions to represent geometry entities.
Partition of area sorted across a dimension.
Definition: Partitions.h:396
virtual std::string describeIntro() const
Introduction to the description of the subpartitions.
Definition: Partitions.h:875
std::size_t nDepthParts() const
Definition: Partitions.h:561
static bool * b
Definition: config.cpp:1043
A container of partitions organised in a width/depth rectangular grid.
Definition: Partitions.h:514
Trait type evaluating true if T is pointer to some PartitionBase.
Definition: Partitions.h:648
virtual std::string doDescribe(std::string indent, std::string firstIndent) const override
Prints the information about the partition grid.
Definition: Partitions.h:965
decltype(auto) constexpr begin(T &&obj)
ADL-aware version of std::begin.
Definition: StdUtils.h:72
std::size_t nParts() const
Returns the number of subparts in the partition (0 if simple element).
Definition: Partitions.h:249
virtual std::string describeIntro() const override
Definition: Partitions.h:910
std::string describeArea(std::string indent, std::string firstIndent) const
Returns a description of the partition area.
Definition: Partitions.h:606
Data_t lower
Starting coordinate.
Definition: SimpleGeo.h:326
LArSoft geometry interface.
Definition: ChannelGeo.h:16
GridPartition(Area_t const &area, Subpartitions_t &&subpartitions, unsigned int nDepthPartitions, unsigned int nWidthPartitions, Data_t *defData=nullptr)
Creates a partition with a grid of subpartitions.
Definition: Partitions.h:934
std::string to_string(ModuleType const mt)
Definition: ModuleType.h:34
Partition also containing data directly.
Definition: Partitions.h:275
PartitionDataDescriber(Stream &&out, Data const *data, std::string indent="", std::string firstIndent="")
Constructor; see describePartitionData() for argument description.
Definition: Partitions.h:767
virtual std::string describeIntro() const override
Definition: Partitions.h:922
Area_t::Range_t(Area_t::*) AreaRangeMember_t
Type of pointer to Area_t data member of type Range_t.
Definition: Partitions.h:46