LArSoft  v07_13_02
Liquid Argon Software toolkit - http://larsoft.org/
DriftPartitions.cxx File Reference

Classes describing partition of cryostat volume. More...

#include "larcorealg/Geometry/DriftPartitions.h"
#include "larcorealg/Geometry/BoxBoundedGeo.h"
#include "larcorealg/Geometry/TPCGeo.h"
#include "larcorealg/Geometry/CryostatGeo.h"
#include "larcorealg/Geometry/Decomposer.h"
#include "larcorealg/CoreUtils/DumpUtils.h"
#include "larcorealg/CoreUtils/RealComparisons.h"
#include "cetlib_except/exception.h"
#include "messagefacility/MessageLogger/MessageLogger.h"
#include <vector>
#include <iterator>
#include <algorithm>
#include <utility>
#include <memory>
#include <type_traits>
#include <cassert>
#include <cmath>
#include <cstdlib>

Go to the source code of this file.

Classes

struct  TPCgroup_t
 
struct  TPCwithArea_t
 
struct  SorterByKey< Key, ExtractKey, Comparer >
 

Typedefs

using TPCandPos_t = std::pair< double, geo::TPCGeo const * >
 
template<geo::part::AreaOwner::AreaRangeMember_t Range>
using SortTPCareaByAreaRangeLower = SorterByKey< double, geo::part::details::RangeLowerBoundExtractor< Range >>
 
using SortTPCwithAreaByWidth = SortTPCareaByAreaRangeLower<&geo::part::AreaOwner::Area_t::width >
 
using SortTPCwithAreaByDepth = SortTPCareaByAreaRangeLower<&geo::part::AreaOwner::Area_t::depth >
 

Functions

std::vector< std::pair< geo::DriftPartitions::DriftDir_t, std::vector< geo::TPCGeo const * > > > groupTPCsByDriftDir (geo::CryostatGeo const &cryo)
 
std::vector< TPCandPos_tsortTPCsByDriftCoord (std::vector< geo::TPCGeo const * > const &TPCs, geo::DriftPartitions::Decomposer_t const &decomp)
 
std::vector< TPCgroup_tgroupByDriftCoordinate (std::vector< TPCandPos_t > const &TPCs)
 
unsigned int checkTPCcoords (std::vector< geo::TPCGeo const * > const &TPCs)
 
template<typename Range >
geo::DriftPartitions::DriftDir_t detectGlobalDriftDir (Range &&directions)
 
geo::part::AreaOwner::Area_t TPCarea (geo::TPCGeo const &TPC, geo::DriftPartitions::Decomposer_t const &decomposer)
 
std::vector< TPCwithArea_taddAreaToTPCs (std::vector< geo::TPCGeo const * > const &TPCs, geo::DriftPartitions::Decomposer_t const &decomposer)
 
template<typename BeginIter , typename EndIter >
geo::part::AreaOwner::Area_t computeTotalArea (BeginIter TPCbegin, EndIter TPCend)
 
template<geo::part::AreaOwner::AreaRangeMember_t sortingRange, typename BeginIter , typename EndIter >
std::vector< std::vector< TPCwithArea_t const * >::const_iteratorgroupTPCsByRangeCoord (BeginIter beginTPCwithArea, EndIter endTPCwithArea)
 
template<geo::part::AreaOwner::AreaRangeMember_t sortingRange, typename BeginIter , typename EndIter >
std::pair< std::vector< TPCwithArea_t const * >, std::vector< std::vector< TPCwithArea_t const * >::const_iterator > > sortAndGroupTPCsByRangeCoord (BeginIter beginTPCwithArea, EndIter endTPCwithArea)
 
template<typename BeginIter , typename EndIter , typename TPCendIter , typename SubpartMaker >
geo::part::Partition< geo::TPCGeo const >::Subpartitions_t createSubpartitions (BeginIter itTPCbegin, EndIter itTPCend, TPCendIter TPCend, SubpartMaker subpartMaker)
 
auto makeTPCPartitionElement (TPCwithArea_t const &TPCinfo)
 
template<typename BeginIter , typename EndIter >
std::unique_ptr< geo::part::Partition< geo::TPCGeo const > > makeWidthPartition (BeginIter beginTPCwithArea, EndIter endTPCwithArea)
 
template<typename BeginIter , typename EndIter >
std::unique_ptr< geo::part::Partition< geo::TPCGeo const > > makeDepthPartition (BeginIter beginTPCwithArea, EndIter endTPCwithArea)
 
template<typename BeginIter , typename EndIter >
std::unique_ptr< geo::part::Partition< geo::TPCGeo const > > makeGridPartition (BeginIter beginTPCwithArea, EndIter endTPCwithArea)
 
template<typename BeginIter , typename EndIter >
std::unique_ptr< geo::part::Partition< geo::TPCGeo const > > makePartition (BeginIter beginTPCwithArea, EndIter endTPCwithArea)
 
template<typename TPCPartitionResultType , geo::part::AreaOwner::AreaRangeMember_t Range, typename BeginIter , typename EndIter , typename SubpartMaker >
std::unique_ptr< geo::part::Partition< geo::TPCGeo const > > makeSortedPartition (BeginIter beginTPCwithArea, EndIter endTPCwithArea, SubpartMaker subpartMaker)
 
template<typename BeginIter , typename EndIter >
auto makeCPointerVector (BeginIter b, EndIter e)
 
template<typename T >
auto makeCPointerVector (std::vector< T > const &v)
 
std::unique_ptr< geo::DriftPartitions::TPCPartition_tmakePartition (std::vector< TPCwithArea_t > const &TPCs)
 

Detailed Description

Classes describing partition of cryostat volume.

Author
Gianluca Petrillo (petri.nosp@m.llo@.nosp@m.fnal..nosp@m.gov)
Date
July 13, 2017
See also
DriftPartitions.h

Definition in file DriftPartitions.cxx.

Typedef Documentation

template<geo::part::AreaOwner::AreaRangeMember_t Range>
using SortTPCareaByAreaRangeLower = SorterByKey<double, geo::part::details::RangeLowerBoundExtractor<Range>>

Definition at line 488 of file DriftPartitions.cxx.

