From 050cb6e016ff6ddb29db07170a2d19a9eac9a259 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Sat, 29 Jul 2017 09:04:41 -0500 Subject: [PATCH] Move cell/tally functionality into View/Mapping classes --- openmc/capi/__init__.py | 56 ++-------------- openmc/capi/cell.py | 68 +++++++++++++++++++ openmc/capi/tally.py | 71 ++++++++++++++++++++ src/api.F90 | 140 +++++++++++++++++++++++++++++----------- 4 files changed, 247 insertions(+), 88 deletions(-) create mode 100644 openmc/capi/cell.py create mode 100644 openmc/capi/tally.py diff --git a/openmc/capi/__init__.py b/openmc/capi/__init__.py index f8beb2fd7..b3b5731c1 100644 --- a/openmc/capi/__init__.py +++ b/openmc/capi/__init__.py @@ -38,8 +38,6 @@ except OSError: _available = False -_int3 = c_int*3 -_double3 = c_double*3 class GeometryError(Exception): @@ -97,22 +95,6 @@ def calculate_volumes(): _dll.openmc_calculate_volumes() -def cell_set_temperature(cell_id, T, instance=None): - """Set the temperature of a cell - - Parameters - ---------- - cell_id : int - ID of the cell - T : float - Temperature in K - instance : int or None - Which instance of the cell - - """ - _dll.openmc_cell_set_temperature(cell_id, T, instance) - - def finalize(): """Finalize simulation and free memory""" _dll.openmc_finalize() @@ -149,7 +131,7 @@ def find(xyz, rtype='cell'): # Call openmc_find uid = c_int32() instance = c_int32() - _dll.openmc_find(_double3(*xyz), r_int, uid, instance) + _dll.openmc_find((c_double*3)(*xyz), r_int, uid, instance) return (uid.value if uid != 0 else None), instance.value @@ -203,25 +185,6 @@ def run(): _dll.openmc_run() -def tally_results(tally_id): - """Get tally results array - - Parameters - ---------- - tally_id : int - ID of tally - - Returns - ------- - numpy.ndarray - Array that exposes the internal tally results array - - """ - data = POINTER(c_double)() - shape = _int3() - _dll.openmc_tally_results(tally_id, data, shape) - return as_array(data, tuple(shape[::-1])) - @contextmanager def run_in_memory(intracomm=None): @@ -254,7 +217,7 @@ if _available: _dll.openmc_calculate_volumes.restype = None _dll.openmc_finalize.restype = None _dll.openmc_find.argtypes = [ - POINTER(_double3), c_int, POINTER(c_int32), POINTER(c_int32)] + POINTER(c_double*3), c_int, POINTER(c_int32), POINTER(c_int32)] _dll.openmc_find.restype = c_int _dll.openmc_find.errcheck = _error_handler _dll.openmc_init.argtypes = [POINTER(c_int)] @@ -262,22 +225,11 @@ if _available: _dll.openmc_get_keff.argtypes = [POINTER(c_double*2)] _dll.openmc_get_keff.restype = c_int _dll.openmc_get_keff.errcheck = _error_handler - - # Cell functions - _dll.openmc_cell_set_temperature.argtypes = [ - c_int32, c_double, POINTER(c_int32)] - _dll.openmc_cell_set_temperature.restype = c_int - _dll.openmc_cell_set_temperature.errcheck = _error_handler - _dll.openmc_plot_geometry.restype = None _dll.openmc_run.restype = None _dll.openmc_reset.restype = None - # Tally functions - _dll.openmc_tally_results.argtypes = [ - c_int32, _double_array, POINTER(_int3)] - _dll.openmc_tally_results.restype = c_int - _dll.openmc_tally_results.errcheck = _error_handler - from .nuclide import * from .material import * + from .cell import * + from .tally import * diff --git a/openmc/capi/cell.py b/openmc/capi/cell.py new file mode 100644 index 000000000..fba34db85 --- /dev/null +++ b/openmc/capi/cell.py @@ -0,0 +1,68 @@ +from collections import Mapping +from ctypes import c_int, c_int32, c_double, c_char_p, POINTER +from weakref import WeakValueDictionary + +import numpy as np + +from openmc.capi import _dll, _error_handler + +__all__ = ['CellView', 'cells'] + +# Cell functions +_dll.openmc_cell_id.argtypes = [c_int32, POINTER(c_int32)] +_dll.openmc_cell_id.restype = c_int +_dll.openmc_cell_id.errcheck = _error_handler +_dll.openmc_cell_set_temperature.argtypes = [ + c_int32, c_double, POINTER(c_int32)] +_dll.openmc_cell_set_temperature.restype = c_int +_dll.openmc_cell_set_temperature.errcheck = _error_handler +_dll.openmc_get_cell.argtypes = [c_int32, POINTER(c_int32)] +_dll.openmc_get_cell.restype = c_int +_dll.openmc_get_cell.errcheck = _error_handler + + +class CellView(object): + __instances = WeakValueDictionary() + def __new__(cls, *args): + if args not in cls.__instances: + instance = super().__new__(cls) + cls.__instances[args] = instance + return cls.__instances[args] + + def __init__(self, index): + self._index = index + + @property + def id(self): + cell_id = c_int32() + _dll.openmc_cell_id(self._index, cell_id) + return cell_id.value + + def set_temperature(self, T, instance=None): + """Set the temperature of a cell + + Parameters + ---------- + T : float + Temperature in K + instance : int or None + Which instance of the cell + + """ + _dll.openmc_cell_set_temperature(self._index, T, instance) + + +class _CellMapping(Mapping): + def __getitem__(self, key): + index = c_int32() + _dll.openmc_get_cell(key, index) + return CellView(index.value) + + def __iter__(self): + for i in range(len(self)): + yield CellView(i + 1).id + + def __len__(self): + return c_int32.in_dll(_dll, 'n_cells').value + +cells = _CellMapping() diff --git a/openmc/capi/tally.py b/openmc/capi/tally.py new file mode 100644 index 000000000..f60d94e92 --- /dev/null +++ b/openmc/capi/tally.py @@ -0,0 +1,71 @@ +from collections import Mapping +from ctypes import c_int, c_int32, c_double, c_char_p, POINTER +from weakref import WeakValueDictionary + +from numpy.ctypeslib import as_array + +from openmc.capi import _dll, _error_handler, NuclideView + + +__all__ = ['TallyView', 'tallies'] + +# Tally functions +_dll.openmc_get_tally.argtypes = [c_int32, POINTER(c_int32)] +_dll.openmc_get_tally.restype = c_int +_dll.openmc_get_tally.errcheck = _error_handler +_dll.openmc_tally_id.argtypes = [c_int32, POINTER(c_int32)] +_dll.openmc_tally_id.restype = c_int +_dll.openmc_tally_id.errcheck = _error_handler +_dll.openmc_tally_results.argtypes = [ + c_int32, POINTER(POINTER(c_double)), POINTER(c_int*3)] +_dll.openmc_tally_results.restype = c_int +_dll.openmc_tally_results.errcheck = _error_handler + + +class TallyView(object): + __instances = WeakValueDictionary() + def __new__(cls, *args): + if args not in cls.__instances: + instance = super().__new__(cls) + cls.__instances[args] = instance + return cls.__instances[args] + + def __init__(self, index): + self._index = index + + @property + def id(self): + tally_id = c_int32() + _dll.openmc_tally_id(self._index, tally_id) + return tally_id.value + + @property + def results(self): + """Get tally results array + + Returns + ------- + numpy.ndarray + Array that exposes the internal tally results array + + """ + data = POINTER(c_double)() + shape = (c_int*3)() + _dll.openmc_tally_results(self._index, data, shape) + return as_array(data, tuple(shape[::-1])) + + +class _TallyMapping(Mapping): + def __getitem__(self, key): + index = c_int32() + _dll.openmc_get_tally(key, index) + return TallyView(index.value) + + def __iter__(self): + for i in range(len(self)): + yield TallyView(i + 1).id + + def __len__(self): + return c_int32.in_dll(_dll, 'n_tallies').value + +tallies = _TallyMapping() diff --git a/src/api.F90 b/src/api.F90 index 0d4c50f41..6d50ca51e 100644 --- a/src/api.F90 +++ b/src/api.F90 @@ -23,12 +23,15 @@ module openmc_api private public :: openmc_calculate_volumes + public :: openmc_cell_id public :: openmc_cell_set_temperature public :: openmc_finalize public :: openmc_find + public :: openmc_get_cell public :: openmc_get_keff public :: openmc_get_material public :: openmc_get_nuclide + public :: openmc_get_tally public :: openmc_init public :: openmc_load_nuclide public :: openmc_material_id @@ -40,6 +43,7 @@ module openmc_api public :: openmc_plot_geometry public :: openmc_reset public :: openmc_run + public :: openmc_tally_id public :: openmc_tally_results ! Error codes @@ -58,12 +62,29 @@ module openmc_api contains +!=============================================================================== +! OPENMC_CELL_ID returns the ID of a cell +!=============================================================================== + + function openmc_cell_id(index, id) result(err) bind(C) + integer(C_INT32_T), value :: index + integer(C_INT32_T), intent(out) :: id + integer(C_INT) :: err + + if (index >= 1 .and. index <= size(cells)) then + id = cells(index) % id + err = 0 + else + err = E_OUT_OF_BOUNDS + end if + end function openmc_cell_id + !=============================================================================== ! OPENMC_CELL_SET_TEMPERATURE sets the temperature of a cell !=============================================================================== - function openmc_cell_set_temperature(id, T, instance) result(err) bind(C) - integer(C_INT32_T), value, intent(in) :: id ! id of cell + function openmc_cell_set_temperature(index, T, instance) result(err) bind(C) + integer(C_INT32_T), value, intent(in) :: index real(C_DOUBLE), value, intent(in) :: T integer(C_INT32_T), optional, intent(in) :: instance integer(C_INT) :: err @@ -71,28 +92,23 @@ contains integer :: i, n err = E_UNASSIGNED - if (allocated(cells)) then - if (cell_dict % has_key(id)) then - i = cell_dict % get_key(id) - associate (c => cells(i)) - if (allocated(c % sqrtkT)) then - n = size(c % sqrtkT) - if (present(instance) .and. n > 1) then - if (instance >= 0 .and. instance < n) then - c % sqrtkT(instance + 1) = sqrt(K_BOLTZMANN * T) - err = 0 - end if - else - c % sqrtkT(:) = sqrt(K_BOLTZMANN * T) + if (index >= 1 .and. index <= size(cells)) then + associate (c => cells(i)) + if (allocated(c % sqrtkT)) then + n = size(c % sqrtkT) + if (present(instance) .and. n > 1) then + if (instance >= 0 .and. instance < n) then + c % sqrtkT(instance + 1) = sqrt(K_BOLTZMANN * T) err = 0 end if + else + c % sqrtkT(:) = sqrt(K_BOLTZMANN * T) + err = 0 end if - end associate - else - err = E_CELL_INVALID_ID - end if + end if + end associate else - err = E_CELL_NOT_ALLOCATED + err = E_OUT_OF_BOUNDS end if end function openmc_cell_set_temperature @@ -226,6 +242,27 @@ contains end function openmc_find +!=============================================================================== +! OPENMC_GET_CELL returns the index in the cells array of a cell with a given ID +!=============================================================================== + + function openmc_get_cell(id, index) result(err) bind(C) + integer(C_INT32_T), value :: id + integer(C_INT32_T), intent(out) :: index + integer(C_INT) :: err + + if (allocated(cells)) then + if (cell_dict % has_key(id)) then + index = cell_dict % get_key(id) + err = 0 + else + err = E_CELL_INVALID_ID + end if + else + err = E_CELL_NOT_ALLOCATED + end if + end function openmc_get_cell + !=============================================================================== ! OPENMC_GET_MATERIAL returns the index in the materials array of a material ! with a given ID @@ -275,6 +312,28 @@ contains end if end function openmc_get_nuclide +!=============================================================================== +! OPENMC_GET_TALLY returns the index in the tallies array of a tally +! with a given ID +!=============================================================================== + + function openmc_get_tally(id, index) result(err) bind(C) + integer(C_INT32_T), value :: id + integer(C_INT32_T), intent(out) :: index + integer(C_INT) :: err + + if (allocated(tallies)) then + if (tally_dict % has_key(id)) then + index = tally_dict % get_key(id) + err = 0 + else + err = E_TALLY_INVALID_ID + end if + else + err = E_TALLY_NOT_ALLOCATED + end if + end function openmc_get_tally + !=============================================================================== ! OPENMC_LOAD_LOAD loads a nuclide from the cross section library !=============================================================================== @@ -581,35 +640,44 @@ contains end subroutine openmc_reset +!=============================================================================== +! OPENMC_TALLY_ID returns the ID of a tally +!=============================================================================== + + function openmc_tally_id(index, id) result(err) bind(C) + integer(C_INT32_T), value :: index + integer(C_INT32_T), intent(out) :: id + integer(C_INT) :: err + + if (index >= 1 .and. index <= size(tallies)) then + id = tallies(index) % id + err = 0 + else + err = E_OUT_OF_BOUNDS + end if + end function openmc_tally_id + !=============================================================================== ! OPENMC_TALLY_RESULTS returns a pointer to a tally results array along with its ! shape. This allows a user to obtain in-memory tally results from Python ! directly. !=============================================================================== - function openmc_tally_results(id, ptr, shape_) result(err) bind(C) - integer(C_INT32_T), intent(in), value :: id + function openmc_tally_results(index, ptr, shape_) result(err) bind(C) + integer(C_INT32_T), intent(in), value :: index type(C_PTR), intent(out) :: ptr integer(C_INT), intent(out) :: shape_(3) integer(C_INT) :: err - integer :: i - - ptr = C_NULL_PTR err = E_UNASSIGNED - if (allocated(tallies)) then - if (tally_dict % has_key(id)) then - i = tally_dict % get_key(id) - if (allocated(tallies(i) % results)) then - ptr = C_LOC(tallies(i) % results(1,1,1)) - shape_(:) = shape(tallies(i) % results) - err = 0 - end if - else - err = E_TALLY_INVALID_ID + if (index >= 1 .and. index <= size(tallies)) then + if (allocated(tallies(index) % results)) then + ptr = C_LOC(tallies(index) % results(1,1,1)) + shape_(:) = shape(tallies(index) % results) + err = 0 end if else - err = E_TALLY_NOT_ALLOCATED + err = E_OUT_OF_BOUNDS end if end function openmc_tally_results