-
Notifications
You must be signed in to change notification settings - Fork 90
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
Fixing sub-block grids #1947
base: main
Are you sure you want to change the base?
Fixing sub-block grids #1947
Changes from 5 commits
0a3764c
f19ea49
b79e2e7
ac34bb3
b244c8a
55c6715
dc73342
1942ed1
3facbc8
37dd62e
0d55251
2f8a350
349e406
7d8ab19
6141cc7
e8182dd
4f8242a
86516c7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -292,7 +292,7 @@ def getSmearDensity(self, cold=True): | |
|
||
return smearDensity | ||
|
||
def autoCreateSpatialGrids(self): | ||
def autoCreateSpatialGrids(self, cornersUp=True): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same reservations about putting |
||
""" | ||
Creates a spatialGrid for a Block. | ||
|
||
|
@@ -2317,7 +2317,7 @@ def getSymmetryFactor(self): | |
return 2.0 | ||
return 1.0 | ||
|
||
def autoCreateSpatialGrids(self): | ||
def autoCreateSpatialGrids(self, cornersUp=True): | ||
""" | ||
Given a block without a spatialGrid, create a spatialGrid and give its children the | ||
corresponding spatialLocators (if it is a simple block). | ||
|
@@ -2326,6 +2326,11 @@ def autoCreateSpatialGrids(self): | |
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. | ||
|
||
Parameters | ||
---------- | ||
cornersUp: bool | ||
Should the hexagons of this grid be corners up (as opposed to flats-up)? | ||
|
||
Notes | ||
----- | ||
If the Block meets all the conditions, we gather all components to either be a | ||
|
@@ -2339,7 +2344,7 @@ def autoCreateSpatialGrids(self): | |
If the multiplicities of the block are not only 1 or N or if generated ringNumber leads | ||
to more positions than necessary. | ||
""" | ||
# Check multiplicities... | ||
# Check multiplicities | ||
mults = {c.getDimension("mult") for c in self.iterComponents()} | ||
|
||
if len(mults) != 2 or 1 not in mults: | ||
|
@@ -2349,29 +2354,31 @@ def autoCreateSpatialGrids(self): | |
) | ||
) | ||
|
||
ringNumber = hexagon.numRingsToHoldNumCells(self.getNumPins()) | ||
# For the below to work, there must not be multiple wire or multiple clad types. | ||
# 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) | ||
# build the grid, from pitch and orientation | ||
grid = grids.HexGrid.fromPitch( | ||
self.getPinPitch(cold=True), numRings=0, cornersUp=True | ||
self.getPinPitch(cold=True), numRings=0, cornersUp=cornersUp | ||
) | ||
john-science marked this conversation as resolved.
Show resolved
Hide resolved
|
||
spatialLocators = grids.MultiIndexLocation(grid=self.spatialGrid) | ||
|
||
ringNumber = hexagon.numRingsToHoldNumCells(self.getNumPins()) | ||
numLocations = 0 | ||
for ring in range(ringNumber): | ||
numLocations = numLocations + hexagon.numPositionsInRing(ring + 1) | ||
|
||
if numLocations != self.getNumPins(): | ||
raise ValueError( | ||
"Cannot create spatialGrid, number of locations in rings{} not equal to pin number{}".format( | ||
numLocations, self.getNumPins() | ||
) | ||
) | ||
|
||
i = 0 | ||
# set the spatial position of the sub-block components | ||
spatialLocators = grids.MultiIndexLocation(grid=grid) | ||
for ring in range(ringNumber): | ||
for pos in range(grid.getPositionsInRing(ring + 1)): | ||
i, j = grid.getIndicesFromRingAndPos(ring + 1, pos + 1) | ||
spatialLocators.append(grid[i, j, 0]) | ||
|
||
# finally, fill the spatial grid, and put the sub-block components on it | ||
if self.spatialGrid is None: | ||
self.spatialGrid = grid | ||
Comment on lines
2418
to
2419
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The caller for this method in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a public method. People can call it multiple times, any time they want, downstream in their plugins. So, this method would cause havoc if we let people call it multiple times in a row. (I am considering moving this check ( |
||
for c in self: | ||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -563,11 +563,15 @@ def add(self, a, spatialLocator=None): | |||||
"".format(aName, self.assembliesByName[aName], a, self.r.p.maxAssemNum) | ||||||
) | ||||||
raise RuntimeError("Core already contains an assembly with the same name.") | ||||||
|
||||||
self.assembliesByName[aName] = a | ||||||
for b in a: | ||||||
self.blocksByName[b.getName()] = b | ||||||
|
||||||
if self.geomType == geometry.GeomType.HEX: | ||||||
cornerUp = self.spatialGrid.cornersUp | ||||||
a.orientBlocks(cornersUp=cornerUp) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
ring, _loc = self.spatialGrid.getRingPos( | ||||||
a.spatialLocator.getCompleteIndices() | ||||||
) | ||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,8 +15,8 @@ | |
"""Tests for grids.""" | ||
from io import BytesIO | ||
import math | ||
import unittest | ||
import pickle | ||
import unittest | ||
|
||
import numpy as np | ||
from numpy.testing import assert_allclose, assert_array_equal | ||
|
@@ -238,8 +238,8 @@ def test_ringPosFromIndicesIncorrect(self): | |
class TestHexGrid(unittest.TestCase): | ||
"""A set of tests for the Hexagonal Grid.""" | ||
|
||
def test_positions(self): | ||
grid = grids.HexGrid.fromPitch(1.0) | ||
def test_getCoordinatesFlatsUp(self): | ||
grid = grids.HexGrid.fromPitch(1.0, cornersUp=False) | ||
self.assertAlmostEqual(grid.pitch, 1.0) | ||
side = 1.0 / math.sqrt(3) | ||
assert_allclose(grid.getCoordinates((0, 0, 0)), (0.0, 0.0, 0.0)) | ||
|
@@ -261,6 +261,82 @@ def test_positions(self): | |
assert_allclose(grid.getCoordinates((1, 0, 0)), iDirection) | ||
assert_allclose(grid.getCoordinates((0, 1, 0)), jDirection) | ||
|
||
def test_getCoordinatesCornersUp(self): | ||
grid = grids.HexGrid.fromPitch(1.0, cornersUp=True) | ||
self.assertAlmostEqual(grid.pitch, 1.0) | ||
side = 1.0 / math.sqrt(3) | ||
assert_allclose(grid.getCoordinates((0, 0, 0)), (0.0, 0.0, 0.0)) | ||
assert_allclose(grid.getCoordinates((1, 0, 0)), (0.5, 1.5 * side, 0.0)) | ||
assert_allclose(grid.getCoordinates((-1, 0, 0)), (-0.5, -1.5 * side, 0.0)) | ||
assert_allclose(grid.getCoordinates((0, 1, 0)), (-0.5, 1.5 * side, 0.0)) | ||
assert_allclose(grid.getCoordinates((1, -1, 0)), (1, 0.0, 0.0)) | ||
john-science marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
unitSteps = grid.reduce()[0] | ||
iDirection = tuple(direction[0] for direction in unitSteps) | ||
jDirection = tuple(direction[1] for direction in unitSteps) | ||
for directionVector in (iDirection, jDirection): | ||
self.assertAlmostEqual( | ||
(sum(val**2 for val in directionVector)) ** 0.5, | ||
1.0, | ||
msg=f"Direction vector {directionVector} should have " | ||
"magnitude 1 for pitch 1.", | ||
) | ||
assert_allclose(grid.getCoordinates((1, 0, 0)), iDirection) | ||
assert_allclose(grid.getCoordinates((0, 1, 0)), jDirection) | ||
|
||
def test_getLocalCoordinates(self): | ||
john-science marked this conversation as resolved.
Show resolved
Hide resolved
|
||
grid0 = grids.HexGrid.fromPitch(1.0, cornersUp=True) | ||
grid1 = grids.HexGrid.fromPitch(1.0, cornersUp=False) | ||
for i in range(3): | ||
for j in range(3): | ||
if i == 0 and j == 0: | ||
continue | ||
coords0 = grid0[i, j, 0].getLocalCoordinates() | ||
coords1 = grid1[i, j, 0].getLocalCoordinates() | ||
self.assertNotEqual(coords0[0], coords1[0], msg=f"X @ ({i}, {j})") | ||
self.assertNotEqual(coords0[1], coords1[1], msg=f"Y @ ({i}, {j})") | ||
self.assertEqual(coords0[2], coords1[2], msg=f"Z @ ({i}, {j})") | ||
|
||
def test_getLocalCoordinatesCornersUp(self): | ||
# validate the first ring of a corners-up hex gric | ||
john-science marked this conversation as resolved.
Show resolved
Hide resolved
|
||
grid = grids.HexGrid.fromPitch(1.0, cornersUp=True) | ||
vals = [] | ||
for pos in range(grid.getPositionsInRing(2)): | ||
i, j = grid.getIndicesFromRingAndPos(2, pos + 1) | ||
vals.append(grid[i, j, 0].getLocalCoordinates()) | ||
|
||
# short in Y | ||
maxY = max(v[1] for v in vals) | ||
minY = min(v[1] for v in vals) | ||
self.assertLess(maxY, 1) | ||
self.assertGreater(minY, -1) | ||
Comment on lines
+315
to
+316
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Recommend a stronger check for asserting max and min y locations are +/- |
||
|
||
# long in X | ||
maxX = max(v[0] for v in vals) | ||
minX = min(v[0] for v in vals) | ||
self.assertAlmostEqual(maxX, 1) | ||
self.assertAlmostEqual(minX, -1) | ||
|
||
def test_getLocalCoordinatesFlatsUp(self): | ||
# validate the first ring of a flats-up hex gric | ||
john-science marked this conversation as resolved.
Show resolved
Hide resolved
|
||
grid = grids.HexGrid.fromPitch(1.0, cornersUp=False) | ||
vals = [] | ||
for pos in range(grid.getPositionsInRing(2)): | ||
i, j = grid.getIndicesFromRingAndPos(2, pos + 1) | ||
vals.append(grid[i, j, 0].getLocalCoordinates()) | ||
|
||
# long in Y | ||
maxY = max(v[1] for v in vals) | ||
minY = min(v[1] for v in vals) | ||
self.assertAlmostEqual(maxY, 1) | ||
self.assertAlmostEqual(minY, -1) | ||
|
||
# short in X | ||
maxX = max(v[0] for v in vals) | ||
minX = min(v[0] for v in vals) | ||
self.assertLess(maxX, 1) | ||
self.assertGreater(minX, -1) | ||
Comment on lines
+342
to
+343
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same suggestion to check max and min x positions are +/- |
||
|
||
def test_neighbors(self): | ||
grid = grids.HexGrid.fromPitch(1.0) | ||
neighbs = grid.getNeighboringCellIndices(0, 0, 0) | ||
|
@@ -837,8 +913,3 @@ def test_getLocations(self): | |
self.assertEqual(x, 0.0) | ||
self.assertEqual(y, 0.0) | ||
self.assertEqual(z, count + 0.5) | ||
|
||
|
||
if __name__ == "__main__": | ||
# import sys;sys.argv = ["", "TestHexGrid.testPositions"] | ||
unittest.main() |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -70,6 +70,10 @@ def add(self, assem, loc=None): | |||||
else: | ||||||
loc = self._getNextLocation() | ||||||
|
||||||
# orient the blocks to match this grid | ||||||
cornerUp = self.spatialGrid._unitSteps[0][1] == 0 | ||||||
john-science marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
assem.orientBlocks(cornerUp) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
super().add(assem, loc) | ||||||
|
||||||
def getAssembly(self, name): | ||||||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -35,8 +35,10 @@ | |||||
from armi.reactor.components import basicShapes, complexShapes | ||||||
from armi.reactor.flags import Flags | ||||||
from armi.reactor.tests.test_assemblies import makeTestAssembly | ||||||
from armi.tests import ISOAA_PATH, TEST_ROOT | ||||||
from armi.reactor.tests.test_reactors import loadTestReactor, TEST_ROOT | ||||||
from armi.tests import ISOAA_PATH | ||||||
from armi.utils import hexagon, units | ||||||
from armi.utils.directoryChangers import TemporaryDirectoryChanger | ||||||
from armi.utils.units import MOLES_PER_CC_TO_ATOMS_PER_BARN_CM | ||||||
|
||||||
NUM_PINS_IN_TEST_BLOCK = 217 | ||||||
|
@@ -2244,6 +2246,80 @@ def test_gridNotCreatedMultipleMultiplicities(self): | |||||
self.assertIsNone(self.HexBlock.spatialGrid) | ||||||
|
||||||
|
||||||
class TestHexBlockOrientation(unittest.TestCase): | ||||||
def setUp(self): | ||||||
self.td = TemporaryDirectoryChanger() | ||||||
self.td.__enter__() | ||||||
|
||||||
def tearDown(self): | ||||||
self.td.__exit__(None, None, None) | ||||||
|
||||||
def test_validateCornersUp(self): | ||||||
# load a corners up reactor | ||||||
_o, r = loadTestReactor( | ||||||
os.path.join(TEST_ROOT, "smallestTestReactor"), | ||||||
inputFileName="armiRunSmallest.yaml", | ||||||
) | ||||||
|
||||||
# grab a pinned fuel block, and verify it is corners up | ||||||
b = r.core.getFirstBlock(Flags.FUEL) | ||||||
self.assertTrue(b.spatialGrid.cornersUp) | ||||||
|
||||||
# for corners up, the hex centroids should stretch more in X than Y | ||||||
maxX = -111 | ||||||
minX = 999 | ||||||
maxY = -111 | ||||||
minY = 999 | ||||||
for comp in b: | ||||||
locs = comp.spatialLocator | ||||||
if not isinstance(locs, grids.MultiIndexLocation): | ||||||
locs = [locs] | ||||||
for loc in locs: | ||||||
x, y, _ = loc.getLocalCoordinates() | ||||||
if x > maxX: | ||||||
maxX = x | ||||||
elif x < minX: | ||||||
minX = x | ||||||
|
||||||
if y > maxY: | ||||||
maxY = y | ||||||
elif y < minY: | ||||||
minY = y | ||||||
|
||||||
self.assertGreater(maxX - minX, maxY - minY) | ||||||
|
||||||
def test_validateFlatsUp(self): | ||||||
# load a flats up reactor | ||||||
_o, r = loadTestReactor(TEST_ROOT, inputFileName="armiRun.yaml") | ||||||
|
||||||
# grab a pinned fuel block, and verify it is flats up | ||||||
b = r.core.getFirstBlock(Flags.FUEL) | ||||||
self.assertFalse(b.spatialGrid.cornersUp) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
# for flats up, the hex centroids should stretch more in Y than X | ||||||
maxX = -111 | ||||||
minX = 999 | ||||||
maxY = -111 | ||||||
minY = 999 | ||||||
for comp in b: | ||||||
locs = comp.spatialLocator | ||||||
if not isinstance(locs, grids.MultiIndexLocation): | ||||||
locs = [locs] | ||||||
for loc in locs: | ||||||
x, y, _ = loc.getLocalCoordinates() | ||||||
if x > maxX: | ||||||
maxX = x | ||||||
elif x < minX: | ||||||
minX = x | ||||||
|
||||||
if y > maxY: | ||||||
maxY = y | ||||||
elif y < minY: | ||||||
minY = y | ||||||
john-science marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
|
||||||
self.assertGreater(maxY - minY, maxX - minX) | ||||||
|
||||||
|
||||||
class ThRZBlock_TestCase(unittest.TestCase): | ||||||
def setUp(self): | ||||||
_ = settings.Settings() | ||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this live on the
HexAssembly
because we have acornerUp
flag that is hex specific?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All assemblies have a
.autoCreateSpatialGrids()
method though, right?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Blocks yes, but the
cornersUp
switch is hex specific. What does this mean for a cartesian grid? I get that it's good OOP practice to have the same signatures for overridden methods, but this feels in the vein of "everything is hexagonal in ARMI"