From 718b267ee981e6426683ec392bfc0caa9414f4c7 Mon Sep 17 00:00:00 2001 From: Zhuoran Han Date: Fri, 10 Aug 2018 16:39:35 -0500 Subject: [PATCH 01/56] Add math functions to calculate normalization arrays --- openmc/capi/math.py | 93 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 89 insertions(+), 4 deletions(-) diff --git a/openmc/capi/math.py b/openmc/capi/math.py index 390ee466f..697ed558d 100644 --- a/openmc/capi/math.py +++ b/openmc/capi/math.py @@ -13,7 +13,10 @@ _dll.calc_pn_c.restype = None _dll.calc_pn_c.argtypes = [c_int, c_double, ndpointer(c_double)] _dll.evaluate_legendre_c.restype = c_double -_dll.evaluate_legendre_c.argtypes = [c_int, POINTER(c_double), c_double] +_dll.evaluate_legendre_c.argtypes = [c_int, POINTER(c_double), c_double, c_int] + +_dll.calc_norm_pn_c.restype = None +_dll.calc_norm_pn_c.argtypes =[c_int, c_double, c_double, ndpointer(c_double)] _dll.calc_rn_c.restype = None _dll.calc_rn_c.argtypes = [c_int, ndpointer(c_double), ndpointer(c_double)] @@ -24,6 +27,12 @@ _dll.calc_zn_c.argtypes = [c_int, c_double, c_double, ndpointer(c_double)] _dll.calc_zn_rad_c.restype = None _dll.calc_zn_rad_c.argtypes = [c_int, c_double, ndpointer(c_double)] +_dll.evaluate_zernike_rad_c.restype = c_double +_dll.evaluate_zernike_rad_c.argtypes = [c_int, POINTER(c_double), c_double] + +_dll.calc_norm_zn_rad_c.restype = None +_dll.calc_norm_zn_rad_c.argtypes = [c_int, c_double, ndpointer(c_double)] + _dll.rotate_angle_c.restype = None _dll.rotate_angle_c.argtypes = [ndpointer(c_double), c_double, POINTER(c_double)] @@ -81,7 +90,7 @@ def calc_pn(n, x): return pnx -def evaluate_legendre(data, x): +def evaluate_legendre(data, x, flag=1): """ Finds the value of f(x) given a set of Legendre coefficients and the value of x. @@ -91,6 +100,8 @@ def evaluate_legendre(data, x): Legendre coefficients x : float Independent variable to evaluate the Legendre at + flag : int + Flags to indicate use default normalization or not Returns ------- @@ -102,7 +113,31 @@ def evaluate_legendre(data, x): data_arr = np.array(data, dtype=np.float64) return _dll.evaluate_legendre_c(len(data), data_arr.ctypes.data_as(POINTER(c_double)), - x) + x, flag) + + +def calc_norm_pn(l, zmin, zmax): + """ Calculate normalization arrays for n orders in Legendre polynomial. + + Parameters + ---------- + l : int + Maximum order + zmin : float + The lowest boundary of the domain + zmax : float + The highest boundary of the domain + + Returns + ------- + numpy.ndarray + Corresponding resulting list of normalization coefficients + + """ + + norm_pn = np.empty(l + 1, dtype=np.float64) + _dll.calc_norm_pn_c(l, zmin, zmax, norm_pn) + return norm_pn def calc_rn(n, uvw): @@ -182,7 +217,57 @@ def calc_zn_rad(n, rho): zn_rad = np.zeros(num_bins, dtype=np.float64) _dll.calc_zn_rad_c(n, rho, zn_rad) return zn_rad - + + +def evaluate_zernike_rad(data, r): + """ Finds the value of f(x) given a set of even order Zernike coefficients + and the value of r. + + Parameters + ---------- + data : iterable of float + Legendre coefficients + r : float + Independent variable to evaluate the radial part of Zernike at + + Returns + ------- + float + Corresponding Zernike expansion result + + """ + + data_arr = np.array(data, dtype=np.float64) + n = int(2 * (len(data) - 1)) + return _dll.evaluate_zernike_rad_c(n, + data_arr.ctypes.data_as(POINTER( + c_double)), + r) + + +def calc_norm_zn_rad(n, rho): + """ Calculate normalization arrays for the even orders in modified Zernike + polynomial moment with no azimuthal dependency (m=0). + + Parameters + ---------- + n : int + Maximum order + rho : float + Radial location in the unit disk + + Returns + ------- + numpy.ndarray + Corresponding resulting list of normalization coefficients + + """ + + num_bins = n // 2 + 1 + norm_zn_rad = np.zeros(num_bins, dtype=np.float64) + _dll.calc_norm_zn_rad_c(n, rho, norm_zn_rad) + return norm_zn_rad + def rotate_angle(uvw0, mu, phi=None): """ Rotates direction cosines through a polar angle whose cosine is From a52f31c95b65f4e97b4ee56ea1b1e5ea51991860 Mon Sep 17 00:00:00 2001 From: Zhuoran Han Date: Fri, 10 Aug 2018 16:40:17 -0500 Subject: [PATCH 02/56] Add cpp math functions to calc normalization arrays Add math funcs to reconstruct FET --- src/math_functions.cpp | 52 +++++++++++++++++++++++++++++++++++++++--- src/math_functions.h | 46 ++++++++++++++++++++++++++++++++++++- 2 files changed, 94 insertions(+), 4 deletions(-) diff --git a/src/math_functions.cpp b/src/math_functions.cpp index 8a36f7b92..b5c718d5d 100644 --- a/src/math_functions.cpp +++ b/src/math_functions.cpp @@ -103,17 +103,36 @@ void calc_pn_c(int n, double x, double pnx[]) { } -double evaluate_legendre_c(int n, const double data[], double x) { +double evaluate_legendre_c(int n, const double data[], double x, int flag) { double pnx[n + 1]; double val = 0.0; calc_pn_c(n, x, pnx); - for (int l = 0; l <= n; l++) { - val += (l + 0.5) * data[l] * pnx[l]; + + if (flag == 1) { + for (int l = 0; l <= n; l++) { + val += (l + 0.5) * data[l] * pnx[l]; + } + } else if (flag == 2) { + for (int l = 0; l <= n; l++) { + val += data[l] * pnx[l]; + } } + return val; } +void calc_norm_pn_c(int l, double zmin, double zmax, double norm_vec[]) { + // =========================================================================== + // Set up the normalization vector for FET Pn reconstruction + double d = zmax - zmin; + + for (int i = 0; i <= l; i++) { + norm_vec[i] = (2 * i + 1)/d; + } +} + + void calc_rn_c(int n, const double uvw[3], double rn[]){ // rn[] is assumed to have already been allocated to the correct size @@ -615,6 +634,33 @@ void calc_zn_rad_c(int n, double rho, double zn_rad[]) { } +void calc_norm_zn_rad_c(int n, double r, double norm_vec[]) { + // =========================================================================== + // Set up the normalization vector for FET Zn Radial only reconstruction + int index; + + for (int i = 0; i <= n; i+=2) { + index = int(i/2); + norm_vec[index] = (i + 1)/(PI * r * r); + } +} + + +double evaluate_zernike_rad_c(int n, const double data[], double r) { + double rnr[n / 2 + 1]; + double val = 0.0; + calc_zn_rad_c(n, r, rnr); + int index; + + for (int i = 0; i <= n; i+ = 2) { + index = int(i/2); + val += data[index] * rnr[index]; + } + + return val; +} + + void rotate_angle_c(double uvw[3], double mu, double* phi) { // Copy original directional cosines double u0 = uvw[0]; // original cosine in x direction diff --git a/src/math_functions.h b/src/math_functions.h index 7ef39c446..30e210e50 100644 --- a/src/math_functions.h +++ b/src/math_functions.h @@ -53,11 +53,27 @@ extern "C" void calc_pn_c(int n, double x, double pnx[]); //! @param data The polynomial expansion coefficient data; without the (2l+1)/2 //! factor. //! @param x The value to evaluate at; x is expected to be within [-1,1] +//! @param flag A flag of which method to calculate Legendre polynomials. 1 for +//! default (2l+1)/2; 2 for custom normalized coefficients //! @return The requested Legendre polynomials of order 0 to n (inclusive) //! evaluated at x //============================================================================== -extern "C" double evaluate_legendre_c(int n, const double data[], double x); +extern "C" double evaluate_legendre_c(int n, const double data[], double x, int flag = 1); + +//============================================================================== +//! Evaluate the normalization vector when reconstructing functional expansion +//! from Legendre polynomials. +//! +//! The normalization is (2 * l + 1)/(zmax - zmin) +//! +//! @param l The maximum order requested +//! @param zmin The minimum location of 1-d domain +//! @param zmax The maximum location of 1-d domain +//! @param norm_vec The requested normalization of order 0 to n (inclusive) +//============================================================================== + +extern "C" void calc_norm_pn_c(int l, double zmin, double zmax, double norm_vec[]); //============================================================================== //! Calculate the n-th order real spherical harmonics for a given angle (in @@ -69,6 +85,7 @@ extern "C" double evaluate_legendre_c(int n, const double data[], double x); //! evaluated at uvw. //============================================================================== + extern "C" void calc_rn_c(int n, const double uvw[3], double rn[]); //============================================================================== @@ -109,6 +126,33 @@ extern "C" void calc_zn_c(int n, double rho, double phi, double zn[]); extern "C" void calc_zn_rad_c(int n, double rho, double zn_rad[]); +//============================================================================== +//! Evaluate the normalization vector when reconstructing functional expansion +//! from radial only Zernike polynomials. +//! +//! The normalization is (2 * l + 1)/(zmax - zmin) +//! +//! @param n The maximum order requested +//! @param r The radius of the disk +//! @param norm_vec The requested normalization of even orders from 0 to n +//============================================================================== + +extern "C" void calc_norm_zn_rad_c(int n, double r, double norm_vec[]); + +//============================================================================== +//! Find the value of f(x) given a set of even order Zernike coefficients and +//! the value of x if there is only radial dependency. +//! +//! @param n The maximum order of the expansion +//! @param data The overall polynomial expansion coefficient data; +//! normalization should be considered by users +//! @param r The value to evaluate at; r is expected to be within [0,1] +//! @return The requested Zernike polynomials of order 0 to n (inclusive) +//! evaluated at r +//============================================================================== + +extern "C" double evaluate_zernike_rad_c(int n, const double data[], double r); + //============================================================================== //! Rotate the direction cosines through a polar angle whose cosine is mu and //! through an azimuthal angle sampled uniformly. From 61431be559fbceb8a5b3fa809056a52702f90eb0 Mon Sep 17 00:00:00 2001 From: Zhuoran Han Date: Fri, 10 Aug 2018 16:41:24 -0500 Subject: [PATCH 03/56] Add unit test. Still need to add another tests for eva_zn --- tests/unit_tests/test_math.py | 49 ++++++++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/tests/unit_tests/test_math.py b/tests/unit_tests/test_math.py index 6825f6b93..a63561854 100644 --- a/tests/unit_tests/test_math.py +++ b/tests/unit_tests/test_math.py @@ -57,9 +57,30 @@ def test_evaluate_legendre(): test_vals = np.array([openmc.capi.math.evaluate_legendre(test_coeffs, x) for x in test_xs]) + # When turn on the flag 2, evaluate_legendre should be the same as + # np.polynomial.legendre.legval(). + test_coeffs = [(2. * l + 1.) / 10 for l in range(max_order + 1)] + ref_vals_1 = np.polynomial.legendre.legval(test_xs, test_coeffs) + + test_vals_1 = np.array([openmc.capi.math.evaluate_legendre(test_coeffs, x, + 2)for x in test_xs]) + + assert np.allclose(ref_vals, test_vals) + assert np.allclose(ref_vals_1, test_vals_1) + + +def test_calc_norm_pn(): + max_order = 10 + zmin = -10 + zmax = 10 + + ref_vals = np.divide(2 * np.arange(max_order + 1) + 1, (zmax-zmin)) + + test_vals = openmc.capi.math.calc_norm_pn(max_order, zmin, zmax) + assert np.allclose(ref_vals, test_vals) - + def test_calc_rn(): max_order = 10 test_ns = np.array([i for i in range(0, max_order + 1)]) @@ -137,6 +158,32 @@ def test_calc_zn(): assert np.allclose(ref_vals, test_vals) +def test_calc_zn_rad(): + n = 10 + rho = 0.5 + phi = 0.5 + + # Reference solution from running the Fortran implementation + ref_vals = np.array([ + 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) + + assert np.allclose(ref_vals, test_vals) + + +def test_calc_norm_zn_rad(): + max_order = 10 + rho = 0.5 + + ref_vals = np.divide(np.arange(0, max_order + 1, 2) + 1, np.pi * rho * rho) + + test_vals = openmc.capi.math.calc_norm_zn_rad(max_order, rho) + + assert np.allclose(ref_vals, test_vals) + + def test_rotate_angle(): uvw0 = np.array([1., 0., 0.]) phi = 0. From 7e54eb0e976bd8a1d1e1f0c75638f3dbde555ffc Mon Sep 17 00:00:00 2001 From: Zhuoran Han Date: Mon, 13 Aug 2018 10:21:22 -0500 Subject: [PATCH 04/56] Add some comments --- src/math_functions.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/math_functions.cpp b/src/math_functions.cpp index b5c718d5d..97dd7b285 100644 --- a/src/math_functions.cpp +++ b/src/math_functions.cpp @@ -112,7 +112,7 @@ double evaluate_legendre_c(int n, const double data[], double x, int flag) { for (int l = 0; l <= n; l++) { val += (l + 0.5) * data[l] * pnx[l]; } - } else if (flag == 2) { + } else if (flag == 2) { // if flag is 2, we don't apply any normalization for (int l = 0; l <= n; l++) { val += data[l] * pnx[l]; } @@ -647,6 +647,7 @@ void calc_norm_zn_rad_c(int n, double r, double norm_vec[]) { double evaluate_zernike_rad_c(int n, const double data[], double r) { + // data here is already normalized outside this function double rnr[n / 2 + 1]; double val = 0.0; calc_zn_rad_c(n, r, rnr); From 1b127cd2e8baca88686948fa8359c74c78513d6a Mon Sep 17 00:00:00 2001 From: Zhuoran Han Date: Mon, 13 Aug 2018 10:35:16 -0500 Subject: [PATCH 05/56] Add test for evaluate zn_rad --- src/math_functions.cpp | 2 +- tests/unit_tests/test_math.py | 17 ++++++++++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/math_functions.cpp b/src/math_functions.cpp index 97dd7b285..72fb85ae8 100644 --- a/src/math_functions.cpp +++ b/src/math_functions.cpp @@ -653,7 +653,7 @@ double evaluate_zernike_rad_c(int n, const double data[], double r) { calc_zn_rad_c(n, r, rnr); int index; - for (int i = 0; i <= n; i+ = 2) { + for (int i = 0; i <= n; i+= 2) { index = int(i/2); val += data[index] * rnr[index]; } diff --git a/tests/unit_tests/test_math.py b/tests/unit_tests/test_math.py index a63561854..65fcd728f 100644 --- a/tests/unit_tests/test_math.py +++ b/tests/unit_tests/test_math.py @@ -161,7 +161,6 @@ def test_calc_zn(): def test_calc_zn_rad(): n = 10 rho = 0.5 - phi = 0.5 # Reference solution from running the Fortran implementation ref_vals = np.array([ @@ -172,6 +171,22 @@ def test_calc_zn_rad(): assert np.allclose(ref_vals, test_vals) +def test_evaluate_legendre(): + max_order = 10 + rho = 0.5 + + raw_zn = np.array([ + 1.00000000e+00, -5.00000000e-01, -1.25000000e-01, + 4.37500000e-01, -2.89062500e-01,-8.98437500e-02]) + raw_coeff = np.ones(6) + norm_vec = np.divide(np.arange(0, max_order + 1, 2) + 1, np.pi * rho * rho) + real_coeff = np.multiply(raw_coeff,norm_vec) + + ref_vals = np.sum(np.multiply(real_coeff,raw_zn)) + + test_vals = openmc.capi.math.evaluate_zernike_rad(real_coeff, rho) + + assert np.allclose(ref_vals, test_vals) def test_calc_norm_zn_rad(): max_order = 10 From 3b8d1ffb4b21a0b64a9577f9dcd81e86303695c0 Mon Sep 17 00:00:00 2001 From: jingang Date: Wed, 15 Aug 2018 22:08:12 -0400 Subject: [PATCH 06/56] update for new wmp library v1.0 - python api and docs --- docs/source/io_formats/data_wmp.rst | 60 +--- docs/source/methods/cross_sections.rst | 5 +- openmc/data/__init__.py | 2 +- openmc/data/multipole.py | 364 +++++++------------------ 4 files changed, 111 insertions(+), 320 deletions(-) diff --git a/docs/source/io_formats/data_wmp.rst b/docs/source/io_formats/data_wmp.rst index 6174e85ff..25916c522 100644 --- a/docs/source/io_formats/data_wmp.rst +++ b/docs/source/io_formats/data_wmp.rst @@ -5,7 +5,7 @@ Windowed Multipole Library Format ================================= **/version** (*char[]*) - The format version of the file. The current version is "v0.2" + The format version of the file. The current version is "v1.0" **/nuclide/** - **broaden_poly** (*int[]*) @@ -23,55 +23,25 @@ Windowed Multipole Library Format \text{data}[:,i] = [\text{pole},~\text{residue}_1,~\text{residue}_2, ~\ldots] - The residues are in the order: total, competitive if present, - absorption, fission. Complex numbers are stored by forming a type with - ":math:`r`" and ":math:`i`" identifiers, similar to how `h5py`_ does it. - - **end_E** (*double*) + The residues are in the order: scattering, absorption, fission. Complex + numbers are stored by forming a type with ":math:`r`" and ":math:`i`" + identifiers, similar to how `h5py`_ does it. + - **E_max** (*double*) Highest energy the windowed multipole part of the library is valid for. - - **formalism** (*int*) - The formalism of the underlying data. Uses the `ENDF-6`_ format - formalism numbers. - - .. table:: Table of supported formalisms. - - +-------------+------------------+ - | Formalism | Formalism number | - +=============+==================+ - | MLBW | 2 | - +-------------+------------------+ - | Reich-Moore | 3 | - +-------------+------------------+ - - - **l_value** (*int[]*) - The index for a corresponding pole. Equivalent to the :math:`l` quantum - number of the resonance the pole comes from :math:`+1`. - - **pseudo_K0RS** (*double[]*) - :math:`l` dependent value of - - .. math:: - \sqrt{\frac{2 m_n}{\hbar}}\frac{AWR}{AWR + 1} r_{s,l} - - Where :math:`m_n` is mass of neutron, :math:`AWR` is the atomic weight - ratio of the target to the neutron, and :math:`r_{s,l}` is the - scattering radius for a given :math:`l`. + - **E_min** (*double*) + Lowest energy the windowed multipole part of the library is valid for. - **spacing** (*double*) .. math:: - \frac{\sqrt{E_{max}}- \sqrt{E_{min}}}{n_w} + \frac{\sqrt{E_{max}} - \sqrt{E_{min}}}{n_w} - Where :math:`E_{max}` is the maximum energy the windows go up to. This - is not equivalent to the maximum energy for which the windowed multipole - data is valid for. It is slightly higher to ensure an integer number of - windows. :math:`E_{min}` is the minimum energy and equivalent to - ``start_E``, and :math:`n_w` is the number of windows, given by - ``windows``. + Where :math:`E_{max}` is the maximum energy the windows go up to. + :math:`E_{min}` is the minimum energy, and :math:`n_w` is the number of + windows, given by ``windows``. - **sqrtAWR** (*double*) Square root of the atomic weight ratio. - - **start_E** (*double*) - Lowest energy the windowed multipole part of the library is valid for. - - **w_start** (*int[]*) - The pole to start from for each window. - - **w_end** (*int[]*) - The pole to end at for each window. + - **windows** (*int[][]*) + The poles to start from and end at for each window. windows[i, 0] and + windows[i, 1] are, respectively, the indexes (1-based) of the first and + last pole in window i. .. _h5py: http://docs.h5py.org/en/latest/ -.. _ENDF-6: https://www.oecd-nea.org/dbdata/data/manual-endf/endf102.pdf diff --git a/docs/source/methods/cross_sections.rst b/docs/source/methods/cross_sections.rst index 9f677bac4..4940275d3 100644 --- a/docs/source/methods/cross_sections.rst +++ b/docs/source/methods/cross_sections.rst @@ -90,7 +90,7 @@ Assuming free-gas thermal motion, cross sections in the multipole form can be analytically Doppler broadened to give the form: .. math:: - \sigma(E, T) = \frac{1}{2 E \sqrt{\xi}} \sum_j \text{Re} \left[i r_j + \sigma(E, T) = \frac{1}{2 E \sqrt{\xi}} \sum_j \text{Re} \left[r_j \sqrt{\pi} W_i(z) - \frac{r_j}{\sqrt{\pi}} C \left(\frac{p_j}{\sqrt{\xi}}, \frac{u}{2 \sqrt{\xi}}\right)\right] .. math:: @@ -141,7 +141,7 @@ scattering does not occur in the resolved resonance region. This is usually, but not always the case. Future library versions may eliminate this issue. The data format used by OpenMC to represent windowed multipole data is specified -in :ref:`io_data_wmp`. +in :ref:`io_data_wmp` with a publicly available `WMP library`_. .. _temperature_treatment: @@ -270,6 +270,7 @@ or even isotropic scattering. https://laws.lanl.gov/vhosts/mcnp.lanl.gov/pdf_files/la-ur-14-24530.pdf .. _Hwang: http://www.ans.org/pubs/journals/nse/a_16381 .. _Josey: http://dx.doi.org/10.1016/j.jcp.2015.08.013 +.. _WMP Library: https://github.com/mit-crpg/WMP_Library .. _MCNP: http://mcnp.lanl.gov .. _Serpent: http://montecarlo.vtt.fi .. _NJOY: http://t2.lanl.gov/codes.shtml diff --git a/openmc/data/__init__.py b/openmc/data/__init__.py index 390a67c9b..dec11cd3a 100644 --- a/openmc/data/__init__.py +++ b/openmc/data/__init__.py @@ -4,7 +4,7 @@ HDF5_VERSION_MINOR = 0 HDF5_VERSION = (HDF5_VERSION_MAJOR, HDF5_VERSION_MINOR) # Version of WMP nuclear data format -WMP_VERSION = 'v0.2' +WMP_VERSION = 'v1.0' from .data import * diff --git a/openmc/data/multipole.py b/openmc/data/multipole.py index f7a78d953..c6e4f123c 100644 --- a/openmc/data/multipole.py +++ b/openmc/data/multipole.py @@ -10,26 +10,16 @@ import openmc.checkvalue as cv from openmc.mixin import EqualityMixin -# Formalisms -_FORM_MLBW = 2 -_FORM_RM = 3 - # Constants that determine which value to access _MP_EA = 0 # Pole -# Reich-Moore indices -_RM_RT = 1 # Residue total -_RM_RA = 2 # Residue absorption -_RM_RF = 3 # Residue fission - -# Multi-level Breit Wigner indices -_MLBW_RT = 1 # Residue total -_MLBW_RX = 2 # Residue competitive -_MLBW_RA = 3 # Residue absorption -_MLBW_RF = 4 # Residue fission +# Residue indices +_MP_RS = 1 # Residue scattering +_MP_RA = 2 # Residue absorption +_MP_RF = 3 # Residue fission # Polynomial fit indices -_FIT_T = 0 # Total +_FIT_S = 0 # Scattering _FIT_A = 1 # Absorption _FIT_F = 2 # Fission @@ -143,98 +133,61 @@ class WindowedMultipole(EqualityMixin): Parameters ---------- - formalism : {'MLBW', 'RM'} - The R-matrix formalism used to reconstruct resonances. Either 'MLBW' - for multi-level Breit Wigner or 'RM' for Reich-Moore. Attributes ---------- - num_l : Integral - Number of possible l quantum states for this nuclide. fit_order : Integral Order of the windowed curvefit. fissionable : bool Whether or not the target nuclide has fission data. - formalism : {'MLBW', 'RM'} - The R-matrix formalism used to reconstruct resonances. Either 'MLBW' - for multi-level Breit Wigner or 'RM' for Reich-Moore. spacing : Real The width of each window in sqrt(E)-space. For example, the frst window - will end at (sqrt(start_E) + spacing)**2 and the second window at - (sqrt(start_E) + 2*spacing)**2. + will end at (sqrt(E_min) + spacing)**2 and the second window at + (sqrt(E_min) + 2*spacing)**2. sqrtAWR : Real Square root of the atomic weight ratio of the target nuclide. - start_E : Real + E_min : Real Lowest energy in eV the library is valid for. - end_E : Real + E_max : Real Highest energy in eV the library is valid for. data : np.ndarray A 2D array of complex poles and residues. data[i, 0] gives the energy at which pole i is located. data[i, 1:] gives the residues associated - with the i-th pole. There are 3 residues for Reich-Moore data, one each - for the total, absorption, and fission channels. Multi-level - Breit Wigner data has an additional residue for the competitive channel. - pseudo_k0RS : np.ndarray - A 1D array of Real values. There is one value for each valid l - quantum number. The values are equal to - sqrt(2 m / hbar) * AWR / (AWR + 1) * r - where m is the neutron mass, AWR is the atomic weight ratio, and r - is the l-dependent scattering radius. - l_value : np.ndarray - A 1D array of Integral values equal to the l quantum number for each - pole + 1. - w_start : np.ndarray - A 1D array of Integral values. w_start[i] - 1 is the index of the first - pole in window i. - w_end : np.ndarray - A 1D array of Integral values. w_end[i] - 1 is the index of the last - pole in window i. + with the i-th pole. There are 3 residues, one each for the scattering, + absorption, and fission channels. + windows : np.ndarray + A 2D array of Integral values. windows[i, 0] - 1 is the index of the + first pole in window i. windows[i, 1] - 1 is the index of the last pole + in window i. broaden_poly : np.ndarray A 1D array of boolean values indicating whether or not the polynomial curvefit in that window should be Doppler broadened. curvefit : np.ndarray A 3D array of Real curvefit polynomial coefficients. curvefit[i, 0, :] - gives coefficients for the total cross section in window i. + gives coefficients for the scattering cross section in window i. curvefit[i, 1, :] gives absorption coefficients and curvefit[i, 2, :] gives fission coefficients. The polynomial terms are increasing powers of sqrt(E) starting with 1/E e.g: a/E + b/sqrt(E) + c + d sqrt(E) + ... """ - def __init__(self, formalism): - self._num_l = None - self.formalism = formalism + def __init__(self): self.spacing = None self.sqrtAWR = None - self.start_E = None - self.end_E = None + self.E_min = None + self.E_max = None self.data = None - self.pseudo_k0RS = None - self.l_value = None - self.w_start = None - self.w_end = None + self.windows = None self.broaden_poly = None self.curvefit = None - @property - def num_l(self): - return self._num_l - @property def fit_order(self): return self.curvefit.shape[1] - 1 @property def fissionable(self): - if self.formalism == 'RM': - return self.data.shape[1] == 4 - else: - # Assume self.formalism == 'MLBW' - return self.data.shape[1] == 5 - - @property - def formalism(self): - return self._formalism + return self.data.shape[1] == 4 @property def spacing(self): @@ -245,32 +198,24 @@ class WindowedMultipole(EqualityMixin): return self._sqrtAWR @property - def start_E(self): - return self._start_E + def E_min(self): + return self._E_min @property - def end_E(self): - return self._end_E + def E_max(self): + return self._E_max @property def data(self): return self._data - @property - def pseudo_k0RS(self): - return self._pseudo_k0RS - @property def l_value(self): return self._l_value @property - def w_start(self): - return self._w_start - - @property - def w_end(self): - return self._w_end + def windows(self): + return self._windows @property def broaden_poly(self): @@ -280,116 +225,64 @@ class WindowedMultipole(EqualityMixin): def curvefit(self): return self._curvefit - @formalism.setter - def formalism(self, formalism): - cv.check_type('formalism', formalism, str) - cv.check_value('formalism', formalism, ('MLBW', 'RM')) - self._formalism = formalism - @spacing.setter def spacing(self, spacing): if spacing is not None: - cv.check_type('spacing', spacing, Real) - cv.check_greater_than('spacing', spacing, 0.0, equality=False) + check_type('spacing', spacing, Real) + check_greater_than('spacing', spacing, 0.0, equality=False) self._spacing = spacing @sqrtAWR.setter def sqrtAWR(self, sqrtAWR): if sqrtAWR is not None: - cv.check_type('sqrtAWR', sqrtAWR, Real) - cv.check_greater_than('sqrtAWR', sqrtAWR, 0.0, equality=False) + check_type('sqrtAWR', sqrtAWR, Real) + check_greater_than('sqrtAWR', sqrtAWR, 0.0, equality=False) self._sqrtAWR = sqrtAWR - @start_E.setter - def start_E(self, start_E): - if start_E is not None: - cv.check_type('start_E', start_E, Real) - cv.check_greater_than('start_E', start_E, 0.0, equality=True) - self._start_E = start_E + @E_min.setter + def E_min(self, E_min): + if E_min is not None: + check_type('E_min', E_min, Real) + check_greater_than('E_min', E_min, 0.0, equality=True) + self._E_min = E_min - @end_E.setter - def end_E(self, end_E): - if end_E is not None: - cv.check_type('end_E', end_E, Real) - cv.check_greater_than('end_E', end_E, 0.0, equality=False) - self._end_E = end_E + @E_max.setter + def E_max(self, E_max): + if E_max is not None: + check_type('E_max', E_max, Real) + check_greater_than('E_max', E_max, 0.0, equality=False) + self._E_max = E_max @data.setter def data(self, data): if data is not None: - cv.check_type('data', data, np.ndarray) + check_type('data', data, np.ndarray) if len(data.shape) != 2: raise ValueError('Multipole data arrays must be 2D') - if self.formalism == 'RM': - if data.shape[1] not in (3, 4): - raise ValueError('For the Reich-Moore formalism, ' - 'data.shape[1] must be 3 or 4. One value for the pole.' - ' One each for the total and absorption residues. ' - 'Possibly one more for a fission residue.') - else: - # Assume self.formalism == 'MLBW' - if data.shape[1] not in (4, 5): - raise ValueError('For the Multi-level Breit-Wigner ' - 'formalism, data.shape[1] must be 4 or 5. One value ' - 'for the pole. One each for the total, competitive, ' - 'and absorption residues. Possibly one more for a ' - 'fission residue.') + if data.shape[1] not in (3, 4): + raise ValueError( + 'data.shape[1] must be 3 or 4. One value for the pole.' + ' One each for the scattering and absorption residues. ' + 'Possibly one more for a fission residue.') if not np.issubdtype(data.dtype, complex): raise TypeError('Multipole data arrays must be complex dtype') self._data = data - @pseudo_k0RS.setter - def pseudo_k0RS(self, pseudo_k0RS): - if pseudo_k0RS is not None: - cv.check_type('pseudo_k0RS', pseudo_k0RS, np.ndarray) - if len(pseudo_k0RS.shape) != 1: - raise ValueError('Multipole pseudo_k0RS arrays must be 1D') - if not np.issubdtype(pseudo_k0RS.dtype, float): - raise TypeError('Multipole data arrays must be float dtype') - self._pseudo_k0RS = pseudo_k0RS - - @l_value.setter - def l_value(self, l_value): - if l_value is not None: - cv.check_type('l_value', l_value, np.ndarray) - if len(l_value.shape) != 1: - raise ValueError('Multipole l_value arrays must be 1D') - if not np.issubdtype(l_value.dtype, int): - raise TypeError('Multipole l_value arrays must be integer' + @windows.setter + def windows(self, windows): + if windows is not None: + check_type('windows', windows, np.ndarray) + if len(windows.shape) != 2: + raise ValueError('Multipole windows arrays must be 2D') + if not np.issubdtype(windows.dtype, int): + raise TypeError('Multipole windows arrays must be integer' ' dtype') - - self._num_l = len(np.unique(l_value)) - - else: - self._num_l = None - - self._l_value = l_value - - @w_start.setter - def w_start(self, w_start): - if w_start is not None: - cv.check_type('w_start', w_start, np.ndarray) - if len(w_start.shape) != 1: - raise ValueError('Multipole w_start arrays must be 1D') - if not np.issubdtype(w_start.dtype, int): - raise TypeError('Multipole w_start arrays must be integer' - ' dtype') - self._w_start = w_start - - @w_end.setter - def w_end(self, w_end): - if w_end is not None: - cv.check_type('w_end', w_end, np.ndarray) - if len(w_end.shape) != 1: - raise ValueError('Multipole w_end arrays must be 1D') - if not np.issubdtype(w_end.dtype, int): - raise TypeError('Multipole w_end arrays must be integer dtype') - self._w_end = w_end + self._windows = windows @broaden_poly.setter def broaden_poly(self, broaden_poly): if broaden_poly is not None: - cv.check_type('broaden_poly', broaden_poly, np.ndarray) + check_type('broaden_poly', broaden_poly, np.ndarray) if len(broaden_poly.shape) != 1: raise ValueError('Multipole broaden_poly arrays must be 1D') if not np.issubdtype(broaden_poly.dtype, bool): @@ -400,10 +293,10 @@ class WindowedMultipole(EqualityMixin): @curvefit.setter def curvefit(self, curvefit): if curvefit is not None: - cv.check_type('curvefit', curvefit, np.ndarray) + check_type('curvefit', curvefit, np.ndarray) if len(curvefit.shape) != 3: raise ValueError('Multipole curvefit arrays must be 3D') - if curvefit.shape[2] not in (2, 3): # sig_t, sig_a (maybe sig_f) + if curvefit.shape[2] not in (2, 3): # sig_s, sig_a (maybe sig_f) raise ValueError('The third dimension of multipole curvefit' ' arrays must have a length of 2 or 3') if not np.issubdtype(curvefit.dtype, float): @@ -443,19 +336,14 @@ class WindowedMultipole(EqualityMixin): 'Python API expects version ' + WMP_VERSION) group = h5file['nuclide'] - # Read scalars. + out = cls() - if group['formalism'].value == _FORM_MLBW: - out = cls('MLBW') - elif group['formalism'].value == _FORM_RM: - out = cls('RM') - else: - raise ValueError('Unrecognized/Unsupported R-matrix formalism') + # Read scalars. out.spacing = group['spacing'].value out.sqrtAWR = group['sqrtAWR'].value - out.start_E = group['start_E'].value - out.end_E = group['end_E'].value + out.E_min = group['E_min'].value + out.E_max = group['E_max'].value # Read arrays. @@ -463,27 +351,15 @@ class WindowedMultipole(EqualityMixin): out.data = group['data'].value - out.l_value = group['l_value'].value - if out.l_value.shape[0] != out.data.shape[0]: - raise ValueError(err.format('l_value', 'data')) - - out.pseudo_k0RS = group['pseudo_K0RS'].value - if out.pseudo_k0RS.shape[0] != out.num_l: - raise ValueError(err.format('pseudo_k0RS', 'l_value')) - - out.w_start = group['w_start'].value - - out.w_end = group['w_end'].value - if out.w_end.shape[0] != out.w_start.shape[0]: - raise ValueError(err.format('w_end', 'w_start')) + out.windows = group['windows'].value out.broaden_poly = group['broaden_poly'].value.astype(np.bool) - if out.broaden_poly.shape[0] != out.w_start.shape[0]: - raise ValueError(err.format('broaden_poly', 'w_start')) + if out.broaden_poly.shape[0] != out.windows.shape[0]: + raise ValueError(err.format('broaden_poly', 'windows')) out.curvefit = group['curvefit'].value - if out.curvefit.shape[0] != out.w_start.shape[0]: - raise ValueError(err.format('curvefit', 'w_start')) + if out.curvefit.shape[0] != out.windows.shape[0]: + raise ValueError(err.format('curvefit', 'windows')) # _broaden_wmp_polynomials assumes the curve fit has at least 3 terms. if out.fit_order < 2: @@ -493,7 +369,7 @@ class WindowedMultipole(EqualityMixin): return out def _evaluate(self, E, T): - """Compute total, absorption, and fission cross sections. + """Compute scattering, absorption, and fission cross sections. Parameters ---------- @@ -510,8 +386,8 @@ class WindowedMultipole(EqualityMixin): """ - if E < self.start_E: return (0, 0, 0) - if E > self.end_E: return (0, 0, 0) + if E < self.E_min: return (0, 0, 0) + if E > self.E_max: return (0, 0, 0) # ====================================================================== # Bookkeeping @@ -525,34 +401,12 @@ class WindowedMultipole(EqualityMixin): # the 1-based vs. 0-based indexing. Similarly startw needs to be # decreased by 1. endw does not need to be decreased because # range(startw, endw) does not include endw. - i_window = int(np.floor((sqrtE - sqrt(self.start_E)) / self.spacing)) - startw = self.w_start[i_window] - 1 - endw = self.w_end[i_window] - - # Fill in factors. Because of the unique interference dips in scatering - # resonances, the total cross section has a special "factor" that does - # not appear in the absorption and fission equations. - if startw <= endw: - twophi = np.zeros(self.num_l, dtype=np.float) - sig_t_factor = np.zeros(self.num_l, dtype=np.cfloat) - - for iL in range(self.num_l): - twophi[iL] = self.pseudo_k0RS[iL] * sqrtE - if iL == 1: - twophi[iL] = twophi[iL] - np.arctan(twophi[iL]) - elif iL == 2: - arg = 3.0 * twophi[iL] / (3.0 - twophi[iL]**2) - twophi[iL] = twophi[iL] - np.arctan(arg) - elif iL == 3: - arg = (twophi[iL] * (15.0 - twophi[iL]**2) - / (15.0 - 6.0 * twophi[iL]**2)) - twophi[iL] = twophi[iL] - np.arctan(arg) - - twophi = 2.0 * twophi - sig_t_factor = np.cos(twophi) - 1j*np.sin(twophi) + i_window = int(np.floor((sqrtE - sqrt(self.E_min)) / self.spacing)) + startw = self.windows[i_window, 0] - 1 + endw = self.windows[i_window, 1] # Initialize the ouptut cross sections. - sig_t = 0.0 + sig_s = 0.0 sig_a = 0.0 sig_f = 0.0 @@ -565,7 +419,7 @@ class WindowedMultipole(EqualityMixin): broadened_polynomials = _broaden_wmp_polynomials(E, dopp, self.fit_order + 1) for i_poly in range(self.fit_order+1): - sig_t += (self.curvefit[i_window, i_poly, _FIT_T] + sig_s += (self.curvefit[i_window, i_poly, _FIT_S] * broadened_polynomials[i_poly]) sig_a += (self.curvefit[i_window, i_poly, _FIT_A] * broadened_polynomials[i_poly]) @@ -575,7 +429,7 @@ class WindowedMultipole(EqualityMixin): else: temp = invE for i_poly in range(self.fit_order+1): - sig_t += self.curvefit[i_window, i_poly, _FIT_T] * temp + sig_s += self.curvefit[i_window, i_poly, _FIT_S] * temp sig_a += self.curvefit[i_window, i_poly, _FIT_A] * temp if self.fissionable: sig_f += self.curvefit[i_window, i_poly, _FIT_F] * temp @@ -589,22 +443,10 @@ class WindowedMultipole(EqualityMixin): for i_pole in range(startw, endw): psi_chi = -1j / (self.data[i_pole, _MP_EA] - sqrtE) c_temp = psi_chi / E - if self.formalism == 'MLBW': - sig_t += ((self.data[i_pole, _MLBW_RT] * c_temp * - sig_t_factor[self.l_value[i_pole]-1]).real - + (self.data[i_pole, _MLBW_RX] * c_temp).real) - sig_a += (self.data[i_pole, _MLBW_RA] * c_temp).real - if self.fissionable: - sig_f += (self.data[i_pole, _MLBW_RF] * c_temp).real - elif self.formalism == 'RM': - sig_t += (self.data[i_pole, _RM_RT] * c_temp * - sig_t_factor[self.l_value[i_pole]-1]).real - sig_a += (self.data[i_pole, _RM_RA] * c_temp).real - if self.fissionable: - sig_f += (self.data[i_pole, _RM_RF] * c_temp).real - else: - raise ValueError('Unrecognized/Unsupported R-matrix' - ' formalism') + sig_s += (self.data[i_pole, _MP_RS] * c_temp).real + sig_a += (self.data[i_pole, _MP_RA] * c_temp).real + if self.fissionable: + sig_f += (self.data[i_pole, _MP_RF] * c_temp).real else: # At temperature, use Faddeeva function-based form. @@ -612,27 +454,15 @@ class WindowedMultipole(EqualityMixin): for i_pole in range(startw, endw): Z = (sqrtE - self.data[i_pole, _MP_EA]) * dopp w_val = _faddeeva(Z) * dopp * invE * sqrt(pi) - if self.formalism == 'MLBW': - sig_t += ((self.data[i_pole, _MLBW_RT] * - sig_t_factor[self.l_value[i_pole]-1] + - self.data[i_pole, _MLBW_RX]) * w_val).real - sig_a += (self.data[i_pole, _MLBW_RA] * w_val).real - if self.fissionable: - sig_f += (self.data[i_pole, _MLBW_RF] * w_val).real - elif self.formalism == 'RM': - sig_t += (self.data[i_pole, _RM_RT] * w_val * - sig_t_factor[self.l_value[i_pole]-1]).real - sig_a += (self.data[i_pole, _RM_RA] * w_val).real - if self.fissionable: - sig_f += (self.data[i_pole, _RM_RF] * w_val).real - else: - raise ValueError('Unrecognized/Unsupported R-matrix' - ' formalism') + sig_s += (self.data[i_pole, _MP_RS] * w_val).real + sig_a += (self.data[i_pole, _MP_RA] * w_val).real + if self.fissionable: + sig_f += (self.data[i_pole, _MP_RF] * w_val).real - return sig_t, sig_a, sig_f + return sig_s, sig_a, sig_f def __call__(self, E, T): - """Compute total, absorption, and fission cross sections. + """Compute scattering, absorption, and fission cross sections. Parameters ---------- @@ -674,24 +504,14 @@ class WindowedMultipole(EqualityMixin): g = f.create_group('nuclide') # Write scalars. - if self.formalism == 'MLBW': - g.create_dataset('formalism', - data=np.array(_FORM_MLBW, dtype=np.int32)) - else: - # Assume RM. - g.create_dataset('formalism', - data=np.array(_FORM_RM, dtype=np.int32)) g.create_dataset('spacing', data=np.array(self.spacing)) g.create_dataset('sqrtAWR', data=np.array(self.sqrtAWR)) - g.create_dataset('start_E', data=np.array(self.start_E)) - g.create_dataset('end_E', data=np.array(self.end_E)) + g.create_dataset('E_min', data=np.array(self.E_min)) + g.create_dataset('E_max', data=np.array(self.E_max)) # Write arrays. g.create_dataset('data', data=self.data) - g.create_dataset('l_value', data=self.l_value) - g.create_dataset('pseudo_K0RS', data=self.pseudo_k0RS) - g.create_dataset('w_start', data=self.w_start) - g.create_dataset('w_end', data=self.w_end) + g.create_dataset('windows', data=self.windows) g.create_dataset('broaden_poly', data=self.broaden_poly.astype(np.int8)) g.create_dataset('curvefit', data=self.curvefit) From 60a88b9cab49d63e71e9ee6ba6b06f0905d6ae9b Mon Sep 17 00:00:00 2001 From: jingang Date: Thu, 16 Aug 2018 00:12:18 -0400 Subject: [PATCH 07/56] update for new wmp library v1.0 - openmc code --- src/constants.F90 | 2 +- src/multipole_header.F90 | 106 +++++++++------------------ src/nuclide_header.F90 | 151 +++++++++------------------------------ src/physics.F90 | 4 +- src/tallies/tally.F90 | 136 +++++++++++++++++------------------ 5 files changed, 140 insertions(+), 259 deletions(-) diff --git a/src/constants.F90 b/src/constants.F90 index ab85b277a..a3118f84d 100644 --- a/src/constants.F90 +++ b/src/constants.F90 @@ -25,7 +25,7 @@ module constants integer, parameter :: VERSION_VOLUME(2) = [1, 0] integer, parameter :: VERSION_VOXEL(2) = [1, 0] integer, parameter :: VERSION_MGXS_LIBRARY(2) = [1, 0] - character(10), parameter :: VERSION_MULTIPOLE = "v0.2" + character(10), parameter :: VERSION_MULTIPOLE = "v1.0" ! ============================================================================ ! ADJUSTABLE PARAMETERS diff --git a/src/multipole_header.F90 b/src/multipole_header.F90 index f2d0c9106..05eb62e1a 100644 --- a/src/multipole_header.F90 +++ b/src/multipole_header.F90 @@ -10,27 +10,16 @@ module multipole_header !======================================================================== ! Multipole related constants - ! Formalisms - integer, parameter :: FORM_MLBW = 2, & - FORM_RM = 3, & - FORM_RML = 7 - ! Constants that determine which value to access integer, parameter :: MP_EA = 1 ! Pole - ! Reich-Moore indices - integer, parameter :: RM_RT = 2, & ! Residue total - RM_RA = 3, & ! Residue absorption - RM_RF = 4 ! Residue fission - - ! Multi-level Breit Wigner indices - integer, parameter :: MLBW_RT = 2, & ! Residue total - MLBW_RX = 3, & ! Residue compettitive - MLBW_RA = 4, & ! Residue absorption - MLBW_RF = 5 ! Residue fission + ! Residue indices + integer, parameter :: MP_RS = 2, & ! Residue scattering + MP_RA = 3, & ! Residue absorption + MP_RF = 4 ! Residue fission ! Polynomial fit indices - integer, parameter :: FIT_T = 1, & ! Total + integer, parameter :: FIT_S = 1, & ! Scattering FIT_A = 2, & ! Absorption FIT_F = 3 ! Fission @@ -46,33 +35,22 @@ module multipole_header ! Isotope Properties logical :: fissionable ! Is this isotope fissionable? - integer, allocatable :: l_value(:) ! The l index of the pole - integer :: num_l ! Number of unique l values - real(8), allocatable :: pseudo_k0RS(:) ! The value (sqrt(2*mass neutron - ! /reduced planck constant) - ! * AWR/(AWR + 1) - ! * scattering radius for - ! each l complex(8), allocatable :: data(:,:) ! Poles and residues real(8) :: sqrtAWR ! Square root of the atomic ! weight ratio - integer :: formalism ! R-matrix formalism !========================================================================= ! Windows integer :: fit_order ! Order of the fit. 1 linear, ! 2 quadratic, etc. - real(8) :: start_E ! Start energy for the windows - real(8) :: end_E ! End energy for the windows + real(8) :: E_min ! Start energy for the windows + real(8) :: E_max ! End energy for the windows real(8) :: spacing ! The actual spacing in sqrt(E) ! space. - ! spacing = sqrt(multipole_w % endE - multipole_w % startE) - ! / multipole_w % windows - integer, allocatable :: w_start(:) ! Contains the index of the pole at - ! the start of the window - integer, allocatable :: w_end(:) ! Contains the index of the pole at - ! the end of the window + integer, allocatable :: windows(:, :) ! Contains the indexes of the poles + ! at the start and end of the + ! window real(8), allocatable :: curvefit(:,:,:) ! Contains the fitting function. ! (reaction type, coeff index, ! window index) @@ -96,7 +74,7 @@ contains character(len=*), intent(in) :: filename character(len=10) :: version - integer :: i, n_poles, n_residue_types, n_windows + integer :: i, n_poles, n_residues, n_windows integer(HSIZE_T) :: dims_1d(1), dims_2d(2), dims_3d(3) integer(HID_T) :: file_id integer(HID_T) :: group_id @@ -114,65 +92,49 @@ contains // trim(filename) // " uses version " // trim(version) // ".") ! Read scalar values. - call read_dataset(this % formalism, group_id, "formalism") call read_dataset(this % spacing, group_id, "spacing") call read_dataset(this % sqrtAWR, group_id, "sqrtAWR") - call read_dataset(this % start_E, group_id, "start_E") - call read_dataset(this % end_E, group_id, "end_E") + call read_dataset(this % E_min, group_id, "E_min") + call read_dataset(this % E_max, group_id, "E_max") ! Read the "data" array. Use its shape to figure out the number of poles ! and residue types in this data. dset = open_dataset(group_id, "data") call get_shape(dset, dims_2d) - n_residue_types = int(dims_2d(1), 4) - 1 + n_residues = int(dims_2d(1), 4) - 1 n_poles = int(dims_2d(2), 4) - allocate(this % data(n_residue_types+1, n_poles)) - call read_dataset(this % data, dset) + allocate(this % data(n_residues+1, n_poles)) + if (n_poles > 0) call read_dataset(this % data, dset) call close_dataset(dset) ! Check to see if this data includes fission residues. - if (this % formalism == FORM_RM) then - this % fissionable = (n_residue_types == 3) - else - ! Assume FORM_MLBW. - this % fissionable = (n_residue_types == 4) - end if + this % fissionable = (n_residues == 3) - ! Read the "l_value" array. - allocate(this % l_value(n_poles)) - call read_dataset(this % l_value, group_id, "l_value") - - ! Figure out the number of unique l values in the l_value array. - do i = 1, n_poles - if (.not. l_val_dict % has(this % l_value(i))) then - call l_val_dict % set(this % l_value(i), 0) - end if - end do - this % num_l = l_val_dict % size() - call l_val_dict % clear() - - ! Read the "pseudo_K0RS" array. - allocate(this % pseudo_k0RS(this % num_l)) - call read_dataset(this % pseudo_k0RS, group_id, "pseudo_K0RS") - - ! Read the "w_start" array and use its shape to figure out the number of + ! Read the "windows" array and use its shape to figure out the number of ! windows. - dset = open_dataset(group_id, "w_start") - call get_shape(dset, dims_1d) - n_windows = int(dims_1d(1), 4) - allocate(this % w_start(n_windows)) - call read_dataset(this % w_start, dset) + dset = open_dataset(group_id, "windows") + call get_shape(dset, dims_2d) + n_windows = int(dims_2d(2), 4) + allocate(this % windows(dims_2d(1), n_windows)) + call read_dataset(this % windows, dset) call close_dataset(dset) - ! Read the "w_end" and "broaden_poly" arrays. - allocate(this % w_end(n_windows)) - call read_dataset(this % w_end, group_id, "w_end") + ! Read the "broaden_poly" arrays. + dset = open_dataset(group_id, "broaden_poly") + call get_shape(dset, dims_1d) + if (dims_1d(1) /= n_windows) call fatal_error("broaden_poly array shape is& + ¬ consistent with the windows array shape in multipole library"& + // trim(filename) // ".") allocate(this % broaden_poly(n_windows)) - call read_dataset(this % broaden_poly, group_id, "broaden_poly") + call read_dataset(this % broaden_poly, dset) + call close_dataset(dset) ! Read the "curvefit" array. dset = open_dataset(group_id, "curvefit") call get_shape(dset, dims_3d) + if (dims_3d(3) /= n_windows) call fatal_error("curvefit array shape is not& + &consistent with the windows array shape in multipole library"& + // trim(filename) // ".") allocate(this % curvefit(dims_3d(1), dims_3d(2), dims_3d(3))) call read_dataset(this % curvefit, dset) call close_dataset(dset) diff --git a/src/nuclide_header.F90 b/src/nuclide_header.F90 index 8cd225bc9..a2e47fa43 100644 --- a/src/nuclide_header.F90 +++ b/src/nuclide_header.F90 @@ -12,11 +12,9 @@ module nuclide_header use hdf5_interface use math, only: faddeeva, w_derivative, & broaden_wmp_polynomials - use multipole_header, only: FORM_RM, FORM_MLBW, MP_EA, RM_RT, RM_RA, & - RM_RF, MLBW_RT, MLBW_RX, MLBW_RA, MLBW_RF, & - FIT_T, FIT_A, FIT_F, MultipoleArray + use multipole_header, only: MP_EA, MP_RS, MP_RA, MP_RF, & + FIT_S, FIT_A, FIT_F, MultipoleArray use message_passing - use multipole_header, only: MultipoleArray use random_lcg, only: prn, future_prn, prn_set_stream use reaction_header, only: Reaction use sab_header, only: SAlphaBeta, sab_tables @@ -849,7 +847,7 @@ contains integer :: threshold ! threshold energy index real(8) :: f ! interp factor on nuclide energy grid real(8) :: kT ! temperature in eV - real(8) :: sig_t, sig_a, sig_f ! Intermediate multipole variables + real(8) :: sig_s, sig_a, sig_f ! Intermediate multipole variables ! Initialize cached cross sections to zero micro_xs % elastic = CACHE_INVALID @@ -859,8 +857,8 @@ contains ! Check to see if there is multipole data present at this energy use_mp = .false. if (this % mp_present) then - if (E >= this % multipole % start_E .and. & - E <= this % multipole % end_E) then + if (E >= this % multipole % E_min .and. & + E <= this % multipole % E_max) then use_mp = .true. end if end if @@ -868,9 +866,10 @@ contains ! Evaluate multipole or interpolate if (use_mp) then ! Call multipole kernel - call multipole_eval(this % multipole, E, sqrtkT, sig_t, sig_a, sig_f) + call multipole_eval(this % multipole, E, sqrtkT, sig_s, sig_a, sig_f) - micro_xs % total = sig_t + micro_xs % total = sig_s + sig_a + micro_xs % elastic = sig_s micro_xs % absorption = sig_a micro_xs % fission = sig_f @@ -1076,9 +1075,6 @@ contains micro_xs % elastic = (ONE - f) * rx % xs(i_temp, i_grid) + & f * rx % xs(i_temp, i_grid + 1) end associate - else - ! For multipole, elastic is total - absorption - micro_xs % elastic = micro_xs % total - micro_xs % absorption end if end subroutine nuclide_calculate_elastic_xs @@ -1130,7 +1126,7 @@ contains ! sections in the resolved resonance regions !=============================================================================== - subroutine multipole_eval(multipole, E, sqrtkT, sig_t, sig_a, sig_f) + subroutine multipole_eval(multipole, E, sqrtkT, sig_s, sig_a, sig_f) type(MultipoleArray), intent(in) :: multipole ! The windowed multipole ! object to process. real(8), intent(in) :: E ! The energy at which to @@ -1138,7 +1134,7 @@ contains real(8), intent(in) :: sqrtkT ! The temperature in the form ! sqrt(kT), at which ! to evaluate the XS. - real(8), intent(out) :: sig_t ! Total cross section + real(8), intent(out) :: sig_s ! Scattering cross section real(8), intent(out) :: sig_a ! Absorption cross section real(8), intent(out) :: sig_f ! Fission cross section complex(8) :: psi_chi ! The value of the psi-chi function for the @@ -1146,7 +1142,6 @@ contains complex(8) :: c_temp ! complex temporary variable complex(8) :: w_val ! The faddeeva function evaluated at Z complex(8) :: Z ! sqrt(atomic weight ratio / kT) * (sqrt(E) - pole) - complex(8) :: sig_t_factor(multipole % num_l) real(8) :: broadened_polynomials(multipole % fit_order + 1) real(8) :: sqrtE ! sqrt(E), eV real(8) :: invE ! 1/E, eV @@ -1166,18 +1161,13 @@ contains invE = ONE / E ! Locate us. - i_window = floor((sqrtE - sqrt(multipole % start_E)) / multipole % spacing & + i_window = floor((sqrtE - sqrt(multipole % E_min)) / multipole % spacing & + ONE) - startw = multipole % w_start(i_window) - endw = multipole % w_end(i_window) - - ! Fill in factors. - if (startw <= endw) then - call compute_sig_t_factor(multipole, sqrtE, sig_t_factor) - end if + startw = multipole % windows(1, i_window) + endw = multipole % windows(2, i_window) ! Initialize the ouptut cross sections. - sig_t = ZERO + sig_s = ZERO sig_a = ZERO sig_f = ZERO @@ -1190,7 +1180,7 @@ contains call broaden_wmp_polynomials(E, dopp, multipole % fit_order + 1, & broadened_polynomials) do i_poly = 1, multipole % fit_order+1 - sig_t = sig_t + multipole % curvefit(FIT_T, i_poly, i_window) & + sig_s = sig_s + multipole % curvefit(FIT_S, i_poly, i_window) & * broadened_polynomials(i_poly) sig_a = sig_a + multipole % curvefit(FIT_A, i_poly, i_window) & * broadened_polynomials(i_poly) @@ -1202,7 +1192,7 @@ contains else ! Evaluate as if it were a polynomial temp = invE do i_poly = 1, multipole % fit_order+1 - sig_t = sig_t + multipole % curvefit(FIT_T, i_poly, i_window) * temp + sig_s = sig_s + multipole % curvefit(FIT_S, i_poly, i_window) * temp sig_a = sig_a + multipole % curvefit(FIT_A, i_poly, i_window) * temp if (multipole % fissionable) then sig_f = sig_f + multipole % curvefit(FIT_F, i_poly, i_window) * temp @@ -1219,21 +1209,10 @@ contains do i_pole = startw, endw psi_chi = -ONEI / (multipole % data(MP_EA, i_pole) - sqrtE) c_temp = psi_chi / E - if (multipole % formalism == FORM_MLBW) then - sig_t = sig_t + real(multipole % data(MLBW_RT, i_pole) * c_temp * & - sig_t_factor(multipole % l_value(i_pole))) & - + real(multipole % data(MLBW_RX, i_pole) * c_temp) - sig_a = sig_a + real(multipole % data(MLBW_RA, i_pole) * c_temp) - if (multipole % fissionable) then - sig_f = sig_f + real(multipole % data(MLBW_RF, i_pole) * c_temp) - end if - else if (multipole % formalism == FORM_RM) then - sig_t = sig_t + real(multipole % data(RM_RT, i_pole) * c_temp * & - sig_t_factor(multipole % l_value(i_pole))) - sig_a = sig_a + real(multipole % data(RM_RA, i_pole) * c_temp) - if (multipole % fissionable) then - sig_f = sig_f + real(multipole % data(RM_RF, i_pole) * c_temp) - end if + sig_s = sig_s + real(multipole % data(MP_RS, i_pole) * c_temp) + sig_a = sig_a + real(multipole % data(MP_RA, i_pole) * c_temp) + if (multipole % fissionable) then + sig_f = sig_f + real(multipole % data(MP_RF, i_pole) * c_temp) end if end do else @@ -1243,21 +1222,10 @@ contains do i_pole = startw, endw Z = (sqrtE - multipole % data(MP_EA, i_pole)) * dopp w_val = faddeeva(Z) * dopp * invE * SQRT_PI - if (multipole % formalism == FORM_MLBW) then - sig_t = sig_t + real((multipole % data(MLBW_RT, i_pole) * & - sig_t_factor(multipole % l_value(i_pole)) + & - multipole % data(MLBW_RX, i_pole)) * w_val) - sig_a = sig_a + real(multipole % data(MLBW_RA, i_pole) * w_val) - if (multipole % fissionable) then - sig_f = sig_f + real(multipole % data(MLBW_RF, i_pole) * w_val) - end if - else if (multipole % formalism == FORM_RM) then - sig_t = sig_t + real(multipole % data(RM_RT, i_pole) * w_val * & - sig_t_factor(multipole % l_value(i_pole))) - sig_a = sig_a + real(multipole % data(RM_RA, i_pole) * w_val) - if (multipole % fissionable) then - sig_f = sig_f + real(multipole % data(RM_RF, i_pole) * w_val) - end if + sig_s = sig_s + real(multipole % data(MP_RS, i_pole) * w_val) + sig_a = sig_a + real(multipole % data(MP_RA, i_pole) * w_val) + if (multipole % fissionable) then + sig_f = sig_f + real(multipole % data(MP_RF, i_pole) * w_val) end if end do end if @@ -1270,7 +1238,7 @@ contains ! temperature. !=============================================================================== - subroutine multipole_deriv_eval(multipole, E, sqrtkT, sig_t, sig_a, sig_f) + subroutine multipole_deriv_eval(multipole, E, sqrtkT, sig_s, sig_a, sig_f) type(MultipoleArray), intent(in) :: multipole ! The windowed multipole ! object to process. real(8), intent(in) :: E ! The energy at which to @@ -1278,12 +1246,11 @@ contains real(8), intent(in) :: sqrtkT ! The temperature in the form ! sqrt(kT), at which to ! evaluate the XS. - real(8), intent(out) :: sig_t ! Total cross section + real(8), intent(out) :: sig_s ! Scattering cross section real(8), intent(out) :: sig_a ! Absorption cross section real(8), intent(out) :: sig_f ! Fission cross section complex(8) :: w_val ! The faddeeva function evaluated at Z complex(8) :: Z ! sqrt(atomic weight ratio / kT) * (sqrt(E) - pole) - complex(8) :: sig_t_factor(multipole % num_l) real(8) :: sqrtE ! sqrt(E), eV real(8) :: invE ! 1/E, eV real(8) :: dopp ! sqrt(atomic weight ratio / kT) @@ -1305,18 +1272,13 @@ contains &derivatives are not implemented for 0 Kelvin cross sections.") ! Locate us - i_window = floor((sqrtE - sqrt(multipole % start_E)) / multipole % spacing & + i_window = floor((sqrtE - sqrt(multipole % E_min)) / multipole % spacing & + ONE) - startw = multipole % w_start(i_window) - endw = multipole % w_end(i_window) - - ! Fill in factors. - if (startw <= endw) then - call compute_sig_t_factor(multipole, sqrtE, sig_t_factor) - end if + startw = multipole % windows(1, i_window) + endw = multipole % windows(2, i_window) ! Initialize the ouptut cross sections. - sig_t = ZERO + sig_s = ZERO sig_a = ZERO sig_f = ZERO @@ -1333,61 +1295,18 @@ contains do i_pole = startw, endw Z = (sqrtE - multipole % data(MP_EA, i_pole)) * dopp w_val = -invE * SQRT_PI * HALF * w_derivative(Z, 2) - if (multipole % formalism == FORM_MLBW) then - sig_t = sig_t + real((multipole % data(MLBW_RT, i_pole) * & - sig_t_factor(multipole%l_value(i_pole)) + & - multipole % data(MLBW_RX, i_pole)) * w_val) - sig_a = sig_a + real(multipole % data(MLBW_RA, i_pole) * w_val) - if (multipole % fissionable) then - sig_f = sig_f + real(multipole % data(MLBW_RF, i_pole) * w_val) - end if - else if (multipole % formalism == FORM_RM) then - sig_t = sig_t + real(multipole % data(RM_RT, i_pole) * w_val * & - sig_t_factor(multipole % l_value(i_pole))) - sig_a = sig_a + real(multipole % data(RM_RA, i_pole) * w_val) - if (multipole % fissionable) then - sig_f = sig_f + real(multipole % data(RM_RF, i_pole) * w_val) - end if + sig_s = sig_s + real(multipole % data(MP_RS, i_pole) * w_val) + sig_a = sig_a + real(multipole % data(MP_RA, i_pole) * w_val) + if (multipole % fissionable) then + sig_f = sig_f + real(multipole % data(MP_RF, i_pole) * w_val) end if end do - sig_t = -HALF*multipole % sqrtAWR / sqrt(K_BOLTZMANN) * T**(-1.5) * sig_t + sig_s = -HALF*multipole % sqrtAWR / sqrt(K_BOLTZMANN) * T**(-1.5) * sig_s sig_a = -HALF*multipole % sqrtAWR / sqrt(K_BOLTZMANN) * T**(-1.5) * sig_a sig_f = -HALF*multipole % sqrtAWR / sqrt(K_BOLTZMANN) * T**(-1.5) * sig_f end if end subroutine multipole_deriv_eval -!=============================================================================== -! COMPUTE_SIG_T_FACTOR calculates the sig_t_factor, a factor inside of the sig_t -! equation not present in the sig_a and sig_f equations. -!=============================================================================== - - subroutine compute_sig_t_factor(multipole, sqrtE, sig_t_factor) - type(MultipoleArray), intent(in) :: multipole - real(8), intent(in) :: sqrtE - complex(8), intent(out) :: sig_t_factor(multipole % num_l) - - integer :: iL - real(8) :: twophi(multipole % num_l) - real(8) :: arg - - do iL = 1, multipole % num_l - twophi(iL) = multipole % pseudo_k0RS(iL) * sqrtE - if (iL == 2) then - twophi(iL) = twophi(iL) - atan(twophi(iL)) - else if (iL == 3) then - arg = 3.0_8 * twophi(iL) / (3.0_8 - twophi(iL)**2) - twophi(iL) = twophi(iL) - atan(arg) - else if (iL == 4) then - arg = twophi(iL) * (15.0_8 - twophi(iL)**2) & - / (15.0_8 - 6.0_8 * twophi(iL)**2) - twophi(iL) = twophi(iL) - atan(arg) - end if - end do - - twophi = 2.0_8 * twophi - sig_t_factor = cmplx(cos(twophi), -sin(twophi), KIND=8) - end subroutine compute_sig_t_factor - !=============================================================================== ! 0K_ELASTIC_XS determines the microscopic 0K elastic cross section ! for a given nuclide at the trial relative energy used in resonance scattering diff --git a/src/physics.F90 b/src/physics.F90 index d5f6302a8..fa75fa0ed 100644 --- a/src/physics.F90 +++ b/src/physics.F90 @@ -526,8 +526,8 @@ contains ! Check to see if we are in a windowed multipole range. WMP only supports ! the first fission reaction. if (nuc % mp_present) then - if (E >= nuc % multipole % start_E .and. & - E <= nuc % multipole % end_E) then + if (E >= nuc % multipole % E_min .and. & + E <= nuc % multipole % E_max) then i_reaction = nuc % index_fission(1) return end if diff --git a/src/tallies/tally.F90 b/src/tallies/tally.F90 index 2c660ce87..2365ec46f 100644 --- a/src/tallies/tally.F90 +++ b/src/tallies/tally.F90 @@ -3009,7 +3009,7 @@ contains integer :: l logical :: scoring_diff_nuclide real(8) :: flux_deriv - real(8) :: dsig_t, dsig_a, dsig_f, cum_dsig + real(8) :: dsig_s, dsig_a, dsig_f, cum_dsig if (score == ZERO) return @@ -3250,17 +3250,18 @@ contains if (mat % nuclide(l) == p % event_nuclide) exit end do - dsig_t = ZERO + dsig_s = ZERO associate (nuc => nuclides(p % event_nuclide)) if (nuc % mp_present .and. & - p % last_E >= nuc % multipole % start_E .and. & - p % last_E <= nuc % multipole % end_E) then + p % last_E >= nuc % multipole % E_min .and. & + p % last_E <= nuc % multipole % E_max) then call multipole_deriv_eval(nuc % multipole, p % last_E, & - p % sqrtkT, dsig_t, dsig_a, dsig_f) + p % sqrtkT, dsig_s, dsig_a, dsig_f) end if end associate score = score * (flux_deriv & - + dsig_t * mat % atom_density(l) / material_xs % total) + + (dsig_s + dsig_a) * mat % atom_density(l) & + / material_xs % total) end associate else score = score * flux_deriv @@ -3276,18 +3277,17 @@ contains if (mat % nuclide(l) == p % event_nuclide) exit end do - dsig_t = ZERO + dsig_s = ZERO dsig_a = ZERO associate (nuc => nuclides(p % event_nuclide)) if (nuc % mp_present .and. & - p % last_E >= nuc % multipole % start_E .and. & - p % last_E <= nuc % multipole % end_E) then + p % last_E >= nuc % multipole % E_min .and. & + p % last_E <= nuc % multipole % E_max) then call multipole_deriv_eval(nuc % multipole, p % last_E, & - p % sqrtkT, dsig_t, dsig_a, dsig_f) + p % sqrtkT, dsig_s, dsig_a, dsig_f) end if end associate - score = score * (flux_deriv + (dsig_t - dsig_a) & - * mat % atom_density(l) / & + score = score * (flux_deriv + dsig_s * mat % atom_density(l) / & (material_xs % total - material_xs % absorption)) end associate else @@ -3306,10 +3306,10 @@ contains dsig_a = ZERO associate (nuc => nuclides(p % event_nuclide)) if (nuc % mp_present .and. & - p % last_E >= nuc % multipole % start_E .and. & - p % last_E <= nuc % multipole % end_E) then + p % last_E >= nuc % multipole % E_min .and. & + p % last_E <= nuc % multipole % E_max) then call multipole_deriv_eval(nuc % multipole, p % last_E, & - p % sqrtkT, dsig_t, dsig_a, dsig_f) + p % sqrtkT, dsig_s, dsig_a, dsig_f) end if end associate score = score * (flux_deriv + dsig_a * mat % atom_density(l) & @@ -3331,10 +3331,10 @@ contains dsig_f = ZERO associate (nuc => nuclides(p % event_nuclide)) if (nuc % mp_present .and. & - p % last_E >= nuc % multipole % start_E .and. & - p % last_E <= nuc % multipole % end_E) then + p % last_E >= nuc % multipole % E_min .and. & + p % last_E <= nuc % multipole % E_max) then call multipole_deriv_eval(nuc % multipole, p % last_E, & - p % sqrtkT, dsig_t, dsig_a, dsig_f) + p % sqrtkT, dsig_s, dsig_a, dsig_f) end if end associate score = score * (flux_deriv & @@ -3356,10 +3356,10 @@ contains dsig_f = ZERO associate (nuc => nuclides(p % event_nuclide)) if (nuc % mp_present .and. & - p % last_E >= nuc % multipole % start_E .and. & - p % last_E <= nuc % multipole % end_E) then + p % last_E >= nuc % multipole % E_min .and. & + p % last_E <= nuc % multipole % E_max) then call multipole_deriv_eval(nuc % multipole, p % last_E, & - p % sqrtkT, dsig_t, dsig_a, dsig_f) + p % sqrtkT, dsig_s, dsig_a, dsig_f) end if end associate score = score * (flux_deriv & @@ -3392,12 +3392,13 @@ contains do l = 1, mat % n_nuclides associate (nuc => nuclides(mat % nuclide(l))) if (nuc % mp_present .and. & - p % last_E >= nuc % multipole % start_E .and. & - p % last_E <= nuc % multipole % end_E .and. & + p % last_E >= nuc % multipole % E_min .and. & + p % last_E <= nuc % multipole % E_max .and. & micro_xs(mat % nuclide(l)) % total > ZERO) then call multipole_deriv_eval(nuc % multipole, p % last_E, & - p % sqrtkT, dsig_t, dsig_a, dsig_f) - cum_dsig = cum_dsig + dsig_t * mat % atom_density(l) + p % sqrtkT, dsig_s, dsig_a, dsig_f) + cum_dsig = cum_dsig + (dsig_s + dsig_a) & + * mat % atom_density(l) end if end associate end do @@ -3406,17 +3407,17 @@ contains + cum_dsig / material_xs % total) else if (materials(p % material) % id == deriv % diff_material & .and. material_xs % total > ZERO) then - dsig_t = ZERO + dsig_s = ZERO associate (nuc => nuclides(i_nuclide)) if (nuc % mp_present .and. & - p % last_E >= nuc % multipole % start_E .and. & - p % last_E <= nuc % multipole % end_E) then + p % last_E >= nuc % multipole % E_min .and. & + p % last_E <= nuc % multipole % E_max) then call multipole_deriv_eval(nuc % multipole, p % last_E, & - p % sqrtkT, dsig_t, dsig_a, dsig_f) + p % sqrtkT, dsig_s, dsig_a, dsig_f) end if end associate score = score * (flux_deriv & - + dsig_t / micro_xs(i_nuclide) % total) + + (dsig_s + dsig_a) / micro_xs(i_nuclide) % total) else score = score * flux_deriv end if @@ -3430,14 +3431,13 @@ contains do l = 1, mat % n_nuclides associate (nuc => nuclides(mat % nuclide(l))) if (nuc % mp_present .and. & - p % last_E >= nuc % multipole % start_E .and. & - p % last_E <= nuc % multipole % end_E .and. & + p % last_E >= nuc % multipole % E_min .and. & + p % last_E <= nuc % multipole % E_max .and. & (micro_xs(mat % nuclide(l)) % total & - micro_xs(mat % nuclide(l)) % absorption) > ZERO) then call multipole_deriv_eval(nuc % multipole, p % last_E, & - p % sqrtkT, dsig_t, dsig_a, dsig_f) - cum_dsig = cum_dsig & - + (dsig_t - dsig_a) * mat % atom_density(l) + p % sqrtkT, dsig_s, dsig_a, dsig_f) + cum_dsig = cum_dsig + dsig_s * mat % atom_density(l) end if end associate end do @@ -3447,17 +3447,17 @@ contains else if ( materials(p % material) % id == deriv % diff_material & .and. (material_xs % total - material_xs % absorption) > ZERO)& then - dsig_t = ZERO + dsig_s = ZERO dsig_a = ZERO associate (nuc => nuclides(i_nuclide)) if (nuc % mp_present .and. & - p % last_E >= nuc % multipole % start_E .and. & - p % last_E <= nuc % multipole % end_E) then + p % last_E >= nuc % multipole % E_min .and. & + p % last_E <= nuc % multipole % E_max) then call multipole_deriv_eval(nuc % multipole, p % last_E, & - p % sqrtkT, dsig_t, dsig_a, dsig_f) + p % sqrtkT, dsig_s, dsig_a, dsig_f) end if end associate - score = score * (flux_deriv + (dsig_t - dsig_a) & + score = score * (flux_deriv + dsig_s & / (micro_xs(i_nuclide) % total & - micro_xs(i_nuclide) % absorption)) else @@ -3473,11 +3473,11 @@ contains do l = 1, mat % n_nuclides associate (nuc => nuclides(mat % nuclide(l))) if (nuc % mp_present .and. & - p % last_E >= nuc % multipole % start_E .and. & - p % last_E <= nuc % multipole % end_E .and. & + p % last_E >= nuc % multipole % E_min .and. & + p % last_E <= nuc % multipole % E_max .and. & micro_xs(mat % nuclide(l)) % absorption > ZERO) then call multipole_deriv_eval(nuc % multipole, p % last_E, & - p % sqrtkT, dsig_t, dsig_a, dsig_f) + p % sqrtkT, dsig_s, dsig_a, dsig_f) cum_dsig = cum_dsig + dsig_a * mat % atom_density(l) end if end associate @@ -3490,10 +3490,10 @@ contains dsig_a = ZERO associate (nuc => nuclides(i_nuclide)) if (nuc % mp_present .and. & - p % last_E >= nuc % multipole % start_E .and. & - p % last_E <= nuc % multipole % end_E) then + p % last_E >= nuc % multipole % E_min .and. & + p % last_E <= nuc % multipole % E_max) then call multipole_deriv_eval(nuc % multipole, p % last_E, & - p % sqrtkT, dsig_t, dsig_a, dsig_f) + p % sqrtkT, dsig_s, dsig_a, dsig_f) end if end associate score = score * (flux_deriv & @@ -3511,11 +3511,11 @@ contains do l = 1, mat % n_nuclides associate (nuc => nuclides(mat % nuclide(l))) if (nuc % mp_present .and. & - p % last_E >= nuc % multipole % start_E .and. & - p % last_E <= nuc % multipole % end_E .and. & + p % last_E >= nuc % multipole % E_min .and. & + p % last_E <= nuc % multipole % E_max .and. & micro_xs(mat % nuclide(l)) % fission > ZERO) then call multipole_deriv_eval(nuc % multipole, p % last_E, & - p % sqrtkT, dsig_t, dsig_a, dsig_f) + p % sqrtkT, dsig_s, dsig_a, dsig_f) cum_dsig = cum_dsig + dsig_f * mat % atom_density(l) end if end associate @@ -3528,10 +3528,10 @@ contains dsig_f = ZERO associate (nuc => nuclides(i_nuclide)) if (nuc % mp_present .and. & - p % last_E >= nuc % multipole % start_E .and. & - p % last_E <= nuc % multipole % end_E) then + p % last_E >= nuc % multipole % E_min .and. & + p % last_E <= nuc % multipole % E_max) then call multipole_deriv_eval(nuc % multipole, p % last_E, & - p % sqrtkT, dsig_t, dsig_a, dsig_f) + p % sqrtkT, dsig_s, dsig_a, dsig_f) end if end associate score = score * (flux_deriv & @@ -3549,11 +3549,11 @@ contains do l = 1, mat % n_nuclides associate (nuc => nuclides(mat % nuclide(l))) if (nuc % mp_present .and. & - p % last_E >= nuc % multipole % start_E .and. & - p % last_E <= nuc % multipole % end_E .and. & + p % last_E >= nuc % multipole % E_min .and. & + p % last_E <= nuc % multipole % E_max .and. & micro_xs(mat % nuclide(l)) % nu_fission > ZERO) then call multipole_deriv_eval(nuc % multipole, p % last_E, & - p % sqrtkT, dsig_t, dsig_a, dsig_f) + p % sqrtkT, dsig_s, dsig_a, dsig_f) cum_dsig = cum_dsig + dsig_f * mat % atom_density(l) & * micro_xs(mat % nuclide(l)) % nu_fission & / micro_xs(mat % nuclide(l)) % fission @@ -3568,10 +3568,10 @@ contains dsig_f = ZERO associate (nuc => nuclides(i_nuclide)) if (nuc % mp_present .and. & - p % last_E >= nuc % multipole % start_E .and. & - p % last_E <= nuc % multipole % end_E) then + p % last_E >= nuc % multipole % E_min .and. & + p % last_E <= nuc % multipole % E_max) then call multipole_deriv_eval(nuc % multipole, p % last_E, & - p % sqrtkT, dsig_t, dsig_a, dsig_f) + p % sqrtkT, dsig_s, dsig_a, dsig_f) end if end associate score = score * (flux_deriv & @@ -3603,7 +3603,7 @@ contains real(8), intent(in) :: distance ! Neutron flight distance integer :: i, l - real(8) :: dsig_t, dsig_a, dsig_f + real(8) :: dsig_s, dsig_a, dsig_f ! A void material cannot be perturbed so it will not affect flux derivatives if (p % material == MATERIAL_VOID) return @@ -3640,15 +3640,15 @@ contains do l=1, mat % n_nuclides associate (nuc => nuclides(mat % nuclide(l))) if (nuc % mp_present .and. & - p % E >= nuc % multipole % start_E .and. & - p % E <= nuc % multipole % end_E) then + p % E >= nuc % multipole % E_min .and. & + p % E <= nuc % multipole % E_max) then ! phi is proportional to e^(-Sigma_tot * dist) ! (1 / phi) * (d_phi / d_T) = - (d_Sigma_tot / d_T) * dist ! (1 / phi) * (d_phi / d_T) = - N (d_sigma_tot / d_T) * dist call multipole_deriv_eval(nuc % multipole, p % E, & - p % sqrtkT, dsig_t, dsig_a, dsig_f) + p % sqrtkT, dsig_s, dsig_a, dsig_f) deriv % flux_deriv = deriv % flux_deriv & - - distance * dsig_t * mat % atom_density(l) + - distance * (dsig_s + dsig_a) * mat % atom_density(l) end if end associate end do @@ -3679,7 +3679,7 @@ contains type(Particle), intent(in) :: p integer :: i, j, l - real(8) :: dsig_t, dsig_a, dsig_f + real(8) :: dsig_s, dsig_a, dsig_f ! A void material cannot be perturbed so it will not affect flux derivatives if (p % material == MATERIAL_VOID) return @@ -3727,14 +3727,14 @@ contains associate (nuc => nuclides(mat % nuclide(l))) if (mat % nuclide(l) == p % event_nuclide .and. & nuc % mp_present .and. & - p % last_E >= nuc % multipole % start_E .and. & - p % last_E <= nuc % multipole % end_E) then + p % last_E >= nuc % multipole % E_min .and. & + p % last_E <= nuc % multipole % E_max) then ! phi is proportional to Sigma_s ! (1 / phi) * (d_phi / d_T) = (d_Sigma_s / d_T) / Sigma_s ! (1 / phi) * (d_phi / d_T) = (d_sigma_s / d_T) / sigma_s call multipole_deriv_eval(nuc % multipole, p % last_E, & - p % sqrtkT, dsig_t, dsig_a, dsig_f) - deriv % flux_deriv = deriv % flux_deriv + (dsig_t - dsig_a)& + p % sqrtkT, dsig_s, dsig_a, dsig_f) + deriv % flux_deriv = deriv % flux_deriv + (dsig_s + dsig_a)& / (micro_xs(mat % nuclide(l)) % total & - micro_xs(mat % nuclide(l)) % absorption) ! Note that this is an approximation! The real scattering From 57387bf1361048b02fc35f8b8c91e28a87744f6f Mon Sep 17 00:00:00 2001 From: Zhuoran Han Date: Thu, 16 Aug 2018 10:39:25 -0500 Subject: [PATCH 08/56] Add Polynomial Class for Pn and Zn rad --- openmc/__init__.py | 1 + openmc/polynomials.py | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 openmc/polynomials.py diff --git a/openmc/__init__.py b/openmc/__init__.py index 191528327..c7db3171c 100644 --- a/openmc/__init__.py +++ b/openmc/__init__.py @@ -28,6 +28,7 @@ from openmc.particle_restart import * from openmc.mixin import * from openmc.plotter import * from openmc.search import * +from openmc.polynomials import * from . import examples # Import a few convencience functions that used to be here diff --git a/openmc/polynomials.py b/openmc/polynomials.py new file mode 100644 index 000000000..b3de1b992 --- /dev/null +++ b/openmc/polynomials.py @@ -0,0 +1,35 @@ +import numpy as np +import openmc +import openmc.capi as capi + +class Polynomials(object): + """Class for Polynomials""" + def __init__(self, coeff): + self.coeff = coeff + self.n_coeff = len(coeff) + +class Legendre(Polynomials): + def __init__(self, coeff, domain_min = -1, domain_max = 1): + super().__init__(coeff) + self.order = self.n_coeff - 1 + self.domain_min = domain_min + self.domain_max = domain_max + self.norm_vec = (2 * np.arange(self.n_coeff) + 1) / (self.domain_max + - self.domain_min) + self.norm_coeff = np.multiply(self.norm_vec,self.coeff) + + def __call__(self, x): + pn = capi.calc_pn(self.order, x) + return np.sum(np.multiply(self.norm_coeff, pn)) + +class ZernikeRadial(Polynomials): + def __init__(self,coeff,radius = 1): + super().__init__(coeff) + self.order = 2 * (self.n_coeff - 1) + self.radius = radius + self.norm_vec = (2 * np.arange(self.n_coeff) + 1)/(np.pi * radius ** 2) + self.norm_coeff = np.multiply(self.norm_vec,self.coeff) + + def __call__(self, r): + zn_rad = capi.calc_zn_rad(self.order, r) + return np.sum(np.multiply(self.norm_coeff, zn_rad)) \ No newline at end of file From a67aab9c4091ccca24425c79c79c1ccb9c3c2f4a Mon Sep 17 00:00:00 2001 From: Zhuoran Han Date: Thu, 16 Aug 2018 10:46:34 -0500 Subject: [PATCH 09/56] revert math funcs for reconstruction, since it is not very necessary --- src/math_functions.cpp | 53 +++---------------------------------- src/math_functions.h | 59 +++++++----------------------------------- 2 files changed, 13 insertions(+), 99 deletions(-) diff --git a/src/math_functions.cpp b/src/math_functions.cpp index 72fb85ae8..8a36f7b92 100644 --- a/src/math_functions.cpp +++ b/src/math_functions.cpp @@ -103,36 +103,17 @@ void calc_pn_c(int n, double x, double pnx[]) { } -double evaluate_legendre_c(int n, const double data[], double x, int flag) { +double evaluate_legendre_c(int n, const double data[], double x) { double pnx[n + 1]; double val = 0.0; calc_pn_c(n, x, pnx); - - if (flag == 1) { - for (int l = 0; l <= n; l++) { - val += (l + 0.5) * data[l] * pnx[l]; - } - } else if (flag == 2) { // if flag is 2, we don't apply any normalization - for (int l = 0; l <= n; l++) { - val += data[l] * pnx[l]; - } + for (int l = 0; l <= n; l++) { + val += (l + 0.5) * data[l] * pnx[l]; } - return val; } -void calc_norm_pn_c(int l, double zmin, double zmax, double norm_vec[]) { - // =========================================================================== - // Set up the normalization vector for FET Pn reconstruction - double d = zmax - zmin; - - for (int i = 0; i <= l; i++) { - norm_vec[i] = (2 * i + 1)/d; - } -} - - void calc_rn_c(int n, const double uvw[3], double rn[]){ // rn[] is assumed to have already been allocated to the correct size @@ -634,34 +615,6 @@ void calc_zn_rad_c(int n, double rho, double zn_rad[]) { } -void calc_norm_zn_rad_c(int n, double r, double norm_vec[]) { - // =========================================================================== - // Set up the normalization vector for FET Zn Radial only reconstruction - int index; - - for (int i = 0; i <= n; i+=2) { - index = int(i/2); - norm_vec[index] = (i + 1)/(PI * r * r); - } -} - - -double evaluate_zernike_rad_c(int n, const double data[], double r) { - // data here is already normalized outside this function - double rnr[n / 2 + 1]; - double val = 0.0; - calc_zn_rad_c(n, r, rnr); - int index; - - for (int i = 0; i <= n; i+= 2) { - index = int(i/2); - val += data[index] * rnr[index]; - } - - return val; -} - - void rotate_angle_c(double uvw[3], double mu, double* phi) { // Copy original directional cosines double u0 = uvw[0]; // original cosine in x direction diff --git a/src/math_functions.h b/src/math_functions.h index 30e210e50..e0ecad60e 100644 --- a/src/math_functions.h +++ b/src/math_functions.h @@ -53,27 +53,11 @@ extern "C" void calc_pn_c(int n, double x, double pnx[]); //! @param data The polynomial expansion coefficient data; without the (2l+1)/2 //! factor. //! @param x The value to evaluate at; x is expected to be within [-1,1] -//! @param flag A flag of which method to calculate Legendre polynomials. 1 for -//! default (2l+1)/2; 2 for custom normalized coefficients //! @return The requested Legendre polynomials of order 0 to n (inclusive) //! evaluated at x //============================================================================== -extern "C" double evaluate_legendre_c(int n, const double data[], double x, int flag = 1); - -//============================================================================== -//! Evaluate the normalization vector when reconstructing functional expansion -//! from Legendre polynomials. -//! -//! The normalization is (2 * l + 1)/(zmax - zmin) -//! -//! @param l The maximum order requested -//! @param zmin The minimum location of 1-d domain -//! @param zmax The maximum location of 1-d domain -//! @param norm_vec The requested normalization of order 0 to n (inclusive) -//============================================================================== - -extern "C" void calc_norm_pn_c(int l, double zmin, double zmax, double norm_vec[]); +extern "C" double evaluate_legendre_c(int n, const double data[], double x); //============================================================================== //! Calculate the n-th order real spherical harmonics for a given angle (in @@ -85,7 +69,6 @@ extern "C" void calc_norm_pn_c(int l, double zmin, double zmax, double norm_vec[ //! evaluated at uvw. //============================================================================== - extern "C" void calc_rn_c(int n, const double uvw[3], double rn[]); //============================================================================== @@ -109,13 +92,18 @@ extern "C" void calc_rn_c(int n, const double uvw[3], double rn[]); extern "C" void calc_zn_c(int n, double rho, double phi, double zn[]); //============================================================================== -//! Calculate only the even order components of n-th order modified Zernike -//! polynomial moment with azimuthal dependency m = 0 for a given radial (rho) -//! location on the unit disk. +//! Calculate only the even radial components of n-th order modified Zernike +//! polynomial moment with azimuthal dependency m = 0 for a given angle +//! (rho, theta) location on the unit disk. //! //! Since m = 0, n could only be even orders. Z_q0 = R_q0 //! -//! See calc_zn_c for methodology. +//! This procedure uses the modified Kintner's method for calculating Zernike +//! polynomials as outlined in Chong, C. W., Raveendran, P., & Mukundan, +//! R. (2003). A comparative analysis of algorithms for fast computation of +//! Zernike moments. Pattern Recognition, 36(3), 731-742. +//! The normalization of the polynomials is such that the integral of Z_pq^2 +//! over the unit disk is exactly pi. //! //! @param n The maximum order requested //! @param rho The radial parameter to specify location on the unit disk @@ -126,33 +114,6 @@ extern "C" void calc_zn_c(int n, double rho, double phi, double zn[]); extern "C" void calc_zn_rad_c(int n, double rho, double zn_rad[]); -//============================================================================== -//! Evaluate the normalization vector when reconstructing functional expansion -//! from radial only Zernike polynomials. -//! -//! The normalization is (2 * l + 1)/(zmax - zmin) -//! -//! @param n The maximum order requested -//! @param r The radius of the disk -//! @param norm_vec The requested normalization of even orders from 0 to n -//============================================================================== - -extern "C" void calc_norm_zn_rad_c(int n, double r, double norm_vec[]); - -//============================================================================== -//! Find the value of f(x) given a set of even order Zernike coefficients and -//! the value of x if there is only radial dependency. -//! -//! @param n The maximum order of the expansion -//! @param data The overall polynomial expansion coefficient data; -//! normalization should be considered by users -//! @param r The value to evaluate at; r is expected to be within [0,1] -//! @return The requested Zernike polynomials of order 0 to n (inclusive) -//! evaluated at r -//============================================================================== - -extern "C" double evaluate_zernike_rad_c(int n, const double data[], double r); - //============================================================================== //! Rotate the direction cosines through a polar angle whose cosine is mu and //! through an azimuthal angle sampled uniformly. From 1e7b5bb3274cb6e2863a677b2a3277adac708fc4 Mon Sep 17 00:00:00 2001 From: Zhuoran Han Date: Thu, 16 Aug 2018 10:57:32 -0500 Subject: [PATCH 10/56] revert capi bc we will have new class --- openmc/capi/math.py | 93 ++------------------------------------------- 1 file changed, 4 insertions(+), 89 deletions(-) diff --git a/openmc/capi/math.py b/openmc/capi/math.py index 697ed558d..390ee466f 100644 --- a/openmc/capi/math.py +++ b/openmc/capi/math.py @@ -13,10 +13,7 @@ _dll.calc_pn_c.restype = None _dll.calc_pn_c.argtypes = [c_int, c_double, ndpointer(c_double)] _dll.evaluate_legendre_c.restype = c_double -_dll.evaluate_legendre_c.argtypes = [c_int, POINTER(c_double), c_double, c_int] - -_dll.calc_norm_pn_c.restype = None -_dll.calc_norm_pn_c.argtypes =[c_int, c_double, c_double, ndpointer(c_double)] +_dll.evaluate_legendre_c.argtypes = [c_int, POINTER(c_double), c_double] _dll.calc_rn_c.restype = None _dll.calc_rn_c.argtypes = [c_int, ndpointer(c_double), ndpointer(c_double)] @@ -27,12 +24,6 @@ _dll.calc_zn_c.argtypes = [c_int, c_double, c_double, ndpointer(c_double)] _dll.calc_zn_rad_c.restype = None _dll.calc_zn_rad_c.argtypes = [c_int, c_double, ndpointer(c_double)] -_dll.evaluate_zernike_rad_c.restype = c_double -_dll.evaluate_zernike_rad_c.argtypes = [c_int, POINTER(c_double), c_double] - -_dll.calc_norm_zn_rad_c.restype = None -_dll.calc_norm_zn_rad_c.argtypes = [c_int, c_double, ndpointer(c_double)] - _dll.rotate_angle_c.restype = None _dll.rotate_angle_c.argtypes = [ndpointer(c_double), c_double, POINTER(c_double)] @@ -90,7 +81,7 @@ def calc_pn(n, x): return pnx -def evaluate_legendre(data, x, flag=1): +def evaluate_legendre(data, x): """ Finds the value of f(x) given a set of Legendre coefficients and the value of x. @@ -100,8 +91,6 @@ def evaluate_legendre(data, x, flag=1): Legendre coefficients x : float Independent variable to evaluate the Legendre at - flag : int - Flags to indicate use default normalization or not Returns ------- @@ -113,31 +102,7 @@ def evaluate_legendre(data, x, flag=1): data_arr = np.array(data, dtype=np.float64) return _dll.evaluate_legendre_c(len(data), data_arr.ctypes.data_as(POINTER(c_double)), - x, flag) - - -def calc_norm_pn(l, zmin, zmax): - """ Calculate normalization arrays for n orders in Legendre polynomial. - - Parameters - ---------- - l : int - Maximum order - zmin : float - The lowest boundary of the domain - zmax : float - The highest boundary of the domain - - Returns - ------- - numpy.ndarray - Corresponding resulting list of normalization coefficients - - """ - - norm_pn = np.empty(l + 1, dtype=np.float64) - _dll.calc_norm_pn_c(l, zmin, zmax, norm_pn) - return norm_pn + x) def calc_rn(n, uvw): @@ -217,57 +182,7 @@ def calc_zn_rad(n, rho): zn_rad = np.zeros(num_bins, dtype=np.float64) _dll.calc_zn_rad_c(n, rho, zn_rad) return zn_rad - - -def evaluate_zernike_rad(data, r): - """ Finds the value of f(x) given a set of even order Zernike coefficients - and the value of r. - - Parameters - ---------- - data : iterable of float - Legendre coefficients - r : float - Independent variable to evaluate the radial part of Zernike at - - Returns - ------- - float - Corresponding Zernike expansion result - - """ - - data_arr = np.array(data, dtype=np.float64) - n = int(2 * (len(data) - 1)) - return _dll.evaluate_zernike_rad_c(n, - data_arr.ctypes.data_as(POINTER( - c_double)), - r) - - -def calc_norm_zn_rad(n, rho): - """ Calculate normalization arrays for the even orders in modified Zernike - polynomial moment with no azimuthal dependency (m=0). - - Parameters - ---------- - n : int - Maximum order - rho : float - Radial location in the unit disk - - Returns - ------- - numpy.ndarray - Corresponding resulting list of normalization coefficients - - """ - - num_bins = n // 2 + 1 - norm_zn_rad = np.zeros(num_bins, dtype=np.float64) - _dll.calc_norm_zn_rad_c(n, rho, norm_zn_rad) - return norm_zn_rad - + def rotate_angle(uvw0, mu, phi=None): """ Rotates direction cosines through a polar angle whose cosine is From 886017ebb0473818cd86f1719ec16e19e85a12df Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Fri, 3 Aug 2018 15:23:45 -0500 Subject: [PATCH 11/56] Add CoherentElasticXS function type --- src/endf.cpp | 31 +++++++++++++++++++++++++++++++ src/endf.h | 13 +++++++++++++ 2 files changed, 44 insertions(+) diff --git a/src/endf.cpp b/src/endf.cpp index 859183d12..8a63893a7 100644 --- a/src/endf.cpp +++ b/src/endf.cpp @@ -144,4 +144,35 @@ double Tabulated1D::operator()(double x) const } } +//============================================================================== +// CoherentElasticXS implementation +//============================================================================== + +CoherentElasticXS::CoherentElasticXS(hid_t dset) +{ + // Read 2D array from dataset + xt::xarray arr; + read_dataset(dset, arr); + + // Get views for Bragg edges and structure factors + auto E = xt::view(arr, 0); + auto s = xt::view(arr, 1); + + // Copy Bragg edges and partial sums of structure factors + std::copy(E.begin(), E.end(), std::back_inserter(bragg_edges_)); + std::copy(s.begin(), s.end(), std::back_inserter(factors_)); +} + +double CoherentElasticXS::operator()(double E) const +{ + if (E < bragg_edges_[0]) { + // If energy is below that of the lowest Bragg peak, the elastic cross + // section will be zero + return 0.0; + } else { + auto i_grid = lower_bound_index(bragg_edges_.begin(), bragg_edges_.end(), E); + return factors_[i_grid] / E; + } +} + } // namespace openmc diff --git a/src/endf.h b/src/endf.h index d2d67685d..369f5d5a6 100644 --- a/src/endf.h +++ b/src/endf.h @@ -73,6 +73,19 @@ private: std::vector y_; //!< values of ordinate }; +//============================================================================== +//! Coherent elastic scattering data from a crystalline material +//============================================================================== + +class CoherentElasticXS : public Function1D { + explicit CoherentElasticXS(hid_t dset); + double operator()(double E) const; +private: + std::vector bragg_edges_; //!< Bragg edges in [eV] + std::vector factors_; //!< Partial sums of structure factors [eV-b] +}; + + } // namespace openmc #endif // OPENMC_ENDF_H From 1d872dcaa3ae54ffecfed284ae1dbe02107a2c8e Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 13 Aug 2018 16:11:48 -0500 Subject: [PATCH 12/56] Add read_attribute overload for vector and dataset_names --- src/hdf5_interface.cpp | 15 +++++++++++++-- src/hdf5_interface.h | 20 ++++++++++++++++++++ 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/src/hdf5_interface.cpp b/src/hdf5_interface.cpp index 5d6926479..74d26a58b 100644 --- a/src/hdf5_interface.cpp +++ b/src/hdf5_interface.cpp @@ -327,7 +327,7 @@ get_groups(hid_t group_id, char* name[]) } std::vector -group_names(hid_t group_id) +member_names(hid_t group_id, H5O_type_t type) { // Determine number of links in the group H5G_info_t info; @@ -341,7 +341,7 @@ group_names(hid_t group_id) // Determine type of object (and skip non-group) H5Oget_info_by_idx(group_id, ".", H5_INDEX_NAME, H5_ITER_INC, i, &oinfo, H5P_DEFAULT); - if (oinfo.type != H5O_TYPE_GROUP) continue; + if (oinfo.type != type) continue; // Get size of name size = 1 + H5Lget_name_by_idx(group_id, ".", H5_INDEX_NAME, H5_ITER_INC, @@ -356,6 +356,17 @@ group_names(hid_t group_id) return names; } +std::vector +group_names(hid_t group_id) +{ + return member_names(group_id, H5O_TYPE_GROUP); +} + +std::vector +dataset_names(hid_t group_id) +{ + return member_names(group_id, H5O_TYPE_DATASET); +} bool object_exists(hid_t object_id, const char* name) diff --git a/src/hdf5_interface.h b/src/hdf5_interface.h index 65a9e2c99..5f7f3064c 100644 --- a/src/hdf5_interface.h +++ b/src/hdf5_interface.h @@ -74,6 +74,7 @@ read_nd_vector(hid_t obj_id, const char* name, bool must_have = false); std::vector attribute_shape(hid_t obj_id, const char* name); +std::vector dataset_names(hid_t group_id); void ensure_exists(hid_t group_id, const char* name); std::vector group_names(hid_t group_id); std::vector object_shape(hid_t obj_id); @@ -209,6 +210,25 @@ read_attribute(hid_t obj_id, const char* name, std::string& str) str = std::string{buffer, n}; } +// overload for std::vector +inline void +read_attribute(hid_t obj_id, const char* name, std::vector& vec) +{ + auto dims = attribute_shape(obj_id, name); + auto m = dims[0]; + + // Allocate a C char array to get strings + auto n = attribute_typesize(obj_id, name); + char buffer[m][n+1]; + + // Read char data in attribute + read_attr_string(obj_id, name, n, buffer[0]); + + for (int i = 0; i < m; ++i) { + vec.emplace_back(&buffer[i][0]); + } +} + //============================================================================== // Templates/overloads for read_dataset //============================================================================== From 5f3022989cd4b75c94e1315e5932815eeb11481d Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Tue, 14 Aug 2018 22:21:41 -0500 Subject: [PATCH 13/56] Initial version of ThermalScattering class --- CMakeLists.txt | 1 + src/distribution.h | 4 + src/secondary_correlated.h | 24 ++- src/settings.cpp | 9 +- src/settings.h | 9 +- src/thermal.cpp | 353 +++++++++++++++++++++++++++++++++++++ src/thermal.h | 78 ++++++++ 7 files changed, 468 insertions(+), 10 deletions(-) create mode 100644 src/thermal.cpp create mode 100644 src/thermal.h diff --git a/CMakeLists.txt b/CMakeLists.txt index dc9a1231b..efbffcb58 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -418,6 +418,7 @@ add_library(libopenmc SHARED src/state_point.cpp src/string_functions.cpp src/surface.cpp + src/thermal.cpp src/xml_interface.cpp src/xsdata.cpp) set_target_properties(libopenmc PROPERTIES diff --git a/src/distribution.h b/src/distribution.h index 84819e3f7..815248a2e 100644 --- a/src/distribution.h +++ b/src/distribution.h @@ -107,6 +107,10 @@ public: //! Sample a value from the distribution //! \return Sampled value double sample() const; + + // x property + std::vector& x() { return x_; } + const std::vector& x() const { return x_; } private: std::vector x_; //!< tabulated independent variable std::vector p_; //!< tabulated probability density diff --git a/src/secondary_correlated.h b/src/secondary_correlated.h index 3b6aae9c1..1e3eab0ab 100644 --- a/src/secondary_correlated.h +++ b/src/secondary_correlated.h @@ -21,14 +21,6 @@ namespace openmc { class CorrelatedAngleEnergy : public AngleEnergy { public: - explicit CorrelatedAngleEnergy(hid_t group); - - //! Sample distribution for an angle and energy - //! \param[in] E_in Incoming energy in [eV] - //! \param[out] E_out Outgoing energy in [eV] - //! \param[out] mu Outgoing cosine with respect to current direction - void sample(double E_in, double& E_out, double& mu) const; -private: //! Outgoing energy/angle at a single incoming energy struct CorrTable { int n_discrete; //!< Number of discrete lines @@ -39,6 +31,22 @@ private: std::vector angle; //!< Angle distribution }; + explicit CorrelatedAngleEnergy(hid_t group); + + //! Sample distribution for an angle and energy + //! \param[in] E_in Incoming energy in [eV] + //! \param[out] E_out Outgoing energy in [eV] + //! \param[out] mu Outgoing cosine with respect to current direction + void sample(double E_in, double& E_out, double& mu) const; + + // energy property + std::vector& energy() { return energy_; } + const std::vector& energy() const { return energy_; } + + // distribution property + std::vector& distribution() { return distribution_; } + const std::vector& distribution() const { return distribution_; } +private: int n_region_; //!< Number of interpolation regions std::vector breakpoints_; //!< Breakpoints between regions std::vector interpolation_; //!< Interpolation laws diff --git a/src/settings.cpp b/src/settings.cpp index 8ecc04a79..8ca07a527 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -1,5 +1,6 @@ #include "settings.h" +#include "constants.h" #include "error.h" #include "openmc.h" #include "string_utils.h" @@ -20,6 +21,12 @@ std::string path_multipole; std::string path_output; std::string path_source; +int temperature_method {TEMPERATURE_NEAREST}; +bool temperature_multipole {false}; +double temperature_tolerance {10.0}; +double temperature_default {293.6}; +std::array temperature_range {0.0, 0.0}; + //============================================================================== // Functions //============================================================================== @@ -67,4 +74,4 @@ void read_settings(pugi::xml_node* root) } } -} // namespace openmc \ No newline at end of file +} // namespace openmc diff --git a/src/settings.h b/src/settings.h index c203aafde..ea4dfebdc 100644 --- a/src/settings.h +++ b/src/settings.h @@ -4,6 +4,7 @@ //! \file settings.h //! \brief Settings for OpenMC +#include #include #include "pugixml.hpp" @@ -31,6 +32,12 @@ extern std::string path_multipole; extern std::string path_output; extern std::string path_source; +extern int temperature_method; +extern bool temperature_multipole; +extern double temperature_tolerance; +extern double temperature_default; +extern std::array temperature_range; + //============================================================================== //! Read settings from XML file //! \param[in] root XML node for @@ -40,4 +47,4 @@ extern "C" void read_settings(pugi::xml_node* root); } // namespace openmc -#endif // OPENMC_SETTINGS_H \ No newline at end of file +#endif // OPENMC_SETTINGS_H diff --git a/src/thermal.cpp b/src/thermal.cpp new file mode 100644 index 000000000..b4818d080 --- /dev/null +++ b/src/thermal.cpp @@ -0,0 +1,353 @@ +#include "thermal.h" + +#include // for sort, move +#include // for round +#include // for stringstream + +#include "xtensor/xarray.hpp" +#include "xtensor/xbuilder.hpp" +#include "xtensor/xmath.hpp" +#include "xtensor/xsort.hpp" +#include "xtensor/xtensor.hpp" +#include "xtensor/xview.hpp" + +#include "constants.h" +#include "error.h" +#include "random_lcg.h" +#include "search.h" +#include "secondary_correlated.h" +#include "settings.h" + +namespace openmc { + +//============================================================================== +// ThermalScattering implementation +//============================================================================== + +ThermalScattering::ThermalScattering(hid_t group, const std::vector& temperature, + int method, double tolerance, const double* minmax) +{ + // Get name of table from group + name_ = object_name(group); + + // Get rid of leading '/' + name_ = name_.substr(1); + + read_attribute(group, "atomic_weight_ratio", awr_); + read_attribute(group, "nuclides", nuclides_); + std::string sec_mode; + read_attribute(group, "secondary_mode", sec_mode); + if (sec_mode == "equal") { + secondary_mode_ = SAB_SECONDARY_EQUAL; + } else if (sec_mode == "skewed") { + secondary_mode_ = SAB_SECONDARY_SKEWED; + } else if (sec_mode == "continuous") { + secondary_mode_ = SAB_SECONDARY_CONT; + } + + // Read temperatures + hid_t kT_group = open_group(group, "kTs"); + + // Determine temperatures available + auto dset_names = dataset_names(kT_group); + auto n = dset_names.size(); + auto temps_available = xt::empty({n}); + for (int i = 0; i < dset_names.size(); ++i) { + // Read temperature value + double T; + read_dataset(kT_group, dset_names[i].data(), T); + temps_available[i] = T / K_BOLTZMANN; + } + std::sort(temps_available.begin(), temps_available.end()); + + // Determine actual temperatures to read -- start by checking whether a + // temperature range was given, in which case all temperatures in the range + // are loaded irrespective of what temperatures actually appear in the model + std::vector temps_to_read; + if (minmax[1] > 0.0) { + for (const auto& T : temps_available) { + if (minmax[0] <= T && T <= minmax[1]) { + temps_to_read.push_back(std::round(T)); + } + } + } + + switch (method) { + case TEMPERATURE_NEAREST: + // Determine actual temperatures to read + for (const auto& T : temperature) { + + auto i_closest = xt::argmin(xt::abs(temps_available - T))[0]; + auto temp_actual = temps_available[i_closest]; + if (std::fabs(temp_actual - T) < tolerance) { + if (std::find(temps_to_read.begin(), temps_to_read.end(), std::round(temp_actual)) + == temps_to_read.end()) { + temps_to_read.push_back(std::round(temp_actual)); + } + } else { + std::stringstream msg; + msg << "Nuclear data library does not contain cross sections for " + << name_ << " at or near " << std::round(T) << " K."; + fatal_error(msg); + } + } + break; + + case TEMPERATURE_INTERPOLATION: + // If temperature interpolation or multipole is selected, get a list of + // bounding temperatures for each actual temperature present in the model + for (const auto& T : temperature) { + bool found = false; + for (int j = 0; j < temps_available.size() - 1; ++j) { + if (temps_available[j] <= T && T < temps_available[j + 1]) { + int T_j = std::round(temps_available[j]); + int T_j1 = std::round(temps_available[j + 1]); + if (std::find(temps_to_read.begin(), temps_to_read.end(), T_j) == temps_to_read.end()) { + temps_to_read.push_back(T_j); + } + if (std::find(temps_to_read.begin(), temps_to_read.end(), T_j1) == temps_to_read.end()) { + temps_to_read.push_back(T_j1); + } + found = true; + } + } + if (!found) { + std::stringstream msg; + msg << "Nuclear data library does not contain cross sections for " + << name_ << " at temperatures that bound " << std::round(T) << " K."; + fatal_error(msg); + } + } + } + + // Sort temperatures to read + std::sort(temps_to_read.begin(), temps_to_read.end()); + + auto n_temperature = temps_to_read.size(); + kTs_.reserve(n_temperature); + data_.reserve(n_temperature); + + for (auto T : temps_to_read) { + // Get temperature as a string + std::string temp_str = std::to_string(T) + "K"; + + // Read exact temperature value + double kT; + read_dataset(kT_group, temp_str.data(), kT); + kTs_.push_back(kT); + + // Open group for temperature i + hid_t T_group = open_group(group, temp_str.data()); + data_.emplace_back(T_group, secondary_mode_); + close_group(group); + } + + close_group(kT_group); +} + +void +ThermalScattering::calculate_xs(double E, double sqrtkT, int* i_temp, + double* elastic, double* inelastic) +{ + // Determine temperature for S(a,b) table + double kT = sqrtkT*sqrtkT; + int i; + if (temperature_method == TEMPERATURE_NEAREST) { + // If using nearest temperature, do linear search on temperature + for (i = 0; i < kTs_.size(); ++i) { + if (abs(kTs_[i] - kT) < K_BOLTZMANN*temperature_tolerance) { + break; + } + } + } else { + // Find temperatures that bound the actual temperature + for (i = 0; i < kTs_.size() - 1; ++i) { + if (kTs_[i] <= kT && kT < kTs_[i+1]) { + break; + } + } + + // Randomly sample between temperature i and i+1 + double f = (kT - kTs_[i]) / (kTs_[i+1] - kTs_[i]); + if (f > prn()) ++i; + } + + // Set temperature index + *i_temp = i; + + // Get pointer to S(a,b) table + auto& sab = data_[i]; + + // Get index and interpolation factor for inelastic grid + int i_grid; + double f; + if (E < sab.inelastic_e_in_.front()) { + i_grid = 0; + f = 0.0; + } else { + auto& E_in = sab.inelastic_e_in_; + i_grid = lower_bound_index(E_in.begin(), E_in.end(), E); + f = (E - E_in[i_grid]) / (E_in[i_grid+1] - E_in[i_grid]); + } + + // Calculate S(a,b) inelastic scattering cross section + auto& xs = sab.inelastic_sigma_; + *inelastic = (1.0 - f) * xs[i_grid] + f * xs[i_grid + 1]; + + // Check for elastic data + if (E < sab.threshold_elastic_) { + // Determine whether elastic scattering is given in the coherent or + // incoherent approximation. For coherent, the cross section is + // represented as P/E whereas for incoherent, it is simply P + + auto& E_in = sab.elastic_e_in_; + + if (sab.elastic_mode_ == SAB_ELASTIC_EXACT) { + if (E < E_in.front()) { + // If energy is below that of the lowest Bragg peak, the elastic + // cross section will be zero + *elastic = 0.0; + } else { + i_grid = lower_bound_index(E_in.begin(), E_in.end(), E); + *elastic = sab.elastic_P_[i_grid] / E; + } + } else { + // Determine index on elastic energy grid + if (E < E_in.front()) { + i_grid = 0; + } else { + i_grid = lower_bound_index(E_in.begin(), E_in.end(), E); + } + + // Get interpolation factor for elastic grid + f = (E - E_in[i_grid])/(E_in[i_grid+1] - E_in[i_grid]); + + // Calculate S(a,b) elastic scattering cross section + auto& xs = sab.elastic_P_; + *elastic = (1.0 - f) * xs[i_grid] + f * xs[i_grid + 1]; + } + } else { + // No elastic data + *elastic = 0.0; + } +} + +//============================================================================== +// ThermalData implementation +//============================================================================== + +ThermalData::ThermalData(hid_t group, int secondary_mode) +{ + // Coherent elastic data + if (object_exists(group, "elastic")) { + // Read cross section data + hid_t elastic_group = open_group(group, "elastic"); + + // Read elastic cross section + xt::xarray temp; + hid_t dset = open_dataset(elastic_group, "xs"); + read_dataset(dset, temp); + + // Get view on energies and cross section/probability values + auto E_in = xt::view(temp, 0); + auto P = xt::view(temp, 1); + + // Set cross section data and type + std::copy(E_in.begin(), E_in.end(), std::back_inserter(elastic_e_in_)); + std::copy(P.begin(), P.end(), std::back_inserter(elastic_P_)); + n_elastic_e_in_ = elastic_e_in_.size(); + + // Determine elastic type + std::string type; + read_attribute(dset, "type", type); + if (type == "tab1") { + elastic_mode_ = SAB_ELASTIC_DISCRETE; + } else if (type == "bragg") { + elastic_mode_ = SAB_ELASTIC_EXACT; + } + close_dataset(dset); + + // Set elastic threshold + threshold_elastic_ = elastic_e_in_.back(); + + // Read angle distribution + if (elastic_mode_ != SAB_ELASTIC_EXACT) { + xt::xarray mu_out; + read_dataset(elastic_group, "mu_out", mu_out); + elastic_mu_ = mu_out; + } + + close_group(elastic_group); + } + + // Inelastic data + if (object_exists(group, "inelastic")) { + // Read type of inelastic data + hid_t inelastic_group = open_group(group, "inelastic"); + + // Read cross section data + xt::xarray temp; + read_dataset(inelastic_group, "xs", temp); + + // Get view of inelastic cross section and energy grid + auto E_in = xt::view(temp, 0); + auto xs = xt::view(temp, 1); + + // Set cross section data + std::copy(E_in.begin(), E_in.end(), std::back_inserter(inelastic_e_in_)); + std::copy(xs.begin(), xs.end(), std::back_inserter(inelastic_sigma_)); + n_inelastic_e_in_ = inelastic_e_in_.size(); + + // Set inelastic threshold + threshold_inelastic_ = inelastic_e_in_.back(); + + if (secondary_mode != SAB_SECONDARY_CONT) { + // Read energy distribution + xt::xarray E_out; + read_dataset(inelastic_group, "energy_out", E_out); + inelastic_e_out_ = E_out; + + // Read angle distribution + xt::xarray mu_out; + read_dataset(inelastic_group, "mu_out", mu_out); + inelastic_mu_ = mu_out; + } else { + // Read correlated angle-energy distribution + CorrelatedAngleEnergy dist {inelastic_group}; + + // Convert to S(a,b) native format + for (const auto& edist : dist.distribution()) { + // Create temporary distribution + DistEnergySab d; + + // Copy outgoing energy distribution + d.n_e_out = edist.e_out.size(); + d.e_out = edist.e_out; + d.e_out_pdf = edist.p; + d.e_out_cdf = edist.c; + + for (int j = 0; j < d.n_e_out; ++j) { + auto adist = dynamic_cast(edist.angle[j].get()); + if (adist) { + // On first pass, allocate space for angles + if (j == 0) { + auto n_mu = adist->x().size(); + n_inelastic_mu_ = n_mu; + d.mu = xt::empty({d.n_e_out, n_mu}); + } + + // Copy outgoing angles + auto mu_j = xt::view(d.mu, j); + std::copy(adist->x().begin(), adist->x().end(), mu_j.begin()); + } + } + + inelastic_data_.push_back(std::move(d)); + } + } + + close_group(inelastic_group); + } +} + +} // namespace openmc diff --git a/src/thermal.h b/src/thermal.h new file mode 100644 index 000000000..59f5c97ee --- /dev/null +++ b/src/thermal.h @@ -0,0 +1,78 @@ +#ifndef OPENMC_THERMAL_SCATTERING_H +#define OPENMC_THERMAL_SCATTERING_H + +#include +#include +#include + +#include "xtensor/xtensor.hpp" + +#include "hdf5_interface.h" + +namespace openmc { + +class ThermalData { +public: + ThermalData(hid_t group, int secondary_mode); +private: + struct DistEnergySab { + std::size_t n_e_out; + xt::xtensor e_out; + xt::xtensor e_out_pdf; + xt::xtensor e_out_cdf; + xt::xtensor mu; + }; + + // Threshold for thermal scattering treatment (usually ~4 eV) + double threshold_inelastic_; + double threshold_elastic_ {0.0}; + + // Inelastic scattering data + std::size_t n_inelastic_e_in_; // # of incoming E for inelastic + std::size_t n_inelastic_e_out_; // # of outgoing E for inelastic + std::size_t n_inelastic_mu_; // # of outgoing angles for inelastic + std::vector inelastic_e_in_; + std::vector inelastic_sigma_; + + // The following are used only if secondary_mode is 0 or 1 + xt::xtensor inelastic_e_out_; + xt::xtensor inelastic_mu_; + + // The following is used only if secondary_mode is 3 + // The different implementation is necessary because the continuous + // representation has a variable number of outgoing energy points for each + // incoming energy + std::vector inelastic_data_; // One for each Ein + + // Elastic scattering data + int elastic_mode_; // elastic mode (discrete/exact) + std::size_t n_elastic_e_in_; // # of incoming E for elastic + std::size_t n_elastic_mu_; // # of outgoing angles for elastic + std::vector elastic_e_in_; + std::vector elastic_P_; + xt::xtensor elastic_mu_; + + friend class ThermalScattering; +}; + +class ThermalScattering { +public: + ThermalScattering(hid_t group, const std::vector& temperature, int method, + double tolerance, const double* minmax); + + void calculate_xs(double E, double sqrtkT, int* i_temp, double* elastic, + double* inelastic); + + std::string name_; // name of table, e.g. "c_H_in_H2O" + double awr_; // weight of nucleus in neutron masses + std::vector kTs_; // temperatures in eV (k*T) + std::vector nuclides_; // List of valid nuclides + int secondary_mode_; // secondary mode (equal/skewed/continuous) + + // cross sections and distributions at each temperature + std::vector data_; +}; + +} // namespace openmc + +#endif // OPENMC_THERMAL_SCATTERING_H From aab7b7ca41b2bd8cd68cc9cb9eabaa627bd954f7 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 15 Aug 2018 10:07:40 -0500 Subject: [PATCH 14/56] Add ThermalData::sample routine (based on sab_scatter) --- src/constants.h | 13 +-- src/nuclide.h | 67 +++++++++++ src/nuclide_header.F90 | 40 +++---- src/settings.cpp | 26 +++++ src/thermal.cpp | 245 +++++++++++++++++++++++++++++++++++++++-- src/thermal.h | 18 ++- src/xml_interface.cpp | 15 +++ src/xml_interface.h | 4 +- 8 files changed, 384 insertions(+), 44 deletions(-) create mode 100644 src/nuclide.h diff --git a/src/constants.h b/src/constants.h index b6bb82d37..12dc21b71 100644 --- a/src/constants.h +++ b/src/constants.h @@ -130,17 +130,6 @@ constexpr int ANGLE_HISTOGRAM {5}; constexpr int TEMPERATURE_NEAREST {1}; constexpr int TEMPERATURE_INTERPOLATION {2}; -// Secondary energy mode for S(a,b) inelastic scattering -// TODO: Convert to enum -constexpr int SAB_SECONDARY_EQUAL {0}; // Equally-likely outgoing energy bins -constexpr int SAB_SECONDARY_SKEWED {1}; // Skewed outgoing energy bins -constexpr int SAB_SECONDARY_CONT {2}; // Continuous, linear-linear interpolation - -// Elastic mode for S(a,b) elastic scattering -// TODO: Convert to enum -constexpr int SAB_ELASTIC_DISCRETE {3}; // Sample from discrete cosines -constexpr int SAB_ELASTIC_EXACT {4}; // Exact treatment for coherent elastic - // Reaction types // TODO: Convert to enum constexpr int TOTAL_XS {1}; @@ -260,6 +249,8 @@ constexpr int N_AC {849}; constexpr int N_2N0 {875}; constexpr int N_2NC {891}; +constexpr std::array DEPLETION_RX {N_GAMMA, N_P, N_A, N_2N, N_3N, N_4N}; + // Fission neutron emission (nu) type constexpr int NU_NONE {0}; // No nu values (non-fissionable) constexpr int NU_POLYNOMIAL {1}; // Nu values given by polynomial diff --git a/src/nuclide.h b/src/nuclide.h new file mode 100644 index 000000000..8c43d55a0 --- /dev/null +++ b/src/nuclide.h @@ -0,0 +1,67 @@ +#ifndef OPENMC_NUCLIDE_H +#define OPENMC_NUCLIDE_H + +#include "constants.h" + +namespace openmc { + +//=============================================================================== +//! Cached microscopic cross sections for a particular nuclide at the current +//! energy +//=============================================================================== + +struct NuclideMicroXS { + // Microscopic cross sections in barns + double total; //!< total cross section + double absorption; //!< absorption (disappearance) + double fission; //!< fission + double nu_fission; //!< neutron production from fission + + double elastic; //!< If sab_frac is not 1 or 0, then this value is + //!< averaged over bound and non-bound nuclei + double thermal; //!< Bound thermal elastic & inelastic scattering + double thermal_elastic; //!< Bound thermal elastic scattering + double photon_prod; //!< microscopic photon production xs + + // Cross sections for depletion reactions (note that these are not stored in + // macroscopic cache) + double reaction[DEPLETION_RX.size()]; + + // Indicies and factors needed to compute cross sections from the data tables + int index_grid; //!< Index on nuclide energy grid + int index_temp; //!< Temperature index for nuclide + double interp_factor; //!< Interpolation factor on nuc. energy grid + int index_sab {-1}; //!< Index in sab_tables + int index_temp_sab; //!< Temperature index for sab_tables + double sab_frac; //!< Fraction of atoms affected by S(a,b) + bool use_ptable; //!< In URR range with probability tables? + + // Energy and temperature last used to evaluate these cross sections. If + // these values have changed, then the cross sections must be re-evaluated. + double last_E {0.0}; //!< Last evaluated energy + double last_sqrtkT {0.0}; //!< Last temperature in sqrt(Boltzmann constant + //!< * temperature (eV)) +}; + +//=============================================================================== +// MATERIALMACROXS contains cached macroscopic cross sections for the material a +// particle is traveling through +//=============================================================================== + + struct MaterialMacroXS { + double total; //!< macroscopic total xs + double absorption; //!< macroscopic absorption xs + double fission; //!< macroscopic fission xs + double nu_fission; //!< macroscopic production xs + double photon_prod; //!< macroscopic photon production xs + + // Photon cross sections + double coherent; //!< macroscopic coherent xs + double incoherent; //!< macroscopic incoherent xs + double photoelectric; //!< macroscopic photoelectric xs + double pair_production; //!< macroscopic pair production xs + }; + +} // namespace openmc + +#endif // OPENMC_NUCLIDE_H diff --git a/src/nuclide_header.F90 b/src/nuclide_header.F90 index 8cd225bc9..6faaaec7f 100644 --- a/src/nuclide_header.F90 +++ b/src/nuclide_header.F90 @@ -126,36 +126,36 @@ module nuclide_header ! (NuclideMicroXS % elastic) real(8), parameter :: CACHE_INVALID = dble(Z"FFE0000000000000") - type NuclideMicroXS + type, bind(C) :: NuclideMicroXS ! Microscopic cross sections in barns - real(8) :: total - real(8) :: absorption ! absorption (disappearance) - real(8) :: fission ! fission - real(8) :: nu_fission ! neutron production from fission + real(C_DOUBLE) :: total + real(C_DOUBLE) :: absorption ! absorption (disappearance) + real(C_DOUBLE) :: fission ! fission + real(C_DOUBLE) :: nu_fission ! neutron production from fission - real(8) :: elastic ! If sab_frac is not 1 or 0, then this value is + real(C_DOUBLE) :: elastic ! If sab_frac is not 1 or 0, then this value is ! averaged over bound and non-bound nuclei - real(8) :: thermal ! Bound thermal elastic & inelastic scattering - real(8) :: thermal_elastic ! Bound thermal elastic scattering - real(8) :: photon_prod ! microscopic photon production xs + real(C_DOUBLE) :: thermal ! Bound thermal elastic & inelastic scattering + real(C_DOUBLE) :: thermal_elastic ! Bound thermal elastic scattering + real(C_DOUBLE) :: photon_prod ! microscopic photon production xs ! Cross sections for depletion reactions (note that these are not stored in ! macroscopic cache) - real(8) :: reaction(size(DEPLETION_RX)) + real(C_DOUBLE) :: reaction(size(DEPLETION_RX)) ! Indicies and factors needed to compute cross sections from the data tables - integer :: index_grid ! Index on nuclide energy grid - integer :: index_temp ! Temperature index for nuclide - real(8) :: interp_factor ! Interpolation factor on nuc. energy grid - integer :: index_sab = NONE ! Index in sab_tables - integer :: index_temp_sab ! Temperature index for sab_tables - real(8) :: sab_frac ! Fraction of atoms affected by S(a,b) - logical :: use_ptable ! In URR range with probability tables? + integer(C_INT) :: index_grid ! Index on nuclide energy grid + integer(C_INT) :: index_temp ! Temperature index for nuclide + real(C_DOUBLE) :: interp_factor ! Interpolation factor on nuc. energy grid + integer(C_INT) :: index_sab = NONE ! Index in sab_tables + integer(C_INT) :: index_temp_sab ! Temperature index for sab_tables + real(C_DOUBLE) :: sab_frac ! Fraction of atoms affected by S(a,b) + logical(C_BOOL) :: use_ptable ! In URR range with probability tables? ! Energy and temperature last used to evaluate these cross sections. If ! these values have changed, then the cross sections must be re-evaluated. - real(8) :: last_E = ZERO ! Last evaluated energy - real(8) :: last_sqrtkT = ZERO ! Last temperature in sqrt(Boltzmann + real(C_DOUBLE) :: last_E = ZERO ! Last evaluated energy + real(C_DOUBLE) :: last_sqrtkT = ZERO ! Last temperature in sqrt(Boltzmann ! constant * temperature (eV)) end type NuclideMicroXS @@ -164,7 +164,7 @@ module nuclide_header ! particle is traveling through !=============================================================================== - type MaterialMacroXS + type, bind(C) :: MaterialMacroXS real(C_DOUBLE) :: total ! macroscopic total xs real(C_DOUBLE) :: absorption ! macroscopic absorption xs real(C_DOUBLE) :: fission ! macroscopic fission xs diff --git a/src/settings.cpp b/src/settings.cpp index 8ca07a527..c705ef8a7 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -72,6 +72,32 @@ void read_settings(pugi::xml_node* root) } } } + + // Get temperature settings + if (check_for_node(*root, "temperature_default")) { + temperature_default = std::stod(get_node_value(*root, "temperature_default")); + } + if (check_for_node(*root, "temperature_method")) { + auto temp_str = get_node_value(*root, "temperature_method", true, true); + if (temp_str == "nearest") { + temperature_method = TEMPERATURE_NEAREST; + } else if (temp_str == "interpolation") { + temperature_method = TEMPERATURE_INTERPOLATION; + } else { + fatal_error("Unknown temperature method: " + temp_str); + } + } + if (check_for_node(*root, "temperature_tolerance")) { + temperature_tolerance = std::stod(get_node_value(*root, "temperature_tolerance")); + } + if (check_for_node(*root, "temperature_multipole")) { + temperature_multipole = get_node_value_bool(*root, "temperature_multipole"); + } + if (check_for_node(*root, "temperature_range")) { + auto range = get_node_array(*root, "temperature_range"); + temperature_range[0] = range[0]; + temperature_range[1] = range[1]; + } } } // namespace openmc diff --git a/src/thermal.cpp b/src/thermal.cpp index b4818d080..29f8c83a4 100644 --- a/src/thermal.cpp +++ b/src/thermal.cpp @@ -1,7 +1,7 @@ #include "thermal.h" -#include // for sort, move -#include // for round +#include // for sort, move, min, max +#include // for round, sqrt, fabs #include // for stringstream #include "xtensor/xarray.hpp" @@ -37,12 +37,13 @@ ThermalScattering::ThermalScattering(hid_t group, const std::vector& tem read_attribute(group, "nuclides", nuclides_); std::string sec_mode; read_attribute(group, "secondary_mode", sec_mode); + int secondary_mode; if (sec_mode == "equal") { - secondary_mode_ = SAB_SECONDARY_EQUAL; + secondary_mode = SAB_SECONDARY_EQUAL; } else if (sec_mode == "skewed") { - secondary_mode_ = SAB_SECONDARY_SKEWED; + secondary_mode = SAB_SECONDARY_SKEWED; } else if (sec_mode == "continuous") { - secondary_mode_ = SAB_SECONDARY_CONT; + secondary_mode = SAB_SECONDARY_CONT; } // Read temperatures @@ -138,7 +139,7 @@ ThermalScattering::ThermalScattering(hid_t group, const std::vector& tem // Open group for temperature i hid_t T_group = open_group(group, temp_str.data()); - data_.emplace_back(T_group, secondary_mode_); + data_.emplace_back(T_group, secondary_mode); close_group(group); } @@ -202,7 +203,7 @@ ThermalScattering::calculate_xs(double E, double sqrtkT, int* i_temp, auto& E_in = sab.elastic_e_in_; - if (sab.elastic_mode_ == SAB_ELASTIC_EXACT) { + if (sab.elastic_mode_ == SAB_ELASTIC_COHERENT) { if (E < E_in.front()) { // If energy is below that of the lowest Bragg peak, the elastic // cross section will be zero @@ -237,6 +238,7 @@ ThermalScattering::calculate_xs(double E, double sqrtkT, int* i_temp, //============================================================================== ThermalData::ThermalData(hid_t group, int secondary_mode) + : inelastic_mode_{secondary_mode} { // Coherent elastic data if (object_exists(group, "elastic")) { @@ -257,13 +259,13 @@ ThermalData::ThermalData(hid_t group, int secondary_mode) std::copy(P.begin(), P.end(), std::back_inserter(elastic_P_)); n_elastic_e_in_ = elastic_e_in_.size(); - // Determine elastic type + // Determine whether elastic scattering is incoherent or coherent std::string type; read_attribute(dset, "type", type); if (type == "tab1") { - elastic_mode_ = SAB_ELASTIC_DISCRETE; + elastic_mode_ = SAB_ELASTIC_INCOHERENT; } else if (type == "bragg") { - elastic_mode_ = SAB_ELASTIC_EXACT; + elastic_mode_ = SAB_ELASTIC_COHERENT; } close_dataset(dset); @@ -271,7 +273,7 @@ ThermalData::ThermalData(hid_t group, int secondary_mode) threshold_elastic_ = elastic_e_in_.back(); // Read angle distribution - if (elastic_mode_ != SAB_ELASTIC_EXACT) { + if (elastic_mode_ == SAB_ELASTIC_INCOHERENT) { xt::xarray mu_out; read_dataset(elastic_group, "mu_out", mu_out); elastic_mu_ = mu_out; @@ -350,4 +352,225 @@ ThermalData::ThermalData(hid_t group, int secondary_mode) } } +void +ThermalData::sample(const NuclideMicroXS* micro_xs, double E, + double* E_out, double* mu) +{ + // Determine whether inelastic or elastic scattering will occur + if (prn() < micro_xs->thermal_elastic / micro_xs->thermal) { + // elastic scattering + + // Get index and interpolation factor for elastic grid + int i = 0; + double f = 0.0; + if (E >= elastic_e_in_.front()) { + auto& E_in = elastic_e_in_; + i = lower_bound_index(E_in.begin(), E_in.end(), E); + f = (E - E_in[i]) / (E_in[i+1] - E_in[i]); + } + + // Select treatment based on elastic mode + if (elastic_mode_ == SAB_ELASTIC_INCOHERENT) { + // With this treatment, we interpolate between two discrete cosines + // corresponding to neighboring incoming energies. This is used for + // data derived in the incoherent approximation + + // Sample outgoing cosine bin + int k = prn() * n_elastic_mu_; + + // Determine outgoing cosine corresponding to E_in[i] and E_in[i+1] + double mu_ijk = elastic_mu_(i, k); + double mu_i1jk = elastic_mu_(i+1, k); + + // Cosine of angle between incoming and outgoing neutron + *mu = (1 - f)*mu_ijk + f*mu_i1jk; + + } else if (elastic_mode_ == SAB_ELASTIC_COHERENT) { + // This treatment is used for data derived in the coherent + // approximation, i.e. for crystalline structures that have Bragg + // edges. + + // Sample a Bragg edge between 1 and i + double prob = prn() * elastic_P_[i+1]; + int k; + if (prob < elastic_P_.front()) { + k = 1; + } else { + k = lower_bound_index(elastic_P_.begin(), elastic_P_.begin() + (i+1), prob); + } + + // Characteristic scattering cosine for this Bragg edge + *mu = 1.0 - 2.0*elastic_e_in_[k] / E; + + } + + // Outgoing energy is same as incoming energy -- no need to do anything + + } else { + // Perform inelastic calculations + + // Get index and interpolation factor for inelastic grid + int i = 0; + double f = 0.0; + if (E >= inelastic_e_in_.front()) { + auto& E_in = inelastic_e_in_; + i = lower_bound_index(E_in.begin(), E_in.end(), E); + f = (E - E_in[i]) / (E_in[i+1] - E_in[i]); + } + + // Now that we have an incoming energy bin, we need to determine the + // outgoing energy bin. This will depend on the "secondary energy + // mode". If the mode is 0, then the outgoing energy bin is chosen from a + // set of equally-likely bins. If the mode is 1, then the first + // two and last two bins are skewed to have lower probabilities than the + // other bins (0.1 for the first and last bins and 0.4 for the second and + // second to last bins, relative to a normal bin probability of 1). + // Finally, if the mode is 2, then a continuous distribution (with + // accompanying PDF and CDF is utilized) + + if (inelastic_mode_ == SAB_SECONDARY_EQUAL || + inelastic_mode_ == SAB_SECONDARY_SKEWED) { + int j; + if (inelastic_mode_ == SAB_SECONDARY_EQUAL) { + // All bins equally likely + j = prn() * n_inelastic_e_out_; + } else if (inelastic_mode_ == SAB_SECONDARY_SKEWED) { + // Distribution skewed away from edge points + double r = prn() * (n_inelastic_e_out_ - 3); + if (r > 1.0) { + // equally likely N-4 middle bins + j = r + 1; + } else if (r > 0.6) { + // second to last bin has relative probability of 0.4 + j = n_inelastic_e_out_ - 2; + } else if (r > 0.5) { + // last bin has relative probability of 0.1 + j = n_inelastic_e_out_ - 1; + } else if (r > 0.1) { + // second bin has relative probability of 0.4 + j = 1; + } else { + // first bin has relative probability of 0.1 + j = 0; + } + } + + // Determine outgoing energy corresponding to E_in[i] and E_in[i+1] + double E_ij = inelastic_e_out_(i, j); + double E_i1j = inelastic_e_out_(i+1, j); + + // Outgoing energy + *E_out = (1 - f)*E_ij + f*E_i1j; + + // Sample outgoing cosine bin + int k = prn() * n_inelastic_mu_; + + // Determine outgoing cosine corresponding to E_in[i] and E_in[i+1] + double mu_ijk = inelastic_mu_(i, j, k); + double mu_i1jk = inelastic_mu_(i+1, j, k); + + // Cosine of angle between incoming and outgoing neutron + *mu = (1 - f)*mu_ijk + f*mu_i1jk; + + } else if (inelastic_mode_ == SAB_SECONDARY_CONT) { + // Continuous secondary energy - this is to be similar to + // Law 61 interpolation on outgoing energy + + // Sample between ith and [i+1]th bin + int l = f > prn() ? i + 1 : i; + + // Determine endpoints on grid i + auto n = inelastic_data_[i].e_out.size(); + double E_i_1 = inelastic_data_[i].e_out(0); + double E_i_J = inelastic_data_[i].e_out(n); + + // Determine endpoints on grid i + 1 + n = inelastic_data_[i].e_out.size(); + double E_i1_1 = inelastic_data_[i + 1].e_out(0); + double E_i1_J = inelastic_data_[i + 1].e_out(n); + + double E_1 = E_i_1 + f * (E_i1_1 - E_i_1); + double E_J = E_i_J + f * (E_i1_J - E_i_J); + + // Determine outgoing energy bin + // (First reset n_energy_out to the right value) + n = inelastic_data_[l].n_e_out; + double r1 = prn(); + double c_j = inelastic_data_[l].e_out_cdf[0]; + double c_j1; + std::size_t j; + for (j = 0; j < n - 2; ++j) { + c_j1 = inelastic_data_[l].e_out_cdf[j + 1]; + if (r1 < c_j1) break; + c_j = c_j1; + } + + // check to make sure j is <= n_energy_out - 2 + j = std::min(j, n - 2); + + // Get the data to interpolate between + double E_l_j = inelastic_data_[l].e_out[j]; + double p_l_j = inelastic_data_[l].e_out_pdf[j]; + + // Next part assumes linear-linear interpolation in standard + double E_l_j1 = inelastic_data_[l].e_out[j + 1]; + double p_l_j1 = inelastic_data_[l].e_out_pdf[j + 1]; + + // Find secondary energy (variable E) + double frac = (p_l_j1 - p_l_j) / (E_l_j1 - E_l_j); + if (frac == 0.0) { + *E_out = E_l_j + (r1 - c_j) / p_l_j; + } else { + *E_out = E_l_j + (std::sqrt(std::max(0.0, p_l_j*p_l_j + + 2.0*frac*(r1 - c_j))) - p_l_j) / frac; + } + + // Now interpolate between incident energy bins i and i + 1 + if (l == i) { + *E_out = E_1 + (E - E_i_1) * (E_J - E_1) / (E_i_J - E_i_1); + } else { + *E_out = E_1 + (E - E_i1_1) * (E_J - E_1) / (E_i1_J - E_i1_1); + } + + // Sample outgoing cosine bin + std::size_t k = prn() * n_inelastic_mu_; + + // Rather than use the sampled discrete mu directly, it is smeared over + // a bin of width min(mu[k] - mu[k-1], mu[k+1] - mu[k]) centered on the + // discrete mu value itself. + const auto& mu_l = inelastic_data_[l].mu; + f = (r1 - c_j)/(c_j1 - c_j); + + // Determine (k-1)th mu value + double mu_left; + if (k == 0) { + mu_left = -1.0; + } else { + mu_left = mu_l(j, k-1) + f*(mu_l(j+1, k-1) - mu_l(j, k-1)); + } + + // Determine kth mu value + *mu = mu_l(j, k) + f*(mu_l(j+1, k) - mu_l(j, k)); + + // Determine (k+1)th mu value + double mu_right; + if (k == n_inelastic_mu_ - 1) { + mu_right = 1.0 - *mu; + } else { + mu_right = mu_l(j, k+1) + f*(mu_l(j+1, k+1) - mu_l(j, k+1)) - *mu; + } + + // Smear angle + *mu += std::min(*mu - mu_left, mu_right - *mu)*(prn() - 0.5); + + } // (inelastic secondary energy treatment) + } // (elastic or inelastic) + + // Because of floating-point roundoff, it may be possible for mu to be + // outside of the range [-1,1). In these cases, we just set mu to exactly + // -1 or 1 + if (std::fabs(*mu) > 1.0) *mu = std::copysign(1.0, *mu); + +} + } // namespace openmc diff --git a/src/thermal.h b/src/thermal.h index 59f5c97ee..922a897b5 100644 --- a/src/thermal.h +++ b/src/thermal.h @@ -8,12 +8,28 @@ #include "xtensor/xtensor.hpp" #include "hdf5_interface.h" +#include "nuclide.h" namespace openmc { +// Secondary energy mode for S(a,b) inelastic scattering +// TODO: Convert to enum +constexpr int SAB_SECONDARY_EQUAL {0}; // Equally-likely outgoing energy bins +constexpr int SAB_SECONDARY_SKEWED {1}; // Skewed outgoing energy bins +constexpr int SAB_SECONDARY_CONT {2}; // Continuous, linear-linear interpolation + +// Elastic mode for S(a,b) elastic scattering +// TODO: Convert to enum +constexpr int SAB_ELASTIC_INCOHERENT {3}; // Incoherent elastic scattering +constexpr int SAB_ELASTIC_COHERENT {4}; // Coherent elastic scattering (Bragg edges) + class ThermalData { public: ThermalData(hid_t group, int secondary_mode); + + // Sample an outgoing energy and angle + void sample(const NuclideMicroXS* micro_xs, double E_in, + double* E_out, double* mu); private: struct DistEnergySab { std::size_t n_e_out; @@ -28,6 +44,7 @@ private: double threshold_elastic_ {0.0}; // Inelastic scattering data + int inelastic_mode_; // secondary mode (equal/skewed/continuous) std::size_t n_inelastic_e_in_; // # of incoming E for inelastic std::size_t n_inelastic_e_out_; // # of outgoing E for inelastic std::size_t n_inelastic_mu_; // # of outgoing angles for inelastic @@ -67,7 +84,6 @@ public: double awr_; // weight of nucleus in neutron masses std::vector kTs_; // temperatures in eV (k*T) std::vector nuclides_; // List of valid nuclides - int secondary_mode_; // secondary mode (equal/skewed/continuous) // cross sections and distributions at each temperature std::vector data_; diff --git a/src/xml_interface.cpp b/src/xml_interface.cpp index c89e19ef1..5835c8600 100644 --- a/src/xml_interface.cpp +++ b/src/xml_interface.cpp @@ -40,4 +40,19 @@ get_node_value(pugi::xml_node node, const char* name, bool lowercase, return value; } +bool +get_node_value_bool(pugi::xml_node node, const char* name) +{ + if (node.attribute(name)) { + return node.attribute(name).as_bool(); + } else if (node.child(name)) { + return node.child(name).text().as_bool(); + } else { + std::stringstream err_msg; + err_msg << "Node \"" << name << "\" is not a member of the \"" + << node.name() << "\" XML node"; + fatal_error(err_msg); + } +} + } // namespace openmc diff --git a/src/xml_interface.h b/src/xml_interface.h index f10143697..1530333c4 100644 --- a/src/xml_interface.h +++ b/src/xml_interface.h @@ -16,9 +16,11 @@ check_for_node(pugi::xml_node node, const char *name) return node.attribute(name) || node.child(name); } -std::string get_node_value(pugi::xml_node node, const char *name, +std::string get_node_value(pugi::xml_node node, const char* name, bool lowercase=false, bool strip=false); +bool get_node_value_bool(pugi::xml_node node, const char* name); + template std::vector get_node_array(pugi::xml_node node, const char* name) { From 7aa6db0c7e2c9ed0f7b6816311cfe44dcee24eaa Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 15 Aug 2018 10:54:02 -0500 Subject: [PATCH 15/56] Add ThermalScattering::has_nuclide method --- src/thermal.cpp | 22 +++++++++++++--------- src/thermal.h | 3 ++- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/thermal.cpp b/src/thermal.cpp index 29f8c83a4..176980592 100644 --- a/src/thermal.cpp +++ b/src/thermal.cpp @@ -1,6 +1,6 @@ #include "thermal.h" -#include // for sort, move, min, max +#include // for sort, move, min, max, find #include // for round, sqrt, fabs #include // for stringstream @@ -148,7 +148,7 @@ ThermalScattering::ThermalScattering(hid_t group, const std::vector& tem void ThermalScattering::calculate_xs(double E, double sqrtkT, int* i_temp, - double* elastic, double* inelastic) + double* elastic, double* inelastic) const { // Determine temperature for S(a,b) table double kT = sqrtkT*sqrtkT; @@ -180,12 +180,9 @@ ThermalScattering::calculate_xs(double E, double sqrtkT, int* i_temp, auto& sab = data_[i]; // Get index and interpolation factor for inelastic grid - int i_grid; - double f; - if (E < sab.inelastic_e_in_.front()) { - i_grid = 0; - f = 0.0; - } else { + int i_grid = 0; + double f = 0.0; + if (E >= sab.inelastic_e_in_.front()) { auto& E_in = sab.inelastic_e_in_; i_grid = lower_bound_index(E_in.begin(), E_in.end(), E); f = (E - E_in[i_grid]) / (E_in[i_grid+1] - E_in[i_grid]); @@ -221,7 +218,7 @@ ThermalScattering::calculate_xs(double E, double sqrtkT, int* i_temp, } // Get interpolation factor for elastic grid - f = (E - E_in[i_grid])/(E_in[i_grid+1] - E_in[i_grid]); + f = (E - E_in[i_grid]) / (E_in[i_grid+1] - E_in[i_grid]); // Calculate S(a,b) elastic scattering cross section auto& xs = sab.elastic_P_; @@ -233,6 +230,13 @@ ThermalScattering::calculate_xs(double E, double sqrtkT, int* i_temp, } } +bool +ThermalScattering::has_nuclide(const char* name) const +{ + std::string nuc {name}; + return std::find(nuclides_.begin(), nuclides_.end(), nuc) != nuclides_.end(); +} + //============================================================================== // ThermalData implementation //============================================================================== diff --git a/src/thermal.h b/src/thermal.h index 922a897b5..341f1799e 100644 --- a/src/thermal.h +++ b/src/thermal.h @@ -78,7 +78,8 @@ public: double tolerance, const double* minmax); void calculate_xs(double E, double sqrtkT, int* i_temp, double* elastic, - double* inelastic); + double* inelastic) const ; + bool has_nuclide(const char* name) const; std::string name_; // name of table, e.g. "c_H_in_H2O" double awr_; // weight of nucleus in neutron masses From c4680b43b7401647a9f363d107a06824aada0ea2 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 15 Aug 2018 11:29:48 -0500 Subject: [PATCH 16/56] Add comments to thermal.h --- src/thermal.h | 90 ++++++++++++++++++++++++++++++++++----------------- 1 file changed, 60 insertions(+), 30 deletions(-) diff --git a/src/thermal.h b/src/thermal.h index 341f1799e..d33465bf8 100644 --- a/src/thermal.h +++ b/src/thermal.h @@ -12,6 +12,10 @@ namespace openmc { +//============================================================================== +// Constants +//============================================================================== + // Secondary energy mode for S(a,b) inelastic scattering // TODO: Convert to enum constexpr int SAB_SECONDARY_EQUAL {0}; // Equally-likely outgoing energy bins @@ -23,6 +27,11 @@ constexpr int SAB_SECONDARY_CONT {2}; // Continuous, linear-linear interpolati constexpr int SAB_ELASTIC_INCOHERENT {3}; // Incoherent elastic scattering constexpr int SAB_ELASTIC_COHERENT {4}; // Coherent elastic scattering (Bragg edges) +//============================================================================== +//! Secondary angle-energy data for thermal neutron scattering at a single +//! temperature +//============================================================================== + class ThermalData { public: ThermalData(hid_t group, int secondary_mode); @@ -31,62 +40,83 @@ public: void sample(const NuclideMicroXS* micro_xs, double E_in, double* E_out, double* mu); private: + //! Secondary energy/angle distributions for inelastic thermal scattering + //! collisions which utilize a continuous secondary energy representation. struct DistEnergySab { - std::size_t n_e_out; - xt::xtensor e_out; - xt::xtensor e_out_pdf; - xt::xtensor e_out_cdf; - xt::xtensor mu; + std::size_t n_e_out; //!< Number of outgoing energies + xt::xtensor e_out; //!< Outgoing energies + xt::xtensor e_out_pdf; //!< Probability density function + xt::xtensor e_out_cdf; //!< Cumulative distribution function + xt::xtensor mu; //!< Equiprobable angles at each outgoing energy }; - // Threshold for thermal scattering treatment (usually ~4 eV) + //! 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 - int inelastic_mode_; // secondary mode (equal/skewed/continuous) - std::size_t n_inelastic_e_in_; // # of incoming E for inelastic - std::size_t n_inelastic_e_out_; // # of outgoing E for inelastic - std::size_t n_inelastic_mu_; // # of outgoing angles for inelastic - std::vector inelastic_e_in_; - std::vector inelastic_sigma_; + int inelastic_mode_; //!< distribution type (equal/skewed/continuous) + std::size_t n_inelastic_e_in_; //!< number of incoming E for inelastic + std::size_t n_inelastic_e_out_; //!< number of outgoing E for inelastic + std::size_t n_inelastic_mu_; //!< number of outgoing angles for inelastic + std::vector inelastic_e_in_; //!< incoming E grid for inelastic + std::vector inelastic_sigma_; //!< inelastic scattering cross section - // The following are used only if secondary_mode is 0 or 1 + // The following are used only for equal/skewed distributions xt::xtensor inelastic_e_out_; xt::xtensor inelastic_mu_; - // The following is used only if secondary_mode is 3 - // The different implementation is necessary because the continuous - // representation has a variable number of outgoing energy points for each - // incoming energy - std::vector inelastic_data_; // One for each Ein + // The following is used only for continuous S(a,b) distributions. The + // different implementation is necessary because the continuous representation + // has a variable number of outgoing energy points for each incoming energy + std::vector inelastic_data_; //!< Secondary angle-energy at + //!< each incoming energy // Elastic scattering data - int elastic_mode_; // elastic mode (discrete/exact) - std::size_t n_elastic_e_in_; // # of incoming E for elastic - std::size_t n_elastic_mu_; // # of outgoing angles for elastic - std::vector elastic_e_in_; - std::vector elastic_P_; - xt::xtensor elastic_mu_; + int elastic_mode_; //!< type of elastic (incoherent/coherent) + std::size_t n_elastic_e_in_; //!< number of incoming E for elastic + std::size_t n_elastic_mu_; //!< number of outgoing angles for elastic + std::vector elastic_e_in_; //!< incoming E grid for elastic + std::vector elastic_P_; //!< elastic scattering cross section + xt::xtensor elastic_mu_; //!< equi-probable angles at each incoming E + // ThermalScattering needs access to private data members friend class ThermalScattering; }; +//============================================================================== +//! Data for thermal neutron scattering, typically off light isotopes in +//! moderating materials such as water, graphite, BeO, etc. +//============================================================================== + class ThermalScattering { public: ThermalScattering(hid_t group, const std::vector& temperature, int method, double tolerance, const double* minmax); + //! Determine inelastic/elastic cross section at given energy + //! + //! \param[in] E incoming energy in [eV] + //! \param[in] sqrtkT square-root of temperature multipled by Boltzmann's constant + //! \param[out] i_temp corresponding temperature index + //! \param[out] elastic Thermal elastic scattering cross section + //! \param[out] inelastic Thermal inelastic scattering cross section void calculate_xs(double E, double sqrtkT, int* i_temp, double* elastic, - double* inelastic) const ; + double* inelastic) const; + + //! Determine whether table applies to a particular nuclide + //! + //! \param[in] name Name of the nuclide, e.g., "H1" + //! \return Whether table applies to the nuclide bool has_nuclide(const char* name) const; - std::string name_; // name of table, e.g. "c_H_in_H2O" - double awr_; // weight of nucleus in neutron masses - std::vector kTs_; // temperatures in eV (k*T) - std::vector nuclides_; // List of valid nuclides + std::string name_; //!< name of table, e.g. "c_H_in_H2O" + double awr_; //!< weight of nucleus in neutron masses + std::vector kTs_; //!< temperatures in [eV] (k*T) + std::vector nuclides_; //!< Valid nuclides - // cross sections and distributions at each temperature + //! cross sections and distributions at each temperature std::vector data_; }; From b7f1f7cf4b2256857b9e3e643c2deaa99bc8dfd7 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 15 Aug 2018 12:59:20 -0500 Subject: [PATCH 17/56] Add/use Fortran bindings to ThermalScattering C++ class --- src/material_header.F90 | 4 +- src/nuclide_header.F90 | 8 +- src/physics.F90 | 261 +------------------- src/sab_header.F90 | 530 +++++++++------------------------------- src/thermal.cpp | 37 +++ src/thermal.h | 22 ++ 6 files changed, 188 insertions(+), 674 deletions(-) diff --git a/src/material_header.F90 b/src/material_header.F90 index 03ecf69d9..9a1502493 100644 --- a/src/material_header.F90 +++ b/src/material_header.F90 @@ -172,7 +172,7 @@ contains found = .false. associate (sab => sab_tables(this % i_sab_tables(k))) FIND_NUCLIDE: do j = 1, size(this % nuclide) - if (any(sab % nuclides == nuclides(this % nuclide(j)) % name)) then + if (sab % has_nuclide(nuclides(this % nuclide(j)) % name)) then call i_sab_tables % push_back(this % i_sab_tables(k)) call i_sab_nuclides % push_back(j) call sab_fracs % push_back(this % sab_fracs(k)) @@ -326,7 +326,7 @@ contains ! If particle energy is greater than the highest energy for the ! S(a,b) table, then don't use the S(a,b) table - if (p % E > sab_tables(i_sab) % data(1) % threshold_inelastic) then + if (p % E > sab_tables(i_sab) % threshold()) then i_sab = 0 end if diff --git a/src/nuclide_header.F90 b/src/nuclide_header.F90 index 6faaaec7f..0411ab102 100644 --- a/src/nuclide_header.F90 +++ b/src/nuclide_header.F90 @@ -198,7 +198,7 @@ module nuclide_header type(DictCharInt) :: nuclide_dict ! Cross section caches - type(NuclideMicroXS), allocatable :: micro_xs(:) ! Cache for each nuclide + type(NuclideMicroXS), allocatable, target :: micro_xs(:) ! Cache for each nuclide type(MaterialMacroXS) :: material_xs ! Cache for current material !$omp threadprivate(micro_xs, material_xs) @@ -1096,9 +1096,9 @@ contains real(8), intent(in) :: sab_frac ! fraction of atoms affected by S(a,b) type(NuclideMicroXS), intent(inout) :: micro_xs ! Cross section cache - integer :: i_temp ! temperature index - real(8) :: inelastic ! S(a,b) inelastic cross section - real(8) :: elastic ! S(a,b) elastic cross section + integer(C_INT) :: i_temp ! temperature index + real(C_DOUBLE) :: inelastic ! S(a,b) inelastic cross section + real(C_DOUBLE) :: elastic ! S(a,b) elastic cross section ! Set flag that S(a,b) treatment should be used for scattering micro_xs % index_sab = i_sab diff --git a/src/physics.F90 b/src/physics.F90 index d5f6302a8..70c922b42 100644 --- a/src/physics.F90 +++ b/src/physics.F90 @@ -884,263 +884,16 @@ contains real(8), intent(inout) :: uvw(3) ! directional cosines real(8), intent(out) :: mu ! scattering cosine - integer :: i ! incoming energy bin - integer :: j ! outgoing energy bin - integer :: k ! outgoing cosine bin - integer :: i_temp ! temperature index - integer :: n_energy_out ! number of outgoing energy bins - real(8) :: f ! interpolation factor - real(8) :: r ! used for skewed sampling & continuous - real(8) :: E_ij ! outgoing energy j for E_in(i) - real(8) :: E_i1j ! outgoing energy j for E_in(i+1) - real(8) :: mu_ijk ! outgoing cosine k for E_in(i) and E_out(j) - real(8) :: mu_i1jk ! outgoing cosine k for E_in(i+1) and E_out(j) - real(8) :: prob ! probability for sampling Bragg edge - ! Following are needed only for SAB_SECONDARY_CONT scattering - integer :: l ! sampled incoming E bin (is i or i + 1) - real(8) :: E_i_1, E_i_J ! endpoints on outgoing grid i - real(8) :: E_i1_1, E_i1_J ! endpoints on outgoing grid i+1 - real(8) :: E_1, E_J ! endpoints interpolated between i and i+1 - real(8) :: E_l_j, E_l_j1 ! adjacent E on outgoing grid l - real(8) :: p_l_j, p_l_j1 ! adjacent p on outgoing grid l - real(8) :: c_j, c_j1 ! cumulative probability - real(8) :: frac ! interpolation factor on outgoing energy - real(8) :: r1 ! RNG for outgoing energy - real(8) :: mu_left, mu_right ! adjacent mu values + real(C_DOUBLE) :: E_out + type(C_PTR) :: ptr - i_temp = micro_xs(i_nuclide) % index_temp_sab + ! Sample from C++ side + ptr = C_LOC(micro_xs(i_nuclide)) + call sab_tables(i_sab) % sample(ptr, E, E_out, mu) - ! Get pointer to S(a,b) table - associate (sab => sab_tables(i_sab) % data(i_temp)) - - ! Determine whether inelastic or elastic scattering will occur - if (prn() < micro_xs(i_nuclide) % thermal_elastic / & - micro_xs(i_nuclide) % thermal) then - ! elastic scattering - - ! Get index and interpolation factor for elastic grid - if (E < sab % elastic_e_in(1)) then - i = 1 - f = ZERO - else - i = binary_search(sab % elastic_e_in, sab % n_elastic_e_in, E) - f = (E - sab%elastic_e_in(i)) / & - (sab%elastic_e_in(i+1) - sab%elastic_e_in(i)) - end if - - ! Select treatment based on elastic mode - if (sab % elastic_mode == SAB_ELASTIC_DISCRETE) then - ! With this treatment, we interpolate between two discrete cosines - ! corresponding to neighboring incoming energies. This is used for - ! data derived in the incoherent approximation - - ! Sample outgoing cosine bin - k = 1 + int(prn() * sab % n_elastic_mu) - - ! Determine outgoing cosine corresponding to E_in(i) and E_in(i+1) - mu_ijk = sab % elastic_mu(k,i) - mu_i1jk = sab % elastic_mu(k,i+1) - - ! Cosine of angle between incoming and outgoing neutron - mu = (1 - f)*mu_ijk + f*mu_i1jk - - elseif (sab % elastic_mode == SAB_ELASTIC_EXACT) then - ! This treatment is used for data derived in the coherent - ! approximation, i.e. for crystalline structures that have Bragg - ! edges. - - ! Sample a Bragg edge between 1 and i - prob = prn() * sab % elastic_P(i+1) - if (prob < sab % elastic_P(1)) then - k = 1 - else - k = binary_search(sab % elastic_P(1:i+1), i+1, prob) - end if - - ! Characteristic scattering cosine for this Bragg edge - mu = ONE - TWO*sab % elastic_e_in(k) / E - - end if - - ! Outgoing energy is same as incoming energy -- no need to do anything - - else - ! Perform inelastic calculations - - ! Get index and interpolation factor for inelastic grid - if (E < sab % inelastic_e_in(1)) then - i = 1 - f = ZERO - else - i = binary_search(sab % inelastic_e_in, sab % n_inelastic_e_in, E) - f = (E - sab%inelastic_e_in(i)) / & - (sab%inelastic_e_in(i+1) - sab%inelastic_e_in(i)) - end if - - ! Now that we have an incoming energy bin, we need to determine the - ! outgoing energy bin. This will depend on the "secondary energy - ! mode". If the mode is 0, then the outgoing energy bin is chosen from a - ! set of equally-likely bins. If the mode is 1, then the first - ! two and last two bins are skewed to have lower probabilities than the - ! other bins (0.1 for the first and last bins and 0.4 for the second and - ! second to last bins, relative to a normal bin probability of 1). - ! Finally, if the mode is 2, then a continuous distribution (with - ! accompanying PDF and CDF is utilized) - - if ((sab_tables(i_sab) % secondary_mode == SAB_SECONDARY_EQUAL) .or. & - (sab_tables(i_sab) % secondary_mode == SAB_SECONDARY_SKEWED)) then - if (sab_tables(i_sab) % secondary_mode == SAB_SECONDARY_EQUAL) then - ! All bins equally likely - - j = 1 + int(prn() * sab % n_inelastic_e_out) - elseif (sab_tables(i_sab) % secondary_mode == SAB_SECONDARY_SKEWED) then - ! Distribution skewed away from edge points - - ! Determine number of outgoing energy and angle bins - n_energy_out = sab % n_inelastic_e_out - - r = prn() * (n_energy_out - 3) - if (r > ONE) then - ! equally likely N-4 middle bins - j = int(r) + 2 - elseif (r > 0.6_8) then - ! second to last bin has relative probability of 0.4 - j = n_energy_out - 1 - elseif (r > HALF) then - ! last bin has relative probability of 0.1 - j = n_energy_out - elseif (r > 0.1_8) then - ! second bin has relative probability of 0.4 - j = 2 - else - ! first bin has relative probability of 0.1 - j = 1 - end if - end if - - ! Determine outgoing energy corresponding to E_in(i) and E_in(i+1) - E_ij = sab % inelastic_e_out(j,i) - E_i1j = sab % inelastic_e_out(j,i+1) - - ! Outgoing energy - E = (1 - f)*E_ij + f*E_i1j - - ! Sample outgoing cosine bin - k = 1 + int(prn() * sab % n_inelastic_mu) - - ! Determine outgoing cosine corresponding to E_in(i) and E_in(i+1) - mu_ijk = sab % inelastic_mu(k,j,i) - mu_i1jk = sab % inelastic_mu(k,j,i+1) - - ! Cosine of angle between incoming and outgoing neutron - mu = (1 - f)*mu_ijk + f*mu_i1jk - - else if (sab_tables(i_sab) % secondary_mode == SAB_SECONDARY_CONT) then - ! Continuous secondary energy - this is to be similar to - ! Law 61 interpolation on outgoing energy - - ! Sample between ith and (i+1)th bin - r = prn() - if (f > r) then - l = i + 1 - else - l = i - end if - - ! Determine endpoints on grid i - n_energy_out = sab % inelastic_data(i) % n_e_out - E_i_1 = sab % inelastic_data(i) % e_out(1) - E_i_J = sab % inelastic_data(i) % e_out(n_energy_out) - - ! Determine endpoints on grid i + 1 - n_energy_out = sab % inelastic_data(i + 1) % n_e_out - E_i1_1 = sab % inelastic_data(i + 1) % e_out(1) - E_i1_J = sab % inelastic_data(i + 1) % e_out(n_energy_out) - - E_1 = E_i_1 + f * (E_i1_1 - E_i_1) - E_J = E_i_J + f * (E_i1_J - E_i_J) - - ! Determine outgoing energy bin - ! (First reset n_energy_out to the right value) - n_energy_out = sab % inelastic_data(l) % n_e_out - r1 = prn() - c_j = sab % inelastic_data(l) % e_out_cdf(1) - do j = 1, n_energy_out - 1 - c_j1 = sab % inelastic_data(l) % e_out_cdf(j + 1) - if (r1 < c_j1) exit - c_j = c_j1 - end do - - ! check to make sure k is <= n_energy_out - 1 - j = min(j, n_energy_out - 1) - - ! Get the data to interpolate between - E_l_j = sab % inelastic_data(l) % e_out(j) - p_l_j = sab % inelastic_data(l) % e_out_pdf(j) - - ! Next part assumes linear-linear interpolation in standard - E_l_j1 = sab % inelastic_data(l) % e_out(j + 1) - p_l_j1 = sab % inelastic_data(l) % e_out_pdf(j + 1) - - ! Find secondary energy (variable E) - frac = (p_l_j1 - p_l_j) / (E_l_j1 - E_l_j) - if (frac == ZERO) then - E = E_l_j + (r1 - c_j) / p_l_j - else - E = E_l_j + (sqrt(max(ZERO, p_l_j * p_l_j + & - TWO * frac * (r1 - c_j))) - p_l_j) / frac - end if - - ! Now interpolate between incident energy bins i and i + 1 - if (l == i) then - E = E_1 + (E - E_i_1) * (E_J - E_1) / (E_i_J - E_i_1) - else - E = E_1 + (E - E_i1_1) * (E_J - E_1) / (E_i1_J - E_i1_1) - end if - - ! Sample outgoing cosine bin - k = 1 + int(prn() * sab % n_inelastic_mu) - - ! Rather than use the sampled discrete mu directly, it is smeared over - ! a bin of width min(mu[k] - mu[k-1], mu[k+1] - mu[k]) centered on the - ! discrete mu value itself. - associate (mu_l => sab % inelastic_data(l) % mu) - f = (r1 - c_j)/(c_j1 - c_j) - - ! Determine (k-1)th mu value - if (k == 1) then - mu_left = -ONE - else - mu_left = mu_l(k-1, j) + f*(mu_l(k-1, j+1) - mu_l(k-1,j)) - end if - - ! Determine kth mu value - mu = mu_l(k, j) + f*(mu_l(k, j+1) - mu_l(k, j)) - - ! Determine (k+1)th mu value - if (k == sab % n_inelastic_mu) then - mu_right = ONE - mu - else - mu_right = mu_l(k+1, j) + f*(mu_l(k+1, j+1) - mu_l(k+1,j)) - mu - end if - end associate - - ! Smear angle - mu = mu + min(mu - mu_left, mu_right - mu)*(prn() - HALF) - - end if ! (inelastic secondary energy treatment) - end if ! (elastic or inelastic) - end associate - - ! Because of floating-point roundoff, it may be possible for mu to be - ! outside of the range [-1,1). In these cases, we just set mu to exactly - ! -1 or 1 - - if (abs(mu) > ONE) mu = sign(ONE,mu) - - ! change direction of particle + ! Set energy to outgoing, change direction of particle + E = E_out uvw = rotate_angle(uvw, mu) - end subroutine sab_scatter !=============================================================================== diff --git a/src/sab_header.F90 b/src/sab_header.F90 index 615e7b281..ece262bd6 100644 --- a/src/sab_header.F90 +++ b/src/sab_header.F90 @@ -1,467 +1,169 @@ module sab_header use, intrinsic :: ISO_C_BINDING - use, intrinsic :: ISO_FORTRAN_ENV - use algorithm, only: find, sort, binary_search - use constants - use dict_header, only: DictIntInt, DictCharInt - use distribution_univariate, only: Tabular - use error, only: warning, fatal_error + use dict_header, only: DictCharInt use hdf5_interface - use random_lcg, only: prn - use secondary_correlated, only: CorrelatedAngleEnergy - use settings - use stl_vector, only: VectorInt, VectorReal - use string, only: to_str, str_to_int + use stl_vector, only: VectorReal + use string, only: to_c_string implicit none + private -!=============================================================================== -! DISTENERGYSAB contains the secondary energy/angle distributions for inelastic -! thermal scattering collisions which utilize a continuous secondary energy -! representation. -!=============================================================================== - - type DistEnergySab - integer :: n_e_out - real(8), allocatable :: e_out(:) - real(8), allocatable :: e_out_pdf(:) - real(8), allocatable :: e_out_cdf(:) - real(8), allocatable :: mu(:,:) - end type DistEnergySab + public :: free_memory_sab !=============================================================================== ! SALPHABETA contains S(a,b) data for thermal neutron scattering, typically off ! of light isotopes such as water, graphite, Be, etc !=============================================================================== - type SabData - ! threshold for S(a,b) treatment (usually ~4 eV) - real(8) :: threshold_inelastic - real(8) :: threshold_elastic = ZERO - - ! Inelastic scattering data - integer :: n_inelastic_e_in ! # of incoming E for inelastic - integer :: n_inelastic_e_out ! # of outgoing E for inelastic - integer :: n_inelastic_mu ! # of outgoing angles for inelastic - real(8), allocatable :: inelastic_e_in(:) - real(8), allocatable :: inelastic_sigma(:) - ! The following are used only if secondary_mode is 0 or 1 - real(8), allocatable :: inelastic_e_out(:,:) - real(8), allocatable :: inelastic_mu(:,:,:) - ! The following is used only if secondary_mode is 3 - ! The different implementation is necessary because the continuous - ! representation has a variable number of outgoing energy points for each - ! incoming energy - type(DistEnergySab), allocatable :: inelastic_data(:) ! One for each Ein - - ! Elastic scattering data - integer :: elastic_mode ! elastic mode (discrete/exact) - integer :: n_elastic_e_in ! # of incoming E for elastic - integer :: n_elastic_mu ! # of outgoing angles for elastic - real(8), allocatable :: elastic_e_in(:) - real(8), allocatable :: elastic_P(:) - real(8), allocatable :: elastic_mu(:,:) - end type SabData - - type SAlphaBeta - character(150) :: name ! name of table, e.g. lwtr.10t - real(8) :: awr ! weight of nucleus in neutron masses - real(8), allocatable :: kTs(:) ! temperatures in eV (k*T) - character(10), allocatable :: nuclides(:) ! List of valid nuclides - integer :: secondary_mode ! secondary mode (equal/skewed/continuous) - - ! cross sections and distributions at each temperature - type(SabData), allocatable :: data(:) + type, public :: SAlphaBeta + type(C_PTR) :: ptr contains - procedure :: from_hdf5 => salphabeta_from_hdf5 - procedure :: calculate_xs => sab_calculate_xs + procedure :: from_hdf5 + procedure :: calculate_xs + procedure :: free + procedure :: has_nuclide + procedure :: sample + procedure :: threshold end type SAlphaBeta ! S(a,b) tables - type(SAlphaBeta), allocatable, target :: sab_tables(:) - integer(C_INT), bind(C) :: n_sab_tables - type(DictCharInt) :: sab_dict + type(SAlphaBeta), public, allocatable, target :: sab_tables(:) + integer(C_INT), public, bind(C) :: n_sab_tables + type(DictCharInt), public :: sab_dict + + interface + function sab_from_hdf5(group_id, temperature, n, method, & + tolerance, minmax) result(ptr) bind(C) + import HID_T, C_DOUBLE, C_INT, C_PTR + integer(HID_T), value :: group_id + real(C_DOUBLE), intent(in) :: temperature + integer(C_INT), value :: n + integer(C_INT), value :: method + real(C_DOUBLE), value :: tolerance + real(C_DOUBLE), intent(in) :: minmax(2) + type(C_PTR) :: ptr + end function + + subroutine sab_calculate_xs(ptr, E, sqrtkT, i_temp, elastic, & + inelastic) bind(C) + import C_PTR, C_DOUBLE, C_INT + type(C_PTR), value :: ptr + real(C_DOUBLE), value :: E + real(C_DOUBLE), value :: sqrtkT + integer(C_INT), intent(out) :: i_temp + real(C_DOUBLE), intent(out) :: elastic + real(C_DOUBLE), intent(out) :: inelastic + end subroutine + + subroutine sab_free(ptr) bind(C) + import C_PTR + type(C_PTR), value :: ptr + end subroutine + + function sab_has_nuclide(ptr, name) result(val) bind(C) + import C_PTR, C_CHAR, C_BOOL + type(C_PTR), value :: ptr + character(kind=C_CHAR), intent(in) :: name(*) + logical(C_BOOL) :: val + end function + + subroutine sab_sample(ptr, micro_xs, E_in, E_out, mu) bind(C) + import C_PTR, C_INT, C_DOUBLE + type(C_PTR), value :: ptr + type(C_PTR), value :: micro_xs + real(C_DOUBLE), value :: E_in + real(C_DOUBLE), intent(out) :: E_out + real(C_DOUBLE), intent(out) :: mu + end subroutine + + function sab_threshold(ptr) result(threshold) bind(C) + import C_PTR, C_double + type(C_PTR), value :: ptr + real(C_DOUBLE) :: threshold + end function + end interface contains - subroutine salphabeta_from_hdf5(this, group_id, temperature, method, & + subroutine from_hdf5(this, group_id, temperature, method, & tolerance, minmax) class(SAlphaBeta), intent(inout) :: this integer(HID_T), intent(in) :: group_id type(VectorReal), intent(in) :: temperature ! list of temperatures - integer, intent(in) :: method - real(8), intent(in) :: tolerance - real(8), intent(in) :: minmax(2) + integer(C_INT), intent(in) :: method + real(C_DOUBLE), intent(in) :: tolerance + real(C_DOUBLE), intent(in) :: minmax(2) - integer :: i, j - integer :: t - integer :: n_energy, n_energy_out, n_mu - integer :: i_closest - integer :: n_temperature - integer(HID_T) :: T_group - integer(HID_T) :: elastic_group - integer(HID_T) :: inelastic_group - integer(HID_T) :: dset_id - integer(HID_T) :: kT_group - integer(HSIZE_T) :: dims2(2) - integer(HSIZE_T) :: dims3(3) - real(8), allocatable :: temp(:,:) - character(20) :: type - type(CorrelatedAngleEnergy) :: correlated_dist + real(C_DOUBLE) :: dummy + integer(C_INT) :: n - character(MAX_WORD_LEN) :: temp_str - character(MAX_WORD_LEN), allocatable :: dset_names(:) - real(8), allocatable :: temps_available(:) ! temperatures available - real(8) :: temp_desired - real(8) :: temp_actual - type(VectorInt) :: temps_to_read - - ! Get name of table from group - this % name = get_name(group_id) - - ! Get rid of leading '/' - this % name = trim(this % name(2:)) - - call read_attribute(this % awr, group_id, 'atomic_weight_ratio') - call read_attribute(this % nuclides, group_id, 'nuclides') - call read_attribute(type, group_id, 'secondary_mode') - select case (type) - case ('equal') - this % secondary_mode = SAB_SECONDARY_EQUAL - case ('skewed') - this % secondary_mode = SAB_SECONDARY_SKEWED - case ('continuous') - this % secondary_mode = SAB_SECONDARY_CONT - end select - - ! Read temperatures - kT_group = open_group(group_id, 'kTs') - - ! Determine temperatures available - call get_datasets(kT_group, dset_names) - allocate(temps_available(size(dset_names))) - do i = 1, size(dset_names) - ! Read temperature value - call read_dataset(temps_available(i), kT_group, trim(dset_names(i))) - temps_available(i) = temps_available(i) / K_BOLTZMANN - end do - call sort(temps_available) - - ! Determine actual temperatures to read -- start by checking whether a - ! temperature range was given, in which case all temperatures in the range - ! are loaded irrespective of what temperatures actually appear in the model - if (minmax(2) > ZERO) then - do i = 1, size(temps_available) - temp_actual = temps_available(i) - if (minmax(1) <= temp_actual .and. temp_actual <= minmax(2)) then - call temps_to_read % push_back(nint(temp_actual)) - end if - end do + n = temperature % size() + if (n > 0) then + this % ptr = sab_from_hdf5(group_id, temperature % data(1), n, method, tolerance, minmax) + else + ! In this case, temperatures % data(1) doesn't exist, so we just pass a + ! dummy value + this % ptr = sab_from_hdf5(group_id, dummy, n, method, tolerance, minmax) end if - - select case (method) - case (TEMPERATURE_NEAREST) - ! Determine actual temperatures to read - do i = 1, temperature % size() - temp_desired = temperature % data(i) - i_closest = minloc(abs(temps_available - temp_desired), dim=1) - temp_actual = temps_available(i_closest) - if (abs(temp_actual - temp_desired) < tolerance) then - if (find(temps_to_read, nint(temp_actual)) == -1) then - call temps_to_read % push_back(nint(temp_actual)) - end if - else - call fatal_error("Nuclear data library does not contain cross sections & - &for " // trim(this % name) // " at or near " // & - trim(to_str(nint(temp_desired))) // " K.") - end if - end do - - case (TEMPERATURE_INTERPOLATION) - ! If temperature interpolation or multipole is selected, get a list of - ! bounding temperatures for each actual temperature present in the model - TEMP_LOOP: do i = 1, temperature % size() - temp_desired = temperature % data(i) - - do j = 1, size(temps_available) - 1 - if (temps_available(j) <= temp_desired .and. & - temp_desired < temps_available(j + 1)) then - if (find(temps_to_read, nint(temps_available(j))) == -1) then - call temps_to_read % push_back(nint(temps_available(j))) - end if - if (find(temps_to_read, nint(temps_available(j + 1))) == -1) then - call temps_to_read % push_back(nint(temps_available(j + 1))) - end if - cycle TEMP_LOOP - end if - end do - - call fatal_error("Nuclear data library does not contain cross sections & - &for " // trim(this % name) // " at temperatures that bound " // & - trim(to_str(nint(temp_desired))) // " K.") - end do TEMP_LOOP - - end select - - ! Sort temperatures to read - call sort(temps_to_read) - - n_temperature = temps_to_read % size() - allocate(this % kTs(n_temperature)) - allocate(this % data(n_temperature)) - - do t = 1, n_temperature - ! Get temperature as a string - temp_str = trim(to_str(temps_to_read % data(t))) // "K" - - ! Read exact temperature value - call read_dataset(this % kTs(t), kT_group, temp_str) - - ! Open group for temperature i - T_group = open_group(group_id, temp_str) - - ! Coherent elastic data - if (object_exists(T_group, 'elastic')) then - ! Read cross section data - elastic_group = open_group(T_group, 'elastic') - dset_id = open_dataset(elastic_group, 'xs') - call read_attribute(type, dset_id, 'type') - call get_shape(dset_id, dims2) - allocate(temp(dims2(1), dims2(2))) - call read_dataset(temp, dset_id) - call close_dataset(dset_id) - - ! Set cross section data and type - this % data(t) % n_elastic_e_in = int(dims2(1), 4) - allocate(this % data(t) % elastic_e_in(this % data(t) % n_elastic_e_in)) - allocate(this % data(t) % elastic_P(this % data(t) % n_elastic_e_in)) - this % data(t) % elastic_e_in(:) = temp(:, 1) - this % data(t) % elastic_P(:) = temp(:, 2) - select case (type) - case ('tab1') - this % data(t) % elastic_mode = SAB_ELASTIC_DISCRETE - case ('bragg') - this % data(t) % elastic_mode = SAB_ELASTIC_EXACT - end select - deallocate(temp) - - ! Set elastic threshold - this % data(t) % threshold_elastic = this % data(t) % elastic_e_in(& - this % data(t) % n_elastic_e_in) - - ! Read angle distribution - if (this % data(t) % elastic_mode /= SAB_ELASTIC_EXACT) then - dset_id = open_dataset(elastic_group, 'mu_out') - call get_shape(dset_id, dims2) - this % data(t) % n_elastic_mu = int(dims2(1), 4) - allocate(this % data(t) % elastic_mu(dims2(1), dims2(2))) - call read_dataset(this % data(t) % elastic_mu, dset_id) - call close_dataset(dset_id) - end if - - call close_group(elastic_group) - end if - - ! Inelastic data - if (object_exists(T_group, 'inelastic')) then - ! Read type of inelastic data - inelastic_group = open_group(T_group, 'inelastic') - - ! Read cross section data - dset_id = open_dataset(inelastic_group, 'xs') - call get_shape(dset_id, dims2) - allocate(temp(dims2(1), dims2(2))) - call read_dataset(temp, dset_id) - call close_dataset(dset_id) - - ! Set cross section data - this % data(t) % n_inelastic_e_in = int(dims2(1), 4) - allocate(this % data(t) % inelastic_e_in(this % data(t) % n_inelastic_e_in)) - allocate(this % data(t) % inelastic_sigma(this % data(t) % n_inelastic_e_in)) - this % data(t) % inelastic_e_in(:) = temp(:, 1) - this % data(t) % inelastic_sigma(:) = temp(:, 2) - deallocate(temp) - - ! Set inelastic threshold - this % data(t) % threshold_inelastic = this % data(t) % inelastic_e_in(& - this % data(t) % n_inelastic_e_in) - - if (this % secondary_mode /= SAB_SECONDARY_CONT) then - ! Read energy distribution - dset_id = open_dataset(inelastic_group, 'energy_out') - call get_shape(dset_id, dims2) - this % data(t) % n_inelastic_e_out = int(dims2(1), 4) - allocate(this % data(t) % inelastic_e_out(dims2(1), dims2(2))) - call read_dataset(this % data(t) % inelastic_e_out, dset_id) - call close_dataset(dset_id) - - ! Read angle distribution - dset_id = open_dataset(inelastic_group, 'mu_out') - call get_shape(dset_id, dims3) - this % data(t) % n_inelastic_mu = int(dims3(1), 4) - allocate(this % data(t) % inelastic_mu(dims3(1), dims3(2), dims3(3))) - call read_dataset(this % data(t) % inelastic_mu, dset_id) - call close_dataset(dset_id) - else - ! Read correlated angle-energy distribution - call correlated_dist % from_hdf5(inelastic_group) - - ! Convert to S(a,b) native format - n_energy = size(correlated_dist % energy) - allocate(this % data(t) % inelastic_data(n_energy)) - do i = 1, n_energy - associate (edist => correlated_dist % distribution(i)) - ! Get number of outgoing energies for incoming energy i - n_energy_out = size(edist % e_out) - this % data(t) % inelastic_data(i) % n_e_out = n_energy_out - allocate(this % data(t) % inelastic_data(i) % e_out(n_energy_out)) - allocate(this % data(t) % inelastic_data(i) % e_out_pdf(n_energy_out)) - allocate(this % data(t) % inelastic_data(i) % e_out_cdf(n_energy_out)) - - ! Copy outgoing energy distribution - this % data(t) % inelastic_data(i) % e_out(:) = edist % e_out - this % data(t) % inelastic_data(i) % e_out_pdf(:) = edist % p - this % data(t) % inelastic_data(i) % e_out_cdf(:) = edist % c - - do j = 1, n_energy_out - select type (adist => edist % angle(j) % obj) - type is (Tabular) - ! On first pass, allocate space for angles - if (j == 1) then - n_mu = size(adist % x) - this % data(t) % n_inelastic_mu = n_mu - allocate(this % data(t) % inelastic_data(i) % mu(& - n_mu, n_energy_out)) - end if - - ! Copy outgoing angles - this % data(t) % inelastic_data(i) % mu(:, j) = adist % x - end select - end do - end associate - end do - - ! Clear data on correlated angle-energy object - deallocate(correlated_dist % breakpoints) - deallocate(correlated_dist % interpolation) - deallocate(correlated_dist % energy) - deallocate(correlated_dist % distribution) - end if - - call close_group(inelastic_group) - end if - call close_group(T_group) - end do - - call close_group(kT_group) - end subroutine salphabeta_from_hdf5 + end subroutine from_hdf5 !=============================================================================== ! SAB_CALCULATE_XS determines the elastic and inelastic scattering ! cross-sections in the thermal energy range. !=============================================================================== - subroutine sab_calculate_xs(this, E, sqrtkT, i_temp, elastic, inelastic) + subroutine calculate_xs(this, E, sqrtkT, i_temp, elastic, inelastic) class(SAlphaBeta), intent(in) :: this ! S(a,b) object - real(8), intent(in) :: E ! energy - real(8), intent(in) :: sqrtkT ! temperature + real(C_DOUBLE), intent(in) :: E ! energy + real(C_DOUBLE), intent(in) :: sqrtkT ! temperature integer, intent(out) :: i_temp ! index in the S(a,b)'s temperature - real(8), intent(out) :: elastic ! thermal elastic cross section - real(8), intent(out) :: inelastic ! thermal inelastic cross section + real(C_DOUBLE), intent(out) :: elastic ! thermal elastic cross section + real(C_DOUBLE), intent(out) :: inelastic ! thermal inelastic cross section - integer :: i_grid ! index on S(a,b) energy grid - real(8) :: f ! interp factor on S(a,b) energy grid - real(8) :: kT + call sab_calculate_xs(this % ptr, E, sqrtkT, i_temp, elastic, inelastic) + end subroutine - ! Determine temperature for S(a,b) table - kT = sqrtkT**2 - if (temperature_method == TEMPERATURE_NEAREST) then - ! If using nearest temperature, do linear search on temperature - do i_temp = 1, size(this % kTs) - if (abs(this % kTs(i_temp) - kT) < & - K_BOLTZMANN*temperature_tolerance) exit - end do - else - ! Find temperatures that bound the actual temperature - do i_temp = 1, size(this % kTs) - 1 - if (this % kTs(i_temp) <= kT .and. & - kT < this % kTs(i_temp + 1)) exit - end do + subroutine free(this) + class(SAlphaBeta), intent(inout) :: this + call sab_free(this % ptr) + end subroutine - ! Randomly sample between temperature i and i+1 - f = (kT - this % kTs(i_temp)) / & - (this % kTs(i_temp + 1) - this % kTs(i_temp)) - if (f > prn()) i_temp = i_temp + 1 - end if + function has_nuclide(this, name) result(val) + class(SAlphaBeta), intent(in) :: this + character(len=*), intent(in) :: name + logical(C_BOOL) :: val + val = sab_has_nuclide(this % ptr, to_c_string(name)) + end function - ! Get pointer to S(a,b) table - associate (sab => this % data(i_temp)) + subroutine sample(this, micro_xs, E_in, E_out, mu) + class(SAlphaBeta), intent(in) :: this + type(C_PTR), value :: micro_xs + real(C_DOUBLE), value :: E_in + real(C_DOUBLE), intent(out) :: E_out + real(C_DOUBLE), intent(out) :: mu - ! Get index and interpolation factor for inelastic grid - if (E < sab % inelastic_e_in(1)) then - i_grid = 1 - f = ZERO - else - i_grid = binary_search(sab % inelastic_e_in, sab % n_inelastic_e_in, E) - f = (E - sab%inelastic_e_in(i_grid)) / & - (sab%inelastic_e_in(i_grid+1) - sab%inelastic_e_in(i_grid)) - end if - - ! Calculate S(a,b) inelastic scattering cross section - inelastic = (ONE - f) * sab % inelastic_sigma(i_grid) + & - f * sab % inelastic_sigma(i_grid + 1) - - ! Check for elastic data - if (E < sab % threshold_elastic) then - ! Determine whether elastic scattering is given in the coherent or - ! incoherent approximation. For coherent, the cross section is - ! represented as P/E whereas for incoherent, it is simply P - - if (sab % elastic_mode == SAB_ELASTIC_EXACT) then - if (E < sab % elastic_e_in(1)) then - ! If energy is below that of the lowest Bragg peak, the elastic - ! cross section will be zero - elastic = ZERO - else - i_grid = binary_search(sab % elastic_e_in, & - sab % n_elastic_e_in, E) - elastic = sab % elastic_P(i_grid) / E - end if - else - ! Determine index on elastic energy grid - if (E < sab % elastic_e_in(1)) then - i_grid = 1 - else - i_grid = binary_search(sab % elastic_e_in, & - sab % n_elastic_e_in, E) - end if - - ! Get interpolation factor for elastic grid - f = (E - sab%elastic_e_in(i_grid))/(sab%elastic_e_in(i_grid+1) - & - sab%elastic_e_in(i_grid)) - - ! Calculate S(a,b) elastic scattering cross section - elastic = (ONE - f) * sab % elastic_P(i_grid) + & - f * sab % elastic_P(i_grid + 1) - end if - else - ! No elastic data - elastic = ZERO - end if - end associate - - end subroutine sab_calculate_xs + call sab_sample(this % ptr, micro_xs, E_in, E_out, mu) + end subroutine + function threshold(this) + class(SAlphaBeta), intent(in) :: this + real(C_DOUBLE) :: threshold + threshold = sab_threshold(this % ptr) + end function !=============================================================================== ! FREE_MEMORY_SAB deallocates global arrays defined in this module !=============================================================================== subroutine free_memory_sab() + integer :: i n_sab_tables = 0 + do i = 1, size(sab_tables) + call sab_tables(i) % free() + end do if (allocated(sab_tables)) deallocate(sab_tables) call sab_dict % clear() end subroutine free_memory_sab diff --git a/src/thermal.cpp b/src/thermal.cpp index 176980592..0738497b5 100644 --- a/src/thermal.cpp +++ b/src/thermal.cpp @@ -577,4 +577,41 @@ ThermalData::sample(const NuclideMicroXS* micro_xs, double E, } +//============================================================================== +// Fortran compatibility functions +//============================================================================== + +ThermalScattering* +sab_from_hdf5(hid_t group, const double* temperature, int n, + int method, double tolerance, const double* minmax) +{ + // Convert temperatures to a vector + std::vector T {temperature, temperature + n}; + + // Create new object and return it + return new ThermalScattering{group, T, method, tolerance, minmax}; +} + +void sab_calculate_xs(ThermalScattering* data, double E, double sqrtkT, + int* i_temp, double* elastic, double* inelastic) +{ + data->calculate_xs(E, sqrtkT, i_temp, elastic, inelastic); +} + +void sab_free(ThermalScattering* data) { delete data; } + +bool sab_has_nuclide(ThermalScattering* data, const char* name) +{ + return data->has_nuclide(name); +} + +void sab_sample(ThermalScattering* data, const NuclideMicroXS* micro_xs, + double E_in, double* E_out, double* mu) +{ + int i_temp = micro_xs->index_temp_sab; + data->data_[i_temp - 1].sample(micro_xs, E_in, E_out, mu); +} + +double sab_threshold(ThermalScattering* data) { return data->threshold(); } + } // namespace openmc diff --git a/src/thermal.h b/src/thermal.h index d33465bf8..e3571a0d5 100644 --- a/src/thermal.h +++ b/src/thermal.h @@ -111,6 +111,12 @@ public: //! \return Whether table applies to the nuclide bool has_nuclide(const char* name) const; + // Sample an outgoing energy and angle + void sample(const NuclideMicroXS* micro_xs, double E_in, + double* E_out, double* mu); + + double threshold() const { return data_[0].threshold_inelastic_; } + std::string name_; //!< name of table, e.g. "c_H_in_H2O" double awr_; //!< weight of nucleus in neutron masses std::vector kTs_; //!< temperatures in [eV] (k*T) @@ -120,6 +126,22 @@ public: std::vector data_; }; +//============================================================================== +// Fortran compatibility functions +//============================================================================== + +extern "C" { + ThermalScattering* sab_from_hdf5(hid_t group, const double* temperature, + int n, int method, double tolerance, const double* minmax); + void sab_calculate_xs(ThermalScattering* data, double E, double sqrtkT, + int* i_temp, double* elastic, double* inelastic); + void sab_free(ThermalScattering* data); + bool sab_has_nuclide(ThermalScattering* data, const char* name); + void sab_sample(ThermalScattering* data, const NuclideMicroXS* micro_xs, + double E_in, double* E_out, double* mu); + double sab_threshold(ThermalScattering* data); +} + } // namespace openmc #endif // OPENMC_THERMAL_SCATTERING_H From 36a6f1e1828497ca35eaa5dd4cf8993872f7a77b Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 15 Aug 2018 22:04:28 -0500 Subject: [PATCH 18/56] Fix bug in templated read_dataset for scalars --- src/hdf5_interface.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hdf5_interface.h b/src/hdf5_interface.h index 5f7f3064c..6ef9a1895 100644 --- a/src/hdf5_interface.h +++ b/src/hdf5_interface.h @@ -234,7 +234,7 @@ read_attribute(hid_t obj_id, const char* name, std::vector& vec) //============================================================================== template -void read_dataset(hid_t obj_id, const char* name, T buffer, bool indep=false) +void read_dataset(hid_t obj_id, const char* name, T& buffer, bool indep=false) { read_dataset(obj_id, name, H5TypeMap::type_id, &buffer, indep); } From e9ff50b784735e946a1e8621111aec3ad9975828 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 15 Aug 2018 22:05:21 -0500 Subject: [PATCH 19/56] Fix bugs to get thermal scattering working --- src/sab_header.F90 | 10 ++++++---- src/thermal.cpp | 20 +++++++++++++------- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/src/sab_header.F90 b/src/sab_header.F90 index ece262bd6..b4696a65d 100644 --- a/src/sab_header.F90 +++ b/src/sab_header.F90 @@ -161,10 +161,12 @@ contains subroutine free_memory_sab() integer :: i n_sab_tables = 0 - do i = 1, size(sab_tables) - call sab_tables(i) % free() - end do - if (allocated(sab_tables)) deallocate(sab_tables) + if (allocated(sab_tables)) then + do i = 1, size(sab_tables) + call sab_tables(i) % free() + end do + deallocate(sab_tables) + end if call sab_dict % clear() end subroutine free_memory_sab diff --git a/src/thermal.cpp b/src/thermal.cpp index 0738497b5..2732b8f02 100644 --- a/src/thermal.cpp +++ b/src/thermal.cpp @@ -140,7 +140,7 @@ ThermalScattering::ThermalScattering(hid_t group, const std::vector& tem // Open group for temperature i hid_t T_group = open_group(group, temp_str.data()); data_.emplace_back(T_group, secondary_mode); - close_group(group); + close_group(T_group); } close_group(kT_group); @@ -312,11 +312,13 @@ ThermalData::ThermalData(hid_t group, int secondary_mode) xt::xarray E_out; read_dataset(inelastic_group, "energy_out", E_out); inelastic_e_out_ = E_out; + n_inelastic_e_out_ = inelastic_e_out_.shape()[1]; // Read angle distribution xt::xarray mu_out; read_dataset(inelastic_group, "mu_out", mu_out); inelastic_mu_ = mu_out; + n_inelastic_mu_ = inelastic_mu_.shape()[2]; } else { // Read correlated angle-energy distribution CorrelatedAngleEnergy dist {inelastic_group}; @@ -396,10 +398,8 @@ ThermalData::sample(const NuclideMicroXS* micro_xs, double E, // Sample a Bragg edge between 1 and i double prob = prn() * elastic_P_[i+1]; - int k; - if (prob < elastic_P_.front()) { - k = 1; - } else { + int k = 0; + if (prob >= elastic_P_.front()) { k = lower_bound_index(elastic_P_.begin(), elastic_P_.begin() + (i+1), prob); } @@ -408,7 +408,8 @@ ThermalData::sample(const NuclideMicroXS* micro_xs, double E, } - // Outgoing energy is same as incoming energy -- no need to do anything + // Outgoing energy is same as incoming energy + *E_out = E; } else { // Perform inelastic calculations @@ -595,7 +596,12 @@ sab_from_hdf5(hid_t group, const double* temperature, int n, void sab_calculate_xs(ThermalScattering* data, double E, double sqrtkT, int* i_temp, double* elastic, double* inelastic) { - data->calculate_xs(E, sqrtkT, i_temp, elastic, inelastic); + // Calculate cross section + int t; + data->calculate_xs(E, sqrtkT, &t, elastic, inelastic); + + // Fortran needs index plus one + *i_temp = t + 1; } void sab_free(ThermalScattering* data) { delete data; } From b0333359d53acb82a42c10257c316957647bd0a9 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 15 Aug 2018 22:07:26 -0500 Subject: [PATCH 20/56] Remove secondary_correlated.F90 and angleenergy_header.F90 --- CMakeLists.txt | 2 - src/angleenergy_header.F90 | 38 ----- src/secondary_correlated.F90 | 302 ----------------------------------- 3 files changed, 342 deletions(-) delete mode 100644 src/angleenergy_header.F90 delete mode 100644 src/secondary_correlated.F90 diff --git a/CMakeLists.txt b/CMakeLists.txt index efbffcb58..e6c899440 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -288,7 +288,6 @@ set_target_properties(faddeeva PROPERTIES add_library(libopenmc SHARED src/algorithm.F90 - src/angleenergy_header.F90 src/bank_header.F90 src/api.F90 src/cmfd_data.F90 @@ -338,7 +337,6 @@ add_library(libopenmc SHARED src/reaction_header.F90 src/relaxng src/sab_header.F90 - src/secondary_correlated.F90 src/set_header.F90 src/settings.F90 src/simulation_header.F90 diff --git a/src/angleenergy_header.F90 b/src/angleenergy_header.F90 deleted file mode 100644 index 9fda5109e..000000000 --- a/src/angleenergy_header.F90 +++ /dev/null @@ -1,38 +0,0 @@ -module angleenergy_header - - use hdf5_interface, only: HID_T - -!=============================================================================== -! ANGLEENERGY (abstract) defines a correlated or uncorrelated angle-energy -! distribution that is a function of incoming energy. Each derived type must -! implement a sample() subroutine that returns an outgoing energy and scattering -! cosine given an incoming energy. -!=============================================================================== - - type, abstract :: AngleEnergy - contains - procedure(angleenergy_sample_), deferred :: sample - procedure(angleenergy_from_hdf5_), deferred :: from_hdf5 - end type AngleEnergy - - abstract interface - subroutine angleenergy_sample_(this, E_in, E_out, mu) - import AngleEnergy - class(AngleEnergy), intent(in) :: this - real(8), intent(in) :: E_in - real(8), intent(out) :: E_out - real(8), intent(out) :: mu - end subroutine angleenergy_sample_ - - subroutine angleenergy_from_hdf5_(this, group_id) - import AngleEnergy, HID_T - class(AngleEnergy), intent(inout) :: this - integer(HID_T), intent(in) :: group_id - end subroutine angleenergy_from_hdf5_ - end interface - - type :: AngleEnergyContainer - class(AngleEnergy), allocatable :: obj - end type AngleEnergyContainer - -end module angleenergy_header diff --git a/src/secondary_correlated.F90 b/src/secondary_correlated.F90 deleted file mode 100644 index 6f5e6cabf..000000000 --- a/src/secondary_correlated.F90 +++ /dev/null @@ -1,302 +0,0 @@ -module secondary_correlated - - use algorithm, only: binary_search - use angleenergy_header, only: AngleEnergy - use constants, only: ZERO, ONE, HALF, TWO, HISTOGRAM, LINEAR_LINEAR - use distribution_univariate, only: DistributionContainer, Tabular - use hdf5_interface - use random_lcg, only: prn - -!=============================================================================== -! CORRELATEDANGLEENERGY represents a correlated angle-energy distribution. This -! corresponds to ACE law 61 and ENDF File 6, LAW=1, LANG/=2. -!=============================================================================== - - type AngleEnergyTable - integer :: interpolation - integer :: n_discrete - real(8), allocatable :: e_out(:) - real(8), allocatable :: p(:) - real(8), allocatable :: c(:) - type(DistributionContainer), allocatable :: angle(:) - end type AngleEnergyTable - - type, extends(AngleEnergy) :: CorrelatedAngleEnergy - integer :: n_region ! number of interpolation regions - integer, allocatable :: breakpoints(:) ! breakpoints of interpolation regions - integer, allocatable :: interpolation(:) ! interpolation region codes - real(8), allocatable :: energy(:) ! incoming energies - type(AngleEnergyTable), allocatable :: distribution(:) ! outgoing E/mu distributions - contains - procedure :: sample => correlated_sample - procedure :: from_hdf5 => correlated_from_hdf5 - end type CorrelatedAngleEnergy - -contains - - subroutine correlated_sample(this, E_in, E_out, mu) - class(CorrelatedAngleEnergy), intent(in) :: this - real(8), intent(in) :: E_in ! incoming energy - real(8), intent(out) :: E_out ! sampled outgoing energy - real(8), intent(out) :: mu ! sapmled scattering cosine - - integer :: i, k, l ! indices - integer :: n_energy_in ! number of incoming energies - integer :: n_energy_out ! number of outgoing energies - real(8) :: r ! interpolation factor on incoming energy - real(8) :: r1 ! random number on [0,1) - real(8) :: frac ! interpolation factor on outgoing energy - real(8) :: E_i_1, E_i_K ! endpoints on outgoing grid i - real(8) :: E_i1_1, E_i1_K ! endpoints on outgoing grid i+1 - real(8) :: E_1, E_K ! endpoints interpolated between i and i+1 - real(8) :: E_l_k, E_l_k1 ! adjacent E on outgoing grid l - real(8) :: p_l_k, p_l_k1 ! adjacent p on outgoing grid l - real(8) :: c_k, c_k1 ! cumulative probability - - ! <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< REMOVE THIS <<<<<<<<<<<<<<<<<<<<<<<<<<<<< - ! Before the secondary distribution refactor, an isotropic polar cosine was - ! always sampled but then overwritten with the polar cosine sampled from the - ! correlated distribution. To preserve the random number stream, we keep - ! this dummy sampling here but can remove it later (will change answers) - mu = TWO*prn() - ONE - ! <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< REMOVE THIS <<<<<<<<<<<<<<<<<<<<<<<<<<<<< - - ! find energy bin and calculate interpolation factor -- if the energy is - ! outside the range of the tabulated energies, choose the first or last bins - n_energy_in = size(this%energy) - if (E_in < this%energy(1)) then - i = 1 - r = ZERO - elseif (E_in > this%energy(n_energy_in)) then - i = n_energy_in - 1 - r = ONE - else - i = binary_search(this%energy, n_energy_in, E_in) - r = (E_in - this%energy(i)) / & - (this%energy(i+1) - this%energy(i)) - end if - - ! Sample between the ith and (i+1)th bin - if (r > prn()) then - l = i + 1 - else - l = i - end if - - ! interpolation for energy E1 and EK - n_energy_out = size(this%distribution(i)%e_out) - E_i_1 = this%distribution(i)%e_out(1) - E_i_K = this%distribution(i)%e_out(n_energy_out) - - n_energy_out = size(this%distribution(i+1)%e_out) - E_i1_1 = this%distribution(i+1)%e_out(1) - E_i1_K = this%distribution(i+1)%e_out(n_energy_out) - - E_1 = E_i_1 + r*(E_i1_1 - E_i_1) - E_K = E_i_K + r*(E_i1_K - E_i_K) - - ! determine outgoing energy bin - n_energy_out = size(this%distribution(l)%e_out) - r1 = prn() - c_k = this%distribution(l)%c(1) - do k = 1, n_energy_out - 1 - c_k1 = this%distribution(l)%c(k+1) - if (r1 < c_k1) exit - c_k = c_k1 - end do - - ! check to make sure k is <= NP - 1 - k = min(k, n_energy_out - 1) - - E_l_k = this%distribution(l)%e_out(k) - p_l_k = this%distribution(l)%p(k) - if (this%distribution(l)%interpolation == HISTOGRAM) then - ! Histogram interpolation - if (p_l_k > ZERO) then - E_out = E_l_k + (r1 - c_k)/p_l_k - else - E_out = E_l_k - end if - - elseif (this%distribution(l)%interpolation == LINEAR_LINEAR) then - ! Linear-linear interpolation - E_l_k1 = this%distribution(l)%e_out(k+1) - p_l_k1 = this%distribution(l)%p(k+1) - - frac = (p_l_k1 - p_l_k)/(E_l_k1 - E_l_k) - if (frac == ZERO) then - E_out = E_l_k + (r1 - c_k)/p_l_k - else - E_out = E_l_k + (sqrt(max(ZERO, p_l_k*p_l_k + & - TWO*frac*(r1 - c_k))) - p_l_k)/frac - end if - end if - - ! Now interpolate between incident energy bins i and i + 1 - if (l == i) then - E_out = E_1 + (E_out - E_i_1)*(E_K - E_1)/(E_i_K - E_i_1) - else - E_out = E_1 + (E_out - E_i1_1)*(E_K - E_1)/(E_i1_K - E_i1_1) - end if - - ! Find correlated angular distribution for closest outgoing energy bin - if (r1 - c_k < c_k1 - r1) then - mu = this%distribution(l)%angle(k)%obj%sample() - else - mu = this%distribution(l)%angle(k + 1)%obj%sample() - end if - end subroutine correlated_sample - - subroutine correlated_from_hdf5(this, group_id) - class(CorrelatedAngleEnergy), intent(inout) :: this - integer(HID_T), intent(in) :: group_id - - integer :: i, j, k - integer :: n_energy - integer :: m, n - integer :: offset_mu - integer :: interp_mu - integer(HID_T) :: dset_id - integer(HSIZE_T) :: dims(1), dims2(2) - integer, allocatable :: temp(:,:) - integer, allocatable :: offsets(:) - integer, allocatable :: interp(:) - integer, allocatable :: n_discrete(:) - real(8), allocatable :: eout(:,:) - real(8), allocatable :: mu(:,:) - - ! Open incoming energy dataset - dset_id = open_dataset(group_id, 'energy') - - ! Get interpolation parameters - call read_attribute(temp, dset_id, 'interpolation') - allocate(this%breakpoints(size(temp, 1))) - allocate(this%interpolation(size(temp, 1))) - this%breakpoints(:) = temp(:, 1) - this%interpolation(:) = temp(:, 2) - this%n_region = size(this%breakpoints) - deallocate(temp) - - ! Get incoming energies - call get_shape(dset_id, dims) - n_energy = int(dims(1), 4) - allocate(this%energy(n_energy)) - allocate(this%distribution(n_energy)) - call read_dataset(this%energy, dset_id) - call close_dataset(dset_id) - - ! Get outgoing energy distribution data - dset_id = open_dataset(group_id, 'energy_out') - call read_attribute(offsets, dset_id, 'offsets') - call read_attribute(interp, dset_id, 'interpolation') - call read_attribute(n_discrete, dset_id, 'n_discrete_lines') - call get_shape(dset_id, dims2) - allocate(eout(dims2(1), dims2(2))) - call read_dataset(eout, dset_id) - call close_dataset(dset_id) - - ! Get outgoing angle data - dset_id = open_dataset(group_id, 'mu') - call get_shape(dset_id, dims2) - allocate(mu(dims2(1), dims2(2))) - call read_dataset(mu, dset_id) - call close_dataset(dset_id) - - do i = 1, n_energy - ! Determine number of outgoing energies - j = offsets(i) - if (i < n_energy) then - n = offsets(i+1) - j - else - n = size(eout, 1) - j - end if - - associate (d => this % distribution(i)) - ! Assign interpolation scheme and number of discrete lines - d % interpolation = interp(i) - d % n_discrete = n_discrete(i) - - ! Allocate arrays for energies and PDF/CDF - allocate(d % e_out(n)) - allocate(d % p(n)) - allocate(d % c(n)) - allocate(d % angle(n)) - - ! Copy data - d % e_out(:) = eout(j+1:j+n, 1) - d % p(:) = eout(j+1:j+n, 2) - d % c(:) = eout(j+1:j+n, 3) - - ! To get answers that match ACE data, for now we still use the tabulated - ! CDF values that were passed through to the HDF5 library. At a later - ! time, we can remove the CDF values from the HDF5 library and - ! reconstruct them using the PDF - if (.false.) then - ! Calculate cumulative distribution function -- discrete portion - do k = 1, d % n_discrete - if (k == 1) then - d % c(k) = d % p(k) - else - d % c(k) = d % c(k-1) + d % p(k) - end if - end do - - ! Continuous portion - do k = d % n_discrete + 1, n - if (k == d % n_discrete + 1) then - d % c(k) = sum(d % p(1:d % n_discrete)) - else - if (d % interpolation == HISTOGRAM) then - d % c(k) = d % c(k-1) + d % p(k-1) * & - (d % e_out(k) - d % e_out(k-1)) - elseif (d % interpolation == LINEAR_LINEAR) then - d % c(k) = d % c(k-1) + HALF*(d % p(k-1) + d % p(k)) * & - (d % e_out(k) - d % e_out(k-1)) - end if - end if - end do - - ! Normalize density and distribution functions - d % p(:) = d % p(:)/d % c(n) - d % c(:) = d % c(:)/d % c(n) - end if - end associate - - do j = 1, n - allocate(Tabular :: this%distribution(i)%angle(j)%obj) - select type(mudist => this%distribution(i)%angle(j)%obj) - type is (Tabular) - ! Get interpolation scheme - interp_mu = nint(eout(offsets(i)+j, 4)) - - ! Determine offset and size of distribution - offset_mu = nint(eout(offsets(i)+j, 5)) - if (offsets(i) + j < size(eout, 1)) then - m = nint(eout(offsets(i)+j+1, 5)) - offset_mu - else - m = size(mu, 1) - offset_mu - end if - - ! To get answers that match ACE data, for now we still use the tabulated - ! CDF values that were passed through to the HDF5 library. At a later - ! time, we can remove the CDF values from the HDF5 library and - ! reconstruct them using the PDF - if (.true.) then - mudist % interpolation = interp_mu - allocate(mudist % x(m)) - allocate(mudist % p(m)) - allocate(mudist % c(m)) - mudist % x(:) = mu(offset_mu+1:offset_mu+m, 1) - mudist % p(:) = mu(offset_mu+1:offset_mu+m, 2) - mudist % c(:) = mu(offset_mu+1:offset_mu+m, 3) - else - ! Initialize tabular distribution - call mudist % initialize(mu(offset_mu+1:offset_mu+m, 1), & - mu(offset_mu+1:offset_mu+m, 2), interp_mu) - end if - end select - end do - end do - end subroutine correlated_from_hdf5 - -end module secondary_correlated From 74c8d70ca6c28cec81321f639913b9bd66554901 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 16 Aug 2018 09:26:50 -0500 Subject: [PATCH 21/56] Use PEP 518 pyproject.toml file to manage build dependencies --- MANIFEST.in | 1 + pyproject.toml | 2 ++ tools/ci/travis-install.sh | 4 ---- 3 files changed, 3 insertions(+), 4 deletions(-) create mode 100644 pyproject.toml diff --git a/MANIFEST.in b/MANIFEST.in index 04348222f..be82928a1 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,6 +1,7 @@ include CMakeLists.txt include LICENSE include schemas.xml +include pyproject.toml include openmc/data/reconstruct.pyx include docs/source/_templates/layout.html include docs/sphinxext/LICENSE diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 000000000..d5970617a --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,2 @@ +[build-system] +requires = ["setuptools", "wheel", "numpy", "cython"] diff --git a/tools/ci/travis-install.sh b/tools/ci/travis-install.sh index 1f80453ad..5ad238169 100755 --- a/tools/ci/travis-install.sh +++ b/tools/ci/travis-install.sh @@ -7,10 +7,6 @@ set -ex # Upgrade pip before doing anything else pip install --upgrade pip -# Running OpenMC's setup.py requires numpy/cython already -pip install numpy -pip install cython - # pytest installed by default -- make sure we get latest pip install --upgrade pytest From 847e2cc28075e367c04c2beb8e54e717cdf0a13a Mon Sep 17 00:00:00 2001 From: Zhuoran Han Date: Thu, 16 Aug 2018 14:13:03 -0500 Subject: [PATCH 22/56] Revert test_math.py --- tests/unit_tests/test_math.py | 50 +---------------------------------- 1 file changed, 1 insertion(+), 49 deletions(-) diff --git a/tests/unit_tests/test_math.py b/tests/unit_tests/test_math.py index 65fcd728f..7ef749dec 100644 --- a/tests/unit_tests/test_math.py +++ b/tests/unit_tests/test_math.py @@ -57,30 +57,9 @@ def test_evaluate_legendre(): test_vals = np.array([openmc.capi.math.evaluate_legendre(test_coeffs, x) for x in test_xs]) - # When turn on the flag 2, evaluate_legendre should be the same as - # np.polynomial.legendre.legval(). - test_coeffs = [(2. * l + 1.) / 10 for l in range(max_order + 1)] - ref_vals_1 = np.polynomial.legendre.legval(test_xs, test_coeffs) - - test_vals_1 = np.array([openmc.capi.math.evaluate_legendre(test_coeffs, x, - 2)for x in test_xs]) - - assert np.allclose(ref_vals, test_vals) - assert np.allclose(ref_vals_1, test_vals_1) - - -def test_calc_norm_pn(): - max_order = 10 - zmin = -10 - zmax = 10 - - ref_vals = np.divide(2 * np.arange(max_order + 1) + 1, (zmax-zmin)) - - test_vals = openmc.capi.math.calc_norm_pn(max_order, zmin, zmax) - assert np.allclose(ref_vals, test_vals) - + def test_calc_rn(): max_order = 10 test_ns = np.array([i for i in range(0, max_order + 1)]) @@ -171,33 +150,6 @@ def test_calc_zn_rad(): assert np.allclose(ref_vals, test_vals) -def test_evaluate_legendre(): - max_order = 10 - rho = 0.5 - - raw_zn = np.array([ - 1.00000000e+00, -5.00000000e-01, -1.25000000e-01, - 4.37500000e-01, -2.89062500e-01,-8.98437500e-02]) - raw_coeff = np.ones(6) - norm_vec = np.divide(np.arange(0, max_order + 1, 2) + 1, np.pi * rho * rho) - real_coeff = np.multiply(raw_coeff,norm_vec) - - ref_vals = np.sum(np.multiply(real_coeff,raw_zn)) - - test_vals = openmc.capi.math.evaluate_zernike_rad(real_coeff, rho) - - assert np.allclose(ref_vals, test_vals) - -def test_calc_norm_zn_rad(): - max_order = 10 - rho = 0.5 - - ref_vals = np.divide(np.arange(0, max_order + 1, 2) + 1, np.pi * rho * rho) - - test_vals = openmc.capi.math.calc_norm_zn_rad(max_order, rho) - - assert np.allclose(ref_vals, test_vals) - def test_rotate_angle(): uvw0 = np.array([1., 0., 0.]) From f7d098f0758231587b9d087c6d12ca0b6677dabd Mon Sep 17 00:00:00 2001 From: Zhuoran Han Date: Thu, 16 Aug 2018 14:14:05 -0500 Subject: [PATCH 23/56] Add some comments --- openmc/polynomials.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/openmc/polynomials.py b/openmc/polynomials.py index b3de1b992..6a9ba23c4 100644 --- a/openmc/polynomials.py +++ b/openmc/polynomials.py @@ -19,6 +19,7 @@ class Legendre(Polynomials): self.norm_coeff = np.multiply(self.norm_vec,self.coeff) def __call__(self, x): + # x is the normalized position on [-1,1] pn = capi.calc_pn(self.order, x) return np.sum(np.multiply(self.norm_coeff, pn)) @@ -27,9 +28,11 @@ class ZernikeRadial(Polynomials): super().__init__(coeff) self.order = 2 * (self.n_coeff - 1) self.radius = radius - self.norm_vec = (2 * np.arange(self.n_coeff) + 1)/(np.pi * radius ** 2) + self.norm_vec = (2 * np.arange(self.n_coeff) + 1) / (np.pi * + radius ** 2) self.norm_coeff = np.multiply(self.norm_vec,self.coeff) def __call__(self, r): + # r is the normalized position on radius [0,1] zn_rad = capi.calc_zn_rad(self.order, r) return np.sum(np.multiply(self.norm_coeff, zn_rad)) \ No newline at end of file From dc3064a79549c4f68d02e7c2b48cfaafcae54da2 Mon Sep 17 00:00:00 2001 From: Zhuoran Han Date: Thu, 16 Aug 2018 14:14:42 -0500 Subject: [PATCH 24/56] Test for the new Polynomial class --- tests/unit_tests/test_polynomials.py | 67 ++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 tests/unit_tests/test_polynomials.py diff --git a/tests/unit_tests/test_polynomials.py b/tests/unit_tests/test_polynomials.py new file mode 100644 index 000000000..6dd220df3 --- /dev/null +++ b/tests/unit_tests/test_polynomials.py @@ -0,0 +1,67 @@ +import numpy as np +import scipy as sp + +import openmc +import openmc.capi + +def test_legendre(): + coeff = np.asarray([2.5, 1.2, -0.2, 0.1]) + pn = openmc.Legendre(coeff) + assert pn.order == 3 + assert pn.domain_min == -1 + assert pn.domain_max == 1 + + norm_vec = (2 * np.arange(4) + 1) / 2 + assert np.allclose(pn.norm_vec,norm_vec) + norm_coeff = np.multiply(norm_vec,coeff) + assert np.allclose(pn.norm_coeff, norm_coeff) + + coeff = np.asarray([2.5, 1.2, -0.2]) + pn = openmc.Legendre(coeff, -10, 10) + assert pn.order == 2 + assert pn.domain_min == -10 + assert pn.domain_max == 10 + norm_vec = (2 * np.arange(3) + 1) / 20 + assert np.allclose(pn.norm_vec,norm_vec) + norm_coeff = np.multiply(norm_vec,coeff) + assert np.allclose(pn.norm_coeff, norm_coeff) + + test_xs = np.linspace(-1., 1., num=5, endpoint=True) + ref_vals = np.polynomial.legendre.legval(test_xs, norm_coeff) + + test_vals = np.array([pn(x) for x in test_xs]) + assert np.allclose(ref_vals, test_vals) + + +def test_zernike_radial(): + coeff = np.asarray([1.3, -3.0, 9e-1, -6e-1, 0.11]) + zn_rad = openmc.ZernikeRadial(coeff) + assert zn_rad.order == 8 + assert zn_rad.radius == 1 + norm_vec = (2 * np.arange(5) + 1) / np.pi + assert np.allclose(zn_rad.norm_vec,norm_vec) + norm_coeff = np.multiply(norm_vec,coeff) + assert np.allclose(zn_rad.norm_coeff,norm_coeff) + + coeff = np.asarray([1.3, -3.0, 9e-1, -6e-1, 0.11, 0.222]) + zn_rad = openmc.ZernikeRadial(coeff, 0.392) + assert zn_rad.order == 10 + assert zn_rad.radius == 0.392 + norm_vec = (2 * np.arange(6) + 1) / (np.pi * 0.392 ** 2) + assert np.allclose(zn_rad.norm_vec,norm_vec) + norm_coeff = np.multiply(norm_vec,coeff) + assert np.allclose(zn_rad.norm_coeff,norm_coeff) + + + rho = 0.5 + # Reference solution from running the Fortran implementation + raw_zn = np.array([ + 1.00000000e+00, -5.00000000e-01, -1.25000000e-01, + 4.37500000e-01, -2.89062500e-01,-8.98437500e-02]) + + ref_vals = np.sum(np.multiply(norm_coeff,raw_zn)) + + test_vals = zn_rad(rho) + + assert ref_vals == test_vals + From 1ec0a806a0b0bba223d64735458fab9fe6a48248 Mon Sep 17 00:00:00 2001 From: Shikhar Kumar Date: Thu, 16 Aug 2018 21:45:47 -0400 Subject: [PATCH 25/56] Extract code from shikhar413::cmfd-capi relevant to PR --- include/openmc.h | 5 ++ openmc/capi/tally.py | 52 ++++++++++++++++ src/api.F90 | 5 ++ src/cmfd_input.F90 | 24 ++++---- src/input_xml.F90 | 37 +++++------ src/tallies/tally_header.F90 | 116 ++++++++++++++++++++++++++++++++++- 6 files changed, 205 insertions(+), 34 deletions(-) diff --git a/include/openmc.h b/include/openmc.h index 1f919d7c6..36bfd81cb 100644 --- a/include/openmc.h +++ b/include/openmc.h @@ -47,6 +47,7 @@ extern "C" { int openmc_get_nuclide_index(const char name[], int* index); int64_t openmc_get_seed(); int openmc_get_tally_index(int32_t id, int32_t* index); + void openmc_get_tally_next_id(int32_t* id); int openmc_hard_reset(); int openmc_init(int argc, char* argv[], const void* intracomm); int openmc_init_f(const int* intracomm); @@ -93,19 +94,23 @@ extern "C" { int openmc_sphharm_filter_set_cosine(int32_t index, const char cosine[]); int openmc_statepoint_write(const char filename[]); int openmc_tally_get_active(int32_t index, bool* active); + int openmc_tally_get_estimator(int32_t index, int32_t* estimator); int openmc_tally_get_id(int32_t index, int32_t* id); int openmc_tally_get_filters(int32_t index, int32_t** indices, int* n); int openmc_tally_get_n_realizations(int32_t index, int32_t* n); int openmc_tally_get_nuclides(int32_t index, int** nuclides, int* n); int openmc_tally_get_scores(int32_t index, int** scores, int* n); + int openmc_tally_get_type(int32_t index, int32_t* type); int openmc_tally_reset(int32_t index); int openmc_tally_results(int32_t index, double** ptr, int shape_[3]); int openmc_tally_set_active(int32_t index, bool active); + int openmc_tally_set_estimator(int32_t index, const char* estimator); int openmc_tally_set_filters(int32_t index, int n, const int32_t* indices); int openmc_tally_set_id(int32_t index, int32_t id); int openmc_tally_set_nuclides(int32_t index, int n, const char** nuclides); int openmc_tally_set_scores(int32_t index, int n, const char** scores); int openmc_tally_set_type(int32_t index, const char* type); + int openmc_tally_update_type(int32_t index, const char* type); int openmc_zernike_filter_get_order(int32_t index, int* order); int openmc_zernike_filter_get_params(int32_t index, double* x, double* y, double* r); int openmc_zernike_filter_set_order(int32_t index, int order); diff --git a/openmc/capi/tally.py b/openmc/capi/tally.py index d4d70af71..e494e3316 100644 --- a/openmc/capi/tally.py +++ b/openmc/capi/tally.py @@ -29,6 +29,9 @@ _dll.openmc_global_tallies.errcheck = _error_handler _dll.openmc_tally_get_active.argtypes = [c_int32, POINTER(c_bool)] _dll.openmc_tally_get_active.restype = c_int _dll.openmc_tally_get_active.errcheck = _error_handler +_dll.openmc_tally_get_estimator.argtypes = [c_int32, POINTER(c_int32)] +_dll.openmc_tally_get_estimator.restype = c_int +_dll.openmc_tally_get_estimator.errcheck = _error_handler _dll.openmc_tally_get_id.argtypes = [c_int32, POINTER(c_int32)] _dll.openmc_tally_get_id.restype = c_int _dll.openmc_tally_get_id.errcheck = _error_handler @@ -47,6 +50,12 @@ _dll.openmc_tally_get_scores.argtypes = [ c_int32, POINTER(POINTER(c_int)), POINTER(c_int)] _dll.openmc_tally_get_scores.restype = c_int _dll.openmc_tally_get_scores.errcheck = _error_handler +_dll.openmc_tally_get_type.argtypes = [c_int32, POINTER(c_int32)] +_dll.openmc_tally_get_type.restype = c_int +_dll.openmc_tally_get_type.errcheck = _error_handler +_dll.openmc_tally_reset.argtypes = [c_int32] +_dll.openmc_tally_reset.restype = c_int +_dll.openmc_tally_reset.errcheck = _error_handler _dll.openmc_tally_results.argtypes = [ c_int32, POINTER(POINTER(c_double)), POINTER(c_int*3)] _dll.openmc_tally_results.restype = c_int @@ -57,6 +66,9 @@ _dll.openmc_tally_set_active.errcheck = _error_handler _dll.openmc_tally_set_filters.argtypes = [c_int32, c_int, POINTER(c_int32)] _dll.openmc_tally_set_filters.restype = c_int _dll.openmc_tally_set_filters.errcheck = _error_handler +_dll.openmc_tally_set_estimator.argtypes = [c_int32, c_char_p] +_dll.openmc_tally_set_estimator.restype = c_int +_dll.openmc_tally_set_estimator.errcheck = _error_handler _dll.openmc_tally_set_id.argtypes = [c_int32, c_int32] _dll.openmc_tally_set_id.restype = c_int _dll.openmc_tally_set_id.errcheck = _error_handler @@ -69,6 +81,9 @@ _dll.openmc_tally_set_scores.errcheck = _error_handler _dll.openmc_tally_set_type.argtypes = [c_int32, c_char_p] _dll.openmc_tally_set_type.restype = c_int _dll.openmc_tally_set_type.errcheck = _error_handler +_dll.openmc_tally_update_type.argtypes = [c_int32, c_char_p] +_dll.openmc_tally_update_type.restype = c_int +_dll.openmc_tally_update_type.errcheck = _error_handler _SCORES = { @@ -78,6 +93,12 @@ _SCORES = { -12: 'prompt-nu-fission', -13: 'inverse-velocity', -14: 'fission-q-prompt', -15: 'fission-q-recoverable', -16: 'decay-rate' } +_ESTIMATORS = { + 1: 'analog', 2: 'tracklength', 3: 'collision' +} +_TALLY_TYPES = { + 1: 'volume', 2: 'mesh-surface', 3: 'surface' +} def global_tallies(): @@ -140,6 +161,8 @@ class Tally(_FortranObjectWithID): ---------- id : int ID of the tally + estimator: str + Estimator type of tally (analog, tracklength, collision) filters : list List of tally filters mean : numpy.ndarray @@ -152,6 +175,8 @@ class Tally(_FortranObjectWithID): Array of tally results std_dev : numpy.ndarray An array containing the sample standard deviation for each bin + type : str + Type of tally (volume, mesh_surface, surface) """ __instances = WeakValueDictionary() @@ -190,6 +215,30 @@ class Tally(_FortranObjectWithID): _dll.openmc_tally_get_active(self._index, active) return active.value + @property + def type(self): + type = c_int32() + _dll.openmc_tally_get_type(self._index, type) + return _TALLY_TYPES[type.value] + + @type.setter + def type(self, type): + _dll.openmc_tally_update_type(self._index, type.encode()) + + @property + def estimator(self): + estimator = c_int32() + try: + _dll.openmc_tally_get_estimator(self._index, estimator) + except AllocationError: + return "" + else: + return _ESTIMATORS[estimator.value] + + @estimator.setter + def estimator(self, estimator): + _dll.openmc_tally_set_estimator(self._index, estimator.encode()) + @active.setter def active(self, active): _dll.openmc_tally_set_active(self._index, active) @@ -302,6 +351,9 @@ class Tally(_FortranObjectWithID): return std_dev + def reset(self): + _dll.openmc_tally_reset(self._index) + def ci_width(self, alpha=0.05): """Confidence interval half-width based on a Student t distribution diff --git a/src/api.F90 b/src/api.F90 index f7e896b7c..61cc6150c 100644 --- a/src/api.F90 +++ b/src/api.F90 @@ -62,6 +62,7 @@ module openmc_api public :: openmc_get_nuclide_index public :: openmc_get_seed public :: openmc_get_tally_index + public :: openmc_get_tally_next_id public :: openmc_global_tallies public :: openmc_hard_reset public :: openmc_init_f @@ -85,17 +86,21 @@ module openmc_api public :: openmc_simulation_init public :: openmc_source_bank public :: openmc_source_set_strength + public :: openmc_tally_get_estimator public :: openmc_tally_get_id public :: openmc_tally_get_filters public :: openmc_tally_get_n_realizations public :: openmc_tally_get_nuclides public :: openmc_tally_get_scores + public :: openmc_tally_get_type public :: openmc_tally_results + public :: openmc_tally_set_estimator public :: openmc_tally_set_filters public :: openmc_tally_set_id public :: openmc_tally_set_nuclides public :: openmc_tally_set_scores public :: openmc_tally_set_type + public :: openmc_tally_update_type contains diff --git a/src/cmfd_input.F90 b/src/cmfd_input.F90 index c1965b220..33cd01a9e 100644 --- a/src/cmfd_input.F90 +++ b/src/cmfd_input.F90 @@ -262,6 +262,7 @@ contains integer(C_INT) :: err integer :: i_filt ! index in filters array integer :: filt_id + integer :: tally_id integer :: iarray3(3) ! temp integer array real(8) :: rarray3(3) ! temp double array real(C_DOUBLE), allocatable :: energies(:) @@ -434,15 +435,12 @@ contains do i = 1, size(cmfd_tallies) ! Allocate tally err = openmc_tally_set_type(i_start + i - 1, C_CHAR_'generic' // C_NULL_CHAR) + call openmc_get_tally_next_id(tally_id) + err = openmc_tally_set_id(i_start + i - 1, tally_id) ! Point t to tally variable associate (t => cmfd_tallies(i) % obj) - ! Set reset property - if (check_for_node(root, "reset")) then - call get_node_value(root, "reset", t % reset) - end if - ! Set the incoming energy mesh filter index in the tally find_filter ! array n_filter = 1 @@ -464,10 +462,10 @@ contains t % name = "CMFD flux, total" ! Set tally estimator to analog - t % estimator = ESTIMATOR_ANALOG + err = openmc_tally_set_estimator(i_start + i - 1, C_CHAR_'analog' // C_NULL_CHAR) ! Set tally type to volume - t % type = TALLY_VOLUME + err = openmc_tally_update_type(i_start + i - 1, C_CHAR_'volume' // C_NULL_CHAR) ! Allocate and set filters allocate(filter_indices(n_filter)) @@ -492,10 +490,10 @@ contains t % name = "CMFD neutron production" ! Set tally estimator to analog - t % estimator = ESTIMATOR_ANALOG + err = openmc_tally_set_estimator(i_start + i - 1, C_CHAR_'analog' // C_NULL_CHAR) ! Set tally type to volume - t % type = TALLY_VOLUME + err = openmc_tally_update_type(i_start + i - 1, C_CHAR_'volume' // C_NULL_CHAR) ! Set the incoming energy mesh filter index in the tally find_filter ! array @@ -527,7 +525,7 @@ contains t % name = "CMFD surface currents" ! Set tally estimator to analog - t % estimator = ESTIMATOR_ANALOG + err = openmc_tally_set_estimator(i_start + i - 1, C_CHAR_'analog' // C_NULL_CHAR) ! Allocate and set filters allocate(filter_indices(n_filter)) @@ -544,17 +542,17 @@ contains ! Set macro bins t % score_bins(1) = SCORE_CURRENT - t % type = TALLY_MESH_SURFACE + err = openmc_tally_update_type(i_start + i - 1, C_CHAR_'mesh-surface' // C_NULL_CHAR) else if (i == 4) then ! Set name t % name = "CMFD P1 scatter" ! Set tally estimator to analog - t % estimator = ESTIMATOR_ANALOG + err = openmc_tally_set_estimator(i_start + i - 1, C_CHAR_'analog' // C_NULL_CHAR) ! Set tally type to volume - t % type = TALLY_VOLUME + err = openmc_tally_update_type(i_start + i - 1, C_CHAR_'volume' // C_NULL_CHAR) ! Allocate and set filters n_filter = 2 diff --git a/src/input_xml.F90 b/src/input_xml.F90 index da33a6627..a6db11c42 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -1960,6 +1960,7 @@ contains integer :: k ! another loop index integer :: l ! loop over bins integer :: filter_id ! user-specified identifier for filter + integer :: tally_id ! user-specified identifier for filter integer :: i_filt ! index in filters array integer :: i_elem ! index of entry in dictionary integer :: n ! size of arrays in mesh specification @@ -2169,15 +2170,15 @@ contains ! Copy tally id if (check_for_node(node_tal, "id")) then - call get_node_value(node_tal, "id", t % id) + call get_node_value(node_tal, "id", tally_id) else call fatal_error("Must specify id for tally in tally XML file.") end if ! Check to make sure 'id' hasn't been used - if (tally_dict % has(t % id)) then + if (tally_dict % has(tally_id)) then call fatal_error("Two or more tallies use the same unique ID: " & - // to_str(t % id)) + // to_str(tally_id)) end if ! Copy tally name @@ -2216,7 +2217,7 @@ contains else call fatal_error("Could not find filter " & // trim(to_str(temp_filter(j))) // " specified on tally " & - // trim(to_str(t % id))) + // trim(to_str(tally_id))) end if ! Store the index of the filter @@ -2270,7 +2271,7 @@ contains if (.not. nuclide_dict % has(word)) then call fatal_error("Could not find the nuclide " & // trim(word) // " specified in tally " & - // trim(to_str(t % id)) // " in any material.") + // trim(to_str(tally_id)) // " in any material.") end if ! Set bin to index in nuclides array @@ -2580,7 +2581,7 @@ contains if (t % score_bins(j) == t % score_bins(k)) then call fatal_error("Duplicate score of type '" // trim(& reaction_name(t % score_bins(j))) // "' found in tally " & - // trim(to_str(t % id))) + // trim(to_str(tally_id))) end if end do end do @@ -2627,7 +2628,7 @@ contains end if else call fatal_error("No specified on tally " & - // trim(to_str(t % id)) // ".") + // trim(to_str(tally_id)) // ".") end if ! Check for a tally derivative. @@ -2650,7 +2651,7 @@ contains if (j == size(tally_derivs)) then call fatal_error("Could not find derivative " & // trim(to_str(t % deriv)) // " specified on tally " & - // trim(to_str(t % id))) + // trim(to_str(tally_id))) end if end do @@ -2658,7 +2659,7 @@ contains .or. tally_derivs(t % deriv) % variable == DIFF_TEMPERATURE) then if (any(t % nuclide_bins == -1)) then if (t % find_filter(FILTER_ENERGYOUT) > 0) then - call fatal_error("Error on tally " // trim(to_str(t % id)) & + call fatal_error("Error on tally " // trim(to_str(tally_id)) & // ": Cannot use a 'nuclide_density' or 'temperature' & &derivative on a tally with an outgoing energy filter and & &'total' nuclide rate. Instead, tally each nuclide in the & @@ -2735,7 +2736,7 @@ contains temp_str = to_lower(temp_str) else call fatal_error("Must specify trigger type for tally " // & - trim(to_str(t % id)) // " in tally XML file.") + trim(to_str(tally_id)) // " in tally XML file.") end if ! Get the convergence threshold for the trigger @@ -2743,7 +2744,7 @@ contains call get_node_value(node_trigger, "threshold", threshold) else call fatal_error("Must specify trigger threshold for tally " // & - trim(to_str(t % id)) // " in tally XML file.") + trim(to_str(tally_id)) // " in tally XML file.") end if ! Get list scores for this trigger @@ -2787,7 +2788,7 @@ contains t % triggers(trig_ind) % type = RELATIVE_ERROR case default call fatal_error("Unknown trigger type " // & - trim(temp_str) // " in tally " // trim(to_str(t % id))) + trim(temp_str) // " in tally " // trim(to_str(tally_id))) end select ! Store the trigger convergence threshold @@ -2808,7 +2809,7 @@ contains ! Check if an invalid score was set for the trigger if (t % triggers(trig_ind) % score_index == 0) then call fatal_error("The trigger score " // trim(score_name) // & - " is not set for tally " // trim(to_str(t % id))) + " is not set for tally " // trim(to_str(tally_id))) end if ! Store the trigger convergence threshold @@ -2824,7 +2825,7 @@ contains t % triggers(trig_ind) % type = RELATIVE_ERROR case default call fatal_error("Unknown trigger type " // trim(temp_str) // & - " in tally " // trim(to_str(t % id))) + " in tally " // trim(to_str(tally_id))) end select ! Increment the overall trigger index @@ -2856,7 +2857,7 @@ contains ! tally needs post-collision information if (t % estimator == ESTIMATOR_ANALOG) then call fatal_error("Cannot use track-length estimator for tally " & - // to_str(t % id)) + // to_str(tally_id)) end if ! Set estimator to track-length estimator @@ -2867,7 +2868,7 @@ contains ! tally needs post-collision information if (t % estimator == ESTIMATOR_ANALOG) then call fatal_error("Cannot use collision estimator for tally " & - // to_str(t % id)) + // to_str(tally_id)) end if ! Set estimator to collision estimator @@ -2879,8 +2880,8 @@ contains end select end if - ! Add tally to dictionary - call tally_dict % set(t % id, i) + ! Set tally id + err = openmc_tally_set_id(i_start + i - 1, tally_id) end associate end do READ_TALLIES diff --git a/src/tallies/tally_header.F90 b/src/tallies/tally_header.F90 index c64fc9d5a..d22a53c6a 100644 --- a/src/tallies/tally_header.F90 +++ b/src/tallies/tally_header.F90 @@ -22,20 +22,25 @@ module tally_header public :: free_memory_tally public :: openmc_extend_tallies public :: openmc_get_tally_index + public :: openmc_get_tally_next_id public :: openmc_global_tallies public :: openmc_tally_get_active + public :: openmc_tally_get_estimator public :: openmc_tally_get_id public :: openmc_tally_get_filters public :: openmc_tally_get_n_realizations public :: openmc_tally_get_nuclides public :: openmc_tally_get_scores + public :: openmc_tally_get_type public :: openmc_tally_reset public :: openmc_tally_results public :: openmc_tally_set_active + public :: openmc_tally_set_estimator public :: openmc_tally_set_filters public :: openmc_tally_set_id public :: openmc_tally_set_nuclides public :: openmc_tally_set_scores + public :: openmc_tally_update_type !=============================================================================== ! TALLYOBJECT describes a user-specified tally. The region of phase space to @@ -86,9 +91,6 @@ module tally_header integer :: total_score_bins real(C_DOUBLE), allocatable :: results(:,:,:) - ! reset property - allows a tally to be reset after every batch - logical :: reset = .false. - ! Number of realizations of tally random variables integer :: n_realizations = 0 @@ -118,6 +120,10 @@ module tally_header ! Dictionary that maps user IDs to indices in 'tallies' type(DictIntInt), public :: tally_dict + ! The largest tally ID that has been specified in the system. This is useful + ! in case the code needs to find an ID for a new tally. + integer :: largest_tally_id + ! Global tallies ! 1) collision estimate of k-eff ! 2) absorption estimate of k-eff @@ -403,6 +409,7 @@ contains n_tallies = 0 if (allocated(tallies)) deallocate(tallies) call tally_dict % clear() + largest_tally_id = 0 if (allocated(global_tallies)) deallocate(global_tallies) @@ -505,6 +512,22 @@ contains end function openmc_tally_get_active + function openmc_tally_get_estimator(index, estimator) result(err) bind(C) + ! Return the type of estimator of a tally + integer(C_INT32_T), value :: index + integer(C_INT32_T), intent(out) :: estimator + integer(C_INT) :: err + + if (index >= 1 .and. index <= size(tallies)) then + estimator = tallies(index) % obj % estimator + err = 0 + else + err = E_OUT_OF_BOUNDS + call set_errmsg('Index in tallies array is out of bounds.') + end if + end function openmc_tally_get_estimator + + function openmc_tally_get_id(index, id) result(err) bind(C) ! Return the ID of a tally integer(C_INT32_T), value :: index @@ -612,6 +635,22 @@ contains end function openmc_tally_get_scores + function openmc_tally_get_type(index, type) result(err) bind(C) + ! Return the type of a tally + integer(C_INT32_T), value :: index + integer(C_INT32_T), intent(out) :: type + integer(C_INT) :: err + + if (index >= 1 .and. index <= size(tallies)) then + type = tallies(index) % obj % type + err = 0 + else + err = E_OUT_OF_BOUNDS + call set_errmsg('Index in tallies array is out of bounds.') + end if + end function openmc_tally_get_type + + function openmc_tally_reset(index) result(err) bind(C) ! Reset tally results and number of realizations integer(C_INT32_T), intent(in), value :: index @@ -656,6 +695,37 @@ contains end function openmc_tally_results + function openmc_tally_set_estimator(index, estimator) result(err) bind(C) + ! Set the type of estimator a tally + integer(C_INT32_T), value, intent(in) :: index + character(kind=C_CHAR), intent(in) :: estimator(*) + integer(C_INT) :: err + + character(:), allocatable :: estimator_ + + ! Convert C string to Fortran string + estimator_ = to_f_string(estimator) + + err = 0 + if (index >= 1 .and. index <= size(tallies)) then + select case (estimator_) + case ('analog') + tallies(index) % obj % estimator = ESTIMATOR_ANALOG + case ('tracklength') + tallies(index) % obj % estimator = ESTIMATOR_TRACKLENGTH + case ('collision') + tallies(index) % obj % estimator = ESTIMATOR_COLLISION + case default + err = E_UNASSIGNED + call set_errmsg("Unknown tally estimator: " // trim(estimator_)) + end select + else + err = E_OUT_OF_BOUNDS + call set_errmsg("Index in tally array is out of bounds.") + end if + end function openmc_tally_set_estimator + + function openmc_tally_set_filters(index, n, filter_indices) result(err) bind(C) ! Set the list of filters for a tally integer(C_INT32_T), value, intent(in) :: index @@ -709,6 +779,7 @@ contains if (allocated(tallies(index) % obj)) then tallies(index) % obj % id = id call tally_dict % set(id, index) + if (id > largest_tally_id) largest_tally_id = id err = 0 else @@ -942,4 +1013,43 @@ contains end if end function openmc_tally_set_scores + + function openmc_tally_update_type(index, type) result(err) bind(C) + ! Update the type of a tally that is already allocated + integer(C_INT32_T), value, intent(in) :: index + character(kind=C_CHAR), intent(in) :: type(*) + integer(C_INT) :: err + + character(:), allocatable :: type_ + + ! Convert C string to Fortran string + type_ = to_f_string(type) + + err = 0 + if (index >= 1 .and. index <= size(tallies)) then + select case (type_) + case ('volume') + tallies(index) % obj % type = TALLY_VOLUME + case ('mesh-surface') + tallies(index) % obj % type = TALLY_MESH_SURFACE + case ('surface') + tallies(index) % obj % type = TALLY_SURFACE + case default + err = E_UNASSIGNED + call set_errmsg("Unknown tally type: " // trim(type_)) + end select + else + err = E_OUT_OF_BOUNDS + call set_errmsg("Index in tally array is out of bounds.") + end if + end function openmc_tally_update_type + + + subroutine openmc_get_tally_next_id(id) bind(C) + ! Returns an ID number that has not been used by any other tallies. + integer(C_INT32_T), intent(out) :: id + + id = largest_tally_id + 1 + end subroutine openmc_get_tally_next_id + end module tally_header From 8106329fe8dd39a927cd2289465828fee539123c Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 23 Jul 2018 09:50:18 -0500 Subject: [PATCH 26/56] Add material volumes to XML and Material type --- docs/source/io_formats/materials.rst | 6 ++++ include/openmc.h | 2 ++ openmc/material.py | 5 +++ src/cell.cpp | 6 ++-- src/error.h | 31 +++++++++++++---- src/input_xml.F90 | 4 +-- src/material.cpp | 52 ++++++++++++++++++++++++++-- src/material.h | 1 + src/material_header.F90 | 10 +++++- src/relaxng/materials.rnc | 10 ++++-- src/relaxng/materials.rng | 39 ++++++++++++++++----- src/summary.F90 | 9 ++++- 12 files changed, 146 insertions(+), 29 deletions(-) diff --git a/docs/source/io_formats/materials.rst b/docs/source/io_formats/materials.rst index 7875eb330..322b9c999 100644 --- a/docs/source/io_formats/materials.rst +++ b/docs/source/io_formats/materials.rst @@ -50,6 +50,12 @@ Each ``material`` element can have the following attributes or sub-elements: *Default*: "" + :depletable: + Boolean value indicating whether the material is depletable. + + :volume: + Volume of the material in cm^3. + :temperature: An element with no attributes which is used to set the default temperature of the material in Kelvin. diff --git a/include/openmc.h b/include/openmc.h index 1f919d7c6..898be784e 100644 --- a/include/openmc.h +++ b/include/openmc.h @@ -56,9 +56,11 @@ extern "C" { int openmc_material_add_nuclide(int32_t index, const char name[], double density); int openmc_material_get_densities(int32_t index, int** nuclides, double** densities, int* n); int openmc_material_get_id(int32_t index, int32_t* id); + int openmc_material_get_volume(int32_t index, double* volume); int openmc_material_set_density(int32_t index, double density); int openmc_material_set_densities(int32_t index, int n, const char** name, const double* density); int openmc_material_set_id(int32_t index, int32_t id); + int openmc_material_set_volume(int32_t index, double volume); int openmc_material_filter_get_bins(int32_t index, int32_t** bins, int32_t* n); int openmc_material_filter_set_bins(int32_t index, int32_t n, const int32_t* bins); int openmc_mesh_filter_get_mesh(int32_t index, int32_t* index_mesh); diff --git a/openmc/material.py b/openmc/material.py index dac2fe14a..bd31fbd23 100644 --- a/openmc/material.py +++ b/openmc/material.py @@ -284,6 +284,8 @@ class Material(IDManagerMixin): # Create the Material material = cls(mat_id, name) material.depletable = bool(group.attrs['depletable']) + if 'volume' in group.attrs: + material.volume = group.attrs['volume'] # Read the names of the S(a,b) tables for this Material and add them if 'sab_names' in group: @@ -833,6 +835,9 @@ class Material(IDManagerMixin): if self._depletable: element.set("depletable", "true") + if self._volume: + element.set("volume", str(self._volume)) + # Create temperature XML subelement if self.temperature is not None: subelement = ET.SubElement(element, "temperature") diff --git a/src/cell.cpp b/src/cell.cpp index d26fa8414..fb364cfdf 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -493,7 +493,7 @@ openmc_cell_get_fill(int32_t index, int* type, int32_t** indices, int32_t* n) *n = 1; } } else { - strcpy(openmc_err_msg, "Index in cells array is out of bounds."); + set_errmsg("Index in cells array is out of bounds."); return OPENMC_E_OUT_OF_BOUNDS; } return 0; @@ -517,7 +517,7 @@ openmc_cell_set_fill(int32_t index, int type, int32_t n, //TODO: off-by-one c.material.push_back(i_mat - 1); } else { - strcpy(openmc_err_msg, "Index in materials array is out of bounds."); + set_errmsg("Index in materials array is out of bounds."); return OPENMC_E_OUT_OF_BOUNDS; } } @@ -528,7 +528,7 @@ openmc_cell_set_fill(int32_t index, int type, int32_t n, c.type = FILL_LATTICE; } } else { - strcpy(openmc_err_msg, "Index in cells array is out of bounds."); + set_errmsg("Index in cells array is out of bounds."); return OPENMC_E_OUT_OF_BOUNDS; } return 0; diff --git a/src/error.h b/src/error.h index 356dfd801..7d015d614 100644 --- a/src/error.h +++ b/src/error.h @@ -5,6 +5,7 @@ #include #include +#include "openmc.h" namespace openmc { @@ -14,20 +15,38 @@ extern "C" void warning_from_c(const char* message, int message_len); extern "C" void write_message_from_c(const char* message, int message_len, int level); -inline -void fatal_error(const char *message) +inline void +set_errmsg(const char* message) { - fatal_error_from_c(message, strlen(message)); + std::strcpy(openmc_err_msg, message); +} + +inline void +set_errmsg(const std::string& message) +{ + std::strcpy(openmc_err_msg, message.c_str()); +} + +inline void +set_errmsg(const std::stringstream& message) +{ + std::strcpy(openmc_err_msg, message.str().c_str()); } inline -void fatal_error(const std::string &message) +void fatal_error(const char* message) +{ + fatal_error_from_c(message, std::strlen(message)); +} + +inline +void fatal_error(const std::string& message) { fatal_error_from_c(message.c_str(), message.length()); } inline -void fatal_error(const std::stringstream &message) +void fatal_error(const std::stringstream& message) { fatal_error(message.str()); } @@ -47,7 +66,7 @@ void warning(const std::stringstream& message) inline void write_message(const char* message, int level) { - write_message_from_c(message, strlen(message), level); + write_message_from_c(message, std::strlen(message), level); } inline diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 23472e21a..ca86ae2ae 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -1534,9 +1534,7 @@ contains ! Check if material is depletable if (check_for_node(node_mat, "depletable")) then - call get_node_value(node_mat, "depletable", temp_str) - if (to_lower(temp_str) == "true" .or. temp_str == "1") & - mat % depletable = .true. + call get_node_value(node_mat, "depletable", mat % depletable) end if ! Copy material name diff --git a/src/material.cpp b/src/material.cpp index c9ef47f07..409908e67 100644 --- a/src/material.cpp +++ b/src/material.cpp @@ -20,13 +20,17 @@ std::unordered_map material_map; // Material implementation //============================================================================== -Material::Material(pugi::xml_node material_node) +Material::Material(pugi::xml_node node) { - if (check_for_node(material_node, "id")) { - id = std::stoi(get_node_value(material_node, "id")); + if (check_for_node(node, "id")) { + id = std::stoi(get_node_value(node, "id")); } else { fatal_error("Must specify id of material in materials XML file."); } + + if (check_for_node(node, "volume")) { + volume_ = std::stod(get_node_value(node, "volume")); + } } //============================================================================== @@ -56,6 +60,48 @@ read_materials(pugi::xml_node* node) } } +//============================================================================== +// C API +//============================================================================== + +extern "C" int +openmc_material_get_volume(int32_t index, double* volume) +{ + if (index >= 1 && index <= global_materials.size()) { + Material* m = global_materials[index - 1]; + if (m->volume_ >= 0.0) { + *volume = m->volume_; + return 0; + } else { + std::stringstream msg; + msg << "Volume for material with ID=" << m->id << " not set."; + set_errmsg(msg); + return OPENMC_E_UNASSIGNED; + } + } else { + set_errmsg("Index in materials array is out of bounds."); + return OPENMC_E_OUT_OF_BOUNDS; + } +} + +extern "C" int +openmc_material_set_volume(int32_t index, double volume) +{ + if (index >= 1 && index <= global_materials.size()) { + Material* m = global_materials[index - 1]; + if (volume >= 0.0) { + m->volume_ = volume; + return 0; + } else { + set_errmsg("Volume must be non-negative"); + return OPENMC_E_INVALID_ARGUMENT; + } + } else { + set_errmsg("Index in materials array is out of bounds."); + return OPENMC_E_OUT_OF_BOUNDS; + } +} + //============================================================================== // Fortran compatibility functions //============================================================================== diff --git a/src/material.h b/src/material.h index 0a9a099a4..c6337f1e2 100644 --- a/src/material.h +++ b/src/material.h @@ -25,6 +25,7 @@ class Material { public: int32_t id; //!< Unique ID + double volume_ {-1.0}; //!< Volume in [cm^3] Material() {}; diff --git a/src/material_header.F90 b/src/material_header.F90 index a9de08ec4..33195497c 100644 --- a/src/material_header.F90 +++ b/src/material_header.F90 @@ -24,6 +24,7 @@ module material_header public :: openmc_material_add_nuclide public :: openmc_material_get_id public :: openmc_material_get_densities + public :: openmc_material_get_volume public :: openmc_material_set_density public :: openmc_material_set_densities public :: openmc_material_set_id @@ -51,9 +52,16 @@ module material_header end subroutine material_set_id_c subroutine extend_materials_c(n) bind(C) - import C_INT32_t + import C_INT32_T integer(C_INT32_T), intent(in), value :: n end subroutine extend_materials_c + + function openmc_material_get_volume(index, volume) result(err) bind(C) + import C_INT32_T, C_DOUBLE, C_INT + integer(C_INT32_T), value :: index + real(C_DOUBLE), intent(out) :: volume + integer(C_INT) :: err + end function openmc_material_get_volume end interface !=============================================================================== diff --git a/src/relaxng/materials.rnc b/src/relaxng/materials.rnc index c7e0fbf86..d2a84418e 100644 --- a/src/relaxng/materials.rnc +++ b/src/relaxng/materials.rnc @@ -1,10 +1,14 @@ element materials { element material { (element id { xsd:int } | attribute id { xsd:int }) & - (element name { xsd:string { maxLength="52" } } | - attribute name { xsd:string { maxLength="52" } })? & - element temperature { xsd:double }? & + (element name { xsd:string } | attribute name { xsd:string })? & + + (element depletable { xsd:boolean } | attribute depletable { xsd:boolean })? & + + (element volume { xsd:double } | attribute volume { xsd:double })? & + + (element temperature { xsd:double } | attribute temperature { xsd:double })? & element density { (element value { xsd:double } | attribute value { xsd:double })? & diff --git a/src/relaxng/materials.rng b/src/relaxng/materials.rng index 342260be8..90d6ec5c6 100644 --- a/src/relaxng/materials.rng +++ b/src/relaxng/materials.rng @@ -15,21 +15,42 @@ - - 52 - + - - 52 - + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/summary.F90 b/src/summary.F90 index 13bc42663..ddc64f707 100644 --- a/src/summary.F90 +++ b/src/summary.F90 @@ -5,7 +5,7 @@ module summary use error, only: write_message use geometry_header use hdf5_interface - use material_header, only: Material, n_materials + use material_header, only: Material, n_materials, openmc_material_get_volume use mesh_header, only: RegularMesh use message_passing use mgxs_interface @@ -315,8 +315,10 @@ contains integer :: j integer :: k integer :: n + integer :: err character(20), allocatable :: nuc_names(:) character(20), allocatable :: macro_names(:) + real(8) :: volume real(8), allocatable :: nuc_densities(:) integer :: num_nuclides integer :: num_macros @@ -341,6 +343,11 @@ contains call write_attribute(material_group, "depletable", 0) end if + err = openmc_material_get_volume(i, volume) + if (err == 0 .and. volume > ZERO) then + call write_attribute(material_group, "volume", volume) + end if + ! Write name for this material call write_dataset(material_group, "name", m % name) From c769c35c302a882f4bb326c8310c22a0a8895886 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Fri, 17 Aug 2018 07:28:47 -0500 Subject: [PATCH 27/56] Add Python bindings to C API material volume funcs --- openmc/capi/material.py | 21 ++++++++++++++++++++- tests/unit_tests/test_capi.py | 4 ++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/openmc/capi/material.py b/openmc/capi/material.py index a6c29a375..9548c0b79 100644 --- a/openmc/capi/material.py +++ b/openmc/capi/material.py @@ -5,7 +5,7 @@ from weakref import WeakValueDictionary import numpy as np from numpy.ctypeslib import as_array -from openmc.exceptions import AllocationError, InvalidIDError +from openmc.exceptions import AllocationError, InvalidIDError, OpenMCError from . import _dll, Nuclide from .core import _FortranObjectWithID from .error import _error_handler @@ -32,6 +32,9 @@ _dll.openmc_material_get_densities.argtypes = [ POINTER(c_int)] _dll.openmc_material_get_densities.restype = c_int _dll.openmc_material_get_densities.errcheck = _error_handler +_dll.openmc_material_get_volume.argtypes = [c_int32, POINTER(c_double)] +_dll.openmc_material_get_volume.restype = c_int +_dll.openmc_material_get_volume.errcheck = _error_handler _dll.openmc_material_set_density.argtypes = [c_int32, c_double] _dll.openmc_material_set_density.restype = c_int _dll.openmc_material_set_density.errcheck = _error_handler @@ -42,6 +45,9 @@ _dll.openmc_material_set_densities.errcheck = _error_handler _dll.openmc_material_set_id.argtypes = [c_int32, c_int32] _dll.openmc_material_set_id.restype = c_int _dll.openmc_material_set_id.errcheck = _error_handler +_dll.openmc_material_set_volume.argtypes = [c_int32, c_double] +_dll.openmc_material_set_volume.restype = c_int +_dll.openmc_material_set_volume.errcheck = _error_handler class Material(_FortranObjectWithID): @@ -113,6 +119,19 @@ class Material(_FortranObjectWithID): def id(self, mat_id): _dll.openmc_material_set_id(self._index, mat_id) + @property + def volume(self): + volume = c_double() + try: + _dll.openmc_material_get_volume(self._index, volume) + except OpenMCError: + return None + return volume.value + + @volume.setter + def volume(self, volume): + _dll.openmc_material_set_volume(self._index, volume) + @property def nuclides(self): return self._get_densities()[0] diff --git a/tests/unit_tests/test_capi.py b/tests/unit_tests/test_capi.py index 92ca0aca9..fa348f59b 100644 --- a/tests/unit_tests/test_capi.py +++ b/tests/unit_tests/test_capi.py @@ -101,6 +101,10 @@ def test_material(capi_init): m.set_densities(m.nuclides, test_dens) assert m.densities == pytest.approx(test_dens) + assert m.volume is None + m.volume = 10.0 + assert m.volume == 10.0 + rho = 2.25e-2 m.set_density(rho) assert sum(m.densities) == pytest.approx(rho) From 26c54e5483203ba8df9245791b674828300372ba Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 8 May 2017 09:24:40 -0500 Subject: [PATCH 28/56] Add Material.from_xml_element and Materials.from_xml classmethods --- openmc/material.py | 84 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/openmc/material.py b/openmc/material.py index dac2fe14a..c8d4c9fd0 100644 --- a/openmc/material.py +++ b/openmc/material.py @@ -907,6 +907,58 @@ class Material(IDManagerMixin): return element + @classmethod + def from_xml_element(cls, elem): + """Generate material from an XML element + + Parameters + ---------- + elem : xml.etree.ElementTree.Element + XML element + + Returns + ------- + openmc.Material + Material generated from XML element + + """ + mat_id = int(elem.get('id')) + mat = cls(mat_id) + mat.name = elem.get('name') + mat.temperature = elem.get('temperature') + mat.depletable = bool(elem.get('depletable')) + + # Get each nuclide + for nuclide in elem.findall('nuclide'): + name = nuclide.attrib['name'] + if 'ao' in nuclide.attrib: + mat.add_nuclide(name, float(nuclide.attrib['ao'])) + elif 'wo' in nuclide.attrib: + mat.add_nuclide(name, float(nuclide.attrib['wo']), 'wo') + + # Get each element + for element in elem.findall('element'): + name = element.attrib['name'] + if 'ao' in element.attrib: + mat.add_element(name, float(element.attrib['ao'])) + elif 'wo' in element.attrib: + mat.add_element(name, float(element.attrib['wo']), 'wo') + + # Get each S(a,b) table + for sab in elem.findall('sab'): + mat.add_s_alpha_beta(sab.get('name')) + + # Get total material density + density = elem.find('density') + units = density.get('units') + if units == 'sum': + mat.set_density(units) + else: + value = float(density.get('value')) + mat.set_density(units, value) + + return mat + class Materials(cv.CheckedList): """Collection of Materials used for an OpenMC simulation. @@ -1031,3 +1083,35 @@ class Materials(cv.CheckedList): # Write the XML Tree to the materials.xml file tree = ET.ElementTree(root_element) tree.write(path, xml_declaration=True, encoding='utf-8') + + @classmethod + def from_xml(cls, path='materials.xml'): + """Generate materials collection from XML file + + Parameters + ---------- + path : str, optional + Path to materials XML file + + Returns + ------- + openmc.Materials + Materials collection + + """ + tree = ET.parse(path) + root = tree.getroot() + + materials = cls() + for material in root.findall('material'): + materials.append(Material.from_xml_element(material)) + + xs = tree.find('cross_sections') + if xs is not None: + materials.cross_sections = xs.text + + mpl = tree.find('multipole_library') + if mpl is not None: + materials.multipole_library = mpl.text + + return materials From b9ade1e7581ea99f5469614047089cd79d7f9db8 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Fri, 10 Aug 2018 11:46:14 -0500 Subject: [PATCH 29/56] Fix input for lattice_hex test --- .../regression_tests/lattice_hex/geometry.xml | 44 +++++++++---------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/tests/regression_tests/lattice_hex/geometry.xml b/tests/regression_tests/lattice_hex/geometry.xml index cfe39849c..fa6a18ee1 100644 --- a/tests/regression_tests/lattice_hex/geometry.xml +++ b/tests/regression_tests/lattice_hex/geometry.xml @@ -7,42 +7,42 @@ - - - - - - + + + + + + - - - - - - - + + + + + + + - - - - - + + + + + - - - + + + - + From f42a75a9e14c9898ed8b5f15aa5f6f4c66aa789a Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Fri, 10 Aug 2018 11:46:51 -0500 Subject: [PATCH 30/56] Add Geometry.from_xml() capability --- openmc/geometry.py | 189 ++++++++++++++++++++++++++++++++++++++++++++- openmc/material.py | 11 ++- openmc/surface.py | 130 ++++++++++++++++++------------- 3 files changed, 273 insertions(+), 57 deletions(-) diff --git a/openmc/geometry.py b/openmc/geometry.py index 1ee93dfd6..471de202b 100644 --- a/openmc/geometry.py +++ b/openmc/geometry.py @@ -1,8 +1,10 @@ -from collections import OrderedDict +from collections import OrderedDict, defaultdict from collections.abc import Iterable from copy import deepcopy from xml.etree import ElementTree as ET +import numpy as np + import openmc from openmc.clean_xml import clean_xml_indentation from openmc.checkvalue import check_type @@ -98,6 +100,191 @@ class Geometry(object): tree = ET.ElementTree(root_element) tree.write(path, xml_declaration=True, encoding='utf-8') + @classmethod + def from_xml(cls, path='geometry.xml', materials=None): + """Generate geometry from XML file + + Parameters + ---------- + path : str, optional + Path to geometry XML file + materials : openmc.Materials or None + Materials used to assign to cells. If None, an attempt is made to + generate it from the materials.xml file. + + Returns + ------- + openmc.Geometry + Geometry object + + """ + # Helper function to get value from an attribute/element + def get(elem, name, default=None): + if name in elem.attrib: + return elem.get(name, default) + else: + child = elem.find(name) + return child.text if child is not None else default + + # Helper function for keeping a cache of Universe instances + universes = {} + def get_universe(univ_id): + if univ_id not in universes: + univ = openmc.Universe(univ_id) + universes[univ_id] = univ + return universes[univ_id] + + tree = ET.parse(path) + root = tree.getroot() + + # Get surfaces + surfaces = {} + periodic = {} + for surface in root.findall('surface'): + s = openmc.Surface.from_xml_element(surface) + surfaces[s.id] = s + + # Check for periodic surface + other_id = get(surface, 'periodic_surface_id') + if other_id is not None: + periodic[s.id] = int(other_id) + + # Apply periodic surfaces + for s1, s2 in periodic.items(): + surfaces[s1].periodic_surface = surfaces[s2] + + # Dictionary that maps each universe to a list of cells/lattices that + # contain it (needed to determine which universe is the root) + child_of = defaultdict(list) + + for elem in root.findall('lattice'): + lat_id = int(get(elem, 'id')) + name = get(elem, 'name') + lat = openmc.RectLattice(lat_id, name) + lat.lower_left = [float(i) for i in get(elem, 'lower_left').split()] + lat.pitch = [float(i) for i in get(elem, 'pitch').split()] + outer = get(elem, 'outer') + if outer is not None: + lat.outer = get_universe(int(outer)) + universes[lat_id] = lat + + # Get array of universes + dimension = get(elem, 'dimension').split() + shape = np.array(dimension, dtype=int)[::-1] + uarray = np.array([get_universe(int(i)) for i in + get(elem, 'universes').split()]) + for u in uarray: + child_of[u].append(lat) + uarray.shape = shape + lat.universes = uarray + + for elem in root.findall('hex_lattice'): + lat_id = int(get(elem, 'id')) + name = get(elem, 'name') + lat = openmc.HexLattice(lat_id, name) + lat.center = [float(i) for i in get(elem, 'center').split()] + lat.pitch = [float(i) for i in get(elem, 'pitch').split()] + outer = get(elem, 'outer') + if outer is not None: + lat.outer = get_universe(int(outer)) + universes[lat_id] = lat + + # Get nested lists of universes + lat._num_rings = n_rings = int(get(elem, 'n_rings')) + lat._num_axial = n_axial = int(get(elem, 'n_axial', 1)) + + # Create empty nested lists for one axial level + univs = [[None for _ in range(max(6*(n_rings - 1 - r), 1))] + for r in range(n_rings)] + if n_axial > 1: + univs = [deepcopy(univs) for i in range(n_axial)] + + # Get flat array of universes numbers + uarray = np.array([get_universe(int(i)) for i in + get(elem, 'universes').split()]) + for u in uarray: + child_of[u].append(lat) + + # Fill nested lists + j = 0 + for z in range(n_axial): + # Get list for a single axial level + axial_level = univs[z] if n_axial > 1 else univs + + # Start iterating from top + x, alpha = 0, n_rings - 1 + while True: + # Set entry in list based on (x,alpha,z) coordinates + _, i_ring, i_within = lat.get_universe_index((x, alpha, z)) + axial_level[i_ring][i_within] = uarray[j] + + # Move to the right + x += 2 + alpha -= 1 + if not lat.is_valid_index((x, alpha, z)): + # Move down in y direction + alpha += x - 1 + x = 1 - x + if not lat.is_valid_index((x, alpha, z)): + # Move to the right + x += 2 + alpha -= 1 + if not lat.is_valid_index((x, alpha, z)): + # Reached the bottom + break + j += 1 + lat.universes = univs + + # Create dictionary to easily look up materials + if materials is None: + materials = openmc.Materials.from_xml() + mats = {str(m.id): m for m in materials} + mats['void'] = None + + for elem in root.findall('cell'): + cell_id = int(get(elem, 'id')) + name = get(elem, 'name') + c = openmc.Cell(cell_id, name) + + # Assign material/distributed materials or fill + mat_text = get(elem, 'material') + if mat_text is not None: + mat_ids = mat_text.split() + if len(mat_ids) > 1: + c.fill = [mats[i] for i in mat_ids] + else: + c.fill = mats[mat_ids[0]] + else: + fill_id = int(get(elem, 'fill')) + c.fill = get_universe(fill_id) + child_of[c.fill].append(c) + + # Assign region + region = get(elem, 'region') + if region is not None: + c.region = openmc.Region.from_expression(region, surfaces) + + # Check for other attributes + t = get(elem, 'temperature') + if t is not None: + c.temperature = float(t) + for key in ('temperature', 'rotation', 'translation'): + value = get(elem, key) + if value is not None: + setattr(c, key, [float(x) for x in value.split()]) + + # Add this cell to appropriate universe + univ_id = int(get(elem, 'universe', 0)) + get_universe(univ_id).add_cell(c) + + # Determine which universe is the root by finding one which is not a + # child of any other object + for u in universes.values(): + if not child_of[u]: + return cls(u) + else: + raise ValueError('Error determining root universe.') + def find(self, point): """Find cells/universes/lattices which contain a given point diff --git a/openmc/material.py b/openmc/material.py index c8d4c9fd0..3d54da31b 100644 --- a/openmc/material.py +++ b/openmc/material.py @@ -946,7 +946,8 @@ class Material(IDManagerMixin): # Get each S(a,b) table for sab in elem.findall('sab'): - mat.add_s_alpha_beta(sab.get('name')) + fraction = float(sab.get('fraction', 1.0)) + mat.add_s_alpha_beta(sab.get('name'), fraction) # Get total material density density = elem.find('density') @@ -957,6 +958,11 @@ class Material(IDManagerMixin): value = float(density.get('value')) mat.set_density(units, value) + # Check for isotropic scattering nuclides + isotropic = elem.find('isotropic') + if isotropic is not None: + mat.isotropic = isotropic.text.split() + return mat @@ -1102,14 +1108,15 @@ class Materials(cv.CheckedList): tree = ET.parse(path) root = tree.getroot() + # Generate each material materials = cls() for material in root.findall('material'): materials.append(Material.from_xml_element(material)) + # Check for cross sections settings xs = tree.find('cross_sections') if xs is not None: materials.cross_sections = xs.text - mpl = tree.find('multipole_library') if mpl is not None: materials.multipole_library = mpl.text diff --git a/openmc/surface.py b/openmc/surface.py index ad5053e37..826ac5cc8 100644 --- a/openmc/surface.py +++ b/openmc/surface.py @@ -59,7 +59,6 @@ class Surface(IDManagerMixin): def __init__(self, surface_id=None, boundary_type='transmission', name=''): self.id = surface_id self.name = name - self._type = '' self.boundary_type = boundary_type # A dictionary of the quadratic surface coefficients @@ -67,10 +66,6 @@ class Surface(IDManagerMixin): # Value - coefficient value self._coefficients = {} - # An ordered list of the coefficient names to export to XML in the - # proper order - self._coeff_keys = [] - def __neg__(self): return Halfspace(self, '-') @@ -203,6 +198,49 @@ class Surface(IDManagerMixin): 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 @@ -324,12 +362,12 @@ class Plane(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=''): super().__init__(surface_id, boundary_type, name=name) - - self._type = 'plane' - self._coeff_keys = ['A', 'B', 'C', 'D'] self._periodic_surface = None self.a = A self.b = B @@ -458,12 +496,12 @@ class XPlane(Plane): """ + _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._type = 'x-plane' - self._coeff_keys = ['x0'] self.x0 = x0 @property @@ -563,13 +601,13 @@ class YPlane(Plane): """ + _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._type = 'y-plane' - self._coeff_keys = ['y0'] self.y0 = y0 @property @@ -669,13 +707,13 @@ class ZPlane(Plane): """ + _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._type = 'z-plane' - self._coeff_keys = ['z0'] self.z0 = z0 @property @@ -774,8 +812,6 @@ class Cylinder(Surface, metaclass=ABCMeta): def __init__(self, surface_id=None, boundary_type='transmission', R=1., name=''): super().__init__(surface_id, boundary_type, name=name) - - self._coeff_keys = ['R'] self.r = R @property @@ -831,12 +867,12 @@ class XCylinder(Cylinder): """ + _type = 'x-cylinder' + _coeff_keys = ('y0', 'z0', 'R') + def __init__(self, surface_id=None, boundary_type='transmission', y0=0., z0=0., R=1., name=''): super().__init__(surface_id, boundary_type, R, name=name) - - self._type = 'x-cylinder' - self._coeff_keys = ['y0', 'z0', 'R'] self.y0 = y0 self.z0 = z0 @@ -953,12 +989,12 @@ class YCylinder(Cylinder): """ + _type = 'y-cylinder' + _coeff_keys = ('x0', 'z0', 'R') + def __init__(self, surface_id=None, boundary_type='transmission', x0=0., z0=0., R=1., name=''): super().__init__(surface_id, boundary_type, R, name=name) - - self._type = 'y-cylinder' - self._coeff_keys = ['x0', 'z0', 'R'] self.x0 = x0 self.z0 = z0 @@ -1075,12 +1111,12 @@ class ZCylinder(Cylinder): """ + _type = 'z-cylinder' + _coeff_keys = ('x0', 'y0', 'R') + def __init__(self, surface_id=None, boundary_type='transmission', x0=0., y0=0., R=1., name=''): super().__init__(surface_id, boundary_type, R, name=name) - - self._type = 'z-cylinder' - self._coeff_keys = ['x0', 'y0', 'R'] self.x0 = x0 self.y0 = y0 @@ -1201,12 +1237,12 @@ class Sphere(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=''): super().__init__(surface_id, boundary_type, name=name) - - self._type = 'sphere' - self._coeff_keys = ['x0', 'y0', 'z0', 'R'] self.x0 = x0 self.y0 = y0 self.z0 = z0 @@ -1348,11 +1384,12 @@ class Cone(Surface, metaclass=ABCMeta): 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=''): super().__init__(surface_id, boundary_type, name=name) - - self._coeff_keys = ['x0', 'y0', 'z0', 'R2'] self.x0 = x0 self.y0 = y0 self.z0 = z0 @@ -1443,12 +1480,7 @@ class XCone(Cone): """ - def __init__(self, surface_id=None, boundary_type='transmission', - x0=0., y0=0., z0=0., R2=1., name=''): - super().__init__(surface_id, boundary_type, x0, y0, - z0, R2, name=name) - - self._type = 'x-cone' + _type = 'x-cone' def evaluate(self, point): """Evaluate the surface equation at a given point. @@ -1519,12 +1551,7 @@ class YCone(Cone): """ - def __init__(self, surface_id=None, boundary_type='transmission', - x0=0., y0=0., z0=0., R2=1., name=''): - super().__init__(surface_id, boundary_type, x0, y0, z0, - R2, name=name) - - self._type = 'y-cone' + _type = 'y-cone' def evaluate(self, point): """Evaluate the surface equation at a given point. @@ -1595,12 +1622,7 @@ class ZCone(Cone): """ - def __init__(self, surface_id=None, boundary_type='transmission', - x0=0., y0=0., z0=0., R2=1., name=''): - super().__init__(surface_id, boundary_type, x0, y0, z0, - R2, name=name) - - self._type = 'z-cone' + _type = 'z-cone' def evaluate(self, point): """Evaluate the surface equation at a given point. @@ -1659,13 +1681,13 @@ class Quadric(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._type = 'quadric' - self._coeff_keys = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'j', 'k'] self.a = a self.b = b self.c = c From c5632794de1d029ad758c3041bf978adf0820596 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Fri, 17 Aug 2018 10:35:24 -0500 Subject: [PATCH 31/56] Add tests for from_xml methods --- openmc/material.py | 8 ----- tests/unit_tests/conftest.py | 51 +++++++++++++++++++++++++++++++ tests/unit_tests/test_geometry.py | 11 +++++++ tests/unit_tests/test_material.py | 34 +++++++++++++++++++++ 4 files changed, 96 insertions(+), 8 deletions(-) diff --git a/openmc/material.py b/openmc/material.py index 3d54da31b..d19a5f4b9 100644 --- a/openmc/material.py +++ b/openmc/material.py @@ -936,14 +936,6 @@ class Material(IDManagerMixin): elif 'wo' in nuclide.attrib: mat.add_nuclide(name, float(nuclide.attrib['wo']), 'wo') - # Get each element - for element in elem.findall('element'): - name = element.attrib['name'] - if 'ao' in element.attrib: - mat.add_element(name, float(element.attrib['ao'])) - elif 'wo' in element.attrib: - mat.add_element(name, float(element.attrib['wo']), 'wo') - # Get each S(a,b) table for sab in elem.findall('sab'): fraction = float(sab.get('fraction', 1.0)) diff --git a/tests/unit_tests/conftest.py b/tests/unit_tests/conftest.py index 1434eaf3b..94fa6abc7 100644 --- a/tests/unit_tests/conftest.py +++ b/tests/unit_tests/conftest.py @@ -60,3 +60,54 @@ def cell_with_lattice(): return ([inside_cyl, outside_cyl, main_cell], [m_inside[0], m_inside[1], m_inside[3], m_outside], univ, lattice) + +@pytest.fixture +def mixed_lattice_model(uo2, water): + cyl = openmc.ZCylinder(R=0.4) + c1 = openmc.Cell(fill=uo2, region=-cyl) + c1.temperature = 600.0 + c2 = openmc.Cell(fill=water, region=+cyl) + pin = openmc.Universe(cells=[c1, c2]) + + empty = openmc.Cell() + empty_univ = openmc.Universe(cells=[empty]) + + hex_lattice = openmc.HexLattice() + hex_lattice.center = (0.0, 0.0) + hex_lattice.pitch = (1.2, 10.0) + outer_ring = [pin]*6 + inner_ring = [empty_univ] + axial_level = [outer_ring, inner_ring] + hex_lattice.universes = [axial_level]*3 + hex_lattice.outer = empty_univ + + cell_hex = openmc.Cell(fill=hex_lattice) + u = openmc.Universe(cells=[cell_hex]) + rotated_cell_hex = openmc.Cell(fill=u) + rotated_cell_hex.rotation = (0., 0., 30.) + ur = openmc.Universe(cells=[rotated_cell_hex]) + + d = 6.0 + rect_lattice = openmc.RectLattice() + rect_lattice.lower_left = (-d, -d) + rect_lattice.pitch = (d, d) + rect_lattice.outer = empty_univ + rect_lattice.universes = [ + [ur, empty_univ], + [empty_univ, u] + ] + + xmin = openmc.XPlane(x0=-d, boundary_type='periodic') + xmax = openmc.XPlane(x0=d, boundary_type='periodic') + xmin.periodic_surface = xmax + ymin = openmc.YPlane(y0=-d, boundary_type='periodic') + ymax = openmc.YPlane(y0=d, boundary_type='periodic') + main_cell = openmc.Cell(fill=rect_lattice, + region=+xmin & -xmax & +ymin & -ymax) + + # Create geometry and use unique material in each fuel cell + geometry = openmc.Geometry([main_cell]) + geometry.determine_paths() + c1.fill = [water.clone() for i in range(c1.num_instances)] + + return openmc.model.Model(geometry) diff --git a/tests/unit_tests/test_geometry.py b/tests/unit_tests/test_geometry.py index 93d2fa634..b5d6076bb 100644 --- a/tests/unit_tests/test_geometry.py +++ b/tests/unit_tests/test_geometry.py @@ -244,3 +244,14 @@ def test_determine_paths(cell_with_lattice): for i in range(4): assert geom.get_instances(cells[0].paths[i]) == i assert geom.get_instances(mats[-1].paths[i]) == i + +def test_from_xml(run_in_tmpdir, mixed_lattice_model): + # Export model + mixed_lattice_model.export_to_xml() + + # Import geometry + geom = openmc.Geometry.from_xml() + assert isinstance(geom, openmc.Geometry) + ll, ur = geom.bounding_box + assert ll == pytest.approx((-6.0, -6.0, -np.inf)) + assert ur == pytest.approx((6.0, 6.0, np.inf)) diff --git a/tests/unit_tests/test_material.py b/tests/unit_tests/test_material.py index b7b745408..7cedd8dee 100644 --- a/tests/unit_tests/test_material.py +++ b/tests/unit_tests/test_material.py @@ -182,3 +182,37 @@ def test_borated_water(): # Test the density override m = openmc.model.borated_water(975, 566.5, 15.51, density=0.9) assert m.density == pytest.approx(0.9, 1e-3) + + +def test_from_xml(run_in_tmpdir): + # Create a materials.xml file + m1 = openmc.Material(1, 'water') + m1.add_nuclide('H1', 1.0) + m1.add_nuclide('O16', 2.0) + m1.add_s_alpha_beta('c_H_in_H2O') + m1.set_density('g/cm3', 0.9) + m1.isotropic = ['H1'] + m2 = openmc.Material(2, 'zirc') + m2.add_nuclide('Zr90', 1.0, 'wo') + m2.set_density('kg/m3', 10.0) + m3 = openmc.Material(3) + m3.add_nuclide('N14', 0.02) + + mats = openmc.Materials([m1, m2, m3]) + mats.cross_sections = 'fake_path.xml' + mats.multipole_library = 'fake_multipole/' + mats.export_to_xml() + + # Regenerate materials from XML + mats = openmc.Materials.from_xml() + assert len(mats) == 3 + m1 = mats[0] + assert m1.id == 1 + assert m1.name == 'water' + assert m1.nuclides == [('H1', 1.0, 'ao'), ('O16', 2.0, 'ao')] + assert m1.isotropic == ['H1'] + m2 = mats[1] + assert m2.nuclides == [('Zr90', 1.0, 'wo')] + assert m2.density == 10.0 + assert m2.density_units == 'kg/m3' + assert mats[2].density_units == 'sum' From d7c2e8ddffc037e261d96468ded1f46edbed6410 Mon Sep 17 00:00:00 2001 From: Shikhar Kumar Date: Fri, 17 Aug 2018 12:43:19 -0400 Subject: [PATCH 32/56] Address #1050 changes --- openmc/capi/tally.py | 9 +++------ src/input_xml.F90 | 34 +++++++++++++++++----------------- src/tallies/tally_header.F90 | 4 ++-- 3 files changed, 22 insertions(+), 25 deletions(-) diff --git a/openmc/capi/tally.py b/openmc/capi/tally.py index e494e3316..5ad9db772 100644 --- a/openmc/capi/tally.py +++ b/openmc/capi/tally.py @@ -228,12 +228,8 @@ class Tally(_FortranObjectWithID): @property def estimator(self): estimator = c_int32() - try: - _dll.openmc_tally_get_estimator(self._index, estimator) - except AllocationError: - return "" - else: - return _ESTIMATORS[estimator.value] + _dll.openmc_tally_get_estimator(self._index, estimator) + return _ESTIMATORS[estimator.value] @estimator.setter def estimator(self, estimator): @@ -352,6 +348,7 @@ class Tally(_FortranObjectWithID): return std_dev def reset(self): + """Reset results and num_realizations of tally""" _dll.openmc_tally_reset(self._index) def ci_width(self, alpha=0.05): diff --git a/src/input_xml.F90 b/src/input_xml.F90 index a6db11c42..5cb156981 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -2176,11 +2176,14 @@ contains end if ! Check to make sure 'id' hasn't been used - if (tally_dict % has(tally_id)) then + if (tally_dict % has(t % id)) then call fatal_error("Two or more tallies use the same unique ID: " & // to_str(tally_id)) end if + ! Set tally id + err = openmc_tally_set_id(i_start + i - 1, tally_id) + ! Copy tally name if (check_for_node(node_tal, "name")) & call get_node_value(node_tal, "name", t % name) @@ -2217,7 +2220,7 @@ contains else call fatal_error("Could not find filter " & // trim(to_str(temp_filter(j))) // " specified on tally " & - // trim(to_str(tally_id))) + // trim(to_str(t % id))) end if ! Store the index of the filter @@ -2271,7 +2274,7 @@ contains if (.not. nuclide_dict % has(word)) then call fatal_error("Could not find the nuclide " & // trim(word) // " specified in tally " & - // trim(to_str(tally_id)) // " in any material.") + // trim(to_str(t % id)) // " in any material.") end if ! Set bin to index in nuclides array @@ -2581,7 +2584,7 @@ contains if (t % score_bins(j) == t % score_bins(k)) then call fatal_error("Duplicate score of type '" // trim(& reaction_name(t % score_bins(j))) // "' found in tally " & - // trim(to_str(tally_id))) + // trim(to_str(t % id))) end if end do end do @@ -2628,7 +2631,7 @@ contains end if else call fatal_error("No specified on tally " & - // trim(to_str(tally_id)) // ".") + // trim(to_str(t % id)) // ".") end if ! Check for a tally derivative. @@ -2651,7 +2654,7 @@ contains if (j == size(tally_derivs)) then call fatal_error("Could not find derivative " & // trim(to_str(t % deriv)) // " specified on tally " & - // trim(to_str(tally_id))) + // trim(to_str(t % id))) end if end do @@ -2659,7 +2662,7 @@ contains .or. tally_derivs(t % deriv) % variable == DIFF_TEMPERATURE) then if (any(t % nuclide_bins == -1)) then if (t % find_filter(FILTER_ENERGYOUT) > 0) then - call fatal_error("Error on tally " // trim(to_str(tally_id)) & + call fatal_error("Error on tally " // trim(to_str(t % id)) & // ": Cannot use a 'nuclide_density' or 'temperature' & &derivative on a tally with an outgoing energy filter and & &'total' nuclide rate. Instead, tally each nuclide in the & @@ -2736,7 +2739,7 @@ contains temp_str = to_lower(temp_str) else call fatal_error("Must specify trigger type for tally " // & - trim(to_str(tally_id)) // " in tally XML file.") + trim(to_str(t % id)) // " in tally XML file.") end if ! Get the convergence threshold for the trigger @@ -2744,7 +2747,7 @@ contains call get_node_value(node_trigger, "threshold", threshold) else call fatal_error("Must specify trigger threshold for tally " // & - trim(to_str(tally_id)) // " in tally XML file.") + trim(to_str(t % id)) // " in tally XML file.") end if ! Get list scores for this trigger @@ -2788,7 +2791,7 @@ contains t % triggers(trig_ind) % type = RELATIVE_ERROR case default call fatal_error("Unknown trigger type " // & - trim(temp_str) // " in tally " // trim(to_str(tally_id))) + trim(temp_str) // " in tally " // trim(to_str(t % id))) end select ! Store the trigger convergence threshold @@ -2809,7 +2812,7 @@ contains ! Check if an invalid score was set for the trigger if (t % triggers(trig_ind) % score_index == 0) then call fatal_error("The trigger score " // trim(score_name) // & - " is not set for tally " // trim(to_str(tally_id))) + " is not set for tally " // trim(to_str(t % id))) end if ! Store the trigger convergence threshold @@ -2825,7 +2828,7 @@ contains t % triggers(trig_ind) % type = RELATIVE_ERROR case default call fatal_error("Unknown trigger type " // trim(temp_str) // & - " in tally " // trim(to_str(tally_id))) + " in tally " // trim(to_str(t % id))) end select ! Increment the overall trigger index @@ -2857,7 +2860,7 @@ contains ! tally needs post-collision information if (t % estimator == ESTIMATOR_ANALOG) then call fatal_error("Cannot use track-length estimator for tally " & - // to_str(tally_id)) + // to_str(t % id)) end if ! Set estimator to track-length estimator @@ -2868,7 +2871,7 @@ contains ! tally needs post-collision information if (t % estimator == ESTIMATOR_ANALOG) then call fatal_error("Cannot use collision estimator for tally " & - // to_str(tally_id)) + // to_str(t % id)) end if ! Set estimator to collision estimator @@ -2880,9 +2883,6 @@ contains end select end if - ! Set tally id - err = openmc_tally_set_id(i_start + i - 1, tally_id) - end associate end do READ_TALLIES diff --git a/src/tallies/tally_header.F90 b/src/tallies/tally_header.F90 index d22a53c6a..726599bfc 100644 --- a/src/tallies/tally_header.F90 +++ b/src/tallies/tally_header.F90 @@ -716,7 +716,7 @@ contains case ('collision') tallies(index) % obj % estimator = ESTIMATOR_COLLISION case default - err = E_UNASSIGNED + err = E_INVALID_ARGUMENT call set_errmsg("Unknown tally estimator: " // trim(estimator_)) end select else @@ -1035,7 +1035,7 @@ contains case ('surface') tallies(index) % obj % type = TALLY_SURFACE case default - err = E_UNASSIGNED + err = E_INVALID_ARGUMENT call set_errmsg("Unknown tally type: " // trim(type_)) end select else From 78a17416280ba9a5189f4703c55f911791831085 Mon Sep 17 00:00:00 2001 From: Shikhar Kumar Date: Fri, 17 Aug 2018 13:08:35 -0400 Subject: [PATCH 33/56] Rename openmc_tally_set_type --> openmc_tally_allocate, openmc_tally_update_type --> openmc_tally_set_type --- include/openmc.h | 2 +- openmc/capi/tally.py | 10 +++++----- src/api.F90 | 4 ++-- src/cmfd_input.F90 | 12 ++++++------ src/input_xml.F90 | 2 +- src/tallies/tally.F90 | 4 ++-- src/tallies/tally_header.F90 | 7 +++---- 7 files changed, 20 insertions(+), 21 deletions(-) diff --git a/include/openmc.h b/include/openmc.h index 36bfd81cb..3c4982110 100644 --- a/include/openmc.h +++ b/include/openmc.h @@ -93,6 +93,7 @@ extern "C" { int openmc_sphharm_filter_set_order(int32_t index, int order); int openmc_sphharm_filter_set_cosine(int32_t index, const char cosine[]); int openmc_statepoint_write(const char filename[]); + int openmc_tally_allocate(int32_t index, const char* type); int openmc_tally_get_active(int32_t index, bool* active); int openmc_tally_get_estimator(int32_t index, int32_t* estimator); int openmc_tally_get_id(int32_t index, int32_t* id); @@ -110,7 +111,6 @@ extern "C" { int openmc_tally_set_nuclides(int32_t index, int n, const char** nuclides); int openmc_tally_set_scores(int32_t index, int n, const char** scores); int openmc_tally_set_type(int32_t index, const char* type); - int openmc_tally_update_type(int32_t index, const char* type); int openmc_zernike_filter_get_order(int32_t index, int* order); int openmc_zernike_filter_get_params(int32_t index, double* x, double* y, double* r); int openmc_zernike_filter_set_order(int32_t index, int order); diff --git a/openmc/capi/tally.py b/openmc/capi/tally.py index 5ad9db772..44bf89415 100644 --- a/openmc/capi/tally.py +++ b/openmc/capi/tally.py @@ -26,6 +26,9 @@ _dll.openmc_get_tally_index.errcheck = _error_handler _dll.openmc_global_tallies.argtypes = [POINTER(POINTER(c_double))] _dll.openmc_global_tallies.restype = c_int _dll.openmc_global_tallies.errcheck = _error_handler +_dll.openmc_tally_allocate.argtypes = [c_int32, c_char_p] +_dll.openmc_tally_allocate.restype = c_int +_dll.openmc_tally_allocate.errcheck = _error_handler _dll.openmc_tally_get_active.argtypes = [c_int32, POINTER(c_bool)] _dll.openmc_tally_get_active.restype = c_int _dll.openmc_tally_get_active.errcheck = _error_handler @@ -81,9 +84,6 @@ _dll.openmc_tally_set_scores.errcheck = _error_handler _dll.openmc_tally_set_type.argtypes = [c_int32, c_char_p] _dll.openmc_tally_set_type.restype = c_int _dll.openmc_tally_set_type.errcheck = _error_handler -_dll.openmc_tally_update_type.argtypes = [c_int32, c_char_p] -_dll.openmc_tally_update_type.restype = c_int -_dll.openmc_tally_update_type.errcheck = _error_handler _SCORES = { @@ -195,7 +195,7 @@ class Tally(_FortranObjectWithID): index = c_int32() _dll.openmc_extend_tallies(1, index, None) - _dll.openmc_tally_set_type(index, b'generic') + _dll.openmc_tally_allocate(index, b'generic') index = index.value else: index = mapping[uid]._index @@ -223,7 +223,7 @@ class Tally(_FortranObjectWithID): @type.setter def type(self, type): - _dll.openmc_tally_update_type(self._index, type.encode()) + _dll.openmc_tally_set_type(self._index, type.encode()) @property def estimator(self): diff --git a/src/api.F90 b/src/api.F90 index 61cc6150c..2c2d46341 100644 --- a/src/api.F90 +++ b/src/api.F90 @@ -25,7 +25,7 @@ module openmc_api use tally_header use tally_filter_header use tally_filter - use tally, only: openmc_tally_set_type + use tally, only: openmc_tally_allocate use simulation use string, only: to_f_string use timer_header @@ -86,6 +86,7 @@ module openmc_api public :: openmc_simulation_init public :: openmc_source_bank public :: openmc_source_set_strength + public :: openmc_tally_allocate public :: openmc_tally_get_estimator public :: openmc_tally_get_id public :: openmc_tally_get_filters @@ -100,7 +101,6 @@ module openmc_api public :: openmc_tally_set_nuclides public :: openmc_tally_set_scores public :: openmc_tally_set_type - public :: openmc_tally_update_type contains diff --git a/src/cmfd_input.F90 b/src/cmfd_input.F90 index 33cd01a9e..de73bc03f 100644 --- a/src/cmfd_input.F90 +++ b/src/cmfd_input.F90 @@ -243,7 +243,7 @@ contains use error, only: fatal_error, warning use mesh_header, only: RegularMesh, openmc_extend_meshes use string - use tally, only: openmc_tally_set_type + use tally, only: openmc_tally_allocate use tally_header, only: openmc_extend_tallies use tally_filter_header use tally_filter @@ -434,7 +434,7 @@ contains ! Begin loop around tallies do i = 1, size(cmfd_tallies) ! Allocate tally - err = openmc_tally_set_type(i_start + i - 1, C_CHAR_'generic' // C_NULL_CHAR) + err = openmc_tally_allocate(i_start + i - 1, C_CHAR_'generic' // C_NULL_CHAR) call openmc_get_tally_next_id(tally_id) err = openmc_tally_set_id(i_start + i - 1, tally_id) @@ -465,7 +465,7 @@ contains err = openmc_tally_set_estimator(i_start + i - 1, C_CHAR_'analog' // C_NULL_CHAR) ! Set tally type to volume - err = openmc_tally_update_type(i_start + i - 1, C_CHAR_'volume' // C_NULL_CHAR) + err = openmc_tally_set_type(i_start + i - 1, C_CHAR_'volume' // C_NULL_CHAR) ! Allocate and set filters allocate(filter_indices(n_filter)) @@ -493,7 +493,7 @@ contains err = openmc_tally_set_estimator(i_start + i - 1, C_CHAR_'analog' // C_NULL_CHAR) ! Set tally type to volume - err = openmc_tally_update_type(i_start + i - 1, C_CHAR_'volume' // C_NULL_CHAR) + err = openmc_tally_set_type(i_start + i - 1, C_CHAR_'volume' // C_NULL_CHAR) ! Set the incoming energy mesh filter index in the tally find_filter ! array @@ -542,7 +542,7 @@ contains ! Set macro bins t % score_bins(1) = SCORE_CURRENT - err = openmc_tally_update_type(i_start + i - 1, C_CHAR_'mesh-surface' // C_NULL_CHAR) + err = openmc_tally_set_type(i_start + i - 1, C_CHAR_'mesh-surface' // C_NULL_CHAR) else if (i == 4) then ! Set name @@ -552,7 +552,7 @@ contains err = openmc_tally_set_estimator(i_start + i - 1, C_CHAR_'analog' // C_NULL_CHAR) ! Set tally type to volume - err = openmc_tally_update_type(i_start + i - 1, C_CHAR_'volume' // C_NULL_CHAR) + err = openmc_tally_set_type(i_start + i - 1, C_CHAR_'volume' // C_NULL_CHAR) ! Allocate and set filters n_filter = 2 diff --git a/src/input_xml.F90 b/src/input_xml.F90 index 5cb156981..e6355af80 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -2159,7 +2159,7 @@ contains READ_TALLIES: do i = 1, n ! Allocate tally - err = openmc_tally_set_type(i_start + i - 1, & + err = openmc_tally_allocate(i_start + i - 1, & C_CHAR_'generic' // C_NULL_CHAR) ! Get pointer to tally diff --git a/src/tallies/tally.F90 b/src/tallies/tally.F90 index 2c660ce87..08079af5d 100644 --- a/src/tallies/tally.F90 +++ b/src/tallies/tally.F90 @@ -3931,7 +3931,7 @@ contains ! C API FUNCTIONS !=============================================================================== - function openmc_tally_set_type(index, type) result(err) bind(C) + function openmc_tally_allocate(index, type) result(err) bind(C) ! Set the type of the tally integer(C_INT32_T), value, intent(in) :: index character(kind=C_CHAR), intent(in) :: type(*) @@ -3964,6 +3964,6 @@ contains err = E_OUT_OF_BOUNDS call set_errmsg("Index in tallies array is out of bounds.") end if - end function openmc_tally_set_type + end function openmc_tally_allocate end module tally diff --git a/src/tallies/tally_header.F90 b/src/tallies/tally_header.F90 index 726599bfc..9e1c56944 100644 --- a/src/tallies/tally_header.F90 +++ b/src/tallies/tally_header.F90 @@ -40,7 +40,7 @@ module tally_header public :: openmc_tally_set_id public :: openmc_tally_set_nuclides public :: openmc_tally_set_scores - public :: openmc_tally_update_type + public :: openmc_tally_set_type !=============================================================================== ! TALLYOBJECT describes a user-specified tally. The region of phase space to @@ -1013,8 +1013,7 @@ contains end if end function openmc_tally_set_scores - - function openmc_tally_update_type(index, type) result(err) bind(C) + function openmc_tally_set_type(index, type) result(err) bind(C) ! Update the type of a tally that is already allocated integer(C_INT32_T), value, intent(in) :: index character(kind=C_CHAR), intent(in) :: type(*) @@ -1042,7 +1041,7 @@ contains err = E_OUT_OF_BOUNDS call set_errmsg("Index in tally array is out of bounds.") end if - end function openmc_tally_update_type + end function openmc_tally_set_type subroutine openmc_get_tally_next_id(id) bind(C) From 652426180798f041068cc0fc5f5f710218efdcab Mon Sep 17 00:00:00 2001 From: Shikhar Kumar Date: Fri, 17 Aug 2018 14:04:28 -0400 Subject: [PATCH 34/56] Move duplicate id checking to openmc_tally_set_id --- src/input_xml.F90 | 13 +++---------- src/tallies/tally_header.F90 | 14 ++++++++++---- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/input_xml.F90 b/src/input_xml.F90 index e6355af80..aae806b7b 100644 --- a/src/input_xml.F90 +++ b/src/input_xml.F90 @@ -2168,22 +2168,15 @@ contains ! Get pointer to tally xml node node_tal = node_tal_list(i) - ! Copy tally id + ! Copy and set tally id if (check_for_node(node_tal, "id")) then call get_node_value(node_tal, "id", tally_id) + err = openmc_tally_set_id(i_start + i - 1, tally_id) + if (err /= 0) call fatal_error(to_f_string(openmc_err_msg)) else call fatal_error("Must specify id for tally in tally XML file.") end if - ! Check to make sure 'id' hasn't been used - if (tally_dict % has(t % id)) then - call fatal_error("Two or more tallies use the same unique ID: " & - // to_str(tally_id)) - end if - - ! Set tally id - err = openmc_tally_set_id(i_start + i - 1, tally_id) - ! Copy tally name if (check_for_node(node_tal, "name")) & call get_node_value(node_tal, "name", t % name) diff --git a/src/tallies/tally_header.F90 b/src/tallies/tally_header.F90 index 9e1c56944..32f094f89 100644 --- a/src/tallies/tally_header.F90 +++ b/src/tallies/tally_header.F90 @@ -777,11 +777,17 @@ contains if (index >= 1 .and. index <= n_tallies) then if (allocated(tallies(index) % obj)) then - tallies(index) % obj % id = id - call tally_dict % set(id, index) - if (id > largest_tally_id) largest_tally_id = id + if (tally_dict % has(id)) then + call set_errmsg("Two or more tallies use the same unique ID: " & + // to_str(id)) + err = E_INVALID_ID + else + tallies(index) % obj % id = id + call tally_dict % set(id, index) + if (id > largest_tally_id) largest_tally_id = id - err = 0 + err = 0 + end if else err = E_ALLOCATE call set_errmsg("Tally type has not been set yet.") From 63032ba40a7029d2476c8dd02c81f77d3b143b28 Mon Sep 17 00:00:00 2001 From: liangjg Date: Fri, 17 Aug 2018 14:22:25 -0400 Subject: [PATCH 35/56] update mutipole tests --- openmc/data/multipole.py | 28 +++++----- .../multipole/results_true.dat | 54 +++++++++---------- tests/unit_tests/test_data_multipole.py | 50 +++++++---------- 3 files changed, 57 insertions(+), 75 deletions(-) diff --git a/openmc/data/multipole.py b/openmc/data/multipole.py index c6e4f123c..04e6dc20b 100644 --- a/openmc/data/multipole.py +++ b/openmc/data/multipole.py @@ -209,10 +209,6 @@ class WindowedMultipole(EqualityMixin): def data(self): return self._data - @property - def l_value(self): - return self._l_value - @property def windows(self): return self._windows @@ -228,35 +224,35 @@ class WindowedMultipole(EqualityMixin): @spacing.setter def spacing(self, spacing): if spacing is not None: - check_type('spacing', spacing, Real) - check_greater_than('spacing', spacing, 0.0, equality=False) + cv.check_type('spacing', spacing, Real) + cv.check_greater_than('spacing', spacing, 0.0, equality=False) self._spacing = spacing @sqrtAWR.setter def sqrtAWR(self, sqrtAWR): if sqrtAWR is not None: - check_type('sqrtAWR', sqrtAWR, Real) - check_greater_than('sqrtAWR', sqrtAWR, 0.0, equality=False) + cv.check_type('sqrtAWR', sqrtAWR, Real) + cv.check_greater_than('sqrtAWR', sqrtAWR, 0.0, equality=False) self._sqrtAWR = sqrtAWR @E_min.setter def E_min(self, E_min): if E_min is not None: - check_type('E_min', E_min, Real) - check_greater_than('E_min', E_min, 0.0, equality=True) + cv.check_type('E_min', E_min, Real) + cv.check_greater_than('E_min', E_min, 0.0, equality=True) self._E_min = E_min @E_max.setter def E_max(self, E_max): if E_max is not None: - check_type('E_max', E_max, Real) - check_greater_than('E_max', E_max, 0.0, equality=False) + cv.check_type('E_max', E_max, Real) + cv.check_greater_than('E_max', E_max, 0.0, equality=False) self._E_max = E_max @data.setter def data(self, data): if data is not None: - check_type('data', data, np.ndarray) + cv.check_type('data', data, np.ndarray) if len(data.shape) != 2: raise ValueError('Multipole data arrays must be 2D') if data.shape[1] not in (3, 4): @@ -271,7 +267,7 @@ class WindowedMultipole(EqualityMixin): @windows.setter def windows(self, windows): if windows is not None: - check_type('windows', windows, np.ndarray) + cv.check_type('windows', windows, np.ndarray) if len(windows.shape) != 2: raise ValueError('Multipole windows arrays must be 2D') if not np.issubdtype(windows.dtype, int): @@ -282,7 +278,7 @@ class WindowedMultipole(EqualityMixin): @broaden_poly.setter def broaden_poly(self, broaden_poly): if broaden_poly is not None: - check_type('broaden_poly', broaden_poly, np.ndarray) + cv.check_type('broaden_poly', broaden_poly, np.ndarray) if len(broaden_poly.shape) != 1: raise ValueError('Multipole broaden_poly arrays must be 1D') if not np.issubdtype(broaden_poly.dtype, bool): @@ -293,7 +289,7 @@ class WindowedMultipole(EqualityMixin): @curvefit.setter def curvefit(self, curvefit): if curvefit is not None: - check_type('curvefit', curvefit, np.ndarray) + cv.check_type('curvefit', curvefit, np.ndarray) if len(curvefit.shape) != 3: raise ValueError('Multipole curvefit arrays must be 3D') if curvefit.shape[2] not in (2, 3): # sig_s, sig_a (maybe sig_f) diff --git a/tests/regression_tests/multipole/results_true.dat b/tests/regression_tests/multipole/results_true.dat index 19c34229f..890e47efd 100644 --- a/tests/regression_tests/multipole/results_true.dat +++ b/tests/regression_tests/multipole/results_true.dat @@ -1,36 +1,36 @@ k-combined: -1.363786E+00 1.103929E-02 +1.342579E+00 1.221176E-02 tally 1: -3.960375E+00 -3.138356E+00 -2.875799E+00 -1.655329E+00 -5.521904E-01 -6.105083E-02 -4.617974E-01 -4.274130E-02 +3.839794E+00 +2.951721E+00 +2.785273E+00 +1.554128E+00 +5.349716E-01 +5.732174E-02 +4.499834E-01 +4.055011E-02 0.000000E+00 0.000000E+00 -2.254165E+01 -1.016444E+02 +2.258507E+01 +1.020294E+02 0.000000E+00 0.000000E+00 -6.839351E-04 -9.359599E-08 -2.251829E+01 -1.014341E+02 -4.903575E-05 -1.199780E-09 -3.595002E+02 -2.586079E+04 -2.875799E+00 -1.655329E+00 -2.174747E+00 -9.465589E-01 -3.543564E+02 -2.512619E+04 -4.903575E-05 -1.199780E-09 +6.862242E-04 +9.421377E-08 +2.256396E+01 +1.018388E+02 +1.146136E-04 +3.296980E-09 +3.624627E+02 +2.628739E+04 +2.785273E+00 +1.554128E+00 +2.176478E+00 +9.480405E-01 +3.574110E+02 +2.555993E+04 +1.146136E-04 +3.296980E-09 Cell ID = 11 Name = diff --git a/tests/unit_tests/test_data_multipole.py b/tests/unit_tests/test_data_multipole.py index a1cc5bc02..4683dcd3a 100644 --- a/tests/unit_tests/test_data_multipole.py +++ b/tests/unit_tests/test_data_multipole.py @@ -3,8 +3,6 @@ import os import numpy as np import pytest import openmc.data - - pytestmark = pytest.mark.skipif( 'OPENMC_MULTIPOLE_LIBRARY' not in os.environ, reason='OPENMC_MULTIPOLE_LIBRARY environment variable must be set') @@ -18,44 +16,32 @@ def u235(): @pytest.fixture(scope='module') -def u234(): +def b10(): directory = os.environ['OPENMC_MULTIPOLE_LIBRARY'] - filename = os.path.join(directory, '092234.h5') + filename = os.path.join(directory, '005010.h5') return openmc.data.WindowedMultipole.from_hdf5(filename) -@pytest.fixture(scope='module') -def fe56(): - directory = os.environ['OPENMC_MULTIPOLE_LIBRARY'] - filename = os.path.join(directory, '026056.h5') - return openmc.data.WindowedMultipole.from_hdf5(filename) - - -def test_evaluate_rm(u235): - """Make sure a Reich-Moore multipole object can be called.""" +def test_evaluate(u235): + """Test the cross section evaluation of a library.""" energies = [1e-3, 1.0, 10.0, 50.] - total, absorption, fission = u235(energies, 0.0) - assert total[1] == pytest.approx(90.64895383) - total, absorption, fission = u235(energies, 300.0) - assert total[1] == pytest.approx(91.12534964) + scattering, absorption, fission = u235(energies, 0.0) + assert (scattering[1], absorption[1], fission[1]) == \ + pytest.approx((13.09, 77.56, 67.36), rel=1e-3) + scattering, absorption, fission = u235(energies, 300.0) + assert (scattering[2], absorption[2], fission[2]) == \ + pytest.approx((11.24, 21.26, 15.50), rel=1e-3) -def test_evaluate_mlbw(u234): - """Make sure a Multi-Level Breit-Wigner multipole object can be called.""" - energies = [1e-3, 1.0, 10.0, 50.] - total, absorption, fission = u234(energies, 0.0) - assert total[3] == pytest.approx(15.02827953) - total, absorption, fission = u234(energies, 300.0) - assert total[3] == pytest.approx(15.08269143) - - -def test_high_l(fe56): - """Test a nuclide (Fe56) with a high l-value (4).""" +def test_evaluate_none_poles(b10): + """Test a library with no poles, i.e., purely polynomials.""" energies = [1e-3, 1.0, 10.0, 1e3, 1e5] - total, absorption, fission = fe56(energies, 0.0) - assert total[0] == pytest.approx(25.072619556789267) - total, absorption, fission = fe56(energies, 300.0) - assert total[0] == pytest.approx(27.85535792368082) + scattering, absorption, fission = b10(energies, 0.0) + assert (scattering[0], absorption[0], fission[0]) == \ + pytest.approx((2.201, 19330., 0.), rel=1e-3) + scattering, absorption, fission = b10(energies, 300.0) + assert (scattering[-1], absorption[-1], fission[-1]) == \ + pytest.approx((2.878, 1.982, 0.), rel=1e-3) def test_export_to_hdf5(tmpdir, u235): From e4de659b12e428269b5ce194f15ad428525c4d1c Mon Sep 17 00:00:00 2001 From: liangjg Date: Fri, 17 Aug 2018 14:42:14 -0400 Subject: [PATCH 36/56] update travis ci scripts to use latest library --- .travis.yml | 3 ++- tools/ci/travis-before-script.sh | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index f61fa1db0..50ef63641 100644 --- a/.travis.yml +++ b/.travis.yml @@ -17,6 +17,7 @@ cache: directories: - $HOME/nndc_hdf5 - $HOME/endf-b-vii.1 + - $HOME/WMP_Library env: global: - FC=gfortran @@ -25,7 +26,7 @@ env: - OMP_NUM_THREADS=2 - OPENMC_CROSS_SECTIONS=$HOME/nndc_hdf5/cross_sections.xml - OPENMC_ENDF_DATA=$HOME/endf-b-vii.1 - - OPENMC_MULTIPOLE_LIBRARY=$HOME/multipole_lib + - OPENMC_MULTIPOLE_LIBRARY=$HOME/WMP_Library/WMP_Library - PATH=$PATH:$HOME/NJOY2016/build - DISPLAY=:99.0 matrix: diff --git a/tools/ci/travis-before-script.sh b/tools/ci/travis-before-script.sh index bbb34358b..ca7cf75e2 100755 --- a/tools/ci/travis-before-script.sh +++ b/tools/ci/travis-before-script.sh @@ -17,5 +17,6 @@ if [[ ! -d $ENDF/neutrons || ! -d $ENDF/photoat || ! -d $ENDF/atomic_relax ]]; t fi # Download multipole library -git clone --branch=master git://github.com/smharper/windowed_multipole_library.git wmp_lib -tar -C $HOME -xzvf wmp_lib/multipole_lib.tar.gz +if [[ ! -d $HOME/WMP_Library ]]; then + git lfs clone https://github.com/mit-crpg/WMP_Library.git +fi From 15be98de928f7a4a4a56c1a1a926e4fadb646e88 Mon Sep 17 00:00:00 2001 From: Zhuoran Han Date: Fri, 17 Aug 2018 14:59:37 -0500 Subject: [PATCH 37/56] Remove odd files --- openmc/polynomials.py | 38 -------------------------------------- 1 file changed, 38 deletions(-) delete mode 100644 openmc/polynomials.py diff --git a/openmc/polynomials.py b/openmc/polynomials.py deleted file mode 100644 index 6a9ba23c4..000000000 --- a/openmc/polynomials.py +++ /dev/null @@ -1,38 +0,0 @@ -import numpy as np -import openmc -import openmc.capi as capi - -class Polynomials(object): - """Class for Polynomials""" - def __init__(self, coeff): - self.coeff = coeff - self.n_coeff = len(coeff) - -class Legendre(Polynomials): - def __init__(self, coeff, domain_min = -1, domain_max = 1): - super().__init__(coeff) - self.order = self.n_coeff - 1 - self.domain_min = domain_min - self.domain_max = domain_max - self.norm_vec = (2 * np.arange(self.n_coeff) + 1) / (self.domain_max - - self.domain_min) - self.norm_coeff = np.multiply(self.norm_vec,self.coeff) - - def __call__(self, x): - # x is the normalized position on [-1,1] - pn = capi.calc_pn(self.order, x) - return np.sum(np.multiply(self.norm_coeff, pn)) - -class ZernikeRadial(Polynomials): - def __init__(self,coeff,radius = 1): - super().__init__(coeff) - self.order = 2 * (self.n_coeff - 1) - self.radius = radius - self.norm_vec = (2 * np.arange(self.n_coeff) + 1) / (np.pi * - radius ** 2) - self.norm_coeff = np.multiply(self.norm_vec,self.coeff) - - def __call__(self, r): - # r is the normalized position on radius [0,1] - zn_rad = capi.calc_zn_rad(self.order, r) - return np.sum(np.multiply(self.norm_coeff, zn_rad)) \ No newline at end of file From 98a32391be03095a2d9cc7c9cc89662275bbd8ee Mon Sep 17 00:00:00 2001 From: Zhuoran Han Date: Fri, 17 Aug 2018 15:00:39 -0500 Subject: [PATCH 38/56] Change Polynomial class and fix PEP 8 style --- openmc/__init__.py | 2 +- openmc/polynomial.py | 71 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 openmc/polynomial.py diff --git a/openmc/__init__.py b/openmc/__init__.py index c7db3171c..4627c340b 100644 --- a/openmc/__init__.py +++ b/openmc/__init__.py @@ -28,7 +28,7 @@ from openmc.particle_restart import * from openmc.mixin import * from openmc.plotter import * from openmc.search import * -from openmc.polynomials import * +from openmc.polynomial import * from . import examples # Import a few convencience functions that used to be here diff --git a/openmc/polynomial.py b/openmc/polynomial.py new file mode 100644 index 000000000..fce068f18 --- /dev/null +++ b/openmc/polynomial.py @@ -0,0 +1,71 @@ +import numpy as np +import openmc +import openmc.capi as capi + + +def legendre_from_expcoef(coef, domain): + """Download file from a URL + + Parameters + ---------- + coef : Iterable of float + A list of coefficients of each term in Legendre polynomials + + Returns + ------- + Legendre class + A numpy Legendre series object + + """ + n = np.arange(len(coef) + 1) + c = (2*n + 1) * np.asarray(coef) / (domain[1] - domain[0]) + return np.polynomial.Legendre(c, domain) + + +class Polynomial(object): + """Abstract Polynomial Class for creating polynomials. + """ + def __init__(self, coef): + self.coef = np.asarray(coef) + + +class ZernikeRadial(Polynomial): + """Create radial only Zernike polynomials given coefficients and domian. + + The radial only Zernike polynomials are defined as in + :class:`ZernikeRadialFilter`. + + Parameters + ---------- + coef : Iterable of float + A list of coefficients of each term in radial only Zernike polynomials + radius : float + Domain of Zernike polynomials to be applied on. Default is 1. + r : float + Position to be evaluated, normalized on radius [0,1] + + Attributes + ---------- + order : int + The maximum (even) order of Zernike polynomials. + radius : float + Domain of Zernike polynomials to be applied on. Default is 1. + norm_coef : iterable of float + The list of coefficients of each term in the polynomials after + normailization. + + """ + def __init__(self, coef, radius=1): + super().__init__(coef) + self._order = 2 * (self.n_coef - 1) + self.radius = radius + norm_vec = (2 * np.arange(self.n_coef) + 1) / (np.pi * radius**2) + self._norm_coef = norm_vec * self.coef + + @property + def order(self): + return self._order + + def __call__(self, r): + zn_rad = capi.calc_zn_rad(self.order, r) + return np.sum(self._norm_coef * zn_rad) From 33be934308ba3c8ad1f9e3c40143d8ed3992142e Mon Sep 17 00:00:00 2001 From: Zhuoran Han Date: Fri, 17 Aug 2018 15:27:51 -0500 Subject: [PATCH 39/56] Add test of Zernike radial. There is really nothing to test for Legendre --- openmc/polynomial.py | 8 +++-- tests/unit_tests/test_polynomials.py | 44 +++------------------------- 2 files changed, 9 insertions(+), 43 deletions(-) diff --git a/openmc/polynomial.py b/openmc/polynomial.py index fce068f18..7264524cb 100644 --- a/openmc/polynomial.py +++ b/openmc/polynomial.py @@ -4,12 +4,14 @@ import openmc.capi as capi def legendre_from_expcoef(coef, domain): - """Download file from a URL + """Return a Legendre object Parameters ---------- coef : Iterable of float A list of coefficients of each term in Legendre polynomials + domain : (2,) List of float + Domain of the Legendre polynomial Returns ------- @@ -57,9 +59,9 @@ class ZernikeRadial(Polynomial): """ def __init__(self, coef, radius=1): super().__init__(coef) - self._order = 2 * (self.n_coef - 1) + self._order = 2 * (len(self.coef) - 1) self.radius = radius - norm_vec = (2 * np.arange(self.n_coef) + 1) / (np.pi * radius**2) + norm_vec = (2 * np.arange(len(self.coef)) + 1) / (np.pi * radius**2) self._norm_coef = norm_vec * self.coef @property diff --git a/tests/unit_tests/test_polynomials.py b/tests/unit_tests/test_polynomials.py index 6dd220df3..4ce767d2e 100644 --- a/tests/unit_tests/test_polynomials.py +++ b/tests/unit_tests/test_polynomials.py @@ -4,64 +4,28 @@ import scipy as sp import openmc import openmc.capi -def test_legendre(): - coeff = np.asarray([2.5, 1.2, -0.2, 0.1]) - pn = openmc.Legendre(coeff) - assert pn.order == 3 - assert pn.domain_min == -1 - assert pn.domain_max == 1 - - norm_vec = (2 * np.arange(4) + 1) / 2 - assert np.allclose(pn.norm_vec,norm_vec) - norm_coeff = np.multiply(norm_vec,coeff) - assert np.allclose(pn.norm_coeff, norm_coeff) - - coeff = np.asarray([2.5, 1.2, -0.2]) - pn = openmc.Legendre(coeff, -10, 10) - assert pn.order == 2 - assert pn.domain_min == -10 - assert pn.domain_max == 10 - norm_vec = (2 * np.arange(3) + 1) / 20 - assert np.allclose(pn.norm_vec,norm_vec) - norm_coeff = np.multiply(norm_vec,coeff) - assert np.allclose(pn.norm_coeff, norm_coeff) - - test_xs = np.linspace(-1., 1., num=5, endpoint=True) - ref_vals = np.polynomial.legendre.legval(test_xs, norm_coeff) - - test_vals = np.array([pn(x) for x in test_xs]) - assert np.allclose(ref_vals, test_vals) - def test_zernike_radial(): coeff = np.asarray([1.3, -3.0, 9e-1, -6e-1, 0.11]) zn_rad = openmc.ZernikeRadial(coeff) assert zn_rad.order == 8 assert zn_rad.radius == 1 - norm_vec = (2 * np.arange(5) + 1) / np.pi - assert np.allclose(zn_rad.norm_vec,norm_vec) - norm_coeff = np.multiply(norm_vec,coeff) - assert np.allclose(zn_rad.norm_coeff,norm_coeff) coeff = np.asarray([1.3, -3.0, 9e-1, -6e-1, 0.11, 0.222]) zn_rad = openmc.ZernikeRadial(coeff, 0.392) assert zn_rad.order == 10 assert zn_rad.radius == 0.392 norm_vec = (2 * np.arange(6) + 1) / (np.pi * 0.392 ** 2) - assert np.allclose(zn_rad.norm_vec,norm_vec) - norm_coeff = np.multiply(norm_vec,coeff) - assert np.allclose(zn_rad.norm_coeff,norm_coeff) - + norm_coeff = norm_vec * coeff rho = 0.5 - # Reference solution from running the Fortran implementation + # Reference solution from running the Fortran implementation raw_zn = np.array([ 1.00000000e+00, -5.00000000e-01, -1.25000000e-01, - 4.37500000e-01, -2.89062500e-01,-8.98437500e-02]) + 4.37500000e-01, -2.89062500e-01, -8.98437500e-02]) - ref_vals = np.sum(np.multiply(norm_coeff,raw_zn)) + ref_vals = np.sum(norm_coeff * raw_zn) test_vals = zn_rad(rho) assert ref_vals == test_vals - From cc295001ff2812b7b4b36072c98be963be03adf9 Mon Sep 17 00:00:00 2001 From: Zhuoran Han Date: Fri, 17 Aug 2018 16:39:56 -0500 Subject: [PATCH 40/56] Fixed a minor bug --- openmc/polynomial.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/openmc/polynomial.py b/openmc/polynomial.py index 7264524cb..d26d7edf8 100644 --- a/openmc/polynomial.py +++ b/openmc/polynomial.py @@ -3,8 +3,11 @@ import openmc import openmc.capi as capi -def legendre_from_expcoef(coef, domain): - """Return a Legendre object +def legendre_from_expcoef(coef, domain= [-1,1]): + """Return a Legendre object. + + Given a list of coefficients from FET tally and a array of down, return + the numpy Legendre object. Parameters ---------- @@ -19,7 +22,8 @@ def legendre_from_expcoef(coef, domain): A numpy Legendre series object """ - n = np.arange(len(coef) + 1) + + n = np.arange(len(coef)) c = (2*n + 1) * np.asarray(coef) / (domain[1] - domain[0]) return np.polynomial.Legendre(c, domain) From 23f71ccfad0bf1825139ed3acc160491c1744747 Mon Sep 17 00:00:00 2001 From: Zhuoran Han Date: Fri, 17 Aug 2018 16:40:17 -0500 Subject: [PATCH 41/56] Add Poly in docs --- docs/source/pythonapi/base.rst | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/docs/source/pythonapi/base.rst b/docs/source/pythonapi/base.rst index 752cf417e..497b8fc3d 100644 --- a/docs/source/pythonapi/base.rst +++ b/docs/source/pythonapi/base.rst @@ -178,6 +178,24 @@ Post-processing openmc.StatePoint openmc.Summary +Polynomial +--------------- + +.. autosummary:: + :toctree: generated + :nosignatures: + :template: myclass.rst + + openmc.ZernikeRadial + +.. autosummary:: + :toctree: generated + :nosignatures: + :template: myfunction.rst + + openmc.legendre_from_expcoef + + Various classes may be created when performing tally slicing and/or arithmetic: .. autosummary:: From 7aecb12781f673d9d675dff8c61c1fa80db57537 Mon Sep 17 00:00:00 2001 From: Shikhar Kumar Date: Sat, 18 Aug 2018 03:36:58 -0400 Subject: [PATCH 42/56] Fix pytest issue: Setting tally id no longer necessary --- tests/unit_tests/test_capi.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/unit_tests/test_capi.py b/tests/unit_tests/test_capi.py index 92ca0aca9..e94c4541c 100644 --- a/tests/unit_tests/test_capi.py +++ b/tests/unit_tests/test_capi.py @@ -155,7 +155,6 @@ def test_tally_mapping(capi_init): def test_tally(capi_init): t = openmc.capi.tallies[1] - t.id = 1 assert len(t.filters) == 2 assert isinstance(t.filters[0], openmc.capi.MaterialFilter) assert isinstance(t.filters[1], openmc.capi.EnergyFilter) @@ -180,7 +179,6 @@ def test_tally(capi_init): assert t.scores == new_scores t2 = openmc.capi.tallies[2] - t2.id = 2 assert len(t2.filters) == 2 assert isinstance(t2.filters[0], openmc.capi.ZernikeFilter) assert isinstance(t2.filters[1], openmc.capi.CellFilter) From 8a20f3cc0ace1ca00aebc7967c926b3cab1d0215 Mon Sep 17 00:00:00 2001 From: liangjg Date: Fri, 17 Aug 2018 16:05:34 -0400 Subject: [PATCH 43/56] check if git-lfs installed in travis --- .travis.yml | 2 +- .../diff_tally/results_true.dat | 220 +++++++++--------- tools/ci/travis-before-script.sh | 11 +- 3 files changed, 120 insertions(+), 113 deletions(-) diff --git a/.travis.yml b/.travis.yml index 50ef63641..ae2ceafa1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,7 +26,7 @@ env: - OMP_NUM_THREADS=2 - OPENMC_CROSS_SECTIONS=$HOME/nndc_hdf5/cross_sections.xml - OPENMC_ENDF_DATA=$HOME/endf-b-vii.1 - - OPENMC_MULTIPOLE_LIBRARY=$HOME/WMP_Library/WMP_Library + - OPENMC_MULTIPOLE_LIBRARY=$HOME/WMP_Library - PATH=$PATH:$HOME/NJOY2016/build - DISPLAY=:99.0 matrix: diff --git a/tests/regression_tests/diff_tally/results_true.dat b/tests/regression_tests/diff_tally/results_true.dat index 29c906f2e..165459e7d 100644 --- a/tests/regression_tests/diff_tally/results_true.dat +++ b/tests/regression_tests/diff_tally/results_true.dat @@ -1,27 +1,27 @@ d_material,d_nuclide,d_variable,score,mean,std. dev. -3,,density,flux,-4.5951022e+00,4.0201889e-01 -3,,density,flux,-9.9630192e+00,1.8897688e+00 -1,,density,flux,-4.2074596e-01,6.8569557e-02 -1,,density,flux,-2.8861314e-01,1.0032157e-01 -1,O16,nuclide_density,flux,-1.7146771e+01,1.8740496e+01 -1,O16,nuclide_density,flux,-1.4411733e+01,1.5986415e+01 -1,U235,nuclide_density,flux,-3.1082590e+03,3.5930199e+02 -1,U235,nuclide_density,flux,-2.5816702e+03,2.4275334e+02 -1,,temperature,flux,-2.2847162e-06,3.5489476e-04 -1,,temperature,flux,-8.5566667e-05,4.3023777e-04 -3,,density,total,-1.5582276e+00,2.8496759e-01 -3,,density,absorption,1.5711173e-01,1.7341244e-01 -3,,density,scatter,-1.7153393e+00,1.9431809e-01 -3,,density,fission,2.0152323e-01,7.4786095e-02 -3,,density,nu-fission,4.8687131e-01,1.8265878e-01 -3,,density,total,2.2943608e-01,8.6539576e-02 -3,,density,absorption,2.4646330e-01,8.6186628e-02 -3,,density,scatter,-1.7027217e-02,3.1732345e-03 -3,,density,fission,2.1668870e-01,7.5183313e-02 -3,,density,nu-fission,5.2774399e-01,1.8320780e-01 -3,,density,total,1.3300225e+01,4.2626034e+00 -3,,density,absorption,2.3903751e-01,8.9355264e-02 -3,,density,scatter,1.3061188e+01,4.1751261e+00 +3,,density,flux,-4.7291290e+00,8.8503902e-01 +3,,density,flux,-1.0533184e+01,3.0256001e+00 +1,,density,flux,-4.9634223e-01,1.3190338e-01 +1,,density,flux,-4.7458622e-01,5.6426916e-02 +1,O16,nuclide_density,flux,-1.4897399e+01,1.3583122e+01 +1,O16,nuclide_density,flux,-2.2389753e+01,1.5574833e+01 +1,U235,nuclide_density,flux,-2.8858701e+03,4.7033287e+02 +1,U235,nuclide_density,flux,-2.4203468e+03,3.2197255e+02 +1,,temperature,flux,1.6417230e-04,4.7576853e-04 +1,,temperature,flux,7.5575279e-05,8.0740029e-04 +3,,density,total,-1.5555916e+00,5.3353204e-01 +3,,density,absorption,1.4925823e-01,2.3501173e-01 +3,,density,scatter,-1.7048498e+00,3.3363896e-01 +3,,density,fission,1.3210039e-01,1.6377610e-01 +3,,density,nu-fission,3.1732288e-01,3.9893191e-01 +3,,density,total,1.4744448e-01,2.0435075e-01 +3,,density,absorption,1.6665433e-01,1.9696442e-01 +3,,density,scatter,-1.9209851e-02,7.8974770e-03 +3,,density,fission,1.4878594e-01,1.6616312e-01 +3,,density,nu-fission,3.6225815e-01,4.0486140e-01 +3,,density,total,1.2662462e+01,6.2596594e+00 +3,,density,absorption,2.2864288e-01,1.3031728e-01 +3,,density,scatter,1.2433820e+01,6.1294912e+00 3,,density,fission,0.0000000e+00,0.0000000e+00 3,,density,nu-fission,0.0000000e+00,0.0000000e+00 3,,density,total,0.0000000e+00,0.0000000e+00 @@ -29,19 +29,19 @@ d_material,d_nuclide,d_variable,score,mean,std. dev. 3,,density,scatter,0.0000000e+00,0.0000000e+00 3,,density,fission,0.0000000e+00,0.0000000e+00 3,,density,nu-fission,0.0000000e+00,0.0000000e+00 -1,,density,total,3.3373495e-01,4.6827421e-02 -1,,density,absorption,6.7487092e-04,6.5232977e-03 -1,,density,scatter,3.3306008e-01,4.0307583e-02 -1,,density,fission,-1.8402784e-03,4.2206212e-03 -1,,density,nu-fission,-3.8312038e-03,1.0337874e-02 -1,,density,total,-2.4831544e-04,5.5020059e-03 -1,,density,absorption,-4.0311629e-03,5.0266899e-03 -1,,density,scatter,3.7828475e-03,4.8043964e-04 -1,,density,fission,-3.6379968e-03,4.1821819e-03 -1,,density,nu-fission,-8.8266852e-03,1.0193373e-02 -1,,density,total,-3.6848185e-01,1.9314902e-01 -1,,density,absorption,-7.3640407e-03,4.0184508e-03 -1,,density,scatter,-3.6111780e-01,1.8936612e-01 +1,,density,total,2.9404312e-01,7.0116815e-02 +1,,density,absorption,-1.1851195e-03,1.6943078e-03 +1,,density,scatter,2.9522824e-01,6.8519873e-02 +1,,density,fission,-4.4865588e-03,2.3660449e-03 +1,,density,nu-fission,-1.0266898e-02,5.7956130e-03 +1,,density,total,-3.6990351e-03,3.5138725e-03 +1,,density,absorption,-7.0064347e-03,2.7205092e-03 +1,,density,scatter,3.3073996e-03,7.9802045e-04 +1,,density,fission,-6.3630708e-03,2.3832611e-03 +1,,density,nu-fission,-1.5466339e-02,5.8086647e-03 +1,,density,total,-5.5743331e-01,6.1625011e-02 +1,,density,absorption,-9.1430498e-03,4.0831822e-03 +1,,density,scatter,-5.4829026e-01,5.7756112e-02 1,,density,fission,0.0000000e+00,0.0000000e+00 1,,density,nu-fission,0.0000000e+00,0.0000000e+00 1,,density,total,0.0000000e+00,0.0000000e+00 @@ -49,19 +49,19 @@ d_material,d_nuclide,d_variable,score,mean,std. dev. 1,,density,scatter,0.0000000e+00,0.0000000e+00 1,,density,fission,0.0000000e+00,0.0000000e+00 1,,density,nu-fission,0.0000000e+00,0.0000000e+00 -1,O16,nuclide_density,total,3.9050701e+01,8.5131265e+00 -1,O16,nuclide_density,absorption,-7.7573286e-01,7.1182570e-01 -1,O16,nuclide_density,scatter,3.9826434e+01,7.8536529e+00 -1,O16,nuclide_density,fission,-4.2193390e-01,6.0091792e-01 -1,O16,nuclide_density,nu-fission,-1.0411912e+00,1.4662352e+00 -1,O16,nuclide_density,total,-5.8976625e-01,7.9559349e-01 -1,O16,nuclide_density,absorption,-5.0047331e-01,7.1666177e-01 -1,O16,nuclide_density,scatter,-8.9292946e-02,8.9937898e-02 -1,O16,nuclide_density,fission,-3.6634959e-01,6.1270658e-01 -1,O16,nuclide_density,nu-fission,-8.9338374e-01,1.4932014e+00 -1,O16,nuclide_density,total,-3.3511352e+00,2.2365725e+01 -1,O16,nuclide_density,absorption,1.5473875e-01,4.3692662e-01 -1,O16,nuclide_density,scatter,-3.5058740e+00,2.1928948e+01 +1,O16,nuclide_density,total,3.9360816e+01,6.1390337e+00 +1,O16,nuclide_density,absorption,-6.8169613e-01,4.5302455e-01 +1,O16,nuclide_density,scatter,4.0042512e+01,6.4069240e+00 +1,O16,nuclide_density,fission,-6.1275244e-01,2.5764187e-01 +1,O16,nuclide_density,nu-fission,-1.5090099e+00,6.3048791e-01 +1,O16,nuclide_density,total,-7.5872288e-01,3.4843447e-01 +1,O16,nuclide_density,absorption,-6.7382098e-01,3.1002267e-01 +1,O16,nuclide_density,scatter,-8.4901894e-02,6.5286818e-02 +1,O16,nuclide_density,fission,-5.5597011e-01,2.7085418e-01 +1,O16,nuclide_density,nu-fission,-1.3555055e+00,6.6014209e-01 +1,O16,nuclide_density,total,-1.5539605e+01,2.3345398e+01 +1,O16,nuclide_density,absorption,-8.5880168e-02,5.0677339e-01 +1,O16,nuclide_density,scatter,-1.5453725e+01,2.2838892e+01 1,O16,nuclide_density,fission,0.0000000e+00,0.0000000e+00 1,O16,nuclide_density,nu-fission,0.0000000e+00,0.0000000e+00 1,O16,nuclide_density,total,0.0000000e+00,0.0000000e+00 @@ -69,19 +69,19 @@ d_material,d_nuclide,d_variable,score,mean,std. dev. 1,O16,nuclide_density,scatter,0.0000000e+00,0.0000000e+00 1,O16,nuclide_density,fission,0.0000000e+00,0.0000000e+00 1,O16,nuclide_density,nu-fission,0.0000000e+00,0.0000000e+00 -1,U235,nuclide_density,total,-9.1643805e+02,1.8814046e+02 -1,U235,nuclide_density,absorption,1.8114000e+02,4.6345847e+01 -1,U235,nuclide_density,scatter,-1.0975781e+03,1.4310981e+02 -1,U235,nuclide_density,fission,2.8765342e+02,2.2586319e+01 -1,U235,nuclide_density,nu-fission,7.0175585e+02,5.5024716e+01 -1,U235,nuclide_density,total,4.6786282e+02,2.8271731e+01 -1,U235,nuclide_density,absorption,3.6134508e+02,2.8453765e+01 -1,U235,nuclide_density,scatter,1.0651774e+02,1.3120589e+00 -1,U235,nuclide_density,fission,2.8859249e+02,2.2522591e+01 -1,U235,nuclide_density,nu-fission,7.0430623e+02,5.4858487e+01 -1,U235,nuclide_density,total,-5.0586963e+03,6.7151365e+02 -1,U235,nuclide_density,absorption,-1.2315731e+02,1.8905184e+01 -1,U235,nuclide_density,scatter,-4.9355390e+03,6.5260939e+02 +1,U235,nuclide_density,total,-7.9766848e+02,2.3476486e+02 +1,U235,nuclide_density,absorption,2.2136536e+02,5.7727802e+01 +1,U235,nuclide_density,scatter,-1.0190338e+03,1.7827380e+02 +1,U235,nuclide_density,fission,3.0782358e+02,2.4835876e+01 +1,U235,nuclide_density,nu-fission,7.5106928e+02,6.0668638e+01 +1,U235,nuclide_density,total,4.9643664e+02,3.6425359e+01 +1,U235,nuclide_density,absorption,3.8860811e+02,3.5290173e+01 +1,U235,nuclide_density,scatter,1.0782853e+02,1.9206965e+00 +1,U235,nuclide_density,fission,3.0827647e+02,2.4266512e+01 +1,U235,nuclide_density,nu-fission,7.5228268e+02,5.9109738e+01 +1,U235,nuclide_density,total,-4.7231732e+03,7.5353357e+02 +1,U235,nuclide_density,absorption,-1.1580370e+02,1.8531790e+01 +1,U235,nuclide_density,scatter,-4.6073695e+03,7.3502263e+02 1,U235,nuclide_density,fission,0.0000000e+00,0.0000000e+00 1,U235,nuclide_density,nu-fission,0.0000000e+00,0.0000000e+00 1,U235,nuclide_density,total,0.0000000e+00,0.0000000e+00 @@ -89,19 +89,19 @@ d_material,d_nuclide,d_variable,score,mean,std. dev. 1,U235,nuclide_density,scatter,0.0000000e+00,0.0000000e+00 1,U235,nuclide_density,fission,0.0000000e+00,0.0000000e+00 1,U235,nuclide_density,nu-fission,0.0000000e+00,0.0000000e+00 -1,,temperature,total,8.6368265e-05,1.7363899e-04 -1,,temperature,absorption,1.9220262e-05,3.4988977e-05 -1,,temperature,scatter,6.7148003e-05,1.4635162e-04 -1,,temperature,fission,-5.2927287e-06,1.2158338e-05 -1,,temperature,nu-fission,-1.2897086e-05,2.9622912e-05 -1,,temperature,total,-4.2009323e-06,1.8263855e-05 -1,,temperature,absorption,-4.3037914e-06,1.6219907e-05 -1,,temperature,scatter,1.0285902e-07,2.0676492e-06 -1,,temperature,fission,-5.2953783e-06,1.2158786e-05 -1,,temperature,nu-fission,-1.2903531e-05,2.9624000e-05 -1,,temperature,total,-1.1160261e-04,6.1705782e-04 -1,,temperature,absorption,-2.0394397e-06,8.4055062e-06 -1,,temperature,scatter,-1.0956317e-04,6.0869070e-04 +1,,temperature,total,3.1189559e-04,2.4271722e-04 +1,,temperature,absorption,1.6665424e-04,8.8838735e-05 +1,,temperature,scatter,1.4524136e-04,1.9136840e-04 +1,,temperature,fission,2.3953827e-05,2.1283894e-05 +1,,temperature,nu-fission,5.8367285e-05,5.1859176e-05 +1,,temperature,total,-7.8880798e-03,5.1962157e-03 +1,,temperature,absorption,3.1100192e-05,2.7372999e-05 +1,,temperature,scatter,1.2500314e-06,2.6699016e-06 +1,,temperature,fission,2.3952417e-05,2.1283903e-05 +1,,temperature,nu-fission,5.8363840e-05,5.1859165e-05 +1,,temperature,total,2.9848900e-04,1.1934160e-03 +1,,temperature,absorption,9.5075952e-06,1.8452256e-05 +1,,temperature,scatter,2.8898141e-04,1.1750098e-03 1,,temperature,fission,0.0000000e+00,0.0000000e+00 1,,temperature,nu-fission,0.0000000e+00,0.0000000e+00 1,,temperature,total,0.0000000e+00,0.0000000e+00 @@ -109,68 +109,68 @@ d_material,d_nuclide,d_variable,score,mean,std. dev. 1,,temperature,scatter,0.0000000e+00,0.0000000e+00 1,,temperature,fission,0.0000000e+00,0.0000000e+00 1,,temperature,nu-fission,0.0000000e+00,0.0000000e+00 -3,,density,absorption,1.3594219e-01,1.0122046e-01 -3,,density,absorption,2.8656499e-01,3.7923985e-02 -1,,density,absorption,-2.2106085e-03,9.8387075e-03 -1,,density,absorption,-3.3239716e-03,8.7768141e-03 -1,O16,nuclide_density,absorption,-1.2640173e+00,9.1596515e-01 -1,O16,nuclide_density,absorption,1.3146714e-01,9.9380272e-01 -1,U235,nuclide_density,absorption,1.5677452e+02,8.1085465e+01 -1,U235,nuclide_density,absorption,-1.4334804e+02,3.2100956e+01 -1,,temperature,absorption,-8.9633351e-06,3.5750907e-05 -1,,temperature,absorption,7.0140498e-07,1.1694324e-05 +3,,density,absorption,3.1512672e-02,2.4627803e-01 +3,,density,absorption,1.1452915e-01,1.5733776e-01 +1,,density,absorption,-1.4010827e-03,5.7414887e-03 +1,,density,absorption,-8.9116087e-03,7.6054344e-03 +1,O16,nuclide_density,absorption,-1.0238428e+00,3.5596763e-01 +1,O16,nuclide_density,absorption,-5.4386638e-01,6.3275232e-01 +1,U235,nuclide_density,absorption,1.9740455e+02,1.1770740e+02 +1,U235,nuclide_density,absorption,-1.3873202e+02,3.0030411e+01 +1,,temperature,absorption,1.6299319e-04,1.0720491e-04 +1,,temperature,absorption,-2.9480687e-05,1.9529799e-05 3,,density,nu-fission,0.0000000e+00,0.0000000e+00 -3,,density,scatter,4.7213241e-01,1.6556808e-01 +3,,density,scatter,2.5895299e-01,3.3093831e-01 3,,density,nu-fission,0.0000000e+00,0.0000000e+00 -3,,density,scatter,3.4067110e-02,2.1267271e-02 -3,,density,nu-fission,4.1265284e-01,1.3891654e-01 -3,,density,scatter,-2.1663022e+00,3.2444877e-01 -3,,density,nu-fission,4.4524898e-01,1.4098968e-01 -3,,density,scatter,-2.1357153e-02,1.7423446e-02 +3,,density,scatter,2.4380993e-02,2.4380993e-02 +3,,density,nu-fission,1.3982705e-01,4.0427820e-01 +3,,density,scatter,-1.8460573e+00,1.6126524e-01 +3,,density,nu-fission,1.7650022e-01,4.0560218e-01 +3,,density,scatter,3.9711501e-02,4.4405692e-02 3,,density,nu-fission,0.0000000e+00,0.0000000e+00 -3,,density,scatter,8.6343785e+00,2.9292930e+00 +3,,density,scatter,7.8960553e+00,4.4763896e+00 3,,density,nu-fission,0.0000000e+00,0.0000000e+00 3,,density,scatter,0.0000000e+00,0.0000000e+00 3,,density,nu-fission,0.0000000e+00,0.0000000e+00 -3,,density,scatter,4.3792818e+00,1.9915652e+00 +3,,density,scatter,4.6518780e+00,1.6862698e+00 3,,density,nu-fission,0.0000000e+00,0.0000000e+00 3,,density,scatter,0.0000000e+00,0.0000000e+00 1,,density,nu-fission,0.0000000e+00,0.0000000e+00 -1,,density,scatter,-5.0479210e-03,9.5688761e-03 +1,,density,scatter,-1.4155379e-02,7.8989014e-03 1,,density,nu-fission,0.0000000e+00,0.0000000e+00 -1,,density,scatter,4.4418327e-04,7.8121620e-04 -1,,density,nu-fission,-1.9240114e-02,1.4935352e-02 -1,,density,scatter,3.4099348e-01,2.8182893e-02 -1,,density,nu-fission,-2.4226858e-02,1.4481188e-02 -1,,density,scatter,1.1073847e-03,2.7478584e-04 +1,,density,scatter,1.0449664e-03,5.7043392e-04 +1,,density,nu-fission,-1.3723982e-02,1.5246898e-02 +1,,density,scatter,3.0959958e-01,5.7651589e-02 +1,,density,nu-fission,-1.9529210e-02,1.4804175e-02 +1,,density,scatter,5.1063052e-04,1.7748731e-03 1,,density,nu-fission,0.0000000e+00,0.0000000e+00 -1,,density,scatter,-2.7695506e-01,1.3529978e-01 +1,,density,scatter,-3.4116700e-01,1.4433252e-01 1,,density,nu-fission,0.0000000e+00,0.0000000e+00 1,,density,scatter,0.0000000e+00,0.0000000e+00 1,,density,nu-fission,0.0000000e+00,0.0000000e+00 -1,,density,scatter,-8.8202815e-02,7.8863942e-02 +1,,density,scatter,-2.0735470e-01,8.6865144e-02 1,,density,nu-fission,0.0000000e+00,0.0000000e+00 1,,density,scatter,0.0000000e+00,0.0000000e+00 1,O16,nuclide_density,nu-fission,0.0000000e+00,0.0000000e+00 -1,O16,nuclide_density,scatter,1.1279170e-01,6.9836765e-02 -1,O16,nuclide_density,nu-fission,-1.6695105e+00,1.6777445e+00 -1,O16,nuclide_density,scatter,-1.0671543e-01,1.9127943e-01 +1,O16,nuclide_density,scatter,1.4017611e-01,9.5507870e-02 +1,O16,nuclide_density,nu-fission,-8.8199870e-01,1.6570982e+00 +1,O16,nuclide_density,scatter,-1.5442745e-01,1.3136597e-01 1,O16,nuclide_density,nu-fission,0.0000000e+00,0.0000000e+00 1,O16,nuclide_density,scatter,0.0000000e+00,0.0000000e+00 1,O16,nuclide_density,nu-fission,0.0000000e+00,0.0000000e+00 1,O16,nuclide_density,scatter,0.0000000e+00,0.0000000e+00 1,U235,nuclide_density,nu-fission,0.0000000e+00,0.0000000e+00 -1,U235,nuclide_density,scatter,6.3235790e+00,3.9733167e+00 -1,U235,nuclide_density,nu-fission,6.2368225e+02,1.0172850e+02 -1,U235,nuclide_density,scatter,3.2601903e+01,6.2672072e+00 +1,U235,nuclide_density,scatter,8.1567193e+00,5.7077716e+00 +1,U235,nuclide_density,nu-fission,7.1482113e+02,1.4806072e+02 +1,U235,nuclide_density,scatter,5.2848809e+01,1.3486619e+01 1,U235,nuclide_density,nu-fission,0.0000000e+00,0.0000000e+00 1,U235,nuclide_density,scatter,0.0000000e+00,0.0000000e+00 1,U235,nuclide_density,nu-fission,0.0000000e+00,0.0000000e+00 1,U235,nuclide_density,scatter,0.0000000e+00,0.0000000e+00 1,,temperature,nu-fission,0.0000000e+00,0.0000000e+00 -1,,temperature,scatter,-2.0884127e-06,1.6684645e-06 -1,,temperature,nu-fission,-1.5670247e-05,4.5939944e-05 -1,,temperature,scatter,3.9749436e-06,3.9749436e-06 +1,,temperature,scatter,-2.9687644e-07,2.8614575e-07 +1,,temperature,nu-fission,6.9612785e-05,8.2246105e-05 +1,,temperature,scatter,5.9452821e-09,8.7655524e-09 1,,temperature,nu-fission,0.0000000e+00,0.0000000e+00 1,,temperature,scatter,0.0000000e+00,0.0000000e+00 1,,temperature,nu-fission,0.0000000e+00,0.0000000e+00 diff --git a/tools/ci/travis-before-script.sh b/tools/ci/travis-before-script.sh index ca7cf75e2..f66add527 100755 --- a/tools/ci/travis-before-script.sh +++ b/tools/ci/travis-before-script.sh @@ -17,6 +17,13 @@ if [[ ! -d $ENDF/neutrons || ! -d $ENDF/photoat || ! -d $ENDF/atomic_relax ]]; t fi # Download multipole library -if [[ ! -d $HOME/WMP_Library ]]; then - git lfs clone https://github.com/mit-crpg/WMP_Library.git +if [[ ! -e $HOME/WMP_Library/092235.h5 ]]; then + if [[ $(command -v git-lfs) ]]; then + echo "Downloading WMP Library ..." + git clone https://github.com/mit-crpg/WMP_Library.git wmp_repo + mv wmp_repo/WMP_Library $HOME + else + echo "git lfs not found" + unset OPENMC_MULTIPOLE_LIBRARY + fi fi From 968cd22e29a535883280a90b0f5e445b727a7d73 Mon Sep 17 00:00:00 2001 From: liangjg Date: Sat, 18 Aug 2018 21:25:06 -0400 Subject: [PATCH 44/56] fixed np.dtype warnings --- openmc/data/multipole.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/openmc/data/multipole.py b/openmc/data/multipole.py index 04e6dc20b..a0d90ac01 100644 --- a/openmc/data/multipole.py +++ b/openmc/data/multipole.py @@ -260,7 +260,7 @@ class WindowedMultipole(EqualityMixin): 'data.shape[1] must be 3 or 4. One value for the pole.' ' One each for the scattering and absorption residues. ' 'Possibly one more for a fission residue.') - if not np.issubdtype(data.dtype, complex): + if not np.issubdtype(data.dtype, np.complexfloating): raise TypeError('Multipole data arrays must be complex dtype') self._data = data @@ -270,7 +270,7 @@ class WindowedMultipole(EqualityMixin): cv.check_type('windows', windows, np.ndarray) if len(windows.shape) != 2: raise ValueError('Multipole windows arrays must be 2D') - if not np.issubdtype(windows.dtype, int): + if not np.issubdtype(windows.dtype, np.integer): raise TypeError('Multipole windows arrays must be integer' ' dtype') self._windows = windows @@ -281,7 +281,7 @@ class WindowedMultipole(EqualityMixin): cv.check_type('broaden_poly', broaden_poly, np.ndarray) if len(broaden_poly.shape) != 1: raise ValueError('Multipole broaden_poly arrays must be 1D') - if not np.issubdtype(broaden_poly.dtype, bool): + if not np.issubdtype(broaden_poly.dtype, np.bool_): raise TypeError('Multipole broaden_poly arrays must be boolean' ' dtype') self._broaden_poly = broaden_poly @@ -295,7 +295,7 @@ class WindowedMultipole(EqualityMixin): if curvefit.shape[2] not in (2, 3): # sig_s, sig_a (maybe sig_f) raise ValueError('The third dimension of multipole curvefit' ' arrays must have a length of 2 or 3') - if not np.issubdtype(curvefit.dtype, float): + if not np.issubdtype(curvefit.dtype, np.floating): raise TypeError('Multipole curvefit arrays must be float dtype') self._curvefit = curvefit From c7115e5b106b5eaf6b8032e3fafb3aa1f3f20520 Mon Sep 17 00:00:00 2001 From: liangjg Date: Sat, 18 Aug 2018 21:44:54 -0400 Subject: [PATCH 45/56] fix bugs in test --- src/tallies/tally.F90 | 6 +-- .../diff_tally/results_true.dat | 38 +++++++++---------- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/tallies/tally.F90 b/src/tallies/tally.F90 index 2365ec46f..78a714032 100644 --- a/src/tallies/tally.F90 +++ b/src/tallies/tally.F90 @@ -3251,6 +3251,7 @@ contains end do dsig_s = ZERO + dsig_a = ZERO associate (nuc => nuclides(p % event_nuclide)) if (nuc % mp_present .and. & p % last_E >= nuc % multipole % E_min .and. & @@ -3278,7 +3279,6 @@ contains end do dsig_s = ZERO - dsig_a = ZERO associate (nuc => nuclides(p % event_nuclide)) if (nuc % mp_present .and. & p % last_E >= nuc % multipole % E_min .and. & @@ -3408,6 +3408,7 @@ contains else if (materials(p % material) % id == deriv % diff_material & .and. material_xs % total > ZERO) then dsig_s = ZERO + dsig_a = ZERO associate (nuc => nuclides(i_nuclide)) if (nuc % mp_present .and. & p % last_E >= nuc % multipole % E_min .and. & @@ -3448,7 +3449,6 @@ contains .and. (material_xs % total - material_xs % absorption) > ZERO)& then dsig_s = ZERO - dsig_a = ZERO associate (nuc => nuclides(i_nuclide)) if (nuc % mp_present .and. & p % last_E >= nuc % multipole % E_min .and. & @@ -3734,7 +3734,7 @@ contains ! (1 / phi) * (d_phi / d_T) = (d_sigma_s / d_T) / sigma_s call multipole_deriv_eval(nuc % multipole, p % last_E, & p % sqrtkT, dsig_s, dsig_a, dsig_f) - deriv % flux_deriv = deriv % flux_deriv + (dsig_s + dsig_a)& + deriv % flux_deriv = deriv % flux_deriv + dsig_s& / (micro_xs(mat % nuclide(l)) % total & - micro_xs(mat % nuclide(l)) % absorption) ! Note that this is an approximation! The real scattering diff --git a/tests/regression_tests/diff_tally/results_true.dat b/tests/regression_tests/diff_tally/results_true.dat index 165459e7d..e3cff4ca0 100644 --- a/tests/regression_tests/diff_tally/results_true.dat +++ b/tests/regression_tests/diff_tally/results_true.dat @@ -7,8 +7,8 @@ d_material,d_nuclide,d_variable,score,mean,std. dev. 1,O16,nuclide_density,flux,-2.2389753e+01,1.5574833e+01 1,U235,nuclide_density,flux,-2.8858701e+03,4.7033287e+02 1,U235,nuclide_density,flux,-2.4203468e+03,3.2197255e+02 -1,,temperature,flux,1.6417230e-04,4.7576853e-04 -1,,temperature,flux,7.5575279e-05,8.0740029e-04 +1,,temperature,flux,-1.1195282e-04,3.5426553e-04 +1,,temperature,flux,-4.4294257e-04,5.4687257e-04 3,,density,total,-1.5555916e+00,5.3353204e-01 3,,density,absorption,1.4925823e-01,2.3501173e-01 3,,density,scatter,-1.7048498e+00,3.3363896e-01 @@ -89,19 +89,19 @@ d_material,d_nuclide,d_variable,score,mean,std. dev. 1,U235,nuclide_density,scatter,0.0000000e+00,0.0000000e+00 1,U235,nuclide_density,fission,0.0000000e+00,0.0000000e+00 1,U235,nuclide_density,nu-fission,0.0000000e+00,0.0000000e+00 -1,,temperature,total,3.1189559e-04,2.4271722e-04 -1,,temperature,absorption,1.6665424e-04,8.8838735e-05 -1,,temperature,scatter,1.4524136e-04,1.9136840e-04 -1,,temperature,fission,2.3953827e-05,2.1283894e-05 -1,,temperature,nu-fission,5.8367285e-05,5.1859176e-05 -1,,temperature,total,-7.8880798e-03,5.1962157e-03 -1,,temperature,absorption,3.1100192e-05,2.7372999e-05 -1,,temperature,scatter,1.2500314e-06,2.6699016e-06 -1,,temperature,fission,2.3952417e-05,2.1283903e-05 -1,,temperature,nu-fission,5.8363840e-05,5.1859165e-05 -1,,temperature,total,2.9848900e-04,1.1934160e-03 -1,,temperature,absorption,9.5075952e-06,1.8452256e-05 -1,,temperature,scatter,2.8898141e-04,1.1750098e-03 +1,,temperature,total,5.7228698e-05,1.7465295e-04 +1,,temperature,absorption,2.9495471e-05,3.1637786e-05 +1,,temperature,scatter,2.7733227e-05,1.4323068e-04 +1,,temperature,fission,-5.6710689e-06,1.2800905e-05 +1,,temperature,nu-fission,-1.3819116e-05,3.1189136e-05 +1,,temperature,total,-5.8315815e-06,1.8705738e-05 +1,,temperature,absorption,-5.3204426e-06,1.6688104e-05 +1,,temperature,scatter,-5.1113883e-07,2.0213875e-06 +1,,temperature,fission,-5.6723577e-06,1.2800214e-05 +1,,temperature,nu-fission,-1.3822264e-05,3.1187458e-05 +1,,temperature,total,-5.5283703e-04,7.6408422e-04 +1,,temperature,absorption,-6.2179157e-06,1.0365194e-05 +1,,temperature,scatter,-5.4661911e-04,7.5373133e-04 1,,temperature,fission,0.0000000e+00,0.0000000e+00 1,,temperature,nu-fission,0.0000000e+00,0.0000000e+00 1,,temperature,total,0.0000000e+00,0.0000000e+00 @@ -117,8 +117,8 @@ d_material,d_nuclide,d_variable,score,mean,std. dev. 1,O16,nuclide_density,absorption,-5.4386638e-01,6.3275232e-01 1,U235,nuclide_density,absorption,1.9740455e+02,1.1770740e+02 1,U235,nuclide_density,absorption,-1.3873202e+02,3.0030411e+01 -1,,temperature,absorption,1.6299319e-04,1.0720491e-04 -1,,temperature,absorption,-2.9480687e-05,1.9529799e-05 +1,,temperature,absorption,5.0340072e-06,2.9911538e-05 +1,,temperature,absorption,-3.7625680e-05,2.4883845e-05 3,,density,nu-fission,0.0000000e+00,0.0000000e+00 3,,density,scatter,2.5895299e-01,3.3093831e-01 3,,density,nu-fission,0.0000000e+00,0.0000000e+00 @@ -168,8 +168,8 @@ d_material,d_nuclide,d_variable,score,mean,std. dev. 1,U235,nuclide_density,nu-fission,0.0000000e+00,0.0000000e+00 1,U235,nuclide_density,scatter,0.0000000e+00,0.0000000e+00 1,,temperature,nu-fission,0.0000000e+00,0.0000000e+00 -1,,temperature,scatter,-2.9687644e-07,2.8614575e-07 -1,,temperature,nu-fission,6.9612785e-05,8.2246105e-05 +1,,temperature,scatter,-2.9956385e-07,2.8883252e-07 +1,,temperature,nu-fission,-2.1023382e-05,4.9883940e-05 1,,temperature,scatter,5.9452821e-09,8.7655524e-09 1,,temperature,nu-fission,0.0000000e+00,0.0000000e+00 1,,temperature,scatter,0.0000000e+00,0.0000000e+00 From 22c393610fbea85ab33e0f3b9022a636b6840561 Mon Sep 17 00:00:00 2001 From: liangjg Date: Mon, 20 Aug 2018 11:18:33 -0400 Subject: [PATCH 46/56] download wmp library from a release link instead of using git-lfs --- scripts/openmc-get-multipole-data | 13 ++++--------- tools/ci/travis-before-script.sh | 10 ++-------- 2 files changed, 6 insertions(+), 17 deletions(-) diff --git a/scripts/openmc-get-multipole-data b/scripts/openmc-get-multipole-data index ea2539648..c8a2d1e9b 100755 --- a/scripts/openmc-get-multipole-data +++ b/scripts/openmc-get-multipole-data @@ -29,9 +29,9 @@ parser.add_argument('-b', '--batch', action='store_true', args = parser.parse_args() -baseUrl = 'https://github.com/smharper/windowed_multipole_library/blob/master/' -files = ['multipole_lib.tar.gz?raw=true'] -checksums = ['3985aea96f7162a9419c7ed8352e6abb'] +baseUrl = 'https://github.com/mit-crpg/WMP_Library/releases/download/v1.0/' +files = ['WMP_Library_v1.0.tar.gz'] +checksums = ['22cb675734cfccb278dffd40dcfbf26a'] block_size = 16384 # ============================================================================== @@ -101,12 +101,7 @@ for f in files: # Extract files with tarfile.open(fname, 'r') as tgz: print('Extracting {0}...'.format(fname)) - tgz.extractall(path='wmp/') - -# Move data files down one level -for filename in glob.glob('wmp/multipole_lib/*'): - shutil.move(filename, 'wmp/') -os.rmdir('wmp/multipole_lib') + tgz.extractall(path='') # ============================================================================== # PROMPT USER TO DELETE .TAR.GZ FILES diff --git a/tools/ci/travis-before-script.sh b/tools/ci/travis-before-script.sh index f66add527..6d44521a6 100755 --- a/tools/ci/travis-before-script.sh +++ b/tools/ci/travis-before-script.sh @@ -18,12 +18,6 @@ fi # Download multipole library if [[ ! -e $HOME/WMP_Library/092235.h5 ]]; then - if [[ $(command -v git-lfs) ]]; then - echo "Downloading WMP Library ..." - git clone https://github.com/mit-crpg/WMP_Library.git wmp_repo - mv wmp_repo/WMP_Library $HOME - else - echo "git lfs not found" - unset OPENMC_MULTIPOLE_LIBRARY - fi + wget https://github.com/mit-crpg/WMP_Library/releases/download/v1.0/WMP_Library_v1.0.tar.gz + tar -C $HOME -xzvf WMP_Library_v1.0.tar.gz fi From 1f760461a3b64ff0792cc3dadd4f78375f04e0fe Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 20 Aug 2018 14:10:11 -0500 Subject: [PATCH 47/56] Change openmc_find -> openmc_find_cell --- include/openmc.h | 2 +- openmc/capi/core.py | 24 ++++++++++++++---------- src/api.F90 | 25 ++++++++----------------- 3 files changed, 23 insertions(+), 28 deletions(-) diff --git a/include/openmc.h b/include/openmc.h index b913d31b1..3b3c48641 100644 --- a/include/openmc.h +++ b/include/openmc.h @@ -37,7 +37,7 @@ extern "C" { int openmc_filter_set_id(int32_t index, int32_t id); int openmc_filter_set_type(int32_t index, const char* type); int openmc_finalize(); - int openmc_find(double* xyz, int rtype, int32_t* id, int32_t* instance); + int openmc_find_cell(double* xyz, int32_t* index, int32_t* instance); int openmc_get_cell_index(int32_t id, int32_t* index); int openmc_get_filter_index(int32_t id, int32_t* index); void openmc_get_filter_next_id(int32_t* id); diff --git a/openmc/capi/core.py b/openmc/capi/core.py index b5ada7956..f0c5ac45e 100644 --- a/openmc/capi/core.py +++ b/openmc/capi/core.py @@ -24,10 +24,10 @@ _dll.openmc_calculate_volumes.restype = c_int _dll.openmc_calculate_volumes.errcheck = _error_handler _dll.openmc_finalize.restype = c_int _dll.openmc_finalize.errcheck = _error_handler -_dll.openmc_find.argtypes = [POINTER(c_double*3), c_int, POINTER(c_int32), - POINTER(c_int32)] -_dll.openmc_find.restype = c_int -_dll.openmc_find.errcheck = _error_handler +_dll.openmc_find_cell.argtypes = [POINTER(c_double*3), POINTER(c_int32), + POINTER(c_int32)] +_dll.openmc_find_cell.restype = c_int +_dll.openmc_find_cell.errcheck = _error_handler _dll.openmc_hard_reset.restype = c_int _dll.openmc_hard_reset.errcheck = _error_handler _dll.openmc_init.argtypes = [c_int, POINTER(POINTER(c_char)), c_void_p] @@ -84,10 +84,10 @@ def find_cell(xyz): indicates which instance it is, i.e., 0 would be the first instance. """ - uid = c_int32() + index = c_int32() instance = c_int32() - _dll.openmc_find((c_double*3)(*xyz), 1, uid, instance) - return openmc.capi.cells[uid.value], instance.value + _dll.openmc_find_cell((c_double*3)(*xyz), index, instance) + return openmc.capi.Cell(index=index.value), instance.value def find_material(xyz): @@ -104,11 +104,15 @@ def find_material(xyz): Material containing the point, or None is no material is found """ - uid = c_int32() + index = c_int32() instance = c_int32() - _dll.openmc_find((c_double*3)(*xyz), 2, uid, instance) - return openmc.capi.materials[uid.value] if uid != 0 else None + _dll.openmc_find_cell((c_double*3)(*xyz), index, instance) + mats = openmc.capi.Cell(index=index.value).fill + if isinstance(mats, openmc.capi.Material): + return mats + else: + return mats[instance] def hard_reset(): """Reset tallies, timers, and pseudo-random number generator state.""" diff --git a/src/api.F90 b/src/api.F90 index 51cc14766..76be2f446 100644 --- a/src/api.F90 +++ b/src/api.F90 @@ -51,7 +51,7 @@ module openmc_api public :: openmc_filter_set_id public :: openmc_filter_set_type public :: openmc_finalize - public :: openmc_find + public :: openmc_find_cell public :: openmc_get_cell_index public :: openmc_get_keff public :: openmc_get_filter_index @@ -188,13 +188,12 @@ contains end function openmc_finalize !=============================================================================== -! OPENMC_FIND determines the ID or a cell or material at a given point in space +! OPENMC_FIND_CELL determines what cell contains a given point in space !=============================================================================== - function openmc_find(xyz, rtype, id, instance) result(err) bind(C) + function openmc_find_cell(xyz, index, instance) result(err) bind(C) real(C_DOUBLE), intent(in) :: xyz(3) ! Cartesian point - integer(C_INT), intent(in), value :: rtype ! 1 for cell, 2 for material - integer(C_INT32_T), intent(out) :: id + integer(C_INT32_T), intent(out) :: index integer(C_INT32_T), intent(out) :: instance integer(C_INT) :: err @@ -206,30 +205,22 @@ contains p % coord(1) % uvw(:) = [ZERO, ZERO, ONE] call find_cell(p, found) - id = -1 + index = -1 instance = -1 err = E_UNASSIGNED if (found) then - if (rtype == 1) then - id = cells(p % coord(p % n_coord) % cell) % id() - elseif (rtype == 2) then - if (p % material == MATERIAL_VOID) then - id = 0 - else - id = materials(p % material) % id() - end if - end if + index = p % coord(p % n_coord) % cell instance = p % cell_instance - 1 err = 0 else err = E_GEOMETRY - call set_errmsg("Could not find cell/material at position (" // & + call set_errmsg("Could not find cell at position (" // & trim(to_str(xyz(1))) // "," // trim(to_str(xyz(2))) // "," // & trim(to_str(xyz(3))) // ").") end if - end function openmc_find + end function openmc_find_cell !=============================================================================== ! OPENMC_HARD_RESET reset tallies and timers as well as the pseudorandom From 9f0ea52d1a7ac6022452669967887abcd38ab2ec Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 20 Aug 2018 14:40:32 -0500 Subject: [PATCH 48/56] Move headers to include/openmc directory and openmc.h -> openmc/capi.h --- CMakeLists.txt | 2 +- {src => include/openmc}/angle_energy.h | 0 include/{openmc.h => openmc/capi.h} | 16 ++++++++-------- {src => include/openmc}/cell.h | 2 +- {src => include/openmc}/constants.h | 0 {src => include/openmc}/distribution.h | 2 +- {src => include/openmc}/distribution_angle.h | 3 ++- {src => include/openmc}/distribution_energy.h | 4 ++-- {src => include/openmc}/distribution_multi.h | 4 ++-- .../openmc}/distribution_spatial.h | 4 ++-- {src => include/openmc}/endf.h | 3 ++- {src => include/openmc}/error.h | 8 ++++---- include/openmc/finalize.h | 6 ++++++ {src => include/openmc}/geometry.h | 0 {src => include/openmc}/geometry_aux.h | 6 +++--- {src => include/openmc}/hdf5_interface.h | 2 +- {src => include/openmc}/initialize.h | 6 +++--- {src => include/openmc}/lattice.h | 4 ++-- {src => include/openmc}/material.h | 0 {src => include/openmc}/math_functions.h | 8 ++++---- {src => include/openmc}/message_passing.h | 6 +++--- {src => include/openmc}/mgxs.h | 12 ++++++------ {src => include/openmc}/mgxs_interface.h | 6 +++--- {src => include/openmc}/nuclide.h | 2 +- {src => include/openmc}/particle.h | 2 +- {src => include/openmc}/plot.h | 6 +++--- {src => include/openmc}/position.h | 0 {src => include/openmc}/random_lcg.h | 6 +++--- {src => include/openmc}/reaction.h | 3 ++- {src => include/openmc}/reaction_product.h | 7 ++++--- {src => include/openmc}/scattdata.h | 8 +++++--- {src => include/openmc}/search.h | 0 .../openmc}/secondary_correlated.h | 7 ++++--- {src => include/openmc}/secondary_kalbach.h | 7 ++++--- {src => include/openmc}/secondary_nbody.h | 2 +- .../openmc}/secondary_uncorrelated.h | 7 ++++--- {src => include/openmc}/settings.h | 0 {src => include/openmc}/simulation.h | 6 +++--- {src => include/openmc}/state_point.h | 9 +++++---- {src => include/openmc}/string_functions.h | 4 ++-- {src => include/openmc}/string_utils.h | 0 {src => include/openmc}/surface.h | 4 ++-- {src => include/openmc}/thermal.h | 10 +++++----- {src => include/openmc}/xml_interface.h | 6 +++--- {src => include/openmc}/xsdata.h | 10 +++++----- src/cell.cpp | 18 +++++++++--------- src/distribution.cpp | 10 +++++----- src/distribution_angle.cpp | 11 ++++++----- src/distribution_energy.cpp | 13 +++++++------ src/distribution_multi.cpp | 8 ++++---- src/distribution_spatial.cpp | 8 ++++---- src/endf.cpp | 9 +++++---- src/finalize.cpp | 4 ++-- src/finalize.h | 6 ------ src/geometry_aux.cpp | 12 ++++++------ src/hdf5_interface.cpp | 6 +++--- src/initialize.cpp | 13 +++++++------ src/lattice.cpp | 14 +++++++------- src/main.cpp | 4 ++-- src/material.cpp | 6 +++--- src/math_functions.cpp | 4 ++-- src/message_passing.cpp | 2 +- src/mgxs.cpp | 19 ++++++++++--------- src/mgxs_interface.cpp | 9 +++++---- src/particle.cpp | 14 +++++++------- src/plot.cpp | 2 +- src/position.cpp | 2 +- src/random_lcg.cpp | 3 ++- src/reaction.cpp | 10 +++++----- src/reaction_product.cpp | 14 +++++++------- src/scattdata.cpp | 11 ++++++----- src/secondary_correlated.cpp | 11 ++++++----- src/secondary_kalbach.cpp | 9 +++++---- src/secondary_nbody.cpp | 10 +++++----- src/secondary_uncorrelated.cpp | 8 ++++---- src/settings.cpp | 12 ++++++------ src/simulation.cpp | 2 +- src/state_point.cpp | 9 +++++---- src/string_functions.cpp | 4 ++-- src/surface.cpp | 8 ++++---- src/thermal.cpp | 14 +++++++------- src/xml_interface.cpp | 4 ++-- src/xsdata.cpp | 11 ++++++----- 83 files changed, 283 insertions(+), 261 deletions(-) rename {src => include/openmc}/angle_energy.h (100%) rename include/{openmc.h => openmc/capi.h} (97%) rename {src => include/openmc}/cell.h (99%) rename {src => include/openmc}/constants.h (100%) rename {src => include/openmc}/distribution.h (99%) rename {src => include/openmc}/distribution_angle.h (96%) rename {src => include/openmc}/distribution_energy.h (99%) rename {src => include/openmc}/distribution_multi.h (97%) rename {src => include/openmc}/distribution_spatial.h (97%) rename {src => include/openmc}/endf.h (98%) rename {src => include/openmc}/error.h (94%) create mode 100644 include/openmc/finalize.h rename {src => include/openmc}/geometry.h (100%) rename {src => include/openmc}/geometry_aux.h (98%) rename {src => include/openmc}/hdf5_interface.h (99%) rename {src => include/openmc}/initialize.h (74%) rename {src => include/openmc}/lattice.h (99%) rename {src => include/openmc}/material.h (100%) rename {src => include/openmc}/math_functions.h (98%) rename {src => include/openmc}/message_passing.h (70%) rename {src => include/openmc}/mgxs.h (98%) rename {src => include/openmc}/mgxs_interface.h (96%) rename {src => include/openmc}/nuclide.h (98%) rename {src => include/openmc}/particle.h (99%) rename {src => include/openmc}/plot.h (85%) rename {src => include/openmc}/position.h (100%) rename {src => include/openmc}/random_lcg.h (97%) rename {src => include/openmc}/reaction.h (98%) rename {src => include/openmc}/reaction_product.h (95%) rename {src => include/openmc}/scattdata.h (98%) rename {src => include/openmc}/search.h (100%) rename {src => include/openmc}/secondary_correlated.h (95%) rename {src => include/openmc}/secondary_kalbach.h (95%) rename {src => include/openmc}/secondary_nbody.h (97%) rename {src => include/openmc}/secondary_uncorrelated.h (92%) rename {src => include/openmc}/settings.h (100%) rename {src => include/openmc}/simulation.h (72%) rename {src => include/openmc}/state_point.h (74%) rename {src => include/openmc}/string_functions.h (80%) rename {src => include/openmc}/string_utils.h (100%) rename {src => include/openmc}/surface.h (99%) rename {src => include/openmc}/thermal.h (97%) rename {src => include/openmc}/xml_interface.h (90%) rename {src => include/openmc}/xsdata.h (96%) delete mode 100644 src/finalize.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 30dfe42a3..57017aa96 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -422,7 +422,7 @@ add_library(libopenmc SHARED src/xsdata.cpp) set_target_properties(libopenmc PROPERTIES OUTPUT_NAME openmc - PUBLIC_HEADER include/openmc.h + PUBLIC_HEADER include/openmc/capi.h LINKER_LANGUAGE Fortran) target_include_directories(libopenmc diff --git a/src/angle_energy.h b/include/openmc/angle_energy.h similarity index 100% rename from src/angle_energy.h rename to include/openmc/angle_energy.h diff --git a/include/openmc.h b/include/openmc/capi.h similarity index 97% rename from include/openmc.h rename to include/openmc/capi.h index 3b3c48641..8fd89334d 100644 --- a/include/openmc.h +++ b/include/openmc/capi.h @@ -1,5 +1,5 @@ -#ifndef OPENMC_H -#define OPENMC_H +#ifndef OPENMC_CAPI_H +#define OPENMC_CAPI_H #include #include @@ -166,14 +166,14 @@ extern "C" { extern int64_t openmc_work; // Run modes - constexpr int RUN_MODE_FIXEDSOURCE {1}; - constexpr int RUN_MODE_EIGENVALUE {2}; - constexpr int RUN_MODE_PLOTTING {3}; - constexpr int RUN_MODE_PARTICLE {4}; - constexpr int RUN_MODE_VOLUME {5}; + const int RUN_MODE_FIXEDSOURCE = 1; + const int RUN_MODE_EIGENVALUE = 2; + const int RUN_MODE_PLOTTING = 3; + const int RUN_MODE_PARTICLE = 4; + const int RUN_MODE_VOLUME = 5; #ifdef __cplusplus } #endif -#endif // OPENMC_H +#endif // OPENMC_CAPI_H diff --git a/src/cell.h b/include/openmc/cell.h similarity index 99% rename from src/cell.h rename to include/openmc/cell.h index 0b42a656c..2b7534b58 100644 --- a/src/cell.h +++ b/include/openmc/cell.h @@ -10,7 +10,7 @@ #include "hdf5.h" #include "pugixml.hpp" -#include "position.h" +#include "openmc/position.h" namespace openmc { diff --git a/src/constants.h b/include/openmc/constants.h similarity index 100% rename from src/constants.h rename to include/openmc/constants.h diff --git a/src/distribution.h b/include/openmc/distribution.h similarity index 99% rename from src/distribution.h rename to include/openmc/distribution.h index 815248a2e..ed71a1ee2 100644 --- a/src/distribution.h +++ b/include/openmc/distribution.h @@ -10,7 +10,7 @@ #include "pugixml.hpp" -#include "constants.h" +#include "openmc/constants.h" namespace openmc { diff --git a/src/distribution_angle.h b/include/openmc/distribution_angle.h similarity index 96% rename from src/distribution_angle.h rename to include/openmc/distribution_angle.h index 1797e086a..4344eb60d 100644 --- a/src/distribution_angle.h +++ b/include/openmc/distribution_angle.h @@ -6,9 +6,10 @@ #include // for vector -#include "distribution.h" #include "hdf5.h" +#include "openmc/distribution.h" + namespace openmc { //============================================================================== diff --git a/src/distribution_energy.h b/include/openmc/distribution_energy.h similarity index 99% rename from src/distribution_energy.h rename to include/openmc/distribution_energy.h index 8dc4baffe..f13bd5de4 100644 --- a/src/distribution_energy.h +++ b/include/openmc/distribution_energy.h @@ -9,8 +9,8 @@ #include "xtensor/xtensor.hpp" #include "hdf5.h" -#include "constants.h" -#include "endf.h" +#include "openmc/constants.h" +#include "openmc/endf.h" namespace openmc { diff --git a/src/distribution_multi.h b/include/openmc/distribution_multi.h similarity index 97% rename from src/distribution_multi.h rename to include/openmc/distribution_multi.h index 2d4dab42c..c93f22d7b 100644 --- a/src/distribution_multi.h +++ b/include/openmc/distribution_multi.h @@ -3,8 +3,8 @@ #include -#include "distribution.h" -#include "position.h" +#include "openmc/distribution.h" +#include "openmc/position.h" namespace openmc { diff --git a/src/distribution_spatial.h b/include/openmc/distribution_spatial.h similarity index 97% rename from src/distribution_spatial.h rename to include/openmc/distribution_spatial.h index 7474b497c..bda4e8cf0 100644 --- a/src/distribution_spatial.h +++ b/include/openmc/distribution_spatial.h @@ -3,8 +3,8 @@ #include "pugixml.hpp" -#include "distribution.h" -#include "position.h" +#include "openmc/distribution.h" +#include "openmc/position.h" namespace openmc { diff --git a/src/endf.h b/include/openmc/endf.h similarity index 98% rename from src/endf.h rename to include/openmc/endf.h index 369f5d5a6..7f224b24f 100644 --- a/src/endf.h +++ b/include/openmc/endf.h @@ -6,9 +6,10 @@ #include -#include "constants.h" #include "hdf5.h" +#include "openmc/constants.h" + namespace openmc { //! Convert integer representing interpolation law to enum diff --git a/src/error.h b/include/openmc/error.h similarity index 94% rename from src/error.h rename to include/openmc/error.h index 7d015d614..17b2f392e 100644 --- a/src/error.h +++ b/include/openmc/error.h @@ -1,11 +1,11 @@ -#ifndef ERROR_H -#define ERROR_H +#ifndef OPENMC_ERROR_H +#define OPENMC_ERROR_H #include #include #include -#include "openmc.h" +#include "openmc/capi.h" namespace openmc { @@ -82,4 +82,4 @@ void write_message(const std::stringstream& message, int level) } } // namespace openmc -#endif // ERROR_H +#endif // OPENMC_ERROR_H diff --git a/include/openmc/finalize.h b/include/openmc/finalize.h new file mode 100644 index 000000000..58cf75606 --- /dev/null +++ b/include/openmc/finalize.h @@ -0,0 +1,6 @@ +#ifndef OPENMC_FINALIZE_H +#define OPENMC_FINALIZE_H + +extern "C" void openmc_free_bank(); + +#endif // OPENMC_FINALIZE_H diff --git a/src/geometry.h b/include/openmc/geometry.h similarity index 100% rename from src/geometry.h rename to include/openmc/geometry.h diff --git a/src/geometry_aux.h b/include/openmc/geometry_aux.h similarity index 98% rename from src/geometry_aux.h rename to include/openmc/geometry_aux.h index fb5940d1c..a99cadc90 100644 --- a/src/geometry_aux.h +++ b/include/openmc/geometry_aux.h @@ -1,8 +1,8 @@ //! \file geometry_aux.h //! Auxilary functions for geometry initialization and general data handling. -#ifndef GEOMETRY_AUX_H -#define GEOMETRY_AUX_H +#ifndef OPENMC_GEOMETRY_AUX_H +#define OPENMC_GEOMETRY_AUX_H #include @@ -109,4 +109,4 @@ extern "C" int maximum_levels(int32_t univ); extern "C" void free_memory_geometry_c(); } // namespace openmc -#endif // GEOMETRY_AUX_H +#endif // OPENMC_GEOMETRY_AUX_H diff --git a/src/hdf5_interface.h b/include/openmc/hdf5_interface.h similarity index 99% rename from src/hdf5_interface.h rename to include/openmc/hdf5_interface.h index 6ef9a1895..0191d4ffb 100644 --- a/src/hdf5_interface.h +++ b/include/openmc/hdf5_interface.h @@ -13,7 +13,7 @@ #include "xtensor/xadapt.hpp" #include "xtensor/xarray.hpp" -#include "position.h" +#include "openmc/position.h" namespace openmc { diff --git a/src/initialize.h b/include/openmc/initialize.h similarity index 74% rename from src/initialize.h rename to include/openmc/initialize.h index 14283fb5f..72ccc12f6 100644 --- a/src/initialize.h +++ b/include/openmc/initialize.h @@ -1,5 +1,5 @@ -#ifndef INITIALIZE_H -#define INITIALIZE_H +#ifndef OPENMC_INITIALIZE_H +#define OPENMC_INITIALIZE_H #ifdef OPENMC_MPI #include "mpi.h" @@ -17,4 +17,4 @@ void initialize_mpi(MPI_Comm intracomm); } -#endif // INITIALIZE_H +#endif // OPENMC_INITIALIZE_H diff --git a/src/lattice.h b/include/openmc/lattice.h similarity index 99% rename from src/lattice.h rename to include/openmc/lattice.h index 94d7b4387..47544938d 100644 --- a/src/lattice.h +++ b/include/openmc/lattice.h @@ -10,8 +10,8 @@ #include "hdf5.h" #include "pugixml.hpp" -#include "constants.h" -#include "position.h" +#include "openmc/constants.h" +#include "openmc/position.h" namespace openmc { diff --git a/src/material.h b/include/openmc/material.h similarity index 100% rename from src/material.h rename to include/openmc/material.h diff --git a/src/math_functions.h b/include/openmc/math_functions.h similarity index 98% rename from src/math_functions.h rename to include/openmc/math_functions.h index 05748e031..927701bc5 100644 --- a/src/math_functions.h +++ b/include/openmc/math_functions.h @@ -7,9 +7,9 @@ #include #include -#include "constants.h" -#include "position.h" -#include "random_lcg.h" +#include "openmc/constants.h" +#include "openmc/position.h" +#include "openmc/random_lcg.h" namespace openmc { @@ -93,7 +93,7 @@ extern "C" void calc_rn_c(int n, const double uvw[3], double rn[]); extern "C" void calc_zn_c(int n, double rho, double phi, double zn[]); //============================================================================== -//! Calculate only the even order components of n-th order modified Zernike +//! Calculate only the even order components of n-th order modified Zernike //! polynomial moment with azimuthal dependency m = 0 for a given radial (rho) //! location on the unit disk. //! diff --git a/src/message_passing.h b/include/openmc/message_passing.h similarity index 70% rename from src/message_passing.h rename to include/openmc/message_passing.h index 14cf3a7cb..1dab43139 100644 --- a/src/message_passing.h +++ b/include/openmc/message_passing.h @@ -1,5 +1,5 @@ -#ifndef MESSAGE_PASSING_H -#define MESSAGE_PASSING_H +#ifndef OPENMC_MESSAGE_PASSING_H +#define OPENMC_MESSAGE_PASSING_H #ifdef OPENMC_MPI #include "mpi.h" @@ -19,4 +19,4 @@ namespace mpi { } // namespace mpi } // namespace openmc -#endif // MESSAGE_PASSING_H +#endif // OPENMC_MESSAGE_PASSING_H diff --git a/src/mgxs.h b/include/openmc/mgxs.h similarity index 98% rename from src/mgxs.h rename to include/openmc/mgxs.h index 0434bd55d..40746c291 100644 --- a/src/mgxs.h +++ b/include/openmc/mgxs.h @@ -1,15 +1,15 @@ //! \file mgxs.h //! A collection of classes for Multi-Group Cross Section data -#ifndef MGXS_H -#define MGXS_H +#ifndef OPENMC_MGXS_H +#define OPENMC_MGXS_H #include #include -#include "constants.h" -#include "hdf5_interface.h" -#include "xsdata.h" +#include "openmc/constants.h" +#include "openmc/hdf5_interface.h" +#include "openmc/xsdata.h" namespace openmc { @@ -202,4 +202,4 @@ class Mgxs { }; } // namespace openmc -#endif // MGXS_H \ No newline at end of file +#endif // OPENMC_MGXS_H diff --git a/src/mgxs_interface.h b/include/openmc/mgxs_interface.h similarity index 96% rename from src/mgxs_interface.h rename to include/openmc/mgxs_interface.h index 65afd20f9..e5f56e997 100644 --- a/src/mgxs_interface.h +++ b/include/openmc/mgxs_interface.h @@ -1,8 +1,8 @@ //! \file mgxs_interface.h //! A collection of C interfaces to the C++ Mgxs class -#ifndef MGXS_INTERFACE_H -#define MGXS_INTERFACE_H +#ifndef OPENMC_MGXS_INTERFACE_H +#define OPENMC_MGXS_INTERFACE_H #include "hdf5_interface.h" #include "mgxs.h" @@ -76,4 +76,4 @@ extern "C" double get_awr_c(int index); } // namespace openmc -#endif // MGXS_INTERFACE_H \ No newline at end of file +#endif // OPENMC_MGXS_INTERFACE_H diff --git a/src/nuclide.h b/include/openmc/nuclide.h similarity index 98% rename from src/nuclide.h rename to include/openmc/nuclide.h index 8c43d55a0..60769139f 100644 --- a/src/nuclide.h +++ b/include/openmc/nuclide.h @@ -1,7 +1,7 @@ #ifndef OPENMC_NUCLIDE_H #define OPENMC_NUCLIDE_H -#include "constants.h" +#include "openmc/constants.h" namespace openmc { diff --git a/src/particle.h b/include/openmc/particle.h similarity index 99% rename from src/particle.h rename to include/openmc/particle.h index b53397171..f351d1186 100644 --- a/src/particle.h +++ b/include/openmc/particle.h @@ -7,7 +7,7 @@ #include #include -#include "openmc.h" +#include "openmc/capi.h" namespace openmc { diff --git a/src/plot.h b/include/openmc/plot.h similarity index 85% rename from src/plot.h rename to include/openmc/plot.h index 75406b9ac..2048189f7 100644 --- a/src/plot.h +++ b/include/openmc/plot.h @@ -1,5 +1,5 @@ -#ifndef PLOT_H -#define PLOT_H +#ifndef OPENMC_PLOT_H +#define OPENMC_PLOT_H #include "hdf5.h" @@ -12,4 +12,4 @@ extern "C" void voxel_write_slice(int x, hid_t dspace, hid_t dset, extern "C" void voxel_finalize(hid_t dspace, hid_t dset, hid_t memspace); } // namespace openmc -#endif // PLOT_H +#endif // OPENMC_PLOT_H diff --git a/src/position.h b/include/openmc/position.h similarity index 100% rename from src/position.h rename to include/openmc/position.h diff --git a/src/random_lcg.h b/include/openmc/random_lcg.h similarity index 97% rename from src/random_lcg.h rename to include/openmc/random_lcg.h index 45f6ba2c0..b02deec2c 100644 --- a/src/random_lcg.h +++ b/include/openmc/random_lcg.h @@ -1,5 +1,5 @@ -#ifndef RANDOM_LCG_H -#define RANDOM_LCG_H +#ifndef OPENMC_RANDOM_LCG_H +#define OPENMC_RANDOM_LCG_H #include @@ -93,4 +93,4 @@ extern "C" int64_t openmc_get_seed(); extern "C" void openmc_set_seed(int64_t new_seed); } // namespace openmc -#endif // RANDOM_LCG_H +#endif // OPENMC_RANDOM_LCG_H diff --git a/src/reaction.h b/include/openmc/reaction.h similarity index 98% rename from src/reaction.h rename to include/openmc/reaction.h index 5efda042a..7b4d32a94 100644 --- a/src/reaction.h +++ b/include/openmc/reaction.h @@ -7,7 +7,8 @@ #include #include "hdf5.h" -#include "reaction_product.h" + +#include "openmc/reaction_product.h" namespace openmc { diff --git a/src/reaction_product.h b/include/openmc/reaction_product.h similarity index 95% rename from src/reaction_product.h rename to include/openmc/reaction_product.h index ee8b5cea5..79a22d260 100644 --- a/src/reaction_product.h +++ b/include/openmc/reaction_product.h @@ -8,9 +8,10 @@ #include // for vector #include "hdf5.h" -#include "angle_energy.h" -#include "endf.h" -#include "particle.h" + +#include "openmc/angle_energy.h" +#include "openmc/endf.h" +#include "openmc/particle.h" namespace openmc { diff --git a/src/scattdata.h b/include/openmc/scattdata.h similarity index 98% rename from src/scattdata.h rename to include/openmc/scattdata.h index efa7accb4..980238aeb 100644 --- a/src/scattdata.h +++ b/include/openmc/scattdata.h @@ -1,11 +1,13 @@ //! \file scattdata.h //! A collection of multi-group scattering data classes -#ifndef SCATTDATA_H -#define SCATTDATA_H +#ifndef OPENMC_SCATTDATA_H +#define OPENMC_SCATTDATA_H #include +#include "openmc/constants.h" + namespace openmc { // forward declarations so we can name our friend functions @@ -257,4 +259,4 @@ convert_legendre_to_tabular(ScattDataLegendre& leg, ScattDataTabular& tab, int n_mu); } // namespace openmc -#endif // SCATTDATA_H \ No newline at end of file +#endif // OPENMC_SCATTDATA_H diff --git a/src/search.h b/include/openmc/search.h similarity index 100% rename from src/search.h rename to include/openmc/search.h diff --git a/src/secondary_correlated.h b/include/openmc/secondary_correlated.h similarity index 95% rename from src/secondary_correlated.h rename to include/openmc/secondary_correlated.h index 1e3eab0ab..8ba18d3d1 100644 --- a/src/secondary_correlated.h +++ b/include/openmc/secondary_correlated.h @@ -8,9 +8,10 @@ #include "hdf5.h" #include "xtensor/xtensor.hpp" -#include "angle_energy.h" -#include "endf.h" -#include "distribution.h" + +#include "openmc/angle_energy.h" +#include "openmc/endf.h" +#include "openmc/distribution.h" namespace openmc { diff --git a/src/secondary_kalbach.h b/include/openmc/secondary_kalbach.h similarity index 95% rename from src/secondary_kalbach.h rename to include/openmc/secondary_kalbach.h index fa4c43694..a898db67c 100644 --- a/src/secondary_kalbach.h +++ b/include/openmc/secondary_kalbach.h @@ -8,9 +8,10 @@ #include "hdf5.h" #include "xtensor/xtensor.hpp" -#include "angle_energy.h" -#include "constants.h" -#include "endf.h" + +#include "openmc/angle_energy.h" +#include "openmc/constants.h" +#include "openmc/endf.h" namespace openmc { diff --git a/src/secondary_nbody.h b/include/openmc/secondary_nbody.h similarity index 97% rename from src/secondary_nbody.h rename to include/openmc/secondary_nbody.h index f80d50670..8509b0714 100644 --- a/src/secondary_nbody.h +++ b/include/openmc/secondary_nbody.h @@ -6,7 +6,7 @@ #include "hdf5.h" -#include "angle_energy.h" +#include "openmc/angle_energy.h" namespace openmc { diff --git a/src/secondary_uncorrelated.h b/include/openmc/secondary_uncorrelated.h similarity index 92% rename from src/secondary_uncorrelated.h rename to include/openmc/secondary_uncorrelated.h index 7f067fc0a..e895a17bd 100644 --- a/src/secondary_uncorrelated.h +++ b/include/openmc/secondary_uncorrelated.h @@ -8,9 +8,10 @@ #include #include "hdf5.h" -#include "angle_energy.h" -#include "distribution_angle.h" -#include "distribution_energy.h" + +#include "openmc/angle_energy.h" +#include "openmc/distribution_angle.h" +#include "openmc/distribution_energy.h" namespace openmc { diff --git a/src/settings.h b/include/openmc/settings.h similarity index 100% rename from src/settings.h rename to include/openmc/settings.h diff --git a/src/simulation.h b/include/openmc/simulation.h similarity index 72% rename from src/simulation.h rename to include/openmc/simulation.h index b7544a6da..14bb56f27 100644 --- a/src/simulation.h +++ b/include/openmc/simulation.h @@ -1,5 +1,5 @@ -#ifndef SIMULATION_H -#define SIMULATION_H +#ifndef OPENMC_SIMULATION_H +#define OPENMC_SIMULATION_H #include @@ -10,4 +10,4 @@ extern "C" int openmc_n_lost_particles; #pragma omp threadprivate(openmc_current_work) -#endif // SIMULATION_H +#endif // OPENMC_SIMULATION_H diff --git a/src/state_point.h b/include/openmc/state_point.h similarity index 74% rename from src/state_point.h rename to include/openmc/state_point.h index 459df1a67..64713ae96 100644 --- a/src/state_point.h +++ b/include/openmc/state_point.h @@ -1,10 +1,11 @@ -#ifndef STATE_POINT_H -#define STATE_POINT_H +#ifndef OPENMC_STATE_POINT_H +#define OPENMC_STATE_POINT_H #include #include "hdf5.h" -#include "openmc.h" + +#include "openmc/capi.h" namespace openmc { @@ -14,4 +15,4 @@ extern "C" void read_source_bank(hid_t group_id, int64_t* work_index, Bank* source_bank); } // namespace openmc -#endif // STATE_POINT_H +#endif // OPENMC_STATE_POINT_H diff --git a/src/string_functions.h b/include/openmc/string_functions.h similarity index 80% rename from src/string_functions.h rename to include/openmc/string_functions.h index bf30612fe..a3da179a0 100644 --- a/src/string_functions.h +++ b/include/openmc/string_functions.h @@ -1,8 +1,8 @@ //! \file string_functions.h //! A collection of helper routines for C-strings and STL strings -#ifndef STRING_FUNCTIONS_H -#define STRING_FUNCTIONS_H +#ifndef OPENMC_STRING_FUNCTIONS_H +#define OPENMC_STRING_FUNCTIONS_H #include diff --git a/src/string_utils.h b/include/openmc/string_utils.h similarity index 100% rename from src/string_utils.h rename to include/openmc/string_utils.h diff --git a/src/surface.h b/include/openmc/surface.h similarity index 99% rename from src/surface.h rename to include/openmc/surface.h index 746db5c3b..1c3811830 100644 --- a/src/surface.h +++ b/include/openmc/surface.h @@ -9,8 +9,8 @@ #include "hdf5.h" #include "pugixml.hpp" -#include "constants.h" -#include "position.h" +#include "openmc/constants.h" +#include "openmc/position.h" namespace openmc { diff --git a/src/thermal.h b/include/openmc/thermal.h similarity index 97% rename from src/thermal.h rename to include/openmc/thermal.h index e3571a0d5..265831e10 100644 --- a/src/thermal.h +++ b/include/openmc/thermal.h @@ -1,5 +1,5 @@ -#ifndef OPENMC_THERMAL_SCATTERING_H -#define OPENMC_THERMAL_SCATTERING_H +#ifndef OPENMC_THERMAL_H +#define OPENMC_THERMAL_H #include #include @@ -7,8 +7,8 @@ #include "xtensor/xtensor.hpp" -#include "hdf5_interface.h" -#include "nuclide.h" +#include "openmc/hdf5_interface.h" +#include "openmc/nuclide.h" namespace openmc { @@ -144,4 +144,4 @@ extern "C" { } // namespace openmc -#endif // OPENMC_THERMAL_SCATTERING_H +#endif // OPENMC_THERMAL_H diff --git a/src/xml_interface.h b/include/openmc/xml_interface.h similarity index 90% rename from src/xml_interface.h rename to include/openmc/xml_interface.h index ec789cd4e..fb87ffdae 100644 --- a/src/xml_interface.h +++ b/include/openmc/xml_interface.h @@ -1,5 +1,5 @@ -#ifndef XML_INTERFACE_H -#define XML_INTERFACE_H +#ifndef OPENMC_XML_INTERFACE_H +#define OPENMC_XML_INTERFACE_H #include // for stringstream #include @@ -39,4 +39,4 @@ std::vector get_node_array(pugi::xml_node node, const char* name, } } // namespace openmc -#endif // XML_INTERFACE_H +#endif // OPENMC_XML_INTERFACE_H diff --git a/src/xsdata.h b/include/openmc/xsdata.h similarity index 96% rename from src/xsdata.h rename to include/openmc/xsdata.h index c855c67d8..156708c78 100644 --- a/src/xsdata.h +++ b/include/openmc/xsdata.h @@ -1,14 +1,14 @@ //! \file xsdata.h //! A collection of classes for containing the Multi-Group Cross Section data -#ifndef XSDATA_H -#define XSDATA_H +#ifndef OPENMC_XSDATA_H +#define OPENMC_XSDATA_H #include #include -#include "hdf5_interface.h" -#include "scattdata.h" +#include "openmc/hdf5_interface.h" +#include "openmc/scattdata.h" namespace openmc { @@ -115,4 +115,4 @@ class XsData { } //namespace openmc -#endif // XSDATA_H \ No newline at end of file +#endif // OPENMC_XSDATA_H diff --git a/src/cell.cpp b/src/cell.cpp index fb364cfdf..f172ddf3b 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -1,17 +1,17 @@ -#include "cell.h" +#include "openmc/cell.h" #include #include #include -#include "constants.h" -#include "error.h" -#include "hdf5_interface.h" -#include "lattice.h" -#include "material.h" -#include "openmc.h" -#include "surface.h" -#include "xml_interface.h" +#include "openmc/capi.h" +#include "openmc/constants.h" +#include "openmc/error.h" +#include "openmc/hdf5_interface.h" +#include "openmc/lattice.h" +#include "openmc/material.h" +#include "openmc/surface.h" +#include "openmc/xml_interface.h" namespace openmc { diff --git a/src/distribution.cpp b/src/distribution.cpp index f513701fb..f02ee1fc0 100644 --- a/src/distribution.cpp +++ b/src/distribution.cpp @@ -1,4 +1,4 @@ -#include "distribution.h" +#include "openmc/distribution.h" #include // for copy #include // for sqrt, floor, max @@ -6,10 +6,10 @@ #include // for accumulate #include // for string, stod -#include "error.h" -#include "math_functions.h" -#include "random_lcg.h" -#include "xml_interface.h" +#include "openmc/error.h" +#include "openmc/math_functions.h" +#include "openmc/random_lcg.h" +#include "openmc/xml_interface.h" namespace openmc { diff --git a/src/distribution_angle.cpp b/src/distribution_angle.cpp index e5263e4ac..615f84f68 100644 --- a/src/distribution_angle.cpp +++ b/src/distribution_angle.cpp @@ -1,15 +1,16 @@ -#include "distribution_angle.h" +#include "openmc/distribution_angle.h" #include // for abs, copysign #include // for vector -#include "endf.h" -#include "hdf5_interface.h" -#include "random_lcg.h" -#include "search.h" #include "xtensor/xarray.hpp" #include "xtensor/xview.hpp" +#include "openmc/endf.h" +#include "openmc/hdf5_interface.h" +#include "openmc/random_lcg.h" +#include "openmc/search.h" + namespace openmc { //============================================================================== diff --git a/src/distribution_energy.cpp b/src/distribution_energy.cpp index cadeeb3df..d5a47957b 100644 --- a/src/distribution_energy.cpp +++ b/src/distribution_energy.cpp @@ -1,16 +1,17 @@ -#include "distribution_energy.h" +#include "openmc/distribution_energy.h" #include // for max, min, copy, move #include // for size_t #include // for back_inserter -#include "endf.h" -#include "hdf5_interface.h" -#include "math_functions.h" -#include "random_lcg.h" -#include "search.h" #include "xtensor/xview.hpp" +#include "openmc/endf.h" +#include "openmc/hdf5_interface.h" +#include "openmc/math_functions.h" +#include "openmc/random_lcg.h" +#include "openmc/search.h" + namespace openmc { //============================================================================== diff --git a/src/distribution_multi.cpp b/src/distribution_multi.cpp index 36184f752..20ee074a8 100644 --- a/src/distribution_multi.cpp +++ b/src/distribution_multi.cpp @@ -1,11 +1,11 @@ -#include "distribution_multi.h" +#include "openmc/distribution_multi.h" #include // for move #include // for sqrt, sin, cos, max -#include "constants.h" -#include "math_functions.h" -#include "random_lcg.h" +#include "openmc/constants.h" +#include "openmc/math_functions.h" +#include "openmc/random_lcg.h" namespace openmc { diff --git a/src/distribution_spatial.cpp b/src/distribution_spatial.cpp index d870a5f93..ad61861e5 100644 --- a/src/distribution_spatial.cpp +++ b/src/distribution_spatial.cpp @@ -1,8 +1,8 @@ -#include "distribution_spatial.h" +#include "openmc/distribution_spatial.h" -#include "error.h" -#include "random_lcg.h" -#include "xml_interface.h" +#include "openmc/error.h" +#include "openmc/random_lcg.h" +#include "openmc/xml_interface.h" namespace openmc { diff --git a/src/endf.cpp b/src/endf.cpp index 8a63893a7..fb7701ac3 100644 --- a/src/endf.cpp +++ b/src/endf.cpp @@ -1,15 +1,16 @@ -#include "endf.h" +#include "openmc/endf.h" #include // for copy #include // for log, exp #include // for back_inserter -#include "constants.h" -#include "hdf5_interface.h" -#include "search.h" #include "xtensor/xarray.hpp" #include "xtensor/xview.hpp" +#include "openmc/constants.h" +#include "openmc/hdf5_interface.h" +#include "openmc/search.h" + namespace openmc { //============================================================================== diff --git a/src/finalize.cpp b/src/finalize.cpp index 696a1e80e..3b4f26764 100644 --- a/src/finalize.cpp +++ b/src/finalize.cpp @@ -1,6 +1,6 @@ -#include "finalize.h" +#include "openmc/finalize.h" -#include "message_passing.h" +#include "openmc/message_passing.h" void openmc_free_bank() { diff --git a/src/finalize.h b/src/finalize.h deleted file mode 100644 index e606493ca..000000000 --- a/src/finalize.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef FINALIZE_H -#define FINALIZE_H - -extern "C" void openmc_free_bank(); - -#endif // FINALIZE_H diff --git a/src/geometry_aux.cpp b/src/geometry_aux.cpp index b20262071..1f2b1e677 100644 --- a/src/geometry_aux.cpp +++ b/src/geometry_aux.cpp @@ -1,14 +1,14 @@ -#include "geometry_aux.h" +#include "openmc/geometry_aux.h" #include // for std::max #include #include -#include "cell.h" -#include "constants.h" -#include "error.h" -#include "lattice.h" -#include "material.h" +#include "openmc/cell.h" +#include "openmc/constants.h" +#include "openmc/error.h" +#include "openmc/lattice.h" +#include "openmc/material.h" namespace openmc { diff --git a/src/hdf5_interface.cpp b/src/hdf5_interface.cpp index 74d26a58b..cc8230739 100644 --- a/src/hdf5_interface.cpp +++ b/src/hdf5_interface.cpp @@ -1,4 +1,4 @@ -#include "hdf5_interface.h" +#include "openmc/hdf5_interface.h" #include #include @@ -9,9 +9,9 @@ #include "hdf5_hl.h" #ifdef OPENMC_MPI #include "mpi.h" -#include "message_passing.h" +#include "openmc/message_passing.h" #endif -#include "error.h" +#include "openmc/error.h" namespace openmc { diff --git a/src/initialize.cpp b/src/initialize.cpp index 62eeea409..59e13512e 100644 --- a/src/initialize.cpp +++ b/src/initialize.cpp @@ -1,4 +1,4 @@ -#include "initialize.h" +#include "openmc/initialize.h" #include #include @@ -6,15 +6,16 @@ #include #include -#include "error.h" -#include "hdf5_interface.h" -#include "message_passing.h" -#include "openmc.h" -#include "settings.h" #ifdef _OPENMP #include "omp.h" #endif +#include "openmc/capi.h" +#include "openmc/error.h" +#include "openmc/hdf5_interface.h" +#include "openmc/message_passing.h" +#include "openmc/settings.h" + // data/functions from Fortran side extern "C" void print_usage(); extern "C" void print_version(); diff --git a/src/lattice.cpp b/src/lattice.cpp index e2871d9e1..a5b56eef8 100644 --- a/src/lattice.cpp +++ b/src/lattice.cpp @@ -1,15 +1,15 @@ -#include "lattice.h" +#include "openmc/lattice.h" #include #include #include -#include "cell.h" -#include "error.h" -#include "geometry_aux.h" -#include "hdf5_interface.h" -#include "string_utils.h" -#include "xml_interface.h" +#include "openmc/cell.h" +#include "openmc/error.h" +#include "openmc/geometry_aux.h" +#include "openmc/hdf5_interface.h" +#include "openmc/string_utils.h" +#include "openmc/xml_interface.h" namespace openmc { diff --git a/src/main.cpp b/src/main.cpp index 8d8f39e24..54b78d38d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,8 +1,8 @@ -#include "error.h" #ifdef OPENMC_MPI #include "mpi.h" #endif -#include "openmc.h" +#include "openmc/capi.h" +#include "openmc/error.h" int main(int argc, char* argv[]) { diff --git a/src/material.cpp b/src/material.cpp index 409908e67..ec930f208 100644 --- a/src/material.cpp +++ b/src/material.cpp @@ -1,10 +1,10 @@ -#include "material.h" +#include "openmc/material.h" #include #include -#include "error.h" -#include "xml_interface.h" +#include "openmc/error.h" +#include "openmc/xml_interface.h" namespace openmc { diff --git a/src/math_functions.cpp b/src/math_functions.cpp index f2a5e415d..5c1a2f4dc 100644 --- a/src/math_functions.cpp +++ b/src/math_functions.cpp @@ -1,4 +1,4 @@ -#include "math_functions.h" +#include "openmc/math_functions.h" namespace openmc { @@ -608,7 +608,7 @@ void calc_zn_rad_c(int n, double rho, double zn_rad[]) { double k2 = 2 * p * (p - 1) * (p - 2); double k3 = -q * q * (p - 1) - p * (p - 1) * (p - 2); double k4 = (-p * (p + q - 2) * (p - q - 2)) / 2.; - zn_rad[index] = + zn_rad[index] = ((k2 * rho * rho + k3) * zn_rad[index-1] + k4 * zn_rad[index-2]) / k1; } } diff --git a/src/message_passing.cpp b/src/message_passing.cpp index 2ff3952d7..aac677c6e 100644 --- a/src/message_passing.cpp +++ b/src/message_passing.cpp @@ -1,4 +1,4 @@ -#include "message_passing.h" +#include "openmc/message_passing.h" namespace openmc { namespace mpi { diff --git a/src/mgxs.cpp b/src/mgxs.cpp index 3e84f6307..eb13a55f6 100644 --- a/src/mgxs.cpp +++ b/src/mgxs.cpp @@ -1,17 +1,18 @@ +#include "openmc/mgxs.h" + #include #include #include #include - #ifdef _OPENMP - # include - #endif +#ifdef _OPENMP +#include +#endif -#include "error.h" -#include "math_functions.h" -#include "random_lcg.h" -#include "string_functions.h" -#include "mgxs.h" +#include "openmc/error.h" +#include "openmc/math_functions.h" +#include "openmc/random_lcg.h" +#include "openmc/string_functions.h" namespace openmc { @@ -709,4 +710,4 @@ Mgxs::set_angle_index(const double uvw[3]) } } -} // namespace openmc \ No newline at end of file +} // namespace openmc diff --git a/src/mgxs_interface.cpp b/src/mgxs_interface.cpp index d87598779..f601f3c71 100644 --- a/src/mgxs_interface.cpp +++ b/src/mgxs_interface.cpp @@ -1,8 +1,9 @@ +#include "openmc/mgxs_interface.h" + #include -#include "error.h" -#include "math_functions.h" -#include "mgxs_interface.h" +#include "openmc/error.h" +#include "openmc/math_functions.h" namespace openmc { @@ -226,4 +227,4 @@ get_awr_c(int index) return nuclides_MG[index - 1].awr; } -} // namespace openmc \ No newline at end of file +} // namespace openmc diff --git a/src/particle.cpp b/src/particle.cpp index e46d06c01..51331cea0 100644 --- a/src/particle.cpp +++ b/src/particle.cpp @@ -1,14 +1,14 @@ -#include "particle.h" +#include "openmc/particle.h" #include #include -#include "constants.h" -#include "error.h" -#include "hdf5_interface.h" -#include "openmc.h" -#include "settings.h" -#include "simulation.h" +#include "openmc/capi.h" +#include "openmc/constants.h" +#include "openmc/error.h" +#include "openmc/hdf5_interface.h" +#include "openmc/settings.h" +#include "openmc/simulation.h" namespace openmc { diff --git a/src/plot.cpp b/src/plot.cpp index 0dca6d08c..79f04c47f 100644 --- a/src/plot.cpp +++ b/src/plot.cpp @@ -1,4 +1,4 @@ -#include "plot.h" +#include "openmc/plot.h" namespace openmc { diff --git a/src/position.cpp b/src/position.cpp index 85e511041..18ec33e80 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -1,4 +1,4 @@ -#include "position.h" +#include "openmc/position.h" namespace openmc { diff --git a/src/random_lcg.cpp b/src/random_lcg.cpp index d82738ca1..cf5d7e34b 100644 --- a/src/random_lcg.cpp +++ b/src/random_lcg.cpp @@ -1,4 +1,5 @@ -#include "random_lcg.h" +#include "openmc/random_lcg.h" + #include diff --git a/src/reaction.cpp b/src/reaction.cpp index 10e07b18a..48eca15e0 100644 --- a/src/reaction.cpp +++ b/src/reaction.cpp @@ -1,12 +1,12 @@ -#include "reaction.h" +#include "openmc/reaction.h" #include #include // for move -#include "hdf5_interface.h" -#include "endf.h" -#include "random_lcg.h" -#include "secondary_uncorrelated.h" +#include "openmc/hdf5_interface.h" +#include "openmc/endf.h" +#include "openmc/random_lcg.h" +#include "openmc/secondary_uncorrelated.h" namespace openmc { diff --git a/src/reaction_product.cpp b/src/reaction_product.cpp index ef5c746bd..7e3175343 100644 --- a/src/reaction_product.cpp +++ b/src/reaction_product.cpp @@ -1,14 +1,14 @@ -#include "reaction_product.h" +#include "openmc/reaction_product.h" #include // for unique_ptr #include // for string -#include "hdf5_interface.h" -#include "random_lcg.h" -#include "secondary_correlated.h" -#include "secondary_kalbach.h" -#include "secondary_nbody.h" -#include "secondary_uncorrelated.h" +#include "openmc/hdf5_interface.h" +#include "openmc/random_lcg.h" +#include "openmc/secondary_correlated.h" +#include "openmc/secondary_kalbach.h" +#include "openmc/secondary_nbody.h" +#include "openmc/secondary_uncorrelated.h" namespace openmc { diff --git a/src/scattdata.cpp b/src/scattdata.cpp index a316eba46..3e18c168f 100644 --- a/src/scattdata.cpp +++ b/src/scattdata.cpp @@ -1,12 +1,13 @@ +#include "openmc/scattdata.h" + #include #include #include -#include "constants.h" -#include "math_functions.h" -#include "random_lcg.h" -#include "error.h" -#include "scattdata.h" +#include "openmc/constants.h" +#include "openmc/error.h" +#include "openmc/math_functions.h" +#include "openmc/random_lcg.h" namespace openmc { diff --git a/src/secondary_correlated.cpp b/src/secondary_correlated.cpp index b1653f317..1acaf6551 100644 --- a/src/secondary_correlated.cpp +++ b/src/secondary_correlated.cpp @@ -1,16 +1,17 @@ -#include "secondary_correlated.h" +#include "openmc/secondary_correlated.h" #include // for copy #include #include // for size_t #include // for back_inserter -#include "hdf5_interface.h" #include "xtensor/xarray.hpp" #include "xtensor/xview.hpp" -#include "endf.h" -#include "random_lcg.h" -#include "search.h" + +#include "openmc/hdf5_interface.h" +#include "openmc/endf.h" +#include "openmc/random_lcg.h" +#include "openmc/search.h" namespace openmc { diff --git a/src/secondary_kalbach.cpp b/src/secondary_kalbach.cpp index e8941ff93..3e7907210 100644 --- a/src/secondary_kalbach.cpp +++ b/src/secondary_kalbach.cpp @@ -1,4 +1,4 @@ -#include "secondary_kalbach.h" +#include "openmc/secondary_kalbach.h" #include // for copy, move #include // for log, sqrt, sinh @@ -8,9 +8,10 @@ #include "xtensor/xarray.hpp" #include "xtensor/xview.hpp" -#include "hdf5_interface.h" -#include "random_lcg.h" -#include "search.h" + +#include "openmc/hdf5_interface.h" +#include "openmc/random_lcg.h" +#include "openmc/search.h" namespace openmc { diff --git a/src/secondary_nbody.cpp b/src/secondary_nbody.cpp index 44a66c6bd..45f6d3cb8 100644 --- a/src/secondary_nbody.cpp +++ b/src/secondary_nbody.cpp @@ -1,11 +1,11 @@ -#include "secondary_nbody.h" +#include "openmc/secondary_nbody.h" #include // for log -#include "constants.h" -#include "hdf5_interface.h" -#include "math_functions.h" -#include "random_lcg.h" +#include "openmc/constants.h" +#include "openmc/hdf5_interface.h" +#include "openmc/math_functions.h" +#include "openmc/random_lcg.h" namespace openmc { diff --git a/src/secondary_uncorrelated.cpp b/src/secondary_uncorrelated.cpp index df5e8139b..3192c1e04 100644 --- a/src/secondary_uncorrelated.cpp +++ b/src/secondary_uncorrelated.cpp @@ -1,11 +1,11 @@ -#include "secondary_uncorrelated.h" +#include "openmc/secondary_uncorrelated.h" #include // for stringstream #include // for string -#include "error.h" -#include "hdf5_interface.h" -#include "random_lcg.h" +#include "openmc/error.h" +#include "openmc/hdf5_interface.h" +#include "openmc/random_lcg.h" namespace openmc { diff --git a/src/settings.cpp b/src/settings.cpp index c705ef8a7..b23013c31 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -1,10 +1,10 @@ -#include "settings.h" +#include "openmc/settings.h" -#include "constants.h" -#include "error.h" -#include "openmc.h" -#include "string_utils.h" -#include "xml_interface.h" +#include "openmc/capi.h" +#include "openmc/constants.h" +#include "openmc/error.h" +#include "openmc/string_utils.h" +#include "openmc/xml_interface.h" namespace openmc { diff --git a/src/simulation.cpp b/src/simulation.cpp index e9bf81775..e1dd0ac93 100644 --- a/src/simulation.cpp +++ b/src/simulation.cpp @@ -1,4 +1,4 @@ -#include "openmc.h" +#include "openmc/capi.h" // OPENMC_RUN encompasses all the main logic where iterations are performed // over the batches, generations, and histories in a fixed source or k-eigenvalue diff --git a/src/state_point.cpp b/src/state_point.cpp index 4e6b9a9f9..1e4c8bdfd 100644 --- a/src/state_point.cpp +++ b/src/state_point.cpp @@ -1,4 +1,4 @@ -#include "state_point.h" +#include "openmc/state_point.h" #include #include @@ -6,9 +6,10 @@ #ifdef OPENMC_MPI #include "mpi.h" #endif -#include "error.h" -#include "message_passing.h" -#include "openmc.h" + +#include "openmc/capi.h" +#include "openmc/error.h" +#include "openmc/message_passing.h" namespace openmc { diff --git a/src/string_functions.cpp b/src/string_functions.cpp index f41ec40c1..f81b09aef 100644 --- a/src/string_functions.cpp +++ b/src/string_functions.cpp @@ -1,4 +1,4 @@ -#include "string_functions.h" +#include "openmc/string_functions.h" namespace openmc { @@ -27,4 +27,4 @@ void to_lower(std::string& str) for (int i = 0; i < str.size(); i++) str[i] = std::tolower(str[i]); } -} // namespace openmc \ No newline at end of file +} // namespace openmc diff --git a/src/surface.cpp b/src/surface.cpp index 421c43d48..78f2302e5 100644 --- a/src/surface.cpp +++ b/src/surface.cpp @@ -1,13 +1,13 @@ -#include "surface.h" +#include "openmc/surface.h" #include #include #include #include -#include "error.h" -#include "hdf5_interface.h" -#include "xml_interface.h" +#include "openmc/error.h" +#include "openmc/hdf5_interface.h" +#include "openmc/xml_interface.h" namespace openmc { diff --git a/src/thermal.cpp b/src/thermal.cpp index 2732b8f02..b63d2e6d1 100644 --- a/src/thermal.cpp +++ b/src/thermal.cpp @@ -1,4 +1,4 @@ -#include "thermal.h" +#include "openmc/thermal.h" #include // for sort, move, min, max, find #include // for round, sqrt, fabs @@ -11,12 +11,12 @@ #include "xtensor/xtensor.hpp" #include "xtensor/xview.hpp" -#include "constants.h" -#include "error.h" -#include "random_lcg.h" -#include "search.h" -#include "secondary_correlated.h" -#include "settings.h" +#include "openmc/constants.h" +#include "openmc/error.h" +#include "openmc/random_lcg.h" +#include "openmc/search.h" +#include "openmc/secondary_correlated.h" +#include "openmc/settings.h" namespace openmc { diff --git a/src/xml_interface.cpp b/src/xml_interface.cpp index 5835c8600..18627efe3 100644 --- a/src/xml_interface.cpp +++ b/src/xml_interface.cpp @@ -1,9 +1,9 @@ -#include "xml_interface.h" +#include "openmc/xml_interface.h" #include // for transform #include -#include "error.h" +#include "openmc/error.h" namespace openmc { diff --git a/src/xsdata.cpp b/src/xsdata.cpp index 3482a316a..d9863694a 100644 --- a/src/xsdata.cpp +++ b/src/xsdata.cpp @@ -1,13 +1,14 @@ +#include "openmc/xsdata.h" + #include #include #include #include -#include "constants.h" -#include "error.h" -#include "math_functions.h" -#include "random_lcg.h" -#include "xsdata.h" +#include "openmc/constants.h" +#include "openmc/error.h" +#include "openmc/math_functions.h" +#include "openmc/random_lcg.h" namespace openmc { From e5a9d50ab24bfb8bccbf36474a3da199f0978e9f Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 20 Aug 2018 14:55:25 -0500 Subject: [PATCH 49/56] Install include/ directory instead of single file --- CMakeLists.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 57017aa96..23a6176a8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -422,7 +422,6 @@ add_library(libopenmc SHARED src/xsdata.cpp) set_target_properties(libopenmc PROPERTIES OUTPUT_NAME openmc - PUBLIC_HEADER include/openmc/capi.h LINKER_LANGUAGE Fortran) target_include_directories(libopenmc @@ -492,8 +491,8 @@ install(TARGETS openmc libopenmc RUNTIME DESTINATION bin LIBRARY DESTINATION lib ARCHIVE DESTINATION lib - PUBLIC_HEADER DESTINATION include ) install(DIRECTORY src/relaxng DESTINATION share/openmc) install(FILES man/man1/openmc.1 DESTINATION share/man/man1) install(FILES LICENSE DESTINATION "share/doc/openmc" RENAME copyright) +install(DIRECTORY include/ DESTINATION include) From 909c43b1e4e67e8d6841fb87b583558792b5da29 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Tue, 21 Aug 2018 06:25:32 -0500 Subject: [PATCH 50/56] Look for materials.xml in same directory as geometry.xml for from_xml --- openmc/geometry.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/openmc/geometry.py b/openmc/geometry.py index 471de202b..8227b1053 100644 --- a/openmc/geometry.py +++ b/openmc/geometry.py @@ -1,6 +1,7 @@ from collections import OrderedDict, defaultdict from collections.abc import Iterable from copy import deepcopy +from pathlib import Path from xml.etree import ElementTree as ET import numpy as np @@ -237,7 +238,8 @@ class Geometry(object): # Create dictionary to easily look up materials if materials is None: - materials = openmc.Materials.from_xml() + filename = Path(path).parent / 'materials.xml' + materials = openmc.Materials.from_xml(str(filename)) mats = {str(m.id): m for m in materials} mats['void'] = None From e8b99c0a389c136f1548f7fcaa7e9fcba928fa09 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Tue, 21 Aug 2018 06:33:32 -0500 Subject: [PATCH 51/56] Make sure lattice outer universe is added to child_of --- openmc/geometry.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openmc/geometry.py b/openmc/geometry.py index 8227b1053..3a2c18311 100644 --- a/openmc/geometry.py +++ b/openmc/geometry.py @@ -167,6 +167,7 @@ class Geometry(object): outer = get(elem, 'outer') if outer is not None: lat.outer = get_universe(int(outer)) + child_of[lat.outer].append(lat) universes[lat_id] = lat # Get array of universes @@ -188,6 +189,7 @@ class Geometry(object): outer = get(elem, 'outer') if outer is not None: lat.outer = get_universe(int(outer)) + child_of[lat.outer].append(lat) universes[lat_id] = lat # Get nested lists of universes From fbf7713a335def236e6a51a74adf2ddd837825f7 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Tue, 21 Aug 2018 07:47:29 -0500 Subject: [PATCH 52/56] Split up Geometry.from_xml, rename clean_xml -> _xml --- openmc/_xml.py | 51 +++++++++++++++ openmc/cell.py | 59 +++++++++++++++++ openmc/clean_xml.py | 26 -------- openmc/cmfd.py | 4 +- openmc/data/library.py | 4 +- openmc/deplete/chain.py | 4 +- openmc/geometry.py | 138 ++++++---------------------------------- openmc/lattice.py | 109 +++++++++++++++++++++++++++++++ openmc/material.py | 4 +- openmc/plots.py | 4 +- openmc/settings.py | 4 +- openmc/tallies.py | 4 +- 12 files changed, 254 insertions(+), 157 deletions(-) create mode 100644 openmc/_xml.py delete mode 100644 openmc/clean_xml.py diff --git a/openmc/_xml.py b/openmc/_xml.py new file mode 100644 index 000000000..9c6c219e2 --- /dev/null +++ b/openmc/_xml.py @@ -0,0 +1,51 @@ +def clean_indentation(element, level=0, spaces_per_level=2): + """ + copy and paste from http://effbot.org/zone/elementent-lib.htm#prettyprint + it basically walks your tree and adds spaces and newlines so the tree is + printed in a nice way + """ + + i = "\n" + level*spaces_per_level*" " + + if len(element): + + if not element.text or not element.text.strip(): + element.text = i + spaces_per_level*" " + + if not element.tail or not element.tail.strip(): + element.tail = i + + for sub_element in element: + clean_indentation(sub_element, level+1, spaces_per_level) + + if not sub_element.tail or not sub_element.tail.strip(): + sub_element.tail = i + + else: + if level and (not element.tail or not element.tail.strip()): + element.tail = i + + +def get_text(elem, name, default=None): + """Retrieve text of an attribute or subelement. + + Parameters + ---------- + elem : xml.etree.ElementTree.Element + Element from which to search + name : str + Name of attribute/subelement + default : object + A defult value to return if matching attribute/subelement exists + + Returns + ------- + str + Text of attribute or subelement + + """ + if name in elem.attrib: + return elem.get(name, default) + else: + child = elem.find(name) + return child.text if child is not None else default diff --git a/openmc/cell.py b/openmc/cell.py index cbfd74b21..492bdeeb6 100644 --- a/openmc/cell.py +++ b/openmc/cell.py @@ -13,6 +13,7 @@ import openmc import openmc.checkvalue as cv from openmc.surface import Halfspace from openmc.region import Region, Intersection, Complement +from openmc._xml import get_text from .mixin import IDManagerMixin @@ -522,3 +523,61 @@ class Cell(IDManagerMixin): element.set("rotation", ' '.join(map(str, self.rotation))) return element + + @classmethod + def from_xml_element(cls, elem, surfaces, materials, get_universe): + """Generate cell from XML element + + Parameters + ---------- + elem : xml.etree.ElementTree.Element + `` element + surfaces : dict + Dictionary mapping surface IDs to :class:`openmc.Surface` instances + materials : dict + Dictionary mapping material IDs to :class:`openmc.Material` + instances (defined in :math:`openmc.Geometry.from_xml`) + get_universe : function + Function returning universe (defined in + :meth:`openmc.Geometry.from_xml`) + + Returns + ------- + Cell + Cell instance + + """ + cell_id = int(get_text(elem, 'id')) + name = get_text(elem, 'name') + c = cls(cell_id, name) + + # Assign material/distributed materials or fill + mat_text = get_text(elem, 'material') + if mat_text is not None: + mat_ids = mat_text.split() + if len(mat_ids) > 1: + c.fill = [materials[i] for i in mat_ids] + else: + c.fill = materials[mat_ids[0]] + else: + fill_id = int(get_text(elem, 'fill')) + c.fill = get_universe(fill_id) + + # Assign region + region = get_text(elem, 'region') + if region is not None: + c.region = Region.from_expression(region, surfaces) + + # Check for other attributes + t = get_text(elem, 'temperature') + if t is not None: + c.temperature = float(t) + for key in ('temperature', 'rotation', 'translation'): + value = get_text(elem, key) + if value is not None: + setattr(c, key, [float(x) for x in value.split()]) + + # Add this cell to appropriate universe + univ_id = int(get_text(elem, 'universe', 0)) + get_universe(univ_id).add_cell(c) + return c diff --git a/openmc/clean_xml.py b/openmc/clean_xml.py deleted file mode 100644 index d1002070b..000000000 --- a/openmc/clean_xml.py +++ /dev/null @@ -1,26 +0,0 @@ -def clean_xml_indentation(element, level=0, spaces_per_level=2): - """ - copy and paste from http://effbot.org/zone/elementent-lib.htm#prettyprint - it basically walks your tree and adds spaces and newlines so the tree is - printed in a nice way - """ - - i = "\n" + level*spaces_per_level*" " - - if len(element): - - if not element.text or not element.text.strip(): - element.text = i + spaces_per_level*" " - - if not element.tail or not element.tail.strip(): - element.tail = i - - for sub_element in element: - clean_xml_indentation(sub_element, level+1, spaces_per_level) - - if not sub_element.tail or not sub_element.tail.strip(): - sub_element.tail = i - - else: - if level and (not element.tail or not element.tail.strip()): - element.tail = i diff --git a/openmc/cmfd.py b/openmc/cmfd.py index 5444334b2..c156cd00a 100644 --- a/openmc/cmfd.py +++ b/openmc/cmfd.py @@ -15,7 +15,7 @@ from numbers import Real, Integral from xml.etree import ElementTree as ET import sys -from openmc.clean_xml import clean_xml_indentation +from openmc._xml import clean_indentation from openmc.checkvalue import (check_type, check_length, check_value, check_greater_than, check_less_than) @@ -512,7 +512,7 @@ class CMFD(object): self._create_write_matrices_subelement() # Clean the indentation in the file to be user-readable - clean_xml_indentation(self._cmfd_file) + clean_indentation(self._cmfd_file) # Write the XML Tree to the cmfd.xml file tree = ET.ElementTree(self._cmfd_file) diff --git a/openmc/data/library.py b/openmc/data/library.py index 58e5e4e16..8d821e49f 100644 --- a/openmc/data/library.py +++ b/openmc/data/library.py @@ -4,7 +4,7 @@ import xml.etree.ElementTree as ET import h5py from openmc.mixin import EqualityMixin -from openmc.clean_xml import clean_xml_indentation +from openmc._xml import clean_indentation from openmc.checkvalue import check_type @@ -95,7 +95,7 @@ class DataLibrary(EqualityMixin): lib_element.set('type', library['type']) # Clean the indentation to be user-readable - clean_xml_indentation(root) + clean_indentation(root) # Write XML file tree = ET.ElementTree(root) diff --git a/openmc/deplete/chain.py b/openmc/deplete/chain.py index 1826ca9ca..4635d99d1 100644 --- a/openmc/deplete/chain.py +++ b/openmc/deplete/chain.py @@ -23,7 +23,7 @@ except ImportError: import scipy.sparse as sp import openmc.data -from openmc.clean_xml import clean_xml_indentation +from openmc._xml import clean_indentation from .nuclide import Nuclide, DecayTuple, ReactionTuple @@ -356,7 +356,7 @@ class Chain(object): if _have_lxml: tree.write(str(filename), encoding='utf-8', pretty_print=True) else: - clean_xml_indentation(root_elem) + clean_indentation(root_elem) tree.write(str(filename), encoding='utf-8') def form_matrix(self, rates): diff --git a/openmc/geometry.py b/openmc/geometry.py index 3a2c18311..4cbc60c24 100644 --- a/openmc/geometry.py +++ b/openmc/geometry.py @@ -7,7 +7,7 @@ from xml.etree import ElementTree as ET import numpy as np import openmc -from openmc.clean_xml import clean_xml_indentation +import openmc._xml as xml from openmc.checkvalue import check_type @@ -95,7 +95,7 @@ class Geometry(object): x.tag, int(x.get('id')))) # Clean the indentation in the file to be user-readable - clean_xml_indentation(root_element) + xml.clean_indentation(root_element) # Write the XML Tree to the geometry.xml file tree = ET.ElementTree(root_element) @@ -119,14 +119,6 @@ class Geometry(object): Geometry object """ - # Helper function to get value from an attribute/element - def get(elem, name, default=None): - if name in elem.attrib: - return elem.get(name, default) - else: - child = elem.find(name) - return child.text if child is not None else default - # Helper function for keeping a cache of Universe instances universes = {} def get_universe(univ_id): @@ -146,7 +138,7 @@ class Geometry(object): surfaces[s.id] = s # Check for periodic surface - other_id = get(surface, 'periodic_surface_id') + other_id = xml.get_text(surface, 'periodic_surface_id') if other_id is not None: periodic[s.id] = int(other_id) @@ -159,84 +151,27 @@ class Geometry(object): child_of = defaultdict(list) for elem in root.findall('lattice'): - lat_id = int(get(elem, 'id')) - name = get(elem, 'name') - lat = openmc.RectLattice(lat_id, name) - lat.lower_left = [float(i) for i in get(elem, 'lower_left').split()] - lat.pitch = [float(i) for i in get(elem, 'pitch').split()] - outer = get(elem, 'outer') - if outer is not None: - lat.outer = get_universe(int(outer)) + lat = openmc.RectLattice.from_xml_element(elem, get_universe) + universes[lat.id] = lat + if lat.outer is not None: child_of[lat.outer].append(lat) - universes[lat_id] = lat - - # Get array of universes - dimension = get(elem, 'dimension').split() - shape = np.array(dimension, dtype=int)[::-1] - uarray = np.array([get_universe(int(i)) for i in - get(elem, 'universes').split()]) - for u in uarray: + for u in lat.universes.ravel(): child_of[u].append(lat) - uarray.shape = shape - lat.universes = uarray for elem in root.findall('hex_lattice'): - lat_id = int(get(elem, 'id')) - name = get(elem, 'name') - lat = openmc.HexLattice(lat_id, name) - lat.center = [float(i) for i in get(elem, 'center').split()] - lat.pitch = [float(i) for i in get(elem, 'pitch').split()] - outer = get(elem, 'outer') - if outer is not None: - lat.outer = get_universe(int(outer)) + lat = openmc.HexLattice.from_xml_element(elem, get_universe) + universes[lat.id] = lat + if lat.outer is not None: child_of[lat.outer].append(lat) - universes[lat_id] = lat - - # Get nested lists of universes - lat._num_rings = n_rings = int(get(elem, 'n_rings')) - lat._num_axial = n_axial = int(get(elem, 'n_axial', 1)) - - # Create empty nested lists for one axial level - univs = [[None for _ in range(max(6*(n_rings - 1 - r), 1))] - for r in range(n_rings)] - if n_axial > 1: - univs = [deepcopy(univs) for i in range(n_axial)] - - # Get flat array of universes numbers - uarray = np.array([get_universe(int(i)) for i in - get(elem, 'universes').split()]) - for u in uarray: - child_of[u].append(lat) - - # Fill nested lists - j = 0 - for z in range(n_axial): - # Get list for a single axial level - axial_level = univs[z] if n_axial > 1 else univs - - # Start iterating from top - x, alpha = 0, n_rings - 1 - while True: - # Set entry in list based on (x,alpha,z) coordinates - _, i_ring, i_within = lat.get_universe_index((x, alpha, z)) - axial_level[i_ring][i_within] = uarray[j] - - # Move to the right - x += 2 - alpha -= 1 - if not lat.is_valid_index((x, alpha, z)): - # Move down in y direction - alpha += x - 1 - x = 1 - x - if not lat.is_valid_index((x, alpha, z)): - # Move to the right - x += 2 - alpha -= 1 - if not lat.is_valid_index((x, alpha, z)): - # Reached the bottom - break - j += 1 - lat.universes = univs + if lat.ndim == 2: + for ring in lat.universes: + for u in ring: + child_of[u].append(lat) + else: + for axial_slice in lat.universes: + for ring in axial_slice: + for u in ring: + child_of[u].append(lat) # Create dictionary to easily look up materials if materials is None: @@ -246,41 +181,10 @@ class Geometry(object): mats['void'] = None for elem in root.findall('cell'): - cell_id = int(get(elem, 'id')) - name = get(elem, 'name') - c = openmc.Cell(cell_id, name) - - # Assign material/distributed materials or fill - mat_text = get(elem, 'material') - if mat_text is not None: - mat_ids = mat_text.split() - if len(mat_ids) > 1: - c.fill = [mats[i] for i in mat_ids] - else: - c.fill = mats[mat_ids[0]] - else: - fill_id = int(get(elem, 'fill')) - c.fill = get_universe(fill_id) + c = openmc.Cell.from_xml_element(elem, surfaces, mats, get_universe) + if c.fill_type in ('universe', 'lattice'): child_of[c.fill].append(c) - # Assign region - region = get(elem, 'region') - if region is not None: - c.region = openmc.Region.from_expression(region, surfaces) - - # Check for other attributes - t = get(elem, 'temperature') - if t is not None: - c.temperature = float(t) - for key in ('temperature', 'rotation', 'translation'): - value = get(elem, key) - if value is not None: - setattr(c, key, [float(x) for x in value.split()]) - - # Add this cell to appropriate universe - univ_id = int(get(elem, 'universe', 0)) - get_universe(univ_id).add_cell(c) - # Determine which universe is the root by finding one which is not a # child of any other object for u in universes.values(): diff --git a/openmc/lattice.py b/openmc/lattice.py index ef33247fc..8bf4e4757 100644 --- a/openmc/lattice.py +++ b/openmc/lattice.py @@ -10,6 +10,7 @@ import numpy as np import openmc.checkvalue as cv import openmc +from openmc._xml import get_text from openmc.mixin import IDManagerMixin @@ -768,6 +769,42 @@ class RectLattice(Lattice): # Append the XML subelement for this Lattice to the XML element xml_element.append(lattice_subelement) + @classmethod + def from_xml_element(cls, elem, get_universe): + """Generate rectangular lattice from XML element + + Parameters + ---------- + elem : xml.etree.ElementTree.Element + `` element + get_universe : function + Function returning universe (defined in + :meth:`openmc.Geometry.from_xml`) + + Returns + ------- + RectLattice + Rectangular lattice + + """ + lat_id = int(get_text(elem, 'id')) + name = get_text(elem, 'name') + lat = cls(lat_id, name) + lat.lower_left = [float(i) for i in get_text(elem, 'lower_left').split()] + lat.pitch = [float(i) for i in get_text(elem, 'pitch').split()] + outer = get_text(elem, 'outer') + if outer is not None: + lat.outer = get_universe(int(outer)) + + # Get array of universes + dimension = get_text(elem, 'dimension').split() + shape = np.array(dimension, dtype=int)[::-1] + uarray = np.array([get_universe(int(i)) for i in + get_text(elem, 'universes').split()]) + uarray.shape = shape + lat.universes = uarray + return lat + class HexLattice(Lattice): r"""A lattice consisting of hexagonal prisms. @@ -1207,6 +1244,78 @@ class HexLattice(Lattice): # Append the XML subelement for this Lattice to the XML element xml_element.append(lattice_subelement) + @classmethod + def from_xml_element(cls, elem, get_universe): + """Generate hexagonal lattice from XML element + + Parameters + ---------- + elem : xml.etree.ElementTree.Element + `` element + get_universe : function + Function returning universe (defined in + :meth:`openmc.Geometry.from_xml`) + + Returns + ------- + HexLattice + Hexagonal lattice + + """ + lat_id = int(get_text(elem, 'id')) + name = get_text(elem, 'name') + lat = cls(lat_id, name) + lat.center = [float(i) for i in get_text(elem, 'center').split()] + lat.pitch = [float(i) for i in get_text(elem, 'pitch').split()] + outer = get_text(elem, 'outer') + if outer is not None: + lat.outer = get_universe(int(outer)) + + # Get nested lists of universes + lat._num_rings = n_rings = int(get_text(elem, 'n_rings')) + lat._num_axial = n_axial = int(get_text(elem, 'n_axial', 1)) + + # Create empty nested lists for one axial level + univs = [[None for _ in range(max(6*(n_rings - 1 - r), 1))] + for r in range(n_rings)] + if n_axial > 1: + univs = [deepcopy(univs) for i in range(n_axial)] + + # Get flat array of universes numbers + uarray = np.array([get_universe(int(i)) for i in + get_text(elem, 'universes').split()]) + + # Fill nested lists + j = 0 + for z in range(n_axial): + # Get list for a single axial level + axial_level = univs[z] if n_axial > 1 else univs + + # Start iterating from top + x, alpha = 0, n_rings - 1 + while True: + # Set entry in list based on (x,alpha,z) coordinates + _, i_ring, i_within = lat.get_universe_index((x, alpha, z)) + axial_level[i_ring][i_within] = uarray[j] + + # Move to the right + x += 2 + alpha -= 1 + if not lat.is_valid_index((x, alpha, z)): + # Move down in y direction + alpha += x - 1 + x = 1 - x + if not lat.is_valid_index((x, alpha, z)): + # Move to the right + x += 2 + alpha -= 1 + if not lat.is_valid_index((x, alpha, z)): + # Reached the bottom + break + j += 1 + lat.universes = univs + return lat + def _repr_axial_slice(self, universes): """Return string representation for the given 2D group of universes. diff --git a/openmc/material.py b/openmc/material.py index d19a5f4b9..4ba4f0306 100644 --- a/openmc/material.py +++ b/openmc/material.py @@ -9,7 +9,7 @@ import numpy as np import openmc import openmc.data import openmc.checkvalue as cv -from openmc.clean_xml import clean_xml_indentation +from openmc._xml import clean_indentation from .mixin import IDManagerMixin @@ -1076,7 +1076,7 @@ class Materials(cv.CheckedList): self._create_material_subelements(root_element) # Clean the indentation in the file to be user-readable - clean_xml_indentation(root_element) + clean_indentation(root_element) # Write the XML Tree to the materials.xml file tree = ET.ElementTree(root_element) diff --git a/openmc/plots.py b/openmc/plots.py index 8eff78b1d..f99392def 100644 --- a/openmc/plots.py +++ b/openmc/plots.py @@ -9,7 +9,7 @@ import numpy as np import openmc import openmc.checkvalue as cv -from openmc.clean_xml import clean_xml_indentation +from openmc._xml import clean_indentation from openmc.mixin import IDManagerMixin @@ -816,7 +816,7 @@ class Plots(cv.CheckedList): self._create_plot_subelements() # Clean the indentation in the file to be user-readable - clean_xml_indentation(self._plots_file) + clean_indentation(self._plots_file) # Write the XML Tree to the plots.xml file tree = ET.ElementTree(self._plots_file) diff --git a/openmc/settings.py b/openmc/settings.py index 7629ea9af..efe41b2a1 100644 --- a/openmc/settings.py +++ b/openmc/settings.py @@ -6,7 +6,7 @@ import sys import numpy as np -from openmc.clean_xml import clean_xml_indentation +from openmc._xml import clean_indentation import openmc.checkvalue as cv from openmc import VolumeCalculation, Source, Mesh @@ -994,7 +994,7 @@ class Settings(object): self._create_log_grid_bins_subelement(root_element) # Clean the indentation in the file to be user-readable - clean_xml_indentation(root_element) + clean_indentation(root_element) # Write the XML Tree to the settings.xml file tree = ET.ElementTree(root_element) diff --git a/openmc/tallies.py b/openmc/tallies.py index 74f342903..1e4b142fe 100644 --- a/openmc/tallies.py +++ b/openmc/tallies.py @@ -15,7 +15,7 @@ import h5py import openmc import openmc.checkvalue as cv -from openmc.clean_xml import clean_xml_indentation +from openmc._xml import clean_indentation from .mixin import IDManagerMixin @@ -3187,7 +3187,7 @@ class Tallies(cv.CheckedList): self._create_derivative_subelements(root_element) # Clean the indentation in the file to be user-readable - clean_xml_indentation(root_element) + clean_indentation(root_element) # Write the XML Tree to the tallies.xml file tree = ET.ElementTree(root_element) From 058ceda821fff5f14ae2c95fbbaaac04ab5cd9b8 Mon Sep 17 00:00:00 2001 From: Zhuoran Han Date: Tue, 21 Aug 2018 10:16:06 -0500 Subject: [PATCH 53/56] Change based on suggestion --- openmc/polynomial.py | 10 +++++----- tests/unit_tests/test_polynomials.py | 2 -- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/openmc/polynomial.py b/openmc/polynomial.py index d26d7edf8..b12065997 100644 --- a/openmc/polynomial.py +++ b/openmc/polynomial.py @@ -3,8 +3,8 @@ import openmc import openmc.capi as capi -def legendre_from_expcoef(coef, domain= [-1,1]): - """Return a Legendre object. +def legendre_from_expcoef(coef, domain= (-1,1)): + """Return a Legendre series object based on expansion coefficients. Given a list of coefficients from FET tally and a array of down, return the numpy Legendre object. @@ -18,8 +18,8 @@ def legendre_from_expcoef(coef, domain= [-1,1]): Returns ------- - Legendre class - A numpy Legendre series object + numpy.polynomial.Legendre + A numpy Legendre series class """ @@ -36,7 +36,7 @@ class Polynomial(object): class ZernikeRadial(Polynomial): - """Create radial only Zernike polynomials given coefficients and domian. + """Create radial only Zernike polynomials given coefficients and domain. The radial only Zernike polynomials are defined as in :class:`ZernikeRadialFilter`. diff --git a/tests/unit_tests/test_polynomials.py b/tests/unit_tests/test_polynomials.py index 4ce767d2e..52c30bb00 100644 --- a/tests/unit_tests/test_polynomials.py +++ b/tests/unit_tests/test_polynomials.py @@ -1,8 +1,6 @@ import numpy as np -import scipy as sp import openmc -import openmc.capi def test_zernike_radial(): From dcf6cfe0a1ae399ead325d947f3be74e9e263e45 Mon Sep 17 00:00:00 2001 From: Zhuoran Han Date: Tue, 21 Aug 2018 10:21:01 -0500 Subject: [PATCH 54/56] Change docs --- docs/source/pythonapi/base.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/source/pythonapi/base.rst b/docs/source/pythonapi/base.rst index 497b8fc3d..84bb3cc54 100644 --- a/docs/source/pythonapi/base.rst +++ b/docs/source/pythonapi/base.rst @@ -178,8 +178,7 @@ Post-processing openmc.StatePoint openmc.Summary -Polynomial ---------------- +The following classes and functions are used for functional expansion reconstruction. .. autosummary:: :toctree: generated From 826557cb31db781c30fec7957de23b76e90b8b53 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Tue, 21 Aug 2018 15:05:44 -0500 Subject: [PATCH 55/56] Use coveralls parallel build webhook --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index f61fa1db0..00f037021 100644 --- a/.travis.yml +++ b/.travis.yml @@ -28,11 +28,14 @@ env: - OPENMC_MULTIPOLE_LIBRARY=$HOME/multipole_lib - PATH=$PATH:$HOME/NJOY2016/build - DISPLAY=:99.0 + - COVERALLS_PARALLEL=true matrix: - OMP=n MPI=n PHDF5=n - OMP=y MPI=n PHDF5=n - OMP=n MPI=y PHDF5=n - OMP=n MPI=y PHDF5=y +notifications: + webhooks: https://coveralls.io/webhook?repo_token=$COVERALLS_REPO_TOKEN install: - ./tools/ci/travis-install.sh before_script: From 0cf903cc67af4267a8216535fc2fa6a61f4341a1 Mon Sep 17 00:00:00 2001 From: liangjg Date: Thu, 23 Aug 2018 09:10:21 -0700 Subject: [PATCH 56/56] update nuclear-data.ipynb --- examples/jupyter/nuclear-data.ipynb | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/examples/jupyter/nuclear-data.ipynb b/examples/jupyter/nuclear-data.ipynb index 7087681a0..726de6f3e 100644 --- a/examples/jupyter/nuclear-data.ipynb +++ b/examples/jupyter/nuclear-data.ipynb @@ -1466,7 +1466,7 @@ }, "outputs": [], "source": [ - "url = 'https://anl.box.com/shared/static/ulhcoohm12gduwdalknmf8dpnepzkxj0.h5'\n", + "url = 'https://github.com/mit-crpg/WMP_Library/releases/download/v1.0/092238.h5'\n", "filename, headers = urllib.request.urlretrieve(url, '092238.h5')" ] }, @@ -1485,7 +1485,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "The `WindowedMultipole` object can be called with energy and temperature values. Calling the object gives a tuple of 3 cross sections: total, radiative capture, and fission." + "The `WindowedMultipole` object can be called with energy and temperature values. Calling the object gives a tuple of 3 cross sections: elastic scattering, radiative capture, and fission." ] }, { @@ -1498,9 +1498,7 @@ { "data": { "text/plain": [ - "(array(9.638243132516015),\n", - " array(0.5053244245010787),\n", - " array(2.931753364280356e-06))" + "(array(9.13284265), array(0.50530278), array(2.9316765e-06))" ] }, "execution_count": 43,