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