Repository: terrapower/armi
Pull request #2060 (2025-01-21 23:06:08)

Fix scaling of edge assembly `VOLUME_INTEGRATED` parameters in third core periodic symmetry
## What is the change?

Combine volume-integrated parameters for symmetric edge assemblies before removing one of them.

## Why is the change being made?

There was previously a condition where the volume-integrated parameters of assemblies on the 0-degree and 120-degree symmetry line in a third-core periodic model were incorrect when the core still had both copies of the symmetric assembly. Typically we remove the assemblies on the 120-degree symmetry line using the `EdgeAssemblyChanger.removeEdgeAssemblies()`, at which point the volume-integrated params in the assemblies on the 0-degree line would become correct again.

A recent updated treatment of the symmetry factor (#2017) applies symmetry factor scaling to volume-integrated block parameters in an assembly immediately before that assembly is moved to a new location in the core (or initially placed in the core). This fixed the condition where the volume-integrated params were technically incorrect while both symmetric identicals were present. However, once the edge assemblies are removed, the volume-integrated params would become incorrect again.

This PR adds a step to scale the volume-integrated params on the 0-degree symmetry line immediately before removing the assemblies along the 120-degree symmetry line, so that the volume-integrated params are always correctly scaled to account for symmetry.

---

## Checklist

<!--
    You (the pull requester) should put an `x` in the boxes below you have completed.

    (If a checkbox doesn't apply to your PR, check it anyway.)
-->

- [x] This PR has only [one purpose or idea](https://terrapower.github.io/armi/developer/tooling.html#one-idea-one-pr).
- [x] [Tests](https://terrapower.github.io/armi/developer/tooling.html#test-it) have been added/updated to verify any new/changed code.

<!-- Check the code quality -->

- [x] The code style follows [good practices](https://terrapower.github.io/armi/developer/standards_and_practices.html).
- [x] The commit message(s) follow [good practices](https://terrapower.github.io/armi/developer/tooling.html).

<!-- Check the project-level cruft -->

- [x] The [release notes](https://terrapower.github.io/armi/developer/tooling.html#add-release-notes) have been updated if necessary.
- [x] The [documentation](https://terrapower.github.io/armi/developer/tooling.html#document-it) is still up-to-date in the `doc` folder.
- [x] The dependencies are still up-to-date in `pyproject.toml`.

mgjarrett: The unit test for the edge assembly changer did not need to be updated because the scaling was already applied in the unit test: 

https://github.com/terrapower/armi/blob/3431c44859a88ead124dfd323781c70c39bae714/armi/reactor/converters/tests/test_geometryConverters.py#L320

It just wasn't being applied when the core was constructed from blueprints.

Patch:
diff --git a/armi/physics/neutronics/globalFlux/globalFluxInterface.py b/armi/physics/neutronics/globalFlux/globalFluxInterface.py
index aef9d280..e99865cb 100644
--- a/armi/physics/neutronics/globalFlux/globalFluxInterface.py
+++ b/armi/physics/neutronics/globalFlux/globalFluxInterface.py
@@ -640,7 +640,7 @@ class GlobalFluxExecuter(executers.DefaultExecuter):
         geomConverter = self.geomConverters.get("edgeAssems")
         if geomConverter:
             geomConverter.scaleParamsRelatedToSymmetry(
-                self.r, paramsToScaleSubset=self.options.paramsToScaleSubset
+                self.r.core, paramsToScaleSubset=self.options.paramsToScaleSubset
             )
 
             # Resets the reactor core model to the correct symmetry and removes
diff --git a/armi/reactor/blueprints/reactorBlueprint.py b/armi/reactor/blueprints/reactorBlueprint.py
index ff7a4e8f..0af2d81f 100644
--- a/armi/reactor/blueprints/reactorBlueprint.py
+++ b/armi/reactor/blueprints/reactorBlueprint.py
@@ -237,6 +237,7 @@ class SystemBlueprint(yamlize.Object):
 
         runLog.header("=========== Applying Geometry Modifications ===========")
         converter = geometryConverters.EdgeAssemblyChanger()
+        converter.scaleParamsRelatedToSymmetry(container)
         converter.removeEdgeAssemblies(container)
 
         # now update the spatial grid dimensions based on the populated children
diff --git a/armi/reactor/converters/geometryConverters.py b/armi/reactor/converters/geometryConverters.py
index 8006a917..64d62d6c 100644
--- a/armi/reactor/converters/geometryConverters.py
+++ b/armi/reactor/converters/geometryConverters.py
@@ -1360,7 +1360,7 @@ class ThirdCoreHexToFullCoreChanger(GeometryChanger):
                         self.listOfVolIntegratedParamsToScale,
                         _,
                     ) = _generateListOfParamsToScale(
-                        self._sourceReactor, paramsToScaleSubset=[]
+                        self._sourceReactor.core, paramsToScaleSubset=[]
                     )
 
                 for b in a:
@@ -1516,6 +1516,7 @@ class EdgeAssemblyChanger(GeometryChanger):
         # Don't use newAssembliesAdded b/c this may be BOL cleaning of a fresh case that has edge
         # assems.
         edgeAssemblies = core.getAssembliesOnSymmetryLine(grids.BOUNDARY_120_DEGREES)
+
         for a in edgeAssemblies:
             runLog.debug(
                 "Removing edge assembly {} from {} from the reactor without discharging".format(
@@ -1538,7 +1539,7 @@ class EdgeAssemblyChanger(GeometryChanger):
         self.reset()
 
     @staticmethod
-    def scaleParamsRelatedToSymmetry(reactor, paramsToScaleSubset=None):
+    def scaleParamsRelatedToSymmetry(core, paramsToScaleSubset=None):
         """
         Scale volume-dependent params like power to account for cut-off edges.
 
@@ -1555,11 +1556,11 @@ class EdgeAssemblyChanger(GeometryChanger):
             "Scaling edge-assembly parameters to account for full hexes instead of two halves"
         )
         completeListOfParamsToScale = _generateListOfParamsToScale(
-            reactor, paramsToScaleSubset
+            core, paramsToScaleSubset
         )
         symmetricAssems = (
-            reactor.core.getAssembliesOnSymmetryLine(grids.BOUNDARY_0_DEGREES),
-            reactor.core.getAssembliesOnSymmetryLine(grids.BOUNDARY_120_DEGREES),
+            core.getAssembliesOnSymmetryLine(grids.BOUNDARY_0_DEGREES),
+            core.getAssembliesOnSymmetryLine(grids.BOUNDARY_120_DEGREES),
         )
         if not all(symmetricAssems):
             runLog.extra("No edge-assemblies found to scale parameters for.")
@@ -1569,15 +1570,15 @@ class EdgeAssemblyChanger(GeometryChanger):
                 _scaleParamsInBlock(b, bSymmetric, completeListOfParamsToScale)
 
 
-def _generateListOfParamsToScale(r, paramsToScaleSubset):
+def _generateListOfParamsToScale(core, paramsToScaleSubset):
     fluxParamsToScale = (
-        r.core.getFirstBlock()
+        core.getFirstBlock()
         .p.paramDefs.inCategory(Category.fluxQuantities)
         .inCategory(Category.multiGroupQuantities)
         .names
     )
     listOfVolumeIntegratedParamsToScale = (
-        r.core.getFirstBlock()
+        core.getFirstBlock()
         .p.paramDefs.atLocation(ParamLocation.VOLUME_INTEGRATED)
         .since(SINCE_LAST_GEOMETRY_TRANSFORMATION)
     )
diff --git a/doc/release/0.5.rst b/doc/release/0.5.rst
index e2d4a065..e005d82f 100644
--- a/doc/release/0.5.rst
+++ b/doc/release/0.5.rst
@@ -20,6 +20,7 @@ API Changes
 Bug Fixes
 ---------
 #. Fixing BP-section ignoring tool in ``PassiveDBLoadPlugin``. (`PR#2055 <https://github.com/terrapower/armi/pull/2055>`_)
+#. Fixing scaling of volume-integrated parameters on edge assembleis. (`PR#2060 <https://github.com/terrapower/armi/pull/2060>`_)
 #. TBD
 
 Quality Work


Test patch:
diff --git a/armi/reactor/converters/tests/test_geometryConverters.py b/armi/reactor/converters/tests/test_geometryConverters.py
index 5746a18b..1c326cd1 100644
--- a/armi/reactor/converters/tests/test_geometryConverters.py
+++ b/armi/reactor/converters/tests/test_geometryConverters.py
@@ -317,7 +317,7 @@ class TestEdgeAssemblyChanger(unittest.TestCase):
         # must be added after geom transform
         for b in self.o.r.core.getBlocks():
             b.p.power = 1.0
-        converter.scaleParamsRelatedToSymmetry(self.r)
+        converter.scaleParamsRelatedToSymmetry(self.r.core)
         a = self.r.core.getAssembliesOnSymmetryLine(grids.BOUNDARY_0_DEGREES)[0]
         self.assertTrue(all(b.p.power == 2.0 for b in a), "Powers were not scaled")