5#define M_PI 3.14159265358979323846
16static double g_OFFSET_EXP = 40.0 * (
M_PI / 180.0);
17static std::vector<double> g_DELTAS = { 1.267, 1.420 + (18.0 *
M_PI / 180.0), 0.0, 0.0, 0.0, 0.0 };
18static bool g_GeometryDirty =
true;
19static std::vector<CylinderConfig> g_Cylinders;
22static double g_RotX = 0.0;
23static double g_RotY = 0.0;
24static double g_RotZ = 0.0;
26static double g_R[3][3] = { { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 } };
27static bool g_IsRotated =
false;
30static double g_TransX = 0.0;
31static double g_TransY = 0.0;
32static double g_TransZ = 0.0;
35static std::vector<int> g_ActiveCylinders;
37static const std::map<int, int> BOARD_OFFSETS = {
46static const std::map<int, std::map<int, int>> BOARD_MAPS = {
48 { { 31, 0 }, { 27, 1 }, { 23, 2 }, { 19, 3 }, { 15, 4 }, { 11, 5 }, { 7, 6 }, { 3, 7 },
49 { 29, 8 }, { 25, 9 }, { 21, 10 }, { 17, 11 }, { 13, 12 }, { 9, 13 }, { 5, 14 },
50 { 1, 15 }, { 0, 16 }, { 4, 17 }, { 8, 18 }, { 12, 19 }, { 16, 20 }, { 20, 21 },
51 { 24, 22 }, { 28, 23 }, { 2, 24 }, { 6, 25 }, { 10, 26 }, { 14, 27 }, { 18, 28 },
52 { 22, 29 }, { 26, 30 }, { 30, 31 }, { 32, 32 }, { 36, 33 }, { 40, 34 }, { 44, 35 },
53 { 48, 36 }, { 52, 37 }, { 56, 38 }, { 60, 39 }, { 34, 40 }, { 38, 41 }, { 42, 42 },
54 { 46, 43 }, { 50, 44 }, { 54, 45 }, { 58, 46 }, { 62, 47 } } },
56 { { 31, 48 }, { 27, 49 }, { 23, 50 }, { 19, 51 }, { 15, 52 }, { 11, 53 }, { 7, 54 },
57 { 3, 55 }, { 29, 56 }, { 25, 57 }, { 21, 58 }, { 17, 59 }, { 13, 60 }, { 9, 61 },
58 { 5, 62 }, { 1, 63 }, { 0, 64 }, { 4, 65 }, { 8, 66 }, { 12, 67 }, { 16, 68 },
59 { 20, 69 }, { 24, 70 }, { 28, 71 }, { 2, 72 }, { 6, 73 }, { 10, 74 }, { 14, 75 },
60 { 18, 76 }, { 22, 77 }, { 26, 78 }, { 30, 79 }, { 32, 80 }, { 36, 81 }, { 40, 82 },
61 { 44, 83 }, { 48, 84 }, { 52, 85 }, { 56, 86 }, { 60, 87 }, { 34, 88 }, { 38, 89 },
62 { 42, 90 }, { 46, 91 }, { 50, 92 }, { 54, 93 } } },
64 { { 31, 0 }, { 27, 1 }, { 23, 2 }, { 19, 3 }, { 15, 4 }, { 11, 5 }, { 7, 6 }, { 3, 7 },
65 { 29, 8 }, { 25, 9 }, { 21, 10 }, { 17, 11 }, { 13, 12 }, { 9, 13 }, { 5, 14 },
66 { 1, 15 }, { 0, 16 }, { 4, 17 }, { 8, 18 }, { 12, 19 }, { 16, 20 }, { 20, 21 },
67 { 24, 22 }, { 28, 23 }, { 2, 24 }, { 6, 25 }, { 10, 26 }, { 14, 27 }, { 18, 28 },
68 { 22, 29 }, { 26, 30 }, { 30, 31 }, { 63, 32 }, { 59, 33 }, { 55, 34 }, { 51, 35 },
69 { 47, 36 }, { 43, 37 }, { 39, 38 }, { 35, 39 }, { 61, 40 }, { 57, 41 }, { 53, 42 },
70 { 49, 43 }, { 45, 44 }, { 41, 45 }, { 37, 46 }, { 33, 47 }, { 32, 48 }, { 36, 49 },
71 { 40, 50 }, { 44, 51 }, { 48, 52 }, { 52, 53 }, { 56, 54 }, { 60, 55 }, { 34, 56 },
72 { 38, 57 }, { 42, 58 }, { 46, 59 }, { 50, 60 }, { 54, 61 }, { 58, 62 }, { 62, 63 } } },
74 { { 31, 64 }, { 27, 65 }, { 23, 66 }, { 19, 67 }, { 15, 68 }, { 11, 69 }, { 7, 70 },
75 { 3, 71 }, { 29, 72 }, { 25, 73 }, { 21, 74 }, { 17, 75 }, { 13, 76 }, { 9, 77 },
76 { 5, 78 }, { 1, 79 }, { 0, 80 }, { 4, 81 }, { 8, 82 }, { 12, 83 }, { 16, 84 },
77 { 20, 85 }, { 24, 86 }, { 28, 87 }, { 2, 88 }, { 6, 89 }, { 10, 90 }, { 14, 91 },
78 { 18, 92 }, { 22, 93 }, { 26, 94 }, { 30, 95 }, { 63, 96 }, { 59, 97 }, { 55, 98 },
79 { 51, 99 }, { 47, 100 }, { 43, 101 }, { 39, 102 }, { 35, 103 }, { 61, 104 },
80 { 57, 105 }, { 53, 106 }, { 49, 107 }, { 45, 108 }, { 41, 109 }, { 37, 110 },
81 { 33, 111 }, { 32, 112 }, { 36, 113 }, { 40, 114 }, { 44, 115 }, { 48, 116 },
82 { 52, 117 }, { 56, 118 } } }
94 g_GeometryDirty =
true;
99 if(cylIdx >= 0 && cylIdx < g_DELTAS.size())
100 return g_DELTAS[cylIdx];
106 if(cylIdx >= 0 && cylIdx < g_DELTAS.size())
108 g_DELTAS[cylIdx] = val;
109 g_GeometryDirty =
true;
117 if(g_DELTAS.size() < 6)
118 g_DELTAS.resize(6, 0.0);
119 g_GeometryDirty =
true;
132 g_IsRotated = (std::abs(rx) > 1e-9 || std::abs(ry) > 1e-9 || std::abs(rz) > 1e-9);
136 double cx = std::cos(rx), sx = std::sin(rx);
137 double cy = std::cos(ry), sy = std::sin(ry);
138 double cz = std::cos(rz), sz = std::sin(rz);
141 auto rotate = [&](
double x,
double y,
double z,
double &ox,
double &oy,
double &oz)
144 double y1 = y * cx - z * sx;
145 double z1 = y * sx + z * cx;
148 double z2 = z1 * cy - x1 * sy;
149 double x2 = z1 * sy + x1 * cy;
152 double x3 = x2 * cz - y2 * sz;
153 double y3 = x2 * sz + y2 * cz;
161 rotate(1, 0, 0, g_R[0][0], g_R[1][0], g_R[2][0]);
163 rotate(0, 1, 0, g_R[0][1], g_R[1][1], g_R[2][1]);
165 rotate(0, 0, 1, g_R[0][2], g_R[1][2], g_R[2][2]);
208 double xn = g_R[0][0] * x + g_R[0][1] * y + g_R[0][2] * z;
209 double yn = g_R[1][0] * x + g_R[1][1] * y + g_R[1][2] * z;
210 double zn = g_R[2][0] * x + g_R[2][1] * y + g_R[2][2] * z;
223 double xn = g_R[0][0] * x + g_R[1][0] * y + g_R[2][0] * z;
224 double yn = g_R[0][1] * x + g_R[1][1] * y + g_R[2][1] * z;
225 double zn = g_R[0][2] * x + g_R[1][2] * y + g_R[2][2] * z;
256 auto it = BOARD_OFFSETS.find(board_id);
257 if(it != BOARD_OFFSETS.end())
264 return 213 + (board_id - 4) * 64;
271 g_ActiveCylinders = active_ids;
272 g_GeometryDirty =
true;
277 if(g_ActiveCylinders.empty())
278 return { 0, 1, 2, 3, 4, 5 };
279 return g_ActiveCylinders;
284 if(g_GeometryDirty || g_Cylinders.empty())
289 auto &active = g_ActiveCylinders;
290 auto isActive = [&](
int id)
294 return std::find(active.begin(), active.end(),
id) != active.end();
298 std::vector<CylinderConfig> all
301 { 45, 16.8, 0.5, 4.294 + g_DELTAS[0] + g_OFFSET_EXP, -1,
GetStereoAngle(16.8),
303 { 49, 17.45, 0.5, 3.829 + g_DELTAS[0] + g_OFFSET_EXP, 1,
GetStereoAngle(17.45),
308 { 59, 20.8, 0.5, 2.609 + g_DELTAS[1] + g_OFFSET_EXP, -1,
GetStereoAngle(20.8),
310 { 60, 21.45, 0.5, 3.351 + g_DELTAS[1] + g_OFFSET_EXP, 1,
315 { 96, 36.8, 0.5, g_DELTAS[2] + g_OFFSET_EXP, -1,
GetStereoAngle(36.8),
317 { 96, 37.45, 0.5, g_DELTAS[2] + g_OFFSET_EXP, 1,
GetStereoAngle(37.45),
322 { 151, 64.8, 0.5, g_DELTAS[3] + g_OFFSET_EXP, -1,
GetStereoAngle(64.8),
324 { 152, 65.45, 0.5, g_DELTAS[3] + g_OFFSET_EXP, 1,
GetStereoAngle(65.45),
329 { 160, 68.8, 0.5, g_DELTAS[4] + g_OFFSET_EXP, -1,
GetStereoAngle(68.8),
331 { 162, 69.45, 0.5, g_DELTAS[4] + g_OFFSET_EXP, 1,
GetStereoAngle(69.45),
336 { 170, 72.8, 0.5, g_DELTAS[5] + g_OFFSET_EXP, -1,
GetStereoAngle(72.8),
338 { 171, 73.45, 0.5, g_DELTAS[5] + g_OFFSET_EXP, 1,
GetStereoAngle(73.45),
343 for(
const auto &c : all)
347 g_Cylinders.push_back(c);
350 g_GeometryDirty =
false;
357 double wrapped = std::fmod(angle, 2.0 *
M_PI);
359 wrapped += 2.0 *
M_PI;
368 for(
const auto &cyl : cylinders)
371 if(b_id < offset + cyl.inner.nBundles)
373 int b_loc = b_id - offset;
374 return { cyl.id, 0, cyl.inner.radius,
375 wrap0_2pi(2.0 *
M_PI * (-b_loc) / cyl.inner.nBundles + cyl.inner.phiOffset),
376 cyl.inner.direction, cyl.inner.color };
378 offset += cyl.inner.nBundles;
381 if(b_id < offset + cyl.outer.nBundles)
383 int b_loc = b_id - offset;
384 return { cyl.id, 1, cyl.outer.radius,
385 wrap0_2pi(2.0 *
M_PI * (b_loc) / cyl.outer.nBundles + cyl.outer.phiOffset),
386 cyl.outer.direction, cyl.outer.color };
388 offset += cyl.outer.nBundles;
391 return { -1, -1, 0, 0, 0, 0 };
398 auto boardMapIt = BOARD_MAPS.find(board_id);
399 if(boardMapIt != BOARD_MAPS.end())
401 auto chanIt = boardMapIt->second.find(channel_id);
402 if(chanIt != boardMapIt->second.end())
404 local_val = chanIt->second;
410 local_val = channel_id;
419 if(boardOffset == -1)
422 return local_val + boardOffset;
427 std::vector<BundlesIntersection> out;
431 for(
size_t i = 0; i < hit_ids.size(); ++i)
433 for(
size_t j = i + 1; j < hit_ids.size(); ++j)
442 double ddir = p1.
dir - p2.
dir;
446 for(
int k = -2; k <= 2; ++k)
449 if(std::abs(ddir) < 1e-9)
452 double alpha = (dphi0 + 2.0 * k *
M_PI) / (ddir *
M_PI);
454 if(alpha >= 0.0 && alpha <= 1.0)
464 double x_loc = p1.
r * std::cos(ph);
465 double y_loc = p1.
r * std::sin(ph);
469 double x_rot = x_loc;
470 double y_rot = y_loc;
471 double z_rot = z_loc;
475 { z_rot, x_rot, y_rot, z_loc, x_loc, y_loc, p1.
cylinderId, deltaZ });
489 int global_offset = 0;
491 for(
const auto &cyl : cylinders)
496 int limit = (layer_id == 0) ? cyl.inner.nBundles : cyl.outer.nBundles;
498 if(layer_idx < 0 || layer_idx >= limit)
500 std::cerr <<
" [ERROR] Index " << layer_idx <<
" out of range for Cylinder "
501 << cyl_id <<
" Layer " << layer_id <<
"!\n";
506 int local_base = (layer_id == 0) ? 0 : cyl.inner.nBundles;
507 return global_offset + local_base + layer_idx;
510 global_offset += (cyl.inner.nBundles + cyl.outer.nBundles);
520 std::cout <<
"\n >>> INFO BUNDLE ID: " << global_id <<
" <<<\n";
523 bool found_hw =
false;
524 for(
auto const &[board, map] : BOARD_MAPS)
531 int target_local = global_id - off;
533 for(
auto const &[chan, val] : map)
535 if(val == target_local)
537 std::cout <<
" [HARDWARE] Board: " << board <<
" | Channel: " << chan <<
"\n";
546 std::cout <<
" [HARDWARE] Not mapped on any board.\n";
550 int current_offset = 0;
551 bool found_geo =
false;
553 for(
const auto &cyl : cylinders)
555 int tot = cyl.inner.nBundles + cyl.outer.nBundles;
556 if(global_id >= current_offset && global_id < current_offset + tot)
558 int local = global_id - current_offset;
559 bool isInner = (local < cyl.inner.nBundles);
560 int layerIdx = isInner ? local : (local - cyl.inner.nBundles);
562 std::cout <<
" [GEOMETRY] Cylinder: " << cyl.id
563 <<
" | Layer: " << (isInner ?
"INNER" :
"OUTER") <<
" | Index: " << layerIdx
568 current_offset += tot;
572 std::cout <<
" [GEOMETRY] ID out of geometric range.\n";
580 std::cout <<
"\n-----------------------------------\n";
581 std::cout <<
" 1. Info from Global ID\n";
582 std::cout <<
" 2. Info from Board/Channel\n";
583 std::cout <<
" 3. Info from Geometry (Cyl, Lay, Idx)\n";
584 std::cout <<
" 4. First bundle of Cylinder (N/A in this version)\n";
590 std::cout <<
" 5. First bundle of Layer\n";
591 std::cout <<
" 0. Quit\n";
592 std::cout <<
"Choice: ";
598 std::cin.ignore(10000,
'\n');
609 std::cout <<
"Global ID: ";
610 std::cin >> target_id;
615 std::cout <<
"Board: ";
617 std::cout <<
"Chan: ";
621 else if(mode >= 3 && mode <= 5)
624 std::cout <<
"Cylinder ID: ";
626 if(mode == 3 || mode == 5)
628 std::cout <<
"Layer (0=In, 1=Out): ";
633 std::cout <<
"Index: ";
644 std::cout <<
" -> Mapping not found or wrong parameters.\n";
FiberProp GetFiberProp(int b_id)
Retrieves fiber properties given a global bundle ID.
int GetBoardGlobalOffset(int board_id)
Returns the global offset (bundle count) for a specific board.
void ApplyInverseTransformation(double &x, double &y, double &z)
Transforms a 3D POINT in-place from the Global Lab Frame to the Detector Local Frame....
double GetOffsetExp()
Retrieves the current experimental angular offset (OFFSET_EXP).
void SetDeltaI(int cylIdx, double val)
Sets the experimental parameter DELTA for a specific cylinder.
void ApplyRotation(double &x, double &y, double &z)
Rotates a 3D VECTOR in-place from the Detector Local Frame to the Global Lab Frame....
std::vector< BundlesIntersection > FindIntersections(const std::vector< int > &hit_ids)
Finds 3D intersections between a list of hit bundles.
void SetDeltas(const std::vector< double > &deltas)
Sets the experimental parameter DELTA for all cylinders.
constexpr double BUNDLE_WIDTH
Physical width of a bundle [mm].
std::vector< int > GetActiveCylinders()
Retrieves the list of currently active cylinder IDs.
void ApplyTransformation(double &x, double &y, double &z)
Transforms a 3D POINT in-place from the Detector Local Frame to the Global Lab Frame....
void SetActiveCylinders(const std::vector< int > &active_ids)
Sets the list of active cylinder IDs. This defines the physical composition of the detector for the c...
void SetOffsetExp(double val)
Sets the experimental angular offset (OFFSET_EXP).
double wrap0_2pi(double angle)
Wraps an angle into the [0, 2*PI) range.
int GetGlobalBundleId(int board_id, int channel_id)
Converts Hardware Board/Channel to Global Bundle ID.
void SetTranslation(double tx, double ty, double tz)
Sets the global translation of the detector origin.
void MapExplorer()
Interactive CLI menu to explore the mapping.
const std::vector< CylinderConfig > & GetCylinders()
Retrieves the configuration for all active cylinders.
int GetGlobalIdFromGeometry(int cyl_id, int layer_id, int layer_idx)
Helper: Converts Geometry (Cyl, Layer, Index) to Global ID.
void PrintBundleMapping(int global_id)
Helper: Prints mapping details for a given Global ID to stdout.
double GetDeltaI(int cylIdx)
Retrieves the current experimental parameter DELTA for a specific cylinder.
constexpr double L_HALF
Half-length of the detector [mm].
std::vector< double > GetDeltas()
Gets the experimental parameter DELTA for all cylinders.
void ApplyInverseRotation(double &x, double &y, double &z)
Rotates a 3D VECTOR in-place from the Global Lab Frame to the Detector Local Frame....
void GetRotation(double &rx, double &ry, double &rz)
Retrieves the current global rotation angles.
void SetRotation(double rx, double ry, double rz)
Sets the global rotation of the detector using Euler angles. Rotations are applied in order: X,...
void GetTranslation(double &tx, double &ty, double &tz)
Retrieves the current global translation.
double GetStereoAngle(double radius, double deltaPhi=M_PI, double length=2.0 *L_HALF)
Computes the analytical stereo angle for a given radius.
Root namespace for the Cylindrical Helix Tracker (CHeT) project.
Properties of a specific reconstructed fiber.
int layerId
0 for inner, 1 for outer
int dir
Winding direction.
double phi0
Initial angle [rad].