Have openmc_next_batch return an actual error

This commit is contained in:
Paul Romano 2018-04-05 16:07:51 -05:00
parent 5fb3031d99
commit c78d296bf6
14 changed files with 154 additions and 117 deletions

View file

@ -65,11 +65,11 @@ extern "C" {
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_simulation_finalize();
void openmc_simulation_init();
int openmc_source_bank(struct Bank** ptr, int64_t* n);
@ -102,17 +102,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

@ -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']

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,9 +6,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
from .mesh import Mesh

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']

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__ = ['Mesh', 'meshes']

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

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

@ -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

@ -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

@ -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

@ -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.))
@ -256,7 +257,7 @@ def test_mesh(capi_init):
mesh = openmc.capi.Mesh()
mesh.dimension = (2, 3, 4)
assert mesh.dimension == (2, 3, 4)
with pytest.raises(openmc.capi.AllocationError):
with pytest.raises(exc.AllocationError):
mesh2 = openmc.capi.Mesh(mesh.id)
# Make sure each combination of parameters works