From 5507df3bfca38a5efd7f8b41f8e3f9301b4f0951 Mon Sep 17 00:00:00 2001 From: Zhiwen Zhao Date: Fri, 12 Jun 2026 23:41:01 -0400 Subject: [PATCH] Fix dependency-stall detection that aborted on progress MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both the volume and material build loops aborted with ERR_G4DEPENDENCIESNOTSOLVED exactly when the build was making progress. Two defects: (1) the remaining-count tracker was updated only in the else branch, so after iteration 1 it froze; (2) the comparison `previous >= current` fires whenever the count stays the same OR decreases — i.e. on progress, not on a stall. Any geometry/material set needing more than one resolution pass (a child built after its mother, the normal multi-pass case) leaves fewer remaining items on the next iteration — the success path — and aborted. Track the previous iteration's count in a dedicated variable updated every iteration, and error only when the count fails to strictly decrease (`current >= previous`) while the previous count was nonzero. Applied identically to both loops. Verified: b1 (sqlite) and cherenkov (optical) examples build all volumes and materials and run to completion with no spurious dependency error (Geant4 11.4.1 dev container). Fixes #108 Co-Authored-By: Claude Fable 5 --- gemc/g4system/g4world.cc | 45 ++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/gemc/g4system/g4world.cc b/gemc/g4system/g4world.cc index 118e7458..cdfca0c7 100644 --- a/gemc/g4system/g4world.cc +++ b/gemc/g4system/g4world.cc @@ -45,7 +45,7 @@ G4World::G4World(const GWorld *gworld, const std::shared_ptr &gopts) // Phase 4: build volumes. Some volumes depend on mothers that may not exist yet, // so we iterate until the remaining list becomes empty or the dependency resolution stalls. std::vector thisIterationRemainingVolumes; - unsigned long allRemainingVolumes = 0; + unsigned long previousRemainingVolumes = 0; do { thisIterationRemainingVolumes.clear(); @@ -80,19 +80,19 @@ G4World::G4World(const GWorld *gworld, const std::shared_ptr &gopts) } } - // Dependency-stall detection: - // If the number of remaining volumes does not decrease across iterations, dependencies are not solvable. - if (allRemainingVolumes != 0 && !thisIterationRemainingVolumes.empty()) { - if (allRemainingVolumes >= thisIterationRemainingVolumes.size()) { - for (auto *gvolumeLeft: thisIterationRemainingVolumes) { - log->warning(" >> ", gvolumeLeft->getName(), - " with mother <", gvolumeLeft->getG4MotherName(), "> not built"); - } - log->error(ERR_G4DEPENDENCIESNOTSOLVED, - "dependencies are not being resolved: their number should diminish. " - "Above are the outstanding gvolumes"); + // Dependency-stall detection: error only when the remaining count fails to strictly + // decrease across iterations (a strictly smaller count means progress was made). + if (previousRemainingVolumes != 0 && !thisIterationRemainingVolumes.empty() && + thisIterationRemainingVolumes.size() >= previousRemainingVolumes) { + for (auto *gvolumeLeft: thisIterationRemainingVolumes) { + log->warning(" >> ", gvolumeLeft->getName(), + " with mother <", gvolumeLeft->getG4MotherName(), "> not built"); } - } else { allRemainingVolumes = thisIterationRemainingVolumes.size(); } + log->error(ERR_G4DEPENDENCIESNOTSOLVED, + "dependencies are not being resolved: their number should diminish. " + "Above are the outstanding gvolumes"); + } + previousRemainingVolumes = thisIterationRemainingVolumes.size(); } while (!thisIterationRemainingVolumes.empty()); // Optional diagnostic output: list known materials from the Geant4 NIST manager. @@ -184,7 +184,7 @@ void G4World::buildMaterials(SystemMap *system_map) { // Build materials across all systems. Some materials may depend on other materials/elements, // so we iterate until all dependencies are resolved or the resolution stalls. std::vector thisIterationRemainingMaterials; - unsigned long allRemainingMaterials = 0; + unsigned long previousRemainingMaterials = 0; do { thisIterationRemainingMaterials.clear(); @@ -197,14 +197,15 @@ void G4World::buildMaterials(SystemMap *system_map) { } } - // Dependency-stall detection for material building. - if (allRemainingMaterials != 0 && !thisIterationRemainingMaterials.empty()) { - if (allRemainingMaterials >= thisIterationRemainingMaterials.size()) { - for (auto &gmaterialLeft: thisIterationRemainingMaterials) { log->warning(gmaterialLeft->getName()); } - log->error(ERR_G4DEPENDENCIESNOTSOLVED, - "Dependencies are not being resolved: their number should diminish. Above are the Outstanding gmaterials"); - } - } else { allRemainingMaterials = thisIterationRemainingMaterials.size(); } + // Dependency-stall detection for material building: error only when the remaining + // count fails to strictly decrease across iterations. + if (previousRemainingMaterials != 0 && !thisIterationRemainingMaterials.empty() && + thisIterationRemainingMaterials.size() >= previousRemainingMaterials) { + for (auto &gmaterialLeft: thisIterationRemainingMaterials) { log->warning(gmaterialLeft->getName()); } + log->error(ERR_G4DEPENDENCIESNOTSOLVED, + "Dependencies are not being resolved: their number should diminish. Above are the Outstanding gmaterials"); + } + previousRemainingMaterials = thisIterationRemainingMaterials.size(); } while (!thisIterationRemainingMaterials.empty()); }