Fully implement 2D and 3D hex lattices for #331

This commit is contained in:
Sterling Harper 2015-03-10 21:34:08 -04:00
parent 6f172ba4a0
commit de3f6f176c
2 changed files with 222 additions and 191 deletions

View file

@ -99,12 +99,29 @@ root.add_cell(cell1)
# Instantiate a Lattice
lattice = openmc.HexLattice(lattice_id=5)
lattice.set_num_rings(2)
lattice.set_center([0., 0.])
lattice.set_pitch([1.])
lattice.set_num_rings(3)
#lattice.set_center([0., 0.])
#lattice.set_pitch([1.])
#lattice.set_universes([
# [univ2, univ2, univ2, univ2, univ2, univ2, univ2, univ2, univ2, univ2, univ2, univ2],
# [univ2, univ2, univ2, univ2, univ2, univ2],
# [univ1]])
lattice.set_center([0., 0., 0.])
lattice.set_pitch([1., 1.])
lattice.set_num_axial(2)
lattice.set_universes([
[univ2, univ2, univ2, univ2, univ2, univ2],
[univ1]])
[
[univ2, univ2, univ2, univ2, univ2, univ2, univ2, univ2, univ2, univ2, univ2, univ2],
[univ2, univ2, univ2, univ2, univ2, univ2],
[univ1]
],
[
[univ2, univ2, univ2, univ2, univ2, univ2, univ2, univ2, univ2, univ2, univ2, univ2],
[univ2, univ2, univ2, univ2, univ2, univ2],
[univ1]
]
])
lattice.set_outer(univ1)
# Fill Cell with the Lattice
cell1.set_fill(lattice)

View file

