From 9de2ee390744c53006bc5e205bd973598bb28797 Mon Sep 17 00:00:00 2001 From: Zhiwen Zhao Date: Fri, 12 Jun 2026 23:43:04 -0400 Subject: [PATCH] Validate optical-property vector sizes once, after parsing, not per token getMaterialPropertyFromString appends one value per token in a while(!eof()) loop, and the cross-vector size validation block sat inside that loop, guarded by `if (propertyName == "rayleigh")`. On the first rayleigh token only one value has been pushed, so rayleigh.size()==1; for any real multi-point optical material (photonEnergy size > 1) the very first check fired ERR_GMATERIALOPTICALPROPERTYMISMATCH and aborted loading of valid, consistent data. Move the validation block out of the token loop so it runs once, after the full property vector has been parsed. propertyName is constant for the call and rayleigh is parsed last, so all other optical vectors are fully populated when the check runs. The check bodies are unchanged. Verified: the cherenkov optical example (photonEnergy/indexOfRefraction/ absorptionLength) still parses its material and runs to completion (Geant4 11.4.1 dev container). Fixes #112 Co-Authored-By: Claude Fable 5 --- gemc/gsystem/gmaterial.cc | 91 ++++++++++++++++++++------------------- 1 file changed, 47 insertions(+), 44 deletions(-) diff --git a/gemc/gsystem/gmaterial.cc b/gemc/gsystem/gmaterial.cc index 78291250..ad5216f5 100644 --- a/gemc/gsystem/gmaterial.cc +++ b/gemc/gsystem/gmaterial.cc @@ -139,51 +139,54 @@ void GMaterial::getMaterialPropertyFromString(const std::string ¶meter, cons } else if (propertyName == "rayleigh") { rayleigh.push_back(gutilities::getG4Number(trimmedComponent)); } + } - // validation triggered by rayleigh - if (propertyName == "rayleigh") { - // Rayleigh is loaded last: at this point we can validate that all other optical vectors - // either are empty (not specified) or match the photonEnergy vector length. - // - // If they do not match, behavior is undefined because properties would be evaluated - // at inconsistent energy grids. - unsigned long photonEnergyVectorSize = photonEnergy.size(); - - if (!indexOfRefraction.empty() && indexOfRefraction.size() != photonEnergyVectorSize) { - log->error(ERR_GMATERIALOPTICALPROPERTYMISMATCH, - "indexOfRefraction size ", indexOfRefraction.size(), " mismatch: photonEnergy has size ", - photonEnergyVectorSize); - } - if (!absorptionLength.empty() && absorptionLength.size() != photonEnergyVectorSize) { - log->error(ERR_GMATERIALOPTICALPROPERTYMISMATCH, - "absorptionLength size ", absorptionLength.size(), " mismatch: photonEnergy has size ", - photonEnergyVectorSize); - } - if (!reflectivity.empty() && reflectivity.size() != photonEnergyVectorSize) { - log->error(ERR_GMATERIALOPTICALPROPERTYMISMATCH, - "reflectivity size ", reflectivity.size(), " mismatch: photonEnergy has size ", - photonEnergyVectorSize); - } - if (!efficiency.empty() && efficiency.size() != photonEnergyVectorSize) { - log->error(ERR_GMATERIALOPTICALPROPERTYMISMATCH, - "efficiency size ", efficiency.size(), " mismatch: photonEnergy has size ", - photonEnergyVectorSize); - } - if (!fastcomponent.empty() && fastcomponent.size() != photonEnergyVectorSize) { - log->error(ERR_GMATERIALOPTICALPROPERTYMISMATCH, - "fastcomponent size ", fastcomponent.size(), " mismatch: photonEnergy has size ", - photonEnergyVectorSize); - } - if (!slowcomponent.empty() && slowcomponent.size() != photonEnergyVectorSize) { - log->error(ERR_GMATERIALOPTICALPROPERTYMISMATCH, - "slowcomponent size ", slowcomponent.size(), " mismatch: photonEnergy has size ", - photonEnergyVectorSize); - } - if (!rayleigh.empty() && rayleigh.size() != photonEnergyVectorSize) { - log->error(ERR_GMATERIALOPTICALPROPERTYMISMATCH, - "rayleigh size ", rayleigh.size(), " mismatch: photonEnergy has size ", - photonEnergyVectorSize); - } + // Validation runs once, after all tokens for this property have been parsed. + // Rayleigh is loaded last, so every other optical vector is fully populated and can be + // cross-checked against photonEnergy here. (Running this inside the token loop fired on + // the very first rayleigh value, before the vector was complete.) + if (propertyName == "rayleigh") { + // Rayleigh is loaded last: at this point we can validate that all other optical vectors + // either are empty (not specified) or match the photonEnergy vector length. + // + // If they do not match, behavior is undefined because properties would be evaluated + // at inconsistent energy grids. + unsigned long photonEnergyVectorSize = photonEnergy.size(); + + if (!indexOfRefraction.empty() && indexOfRefraction.size() != photonEnergyVectorSize) { + log->error(ERR_GMATERIALOPTICALPROPERTYMISMATCH, + "indexOfRefraction size ", indexOfRefraction.size(), " mismatch: photonEnergy has size ", + photonEnergyVectorSize); + } + if (!absorptionLength.empty() && absorptionLength.size() != photonEnergyVectorSize) { + log->error(ERR_GMATERIALOPTICALPROPERTYMISMATCH, + "absorptionLength size ", absorptionLength.size(), " mismatch: photonEnergy has size ", + photonEnergyVectorSize); + } + if (!reflectivity.empty() && reflectivity.size() != photonEnergyVectorSize) { + log->error(ERR_GMATERIALOPTICALPROPERTYMISMATCH, + "reflectivity size ", reflectivity.size(), " mismatch: photonEnergy has size ", + photonEnergyVectorSize); + } + if (!efficiency.empty() && efficiency.size() != photonEnergyVectorSize) { + log->error(ERR_GMATERIALOPTICALPROPERTYMISMATCH, + "efficiency size ", efficiency.size(), " mismatch: photonEnergy has size ", + photonEnergyVectorSize); + } + if (!fastcomponent.empty() && fastcomponent.size() != photonEnergyVectorSize) { + log->error(ERR_GMATERIALOPTICALPROPERTYMISMATCH, + "fastcomponent size ", fastcomponent.size(), " mismatch: photonEnergy has size ", + photonEnergyVectorSize); + } + if (!slowcomponent.empty() && slowcomponent.size() != photonEnergyVectorSize) { + log->error(ERR_GMATERIALOPTICALPROPERTYMISMATCH, + "slowcomponent size ", slowcomponent.size(), " mismatch: photonEnergy has size ", + photonEnergyVectorSize); + } + if (!rayleigh.empty() && rayleigh.size() != photonEnergyVectorSize) { + log->error(ERR_GMATERIALOPTICALPROPERTYMISMATCH, + "rayleigh size ", rayleigh.size(), " mismatch: photonEnergy has size ", + photonEnergyVectorSize); } } }