Add Plot.from_geometry() classmethod

This commit is contained in:
Paul Romano 2017-03-08 13:42:26 -06:00
parent 3913d55e2c
commit 61f0138555
9 changed files with 107 additions and 31 deletions

View file

@ -55,7 +55,8 @@ images: $(PDFS) $(PNGS)
clean:
-rm -rf $(BUILDDIR)/*
-rm $(PDFS)
-rm -rf $(PDFS)
-rm -rf source/pythonapi/generated/
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html

View file

@ -2178,7 +2178,7 @@ attributes or sub-elements. These are not used in "voxel" plots:
cells or materials to plot. This overrides any ``color`` color
specifications.
*Default*: None
*Default*: 255 255 255 (white)
:meshlines:
The ``meshlines`` sub-element allows for plotting the boundaries of a

View file

@ -224,6 +224,14 @@ class Cell(object):
'Call the Geometry.determine_paths() method.')
return self._paths
@property
def bounding_box(self):
if self.region is not None:
return self.region.bounding_box
else:
return (np.array([-np.inf, -np.inf, -np.inf]),
np.array([np.inf, np.inf, np.inf]))
@property
def num_instances(self):
return len(self.paths)

View file

@ -28,6 +28,9 @@ class Geometry(object):
----------
root_universe : openmc.Universe
Root universe which contains all others
bounding_box : 2-tuple of numpy.array
Lower-left and upper-right coordinates of an axis-aligned bounding box
of the universe.
"""
@ -41,6 +44,10 @@ class Geometry(object):
def root_universe(self):
return self._root_universe
@property
def bounding_box(self):
return self.root_universe.bounding_box
@root_universe.setter
def root_universe(self, root_universe):
check_type('root universe', root_universe, openmc.Universe)

View file

@ -23,12 +23,16 @@ def reset_auto_plot_id():
AUTO_PLOT_ID = 10000
BASES = ['xy', 'xz', 'yz']
_BASES = ['xy', 'xz', 'yz']
class Plot(object):
"""Definition of a finite region of space to be plotted, either as a slice plot
in two dimensions or as a voxel plot in three dimensions.
"""Definition of a finite region of space to be plotted.
OpenMC is capable of generating two-dimensional slice plots and
three-dimensional voxel plots. Colors that are used in plots can be given as
RGB tuples, e.g. (255, 255, 255) would be white, or by a string indicating a
valid `SVG color <https://www.w3.org/TR/SVG/types.html#ColorKeywords>`_.
Parameters
----------
@ -58,15 +62,14 @@ class Plot(object):
basis : {'xy', 'xz', 'yz'}
The basis directions for the plot
background : Iterable of int or str
Color of the background defined by RGB
Color of the background
mask_components : Iterable of openmc.Cell or openmc.Material
The cells or materials to plot
mask_background : Iterable of int
mask_background : Iterable of int or str
Color to apply to all cells/materials not listed in mask_components
defined by RGB
colors : dict
Dictionary indicating that certain cells/materials (keys) should be
colored with a specific RGB (values)
displayed with a particular color.
level : int
Universe depth to plot at
meshlines : dict
@ -80,7 +83,7 @@ class Plot(object):
self.id = plot_id
self.name = name
self._width = [4.0, 4.0]
self._pixels = [1000, 1000]
self._pixels = [400, 400]
self._origin = [0., 0., 0.]
self._filename = None
self._color_by = 'cell'
@ -206,7 +209,7 @@ class Plot(object):
@basis.setter
def basis(self, basis):
cv.check_value('plot basis', basis, ['xy', 'xz', 'yz'])
cv.check_value('plot basis', basis, _BASES)
self._basis = basis
@background.setter
@ -242,18 +245,21 @@ class Plot(object):
@mask_components.setter
def mask_components(self, mask_components):
cv.check_type('plot mask components', mask_components, Iterable, Integral)
for component in mask_components:
cv.check_greater_than('plot mask components', component, 0, True)
cv.check_type('plot mask components', mask_components, Iterable,
(openmc.Cell, openmc.Material))
self._mask_components = mask_components
@mask_background.setter
def mask_background(self, mask_background):
cv.check_type('plot mask background', mask_background, Iterable, Integral)
cv.check_length('plot mask background', mask_background, 3)
for rgb in mask_background:
cv.check_greater_than('plot mask background', rgb, 0, True)
cv.check_less_than('plot mask background', rgb, 256)
cv.check_type('plot mask background', mask_background, Iterable)
if isinstance(mask_background, string_types):
if not is_color_like(mask_background):
raise ValueError("'{}' is not a valid color.".format(mask_background))
else:
cv.check_length('plot mask_background', mask_background, 3)
for rgb in mask_background:
cv.check_greater_than('plot mask background', rgb, 0, True)
cv.check_less_than('plot mask background', rgb, 256)
self._mask_background = mask_background
@level.setter
@ -316,6 +322,51 @@ class Plot(object):
string += '{: <16}=\t{}\n'.format('\tMeshlines', self._meshlines)
return string
@classmethod
def from_geometry(cls, geometry, basis='xy', slice_coord=0.):
"""Return plot that encompasses a geometry.
Parameters
----------
geometry : openmc.Geometry
The geometry the base the plot off of
basis : {'xy', 'xz', 'yz'}
The basis directions for the plot
slice_coord : float
The level at which the slice plot should be plotted. For example, if
the basis is 'xy', this would indicate at what z value is used in
the origin.
"""
cv.check_type('geometry', geometry, openmc.Geometry)
cv.check_value('basis', basis, _BASES)
# Decide which axes to keep
if basis == 'xy':
pick_index = (0, 1)
slice_index = 2
elif basis == 'yz':
pick_index = (1, 2)
slice_index = 0
elif basis == 'xz':
pick_index = (0, 2)
slice_index = 1
# Get lower-left and upper-right coordinates for desired axes
lower_left, upper_right = geometry.bounding_box
lower_left = lower_left[np.array(pick_index)]
upper_right = upper_right[np.array(pick_index)]
if np.any(np.isinf((lower_left, upper_right))):
raise ValueError('The geometry does not appear to be bounded '
'in the {} plane.'.format(basis))
plot = cls()
plot.origin = np.insert((lower_left + upper_right)/2,
slice_index, slice_coord)
plot.width = upper_right - lower_left
return plot
def colorize(self, geometry, seed=1):
"""Generate a color scheme for each domain in the plot.
@ -446,10 +497,14 @@ class Plot(object):
if self._mask_components is not None:
subelement = ET.SubElement(element, "mask")
subelement.set("components", ' '.join(map(
str, self._mask_components)))
subelement.set("background", ' '.join(map(
str, self._mask_background)))
subelement.set("components", ' '.join(
str(d.id) for d in self._mask_components))
color = self._mask_background
if color is not None:
if isinstance(color, string_types):
color = [int(255*x) for x in to_rgb(color)]
subelement.set("background", ' '.join(
str(x) for x in color))
if self._level is not None:
subelement = ET.SubElement(element, "level")

View file

@ -301,7 +301,7 @@ class Union(Region):
----------
nodes : tuple of openmc.Region
Regions to take the union of
bounding_box : tuple of numpy.array
bounding_box : 2-tuple of numpy.array
Lower-left and upper-right coordinates of an axis-aligned bounding box
"""

View file

@ -46,6 +46,9 @@ class Universe(object):
Volume of the universe in cm^3. This can either be set manually or
calculated in a stochastic volume calculation and added via the
:meth:`Universe.add_volume_information` method.
bounding_box : 2-tuple of numpy.array
Lower-left and upper-right coordinates of an axis-aligned bounding box
of the universe.
"""
@ -105,6 +108,11 @@ class Universe(object):
def volume(self):
return self._volume
@property
def bounding_box(self):
regions = [c.region for c in self.cells.values()]
return openmc.Union(*regions).bounding_box
@id.setter
def id(self, universe_id):
if universe_id is None:

View file

@ -80,9 +80,7 @@ class VolumeCalculation(object):
# user-specified one is valid
if self.domain_type == 'cell':
for c in domains:
if c.region is None:
continue
ll, ur = c.region.bounding_box
ll, ur = c.bounding_box
if np.any(np.isinf(ll)) or np.any(np.isinf(ur)):
continue
if (np.any(np.asarray(lower_left) > ll) or

View file

@ -4634,13 +4634,12 @@ contains
end do
! Alter colors based on mask information
do j=1,size(pl % colors)
if (.not. any(j .eq. iarray)) then
do j = 1, size(pl % colors)
if (.not. any(j == iarray)) then
if (check_for_node(node_mask, "background")) then
call get_node_array(node_mask, "background", pl % colors(j) % rgb)
else
call fatal_error("Missing <background> in mask of plot " &
// trim(to_str(pl % id)))
pl % colors(j) % rgb(:) = [255, 255, 255]
end if
end if
end do