All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
PMTverticalSlicingAlg.cxx
Go to the documentation of this file.
1 /**
2  * @file icaruscode/PMT/Algorithms/PMTverticalSlicingAlg.cxx
3  * @brief Algorihtm to group PMTs into piling towers (implementation file).
4  * @author Gianluca Petrillo (petrillo@slac.stanford.edu)
5  * @date January 7, 2020
6  * @see icaruscode/PMT/Algorithms/PMTverticalSlicingAlg.h
7  */
8 
9 // library header
11 #include "icarusalg/Utilities/SimpleClustering.h" // util::clusterBy()
12 
13 // LArSoft libraries
20 #include "larcorealg/CoreUtils/RealComparisons.h" // lar::util::Vector3DComparisons
21 
22 // C/C++ standard library
23 #include <vector>
24 #include <functional> // std::less
25 #include <iterator> // std::make_move_iterator(), std::back_inserter()
26 #include <limits>
27 #include <cmath> // std::abs()
28 #include <cassert>
29 
30 
31 //------------------------------------------------------------------------------
32 namespace {
33 
34  // Use the projection of the PMT center on the specified direction as
35  // clustering key; we need a reference point to project... we pick `origin()`.
36  struct PMTprojectorClass {
37  geo::Vector_t const dir; ///< Projection direction.
38  double operator() (geo::OpDetGeo const* opDet) const
39  { return (opDet->GetCenter() - geo::origin()).Dot(dir); };
40  }; // PMTprojectorClass
41 
42  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
43  /**
44  * @brief Moves the content of `source` into the end of `dest`.
45  * @tparam T type of objects contained in the collections
46  * @tparam Src type of source collection
47  * @param dest vector to be added elements
48  * @param source container with all the elements to be appended to `dest`
49  * @return a reference to `dest` itself
50  *
51  * The content of `source` is moved away, and `source` itself is moved.
52  */
53  template <typename T, typename Src>
54  std::vector<T>& append(std::vector<T>& dest, Src&& src) {
55 
56  using std::size;
57  using std::begin;
58  using std::end;
59 
60  dest.reserve(dest.size() + size(src));
61  dest.insert(dest.end(),
62  std::make_move_iterator(begin(src)), std::make_move_iterator(end(src))
63  );
64  Src{ std::move(src) }; // move src into a temporary (which we don't care of)
65  return dest;
66  } // append()
67 
68 } // local namespace
69 
70 
71 //------------------------------------------------------------------------------
72 //--- icarus::trigger::PMTverticalSlicingAlg
73 //------------------------------------------------------------------------------
75  (std::string logCategory /* = "PMTverticalSlicingAlg" */)
76  : fLogCategory(std::move(logCategory))
77  {}
78 
79 
80 //------------------------------------------------------------------------------
82  (Slices_t& slices, geo::CryostatGeo const& cryo) const
83 {
84  geo::Vector_t const& driftDir = determineDriftDir(cryo.IterateTPCs());
85  geo::Vector_t const& widthDir = determineLengthDir(cryo.IterateTPCs());
86  appendSlices(slices, getCryoPMTs(cryo), driftDir, widthDir);
87 } // icarus::trigger::PMTverticalSlicingAlg::appendCryoSlices()
88 
89 
90 //------------------------------------------------------------------------------
92  (geo::CryostatGeo const& cryo) const
93  -> std::vector<std::pair<double, PMTlist_t>>
94 {
95  return PMTwalls(getCryoPMTs(cryo), determineDriftDir(cryo.IterateTPCs()));
96 } // icarus::trigger::PMTverticalSlicingAlg::PMTwalls(CryostatGeo)
97 
98 
99 //------------------------------------------------------------------------------
101  (geo::GeometryCore const& geom) const
102  -> std::vector<std::pair<double, PMTlist_t>>
103 {
104  return PMTwalls(getPMTs(geom), determineDriftDir(geom.IterateTPCs()));
105 } // icarus::trigger::PMTverticalSlicingAlg::PMTwalls(GeometryCore)
106 
107 
108 //------------------------------------------------------------------------------
110  Slices_t& slices, PMTlist_t const& PMTs,
111  geo::Vector_t const& planeNorm, geo::Vector_t const& clusterDir
112  ) const
113 {
114 
115  /*
116  * 1. group PMT by plane (cluster on drift direction)
117  * 2. group PMT in each plane by width coordinate (cluster by width direction)
118  */
119 
120  //
121  // 1. group PMT by plane (cluster on drift direction)
122  //
123 
124  std::vector<PMTlist_t> const PMTplanes = clusterPMTby(PMTs, planeNorm);
125 
126  // BEGIN debug
127  {
128  mf::LogTrace log { fLogCategory };
129  log << PMTs.size() << " PMTs grouped into " << PMTplanes.size()
130  << " planes in direction " << planeNorm << ":";
131  for (auto&& [ iPlane, PMTplane ]: util::enumerate(PMTplanes)) {
132  log << "\n [#" << iPlane << "] " << PMTplane.size() << " PMT:";
133  for (geo::OpDetGeo const* opDet: PMTplane)
134  log << " <" << opDet->ID() << ">";
135  } // for
136  }
137  // END debug
138 
139  //
140  // 2. group PMT in each plane by width coordinate (cluster by width direction)
141  //
142  unsigned int NClusteredPMTs [[maybe_unused]] = 0U;
143  for (auto const& PMTplane: PMTplanes) {
144  slices.push_back(clusterPMTby(PMTplane, clusterDir));
145 
146  // BEGIN debug
147  auto const& planeSlices = slices.back();
148  mf::LogTrace log { fLogCategory };
149  log << PMTplane.size() << " PMTs in the plane grouped into "
150  << planeSlices.size() << " towers in direction " << clusterDir << ":";
151  for (auto&& [ iSlice, slice ]: util::enumerate(planeSlices)) {
152  NClusteredPMTs += slice.size();
153  log << "\n [#" << iSlice << "] " << slice.size() << " PMT:";
154  for (geo::OpDetGeo const* opDet: slice) log << " <" << opDet->ID() << ">";
155  } // for planeSlices
156  // END debug
157 
158  } // for planes
159 
160  assert(NClusteredPMTs == PMTs.size());
161 
162 } // icarus::trigger::PMTverticalSlicingAlg::appendSlices()
163 
164 
165 //------------------------------------------------------------------------------
167  (PMTlist_t const& PMTs, geo::Vector_t const& dir) const
168  -> std::vector<std::pair<double, PMTlist_t>>
169 {
170  // fill the walls with PMTs
171  std::vector<PMTlist_t> walls = clusterPMTby(PMTs, dir);
172 
173  // determine their coordinate
174  std::vector<std::pair<double, PMTlist_t>> posAndWalls;
175  posAndWalls.reserve(walls.size());
176  for (PMTlist_t& wall: walls)
177  posAndWalls.emplace_back(PMTwallPosition(wall, dir), std::move(wall));
178 
179  // sort by coordinate
180  std::sort(posAndWalls.begin(), posAndWalls.end()); // sort by std::pair::first
181 
182  return posAndWalls;
183 
184 } // icarus::trigger::PMTverticalSlicingAlg::PMTwalls(CryostatGeo)
185 
186 
187 //------------------------------------------------------------------------------
189  (PMTlist_t const& PMTs, geo::Vector_t const& dir)
190 {
191  if (PMTs.empty()) return std::numeric_limits<double>::lowest(); // arbitrary
192 
193  PMTprojectorClass const PMTcenterProjection { dir };
195  for (geo::OpDetGeo const* PMT: PMTs) stats.add(PMTcenterProjection(PMT));
196  return stats.Average();
197 
198 } // icarus::trigger::PMTverticalSlicingAlg::PMTwallPosition()
199 
200 
201 //------------------------------------------------------------------------------
203  (PMTlist_t const& PMTs, geo::Vector_t const& dir) -> std::vector<PMTlist_t>
204 {
205 #if 0
206  // use the projection of the PMT center on the specified direction as
207  // clustering key; we need a reference point to project... we pick `origin()`.
208  auto const PMTcenterProjection = [dir](geo::OpDetGeo const* opDet)
209  { return (opDet->GetCenter() - geo::origin()).Dot(dir); };
210 #endif // 0
211 
212  PMTprojectorClass const PMTcenterProjection { dir };
213 
214  // PMTs with a coordinate within 5 cm (kind of) will be clustered together
215  constexpr double tol = 5.0; // cm
216  auto const closeEnough
217  = [](double a, double b){ return std::abs(a - b) < tol; };
218 
219  return util::clusterBy(PMTs, PMTcenterProjection, closeEnough, std::less<>());
220 
221 } // icarus::trigger::PMTverticalSlicingAlg::clusterPMTby()
222 
223 
224 //------------------------------------------------------------------------------
226  (geo::CryostatGeo const& cryo) -> PMTlist_t
227 {
228  PMTlist_t opDets;
229  for (auto iOpDet: util::counter(cryo.NOpDet()))
230  opDets.push_back(&cryo.OpDet(iOpDet));
231  return opDets;
232 } // icarus::trigger::PMTverticalSlicingAlg::getCryoPMTs()
233 
234 
235 //------------------------------------------------------------------------------
237  (geo::GeometryCore const& geom) -> PMTlist_t
238 {
239  PMTlist_t opDets;
240  for (geo::CryostatGeo const& cryo: geom.IterateCryostats())
241  append(opDets, getCryoPMTs(cryo));
242  return opDets;
243 } // icarus::trigger::PMTverticalSlicingAlg::getCryoPMTs()
244 
245 
246 //------------------------------------------------------------------------------
248  (geo::Vector_t const& a, geo::Vector_t const& b)
249 {
250  lar::util::Vector3DComparison cmp { 1e-4 };
251  return cmp.zero(a.Cross(b));
252 } // icarus::trigger::PMTverticalSlicingAlg::areParallel()
253 
254 
255 //------------------------------------------------------------------------------
ROOT::Math::DisplacementVector3D< ROOT::Math::Cartesian3D< double >, ROOT::Math::GlobalCoordinateSystemTag > Vector_t
Type for representation of momenta in 3D space.
Definition: geo_vectors.h:164
std::vector< geo::OpDetGeo const * > PMTlist_t
Type of optical detector list.
Encapsulate the construction of a single cyostat.
Class comparing 2D vectors.
PMTverticalSlicingAlg(std::string logCategory="PMTverticalSlicingAlg")
Constructor: no configuration parameters so far.
#define PMT
Definition: NestAlg.cxx:19
Definition of util::enumerate().
void appendSlices(Slices_t &slices, PMTlist_t const &PMTs, geo::Vector_t const &planeNorm, geo::Vector_t const &clusterDir) const
Computes slices and appends them to an existing list.
auto const tol
Definition: SurfXYZTest.cc:16
ElementIteratorBox IterateTPCs() const
Returns an object suitable for iterating through all TPCs.
Definition: CryostatGeo.h:258
static std::vector< PMTlist_t > clusterPMTby(PMTlist_t const &PMTs, geo::Vector_t const &dir)
Clusters the PMTs along the specified direction.
std::size_t size(FixedBins< T, C > const &) noexcept
Definition: FixedBins.h:561
static PMTlist_t getPMTs(geo::GeometryCore const &geom)
Returns a list of all geo::OpDetGeo in the whole geometry.
void GetCenter(double *xyz, double localz=0.0) const
Definition: OpDetGeo.cxx:40
Geometry information for a single cryostat.
Definition: CryostatGeo.h:43
Classes gathering simple statistics.
Class for approximate comparisons.
auto enumerate(Iterables &&...iterables)
Range-for loop helper tracking the number of iteration.
Definition: enumerate.h:69
Weight_t Average() const
Returns the value average.
process_name gaushit a
fDetProps &fDetProps fDetProps &fDetProps fLogCategory
Access the description of detector geometry.
T abs(T value)
auto counter(T begin, T end)
Returns an object to iterate values from begin to end in a range-for loop.
Definition: counter.h:285
void appendCryoSlices(Slices_t &slices, geo::CryostatGeo const &cryo) const
Computes slices from all PMT in cryo and appends them to slices.
const OpDetGeo & OpDet(unsigned int iopdet) const
Return the iopdet&#39;th optical detector in the cryostat.
IteratorBox< TPC_iterator,&GeometryCore::begin_TPC,&GeometryCore::end_TPC > IterateTPCs() const
Enables ranged-for loops on all TPCs of the detector.
auto end(FixedBins< T, C > const &) noexcept
Definition: FixedBins.h:585
Algorihtm to group PMTs into piling towers.
Test of util::counter and support utilities.
Description of geometry of one entire detector.
auto clusterBy(Coll const &objs, KeyOp keyFunc, CmpOp sameGroup, RefOp objRef, KeySortOp keySort)
Performs a simple clustering.
std::string fLogCategory
Category for message streaming.
std::vector< TCSlice > slices
Definition: DataStructs.cxx:13
static bool areParallel(geo::Vector_t const &a, geo::Vector_t const &b)
Returns whether a and b are parallel.
tuple dir
Definition: dropbox.py:28
auto begin(FixedBins< T, C > const &) noexcept
Definition: FixedBins.h:573
Encapsulate the geometry of an optical detector.
IteratorBox< cryostat_iterator,&GeometryCore::begin_cryostat,&GeometryCore::end_cryostat > IterateCryostats() const
Enables ranged-for loops on all cryostats of the detector.
std::vector< std::pair< double, PMTlist_t > > PMTwalls(geo::CryostatGeo const &cryo) const
Groups optical detectors under the specified cryostat into walls.
unsigned int NOpDet() const
Number of optical detectors in this TPC.
Definition: CryostatGeo.h:361
Algorithms to cluster objects according to specified criteria.
walls no wall
Definition: selectors.fcl:105
static double PMTwallPosition(PMTlist_t const &PMTs, geo::Vector_t const &dir)
Returns an (arbitrary) coordinate along dir representing the PMT list.
do i e
geo::OpDetID const & ID() const
Returns the geometry ID of this optical detector.
Definition: OpDetGeo.h:72
std::vector< PMTtowerOnPlane_t > Slices_t
Type of PMT towers, per plane.
static PMTlist_t getCryoPMTs(geo::CryostatGeo const &cryo)
Returns a list of all geo::OpDetGeo in cryostat cryo.
constexpr Point origin()
Returns a origin position with a point of the specified type.
Definition: geo_vectors.h:227
void add(Data_t value, Weight_t weight=Weight_t(1.0))
Adds one entry with specified value and weight.