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