OpenMC/openmc/lib/plot.py
2021-07-12 07:28:21 -05:00

265 lines
7.2 KiB
Python

from ctypes import (c_bool, c_int, c_size_t, c_int32,
c_double, Structure, POINTER)
from . import _dll
from .error import _error_handler
import numpy as np
class _Position(Structure):
"""Definition of an xyz location in space with underlying c-types
C-type Attributes
-----------------
x : c_double
Position's x value (default: 0.0)
y : c_double
Position's y value (default: 0.0)
z : c_double
Position's z value (default: 0.0)
"""
_fields_ = [('x', c_double),
('y', c_double),
('z', c_double)]
def __getitem__(self, idx):
if idx == 0:
return self.x
elif idx == 1:
return self.y
elif idx == 2:
return self.z
else:
raise IndexError("{} index is invalid for _Position".format(idx))
def __setitem__(self, idx, val):
if idx == 0:
self.x = val
elif idx == 1:
self.y = val
elif idx == 2:
self.z = val
else:
raise IndexError("{} index is invalid for _Position".format(idx))
def __repr__(self):
return "({}, {}, {})".format(self.x, self.y, self.z)
class _PlotBase(Structure):
"""A structure defining a 2-D geometry slice with underlying c-types
C-Type Attributes
-----------------
origin : openmc.lib.plot._Position
A position defining the origin of the plot.
width_ : openmc.lib.plot._Position
The width of the plot along the x, y, and z axes, respectively
basis_ : c_int
The axes basis of the plot view.
pixels_ : c_size_t[3]
The resolution of the plot in the horizontal and vertical dimensions
level_ : c_int
The universe level for the plot view
Attributes
----------
origin : tuple or list of ndarray
Origin (center) of the plot
width : float
The horizontal dimension of the plot in geometry units (cm)
height : float
The vertical dimension of the plot in geometry units (cm)
basis : string
One of {'xy', 'xz', 'yz'} indicating the horizontal and vertical
axes of the plot.
h_res : int
The horizontal resolution of the plot in pixels
v_res : int
The vertical resolution of the plot in pixels
level : int
The universe level for the plot (default: -1 -> all universes shown)
"""
_fields_ = [('origin_', _Position),
('width_', _Position),
('basis_', c_int),
('pixels_', 3*c_size_t),
('color_overlaps_', c_bool),
('level_', c_int)]
def __init__(self):
self.level_ = -1
self.color_overlaps_ = False
@property
def origin(self):
return self.origin_
@property
def width(self):
return self.width_.x
@property
def height(self):
return self.width_.y
@property
def basis(self):
if self.basis_ == 1:
return 'xy'
elif self.basis_ == 2:
return 'xz'
elif self.basis_ == 3:
return 'yz'
raise ValueError("Plot basis {} is invalid".format(self.basis_))
@basis.setter
def basis(self, basis):
if isinstance(basis, str):
valid_bases = ('xy', 'xz', 'yz')
basis = basis.lower()
if basis not in valid_bases:
raise ValueError("{} is not a valid plot basis.".format(basis))
if basis == 'xy':
self.basis_ = 1
elif basis == 'xz':
self.basis_ = 2
elif basis == 'yz':
self.basis_ = 3
return
if isinstance(basis, int):
valid_bases = (1, 2, 3)
if basis not in valid_bases:
raise ValueError("{} is not a valid plot basis.".format(basis))
self.basis_ = basis
return
raise ValueError("{} of type {} is an"
" invalid plot basis".format(basis, type(basis)))
@property
def h_res(self):
return self.pixels_[0]
@property
def v_res(self):
return self.pixels_[1]
@property
def level(self):
return int(self.level_)
@property
def color_overlaps(self):
return self.color_overlaps_
@color_overlaps.setter
def color_overlaps(self, color_overlaps):
self.color_overlaps_ = color_overlaps
@origin.setter
def origin(self, origin):
self.origin_.x = origin[0]
self.origin_.y = origin[1]
self.origin_.z = origin[2]
@width.setter
def width(self, width):
self.width_.x = width
@height.setter
def height(self, height):
self.width_.y = height
@h_res.setter
def h_res(self, h_res):
self.pixels_[0] = h_res
@v_res.setter
def v_res(self, v_res):
self.pixels_[1] = v_res
@level.setter
def level(self, level):
self.level_ = level
@property
def color_overlaps(self):
return self.color_overlaps_
@color_overlaps.setter
def color_overlaps(self, val):
self.color_overlaps_ = val
def __repr__(self):
out_str = ["-----",
"Plot:",
"-----",
"Origin: {}".format(self.origin),
"Width: {}".format(self.width),
"Height: {}".format(self.height),
"Basis: {}".format(self.basis),
"HRes: {}".format(self.h_res),
"VRes: {}".format(self.v_res),
"Color Overlaps: {}".format(self.color_overlaps),
"Level: {}".format(self.level)]
return '\n'.join(out_str)
_dll.openmc_id_map.argtypes = [POINTER(_PlotBase), POINTER(c_int32)]
_dll.openmc_id_map.restype = c_int
_dll.openmc_id_map.errcheck = _error_handler
def id_map(plot):
"""
Generate a 2-D map of cell and material IDs. Used for in-memory image
generation.
Parameters
----------
plot : openmc.lib.plot._PlotBase
Object describing the slice of the model to be generated
Returns
-------
id_map : numpy.ndarray
A NumPy array with shape (vertical pixels, horizontal pixels, 3) of
OpenMC property ids with dtype int32
"""
img_data = np.zeros((plot.v_res, plot.h_res, 3),
dtype=np.dtype('int32'))
_dll.openmc_id_map(plot, img_data.ctypes.data_as(POINTER(c_int32)))
return img_data
_dll.openmc_property_map.argtypes = [POINTER(_PlotBase), POINTER(c_double)]
_dll.openmc_property_map.restype = c_int
_dll.openmc_property_map.errcheck = _error_handler
def property_map(plot):
"""
Generate a 2-D map of cell temperatures and material densities. Used for
in-memory image generation.
Parameters
----------
plot : openmc.lib.plot._PlotBase
Object describing the slice of the model to be generated
Returns
-------
property_map : numpy.ndarray
A NumPy array with shape (vertical pixels, horizontal pixels, 2) of
OpenMC property ids with dtype float
"""
prop_data = np.zeros((plot.v_res, plot.h_res, 2))
_dll.openmc_property_map(plot, prop_data.ctypes.data_as(POINTER(c_double)))
return prop_data