Source code for armi.reactor.blocks.cartesianBlock

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

"""Cartesian blocks can be square or more generically rectangular in cross section."""

import math

from armi.reactor import components, geometry
from armi.reactor.blocks.block import Block
from armi.reactor.flags import Flags


[docs] class CartesianBlock(Block): """ A Cartesian Block is a vertical slice of an Assembly which is laid out on a Cartesian grid. That is, a grid that is square or rectangular. A Cartesian grid can have an origin that is in the middle of a grid cell: +---------+--------+--------+ | | | | | (-1,1) | (0,1) | (1,1) | | | | | +---------+--------+--------+ | | | | | (-1,0) | (0,0) | (1,0) | | | | | +---------+--------+--------+ | | | | | (-1,-1) | (0,-1) | (1,-1) | | | | | +---------+--------+--------+ Or the grid cells can be aligned so the origin is between the grid cells: +---------+---------+--------+--------+ | | | | | | (-2,1) | (-1,1) | (0,1) | (1,1) | | | | | | +---------+---------+--------+--------+ | | | | | | (-2,0) | (-1,0) | (0,0) | (1,0) | | | | | | +---------+---------+--------+--------+ | | | | | | (-2,-1) | (-1,-1) | (0,-1) | (1,-1) | | | | | | +---------+---------+--------+--------+ | | | | | | (-2,-2) | (-1,-2) | (0,-2) | (1,-2) | | | | | | +---------+---------+--------+--------+ """ PITCH_DIMENSION = "widthOuter" PITCH_COMPONENT_TYPE = components.Rectangle
[docs] def getMaxArea(self): """Get area of this block if it were totally full.""" xw, yw = self.getPitch() return xw * yw
[docs] def setPitch(self, val, updateBolParams=False): raise NotImplementedError("Directly setting the pitch of a cartesian block is currently not supported.")
[docs] def getSymmetryFactor(self): """Return a factor between 1 and N where 1/N is how much cut-off by symmetry lines this mesh cell is.""" if self.core is not None and self.core.symmetry.domain != geometry.DomainType.FULL_CORE: indices = self.spatialLocator.getCompleteIndices() if self.core.symmetry.isThroughCenterAssembly: if indices[0] == 0 and indices[1] == 0: # central location return 4.0 elif indices[0] == 0 or indices[1] == 0: # edge location return 2.0 return 1.0
[docs] def getPinCenterFlatToFlat(self, cold=False): """Return the flat-to-flat distance between the centers of opposing pins (corner-2-corner) in the outer ring.""" clad = self.getComponent(Flags.CLAD) nRings = self.numRingsToHoldNumCells(clad.getDimension("mult")) pinPitch = self.getPinPitch(cold=cold) pinPitchDist = math.sqrt(pinPitch[0] ** 2 + pinPitch[1] ** 2) if self.core.symmetry.isThroughCenterAssembly: return 2 * (nRings - 1) * pinPitchDist else: return ((2 * nRings) - 1) * pinPitchDist
[docs] def getNumCellsGivenRings(self, nRings: int): """Calculate the number of cells in a Cartesian grid with a given number of rings. The logic here is separated out into two scenarios: one for when the origin is inside the center grid cell and one where the origin is on the line between grid cells. """ if self.core.symmetry.isThroughCenterAssembly: return (2 * nRings - 1) ** 2 else: return (2 * nRings) ** 2
[docs] def numRingsToHoldNumCells(self, nCells: int): """Calculate the number of rings needed in a Cartesian grid to hold a given number of cells. The logic here is separated out into two scenarios: one for when the origin is inside the center grid cell and one where the origin is on the line between grid cells. """ if self.core.symmetry.isThroughCenterAssembly: return math.ceil((math.sqrt(nCells) + 1) / 2.0) else: return math.ceil(math.sqrt(nCells) / 2.0)