File indexing completed on 2026-10-23 08:28:14
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091 #include "MPGDTrackerDigi.h"
0092
0093 #include <DD4hep/Alignments.h>
0094 #include <DD4hep/DetElement.h>
0095 #include <DD4hep/IDDescriptor.h>
0096 #include <DD4hep/Objects.h>
0097 #include <DD4hep/Readout.h>
0098 #include <DD4hep/Shapes.h>
0099 #include <DD4hep/VolumeManager.h>
0100 #include <DD4hep/detail/SegmentationsInterna.h>
0101 #include <DDSegmentation/BitFieldCoder.h>
0102 #include <DDSegmentation/CartesianGridUV.h>
0103 #include <DDSegmentation/CartesianGridXY.h>
0104 #include <DDSegmentation/CylindricalGridPhiZ.h>
0105 #include <DDSegmentation/MultiSegmentation.h>
0106 #include <DDSegmentation/Segmentation.h>
0107 #include <Evaluator/DD4hepUnits.h>
0108 #include <Math/GenVector/Cartesian3D.h>
0109 #include <Math/GenVector/DisplacementVector3D.h>
0110 #include <Parsers/Primitives.h>
0111 #include <TGeoMatrix.h>
0112 #include <TMath.h>
0113
0114 #include <algorithms/geo.h>
0115 #include <algorithms/logger.h>
0116 #include <edm4eic/unit_system.h>
0117 #include <edm4hep/MCParticleCollection.h>
0118 #include <edm4hep/Vector3d.h>
0119 #include <edm4hep/Vector3f.h>
0120 #include <format>
0121 #include <podio/detail/Link.h>
0122 #include <podio/detail/LinkCollectionImpl.h>
0123 #include <algorithm>
0124 #include <array>
0125 #include <cmath>
0126 #include <cstdint>
0127 #include <gsl/pointers>
0128 #include <gsl/util>
0129 #include <initializer_list>
0130 #include <iterator>
0131 #include <map>
0132 #include <memory>
0133 #include <random>
0134 #include <stdexcept>
0135 #include <tuple>
0136 #include <utility>
0137 #include <vector>
0138
0139 #include "algorithms/digi/MPGDTrackerDigiConfig.h"
0140
0141 using namespace dd4hep;
0142
0143 namespace eicrecon {
0144
0145 void MPGDTrackerDigi::init() {
0146
0147 m_detector = algorithms::GeoSvc::instance().detector();
0148
0149 if (m_cfg.readout.empty()) {
0150 throw std::runtime_error("Readout is empty");
0151 }
0152 try {
0153 m_seg = m_detector->readout(m_cfg.readout).segmentation();
0154 m_id_dec = m_detector->readout(m_cfg.readout).idSpec().decoder();
0155 } catch (const std::runtime_error&) {
0156 critical(R"(Failed to load ID decoder for "{}" readout.)", m_cfg.readout);
0157 throw std::runtime_error("Failed to load ID decoder");
0158 }
0159
0160
0161 parseIDDescriptor();
0162 parseSegmentation();
0163
0164
0165 m_stripRank = [&](CellID vID) {
0166 CellID sID = vID & m_stripBits;
0167 for (int rank = 0; rank < 5; rank++) {
0168 if (sID == m_stripIDs[rank]) {
0169 return rank;
0170 }
0171 }
0172 return -1;
0173 };
0174 m_orientation = [&](CellID vID, CellID vJD) {
0175 int ranki = m_stripRank(vID);
0176 int rankj = m_stripRank(vJD);
0177 if (rankj > ranki) {
0178 return +1;
0179 }
0180 if (rankj < ranki) {
0181 return -1;
0182 }
0183 return 0;
0184 };
0185 m_isUpstream = [](int orientation, unsigned int status) {
0186
0187 bool isUpstream =
0188 (orientation < 0 && (status & 0x2)) ||
0189 (orientation > 0 && (status & 0x8)) ||
0190 (orientation == 0 && (status & 0x102) == 0x102);
0191 return isUpstream;
0192 };
0193 m_isDownstream = [](int orientation, unsigned int status) {
0194
0195 bool isDownstream =
0196 (orientation > 0 && (status & 0x1)) ||
0197 (orientation < 0 && (status & 0x4)) ||
0198 (orientation == 0 && (status & 0x101) == 0x101);
0199 return isDownstream;
0200 };
0201
0202 m_toleranceFactor = [](double P) {
0203 int factor = 0;
0204 if (P < 1 * dd4hep::MeV) {
0205 factor = 4;
0206 } else if (P < 10 * dd4hep::MeV) {
0207 factor = 2;
0208 } else {
0209 factor = 1;
0210 }
0211 return factor;
0212 };
0213
0214
0215 m_binToPosition = [](FieldID bin, double cellSize, double offset) {
0216 return bin * cellSize + offset;
0217 };
0218 }
0219
0220
0221 void getLocalPosMom(const edm4hep::SimTrackerHit& sim_hit, const TGeoHMatrix& toModule,
0222 double* lpos, double* lmom);
0223 bool cExtrapolate(const double* lpos, const double* lmom,
0224 double rT,
0225 double* lext);
0226 double getRef2Cur(DetElement refVol, DetElement curVol);
0227 bool bExtrapolate(const double* lpos, const double* lmom,
0228 double zT,
0229 double* lext);
0230 std::string inconsistency(const edm4hep::EventHeader& event, unsigned int status, CellID cID,
0231 const double* lpos, const double* lmom);
0232 std::string oddity(const edm4hep::EventHeader& event, unsigned int status, double dist, CellID cID,
0233 const double* lpos, const double* lmom, CellID cJD, const double* lpoj,
0234 const double* lmoj);
0235 double outInDistance(int shape, int orientation, double lintos[][3], double louts[][3],
0236 double* lmom, double* lmoj);
0237 void flagUnexpected(const edm4hep::EventHeader& event, int shape, double expected,
0238 const edm4hep::SimTrackerHit& sim_hit, double* lpini, double* lpend,
0239 double* lpos, double* lmom);
0240
0241 void MPGDTrackerDigi::process(const MPGDTrackerDigi::Input& input,
0242 const MPGDTrackerDigi::Output& output) const {
0243
0244 const auto [headers, sim_hits] = input;
0245 auto [raw_hits, links, associations] = output;
0246
0247
0248 auto seed = m_uid.getUniqueID(*headers, name());
0249 std::default_random_engine generator(seed);
0250 std::normal_distribution<double> gaussian;
0251
0252
0253 std::map<std::uint64_t, edm4eic::MutableRawTrackerHit> cell_hit_maps[2];
0254
0255 std::map<std::uint64_t, std::vector<std::uint64_t>> stripID2cIDs;
0256
0257 const VolumeManager& volman = m_detector->volumeManager();
0258
0259
0260
0261
0262 const edm4hep::EventHeader& header = headers->at(0);
0263
0264
0265 size_t sim_size = sim_hits->size();
0266 for (int idx = 0; idx < (int)sim_size; idx++) {
0267 const edm4hep::SimTrackerHit& sim_hit = sim_hits->at(idx);
0268
0269
0270
0271
0272
0273
0274
0275 double time_smearing = gaussian(generator) * m_cfg.timeResolution;
0276
0277
0278 CellID refID = sim_hit.getCellID() & m_moduleBits;
0279 DetElement refVol = volman.lookupDetElement(refID);
0280
0281
0282
0283
0284
0285 double lpos[3], eDep, time;
0286 std::vector<std::uint64_t> cIDs;
0287 const auto& shape = refVol.solid();
0288 if (std::string_view{shape.type()} == "TGeoTubeSeg") {
0289
0290 if (!cCoalesceExtend(input, idx, cIDs, lpos, eDep, time))
0291 continue;
0292 } else if (std::string_view{shape.type()} == "TGeoBBox") {
0293
0294 if (!bCoalesceExtend(input, idx, cIDs, lpos, eDep, time))
0295 continue;
0296 } else {
0297 critical(R"(Bad input data: CellID {:x} has invalid shape "{}")", refID, shape.type());
0298 throw std::runtime_error(R"(Inconsistency: Inappropriate SimHits fed to "MPGDTrackerDigi".)");
0299 }
0300
0301
0302 double surfPos[2];
0303 Position locPos;
0304 if (std::string_view{shape.type()} == "TGeoTubeSeg") {
0305
0306 const Tube& tRef = refVol.solid();
0307 double R = (tRef.rMin() + tRef.rMax()) / 2;
0308 double phi = atan2(lpos[1], lpos[0]);
0309 surfPos[0] = phi * R;
0310 surfPos[1] = lpos[2];
0311 locPos = Position(R * cos(phi), R * sin(phi), lpos[2]);
0312 } else {
0313 locPos = Position(lpos[0], lpos[1], lpos[2]);
0314 if (m_gridAngle != 0.0) {
0315 dd4hep::DDSegmentation::Vector3D position;
0316 position.X = lpos[0];
0317 position.Y = lpos[1];
0318 position = RotationZ(m_gridAngle) * position;
0319 surfPos[0] = position.X;
0320 surfPos[1] = position.Y;
0321 } else {
0322 surfPos[0] = lpos[0];
0323 surfPos[1] = lpos[1];
0324 }
0325 }
0326
0327
0328 for (int pn = 0; pn < 2; pn++) {
0329
0330
0331 Cluster cluster;
0332 int status = get2HitCluster(refID, locPos, surfPos, pn, generator, cluster);
0333 if (status != 0) {
0334 CellID vIDs = (std::uint32_t)refID;
0335 CellID hIDs = refID >> 32;
0336 error(R"(SimHit (= 0x{:08x}, 0x{:08x}, {:.2f},{:.2f} cm) beyond limits of {}Strips.)", hIDs,
0337 vIDs, surfPos[0] / cm, surfPos[1] / cm, (pn != 0) ? 'n' : 'p');
0338 }
0339
0340 if (level() >= algorithms::LogLevel::kDebug) {
0341 std::string sCellID = (pn != 0) ? "cellIDn" : "cellIDp";
0342 if (pn == 0) {
0343 debug(" =>=>");
0344 }
0345 for (auto clusterHit : cluster) {
0346 CellID cID = clusterHit.first;
0347 CellID hID = cID >> 32;
0348 CellID vID = (std::uint32_t)cID;
0349 debug("Hit {} = 0x{:08x}, 0x{:08x}", sCellID, hID, vID);
0350 debug(" edep = {:.0f} [eV]", clusterHit.second * eDep / eV);
0351 }
0352 }
0353
0354
0355
0356 std::map<std::uint64_t, edm4eic::MutableRawTrackerHit>& cell_hit_map =
0357 gsl::at(cell_hit_maps, pn);
0358 double g = m_cfg.gain;
0359 for (auto clusterHit : cluster) {
0360 CellID cID = clusterHit.first;
0361 double f = clusterHit.second;
0362
0363
0364
0365
0366
0367 if (eDep < m_cfg.threshold) {
0368 debug(" eDep {:.2f} is below threshold of {:.2f} [keV]", eDep, m_cfg.threshold / keV);
0369 continue;
0370 }
0371 stripID2cIDs[cID] = cIDs;
0372 double result_time = time + time_smearing;
0373 auto hit_time_stamp = (std::int32_t)(result_time * 1e3);
0374 if (!cell_hit_map.contains(cID)) {
0375
0376 cell_hit_map[cID] = {
0377 cID, (std::int32_t)std::llround(eDep * 1e6 * f * g),
0378 hit_time_stamp
0379 };
0380 } else {
0381
0382 auto& hit = cell_hit_map[cID];
0383 debug(" Hit already exists in cell ID={}, prev. hit time: {}", cID, hit.getTimeStamp());
0384
0385
0386 hit.setTimeStamp(std::min(hit_time_stamp, hit.getTimeStamp()));
0387
0388
0389 auto charge = hit.getCharge();
0390 hit.setCharge(charge + (std::int32_t)std::llround(eDep * 1e6 * f * g));
0391 }
0392 }
0393 }
0394 }
0395
0396
0397 for (auto& cell_hit_map : cell_hit_maps) {
0398 for (const auto& [stripID, hit] : cell_hit_map) {
0399 raw_hits->push_back(hit);
0400 const auto raw_hit = raw_hits->at(raw_hits->size() - 1);
0401 const auto is = stripID2cIDs.find(stripID);
0402 if (is == stripID2cIDs.end()) {
0403 error(R"(Inconsistency: CellID {:x} not found in "stripID2cIDs" map)", stripID);
0404 throw std::runtime_error(R"(Inconsistency in the handling of "stripID2cIDs" map)");
0405 }
0406 std::vector<std::uint64_t> cIDs = is->second;
0407 for (CellID cID : cIDs) {
0408 for (const auto& sim_hit : *sim_hits) {
0409 if (sim_hit.getCellID() == cID) {
0410
0411 auto link = links->create();
0412 link.setFrom(raw_hit);
0413 link.setTo(sim_hit);
0414 link.setWeight(1.0);
0415
0416 auto hitassoc = associations->create();
0417 hitassoc.setWeight(1.0);
0418 hitassoc.setRawHit(raw_hit);
0419 hitassoc.setSimHit(sim_hit);
0420 }
0421 }
0422 }
0423 }
0424 }
0425 }
0426
0427
0428
0429
0430
0431
0432
0433
0434
0435
0436
0437
0438
0439
0440
0441
0442
0443
0444
0445
0446
0447
0448
0449
0450
0451
0452
0453
0454 void MPGDTrackerDigi::parseIDDescriptor() {
0455
0456
0457
0458
0459
0460
0461
0462 debug(R"(Parsing IDDescriptor for "{}" readout)", m_cfg.readout);
0463 CellID sensorBits = 0;
0464 for (int field = 0; field < 5; field++) {
0465 const char* fieldName = m_fieldNames[field];
0466 CellID fieldID = 0;
0467 try {
0468 fieldID = m_id_dec->get(~((CellID)0x0), fieldName);
0469 } catch (const std::runtime_error& error) {
0470 critical(R"(No field "{}" in IDDescriptor of readout "{}".)", fieldName, m_cfg.readout);
0471 throw std::runtime_error("Invalid IDDescriptor");
0472 }
0473 const BitFieldElement& fieldElement = (*m_id_dec)[fieldName];
0474 CellID fieldBits = fieldID << fieldElement.offset();
0475 m_volumeBits |= fieldBits;
0476
0477 if (std::string_view{fieldName} == "strip") {
0478 m_stripBits = fieldBits;
0479
0480 CellID bits[5] = {0x3, 0x1, 0, 0x2, 0x4};
0481 for (int subVolume = 0; subVolume < 5; subVolume++) {
0482 m_stripIDs[subVolume] = bits[subVolume] << fieldElement.offset();
0483 }
0484 }
0485
0486 else if (m_cfg.readout == "MPGDBarrelHits" && std::string_view{fieldName} == "sensor") {
0487 sensorBits = fieldBits;
0488 m_sensorOffset = fieldElement.offset();
0489 }
0490 }
0491
0492 m_moduleBits = m_volumeBits & ~m_stripBits;
0493 m_pStripBit = m_stripIDs[1];
0494 m_nStripBit = m_stripIDs[3];
0495
0496 if (m_cfg.readout == "MPGDBarrelHits") {
0497 m_sensorStripBits = sensorBits | m_stripBits;
0498 } else {
0499 m_sensorStripBits = m_stripBits;
0500 }
0501
0502
0503
0504
0505 int coordOffsets[2] = {64, 64};
0506 for (int pn = 0; pn < 2; pn++) {
0507 std::string coordName;
0508 if (m_cfg.readout == "MPGDBarrelHits") {
0509 coordName = pn ? "z" : "phi";
0510 } else if (m_cfg.readout == "OuterMPGDBarrelHits") {
0511 coordName = pn ? "v" : "u";
0512 } else {
0513 coordName = pn ? "y" : "x";
0514 }
0515 try {
0516 m_stripIndices[pn] = m_id_dec->index(coordName);
0517 } catch (const std::runtime_error& error) {
0518 critical(R"(No "{}" field in IDDescriptor of readout "{}".)", coordName, m_cfg.readout);
0519 throw std::runtime_error("Invalid IDDescriptor");
0520 }
0521 const BitFieldElement& fieldElement = (*m_id_dec)[coordName];
0522 int offset = fieldElement.offset();
0523 m_stripIncs[pn] = ((CellID)0x1) << offset;
0524 if (offset < coordOffsets[pn])
0525 coordOffsets[pn] = offset;
0526 }
0527 if (coordOffsets[0] != 32 || coordOffsets[1] != 48) {
0528 critical(R"(Coordinate fields in IDDescriptor of readout "{}" do not start @ bits 32 and 48.)",
0529 m_cfg.readout);
0530 throw std::runtime_error("Invalid IDDescriptor");
0531 }
0532 }
0533 void MPGDTrackerDigi::parseSegmentation() {
0534 debug(R"(Find valid "MultiSegmentation" for "{}" readout.)", m_cfg.readout);
0535
0536
0537 std::function<void(int, double)> checkResolutionVsPitch = [&](int pn, double pitch) {
0538 double sigma = m_cfg.stripResolutions[pn];
0539 if (m_truncation * sigma > pitch) {
0540 critical(R"(stripResolutions[{}] (= {}) too large for pitch (={}) of "{}" readout.)", pn,
0541 sigma, pitch, m_cfg.readout);
0542 throw std::runtime_error("Space resolution parameter too large");
0543 }
0544 return;
0545 };
0546 using Segmentation = dd4hep::DDSegmentation::Segmentation;
0547 const Segmentation* segmentation = m_seg->segmentation;
0548
0549 unsigned int required = 0, fulfilled = 0;
0550 if (segmentation->type() == "MultiSegmentation") {
0551 using MultiSegmentation = dd4hep::DDSegmentation::MultiSegmentation;
0552 const auto* multiSeg = dynamic_cast<const MultiSegmentation*>(segmentation);
0553 StripParameters pars;
0554 if (m_cfg.readout == "MPGDBarrelHits") {
0555
0556 required = 0x3 | m_pStripBit | m_nStripBit;
0557 unsigned int innerBit = 0x0, outerBit = 0x1;
0558 for (unsigned int sectorBit : {innerBit, outerBit}) {
0559 CellID sensorID = ((CellID)sectorBit) << m_sensorOffset;
0560 const Segmentation& sectorSeg = multiSeg->subsegmentation(sensorID);
0561 if (multiSeg->type() != "MultiSegmentation")
0562 continue;
0563 const auto& stripMultiSeg = dynamic_cast<const MultiSegmentation&>(sectorSeg);
0564 for (CellID stripID : {m_pStripBit, m_nStripBit}) {
0565 const Segmentation& stripSeg = stripMultiSeg.subsegmentation(stripID);
0566 if (stripSeg.type() != "CylindricalGridPhiZ") {
0567 critical(
0568 R"(Segmentation type for "{}" readout = "{}", whereas expected = "CylindricalGridPhiZ".)",
0569 m_cfg.readout, stripSeg.type());
0570 continue;
0571 }
0572 const dd4hep::DDSegmentation::CylindricalGridPhiZ& gridPhiZ =
0573 dynamic_cast<const dd4hep::DDSegmentation::CylindricalGridPhiZ&>(stripSeg);
0574 fulfilled |= sectorBit == innerBit ? 0x1 : 0x2;
0575 fulfilled |= stripID;
0576
0577 double radius = gridPhiZ.radius();
0578 int pn;
0579 std::string stripName;
0580 if (stripID == m_pStripBit) {
0581 pars.pitch = gridPhiZ.gridSizePhi() * radius;
0582 pars.offset = gridPhiZ.offsetPhi() * radius;
0583 pn = 0;
0584 } else {
0585 pars.pitch = gridPhiZ.gridSizeZ();
0586 pars.offset = gridPhiZ.offsetZ();
0587 pn = 1;
0588 }
0589 pars.index = m_stripIndices[pn];
0590
0591 checkResolutionVsPitch(pn, pars.pitch);
0592 int nStrips = m_cfg.stripNumbers[pn];
0593
0594
0595
0596 pars.max = (nStrips / 2 - .5) * pars.pitch + pars.offset;
0597 pars.min = (-nStrips / 2 - .5) * pars.pitch + pars.offset;
0598
0599 CellID sensorStripID = sensorID | stripID;
0600 m_stripParameters[sensorStripID] = pars;
0601 }
0602 }
0603 } else if (m_cfg.readout == "OuterMPGDBarrelHits") {
0604
0605 required = m_pStripBit | m_nStripBit;
0606 double gridAngles[2];
0607 for (unsigned int stripID : {m_pStripBit, m_nStripBit}) {
0608 const dd4hep::DDSegmentation::Segmentation& stripSeg = multiSeg->subsegmentation(stripID);
0609 if (stripSeg.type() != "CartesianGridUV") {
0610 critical(
0611 R"(Segmentation type for "{}" readout = "{}", whereas expected = "CartesianGridUV".)",
0612 m_cfg.readout, stripSeg.type());
0613 continue;
0614 }
0615 const dd4hep::DDSegmentation::CartesianGridUV& gridUV =
0616 dynamic_cast<const dd4hep::DDSegmentation::CartesianGridUV&>(stripSeg);
0617 fulfilled |= stripID;
0618
0619 int pn;
0620 std::string stripName;
0621 if (stripID == m_pStripBit) {
0622 pars.pitch = gridUV.gridSizeU();
0623 pars.offset = gridUV.offsetU();
0624 pn = 0;
0625 } else {
0626 pars.pitch = gridUV.gridSizeV();
0627 pars.offset = gridUV.offsetV();
0628 pn = 1;
0629 }
0630 pars.index = m_stripIndices[pn];
0631 gridAngles[pn] = gridUV.gridAngle();
0632
0633 checkResolutionVsPitch(pn, pars.pitch);
0634 int nStrips = m_cfg.stripNumbers[pn];
0635 pars.max = (nStrips / 2 - .5) * pars.pitch + pars.offset;
0636 pars.min = (-nStrips / 2 - .5) * pars.pitch + pars.offset;
0637
0638 m_stripParameters[stripID] = pars;
0639 }
0640 if (fabs(gridAngles[0] - gridAngles[1]) > 1e-6) {
0641 critical(
0642 R"(Inconsistent gridAngles of "CartesianGridUV" for readout "{}": 'p' = {:.6f}, 'n' = {:.6f}.)",
0643 m_cfg.readout, gridAngles[0], gridAngles[1]);
0644 fulfilled = 0;
0645 }
0646 m_gridAngle = gridAngles[0];
0647 } else {
0648
0649 required = m_pStripBit | m_nStripBit;
0650 for (unsigned int stripID : {m_pStripBit, m_nStripBit}) {
0651 const dd4hep::DDSegmentation::Segmentation& stripSeg = multiSeg->subsegmentation(stripID);
0652 if (stripSeg.type() != "CartesianGridXY") {
0653 critical(
0654 R"(Segmentation type for "{}" readout = "{}", whereas expected = "CartesianGridXY".)",
0655 m_cfg.readout, stripSeg.type());
0656 continue;
0657 }
0658 const dd4hep::DDSegmentation::CartesianGridXY& gridXY =
0659 dynamic_cast<const dd4hep::DDSegmentation::CartesianGridXY&>(stripSeg);
0660 fulfilled |= stripID;
0661
0662 int pn;
0663 std::string stripName;
0664 if (stripID == m_pStripBit) {
0665 pars.pitch = gridXY.gridSizeX();
0666 pars.offset = gridXY.offsetX();
0667 pn = 0;
0668 } else {
0669 pars.pitch = gridXY.gridSizeY();
0670 pars.offset = gridXY.offsetY();
0671 pn = 1;
0672 }
0673 pars.index = m_stripIndices[pn];
0674
0675 checkResolutionVsPitch(pn, pars.pitch);
0676 int nStrips = m_cfg.stripNumbers[pn];
0677 pars.max = (nStrips / 2 - .5) * pars.pitch + pars.offset;
0678 pars.min = (-nStrips / 2 - .5) * pars.pitch + pars.offset;
0679
0680 m_stripParameters[stripID] = pars;
0681 }
0682 }
0683 } else {
0684 critical(
0685 R"(Segmentation type for "{}" readout = "{}", whereas expected = "MultiSegmentation".)",
0686 m_cfg.readout, segmentation->type());
0687 }
0688 if (fulfilled != required) {
0689 critical(R"(Error retrieving Segmentation parameters for "{}" readout.)", m_cfg.readout);
0690 throw std::runtime_error("Error retrieving Segmentation parameters");
0691 }
0692 }
0693
0694
0695
0696
0697
0698
0699
0700
0701
0702
0703
0704
0705
0706
0707 bool MPGDTrackerDigi::cCoalesceExtend(const Input& input, int& idx,
0708 std::vector<std::uint64_t>& cIDs, double* lpos, double& eDep,
0709 double& time) const {
0710 const auto [headers, sim_hits] = input;
0711 const edm4hep::EventHeader& header = headers->at(0);
0712 const edm4hep::SimTrackerHit& sim_hit = sim_hits->at(idx);
0713 CellID vID = sim_hit.getCellID() & m_volumeBits;
0714 CellID refID = vID & m_moduleBits;
0715 const VolumeManager& volman = m_detector->volumeManager();
0716 DetElement refVol = volman.lookupDetElement(refID);
0717
0718
0719 const TGeoHMatrix toRefVol = refVol.nominal().worldTransformation();
0720 double lmom[3];
0721 getLocalPosMom(sim_hit, toRefVol, lpos, lmom);
0722 const double edmm = edm4eic::unit::mm, ed2dd = dd4hep::mm / edmm;
0723 using dd4hep::mm;
0724 using edm4eic::unit::eV, edm4eic::unit::GeV;
0725
0726 eDep = sim_hit.getEDep();
0727 time = sim_hit.getTime();
0728
0729 const Tube& tRef = refVol.solid();
0730 double dZ = tRef.dZ();
0731
0732
0733
0734
0735
0736 double startPhi = tRef.startPhi() * radian;
0737 startPhi -= 2 * TMath::Pi();
0738 double endPhi = tRef.endPhi() * radian;
0739 endPhi -= 2 * TMath::Pi();
0740
0741 DetElement curVol = volman.lookupDetElement(vID);
0742 const Tube& tCur = curVol.solid();
0743 double rMin = tCur.rMin(), rMax = tCur.rMax();
0744
0745 double lintos[2][3], louts[2][3], lpini[3], lpend[3], lmend[3];
0746 std::copy(std::begin(lmom), std::end(lmom), std::begin(lmend));
0747 unsigned int status =
0748 cTraversing(lpos, lmom, sim_hit.getPathLength() * ed2dd, sim_hit.isProducedBySecondary(),
0749 rMin, rMax, dZ, startPhi, endPhi, lintos, louts, lpini, lpend);
0750 if (status & m_inconsistency) {
0751 error(inconsistency(header, status, sim_hit.getCellID(), lpos, lmom));
0752 return false;
0753 }
0754 cIDs.push_back(sim_hit.getCellID());
0755 std::vector<int> subHitList;
0756 if (level() >= algorithms::LogLevel::kDebug) {
0757 subHitList.push_back(idx);
0758 }
0759
0760 bool isContinuation = status & (m_intoLower | m_intoUpper);
0761 bool hasContinuation = status & (m_outLower | m_outUpper);
0762 bool canReEnter = status & m_canReEnter;
0763 int rank = m_stripRank(vID);
0764 if (!canReEnter) {
0765 if (rank == 0 && (status & m_intoLower))
0766 isContinuation = false;
0767 if (rank == 0 && (status & m_outLower))
0768 hasContinuation = false;
0769 }
0770 if (rank == 4 && (status & m_intoUpper))
0771 isContinuation = false;
0772 if (rank == 4 && (status & m_outUpper))
0773 hasContinuation = false;
0774 if (hasContinuation) {
0775
0776 int jdx;
0777 CellID vIDPrv = vID;
0778 size_t sim_size = sim_hits->size();
0779 for (jdx = idx + 1; jdx < (int)sim_size; jdx++) {
0780 const edm4hep::SimTrackerHit& sim_hjt = sim_hits->at(jdx);
0781 CellID vJD = sim_hjt.getCellID() & m_volumeBits;
0782
0783
0784 int orientation = m_orientation(vIDPrv, vJD);
0785 bool isUpstream = m_isUpstream(orientation, status);
0786 bool pmoStatus = samePMO(sim_hit, sim_hjt);
0787 if (!pmoStatus || !isUpstream) {
0788 if ((pmoStatus && !isUpstream) && !sim_hit.isProducedBySecondary()) {
0789
0790
0791 double P = sqrt(lmom[0] * lmom[0] + lmom[1] * lmom[1] + lmom[2] * lmom[2]);
0792 if (P > 10 * dd4hep::MeV)
0793 debug(inconsistency(header, 0, sim_hit.getCellID(), lpos, lmom));
0794 }
0795 break;
0796 }
0797
0798 curVol = volman.lookupDetElement(vJD);
0799 const Tube& tubj = curVol.solid();
0800 rMin = tubj.rMin();
0801 rMax = tubj.rMax();
0802 double lpoj[3], lmoj[3];
0803 getLocalPosMom(sim_hjt, toRefVol, lpoj, lmoj);
0804
0805 double ljns[2][3], lovts[2][3], lpjni[3], lpfnd[3];
0806 status =
0807 cTraversing(lpoj, lmoj, sim_hjt.getPathLength() * ed2dd, sim_hit.isProducedBySecondary(),
0808 rMin, rMax, dZ, startPhi, endPhi, ljns, lovts, lpjni, lpfnd);
0809 if (status & m_inconsistency) {
0810 error(inconsistency(header, status, sim_hjt.getCellID(), lpoj, lmoj));
0811 break;
0812 }
0813
0814 bool jsDownstream = m_isDownstream(orientation, status);
0815 if (!jsDownstream)
0816 break;
0817
0818 double dist = outInDistance(0, orientation, ljns, louts, lmom, lmoj);
0819
0820 double P = sqrt(lmom[0] * lmom[0] + lmom[1] * lmom[1] + lmom[2] * lmom[2]);
0821 double tolerance = m_toleranceFactor(P) * 25 * dd4hep::um;
0822 bool isCompatible = dist > 0 && dist < tolerance;
0823 if (!isCompatible) {
0824 if (!sim_hit.isProducedBySecondary())
0825 debug(oddity(header, status, dist, sim_hit.getCellID(), lpos, lmom,
0826 sim_hjt.getCellID(), lpoj, lmoj));
0827 break;
0828 }
0829
0830 vIDPrv = vJD;
0831 eDep += sim_hjt.getEDep();
0832 for (int i = 0; i < 3; i++) {
0833 lpend[i] = lpfnd[i];
0834 lmend[i] = lmoj[i];
0835 }
0836
0837 cIDs.push_back(sim_hjt.getCellID());
0838 if (level() >= algorithms::LogLevel::kDebug) {
0839 subHitList.push_back(jdx);
0840 }
0841
0842 hasContinuation = status & 0xa;
0843 canReEnter = status & 0x100;
0844 if (!canReEnter && m_stripRank(vJD) == 4)
0845 hasContinuation = false;
0846 if (!hasContinuation) {
0847 jdx++;
0848 break;
0849 } else {
0850 for (int i = 0; i < 3; i++) {
0851 louts[0][i] = lovts[0][i];
0852 louts[1][i] = lovts[1][i];
0853 }
0854 }
0855 }
0856 idx = jdx - 1;
0857 }
0858
0859 if (sim_hit.isProducedBySecondary() && cIDs.size() < 2)
0860 if (denyExtension(sim_hit, tCur.rMax() - tCur.rMin())) {
0861 isContinuation = hasContinuation = false;
0862 }
0863 for (int io = 0; io < 2; io++) {
0864 if ((io == 0 && !isContinuation) || (io == 1 && !hasContinuation))
0865 continue;
0866 int direction = io ? +1 : -1;
0867 extendHit(refID, cIDs, direction, lpini, lmom, lpend, lmend);
0868 }
0869
0870 flagUnexpected(header, 0, (tRef.rMin() + tRef.rMax()) / 2, sim_hit, lpini, lpend, lpos, lmom);
0871
0872 double DoF2 = 0, dir = 0;
0873 for (int i = 0; i < 3; i++) {
0874 double neu = (lpini[i] + lpend[i]) / 2, alt = lpos[i];
0875 lpos[i] = neu;
0876 double d = neu - alt;
0877 dir += d * lmom[i];
0878 DoF2 += d * d;
0879 }
0880
0881 time += ((dir > 0) ? 1 : ((dir < 0) ? -1 : 0)) * sqrt(DoF2) / dd4hep::c_light;
0882 if (level() >= algorithms::LogLevel::kDebug) {
0883 debug("--------------------");
0884 printSubHitList(input, subHitList);
0885 debug(" =");
0886
0887 Position locPos(lpos[0], lpos[1], lpos[2]);
0888 Position globPos = refVol.nominal().localToWorld(locPos);
0889 debug(" position = ({:7.2f},{:7.2f},{:7.2f}) [mm]", globPos.X() / mm, globPos.Y() / mm,
0890 globPos.Z() / mm);
0891 debug(" edep = {:.0f} [eV]", eDep / eV);
0892 debug(" time = {:.2f} [ns]", time);
0893 }
0894 return true;
0895 }
0896 bool MPGDTrackerDigi::bCoalesceExtend(const Input& input, int& idx,
0897 std::vector<std::uint64_t>& cIDs, double* lpos, double& eDep,
0898 double& time) const {
0899 const auto [headers, sim_hits] = input;
0900 const edm4hep::EventHeader& header = headers->at(0);
0901 const edm4hep::SimTrackerHit& sim_hit = sim_hits->at(idx);
0902 CellID vID = sim_hit.getCellID() & m_volumeBits;
0903 CellID refID = vID & m_moduleBits;
0904 const VolumeManager& volman = m_detector->volumeManager();
0905 DetElement refVol = volman.lookupDetElement(refID);
0906
0907
0908 const TGeoHMatrix toRefVol = refVol.nominal().worldTransformation();
0909 double lmom[3];
0910 getLocalPosMom(sim_hit, toRefVol, lpos, lmom);
0911 const double edmm = edm4eic::unit::mm, ed2dd = dd4hep::mm / edmm;
0912 using dd4hep::mm;
0913 using edm4eic::unit::eV, edm4eic::unit::GeV;
0914
0915 eDep = sim_hit.getEDep();
0916 time = sim_hit.getTime();
0917
0918 const Box& bRef = refVol.solid();
0919 double dX = bRef.x(), dY = bRef.y();
0920
0921 DetElement curVol = volman.lookupDetElement(vID);
0922 const Box& bCur = curVol.solid();
0923 double dZ = bCur.z();
0924 double ref2Cur = getRef2Cur(refVol, curVol);
0925
0926 double lintos[2][3], louts[2][3], lpini[3], lpend[3], lmend[3];
0927 std::copy(std::begin(lmom), std::end(lmom), std::begin(lmend));
0928 unsigned int status =
0929 bTraversing(lpos, lmom, ref2Cur, sim_hit.getPathLength() * ed2dd,
0930 sim_hit.isProducedBySecondary(), dZ, dX, dY, lintos, louts, lpini, lpend);
0931 if (status & m_inconsistency) {
0932 error(inconsistency(header, status, sim_hit.getCellID(), lpos, lmom));
0933 return false;
0934 }
0935 cIDs.push_back(sim_hit.getCellID());
0936 std::vector<int> subHitList;
0937 if (level() >= algorithms::LogLevel::kDebug) {
0938 subHitList.push_back(idx);
0939 }
0940
0941 int rank = m_stripRank(vID);
0942 bool isContinuation = status & (m_intoLower | m_intoUpper);
0943 bool hasContinuation = status & (m_outLower | m_outUpper);
0944 if ((rank == 0 && (status & m_intoLower)) || (rank == 4 && (status & m_intoUpper)))
0945 isContinuation = false;
0946 if ((rank == 0 && (status & m_outLower)) || (rank == 4 && (status & m_outUpper)))
0947 hasContinuation = false;
0948 if (hasContinuation) {
0949
0950 int jdx;
0951 CellID vIDPrv = vID;
0952 size_t sim_size = sim_hits->size();
0953 for (jdx = idx + 1; jdx < (int)sim_size; jdx++) {
0954 const edm4hep::SimTrackerHit& sim_hjt = sim_hits->at(jdx);
0955 CellID vJD = sim_hjt.getCellID() & m_volumeBits;
0956 int orientation = m_orientation(vIDPrv, vJD);
0957 bool isUpstream = m_isUpstream(orientation, status);
0958 bool pmoStatus = samePMO(sim_hit, sim_hjt);
0959 if (!pmoStatus || !isUpstream) {
0960 if ((pmoStatus && !isUpstream) && !sim_hit.isProducedBySecondary()) {
0961
0962 double P = sqrt(lmom[0] * lmom[0] + lmom[1] * lmom[1] + lmom[2] * lmom[2]);
0963 if (P > 10 * dd4hep::MeV)
0964 debug(inconsistency(header, 0, sim_hit.getCellID(), lpos, lmom));
0965 }
0966 break;
0967 }
0968
0969 curVol = volman.lookupDetElement(vJD);
0970 const Box& boxj = curVol.solid();
0971 dZ = boxj.z();
0972 double ref2j = getRef2Cur(refVol, curVol);
0973
0974 double lpoj[3], lmoj[3];
0975 getLocalPosMom(sim_hjt, toRefVol, lpoj, lmoj);
0976 double ljns[2][3], lovts[2][3], lpjni[3], lpfnd[3];
0977 status = bTraversing(lpoj, lmoj, ref2j, sim_hjt.getPathLength() * ed2dd,
0978 sim_hit.isProducedBySecondary(), dZ, dX, dY, ljns, lovts, lpjni, lpfnd);
0979 if (status & m_inconsistency) {
0980 error(inconsistency(header, status, sim_hjt.getCellID(), lpoj, lmoj));
0981 break;
0982 }
0983
0984 bool jsDownstream = m_isDownstream(orientation, status);
0985 if (!jsDownstream)
0986 break;
0987
0988 double dist = outInDistance(1, orientation, ljns, louts, lmom, lmoj);
0989
0990 double P = sqrt(lmom[0] * lmom[0] + lmom[1] * lmom[1] + lmom[2] * lmom[2]);
0991 double tolerance = m_toleranceFactor(P) * 25 * dd4hep::um;
0992 bool isCompatible = dist > 0 && dist < tolerance;
0993 if (!isCompatible) {
0994 if (!sim_hit.isProducedBySecondary())
0995 debug(oddity(header, status, dist, sim_hit.getCellID(), lpos, lmom,
0996 sim_hjt.getCellID(), lpoj, lmoj));
0997 break;
0998 }
0999
1000 vIDPrv = vJD;
1001 eDep += sim_hjt.getEDep();
1002 for (int i = 0; i < 3; i++) {
1003 lpend[i] = lpfnd[i];
1004 lmend[i] = lmoj[i];
1005 }
1006
1007 cIDs.push_back(sim_hjt.getCellID());
1008 if (level() >= algorithms::LogLevel::kDebug) {
1009 subHitList.push_back(jdx);
1010 }
1011
1012 hasContinuation = status & 0xa;
1013 if (!hasContinuation) {
1014 jdx++;
1015 break;
1016 } else {
1017 for (int i = 0; i < 3; i++) {
1018 louts[0][i] = lovts[0][i];
1019 louts[1][i] = lovts[1][i];
1020 }
1021 }
1022 }
1023 idx = jdx - 1;
1024 }
1025
1026 if (sim_hit.isProducedBySecondary() && cIDs.size() < 2)
1027 if (denyExtension(sim_hit, bCur.z())) {
1028 isContinuation = hasContinuation = false;
1029 }
1030 for (int io = 0; io < 2; io++) {
1031 if ((io == 0 && !isContinuation) || (io == 1 && !hasContinuation))
1032 continue;
1033 int direction = io ? +1 : -1;
1034 extendHit(refID, cIDs, direction, lpini, lmom, lpend, lmend);
1035 }
1036
1037 flagUnexpected(header, 1, 0, sim_hit, lpini, lpend, lpos, lmom);
1038
1039 double DoF2 = 0, dir = 0;
1040 for (int i = 0; i < 3; i++) {
1041 double neu = (lpini[i] + lpend[i]) / 2, alt = lpos[i];
1042 lpos[i] = neu;
1043 double d = neu - alt;
1044 dir += d * lmom[i];
1045 DoF2 += d * d;
1046 }
1047
1048 time += ((dir > 0) ? 1 : ((dir < 0) ? -1 : 0)) * sqrt(DoF2) / dd4hep::c_light;
1049 if (level() >= algorithms::LogLevel::kDebug) {
1050 debug("--------------------");
1051 printSubHitList(input, subHitList);
1052 debug(" =");
1053
1054 Position locPos(lpos[0], lpos[1], lpos[2]);
1055 Position globPos = refVol.nominal().localToWorld(locPos);
1056 debug(" position = ({:7.2f},{:7.2f},{:7.2f}) [mm]", globPos.X() / mm, globPos.Y() / mm,
1057 globPos.Z() / mm);
1058 debug(" edep = {:.0f} [eV]", eDep / eV);
1059 debug(" time = {:.2f} [ns]", time);
1060 }
1061 return true;
1062 }
1063 void MPGDTrackerDigi::printSubHitList(const Input& input, std::vector<int>& subHitList) const {
1064 const auto [headers, sim_hits] = input;
1065 const double edmm = edm4eic::unit::mm;
1066 using edm4eic::unit::eV, edm4eic::unit::GeV;
1067 int ldx = 0;
1068 for (int kdx : subHitList) {
1069 const edm4hep::SimTrackerHit& sim_hp = sim_hits->at(kdx);
1070 CellID cIDk = sim_hp.getCellID();
1071 CellID hIDk = cIDk >> 32, vIDk = cIDk & m_volumeBits;
1072 if (ldx == 0) {
1073 debug("Hit cellID{:d} = 0x{:08x}, 0x{:08x}", ldx++, hIDk, vIDk);
1074 } else {
1075 debug(" + cellID{:d} = 0x{:08x}, 0x{:08x}", ldx++, hIDk, vIDk);
1076 }
1077 debug(" position = ({:7.2f},{:7.2f},{:7.2f}) [mm]", sim_hp.getPosition().x / edmm,
1078 sim_hp.getPosition().y / edmm, sim_hp.getPosition().z / edmm);
1079 debug(" xy_radius = {:.2f}",
1080 std::hypot(sim_hp.getPosition().x, sim_hp.getPosition().y) / edmm);
1081 debug(" momentum = ({:.2f}, {:.2f}, {:.2f}) [GeV]", sim_hp.getMomentum().x / GeV,
1082 sim_hp.getMomentum().y / GeV, sim_hp.getMomentum().z / GeV);
1083 debug(" edep = {:.0f} [eV]", sim_hp.getEDep() / eV);
1084 debug(" time = {:.2f} [ns]", sim_hp.getTime());
1085 }
1086 }
1087
1088 void getLocalPosMom(const edm4hep::SimTrackerHit& sim_hit, const TGeoHMatrix& toModule,
1089 double* lpos, double* lmom) {
1090 const edm4hep::Vector3d& pos = sim_hit.getPosition();
1091
1092 const double edmm = edm4eic::unit::mm, ed2dd = dd4hep::mm / edmm;
1093 const double gpos[3] = {pos.x * ed2dd, pos.y * ed2dd, pos.z * ed2dd};
1094 const edm4hep::Vector3f& mom = sim_hit.getMomentum();
1095 const double gmom[3] = {mom.x, mom.y, mom.z};
1096 toModule.MasterToLocal(gpos, lpos);
1097 toModule.MasterToLocalVect(gmom, lmom);
1098 }
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117 unsigned int MPGDTrackerDigi::cTraversing(const double* lpos, const double* lmom, double path,
1118 bool isSecondary,
1119 double rMin, double rMax,
1120 double dZ, double startPhi,
1121 double endPhi,
1122 double lintos[][3], double louts[][3], double* lpini,
1123 double* lpend) const {
1124 unsigned int status = 0;
1125 double Mx = lpos[0], My = lpos[1], Mz = lpos[2], M2 = Mx * Mx + My * My;
1126 double Px = lmom[0], Py = lmom[1], Pz = lmom[2];
1127
1128 double tIn = 0, tOut = 0;
1129 for (double phi : {startPhi, endPhi}) {
1130
1131 double Ux = cos(phi), Uy = sin(phi);
1132 double D = Px * Uy - Py * Ux;
1133 if (D) {
1134 double t = (My * Ux - Mx * Uy) / D;
1135 double Ex = Mx + t * Px, Ey = My + t * Py, Ez = Mz + t * Pz;
1136 double rE = sqrt(Ex * Ex + Ey * Ey), phiE = atan2(Ey, Ex);
1137
1138
1139 if (rMin < rE && rE < rMax && fabs(Ez) < dZ && fabs(phiE - phi) < 1) {
1140 if (t < 0) {
1141 status |= 0x10;
1142 tIn = t;
1143 } else {
1144 status |= 0x20;
1145 tOut = t;
1146 }
1147 }
1148 }
1149 }
1150
1151 double zLow = -dZ, zUp = +dZ;
1152 for (double Z : {zLow, zUp}) {
1153
1154 if (Pz) {
1155 double t = (Z - Mz) / Pz;
1156 double Ex = Mx + t * Px, Ey = My + t * Py, rE = sqrt(Ex * Ex + Ey * Ey);
1157 double phi = atan2(Ey, Ex);
1158 if (rMin < rE && rE < rMax && startPhi < phi && phi < endPhi) {
1159 if (t < 0) {
1160 if (!(status & 0x10) || ((status & 0x10) && t > tIn)) {
1161 status |= 0x10;
1162 tIn = t;
1163 }
1164 } else if (t > 0) {
1165 if (!(status & 0x20) || ((status & 0x20) && t < tOut)) {
1166 status |= 0x20;
1167 tOut = t;
1168 }
1169 }
1170 }
1171 }
1172 }
1173
1174 double ts[3 ][2 ] = {
1175 {0, 0}, {0, 0}, {tIn, tOut}};
1176 double a = Px * Px + Py * Py, b = Px * Mx + Py * My;
1177 for (int lu = 0; lu < 2; lu++) {
1178 double R;
1179 unsigned int statGene;
1180 if (lu == 1) {
1181 R = rMax;
1182 statGene = 0x4;
1183 } else {
1184 R = rMin;
1185 statGene = 0x1;
1186 }
1187 double c = M2 - R * R;
1188 if (!a) {
1189 if ((status & 0x30) != 0x30)
1190 status |= 0x1000;
1191 continue;
1192 } else if (!c) {
1193 status |= 0x2000;
1194 continue;
1195 } else {
1196 double det = b * b - a * c;
1197 if (det < 0) {
1198 if (lu == 1) {
1199 status |= 0x4000;
1200 continue;
1201 }
1202 } else {
1203 double sqdet = sqrt(det);
1204 for (int is = 0; is < 2; is++) {
1205 int s = 1 - 2 * is;
1206 double t = (-b + s * sqdet) / a;
1207 double Ix = Mx + t * Px, Iy = My + t * Py, Iz = Mz + t * Pz, phi = atan2(Iy, Ix);
1208 if (fabs(Iz) > dZ || phi < startPhi || endPhi < phi)
1209 continue;
1210 if (t < 0) {
1211
1212
1213
1214
1215 if (status & statGene) {
1216 double tPrv = ts[lu][0];
1217 if (t > tPrv) {
1218 ts[lu][0] = t;
1219 ts[lu][1] = tPrv;
1220 }
1221 status |= statGene << 1;
1222 } else {
1223 ts[lu][0] = t;
1224 status |= statGene;
1225 }
1226 } else {
1227 if (status & statGene << 1) {
1228 double tPrv = ts[lu][1];
1229 if (t < tPrv) {
1230 ts[lu][1] = t;
1231 ts[lu][0] = tPrv;
1232 }
1233 status |= statGene;
1234 } else {
1235 ts[lu][1] = t;
1236 status |= statGene << 1;
1237 }
1238 }
1239 }
1240 }
1241 }
1242 }
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260 bool canReEnter = (status & 0x3) == 0x3;
1261 double norm = sqrt(a + Pz * Pz);
1262 if (canReEnter) {
1263 bool doesReEnter = true;
1264 for (int i12 = 0; i12 < 2; i12++) {
1265 double t = ts[0][i12];
1266 int s = t > 0 ? +1 : -1;
1267 const double tolerance = 20 * dd4hep::um;
1268 if (path / 2 - s * t * norm < tolerance)
1269 doesReEnter = false;
1270 }
1271 if (doesReEnter) {
1272 status &= ~0x3;
1273 canReEnter = false;
1274 }
1275 }
1276 double rHit = sqrt(M2);
1277 if (rHit < rMin && !canReEnter) {
1278 unsigned int statvs = status;
1279 if (statvs & 0x1) {
1280 status &= ~0x1;
1281 status |= 0x2;
1282 ts[0][1] = -ts[0][0];
1283 }
1284 if (statvs & 0x2) {
1285 status &= ~0x2;
1286 status |= 0x1;
1287 ts[0][0] = -ts[0][1];
1288 }
1289 } else if (rHit > rMax) {
1290 unsigned int statvs = status;
1291 if (statvs & 0x4) {
1292 status &= ~0x4;
1293 status |= 0x8;
1294 ts[1][1] = -ts[1][0];
1295 }
1296 if (statvs & 0x8) {
1297 status &= ~0x8;
1298 status |= 0x4;
1299 ts[1][0] = -ts[1][1];
1300 }
1301 }
1302 for (int lu = 0; lu < 2; lu++) {
1303 unsigned int statGene = lu ? 0x4 : 0x1;
1304 if (status & statGene) {
1305 double t = ts[lu][0];
1306 if (t < 0) {
1307 if (status & 0x10) {
1308 if (lu == 1 || !canReEnter) {
1309 status |= 0x10000;
1310 status &= ~statGene;
1311 } else {
1312 if (t < tIn)
1313 status |= 0x10000;
1314 }
1315 }
1316 } else {
1317 if (status & 0x20) {
1318 if (lu == 1 || !canReEnter) {
1319 status |= 0x20000;
1320 status &= ~statGene;
1321 } else {
1322 if (t > tOut)
1323 status |= 0x20000;
1324 }
1325 }
1326 }
1327 }
1328 if (status & statGene << 1) {
1329 double t = ts[lu][1];
1330 if (t < 0) {
1331 if (status & 0x10) {
1332 if (lu == 1 || !canReEnter) {
1333 status |= 0x40000;
1334 status &= ~(statGene << 1);
1335 } else {
1336 if (t < tIn)
1337 status |= 0x40000;
1338 }
1339 }
1340 } else {
1341 if (status & 0x20) {
1342 if (lu == 1 || !canReEnter) {
1343 status |= 0x80000;
1344 status &= ~(statGene << 1);
1345 } else {
1346 if (t > tOut)
1347 status |= 0x80000;
1348 }
1349 }
1350 }
1351 }
1352 }
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362 if (canReEnter)
1363 status |= 0x100;
1364 double at = path / 2 / norm;
1365 unsigned int statws = 0;
1366 for (int is = 0; is < 2; is++) {
1367 int s = 1 - 2 * is;
1368 double Ix = s * at * Px, Iy = s * at * Py, Iz = s * at * Pz;
1369 for (int lu = 0; lu < 2; lu++) {
1370 unsigned int statvs = lu ? 0x4 : 0x1;
1371 for (int io = 0; io < 2; io++) {
1372 statvs <<= io;
1373 if (status & statvs) {
1374 double t = ts[lu][io];
1375 if (t * s < 0)
1376 continue;
1377 double dIx = t * Px - Ix, dIy = t * Py - Iy, dIz = t * Pz - Iz;
1378 double dist = sqrt(dIx * dIx + dIy * dIy + dIz * dIz);
1379
1380 double tolerance = m_toleranceFactor(norm) * 20 * dd4hep::um;
1381 if (dist < tolerance)
1382 statws |= statvs;
1383 }
1384 }
1385 }
1386 }
1387 if (!(statws & 0x5))
1388 status &= ~0x5;
1389 if (!(statws & 0xa))
1390 status &= ~0xa;
1391
1392
1393
1394 if (((status & 0x5) == 0x1 || (status & 0x5) == 0x4) && !isSecondary) {
1395 double tIn = (status & 0x1) ? ts[0][0] : ts[1][0];
1396 lpini[0] = Mx + tIn * Px;
1397 lpini[1] = My + tIn * Py;
1398 lpini[2] = Mz + tIn * Pz;
1399 } else {
1400 lpini[0] = Mx - at * Px;
1401 lpini[1] = My - at * Py;
1402 lpini[2] = Mz - at * Pz;
1403 }
1404 if (((status & 0xa) == 0x2 || (status & 0xa) == 0x8) && !isSecondary) {
1405 double tOut = (status & 0x2) ? ts[0][1] : ts[1][1];
1406 lpend[0] = Mx + tOut * Px;
1407 lpend[1] = My + tOut * Py;
1408 lpend[2] = Mz + tOut * Pz;
1409 } else {
1410 lpend[0] = Mx + at * Px;
1411 lpend[1] = My + at * Py;
1412 lpend[2] = Mz + at * Pz;
1413 }
1414
1415 for (int lu = 0; lu < 2; lu++) {
1416 unsigned int statvs = lu ? 0x4 : 0x1;
1417 double tIn = ts[lu][0], tOut = ts[lu][1];
1418 if (status & statvs) {
1419 lintos[lu][0] = Mx + tIn * Px;
1420 lintos[lu][1] = My + tIn * Py;
1421 lintos[lu][2] = Mz + tIn * Pz;
1422 }
1423 statvs <<= 1;
1424 if (status & statvs) {
1425 louts[lu][0] = Mx + tOut * Px;
1426 louts[lu][1] = My + tOut * Py;
1427 louts[lu][2] = Mz + tOut * Pz;
1428 }
1429 }
1430 return status;
1431 }
1432 unsigned int MPGDTrackerDigi::bTraversing(const double* lpos, const double* lmom, double ref2Cur,
1433 double path,
1434 bool isSecondary,
1435 double dZ,
1436 double dX, double dY,
1437 double lintos[][3], double louts[][3], double* lpini,
1438 double* lpend) const {
1439 unsigned int status = 0;
1440 double Mx = lpos[0], My = lpos[1], Mxy[2] = {Mx, My};
1441 double Px = lmom[0], Py = lmom[1], Pxy[2] = {Px, Py};
1442 double Mz = lpos[2] + ref2Cur, Pz = lmom[2];
1443
1444 double tIn = 0, tOut = 0;
1445 double xyLow[2] = {-dX, -dY}, xyUp[2] = {+dX, +dY};
1446 for (int xy = 0; xy < 2; xy++) {
1447 int yx = 1 - xy;
1448 double a_Low = xyLow[xy], a_Up = xyUp[xy], Ma = Mxy[xy], Pa = Pxy[xy];
1449 double b_Low = xyLow[yx], b_Up = xyUp[yx], Mb = Mxy[yx], Pb = Pxy[yx];
1450 for (double A : {a_Low, a_Up}) {
1451
1452 if (Pa) {
1453 double t = (A - Ma) / Pa;
1454 double Eb = Mb + t * Pb, Ez = Mz + t * Pz;
1455 if (b_Low < Eb && Eb < b_Up && fabs(Ez) < dZ) {
1456 if (t < 0) {
1457 if (!(status & 0x10) || ((status & 0x10) && t > tIn)) {
1458 status |= 0x10;
1459 tIn = t;
1460 }
1461 } else if (t > 0) {
1462 if (!(status & 0x20) || ((status & 0x20) && t < tOut)) {
1463 status |= 0x20;
1464 tOut = t;
1465 }
1466 }
1467 }
1468 }
1469 }
1470 }
1471
1472 for (int lu = 0; lu < 2; lu++) {
1473 int s = 2 * lu - 1;
1474 double Z = s * dZ;
1475 unsigned int statGene = lu ? 0x4 : 0x1;
1476
1477 if (Pz) {
1478 double t = (Z - Mz) / Pz;
1479 if (t < 0) {
1480 if (!(status & 0x10) || ((status & 0x10) && t > tIn)) {
1481 status |= statGene;
1482 tIn = t;
1483 }
1484 } else if (t > 0) {
1485 if (!(status & 0x20) || ((status & 0x20) && t < tOut)) {
1486 status |= statGene << 1;
1487 tOut = t;
1488 }
1489 }
1490 }
1491 }
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501 double norm = sqrt(Px * Px + Py * Py + Pz * Pz), at = path / 2 / norm;
1502 unsigned int statws = 0;
1503 for (int is = 0; is < 2; is++) {
1504 int s = 1 - 2 * is;
1505 double Ix = s * at * Px, Iy = s * at * Py, Iz = s * at * Pz;
1506 for (int lu = 0; lu < 2; lu++) {
1507 unsigned int statvs = lu ? 0x4 : 0x1;
1508 for (int io = 0; io < 2; io++) {
1509 statvs <<= io;
1510 if (status & statvs) {
1511 double t = io ? tOut : tIn;
1512 if (t * s < 0)
1513 continue;
1514 double dIx = t * Px - Ix, dIy = t * Py - Iy, dIz = t * Pz - Iz;
1515 double dist = sqrt(dIx * dIx + dIy * dIy + dIz * dIz);
1516
1517 double tolerance = m_toleranceFactor(norm) * 20 * dd4hep::um;
1518 if (dist < tolerance)
1519 statws |= statvs;
1520 }
1521 }
1522 }
1523 }
1524 if (!(statws & 0x5))
1525 status &= ~0x5;
1526 if (!(statws & 0xa))
1527 status &= ~0xa;
1528
1529 Mz -= ref2Cur;
1530
1531
1532 if ((status & 0x5) && !isSecondary) {
1533 lpini[0] = Mx + tIn * Px;
1534 lpini[1] = My + tIn * Py;
1535 lpini[2] = Mz + tIn * Pz;
1536 } else {
1537 lpini[0] = Mx - at * Px;
1538 lpini[1] = My - at * Py;
1539 lpini[2] = Mz - at * Pz;
1540 }
1541 if ((status & 0xa) && !isSecondary) {
1542 lpend[0] = Mx + tOut * Px;
1543 lpend[1] = My + tOut * Py;
1544 lpend[2] = Mz + tOut * Pz;
1545 } else {
1546 lpend[0] = Mx + at * Px;
1547 lpend[1] = My + at * Py;
1548 lpend[2] = Mz + at * Pz;
1549 }
1550
1551 for (int lu = 0; lu < 2; lu++) {
1552 unsigned int statvs = lu ? 0x4 : 0x1;
1553 if (status & statvs) {
1554 lintos[lu][0] = Mx + tIn * Px;
1555 lintos[lu][1] = My + tIn * Py;
1556 lintos[lu][2] = Mz + tIn * Pz;
1557 }
1558 statvs <<= 1;
1559 if (status & statvs) {
1560 louts[lu][0] = Mx + tOut * Px;
1561 louts[lu][1] = My + tOut * Py;
1562 louts[lu][2] = Mz + tOut * Pz;
1563 }
1564 }
1565 return status;
1566 }
1567
1568
1569 bool cExtrapolate(const double* lpos, const double* lmom,
1570 double rT,
1571 double* lext)
1572 {
1573 bool ok = false;
1574 double Mx = lpos[0], My = lpos[1], Mz = lpos[2], M2 = Mx * Mx + My * My;
1575 double Px = lmom[0], Py = lmom[1], Pz = lmom[2];
1576 double a = Px * Px + Py * Py, b = Px * Mx + Py * My, c = M2 - rT * rT;
1577 double tF = 0;
1578 if (!c)
1579 ok = true;
1580 else if (a) {
1581 double det = b * b - a * c;
1582 if (det >= 0) {
1583 double sqdet = sqrt(det);
1584 for (int is = 0; is < 2; is++) {
1585 int s = 1 - 2 * is;
1586 double t = (-b + s * sqdet) / a, norm = sqrt(a + Pz * Pz);
1587
1588 if (t * norm < -dd4hep::nm)
1589 continue;
1590 if (!ok ||
1591
1592 (ok && fabs(t) < fabs(tF))) {
1593 tF = t;
1594 ok = true;
1595 }
1596 }
1597 }
1598 }
1599 if (ok) {
1600 lext[0] = Mx + tF * Px;
1601 lext[1] = My + tF * Py;
1602 lext[2] = Mz + tF * Pz;
1603 }
1604 return ok;
1605 }
1606 bool bExtrapolate(const double* lpos, const double* lmom,
1607 double zT,
1608 double* lext)
1609 {
1610 bool ok = false;
1611 double Mx = lpos[0], My = lpos[1], Mz = lpos[2];
1612 double Px = lmom[0], Py = lmom[1], Pz = lmom[2], norm = sqrt(Px * Px + Py * Py + Pz * Pz);
1613 double tF = 0;
1614 if (Pz) {
1615 tF = (zT - Mz) / Pz;
1616
1617 ok = tF * norm > -dd4hep::nm;
1618 }
1619 if (ok) {
1620 lext[0] = Mx + tF * Px;
1621 lext[1] = My + tF * Py;
1622 lext[2] = Mz + tF * Pz;
1623 }
1624 return ok;
1625 }
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636 unsigned int MPGDTrackerDigi::cExtension(double const* lpos, double const* lmom,
1637 double rT, int direction,
1638 double dZ, double startPhi,
1639 double endPhi,
1640 double* lext) const {
1641 unsigned int status = 0;
1642 double Mx = lpos[0], My = lpos[1], Mz = lpos[2];
1643 double Px = lmom[0], Py = lmom[1], Pz = lmom[2], norm = sqrt(Px * Px + Py * Py + Pz * Pz);
1644
1645
1646 const double margin = 10 * dd4hep::um;
1647 double t = direction * margin / norm;
1648 Mx += t * Px;
1649 My += t * Py;
1650 Mz += t * Pz;
1651 double M2 = Mx * Mx + My * My, rIni = sqrt(M2), rLow, rUp;
1652 if (rIni < rT) {
1653 rLow = rIni;
1654 rUp = rT;
1655 } else {
1656 rLow = rT;
1657 rUp = rIni;
1658 }
1659
1660 double tF = 0;
1661 for (double phi : {startPhi, endPhi}) {
1662
1663 double Ux = cos(phi), Uy = sin(phi);
1664 double D = Px * Uy - Py * Ux;
1665 if (D) {
1666 double t = (My * Ux - Mx * Uy) / D;
1667 if (t * direction < 0)
1668 continue;
1669 double Ex = Mx + t * Px, Ey = My + t * Py, Ez = Mz + t * Pz;
1670 double rE = sqrt(Ex * Ex + Ey * Ey), phiE = atan2(Ey, Ex);
1671
1672 if (rLow < rE && rE < rUp && fabs(Ez) < dZ && fabs(phiE - phi) < 1) {
1673 status |= 0x1;
1674 tF = t;
1675 }
1676 }
1677 }
1678
1679 double zLow = -dZ, zUp = +dZ;
1680 for (double Z : {zLow, zUp}) {
1681
1682 if (Pz) {
1683 double t = (Z - Mz) / Pz;
1684 if (t * direction < 0)
1685 continue;
1686 double Ex = Mx + t * Px, Ey = My + t * Py, rE = sqrt(Ex * Ex + Ey * Ey);
1687 double phi = atan2(Ey, Ex);
1688 if (rLow < rE && rE < rUp && startPhi < phi && phi < endPhi) {
1689 if (t < 0) {
1690 if (!status || (status && t > tF)) {
1691 status |= 0x1;
1692 tF = t;
1693 }
1694 } else if (t > 0) {
1695 if (!status || (status && t < tF)) {
1696 status |= 0x1;
1697 tF = t;
1698 }
1699 }
1700 }
1701 }
1702 }
1703
1704 if (!status) {
1705 double a = Px * Px + Py * Py, b = Px * Mx + Py * My, c = M2 - rT * rT;
1706 if (!a) {
1707 status |= 0x1000;
1708 } else if (!c) {
1709 status |= 0x2000;
1710 } else {
1711 double det = b * b - a * c;
1712 if (det >= 0) {
1713 double sqdet = sqrt(det);
1714 for (int is = 0; is < 2; is++) {
1715 int s = 1 - 2 * is;
1716 double t = (-b + s * sqdet) / a;
1717 if (t * direction < 0)
1718 continue;
1719 double Ix = Mx + t * Px, Iy = My + t * Py, Iz = Mz + t * Pz, phi = atan2(Iy, Ix);
1720 if (fabs(Iz) > dZ || phi < startPhi || endPhi < phi)
1721 continue;
1722 if (!(status & 0x1) ||
1723
1724 ((status & 0x1) && fabs(t) < fabs(tF))) {
1725 tF = t;
1726 status |= 0x1;
1727 }
1728 }
1729 }
1730 }
1731 }
1732 if (status & 0x1) {
1733 lext[0] = Mx + tF * Px;
1734 lext[1] = My + tF * Py;
1735 lext[2] = Mz + tF * Pz;
1736 }
1737 return status;
1738 }
1739 unsigned int MPGDTrackerDigi::bExtension(const double* lpos, const double* lmom,
1740 double zT, int direction,
1741 double dX, double dY,
1742 double* lext) const {
1743 unsigned int status = 0;
1744 double Mx = lpos[0], My = lpos[1], Mxy[2] = {Mx, My};
1745 double Px = lmom[0], Py = lmom[1], Pxy[2] = {Px, Py};
1746 double Mz = lpos[2], Pz = lmom[2];
1747 double norm = sqrt(Px * Px + Py * Py + Pz * Pz);
1748
1749
1750 const double margin = 10 * dd4hep::um;
1751 double t = direction * margin / norm;
1752 Mx += t * Px;
1753 My += t * Py;
1754 Mz += t * Pz;
1755 double &zIni = Mz, zLow, zUp;
1756 if (zIni < zT) {
1757 zLow = zIni;
1758 zUp = zT;
1759 } else {
1760 zLow = zT;
1761 zUp = zIni;
1762 }
1763
1764 double tF = 0;
1765 double xyLow[2] = {-dX, -dY}, xyUp[2] = {+dX, +dY};
1766 for (int xy = 0; xy < 2; xy++) {
1767 int yx = 1 - xy;
1768 double a_Low = xyLow[xy], a_Up = xyUp[xy], Ma = Mxy[xy], Pa = Pxy[xy];
1769 double b_Low = xyLow[yx], b_Up = xyUp[yx], Mb = Mxy[yx], Pb = Pxy[yx];
1770 for (double A : {a_Low, a_Up}) {
1771
1772 if (Pa) {
1773 double t = (A - Ma) / Pa;
1774 if (t * direction < 0)
1775 continue;
1776 double Eb = Mb + t * Pb, Ez = Mz + t * Pz;
1777 if (zLow < Ez && Ez < zUp && b_Low < Eb && Eb < b_Up) {
1778 if (!status || (status && fabs(t) < fabs(tF))) {
1779 status |= 0x1;
1780 tF = t;
1781 }
1782 }
1783 }
1784 }
1785 }
1786
1787 if (!status) {
1788 if (Pz) {
1789 tF = (zT - Mz) / Pz;
1790 if (tF * direction > 0)
1791 status = 0x1;
1792 }
1793 }
1794 if (status) {
1795 lext[0] = Mx + tF * Px;
1796 lext[1] = My + tF * Py;
1797 lext[2] = Mz + tF * Pz;
1798 }
1799 return status;
1800 }
1801
1802 double getRef2Cur(DetElement refVol, DetElement curVol) {
1803
1804
1805 const TGeoHMatrix toRefVol = refVol.nominal().worldTransformation();
1806 const TGeoHMatrix toCurVol = curVol.nominal().worldTransformation();
1807 const double* TRef = toRefVol.GetTranslation();
1808 const double* TCur = toCurVol.GetTranslation();
1809
1810 double gdT[3];
1811 for (int i = 0; i < 3; i++)
1812 gdT[i] = TRef[i] - TCur[i];
1813 double ldT[3];
1814 toRefVol.MasterToLocalVect(gdT, ldT);
1815 return ldT[2];
1816 }
1817
1818 std::string inconsistency(const edm4hep::EventHeader& event, unsigned int status, CellID cID,
1819 const double* lpos, const double* lmom) {
1820 using edm4eic::unit::GeV, dd4hep::mm;
1821 return std::format("Event {}#{}, SimHit 0x{:016x} @ {:.2f},{:.2f},{:.2f} mm, P = "
1822 "{:.2f},{:.2f},{:.2f} GeV inconsistency 0x{:x}",
1823 event.getRunNumber(), event.getEventNumber(), cID, lpos[0] / mm, lpos[1] / mm,
1824 lpos[2] / mm, lmom[0] / GeV, lmom[1] / GeV, lmom[2] / GeV, status);
1825 }
1826 std::string oddity(const edm4hep::EventHeader& event, unsigned int status, double dist, CellID cID,
1827 const double* lpos, const double* lmom, CellID cJD, const double* lpoj,
1828 const double* lmoj) {
1829 using edm4eic::unit::GeV, dd4hep::mm;
1830 return std::format("Event {}#{}, Bizarre SimHit sequence: 0x{:016x} @ {:.4f},{:.4f},{:.4f} mm, P "
1831 "= {:.2f},{:.2f},{:.2f} GeV and 0x{:016x} @ {:.4f},{:.4f},{:.4f} mm, P = "
1832 "{:.2f},{:.2f},{:.2f} GeV: status 0x{:x}, distance {:.4f}",
1833 event.getRunNumber(), event.getEventNumber(), cID, lpos[0] / mm, lpos[1] / mm,
1834 lpos[2] / mm, lmom[0] / GeV, lmom[1] / GeV, lmom[2] / GeV, cJD, lpoj[0] / mm,
1835 lpoj[1] / mm, lpoj[2] / mm, lmoj[0] / GeV, lmoj[1] / GeV, lmoj[2] / GeV,
1836 status, dist);
1837 }
1838
1839 bool MPGDTrackerDigi::samePMO(const edm4hep::SimTrackerHit& sim_hit,
1840 const edm4hep::SimTrackerHit& sim_hjt) const {
1841
1842
1843
1844
1845 bool sameParticle = sim_hjt.getParticle() == sim_hit.getParticle();
1846
1847 CellID vID = sim_hit.getCellID() & m_volumeBits;
1848 CellID refID = vID & m_moduleBits;
1849 CellID vJD = sim_hjt.getCellID() & m_volumeBits;
1850 CellID refJD = vJD & m_moduleBits;
1851 bool sameModule = refJD == refID;
1852
1853
1854
1855 bool isSecondary = sim_hit.isProducedBySecondary();
1856 bool jsSecondary = sim_hjt.isProducedBySecondary();
1857 bool sameOrigin = jsSecondary == isSecondary;
1858 return sameParticle && sameModule && sameOrigin;
1859 }
1860
1861 double outInDistance(int shape, int orientation, double lintos[][3], double louts[][3],
1862 double* lmom, double* lmoj) {
1863
1864 bool ok;
1865 double lExt[3];
1866 double lmOI[3];
1867 for (int i = 0; i < 3; i++)
1868 lmOI[i] = (lmom[i] + lmoj[i]) / 2;
1869 double *lOut, *lInto;
1870 if (orientation > 0) {
1871 lOut = louts[1];
1872 lInto = lintos[0];
1873 } else if (orientation < 0) {
1874 lOut = louts[0];
1875 lInto = lintos[1];
1876 } else {
1877 lOut = louts[0];
1878 lInto = lintos[0];
1879 }
1880 if (shape == 0) {
1881 double rInto = sqrt(lInto[0] * lInto[0] + lInto[1] * lInto[1]);
1882 ok = cExtrapolate(lOut, lmOI, rInto, lExt);
1883 } else {
1884 ok = bExtrapolate(lOut, lmOI, lInto[2], lExt);
1885 }
1886 if (ok) {
1887 double dist2 = 0;
1888 for (int i = 0; i < 3; i++) {
1889 double d = lExt[i] - lInto[i];
1890 dist2 += d * d;
1891 }
1892 return sqrt(dist2);
1893 } else
1894 return -1;
1895 }
1896
1897 unsigned int MPGDTrackerDigi::extendHit(CellID refID, std::vector<std::uint64_t>& cIDs,
1898 int direction, double* lpini, double* lmini, double* lpend,
1899 double* lmend) const {
1900 unsigned int status = 0;
1901 const VolumeManager& volman = m_detector->volumeManager();
1902 DetElement refVol = volman.lookupDetElement(refID);
1903 const auto& shape = refVol.solid();
1904 double *lpoE, *lmoE;
1905 if (direction < 0) {
1906 lpoE = lpini;
1907 lmoE = lmini;
1908 } else {
1909 lpoE = lpend;
1910 lmoE = lmend;
1911 }
1912
1913
1914
1915
1916
1917
1918
1919 for (int rankE : {0, 4}) {
1920 CellID vIDE = refID | m_stripIDs[rankE];
1921 int alreadyThere = 0;
1922 for (int i = 0; i < (int)cIDs.size(); i++) {
1923 if ((cIDs[i] & m_volumeBits) == vIDE) {
1924 alreadyThere = 1;
1925 break;
1926 }
1927 }
1928 if (alreadyThere)
1929 continue;
1930 if (std::find(cIDs.begin(), cIDs.end(), vIDE) != cIDs.end())
1931 continue;
1932 DetElement volE = volman.lookupDetElement(vIDE);
1933 double lext[3];
1934 if (std::string_view{shape.type()} == "TGeoTubeSeg") {
1935 const Tube& tExt = volE.solid();
1936 double R = rankE == 0 ? tExt.rMin() : tExt.rMax();
1937 double startPhi = tExt.startPhi() * radian;
1938 startPhi -= 2 * TMath::Pi();
1939 double endPhi = tExt.endPhi() * radian;
1940 endPhi -= 2 * TMath::Pi();
1941 double dZ = tExt.dZ();
1942 status = cExtension(lpoE, lmoE, R, direction, dZ, startPhi, endPhi, lext);
1943 } else if (std::string_view{shape.type()} == "TGeoBBox") {
1944 double ref2E = getRef2Cur(refVol, volE);
1945 const Box& bExt = volE.solid();
1946 double Z = rankE == 0 ? -bExt.z() : +bExt.z();
1947 Z -= ref2E;
1948 double dX = bExt.x(), dY = bExt.y();
1949 status = bExtension(lpoE, lmoE, Z, direction, dX, dY, lext);
1950 } else {
1951 critical(R"(Bad input data: CellID {:x} has invalid shape "{}")", refID, shape.type());
1952 throw std::runtime_error(R"(Inconsistency: Inappropriate SimHits fed to "MPGDTrackerDigi".)");
1953 }
1954 if (status != 0x1)
1955 continue;
1956 if (direction < 0) {
1957 for (int i = 0; i < 3; i++)
1958 lpini[i] = lext[i];
1959 } else {
1960 for (int i = 0; i < 3; i++)
1961 lpend[i] = lext[i];
1962 }
1963 break;
1964 }
1965 return status;
1966 }
1967
1968 bool MPGDTrackerDigi::denyExtension(const edm4hep::SimTrackerHit& sim_hit, double depth) const {
1969
1970
1971
1972 CellID vID = sim_hit.getCellID() & m_volumeBits;
1973 bool isHelperVolume = m_stripRank(vID) != 0 && m_stripRank(vID) != 4;
1974
1975
1976 const double fraction = .10;
1977 const double edmm = edm4eic::unit::mm, ed2dd = dd4hep::mm / edmm;
1978 bool smallPathLength = sim_hit.getPathLength() * ed2dd < fraction * depth;
1979 return isHelperVolume || smallPathLength;
1980 }
1981
1982 void MPGDTrackerDigi::flagUnexpected(const edm4hep::EventHeader& event, int shape, double expected,
1983 const edm4hep::SimTrackerHit& sim_hit, double* lpini,
1984 double* lpend, double* lpos, double* lmom) const {
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995 double Rnew2 = 0, Znew, diff2 = 0;
1996 for (int i = 0; i < 3; i++) {
1997 double neu = (lpini[i] + lpend[i]) / 2, alt = lpos[i];
1998 double d = neu - alt;
1999 diff2 += d * d;
2000 if (i != 2)
2001 Rnew2 += neu * neu;
2002 if (i == 2)
2003 Znew = neu;
2004 }
2005 double found = shape ? Znew : sqrt(Rnew2), residual = found - expected;
2006 bool isSecondary = sim_hit.isProducedBySecondary();
2007 bool isPrimary =
2008 !isSecondary && sqrt(lmom[0] * lmom[0] + lmom[1] * lmom[1] + lmom[2] * lmom[2]) > .1 * GeV;
2009 if ((fabs(residual) > .000001 && isPrimary) || (sqrt(diff2) > .000001 && isSecondary)) {
2010 debug("Event {}#{}, SimHit 0x{:016x} origin {:d}: d{:c} = {:.5f} diff = {:.5f}",
2011 event.getRunNumber(), event.getEventNumber(), sim_hit.getCellID(), isSecondary,
2012 shape ? 'Z' : 'R', residual, sqrt(diff2));
2013 }
2014 }
2015
2016
2017
2018
2019
2020 int MPGDTrackerDigi::get2HitCluster(CellID refID,
2021 Position& locPos,
2022 double surfPos[2],
2023 int pn,
2024 std::default_random_engine& generator, Cluster& cluster) const {
2025
2026
2027 CellID stripID = m_stripIDs[pn ? 3 : 1];
2028 const Position dummy(0, 0, 0);
2029 CellID masterID = m_seg->cellID(locPos, dummy, refID | stripID);
2030
2031 const StripParameters* pars;
2032 CellID sensorStripID = masterID & m_sensorStripBits;
2033 try {
2034 pars = &m_stripParameters.at(sensorStripID);
2035 } catch (const std::out_of_range& oor) {
2036 critical(R"(Error retrieving StripParameters for readout "{}", cellID 0x{:0>16x}: {}.)",
2037 m_cfg.readout, masterID, oor.what());
2038 throw std::runtime_error("Error retrieving StripParameters");
2039 }
2040
2041
2042
2043
2044
2045 const double& sigma = m_cfg.stripResolutions[pn];
2046 const double min = pars->min, max = pars->max, pitch = pars->pitch;
2047 double hA = surfPos[pn];
2048 if (hA < min - (m_truncation - .1 * dd4hep::cm) * sigma ||
2049 hA > max + (m_truncation - .1 * dd4hep::cm) * sigma) {
2050
2051
2052
2053
2054
2055
2056 return 1;
2057 }
2058 FieldID stripNum = m_id_dec->get(masterID, pars->index);
2059 double mA = m_binToPosition(stripNum, pitch, pars->offset);
2060 std::normal_distribution<double> gaussian;
2061 auto stripGauss = [&](double abscissa, double sigma, double min, double max) {
2062
2063 double low = abscissa - m_truncation * sigma;
2064 double up = abscissa + m_truncation * sigma;
2065 if (min > low)
2066 low = min;
2067 if (max < up)
2068 up = max;
2069 double x;
2070 do {
2071 x = abscissa + gaussian(generator) * sigma;
2072 } while (x < low || up < x);
2073 return x;
2074 };
2075 double sA = stripGauss(hA, sigma, min, max);
2076
2077
2078 if (sA < min + pitch / 2 || sA > max - pitch / 2) {
2079
2080 cluster.push_back({masterID, 1});
2081 } else {
2082
2083 CellID neighID, inc = m_stripIncs[pn];
2084 double nA;
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094 auto incrementID = [&](int pn) {
2095 CellID spectatorBits = pn == 0 ? ((CellID)0xffff) << 48 : ((CellID)0xffff) << 32;
2096 CellID iniID = masterID & spectatorBits;
2097 neighID = masterID + inc;
2098 neighID &= ~spectatorBits;
2099 neighID |= iniID;
2100 };
2101 auto decrementID = [&](int pn) {
2102 CellID spectatorBits = pn == 0 ? ((CellID)0xffff) << 48 : ((CellID)0xffff) << 32;
2103 CellID iniID = masterID & spectatorBits;
2104 neighID = masterID - inc;
2105 neighID &= ~spectatorBits;
2106 neighID |= iniID;
2107 };
2108 if (sA < mA) {
2109 decrementID(pn);
2110 nA = mA - pitch;
2111 } else {
2112 incrementID(pn);
2113 nA = mA + pitch;
2114 }
2115
2116 double fn = (sA - mA) / (nA - mA);
2117 cluster.push_back({masterID, 1 - fn});
2118 cluster.push_back({neighID, fn});
2119 }
2120 return 0;
2121 }
2122
2123 }