21 #include "messagefacility/MessageLogger/MessageLogger.h"
22 #include "cetlib_except/exception.h"
30 #include <type_traits>
40 template <
typename Coll,
typename Op>
41 auto transformCollection(Coll
const& coll, Op op) {
44 = std::decay_t<decltype(op(std::declval<typename Coll::value_type>()))>;
46 std::vector<Result_t> transformed;
49 (coll.begin(), coll.end(), std::back_inserter(transformed), op);
62 namespace icarus::details {
64 template <
typename SetColl> SetColl
stableMerge(SetColl
const& sets);
67 template <
typename SetColl>
76 using Coll_t =
typename SetColl_t::value_type;
77 using Value_t =
typename Coll_t::value_type;
91 template <
typename SetColl>
97 template <
typename SetColl>
101 if (std::find(coll.begin(), coll.end(),
value) != coll.end())
return false;
102 coll.push_back(value);
108 template <
typename SetColl>
113 for (
Value_t const& value: a) addNewValue(merged, value);
114 for (
Value_t const& value: b) addNewValue(merged, value);
120 template <
typename SetColl>
125 for (
auto const& aElem: a) {
126 if (std::find(b.begin(), b.end(), aElem) != b.end())
return true;
133 template <
typename SetColl>
139 for (
Coll_t const& set: sets) {
144 Coll_t* mergeWith =
nullptr;
145 for (
Coll_t& mergedSet: mergedSets) {
146 if (!
overlap(mergedSet, set))
continue;
147 mergeWith = &mergedSet;
152 *mergeWith = (mergeWith->size() < set.size())
153 ? mergeColls(set, *mergeWith)
154 : mergeColls(*mergeWith, set)
158 mergedSets.push_back(set);
167 template <
typename SetColl>
180 nSets = mergedSets.size();
182 mergedSets = mergePass(mergedSets);
184 }
while (mergedSets.size() != nSets);
219 template <
typename T>
235 (std::vector<PlaneColl_t>
const& ROPplanes)
const;
239 (std::vector<PlaneColl_t>
const& ROPs)
const;
244 (std::vector<PlaneColl_t>
const& refROP, std::string
const& logCategory)
266 (std::vector<PlaneColl_t>
const& ROPs)
const
289 if (!FirstROPno.emplace(view, nextAvailable).second)
continue;
293 <<
" preferring numbers from " << nextAvailable
294 <<
" (" << viewROPcounts.at(view) <<
" numbers reserved)";
297 nextAvailable += viewROPcounts.at(view);
308 (std::vector<PlaneColl_t>
const& ROPplanes)
const
314 if (
planes.empty())
continue;
319 log <<
"A ROP spans multiple views:";
322 <<
" (" << plane->ID() <<
")";
326 ++(viewROPcounts[view]);
330 return viewROPcounts;
338 auto iPlane = planes.begin();
339 auto const pend = planes.end();
342 while (++iPlane != pend) {
376 <<
"Building TPC sets and readout planes from " << Cryostats.size()
379 fCryostats = &Cryostats;
390 auto standaloneHorizontalWires = [](
geo::PlaneGeo const& plane)
391 {
return std::abs(plane.ThetaZ()) < 1
e-3; };
393 std::vector<std::vector<PlaneColl_t>> AllPlanesInROPs
394 = groupPlanesAndTPCs(standaloneHorizontalWires);
396 std::vector<std::vector<std::vector<geo::TPCID>>>
const AllTPCsInTPCsets
397 = extractTPCsetsFromROPs(AllPlanesInROPs);
403 fillTPCsInSet(AllTPCsInTPCsets);
409 = groupPlanesIntoROPs(AllTPCsInTPCsets, std::move(AllPlanesInROPs));
414 fillPlanesInROP(PlanesInProtoROPs);
419 fillTPCtoTPCsetMap();
425 assert(!fTPCsetCount.empty());
426 assert(!fTPCsetTPCs .
empty());
427 assert(!fROPcount .
empty());
428 assert(!fTPCtoTPCset.empty());
429 assert(!fPlaneToROP .
empty());
431 std::move(fTPCsetCount),
432 std::move(fTPCsetTPCs ),
433 std::move(fROPcount ),
434 std::move(fROPplanes ),
435 std::move(fTPCtoTPCset),
436 std::move(fPlaneToROP )
455 template <
typename Pred>
457 (Pred standalonePlane)
458 -> std::vector<std::vector<PlaneColl_t>>
479 std::vector<std::vector<PlaneColl_t>> AllPlanesInROPs;
485 log <<
"New group of " << planes.size() <<
" planes:";
487 log <<
" <" << plane->ID() <<
">";
500 std::vector<geo::PlaneGeo const*>
planes;
503 planes.push_back(&plane);
507 std::vector<PlaneColl_t> protoGroups = groupPlanesByDriftCoord(planes);
515 std::vector<PlaneColl_t> groupedPlanes;
517 if (protoGroup.empty())
continue;
520 if (standalonePlane(*plane)) {
521 groupedPlanes.push_back({ plane });
522 logPlanes(groupedPlanes.back());
524 else group.push_back(plane);
526 if (!group.empty()) {
527 groupedPlanes.push_back(std::move(group));
528 logPlanes(groupedPlanes.back());
535 AllPlanesInROPs.push_back(std::move(groupedPlanes));
539 return AllPlanesInROPs;
546 -> std::vector<std::vector<PlaneColl_t>>
547 {
return groupPlanesAndTPCs([](
geo::PlaneGeo const&){
return false; }); }
551 std::vector<std::vector<std::vector<geo::TPCID>>>
559 std::vector<std::vector<std::vector<geo::TPCID>>> AllTPCsOnROPs;
564 unsigned int& MaxTPCsets = fMaxTPCsets;
569 for (std::vector<PlaneColl_t>
const& planeGroupsInCryostat: groupedPlanes) {
578 std::vector<std::vector<geo::TPCID>> TPCsOnROPs
579 = transformCollection(planeGroupsInCryostat, extractTPCIDs);
591 = std::max(MaxTPCsets, static_cast<unsigned int>(TPCsOnROPs.size()));
592 AllTPCsOnROPs.push_back(std::move(TPCsOnROPs));
595 mf::LogTrace(
"ICARUSChannelMapAlg")
596 <<
"The maximum number of TPC sets in any cryostat is " << MaxTPCsets;
598 return AllTPCsOnROPs;
619 unsigned int const MaxTPCsets = fMaxTPCsets;
625 fTPCsetCount.clear();
626 fTPCsetCount.resize(AllTPCsOnROPs.size(), 0U);
627 std::vector<unsigned int>& TPCsetCount = fTPCsetCount;
629 fTPCsetTPCs.resize(AllTPCsOnROPs.size(), MaxTPCsets);
638 TPCsetCount[c] = TPCsets.size();
639 mf::LogTrace(
"ICARUSChannelMapAlg")
640 <<
"Cryostat " << cryo.
ID() <<
" has " << TPCsetCount[c] <<
" TPC sets";
646 TPCsetTPCs[tpcsetid] = transformCollection(
647 TPCIDs, [&cryo](
geo::TPCID const& tpcid){
return &(cryo.
TPC(tpcid)); }
651 auto const&
TPCs = TPCsetTPCs[tpcsetid];
652 mf::LogTrace log(
"ICARUSChannelMapAlg");
653 log << tpcsetid <<
" has " <<
TPCs.size() <<
" TPCs:";
665 std::vector<std::vector<PlaneColl_t>>&& AllPlanesInROPs
679 assert(!fTPCsetTPCs.empty());
686 (TPCsetTPCs.dimSize<0U>(), TPCsetTPCs.dimSize<1U>());
687 unsigned int& MaxROPs = fMaxROPs;
699 std::vector<std::vector<geo::TPCID>>
const& TPCsets = AllTPCsOnROPs[c];
700 for (std::vector<geo::PlaneGeo const*>& ROPplanes: ROPs) {
701 std::vector<geo::TPCID>
const ROPTPCIDs = extractTPCIDs(ROPplanes);
708 if (!isROPinTPCset(ROPTPCIDs, TPCset))
continue;
715 log <<
"Candidate ROP did not match any TPC set.";
716 log <<
"\nROP planes:";
718 log <<
" (" << plane->ID() <<
")";
719 log <<
"\nAvailable TPC sets (" << TPCsets.size() <<
"):";
723 log <<
"\n - " << tpcsetid <<
", " << TPCset.size() <<
" TPC's:";
724 for (
geo::TPCID const& tpcid: TPCset) log <<
" (" << tpcid <<
")";
732 auto& TPCsetROPs = PlanesInProtoROPs[tpcsetid];
733 TPCsetROPs.push_back(std::move(ROPplanes));
734 MaxROPs = std::max(MaxROPs, static_cast<unsigned int>(TPCsetROPs.size()));
739 AllPlanesInROPs.clear();
743 <<
"Encountered " << nErrors
744 <<
" errors while assigning TPC sets to ROPs (see error messages above)\n"
749 <<
"The maximum number of readout planes in any TPC set is " << MaxROPs;
751 return PlanesInProtoROPs;
765 assert(!fTPCsetTPCs.empty());
766 assert(!fTPCsetCount.empty());
767 assert(fMaxROPs > 0U);
772 auto const& TPCsetTPCs = fTPCsetTPCs;
773 auto const& TPCsetCount = fTPCsetCount;
779 fROPcount.resize(TPCsetTPCs.dimSize<0U>(), TPCsetTPCs.dimSize<1U>(), 0U);
781 (TPCsetTPCs.dimSize<0U>(), TPCsetTPCs.dimSize<1U>(), fMaxROPs);
783 auto& ROPcount = fROPcount;
784 auto& ROPplanes = fROPplanes;
789 std::vector<PlaneColl_t>
const sortedTPCset0
790 = sortByNormalCoordinate(PlanesInProtoROPs[{ 0, 0 }]);
803 std::vector<PlaneColl_t>
const& ROPs = PlanesInProtoROPs[tpcsetid];
805 ROPcount[tpcsetid] = ROPs.size();
807 ROPIDdispatcher.setTPCset(tpcsetid);
814 log <<
"Readout plane " << ropid <<
" assigned with " << planes.size()
817 log <<
" (" << plane->ID() <<
")";
819 if (!ROPplanes[ropid].
empty()) {
827 <<
"Logic error: ROPID " << ropid
828 <<
" has already been assigned!\n";
830 ROPplanes[ropid] = std::move(planes);
846 assert(!fCryostats->empty());
847 assert(!fTPCsetTPCs.empty());
852 auto const& Cryostats = *fCryostats;
853 auto const& TPCsetTPCs = fTPCsetTPCs;
858 auto const [ NCryostats, MaxTPCs ]
859 = geo::details::extractMaxGeometryElements<2U>(Cryostats);
862 <<
"Detected " << NCryostats <<
" cryostats."
863 <<
"\nDetected at most " << MaxTPCs <<
" TPCs per cryostat."
865 fTPCtoTPCset.resize(NCryostats, MaxTPCs, {});
868 : util::counter<geo::CryostatID::CryostatID_t>(TPCsetTPCs.dimSize<0>())
872 for (
auto s: util::counter<readout::TPCsetID::TPCsetID_t>(TPCsetTPCs.dimSize<1>()))
878 fTPCtoTPCset[
TPC->ID()] = sid;
896 assert(!fCryostats->empty());
897 assert(!fROPplanes.empty());
902 auto const& Cryostats = *fCryostats;
903 auto const& ROPplanes = fROPplanes;
908 auto const [ NCryostats, MaxTPCs, MaxPlanes ]
909 = geo::details::extractMaxGeometryElements<3U>(Cryostats);
912 <<
"Detected " << NCryostats <<
" cryostats."
913 <<
"\nDetected at most " << MaxTPCs <<
" TPCs per cryostat."
914 <<
"\nDetected at most " << MaxPlanes <<
" planes per TPC."
916 fPlaneToROP.resize(NCryostats, MaxTPCs, MaxPlanes, {});
919 : util::counter<geo::CryostatID::CryostatID_t>(ROPplanes.dimSize<0>())
923 for (
auto s: util::counter<readout::TPCsetID::TPCsetID_t>(ROPplanes.dimSize<1>()))
926 for (
auto r: util::counter<readout::ROPID::ROPID_t>(ROPplanes.dimSize<2>()))
931 assert(plane && plane->ID());
932 fPlaneToROP[plane->ID()] = rid;
933 MF_LOG_TRACE(
fLogCategory) << plane->ID() <<
" => " << rid;
947 (std::vector<PlaneColl_t>
const& ROPs)
const -> std::vector<PlaneColl_t>
958 assert(!ROPs.empty());
960 checkNormalDirection(ROPs);
963 auto sortedROPs { ROPs };
964 std::stable_sort(sortedROPs.begin(), sortedROPs.end(),
979 (std::vector<PlaneColl_t>
const& ROPs)
const
985 if (ROPs.empty())
return;
987 auto iROP = ROPs.begin();
988 assert(!iROP->empty());
998 <<
"icarus::details::ROPandTPCsetBuildingAlg::checkNormalDirection(): "
999 "ROP must contain planes.\n"
1003 if (comp.equal(normDir, plane->GetNormalDirection<
geo::Vector_t>()))
1007 <<
"icarus::details::ROPandTPCsetBuildingAlg::checkNormalDirection(): "
1008 " plane " << plane->ID()
1009 <<
" has normal " << plane->GetNormalDirection<
geo::Vector_t>()
1010 <<
", " << normDir <<
" (as for " << pFirstPlane->
ID()
1021 template <
typename PlaneColl>
1024 -> std::vector<PlaneColl_t>
1026 std::map<double, PlaneColl_t> groupedByDrift;
1039 double const planeD = plane->GetCenter<
geo::Point_t>().Dot(driftDir);
1042 auto iGroup = groupedByDrift.lower_bound(planeD);
1048 if ((iGroup != groupedByDrift.end())
1049 && (iGroup->first - planeD <= tolerance))
1051 iGroup->second.push_back(plane);
1060 groupedByDrift.emplace_hint
1061 (iGroup, planeD + tolerance / 2.0,
PlaneColl_t({ plane }));
1069 std::vector<PlaneColl_t> groups;
1070 groups.reserve(groupedByDrift.size());
1071 for (
auto&&
group: groupedByDrift)
1072 groups.push_back(std::move(std::get<1U>(
group)));
1080 (std::vector<geo::PlaneGeo const*>
const& planes)
1082 return transformCollection(planes,
1095 if (!plane)
continue;
1097 auto const fromPlane
1102 else if (r != fromPlane)
1112 std::vector<geo::TPCID>
const& ROPTPCIDs,
1113 std::vector<geo::TPCID>
const& TPCsetTPCIDs
1119 if (
TPC != ROPTPC)
continue;
1123 if (found)
continue;
void reset()
Sets all the elements to a default-constructed value_type.
typename Coll_t::value_type Value_t
ROOT::Math::DisplacementVector3D< ROOT::Math::Cartesian3D< double >, ROOT::Math::GlobalCoordinateSystemTag > Vector_t
Type for representation of momenta in 3D space.
readout::TPCsetDataContainer< TPCColl_t > fTPCsetTPCs
Output: TPC's in each TPC set.
void fillTPCsInSet(std::vector< std::vector< std::vector< geo::TPCID >>> const &AllTPCsOnROPs)
Extracts the final set of TPC sets.
static std::string ViewName(geo::View_t view)
Returns the name of the specified view.
static bool addNewValue(Coll_t &coll, Value_t const &value)
Container with one element per readout TPC set.
icarus::details::PlaneColl_t PlaneColl_t
Classes identifying readout-related concepts.
static constexpr ROPID_t getInvalidID()
Return the value of the invalid ROP ID as a r-value.
Definition of util::enumerate().
enum geo::_plane_proj View_t
Enumerate the possible plane projections.
unsigned int ROPID_t
Type for the ID number.
unsigned int fMaxTPCsets
Highest number of TPC sets in any cryostat.
readout::TPCsetDataContainer< unsigned int > fROPcount
Output: number of readout planes in each TPC set.
BEGIN_PROLOG opflashtpc1 TPCs
unsigned short TPCsetID_t
Type for the ID number.
Geometry information for a single TPC.
Class identifying a set of TPC sharing readout channels.
DataByView_t< readout::ROPID::ROPID_t > fAvailableROPno
The first available ROP number for each view.
std::map< geo::View_t, T > DataByView_t
Type of collection of T by view.
static std::vector< std::vector< geo::PlaneGeo const * > > groupPlanesByDriftCoord(PlaneColl const &planes, double tolerance=0.1)
Returns the planes grouped by their drift coordinate.
std::vector< geo::CryostatGeo > CryostatList_t
Type of list of cryostats.
std::string const fLogCategory
Log category name for messages.
std::vector< std::vector< PlaneColl_t > > groupPlanesAndTPCs()
Extracts composition of all readout planes.
void fillTPCtoTPCsetMap()
Creates the map from each TPC to its TPC set.
SetColl stableMerge(SetColl const &sets)
void setTPCset(readout::TPCsetID const &TPCset)
Rests the object to work with the specified TPC set next.
Geometry information for a single cryostat.
Vector GetNormalDirection() const
Returns the direction normal to the plane.
static bool overlap(Coll_t const &a, Coll_t const &b)
DataByView_t< unsigned int > ViewROPcounts(std::vector< PlaneColl_t > const &ROPplanes) const
Returns the number of planes with each view.
Class for approximate comparisons.
auto enumerate(Iterables &&...iterables)
Range-for loop helper tracking the number of iteration.
std::vector< unsigned int > fTPCsetCount
Output: number of TPC sets in each cryostat.
decltype(auto) constexpr size(T &&obj)
ADL-aware version of std::size.
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
DataByView_t< readout::ROPID::ROPID_t > const fFirstROPno
The first ROP number for each view.
static readout::ROPID::ROPID_t ROPnumberFromPlanes(PlaneColl_t const &planes)
Returns ROP number matching the plane number shared by all planes.
ROPnumberDispatcher(std::vector< PlaneColl_t > const &refROP, std::string const &logCategory)
Constructor: uses refROP as reference to assign number ranges to views.
auto makeVector3DComparison(RealType threshold)
Creates a Vector3DComparison from a RealComparisons object.
static std::vector< geo::TPCID > extractTPCIDs(std::vector< geo::PlaneGeo const * > const &planes)
Returns a collection with a TPC ID for each plane in the list of planes.
std::vector< PlaneColl_t > sortByNormalCoordinate(std::vector< PlaneColl_t > const &planes) const
Returns the planes sorted by decreasing normal coordinate.
void fillPlanesInROP(readout::TPCsetDataContainer< std::vector< PlaneColl_t >> const &PlanesInProtoROPs)
Builds final readout plane information.
readout::TPCsetID fTPCset
The TPC set being served.
Geometry information for a single wire plane.The plane is represented in the geometry by a solid whic...
std::vector< std::vector< std::vector< geo::TPCID > > > extractTPCsetsFromROPs(std::vector< std::vector< PlaneColl_t >> const &planes)
Extracts all the TPC sets covered by any of the plane groups.
readout::TPCsetDataContainer< std::vector< PlaneColl_t > > groupPlanesIntoROPs(std::vector< std::vector< std::vector< geo::TPCID >>> const &AllTPCsOnROPs, std::vector< std::vector< PlaneColl_t >> &&AllPlanesInROPs)
Assigns each of the readout planes to a TPC set.
constexpr Vector Xaxis()
Returns a x axis vector of the specified type.
std::tuple< std::vector< unsigned int >, readout::TPCsetDataContainer< TPCColl_t >, readout::TPCsetDataContainer< unsigned int >, readout::ROPDataContainer< PlaneColl_t >, geo::TPCDataContainer< readout::TPCsetID >, geo::PlaneDataContainer< readout::ROPID > > ResultsBase_t
Full group of results of the algorithm.
Algorithm discovering TPC sets and readout planes for ICARUS.
static SetColl_t merge(SetColl_t const &sets)
static SetColl_t mergePass(SetColl_t const &sets)
std::vector< geo::PlaneGeo const * > PlaneColl_t
Type of collection of planes (pointers to geo::PlaneGeo).
Algorithm assigning IDs to readout planes.
The data type to uniquely identify a TPC.
Definition of data types for geometry description.
typename SetColl_t::value_type Coll_t
Class identifying a set of planes sharing readout channels.
static geo::View_t ROPview(PlaneColl_t const &planes)
Returns the view of the planes (geo::kUnknown if mixed or none).
unsigned int fMaxROPs
Highest number of ROPs in any TPC set.
constexpr TPCID const & asTPCID() const
Conversion to TPCID (for convenience of notation).
geo::PlaneDataContainer< readout::ROPID > fPlaneToROP
Output: the ROP each wire plane belongs to.
readout::ROPDataContainer< PlaneColl_t > fROPplanes
Output: planes in each of the readout plane.
unsigned int CryostatID_t
Type for the ID number.
geo::TPCDataContainer< readout::TPCsetID > fTPCtoTPCset
Output: the TPC set each TPC belongs to.
DataByView_t< readout::ROPID::ROPID_t > PreferredROPrangesByView(std::vector< PlaneColl_t > const &ROPs) const
Returns the fist ROP number for each view in ROP.
double DistanceFromPlane(geo::Point_t const &point) const
Returns the distance of the specified point from the wire plane.
const TPCGeo & TPC(unsigned int itpc) const
Return the itpc'th TPC in the cryostat.
then echo File list $list not found else cat $list while read file do echo $file sed s
static Coll_t mergeColls(Coll_t const &a, Coll_t const &b)
geo::PlaneID const & ID() const
Returns the identifier of this plane.
Functions pulling in STL customization if available.
readout::ROPID assignID(PlaneColl_t const &ROP)
Returns the next available ID for the specified ROP.
void fillPlaneToROPmap()
Creates the map from each wire plane to its readout plane.
static bool isROPinTPCset(std::vector< geo::TPCID > const &ROPTPCIDs, std::vector< geo::TPCID > const &TPCsetTPCIDs)
Returns whether all the TPCs covered by a ROP are in a given TPC set.
void clear()
Destroys all the result data members.
Results_t run(geo::GeometryData_t::CryostatList_t const &Cryostats)
Runs the algorithm as configured from start to end.
ROOT::Math::PositionVector3D< ROOT::Math::Cartesian3D< double >, ROOT::Math::GlobalCoordinateSystemTag > Point_t
Type for representation of position in physical 3D space.
void checkNormalDirection(std::vector< PlaneColl_t > const &planes) const
Throws an exception if planes do not share the same normal direction.
bool empty(FixedBins< T, C > const &) noexcept
The data type to uniquely identify a cryostat.
geo::CryostatID const & ID() const
Returns the identifier of this cryostat.