From b78c808c63066970f0223983d0fcd9131aabca87 Mon Sep 17 00:00:00 2001 From: jakehader Date: Mon, 3 Oct 2022 13:13:44 -0700 Subject: [PATCH] Address small fixes in the reaction rate calculation --- .../converters/tests/test_uniformMesh.py | 17 +++++ armi/reactor/converters/uniformMesh.py | 69 ++++++++++--------- 2 files changed, 53 insertions(+), 33 deletions(-) diff --git a/armi/reactor/converters/tests/test_uniformMesh.py b/armi/reactor/converters/tests/test_uniformMesh.py index a61d79e8b..07d103f2d 100644 --- a/armi/reactor/converters/tests/test_uniformMesh.py +++ b/armi/reactor/converters/tests/test_uniformMesh.py @@ -410,19 +410,36 @@ def setUp(self): def test_reactorConversion(self): """Tests the reactor conversion to and from the original reactor.""" self.assertTrue(self.converter._hasNonUniformAssems) + self.assertTrue(self.r.core.lib) + self.assertEqual(self.r.core.p.keff, 1.0) controlAssems = self.r.core.getAssemblies(Flags.PRIMARY | Flags.CONTROL) + # Add a bunch of multi-group flux to the control assemblies + # in the core to demonstrate that data can be mapped back + # to the original control rod assemblies if they are changed. + # Additionally, this will check that block-level reaction rates + # are being calculated (i.e., `rateAbs`). + for a in controlAssems: + for b in a: + b.p.mgFlux = [1.0] * 33 + self.assertFalse(b.p.rateAbs) + self.converter.convert(self.r) self.assertEqual( len(controlAssems), len(self.converter._nonUniformAssemStorage), ) + self.converter.applyStateToOriginal() self.assertEqual( len(self.converter._nonUniformAssemStorage), 0, ) + for a in controlAssems: + for b in a: + self.assertTrue(all(b.getMgFlux())) + self.assertTrue(b.p.rateAbs) if __name__ == "__main__": diff --git a/armi/reactor/converters/uniformMesh.py b/armi/reactor/converters/uniformMesh.py index 4e10962bf..025248b68 100644 --- a/armi/reactor/converters/uniformMesh.py +++ b/armi/reactor/converters/uniformMesh.py @@ -11,7 +11,9 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -from framework.armi.physics.neutronics.globalFlux.globalFluxInterface import calcReactionRates +from framework.armi.physics.neutronics.globalFlux.globalFluxInterface import ( + calcReactionRates, +) """ Converts reactor with arbitrary axial meshing (e.g. multiple assemblies with different @@ -544,18 +546,20 @@ def setAssemblyStateFromOverlaps( UniformMeshGeometryConverter._applyCachedParamValues( destBlock, blockParamNames, cachedParams ) - + # If requested, the reaction rates will be calculated based on the # mapped neutron flux and the XS library. if calcReactionRates: - core = destinationAssembly.getAncestor(lambda c: isinstance(c, Core)) + core = sourceAssembly.getAncestor(lambda c: isinstance(c, Core)) if core is not None: - UniformMeshGeometryConverter._calculateReactionRates(lib=core.lib, - keff=core.p.keff, - assem=destinationAssembly) + UniformMeshGeometryConverter._calculateReactionRates( + lib=core.lib, keff=core.p.keff, assem=destinationAssembly + ) else: - runLog.warning(f"Reaction rates requested for {destinationAssembly}, but no core object exists. This calculation " - "will be skipped.") + runLog.warning( + f"Reaction rates requested for {destinationAssembly}, but no core object exists. This calculation " + "will be skipped." + ) @staticmethod def _applyCachedParamValues(destBlock, paramNames, cachedParams): @@ -751,10 +755,31 @@ def _mapStateFromReactorToOther( This can be implemented in sub-classes to map specific reactor and assembly data. """ pass - + @staticmethod def _calculateReactionRates(lib, keff, assem): - pass + """ + Calculates the neutron reaction rates on the given assembly. + + Notes + ----- + If a block in the assembly does not contain any multi-group flux + than the reaction rate calculation for this block will be skipped. + """ + for b in assem: + print(b) + # Checks if the block has a multi-group flux defined and if it + # does not then this will skip the reaction rate calculation. This + # is captured by the TypeError, due to a `NoneType` divide by float + # error. + try: + b.getMgFlux() + except TypeError: + continue + + print(b.getMgFlux()) + globalFluxInterface.calcReactionRates(b, keff, lib) + class NeutronicsUniformMeshConverter(UniformMeshGeometryConverter): """ @@ -841,29 +866,7 @@ def _mapStateFromReactorToOther( # Clear the cached data after it has been mapped to prevent issues with # holding on to block data long-term. self._cachedReactorCoreParamData = {} - - @staticmethod - def _calculateReactionRates(self, lib, keff, assem): - """ - Calculates the neutron reaction rates on the given assembly. - - Notes - ----- - If a block in the assembly does not contain any multi-group flux - than the reaction rate calculation for this block will be skipped. - """ - for b in assem: - # Checks if the block has a multi-group flux defined and if it - # does not then this will skip the reaction rate calculation. This - # is captured by the TypeError, due to a `NoneType` divide by float - # error. - try: - b.getMgFlux() - except TypeError: - continue - globalFluxInterface.calcReactionRates( - b, keff, lib - ) + class BlockParamMapper: """