diff --git a/armi/physics/neutronics/crossSectionGroupManager.py b/armi/physics/neutronics/crossSectionGroupManager.py index 2326da92e..ba27ca1ea 100644 --- a/armi/physics/neutronics/crossSectionGroupManager.py +++ b/armi/physics/neutronics/crossSectionGroupManager.py @@ -451,13 +451,15 @@ def _getAverageComponentTemperature(self, compIndex): weights = np.array([self.getWeight(b) / b.getHeight() for b in blocks]) weights /= weights.sum() # normalize by total weight components = [sorted(b.getComponents())[compIndex] for b in blocks] - weightedAvgComponentMass = sum(w * c.getMass() for w, c in zip(weights, components)) + weightedMass = [w * c.getMass() for w, c in zip(weights, components)] + weightedAvgComponentMass = sum(m for m in weightedMass if m > 0.0) if weightedAvgComponentMass == 0.0: # if there is no component mass (e.g., gap), do a regular average return np.mean(np.array([c.temperatureInC for c in components])) else: return ( - weights.dot(np.array([c.temperatureInC * c.getMass() for c in components])) / weightedAvgComponentMass + sum([c.temperatureInC * mass if mass > 0.0 else 0.0 for c, mass in zip(components, weightedMass)]) + / weightedAvgComponentMass ) def _performAverageByComponent(self): @@ -844,7 +846,10 @@ def _getAverageComponentNucs(self, components, bWeights): densities = np.zeros(len(allNucNames)) totalWeight = 0.0 for c, bWeight in zip(components, bWeights): - weight = bWeight * c.getArea() + compArea = c.getArea() + if compArea <= 0.0: + continue + weight = bWeight * compArea totalWeight += weight densities += weight * np.array(c.getNuclideNumberDensities(allNucNames)) if totalWeight > 0.0: diff --git a/armi/physics/neutronics/tests/test_crossSectionManager.py b/armi/physics/neutronics/tests/test_crossSectionManager.py index 0d0913ae5..eeb5275af 100644 --- a/armi/physics/neutronics/tests/test_crossSectionManager.py +++ b/armi/physics/neutronics/tests/test_crossSectionManager.py @@ -27,6 +27,7 @@ from armi import settings from armi.context import PLATFORM, Platform +from armi.materials.water import Water from armi.physics.neutronics import crossSectionGroupManager from armi.physics.neutronics.const import CONF_CROSS_SECTION from armi.physics.neutronics.crossSectionGroupManager import ( @@ -585,6 +586,47 @@ def test_ComponentAverageDuctHet1DCylinder(self): f"{nuc} temperature should be different from {compTemp} for component {c}", ) + def test_compAverageNegativeVolume(self): + """Test creation of a representative block when negative-volume components are present. + + .. test:: Create representative blocks using a volume-weighted averaging. + :id: T_ARMI_XSGM_CREATE_REPR_BLOCKS2 + :tests: R_ARMI_XSGM_CREATE_REPR_BLOCKS + """ + xsgm = self.o.getInterface("xsGroups") + xsgm.interactBOL() + + annularFuel = self.r.core.getAssemblies(Flags.FUEL | Flags.ANNULAR, includeBolAssems=True)[0] + # set temperatures of each gap component before performing average + # give the gaps some mass (material is arbitrary) + for i, b in enumerate(annularFuel.getBlocks(Flags.FUEL)): + gaps = b.getComponents(Flags.GAP) + for c in gaps: + c.temperatureInC = 500.0 + 100.0 * i + c.material = Water() + c.setNumberDensities({"H": 0.5, "O": 0.25}) + # make some of the negative-volume gaps have positive volume by adjusting liner temperature + liner = b.getComponent(Flags.LINER | Flags.OUTER) + liner.setTemperature(500.0 + 100.0 * i) + + xsgm.createRepresentativeBlocks() + xsgm.updateNuclideTemperatures() + + reprBlock = xsgm.representativeBlocks["UA"] + for c in reprBlock.getComponents(Flags.GAP): + if c.getName() == "gap3": + # gap3 temp is 700 C because the 500 C and 600 C components have negative volume + self.assertAlmostEqual(c.temperatureInC, 700.0) + elif c.getName() == "gap4": + # gap4 temp is between 500 C and 600 C because the 700C component has negative volume + self.assertLess(c.temperatureInC, 600.0) + self.assertGreater(c.temperatureInC, 500.0) + else: + # other gap components all have positive volume + self.assertAlmostEqual(c.temperatureInC, 600.0) + outerLiner = reprBlock.getComponent(Flags.LINER | Flags.OUTER) + self.assertAlmostEqual(outerLiner.temperatureInC, 600.0) + def test_checkComponentConsistency(self): xsgm = self.o.getInterface("xsGroups") xsgm.interactBOL()