21 #include "cetlib_except/exception.h" 31 #include <type_traits> 40 template <
typename T,
typename CONT>
41 void append(std::vector<T>& dest, CONT
const& src)
45 dest.insert(dest.end(),
cbegin(src),
cend(src));
50 void append(std::vector<T>& dest, std::vector<T>&& src)
53 dest = std::move(src);
60 template <
typename Cont>
61 auto keys(Cont
const& m)
64 std::vector<typename Cont::value_type::first_type> result;
65 result.reserve(m.size());
67 m.cbegin(), m.cend(), std::back_inserter(result), [](
auto const& p) {
return p.first; });
81 if (iVol ==
volumes.cbegin())
return nullptr;
82 if (!(--iVol)->coversDrift(drift))
return nullptr;
91 return (volume && volume->partition) ?
92 volume->partition->atPoint(comp.projection.X(), comp.projection.Y()) :
116 struct CoverageExtractor {
137 TPCpart.walk(extractor);
138 return extractor.coverage;
152 std::vector<geo::TPCGeo const*>
TPCs;
155 TPCgroup_t(
double pos, std::vector<geo::TPCGeo const*>&& TPCs) : pos(pos), TPCs(
std::move(TPCs))
167 std::vector<std::pair<geo::DriftPartitions::DriftDir_t, std::vector<geo::TPCGeo const*>>>
178 std::vector<std::pair<geo::DriftPartitions::DriftDir_t, std::vector<geo::TPCGeo const*>>> result;
183 auto const nTPCs = cryo.
NTPC();
184 for (
unsigned int iTPC = 0; iTPC < nTPCs; ++iTPC) {
187 decltype(
auto) driftDir = TPC.
DriftDir();
189 std::size_t iGroup = 0;
190 for (; iGroup < result.size(); ++iGroup) {
191 if (vectorIs.nonEqual(driftDir, result[iGroup].first))
continue;
192 result[iGroup].second.push_back(&TPC);
197 if (iGroup == result.size()) {
199 std::vector<geo::TPCGeo const*>{&TPC});
225 geo::vect::convertTo<geo::DriftPartitions::Position_t>(TPC.FirstPlane().GetCenter()));
228 std::vector<TPCandPos_t> result;
229 result.reserve(TPCs.size());
236 std::sort(result.begin(), result.end());
249 if (TPCs.empty())
return {};
251 geo::TPCGeo const& firstTPC = *(TPCs.front().second);
255 double const groupThickness =
258 auto iFirstTPC = TPCs.cbegin(), tend = TPCs.cend();
260 std::vector<TPCgroup_t> result;
261 while (iFirstTPC != tend) {
262 double const posEnd = iFirstTPC->first + groupThickness;
264 std::vector<geo::TPCGeo const*> TPCs;
265 auto iEndGroup = iFirstTPC;
267 TPCs.push_back(iEndGroup->second);
268 sumPos += iEndGroup->first;
270 }
while ((iEndGroup != tend) && (iEndGroup->first < posEnd));
272 double const averagePos = sumPos / TPCs.size();
273 result.emplace_back(averagePos, std::move(TPCs));
275 iFirstTPC = iEndGroup;
293 auto iTPC = TPCs.cbegin(), tend = TPCs.cend();
295 mf::LogProblem(
"GeometryPartitions") <<
"checkTPCcoords() got an empty partition.";
300 decltype(
auto) refDriftDir = refTPC.
DriftDir();
311 unsigned int nErrors = 0U;
312 while (++iTPC != tend) {
315 if (vectorIs.nonEqual(TPC.
DriftDir(), refDriftDir)) {
317 <<
"Incompatible drift directions between " << TPC.
ID() <<
" " 323 if (coordIs.
nonEqual(driftPos, refDriftPos)) {
325 <<
"Incompatible drift coordinate between " << TPC.
ID() <<
" (" << driftPos <<
"( and " 326 << refTPC.
ID() <<
" (" << refDriftPos <<
")";
334 template <
typename Range>
343 auto iDir =
cbegin(directions);
344 auto dend =
cend(directions);
345 if (!(iDir != dend)) {
346 throw cet::exception(
"buildDriftVolumes") <<
"detectGlobalDriftDir(): no TPCs provided!\n";
350 auto compatibleDir = [comp](
auto const& a,
auto const& b) {
354 auto const dir = *(iDir++);
355 for (; iDir != dend; ++iDir) {
356 if (compatibleDir(
dir, *iDir))
continue;
363 return ((
dir.X() <= 0.0) && (
dir.Y() <= 0.0) && (
dir.Z() <= 0.0)) ? -
dir :
dir;
393 return {{lowerProj.X(), upperProj.X(),
true}, {lowerProj.Y(), upperProj.Y(),
true}};
397 std::vector<TPCwithArea_t>
addAreaToTPCs(std::vector<geo::TPCGeo const*>
const& TPCs,
403 std::vector<TPCwithArea_t> result;
404 result.reserve(TPCs.size());
406 for (
auto const& TPC : TPCs)
407 result.emplace_back(
TPCarea(*TPC, decomposer), TPC);
413 template <
typename BeginIter,
typename EndIter>
421 auto iTPC = TPCbegin;
423 while (++iTPC != TPCend)
430 template <
typename Key,
typename ExtractKey,
typename Comparer = std::less<Key>>
439 template <
typename Data>
442 return ExtractKey()(obj);
445 template <
typename A,
typename B>
448 return sortKey(key(a), key(b));
455 template <geo::part::AreaOwner::AreaRangeMember_t Range>
467 BeginIter beginTPCwithArea,
468 EndIter endTPCwithArea)
486 auto gbegin = beginTPCwithArea;
487 while (gbegin != endTPCwithArea) {
489 groupStart.push_back(gbegin);
494 auto range = (*gbegin)->area().*sortingRange;
496 while (++gend != endTPCwithArea) {
505 auto const& TPCrange = (*gend)->area().*sortingRange;
506 if (coordIs.
nonSmaller(TPCrange.lower, range.upper))
break;
507 range.extendToInclude(TPCrange);
523 std::pair<std::vector<TPCwithArea_t const*>,
530 std::vector<TPCwithArea_t const*> TPCs(beginTPCwithArea, endTPCwithArea);
531 if (TPCs.size() <= 1)
return {};
538 groupTPCsByRangeCoord<sortingRange>(TPCs.cbegin(), TPCs.cend());
539 assert(!TPCgroups.empty());
541 return {std::move(TPCs), std::move(TPCgroups)};
546 template <
typename BeginIter,
typename EndIter,
typename TPCendIter,
typename SubpartMaker>
548 BeginIter itTPCbegin,
551 SubpartMaker subpartMaker)
580 auto igbegin = itTPCbegin;
581 while (igbegin != itTPCend) {
582 auto const gbegin = *igbegin;
583 auto const gend = (++igbegin == itTPCend) ? TPCend : *igbegin;
588 if (std::distance(gbegin, gend) == 1) {
592 auto subpart = subpartMaker(gbegin, gend);
593 if (!subpart)
return {};
595 subparts.emplace_back(std::move(subpart));
604 return std::make_unique<geo::part::PartitionElement<geo::TPCGeo const>>(TPCinfo.
area(),
610 template <
typename BeginIter,
typename EndIter>
612 BeginIter beginTPCwithArea,
613 EndIter endTPCwithArea);
614 template <
typename BeginIter,
typename EndIter>
616 BeginIter beginTPCwithArea,
617 EndIter endTPCwithArea);
618 template <
typename BeginIter,
typename EndIter>
620 BeginIter beginTPCwithArea,
621 EndIter endTPCwithArea);
622 template <
typename BeginIter,
typename EndIter>
623 std::unique_ptr<geo::part::Partition<geo::TPCGeo const>>
makePartition(BeginIter beginTPCwithArea,
624 EndIter endTPCwithArea);
627 template <
typename TPCPartitionResultType,
631 typename SubpartMaker>
632 std::unique_ptr<geo::part::Partition<geo::TPCGeo const>>
658 auto const TPCgroupInfo = sortAndGroupTPCsByRangeCoord<Range>(beginTPCwithArea, endTPCwithArea);
659 std::vector<TPCwithArea_t const*>
const& TPCs = TPCgroupInfo.first;
663 if (TPCs.empty())
return {};
672 if (subparts.size() == 1)
return {};
682 return std::make_unique<TPCPartitionResultType>(totalArea, std::move(subparts));
687 template <
typename BeginIter,
typename EndIter>
689 BeginIter beginTPCwithArea,
690 EndIter endTPCwithArea)
692 return makeSortedPartition<geo::part::WidthPartition<geo::TPCGeo const>,
694 beginTPCwithArea, endTPCwithArea, &makeDepthPartition<BeginIter, EndIter>);
697 template <
typename BeginIter,
typename EndIter>
699 BeginIter beginTPCwithArea,
700 EndIter endTPCwithArea)
702 return makeSortedPartition<geo::part::DepthPartition<geo::TPCGeo const>,
704 beginTPCwithArea, endTPCwithArea, &makeWidthPartition<BeginIter, EndIter>);
708 template <
typename BeginIter,
typename EndIter>
710 BeginIter beginTPCwithArea,
711 EndIter endTPCwithArea)
734 auto const TPCgroupInfo =
735 sortAndGroupTPCsByRangeCoord<&Area_t::width>(beginTPCwithArea, endTPCwithArea);
736 std::vector<TPCwithArea_t const*>
const& TPCs = TPCgroupInfo.first;
740 if (TPCs.empty())
return {};
742 if (TPCs.size() < 4)
return {};
744 unsigned int const nWidthParts = TPCgroups.size();
745 if (nWidthParts <= 1)
return {};
750 auto const FirstColGroupInfo =
751 sortAndGroupTPCsByRangeCoord<&Area_t::depth>(TPCgroups[0], TPCgroups[1]);
752 std::vector<TPCwithArea_t const*>
const& FirstColTPCs = FirstColGroupInfo.first;
754 FirstColGroupInfo.second;
756 if (FirstColTPCs.empty())
return {};
757 if (FirstColGroups.size() <= 1)
return {};
769 std::vector<Area_t::Range_t> depthGaps;
770 auto icnext = FirstColGroups.cbegin(), icprev = icnext, icend = FirstColGroups.cend();
771 while (++icnext != icend) {
776 auto const cprev = *icprev;
777 auto const cnext = *icnext;
779 depthGaps.emplace_back((*cprev)->area().depth.upper, (*cnext)->area().depth.lower);
783 assert(!depthGaps.empty());
788 auto igbegin = TPCgroups.cbegin();
789 while (++igbegin != TPCgroups.cend()) {
793 auto igend = std::next(igbegin);
794 auto gbegin = *igbegin;
795 auto gend = (igend == TPCgroups.cend()) ? TPCs.cend() : *igend;
797 auto const ColGroupInfo = sortAndGroupTPCsByRangeCoord<&Area_t::depth>(gbegin, gend);
798 std::vector<TPCwithArea_t const*>
const& ColTPCs = ColGroupInfo.first;
803 if (ColTPCs.empty())
return {};
804 if (ColGroups.size() <= 1)
return {};
809 std::vector<TPCwithArea_t::Area_t::Range_t> groupDepths(ColGroups.size());
810 auto iGDepth = groupDepths.begin();
811 for (
auto icgstart = ColGroups.cbegin(); icgstart != ColGroups.cend(); ++icgstart, ++iGDepth) {
812 auto const icgend = std::next(icgstart);
813 auto ictpc = *icgstart;
814 auto const ictend = (icgend == ColGroups.cend()) ? ColTPCs.cend() : *icgend;
815 while (ictpc != ictend)
816 iGDepth->extendToInclude((*(ictpc++))->area().depth);
822 auto iGap = depthGaps.begin();
823 while (iGap != depthGaps.end()) {
824 Area_t::Range_t& gap = *iGap;
829 bool bGoodGap =
false;
831 auto iCGroup = std::lower_bound(
835 if ((iCGroup != groupDepths.begin()) && (iCGroup != groupDepths.end())) {
836 Area_t::Range_t
const& before = *(std::prev(iCGroup));
837 Area_t::Range_t
const& after = *iCGroup;
838 Area_t::Range_t
const TPCgap{before.upper, after.lower};
841 if (coordIs.
strictlySmaller(iGap->lower, TPCgap.lower)) iGap->lower = TPCgap.lower;
842 if (coordIs.
strictlyGreater(iGap->upper, TPCgap.upper)) iGap->upper = TPCgap.upper;
845 bGoodGap = coordIs.
nonSmaller(iGap->upper, iGap->lower);
854 iGap = depthGaps.erase(iGap);
858 if (depthGaps.empty())
return {};
865 std::vector<double> depthSep;
866 std::transform(depthGaps.cbegin(),
868 std::back_inserter(depthSep),
869 [](
auto const&
r) {
return (
r.lower +
r.upper) / 2.0; });
870 unsigned int const nDepthParts = depthSep.size() + 1;
878 unsigned int iWidth = 0;
879 for (
auto igbegin = TPCgroups.cbegin(); igbegin != TPCgroups.cend(); ++igbegin, ++iWidth) {
882 auto igend = std::next(igbegin);
883 auto gbegin = *igbegin;
884 auto gend = (igend == TPCgroups.cend()) ? TPCs.cend() : *igend;
885 std::vector<TPCwithArea_t const*> ColTPCs(gbegin, gend);
888 unsigned int iDepth = 0;
889 auto cgstart = ColTPCs.cbegin(), TPCend = ColTPCs.cend();
890 for (
double sep : depthSep) {
899 while (cgend != cgstart) {
900 auto cglast = std::prev(cgend);
901 if (coordIs.
strictlySmaller((*cglast)->area().depth.lower, sep))
break;
904 assert(cgstart != cgend);
910 if (!
part)
return {};
911 totalArea.extendToInclude(
part->area());
912 subparts[iDepth * nWidthParts + iWidth] = std::move(
part);
922 if (!
part)
return {};
923 totalArea.extendToInclude(
part->area());
924 subparts[iDepth * nWidthParts + iWidth] = std::move(
part);
928 return std::make_unique<geo::part::GridPartition<geo::TPCGeo const>>(
929 totalArea, std::move(subparts), nWidthParts, nDepthParts);
934 template <
typename BeginIter,
typename EndIter>
935 std::unique_ptr<geo::part::Partition<geo::TPCGeo const>>
makePartition(BeginIter beginTPCwithArea,
936 EndIter endTPCwithArea)
961 using value_type = std::remove_reference_t<decltype(*beginTPCwithArea)>;
962 static_assert(std::is_pointer<value_type>() &&
963 std::is_same<std::decay_t<std::remove_pointer_t<value_type>>,
TPCwithArea_t>(),
964 "Iterators must point to TPCwithArea_t pointers.");
966 auto const size = std::distance(beginTPCwithArea, endTPCwithArea);
970 if (gPart)
return gPart;
978 if (wPart->nParts() < dPart->nParts())
1000 template <
typename BeginIter,
typename EndIter>
1003 using value_type =
typename BeginIter::value_type;
1004 std::vector<value_type const*> result;
1005 result.reserve(std::distance(b, e));
1006 std::transform(b, e, std::back_inserter(result), [](
auto& obj) {
return std::addressof(obj); });
1010 template <
typename T>
1018 std::vector<TPCwithArea_t>
const& TPCs)
1054 std::vector<TPCgroup_t> TPCgroups;
1055 for (
auto const& TPCsOnDriftDir : TPCsByDriftDir) {
1063 for (
auto const& TPCgroup : TPCgroups) {
1067 <<
"TPCs in partition have different drift directions (" << errors <<
" errors found in " 1068 << TPCgroup.TPCs.size() <<
" TPCs).\n";
1076 for (
auto const& TPCgroup : TPCgroups) {
1081 e <<
"Failed to construct partition out of " << TPCs.size() <<
" TPCs:";
1082 for (
auto const& TPCinfo : TPCs) {
1083 e <<
"\n at " << TPCinfo.area() <<
" TPC ";
1084 TPCinfo.TPC->PrintTPCInfo(e,
" ", 5U);
Range_t computeCoverage(TPCPartition_t const &TPCpart) const
Computes the coverage of the specified partition in the drift direction.
geo::TPCID const & ID() const
Returns the identifier of this TPC.
double driftCoord(Position_t const &pos) const
Returns drift coordinate (in the drift-volume-specific frame) of pos.
Data structures and algorithms to partition a cryostat volume.
A basic interface for objects owning an area.
Point_t GetCathodeCenter() const
Decomposer_t decomposer
Decomposition on drift, width and depth axes.
std::unique_ptr< geo::part::Partition< geo::TPCGeo const > > makePartition(BeginIter beginTPCwithArea, EndIter endTPCwithArea)
auto vector3D(Vector3D const &v)
Returns a manipulator which will print the specified vector.
auto PointNormalComponent(Point_t const &point) const
Returns the secondary component of a point.
static Key_t key(Data const &obj)
decltype(auto) constexpr cend(T &&obj)
ADL-aware version of std::cend.
geo::part::Partition< geo::TPCGeo const >::Subpartitions_t createSubpartitions(BeginIter itTPCbegin, EndIter itTPCend, TPCendIter TPCend, SubpartMaker subpartMaker)
constexpr bool nonEqual(Value_t a, Value_t b) const
Returns whether a and b are farther than the threshold.
Encapsulate the construction of a single cyostat.
Point_t const & GetCenter() const
Returns the centre of the wire plane in world coordinates [cm].
geo::part::AreaOwner::Area_t computeTotalArea(BeginIter TPCbegin, EndIter TPCend)
unsigned int Nplanes() const
Number of planes in this tpc.
Provides simple real number checks.
TPCgroup_t(double pos, std::vector< geo::TPCGeo const * > &&TPCs)
std::vector< DriftVolume_t >::iterator volumeAfter(double pos)
Returns an iterator to the drift volume starting after pos.
double MinX() const
Returns the world x coordinate of the start of the box.
void extendToInclude(Data_t)
Extends the range to include the specified point.
Geometry information for a single TPC.
SortTPCareaByAreaRangeLower<&geo::part::AreaOwner::Area_t::depth > SortTPCwithAreaByDepth
constexpr auto abs(T v)
Returns the absolute value of the argument.
Vector_t RefDepthDir() const
Return the direction of reference plane depth.
DriftPartitions buildDriftVolumes(geo::CryostatGeo const &cryo)
Creates a DriftPartitions object from the TPCs in a cryostat.
double MaxX() const
Returns the world x coordinate of the end of the box.
virtual Data_t * data() const
Returns the datum directly stored (nullptr if none).
bool operator()(A const &a, B const &b) const
Geometry information for a single cryostat.
geo::part::AreaOwner::Area_t TPCarea(geo::TPCGeo const &TPC, geo::DriftPartitions::Decomposer_t const &decomposer)
geo::TPCGeo const * TPCat(Position_t const &pos) const
Returns which TPC contains the specified position (nullptr if none).
Class for approximate comparisons.
Projection_t ProjectPointOnPlane(Point_t const &point) const
Returns the projection of the specified point on the plane.
std::vector< TPCwithArea_t > addAreaToTPCs(std::vector< geo::TPCGeo const * > const &TPCs, geo::DriftPartitions::Decomposer_t const &decomposer)
constexpr bool strictlySmaller(Value_t a, Value_t b) const
Returns whether a is strictly smaller than b.
decltype(auto) constexpr size(T &&obj)
ADL-aware version of std::size.
MaybeLogger_< ELseverityLevel::ELsev_error, true > LogProblem
constexpr bool strictlyGreater(Value_t a, Value_t b) const
Returns whether a is strictly greater than b.
std::vector< std::unique_ptr< Partition_t const >> Subpartitions_t
Type of list of subpartitions. It needs to preserve polymorphism.
Base element of a partitioned structure.
DriftVolume_t const * driftVolumeAt(Position_t const &pos) const
auto makeCPointerVector(BeginIter b, EndIter e)
Utilities to dump objects into a stream.
auto makeVector3DComparison(RealType threshold)
Creates a Vector3DComparison from a RealComparisons object.
geo::Point_t Position_t
Type representing a position in 3D space.
std::unique_ptr< geo::part::Partition< geo::TPCGeo const > > makeDepthPartition(BeginIter beginTPCwithArea, EndIter endTPCwithArea)
Classes to project and compose a vector on a plane.
geo::DriftPartitions::DriftDir_t detectGlobalDriftDir(Range &&directions)
static bool sortKey(Key_t a, Key_t b)
std::unique_ptr< geo::part::Partition< geo::TPCGeo const > > makeWidthPartition(BeginIter beginTPCwithArea, EndIter endTPCwithArea)
lar::util::simple_geo::Rectangle< double > Area_t
Type of area covered by the partition.
static double Position(TPCgroup_t const &tpcg)
Class managing comparisons between T objects via a Key key.
double MinZ() const
Returns the world z coordinate of the start of the box.
Area_t const & area() const
Returns the covered area.
unsigned int NTPC() const
Number of TPCs in this cryostat.
DecomposedVector_t DecomposePoint(Point_t const &point) const
Decomposes a 3D point in two components.
std::pair< double, geo::TPCGeo const * > TPCandPos_t
Range_t width
Range along width direction.
auto makeTPCPartitionElement(TPCwithArea_t const &TPCinfo)
constexpr auto dot(Vector const &a, OtherVector const &b)
Return cross product of two vectors.
double Plane0Pitch(unsigned int p) const
Returns the center of the TPC volume in world coordinates [cm].
Vector rounded01(Vector const &v, Scalar tol)
Returns a vector with all components rounded if close to 0, -1 or +1.
double MaxY() const
Returns the world y coordinate of the end of the box.
void addPartition(std::unique_ptr< TPCPartition_t > &&part)
Adds the specified partition as a new drift volume.
Range_t depth
Range along depth direction.
std::vector< TPCgroup_t > groupByDriftCoordinate(std::vector< TPCandPos_t > const &TPCs)
std::vector< DriftVolume_t > volumes
All drift volumes, sorted by position.
Encapsulate the construction of a single detector plane.
const TPCGeo & TPC(unsigned int itpc) const
Return the itpc'th TPC in the cryostat.
std::unique_ptr< geo::part::Partition< geo::TPCGeo const > > makeSortedPartition(BeginIter beginTPCwithArea, EndIter endTPCwithArea, SubpartMaker subpartMaker)
double MaxZ() const
Returns the world z coordinate of the end of the box.
std::vector< std::pair< geo::DriftPartitions::DriftDir_t, std::vector< geo::TPCGeo const * > > > groupTPCsByDriftDir(geo::CryostatGeo const &cryo)
geo::PlaneGeo const & LastPlane() const
Returns the last wire plane (the farther from TPC center).
std::pair< std::vector< TPCwithArea_t const * >, std::vector< std::vector< TPCwithArea_t const * >::const_iterator > > sortAndGroupTPCsByRangeCoord(BeginIter beginTPCwithArea, EndIter endTPCwithArea)
decltype(auto) constexpr cbegin(T &&obj)
ADL-aware version of std::cbegin.
std::vector< geo::TPCGeo const * > TPCs
TPCwithArea_t(Area_t area, geo::TPCGeo const *TPC)
void extendToInclude(Rectangle_t const &r)
Extends the range to include the specified point.
constexpr bool nonSmaller(Value_t a, Value_t b) const
Returns whether a is greater than (or equal to) b.
Vector_t RefWidthDir() const
Return the direction of reference plane width.
static Key_t key(Key_t k)
Direction_t DriftDir_t
Type representing the drift direction (assumed to have norm 1).
constexpr bool equal(Value_t a, Value_t b) const
Returns whether a and b are no farther than the threshold.
Data associated to a single drift volume.
Vector_t DriftDir() const
Returns the direction of the drift (vector pointing toward the planes).
std::unique_ptr< geo::part::Partition< geo::TPCGeo const > > makeGridPartition(BeginIter beginTPCwithArea, EndIter endTPCwithArea)
Namespace collecting geometry-related classes utilities.
std::vector< std::vector< TPCwithArea_t const * >::const_iterator > groupTPCsByRangeCoord(BeginIter beginTPCwithArea, EndIter endTPCwithArea)
double MinY() const
Returns the world y coordinate of the start of the box.
unsigned int checkTPCcoords(std::vector< geo::TPCGeo const * > const &TPCs)
cet::coded_exception< error, detail::translate > exception
Encapsulate the construction of a single detector plane.
Area_t::Range_t(Area_t::*) AreaRangeMember_t
Type of pointer to Area_t data member of type Range_t.
geo::Vector_t Direction_t
Type representing a direction in 3D space (norm is not constrained).
geo::Point_t Center() const
Returns the center point of the box.
std::vector< TPCandPos_t > sortTPCsByDriftCoord(std::vector< geo::TPCGeo const * > const &TPCs, geo::DriftPartitions::Decomposer_t const &decomp)