Classes | Typedefs | Functions
DriftPartitions.cxx File Reference

Classes describing partition of cryostat volume. More...

#include "larcorealg/Geometry/DriftPartitions.h"
#include "larcorealg/Geometry/PlaneGeo.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 485 of file DriftPartitions.cxx.

Definition at line 490 of file DriftPartitions.cxx.

Definition at line 488 of file DriftPartitions.cxx.

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

Definition at line 156 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 426 of file DriftPartitions.cxx.

429  {
430  /*
431  * Transforms a collection of TPCs into a collection of TPCs with area.
432  */
433  std::vector<TPCwithArea_t> result;
434  result.reserve(TPCs.size());
435 
436  for (auto const& TPC: TPCs)
437  result.emplace_back(TPCarea(*TPC, decomposer), TPC);
438 
439  return result;
440 } // addAreaToTPCs()
static QCString result
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 302 of file DriftPartitions.cxx.

302  {
303  /*
304  * Verify coordinate system consistency between TPCs:
305  * * need to have the same drift direction
306  * * need to have the same drift coordinate
307  *
308  * On error, it prints information on the error stream ("GeometryPartitions").
309  * It returns the number of errors found.
310  */
311 
312  auto iTPC = TPCs.cbegin(), tend = TPCs.cend();
313  if (iTPC == tend) {
314  mf::LogProblem("GeometryPartitions")
315  << "checkTPCcoords() got an empty partition.";
316  return 0;
317  }
318 
319  geo::TPCGeo const& refTPC = **iTPC;
320  decltype(auto) refDriftDir = refTPC.DriftDir();
321 
322  auto driftCoord = [&refDriftDir](geo::TPCGeo const& TPC)
323  { return geo::vect::dot(TPC.FirstPlane().GetCenter(), refDriftDir); };
324 
325  auto const refDriftPos = driftCoord(refTPC);
326 
328  auto vectorIs = lar::util::makeVector3DComparison(coordIs);
329 
330  unsigned int nErrors = 0U;
331  while (++iTPC != tend) {
332  geo::TPCGeo const& TPC = **iTPC;
333 
334  if (vectorIs.nonEqual(TPC.DriftDir(), refDriftDir)) {
335  mf::LogProblem("GeometryPartitions")
336  << "Incompatible drift directions between " << TPC.ID()
337  << " " << lar::dump::vector3D(TPC.DriftDir()) << " and " << refTPC.ID()
338  << " " << lar::dump::vector3D(refTPC.DriftDir());
339  ++nErrors;
340  }
341  auto const driftPos = driftCoord(TPC);
342  if (coordIs.nonEqual(driftPos, refDriftPos)) {
343  mf::LogProblem("GeometryPartitions")
344  << "Incompatible drift coordinate between " << TPC.ID()
345  << " (" << driftPos << "( and " << refTPC.ID() << " ("
346  << refDriftPos << ")";
347  ++nErrors;
348  }
349  } // while
350  return nErrors;
351 } // checkTPCcoords()
geo::TPCID const & ID() const
Returns the identifier of this TPC.
Definition: TPCGeo.h:333
Vector DriftDir() const
Returns the direction of the drift (vector pointing toward the planes).
Definition: TPCGeo.h:773
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:38
MaybeLogger_< ELseverityLevel::ELsev_error, true > LogProblem
const double e
auto makeVector3DComparison(RealType threshold)
Creates a Vector3DComparison from a RealComparisons object.
LArSoft geometry interface.
Definition: ChannelGeo.h:16
template<typename BeginIter , typename EndIter >
geo::part::AreaOwner::Area_t computeTotalArea ( BeginIter  TPCbegin,
EndIter  TPCend 
)

Definition at line 446 of file DriftPartitions.cxx.

447 {
448  /*
449  * Computes an area covering the areas from all TPCs delimited by the
450  * iterators in argument.
451  * Each iterator points to a AreaOwner pointer.
452  */
453  auto iTPC = TPCbegin;
454  geo::part::AreaOwner::Area_t totalArea((*iTPC)->area());
455  while (++iTPC != TPCend) totalArea.extendToInclude((*iTPC)->area());
456  return totalArea;
457 } // 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 590 of file DriftPartitions.cxx.

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

Definition at line 356 of file DriftPartitions.cxx.

356  {
357  /*
358  * Returns the first of the specified directions (possibly flipped);
359  * throws an exception if any of them is not parallel to that one.
360  */
361  using std::cbegin;
362  using std::cend;
363  auto iDir = cbegin(directions);
364  auto dend = cend(directions);
365  if (!(iDir != dend)) {
366  throw cet::exception("buildDriftVolumes")
367  << "detectGlobalDriftDir(): no TPCs provided!\n";
368  }
369 
371  auto compatibleDir = [comp](auto const& a, auto const& b)
372  { return comp.equal(std::abs(geo::vect::dot(a, b)), +1.0); };
373 
374  auto const dir = *(iDir++);
375  for (; iDir != dend; ++iDir) {
376  if (compatibleDir(dir, *iDir)) continue;
377  throw cet::exception("buildDriftVolumes")
378  << "Found drift directions not compatible: " << lar::dump::vector3D(dir)
379  << " and " << lar::dump::vector3D(*iDir) << "\n";
380  } // for
381 
382  // mildly prefer positive directions
383  return ((dir.X() <= 0.0) && (dir.Y() <= 0.0) && (dir.Z() <= 0.0))? -dir: dir;
384 } // 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.
decltype(auto) constexpr cend(T &&obj)
ADL-aware version of std::cend.
Definition: StdUtils.h:87
Provides simple real number checks.
string dir
T abs(T value)
const double e
const double a
decltype(auto) constexpr cbegin(T &&obj)
ADL-aware version of std::cbegin.
Definition: StdUtils.h:82
static bool * b
Definition: config.cpp:1043
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 260 of file DriftPartitions.cxx.

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

