add unit test, select wireframing by id

This commit is contained in:
Gavin Ridley 2022-01-09 01:54:38 -05:00
parent 31174736e9
commit 6726cc378f
4 changed files with 530 additions and 132 deletions

View file

@ -282,6 +282,8 @@ private:
void set_opacities(pugi::xml_node node);
void set_orthographic_width(pugi::xml_node node);
void set_wireframe_thickness(pugi::xml_node node);
void set_wireframe_ids(pugi::xml_node node);
void set_wireframe_color(pugi::xml_node node);
/* Used for drawing wireframe and colors. We record the list of
* surface/cell/material intersections and the corresponding lengths as a ray
@ -306,6 +308,8 @@ private:
Position camera_position_; // where camera is
Position look_at_; // point camera is centered looking at
Direction up_ {0.0, 0.0, 1.0}; // which way is up
std::vector<int>
wireframe_ids_; // which color IDs should be wireframed. If empty, all
/* The horizontal thickness, if using an orthographic projection.
* If set to zero, we assume using a perspective projection.
@ -329,8 +333,8 @@ private:
* to mean not having matching intersection lengths, but rather having
* a matching sequence of surface/cell/material intersections.
*/
static bool trackstack_equivalent(const std::vector<TrackSegment>& track1,
const std::vector<TrackSegment>& track2);
bool trackstack_equivalent(const std::vector<TrackSegment>& track1,
const std::vector<TrackSegment>& track2) const;
// Closed form 3x3 matrix inversion
static std::vector<double> invert_matrix(const std::vector<double>& input);

View file

