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
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: 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)