using TPCandPos_t = std::pair<double, geo::TPCGeo const*>

Definition at line 159 of file DriftPartitions.cxx.

Function Documentation

std::vector<TPCwithArea_t> addAreaToTPCs ( std::vector< geo::TPCGeo const * > const &  TPCs,
geo::DriftPartitions::Decomposer_t const &  decomposer 
)

Definition at line 429 of file DriftPartitions.cxx.

References computeTotalArea(), and TPCarea().

Referenced by geo::buildDriftVolumes().

432  {
433  /*
434  * Transforms a collection of TPCs into a collection of TPCs with area.
435  */
436  std::vector<TPCwithArea_t> result;
437  result.reserve(TPCs.size());
438 
439  for (auto const& TPC: TPCs)
440  result.emplace_back(TPCarea(*TPC, decomposer), TPC);
441 
442  return result;
443 } // addAreaToTPCs()
geo::part::AreaOwner::Area_t TPCarea(geo::TPCGeo const &TPC, geo::DriftPartitions::Decomposer_t const &decomposer)
unsigned int checkTPCcoords ( std::vector< geo::TPCGeo const * > const &  TPCs)

Definition at line 305 of file DriftPartitions.cxx.

References geo::vect::dot(), geo::DriftPartitions::driftCoord(), geo::TPCGeo::DriftDir(), e, geo::TPCGeo::ID(), lar::util::makeVector3DComparison(), lar::util::RealComparisons< RealType >::nonEqual(), and lar::dump::vector3D().

Referenced by geo::buildDriftVolumes().

305  {
306  /*
307  * Verify coordinate system consistency between TPCs:
308  * * need to have the same drift direction
309  * * need to have the same drift coordinate
310  *
311  * On error, it prints information on the error stream ("GeometryPartitions").
312  * It returns the number of errors found.
313  */
314 
315  auto iTPC = TPCs.cbegin(), tend = TPCs.cend();
316  if (iTPC == tend) {
317  mf::LogProblem("GeometryPartitions")
318  << "checkTPCcoords() got an empty partition.";
319  return 0;
320  }
321 
322  geo::TPCGeo const& refTPC = **iTPC;
323  decltype(auto) refDriftDir = refTPC.DriftDir();
324 
325  auto driftCoord = [&refDriftDir](geo::TPCGeo const& TPC)
326  { return geo::vect::dot(TPC.FirstPlane().GetCenter(), refDriftDir); };
327 
328  auto const refDriftPos = driftCoord(refTPC);
329 
331  auto vectorIs = lar::util::makeVector3DComparison(coordIs);
332 
333  unsigned int nErrors = 0U;
334  while (++iTPC != tend) {
335  geo::TPCGeo const& TPC = **iTPC;
336 
337  if (vectorIs.nonEqual(TPC.DriftDir(), refDriftDir)) {
338  mf::LogProblem("GeometryPartitions")
339  << "Incompatible drift directions between " << TPC.ID()
340  << " " << lar::dump::vector3D(TPC.DriftDir()) << " and " << refTPC.ID()
341  << " " << lar::dump::vector3D(refTPC.DriftDir());
342  ++nErrors;
343  }
344  auto const driftPos = driftCoord(TPC);
345  if (coordIs.nonEqual(driftPos, refDriftPos)) {
346  mf::LogProblem("GeometryPartitions")
347  << "Incompatible drift coordinate between " << TPC.ID()
348  << " (" << driftPos << "( and " << refTPC.ID() << " ("
349  << refDriftPos << ")";
350  ++nErrors;
351  }
352  } // while
353  return nErrors;
354 } // checkTPCcoords()
geo::TPCID const & ID() const
Returns the identifier of this TPC.
Definition: TPCGeo.h:278
Vector DriftDir() const
Returns the direction of the drift (vector pointing toward the planes).
Definition: TPCGeo.h:687
auto vector3D(Vector3D const &v)
Returns a manipulator which will print the specified vector.
Definition: DumpUtils.h:301
constexpr auto dot(Vector const &a, Vector const &b)
Return cross product of two vectors.
Provides simple real number checks.
Geometry information for a single TPC.
Definition: TPCGeo.h:37
MaybeLogger_< ELseverityLevel::ELsev_error, true > LogProblem
auto makeVector3DComparison(RealType threshold)
Creates a Vector3DComparison from a RealComparisons object.
Float_t e
Definition: plot.C:34
Namespace collecting geometry-related classes utilities.
template<typename BeginIter , typename EndIter >
geo::part::AreaOwner::Area_t computeTotalArea ( BeginIter  TPCbegin,
EndIter  TPCend 
)

Definition at line 449 of file DriftPartitions.cxx.

References lar::util::simple_geo::Rectangle< Data >::extendToInclude().

Referenced by addAreaToTPCs(), and makeSortedPartition().

450 {
451  /*
452  * Computes an area covering the areas from all TPCs delimited by the
453  * iterators in argument.
454  * Each iterator points to a AreaOwner pointer.
455  */
456  auto iTPC = TPCbegin;
457  geo::part::AreaOwner::Area_t totalArea((*iTPC)->area());
458  while (++iTPC != TPCend) totalArea.extendToInclude((*iTPC)->area());
459  return totalArea;
460 } // computeTotalArea()
void extendToInclude(Rectangle_t const &r)
Extends the range to include the specified point.
Definition: SimpleGeo.h:517
template<typename BeginIter , typename EndIter , typename TPCendIter , typename SubpartMaker >
geo::part::Partition<geo::TPCGeo const>::Subpartitions_t createSubpartitions ( BeginIter  itTPCbegin,
EndIter  itTPCend,
TPCendIter  TPCend,
SubpartMaker  subpartMaker 
)

Definition at line 593 of file DriftPartitions.cxx.

References makeTPCPartitionElement().

Referenced by makeSortedPartition().

