PhotonVoxels.cxx
Go to the documentation of this file.
1 /**
2  * @file larsim/Simulation/PhotonVoxels.cxx
3  * @brief Definitions of voxel data structures: implementation.
4  * @see larsim/Simulation/PhotonVoxels.h
5  */
6 
7 // library header
10 
11 // C++ standard libraries
12 #include <algorithm> // std::min(), std::max()
13 #include <cmath> // std::abs(), std::floor()
14 #include <stdexcept> // std::runtime_error
15 #include <string>
16 
17 namespace sim {
18 
19  //----------------------------------------------------------------------------
20  // PhotonVoxelDef class
21  //----------------------------------------------------------------------------
23  double xMax,
24  int xN,
25  double yMin,
26  double yMax,
27  int yN,
28  double zMin,
29  double zMax,
30  int zN)
31  : fLowerCorner(xMin, yMin, zMin)
32  , fUpperCorner(xMax, yMax, zMax)
33  , fxSteps(xN)
34  , fySteps(yN)
35  , fzSteps(zN)
36  {}
37 
38  //----------------------------------------------------------------------------
39  std::array<unsigned int, 3U>
41  {
42  // BUG the double brace syntax is required to work around clang bug 21629
43  // (https://bugs.llvm.org/show_bug.cgi?id=21629)
44  return {{fxSteps, fySteps, fzSteps}};
45  }
46 
47  //----------------------------------------------------------------------------
48  bool
50  {
51  return ((GetRegionUpperCorner() == right.GetRegionUpperCorner()) &&
53  (GetSteps() == right.GetSteps()));
54  }
55 
56  //----------------------------------------------------------------------------
57  unsigned int
59  {
60  return fxSteps * fySteps * fzSteps;
61  }
62 
63  //----------------------------------------------------------------------------
64  int
65  PhotonVoxelDef::GetVoxelID(double const* Position) const
66  {
67  return GetVoxelIDImpl(geo::vect::makeFromCoords<geo::Point_t>(Position));
68  }
69 
70  //----------------------------------------------------------------------------
71  std::optional<std::array<sim::PhotonVoxelDef::NeiInfo, 8U>>
73  {
74  if (!isInside(v)) return {};
75 
76  std::array<sim::PhotonVoxelDef::NeiInfo, 8U> ret;
77 
78  // Position in voxel coordinates including floating point part
79  auto const rStepD = GetVoxelStepCoordsUnchecked(v);
80 
81  // The neighbours are the 8 corners of a cube around this point
82  std::size_t iNeigh = 0U;
83  for (int dx : {0, 1}) {
84  for (int dy : {0, 1}) {
85  for (int dz : {0, 1}) {
86  // The full 3D step
87  const int dr[3] = {dx, dy, dz};
88 
89  // The integer-only position of the current corner
90  int rStepI[3];
91  for (int d = 0; d < 3; ++d) {
92  // Round down to get the "lower left" corner
93  rStepI[d] = int(rStepD[d]);
94  // Ensure we'll stay in-bounds
95  rStepI[d] = std::max(0, rStepI[d]);
96  rStepI[d] = std::min(rStepI[d], int(GetSteps()[d]) - 2);
97  // Adjust to the corner we're actually considering
98  rStepI[d] += dr[d];
99  }
100 
101  double w = 1;
102  for (int d = 0; d < 3; ++d) {
103  // These expressions will interpolate when between the 8 corners,
104  // and extrapolate in the half-voxel space around the edges.
105  if (dr[d] == 0)
106  w *= 1 + rStepI[d] - rStepD[d];
107  else
108  w *= 1 - rStepI[d] + rStepD[d];
109  }
110 
111  const int id = (rStepI[0] + rStepI[1] * (fxSteps) + rStepI[2] * (fxSteps * fySteps));
112 
113  ret[iNeigh++] = {id, w};
114  }
115  }
116  }
117 
118  // Sanity check the weights sum to 1
119  double wSum = 0;
120  for (const NeiInfo& n : ret)
121  wSum += n.weight;
122  if (std::abs(wSum - 1) > 1e-3) {
123  std::string msg = "PhotonVoxelDef::GetNeighboringVoxelIDs():"
124  " Weights sum to " +
125  std::to_string(wSum) +
126  " (should be 1)."
127  " Weights are:";
128  for (const NeiInfo& n : ret) {
129  msg += ' ';
130  msg += std::to_string(n.weight);
131  }
132  throw std::runtime_error(msg);
133  }
134  return {ret};
135  }
136 
137  //----------------------------------------------------------------------------
140  {
141  // float TempID = (float) ID;
142 
143  // Decompose ID into steps in each direction
144  int xStep = ID % fxSteps;
145  int yStep = ((ID - xStep) / fxSteps) % fySteps;
146  int zStep = ((ID - xStep - (yStep * fxSteps)) / (fySteps * fxSteps)) % fzSteps;
147 
148  auto const VoxelSize = GetVoxelSize<geo::Vector_t>();
149 
150  double const xMin = VoxelSize.X() * (xStep) + fLowerCorner.X();
151  double const xMax = VoxelSize.X() * (xStep + 1) + fLowerCorner.X();
152  double const yMin = VoxelSize.Y() * (yStep) + fLowerCorner.Y();
153  double const yMax = VoxelSize.Y() * (yStep + 1) + fLowerCorner.Y();
154  double const zMin = VoxelSize.Z() * (zStep) + fLowerCorner.Z();
155  double const zMax = VoxelSize.Z() * (zStep + 1) + fLowerCorner.Z();
156 
157  return PhotonVoxel(xMin, xMax, yMin, yMax, zMin, zMax);
158  }
159 
160  //----------------------------------------------------------------------------
161  bool
163  {
164  return ((ID >= 0) && (static_cast<unsigned int>(ID) < GetNVoxels()));
165  }
166 
167  std::array<int, 3U>
169  {
170  std::array<int, 3U> ReturnVector;
171  ReturnVector[0] = ID % fxSteps;
172  ReturnVector[1] = ((ID - ReturnVector[0]) / fxSteps) % fySteps;
173  ReturnVector[2] =
174  ((ID - ReturnVector[0] - (ReturnVector[1] * fxSteps)) / (fySteps * fxSteps)) % fzSteps;
175  return ReturnVector;
176  }
177 
178  //----------------------------------------------------------------------------
179  std::array<double, 3U>
181  {
182 
183  auto const span = fUpperCorner - fLowerCorner;
184  auto const relPos = p - fLowerCorner;
185 
186  // BUG the double brace syntax is required to work around clang bug 21629
187  // (https://bugs.llvm.org/show_bug.cgi?id=21629)
188  return {{(relPos.X() / span.X()) * fxSteps,
189  (relPos.Y() / span.Y()) * fySteps,
190  (relPos.Z() / span.Z()) * fzSteps}};
191  } // PhotonVoxelDef::GetVoxelStepCoordsUnchecked()
192 
193  //----------------------------------------------------------------------------
194  int
196  {
197  if (!isInside(p)) return -1;
198 
199  auto const stepCoords = GetVoxelStepCoordsUnchecked(p);
200 
201  // figure out how many steps this point is in the x,y,z directions;
202  // `p` is guaranteed to be in the mapped volume by the previous check
203  int xStep = static_cast<int>(stepCoords[0]);
204  int yStep = static_cast<int>(stepCoords[1]);
205  int zStep = static_cast<int>(stepCoords[2]);
206 
207  // if within bounds, generate the voxel ID
208  return (xStep + yStep * (fxSteps) + zStep * (fxSteps * fySteps));
209  }
210 
211  //----------------------------------------------------------------------------
212  bool
214  geo::Point_t const& lower,
215  geo::Point_t const& upper)
216  {
217  return isInsideRange(point.X(), lower.X(), upper.X()) &&
218  isInsideRange(point.Y(), lower.Y(), upper.Y()) &&
219  isInsideRange(point.Z(), lower.Z(), upper.Z());
220  }
221 
222  bool
223  PhotonVoxelDef::isInsideRange(double value, double lower, double upper)
224  {
225 
226  return (value >= lower) && (value < upper);
227 
228  } // PhotonVoxelDef::isInsideRange()
229 
230  //----------------------------------------------------------------------------
231 
232  std::ostream&
233  operator<<(std::ostream& out, sim::PhotonVoxelDef const& voxelDef)
234  {
235 
236  auto const& lower = voxelDef.GetRegionLowerCorner();
237  auto const& upper = voxelDef.GetRegionUpperCorner();
238  auto const& steps = voxelDef.GetSteps();
239  auto const& stepSize = voxelDef.GetVoxelSize();
240 
241  out << "Volume " << voxelDef.GetVolumeSize() << " cm^3 split in " << voxelDef.GetNVoxels()
242  << " voxels:"
243  << "\n - x axis: [ " << lower.X() << " ; " << upper.X() << " ] split in " << steps[0]
244  << "x " << stepSize.X() << " cm steps"
245  << "\n - y axis: [ " << lower.Y() << " ; " << upper.Y() << " ] split in " << steps[1]
246  << "x " << stepSize.Y() << " cm steps"
247  << "\n - z axis: [ " << lower.Z() << " ; " << upper.Z() << " ] split in " << steps[2]
248  << "x " << stepSize.Z() << " cm steps"
249  << "\n";
250 
251  return out;
252  } // operator<< (sim::PhotonVoxelDef)
253 
254  //----------------------------------------------------------------------------
255 
256 } // namespace sim
Definitions of voxel data structures.
span(IterB &&b, IterE &&e, Adaptor &&adaptor) -> span< decltype(adaptor(std::forward< IterB >(b))), decltype(adaptor(std::forward< IterE >(e))) >
Utilities to extend the interface of geometry vectors.
void msg(const char *fmt,...)
Definition: message.cpp:107
unsigned int fySteps
Definition: PhotonVoxels.h:65
std::string string
Definition: nybbler.cc:12
unsigned int ID
PhotonVoxelDef()=default
Vector GetVoxelSize() const
Returns a vector describing the span of a single voxel in x, y an z [cm].
Definition: PhotonVoxels.h:224
int GetVoxelIDImpl(geo::Point_t const &p) const
bool operator==(const PhotonVoxelDef &rhs) const
Representation of a region of space diced into voxels.
Definition: PhotonVoxels.h:58
std::array< double, 3U > GetVoxelStepCoordsUnchecked(geo::Point_t const &p) const
Returns the coordinates of the cvoxel containing p in step units.
int GetVoxelID(Point const &p) const
Returns the ID of the voxel containing p, or -1 if none.
Definition: PhotonVoxels.h:234
std::array< int, 3U > GetVoxelCoords(int ID) const
bool isInside(geo::Point_t const &p) const
Returns whether point p is inside the region (upper border excluded).
Definition: PhotonVoxels.h:139
T abs(T value)
const double e
static bool isInsideRange(double value, double lower, double upper)
unsigned int fzSteps
Definition: PhotonVoxels.h:66
std::void_t< T > n
decltype(auto) GetRegionUpperCorner() const
Returns the volume vertex (type Point) with the highest coordinates.
p
Definition: test.py:223
static int max(int a, int b)
Code to link reconstructed objects back to the MC truth information.
bool IsLegalVoxelID(int) const
unsigned int fxSteps
Definition: PhotonVoxels.h:64
geo::Point_t fLowerCorner
Definition: PhotonVoxels.h:62
ROOT::Math::PositionVector3D< ROOT::Math::Cartesian3D< double >, ROOT::Math::GlobalCoordinateSystemTag > Point_t
Type for representation of position in physical 3D space.
Definition: geo_vectors.h:184
Representation of a single small volume (voxel).
Definition: PhotonVoxels.h:20
T min(sqlite3 *const db, std::string const &table_name, std::string const &column_name)
Definition: statistics.h:55
geo::Point_t fUpperCorner
Definition: PhotonVoxels.h:63
unsigned int GetNVoxels() const
Returns the total number of voxels in the volume.
std::array< unsigned int, 3U > GetSteps() const
Returns the number of voxels along each of the three dimensions.
Vector GetVolumeSize() const
Returns a vector describing the full span in x, y an z [cm].
Definition: PhotonVoxels.h:98
std::ostream & operator<<(std::ostream &output, const LArVoxelData &data)
static bool isInsideVolume(geo::Point_t const &point, geo::Point_t const &lower, geo::Point_t const &upper)
std::optional< std::array< NeiInfo, 8U > > GetNeighboringVoxelIDsImpl(geo::Point_t const &v) const
std::string to_string(ModuleType const mt)
Definition: ModuleType.h:34
decltype(auto) GetRegionLowerCorner() const
Returns the volume vertex (type Point) with the lowest coordinates.
PhotonVoxel GetPhotonVoxel(int ID) const