8#include "TGeoPolygon.h"
12#include "TMultiGraph.h"
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));
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)));
36static void rotate(
double& p,
double& q) {
45static void unrotate(
double& p,
double& q) {
66 EXCEPTION_RAISE(
"BadConf",
67 "Cannot shift both odd sensitive layers and odd bilayers");
75 std::cout << std::endl
76 <<
"[EcalGeometry] Verbosity set in header to " <<
verbose_
78 std::cout <<
" Building module map with gap " << std::setprecision(2)
80 <<
", min/max radii of cell " <<
cellr_ <<
" / " <<
cellR_
91 std::cout <<
"[EcalGeometry] : fully constructed" << std::endl;
95 static const double tolerance = 0.3;
98 if (abs(std::get<2>(layer_xyz) - z) < tolerance) {
107 EXCEPTION_RAISE(
"BadConf",
"z = " + std::to_string(z) +
108 " mm is not within any"
109 " of the configured layers.");
112 return getID(x, y, layer_id, fallible);
116 bool fallible)
const {
129 double probe_x{p - module_xy.first}, probe_y{q - module_xy.second};
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)
152 return getID(x, y, layer_id, module_id);
156 bool fallible)
const {
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)
185 return EcalID(layer_id, module_id, cell_id);
203 std::cout <<
"[EcalGeometry::buildLayerMap] "
205 <<
" layers" << std::endl;
208 std::cout <<
" shifting odd ";
210 std::cout <<
"layers";
212 std::cout <<
"bilayers";
214 <<
") mm" << std::endl;
216 std::cout <<
" without any shifting" << std::endl;
219 for (std::size_t i_layer{0}; i_layer <
layerZPositions_.size(); ++i_layer) {
230 std::cout <<
" Layer " << i_layer <<
" has center at (" << x <<
", "
231 << y <<
", " << z <<
") mm" << std::endl;
239 3.14159265358979323846;
241 std::cout <<
"[EcalGeometry::buildModuleMap] "
242 <<
"Building module position map for module min r of " <<
moduler_
243 <<
" and gap of " <<
gap_ << std::endl;
255 for (
unsigned id = 1;
id < 7;
id++) {
257 double x = (2. *
moduler_ +
gap_) * sin((
id - 1) * (C_PI / 3.));
258 double y = (2. *
moduler_ +
gap_) * cos((
id - 1) * (C_PI / 3.));
261 x = (2. *
moduler_ +
gap_) * cos((
id - 1) * (C_PI / 3.));
262 y = -(2. *
moduler_ +
gap_) * sin((
id - 1) * (C_PI / 3.));
266 std::cout <<
" Module " <<
id <<
" is centered at (x,y) = "
267 <<
"(" << x <<
", " << y <<
") mm" << std::endl;
294 double gridMinP = 0., gridMinQ = 0.;
295 int numPCells = 0, numQCells = 0;
308 if (numQCells % 2 == 0)
318 gridMap.Honeycomb(gridMinP, gridMinQ,
cellR_, numPCells, numQCells);
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
330 TListIter next(gridMap.GetBins());
331 TH2PolyBin* polyBin = 0;
335 while ((polyBin = (TH2PolyBin*)next())) {
339 poly = (TGraph*)polyBin->GetPolygon();
343 int numVerticesInside = 0;
344 double vertex_p[6], vertex_q[6];
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]);
350 std::cout <<
" vtx # " << i << std::endl;
351 std::cout <<
" vtx p,q " << vertex_p[i] <<
" " << vertex_q[i]
355 if (isinside[i]) numVerticesInside++;
358 if (numVerticesInside > 1) {
361 double actual_p[8], actual_q[8];
363 if (numVerticesInside < 6) {
368 std::cout <<
" Polygon " << cell_id
369 <<
" has vertices poking out of module hexagon."
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])) {
384 double edge_origin_p, edge_origin_q;
385 double edge_dest_p, edge_dest_q;
392 }
else if (vertex_p[i] >
moduleR_ / 2.) {
406 if (vertex_q[i] < 0) {
412 double edge_slope_p = edge_dest_p - edge_origin_p;
413 double edge_slope_q = edge_dest_q - edge_origin_q;
418 <<
" is inside and adjacent to a vertex outside the module."
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;
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);
433 double proj_p = edge_origin_p + projection_factor * edge_slope_p;
434 double proj_q = edge_origin_q + projection_factor * edge_slope_q;
436 if (not isinside[up]) {
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;
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];
452 std::cout <<
"New Vertex " << i <<
" : (" << vertex_p[i] <<
","
453 << vertex_q[i] <<
")" << std::endl;
456 actual_p[num_vertices] = vertex_p[i];
457 actual_q[num_vertices] = vertex_q[i];
464 for (
int i = 0; i < 6; i++) {
465 actual_p[i] = vertex_p[i];
466 actual_q[i] = vertex_q[i];
479 double p = (polyBin->GetXMax() + polyBin->GetXMin()) / 2.;
480 double q = (polyBin->GetYMax() + polyBin->GetYMin()) / 2.;
482 std::cout <<
" Copying poly with ID " << polyBin->GetBinNumber()
483 <<
" and (p,q) (" << std::setprecision(2) << p <<
"," << q
497 <<
"[EcalGeometry::buildCellModuleMap] Building cellModule position map"
502 double cell_x{cell_pq.first}, cell_y{cell_pq.second};
509 auto cell_rel_to_layer =
510 std::make_pair(module_xy.first + cell_x, module_xy.second + cell_y);
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));
551 std::cout <<
"[EcalGeometry::buildNeighborMaps] : "
552 <<
"Building Nearest and Next-Nearest Neighbor maps" << std::endl;
559 double dist = distance(probe_xyz, center_xyz);
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);
567 std::cout <<
" Found " <<
NNMap_[center_id].size() <<
" NN and "
568 <<
NNNMap_[center_id].size() <<
" NNN for cell " << center_id
611 double x = fabs(cellLocation.first);
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;
618 sqrt(3.) *
moduleR_ / (std::sin(theta) + sqrt(3.) * std::cos(theta));
624 std::cout << TString::Format(
625 "[isInside] Checking if normXY=(%.2f,%.2f) is inside.",
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)) {
633 std::cout <<
"[isInside] they are outside quadrant." << std::endl;
636 double dotProd = (xvec * (normX - xref) + yvec * (normY - yref));
638 std::cout << TString::Format(
639 "[isInside] they are inside quadrant. Dot product (>0 is "
643 return (dotProd > 0.);
Class that translates raw positions of ECal module hits into cells in a hexagonal readout.
Class encapsulating parameters for configuring a processor.
T getParameter(const std::string &name) const
Retrieve the parameter of the given name.
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.
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.
All classes in the ldmx-sw project use this namespace.