596  {
597  /*
598  * Internal helper to create a sequence of partitions (geo::part::Partition)
599  * from groups of TPCs. Each TPC is specified as a pointer to TPCwithArea_t
600  * object.
601  *
602  * The groups are specified in a way that is more or less convenient after
603  * calling groupTPCsByRangeCoord(): the uber-iterators itTPCbegin and itTPCend
604  * delimit a collection of iterators pointing to the first TPC of a group
605  * (the pointed TPCs are on a different collection). This can define all
606  * groups, each group delimited by the TPC pointed by an iterator pointing at
607  * the beginning of that group and the TPC pointed by the next iterator,
608  * pointing at the beginning of the next group. The exception is the last
609  * group, for which there is no "next iterator pointing to the beginning of
610  * the next group". That information is provided separately by the third
611  * iterator argument, that is an iterator of a different type than the other
612  * two (which are "uber-iterators" whose values are iterators), and which
613  * points to the last available TPC, that is also the end iterator for the
614  * TPCs of the last group.
615  *
616  */
618 
619  // TPCgroups has an iterator to the starting TPC of each group.
620  // Iterators refer to the `TPCs` collection.
621  // The end iterator of the group is the starting iterator of the next one;
622  // the last group includes all the remaining TPCs and its end iterator is
623  // the end iterator of `TPCs`.
624  auto igbegin = itTPCbegin;
625  while (igbegin != itTPCend) {
626  auto const gbegin = *igbegin;
627  auto const gend = (++igbegin == itTPCend)? TPCend: *igbegin;
628 
629  //
630  // create a partition from the new group
631  //
632  if (std::distance(gbegin, gend) == 1) {
633  subparts.emplace_back(makeTPCPartitionElement(**gbegin));
634  }
635  else {
636  auto subpart = subpartMaker(gbegin, gend);
637  if (!subpart) return {}; // failure!!
638 
639  subparts.emplace_back(std::move(subpart));
640  }
641  } // while
642  return subparts;
643 } // createSubpartitions()
std::vector< std::unique_ptr< Partition_t const >> Subpartitions_t
Type of list of subpartitions. It needs to preserve polymorphism.
Definition: Partitions.h:196
auto makeTPCPartitionElement(TPCwithArea_t const &TPCinfo)
template<typename Range >
geo::DriftPartitions::DriftDir_t detectGlobalDriftDir ( Range &&  directions)

Definition at line 359 of file DriftPartitions.cxx.

References dir, geo::vect::dot(), e, lar::util::RealComparisons< RealType >::equal(), and lar::dump::vector3D().

Referenced by geo::buildDriftVolumes().

359  {
360  /*
361  * Returns the first of the specified directions (possibly flipped);
362  * throws an exception if any of them is not parallel to that one.
363  */
364  using std::cbegin;
365  using std::cend;
366  auto iDir = cbegin(directions);
367  auto dend = cend(directions);
368  if (!(iDir != dend)) {
369  throw cet::exception("buildDriftVolumes")
370  << "detectGlobalDriftDir(): no TPCs provided!\n";
371  }
372 
374  auto compatibleDir = [comp](auto const& a, auto const& b)
375  { return comp.equal(std::abs(geo::vect::dot(a, b)), +1.0); };
376 
377  auto const dir = *(iDir++);
378  for (; iDir != dend; ++iDir) {
379  if (compatibleDir(dir, *iDir)) continue;
380  throw cet::exception("buildDriftVolumes")
381  << "Found drift directions not compatible: " << lar::dump::vector3D(dir)
382  << " and " << lar::dump::vector3D(*iDir) << "\n";
383  } // for
384 
385  // mildly prefer positive directions
386  return ((dir.X() <= 0.0) && (dir.Y() <= 0.0) && (dir.Z() <= 0.0))? -dir: dir;
387 } // detectGlobalDriftDir()
auto vector3D(Vector3D const &v)
Returns a manipulator which will print the specified vector.
Definition: DumpUtils.h:301
constexpr auto dot(Vector const &a, Vector const &b)
Return cross product of two vectors.
Provides simple real number checks.
TDirectory * dir
Definition: macro.C:5
Float_t e
Definition: plot.C:34
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33
std::vector<TPCgroup_t> groupByDriftCoordinate ( std::vector< TPCandPos_t > const &  TPCs)

Definition at line 263 of file DriftPartitions.cxx.

References min, geo::TPCGeo::Nplanes(), and geo::TPCGeo::Plane0Pitch().

Referenced by geo::buildDriftVolumes(), and sortTPCsByDriftCoord().

264 {
265  /*
266  * Produces a list of TPC groups. Within each group, the TPCs have similar
267  * drift coordinate.
268  * Similar is defined arbitrarily as ten times the plane pitch (of the first
269  * planes of the TPC).
270  */
271  if (TPCs.empty()) return {};
272 
273  geo::TPCGeo const& firstTPC = *(TPCs.front().second);
274  // arbitrary 5 cm if the first TPC has only one plane (pixel readout?);
275  // protect against the case where planes have the same position
276  // (e.g. dual phase)
277  double const groupThickness = 10.0
278  * std::min(((firstTPC.Nplanes() > 1)? firstTPC.Plane0Pitch(1): 0.5), 0.1);
279 
280  auto iFirstTPC = TPCs.cbegin(), tend = TPCs.cend();
281 
282  std::vector<TPCgroup_t> result;
283  while (iFirstTPC != tend) {
284  double const posEnd = iFirstTPC->first + groupThickness; // not beyond here
285  double sumPos = 0.0;
286  std::vector<geo::TPCGeo const*> TPCs;
287  auto iEndGroup = iFirstTPC;
288  do {
289  TPCs.push_back(iEndGroup->second);
290  sumPos += iEndGroup->first;
291  ++iEndGroup;
292  } while ((iEndGroup != tend) && (iEndGroup->first < posEnd));
293 
294  double const averagePos = sumPos / TPCs.size();
295  result.emplace_back(averagePos, std::move(TPCs));
296 
297  iFirstTPC = iEndGroup;
298  } // while (outer)
299 
300  return result;
301 } // groupByDriftCoordinate()
unsigned int Nplanes() const
Number of planes in this tpc.
Definition: TPCGeo.h:145
Geometry information for a single TPC.
Definition: TPCGeo.h:37
double Plane0Pitch(unsigned int p) const
Returns the center of the TPC volume in world coordinates [cm].
Definition: TPCGeo.cxx:355
Int_t min
Definition: plot.C:26
std::vector<std::pair<geo::DriftPartitions::DriftDir_t, std::vector<geo::TPCGeo const*> > > groupTPCsByDriftDir ( geo::CryostatGeo const &  cryo)

