Scfi Img CrossSystem Topo Clustering (#2861) - #2865
Conversation
### Briefly, what does this PR introduce? Please link to any relevant presentations or discussions. ### What is the urgency of this PR? - [ ] High (please describe reason below) - [x] Medium - [ ] Low ### What kind of change does this PR introduce? - [ ] Bug fix (issue #__) - [x] New feature (issue #__) - [ ] Optimization (issue #__) - [ ] Updated parameters, constants (issue #__) - [ ] Updated documentation - [ ] other: __ ### Please check if any of the following apply - [ ] This PR requires changes to geometry (epic PR: __) - [ ] This PR requires changes to EDM4eic (EDM PR: __) - [ ] This PR introduces breaking changes. Please describe changes users need to make below. - [ ] This PR changes default behavior. Please describe changes below. - [ ] AI was used in preparing this PR. Please describe usage below. --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Wouter Deconinck <wdconinc@gmail.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR enables topological clustering across SciFi and Imaging calorimeter hits (notably in BEMC) by introducing combined hit collections and extending the topo clustering + CoG reconstruction logic to be “system-aware” via DD4hep cellID decoding.
Changes:
- Add
readoutfields to clustering/reco configs and use DD4hepIDDescriptorto decodesystemfor cross-system / system-specific behavior. - Extend
ImagingTopoClusterto cluster per system and optionally merge SciFi+Imaging clusters, and add combined hit/link/association collections in the BEMC plugin. - Update algorithm unit tests to provide the new
readoutconfiguration.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| src/tests/algorithms_test/particle_flow_TrackProtoClusterMatchPromoter.cc | Updates test config to set readout for CoG cluster reco. |
| src/tests/algorithms_test/calorimetry_ImagingTopoCluster.cc | Updates topo clustering test to set readout and new mode/distance fields. |
| src/tests/algorithms_test/calorimetry_CalorimeterClusterRecoCoG.cc | Updates CoG clustering test to set readout. |
| src/detectors/BEMC/BEMC.cc | Adds merged SciFi+Imaging hit/link/association collections and runs topo clustering + CoG on the combined collection. |
| src/algorithms/calorimetry/ImagingTopoClusterConfig.h | Expands config to include readout, additional system-specific parameters, and new xz layer mode. |
| src/algorithms/calorimetry/ImagingTopoCluster.h | Adds geometry/ID decoding state and cross-system neighbor helper declarations. |
| src/algorithms/calorimetry/ImagingTopoCluster.cc | Implements system-aware grouping/merging and readout-based ID decoding. |
| src/algorithms/calorimetry/CalorimeterClusterRecoCoGConfig.h | Adds readout to support system-aware behavior. |
| src/algorithms/calorimetry/CalorimeterClusterRecoCoG.h | Adds geometry/ID decoding state used by system-aware weighting. |
| src/algorithms/calorimetry/CalorimeterClusterRecoCoG.cc | Implements system-aware energy/position weighting based on decoded system IDs. |
Suppressed comments (2)
src/algorithms/calorimetry/ImagingTopoCluster.cc:337
- Typo in the exception message: it says the expected tuple is "(x_dist, y_dist, y_dist)" but the third component is z_dist.
const std::string msg =
"Expected 3 values (x_dist, y_dist, y_dist) for ScFi_diffLayerDistXYZ";
error(msg);
src/algorithms/calorimetry/ImagingTopoCluster.cc:432
- Typo in the exception message: it says the expected tuple is "(x_dist, y_dist, y_dist)" but the third component is z_dist.
const std::string msg = "Expected 3 values (x_dist, y_dist, y_dist) for Img_diffLayerDistXYZ";
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| inline int getSystemID(const edm4eic::CalorimeterHit& hit, const dd4hep::IDDescriptor& m_idSpec) { | ||
| static thread_local auto* sys_field = m_idSpec.field("system"); | ||
| return sys_field->value(hit.getCellID()); | ||
| } |
| bool hasSciFi = false; | ||
| bool hasImaging = false; | ||
|
|
||
| for (auto& hit : pcl.getHits()) { | ||
| if (isSciFiHit(hit, m_idSpec)) | ||
| hasSciFi = true; | ||
| if (isImagingHit(hit, m_idSpec)) | ||
| hasImaging = true; | ||
| } | ||
|
|
||
| bool specialMode = hasSciFi && hasImaging; | ||
|
|
|
|
||
| totalE += energy; | ||
| time += (hit.getTime() - time) * energy / totalE; | ||
|
|
| m_detector = algorithms::GeoSvc::instance().detector(); | ||
| if (!m_detector) { | ||
| error("Failed to get detector from GeometrySvc for readout '{}'", m_cfg.readout); | ||
| throw std::runtime_error("Detector not available"); | ||
| } | ||
|
|
||
| m_idSpec = m_detector->readout(m_cfg.readout).idSpec(); | ||
|
|
| case ImagingTopoClusterConfig::ELayerMode::xyz: | ||
| if (m_cfg.diffLayerDistXYZ.size() != 3) { | ||
| const std::string msg = "Expected 3 values (x_dist, y_dist, z_dist) for diffLayerDistXYZ"; | ||
| const std::string msg = "Expected 3 values (x_dist, y_dist, y_dist) for diffLayerDistXYZ"; |
| } else if (s == "xz" or s == "2") { | ||
| layerMode = ImagingTopoClusterConfig::ELayerMode::xz; | ||
| } else if (s == "xyz" or s == "3") { |
This PR applies the include-what-you-use fixes as suggested by https://github.com/eic/EICrecon/actions/runs/31633457160. Please merge this PR into the branch `Hybrid-Clustering-Algorithm-for-BIC` to resolve failures in PR #2865. Auto-generated by [create-pull-request][1] [1]: https://github.com/peter-evans/create-pull-request Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 10 out of 10 changed files in this pull request and generated 1 comment.
Suppressed comments (6)
src/algorithms/calorimetry/CalorimeterClusterRecoCoG.cc:120
getSystemIDcachessys_fieldasthread_localand dereferences it without a null check. This can crash when the configured readout (or IDSpec) doesn't have asystemfield, and thethread_localcache can also become stale if different instances use differentIDDescriptors on the same thread.
inline int getSystemID(const edm4eic::CalorimeterHit& hit, const dd4hep::IDDescriptor& m_idSpec) {
static thread_local auto* sys_field = m_idSpec.field("system");
return sys_field->value(hit.getCellID());
}
src/algorithms/calorimetry/CalorimeterClusterRecoCoG.cc:186
- When
specialModeis enabled, some hits can contributeenergy = 0. If the first hits processed have zero energy,totalEstays 0 andenergy / totalEbecomes0/0, producing NaNs/undefined behavior in the incremental time update.
totalE += energy;
time += (hit.getTime() - time) * energy / totalE;
src/algorithms/calorimetry/ImagingTopoCluster.cc:474
process()currently returns early when the configured IDSpec lacks asystemfield. Combined withinit()unconditionally doingm_detector->readout(m_cfg.readout)this makesreadout/systemeffectively mandatory and will cause existing configurations to stop producing clusters (e.g.ZDC.cc:190-205andFHCAL.cc:98-120configureImagingTopoCluster_factorywithout.readout). Either update those callers to set.readout, or add a backward-compatible fallback path whensystemisn't available.
auto* sys_field = m_idSpec.field("system");
if (!sys_field) {
error("Field 'system' not found in IDSpec for readout {}", m_cfg.readout);
return;
}
src/algorithms/calorimetry/ImagingTopoCluster.cc:220
- Typo in error message: the third component should be
z_dist, noty_dist(this message is user-facing and currently misleading).
const std::string msg = "Expected 3 values (x_dist, y_dist, y_dist) for diffLayerDistXYZ";
src/algorithms/calorimetry/ImagingTopoCluster.cc:339
- Typo in error message: the third component should be
z_dist, noty_dist(this message is user-facing and currently misleading).
"Expected 3 values (x_dist, y_dist, y_dist) for ScFi_diffLayerDistXYZ";
error(msg);
src/algorithms/calorimetry/ImagingTopoCluster.cc:434
- Typo in error message: the third component should be
z_dist, noty_dist(this message is user-facing and currently misleading).
const std::string msg = "Expected 3 values (x_dist, y_dist, y_dist) for Img_diffLayerDistXYZ";
| // Check against all ScFi clusters | ||
| for (size_t idx_ScFi : ScFi) { | ||
|
|
||
| const auto& cl_ScFi = all_clusters[idx_ScFi]; | ||
| bool neighbor_found = false; | ||
|
|
Capybara summary for PR 2865
Last updated 2026-08-25T18:42-04:00 48f87dc |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 10 out of 10 changed files in this pull request and generated 1 comment.
Suppressed comments (6)
src/algorithms/calorimetry/CalorimeterClusterRecoCoG.cc:188
- In specialMode, Imaging hits are forced to contribute
energy = 0, so the first few iterations can leavetotalE == 0and trigger0/0in the running time update (time += ... * energy / totalE), producing NaN/UB.
energy = hit.getEnergy() * weight;
}
totalE += energy;
time += (hit.getTime() - time) * energy / totalE;
src/algorithms/calorimetry/ImagingTopoCluster.cc:58
- init() unconditionally does
m_detector->readout(m_cfg.readout).idSpec(). SinceImagingTopoClusterConfig::readoutdefaults to an empty string, this will fail at runtime with a less actionable DD4hep error when callers forget to set it.
void ImagingTopoCluster::init() {
m_detector = algorithms::GeoSvc::instance().detector();
if (!m_detector) {
error("Failed to get detector from GeometrySvc for readout '{}'", m_cfg.readout);
throw std::runtime_error("Detector not available");
}
m_idSpec = m_detector->readout(m_cfg.readout).idSpec();
src/algorithms/calorimetry/ImagingTopoCluster.cc:223
- The exception text for diffLayerDistXYZ says "(x_dist, y_dist, y_dist)" but the third component is z. This makes configuration/debugging confusing.
case ImagingTopoClusterConfig::ELayerMode::xyz:
if (m_cfg.diffLayerDistXYZ.size() != 3) {
const std::string msg = "Expected 3 values (x_dist, y_dist, y_dist) for diffLayerDistXYZ";
error(msg);
throw std::runtime_error(msg);
}
src/algorithms/calorimetry/ImagingTopoCluster.cc:623
- Cross-system merging can duplicate the same ScFi cluster into multiple merged outputs:
used_ScFiis set but never used to skip already-merged ScFi clusters in the inner loop, so later Img clusters can merge the same ScFi hits again.
// Check against all ScFi clusters
for (size_t idx_ScFi : ScFi) {
const auto& cl_ScFi = all_clusters[idx_ScFi];
bool neighbor_found = false;
src/algorithms/calorimetry/ImagingTopoCluster.cc:474
- If the configured readout does not contain a
systemfield, the algorithm currently logs an error and silently returns without producing any proto-clusters. This is easy to miss and turns a configuration problem into an empty-output failure mode.
auto* sys_field = m_idSpec.field("system");
if (!sys_field) {
error("Field 'system' not found in IDSpec for readout {}", m_cfg.readout);
return;
}
src/algorithms/calorimetry/ImagingTopoCluster.cc:627
- The cross-system merge checks every hit in every Img cluster against every hit in every ScFi cluster (nested loops over clusters and hits). In high-occupancy events this can become very expensive (worst-case O(N^2) in hits). Consider precomputing per-cluster bounding boxes / representative points or building a spatial index to shortlist candidate cluster pairs before doing hit-by-hit checks.
for (auto h1 : cl_Img) {
for (auto h2 : cl_ScFi) {
if (cross_system_is_neighbour((*hits)[h1], (*hits)[h2])) {
debug(" Cross system neighbour: Img cluster {} hit {} <-> ScFi cluster {} hit {}",
| inline int getSystemID(const edm4eic::CalorimeterHit& hit, const dd4hep::IDDescriptor& m_idSpec) { | ||
| static thread_local const auto* sys_field = m_idSpec.field("system"); | ||
| return sys_field->value(hit.getCellID()); | ||
| } |
No Clang-Tidy warnings found so I assume my comments were addressed
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 10 out of 10 changed files in this pull request and generated no new comments.
Suppressed comments (9)
src/algorithms/calorimetry/ImagingTopoCluster.cc:57
- ImagingTopoCluster::init unconditionally does
m_detector->readout(m_cfg.readout).idSpec(). Several existing factory configurations don’t setreadout(e.g.src/detectors/FHCAL/FHCAL.cc:98andsrc/detectors/ZDC/ZDC.cc:190), so this will likely throw or leavem_idSpecwithout asystemfield, breaking clustering outside BEMC. Either makereadouta required config everywhere (and update all call sites in this PR) or add a backward-compatible path whenreadoutis empty / missing thesystemfield (fall back to the pre-existing system-agnostic clustering).
m_idSpec = m_detector->readout(m_cfg.readout).idSpec();
src/algorithms/calorimetry/ImagingTopoCluster.cc:220
- Typo in error message: the third expected value for
diffLayerDistXYZshould bez_dist(not a secondy_dist).
const std::string msg = "Expected 3 values (x_dist, y_dist, y_dist) for diffLayerDistXYZ";
src/algorithms/calorimetry/ImagingTopoCluster.cc:338
- Typo in error message: the third expected value for
ScFi_diffLayerDistXYZshould bez_dist(not a secondy_dist).
"Expected 3 values (x_dist, y_dist, y_dist) for ScFi_diffLayerDistXYZ";
src/algorithms/calorimetry/ImagingTopoCluster.cc:434
- Typo in error message: the third expected value for
Img_diffLayerDistXYZshould bez_dist(not a secondy_dist).
const std::string msg = "Expected 3 values (x_dist, y_dist, y_dist) for Img_diffLayerDistXYZ";
src/algorithms/calorimetry/ImagingTopoClusterConfig.h:117
ELayerModeparsing changed the numeric mapping fortzfrom "2" to "4" (and repurposes "2" forxz). Since numeric values are explicitly accepted here, this is an observable API behavior change that can silently alter existing runtime configs. Consider keeping backward compatibility by still accepting "2" fortz(and givingxza new numeric alias).
} else if (s == "xz" or s == "2") {
layerMode = ImagingTopoClusterConfig::ELayerMode::xz;
} else if (s == "xyz" or s == "3") {
layerMode = ImagingTopoClusterConfig::ELayerMode::xyz;
} else if (s == "tz" or s == "4") {
src/algorithms/calorimetry/CalorimeterClusterRecoCoG.cc:120
getSystemID()cachessys_fieldin astatic thread_localusing the firstIDDescriptorit sees, which can return incorrect results if the helper is ever called with a different descriptor (or beforem_idSpecis initialized). It also dereferencessys_fieldwithout a nullptr check, so missingsystemfields (or emptyreadout) can crash.
inline int getSystemID(const edm4eic::CalorimeterHit& hit, const dd4hep::IDDescriptor& m_idSpec) {
static thread_local const auto* sys_field = m_idSpec.field("system");
return sys_field->value(hit.getCellID());
}
src/algorithms/calorimetry/CalorimeterClusterRecoCoG.cc:188
- In
specialMode, Imaging hits contributeenergy = 0. If an Imaging hit is processed before any ScFi hit,totalEremains 0 andenergy/totalEbecomes 0/0, producing NaN/UB when updatingtime. Guard the running-average update so it only executes whenenergy > 0(ortotalE > 0).
totalE += energy;
time += (hit.getTime() - time) * energy / totalE;
src/tests/algorithms_test/calorimetry_ImagingTopoCluster.cc:40
- Redundant assignment:
cfg.sameLayerModeis set toxytwice (once witheicrecon::...and again without). Removing the duplicate avoids confusion about which value is intended.
cfg.readout = "MockCalorimeterHits";
cfg.sameLayerMode = eicrecon::ImagingTopoClusterConfig::ELayerMode::xy;
cfg.minClusterHitEdep = 0. * dd4hep::GeV;
cfg.minClusterCenterEdep = 0. * dd4hep::GeV;
cfg.sameLayerMode = ImagingTopoClusterConfig::ELayerMode::xy;
src/algorithms/calorimetry/ImagingTopoCluster.cc:593
- The new cross-system merge logic (hard-coded system IDs 101/105 and nested neighbor checks) is a substantial behavior change but doesn’t appear to be covered by a unit test. Adding a focused algorithm test (e.g., build two proto-clusters with
system=101andsystem=105hits within/outsidecross_system_DistXYZ) would reduce regression risk and help validate deterministic behavior regardless of hit ordering (important for multi-thread reproducibility).
// mergeCrossSystemClusters
std::vector<std::vector<size_t>> final_clusters;
std::set<size_t> used_Img;
std::set<size_t> used_ScFi;
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.
Suppressed comments (7)
src/algorithms/calorimetry/CalorimeterClusterRecoCoG.cc:120
- getSystemID() caches the BitFieldElement pointer in a
static thread_localvariable and does not check for a missingsystemfield. This can (a) crash when no readout/IDDescriptor is configured and (b) return incorrect results if multiple CalorimeterClusterRecoCoG instances use different IDDescriptors in the same thread (the cached pointer is taken from the first call).
inline int getSystemID(const edm4eic::CalorimeterHit& hit, const dd4hep::IDDescriptor& m_idSpec) {
static thread_local const auto* sys_field = m_idSpec.field("system");
return sys_field->value(hit.getCellID());
}
src/algorithms/calorimetry/CalorimeterClusterRecoCoG.cc:188
- In specialMode, Imaging hits contribute
energy = 0, sototalEcan remain 0 for the first few loop iterations. The time update... * energy / totalEthen divides by zero (0/0) and can produce NaN/inf time values.
totalE += energy;
time += (hit.getTime() - time) * energy / totalE;
src/algorithms/calorimetry/ImagingTopoCluster.cc:222
- The diffLayerDistXYZ validation error message lists
(x_dist, y_dist, y_dist)but the third component is z distance.
if (m_cfg.diffLayerDistXYZ.size() != 3) {
const std::string msg = "Expected 3 values (x_dist, y_dist, y_dist) for diffLayerDistXYZ";
error(msg);
throw std::runtime_error(msg);
src/algorithms/calorimetry/ImagingTopoCluster.cc:770
- is_neighbour() returns false when the
systemfield is missing, which prevents any hits from being connected into clusters. If system decoding is unavailable, it would be safer to fall back to the legacy (system-agnostic) neighbor logic instead of bailing out.
// Get the "system" field from the ID specification
auto* sys_field = m_idSpec.field("system");
if (!sys_field) {
error("Field 'system' not found in IDSpec for readout {}", m_cfg.readout);
return false;
src/algorithms/calorimetry/ImagingTopoCluster.cc:622
- During cross-system merging, ScFi clusters are marked in used_ScFi but the loop does not skip already-used ScFi clusters. This allows the same ScFi cluster to be merged into multiple Imaging clusters (duplicating hits across output proto-clusters and making results order-dependent).
// Check against all ScFi clusters
for (size_t idx_ScFi : ScFi) {
const auto& cl_ScFi = all_clusters[idx_ScFi];
bool neighbor_found = false;
src/algorithms/calorimetry/ImagingTopoCluster.h:159
- In bfs_group(), the system-filtering check unconditionally dereferences sys_field. If sys_field is optional (or missing due to misconfiguration), this will crash. Guard the check so BFS can still run in system-agnostic mode.
// skip hits from other system
if (sys_field->value(hits[*idx2].getCellID()) != sys) {
debug(" Skipping hit {}: different system", *idx2);
++idx2;
continue;
src/algorithms/calorimetry/ImagingTopoClusterConfig.h:78
- Changing the numeric values of ELayerMode (by inserting
xz=2and movingtzfrom 2→4) is likely a breaking change for configuration/parameter serialization that relies on the integer representation of the enum. Consider preserving the existing numeric mapping (tz=2, xyz=3) and assigning a new value to xz instead.
enum class ELayerMode { etaphi = 0, xy = 1, xz = 2, xyz = 3, tz = 4 };
| auto* sys_field = m_idSpec.field("system"); | ||
| if (!sys_field) { | ||
| error("Field 'system' not found in IDSpec for readout {}", m_cfg.readout); | ||
| return; | ||
| } |
| auto* sys_field = m_idSpec.field("system"); | ||
| if (!sys_field) { | ||
| error("Field 'system' not found in IDSpec for BFS grouping"); | ||
| return; | ||
| } | ||
|
|
||
| int sys = sys_field->value(hits[idx].getCellID()); | ||
| // debug("Starting BFS for hit {} in system {}", idx, sys); |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.
Suppressed comments (7)
src/algorithms/calorimetry/ImagingTopoCluster.cc:58
- ImagingTopoCluster::init() now unconditionally calls
m_detector->readout(m_cfg.readout)to get an IDDescriptor, butreadoutdefaults to an empty string andImagingTopoCluster_factorydoes not expose a JANA parameter to populate it. Existing detector plugins that constructImagingTopoClusterConfigwithout setting.readout(e.g. FHCAL) will now throw at runtime wheninit()runs. Either wirereadoutthrough the factory (and set it in all detector plugin configs), or makeImagingTopoClustergracefully fall back to the previous non-system-aware behavior whenreadoutis empty.
m_detector = algorithms::GeoSvc::instance().detector();
if (!m_detector) {
error("Failed to get detector from GeometrySvc for readout '{}'", m_cfg.readout);
throw std::runtime_error("Detector not available");
}
m_idSpec = m_detector->readout(m_cfg.readout).idSpec();
src/algorithms/calorimetry/ImagingTopoCluster.cc:222
- Error message typo: the code checks
diffLayerDistXYZ.size() != 3but the message currently says the expected tuple is(x_dist, y_dist, y_dist). This is misleading when diagnosing configuration issues.
if (m_cfg.diffLayerDistXYZ.size() != 3) {
const std::string msg = "Expected 3 values (x_dist, y_dist, y_dist) for diffLayerDistXYZ";
error(msg);
throw std::runtime_error(msg);
src/algorithms/calorimetry/ImagingTopoCluster.cc:339
- Error message typo: for the ScFi different-layer XYZ distances, the message says
(x_dist, y_dist, y_dist)even though the third component is the z-distance.
if (m_cfg.ScFi_diffLayerDistXYZ.size() != 3) {
const std::string msg =
"Expected 3 values (x_dist, y_dist, y_dist) for ScFi_diffLayerDistXYZ";
error(msg);
src/algorithms/calorimetry/ImagingTopoCluster.cc:436
- Error message typo: for the Imaging different-layer XYZ distances, the message says
(x_dist, y_dist, y_dist)even though the third component is the z-distance.
if (m_cfg.Img_diffLayerDistXYZ.size() != 3) {
const std::string msg = "Expected 3 values (x_dist, y_dist, y_dist) for Img_diffLayerDistXYZ";
error(msg);
throw std::runtime_error(msg);
src/algorithms/calorimetry/ImagingTopoCluster.cc:622
- Cross-system merging marks
idx_ScFias used, but the loop overScFiclusters never checksused_ScFibefore merging. If a ScFi cluster is neighbor to multiple Img clusters, it can be inserted into multiplefinal_clusters, duplicating hits and producing inconsistent output.
// Check against all ScFi clusters
for (size_t idx_ScFi : ScFi) {
const auto& cl_ScFi = all_clusters[idx_ScFi];
bool neighbor_found = false;
src/algorithms/calorimetry/CalorimeterClusterRecoCoG.cc:120
getSystemID()caches the dd4hep field pointer in astatic thread_localvariable and never null-checks it. This is unsafe because (1)m_idSpec.field("system")can be null (e.g. ifreadoutis not configured or the IDDescriptor lacks the field), and (2) the cached pointer can outlive or mismatch a differentIDDescriptorif multiple CalorimeterClusterRecoCoG instances (or different readouts) exist in the same thread.
inline int getSystemID(const edm4eic::CalorimeterHit& hit, const dd4hep::IDDescriptor& m_idSpec) {
static thread_local const auto* sys_field = m_idSpec.field("system");
return sys_field->value(hit.getCellID());
}
src/algorithms/calorimetry/CalorimeterClusterRecoCoG.cc:188
- In
specialMode, Imaging hits contributeenergy = 0, sototalEcan remain 0 for the first few hits. The current updatetime += ... * energy / totalEcan evaluate0/0whenenergy == 0andtotalE == 0, producing NaNs/UB and an invalid cluster time.
totalE += energy;
time += (hit.getTime() - time) * energy / totalE;
| default: | ||
| error("Unknown layer mode for same-layer clustering."); | ||
| return false; |
| ImagingTopoClusterConfig cfg; | ||
| cfg.readout = "MockCalorimeterHits"; | ||
| cfg.sameLayerMode = eicrecon::ImagingTopoClusterConfig::ELayerMode::xy; | ||
| cfg.minClusterHitEdep = 0. * dd4hep::GeV; | ||
| cfg.minClusterCenterEdep = 0. * dd4hep::GeV; | ||
| cfg.sameLayerDistXY = {1.0 * dd4hep::mm, 1.0 * dd4hep::mm}; //mm | ||
| cfg.diffLayerDistXY = {1.0 * dd4hep::mm, 1.0 * dd4hep::mm}; //mm | ||
| cfg.sameLayerMode = ImagingTopoClusterConfig::ELayerMode::xy; | ||
| cfg.sameLayerDistXY = {1.0 * dd4hep::mm, 1.0 * dd4hep::mm}; |
Briefly, what does this PR introduce? Please link to any relevant presentations or discussions.
Allows clustering of ScFi and Imaging Hits together based on the Topological Clustering Algorithm
What is the urgency of this PR?
What kind of change does this PR introduce?
Please check if any of the following apply
Briefly, what does this PR introduce? Please link to any relevant presentations or discussions.
What is the urgency of this PR?
What kind of change does this PR introduce?
Please check if any of the following apply