diff --git a/armi/reactor/components/__init__.py b/armi/reactor/components/__init__.py index 404c29be7..0fc7f11dc 100644 --- a/armi/reactor/components/__init__.py +++ b/armi/reactor/components/__init__.py @@ -28,8 +28,9 @@ """ from armi.reactor.components.component import * # pylint: disable=wildcard-import -from armi.reactor.components.shapes import * # pylint: disable=wildcard-import +from armi.reactor.components.componentCategories import * # pylint: disable=wildcard-import from armi.reactor.components.basicShapes import * # pylint: disable=wildcard-import +from armi.reactor.components.complexShapes import * # pylint: disable=wildcard-import from armi.reactor.components.volumetricShapes import * # pylint: disable=wildcard-import diff --git a/armi/reactor/components/basicShapes.py b/armi/reactor/components/basicShapes.py index 62441df7a..5c6768ee6 100644 --- a/armi/reactor/components/basicShapes.py +++ b/armi/reactor/components/basicShapes.py @@ -21,7 +21,7 @@ import math -from armi.reactor.components.shapes import ShapedComponent +from armi.reactor.components.componentCategories import ShapedComponent from armi.reactor.components import componentParameters @@ -145,126 +145,6 @@ def getPerimeter(self, Tc=None): return perimeter -class ShieldBlock(Hexagon): - """Solid hexagonal block with n uniform circular holes hollowed out of it.""" - - is3D = False - - THERMAL_EXPANSION_DIMS = {"op", "holeOD"} - - pDefs = componentParameters.getShieldBlockParameterDefinitions() - - def __init__( - self, - name, - material, - Tinput, - Thot, - op, - holeOD, - nHoles, - mult=1.0, - modArea=None, - isotopics=None, - mergeWith=None, - components=None, - ): - ShapedComponent.__init__( - self, - name, - material, - Tinput, - Thot, - isotopics=isotopics, - mergeWith=mergeWith, - components=components, - ) - self._linkAndStoreDimensions( - components, op=op, holeOD=holeOD, nHoles=nHoles, mult=mult, modArea=modArea - ) - - def getComponentArea(self, cold=False): - r"""Computes the area for the hexagon with n number of circular holes in cm^2.""" - op = self.getDimension("op", cold=cold) - holeOD = self.getDimension("holeOD", cold=cold) - nHoles = self.getDimension("nHoles", cold=cold) - mult = self.getDimension("mult") - hexArea = math.sqrt(3.0) / 2.0 * (op ** 2) - circularArea = nHoles * math.pi * ((holeOD / 2.0) ** 2) - area = mult * (hexArea - circularArea) - return area - - -class Helix(ShapedComponent): - """A spiral wire component used to model a pin wire-wrap. - - Notes - ----- - http://mathworld.wolfram.com/Helix.html - In a single rotation with an axial climb of P, the length of the helix will be a factor of - 2*pi*sqrt(r^2+c^2)/2*pi*c longer than vertical length L. P = 2*pi*c. - """ - - is3D = False - - THERMAL_EXPANSION_DIMS = {"od", "id", "axialPitch", "helixDiameter"} - - pDefs = componentParameters.getHelixParameterDefinitions() - - def __init__( - self, - name, - material, - Tinput, - Thot, - od=None, - axialPitch=None, - mult=None, - helixDiameter=None, - id=0.0, - modArea=None, - isotopics=None, - mergeWith=None, - components=None, - ): - ShapedComponent.__init__( - self, - name, - material, - Tinput, - Thot, - isotopics=isotopics, - mergeWith=mergeWith, - components=components, - ) - self._linkAndStoreDimensions( - components, - od=od, - axialPitch=axialPitch, - mult=mult, - helixDiameter=helixDiameter, - id=id, - modArea=modArea, - ) - - def getBoundingCircleOuterDiameter(self, Tc=None, cold=False): - return self.getDimension("od", Tc, cold) + self.getDimension( - "helixDiameter", Tc, cold=cold - ) - - def getComponentArea(self, cold=False): - """Computes the area for the helix in cm^2.""" - ap = self.getDimension("axialPitch", cold=cold) - hd = self.getDimension("helixDiameter", cold=cold) - id = self.getDimension("id", cold=cold) - od = self.getDimension("od", cold=cold) - mult = self.getDimension("mult") - c = ap / (2.0 * math.pi) - helixFactor = math.sqrt((hd / 2.0) ** 2 + c ** 2) / c - area = mult * math.pi * ((od / 2.0) ** 2 - (id / 2.0) ** 2) * helixFactor - return area - - class Rectangle(ShapedComponent): """A rectangle component.""" @@ -436,6 +316,14 @@ def getComponentArea(self, cold=False): class Triangle(ShapedComponent): + """ + Triangle with defined base and height. + + Notes + ----- + The exact angles of the triangle are undefined. The exact side lenths and angles + are not critical to calculation of component area, so area can still be calculated. + """ is3D = False diff --git a/armi/reactor/components/complexShapes.py b/armi/reactor/components/complexShapes.py new file mode 100644 index 000000000..26c81d1a3 --- /dev/null +++ b/armi/reactor/components/complexShapes.py @@ -0,0 +1,240 @@ +# Copyright 2019 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. + +""" +Components represented by complex shapes, and typically less widely used. +""" + +import math + +from armi.reactor.components.componentCategories import ShapedComponent +from armi.reactor.components import componentParameters +from armi.reactor.components import basicShapes + + +class HoledHexagon(basicShapes.Hexagon): + """Hexagon with n uniform circular holes hollowed out of it.""" + + THERMAL_EXPANSION_DIMS = {"op", "holeOD"} + + pDefs = componentParameters.getHoledHexagonParameterDefinitions() + + def __init__( + self, + name, + material, + Tinput, + Thot, + op, + holeOD, + nHoles, + mult=1.0, + modArea=None, + isotopics=None, + mergeWith=None, + components=None, + ): + ShapedComponent.__init__( + self, + name, + material, + Tinput, + Thot, + isotopics=isotopics, + mergeWith=mergeWith, + components=components, + ) + self._linkAndStoreDimensions( + components, op=op, holeOD=holeOD, nHoles=nHoles, mult=mult, modArea=modArea + ) + + def getComponentArea(self, cold=False): + r"""Computes the area for the hexagon with n number of circular holes in cm^2.""" + op = self.getDimension("op", cold=cold) + holeOD = self.getDimension("holeOD", cold=cold) + nHoles = self.getDimension("nHoles", cold=cold) + mult = self.getDimension("mult") + hexArea = math.sqrt(3.0) / 2.0 * (op ** 2) + circularArea = nHoles * math.pi * ((holeOD / 2.0) ** 2) + area = mult * (hexArea - circularArea) + return area + + +class HoledRectangle(basicShapes.Rectangle): + """Rectangle with one circular hole in it.""" + + THERMAL_EXPANSION_DIMS = {"lengthOuter", "widthOuter", "holeOD"} + + pDefs = componentParameters.getHoledRectangleParameterDefinitions() + + def __init__( + self, + name, + material, + Tinput, + Thot, + holeOD, + lengthOuter=None, + widthOuter=None, + mult=1.0, + modArea=None, + isotopics=None, + mergeWith=None, + components=None, + ): + ShapedComponent.__init__( + self, + name, + material, + Tinput, + Thot, + isotopics=isotopics, + mergeWith=mergeWith, + components=components, + ) + self._linkAndStoreDimensions( + components, + lengthOuter=lengthOuter, + widthOuter=widthOuter, + holeOD=holeOD, + mult=mult, + modArea=modArea, + ) + + def getComponentArea(self, cold=False): + r"""Computes the area (in cm^2) for the the rectangle with one hole in it.""" + length = self.getDimension("lengthOuter", cold=cold) + width = self.getDimension("widthOuter", cold=cold) + rectangleArea = length * width + holeOD = self.getDimension("holeOD", cold=cold) + circularArea = math.pi * ((holeOD / 2.0) ** 2) + mult = self.getDimension("mult") + area = mult * (rectangleArea - circularArea) + return area + + +class HoledSquare(basicShapes.Square): + """Square with one circular hole in it.""" + + THERMAL_EXPANSION_DIMS = {"widthOuter", "holeOD"} + + pDefs = componentParameters.getHoledRectangleParameterDefinitions() + + def __init__( + self, + name, + material, + Tinput, + Thot, + holeOD, + widthOuter=None, + mult=1.0, + modArea=None, + isotopics=None, + mergeWith=None, + components=None, + ): + ShapedComponent.__init__( + self, + name, + material, + Tinput, + Thot, + isotopics=isotopics, + mergeWith=mergeWith, + components=components, + ) + self._linkAndStoreDimensions( + components, widthOuter=widthOuter, holeOD=holeOD, mult=mult, modArea=modArea + ) + + def getComponentArea(self, cold=False): + r"""Computes the area (in cm^2) for the the square with one hole in it.""" + width = self.getDimension("widthOuter", cold=cold) + rectangleArea = width ** 2 + holeOD = self.getDimension("holeOD", cold=cold) + circularArea = math.pi * ((holeOD / 2.0) ** 2) + mult = self.getDimension("mult") + area = mult * (rectangleArea - circularArea) + return area + + +class Helix(ShapedComponent): + """A spiral wire component used to model a pin wire-wrap. + + Notes + ----- + http://mathworld.wolfram.com/Helix.html + In a single rotation with an axial climb of P, the length of the helix will be a factor of + 2*pi*sqrt(r^2+c^2)/2*pi*c longer than vertical length L. P = 2*pi*c. + """ + + is3D = False + + THERMAL_EXPANSION_DIMS = {"od", "id", "axialPitch", "helixDiameter"} + + pDefs = componentParameters.getHelixParameterDefinitions() + + def __init__( + self, + name, + material, + Tinput, + Thot, + od=None, + axialPitch=None, + mult=None, + helixDiameter=None, + id=0.0, + modArea=None, + isotopics=None, + mergeWith=None, + components=None, + ): + ShapedComponent.__init__( + self, + name, + material, + Tinput, + Thot, + isotopics=isotopics, + mergeWith=mergeWith, + components=components, + ) + self._linkAndStoreDimensions( + components, + od=od, + axialPitch=axialPitch, + mult=mult, + helixDiameter=helixDiameter, + id=id, + modArea=modArea, + ) + + def getBoundingCircleOuterDiameter(self, Tc=None, cold=False): + return self.getDimension("od", Tc, cold) + self.getDimension( + "helixDiameter", Tc, cold=cold + ) + + def getComponentArea(self, cold=False): + """Computes the area for the helix in cm^2.""" + ap = self.getDimension("axialPitch", cold=cold) + hd = self.getDimension("helixDiameter", cold=cold) + id = self.getDimension("id", cold=cold) + od = self.getDimension("od", cold=cold) + mult = self.getDimension("mult") + c = ap / (2.0 * math.pi) + helixFactor = math.sqrt((hd / 2.0) ** 2 + c ** 2) / c + area = mult * math.pi * ((od / 2.0) ** 2 - (id / 2.0) ** 2) * helixFactor + return area diff --git a/armi/reactor/components/component.py b/armi/reactor/components/component.py index c90ac9259..b61b8bae7 100644 --- a/armi/reactor/components/component.py +++ b/armi/reactor/components/component.py @@ -65,7 +65,7 @@ def componentTypeIsValid(component, name): `DerivedShape` if the coolant dimensions are not provided. """ - from armi.reactor.components.shapes import NullComponent + from armi.reactor.components.componentCategories import NullComponent if name.lower() == "coolant": invalidComponentTypes = [Component, NullComponent] diff --git a/armi/reactor/components/shapes.py b/armi/reactor/components/componentCategories.py similarity index 99% rename from armi/reactor/components/shapes.py rename to armi/reactor/components/componentCategories.py index c843271af..92dbadf3b 100644 --- a/armi/reactor/components/shapes.py +++ b/armi/reactor/components/componentCategories.py @@ -13,7 +13,7 @@ # limitations under the License. """ -Component subclasses that have shape. +Basic component categories. """ import math diff --git a/armi/reactor/components/componentParameters.py b/armi/reactor/components/componentParameters.py index 5197917ef..2117abd6b 100644 --- a/armi/reactor/components/componentParameters.py +++ b/armi/reactor/components/componentParameters.py @@ -141,8 +141,8 @@ def getHexagonParameterDefinitions(): return pDefs -def getShieldBlockParameterDefinitions(): - """Return parameters for ShieldBlock.""" +def getHoledHexagonParameterDefinitions(): + """Return parameters for HoledHexagon.""" pDefs = parameters.ParameterDefinitionCollection() with pDefs.createBuilder(location=ParamLocation.AVERAGE, saveToDB=True) as pb: @@ -153,6 +153,16 @@ def getShieldBlockParameterDefinitions(): return pDefs +def getHoledRectangleParameterDefinitions(): + """Return parameters for HoledRectangle.""" + + pDefs = parameters.ParameterDefinitionCollection() + with pDefs.createBuilder(location=ParamLocation.AVERAGE, saveToDB=True) as pb: + pb.defParam("holeOD", units="?", description="?") + + return pDefs + + def getHelixParameterDefinitions(): """Return parameters for Helix.""" diff --git a/armi/reactor/components/volumetricShapes.py b/armi/reactor/components/volumetricShapes.py index f109f5763..2f06450e9 100644 --- a/armi/reactor/components/volumetricShapes.py +++ b/armi/reactor/components/volumetricShapes.py @@ -17,7 +17,7 @@ import math from armi.reactor.components import componentParameters -from armi.reactor.components.shapes import ShapedComponent +from armi.reactor.components.componentCategories import ShapedComponent class Sphere(ShapedComponent): diff --git a/armi/reactor/tests/test_blocks.py b/armi/reactor/tests/test_blocks.py index 6acbead2e..6099e9e34 100644 --- a/armi/reactor/tests/test_blocks.py +++ b/armi/reactor/tests/test_blocks.py @@ -24,7 +24,7 @@ from armi.reactor import components import armi.runLog as runLog import armi.settings as settings -from armi.reactor.components import shapes +from armi.reactor.components import componentCategories from armi import materials from armi.nucDirectory import nucDir, nuclideBases from armi.utils.units import MOLES_PER_CC_TO_ATOMS_PER_BARN_CM @@ -1126,7 +1126,7 @@ def test_UnshapedGetPitch(self): block = blocks.HexBlock("TestHexBlock", location=None) outerPitch = 2.0 block.addComponent( - shapes.UnshapedComponent( + componentCategories.UnshapedComponent( "TestComponent", "Void", Tinput=25.0, Thot=25.0, op=outerPitch ) ) diff --git a/armi/reactor/tests/test_components.py b/armi/reactor/tests/test_components.py index 8a2df8e9d..dc5fc771d 100644 --- a/armi/reactor/tests/test_components.py +++ b/armi/reactor/tests/test_components.py @@ -26,7 +26,7 @@ NullComponent, Circle, Hexagon, - ShieldBlock, + HoledHexagon, Helix, Sphere, Cube, @@ -101,7 +101,6 @@ def test_componentInitializationAndDuplication(self): thisAttrs["name"] = "banana{}".format(i) if "modArea" in thisAttrs: thisAttrs["modArea"] = None - component = components.factory(name, [], thisAttrs) duped = copy.deepcopy(component) for key, val in component.p.items(): @@ -667,8 +666,8 @@ def test_dimensionThermallyExpands(self): self.assertEqual(cur, ref[i]) -class TestShieldBlock(TestShapedComponent): - componentCls = ShieldBlock +class TestHoledHexagon(TestShapedComponent): + componentCls = HoledHexagon componentDims = { "Tinput": 25.0, "Thot": 430.0, diff --git a/armi/reactor/tests/test_composites.py b/armi/reactor/tests/test_composites.py index 2e1480419..d766dd336 100644 --- a/armi/reactor/tests/test_composites.py +++ b/armi/reactor/tests/test_composites.py @@ -27,9 +27,9 @@ from armi.reactor import batch from armi.reactor import blocks from armi.reactor import assemblies -from armi.reactor.components import shapes +from armi.reactor.components import componentCategories from armi.reactor.components import basicShapes -from armi.reactor.components.shapes import UnshapedVolumetricComponent +from armi.reactor.components.componentCategories import UnshapedVolumetricComponent from armi.materials import custom from armi.reactor import locations from armi.reactor import grids @@ -438,7 +438,7 @@ def test_addMass(self): mass = 1.0 aB = batch.Batch("testBatch") - c = shapes.UnshapedVolumetricComponent( + c = componentCategories.UnshapedVolumetricComponent( "batchMassAdditionComponent", custom.Custom(), 0.0, 0.0, volume=1 ) b = blocks.Block("testBlock", location=loc) @@ -482,7 +482,7 @@ def test_setMass(self): mass = 1.0 aB = batch.Batch("testBatch") - c = shapes.UnshapedVolumetricComponent( + c = componentCategories.UnshapedVolumetricComponent( "batchMassAdditionComponent", custom.Custom(), 0.0, 0.0, volume=1 ) b = blocks.Block("testBlock", location=loc)