Definition at line 183 of file DriftPartitions.cxx.

References geo::TPCGeo::DriftDir(), e, lar::util::makeVector3DComparison(), geo::CryostatGeo::NTPC(), geo::vect::rounded01(), lar::util::RealComparisons< RealType >::threshold, geo::CryostatGeo::TPC(), and lar::dump::vector().

Referenced by geo::buildDriftVolumes().

184 {
185  /*
186  * TPCs are grouped by their drift direction, allowing for a small rounding
187  * error.
188  * The result is a collection with one element for each group of TPCs sharing
189  * the same drift direction. Each element is a pair with that drift direction
190  * first, and a collection of all TPCs with that drift direction.
191  * Elements are in no particular order.
192  */
193  std::vector<std::pair
194  <geo::DriftPartitions::DriftDir_t, std::vector<geo::TPCGeo const*>>
195  >
196  result;
197 
199  auto vectorIs = lar::util::makeVector3DComparison(coordIs);
200 
201  auto const nTPCs = cryo.NTPC();
202  for (unsigned int iTPC = 0; iTPC < nTPCs; ++iTPC) {
203  geo::TPCGeo const& TPC = cryo.TPC(iTPC);
204 
205  decltype(auto) driftDir = TPC.DriftDir();
206 
207  std::size_t iGroup = 0;
208  for (; iGroup < result.size(); ++iGroup) {
209  if (vectorIs.nonEqual(driftDir, result[iGroup].first)) continue;
210  result[iGroup].second.push_back(&TPC);
211  break;
212  } // for
213 
214  // if we did not find a group yet, make a new one
215  if (iGroup == result.size()) {
216  result.emplace_back(
217  geo::vect::rounded01(driftDir, coordIs.threshold),
218  std::vector<geo::TPCGeo const*>{ &TPC }
219  );
220  } // if
221 
222  } // for
223 
224  return result;
225 } // groupTPCsByDriftDir()
Provides simple real number checks.
Geometry information for a single TPC.
Definition: TPCGeo.h:37
STL namespace.
for(int i=0;i< 401;i++)
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
Definition: DumpUtils.h:265
auto makeVector3DComparison(RealType threshold)
Creates a Vector3DComparison from a RealComparisons object.
Vector rounded01(Vector const &v, Scalar tol)
Returns a vector with all components rounded if close to 0, -1 or +1.
Direction_t DriftDir_t
Type representing the drift direction (assumed to have norm 1).
Float_t e
Definition: plot.C:34
template<geo::part::AreaOwner::AreaRangeMember_t sortingRange, typename BeginIter , typename EndIter >
std::vector<std::vector<TPCwithArea_t const*>::const_iterator> groupTPCsByRangeCoord ( BeginIter  beginTPCwithArea,
EndIter  endTPCwithArea 
)

Definition at line 503 of file DriftPartitions.cxx.

References lar::util::RealComparisons< RealType >::nonSmaller(), and sortAndGroupTPCsByRangeCoord().

504 {
505  /*
506  * Groups each TPC with all the following ones overlapping in the selected
507  * sorting range.
508  * The range of TPCs must be already sorted by lower sorting range coordinate.
509  * The result is a list of iterators like the ones in input (in fact, the
510  * first is always beginTPCwithArea).
511  * The iterators are expected to be valid also after this function has
512  * returned (lest the result be unusable).
513  */
514 
516 
517  // tolerate 1mm overlaps; this is way forgiving, but apparently there are
518  // geometries around (DUNE 35t) with overlaps of that size.
520 
521  auto gbegin = beginTPCwithArea;
522  while (gbegin != endTPCwithArea) {
523 
524  groupStart.push_back(gbegin);
525 
526  //
527  // detect the end of this group
528  //
529  auto range = (*gbegin)->area().*sortingRange;
530  auto gend = gbegin;
531  while (++gend != endTPCwithArea) {
532  //
533  // check if the sorting range of this TPC (gend) overlaps the accumulated
534  // one; since TPCs are sorted by lower end of the range, gend has that one
535  // larger than the accumulated one, and overlap happens only if that lower
536  // bound is smaller than the upper bound of the accumulated range;
537  // we need to avoid rounding errors: close borders are decided as
538  // non-overlapping
539  //
540  auto const& TPCrange = (*gend)->area().*sortingRange;
541  if (coordIs.nonSmaller(TPCrange.lower, range.upper))
542  break;
543  range.extendToInclude(TPCrange);
544  } // while (inner)
545 
546  // prepare for the next group
547  gbegin = gend;
548  } // while (outer)
549 
550  return groupStart;
551 
552 } // groupTPCsByRangeCoord<>()
Provides simple real number checks.
intermediate_table::const_iterator const_iterator
template<typename BeginIter , typename EndIter >
auto makeCPointerVector ( BeginIter  b,
EndIter  e 
)

Definition at line 1074 of file DriftPartitions.cxx.

Referenced by makeCPointerVector(), and makePartition().

1074  {
1075  using value_type = typename BeginIter::value_type;
1076  std::vector<value_type const*> result;
1077  result.reserve(std::distance(b, e));
1078  std::transform(b, e, std::back_inserter(result),
1079  [](auto& obj){ return std::addressof(obj); });
1080  return result;
1081 } // makeCPointerVector()
Float_t e
Definition: plot.C:34
template<typename T >
auto makeCPointerVector ( std::vector< T > const &  v)

Definition at line 1084 of file DriftPartitions.cxx.

References makeCPointerVector(), and makePartition().

1085  { return makeCPointerVector(v.cbegin(), v.cend()); }
auto makeCPointerVector(BeginIter b, EndIter e)
template<typename BeginIter , typename EndIter >
std::unique_ptr< geo::part::Partition< geo::TPCGeo const > > makeDepthPartition ( BeginIter  beginTPCwithArea,
EndIter  endTPCwithArea 
)

Definition at line 750 of file DriftPartitions.cxx.

References lar::util::simple_geo::Rectangle< Data >::depth, makeGridPartition(), and makeSortedPartition().

