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

Fix the hex orientation of pin locations. #730

Merged
merged 3 commits into from Jul 7, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
57 changes: 25 additions & 32 deletions armi/reactor/blocks.py
Expand Up @@ -1933,7 +1933,9 @@ def getSymmetryFactor(self):

def getPinCoordinates(self):
"""
Compute the centroid coordinates of any pins in this block.
Compute the local centroid coordinates of any pins in this block.

The pins must have a CLAD-flagged component for this to work.

Returns
-------
Expand All @@ -1943,48 +1945,35 @@ def getPinCoordinates(self):
Notes
-----
This assumes hexagonal pin lattice and needs to be upgraded once more generic geometry
options are needed.

A block with fully-defined pins could just use their individual spatialLocators in a
block-level 2-D grid. However most cases do not have this to minimize overhead and maximize
speed. Thus we want to just come up with a uniform mesh of pins if they're not explicitly
placed in the grid.

options are needed. Only works if pins have clad.
john-science marked this conversation as resolved.
Show resolved Hide resolved
"""
return self._getPinCoordinatesHex()

def _getPinCoordinatesHex(self):
pinPitch = self.getPinPitch()
if pinPitch is None:
return []

coordinates = []
numPins = self.getNumPins()
numPinRings = hexagon.numRingsToHoldNumCells(numPins)

# pin lattice is rotated 30 degrees from assembly lattice
grid = grids.HexGrid.fromPitch(pinPitch, numPinRings, self, pointedEndUp=True)
for ring in range(numPinRings):
for pos in range(grid.getPositionsInRing(ring + 1)):
i, j = grid.getIndicesFromRingAndPos(ring + 1, pos + 1)
xyz = grid[i, j, 0].getLocalCoordinates()
coordinates.append(xyz)
return coordinates
coords = []
for clad in self.getChildrenWithFlags(Flags.CLAD):
if isinstance(clad.spatialLocator, grids.MultiIndexLocation):
coords.extend(
[locator.getLocalCoordinates() for locator in clad.spatialLocator]
)
else:
coords.append(clad.spatialLocator.getLocalCoordinates())
return coords

def autoCreateSpatialGrids(self):
"""
Given a block without a spatialGrid, create a spatialGrid and give its children
the corresponding spatialLocators (if it is a simple block).

In this case, a simple block would
be one that has either multiplicity of components equal to 1 or N but no other multiplicities. Also, this should only happen when N fits exactly into a given number of hex rings.
Otherwise, do not create a grid for this block.
In this case, a simple block would be one that has either multiplicity of
components equal to 1 or N but no other multiplicities. Also, this should only
happen when N fits exactly into a given number of hex rings. Otherwise, do not
create a grid for this block.

Notes
-----
If the block meets all the conditions, we gather all components to either be a multiIndexLocation containing all
of the pin positions, otherwise, locator is the center (0,0).

Also, this only works on blocks that have 'flat side up'.

Raises
------
ValueError
Expand All @@ -2003,10 +1992,14 @@ def autoCreateSpatialGrids(self):
)
)

spatialLocators = grids.MultiIndexLocation(grid=self.spatialGrid)
ringNumber = hexagon.numRingsToHoldNumCells(self.getNumPins())
# For the below to work, there must not be multiple wire or multiple clad types.
grid = grids.HexGrid.fromPitch(self.getPinPitch(cold=True), numRings=0)
# note that it's the pointed end of the cell hexes that are up (but the
# macro shape of the pins forms a hex with a flat top fitting in the assembly)
grid = grids.HexGrid.fromPitch(
self.getPinPitch(cold=True), numRings=0, pointedEndUp=True
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this still working if a user puts into their layout blueprint the geom: hex_corners_up option?

I can't quite tell myself, but it feels like maybe in that case you should set pointedEndUp=False?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it only works on flat side up cases, you're right. I added a note in the docstring to the effect. It's be nice to detect that situation and throw an error, but we don't currently have a good way to look at a grid and determine which 'orientation' it is at this level.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we don't currently have a good way to look at a grid and determine which 'orientation'

Sad trombone noises.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Found this researching #1284

)
spatialLocators = grids.MultiIndexLocation(grid=self.spatialGrid)
numLocations = 0
for ring in range(ringNumber):
numLocations = numLocations + hexagon.numPositionsInRing(ring + 1)
Expand Down
24 changes: 24 additions & 0 deletions armi/reactor/tests/test_blocks.py
Expand Up @@ -1625,6 +1625,7 @@ def setUp(self):
self.HexBlock.add(
components.DerivedShape("coolant", "Sodium", Tinput=273.0, Thot=273.0)
)
self.HexBlock.autoCreateSpatialGrids()
john-science marked this conversation as resolved.
Show resolved Hide resolved
r = tests.getEmptyHexReactor()
a = makeTestAssembly(1, 1)
a.add(self.HexBlock)
Expand Down Expand Up @@ -1692,6 +1693,10 @@ def test_retainState(self):
self.assertTrue(self.HexBlock.hasFlags(Flags.INTERCOOLANT))

def test_getPinCoords(self):
blockPitch = self.HexBlock.getPitch()
pinPitch = self.HexBlock.getPinPitch()
nPins = self.HexBlock.getNumPins()
side = hexagon.side(blockPitch)
xyz = self.HexBlock.getPinCoordinates()
x, y, _z = zip(*xyz)
self.assertAlmostEqual(
Expand All @@ -1700,6 +1705,24 @@ def test_getPinCoords(self):
self.assertNotAlmostEqual(x[1], x[2])
self.assertEqual(len(xyz), self.HexBlock.getNumPins())

# ensure all pins are within the proper bounds of a
# flats-up oriented hex block
self.assertLess(max(y), blockPitch / 2.0)
self.assertGreater(min(y), -blockPitch / 2.0)
self.assertLess(max(x), side)
self.assertGreater(min(x), -side)

# center pin should be at 0
mags = [(xi ** 2 + yi ** 2, (xi, yi)) for xi, yi, zi in xyz]
_centerMag, (cx, cy) = min(mags)
self.assertAlmostEqual(cx, 0.0)
self.assertAlmostEqual(cy, 0.0)

# extreme pin should be at proper radius
cornerMag, (cx, cy) = max(mags)
nRings = hexagon.numRingsToHoldNumCells(nPins) - 1
self.assertAlmostEqual(math.sqrt(cornerMag), nRings * pinPitch)

def test_getPitchHomogenousBlock(self):
"""
Demonstrate how to communicate pitch on a hex block with unshaped components.
Expand Down Expand Up @@ -1843,6 +1866,7 @@ def test_gridNotCreatedMultipleMultiplicities(self):
# add a wire only some places in the block, so grid should not be created.
wire = components.Helix("wire", "HT9", **wireDims)
self.HexBlock.add(wire)
self.HexBlock.spatialGrid = None # clear existing
with self.assertRaises(ValueError):
self.HexBlock.autoCreateSpatialGrids()

Expand Down