@ -178,14 +178,8 @@ def _get_plot_image(plot, cwd):
return Image(str(png_file))
class Plot(IDManagerMixin):
"""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/SVG11/types.html#ColorKeywords>`_.
class PlotBase(IDManagerMixin):
"""
Parameters
----------
plot_id : int
@ -199,20 +193,12 @@ class Plot(IDManagerMixin):
Unique identifier
name : str
Name of the plot
width : Iterable of float
Width of the plot in each basis direction
pixels : Iterable of int
Number of pixels to use in each basis direction
origin : tuple or list of ndarray
Origin (center) of the plot
filename :
Path to write the plot to
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 : Iterable of int or str
Color of the background
mask_components : Iterable of openmc.Cell or openmc.Material or int
@ -230,10 +216,6 @@ class Plot(IDManagerMixin):
cell/material).
level : int
Universe depth to plot at
meshlines : dict
Dictionary defining type, id, linewidth and color of a mesh to be
plotted on top of a plot
"""
next_id = 1
@ -243,13 +225,9 @@ class Plot(IDManagerMixin):
# Initialize Plot class attributes
self.id = plot_id
self.name = name
self._width = [4.0, 4.0]
self._pixels = [400, 400]
self._origin = [0., 0., 0.]
self._filename = None
self._color_by = 'cell'
self._type = 'slice'
self._basis = 'xy'
self._background = None
self._mask_components = None
self._mask_background = None
@ -257,24 +235,15 @@ class Plot(IDManagerMixin):
self._overlap_color = None
self._colors = {}
self._level = None
self._meshlines = None
@property
def name(self):
return self._name
@property
def width(self):
return self._width
@property
def pixels(self):
return self._pixels
@property
def origin(self):
return self._origin
@property
def filename(self):
return self._filename
@ -283,14 +252,6 @@ class Plot(IDManagerMixin):
def color_by(self):
return self._color_by
@property
def type(self):
return self._type
@property
def basis(self):
return self._basis
@property
def background(self):
return self._background
@ -319,27 +280,11 @@ class Plot(IDManagerMixin):
def level(self):
return self._level
@property
def meshlines(self):
return self._meshlines
@name.setter
def name(self, name):
cv.check_type('plot name', name, str)
self._name = name
@width.setter
def width(self, width):
cv.check_type('plot width', width, Iterable, Real)
cv.check_length('plot width', width, 2, 3)
self._width = width
@origin.setter
def origin(self, origin):
cv.check_type('plot origin', origin, Iterable, Real)
cv.check_length('plot origin', origin, 3)
self._origin = origin
@pixels.setter
def pixels(self, pixels):
cv.check_type('plot pixels', pixels, Iterable, Integral)
@ -358,16 +303,6 @@ class Plot(IDManagerMixin):
cv.check_value('plot color_by', color_by, ['cell', 'material'])
self._color_by = color_by
@type.setter
def type(self, plottype):
cv.check_value('plot type', plottype, ['slice', 'voxel'])
self._type = plottype
@basis.setter
def basis(self, basis):
cv.check_value('plot basis', basis, _BASES)
self._basis = basis
@background.setter
def background(self, background):
self._check_color('plot background', background)
@ -410,6 +345,132 @@ class Plot(IDManagerMixin):
cv.check_greater_than('plot level', plot_level, 0, equality=True)
self._level = plot_level
@staticmethod
def _check_color(err_string, color):
cv.check_type(err_string, color, Iterable)
if isinstance(color, str):
if color.lower() not in _SVG_COLORS:
raise ValueError(f"'{color}' is not a valid color.")
else:
cv.check_length(err_string, color, 3)
for rgb in color:
cv.check_type(err_string, rgb, Real)
cv.check_greater_than('RGB component', rgb, 0, True)
cv.check_less_than('RGB component', rgb, 256)
def colorize(self, geometry, seed=1):
"""Generate a color scheme for each domain in the plot.
This routine may be used to generate random, reproducible color schemes.
The colors generated are based upon cell/material IDs in the geometry.
Parameters
----------
geometry : openmc.Geometry
The geometry for which the plot is defined
seed : Integral
The random number seed used to generate the color scheme
"""
cv.check_type('geometry', geometry, openmc.Geometry)
cv.check_type('seed', seed, Integral)
cv.check_greater_than('seed', seed, 1, equality=True)
# Get collections of the domains which will be plotted
if self.color_by == 'material':
domains = geometry.get_all_materials().values()
else:
domains = geometry.get_all_cells().values()
# Set the seed for the random number generator
np.random.seed(seed)
# Generate random colors for each feature
for domain in domains:
self.colors[domain] = np.random.randint(0, 256, (3,))
class Plot(PlotBase):
'''Definition of a finite region of space to be plotted.
OpenMC is capable of generating two-dimensional slice plots, or
three-dimensional voxel or projection 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/SVG11/types.html#ColorKeywords>`_.
Parameters
----------
plot_id : int
Unique identifier for the plot
name : str
Name of the plot
Attributes
----------
width : Iterable of float
Width of the plot in each basis direction
origin : tuple or list of ndarray
Origin (center) of the plot
type : {'slice', 'voxel'}
The type of the plot
basis : {'xy', 'xz', 'yz'}
The basis directions for the plot
meshlines : dict
Dictionary defining type, id, linewidth and color of a mesh to be
plotted on top of a plot
'''
def __init__(self, plot_id=None, name=''):
super().__init__(plot_id, name)
self._width = [4.0, 4.0]
self._origin = [0., 0., 0.]
self._type = 'slice'
self._basis = 'xy'
self._meshlines = None
@property
def width(self):
return self._width
@property
def origin(self):
return self._origin
@property
def type(self):
return self._type
@property
def basis(self):
return self._basis
@property
def meshlines(self):
return self._meshlines
@width.setter
def width(self, width):
cv.check_type('plot width', width, Iterable, Real)
cv.check_length('plot width', width, 2, 3)
self._width = width
@origin.setter
def origin(self, origin):
cv.check_type('plot origin', origin, Iterable, Real)
cv.check_length('plot origin', origin, 3)
self._origin = origin
@type.setter
def type(self, plottype):
cv.check_value('plot type', plottype, ['slice', 'voxel'])
self._type = plottype
@basis.setter
def basis(self, basis):
cv.check_value('plot basis', basis, _BASES)
self._basis = basis
@meshlines.setter
def meshlines(self, meshlines):
cv.check_type('plot meshlines', meshlines, dict)
@ -438,19 +499,6 @@ class Plot(IDManagerMixin):
self._meshlines = meshlines
@staticmethod
def _check_color(err_string, color):
cv.check_type(err_string, color, Iterable)
if isinstance(color, str):
if color.lower() not in _SVG_COLORS:
raise ValueError(f"'{color}' is not a valid color.")
else:
cv.check_length(err_string, color, 3)
for rgb in color:
cv.check_type(err_string, rgb, Real)
cv.check_greater_than('RGB component', rgb, 0, True)
cv.check_less_than('RGB component', rgb, 256)
def __repr__(self):
string = 'Plot\n'
string += '{: <16}=\t{}\n'.format('\tID', self._id)
@ -474,6 +522,7 @@ class Plot(IDManagerMixin):
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.
@ -520,38 +569,6 @@ class Plot(IDManagerMixin):
plot.basis = basis
return plot
def colorize(self, geometry, seed=1):
"""Generate a color scheme for each domain in the plot.
This routine may be used to generate random, reproducible color schemes.
The colors generated are based upon cell/material IDs in the geometry.
Parameters
----------
geometry : openmc.Geometry
The geometry for which the plot is defined
seed : Integral
The random number seed used to generate the color scheme
"""
cv.check_type('geometry', geometry, openmc.Geometry)
cv.check_type('seed', seed, Integral)
cv.check_greater_than('seed', seed, 1, equality=True)
# Get collections of the domains which will be plotted
if self.color_by == 'material':
domains = geometry.get_all_materials().values()
else:
domains = geometry.get_all_cells().values()
# Set the seed for the random number generator
np.random.seed(seed)
# Generate random colors for each feature
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.
@ -604,7 +621,7 @@ class Plot(IDManagerMixin):
self._colors[domain] = (r, g, b)
def to_xml_element(self):
"""Return XML representation of the plot
"""Return XML representation of the slice/voxel plot
Returns
-------
@ -802,13 +819,271 @@ class Plot(IDManagerMixin):
# Return produced image
return _get_plot_image(self, cwd)
class ProjectionPlot(PlotBase):
"""Definition of a camera's view of OpenMC geometry
Colors are defined in the same manner as the Plot class, but with the addition
of a coloring parameter resembling a macroscopic cross section in units of inverse
centimeters. The volume rendering technique is used to color regions of the model.
An infinite cross section denotes a fully opaque region, and zero represents a
transparent region which will expose the color of the regions behind it.
The camera projection may either by orthographic or perspective. Perspective
projections are more similar to a pinhole camera, and orthographic projections
preserve parallel lines and distances.
Parameters
----------
plot_id : int
Unique identifier for the plot
name : str
Name of the plot
Attributes
----------
horizontal_field_of_view : float
Field of view horizontally, in units of degrees.
camera_position : tuple or list of ndarray
Position of the camera in 3D space
look_at : tuple or list of ndarray
The center of the camera's image points to this place in 3D space
up : tuple or list of ndarray
Which way is up for the camera. Must not be parallel to the
line between look_at and camera_position
orthographic_width : float
If set to a nonzero value, an orthographic projection is used.
All rays traced from the orthographic pixel array travel in the
same direction. The width of the starting array must be specified,
unlike with the default perspective projection. The height of the
array is deduced from the ratio of pixel dimensions for the image.
wireframe_thickness : int
Line thickness employed for drawing wireframes around cells or
material regions. Can be set to zero for no wireframes
wireframe_color : tuple of ints
RGB color of the wireframe lines
wireframe_regions : iterable of either Material or Cells
If provided, the wireframe is only drawn around these.
If color_by is by material, it must be a list of materials, else cells.
xs : dict
A mapping from cell/material IDs to floats. The floating point values
are macroscopic cross sections influencing the volume rendering opacity
of each geometric region. Zero corresponds to perfect transparency, and
infinity equivalent to opaque.
"""
def __init__(self, plot_id=None, name=''):
# Initialize Plot class attributes
super().__init__(plot_id, name)
self._horizontal_field_of_view = 70.0
self._camera_position = (1.0, 0.0, 0.0)
self._look_at = (0.0, 0.0, 0.0)
self._up = (0.0, 0.0, 1.0)
self._orthographic_width = 0.0
self._wireframe_thickness = 1
self._wireframe_color = _SVG_COLORS['black']
self._wireframe_regions = []
self._xs = {}
@property
def horizontal_field_of_view(self):
return self._horizontal_field_of_view
@property
def camera_position(self):
return self._camera_position
@property
def look_at(self):
return self._look_at
@property
def up(self):
return self._up
@property
def orthographic_width(self):
return self._orthographic_width
@property
def wireframe_thickness(self):
return self._wireframe_thickness
@property
def wireframe_color(self):
return self._wireframe_color
@property
def wireframe_regions(self):
return self._wireframe_regions
@property
def xs(self):
return self._xs
@horizontal_field_of_view.setter
def horizontal_field_of_view(self, horizontal_field_of_view):
cv.check_type('plot horizontal field of view', horizontal_field_of_view,
Real)
assert horizontal_field_of_view > 0.0
assert horizontal_field_of_view < 180.0
self._horizontal_field_of_view = horizontal_field_of_view
@camera_position.setter
def camera_position(self, camera_position):
cv.check_type('plot camera position', camera_position, Iterable, Real)
cv.check_length('plot camera position', camera_position, 3)
self._camera_position = camera_position
@look_at.setter
def look_at(self, look_at):
cv.check_type('plot look at', look_at, Iterable, Real)
cv.check_length('plot look at', look_at, 3)
self._look_at = look_at
@up.setter
def up(self, up):
cv.check_type('plot up', up, Iterable, Real)
cv.check_length('plot up', up, 3)
self._up = up
@orthographic_width.setter
def orthographic_width(self, orthographic_width):
cv.check_type('plot orthographic width', orthographic_width, Real)
self._orthographic_width = orthographic_width
@wireframe_thickness.setter
def wireframe_thickness(self, wireframe_thickness):
cv.check_type('plot orthographic width', wireframe_thickness, Integral)
assert wireframe_thickness >= 0
self._wireframe_thickness = wireframe_thickness
@wireframe_color.setter
def wireframe_color(self, wireframe_color):
self._check_color('plot wireframe color', wireframe_color)
self._wireframe_color = wireframe_color
@wireframe_regions.setter
def wireframe_regions(self, wireframe_regions):
for region in wireframe_regions:
if self._color_by == 'material':
if not isinstance(region, openmc.Material):
raise Exception('Must provide a list of materials for \
wireframe_region if color_by=Material')
else:
if not isinstance(region, openmc.Cell):
raise Exception('Must provide a list of cells for \
wireframe_region if color_by=cell')
self._wireframe_regions = wireframe_regions
@xs.setter
def xs(self, xs):
cv.check_type('plot xs', xs, Mapping)
for key, value in xs.items():
cv.check_type('plot xs key', key, (openmc.Cell, openmc.Material))
cv.check_type('plot xs value', value, Real)
assert value >= 0.0
self._xs = xs
def set_transparent(self, geometry):
"""Sets all volume rendering XS to zero for the model
Parameters
----------
geometry : openmc.Geometry
The geometry for which the plot is defined
"""
cv.check_type('geometry', geometry, openmc.Geometry)
# Get collections of the domains which will be plotted
if self.color_by == 'material':
domains = geometry.get_all_materials().values()
else:
domains = geometry.get_all_cells().values()
# Generate random colors for each feature
for domain in domains:
self.xs[domain] = 0.0
def to_xml_element(self):
"""Return XML representation of the projection plot
Returns
-------
element : xml.etree.ElementTree.Element
XML element containing plot data
"""
element = ET.Element("plot")
element.set("id", str(self._id))
if self._filename is not None:
element.set("filename", self._filename)
element.set("color_by", self._color_by)
element.set("type", "projection")
subelement = ET.SubElement(element, "pixels")
subelement.text = ' '.join(map(str, self._pixels))
subelement = ET.SubElement(element, "camera_position")
subelement.text = ' '.join(map(str, self._camera_position))
subelement = ET.SubElement(element, "look_at")
subelement.text = ' '.join(map(str, self._look_at))
subelement = ET.SubElement(element, "wireframe_thickness")
subelement.text = str(self._wireframe_thickness)
subelement = ET.SubElement(element, "wireframe_color")
color = self._wireframe_color
if isinstance(color, str):
color = _SVG_COLORS[color.lower()]
subelement.text = ' '.join(str(x) for x in color)
if self._wireframe_regions:
id_list = [x.id for x in self._wireframe_regions]
subelement = ET.SubElement(element, "wireframe_ids")
subelement.text = ' '.join([str(x) for x in id_list])
if self._background is not None:
subelement = ET.SubElement(element, "background")
color = self._background
if isinstance(color, str):
color = _SVG_COLORS[color.lower()]
subelement.text = ' '.join(str(x) for x in color)
if self._mask_components is not None:
subelement = ET.SubElement(element, "mask")
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, str):
color = _SVG_COLORS[color.lower()]
subelement.set("background", ' '.join(
str(x) for x in color))
if self._colors:
for domain, color in sorted(self._colors.items(),
key=lambda x: x[0].id):
subelement = ET.SubElement(element, "color")
subelement.set("id", str(domain.id))
if isinstance(color, str):
color = _SVG_COLORS[color.lower()]
subelement.set("rgb", ' '.join(str(x) for x in color))
subelement.set("xs", str(self._xs[domain]))
return element
class Plots(cv.CheckedList):
"""Collection of Plots used for an OpenMC simulation.
This class corresponds directly to the plots.xml input file. It can be
thought of as a normal Python list where each member is a :class:`Plot`. It
behaves like a list as the following example demonstrates:
thought of as a normal Python list where each member is inherits from
:class:`PlotBase`. It behaves like a list as the following example
demonstrates:
>>> xz_plot = openmc.Plot()
>>> big_plot = openmc.Plot()
@ -819,13 +1094,13 @@ class Plots(cv.CheckedList):
Parameters
----------
plots : Iterable of openmc.Plot
Plots to add to the collection
plots : Iterable of openmc.Plot or openmc.ProjectionPlot
plots to add to the collection
"""
def __init__(self, plots=None):
super().__init__(Plot, 'plots collection')
super().__init__((Plot, ProjectionPlot), 'plots collection')
self._plots_file = ET.Element("plots")
if plots is not None:
self += plots
@ -835,7 +1110,7 @@ class Plots(cv.CheckedList):
Parameters
----------
plot : openmc.Plot
plot : openmc.Plot or openmc.ProjectionPlot
Plot to append
"""

