LDMX Software
EcalGeometry.cxx
2
3#include <assert.h>
4
5#include <iomanip>
6#include <iostream>
7
8#include "TGeoPolygon.h"
9#include "TGraph.h"
10#include "TList.h"
11#include "TMath.h"
12#include "TMultiGraph.h"
13
14namespace ldmx {
15
16static double distance(const std::pair<double, double>& p1,
17 const std::pair<double, double>& p2) {
18 return sqrt((p1.first - p2.first) * (p1.first - p2.first) +
19 (p1.second - p2.second) * (p1.second - p2.second));
20}
21
22[[maybe_unused]] static double distance(
23 const std::tuple<double, double, double>& p1,
24 const std::tuple<double, double, double>& p2) {
25 return sqrt((std::get<0>(p1) - std::get<0>(p2)) *
26 (std::get<0>(p1) - std::get<0>(p2)) +
27 (std::get<1>(p1) - std::get<1>(p2)) *
28 (std::get<1>(p1) - std::get<1>(p2)) +
29 (std::get<2>(p1) - std::get<2>(p2)) *
30 (std::get<2>(p1) - std::get<2>(p2)));
31}
32
36static void rotate(double& p, double& q) {
37 double tmp{p};
38 p = -q;
39 q = tmp;
40}
41
45static void unrotate(double& p, double& q) {
46 double tmp{p};
47 p = q;
48 q = -tmp;
49}
50
52 : framework::ConditionsObject(EcalGeometry::CONDITIONS_OBJECT_NAME) {
53 layerZPositions_ = ps.getParameter<std::vector<double>>("layerZPositions");
54 ecalFrontZ_ = ps.getParameter<double>("ecalFrontZ");
55 moduler_ = ps.getParameter<double>("moduleMinR");
56 gap_ = ps.getParameter<double>("gap");
57 nCellRHeight_ = ps.getParameter<double>("nCellRHeight");
58 verbose_ = ps.getParameter<int>("verbose");
59 cornersSideUp_ = ps.getParameter<bool>("cornersSideUp");
60 layer_shift_x_ = ps.getParameter<double>("layer_shift_x");
61 layer_shift_y_ = ps.getParameter<double>("layer_shift_y");
62 layer_shift_odd_ = ps.getParameter<bool>("layer_shift_odd");
63 layer_shift_odd_bilayer_ = ps.getParameter<bool>("layer_shift_odd_bilayer");
64
66 EXCEPTION_RAISE("BadConf",
67 "Cannot shift both odd sensitive layers and odd bilayers");
68 }
69
70 moduleR_ = moduler_ * (2 / sqrt(3));
72 cellr_ = (sqrt(3.) / 2.) * cellR_;
73
74 if (verbose_ > 0) {
75 std::cout << std::endl
76 << "[EcalGeometry] Verbosity set in header to " << verbose_
77 << std::endl;
78 std::cout << " Building module map with gap " << std::setprecision(2)
79 << gap_ << ", nCellRHeight " << nCellRHeight_
80 << ", min/max radii of cell " << cellr_ << " / " << cellR_
81 << ", and module " << moduler_ << " / " << moduleR_ << std::endl;
82 }
83
89
90 if (verbose_ > 0)
91 std::cout << "[EcalGeometry] : fully constructed" << std::endl;
92}
93
94EcalID EcalGeometry::getID(double x, double y, double z, bool fallible) const {
95 static const double tolerance = 0.3; // thickness of Si
96 int layer_id{-1};
97 for (const auto& [lid, layer_xyz] : layer_pos_xy_) {
98 if (abs(std::get<2>(layer_xyz) - z) < tolerance) {
99 layer_id = lid;
100 break;
101 }
102 }
103 if (layer_id < 0) {
104 if (fallible) {
105 return ldmx::EcalID(0);
106 } else {
107 EXCEPTION_RAISE("BadConf", "z = " + std::to_string(z) +
108 " mm is not within any"
109 " of the configured layers.");
110 }
111 }
112 return getID(x, y, layer_id, fallible);
113}
114
115EcalID EcalGeometry::getID(double x, double y, int layer_id,
116 bool fallible) const {
117 // now assume we know the layer
118 // shift to center of layer
119 // and convert to flower coordinates
120 double p{x - std::get<0>(layer_pos_xy_.at(layer_id))},
121 q{y - std::get<1>(layer_pos_xy_.at(layer_id))};
122
123 // deduce module ID
124 // there are only 7 modules so we just loop through them
125 // all and pick out the module ID that we are inside of
126
127 int module_id{-1};
128 for (auto const& [mid, module_xy] : module_pos_xy_) {
129 double probe_x{p - module_xy.first}, probe_y{q - module_xy.second};
130 if (cornersSideUp_) rotate(probe_x, probe_y);
131 if (isInside(probe_x / moduleR_, probe_y / moduleR_)) {
132 module_id = mid;
133 break;
134 }
135 }
136
137 if (module_id < 0) {
138 if (fallible) {
139 return ldmx::EcalID(0);
140 } else {
141 EXCEPTION_RAISE(
142 "BadConf",
143 TString::Format(
144 "Coordinates relative to layer (p,q) = (%.2f, %.2f) mm "
145 "derived from world coordinates (%.2f, %.2f) mm with layer = %d "
146 "are not inside any module.",
147 p, q, x, y, layer_id)
148 .Data());
149 }
150 }
151
152 return getID(x, y, layer_id, module_id);
153}
154
155EcalID EcalGeometry::getID(double x, double y, int layer_id, int module_id,
156 bool fallible) const {
157 // now assume we know the layer and module
158 // shift to center of layer and then center of module
159 double p{x - std::get<0>(layer_pos_xy_.at(layer_id)) -
160 module_pos_xy_.at(module_id).first},
161 q{y - std::get<1>(layer_pos_xy_.at(layer_id)) -
162 module_pos_xy_.at(module_id).second};
163
164 // need to rotate
165 if (cornersSideUp_) rotate(p, q);
166
167 // deduce cell ID
168 int cell_id = cell_id_in_module_.FindBin(p, q) - 1;
169
170 if (cell_id < 0) {
171 if (fallible) {
172 return ldmx::EcalID(0);
173 } else {
174 EXCEPTION_RAISE(
175 "BadConf",
176 TString::Format(
177 "Relative cell coordinates (%.2f, %.2f) mm "
178 "derived from world coordinates (%.2f, %.2f) mm with layer = %d "
179 "and module = %d are outside module hexagon",
180 p, q, x, y, layer_id, module_id)
181 .Data());
182 }
183 }
184
185 return EcalID(layer_id, module_id, cell_id);
186}
187
188std::tuple<double, double, double> EcalGeometry::getPosition(EcalID id) const {
189 return cell_global_pos_.at(id);
190}
191
192std::pair<double, double> EcalGeometry::getPositionInModule(int cell_id) const {
193 auto pq = cell_pos_in_module_.at(cell_id);
194
195 // going from (p,q) to (x,y) is a unrotate
196 if (cornersSideUp_) unrotate(pq.first, pq.second);
197
198 return pq;
199}
200
202 if (verbose_ > 0) {
203 std::cout << "[EcalGeometry::buildLayerMap] "
204 << " Building layer map with " << layerZPositions_.size()
205 << " layers" << std::endl;
206 ;
208 std::cout << " shifting odd ";
210 std::cout << "layers";
211 else
212 std::cout << "bilayers";
213 std::cout << " by (x,y) = (" << layer_shift_x_ << ", " << layer_shift_y_
214 << ") mm" << std::endl;
215 } else {
216 std::cout << " without any shifting" << std::endl;
217 }
218 }
219 for (std::size_t i_layer{0}; i_layer < layerZPositions_.size(); ++i_layer) {
220 // default is centered on z-axis
221 double x{0}, y{0}, z{ecalFrontZ_ + layerZPositions_.at(i_layer)};
222 if (layer_shift_odd_ and (i_layer % 2 == 1)) {
223 x += layer_shift_x_;
224 y += layer_shift_y_;
225 } else if (layer_shift_odd_bilayer_ and ((i_layer / 2) % 2 == 1)) {
226 x += layer_shift_x_;
227 y += layer_shift_y_;
228 }
229 if (verbose_ > 2) {
230 std::cout << " Layer " << i_layer << " has center at (" << x << ", "
231 << y << ", " << z << ") mm" << std::endl;
232 }
233 layer_pos_xy_[i_layer] = std::make_tuple(x, y, z);
234 }
235}
236
238 static double C_PI =
239 3.14159265358979323846; // or TMath::Pi(), #define, atan(), ...
240 if (verbose_ > 0) {
241 std::cout << "[EcalGeometry::buildModuleMap] "
242 << "Building module position map for module min r of " << moduler_
243 << " and gap of " << gap_ << std::endl;
244 }
245
246 // the center module (module_id == 0) has always been (and will always be?)
247 // centered with respect to the layer position
248 module_pos_xy_[0] = std::pair<double, double>(0., 0.);
249
250 // for flat-side-up designs (v12 and earlier), the modules are numbered 1 on
251 // positive y-axis and then counter-clockwise until 6
252 //
253 // for corner-side-up designes (v13 and later), the modules are numbered 1 on
254 // positive x-axis and then counter-clockwise until 6.
255 for (unsigned id = 1; id < 7; id++) {
256 // flat-side-up
257 double x = (2. * moduler_ + gap_) * sin((id - 1) * (C_PI / 3.));
258 double y = (2. * moduler_ + gap_) * cos((id - 1) * (C_PI / 3.));
259 if (cornersSideUp_) {
260 // re-calculating to make sure centers match GDML
261 x = (2. * moduler_ + gap_) * cos((id - 1) * (C_PI / 3.));
262 y = -(2. * moduler_ + gap_) * sin((id - 1) * (C_PI / 3.));
263 }
264 module_pos_xy_[id] = std::pair<double, double>(x, y);
265 if (verbose_ > 2)
266 std::cout << " Module " << id << " is centered at (x,y) = "
267 << "(" << x << ", " << y << ") mm" << std::endl;
268 }
269}
270
291 TH2Poly gridMap;
292
293 // make hexagonal grid [boundary is rectangle] larger than the module
294 double gridMinP = 0., gridMinQ = 0.; // start at the origin
295 int numPCells = 0, numQCells = 0;
296
297 // first x-cell is only a half
298 gridMinP -= cellr_;
299 numPCells++;
300 while (gridMinP > -1 * moduleR_) {
301 gridMinP -= 2 * cellr_; // decrement x by cell center-to-flat diameter
302 numPCells++;
303 }
304 while (gridMinQ > -1 * moduler_) {
305 // decrement y by cell center-to-corner radius
306 // alternate between a full corner-to-corner diameter
307 // and a side of a cell (center-to-corner radius)
308 if (numQCells % 2 == 0)
309 gridMinQ -= 1 * cellR_;
310 else
311 gridMinQ -= 2 * cellR_;
312 numQCells++;
313 }
314 // only counted one half of the cells
315 numPCells *= 2;
316 numQCells *= 2;
317
318 gridMap.Honeycomb(gridMinP, gridMinQ, cellR_, numPCells, numQCells);
319
320 if (verbose_ > 0) {
321 std::cout << std::setprecision(2)
322 << "[EcalGeometry::buildCellMap] cell rmin: " << cellr_
323 << " cell rmax: " << cellR_ << " (gridMinP,gridMinQ) = ("
324 << gridMinP << "," << gridMinQ << ")"
325 << " (numPCells,numQCells) = (" << numPCells << "," << numQCells
326 << ")" << std::endl;
327 }
328
329 // copy cells lying within module boundaries to a module grid
330 TListIter next(gridMap.GetBins()); // a TH2Poly is a TList of TH2PolyBin
331 TH2PolyBin* polyBin = 0;
332 TGraph* poly = 0; // a polygon returned by TH2Poly is a TGraph
333 // cells_in_module_ IDs go from 0 to N-1, not equal to original grid cell ID
334 int cell_id = 0;
335 while ((polyBin = (TH2PolyBin*)next())) {
336 // these bins are coming from the honeycomb
337 // grid so we assume that they are regular
338 // hexagons i.e. has 6 vertices
339 poly = (TGraph*)polyBin->GetPolygon();
340
341 // decide whether to copy polygon to new map.
342 // use all vertices in case of cut-off edge polygons.
343 int numVerticesInside = 0;
344 double vertex_p[6], vertex_q[6]; // vertices of the cell
345 bool isinside[6]; // which vertices are inside
346 if (verbose_ > 2) std::cout << " Cell vertices" << std::endl;
347 for (unsigned i = 0; i < 6; i++) {
348 poly->GetPoint(i, vertex_p[i], vertex_q[i]);
349 if (verbose_ > 2) {
350 std::cout << " vtx # " << i << std::endl;
351 std::cout << " vtx p,q " << vertex_p[i] << " " << vertex_q[i]
352 << std::endl;
353 }
354 isinside[i] = isInside(vertex_p[i] / moduleR_, vertex_q[i] / moduleR_);
355 if (isinside[i]) numVerticesInside++;
356 }
357
358 if (numVerticesInside > 1) {
359 // Include this cell if more than one of its vertices is inside the module
360 // hexagon
361 double actual_p[8], actual_q[8];
362 int num_vertices{0};
363 if (numVerticesInside < 6) {
364 // This cell is stradling the edge of the module
365 // and is NOT cleanly cut by module edge
366
367 if (verbose_ > 1) {
368 std::cout << " Polygon " << cell_id
369 << " has vertices poking out of module hexagon."
370 << std::endl;
371 }
372
373 // loop through vertices
374 for (int i = 0; i < 6; i++) {
375 int up = i == 5 ? 0 : i + 1;
376 int dn = i == 0 ? 5 : i - 1;
377 if (isinside[i] and (not isinside[up] or not isinside[dn])) {
378 // this vertex is inside the module hexagon and is adjacent to a
379 // vertex outside
380 // ==> project this vertex onto the nearest edge of the module
381 // hexagon
382
383 // determine which side of hexagon we should project onto
384 double edge_origin_p, edge_origin_q;
385 double edge_dest_p, edge_dest_q;
386 if (vertex_p[i] < -moduleR_ / 2.) {
387 // sloped edge on negative-x side
388 edge_origin_p = -1. * moduleR_;
389 edge_origin_q = 0.;
390 edge_dest_p = -0.5 * moduleR_;
391 edge_dest_q = moduler_;
392 } else if (vertex_p[i] > moduleR_ / 2.) {
393 // sloped edge on positive-x side
394 edge_origin_p = 0.5 * moduleR_;
395 edge_origin_q = moduler_;
396 edge_dest_p = moduleR_;
397 edge_dest_q = 0.;
398 } else {
399 // flat edge at top
400 edge_origin_p = 0.5 * moduleR_;
401 edge_origin_q = moduler_;
402 edge_dest_p = -0.5 * moduleR_;
403 edge_dest_q = moduler_;
404 }
405 // flip to bottom half if below x-axis
406 if (vertex_q[i] < 0) {
407 edge_dest_q *= -1;
408 edge_origin_q *= -1;
409 }
410
411 // get edge slope vector
412 double edge_slope_p = edge_dest_p - edge_origin_p;
413 double edge_slope_q = edge_dest_q - edge_origin_q;
414
415 if (verbose_ > 2) {
416 std::cout
417 << "Vertex " << i
418 << " is inside and adjacent to a vertex outside the module."
419 << std::endl;
420 std::cout << "Working on edge with slope (" << edge_slope_p << ","
421 << edge_slope_q << ")"
422 << " and origin (" << edge_origin_p << ","
423 << edge_origin_q << ")" << std::endl;
424 }
425
426 // project vertices adjacent to the vertex outside the module onto
427 // the module edge
428 double projection_factor =
429 ((vertex_p[i] - edge_origin_p) * edge_slope_p +
430 (vertex_q[i] - edge_origin_q) * edge_slope_q) /
431 (edge_slope_p * edge_slope_p + edge_slope_q * edge_slope_q);
432
433 double proj_p = edge_origin_p + projection_factor * edge_slope_p;
434 double proj_q = edge_origin_q + projection_factor * edge_slope_q;
435
436 if (not isinside[up]) {
437 // the next point is outside
438 actual_p[num_vertices] = vertex_p[i];
439 actual_q[num_vertices] = vertex_q[i];
440 actual_p[num_vertices + 1] = proj_p;
441 actual_q[num_vertices + 1] = proj_q;
442 } else {
443 // the previous point was outside
444 actual_p[num_vertices] = proj_p;
445 actual_q[num_vertices] = proj_q;
446 actual_p[num_vertices + 1] = vertex_p[i];
447 actual_q[num_vertices + 1] = vertex_q[i];
448 }
449 num_vertices += 2;
450
451 if (verbose_ > 2) {
452 std::cout << "New Vertex " << i << " : (" << vertex_p[i] << ","
453 << vertex_q[i] << ")" << std::endl;
454 }
455 } else {
456 actual_p[num_vertices] = vertex_p[i];
457 actual_q[num_vertices] = vertex_q[i];
458 num_vertices++;
459 } // should we project or not
460 } // loop through vertices
461 } else {
462 // all 6 inside, just copy the vertices over
463 num_vertices = 6;
464 for (int i = 0; i < 6; i++) {
465 actual_p[i] = vertex_p[i];
466 actual_q[i] = vertex_q[i];
467 }
468 } // if numVerticesInside is less than 5
469
470 // TH2Poly needs to have its own copy of the polygon TGraph
471 // otherwise, we get a seg fault when EcalGeometry is destructed
472 // because the polygon that was copied over from gridMap is deleted at
473 // the end of this function
474 cell_id_in_module_.AddBin(num_vertices, actual_p, actual_q);
475
479 double p = (polyBin->GetXMax() + polyBin->GetXMin()) / 2.;
480 double q = (polyBin->GetYMax() + polyBin->GetYMin()) / 2.;
481 if (verbose_ > 1) {
482 std::cout << " Copying poly with ID " << polyBin->GetBinNumber()
483 << " and (p,q) (" << std::setprecision(2) << p << "," << q
484 << ")" << std::endl;
485 }
486 // save cell location as center of ENTIRE hexagon
487 cell_pos_in_module_[cell_id] = std::pair<double, double>(p, q);
488 ++cell_id; // incrememnt cell ID
489 } // if num vertices inside is > 1
490 } // loop over larger grid spanning module hexagon
491 return;
492}
493
495 if (verbose_ > 0)
496 std::cout
497 << "[EcalGeometry::buildCellModuleMap] Building cellModule position map"
498 << std::endl;
500 for (auto const& [module_id, module_xy] : module_pos_xy_) {
501 for (auto const& [cell_id, cell_pq] : cell_pos_in_module_) {
502 double cell_x{cell_pq.first}, cell_y{cell_pq.second};
503 // convert from (p,q) to (x,y) space
504 // when the corners are not up, x = p and y = q
505 // so no transformation needs to be done
506 if (cornersSideUp_) unrotate(cell_x, cell_y);
507
508 // calculate cell's pq relative to entire layer center
509 auto cell_rel_to_layer =
510 std::make_pair(module_xy.first + cell_x, module_xy.second + cell_y);
511
512 // now add the layer-center values to get the global position
513 // of the cell
514 cell_pos_in_layer_[EcalID(0, module_id, cell_id)] = cell_rel_to_layer;
515 }
516 }
517
519 for (auto const& [layer_id, layer_xyz] : layer_pos_xy_) {
520 for (auto const& [flat_id, rel_to_layer] : cell_pos_in_layer_) {
521 // now add the layer-center values to get the global position
522 // of the cell
523 cell_global_pos_[EcalID(layer_id, flat_id.module(), flat_id.cell())] =
524 std::make_tuple(rel_to_layer.first + std::get<0>(layer_xyz),
525 rel_to_layer.second + std::get<1>(layer_xyz),
526 std::get<2>(layer_xyz));
527 }
528 }
529
530 if (verbose_ > 0)
531 std::cout << " contained " << cell_global_pos_.size() << " entries. "
532 << std::endl;
533 return;
534}
535
550 if (verbose_ > 0)
551 std::cout << "[EcalGeometry::buildNeighborMaps] : "
552 << "Building Nearest and Next-Nearest Neighbor maps" << std::endl;
553
554 NNMap_.clear();
555 NNNMap_.clear();
556 for (auto const& [center_id, center_xyz] : cell_pos_in_layer_) {
557 for (auto const& [probe_id, probe_xyz] : cell_pos_in_layer_) {
559 double dist = distance(probe_xyz, center_xyz);
560 if (dist > 1 * cellr_ && dist <= 3. * cellr_) {
561 NNMap_[center_id].push_back(probe_id);
562 } else if (dist > 3. * cellr_ && dist <= 4.5 * cellr_) {
563 NNNMap_[center_id].push_back(probe_id);
564 }
565 }
566 if (verbose_ > 1)
567 std::cout << " Found " << NNMap_[center_id].size() << " NN and "
568 << NNNMap_[center_id].size() << " NNN for cell " << center_id
569 << std::endl;
570 }
571 /*
572 * DEBUG CHECK HERE
573 * this is double checking that NN and NNN can cross modules
574 if (verbose_ > 2) {
575 double specialX =
576 0.5 * moduleR_ - 0.5 * cellr_; // center of cell which is upper-right
577 // corner of center module
578 double specialY = moduler_ - 0.5 * cellR_;
579 EcalID specialCellModuleID = getCellModuleID(specialX, specialY);
580 std::cout << "The neighbors of the bin in the upper-right corner of the "
581 "center module, with cellModuleID "
582 << specialCellModuleID << " include " << std::endl;
583 for (auto centerNN : NNMap_.at(specialCellModuleID)) {
584 std::cout << " NN " << centerNN
585 << TString::Format(" (x,y) (%.2f, %.2f)",
586 getCellCenterAbsolute(centerNN).first,
587 getCellCenterAbsolute(centerNN).second)
588 << std::endl;
589 }
590 for (auto centerNNN : NNNMap_.at(specialCellModuleID)) {
591 std::cout << " NNN " << centerNNN
592 << TString::Format(" (x,y) (%.2f, %.2f)",
593 getCellCenterAbsolute(centerNNN).first,
594 getCellCenterAbsolute(centerNNN).second)
595 << std::endl;
596 }
597 std::cout << TString::Format(
598 "This bin is a distance of %.2f away from a module edge. "
599 "Decision isEdge %d.",
600 distanceToEdge(specialCellModuleID),
601 isEdgeCell(specialCellModuleID))
602 << std::endl;
603 }
604 */
605 return;
606}
607
609 // https://math.stackexchange.com/questions/1210572/find-the-distance-to-the-edge-of-a-hexagon
610 std::pair<double, double> cellLocation = cell_pos_in_module_.at(id.cell());
611 double x = fabs(cellLocation.first); // bring to first quadrant
612 double y = fabs(cellLocation.second);
613 double r = sqrt(x * x + y * y);
614 double theta = (r > 1E-3) ? fabs(std::atan(y / x)) : 0;
615 if (x < moduleR_ / 2.)
616 return (moduler_ - y); // closest line is straight vertical to top edge
617 double dist =
618 sqrt(3.) * moduleR_ / (std::sin(theta) + sqrt(3.) * std::cos(theta));
619 return dist;
620}
621
622bool EcalGeometry::isInside(double normX, double normY) const {
623 if (verbose_ > 2)
624 std::cout << TString::Format(
625 "[isInside] Checking if normXY=(%.2f,%.2f) is inside.",
626 normX, normY)
627 << std::endl;
628 normX = fabs(normX), normY = fabs(normY);
629 double xvec = -1, yvec = -1. / sqrt(3);
630 double xref = 0.5, yref = sqrt(3) / 2.;
631 if ((normX > 1.) || (normY > yref)) {
632 if (verbose_ > 2)
633 std::cout << "[isInside] they are outside quadrant." << std::endl;
634 return false;
635 }
636 double dotProd = (xvec * (normX - xref) + yvec * (normY - yref));
637 if (verbose_ > 2)
638 std::cout << TString::Format(
639 "[isInside] they are inside quadrant. Dot product (>0 is "
640 "inside): %.2f ",
641 dotProd)
642 << std::endl;
643 return (dotProd > 0.);
644}
645
646} // 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:27
T getParameter(const std::string &name) const
Retrieve the parameter of the given name.
Definition Parameters.h:89
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 > > NNNMap_
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.
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.
double moduler_
Center-to-Flat Radius of module hexagon [mm].
double cellr_
Center-to-Flat Radius of cell hexagon [mm].
bool layer_shift_odd_
shift odd layers
std::vector< double > layerZPositions_
The layer Z postions are with respect to the front of the ECal [mm].
double nCellRHeight_
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::tuple< double, double, double > > layer_pos_xy_
Position of layer centers in world coordinates (uses layer ID as key)
double ecalFrontZ_
Front of ECal relative to world geometry [mm].
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]
double cellR_
Center-to-Corner Radius of cell hexagon [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.
int verbose_
verbosity
bool isInside(double normX, double normY) const
Determines if point (x,y), already normed to max hexagon radius, lies within a hexagon.
bool layer_shift_odd_bilayer_
shift odd bi layers
bool cornersSideUp_
indicator of geometry orientation if true, flower shape's corners side (ie: side with two modules) is...
void buildLayerMap()
Constructs the positions of the layers in world coordinates.
std::map< EcalID, std::vector< EcalID > > NNMap_
Map of cell ID to neighboring cells.
double moduleR_
Center-to-Corner Radius of module hexagon [mm].
EcalGeometry(const framework::config::Parameters &ps)
Class constructor, for use only by the provider.
double gap_
Gap between module flat sides [mm].
TH2Poly cell_id_in_module_
Honeycomb Binning from ROOT.
void buildNeighborMaps()
Construts NNMap and NNNMap.
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.
Definition PerfDict.cxx:45