LDMX Software
EcalGeometry.cxx
2
3#include <cmath>
4#include <iomanip>
5#include <iostream>
6#include <tuple>
7
8#include "Framework/Exception/Exception.h"
9#include "TGraph.h"
10#include "TList.h"
11
12namespace ldmx {
13
14static double distance(const std::pair<double, double>& p1,
15 const std::pair<double, double>& p2) {
16 return sqrt((p1.first - p2.first) * (p1.first - p2.first) +
17 (p1.second - p2.second) * (p1.second - p2.second));
18}
19
20[[maybe_unused]] static double distance(
21 const std::tuple<double, double, double>& p1,
22 const std::tuple<double, double, double>& p2) {
23 return sqrt((std::get<0>(p1) - std::get<0>(p2)) *
24 (std::get<0>(p1) - std::get<0>(p2)) +
25 (std::get<1>(p1) - std::get<1>(p2)) *
26 (std::get<1>(p1) - std::get<1>(p2)) +
27 (std::get<2>(p1) - std::get<2>(p2)) *
28 (std::get<2>(p1) - std::get<2>(p2)));
29}
30
34static void rotate(double& p, double& q) {
35 double tmp{p};
36 p = -q;
37 q = tmp;
38}
39
43static void unrotate(double& p, double& q) {
44 double tmp{p};
45 p = q;
46 q = -tmp;
47}
48
50 : framework::ConditionsObject(EcalGeometry::CONDITIONS_OBJECT_NAME) {
51 layer_z_positions_ = ps.get<std::vector<double>>("layer_z_positions");
52 ecal_front_z_ = ps.get<double>("ecal_front_z");
53 module_r_min_ = ps.get<double>("module_min_r");
54 gap_ = ps.get<double>("gap");
55 n_cell_r_height_ = ps.get<double>("n_cell_r_height");
56 corners_side_up_ = ps.get<bool>("corners_side_up");
57 layer_shift_x_ = ps.get<double>("layer_shift_x");
58 layer_shift_y_ = ps.get<double>("layer_shift_y");
59 layer_shift_odd_ = ps.get<bool>("layer_shift_odd");
60 layer_shift_odd_bilayer_ = ps.get<bool>("layer_shift_odd_bilayer");
61 ecal_center_x_ = ps.get<double>("ecal_center_x", 0.);
62 ecal_center_y_ = ps.get<double>("ecal_center_y", 0.);
63 flip_y_ = ps.get<bool>("flip_y", false);
64 si_thickness_ = ps.get<double>("si_thickness");
65
67 EXCEPTION_RAISE("BadConf",
68 "Cannot shift both odd sensitive layers and odd bilayers");
69 }
70
71 module_r_max_ = module_r_min_ * (2 / sqrt(3));
73 cell_r_min_ = (sqrt(3.) / 2.) * cell_r_max_;
74
75 ldmx_log(debug) << "Building module map with gap " << std::setprecision(2)
76 << gap_ << ", nCellRHeight " << n_cell_r_height_
77 << ", min/max radii of cell " << cell_r_min_ << " / "
78 << cell_r_max_ << ", and module " << module_r_min_ << " / "
80
86
87 ldmx_log(trace) << "Geometry fully constructed";
88}
89
90EcalID EcalGeometry::getID(double x, double y, double z, bool fallible) const {
91 int layer_id{-1};
92 for (const auto& [lid, layer_xyz] : layer_pos_xy_) {
93 // check if the z coordinate is within the layer thickness
94 if (std::abs(std::get<2>(layer_xyz) - z) < si_thickness_) {
95 layer_id = lid;
96 break;
97 }
98 }
99 if (layer_id < 0) {
100 if (fallible) {
101 return ldmx::EcalID(0);
102 } else {
103 EXCEPTION_RAISE("BadConf", "z = " + std::to_string(z) +
104 " mm is not within any"
105 " of the configured layers.");
106 }
107 }
108 return getID(x, y, layer_id, fallible);
109}
110
111EcalID EcalGeometry::getID(double x, double y, int layer_id,
112 bool fallible) const {
113 // now assume we know the layer
114 // shift to center of layer
115 // and convert to flower coordinates
116 double p{x - std::get<0>(layer_pos_xy_.at(layer_id))},
117 q{y - std::get<1>(layer_pos_xy_.at(layer_id))};
118 if (flip_y_) q = -q;
119
120 // deduce module ID
121 // there are only 7 modules so we just loop through them
122 // all and pick out the module ID that we are inside of
123
124 int module_id{-1};
125 for (auto const& [mid, module_xy] : module_pos_xy_) {
126 double probe_x{p - module_xy.first}, probe_y{q - module_xy.second};
127 if (corners_side_up_) rotate(probe_x, probe_y);
128 if (isInside(probe_x / module_r_max_, probe_y / module_r_max_)) {
129 module_id = mid;
130 break;
131 }
132 }
133
134 if (module_id < 0) {
135 if (fallible) {
136 return ldmx::EcalID(0);
137 } else {
138 EXCEPTION_RAISE(
139 "BadConf",
140 TString::Format(
141 "Coordinates relative to layer (p,q) = (%.2f, %.2f) mm "
142 "derived from world coordinates (%.2f, %.2f) mm with layer = %d "
143 "are not inside any module.",
144 p, q, x, y, layer_id)
145 .Data());
146 }
147 }
148
149 return getID(x, y, layer_id, module_id);
150}
151
152EcalID EcalGeometry::getID(double x, double y, int layer_id, int module_id,
153 bool fallible) const {
154 // now assume we know the layer and module
155 // shift to center of layer and then center of module
156 double p{x - std::get<0>(layer_pos_xy_.at(layer_id)) -
157 module_pos_xy_.at(module_id).first},
158 q{(flip_y_ ? -1. : 1.) * (y - std::get<1>(layer_pos_xy_.at(layer_id))) -
159 module_pos_xy_.at(module_id).second};
160
161 // need to rotate
162 if (corners_side_up_) rotate(p, q);
163
164 // deduce cell ID
165 int cell_id = cell_id_in_module_.FindBin(p, q) - 1;
166
167 if (cell_id < 0) {
168 if (fallible) {
169 return ldmx::EcalID(0);
170 } else {
171 EXCEPTION_RAISE(
172 "BadConf",
173 TString::Format(
174 "Relative cell coordinates (%.2f, %.2f) mm "
175 "derived from world coordinates (%.2f, %.2f) mm with layer = %d "
176 "and module = %d are outside module hexagon",
177 p, q, x, y, layer_id, module_id)
178 .Data());
179 }
180 }
181
182 return EcalID(layer_id, module_id, cell_id);
183}
184
185std::tuple<double, double, double> EcalGeometry::getPosition(EcalID id) const {
186 return cell_global_pos_.at(id);
187}
188
189std::pair<double, double> EcalGeometry::getPositionInModule(int cell_id) const {
190 auto pq = cell_pos_in_module_.at(cell_id);
191
192 // going from (p,q) to (x,y) is a unrotate
193 if (corners_side_up_) unrotate(pq.first, pq.second);
194
195 return pq;
196}
197
199 ldmx_log(debug) << "Building layer map with " << layer_z_positions_.size()
200 << " layers";
202 if (layer_shift_odd_) {
203 ldmx_log(debug) << "Shifting odd layers by (x,y) = (" << layer_shift_x_
204 << ", " << layer_shift_y_ << ") mm";
205 } else {
206 ldmx_log(debug) << "Shifting odd bilayers by (x,y) = (" << layer_shift_x_
207 << ", " << layer_shift_y_ << ") mm";
208 }
209 }
210
211 for (std::size_t i_layer{0}; i_layer < layer_z_positions_.size(); ++i_layer) {
212 // default is centered on z-axis
213 double x{ecal_center_x_}, y{ecal_center_y_},
214 z{ecal_front_z_ + layer_z_positions_.at(i_layer)};
215 const double shift_y{flip_y_ ? -layer_shift_y_ : layer_shift_y_};
216 if (layer_shift_odd_ and (i_layer % 2 == 1)) {
217 x += layer_shift_x_;
218 y += shift_y;
219 } else if (layer_shift_odd_bilayer_ and ((i_layer / 2) % 2 == 1)) {
220 x += layer_shift_x_;
221 y += shift_y;
222 }
223 ldmx_log(trace) << " Layer " << i_layer << " has center at (" << x
224 << ", " << y << ", " << z << ") mm";
225
226 layer_pos_xy_[i_layer] = std::make_tuple(x, y, z);
227 }
228}
229
231 static const double c_pi = 3.14159265358979323846;
232
233 // the center module (module_id == 0) has always been (and will always be?)
234 // centered with respect to the layer position
235 module_pos_xy_[0] = std::pair<double, double>(0., 0.);
236
237 // for flat-side-up designs (v12 and earlier), the modules are numbered 1 on
238 // positive y-axis and then counter-clockwise until 6
239 //
240 // for corner-side-up designes (v13 and later), the modules are numbered 1 on
241 // positive x-axis and then counter-clockwise until 6.
242 for (unsigned id = 1; id < 7; id++) {
243 // flat-side-up
244 double x = (2. * module_r_min_ + gap_) * sin((id - 1) * (c_pi / 3.));
245 double y = (2. * module_r_min_ + gap_) * cos((id - 1) * (c_pi / 3.));
246 if (corners_side_up_) {
247 // re-calculating to make sure centers match GDML
248 x = (2. * module_r_min_ + gap_) * cos((id - 1) * (c_pi / 3.));
249 y = -(2. * module_r_min_ + gap_) * sin((id - 1) * (c_pi / 3.));
250 }
251 module_pos_xy_[id] = std::pair<double, double>(x, y);
252 ldmx_log(trace) << " Module " << id << " is centered at (x,y) = " << "("
253 << x << ", " << y << ") mm";
254 }
255}
256
277 TH2Poly grid_map;
278
279 // make hexagonal grid [boundary is rectangle] larger than the module
280 double grid_min_p = 0., grid_min_q = 0.; // start at the origin
281 int num_p_cells = 0, num_q_cells = 0;
282
283 // first x-cell is only a half
284 grid_min_p -= cell_r_min_;
285 num_p_cells++;
286 while (grid_min_p > -1 * module_r_max_) {
287 // decrement x by cell center-to-flat diameter
288 grid_min_p -= 2 * cell_r_min_;
289 num_p_cells++;
290 }
291 while (grid_min_q > -1 * module_r_min_) {
292 // decrement y by cell center-to-corner radius
293 // alternate between a full corner-to-corner diameter
294 // and a side of a cell (center-to-corner radius)
295 if (num_q_cells % 2 == 0)
296 grid_min_q -= 1 * cell_r_max_;
297 else
298 grid_min_q -= 2 * cell_r_max_;
299 num_q_cells++;
300 }
301 // only counted one half of the cells
302 num_p_cells *= 2;
303 num_q_cells *= 2;
304
305 grid_map.Honeycomb(grid_min_p, grid_min_q, cell_r_max_, num_p_cells,
306 num_q_cells);
307
308 ldmx_log(trace) << std::setprecision(2)
309 << "Building buildCellMap with cell rmin: " << cell_r_min_
310 << " cell rmax: " << cell_r_max_ << " (gridMinP,gridMinQ) = ("
311 << grid_min_p << "," << grid_min_q << ")"
312 << " (numPCells,numQCells) = (" << num_p_cells << ","
313 << num_q_cells << ")";
314
315 // copy cells lying within module boundaries to a module grid
316 TListIter next(grid_map.GetBins()); // a TH2Poly is a TList of TH2PolyBin
317 TH2PolyBin* poly_bin = 0;
318 TGraph* poly = 0; // a polygon returned by TH2Poly is a TGraph
319 // cells_in_module_ IDs go from 0 to N-1, not equal to original grid cell ID
320 int cell_id = 0;
321 while ((poly_bin = (TH2PolyBin*)next())) {
322 // these bins are coming from the honeycomb
323 // grid so we assume that they are regular
324 // hexagons i.e. has 6 vertices
325 poly = (TGraph*)poly_bin->GetPolygon();
326
327 // decide whether to copy polygon to new map.
328 // use all vertices in case of cut-off edge polygons.
329 int num_vertices_inside = 0;
330 double vertex_p[6], vertex_q[6]; // vertices of the cell
331 bool isinside[6]; // which vertices are inside
332 ldmx_log(trace) << " Cell vertices";
333 for (unsigned i = 0; i < 6; i++) {
334 poly->GetPoint(i, vertex_p[i], vertex_q[i]);
335 ldmx_log(trace) << " vtx # " << i;
336 ldmx_log(trace) << " vtx p,q " << vertex_p[i] << " " << vertex_q[i];
337
338 isinside[i] =
339 isInside(vertex_p[i] / module_r_max_, vertex_q[i] / module_r_max_);
340 if (isinside[i]) num_vertices_inside++;
341 }
342
343 if (num_vertices_inside > 1) {
344 // Include this cell if more than one of its vertices is inside the module
345 // hexagon
346 double actual_p[8], actual_q[8];
347 int num_vertices{0};
348 if (num_vertices_inside < 6) {
349 // This cell is stradling the edge of the module
350 // and is NOT cleanly cut by module edge
351
352 ldmx_log(trace) << " Polygon " << cell_id
353 << " has vertices poking out of module hexagon.";
354
355 // loop through vertices
356 for (int i = 0; i < 6; i++) {
357 int up = i == 5 ? 0 : i + 1;
358 int dn = i == 0 ? 5 : i - 1;
359 if (isinside[i] and (not isinside[up] or not isinside[dn])) {
360 // this vertex is inside the module hexagon and is adjacent to a
361 // vertex outside
362 // ==> project this vertex onto the nearest edge of the module
363 // hexagon
364
365 // determine which side of hexagon we should project onto
366 double edge_origin_p, edge_origin_q;
367 double edge_dest_p, edge_dest_q;
368 if (vertex_p[i] < -module_r_max_ / 2.) {
369 // sloped edge on negative-x side
370 edge_origin_p = -1. * module_r_max_;
371 edge_origin_q = 0.;
372 edge_dest_p = -0.5 * module_r_max_;
373 edge_dest_q = module_r_min_;
374 } else if (vertex_p[i] > module_r_max_ / 2.) {
375 // sloped edge on positive-x side
376 edge_origin_p = 0.5 * module_r_max_;
377 edge_origin_q = module_r_min_;
378 edge_dest_p = module_r_max_;
379 edge_dest_q = 0.;
380 } else {
381 // flat edge at top
382 edge_origin_p = 0.5 * module_r_max_;
383 edge_origin_q = module_r_min_;
384 edge_dest_p = -0.5 * module_r_max_;
385 edge_dest_q = module_r_min_;
386 }
387 // flip to bottom half if below x-axis
388 if (vertex_q[i] < 0) {
389 edge_dest_q *= -1;
390 edge_origin_q *= -1;
391 }
392
393 // get edge slope vector
394 double edge_slope_p = edge_dest_p - edge_origin_p;
395 double edge_slope_q = edge_dest_q - edge_origin_q;
396
397 ldmx_log(trace)
398 << "Vertex " << i
399 << " is inside and adjacent to a vertex outside the module.";
400 ldmx_log(trace) << "Working on edge with slope (" << edge_slope_p
401 << "," << edge_slope_q << ")" << " and origin ("
402 << edge_origin_p << "," << edge_origin_q << ")";
403
404 // project vertices adjacent to the vertex outside the module onto
405 // the module edge
406 double projection_factor =
407 ((vertex_p[i] - edge_origin_p) * edge_slope_p +
408 (vertex_q[i] - edge_origin_q) * edge_slope_q) /
409 (edge_slope_p * edge_slope_p + edge_slope_q * edge_slope_q);
410
411 double proj_p = edge_origin_p + projection_factor * edge_slope_p;
412 double proj_q = edge_origin_q + projection_factor * edge_slope_q;
413
414 if (not isinside[up]) {
415 // the next point is outside
416 actual_p[num_vertices] = vertex_p[i];
417 actual_q[num_vertices] = vertex_q[i];
418 actual_p[num_vertices + 1] = proj_p;
419 actual_q[num_vertices + 1] = proj_q;
420 } else {
421 // the previous point was outside
422 actual_p[num_vertices] = proj_p;
423 actual_q[num_vertices] = proj_q;
424 actual_p[num_vertices + 1] = vertex_p[i];
425 actual_q[num_vertices + 1] = vertex_q[i];
426 }
427 num_vertices += 2;
428
429 ldmx_log(trace) << "New Vertex " << i << " : (" << vertex_p[i]
430 << "," << vertex_q[i] << ")";
431
432 } else {
433 actual_p[num_vertices] = vertex_p[i];
434 actual_q[num_vertices] = vertex_q[i];
435 num_vertices++;
436 } // should we project or not
437 } // loop through vertices
438 } else {
439 // all 6 inside, just copy the vertices over
440 num_vertices = 6;
441 for (int i = 0; i < 6; i++) {
442 actual_p[i] = vertex_p[i];
443 actual_q[i] = vertex_q[i];
444 }
445 } // if numVerticesInside is less than 5
446
447 // TH2Poly needs to have its own copy of the polygon TGraph
448 // otherwise, we get a seg fault when EcalGeometry is destructed
449 // because the polygon that was copied over from gridMap is deleted at
450 // the end of this function
451 cell_id_in_module_.AddBin(num_vertices, actual_p, actual_q);
452
456 double p = (poly_bin->GetXMax() + poly_bin->GetXMin()) / 2.;
457 double q = (poly_bin->GetYMax() + poly_bin->GetYMin()) / 2.;
458
459 ldmx_log(trace) << " Copying poly with ID " << poly_bin->GetBinNumber()
460 << " and (p,q) (" << std::setprecision(2) << p << "," << q
461 << ")";
462 // save cell location as center of ENTIRE hexagon
463 cell_pos_in_module_[cell_id] = std::pair<double, double>(p, q);
464 ++cell_id; // incrememnt cell ID
465 } // if num vertices inside is > 1
466 } // loop over larger grid spanning module hexagon
467 return;
468}
469
471 ldmx_log(trace) << "Building cellModule position map";
473 for (auto const& [module_id, module_xy] : module_pos_xy_) {
474 for (auto const& [cell_id, cell_pq] : cell_pos_in_module_) {
475 double cell_x{cell_pq.first}, cell_y{cell_pq.second};
476 // convert from (p,q) to (x,y) space
477 // when the corners are not up, x = p and y = q
478 // so no transformation needs to be done
479 if (corners_side_up_) unrotate(cell_x, cell_y);
480
481 // calculate cell's pq relative to entire layer center
482 auto cell_rel_to_layer =
483 std::make_pair(module_xy.first + cell_x, module_xy.second + cell_y);
484
485 // now add the layer-center values to get the global position
486 // of the cell
487 cell_pos_in_layer_[EcalID(0, module_id, cell_id)] = cell_rel_to_layer;
488 }
489 }
490
492 for (auto const& [layer_id, layer_xyz] : layer_pos_xy_) {
493 for (auto const& [flat_id, rel_to_layer] : cell_pos_in_layer_) {
494 // now add the layer-center values to get the global position
495 // of the cell
496 cell_global_pos_[EcalID(layer_id, flat_id.module(), flat_id.cell())] =
497 std::make_tuple(rel_to_layer.first + std::get<0>(layer_xyz),
498 (flip_y_ ? -1. : 1.) * rel_to_layer.second +
499 std::get<1>(layer_xyz),
500 std::get<2>(layer_xyz));
501 }
502 }
503
504 ldmx_log(trace) << "Cell module map contains " << cell_global_pos_.size()
505 << " entries. ";
506 return;
507}
508
523 ldmx_log(trace) << "Building Nearest and Next-Nearest Neighbor maps";
524
525 nn_map_.clear();
526 nnn_map_.clear();
527 for (auto const& [center_id, center_xyz] : cell_pos_in_layer_) {
528 for (auto const& [probe_id, probe_xyz] : cell_pos_in_layer_) {
530 double dist = distance(probe_xyz, center_xyz);
531 if (dist > 1 * cell_r_min_ && dist <= 3. * cell_r_min_) {
532 nn_map_[center_id].push_back(probe_id);
533 } else if (dist > 3. * cell_r_min_ && dist <= 4.5 * cell_r_min_) {
534 nnn_map_[center_id].push_back(probe_id);
535 }
536 }
537 // Keeping this commented out until the SimIDs string method is implemented
538 // ldmx_log(debug) << " Found " << nn_map_[center_id].size() << " NN and "
539 // << nnn_map_[center_id].size() << " NNN for cell " << center_id;
540 }
541 return;
542}
543
545 // https://math.stackexchange.com/questions/1210572/find-the-distance-to-the-edge-of-a-hexagon
546 std::pair<double, double> cell_location = cell_pos_in_module_.at(id.cell());
547 double x = fabs(cell_location.first); // bring to first quadrant
548 double y = fabs(cell_location.second);
549 double r = sqrt(x * x + y * y);
550 double theta = (r > 1E-3) ? fabs(std::atan(y / x)) : 0;
551 if (x < module_r_max_ / 2.)
552 return (module_r_min_ -
553 y); // closest line is straight vertical to top edge
554 double dist =
555 sqrt(3.) * module_r_max_ / (std::sin(theta) + sqrt(3.) * std::cos(theta));
556 return dist;
557}
558
559bool EcalGeometry::isInside(double normX, double normY) const {
560 ldmx_log(trace) << std::fixed << std::setprecision(2)
561 << "Checking if normXY=(" << normX << "," << normY
562 << ") is inside.";
563 normX = fabs(normX), normY = fabs(normY);
564 double xvec = -1, yvec = -1. / sqrt(3);
565 double xref = 0.5, yref = sqrt(3) / 2.;
566 if ((normX > 1.) || (normY > yref)) {
567 ldmx_log(trace) << "They are outside quadrant.";
568 return false;
569 }
570 double dot_prod = (xvec * (normX - xref) + yvec * (normY - yref));
571 ldmx_log(trace) << std::fixed << std::setprecision(2)
572 << "They are inside quadrant. Dot product (>0 is inside): "
573 << dot_prod;
574 return (dot_prod > 0.);
575}
576
577} // namespace ldmx
Class that translates raw positions of ECal module hits into cells in a hexagonal readout.
Class encapsulating parameters for configuring a processor.
Definition Parameters.h:26
const T & get(const std::string &name) const
Retrieve the parameter of the given name.
Definition Parameters.h:75
Translation between real-space positions and cell IDs within the ECal.
std::map< EcalID, std::tuple< double, double, double > > cell_global_pos_
Position of cell centers relative to world geometry.
std::map< EcalID, std::vector< EcalID > > nnn_map_
Map of cell ID to neighbors of neighbor cells.
EcalID getID(double x, double y, double z, bool fallible=false) const
Get a cell's ID number from its position.
std::tuple< double, double, double > getPosition(EcalID id) const
Get a cell's position from its ID number.
void buildCellModuleMap()
Constructs the positions of all the cells in a layer relative to the ecal center.
double layer_shift_y_
shift of layers in the y-direction [mm]
double distanceToEdge(EcalID id) const
Distance to module edge, and whether cell is on edge of module.
std::pair< double, double > getPositionInModule(int cell_id) const
Get a cell's position within a module.
double ecal_center_x_
World x of the layer centers [mm].
std::map< int, std::pair< double, double > > module_pos_xy_
Postion of module centers relative to the center of the layer in world coordinates.
void buildCellMap()
Constructs the flat-bottomed hexagonal grid (cellID) of corner-down hexagonal cells.
bool layer_shift_odd_
shift odd layers
double module_r_max_
Center-to-Corner Radius of module hexagon [mm].
double cell_r_min_
Center-to-Flat Radius of cell hexagon [mm].
std::map< int, std::tuple< double, double, double > > layer_pos_xy_
Position of layer centers in world coordinates (uses layer ID as key)
double n_cell_r_height_
Number of cell center-to-corner radii (one side of the cell) from the bottom to the top of the module...
std::map< int, std::pair< double, double > > cell_pos_in_module_
Position of cell centers relative to center of module in p,q space.
double layer_shift_x_
shift of layers in the x-direction [mm]
void buildModuleMap()
Constructs the positions of the seven modules (moduleID) relative to the ecal center.
std::map< EcalID, std::pair< double, double > > cell_pos_in_layer_
Position of cell centers relative to center of layer in world coordinates.
std::map< EcalID, std::vector< EcalID > > nn_map_
Map of cell ID to neighboring cells.
std::vector< double > layer_z_positions_
The layer Z postions are with respect to the front of the ECal [mm].
bool isInside(double normX, double normY) const
Determines if point (x,y), already normed to max hexagon radius, lies within a hexagon.
double si_thickness_
Thickness of the Si sensitive layer [mm].
bool layer_shift_odd_bilayer_
shift odd bi layers
double ecal_center_y_
World y of the layer centers [mm].
void buildLayerMap()
Constructs the positions of the layers in world coordinates.
EcalGeometry(const framework::config::Parameters &ps)
Class constructor, for use only by the provider.
double cell_r_max_
Center-to-Corner Radius of cell hexagon [mm].
bool flip_y_
ECal y axis points along world -y, e.g. rotated about x by 180 deg.
double ecal_front_z_
Front of ECal relative to world geometry [mm].
double gap_
Gap between module flat sides [mm].
double module_r_min_
Center-to-Flat Radius of module hexagon [mm].
TH2Poly cell_id_in_module_
Honeycomb Binning from ROOT.
void buildNeighborMaps()
Construts NNMap and NNNMap.
bool corners_side_up_
indicator of geometry orientation if true, flower shape's corners side (ie: side with two modules) is...
Extension of DetectorID providing access to ECal layers and cell numbers in a hex grid.
Definition EcalID.h:20
All classes in the ldmx-sw project use this namespace.