View file

@ -1035,6 +1035,8 @@ ProjectionPlot::ProjectionPlot(pugi::xml_node node) : PlottableInterface(node)
set_opacities(node);
set_orthographic_width(node);
set_wireframe_thickness(node);
set_wireframe_ids(node);
set_wireframe_color(node);
if (check_for_node(node, "orthographic_width") &&
check_for_node(node, "field_of_view"))
@ -1042,6 +1044,19 @@ ProjectionPlot::ProjectionPlot(pugi::xml_node node) : PlottableInterface(node)
"parameters.");
}
void ProjectionPlot::set_wireframe_color(pugi::xml_node plot_node)
{
// Copy plot background color
if (check_for_node(plot_node, "wireframe_color")) {
vector<int> w_rgb = get_node_array<int>(plot_node, "wireframe_color");
if (w_rgb.size() == 3) {
wireframe_color_ = w_rgb;
} else {
fatal_error(fmt::format("Bad wireframe RGB in plot {}", id()));
}
}
}
void ProjectionPlot::set_output_path(pugi::xml_node node)
{
// Set output file path
@ -1091,17 +1106,55 @@ int ProjectionPlot::advance_to_boundary_from_void(Particle& p)
bool ProjectionPlot::trackstack_equivalent(
const std::vector<TrackSegment>& track1,
const std::vector<TrackSegment>& track2)
const std::vector<TrackSegment>& track2) const
{
if (track1.size() != track2.size())
return false;
for (int i = 0; i < track1.size(); ++i) {
if (track1[i].id != track2[i].id ||
track1[i].surface != track2[i].surface) {
return false;
if (wireframe_ids_.empty()) {
// TODO old version
return true;
} else {
// This runs in O(nm) where n is the intersection stack size
// and m is the number of IDs we are wireframing. A simpler
// algorithm can likely be found.
for (const int id : wireframe_ids_) {
int t1_i = 0;
int t2_i = 0;
// Advance to first instance of the ID
while (t1_i < track1.size() && t2_i < track2.size()) {
while (t1_i < track1.size() && track1[t1_i].id != id)
t1_i++;
while (t2_i < track2.size() && track2[t2_i].id != id)
t2_i++;
// This one is really important!
if ((t1_i == track1.size() && t2_i != track2.size()) ||
(t1_i != track1.size() && t2_i == track2.size()))
return false;
if (t1_i == track1.size() && t2_i == track2.size())
break;
// Check if surface different
if (track1[t1_i].surface != track2[t2_i].surface)
return false;
// Pretty sure this should not be used:
// if (t2_i != track2.size() - 1 &&
// t1_i != track1.size() - 1 &&
// track1[t1_i+1].id != track2[t2_i+1].id) return false;
if (t2_i != 0 && t1_i != 0 &&
track1[t1_i - 1].surface != track2[t2_i - 1].surface)
return false;
// Check if neighboring cells are different
// if (track1[t1_i ? t1_i - 1 : 0].id != track2[t2_i ? t2_i - 1 : 0].id)
// return false; if (track1[t1_i < track1.size() - 1 ? t1_i + 1 : t1_i
// ].id !=
// track2[t2_i < track2.size() - 1 ? t2_i + 1 : t2_i].id) return
// false;
t1_i++, t2_i++;
}
}
return true;
}
return true;
}
void ProjectionPlot::create_output() const
@ -1247,7 +1300,10 @@ void ProjectionPlot::create_output() const
// edges on the model boundary for the same cell.
if (first_inside_model) {
this_line_segments[tid][horiz].emplace_back(
0, 0.0, first_surface);
color_by_ == PlotColorBy::mats
? p.material()
: p.coord(p.n_coord() - 1).cell,
0.0, first_surface);
first_inside_model = false;
}
@ -1435,6 +1491,21 @@ void ProjectionPlot::set_wireframe_thickness(pugi::xml_node node)
}
}
void ProjectionPlot::set_wireframe_ids(pugi::xml_node node)
{
if (check_for_node(node, "wireframe_ids")) {
wireframe_ids_ = get_node_array<int>(node, "wireframe_ids");
// It is read in as actual ID values, but we have to convert to indices in
// mat/cell array
for (auto& x : wireframe_ids_)
x = color_by_ == PlotColorBy::mats ? model::material_map[x]
: model::cell_map[x];
}
// We make sure the list is sorted in order to later use
// std::binary_search.
std::sort(wireframe_ids_.begin(), wireframe_ids_.end());
}
void ProjectionPlot::set_pixels(pugi::xml_node node)
{
vector<int> pxls = get_node_array<int>(node, "pixels");

View file

@ -37,15 +37,47 @@ def myplot():
}
return plot
@pytest.fixture(scope='module')
def myprojectionplot():
plot = openmc.ProjectionPlot(name='myprojectionplot')
plot.look_at = (0.0, 0.0, 0.0)
plot.camera_position = (4.0, 3.0, 0.0)
plot.pixels = (500, 500)
plot.filename = 'myprojectionplot'
plot.background = (0, 0, 0)
plot.background = 'black'
plot.color_by = 'material'
m1, m2 = openmc.Material(), openmc.Material()
plot.colors = {m1: (0, 255, 0), m2: (0, 0, 255)}
plot.colors = {m1: 'green', m2: 'blue'}
plot.xs = {m1: 1.0, m2: 0.01}
plot.mask_components = [openmc.Material()]
plot.mask_background = (255, 255, 255)
plot.mask_background = 'white'
plot.overlap_color = (255, 211, 0)
plot.overlap_color = 'yellow'
plot.wireframe_thickness = 2
plot.level = 1
return plot
def test_attributes(myplot):
assert myplot.name == 'myplot'
def test_attributes_proj(myprojectionplot):
assert myprojectionplot.name == 'myprojectionplot'
def test_repr(myplot):
r = repr(myplot)
assert isinstance(r, str)
def test_repr_proj(myprojectionplot):
r = repr(myprojectionplot)
assert isinstance(r, str)
def test_from_geometry():
width = 25.
@ -89,6 +121,18 @@ def test_xml_element(myplot):
assert getattr(newplot, attr) == getattr(myplot, attr), attr
def test_to_xml_element_proj(myprojectionplot):
elem = myprojectionplot.to_xml_element()
assert 'id' in elem.attrib
assert 'color_by' in elem.attrib
assert 'type' in elem.attrib
assert elem.find('camera_position') is not None
assert elem.find('wireframe_thickness') is not None
assert elem.find('look_at') is not None
assert elem.find('pixels') is not None
assert elem.find('background').text == '0 0 0'
def test_plots(run_in_tmpdir):
p1 = openmc.Plot(name='plot1')
p1.origin = (5., 5., 5.)
@ -99,10 +143,14 @@ def test_plots(run_in_tmpdir):
plots = openmc.Plots([p1, p2])
assert len(plots) == 2
p3 = openmc.Plot(name='plot3')
plots.append(p3)
p3 = openmc.ProjectionPlot(name='plot3')
plots = openmc.Plots([p1, p2, p3])
assert len(plots) == 3
p4 = openmc.Plot(name='plot4')
plots.append(p4)
assert len(plots) == 4
plots.export_to_xml()
# from_xml