mirror of
https://github.com/openmc-dev/openmc.git
synced 2026-07-27 13:45:36 -04:00
Merge pull request #826 from paulromano/plot-improvements
Improvements to geometry plotting
This commit is contained in:
commit
561cf39b63
33 changed files with 531 additions and 254 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -188,6 +188,7 @@ Running OpenMC
|
|||
openmc.run
|
||||
openmc.calculate_volumes
|
||||
openmc.plot_geometry
|
||||
openmc.plot_inline
|
||||
|
||||
Post-processing
|
||||
---------------
|
||||
|
|
|
|||
|
|
@ -2056,13 +2056,12 @@ sub-elements:
|
|||
|
||||
*Default*: "plot"
|
||||
|
||||
:color:
|
||||
Keyword for plot coloring. This can only be either ``cell`` or ``mat``,
|
||||
which colors regions by cells and materials, respectively. For voxel plots,
|
||||
this determines which id (cell or material) is associated with each
|
||||
position.
|
||||
:color_by:
|
||||
Keyword for plot coloring. This can be either "cell" or "material", which
|
||||
colors regions by cells and materials, respectively. For voxel plots, this
|
||||
determines which id (cell or material) is associated with each position.
|
||||
|
||||
*Default*: ``cell``
|
||||
*Default*: "cell"
|
||||
|
||||
:level:
|
||||
Universe depth to plot at (optional). This parameter controls how many
|
||||
|
|
@ -2148,10 +2147,10 @@ attributes or sub-elements. These are not used in "voxel" plots:
|
|||
|
||||
*Default*: 0 0 0 (black)
|
||||
|
||||
:col_spec:
|
||||
:color:
|
||||
Any number of this optional tag may be included in each ``<plot>`` element,
|
||||
which can override the default random colors for cells or materials. Each
|
||||
``col_spec`` element must contain ``id`` and ``rgb`` sub-elements.
|
||||
``color`` element must contain ``id`` and ``rgb`` sub-elements.
|
||||
|
||||
:id:
|
||||
Specifies the cell or material unique id for the color specification.
|
||||
|
|
@ -2161,11 +2160,11 @@ attributes or sub-elements. These are not used in "voxel" plots:
|
|||
separated by spaces.
|
||||
|
||||
As an example, if your plot is colored by material and you want material 23
|
||||
to be blue, the corresponding ``col_spec`` element would look like:
|
||||
to be blue, the corresponding ``color`` element would look like:
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<col_spec id="23" rgb="0 0 255" />
|
||||
<color id="23" rgb="0 0 255" />
|
||||
|
||||
*Default*: None
|
||||
|
||||
|
|
@ -2181,10 +2180,10 @@ attributes or sub-elements. These are not used in "voxel" plots:
|
|||
|
||||
:background:
|
||||
Color to apply to all cells or materials not in the ``components`` list of
|
||||
cells or materials to plot. This overrides any ``col_spec`` color
|
||||
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
|
||||
|
|
|
|||
|
|
@ -118,7 +118,7 @@ plot = openmc.Plot(plot_id=1)
|
|||
plot.origin = [0, 0, 0]
|
||||
plot.width = [20, 20]
|
||||
plot.pixels = [200, 200]
|
||||
plot.color = 'cell'
|
||||
plot.color_by = 'cell'
|
||||
|
||||
# Instantiate a Plots collection and export to XML
|
||||
plot_file = openmc.Plots([plot])
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@ plot_xy.filename = 'plot_xy'
|
|||
plot_xy.origin = [0, 0, 0]
|
||||
plot_xy.width = [6, 6]
|
||||
plot_xy.pixels = [400, 400]
|
||||
plot_xy.color = 'mat'
|
||||
plot_xy.color_by = 'material'
|
||||
|
||||
plot_yz = openmc.Plot(plot_id=2)
|
||||
plot_yz.filename = 'plot_yz'
|
||||
|
|
@ -140,7 +140,7 @@ plot_yz.basis = 'yz'
|
|||
plot_yz.origin = [0, 0, 0]
|
||||
plot_yz.width = [8, 8]
|
||||
plot_yz.pixels = [400, 400]
|
||||
plot_yz.color = 'mat'
|
||||
plot_yz.color_by = 'material'
|
||||
|
||||
# Instantiate a Plots collection, add plots, and export to XML
|
||||
plot_file = openmc.Plots((plot_xy, plot_yz))
|
||||
|
|
|
|||
|
|
@ -138,7 +138,7 @@ plot = openmc.Plot(plot_id=1)
|
|||
plot.origin = [0, 0, 0]
|
||||
plot.width = [4, 4]
|
||||
plot.pixels = [400, 400]
|
||||
plot.color = 'mat'
|
||||
plot.color_by = 'material'
|
||||
|
||||
# Instantiate a Plots object and export to XML
|
||||
plot_file = openmc.Plots([plot])
|
||||
|
|
|
|||
|
|
@ -131,7 +131,7 @@ plot = openmc.Plot(plot_id=1)
|
|||
plot.origin = [0, 0, 0]
|
||||
plot.width = [4, 4]
|
||||
plot.pixels = [400, 400]
|
||||
plot.color = 'mat'
|
||||
plot.color_by = 'material'
|
||||
|
||||
# Instantiate a Plots collection and export to XML
|
||||
plot_file = openmc.Plots([plot])
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0"?>
|
||||
<plots>
|
||||
<plot id="1" type="slice">
|
||||
<color>cell</color>
|
||||
<color_by>cell</color_by>
|
||||
<origin>0. 0. 0.</origin>
|
||||
<width>20. 20.</width>
|
||||
<pixels>200 200</pixels>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0"?>
|
||||
<plots>
|
||||
|
||||
<plot id="1" color="mat">
|
||||
<plot id="1" color_by="material">
|
||||
<origin>0. 0. 0.</origin>
|
||||
<width>4.0 4.0</width>
|
||||
<pixels>400 400</pixels>
|
||||
|
|
|
|||
|
|
@ -1,11 +1,10 @@
|
|||
<?xml version="1.0"?>
|
||||
<plots>
|
||||
|
||||
<plot id="1" color="mat">
|
||||
<plot id="1" color_by="material">
|
||||
<origin>0. 0. 0.</origin>
|
||||
<width>4.0 4.0</width>
|
||||
<pixels>400 400</pixels>
|
||||
<!-- <meshlines mesh="1" linewidth="2" color="0 255 0"/> -->
|
||||
</plot>
|
||||
|
||||
</plots>
|
||||
|
|
|
|||
|
|
@ -4,21 +4,21 @@
|
|||
<plot>
|
||||
<id>1</id>
|
||||
<filename>mat</filename>
|
||||
<color>material</color>
|
||||
<color_by>material</color_by>
|
||||
<origin>0 0 0</origin>
|
||||
<width>1.26 1.26</width>
|
||||
<type>slice</type>
|
||||
<pixels>1000 1000 </pixels>
|
||||
<col_spec id="1" rgb="255 0 0" />
|
||||
<col_spec id="2" rgb="0 0 0" />
|
||||
<col_spec id="3" rgb="0 255 0" />
|
||||
<col_spec id="4" rgb="0 0 255" />
|
||||
<color id="1" rgb="255 0 0" />
|
||||
<color id="2" rgb="0 0 0" />
|
||||
<color id="3" rgb="0 255 0" />
|
||||
<color id="4" rgb="0 0 255" />
|
||||
</plot>
|
||||
|
||||
<plot>
|
||||
<id>2</id>
|
||||
<filename>cell</filename>
|
||||
<color>cell</color>
|
||||
<color_by>cell</color_by>
|
||||
<origin>0 0 0</origin>
|
||||
<width>1.26 1.26</width>
|
||||
<type>slice</type>
|
||||
|
|
|
|||
|
|
@ -218,6 +218,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)
|
||||
|
|
@ -267,22 +275,23 @@ class Cell(object):
|
|||
@rotation.setter
|
||||
def rotation(self, rotation):
|
||||
if not isinstance(self.fill, openmc.Universe):
|
||||
raise RuntimeError('Cell rotation can only be applied if the cell '
|
||||
'is filled with a Universe')
|
||||
raise TypeError('Cell rotation can only be applied if the cell '
|
||||
'is filled with a Universe.')
|
||||
|
||||
cv.check_type('cell rotation', rotation, Iterable, Real)
|
||||
cv.check_length('cell rotation', rotation, 3)
|
||||
self._rotation = np.asarray(rotation)
|
||||
|
||||
# Save rotation matrix
|
||||
# Save rotation matrix -- the reason we do this instead of having it be
|
||||
# automatically calculated when the rotation_matrix property is accessed
|
||||
# is so that plotting on a rotated geometry can be done faster.
|
||||
phi, theta, psi = self.rotation*(-pi/180.)
|
||||
c3, s3 = cos(phi), sin(phi)
|
||||
c2, s2 = cos(theta), sin(theta)
|
||||
c1, s1 = cos(psi), sin(psi)
|
||||
self._rotation_matrix = np.array([
|
||||
[c1*c2, c1*s2*s3 - c3*s1, s1*s3 + c1*c3*s2],
|
||||
[c2*s1, c1*c3 + s1*s2*s3, c3*s1*s2 - c1*s3],
|
||||
[-s2, c2*s3, c2*c3]])
|
||||
return np.array([[c1*c2, c1*s2*s3 - c3*s1, s1*s3 + c1*c3*s2],
|
||||
[c2*s1, c1*c3 + s1*s2*s3, c3*s1*s2 - c1*s3],
|
||||
[-s2, c2*s3, c2*c3]])
|
||||
|
||||
@translation.setter
|
||||
def translation(self, translation):
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
from __future__ import print_function
|
||||
from collections import Iterable
|
||||
import subprocess
|
||||
from numbers import Integral
|
||||
|
||||
from six import string_types
|
||||
|
||||
import openmc
|
||||
from openmc import VolumeCalculation
|
||||
|
||||
|
||||
|
|
@ -32,17 +34,60 @@ def plot_geometry(output=True, openmc_exec='openmc', cwd='.'):
|
|||
|
||||
Parameters
|
||||
----------
|
||||
output : bool
|
||||
output : bool, optional
|
||||
Capture OpenMC output from standard out
|
||||
openmc_exec : str
|
||||
openmc_exec : str, optional
|
||||
Path to OpenMC executable
|
||||
cwd : str, optional
|
||||
Path to working directory to run in. Defaults to the current working directory.
|
||||
Path to working directory to run in
|
||||
|
||||
"""
|
||||
return _run([openmc_exec, '-p'], output, cwd)
|
||||
|
||||
|
||||
def plot_inline(plots, openmc_exec='openmc', cwd='.', convert_exec='convert'):
|
||||
"""Display plots inline in a Jupyter notebook.
|
||||
|
||||
This function requires that you have a program installed to convert PPM
|
||||
files to PNG files. Typically, that would be `ImageMagick
|
||||
<https://www.imagemagick.org>`_ which includes a `convert` command.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
plots : Iterable of openmc.Plot
|
||||
Plots to display
|
||||
openmc_exec : str
|
||||
Path to OpenMC executable
|
||||
cwd : str, optional
|
||||
Path to working directory to run in
|
||||
convert_exec : str, optional
|
||||
Command that can convert PPM files into PNG files
|
||||
|
||||
"""
|
||||
from IPython.display import Image, display
|
||||
|
||||
if not isinstance(plots, Iterable):
|
||||
plots = [plots]
|
||||
|
||||
# Create plots.xml
|
||||
openmc.Plots(plots).export_to_xml()
|
||||
|
||||
# Run OpenMC in geometry plotting mode
|
||||
plot_geometry(False, openmc_exec, cwd)
|
||||
|
||||
images = []
|
||||
if plots is not None:
|
||||
for p in plots:
|
||||
if p.filename is not None:
|
||||
ppm_file = '{}.ppm'.format(p.filename)
|
||||
else:
|
||||
ppm_file = 'plot_{}.ppm'.format(p.id)
|
||||
png_file = ppm_file.replace('.ppm', '.png')
|
||||
subprocess.check_call([convert_exec, ppm_file, png_file])
|
||||
images.append(Image(png_file))
|
||||
display(*images)
|
||||
|
||||
|
||||
def calculate_volumes(threads=None, output=True, cwd='.',
|
||||
openmc_exec='openmc', mpi_args=None):
|
||||
"""Run stochastic volume calculations in OpenMC.
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -464,16 +464,16 @@ class Material(object):
|
|||
Nuclide to remove
|
||||
|
||||
"""
|
||||
cv.check_type('nuclide', nuclide, string_types + (openmc.Nuclide,))
|
||||
|
||||
if not isinstance(nuclide, openmc.Nuclide):
|
||||
msg = 'Unable to remove a Nuclide "{}" in Material ID="{}" ' \
|
||||
'since it is not a Nuclide'.format(self._id, nuclide)
|
||||
raise ValueError(msg)
|
||||
if isinstance(nuclide, string_types):
|
||||
nuclide = openmc.Nuclide(nuclide)
|
||||
|
||||
# If the Material contains the Nuclide, delete it
|
||||
for nuc in self._nuclides:
|
||||
if nuclide == nuc:
|
||||
if nuclide == nuc[0]:
|
||||
self._nuclides.remove(nuc)
|
||||
break
|
||||
|
||||
def add_macroscopic(self, macroscopic):
|
||||
"""Add a macroscopic to the material. This will also set the
|
||||
|
|
@ -625,15 +625,14 @@ class Material(object):
|
|||
Element to remove
|
||||
|
||||
"""
|
||||
cv.check_type('element', element, string_types + (openmc.Element,))
|
||||
|
||||
if not isinstance(element, openmc.Element):
|
||||
msg = 'Unable to remove "{}" in Material ID="{}" ' \
|
||||
'since it is not an Element'.format(self.id, element)
|
||||
raise ValueError(msg)
|
||||
if isinstance(element, string_types):
|
||||
element = openmc.Element(element)
|
||||
|
||||
# If the Material contains the Element, delete it
|
||||
for elm in self._elements:
|
||||
if element == elm:
|
||||
if element == elm[0]:
|
||||
self._elements.remove(elm)
|
||||
|
||||
def add_s_alpha_beta(self, name):
|
||||
|
|
|
|||
465
openmc/plots.py
465
openmc/plots.py
|
|
@ -1,4 +1,4 @@
|
|||
from collections import Iterable
|
||||
from collections import Iterable, Mapping
|
||||
from numbers import Real, Integral
|
||||
from xml.etree import ElementTree as ET
|
||||
import sys
|
||||
|
|
@ -22,12 +22,166 @@ def reset_auto_plot_id():
|
|||
AUTO_PLOT_ID = 10000
|
||||
|
||||
|
||||
BASES = ['xy', 'xz', 'yz']
|
||||
_BASES = ['xy', 'xz', 'yz']
|
||||
|
||||
_SVG_COLORS = {
|
||||
'aliceblue': (240, 248, 255),
|
||||
'antiquewhite': (250, 235, 215),
|
||||
'aqua': (0, 255, 255),
|
||||
'aquamarine': (127, 255, 212),
|
||||
'azure': (240, 255, 255),
|
||||
'beige': (245, 245, 220),
|
||||
'bisque': (255, 228, 196),
|
||||
'black': (0, 0, 0),
|
||||
'blanchedalmond': (255, 235, 205),
|
||||
'blue': (0, 0, 255),
|
||||
'blueviolet': (138, 43, 226),
|
||||
'brown': (165, 42, 42),
|
||||
'burlywood': (222, 184, 135),
|
||||
'cadetblue': (95, 158, 160),
|
||||
'chartreuse': (127, 255, 0),
|
||||
'chocolate': (210, 105, 30),
|
||||
'coral': (255, 127, 80),
|
||||
'cornflowerblue': (100, 149, 237),
|
||||
'cornsilk': (255, 248, 220),
|
||||
'crimson': (220, 20, 60),
|
||||
'cyan': (0, 255, 255),
|
||||
'darkblue': (0, 0, 139),
|
||||
'darkcyan': (0, 139, 139),
|
||||
'darkgoldenrod': (184, 134, 11),
|
||||
'darkgray': (169, 169, 169),
|
||||
'darkgreen': (0, 100, 0),
|
||||
'darkgrey': (169, 169, 169),
|
||||
'darkkhaki': (189, 183, 107),
|
||||
'darkmagenta': (139, 0, 139),
|
||||
'darkolivegreen': (85, 107, 47),
|
||||
'darkorange': (255, 140, 0),
|
||||
'darkorchid': (153, 50, 204),
|
||||
'darkred': (139, 0, 0),
|
||||
'darksalmon': (233, 150, 122),
|
||||
'darkseagreen': (143, 188, 143),
|
||||
'darkslateblue': (72, 61, 139),
|
||||
'darkslategray': (47, 79, 79),
|
||||
'darkslategrey': (47, 79, 79),
|
||||
'darkturquoise': (0, 206, 209),
|
||||
'darkviolet': (148, 0, 211),
|
||||
'deeppink': (255, 20, 147),
|
||||
'deepskyblue': (0, 191, 255),
|
||||
'dimgray': (105, 105, 105),
|
||||
'dimgrey': (105, 105, 105),
|
||||
'dodgerblue': (30, 144, 255),
|
||||
'firebrick': (178, 34, 34),
|
||||
'floralwhite': (255, 250, 240),
|
||||
'forestgreen': (34, 139, 34),
|
||||
'fuchsia': (255, 0, 255),
|
||||
'gainsboro': (220, 220, 220),
|
||||
'ghostwhite': (248, 248, 255),
|
||||
'gold': (255, 215, 0),
|
||||
'goldenrod': (218, 165, 32),
|
||||
'gray': (128, 128, 128),
|
||||
'green': (0, 128, 0),
|
||||
'greenyellow': (173, 255, 47),
|
||||
'grey': (128, 128, 128),
|
||||
'honeydew': (240, 255, 240),
|
||||
'hotpink': (255, 105, 180),
|
||||
'indianred': (205, 92, 92),
|
||||
'indigo': (75, 0, 130),
|
||||
'ivory': (255, 255, 240),
|
||||
'khaki': (240, 230, 140),
|
||||
'lavender': (230, 230, 250),
|
||||
'lavenderblush': (255, 240, 245),
|
||||
'lawngreen': (124, 252, 0),
|
||||
'lemonchiffon': (255, 250, 205),
|
||||
'lightblue': (173, 216, 230),
|
||||
'lightcoral': (240, 128, 128),
|
||||
'lightcyan': (224, 255, 255),
|
||||
'lightgoldenrodyellow': (250, 250, 210),
|
||||
'lightgray': (211, 211, 211),
|
||||
'lightgreen': (144, 238, 144),
|
||||
'lightgrey': (211, 211, 211),
|
||||
'lightpink': (255, 182, 193),
|
||||
'lightsalmon': (255, 160, 122),
|
||||
'lightseagreen': (32, 178, 170),
|
||||
'lightskyblue': (135, 206, 250),
|
||||
'lightslategray': (119, 136, 153),
|
||||
'lightslategrey': (119, 136, 153),
|
||||
'lightsteelblue': (176, 196, 222),
|
||||
'lightyellow': (255, 255, 224),
|
||||
'lime': (0, 255, 0),
|
||||
'limegreen': (50, 205, 50),
|
||||
'linen': (250, 240, 230),
|
||||
'magenta': (255, 0, 255),
|
||||
'maroon': (128, 0, 0),
|
||||
'mediumaquamarine': (102, 205, 170),
|
||||
'mediumblue': (0, 0, 205),
|
||||
'mediumorchid': (186, 85, 211),
|
||||
'mediumpurple': (147, 112, 219),
|
||||
'mediumseagreen': (60, 179, 113),
|
||||
'mediumslateblue': (123, 104, 238),
|
||||
'mediumspringgreen': (0, 250, 154),
|
||||
'mediumturquoise': (72, 209, 204),
|
||||
'mediumvioletred': (199, 21, 133),
|
||||
'midnightblue': (25, 25, 112),
|
||||
'mintcream': (245, 255, 250),
|
||||
'mistyrose': (255, 228, 225),
|
||||
'moccasin': (255, 228, 181),
|
||||
'navajowhite': (255, 222, 173),
|
||||
'navy': (0, 0, 128),
|
||||
'oldlace': (253, 245, 230),
|
||||
'olive': (128, 128, 0),
|
||||
'olivedrab': (107, 142, 35),
|
||||
'orange': (255, 165, 0),
|
||||
'orangered': (255, 69, 0),
|
||||
'orchid': (218, 112, 214),
|
||||
'palegoldenrod': (238, 232, 170),
|
||||
'palegreen': (152, 251, 152),
|
||||
'paleturquoise': (175, 238, 238),
|
||||
'palevioletred': (219, 112, 147),
|
||||
'papayawhip': (255, 239, 213),
|
||||
'peachpuff': (255, 218, 185),
|
||||
'peru': (205, 133, 63),
|
||||
'pink': (255, 192, 203),
|
||||
'plum': (221, 160, 221),
|
||||
'powderblue': (176, 224, 230),
|
||||
'purple': (128, 0, 128),
|
||||
'red': (255, 0, 0),
|
||||
'rosybrown': (188, 143, 143),
|
||||
'royalblue': (65, 105, 225),
|
||||
'saddlebrown': (139, 69, 19),
|
||||
'salmon': (250, 128, 114),
|
||||
'sandybrown': (244, 164, 96),
|
||||
'seagreen': (46, 139, 87),
|
||||
'seashell': (255, 245, 238),
|
||||
'sienna': (160, 82, 45),
|
||||
'silver': (192, 192, 192),
|
||||
'skyblue': (135, 206, 235),
|
||||
'slateblue': (106, 90, 205),
|
||||
'slategray': (112, 128, 144),
|
||||
'slategrey': (112, 128, 144),
|
||||
'snow': (255, 250, 250),
|
||||
'springgreen': (0, 255, 127),
|
||||
'steelblue': (70, 130, 180),
|
||||
'tan': (210, 180, 140),
|
||||
'teal': (0, 128, 128),
|
||||
'thistle': (216, 191, 216),
|
||||
'tomato': (255, 99, 71),
|
||||
'turquoise': (64, 224, 208),
|
||||
'violet': (238, 130, 238),
|
||||
'wheat': (245, 222, 179),
|
||||
'white': (255, 255, 255),
|
||||
'whitesmoke': (245, 245, 245),
|
||||
'yellow': (255, 255, 0),
|
||||
'yellowgreen': (154, 205, 50)
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
----------
|
||||
|
|
@ -50,22 +204,21 @@ class Plot(object):
|
|||
Origin (center) of the plot
|
||||
filename :
|
||||
Path to write the plot to
|
||||
color : {'cell', 'mat'}
|
||||
color_by : {'cell', 'material'}
|
||||
Indicate whether the plot should be colored by cell or by material
|
||||
type : {'slice', 'voxel'}
|
||||
The type of the plot
|
||||
basis : {'xy', 'xz', 'yz'}
|
||||
The basis directions for the plot
|
||||
background : tuple or list of ndarray
|
||||
Color of the background defined by RGB
|
||||
mask_components : Iterable of int
|
||||
Unique id numbers of the cells or materials to plot
|
||||
mask_background : Iterable of int
|
||||
background : Iterable of int or str
|
||||
Color of the background
|
||||
mask_components : Iterable of openmc.Cell or openmc.Material
|
||||
The cells or materials to plot
|
||||
mask_background : Iterable of int or str
|
||||
Color to apply to all cells/materials not listed in mask_components
|
||||
defined by RGB
|
||||
col_spec : dict
|
||||
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
|
||||
|
|
@ -79,16 +232,16 @@ 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 = 'plot'
|
||||
self._color = 'cell'
|
||||
self._filename = None
|
||||
self._color_by = 'cell'
|
||||
self._type = 'slice'
|
||||
self._basis = 'xy'
|
||||
self._background = None
|
||||
self._mask_components = None
|
||||
self._mask_background = None
|
||||
self._col_spec = None
|
||||
self._colors = {}
|
||||
self._level = None
|
||||
self._meshlines = None
|
||||
|
||||
|
|
@ -117,8 +270,8 @@ class Plot(object):
|
|||
return self._filename
|
||||
|
||||
@property
|
||||
def color(self):
|
||||
return self._color
|
||||
def color_by(self):
|
||||
return self._color_by
|
||||
|
||||
@property
|
||||
def type(self):
|
||||
|
|
@ -141,8 +294,8 @@ class Plot(object):
|
|||
return self._mask_background
|
||||
|
||||
@property
|
||||
def col_spec(self):
|
||||
return self._col_spec
|
||||
def colors(self):
|
||||
return self._colors
|
||||
|
||||
@property
|
||||
def level(self):
|
||||
|
|
@ -193,70 +346,69 @@ class Plot(object):
|
|||
cv.check_type('filename', filename, string_types)
|
||||
self._filename = filename
|
||||
|
||||
@color.setter
|
||||
def color(self, color):
|
||||
cv.check_type('plot color', color, string_types)
|
||||
cv.check_value('plot color', color, ['cell', 'mat'])
|
||||
self._color = color
|
||||
@color_by.setter
|
||||
def color_by(self, color_by):
|
||||
cv.check_value('plot color_by', color_by, ['cell', 'material'])
|
||||
self._color_by = color_by
|
||||
|
||||
@type.setter
|
||||
def type(self, plottype):
|
||||
cv.check_type('plot type', plottype, string_types)
|
||||
cv.check_value('plot type', plottype, ['slice', 'voxel'])
|
||||
self._type = plottype
|
||||
|
||||
@basis.setter
|
||||
def basis(self, basis):
|
||||
cv.check_type('plot basis', basis, string_types)
|
||||
cv.check_value('plot basis', basis, ['xy', 'xz', 'yz'])
|
||||
cv.check_value('plot basis', basis, _BASES)
|
||||
self._basis = basis
|
||||
|
||||
@background.setter
|
||||
def background(self, background):
|
||||
cv.check_type('plot background', background, Iterable, Integral)
|
||||
cv.check_length('plot background', background, 3)
|
||||
for rgb in background:
|
||||
cv.check_greater_than('plot background', rgb, 0, True)
|
||||
cv.check_less_than('plot background', rgb, 256)
|
||||
cv.check_type('plot background', background, Iterable)
|
||||
if isinstance(background, string_types):
|
||||
if background.lower() not in _SVG_COLORS:
|
||||
raise ValueError("'{}' is not a valid color.".format(background))
|
||||
else:
|
||||
cv.check_length('plot background', background, 3)
|
||||
for rgb in background:
|
||||
cv.check_greater_than('plot background', rgb, 0, True)
|
||||
cv.check_less_than('plot background', rgb, 256)
|
||||
self._background = background
|
||||
|
||||
@col_spec.setter
|
||||
def col_spec(self, col_spec):
|
||||
cv.check_type('plot col_spec parameter', col_spec, dict, Integral)
|
||||
@colors.setter
|
||||
def colors(self, colors):
|
||||
cv.check_type('plot colors', colors, Mapping)
|
||||
for key, value in colors.items():
|
||||
cv.check_type('plot color key', key, (openmc.Cell, openmc.Material))
|
||||
cv.check_type('plot color value', value, Iterable)
|
||||
if isinstance(value, string_types):
|
||||
if value.lower() not in _SVG_COLORS:
|
||||
raise ValueError("'{}' is not a valid color.".format(value))
|
||||
else:
|
||||
cv.check_length('plot color (RGB)', value, 3)
|
||||
for component in value:
|
||||
cv.check_type('RGB component', component, Real)
|
||||
cv.check_greater_than('RGB component', component, 0, True)
|
||||
cv.check_less_than('RGB component', component, 255, True)
|
||||
|
||||
for key in col_spec:
|
||||
if key < 0:
|
||||
msg = 'Unable to create Plot ID="{0}" with col_spec ID "{1}" ' \
|
||||
'which is less than 0'.format(self._id, key)
|
||||
raise ValueError(msg)
|
||||
|
||||
elif not isinstance(col_spec[key], Iterable):
|
||||
msg = 'Unable to create Plot ID="{0}" with col_spec RGB values' \
|
||||
' "{1}" which is not iterable'.format(self._id, col_spec[key])
|
||||
raise ValueError(msg)
|
||||
|
||||
elif len(col_spec[key]) != 3:
|
||||
msg = 'Unable to create Plot ID="{0}" with col_spec RGB ' \
|
||||
'values of length "{1}" since 3 values must be ' \
|
||||
'input'.format(self._id, len(col_spec[key]))
|
||||
raise ValueError(msg)
|
||||
|
||||
self._col_spec = col_spec
|
||||
self._colors = colors
|
||||
|
||||
@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 mask_background.lower() not in _SVG_COLORS:
|
||||
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
|
||||
|
|
@ -300,27 +452,70 @@ class Plot(object):
|
|||
|
||||
def __repr__(self):
|
||||
string = 'Plot\n'
|
||||
string += '{0: <16}{1}{2}\n'.format('\tID', '=\t', self._id)
|
||||
string += '{0: <16}{1}{2}\n'.format('\tName', '=\t', self._name)
|
||||
string += '{0: <16}{1}{2}\n'.format('\tFilename', '=\t', self._filename)
|
||||
string += '{0: <16}{1}{2}\n'.format('\tType', '=\t', self._type)
|
||||
string += '{0: <16}{1}{2}\n'.format('\tBasis', '=\t', self._basis)
|
||||
string += '{0: <16}{1}{2}\n'.format('\tWidth', '=\t', self._width)
|
||||
string += '{0: <16}{1}{2}\n'.format('\tOrigin', '=\t', self._origin)
|
||||
string += '{0: <16}{1}{2}\n'.format('\tPixels', '=\t', self._origin)
|
||||
string += '{0: <16}{1}{2}\n'.format('\tColor', '=\t', self._color)
|
||||
string += '{0: <16}{1}{2}\n'.format('\tBackground', '=\t',
|
||||
self._background)
|
||||
string += '{0: <16}{1}{2}\n'.format('\tMask components', '=\t',
|
||||
string += '{: <16}=\t{}\n'.format('\tID', self._id)
|
||||
string += '{: <16}=\t{}\n'.format('\tName', self._name)
|
||||
string += '{: <16}=\t{}\n'.format('\tFilename', self._filename)
|
||||
string += '{: <16}=\t{}\n'.format('\tType', self._type)
|
||||
string += '{: <16}=\t{}\n'.format('\tBasis', self._basis)
|
||||
string += '{: <16}=\t{}\n'.format('\tWidth', self._width)
|
||||
string += '{: <16}=\t{}\n'.format('\tOrigin', self._origin)
|
||||
string += '{: <16}=\t{}\n'.format('\tPixels', self._origin)
|
||||
string += '{: <16}=\t{}\n'.format('\tColor by', self._color)
|
||||
string += '{: <16}=\t{}\n'.format('\tBackground', self._background)
|
||||
string += '{: <16}=\t{}\n'.format('\tMask components',
|
||||
self._mask_components)
|
||||
string += '{0: <16}{1}{2}\n'.format('\tMask background', '=\t',
|
||||
string += '{: <16}=\t{}\n'.format('\tMask background',
|
||||
self._mask_background)
|
||||
string += '{0: <16}{1}{2}\n'.format('\tCol Spec', '=\t', self._col_spec)
|
||||
string += '{0: <16}{1}{2}\n'.format('\tLevel', '=\t', self._level)
|
||||
string += '{0: <16}{1}{2}\n'.format('\tMeshlines', '=\t',
|
||||
self._meshlines)
|
||||
string += '{: <16}=\t{}\n'.format('\tColors', self._colors)
|
||||
string += '{: <16}=\t{}\n'.format('\tLevel', self._level)
|
||||
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 the z value 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.
|
||||
|
||||
|
|
@ -341,78 +536,70 @@ class Plot(object):
|
|||
cv.check_greater_than('seed', seed, 1, equality=True)
|
||||
|
||||
# Get collections of the domains which will be plotted
|
||||
if self.color is 'mat':
|
||||
domains = geometry.get_all_materials()
|
||||
if self.color_by == 'material':
|
||||
domains = geometry.get_all_materials().values()
|
||||
else:
|
||||
domains = geometry.get_all_cells()
|
||||
domains = geometry.get_all_cells().values()
|
||||
|
||||
# Set the seed for the random number generator
|
||||
np.random.seed(seed)
|
||||
|
||||
# Generate random colors for each feature
|
||||
self.col_spec = {}
|
||||
for domain_id in domains:
|
||||
r = np.random.randint(0, 256)
|
||||
g = np.random.randint(0, 256)
|
||||
b = np.random.randint(0, 256)
|
||||
self.col_spec[domain_id] = (r, g, b)
|
||||
for domain in domains:
|
||||
self.colors[domain] = np.random.randint(0, 256, (3,))
|
||||
|
||||
def highlight_domains(self, geometry, domains, seed=1,
|
||||
alpha=0.5, background='gray'):
|
||||
"""Use alpha compositing to highlight one or more domains in the plot.
|
||||
|
||||
This routine generates a color scheme and applies alpha compositing
|
||||
to make all domains except the highlighted ones appear partially
|
||||
This routine generates a color scheme and applies alpha compositing to
|
||||
make all domains except the highlighted ones appear partially
|
||||
transparent.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
geometry : openmc.Geometry
|
||||
The geometry for which the plot is defined
|
||||
domains : Iterable of Integral
|
||||
domains : Iterable of openmc.Cell or openmc.Material
|
||||
A collection of the domain IDs to highlight in the plot
|
||||
seed : Integral
|
||||
seed : int
|
||||
The random number seed used to generate the color scheme
|
||||
alpha : Real in [0,1]
|
||||
The value to apply in alpha compisiting
|
||||
background : 3-tuple of Integral or 'white' or 'black' or 'gray'
|
||||
alpha : float
|
||||
The value between 0 and 1 to apply in alpha compisiting
|
||||
background : 3-tuple of int or str
|
||||
The background color to apply in alpha compisiting
|
||||
|
||||
"""
|
||||
|
||||
cv.check_iterable_type('domains', domains, Integral)
|
||||
cv.check_type('domains', domains, Iterable,
|
||||
(openmc.Cell, openmc.Material))
|
||||
cv.check_type('alpha', alpha, Real)
|
||||
cv.check_greater_than('alpha', alpha, 0., equality=True)
|
||||
cv.check_less_than('alpha', alpha, 1., equality=True)
|
||||
cv.check_type('background', background, Iterable)
|
||||
|
||||
# Get a background (R,G,B) tuple to apply in alpha compositing
|
||||
if isinstance(background, string_types):
|
||||
if background == 'white':
|
||||
background = (255, 255, 255)
|
||||
elif background == 'black':
|
||||
background = (0, 0, 0)
|
||||
elif background == 'gray':
|
||||
background = (160, 160, 160)
|
||||
else:
|
||||
msg = 'The background "{}" is not defined'.format(background)
|
||||
raise ValueError(msg)
|
||||
|
||||
cv.check_iterable_type('background', background, Integral)
|
||||
if background.lower() not in _SVG_COLORS:
|
||||
raise ValueError("'{}' is not a valid color.".format(background))
|
||||
background = _SVG_COLORS[background.lower()]
|
||||
|
||||
# Generate a color scheme
|
||||
self.colorize(geometry, seed)
|
||||
|
||||
# Apply alpha compositing to the colors for all domains
|
||||
# other than those the user wishes to highlight
|
||||
for domain_id in self.col_spec:
|
||||
if domain_id not in domains:
|
||||
r, g, b = self.col_spec[domain_id]
|
||||
for domain, color in self.colors.items():
|
||||
if domain not in domains:
|
||||
if isinstance(color, string_types):
|
||||
color = _SVG_COLORS[color.lower()]
|
||||
r, g, b = color
|
||||
r = int(((1-alpha) * background[0]) + (alpha * r))
|
||||
g = int(((1-alpha) * background[1]) + (alpha * g))
|
||||
b = int(((1-alpha) * background[2]) + (alpha * b))
|
||||
self._col_spec[domain_id] = (r, g, b)
|
||||
self._colors[domain] = (r, g, b)
|
||||
|
||||
def get_plot_xml(self):
|
||||
def to_xml_element(self):
|
||||
"""Return XML representation of the plot
|
||||
|
||||
Returns
|
||||
|
|
@ -424,8 +611,9 @@ class Plot(object):
|
|||
|
||||
element = ET.Element("plot")
|
||||
element.set("id", str(self._id))
|
||||
element.set("filename", self._filename)
|
||||
element.set("color", self._color)
|
||||
if self._filename is not None:
|
||||
element.set("filename", self._filename)
|
||||
element.set("color_by", self._color_by)
|
||||
element.set("type", self._type)
|
||||
|
||||
if self._type is 'slice':
|
||||
|
|
@ -442,21 +630,29 @@ class Plot(object):
|
|||
|
||||
if self._background is not None:
|
||||
subelement = ET.SubElement(element, "background")
|
||||
subelement.text = ' '.join(map(str, self._background))
|
||||
color = self._background
|
||||
if isinstance(color, string_types):
|
||||
color = _SVG_COLORS[color.lower()]
|
||||
subelement.text = ' '.join(str(x) for x in color)
|
||||
|
||||
if self._col_spec is not None:
|
||||
for key in self._col_spec:
|
||||
subelement = ET.SubElement(element, "col_spec")
|
||||
subelement.set("id", str(key))
|
||||
subelement.set("rgb", ' '.join(map(
|
||||
str, self._col_spec[key])))
|
||||
if self._colors:
|
||||
for domain, color in self._colors.items():
|
||||
subelement = ET.SubElement(element, "color")
|
||||
subelement.set("id", str(domain.id))
|
||||
if isinstance(color, string_types):
|
||||
color = _SVG_COLORS[color.lower()]
|
||||
subelement.set("rgb", ' '.join(str(x) for x in color))
|
||||
|
||||
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 = _SVG_COLORS[color.lower()]
|
||||
subelement.set("background", ' '.join(
|
||||
str(x) for x in color))
|
||||
|
||||
if self._level is not None:
|
||||
subelement = ET.SubElement(element, "level")
|
||||
|
|
@ -585,20 +781,21 @@ class Plots(cv.CheckedList):
|
|||
alpha=0.5, background='gray'):
|
||||
"""Use alpha compositing to highlight one or more domains in the plot.
|
||||
|
||||
This routine generates a color scheme and applies alpha compositing
|
||||
to make all domains except the highlighted ones partially transparent.
|
||||
This routine generates a color scheme and applies alpha compositing to
|
||||
make all domains except the highlighted ones appear partially
|
||||
transparent.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
geometry : openmc.Geometry
|
||||
The geometry for which the plot is defined
|
||||
domains : Iterable of Integral
|
||||
domains : Iterable of openmc.Cell or openmc.Material
|
||||
A collection of the domain IDs to highlight in the plot
|
||||
seed : Integral
|
||||
seed : int
|
||||
The random number seed used to generate the color scheme
|
||||
alpha : Real in [0,1]
|
||||
The value to apply in alpha compisiting
|
||||
background : 3-tuple of Integral or 'white' or 'black' or 'gray'
|
||||
alpha : float
|
||||
The value between 0 and 1 to apply in alpha compisiting
|
||||
background : 3-tuple of int or str
|
||||
The background color to apply in alpha compisiting
|
||||
|
||||
"""
|
||||
|
|
@ -608,7 +805,7 @@ class Plots(cv.CheckedList):
|
|||
|
||||
def _create_plot_subelements(self):
|
||||
for plot in self:
|
||||
xml_element = plot.get_plot_xml()
|
||||
xml_element = plot.to_xml_element()
|
||||
|
||||
if len(plot.name) > 0:
|
||||
self._plots_file.append(ET.Comment(plot.name))
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ class Summary(object):
|
|||
|
||||
@property
|
||||
def date_and_time(self):
|
||||
return self._f.attrs['date_and_time']
|
||||
return self._f.attrs['date_and_time'].decode()
|
||||
|
||||
@property
|
||||
def geometry(self):
|
||||
|
|
@ -185,6 +185,8 @@ class Summary(object):
|
|||
for idx in fill._natural_indices:
|
||||
univ = fill.get_universe(idx)
|
||||
fill_univ_ids.add(univ.id)
|
||||
if fill.outer is not None:
|
||||
fill_univ_ids.add(fill.outer.id)
|
||||
|
||||
# Set the fill for the Cell
|
||||
cells[cell_id].fill = fill
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
from __future__ import division
|
||||
from copy import copy
|
||||
from collections import OrderedDict, Iterable
|
||||
from numbers import Integral, Real
|
||||
import random
|
||||
|
|
@ -8,6 +10,7 @@ import numpy as np
|
|||
|
||||
import openmc
|
||||
import openmc.checkvalue as cv
|
||||
from openmc.plots import _SVG_COLORS
|
||||
|
||||
|
||||
# A static variable for auto-generated Lattice (Universe) IDs
|
||||
|
|
@ -46,6 +49,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 +111,16 @@ class Universe(object):
|
|||
def volume(self):
|
||||
return self._volume
|
||||
|
||||
@property
|
||||
def bounding_box(self):
|
||||
regions = [c.region for c in self.cells.values()
|
||||
if c.region is not None]
|
||||
if regions:
|
||||
return openmc.Union(*regions).bounding_box
|
||||
else:
|
||||
# Infinite bounding box
|
||||
return openmc.Intersection().bounding_box
|
||||
|
||||
@id.setter
|
||||
def id(self, universe_id):
|
||||
if universe_id is None:
|
||||
|
|
@ -207,15 +223,15 @@ class Universe(object):
|
|||
return [self, cell] + cell.fill.find(p)
|
||||
return []
|
||||
|
||||
def plot(self, center=(0., 0., 0.), width=(1., 1.), pixels=(200, 200),
|
||||
def plot(self, origin=(0., 0., 0.), width=(1., 1.), pixels=(200, 200),
|
||||
basis='xy', color_by='cell', colors=None, filename=None, seed=None,
|
||||
**kwargs):
|
||||
"""Display a slice plot of the universe.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
center : Iterable of float
|
||||
Coordinates at the center of the plot
|
||||
origin : Iterable of float
|
||||
Coordinates at the origin of the plot
|
||||
width : Iterable of float
|
||||
Width of the plot in each basis direction
|
||||
pixels : Iterable of int
|
||||
|
|
@ -225,11 +241,10 @@ class Universe(object):
|
|||
color_by : {'cell', 'material'}
|
||||
Indicate whether the plot should be colored by cell or by material
|
||||
colors : dict
|
||||
|
||||
Assigns colors to specific materials or cells. Keys are instances of
|
||||
:class:`Cell` or :class:`Material` and values are RGB 3-tuples or
|
||||
RGBA 4-tuples. Red, green, blue, and alpha should all be floats in
|
||||
the range [0.0, 1.0], for example:
|
||||
:class:`Cell` or :class:`Material` and values are RGB 3-tuples, RGBA
|
||||
4-tuples, or strings indicating SVG color names. Red, green, blue,
|
||||
and alpha should all be floats in the range [0.0, 1.0], for example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
|
|
@ -260,28 +275,35 @@ class Universe(object):
|
|||
colors = {}
|
||||
else:
|
||||
# Convert to RGBA if necessary
|
||||
for obj, rgb in colors.items():
|
||||
if len(rgb) == 3:
|
||||
colors[obj] = rgb + (1.0,)
|
||||
colors = copy(colors)
|
||||
for obj, color in colors.items():
|
||||
if isinstance(color, string_types):
|
||||
if color.lower() not in _SVG_COLORS:
|
||||
raise ValueError("'{}' is not a valid color."
|
||||
.format(color))
|
||||
colors[obj] = [x/255 for x in
|
||||
_SVG_COLORS[color.lower()]] + [1.0]
|
||||
elif len(color) == 3:
|
||||
colors[obj] = list(color) + [1.0]
|
||||
|
||||
if basis == 'xy':
|
||||
x_min = center[0] - 0.5*width[0]
|
||||
x_max = center[0] + 0.5*width[0]
|
||||
y_min = center[1] - 0.5*width[1]
|
||||
y_max = center[1] + 0.5*width[1]
|
||||
x_min = origin[0] - 0.5*width[0]
|
||||
x_max = origin[0] + 0.5*width[0]
|
||||
y_min = origin[1] - 0.5*width[1]
|
||||
y_max = origin[1] + 0.5*width[1]
|
||||
elif basis == 'yz':
|
||||
# The x-axis will correspond to physical y and the y-axis will
|
||||
# correspond to physical z
|
||||
x_min = center[1] - 0.5*width[0]
|
||||
x_max = center[1] + 0.5*width[0]
|
||||
y_min = center[2] - 0.5*width[1]
|
||||
y_max = center[2] + 0.5*width[1]
|
||||
x_min = origin[1] - 0.5*width[0]
|
||||
x_max = origin[1] + 0.5*width[0]
|
||||
y_min = origin[2] - 0.5*width[1]
|
||||
y_max = origin[2] + 0.5*width[1]
|
||||
elif basis == 'xz':
|
||||
# The y-axis will correspond to physical z
|
||||
x_min = center[0] - 0.5*width[0]
|
||||
x_max = center[0] + 0.5*width[0]
|
||||
y_min = center[2] - 0.5*width[1]
|
||||
y_max = center[2] + 0.5*width[1]
|
||||
x_min = origin[0] - 0.5*width[0]
|
||||
x_max = origin[0] + 0.5*width[0]
|
||||
y_min = origin[2] - 0.5*width[1]
|
||||
y_max = origin[2] + 0.5*width[1]
|
||||
|
||||
# Determine locations to determine cells at
|
||||
x_coords = np.linspace(x_min, x_max, pixels[0], endpoint=False) + \
|
||||
|
|
@ -295,11 +317,11 @@ class Universe(object):
|
|||
for i, x in enumerate(x_coords):
|
||||
for j, y in enumerate(y_coords):
|
||||
if basis == 'xy':
|
||||
path = self.find((x, y, center[2]))
|
||||
path = self.find((x, y, origin[2]))
|
||||
elif basis == 'yz':
|
||||
path = self.find((center[0], x, y))
|
||||
path = self.find((origin[0], x, y))
|
||||
elif basis == 'xz':
|
||||
path = self.find((x, center[1], y))
|
||||
path = self.find((x, origin[1], y))
|
||||
|
||||
if len(path) > 0:
|
||||
try:
|
||||
|
|
@ -318,7 +340,8 @@ class Universe(object):
|
|||
img[j, i, :] = colors[obj]
|
||||
|
||||
# Display image
|
||||
plt.imshow(img, extent=(x_min, x_max, y_min, y_max), **kwargs)
|
||||
plt.imshow(img, extent=(x_min, x_max, y_min, y_max),
|
||||
interpolation='nearest', **kwargs)
|
||||
|
||||
# Show or save the plot
|
||||
if filename is None:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -4364,8 +4364,8 @@ contains
|
|||
|
||||
! Copy plot color type and initialize all colors randomly
|
||||
temp_str = "cell"
|
||||
if (check_for_node(node_plot, "color")) &
|
||||
call get_node_value(node_plot, "color", temp_str)
|
||||
if (check_for_node(node_plot, "color_by")) &
|
||||
call get_node_value(node_plot, "color_by", temp_str)
|
||||
temp_str = to_lower(temp_str)
|
||||
select case (trim(temp_str))
|
||||
case ("cell")
|
||||
|
|
@ -4378,7 +4378,7 @@ contains
|
|||
pl % colors(j) % rgb(3) = int(prn()*255)
|
||||
end do
|
||||
|
||||
case ("mat", "material")
|
||||
case ("material")
|
||||
|
||||
pl % color_by = PLOT_COLOR_MATS
|
||||
allocate(pl % colors(n_materials))
|
||||
|
|
@ -4393,8 +4393,8 @@ contains
|
|||
// "' in plot " // trim(to_str(pl % id)))
|
||||
end select
|
||||
|
||||
! Get the number of <col_spec> nodes and get a list of them
|
||||
call get_node_list(node_plot, "col_spec", node_col_list)
|
||||
! Get the number of <color> nodes and get a list of them
|
||||
call get_node_list(node_plot, "color", node_col_list)
|
||||
n_cols = size(node_col_list)
|
||||
|
||||
! Copy user specified colors
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@ element plots {
|
|||
attribute filename { xsd:string { maxLength = "50" } })? &
|
||||
(element type { "slice" | "voxel" } |
|
||||
attribute type { "slice" | "voxel" })? &
|
||||
(element color { ( "cell" | "mat" | "material" ) } |
|
||||
attribute color { ( "cell" | "mat" | "material" ) })? &
|
||||
(element color_by { ( "cell" | "material" ) } |
|
||||
attribute color_by { ( "cell" | "material" ) })? &
|
||||
(element level { xsd:int } | attribute level { xsd:int })? &
|
||||
(element origin { list { xsd:double+ } } |
|
||||
attribute origin { list { xsd:double+ } })? &
|
||||
|
|
@ -18,7 +18,7 @@ element plots {
|
|||
attribute pixels { list { xsd:int+ } })? &
|
||||
(element background { list { xsd:int+ } } |
|
||||
attribute background { list { xsd:int+ } })? &
|
||||
element col_spec {
|
||||
element color {
|
||||
(element id { xsd:int } | attribute id { xsd:int }) &
|
||||
(element rgb { list { xsd:int+ } } |
|
||||
attribute rgb { list { xsd:int+ } })
|
||||
|
|
|
|||
|
|
@ -45,17 +45,15 @@
|
|||
</optional>
|
||||
<optional>
|
||||
<choice>
|
||||
<element name="color">
|
||||
<element name="color_by">
|
||||
<choice>
|
||||
<value>cell</value>
|
||||
<value>mat</value>
|
||||
<value>material</value>
|
||||
</choice>
|
||||
</element>
|
||||
<attribute name="color">
|
||||
<attribute name="color_by">
|
||||
<choice>
|
||||
<value>cell</value>
|
||||
<value>mat</value>
|
||||
<value>material</value>
|
||||
</choice>
|
||||
</attribute>
|
||||
|
|
@ -162,7 +160,7 @@
|
|||
</choice>
|
||||
</optional>
|
||||
<zeroOrMore>
|
||||
<element name="col_spec">
|
||||
<element name="color">
|
||||
<interleave>
|
||||
<choice>
|
||||
<element name="id">
|
||||
|
|
|
|||
|
|
@ -471,7 +471,7 @@ class InputSet(object):
|
|||
plot.origin = (125, 125, 0)
|
||||
plot.width = (250, 250)
|
||||
plot.pixels = (3000, 3000)
|
||||
plot.color = 'mat'
|
||||
plot.color_by = 'material'
|
||||
|
||||
self.plots.add_plot(plot)
|
||||
|
||||
|
|
@ -563,7 +563,7 @@ class PinCellInputSet(object):
|
|||
plot.origin = (0.0, 0.0, 0)
|
||||
plot.width = (1.26, 1.26)
|
||||
plot.pixels = (300, 300)
|
||||
plot.color = 'mat'
|
||||
plot.color_by = 'material'
|
||||
|
||||
self.plots.add_plot(plot)
|
||||
|
||||
|
|
@ -714,7 +714,7 @@ class AssemblyInputSet(object):
|
|||
plot.origin = (0.0, 0.0, 0)
|
||||
plot.width = (21.42, 21.42)
|
||||
plot.pixels = (300, 300)
|
||||
plot.color = 'mat'
|
||||
plot.color_by = 'material'
|
||||
|
||||
self.plots.add_plot(plot)
|
||||
|
||||
|
|
@ -793,6 +793,6 @@ class MGInputSet(InputSet):
|
|||
plot.width = (2.5, 2.5)
|
||||
plot.basis = 'xz'
|
||||
plot.pixels = (3000, 3000)
|
||||
plot.color = 'mat'
|
||||
plot.color_by = 'material'
|
||||
|
||||
self.plots.add_plot(plot)
|
||||
|
|
|
|||
|
|
@ -52,12 +52,12 @@
|
|||
</settings>
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<plots>
|
||||
<plot basis="xy" color="cell" filename="cellplot" id="1" type="slice">
|
||||
<plot basis="xy" color_by="cell" filename="cellplot" id="1" type="slice">
|
||||
<origin>0 0 0</origin>
|
||||
<width>7 7</width>
|
||||
<pixels>400 400</pixels>
|
||||
</plot>
|
||||
<plot basis="xy" color="mat" filename="matplot" id="2" type="slice">
|
||||
<plot basis="xy" color_by="material" filename="matplot" id="2" type="slice">
|
||||
<origin>0 0 0</origin>
|
||||
<width>7 7</width>
|
||||
<pixels>400 400</pixels>
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ class DistribmatTestHarness(PyAPITestHarness):
|
|||
|
||||
plot = openmc.Plot(plot_id=1)
|
||||
plot.basis = 'xy'
|
||||
plot.color = 'cell'
|
||||
plot.color_by = 'cell'
|
||||
plot.filename = 'cellplot'
|
||||
plot.origin = (0, 0, 0)
|
||||
plot.width = (7, 7)
|
||||
|
|
@ -104,7 +104,7 @@ class DistribmatTestHarness(PyAPITestHarness):
|
|||
|
||||
plot = openmc.Plot(plot_id=2)
|
||||
plot.basis = 'xy'
|
||||
plot.color = 'mat'
|
||||
plot.color_by = 'material'
|
||||
plot.filename = 'matplot'
|
||||
plot.origin = (0, 0, 0)
|
||||
plot.width = (7, 7)
|
||||
|
|
|
|||
|
|
@ -1,28 +1,28 @@
|
|||
<?xml version="1.0"?>
|
||||
<plots>
|
||||
|
||||
<plot id="1" type="slice" basis="xy" color="cell">
|
||||
<plot id="1" type="slice" basis="xy" color_by="cell">
|
||||
<filename>xy_cell</filename>
|
||||
<origin>0 0 0</origin>
|
||||
<width>30 30</width>
|
||||
<pixels>500 500</pixels>
|
||||
</plot>
|
||||
|
||||
<plot id="2" type="slice" basis="xy" color="material">
|
||||
<plot id="2" type="slice" basis="xy" color_by="material">
|
||||
<filename>xy_material</filename>
|
||||
<origin>0 0 0</origin>
|
||||
<width>30 30</width>
|
||||
<pixels>500 500</pixels>
|
||||
</plot>
|
||||
|
||||
<plot id="3" type="slice" basis="yz" color="cell">
|
||||
<plot id="3" type="slice" basis="yz" color_by="cell">
|
||||
<filename>yz_cell</filename>
|
||||
<origin>0 0 0</origin>
|
||||
<width>50 400</width>
|
||||
<pixels>500 4000</pixels>
|
||||
</plot>
|
||||
|
||||
<plot id="4" type="slice" basis="yz" color="material">
|
||||
<plot id="4" type="slice" basis="yz" color_by="material">
|
||||
<filename>yz_material</filename>
|
||||
<origin>0 0 0</origin>
|
||||
<width>5 5</width>
|
||||
|
|
|
|||
|
|
@ -1,28 +1,28 @@
|
|||
<?xml version="1.0"?>
|
||||
<plots>
|
||||
|
||||
<plot id="1" type="slice" basis="xy" color="cell">
|
||||
<plot id="1" type="slice" basis="xy" color_by="cell">
|
||||
<filename>xy_cell</filename>
|
||||
<origin>0 0 0</origin>
|
||||
<width>30 30</width>
|
||||
<pixels>500 500</pixels>
|
||||
</plot>
|
||||
|
||||
<plot id="2" type="slice" basis="xy" color="material">
|
||||
<plot id="2" type="slice" basis="xy" color_by="material">
|
||||
<filename>xy_material</filename>
|
||||
<origin>0 0 0</origin>
|
||||
<width>30 30</width>
|
||||
<pixels>500 500</pixels>
|
||||
</plot>
|
||||
|
||||
<plot id="3" type="slice" basis="yz" color="cell">
|
||||
<plot id="3" type="slice" basis="yz" color_by="cell">
|
||||
<filename>yz_cell</filename>
|
||||
<origin>0 0 0</origin>
|
||||
<width>50 400</width>
|
||||
<pixels>500 4000</pixels>
|
||||
</plot>
|
||||
|
||||
<plot id="4" type="slice" basis="yz" color="material">
|
||||
<plot id="4" type="slice" basis="yz" color_by="material">
|
||||
<filename>yz_material</filename>
|
||||
<origin>0 0 0</origin>
|
||||
<width>5 5</width>
|
||||
|
|
|
|||
|
|
@ -51,12 +51,12 @@
|
|||
</settings>
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<plots>
|
||||
<plot basis="xy" color="cell" filename="cellplot" id="1" type="slice">
|
||||
<plot basis="xy" color_by="cell" filename="cellplot" id="1" type="slice">
|
||||
<origin>0 0 0</origin>
|
||||
<width>7 7</width>
|
||||
<pixels>400 400</pixels>
|
||||
</plot>
|
||||
<plot basis="xy" color="mat" filename="matplot" id="2" type="slice">
|
||||
<plot basis="xy" color_by="material" filename="matplot" id="2" type="slice">
|
||||
<origin>0 0 0</origin>
|
||||
<width>7 7</width>
|
||||
<pixels>400 400</pixels>
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ class MultipoleTestHarness(PyAPITestHarness):
|
|||
|
||||
plot = openmc.Plot(plot_id=1)
|
||||
plot.basis = 'xy'
|
||||
plot.color = 'cell'
|
||||
plot.color_by = 'cell'
|
||||
plot.filename = 'cellplot'
|
||||
plot.origin = (0, 0, 0)
|
||||
plot.width = (7, 7)
|
||||
|
|
@ -88,7 +88,7 @@ class MultipoleTestHarness(PyAPITestHarness):
|
|||
|
||||
plot = openmc.Plot(plot_id=2)
|
||||
plot.basis = 'xy'
|
||||
plot.color = 'mat'
|
||||
plot.color_by = 'material'
|
||||
plot.filename = 'matplot'
|
||||
plot.origin = (0, 0, 0)
|
||||
plot.width = (7, 7)
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
<origin>0. 0. 0.</origin>
|
||||
<width>25 25</width>
|
||||
<pixels>200 200</pixels>
|
||||
<col_spec id="1" rgb="255 0 0" /> <!-- Red -->
|
||||
<color id="1" rgb="255 0 0" /> <!-- Red -->
|
||||
<meshlines meshtype="entropy" linewidth="0" />
|
||||
</plot>
|
||||
|
||||
|
|
@ -16,7 +16,7 @@
|
|||
<mask components="1 3" background="255 255 255" />
|
||||
</plot>
|
||||
|
||||
<plot id="3" basis="yz" color="mat">
|
||||
<plot id="3" basis="yz" color_by="material">
|
||||
<origin>0. 0. 0.</origin>
|
||||
<width>25 25</width>
|
||||
<pixels>200 200</pixels>
|
||||
|
|
|
|||
|
|
@ -442,7 +442,7 @@
|
|||
</settings>
|
||||
<?xml version="1.0"?>
|
||||
<plots>
|
||||
<plot id="1" type="slice" basis="xy" color="material"
|
||||
<plot id="1" type="slice" basis="xy" color_by="material"
|
||||
origin="0.0 0.0 0.0" width="1.0 1.0" pixels="400 400">
|
||||
</plot>
|
||||
</plots>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0"?>
|
||||
<plots>
|
||||
<plot id="1" type="slice" basis="xy" color="material"
|
||||
<plot id="1" type="slice" basis="xy" color_by="material"
|
||||
origin="0.0 0.0 0.0" width="1.0 1.0" pixels="400 400">
|
||||
</plot>
|
||||
</plots>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue