Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ignoring Fluid density warning for Component Fluids #2075

Merged
merged 6 commits into from
Feb 6, 2025
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions armi/materials/material.py
Original file line number Diff line number Diff line change
Expand Up @@ -757,6 +757,15 @@ def adjustTD(self, val):
class Fluid(Material):
"""A material that fills its container. Could also be a gas."""

def __init_subclass__(cls):
# Undo the parent-aware density wrapping
# Justification: fluids do not expand in the same way solids expand so
# fluid.density(T) is an appropriate representation of the density of
# the fluid. This does not hold for solids because of the thermal expansion
# mechanics imposed by the rest of the framework
john-science marked this conversation as resolved.
Show resolved Hide resolved
if hasattr(cls.density, "__wrapped__"):
cls.density = cls.density.__wrapped__

def getThermalExpansionDensityReduction(self, prevTempInC, newTempInC):
"""Return the factor required to update thermal expansion going from one temperature (in
Celcius) to a new temperature.
Expand Down
64 changes: 64 additions & 0 deletions armi/materials/tests/test_fluids.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Copyright 2025 TerraPower, LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# 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.
"""Unit tests for fluid-specific behaviors.

The ARMI framework has a lot of thermal expansion machinery that applies to all components
but doesn't make sense for fluids. The tests here help show fluid materials still
play nice with the rest of the framework.
"""

from unittest import TestCase

from armi.materials.material import Fluid, Material
from armi.reactor.components import Circle
from armi.tests import mockRunLogs


class TestFluids(TestCase):
class MyFluid(Fluid):
"""Stand-in fluid that doesn't provide lots of functionality."""

class MySolid(Material):
"""Stand-in solid that doesn't provide lots of functionality."""

def test_fluidDensityWrapperNoWarning(self):
"""Test that Component.material.density does not raise a warning for fluids.

The ARMI Framework contains a mechanism to warn users if they as for the density
of a material when that material is attached to a component, e.g., ``comp.material.density()``.
The problem here is the component is the source of truth for volume and composition. It stores
dimensions, which can be thermally expanded according to the material, and number densities, which
may be updated through operation. Much of the framework operates on ``component.density`` and
other ``Component`` methods for mass accounting. However, ``comp.material.density`` does
not know about the new composition or volumes and can diverge from ``component.density``.
john-science marked this conversation as resolved.
Show resolved Hide resolved

Additionally, the framework does not do any thermal expansion on fluids. So the above calls to
``component.material.density`` are warranted if the material is a fluid.
"""
self._checkCompDensityLogs(
mat=self.MySolid(),
nExpectedWarnings=1,
msg="Solids should have the density warning logged.",
)
self._checkCompDensityLogs(
mat=self.MyFluid(),
nExpectedWarnings=0,
msg="Fluids should not have the density warning logged.",
)

def _checkCompDensityLogs(self, mat: Material, nExpectedWarnings: int, msg: str):
comp = Circle(name="test", material=mat, Tinput=20, Thot=20, id=0, od=1, mult=1)
with mockRunLogs.LogCounter() as logs:
comp.material.density(Tc=comp.temperatureInC)
self.assertEqual(logs.messageCounts["warning"], nExpectedWarnings, msg=msg)
8 changes: 6 additions & 2 deletions armi/materials/tests/test_materials.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,12 @@ def test_pseudoDensityKgM3(self):
self.assertEqual(dens * 1000.0, densKgM3)

def test_wrappedDensity(self):
"""Test that the density decorator is applied."""
self.assertTrue(hasattr(self.mat.density, "__wrapped__"))
"""Test that the density decorator is applied to non-fluids."""
self.assertEqual(
hasattr(self.mat.density, "__wrapped__"),
not isinstance(self.mat, materials.Fluid),
msg=self.mat,
)


class MaterialConstructionTests(unittest.TestCase):
Expand Down
2 changes: 2 additions & 0 deletions doc/release/0.5.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ New Features
------------
#. Move instead of copy files from TemporaryDirectoryChanger. (`PR#2022 <https://github.com/terrapower/armi/pull/2022>`_)
#. Creating the ``armi.testing`` module, to share ARMI testing tools. (`PR#2028 <https://github.com/terrapower/armi/pull/2028>`_)
#. Invoking ``component.material.density()`` does not log an expensive stack trace if the material
is a fluid. (`PR#2075 <https://github.com/terrapower/armi/pull/2075>`_)
#. TBD

API Changes
Expand Down