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