From 411fd288ea69fbf7d1678444c5d5542ea448f304 Mon Sep 17 00:00:00 2001 From: Alex Lindsay Date: Thu, 26 Apr 2018 10:04:38 -0600 Subject: [PATCH 1/5] Expand C API, targeting FETs --- include/openmc.h | 1 + openmc/capi/filter.py | 103 ++++++++++++++++++++++++++++-- src/api.F90 | 1 + src/tallies/tally_filter_cell.F90 | 27 +++++++- 4 files changed, 127 insertions(+), 5 deletions(-) diff --git a/include/openmc.h b/include/openmc.h index 38b7f21670..ce28fa2d04 100644 --- a/include/openmc.h +++ b/include/openmc.h @@ -17,6 +17,7 @@ extern "C" { }; int openmc_calculate_volumes(); + int openmc_cell_filter_get_bins(int32_t index, int32_t** cells, int32_t* n); 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); diff --git a/openmc/capi/filter.py b/openmc/capi/filter.py index 5c21c3ef4b..4f5b46915a 100644 --- a/openmc/capi/filter.py +++ b/openmc/capi/filter.py @@ -17,11 +17,16 @@ from .mesh import Mesh __all__ = ['Filter', 'AzimuthalFilter', 'CellFilter', 'CellbornFilter', 'CellfromFilter', 'DistribcellFilter', 'DelayedGroupFilter', 'EnergyFilter', 'EnergyoutFilter', - 'EnergyFunctionFilter', 'MaterialFilter', 'MeshFilter', - 'MeshSurfaceFilter', 'MuFilter', 'PolarFilter', 'SurfaceFilter', - 'UniverseFilter', 'filters'] + 'EnergyFunctionFilter', 'LegendreFilter', 'MaterialFilter', 'MeshFilter', + 'MeshSurfaceFilter', 'MuFilter', 'PolarFilter', 'SphericalHarmonicsFilter', + 'SpatialLegendreFilter', 'SurfaceFilter', + 'UniverseFilter', 'ZernikeFilter', 'filters'] # Tally functions +_dll.openmc_cell_filter_get_bins.argtypes = [ + c_int32, POINTER(POINTER(c_int32)), POINTER(c_int32)] +_dll.openmc_cell_filter_get_bins.restype = c_int +_dll.openmc_cell_filter_get_bins.errcheck = _error_handler _dll.openmc_energy_filter_get_bins.argtypes = [ c_int32, POINTER(POINTER(c_double)), POINTER(c_int32)] _dll.openmc_energy_filter_get_bins.restype = c_int @@ -47,6 +52,12 @@ _dll.openmc_filter_set_type.errcheck = _error_handler _dll.openmc_get_filter_index.argtypes = [c_int32, POINTER(c_int32)] _dll.openmc_get_filter_index.restype = c_int _dll.openmc_get_filter_index.errcheck = _error_handler +_dll.openmc_legendre_filter_get_order.argtypes = [c_int32, POINTER(c_int)] +_dll.openmc_legendre_filter_get_order.restype = c_int +_dll.openmc_legendre_filter_get_order.errcheck = _error_handler +_dll.openmc_legendre_filter_set_order.argtypes = [c_int32, c_int] +_dll.openmc_legendre_filter_set_order.restype = c_int +_dll.openmc_legendre_filter_set_order.errcheck = _error_handler _dll.openmc_material_filter_get_bins.argtypes = [ c_int32, POINTER(POINTER(c_int32)), POINTER(c_int32)] _dll.openmc_material_filter_get_bins.restype = c_int @@ -66,7 +77,24 @@ _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 - +_dll.openmc_spatial_legendre_filter_get_order.argtypes = [c_int32, POINTER(c_int)] +_dll.openmc_spatial_legendre_filter_get_order.restype = c_int +_dll.openmc_spatial_legendre_filter_get_order.errcheck = _error_handler +_dll.openmc_spatial_legendre_filter_set_order.argtypes = [c_int32, c_int] +_dll.openmc_spatial_legendre_filter_set_order.restype = c_int +_dll.openmc_spatial_legendre_filter_set_order.errcheck = _error_handler +_dll.openmc_sphharm_filter_get_order.argtypes = [c_int32, POINTER(c_int)] +_dll.openmc_sphharm_filter_get_order.restype = c_int +_dll.openmc_sphharm_filter_get_order.errcheck = _error_handler +_dll.openmc_sphharm_filter_set_order.argtypes = [c_int32, c_int] +_dll.openmc_sphharm_filter_set_order.restype = c_int +_dll.openmc_sphharm_filter_set_order.errcheck = _error_handler +_dll.openmc_zernike_filter_get_order.argtypes = [c_int32, POINTER(c_int)] +_dll.openmc_zernike_filter_get_order.restype = c_int +_dll.openmc_zernike_filter_get_order.errcheck = _error_handler +_dll.openmc_zernike_filter_set_order.argtypes = [c_int32, c_int] +_dll.openmc_zernike_filter_set_order.restype = c_int +_dll.openmc_zernike_filter_set_order.errcheck = _error_handler class Filter(_FortranObjectWithID): __instances = WeakValueDictionary() @@ -150,6 +178,13 @@ class AzimuthalFilter(Filter): class CellFilter(Filter): filter_type = 'cell' + @property + def bins(self): + cells = POINTER(c_int32)() + n = c_int32() + _dll.openmc_cell_filter_get_bins(self._index, cells, n) + return as_array(cells, (n.value,)) + class CellbornFilter(Filter): filter_type = 'cellborn' @@ -171,6 +206,20 @@ class EnergyFunctionFilter(Filter): filter_type = 'energyfunction' +class LegendreFilter(Filter): + filter_type = 'legendre' + + @property + def order(self): + temp_order = c_int() + _dll.openmc_legendre_filter_get_order(self._index, temp_order) + return temp_order.value + + @order.setter + def order(self, order): + _dll.openmc_legendre_filter_set_order(self._index, order) + + class MaterialFilter(Filter): filter_type = 'material' @@ -241,6 +290,34 @@ class PolarFilter(Filter): filter_type = 'polar' +class SphericalHarmonicsFilter(Filter): + filter_type = 'sphericalharmonics' + + @property + def order(self): + temp_order = c_int() + _dll.openmc_sphharm_filter_get_order(self._index, temp_order) + return temp_order.value + + @order.setter + def order(self, order): + _dll.openmc_sphharm_filter_set_order(self._index, order) + + +class SpatialLegendreFilter(Filter): + filter_type = 'spatiallegendre' + + @property + def order(self): + temp_order = c_int() + _dll.openmc_spatial_legendre_filter_get_order(self._index, temp_order) + return temp_order.value + + @order.setter + def order(self, order): + _dll.openmc_spatial_legendre_filter_set_order(self._index, order) + + class SurfaceFilter(Filter): filter_type = 'surface' @@ -249,6 +326,20 @@ class UniverseFilter(Filter): filter_type = 'universe' +class ZernikeFilter(Filter): + filter_type = 'zernike' + + @property + def order(self): + temp_order = c_int() + _dll.openmc_zernike_filter_get_order(self._index, temp_order) + return temp_order.value + + @order.setter + def order(self, order): + _dll.openmc_zernike_filter_set_order(self._index, order) + + _FILTER_TYPE_MAP = { 'azimuthal': AzimuthalFilter, 'cell': CellFilter, @@ -259,13 +350,17 @@ _FILTER_TYPE_MAP = { 'energy': EnergyFilter, 'energyout': EnergyoutFilter, 'energyfunction': EnergyFunctionFilter, + 'legendre': LegendreFilter, 'material': MaterialFilter, 'mesh': MeshFilter, 'meshsurface': MeshSurfaceFilter, 'mu': MuFilter, 'polar': PolarFilter, + 'sphericalharmoics': SphericalHarmonicsFilter, + 'spatiallegendre': SpatialLegendreFilter, 'surface': SurfaceFilter, 'universe': UniverseFilter, + 'zernike': ZernikeFilter } diff --git a/src/api.F90 b/src/api.F90 index da50007d68..1740fa2abd 100644 --- a/src/api.F90 +++ b/src/api.F90 @@ -35,6 +35,7 @@ module openmc_api private public :: openmc_calculate_volumes + public :: openmc_cell_filter_get_bins public :: openmc_cell_get_id public :: openmc_cell_get_fill public :: openmc_cell_set_fill diff --git a/src/tallies/tally_filter_cell.F90 b/src/tallies/tally_filter_cell.F90 index 00ab8fa15b..99a9892a77 100644 --- a/src/tallies/tally_filter_cell.F90 +++ b/src/tallies/tally_filter_cell.F90 @@ -14,13 +14,14 @@ module tally_filter_cell implicit none private + public :: openmc_cell_filter_get_bins !=============================================================================== ! CELLFILTER specifies which geometric cells tally events reside in. !=============================================================================== type, public, extends(TallyFilter) :: CellFilter - integer, allocatable :: cells(:) + integer(C_INT32_T), allocatable :: cells(:) type(DictIntInt) :: map contains procedure :: from_xml @@ -116,4 +117,28 @@ contains label = "Cell " // to_str(cells(this % cells(bin)) % id) end function text_label_cell +!=============================================================================== +! C API FUNCTIONS +!=============================================================================== + + function openmc_cell_filter_get_bins(index, cells, n) result(err) bind(C) + ! Return the cells associated with a cell filter + integer(C_INT32_T), value :: index + type(C_PTR), intent(out) :: cells + integer(C_INT32_T), intent(out) :: n + integer(C_INT) :: err + + err = verify_filter(index) + if (err == 0) then + select type (f => filters(index) % obj) + type is (CellFilter) + cells = C_LOC(f % cells) + n = size(f % cells) + class default + err = E_INVALID_TYPE + call set_errmsg("Tried to get cells from a non-cell filter.") + end select + end if + end function openmc_cell_filter_get_bins + end module tally_filter_cell From 5a863215f310a8d252fc3f136a29c679bc428bf9 Mon Sep 17 00:00:00 2001 From: Alex Lindsay Date: Mon, 7 May 2018 14:41:51 -0600 Subject: [PATCH 2/5] Take char* instead of char** --- include/openmc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/openmc.h b/include/openmc.h index ce28fa2d04..a9ffa74d75 100644 --- a/include/openmc.h +++ b/include/openmc.h @@ -32,7 +32,7 @@ extern "C" { 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_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); int openmc_finalize(); From 85e6eb961680e1d3066beb5c57d9beb41ec9c103 Mon Sep 17 00:00:00 2001 From: Alex Lindsay Date: Mon, 21 May 2018 14:14:00 -0600 Subject: [PATCH 3/5] hitting out of bounds error in fortran --- openmc/capi/filter.py | 2 +- tests/unit_tests/test_capi.py | 26 ++++++++++++++++++++++++-- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/openmc/capi/filter.py b/openmc/capi/filter.py index 4f5b46915a..611efb7fda 100644 --- a/openmc/capi/filter.py +++ b/openmc/capi/filter.py @@ -356,7 +356,7 @@ _FILTER_TYPE_MAP = { 'meshsurface': MeshSurfaceFilter, 'mu': MuFilter, 'polar': PolarFilter, - 'sphericalharmoics': SphericalHarmonicsFilter, + 'sphericalharmonics': SphericalHarmonicsFilter, 'spatiallegendre': SpatialLegendreFilter, 'surface': SurfaceFilter, 'universe': UniverseFilter, diff --git a/tests/unit_tests/test_capi.py b/tests/unit_tests/test_capi.py index a21e858fda..c353d8317f 100644 --- a/tests/unit_tests/test_capi.py +++ b/tests/unit_tests/test_capi.py @@ -26,6 +26,15 @@ def pincell_model(): mat_tally.scores = ['total', 'elastic', '(n,gamma)'] pincell.tallies.append(mat_tally) + # Add an expansion tally + zernike_tally = openmc.Tally() + filter3 = openmc.ZernikeFilter(5, r=.63) + cells = pincell.geometry.root_universe.cells + filter4 = openmc.CellFilter(list(cells.values())) + zernike_tally.filters = [filter3, filter4] + zernike_tally.scores = ['fission'] + pincell.tallies.append(zernike_tally) + # Write XML files in tmpdir with cdtemp(): pincell.export_to_xml() @@ -132,7 +141,7 @@ def test_settings(capi_init): def test_tally_mapping(capi_init): tallies = openmc.capi.tallies assert isinstance(tallies, Mapping) - assert len(tallies) == 1 + assert len(tallies) == 2 for tally_id, tally in tallies.items(): assert isinstance(tally, openmc.capi.Tally) assert tally_id == tally.id @@ -168,6 +177,16 @@ def test_tally(capi_init): t.active = True assert t.active + t2 = openmc.capi.tallies[2] + t2.id = 2 + assert len(t2.filters) == 2 + assert isinstance(t2.filters[0], openmc.capi.ZernikeFilter) + assert isinstance(t2.filters[1], openmc.capi.CellFilter) + assert len(t2.filters[1].bins) == 3 + assert t2.filters[0].order == 5 + t2.filters[0].order = 7 + openmc.capi.simulation_init() + def test_new_tally(capi_init): with pytest.raises(exc.AllocationError): @@ -176,7 +195,7 @@ def test_new_tally(capi_init): new_tally.scores = ['flux'] new_tally_with_id = openmc.capi.Tally(10) new_tally_with_id.scores = ['flux'] - assert len(openmc.capi.tallies) == 3 + assert len(openmc.capi.tallies) == 4 def test_tally_results(capi_run): @@ -187,6 +206,9 @@ def test_tally_results(capi_run): assert np.all(t.std_dev[nonzero] >= 0) assert np.all(t.ci_width()[nonzero] >= 1.95*t.std_dev[nonzero]) + t2 = openmc.capi.tallies[2] + assert t2.mean.size == 108 # 36 coefficients for 7th order Zernike * 3 cells + def test_global_tallies(capi_run): assert openmc.capi.num_realizations() == 5 From 609877e131dda4aad7d7db0866509026c8ec80bd Mon Sep 17 00:00:00 2001 From: Alex Lindsay Date: Mon, 21 May 2018 15:18:05 -0600 Subject: [PATCH 4/5] Give up on setter test for now. --- tests/unit_tests/test_capi.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/unit_tests/test_capi.py b/tests/unit_tests/test_capi.py index c353d8317f..11a47b1506 100644 --- a/tests/unit_tests/test_capi.py +++ b/tests/unit_tests/test_capi.py @@ -184,8 +184,6 @@ def test_tally(capi_init): assert isinstance(t2.filters[1], openmc.capi.CellFilter) assert len(t2.filters[1].bins) == 3 assert t2.filters[0].order == 5 - t2.filters[0].order = 7 - openmc.capi.simulation_init() def test_new_tally(capi_init): @@ -207,7 +205,7 @@ def test_tally_results(capi_run): assert np.all(t.ci_width()[nonzero] >= 1.95*t.std_dev[nonzero]) t2 = openmc.capi.tallies[2] - assert t2.mean.size == 108 # 36 coefficients for 7th order Zernike * 3 cells + assert t2.mean.size == 63 # 21 coefficients for 5th order Zernike * 3 cells def test_global_tallies(capi_run): From 7c01594111f25fe4df4bb7a71ec0f13bd1116798 Mon Sep 17 00:00:00 2001 From: Alex Lindsay Date: Tue, 22 May 2018 08:12:49 -0600 Subject: [PATCH 5/5] Add init methods (with order) for capi expansion filters --- include/openmc.h | 2 +- openmc/capi/filter.py | 20 ++++++++++++++++++++ tests/unit_tests/test_capi.py | 3 ++- 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/include/openmc.h b/include/openmc.h index a9ffa74d75..2c0f10eae0 100644 --- a/include/openmc.h +++ b/include/openmc.h @@ -32,7 +32,7 @@ extern "C" { 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_get_type(int32_t index, char* type); int openmc_filter_set_id(int32_t index, int32_t id); int openmc_filter_set_type(int32_t index, const char* type); int openmc_finalize(); diff --git a/openmc/capi/filter.py b/openmc/capi/filter.py index 611efb7fda..391e63f073 100644 --- a/openmc/capi/filter.py +++ b/openmc/capi/filter.py @@ -209,6 +209,11 @@ class EnergyFunctionFilter(Filter): class LegendreFilter(Filter): filter_type = 'legendre' + def __init__(self, order=None, uid=None, new=True, index=None): + super().__init__(uid, new, index) + if order is not None: + self.order = order + @property def order(self): temp_order = c_int() @@ -293,6 +298,11 @@ class PolarFilter(Filter): class SphericalHarmonicsFilter(Filter): filter_type = 'sphericalharmonics' + def __init__(self, order=None, uid=None, new=True, index=None): + super().__init__(uid, new, index) + if order is not None: + self.order = order + @property def order(self): temp_order = c_int() @@ -307,6 +317,11 @@ class SphericalHarmonicsFilter(Filter): class SpatialLegendreFilter(Filter): filter_type = 'spatiallegendre' + def __init__(self, order=None, uid=None, new=True, index=None): + super().__init__(uid, new, index) + if order is not None: + self.order = order + @property def order(self): temp_order = c_int() @@ -329,6 +344,11 @@ class UniverseFilter(Filter): class ZernikeFilter(Filter): filter_type = 'zernike' + def __init__(self, order=None, uid=None, new=True, index=None): + super().__init__(uid, new, index) + if order is not None: + self.order = order + @property def order(self): temp_order = c_int() diff --git a/tests/unit_tests/test_capi.py b/tests/unit_tests/test_capi.py index 11a47b1506..af013cbb5b 100644 --- a/tests/unit_tests/test_capi.py +++ b/tests/unit_tests/test_capi.py @@ -205,7 +205,8 @@ def test_tally_results(capi_run): assert np.all(t.ci_width()[nonzero] >= 1.95*t.std_dev[nonzero]) t2 = openmc.capi.tallies[2] - assert t2.mean.size == 63 # 21 coefficients for 5th order Zernike * 3 cells + n = 5 + assert t2.mean.size == (n + 1) * (n + 2) // 2 * 3 # Number of Zernike coeffs * 3 cells def test_global_tallies(capi_run):