Definition at line 180 of file DriftPartitions.cxx.

181 {
182  /*
183  * TPCs are grouped by their drift direction, allowing for a small rounding
184  * error.
185  * The result is a collection with one element for each group of TPCs sharing
186  * the same drift direction. Each element is a pair with that drift direction
187  * first, and a collection of all TPCs with that drift direction.
188  * Elements are in no particular order.
189  */
190  std::vector<std::pair
191  <geo::DriftPartitions::DriftDir_t, std::vector<geo::TPCGeo const*>>
192  >
193  result;
194 
196  auto vectorIs = lar::util::makeVector3DComparison(coordIs);
197 
198  auto const nTPCs = cryo.NTPC();
199  for (unsigned int iTPC = 0; iTPC < nTPCs; ++iTPC) {
200  geo::TPCGeo const& TPC = cryo.TPC(iTPC);
201 
202  decltype(auto) driftDir = TPC.DriftDir();
203 
204  std::size_t iGroup = 0;
205  for (; iGroup < result.size(); ++iGroup) {
206  if (vectorIs.nonEqual(driftDir, result[iGroup].first)) continue;
207  result[iGroup].second.push_back(&TPC);
208  break;
209  } // for
210 
211  // if we did not find a group yet, make a new one
212  if (iGroup == result.size()) {
213  result.emplace_back(
214  geo::vect::rounded01(driftDir, coordIs.threshold),
215  std::vector<geo::TPCGeo const*>{ &TPC }
216  );
217  } // if
218 
219  } // for
220 
221  return result;
222 } // groupTPCsByDriftDir()
static QCString result
Provides simple real number checks.
Geometry information for a single TPC.
Definition: TPCGeo.h:38
struct vector vector
STL namespace.
decltype(auto) constexpr size(T &&obj)
ADL-aware version of std::size.
Definition: StdUtils.h:92
const double e
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.
for(std::string line;std::getline(inFile, line);)
Definition: regex_t.cc:37
Direction_t DriftDir_t
Type representing the drift direction (assumed to have norm 1).
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 500 of file DriftPartitions.cxx.

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

1071  {
1072  using value_type = typename BeginIter::value_type;
1073  std::vector<value_type const*> result;
1074  result.reserve(std::distance(b, e));
1075  std::transform(b, e, std::back_inserter(result),
1076  [](auto& obj){ return std::addressof(obj); });
1077  return result;
1078 } // makeCPointerVector()
static QCString result
const double e
double distance(double x1, double y1, double z1, double x2, double y2, double z2)
static bool * b
Definition: config.cpp:1043
template<typename T >
auto makeCPointerVector ( std::vector< T > const &  v)

Definition at line 1081 of file DriftPartitions.cxx.

1082  { 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 747 of file DriftPartitions.cxx.

748 {
749  return makeSortedPartition<
752  >
753  (beginTPCwithArea, endTPCwithArea, &makeWidthPartition<BeginIter, EndIter>);
754 } // 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 760 of file DriftPartitions.cxx.

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

Definition at line 999 of file DriftPartitions.cxx.

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

1088 {
1089  // TODO use range library instead:
1090 // auto TPCptrs = TPCs | ranges::views::transform(std::addressof);
1091  auto TPCptrs = makeCPointerVector(TPCs);
1092  using std::cbegin;
1093  using std::cend;
1094  return makePartition(cbegin(TPCptrs), cend(TPCptrs));
1095 } // makePartition(coll)
std::unique_ptr< geo::part::Partition< geo::TPCGeo const > > makePartition(BeginIter beginTPCwithArea, EndIter endTPCwithArea)
decltype(auto) constexpr cend(T &&obj)
ADL-aware version of std::cend.
Definition: StdUtils.h:87
auto makeCPointerVector(BeginIter b, EndIter e)
decltype(auto) constexpr cbegin(T &&obj)
ADL-aware version of std::cbegin.
Definition: StdUtils.h:82
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 674 of file DriftPartitions.cxx.

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

Definition at line 644 of file DriftPartitions.cxx.

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

Definition at line 735 of file DriftPartitions.cxx.

736 {
737  return makeSortedPartition<
740  >
741  (beginTPCwithArea, endTPCwithArea, &makeDepthPartition<BeginIter, EndIter>);
742 } // 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 563 of file DriftPartitions.cxx.

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

Definition at line 226 of file DriftPartitions.cxx.

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

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