Merge pull request #993 from paulromano/capi-more

Add C API bindings for mesh creation
This commit is contained in:
shikhar413 2018-04-18 10:14:07 -04:00 committed by GitHub
commit 06161d1693
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 755 additions and 234 deletions

View file

@ -93,29 +93,13 @@ or ``multi-group``.
*Default*: continuous-energy
---------------------
``<entropy>`` Element
---------------------
--------------------------
``<entropy_mesh>`` Element
--------------------------
The ``<entropy>`` element describes a mesh that is used for calculating Shannon
entropy. This mesh should cover all possible fissionable materials in the
problem. It has the following attributes/sub-elements:
:dimension:
The number of mesh cells in the x, y, and z directions, respectively.
*Default*: If this tag is not present, the number of mesh cells is
automatically determined by the code.
:lower_left:
The Cartesian coordinates of the lower-left corner of the mesh.
*Default*: None
:upper_right:
The Cartesian coordinates of the upper-right corner of the mesh.
*Default*: None
The ``<entropy_mesh>`` element indicates the ID of a mesh that is to be used for
calculating Shannon entropy. The mesh should cover all possible fissionable
materials in the problem and is specified using a :ref:`mesh_element`.
-----------------------------------
``<generations_per_batch>`` Element
@ -199,6 +183,36 @@ then, OpenMC will only use up to the :math:`P_1` data.
.. note:: This element is not used in the continuous-energy
:ref:`energy_mode`.
.. _mesh_element:
------------------
``<mesh>`` Element
------------------
The ``<mesh>`` element describes a mesh that is used either for calculating
Shannon entropy, applying the uniform fission site method, or in tallies. For
Shannon entropy meshes, the mesh should cover all possible fissionable materials
in the problem. It has the following attributes/sub-elements:
:id:
A unique integer that is used to identify the mesh.
:dimension:
The number of mesh cells in the x, y, and z directions, respectively.
*Default*: If this tag is not present, the number of mesh cells is
automatically determined by the code.
:lower_left:
The Cartesian coordinates of the lower-left corner of the mesh.
*Default*: None
:upper_right:
The Cartesian coordinates of the upper-right corner of the mesh.
*Default*: None
-----------------------
``<no_reduce>`` Element
-----------------------
@ -765,30 +779,15 @@ has the following attributes/sub-elements:
------------------------
``<uniform_fs>`` Element
``<ufs_mesh>`` Element
------------------------
The ``<uniform_fs>`` element describes a mesh that is used for re-weighting
source sites at every generation based on the uniform fission site methodology
described in Kelly et al., "MC21 Analysis of the Nuclear Energy Agency Monte
Carlo Performance Benchmark Problem," Proceedings of *Physor 2012*, Knoxville,
TN (2012). This mesh should cover all possible fissionable materials in the
problem. It has the following attributes/sub-elements:
:dimension:
The number of mesh cells in the x, y, and z directions, respectively.
*Default*: None
:lower_left:
The Cartesian coordinates of the lower-left corner of the mesh.
*Default*: None
:upper_right:
The Cartesian coordinates of the upper-right corner of the mesh.
*Default*: None
The ``<ufs_mesh>`` element indicates the ID of a mesh that is used for
re-weighting source sites at every generation based on the uniform fission site
methodology described in Kelly et al., "MC21 Analysis of the Nuclear Energy
Agency Monte Carlo Performance Benchmark Problem," Proceedings of *Physor 2012*,
Knoxville, TN (2012). The mesh should cover all possible fissionable materials
in the problem and is specified using a :ref:`mesh_element`.
.. _verbosity:

View file

@ -44,5 +44,8 @@ Classes
EnergyFilter
MaterialFilter
Material
Mesh
MeshFilter
MeshSurfaceFilter
Nuclide
Tally

View file

