diff --git a/CMakeLists.txt b/CMakeLists.txt index 381f0cd7b7..626aadae82 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -336,7 +336,7 @@ set_target_properties( add_custom_command(TARGET libopenmc POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy $ - ${CMAKE_CURRENT_SOURCE_DIR}/openmc/capi/$ + ${CMAKE_CURRENT_SOURCE_DIR}/openmc/lib/$ COMMENT "Copying libopenmc to Python module directory") #=============================================================================== diff --git a/docs/requirements-rtd.txt b/docs/requirements-rtd.txt index 15345247eb..7801c670f8 100644 --- a/docs/requirements-rtd.txt +++ b/docs/requirements-rtd.txt @@ -1,3 +1,4 @@ sphinx-numfig jupyter sphinxcontrib-katex +sphinxcontrib-svg2pdfconverter diff --git a/docs/source/capi/index.rst b/docs/source/capi/index.rst index 90bef1909c..0ce1c234d1 100644 --- a/docs/source/capi/index.rst +++ b/docs/source/capi/index.rst @@ -1,17 +1,17 @@ .. _capi: -===== -C API -===== +========= +C/C++ API +========= The libopenmc shared library that is built when installing OpenMC exports a number of C interoperable functions and global variables that can be used for -in-memory coupling. While it is possible to directly use the C API as documented -here for coupling, most advanced users will find it easier to work with the -Python bindings in the :py:mod:`openmc.capi` module. +in-memory coupling. While it is possible to directly use the C/C++ API as +documented here for coupling, most advanced users will find it easier to work +with the Python bindings in the :py:mod:`openmc.lib` module. -.. warning:: The C API is still experimental and may undergo substantial changes - in future releases. +.. warning:: The C/C++ API is still experimental and may undergo substantial + changes in future releases. ---------------- Type Definitions diff --git a/docs/source/conf.py b/docs/source/conf.py index a24f9b398a..55776b8f49 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -56,7 +56,7 @@ extensions = ['sphinx.ext.autodoc', 'sphinx_numfig', 'notebook_sphinxext'] if not on_rtd: - extensions.append('sphinx.ext.imgconverter') + extensions.append('sphinxcontrib.rsvgconverter') # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] diff --git a/docs/source/methods/photon_physics.rst b/docs/source/methods/photon_physics.rst index 4494fc6431..f9bdcfa1cc 100644 --- a/docs/source/methods/photon_physics.rst +++ b/docs/source/methods/photon_physics.rst @@ -579,7 +579,7 @@ sampled using the leading order term of the Sauter–Gluckstern–Hull distribution, .. math:: - :label: sauter–gluckstern–hull + :label: sauter-gluckstern-hull p(\mu_{\pm}) = C(1 - \beta_{\pm}\mu_{\pm})^{-2}, @@ -588,7 +588,7 @@ ratio of the velocity of the charged particle to the speed of light given in :eq:`beta-2`. The inverse transform method is used to sample :math:`\mu_{-}` and -:math:`\mu_{+}` from :eq:`sauter–gluckstern–hull`, using the sampling formula +:math:`\mu_{+}` from :eq:`sauter-gluckstern-hull`, using the sampling formula .. math:: :label: sample-mu diff --git a/docs/source/publications.rst b/docs/source/publications.rst index f33cf79587..32b911e5b8 100644 --- a/docs/source/publications.rst +++ b/docs/source/publications.rst @@ -58,7 +58,8 @@ Coupling and Multi-physics -------------------------- - Miriam A. Kreher, Benoit Forget, and Kord Smith, "Single-Batch Monte Carlo - Multiphysics Coupling," *Proc. M&C*, Portland, Oregon, Aug. 25-29 (2019). + Multiphysics Coupling," *Proc. M&C*, 1789-1797, Portland, Oregon, Aug. 25-29 + (2019). - Ze-Long Zhao, Yongwei Yang, and Shuang Hong, "`Application of FLUKA and OpenMC in coupled physics calculation of target and subcritical reactor for ADS @@ -118,7 +119,7 @@ Geometry and Visualization - Sterling Harper, Paul Romano, Benoit Forget, and Kord Smith, "Efficient dynamic threadsafe neighbor lists for Monte Carlo ray tracing," *Proc. M&C*, - Portland, Oregon, Aug. 25-29 (2019). + 918-926, Portland, Oregon, Aug. 25-29 (2019). - Jin-Yang Li, Long Gu, Hu-Shan Xu, Nadezha Korepanova, Rui Yu, Yan-Lei Zhu, and Chang-Ping Qin, "`CAD modeling study on FLUKA and OpenMC for accelerator @@ -141,6 +142,10 @@ Geometry and Visualization Miscellaneous ------------- +- Shikhar Kumar, Benoit Forget, and Kord Smith, "Analysis of fission source + convergence for a 3-D SMR core using functional expansion tallies," *Proc. + M&C*, 937-947, Portland, Oregon, Aug. 25-29 (2019). + - Faisal Qayyum, Muhammad R. Ali, Awais Zahur, and R. Khan, "`Improvements in methodology to determine feedback reactivity coefficients `_," *Nucl. Sci. Tech.*, **30**: 63 @@ -496,7 +501,7 @@ Depletion - Jose L. Salcedo-Perez, Benoit Forget, Kord Smith, and Paul Romano, "Hybrid tallies to improve performance in depletion Monte Carlo simulations," *Proc. - M&C*, Aug. 25-29 (2019). + M&C*, 927-936, Portland, Oregon, Aug. 25-29 (2019). - Zhao-Qing Liu, Ze-Long Zhao, Yong-Wei Yang, Yu-Cui Gao, Hai-Yan Meng, and Qing-Yu Gao, "`Development and validation of depletion code system IMPC-Burnup @@ -526,6 +531,10 @@ Depletion Sensitivity Analysis -------------------- +- Abdulla Alhajri and Benoit Forget, "Eigenvalue Sensitivity in Monte Carlo + Simulations to Nuclear Data Parameters using the Multipole Formalism," *Proc. + M&C*, 1895-1906, Portland, Oregon, Aug. 25-29 (2019). + - Xingjie Peng, Jingang Liang, Benoit Forget, and Kord Smith, "`Calculation of adjoint-weighted reactor kinetics parameters in OpenMC `_", *Ann. Nucl. Energy*, diff --git a/docs/source/pythonapi/capi.rst b/docs/source/pythonapi/capi.rst index cacc5472e1..44094ffd41 100644 --- a/docs/source/pythonapi/capi.rst +++ b/docs/source/pythonapi/capi.rst @@ -1,8 +1,8 @@ --------------------------------------------------- -:mod:`openmc.capi` -- Python bindings to the C API --------------------------------------------------- +------------------------------------------------------ +:mod:`openmc.lib` -- Python bindings to the C/C++ API +------------------------------------------------------ -.. automodule:: openmc.capi +.. automodule:: openmc.lib Functions --------- diff --git a/docs/source/releasenotes/0.11.0.rst b/docs/source/releasenotes/0.11.0.rst index 0bf44be3d4..170630ea72 100644 --- a/docs/source/releasenotes/0.11.0.rst +++ b/docs/source/releasenotes/0.11.0.rst @@ -17,7 +17,7 @@ This release of OpenMC adds several major new features: :ref:`depletion `, photon transport, and support for CAD geometries through DAGMC. In addition, the core codebase has been rewritten in C++14 (it was previously written in Fortran 2008). This makes compiling the code -cosiderably simpler as no Fortran compiler is needed. +considerably simpler as no Fortran compiler is needed. Functional expansion tallies are now supported through several new tally filters that can be arbitrarily combined: @@ -40,6 +40,7 @@ random, non-overlapping configuration of spheres within the region. New Features ------------ +- Support for rectilinear meshes through :class:`openmc.RectilinearMesh`. - The :class:`Geometry`, :class:`Materials`, and :class:`Settings` classes now have a ``from_xml`` method that will build an instance from an existing XML file. @@ -54,6 +55,34 @@ New Features - The :mod:`openmc.data` module now supports reading and sampling from ENDF File 32 resonance covariance data (`PR 1024 `_). +- Several new convenience functions/methods have been added: + + - The :func:`openmc.model.cylinder_from_points` function creates a cylinder + given two points passing through its center and a radius. + - The :meth:`openmc.Plane.from_points` function creates a plane given three + points that pass through it. + - The :func:`openmc.model.pin` function creates a pin cell universe given a + sequence of concentric cylinders and materials. + +------------------ +Python API Changes +------------------ + +- All surface classes now have coefficient arguments given as lowercase names. +- The order of arguments in surface classes has been changed so that + coefficients are the first arguments (rather than the optional surface ID). + This means you can now write:: + + x = openmc.XPlane(5.0, 'reflective') + zc = openmc.ZCylinder(0., 0., 10.) + +- The ``Mesh`` class has been renamed :class:`openmc.RegularMesh`. +- The ``get_rectangular_prism`` function has been renamed + :func:`openmc.model.rectangular_prism`. +- The ``get_hexagonal_prism`` function has been renamed + :func:`openmc.model.hexagonal_prism`. +- Python bindings to the C/C++ API have been move from ``openmc.capi`` to + :mod:`openmc.lib`. --------- Bug Fixes diff --git a/include/openmc/thermal.h b/include/openmc/thermal.h index a084c18884..cb6a7ce7bd 100644 --- a/include/openmc/thermal.h +++ b/include/openmc/thermal.h @@ -76,11 +76,6 @@ private: std::unique_ptr distribution; //!< Secondary angle-energy distribution }; - //! Upper threshold for incoherent inelastic scattering (usually ~4 eV) - double threshold_inelastic_; - //! Upper threshold for coherent/incoherent elastic scattering - double threshold_elastic_ {0.0}; - // Inelastic scattering data Reaction elastic_; Reaction inelastic_; diff --git a/openmc/__init__.py b/openmc/__init__.py index 1661c4ac47..1195db725e 100644 --- a/openmc/__init__.py +++ b/openmc/__init__.py @@ -34,4 +34,4 @@ from . import examples # Import a few convencience functions that used to be here from openmc.model import rectangular_prism, hexagonal_prism -__version__ = '0.10.0' +__version__ = '0.11.0-dev' diff --git a/openmc/cmfd.py b/openmc/cmfd.py index 742cdeabfd..b215d20584 100644 --- a/openmc/cmfd.py +++ b/openmc/cmfd.py @@ -22,7 +22,7 @@ import numpy as np from scipy import sparse import h5py -import openmc.capi +import openmc.lib from openmc.checkvalue import (check_type, check_length, check_value, check_greater_than, check_less_than) from openmc.exceptions import OpenMCError @@ -701,7 +701,7 @@ class CMFDRun(object): ---------- **kwargs All keyword arguments are passed to - :func:`openmc.capi.run_in_memory`. + :func:`openmc.lib.run_in_memory`. """ with self.run_in_memory(**kwargs): @@ -726,7 +726,7 @@ class CMFDRun(object): Parameters ---------- **kwargs - All keyword arguments passed to :func:`openmc.capi.run_in_memory`. + All keyword arguments passed to :func:`openmc.lib.run_in_memory`. """ # Store intracomm for part of CMFD routine where MPI reduce and @@ -737,7 +737,7 @@ class CMFDRun(object): self._intracomm = MPI.COMM_WORLD # Run and pass arguments to C API run_in_memory function - with openmc.capi.run_in_memory(**kwargs): + with openmc.lib.run_in_memory(**kwargs): self.init() yield self.finalize() @@ -759,7 +759,7 @@ class CMFDRun(object): def init(self): """ Initialize CMFDRun instance by setting up CMFD parameters and - calling :func:`openmc.capi.simulation_init` + calling :func:`openmc.lib.simulation_init` """ # Configure CMFD parameters and tallies @@ -780,10 +780,10 @@ class CMFDRun(object): self._initialize_linsolver() # Initialize simulation - openmc.capi.simulation_init() + openmc.lib.simulation_init() # Set cmfd_run variable to True through C API - openmc.capi.settings.cmfd_run = True + openmc.lib.settings.cmfd_run = True def next_batch(self): """ Run next batch for CMFDRun. @@ -799,29 +799,29 @@ class CMFDRun(object): self._cmfd_init_batch() # Run next batch - status = openmc.capi.next_batch() + status = openmc.lib.next_batch() # Perform CMFD calculation if on if self._cmfd_on: self._execute_cmfd() # Write CMFD output if CMFD on for current batch - if openmc.capi.master(): + if openmc.lib.master(): self._write_cmfd_output() # Write CMFD data to statepoint - if openmc.capi.is_statepoint_batch(): + if openmc.lib.is_statepoint_batch(): self.statepoint_write() return status def finalize(self): """ Finalize simulation by calling - :func:`openmc.capi.simulation_finalize` and print out CMFD timing + :func:`openmc.lib.simulation_finalize` and print out CMFD timing information. """ # Finalize simuation - openmc.capi.simulation_finalize() + openmc.lib.simulation_finalize() # Print out CMFD timing statistics self._write_cmfd_timing_stats() @@ -836,13 +836,13 @@ class CMFDRun(object): """ if filename is None: - batch_str_len = len(str(openmc.capi.settings.batches)) - batch_str = str(openmc.capi.current_batch()).zfill(batch_str_len) + batch_str_len = len(str(openmc.lib.settings.batches)) + batch_str = str(openmc.lib.current_batch()).zfill(batch_str_len) filename = 'statepoint.{}.h5'.format(batch_str) # Call C API statepoint_write to save source distribution with CMFD # feedback - openmc.capi.statepoint_write(filename=filename) + openmc.lib.statepoint_write(filename=filename) # Append CMFD data to statepoint file using h5py self._write_cmfd_statepoint(filename) @@ -856,10 +856,10 @@ class CMFDRun(object): Filename of statepoint """ - if openmc.capi.master(): + if openmc.lib.master(): with h5py.File(filename, 'a') as f: if 'cmfd' not in f: - if openmc.capi.settings.verbosity >= 5: + if openmc.lib.settings.verbosity >= 5: print(' Writing CMFD data to {}...'.format(filename)) sys.stdout.flush() cmfd_group = f.create_group("cmfd") @@ -922,7 +922,7 @@ class CMFDRun(object): args = temp_loss.indptr, len(temp_loss.indptr), \ temp_loss.indices, len(temp_loss.indices), n, \ self._spectral, self._indices, coremap - return openmc.capi._dll.openmc_initialize_linsolver(*args) + return openmc.lib._dll.openmc_initialize_linsolver(*args) def _write_cmfd_output(self): """Write CMFD output to buffer at the end of each batch""" @@ -948,7 +948,7 @@ class CMFDRun(object): def _write_cmfd_timing_stats(self): """Write CMFD timing stats to buffer after finalizing simulation""" - if openmc.capi.master(): + if openmc.lib.master(): outstr = ("=====================> " "CMFD TIMING STATISTICS <====================\n\n" " Time in CMFD = {:.5E} seconds\n" @@ -961,7 +961,7 @@ class CMFDRun(object): def _configure_cmfd(self): """Initialize CMFD parameters and set CMFD input variables""" # Check if restarting simulation from statepoint file - if not openmc.capi.settings.restart_run: + if not openmc.lib.settings.restart_run: # Read in cmfd input defined in Python self._read_cmfd_input() @@ -990,13 +990,13 @@ class CMFDRun(object): else: # Reset CMFD parameters from statepoint file - path_statepoint = openmc.capi.settings.path_statepoint + path_statepoint = openmc.lib.settings.path_statepoint self._reset_cmfd(path_statepoint) def _read_cmfd_input(self): """Sets values of additional instance variables based on user input""" # Print message to user and flush output to stdout - if openmc.capi.settings.verbosity >= 7 and openmc.capi.master(): + if openmc.lib.settings.verbosity >= 7 and openmc.lib.master(): print(' Configuring CMFD parameters for simulation') sys.stdout.flush() @@ -1010,7 +1010,7 @@ class CMFDRun(object): self._indices[i] = n # Check if in continuous energy mode - if not openmc.capi.settings.run_CE: + if not openmc.lib.settings.run_CE: raise OpenMCError('CMFD must be run in continuous energy mode') # Set number of energy groups @@ -1065,8 +1065,8 @@ class CMFDRun(object): 'file {}'.format(filename)) else: # Overwrite CMFD values from statepoint - if (openmc.capi.master() and - openmc.capi.settings.verbosity >= 5): + if (openmc.lib.master() and + openmc.lib.settings.verbosity >= 5): print(' Loading CMFD data from {}...'.format(filename)) sys.stdout.flush() cmfd_group = f['cmfd'] @@ -1126,7 +1126,7 @@ class CMFDRun(object): # Allocate dimensions for each mesh cell self._hxyz = np.zeros((nx, ny, nz, 3)) - self._hxyz[:] = openmc.capi.meshes[self._mesh_id].width + self._hxyz[:] = openmc.lib.meshes[self._mesh_id].width # Allocate flux, cross sections and diffusion coefficient self._flux = np.zeros((nx, ny, nz, ng)) @@ -1167,7 +1167,7 @@ class CMFDRun(object): """Handles CMFD options at the beginning of each batch""" # Get current batch through C API # Add 1 as next_batch has not been called yet - current_batch = openmc.capi.current_batch() + 1 + current_batch = openmc.lib.current_batch() + 1 # Check to activate CMFD diffusion and possible feedback # Check to activate CMFD tallies @@ -1182,7 +1182,7 @@ class CMFDRun(object): def _execute_cmfd(self): """Runs CMFD calculation on master node""" # Run CMFD on single processor on master - if openmc.capi.master(): + if openmc.lib.master(): # Start CMFD timer time_start_cmfd = time.time() @@ -1196,7 +1196,7 @@ class CMFDRun(object): self._k_cmfd.append(self._keff) # Check to perform adjoint on last batch - if (openmc.capi.current_batch() == openmc.capi.settings.batches + if (openmc.lib.current_batch() == openmc.lib.settings.batches and self._run_adjoint): self._cmfd_solver_execute(adjoint=True) @@ -1207,20 +1207,20 @@ class CMFDRun(object): self._cmfd_reweight(True) # Stop CMFD timer - if openmc.capi.master(): + if openmc.lib.master(): time_stop_cmfd = time.time() self._time_cmfd += time_stop_cmfd - time_start_cmfd def _cmfd_tally_reset(self): """Resets all CMFD tallies in memory""" # Print message - if (openmc.capi.settings.verbosity >= 6 and openmc.capi.master() and + if (openmc.lib.settings.verbosity >= 6 and openmc.lib.master() and not self._reset_every): print(' CMFD tallies reset') sys.stdout.flush() # Reset CMFD tallies - tallies = openmc.capi.tallies + tallies = openmc.lib.tallies for tally_id in self._tally_ids: tallies[tally_id].reset() @@ -1407,7 +1407,7 @@ class CMFDRun(object): self._cmfd_src = cmfd_src / np.sum(cmfd_src) # Compute entropy - if openmc.capi.settings.entropy_on: + if openmc.lib.settings.entropy_on: # Compute source times log_2(source) source = self._cmfd_src[self._cmfd_src > 0] \ * np.log(self._cmfd_src[self._cmfd_src > 0])/np.log(2) @@ -1441,12 +1441,12 @@ class CMFDRun(object): outside = self._count_bank_sites() # Check and raise error if source sites exist outside of CMFD mesh - if openmc.capi.master() and outside: + if openmc.lib.master() and outside: raise OpenMCError('Source sites outside of the CMFD mesh') # Have master compute weight factors, ignore any zeros in # sourcecounts or cmfd_src - if openmc.capi.master(): + if openmc.lib.master(): # Compute normalization factor norm = np.sum(self._sourcecounts) / np.sum(self._cmfd_src) @@ -1471,7 +1471,7 @@ class CMFDRun(object): dtype=np.float32)) if (not self._feedback - or openmc.capi.current_batch() < self._feedback_begin): + or openmc.lib.current_batch() < self._feedback_begin): return # Broadcast weight factors to all procs @@ -1479,13 +1479,13 @@ class CMFDRun(object): self._weightfactors = self._intracomm.bcast( self._weightfactors) - m = openmc.capi.meshes[self._mesh_id] + m = openmc.lib.meshes[self._mesh_id] energy = self._egrid ng = self._indices[3] # Get locations and energies of all particles in source bank - source_xyz = openmc.capi.source_bank()['r'] - source_energies = openmc.capi.source_bank()['E'] + source_xyz = openmc.lib.source_bank()['r'] + source_energies = openmc.lib.source_bank()['E'] # Convert xyz location to the CMFD mesh index mesh_ijk = np.floor((source_xyz-m.lower_left)/m.width).astype(int) @@ -1503,13 +1503,13 @@ class CMFDRun(object): # Determine weight factor of each particle based on its mesh index # and energy bin and updates its weight - openmc.capi.source_bank()['wgt'] *= self._weightfactors[ + openmc.lib.source_bank()['wgt'] *= self._weightfactors[ mesh_ijk[:,0], mesh_ijk[:,1], mesh_ijk[:,2], energy_bins] - if openmc.capi.master() and np.any(source_energies < energy[0]): + if openmc.lib.master() and np.any(source_energies < energy[0]): print(' WARNING: Source pt below energy grid') sys.stdout.flush() - if openmc.capi.master() and np.any(source_energies > energy[-1]): + if openmc.lib.master() and np.any(source_energies > energy[-1]): print(' WARNING: Source pt above energy grid') sys.stdout.flush() @@ -1523,8 +1523,8 @@ class CMFDRun(object): """ # Initialize variables - m = openmc.capi.meshes[self._mesh_id] - bank = openmc.capi.source_bank() + m = openmc.lib.meshes[self._mesh_id] + bank = openmc.lib.source_bank() energy = self._egrid sites_outside = np.zeros(1, dtype=bool) nxnynz = np.prod(self._indices[0:3]) @@ -1535,8 +1535,8 @@ class CMFDRun(object): count = np.zeros(self._sourcecounts.shape) # Get location and energy of each particle in source bank - source_xyz = openmc.capi.source_bank()['r'] - source_energies = openmc.capi.source_bank()['E'] + source_xyz = openmc.lib.source_bank()['r'] + source_energies = openmc.lib.source_bank()['E'] # Convert xyz location to mesh index and ravel index to scalar mesh_locations = np.floor((source_xyz - m.lower_left) / m.width) @@ -1760,7 +1760,7 @@ class CMFDRun(object): s_o = np.zeros((n,)) # Set initial guess - k_n = openmc.capi.keff()[0] + k_n = openmc.lib.keff()[0] k_o = k_n dw = self._w_shift k_s = k_o + dw @@ -1791,7 +1791,7 @@ class CMFDRun(object): s_o /= k_lo # Compute new flux with C++ solver - innerits = openmc.capi._dll.openmc_run_linsolver(loss.data, s_o, + innerits = openmc.lib._dll.openmc_run_linsolver(loss.data, s_o, phi_n, toli) # Compute new source vector @@ -1863,7 +1863,7 @@ class CMFDRun(object): iconv = kerr < self._cmfd_ktol and serr < self._stol # Print out to user - if self._power_monitor and openmc.capi.master(): + if self._power_monitor and openmc.lib.master(): str1 = ' {:d}:'.format(iter) str2 = 'k-eff: {:0.8f}'.format(k_n) str3 = 'k-error: {:.5E}'.format(kerr) @@ -1904,7 +1904,7 @@ class CMFDRun(object): """ # Update window size for expanding window if necessary - num_cmfd_batches = openmc.capi.current_batch() - self._tally_begin + 1 + num_cmfd_batches = openmc.lib.current_batch() - self._tally_begin + 1 if (self._window_type == 'expanding' and num_cmfd_batches == self._window_size * 2): self._window_size *= 2 @@ -1925,7 +1925,7 @@ class CMFDRun(object): nx, ny, nz, ng = self._indices # Get tallies in-memory - tallies = openmc.capi.tallies + tallies = openmc.lib.tallies # Ravel coremap as 1d array similar to how tally data is arranged coremap = np.ravel(self._coremap.swapaxes(0, 2)) @@ -2181,7 +2181,7 @@ class CMFDRun(object): num_accel = self._mat_dim # Get openmc k-effective - keff = openmc.capi.keff()[0] + keff = openmc.lib.keff()[0] # Define leakage in each mesh cell and energy group leakage = (((self._current[:,:,:,_CURRENTS['out_right'],:] - @@ -2973,7 +2973,7 @@ class CMFDRun(object): def _create_cmfd_tally(self): """Creates all tallies in-memory that are used to solve CMFD problem""" # Create Mesh object based on CMFDMesh, stored internally - cmfd_mesh = openmc.capi.RegularMesh() + cmfd_mesh = openmc.lib.RegularMesh() # Store id of mesh object self._mesh_id = cmfd_mesh.id # Set dimension and parameters of mesh object @@ -2983,29 +2983,29 @@ class CMFDRun(object): width=self._mesh.width) # Create mesh Filter object, stored internally - mesh_filter = openmc.capi.MeshFilter() + mesh_filter = openmc.lib.MeshFilter() # Set mesh for Mesh Filter mesh_filter.mesh = cmfd_mesh # Set up energy filters, if applicable if self._energy_filters: # Create Energy Filter object, stored internally - energy_filter = openmc.capi.EnergyFilter() + energy_filter = openmc.lib.EnergyFilter() # Set bins for Energy Filter energy_filter.bins = self._egrid # Create Energy Out Filter object, stored internally - energyout_filter = openmc.capi.EnergyoutFilter() + energyout_filter = openmc.lib.EnergyoutFilter() # Set bins for Energy Filter energyout_filter.bins = self._egrid # Create Mesh Surface Filter object, stored internally - meshsurface_filter = openmc.capi.MeshSurfaceFilter() + meshsurface_filter = openmc.lib.MeshSurfaceFilter() # Set mesh for Mesh Surface Filter meshsurface_filter.mesh = cmfd_mesh # Create Legendre Filter object, stored internally - legendre_filter = openmc.capi.LegendreFilter() + legendre_filter = openmc.lib.LegendreFilter() # Set order for Legendre Filter legendre_filter.order = 1 @@ -3013,7 +3013,7 @@ class CMFDRun(object): n_tallies = 4 self._tally_ids = [] for i in range(n_tallies): - cmfd_tally = openmc.capi.Tally() + cmfd_tally = openmc.lib.Tally() # Set nuclide bins cmfd_tally.nuclides = ['total'] self._tally_ids.append(cmfd_tally.id) diff --git a/openmc/data/neutron.py b/openmc/data/neutron.py index 9024b932e4..dfd44a4d07 100644 --- a/openmc/data/neutron.py +++ b/openmc/data/neutron.py @@ -834,6 +834,7 @@ class IncidentNeutron(EqualityMixin): non_fission_heating = Reaction(999) non_fission_heating.redundant = True fission_heating = Reaction(318) + fission_heating.redundant = True heatr_evals = get_evaluations(kwargs["heatr"]) for heatr in heatr_evals: @@ -841,15 +842,17 @@ class IncidentNeutron(EqualityMixin): f318 = StringIO(heatr.section[3, 318]) get_head_record(f318) _params, fission_kerma = get_tab1_record(f318) - fission_heating.xs[temp] = fission_kerma total_heating_xs = data.reactions[301].xs.get(temp) if total_heating_xs is None: + fission_heating.xs[temp] = fission_kerma continue + # Cast fission heating to same grid as total heating + new_fission_heat_xs = fission_kerma(total_heating_xs.x) + fission_heating.xs[temp] = Tabulated1D( + total_heating_xs.x, new_fission_heat_xs) non_fission_heating.xs[temp] = Tabulated1D( - fission_kerma.x, - total_heating_xs(fission_kerma.x) - fission_kerma.y, - breakpoints=fission_kerma.breakpoints, - interpolation=fission_kerma.interpolation) + total_heating_xs.x, + total_heating_xs.y - new_fission_heat_xs) data.reactions[318] = fission_heating data.reactions[999] = non_fission_heating diff --git a/openmc/deplete/abc.py b/openmc/deplete/abc.py index fb638e5c21..e0ed64645e 100644 --- a/openmc/deplete/abc.py +++ b/openmc/deplete/abc.py @@ -5,6 +5,7 @@ to run a full depletion simulation. """ from collections import namedtuple +from collections import defaultdict from collections.abc import Iterable import os from pathlib import Path @@ -17,7 +18,7 @@ from numpy import nonzero, empty, asarray from uncertainties import ufloat from openmc.data import DataLibrary, JOULE_PER_EV -from openmc.capi import MaterialFilter, Tally +from openmc.lib import MaterialFilter, Tally from openmc.checkvalue import check_type, check_greater_than from .results import Results from .chain import Chain @@ -376,14 +377,17 @@ class FissionYieldHelper(ABC): Attributes ---------- - constant_yields : dict of str to :class:`openmc.deplete.FissionYield` + constant_yields : collections.defaultdict Fission yields for all nuclides that only have one set of - fission yield data. Can be accessed as ``{parent: {product: yield}}`` + fission yield data. Dictionary of form ``{str: {str: float}}`` + representing yields for ``{parent: {product: yield}}``. Default + return object is an empty dictionary + """ def __init__(self, chain_nuclides): self._chain_nuclides = {} - self._constant_yields = {} + self._constant_yields = defaultdict(dict) # Get all nuclides with fission yield data for nuc in chain_nuclides: @@ -407,14 +411,16 @@ class FissionYieldHelper(ABC): Parameters ---------- local_mat_index : int - Index for material tracked on this process that - exists in :attr:`local_mat_index` and fits within - the first axis in :attr:`results` + Index for the material with requested fission yields. + Should correspond to the material represented in + ``mat_indexes[local_mat_index]`` during + :meth:`generate_tallies`. Returns ------- - library : dict - Dictionary of ``{parent: {product: fyield}}`` + library : collections.abc.Mapping + Dictionary-like object mapping ``{str: {str: float}``. + This reflects fission yields for ``{parent: {product: fyield}}``. """ @staticmethod @@ -438,7 +444,7 @@ class FissionYieldHelper(ABC): Parameters ---------- materials : iterable of C-API materials - Materials to be used in :class:`openmc.capi.MaterialFilter` + Materials to be used in :class:`openmc.lib.MaterialFilter` mat_indexes : iterable of int Indices of tallied materials that will have their fission yields computed by this helper. Necessary as the @@ -520,8 +526,8 @@ class TalliedFissionYieldHelper(FissionYieldHelper): Parameters ---------- - materials : iterable of :class:`openmc.capi.Material` - Materials to be used in :class:`openmc.capi.MaterialFilter` + materials : iterable of :class:`openmc.lib.Material` + Materials to be used in :class:`openmc.lib.MaterialFilter` mat_indexes : iterable of int Indices of tallied materials that will have their fission yields computed by this helper. Necessary as the diff --git a/openmc/deplete/chain.py b/openmc/deplete/chain.py index c2b5b75b31..510112c7c9 100644 --- a/openmc/deplete/chain.py +++ b/openmc/deplete/chain.py @@ -398,7 +398,7 @@ class Chain(object): clean_indentation(root_elem) tree.write(str(filename), encoding='utf-8') - def get_thermal_fission_yields(self): + def get_default_fission_yields(self): """Return fission yields at lowest incident neutron energy Used as the default set of fission yields for :meth:`form_matrix` @@ -412,7 +412,7 @@ class Chain(object): names of nuclides with yield data and ``f_yield`` is a float for the fission yield. """ - out = {} + out = defaultdict(dict) for nuc in self.nuclides: if nuc.yield_data is None: continue @@ -440,13 +440,13 @@ class Chain(object): See Also -------- - :meth:`get_thermal_fission_yields` + :meth:`get_default_fission_yields` """ matrix = defaultdict(float) reactions = set() if fission_yields is None: - fission_yields = self.get_thermal_fission_yields() + fission_yields = self.get_default_fission_yields() for i, nuc in enumerate(self.nuclides): @@ -721,7 +721,7 @@ class Chain(object): @property def fission_yields(self): if self._fission_yields is None: - self._fission_yields = [self.get_thermal_fission_yields()] + self._fission_yields = [self.get_default_fission_yields()] return self._fission_yields @fission_yields.setter diff --git a/openmc/deplete/helpers.py b/openmc/deplete/helpers.py index 56644a3bba..c50ffd6ab6 100644 --- a/openmc/deplete/helpers.py +++ b/openmc/deplete/helpers.py @@ -5,11 +5,12 @@ from copy import deepcopy from itertools import product from numbers import Real import bisect +from collections import defaultdict from numpy import dot, zeros, newaxis from openmc.checkvalue import check_type, check_greater_than -from openmc.capi import ( +from openmc.lib import ( Tally, MaterialFilter, EnergyFilter, EnergyFunctionFilter) from .abc import ( ReactionRateHelper, EnergyHelper, FissionYieldHelper, @@ -44,7 +45,7 @@ class DirectReactionRateHelper(ReactionRateHelper): def generate_tallies(self, materials, scores): """Produce one-group reaction rate tally - Uses the :mod:`openmc.capi` to generate a tally + Uses the :mod:`openmc.lib` to generate a tally of relevant reactions across all burnable materials. Parameters @@ -179,9 +180,11 @@ class ConstantFissionYieldHelper(FissionYieldHelper): Attributes ---------- - constant_yields : dict of str to :class:`openmc.deplete.FissionYield` + constant_yields : collections.defaultdict Fission yields for all nuclides that only have one set of - fission yield data. Can be accessed as ``{parent: {product: yield}}`` + fission yield data. Dictionary of form ``{str: {str: float}}`` + representing yields for ``{parent: {product: yield}}``. Default + return object is an empty dictionary energy : float Energy of fission yield libraries. """ @@ -237,7 +240,7 @@ class ConstantFissionYieldHelper(FissionYieldHelper): Returns ------- - library : dict + library : collections.defaultdict Dictionary of ``{parent: {product: fyield}}`` """ return self.constant_yields @@ -282,6 +285,11 @@ class FissionYieldCutoffHelper(TalliedFissionYieldHelper): fast_yields : dict Dictionary of the form ``{parent: {product: yield}}`` with fast yields + constant_yields : collections.defaultdict + Fission yields for all nuclides that only have one set of + fission yield data. Dictionary of form ``{str: {str: float}}`` + representing yields for ``{parent: {product: yield}}``. Default + return object is an empty dictionary results : numpy.ndarray Array of fission rate fractions with shape ``(n_mats, 2, n_nucs)``. ``results[:, 0]`` @@ -362,13 +370,13 @@ class FissionYieldCutoffHelper(TalliedFissionYieldHelper): def generate_tallies(self, materials, mat_indexes): """Use C API to produce a fission rate tally in burnable materials - Include a :class:`openmc.capi.EnergyFilter` to tally fission rates + Include a :class:`openmc.lib.EnergyFilter` to tally fission rates above and below cutoff energy. Parameters ---------- - materials : iterable of :class:`openmc.capi.Material` - Materials to be used in :class:`openmc.capi.MaterialFilter` + materials : iterable of :class:`openmc.lib.Material` + Materials to be used in :class:`openmc.lib.MaterialFilter` mat_indexes : iterable of int Indices of tallied materials that will have their fission yields computed by this helper. Necessary as the @@ -417,7 +425,7 @@ class FissionYieldCutoffHelper(TalliedFissionYieldHelper): Returns ------- - library : dict + library : collections.defaultdict Dictionary of ``{parent: {product: fyield}}`` """ yields = self.constant_yields @@ -469,9 +477,11 @@ class AveragedFissionYieldHelper(TalliedFissionYieldHelper): Attributes ---------- - constant_yields : dict of str to :class:`openmc.deplete.FissionYield` + constant_yields : collections.defaultdict Fission yields for all nuclides that only have one set of - fission yield data. Can be accessed as ``{parent: {product: yield}}`` + fission yield data. Dictionary of form ``{str: {str: float}}`` + representing yields for ``{parent: {product: yield}}``. Default + return object is an empty dictionary results : None or numpy.ndarray If tallies have been generated and unpacked, then the array will have shape ``(n_mats, n_tnucs)``, where ``n_mats`` is the number @@ -490,8 +500,8 @@ class AveragedFissionYieldHelper(TalliedFissionYieldHelper): Parameters ---------- - materials : iterable of :class:`openmc.capi.Material` - Materials to be used in :class:`openmc.capi.MaterialFilter` + materials : iterable of :class:`openmc.lib.Material` + Materials to be used in :class:`openmc.lib.MaterialFilter` mat_indexes : iterable of int Indices of tallied materials that will have their fission yields computed by this helper. Necessary as the @@ -569,12 +579,13 @@ class AveragedFissionYieldHelper(TalliedFissionYieldHelper): Returns ------- - library : dict - Dictionary of ``{parent: {product: fyield}}`` + library : collections.defaultdict + Dictionary of ``{parent: {product: fyield}}``. Default return + value is an empty dictionary """ if not self._tally_nucs: return self.constant_yields - mat_yields = {} + mat_yields = defaultdict(dict) average_energies = self.results[local_mat_index] for avg_e, nuc in zip(average_energies, self._tally_nucs): nuc_energies = nuc.yield_energies diff --git a/openmc/deplete/operator.py b/openmc/deplete/operator.py index 01bf92dcc9..86dbeb7550 100644 --- a/openmc/deplete/operator.py +++ b/openmc/deplete/operator.py @@ -19,7 +19,7 @@ import numpy as np from uncertainties import ufloat import openmc -import openmc.capi +import openmc.lib from . import comm from .abc import TransportOperator, OperatorResult from .atom_number import AtomNumber @@ -245,8 +245,8 @@ class Operator(TransportOperator): self._yield_helper.update_tally_nuclides(nuclides) # Run OpenMC - openmc.capi.reset() - openmc.capi.run() + openmc.lib.reset() + openmc.lib.run() time_openmc = time.time() @@ -264,7 +264,7 @@ class Operator(TransportOperator): step : int Current depletion step including restarts """ - openmc.capi.statepoint_write( + openmc.lib.statepoint_write( "openmc_simulation_n{}.h5".format(step), write_source=False) @@ -438,10 +438,10 @@ class Operator(TransportOperator): # Initialize OpenMC library comm.barrier() - openmc.capi.init(intracomm=comm) + openmc.lib.init(intracomm=comm) # Generate tallies in memory - materials = [openmc.capi.materials[int(i)] + materials = [openmc.lib.materials[int(i)] for i in self.burnable_mats] self._rate_helper.generate_tallies(materials, self.chain.reactions) self._energy_helper.prepare( @@ -456,7 +456,7 @@ class Operator(TransportOperator): def finalize(self): """Finalize a depletion simulation and release resources.""" - openmc.capi.finalize() + openmc.lib.finalize() def _update_materials(self): """Updates material compositions in OpenMC on all processes.""" @@ -491,7 +491,7 @@ class Operator(TransportOperator): number_i[mat, nuc] = 0.0 # Update densities on C API side - mat_internal = openmc.capi.materials[int(mat)] + mat_internal = openmc.lib.materials[int(mat)] mat_internal.set_densities(nuclides, densities) #TODO Update densities on the Python side, otherwise the @@ -581,7 +581,7 @@ class Operator(TransportOperator): rates.fill(0.0) # Get k and uncertainty - k_combined = ufloat(*openmc.capi.keff()) + k_combined = ufloat(*openmc.lib.keff()) # Extract tally bins nuclides = self._rate_helper.nuclides diff --git a/openmc/capi/__init__.py b/openmc/lib/__init__.py similarity index 69% rename from openmc/capi/__init__.py rename to openmc/lib/__init__.py index 5ca867d67e..92fd1730d3 100644 --- a/openmc/capi/__init__.py +++ b/openmc/lib/__init__.py @@ -1,14 +1,14 @@ """ -This module provides bindings to C functions defined by OpenMC shared library. -When the :mod:`openmc` package is imported, the OpenMC shared library is -automatically loaded. Calls to the OpenMC library can then be via functions or -objects in the :mod:`openmc.capi` subpackage, for example: +This module provides bindings to C/C++ functions defined by OpenMC shared +library. When the :mod:`openmc.lib` package is imported, the OpenMC shared +library is automatically loaded. Calls to the OpenMC library can then be via +functions or objects in :mod:`openmc.lib`, for example: .. code-block:: python - openmc.capi.init() - openmc.capi.run() - openmc.capi.finalize() + openmc.lib.init() + openmc.lib.run() + openmc.lib.finalize() """ @@ -33,7 +33,7 @@ if os.environ.get('READTHEDOCS', None) != 'True': else: # For documentation builds, we don't actually have the shared library # available. Instead, we create a mock object so that when the modules - # within the openmc.capi package try to configure arguments and return + # within the openmc.lib package try to configure arguments and return # values for symbols, no errors occur from unittest.mock import Mock _dll = Mock() diff --git a/openmc/capi/cell.py b/openmc/lib/cell.py similarity index 99% rename from openmc/capi/cell.py rename to openmc/lib/cell.py index 784ebd087b..6ed4bca1ea 100644 --- a/openmc/capi/cell.py +++ b/openmc/lib/cell.py @@ -63,7 +63,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.cells` mapping. + :data:`openmc.lib.cells` mapping. Parameters ---------- diff --git a/openmc/capi/core.py b/openmc/lib/core.py similarity index 94% rename from openmc/capi/core.py rename to openmc/lib/core.py index a470f0665b..0bfdb457b4 100644 --- a/openmc/capi/core.py +++ b/openmc/lib/core.py @@ -11,7 +11,7 @@ from numpy.ctypeslib import as_array from openmc.exceptions import AllocationError from . import _dll from .error import _error_handler -import openmc.capi +import openmc.lib class _Bank(Structure): @@ -127,7 +127,7 @@ def find_cell(xyz): Returns ------- - openmc.capi.Cell + openmc.lib.Cell Cell containing the point int If the cell at the given point is repeated in the geometry, this @@ -137,7 +137,7 @@ def find_cell(xyz): index = c_int32() instance = c_int32() _dll.openmc_find_cell((c_double*3)(*xyz), index, instance) - return openmc.capi.Cell(index=index.value), instance.value + return openmc.lib.Cell(index=index.value), instance.value def find_material(xyz): @@ -150,7 +150,7 @@ def find_material(xyz): Returns ------- - openmc.capi.Material or None + openmc.lib.Material or None Material containing the point, or None is no material is found """ @@ -158,8 +158,8 @@ def find_material(xyz): instance = c_int32() _dll.openmc_find_cell((c_double*3)(*xyz), index, instance) - mats = openmc.capi.Cell(index=index.value).fill - if isinstance(mats, (openmc.capi.Material, type(None))): + mats = openmc.lib.Cell(index=index.value).fill + if isinstance(mats, (openmc.lib.Material, type(None))): return mats else: return mats[instance.value] @@ -225,21 +225,21 @@ def iter_batches(): This function returns a generator-iterator that allows Python code to be run between batches in an OpenMC simulation. It should be used in conjunction - with :func:`openmc.capi.simulation_init` and - :func:`openmc.capi.simulation_finalize`. For example: + with :func:`openmc.lib.simulation_init` and + :func:`openmc.lib.simulation_finalize`. For example: .. code-block:: Python - with openmc.capi.run_in_memory(): - openmc.capi.simulation_init() - for _ in openmc.capi.iter_batches(): + with openmc.lib.run_in_memory(): + openmc.lib.simulation_init() + for _ in openmc.lib.iter_batches(): # Look at convergence of tallies, for example ... - openmc.capi.simulation_finalize() + openmc.lib.simulation_finalize() See Also -------- - openmc.capi.next_batch + openmc.lib.next_batch """ while True: @@ -365,11 +365,11 @@ def run_in_memory(**kwargs): block, all memory that was allocated during the block is freed. For example:: - with openmc.capi.run_in_memory(): + with openmc.lib.run_in_memory(): for i in range(n_iters): - openmc.capi.reset() + openmc.lib.reset() do_stuff() - openmc.capi.run() + openmc.lib.run() Parameters ---------- diff --git a/openmc/capi/error.py b/openmc/lib/error.py similarity index 100% rename from openmc/capi/error.py rename to openmc/lib/error.py diff --git a/openmc/capi/filter.py b/openmc/lib/filter.py similarity index 100% rename from openmc/capi/filter.py rename to openmc/lib/filter.py diff --git a/openmc/capi/material.py b/openmc/lib/material.py similarity index 99% rename from openmc/capi/material.py rename to openmc/lib/material.py index f0ecac7610..0fbce72458 100644 --- a/openmc/capi/material.py +++ b/openmc/lib/material.py @@ -66,7 +66,7 @@ class Material(_FortranObjectWithID): This class exposes a material that is stored internally in the OpenMC library. To obtain a view of a material with a given ID, use the - :data:`openmc.capi.materials` mapping. + :data:`openmc.lib.materials` mapping. Parameters ---------- diff --git a/openmc/capi/math.py b/openmc/lib/math.py similarity index 100% rename from openmc/capi/math.py rename to openmc/lib/math.py diff --git a/openmc/capi/mesh.py b/openmc/lib/mesh.py similarity index 99% rename from openmc/capi/mesh.py rename to openmc/lib/mesh.py index a1161f48f3..bf51bdfe98 100644 --- a/openmc/capi/mesh.py +++ b/openmc/lib/mesh.py @@ -50,7 +50,7 @@ class RegularMesh(_FortranObjectWithID): 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. + :data:`openmc.lib.meshes` mapping. Parameters ---------- diff --git a/openmc/capi/nuclide.py b/openmc/lib/nuclide.py similarity index 98% rename from openmc/capi/nuclide.py rename to openmc/lib/nuclide.py index 4a21a6d2b4..81ef7e648e 100644 --- a/openmc/capi/nuclide.py +++ b/openmc/lib/nuclide.py @@ -43,7 +43,7 @@ class Nuclide(_FortranObject): This class exposes a nuclide that is stored internally in the OpenMC solver. To obtain a view of a nuclide with a given name, use the - :data:`openmc.capi.nuclides` mapping. + :data:`openmc.lib.nuclides` mapping. Parameters ---------- diff --git a/openmc/capi/plot.py b/openmc/lib/plot.py similarity index 97% rename from openmc/capi/plot.py rename to openmc/lib/plot.py index c4bff4cb3f..c51000e0de 100644 --- a/openmc/capi/plot.py +++ b/openmc/lib/plot.py @@ -52,9 +52,9 @@ class _PlotBase(Structure): C-Type Attributes ----------------- - origin : openmc.capi.plot._Position + origin : openmc.lib.plot._Position A position defining the origin of the plot. - width_ : openmc.capi.plot._Position + 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. @@ -222,7 +222,7 @@ def id_map(plot): Parameters ---------- - plot : openmc.capi.plot._PlotBase + plot : openmc.lib.plot._PlotBase Object describing the slice of the model to be generated Returns @@ -250,7 +250,7 @@ def property_map(plot): Parameters ---------- - plot : openmc.capi.plot._PlotBase + plot : openmc.lib.plot._PlotBase Object describing the slice of the model to be generated Returns diff --git a/openmc/capi/settings.py b/openmc/lib/settings.py similarity index 100% rename from openmc/capi/settings.py rename to openmc/lib/settings.py diff --git a/openmc/capi/tally.py b/openmc/lib/tally.py similarity index 99% rename from openmc/capi/tally.py rename to openmc/lib/tally.py index 88c14e4494..0001b2c4b6 100644 --- a/openmc/capi/tally.py +++ b/openmc/lib/tally.py @@ -143,7 +143,7 @@ class Tally(_FortranObjectWithID): This class exposes a tally that is stored internally in the OpenMC library. To obtain a view of a tally with a given ID, use the - :data:`openmc.capi.tallies` mapping. + :data:`openmc.lib.tallies` mapping. Parameters ---------- diff --git a/openmc/mesh.py b/openmc/mesh.py index 4186b56a88..0a8b51c5f6 100644 --- a/openmc/mesh.py +++ b/openmc/mesh.py @@ -350,18 +350,14 @@ class RegularMesh(MeshBase): n_dim = len(self.dimension) # Build the cell which will contain the lattice - xplanes = [openmc.XPlane(x0=self.lower_left[0], - boundary_type=bc[0]), - openmc.XPlane(x0=self.upper_right[0], - boundary_type=bc[1])] + xplanes = [openmc.XPlane(self.lower_left[0], bc[0]), + openmc.XPlane(self.upper_right[0], bc[1])] if n_dim == 1: - yplanes = [openmc.YPlane(y0=-1e10, boundary_type='reflective'), - openmc.YPlane(y0=1e10, boundary_type='reflective')] + yplanes = [openmc.YPlane(-1e10, 'reflective'), + openmc.YPlane(1e10, 'reflective')] else: - yplanes = [openmc.YPlane(y0=self.lower_left[1], - boundary_type=bc[2]), - openmc.YPlane(y0=self.upper_right[1], - boundary_type=bc[3])] + yplanes = [openmc.YPlane(self.lower_left[1], bc[2]), + openmc.YPlane(self.upper_right[1], bc[3])] if n_dim <= 2: # Would prefer to have the z ranges be the max supported float, but @@ -371,13 +367,11 @@ class RegularMesh(MeshBase): # inconsistency between what numpy uses as the max float and what # Fortran expects for a real(8), so this avoids code complication # and achieves the same goal. - zplanes = [openmc.ZPlane(z0=-1e10, boundary_type='reflective'), - openmc.ZPlane(z0=1e10, boundary_type='reflective')] + zplanes = [openmc.ZPlane(-1e10, 'reflective'), + openmc.ZPlane(1e10, 'reflective')] else: - zplanes = [openmc.ZPlane(z0=self.lower_left[2], - boundary_type=bc[4]), - openmc.ZPlane(z0=self.upper_right[2], - boundary_type=bc[5])] + zplanes = [openmc.ZPlane(self.lower_left[2], bc[4]), + openmc.ZPlane(self.upper_right[2], bc[5])] root_cell = openmc.Cell() root_cell.region = ((+xplanes[0] & -xplanes[1]) & (+yplanes[0] & -yplanes[1]) & diff --git a/openmc/mgxs/mgxs.py b/openmc/mgxs/mgxs.py index 46b0048385..e9fee5a2f1 100644 --- a/openmc/mgxs/mgxs.py +++ b/openmc/mgxs/mgxs.py @@ -3552,7 +3552,7 @@ class ScatterMatrixXS(MatrixMGXS): .. math:: \begin{aligned} - \langle \sigma}_{s,\ell,g'\rightarrow g} \phi \rangle &= \int_{r \in V} dr + \langle \sigma_{s,\ell,g'\rightarrow g} \phi \rangle &= \int_{r \in V} dr \int_{4\pi} d\Omega' \int_{E_{g'}}^{E_{g'-1}} dE' \int_{4\pi} d\Omega \int_{E_g}^{E_{g-1}} dE \; P_\ell (\Omega \cdot \Omega') \sigma_s (r, E' \rightarrow E, \Omega' \cdot \Omega) \psi(r, E', \Omega')\\ diff --git a/openmc/model/funcs.py b/openmc/model/funcs.py index bb5d39a2d9..3ee5052402 100644 --- a/openmc/model/funcs.py +++ b/openmc/model/funcs.py @@ -253,8 +253,8 @@ def hexagonal_prism(edge_length=1., orientation='y', origin=(0., 0.), x, y = origin if orientation == 'y': - right = XPlane(x0=x + sqrt(3.)/2*l, boundary_type=boundary_type) - left = XPlane(x0=x - sqrt(3.)/2*l, boundary_type=boundary_type) + right = XPlane(x + sqrt(3.)/2*l, boundary_type) + left = XPlane(x - sqrt(3.)/2*l, boundary_type) c = sqrt(3.)/3. # y = -x/sqrt(3) + a diff --git a/openmc/model/model.py b/openmc/model/model.py index 2f515ca78f..33a38ef224 100644 --- a/openmc/model/model.py +++ b/openmc/model/model.py @@ -147,7 +147,7 @@ class Model(object): """ # Import the depletion module. This is done here rather than the module - # header to delay importing openmc.capi (through openmc.deplete) which + # header to delay importing openmc.lib (through openmc.deplete) which # can be tough to install properly. import openmc.deplete as dep diff --git a/openmc/polynomial.py b/openmc/polynomial.py index ac1ad675d6..abcfd8057e 100644 --- a/openmc/polynomial.py +++ b/openmc/polynomial.py @@ -73,9 +73,9 @@ class ZernikeRadial(Polynomial): return self._order def __call__(self, r): - import openmc.capi as capi + import openmc.lib as lib if isinstance(r, Iterable): - return [np.sum(self._norm_coef * capi.calc_zn_rad(self.order, r_i)) + return [np.sum(self._norm_coef * lib.calc_zn_rad(self.order, r_i)) for r_i in r] else: - return np.sum(self._norm_coef * capi.calc_zn_rad(self.order, r)) + return np.sum(self._norm_coef * lib.calc_zn_rad(self.order, r)) diff --git a/openmc/region.py b/openmc/region.py index d12ae7112a..a751e1ebf2 100644 --- a/openmc/region.py +++ b/openmc/region.py @@ -527,10 +527,10 @@ class Complement(Region): The Complement of an existing :class:`openmc.Region` can be created by using the ~ operator as the following example demonstrates: - >>> xl = openmc.XPlane(x0=-10.0) - >>> xr = openmc.XPlane(x0=10.0) - >>> yl = openmc.YPlane(y0=-10.0) - >>> yr = openmc.YPlane(y0=10.0) + >>> xl = openmc.XPlane(-10.0) + >>> xr = openmc.XPlane(10.0) + >>> yl = openmc.YPlane(-10.0) + >>> yr = openmc.YPlane(10.0) >>> inside_box = +xl & -xr & +yl & -yr >>> outside_box = ~inside_box >>> type(outside_box) diff --git a/openmc/surface.py b/openmc/surface.py deleted file mode 100644 index ec5b833048..0000000000 --- a/openmc/surface.py +++ /dev/null @@ -1,2265 +0,0 @@ -from abc import ABCMeta, abstractmethod -from collections import OrderedDict -from copy import deepcopy -from numbers import Real, Integral -from xml.etree import ElementTree as ET -from warnings import warn - -import numpy as np - -from openmc.checkvalue import check_type, check_value -from openmc.region import Region, Intersection, Union -from openmc.mixin import IDManagerMixin - - -_BOUNDARY_TYPES = ['transmission', 'vacuum', 'reflective', 'periodic', 'white'] - -_WARNING_UPPER = """\ -"{}(...) accepts an argument named '{}', not '{}'. Future versions of OpenMC \ -will not accept the capitalized version.\ -""" - - -class Surface(IDManagerMixin, metaclass=ABCMeta): - """An implicit surface with an associated boundary condition. - - An implicit surface is defined as the set of zeros of a function of the - three Cartesian coordinates. Surfaces in OpenMC are limited to a set of - algebraic surfaces, i.e., surfaces that are polynomial in x, y, and z. - - Parameters - ---------- - surface_id : int, optional - Unique identifier for the surface. If not specified, an identifier will - automatically be assigned. - boundary_type : {'transmission, 'vacuum', 'reflective', 'periodic', 'white'}, optional - Boundary condition that defines the behavior for particles hitting the - surface. Defaults to transmissive boundary condition where particles - freely pass through the surface. Note that periodic boundary conditions - can only be applied to x-, y-, and z-planes, and only axis-aligned - periodicity is supported. - name : str, optional - Name of the surface. If not specified, the name will be the empty - string. - - Attributes - ---------- - boundary_type : {'transmission, 'vacuum', 'reflective', 'periodic'} - Boundary condition that defines the behavior for particles hitting the - surface. - coefficients : dict - Dictionary of surface coefficients - id : int - Unique identifier for the surface - name : str - Name of the surface - type : str - Type of the surface - - """ - - next_id = 1 - used_ids = set() - - def __init__(self, surface_id=None, boundary_type='transmission', name=''): - self.id = surface_id - self.name = name - self.boundary_type = boundary_type - - # A dictionary of the quadratic surface coefficients - # Key - coefficient name - # Value - coefficient value - self._coefficients = {} - - def __neg__(self): - return Halfspace(self, '-') - - def __pos__(self): - return Halfspace(self, '+') - - def __repr__(self): - string = 'Surface\n' - string += '{0: <16}{1}{2}\n'.format('\tID', '=\t', self._id) - string += '{0: <16}{1}{2}\n'.format('\tName', '=\t', self._name) - string += '{0: <16}{1}{2}\n'.format('\tType', '=\t', self._type) - string += '{0: <16}{1}{2}\n'.format('\tBoundary', '=\t', self._boundary_type) - - coefficients = '{0: <16}'.format('\tCoefficients') + '\n' - - for coeff in self._coefficients: - coefficients += '{0: <16}{1}{2}\n'.format( - coeff, '=\t', self._coefficients[coeff]) - - string += coefficients - - return string - - @property - def name(self): - return self._name - - @property - def type(self): - return self._type - - @property - def boundary_type(self): - return self._boundary_type - - @property - def coefficients(self): - return self._coefficients - - @name.setter - def name(self, name): - if name is not None: - check_type('surface name', name, str) - self._name = name - else: - self._name = '' - - @boundary_type.setter - def boundary_type(self, boundary_type): - check_type('boundary type', boundary_type, str) - check_value('boundary type', boundary_type, _BOUNDARY_TYPES) - self._boundary_type = boundary_type - - def bounding_box(self, side): - """Determine an axis-aligned bounding box. - - An axis-aligned bounding box for surface half-spaces is represented by - its lower-left and upper-right coordinates. If the half-space is - unbounded in a particular direction, numpy.inf is used to represent - infinity. - - Parameters - ---------- - side : {'+', '-'} - Indicates the negative or positive half-space - - Returns - ------- - numpy.ndarray - Lower-left coordinates of the axis-aligned bounding box for the - desired half-space - numpy.ndarray - Upper-right coordinates of the axis-aligned bounding box for the - desired half-space - - """ - return (np.array([-np.inf, -np.inf, -np.inf]), - np.array([np.inf, np.inf, np.inf])) - - def clone(self, memo=None): - """Create a copy of this surface with a new unique ID. - - Parameters - ---------- - memo : dict or None - A nested dictionary of previously cloned objects. This parameter - is used internally and should not be specified by the user. - - Returns - ------- - clone : openmc.Surface - The clone of this surface - - """ - - if memo is None: - memo = {} - - # If no nemoize'd clone exists, instantiate one - if self not in memo: - clone = deepcopy(self) - clone.id = None - - # Memoize the clone - memo[self] = clone - - return memo[self] - - @abstractmethod - def evaluate(self, point): - pass - - @abstractmethod - def translate(self, vector): - pass - - def to_xml_element(self): - """Return XML representation of the surface - - Returns - ------- - element : xml.etree.ElementTree.Element - XML element containing source data - - """ - element = ET.Element("surface") - element.set("id", str(self._id)) - - if len(self._name) > 0: - element.set("name", str(self._name)) - - element.set("type", self._type) - if self.boundary_type != 'transmission': - element.set("boundary", self.boundary_type) - element.set("coeffs", ' '.join([str(self._coefficients.setdefault(key, 0.0)) - for key in self._coeff_keys])) - - return element - - @staticmethod - def from_xml_element(elem): - """Generate surface from an XML element - - Parameters - ---------- - elem : xml.etree.ElementTree.Element - XML element - - Returns - ------- - openmc.Surface - Instance of a surface subclass - - """ - - # Determine appropriate class - surf_type = elem.get('type') - surface_classes = { - 'plane': Plane, - 'x-plane': XPlane, - 'y-plane': YPlane, - 'z-plane': ZPlane, - 'x-cylinder': XCylinder, - 'y-cylinder': YCylinder, - 'z-cylinder': ZCylinder, - 'sphere': Sphere, - 'x-cone': XCone, - 'y-cone': YCone, - 'z-cone': ZCone, - 'quadric': Quadric, - } - cls = surface_classes[surf_type] - - # Determine ID, boundary type, coefficients - kwargs = {} - kwargs['surface_id'] = int(elem.get('id')) - kwargs['boundary_type'] = elem.get('boundary', 'transmission') - coeffs = [float(x) for x in elem.get('coeffs').split()] - kwargs.update(dict(zip(cls._coeff_keys, coeffs))) - - return cls(**kwargs) - - @staticmethod - def from_hdf5(group): - """Create surface from HDF5 group - - Parameters - ---------- - group : h5py.Group - Group in HDF5 file - - Returns - ------- - openmc.Surface - Instance of surface subclass - - """ - surface_id = int(group.name.split('/')[-1].lstrip('surface ')) - name = group['name'][()].decode() if 'name' in group else '' - surf_type = group['type'][()].decode() - bc = group['boundary_type'][()].decode() - coeffs = group['coefficients'][...] - - # Create the Surface based on its type - if surf_type == 'x-plane': - x0 = coeffs[0] - surface = XPlane(surface_id, bc, x0, name) - - elif surf_type == 'y-plane': - y0 = coeffs[0] - surface = YPlane(surface_id, bc, y0, name) - - elif surf_type == 'z-plane': - z0 = coeffs[0] - surface = ZPlane(surface_id, bc, z0, name) - - elif surf_type == 'plane': - A, B, C, D = coeffs - surface = Plane(surface_id, bc, A, B, C, D, name) - - elif surf_type == 'x-cylinder': - y0, z0, r = coeffs - surface = XCylinder(surface_id, bc, y0, z0, r, name) - - elif surf_type == 'y-cylinder': - x0, z0, r = coeffs - surface = YCylinder(surface_id, bc, x0, z0, r, name) - - elif surf_type == 'z-cylinder': - x0, y0, r = coeffs - surface = ZCylinder(surface_id, bc, x0, y0, r, name) - - elif surf_type == 'sphere': - x0, y0, z0, r = coeffs - surface = Sphere(surface_id, bc, x0, y0, z0, r, name) - - elif surf_type in ['x-cone', 'y-cone', 'z-cone']: - x0, y0, z0, r2 = coeffs - if surf_type == 'x-cone': - surface = XCone(surface_id, bc, x0, y0, z0, r2, name) - elif surf_type == 'y-cone': - surface = YCone(surface_id, bc, x0, y0, z0, r2, name) - elif surf_type == 'z-cone': - surface = ZCone(surface_id, bc, x0, y0, z0, r2, name) - - elif surf_type == 'quadric': - a, b, c, d, e, f, g, h, j, k = coeffs - surface = Quadric(surface_id, bc, a, b, c, d, e, f, g, - h, j, k, name) - - return surface - - -class Plane(Surface): - """An arbitrary plane of the form :math:`Ax + By + Cz = D`. - - Parameters - ---------- - surface_id : int, optional - Unique identifier for the surface. If not specified, an identifier will - automatically be assigned. - boundary_type : {'transmission, 'vacuum', 'reflective'}, optional - Boundary condition that defines the behavior for particles hitting the - surface. Defaults to transmissive boundary condition where particles - freely pass through the surface. - a : float, optional - The 'A' parameter for the plane. Defaults to 1. - b : float, optional - The 'B' parameter for the plane. Defaults to 0. - c : float, optional - The 'C' parameter for the plane. Defaults to 0. - d : float, optional - The 'D' parameter for the plane. Defaults to 0. - name : str, optional - Name of the plane. If not specified, the name will be the empty string. - - Attributes - ---------- - a : float - The 'A' parameter for the plane - b : float - The 'B' parameter for the plane - c : float - The 'C' parameter for the plane - d : float - The 'D' parameter for the plane - boundary_type : {'transmission, 'vacuum', 'reflective'} - Boundary condition that defines the behavior for particles hitting the - surface. - periodic_surface : openmc.Surface - If a periodic boundary condition is used, the surface with which this - one is periodic with - coefficients : dict - Dictionary of surface coefficients - id : int - Unique identifier for the surface - name : str - Name of the surface - type : str - Type of the surface - - """ - - _type = 'plane' - _coeff_keys = ('a', 'b', 'c', 'd') - - def __init__(self, surface_id=None, boundary_type='transmission', - a=1., b=0., c=0., d=0., name='', **kwargs): - super().__init__(surface_id, boundary_type, name=name) - self._periodic_surface = None - self.a = a - self.b = b - self.c = c - self.d = d - for k, v in kwargs.items(): - if k in 'ABCD': - warn(_WARNING_UPPER.format(type(self).__name__, k.lower(), k), - FutureWarning) - setattr(self, k.lower(), v) - - @property - def a(self): - return self.coefficients['a'] - - @property - def b(self): - return self.coefficients['b'] - - @property - def c(self): - return self.coefficients['c'] - - @property - def d(self): - return self.coefficients['d'] - - @property - def periodic_surface(self): - return self._periodic_surface - - @a.setter - def a(self, a): - check_type('A coefficient', a, Real) - self._coefficients['a'] = a - - @b.setter - def b(self, b): - check_type('B coefficient', b, Real) - self._coefficients['b'] = b - - @c.setter - def c(self, c): - check_type('C coefficient', c, Real) - self._coefficients['c'] = c - - @d.setter - def d(self, d): - check_type('D coefficient', d, Real) - self._coefficients['d'] = d - - @periodic_surface.setter - def periodic_surface(self, periodic_surface): - check_type('periodic surface', periodic_surface, Plane) - self._periodic_surface = periodic_surface - periodic_surface._periodic_surface = self - - def evaluate(self, point): - """Evaluate the surface equation at a given point. - - Parameters - ---------- - point : 3-tuple of float - The Cartesian coordinates, :math:`(x',y',z')`, at which the surface - equation should be evaluated. - - Returns - ------- - float - :math:`Ax' + By' + Cz' - D` - - """ - - x, y, z = point - return self.a*x + self.b*y + self.c*z - self.d - - def translate(self, vector): - """Translate surface in given direction - - Parameters - ---------- - vector : iterable of float - Direction in which surface should be translated - - Returns - ------- - openmc.Plane - Translated surface - - """ - vx, vy, vz = vector - d = self.d + self.a*vx + self.b*vy + self.c*vz - if d == self.d: - return self - else: - return type(self)(a=self.a, b=self.b, c=self.c, d=d) - - def to_xml_element(self): - """Return XML representation of the surface - - Returns - ------- - element : xml.etree.ElementTree.Element - XML element containing source data - - """ - element = super().to_xml_element() - - # Add periodic surface pair information - if self.boundary_type == 'periodic': - if self.periodic_surface is not None: - element.set("periodic_surface_id", str(self.periodic_surface.id)) - return element - - @classmethod - def from_points(cls, p1, p2, p3, **kwargs): - """Return a plane given three points that pass through it. - - Parameters - ---------- - p1, p2, p3 : 3-tuples - Points that pass through the plane - kwargs : dict - Keyword arguments passed to the :class:`Plane` constructor - - Returns - ------- - Plane - Plane that passes through the three points - - """ - # Convert to numpy arrays - p1 = np.asarray(p1) - p2 = np.asarray(p2) - p3 = np.asarray(p3) - - # Find normal vector to plane by taking cross product of two vectors - # connecting p1->p2 and p1->p3 - n = np.cross(p2 - p1, p3 - p1) - - # The equation of the plane will by n·( - p1) = 0. Determine - # coefficients a, b, c, and d based on that - a, b, c = n - d = np.dot(n, p1) - return cls(a=a, b=b, c=c, d=d, **kwargs) - - -class XPlane(Plane): - """A plane perpendicular to the x axis of the form :math:`x - x_0 = 0` - - Parameters - ---------- - surface_id : int, optional - Unique identifier for the surface. If not specified, an identifier will - automatically be assigned. - boundary_type : {'transmission, 'vacuum', 'reflective', 'periodic', 'white'}, optional - Boundary condition that defines the behavior for particles hitting the - surface. Defaults to transmissive boundary condition where particles - freely pass through the surface. Only axis-aligned periodicity is - supported, i.e., x-planes can only be paired with x-planes. - x0 : float, optional - Location of the plane. Defaults to 0. - name : str, optional - Name of the plane. If not specified, the name will be the empty string. - - Attributes - ---------- - x0 : float - Location of the plane - boundary_type : {'transmission, 'vacuum', 'reflective', 'periodic', 'white'} - Boundary condition that defines the behavior for particles hitting the - surface. - periodic_surface : openmc.Surface - If a periodic boundary condition is used, the surface with which this - one is periodic with - coefficients : dict - Dictionary of surface coefficients - id : int - Unique identifier for the surface - name : str - Name of the surface - type : str - Type of the surface - - """ - - _type = 'x-plane' - _coeff_keys = ('x0',) - - def __init__(self, surface_id=None, boundary_type='transmission', - x0=0., name=''): - super().__init__(surface_id, boundary_type, name=name) - self.x0 = x0 - - @property - def x0(self): - return self.coefficients['x0'] - - @x0.setter - def x0(self, x0): - check_type('x0 coefficient', x0, Real) - self._coefficients['x0'] = x0 - - def bounding_box(self, side): - """Determine an axis-aligned bounding box. - - An axis-aligned bounding box for surface half-spaces is represented by - its lower-left and upper-right coordinates. For the x-plane surface, the - half-spaces are unbounded in their y- and z- directions. To represent - infinity, numpy.inf is used. - - Parameters - ---------- - side : {'+', '-'} - Indicates the negative or positive half-space - - Returns - ------- - numpy.ndarray - Lower-left coordinates of the axis-aligned bounding box for the - desired half-space - numpy.ndarray - Upper-right coordinates of the axis-aligned bounding box for the - desired half-space - - """ - - if side == '-': - return (np.array([-np.inf, -np.inf, -np.inf]), - np.array([self.x0, np.inf, np.inf])) - elif side == '+': - return (np.array([self.x0, -np.inf, -np.inf]), - np.array([np.inf, np.inf, np.inf])) - - def evaluate(self, point): - """Evaluate the surface equation at a given point. - - Parameters - ---------- - point : 3-tuple of float - The Cartesian coordinates, :math:`(x',y',z')`, at which the surface - equation should be evaluated. - - Returns - ------- - float - :math:`x' - x_0` - - """ - return point[0] - self.x0 - - def translate(self, vector): - """Translate surface in given direction - - Parameters - ---------- - vector : iterable of float - Direction in which surface should be translated - - Returns - ------- - openmc.XPlane - Translated surface - - """ - vx = vector[0] - if vx == 0: - return self - else: - return type(self)(x0=self.x0 + vx) - - -class YPlane(Plane): - """A plane perpendicular to the y axis of the form :math:`y - y_0 = 0` - - Parameters - ---------- - surface_id : int, optional - Unique identifier for the surface. If not specified, an identifier will - automatically be assigned. - boundary_type : {'transmission, 'vacuum', 'reflective', 'periodic', 'white'}, optional - Boundary condition that defines the behavior for particles hitting the - surface. Defaults to transmissive boundary condition where particles - freely pass through the surface. Only axis-aligned periodicity is - supported, i.e., x-planes can only be paired with x-planes. - y0 : float, optional - Location of the plane - name : str, optional - Name of the plane. If not specified, the name will be the empty string. - - Attributes - ---------- - y0 : float - Location of the plane - boundary_type : {'transmission, 'vacuum', 'reflective', 'periodic', 'white'} - Boundary condition that defines the behavior for particles hitting the - surface. - periodic_surface : openmc.Surface - If a periodic boundary condition is used, the surface with which this - one is periodic with - coefficients : dict - Dictionary of surface coefficients - id : int - Unique identifier for the surface - name : str - Name of the surface - type : str - Type of the surface - - """ - - _type = 'y-plane' - _coeff_keys = ('y0',) - - def __init__(self, surface_id=None, boundary_type='transmission', - y0=0., name=''): - # Initialize YPlane class attributes - super().__init__(surface_id, boundary_type, name=name) - self.y0 = y0 - - @property - def y0(self): - return self.coefficients['y0'] - - @y0.setter - def y0(self, y0): - check_type('y0 coefficient', y0, Real) - self._coefficients['y0'] = y0 - - def bounding_box(self, side): - """Determine an axis-aligned bounding box. - - An axis-aligned bounding box for surface half-spaces is represented by - its lower-left and upper-right coordinates. For the y-plane surface, the - half-spaces are unbounded in their x- and z- directions. To represent - infinity, numpy.inf is used. - - Parameters - ---------- - side : {'+', '-'} - Indicates the negative or positive half-space - - Returns - ------- - numpy.ndarray - Lower-left coordinates of the axis-aligned bounding box for the - desired half-space - numpy.ndarray - Upper-right coordinates of the axis-aligned bounding box for the - desired half-space - - """ - - if side == '-': - return (np.array([-np.inf, -np.inf, -np.inf]), - np.array([np.inf, self.y0, np.inf])) - elif side == '+': - return (np.array([-np.inf, self.y0, -np.inf]), - np.array([np.inf, np.inf, np.inf])) - - def evaluate(self, point): - """Evaluate the surface equation at a given point. - - Parameters - ---------- - point : 3-tuple of float - The Cartesian coordinates, :math:`(x',y',z')`, at which the surface - equation should be evaluated. - - Returns - ------- - float - :math:`y' - y_0` - - """ - return point[1] - self.y0 - - def translate(self, vector): - """Translate surface in given direction - - Parameters - ---------- - vector : iterable of float - Direction in which surface should be translated - - Returns - ------- - openmc.YPlane - Translated surface - - """ - vy = vector[1] - if vy == 0.0: - return self - else: - return type(self)(y0=self.y0 + vy) - - -class ZPlane(Plane): - """A plane perpendicular to the z axis of the form :math:`z - z_0 = 0` - - Parameters - ---------- - surface_id : int, optional - Unique identifier for the surface. If not specified, an identifier will - automatically be assigned. - boundary_type : {'transmission, 'vacuum', 'reflective', 'periodic', 'white'}, optional - Boundary condition that defines the behavior for particles hitting the - surface. Defaults to transmissive boundary condition where particles - freely pass through the surface. Only axis-aligned periodicity is - supported, i.e., x-planes can only be paired with x-planes. - z0 : float, optional - Location of the plane. Defaults to 0. - name : str, optional - Name of the plane. If not specified, the name will be the empty string. - - Attributes - ---------- - z0 : float - Location of the plane - boundary_type : {'transmission, 'vacuum', 'reflective', 'periodic', 'white'} - Boundary condition that defines the behavior for particles hitting the - surface. - periodic_surface : openmc.Surface - If a periodic boundary condition is used, the surface with which this - one is periodic with - coefficients : dict - Dictionary of surface coefficients - id : int - Unique identifier for the surface - name : str - Name of the surface - type : str - Type of the surface - - """ - - _type = 'z-plane' - _coeff_keys = ('z0',) - - def __init__(self, surface_id=None, boundary_type='transmission', - z0=0., name=''): - # Initialize ZPlane class attributes - super().__init__(surface_id, boundary_type, name=name) - self.z0 = z0 - - @property - def z0(self): - return self.coefficients['z0'] - - @z0.setter - def z0(self, z0): - check_type('z0 coefficient', z0, Real) - self._coefficients['z0'] = z0 - - def bounding_box(self, side): - """Determine an axis-aligned bounding box. - - An axis-aligned bounding box for surface half-spaces is represented by - its lower-left and upper-right coordinates. For the z-plane surface, the - half-spaces are unbounded in their x- and y- directions. To represent - infinity, numpy.inf is used. - - Parameters - ---------- - side : {'+', '-'} - Indicates the negative or positive half-space - - Returns - ------- - numpy.ndarray - Lower-left coordinates of the axis-aligned bounding box for the - desired half-space - numpy.ndarray - Upper-right coordinates of the axis-aligned bounding box for the - desired half-space - - """ - - if side == '-': - return (np.array([-np.inf, -np.inf, -np.inf]), - np.array([np.inf, np.inf, self.z0])) - elif side == '+': - return (np.array([-np.inf, -np.inf, self.z0]), - np.array([np.inf, np.inf, np.inf])) - - def evaluate(self, point): - """Evaluate the surface equation at a given point. - - Parameters - ---------- - point : 3-tuple of float - The Cartesian coordinates, :math:`(x',y',z')`, at which the surface - equation should be evaluated. - - Returns - ------- - float - :math:`z' - z_0` - - """ - return point[2] - self.z0 - - def translate(self, vector): - """Translate surface in given direction - - Parameters - ---------- - vector : iterable of float - Direction in which surface should be translated - - Returns - ------- - openmc.ZPlane - Translated surface - - """ - vz = vector[2] - if vz == 0.0: - return self - else: - return type(self)(z0=self.z0 + vz) - - -class Cylinder(Surface): - """A cylinder whose length is parallel to the x-, y-, or z-axis. - - Parameters - ---------- - surface_id : int, optional - Unique identifier for the surface. If not specified, an identifier will - automatically be assigned. - boundary_type : {'transmission, 'vacuum', 'reflective', 'white'}, optional - Boundary condition that defines the behavior for particles hitting the - surface. Defaults to transmissive boundary condition where particles - freely pass through the surface. - r : float, optional - Radius of the cylinder. Defaults to 1. - name : str, optional - Name of the cylinder. If not specified, the name will be the empty - string. - - Attributes - ---------- - r : float - Radius of the cylinder - boundary_type : {'transmission, 'vacuum', 'reflective', 'white'} - Boundary condition that defines the behavior for particles hitting the - surface. - coefficients : dict - Dictionary of surface coefficients - id : int - Unique identifier for the surface - name : str - Name of the surface - type : str - Type of the surface - - """ - def __init__(self, surface_id=None, boundary_type='transmission', - r=1., name=''): - super().__init__(surface_id, boundary_type, name=name) - self.r = r - - @property - def r(self): - return self.coefficients['r'] - - @r.setter - def r(self, r): - check_type('r coefficient', r, Real) - self._coefficients['r'] = r - - -class XCylinder(Cylinder): - """An infinite cylinder whose length is parallel to the x-axis of the form - :math:`(y - y_0)^2 + (z - z_0)^2 = r^2`. - - Parameters - ---------- - surface_id : int, optional - Unique identifier for the surface. If not specified, an identifier will - automatically be assigned. - boundary_type : {'transmission, 'vacuum', 'reflective', 'white'}, optional - Boundary condition that defines the behavior for particles hitting the - surface. Defaults to transmissive boundary condition where particles - freely pass through the surface. - y0 : float, optional - y-coordinate of the center of the cylinder. Defaults to 0. - z0 : float, optional - z-coordinate of the center of the cylinder. Defaults to 0. - r : float, optional - Radius of the cylinder. Defaults to 0. - name : str, optional - Name of the cylinder. If not specified, the name will be the empty - string. - - Attributes - ---------- - y0 : float - y-coordinate of the center of the cylinder - z0 : float - z-coordinate of the center of the cylinder - boundary_type : {'transmission, 'vacuum', 'reflective', 'white'} - Boundary condition that defines the behavior for particles hitting the - surface. - coefficients : dict - Dictionary of surface coefficients - id : int - Unique identifier for the surface - name : str - Name of the surface - type : str - Type of the surface - - """ - - _type = 'x-cylinder' - _coeff_keys = ('y0', 'z0', 'r') - - def __init__(self, surface_id=None, boundary_type='transmission', - y0=0., z0=0., r=1., name='', *, R=None): - if R is not None: - warn(_WARNING_UPPER.format(type(self).__name__, 'r', 'R'), FutureWarning) - r = R - super().__init__(surface_id, boundary_type, r, name=name) - self.y0 = y0 - self.z0 = z0 - - @property - def y0(self): - return self.coefficients['y0'] - - @property - def z0(self): - return self.coefficients['z0'] - - @y0.setter - def y0(self, y0): - check_type('y0 coefficient', y0, Real) - self._coefficients['y0'] = y0 - - @z0.setter - def z0(self, z0): - check_type('z0 coefficient', z0, Real) - self._coefficients['z0'] = z0 - - def bounding_box(self, side): - """Determine an axis-aligned bounding box. - - An axis-aligned bounding box for surface half-spaces is represented by - its lower-left and upper-right coordinates. For the x-cylinder surface, - the negative half-space is unbounded in the x- direction and the - positive half-space is unbounded in all directions. To represent - infinity, numpy.inf is used. - - Parameters - ---------- - side : {'+', '-'} - Indicates the negative or positive half-space - - Returns - ------- - numpy.ndarray - Lower-left coordinates of the axis-aligned bounding box for the - desired half-space - numpy.ndarray - Upper-right coordinates of the axis-aligned bounding box for the - desired half-space - - """ - - if side == '-': - return (np.array([-np.inf, self.y0 - self.r, self.z0 - self.r]), - np.array([np.inf, self.y0 + self.r, self.z0 + self.r])) - elif side == '+': - return (np.array([-np.inf, -np.inf, -np.inf]), - np.array([np.inf, np.inf, np.inf])) - - def evaluate(self, point): - """Evaluate the surface equation at a given point. - - Parameters - ---------- - point : 3-tuple of float - The Cartesian coordinates, :math:`(x',y',z')`, at which the surface - equation should be evaluated. - - Returns - ------- - float - :math:`(y' - y_0)^2 + (z' - z_0)^2 - r^2` - - """ - y = point[1] - self.y0 - z = point[2] - self.z0 - return y**2 + z**2 - self.r**2 - - def translate(self, vector): - """Translate surface in given direction - - Parameters - ---------- - vector : iterable of float - Direction in which surface should be translated - - Returns - ------- - openmc.XCylinder - Translated surface - - """ - vx, vy, vz = vector - if vy == 0.0 and vz == 0.0: - return self - else: - y0 = self.y0 + vy - z0 = self.z0 + vz - return type(self)(y0=y0, z0=z0, r=self.r) - - -class YCylinder(Cylinder): - """An infinite cylinder whose length is parallel to the y-axis of the form - :math:`(x - x_0)^2 + (z - z_0)^2 = r^2`. - - Parameters - ---------- - surface_id : int, optional - Unique identifier for the surface. If not specified, an identifier will - automatically be assigned. - boundary_type : {'transmission, 'vacuum', 'reflective', 'white'}, optional - Boundary condition that defines the behavior for particles hitting the - surface. Defaults to transmissive boundary condition where particles - freely pass through the surface. - x0 : float, optional - x-coordinate of the center of the cylinder. Defaults to 0. - z0 : float, optional - z-coordinate of the center of the cylinder. Defaults to 0. - r : float, optional - Radius of the cylinder. Defaults to 1. - name : str, optional - Name of the cylinder. If not specified, the name will be the empty - string. - - Attributes - ---------- - x0 : float - x-coordinate of the center of the cylinder - z0 : float - z-coordinate of the center of the cylinder - boundary_type : {'transmission, 'vacuum', 'reflective', 'white'} - Boundary condition that defines the behavior for particles hitting the - surface. - coefficients : dict - Dictionary of surface coefficients - id : int - Unique identifier for the surface - name : str - Name of the surface - type : str - Type of the surface - - """ - - _type = 'y-cylinder' - _coeff_keys = ('x0', 'z0', 'r') - - def __init__(self, surface_id=None, boundary_type='transmission', - x0=0., z0=0., r=1., name='', *, R=None): - if R is not None: - warn(_WARNING_UPPER.format(type(self).__name__, 'r', 'R'), FutureWarning) - r = R - super().__init__(surface_id, boundary_type, r, name=name) - self.x0 = x0 - self.z0 = z0 - - @property - def x0(self): - return self.coefficients['x0'] - - @property - def z0(self): - return self.coefficients['z0'] - - @x0.setter - def x0(self, x0): - check_type('x0 coefficient', x0, Real) - self._coefficients['x0'] = x0 - - @z0.setter - def z0(self, z0): - check_type('z0 coefficient', z0, Real) - self._coefficients['z0'] = z0 - - def bounding_box(self, side): - """Determine an axis-aligned bounding box. - - An axis-aligned bounding box for surface half-spaces is represented by - its lower-left and upper-right coordinates. For the y-cylinder surface, - the negative half-space is unbounded in the y- direction and the - positive half-space is unbounded in all directions. To represent - infinity, numpy.inf is used. - - Parameters - ---------- - side : {'+', '-'} - Indicates the negative or positive half-space - - Returns - ------- - numpy.ndarray - Lower-left coordinates of the axis-aligned bounding box for the - desired half-space - numpy.ndarray - Upper-right coordinates of the axis-aligned bounding box for the - desired half-space - - """ - - if side == '-': - return (np.array([self.x0 - self.r, -np.inf, self.z0 - self.r]), - np.array([self.x0 + self.r, np.inf, self.z0 + self.r])) - elif side == '+': - return (np.array([-np.inf, -np.inf, -np.inf]), - np.array([np.inf, np.inf, np.inf])) - - def evaluate(self, point): - """Evaluate the surface equation at a given point. - - Parameters - ---------- - point : 3-tuple of float - The Cartesian coordinates, :math:`(x',y',z')`, at which the surface - equation should be evaluated. - - Returns - ------- - float - :math:`(x' - x_0)^2 + (z' - z_0)^2 - r^2` - - """ - x = point[0] - self.x0 - z = point[2] - self.z0 - return x**2 + z**2 - self.r**2 - - def translate(self, vector): - """Translate surface in given direction - - Parameters - ---------- - vector : iterable of float - Direction in which surface should be translated - - Returns - ------- - openmc.YCylinder - Translated surface - - """ - vx, vy, vz = vector - if vx == 0.0 and vz == 0.0: - return self - else: - x0 = self.x0 + vx - z0 = self.z0 + vz - return type(self)(x0=x0, z0=z0, r=self.r) - - -class ZCylinder(Cylinder): - """An infinite cylinder whose length is parallel to the z-axis of the form - :math:`(x - x_0)^2 + (y - y_0)^2 = r^2`. - - Parameters - ---------- - surface_id : int, optional - Unique identifier for the surface. If not specified, an identifier will - automatically be assigned. - boundary_type : {'transmission, 'vacuum', 'reflective', 'white'}, optional - Boundary condition that defines the behavior for particles hitting the - surface. Defaults to transmissive boundary condition where particles - freely pass through the surface. - x0 : float, optional - x-coordinate of the center of the cylinder. Defaults to 0. - y0 : float, optional - y-coordinate of the center of the cylinder. Defaults to 0. - r : float, optional - Radius of the cylinder. Defaults to 1. - name : str, optional - Name of the cylinder. If not specified, the name will be the empty - string. - - Attributes - ---------- - x0 : float - x-coordinate of the center of the cylinder - y0 : float - y-coordinate of the center of the cylinder - boundary_type : {'transmission, 'vacuum', 'reflective', 'white'} - Boundary condition that defines the behavior for particles hitting the - surface. - coefficients : dict - Dictionary of surface coefficients - id : int - Unique identifier for the surface - name : str - Name of the surface - type : str - Type of the surface - - """ - - _type = 'z-cylinder' - _coeff_keys = ('x0', 'y0', 'r') - - def __init__(self, surface_id=None, boundary_type='transmission', - x0=0., y0=0., r=1., name='', *, R=None): - if R is not None: - warn(_WARNING_UPPER.format(type(self).__name__, 'r', 'R'), FutureWarning) - r = R - super().__init__(surface_id, boundary_type, r, name=name) - self.x0 = x0 - self.y0 = y0 - - @property - def x0(self): - return self.coefficients['x0'] - - @property - def y0(self): - return self.coefficients['y0'] - - @x0.setter - def x0(self, x0): - check_type('x0 coefficient', x0, Real) - self._coefficients['x0'] = x0 - - @y0.setter - def y0(self, y0): - check_type('y0 coefficient', y0, Real) - self._coefficients['y0'] = y0 - - def bounding_box(self, side): - """Determine an axis-aligned bounding box. - - An axis-aligned bounding box for surface half-spaces is represented by - its lower-left and upper-right coordinates. For the z-cylinder surface, - the negative half-space is unbounded in the z- direction and the - positive half-space is unbounded in all directions. To represent - infinity, numpy.inf is used. - - Parameters - ---------- - side : {'+', '-'} - Indicates the negative or positive half-space - - Returns - ------- - numpy.ndarray - Lower-left coordinates of the axis-aligned bounding box for the - desired half-space - numpy.ndarray - Upper-right coordinates of the axis-aligned bounding box for the - desired half-space - - """ - - if side == '-': - return (np.array([self.x0 - self.r, self.y0 - self.r, -np.inf]), - np.array([self.x0 + self.r, self.y0 + self.r, np.inf])) - elif side == '+': - return (np.array([-np.inf, -np.inf, -np.inf]), - np.array([np.inf, np.inf, np.inf])) - - def evaluate(self, point): - """Evaluate the surface equation at a given point. - - Parameters - ---------- - point : 3-tuple of float - The Cartesian coordinates, :math:`(x',y',z')`, at which the surface - equation should be evaluated. - - Returns - ------- - float - :math:`(x' - x_0)^2 + (y' - y_0)^2 - r^2` - - """ - x = point[0] - self.x0 - y = point[1] - self.y0 - return x**2 + y**2 - self.r**2 - - def translate(self, vector): - """Translate surface in given direction - - Parameters - ---------- - vector : iterable of float - Direction in which surface should be translated - - Returns - ------- - openmc.ZCylinder - Translated surface - - """ - vx, vy, vz = vector - if vx == 0.0 and vy == 0.0: - return self - else: - x0 = self.x0 + vx - y0 = self.y0 + vy - return type(self)(x0=x0, y0=y0, r=self.r) - - -class Sphere(Surface): - """A sphere of the form :math:`(x - x_0)^2 + (y - y_0)^2 + (z - z_0)^2 = r^2`. - - Parameters - ---------- - surface_id : int, optional - Unique identifier for the surface. If not specified, an identifier will - automatically be assigned. - boundary_type : {'transmission, 'vacuum', 'reflective', 'white'}, optional - Boundary condition that defines the behavior for particles hitting the - surface. Defaults to transmissive boundary condition where particles - freely pass through the surface. - x0 : float, optional - x-coordinate of the center of the sphere. Defaults to 0. - y0 : float, optional - y-coordinate of the center of the sphere. Defaults to 0. - z0 : float, optional - z-coordinate of the center of the sphere. Defaults to 0. - r : float, optional - Radius of the sphere. Defaults to 1. - name : str, optional - Name of the sphere. If not specified, the name will be the empty string. - - Attributes - ---------- - x0 : float - x-coordinate of the center of the sphere - y0 : float - y-coordinate of the center of the sphere - z0 : float - z-coordinate of the center of the sphere - r : float - Radius of the sphere - boundary_type : {'transmission, 'vacuum', 'reflective', 'white'} - Boundary condition that defines the behavior for particles hitting the - surface. - coefficients : dict - Dictionary of surface coefficients - id : int - Unique identifier for the surface - name : str - Name of the surface - type : str - Type of the surface - - """ - - _type = 'sphere' - _coeff_keys = ('x0', 'y0', 'z0', 'r') - - def __init__(self, surface_id=None, boundary_type='transmission', - x0=0., y0=0., z0=0., r=1., name='', *, R=None): - if R is not None: - warn(_WARNING_UPPER.format(type(self).__name__, 'r', 'R'), FutureWarning) - r = R - super().__init__(surface_id, boundary_type, name=name) - self.x0 = x0 - self.y0 = y0 - self.z0 = z0 - self.r = r - - @property - def x0(self): - return self.coefficients['x0'] - - @property - def y0(self): - return self.coefficients['y0'] - - @property - def z0(self): - return self.coefficients['z0'] - - @property - def r(self): - return self.coefficients['r'] - - @x0.setter - def x0(self, x0): - check_type('x0 coefficient', x0, Real) - self._coefficients['x0'] = x0 - - @y0.setter - def y0(self, y0): - check_type('y0 coefficient', y0, Real) - self._coefficients['y0'] = y0 - - @z0.setter - def z0(self, z0): - check_type('z0 coefficient', z0, Real) - self._coefficients['z0'] = z0 - - @r.setter - def r(self, r): - check_type('r coefficient', r, Real) - self._coefficients['r'] = r - - def bounding_box(self, side): - """Determine an axis-aligned bounding box. - - An axis-aligned bounding box for surface half-spaces is represented by - its lower-left and upper-right coordinates. The positive half-space of a - sphere is unbounded in all directions. To represent infinity, numpy.inf - is used. - - Parameters - ---------- - side : {'+', '-'} - Indicates the negative or positive half-space - - Returns - ------- - numpy.ndarray - Lower-left coordinates of the axis-aligned bounding box for the - desired half-space - numpy.ndarray - Upper-right coordinates of the axis-aligned bounding box for the - desired half-space - - """ - - if side == '-': - return (np.array([self.x0 - self.r, self.y0 - self.r, - self.z0 - self.r]), - np.array([self.x0 + self.r, self.y0 + self.r, - self.z0 + self.r])) - elif side == '+': - return (np.array([-np.inf, -np.inf, -np.inf]), - np.array([np.inf, np.inf, np.inf])) - - def evaluate(self, point): - """Evaluate the surface equation at a given point. - - Parameters - ---------- - point : 3-tuple of float - The Cartesian coordinates, :math:`(x',y',z')`, at which the surface - equation should be evaluated. - - Returns - ------- - float - :math:`(x' - x_0)^2 + (y' - y_0)^2 + (z' - z_0)^2 - r^2` - - """ - x = point[0] - self.x0 - y = point[1] - self.y0 - z = point[2] - self.z0 - return x**2 + y**2 + z**2 - self.r**2 - - def translate(self, vector): - """Translate surface in given direction - - Parameters - ---------- - vector : iterable of float - Direction in which surface should be translated - - Returns - ------- - openmc.Sphere - Translated surface - - """ - vx, vy, vz = vector - if vx == 0.0 and vy == 0.0 and vz == 0.0: - return self - else: - x0 = self.x0 + vx - y0 = self.y0 + vy - z0 = self.z0 + vz - return type(self)(x0=x0, y0=y0, z0=z0, r=self.r) - - -class Cone(Surface): - """A conical surface parallel to the x-, y-, or z-axis. - - Parameters - ---------- - surface_id : int, optional - Unique identifier for the surface. If not specified, an identifier will - automatically be assigned. - boundary_type : {'transmission, 'vacuum', 'reflective', 'white'}, optional - Boundary condition that defines the behavior for particles hitting the - surface. Defaults to transmissive boundary condition where particles - freely pass through the surface. - x0 : float, optional - x-coordinate of the apex. Defaults to 0. - y0 : float - y-coordinate of the apex. Defaults to 0. - z0 : float - z-coordinate of the apex. Defaults to 0. - r2 : float - Parameter related to the aperature. Defaults to 1. - name : str - Name of the cone. If not specified, the name will be the empty string. - - Attributes - ---------- - x0 : float - x-coordinate of the apex - y0 : float - y-coordinate of the apex - z0 : float - z-coordinate of the apex - r2 : float - Parameter related to the aperature - boundary_type : {'transmission, 'vacuum', 'reflective', 'white'} - Boundary condition that defines the behavior for particles hitting the - surface. - coefficients : dict - Dictionary of surface coefficients - id : int - Unique identifier for the surface - name : str - Name of the surface - type : str - Type of the surface - - """ - - _coeff_keys = ('x0', 'y0', 'z0', 'r2') - - def __init__(self, surface_id=None, boundary_type='transmission', - x0=0., y0=0., z0=0., r2=1., name='', *, R2=None): - if R2 is not None: - warn(_WARNING_UPPER.format(type(self).__name__, 'r2', 'R2'), FutureWarning) - r2 = R2 - super().__init__(surface_id, boundary_type, name=name) - self.x0 = x0 - self.y0 = y0 - self.z0 = z0 - self.r2 = r2 - - @property - def x0(self): - return self.coefficients['x0'] - - @property - def y0(self): - return self.coefficients['y0'] - - @property - def z0(self): - return self.coefficients['z0'] - - @property - def r2(self): - return self.coefficients['r2'] - - @x0.setter - def x0(self, x0): - check_type('x0 coefficient', x0, Real) - self._coefficients['x0'] = x0 - - @y0.setter - def y0(self, y0): - check_type('y0 coefficient', y0, Real) - self._coefficients['y0'] = y0 - - @z0.setter - def z0(self, z0): - check_type('z0 coefficient', z0, Real) - self._coefficients['z0'] = z0 - - @r2.setter - def r2(self, r2): - check_type('r^2 coefficient', r2, Real) - self._coefficients['r2'] = r2 - - def translate(self, vector): - """Translate surface in given direction - - Parameters - ---------- - vector : iterable of float - Direction in which surface should be translated - - Returns - ------- - openmc.Cone - Translated surface - - """ - vx, vy, vz = vector - if vx == 0.0 and vy == 0.0 and vz == 0.0: - return self - else: - x0 = self.x0 + vx - y0 = self.y0 + vy - z0 = self.z0 + vz - return type(self)(x0=x0, y0=y0, z0=z0, r2=self.r2) - - -class XCone(Cone): - """A cone parallel to the x-axis of the form :math:`(y - y_0)^2 + (z - z_0)^2 = - r^2 (x - x_0)^2`. - - Parameters - ---------- - surface_id : int, optional - Unique identifier for the surface. If not specified, an identifier will - automatically be assigned. - boundary_type : {'transmission, 'vacuum', 'reflective', 'white'}, optional - Boundary condition that defines the behavior for particles hitting the - surface. Defaults to transmissive boundary condition where particles - freely pass through the surface. - x0 : float, optional - x-coordinate of the apex. Defaults to 0. - y0 : float, optional - y-coordinate of the apex. Defaults to 0. - z0 : float, optional - z-coordinate of the apex. Defaults to 0. - r2 : float, optional - Parameter related to the aperature. Defaults to 1. - name : str, optional - Name of the cone. If not specified, the name will be the empty string. - - Attributes - ---------- - x0 : float - x-coordinate of the apex - y0 : float - y-coordinate of the apex - z0 : float - z-coordinate of the apex - r2 : float - Parameter related to the aperature - boundary_type : {'transmission, 'vacuum', 'reflective', 'white'} - Boundary condition that defines the behavior for particles hitting the - surface. - coefficients : dict - Dictionary of surface coefficients - id : int - Unique identifier for the surface - name : str - Name of the surface - type : str - Type of the surface - - """ - - _type = 'x-cone' - - def evaluate(self, point): - """Evaluate the surface equation at a given point. - - Parameters - ---------- - point : 3-tuple of float - The Cartesian coordinates, :math:`(x',y',z')`, at which the surface - equation should be evaluated. - - Returns - ------- - float - :math:`(y' - y_0)^2 + (z' - z_0)^2 - r^2(x' - x_0)^2` - - """ - x = point[0] - self.x0 - y = point[1] - self.y0 - z = point[2] - self.z0 - return y**2 + z**2 - self.r2*x**2 - - -class YCone(Cone): - """A cone parallel to the y-axis of the form :math:`(x - x_0)^2 + (z - z_0)^2 = - r^2 (y - y_0)^2`. - - Parameters - ---------- - surface_id : int, optional - Unique identifier for the surface. If not specified, an identifier will - automatically be assigned. - boundary_type : {'transmission, 'vacuum', 'reflective', 'white'}, optional - Boundary condition that defines the behavior for particles hitting the - surface. Defaults to transmissive boundary condition where particles - freely pass through the surface. - x0 : float, optional - x-coordinate of the apex. Defaults to 0. - y0 : float, optional - y-coordinate of the apex. Defaults to 0. - z0 : float, optional - z-coordinate of the apex. Defaults to 0. - r2 : float, optional - Parameter related to the aperature. Defaults to 1. - name : str, optional - Name of the cone. If not specified, the name will be the empty string. - - Attributes - ---------- - x0 : float - x-coordinate of the apex - y0 : float - y-coordinate of the apex - z0 : float - z-coordinate of the apex - r2 : float - Parameter related to the aperature - boundary_type : {'transmission, 'vacuum', 'reflective', 'white'} - Boundary condition that defines the behavior for particles hitting the - surface. - coefficients : dict - Dictionary of surface coefficients - id : int - Unique identifier for the surface - name : str - Name of the surface - type : str - Type of the surface - - """ - - _type = 'y-cone' - - def evaluate(self, point): - """Evaluate the surface equation at a given point. - - Parameters - ---------- - point : 3-tuple of float - The Cartesian coordinates, :math:`(x',y',z')`, at which the surface - equation should be evaluated. - - Returns - ------- - float - :math:`(x' - x_0)^2 + (z' - z_0)^2 - r^2(y' - y_0)^2` - - """ - x = point[0] - self.x0 - y = point[1] - self.y0 - z = point[2] - self.z0 - return x**2 + z**2 - self.r2*y**2 - - -class ZCone(Cone): - """A cone parallel to the x-axis of the form :math:`(x - x_0)^2 + (y - y_0)^2 = - r^2 (z - z_0)^2`. - - Parameters - ---------- - surface_id : int, optional - Unique identifier for the surface. If not specified, an identifier will - automatically be assigned. - boundary_type : {'transmission, 'vacuum', 'reflective', 'white'}, optional - Boundary condition that defines the behavior for particles hitting the - surface. Defaults to transmissive boundary condition where particles - freely pass through the surface. - x0 : float, optional - x-coordinate of the apex. Defaults to 0. - y0 : float, optional - y-coordinate of the apex. Defaults to 0. - z0 : float, optional - z-coordinate of the apex. Defaults to 0. - r2 : float, optional - Parameter related to the aperature. Defaults to 1. - name : str, optional - Name of the cone. If not specified, the name will be the empty string. - - Attributes - ---------- - x0 : float - x-coordinate of the apex - y0 : float - y-coordinate of the apex - z0 : float - z-coordinate of the apex - r2 : float - Parameter related to the aperature - boundary_type : {'transmission, 'vacuum', 'reflective', 'white'} - Boundary condition that defines the behavior for particles hitting the - surface. - coefficients : dict - Dictionary of surface coefficients - id : int - Unique identifier for the surface - name : str - Name of the surface - type : str - Type of the surface - - """ - - _type = 'z-cone' - - def evaluate(self, point): - """Evaluate the surface equation at a given point. - - Parameters - ---------- - point : 3-tuple of float - The Cartesian coordinates, :math:`(x',y',z')`, at which the surface - equation should be evaluated. - - Returns - ------- - float - :math:`(x' - x_0)^2 + (y' - y_0)^2 - r^2(z' - z_0)^2` - - """ - x = point[0] - self.x0 - y = point[1] - self.y0 - z = point[2] - self.z0 - return x**2 + y**2 - self.r2*z**2 - - -class Quadric(Surface): - """A surface of the form :math:`Ax^2 + By^2 + Cz^2 + Dxy + Eyz + Fxz + Gx + Hy + - Jz + K = 0`. - - Parameters - ---------- - surface_id : int, optional - Unique identifier for the surface. If not specified, an identifier will - automatically be assigned. - boundary_type : {'transmission, 'vacuum', 'reflective', 'periodic', 'white'}, optional - Boundary condition that defines the behavior for particles hitting the - surface. Defaults to transmissive boundary condition where particles - freely pass through the surface. - a, b, c, d, e, f, g, h, j, k : float, optional - coefficients for the surface. All default to 0. - name : str, optional - Name of the surface. If not specified, the name will be the empty string. - - Attributes - ---------- - a, b, c, d, e, f, g, h, j, k : float - coefficients for the surface - boundary_type : {'transmission, 'vacuum', 'reflective', 'periodic', 'white'} - Boundary condition that defines the behavior for particles hitting the - surface. - coefficients : dict - Dictionary of surface coefficients - id : int - Unique identifier for the surface - name : str - Name of the surface - type : str - Type of the surface - - """ - - _type = 'quadric' - _coeff_keys = ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'j', 'k') - - def __init__(self, surface_id=None, boundary_type='transmission', - a=0., b=0., c=0., d=0., e=0., f=0., g=0., - h=0., j=0., k=0., name=''): - super().__init__(surface_id, boundary_type, name=name) - self.a = a - self.b = b - self.c = c - self.d = d - self.e = e - self.f = f - self.g = g - self.h = h - self.j = j - self.k = k - - @property - def a(self): - return self.coefficients['a'] - - @property - def b(self): - return self.coefficients['b'] - - @property - def c(self): - return self.coefficients['c'] - - @property - def d(self): - return self.coefficients['d'] - - @property - def e(self): - return self.coefficients['e'] - - @property - def f(self): - return self.coefficients['f'] - - @property - def g(self): - return self.coefficients['g'] - - @property - def h(self): - return self.coefficients['h'] - - @property - def j(self): - return self.coefficients['j'] - - @property - def k(self): - return self.coefficients['k'] - - @a.setter - def a(self, a): - check_type('a coefficient', a, Real) - self._coefficients['a'] = a - - @b.setter - def b(self, b): - check_type('b coefficient', b, Real) - self._coefficients['b'] = b - - @c.setter - def c(self, c): - check_type('c coefficient', c, Real) - self._coefficients['c'] = c - - @d.setter - def d(self, d): - check_type('d coefficient', d, Real) - self._coefficients['d'] = d - - @e.setter - def e(self, e): - check_type('e coefficient', e, Real) - self._coefficients['e'] = e - - @f.setter - def f(self, f): - check_type('f coefficient', f, Real) - self._coefficients['f'] = f - - @g.setter - def g(self, g): - check_type('g coefficient', g, Real) - self._coefficients['g'] = g - - @h.setter - def h(self, h): - check_type('h coefficient', h, Real) - self._coefficients['h'] = h - - @j.setter - def j(self, j): - check_type('j coefficient', j, Real) - self._coefficients['j'] = j - - @k.setter - def k(self, k): - check_type('k coefficient', k, Real) - self._coefficients['k'] = k - - def evaluate(self, point): - """Evaluate the surface equation at a given point. - - Parameters - ---------- - point : 3-tuple of float - The Cartesian coordinates, :math:`(x',y',z')`, at which the surface - equation should be evaluated. - - Returns - ------- - float - :math:`Ax'^2 + By'^2 + Cz'^2 + Dx'y' + Ey'z' + Fx'z' + Gx' + Hy' + - Jz' + K = 0` - - """ - x, y, z = point - return x*(self.a*x + self.d*y + self.g) + \ - y*(self.b*y + self.e*z + self.h) + \ - z*(self.c*z + self.f*x + self.j) + self.k - - def translate(self, vector): - """Translate surface in given direction - - Parameters - ---------- - vector : iterable of float - Direction in which surface should be translated - - Returns - ------- - openmc.Quadric - Translated surface - - """ - vx, vy, vz = vector - a, b, c, d, e, f, g, h, j, k = (getattr(self, key) for key in - self._coeff_keys) - k = (k + vx*vx + vy*vy + vz*vz + d*vx*vy + e*vy*vz + f*vx*vz - - g*vx - h*vy - j*vz) - g = g - 2*a*vx - d*vy - f*vz - h = h - 2*b*vy - d*vx - e*vz - j = j - 2*c*vz - e*vy - f*vx - return type(self)(a=a, b=b, c=c, d=d, e=e, f=f, g=g, h=h, j=j, k=k) - - -class Halfspace(Region): - """A positive or negative half-space region. - - A half-space is either of the two parts into which a two-dimension surface - divides the three-dimensional Euclidean space. If the equation of the - surface is :math:`f(x,y,z) = 0`, the region for which :math:`f(x,y,z) < 0` - is referred to as the negative half-space and the region for which - :math:`f(x,y,z) > 0` is referred to as the positive half-space. - - Instances of Halfspace are generally not instantiated directly. Rather, they - can be created from an existing Surface through the __neg__ and __pos__ - operators, as the following example demonstrates: - - >>> sphere = openmc.Sphere(surface_id=1, r=10.0) - >>> inside_sphere = -sphere - >>> outside_sphere = +sphere - >>> type(inside_sphere) - - - Parameters - ---------- - surface : openmc.Surface - Surface which divides Euclidean space. - side : {'+', '-'} - Indicates whether the positive or negative half-space is used. - - Attributes - ---------- - surface : openmc.Surface - Surface which divides Euclidean space. - side : {'+', '-'} - Indicates whether the positive or negative half-space is used. - bounding_box : tuple of numpy.ndarray - Lower-left and upper-right coordinates of an axis-aligned bounding box - - """ - - def __init__(self, surface, side): - self.surface = surface - self.side = side - - def __and__(self, other): - if isinstance(other, Intersection): - return Intersection([self] + other[:]) - else: - return Intersection((self, other)) - - def __or__(self, other): - if isinstance(other, Union): - return Union([self] + other[:]) - else: - return Union((self, other)) - - def __invert__(self): - return -self.surface if self.side == '+' else +self.surface - - def __contains__(self, point): - """Check whether a point is contained in the half-space. - - Parameters - ---------- - point : 3-tuple of float - Cartesian coordinates, :math:`(x',y',z')`, of the point - - Returns - ------- - bool - Whether the point is in the half-space - - """ - - val = self.surface.evaluate(point) - return val >= 0. if self.side == '+' else val < 0. - - @property - def surface(self): - return self._surface - - @surface.setter - def surface(self, surface): - check_type('surface', surface, Surface) - self._surface = surface - - @property - def side(self): - return self._side - - @side.setter - def side(self, side): - check_value('side', side, ('+', '-')) - self._side = side - - @property - def bounding_box(self): - return self.surface.bounding_box(self.side) - - def __str__(self): - return '-' + str(self.surface.id) if self.side == '-' \ - else str(self.surface.id) - - def get_surfaces(self, surfaces=None): - """ - Returns the surface that this is a halfspace of. - - Parameters - ---------- - surfaces: collections.OrderedDict, optional - Dictionary mapping surface IDs to :class:`openmc.Surface` instances - - Returns - ------- - surfaces: collections.OrderedDict - Dictionary mapping surface IDs to :class:`openmc.Surface` instances - - """ - if surfaces is None: - surfaces = OrderedDict() - - surfaces[self.surface.id] = self.surface - return surfaces - - def clone(self, memo=None): - """Create a copy of this halfspace, with a cloned surface with a - unique ID. - - Parameters - ---------- - memo : dict or None - A nested dictionary of previously cloned objects. This parameter - is used internally and should not be specified by the user. - - Returns - ------- - clone : openmc.Halfspace - The clone of this halfspace - - """ - - if memo is None: - memo = dict - - clone = deepcopy(self) - clone.surface = self.surface.clone(memo) - return clone - - def translate(self, vector, memo=None): - """Translate half-space in given direction - - Parameters - ---------- - vector : iterable of float - Direction in which region should be translated - memo : dict or None - Dictionary used for memoization - - Returns - ------- - openmc.Halfspace - Translated half-space - - """ - if memo is None: - memo = {} - - # If translated surface not in memo, add it - key = (self.surface, tuple(vector)) - if key not in memo: - memo[key] = self.surface.translate(vector) - - # Return translated surface - return type(self)(memo[key], self.side) diff --git a/setup.py b/setup.py index 712244efb4..aff7834d7b 100755 --- a/setup.py +++ b/setup.py @@ -31,7 +31,7 @@ kwargs = { # Data files and librarries 'package_data': { - 'openmc.capi': ['libopenmc.{}'.format(suffix)], + 'openmc.lib': ['libopenmc.{}'.format(suffix)], 'openmc.data': ['mass16.txt', 'BREMX.DAT', '*.h5'] }, diff --git a/src/finalize.cpp b/src/finalize.cpp index 7c39a7c198..3de20d6d09 100644 --- a/src/finalize.cpp +++ b/src/finalize.cpp @@ -127,9 +127,7 @@ int openmc_finalize() // Free all MPI types #ifdef OPENMC_MPI - int init_called; - MPI_Initialized(&init_called); - if (init_called) MPI_Type_free(&mpi::bank); + if (mpi::bank != MPI_DATATYPE_NULL) MPI_Type_free(&mpi::bank); #endif return 0; diff --git a/src/secondary_thermal.cpp b/src/secondary_thermal.cpp index 696907a17e..8c9cc69676 100644 --- a/src/secondary_thermal.cpp +++ b/src/secondary_thermal.cpp @@ -61,7 +61,7 @@ CoherentElasticAE::sample(double E_in, double& E_out, double& mu) const IncoherentElasticAE::IncoherentElasticAE(hid_t group) { - read_attribute(group, "debye_waller", debye_waller_); + read_dataset(group, "debye_waller", debye_waller_); } void diff --git a/src/thermal.cpp b/src/thermal.cpp index 5cc395e13c..49b5223763 100644 --- a/src/thermal.cpp +++ b/src/thermal.cpp @@ -210,22 +210,15 @@ ThermalData::ThermalData(hid_t group) if (temp == "coherent_elastic") { auto xs = dynamic_cast(elastic_.xs.get()); elastic_.distribution = std::make_unique(*xs); - - // Set threshold energy - threshold_elastic_ = xs->bragg_edges().back(); - } else { - auto xs = dynamic_cast(elastic_.xs.get()); if (temp == "incoherent_elastic") { elastic_.distribution = std::make_unique(dgroup); } else if (temp == "incoherent_elastic_discrete") { + auto xs = dynamic_cast(elastic_.xs.get()); elastic_.distribution = std::make_unique( dgroup, xs->x() ); } - - // Set threshold energy - threshold_elastic_ = xs->x().back(); } close_group(elastic_group); @@ -239,10 +232,6 @@ ThermalData::ThermalData(hid_t group) // Read inelastic cross section inelastic_.xs = read_function(inelastic_group, "xs"); - // Set inelastic threshold - auto xs = dynamic_cast(inelastic_.xs.get()); - threshold_inelastic_ = xs->x().back(); - // Read angle-energy distribution hid_t dgroup = open_group(inelastic_group, "distribution"); std::string temp; @@ -250,6 +239,7 @@ ThermalData::ThermalData(hid_t group) if (temp == "incoherent_inelastic") { inelastic_.distribution = std::make_unique(dgroup); } else if (temp == "incoherent_inelastic_discrete") { + auto xs = dynamic_cast(inelastic_.xs.get()); inelastic_.distribution = std::make_unique( dgroup, xs->x() ); diff --git a/tests/dummy_operator.py b/tests/dummy_operator.py index 85c689743a..35a526c30d 100644 --- a/tests/dummy_operator.py +++ b/tests/dummy_operator.py @@ -83,7 +83,7 @@ class TestChain(object): fission_yields = [None] @staticmethod - def get_thermal_fission_yields(): + def get_default_fission_yields(): return None def form_matrix(self, rates, _fission_yields=None): diff --git a/tests/regression_tests/asymmetric_lattice/test.py b/tests/regression_tests/asymmetric_lattice/test.py index d6a0ab9b73..7ed0293ce9 100644 --- a/tests/regression_tests/asymmetric_lattice/test.py +++ b/tests/regression_tests/asymmetric_lattice/test.py @@ -25,12 +25,12 @@ class AsymmetricLatticeTestHarness(PyAPITestHarness): [water, water, water]] # Create bounding surfaces - min_x = openmc.XPlane(x0=-32.13, boundary_type='reflective') - max_x = openmc.XPlane(x0=+32.13, boundary_type='reflective') - min_y = openmc.YPlane(y0=-32.13, boundary_type='reflective') - max_y = openmc.YPlane(y0=+32.13, boundary_type='reflective') - min_z = openmc.ZPlane(z0=0, boundary_type='reflective') - max_z = openmc.ZPlane(z0=+32.13, boundary_type='reflective') + min_x = openmc.XPlane(-32.13, 'reflective') + max_x = openmc.XPlane(+32.13, 'reflective') + min_y = openmc.YPlane(-32.13, 'reflective') + max_y = openmc.YPlane(+32.13, 'reflective') + min_z = openmc.ZPlane(0, 'reflective') + max_z = openmc.ZPlane(+32.13, 'reflective') # Define root universe root_univ = openmc.Universe(universe_id=0, name='root universe') diff --git a/tests/regression_tests/complex_cell/test.py b/tests/regression_tests/complex_cell/test.py index b43ccd72f9..77cbd6cb7d 100755 --- a/tests/regression_tests/complex_cell/test.py +++ b/tests/regression_tests/complex_cell/test.py @@ -1,8 +1,5 @@ from tests.testing_harness import TestHarness -import sys - -import openmc.capi def test_complex_cell(): harness = TestHarness('statepoint.10.h5') diff --git a/tests/regression_tests/dagmc/legacy/test.py b/tests/regression_tests/dagmc/legacy/test.py index db062d36eb..963e73226e 100644 --- a/tests/regression_tests/dagmc/legacy/test.py +++ b/tests/regression_tests/dagmc/legacy/test.py @@ -1,11 +1,11 @@ import openmc -import openmc.capi +import openmc.lib import pytest from tests.testing_harness import PyAPITestHarness pytestmark = pytest.mark.skipif( - not openmc.capi._dagmc_enabled(), + not openmc.lib._dagmc_enabled(), reason="DAGMC CAD geometry is not enabled.") def test_dagmc(): diff --git a/tests/regression_tests/dagmc/refl/test.py b/tests/regression_tests/dagmc/refl/test.py index 93104f1d0d..c451b61250 100644 --- a/tests/regression_tests/dagmc/refl/test.py +++ b/tests/regression_tests/dagmc/refl/test.py @@ -1,12 +1,12 @@ import openmc -import openmc.capi +import openmc.lib from openmc.stats import Box import pytest from tests.testing_harness import PyAPITestHarness pytestmark = pytest.mark.skipif( - not openmc.capi._dagmc_enabled(), + not openmc.lib._dagmc_enabled(), reason="DAGMC CAD geometry is not enabled.") class UWUWTest(PyAPITestHarness): diff --git a/tests/regression_tests/dagmc/uwuw/test.py b/tests/regression_tests/dagmc/uwuw/test.py index 885b83766f..b4391d8e77 100644 --- a/tests/regression_tests/dagmc/uwuw/test.py +++ b/tests/regression_tests/dagmc/uwuw/test.py @@ -1,12 +1,12 @@ import openmc -import openmc.capi +import openmc.lib from openmc.stats import Box import pytest from tests.testing_harness import PyAPITestHarness pytestmark = pytest.mark.skipif( - not openmc.capi._dagmc_enabled(), + not openmc.lib._dagmc_enabled(), reason="DAGMC CAD geometry is not enabled.") class UWUWTest(PyAPITestHarness): diff --git a/tests/regression_tests/deplete/example_geometry.py b/tests/regression_tests/deplete/example_geometry.py index d4fdf585df..f79044558c 100644 --- a/tests/regression_tests/deplete/example_geometry.py +++ b/tests/regression_tests/deplete/example_geometry.py @@ -158,6 +158,7 @@ def generate_initial_number_density(): return temperature, sab, initial_density, burn + def segment_pin(n_rings, n_wedges, r_fuel, r_gap, r_clad): """ Calculates a segmented pin. @@ -248,6 +249,7 @@ def segment_pin(n_rings, n_wedges, r_fuel, r_gap, r_clad): return fuel_u, v_segment, v_gap, v_clad + def generate_geometry(n_rings, n_wedges): """ Generates example geometry. @@ -296,12 +298,12 @@ def generate_geometry(n_rings, n_wedges): lattice.outer = all_water_u # Bound universe - x_low = openmc.XPlane(x0=-pitch*n_pin/2, boundary_type='reflective') - x_high = openmc.XPlane(x0=pitch*n_pin/2, boundary_type='reflective') - y_low = openmc.YPlane(y0=-pitch*n_pin/2, boundary_type='reflective') - y_high = openmc.YPlane(y0=pitch*n_pin/2, boundary_type='reflective') - z_low = openmc.ZPlane(z0=-10, boundary_type='reflective') - z_high = openmc.ZPlane(z0=10, boundary_type='reflective') + x_low = openmc.XPlane(-pitch*n_pin/2, 'reflective') + x_high = openmc.XPlane(pitch*n_pin/2, 'reflective') + y_low = openmc.YPlane(-pitch*n_pin/2, 'reflective') + y_high = openmc.YPlane(pitch*n_pin/2, 'reflective') + z_low = openmc.ZPlane(-10, 'reflective') + z_high = openmc.ZPlane(10, 'reflective') # Compute bounding box lower_left = [-pitch*n_pin/2, -pitch*n_pin/2, -10] @@ -317,10 +319,11 @@ def generate_geometry(n_rings, n_wedges): v_cool = pitch**2 - (v_gap + v_clad + n_rings * n_wedges * v_segment) # Store volumes for later usage - volume = {'fuel': v_segment, 'gap':v_gap, 'clad':v_clad, 'cool':v_cool} + volume = {'fuel': v_segment, 'gap': v_gap, 'clad': v_clad, 'cool': v_cool} return geometry, volume, mapping, lower_left, upper_right + def generate_problem(n_rings=5, n_wedges=8): """ Merges geometry and materials. diff --git a/tests/regression_tests/periodic/test.py b/tests/regression_tests/periodic/test.py index 5df935b22e..879bd84809 100644 --- a/tests/regression_tests/periodic/test.py +++ b/tests/regression_tests/periodic/test.py @@ -21,16 +21,16 @@ class PeriodicTest(PyAPITestHarness): materials.export_to_xml() # Define geometry - x_min = openmc.XPlane(1, x0=-5., boundary_type='periodic') - x_max = openmc.XPlane(2, x0=5., boundary_type='periodic') + x_min = openmc.XPlane(surface_id=1, x0=-5., boundary_type='periodic') + x_max = openmc.XPlane(surface_id=2, x0=5., boundary_type='periodic') x_max.periodic_surface = x_min - y_min = openmc.YPlane(3, y0=-5., boundary_type='periodic') - y_max = openmc.YPlane(4, y0=5., boundary_type='periodic') + y_min = openmc.YPlane(surface_id=3, y0=-5., boundary_type='periodic') + y_max = openmc.YPlane(surface_id=4, y0=5., boundary_type='periodic') - z_min = openmc.ZPlane(5, z0=-5., boundary_type='reflective') - z_max = openmc.ZPlane(6, z0=5., boundary_type='reflective') - z_cyl = openmc.ZCylinder(7, x0=-2.5, y0=2.5, r=2.0) + z_min = openmc.ZPlane(surface_id=5, z0=-5., boundary_type='reflective') + z_max = openmc.ZPlane(surface_id=6, z0=5., boundary_type='reflective') + z_cyl = openmc.ZCylinder(surface_id=7, x0=-2.5, y0=2.5, r=2.0) outside_cyl = openmc.Cell(1, fill=water, region=( +x_min & -x_max & +y_min & -y_max & +z_min & -z_max & +z_cyl)) diff --git a/tests/regression_tests/photon_production/test.py b/tests/regression_tests/photon_production/test.py index c6a1fc3908..1f645ebb94 100644 --- a/tests/regression_tests/photon_production/test.py +++ b/tests/regression_tests/photon_production/test.py @@ -14,10 +14,10 @@ class SourceTestHarness(PyAPITestHarness): materials = openmc.Materials([mat]) materials.export_to_xml() - cyl = openmc.XCylinder(boundary_type='vacuum', r=1.0) - x_plane_left = openmc.XPlane(boundary_type='vacuum', x0=-1.0) - x_plane_center = openmc.XPlane(boundary_type='transmission', x0=1.0) - x_plane_right = openmc.XPlane(boundary_type='vacuum', x0=1.0e9) + cyl = openmc.XCylinder(r=1.0, boundary_type='vacuum') + x_plane_left = openmc.XPlane(-1.0, 'vacuum') + x_plane_center = openmc.XPlane(1.0) + x_plane_right = openmc.XPlane(1.0e9, 'vacuum') inner_cyl_left = openmc.Cell() inner_cyl_right = openmc.Cell() @@ -31,7 +31,7 @@ class SourceTestHarness(PyAPITestHarness): geometry.export_to_xml() source = openmc.Source() - source.space = openmc.stats.Point((0,0,0)) + source.space = openmc.stats.Point((0, 0, 0)) source.angle = openmc.stats.Monodirectional() source.energy = openmc.stats.Discrete([14.0e6], [1.0]) source.particle = 'neutron' diff --git a/tests/regression_tests/resonance_scattering/test.py b/tests/regression_tests/resonance_scattering/test.py index c83005ff2c..588ba7c977 100644 --- a/tests/regression_tests/resonance_scattering/test.py +++ b/tests/regression_tests/resonance_scattering/test.py @@ -17,7 +17,7 @@ class ResonanceScatteringTestHarness(PyAPITestHarness): mats_file.export_to_xml() # Geometry - dumb_surface = openmc.XPlane(x0=100, boundary_type='reflective') + dumb_surface = openmc.XPlane(100, 'reflective') c1 = openmc.Cell(cell_id=1, fill=mat, region=-dumb_surface) root_univ = openmc.Universe(universe_id=0, cells=[c1]) geometry = openmc.Geometry(root_univ) diff --git a/tests/regression_tests/salphabeta/test.py b/tests/regression_tests/salphabeta/test.py index ab5305126e..f487723dee 100644 --- a/tests/regression_tests/salphabeta/test.py +++ b/tests/regression_tests/salphabeta/test.py @@ -44,11 +44,11 @@ def make_model(): model.materials += [m1, m2, m3, m4] # Geometry - x0 = openmc.XPlane(x0=-10, boundary_type='vacuum') - x1 = openmc.XPlane(x0=-5) - x2 = openmc.XPlane(x0=0) - x3 = openmc.XPlane(x0=5) - x4 = openmc.XPlane(x0=10, boundary_type='vacuum') + x0 = openmc.XPlane(-10, 'vacuum') + x1 = openmc.XPlane(-5) + x2 = openmc.XPlane(0) + x3 = openmc.XPlane(5) + x4 = openmc.XPlane(10, 'vacuum') root_univ = openmc.Universe() diff --git a/tests/regression_tests/triso/test.py b/tests/regression_tests/triso/test.py index aa1bf08289..7bef80ea87 100644 --- a/tests/regression_tests/triso/test.py +++ b/tests/regression_tests/triso/test.py @@ -54,12 +54,12 @@ class TRISOTestHarness(PyAPITestHarness): inner_univ = openmc.Universe(cells=[c1, c2, c3, c4, c5]) # Define box to contain lattice and to pack TRISO particles in - min_x = openmc.XPlane(x0=-0.5, boundary_type='reflective') - max_x = openmc.XPlane(x0=0.5, boundary_type='reflective') - min_y = openmc.YPlane(y0=-0.5, boundary_type='reflective') - max_y = openmc.YPlane(y0=0.5, boundary_type='reflective') - min_z = openmc.ZPlane(z0=-0.5, boundary_type='reflective') - max_z = openmc.ZPlane(z0=0.5, boundary_type='reflective') + min_x = openmc.XPlane(-0.5, 'reflective') + max_x = openmc.XPlane(0.5, 'reflective') + min_y = openmc.YPlane(-0.5, 'reflective') + max_y = openmc.YPlane(0.5, 'reflective') + min_z = openmc.ZPlane(-0.5, 'reflective') + max_z = openmc.ZPlane(0.5, 'reflective') box_region = +min_x & -max_x & +min_y & -max_y & +min_z & -max_z box = openmc.Cell(region=box_region) diff --git a/tests/regression_tests/volume_calc/test.py b/tests/regression_tests/volume_calc/test.py index da8399c1fd..8ea4ab04e0 100644 --- a/tests/regression_tests/volume_calc/test.py +++ b/tests/regression_tests/volume_calc/test.py @@ -25,11 +25,11 @@ class VolumeTest(PyAPITestHarness): materials = openmc.Materials((water, fuel)) materials.export_to_xml() - cyl = openmc.ZCylinder(1, r=1.0, boundary_type='vacuum') - top_sphere = openmc.Sphere(2, z0=5., r=1., boundary_type='vacuum') - top_plane = openmc.ZPlane(3, z0=5.) - bottom_sphere = openmc.Sphere(4, z0=-5., r=1., boundary_type='vacuum') - bottom_plane = openmc.ZPlane(5, z0=-5.) + cyl = openmc.ZCylinder(surface_id=1, r=1.0, boundary_type='vacuum') + top_sphere = openmc.Sphere(surface_id=2, z0=5., r=1., boundary_type='vacuum') + top_plane = openmc.ZPlane(surface_id=3, z0=5.) + bottom_sphere = openmc.Sphere(surface_id=4, z0=-5., r=1., boundary_type='vacuum') + bottom_plane = openmc.ZPlane(surface_id=5, z0=-5.) # Define geometry inside_cyl = openmc.Cell(1, fill=fuel, region=-cyl & -top_plane & +bottom_plane) diff --git a/tests/unit_tests/__init__.py b/tests/unit_tests/__init__.py index 59a520c12a..e97ab13e2a 100644 --- a/tests/unit_tests/__init__.py +++ b/tests/unit_tests/__init__.py @@ -1,7 +1,14 @@ +import shutil + import numpy as np import pytest +# Check if NJOY is available +needs_njoy = pytest.mark.skipif(shutil.which('njoy') is None, + reason="NJOY not installed") + + def assert_unbounded(obj): """Assert that a region/cell is unbounded.""" ll, ur = obj.bounding_box diff --git a/tests/unit_tests/conftest.py b/tests/unit_tests/conftest.py index b69ef0b138..926535a9c8 100644 --- a/tests/unit_tests/conftest.py +++ b/tests/unit_tests/conftest.py @@ -108,11 +108,11 @@ def mixed_lattice_model(uo2, water): [empty_univ, u] ] - xmin = openmc.XPlane(x0=-d, boundary_type='periodic') - xmax = openmc.XPlane(x0=d, boundary_type='periodic') + xmin = openmc.XPlane(-d, 'periodic') + xmax = openmc.XPlane(d, 'periodic') xmin.periodic_surface = xmax - ymin = openmc.YPlane(y0=-d, boundary_type='periodic') - ymax = openmc.YPlane(y0=d, boundary_type='periodic') + ymin = openmc.YPlane(-d, 'periodic') + ymax = openmc.YPlane(d, 'periodic') main_cell = openmc.Cell(fill=rect_lattice, region=+xmin & -xmax & +ymin & -ymax) diff --git a/tests/unit_tests/dagmc/test.py b/tests/unit_tests/dagmc/test.py index bfe054dd82..f7b2844f6a 100644 --- a/tests/unit_tests/dagmc/test.py +++ b/tests/unit_tests/dagmc/test.py @@ -4,12 +4,12 @@ import numpy as np import pytest import openmc -import openmc.capi +import openmc.lib from tests import cdtemp pytestmark = pytest.mark.skipif( - not openmc.capi._dagmc_enabled(), + not openmc.lib._dagmc_enabled(), reason="DAGMC CAD geometry is not enabled.") @@ -60,15 +60,15 @@ def dagmc_model(request): with cdtemp(): shutil.copyfile(dagmc_file, "./dagmc.h5m") model.export_to_xml() - openmc.capi.init() + openmc.lib.init() yield - openmc.capi.finalize() + openmc.lib.finalize() @pytest.mark.parametrize("cell_id,exp_temp", ((1, 320.0), # assigned by material (2, 300.0), # assigned in dagmc file (3, 293.6))) # assigned by default def test_dagmc_temperatures(cell_id, exp_temp): - cell = openmc.capi.cells[cell_id] + cell = openmc.lib.cells[cell_id] assert np.isclose(cell.get_temperature(), exp_temp) diff --git a/tests/unit_tests/test_complex_cell_capi.py b/tests/unit_tests/test_complex_cell_bb.py similarity index 76% rename from tests/unit_tests/test_complex_cell_capi.py rename to tests/unit_tests/test_complex_cell_bb.py index a76fa63076..39431684d9 100644 --- a/tests/unit_tests/test_complex_cell_capi.py +++ b/tests/unit_tests/test_complex_cell_bb.py @@ -1,5 +1,5 @@ import numpy as np -import openmc.capi +import openmc.lib import pytest @pytest.fixture(autouse=True) @@ -27,21 +27,21 @@ def complex_cell(run_in_tmpdir, mpi_intracomm): model.materials = (u235, u238, zr90, n14) - s1 = openmc.XPlane(x0=-10.0, boundary_type='vacuum') - s2 = openmc.XPlane(x0=-7.0) - s3 = openmc.XPlane(x0=-4.0) - s4 = openmc.XPlane(x0=4.0) - s5 = openmc.XPlane(x0=7.0) - s6 = openmc.XPlane(x0=10.0, boundary_type='vacuum') - s7 = openmc.XPlane(x0=0.0) + s1 = openmc.XPlane(-10.0, 'vacuum') + s2 = openmc.XPlane(-7.0) + s3 = openmc.XPlane(-4.0) + s4 = openmc.XPlane(4.0) + s5 = openmc.XPlane(7.0) + s6 = openmc.XPlane(10.0, 'vacuum') + s7 = openmc.XPlane(0.0) - s11 = openmc.YPlane(y0=-10.0, boundary_type='vacuum') - s12 = openmc.YPlane(y0=-7.0) - s13 = openmc.YPlane(y0=-4.0) - s14 = openmc.YPlane(y0=4.0) - s15 = openmc.YPlane(y0=7.0) - s16 = openmc.YPlane(y0=10.0, boundary_type='vacuum') - s17 = openmc.YPlane(y0=0.0) + s11 = openmc.YPlane(-10.0, 'vacuum') + s12 = openmc.YPlane(-7.0) + s13 = openmc.YPlane(-4.0) + s14 = openmc.YPlane(4.0) + s15 = openmc.YPlane(7.0) + s16 = openmc.YPlane(10.0, 'vacuum') + s17 = openmc.YPlane(0.0) c1 = openmc.Cell(fill=u235) c1.region = ~(-s3 | +s4 | ~(+s13 & -s14)) @@ -73,12 +73,12 @@ def complex_cell(run_in_tmpdir, mpi_intracomm): model.export_to_xml() - openmc.capi.finalize() - openmc.capi.init(intracomm=mpi_intracomm) + openmc.lib.finalize() + openmc.lib.init(intracomm=mpi_intracomm) yield - openmc.capi.finalize() + openmc.lib.finalize() expected_results = ( (1, (( -4., -4., -np.inf), @@ -93,6 +93,6 @@ expected_results = ( (1, (( -4., -4., -np.inf), ( np.inf, np.inf, np.inf))) ) @pytest.mark.parametrize("cell_id,expected_box", expected_results) def test_cell_box(cell_id, expected_box): - cell_box = openmc.capi.cells[cell_id].bounding_box + cell_box = openmc.lib.cells[cell_id].bounding_box assert tuple(cell_box[0]) == expected_box[0] assert tuple(cell_box[1]) == expected_box[1] diff --git a/tests/unit_tests/test_data_neutron.py b/tests/unit_tests/test_data_neutron.py index 40a286331e..ed83956031 100644 --- a/tests/unit_tests/test_data_neutron.py +++ b/tests/unit_tests/test_data_neutron.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - from collections.abc import Mapping, Callable import os @@ -8,6 +6,7 @@ import pandas as pd import pytest import openmc.data +from . import needs_njoy _TEMPERATURES = [300., 600., 900.] _ENDF_DATA = os.environ['OPENMC_ENDF_DATA'] @@ -198,6 +197,7 @@ def test_fission(pu239): assert photon.particle == 'photon' +@needs_njoy def test_derived_products(am244): fission = am244.reactions[18] total_neutron = fission.derived_products[0] @@ -236,6 +236,7 @@ def test_urr(pu239): assert ptable.table.shape[0] == ptable.energy.size +@needs_njoy def test_get_reaction_components(h2): assert h2.get_reaction_components(1) == [2, 16, 102] assert h2.get_reaction_components(101) == [102] @@ -453,6 +454,7 @@ def test_laboratory(be9): assert np.all((-1. <= mu.x) & (mu.x <= 1.)) +@needs_njoy def test_correlated(tmpdir): endf_file = os.path.join(_ENDF_DATA, 'neutrons', 'n-014_Si_030.endf') si30 = openmc.data.IncidentNeutron.from_njoy(endf_file, heatr=False) @@ -463,6 +465,7 @@ def test_correlated(tmpdir): si30_copy = openmc.data.IncidentNeutron.from_hdf5(filename) +@needs_njoy def test_nbody(tmpdir, h2): # Convert to HDF5 and read back filename = str(tmpdir.join('h2.h5')) @@ -477,6 +480,7 @@ def test_nbody(tmpdir, h2): assert nbody1.q_value == nbody2.q_value +@needs_njoy def test_ace_convert(run_in_tmpdir): filename = os.path.join(_ENDF_DATA, 'neutrons', 'n-001_H_001.endf') ace_ascii = 'ace_ascii' diff --git a/tests/unit_tests/test_data_thermal.py b/tests/unit_tests/test_data_thermal.py index 47cbe27b97..2d8d7de2c4 100644 --- a/tests/unit_tests/test_data_thermal.py +++ b/tests/unit_tests/test_data_thermal.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - from collections.abc import Callable from math import exp import os @@ -9,6 +7,8 @@ import numpy as np import pytest import openmc.data +from . import needs_njoy + _ENDF_DATA = os.environ['OPENMC_ENDF_DATA'] @@ -101,6 +101,7 @@ def test_graphite_xs(graphite): assert elastic([1e-3, 1.0]) == pytest.approx([0.0, 0.62586153]) +@needs_njoy def test_graphite_njoy(): path_c0 = os.path.join(_ENDF_DATA, 'neutrons', 'n-006_C_000.endf') path_gr = os.path.join(_ENDF_DATA, 'thermal_scatt', 'tsl-graphite.endf') @@ -112,6 +113,7 @@ def test_graphite_njoy(): assert graphite.temperatures == ['296K'] +@needs_njoy def test_export_to_hdf5(tmpdir, h2o_njoy, hzrh_njoy, graphite): filename = str(tmpdir.join('water.h5')) h2o_njoy.export_to_hdf5(filename) @@ -131,6 +133,7 @@ def test_export_to_hdf5(tmpdir, h2o_njoy, hzrh_njoy, graphite): assert os.path.exists(filename) +@needs_njoy def test_continuous_dist(h2o_njoy): for temperature, dist in h2o_njoy.inelastic.distribution.items(): assert temperature.endswith('K') @@ -173,6 +176,7 @@ def test_hzrh_elastic(hzrh): assert dist.debye_waller > 0.0 +@needs_njoy def test_hzrh_njoy(hzrh_njoy): endf, ace = hzrh_njoy diff --git a/tests/unit_tests/test_deplete_chain.py b/tests/unit_tests/test_deplete_chain.py index 3dcd3ad750..d5a3857a52 100644 --- a/tests/unit_tests/test_deplete_chain.py +++ b/tests/unit_tests/test_deplete_chain.py @@ -385,13 +385,13 @@ def test_set_alpha_branches(): def test_simple_fission_yields(simple_chain): """Check the default fission yields that can be used to form the matrix """ - fission_yields = simple_chain.get_thermal_fission_yields() + fission_yields = simple_chain.get_default_fission_yields() assert fission_yields == {"C": {"A": 0.0292737, "B": 0.002566345}} def test_fission_yield_attribute(simple_chain): """Test the fission_yields property""" - thermal_yields = simple_chain.get_thermal_fission_yields() + thermal_yields = simple_chain.get_default_fission_yields() # generate default with property assert simple_chain.fission_yields[0] == thermal_yields empty_chain = Chain() diff --git a/tests/unit_tests/test_deplete_fission_yields.py b/tests/unit_tests/test_deplete_fission_yields.py index bedd702a90..854c530f95 100644 --- a/tests/unit_tests/test_deplete_fission_yields.py +++ b/tests/unit_tests/test_deplete_fission_yields.py @@ -8,7 +8,7 @@ import bisect import pytest import numpy as np import openmc -from openmc import capi +from openmc import lib from openmc.deplete.nuclide import Nuclide, FissionYieldDistribution from openmc.deplete.helpers import ( FissionYieldCutoffHelper, ConstantFissionYieldHelper, @@ -18,7 +18,7 @@ from openmc.deplete.helpers import ( @pytest.fixture(scope="module") def materials(tmpdir_factory): """Use C API to construct realistic materials for testing tallies""" - tmpdir = tmpdir_factory.mktemp("capi") + tmpdir = tmpdir_factory.mktemp("lib") orig = tmpdir.chdir() # Create proxy problem to please openmc mfuel = openmc.Material(name="test_fuel") @@ -40,8 +40,8 @@ def materials(tmpdir_factory): settings.export_to_xml() try: - with capi.run_in_memory(): - yield [capi.Material(), capi.Material()] + with lib.run_in_memory(): + yield [lib.Material(), lib.Material()] finally: # Convert to strings as os.remove in py 3.5 doesn't support Paths for file_path in ("settings.xml", "geometry.xml", "materials.xml", @@ -64,7 +64,7 @@ def proxy_tally_data(tally, fill=None): if not hasattr(tfilter, "bins"): continue this_bins = len(tfilter.bins) - if isinstance(tfilter, capi.EnergyFilter): + if isinstance(tfilter, lib.EnergyFilter): this_bins -= 1 n_bins *= max(this_bins, 1) data = np.empty((n_bins, n_nucs * n_scores, 3)) @@ -192,9 +192,9 @@ def test_cutoff_helper(materials, nuclide_bundle, therm_frac): assert fission_tally is not None filters = fission_tally.filters assert len(filters) == 2 - assert isinstance(filters[0], capi.MaterialFilter) + assert isinstance(filters[0], lib.MaterialFilter) assert len(filters[0].bins) == len(materials) - assert isinstance(filters[1], capi.EnergyFilter) + assert isinstance(filters[1], lib.EnergyFilter) # lower, cutoff, and upper energy assert len(filters[1].bins) == 3 @@ -235,9 +235,9 @@ def test_averaged_helper(materials, nuclide_bundle, avg_energy): assert fission_tally is not None fission_filters = fission_tally.filters assert len(fission_filters) == 2 - assert isinstance(fission_filters[0], capi.MaterialFilter) + assert isinstance(fission_filters[0], lib.MaterialFilter) assert len(fission_filters[0].bins) == len(materials) - assert isinstance(fission_filters[1], capi.EnergyFilter) + assert isinstance(fission_filters[1], lib.EnergyFilter) assert len(fission_filters[1].bins) == 2 assert fission_tally.scores == ["fission"] assert fission_tally.nuclides == list(tallied_nucs) @@ -246,9 +246,9 @@ def test_averaged_helper(materials, nuclide_bundle, avg_energy): assert weighted_tally is not None weighted_filters = weighted_tally.filters assert len(weighted_filters) == 2 - assert isinstance(weighted_filters[0], capi.MaterialFilter) + assert isinstance(weighted_filters[0], lib.MaterialFilter) assert len(weighted_filters[0].bins) == len(materials) - assert isinstance(weighted_filters[1], capi.EnergyFunctionFilter) + assert isinstance(weighted_filters[1], lib.EnergyFunctionFilter) assert len(weighted_filters[1].energy) == 2 assert len(weighted_filters[1].y) == 2 assert weighted_tally.scores == ["fission"] diff --git a/tests/unit_tests/test_capi.py b/tests/unit_tests/test_lib.py similarity index 67% rename from tests/unit_tests/test_capi.py rename to tests/unit_tests/test_lib.py index c8ad0907c5..2f39f0b0d3 100644 --- a/tests/unit_tests/test_capi.py +++ b/tests/unit_tests/test_lib.py @@ -5,7 +5,7 @@ import numpy as np import pytest import openmc import openmc.exceptions as exc -import openmc.capi +import openmc.lib from tests import cdtemp @@ -51,42 +51,42 @@ def pincell_model(): @pytest.fixture(scope='module') def capi_init(pincell_model, mpi_intracomm): - openmc.capi.init(intracomm=mpi_intracomm) + openmc.lib.init(intracomm=mpi_intracomm) yield - openmc.capi.finalize() + openmc.lib.finalize() @pytest.fixture(scope='module') def capi_simulation_init(capi_init): - openmc.capi.simulation_init() + openmc.lib.simulation_init() yield @pytest.fixture(scope='module') def capi_run(capi_simulation_init): - openmc.capi.run() + openmc.lib.run() def test_cell_mapping(capi_init): - cells = openmc.capi.cells + cells = openmc.lib.cells assert isinstance(cells, Mapping) assert len(cells) == 3 for cell_id, cell in cells.items(): - assert isinstance(cell, openmc.capi.Cell) + assert isinstance(cell, openmc.lib.Cell) assert cell_id == cell.id def test_cell(capi_init): - cell = openmc.capi.cells[1] - assert isinstance(cell.fill, openmc.capi.Material) - cell.fill = openmc.capi.materials[1] + cell = openmc.lib.cells[1] + assert isinstance(cell.fill, openmc.lib.Material) + cell.fill = openmc.lib.materials[1] assert str(cell) == 'Cell[0]' assert cell.name == "Fuel" cell.name = "Not fuel" assert cell.name == "Not fuel" def test_cell_temperature(capi_init): - cell = openmc.capi.cells[1] + cell = openmc.lib.cells[1] cell.set_temperature(100.0, 0) assert cell.get_temperature(0) == 100.0 cell.set_temperature(200) @@ -95,23 +95,23 @@ def test_cell_temperature(capi_init): def test_new_cell(capi_init): with pytest.raises(exc.AllocationError): - openmc.capi.Cell(1) - new_cell = openmc.capi.Cell() - new_cell_with_id = openmc.capi.Cell(10) - assert len(openmc.capi.cells) == 5 + openmc.lib.Cell(1) + new_cell = openmc.lib.Cell() + new_cell_with_id = openmc.lib.Cell(10) + assert len(openmc.lib.cells) == 5 def test_material_mapping(capi_init): - mats = openmc.capi.materials + mats = openmc.lib.materials assert isinstance(mats, Mapping) assert len(mats) == 3 for mat_id, mat in mats.items(): - assert isinstance(mat, openmc.capi.Material) + assert isinstance(mat, openmc.lib.Material) assert mat_id == mat.id def test_material(capi_init): - m = openmc.capi.materials[3] + m = openmc.lib.materials[3] assert m.nuclides == ['H1', 'O16', 'B10', 'B11'] old_dens = m.densities @@ -137,7 +137,7 @@ def test_material(capi_init): assert m.name == "Not hot borated water" def test_material_add_nuclide(capi_init): - m = openmc.capi.materials[3] + m = openmc.lib.materials[3] m.add_nuclide('Xe135', 1e-12) assert m.nuclides[-1] == 'Xe135' assert m.densities[-1] == 1e-12 @@ -145,23 +145,23 @@ def test_material_add_nuclide(capi_init): def test_new_material(capi_init): with pytest.raises(exc.AllocationError): - openmc.capi.Material(1) - new_mat = openmc.capi.Material() - new_mat_with_id = openmc.capi.Material(10) - assert len(openmc.capi.materials) == 5 + openmc.lib.Material(1) + new_mat = openmc.lib.Material() + new_mat_with_id = openmc.lib.Material(10) + assert len(openmc.lib.materials) == 5 def test_nuclide_mapping(capi_init): - nucs = openmc.capi.nuclides + nucs = openmc.lib.nuclides assert isinstance(nucs, Mapping) assert len(nucs) == 13 for name, nuc in nucs.items(): - assert isinstance(nuc, openmc.capi.Nuclide) + assert isinstance(nuc, openmc.lib.Nuclide) assert name == nuc.name def test_settings(capi_init): - settings = openmc.capi.settings + settings = openmc.lib.settings assert settings.batches == 10 settings.batches = 10 assert settings.inactive == 5 @@ -176,17 +176,17 @@ def test_settings(capi_init): def test_tally_mapping(capi_init): - tallies = openmc.capi.tallies + tallies = openmc.lib.tallies assert isinstance(tallies, Mapping) assert len(tallies) == 3 for tally_id, tally in tallies.items(): - assert isinstance(tally, openmc.capi.Tally) + assert isinstance(tally, openmc.lib.Tally) assert tally_id == tally.id def test_energy_function_filter(capi_init): """Test special __new__ and __init__ for EnergyFunctionFilter""" - efunc = openmc.capi.EnergyFunctionFilter([0.0, 1.0], [0.0, 2.0]) + efunc = openmc.lib.EnergyFunctionFilter([0.0, 1.0], [0.0, 2.0]) assert len(efunc.energy) == 2 assert (efunc.energy == [0.0, 1.0]).all() assert len(efunc.y) == 2 @@ -194,17 +194,17 @@ def test_energy_function_filter(capi_init): def test_tally(capi_init): - t = openmc.capi.tallies[1] + t = openmc.lib.tallies[1] assert t.type == 'volume' assert len(t.filters) == 2 - assert isinstance(t.filters[0], openmc.capi.MaterialFilter) - assert isinstance(t.filters[1], openmc.capi.EnergyFilter) + assert isinstance(t.filters[0], openmc.lib.MaterialFilter) + assert isinstance(t.filters[1], openmc.lib.EnergyFilter) # Create new filter and replace existing with pytest.raises(exc.AllocationError): - openmc.capi.MaterialFilter(uid=1) - mats = openmc.capi.materials - f = openmc.capi.MaterialFilter([mats[2], mats[1]]) + openmc.lib.MaterialFilter(uid=1) + mats = openmc.lib.materials + f = openmc.lib.MaterialFilter([mats[2], mats[1]]) assert f.bins[0] == mats[2] assert f.bins[1] == mats[1] t.filters = [f] @@ -221,17 +221,17 @@ def test_tally(capi_init): t.scores = new_scores assert t.scores == new_scores - t2 = openmc.capi.tallies[2] + t2 = openmc.lib.tallies[2] assert len(t2.filters) == 2 - assert isinstance(t2.filters[0], openmc.capi.ZernikeFilter) - assert isinstance(t2.filters[1], openmc.capi.CellFilter) + assert isinstance(t2.filters[0], openmc.lib.ZernikeFilter) + assert isinstance(t2.filters[1], openmc.lib.CellFilter) assert len(t2.filters[1].bins) == 3 assert t2.filters[0].order == 5 - t3 = openmc.capi.tallies[3] + t3 = openmc.lib.tallies[3] assert len(t3.filters) == 1 t3_f = t3.filters[0] - assert isinstance(t3_f, openmc.capi.EnergyFunctionFilter) + assert isinstance(t3_f, openmc.lib.EnergyFunctionFilter) assert len(t3_f.energy) == 2 assert len(t3_f.y) == 2 t3_f.set_data([0.0, 1.0, 2.0], [0.0, 1.0, 4.0]) @@ -241,144 +241,144 @@ def test_tally(capi_init): def test_new_tally(capi_init): with pytest.raises(exc.AllocationError): - openmc.capi.Material(1) - new_tally = openmc.capi.Tally() + openmc.lib.Material(1) + new_tally = openmc.lib.Tally() new_tally.scores = ['flux'] - new_tally_with_id = openmc.capi.Tally(10) + new_tally_with_id = openmc.lib.Tally(10) new_tally_with_id.scores = ['flux'] - assert len(openmc.capi.tallies) == 5 + assert len(openmc.lib.tallies) == 5 def test_tally_activate(capi_simulation_init): - t = openmc.capi.tallies[1] + t = openmc.lib.tallies[1] assert not t.active t.active = True assert t.active def test_tally_results(capi_run): - t = openmc.capi.tallies[1] + t = openmc.lib.tallies[1] assert t.num_realizations == 10 # t was made active in test_tally assert np.all(t.mean >= 0) nonzero = (t.mean > 0.0) 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] + t2 = openmc.lib.tallies[2] n = 5 assert t2.mean.size == (n + 1) * (n + 2) // 2 * 3 # Number of Zernike coeffs * 3 cells def test_global_tallies(capi_run): - assert openmc.capi.num_realizations() == 5 - gt = openmc.capi.global_tallies() + assert openmc.lib.num_realizations() == 5 + gt = openmc.lib.global_tallies() for mean, std_dev in gt: assert mean >= 0 def test_statepoint(capi_run): - openmc.capi.statepoint_write('test_sp.h5') + openmc.lib.statepoint_write('test_sp.h5') assert os.path.exists('test_sp.h5') def test_source_bank(capi_run): - source = openmc.capi.source_bank() + source = openmc.lib.source_bank() assert np.all(source['E'] > 0.0) assert np.all(source['wgt'] == 1.0) assert np.allclose(np.linalg.norm(source['u'], axis=1), 1.0) def test_by_batch(capi_run): - openmc.capi.hard_reset() + openmc.lib.hard_reset() # Running next batch before simulation is initialized should raise an # exception with pytest.raises(exc.AllocationError): - openmc.capi.next_batch() + openmc.lib.next_batch() - openmc.capi.simulation_init() + openmc.lib.simulation_init() try: - for _ in openmc.capi.iter_batches(): + for _ in openmc.lib.iter_batches(): # Make sure we can get k-effective during inactive/active batches - mean, std_dev = openmc.capi.keff() + mean, std_dev = openmc.lib.keff() assert 0.0 < mean < 2.5 assert std_dev > 0.0 - assert openmc.capi.num_realizations() == 5 + assert openmc.lib.num_realizations() == 5 for i in range(3): - openmc.capi.next_batch() - assert openmc.capi.num_realizations() == 8 + openmc.lib.next_batch() + assert openmc.lib.num_realizations() == 8 finally: - openmc.capi.simulation_finalize() + openmc.lib.simulation_finalize() def test_reset(capi_run): # Init and run 10 batches. - openmc.capi.hard_reset() - openmc.capi.simulation_init() + openmc.lib.hard_reset() + openmc.lib.simulation_init() try: for i in range(10): - openmc.capi.next_batch() + openmc.lib.next_batch() # Make sure there are 5 realizations for the 5 active batches. - assert openmc.capi.num_realizations() == 5 - assert openmc.capi.tallies[2].num_realizations == 5 - _, keff_sd1 = openmc.capi.keff() - tally_sd1 = openmc.capi.tallies[2].std_dev[0] + assert openmc.lib.num_realizations() == 5 + assert openmc.lib.tallies[2].num_realizations == 5 + _, keff_sd1 = openmc.lib.keff() + tally_sd1 = openmc.lib.tallies[2].std_dev[0] # Reset and run 3 more batches. Check the number of realizations. - openmc.capi.reset() + openmc.lib.reset() for i in range(3): - openmc.capi.next_batch() - assert openmc.capi.num_realizations() == 3 - assert openmc.capi.tallies[2].num_realizations == 3 + openmc.lib.next_batch() + assert openmc.lib.num_realizations() == 3 + assert openmc.lib.tallies[2].num_realizations == 3 # Check the tally std devs to make sure results were cleared. - _, keff_sd2 = openmc.capi.keff() - tally_sd2 = openmc.capi.tallies[2].std_dev[0] + _, keff_sd2 = openmc.lib.keff() + tally_sd2 = openmc.lib.tallies[2].std_dev[0] assert keff_sd2 > keff_sd1 assert tally_sd2 > tally_sd1 finally: - openmc.capi.simulation_finalize() + openmc.lib.simulation_finalize() def test_reproduce_keff(capi_init): # Get k-effective after run - openmc.capi.hard_reset() - openmc.capi.run() - keff0 = openmc.capi.keff() + openmc.lib.hard_reset() + openmc.lib.run() + keff0 = openmc.lib.keff() # Reset, run again, and get k-effective again. they should match - openmc.capi.hard_reset() - openmc.capi.run() - keff1 = openmc.capi.keff() + openmc.lib.hard_reset() + openmc.lib.run() + keff1 = openmc.lib.keff() assert keff0 == pytest.approx(keff1) def test_find_cell(capi_init): - cell, instance = openmc.capi.find_cell((0., 0., 0.)) - assert cell is openmc.capi.cells[1] - cell, instance = openmc.capi.find_cell((0.4, 0., 0.)) - assert cell is openmc.capi.cells[2] + cell, instance = openmc.lib.find_cell((0., 0., 0.)) + assert cell is openmc.lib.cells[1] + cell, instance = openmc.lib.find_cell((0.4, 0., 0.)) + assert cell is openmc.lib.cells[2] with pytest.raises(exc.GeometryError): - openmc.capi.find_cell((100., 100., 100.)) + openmc.lib.find_cell((100., 100., 100.)) def test_find_material(capi_init): - mat = openmc.capi.find_material((0., 0., 0.)) - assert mat is openmc.capi.materials[1] - mat = openmc.capi.find_material((0.4, 0., 0.)) - assert mat is openmc.capi.materials[2] + mat = openmc.lib.find_material((0., 0., 0.)) + assert mat is openmc.lib.materials[1] + mat = openmc.lib.find_material((0.4, 0., 0.)) + assert mat is openmc.lib.materials[2] def test_mesh(capi_init): - mesh = openmc.capi.RegularMesh() + mesh = openmc.lib.RegularMesh() mesh.dimension = (2, 3, 4) assert mesh.dimension == (2, 3, 4) with pytest.raises(exc.AllocationError): - mesh2 = openmc.capi.RegularMesh(mesh.id) + mesh2 = openmc.lib.RegularMesh(mesh.id) # Make sure each combination of parameters works ll = (0., 0., 0.) @@ -394,47 +394,47 @@ def test_mesh(capi_init): assert mesh.upper_right == pytest.approx(ur) assert mesh.width == pytest.approx(width) - meshes = openmc.capi.meshes + meshes = openmc.lib.meshes assert isinstance(meshes, Mapping) assert len(meshes) == 1 for mesh_id, mesh in meshes.items(): - assert isinstance(mesh, openmc.capi.RegularMesh) + assert isinstance(mesh, openmc.lib.RegularMesh) assert mesh_id == mesh.id - mf = openmc.capi.MeshFilter(mesh) + mf = openmc.lib.MeshFilter(mesh) assert mf.mesh == mesh - msf = openmc.capi.MeshSurfaceFilter(mesh) + msf = openmc.lib.MeshSurfaceFilter(mesh) assert msf.mesh == mesh def test_restart(capi_init, mpi_intracomm): # Finalize and re-init to make internal state consistent with XML. - openmc.capi.hard_reset() - openmc.capi.finalize() - openmc.capi.init(intracomm=mpi_intracomm) - openmc.capi.simulation_init() + openmc.lib.hard_reset() + openmc.lib.finalize() + openmc.lib.init(intracomm=mpi_intracomm) + openmc.lib.simulation_init() # Run for 7 batches then write a statepoint. for i in range(7): - openmc.capi.next_batch() - openmc.capi.statepoint_write('restart_test.h5', True) + openmc.lib.next_batch() + openmc.lib.statepoint_write('restart_test.h5', True) # Run 3 more batches and copy the keff. for i in range(3): - openmc.capi.next_batch() - keff0 = openmc.capi.keff() + openmc.lib.next_batch() + keff0 = openmc.lib.keff() # Restart the simulation from the statepoint and the 3 remaining active batches. - openmc.capi.simulation_finalize() - openmc.capi.hard_reset() - openmc.capi.finalize() - openmc.capi.init(args=('-r', 'restart_test.h5')) - openmc.capi.simulation_init() + openmc.lib.simulation_finalize() + openmc.lib.hard_reset() + openmc.lib.finalize() + openmc.lib.init(args=('-r', 'restart_test.h5')) + openmc.lib.simulation_init() for i in range(3): - openmc.capi.next_batch() - keff1 = openmc.capi.keff() - openmc.capi.simulation_finalize() + openmc.lib.next_batch() + keff1 = openmc.lib.keff() + openmc.lib.simulation_finalize() # Compare the keff values. assert keff0 == pytest.approx(keff1) @@ -442,13 +442,13 @@ def test_restart(capi_init, mpi_intracomm): def test_load_nuclide(capi_init): # load multiple nuclides - openmc.capi.load_nuclide('H3') - assert 'H3' in openmc.capi.nuclides - openmc.capi.load_nuclide('Pu239') - assert 'Pu239' in openmc.capi.nuclides + openmc.lib.load_nuclide('H3') + assert 'H3' in openmc.lib.nuclides + openmc.lib.load_nuclide('Pu239') + assert 'Pu239' in openmc.lib.nuclides # load non-existent nuclide with pytest.raises(exc.DataError): - openmc.capi.load_nuclide('Pu3') + openmc.lib.load_nuclide('Pu3') def test_id_map(capi_init): @@ -457,7 +457,7 @@ def test_id_map(capi_init): [(3, 3), (2, 2), (3, 3)]], dtype='int32') # create a plot object - s = openmc.capi.plot._PlotBase() + s = openmc.lib.plot._PlotBase() s.width = 1.26 s.height = 1.26 s.v_res = 3 @@ -466,7 +466,7 @@ def test_id_map(capi_init): s.basis = 'xy' s.level = -1 - ids = openmc.capi.plot.id_map(s) + ids = openmc.lib.plot.id_map(s) assert np.array_equal(expected_ids, ids) def test_property_map(capi_init): @@ -476,7 +476,7 @@ def test_property_map(capi_init): [(293.6, 0.740582), (293.6, 6.55), (293.6, 0.740582)]], dtype='float') # create a plot object - s = openmc.capi.plot._PlotBase() + s = openmc.lib.plot._PlotBase() s.width = 1.26 s.height = 1.26 s.v_res = 3 @@ -485,13 +485,13 @@ def test_property_map(capi_init): s.basis = 'xy' s.level = -1 - properties = openmc.capi.plot.property_map(s) + properties = openmc.lib.plot.property_map(s) assert np.allclose(expected_properties, properties, atol=1e-04) def test_position(capi_init): - pos = openmc.capi.plot._Position(1.0, 2.0, 3.0) + pos = openmc.lib.plot._Position(1.0, 2.0, 3.0) assert tuple(pos) == (1.0, 2.0, 3.0) @@ -506,7 +506,7 @@ def test_global_bounding_box(capi_init): expected_llc = (-0.63, -0.63, -np.inf) expected_urc = (0.63, 0.63, np.inf) - llc, urc = openmc.capi.global_bounding_box() + llc, urc = openmc.lib.global_bounding_box() assert tuple(llc) == expected_llc assert tuple(urc) == expected_urc diff --git a/tests/unit_tests/test_math.py b/tests/unit_tests/test_math.py index e6b2ddecd6..7c0218fbd7 100644 --- a/tests/unit_tests/test_math.py +++ b/tests/unit_tests/test_math.py @@ -2,7 +2,7 @@ import numpy as np import scipy as sp import openmc -import openmc.capi +import openmc.lib import pytest @@ -15,10 +15,10 @@ def test_t_percentile(): # The reference solutions come from Scipy ref_ts = [[sp.stats.t.ppf(p, df) for p in test_ps] for df in test_dfs] - test_ts = [[openmc.capi.math.t_percentile(p, df) for p in test_ps] + test_ts = [[openmc.lib.math.t_percentile(p, df) for p in test_ps] for df in test_dfs] - # The 5 DoF approximation in openmc.capi.math.t_percentile is off by up to + # The 5 DoF approximation in openmc.lib.math.t_percentile is off by up to # 8e-3 from the scipy solution, so test that one separately with looser # tolerance assert np.allclose(ref_ts[:-1], test_ts[:-1]) @@ -35,7 +35,7 @@ def test_calc_pn(): test_vals = [] for x in test_xs: - test_vals.append(openmc.capi.math.calc_pn(max_order, x).tolist()) + test_vals.append(openmc.lib.math.calc_pn(max_order, x).tolist()) test_vals = np.swapaxes(np.array(test_vals), 0, 1) @@ -55,7 +55,7 @@ def test_evaluate_legendre(): # evaluate legendre incorporates the (2l+1)/2 term on its own test_coeffs = [1. for l in range(max_order + 1)] - test_vals = np.array([openmc.capi.math.evaluate_legendre(test_coeffs, x) + test_vals = np.array([openmc.lib.math.evaluate_legendre(test_coeffs, x) for x in test_xs]) assert np.allclose(ref_vals, test_vals) @@ -98,7 +98,7 @@ def test_calc_rn(): ref_vals.append(ylm) test_vals = [] - test_vals = openmc.capi.math.calc_rn(max_order, test_uvw) + test_vals = openmc.lib.math.calc_rn(max_order, test_uvw) assert np.allclose(ref_vals, test_vals) @@ -133,7 +133,7 @@ def test_calc_zn(): -8.98437500e-02, -1.08693628e-01, 1.78813094e-01, -1.98191857e-01, 1.65964201e-02, 2.77013853e-04]) - test_vals = openmc.capi.math.calc_zn(n, rho, phi) + test_vals = openmc.lib.math.calc_zn(n, rho, phi) assert np.allclose(ref_vals, test_vals) @@ -147,7 +147,7 @@ def test_calc_zn_rad(): 1.00000000e+00, -5.00000000e-01, -1.25000000e-01, 4.37500000e-01, -2.89062500e-01,-8.98437500e-02]) - test_vals = openmc.capi.math.calc_zn_rad(n, rho) + test_vals = openmc.lib.math.calc_zn_rad(n, rho) assert np.allclose(ref_vals, test_vals) @@ -160,7 +160,7 @@ def test_rotate_angle(): # reference: mu of 0 pulls the vector the bottom, so: ref_uvw = np.array([0., 0., -1.]) - test_uvw = openmc.capi.math.rotate_angle(uvw0, mu, phi) + test_uvw = openmc.lib.math.rotate_angle(uvw0, mu, phi) assert np.array_equal(ref_uvw, test_uvw) @@ -168,51 +168,51 @@ def test_rotate_angle(): mu = 1. ref_uvw = np.array([1., 0., 0.]) - test_uvw = openmc.capi.math.rotate_angle(uvw0, mu, phi) + test_uvw = openmc.lib.math.rotate_angle(uvw0, mu, phi) assert np.array_equal(ref_uvw, test_uvw) # Now to test phi is None mu = 0.9 - settings = openmc.capi.settings + settings = openmc.lib.settings settings.seed = 1 # When seed = 1, phi will be sampled as 1.9116495709698769 # The resultant reference is from hand-calculations given the above ref_uvw = [0.9, 0.410813051297112, 0.1457142302040] - test_uvw = openmc.capi.math.rotate_angle(uvw0, mu) + test_uvw = openmc.lib.math.rotate_angle(uvw0, mu) assert np.allclose(ref_uvw, test_uvw) def test_maxwell_spectrum(): - settings = openmc.capi.settings + settings = openmc.lib.settings settings.seed = 1 T = 0.5 ref_val = 0.6129982175261098 - test_val = openmc.capi.math.maxwell_spectrum(T) + test_val = openmc.lib.math.maxwell_spectrum(T) assert ref_val == test_val def test_watt_spectrum(): - settings = openmc.capi.settings + settings = openmc.lib.settings settings.seed = 1 a = 0.5 b = 0.75 ref_val = 0.6247242713640233 - test_val = openmc.capi.math.watt_spectrum(a, b) + test_val = openmc.lib.math.watt_spectrum(a, b) assert ref_val == test_val def test_normal_dist(): - settings = openmc.capi.settings + settings = openmc.lib.settings settings.seed = 1 a = 14.08 b = 0.0 ref_val = 14.08 - test_val = openmc.capi.math.normal_variate(a, b) + test_val = openmc.lib.math.normal_variate(a, b) assert ref_val == pytest.approx(test_val) @@ -220,7 +220,7 @@ def test_normal_dist(): a = 14.08 b = 1.0 ref_val = 16.436645416691427 - test_val = openmc.capi.math.normal_variate(a, b) + test_val = openmc.lib.math.normal_variate(a, b) assert ref_val == pytest.approx(test_val) @@ -234,13 +234,13 @@ def test_broaden_wmp_polynomials(): n = 6 ref_val = [2., 1.41421356, 1.0001, 0.70731891, 0.50030001, 0.353907] - test_val = openmc.capi.math.broaden_wmp_polynomials(test_E, test_dopp, n) + test_val = openmc.lib.math.broaden_wmp_polynomials(test_E, test_dopp, n) assert np.allclose(ref_val, test_val) # now beta < 6 test_dopp = 5. ref_val = [1.99999885, 1.41421356, 1.04, 0.79195959, 0.6224, 0.50346003] - test_val = openmc.capi.math.broaden_wmp_polynomials(test_E, test_dopp, n) + test_val = openmc.lib.math.broaden_wmp_polynomials(test_E, test_dopp, n) assert np.allclose(ref_val, test_val) diff --git a/tests/unit_tests/test_model_triso.py b/tests/unit_tests/test_model_triso.py index 782373414c..c1f8c039e5 100644 --- a/tests/unit_tests/test_model_triso.py +++ b/tests/unit_tests/test_model_triso.py @@ -34,12 +34,12 @@ def centers(request, container): @pytest.fixture(scope='module') def centers_rectangular_prism(): - min_x = openmc.XPlane(x0=0) - max_x = openmc.XPlane(x0=1) - min_y = openmc.YPlane(y0=0) - max_y = openmc.YPlane(y0=1) - min_z = openmc.ZPlane(z0=0) - max_z = openmc.ZPlane(z0=1) + min_x = openmc.XPlane(0) + max_x = openmc.XPlane(1) + min_y = openmc.YPlane(0) + max_y = openmc.YPlane(1) + min_z = openmc.ZPlane(0) + max_z = openmc.ZPlane(1) region = +min_x & -max_x & +min_y & -max_y & +min_z & -max_z return openmc.model.pack_spheres(radius=_RADIUS, region=region, pf=_PACKING_FRACTION, initial_pf=0.2) @@ -48,8 +48,8 @@ def centers_rectangular_prism(): @pytest.fixture(scope='module') def centers_x_cylinder(): cylinder = openmc.XCylinder(r=1, y0=1, z0=2) - min_x = openmc.XPlane(x0=0) - max_x = openmc.XPlane(x0=1) + min_x = openmc.XPlane(0) + max_x = openmc.XPlane(1) region = +min_x & -max_x & -cylinder return openmc.model.pack_spheres(radius=_RADIUS, region=region, pf=_PACKING_FRACTION, initial_pf=0.2) @@ -58,8 +58,8 @@ def centers_x_cylinder(): @pytest.fixture(scope='module') def centers_y_cylinder(): cylinder = openmc.YCylinder(r=1, x0=1, z0=2) - min_y = openmc.YPlane(y0=0) - max_y = openmc.YPlane(y0=1) + min_y = openmc.YPlane(0) + max_y = openmc.YPlane(1) region = +min_y & -max_y & -cylinder return openmc.model.pack_spheres(radius=_RADIUS, region=region, pf=_PACKING_FRACTION, initial_pf=0.2) @@ -68,8 +68,8 @@ def centers_y_cylinder(): @pytest.fixture(scope='module') def centers_z_cylinder(): cylinder = openmc.ZCylinder(r=1, x0=1, y0=2) - min_z = openmc.ZPlane(z0=0) - max_z = openmc.ZPlane(z0=1) + min_z = openmc.ZPlane(0) + max_z = openmc.ZPlane(1) region = +min_z & -max_z & -cylinder return openmc.model.pack_spheres(radius=_RADIUS, region=region, pf=_PACKING_FRACTION, initial_pf=0.2) diff --git a/tests/unit_tests/test_region.py b/tests/unit_tests/test_region.py index d1074fd7d9..f9656ebb4b 100644 --- a/tests/unit_tests/test_region.py +++ b/tests/unit_tests/test_region.py @@ -11,8 +11,8 @@ def reset(): def test_union(reset): - s1 = openmc.XPlane(surface_id=1, x0=5) - s2 = openmc.XPlane(surface_id=2, x0=-5) + s1 = openmc.XPlane(x0=5, surface_id=1) + s2 = openmc.XPlane(x0=-5, surface_id=2) region = +s1 | -s2 assert isinstance(region, openmc.Union) @@ -42,8 +42,8 @@ def test_union(reset): def test_intersection(reset): - s1 = openmc.XPlane(surface_id=1, x0=5) - s2 = openmc.XPlane(surface_id=2, x0=-5) + s1 = openmc.XPlane(x0=5, surface_id=1) + s2 = openmc.XPlane(x0=-5, surface_id=2) region = -s1 & +s2 assert isinstance(region, openmc.Intersection) @@ -75,9 +75,9 @@ def test_intersection(reset): def test_complement(reset): - zcyl = openmc.ZCylinder(surface_id=1, r=1.) - z0 = openmc.ZPlane(surface_id=2, z0=-5.) - z1 = openmc.ZPlane(surface_id=3, z0=5.) + zcyl = openmc.ZCylinder(r=1., surface_id=1) + z0 = openmc.ZPlane(-5., surface_id=2) + z1 = openmc.ZPlane(5., surface_id=3) outside = +zcyl | -z0 | +z1 inside = ~outside outside_equiv = ~(-zcyl & +z0 & -z1) @@ -151,8 +151,8 @@ def test_extend_clone(): def test_from_expression(reset): # Create surface dictionary s1 = openmc.ZCylinder(surface_id=1) - s2 = openmc.ZPlane(surface_id=2, z0=-10.) - s3 = openmc.ZPlane(surface_id=3, z0=10.) + s2 = openmc.ZPlane(-10., surface_id=2) + s3 = openmc.ZPlane(10., surface_id=3) surfs = {1: s1, 2: s2, 3: s3} r = openmc.Region.from_expression('-1 2 -3', surfs) diff --git a/tests/unit_tests/test_surface.py b/tests/unit_tests/test_surface.py index 8ce1040213..703010a059 100644 --- a/tests/unit_tests/test_surface.py +++ b/tests/unit_tests/test_surface.py @@ -55,7 +55,7 @@ def test_plane_from_points(): def test_xplane(): - s = openmc.XPlane(x0=3., boundary_type='reflective') + s = openmc.XPlane(3., 'reflective') assert s.x0 == 3. assert s.boundary_type == 'reflective'