@ -610,36 +610,6 @@ class Lattice(object):
self._name = name
def set_pitch(self, pitch):
if not isinstance(pitch, (tuple, list, np.ndarray)):
msg = 'Unable to set Lattice ID={0} pitch to {1} since ' \
'it is not a Python tuple/list or NumPy ' \
'array'.format(self._id, pitch)
raise ValueError(msg)
elif len(pitch) != 2 and len(pitch) != 3:
msg = 'Unable to set Lattice ID={0} pitch to {1} since it does ' \
'not contain 2 or 3 coordinates'.format(self._id, pitch)
raise ValueError(msg)
for dim in pitch:
if not is_integer(dim) and not is_float(dim):
msg = 'Unable to set Lattice ID={0} pitch to {1} since ' \
'it is not an an integer or floating point ' \
'value'.format(self._id, dim)
raise ValueError(msg)
elif dim < 0:
msg = 'Unable to set Lattice ID={0} pitch to {1} since it ' \
'is a negative value'.format(self._id, dim)
raise ValueError(msg)
self._pitch = pitch
def set_outer(self, outer):
if not isinstance(outer, Universe):
@ -716,41 +686,6 @@ class Lattice(object):
return all_universes
def create_xml_subelement(self, xml_element):
# Determine if XML element already contains subelement for this Lattice
path = './lattice[@id=\'{0}\']'.format(self._id)
test = xml_element.find(path)
# If the element does contain the Lattice subelement, then return
if not test is None:
return
lattice_subelement = ET.Element("lattice")
lattice_subelement.set("id", str(self._id))
# Export the Lattice cell pitch
if len(self._pitch) == 3:
pitch = ET.SubElement(lattice_subelement, "pitch")
pitch.text = '{0} {1} {2}'.format(self._pitch[0], \
self._pitch[1], \
self._pitch[2])
elif len(self._pitch) == 2:
pitch = ET.SubElement(lattice_subelement, "pitch")
pitch.text = '{0} {1}'.format(self._pitch[0], \
self._pitch[1])
else:
pitch = ET.SubElement(lattice_subelement, "pitch")
pitch.text = '{0}'.format(self._pitch[0])
# Export the Lattice outer Universe (if specified)
if self._outer is not None:
outer = ET.SubElement(lattice_subelement, "outer")
outer.text = '{0}'.format(self._outer._id)
return lattice_subelement
################################################################################
@ -838,6 +773,36 @@ class RectLattice(Lattice):
self._offsets = offsets
def set_pitch(self, pitch):
if not isinstance(pitch, (tuple, list, np.ndarray)):
msg = 'Unable to set Lattice ID={0} pitch to {1} since ' \
'it is not a Python tuple/list or NumPy ' \
'array'.format(self._id, pitch)
raise ValueError(msg)
elif len(pitch) != 2 and len(pitch) != 3:
msg = 'Unable to set Lattice ID={0} pitch to {1} since it does ' \
'not contain 2 or 3 coordinates'.format(self._id, pitch)
raise ValueError(msg)
for dim in pitch:
if not is_integer(dim) and not is_float(dim):
msg = 'Unable to set Lattice ID={0} pitch to {1} since ' \
'it is not an an integer or floating point ' \
'value'.format(self._id, dim)
raise ValueError(msg)
elif dim < 0:
msg = 'Unable to set Lattice ID={0} pitch to {1} since it ' \
'is a negative value'.format(self._id, dim)
raise ValueError(msg)
self._pitch = pitch
def get_offset(self, path, filter_offset):
# Get the current element and remove it from the list
@ -915,8 +880,24 @@ class RectLattice(Lattice):
if not test is None:
return
lattice_subelement = \
super(RectLattice, self).create_xml_subelement(xml_element)
lattice_subelement = ET.Element("lattice")
lattice_subelement.set("id", str(self._id))
# Export the Lattice cell pitch
if len(self._pitch) == 3:
pitch = ET.SubElement(lattice_subelement, "pitch")
pitch.text = '{0} {1} {2}'.format(self._pitch[0], \
self._pitch[1], \
self._pitch[2])
else:
pitch = ET.SubElement(lattice_subelement, "pitch")
pitch.text = '{0} {1}'.format(self._pitch[0], \
self._pitch[1])
# Export the Lattice outer Universe (if specified)
if self._outer is not None:
outer = ET.SubElement(lattice_subelement, "outer")
outer.text = '{0}'.format(self._outer._id)
# Export Lattice cell dimensions
if len(self._dimension) == 3:
@ -1054,8 +1035,6 @@ class HexLattice(Lattice):
self._center = center
# NOTE to wboyd: this method needs to be hex/rect specific because only
# one pitch is needed to describe a 2D hex lattice.
def set_pitch(self, pitch):
if not isinstance(pitch, (tuple, list, np.ndarray)):
@ -1094,8 +1073,13 @@ class HexLattice(Lattice):
# The sub-lists are ordered from outermost ring to innermost ring.
# The Universes within each sub-list are ordered from the "top" in a
# clockwise fashion.
# TODO: Does this need some work to handle numpy arrays? I'm not sure
# we can use numpy arrays at all because they will assume a constant
# number of columns, but the columns will depend on the row in this
# ragged format.
#self.set_num_rings(universes.shape[0])
self.set_num_rings(len(universes))
#self.set_num_rings(len(universes))
def __repr__(self):
@ -1135,18 +1119,34 @@ class HexLattice(Lattice):
def create_xml_subelement(self, xml_element):
# Determine if XML element already contains subelement for this Lattice
path = './lattice[@id=\'{0}\']'.format(self._id)
path = './hex_lattice[@id=\'{0}\']'.format(self._id)
test = xml_element.find(path)
# If the element does contain the Lattice subelement, then return
if not test is None:
return
lattice_subelement = \
super(HexLattice, self).create_xml_subelement(xml_element)
lattice_subelement = ET.Element("hex_lattice")
lattice_subelement.set("id", str(self._id))
# Export the Lattice cell pitch
if len(self._pitch) == 2:
pitch = ET.SubElement(lattice_subelement, "pitch")
pitch.text = '{0} {1}'.format(self._pitch[0], \
self._pitch[1])
else:
pitch = ET.SubElement(lattice_subelement, "pitch")
pitch.text = '{0}'.format(self._pitch[0])
# Export the Lattice outer Universe (if specified)
if self._outer is not None:
outer = ET.SubElement(lattice_subelement, "outer")
outer.text = '{0}'.format(self._outer._id)
lattice_subelement.set("n_rings", str(self._num_rings))
lattice_subelement.set("n_axial", str(self._num_axial))
if self._num_axial is not None:
lattice_subelement.set("n_axial", str(self._num_axial))
# Export Lattice cell center
if len(self._center) == 3:
@ -1159,134 +1159,148 @@ class HexLattice(Lattice):
dimension.text = '{0} {1}'.format(self._center[0], \
self._center[1])
# FIXME: The following must be revised for hexagonal lattice ordering
# Export the Lattice nested Universe IDs - column major for Fortran
universe_ids = '\n'
# Export the Lattice nested Universe IDs.
# 3D Lattices
#if len(self._dimension) == 3:
if self._num_axial is not None:
pass
# for z in range(self._dimension[2]):
# for y in range(self._dimension[1]):
# for x in range(self._dimension[0]):
#
# universe = self._universes[x][y][z]
#
# # Append Universe ID to the Lattice XML subelement
# universe_ids += '{0} '.format(universe._id)
#
# # Create XML subelement for this Universe
# universe.create_xml_subelement(xml_element)
#
# # Add newline character when we reach end of row of cells
# universe_ids += '\n'
#
# # Add newline character when we reach end of row of cells
# universe_ids += '\n'
slices = []
for z in range(self._num_axial):
# Initialize the center universe.
universe = self._universes[z][-1][0]
universe.create_xml_subelement(xml_element)
# Initialize the remaining universes.
for r in range(self._num_rings-1):
for theta in range(2*(self._num_rings - r)):
universe = self._universes[z][r][theta]
universe.create_xml_subelement(xml_element)
# Get a string representation of the universe IDs.
slices.append(self._repr_axial_slice(self._universes[z]))
# Collapse the list of axial slices into a single string.
universe_ids = '\n'.join(slices)
# 2D Lattices
else:
# Initialize the list for each row.
rows = [ [] for i in range(1 + 4 * (self._num_rings-1)) ]
middle = self._num_rings - 1
middle = 2 * (self._num_rings - 1)
# Start with the degenerate first ring.
# Initialize the center universe.
universe = self._universes[-1][0]
rows[middle] = [str(universe._id)]
universe.create_xml_subelement(xml_element)
# Add universes one ring at a time.
for r in range(1, self._num_rings):
# r_prime increments down while r increments up.
r_prime = self._num_rings - 1 - r
theta = 0
y = middle + 2*r
# Climb down the top-right.
for i in range(r):
# Add the universe.
universe = self._universes[r_prime][theta]
rows[y].append(str(universe._id))
# Initialize the remaining universes.
for r in range(self._num_rings-1):
for theta in range(2*(self._num_rings - r)):
universe = self._universes[r][theta]
universe.create_xml_subelement(xml_element)
# Translate the indecies.
y -= 1
theta += 1
# Climb down the right.
for i in range(r):
# Add the universe.
universe = self._universes[r_prime][theta]
rows[y].append(str(universe._id))
universe.create_xml_subelement(xml_element)
# Translate the indecies.
y -= 2
theta += 1
# Climb down the bottom-right.
for i in range(r):
# Add the universe.
universe = self._universes[r_prime][theta]
rows[y].append(str(universe._id))
universe.create_xml_subelement(xml_element)
# Translate the indecies.
y -= 1
theta += 1
# Make sure we reached the bottom.
assert y == middle - 2*r
# Climb up the bottom-left.
for i in range(r):
# Add the universe.
universe = self._universes[r_prime][theta]
rows[y].insert(0, str(universe._id))
universe.create_xml_subelement(xml_element)
# Translate the indecies.
y += 1
theta += 1
# Climb up the left.
for i in range(r):
# Add the universe.
universe = self._universes[r_prime][theta]
rows[y].insert(0, str(universe._id))
universe.create_xml_subelement(xml_element)
# Translate the indecies.
y += 2
theta += 1
# Climb up the top-left.
for i in range(r):
# Add the universe.
universe = self._universes[r_prime][theta]
rows[y].insert(0, str(universe._id))
universe.create_xml_subelement(xml_element)
# Translate the indecies.
y += 1
theta += 1
# Make sure we reached the top and used all the universes.
assert y == middle + 2*r
assert theta == len(self._universes[r_prime])
# Collapse the list of lists of IDs into one string.
print(rows)
rows = [' '.join(x) for x in rows]
universe_ids = '\n'.join(rows)
# Get a string representation of the universe IDs.
universe_ids = self._repr_axial_slice(self._universes)
universes = ET.SubElement(lattice_subelement, "universes")
universes.text = universe_ids
universes.text = '\n' + universe_ids
if len(self._name) > 0:
xml_element.append(ET.Comment(self._name))
# Append the XML subelement for this Lattice to the XML element
xml_element.append(lattice_subelement)
def _repr_axial_slice(self, universes):
"""Return string representation for the given 2D group of universes.
The 'universes' argument should be a list of lists of universes where
each sub-list represents a single ring. The first list should be the
outer ring.
"""
assert len(universes) == self._num_rings
# Initialize the list for each row.
rows = [ [] for i in range(1 + 4 * (self._num_rings-1)) ]
middle = self._num_rings - 1
middle = 2 * (self._num_rings - 1)
# Start with the degenerate first ring.
universe = universes[-1][0]
rows[middle] = [str(universe._id)]
# Add universes one ring at a time.
for r in range(1, self._num_rings):
# r_prime increments down while r increments up.
r_prime = self._num_rings - 1 - r
theta = 0
y = middle + 2*r
# Climb down the top-right.
for i in range(r):
# Add the universe.
universe = universes[r_prime][theta]
rows[y].append(str(universe._id))
# Translate the indecies.
y -= 1
theta += 1
# Climb down the right.
for i in range(r):
# Add the universe.
universe = universes[r_prime][theta]
rows[y].append(str(universe._id))
# Translate the indecies.
y -= 2
theta += 1
# Climb down the bottom-right.
for i in range(r):
# Add the universe.
universe = universes[r_prime][theta]
rows[y].append(str(universe._id))
# Translate the indecies.
y -= 1
theta += 1
# Make sure we reached the bottom.
assert y == middle - 2*r
# Climb up the bottom-left.
for i in range(r):
# Add the universe.
universe = universes[r_prime][theta]
rows[y].insert(0, str(universe._id))
# Translate the indecies.
y += 1
theta += 1
# Climb up the left.
for i in range(r):
# Add the universe.
universe = universes[r_prime][theta]
rows[y].insert(0, str(universe._id))
# Translate the indecies.
y += 2
theta += 1
# Climb up the top-left.
for i in range(r):
# Add the universe.
universe = universes[r_prime][theta]
rows[y].insert(0, str(universe._id))
# Translate the indecies.
y += 1
theta += 1
# Make sure we reached the top and used all the universes.
assert y == middle + 2*r
assert theta == len(universes[r_prime])
# Collapse the list of lists of IDs into one string.
rows = [' '.join(x) for x in rows]
universe_ids = '\n'.join(rows)
return universe_ids