Referenced by makePartition(), makeTPCPartitionElement(), and makeWidthPartition().

751 {
752  return makeSortedPartition<
755  >
756  (beginTPCwithArea, endTPCwithArea, &makeWidthPartition<BeginIter, EndIter>);
757 } // makeDepthPartition()
Partition of area along the depth dimension.
Definition: Partitions.h:464
Range_t depth
Range along depth direction.
Definition: SimpleGeo.h:394
std::unique_ptr< geo::part::Partition< geo::TPCGeo const > > makeSortedPartition(BeginIter beginTPCwithArea, EndIter endTPCwithArea, SubpartMaker subpartMaker)
template<typename BeginIter , typename EndIter >
std::unique_ptr< geo::part::Partition< geo::TPCGeo const > > makeGridPartition ( BeginIter  beginTPCwithArea,
EndIter  endTPCwithArea 
)

Definition at line 763 of file DriftPartitions.cxx.

References if(), makePartition(), lar::util::RealComparisons< RealType >::nonSmaller(), part, lar::util::RealComparisons< RealType >::strictlyGreater(), and lar::util::RealComparisons< RealType >::strictlySmaller().

Referenced by makeDepthPartition(), makePartition(), and makeTPCPartitionElement().

764 {
765  /*
766  * Requires at least 4 input TPCs (otherwise, do not use GridPartition).
767  *
768  * 1. attempt a partition on width
769  * 1. if failed, return failure
770  * 2. attempt to partition the first subpartition on depth
771  * 1. if failed, return failure
772  * 3. extend each depth partition to the other width partitions
773  * 1. if the extension of one partition line fails, discard it
774  * 2. if no partition line survives, return failure
775  * 4. run makePartition() on each of the cells
776  * 5. create and return a GridPartition object from the subpartitions so
777  * created
778  *
779  * This algorithm could use some factorization...
780  */
781  using Area_t = geo::part::AreaOwner::Area_t;
782 
783  //
784  // sort by width coordinate; work with pointers for convenience
785  //
786  auto const TPCgroupInfo = sortAndGroupTPCsByRangeCoord<&Area_t::width>
787  (beginTPCwithArea, endTPCwithArea);
788  std::vector<TPCwithArea_t const*> const& TPCs = TPCgroupInfo.first;
790  TPCgroups = TPCgroupInfo.second;
791 
792  if (TPCs.empty()) return {}; // failure?
793  // with only one TPC, then makeTPCPartitionElement() should be used instead!
794  if (TPCs.size() < 4) return {};
795 
796  unsigned int const nWidthParts = TPCgroups.size();
797  if (nWidthParts <= 1) return {}; // only one group ain't no good
798 
799  //
800  // sort TPCs in the first width partition by depth coordinate
801  //
802  auto const FirstColGroupInfo
803  = sortAndGroupTPCsByRangeCoord<&Area_t::depth>(TPCgroups[0], TPCgroups[1]);
804  std::vector<TPCwithArea_t const*> const& FirstColTPCs
805  = FirstColGroupInfo.first;
807  FirstColGroups = FirstColGroupInfo.second;
808 
809  if (FirstColTPCs.empty()) return {}; // failure?
810  if (FirstColGroups.size() <= 1 ) return {}; // only one row ain't good either
811 
812  //
813  // collect all candidate separation ranges
814  //
815  // First depth partition has no lower limit, last one has no upper limit
816  // (they include all TPCs with depth lower than the upper limit in the first
817  // case, all TPCs with depth higher of the lower limit in the last case).
818  // Checks need to be done in the gaps between depth partitions.
819  // So we start by skipping the first border.
820 
822  std::vector<Area_t::Range_t> depthGaps; // candidate gaps
823  auto icnext = FirstColGroups.cbegin(), icprev = icnext,
824  icend = FirstColGroups.cend();
825  while (++icnext != icend) {
826  //
827  // establish the range of the group in the candidate depth partition
828  // from the group in the first width partition
829  //
830  auto const cprev = *icprev;
831  auto const cnext = *icnext;
832 
833  depthGaps.emplace_back
834  ((*cprev)->area().depth.upper, (*cnext)->area().depth.lower);
835 
836  icprev = icnext;
837  } // while
838  assert(!depthGaps.empty());
839 
840  //
841  // see that for every other width partition separations hold
842  //
843  auto igbegin = TPCgroups.cbegin();
844  while (++igbegin != TPCgroups.cend()) {
845  //
846  // prepare the TPC groups within this width partition
847  //
848  auto igend = std::next(igbegin);
849  auto gbegin = *igbegin;
850  auto gend = (igend == TPCgroups.cend())? TPCs.cend(): *igend;
851 
852  auto const ColGroupInfo
853  = sortAndGroupTPCsByRangeCoord<&Area_t::depth>(gbegin, gend);
854  std::vector<TPCwithArea_t const*> const& ColTPCs = ColGroupInfo.first;
856  ColGroups = ColGroupInfo.second;
857 
858  // failure to partition a single column means total failure
859  if (ColTPCs.empty()) return {};
860  if (ColGroups.size() <= 1) return {}; // only one row ain't good either
861 
862  //
863  // compute the coverage of each of the depth groups
864  //
865  std::vector<TPCwithArea_t::Area_t::Range_t> groupDepths(ColGroups.size());
866  auto iGDepth = groupDepths.begin();
867  for (auto icgstart = ColGroups.cbegin(); icgstart != ColGroups.cend();
868  ++icgstart, ++iGDepth)
869  {
870  auto const icgend = std::next(icgstart);
871  auto ictpc = *icgstart;
872  auto const ictend = (icgend == ColGroups.cend())? ColTPCs.cend(): *icgend;
873  while (ictpc != ictend)
874  iGDepth->extendToInclude((*(ictpc++))->area().depth);
875  } // for
876 
877  //
878  // check each of the remaining candidate gaps
879  //
880  auto iGap = depthGaps.begin();
881  while (iGap != depthGaps.end()) {
882  Area_t::Range_t& gap = *iGap;
883 
884  //
885  // check that the gap holds
886  //
887  bool bGoodGap = false;
888  // first TPC starting after the gap (even immediately after):
889  auto iCGroup = std::lower_bound(
890  groupDepths.cbegin(), groupDepths.cend(), gap.upper,
892  );
893 
894  // any TPCs before/after this gap?
895  if ((iCGroup != groupDepths.begin()) && (iCGroup != groupDepths.end())) {
896  Area_t::Range_t const& before = *(std::prev(iCGroup));
897  Area_t::Range_t const& after = *iCGroup;
898  Area_t::Range_t const TPCgap{ before.upper, after.lower };
899 
900  // correct the gap
901  if (coordIs.strictlySmaller(iGap->lower, TPCgap.lower))
902  iGap->lower = TPCgap.lower;
903  if (coordIs.strictlyGreater(iGap->upper, TPCgap.upper))
904  iGap->upper = TPCgap.upper;
905 
906  // if nothing is left, gap is gone
907  bGoodGap = coordIs.nonSmaller(iGap->upper, iGap->lower);
908  } // if TPCs around the gap
909 
910  //
911  // if the gap has been flagged as bad, remove it
912  //
913  if (bGoodGap) ++iGap;
914  else iGap = depthGaps.erase(iGap);
915 
916  } // while (separation)
917 
918  if (depthGaps.empty()) return {}; // no surviving gaps means failure
919 
920  } // while (width partition)
921 
922  //
923  // turn the gaps into separators
924  //
925  std::vector<double> depthSep;
926  std::transform(
927  depthGaps.cbegin(), depthGaps.cend(), std::back_inserter(depthSep),
928  [](auto const& r){ return (r.lower + r.upper) / 2.0; }
929  );
930  unsigned int const nDepthParts = depthSep.size() + 1;
931 
932  //
933  // fill the groups with TPCs, and create subpartitions from each of them
934  //
936  (nWidthParts * nDepthParts);
937  Area_t totalArea;
938 
939  unsigned int iWidth = 0;
940  for (auto igbegin = TPCgroups.cbegin(); igbegin != TPCgroups.cend();
941  ++igbegin, ++iWidth
942  ) {
943 
944  // sort TPCs in this group (yes, again; this time we don't group just yet)
945  auto igend = std::next(igbegin);
946  auto gbegin = *igbegin;
947  auto gend = (igend == TPCgroups.cend())? TPCs.cend(): *igend;
948  std::vector<TPCwithArea_t const*> ColTPCs(gbegin, gend);
949  std::sort(ColTPCs.begin(), ColTPCs.end(),
951 
952  unsigned int iDepth = 0;
953  auto cgstart = ColTPCs.cbegin(), TPCend = ColTPCs.cend();
954  for (double sep: depthSep) {
955 
956  //
957  // collect all TPCs for this partition
958  //
959  // the first TPC that starts *after* the separator:
960  auto cgend
961  = std::upper_bound(cgstart, TPCend, sep, SortTPCwithAreaByDepth());
962  // if we cut out TPCs that were included because of some tolerance,
963  // recover them now
964  while (cgend != cgstart) {
965  auto cglast = std::prev(cgend);
966  if (coordIs.strictlySmaller((*cglast)->area().depth.lower, sep)) break;
967  cgend = cglast;
968  } // while
969  assert(cgstart != cgend); // separator selection should guarantee this
970 
971  //
972  // create and register the partition
973  //
974  auto part = makePartition(cgstart, cgend);
975  if (!part) return {}; // late failure!
976  totalArea.extendToInclude(part->area());
977  subparts[iDepth * nWidthParts + iWidth] = std::move(part);
978 
979  ++iDepth;
980  cgstart = cgend;
981  } // for all depth separators
982 
983  //
984  // collect all the TPCs after the last separator
985  //
986  auto part = makePartition(cgstart, TPCend);
987  if (!part) return {}; // super-late failure!
988  totalArea.extendToInclude(part->area());
989  subparts[iDepth * nWidthParts + iWidth] = std::move(part);
990 
991  } // for all width partitions
992 
993  return std::make_unique<geo::part::GridPartition<geo::TPCGeo const>>
994  (totalArea, std::move(subparts), nWidthParts, nDepthParts);
995 
996 } // makeGridPartition()
std::unique_ptr< geo::part::Partition< geo::TPCGeo const > > makePartition(BeginIter beginTPCwithArea, EndIter endTPCwithArea)
Provides simple real number checks.
SortTPCareaByAreaRangeLower<&geo::part::AreaOwner::Area_t::depth > SortTPCwithAreaByDepth
std::vector< std::unique_ptr< Partition_t const >> Subpartitions_t
Type of list of subpartitions. It needs to preserve polymorphism.
Definition: Partitions.h:196
if(nlines<=0)
intermediate_table::const_iterator const_iterator
lar::util::simple_geo::Rectangle< double > Area_t
Type of area covered by the partition.
Definition: Partitions.h:43
TString part[npart]
Definition: Style.C:32
template<typename BeginIter , typename EndIter >
std::unique_ptr< geo::part::Partition< geo::TPCGeo const > > makePartition ( BeginIter  beginTPCwithArea,
EndIter  endTPCwithArea 
)

Definition at line 1002 of file DriftPartitions.cxx.

References makeDepthPartition(), makeGridPartition(), makeTPCPartitionElement(), and makeWidthPartition().

Referenced by geo::buildDriftVolumes(), makeCPointerVector(), makeGridPartition(), makePartition(), and makeTPCPartitionElement().

1003 {
1004  /*
1005  * Organizes a list of TPCs in a hierarchical partition.
1006  * Three main elements are used:
1007  * - single element partition objects: that's the single TPC end point
1008  * - TPC groups organised along width
1009  * - TPC groups organised along depth
1010  *
1011  * The procedure is recursively analysing a set of TPCs:
1012  * - if the set is actually one TPC only, use a PartitionElement
1013  * - attempt partitioning o a grid; if fails:
1014  * - attempt partitioning along width:
1015  * * determine overlapping groups: a set of TPCs which share part of the
1016  * width range
1017  * * recurse on each overlapping group with more than one TPC,
1018  * attempting a depth partition
1019  * * if that fails, bail out since we don't have code to deal with a layout
1020  * with areas overlapping on both directions at the same time
1021  * * add the single elements and the overlapping groups to the width
1022  * partition
1023  * - attempt partitioning along height:
1024  * * same algorithm as for width
1025  * - pick the partitioning with less elements
1026  */
1027  using value_type = std::remove_reference_t<decltype(*beginTPCwithArea)>;
1028  static_assert(
1029  std::is_pointer<value_type>()
1030  && std::is_same
1031  <std::decay_t<std::remove_pointer_t<value_type>>, TPCwithArea_t>(),
1032  "Iterators must point to TPCwithArea_t pointers."
1033  );
1034 
1035 
1036  auto const size = std::distance(beginTPCwithArea, endTPCwithArea);
1037  if (size == 1) {
1038  return makeTPCPartitionElement(**beginTPCwithArea);
1039  }
1040 
1041  auto gPart = makeGridPartition(beginTPCwithArea, endTPCwithArea);
1042  if (gPart) return gPart;
1043 
1044  auto wPart = makeWidthPartition(beginTPCwithArea, endTPCwithArea);
1045  auto dPart = makeDepthPartition(beginTPCwithArea, endTPCwithArea);
1046 
1047  if (wPart) {
1048 
1049  if (dPart) { // wPart && dPart
1050  if (wPart->nParts() < dPart->nParts()) return wPart;
1051  else return dPart; // slight preference
1052  }
1053  else { // wPart && !dPart
1054  return wPart; // easy choice
1055  }
1056 
1057  }
1058  else {
1059 
1060  if (dPart) { // !wPart && dPart
1061  return dPart; // easy choice
1062  }
1063  else { // !wPart && !dPart
1064  return {}; // failure!!
1065  }
1066 
1067  }
1068 
1069 } // makePartition(Iter)
std::unique_ptr< geo::part::Partition< geo::TPCGeo const > > makeDepthPartition(BeginIter beginTPCwithArea, EndIter endTPCwithArea)
std::unique_ptr< geo::part::Partition< geo::TPCGeo const > > makeWidthPartition(BeginIter beginTPCwithArea, EndIter endTPCwithArea)
auto makeTPCPartitionElement(TPCwithArea_t const &TPCinfo)
std::unique_ptr< geo::part::Partition< geo::TPCGeo const > > makeGridPartition(BeginIter beginTPCwithArea, EndIter endTPCwithArea)
std::unique_ptr<geo::DriftPartitions::TPCPartition_t> makePartition ( std::vector< TPCwithArea_t > const &  TPCs)

Definition at line 1090 of file DriftPartitions.cxx.

References makeCPointerVector(), and makePartition().

1091 {
1092  // TODO use range library instead:
1093 // auto TPCptrs = TPCs | ranges::view::transform(std::addressof);
1094  auto TPCptrs = makeCPointerVector(TPCs);
1095  using std::cbegin;
1096  using std::cend;
1097  return makePartition(cbegin(TPCptrs), cend(TPCptrs));
1098 } // makePartition(coll)
std::unique_ptr< geo::part::Partition< geo::TPCGeo const > > makePartition(BeginIter beginTPCwithArea, EndIter endTPCwithArea)
auto makeCPointerVector(BeginIter b, EndIter e)
template<typename TPCPartitionResultType , geo::part::AreaOwner::AreaRangeMember_t Range, typename BeginIter , typename EndIter , typename SubpartMaker >
std::unique_ptr<geo::part::Partition<geo::TPCGeo const> > makeSortedPartition ( BeginIter  beginTPCwithArea,
EndIter  endTPCwithArea,
SubpartMaker  subpartMaker 
)

Definition at line 677 of file DriftPartitions.cxx.

References computeTotalArea(), createSubpartitions(), and makeWidthPartition().

Referenced by makeDepthPartition(), and makeWidthPartition().

680  {
681  /*
682  * TPCs in input are arranged into a partition split on width direction.
683  * In case of failure, a null pointer is returned.
684  * Do not use this function for a single TPC.
685  * The algorithm is as follows:
686  *
687  * 1. sort the TPCs by width coordinate
688  * 2. for each one, group it with all the following ones overlapping in width
689  * 3. for each group with:
690  * .1 more than one element:
691  * .1 let the group be partitioned on depth
692  * .2 if that fails, we fail
693  * .2 just one element: create a partition element
694  * 4. the resulting partition is the list of one-TPC "groups" and depth-based
695  * subpartitions of many-TPC groups
696  * 5. if the result is a single partition, it must be a depth partition;
697  * then, there is no room for a partition along width, and we declare
698  * failure
699  */
700 
701  //
702  // sort by coordinate and group TPCs; work with pointers for convenience
703  //
704  auto const TPCgroupInfo
705  = sortAndGroupTPCsByRangeCoord<Range>(beginTPCwithArea, endTPCwithArea);
706  std::vector<TPCwithArea_t const*> const& TPCs = TPCgroupInfo.first;
708  TPCgroups = TPCgroupInfo.second;
709 
710  if (TPCs.empty()) return {}; // failure?
711 
712  //
713  // for each group, create a subpartition
714  //
715  auto subparts = createSubpartitions
716  (TPCgroups.cbegin(), TPCgroups.cend(), TPCs.cend(), subpartMaker);
717 
718  // if we have grouped everything in a single unit, we have not done any good
719  if (subparts.size() == 1) return {};
720 
721  //
722  // compute the total area (it might have been merged in a previous loop...)
723  //
724  auto totalArea = computeTotalArea(TPCs.cbegin(), TPCs.cend());
725 
726  //
727  // construct and return the final partition
728  //
729  return std::make_unique<TPCPartitionResultType>
730  (totalArea, std::move(subparts));
731 
732 } // makeSortedPartition()
geo::part::Partition< geo::TPCGeo const >::Subpartitions_t createSubpartitions(BeginIter itTPCbegin, EndIter itTPCend, TPCendIter TPCend, SubpartMaker subpartMaker)
geo::part::AreaOwner::Area_t computeTotalArea(BeginIter TPCbegin, EndIter TPCend)
intermediate_table::const_iterator const_iterator
auto makeTPCPartitionElement ( TPCwithArea_t const &  TPCinfo)

Definition at line 647 of file DriftPartitions.cxx.

References geo::part::AreaOwner::area(), makeDepthPartition(), makeGridPartition(), makePartition(), makeWidthPartition(), and TPCwithArea_t::TPC.

Referenced by createSubpartitions(), and makePartition().

648 {
649  return std::make_unique<geo::part::PartitionElement<geo::TPCGeo const>>
650  (TPCinfo.area(), TPCinfo.TPC);
651 }
template<typename BeginIter , typename EndIter >
std::unique_ptr< geo::part::Partition< geo::TPCGeo const > > makeWidthPartition ( BeginIter  beginTPCwithArea,
EndIter  endTPCwithArea 
)

Definition at line 738 of file DriftPartitions.cxx.

References makeDepthPartition(), makeSortedPartition(), and lar::util::simple_geo::Rectangle< Data >::width.

Referenced by makePartition(), makeSortedPartition(), and makeTPCPartitionElement().

739 {
740  return makeSortedPartition<
743  >
744  (beginTPCwithArea, endTPCwithArea, &makeDepthPartition<BeginIter, EndIter>);
745 } // makeWidthPartition()
Partition of area along the width dimension.
Definition: Partitions.h:489
Range_t width
Range along width direction.
Definition: SimpleGeo.h:393
std::unique_ptr< geo::part::Partition< geo::TPCGeo const > > makeSortedPartition(BeginIter beginTPCwithArea, EndIter endTPCwithArea, SubpartMaker subpartMaker)
template<geo::part::AreaOwner::AreaRangeMember_t sortingRange, typename BeginIter , typename EndIter >
std::pair< std::vector<TPCwithArea_t const*>, std::vector<std::vector<TPCwithArea_t const*>::const_iterator> > sortAndGroupTPCsByRangeCoord ( BeginIter  beginTPCwithArea,
EndIter  endTPCwithArea 
)

Definition at line 566 of file DriftPartitions.cxx.

Referenced by groupTPCsByRangeCoord().

567 {
568  //
569  // sort by coordinate; work with pointers for convenience
570  //
571  std::vector<TPCwithArea_t const*> TPCs(beginTPCwithArea, endTPCwithArea);
572  if (TPCs.size() <= 1) return {}; // with only one TPC, refuse to operate
573  std::sort
574  (TPCs.begin(), TPCs.end(), SortTPCareaByAreaRangeLower<sortingRange>());
575 
576  //
577  // group
578  //
580  = groupTPCsByRangeCoord<sortingRange>(TPCs.cbegin(), TPCs.cend());
581  assert(!TPCgroups.empty());
582 
583  return { std::move(TPCs), std::move(TPCgroups) };
584 
585 } // sortAndGroupTPCsByRangeCoord()
intermediate_table::const_iterator const_iterator
std::vector<TPCandPos_t> sortTPCsByDriftCoord ( std::vector< geo::TPCGeo const * > const &  TPCs,
geo::DriftPartitions::Decomposer_t const &  decomp 
)

Definition at line 229 of file DriftPartitions.cxx.

References geo::DriftPartitions::driftCoord(), groupByDriftCoordinate(), and geo::Decomposer< Vector, Point, ProjVector >::PointNormalComponent().

Referenced by geo::buildDriftVolumes().

232  {
233  /*
234  * TPCs in the argument are sorted by their drift coordinate.
235  * The drift coordinate is defined as the coordinate specified by the normal
236  * direction of the decomposer in argument.
237  * The result is a collection of data structures containing each a TPC and
238  * the drift coordinate that was used to sort it.
239  *
240  * Sorting happens by the drift coordinate of the first wire plane;
241  * the absolute value of the drift coordinate value is not relevant nor it is
242  * well defined.
243  * The result preserves that coordinate for further processing (grouping).
244  */
245  auto const driftCoord = [&decomp](geo::TPCGeo const& TPC)
246  { return decomp.PointNormalComponent(geo::vect::convertTo<geo::DriftPartitions::Position_t>(TPC.FirstPlane().GetCenter())); };
247 
248  std::vector<TPCandPos_t> result;
249  result.reserve(TPCs.size());
250  std::transform(TPCs.cbegin(), TPCs.cend(), std::back_inserter(result),
251  [&driftCoord](geo::TPCGeo const* pTPC)
252  { return TPCandPos_t(driftCoord(*pTPC), pTPC); }
253  );
254  // std::pair sorts by first key first, and second key on par
255  // (on par, which may happen often, we don't have means to decide here...)
256  std::sort(result.begin(), result.end());
257  return result;
258 } // sortTPCsByDriftCoord()
Geometry information for a single TPC.
Definition: TPCGeo.h:37
std::pair< double, geo::TPCGeo const * > TPCandPos_t
geo::part::AreaOwner::Area_t TPCarea ( geo::TPCGeo const &  TPC,
geo::DriftPartitions::Decomposer_t const &  decomposer 
)

Definition at line 405 of file DriftPartitions.cxx.

References geo::BoxBoundedGeo::MaxX(), geo::BoxBoundedGeo::MaxY(), geo::BoxBoundedGeo::MaxZ(), geo::BoxBoundedGeo::MinX(), geo::BoxBoundedGeo::MinY(), geo::BoxBoundedGeo::MinZ(), and geo::Decomposer< Vector, Point, ProjVector >::ProjectPointOnPlane().

Referenced by addAreaToTPCs(), and TPCwithArea_t::TPCwithArea_t().

406 {
407  /*
408  * Returns the "area" of the TPC.
409  * The area is delimited by TPC bounding box
410  */
411 
413  { TPC.MinX(), TPC.MinY(), TPC.MinZ() };
415  { TPC.MaxX(), TPC.MaxY(), TPC.MaxZ() };
416 
417  auto const lowerProj = decomposer.ProjectPointOnPlane(lower);
418  auto const upperProj = decomposer.ProjectPointOnPlane(upper);
419 
420  // we ask to sort the ranges, since the reference base may be flipped
421  return {
422  { lowerProj.X(), upperProj.X(), true },
423  { lowerProj.Y(), upperProj.Y(), true }
424  };
425 
426 } // TPCarea()
geo::Point_t Position_t
Type representing a position in 3D space.