Source code for armi.reactor.components.volumetricShapes

# 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.

"""Three-dimensional shapes."""

import math

from armi.reactor.components import componentParameters
from armi.reactor.components import ShapedComponent


[docs]class Sphere(ShapedComponent): """A spherical component.""" is3D = True THERMAL_EXPANSION_DIMS = {} # Just usurp the Circle parameters. This may lead to issues at some point in things like the DB # interface, but for now, they are the same params, so why not? pDefs = componentParameters.getCircleParameterDefinitions() def __init__( self, name, material, Tinput, Thot, od=None, id=None, mult=None, 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, id=id, mult=mult, modArea=modArea )
[docs] def getBoundingCircleOuterDiameter(self, Tc=None, cold=False): """Abstract bounding circle method that should be overwritten by each shape subclass.""" return self.getDimension("od")
[docs] def getComponentArea(self, cold=False): """Compute an average area over the height.""" from armi.reactor.blocks import Block # avoid circular import block = self.getAncestor(lambda c: isinstance(c, Block)) return self.getComponentVolume(cold) / block.getHeight()
# raise NotImplementedError("Cannot compute area of a sphere component.")
[docs] def getComponentVolume(self, cold=False): """Computes the volume of the sphere in cm^3.""" od = self.getDimension("od", cold=cold) iD = self.getDimension("id", cold=cold) mult = self.getDimension("mult") vol = mult * 4.0 / 3.0 * math.pi * ((od / 2.0) ** 3 - (iD / 2.0) ** 3) return vol
[docs]class Cube(ShapedComponent): """More correctly, a rectangular cuboid. Optionally, there may be a centric cuboid volume cut out of center of this shape. """ is3D = True THERMAL_EXPANSION_DIMS = {} pDefs = componentParameters.getCubeParameterDefinitions() def __init__( self, name, material, Tinput, Thot, lengthOuter=None, lengthInner=None, widthOuter=None, widthInner=None, heightOuter=None, heightInner=None, mult=None, 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, lengthInner=lengthInner, widthOuter=widthOuter, widthInner=widthInner, heightOuter=heightOuter, heightInner=heightInner, mult=mult, modArea=modArea, )
[docs] def getComponentArea(self, cold=False): raise NotImplementedError("Cannot compute area of a cube component.")
[docs] def getComponentVolume(self): """Computes the volume of the cube in cm^3.""" lengthO = self.getDimension("lengthOuter") widthO = self.getDimension("widthOuter") heightO = self.getDimension("heightOuter") lengthI = self.getDimension("lengthInner") widthI = self.getDimension("widthInner") heightI = self.getDimension("heightInner") mult = self.getDimension("mult") vol = mult * (lengthO * widthO * heightO - lengthI * widthI * heightI) return vol
[docs]class RadialSegment(ShapedComponent): r"""A RadialSegement represents a volume element with thicknesses in the azimuthal, radial and axial directions. This a 3D projection of a 2D shape that is an angular slice of a ring or circle. The 2D shape is like the one below, with an inner and outer position for the theta and the radius: Image:: Y ^ - | - | -XXXX\ | - \XXXXXXX\ | theta |XXXXXXX| |-----------------------> radius, X | | """ is3D = True THERMAL_EXPANSION_DIMS = {} pDefs = componentParameters.getRadialSegmentParameterDefinitions() def __init__( self, name, material, Tinput, Thot, inner_radius=None, outer_radius=None, height=None, mult=None, inner_theta=0, outer_theta=math.pi * 2, isotopics=None, mergeWith=None, components=None, ): ShapedComponent.__init__( self, name, material, Tinput, Thot, isotopics=isotopics, mergeWith=mergeWith, components=components, ) self._linkAndStoreDimensions( components, inner_radius=inner_radius, outer_radius=outer_radius, height=height, mult=mult, inner_theta=inner_theta, outer_theta=outer_theta, )
[docs] def getComponentArea(self, refVolume=None, refHeight=None, cold=False): if refHeight: return ( (self.getDimension("height", cold=cold) / refHeight) * self.getDimension("mult") * ( math.pi * ( self.getDimension("outer_radius", cold=cold) ** 2 - self.getDimension("inner_radius", cold=cold) ** 2 ) * ( ( self.getDimension("outer_theta", cold=cold) - self.getDimension("inner_theta", cold=cold) ) / (math.pi * 2.0) ) ) ) if refVolume: return (self.getComponentVolume() / refVolume) / self.getDimension("height") else: return self.getComponentVolume() / self.getDimension("height")
[docs] def getComponentVolume(self): mult = self.getDimension("mult") outerRad = self.getDimension("outer_radius") innerRad = self.getDimension("inner_radius") outerTheta = self.getDimension("outer_theta") innerTheta = self.getDimension("inner_theta") height = self.getDimension("height") radialArea = math.pi * (outerRad**2 - innerRad**2) aziFraction = (outerTheta - innerTheta) / (math.pi * 2.0) vol = mult * radialArea * aziFraction * height return vol
[docs] def getBoundingCircleOuterDiameter(self, Tc=None, cold=False): return self.getDimension("outer_radius", Tc, cold)
[docs]class DifferentialRadialSegment(RadialSegment): """ This component class represents a volume element with thicknesses in the azimuthal, radial and axial directions. Furthermore it has dependent dimensions: (outer theta, outer radius, outer axial) that can be updated depending on the 'differential' in the corresponding directions. This component class is super useful for defining ThRZ reactors and perturbing its dimensions using the optimization modules See Also -------- geometry purturbation: armi.physics.optimize.OptimizationInterface.modifyCase (ThRZReflectorThickness,ThRZActiveHeight,ThRZActiveRadius) mesh updating: armi.reactor.reactors.Reactor.importGeom """ is3D = True THERMAL_EXPANSION_DIMS = {} def __init__( self, name, material, Tinput, Thot, inner_radius=None, radius_differential=None, inner_axial=None, height=None, inner_theta=0, azimuthal_differential=2 * math.pi, mult=1, isotopics=None, mergeWith=None, components=None, ): ShapedComponent.__init__( self, name, material, Tinput, Thot, isotopics=isotopics, mergeWith=mergeWith, components=components, ) self._linkAndStoreDimensions( components, inner_radius=inner_radius, radius_differential=radius_differential, inner_axial=inner_axial, height=height, inner_theta=inner_theta, azimuthal_differential=azimuthal_differential, mult=mult, ) self.updateDims()
[docs] def updateDims(self, key="", val=None): """ Update the dimensions of differential radial segment component. Notes ----- Can be used to update any dimension on the component, but outer_radius, outer_axial, and outer_theta are always updated. See Also -------- armi.reactor.blocks.Block.updateComponentDims """ self.setDimension(key, val) self.setDimension( "outer_radius", self.getDimension("inner_radius") + self.getDimension("radius_differential"), ) self.setDimension( "outer_axial", self.getDimension("inner_axial") + self.getDimension("height"), ) self.setDimension( "outer_theta", self.getDimension("inner_theta") + self.getDimension("azimuthal_differential"), )
[docs] def getComponentArea(self, refVolume=None, refHeight=None, cold=False): self.updateDims() return RadialSegment.getComponentArea( self, refVolume=None, refHeight=None, cold=False )
[docs] def getComponentVolume(self): self.updateDims() return RadialSegment.getComponentVolume(self)