@ -16,7 +16,7 @@ extern "C" {
int delayed_group;
};
void openmc_calculate_voumes();
void openmc_calculate_volumes();
int openmc_cell_get_fill(int32_t index, int* type, int32_t** indices, int32_t* n);
int openmc_cell_get_id(int32_t index, int32_t* id);
int openmc_cell_set_fill(int32_t index, int type, int32_t n, const int32_t* indices);
@ -27,10 +27,13 @@ extern "C" {
int openmc_extend_cells(int32_t n, int32_t* index_start, int32_t* index_end);
int openmc_extend_filters(int32_t n, int32_t* index_start, int32_t* index_end);
int openmc_extend_materials(int32_t n, int32_t* index_start, int32_t* index_end);
int openmc_extend_meshes(int32_t n, int32_t* index_start, int32_t* index_end);
int openmc_extend_sources(int32_t n, int32_t* index_start, int32_t* index_end);
int openmc_extend_tallies(int32_t n, int32_t* index_start, int32_t* index_end);
int openmc_filter_get_id(int32_t index, int32_t* id);
int openmc_filter_get_type(int32_t index, const char** type);
int openmc_filter_set_id(int32_t index, int32_t id);
int openmc_filter_set_type(int32_t index, const char* type);
void openmc_finalize();
int openmc_find(double* xyz, int rtype, int32_t* id, int32_t* instance);
int openmc_get_cell_index(int32_t id, int32_t* index);
@ -38,7 +41,9 @@ extern "C" {
void openmc_get_filter_next_id(int32_t* id);
int openmc_get_keff(double k_combined[]);
int openmc_get_material_index(int32_t id, int32_t* index);
int openmc_get_mesh_index(int32_t id, int32_t* index);
int openmc_get_nuclide_index(const char name[], int* index);
int64_t openmc_get_seed();
int openmc_get_tally_index(int32_t id, int32_t* index);
void openmc_hard_reset();
void openmc_init(const int* intracomm);
@ -53,13 +58,22 @@ extern "C" {
int openmc_material_set_id(int32_t index, int32_t id);
int openmc_material_filter_get_bins(int32_t index, int32_t** bins, int32_t* n);
int openmc_material_filter_set_bins(int32_t index, int32_t n, const int32_t* bins);
int openmc_mesh_filter_get_mesh(int32_t index, int32_t* index_mesh);
int openmc_mesh_filter_set_mesh(int32_t index, int32_t index_mesh);
int openmc_mesh_get_id(int32_t index, int32_t* id);
int openmc_mesh_get_dimension(int32_t index, int** id, int* n);
int openmc_mesh_get_params(int32_t index, double** ll, double** ur, double** width, int* n);
int openmc_mesh_set_id(int32_t index, int32_t id);
int openmc_mesh_set_dimension(int32_t index, int n, const int* dims);
int openmc_mesh_set_params(int32_t index, const double* ll, const double* ur, const double* width, int n);
int openmc_meshsurface_filter_get_mesh(int32_t index, int32_t* index_mesh);
int openmc_meshsurface_filter_set_mesh(int32_t index, int32_t index_mesh);
int openmc_next_batch();
int openmc_next_batch(int* status);
int openmc_nuclide_name(int index, char** name);
void openmc_plot_geometry();
void openmc_reset();
void openmc_run();
int openmc_run();
void openmc_set_seed(int64_t new_seed);
void openmc_simulation_finalize();
void openmc_simulation_init();
int openmc_source_bank(struct Bank** ptr, int64_t* n);
@ -83,7 +97,8 @@ extern "C" {
int openmc_tally_set_filters(int32_t index, int n, const int32_t* indices);
int openmc_tally_set_id(int32_t index, int32_t id);
int openmc_tally_set_nuclides(int32_t index, int n, const char** nuclides);
int openmc_tally_set_scores(int32_t index, int n, const int* scores);
int openmc_tally_set_scores(int32_t index, int n, const char** scores);
int openmc_tally_set_type(int32_t index, const char* type);
int openmc_zernike_filter_get_order(int32_t index, int* order);
int openmc_zernike_filter_get_params(int32_t index, double* x, double* y, double* r);
int openmc_zernike_filter_set_order(int32_t index, int order);
@ -91,17 +106,17 @@ extern "C" {
const double* y, const double* r);
// Error codes
extern int E_UNASSIGNED;
extern int E_ALLOCATE;
extern int E_OUT_OF_BOUNDS;
extern int E_INVALID_SIZE;
extern int E_INVALID_ARGUMENT;
extern int E_INVALID_TYPE;
extern int E_INVALID_ID;
extern int E_GEOMETRY;
extern int E_DATA;
extern int E_PHYSICS;
extern int E_WARNING;
extern int OPENMC_E_UNASSIGNED;
extern int OPENMC_E_ALLOCATE;
extern int OPENMC_E_OUT_OF_BOUNDS;
extern int OPENMC_E_INVALID_SIZE;
extern int OPENMC_E_INVALID_ARGUMENT;
extern int OPENMC_E_INVALID_TYPE;
extern int OPENMC_E_INVALID_ID;
extern int OPENMC_E_GEOMETRY;
extern int OPENMC_E_DATA;
extern int OPENMC_E_PHYSICS;
extern int OPENMC_E_WARNING;
// Global variables
extern char openmc_err_msg[256];

View file

@ -43,6 +43,7 @@ from .core import *
from .nuclide import *
from .material import *
from .cell import *
from .mesh import *
from .filter import *
from .tally import *
from .settings import settings

View file

@ -5,9 +5,10 @@ from weakref import WeakValueDictionary
import numpy as np
from numpy.ctypeslib import as_array
from openmc.exceptions import AllocationError, InvalidIDError
from . import _dll
from .core import _FortranObjectWithID
from .error import _error_handler, AllocationError, InvalidIDError
from .error import _error_handler
from .material import Material
__all__ = ['Cell', 'cells']
@ -44,7 +45,7 @@ class Cell(_FortranObjectWithID):
This class exposes a cell that is stored internally in the OpenMC
library. To obtain a view of a cell with a given ID, use the
:data:`openmc.capi.nuclides` mapping.
:data:`openmc.capi.cells` mapping.
Parameters
----------
@ -115,14 +116,15 @@ class Cell(_FortranObjectWithID):
def fill(self, fill):
if isinstance(fill, Iterable):
n = len(fill)
indices = (c_int*n)(*(m._index for m in fill))
_dll.openmc_cell_set_fill(self._index, 1, 1, indices)
indices = (c_int32*n)(*(m._index if m is not None else -1
for m in fill))
_dll.openmc_cell_set_fill(self._index, 1, n, indices)
elif isinstance(fill, Material):
materials = [fill]
indices = (c_int*1)(fill._index)
indices = (c_int32*1)(fill._index)
_dll.openmc_cell_set_fill(self._index, 1, 1, indices)
elif fill is None:
indices = (c_int32*1)(-1)
_dll.openmc_cell_set_fill(self._index, 1, 1, indices)
else:
raise NotImplementedError
def set_temperature(self, T, instance=None):
"""Set the temperature of a cell

View file

@ -6,8 +6,9 @@ from warnings import warn
import numpy as np
from numpy.ctypeslib import as_array
from openmc.exceptions import AllocationError
from . import _dll
from .error import _error_handler, AllocationError
from .error import _error_handler
import openmc.capi
@ -31,9 +32,12 @@ _dll.openmc_init.restype = None
_dll.openmc_get_keff.argtypes = [POINTER(c_double*2)]
_dll.openmc_get_keff.restype = c_int
_dll.openmc_get_keff.errcheck = _error_handler
_dll.openmc_next_batch.argtypes = [POINTER(c_int)]
_dll.openmc_next_batch.restype = c_int
_dll.openmc_next_batch.errcheck = _error_handler
_dll.openmc_plot_geometry.restype = None
_dll.openmc_run.restype = None
_dll.openmc_run.restype = c_int
_dll.openmc_run.errcheck = _error_handler
_dll.openmc_reset.restype = None
_dll.openmc_source_bank.argtypes = [POINTER(POINTER(_Bank)), POINTER(c_int64)]
_dll.openmc_source_bank.restype = c_int
@ -147,13 +151,13 @@ def iter_batches():
"""
while True:
# Run next batch
retval = next_batch()
status = next_batch()
# Provide opportunity for user to perform action between batches
yield
# End the iteration
if retval < 0:
if status != 0:
break
@ -180,12 +184,18 @@ def keff():
def next_batch():
"""Run next batch."""
retval = _dll.openmc_next_batch()
if retval == -3:
raise AllocationError('Simulation has not been initialized. You must call '
'openmc.capi.simulation_init() first.')
return retval
"""Run next batch.
Returns
-------
int
Status after running a batch (0=normal, 1=reached maximum number of
batches, 2=tally triggers reached)
"""
status = c_int()
_dll.openmc_next_batch(status)
return status.value
def plot_geometry():

View file

@ -1,45 +1,10 @@
from ctypes import c_int, c_char
from warnings import warn
import openmc.exceptions as exc
from . import _dll
class OpenMCError(Exception):
"""Root exception class for OpenMC."""
class GeometryError(OpenMCError):
"""Geometry-related error"""
class InvalidIDError(OpenMCError):
"""Use of an ID that is invalid."""
class AllocationError(OpenMCError):
"""Error related to memory allocation."""
class OutOfBoundsError(OpenMCError):
"""Index in array out of bounds."""
class DataError(OpenMCError):
"""Error relating to nuclear data."""
class PhysicsError(OpenMCError):
"""Error relating to performing physics."""
class InvalidArgumentError(OpenMCError):
"""Argument passed was invalid."""
class InvalidTypeError(OpenMCError):
"""Tried to perform an operation on the wrong type."""
def _error_handler(err, func, args):
"""Raise exception according to error code."""
@ -52,23 +17,23 @@ def _error_handler(err, func, args):
msg = errmsg.value.decode()
# Raise exception type corresponding to error code
if err == errcode('e_allocate'):
raise AllocationError(msg)
elif err == errcode('e_out_of_bounds'):
raise OutOfBoundsError(msg)
elif err == errcode('e_invalid_argument'):
raise InvalidArgumentError(msg)
elif err == errcode('e_invalid_type'):
raise InvalidTypeError(msg)
if err == errcode('e_invalid_id'):
raise InvalidIDError(msg)
elif err == errcode('e_geometry'):
raise GeometryError(msg)
elif err == errcode('e_data'):
raise DataError(msg)
elif err == errcode('e_physics'):
raise PhysicsError(msg)
elif err == errcode('e_warning'):
if err == errcode('OPENMC_E_ALLOCATE'):
raise exc.AllocationError(msg)
elif err == errcode('OPENMC_E_OUT_OF_BOUNDS'):
raise exc.OutOfBoundsError(msg)
elif err == errcode('OPENMC_E_INVALID_ARGUMENT'):
raise exc.InvalidArgumentError(msg)
elif err == errcode('OPENMC_E_INVALID_TYPE'):
raise exc.InvalidTypeError(msg)
if err == errcode('OPENMC_E_INVALID_ID'):
raise exc.InvalidIDError(msg)
elif err == errcode('OPENMC_E_GEOMETRY'):
raise exc.GeometryError(msg)
elif err == errcode('OPENMC_E_DATA'):
raise exc.DataError(msg)
elif err == errcode('OPENMC_E_PHYSICS'):
raise exc.PhysicsError(msg)
elif err == errcode('OPENMC_E_WARNING'):
warn(msg)
elif err < 0:
raise OpenMCError("Unknown error encountered (code {}).".format(err))
raise exc.OpenMCError("Unknown error encountered (code {}).".format(err))

View file

@ -6,17 +6,19 @@ from weakref import WeakValueDictionary
import numpy as np
from numpy.ctypeslib import as_array
from openmc.exceptions import AllocationError, InvalidIDError
from . import _dll
from .core import _FortranObjectWithID
from .error import _error_handler, AllocationError, InvalidIDError
from .error import _error_handler
from .material import Material
from .mesh import Mesh
__all__ = ['Filter', 'AzimuthalFilter', 'CellFilter',
'CellbornFilter', 'CellfromFilter', 'DistribcellFilter',
'DelayedGroupFilter', 'EnergyFilter', 'EnergyoutFilter',
'EnergyFunctionFilter', 'MaterialFilter', 'MeshFilter',
'MuFilter', 'PolarFilter', 'SurfaceFilter',
'MeshSurfaceFilter', 'MuFilter', 'PolarFilter', 'SurfaceFilter',
'UniverseFilter', 'filters']
# Tally functions
@ -52,9 +54,15 @@ _dll.openmc_material_filter_get_bins.errcheck = _error_handler
_dll.openmc_material_filter_set_bins.argtypes = [c_int32, c_int32, POINTER(c_int32)]
_dll.openmc_material_filter_set_bins.restype = c_int
_dll.openmc_material_filter_set_bins.errcheck = _error_handler
_dll.openmc_mesh_filter_get_mesh.argtypes = [c_int32, POINTER(c_int32)]
_dll.openmc_mesh_filter_get_mesh.restype = c_int
_dll.openmc_mesh_filter_get_mesh.errcheck = _error_handler
_dll.openmc_mesh_filter_set_mesh.argtypes = [c_int32, c_int32]
_dll.openmc_mesh_filter_set_mesh.restype = c_int
_dll.openmc_mesh_filter_set_mesh.errcheck = _error_handler
_dll.openmc_meshsurface_filter_get_mesh.argtypes = [c_int32, POINTER(c_int32)]
_dll.openmc_meshsurface_filter_get_mesh.restype = c_int
_dll.openmc_meshsurface_filter_get_mesh.errcheck = _error_handler
_dll.openmc_meshsurface_filter_set_mesh.argtypes = [c_int32, c_int32]
_dll.openmc_meshsurface_filter_set_mesh.restype = c_int
_dll.openmc_meshsurface_filter_set_mesh.errcheck = _error_handler
@ -190,10 +198,40 @@ class MaterialFilter(Filter):
class MeshFilter(Filter):
filter_type = 'mesh'
def __init__(self, mesh=None, uid=None, new=True, index=None):
super().__init__(uid, new, index)
if mesh is not None:
self.mesh = mesh
@property
def mesh(self):
index_mesh = c_int32()
_dll.openmc_mesh_filter_get_mesh(self._index, index_mesh)
return Mesh(index=index_mesh.value)
@mesh.setter
def mesh(self, mesh):
_dll.openmc_mesh_filter_set_mesh(self._index, mesh._index)
class MeshSurfaceFilter(Filter):
filter_type = 'meshsurface'
def __init__(self, mesh=None, uid=None, new=True, index=None):
super().__init__(uid, new, index)
if mesh is not None:
self.mesh = mesh
@property
def mesh(self):
index_mesh = c_int32()
_dll.openmc_meshsurface_filter_get_mesh(self._index, index_mesh)
return Mesh(index=index_mesh.value)
@mesh.setter
def mesh(self, mesh):
_dll.openmc_meshsurface_filter_set_mesh(self._index, mesh._index)
class MuFilter(Filter):
filter_type = 'mu'

View file

@ -5,9 +5,10 @@ from weakref import WeakValueDictionary
import numpy as np
from numpy.ctypeslib import as_array
from openmc.exceptions import AllocationError, InvalidIDError
from . import _dll, Nuclide
from .core import _FortranObjectWithID
from .error import _error_handler, AllocationError, InvalidIDError
from .error import _error_handler
__all__ = ['Material', 'materials']
@ -89,6 +90,9 @@ class Material(_FortranObjectWithID):
index = index.value
else:
index = mapping[uid]._index
elif index == -1:
# Special value indicates void material
return None
if index not in cls.__instances:
instance = super(Material, cls).__new__(cls)

183
openmc/capi/mesh.py Normal file
View file

@ -0,0 +1,183 @@
from collections.abc import Mapping, Iterable
from ctypes import c_int, c_int32, c_double, POINTER
from weakref import WeakValueDictionary
import numpy as np
from numpy.ctypeslib import as_array
from openmc.exceptions import AllocationError, InvalidIDError
from . import _dll
from .core import _FortranObjectWithID
from .error import _error_handler
from .material import Material
__all__ = ['Mesh', 'meshes']
# Mesh functions
_dll.openmc_extend_meshes.argtypes = [c_int32, POINTER(c_int32), POINTER(c_int32)]
_dll.openmc_extend_meshes.restype = c_int
_dll.openmc_extend_meshes.errcheck = _error_handler
_dll.openmc_mesh_get_id.argtypes = [c_int32, POINTER(c_int32)]
_dll.openmc_mesh_get_id.restype = c_int
_dll.openmc_mesh_get_id.errcheck = _error_handler
_dll.openmc_mesh_get_dimension.argtypes = [c_int32, POINTER(POINTER(c_int)), POINTER(c_int)]
_dll.openmc_mesh_get_dimension.restype = c_int
_dll.openmc_mesh_get_dimension.errcheck = _error_handler
_dll.openmc_mesh_get_params.argtypes = [
c_int32, POINTER(POINTER(c_double)), POINTER(POINTER(c_double)),
POINTER(POINTER(c_double)), POINTER(c_int)]
_dll.openmc_mesh_get_params.restype = c_int
_dll.openmc_mesh_get_params.errcheck = _error_handler
_dll.openmc_mesh_set_id.argtypes = [c_int32, c_int32]
_dll.openmc_mesh_set_id.restype = c_int
_dll.openmc_mesh_set_id.errcheck = _error_handler
_dll.openmc_mesh_set_dimension.argtypes = [c_int32, c_int, POINTER(c_int)]
_dll.openmc_mesh_set_dimension.restype = c_int
_dll.openmc_mesh_set_dimension.errcheck = _error_handler
_dll.openmc_mesh_set_params.argtypes = [
c_int32, c_int, POINTER(c_double), POINTER(c_double), POINTER(c_double)]
_dll.openmc_mesh_set_params.restype = c_int
_dll.openmc_mesh_set_params.errcheck = _error_handler
_dll.openmc_get_mesh_index.argtypes = [c_int32, POINTER(c_int32)]
_dll.openmc_get_mesh_index.restype = c_int
_dll.openmc_get_mesh_index.errcheck = _error_handler
class Mesh(_FortranObjectWithID):
"""Mesh stored internally.
This class exposes a mesh that is stored internally in the OpenMC
library. To obtain a view of a mesh with a given ID, use the
:data:`openmc.capi.meshes` mapping.
Parameters
----------
index : int
Index in the `meshes` array.
Attributes
----------
id : int
ID of the mesh
dimension : iterable of int
The number of mesh cells in each direction.
lower_left : numpy.ndarray
The lower-left corner of the structured mesh. If only two coordinate are
given, it is assumed that the mesh is an x-y mesh.
upper_right : numpy.ndarray
The upper-right corner of the structrued mesh. If only two coordinate
are given, it is assumed that the mesh is an x-y mesh.
width : numpy.ndarray
The width of mesh cells in each direction.
"""
__instances = WeakValueDictionary()
def __new__(cls, uid=None, new=True, index=None):
mapping = meshes
if index is None:
if new:
# Determine ID to assign
if uid is None:
uid = max(mapping, default=0) + 1
else:
if uid in mapping:
raise AllocationError('A mesh with ID={} has already '
'been allocated.'.format(uid))
index = c_int32()
_dll.openmc_extend_meshes(1, index, None)
index = index.value
else:
index = mapping[uid]._index
if index not in cls.__instances:
instance = super().__new__(cls)
instance._index = index
if uid is not None:
instance.id = uid
cls.__instances[index] = instance
return cls.__instances[index]
@property
def id(self):
mesh_id = c_int32()
_dll.openmc_mesh_get_id(self._index, mesh_id)
return mesh_id.value
@id.setter
def id(self, mesh_id):
_dll.openmc_mesh_set_id(self._index, mesh_id)
@property
def dimension(self):
dims = POINTER(c_int)()
n = c_int()
_dll.openmc_mesh_get_dimension(self._index, dims, n)
return tuple(as_array(dims, (n.value,)))
@dimension.setter
def dimension(self, dimension):
n = len(dimension)
dimension = (c_int*n)(*dimension)
_dll.openmc_mesh_set_dimension(self._index, n, dimension)
@property
def lower_left(self):
return self._get_parameters()[0]
@property
def upper_right(self):
return self._get_parameters()[1]
@property
def width(self):
return self._get_parameters()[2]
def _get_parameters(self):
ll = POINTER(c_double)()
ur = POINTER(c_double)()
w = POINTER(c_double)()
n = c_int()
_dll.openmc_mesh_get_params(self._index, ll, ur, w, n)
return (
as_array(ll, (n.value,)),
as_array(ur, (n.value,)),
as_array(w, (n.value,))
)
def set_parameters(self, lower_left=None, upper_right=None, width=None):
if lower_left is not None:
n = len(lower_left)
lower_left = (c_double*n)(*lower_left)
if upper_right is not None:
n = len(upper_right)
upper_right = (c_double*n)(*upper_right)
if width is not None:
n = len(width)
width = (c_double*n)(*width)
_dll.openmc_mesh_set_params(self._index, n, lower_left, upper_right, width)
class _MeshMapping(Mapping):
def __getitem__(self, key):
index = c_int32()
try:
_dll.openmc_get_mesh_index(key, index)
except (AllocationError, InvalidIDError) as e:
# __contains__ expects a KeyError to work correctly
raise KeyError(str(e))
return Mesh(index=index.value)
def __iter__(self):
for i in range(len(self)):
yield Mesh(index=i + 1).id
def __len__(self):
return c_int32.in_dll(_dll, 'n_meshes').value
def __repr__(self):
return repr(dict(self))
meshes = _MeshMapping()

View file

@ -5,9 +5,10 @@ from weakref import WeakValueDictionary
import numpy as np
from numpy.ctypeslib import as_array
from openmc.exceptions import DataError, AllocationError
from . import _dll
from .core import _FortranObject
from .error import _error_handler, DataError, AllocationError
from .error import _error_handler
__all__ = ['Nuclide', 'nuclides', 'load_nuclide']

View file

@ -6,10 +6,11 @@ import numpy as np
from numpy.ctypeslib import as_array
import scipy.stats
from openmc.exceptions import AllocationError, InvalidIDError
from openmc.data.reaction import REACTION_NAME
from . import _dll, Nuclide
from .core import _FortranObjectWithID
from .error import _error_handler, AllocationError, InvalidIDError
from .error import _error_handler
from .filter import _get_filter

View file

@ -23,9 +23,14 @@ class DataLibrary(EqualityMixin):
def __init__(self):
self.libraries = []
def get_by_material(self, value):
def get_by_material(self, name):
"""Return the library dictionary containing a given material.
Parameters
----------
name : str
Name of material, e.g. 'Am241'
Returns
-------
library : dict or None
@ -34,7 +39,7 @@ class DataLibrary(EqualityMixin):
"""
for library in self.libraries:
if value in library['materials']:
if name in library['materials']:
return library
return None

38
openmc/exceptions.py Normal file
View file

@ -0,0 +1,38 @@
class OpenMCError(Exception):
"""Root exception class for OpenMC."""
class GeometryError(OpenMCError):
"""Geometry-related error"""
class InvalidIDError(OpenMCError):
"""Use of an ID that is invalid."""
class AllocationError(OpenMCError):
"""Error related to memory allocation."""
class OutOfBoundsError(OpenMCError):
"""Index in array out of bounds."""
class DataError(OpenMCError):
"""Error relating to nuclear data."""
class PhysicsError(OpenMCError):
"""Error relating to performing physics."""
class InvalidArgumentError(OpenMCError):
"""Argument passed was invalid."""
class InvalidTypeError(OpenMCError):
"""Tried to perform an operation on the wrong type."""
class SetupError(OpenMCError):
"""Error while setting up a problem."""

View file

@ -278,7 +278,7 @@ contains
m % id = i_start
! Set mesh type to rectangular
m % type = LATTICE_RECT
m % type = MESH_REGULAR
! Get pointer to mesh XML node
node_mesh = root % child("mesh")

View file

@ -15,19 +15,19 @@ module error
public :: write_message
! Error codes
integer(C_INT), public, bind(C) :: E_UNASSIGNED = -1
integer(C_INT), public, bind(C) :: E_ALLOCATE = -2
integer(C_INT), public, bind(C) :: E_OUT_OF_BOUNDS = -3
integer(C_INT), public, bind(C) :: E_INVALID_SIZE = -4
integer(C_INT), public, bind(C) :: E_INVALID_ARGUMENT = -5
integer(C_INT), public, bind(C) :: E_INVALID_TYPE = -6
integer(C_INT), public, bind(C) :: E_INVALID_ID = -7
integer(C_INT), public, bind(C) :: E_GEOMETRY = -8
integer(C_INT), public, bind(C) :: E_DATA = -9
integer(C_INT), public, bind(C) :: E_PHYSICS = -10
integer(C_INT), public, bind(C, name='OPENMC_E_UNASSIGNED') :: E_UNASSIGNED = -1
integer(C_INT), public, bind(C, name='OPENMC_E_ALLOCATE') :: E_ALLOCATE = -2
integer(C_INT), public, bind(C, name='OPENMC_E_OUT_OF_BOUNDS') :: E_OUT_OF_BOUNDS = -3
integer(C_INT), public, bind(C, name='OPENMC_E_INVALID_SIZE') :: E_INVALID_SIZE = -4
integer(C_INT), public, bind(C, name='OPENMC_E_INVALID_ARGUMENT') :: E_INVALID_ARGUMENT = -5
integer(C_INT), public, bind(C, name='OPENMC_E_INVALID_TYPE') :: E_INVALID_TYPE = -6
integer(C_INT), public, bind(C, name='OPENMC_E_INVALID_ID') :: E_INVALID_ID = -7
integer(C_INT), public, bind(C, name='OPENMC_E_GEOMETRY') :: E_GEOMETRY = -8
integer(C_INT), public, bind(C, name='OPENMC_E_DATA') :: E_DATA = -9
integer(C_INT), public, bind(C, name='OPENMC_E_PHYSICS') :: E_PHYSICS = -10
! Warning codes
integer(C_INT), public, bind(C) :: E_WARNING = 1
integer(C_INT), public, bind(C, name='OPENMC_E_WARNING') :: E_WARNING = 1
! Error message
character(kind=C_CHAR), public, bind(C) :: openmc_err_msg(256)

View file

@ -544,16 +544,12 @@ contains
c % type = FILL_MATERIAL
do i = 1, n
j = indices(i)
if (j == 0) then
c % material(i) = MATERIAL_VOID
if ((j >= 1 .and. j <= n_materials) .or. j == MATERIAL_VOID) then
c % material(i) = j
else
if (j >= 1 .and. j <= n_materials) then
c % material(i) = j
else
err = E_OUT_OF_BOUNDS
call set_errmsg("Index " // trim(to_str(j)) // " in the &
&materials array is out of bounds.")
end if
err = E_OUT_OF_BOUNDS
call set_errmsg("Index " // trim(to_str(j)) // " in the &
&materials array is out of bounds.")
end if
end do
case (FILL_UNIVERSE)

View file

@ -1,5 +1,7 @@
program main
use, intrinsic :: ISO_C_BINDING
use constants
use message_passing
use openmc_api, only: openmc_init, openmc_finalize, openmc_run, &
@ -9,6 +11,7 @@ program main
implicit none
integer(C_INT) :: err
#ifdef OPENMC_MPI
integer :: mpi_err ! MPI error code
#endif
@ -27,7 +30,7 @@ program main
! start problem based on mode
select case (run_mode)
case (MODE_FIXEDSOURCE, MODE_EIGENVALUE)
call openmc_run()
err = openmc_run()
case (MODE_PLOTTING)
call openmc_plot_geometry()
case (MODE_PARTICLE)

View file

@ -6,7 +6,7 @@ module mesh_header
use constants
use dict_header, only: DictIntInt
use error, only: warning, fatal_error
use error
use hdf5_interface
use string, only: to_str, to_lower
use xml_interface
@ -15,6 +15,13 @@ module mesh_header
private
public :: free_memory_mesh
public :: openmc_extend_meshes
public :: openmc_get_mesh_index
public :: openmc_mesh_get_id
public :: openmc_mesh_get_dimension
public :: openmc_mesh_get_params
public :: openmc_mesh_set_id
public :: openmc_mesh_set_dimension
public :: openmc_mesh_set_params
!===============================================================================
! STRUCTUREDMESH represents a tessellation of n-dimensional Euclidean space by
@ -23,13 +30,13 @@ module mesh_header
type, public :: RegularMesh
integer :: id = -1 ! user-specified id
integer :: type ! rectangular, hexagonal
integer :: n_dimension ! rank of mesh
integer :: type = MESH_REGULAR ! rectangular, hexagonal
integer(C_INT) :: n_dimension ! rank of mesh
real(8) :: volume_frac ! volume fraction of each cell
integer, allocatable :: dimension(:) ! number of cells in each direction
real(8), allocatable :: lower_left(:) ! lower-left corner of mesh
real(8), allocatable :: upper_right(:) ! upper-right corner of mesh
real(8), allocatable :: width(:) ! width of each mesh cell
integer(C_INT), allocatable :: dimension(:) ! number of cells in each direction
real(C_DOUBLE), allocatable :: lower_left(:) ! lower-left corner of mesh
real(C_DOUBLE), allocatable :: upper_right(:) ! upper-right corner of mesh
real(C_DOUBLE), allocatable :: width(:) ! width of each mesh cell
contains
procedure :: from_xml => regular_from_xml
procedure :: get_bin => regular_get_bin
@ -592,4 +599,180 @@ contains
err = 0
end function openmc_extend_meshes
function openmc_get_mesh_index(id, index) result(err) bind(C)
! Return the index in the meshes array of a mesh with a given ID
integer(C_INT32_T), value :: id
integer(C_INT32_T), intent(out) :: index
integer(C_INT) :: err
if (allocated(meshes)) then
if (mesh_dict % has(id)) then
index = mesh_dict % get(id)
err = 0
else
err = E_INVALID_ID
call set_errmsg("No mesh exists with ID=" // trim(to_str(id)) // ".")
end if
else
err = E_ALLOCATE
call set_errmsg("Memory has not been allocated for meshes.")
end if
end function openmc_get_mesh_index
function openmc_mesh_get_id(index, id) result(err) bind(C)
! Return the ID of a mesh
integer(C_INT32_T), value :: index
integer(C_INT32_T), intent(out) :: id
integer(C_INT) :: err
if (index >= 1 .and. index <= size(meshes)) then
id = meshes(index) % id
err = 0
else
err = E_OUT_OF_BOUNDS
call set_errmsg("Index in meshes array is out of bounds.")
end if
end function openmc_mesh_get_id
function openmc_mesh_set_id(index, id) result(err) bind(C)
! Set the ID of a mesh
integer(C_INT32_T), value, intent(in) :: index
integer(C_INT32_T), value, intent(in) :: id
integer(C_INT) :: err
if (index >= 1 .and. index <= n_meshes) then
meshes(index) % id = id
call mesh_dict % set(id, index)
err = 0
else
err = E_OUT_OF_BOUNDS
call set_errmsg("Index in meshes array is out of bounds.")
end if
end function openmc_mesh_set_id
function openmc_mesh_get_dimension(index, dims, n) result(err) bind(C)
! Get the dimension of a mesh
integer(C_INT32_T), value, intent(in) :: index
type(C_PTR), intent(out) :: dims
integer(C_INT), intent(out) :: n
integer(C_INT) :: err
if (index >= 1 .and. index <= n_meshes) then
dims = C_LOC(meshes(index) % dimension)
n = meshes(index) % n_dimension
err = 0
else
err = E_OUT_OF_BOUNDS
call set_errmsg("Index in meshes array is out of bounds.")
end if
end function openmc_mesh_get_dimension
function openmc_mesh_set_dimension(index, n, dims) result(err) bind(C)
! Set the dimension of a mesh
integer(C_INT32_T), value, intent(in) :: index
integer(C_INT), value, intent(in) :: n
integer(C_INT), intent(in) :: dims(n)
integer(C_INT) :: err
if (index >= 1 .and. index <= n_meshes) then
associate (m => meshes(index))
if (allocated(m % dimension)) deallocate (m % dimension)
if (allocated(m % lower_left)) deallocate (m % lower_left)
if (allocated(m % upper_right)) deallocate (m % upper_right)
if (allocated(m % width)) deallocate (m % width)
m % n_dimension = n
allocate(m % dimension(n))
allocate(m % lower_left(n))
allocate(m % upper_right(n))
allocate(m % width(n))
! Copy dimension
m % dimension(:) = dims
end associate
err = 0
else
err = E_OUT_OF_BOUNDS
call set_errmsg("Index in meshes array is out of bounds.")
end if
end function openmc_mesh_set_dimension
function openmc_mesh_get_params(index, ll, ur, width, n) result(err) bind(C)
! Get the mesh parameters
integer(C_INT32_T), value, intent(in) :: index
type(C_PTR), intent(out) :: ll
type(C_PTR), intent(out) :: ur
type(C_PTR), intent(out) :: width
integer(C_INT), intent(out) :: n
integer(C_INT) :: err
err = 0
if (index >= 1 .and. index <= n_meshes) then
associate (m => meshes(index))
if (allocated(m % lower_left)) then
ll = C_LOC(m % lower_left(1))
ur = C_LOC(m % upper_right(1))
width = C_LOC(m % width(1))
n = m % n_dimension
else
err = E_ALLOCATE
call set_errmsg("Mesh parameters have not been set.")
end if
end associate
else
err = E_OUT_OF_BOUNDS
call set_errmsg("Index in meshes array is out of bounds.")
end if
end function openmc_mesh_get_params
function openmc_mesh_set_params(index, n, ll, ur, width) result(err) bind(C)
! Set the mesh parameters
integer(C_INT32_T), value, intent(in) :: index
integer(C_INT), value, intent(in) :: n
real(C_DOUBLE), intent(in), optional :: ll(n)
real(C_DOUBLE), intent(in), optional :: ur(n)
real(C_DOUBLE), intent(in), optional :: width(n)
integer(C_INT) :: err
err = 0
if (index >= 1 .and. index <= n_meshes) then
associate (m => meshes(index))
if (allocated(m % lower_left)) deallocate (m % lower_left)
if (allocated(m % upper_right)) deallocate (m % upper_right)
if (allocated(m % width)) deallocate (m % width)
allocate(m % lower_left(n))
allocate(m % upper_right(n))
allocate(m % width(n))
if (present(ll) .and. present(ur)) then
m % lower_left(:) = ll
m % upper_right(:) = ur
m % width(:) = (ur - ll) / m % dimension
elseif (present(ll) .and. present(width)) then
m % lower_left(:) = ll
m % width(:) = width
m % upper_right(:) = ll + width * m % dimension
elseif (present(ur) .and. present(width)) then
m % upper_right(:) = ur
m % width(:) = width
m % lower_left(:) = ur - width * m % dimension
else
err = E_INVALID_ARGUMENT
call set_errmsg("At least two parameters must be specified.")
end if
end associate
else
err = E_OUT_OF_BOUNDS
call set_errmsg("Index in meshes array is out of bounds.")
end if
end function openmc_mesh_set_params
end module mesh_header

View file

@ -48,6 +48,10 @@ module simulation
public :: openmc_simulation_init
public :: openmc_simulation_finalize
integer(C_INT), parameter :: STATUS_EXIT_NORMAL = 0
integer(C_INT), parameter :: STATUS_EXIT_MAX_BATCH = 1
integer(C_INT), parameter :: STATUS_EXIT_ON_TRIGGER = 2
contains
!===============================================================================
@ -56,28 +60,36 @@ contains
! calculation.
!===============================================================================
subroutine openmc_run() bind(C)
function openmc_run() result(err) bind(C)
integer(C_INT) :: err
integer(C_INT) :: status
call openmc_simulation_init()
do while (openmc_next_batch() == 0)
do
err = openmc_next_batch(status)
if (status /= 0 .or. err < 0) exit
end do
call openmc_simulation_finalize()
end subroutine openmc_run
end function openmc_run
!===============================================================================
! OPENMC_NEXT_BATCH
!===============================================================================
function openmc_next_batch() result(retval) bind(C)
integer(C_INT) :: retval
function openmc_next_batch(status) result(err) bind(C)
integer(C_INT), intent(out), optional :: status
integer(C_INT) :: err
type(Particle) :: p
integer(8) :: i_work
err = 0
! Make sure simulation has been initialized
if (.not. simulation_initialized) then
retval = -3
err = E_ALLOCATE
call set_errmsg("Simulation has not been initialized yet.")
return
end if
@ -86,7 +98,7 @@ contains
! Handle restart runs
if (restart_run .and. current_batch <= restart_batch) then
call replay_batch_history()
retval = 0
status = STATUS_EXIT_NORMAL
return
end if
@ -124,12 +136,14 @@ contains
call finalize_batch()
! Check simulation ending criteria
if (current_batch == n_max_batches) then
retval = -1
elseif (satisfy_triggers) then
retval = -2
else
retval = 0
if (present(status)) then
if (current_batch == n_max_batches) then
status = STATUS_EXIT_MAX_BATCH
elseif (satisfy_triggers) then
status = STATUS_EXIT_ON_TRIGGER
else
status = STATUS_EXIT_NORMAL
end if
end if
end function openmc_next_batch

View file

@ -16,6 +16,7 @@ module tally_filter_mesh
implicit none
private
public :: openmc_mesh_filter_get_mesh
public :: openmc_mesh_filter_set_mesh
!===============================================================================
@ -280,35 +281,46 @@ contains
! C API FUNCTIONS
!===============================================================================
function openmc_mesh_filter_get_mesh(index, index_mesh) result(err) bind(C)
! Get the mesh for a mesh filter
integer(C_INT32_T), value, intent(in) :: index
integer(C_INT32_T), intent(out) :: index_mesh
integer(C_INT) :: err
err = verify_filter(index)
if (err == 0) then
select type (f => filters(index) % obj)
type is (MeshFilter)
index_mesh = f % mesh
class default
err = E_INVALID_TYPE
call set_errmsg("Tried to set mesh on a non-mesh filter.")
end select
end if
end function openmc_mesh_filter_get_mesh
function openmc_mesh_filter_set_mesh(index, index_mesh) result(err) bind(C)
! Set the mesh for a mesh filter
integer(C_INT32_T), value, intent(in) :: index
integer(C_INT32_T), value, intent(in) :: index_mesh
integer(C_INT) :: err
err = 0
if (index >= 1 .and. index <= n_filters) then
if (allocated(filters(index) % obj)) then
select type (f => filters(index) % obj)
type is (MeshFilter)
if (index_mesh >= 1 .and. index_mesh <= n_meshes) then
f % mesh = index_mesh
f % n_bins = product(meshes(index_mesh) % dimension)
else
err = E_OUT_OF_BOUNDS
call set_errmsg("Index in 'meshes' array is out of bounds.")
end if
err = verify_filter(index)
if (err == 0) then
select type (f => filters(index) % obj)
type is (MeshFilter)
if (index_mesh >= 1 .and. index_mesh <= n_meshes) then
f % mesh = index_mesh
f % n_bins = product(meshes(index_mesh) % dimension)
else
err = E_OUT_OF_BOUNDS
call set_errmsg("Index in 'meshes' array is out of bounds.")
end if
class default
err = E_INVALID_TYPE
call set_errmsg("Tried to set mesh on a non-mesh filter.")
end select
else
err = E_ALLOCATE
call set_errmsg("Filter type has not been set yet.")
end if
else
err = E_OUT_OF_BOUNDS
call set_errmsg("Index in filters array out of bounds.")
err = E_INVALID_TYPE
call set_errmsg("Tried to set mesh on a non-mesh filter.")
end select
end if
end function openmc_mesh_filter_set_mesh

View file

@ -16,6 +16,7 @@ module tally_filter_meshsurface
implicit none
private
public :: openmc_meshsurface_filter_get_mesh
public :: openmc_meshsurface_filter_set_mesh
!===============================================================================
@ -296,6 +297,25 @@ contains
! C API FUNCTIONS
!===============================================================================
function openmc_meshsurface_filter_get_mesh(index, index_mesh) result(err) bind(C)
! Get the mesh for a mesh surface filter
integer(C_INT32_T), value, intent(in) :: index
integer(C_INT32_T), intent(out) :: index_mesh
integer(C_INT) :: err
err = verify_filter(index)
if (err == 0) then
select type (f => filters(index) % obj)
type is (MeshSurfaceFilter)
index_mesh = f % mesh
class default
err = E_INVALID_TYPE
call set_errmsg("Tried to set mesh on a non-mesh filter.")
end select
end if
end function openmc_meshsurface_filter_get_mesh
function openmc_meshsurface_filter_set_mesh(index, index_mesh) result(err) bind(C)
! Set the mesh for a mesh surface filter
integer(C_INT32_T), value, intent(in) :: index
@ -304,30 +324,22 @@ contains
integer :: n_dim
err = 0
if (index >= 1 .and. index <= n_filters) then
if (allocated(filters(index) % obj)) then
select type (f => filters(index) % obj)
type is (MeshSurfaceFilter)
if (index_mesh >= 1 .and. index_mesh <= n_meshes) then
f % mesh = index_mesh
n_dim = meshes(index_mesh) % n_dimension
f % n_bins = 4*n_dim*product(meshes(index_mesh) % dimension)
else
err = E_OUT_OF_BOUNDS
call set_errmsg("Index in 'meshes' array is out of bounds.")
end if
class default
err = E_INVALID_TYPE
call set_errmsg("Tried to set mesh on a non-mesh filter.")
end select
else
err = E_ALLOCATE
call set_errmsg("Filter type has not been set yet.")
end if
else
err = E_OUT_OF_BOUNDS
call set_errmsg("Index in filters array out of bounds.")
err = verify_filter(index)
if (err == 0) then
select type (f => filters(index) % obj)
type is (MeshSurfaceFilter)
if (index_mesh >= 1 .and. index_mesh <= n_meshes) then
f % mesh = index_mesh
n_dim = meshes(index_mesh) % n_dimension
f % n_bins = 4*n_dim*product(meshes(index_mesh) % dimension)
else
err = E_OUT_OF_BOUNDS
call set_errmsg("Index in 'meshes' array is out of bounds.")
end if
class default
err = E_INVALID_TYPE
call set_errmsg("Tried to set mesh on a non-mesh filter.")
end select
end if
end function openmc_meshsurface_filter_set_mesh

View file

@ -4,6 +4,7 @@ import os
import numpy as np
import pytest
import openmc
import openmc.exceptions as exc
import openmc.capi
from tests import cdtemp
@ -60,7 +61,7 @@ def test_cell(capi_init):
def test_new_cell(capi_init):
with pytest.raises(openmc.capi.AllocationError):
with pytest.raises(exc.AllocationError):
openmc.capi.Cell(1)
new_cell = openmc.capi.Cell()
new_cell_with_id = openmc.capi.Cell(10)
@ -91,7 +92,7 @@ def test_material(capi_init):
def test_new_material(capi_init):
with pytest.raises(openmc.capi.AllocationError):
with pytest.raises(exc.AllocationError):
openmc.capi.Material(1)
new_mat = openmc.capi.Material()
new_mat_with_id = openmc.capi.Material(10)
@ -109,7 +110,7 @@ def test_nuclide_mapping(capi_init):
def test_load_nuclide(capi_init):
openmc.capi.load_nuclide('Pu239')
with pytest.raises(openmc.capi.DataError):
with pytest.raises(exc.DataError):
openmc.capi.load_nuclide('Pu3')
@ -145,7 +146,7 @@ def test_tally(capi_init):
assert isinstance(t.filters[1], openmc.capi.EnergyFilter)
# Create new filter and replace existing
with pytest.raises(openmc.capi.AllocationError):
with pytest.raises(exc.AllocationError):
openmc.capi.MaterialFilter(uid=1)
mats = openmc.capi.materials
f = openmc.capi.MaterialFilter([mats[2], mats[1]])
@ -153,7 +154,7 @@ def test_tally(capi_init):
assert t.filters == [f]
assert t.nuclides == ['U235', 'U238']
with pytest.raises(openmc.capi.DataError):
with pytest.raises(exc.DataError):
t.nuclides = ['Zr2']
t.nuclides = ['U234', 'Zr90']
assert t.nuclides == ['U234', 'Zr90']
@ -165,7 +166,7 @@ def test_tally(capi_init):
def test_new_tally(capi_init):
with pytest.raises(openmc.capi.AllocationError):
with pytest.raises(exc.AllocationError):
openmc.capi.Material(1)
new_tally = openmc.capi.Tally()
new_tally.scores = ['flux']
@ -206,7 +207,7 @@ def test_by_batch(capi_run):
# Running next batch before simulation is initialized should raise an
# exception
with pytest.raises(openmc.capi.AllocationError):
with pytest.raises(exc.AllocationError):
openmc.capi.next_batch()
openmc.capi.simulation_init()
@ -241,7 +242,7 @@ def test_find_cell(capi_init):
assert cell is openmc.capi.cells[1]
cell, instance = openmc.capi.find_cell((0.4, 0., 0.))
assert cell is openmc.capi.cells[2]
with pytest.raises(openmc.capi.GeometryError):
with pytest.raises(exc.GeometryError):
openmc.capi.find_cell((100., 100., 100.))
@ -250,3 +251,38 @@ def test_find_material(capi_init):
assert mat is openmc.capi.materials[1]
mat = openmc.capi.find_material((0.4, 0., 0.))
assert mat is openmc.capi.materials[2]
def test_mesh(capi_init):
mesh = openmc.capi.Mesh()
mesh.dimension = (2, 3, 4)
assert mesh.dimension == (2, 3, 4)
with pytest.raises(exc.AllocationError):
mesh2 = openmc.capi.Mesh(mesh.id)
# Make sure each combination of parameters works
ll = (0., 0., 0.)
ur = (10., 10., 10.)
width = (1., 1., 1.)
mesh.set_parameters(lower_left=ll, upper_right=ur)
assert mesh.lower_left == pytest.approx(ll)
assert mesh.upper_right == pytest.approx(ur)
mesh.set_parameters(lower_left=ll, width=width)
assert mesh.lower_left == pytest.approx(ll)
assert mesh.width == pytest.approx(width)
mesh.set_parameters(upper_right=ur, width=width)
assert mesh.upper_right == pytest.approx(ur)
assert mesh.width == pytest.approx(width)
meshes = openmc.capi.meshes
assert isinstance(meshes, Mapping)
assert len(meshes) == 1
for mesh_id, mesh in meshes.items():
assert isinstance(mesh, openmc.capi.Mesh)
assert mesh_id == mesh.id
mf = openmc.capi.MeshFilter(mesh)
assert mf.mesh == mesh
msf = openmc.capi.MeshSurfaceFilter(mesh)
assert msf.mesh == mesh