From e17687d457945136c6c632d409b54f8c9556a2bd Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Thu, 19 Sep 2019 09:18:26 -0500 Subject: [PATCH 001/158] Add openmc::Tally.writeable_ attribute Boolean flag that indicates if a tally should be written to output files. This has no effect on tally scoring, but instead will be used to skip writing Tally data for those not marked as writeable. Related to #1327 as the depletion interface will use this flag to reduce time spent writing reaction rate tallies and also reducing the size of the final statepoint files --- include/openmc/tallies/tally.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/openmc/tallies/tally.h b/include/openmc/tallies/tally.h index 2a166738d..0b0baeb8c 100644 --- a/include/openmc/tallies/tally.h +++ b/include/openmc/tallies/tally.h @@ -98,6 +98,9 @@ public: //! (e.g. specific cell, specific energy group, etc.) xt::xtensor results_; + //! True if this tally should be written to statepoint files + bool writeable_ {true}; + //---------------------------------------------------------------------------- // Miscellaneous public members. From 0fc57b207b712cd7e9a01a5a188fe3f30571c11a Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Thu, 19 Sep 2019 10:06:58 -0500 Subject: [PATCH 002/158] Teach output write_tallies about writeable tallies The tally header will still be written, but no summary, scores, or filters will be written. Instead, the output will indicate the tally is internal. --- src/output.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/output.cpp b/src/output.cpp index 40cd1dbfe..439fc1558 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -638,6 +638,16 @@ write_tallies() for (auto i_tally = 0; i_tally < model::tallies.size(); ++i_tally) { const auto& tally {*model::tallies[i_tally]}; + // Write header block. + std::string tally_header("TALLY " + std::to_string(tally.id_)); + if (!tally.name_.empty()) tally_header += ": " + tally.name_; + tallies_out << header(tally_header) << "\n\n"; + + if (!tally.writeable_) { + tallies_out << " Internal\n\n"; + continue; + } + // Calculate t-value for confidence intervals double t_value = 1; if (settings::confidence_intervals) { @@ -645,11 +655,6 @@ write_tallies() t_value = t_percentile(1 - alpha*0.5, tally.n_realizations_ - 1); } - // Write header block. - std::string tally_header("TALLY " + std::to_string(tally.id_)); - if (!tally.name_.empty()) tally_header += ": " + tally.name_; - tallies_out << header(tally_header) << "\n\n"; - // Write derivative information. if (tally.deriv_ != C_NONE) { const auto& deriv {model::tally_derivs[tally.deriv_]}; From 07d3207d88ca5c0c8752ae81f0fb8794df298188 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Thu, 19 Sep 2019 08:50:42 -0500 Subject: [PATCH 003/158] Provide class-based CRAM solvers CRAM16 and CRAM48 are now aliases for __call__ methods on two new classes: openmc.deplete.cram.Cram16Solver and Cram48Solver. These are two concrete subclasses of openmc.deplete.abc.IPFCramSolver and openmc.deplete.abc.DepSystemSolver abstract classes. The primary benefit of the class based approach is that the 16th and 48th order have nearly identical implementations. The only differences are the alpha, theta, and alpha_0 coefficients used. This allows both the Cram16Solver and Cram48Solver to have unique sets of coefficient vectors, while relying on the IPFSolver base class implementation. The implementation of IPF CRAM has been cleaned up. The NxN identity matrix is not re-created each iteration. Given the alpha and theta attributes on the IPFCramSolver instances, one can iterate through the orders using a zip command. By forcing concrete classes to declared alpha and theta vectors, the need to re-declare the vectors at each entrance into CRAM48 is also removed. Using these classes, a 10% speedup is observed depleting up to 500 materials on a single MPI process. The function-based approach took 62s, while the new classes required 52s. --- openmc/deplete/abc.py | 117 +++++++++++++++++- openmc/deplete/cram.py | 271 +++++++++++++++++++++++------------------ 2 files changed, 267 insertions(+), 121 deletions(-) diff --git a/openmc/deplete/abc.py b/openmc/deplete/abc.py index 565b9e2dc..b42aa3e74 100644 --- a/openmc/deplete/abc.py +++ b/openmc/deplete/abc.py @@ -14,7 +14,9 @@ from copy import deepcopy from warnings import warn from numbers import Real, Integral -from numpy import nonzero, empty, asarray +from numpy import nonzero, empty, asarray, float64, real +import scipy.sparse as sp +import scipy.sparse.linalg as sla from uncertainties import ufloat from openmc.data import DataLibrary, JOULE_PER_EV @@ -855,3 +857,116 @@ class SIIntegrator(Integrator): Results.save(self.operator, [conc], [res_list[-1]], [t, t], p, self._i_res + len(self), proc_time) self.operator.write_bos_data(self._i_res + len(self)) + + +class DepSystemSolver(ABC): + r"""Abstract class for solving depletion equations + + Responsible for solving + + .. math:: + + \frac{\partial \vec{N}}{\partial t} = \bar{A}\vec{N}(t), + + for :math:`0< t\leq t +\Delta t`, given :math:`\vec{N}(0) = \vec{N}_0` + + """ + + @abstractmethod + def __call__(self, A, n0, dt): + """Solve the linear system of equations for depletion + + Parameters + ---------- + A : scipy.sparse.csr_matrix + Sparse transmutation matrix ``A[j, i]`` desribing rates at + which isotope ``i`` transmutes to isotope ``j`` + n0 : numpy.ndarray + Initial compositions, typically given in number of atoms in some + material or an atom density + dt : float + Time [s] of the specific interval to be solved + + Returns + ------- + numpy.ndarray + Final compositions after ``dt``. Should be of identical shape + to ``n0``. + + """ + + +class IPFCramSolver(DepSystemSolver): + r"""Abstract class that implements the IPF form of CRAM + + Provides a :meth:`__call__` that utilizes an incomplete + partial factorization (IPF) for the Chebyshev Rational Approximation + Method (CRAM) [Pusa16]_ + + Concrete subclasses must provide two complex vectors :attr:`alpha` + and :attr:`theta` that make up the coefficients of the decompostion. + Vectors are expected to be of equal length ``N``. + Subclases are also expected to provide a coefficient :attr:`alpha0` + used in the final scaling step. + + Attributes + ---------- + alpha : numpy.ndarray + Complex residues of poles :attr:`theta` in the incomplete partial + factorization. Denoted as :math:`\tilde{\alpha}` + theta : numpy.ndarray + Complex poles :math:`\theta` of the rational approximation + alpha0 : float + Limit of the approximation at infinity + + References + ---------- + + .. [Pusa16] M. Pusa, "Higher-Order Chebyshev Rational Approximation + Method and Application to Burnup Equations," Nuclear Science And + Engineering, 182:3,297-318 + `DOI: 10.13182/NSE15-26 `_ + + """ + + @property + @abstractmethod + def alpha(self): + pass + + @property + @abstractmethod + def theta(self): + pass + + @property + @abstractmethod + def alpha0(self): + pass + + def __call__(self, A, n0, dt): + """Solve depletion equations using IPF CRAM + + Parameters + ---------- + A : scipy.sparse.csr_matrix + Sparse transmutation matrix ``A[j, i]`` desribing rates at + which isotope ``i`` transmutes to isotope ``j`` + n0 : numpy.ndarray + Initial compositions, typically given in number of atoms in some + material or an atom density + dt : float + Time [s] of the specific interval to be solved + + Returns + ------- + numpy.ndarray + Final compositions after ``dt`` + + """ + A = sp.csr_matrix(A * dt, dtype=float64) + y = asarray(n0, dtype=float64) + ident = sp.eye(A.shape[0]) + for alpha, theta in zip(self.alpha, self.theta): + y += 2*real(alpha*sla.spsolve(A - theta*ident, y)) + return y * self.alpha0 diff --git a/openmc/deplete/cram.py b/openmc/deplete/cram.py index 31049bb72..4fdba87bf 100644 --- a/openmc/deplete/cram.py +++ b/openmc/deplete/cram.py @@ -8,10 +8,12 @@ from multiprocessing import Pool import time import numpy as np -import scipy.sparse as sp -import scipy.sparse.linalg as sla -from . import comm +from .abc import IPFCramSolver + +__all__ = [ + "deplete", "timed_deplete", "CRAM16", "CRAM48", + "Cram16Solver", "Cram48Solver"] def deplete(chain, x, rates, dt, matrix_func=None): @@ -81,147 +83,176 @@ def timed_deplete(*args, **kwargs): return time.time() - start, results -def CRAM16(A, n0, dt): - """Chebyshev Rational Approximation Method, order 16 +class Cram16Solver(IPFCramSolver): + r"""Solver implementing the 16th order IPF CRAM - Algorithm is the 16th order Chebyshev Rational Approximation Method, - implemented in the more stable `incomplete partial fraction (IPF) - `_ form. + Coefficients to :attr:`alpha`, :attr:`theta`, and :attr:`alpha0` + are from Table A.IV in [Pusa16]_. - Parameters + Attributes ---------- - A : scipy.linalg.csr_matrix - Matrix to take exponent of. - n0 : numpy.array - Vector to operate a matrix exponent on. - dt : float - Time to integrate to. - - Returns - ------- - numpy.array - Results of the matrix exponent. + alpha : numpy.ndarray + Complex residues of poles :attr:`theta` in the incomplete partial + factorization. Denoted as :math:`\tilde{\alpha}` + in Algorithm 1 of [Pusa16]_ + theta : numpy.ndarray + Complex poles :math:`\theta` of the rational approximation + alpha0 : float + Limit of the approximation at infinity """ + alpha = np.array([ + +5.464930576870210e+3 - 3.797983575308356e+4j, + +9.045112476907548e+1 - 1.115537522430261e+3j, + +2.344818070467641e+2 - 4.228020157070496e+2j, + +9.453304067358312e+1 - 2.951294291446048e+2j, + +7.283792954673409e+2 - 1.205646080220011e+5j, + +3.648229059594851e+1 - 1.155509621409682e+2j, + +2.547321630156819e+1 - 2.639500283021502e+1j, + +2.394538338734709e+1 - 5.650522971778156e+0j], + dtype=np.complex128) - alpha = np.array([+2.124853710495224e-16, - +5.464930576870210e+3 - 3.797983575308356e+4j, - +9.045112476907548e+1 - 1.115537522430261e+3j, - +2.344818070467641e+2 - 4.228020157070496e+2j, - +9.453304067358312e+1 - 2.951294291446048e+2j, - +7.283792954673409e+2 - 1.205646080220011e+5j, - +3.648229059594851e+1 - 1.155509621409682e+2j, - +2.547321630156819e+1 - 2.639500283021502e+1j, - +2.394538338734709e+1 - 5.650522971778156e+0j], - dtype=np.complex128) - theta = np.array([+0.0, - +3.509103608414918 + 8.436198985884374j, - +5.948152268951177 + 3.587457362018322j, - -5.264971343442647 + 16.22022147316793j, - +1.419375897185666 + 10.92536348449672j, - +6.416177699099435 + 1.194122393370139j, - +4.993174737717997 + 5.996881713603942j, - -1.413928462488886 + 13.49772569889275j, - -10.84391707869699 + 19.27744616718165j], - dtype=np.complex128) - - n = A.shape[0] + theta = np.array([ + +3.509103608414918 + 8.436198985884374j, + +5.948152268951177 + 3.587457362018322j, + -5.264971343442647 + 16.22022147316793j, + +1.419375897185666 + 10.92536348449672j, + +6.416177699099435 + 1.194122393370139j, + +4.993174737717997 + 5.996881713603942j, + -1.413928462488886 + 13.49772569889275j, + -10.84391707869699 + 19.27744616718165j], + dtype=np.complex128) alpha0 = 2.124853710495224e-16 - k = 8 + def __call__(self, A, n0, dt): + """Solve using 16th order IPF CRAM [Pusa16]_ - y = np.array(n0, dtype=np.float64) - for l in range(1, k+1): - y = 2.0*np.real(alpha[l]*sla.spsolve(A*dt - theta[l]*sp.eye(n), y)) + y + Parameters + ---------- + A : scipy.sparse.csr_matrix + Sparse transmutation matrix ``A[j, i]`` desribing rates at + which isotope ``i`` transmutes to isotope ``j`` + n0 : numpy.ndarray + Initial compositions, typically given in number of atoms in some + material or an atom density + dt : float + Time [s] of the specific interval to be solved - y *= alpha0 - return y + Returns + ------- + numpy.ndarray + Final compositions after ``dt`` + + """ + return super().__call__(A, n0, dt) -def CRAM48(A, n0, dt): - """Chebyshev Rational Approximation Method, order 48 +class Cram48Solver(IPFCramSolver): + r"""Solver implementing the 48th order IPF CRAM - Algorithm is the 48th order Chebyshev Rational Approximation Method, - implemented in the more stable `incomplete partial fraction (IPF) - `_ form. + Coefficients to :attr:`alpha`, :attr:`theta`, and :attr:`alpha0` + are from Table A.XII in [Pusa16]_. - Parameters + Attributes ---------- - A : scipy.linalg.csr_matrix - Matrix to take exponent of. - n0 : numpy.array - Vector to operate a matrix exponent on. - dt : float - Time to integrate to. - - Returns - ------- - numpy.array - Results of the matrix exponent. + alpha : numpy.ndarray + Complex residues of poles :attr:`theta` in the incomplete partial + factorization. Denoted as :math:`\tilde{\alpha}` + in Algorithm 1 of [Pusa16]_ + theta : numpy.ndarray + Complex poles :math:`\theta` of the rational approximation + alpha0 : float + Limit of the approximation at infinity """ - theta_r = np.array([-4.465731934165702e+1, -5.284616241568964e+0, - -8.867715667624458e+0, +3.493013124279215e+0, - +1.564102508858634e+1, +1.742097597385893e+1, - -2.834466755180654e+1, +1.661569367939544e+1, - +8.011836167974721e+0, -2.056267541998229e+0, - +1.449208170441839e+1, +1.853807176907916e+1, - +9.932562704505182e+0, -2.244223871767187e+1, - +8.590014121680897e-1, -1.286192925744479e+1, - +1.164596909542055e+1, +1.806076684783089e+1, - +5.870672154659249e+0, -3.542938819659747e+1, - +1.901323489060250e+1, +1.885508331552577e+1, - -1.734689708174982e+1, +1.316284237125190e+1]) - theta_i = np.array([+6.233225190695437e+1, +4.057499381311059e+1, - +4.325515754166724e+1, +3.281615453173585e+1, - +1.558061616372237e+1, +1.076629305714420e+1, - +5.492841024648724e+1, +1.316994930024688e+1, - +2.780232111309410e+1, +3.794824788914354e+1, - +1.799988210051809e+1, +5.974332563100539e+0, - +2.532823409972962e+1, +5.179633600312162e+1, - +3.536456194294350e+1, +4.600304902833652e+1, - +2.287153304140217e+1, +8.368200580099821e+0, - +3.029700159040121e+1, +5.834381701800013e+1, - +1.194282058271408e+0, +3.583428564427879e+0, - +4.883941101108207e+1, +2.042951874827759e+1]) + theta_r = np.array([ + -4.465731934165702e+1, -5.284616241568964e+0, + -8.867715667624458e+0, +3.493013124279215e+0, + +1.564102508858634e+1, +1.742097597385893e+1, + -2.834466755180654e+1, +1.661569367939544e+1, + +8.011836167974721e+0, -2.056267541998229e+0, + +1.449208170441839e+1, +1.853807176907916e+1, + +9.932562704505182e+0, -2.244223871767187e+1, + +8.590014121680897e-1, -1.286192925744479e+1, + +1.164596909542055e+1, +1.806076684783089e+1, + +5.870672154659249e+0, -3.542938819659747e+1, + +1.901323489060250e+1, +1.885508331552577e+1, + -1.734689708174982e+1, +1.316284237125190e+1]) + + theta_i = np.array([ + +6.233225190695437e+1, +4.057499381311059e+1, + +4.325515754166724e+1, +3.281615453173585e+1, + +1.558061616372237e+1, +1.076629305714420e+1, + +5.492841024648724e+1, +1.316994930024688e+1, + +2.780232111309410e+1, +3.794824788914354e+1, + +1.799988210051809e+1, +5.974332563100539e+0, + +2.532823409972962e+1, +5.179633600312162e+1, + +3.536456194294350e+1, +4.600304902833652e+1, + +2.287153304140217e+1, +8.368200580099821e+0, + +3.029700159040121e+1, +5.834381701800013e+1, + +1.194282058271408e+0, +3.583428564427879e+0, + +4.883941101108207e+1, +2.042951874827759e+1]) + theta = np.array(theta_r + theta_i * 1j, dtype=np.complex128) - alpha_r = np.array([+6.387380733878774e+2, +1.909896179065730e+2, - +4.236195226571914e+2, +4.645770595258726e+2, - +7.765163276752433e+2, +1.907115136768522e+3, - +2.909892685603256e+3, +1.944772206620450e+2, - +1.382799786972332e+5, +5.628442079602433e+3, - +2.151681283794220e+2, +1.324720240514420e+3, - +1.617548476343347e+4, +1.112729040439685e+2, - +1.074624783191125e+2, +8.835727765158191e+1, - +9.354078136054179e+1, +9.418142823531573e+1, - +1.040012390717851e+2, +6.861882624343235e+1, - +8.766654491283722e+1, +1.056007619389650e+2, - +7.738987569039419e+1, +1.041366366475571e+2]) - alpha_i = np.array([-6.743912502859256e+2, -3.973203432721332e+2, - -2.041233768918671e+3, -1.652917287299683e+3, - -1.783617639907328e+4, -5.887068595142284e+4, - -9.953255345514560e+3, -1.427131226068449e+3, - -3.256885197214938e+6, -2.924284515884309e+4, - -1.121774011188224e+3, -6.370088443140973e+4, - -1.008798413156542e+6, -8.837109731680418e+1, - -1.457246116408180e+2, -6.388286188419360e+1, - -2.195424319460237e+2, -6.719055740098035e+2, - -1.693747595553868e+2, -1.177598523430493e+1, - -4.596464999363902e+3, -1.738294585524067e+3, - -4.311715386228984e+1, -2.777743732451969e+2]) + alpha_r = np.array([ + +6.387380733878774e+2, +1.909896179065730e+2, + +4.236195226571914e+2, +4.645770595258726e+2, + +7.765163276752433e+2, +1.907115136768522e+3, + +2.909892685603256e+3, +1.944772206620450e+2, + +1.382799786972332e+5, +5.628442079602433e+3, + +2.151681283794220e+2, +1.324720240514420e+3, + +1.617548476343347e+4, +1.112729040439685e+2, + +1.074624783191125e+2, +8.835727765158191e+1, + +9.354078136054179e+1, +9.418142823531573e+1, + +1.040012390717851e+2, +6.861882624343235e+1, + +8.766654491283722e+1, +1.056007619389650e+2, + +7.738987569039419e+1, +1.041366366475571e+2]) + + alpha_i = np.array([ + -6.743912502859256e+2, -3.973203432721332e+2, + -2.041233768918671e+3, -1.652917287299683e+3, + -1.783617639907328e+4, -5.887068595142284e+4, + -9.953255345514560e+3, -1.427131226068449e+3, + -3.256885197214938e+6, -2.924284515884309e+4, + -1.121774011188224e+3, -6.370088443140973e+4, + -1.008798413156542e+6, -8.837109731680418e+1, + -1.457246116408180e+2, -6.388286188419360e+1, + -2.195424319460237e+2, -6.719055740098035e+2, + -1.693747595553868e+2, -1.177598523430493e+1, + -4.596464999363902e+3, -1.738294585524067e+3, + -4.311715386228984e+1, -2.777743732451969e+2]) + alpha = np.array(alpha_r + alpha_i * 1j, dtype=np.complex128) - n = A.shape[0] + + del theta_i, theta_r, alpha_r, alpha_i alpha0 = 2.258038182743983e-47 - k = 24 + def __call__(self, A, n0, dt): + """Solve using 48th order IPF CRAM [Pusa16]_ - y = np.array(n0, dtype=np.float64) - for l in range(k): - y = 2.0*np.real(alpha[l]*sla.spsolve(A*dt - theta[l]*sp.eye(n), y)) + y + Parameters + ---------- + A : scipy.sparse.csr_matrix + Sparse transmutation matrix ``A[j, i]`` desribing rates at + which isotope ``i`` transmutes to isotope ``j`` + n0 : numpy.ndarray + Initial compositions, typically given in number of atoms in some + material or an atom density + dt : float + Time [s] of the specific interval to be solved - y *= alpha0 - return y + Returns + ------- + numpy.ndarray + Final compositions after ``dt`` + + """ + return super().__call__(A, n0, dt) + + +CRAM16 = Cram16Solver().__call__ +CRAM48 = Cram48Solver().__call__ From df387e87dc069836a80cf62ed4839369fe66ca4c Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Thu, 19 Sep 2019 16:51:38 -0500 Subject: [PATCH 004/158] Document concrete and abstract depletion solvers --- docs/source/pythonapi/deplete.rst | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/docs/source/pythonapi/deplete.rst b/docs/source/pythonapi/deplete.rst index e18afd920..03f5e6b61 100644 --- a/docs/source/pythonapi/deplete.rst +++ b/docs/source/pythonapi/deplete.rst @@ -139,6 +139,18 @@ The following functions are used to solve the depletion equations, with cram.deplete cram.timed_deplete + +:func:`cram.CRAM16` and :func:`cram.CRAM48` are aliases to the ``__call__`` +methods for the following classes + +.. autosummary:: + :toctree: generated + :nosignatures: + :template: mycallable.rst + + cram.Cram16Solver + cram.Cram48Solver + The following classes are used to help the :class:`openmc.deplete.Operator` compute quantities like effective fission yields, reaction rates, and total system energy. @@ -185,8 +197,8 @@ OpenMC simulations back on to the :class:`abc.TransportOperator` abc.ReactionRateHelper abc.TalliedFissionYieldHelper -Custom integrators can be developed by subclassing from the following abstract -base classes: +Custom integrators or depletion solvers can be developed by subclassing from +the following abstract base classes: .. autosummary:: :toctree: generated @@ -195,3 +207,5 @@ base classes: abc.Integrator abc.SIIntegrator + abc.DepSystemSolver + abc.IPFCramSolver From 2ead24e1723314da6721e04eb680d1851b88618f Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Thu, 19 Sep 2019 10:22:07 -0500 Subject: [PATCH 005/158] Teach openmc_statepoint_write about internal tallies If a tally is marked as not writeable, a tally group will still be added to the statepoint file. However, no filter, score, nuclide, or results data will be written to this tally group. A new attribute is introduced to this tally group "internal" that is an integer flag: 0 if the tally is not internal (i.e. is writeable) and 1 if the tally is internal (i.e. is not writeable). The internal attribute has been added to the statepoint io format in the documentation. Other changes: use ``` const auto& tally : model::tallies tally->X ``` to iterate over tallies during the writing process --- docs/source/io_formats/statepoint.rst | 4 +++ src/state_point.cpp | 40 ++++++++++++++++----------- 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/docs/source/io_formats/statepoint.rst b/docs/source/io_formats/statepoint.rst index 9c5b8f526..5a373580d 100644 --- a/docs/source/io_formats/statepoint.rst +++ b/docs/source/io_formats/statepoint.rst @@ -109,6 +109,10 @@ The current version of the statepoint file format is 17.0. **/tallies/tally /** +:Attributes: - **internal** (*int*) -- Flag indicating the presence of tally + data (0) or absence of tally data (1). All user defined + tallies will have a value of 0 unless otherwise instructed. + :Datasets: - **n_realizations** (*int*) -- Number of realizations. - **n_filters** (*int*) -- Number of filters used. - **filters** (*int[]*) -- User-defined unique IDs of the filters on diff --git a/src/state_point.cpp b/src/state_point.cpp index 7239f3284..8c1780c82 100644 --- a/src/state_point.cpp +++ b/src/state_point.cpp @@ -165,36 +165,43 @@ openmc_statepoint_write(const char* filename, bool* write_source) write_attribute(tallies_group, "ids", tally_ids); // Write all tally information except results - for (const auto& tally_ptr : model::tallies) { - const auto& tally {*tally_ptr}; + for (const auto& tally : model::tallies) { hid_t tally_group = create_group(tallies_group, - "tally " + std::to_string(tally.id_)); + "tally " + std::to_string(tally->id_)); - write_dataset(tally_group, "name", tally.name_); + write_dataset(tally_group, "name", tally->name_); - if (tally.estimator_ == ESTIMATOR_ANALOG) { + if (tally->writeable_) { + write_attribute(tally_group, "internal", 0); + } else { + write_attribute(tally_group, "internal", 1); + close_group(tally_group); + continue; + } + + if (tally->estimator_ == ESTIMATOR_ANALOG) { write_dataset(tally_group, "estimator", "analog"); - } else if (tally.estimator_ == ESTIMATOR_TRACKLENGTH) { + } else if (tally->estimator_ == ESTIMATOR_TRACKLENGTH) { write_dataset(tally_group, "estimator", "tracklength"); - } else if (tally.estimator_ == ESTIMATOR_COLLISION) { + } else if (tally->estimator_ == ESTIMATOR_COLLISION) { write_dataset(tally_group, "estimator", "collision"); } - write_dataset(tally_group, "n_realizations", tally.n_realizations_); + write_dataset(tally_group, "n_realizations", tally->n_realizations_); // Write the ID of each filter attached to this tally - write_dataset(tally_group, "n_filters", tally.filters().size()); - if (!tally.filters().empty()) { + write_dataset(tally_group, "n_filters", tally->filters().size()); + if (!tally->filters().empty()) { std::vector filter_ids; - filter_ids.reserve(tally.filters().size()); - for (auto i_filt : tally.filters()) + filter_ids.reserve(tally->filters().size()); + for (auto i_filt : tally->filters()) filter_ids.push_back(model::tally_filters[i_filt]->id()); write_dataset(tally_group, "filters", filter_ids); } // Write the nuclides this tally scores std::vector nuclides; - for (auto i_nuclide : tally.nuclides_) { + for (auto i_nuclide : tally->nuclides_) { if (i_nuclide == -1) { nuclides.push_back("total"); } else { @@ -207,12 +214,12 @@ openmc_statepoint_write(const char* filename, bool* write_source) } write_dataset(tally_group, "nuclides", nuclides); - if (tally.deriv_ != C_NONE) write_dataset(tally_group, "derivative", - model::tally_derivs[tally.deriv_].id); + if (tally->deriv_ != C_NONE) write_dataset(tally_group, "derivative", + model::tally_derivs[tally->deriv_].id); // Write the tally score bins std::vector scores; - for (auto sc : tally.scores_) scores.push_back(reaction_name(sc)); + for (auto sc : tally->scores_) scores.push_back(reaction_name(sc)); write_dataset(tally_group, "n_score_bins", scores.size()); write_dataset(tally_group, "score_bins", scores); @@ -232,6 +239,7 @@ openmc_statepoint_write(const char* filename, bool* write_source) // Write all tally results for (const auto& tally : model::tallies) { + if (!tally->writeable_) continue; // Write sum and sum_sq for each bin std::string name = "tally " + std::to_string(tally->id_); hid_t tally_group = open_group(tallies_group, name.c_str()); From 1300ca2678ad3f0bfc37822c68d2800317a6f9e7 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Fri, 20 Sep 2019 08:48:27 -0500 Subject: [PATCH 006/158] Teach load_state_point about internal tallies When reading in tally data from a statepoint file, a check is performed on the "internal" attribute of the tally group. If the attribute doesn't exist (previous statepoint files), then it is assumed that the tally is writeable / not internal. Otherwise, the internal attribute is read from the dataset. If the tally is determined to be internal, the value of tally.writeable_ is set to false and no tally data is read --- src/state_point.cpp | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/state_point.cpp b/src/state_point.cpp index 8c1780c82..a550748a5 100644 --- a/src/state_point.cpp +++ b/src/state_point.cpp @@ -433,11 +433,23 @@ void load_state_point() // Read sum, sum_sq, and N for each bin std::string name = "tally " + std::to_string(tally->id_); hid_t tally_group = open_group(tallies_group, name.c_str()); - auto& results = tally->results_; - read_tally_results(tally_group, results.shape()[0], - results.shape()[1], results.data()); - read_dataset(tally_group, "n_realizations", tally->n_realizations_); - close_group(tally_group); + + int internal; + if (attribute_exists(tally_group, "internal")) { + read_attribute(tally_group, "internal", internal); + } else { + internal = 0; + } + if (internal) { + tally->writeable_ = false; + } else { + + auto& results = tally->results_; + read_tally_results(tally_group, results.shape()[0], + results.shape()[1], results.data()); + read_dataset(tally_group, "n_realizations", tally->n_realizations_); + close_group(tally_group); + } } close_group(tallies_group); @@ -705,6 +717,7 @@ void write_tally_results_nr(hid_t file_id) for (const auto& t : model::tallies) { // Skip any tallies that are not active if (!t->active_) continue; + if (!t->writeable_) continue; if (mpi::master && !object_exists(file_id, "tallies_present")) { write_attribute(file_id, "tallies_present", 1); From 66593fd7e1d072e1ad07e4fb5d6d3724cbad0ac6 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Fri, 20 Sep 2019 09:14:09 -0500 Subject: [PATCH 007/158] Expose tally.writeable_ through openmc.lib Add two functions to capi.h: openmc_tally_set_writeable and openmc_tally_get_writeable which are exposed to the Python API through the openmc.lib.Tally.writeable property. These functions are very similar to the set/get active counterparts as both act on a boolean Tally attribute A new unit test test_tally_writeable has been added that toggles the writeable state of a tally. It is important to note that the writeable state must be reset, otherwise tallies in subsequent tests will be skewed. This is because the test_tally_writeable function requires the capi_simulation_init fixture and the tallies are shared by those functions that use the capi_run fixture --- include/openmc/capi.h | 2 ++ openmc/lib/tally.py | 16 ++++++++++++++++ src/tallies/tally.cpp | 24 ++++++++++++++++++++++++ tests/unit_tests/test_lib.py | 11 ++++++++++- 4 files changed, 52 insertions(+), 1 deletion(-) diff --git a/include/openmc/capi.h b/include/openmc/capi.h index 3d2e8f57b..327594c3e 100644 --- a/include/openmc/capi.h +++ b/include/openmc/capi.h @@ -110,6 +110,7 @@ extern "C" { 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_get_writeable(int32_t index, bool* writeable); int openmc_tally_reset(int32_t index); int openmc_tally_results(int32_t index, double** ptr, size_t shape_[3]); int openmc_tally_set_active(int32_t index, bool active); @@ -119,6 +120,7 @@ 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_set_writeable(int32_t index, bool writeable); 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/lib/tally.py b/openmc/lib/tally.py index 97b7437ea..906084c4b 100644 --- a/openmc/lib/tally.py +++ b/openmc/lib/tally.py @@ -53,6 +53,9 @@ _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_get_writeable.argtypes = [c_int32, POINTER(c_bool)] +_dll.openmc_tally_get_writeable.restype = c_int +_dll.openmc_tally_get_writeable.errcheck = _error_handler _dll.openmc_tally_reset.argtypes = [c_int32] _dll.openmc_tally_reset.restype = c_int _dll.openmc_tally_reset.errcheck = _error_handler @@ -81,6 +84,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_set_writeable.argtypes = [c_int32, c_bool] +_dll.openmc_tally_set_writeable.restype = c_int +_dll.openmc_tally_set_writeable.errcheck = _error_handler _dll.tallies_size.restype = c_size_t @@ -344,6 +350,16 @@ class Tally(_FortranObjectWithID): return std_dev + @property + def writeable(self): + writeable = c_bool() + _dll.openmc_tally_get_writeable(self._index, writeable) + return writeable.value + + @writeable.setter + def writeable(self, writeable): + _dll.openmc_tally_set_writeable(self._index, writeable) + def reset(self): """Reset results and num_realizations of tally""" _dll.openmc_tally_reset(self._index) diff --git a/src/tallies/tally.cpp b/src/tallies/tally.cpp index 563beee76..96253285e 100644 --- a/src/tallies/tally.cpp +++ b/src/tallies/tally.cpp @@ -1220,6 +1220,30 @@ openmc_tally_set_active(int32_t index, bool active) return 0; } +extern "C" int +openmc_tally_get_writeable(int32_t index, bool* writeable) +{ + if (index < 0 || index >= model::tallies.size()) { + set_errmsg("Index in tallies array is out of bounds."); + return OPENMC_E_OUT_OF_BOUNDS; + } + *writeable = model::tallies[index]->writeable_; + + return 0; +} + +extern "C" int +openmc_tally_set_writeable(int32_t index, bool writeable) +{ + if (index < 0 || index >= model::tallies.size()) { + set_errmsg("Index in tallies array is out of bounds."); + return OPENMC_E_OUT_OF_BOUNDS; + } + model::tallies[index]->writeable_ = writeable; + + return 0; +} + extern "C" int openmc_tally_get_scores(int32_t index, int** scores, int* n) { diff --git a/tests/unit_tests/test_lib.py b/tests/unit_tests/test_lib.py index 2f39f0b0d..3736ddc1e 100644 --- a/tests/unit_tests/test_lib.py +++ b/tests/unit_tests/test_lib.py @@ -256,9 +256,18 @@ def test_tally_activate(capi_simulation_init): assert t.active +def test_tally_writeable(capi_simulation_init): + t = openmc.lib.tallies[1] + assert t.writeable + t.writeable = False + assert not t.writeable + # Revert tally to writeable state for capi_run fixtures + t.writeable = True + + def test_tally_results(capi_run): t = openmc.lib.tallies[1] - assert t.num_realizations == 10 # t was made active in test_tally + assert t.num_realizations == 10 # t was made active in test_tally_active assert np.all(t.mean >= 0) nonzero = (t.mean > 0.0) assert np.all(t.std_dev[nonzero] >= 0) From a83f4d2bb2def7466bdd0d8b244e4b4c31266af4 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Fri, 20 Sep 2019 09:15:25 -0500 Subject: [PATCH 008/158] Rename capi_* fixtures to lib_* in test_lib.py --- tests/unit_tests/test_lib.py | 72 ++++++++++++++++++------------------ 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/tests/unit_tests/test_lib.py b/tests/unit_tests/test_lib.py index 3736ddc1e..7f992cb09 100644 --- a/tests/unit_tests/test_lib.py +++ b/tests/unit_tests/test_lib.py @@ -50,24 +50,24 @@ def pincell_model(): @pytest.fixture(scope='module') -def capi_init(pincell_model, mpi_intracomm): +def lib_init(pincell_model, mpi_intracomm): openmc.lib.init(intracomm=mpi_intracomm) yield openmc.lib.finalize() @pytest.fixture(scope='module') -def capi_simulation_init(capi_init): +def lib_simulation_init(lib_init): openmc.lib.simulation_init() yield @pytest.fixture(scope='module') -def capi_run(capi_simulation_init): +def lib_run(lib_simulation_init): openmc.lib.run() -def test_cell_mapping(capi_init): +def test_cell_mapping(lib_init): cells = openmc.lib.cells assert isinstance(cells, Mapping) assert len(cells) == 3 @@ -76,7 +76,7 @@ def test_cell_mapping(capi_init): assert cell_id == cell.id -def test_cell(capi_init): +def test_cell(lib_init): cell = openmc.lib.cells[1] assert isinstance(cell.fill, openmc.lib.Material) cell.fill = openmc.lib.materials[1] @@ -85,7 +85,7 @@ def test_cell(capi_init): cell.name = "Not fuel" assert cell.name == "Not fuel" -def test_cell_temperature(capi_init): +def test_cell_temperature(lib_init): cell = openmc.lib.cells[1] cell.set_temperature(100.0, 0) assert cell.get_temperature(0) == 100.0 @@ -93,7 +93,7 @@ def test_cell_temperature(capi_init): assert cell.get_temperature() == 200.0 -def test_new_cell(capi_init): +def test_new_cell(lib_init): with pytest.raises(exc.AllocationError): openmc.lib.Cell(1) new_cell = openmc.lib.Cell() @@ -101,7 +101,7 @@ def test_new_cell(capi_init): assert len(openmc.lib.cells) == 5 -def test_material_mapping(capi_init): +def test_material_mapping(lib_init): mats = openmc.lib.materials assert isinstance(mats, Mapping) assert len(mats) == 3 @@ -110,7 +110,7 @@ def test_material_mapping(capi_init): assert mat_id == mat.id -def test_material(capi_init): +def test_material(lib_init): m = openmc.lib.materials[3] assert m.nuclides == ['H1', 'O16', 'B10', 'B11'] @@ -136,14 +136,14 @@ def test_material(capi_init): m.name = "Not hot borated water" assert m.name == "Not hot borated water" -def test_material_add_nuclide(capi_init): +def test_material_add_nuclide(lib_init): m = openmc.lib.materials[3] m.add_nuclide('Xe135', 1e-12) assert m.nuclides[-1] == 'Xe135' assert m.densities[-1] == 1e-12 -def test_new_material(capi_init): +def test_new_material(lib_init): with pytest.raises(exc.AllocationError): openmc.lib.Material(1) new_mat = openmc.lib.Material() @@ -151,7 +151,7 @@ def test_new_material(capi_init): assert len(openmc.lib.materials) == 5 -def test_nuclide_mapping(capi_init): +def test_nuclide_mapping(lib_init): nucs = openmc.lib.nuclides assert isinstance(nucs, Mapping) assert len(nucs) == 13 @@ -160,7 +160,7 @@ def test_nuclide_mapping(capi_init): assert name == nuc.name -def test_settings(capi_init): +def test_settings(lib_init): settings = openmc.lib.settings assert settings.batches == 10 settings.batches = 10 @@ -175,7 +175,7 @@ def test_settings(capi_init): settings.run_mode = 'eigenvalue' -def test_tally_mapping(capi_init): +def test_tally_mapping(lib_init): tallies = openmc.lib.tallies assert isinstance(tallies, Mapping) assert len(tallies) == 3 @@ -184,7 +184,7 @@ def test_tally_mapping(capi_init): assert tally_id == tally.id -def test_energy_function_filter(capi_init): +def test_energy_function_filter(lib_init): """Test special __new__ and __init__ for EnergyFunctionFilter""" efunc = openmc.lib.EnergyFunctionFilter([0.0, 1.0], [0.0, 2.0]) assert len(efunc.energy) == 2 @@ -193,7 +193,7 @@ def test_energy_function_filter(capi_init): assert (efunc.y == [0.0, 2.0]).all() -def test_tally(capi_init): +def test_tally(lib_init): t = openmc.lib.tallies[1] assert t.type == 'volume' assert len(t.filters) == 2 @@ -239,7 +239,7 @@ def test_tally(capi_init): assert len(t3_f.y) == 3 -def test_new_tally(capi_init): +def test_new_tally(lib_init): with pytest.raises(exc.AllocationError): openmc.lib.Material(1) new_tally = openmc.lib.Tally() @@ -249,23 +249,23 @@ def test_new_tally(capi_init): assert len(openmc.lib.tallies) == 5 -def test_tally_activate(capi_simulation_init): +def test_tally_activate(lib_simulation_init): t = openmc.lib.tallies[1] assert not t.active t.active = True assert t.active -def test_tally_writeable(capi_simulation_init): +def test_tally_writeable(lib_simulation_init): t = openmc.lib.tallies[1] assert t.writeable t.writeable = False assert not t.writeable - # Revert tally to writeable state for capi_run fixtures + # Revert tally to writeable state for lib_run fixtures t.writeable = True -def test_tally_results(capi_run): +def test_tally_results(lib_run): t = openmc.lib.tallies[1] assert t.num_realizations == 10 # t was made active in test_tally_active assert np.all(t.mean >= 0) @@ -278,26 +278,26 @@ def test_tally_results(capi_run): assert t2.mean.size == (n + 1) * (n + 2) // 2 * 3 # Number of Zernike coeffs * 3 cells -def test_global_tallies(capi_run): +def test_global_tallies(lib_run): assert openmc.lib.num_realizations() == 5 gt = openmc.lib.global_tallies() for mean, std_dev in gt: assert mean >= 0 -def test_statepoint(capi_run): +def test_statepoint(lib_run): openmc.lib.statepoint_write('test_sp.h5') assert os.path.exists('test_sp.h5') -def test_source_bank(capi_run): +def test_source_bank(lib_run): source = openmc.lib.source_bank() assert np.all(source['E'] > 0.0) assert np.all(source['wgt'] == 1.0) assert np.allclose(np.linalg.norm(source['u'], axis=1), 1.0) -def test_by_batch(capi_run): +def test_by_batch(lib_run): openmc.lib.hard_reset() # Running next batch before simulation is initialized should raise an @@ -322,7 +322,7 @@ def test_by_batch(capi_run): openmc.lib.simulation_finalize() -def test_reset(capi_run): +def test_reset(lib_run): # Init and run 10 batches. openmc.lib.hard_reset() openmc.lib.simulation_init() @@ -353,7 +353,7 @@ def test_reset(capi_run): openmc.lib.simulation_finalize() -def test_reproduce_keff(capi_init): +def test_reproduce_keff(lib_init): # Get k-effective after run openmc.lib.hard_reset() openmc.lib.run() @@ -366,7 +366,7 @@ def test_reproduce_keff(capi_init): assert keff0 == pytest.approx(keff1) -def test_find_cell(capi_init): +def test_find_cell(lib_init): cell, instance = openmc.lib.find_cell((0., 0., 0.)) assert cell is openmc.lib.cells[1] cell, instance = openmc.lib.find_cell((0.4, 0., 0.)) @@ -375,14 +375,14 @@ def test_find_cell(capi_init): openmc.lib.find_cell((100., 100., 100.)) -def test_find_material(capi_init): +def test_find_material(lib_init): mat = openmc.lib.find_material((0., 0., 0.)) assert mat is openmc.lib.materials[1] mat = openmc.lib.find_material((0.4, 0., 0.)) assert mat is openmc.lib.materials[2] -def test_mesh(capi_init): +def test_mesh(lib_init): mesh = openmc.lib.RegularMesh() mesh.dimension = (2, 3, 4) assert mesh.dimension == (2, 3, 4) @@ -417,7 +417,7 @@ def test_mesh(capi_init): assert msf.mesh == mesh -def test_restart(capi_init, mpi_intracomm): +def test_restart(lib_init, mpi_intracomm): # Finalize and re-init to make internal state consistent with XML. openmc.lib.hard_reset() openmc.lib.finalize() @@ -449,7 +449,7 @@ def test_restart(capi_init, mpi_intracomm): assert keff0 == pytest.approx(keff1) -def test_load_nuclide(capi_init): +def test_load_nuclide(lib_init): # load multiple nuclides openmc.lib.load_nuclide('H3') assert 'H3' in openmc.lib.nuclides @@ -460,7 +460,7 @@ def test_load_nuclide(capi_init): openmc.lib.load_nuclide('Pu3') -def test_id_map(capi_init): +def test_id_map(lib_init): expected_ids = np.array([[(3, 3), (2, 2), (3, 3)], [(2, 2), (1, 1), (2, 2)], [(3, 3), (2, 2), (3, 3)]], dtype='int32') @@ -478,7 +478,7 @@ def test_id_map(capi_init): ids = openmc.lib.plot.id_map(s) assert np.array_equal(expected_ids, ids) -def test_property_map(capi_init): +def test_property_map(lib_init): expected_properties = np.array( [[(293.6, 0.740582), (293.6, 6.55), (293.6, 0.740582)], [ (293.6, 6.55), (293.6, 10.29769), (293.6, 6.55)], @@ -498,7 +498,7 @@ def test_property_map(capi_init): assert np.allclose(expected_properties, properties, atol=1e-04) -def test_position(capi_init): +def test_position(lib_init): pos = openmc.lib.plot._Position(1.0, 2.0, 3.0) @@ -511,7 +511,7 @@ def test_position(capi_init): assert tuple(pos) == (1.3, 2.3, 3.3) -def test_global_bounding_box(capi_init): +def test_global_bounding_box(lib_init): expected_llc = (-0.63, -0.63, -np.inf) expected_urc = (0.63, 0.63, np.inf) From 4b688e5efae9bd99c586d2f8afd795d28c6e0fd2 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Fri, 20 Sep 2019 10:31:56 -0500 Subject: [PATCH 009/158] Teach openmc.StatePoint about internal tallies When reading tally data from the statepoint file, tallies that are marked as internal are not created nor added to the StatePoint.tallies property --- openmc/statepoint.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/openmc/statepoint.py b/openmc/statepoint.py index c9a8f9f9a..5802a74ca 100644 --- a/openmc/statepoint.py +++ b/openmc/statepoint.py @@ -375,13 +375,18 @@ class StatePoint(object): for tally_id in tally_ids: group = tallies_group['tally {}'.format(tally_id)] - # Read the number of realizations - n_realizations = group['n_realizations'][()] + # Check if tally is internal and therefore has no data + if group.attrs.get("internal"): + continue # Create Tally object and assign basic properties tally = openmc.Tally(tally_id) tally._sp_filename = self._f.filename tally.name = group['name'][()].decode() if 'name' in group else '' + + # Read the number of realizations + n_realizations = group['n_realizations'][()] + tally.estimator = group['estimator'][()].decode() tally.num_realizations = n_realizations From 72212f60a2ea64cbd37059ed7c45b5ca2c7f3cee Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Fri, 20 Sep 2019 10:49:32 -0500 Subject: [PATCH 010/158] Use internal tallies to compute quantities for depletion Tallies created by internal depletion helpers are marked as internal using the openmc.lib.Tally.writeable property. This is done to resolve issue #1327 where statepoint files could grow to be quite large after tallying reaction rates across many burnable materials for all nuclides of interest. A check is added in the depletion regression test to ensure that no additional tallies are loaded to the StatePoint. --- openmc/deplete/abc.py | 1 + openmc/deplete/helpers.py | 3 +++ tests/regression_tests/deplete/test.py | 6 ++++++ 3 files changed, 10 insertions(+) diff --git a/openmc/deplete/abc.py b/openmc/deplete/abc.py index e0ed64645..3a7eee34d 100644 --- a/openmc/deplete/abc.py +++ b/openmc/deplete/abc.py @@ -539,6 +539,7 @@ class TalliedFissionYieldHelper(FissionYieldHelper): # Tally group-wise fission reaction rates self._fission_rate_tally = Tally() + self._fission_rate_tally.writeable = False self._fission_rate_tally.scores = ['fission'] self._fission_rate_tally.filters = [MaterialFilter(materials)] diff --git a/openmc/deplete/helpers.py b/openmc/deplete/helpers.py index 9e3e379d5..b1e7e17ef 100644 --- a/openmc/deplete/helpers.py +++ b/openmc/deplete/helpers.py @@ -59,6 +59,7 @@ class DirectReactionRateHelper(ReactionRateHelper): ``"(n, gamma)"``, needed for the reaction rate tally. """ self._rate_tally = Tally() + self._rate_tally.writeable = False self._rate_tally.scores = scores self._rate_tally.filters = [MaterialFilter(materials)] @@ -194,6 +195,7 @@ class EnergyScoreHelper(EnergyHelper): """ self._tally = Tally() + self._tally.writeable = False self._tally.scores = [self.score] def reset(self): @@ -570,6 +572,7 @@ class AveragedFissionYieldHelper(TalliedFissionYieldHelper): func_filter = EnergyFunctionFilter() func_filter.set_data((0, self._upper_energy), (0, self._upper_energy)) weighted_tally = Tally() + weighted_tally.writeable = False weighted_tally.scores = ['fission'] weighted_tally.filters = filters + [func_filter] self._weighted_tally = weighted_tally diff --git a/tests/regression_tests/deplete/test.py b/tests/regression_tests/deplete/test.py index c7a9c162e..01ce21c01 100644 --- a/tests/regression_tests/deplete/test.py +++ b/tests/regression_tests/deplete/test.py @@ -108,11 +108,17 @@ def test_full(run_in_tmpdir): t_ref, k_ref = res_ref.get_eigenvalue() k_state = np.empty_like(k_ref) + n_tallies = np.empty(N + 1, dtype=int) + # Get statepoint files for all BOS points and EOL for n in range(N + 1): statepoint = openmc.StatePoint("openmc_simulation_n{}.h5".format(n)) k_n = statepoint.k_combined k_state[n] = [k_n.nominal_value, k_n.std_dev] + n_tallies[n] = len(statepoint.tallies) # Look for exact match pulling from statepoint and depletion_results assert np.all(k_state == k_test) assert np.allclose(k_test, k_ref) + + # Check that no additional tallies are loaded from the files + assert np.all(n_tallies == 0) From 0055ecbb3a4ef859f5e3f834548868168ae89810 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Fri, 20 Sep 2019 14:22:28 -0500 Subject: [PATCH 011/158] Read materials from summary.h5 if using DagMC geometry. --- openmc/summary.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/openmc/summary.py b/openmc/summary.py index 2ab29c00a..6b8471977 100644 --- a/openmc/summary.py +++ b/openmc/summary.py @@ -97,16 +97,17 @@ class Summary(object): self._macroscopics = name.decode() def _read_geometry(self): - if "dagmc" in self._f['geometry'].attrs.keys(): - return - # Read in and initialize the Materials and Geometry + # Read in and initialize the Materials self._read_materials() - self._read_surfaces() - cell_fills = self._read_cells() - self._read_universes() - self._read_lattices() - self._finalize_geometry(cell_fills) + + # Read native geometry only + if "dagmc" not in self._f['geometry'].attrs.keys(): + self._read_surfaces() + cell_fills = self._read_cells() + self._read_universes() + self._read_lattices() + self._finalize_geometry(cell_fills) def _read_materials(self): for group in self._f['materials'].values(): From c1d746164fa47849d7f4e89bfcd203a825e8556c Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Mon, 23 Sep 2019 12:00:24 -0500 Subject: [PATCH 012/158] Writing empty groups for nuclides/atoms in volume calc if no entries are found. --- openmc/volume.py | 3 +-- src/volume_calc.cpp | 26 ++++++++++++-------------- 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/openmc/volume.py b/openmc/volume.py index 7ac4fdd0c..91ff829cb 100644 --- a/openmc/volume.py +++ b/openmc/volume.py @@ -212,13 +212,12 @@ class VolumeCalculation(object): ids.append(domain_id) group = f[obj_name] volume = ufloat(*group['volume'][()]) + volumes[domain_id] = volume nucnames = group['nuclides'][()] atoms_ = group['atoms'][()] - atom_dict = OrderedDict() for name_i, atoms_i in zip(nucnames, atoms_): atom_dict[name_i.decode()] = ufloat(*atoms_i) - volumes[domain_id] = volume atoms[domain_id] = atom_dict # Instantiate some throw-away domains that are used by the constructor diff --git a/src/volume_calc.cpp b/src/volume_calc.cpp index 93b729bd6..6c1c48932 100644 --- a/src/volume_calc.cpp +++ b/src/volume_calc.cpp @@ -311,22 +311,20 @@ void VolumeCalculation::to_hdf5(const std::string& filename, // Create array of nuclide names from the vector auto n_nuc = result.nuclides.size(); - if (!result.nuclides.empty()) { - std::vector nucnames; - for (int i_nuc : result.nuclides) { - nucnames.push_back(data::nuclides[i_nuc]->name_); - } - - // Create array of total # of atoms with uncertainty for each nuclide - xt::xtensor atom_data({n_nuc, 2}); - xt::view(atom_data, xt::all(), 0) = xt::adapt(result.atoms); - xt::view(atom_data, xt::all(), 1) = xt::adapt(result.uncertainty); - - // Write results - write_dataset(group_id, "nuclides", nucnames); - write_dataset(group_id, "atoms", atom_data); + std::vector nucnames; + for (int i_nuc : result.nuclides) { + nucnames.push_back(data::nuclides[i_nuc]->name_); } + // Create array of total # of atoms with uncertainty for each nuclide + xt::xtensor atom_data({n_nuc, 2}); + xt::view(atom_data, xt::all(), 0) = xt::adapt(result.atoms); + xt::view(atom_data, xt::all(), 1) = xt::adapt(result.uncertainty); + + // Write results + write_dataset(group_id, "nuclides", nucnames); + write_dataset(group_id, "atoms", atom_data); + close_group(group_id); } From 45aeb35aa99e9ea80c58ebe8f356a50b8e729cac Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Tue, 24 Sep 2019 15:15:30 -0400 Subject: [PATCH 013/158] Rotate azimuthal distributions by pi/2 --- src/distribution_multi.cpp | 4 ++-- tests/regression_tests/source/results_true.dat | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/distribution_multi.cpp b/src/distribution_multi.cpp index d4a728c71..0c1ecddec 100644 --- a/src/distribution_multi.cpp +++ b/src/distribution_multi.cpp @@ -59,8 +59,8 @@ Direction PolarAzimuthal::sample() const double mu = mu_->sample(); if (mu == 1.0) return u_ref_; - // Sample azimuthal angle - double phi = phi_->sample(); + // Sample the azimuthal angle with an offset to match azimuth conventions + double phi = phi_->sample() + 0.5*PI; return rotate_angle(u_ref_, mu, &phi); } diff --git a/tests/regression_tests/source/results_true.dat b/tests/regression_tests/source/results_true.dat index 90cc3ec1f..6fe76c8cd 100644 --- a/tests/regression_tests/source/results_true.dat +++ b/tests/regression_tests/source/results_true.dat @@ -1,2 +1,2 @@ k-combined: -3.026614E-01 3.952008E-03 +2.800827E-01 7.360163E-03 From 60f17ea4663886af845a15f393e6e026f4b373f7 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 25 Sep 2019 12:36:47 -0500 Subject: [PATCH 014/158] Make sure from_ace classmethods get correct type of ACE table --- openmc/data/neutron.py | 3 +++ openmc/data/photon.py | 4 +++- openmc/data/thermal.py | 2 ++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/openmc/data/neutron.py b/openmc/data/neutron.py index 022cf8283..8a6c88981 100644 --- a/openmc/data/neutron.py +++ b/openmc/data/neutron.py @@ -588,6 +588,9 @@ class IncidentNeutron(EqualityMixin): # If mass number hasn't been specified, make an educated guess zaid, xs = ace.name.split('.') + if not xs.endswith('c'): + raise TypeError( + "{} is not a continuous-energy neutron ACE table.".format(ace)) name, element, Z, mass_number, metastable = \ get_metadata(int(zaid), metastable_scheme) diff --git a/openmc/data/photon.py b/openmc/data/photon.py index 0d0e52753..3766b697e 100644 --- a/openmc/data/photon.py +++ b/openmc/data/photon.py @@ -549,7 +549,9 @@ class IncidentPhoton(EqualityMixin): ace = get_table(ace_or_filename) # Get atomic number based on name of ACE table - zaid = ace.name.split('.')[0] + zaid, xs = ace.name.split('.') + if not xs.endswith('p'): + raise TypeError("{} is not a photoatomic transport ACE table.".format(ace)) Z = get_metadata(int(zaid))[2] # Read each reaction diff --git a/openmc/data/thermal.py b/openmc/data/thermal.py index 06e50c661..4fbe96363 100644 --- a/openmc/data/thermal.py +++ b/openmc/data/thermal.py @@ -600,6 +600,8 @@ class ThermalScattering(EqualityMixin): # Get new name that is GND-consistent ace_name, xs = ace.name.split('.') + if not xs.endswith('t'): + raise TypeError("{} is not a thermal scattering ACE table.".format(ace)) name = get_thermal_name(ace_name) # Assign temperature to the running list From d112eddbc39470b9df8d2d5b8797d69e7d1002c1 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Thu, 26 Sep 2019 20:26:13 -0400 Subject: [PATCH 015/158] openmc.deplete.cram.IPFCramSolver accepts coefficients at init Moved from deplete.abc into openmc.deplete.cram. CRAM16 and CRAM48 are aliases to __call__ methods for two instances of IPFCramSolver: Cram16Solver and Cram48Solver, created using 16th and 48th order coefficients --- docs/source/pythonapi/deplete.rst | 12 -- openmc/deplete/abc.py | 80 +--------- openmc/deplete/cram.py | 247 +++++++++++++++--------------- 3 files changed, 125 insertions(+), 214 deletions(-) diff --git a/docs/source/pythonapi/deplete.rst b/docs/source/pythonapi/deplete.rst index 03f5e6b61..82143e14a 100644 --- a/docs/source/pythonapi/deplete.rst +++ b/docs/source/pythonapi/deplete.rst @@ -139,18 +139,6 @@ The following functions are used to solve the depletion equations, with cram.deplete cram.timed_deplete - -:func:`cram.CRAM16` and :func:`cram.CRAM48` are aliases to the ``__call__`` -methods for the following classes - -.. autosummary:: - :toctree: generated - :nosignatures: - :template: mycallable.rst - - cram.Cram16Solver - cram.Cram48Solver - The following classes are used to help the :class:`openmc.deplete.Operator` compute quantities like effective fission yields, reaction rates, and total system energy. diff --git a/openmc/deplete/abc.py b/openmc/deplete/abc.py index b42aa3e74..200552870 100644 --- a/openmc/deplete/abc.py +++ b/openmc/deplete/abc.py @@ -14,9 +14,7 @@ from copy import deepcopy from warnings import warn from numbers import Real, Integral -from numpy import nonzero, empty, asarray, float64, real -import scipy.sparse as sp -import scipy.sparse.linalg as sla +from numpy import nonzero, empty, asarray from uncertainties import ufloat from openmc.data import DataLibrary, JOULE_PER_EV @@ -894,79 +892,3 @@ class DepSystemSolver(ABC): to ``n0``. """ - - -class IPFCramSolver(DepSystemSolver): - r"""Abstract class that implements the IPF form of CRAM - - Provides a :meth:`__call__` that utilizes an incomplete - partial factorization (IPF) for the Chebyshev Rational Approximation - Method (CRAM) [Pusa16]_ - - Concrete subclasses must provide two complex vectors :attr:`alpha` - and :attr:`theta` that make up the coefficients of the decompostion. - Vectors are expected to be of equal length ``N``. - Subclases are also expected to provide a coefficient :attr:`alpha0` - used in the final scaling step. - - Attributes - ---------- - alpha : numpy.ndarray - Complex residues of poles :attr:`theta` in the incomplete partial - factorization. Denoted as :math:`\tilde{\alpha}` - theta : numpy.ndarray - Complex poles :math:`\theta` of the rational approximation - alpha0 : float - Limit of the approximation at infinity - - References - ---------- - - .. [Pusa16] M. Pusa, "Higher-Order Chebyshev Rational Approximation - Method and Application to Burnup Equations," Nuclear Science And - Engineering, 182:3,297-318 - `DOI: 10.13182/NSE15-26 `_ - - """ - - @property - @abstractmethod - def alpha(self): - pass - - @property - @abstractmethod - def theta(self): - pass - - @property - @abstractmethod - def alpha0(self): - pass - - def __call__(self, A, n0, dt): - """Solve depletion equations using IPF CRAM - - Parameters - ---------- - A : scipy.sparse.csr_matrix - Sparse transmutation matrix ``A[j, i]`` desribing rates at - which isotope ``i`` transmutes to isotope ``j`` - n0 : numpy.ndarray - Initial compositions, typically given in number of atoms in some - material or an atom density - dt : float - Time [s] of the specific interval to be solved - - Returns - ------- - numpy.ndarray - Final compositions after ``dt`` - - """ - A = sp.csr_matrix(A * dt, dtype=float64) - y = asarray(n0, dtype=float64) - ident = sp.eye(A.shape[0]) - for alpha, theta in zip(self.alpha, self.theta): - y += 2*real(alpha*sla.spsolve(A - theta*ident, y)) - return y * self.alpha0 diff --git a/openmc/deplete/cram.py b/openmc/deplete/cram.py index 4fdba87bf..f4a847907 100644 --- a/openmc/deplete/cram.py +++ b/openmc/deplete/cram.py @@ -3,13 +3,17 @@ Implements two different forms of CRAM for use in openmc.deplete. """ +import numbers from itertools import repeat from multiprocessing import Pool import time import numpy as np +import scipy.sparse as sp +import scipy.sparse.linalg as sla -from .abc import IPFCramSolver +from openmc.checkvalue import check_type, check_length +from .abc import DepSystemSolver __all__ = [ "deplete", "timed_deplete", "CRAM16", "CRAM48", @@ -83,50 +87,51 @@ def timed_deplete(*args, **kwargs): return time.time() - start, results -class Cram16Solver(IPFCramSolver): - r"""Solver implementing the 16th order IPF CRAM +class IPFCramSolver(DepSystemSolver): + r"""Class for solving depletion systems with IPF Cram - Coefficients to :attr:`alpha`, :attr:`theta`, and :attr:`alpha0` - are from Table A.IV in [Pusa16]_. + Provides a :meth:`__call__` that utilizes an incomplete + partial factorization (IPF) for the Chebyshev Rational Approximation + Method (CRAM) + + M. Pusa, "Higher-Order Chebyshev Rational Approximation + Method and Application to Burnup Equations," Nuclear Science And + Engineering, 182:3,297-318 + `DOI: 10.13182/NSE15-26 `_ + + Parameters + ---------- + alpha : numpy.ndarray + Complex residues of poles used in the factorization. Must be a + vector with even number of items. + theta : numpy.ndarray + Complex poles. Must have an equal size as ``alpha``. + alpha0 : float + Limit of the approximation at infinity Attributes ---------- alpha : numpy.ndarray Complex residues of poles :attr:`theta` in the incomplete partial factorization. Denoted as :math:`\tilde{\alpha}` - in Algorithm 1 of [Pusa16]_ theta : numpy.ndarray Complex poles :math:`\theta` of the rational approximation alpha0 : float Limit of the approximation at infinity """ - alpha = np.array([ - +5.464930576870210e+3 - 3.797983575308356e+4j, - +9.045112476907548e+1 - 1.115537522430261e+3j, - +2.344818070467641e+2 - 4.228020157070496e+2j, - +9.453304067358312e+1 - 2.951294291446048e+2j, - +7.283792954673409e+2 - 1.205646080220011e+5j, - +3.648229059594851e+1 - 1.155509621409682e+2j, - +2.547321630156819e+1 - 2.639500283021502e+1j, - +2.394538338734709e+1 - 5.650522971778156e+0j], - dtype=np.complex128) - theta = np.array([ - +3.509103608414918 + 8.436198985884374j, - +5.948152268951177 + 3.587457362018322j, - -5.264971343442647 + 16.22022147316793j, - +1.419375897185666 + 10.92536348449672j, - +6.416177699099435 + 1.194122393370139j, - +4.993174737717997 + 5.996881713603942j, - -1.413928462488886 + 13.49772569889275j, - -10.84391707869699 + 19.27744616718165j], - dtype=np.complex128) - - alpha0 = 2.124853710495224e-16 + def __init__(self, alpha, theta, alpha0): + check_type("alpha", alpha, np.ndarray, numbers.Complex) + check_type("theta", theta, np.ndarray, numbers.Complex) + check_length("theta", theta, alpha.size) + check_type("alpha0", alpha0, numbers.Real) + self.alpha = alpha + self.theta = theta + self.alpha0 = alpha0 def __call__(self, A, n0, dt): - """Solve using 16th order IPF CRAM [Pusa16]_ + """Solve depletion equations using IPF CRAM Parameters ---------- @@ -145,114 +150,110 @@ class Cram16Solver(IPFCramSolver): Final compositions after ``dt`` """ - return super().__call__(A, n0, dt) + A = sp.csr_matrix(A * dt, dtype=np.float64) + y = np.asarray(n0, dtype=np.float64) + ident = sp.eye(A.shape[0]) + for alpha, theta in zip(self.alpha, self.theta): + y += 2*np.real(alpha*sla.spsolve(A - theta*ident, y)) + return y * self.alpha0 -class Cram48Solver(IPFCramSolver): - r"""Solver implementing the 48th order IPF CRAM +# Coefficients for IPF Cram 16 +c16_alpha = np.array([ + +5.464930576870210e+3 - 3.797983575308356e+4j, + +9.045112476907548e+1 - 1.115537522430261e+3j, + +2.344818070467641e+2 - 4.228020157070496e+2j, + +9.453304067358312e+1 - 2.951294291446048e+2j, + +7.283792954673409e+2 - 1.205646080220011e+5j, + +3.648229059594851e+1 - 1.155509621409682e+2j, + +2.547321630156819e+1 - 2.639500283021502e+1j, + +2.394538338734709e+1 - 5.650522971778156e+0j], + dtype=np.complex128) - Coefficients to :attr:`alpha`, :attr:`theta`, and :attr:`alpha0` - are from Table A.XII in [Pusa16]_. +c16_theta = np.array([ + +3.509103608414918 + 8.436198985884374j, + +5.948152268951177 + 3.587457362018322j, + -5.264971343442647 + 16.22022147316793j, + +1.419375897185666 + 10.92536348449672j, + +6.416177699099435 + 1.194122393370139j, + +4.993174737717997 + 5.996881713603942j, + -1.413928462488886 + 13.49772569889275j, + -10.84391707869699 + 19.27744616718165j], + dtype=np.complex128) - Attributes - ---------- - alpha : numpy.ndarray - Complex residues of poles :attr:`theta` in the incomplete partial - factorization. Denoted as :math:`\tilde{\alpha}` - in Algorithm 1 of [Pusa16]_ - theta : numpy.ndarray - Complex poles :math:`\theta` of the rational approximation - alpha0 : float - Limit of the approximation at infinity +c16_alpha0 = 2.124853710495224e-16 +Cram16Solver = IPFCramSolver(c16_alpha, c16_theta, c16_alpha0) +CRAM16 = Cram16Solver.__call__ - """ +del c16_alpha, c16_alpha0, c16_theta - theta_r = np.array([ - -4.465731934165702e+1, -5.284616241568964e+0, - -8.867715667624458e+0, +3.493013124279215e+0, - +1.564102508858634e+1, +1.742097597385893e+1, - -2.834466755180654e+1, +1.661569367939544e+1, - +8.011836167974721e+0, -2.056267541998229e+0, - +1.449208170441839e+1, +1.853807176907916e+1, - +9.932562704505182e+0, -2.244223871767187e+1, - +8.590014121680897e-1, -1.286192925744479e+1, - +1.164596909542055e+1, +1.806076684783089e+1, - +5.870672154659249e+0, -3.542938819659747e+1, - +1.901323489060250e+1, +1.885508331552577e+1, - -1.734689708174982e+1, +1.316284237125190e+1]) +# Coefficients for 48th order IPF Cram - theta_i = np.array([ - +6.233225190695437e+1, +4.057499381311059e+1, - +4.325515754166724e+1, +3.281615453173585e+1, - +1.558061616372237e+1, +1.076629305714420e+1, - +5.492841024648724e+1, +1.316994930024688e+1, - +2.780232111309410e+1, +3.794824788914354e+1, - +1.799988210051809e+1, +5.974332563100539e+0, - +2.532823409972962e+1, +5.179633600312162e+1, - +3.536456194294350e+1, +4.600304902833652e+1, - +2.287153304140217e+1, +8.368200580099821e+0, - +3.029700159040121e+1, +5.834381701800013e+1, - +1.194282058271408e+0, +3.583428564427879e+0, - +4.883941101108207e+1, +2.042951874827759e+1]) +theta_r = np.array([ + -4.465731934165702e+1, -5.284616241568964e+0, + -8.867715667624458e+0, +3.493013124279215e+0, + +1.564102508858634e+1, +1.742097597385893e+1, + -2.834466755180654e+1, +1.661569367939544e+1, + +8.011836167974721e+0, -2.056267541998229e+0, + +1.449208170441839e+1, +1.853807176907916e+1, + +9.932562704505182e+0, -2.244223871767187e+1, + +8.590014121680897e-1, -1.286192925744479e+1, + +1.164596909542055e+1, +1.806076684783089e+1, + +5.870672154659249e+0, -3.542938819659747e+1, + +1.901323489060250e+1, +1.885508331552577e+1, + -1.734689708174982e+1, +1.316284237125190e+1]) - theta = np.array(theta_r + theta_i * 1j, dtype=np.complex128) +theta_i = np.array([ + +6.233225190695437e+1, +4.057499381311059e+1, + +4.325515754166724e+1, +3.281615453173585e+1, + +1.558061616372237e+1, +1.076629305714420e+1, + +5.492841024648724e+1, +1.316994930024688e+1, + +2.780232111309410e+1, +3.794824788914354e+1, + +1.799988210051809e+1, +5.974332563100539e+0, + +2.532823409972962e+1, +5.179633600312162e+1, + +3.536456194294350e+1, +4.600304902833652e+1, + +2.287153304140217e+1, +8.368200580099821e+0, + +3.029700159040121e+1, +5.834381701800013e+1, + +1.194282058271408e+0, +3.583428564427879e+0, + +4.883941101108207e+1, +2.042951874827759e+1]) - alpha_r = np.array([ - +6.387380733878774e+2, +1.909896179065730e+2, - +4.236195226571914e+2, +4.645770595258726e+2, - +7.765163276752433e+2, +1.907115136768522e+3, - +2.909892685603256e+3, +1.944772206620450e+2, - +1.382799786972332e+5, +5.628442079602433e+3, - +2.151681283794220e+2, +1.324720240514420e+3, - +1.617548476343347e+4, +1.112729040439685e+2, - +1.074624783191125e+2, +8.835727765158191e+1, - +9.354078136054179e+1, +9.418142823531573e+1, - +1.040012390717851e+2, +6.861882624343235e+1, - +8.766654491283722e+1, +1.056007619389650e+2, - +7.738987569039419e+1, +1.041366366475571e+2]) +c48_theta = np.array(theta_r + theta_i * 1j, dtype=np.complex128) - alpha_i = np.array([ - -6.743912502859256e+2, -3.973203432721332e+2, - -2.041233768918671e+3, -1.652917287299683e+3, - -1.783617639907328e+4, -5.887068595142284e+4, - -9.953255345514560e+3, -1.427131226068449e+3, - -3.256885197214938e+6, -2.924284515884309e+4, - -1.121774011188224e+3, -6.370088443140973e+4, - -1.008798413156542e+6, -8.837109731680418e+1, - -1.457246116408180e+2, -6.388286188419360e+1, - -2.195424319460237e+2, -6.719055740098035e+2, - -1.693747595553868e+2, -1.177598523430493e+1, - -4.596464999363902e+3, -1.738294585524067e+3, - -4.311715386228984e+1, -2.777743732451969e+2]) +alpha_r = np.array([ + +6.387380733878774e+2, +1.909896179065730e+2, + +4.236195226571914e+2, +4.645770595258726e+2, + +7.765163276752433e+2, +1.907115136768522e+3, + +2.909892685603256e+3, +1.944772206620450e+2, + +1.382799786972332e+5, +5.628442079602433e+3, + +2.151681283794220e+2, +1.324720240514420e+3, + +1.617548476343347e+4, +1.112729040439685e+2, + +1.074624783191125e+2, +8.835727765158191e+1, + +9.354078136054179e+1, +9.418142823531573e+1, + +1.040012390717851e+2, +6.861882624343235e+1, + +8.766654491283722e+1, +1.056007619389650e+2, + +7.738987569039419e+1, +1.041366366475571e+2]) - alpha = np.array(alpha_r + alpha_i * 1j, dtype=np.complex128) +alpha_i = np.array([ + -6.743912502859256e+2, -3.973203432721332e+2, + -2.041233768918671e+3, -1.652917287299683e+3, + -1.783617639907328e+4, -5.887068595142284e+4, + -9.953255345514560e+3, -1.427131226068449e+3, + -3.256885197214938e+6, -2.924284515884309e+4, + -1.121774011188224e+3, -6.370088443140973e+4, + -1.008798413156542e+6, -8.837109731680418e+1, + -1.457246116408180e+2, -6.388286188419360e+1, + -2.195424319460237e+2, -6.719055740098035e+2, + -1.693747595553868e+2, -1.177598523430493e+1, + -4.596464999363902e+3, -1.738294585524067e+3, + -4.311715386228984e+1, -2.777743732451969e+2]) - del theta_i, theta_r, alpha_r, alpha_i +c48_alpha = np.array(alpha_r + alpha_i * 1j, dtype=np.complex128) - alpha0 = 2.258038182743983e-47 +c48_alpha0 = 2.258038182743983e-47 - def __call__(self, A, n0, dt): - """Solve using 48th order IPF CRAM [Pusa16]_ +Cram48Solver = IPFCramSolver(c48_alpha, c48_theta, c48_alpha0) - Parameters - ---------- - A : scipy.sparse.csr_matrix - Sparse transmutation matrix ``A[j, i]`` desribing rates at - which isotope ``i`` transmutes to isotope ``j`` - n0 : numpy.ndarray - Initial compositions, typically given in number of atoms in some - material or an atom density - dt : float - Time [s] of the specific interval to be solved +del c48_alpha, c48_alpha0, c48_theta, alpha_r, alpha_i, theta_r, theta_i - Returns - ------- - numpy.ndarray - Final compositions after ``dt`` +CRAM48 = Cram48Solver.__call__ - """ - return super().__call__(A, n0, dt) - - -CRAM16 = Cram16Solver().__call__ -CRAM48 = Cram48Solver().__call__ From 7a1a424d0fa5a033139513dd0a71db0701897090 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Thu, 26 Sep 2019 20:34:11 -0400 Subject: [PATCH 016/158] Tally.writeable -> Tally.writable Oops Co-Authored-By: Paul Romano --- include/openmc/capi.h | 4 ++-- include/openmc/tallies/tally.h | 2 +- openmc/deplete/abc.py | 2 +- openmc/deplete/helpers.py | 6 +++--- openmc/lib/tally.py | 26 +++++++++++++------------- 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/include/openmc/capi.h b/include/openmc/capi.h index 327594c3e..82f01d60b 100644 --- a/include/openmc/capi.h +++ b/include/openmc/capi.h @@ -110,7 +110,7 @@ extern "C" { 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_get_writeable(int32_t index, bool* writeable); + int openmc_tally_get_writable(int32_t index, bool* writable); int openmc_tally_reset(int32_t index); int openmc_tally_results(int32_t index, double** ptr, size_t shape_[3]); int openmc_tally_set_active(int32_t index, bool active); @@ -120,7 +120,7 @@ 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_set_writeable(int32_t index, bool writeable); + int openmc_tally_set_writable(int32_t index, bool writable); 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/include/openmc/tallies/tally.h b/include/openmc/tallies/tally.h index 0b0baeb8c..554d302ac 100644 --- a/include/openmc/tallies/tally.h +++ b/include/openmc/tallies/tally.h @@ -99,7 +99,7 @@ public: xt::xtensor results_; //! True if this tally should be written to statepoint files - bool writeable_ {true}; + bool writable_ {true}; //---------------------------------------------------------------------------- // Miscellaneous public members. diff --git a/openmc/deplete/abc.py b/openmc/deplete/abc.py index 3a7eee34d..44f93c7ee 100644 --- a/openmc/deplete/abc.py +++ b/openmc/deplete/abc.py @@ -539,7 +539,7 @@ class TalliedFissionYieldHelper(FissionYieldHelper): # Tally group-wise fission reaction rates self._fission_rate_tally = Tally() - self._fission_rate_tally.writeable = False + self._fission_rate_tally.writable = False self._fission_rate_tally.scores = ['fission'] self._fission_rate_tally.filters = [MaterialFilter(materials)] diff --git a/openmc/deplete/helpers.py b/openmc/deplete/helpers.py index b1e7e17ef..d79a03111 100644 --- a/openmc/deplete/helpers.py +++ b/openmc/deplete/helpers.py @@ -59,7 +59,7 @@ class DirectReactionRateHelper(ReactionRateHelper): ``"(n, gamma)"``, needed for the reaction rate tally. """ self._rate_tally = Tally() - self._rate_tally.writeable = False + self._rate_tally.writable = False self._rate_tally.scores = scores self._rate_tally.filters = [MaterialFilter(materials)] @@ -195,7 +195,7 @@ class EnergyScoreHelper(EnergyHelper): """ self._tally = Tally() - self._tally.writeable = False + self._tally.writable = False self._tally.scores = [self.score] def reset(self): @@ -572,7 +572,7 @@ class AveragedFissionYieldHelper(TalliedFissionYieldHelper): func_filter = EnergyFunctionFilter() func_filter.set_data((0, self._upper_energy), (0, self._upper_energy)) weighted_tally = Tally() - weighted_tally.writeable = False + weighted_tally.writable = False weighted_tally.scores = ['fission'] weighted_tally.filters = filters + [func_filter] self._weighted_tally = weighted_tally diff --git a/openmc/lib/tally.py b/openmc/lib/tally.py index 906084c4b..2e8d43ae8 100644 --- a/openmc/lib/tally.py +++ b/openmc/lib/tally.py @@ -53,9 +53,9 @@ _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_get_writeable.argtypes = [c_int32, POINTER(c_bool)] -_dll.openmc_tally_get_writeable.restype = c_int -_dll.openmc_tally_get_writeable.errcheck = _error_handler +_dll.openmc_tally_get_writable.argtypes = [c_int32, POINTER(c_bool)] +_dll.openmc_tally_get_writable.restype = c_int +_dll.openmc_tally_get_writable.errcheck = _error_handler _dll.openmc_tally_reset.argtypes = [c_int32] _dll.openmc_tally_reset.restype = c_int _dll.openmc_tally_reset.errcheck = _error_handler @@ -84,9 +84,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_set_writeable.argtypes = [c_int32, c_bool] -_dll.openmc_tally_set_writeable.restype = c_int -_dll.openmc_tally_set_writeable.errcheck = _error_handler +_dll.openmc_tally_set_writable.argtypes = [c_int32, c_bool] +_dll.openmc_tally_set_writable.restype = c_int +_dll.openmc_tally_set_writable.errcheck = _error_handler _dll.tallies_size.restype = c_size_t @@ -351,14 +351,14 @@ class Tally(_FortranObjectWithID): return std_dev @property - def writeable(self): - writeable = c_bool() - _dll.openmc_tally_get_writeable(self._index, writeable) - return writeable.value + def writable(self): + writable = c_bool() + _dll.openmc_tally_get_writable(self._index, writable) + return writable.value - @writeable.setter - def writeable(self, writeable): - _dll.openmc_tally_set_writeable(self._index, writeable) + @writable.setter + def writable(self, writable): + _dll.openmc_tally_set_writable(self._index, writable) def reset(self): """Reset results and num_realizations of tally""" From 801f18b3573a4eadb18618751d44dfafa577d9a4 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Thu, 26 Sep 2019 20:56:31 -0400 Subject: [PATCH 017/158] Provide Tally writable_ setter and getters New member functions openmc::Tally.set_writable and get_writable act on the writable attribute. These are used in the external API with openmc_tally_set_writable and openmc_tally_get_writable functions. Cleaned up some other writeable -> writable typos as well --- include/openmc/tallies/tally.h | 4 ++++ src/output.cpp | 2 +- src/state_point.cpp | 12 +++++------- src/tallies/tally.cpp | 8 ++++---- tests/unit_tests/test_lib.py | 12 ++++++------ 5 files changed, 20 insertions(+), 18 deletions(-) diff --git a/include/openmc/tallies/tally.h b/include/openmc/tallies/tally.h index 554d302ac..f411e6560 100644 --- a/include/openmc/tallies/tally.h +++ b/include/openmc/tallies/tally.h @@ -37,6 +37,8 @@ public: void set_active(bool active) { active_ = active; } + void set_writable(bool writable) { writable_ = writable; } + void set_scores(pugi::xml_node node); void set_scores(const std::vector& scores); @@ -55,6 +57,8 @@ public: int32_t n_filter_bins() const {return n_filter_bins_;} + bool get_writable() const { return writable_;} + //---------------------------------------------------------------------------- // Other methods. diff --git a/src/output.cpp b/src/output.cpp index 439fc1558..d3262cc4d 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -643,7 +643,7 @@ write_tallies() if (!tally.name_.empty()) tally_header += ": " + tally.name_; tallies_out << header(tally_header) << "\n\n"; - if (!tally.writeable_) { + if (!tally.writable_) { tallies_out << " Internal\n\n"; continue; } diff --git a/src/state_point.cpp b/src/state_point.cpp index a550748a5..cd2c475d8 100644 --- a/src/state_point.cpp +++ b/src/state_point.cpp @@ -171,7 +171,7 @@ openmc_statepoint_write(const char* filename, bool* write_source) write_dataset(tally_group, "name", tally->name_); - if (tally->writeable_) { + if (tally->writable_) { write_attribute(tally_group, "internal", 0); } else { write_attribute(tally_group, "internal", 1); @@ -239,7 +239,7 @@ openmc_statepoint_write(const char* filename, bool* write_source) // Write all tally results for (const auto& tally : model::tallies) { - if (!tally->writeable_) continue; + if (!tally->writable_) continue; // Write sum and sum_sq for each bin std::string name = "tally " + std::to_string(tally->id_); hid_t tally_group = open_group(tallies_group, name.c_str()); @@ -434,14 +434,12 @@ void load_state_point() std::string name = "tally " + std::to_string(tally->id_); hid_t tally_group = open_group(tallies_group, name.c_str()); - int internal; + int internal=0; if (attribute_exists(tally_group, "internal")) { read_attribute(tally_group, "internal", internal); - } else { - internal = 0; } if (internal) { - tally->writeable_ = false; + tally->writable_ = false; } else { auto& results = tally->results_; @@ -717,7 +715,7 @@ void write_tally_results_nr(hid_t file_id) for (const auto& t : model::tallies) { // Skip any tallies that are not active if (!t->active_) continue; - if (!t->writeable_) continue; + if (!t->writable_) continue; if (mpi::master && !object_exists(file_id, "tallies_present")) { write_attribute(file_id, "tallies_present", 1); diff --git a/src/tallies/tally.cpp b/src/tallies/tally.cpp index 96253285e..3e9de83b1 100644 --- a/src/tallies/tally.cpp +++ b/src/tallies/tally.cpp @@ -1221,25 +1221,25 @@ openmc_tally_set_active(int32_t index, bool active) } extern "C" int -openmc_tally_get_writeable(int32_t index, bool* writeable) +openmc_tally_get_writable(int32_t index, bool* writable) { if (index < 0 || index >= model::tallies.size()) { set_errmsg("Index in tallies array is out of bounds."); return OPENMC_E_OUT_OF_BOUNDS; } - *writeable = model::tallies[index]->writeable_; + *writable = model::tallies[index]->get_writable(); return 0; } extern "C" int -openmc_tally_set_writeable(int32_t index, bool writeable) +openmc_tally_set_writable(int32_t index, bool writable) { if (index < 0 || index >= model::tallies.size()) { set_errmsg("Index in tallies array is out of bounds."); return OPENMC_E_OUT_OF_BOUNDS; } - model::tallies[index]->writeable_ = writeable; + model::tallies[index]->set_writable(writable); return 0; } diff --git a/tests/unit_tests/test_lib.py b/tests/unit_tests/test_lib.py index 7f992cb09..ad198f255 100644 --- a/tests/unit_tests/test_lib.py +++ b/tests/unit_tests/test_lib.py @@ -256,13 +256,13 @@ def test_tally_activate(lib_simulation_init): assert t.active -def test_tally_writeable(lib_simulation_init): +def test_tally_writable(lib_simulation_init): t = openmc.lib.tallies[1] - assert t.writeable - t.writeable = False - assert not t.writeable - # Revert tally to writeable state for lib_run fixtures - t.writeable = True + assert t.writable + t.writable = False + assert not t.writable + # Revert tally to writable state for lib_run fixtures + t.writable = True def test_tally_results(lib_run): From 1b8bc2d01d3038fbf6d0eb1dd17ad331b587af82 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Fri, 27 Sep 2019 10:43:36 -0500 Subject: [PATCH 018/158] Correcting default values in set_id methods. Initializing material ids to match the initialization logic. --- include/openmc/material.h | 4 ++-- include/openmc/tallies/filter.h | 2 +- src/material.cpp | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/openmc/material.h b/include/openmc/material.h index 652f3db8e..8771b372a 100644 --- a/include/openmc/material.h +++ b/include/openmc/material.h @@ -120,7 +120,7 @@ public: //! Assign a unique ID to the material //! \param[in] Unique ID to assign. A value of -1 indicates that an ID //! should be automatically assigned. - void set_id(int32_t id); + void set_id(int32_t id = -1); //! Get whether material is fissionable //! \return Whether material is fissionable @@ -132,7 +132,7 @@ public: //---------------------------------------------------------------------------- // Data - int32_t id_; //!< Unique ID + int32_t id_ {-1}; //!< Unique ID std::string name_; //!< Name of material std::vector nuclide_; //!< Indices in nuclides vector std::vector element_; //!< Indices in elements vector diff --git a/include/openmc/tallies/filter.h b/include/openmc/tallies/filter.h index ba6ca0883..b25110e07 100644 --- a/include/openmc/tallies/filter.h +++ b/include/openmc/tallies/filter.h @@ -104,7 +104,7 @@ public: //! Assign a unique ID to the filter //! \param[in] Unique ID to assign. A value of -1 indicates that an ID should //! be automatically assigned - void set_id(int32_t id); + void set_id(int32_t id = -1); //! Get number of bins //! \return Number of bins diff --git a/src/material.cpp b/src/material.cpp index 685fd1da2..9a1e206ac 100644 --- a/src/material.cpp +++ b/src/material.cpp @@ -873,8 +873,8 @@ void Material::set_id(int32_t id) // If no ID specified, auto-assign next ID in sequence if (id == -1) { id = 0; - for (const auto& f : model::materials) { - id = std::max(id, f->id_); + for (const auto& m : model::materials) { + id = std::max(id, m->id_); } ++id; } From e7b28ab8d99c43aeb3419c52eeada0bf83cdd4a6 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Mon, 30 Sep 2019 14:31:26 -0500 Subject: [PATCH 019/158] Removing default values for set_id args as requested by @paulromano. --- include/openmc/material.h | 2 +- include/openmc/tallies/filter.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/openmc/material.h b/include/openmc/material.h index 8771b372a..70c6b3852 100644 --- a/include/openmc/material.h +++ b/include/openmc/material.h @@ -120,7 +120,7 @@ public: //! Assign a unique ID to the material //! \param[in] Unique ID to assign. A value of -1 indicates that an ID //! should be automatically assigned. - void set_id(int32_t id = -1); + void set_id(int32_t id); //! Get whether material is fissionable //! \return Whether material is fissionable diff --git a/include/openmc/tallies/filter.h b/include/openmc/tallies/filter.h index b25110e07..ba6ca0883 100644 --- a/include/openmc/tallies/filter.h +++ b/include/openmc/tallies/filter.h @@ -104,7 +104,7 @@ public: //! Assign a unique ID to the filter //! \param[in] Unique ID to assign. A value of -1 indicates that an ID should //! be automatically assigned - void set_id(int32_t id = -1); + void set_id(int32_t id); //! Get number of bins //! \return Number of bins From 484bf70c86a3f46280fd0bed5a95d8180148d808 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Mon, 30 Sep 2019 18:55:42 -0400 Subject: [PATCH 020/158] Tally.get_writable() -> Tally.writable() Co-Authored-By: Paul Romano --- include/openmc/tallies/tally.h | 2 +- src/tallies/tally.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/openmc/tallies/tally.h b/include/openmc/tallies/tally.h index f411e6560..dc7cd8ce2 100644 --- a/include/openmc/tallies/tally.h +++ b/include/openmc/tallies/tally.h @@ -57,7 +57,7 @@ public: int32_t n_filter_bins() const {return n_filter_bins_;} - bool get_writable() const { return writable_;} + bool writable() const { return writable_;} //---------------------------------------------------------------------------- // Other methods. diff --git a/src/tallies/tally.cpp b/src/tallies/tally.cpp index 3e9de83b1..f84387411 100644 --- a/src/tallies/tally.cpp +++ b/src/tallies/tally.cpp @@ -1227,7 +1227,7 @@ openmc_tally_get_writable(int32_t index, bool* writable) set_errmsg("Index in tallies array is out of bounds."); return OPENMC_E_OUT_OF_BOUNDS; } - *writable = model::tallies[index]->get_writable(); + *writable = model::tallies[index]->writable(); return 0; } From 9a78836d2238fe11fa637447f236ff45b6fc0e04 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Tue, 1 Oct 2019 10:31:29 -0500 Subject: [PATCH 021/158] Make sure Shannon entropy mesh without dimension can be assigned --- src/mesh.cpp | 3 ++- src/settings.cpp | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/mesh.cpp b/src/mesh.cpp index ac02b679e..acd80c7ba 100644 --- a/src/mesh.cpp +++ b/src/mesh.cpp @@ -155,7 +155,8 @@ RegularMesh::RegularMesh(pugi::xml_node node) fatal_error("Must specify either and on a mesh."); } - if (shape_.dimension() > 0) { + // TODO: Change to zero when xtensor is updated + if (shape_.size() > 1) { if (shape_.size() != lower_left_.size()) { fatal_error("Number of entries on must be the same " "as the number of entries on ."); diff --git a/src/settings.cpp b/src/settings.cpp index 1c9d1161a..796a2862a 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -512,7 +512,8 @@ void read_settings_xml() if (!m) fatal_error("Only regular meshes can be used as an entropy mesh"); simulation::entropy_mesh = m; - if (m->shape_.dimension() == 0) { + // TODO: Change to zero when xtensor is updated + if (m->shape_.size() == 1) { // If the user did not specify how many mesh cells are to be used in // each direction, we automatically determine an appropriate number of // cells From 4b19dc9ffce638276a546ef17d51442a96377d6b Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Tue, 1 Oct 2019 11:41:18 -0400 Subject: [PATCH 022/158] Add TODOs to rotate_angle for a change in azimuth --- src/distribution_multi.cpp | 10 ++++++++-- src/math_functions.cpp | 6 ++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/distribution_multi.cpp b/src/distribution_multi.cpp index 0c1ecddec..c388254b6 100644 --- a/src/distribution_multi.cpp +++ b/src/distribution_multi.cpp @@ -59,8 +59,14 @@ Direction PolarAzimuthal::sample() const double mu = mu_->sample(); if (mu == 1.0) return u_ref_; - // Sample the azimuthal angle with an offset to match azimuth conventions - double phi = phi_->sample() + 0.5*PI; + // Sample azimuthal angle + double phi = phi_->sample(); + + // If the reference direction is along the z-axis, rotate the aziumthal angle + // to match spherical coordinate conventions. + // TODO: apply this change directly to rotate_angle + if (u_ref_.x == 0 && u_ref_.y == 0) phi += 0.5*PI; + return rotate_angle(u_ref_, mu, &phi); } diff --git a/src/math_functions.cpp b/src/math_functions.cpp index ec5d64eac..7525a7ddd 100644 --- a/src/math_functions.cpp +++ b/src/math_functions.cpp @@ -665,6 +665,12 @@ Direction rotate_angle(Direction u, double mu, const double* phi) return {mu*u.x + a*(u.x*u.y*cosphi + u.z*sinphi) / b, mu*u.y - a*b*cosphi, mu*u.z + a*(u.y*u.z*cosphi - u.x*sinphi) / b}; + // TODO: use the following code to make PolarAzimuthal distributions match + // spherical coordinate conventions. Remove the related fixup code in + // PolarAzimuthal::sample. + //return {mu*u.x + a*(-u.x*u.y*sinphi + u.z*cosphi) / b, + // mu*u.y + a*b*sinphi, + // mu*u.z - a*(u.y*u.z*sinphi + u.x*cosphi) / b}; } } From e510064b9cbf58bbf4e630d9a61f151a67043d62 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 2 Oct 2019 21:09:18 -0500 Subject: [PATCH 023/158] Make sure heating is calculated correctly with threshold fission When trying to process Pa233 from ENDF/B-VIII.0, which has a threshold fission reaction, I discovered that calculating heating numbers crashed because we were trying to do arithmetic on arrays of different sizes. Re-evaluting the fission cross section on the proper energy grid does the trick here. --- openmc/data/neutron.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openmc/data/neutron.py b/openmc/data/neutron.py index 8a6c88981..ea14be784 100644 --- a/openmc/data/neutron.py +++ b/openmc/data/neutron.py @@ -874,7 +874,7 @@ class IncidentNeutron(EqualityMixin): fission = data.reactions[18].xs[temp] kerma_fission = get_file3_xs(ev, 318, E) kerma.y = kerma.y - kerma_fission + ( - f.fragments(E) + f.betas(E)) * fission.y + f.fragments(E) + f.betas(E)) * fission(E) # For local KERMA, we first need to get the values from the # HEATR run with photon energy deposited locally and put @@ -887,7 +887,7 @@ class IncidentNeutron(EqualityMixin): kerma_fission_local = get_file3_xs(ev_local, 318, E) kerma_local = kerma_local - kerma_fission_local + ( f.fragments(E) + f.prompt_photons(E) - + f.delayed_photons(E) + f.betas(E))*fission.y + + f.delayed_photons(E) + f.betas(E))*fission(E) heating_local.xs[temp] = Tabulated1D(E, kerma_local) From 92d410ed776df1f3758c17a8bc6663fd42ae0958 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 2 Oct 2019 21:29:42 -0500 Subject: [PATCH 024/158] Ensure all thermal scattering evals from ENDF/B-VIII.0 and JEFF 3.3 work --- openmc/data/njoy.py | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/openmc/data/njoy.py b/openmc/data/njoy.py index 4983098f7..83fe991c7 100644 --- a/openmc/data/njoy.py +++ b/openmc/data/njoy.py @@ -25,13 +25,16 @@ _THERMAL_DATA = { 13: ThermalTuple('orthod', [1002], 1), 26: ThermalTuple('be', [4009], 1), 27: ThermalTuple('bebeo', [4009], 1), - 31: ThermalTuple('graph', [6000, 6012, 6013], 1), + 30: ThermalTuple('graph', [6000, 6012, 6013], 1), + 31: ThermalTuple('grph10', [6000, 6012, 6013], 1), + 32: ThermalTuple('grph30', [6000, 6012, 6013], 1), 33: ThermalTuple('lch4', [1001], 1), 34: ThermalTuple('sch4', [1001], 1), 37: ThermalTuple('hch2', [1001], 1), + 38: ThermalTuple('mesi00', [1001], 1), 39: ThermalTuple('lucite', [1001], 1), 40: ThermalTuple('benz', [1001, 6000, 6012], 2), - 41: ThermalTuple('od2o', [8016, 8017, 8018], 1), + 42: ThermalTuple('tol00', [1001], 1), 43: ThermalTuple('sisic', [14028, 14029, 14030], 1), 44: ThermalTuple('csic', [6000, 6012, 6013], 1), 46: ThermalTuple('obeo', [8016, 8017, 8018], 1), @@ -39,12 +42,16 @@ _THERMAL_DATA = { 48: ThermalTuple('uuo2', [92238], 1), 49: ThermalTuple('sio2-b', [8016, 8017, 8018, 14028, 14029, 14030], 3), 50: ThermalTuple('oice', [8016, 8017, 8018], 1), + 51: ThermalTuple('od2o', [8016, 8017, 8018], 1), 52: ThermalTuple('mg24', [12024], 1), 53: ThermalTuple('al27', [13027], 1), 55: ThermalTuple('yyh2', [39089], 1), 56: ThermalTuple('fe56', [26056], 1), 58: ThermalTuple('zrzrh', [40000, 40090, 40091, 40092, 40094, 40096], 1), 59: ThermalTuple('cacah2', [20040, 20042, 20043, 20044, 20046, 20048], 1), + 60: ThermalTuple('asap00', [13027], 1), + 71: ThermalTuple('n-un', [7014, 7015], 1), + 72: ThermalTuple('u-un', [92238], 1), 75: ThermalTuple('ouo2', [8016, 8017, 8018], 1), } @@ -444,7 +451,21 @@ def make_ace_thermal(filename, filename_thermal, temperatures=None, mat_thermal = ev_thermal.material zsymam_thermal = ev_thermal.target['zsymam'] + # Determine name, isotopes based on MAT number data = _THERMAL_DATA[mat_thermal] + if ev_thermal.info['library'][0] == 'JEFF': + # JEFF uses MAT=48 for O in Sapphire even though ENDF already uses + # that MAT number for U in UO2. It also assigns MAT=49 (which is + # supposed to be Ca in CaH2) to silicon. + if ev_thermal.material == 48: + data = ThermalTuple('osap00', [8016, 8017, 8018], 1) + elif ev_thermal.gnd_name == 'Si28': + data = ThermalTuple('si00', [14028], 1) + elif ev_thermal.info['library'] != ('ENDF/B', 8, 0): + # Before ENDF/B-VIII.0, crystalline graphite was MAT=31 + if ev_thermal.material == 31: + data = ThermalTuple('graph', [6000, 6012, 6013], 1) + zaids = ' '.join(str(zaid) for zaid in data.zaids[:3]) # Determine name of library From 829f12b1b52daf0218b9b929710301a0b9b89dee Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 3 Oct 2019 11:49:56 -0500 Subject: [PATCH 025/158] Move thermal scattering MAT number bug fixes into a dedicated function --- openmc/data/njoy.py | 62 ++++++++++++++++++++++++++++++------------ openmc/data/thermal.py | 3 ++ 2 files changed, 47 insertions(+), 18 deletions(-) diff --git a/openmc/data/njoy.py b/openmc/data/njoy.py index 83fe991c7..0c853102f 100644 --- a/openmc/data/njoy.py +++ b/openmc/data/njoy.py @@ -10,7 +10,7 @@ from . import endf # For a given MAT number, give a name for the ACE table and a list of ZAID -# identifiers +# identifiers. This is based on Appendix C in the ENDF manual. ThermalTuple = namedtuple('ThermalTuple', ['name', 'zaids', 'nmix']) _THERMAL_DATA = { 1: ThermalTuple('hh2o', [1001], 1), @@ -23,13 +23,16 @@ _THERMAL_DATA = { 11: ThermalTuple('dd2o', [1002], 1), 12: ThermalTuple('parad', [1002], 1), 13: ThermalTuple('orthod', [1002], 1), + 14: ThermalTuple('dice', [1002], 1), 26: ThermalTuple('be', [4009], 1), 27: ThermalTuple('bebeo', [4009], 1), + 28: ThermalTuple('bebe2c', [4009], 1), 30: ThermalTuple('graph', [6000, 6012, 6013], 1), 31: ThermalTuple('grph10', [6000, 6012, 6013], 1), 32: ThermalTuple('grph30', [6000, 6012, 6013], 1), 33: ThermalTuple('lch4', [1001], 1), 34: ThermalTuple('sch4', [1001], 1), + 35: ThermalTuple('sch4p2', [1001], 1), 37: ThermalTuple('hch2', [1001], 1), 38: ThermalTuple('mesi00', [1001], 1), 39: ThermalTuple('lucite', [1001], 1), @@ -37,9 +40,10 @@ _THERMAL_DATA = { 42: ThermalTuple('tol00', [1001], 1), 43: ThermalTuple('sisic', [14028, 14029, 14030], 1), 44: ThermalTuple('csic', [6000, 6012, 6013], 1), + 45: ThermalTuple('ouo2', [8016, 8017, 8018], 1), 46: ThermalTuple('obeo', [8016, 8017, 8018], 1), 47: ThermalTuple('sio2-a', [8016, 8017, 8018, 14028, 14029, 14030], 3), - 48: ThermalTuple('uuo2', [92238], 1), + 48: ThermalTuple('osap00', [92238], 1), 49: ThermalTuple('sio2-b', [8016, 8017, 8018, 14028, 14029, 14030], 3), 50: ThermalTuple('oice', [8016, 8017, 8018], 1), 51: ThermalTuple('od2o', [8016, 8017, 8018], 1), @@ -48,13 +52,48 @@ _THERMAL_DATA = { 55: ThermalTuple('yyh2', [39089], 1), 56: ThermalTuple('fe56', [26056], 1), 58: ThermalTuple('zrzrh', [40000, 40090, 40091, 40092, 40094, 40096], 1), - 59: ThermalTuple('cacah2', [20040, 20042, 20043, 20044, 20046, 20048], 1), + 59: ThermalTuple('si00', [14028], 1), 60: ThermalTuple('asap00', [13027], 1), 71: ThermalTuple('n-un', [7014, 7015], 1), 72: ThermalTuple('u-un', [92238], 1), - 75: ThermalTuple('ouo2', [8016, 8017, 8018], 1), + 75: ThermalTuple('uuo2', [8016, 8017, 8018], 1), } + +def _get_thermal_data(ev, mat): + """Return appropriate ThermalTuple, accounting for bugs.""" + + # JEFF assigns MAT=59 to Ca in CaH2 (which is supposed to be silicon). + if ev.info['library'][0] == 'JEFF': + if ev.material == 59: + if 'CaH2' in ''.join(ev.info['description']): + zaids = [20040, 20042, 20043, 20044, 20046, 20048] + return ThermalTuple('cacah2', zaids, 1) + + # Before ENDF/B-VIII.0, crystalline graphite was MAT=31 + if ev.info['library'] != ('ENDF/B', 8, 0): + if ev.material == 31: + return _THERMAL_DATA[30] + + # ENDF/B incorrectly assigns MAT numbers for UO2 + # + # Material | ENDF Manual | VII.0 | VII.1 | VIII.0 + # ---------|-------------|-------|-------|------- + # O in UO2 | 45 | 75 | 75 | 75 + # U in UO2 | 75 | 76 | 48 | 48 + if ev.info['library'][0] == 'ENDF/B': + if ev.material == 75: + return _THERMAL_DATA[45] + version = ev.info['library'][1:] + if version in ((7, 1), (8, 0)) and ev.material == 48: + return _THERMAL_DATA[75] + if version == (7, 0) and ev.material == 76: + return _THERMAL_DATA[75] + + # If not a problematic material, use the dictionary as is + return _THERMAL_DATA[mat] + + _TEMPLATE_RECONR = """ reconr / %%%%%%%%%%%%%%%%%%% Reconstruct XS for neutrons %%%%%%%%%%%%%%%%%%%%%%% {nendf} {npendf} @@ -452,20 +491,7 @@ def make_ace_thermal(filename, filename_thermal, temperatures=None, zsymam_thermal = ev_thermal.target['zsymam'] # Determine name, isotopes based on MAT number - data = _THERMAL_DATA[mat_thermal] - if ev_thermal.info['library'][0] == 'JEFF': - # JEFF uses MAT=48 for O in Sapphire even though ENDF already uses - # that MAT number for U in UO2. It also assigns MAT=49 (which is - # supposed to be Ca in CaH2) to silicon. - if ev_thermal.material == 48: - data = ThermalTuple('osap00', [8016, 8017, 8018], 1) - elif ev_thermal.gnd_name == 'Si28': - data = ThermalTuple('si00', [14028], 1) - elif ev_thermal.info['library'] != ('ENDF/B', 8, 0): - # Before ENDF/B-VIII.0, crystalline graphite was MAT=31 - if ev_thermal.material == 31: - data = ThermalTuple('graph', [6000, 6012, 6013], 1) - + data = _get_thermal_data(ev_thermal, mat_thermal) zaids = ' '.join(str(zaid) for zaid in data.zaids[:3]) # Determine name of library diff --git a/openmc/data/thermal.py b/openmc/data/thermal.py index 4fbe96363..067c0a703 100644 --- a/openmc/data/thermal.py +++ b/openmc/data/thermal.py @@ -33,10 +33,12 @@ _THERMAL_NAMES = { 'c_Be': ('be', 'be-metal', 'be-met', 'be00'), 'c_BeO': ('beo',), 'c_Be_in_BeO': ('bebeo', 'be-beo', 'be-o', 'be/o', 'bbeo00'), + 'c_Be_in_Be2C': ('bebe2c',), 'c_C6H6': ('benz', 'c6h6'), 'c_C_in_SiC': ('csic', 'c-sic'), 'c_Ca_in_CaH2': ('cah', 'cah00'), 'c_D_in_D2O': ('dd2o', 'd-d2o', 'hwtr', 'hw', 'dhw00'), + 'c_D_in_D2O_ice': ('dice',), 'c_Fe56': ('fe', 'fe56', 'fe-56'), 'c_Graphite': ('graph', 'grph', 'gr', 'gr00'), 'c_Graphite_10p': ('grph10',), @@ -45,6 +47,7 @@ _THERMAL_NAMES = { 'c_H_in_CH2': ('hch2', 'poly', 'pol', 'h-poly', 'pol00'), 'c_H_in_CH4_liquid': ('lch4', 'lmeth'), 'c_H_in_CH4_solid': ('sch4', 'smeth'), + 'c_H_in_CH4_solid_phase_II': ('sch4p2',), 'c_H_in_H2O': ('hh2o', 'h-h2o', 'lwtr', 'lw', 'lw00'), 'c_H_in_H2O_solid': ('hice', 'h-ice', 'ice00'), 'c_H_in_C5O2H8': ('lucite', 'c5o2h8', 'h-luci'), From c18f8457123ffea9f482966844a3912c0f2287a7 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 3 Oct 2019 13:17:15 -0500 Subject: [PATCH 026/158] Fix broken links in documentation --- docs/source/devguide/docbuild.rst | 13 +++++---- docs/source/devguide/docker.rst | 3 +- docs/source/devguide/styleguide.rst | 6 ++-- docs/source/devguide/workflow.rst | 2 +- docs/source/index.rst | 12 ++++---- docs/source/io_formats/settings.rst | 2 +- docs/source/methods/cmfd.rst | 2 +- docs/source/methods/cross_sections.rst | 4 +-- docs/source/methods/geometry.rst | 4 +-- docs/source/methods/introduction.rst | 8 +++--- docs/source/methods/neutron_physics.rst | 18 ++++++------ docs/source/methods/parallelization.rst | 24 ++++++++-------- docs/source/methods/random_numbers.rst | 4 +-- docs/source/methods/tallies.rst | 26 ++++++++--------- docs/source/publications.rst | 4 +-- docs/source/pythonapi/deplete.rst | 10 +++---- docs/source/pythonapi/index.rst | 2 +- docs/source/releasenotes/0.11.0.rst | 5 +++- docs/source/releasenotes/0.4.1.rst | 12 ++++---- docs/source/releasenotes/0.4.2.rst | 20 ++++++------- docs/source/releasenotes/0.4.3.rst | 18 ++++++------ docs/source/releasenotes/0.4.4.rst | 10 +++---- docs/source/releasenotes/0.5.0.rst | 16 +++++------ docs/source/releasenotes/0.5.1.rst | 10 +++---- docs/source/releasenotes/0.5.2.rst | 24 ++++++++-------- docs/source/releasenotes/0.5.3.rst | 10 +++---- docs/source/releasenotes/0.5.4.rst | 14 ++++----- docs/source/releasenotes/0.6.0.rst | 14 ++++----- docs/source/releasenotes/0.6.1.rst | 20 ++++++------- docs/source/releasenotes/0.6.2.rst | 8 +++--- docs/source/releasenotes/0.7.0.rst | 10 +++---- docs/source/releasenotes/0.7.1.rst | 18 ++++++------ docs/source/releasenotes/0.8.0.rst | 22 +++++++------- docs/source/releasenotes/0.9.0.rst | 38 ++++++++++++------------- docs/source/usersguide/beginners.rst | 18 ++++++------ docs/source/usersguide/geometry.rst | 4 +-- docs/source/usersguide/install.rst | 9 +++--- docs/source/usersguide/plots.rst | 2 +- openmc/mgxs/__init__.py | 2 +- openmc/plots.py | 2 +- 40 files changed, 228 insertions(+), 222 deletions(-) diff --git a/docs/source/devguide/docbuild.rst b/docs/source/devguide/docbuild.rst index 5cbbb65bb..38ef628df 100644 --- a/docs/source/devguide/docbuild.rst +++ b/docs/source/devguide/docbuild.rst @@ -5,27 +5,28 @@ Building Sphinx Documentation ============================= In order to build the documentation in the ``docs`` directory, you will need to -have the `Sphinx `_ third-party Python +have the `Sphinx `_ third-party Python package. The easiest way to install Sphinx is via pip: .. code-block:: sh - sudo pip install sphinx + pip install sphinx -Additionally, you will also need a Sphinx extension for numbering figures. The -`Numfig `_ package can be installed +Additionally, you will need several Sphinx extensions that can be installed directly with pip: .. code-block:: sh - sudo pip install sphinx-numfig + pip install sphinx-numfig + pip install sphinxcontrib-katex + pip install sphinxcontrib-svg2pdfconverter ----------------------------------- Building Documentation as a Webpage ----------------------------------- To build the documentation as a webpage (what appears at -http://openmc.readthedocs.io), simply go to the ``docs`` directory and run: +https://docs.openmc.org), simply go to the ``docs`` directory and run: .. code-block:: sh diff --git a/docs/source/devguide/docker.rst b/docs/source/devguide/docker.rst index 12c095c45..0b2191168 100644 --- a/docs/source/devguide/docker.rst +++ b/docs/source/devguide/docker.rst @@ -19,7 +19,7 @@ build a Docker image with OpenMC installed. The image includes OpenMC with MPICH and parallel HDF5 in the ``/opt/openmc`` directory, and `Miniconda3 `_ with all of the Python pre-requisites (NumPy, SciPy, Pandas, etc.) installed. The -`NJOY2016 `_ codebase is installed in +`NJOY2016 `_ codebase is installed in ``/opt/NJOY2016`` to support full functionality and testing of the ``openmc.data`` Python module. The publicly available nuclear data libraries necessary to run OpenMC's test suite -- including NNDC and WMP cross sections @@ -54,4 +54,3 @@ Docker container where you have access to use OpenMC. .. _Docker container: https://www.docker.com/resources/what-container .. _options: https://docs.docker.com/engine/reference/commandline/run/ .. _mounting volumes: https://docs.docker.com/storage/volumes/ - diff --git a/docs/source/devguide/styleguide.rst b/docs/source/devguide/styleguide.rst index cbf665cc8..562b75e89 100644 --- a/docs/source/devguide/styleguide.rst +++ b/docs/source/devguide/styleguide.rst @@ -207,8 +207,8 @@ Documentation ------------- Classes, structs, and functions are to be annotated for the `Doxygen -`_ documentation generation tool. Use the -``\`` form of Doxygen commands, e.g., ``\brief`` instead of ``@brief``. +`_ documentation generation tool. Use the ``\`` form of +Doxygen commands, e.g., ``\brief`` instead of ``@brief``. ------ Python @@ -231,7 +231,7 @@ represent a filesystem path should work with both strings and Path_ objects. .. _C++ Core Guidelines: http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines .. _PEP8: https://www.python.org/dev/peps/pep-0008/ .. _numpydoc: https://numpydoc.readthedocs.io/en/latest/format.html -.. _numpy: http://www.numpy.org/ +.. _numpy: https://numpy.org/ .. _scipy: https://www.scipy.org/ .. _matplotlib: https://matplotlib.org/ .. _pandas: https://pandas.pydata.org/ diff --git a/docs/source/devguide/workflow.rst b/docs/source/devguide/workflow.rst index 31dc08842..037b8b68a 100644 --- a/docs/source/devguide/workflow.rst +++ b/docs/source/devguide/workflow.rst @@ -124,7 +124,7 @@ can interfere with virtual environments. .. _GitHub: https://github.com/ .. _git flow: http://nvie.com/git-model .. _valgrind: http://valgrind.org/ -.. _style guide: http://openmc.readthedocs.io/en/latest/devguide/styleguide.html +.. _style guide: https://docs.openmc.org/en/latest/devguide/styleguide.html .. _pull request: https://help.github.com/articles/using-pull-requests .. _openmc-dev/openmc: https://github.com/openmc-dev/openmc .. _paid plan: https://github.com/plans diff --git a/docs/source/index.rst b/docs/source/index.rst index 2ce5072d0..198a9429e 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -2,12 +2,14 @@ The OpenMC Monte Carlo Code =========================== -OpenMC is a Monte Carlo particle transport simulation code focused on neutron -criticality calculations. It is capable of simulating 3D models based on -constructive solid geometry with second-order surfaces. OpenMC supports either -continuous-energy or multi-group transport. The continuous-energy particle +OpenMC is a community-developed Monte Carlo neutron and photon transport +simulation code. It is capable of performing fixed source, k-eigenvalue, and +subcritical multiplication calculations on models built using either a +constructive solid geometry or CAD representation. OpenMC supports both +continuous-energy and multigroup transport. The continuous-energy particle interaction data is based on a native HDF5 format that can be generated from ACE -files used by the MCNP and Serpent Monte Carlo codes. +files produced by NJOY. Parallelism is enabled via a hybrid MPI and OpenMP +programming model. OpenMC was originally developed by members of the `Computational Reactor Physics Group `_ at the `Massachusetts Institute of Technology diff --git a/docs/source/io_formats/settings.rst b/docs/source/io_formats/settings.rst index 9c68a9730..fb55f9e51 100644 --- a/docs/source/io_formats/settings.rst +++ b/docs/source/io_formats/settings.rst @@ -333,7 +333,7 @@ or sub-elements: velocity sampling) or "dbrc" (Doppler broadening rejection correction). Descriptions of each of these methods are documented here_. - .. _here: http://dx.doi.org/10.1016/j.anucene.2017.12.044 + .. _here: https://doi.org/10.1016/j.anucene.2017.12.044 *Default*: "rvs" diff --git a/docs/source/methods/cmfd.rst b/docs/source/methods/cmfd.rst index b13004e10..344a4cc1a 100644 --- a/docs/source/methods/cmfd.rst +++ b/docs/source/methods/cmfd.rst @@ -538,7 +538,7 @@ Examples of CMFD simulations using OpenMC can be found in [HermanThesis]_. .. rubric:: References .. [BEAVRS] Nick Horelik, Bryan Herman. *Benchmark for Evaluation And Verification of Reactor - Simulations*. Massachusetts Institute of Technology, http://crpg.mit.edu/pub/beavrs + Simulations*. Massachusetts Institute of Technology, https://crpg.mit.edu/research/beavrs , 2013. .. [Gill] Daniel F. Gill. *Newton-Krylov methods for the solution of the k-eigenvalue problem in diff --git a/docs/source/methods/cross_sections.rst b/docs/source/methods/cross_sections.rst index 4940275d3..dbf078654 100644 --- a/docs/source/methods/cross_sections.rst +++ b/docs/source/methods/cross_sections.rst @@ -269,11 +269,11 @@ or even isotropic scattering. .. _logarithmic mapping technique: 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 +.. _Josey: https://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 .. _ENDF/B data: http://www.nndc.bnl.gov/endf -.. _Leppanen: http://dx.doi.org/10.1016/j.anucene.2009.03.019 +.. _Leppanen: https://doi.org/10.1016/j.anucene.2009.03.019 .. _algorithms: http://ab-initio.mit.edu/wiki/index.php/Faddeeva_Package diff --git a/docs/source/methods/geometry.rst b/docs/source/methods/geometry.rst index 7416aee5b..38d9eb172 100644 --- a/docs/source/methods/geometry.rst +++ b/docs/source/methods/geometry.rst @@ -960,8 +960,8 @@ normal using the equations from :ref:`transform-coordinates`. The white boundary condition can be applied to any kind of surface, as long as the normal to the surface is known as in :ref:`reflection`. -.. _constructive solid geometry: http://en.wikipedia.org/wiki/Constructive_solid_geometry -.. _surfaces: http://en.wikipedia.org/wiki/Surface +.. _constructive solid geometry: https://en.wikipedia.org/wiki/Constructive_solid_geometry +.. _surfaces: https://en.wikipedia.org/wiki/Surface .. _MCNP: http://mcnp.lanl.gov .. _Serpent: http://montecarlo.vtt.fi .. _Monte Carlo Performance benchmark: https://github.com/mit-crpg/benchmarks/tree/master/mc-performance/openmc diff --git a/docs/source/methods/introduction.rst b/docs/source/methods/introduction.rst index dab1c544a..0b9544d63 100644 --- a/docs/source/methods/introduction.rst +++ b/docs/source/methods/introduction.rst @@ -141,7 +141,7 @@ be performed before the run is finished. This include the following: - All allocatable arrays are deallocated. -.. _probability distributions: http://en.wikipedia.org/wiki/Probability_distribution -.. _Monte Carlo: http://en.wikipedia.org/wiki/Monte_Carlo_method -.. _central limit theorem: http://en.wikipedia.org/wiki/Central_limit_theorem -.. _pseudorandom number: http://en.wikipedia.org/wiki/Pseudorandom_number_generator +.. _probability distributions: https://en.wikipedia.org/wiki/Probability_distribution +.. _Monte Carlo: https://en.wikipedia.org/wiki/Monte_Carlo_method +.. _central limit theorem: https://en.wikipedia.org/wiki/Central_limit_theorem +.. _pseudorandom number: https://en.wikipedia.org/wiki/Pseudorandom_number_generator diff --git a/docs/source/methods/neutron_physics.rst b/docs/source/methods/neutron_physics.rst index 60d3c1468..71e9b6bcd 100644 --- a/docs/source/methods/neutron_physics.rst +++ b/docs/source/methods/neutron_physics.rst @@ -1301,8 +1301,8 @@ correction (DBRC) and was first introduced by `Becker et al.`_. OpenMC has an implementation of DBRC as well as an accelerated sampling method that are described fully in `Walsh et al.`_ -.. _Becker et al.: http://dx.doi.org/10.1016/j.anucene.2008.12.001 -.. _Walsh et al.: http://dx.doi.org/10.1016/j.anucene.2014.01.017 +.. _Becker et al.: https://doi.org/10.1016/j.anucene.2008.12.001 +.. _Walsh et al.: https://doi.org/10.1016/j.anucene.2014.01.017 .. _sab_tables: @@ -1645,23 +1645,23 @@ another. .. |sab| replace:: S(:math:`\alpha,\beta,T`) -.. _SIGMA1 method: http://dx.doi.org/10.13182/NSE76-1 +.. _SIGMA1 method: https://doi.org/10.13182/NSE76-1 .. _scaled interpolation: http://www.ans.org/pubs/journals/nse/a_26575 -.. _probability table method: http://dx.doi.org/10.13182/NSE72-3 +.. _probability table method: https://doi.org/10.13182/NSE72-3 -.. _Watt fission spectrum: http://dx.doi.org/10.1103/PhysRev.87.1037 +.. _Watt fission spectrum: https://doi.org/10.1103/PhysRev.87.1037 .. _Foderaro: http://hdl.handle.net/1721.1/1716 -.. _OECD: http://www.oecd-nea.org/dbprog/MMRW-BOOKS.html +.. _OECD: http://www.oecd-nea.org/tools/abstract/detail/NEA-1792 -.. _NJOY: https://njoy.github.io/NJOY2016/ +.. _NJOY: https://www.njoy21.io/NJOY2016/ .. _PREPRO: http://www-nds.iaea.org/ndspub/endf/prepro/ -.. _ENDF-6 Format: http://www-nds.iaea.org/ndspub/documents/endf/endf102/endf102.pdf +.. _ENDF-6 Format: https://www.oecd-nea.org/dbdata/data/manual-endf/endf102.pdf .. _Monte Carlo Sampler: https://laws.lanl.gov/vhosts/mcnp.lanl.gov/pdf_files/la-9721.pdf @@ -1669,7 +1669,7 @@ another. .. _MC21: http://www.osti.gov/bridge/servlets/purl/903083-HT5p1o/903083.pdf -.. _Romano: http://dx.doi.org/10.1016/j.cpc.2014.11.001 +.. _Romano: https://doi.org/10.1016/j.cpc.2014.11.001 .. _Sutton and Brown: http://www.osti.gov/bridge/product.biblio.jsp?osti_id=307911 diff --git a/docs/source/methods/parallelization.rst b/docs/source/methods/parallelization.rst index 63c4a9d21..5bf090a2b 100644 --- a/docs/source/methods/parallelization.rst +++ b/docs/source/methods/parallelization.rst @@ -607,33 +607,33 @@ is actually independent of the number of nodes: Radiation Penetration Calculations on a Parallel Computer," *Trans. Am. Nucl. Soc.*, **17**, 260 (1973). -.. _first paper: http://www.jstor.org/stable/2280232 +.. _first paper: https://doi.org/10.2307/2280232 .. _work of Forrest Brown: http://hdl.handle.net/2027.42/24996 -.. _Brissenden and Garlick: http://dx.doi.org/10.1016/0306-4549(86)90095-2 +.. _Brissenden and Garlick: https://doi.org/10.1016/0306-4549(86)90095-2 .. _MPICH2: http://www.mcs.anl.gov/mpi/mpich -.. _binomial tree: http://www.cs.auckland.ac.nz/~jmor159/PLDS210/trees.html +.. _binomial tree: https://www.mcs.anl.gov/~thakur/papers/ijhpca-coll.pdf -.. _Geary: http://www.jstor.org/stable/10.2307/2342070 +.. _Geary: https://doi.org/10.2307/2342070 .. _Barnett: http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.51.7772 -.. _single-instruction multiple-data: http://en.wikipedia.org/wiki/SIMD +.. _single-instruction multiple-data: https://en.wikipedia.org/wiki/SIMD -.. _vector computers: http://en.wikipedia.org/wiki/Vector_processor +.. _vector computers: https://en.wikipedia.org/wiki/Vector_processor -.. _single program multiple data: http://en.wikipedia.org/wiki/SPMD +.. _single program multiple data: https://en.wikipedia.org/wiki/SPMD -.. _message-passing interface: http://en.wikipedia.org/wiki/Message_Passing_Interface +.. _message-passing interface: https://en.wikipedia.org/wiki/Message_Passing_Interface .. _PVM: http://www.csm.ornl.gov/pvm/pvm_home.html .. _MPI: http://www.mcs.anl.gov/research/projects/mpi/ -.. _embarrassingly parallel: http://en.wikipedia.org/wiki/Embarrassingly_parallel +.. _embarrassingly parallel: https://en.wikipedia.org/wiki/Embarrassingly_parallel .. _sends: http://www.mcs.anl.gov/research/projects/mpi/www/www3/MPI_Send.html @@ -643,8 +643,8 @@ is actually independent of the number of nodes: .. _allgather: http://www.mcs.anl.gov/research/projects/mpi/www/www3/MPI_Allgather.html -.. _Cauchy distribution: http://en.wikipedia.org/wiki/Cauchy_distribution +.. _Cauchy distribution: https://en.wikipedia.org/wiki/Cauchy_distribution -.. _latency: http://en.wikipedia.org/wiki/Latency_(engineering)#Packet-switched_networks +.. _latency: https://en.wikipedia.org/wiki/Latency_(engineering)#Packet-switched_networks -.. _bandwidth: http://en.wikipedia.org/wiki/Bandwidth_(computing) +.. _bandwidth: https://en.wikipedia.org/wiki/Bandwidth_(computing) diff --git a/docs/source/methods/random_numbers.rst b/docs/source/methods/random_numbers.rst index ce118556e..0cefc9156 100644 --- a/docs/source/methods/random_numbers.rst +++ b/docs/source/methods/random_numbers.rst @@ -67,6 +67,6 @@ the idea is to determine the new multiplicative and additive constants in .. rubric:: References -.. _L'Ecuyer: http://dx.doi.org/10.1090/S0025-5718-99-00996-5 +.. _L'Ecuyer: https://doi.org/10.1090/S0025-5718-99-00996-5 .. _Brown: https://laws.lanl.gov/vhosts/mcnp.lanl.gov/pdf_files/anl-rn-arb-stride.pdf -.. _linear congruential generator: http://en.wikipedia.org/wiki/Linear_congruential_generator +.. _linear congruential generator: https://en.wikipedia.org/wiki/Linear_congruential_generator diff --git a/docs/source/methods/tallies.rst b/docs/source/methods/tallies.rst index 9e7bd93bb..d67584622 100644 --- a/docs/source/methods/tallies.rst +++ b/docs/source/methods/tallies.rst @@ -484,31 +484,31 @@ improve the estimate of the percentile. .. rubric:: References -.. _following approximation: http://dx.doi.org/10.1080/03610918708812641 +.. _following approximation: https://doi.org/10.1080/03610918708812641 -.. _Bessel's correction: http://en.wikipedia.org/wiki/Bessel's_correction +.. _Bessel's correction: https://en.wikipedia.org/wiki/Bessel's_correction -.. _random variable: http://en.wikipedia.org/wiki/Random_variable +.. _random variable: https://en.wikipedia.org/wiki/Random_variable -.. _stochastic process: http://en.wikipedia.org/wiki/Stochastic_process +.. _stochastic process: https://en.wikipedia.org/wiki/Stochastic_process -.. _independent, identically-distributed random variables: http://en.wikipedia.org/wiki/Independent_and_identically_distributed_random_variables +.. _independent, identically-distributed random variables: https://en.wikipedia.org/wiki/Independent_and_identically_distributed_random_variables -.. _law of large numbers: http://en.wikipedia.org/wiki/Law_of_large_numbers +.. _law of large numbers: https://en.wikipedia.org/wiki/Law_of_large_numbers -.. _expected value: http://en.wikipedia.org/wiki/Expected_value +.. _expected value: https://en.wikipedia.org/wiki/Expected_value -.. _converges in probability: http://en.wikipedia.org/wiki/Convergence_of_random_variables#Convergence_in_probability +.. _converges in probability: https://en.wikipedia.org/wiki/Convergence_of_random_variables#Convergence_in_probability -.. _normal distribution: http://en.wikipedia.org/wiki/Normal_distribution +.. _normal distribution: https://en.wikipedia.org/wiki/Normal_distribution -.. _converges in distribution: http://en.wikipedia.org/wiki/Convergence_of_random_variables#Convergence_in_distribution +.. _converges in distribution: https://en.wikipedia.org/wiki/Convergence_of_random_variables#Convergence_in_distribution -.. _confidence intervals: http://en.wikipedia.org/wiki/Confidence_interval +.. _confidence intervals: https://en.wikipedia.org/wiki/Confidence_interval -.. _Student's t-distribution: http://en.wikipedia.org/wiki/Student%27s_t-distribution +.. _Student's t-distribution: https://en.wikipedia.org/wiki/Student%27s_t-distribution -.. _Cauchy distribution: http://en.wikipedia.org/wiki/Cauchy_distribution +.. _Cauchy distribution: https://en.wikipedia.org/wiki/Cauchy_distribution .. _unpublished rational approximation: https://web.archive.org/web/20150926021742/http://home.online.no/~pjacklam/notes/invnorm/ diff --git a/docs/source/publications.rst b/docs/source/publications.rst index 32b911e5b..24bcc66a1 100644 --- a/docs/source/publications.rst +++ b/docs/source/publications.rst @@ -366,7 +366,7 @@ Nuclear Data - Jonathan A. Walsh, Benoit Forget, Kord S. Smith, and Forrest B. Brown, "`Uncertainty in Fast Reactor-Relevant Critical Benchmark Simulations Due to Unresolved Resonance Structure - `_," + `_," *Proc. Int. Conf. Mathematics & Computational Methods Applied to Nuclear Science and Engineering*, Jeju, Korea, Apr. 16-20, 2017. @@ -409,7 +409,7 @@ Parallelism - Paul K. Romano and Andrew R. Siegel, "`Limits on the efficiency of event-based algorithms for Monte Carlo neutron transport - `_," + `_," *Proc. Int. Conf. Mathematics & Computational Methods Applied to Nuclear Science and Engineering*, Jeju, Korea, Apr. 16-20, 2017. diff --git a/docs/source/pythonapi/deplete.rst b/docs/source/pythonapi/deplete.rst index 82143e14a..48cb3f1cb 100644 --- a/docs/source/pythonapi/deplete.rst +++ b/docs/source/pythonapi/deplete.rst @@ -82,10 +82,10 @@ A minimal example for performing depletion would be: Internal Classes and Functions ------------------------------ -When running in parallel using `mpi4py `_, the MPI -intercommunicator used can be changed by modifying the following module -variable. If it is not explicitly modified, it defaults to -``mpi4py.MPI.COMM_WORLD``. +When running in parallel using `mpi4py +`_, the MPI intercommunicator used can +be changed by modifying the following module variable. If it is not explicitly +modified, it defaults to ``mpi4py.MPI.COMM_WORLD``. .. data:: comm @@ -161,7 +161,7 @@ Abstract Base Classes A good starting point for extending capabilities in :mod:`openmc.deplete` is to examine the following abstract base classes. Custom classes can -inherit from :class:`abc.TransportOperator` to implement alternative +inherit from :class:`abc.TransportOperator` to implement alternative schemes for collecting reaction rates and other data from a transport code prior to depleting materials diff --git a/docs/source/pythonapi/index.rst b/docs/source/pythonapi/index.rst index 87d0d2a24..7f67f95ce 100644 --- a/docs/source/pythonapi/index.rst +++ b/docs/source/pythonapi/index.rst @@ -27,7 +27,7 @@ there are many substantial benefits to using the Python API, including: For those new to Python, there are many good tutorials available online. We recommend going through the modules from `Codecademy -`_ and/or the `Scipy lectures +`_ and/or the `Scipy lectures `_. The full API documentation serves to provide more information on a given module diff --git a/docs/source/releasenotes/0.11.0.rst b/docs/source/releasenotes/0.11.0.rst index 170630ea7..ba9a35d1a 100644 --- a/docs/source/releasenotes/0.11.0.rst +++ b/docs/source/releasenotes/0.11.0.rst @@ -40,6 +40,7 @@ random, non-overlapping configuration of spheres within the region. New Features ------------ +- White boundary conditions can be applied to surfaces - Support for rectilinear meshes through :class:`openmc.RectilinearMesh`. - The :class:`Geometry`, :class:`Materials`, and :class:`Settings` classes now have a ``from_xml`` method that will build an instance from an existing XML @@ -47,7 +48,8 @@ New Features - Predefined energy group structures can be found in :data:`openmc.mgxs.GROUP_STRUCTURES`. - New tally scores: ``H1-production``, ``H2-production``, ``H3-production``, - ``He3-production``, ``He4-production``, ``heating``, and ``damage-energy`` + ``He3-production``, ``He4-production``, ``heating``, ``heating-local``, and + ``damage-energy``. - Switched to cell-based neighor lists (`PR 1140 `_) - Two new probability distributions that can be used for source distributions: @@ -129,3 +131,4 @@ This release contains new contributions from the following people: - `Jonathan Shimwell `_ - `Patrick Shriwise `_ - `John Tramm `_ +- `Jiankai Yu `_ diff --git a/docs/source/releasenotes/0.4.1.rst b/docs/source/releasenotes/0.4.1.rst index 8ec96897e..4bc3bc658 100644 --- a/docs/source/releasenotes/0.4.1.rst +++ b/docs/source/releasenotes/0.4.1.rst @@ -45,9 +45,9 @@ Bug Fixes - `95cfac`_: Fixed error in cell neighbor searches. - `83a803`_: Fixed bug related to probability tables. -.. _b206a8: https://github.com/mit-crpg/openmc/commit/b206a8 -.. _800742: https://github.com/mit-crpg/openmc/commit/800742 -.. _a07c08: https://github.com/mit-crpg/openmc/commit/a07c08 -.. _a75283: https://github.com/mit-crpg/openmc/commit/a75283 -.. _95cfac: https://github.com/mit-crpg/openmc/commit/95cfac -.. _83a803: https://github.com/mit-crpg/openmc/commit/83a803 +.. _b206a8: https://github.com/openmc-dev/openmc/commit/b206a8 +.. _800742: https://github.com/openmc-dev/openmc/commit/800742 +.. _a07c08: https://github.com/openmc-dev/openmc/commit/a07c08 +.. _a75283: https://github.com/openmc-dev/openmc/commit/a75283 +.. _95cfac: https://github.com/openmc-dev/openmc/commit/95cfac +.. _83a803: https://github.com/openmc-dev/openmc/commit/83a803 diff --git a/docs/source/releasenotes/0.4.2.rst b/docs/source/releasenotes/0.4.2.rst index c0d399301..0e28eb6e6 100644 --- a/docs/source/releasenotes/0.4.2.rst +++ b/docs/source/releasenotes/0.4.2.rst @@ -42,13 +42,13 @@ Bug Fixes - d050c7_: Added Bessel's correction to make estimate of variance unbiased. - 2a5b9c_: Fixed regression in plotting. -.. _a27f8f: https://github.com/mit-crpg/openmc/commit/a27f8f -.. _afe121: https://github.com/mit-crpg/openmc/commit/afe121 -.. _e0968e: https://github.com/mit-crpg/openmc/commit/e0968e -.. _298db8: https://github.com/mit-crpg/openmc/commit/298db8 -.. _2f3bbe: https://github.com/mit-crpg/openmc/commit/2f3bbe -.. _671f30: https://github.com/mit-crpg/openmc/commit/671f30 -.. _b2c40e: https://github.com/mit-crpg/openmc/commit/b2c40e -.. _5524fd: https://github.com/mit-crpg/openmc/commit/5524fd -.. _d050c7: https://github.com/mit-crpg/openmc/commit/d050c7 -.. _2a5b9c: https://github.com/mit-crpg/openmc/commit/2a5b9c +.. _a27f8f: https://github.com/openmc-dev/openmc/commit/a27f8f +.. _afe121: https://github.com/openmc-dev/openmc/commit/afe121 +.. _e0968e: https://github.com/openmc-dev/openmc/commit/e0968e +.. _298db8: https://github.com/openmc-dev/openmc/commit/298db8 +.. _2f3bbe: https://github.com/openmc-dev/openmc/commit/2f3bbe +.. _671f30: https://github.com/openmc-dev/openmc/commit/671f30 +.. _b2c40e: https://github.com/openmc-dev/openmc/commit/b2c40e +.. _5524fd: https://github.com/openmc-dev/openmc/commit/5524fd +.. _d050c7: https://github.com/openmc-dev/openmc/commit/d050c7 +.. _2a5b9c: https://github.com/openmc-dev/openmc/commit/2a5b9c diff --git a/docs/source/releasenotes/0.4.3.rst b/docs/source/releasenotes/0.4.3.rst index 7ef12198d..4023cb525 100644 --- a/docs/source/releasenotes/0.4.3.rst +++ b/docs/source/releasenotes/0.4.3.rst @@ -40,12 +40,12 @@ Bug Fixes - 3212f5_: Fixed issue with blank line at beginning of XML files. .. _nelsonag: https://github.com/nelsonag -.. _33f29a: https://github.com/mit-crpg/openmc/commit/33f29a -.. _1c472d: https://github.com/mit-crpg/openmc/commit/1c472d -.. _3c6e80: https://github.com/mit-crpg/openmc/commit/3c6e80 -.. _3bd35b: https://github.com/mit-crpg/openmc/commit/3bd35b -.. _0069d5: https://github.com/mit-crpg/openmc/commit/0069d5 -.. _7af2cf: https://github.com/mit-crpg/openmc/commit/7af2cf -.. _460ef1: https://github.com/mit-crpg/openmc/commit/460ef1 -.. _85a60e: https://github.com/mit-crpg/openmc/commit/85a60e -.. _3212f5: https://github.com/mit-crpg/openmc/commit/3212f5 +.. _33f29a: https://github.com/openmc-dev/openmc/commit/33f29a +.. _1c472d: https://github.com/openmc-dev/openmc/commit/1c472d +.. _3c6e80: https://github.com/openmc-dev/openmc/commit/3c6e80 +.. _3bd35b: https://github.com/openmc-dev/openmc/commit/3bd35b +.. _0069d5: https://github.com/openmc-dev/openmc/commit/0069d5 +.. _7af2cf: https://github.com/openmc-dev/openmc/commit/7af2cf +.. _460ef1: https://github.com/openmc-dev/openmc/commit/460ef1 +.. _85a60e: https://github.com/openmc-dev/openmc/commit/85a60e +.. _3212f5: https://github.com/openmc-dev/openmc/commit/3212f5 diff --git a/docs/source/releasenotes/0.4.4.rst b/docs/source/releasenotes/0.4.4.rst index d700e610d..c5201b30f 100644 --- a/docs/source/releasenotes/0.4.4.rst +++ b/docs/source/releasenotes/0.4.4.rst @@ -36,8 +36,8 @@ Bug Fixes - 7fd617_: Fixed bug with restart runs in parallel. - dc4a8f_: Fixed bug with fixed source restart runs. -.. _4654ee: https://github.com/mit-crpg/openmc/commit/4654ee -.. _7ee461: https://github.com/mit-crpg/openmc/commit/7ee461 -.. _792eb3: https://github.com/mit-crpg/openmc/commit/792eb3 -.. _7fd617: https://github.com/mit-crpg/openmc/commit/7fd617 -.. _dc4a8f: https://github.com/mit-crpg/openmc/commit/dc4a8f +.. _4654ee: https://github.com/openmc-dev/openmc/commit/4654ee +.. _7ee461: https://github.com/openmc-dev/openmc/commit/7ee461 +.. _792eb3: https://github.com/openmc-dev/openmc/commit/792eb3 +.. _7fd617: https://github.com/openmc-dev/openmc/commit/7fd617 +.. _dc4a8f: https://github.com/openmc-dev/openmc/commit/dc4a8f diff --git a/docs/source/releasenotes/0.5.0.rst b/docs/source/releasenotes/0.5.0.rst index 443216e33..aa906a323 100644 --- a/docs/source/releasenotes/0.5.0.rst +++ b/docs/source/releasenotes/0.5.0.rst @@ -39,11 +39,11 @@ Bug Fixes - 6f8d9d_: Set default tally labels. - 6a3a5e_: Fix problem with corner-crossing in lattices. -.. _737b90: https://github.com/mit-crpg/openmc/commit/737b90 -.. _a819b4: https://github.com/mit-crpg/openmc/commit/a819b4 -.. _b11696: https://github.com/mit-crpg/openmc/commit/b11696 -.. _2bd46a: https://github.com/mit-crpg/openmc/commit/2bd46a -.. _7a1f08: https://github.com/mit-crpg/openmc/commit/7a1f08 -.. _c0e3ec: https://github.com/mit-crpg/openmc/commit/c0e3ec -.. _6f8d9d: https://github.com/mit-crpg/openmc/commit/6f8d9d -.. _6a3a5e: https://github.com/mit-crpg/openmc/commit/6a3a5e +.. _737b90: https://github.com/openmc-dev/openmc/commit/737b90 +.. _a819b4: https://github.com/openmc-dev/openmc/commit/a819b4 +.. _b11696: https://github.com/openmc-dev/openmc/commit/b11696 +.. _2bd46a: https://github.com/openmc-dev/openmc/commit/2bd46a +.. _7a1f08: https://github.com/openmc-dev/openmc/commit/7a1f08 +.. _c0e3ec: https://github.com/openmc-dev/openmc/commit/c0e3ec +.. _6f8d9d: https://github.com/openmc-dev/openmc/commit/6f8d9d +.. _6a3a5e: https://github.com/openmc-dev/openmc/commit/6a3a5e diff --git a/docs/source/releasenotes/0.5.1.rst b/docs/source/releasenotes/0.5.1.rst index 6fa584fcf..26a6927c7 100644 --- a/docs/source/releasenotes/0.5.1.rst +++ b/docs/source/releasenotes/0.5.1.rst @@ -36,8 +36,8 @@ Bug Fixes - 63bfd2_: Fix tracklength tallies with cell filter and universes. - 88daf7_: Fix analog tallies with survival biasing. -.. _94103e: https://github.com/mit-crpg/openmc/commit/94103e -.. _e77059: https://github.com/mit-crpg/openmc/commit/e77059 -.. _b0fe88: https://github.com/mit-crpg/openmc/commit/b0fe88 -.. _63bfd2: https://github.com/mit-crpg/openmc/commit/63bfd2 -.. _88daf7: https://github.com/mit-crpg/openmc/commit/88daf7 +.. _94103e: https://github.com/openmc-dev/openmc/commit/94103e +.. _e77059: https://github.com/openmc-dev/openmc/commit/e77059 +.. _b0fe88: https://github.com/openmc-dev/openmc/commit/b0fe88 +.. _63bfd2: https://github.com/openmc-dev/openmc/commit/63bfd2 +.. _88daf7: https://github.com/openmc-dev/openmc/commit/88daf7 diff --git a/docs/source/releasenotes/0.5.2.rst b/docs/source/releasenotes/0.5.2.rst index ba6374ea7..1a5702895 100644 --- a/docs/source/releasenotes/0.5.2.rst +++ b/docs/source/releasenotes/0.5.2.rst @@ -41,15 +41,15 @@ Bug Fixes - ab0793_: Corrected PETSC_NULL references to their correct types. - 182ebd_: Use analog estimator with energyout filter. -.. _7632f3: https://github.com/mit-crpg/openmc/commit/7632f3 -.. _f85ac4: https://github.com/mit-crpg/openmc/commit/f85ac4 -.. _49c36b: https://github.com/mit-crpg/openmc/commit/49c36b -.. _5ccc78: https://github.com/mit-crpg/openmc/commit/5ccc78 -.. _b1f52f: https://github.com/mit-crpg/openmc/commit/b1f52f -.. _eae7e5: https://github.com/mit-crpg/openmc/commit/eae7e5 -.. _10c1cc: https://github.com/mit-crpg/openmc/commit/10c1cc -.. _afdb50: https://github.com/mit-crpg/openmc/commit/afdb50 -.. _a3c593: https://github.com/mit-crpg/openmc/commit/a3c593 -.. _3a66e3: https://github.com/mit-crpg/openmc/commit/3a66e3 -.. _ab0793: https://github.com/mit-crpg/openmc/commit/ab0793 -.. _182ebd: https://github.com/mit-crpg/openmc/commit/182ebd +.. _7632f3: https://github.com/openmc-dev/openmc/commit/7632f3 +.. _f85ac4: https://github.com/openmc-dev/openmc/commit/f85ac4 +.. _49c36b: https://github.com/openmc-dev/openmc/commit/49c36b +.. _5ccc78: https://github.com/openmc-dev/openmc/commit/5ccc78 +.. _b1f52f: https://github.com/openmc-dev/openmc/commit/b1f52f +.. _eae7e5: https://github.com/openmc-dev/openmc/commit/eae7e5 +.. _10c1cc: https://github.com/openmc-dev/openmc/commit/10c1cc +.. _afdb50: https://github.com/openmc-dev/openmc/commit/afdb50 +.. _a3c593: https://github.com/openmc-dev/openmc/commit/a3c593 +.. _3a66e3: https://github.com/openmc-dev/openmc/commit/3a66e3 +.. _ab0793: https://github.com/openmc-dev/openmc/commit/ab0793 +.. _182ebd: https://github.com/openmc-dev/openmc/commit/182ebd diff --git a/docs/source/releasenotes/0.5.3.rst b/docs/source/releasenotes/0.5.3.rst index a7305da71..7b2878d91 100644 --- a/docs/source/releasenotes/0.5.3.rst +++ b/docs/source/releasenotes/0.5.3.rst @@ -40,8 +40,8 @@ Bug Fixes - c18a6e_: Check for valid secondary mode on S(a,b) tables. - 82c456_: Fix bug where last process could have zero particles. -.. _2b1e8a: https://github.com/mit-crpg/openmc/commit/2b1e8a -.. _5853d2: https://github.com/mit-crpg/openmc/commit/5853d2 -.. _e178c7: https://github.com/mit-crpg/openmc/commit/e178c7 -.. _c18a6e: https://github.com/mit-crpg/openmc/commit/c18a6e -.. _82c456: https://github.com/mit-crpg/openmc/commit/82c456 +.. _2b1e8a: https://github.com/openmc-dev/openmc/commit/2b1e8a +.. _5853d2: https://github.com/openmc-dev/openmc/commit/5853d2 +.. _e178c7: https://github.com/openmc-dev/openmc/commit/e178c7 +.. _c18a6e: https://github.com/openmc-dev/openmc/commit/c18a6e +.. _82c456: https://github.com/openmc-dev/openmc/commit/82c456 diff --git a/docs/source/releasenotes/0.5.4.rst b/docs/source/releasenotes/0.5.4.rst index 36d9ec4d5..ed40d29df 100644 --- a/docs/source/releasenotes/0.5.4.rst +++ b/docs/source/releasenotes/0.5.4.rst @@ -39,13 +39,13 @@ Bug Fixes - cf567c_: ENDF/B-VI data checked for compatibility - 6b9461_: Fix p_valid sampling inside of sample_energy -.. _32c03c: https://github.com/mit-crpg/openmc/commit/32c03c -.. _c71ef5: https://github.com/mit-crpg/openmc/commit/c71ef5 -.. _8884fb: https://github.com/mit-crpg/openmc/commit/8884fb -.. _b38af0: https://github.com/mit-crpg/openmc/commit/b38af0 -.. _d28750: https://github.com/mit-crpg/openmc/commit/d28750 -.. _cf567c: https://github.com/mit-crpg/openmc/commit/cf567c -.. _6b9461: https://github.com/mit-crpg/openmc/commit/6b9461 +.. _32c03c: https://github.com/openmc-dev/openmc/commit/32c03c +.. _c71ef5: https://github.com/openmc-dev/openmc/commit/c71ef5 +.. _8884fb: https://github.com/openmc-dev/openmc/commit/8884fb +.. _b38af0: https://github.com/openmc-dev/openmc/commit/b38af0 +.. _d28750: https://github.com/openmc-dev/openmc/commit/d28750 +.. _cf567c: https://github.com/openmc-dev/openmc/commit/cf567c +.. _6b9461: https://github.com/openmc-dev/openmc/commit/6b9461 ------------ Contributors diff --git a/docs/source/releasenotes/0.6.0.rst b/docs/source/releasenotes/0.6.0.rst index 63e234583..8d0d2957b 100644 --- a/docs/source/releasenotes/0.6.0.rst +++ b/docs/source/releasenotes/0.6.0.rst @@ -35,13 +35,13 @@ Bug Fixes - d7a7d0_: Fix bug with specifying xs attribute - 85b3cb_: Fix out-of-bounds error with OpenMP threading -.. _41f7ca: https://github.com/mit-crpg/openmc/commit/41f7ca -.. _038736: https://github.com/mit-crpg/openmc/commit/038736 -.. _46f9e8: https://github.com/mit-crpg/openmc/commit/46f9e8 -.. _d1ca35: https://github.com/mit-crpg/openmc/commit/d1ca35 -.. _0291c0: https://github.com/mit-crpg/openmc/commit/0291c0 -.. _d7a7d0: https://github.com/mit-crpg/openmc/commit/d7a7d0 -.. _85b3cb: https://github.com/mit-crpg/openmc/commit/85b3cb +.. _41f7ca: https://github.com/openmc-dev/openmc/commit/41f7ca +.. _038736: https://github.com/openmc-dev/openmc/commit/038736 +.. _46f9e8: https://github.com/openmc-dev/openmc/commit/46f9e8 +.. _d1ca35: https://github.com/openmc-dev/openmc/commit/d1ca35 +.. _0291c0: https://github.com/openmc-dev/openmc/commit/0291c0 +.. _d7a7d0: https://github.com/openmc-dev/openmc/commit/d7a7d0 +.. _85b3cb: https://github.com/openmc-dev/openmc/commit/85b3cb ------------ Contributors diff --git a/docs/source/releasenotes/0.6.1.rst b/docs/source/releasenotes/0.6.1.rst index a8c59aa51..c0f11ef68 100644 --- a/docs/source/releasenotes/0.6.1.rst +++ b/docs/source/releasenotes/0.6.1.rst @@ -38,16 +38,16 @@ Bug Fixes - 2a95ef_: Prevent segmentation fault on "current" score without mesh filter - 93e482_: Check for negative values in probability tables -.. _03e890: https://github.com/mit-crpg/openmc/commit/03e890 -.. _4439de: https://github.com/mit-crpg/openmc/commit/4439de -.. _5808ed: https://github.com/mit-crpg/openmc/commit/5808ed -.. _2e60c0: https://github.com/mit-crpg/openmc/commit/2e60c0 -.. _3e0870: https://github.com/mit-crpg/openmc/commit/3e0870 -.. _dc4776: https://github.com/mit-crpg/openmc/commit/dc4776 -.. _01178b: https://github.com/mit-crpg/openmc/commit/01178b -.. _62ec43: https://github.com/mit-crpg/openmc/commit/62ec43 -.. _2a95ef: https://github.com/mit-crpg/openmc/commit/2a95ef -.. _93e482: https://github.com/mit-crpg/openmc/commit/93e482 +.. _03e890: https://github.com/openmc-dev/openmc/commit/03e890 +.. _4439de: https://github.com/openmc-dev/openmc/commit/4439de +.. _5808ed: https://github.com/openmc-dev/openmc/commit/5808ed +.. _2e60c0: https://github.com/openmc-dev/openmc/commit/2e60c0 +.. _3e0870: https://github.com/openmc-dev/openmc/commit/3e0870 +.. _dc4776: https://github.com/openmc-dev/openmc/commit/dc4776 +.. _01178b: https://github.com/openmc-dev/openmc/commit/01178b +.. _62ec43: https://github.com/openmc-dev/openmc/commit/62ec43 +.. _2a95ef: https://github.com/openmc-dev/openmc/commit/2a95ef +.. _93e482: https://github.com/openmc-dev/openmc/commit/93e482 ------------ Contributors diff --git a/docs/source/releasenotes/0.6.2.rst b/docs/source/releasenotes/0.6.2.rst index 6fe6c28da..9a5400cac 100644 --- a/docs/source/releasenotes/0.6.2.rst +++ b/docs/source/releasenotes/0.6.2.rst @@ -33,10 +33,10 @@ Bug Fixes - e6abb9_: Fix segfault when tallying in a void material - 291b45_: Handle metastable nuclides in NNDC data and multiplicities in MT=5 data -.. _26fb93: https://github.com/mit-crpg/openmc/commit/26fb93 -.. _2f07c0: https://github.com/mit-crpg/openmc/commit/2f07c0 -.. _e6abb9: https://github.com/mit-crpg/openmc/commit/e6abb9 -.. _291b45: https://github.com/mit-crpg/openmc/commit/291b45 +.. _26fb93: https://github.com/openmc-dev/openmc/commit/26fb93 +.. _2f07c0: https://github.com/openmc-dev/openmc/commit/2f07c0 +.. _e6abb9: https://github.com/openmc-dev/openmc/commit/e6abb9 +.. _291b45: https://github.com/openmc-dev/openmc/commit/291b45 ------------ Contributors diff --git a/docs/source/releasenotes/0.7.0.rst b/docs/source/releasenotes/0.7.0.rst index 8f86631ea..2a3063a92 100644 --- a/docs/source/releasenotes/0.7.0.rst +++ b/docs/source/releasenotes/0.7.0.rst @@ -40,11 +40,11 @@ Bug Fixes - 6121d9_: Fix bugs related to particle track files - 2f0e89_: Fixes for nuclide specification in tallies -.. _b5f712: https://github.com/mit-crpg/openmc/commit/b5f712 -.. _e6675b: https://github.com/mit-crpg/openmc/commit/e6675b -.. _04e2c1: https://github.com/mit-crpg/openmc/commit/04e2c1 -.. _6121d9: https://github.com/mit-crpg/openmc/commit/6121d9 -.. _2f0e89: https://github.com/mit-crpg/openmc/commit/2f0e89 +.. _b5f712: https://github.com/openmc-dev/openmc/commit/b5f712 +.. _e6675b: https://github.com/openmc-dev/openmc/commit/e6675b +.. _04e2c1: https://github.com/openmc-dev/openmc/commit/04e2c1 +.. _6121d9: https://github.com/openmc-dev/openmc/commit/6121d9 +.. _2f0e89: https://github.com/openmc-dev/openmc/commit/2f0e89 ------------ Contributors diff --git a/docs/source/releasenotes/0.7.1.rst b/docs/source/releasenotes/0.7.1.rst index 5ee2c9f69..01af74239 100644 --- a/docs/source/releasenotes/0.7.1.rst +++ b/docs/source/releasenotes/0.7.1.rst @@ -62,15 +62,15 @@ Bug Fixes - 441fd4_: Fix bug in kappa-fission score - 7e5974_: Allow fixed source simulations from Python API -.. _299322: https://github.com/mit-crpg/openmc/commit/299322 -.. _d74840: https://github.com/mit-crpg/openmc/commit/d74840 -.. _c29a81: https://github.com/mit-crpg/openmc/commit/c29a81 -.. _3edc23: https://github.com/mit-crpg/openmc/commit/3edc23 -.. _629e3b: https://github.com/mit-crpg/openmc/commit/629e3b -.. _5dbe8b: https://github.com/mit-crpg/openmc/commit/5dbe8b -.. _ff66f4: https://github.com/mit-crpg/openmc/commit/ff66f4 -.. _441fd4: https://github.com/mit-crpg/openmc/commit/441fd4 -.. _7e5974: https://github.com/mit-crpg/openmc/commit/7e5974 +.. _299322: https://github.com/openmc-dev/openmc/commit/299322 +.. _d74840: https://github.com/openmc-dev/openmc/commit/d74840 +.. _c29a81: https://github.com/openmc-dev/openmc/commit/c29a81 +.. _3edc23: https://github.com/openmc-dev/openmc/commit/3edc23 +.. _629e3b: https://github.com/openmc-dev/openmc/commit/629e3b +.. _5dbe8b: https://github.com/openmc-dev/openmc/commit/5dbe8b +.. _ff66f4: https://github.com/openmc-dev/openmc/commit/ff66f4 +.. _441fd4: https://github.com/openmc-dev/openmc/commit/441fd4 +.. _7e5974: https://github.com/openmc-dev/openmc/commit/7e5974 ------------ Contributors diff --git a/docs/source/releasenotes/0.8.0.rst b/docs/source/releasenotes/0.8.0.rst index bd8a89a64..d4f5a878b 100644 --- a/docs/source/releasenotes/0.8.0.rst +++ b/docs/source/releasenotes/0.8.0.rst @@ -65,17 +65,17 @@ Bug Fixes - 8467ae_: Better threshold for allowable lost particles - 493c6f_: Fix type of return argument for h5pget_driver_f -.. _70daa7: https://github.com/mit-crpg/openmc/commit/70daa7 -.. _40b05f: https://github.com/mit-crpg/openmc/commit/40b05f -.. _9586ed: https://github.com/mit-crpg/openmc/commit/9586ed -.. _a855e8: https://github.com/mit-crpg/openmc/commit/a855e8 -.. _7294a1: https://github.com/mit-crpg/openmc/commit/7294a1 -.. _12f246: https://github.com/mit-crpg/openmc/commit/12f246 -.. _0227f4: https://github.com/mit-crpg/openmc/commit/0227f4 -.. _51deaa: https://github.com/mit-crpg/openmc/commit/51deaa -.. _fed74b: https://github.com/mit-crpg/openmc/commit/fed74b -.. _8467ae: https://github.com/mit-crpg/openmc/commit/8467ae -.. _493c6f: https://github.com/mit-crpg/openmc/commit/493c6f +.. _70daa7: https://github.com/openmc-dev/openmc/commit/70daa7 +.. _40b05f: https://github.com/openmc-dev/openmc/commit/40b05f +.. _9586ed: https://github.com/openmc-dev/openmc/commit/9586ed +.. _a855e8: https://github.com/openmc-dev/openmc/commit/a855e8 +.. _7294a1: https://github.com/openmc-dev/openmc/commit/7294a1 +.. _12f246: https://github.com/openmc-dev/openmc/commit/12f246 +.. _0227f4: https://github.com/openmc-dev/openmc/commit/0227f4 +.. _51deaa: https://github.com/openmc-dev/openmc/commit/51deaa +.. _fed74b: https://github.com/openmc-dev/openmc/commit/fed74b +.. _8467ae: https://github.com/openmc-dev/openmc/commit/8467ae +.. _493c6f: https://github.com/openmc-dev/openmc/commit/493c6f ------------ Contributors diff --git a/docs/source/releasenotes/0.9.0.rst b/docs/source/releasenotes/0.9.0.rst index 478c57096..778a7d135 100644 --- a/docs/source/releasenotes/0.9.0.rst +++ b/docs/source/releasenotes/0.9.0.rst @@ -111,25 +111,25 @@ Bug Fixes - 489540_: Check for void materials in tracklength tallies - f0214f_: Fixes/improvements to the ARES algorithm -.. _c5df6c: https://github.com/mit-crpg/openmc/commit/c5df6c -.. _1cfa39: https://github.com/mit-crpg/openmc/commit/1cfa39 -.. _335359: https://github.com/mit-crpg/openmc/commit/335359 -.. _17c678: https://github.com/mit-crpg/openmc/commit/17c678 -.. _23ec0b: https://github.com/mit-crpg/openmc/commit/23ec0b -.. _7eefb7: https://github.com/mit-crpg/openmc/commit/7eefb7 -.. _7880d4: https://github.com/mit-crpg/openmc/commit/7880d4 -.. _ad2d9f: https://github.com/mit-crpg/openmc/commit/ad2d9f -.. _59fdca: https://github.com/mit-crpg/openmc/commit/59fdca -.. _9eff5b: https://github.com/mit-crpg/openmc/commit/9eff5b -.. _7848a9: https://github.com/mit-crpg/openmc/commit/7848a9 -.. _f139ce: https://github.com/mit-crpg/openmc/commit/f139ce -.. _b8ddfa: https://github.com/mit-crpg/openmc/commit/b8ddfa -.. _ec3cfb: https://github.com/mit-crpg/openmc/commit/ec3cfb -.. _5e9b06: https://github.com/mit-crpg/openmc/commit/5e9b06 -.. _c39990: https://github.com/mit-crpg/openmc/commit/c39990 -.. _c6b67e: https://github.com/mit-crpg/openmc/commit/c6b67e -.. _489540: https://github.com/mit-crpg/openmc/commit/489540 -.. _f0214f: https://github.com/mit-crpg/openmc/commit/f0214f +.. _c5df6c: https://github.com/openmc-dev/openmc/commit/c5df6c +.. _1cfa39: https://github.com/openmc-dev/openmc/commit/1cfa39 +.. _335359: https://github.com/openmc-dev/openmc/commit/335359 +.. _17c678: https://github.com/openmc-dev/openmc/commit/17c678 +.. _23ec0b: https://github.com/openmc-dev/openmc/commit/23ec0b +.. _7eefb7: https://github.com/openmc-dev/openmc/commit/7eefb7 +.. _7880d4: https://github.com/openmc-dev/openmc/commit/7880d4 +.. _ad2d9f: https://github.com/openmc-dev/openmc/commit/ad2d9f +.. _59fdca: https://github.com/openmc-dev/openmc/commit/59fdca +.. _9eff5b: https://github.com/openmc-dev/openmc/commit/9eff5b +.. _7848a9: https://github.com/openmc-dev/openmc/commit/7848a9 +.. _f139ce: https://github.com/openmc-dev/openmc/commit/f139ce +.. _b8ddfa: https://github.com/openmc-dev/openmc/commit/b8ddfa +.. _ec3cfb: https://github.com/openmc-dev/openmc/commit/ec3cfb +.. _5e9b06: https://github.com/openmc-dev/openmc/commit/5e9b06 +.. _c39990: https://github.com/openmc-dev/openmc/commit/c39990 +.. _c6b67e: https://github.com/openmc-dev/openmc/commit/c6b67e +.. _489540: https://github.com/openmc-dev/openmc/commit/489540 +.. _f0214f: https://github.com/openmc-dev/openmc/commit/f0214f ------------ Contributors diff --git a/docs/source/usersguide/beginners.rst b/docs/source/usersguide/beginners.rst index 38e016d1e..85d50a2d4 100644 --- a/docs/source/usersguide/beginners.rst +++ b/docs/source/usersguide/beginners.rst @@ -141,13 +141,13 @@ and `Volume II`_. You may also find it helpful to review the following terms: - `Effective multiplication factor`_ - `Flux`_ -.. _nuclear reactor: http://en.wikipedia.org/wiki/Nuclear_reactor -.. _Monte Carlo: http://en.wikipedia.org/wiki/Monte_Carlo_method -.. _fission: http://en.wikipedia.org/wiki/Nuclear_fission -.. _deterministic: http://en.wikipedia.org/wiki/Deterministic_algorithm -.. _neutron transport: http://en.wikipedia.org/wiki/Neutron_transport -.. _discretization: http://en.wikipedia.org/wiki/Discretization -.. _constructive solid geometry: http://en.wikipedia.org/wiki/Constructive_solid_geometry +.. _nuclear reactor: https://en.wikipedia.org/wiki/Nuclear_reactor +.. _Monte Carlo: https://en.wikipedia.org/wiki/Monte_Carlo_method +.. _fission: https://en.wikipedia.org/wiki/Nuclear_fission +.. _deterministic: https://en.wikipedia.org/wiki/Deterministic_algorithm +.. _neutron transport: https://en.wikipedia.org/wiki/Neutron_transport +.. _discretization: https://en.wikipedia.org/wiki/Discretization +.. _constructive solid geometry: https://en.wikipedia.org/wiki/Constructive_solid_geometry .. _git: http://git-scm.com/ .. _git tutorials: http://git-scm.com/documentation .. _Reactor Concepts Manual: http://www.tayloredge.com/periodic/trivia/ReactorConcepts.pdf @@ -156,6 +156,6 @@ and `Volume II`_. You may also find it helpful to review the following terms: .. _OpenMC source code: https://github.com/openmc-dev/openmc .. _GitHub: https://github.com/ .. _bug reports: https://github.com/openmc-dev/openmc/issues -.. _Neutron cross section: http://en.wikipedia.org/wiki/Neutron_cross_section +.. _Neutron cross section: https://en.wikipedia.org/wiki/Neutron_cross_section .. _Effective multiplication factor: https://en.wikipedia.org/wiki/Nuclear_chain_reaction#Effective_neutron_multiplication_factor -.. _Flux: http://en.wikipedia.org/wiki/Neutron_flux +.. _Flux: https://en.wikipedia.org/wiki/Neutron_flux diff --git a/docs/source/usersguide/geometry.rst b/docs/source/usersguide/geometry.rst index 51daf7b5d..5e583cfd2 100644 --- a/docs/source/usersguide/geometry.rst +++ b/docs/source/usersguide/geometry.rst @@ -396,8 +396,8 @@ if needed, lattices, the last step is to create an instance of geom.root_universe = root_univ geom.export_to_xml() -.. _constructive solid geometry: http://en.wikipedia.org/wiki/Constructive_solid_geometry -.. _quadratic surfaces: http://en.wikipedia.org/wiki/Quadric +.. _constructive solid geometry: https://en.wikipedia.org/wiki/Constructive_solid_geometry +.. _quadratic surfaces: https://en.wikipedia.org/wiki/Quadric -------------------------- Using CAD-based Geometry diff --git a/docs/source/usersguide/install.rst b/docs/source/usersguide/install.rst index 96b4f5024..8ca7e0b35 100644 --- a/docs/source/usersguide/install.rst +++ b/docs/source/usersguide/install.rst @@ -17,7 +17,8 @@ system for installing multiple versions of software packages and their dependencies and switching easily between them. `conda-forge `_ is a community-led conda channel of installable packages. For instructions on installing conda, please consult their -`documentation `_. +`documentation +`_. Once you have `conda` installed on your system, add the `conda-forge` channel to your configuration with: @@ -444,7 +445,7 @@ as for OpenMC. .. admonition:: Optional :class: note - `mpi4py `_ + `mpi4py `_ mpi4py provides Python bindings to MPI for running distributed-memory parallel runs. This package is needed if you plan on running depletion simulations in parallel using MPI. @@ -483,9 +484,9 @@ Make sure to replace the last string on the second line with the path to the schemas.xml file in your own OpenMC source directory. .. _GNU Emacs: http://www.gnu.org/software/emacs/ -.. _validation: http://en.wikipedia.org/wiki/XML_validation +.. _validation: https://en.wikipedia.org/wiki/XML_validation .. _RELAX NG: http://relaxng.org/ .. _NNDC: http://www.nndc.bnl.gov/endf/b7.1/acefiles.html .. _ctest: http://www.cmake.org/cmake/help/v2.8.12/ctest.html -.. _Conda: https://conda.io/docs/ +.. _Conda: https://docs.conda.io/en/latest/ .. _pip: https://pip.pypa.io/en/stable/ diff --git a/docs/source/usersguide/plots.rst b/docs/source/usersguide/plots.rst index f21d2c8c5..a10f370d6 100644 --- a/docs/source/usersguide/plots.rst +++ b/docs/source/usersguide/plots.rst @@ -66,7 +66,7 @@ particular cells/materials should be given colors of your choosing:: } Note that colors can be given as RGB tuples or by a string indicating a valid -`SVG color `_. +`SVG color `_. When you're done creating your :class:`openmc.Plot` instances, you need to then assign them to a :class:`openmc.Plots` collection and export it to XML:: diff --git a/openmc/mgxs/__init__.py b/openmc/mgxs/__init__.py index 886cc904a..1b1ad0dce 100644 --- a/openmc/mgxs/__init__.py +++ b/openmc/mgxs/__init__.py @@ -18,7 +18,7 @@ GROUP_STRUCTURES = {} .. _CASMO: https://www.studsvik.com/SharepointFiles/CASMO-5%20Development%20and%20Applications.pdf .. _XMAS-172: https://www-nds.iaea.org/wimsd/energy.htm -.. _SHEM-361: https://www.polymtl.ca/merlin/libraries.htm +.. _SHEM-361: https://www.polymtl.ca/merlin/downloads/FP214.pdf .. _activation: https://fispact.ukaea.uk/wiki/Keyword:GETXS .. _CCFE-709: https://fispact.ukaea.uk/wiki/CCFE-709_group_structure .. _UKAEA-1102: https://fispact.ukaea.uk/wiki/UKAEA-1102_group_structure diff --git a/openmc/plots.py b/openmc/plots.py index b4712c902..10d773868 100644 --- a/openmc/plots.py +++ b/openmc/plots.py @@ -173,7 +173,7 @@ class Plot(IDManagerMixin): OpenMC is capable of generating two-dimensional slice plots and three-dimensional voxel plots. Colors that are used in plots can be given as RGB tuples, e.g. (255, 255, 255) would be white, or by a string indicating a - valid `SVG color `_. + valid `SVG color `_. Parameters ---------- From d32c2175ba840af04b65ede5f6a6915adf808b97 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Fri, 4 Oct 2019 11:26:20 -0500 Subject: [PATCH 027/158] Add symbolic link to chain_simple.xml in jupyter notebook directory --- examples/jupyter/chain_simple.xml | 1 + 1 file changed, 1 insertion(+) create mode 120000 examples/jupyter/chain_simple.xml diff --git a/examples/jupyter/chain_simple.xml b/examples/jupyter/chain_simple.xml new file mode 120000 index 000000000..8b1b45535 --- /dev/null +++ b/examples/jupyter/chain_simple.xml @@ -0,0 +1 @@ +/home/romano/openmc/tests/chain_simple.xml \ No newline at end of file From e869d8eef1b766d8d0c4f221a385677f67f1017d Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Fri, 4 Oct 2019 12:48:23 -0500 Subject: [PATCH 028/158] Fix documentation build (deplete module was causing issues) --- docs/source/conf.py | 2 +- docs/source/pythonapi/deplete.rst | 12 +++++++++--- openmc/deplete/__init__.py | 7 +++---- openmc/deplete/abc.py | 2 +- openmc/deplete/cram.py | 12 +++--------- 5 files changed, 17 insertions(+), 18 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 55776b8f4..f46b11334 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -27,7 +27,7 @@ MOCK_MODULES = [ 'scipy.interpolate', 'scipy.integrate', 'scipy.optimize', 'scipy.special', 'scipy.stats', 'scipy.spatial', 'h5py', 'pandas', 'uncertainties', 'matplotlib', 'matplotlib.pyplot', 'openmoc', - 'openmc.data.reconstruct' + 'openmc.data.reconstruct', 'openmc.checkvalue' ] sys.modules.update((mod_name, MagicMock()) for mod_name in MOCK_MODULES) diff --git a/docs/source/pythonapi/deplete.rst b/docs/source/pythonapi/deplete.rst index 48cb3f1cb..b864529d1 100644 --- a/docs/source/pythonapi/deplete.rst +++ b/docs/source/pythonapi/deplete.rst @@ -126,8 +126,15 @@ data, such as number densities and reaction rates for each material. Results ResultsList -The following functions are used to solve the depletion equations, with -:func:`cram.CRAM48` being the default. +The following class and functions are used to solve the depletion equations, +with :func:`cram.CRAM48` being the default. + +.. autosummary:: + :toctree: generated + :nosignatures: + :template: myintegrator.rst + + cram.IPFCramSolver .. autosummary:: :toctree: generated @@ -196,4 +203,3 @@ the following abstract base classes: abc.Integrator abc.SIIntegrator abc.DepSystemSolver - abc.IPFCramSolver diff --git a/openmc/deplete/__init__.py b/openmc/deplete/__init__.py index f0b04c3de..b54d7f11d 100644 --- a/openmc/deplete/__init__.py +++ b/openmc/deplete/__init__.py @@ -4,12 +4,11 @@ openmc.deplete A depletion front-end tool. """ -from sys import exit +import sys +from unittest.mock import Mock from h5py import get_config -from unittest.mock import Mock - from .dummy_comm import DummyCommunicator try: @@ -22,7 +21,7 @@ try: if not get_config().mpi and comm.size > 1: # Raise exception only on process 0 if comm.rank: - exit() + sys.exit() raise RuntimeError( "Need parallel HDF5 installed to perform depletion with MPI" ) diff --git a/openmc/deplete/abc.py b/openmc/deplete/abc.py index 0bcd1eb2c..462d0f346 100644 --- a/openmc/deplete/abc.py +++ b/openmc/deplete/abc.py @@ -28,7 +28,7 @@ from .results_list import ResultsList __all__ = [ "OperatorResult", "TransportOperator", "ReactionRateHelper", "EnergyHelper", "FissionYieldHelper", "TalliedFissionYieldHelper", - "Integrator", "SIIntegrator"] + "Integrator", "SIIntegrator", "DepSystemSolver"] OperatorResult = namedtuple('OperatorResult', ['k', 'rates']) diff --git a/openmc/deplete/cram.py b/openmc/deplete/cram.py index f4a847907..c684b3394 100644 --- a/openmc/deplete/cram.py +++ b/openmc/deplete/cram.py @@ -17,7 +17,7 @@ from .abc import DepSystemSolver __all__ = [ "deplete", "timed_deplete", "CRAM16", "CRAM48", - "Cram16Solver", "Cram48Solver"] + "Cram16Solver", "Cram48Solver", "IPFCramSolver"] def deplete(chain, x, rates, dt, matrix_func=None): @@ -88,16 +88,11 @@ def timed_deplete(*args, **kwargs): class IPFCramSolver(DepSystemSolver): - r"""Class for solving depletion systems with IPF Cram + r"""CRAM depletion solver that uses incomplete partial factorization Provides a :meth:`__call__` that utilizes an incomplete partial factorization (IPF) for the Chebyshev Rational Approximation - Method (CRAM) - - M. Pusa, "Higher-Order Chebyshev Rational Approximation - Method and Application to Burnup Equations," Nuclear Science And - Engineering, 182:3,297-318 - `DOI: 10.13182/NSE15-26 `_ + Method (CRAM), as described in the following paper: M. Pusa, "`Higher-Order Chebyshev Rational Approximation Method and Application to Burnup Equations `_," Nucl. Sci. Eng., 182:3, 297-318. Parameters ---------- @@ -256,4 +251,3 @@ Cram48Solver = IPFCramSolver(c48_alpha, c48_theta, c48_alpha0) del c48_alpha, c48_alpha0, c48_theta, alpha_r, alpha_i, theta_r, theta_i CRAM48 = Cram48Solver.__call__ - From 86c081b28b16827d29416dc3a08eb7d07b25bd31 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Fri, 4 Oct 2019 13:59:19 -0500 Subject: [PATCH 029/158] Update MG mode part 3 notebook --- examples/jupyter/mg-mode-part-iii.ipynb | 433 ++++++++++++------------ 1 file changed, 210 insertions(+), 223 deletions(-) diff --git a/examples/jupyter/mg-mode-part-iii.ipynb b/examples/jupyter/mg-mode-part-iii.ipynb index 2cf998188..e953d64d3 100644 --- a/examples/jupyter/mg-mode-part-iii.ipynb +++ b/examples/jupyter/mg-mode-part-iii.ipynb @@ -30,7 +30,6 @@ "\n", "import matplotlib.pyplot as plt\n", "import numpy as np\n", - "\n", "import openmc\n", "\n", "%matplotlib inline" @@ -40,7 +39,12 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "We will be running a rodded 8x8 assembly with Gadolinia fuel pins. Let's create all the elemental data we would need for this case." + "We will be running a rodded 8x8 assembly with Gadolinia fuel pins. Let's start by creating the materials that we will use later.\n", + "\n", + "Material Definition Simplifications:\n", + "\n", + "- This model will be run at room temperature so the NNDC ENDF-B/VII.1 data set can be used but the water density will be representative of a module with around 20% voiding. This water density will be non-physically used in all regions of the problem.\n", + "- Steel is composed of more than just iron, but we will only treat it as such here." ] }, { @@ -48,67 +52,43 @@ "execution_count": 2, "metadata": {}, "outputs": [], - "source": [ - "# Instantiate some elements\n", - "elements = {}\n", - "for elem in ['H', 'O', 'U', 'Zr', 'Gd', 'B', 'C', 'Fe']:\n", - " elements[elem] = openmc.Element(elem)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "With the elements we defined, we will now create the materials we will use later.\n", - "\n", - "Material Definition Simplifications:\n", - "\n", - "- This model will be run at room temperature so the NNDC ENDF-B/VII.1 data set can be used but the water density will be representative of a module with around 20% voiding. This water density will be non-physically used in all regions of the problem.\n", - "- Steel is composed of more than just iron, but we will only treat it as such here.\n" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [], "source": [ "materials = {}\n", "\n", "# Fuel\n", "materials['Fuel'] = openmc.Material(name='Fuel')\n", "materials['Fuel'].set_density('g/cm3', 10.32)\n", - "materials['Fuel'].add_element(elements['O'], 2)\n", - "materials['Fuel'].add_element(elements['U'], 1, enrichment=3.)\n", + "materials['Fuel'].add_element('O', 2)\n", + "materials['Fuel'].add_element('U', 1, enrichment=3.)\n", "\n", "# Gadolinia bearing fuel\n", "materials['Gad'] = openmc.Material(name='Gad')\n", "materials['Gad'].set_density('g/cm3', 10.23)\n", - "materials['Gad'].add_element(elements['O'], 2)\n", - "materials['Gad'].add_element(elements['U'], 1, enrichment=3.)\n", - "materials['Gad'].add_element(elements['Gd'], .02)\n", + "materials['Gad'].add_element('O', 2)\n", + "materials['Gad'].add_element('U', 1, enrichment=3.)\n", + "materials['Gad'].add_element('Gd', .02)\n", "\n", "# Zircaloy\n", "materials['Zirc2'] = openmc.Material(name='Zirc2')\n", "materials['Zirc2'].set_density('g/cm3', 6.55)\n", - "materials['Zirc2'].add_element(elements['Zr'], 1)\n", + "materials['Zirc2'].add_element('Zr', 1)\n", "\n", "# Boiling Water\n", "materials['Water'] = openmc.Material(name='Water')\n", "materials['Water'].set_density('g/cm3', 0.6)\n", - "materials['Water'].add_element(elements['H'], 2)\n", - "materials['Water'].add_element(elements['O'], 1)\n", + "materials['Water'].add_element('H', 2)\n", + "materials['Water'].add_element('O', 1)\n", "\n", "# Boron Carbide for the Control Rods\n", "materials['B4C'] = openmc.Material(name='B4C')\n", "materials['B4C'].set_density('g/cm3', 0.7 * 2.52)\n", - "materials['B4C'].add_element(elements['B'], 4)\n", - "materials['B4C'].add_element(elements['C'], 1)\n", + "materials['B4C'].add_element('B', 4)\n", + "materials['B4C'].add_element('C', 1)\n", "\n", "# Steel \n", "materials['Steel'] = openmc.Material(name='Steel')\n", "materials['Steel'].set_density('g/cm3', 7.75)\n", - "materials['Steel'].add_element(elements['Fe'], 1)" + "materials['Steel'].add_element('Fe', 1)" ] }, { @@ -120,7 +100,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 3, "metadata": {}, "outputs": [], "source": [ @@ -147,7 +127,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 4, "metadata": {}, "outputs": [], "source": [ @@ -164,27 +144,27 @@ "surfaces = {}\n", "\n", "# Create boundary planes to surround the geometry\n", - "surfaces['Global x-'] = openmc.XPlane(x0=0., boundary_type='reflective')\n", - "surfaces['Global x+'] = openmc.XPlane(x0=length, boundary_type='reflective')\n", - "surfaces['Global y-'] = openmc.YPlane(y0=0., boundary_type='reflective')\n", - "surfaces['Global y+'] = openmc.YPlane(y0=length, boundary_type='reflective')\n", + "surfaces['Global x-'] = openmc.XPlane(0., boundary_type='reflective')\n", + "surfaces['Global x+'] = openmc.XPlane(length, boundary_type='reflective')\n", + "surfaces['Global y-'] = openmc.YPlane(0., boundary_type='reflective')\n", + "surfaces['Global y+'] = openmc.YPlane(length, boundary_type='reflective')\n", "\n", "# Create cylinders for the fuel and clad\n", - "surfaces['Fuel Radius'] = openmc.ZCylinder(R=fuel_rad)\n", - "surfaces['Clad Radius'] = openmc.ZCylinder(R=clad_rad)\n", + "surfaces['Fuel Radius'] = openmc.ZCylinder(r=fuel_rad)\n", + "surfaces['Clad Radius'] = openmc.ZCylinder(r=clad_rad)\n", "\n", - "surfaces['Assembly x-'] = openmc.XPlane(x0=pin_pitch)\n", - "surfaces['Assembly x+'] = openmc.XPlane(x0=length - pin_pitch)\n", - "surfaces['Assembly y-'] = openmc.YPlane(y0=pin_pitch)\n", - "surfaces['Assembly y+'] = openmc.YPlane(y0=length - pin_pitch)\n", + "surfaces['Assembly x-'] = openmc.XPlane(pin_pitch)\n", + "surfaces['Assembly x+'] = openmc.XPlane(length - pin_pitch)\n", + "surfaces['Assembly y-'] = openmc.YPlane(pin_pitch)\n", + "surfaces['Assembly y+'] = openmc.YPlane(length - pin_pitch)\n", "\n", "# Set surfaces for the control blades\n", - "surfaces['Top Blade y-'] = openmc.YPlane(y0=length - rod_thick)\n", - "surfaces['Top Blade x-'] = openmc.XPlane(x0=pin_pitch)\n", - "surfaces['Top Blade x+'] = openmc.XPlane(x0=rod_span)\n", - "surfaces['Left Blade x+'] = openmc.XPlane(x0=rod_thick)\n", - "surfaces['Left Blade y-'] = openmc.YPlane(y0=length - rod_span)\n", - "surfaces['Left Blade y+'] = openmc.YPlane(y0=9. * pin_pitch)" + "surfaces['Top Blade y-'] = openmc.YPlane(length - rod_thick)\n", + "surfaces['Top Blade x-'] = openmc.XPlane(pin_pitch)\n", + "surfaces['Top Blade x+'] = openmc.XPlane(rod_span)\n", + "surfaces['Left Blade x+'] = openmc.XPlane(rod_thick)\n", + "surfaces['Left Blade y-'] = openmc.YPlane(length - rod_span)\n", + "surfaces['Left Blade y+'] = openmc.YPlane(9. * pin_pitch)" ] }, { @@ -196,7 +176,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 5, "metadata": {}, "outputs": [], "source": [ @@ -240,7 +220,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 6, "metadata": {}, "outputs": [], "source": [ @@ -280,7 +260,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 7, "metadata": {}, "outputs": [], "source": [ @@ -319,7 +299,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 8, "metadata": {}, "outputs": [], "source": [ @@ -353,7 +333,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 9, "metadata": {}, "outputs": [], "source": [ @@ -375,27 +355,29 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "" + "" ] }, - "execution_count": 11, + "execution_count": 10, "metadata": {}, "output_type": "execute_result" }, { "data": { - "image/png": "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\n", + "image/png": "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\n", "text/plain": [ - "" + "
" ] }, - "metadata": {}, + "metadata": { + "needs_background": "light" + }, "output_type": "display_data" } ], @@ -422,7 +404,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 11, "metadata": {}, "outputs": [], "source": [ @@ -444,7 +426,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 12, "metadata": {}, "outputs": [], "source": [ @@ -481,7 +463,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 13, "metadata": {}, "outputs": [], "source": [ @@ -499,7 +481,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 14, "metadata": {}, "outputs": [], "source": [ @@ -520,7 +502,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 15, "metadata": {}, "outputs": [], "source": [ @@ -540,7 +522,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 16, "metadata": {}, "outputs": [], "source": [ @@ -572,7 +554,7 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 17, "metadata": {}, "outputs": [], "source": [ @@ -602,7 +584,7 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 18, "metadata": {}, "outputs": [], "source": [ @@ -632,7 +614,7 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 19, "metadata": {}, "outputs": [], "source": [ @@ -652,14 +634,14 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 20, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "/home/nelsonag/git/openmc/openmc/mgxs/mgxs.py:4116: UserWarning: The legendre order will be ignored since the scatter format is set to histogram\n", + "/home/romano/openmc/openmc/mgxs/mgxs.py:4144: UserWarning: The legendre order will be ignored since the scatter format is set to histogram\n", " warnings.warn(msg)\n" ] } @@ -679,7 +661,7 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 21, "metadata": {}, "outputs": [], "source": [ @@ -698,26 +680,26 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": 22, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "/home/nelsonag/git/openmc/openmc/mixin.py:71: IDWarning: Another Filter instance already exists with id=1.\n", + "/home/romano/openmc/openmc/mixin.py:71: IDWarning: Another Filter instance already exists with id=1.\n", " warn(msg, IDWarning)\n", - "/home/nelsonag/git/openmc/openmc/mixin.py:71: IDWarning: Another Filter instance already exists with id=2.\n", + "/home/romano/openmc/openmc/mixin.py:71: IDWarning: Another Filter instance already exists with id=2.\n", " warn(msg, IDWarning)\n", - "/home/nelsonag/git/openmc/openmc/mixin.py:71: IDWarning: Another Filter instance already exists with id=11.\n", + "/home/romano/openmc/openmc/mixin.py:71: IDWarning: Another Filter instance already exists with id=11.\n", " warn(msg, IDWarning)\n", - "/home/nelsonag/git/openmc/openmc/mixin.py:71: IDWarning: Another Filter instance already exists with id=21.\n", + "/home/romano/openmc/openmc/mixin.py:71: IDWarning: Another Filter instance already exists with id=21.\n", " warn(msg, IDWarning)\n", - "/home/nelsonag/git/openmc/openmc/mixin.py:71: IDWarning: Another Filter instance already exists with id=22.\n", + "/home/romano/openmc/openmc/mixin.py:71: IDWarning: Another Filter instance already exists with id=22.\n", " warn(msg, IDWarning)\n", - "/home/nelsonag/git/openmc/openmc/mixin.py:71: IDWarning: Another Filter instance already exists with id=12.\n", + "/home/romano/openmc/openmc/mixin.py:71: IDWarning: Another Filter instance already exists with id=12.\n", " warn(msg, IDWarning)\n", - "/home/nelsonag/git/openmc/openmc/mixin.py:71: IDWarning: Another Filter instance already exists with id=18.\n", + "/home/romano/openmc/openmc/mixin.py:71: IDWarning: Another Filter instance already exists with id=18.\n", " warn(msg, IDWarning)\n" ] } @@ -749,57 +731,58 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 23, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "\n", - " %%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", + " %%%%%%%%%%%%%%%\n", + " %%%%%%%%%%%%%%%%%%%%%%%%\n", + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " ############### %%%%%%%%%%%%%%%%%%%%%%%%\n", - " ################## %%%%%%%%%%%%%%%%%%%%%%%\n", - " ################### %%%%%%%%%%%%%%%%%%%%%%%\n", - " #################### %%%%%%%%%%%%%%%%%%%%%%\n", - " ##################### %%%%%%%%%%%%%%%%%%%%%\n", - " ###################### %%%%%%%%%%%%%%%%%%%%\n", - " ####################### %%%%%%%%%%%%%%%%%%\n", - " ####################### %%%%%%%%%%%%%%%%%\n", - " ###################### %%%%%%%%%%%%%%%%%\n", - " #################### %%%%%%%%%%%%%%%%%\n", - " ################# %%%%%%%%%%%%%%%%%\n", - " ############### %%%%%%%%%%%%%%%%\n", - " ############ %%%%%%%%%%%%%%%\n", - " ######## %%%%%%%%%%%%%%\n", - " %%%%%%%%%%%\n", + " %%%%%%%%%%%%%%%%%%%%%%%%\n", + " ############### %%%%%%%%%%%%%%%%%%%%%%%%\n", + " ################## %%%%%%%%%%%%%%%%%%%%%%%\n", + " ################### %%%%%%%%%%%%%%%%%%%%%%%\n", + " #################### %%%%%%%%%%%%%%%%%%%%%%\n", + " ##################### %%%%%%%%%%%%%%%%%%%%%\n", + " ###################### %%%%%%%%%%%%%%%%%%%%\n", + " ####################### %%%%%%%%%%%%%%%%%%\n", + " ####################### %%%%%%%%%%%%%%%%%\n", + " ###################### %%%%%%%%%%%%%%%%%\n", + " #################### %%%%%%%%%%%%%%%%%\n", + " ################# %%%%%%%%%%%%%%%%%\n", + " ############### %%%%%%%%%%%%%%%%\n", + " ############ %%%%%%%%%%%%%%%\n", + " ######## %%%%%%%%%%%%%%\n", + " %%%%%%%%%%%\n", "\n", " | The OpenMC Monte Carlo Code\n", - " Copyright | 2011-2018 Massachusetts Institute of Technology\n", + " Copyright | 2011-2019 MIT and OpenMC contributors\n", " License | http://openmc.readthedocs.io/en/latest/license.html\n", - " Version | 0.10.0\n", - " Git SHA1 | 6c2d82a4d7dfe10312329d5969568fc03a698416\n", - " Date/Time | 2018-04-24 19:15:17\n", - " OpenMP Threads | 8\n", + " Version | 0.11.0-dev\n", + " Git SHA1 | ed7123f4e7ce7b097c4b2bfb0ef5283eaa8afaea\n", + " Date/Time | 2019-10-04 10:54:35\n", + " OpenMP Threads | 4\n", "\n", + " Minimum neutron data temperature: 294.000000 K\n", + " Maximum neutron data temperature: 294.000000 K\n", "\n", " ====================> K EIGENVALUE SIMULATION <====================\n", "\n", "\n", " ============================> RESULTS <============================\n", "\n", - " k-effective (Collision) = 0.83880 +/- 0.00101\n", - " k-effective (Track-length) = 0.83917 +/- 0.00118\n", - " k-effective (Absorption) = 0.83859 +/- 0.00104\n", - " Combined k-effective = 0.83879 +/- 0.00086\n", - " Leakage Fraction = 0.00000 +/- 0.00000\n", + " k-effective (Collision) = 0.83866 +/- 0.00102\n", + " k-effective (Track-length) = 0.83799 +/- 0.00118\n", + " k-effective (Absorption) = 0.83968 +/- 0.00103\n", + " Combined k-effective = 0.83900 +/- 0.00085\n", + " Leakage Fraction = 0.00000 +/- 0.00000\n", "\n" ] } @@ -818,7 +801,7 @@ }, { "cell_type": "code", - "execution_count": 25, + "execution_count": 24, "metadata": {}, "outputs": [], "source": [ @@ -841,7 +824,7 @@ }, { "cell_type": "code", - "execution_count": 26, + "execution_count": 25, "metadata": {}, "outputs": [], "source": [ @@ -858,7 +841,7 @@ }, { "cell_type": "code", - "execution_count": 27, + "execution_count": 26, "metadata": {}, "outputs": [], "source": [ @@ -875,7 +858,7 @@ }, { "cell_type": "code", - "execution_count": 28, + "execution_count": 27, "metadata": {}, "outputs": [], "source": [ @@ -912,14 +895,14 @@ }, { "cell_type": "code", - "execution_count": 29, + "execution_count": 28, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "/home/nelsonag/git/openmc/openmc/mixin.py:71: IDWarning: Another Universe instance already exists with id=0.\n", + "/home/romano/openmc/openmc/mixin.py:71: IDWarning: Another Universe instance already exists with id=0.\n", " warn(msg, IDWarning)\n" ] } @@ -947,7 +930,7 @@ }, { "cell_type": "code", - "execution_count": 30, + "execution_count": 29, "metadata": {}, "outputs": [], "source": [ @@ -967,7 +950,7 @@ }, { "cell_type": "code", - "execution_count": 31, + "execution_count": 30, "metadata": {}, "outputs": [], "source": [ @@ -990,27 +973,29 @@ }, { "cell_type": "code", - "execution_count": 32, + "execution_count": 31, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "" + "" ] }, - "execution_count": 32, + "execution_count": 31, "metadata": {}, "output_type": "execute_result" }, { "data": { - "image/png": "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\n", + "image/png": "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\n", "text/plain": [ - "" + "
" ] }, - "metadata": {}, + "metadata": { + "needs_background": "light" + }, "output_type": "display_data" } ], @@ -1031,45 +1016,44 @@ }, { "cell_type": "code", - "execution_count": 33, + "execution_count": 32, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "\n", - " %%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", + " %%%%%%%%%%%%%%%\n", + " %%%%%%%%%%%%%%%%%%%%%%%%\n", + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " ############### %%%%%%%%%%%%%%%%%%%%%%%%\n", - " ################## %%%%%%%%%%%%%%%%%%%%%%%\n", - " ################### %%%%%%%%%%%%%%%%%%%%%%%\n", - " #################### %%%%%%%%%%%%%%%%%%%%%%\n", - " ##################### %%%%%%%%%%%%%%%%%%%%%\n", - " ###################### %%%%%%%%%%%%%%%%%%%%\n", - " ####################### %%%%%%%%%%%%%%%%%%\n", - " ####################### %%%%%%%%%%%%%%%%%\n", - " ###################### %%%%%%%%%%%%%%%%%\n", - " #################### %%%%%%%%%%%%%%%%%\n", - " ################# %%%%%%%%%%%%%%%%%\n", - " ############### %%%%%%%%%%%%%%%%\n", - " ############ %%%%%%%%%%%%%%%\n", - " ######## %%%%%%%%%%%%%%\n", - " %%%%%%%%%%%\n", + " %%%%%%%%%%%%%%%%%%%%%%%%\n", + " ############### %%%%%%%%%%%%%%%%%%%%%%%%\n", + " ################## %%%%%%%%%%%%%%%%%%%%%%%\n", + " ################### %%%%%%%%%%%%%%%%%%%%%%%\n", + " #################### %%%%%%%%%%%%%%%%%%%%%%\n", + " ##################### %%%%%%%%%%%%%%%%%%%%%\n", + " ###################### %%%%%%%%%%%%%%%%%%%%\n", + " ####################### %%%%%%%%%%%%%%%%%%\n", + " ####################### %%%%%%%%%%%%%%%%%\n", + " ###################### %%%%%%%%%%%%%%%%%\n", + " #################### %%%%%%%%%%%%%%%%%\n", + " ################# %%%%%%%%%%%%%%%%%\n", + " ############### %%%%%%%%%%%%%%%%\n", + " ############ %%%%%%%%%%%%%%%\n", + " ######## %%%%%%%%%%%%%%\n", + " %%%%%%%%%%%\n", "\n", " | The OpenMC Monte Carlo Code\n", - " Copyright | 2011-2018 Massachusetts Institute of Technology\n", + " Copyright | 2011-2019 MIT and OpenMC contributors\n", " License | http://openmc.readthedocs.io/en/latest/license.html\n", - " Version | 0.10.0\n", - " Git SHA1 | 6c2d82a4d7dfe10312329d5969568fc03a698416\n", - " Date/Time | 2018-04-24 19:16:03\n", - " OpenMP Threads | 8\n", + " Version | 0.11.0-dev\n", + " Git SHA1 | ed7123f4e7ce7b097c4b2bfb0ef5283eaa8afaea\n", + " Date/Time | 2019-10-04 10:56:58\n", + " OpenMP Threads | 4\n", "\n", "\n", " ====================> K EIGENVALUE SIMULATION <====================\n", @@ -1077,11 +1061,11 @@ "\n", " ============================> RESULTS <============================\n", "\n", - " k-effective (Collision) = 0.82313 +/- 0.00100\n", - " k-effective (Track-length) = 0.82363 +/- 0.00102\n", - " k-effective (Absorption) = 0.82532 +/- 0.00076\n", - " Combined k-effective = 0.82484 +/- 0.00067\n", - " Leakage Fraction = 0.00000 +/- 0.00000\n", + " k-effective (Collision) = 0.82471 +/- 0.00104\n", + " k-effective (Track-length) = 0.82466 +/- 0.00103\n", + " k-effective (Absorption) = 0.82482 +/- 0.00075\n", + " Combined k-effective = 0.82477 +/- 0.00068\n", + " Leakage Fraction = 0.00000 +/- 0.00000\n", "\n" ] } @@ -1100,7 +1084,7 @@ }, { "cell_type": "code", - "execution_count": 34, + "execution_count": 33, "metadata": {}, "outputs": [], "source": [ @@ -1125,14 +1109,14 @@ }, { "cell_type": "code", - "execution_count": 35, + "execution_count": 34, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "/home/nelsonag/git/openmc/openmc/mixin.py:71: IDWarning: Another Universe instance already exists with id=0.\n", + "/home/romano/openmc/openmc/mixin.py:71: IDWarning: Another Universe instance already exists with id=0.\n", " warn(msg, IDWarning)\n" ] } @@ -1153,45 +1137,44 @@ }, { "cell_type": "code", - "execution_count": 36, + "execution_count": 35, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "\n", - " %%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", - " %%%%%%%%%%%%%%%%%%%%%%%%\n", + " %%%%%%%%%%%%%%%\n", + " %%%%%%%%%%%%%%%%%%%%%%%%\n", + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", + " %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n", " %%%%%%%%%%%%%%%%%%%%%%%%\n", - " ############### %%%%%%%%%%%%%%%%%%%%%%%%\n", - " ################## %%%%%%%%%%%%%%%%%%%%%%%\n", - " ################### %%%%%%%%%%%%%%%%%%%%%%%\n", - " #################### %%%%%%%%%%%%%%%%%%%%%%\n", - " ##################### %%%%%%%%%%%%%%%%%%%%%\n", - " ###################### %%%%%%%%%%%%%%%%%%%%\n", - " ####################### %%%%%%%%%%%%%%%%%%\n", - " ####################### %%%%%%%%%%%%%%%%%\n", - " ###################### %%%%%%%%%%%%%%%%%\n", - " #################### %%%%%%%%%%%%%%%%%\n", - " ################# %%%%%%%%%%%%%%%%%\n", - " ############### %%%%%%%%%%%%%%%%\n", - " ############ %%%%%%%%%%%%%%%\n", - " ######## %%%%%%%%%%%%%%\n", - " %%%%%%%%%%%\n", + " %%%%%%%%%%%%%%%%%%%%%%%%\n", + " ############### %%%%%%%%%%%%%%%%%%%%%%%%\n", + " ################## %%%%%%%%%%%%%%%%%%%%%%%\n", + " ################### %%%%%%%%%%%%%%%%%%%%%%%\n", + " #################### %%%%%%%%%%%%%%%%%%%%%%\n", + " ##################### %%%%%%%%%%%%%%%%%%%%%\n", + " ###################### %%%%%%%%%%%%%%%%%%%%\n", + " ####################### %%%%%%%%%%%%%%%%%%\n", + " ####################### %%%%%%%%%%%%%%%%%\n", + " ###################### %%%%%%%%%%%%%%%%%\n", + " #################### %%%%%%%%%%%%%%%%%\n", + " ################# %%%%%%%%%%%%%%%%%\n", + " ############### %%%%%%%%%%%%%%%%\n", + " ############ %%%%%%%%%%%%%%%\n", + " ######## %%%%%%%%%%%%%%\n", + " %%%%%%%%%%%\n", "\n", " | The OpenMC Monte Carlo Code\n", - " Copyright | 2011-2018 Massachusetts Institute of Technology\n", + " Copyright | 2011-2019 MIT and OpenMC contributors\n", " License | http://openmc.readthedocs.io/en/latest/license.html\n", - " Version | 0.10.0\n", - " Git SHA1 | 6c2d82a4d7dfe10312329d5969568fc03a698416\n", - " Date/Time | 2018-04-24 19:16:12\n", - " OpenMP Threads | 8\n", + " Version | 0.11.0-dev\n", + " Git SHA1 | ed7123f4e7ce7b097c4b2bfb0ef5283eaa8afaea\n", + " Date/Time | 2019-10-04 10:57:24\n", + " OpenMP Threads | 4\n", "\n", "\n", " ====================> K EIGENVALUE SIMULATION <====================\n", @@ -1199,11 +1182,11 @@ "\n", " ============================> RESULTS <============================\n", "\n", - " k-effective (Collision) = 0.83745 +/- 0.00108\n", - " k-effective (Track-length) = 0.83712 +/- 0.00108\n", - " k-effective (Absorption) = 0.83694 +/- 0.00078\n", - " Combined k-effective = 0.83695 +/- 0.00070\n", - " Leakage Fraction = 0.00000 +/- 0.00000\n", + " k-effective (Collision) = 0.83564 +/- 0.00103\n", + " k-effective (Track-length) = 0.83572 +/- 0.00104\n", + " k-effective (Absorption) = 0.83478 +/- 0.00073\n", + " Combined k-effective = 0.83504 +/- 0.00066\n", + " Leakage Fraction = 0.00000 +/- 0.00000\n", "\n" ] } @@ -1225,7 +1208,7 @@ }, { "cell_type": "code", - "execution_count": 37, + "execution_count": 36, "metadata": {}, "outputs": [], "source": [ @@ -1248,7 +1231,7 @@ }, { "cell_type": "code", - "execution_count": 38, + "execution_count": 37, "metadata": {}, "outputs": [], "source": [ @@ -1257,8 +1240,8 @@ "angle_mg_keff = angle_mgsp.k_combined\n", "\n", "# Find eigenvalue bias\n", - "iso_bias = 1.0E5 * (ce_keff - iso_mg_keff)\n", - "angle_bias = 1.0E5 * (ce_keff - angle_mg_keff)" + "iso_bias = 1.0e5 * (ce_keff - iso_mg_keff)\n", + "angle_bias = 1.0e5 * (ce_keff - angle_mg_keff)" ] }, { @@ -1270,15 +1253,15 @@ }, { "cell_type": "code", - "execution_count": 39, + "execution_count": 38, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Isotropic to CE Bias [pcm]: 1394.6\n", - "Angle to CE Bias [pcm]: 183.4\n" + "Isotropic to CE Bias [pcm]: 1423.5\n", + "Angle to CE Bias [pcm]: 396.6\n" ] } ], @@ -1305,19 +1288,21 @@ }, { "cell_type": "code", - "execution_count": 40, + "execution_count": 39, "metadata": { "scrolled": false }, "outputs": [ { "data": { - "image/png": "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\n", + "image/png": "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\n", "text/plain": [ - "" + "
" ] }, - "metadata": {}, + "metadata": { + "needs_background": "light" + }, "output_type": "display_data" } ], @@ -1363,27 +1348,29 @@ }, { "cell_type": "code", - "execution_count": 41, + "execution_count": 40, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "" + "" ] }, - "execution_count": 41, + "execution_count": 40, "metadata": {}, "output_type": "execute_result" }, { "data": { - "image/png": "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\n", + "image/png": "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\n", "text/plain": [ - "" + "
" ] }, - "metadata": {}, + "metadata": { + "needs_background": "light" + }, "output_type": "display_data" } ], @@ -1430,7 +1417,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.6.7" + "version": "3.7.0" } }, "nbformat": 4, From 5b195b6e9fed2b5c144bdaa9aa6feea3b4fa6d12 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Fri, 4 Oct 2019 14:00:22 -0500 Subject: [PATCH 030/158] Various fixes and updates in documentation --- docs/source/io_formats/statepoint.rst | 3 +- docs/source/methods/cross_sections.rst | 25 ++-- docs/source/methods/energy_deposition.rst | 10 +- docs/source/methods/introduction.rst | 2 +- docs/source/methods/neutron_physics.rst | 5 +- docs/source/pythonapi/data.rst | 160 +++++++++++----------- docs/source/pythonapi/deplete.rst | 4 +- docs/source/usersguide/cross_sections.rst | 18 +-- docs/source/usersguide/geometry.rst | 13 +- docs/source/usersguide/settings.rst | 15 -- 10 files changed, 125 insertions(+), 130 deletions(-) diff --git a/docs/source/io_formats/statepoint.rst b/docs/source/io_formats/statepoint.rst index 5a373580d..9156e848f 100644 --- a/docs/source/io_formats/statepoint.rst +++ b/docs/source/io_formats/statepoint.rst @@ -109,7 +109,8 @@ The current version of the statepoint file format is 17.0. **/tallies/tally /** -:Attributes: - **internal** (*int*) -- Flag indicating the presence of tally +:Attributes: + - **internal** (*int*) -- Flag indicating the presence of tally data (0) or absence of tally data (1). All user defined tallies will have a value of 0 unless otherwise instructed. diff --git a/docs/source/methods/cross_sections.rst b/docs/source/methods/cross_sections.rst index dbf078654..70d80a537 100644 --- a/docs/source/methods/cross_sections.rst +++ b/docs/source/methods/cross_sections.rst @@ -8,13 +8,14 @@ Cross Section Representations Continuous-Energy Data ---------------------- -The data governing the interaction of neutrons with -various nuclei for continous-energy problems are represented using the ACE -format which is used by MCNP_ and Serpent_. ACE-format data can be generated -with the NJOY_ nuclear data processing system which converts raw -`ENDF/B data`_ into linearly-interpolable data as required by most Monte Carlo -codes. The use of a standard cross section format allows for a direct comparison -of OpenMC with other codes since the same cross section libraries can be used. +In OpenMC, the data governing the interaction of neutrons with various nuclei +for continous-energy problems are represented using an HDF5 format that can be +produced by converting files in the ACE format, which is used by MCNP_ and +Serpent_. ACE-format data can be generated with the NJOY_ nuclear data +processing system, which converts raw `ENDF/B data`_ into linearly-interpolable +data as required by most Monte Carlo codes. Since ACE-format data can be +converted into OpenMC's HDF5 format, it is possible to perform direct comparison +of OpenMC with other codes using the same underlying nuclear data library. The ACE format contains continuous-energy cross sections for the following types of reactions: elastic scattering, fission (or first-chance fission, @@ -31,7 +32,7 @@ data can be used. Energy Grid Methods ------------------- -The method by which continuous energy cross sections for each nuclide in a +The method by which continuous-energy cross sections for each nuclide in a problem are stored as a function of energy can have a substantial effect on the performance of a Monte Carlo simulation. Since the ACE format is based on linearly-interpolable cross sections, each nuclide has cross sections tabulated @@ -72,9 +73,9 @@ Windowed Multipole Representation --------------------------------- In addition to the usual pointwise representation of cross sections, OpenMC -offers support for an experimental data format called windowed multipole (WMP). -This data format requires less memory than pointwise cross sections, and it -allows on-the-fly Doppler broadening to arbitrary temperature. +offers support for an data format called windowed multipole (WMP). This data +format requires less memory than pointwise cross sections, and it allows +on-the-fly Doppler broadening to arbitrary temperature. The multipole method was introduced by Hwang_ and the faster windowed multipole method by Josey_. In the multipole format, cross section resonances are @@ -258,7 +259,7 @@ where a material has a very large cross sections relative to the other material used to minimize this error. Finally, the above options for representing the physics do not have to be -consistent across the problem. The number of groups and the structure, however, +consistent across the problem. The number of groups and the structure, however, does have to be consistent across the data sets. That is to say that each microscopic or macroscopic data set does not have to apply the same scattering expansion, treatment of multiplicity or angular representation of the cross diff --git a/docs/source/methods/energy_deposition.rst b/docs/source/methods/energy_deposition.rst index af4962c55..86dfb9bf9 100644 --- a/docs/source/methods/energy_deposition.rst +++ b/docs/source/methods/energy_deposition.rst @@ -4,11 +4,11 @@ Heating and Energy Deposition ============================= -As particles traverse a problem, some portion of their energy is deposited at +As particles traverse a problem, some portion of their energy is deposited at collision sites. This energy is deposited when charged particles, including electrons and recoil nuclei, undergo electromagnetic interactions with surrounding electons and ions. The information describing how much energy -is deposited for a specific reaction is referred to as +is deposited for a specific reaction is referred to as "heating numbers" and can be computed using a program like NJOY with the ``heatr`` module. @@ -108,7 +108,7 @@ Neutron Transport For this case, OpenMC instructs ``heatr`` to produce heating coefficients assuming that energy from photons, :math:`E_{\gamma, p}` and :math:`E_{\gamma, d}`, is deposited at the fission site. -Let :math:`N901` represent the total heating number returned from this ``heatr`` +Let :math:`N901` represent the total heating number returned from this ``heatr`` run with :math:`N918` reflecting fission heating computed from NJOY. :math:`M901` represent the following modification @@ -119,7 +119,7 @@ run with :math:`N918` reflecting fission heating computed from NJOY. + E_{i, \gamma, d}\right]\sigma_{i, f}(E). This modified heating data is stored as the MT=901 reaction and will be scored -if ``901`` is included in :attr:`openmc.Tally.scores`. +if ``heating-local`` is included in :attr:`openmc.Tally.scores`. Coupled neutron-photon transport -------------------------------- @@ -146,4 +146,4 @@ References .. [Mack97] Abdou, M.A., Maynard, C.W., and Wright, R.Q. MACK: computer program to calculate neutron energy release parameters (fluence-to-kerma factors) and multigroup neutron reaction cross sections from nuclear data - in ENDF Format. Oak Ridge National Laboratory report ORNL-TM-3994. \ No newline at end of file + in ENDF Format. Oak Ridge National Laboratory report ORNL-TM-3994. diff --git a/docs/source/methods/introduction.rst b/docs/source/methods/introduction.rst index 0b9544d63..adb52c02e 100644 --- a/docs/source/methods/introduction.rst +++ b/docs/source/methods/introduction.rst @@ -139,7 +139,7 @@ be performed before the run is finished. This include the following: - If requested, a source file is written to disk. - - All allocatable arrays are deallocated. + - Dynamically-allocated memory should be freed. .. _probability distributions: https://en.wikipedia.org/wiki/Probability_distribution .. _Monte Carlo: https://en.wikipedia.org/wiki/Monte_Carlo_method diff --git a/docs/source/methods/neutron_physics.rst b/docs/source/methods/neutron_physics.rst index 71e9b6bcd..384e79bdd 100644 --- a/docs/source/methods/neutron_physics.rst +++ b/docs/source/methods/neutron_physics.rst @@ -1298,11 +1298,10 @@ section over the range of velocities considered: where it should be noted that the maximum is taken over the range :math:`[v_n - 4/\beta, 4_n + 4\beta]`. This method is known as Doppler broadening rejection correction (DBRC) and was first introduced by `Becker et al.`_. OpenMC has an -implementation of DBRC as well as an accelerated sampling method that are -described fully in `Walsh et al.`_ +implementation of DBRC as well as an accelerated sampling method that samples the `relative velocity`_ directly. .. _Becker et al.: https://doi.org/10.1016/j.anucene.2008.12.001 -.. _Walsh et al.: https://doi.org/10.1016/j.anucene.2014.01.017 +.. _relative velocity: https://doi.org/10.1016/j.anucene.2017.12.044 .. _sab_tables: diff --git a/docs/source/pythonapi/data.rst b/docs/source/pythonapi/data.rst index 92cb78548..be29d7c0e 100644 --- a/docs/source/pythonapi/data.rst +++ b/docs/source/pythonapi/data.rst @@ -2,6 +2,8 @@ :mod:`openmc.data` -- Nuclear Data Interface -------------------------------------------- +.. module:: openmc.data + Core Classes ------------ @@ -13,15 +15,15 @@ and product yields. :nosignatures: :template: myclass.rst - openmc.data.IncidentNeutron - openmc.data.Reaction - openmc.data.Product - openmc.data.FissionEnergyRelease - openmc.data.DataLibrary - openmc.data.Decay - openmc.data.FissionProductYields - openmc.data.WindowedMultipole - openmc.data.ProbabilityTables + IncidentNeutron + Reaction + Product + FissionEnergyRelease + DataLibrary + Decay + FissionProductYields + WindowedMultipole + ProbabilityTables The following classes are used for storing atomic data (incident photon cross sections, atomic relaxation): @@ -31,9 +33,9 @@ sections, atomic relaxation): :nosignatures: :template: myclass.rst - openmc.data.IncidentPhoton - openmc.data.PhotonReaction - openmc.data.AtomicRelaxation + IncidentPhoton + PhotonReaction + AtomicRelaxation The following classes are used for storing thermal neutron scattering data: @@ -43,10 +45,10 @@ The following classes are used for storing thermal neutron scattering data: :nosignatures: :template: myclass.rst - openmc.data.ThermalScattering - openmc.data.ThermalScatteringReaction - openmc.data.CoherentElastic - openmc.data.IncoherentElastic + ThermalScattering + ThermalScatteringReaction + CoherentElastic + IncoherentElastic Core Functions @@ -57,12 +59,12 @@ Core Functions :nosignatures: :template: myfunction.rst - openmc.data.atomic_mass - openmc.data.gnd_name - openmc.data.linearize - openmc.data.thin - openmc.data.water_density - openmc.data.zam + atomic_mass + gnd_name + linearize + thin + water_density + zam One-dimensional Functions ------------------------- @@ -72,13 +74,13 @@ One-dimensional Functions :nosignatures: :template: myclass.rst - openmc.data.Function1D - openmc.data.Tabulated1D - openmc.data.Polynomial - openmc.data.Combination - openmc.data.Sum - openmc.data.Regions1D - openmc.data.ResonancesWithBackground + Function1D + Tabulated1D + Polynomial + Combination + Sum + Regions1D + ResonancesWithBackground Angle-Energy Distributions -------------------------- @@ -88,27 +90,27 @@ Angle-Energy Distributions :nosignatures: :template: myclass.rst - openmc.data.AngleEnergy - openmc.data.KalbachMann - openmc.data.CorrelatedAngleEnergy - openmc.data.UncorrelatedAngleEnergy - openmc.data.NBodyPhaseSpace - openmc.data.LaboratoryAngleEnergy - openmc.data.AngleDistribution - openmc.data.EnergyDistribution - openmc.data.ArbitraryTabulated - openmc.data.GeneralEvaporation - openmc.data.MaxwellEnergy - openmc.data.Evaporation - openmc.data.WattEnergy - openmc.data.MadlandNix - openmc.data.DiscretePhoton - openmc.data.LevelInelastic - openmc.data.ContinuousTabular - openmc.data.CoherentElasticAE - openmc.data.IncoherentElasticAE - openmc.data.IncoherentElasticAEDiscrete - openmc.data.IncoherentInelasticAEDiscrete + AngleEnergy + KalbachMann + CorrelatedAngleEnergy + UncorrelatedAngleEnergy + NBodyPhaseSpace + LaboratoryAngleEnergy + AngleDistribution + EnergyDistribution + ArbitraryTabulated + GeneralEvaporation + MaxwellEnergy + Evaporation + WattEnergy + MadlandNix + DiscretePhoton + LevelInelastic + ContinuousTabular + CoherentElasticAE + IncoherentElasticAE + IncoherentElasticAEDiscrete + IncoherentInelasticAEDiscrete Resonance Data -------------- @@ -118,20 +120,20 @@ Resonance Data :nosignatures: :template: myclass.rst - openmc.data.Resonances - openmc.data.ResonanceRange - openmc.data.SingleLevelBreitWigner - openmc.data.MultiLevelBreitWigner - openmc.data.ReichMoore - openmc.data.RMatrixLimited - openmc.data.ResonanceCovariances - openmc.data.ResonanceCovarianceRange - openmc.data.SingleLevelBreitWignerCovariance - openmc.data.MultiLevelBreitWignerCovariance - openmc.data.ReichMooreCovariance - openmc.data.ParticlePair - openmc.data.SpinGroup - openmc.data.Unresolved + Resonances + ResonanceRange + SingleLevelBreitWigner + MultiLevelBreitWigner + ReichMoore + RMatrixLimited + ResonanceCovariances + ResonanceCovarianceRange + SingleLevelBreitWignerCovariance + MultiLevelBreitWignerCovariance + ReichMooreCovariance + ParticlePair + SpinGroup + Unresolved ACE Format ---------- @@ -144,8 +146,8 @@ Classes :nosignatures: :template: myclass.rst - openmc.data.ace.Library - openmc.data.ace.Table + ace.Library + ace.Table Functions +++++++++ @@ -155,7 +157,7 @@ Functions :nosignatures: :template: myfunction.rst - openmc.data.ace.ascii_to_binary + ace.ascii_to_binary ENDF Format ----------- @@ -168,7 +170,7 @@ Classes :nosignatures: :template: myclass.rst - openmc.data.endf.Evaluation + endf.Evaluation Functions +++++++++ @@ -178,13 +180,13 @@ Functions :nosignatures: :template: myfunction.rst - openmc.data.endf.float_endf - openmc.data.endf.get_cont_record - openmc.data.endf.get_evaluations - openmc.data.endf.get_head_record - openmc.data.endf.get_tab1_record - openmc.data.endf.get_tab2_record - openmc.data.endf.get_text_record + endf.float_endf + endf.get_cont_record + endf.get_evaluations + endf.get_head_record + endf.get_tab1_record + endf.get_tab2_record + endf.get_text_record NJOY Interface -------------- @@ -194,7 +196,7 @@ NJOY Interface :nosignatures: :template: myfunction.rst - openmc.data.njoy.run - openmc.data.njoy.make_pendf - openmc.data.njoy.make_ace - openmc.data.njoy.make_ace_thermal + njoy.run + njoy.make_pendf + njoy.make_ace + njoy.make_ace_thermal diff --git a/docs/source/pythonapi/deplete.rst b/docs/source/pythonapi/deplete.rst index b864529d1..b9970ffb1 100644 --- a/docs/source/pythonapi/deplete.rst +++ b/docs/source/pythonapi/deplete.rst @@ -1,11 +1,11 @@ .. _pythonapi_deplete: +.. module:: openmc.deplete + ---------------------------------- :mod:`openmc.deplete` -- Depletion ---------------------------------- -.. module:: openmc.deplete - Primary API ----------- diff --git a/docs/source/usersguide/cross_sections.rst b/docs/source/usersguide/cross_sections.rst index 636b44db4..144b1c152 100644 --- a/docs/source/usersguide/cross_sections.rst +++ b/docs/source/usersguide/cross_sections.rst @@ -16,10 +16,10 @@ recommended to use one of the pregenerated libraries. Alternatively, if you have ACE format data that was produced with NJOY_, such as that distributed with MCNP_ or Serpent_, it can be converted to the HDF5 format using the :ref:`using the Python API `. Several sources provide openly available -ACE data including the `ENDF/B`_, JEFF_, and TENDL_ -libraries. In addition to tabulated cross sections in the HDF5 files, OpenMC -relies on :ref:`windowed multipole ` data to perform -on-the-fly Doppler broadening. +ACE data including the `ENDF/B`_, JEFF_, and TENDL_ libraries as well as the +`LANL Nuclear Data Team `_. In addition to +tabulated cross sections in the HDF5 files, OpenMC relies on :ref:`windowed +multipole ` data to perform on-the-fly Doppler broadening. In multi-group mode, OpenMC utilizes an HDF5-based library format which can be used to describe nuclide- or material-specific quantities. @@ -30,11 +30,11 @@ Environment Variables When :ref:`scripts_openmc` is run, it will look for several environment variables that indicate where cross sections can be found. While the location of -cross sections can also be indicated through the :class:`openmc.Materials` class -(or in the :ref:`materials.xml ` file), if you always use the same -set of cross section data, it is often easier to just set an environment -variable that will be picked up by default every time OpenMC is run. The -following environment variables are used: +cross sections can also be indicated through the +:attr:`openmc.Materials.cross_setion` attribute (or in the :ref:`materials.xml +` file), if you always use the same set of cross section data, it +is often easier to just set an environment variable that will be picked up by +default every time OpenMC is run. The following environment variables are used: :envvar:`OPENMC_CROSS_SECTIONS` Indicates the path to the :ref:`cross_sections.xml ` diff --git a/docs/source/usersguide/geometry.rst b/docs/source/usersguide/geometry.rst index 5e583cfd2..dc7dd978e 100644 --- a/docs/source/usersguide/geometry.rst +++ b/docs/source/usersguide/geometry.rst @@ -121,11 +121,11 @@ For many regions, a bounding-box can be determined automatically:: While a bounding box can be determined for regions involving half-spaces of spheres, cylinders, and axis-aligned planes, it generally cannot be determined if the region involves cones, non-axis-aligned planes, or other exotic -second-order surfaces. For example, the :func:`openmc.get_hexagonal_prism` +second-order surfaces. For example, the :func:`openmc.model.hexagonal_prism` function returns the interior region of a hexagonal prism; because it is bounded by a :class:`openmc.Plane`, trying to get its bounding box won't work:: - >>> hex = openmc.get_hexagonal_prism() + >>> hex = openmc.model.hexagonal_prism() >>> hex.bounding_box (array([-0.8660254, -inf, -inf]), array([ 0.8660254, inf, inf])) @@ -374,7 +374,7 @@ code would work:: hexlat.universes = [outer_ring, middle_ring, inner_ring] If you need to create a hexagonal boundary (composed of six planar surfaces) for -a hexagonal lattice, :func:`openmc.get_hexagonal_prism` can be used. +a hexagonal lattice, :func:`openmc.model.hexagonal_prism` can be used. .. _usersguide_geom_export: @@ -396,6 +396,13 @@ if needed, lattices, the last step is to create an instance of geom.root_universe = root_univ geom.export_to_xml() +Note that it's not strictly required to manually create a root universe. You can +also pass a list of cells to the :class:`openmc.Geometry` constructor and it +will handle creating the unverse:: + + geom = openmc.Geometry([cell1, cell2, cell3]) + geom.export_to_xml() + .. _constructive solid geometry: https://en.wikipedia.org/wiki/Constructive_solid_geometry .. _quadratic surfaces: https://en.wikipedia.org/wiki/Quadric diff --git a/docs/source/usersguide/settings.rst b/docs/source/usersguide/settings.rst index 496d18f7f..1254c4ed5 100644 --- a/docs/source/usersguide/settings.rst +++ b/docs/source/usersguide/settings.rst @@ -221,26 +221,11 @@ selected:: settings.electron_treatment = 'led' -.. warning:: - Currently, collision stopping powers used in the TTB approximation come from - the `NIST ESTAR database`_, which provides data for each element calculated - using by default the material density at standard temperature and pressure. - In OpenMC, stopping powers for compounds are calculated from this elemental - data using Bragg's additivity rule. However, this is not a good - approximation --- the collision stopping power is a function of certain - quantities, such as the mean excitation energy and particularly the density - effect correction, that depend on material properties. Data for constituent - elements in a compound cannot simply be summed together, but rather these - quantities should be calculated for the material. This treatment will be - especially poor when the density of a material is different from the - densities used in the NIST data. - .. note:: Some features related to photon transport are not currently implemented, including: * Tallying photon energy deposition. - * Properly accounting for energy deposition in coupled n-p calculations. * Generating a photon source from a neutron calculation that can be used for a later fixed source photon calculation. * Photoneutron reactions. From 130b7a5eebea279206ac84138608fa990fe0f6dd Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Sat, 5 Oct 2019 01:14:27 -0500 Subject: [PATCH 031/158] Setting up new function implement a stopping criterion for volume calculations. --- include/openmc/volume_calc.h | 29 +++++++++++++++++++++++++++ src/volume_calc.cpp | 38 ++++++++++++++++++++++++++++++++++-- 2 files changed, 65 insertions(+), 2 deletions(-) diff --git a/include/openmc/volume_calc.h b/include/openmc/volume_calc.h index 7ee660d8b..c7f6413b0 100644 --- a/include/openmc/volume_calc.h +++ b/include/openmc/volume_calc.h @@ -8,6 +8,7 @@ #include #include +#include namespace openmc { @@ -23,6 +24,31 @@ public: std::vector nuclides; //!< Index of nuclides std::vector atoms; //!< Number of atoms for each nuclide std::vector uncertainty; //!< Uncertainty on number of atoms + size_t num_samples; + + Result& operator +=( const Result& other) { + Expects(volume.size() == other.volume.size()); + Expects(atoms.size() == atoms.size()); + + size_t total_samples = num_samples + other.num_samples; + + for (int i = 0; i < volume.size(); i++) { + // average volume results + volume[0] = (num_samples * volume[0] + other.num_samples * other.volume[0]) / total_samples; + // propagate error + volume[1] = std::sqrt(num_samples * volume[1] *volume[1] + other.num_samples * other.volume[1] * other.volume[1]) / total_samples; + } + + for (int i = 0; i < atoms.size(); i++) { + atoms[i] = (num_samples * atoms[i] + other.num_samples * other.atoms[i]) / total_samples; + uncertainty[i] = std::sqrt(num_samples * uncertainty[i] * uncertainty[i] + other.num_samples * other.uncertainty[i] * other.uncertainty[i]) / total_samples; + } + + num_samples = total_samples; + + return *this; + + } }; // Results for a single domain // Constructors @@ -36,6 +62,8 @@ public: //! \return Vector of results for each user-specified domain std::vector execute() const; + std::vector _execute(size_t seed_offset = 0) const; + //! \brief Write volume calculation results to HDF5 file // //! \param[in] filename Path to HDF5 file to write @@ -45,6 +73,7 @@ public: // Data members int domain_type_; //!< Type of domain (cell, material, etc.) int n_samples_; //!< Number of samples to use + int seed_offset_; Position lower_left_; //!< Lower-left position of bounding box Position upper_right_; //!< Upper-right position of bounding box std::vector domain_ids_; //!< IDs of domains to find volumes of diff --git a/src/volume_calc.cpp b/src/volume_calc.cpp index 6c1c48932..bd6ada96a 100644 --- a/src/volume_calc.cpp +++ b/src/volume_calc.cpp @@ -71,7 +71,40 @@ VolumeCalculation::VolumeCalculation(pugi::xml_node node) } -std::vector VolumeCalculation::execute() const +std::vector VolumeCalculation::execute() const { + + std::vector results; + size_t offset = 0; + + results = _execute(offset); + offset += n_samples_; + + double max_err = -INFTY; + for (int i = 0; i < results.size(); i++) { + max_err = std::max(max_err, results[i].volume[1]); + } + + double error_limit = 1E-05; + int iters = 1; + while (max_err > error_limit) { + std::cout << "Iter " << iters++ << std::endl; + std::vector tmp = _execute(offset); + max_err = -INFTY; + for (int i = 0; i < results.size(); i++) { + auto& result = results[i]; + result += tmp[i]; + max_err = std::max(max_err, result.volume[1]); + } + + offset += n_samples_; + + std::cout << "Max error: " << max_err << std::endl; + } + + return results; +} + +std::vector VolumeCalculation::_execute(size_t seed_offset) const { // Shared data that is collected from all threads int n = domain_ids_.size(); @@ -102,7 +135,7 @@ std::vector VolumeCalculation::execute() const // Sample locations and count hits #pragma omp for for (int i = i_start; i < i_end; i++) { - set_particle_seed(i); + set_particle_seed(seed_offset + i); p.n_coord_ = 1; Position xi {prn(), prn(), prn()}; @@ -248,6 +281,7 @@ std::vector VolumeCalculation::execute() const result.volume[0] = static_cast(total_hits) / n_samples_ * volume_sample; result.volume[1] = std::sqrt(result.volume[0] * (volume_sample - result.volume[0]) / n_samples_); + result.num_samples = n_samples_; for (int j = 0; j < n_nuc; ++j) { // Determine total number of atoms. At this point, we have values in From 1c5218aad6cc14772c454360ced1da08ad69c645 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Sat, 5 Oct 2019 01:26:21 -0500 Subject: [PATCH 032/158] Cleaning up operator a bit. --- include/openmc/volume_calc.h | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/include/openmc/volume_calc.h b/include/openmc/volume_calc.h index c7f6413b0..b5e847742 100644 --- a/include/openmc/volume_calc.h +++ b/include/openmc/volume_calc.h @@ -30,25 +30,41 @@ public: Expects(volume.size() == other.volume.size()); Expects(atoms.size() == atoms.size()); + auto& a_samples = num_samples; + auto& b_samples = other.num_samples; + size_t total_samples = num_samples + other.num_samples; for (int i = 0; i < volume.size(); i++) { - // average volume results - volume[0] = (num_samples * volume[0] + other.num_samples * other.volume[0]) / total_samples; + // calculate weighted average of volume results + auto& a_vol = volume[0]; + auto& b_vol = other.volume[1]; + volume[0] = (a_samples * a_vol + b_samples * b_vol) / total_samples; + // propagate error - volume[1] = std::sqrt(num_samples * volume[1] *volume[1] + other.num_samples * other.volume[1] * other.volume[1]) / total_samples; + auto& a_err = volume[1]; + auto& b_err = other.volume[1]; + volume[1] = std::sqrt(a_samples * a_err * a_err + b_samples * b_err * b_err) / total_samples; } for (int i = 0; i < atoms.size(); i++) { - atoms[i] = (num_samples * atoms[i] + other.num_samples * other.atoms[i]) / total_samples; - uncertainty[i] = std::sqrt(num_samples * uncertainty[i] * uncertainty[i] + other.num_samples * other.uncertainty[i] * other.uncertainty[i]) / total_samples; + // calculate weighted average of atom results + auto& a_atoms = atoms[i]; + auto& b_atoms = other.atoms[i]; + atoms[i] = (a_samples * a_atoms + b_samples * b_atoms) / total_samples; + + // propagate error + auto& a_err = uncertainty[i]; + auto& b_err = other.uncertainty[i]; + uncertainty[i] = std::sqrt(a_samples * a_err * a_err + b_samples * b_err * b_err) / total_samples; } + // update number of samples on the returned set of results; num_samples = total_samples; - - return *this; + return *this; } + }; // Results for a single domain // Constructors From d3bcfeda0f667650c2e6d5fdb948f5b0db8f26af Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Sat, 5 Oct 2019 01:41:07 -0500 Subject: [PATCH 033/158] Cleaning up while loop. --- src/volume_calc.cpp | 36 ++++++++++++++---------------------- 1 file changed, 14 insertions(+), 22 deletions(-) diff --git a/src/volume_calc.cpp b/src/volume_calc.cpp index bd6ada96a..40b5f08dd 100644 --- a/src/volume_calc.cpp +++ b/src/volume_calc.cpp @@ -73,32 +73,24 @@ VolumeCalculation::VolumeCalculation(pugi::xml_node node) std::vector VolumeCalculation::execute() const { - std::vector results; - size_t offset = 0; - - results = _execute(offset); - offset += n_samples_; - - double max_err = -INFTY; - for (int i = 0; i < results.size(); i++) { - max_err = std::max(max_err, results[i].volume[1]); - } - + std::vector results = _execute(); + size_t offset = n_samples_; double error_limit = 1E-05; - int iters = 1; - while (max_err > error_limit) { - std::cout << "Iter " << iters++ << std::endl; - std::vector tmp = _execute(offset); + double max_err; + + while (true) { + // check maximum error value for all domains max_err = -INFTY; - for (int i = 0; i < results.size(); i++) { - auto& result = results[i]; - result += tmp[i]; - max_err = std::max(max_err, result.volume[1]); - } - + for (const auto& result : results) { max_err = std::max(max_err, result.volume[1]); } + + // exit once we're below our error limit + if (max_err <= error_limit) { break; } + + std::vector tmp = _execute(offset); offset += n_samples_; - std::cout << "Max error: " << max_err << std::endl; + // update current results + for (int i = 0; i < results.size(); i++) { results[i] += tmp[i]; } } return results; From 5109bd0de1222f3096f9f511b194c35e25a69696 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Sat, 5 Oct 2019 02:13:12 -0500 Subject: [PATCH 034/158] Adding error trigger attribute to volume calc. --- include/openmc/volume_calc.h | 4 ++-- src/volume_calc.cpp | 32 +++++++++++++++++++++++++------- 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/include/openmc/volume_calc.h b/include/openmc/volume_calc.h index b5e847742..2a8273f9b 100644 --- a/include/openmc/volume_calc.h +++ b/include/openmc/volume_calc.h @@ -88,8 +88,8 @@ public: // Data members int domain_type_; //!< Type of domain (cell, material, etc.) - int n_samples_; //!< Number of samples to use - int seed_offset_; + size_t n_samples_; //!< Number of samples to use + double error_trigger_ {-1.0}; //!< Error below which the calculation will stop Position lower_left_; //!< Lower-left position of bounding box Position upper_right_; //!< Upper-right position of bounding box std::vector domain_ids_; //!< IDs of domains to find volumes of diff --git a/src/volume_calc.cpp b/src/volume_calc.cpp index 40b5f08dd..a57305db9 100644 --- a/src/volume_calc.cpp +++ b/src/volume_calc.cpp @@ -59,7 +59,23 @@ VolumeCalculation::VolumeCalculation(pugi::xml_node node) domain_ids_ = get_node_array(node, "domain_ids"); lower_left_ = get_node_array(node, "lower_left"); upper_right_ = get_node_array(node, "upper_right"); - n_samples_ = std::stoi(get_node_value(node, "samples")); + std::stringstream size_t_stream(get_node_value(node, "samples")); + size_t_stream >> n_samples_; + if (size_t_stream.fail()) { + std::stringstream msg; + msg << "Could not read number of samples (" + << size_t_stream.str() << ")\n"; + fatal_error(msg); + } + + if (check_for_node(node, "error_trigger")) { + error_trigger_ = std::stod(get_node_value(node, "error_trigger")); + if (error_trigger_ <= 0.0) { + std::stringstream msg; + msg << "Invalid error trigger " << error_trigger_ << " provided for a volume calculation."; + fatal_error(msg); + } + } // Ensure there are no duplicates by copying elements to a set and then // comparing the length with the original vector @@ -74,8 +90,10 @@ VolumeCalculation::VolumeCalculation(pugi::xml_node node) std::vector VolumeCalculation::execute() const { std::vector results = _execute(); + + if (error_trigger_ <= 0.0) { return results; } + size_t offset = n_samples_; - double error_limit = 1E-05; double max_err; while (true) { @@ -84,7 +102,7 @@ std::vector VolumeCalculation::execute() const { for (const auto& result : results) { max_err = std::max(max_err, result.volume[1]); } // exit once we're below our error limit - if (max_err <= error_limit) { break; } + if (max_err <= error_trigger_) { break; } std::vector tmp = _execute(offset); offset += n_samples_; @@ -104,9 +122,9 @@ std::vector VolumeCalculation::_execute(size_t seed_o std::vector> master_hits(n); // Number of hits for each material in each domain // Divide work over MPI processes - int min_samples = n_samples_ / mpi::n_procs; - int remainder = n_samples_ % mpi::n_procs; - int i_start, i_end; + size_t min_samples = n_samples_ / mpi::n_procs; + size_t remainder = n_samples_ % mpi::n_procs; + size_t i_start, i_end; if (mpi::rank < remainder) { i_start = (min_samples + 1)*mpi::rank; i_end = i_start + min_samples + 1; @@ -126,7 +144,7 @@ std::vector VolumeCalculation::_execute(size_t seed_o // Sample locations and count hits #pragma omp for - for (int i = i_start; i < i_end; i++) { + for (size_t i = i_start; i < i_end; i++) { set_particle_seed(seed_offset + i); p.n_coord_ = 1; From 4b690ab7518e6de2376ab3ebd01a12c7e463cba1 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Sat, 5 Oct 2019 02:18:16 -0500 Subject: [PATCH 035/158] Fixing a bug. --- include/openmc/volume_calc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/openmc/volume_calc.h b/include/openmc/volume_calc.h index 2a8273f9b..18aa2e2d1 100644 --- a/include/openmc/volume_calc.h +++ b/include/openmc/volume_calc.h @@ -38,7 +38,7 @@ public: for (int i = 0; i < volume.size(); i++) { // calculate weighted average of volume results auto& a_vol = volume[0]; - auto& b_vol = other.volume[1]; + auto& b_vol = other.volume[0]; volume[0] = (a_samples * a_vol + b_samples * b_vol) / total_samples; // propagate error From 507bc0d9339a896dd00ed80ed00f0e5f6724eca7 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Sat, 5 Oct 2019 10:23:11 -0500 Subject: [PATCH 036/158] Exposing volume trigger through Python API. --- include/openmc/volume_calc.h | 12 ++++++--- openmc/volume.py | 31 +++++++++++++++++++--- src/volume_calc.cpp | 16 ++++++----- tests/regression_tests/volume_calc/test.py | 2 +- 4 files changed, 48 insertions(+), 13 deletions(-) diff --git a/include/openmc/volume_calc.h b/include/openmc/volume_calc.h index 18aa2e2d1..4e2b2a2a6 100644 --- a/include/openmc/volume_calc.h +++ b/include/openmc/volume_calc.h @@ -78,8 +78,6 @@ public: //! \return Vector of results for each user-specified domain std::vector execute() const; - std::vector _execute(size_t seed_offset = 0) const; - //! \brief Write volume calculation results to HDF5 file // //! \param[in] filename Path to HDF5 file to write @@ -89,7 +87,7 @@ public: // Data members int domain_type_; //!< Type of domain (cell, material, etc.) size_t n_samples_; //!< Number of samples to use - double error_trigger_ {-1.0}; //!< Error below which the calculation will stop + double trigger_ {-1.0}; //!< Error threshold for domain volumes Position lower_left_; //!< Lower-left position of bounding box Position upper_right_; //!< Upper-right position of bounding box std::vector domain_ids_; //!< IDs of domains to find volumes of @@ -104,6 +102,14 @@ private: void check_hit(int i_material, std::vector& indices, std::vector& hits) const; + //! \brief Perform calculation for domain volumes and average nuclide density + //! using n_samples_ + // + //! \param[in] seed_offset Seed offset used for independent calculations + //! \return Vector of results for each user-specified domain + std::vector _execute(size_t seed_offset = 0) const; + + }; //============================================================================== diff --git a/openmc/volume.py b/openmc/volume.py index 91ff829cb..189287bef 100644 --- a/openmc/volume.py +++ b/openmc/volume.py @@ -12,7 +12,7 @@ from uncertainties import ufloat import openmc import openmc.checkvalue as cv -_VERSION_VOLUME = 1 +_VERSION_VOLUME = 2 class VolumeCalculation(object): @@ -32,6 +32,8 @@ class VolumeCalculation(object): Upper-right coordinates of bounding box used to sample points. If this argument is not supplied, an attempt is made to automatically determine a bounding box. + trigger : float + Threshold for the maxmimum standard deviation of volumes Attributes ---------- @@ -45,6 +47,8 @@ class VolumeCalculation(object): Lower-left coordinates of bounding box used to sample points upper_right : Iterable of float Upper-right coordinates of bounding box used to sample points + trigger : float + Threshold for the maximum standard deviation of volume in the calculation atoms : dict Dictionary mapping unique IDs of domains to a mapping of nuclides to total number of atoms for each nuclide present in the domain. For @@ -57,9 +61,10 @@ class VolumeCalculation(object): """ def __init__(self, domains, samples, lower_left=None, - upper_right=None): + upper_right=None, trigger=None): self._atoms = {} self._volumes = {} + self._trigger = None cv.check_type('domains', domains, Iterable, (openmc.Cell, openmc.Material, openmc.Universe)) @@ -72,6 +77,9 @@ class VolumeCalculation(object): self.ids = [d.id for d in domains] self.samples = samples + + if trigger is not None: + self.trigger = trigger if lower_left is not None: if upper_right is None: @@ -123,6 +131,10 @@ class VolumeCalculation(object): def upper_right(self): return self._upper_right + @property + def trigger(self): + return self._trigger + @property def domain_type(self): return self._domain_type @@ -170,6 +182,12 @@ class VolumeCalculation(object): cv.check_length(name, upper_right, 3) self._upper_right = upper_right + @trigger.setter + def trigger(self, trigger): + name = 'Volume std. dev. trigger' + cv.check_type(name, trigger, Real) + self._trigger = trigger + @volumes.setter def volumes(self, volumes): cv.check_type('volumes', volumes, Mapping) @@ -202,6 +220,10 @@ class VolumeCalculation(object): samples = f.attrs['samples'] lower_left = f.attrs['lower_left'] upper_right = f.attrs['upper_right'] + trigger = f.attrs['trigger'] + + if trigger == -1.0: + trigger = None volumes = {} atoms = {} @@ -232,7 +254,7 @@ class VolumeCalculation(object): domains = [openmc.Universe(uid) for uid in ids] # Instantiate the class and assign results - vol = cls(domains, samples, lower_left, upper_right) + vol = cls(domains, samples, lower_left, upper_right, trigger) vol.volumes = volumes vol.atoms = atoms return vol @@ -277,4 +299,7 @@ class VolumeCalculation(object): ll_elem.text = ' '.join(str(x) for x in self.lower_left) ur_elem = ET.SubElement(element, "upper_right") ur_elem.text = ' '.join(str(x) for x in self.upper_right) + if self.trigger: + trigger_elem = ET.SubElement(element, "trigger") + trigger_elem.text = str(self.trigger) return element diff --git a/src/volume_calc.cpp b/src/volume_calc.cpp index a57305db9..358d8cfd4 100644 --- a/src/volume_calc.cpp +++ b/src/volume_calc.cpp @@ -68,11 +68,11 @@ VolumeCalculation::VolumeCalculation(pugi::xml_node node) fatal_error(msg); } - if (check_for_node(node, "error_trigger")) { - error_trigger_ = std::stod(get_node_value(node, "error_trigger")); - if (error_trigger_ <= 0.0) { + if (check_for_node(node, "trigger")) { + trigger_ = std::stod(get_node_value(node, "trigger")); + if (trigger_ <= 0.0) { std::stringstream msg; - msg << "Invalid error trigger " << error_trigger_ << " provided for a volume calculation."; + msg << "Invalid error threshold " << trigger_ << " provided for a volume calculation."; fatal_error(msg); } } @@ -89,9 +89,11 @@ VolumeCalculation::VolumeCalculation(pugi::xml_node node) std::vector VolumeCalculation::execute() const { + // execute the calculation once std::vector results = _execute(); - if (error_trigger_ <= 0.0) { return results; } + // if no std. dev. threshold is set, return these resuls + if (trigger_ == -1.0) { return results; } size_t offset = n_samples_; double max_err; @@ -102,8 +104,9 @@ std::vector VolumeCalculation::execute() const { for (const auto& result : results) { max_err = std::max(max_err, result.volume[1]); } // exit once we're below our error limit - if (max_err <= error_trigger_) { break; } + if (max_err <= trigger_) { break; } + // perform the calculation std::vector tmp = _execute(offset); offset += n_samples_; @@ -333,6 +336,7 @@ void VolumeCalculation::to_hdf5(const std::string& filename, write_attribute(file_id, "samples", n_samples_); write_attribute(file_id, "lower_left", lower_left_); write_attribute(file_id, "upper_right", upper_right_); + write_attribute(file_id, "trigger", trigger_); if (domain_type_ == FILTER_CELL) { write_attribute(file_id, "domain_type", "cell"); } diff --git a/tests/regression_tests/volume_calc/test.py b/tests/regression_tests/volume_calc/test.py index 8ea4ab04e..2affc4085 100644 --- a/tests/regression_tests/volume_calc/test.py +++ b/tests/regression_tests/volume_calc/test.py @@ -74,4 +74,4 @@ class VolumeTest(PyAPITestHarness): def test_volume_calc(): harness = VolumeTest('') - harness.main() + harness._build_inputs() From 48fab6dcac29a9935a575d26d158503de420379b Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Sat, 5 Oct 2019 10:50:32 -0500 Subject: [PATCH 037/158] Only write threshold to file if used. --- include/openmc/volume_calc.h | 2 +- openmc/volume.py | 46 ++++++++++++++++++------------------ src/volume_calc.cpp | 17 +++++++------ 3 files changed, 34 insertions(+), 31 deletions(-) diff --git a/include/openmc/volume_calc.h b/include/openmc/volume_calc.h index 4e2b2a2a6..33c8cbfea 100644 --- a/include/openmc/volume_calc.h +++ b/include/openmc/volume_calc.h @@ -87,7 +87,7 @@ public: // Data members int domain_type_; //!< Type of domain (cell, material, etc.) size_t n_samples_; //!< Number of samples to use - double trigger_ {-1.0}; //!< Error threshold for domain volumes + double threshold_ {-1.0}; //!< Error threshold for domain volumes Position lower_left_; //!< Lower-left position of bounding box Position upper_right_; //!< Upper-right position of bounding box std::vector domain_ids_; //!< IDs of domains to find volumes of diff --git a/openmc/volume.py b/openmc/volume.py index 189287bef..bcc46d19e 100644 --- a/openmc/volume.py +++ b/openmc/volume.py @@ -12,7 +12,7 @@ from uncertainties import ufloat import openmc import openmc.checkvalue as cv -_VERSION_VOLUME = 2 +_VERSION_VOLUME = 1 class VolumeCalculation(object): @@ -32,7 +32,7 @@ class VolumeCalculation(object): Upper-right coordinates of bounding box used to sample points. If this argument is not supplied, an attempt is made to automatically determine a bounding box. - trigger : float + threshold : float Threshold for the maxmimum standard deviation of volumes Attributes @@ -47,7 +47,7 @@ class VolumeCalculation(object): Lower-left coordinates of bounding box used to sample points upper_right : Iterable of float Upper-right coordinates of bounding box used to sample points - trigger : float + threshold : float Threshold for the maximum standard deviation of volume in the calculation atoms : dict Dictionary mapping unique IDs of domains to a mapping of nuclides to @@ -61,10 +61,10 @@ class VolumeCalculation(object): """ def __init__(self, domains, samples, lower_left=None, - upper_right=None, trigger=None): + upper_right=None, threshold=None): self._atoms = {} self._volumes = {} - self._trigger = None + self._threshold = None cv.check_type('domains', domains, Iterable, (openmc.Cell, openmc.Material, openmc.Universe)) @@ -78,8 +78,8 @@ class VolumeCalculation(object): self.samples = samples - if trigger is not None: - self.trigger = trigger + if threshold is not None: + self.threshold = threshold if lower_left is not None: if upper_right is None: @@ -132,8 +132,8 @@ class VolumeCalculation(object): return self._upper_right @property - def trigger(self): - return self._trigger + def threshold(self): + return self._threshold @property def domain_type(self): @@ -182,11 +182,11 @@ class VolumeCalculation(object): cv.check_length(name, upper_right, 3) self._upper_right = upper_right - @trigger.setter - def trigger(self, trigger): - name = 'Volume std. dev. trigger' - cv.check_type(name, trigger, Real) - self._trigger = trigger + @threshold.setter + def threshold(self, threshold): + name = 'volume std. dev. threshold' + cv.check_type(name, threshold, Real) + self._threshold = threshold @volumes.setter def volumes(self, volumes): @@ -220,11 +220,11 @@ class VolumeCalculation(object): samples = f.attrs['samples'] lower_left = f.attrs['lower_left'] upper_right = f.attrs['upper_right'] - trigger = f.attrs['trigger'] - - if trigger == -1.0: - trigger = None - + try: + threshold = f.attrs['threshold'] + except KeyError: + threshold = None + volumes = {} atoms = {} ids = [] @@ -254,7 +254,7 @@ class VolumeCalculation(object): domains = [openmc.Universe(uid) for uid in ids] # Instantiate the class and assign results - vol = cls(domains, samples, lower_left, upper_right, trigger) + vol = cls(domains, samples, lower_left, upper_right, threshold) vol.volumes = volumes vol.atoms = atoms return vol @@ -299,7 +299,7 @@ class VolumeCalculation(object): ll_elem.text = ' '.join(str(x) for x in self.lower_left) ur_elem = ET.SubElement(element, "upper_right") ur_elem.text = ' '.join(str(x) for x in self.upper_right) - if self.trigger: - trigger_elem = ET.SubElement(element, "trigger") - trigger_elem.text = str(self.trigger) + if self.threshold: + threshold_elem = ET.SubElement(element, "threshold") + threshold_elem.text = str(self.threshold) return element diff --git a/src/volume_calc.cpp b/src/volume_calc.cpp index 358d8cfd4..9b2ef7c51 100644 --- a/src/volume_calc.cpp +++ b/src/volume_calc.cpp @@ -68,11 +68,11 @@ VolumeCalculation::VolumeCalculation(pugi::xml_node node) fatal_error(msg); } - if (check_for_node(node, "trigger")) { - trigger_ = std::stod(get_node_value(node, "trigger")); - if (trigger_ <= 0.0) { + if (check_for_node(node, "threshold")) { + threshold_ = std::stod(get_node_value(node, "threshold")); + if (threshold_ <= 0.0) { std::stringstream msg; - msg << "Invalid error threshold " << trigger_ << " provided for a volume calculation."; + msg << "Invalid error threshold " << threshold_ << " provided for a volume calculation."; fatal_error(msg); } } @@ -93,7 +93,7 @@ std::vector VolumeCalculation::execute() const { std::vector results = _execute(); // if no std. dev. threshold is set, return these resuls - if (trigger_ == -1.0) { return results; } + if (threshold_ == -1.0) { return results; } size_t offset = n_samples_; double max_err; @@ -104,7 +104,7 @@ std::vector VolumeCalculation::execute() const { for (const auto& result : results) { max_err = std::max(max_err, result.volume[1]); } // exit once we're below our error limit - if (max_err <= trigger_) { break; } + if (max_err <= threshold_) { break; } // perform the calculation std::vector tmp = _execute(offset); @@ -336,7 +336,10 @@ void VolumeCalculation::to_hdf5(const std::string& filename, write_attribute(file_id, "samples", n_samples_); write_attribute(file_id, "lower_left", lower_left_); write_attribute(file_id, "upper_right", upper_right_); - write_attribute(file_id, "trigger", trigger_); + if (threshold_ != -1.0) { + write_attribute(file_id, "threshold", threshold_); + } + if (domain_type_ == FILTER_CELL) { write_attribute(file_id, "domain_type", "cell"); } From 0914330f8d773b62f321b6ceb21a218b95247bcb Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Sat, 5 Oct 2019 10:58:11 -0500 Subject: [PATCH 038/158] Updating volume documentation. --- docs/source/io_formats/volume.rst | 1 + docs/source/usersguide/volume.rst | 12 +++++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/docs/source/io_formats/volume.rst b/docs/source/io_formats/volume.rst index 456a06eef..e421de566 100644 --- a/docs/source/io_formats/volume.rst +++ b/docs/source/io_formats/volume.rst @@ -23,6 +23,7 @@ The current version of the volume file format is 1.0. bounding box - **upper_right** (*double[3]*) -- Upper-right coordinates of bounding box + - **threshold** (*double*) -- Threshold used for volume uncertainty **/domain_/** diff --git a/docs/source/usersguide/volume.rst b/docs/source/usersguide/volume.rst index e4bdbf715..f34710232 100644 --- a/docs/source/usersguide/volume.rst +++ b/docs/source/usersguide/volume.rst @@ -37,6 +37,16 @@ arguments are not necessary. For example, Of course, the volumes that you *need* this capability for are often the ones with complex definitions. +A threshold for the uncertainty in volume estimates can be specified using +::attr::`openmc.VolumeCalculation.threshold` :: + + vol_calc.threshold = 1E-05 + +If a threshold is provided, calculations will be performed iteratively using the +number of samples specified on the calculation until all volume estimates have a +standard deviation lower than this value. If no threshold is provided, the +calculation will run the number of samples specified once and return the result. + Once you have one or more :class:`openmc.VolumeCalculation` objects created, you can then assign then to :attr:`Settings.volume_calculations`:: @@ -66,4 +76,4 @@ After the results are loaded, volume estimates will be stored in :attr:`VolumeCalculation.volumes`. There is also a :attr:`VolumeCalculation.atoms_dataframe` attribute that shows stochastic estimates of the number of atoms of each type of nuclide within the specified -domains along with their uncertainties. +domains along with their uncertainties. \ No newline at end of file From 9415bbb71550772c7152836ab1452b635ad5f720 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Sat, 5 Oct 2019 11:02:23 -0500 Subject: [PATCH 039/158] Adding check for valid threshold value in Python API. --- openmc/volume.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/openmc/volume.py b/openmc/volume.py index bcc46d19e..f185620cd 100644 --- a/openmc/volume.py +++ b/openmc/volume.py @@ -186,6 +186,9 @@ class VolumeCalculation(object): def threshold(self, threshold): name = 'volume std. dev. threshold' cv.check_type(name, threshold, Real) + if (threshold <= 0.0): + raise ValueError("Invalid value '{}' (<= 0.0) provided for volume " + "calculation threshold.".format(threshold)) self._threshold = threshold @volumes.setter @@ -224,7 +227,7 @@ class VolumeCalculation(object): threshold = f.attrs['threshold'] except KeyError: threshold = None - + volumes = {} atoms = {} ids = [] From 8d1e8711f564f4f7e97fb79265bf4fbbaa0174ed Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Sat, 5 Oct 2019 12:33:00 -0500 Subject: [PATCH 040/158] Adding volume trigger via different methods. --- include/openmc/volume_calc.h | 8 +++++++ src/volume_calc.cpp | 44 ++++++++++++++++++++++++++++++++---- 2 files changed, 47 insertions(+), 5 deletions(-) diff --git a/include/openmc/volume_calc.h b/include/openmc/volume_calc.h index 33c8cbfea..e2cf1b3ef 100644 --- a/include/openmc/volume_calc.h +++ b/include/openmc/volume_calc.h @@ -12,11 +12,18 @@ namespace openmc { +enum class ThresholdType { + VARIANCE = 0, + STD_DEV = 1, + REL_ERR = 2 +}; + //============================================================================== // Volume calculation class //============================================================================== class VolumeCalculation { + public: // Aliases, types struct Result { @@ -88,6 +95,7 @@ public: int domain_type_; //!< Type of domain (cell, material, etc.) size_t n_samples_; //!< Number of samples to use double threshold_ {-1.0}; //!< Error threshold for domain volumes + ThresholdType threshold_type_; Position lower_left_; //!< Lower-left position of bounding box Position upper_right_; //!< Upper-right position of bounding box std::vector domain_ids_; //!< IDs of domains to find volumes of diff --git a/src/volume_calc.cpp b/src/volume_calc.cpp index 9b2ef7c51..870721f3e 100644 --- a/src/volume_calc.cpp +++ b/src/volume_calc.cpp @@ -75,6 +75,21 @@ VolumeCalculation::VolumeCalculation(pugi::xml_node node) msg << "Invalid error threshold " << threshold_ << " provided for a volume calculation."; fatal_error(msg); } + + pugi::xml_node threshold_node = node.child("threshold"); + std::string tmp = get_node_value(threshold_node, "type"); + if (tmp == "variance") { + threshold_type_ = ThresholdType::VARIANCE; + } else if (tmp == "std_dev") { + threshold_type_ = ThresholdType::STD_DEV; + } else if ( tmp == "rel_err") { + threshold_type_ = ThresholdType::REL_ERR; + } else { + std::stringstream msg; + msg << "Invalid volume calculation trigger type '" << tmp << "' provided."; + fatal_error(msg); + } + } // Ensure there are no duplicates by copying elements to a set and then @@ -96,15 +111,30 @@ std::vector VolumeCalculation::execute() const { if (threshold_ == -1.0) { return results; } size_t offset = n_samples_; - double max_err; + double max_val; while (true) { // check maximum error value for all domains - max_err = -INFTY; - for (const auto& result : results) { max_err = std::max(max_err, result.volume[1]); } + max_val = -INFTY; + for (const auto& result : results) { + double val; + switch (threshold_type_) { + case ThresholdType::STD_DEV: + val = result.volume[1]; + break; + case ThresholdType::REL_ERR: + val = result.volume[1] / result.volume[0]; + break; + case ThresholdType::VARIANCE: + val = result.volume[1] * result.volume[1]; + break; + } + // update max + max_val = std::max(max_val, val); + } // exit once we're below our error limit - if (max_err <= threshold_) { break; } + if (max_val <= threshold_) { break; } // perform the calculation std::vector tmp = _execute(offset); @@ -307,6 +337,10 @@ std::vector VolumeCalculation::_execute(size_t seed_o result.nuclides.push_back(j); result.atoms.push_back(mean); result.uncertainty.push_back(stdev); + } else { + result.nuclides.push_back(j); + result.atoms.push_back(0.0); + result.uncertainty.push_back(INFTY); } } } @@ -339,7 +373,7 @@ void VolumeCalculation::to_hdf5(const std::string& filename, if (threshold_ != -1.0) { write_attribute(file_id, "threshold", threshold_); } - + if (domain_type_ == FILTER_CELL) { write_attribute(file_id, "domain_type", "cell"); } From 85e25d79eafd65a064c3afeea3a77e30e50b0047 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Sat, 5 Oct 2019 13:12:31 -0500 Subject: [PATCH 041/158] Finishing addition of a trigger type. --- include/openmc/volume_calc.h | 2 +- src/volume_calc.cpp | 21 +++++++++++++++++---- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/include/openmc/volume_calc.h b/include/openmc/volume_calc.h index e2cf1b3ef..a7dd75009 100644 --- a/include/openmc/volume_calc.h +++ b/include/openmc/volume_calc.h @@ -95,7 +95,7 @@ public: int domain_type_; //!< Type of domain (cell, material, etc.) size_t n_samples_; //!< Number of samples to use double threshold_ {-1.0}; //!< Error threshold for domain volumes - ThresholdType threshold_type_; + ThresholdType trigger_type_; Position lower_left_; //!< Lower-left position of bounding box Position upper_right_; //!< Upper-right position of bounding box std::vector domain_ids_; //!< IDs of domains to find volumes of diff --git a/src/volume_calc.cpp b/src/volume_calc.cpp index 870721f3e..f352e71f8 100644 --- a/src/volume_calc.cpp +++ b/src/volume_calc.cpp @@ -79,11 +79,11 @@ VolumeCalculation::VolumeCalculation(pugi::xml_node node) pugi::xml_node threshold_node = node.child("threshold"); std::string tmp = get_node_value(threshold_node, "type"); if (tmp == "variance") { - threshold_type_ = ThresholdType::VARIANCE; + trigger_type_ = ThresholdType::VARIANCE; } else if (tmp == "std_dev") { - threshold_type_ = ThresholdType::STD_DEV; + trigger_type_ = ThresholdType::STD_DEV; } else if ( tmp == "rel_err") { - threshold_type_ = ThresholdType::REL_ERR; + trigger_type_ = ThresholdType::REL_ERR; } else { std::stringstream msg; msg << "Invalid volume calculation trigger type '" << tmp << "' provided."; @@ -118,7 +118,7 @@ std::vector VolumeCalculation::execute() const { max_val = -INFTY; for (const auto& result : results) { double val; - switch (threshold_type_) { + switch (trigger_type_) { case ThresholdType::STD_DEV: val = result.volume[1]; break; @@ -372,6 +372,19 @@ void VolumeCalculation::to_hdf5(const std::string& filename, write_attribute(file_id, "upper_right", upper_right_); if (threshold_ != -1.0) { write_attribute(file_id, "threshold", threshold_); + + switch(trigger_type_) { + case ThresholdType::VARIANCE: + write_attribute(file_id, "trigger_type", "variance"); + break; + case ThresholdType::STD_DEV: + write_attribute(file_id, "trigger_type", "std_dev"); + break; + case ThresholdType::REL_ERR: + write_attribute(file_id, "trigger_type", "rel_err"); + break; + } + } if (domain_type_ == FILTER_CELL) { From 8aed7b019abc7666d553b4f508deee2a5fb9cf94 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Sat, 5 Oct 2019 13:12:56 -0500 Subject: [PATCH 042/158] Adding support for trigger type in the Python API. --- openmc/volume.py | 50 ++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 42 insertions(+), 8 deletions(-) diff --git a/openmc/volume.py b/openmc/volume.py index f185620cd..a72f32ab3 100644 --- a/openmc/volume.py +++ b/openmc/volume.py @@ -32,8 +32,7 @@ class VolumeCalculation(object): Upper-right coordinates of bounding box used to sample points. If this argument is not supplied, an attempt is made to automatically determine a bounding box. - threshold : float - Threshold for the maxmimum standard deviation of volumes + Attributes ---------- @@ -58,13 +57,17 @@ class VolumeCalculation(object): in each domain specified. volumes : dict Dictionary mapping unique IDs of domains to estimated volumes in cm^3. + threshold : float + Threshold for the maxmimum standard deviation of volumes + trigger_type : {'variance', 'std_dev', 'rel_err'} + Value type used to halt volume calculation """ - def __init__(self, domains, samples, lower_left=None, - upper_right=None, threshold=None): + def __init__(self, domains, samples, lower_left=None, upper_right=None): self._atoms = {} self._volumes = {} self._threshold = None + self._trigger_type = None cv.check_type('domains', domains, Iterable, (openmc.Cell, openmc.Material, openmc.Universe)) @@ -78,9 +81,6 @@ class VolumeCalculation(object): self.samples = samples - if threshold is not None: - self.threshold = threshold - if lower_left is not None: if upper_right is None: raise ValueError('Both lower-left and upper-right coordinates ' @@ -135,6 +135,10 @@ class VolumeCalculation(object): def threshold(self): return self._threshold + @property + def trigger_type(self): + return self._trigger_type + @property def domain_type(self): return self._domain_type @@ -191,6 +195,12 @@ class VolumeCalculation(object): "calculation threshold.".format(threshold)) self._threshold = threshold + @trigger_type.setter + def trigger_type(self, trigger_type): + cv.check_value('tally trigger type', trigger_type, + ['variance', 'std_dev', 'rel_err']) + self._trigger_type = trigger_type + @volumes.setter def volumes(self, volumes): cv.check_type('volumes', volumes, Mapping) @@ -201,6 +211,19 @@ class VolumeCalculation(object): cv.check_type('atoms', atoms, Mapping) self._atoms = atoms + def set_trigger(self, threshold, trigger_type): + """Set a trigger on the voulme calculation + + Parameters + ---------- + threshold : float + Threshold for the maxmimum standard deviation of volumes + trigger_type : {'variance', 'std_dev', 'rel_err'} + Value type used to halt volume calculation + """ + self.trigger_type = trigger_type + self.threshold = threshold + @classmethod def from_hdf5(cls, filename): """Load stochastic volume calculation results from HDF5 file. @@ -223,11 +246,17 @@ class VolumeCalculation(object): samples = f.attrs['samples'] lower_left = f.attrs['lower_left'] upper_right = f.attrs['upper_right'] + try: threshold = f.attrs['threshold'] except KeyError: threshold = None + try: + trigger_type = f.attrs['trigger_type'].decode() + except KeyError: + trigger_type = None + volumes = {} atoms = {} ids = [] @@ -257,7 +286,11 @@ class VolumeCalculation(object): domains = [openmc.Universe(uid) for uid in ids] # Instantiate the class and assign results - vol = cls(domains, samples, lower_left, upper_right, threshold) + vol = cls(domains, samples, lower_left, upper_right) + + if threshold is not None: + vol.set_trigger(threshold, trigger_type) + vol.volumes = volumes vol.atoms = atoms return vol @@ -305,4 +338,5 @@ class VolumeCalculation(object): if self.threshold: threshold_elem = ET.SubElement(element, "threshold") threshold_elem.text = str(self.threshold) + threshold_elem.set("type", self.trigger_type) return element From 1d27972d5040ad869818492f1e3efbaafe83800e Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Sat, 5 Oct 2019 13:25:25 -0500 Subject: [PATCH 043/158] Updating volume documentation to include info about volume trigger types. --- docs/source/io_formats/volume.rst | 1 + docs/source/usersguide/volume.rst | 12 ++++++------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/docs/source/io_formats/volume.rst b/docs/source/io_formats/volume.rst index e421de566..c79255a1c 100644 --- a/docs/source/io_formats/volume.rst +++ b/docs/source/io_formats/volume.rst @@ -24,6 +24,7 @@ The current version of the volume file format is 1.0. - **upper_right** (*double[3]*) -- Upper-right coordinates of bounding box - **threshold** (*double*) -- Threshold used for volume uncertainty + - **trigger_type** (*char[]*) -- Trigger type used for volume uncertainty **/domain_/** diff --git a/docs/source/usersguide/volume.rst b/docs/source/usersguide/volume.rst index f34710232..d35386b38 100644 --- a/docs/source/usersguide/volume.rst +++ b/docs/source/usersguide/volume.rst @@ -37,15 +37,15 @@ arguments are not necessary. For example, Of course, the volumes that you *need* this capability for are often the ones with complex definitions. -A threshold for the uncertainty in volume estimates can be specified using -::attr::`openmc.VolumeCalculation.threshold` :: +A threshold can be applied for the calculation's variance, standard deviation, +or relative error of volume estimates using ::attr::`openmc.VolumeCalculation.set_trigger`:: - vol_calc.threshold = 1E-05 + vol_calc.set_trigger(1e-05, 'std_dev') If a threshold is provided, calculations will be performed iteratively using the -number of samples specified on the calculation until all volume estimates have a -standard deviation lower than this value. If no threshold is provided, the -calculation will run the number of samples specified once and return the result. +number of samples specified on the calculation until all volume uncertainties are below +the threshold value. If no threshold is provided, the calculation will run the number of +samples specified once and return the result. Once you have one or more :class:`openmc.VolumeCalculation` objects created, you can then assign then to :attr:`Settings.volume_calculations`:: From f3fa1f25782fa1ebc8c8427f7f950be4abf053b7 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Mon, 7 Oct 2019 00:08:47 -0500 Subject: [PATCH 044/158] Fixing issue with INF error values. Adding test case. --- openmc/volume.py | 6 +-- src/volume_calc.cpp | 22 ++++---- .../volume_calc/inputs_true.dat | 8 +++ .../volume_calc/results_true.dat | 54 +++++++++++++++---- tests/regression_tests/volume_calc/test.py | 12 ++++- 5 files changed, 76 insertions(+), 26 deletions(-) diff --git a/openmc/volume.py b/openmc/volume.py index a72f32ab3..3996ce9dd 100644 --- a/openmc/volume.py +++ b/openmc/volume.py @@ -336,7 +336,7 @@ class VolumeCalculation(object): ur_elem = ET.SubElement(element, "upper_right") ur_elem.text = ' '.join(str(x) for x in self.upper_right) if self.threshold: - threshold_elem = ET.SubElement(element, "threshold") - threshold_elem.text = str(self.threshold) - threshold_elem.set("type", self.trigger_type) + trigger_elem = ET.SubElement(element, "threshold") + trigger_elem.set("type", self.trigger_type) + trigger_elem.set("threshold", str(self.threshold)) return element diff --git a/src/volume_calc.cpp b/src/volume_calc.cpp index f352e71f8..f65cb89ed 100644 --- a/src/volume_calc.cpp +++ b/src/volume_calc.cpp @@ -69,19 +69,20 @@ VolumeCalculation::VolumeCalculation(pugi::xml_node node) } if (check_for_node(node, "threshold")) { - threshold_ = std::stod(get_node_value(node, "threshold")); + pugi::xml_node threshold_node = node.child("threshold"); + + threshold_ = std::stod(get_node_value(threshold_node, "threshold")); if (threshold_ <= 0.0) { std::stringstream msg; msg << "Invalid error threshold " << threshold_ << " provided for a volume calculation."; fatal_error(msg); } - pugi::xml_node threshold_node = node.child("threshold"); std::string tmp = get_node_value(threshold_node, "type"); if (tmp == "variance") { trigger_type_ = ThresholdType::VARIANCE; } else if (tmp == "std_dev") { - trigger_type_ = ThresholdType::STD_DEV; + trigger_type_ = ThresholdType::STD_DEV; } else if ( tmp == "rel_err") { trigger_type_ = ThresholdType::REL_ERR; } else { @@ -116,11 +117,11 @@ std::vector VolumeCalculation::execute() const { while (true) { // check maximum error value for all domains max_val = -INFTY; - for (const auto& result : results) { + for (const auto& result : results) { double val; switch (trigger_type_) { case ThresholdType::STD_DEV: - val = result.volume[1]; + val = result.volume[1]; break; case ThresholdType::REL_ERR: val = result.volume[1] / result.volume[0]; @@ -129,8 +130,9 @@ std::vector VolumeCalculation::execute() const { val = result.volume[1] * result.volume[1]; break; } - // update max - max_val = std::max(max_val, val); + // update max if entry is valid + if (val > 0.0) { max_val = std::max(max_val, val); } + } // exit once we're below our error limit @@ -306,7 +308,7 @@ std::vector VolumeCalculation::_execute(size_t seed_o for (int j = 0; j < master_indices[i_domain].size(); ++j) { total_hits += master_hits[i_domain][j]; double f = static_cast(master_hits[i_domain][j]) / n_samples_; - double var_f = f*(1.0 - f)/n_samples_; + double var_f = f*(1.0 - f) / n_samples_; int i_material = master_indices[i_domain][j]; if (i_material == MATERIAL_VOID) continue; @@ -340,7 +342,7 @@ std::vector VolumeCalculation::_execute(size_t seed_o } else { result.nuclides.push_back(j); result.atoms.push_back(0.0); - result.uncertainty.push_back(INFTY); + result.uncertainty.push_back(0.0); } } } @@ -384,7 +386,7 @@ void VolumeCalculation::to_hdf5(const std::string& filename, write_attribute(file_id, "trigger_type", "rel_err"); break; } - + } if (domain_type_ == FILTER_CELL) { diff --git a/tests/regression_tests/volume_calc/inputs_true.dat b/tests/regression_tests/volume_calc/inputs_true.dat index 607921af2..1af345405 100644 --- a/tests/regression_tests/volume_calc/inputs_true.dat +++ b/tests/regression_tests/volume_calc/inputs_true.dat @@ -48,4 +48,12 @@ -1.0 -1.0 -6.0 1.0 1.0 6.0 + + cell + 1 2 3 + 100 + -1.0 -1.0 -6.0 + 1.0 1.0 6.0 + + diff --git a/tests/regression_tests/volume_calc/results_true.dat b/tests/regression_tests/volume_calc/results_true.dat index 466139cd6..4fe3b4b6e 100644 --- a/tests/regression_tests/volume_calc/results_true.dat +++ b/tests/regression_tests/volume_calc/results_true.dat @@ -2,15 +2,22 @@ Volume calculation 0 Domain 1: 31.47+/-0.07 cm^3 Domain 2: 2.093+/-0.031 cm^3 Domain 3: 2.049+/-0.031 cm^3 - Cell Nuclide Atoms -0 1 U235 (3.482+/-0.008)e+23 -1 1 Mo99 (3.482+/-0.008)e+22 -2 2 H1 (1.400+/-0.021)e+23 -3 2 O16 (7.00+/-0.10)e+22 -4 2 B10 (7.00+/-0.10)e+18 -5 3 H1 (1.370+/-0.021)e+23 -6 3 O16 (6.85+/-0.10)e+22 -7 3 B10 (6.85+/-0.10)e+18 + Cell Nuclide Atoms +0 1 H1 0.0+/-0 +1 1 O16 0.0+/-0 +2 1 B10 0.0+/-0 +3 1 U235 (3.482+/-0.008)e+23 +4 1 Mo99 (3.482+/-0.008)e+22 +5 2 H1 (1.400+/-0.021)e+23 +6 2 O16 (7.00+/-0.10)e+22 +7 2 B10 (7.00+/-0.10)e+18 +8 2 U235 0.0+/-0 +9 2 Mo99 0.0+/-0 +10 3 H1 (1.370+/-0.021)e+23 +11 3 O16 (6.85+/-0.10)e+22 +12 3 B10 (6.85+/-0.10)e+18 +13 3 U235 0.0+/-0 +14 3 Mo99 0.0+/-0 Volume calculation 1 Domain 1: 4.14+/-0.04 cm^3 Domain 2: 31.47+/-0.07 cm^3 @@ -18,8 +25,13 @@ Domain 2: 31.47+/-0.07 cm^3 0 1 H1 (2.770+/-0.029)e+23 1 1 O16 (1.385+/-0.014)e+23 2 1 B10 (1.385+/-0.014)e+19 -3 2 U235 (3.482+/-0.008)e+23 -4 2 Mo99 (3.482+/-0.008)e+22 +3 1 U235 0.0+/-0 +4 1 Mo99 0.0+/-0 +5 2 H1 0.0+/-0 +6 2 O16 0.0+/-0 +7 2 B10 0.0+/-0 +8 2 U235 (3.482+/-0.008)e+23 +9 2 Mo99 (3.482+/-0.008)e+22 Volume calculation 2 Domain 0: 35.61+/-0.07 cm^3 Universe Nuclide Atoms @@ -28,3 +40,23 @@ Domain 0: 35.61+/-0.07 cm^3 2 0 B10 (1.385+/-0.014)e+19 3 0 U235 (3.482+/-0.008)e+23 4 0 Mo99 (3.482+/-0.008)e+22 +Volume calculation 3 +Domain 1: 31.35476+/-0.00010 cm^3 +Domain 2: 2.09147+/-0.00005 cm^3 +Domain 3: 2.110402+/-0.000033 cm^3 + Cell Nuclide Atoms +0 1 H1 0.0+/-0 +1 1 O16 0.0+/-0 +2 1 B10 0.0+/-0 +3 1 U235 (3.474110+/-0.000011)e+23 +4 1 Mo99 (3.474110+/-0.000011)e+22 +5 2 H1 (1.398833+/-0.000031)e+23 +6 2 O16 (6.99416+/-0.00015)e+22 +7 2 B10 (6.99416+/-0.00015)e+18 +8 2 U235 0.0+/-0 +9 2 Mo99 0.0+/-0 +10 3 H1 (1.401947+/-0.000022)e+23 +11 3 O16 (7.00974+/-0.00011)e+22 +12 3 B10 (7.00974+/-0.00011)e+18 +13 3 U235 0.0+/-0 +14 3 Mo99 0.0+/-0 diff --git a/tests/regression_tests/volume_calc/test.py b/tests/regression_tests/volume_calc/test.py index 2affc4085..6bcedd397 100644 --- a/tests/regression_tests/volume_calc/test.py +++ b/tests/regression_tests/volume_calc/test.py @@ -45,9 +45,12 @@ class VolumeTest(PyAPITestHarness): vol_calcs = [ openmc.VolumeCalculation(list(root.cells.values()), 100000), openmc.VolumeCalculation([water, fuel], 100000, ll, ur), - openmc.VolumeCalculation([root], 100000, ll, ur) + openmc.VolumeCalculation([root], 100000, ll, ur), + openmc.VolumeCalculation(list(root.cells.values()), 100) ] + vol_calcs[-1].set_trigger(1e-04, 'std_dev') + # Define settings settings = openmc.Settings() settings.run_mode = 'volume' @@ -62,6 +65,11 @@ class VolumeTest(PyAPITestHarness): # Read volume calculation results volume_calc = openmc.VolumeCalculation.from_hdf5(filename) + if volume_calc.samples == 100: + assert(volume_calc.trigger_type == 'std_dev') + assert(volume_calc.threshold == 1e-04) + + # Write cell volumes and total # of atoms for each nuclide for uid, volume in sorted(volume_calc.volumes.items()): outstr += 'Domain {}: {} cm^3\n'.format(uid, volume) @@ -74,4 +82,4 @@ class VolumeTest(PyAPITestHarness): def test_volume_calc(): harness = VolumeTest('') - harness._build_inputs() + harness.main() From cc6822f171e9963f91a6adeb7d3fabcbbe363f46 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Mon, 7 Oct 2019 00:11:51 -0500 Subject: [PATCH 045/158] Pulling in C++ side changes for counter caching. --- include/openmc/geometry_aux.h | 70 +++++++++++++++++++ src/finalize.cpp | 4 ++ src/geometry_aux.cpp | 126 +++++++++++++++++++++++++++++++--- 3 files changed, 189 insertions(+), 11 deletions(-) diff --git a/include/openmc/geometry_aux.h b/include/openmc/geometry_aux.h index ffcdcf885..557d82193 100644 --- a/include/openmc/geometry_aux.h +++ b/include/openmc/geometry_aux.h @@ -7,8 +7,78 @@ #include #include #include +#include namespace openmc { + struct CellCountStorage { + private: + CellCountStorage() {} + CellCountStorage(CellCountStorage& c) {} + CellCountStorage(const CellCountStorage& c) {} + + static CellCountStorage* instance_; + + std::map> counts; + + public: + + static CellCountStorage* instance() { + if (instance_ == nullptr) + instance_ = new CellCountStorage; + + return instance_; + } + + + + void clear(); + + void set_cell_count_for_univ(int32_t univ, int32_t cell, int count); + + void increment_count_for_univ(int32_t univ, int32_t cell); + + bool has_count(int32_t univ, int32_t cell); + + bool has_count(int32_t univ); + + void absorb_b_into_a(int32_t a, int32_t b); + + auto get_count(int32_t univ); + }; + + struct LevelCountStorage { + private: + LevelCountStorage() {} + LevelCountStorage(LevelCountStorage& c) {} + LevelCountStorage(const LevelCountStorage& c) {} + + static LevelCountStorage* instance_; + + std::map counts; + + public: + + static LevelCountStorage* instance() { + if (instance_ == nullptr) + instance_ = new LevelCountStorage; + + return instance_; + } + + void clear(); + + void set_cell_count_for_univ(int32_t univ, int count); + + void increment_count_for_univ(int32_t univ); + + bool has_count(int32_t univ); + + void absorb_b_into_a(int32_t a, int32_t b); + + void set_count(int32_t univ, int count); + + int get_count(int32_t univ); + }; void read_geometry_xml(); diff --git a/src/finalize.cpp b/src/finalize.cpp index 3de20d6d0..f2cbc973c 100644 --- a/src/finalize.cpp +++ b/src/finalize.cpp @@ -135,6 +135,10 @@ int openmc_finalize() int openmc_reset() { + + CellCountStorage::instance()->clear(); + LevelCountStorage::instance()->clear(); + for (auto& t : model::tallies) { t->reset(); } diff --git a/src/geometry_aux.cpp b/src/geometry_aux.cpp index d195a9de3..662b6790d 100644 --- a/src/geometry_aux.cpp +++ b/src/geometry_aux.cpp @@ -60,6 +60,91 @@ void read_geometry_xml() model::root_universe = find_root_universe(); } +void CellCountStorage::clear() { + if (instance_ != nullptr) { + delete instance_; + instance_ = nullptr; + } +} + +void CellCountStorage::set_cell_count_for_univ(int32_t univ, int32_t cell, int count) { + counts[univ][cell] = count; +} + + void CellCountStorage::increment_count_for_univ(int32_t univ, int32_t cell) { + if (has_count(univ,cell)) { + counts[univ][cell] += 1; + } else { + counts[univ][cell] = 1; + } + } + +bool CellCountStorage::has_count(int32_t univ, int32_t cell) { + return counts.count(univ) && counts[univ].count(cell); +} + +bool CellCountStorage::has_count(int32_t univ) { + return counts.count(univ); +} + +void CellCountStorage::absorb_b_into_a(int32_t a, int32_t b) { + std::map b_map = counts[b]; + + for (auto it : b_map) { + if (has_count(a, it.first)) { + counts[a][it.first] += it.second; + } else { + counts[a][it.first] = it.second; + } + } +} + +auto CellCountStorage::get_count(int32_t univ) { + return counts[univ]; +} + +void LevelCountStorage::clear() { + if (instance_ != nullptr) { + delete instance_; + instance_ = nullptr; + } +} + +void LevelCountStorage::set_cell_count_for_univ(int32_t univ, int count) { + counts[univ] = count; +} + +void LevelCountStorage::increment_count_for_univ(int32_t univ) { + if (has_count(univ)) { + counts[univ] += 1; + } else { + counts[univ] = 1; + } +} + +bool LevelCountStorage::has_count(int32_t univ) { + return counts.count(univ); +} + +void LevelCountStorage::absorb_b_into_a(int32_t a, int32_t b) { + if (has_count(a)) { + counts[a] += counts[b]; + } else { + counts[a] = counts[b]; + } +} + +void LevelCountStorage::set_count(int32_t univ, int count) { + counts[univ] = count; +} + +int LevelCountStorage::get_count(int32_t univ) { + return counts[univ]; +} + +CellCountStorage* CellCountStorage::instance_ = nullptr; +LevelCountStorage* LevelCountStorage::instance_ = nullptr; + //============================================================================== void @@ -395,19 +480,31 @@ prepare_distribcell() void count_cell_instances(int32_t univ_indx) { - for (int32_t cell_indx : model::universes[univ_indx]->cells_) { - Cell& c = *model::cells[cell_indx]; - ++c.n_instances_; + CellCountStorage* counter = CellCountStorage::instance(); - if (c.type_ == FILL_UNIVERSE) { - // This cell contains another universe. Recurse into that universe. - count_cell_instances(c.fill_); + if (counter->has_count(univ_indx)) { + std::map univ_counts = counter->get_count(univ_indx); + for(auto it : univ_counts) { + Cell& c = *model::cells[it.first]; + c.n_instances_ += it.second; + } + } else { + for (int32_t cell_indx : model::universes[univ_indx]->cells_) { + Cell& c = *model::cells[cell_indx]; + ++c.n_instances_; + counter->increment_count_for_univ(univ_indx, cell_indx); - } else if (c.type_ == FILL_LATTICE) { - // This cell contains a lattice. Recurse into the lattice universes. - Lattice& lat = *model::lattices[c.fill_]; - for (auto it = lat.begin(); it != lat.end(); ++it) { - count_cell_instances(*it); + if (c.type_ == FILL_UNIVERSE) { + // This cell contains another universe. Recurse into that universe. + count_cell_instances(c.fill_); + counter->absorb_b_into_a(univ_indx, c.fill_); + } else if (c.type_ == FILL_LATTICE) { + // This cell contains a lattice. Recurse into the lattice universes. + Lattice& lat = *model::lattices[c.fill_]; + for (auto it = lat.begin(); it != lat.end(); ++it) { + count_cell_instances(*it); + counter->absorb_b_into_a(univ_indx, *it); + } } } } @@ -529,6 +626,12 @@ distribcell_path(int32_t target_cell, int32_t map, int32_t target_offset) int maximum_levels(int32_t univ) { + LevelCountStorage* counter = LevelCountStorage::instance(); + + if (counter->has_count(univ)) { + return counter->get_count(univ); + } + int levels_below {0}; for (int32_t cell_indx : model::universes[univ]->cells_) { @@ -546,6 +649,7 @@ maximum_levels(int32_t univ) } ++levels_below; + counter->set_count(univ, levels_below); return levels_below; } From 1c1fca3d708db4d131806ccc79a00952d8c5c350 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 7 Oct 2019 07:40:56 -0500 Subject: [PATCH 046/158] Respond to @drewejohnson comments on #1371 --- docs/source/methods/cross_sections.rst | 2 +- openmc/deplete/cram.py | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/source/methods/cross_sections.rst b/docs/source/methods/cross_sections.rst index 70d80a537..c360805be 100644 --- a/docs/source/methods/cross_sections.rst +++ b/docs/source/methods/cross_sections.rst @@ -73,7 +73,7 @@ Windowed Multipole Representation --------------------------------- In addition to the usual pointwise representation of cross sections, OpenMC -offers support for an data format called windowed multipole (WMP). This data +offers support for a data format called windowed multipole (WMP). This data format requires less memory than pointwise cross sections, and it allows on-the-fly Doppler broadening to arbitrary temperature. diff --git a/openmc/deplete/cram.py b/openmc/deplete/cram.py index c684b3394..7dad820a9 100644 --- a/openmc/deplete/cram.py +++ b/openmc/deplete/cram.py @@ -92,7 +92,9 @@ class IPFCramSolver(DepSystemSolver): Provides a :meth:`__call__` that utilizes an incomplete partial factorization (IPF) for the Chebyshev Rational Approximation - Method (CRAM), as described in the following paper: M. Pusa, "`Higher-Order Chebyshev Rational Approximation Method and Application to Burnup Equations `_," Nucl. Sci. Eng., 182:3, 297-318. + Method (CRAM), as described in the following paper: M. Pusa, "`Higher-Order + Chebyshev Rational Approximation Method and Application to Burnup Equations + `_," Nucl. Sci. Eng., 182:3, 297-318. Parameters ---------- From e07fe0632319e40f4e9ca0f56402468b0b2070af Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Fri, 4 Oct 2019 14:27:55 -0500 Subject: [PATCH 047/158] Remove -dev tag from version number. Small updates to release notes --- docs/source/conf.py | 2 +- docs/source/releasenotes/0.11.0.rst | 9 ++++----- include/openmc/constants.h | 2 +- openmc/__init__.py | 2 +- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index f46b11334..f54a8df0e 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -81,7 +81,7 @@ copyright = '2011-2019, Massachusetts Institute of Technology and OpenMC contrib # The short X.Y version. version = "0.11" # The full version, including alpha/beta/rc tags. -release = "0.11.0-dev" +release = "0.11.0" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/docs/source/releasenotes/0.11.0.rst b/docs/source/releasenotes/0.11.0.rst index ba9a35d1a..221d57658 100644 --- a/docs/source/releasenotes/0.11.0.rst +++ b/docs/source/releasenotes/0.11.0.rst @@ -2,11 +2,6 @@ What's New in 0.11.0 ==================== -.. note:: - These release notes are for a future release of OpenMC and are still subject - to change. The new features and bug fixes documented here reflect the - current status of the ``develop`` branch of OpenMC. - .. currentmodule:: openmc ------- @@ -90,6 +85,7 @@ Python API Changes Bug Fixes --------- +- `Rotate azimuthal distributions correctly for source sampling `_ - `Fix reading ASCII ACE tables in Python 3 `_ - `Fix bug for distributed temperatures `_ - `Fix bug for distance to boundary in complex cells `_ @@ -108,6 +104,7 @@ This release contains new contributions from the following people: - `Brody Bassett `_ - `Will Boyd `_ - `Andrew Davis `_ +- `Iurii Drobyshev `_ - `Guillaume Giudicelli `_ - `Brittany Grayson `_ - `Zhuoran Han `_ @@ -125,6 +122,7 @@ This release contains new contributions from the following people: - `Isaac Meyer `_ - `April Novak `_ - `Adam Nelson `_ +- `Gavin Ridley `_ - `Jose Salcedo Perez `_ - `Paul Romano `_ - `Sam Shaner `_ @@ -132,3 +130,4 @@ This release contains new contributions from the following people: - `Patrick Shriwise `_ - `John Tramm `_ - `Jiankai Yu `_ +- `Xiaokang Zhang `_ diff --git a/include/openmc/constants.h b/include/openmc/constants.h index 51df59acc..046a7abef 100644 --- a/include/openmc/constants.h +++ b/include/openmc/constants.h @@ -22,7 +22,7 @@ using double_4dvec = std::vector>>>; constexpr int VERSION_MAJOR {0}; constexpr int VERSION_MINOR {11}; constexpr int VERSION_RELEASE {0}; -constexpr bool VERSION_DEV {true}; +constexpr bool VERSION_DEV {false}; constexpr std::array VERSION {VERSION_MAJOR, VERSION_MINOR, VERSION_RELEASE}; // HDF5 data format diff --git a/openmc/__init__.py b/openmc/__init__.py index 1195db725..f1703dfea 100644 --- a/openmc/__init__.py +++ b/openmc/__init__.py @@ -34,4 +34,4 @@ from . import examples # Import a few convencience functions that used to be here from openmc.model import rectangular_prism, hexagonal_prism -__version__ = '0.11.0-dev' +__version__ = '0.11.0' From a85438b8253da4f8b629162eb7fc98acb2e8ad79 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Mon, 7 Oct 2019 01:04:37 -0500 Subject: [PATCH 048/158] Updating DAGMC legacy test. --- tests/regression_tests/dagmc/legacy/test.py | 82 +++++++++++---------- 1 file changed, 44 insertions(+), 38 deletions(-) diff --git a/tests/regression_tests/dagmc/legacy/test.py b/tests/regression_tests/dagmc/legacy/test.py index 963e73226..1551256f9 100644 --- a/tests/regression_tests/dagmc/legacy/test.py +++ b/tests/regression_tests/dagmc/legacy/test.py @@ -8,42 +8,48 @@ pytestmark = pytest.mark.skipif( not openmc.lib._dagmc_enabled(), reason="DAGMC CAD geometry is not enabled.") +class DAGMCLegacyTest(PyAPITestHarness): + + def _build_inputs(self): + model = openmc.model.Model() + + # settings + model.settings.batches = 5 + model.settings.inactive = 0 + model.settings.particles = 100 + + source_box = openmc.stats.Box([-4, -4, -4], + [ 4, 4, 4]) + source = openmc.Source(space=source_box) + + model.settings.source = source + + model.settings.dagmc = True + + # tally + tally = openmc.Tally() + tally.scores = ['total'] + tally.filters = [openmc.CellFilter(1)] + model.tallies = [tally] + + # materials + u235 = openmc.Material(name="fuel") + u235.add_nuclide('U235', 1.0, 'ao') + u235.set_density('g/cc', 11) + u235.id = 40 + + water = openmc.Material(name="water") + water.add_nuclide('H1', 2.0, 'ao') + water.add_nuclide('O16', 1.0, 'ao') + water.set_density('g/cc', 1.0) + water.add_s_alpha_beta('c_H_in_H2O') + water.id = 41 + + mats = openmc.Materials([u235, water]) + model.materials = mats + + model.export_to_xml() + def test_dagmc(): - model = openmc.model.Model() - - # settings - model.settings.batches = 5 - model.settings.inactive = 0 - model.settings.particles = 100 - - source_box = openmc.stats.Box([-4, -4, -4], - [ 4, 4, 4]) - source = openmc.Source(space=source_box) - - model.settings.source = source - - model.settings.dagmc = True - - # tally - tally = openmc.Tally() - tally.scores = ['total'] - tally.filters = [openmc.CellFilter(1)] - model.tallies = [tally] - - # materials - u235 = openmc.Material(name="fuel") - u235.add_nuclide('U235', 1.0, 'ao') - u235.set_density('g/cc', 11) - u235.id = 40 - - water = openmc.Material(name="water") - water.add_nuclide('H1', 2.0, 'ao') - water.add_nuclide('O16', 1.0, 'ao') - water.set_density('g/cc', 1.0) - water.add_s_alpha_beta('c_H_in_H2O') - water.id = 41 - - mats = openmc.Materials([u235, water]) - model.materials = mats - - model.export_to_xml() + harness = DAGMCLegacyTest('statepoint.5.h5') + harness.main() From 6e9a78c431e98b048f63bf7061b8c8b1d6907716 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Mon, 7 Oct 2019 18:10:05 -0500 Subject: [PATCH 049/158] Updating check for graveyard and other void volumes. --- src/dagmc.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/dagmc.cpp b/src/dagmc.cpp index 04d4f08c1..9d14c1b86 100644 --- a/src/dagmc.cpp +++ b/src/dagmc.cpp @@ -268,14 +268,12 @@ void load_dagmc_geometry() std::string cmp_str = mat_value; to_lower(cmp_str); - if (cmp_str.find("graveyard") != std::string::npos) { + if (cmp_str == "graveyard") { graveyard = vol_handle; } // material void checks - if (cmp_str.find("void") != std::string::npos || - cmp_str.find("vacuum") != std::string::npos || - cmp_str.find("graveyard") != std::string::npos) { + if (cmp_str == "void" || cmp_str == "vacuum" || cmp_str == "graveyard") { c->material_.push_back(MATERIAL_VOID); } else { if (using_uwuw) { From ec59d02300ed1426e16818c55db6a3cf25c5e14f Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Mon, 7 Oct 2019 23:21:42 -0500 Subject: [PATCH 050/158] Updating test to add check for 'void' in material name. --- tests/regression_tests/dagmc/legacy/dagmc.h5m | Bin 1233364 -> 1233364 bytes .../dagmc/legacy/inputs_true.dat | 2 +- tests/regression_tests/dagmc/legacy/test.py | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/regression_tests/dagmc/legacy/dagmc.h5m b/tests/regression_tests/dagmc/legacy/dagmc.h5m index fbbe9a34a8c01b245375acaffc5e3f2f33fd60aa..bd50a9691464941dec3526cb67f992138ba0a3f3 100644 GIT binary patch delta 487 zcmcbz*!#+2?+tHcm}~gvOnxu(P{GhZ-@sho(2|J(0yvd3#<)utE17{(=SWJ3<6DzjuN%{yR?>$z2`UOy9?F*MebkDCnJb6{Q7g*2w zx<#93RxpDlHqWnxDqUaql?^OCzxK%F>^4s@+rDt&=7{zy5T*LPFjMd3#<)utE17{(=SWJ3<6DzjuN%{yR?>$z2`UOy9?F*MebkDCnJb6{Q7g*2w zx<#93RxpDlHqWnxDqUaql?^OCzxK%F>^4s@+rDt&=7{zy5T*LPFjM;$MlkmLJ0ugJ-{&l diff --git a/tests/regression_tests/dagmc/legacy/inputs_true.dat b/tests/regression_tests/dagmc/legacy/inputs_true.dat index 8ca49c324..769a3384c 100644 --- a/tests/regression_tests/dagmc/legacy/inputs_true.dat +++ b/tests/regression_tests/dagmc/legacy/inputs_true.dat @@ -1,6 +1,6 @@ - + diff --git a/tests/regression_tests/dagmc/legacy/test.py b/tests/regression_tests/dagmc/legacy/test.py index 1551256f9..624a7f97b 100644 --- a/tests/regression_tests/dagmc/legacy/test.py +++ b/tests/regression_tests/dagmc/legacy/test.py @@ -33,7 +33,7 @@ class DAGMCLegacyTest(PyAPITestHarness): model.tallies = [tally] # materials - u235 = openmc.Material(name="fuel") + u235 = openmc.Material(name="no-void fuel") u235.add_nuclide('U235', 1.0, 'ao') u235.set_density('g/cc', 11) u235.id = 40 From 51ea427b25214a31033bad675069ee00f3e9d20c Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Tue, 8 Oct 2019 09:44:24 -0500 Subject: [PATCH 051/158] Moved trigger logic into main func. --- include/openmc/volume_calc.h | 9 +- src/volume_calc.cpp | 329 +++++++++++++++++++---------------- 2 files changed, 186 insertions(+), 152 deletions(-) diff --git a/include/openmc/volume_calc.h b/include/openmc/volume_calc.h index a7dd75009..982e6a9e7 100644 --- a/include/openmc/volume_calc.h +++ b/include/openmc/volume_calc.h @@ -13,9 +13,10 @@ namespace openmc { enum class ThresholdType { - VARIANCE = 0, - STD_DEV = 1, - REL_ERR = 2 + NONE = 0, + VARIANCE = 1, + STD_DEV = 2, + REL_ERR = 3 }; //============================================================================== @@ -115,7 +116,7 @@ private: // //! \param[in] seed_offset Seed offset used for independent calculations //! \return Vector of results for each user-specified domain - std::vector _execute(size_t seed_offset = 0) const; + std::vector _execute() const; }; diff --git a/src/volume_calc.cpp b/src/volume_calc.cpp index f65cb89ed..f2cb7a7d1 100644 --- a/src/volume_calc.cpp +++ b/src/volume_calc.cpp @@ -107,6 +107,7 @@ std::vector VolumeCalculation::execute() const { // execute the calculation once std::vector results = _execute(); + return results; // if no std. dev. threshold is set, return these resuls if (threshold_ == -1.0) { return results; } @@ -139,7 +140,7 @@ std::vector VolumeCalculation::execute() const { if (max_val <= threshold_) { break; } // perform the calculation - std::vector tmp = _execute(offset); + std::vector tmp = _execute(); offset += n_samples_; // update current results @@ -149,12 +150,13 @@ std::vector VolumeCalculation::execute() const { return results; } -std::vector VolumeCalculation::_execute(size_t seed_offset) const +std::vector VolumeCalculation::_execute() const { // Shared data that is collected from all threads int n = domain_ids_.size(); std::vector> master_indices(n); // List of material indices for each domain std::vector> master_hits(n); // Number of hits for each material in each domain + int iterations = 0; // Divide work over MPI processes size_t min_samples = n_samples_ / mpi::n_procs; @@ -168,187 +170,218 @@ std::vector VolumeCalculation::_execute(size_t seed_o i_end = i_start + min_samples; } - #pragma omp parallel - { - // Variables that are private to each thread - std::vector> indices(n); - std::vector> hits(n); - Particle p; + while (true) { + #pragma omp parallel + { + // Variables that are private to each thread + std::vector> indices(n); + std::vector> hits(n); + Particle p; - prn_set_stream(STREAM_VOLUME); + prn_set_stream(STREAM_VOLUME); - // Sample locations and count hits - #pragma omp for - for (size_t i = i_start; i < i_end; i++) { - set_particle_seed(seed_offset + i); + // Sample locations and count hits + #pragma omp for + for (size_t i = i_start; i < i_end; i++) { + set_particle_seed(iterations * n_samples_ + i); - p.n_coord_ = 1; - Position xi {prn(), prn(), prn()}; - p.r() = lower_left_ + xi*(upper_right_ - lower_left_); - p.u() = {0.5, 0.5, 0.5}; + p.n_coord_ = 1; + Position xi {prn(), prn(), prn()}; + p.r() = lower_left_ + xi*(upper_right_ - lower_left_); + p.u() = {0.5, 0.5, 0.5}; - // If this location is not in the geometry at all, move on to next block - if (!find_cell(&p, false)) continue; + // If this location is not in the geometry at all, move on to next block + if (!find_cell(&p, false)) continue; - if (domain_type_ == FILTER_MATERIAL) { - if (p.material_ != MATERIAL_VOID) { - for (int i_domain = 0; i_domain < n; i_domain++) { - if (model::materials[p.material_]->id_ == domain_ids_[i_domain]) { - this->check_hit(p.material_, indices[i_domain], hits[i_domain]); - break; + if (domain_type_ == FILTER_MATERIAL) { + if (p.material_ != MATERIAL_VOID) { + for (int i_domain = 0; i_domain < n; i_domain++) { + if (model::materials[p.material_]->id_ == domain_ids_[i_domain]) { + this->check_hit(p.material_, indices[i_domain], hits[i_domain]); + break; + } } } - } - } else if (domain_type_ == FILTER_CELL) { - for (int level = 0; level < p.n_coord_; ++level) { - for (int i_domain=0; i_domain < n; i_domain++) { - if (model::cells[p.coord_[level].cell]->id_ == domain_ids_[i_domain]) { - this->check_hit(p.material_, indices[i_domain], hits[i_domain]); - break; + } else if (domain_type_ == FILTER_CELL) { + for (int level = 0; level < p.n_coord_; ++level) { + for (int i_domain=0; i_domain < n; i_domain++) { + if (model::cells[p.coord_[level].cell]->id_ == domain_ids_[i_domain]) { + this->check_hit(p.material_, indices[i_domain], hits[i_domain]); + break; + } } } - } - } else if (domain_type_ == FILTER_UNIVERSE) { - for (int level = 0; level < p.n_coord_; ++level) { - for (int i_domain = 0; i_domain < n; ++i_domain) { - if (model::universes[p.coord_[level].universe]->id_ == domain_ids_[i_domain]) { - check_hit(p.material_, indices[i_domain], hits[i_domain]); - break; + } else if (domain_type_ == FILTER_UNIVERSE) { + for (int level = 0; level < p.n_coord_; ++level) { + for (int i_domain = 0; i_domain < n; ++i_domain) { + if (model::universes[p.coord_[level].universe]->id_ == domain_ids_[i_domain]) { + check_hit(p.material_, indices[i_domain], hits[i_domain]); + break; + } } } } } - } - // At this point, each thread has its own pair of index/hits lists and we now - // need to reduce them. OpenMP is not nearly smart enough to do this on its own, - // so we have to manually reduce them + // At this point, each thread has its own pair of index/hits lists and we now + // need to reduce them. OpenMP is not nearly smart enough to do this on its own, + // so we have to manually reduce them -#ifdef _OPENMP - #pragma omp for ordered schedule(static) - for (int i = 0; i < omp_get_num_threads(); ++i) { - #pragma omp ordered - for (int i_domain = 0; i_domain < n; ++i_domain) { - for (int j = 0; j < indices[i_domain].size(); ++j) { - // Check if this material has been added to the master list and if so, - // accumulate the number of hits - bool already_added = false; - for (int k = 0; k < master_indices[i_domain].size(); k++) { - if (indices[i_domain][j] == master_indices[i_domain][k]) { - master_hits[i_domain][k] += hits[i_domain][j]; - already_added = true; + #ifdef _OPENMP + int n_threads = omp_get_num_threads(); + #else + int n_threads = 1; + #endif + + #pragma omp for ordered schedule(static) + for (int i = 0; i < n_threads; ++i) { + #pragma omp ordered + for (int i_domain = 0; i_domain < n; ++i_domain) { + for (int j = 0; j < indices[i_domain].size(); ++j) { + // Check if this material has been added to the master list and if so, + // accumulate the number of hits + bool already_added = false; + for (int k = 0; k < master_indices[i_domain].size(); k++) { + if (indices[i_domain][j] == master_indices[i_domain][k]) { + master_hits[i_domain][k] += hits[i_domain][j]; + already_added = true; + } + } + if (!already_added) { + // If we made it here, the material hasn't yet been added to the master + // list, so add entries to the master indices and master hits lists + master_indices[i_domain].push_back(indices[i_domain][j]); + master_hits[i_domain].push_back(hits[i_domain][j]); } - } - if (!already_added) { - // If we made it here, the material hasn't yet been added to the master - // list, so add entries to the master indices and master hits lists - master_indices[i_domain].push_back(indices[i_domain][j]); - master_hits[i_domain].push_back(hits[i_domain][j]); } } } - } -#else - master_indices = indices; - master_hits = hits; -#endif + prn_set_stream(STREAM_TRACKING); + } // omp parallel - prn_set_stream(STREAM_TRACKING); - } // omp parallel + // Reduce hits onto master process - // Reduce hits onto master process + // Determine volume of bounding box + Position d {upper_right_ - lower_left_}; + double volume_sample = d.x*d.y*d.z; - // Determine volume of bounding box - Position d {upper_right_ - lower_left_}; - double volume_sample = d.x*d.y*d.z; + // bump iteration counter and get total number + // of samples at this point + iterations++; + size_t total_samples = iterations * n_samples_; - // Set size for members of the Result struct - std::vector results(n); + double max_vol_err = -INFTY; - for (int i_domain = 0; i_domain < n; ++i_domain) { - // Get reference to result for this domain - auto& result {results[i_domain]}; + // Set size for members of the Result struct + std::vector results(n); - // Create 2D array to store atoms/uncertainty for each nuclide. Later this - // is compressed into vectors storing only those nuclides that are non-zero - auto n_nuc = data::nuclides.size(); - xt::xtensor atoms({n_nuc, 2}, 0.0); + for (int i_domain = 0; i_domain < n; ++i_domain) { + // Get reference to result for this domain + auto& result {results[i_domain]}; -#ifdef OPENMC_MPI - if (mpi::master) { - for (int j = 1; j < mpi::n_procs; j++) { - int q; - MPI_Recv(&q, 1, MPI_INTEGER, j, 0, mpi::intracomm, MPI_STATUS_IGNORE); + // Create 2D array to store atoms/uncertainty for each nuclide. Later this + // is compressed into vectors storing only those nuclides that are non-zero + auto n_nuc = data::nuclides.size(); + xt::xtensor atoms({n_nuc, 2}, 0.0); + + #ifdef OPENMC_MPI + if (mpi::master) { + for (int j = 1; j < mpi::n_procs; j++) { + int q; + MPI_Recv(&q, 1, MPI_INTEGER, j, 0, mpi::intracomm, MPI_STATUS_IGNORE); + int buffer[2*q]; + MPI_Recv(&buffer[0], 2*q, MPI_INTEGER, j, 1, mpi::intracomm, MPI_STATUS_IGNORE); + for (int k = 0; k < q; ++k) { + for (int m = 0; m < master_indices[i_domain].size(); ++m) { + if (buffer[2*k] == master_indices[i_domain][m]) { + master_hits[i_domain][m] += buffer[2*k + 1]; + break; + } + } + } + } + } else { + int q = master_indices[i_domain].size(); int buffer[2*q]; - MPI_Recv(&buffer[0], 2*q, MPI_INTEGER, j, 1, mpi::intracomm, MPI_STATUS_IGNORE); for (int k = 0; k < q; ++k) { - for (int m = 0; m < master_indices[i_domain].size(); ++m) { - if (buffer[2*k] == master_indices[i_domain][m]) { - master_hits[i_domain][m] += buffer[2*k + 1]; + buffer[2*k] = master_indices[i_domain][k]; + buffer[2*k + 1] = master_hits[i_domain][k]; + } + + MPI_Send(&q, 1, MPI_INTEGER, 0, 0, mpi::intracomm); + MPI_Send(&buffer[0], 2*q, MPI_INTEGER, 0, 1, mpi::intracomm); + } + #endif + + if (mpi::master) { + int total_hits = 0; + for (int j = 0; j < master_indices[i_domain].size(); ++j) { + total_hits += master_hits[i_domain][j]; + double f = static_cast(master_hits[i_domain][j]) / total_samples; + double var_f = f*(1.0 - f) / total_samples; + + int i_material = master_indices[i_domain][j]; + if (i_material == MATERIAL_VOID) continue; + + const auto& mat = model::materials[i_material]; + for (int k = 0; k < mat->nuclide_.size(); ++k) { + // Accumulate nuclide density + int i_nuclide = mat->nuclide_[k]; + atoms(i_nuclide, 0) += mat->atom_density_[k] * f; + atoms(i_nuclide, 1) += std::pow(mat->atom_density_[k], 2) * var_f; + } + } + + // Determine volume + result.volume[0] = static_cast(total_hits) / total_samples * volume_sample; + result.volume[1] = std::sqrt(result.volume[0] + * (volume_sample - result.volume[0]) / total_samples); + result.num_samples = total_samples; + + // update threshold value if needed + if (trigger_type_ != ThresholdType::NONE) { + double val = 0.0; + switch (trigger_type_) { + case ThresholdType::STD_DEV: + val = result.volume[1]; break; - } + case ThresholdType::REL_ERR: + val = result.volume[1] / result.volume[0]; + break; + case ThresholdType::VARIANCE: + val = result.volume[1] * result.volume[1]; + break; + } + // update max if entry is valid + if (val > 0.0) { max_vol_err = std::max(max_vol_err, val); } + } + + for (int j = 0; j < n_nuc; ++j) { + // Determine total number of atoms. At this point, we have values in + // atoms/b-cm. To get to atoms we multiply by 10^24 V. + double mean = 1.0e24 * volume_sample * atoms(j, 0); + double stdev = 1.0e24 * volume_sample * std::sqrt(atoms(j, 1)); + + // Convert full arrays to vectors + if (mean > 0.0) { + result.nuclides.push_back(j); + result.atoms.push_back(mean); + result.uncertainty.push_back(stdev); + } else { + result.nuclides.push_back(j); + result.atoms.push_back(0.0); + result.uncertainty.push_back(0.0); } } } - } else { - int q = master_indices[i_domain].size(); - int buffer[2*q]; - for (int k = 0; k < q; ++k) { - buffer[2*k] = master_indices[i_domain][k]; - buffer[2*k + 1] = master_hits[i_domain][k]; - } - - MPI_Send(&q, 1, MPI_INTEGER, 0, 0, mpi::intracomm); - MPI_Send(&buffer[0], 2*q, MPI_INTEGER, 0, 1, mpi::intracomm); } -#endif - if (mpi::master) { - int total_hits = 0; - for (int j = 0; j < master_indices[i_domain].size(); ++j) { - total_hits += master_hits[i_domain][j]; - double f = static_cast(master_hits[i_domain][j]) / n_samples_; - double var_f = f*(1.0 - f) / n_samples_; + // return results of the calculation + if (trigger_type_ == ThresholdType::NONE || max_vol_err < threshold_) { + return results; + } - int i_material = master_indices[i_domain][j]; - if (i_material == MATERIAL_VOID) continue; - - const auto& mat = model::materials[i_material]; - for (int k = 0; k < mat->nuclide_.size(); ++k) { - // Accumulate nuclide density - int i_nuclide = mat->nuclide_[k]; - atoms(i_nuclide, 0) += mat->atom_density_[k] * f; - atoms(i_nuclide, 1) += std::pow(mat->atom_density_[k], 2) * var_f; - } - } - - // Determine volume - result.volume[0] = static_cast(total_hits) / n_samples_ * volume_sample; - result.volume[1] = std::sqrt(result.volume[0] - * (volume_sample - result.volume[0]) / n_samples_); - result.num_samples = n_samples_; - - for (int j = 0; j < n_nuc; ++j) { - // Determine total number of atoms. At this point, we have values in - // atoms/b-cm. To get to atoms we multiply by 10^24 V. - double mean = 1.0e24 * volume_sample * atoms(j, 0); - double stdev = 1.0e24 * volume_sample * std::sqrt(atoms(j, 1)); - - // Convert full arrays to vectors - if (mean > 0.0) { - result.nuclides.push_back(j); - result.atoms.push_back(mean); - result.uncertainty.push_back(stdev); - } else { - result.nuclides.push_back(j); - result.atoms.push_back(0.0); - result.uncertainty.push_back(0.0); - } - } - } - } - - return results; + } // end while } void VolumeCalculation::to_hdf5(const std::string& filename, From 4c344e962617b193130ddc39260c6e2757ca67fd Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Tue, 8 Oct 2019 09:46:52 -0500 Subject: [PATCH 052/158] Removing unused code. --- include/openmc/volume_calc.h | 52 ++---------------------------------- src/volume_calc.cpp | 51 ++--------------------------------- 2 files changed, 4 insertions(+), 99 deletions(-) diff --git a/include/openmc/volume_calc.h b/include/openmc/volume_calc.h index 982e6a9e7..74331de87 100644 --- a/include/openmc/volume_calc.h +++ b/include/openmc/volume_calc.h @@ -31,48 +31,8 @@ public: std::array volume; //!< Mean/standard deviation of volume std::vector nuclides; //!< Index of nuclides std::vector atoms; //!< Number of atoms for each nuclide - std::vector uncertainty; //!< Uncertainty on number of atoms - size_t num_samples; - - Result& operator +=( const Result& other) { - Expects(volume.size() == other.volume.size()); - Expects(atoms.size() == atoms.size()); - - auto& a_samples = num_samples; - auto& b_samples = other.num_samples; - - size_t total_samples = num_samples + other.num_samples; - - for (int i = 0; i < volume.size(); i++) { - // calculate weighted average of volume results - auto& a_vol = volume[0]; - auto& b_vol = other.volume[0]; - volume[0] = (a_samples * a_vol + b_samples * b_vol) / total_samples; - - // propagate error - auto& a_err = volume[1]; - auto& b_err = other.volume[1]; - volume[1] = std::sqrt(a_samples * a_err * a_err + b_samples * b_err * b_err) / total_samples; - } - - for (int i = 0; i < atoms.size(); i++) { - // calculate weighted average of atom results - auto& a_atoms = atoms[i]; - auto& b_atoms = other.atoms[i]; - atoms[i] = (a_samples * a_atoms + b_samples * b_atoms) / total_samples; - - // propagate error - auto& a_err = uncertainty[i]; - auto& b_err = other.uncertainty[i]; - uncertainty[i] = std::sqrt(a_samples * a_err * a_err + b_samples * b_err * b_err) / total_samples; - } - - // update number of samples on the returned set of results; - num_samples = total_samples; - - return *this; - } - + std::vector uncertainty; //!< Uncertainty on number of atoms + int iterations; }; // Results for a single domain // Constructors @@ -111,14 +71,6 @@ private: void check_hit(int i_material, std::vector& indices, std::vector& hits) const; - //! \brief Perform calculation for domain volumes and average nuclide density - //! using n_samples_ - // - //! \param[in] seed_offset Seed offset used for independent calculations - //! \return Vector of results for each user-specified domain - std::vector _execute() const; - - }; //============================================================================== diff --git a/src/volume_calc.cpp b/src/volume_calc.cpp index f2cb7a7d1..21d9c3cb0 100644 --- a/src/volume_calc.cpp +++ b/src/volume_calc.cpp @@ -103,54 +103,7 @@ VolumeCalculation::VolumeCalculation(pugi::xml_node node) } -std::vector VolumeCalculation::execute() const { - - // execute the calculation once - std::vector results = _execute(); - return results; - - // if no std. dev. threshold is set, return these resuls - if (threshold_ == -1.0) { return results; } - - size_t offset = n_samples_; - double max_val; - - while (true) { - // check maximum error value for all domains - max_val = -INFTY; - for (const auto& result : results) { - double val; - switch (trigger_type_) { - case ThresholdType::STD_DEV: - val = result.volume[1]; - break; - case ThresholdType::REL_ERR: - val = result.volume[1] / result.volume[0]; - break; - case ThresholdType::VARIANCE: - val = result.volume[1] * result.volume[1]; - break; - } - // update max if entry is valid - if (val > 0.0) { max_val = std::max(max_val, val); } - - } - - // exit once we're below our error limit - if (max_val <= threshold_) { break; } - - // perform the calculation - std::vector tmp = _execute(); - offset += n_samples_; - - // update current results - for (int i = 0; i < results.size(); i++) { results[i] += tmp[i]; } - } - - return results; -} - -std::vector VolumeCalculation::_execute() const +std::vector VolumeCalculation::execute() const { // Shared data that is collected from all threads int n = domain_ids_.size(); @@ -336,7 +289,7 @@ std::vector VolumeCalculation::_execute() const result.volume[0] = static_cast(total_hits) / total_samples * volume_sample; result.volume[1] = std::sqrt(result.volume[0] * (volume_sample - result.volume[0]) / total_samples); - result.num_samples = total_samples; + result.iterations = iterations; // update threshold value if needed if (trigger_type_ != ThresholdType::NONE) { From 24bfa0051a09ef06286b36b61537c3be921100ac Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Tue, 8 Oct 2019 10:55:04 -0500 Subject: [PATCH 053/158] Updating default trigger value and how trigger value is written to file --- include/openmc/volume_calc.h | 2 +- src/volume_calc.cpp | 18 +++---- .../volume_calc/results_true.dat | 54 ++++--------------- 3 files changed, 20 insertions(+), 54 deletions(-) diff --git a/include/openmc/volume_calc.h b/include/openmc/volume_calc.h index 74331de87..33d10209e 100644 --- a/include/openmc/volume_calc.h +++ b/include/openmc/volume_calc.h @@ -56,7 +56,7 @@ public: int domain_type_; //!< Type of domain (cell, material, etc.) size_t n_samples_; //!< Number of samples to use double threshold_ {-1.0}; //!< Error threshold for domain volumes - ThresholdType trigger_type_; + ThresholdType trigger_type_ {ThresholdType::NONE}; Position lower_left_; //!< Lower-left position of bounding box Position upper_right_; //!< Upper-right position of bounding box std::vector domain_ids_; //!< IDs of domains to find volumes of diff --git a/src/volume_calc.cpp b/src/volume_calc.cpp index 21d9c3cb0..23bb08f82 100644 --- a/src/volume_calc.cpp +++ b/src/volume_calc.cpp @@ -320,10 +320,6 @@ std::vector VolumeCalculation::execute() const result.nuclides.push_back(j); result.atoms.push_back(mean); result.uncertainty.push_back(stdev); - } else { - result.nuclides.push_back(j); - result.atoms.push_back(0.0); - result.uncertainty.push_back(0.0); } } } @@ -358,21 +354,23 @@ void VolumeCalculation::to_hdf5(const std::string& filename, write_attribute(file_id, "samples", n_samples_); write_attribute(file_id, "lower_left", lower_left_); write_attribute(file_id, "upper_right", upper_right_); - if (threshold_ != -1.0) { + // Write trigger info + if (trigger_type_ != ThresholdType::NONE) { + write_attribute(file_id, "iterations", results[0].iterations); write_attribute(file_id, "threshold", threshold_); - + std::string trigger_str; switch(trigger_type_) { case ThresholdType::VARIANCE: - write_attribute(file_id, "trigger_type", "variance"); + trigger_str = "variance"; break; case ThresholdType::STD_DEV: - write_attribute(file_id, "trigger_type", "std_dev"); + trigger_str = "std_dev"; break; case ThresholdType::REL_ERR: - write_attribute(file_id, "trigger_type", "rel_err"); + trigger_str = "rel_err"; break; } - + write_attribute(file_id, "trigger_type", trigger_str); } if (domain_type_ == FILTER_CELL) { diff --git a/tests/regression_tests/volume_calc/results_true.dat b/tests/regression_tests/volume_calc/results_true.dat index 4fe3b4b6e..466139cd6 100644 --- a/tests/regression_tests/volume_calc/results_true.dat +++ b/tests/regression_tests/volume_calc/results_true.dat @@ -2,22 +2,15 @@ Volume calculation 0 Domain 1: 31.47+/-0.07 cm^3 Domain 2: 2.093+/-0.031 cm^3 Domain 3: 2.049+/-0.031 cm^3 - Cell Nuclide Atoms -0 1 H1 0.0+/-0 -1 1 O16 0.0+/-0 -2 1 B10 0.0+/-0 -3 1 U235 (3.482+/-0.008)e+23 -4 1 Mo99 (3.482+/-0.008)e+22 -5 2 H1 (1.400+/-0.021)e+23 -6 2 O16 (7.00+/-0.10)e+22 -7 2 B10 (7.00+/-0.10)e+18 -8 2 U235 0.0+/-0 -9 2 Mo99 0.0+/-0 -10 3 H1 (1.370+/-0.021)e+23 -11 3 O16 (6.85+/-0.10)e+22 -12 3 B10 (6.85+/-0.10)e+18 -13 3 U235 0.0+/-0 -14 3 Mo99 0.0+/-0 + Cell Nuclide Atoms +0 1 U235 (3.482+/-0.008)e+23 +1 1 Mo99 (3.482+/-0.008)e+22 +2 2 H1 (1.400+/-0.021)e+23 +3 2 O16 (7.00+/-0.10)e+22 +4 2 B10 (7.00+/-0.10)e+18 +5 3 H1 (1.370+/-0.021)e+23 +6 3 O16 (6.85+/-0.10)e+22 +7 3 B10 (6.85+/-0.10)e+18 Volume calculation 1 Domain 1: 4.14+/-0.04 cm^3 Domain 2: 31.47+/-0.07 cm^3 @@ -25,13 +18,8 @@ Domain 2: 31.47+/-0.07 cm^3 0 1 H1 (2.770+/-0.029)e+23 1 1 O16 (1.385+/-0.014)e+23 2 1 B10 (1.385+/-0.014)e+19 -3 1 U235 0.0+/-0 -4 1 Mo99 0.0+/-0 -5 2 H1 0.0+/-0 -6 2 O16 0.0+/-0 -7 2 B10 0.0+/-0 -8 2 U235 (3.482+/-0.008)e+23 -9 2 Mo99 (3.482+/-0.008)e+22 +3 2 U235 (3.482+/-0.008)e+23 +4 2 Mo99 (3.482+/-0.008)e+22 Volume calculation 2 Domain 0: 35.61+/-0.07 cm^3 Universe Nuclide Atoms @@ -40,23 +28,3 @@ Domain 0: 35.61+/-0.07 cm^3 2 0 B10 (1.385+/-0.014)e+19 3 0 U235 (3.482+/-0.008)e+23 4 0 Mo99 (3.482+/-0.008)e+22 -Volume calculation 3 -Domain 1: 31.35476+/-0.00010 cm^3 -Domain 2: 2.09147+/-0.00005 cm^3 -Domain 3: 2.110402+/-0.000033 cm^3 - Cell Nuclide Atoms -0 1 H1 0.0+/-0 -1 1 O16 0.0+/-0 -2 1 B10 0.0+/-0 -3 1 U235 (3.474110+/-0.000011)e+23 -4 1 Mo99 (3.474110+/-0.000011)e+22 -5 2 H1 (1.398833+/-0.000031)e+23 -6 2 O16 (6.99416+/-0.00015)e+22 -7 2 B10 (6.99416+/-0.00015)e+18 -8 2 U235 0.0+/-0 -9 2 Mo99 0.0+/-0 -10 3 H1 (1.401947+/-0.000022)e+23 -11 3 O16 (7.00974+/-0.00011)e+22 -12 3 B10 (7.00974+/-0.00011)e+18 -13 3 U235 0.0+/-0 -14 3 Mo99 0.0+/-0 From 884a083a50eaf28ac86a3ba35ad96572534724c0 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Tue, 8 Oct 2019 10:55:45 -0500 Subject: [PATCH 054/158] Adding iteration property to volume calculation in Python API. --- openmc/volume.py | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/openmc/volume.py b/openmc/volume.py index 3996ce9dd..99eadb57d 100644 --- a/openmc/volume.py +++ b/openmc/volume.py @@ -58,7 +58,9 @@ class VolumeCalculation(object): volumes : dict Dictionary mapping unique IDs of domains to estimated volumes in cm^3. threshold : float - Threshold for the maxmimum standard deviation of volumes + Threshold for the maxmimum standard deviation of volumes. + iterations : int + Number of iterations over samples (for calculations with a trigger). trigger_type : {'variance', 'std_dev', 'rel_err'} Value type used to halt volume calculation @@ -68,6 +70,7 @@ class VolumeCalculation(object): self._volumes = {} self._threshold = None self._trigger_type = None + self._iterations = None cv.check_type('domains', domains, Iterable, (openmc.Cell, openmc.Material, openmc.Universe)) @@ -139,6 +142,10 @@ class VolumeCalculation(object): def trigger_type(self): return self._trigger_type + @property + def iterations(self): + return self._iterations + @property def domain_type(self): return self._domain_type @@ -189,10 +196,8 @@ class VolumeCalculation(object): @threshold.setter def threshold(self, threshold): name = 'volume std. dev. threshold' - cv.check_type(name, threshold, Real) - if (threshold <= 0.0): - raise ValueError("Invalid value '{}' (<= 0.0) provided for volume " - "calculation threshold.".format(threshold)) + cv.check_type(name, threshold, Real) + cv.check_greater_than(name, threshold, 0.0) self._threshold = threshold @trigger_type.setter @@ -201,6 +206,13 @@ class VolumeCalculation(object): ['variance', 'std_dev', 'rel_err']) self._trigger_type = trigger_type + @iterations.setter + def iterations(self, iterations): + name = 'volume calculation iterations' + cv.check_type(name, iterations, Integral) + cv.check_greater_than(name, iterations, 0) + self._iterations = iterations + @volumes.setter def volumes(self, volumes): cv.check_type('volumes', volumes, Mapping) @@ -247,15 +259,9 @@ class VolumeCalculation(object): lower_left = f.attrs['lower_left'] upper_right = f.attrs['upper_right'] - try: - threshold = f.attrs['threshold'] - except KeyError: - threshold = None - - try: - trigger_type = f.attrs['trigger_type'].decode() - except KeyError: - trigger_type = None + threshold = f.attrs.get('threshold') + trigger_type = f.attrs.get('trigger_type') + iterations = f.attrs.get('iterations', 1) volumes = {} atoms = {} @@ -288,9 +294,10 @@ class VolumeCalculation(object): # Instantiate the class and assign results vol = cls(domains, samples, lower_left, upper_right) - if threshold is not None: - vol.set_trigger(threshold, trigger_type) + if trigger_type is not None: + vol.set_trigger(threshold, trigger_type.decode()) + vol.iterations = iterations vol.volumes = volumes vol.atoms = atoms return vol From 17ebd34b452b94c8d9431bdae3a3d99af835e878 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Tue, 8 Oct 2019 10:55:54 -0500 Subject: [PATCH 055/158] Updating tests. --- .../volume_calc/inputs_true.dat | 18 ++++++- .../volume_calc/results_true.dat | 35 ++++++++++++++ tests/regression_tests/volume_calc/test.py | 48 +++++++++++++++++-- 3 files changed, 95 insertions(+), 6 deletions(-) diff --git a/tests/regression_tests/volume_calc/inputs_true.dat b/tests/regression_tests/volume_calc/inputs_true.dat index 1af345405..aaf6d8b00 100644 --- a/tests/regression_tests/volume_calc/inputs_true.dat +++ b/tests/regression_tests/volume_calc/inputs_true.dat @@ -54,6 +54,22 @@ 100 -1.0 -1.0 -6.0 1.0 1.0 6.0 - + + + + material + 1 2 + 100 + -1.0 -1.0 -6.0 + 1.0 1.0 6.0 + + + + cell + 1 2 3 + 100 + -1.0 -1.0 -6.0 + 1.0 1.0 6.0 + diff --git a/tests/regression_tests/volume_calc/results_true.dat b/tests/regression_tests/volume_calc/results_true.dat index 466139cd6..a31360abc 100644 --- a/tests/regression_tests/volume_calc/results_true.dat +++ b/tests/regression_tests/volume_calc/results_true.dat @@ -28,3 +28,38 @@ Domain 0: 35.61+/-0.07 cm^3 2 0 B10 (1.385+/-0.014)e+19 3 0 U235 (3.482+/-0.008)e+23 4 0 Mo99 (3.482+/-0.008)e+22 +Volume calculation 3 +Domain 1: 31.47+/-0.10 cm^3 +Domain 2: 2.10+/-0.04 cm^3 +Domain 3: 2.11+/-0.04 cm^3 + Cell Nuclide Atoms +0 1 U235 (3.481+/-0.011)e+23 +1 1 Mo99 (3.481+/-0.011)e+22 +2 2 H1 (1.403+/-0.029)e+23 +3 2 O16 (7.01+/-0.14)e+22 +4 2 B10 (7.01+/-0.14)e+18 +5 3 H1 (1.412+/-0.029)e+23 +6 3 O16 (7.06+/-0.14)e+22 +7 3 B10 (7.06+/-0.14)e+18 +Volume calculation 4 +Domain 1: 4.5+/-0.4 cm^3 +Domain 2: 30.5+/-0.7 cm^3 + Material Nuclide Atoms +0 1 H1 (3.02+/-0.30)e+23 +1 1 O16 (1.51+/-0.15)e+23 +2 1 B10 (1.51+/-0.15)e+19 +3 2 U235 (3.38+/-0.08)e+23 +4 2 Mo99 (3.38+/-0.08)e+22 +Volume calculation 5 +Domain 1: 31.51+/-0.22 cm^3 +Domain 2: 2.13+/-0.10 cm^3 +Domain 3: 2.11+/-0.10 cm^3 + Cell Nuclide Atoms +0 1 U235 (3.486+/-0.025)e+23 +1 1 Mo99 (3.486+/-0.025)e+22 +2 2 H1 (1.42+/-0.06)e+23 +3 2 O16 (7.11+/-0.32)e+22 +4 2 B10 (7.11+/-0.32)e+18 +5 3 H1 (1.41+/-0.06)e+23 +6 3 O16 (7.05+/-0.32)e+22 +7 3 B10 (7.05+/-0.32)e+18 diff --git a/tests/regression_tests/volume_calc/test.py b/tests/regression_tests/volume_calc/test.py index 6bcedd397..8f003aa68 100644 --- a/tests/regression_tests/volume_calc/test.py +++ b/tests/regression_tests/volume_calc/test.py @@ -8,6 +8,19 @@ from tests.testing_harness import PyAPITestHarness class VolumeTest(PyAPITestHarness): + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + self.exp_std_dev = 1e-01 + self.std_dev_iters = 521 + + self.exp_rel_err = 1e-01 + self.rel_err_iters = 10 + + self.exp_variance = 5e-02 + self.variance_iters = 105 + def _build_inputs(self): # Define materials water = openmc.Material(1) @@ -46,10 +59,17 @@ class VolumeTest(PyAPITestHarness): openmc.VolumeCalculation(list(root.cells.values()), 100000), openmc.VolumeCalculation([water, fuel], 100000, ll, ur), openmc.VolumeCalculation([root], 100000, ll, ur), + openmc.VolumeCalculation(list(root.cells.values()), 100), + openmc.VolumeCalculation([water, fuel], 100, ll, ur), openmc.VolumeCalculation(list(root.cells.values()), 100) ] - vol_calcs[-1].set_trigger(1e-04, 'std_dev') + + vol_calcs[3].set_trigger(self.exp_std_dev, 'std_dev') + + vol_calcs[4].set_trigger(self.exp_rel_err, 'rel_err') + + vol_calcs[5].set_trigger(self.exp_variance, 'variance') # Define settings settings = openmc.Settings() @@ -65,10 +85,28 @@ class VolumeTest(PyAPITestHarness): # Read volume calculation results volume_calc = openmc.VolumeCalculation.from_hdf5(filename) - if volume_calc.samples == 100: + if i == 3: assert(volume_calc.trigger_type == 'std_dev') - assert(volume_calc.threshold == 1e-04) - + assert(volume_calc.threshold == self.exp_std_dev) + assert(volume_calc.iterations == self.std_dev_iters) + for vol in volume_calc.volumes.values(): + assert(vol.std_dev <= self.exp_std_dev) + elif i == 4: + assert(volume_calc.trigger_type == 'rel_err') + assert(volume_calc.threshold == self.exp_rel_err) + assert(volume_calc.iterations == self.rel_err_iters) + for vol in volume_calc.volumes.values(): + assert(vol.std_dev/vol.nominal_value <= self.exp_rel_err) + elif i == 5: + assert(volume_calc.trigger_type == 'variance') + assert(volume_calc.threshold == self.exp_variance) + assert(volume_calc.iterations == self.variance_iters) + for vol in volume_calc.volumes.values(): + assert(vol.std_dev * vol.std_dev <= self.exp_variance) + else: + assert(volume_calc.trigger_type == None) + assert(volume_calc.threshold == None) + assert(volume_calc.iterations == 1) # Write cell volumes and total # of atoms for each nuclide for uid, volume in sorted(volume_calc.volumes.items()): @@ -82,4 +120,4 @@ class VolumeTest(PyAPITestHarness): def test_volume_calc(): harness = VolumeTest('') - harness.main() + harness.main() \ No newline at end of file From b2c064cc357415b4699302dabf7e0ea6d1f40d9d Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Tue, 8 Oct 2019 11:34:26 -0500 Subject: [PATCH 056/158] Updates for MPI runs. --- src/volume_calc.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/volume_calc.cpp b/src/volume_calc.cpp index 23bb08f82..13cfcf569 100644 --- a/src/volume_calc.cpp +++ b/src/volume_calc.cpp @@ -325,11 +325,30 @@ std::vector VolumeCalculation::execute() const } } +#ifdef OPENMC_MPI + // update maximum error value on all processes + if (mpi::master) { + for (int i = 1; i < mpi::n_procs; i++) { + MPI_Send(&max_vol_err, 1, MPI_DOUBLE, i, 0, mpi::intracomm); + } + } else { + MPI_Recv(&max_vol_err, 1, MPI_DOUBLE, 0, 0, mpi::intracomm, MPI_STATUS_IGNORE); + } +#endif + // return results of the calculation if (trigger_type_ == ThresholdType::NONE || max_vol_err < threshold_) { return results; } +#ifdef OPENMC_MPI + // if iterating in MPI, need to zero indices and hits to they aren't counted twice + if (!mpi::master) { + for (auto& v : master_indices) { std::fill(v.begin(), v.end(), 0.0); } + for (auto& v : master_hits) { std::fill(v.begin(), v.end(), 0.0); } + } +#endif + } // end while } From eeb8b3cbb337635387de225c0d4c31819ac4e0df Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Tue, 8 Oct 2019 13:15:30 -0500 Subject: [PATCH 057/158] Updating name VolumeCalculation attribute. --- include/openmc/volume_calc.h | 4 ++-- src/volume_calc.cpp | 24 ++++++++++++------------ 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/include/openmc/volume_calc.h b/include/openmc/volume_calc.h index 33d10209e..dade67f5a 100644 --- a/include/openmc/volume_calc.h +++ b/include/openmc/volume_calc.h @@ -12,7 +12,7 @@ namespace openmc { -enum class ThresholdType { +enum class VolumeTriggerMetric { NONE = 0, VARIANCE = 1, STD_DEV = 2, @@ -56,7 +56,7 @@ public: int domain_type_; //!< Type of domain (cell, material, etc.) size_t n_samples_; //!< Number of samples to use double threshold_ {-1.0}; //!< Error threshold for domain volumes - ThresholdType trigger_type_ {ThresholdType::NONE}; + VolumeTriggerMetric trigger_type_ {VolumeTriggerMetric::NONE}; //!< Trigger metric for the volume calculation Position lower_left_; //!< Lower-left position of bounding box Position upper_right_; //!< Upper-right position of bounding box std::vector domain_ids_; //!< IDs of domains to find volumes of diff --git a/src/volume_calc.cpp b/src/volume_calc.cpp index 13cfcf569..0b5c0204c 100644 --- a/src/volume_calc.cpp +++ b/src/volume_calc.cpp @@ -80,11 +80,11 @@ VolumeCalculation::VolumeCalculation(pugi::xml_node node) std::string tmp = get_node_value(threshold_node, "type"); if (tmp == "variance") { - trigger_type_ = ThresholdType::VARIANCE; + trigger_type_ = VolumeTriggerMetric::VARIANCE; } else if (tmp == "std_dev") { - trigger_type_ = ThresholdType::STD_DEV; + trigger_type_ = VolumeTriggerMetric::STD_DEV; } else if ( tmp == "rel_err") { - trigger_type_ = ThresholdType::REL_ERR; + trigger_type_ = VolumeTriggerMetric::REL_ERR; } else { std::stringstream msg; msg << "Invalid volume calculation trigger type '" << tmp << "' provided."; @@ -292,16 +292,16 @@ std::vector VolumeCalculation::execute() const result.iterations = iterations; // update threshold value if needed - if (trigger_type_ != ThresholdType::NONE) { + if (trigger_type_ != VolumeTriggerMetric::NONE) { double val = 0.0; switch (trigger_type_) { - case ThresholdType::STD_DEV: + case VolumeTriggerMetric::STD_DEV: val = result.volume[1]; break; - case ThresholdType::REL_ERR: + case VolumeTriggerMetric::REL_ERR: val = result.volume[1] / result.volume[0]; break; - case ThresholdType::VARIANCE: + case VolumeTriggerMetric::VARIANCE: val = result.volume[1] * result.volume[1]; break; } @@ -337,7 +337,7 @@ std::vector VolumeCalculation::execute() const #endif // return results of the calculation - if (trigger_type_ == ThresholdType::NONE || max_vol_err < threshold_) { + if (trigger_type_ == VolumeTriggerMetric::NONE || max_vol_err < threshold_) { return results; } @@ -374,18 +374,18 @@ void VolumeCalculation::to_hdf5(const std::string& filename, write_attribute(file_id, "lower_left", lower_left_); write_attribute(file_id, "upper_right", upper_right_); // Write trigger info - if (trigger_type_ != ThresholdType::NONE) { + if (trigger_type_ != VolumeTriggerMetric::NONE) { write_attribute(file_id, "iterations", results[0].iterations); write_attribute(file_id, "threshold", threshold_); std::string trigger_str; switch(trigger_type_) { - case ThresholdType::VARIANCE: + case VolumeTriggerMetric::VARIANCE: trigger_str = "variance"; break; - case ThresholdType::STD_DEV: + case VolumeTriggerMetric::STD_DEV: trigger_str = "std_dev"; break; - case ThresholdType::REL_ERR: + case VolumeTriggerMetric::REL_ERR: trigger_str = "rel_err"; break; } From f251822b9f16af12f18f08ec7fa94c1fae1be59e Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Tue, 8 Oct 2019 13:31:37 -0500 Subject: [PATCH 058/158] Removing trailing whitespace in doc file. --- docs/source/usersguide/volume.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/usersguide/volume.rst b/docs/source/usersguide/volume.rst index d35386b38..b946858ea 100644 --- a/docs/source/usersguide/volume.rst +++ b/docs/source/usersguide/volume.rst @@ -42,8 +42,8 @@ or relative error of volume estimates using ::attr::`openmc.VolumeCalculation.se vol_calc.set_trigger(1e-05, 'std_dev') -If a threshold is provided, calculations will be performed iteratively using the -number of samples specified on the calculation until all volume uncertainties are below +If a threshold is provided, calculations will be performed iteratively using the +number of samples specified on the calculation until all volume uncertainties are below the threshold value. If no threshold is provided, the calculation will run the number of samples specified once and return the result. From 919c19c9094add032881fe07ad7d12d1091d6424 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Tue, 8 Oct 2019 13:53:22 -0500 Subject: [PATCH 059/158] Cleanup from self-review. --- include/openmc/volume_calc.h | 4 +- openmc/volume.py | 13 +++---- src/volume_calc.cpp | 43 ++++++++++++---------- tests/regression_tests/volume_calc/test.py | 6 +-- 4 files changed, 35 insertions(+), 31 deletions(-) diff --git a/include/openmc/volume_calc.h b/include/openmc/volume_calc.h index dade67f5a..bf85a435d 100644 --- a/include/openmc/volume_calc.h +++ b/include/openmc/volume_calc.h @@ -31,8 +31,8 @@ public: std::array volume; //!< Mean/standard deviation of volume std::vector nuclides; //!< Index of nuclides std::vector atoms; //!< Number of atoms for each nuclide - std::vector uncertainty; //!< Uncertainty on number of atoms - int iterations; + std::vector uncertainty; //!< Uncertainty on number of atoms + int iterations; //!< Number of iterations needed to obtain the results }; // Results for a single domain // Constructors diff --git a/openmc/volume.py b/openmc/volume.py index 99eadb57d..a59fb2acf 100644 --- a/openmc/volume.py +++ b/openmc/volume.py @@ -32,7 +32,6 @@ class VolumeCalculation(object): Upper-right coordinates of bounding box used to sample points. If this argument is not supplied, an attempt is made to automatically determine a bounding box. - Attributes ---------- @@ -59,10 +58,10 @@ class VolumeCalculation(object): Dictionary mapping unique IDs of domains to estimated volumes in cm^3. threshold : float Threshold for the maxmimum standard deviation of volumes. - iterations : int - Number of iterations over samples (for calculations with a trigger). trigger_type : {'variance', 'std_dev', 'rel_err'} Value type used to halt volume calculation + iterations : int + Number of iterations over samples (for calculations with a trigger). """ def __init__(self, domains, samples, lower_left=None, upper_right=None): @@ -83,7 +82,7 @@ class VolumeCalculation(object): self.ids = [d.id for d in domains] self.samples = samples - + if lower_left is not None: if upper_right is None: raise ValueError('Both lower-left and upper-right coordinates ' @@ -193,7 +192,7 @@ class VolumeCalculation(object): cv.check_length(name, upper_right, 3) self._upper_right = upper_right - @threshold.setter + @threshold.setter def threshold(self, threshold): name = 'volume std. dev. threshold' cv.check_type(name, threshold, Real) @@ -203,7 +202,7 @@ class VolumeCalculation(object): @trigger_type.setter def trigger_type(self, trigger_type): cv.check_value('tally trigger type', trigger_type, - ['variance', 'std_dev', 'rel_err']) + ('variance', 'std_dev', 'rel_err')) self._trigger_type = trigger_type @iterations.setter @@ -293,7 +292,7 @@ class VolumeCalculation(object): # Instantiate the class and assign results vol = cls(domains, samples, lower_left, upper_right) - + if trigger_type is not None: vol.set_trigger(threshold, trigger_type.decode()) diff --git a/src/volume_calc.cpp b/src/volume_calc.cpp index 0b5c0204c..32b6f03e2 100644 --- a/src/volume_calc.cpp +++ b/src/volume_calc.cpp @@ -64,13 +64,13 @@ VolumeCalculation::VolumeCalculation(pugi::xml_node node) if (size_t_stream.fail()) { std::stringstream msg; msg << "Could not read number of samples (" - << size_t_stream.str() << ")\n"; + << size_t_stream.str() << ")"; fatal_error(msg); } if (check_for_node(node, "threshold")) { pugi::xml_node threshold_node = node.child("threshold"); - + threshold_ = std::stod(get_node_value(threshold_node, "threshold")); if (threshold_ <= 0.0) { std::stringstream msg; @@ -124,6 +124,7 @@ std::vector VolumeCalculation::execute() const } while (true) { + #pragma omp parallel { // Variables that are private to each thread @@ -223,7 +224,8 @@ std::vector VolumeCalculation::execute() const iterations++; size_t total_samples = iterations * n_samples_; - double max_vol_err = -INFTY; + // reset + double trigger_val = -INFTY; // Set size for members of the Result struct std::vector results(n); @@ -237,7 +239,7 @@ std::vector VolumeCalculation::execute() const auto n_nuc = data::nuclides.size(); xt::xtensor atoms({n_nuc, 2}, 0.0); - #ifdef OPENMC_MPI +#ifdef OPENMC_MPI if (mpi::master) { for (int j = 1; j < mpi::n_procs; j++) { int q; @@ -264,7 +266,7 @@ std::vector VolumeCalculation::execute() const MPI_Send(&q, 1, MPI_INTEGER, 0, 0, mpi::intracomm); MPI_Send(&buffer[0], 2*q, MPI_INTEGER, 0, 1, mpi::intracomm); } - #endif +#endif if (mpi::master) { int total_hits = 0; @@ -299,14 +301,14 @@ std::vector VolumeCalculation::execute() const val = result.volume[1]; break; case VolumeTriggerMetric::REL_ERR: - val = result.volume[1] / result.volume[0]; + val = result.volume[0] == 0.0 ? 0.0 : result.volume[1] / result.volume[0]; break; case VolumeTriggerMetric::VARIANCE: val = result.volume[1] * result.volume[1]; break; } // update max if entry is valid - if (val > 0.0) { max_vol_err = std::max(max_vol_err, val); } + if (val > 0.0) { trigger_val = std::max(trigger_val, val); } } for (int j = 0; j < n_nuc; ++j) { @@ -323,29 +325,30 @@ std::vector VolumeCalculation::execute() const } } } - } + } // end domain loop + + // if no trigger is applied, we're done + if (trigger_type_ == VolumeTriggerMetric::NONE) { return results; } #ifdef OPENMC_MPI // update maximum error value on all processes if (mpi::master) { for (int i = 1; i < mpi::n_procs; i++) { - MPI_Send(&max_vol_err, 1, MPI_DOUBLE, i, 0, mpi::intracomm); + MPI_Send(&trigger_val, 1, MPI_DOUBLE, i, 0, mpi::intracomm); } } else { - MPI_Recv(&max_vol_err, 1, MPI_DOUBLE, 0, 0, mpi::intracomm, MPI_STATUS_IGNORE); - } + MPI_Recv(&trigger_val, 1, MPI_DOUBLE, 0, 0, mpi::intracomm, MPI_STATUS_IGNORE); + } #endif - + // return results of the calculation - if (trigger_type_ == VolumeTriggerMetric::NONE || max_vol_err < threshold_) { - return results; - } + if (trigger_val < threshold_) { return results; } #ifdef OPENMC_MPI - // if iterating in MPI, need to zero indices and hits to they aren't counted twice + // if iterating in an MPI run, need to zero indices and hits so they aren't counted twice if (!mpi::master) { - for (auto& v : master_indices) { std::fill(v.begin(), v.end(), 0.0); } - for (auto& v : master_hits) { std::fill(v.begin(), v.end(), 0.0); } + for (auto& v : master_indices) { std::fill(v.begin(), v.end(), 0); } + for (auto& v : master_hits) { std::fill(v.begin(), v.end(), 0); } } #endif @@ -373,7 +376,7 @@ void VolumeCalculation::to_hdf5(const std::string& filename, write_attribute(file_id, "samples", n_samples_); write_attribute(file_id, "lower_left", lower_left_); write_attribute(file_id, "upper_right", upper_right_); - // Write trigger info + // Write trigger info if (trigger_type_ != VolumeTriggerMetric::NONE) { write_attribute(file_id, "iterations", results[0].iterations); write_attribute(file_id, "threshold", threshold_); @@ -390,6 +393,8 @@ void VolumeCalculation::to_hdf5(const std::string& filename, break; } write_attribute(file_id, "trigger_type", trigger_str); + } else { + write_attribute(file_id, "iterations", 1); } if (domain_type_ == FILTER_CELL) { diff --git a/tests/regression_tests/volume_calc/test.py b/tests/regression_tests/volume_calc/test.py index 8f003aa68..96acf59b9 100644 --- a/tests/regression_tests/volume_calc/test.py +++ b/tests/regression_tests/volume_calc/test.py @@ -64,7 +64,7 @@ class VolumeTest(PyAPITestHarness): openmc.VolumeCalculation(list(root.cells.values()), 100) ] - + vol_calcs[3].set_trigger(self.exp_std_dev, 'std_dev') vol_calcs[4].set_trigger(self.exp_rel_err, 'rel_err') @@ -102,7 +102,7 @@ class VolumeTest(PyAPITestHarness): assert(volume_calc.threshold == self.exp_variance) assert(volume_calc.iterations == self.variance_iters) for vol in volume_calc.volumes.values(): - assert(vol.std_dev * vol.std_dev <= self.exp_variance) + assert(vol.std_dev * vol.std_dev <= self.exp_variance) else: assert(volume_calc.trigger_type == None) assert(volume_calc.threshold == None) @@ -120,4 +120,4 @@ class VolumeTest(PyAPITestHarness): def test_volume_calc(): harness = VolumeTest('') - harness.main() \ No newline at end of file + harness.main() From 9a00357393258e362737258697becfae682572c1 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Tue, 8 Oct 2019 14:45:36 -0500 Subject: [PATCH 060/158] Updating name of material in DAGMC unit test. --- tests/unit_tests/dagmc/test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit_tests/dagmc/test.py b/tests/unit_tests/dagmc/test.py index f7b2844f6..e5d772555 100644 --- a/tests/unit_tests/dagmc/test.py +++ b/tests/unit_tests/dagmc/test.py @@ -38,7 +38,7 @@ def dagmc_model(request): model.tallies = [tally] # materials - u235 = openmc.Material(name="fuel") + u235 = openmc.Material(name="no-void fuel") u235.add_nuclide('U235', 1.0, 'ao') u235.set_density('g/cc', 11) u235.id = 40 From 711819ef62e884353783e5f1fb476085265943c5 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 9 Oct 2019 09:33:17 -0500 Subject: [PATCH 061/158] Move version number to 0.12.0-dev --- docs/source/conf.py | 4 ++-- include/openmc/constants.h | 4 ++-- openmc/__init__.py | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index f54a8df0e..68caff888 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -79,9 +79,9 @@ copyright = '2011-2019, Massachusetts Institute of Technology and OpenMC contrib # built documents. # # The short X.Y version. -version = "0.11" +version = "0.12" # The full version, including alpha/beta/rc tags. -release = "0.11.0" +release = "0.12.0-dev" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/include/openmc/constants.h b/include/openmc/constants.h index 046a7abef..d55744117 100644 --- a/include/openmc/constants.h +++ b/include/openmc/constants.h @@ -20,9 +20,9 @@ using double_4dvec = std::vector>>>; // OpenMC major, minor, and release numbers constexpr int VERSION_MAJOR {0}; -constexpr int VERSION_MINOR {11}; +constexpr int VERSION_MINOR {12}; constexpr int VERSION_RELEASE {0}; -constexpr bool VERSION_DEV {false}; +constexpr bool VERSION_DEV {true}; constexpr std::array VERSION {VERSION_MAJOR, VERSION_MINOR, VERSION_RELEASE}; // HDF5 data format diff --git a/openmc/__init__.py b/openmc/__init__.py index f1703dfea..6af629422 100644 --- a/openmc/__init__.py +++ b/openmc/__init__.py @@ -34,4 +34,4 @@ from . import examples # Import a few convencience functions that used to be here from openmc.model import rectangular_prism, hexagonal_prism -__version__ = '0.11.0' +__version__ = '0.12.0-dev' From f3be90ee6ca629d86d334cc99ed25830405548be Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 9 Oct 2019 10:04:37 -0500 Subject: [PATCH 062/158] Update year in LICENSE file --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index cfa34033c..328f3ee46 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2011-2018 Massachusetts Institute of Technology and OpenMC contributors +Copyright (c) 2011-2019 Massachusetts Institute of Technology and OpenMC contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in From 61ec96a934aba7c5e672c6b671356902e4370daa Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 9 Oct 2019 13:11:46 -0500 Subject: [PATCH 063/158] Add CODEOWNERS file --- CODEOWNERS | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 CODEOWNERS diff --git a/CODEOWNERS b/CODEOWNERS new file mode 100644 index 000000000..a061b7b6e --- /dev/null +++ b/CODEOWNERS @@ -0,0 +1,48 @@ +# Data interface +openmc/data/ @paulromano + +# Python bindings to C/C++ API +openmc/lib/ @paulromano + +# Depletion +openmc/deplete/ @drewejohnson +tests/regression_tests/deplete/ @drewejohnson +tests/unit_tests/test_deplete_*.py @drewejohnson + +# MG-related functionality +openmc/mgxs_library.py @nelsonag +src/mgxs.cpp @nelsonag +src/mgxs_interface.cpp @nelsonag +src/physics_mg.cpp @nelsonag +src/scattdata.cpp @nelsonag +src/xsdata.cpp @nelsonag + +# CMFD +openmc/cmfd.py @shikhar413 +src/cmfd_solver.cpp @shikhar413 + +# DAGMC +src/dagmc.cpp @pshriwise +tests/regression_tests/dagmc/ @pshriwise +tests/unit_tests/dagmc/ @pshriwise + +# Photon transport +openmc/data/BREMX.DAT @amandalund +openmc/data/compton_profiles.h5 @amandalund +openmc/data/photon.py @amandalund +src/photon.cpp @amandalund +src/bremsstrahlung.cpp @amandalund +tests/regression_tests/photon_production/ @amandalund +tests/regression_tests/photon_source/ @amandalund + +# RCP and TRISOs +openmc/model/triso.py @amandalund +tests/regression_tests/triso/ @amandalund +tests/unit_tests/test_model_triso.py @amandalund + +# Geometry plotting +src/plot.cpp @pshriwise +openmc/lib/plot.py @pshriwise + +# Resonance covariance +openmc/data/resonance_covariance.py @icmeyer From 4fc6319f03299d8192471f2bfc677909919b570f Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Thu, 10 Oct 2019 10:06:33 -0500 Subject: [PATCH 064/158] Updating legacy test as requested in PR by @paulromano. --- tests/regression_tests/dagmc/legacy/test.py | 66 ++++++++++----------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/tests/regression_tests/dagmc/legacy/test.py b/tests/regression_tests/dagmc/legacy/test.py index 624a7f97b..5af18e5c8 100644 --- a/tests/regression_tests/dagmc/legacy/test.py +++ b/tests/regression_tests/dagmc/legacy/test.py @@ -8,48 +8,48 @@ pytestmark = pytest.mark.skipif( not openmc.lib._dagmc_enabled(), reason="DAGMC CAD geometry is not enabled.") -class DAGMCLegacyTest(PyAPITestHarness): +@pytest.fixture +def model(): - def _build_inputs(self): - model = openmc.model.Model() + model = openmc.model.Model() - # settings - model.settings.batches = 5 - model.settings.inactive = 0 - model.settings.particles = 100 + # settings + model.settings.batches = 5 + model.settings.inactive = 0 + model.settings.particles = 100 - source_box = openmc.stats.Box([-4, -4, -4], - [ 4, 4, 4]) - source = openmc.Source(space=source_box) + source_box = openmc.stats.Box([-4, -4, -4], + [ 4, 4, 4]) + source = openmc.Source(space=source_box) - model.settings.source = source + model.settings.source = source - model.settings.dagmc = True + model.settings.dagmc = True - # tally - tally = openmc.Tally() - tally.scores = ['total'] - tally.filters = [openmc.CellFilter(1)] - model.tallies = [tally] + # tally + tally = openmc.Tally() + tally.scores = ['total'] + tally.filters = [openmc.CellFilter(1)] + model.tallies = [tally] - # materials - u235 = openmc.Material(name="no-void fuel") - u235.add_nuclide('U235', 1.0, 'ao') - u235.set_density('g/cc', 11) - u235.id = 40 + # materials + u235 = openmc.Material(name="no-void fuel") + u235.add_nuclide('U235', 1.0, 'ao') + u235.set_density('g/cc', 11) + u235.id = 40 - water = openmc.Material(name="water") - water.add_nuclide('H1', 2.0, 'ao') - water.add_nuclide('O16', 1.0, 'ao') - water.set_density('g/cc', 1.0) - water.add_s_alpha_beta('c_H_in_H2O') - water.id = 41 + water = openmc.Material(name="water") + water.add_nuclide('H1', 2.0, 'ao') + water.add_nuclide('O16', 1.0, 'ao') + water.set_density('g/cc', 1.0) + water.add_s_alpha_beta('c_H_in_H2O') + water.id = 41 - mats = openmc.Materials([u235, water]) - model.materials = mats + mats = openmc.Materials([u235, water]) + model.materials = mats - model.export_to_xml() + return model -def test_dagmc(): - harness = DAGMCLegacyTest('statepoint.5.h5') +def test_dagmc(model): + harness = PyAPITestHarness('statepoint.5.h5', model) harness.main() From a4f98661c1bab079323f58ebc0fa6aa54906b703 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Mon, 14 Oct 2019 18:45:30 -0500 Subject: [PATCH 065/158] Update docs/source/usersguide/volume.rst Co-Authored-By: Paul Romano --- docs/source/usersguide/volume.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/usersguide/volume.rst b/docs/source/usersguide/volume.rst index b946858ea..c040eb2d7 100644 --- a/docs/source/usersguide/volume.rst +++ b/docs/source/usersguide/volume.rst @@ -38,7 +38,7 @@ Of course, the volumes that you *need* this capability for are often the ones with complex definitions. A threshold can be applied for the calculation's variance, standard deviation, -or relative error of volume estimates using ::attr::`openmc.VolumeCalculation.set_trigger`:: +or relative error of volume estimates using :meth:`openmc.VolumeCalculation.set_trigger`:: vol_calc.set_trigger(1e-05, 'std_dev') @@ -76,4 +76,4 @@ After the results are loaded, volume estimates will be stored in :attr:`VolumeCalculation.volumes`. There is also a :attr:`VolumeCalculation.atoms_dataframe` attribute that shows stochastic estimates of the number of atoms of each type of nuclide within the specified -domains along with their uncertainties. \ No newline at end of file +domains along with their uncertainties. From 143fe6405757b15f34b1396ee63e3be2dfb668a6 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Mon, 14 Oct 2019 20:26:23 -0500 Subject: [PATCH 066/158] Using trigger enum --- include/openmc/volume_calc.h | 10 ++-------- src/volume_calc.cpp | 24 ++++++++++++------------ 2 files changed, 14 insertions(+), 20 deletions(-) diff --git a/include/openmc/volume_calc.h b/include/openmc/volume_calc.h index bf85a435d..1b49da814 100644 --- a/include/openmc/volume_calc.h +++ b/include/openmc/volume_calc.h @@ -2,6 +2,7 @@ #define OPENMC_VOLUME_CALC_H #include "openmc/position.h" +#include "openmc/tallies/trigger.h" #include "pugixml.hpp" #include "xtensor/xtensor.hpp" @@ -12,13 +13,6 @@ namespace openmc { -enum class VolumeTriggerMetric { - NONE = 0, - VARIANCE = 1, - STD_DEV = 2, - REL_ERR = 3 -}; - //============================================================================== // Volume calculation class //============================================================================== @@ -56,7 +50,7 @@ public: int domain_type_; //!< Type of domain (cell, material, etc.) size_t n_samples_; //!< Number of samples to use double threshold_ {-1.0}; //!< Error threshold for domain volumes - VolumeTriggerMetric trigger_type_ {VolumeTriggerMetric::NONE}; //!< Trigger metric for the volume calculation + TriggerMetric trigger_type_ {TriggerMetric::not_active}; //!< Trigger metric for the volume calculation Position lower_left_; //!< Lower-left position of bounding box Position upper_right_; //!< Upper-right position of bounding box std::vector domain_ids_; //!< IDs of domains to find volumes of diff --git a/src/volume_calc.cpp b/src/volume_calc.cpp index 32b6f03e2..b354b1db6 100644 --- a/src/volume_calc.cpp +++ b/src/volume_calc.cpp @@ -80,11 +80,11 @@ VolumeCalculation::VolumeCalculation(pugi::xml_node node) std::string tmp = get_node_value(threshold_node, "type"); if (tmp == "variance") { - trigger_type_ = VolumeTriggerMetric::VARIANCE; + trigger_type_ = TriggerMetric::variance; } else if (tmp == "std_dev") { - trigger_type_ = VolumeTriggerMetric::STD_DEV; + trigger_type_ = TriggerMetric::standard_deviation; } else if ( tmp == "rel_err") { - trigger_type_ = VolumeTriggerMetric::REL_ERR; + trigger_type_ = TriggerMetric::relative_error; } else { std::stringstream msg; msg << "Invalid volume calculation trigger type '" << tmp << "' provided."; @@ -294,16 +294,16 @@ std::vector VolumeCalculation::execute() const result.iterations = iterations; // update threshold value if needed - if (trigger_type_ != VolumeTriggerMetric::NONE) { + if (trigger_type_ != TriggerMetric::not_active) { double val = 0.0; switch (trigger_type_) { - case VolumeTriggerMetric::STD_DEV: + case TriggerMetric::standard_deviation: val = result.volume[1]; break; - case VolumeTriggerMetric::REL_ERR: + case TriggerMetric::relative_error: val = result.volume[0] == 0.0 ? 0.0 : result.volume[1] / result.volume[0]; break; - case VolumeTriggerMetric::VARIANCE: + case TriggerMetric::variance: val = result.volume[1] * result.volume[1]; break; } @@ -328,7 +328,7 @@ std::vector VolumeCalculation::execute() const } // end domain loop // if no trigger is applied, we're done - if (trigger_type_ == VolumeTriggerMetric::NONE) { return results; } + if (trigger_type_ == TriggerMetric::not_active) { return results; } #ifdef OPENMC_MPI // update maximum error value on all processes @@ -377,18 +377,18 @@ void VolumeCalculation::to_hdf5(const std::string& filename, write_attribute(file_id, "lower_left", lower_left_); write_attribute(file_id, "upper_right", upper_right_); // Write trigger info - if (trigger_type_ != VolumeTriggerMetric::NONE) { + if (trigger_type_ != TriggerMetric::not_active) { write_attribute(file_id, "iterations", results[0].iterations); write_attribute(file_id, "threshold", threshold_); std::string trigger_str; switch(trigger_type_) { - case VolumeTriggerMetric::VARIANCE: + case TriggerMetric::variance: trigger_str = "variance"; break; - case VolumeTriggerMetric::STD_DEV: + case TriggerMetric::standard_deviation: trigger_str = "std_dev"; break; - case VolumeTriggerMetric::REL_ERR: + case TriggerMetric::relative_error: trigger_str = "rel_err"; break; } From 5c723bd360f8b8a73ac7c39b9a2887bdb353ad4f Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Mon, 14 Oct 2019 20:27:18 -0500 Subject: [PATCH 067/158] Keeping Python API checks, but writing number of iterations to results file. --- .../volume_calc/results_true.dat | 18 +++++++++++++ tests/regression_tests/volume_calc/test.py | 27 +++++++++---------- 2 files changed, 31 insertions(+), 14 deletions(-) diff --git a/tests/regression_tests/volume_calc/results_true.dat b/tests/regression_tests/volume_calc/results_true.dat index a31360abc..800356e35 100644 --- a/tests/regression_tests/volume_calc/results_true.dat +++ b/tests/regression_tests/volume_calc/results_true.dat @@ -1,4 +1,7 @@ Volume calculation 0 +Trigger Type: None +Trigger threshold: None +Iterations: 1 Domain 1: 31.47+/-0.07 cm^3 Domain 2: 2.093+/-0.031 cm^3 Domain 3: 2.049+/-0.031 cm^3 @@ -12,6 +15,9 @@ Domain 3: 2.049+/-0.031 cm^3 6 3 O16 (6.85+/-0.10)e+22 7 3 B10 (6.85+/-0.10)e+18 Volume calculation 1 +Trigger Type: None +Trigger threshold: None +Iterations: 1 Domain 1: 4.14+/-0.04 cm^3 Domain 2: 31.47+/-0.07 cm^3 Material Nuclide Atoms @@ -21,6 +27,9 @@ Domain 2: 31.47+/-0.07 cm^3 3 2 U235 (3.482+/-0.008)e+23 4 2 Mo99 (3.482+/-0.008)e+22 Volume calculation 2 +Trigger Type: None +Trigger threshold: None +Iterations: 1 Domain 0: 35.61+/-0.07 cm^3 Universe Nuclide Atoms 0 0 H1 (2.770+/-0.029)e+23 @@ -29,6 +38,9 @@ Domain 0: 35.61+/-0.07 cm^3 3 0 U235 (3.482+/-0.008)e+23 4 0 Mo99 (3.482+/-0.008)e+22 Volume calculation 3 +Trigger Type: std_dev +Trigger threshold: 0.1 +Iterations: 521 Domain 1: 31.47+/-0.10 cm^3 Domain 2: 2.10+/-0.04 cm^3 Domain 3: 2.11+/-0.04 cm^3 @@ -42,6 +54,9 @@ Domain 3: 2.11+/-0.04 cm^3 6 3 O16 (7.06+/-0.14)e+22 7 3 B10 (7.06+/-0.14)e+18 Volume calculation 4 +Trigger Type: rel_err +Trigger threshold: 0.1 +Iterations: 10 Domain 1: 4.5+/-0.4 cm^3 Domain 2: 30.5+/-0.7 cm^3 Material Nuclide Atoms @@ -51,6 +66,9 @@ Domain 2: 30.5+/-0.7 cm^3 3 2 U235 (3.38+/-0.08)e+23 4 2 Mo99 (3.38+/-0.08)e+22 Volume calculation 5 +Trigger Type: variance +Trigger threshold: 0.05 +Iterations: 105 Domain 1: 31.51+/-0.22 cm^3 Domain 2: 2.13+/-0.10 cm^3 Domain 3: 2.11+/-0.10 cm^3 diff --git a/tests/regression_tests/volume_calc/test.py b/tests/regression_tests/volume_calc/test.py index 96acf59b9..ae4987f1c 100644 --- a/tests/regression_tests/volume_calc/test.py +++ b/tests/regression_tests/volume_calc/test.py @@ -13,13 +13,8 @@ class VolumeTest(PyAPITestHarness): super().__init__(*args, **kwargs) self.exp_std_dev = 1e-01 - self.std_dev_iters = 521 - self.exp_rel_err = 1e-01 - self.rel_err_iters = 10 - self.exp_variance = 5e-02 - self.variance_iters = 105 def _build_inputs(self): # Define materials @@ -85,29 +80,33 @@ class VolumeTest(PyAPITestHarness): # Read volume calculation results volume_calc = openmc.VolumeCalculation.from_hdf5(filename) + outstr += 'Trigger Type: {}\n'.format(volume_calc.trigger_type) + outstr += 'Trigger threshold: {}\n'.format(volume_calc.threshold) + outstr += 'Iterations: {}\n'.format(volume_calc.iterations) + if i == 3: assert(volume_calc.trigger_type == 'std_dev') assert(volume_calc.threshold == self.exp_std_dev) - assert(volume_calc.iterations == self.std_dev_iters) - for vol in volume_calc.volumes.values(): - assert(vol.std_dev <= self.exp_std_dev) elif i == 4: assert(volume_calc.trigger_type == 'rel_err') assert(volume_calc.threshold == self.exp_rel_err) - assert(volume_calc.iterations == self.rel_err_iters) - for vol in volume_calc.volumes.values(): - assert(vol.std_dev/vol.nominal_value <= self.exp_rel_err) elif i == 5: assert(volume_calc.trigger_type == 'variance') assert(volume_calc.threshold == self.exp_variance) - assert(volume_calc.iterations == self.variance_iters) - for vol in volume_calc.volumes.values(): - assert(vol.std_dev * vol.std_dev <= self.exp_variance) else: assert(volume_calc.trigger_type == None) assert(volume_calc.threshold == None) assert(volume_calc.iterations == 1) + # if a trigger is applied, make sure the calculation satisfies the trigger + for vol in volume_calc.volumes.values(): + if volume_calc.trigger_type == 'std_dev': + assert(vol.std_dev <= self.exp_std_dev) + if volume_calc.trigger_type == 'rel_err': + assert(vol.std_dev/vol.nominal_value <= self.exp_rel_err) + if volume_calc.trigger_type == 'variance': + assert(vol.std_dev * vol.std_dev <= self.exp_variance) + # Write cell volumes and total # of atoms for each nuclide for uid, volume in sorted(volume_calc.volumes.items()): outstr += 'Domain {}: {} cm^3\n'.format(uid, volume) From e91a21add239108c9f950125661b0d6fc626eb8d Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Mon, 14 Oct 2019 20:30:25 -0500 Subject: [PATCH 068/158] Simplyfing MPI send to broadcast. --- src/volume_calc.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/volume_calc.cpp b/src/volume_calc.cpp index b354b1db6..a89c67368 100644 --- a/src/volume_calc.cpp +++ b/src/volume_calc.cpp @@ -333,9 +333,7 @@ std::vector VolumeCalculation::execute() const #ifdef OPENMC_MPI // update maximum error value on all processes if (mpi::master) { - for (int i = 1; i < mpi::n_procs; i++) { - MPI_Send(&trigger_val, 1, MPI_DOUBLE, i, 0, mpi::intracomm); - } + MPI_Bcast(&trigger_val, 1, MPI_DOUBLE, mpi:intracomm); } else { MPI_Recv(&trigger_val, 1, MPI_DOUBLE, 0, 0, mpi::intracomm, MPI_STATUS_IGNORE); } From 6c387b66c56620bf5fa506d7b325e0297368370b Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Mon, 14 Oct 2019 20:39:52 -0500 Subject: [PATCH 069/158] Setting volume variance to INF if the domain is unsampled to avoid early trigger exit. --- src/volume_calc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/volume_calc.cpp b/src/volume_calc.cpp index a89c67368..2c4aa8287 100644 --- a/src/volume_calc.cpp +++ b/src/volume_calc.cpp @@ -301,7 +301,7 @@ std::vector VolumeCalculation::execute() const val = result.volume[1]; break; case TriggerMetric::relative_error: - val = result.volume[0] == 0.0 ? 0.0 : result.volume[1] / result.volume[0]; + val = result.volume[0] == 0.0 ? INFTY : result.volume[1] / result.volume[0]; break; case TriggerMetric::variance: val = result.volume[1] * result.volume[1]; From f47e35da75e6c6a8522e1234a4f57669680777ea Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Mon, 14 Oct 2019 20:53:04 -0500 Subject: [PATCH 070/158] Removing blank line. --- tests/regression_tests/volume_calc/test.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/regression_tests/volume_calc/test.py b/tests/regression_tests/volume_calc/test.py index ae4987f1c..f7b9a27a0 100644 --- a/tests/regression_tests/volume_calc/test.py +++ b/tests/regression_tests/volume_calc/test.py @@ -59,7 +59,6 @@ class VolumeTest(PyAPITestHarness): openmc.VolumeCalculation(list(root.cells.values()), 100) ] - vol_calcs[3].set_trigger(self.exp_std_dev, 'std_dev') vol_calcs[4].set_trigger(self.exp_rel_err, 'rel_err') From d213373a4ba18d4bea3a13b8d576b823d758d9d9 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Mon, 14 Oct 2019 20:55:52 -0500 Subject: [PATCH 071/158] Converting to unsigned long long for number of samples in volume calc. --- src/volume_calc.cpp | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/volume_calc.cpp b/src/volume_calc.cpp index 2c4aa8287..aa685e353 100644 --- a/src/volume_calc.cpp +++ b/src/volume_calc.cpp @@ -59,14 +59,7 @@ VolumeCalculation::VolumeCalculation(pugi::xml_node node) domain_ids_ = get_node_array(node, "domain_ids"); lower_left_ = get_node_array(node, "lower_left"); upper_right_ = get_node_array(node, "upper_right"); - std::stringstream size_t_stream(get_node_value(node, "samples")); - size_t_stream >> n_samples_; - if (size_t_stream.fail()) { - std::stringstream msg; - msg << "Could not read number of samples (" - << size_t_stream.str() << ")"; - fatal_error(msg); - } + n_samples_ = std::stoull(get_node_value(node, "samples")); if (check_for_node(node, "threshold")) { pugi::xml_node threshold_node = node.child("threshold"); From dc5fe42af3deda3f43263203e9e7aca9fc158bd1 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Tue, 15 Oct 2019 00:40:58 -0500 Subject: [PATCH 072/158] Update src/volume_calc.cpp Co-Authored-By: Paul Romano --- src/volume_calc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/volume_calc.cpp b/src/volume_calc.cpp index aa685e353..0c91c463e 100644 --- a/src/volume_calc.cpp +++ b/src/volume_calc.cpp @@ -326,7 +326,7 @@ std::vector VolumeCalculation::execute() const #ifdef OPENMC_MPI // update maximum error value on all processes if (mpi::master) { - MPI_Bcast(&trigger_val, 1, MPI_DOUBLE, mpi:intracomm); + MPI_Bcast(&trigger_val, 1, MPI_DOUBLE, 0, mpi::intracomm); } else { MPI_Recv(&trigger_val, 1, MPI_DOUBLE, 0, 0, mpi::intracomm, MPI_STATUS_IGNORE); } From 67907e53d9279eefb9a138e82e449bcb965550c9 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Tue, 15 Oct 2019 00:43:21 -0500 Subject: [PATCH 073/158] Removing if block in MPI ifdef. --- src/volume_calc.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/volume_calc.cpp b/src/volume_calc.cpp index 0c91c463e..419bf0ea5 100644 --- a/src/volume_calc.cpp +++ b/src/volume_calc.cpp @@ -325,11 +325,7 @@ std::vector VolumeCalculation::execute() const #ifdef OPENMC_MPI // update maximum error value on all processes - if (mpi::master) { - MPI_Bcast(&trigger_val, 1, MPI_DOUBLE, 0, mpi::intracomm); - } else { - MPI_Recv(&trigger_val, 1, MPI_DOUBLE, 0, 0, mpi::intracomm, MPI_STATUS_IGNORE); - } + MPI_Bcast(&trigger_val, 1, MPI_DOUBLE, 0, mpi::intracomm); #endif // return results of the calculation From 4950392fd09c47de7c88a4e6c8098f1ffe62877d Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 16 Oct 2019 10:57:45 +0700 Subject: [PATCH 074/158] Support for setting rotation matrix directly --- include/openmc/cell.h | 8 ++--- openmc/cell.py | 27 ++++++++------ openmc/summary.py | 5 +-- src/cell.cpp | 60 ++++++++++++++++++------------- src/position.cpp | 4 +-- tests/unit_tests/test_geometry.py | 21 +++++++++++ 6 files changed, 82 insertions(+), 43 deletions(-) diff --git a/include/openmc/cell.h b/include/openmc/cell.h index 7206938c4..8a330060c 100644 --- a/include/openmc/cell.h +++ b/include/openmc/cell.h @@ -179,10 +179,10 @@ public: //! \brief Rotational tranfsormation of the filled universe. // - //! The vector is empty if there is no rotation. Otherwise, the first three - //! values are the rotation angles respectively about the x-, y-, and z-, axes - //! in degrees. The next 9 values give the rotation matrix in row-major - //! order. + //! The vector is empty if there is no rotation. Otherwise, the first 9 values + //! give the rotation matrix in row-major order. When the user specifies + //! rotation angles about the x-, y- and z- axes in degrees, these values are + //! also present at the end of the vector, making it of length 12. std::vector rotation_; std::vector offset_; //!< Distribcell offset table diff --git a/openmc/cell.py b/openmc/cell.py index 3fd70b345..58e3d4889 100644 --- a/openmc/cell.py +++ b/openmc/cell.py @@ -63,6 +63,10 @@ class Cell(IDManagerMixin): \sin\phi \sin\theta \sin\psi & -\sin\phi \cos\psi + \cos\phi \sin\theta \sin\psi \\ -\sin\theta & \sin\phi \cos\theta & \cos\phi \cos\theta \end{array} \right ] + + A rotation matrix can also be specified directly by setting this + attribute to a nested list (or 2D numpy array) that specifies each + element of the matrix. rotation_matrix : numpy.ndarray The rotation matrix defined by the angles specified in the :attr:`Cell.rotation` property. @@ -227,21 +231,24 @@ class Cell(IDManagerMixin): @rotation.setter def rotation(self, rotation): - cv.check_type('cell rotation', rotation, Iterable, Real) cv.check_length('cell rotation', rotation, 3) self._rotation = np.asarray(rotation) # Save rotation matrix -- the reason we do this instead of having it be # automatically calculated when the rotation_matrix property is accessed # is so that plotting on a rotated geometry can be done faster. - phi, theta, psi = self.rotation*(-pi/180.) - c3, s3 = cos(phi), sin(phi) - c2, s2 = cos(theta), sin(theta) - c1, s1 = cos(psi), sin(psi) - self._rotation_matrix = np.array([ - [c1*c2, c1*s2*s3 - c3*s1, s1*s3 + c1*c3*s2], - [c2*s1, c1*c3 + s1*s2*s3, c3*s1*s2 - c1*s3], - [-s2, c2*s3, c2*c3]]) + if self._rotation.ndim == 2: + # User specified rotation matrix directly + self._rotation_matrix = self._rotation + else: + phi, theta, psi = self.rotation*(-pi/180.) + c3, s3 = cos(phi), sin(phi) + c2, s2 = cos(theta), sin(theta) + c1, s1 = cos(psi), sin(psi) + self._rotation_matrix = np.array([ + [c1*c2, c1*s2*s3 - c3*s1, s1*s3 + c1*c3*s2], + [c2*s1, c1*c3 + s1*s2*s3, c3*s1*s2 - c1*s3], + [-s2, c2*s3, c2*c3]]) @translation.setter def translation(self, translation): @@ -516,7 +523,7 @@ class Cell(IDManagerMixin): element.set("translation", ' '.join(map(str, self.translation))) if self.rotation is not None: - element.set("rotation", ' '.join(map(str, self.rotation))) + element.set("rotation", ' '.join(map(str, self.rotation.ravel()))) return element diff --git a/openmc/summary.py b/openmc/summary.py index 6b8471977..bcb3ba33b 100644 --- a/openmc/summary.py +++ b/openmc/summary.py @@ -154,8 +154,9 @@ class Summary(object): if 'rotation' in group: rotation = group['rotation'][()] - rotation = np.asarray(rotation, dtype=np.int) - cell._rotation = rotation + if rotation.size == 9: + rotation.shape = (3, 3) + cell.rotation = rotation elif fill_type == 'material': cell.temperature = group['temperature'][()] diff --git a/src/cell.cpp b/src/cell.cpp index 3a7a2598f..3a7d0cdd4 100644 --- a/src/cell.cpp +++ b/src/cell.cpp @@ -1,8 +1,10 @@ #include "openmc/cell.h" +#include #include #include +#include #include #include #include @@ -438,35 +440,39 @@ CSGCell::CSGCell(pugi::xml_node cell_node) } auto rot {get_node_array(cell_node, "rotation")}; - if (rot.size() != 3) { + if (rot.size() != 3 && rot.size() != 9) { std::stringstream err_msg; err_msg << "Non-3D rotation vector applied to cell " << id_; fatal_error(err_msg); } - // Store the rotation angles. - rotation_.reserve(12); - rotation_.push_back(rot[0]); - rotation_.push_back(rot[1]); - rotation_.push_back(rot[2]); - // Compute and store the rotation matrix. - auto phi = -rot[0] * PI / 180.0; - auto theta = -rot[1] * PI / 180.0; - auto psi = -rot[2] * PI / 180.0; - rotation_.push_back(std::cos(theta) * std::cos(psi)); - rotation_.push_back(-std::cos(phi) * std::sin(psi) - + std::sin(phi) * std::sin(theta) * std::cos(psi)); - rotation_.push_back(std::sin(phi) * std::sin(psi) - + std::cos(phi) * std::sin(theta) * std::cos(psi)); - rotation_.push_back(std::cos(theta) * std::sin(psi)); - rotation_.push_back(std::cos(phi) * std::cos(psi) - + std::sin(phi) * std::sin(theta) * std::sin(psi)); - rotation_.push_back(-std::sin(phi) * std::cos(psi) - + std::cos(phi) * std::sin(theta) * std::sin(psi)); - rotation_.push_back(-std::sin(theta)); - rotation_.push_back(std::sin(phi) * std::cos(theta)); - rotation_.push_back(std::cos(phi) * std::cos(theta)); + rotation_.reserve(rot.size() == 9 ? 9 : 12); + if (rot.size() == 3) { + double phi = -rot[0] * PI / 180.0; + double theta = -rot[1] * PI / 180.0; + double psi = -rot[2] * PI / 180.0; + rotation_.push_back(std::cos(theta) * std::cos(psi)); + rotation_.push_back(-std::cos(phi) * std::sin(psi) + + std::sin(phi) * std::sin(theta) * std::cos(psi)); + rotation_.push_back(std::sin(phi) * std::sin(psi) + + std::cos(phi) * std::sin(theta) * std::cos(psi)); + rotation_.push_back(std::cos(theta) * std::sin(psi)); + rotation_.push_back(std::cos(phi) * std::cos(psi) + + std::sin(phi) * std::sin(theta) * std::sin(psi)); + rotation_.push_back(-std::sin(phi) * std::cos(psi) + + std::cos(phi) * std::sin(theta) * std::sin(psi)); + rotation_.push_back(-std::sin(theta)); + rotation_.push_back(std::sin(phi) * std::cos(theta)); + rotation_.push_back(std::cos(phi) * std::cos(theta)); + + // When user specifies angles, write them at end of vector + rotation_.push_back(rot[0]); + rotation_.push_back(rot[1]); + rotation_.push_back(rot[2]); + } else { + std::copy(rot.begin(), rot.end(), std::back_inserter(rotation_)); + } } } @@ -578,8 +584,12 @@ CSGCell::to_hdf5(hid_t cell_group) const write_dataset(group, "translation", translation_); } if (!rotation_.empty()) { - std::array rot {rotation_[0], rotation_[1], rotation_[2]}; - write_dataset(group, "rotation", rot); + if (rotation_.size() == 12) { + std::array rot {rotation_[9], rotation_[10], rotation_[11]}; + write_dataset(group, "rotation", rot); + } else { + write_dataset(group, "rotation", rotation_); + } } } else if (type_ == FILL_LATTICE) { diff --git a/src/position.cpp b/src/position.cpp index 1215bfb12..d29e8d81c 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -88,9 +88,9 @@ Position Position::rotate(const std::vector& rotation) const { return { + x*rotation[0] + y*rotation[1] + z*rotation[2], x*rotation[3] + y*rotation[4] + z*rotation[5], - x*rotation[6] + y*rotation[7] + z*rotation[8], - x*rotation[9] + y*rotation[10] + z*rotation[11] + x*rotation[6] + y*rotation[7] + z*rotation[8] }; } diff --git a/tests/unit_tests/test_geometry.py b/tests/unit_tests/test_geometry.py index 69211f72e..70d90b615 100644 --- a/tests/unit_tests/test_geometry.py +++ b/tests/unit_tests/test_geometry.py @@ -280,3 +280,24 @@ def test_from_xml(run_in_tmpdir, mixed_lattice_model): 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)) + + +def test_rotation_matrix(): + """Test ability to set a rotation matrix directly""" + y = openmc.YPlane() + cyl1 = openmc.ZCylinder(r=1.0) + cyl2 = openmc.ZCylinder(r=2.0, boundary_type='vacuum') + + # Create a universe and then reflect in the y-direction + c1 = openmc.Cell(region=-cyl1 & +y) + c2 = openmc.Cell(region=+cyl1 & +y) + c3 = openmc.Cell(region=-y) + univ = openmc.Universe(cells=[c1, c2, c3]) + c = openmc.Cell(fill=univ, region=-cyl2) + c.rotation = [[1, 0, 0], [0, -1, 0], [0, 0, 1]] + assert np.all(c.rotation_matrix == c.rotation) + geom = openmc.Geometry([c]) + + assert geom.find((0.0, 0.5, 0.0))[-1] == c3 + assert geom.find((0.0, -0.5, 0.0))[-1] == c1 + assert geom.find((0.0, -1.5, 0.0))[-1] == c2 From bb7b9e570bd1e06b2ece8835e4bf83cdcf42ca1a Mon Sep 17 00:00:00 2001 From: Jingang Liang Date: Sun, 20 Oct 2019 14:11:21 +0800 Subject: [PATCH 075/158] create redundant xs upon requested --- openmc/data/neutron.py | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/openmc/data/neutron.py b/openmc/data/neutron.py index ea14be784..7420387da 100644 --- a/openmc/data/neutron.py +++ b/openmc/data/neutron.py @@ -118,7 +118,12 @@ class IncidentNeutron(EqualityMixin): if mt in self.reactions: return self.reactions[mt] else: - raise KeyError('No reaction with MT={}.'.format(mt)) + # Try to create a redundant cross section + mts = self.get_reaction_components(mt) + if len(mts) > 0: + return self._get_redundant_reaction(mt, mts) + else: + raise KeyError('No reaction with MT={}.'.format(mt)) def __repr__(self): return "".format(self.name) @@ -911,16 +916,17 @@ class IncidentNeutron(EqualityMixin): Redundant reaction """ - # Get energy grid - strT = self.temperatures[0] - energy = self.energy[strT] rx = Reaction(mt) - xss = [self.reactions[mt_i].xs[strT] for mt_i in mts] - idx = min([xs._threshold_idx if hasattr(xs, '_threshold_idx') - else 0 for xs in xss]) - rx.xs[strT] = Tabulated1D(energy[idx:], Sum(xss)(energy[idx:])) - rx.xs[strT]._threshold_idx = idx + # Get energy grid + for strT in self.temperatures: + energy = self.energy[strT] + xss = [self.reactions[mt_i].xs[strT] for mt_i in mts] + idx = min([xs._threshold_idx if hasattr(xs, '_threshold_idx') + else 0 for xs in xss]) + rx.xs[strT] = Tabulated1D(energy[idx:], Sum(xss)(energy[idx:])) + rx.xs[strT]._threshold_idx = idx + rx.redundant = True return rx From a3bb85c35896866b9ace72f8b0bc97fea1e10143 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Wed, 23 Oct 2019 08:55:34 -0500 Subject: [PATCH 076/158] Updating Python mesh class string representations. --- openmc/mesh.py | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/openmc/mesh.py b/openmc/mesh.py index 0a8b51c5f..e6bd96754 100644 --- a/openmc/mesh.py +++ b/openmc/mesh.py @@ -53,6 +53,12 @@ class MeshBase(IDManagerMixin, metaclass=ABCMeta): else: self._name = '' + def __repr__(self): + string = type(self).__name__ + '\n' + string += '{0: <16}{1}{2}\n'.format('\tID', '=\t', self._id) + string += '{0: <16}{1}{2}\n'.format('\tName', '=\t', self._name) + return string + @classmethod def from_hdf5(cls, group): """Create mesh from HDF5 group @@ -126,7 +132,10 @@ class RegularMesh(MeshBase): @property def n_dimension(self): - return len(self._dimension) + if self._dimension is not None: + return len(self._dimension) + else: + return None @property def lower_left(self): @@ -187,11 +196,9 @@ class RegularMesh(MeshBase): self._width = width def __repr__(self): - string = 'RegularMesh\n' - string += '{0: <16}{1}{2}\n'.format('\tID', '=\t', self._id) - string += '{0: <16}{1}{2}\n'.format('\tName', '=\t', self._name) - string += '{0: <16}{1}{2}\n'.format('\tType', '=\t', self._type) - string += '{0: <16}{1}{2}\n'.format('\tBasis', '=\t', self._dimension) + string = super().__repr__() + string += '{0: <16}{1}{2}\n'.format('\tDimensions', '=\t', self.n_dimension) + string += '{0: <16}{1}{2}\n'.format('\tMesh Cells', '=\t', self._dimension) string += '{0: <16}{1}{2}\n'.format('\tWidth', '=\t', self._lower_left) string += '{0: <16}{1}{2}\n'.format('\tOrigin', '=\t', self._upper_right) string += '{0: <16}{1}{2}\n'.format('\tPixels', '=\t', self._width) @@ -522,6 +529,17 @@ class RectilinearMesh(MeshBase): cv.check_type('mesh z_grid', grid, Iterable, Real) self._z_grid = grid + def __repr__(self): + string = super().__repr__() + string += '{0: <16}{1}{2}\n'.format('\tDimensions', '=\t', self.n_dimension) + x_grid_str = str(self._x_grid) if not self._x_grid else len(self._x_grid) + y_grid_str = str(self._y_grid) if not self._y_grid else len(self._y_grid) + z_grid_str = str(self._z_grid) if not self._z_grid else len(self._z_grid) + string += '{0: <16}{1}{2}\n'.format('\tx pnts:', '=\t', x_grid_str) + string += '{0: <16}{1}{2}\n'.format('\ty pnts:', '=\t', y_grid_str) + string += '{0: <16}{1}{2}\n'.format('\tz pnts:', '=\t', z_grid_str) + return string + @classmethod def from_hdf5(cls, group): mesh_id = int(group.name.split('/')[-1].lstrip('mesh ')) From 392f4461445b16cdb961449494ee1dc4575cef4c Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Wed, 23 Oct 2019 10:33:26 -0500 Subject: [PATCH 077/158] More accurate description of rectilinear mesh attribute. --- openmc/mesh.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/openmc/mesh.py b/openmc/mesh.py index e6bd96754..6ef8776fe 100644 --- a/openmc/mesh.py +++ b/openmc/mesh.py @@ -530,14 +530,24 @@ class RectilinearMesh(MeshBase): self._z_grid = grid def __repr__(self): + fmt = '{0: <16}{1}{2}\n' string = super().__repr__() - string += '{0: <16}{1}{2}\n'.format('\tDimensions', '=\t', self.n_dimension) + string += fmt.format('\tDimensions', '=\t', self.n_dimension) x_grid_str = str(self._x_grid) if not self._x_grid else len(self._x_grid) + string += fmt.format('\tN X pnts:', '=\t', x_grid_str) + if self._x_grid: + string += fmt.format('\tX Min:', '=\t', self._x_grid[0]) + string += fmt.format('\tX Max:', '=\t', self._x_grid[-1]) y_grid_str = str(self._y_grid) if not self._y_grid else len(self._y_grid) + string += fmt.format('\tN Y pnts:', '=\t', y_grid_str) + if self._y_grid: + string += fmt.format('\tY Min:', '=\t', self._y_grid[0]) + string += fmt.format('\tY Max:', '=\t', self._y_grid[-1]) z_grid_str = str(self._z_grid) if not self._z_grid else len(self._z_grid) - string += '{0: <16}{1}{2}\n'.format('\tx pnts:', '=\t', x_grid_str) - string += '{0: <16}{1}{2}\n'.format('\ty pnts:', '=\t', y_grid_str) - string += '{0: <16}{1}{2}\n'.format('\tz pnts:', '=\t', z_grid_str) + string += fmt.format('\tN Z pnts:', '=\t', z_grid_str) + if self._z_grid: + string += fmt.format('\tZ Min:', '=\t', self._z_grid[0]) + string += fmt.format('\tZ Max:', '=\t', self._z_grid[-1]) return string @classmethod From a51108ba42527a026fe30a38c5d04a5d320c08ed Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Wed, 23 Oct 2019 16:33:18 -0500 Subject: [PATCH 078/158] Remove un-needed indexing of nuclide value. --- openmc/mgxs/library.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openmc/mgxs/library.py b/openmc/mgxs/library.py index fbf08f85f..83d3178ff 100644 --- a/openmc/mgxs/library.py +++ b/openmc/mgxs/library.py @@ -986,7 +986,7 @@ class Library(object): xsdata.num_azimuthal = self.num_azimuthal if nuclide != 'total': - xsdata.atomic_weight_ratio = self._nuclides[nuclide][1] + xsdata.atomic_weight_ratio = self._nuclides[nuclide] if subdomain is None: subdomain = 'all' From 521964149f39d66643d40a546eb254a52f4403c1 Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Mon, 28 Oct 2019 11:15:53 -0400 Subject: [PATCH 079/158] Fix tally mesh bug for very short tracks --- src/mesh.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/mesh.cpp b/src/mesh.cpp index ac02b679e..d6da64bb7 100644 --- a/src/mesh.cpp +++ b/src/mesh.cpp @@ -523,6 +523,14 @@ void RegularMesh::bins_crossed(const Particle* p, std::vector& bins, } r1 = r; + // The TINY_BIT offsets above mean that the preceding logic cannot always find + // the correct ijk0 and ijk1 indices. For tracks shorter than 2*TINY_BIT, just + // assume the track lies in only one mesh bin. These tracks are very short so + // any error caused by this assumption will be small. + if (total_distance < 2*TINY_BIT) { + for (int i = 0; i < n; ++i) ijk0[i] = ijk1[i]; + } + // ======================================================================== // Find which mesh cells are traversed and the length of each traversal. @@ -898,6 +906,14 @@ void RectilinearMesh::bins_crossed(const Particle* p, std::vector& bins, } r1 = r; + // The TINY_BIT offsets above mean that the preceding logic cannot always find + // the correct ijk0 and ijk1 indices. For tracks shorter than 2*TINY_BIT, just + // assume the track lies in only one mesh bin. These tracks are very short so + // any error caused by this assumption will be small. + if (total_distance < 2*TINY_BIT) { + for (int i = 0; i < 3; ++i) ijk0[i] = ijk1[i]; + } + // ======================================================================== // Find which mesh cells are traversed and the length of each traversal. From 4d4c174a1bee3c36ad5b43fdcef9da884b462d23 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Mon, 28 Oct 2019 21:43:26 -0500 Subject: [PATCH 080/158] Allow voxel plots to be colored by material --- src/plot.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/plot.cpp b/src/plot.cpp index 98a3645c7..ba63da16b 100644 --- a/src/plot.cpp +++ b/src/plot.cpp @@ -908,11 +908,13 @@ void create_voxel(Plot pl) // generate ids using plotbase IdData ids = pltbase.get_map(); - // select only cell ID data and flip the y-axis - xt::xtensor data1 = xt::flip(xt::view(ids.data_, xt::all(), xt::all(), 0), 0); + // select only cell/material ID data and flip the y-axis + int idx = pl.color_by_ == PlotColorBy::cells ? 0 : 1; + xt::xtensor data_slice = xt::view(ids.data_, xt::all(), xt::all(), idx); + xt::xtensor data_flipped = xt::flip(data_slice, 0); // Write to HDF5 dataset - voxel_write_slice(z, dspace, dset, memspace, &(data1(0,0))); + voxel_write_slice(z, dspace, dset, memspace, data_flipped.data()); } voxel_finalize(dspace, dset, memspace); From 90288f2a62d39ca62799f19c042b7c81a8a40912 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 30 Oct 2019 16:01:31 -0500 Subject: [PATCH 081/158] Export targets from CMakeLists.txt --- CMakeLists.txt | 58 +++++++++++++++++++++++++++++++--------- cmake/OpenMCConfig.cmake | 8 ++++++ 2 files changed, 53 insertions(+), 13 deletions(-) create mode 100644 cmake/OpenMCConfig.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 626aadae8..6acfcf2c8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -114,7 +114,11 @@ endif() #=============================================================================== add_library(pugixml vendor/pugixml/pugixml.cpp) -target_include_directories(pugixml PUBLIC vendor/pugixml/) +target_include_directories(pugixml + PUBLIC + $ + $ +) #=============================================================================== # xtensor header-only library @@ -134,7 +138,11 @@ target_link_libraries(xtensor INTERFACE xtl) #=============================================================================== add_library(gsl INTERFACE) -target_include_directories(gsl INTERFACE vendor/gsl/include) +target_include_directories(gsl + INTERFACE + $ + $ +) # Make sure contract violations throw exceptions target_compile_definitions(gsl INTERFACE GSL_THROW_ON_CONTRACT_VIOLATION) @@ -172,7 +180,11 @@ endif() #=============================================================================== add_library(faddeeva STATIC vendor/faddeeva/Faddeeva.cc) -target_include_directories(faddeeva PUBLIC vendor/faddeeva/) +target_include_directories(faddeeva + PUBLIC + $ + $ +) target_compile_options(faddeeva PRIVATE ${cxxflags}) #=============================================================================== @@ -283,7 +295,11 @@ set_target_properties(libopenmc PROPERTIES OUTPUT_NAME openmc) target_include_directories(libopenmc - PUBLIC include ${HDF5_INCLUDE_DIRS}) + PUBLIC + $ + $ + ${HDF5_INCLUDE_DIRS} +) # Set compile flags target_compile_options(libopenmc PRIVATE ${cxxflags}) @@ -343,12 +359,28 @@ add_custom_command(TARGET libopenmc POST_BUILD # Install executable, scripts, manpage, license #=============================================================================== -install(TARGETS openmc libopenmc - RUNTIME DESTINATION bin - LIBRARY DESTINATION lib - ARCHIVE DESTINATION lib - ) -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) +include(GNUInstallDirs) +set(INSTALL_CONFIGDIR ${CMAKE_INSTALL_LIBDIR}/cmake/OpenMC) +install(TARGETS openmc libopenmc pugixml faddeeva gsl + EXPORT openmc-targets + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} +) +install(EXPORT openmc-targets + FILE OpenMCTargets.cmake + NAMESPACE OpenMC:: + DESTINATION ${INSTALL_CONFIGDIR}) + +install(DIRECTORY src/relaxng DESTINATION ${CMAKE_INSTALL_DATADIR}/openmc) +install(FILES cmake/OpenMCConfig.cmake DESTINATION ${INSTALL_CONFIGDIR}) +install(FILES man/man1/openmc.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1) +install(FILES LICENSE DESTINATION "${CMAKE_INSTALL_DOCDIR}" RENAME copyright) +install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) + +# Copy headers for vendored dependencies (note that xtensor/xtl are handled +# separately since they are managed by CMake) +install(DIRECTORY vendor/pugixml DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + FILES_MATCHING PATTERN "*.hpp") +install(DIRECTORY vendor/gsl DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) +install(DIRECTORY vendor/faddeeva DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) diff --git a/cmake/OpenMCConfig.cmake b/cmake/OpenMCConfig.cmake new file mode 100644 index 000000000..0bc86fa71 --- /dev/null +++ b/cmake/OpenMCConfig.cmake @@ -0,0 +1,8 @@ +get_filename_component(OpenMC_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" DIRECTORY) + +find_package(xtl REQUIRED HINTS ${OpenMC_CMAKE_DIR}/../xtl) +find_package(xtensor REQUIRED HINTS ${OpenMC_CMAKE_DIR}/../xtensor) + +if(NOT TARGET OpenMC::libopenmc) + include("${OpenMC_CMAKE_DIR}/OpenMCTargets.cmake") +endif() From 739419b8b737e8cf0e058d31e91505670e87367d Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Mon, 28 Oct 2019 13:23:58 -0500 Subject: [PATCH 082/158] Exposing write summary settings option to CAPI. --- include/openmc/settings.h | 2 +- openmc/lib/settings.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/include/openmc/settings.h b/include/openmc/settings.h index 8f4376717..45cb7394c 100644 --- a/include/openmc/settings.h +++ b/include/openmc/settings.h @@ -31,7 +31,7 @@ extern "C" bool cmfd_run; //!< is a CMFD run? extern "C" bool dagmc; //!< indicator of DAGMC geometry extern "C" bool entropy_on; //!< calculate Shannon entropy? extern bool legendre_to_tabular; //!< convert Legendre distributions to tabular? -extern bool output_summary; //!< write summary.h5? +extern "C" bool output_summary; //!< write summary.h5? extern bool output_tallies; //!< write tallies.out? extern bool particle_restart_run; //!< particle restart run? extern "C" bool photon_transport; //!< photon transport turned on? diff --git a/openmc/lib/settings.py b/openmc/lib/settings.py index 78794d856..275c73a93 100644 --- a/openmc/lib/settings.py +++ b/openmc/lib/settings.py @@ -26,6 +26,7 @@ class _Settings(object): restart_run = _DLLGlobal(c_bool, 'restart_run') run_CE = _DLLGlobal(c_bool, 'run_CE') verbosity = _DLLGlobal(c_int, 'verbosity') + output_summary = _DLLGlobal(c_bool, 'output_summary') @property def run_mode(self): From ecbc05ce14fc4a0499ead169d03ef8fa0ca13e69 Mon Sep 17 00:00:00 2001 From: Alec Golas Date: Thu, 31 Oct 2019 16:46:49 -0400 Subject: [PATCH 083/158] Update operator.py Changed burnable material volume to volume of material instance --- openmc/deplete/operator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openmc/deplete/operator.py b/openmc/deplete/operator.py index e3a767e57..d8aeb33fd 100644 --- a/openmc/deplete/operator.py +++ b/openmc/deplete/operator.py @@ -341,7 +341,7 @@ class Operator(TransportOperator): if mat.volume is None: raise RuntimeError("Volume not specified for depletable " "material with ID={}.".format(mat.id)) - volume[str(mat.id)] = mat.volume + volume[str(mat.id)] = mat.volume/mat.num_instances self.heavy_metal += mat.fissionable_mass # Make sure there are burnable materials From 4cccdbece4d0874b692c2eb12eca4252b4cec479 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Thu, 24 Jan 2019 11:59:17 -0600 Subject: [PATCH 084/158] Singleton approach to tracking openmc xml elements with sets. --- openmc/cell.py | 7 ++++++- openmc/geomtrack.py | 40 ++++++++++++++++++++++++++++++++++++++++ openmc/lattice.py | 12 +++++++++--- openmc/universe.py | 5 ++++- 4 files changed, 59 insertions(+), 5 deletions(-) create mode 100644 openmc/geomtrack.py diff --git a/openmc/cell.py b/openmc/cell.py index 58e3d4889..dd3d22ed1 100644 --- a/openmc/cell.py +++ b/openmc/cell.py @@ -16,6 +16,7 @@ from openmc.region import Region, Intersection, Complement from openmc._xml import get_text from .mixin import IDManagerMixin +from .geomtrack import ElementTracker class Cell(IDManagerMixin): r"""A region of space defined as the intersection of half-space created by @@ -464,6 +465,7 @@ class Cell(IDManagerMixin): return memo[self] def create_xml_subelement(self, xml_element): + et = ElementTracker() element = ET.Element("cell") element.set("id", str(self.id)) @@ -499,10 +501,13 @@ class Cell(IDManagerMixin): # element for the corresponding surface if none has been created # thus far. def create_surface_elements(node, element): + et = ElementTracker() if isinstance(node, Halfspace): path = "./surface[@id='{}']".format(node.surface.id) - if xml_element.find(path) is None: + if node.surface.id not in et.surfaces: + et.add_surface(node.surface.id) xml_element.append(node.surface.to_xml_element()) + elif isinstance(node, Complement): create_surface_elements(node.node, element) else: diff --git a/openmc/geomtrack.py b/openmc/geomtrack.py new file mode 100644 index 000000000..bf3fcac12 --- /dev/null +++ b/openmc/geomtrack.py @@ -0,0 +1,40 @@ + +class ElementTracker: + class __ElementTracker: + def __init__(self): + self.cells = set() + self.surfaces = set() + self.lattices = set() + self.universes = set() + + def update(self, element_type, element_id): + if element_type == "cell": + self.cells.add(element_id) + elif element_type == "surface": + self.surfaces.add(element_id) + elif element_type == "lattice": + self.lattices.add(element_id) + elif element_type == "universe": + self.universes.add(element_id) + + def add_cell(self, cell_id): + self.update("cell", cell_id) + + def add_surface(self, surface_id): + self.update("surface", surface_id) + + def add_lattice(self, lattice_id): + self.update("lattice", lattice_id) + + def add_universe(self, universe_id): + self.update("universe", universe_id) + + instance = None + + def __init__(self): + if not ElementTracker.instance: + ElementTracker.instance = ElementTracker.__ElementTracker() + else: + pass + def __getattr__(self, name): + return getattr(self.instance, name) diff --git a/openmc/lattice.py b/openmc/lattice.py index 4776222da..c1ce4c6a2 100644 --- a/openmc/lattice.py +++ b/openmc/lattice.py @@ -13,6 +13,7 @@ import openmc from openmc._xml import get_text from openmc.mixin import IDManagerMixin +from .geomtrack import ElementTracker class Lattice(IDManagerMixin, metaclass=ABCMeta): """A repeating structure wherein each element is a universe. @@ -754,14 +755,16 @@ class RectLattice(Lattice): 0 <= idx[2] < self.shape[2]) def create_xml_subelement(self, xml_element): - + et = ElementTracker() # Determine if XML element already contains subelement for this Lattice path = './lattice[@id=\'{0}\']'.format(self._id) test = xml_element.find(path) # If the element does contain the Lattice subelement, then return - if test is not None: + if self._id in et.lattices: return + else: + et.add_lattice(self._id) lattice_subelement = ET.Element("lattice") lattice_subelement.set("id", str(self._id)) @@ -1275,13 +1278,16 @@ class HexLattice(Lattice): return g < self.num_rings and 0 <= idx[2] < self.num_axial def create_xml_subelement(self, xml_element): + et = ElementTracker() # Determine if XML element already contains subelement for this Lattice path = './hex_lattice[@id=\'{0}\']'.format(self._id) test = xml_element.find(path) # If the element does contain the Lattice subelement, then return - if test is not None: + if self._id in et.lattices: return + else: + et.add_lattice(self._id) lattice_subelement = ET.Element("hex_lattice") lattice_subelement.set("id", str(self._id)) diff --git a/openmc/universe.py b/openmc/universe.py index ee038ebef..876883cea 100644 --- a/openmc/universe.py +++ b/openmc/universe.py @@ -12,6 +12,7 @@ import openmc.checkvalue as cv from openmc.plots import _SVG_COLORS from openmc.mixin import IDManagerMixin +from .geomtrack import ElementTracker class Universe(IDManagerMixin): """A collection of cells that can be repeated. @@ -513,12 +514,14 @@ class Universe(IDManagerMixin): return memo[self] def create_xml_subelement(self, xml_element): + et = ElementTracker() # Iterate over all Cells for cell_id, cell in self._cells.items(): path = "./cell[@id='{}']".format(cell_id) # If the cell was not already written, write it - if xml_element.find(path) is None: + if cell_id not in et.cells: + et.add_cell(cell_id) # Create XML subelement for this Cell cell_element = cell.create_xml_subelement(xml_element) From e12f7c9041281ca37a1bc9f2ac54bd6870f2e180 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Thu, 31 Jan 2019 10:30:38 -0600 Subject: [PATCH 085/158] Adding reset before exporting a geometry. --- openmc/geometry.py | 5 +++++ openmc/geomtrack.py | 6 ++++++ 2 files changed, 11 insertions(+) diff --git a/openmc/geometry.py b/openmc/geometry.py index 260bb9e83..61032d9a8 100644 --- a/openmc/geometry.py +++ b/openmc/geometry.py @@ -10,6 +10,7 @@ import openmc import openmc._xml as xml from openmc.checkvalue import check_type +from .geomtrack import ElementTracker class Geometry(object): """Geometry representing a collection of surfaces, cells, and universes. @@ -87,6 +88,10 @@ class Geometry(object): """ # Create XML representation + + et = ElementTracker() + et.reset() + root_element = ET.Element("geometry") self.root_universe.create_xml_subelement(root_element) diff --git a/openmc/geomtrack.py b/openmc/geomtrack.py index bf3fcac12..f2230ce7d 100644 --- a/openmc/geomtrack.py +++ b/openmc/geomtrack.py @@ -29,6 +29,12 @@ class ElementTracker: def add_universe(self, universe_id): self.update("universe", universe_id) + def reset(self): + self.cells = set() + self.surfaces = set() + self.lattices = set() + self.universes = set() + instance = None def __init__(self): From f281d135fcdabcc28d14bbda97c06344a92e3178 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Wed, 30 Jan 2019 15:23:47 -0600 Subject: [PATCH 086/158] Adding singleton class for tracking cell counts. --- src/geometry_aux.cpp | 99 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 88 insertions(+), 11 deletions(-) diff --git a/src/geometry_aux.cpp b/src/geometry_aux.cpp index d195a9de3..c6e120fff 100644 --- a/src/geometry_aux.cpp +++ b/src/geometry_aux.cpp @@ -60,6 +60,71 @@ void read_geometry_xml() model::root_universe = find_root_universe(); } + struct CellCountStorage { + private: + CellCountStorage() {} + CellCountStorage(CellCountStorage& c) {} + CellCountStorage(const CellCountStorage& c) {} + + static CellCountStorage* instance_; + + std::map> counts; + + public: + + static CellCountStorage* instance() { + if (instance_ == nullptr) + instance_ = new CellCountStorage; + + return instance_; + } + + void clear() { + if (instance_ != nullptr) { + delete instance_; + instance_ = nullptr; + } + } + + void set_cell_count_for_univ(int32_t univ, int32_t cell, int count) { + counts[univ][cell] = count; + } + + void increment_count_for_univ(int32_t univ, int32_t cell) { + if (has_count(univ,cell)) { + counts[univ][cell] += 1; + } else { + counts[univ][cell] = 1; + } + } + + bool has_count(int32_t univ, int32_t cell) { + return counts.count(univ) && counts[univ].count(cell); + } + + bool has_count(int32_t univ) { + return counts.count(univ); + } + + void absorb_b_into_a(int32_t a, int32_t b) { + std::map b_map = counts[b]; + + for (auto it : b_map) { + if (has_count(a, it.first)) { + counts[a][it.first] += it.second; + } else { + counts[a][it.first] = it.second; + } + } + } + + std::map get_count(int32_t univ) { + return counts[univ]; + } + }; + +CellCountStorage* CellCountStorage::instance_ = nullptr; + //============================================================================== void @@ -395,19 +460,31 @@ prepare_distribcell() void count_cell_instances(int32_t univ_indx) { - for (int32_t cell_indx : model::universes[univ_indx]->cells_) { - Cell& c = *model::cells[cell_indx]; - ++c.n_instances_; + CellCountStorage* counter = CellCountStorage::instance(); - if (c.type_ == FILL_UNIVERSE) { - // This cell contains another universe. Recurse into that universe. - count_cell_instances(c.fill_); + if (counter->has_count(univ_indx)) { + std::map univ_counts = counter->get_count(univ_indx); + for(auto it : univ_counts) { + Cell& c = *model::cells[it.first]; + c.n_instances_ += it.second; + } + } else { + for (int32_t cell_indx : model::universes[univ_indx]->cells_) { + Cell& c = *model::cells[cell_indx]; + ++c.n_instances_; + counter->increment_count_for_univ(univ_indx, cell_indx); - } else if (c.type_ == FILL_LATTICE) { - // This cell contains a lattice. Recurse into the lattice universes. - Lattice& lat = *model::lattices[c.fill_]; - for (auto it = lat.begin(); it != lat.end(); ++it) { - count_cell_instances(*it); + if (c.type_ == FILL_UNIVERSE) { + // This cell contains another universe. Recurse into that universe. + count_cell_instances(c.fill_); + counter->absorb_b_into_a(univ_indx, c.fill_); + } else if (c.type_ == FILL_LATTICE) { + // This cell contains a lattice. Recurse into the lattice universes. + Lattice& lat = *model::lattices[c.fill_]; + for (auto it = lat.begin(); it != lat.end(); ++it) { + count_cell_instances(*it); + counter->absorb_b_into_a(univ_indx, *it); + } } } } From 573a0280b8b13a32544ed0d26b9d441721ff3add Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Wed, 30 Jan 2019 16:17:34 -0600 Subject: [PATCH 087/158] Adding a singleton class for tracking the universe levels as well. --- src/geometry_aux.cpp | 68 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/src/geometry_aux.cpp b/src/geometry_aux.cpp index c6e120fff..00b54ad91 100644 --- a/src/geometry_aux.cpp +++ b/src/geometry_aux.cpp @@ -123,7 +123,68 @@ void read_geometry_xml() } }; + struct LevelCountStorage { + private: + LevelCountStorage() {} + LevelCountStorage(LevelCountStorage& c) {} + LevelCountStorage(const LevelCountStorage& c) {} + + static LevelCountStorage* instance_; + + std::map counts; + + public: + + static LevelCountStorage* instance() { + if (instance_ == nullptr) + instance_ = new LevelCountStorage; + + return instance_; + } + + void clear() { + if (instance_ != nullptr) { + delete instance_; + instance_ = nullptr; + } + } + + void set_cell_count_for_univ(int32_t univ, int count) { + counts[univ] = count; + } + + void increment_count_for_univ(int32_t univ) { + if (has_count(univ)) { + counts[univ] += 1; + } else { + counts[univ] = 1; + } + } + + bool has_count(int32_t univ) { + return counts.count(univ); + } + + void absorb_b_into_a(int32_t a, int32_t b) { + + if (has_count(a)) { + counts[a] += counts[b]; + } else { + counts[a] = counts[b]; + } + } + + void set_count(int32_t univ, int count) { + counts[univ] = count; + } + + int get_count(int32_t univ) { + return counts[univ]; + } + }; + CellCountStorage* CellCountStorage::instance_ = nullptr; +LevelCountStorage* LevelCountStorage::instance_ = nullptr; //============================================================================== @@ -606,6 +667,12 @@ distribcell_path(int32_t target_cell, int32_t map, int32_t target_offset) int maximum_levels(int32_t univ) { + LevelCountStorage* counter = LevelCountStorage::instance(); + + if (counter->has_count(univ)) { + return counter->get_count(univ); + } + int levels_below {0}; for (int32_t cell_indx : model::universes[univ]->cells_) { @@ -623,6 +690,7 @@ maximum_levels(int32_t univ) } ++levels_below; + counter->set_count(univ, levels_below); return levels_below; } From 2a6adc822fce827456b7f27766a37dcda1bc5a50 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Thu, 31 Jan 2019 16:16:24 -0600 Subject: [PATCH 088/158] Formalizing LevelCounter and CellCounter classes. Adding clear call in OpenMC finalize. --- include/openmc/geometry_aux.h | 70 ++++++++++++++++ src/finalize.cpp | 4 + src/geometry_aux.cpp | 148 +++++++++++++++------------------- 3 files changed, 138 insertions(+), 84 deletions(-) diff --git a/include/openmc/geometry_aux.h b/include/openmc/geometry_aux.h index ffcdcf885..557d82193 100644 --- a/include/openmc/geometry_aux.h +++ b/include/openmc/geometry_aux.h @@ -7,8 +7,78 @@ #include #include #include +#include namespace openmc { + struct CellCountStorage { + private: + CellCountStorage() {} + CellCountStorage(CellCountStorage& c) {} + CellCountStorage(const CellCountStorage& c) {} + + static CellCountStorage* instance_; + + std::map> counts; + + public: + + static CellCountStorage* instance() { + if (instance_ == nullptr) + instance_ = new CellCountStorage; + + return instance_; + } + + + + void clear(); + + void set_cell_count_for_univ(int32_t univ, int32_t cell, int count); + + void increment_count_for_univ(int32_t univ, int32_t cell); + + bool has_count(int32_t univ, int32_t cell); + + bool has_count(int32_t univ); + + void absorb_b_into_a(int32_t a, int32_t b); + + auto get_count(int32_t univ); + }; + + struct LevelCountStorage { + private: + LevelCountStorage() {} + LevelCountStorage(LevelCountStorage& c) {} + LevelCountStorage(const LevelCountStorage& c) {} + + static LevelCountStorage* instance_; + + std::map counts; + + public: + + static LevelCountStorage* instance() { + if (instance_ == nullptr) + instance_ = new LevelCountStorage; + + return instance_; + } + + void clear(); + + void set_cell_count_for_univ(int32_t univ, int count); + + void increment_count_for_univ(int32_t univ); + + bool has_count(int32_t univ); + + void absorb_b_into_a(int32_t a, int32_t b); + + void set_count(int32_t univ, int count); + + int get_count(int32_t univ); + }; void read_geometry_xml(); diff --git a/src/finalize.cpp b/src/finalize.cpp index 3de20d6d0..f2cbc973c 100644 --- a/src/finalize.cpp +++ b/src/finalize.cpp @@ -135,6 +135,10 @@ int openmc_finalize() int openmc_reset() { + + CellCountStorage::instance()->clear(); + LevelCountStorage::instance()->clear(); + for (auto& t : model::tallies) { t->reset(); } diff --git a/src/geometry_aux.cpp b/src/geometry_aux.cpp index 00b54ad91..5228bddc1 100644 --- a/src/geometry_aux.cpp +++ b/src/geometry_aux.cpp @@ -85,106 +85,86 @@ void read_geometry_xml() instance_ = nullptr; } } + } - void set_cell_count_for_univ(int32_t univ, int32_t cell, int count) { - counts[univ][cell] = count; + void CellCountStorage::set_cell_count_for_univ(int32_t univ, int32_t cell, int count) { + counts[univ][cell] = count; + } + + void CellCountStorage::increment_count_for_univ(int32_t univ, int32_t cell) { + if (has_count(univ,cell)) { + counts[univ][cell] += 1; + } else { + counts[univ][cell] = 1; } + } - void increment_count_for_univ(int32_t univ, int32_t cell) { - if (has_count(univ,cell)) { - counts[univ][cell] += 1; + bool CellCountStorage::has_count(int32_t univ, int32_t cell) { + return counts.count(univ) && counts[univ].count(cell); + } + + bool CellCountStorage::has_count(int32_t univ) { + return counts.count(univ); + } + + void CellCountStorage::absorb_b_into_a(int32_t a, int32_t b) { + std::map b_map = counts[b]; + + for (auto it : b_map) { + if (has_count(a, it.first)) { + counts[a][it.first] += it.second; } else { - counts[univ][cell] = 1; + counts[a][it.first] = it.second; } } + } - bool has_count(int32_t univ, int32_t cell) { - return counts.count(univ) && counts[univ].count(cell); + auto CellCountStorage::get_count(int32_t univ) { + return counts[univ]; + } + + void LevelCountStorage::clear() { + if (instance_ != nullptr) { + delete instance_; + instance_ = nullptr; } + } - bool has_count(int32_t univ) { - return counts.count(univ); + void LevelCountStorage::set_cell_count_for_univ(int32_t univ, int count) { + counts[univ] = count; + } + + void LevelCountStorage::increment_count_for_univ(int32_t univ) { + if (has_count(univ)) { + counts[univ] += 1; + } else { + counts[univ] = 1; } + } - void absorb_b_into_a(int32_t a, int32_t b) { - std::map b_map = counts[b]; + bool LevelCountStorage::has_count(int32_t univ) { + return counts.count(univ); + } - for (auto it : b_map) { - if (has_count(a, it.first)) { - counts[a][it.first] += it.second; - } else { - counts[a][it.first] = it.second; - } - } + void LevelCountStorage::absorb_b_into_a(int32_t a, int32_t b) { + + if (has_count(a)) { + counts[a] += counts[b]; + } else { + counts[a] = counts[b]; } + } - std::map get_count(int32_t univ) { - return counts[univ]; - } - }; + void LevelCountStorage::set_count(int32_t univ, int count) { + counts[univ] = count; + } - struct LevelCountStorage { - private: - LevelCountStorage() {} - LevelCountStorage(LevelCountStorage& c) {} - LevelCountStorage(const LevelCountStorage& c) {} + int LevelCountStorage::get_count(int32_t univ) { + return counts[univ]; + } - static LevelCountStorage* instance_; - - std::map counts; - - public: - - static LevelCountStorage* instance() { - if (instance_ == nullptr) - instance_ = new LevelCountStorage; - - return instance_; - } - - void clear() { - if (instance_ != nullptr) { - delete instance_; - instance_ = nullptr; - } - } - - void set_cell_count_for_univ(int32_t univ, int count) { - counts[univ] = count; - } - - void increment_count_for_univ(int32_t univ) { - if (has_count(univ)) { - counts[univ] += 1; - } else { - counts[univ] = 1; - } - } - - bool has_count(int32_t univ) { - return counts.count(univ); - } - - void absorb_b_into_a(int32_t a, int32_t b) { - - if (has_count(a)) { - counts[a] += counts[b]; - } else { - counts[a] = counts[b]; - } - } - - void set_count(int32_t univ, int count) { - counts[univ] = count; - } - - int get_count(int32_t univ) { - return counts[univ]; - } - }; - -CellCountStorage* CellCountStorage::instance_ = nullptr; -LevelCountStorage* LevelCountStorage::instance_ = nullptr; + CellCountStorage* CellCountStorage::instance_ = nullptr; + LevelCountStorage* LevelCountStorage::instance_ = nullptr; //============================================================================== From cc826a7db321ea2034332dfa861a37c140fe9428 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Tue, 26 Feb 2019 11:28:04 -0600 Subject: [PATCH 089/158] Fixes after rebase. --- src/geometry_aux.cpp | 135 ++++++++++++++++++------------------------- 1 file changed, 57 insertions(+), 78 deletions(-) diff --git a/src/geometry_aux.cpp b/src/geometry_aux.cpp index 5228bddc1..662b6790d 100644 --- a/src/geometry_aux.cpp +++ b/src/geometry_aux.cpp @@ -60,36 +60,16 @@ void read_geometry_xml() model::root_universe = find_root_universe(); } - struct CellCountStorage { - private: - CellCountStorage() {} - CellCountStorage(CellCountStorage& c) {} - CellCountStorage(const CellCountStorage& c) {} - - static CellCountStorage* instance_; - - std::map> counts; - - public: - - static CellCountStorage* instance() { - if (instance_ == nullptr) - instance_ = new CellCountStorage; - - return instance_; - } - - void clear() { - if (instance_ != nullptr) { - delete instance_; - instance_ = nullptr; - } - } +void CellCountStorage::clear() { + if (instance_ != nullptr) { + delete instance_; + instance_ = nullptr; } +} - void CellCountStorage::set_cell_count_for_univ(int32_t univ, int32_t cell, int count) { +void CellCountStorage::set_cell_count_for_univ(int32_t univ, int32_t cell, int count) { counts[univ][cell] = count; - } +} void CellCountStorage::increment_count_for_univ(int32_t univ, int32_t cell) { if (has_count(univ,cell)) { @@ -99,72 +79,71 @@ void read_geometry_xml() } } - bool CellCountStorage::has_count(int32_t univ, int32_t cell) { - return counts.count(univ) && counts[univ].count(cell); - } +bool CellCountStorage::has_count(int32_t univ, int32_t cell) { + return counts.count(univ) && counts[univ].count(cell); +} - bool CellCountStorage::has_count(int32_t univ) { - return counts.count(univ); - } +bool CellCountStorage::has_count(int32_t univ) { + return counts.count(univ); +} - void CellCountStorage::absorb_b_into_a(int32_t a, int32_t b) { - std::map b_map = counts[b]; +void CellCountStorage::absorb_b_into_a(int32_t a, int32_t b) { + std::map b_map = counts[b]; - for (auto it : b_map) { - if (has_count(a, it.first)) { - counts[a][it.first] += it.second; - } else { - counts[a][it.first] = it.second; + for (auto it : b_map) { + if (has_count(a, it.first)) { + counts[a][it.first] += it.second; + } else { + counts[a][it.first] = it.second; } - } } +} - auto CellCountStorage::get_count(int32_t univ) { +auto CellCountStorage::get_count(int32_t univ) { return counts[univ]; - } +} - void LevelCountStorage::clear() { - if (instance_ != nullptr) { - delete instance_; - instance_ = nullptr; +void LevelCountStorage::clear() { + if (instance_ != nullptr) { + delete instance_; + instance_ = nullptr; } +} + +void LevelCountStorage::set_cell_count_for_univ(int32_t univ, int count) { + counts[univ] = count; +} + +void LevelCountStorage::increment_count_for_univ(int32_t univ) { + if (has_count(univ)) { + counts[univ] += 1; + } else { + counts[univ] = 1; } +} - void LevelCountStorage::set_cell_count_for_univ(int32_t univ, int count) { - counts[univ] = count; +bool LevelCountStorage::has_count(int32_t univ) { + return counts.count(univ); +} + +void LevelCountStorage::absorb_b_into_a(int32_t a, int32_t b) { + if (has_count(a)) { + counts[a] += counts[b]; + } else { + counts[a] = counts[b]; } +} - void LevelCountStorage::increment_count_for_univ(int32_t univ) { - if (has_count(univ)) { - counts[univ] += 1; - } else { - counts[univ] = 1; - } - } +void LevelCountStorage::set_count(int32_t univ, int count) { + counts[univ] = count; +} - bool LevelCountStorage::has_count(int32_t univ) { - return counts.count(univ); - } +int LevelCountStorage::get_count(int32_t univ) { + return counts[univ]; +} - void LevelCountStorage::absorb_b_into_a(int32_t a, int32_t b) { - - if (has_count(a)) { - counts[a] += counts[b]; - } else { - counts[a] = counts[b]; - } - } - - void LevelCountStorage::set_count(int32_t univ, int count) { - counts[univ] = count; - } - - int LevelCountStorage::get_count(int32_t univ) { - return counts[univ]; - } - - CellCountStorage* CellCountStorage::instance_ = nullptr; - LevelCountStorage* LevelCountStorage::instance_ = nullptr; +CellCountStorage* CellCountStorage::instance_ = nullptr; +LevelCountStorage* LevelCountStorage::instance_ = nullptr; //============================================================================== From 4b654c2be0f7f9447f3363662e911f1ab1f2faad Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Tue, 5 Mar 2019 10:21:11 -0600 Subject: [PATCH 090/158] Moving to memoization pattern instead of singleton class. --- openmc/cell.py | 25 ++++++++++++------------ openmc/geometry.py | 10 +++++----- openmc/geomtrack.py | 46 --------------------------------------------- openmc/lattice.py | 36 ++++++++++++++++------------------- openmc/universe.py | 22 +++++++++++----------- 5 files changed, 44 insertions(+), 95 deletions(-) delete mode 100644 openmc/geomtrack.py diff --git a/openmc/cell.py b/openmc/cell.py index dd3d22ed1..36f772ff5 100644 --- a/openmc/cell.py +++ b/openmc/cell.py @@ -16,8 +16,6 @@ from openmc.region import Region, Intersection, Complement from openmc._xml import get_text from .mixin import IDManagerMixin -from .geomtrack import ElementTracker - class Cell(IDManagerMixin): r"""A region of space defined as the intersection of half-space created by quadric surfaces. @@ -464,8 +462,8 @@ class Cell(IDManagerMixin): return memo[self] - def create_xml_subelement(self, xml_element): - et = ElementTracker() + def create_xml_subelement(self, xml_element, memo=None): + element = ET.Element("cell") element.set("id", str(self.id)) @@ -484,7 +482,7 @@ class Cell(IDManagerMixin): elif self.fill_type in ('universe', 'lattice'): element.set("fill", str(self.fill.id)) - self.fill.create_xml_subelement(xml_element) + self.fill.create_xml_subelement(xml_element, memo) if self.region is not None: # Set the region attribute with the region specification @@ -500,22 +498,23 @@ class Cell(IDManagerMixin): # tree. When it reaches a leaf (a Halfspace), it creates a # element for the corresponding surface if none has been created # thus far. - def create_surface_elements(node, element): - et = ElementTracker() + def create_surface_elements(node, element, memo=None): if isinstance(node, Halfspace): path = "./surface[@id='{}']".format(node.surface.id) - if node.surface.id not in et.surfaces: - et.add_surface(node.surface.id) - xml_element.append(node.surface.to_xml_element()) + if memo and node.surface.id in memo['surfaces']: + return + if memo: + memo['surfaces'].add(node.surface.id) + xml_element.append(node.surface.to_xml_element()) elif isinstance(node, Complement): - create_surface_elements(node.node, element) + create_surface_elements(node.node, element, memo) else: for subnode in node: - create_surface_elements(subnode, element) + create_surface_elements(subnode, element, memo) # Call the recursive function from the top node - create_surface_elements(self.region, xml_element) + create_surface_elements(self.region, xml_element, memo) if self.temperature is not None: if isinstance(self.temperature, Iterable): diff --git a/openmc/geometry.py b/openmc/geometry.py index 61032d9a8..28fcb3fc0 100644 --- a/openmc/geometry.py +++ b/openmc/geometry.py @@ -10,8 +10,6 @@ import openmc import openmc._xml as xml from openmc.checkvalue import check_type -from .geomtrack import ElementTracker - class Geometry(object): """Geometry representing a collection of surfaces, cells, and universes. @@ -89,11 +87,13 @@ class Geometry(object): """ # Create XML representation - et = ElementTracker() - et.reset() + memo = {'cells' : set(), + 'surfaces' : set(), + 'lattices' : set(), + 'universes' : set()} root_element = ET.Element("geometry") - self.root_universe.create_xml_subelement(root_element) + self.root_universe.create_xml_subelement(root_element, memo) # Sort the elements in the file root_element[:] = sorted(root_element, key=lambda x: ( diff --git a/openmc/geomtrack.py b/openmc/geomtrack.py deleted file mode 100644 index f2230ce7d..000000000 --- a/openmc/geomtrack.py +++ /dev/null @@ -1,46 +0,0 @@ - -class ElementTracker: - class __ElementTracker: - def __init__(self): - self.cells = set() - self.surfaces = set() - self.lattices = set() - self.universes = set() - - def update(self, element_type, element_id): - if element_type == "cell": - self.cells.add(element_id) - elif element_type == "surface": - self.surfaces.add(element_id) - elif element_type == "lattice": - self.lattices.add(element_id) - elif element_type == "universe": - self.universes.add(element_id) - - def add_cell(self, cell_id): - self.update("cell", cell_id) - - def add_surface(self, surface_id): - self.update("surface", surface_id) - - def add_lattice(self, lattice_id): - self.update("lattice", lattice_id) - - def add_universe(self, universe_id): - self.update("universe", universe_id) - - def reset(self): - self.cells = set() - self.surfaces = set() - self.lattices = set() - self.universes = set() - - instance = None - - def __init__(self): - if not ElementTracker.instance: - ElementTracker.instance = ElementTracker.__ElementTracker() - else: - pass - def __getattr__(self, name): - return getattr(self.instance, name) diff --git a/openmc/lattice.py b/openmc/lattice.py index c1ce4c6a2..985fec86e 100644 --- a/openmc/lattice.py +++ b/openmc/lattice.py @@ -13,8 +13,6 @@ import openmc from openmc._xml import get_text from openmc.mixin import IDManagerMixin -from .geomtrack import ElementTracker - class Lattice(IDManagerMixin, metaclass=ABCMeta): """A repeating structure wherein each element is a universe. @@ -754,17 +752,16 @@ class RectLattice(Lattice): 0 <= idx[1] < self.shape[1] and 0 <= idx[2] < self.shape[2]) - def create_xml_subelement(self, xml_element): - et = ElementTracker() + def create_xml_subelement(self, xml_element, memo=None): # Determine if XML element already contains subelement for this Lattice path = './lattice[@id=\'{0}\']'.format(self._id) test = xml_element.find(path) # If the element does contain the Lattice subelement, then return - if self._id in et.lattices: + if memo and self._id in memo['lattices']: return - else: - et.add_lattice(self._id) + if memo: + memo['lattices'].add(self._id) lattice_subelement = ET.Element("lattice") lattice_subelement.set("id", str(self._id)) @@ -780,7 +777,7 @@ class RectLattice(Lattice): if self._outer is not None: outer = ET.SubElement(lattice_subelement, "outer") outer.text = '{0}'.format(self._outer._id) - self._outer.create_xml_subelement(xml_element) + self._outer.create_xml_subelement(xml_element, memo) # Export Lattice cell dimensions dimension = ET.SubElement(lattice_subelement, "dimension") @@ -804,7 +801,7 @@ class RectLattice(Lattice): universe_ids += '{0} '.format(universe._id) # Create XML subelement for this Universe - universe.create_xml_subelement(xml_element) + universe.create_xml_subelement(xml_element, memo) # Add newline character when we reach end of row of cells universe_ids += '\n' @@ -822,7 +819,7 @@ class RectLattice(Lattice): universe_ids += '{0} '.format(universe._id) # Create XML subelement for this Universe - universe.create_xml_subelement(xml_element) + universe.create_xml_subelement(xml_element, memo) # Add newline character when we reach end of row of cells universe_ids += '\n' @@ -1277,17 +1274,16 @@ class HexLattice(Lattice): else: return g < self.num_rings and 0 <= idx[2] < self.num_axial - def create_xml_subelement(self, xml_element): - et = ElementTracker() + def create_xml_subelement(self, xml_element, memo=None): # Determine if XML element already contains subelement for this Lattice path = './hex_lattice[@id=\'{0}\']'.format(self._id) test = xml_element.find(path) # If the element does contain the Lattice subelement, then return - if self._id in et.lattices: + if memo and self._id in memo['lattices']: return - else: - et.add_lattice(self._id) + if memo: + memo['lattices'].add(self._id) lattice_subelement = ET.Element("hex_lattice") lattice_subelement.set("id", str(self._id)) @@ -1303,7 +1299,7 @@ class HexLattice(Lattice): if self._outer is not None: outer = ET.SubElement(lattice_subelement, "outer") outer.text = '{0}'.format(self._outer._id) - self._outer.create_xml_subelement(xml_element) + self._outer.create_xml_subelement(xml_element, memo) lattice_subelement.set("n_rings", str(self._num_rings)) # If orientation is "x" export it to XML @@ -1325,13 +1321,13 @@ class HexLattice(Lattice): for z in range(self._num_axial): # Initialize the center universe. universe = self._universes[z][-1][0] - universe.create_xml_subelement(xml_element) + universe.create_xml_subelement(xml_element, memo) # Initialize the remaining universes. for r in range(self._num_rings-1): for theta in range(6*(self._num_rings - 1 - r)): universe = self._universes[z][r][theta] - universe.create_xml_subelement(xml_element) + universe.create_xml_subelement(xml_element, memo) # Get a string representation of the universe IDs. slices.append(self._repr_axial_slice(self._universes[z])) @@ -1343,13 +1339,13 @@ class HexLattice(Lattice): else: # Initialize the center universe. universe = self._universes[-1][0] - universe.create_xml_subelement(xml_element) + universe.create_xml_subelement(xml_element, memo) # Initialize the remaining universes. for r in range(self._num_rings - 1): for theta in range(6*(self._num_rings - 1 - r)): universe = self._universes[r][theta] - universe.create_xml_subelement(xml_element) + universe.create_xml_subelement(xml_element, memo) # Get a string representation of the universe IDs. universe_ids = self._repr_axial_slice(self._universes) diff --git a/openmc/universe.py b/openmc/universe.py index 876883cea..7a9411ecf 100644 --- a/openmc/universe.py +++ b/openmc/universe.py @@ -12,8 +12,6 @@ import openmc.checkvalue as cv from openmc.plots import _SVG_COLORS from openmc.mixin import IDManagerMixin -from .geomtrack import ElementTracker - class Universe(IDManagerMixin): """A collection of cells that can be repeated. @@ -513,21 +511,23 @@ class Universe(IDManagerMixin): return memo[self] - def create_xml_subelement(self, xml_element): - et = ElementTracker() + def create_xml_subelement(self, xml_element, memo=None): # Iterate over all Cells for cell_id, cell in self._cells.items(): path = "./cell[@id='{}']".format(cell_id) # If the cell was not already written, write it - if cell_id not in et.cells: - et.add_cell(cell_id) - # Create XML subelement for this Cell - cell_element = cell.create_xml_subelement(xml_element) + if memo and cell_id in memo['cells']: + continue + if memo: + memo['cells'].add(cell_id) - # Append the Universe ID to the subelement and add to Element - cell_element.set("universe", str(self._id)) - xml_element.append(cell_element) + # Create XML subelement for this Cell + cell_element = cell.create_xml_subelement(xml_element, memo) + + # Append the Universe ID to the subelement and add to Element + cell_element.set("universe", str(self._id)) + xml_element.append(cell_element) def _determine_paths(self, path='', instances_only=False): """Count the number of instances for each cell in the universe, and From 177f3d1423f5db7d7fb8bbd2ab50df39ffd56f11 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Tue, 5 Mar 2019 11:08:27 -0600 Subject: [PATCH 091/158] Correction to memoization for xml export. --- openmc/cell.py | 2 +- openmc/lattice.py | 6 +++--- openmc/universe.py | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/openmc/cell.py b/openmc/cell.py index 36f772ff5..bb59b1d3a 100644 --- a/openmc/cell.py +++ b/openmc/cell.py @@ -503,7 +503,7 @@ class Cell(IDManagerMixin): path = "./surface[@id='{}']".format(node.surface.id) if memo and node.surface.id in memo['surfaces']: return - if memo: + if memo is not None: memo['surfaces'].add(node.surface.id) xml_element.append(node.surface.to_xml_element()) diff --git a/openmc/lattice.py b/openmc/lattice.py index 985fec86e..dff00306a 100644 --- a/openmc/lattice.py +++ b/openmc/lattice.py @@ -467,7 +467,7 @@ class Lattice(IDManagerMixin, metaclass=ABCMeta): if memo is None: memo = {} - # If no nemoize'd clone exists, instantiate one + # If no memoize'd clone exists, instantiate one if self not in memo: clone = deepcopy(self) clone.id = None @@ -760,7 +760,7 @@ class RectLattice(Lattice): # If the element does contain the Lattice subelement, then return if memo and self._id in memo['lattices']: return - if memo: + if memo is not None: memo['lattices'].add(self._id) lattice_subelement = ET.Element("lattice") @@ -1282,7 +1282,7 @@ class HexLattice(Lattice): # If the element does contain the Lattice subelement, then return if memo and self._id in memo['lattices']: return - if memo: + if memo is not None: memo['lattices'].add(self._id) lattice_subelement = ET.Element("hex_lattice") diff --git a/openmc/universe.py b/openmc/universe.py index 7a9411ecf..ea8c7f294 100644 --- a/openmc/universe.py +++ b/openmc/universe.py @@ -519,7 +519,7 @@ class Universe(IDManagerMixin): # If the cell was not already written, write it if memo and cell_id in memo['cells']: continue - if memo: + if memo is not None: memo['cells'].add(cell_id) # Create XML subelement for this Cell From ec1a4b5d2b8a092bc2bbec86b6f0f04882c685a5 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Tue, 5 Mar 2019 13:22:50 -0600 Subject: [PATCH 092/158] Adding documentation to create_xml_subelement methods. Removing old, now unused, path variables from those methods as well. --- openmc/cell.py | 17 ++++++++++++++++- openmc/lattice.py | 25 +++++++++++++++++-------- openmc/universe.py | 18 +++++++++++++++++- 3 files changed, 50 insertions(+), 10 deletions(-) diff --git a/openmc/cell.py b/openmc/cell.py index bb59b1d3a..fb39dd7ec 100644 --- a/openmc/cell.py +++ b/openmc/cell.py @@ -463,7 +463,23 @@ class Cell(IDManagerMixin): return memo[self] def create_xml_subelement(self, xml_element, memo=None): + """Add the cell's xml representation to an incoming xml element + Parameters + ---------- + xml_element : xml.etree.ElementTree.Element + XML element to be added to + + memo : dict or None + A dictionary containing sets of universe, lattice, cell, and surface + id sets already written to the xml_element. This parameter + is used internally and should not be specified by the user. + + Returns + ------- + None + + """ element = ET.Element("cell") element.set("id", str(self.id)) @@ -500,7 +516,6 @@ class Cell(IDManagerMixin): # thus far. def create_surface_elements(node, element, memo=None): if isinstance(node, Halfspace): - path = "./surface[@id='{}']".format(node.surface.id) if memo and node.surface.id in memo['surfaces']: return if memo is not None: diff --git a/openmc/lattice.py b/openmc/lattice.py index dff00306a..0434d626b 100644 --- a/openmc/lattice.py +++ b/openmc/lattice.py @@ -753,11 +753,24 @@ class RectLattice(Lattice): 0 <= idx[2] < self.shape[2]) def create_xml_subelement(self, xml_element, memo=None): - # Determine if XML element already contains subelement for this Lattice - path = './lattice[@id=\'{0}\']'.format(self._id) - test = xml_element.find(path) + """Add the lattice xml representation to an incoming xml element - # If the element does contain the Lattice subelement, then return + Parameters + ---------- + xml_element : xml.etree.ElementTree.Element + XML element to be added to + + memo : dict or None + A dictionary containing sets of universe, lattice, cell, and surface + id sets already written to the xml_element. This parameter + is used internally and should not be specified by the user. + + Returns + ------- + None + + """ + # If the element already contains the Lattice subelement, then return if memo and self._id in memo['lattices']: return if memo is not None: @@ -1275,10 +1288,6 @@ class HexLattice(Lattice): return g < self.num_rings and 0 <= idx[2] < self.num_axial def create_xml_subelement(self, xml_element, memo=None): - # Determine if XML element already contains subelement for this Lattice - path = './hex_lattice[@id=\'{0}\']'.format(self._id) - test = xml_element.find(path) - # If the element does contain the Lattice subelement, then return if memo and self._id in memo['lattices']: return diff --git a/openmc/universe.py b/openmc/universe.py index ea8c7f294..e1c1e1b0c 100644 --- a/openmc/universe.py +++ b/openmc/universe.py @@ -512,9 +512,25 @@ class Universe(IDManagerMixin): return memo[self] def create_xml_subelement(self, xml_element, memo=None): + """Add the universe xml representation to an incoming xml element + + Parameters + ---------- + xml_element : xml.etree.ElementTree.Element + XML element to be added to + + memo : dict or None + A dictionary containing sets of universe, lattice, cell, and surface + id sets already written to the xml_element. This parameter + is used internally and should not be specified by the user. + + Returns + ------- + None + + """ # Iterate over all Cells for cell_id, cell in self._cells.items(): - path = "./cell[@id='{}']".format(cell_id) # If the cell was not already written, write it if memo and cell_id in memo['cells']: From 05942a5ab5872f12e273251a464ef03916485b93 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Fri, 4 Oct 2019 17:35:46 -0500 Subject: [PATCH 093/158] Using a single set of object IDs as a memo. --- openmc/cell.py | 4 ++-- openmc/geometry.py | 5 +---- openmc/lattice.py | 8 ++++---- openmc/universe.py | 4 ++-- 4 files changed, 9 insertions(+), 12 deletions(-) diff --git a/openmc/cell.py b/openmc/cell.py index fb39dd7ec..ccfec35b1 100644 --- a/openmc/cell.py +++ b/openmc/cell.py @@ -516,10 +516,10 @@ class Cell(IDManagerMixin): # thus far. def create_surface_elements(node, element, memo=None): if isinstance(node, Halfspace): - if memo and node.surface.id in memo['surfaces']: + if memo and id(node.surface) in memo: return if memo is not None: - memo['surfaces'].add(node.surface.id) + memo.add(id(node.surface)) xml_element.append(node.surface.to_xml_element()) elif isinstance(node, Complement): diff --git a/openmc/geometry.py b/openmc/geometry.py index 28fcb3fc0..a629d1189 100644 --- a/openmc/geometry.py +++ b/openmc/geometry.py @@ -87,10 +87,7 @@ class Geometry(object): """ # Create XML representation - memo = {'cells' : set(), - 'surfaces' : set(), - 'lattices' : set(), - 'universes' : set()} + memo = set() root_element = ET.Element("geometry") self.root_universe.create_xml_subelement(root_element, memo) diff --git a/openmc/lattice.py b/openmc/lattice.py index 0434d626b..5305e4192 100644 --- a/openmc/lattice.py +++ b/openmc/lattice.py @@ -771,10 +771,10 @@ class RectLattice(Lattice): """ # If the element already contains the Lattice subelement, then return - if memo and self._id in memo['lattices']: + if memo and id(self) in memo: return if memo is not None: - memo['lattices'].add(self._id) + memo.add(id(self)) lattice_subelement = ET.Element("lattice") lattice_subelement.set("id", str(self._id)) @@ -1289,10 +1289,10 @@ class HexLattice(Lattice): def create_xml_subelement(self, xml_element, memo=None): # If the element does contain the Lattice subelement, then return - if memo and self._id in memo['lattices']: + if memo and id(self) in memo: return if memo is not None: - memo['lattices'].add(self._id) + memo.add(id(self)) lattice_subelement = ET.Element("hex_lattice") lattice_subelement.set("id", str(self._id)) diff --git a/openmc/universe.py b/openmc/universe.py index e1c1e1b0c..96f09c867 100644 --- a/openmc/universe.py +++ b/openmc/universe.py @@ -533,10 +533,10 @@ class Universe(IDManagerMixin): for cell_id, cell in self._cells.items(): # If the cell was not already written, write it - if memo and cell_id in memo['cells']: + if memo and id(cell) in memo: continue if memo is not None: - memo['cells'].add(cell_id) + memo.add(id(cell)) # Create XML subelement for this Cell cell_element = cell.create_xml_subelement(xml_element, memo) From 07923052a20cbb82ac4fc2cfe895500a25421680 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Mon, 7 Oct 2019 00:31:14 -0500 Subject: [PATCH 094/158] Resetting C++ files. --- include/openmc/geometry_aux.h | 70 ------------------- src/finalize.cpp | 4 -- src/geometry_aux.cpp | 126 +++------------------------------- 3 files changed, 11 insertions(+), 189 deletions(-) diff --git a/include/openmc/geometry_aux.h b/include/openmc/geometry_aux.h index 557d82193..ffcdcf885 100644 --- a/include/openmc/geometry_aux.h +++ b/include/openmc/geometry_aux.h @@ -7,78 +7,8 @@ #include #include #include -#include namespace openmc { - struct CellCountStorage { - private: - CellCountStorage() {} - CellCountStorage(CellCountStorage& c) {} - CellCountStorage(const CellCountStorage& c) {} - - static CellCountStorage* instance_; - - std::map> counts; - - public: - - static CellCountStorage* instance() { - if (instance_ == nullptr) - instance_ = new CellCountStorage; - - return instance_; - } - - - - void clear(); - - void set_cell_count_for_univ(int32_t univ, int32_t cell, int count); - - void increment_count_for_univ(int32_t univ, int32_t cell); - - bool has_count(int32_t univ, int32_t cell); - - bool has_count(int32_t univ); - - void absorb_b_into_a(int32_t a, int32_t b); - - auto get_count(int32_t univ); - }; - - struct LevelCountStorage { - private: - LevelCountStorage() {} - LevelCountStorage(LevelCountStorage& c) {} - LevelCountStorage(const LevelCountStorage& c) {} - - static LevelCountStorage* instance_; - - std::map counts; - - public: - - static LevelCountStorage* instance() { - if (instance_ == nullptr) - instance_ = new LevelCountStorage; - - return instance_; - } - - void clear(); - - void set_cell_count_for_univ(int32_t univ, int count); - - void increment_count_for_univ(int32_t univ); - - bool has_count(int32_t univ); - - void absorb_b_into_a(int32_t a, int32_t b); - - void set_count(int32_t univ, int count); - - int get_count(int32_t univ); - }; void read_geometry_xml(); diff --git a/src/finalize.cpp b/src/finalize.cpp index f2cbc973c..3de20d6d0 100644 --- a/src/finalize.cpp +++ b/src/finalize.cpp @@ -135,10 +135,6 @@ int openmc_finalize() int openmc_reset() { - - CellCountStorage::instance()->clear(); - LevelCountStorage::instance()->clear(); - for (auto& t : model::tallies) { t->reset(); } diff --git a/src/geometry_aux.cpp b/src/geometry_aux.cpp index 662b6790d..d195a9de3 100644 --- a/src/geometry_aux.cpp +++ b/src/geometry_aux.cpp @@ -60,91 +60,6 @@ void read_geometry_xml() model::root_universe = find_root_universe(); } -void CellCountStorage::clear() { - if (instance_ != nullptr) { - delete instance_; - instance_ = nullptr; - } -} - -void CellCountStorage::set_cell_count_for_univ(int32_t univ, int32_t cell, int count) { - counts[univ][cell] = count; -} - - void CellCountStorage::increment_count_for_univ(int32_t univ, int32_t cell) { - if (has_count(univ,cell)) { - counts[univ][cell] += 1; - } else { - counts[univ][cell] = 1; - } - } - -bool CellCountStorage::has_count(int32_t univ, int32_t cell) { - return counts.count(univ) && counts[univ].count(cell); -} - -bool CellCountStorage::has_count(int32_t univ) { - return counts.count(univ); -} - -void CellCountStorage::absorb_b_into_a(int32_t a, int32_t b) { - std::map b_map = counts[b]; - - for (auto it : b_map) { - if (has_count(a, it.first)) { - counts[a][it.first] += it.second; - } else { - counts[a][it.first] = it.second; - } - } -} - -auto CellCountStorage::get_count(int32_t univ) { - return counts[univ]; -} - -void LevelCountStorage::clear() { - if (instance_ != nullptr) { - delete instance_; - instance_ = nullptr; - } -} - -void LevelCountStorage::set_cell_count_for_univ(int32_t univ, int count) { - counts[univ] = count; -} - -void LevelCountStorage::increment_count_for_univ(int32_t univ) { - if (has_count(univ)) { - counts[univ] += 1; - } else { - counts[univ] = 1; - } -} - -bool LevelCountStorage::has_count(int32_t univ) { - return counts.count(univ); -} - -void LevelCountStorage::absorb_b_into_a(int32_t a, int32_t b) { - if (has_count(a)) { - counts[a] += counts[b]; - } else { - counts[a] = counts[b]; - } -} - -void LevelCountStorage::set_count(int32_t univ, int count) { - counts[univ] = count; -} - -int LevelCountStorage::get_count(int32_t univ) { - return counts[univ]; -} - -CellCountStorage* CellCountStorage::instance_ = nullptr; -LevelCountStorage* LevelCountStorage::instance_ = nullptr; - //============================================================================== void @@ -480,31 +395,19 @@ prepare_distribcell() void count_cell_instances(int32_t univ_indx) { - CellCountStorage* counter = CellCountStorage::instance(); + for (int32_t cell_indx : model::universes[univ_indx]->cells_) { + Cell& c = *model::cells[cell_indx]; + ++c.n_instances_; - if (counter->has_count(univ_indx)) { - std::map univ_counts = counter->get_count(univ_indx); - for(auto it : univ_counts) { - Cell& c = *model::cells[it.first]; - c.n_instances_ += it.second; - } - } else { - for (int32_t cell_indx : model::universes[univ_indx]->cells_) { - Cell& c = *model::cells[cell_indx]; - ++c.n_instances_; - counter->increment_count_for_univ(univ_indx, cell_indx); + if (c.type_ == FILL_UNIVERSE) { + // This cell contains another universe. Recurse into that universe. + count_cell_instances(c.fill_); - if (c.type_ == FILL_UNIVERSE) { - // This cell contains another universe. Recurse into that universe. - count_cell_instances(c.fill_); - counter->absorb_b_into_a(univ_indx, c.fill_); - } else if (c.type_ == FILL_LATTICE) { - // This cell contains a lattice. Recurse into the lattice universes. - Lattice& lat = *model::lattices[c.fill_]; - for (auto it = lat.begin(); it != lat.end(); ++it) { - count_cell_instances(*it); - counter->absorb_b_into_a(univ_indx, *it); - } + } else if (c.type_ == FILL_LATTICE) { + // This cell contains a lattice. Recurse into the lattice universes. + Lattice& lat = *model::lattices[c.fill_]; + for (auto it = lat.begin(); it != lat.end(); ++it) { + count_cell_instances(*it); } } } @@ -626,12 +529,6 @@ distribcell_path(int32_t target_cell, int32_t map, int32_t target_offset) int maximum_levels(int32_t univ) { - LevelCountStorage* counter = LevelCountStorage::instance(); - - if (counter->has_count(univ)) { - return counter->get_count(univ); - } - int levels_below {0}; for (int32_t cell_indx : model::universes[univ]->cells_) { @@ -649,7 +546,6 @@ maximum_levels(int32_t univ) } ++levels_below; - counter->set_count(univ, levels_below); return levels_below; } From 6bd25d43a3f44881cca3837d3581276282077c81 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Fri, 1 Nov 2019 07:35:57 -0500 Subject: [PATCH 095/158] Updating doc strings for the memo object in xml related calls. --- openmc/cell.py | 9 +++++---- openmc/geometry.py | 1 + openmc/lattice.py | 9 +++++---- openmc/universe.py | 9 +++++---- 4 files changed, 16 insertions(+), 12 deletions(-) diff --git a/openmc/cell.py b/openmc/cell.py index ccfec35b1..3de20f259 100644 --- a/openmc/cell.py +++ b/openmc/cell.py @@ -16,6 +16,7 @@ from openmc.region import Region, Intersection, Complement from openmc._xml import get_text from .mixin import IDManagerMixin + class Cell(IDManagerMixin): r"""A region of space defined as the intersection of half-space created by quadric surfaces. @@ -470,10 +471,10 @@ class Cell(IDManagerMixin): xml_element : xml.etree.ElementTree.Element XML element to be added to - memo : dict or None - A dictionary containing sets of universe, lattice, cell, and surface - id sets already written to the xml_element. This parameter - is used internally and should not be specified by the user. + memo : set or None + A set of object id's representing geometry entities already + written to the xml_element. This parameter is used internally + and should not be specified by users. Returns ------- diff --git a/openmc/geometry.py b/openmc/geometry.py index a629d1189..013e9ed12 100644 --- a/openmc/geometry.py +++ b/openmc/geometry.py @@ -10,6 +10,7 @@ import openmc import openmc._xml as xml from openmc.checkvalue import check_type + class Geometry(object): """Geometry representing a collection of surfaces, cells, and universes. diff --git a/openmc/lattice.py b/openmc/lattice.py index 5305e4192..077fb2669 100644 --- a/openmc/lattice.py +++ b/openmc/lattice.py @@ -13,6 +13,7 @@ import openmc from openmc._xml import get_text from openmc.mixin import IDManagerMixin + class Lattice(IDManagerMixin, metaclass=ABCMeta): """A repeating structure wherein each element is a universe. @@ -760,10 +761,10 @@ class RectLattice(Lattice): xml_element : xml.etree.ElementTree.Element XML element to be added to - memo : dict or None - A dictionary containing sets of universe, lattice, cell, and surface - id sets already written to the xml_element. This parameter - is used internally and should not be specified by the user. + memo : set or None + A set of object id's representing geometry entities already + written to the xml_element. This parameter is used internally + and should not be specified by users. Returns ------- diff --git a/openmc/universe.py b/openmc/universe.py index 96f09c867..418fe1236 100644 --- a/openmc/universe.py +++ b/openmc/universe.py @@ -12,6 +12,7 @@ import openmc.checkvalue as cv from openmc.plots import _SVG_COLORS from openmc.mixin import IDManagerMixin + class Universe(IDManagerMixin): """A collection of cells that can be repeated. @@ -519,10 +520,10 @@ class Universe(IDManagerMixin): xml_element : xml.etree.ElementTree.Element XML element to be added to - memo : dict or None - A dictionary containing sets of universe, lattice, cell, and surface - id sets already written to the xml_element. This parameter - is used internally and should not be specified by the user. + memo : set or None + A set of object id's representing geometry entities already + written to the xml_element. This parameter is used internally + and should not be specified by users. Returns ------- From 1308dc9f38b1e6ab432088824a9fd127bc33ac99 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Fri, 1 Nov 2019 07:54:44 -0500 Subject: [PATCH 096/158] Removing whitespace --- openmc/geometry.py | 1 - 1 file changed, 1 deletion(-) diff --git a/openmc/geometry.py b/openmc/geometry.py index 013e9ed12..89016b722 100644 --- a/openmc/geometry.py +++ b/openmc/geometry.py @@ -87,7 +87,6 @@ class Geometry(object): """ # Create XML representation - memo = set() root_element = ET.Element("geometry") From 9c06a128d963cfb744075ed599c17e4d415d6cd0 Mon Sep 17 00:00:00 2001 From: Gavin Ridley Date: Sat, 2 Nov 2019 22:08:06 -0400 Subject: [PATCH 097/158] initial stab at making mgxs externally usable --- include/openmc/mgxs.h | 10 +++- include/openmc/mgxs_interface.h | 59 +++++++++++++----------- src/cross_sections.cpp | 2 +- src/initialize.cpp | 4 +- src/material.cpp | 12 ++--- src/mgxs.cpp | 24 ++++------ src/mgxs_interface.cpp | 82 ++++++++++++++++----------------- src/output.cpp | 2 +- src/particle.cpp | 2 +- src/particle_restart.cpp | 2 +- src/physics_mg.cpp | 6 +-- src/source.cpp | 6 +-- src/state_point.cpp | 2 +- src/summary.cpp | 2 +- src/tallies/filter_energy.cpp | 10 ++-- src/tallies/tally_scoring.cpp | 12 ++--- src/xsdata.cpp | 32 ++++++------- 17 files changed, 135 insertions(+), 134 deletions(-) diff --git a/include/openmc/mgxs.h b/include/openmc/mgxs.h index 1b4062da9..313677f6c 100644 --- a/include/openmc/mgxs.h +++ b/include/openmc/mgxs.h @@ -110,7 +110,10 @@ class Mgxs { //! //! @param xs_id HDF5 group id for the cross section data. //! @param temperature Temperatures to read. - Mgxs(hid_t xs_id, const std::vector& temperature); + //! @param num_group number of energy groups + //! @param num_delay number of delayed groups + Mgxs(hid_t xs_id, const std::vector& temperature, + int num_group, int num_delay); //! \brief Constructor that initializes and populates all data to build a //! macroscopic cross section from microscopic cross section. @@ -119,8 +122,11 @@ class Mgxs { //! @param mat_kTs temperatures (in units of eV) that data is needed. //! @param micros Microscopic objects to combine. //! @param atom_densities Atom densities of those microscopic quantities. + //! @param num_group number of energy groups + //! @param num_delay number of delayed groups Mgxs(const std::string& in_name, const std::vector& mat_kTs, - const std::vector& micros, const std::vector& atom_densities); + const std::vector& micros, const std::vector& atom_densities, + int num_group, int num_delay); //! \brief Provides a cross section value given certain parameters //! diff --git a/include/openmc/mgxs_interface.h b/include/openmc/mgxs_interface.h index bf72d675b..c72587be2 100644 --- a/include/openmc/mgxs_interface.h +++ b/include/openmc/mgxs_interface.h @@ -12,36 +12,41 @@ namespace openmc { //============================================================================== -// Global variables +// Global MGXS data container structure //============================================================================== +struct MgxsInterface +{ + int num_energy_groups; + int num_delayed_groups; + + std::vector nuclides_MG; + std::vector macro_xs; + + std::vector energy_bins; + std::vector energy_bin_avg; + std::vector rev_energy_bins; + + MgxsInterface() = default; + + // Construct from path to cross sections file + MgxsInterface(const std::string& path_cross_sections); + + void init(const std::string& path_cross_sections); + + void add_mgxs(hid_t file_id, const std::string& name, + const std::vector& temperature); + + void create_macro_xs(); + + std::vector> get_mat_kTs(); + + void read_mg_cross_sections_header(); +}; + namespace data { - -extern std::vector nuclides_MG; -extern std::vector macro_xs; -extern int num_energy_groups; -extern int num_delayed_groups; -extern std::vector energy_bins; -extern std::vector energy_bin_avg; -extern std::vector rev_energy_bins; - -} // namespace data - -//============================================================================== -// Mgxs data loading interface methods -//============================================================================== - -void read_mgxs(); - -void -add_mgxs(hid_t file_id, const std::string& name, - const std::vector& temperature); - -void create_macro_xs(); - -std::vector> get_mat_kTs(); - -void read_mg_cross_sections_header(); + extern MgxsInterface mgInterface; +} //============================================================================== // Mgxs tracking/transport/tallying interface methods diff --git a/src/cross_sections.cpp b/src/cross_sections.cpp index 3c29dd8e6..e5315b9fd 100644 --- a/src/cross_sections.cpp +++ b/src/cross_sections.cpp @@ -155,7 +155,7 @@ void read_cross_sections_xml() if (settings::run_CE) { read_ce_cross_sections_xml(); } else { - read_mg_cross_sections_header(); + data::mgInterface.read_mg_cross_sections_header(); } // Establish mapping between (type, material) and index in libraries diff --git a/src/initialize.cpp b/src/initialize.cpp index fd524a2de..203b5fe91 100644 --- a/src/initialize.cpp +++ b/src/initialize.cpp @@ -260,8 +260,8 @@ void read_input_xml() read_ce_cross_sections(nuc_temps, thermal_temps); } else { // Create material macroscopic data for MGXS - read_mgxs(); - create_macro_xs(); + data::mgInterface.init(settings::path_cross_sections); + data::mgInterface.create_macro_xs(); } simulation::time_read_xs.stop(); } diff --git a/src/material.cpp b/src/material.cpp index 9a1e206ac..e4579e10e 100644 --- a/src/material.cpp +++ b/src/material.cpp @@ -368,7 +368,7 @@ void Material::normalize_density() // determine atomic weight ratio int i_nuc = nuclide_[i]; double awr = settings::run_CE ? - data::nuclides[i_nuc]->awr_ : data::nuclides_MG[i_nuc].awr; + data::nuclides[i_nuc]->awr_ : data::mgInterface.nuclides_MG[i_nuc].awr; // if given weight percent, convert all values so that they are divided // by awr. thus, when a sum is done over the values, it's actually @@ -388,7 +388,7 @@ void Material::normalize_density() for (int i = 0; i < nuclide_.size(); ++i) { int i_nuc = nuclide_[i]; double awr = settings::run_CE ? - data::nuclides[i_nuc]->awr_ : data::nuclides_MG[i_nuc].awr; + data::nuclides[i_nuc]->awr_ : data::mgInterface.nuclides_MG[i_nuc].awr; sum_percent += atom_density_(i)*awr; } sum_percent = 1.0 / sum_percent; @@ -726,7 +726,7 @@ void Material::init_bremsstrahlung() void Material::init_nuclide_index() { int n = settings::run_CE ? - data::nuclides.size() : data::nuclides_MG.size(); + data::nuclides.size() : data::mgInterface.nuclides_MG.size(); mat_nuclide_index_.resize(n); std::fill(mat_nuclide_index_.begin(), mat_nuclide_index_.end(), C_NONE); for (int i = 0; i < nuclide_.size(); ++i) { @@ -994,11 +994,11 @@ void Material::to_hdf5(hid_t group) const } else { for (int i = 0; i < nuclide_.size(); ++i) { int i_nuc = nuclide_[i]; - if (data::nuclides_MG[i_nuc].awr != MACROSCOPIC_AWR) { - nuc_names.push_back(data::nuclides_MG[i_nuc].name); + if (data::mgInterface.nuclides_MG[i_nuc].awr != MACROSCOPIC_AWR) { + nuc_names.push_back(data::mgInterface.nuclides_MG[i_nuc].name); nuc_densities.push_back(atom_density_(i)); } else { - macro_names.push_back(data::nuclides_MG[i_nuc].name); + macro_names.push_back(data::mgInterface.nuclides_MG[i_nuc].name); } } } diff --git a/src/mgxs.cpp b/src/mgxs.cpp index 1fca66308..83adfd0b4 100644 --- a/src/mgxs.cpp +++ b/src/mgxs.cpp @@ -24,18 +24,6 @@ namespace openmc { -//============================================================================== -// Global variables -//============================================================================== - -namespace data { - -// Storage for the MGXS data -std::vector nuclides_MG; -std::vector macro_xs; - -} // namespace data - //============================================================================== // Mgxs base-class methods //============================================================================== @@ -53,8 +41,6 @@ Mgxs::init(const std::string& in_name, double in_awr, kTs = xt::adapt(in_kTs); fissionable = in_fissionable; scatter_format = in_scatter_format; - num_groups = data::num_energy_groups; - num_delayed_groups = data::num_delayed_groups; xs.resize(in_kTs.size()); is_isotropic = in_is_isotropic; n_pol = in_polar.size(); @@ -284,7 +270,10 @@ Mgxs::metadata_from_hdf5(hid_t xs_id, const std::vector& temperature, //============================================================================== -Mgxs::Mgxs(hid_t xs_id, const std::vector& temperature) +Mgxs::Mgxs(hid_t xs_id, const std::vector& temperature, + int num_group, int num_delay) : + num_groups(num_group), + num_delayed_groups(num_delay) { // Call generic data gathering routine (will populate the metadata) int order_data; @@ -317,7 +306,10 @@ Mgxs::Mgxs(hid_t xs_id, const std::vector& temperature) //============================================================================== Mgxs::Mgxs(const std::string& in_name, const std::vector& mat_kTs, - const std::vector& micros, const std::vector& atom_densities) + const std::vector& micros, const std::vector& atom_densities, + int num_group, int num_delay) : + num_groups(num_group), + num_delayed_groups(num_delay) { // Get the minimum data needed to initialize: // Dont need awr, but lets just initialize it anyways diff --git a/src/mgxs_interface.cpp b/src/mgxs_interface.cpp index 29e5e8b36..befa94682 100644 --- a/src/mgxs_interface.cpp +++ b/src/mgxs_interface.cpp @@ -18,30 +18,25 @@ namespace openmc { -//============================================================================== -// Global variable definitions -//============================================================================== - -namespace data { - -int num_energy_groups; -int num_delayed_groups; -std::vector energy_bins; -std::vector energy_bin_avg; -std::vector rev_energy_bins; - -} // namesapce data - //============================================================================== // Mgxs data loading interface methods //============================================================================== -void read_mgxs() +namespace data { + MgxsInterface mgInterface; +} + +MgxsInterface::MgxsInterface(const std::string& path_cross_sections) +{ + init(path_cross_sections); +} + +void MgxsInterface::init(const std::string& path_cross_sections) { // Check if MGXS Library exists - if (!file_exists(settings::path_cross_sections)) { + if (!file_exists(path_cross_sections)) { // Could not find MGXS Library file - fatal_error("Cross sections HDF5 file '" + settings::path_cross_sections + + fatal_error("Cross sections HDF5 file '" + path_cross_sections + "' does not exist."); } @@ -53,7 +48,7 @@ void read_mgxs() get_temperatures(nuc_temps, dummy); // Open file for reading - hid_t file_id = file_open(settings::path_cross_sections, 'r'); + hid_t file_id = file_open(path_cross_sections, 'r'); // Read filetype std::string type; @@ -92,7 +87,7 @@ void read_mgxs() already_read.insert(name); } - if (data::nuclides_MG[i_nuc].fissionable) { + if (nuclides_MG[i_nuc].fissionable) { mat->fissionable_ = true; } } @@ -104,7 +99,7 @@ void read_mgxs() //============================================================================== void -add_mgxs(hid_t file_id, const std::string& name, +MgxsInterface::add_mgxs(hid_t file_id, const std::string& name, const std::vector& temperature) { write_message("Loading " + std::string(name) + " data...", 6); @@ -118,13 +113,14 @@ add_mgxs(hid_t file_id, const std::string& name, + "provided MGXS Library"); } - data::nuclides_MG.emplace_back(xs_grp, temperature); + nuclides_MG.emplace_back(xs_grp, temperature, num_energy_groups, + num_delayed_groups); close_group(xs_grp); } //============================================================================== -void create_macro_xs() +void MgxsInterface::create_macro_xs() { // Get temperatures to read for each material auto kTs = get_mat_kTs(); @@ -144,20 +140,21 @@ void create_macro_xs() // material std::vector mgxs_ptr; for (int i_nuclide : mat->nuclide_) { - mgxs_ptr.push_back(&data::nuclides_MG[i_nuclide]); + mgxs_ptr.push_back(&nuclides_MG[i_nuclide]); } - data::macro_xs.emplace_back(mat->name_, kTs[i], mgxs_ptr, atom_densities); + macro_xs.emplace_back(mat->name_, kTs[i], mgxs_ptr, atom_densities, + num_energy_groups, num_delayed_groups); } else { // Preserve the ordering of materials by including a blank entry - data::macro_xs.emplace_back(); + macro_xs.emplace_back(); } } } //============================================================================== -std::vector> get_mat_kTs() +std::vector> MgxsInterface::get_mat_kTs() { std::vector> kTs(model::materials.size()); @@ -186,7 +183,7 @@ std::vector> get_mat_kTs() //============================================================================== -void read_mg_cross_sections_header() +void MgxsInterface::read_mg_cross_sections_header() { // Check if MGXS Library exists if (!file_exists(settings::path_cross_sections)) { @@ -200,24 +197,25 @@ void read_mg_cross_sections_header() hid_t file_id = file_open(settings::path_cross_sections, 'r', true); ensure_exists(file_id, "energy_groups", true); - read_attribute(file_id, "energy_groups", data::num_energy_groups); + read_attribute(file_id, "energy_groups", num_energy_groups); if (attribute_exists(file_id, "delayed_groups")) { - read_attribute(file_id, "delayed_groups", data::num_delayed_groups); + read_attribute(file_id, "delayed_groups", num_delayed_groups); } else { - data::num_delayed_groups = 0; + num_delayed_groups = 0; } ensure_exists(file_id, "group structure", true); - read_attribute(file_id, "group structure", data::rev_energy_bins); + read_attribute(file_id, "group structure", rev_energy_bins); // Reverse energy bins - std::copy(data::rev_energy_bins.crbegin(), data::rev_energy_bins.crend(), - std::back_inserter(data::energy_bins)); + std::copy(rev_energy_bins.crbegin(), rev_energy_bins.crend(), + std::back_inserter(data::mgInterface.energy_bins)); // Create average energies - for (int i = 0; i < data::energy_bins.size() - 1; ++i) { - data::energy_bin_avg.push_back(0.5*(data::energy_bins[i] + data::energy_bins[i+1])); + for (int i = 0; i < data::mgInterface.energy_bins.size() - 1; ++i) { + data::mgInterface.energy_bin_avg.push_back(0.5* + (data::mgInterface.energy_bins[i] + data::mgInterface.energy_bins[i+1])); } // Add entries into libraries for MG data @@ -236,8 +234,8 @@ void read_mg_cross_sections_header() // Get the minimum and maximum energies int neutron = static_cast(Particle::Type::neutron); - data::energy_min[neutron] = data::energy_bins.back(); - data::energy_max[neutron] = data::energy_bins.front(); + data::energy_min[neutron] = data::mgInterface.energy_bins.back(); + data::energy_max[neutron] = data::mgInterface.energy_bins.front(); // Close MGXS HDF5 file file_close(file_id); @@ -251,7 +249,7 @@ void calculate_xs_c(int i_mat, int gin, double sqrtkT, Direction u, double& total_xs, double& abs_xs, double& nu_fiss_xs) { - data::macro_xs[i_mat].calculate_xs(gin - 1, sqrtkT, u, total_xs, abs_xs, + data::mgInterface.macro_xs[i_mat].calculate_xs(gin - 1, sqrtkT, u, total_xs, abs_xs, nu_fiss_xs); } @@ -269,7 +267,7 @@ get_nuclide_xs(int index, int xstype, int gin, const int* gout, } else { gout_c_p = gout; } - return data::nuclides_MG[index].get_xs(xstype, gin - 1, gout_c_p, mu, dg); + return data::mgInterface.nuclides_MG[index].get_xs(xstype, gin - 1, gout_c_p, mu, dg); } //============================================================================== @@ -286,7 +284,7 @@ get_macro_xs(int index, int xstype, int gin, const int* gout, } else { gout_c_p = gout; } - return data::macro_xs[index].get_xs(xstype, gin - 1, gout_c_p, mu, dg); + return data::mgInterface.macro_xs[index].get_xs(xstype, gin - 1, gout_c_p, mu, dg); } //============================================================================== @@ -301,7 +299,7 @@ get_name_c(int index, int name_len, char* name) std::strcpy(name, str.c_str()); // Now get the data and copy to the C-string - str = data::nuclides_MG[index - 1].name; + str = data::mgInterface.nuclides_MG[index - 1].name; std::strcpy(name, str.c_str()); // Finally, remove the null terminator @@ -313,7 +311,7 @@ get_name_c(int index, int name_len, char* name) double get_awr_c(int index) { - return data::nuclides_MG[index - 1].awr; + return data::mgInterface.nuclides_MG[index - 1].awr; } } // namespace openmc diff --git a/src/output.cpp b/src/output.cpp index d3262cc4d..8fb628e77 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -710,7 +710,7 @@ write_tallies() << data::nuclides[i_nuclide]->name_ << "\n"; } else { tallies_out << std::string(indent+1, ' ') - << data::nuclides_MG[i_nuclide].name << "\n"; + << data::mgInterface.nuclides_MG[i_nuclide].name << "\n"; } } diff --git a/src/particle.cpp b/src/particle.cpp index bf107a741..742f1ead3 100644 --- a/src/particle.cpp +++ b/src/particle.cpp @@ -123,7 +123,7 @@ Particle::from_source(const Bank* src) } else { g_ = static_cast(src->E); g_last_ = static_cast(src->E); - E_ = data::energy_bin_avg[g_ - 1]; + E_ = data::mgInterface.energy_bin_avg[g_ - 1]; } E_last_ = E_; } diff --git a/src/particle_restart.cpp b/src/particle_restart.cpp index b2017bbeb..87b0093d0 100644 --- a/src/particle_restart.cpp +++ b/src/particle_restart.cpp @@ -52,7 +52,7 @@ void read_particle_restart(Particle& p, int& previous_run_mode) // Set energy group and average energy in multi-group mode if (!settings::run_CE) { p.g_ = p.E_; - p.E_ = data::energy_bin_avg[p.g_ - 1]; + p.E_ = data::mgInterface.energy_bin_avg[p.g_ - 1]; } // Set particle last attributes diff --git a/src/physics_mg.cpp b/src/physics_mg.cpp index f99d15aac..e2682792f 100644 --- a/src/physics_mg.cpp +++ b/src/physics_mg.cpp @@ -82,7 +82,7 @@ scatter(Particle* p) int gin = p->g_last_ - 1; int gout = p->g_ - 1; int i_mat = p->material_; - data::macro_xs[i_mat].sample_scatter(gin, gout, p->mu_, p->wgt_); + data::mgInterface.macro_xs[i_mat].sample_scatter(gin, gout, p->mu_, p->wgt_); // Adjust return value for fortran indexing // TODO: Remove when no longer needed @@ -92,7 +92,7 @@ scatter(Particle* p) p->u() = rotate_angle(p->u(), p->mu_, nullptr); // Update energy value for downstream compatability (in tallying) - p->E_ = data::energy_bin_avg[gout]; + p->E_ = data::mgInterface.energy_bin_avg[gout]; // Set event component p->event_ = EVENT_SCATTER; @@ -148,7 +148,7 @@ create_fission_sites(Particle* p, std::vector& bank) // the energy in the fission bank int dg; int gout; - data::macro_xs[p->material_].sample_fission_energy(p->g_ - 1, dg, gout); + data::mgInterface.macro_xs[p->material_].sample_fission_energy(p->g_ - 1, dg, gout); site.E = gout + 1; site.delayed_group = dg + 1; diff --git a/src/source.cpp b/src/source.cpp index 0baa21b17..f495d5572 100644 --- a/src/source.cpp +++ b/src/source.cpp @@ -311,9 +311,9 @@ Particle::Bank sample_external_source() // If running in MG, convert site % E to group if (!settings::run_CE) { - site.E = lower_bound_index(data::rev_energy_bins.begin(), - data::rev_energy_bins.end(), site.E); - site.E = data::num_energy_groups - site.E; + site.E = lower_bound_index(data::mgInterface.rev_energy_bins.begin(), + data::mgInterface.rev_energy_bins.end(), site.E); + site.E = data::mgInterface.num_energy_groups - site.E; } // Set the random number generator back to the tracking stream. diff --git a/src/state_point.cpp b/src/state_point.cpp index cd2c475d8..f0dcfe2b0 100644 --- a/src/state_point.cpp +++ b/src/state_point.cpp @@ -208,7 +208,7 @@ openmc_statepoint_write(const char* filename, bool* write_source) if (settings::run_CE) { nuclides.push_back(data::nuclides[i_nuclide]->name_); } else { - nuclides.push_back(data::nuclides_MG[i_nuclide].name); + nuclides.push_back(data::mgInterface.nuclides_MG[i_nuclide].name); } } } diff --git a/src/summary.cpp b/src/summary.cpp index d2721f97e..0c6222cef 100644 --- a/src/summary.cpp +++ b/src/summary.cpp @@ -57,7 +57,7 @@ void write_nuclides(hid_t file) nuc_names.push_back(nuc->name_); awrs.push_back(nuc->awr_); } else { - const auto& nuc {data::nuclides_MG[i]}; + const auto& nuc {data::mgInterface.nuclides_MG[i]}; if (nuc.awr != MACROSCOPIC_AWR) { nuc_names.push_back(nuc.name); awrs.push_back(nuc.awr); diff --git a/src/tallies/filter_energy.cpp b/src/tallies/filter_energy.cpp index dde9b692a..d69b335b6 100644 --- a/src/tallies/filter_energy.cpp +++ b/src/tallies/filter_energy.cpp @@ -43,10 +43,10 @@ EnergyFilter::set_bins(gsl::span bins) // (after flipping for the different ordering of the library and tallying // systems). if (!settings::run_CE) { - if (n_bins_ == data::num_energy_groups) { + if (n_bins_ == data::mgInterface.num_energy_groups) { matches_transport_groups_ = true; for (gsl::index i = 0; i < n_bins_ + 1; ++i) { - if (data::rev_energy_bins[i] != bins_[i]) { + if (data::mgInterface.rev_energy_bins[i] != bins_[i]) { matches_transport_groups_ = false; break; } @@ -61,9 +61,9 @@ const { if (p->g_ != F90_NONE && matches_transport_groups_) { if (estimator == ESTIMATOR_TRACKLENGTH) { - match.bins_.push_back(data::num_energy_groups - p->g_); + match.bins_.push_back(data::mgInterface.num_energy_groups - p->g_); } else { - match.bins_.push_back(data::num_energy_groups - p->g_last_); + match.bins_.push_back(data::mgInterface.num_energy_groups - p->g_last_); } match.weights_.push_back(1.0); @@ -104,7 +104,7 @@ EnergyoutFilter::get_all_bins(const Particle* p, int estimator, FilterMatch& match) const { if (p->g_ != F90_NONE && matches_transport_groups_) { - match.bins_.push_back(data::num_energy_groups - p->g_); + match.bins_.push_back(data::mgInterface.num_energy_groups - p->g_); match.weights_.push_back(1.0); } else { diff --git a/src/tallies/tally_scoring.cpp b/src/tallies/tally_scoring.cpp index 37310070f..bd31960be 100644 --- a/src/tallies/tally_scoring.cpp +++ b/src/tallies/tally_scoring.cpp @@ -361,7 +361,7 @@ score_fission_eout(const Particle* p, int i_tally, int i_score, int score_bin) if (settings::run_CE) { E_out = bank.E; } else { - E_out = data::energy_bin_avg[static_cast(bank.E)]; + E_out = data::mgInterface.energy_bin_avg[static_cast(bank.E)]; } // Set EnergyoutFilter bin index @@ -1376,13 +1376,13 @@ score_general_mg(const Particle* p, int i_tally, int start_index, // To significantly reduce de-referencing, point matxs to the macroscopic // Mgxs for the material of interest - data::macro_xs[p->material_].set_angle_index(p_u); + data::mgInterface.macro_xs[p->material_].set_angle_index(p_u); // Do same for nucxs, point it to the microscopic nuclide data of interest if (i_nuclide >= 0) { // And since we haven't calculated this temperature index yet, do so now - data::nuclides_MG[i_nuclide].set_temperature_index(p->sqrtkT_); - data::nuclides_MG[i_nuclide].set_angle_index(p_u); + data::mgInterface.nuclides_MG[i_nuclide].set_temperature_index(p->sqrtkT_); + data::mgInterface.nuclides_MG[i_nuclide].set_angle_index(p_u); } for (auto i = 0; i < tally.scores_.size(); ++i) { @@ -1869,7 +1869,7 @@ score_general_mg(const Particle* p, int i_tally, int start_index, // delayed-nu-fission xs to the absorption xs for all delayed // groups score = 0.; - for (auto d = 0; d < data::num_delayed_groups; ++d) { + for (auto d = 0; d < data::mgInterface.num_delayed_groups; ++d) { if (i_nuclide >= 0) { score += p->wgt_absorb_ * flux * get_nuclide_xs(i_nuclide, MG_GET_XS_DECAY_RATE, @@ -1960,7 +1960,7 @@ score_general_mg(const Particle* p, int i_tally, int start_index, continue; } else { score = 0.; - for (auto d = 0; d < data::num_delayed_groups; ++d) { + for (auto d = 0; d < data::mgInterface.num_delayed_groups; ++d) { if (i_nuclide >= 0) { score += atom_density * flux * get_nuclide_xs(i_nuclide, MG_GET_XS_DECAY_RATE, diff --git a/src/xsdata.cpp b/src/xsdata.cpp index cee36a938..ab6fb52d0 100644 --- a/src/xsdata.cpp +++ b/src/xsdata.cpp @@ -27,8 +27,8 @@ namespace openmc { XsData::XsData(bool fissionable, int scatter_format, int n_pol, int n_azi) { size_t n_ang = n_pol * n_azi; - size_t n_dg = data::num_delayed_groups; - size_t n_g = data::num_energy_groups; + size_t n_dg = data::mgInterface.num_delayed_groups; + size_t n_g = data::mgInterface.num_energy_groups; // check to make sure scatter format is OK before we allocate if (scatter_format != ANGLE_HISTOGRAM && scatter_format != ANGLE_TABULAR && @@ -127,8 +127,8 @@ XsData::fission_vector_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, { // Data is provided as nu-fission and chi with a beta for delayed info - size_t n_g = data::num_energy_groups; - size_t n_dg = data::num_delayed_groups; + size_t n_g = data::mgInterface.num_energy_groups; + size_t n_dg = data::mgInterface.num_delayed_groups; // Get chi xt::xtensor temp_chi({n_ang, n_g}, 0.); @@ -182,8 +182,8 @@ XsData::fission_vector_no_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang) { // Data is provided separately as prompt + delayed nu-fission and chi - size_t n_g = data::num_energy_groups; - size_t n_dg = data::num_delayed_groups; + size_t n_g = data::mgInterface.num_energy_groups; + size_t n_dg = data::mgInterface.num_delayed_groups; // Get chi-prompt xt::xtensor temp_chi_p({n_ang, n_g}, 0.); @@ -218,7 +218,7 @@ XsData::fission_vector_no_delayed_from_hdf5(hid_t xsdata_grp, size_t n_ang) // No beta is provided and there is no prompt/delay distinction. // Therefore, the code only considers the data as prompt. - size_t n_g = data::num_energy_groups; + size_t n_g = data::mgInterface.num_energy_groups; // Get chi xt::xtensor temp_chi({n_ang, n_g}, 0.); @@ -241,8 +241,8 @@ XsData::fission_matrix_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, bool is_is { // Data is provided as nu-fission and chi with a beta for delayed info - size_t n_g = data::num_energy_groups; - size_t n_dg = data::num_delayed_groups; + size_t n_g = data::mgInterface.num_energy_groups; + size_t n_dg = data::mgInterface.num_delayed_groups; // Get nu-fission matrix xt::xtensor temp_matrix({n_ang, n_g, n_g}, 0.); @@ -319,8 +319,8 @@ XsData::fission_matrix_no_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang) { // Data is provided separately as prompt + delayed nu-fission and chi - size_t n_g = data::num_energy_groups; - size_t n_dg = data::num_delayed_groups; + size_t n_g = data::mgInterface.num_energy_groups; + size_t n_dg = data::mgInterface.num_delayed_groups; // Get the prompt nu-fission matrix xt::xtensor temp_matrix_p({n_ang, n_g, n_g}, 0.); @@ -353,7 +353,7 @@ XsData::fission_matrix_no_delayed_from_hdf5(hid_t xsdata_grp, size_t n_ang) // No beta is provided and there is no prompt/delay distinction. // Therefore, the code only considers the data as prompt. - size_t n_g = data::num_energy_groups; + size_t n_g = data::mgInterface.num_energy_groups; // Get nu-fission matrix xt::xtensor temp_matrix({n_ang, n_g, n_g}, 0.); @@ -381,7 +381,7 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, size_t n_ang, bool is_isotropic) // as a nu-fission matrix or a set of chi and nu-fission vectors if (object_exists(xsdata_grp, "chi") || object_exists(xsdata_grp, "chi-prompt")) { - if (data::num_delayed_groups == 0) { + if (data::mgInterface.num_delayed_groups == 0) { fission_vector_no_delayed_from_hdf5(xsdata_grp, n_ang); } else { if (object_exists(xsdata_grp, "beta")) { @@ -391,7 +391,7 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, size_t n_ang, bool is_isotropic) } } } else { - if (data::num_delayed_groups == 0) { + if (data::mgInterface.num_delayed_groups == 0) { fission_matrix_no_delayed_from_hdf5(xsdata_grp, n_ang); } else { if (object_exists(xsdata_grp, "beta")) { @@ -403,7 +403,7 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, size_t n_ang, bool is_isotropic) } // Combine prompt_nu_fission and delayed_nu_fission into nu_fission - if (data::num_delayed_groups == 0) { + if (data::mgInterface.num_delayed_groups == 0) { nu_fission = prompt_nu_fission; } else { nu_fission = prompt_nu_fission + xt::sum(delayed_nu_fission, {1}); @@ -422,7 +422,7 @@ XsData::scatter_from_hdf5(hid_t xsdata_grp, size_t n_ang, hid_t scatt_grp = open_group(xsdata_grp, "scatter_data"); // Get the outgoing group boundary indices - size_t n_g = data::num_energy_groups; + size_t n_g = data::mgInterface.num_energy_groups; xt::xtensor gmin({n_ang, n_g}, 0.); read_nd_vector(scatt_grp, "g_min", gmin, true); xt::xtensor gmax({n_ang, n_g}, 0.); From 9e40a8328e6668ee80cef41c1b630c9dbb5a9aac Mon Sep 17 00:00:00 2001 From: Sterling Harper Date: Sun, 3 Nov 2019 13:50:22 -0500 Subject: [PATCH 098/158] Free tally_deriv_map memory --- src/tallies/tally.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tallies/tally.cpp b/src/tallies/tally.cpp index f84387411..eea43989e 100644 --- a/src/tallies/tally.cpp +++ b/src/tallies/tally.cpp @@ -1047,6 +1047,7 @@ free_memory_tally() { model::tally_derivs.clear(); } + model::tally_deriv_map.clear(); model::tally_filters.clear(); model::filter_map.clear(); From b23488325d605fae7a1d4bb63bfaf929e081b95b Mon Sep 17 00:00:00 2001 From: Alec Golas <43121733+awgolas@users.noreply.github.com> Date: Sun, 3 Nov 2019 19:07:29 -0500 Subject: [PATCH 099/158] Update operator.py --- openmc/deplete/operator.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/openmc/deplete/operator.py b/openmc/deplete/operator.py index d8aeb33fd..5ce725a67 100644 --- a/openmc/deplete/operator.py +++ b/openmc/deplete/operator.py @@ -309,7 +309,12 @@ class Operator(TransportOperator): # Assign distribmats to cells for cell in self.geometry.get_all_material_cells().values(): if cell.fill in distribmats and cell.num_instances > 1: - cell.fill = [cell.fill.clone() + mat = cell.fill + if mat.volume is None: + raise RuntimeError("Volume not specified for depletable " + "material with ID={}.".format(mat.id)) + mat.volume /= mat.num_instances + cell.fill = [mat.clone() for i in range(cell.num_instances)] def _get_burnable_mats(self): @@ -341,7 +346,7 @@ class Operator(TransportOperator): if mat.volume is None: raise RuntimeError("Volume not specified for depletable " "material with ID={}.".format(mat.id)) - volume[str(mat.id)] = mat.volume/mat.num_instances + volume[str(mat.id)] = mat.volume self.heavy_metal += mat.fissionable_mass # Make sure there are burnable materials From 57cb1a37defdb35710bca583ba1354fe50fb9ef9 Mon Sep 17 00:00:00 2001 From: rockfool Date: Tue, 5 Nov 2019 11:57:28 -0500 Subject: [PATCH 100/158] create deepcopy in triso model and remove the unnecessary sorted fucntion --- openmc/model/triso.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/openmc/model/triso.py b/openmc/model/triso.py index 2afc88d64..aa561226a 100644 --- a/openmc/model/triso.py +++ b/openmc/model/triso.py @@ -41,6 +41,8 @@ class TRISO(openmc.Cell): Name of the TRISO cell center : numpy.ndarray Cartesian coordinates of the center of the TRISO particle in cm + outer_radius : float + Outer radius of TRISO particle fill : openmc.Universe Universe that contains the TRISO layers region : openmc.Region @@ -52,6 +54,10 @@ class TRISO(openmc.Cell): self._surface = openmc.Sphere(r=outer_radius) super().__init__(fill=fill, region=-self._surface) self.center = np.asarray(center) + self.outer_radius = outer_radius + + def __deepcopy__(self): + return TRISO(outer_radius=self.outer_radius, fill=self.fill, center=self.center) @property def center(self): @@ -827,10 +833,10 @@ def create_triso_lattice(trisos, lower_left, pitch, shape, background): triso_locations = {idx: [] for idx in indices} for t in trisos: for idx in t.classify(lattice): - if idx in sorted(triso_locations): + if idx in triso_locations: # Create copy of TRISO particle with materials preserved and # different cell/surface IDs - t_copy = copy.deepcopy(t) + t_copy = t.__deepcopy__() t_copy.id = None t_copy.fill = t.fill t_copy._surface.id = None From ae5d8cf33b9ca3dd150db1dfbe881ea7d2cc90d4 Mon Sep 17 00:00:00 2001 From: rockfool Date: Tue, 5 Nov 2019 20:19:36 -0500 Subject: [PATCH 101/158] change names for function and variables --- openmc/model/triso.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/openmc/model/triso.py b/openmc/model/triso.py index aa561226a..bc34eed93 100644 --- a/openmc/model/triso.py +++ b/openmc/model/triso.py @@ -54,10 +54,10 @@ class TRISO(openmc.Cell): self._surface = openmc.Sphere(r=outer_radius) super().__init__(fill=fill, region=-self._surface) self.center = np.asarray(center) - self.outer_radius = outer_radius + self._outer_radius = outer_radius - def __deepcopy__(self): - return TRISO(outer_radius=self.outer_radius, fill=self.fill, center=self.center) + def deepcopy(self): + return TRISO(outer_radius=self._outer_radius, fill=self.fill, center=self.center) @property def center(self): @@ -836,7 +836,7 @@ def create_triso_lattice(trisos, lower_left, pitch, shape, background): if idx in triso_locations: # Create copy of TRISO particle with materials preserved and # different cell/surface IDs - t_copy = t.__deepcopy__() + t_copy = t.deepcopy() t_copy.id = None t_copy.fill = t.fill t_copy._surface.id = None From bd6a479370236e9b60f87cae9ba183958c81b923 Mon Sep 17 00:00:00 2001 From: rockfool Date: Wed, 6 Nov 2019 09:49:29 -0500 Subject: [PATCH 102/158] update the input files generated by openmc.model.triso --- tests/regression_tests/triso/inputs_true.dat | 776 +++++++++---------- 1 file changed, 388 insertions(+), 388 deletions(-) diff --git a/tests/regression_tests/triso/inputs_true.dat b/tests/regression_tests/triso/inputs_true.dat index 2ea049465..5c03ad86b 100644 --- a/tests/regression_tests/triso/inputs_true.dat +++ b/tests/regression_tests/triso/inputs_true.dat @@ -1,428 +1,428 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0.3333333333333333 0.3333333333333333 0.3333333333333333 - 38 + 30 3 3 3 -0.5 -0.5 -0.5 -17 18 19 -14 15 16 -11 12 13 +9 10 11 +6 7 8 +3 4 5 -26 27 28 -23 24 25 -20 21 22 +18 19 20 +15 16 17 +12 13 14 -35 36 37 -32 33 34 -29 30 31 +27 28 29 +24 25 26 +21 22 23 - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - + - + - + From 4860bd5ed207bbe1584b0ca29d97022c902c8fff Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Wed, 6 Nov 2019 09:31:56 -0600 Subject: [PATCH 103/158] Updating name of Universer counter class. --- include/openmc/geometry_aux.h | 14 +++++++------- src/finalize.cpp | 2 +- src/geometry_aux.cpp | 18 +++++++++--------- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/include/openmc/geometry_aux.h b/include/openmc/geometry_aux.h index 557d82193..14e119282 100644 --- a/include/openmc/geometry_aux.h +++ b/include/openmc/geometry_aux.h @@ -10,21 +10,21 @@ #include namespace openmc { - struct CellCountStorage { + struct UniverseCellCounter { private: - CellCountStorage() {} - CellCountStorage(CellCountStorage& c) {} - CellCountStorage(const CellCountStorage& c) {} + UniverseCellCounter() {} + UniverseCellCounter(UniverseCellCounter& c) {} + UniverseCellCounter(const UniverseCellCounter& c) {} - static CellCountStorage* instance_; + static UniverseCellCounter* instance_; std::map> counts; public: - static CellCountStorage* instance() { + static UniverseCellCounter* instance() { if (instance_ == nullptr) - instance_ = new CellCountStorage; + instance_ = new UniverseCellCounter; return instance_; } diff --git a/src/finalize.cpp b/src/finalize.cpp index f2cbc973c..3b8530b21 100644 --- a/src/finalize.cpp +++ b/src/finalize.cpp @@ -136,7 +136,7 @@ int openmc_finalize() int openmc_reset() { - CellCountStorage::instance()->clear(); + UniverseCellCounter::instance()->clear(); LevelCountStorage::instance()->clear(); for (auto& t : model::tallies) { diff --git a/src/geometry_aux.cpp b/src/geometry_aux.cpp index 662b6790d..42fb33284 100644 --- a/src/geometry_aux.cpp +++ b/src/geometry_aux.cpp @@ -60,18 +60,18 @@ void read_geometry_xml() model::root_universe = find_root_universe(); } -void CellCountStorage::clear() { +void UniverseCellCounter::clear() { if (instance_ != nullptr) { delete instance_; instance_ = nullptr; } } -void CellCountStorage::set_cell_count_for_univ(int32_t univ, int32_t cell, int count) { +void UniverseCellCounter::set_cell_count_for_univ(int32_t univ, int32_t cell, int count) { counts[univ][cell] = count; } - void CellCountStorage::increment_count_for_univ(int32_t univ, int32_t cell) { + void UniverseCellCounter::increment_count_for_univ(int32_t univ, int32_t cell) { if (has_count(univ,cell)) { counts[univ][cell] += 1; } else { @@ -79,15 +79,15 @@ void CellCountStorage::set_cell_count_for_univ(int32_t univ, int32_t cell, int c } } -bool CellCountStorage::has_count(int32_t univ, int32_t cell) { +bool UniverseCellCounter::has_count(int32_t univ, int32_t cell) { return counts.count(univ) && counts[univ].count(cell); } -bool CellCountStorage::has_count(int32_t univ) { +bool UniverseCellCounter::has_count(int32_t univ) { return counts.count(univ); } -void CellCountStorage::absorb_b_into_a(int32_t a, int32_t b) { +void UniverseCellCounter::absorb_b_into_a(int32_t a, int32_t b) { std::map b_map = counts[b]; for (auto it : b_map) { @@ -99,7 +99,7 @@ void CellCountStorage::absorb_b_into_a(int32_t a, int32_t b) { } } -auto CellCountStorage::get_count(int32_t univ) { +auto UniverseCellCounter::get_count(int32_t univ) { return counts[univ]; } @@ -142,7 +142,7 @@ int LevelCountStorage::get_count(int32_t univ) { return counts[univ]; } -CellCountStorage* CellCountStorage::instance_ = nullptr; +UniverseCellCounter* UniverseCellCounter::instance_ = nullptr; LevelCountStorage* LevelCountStorage::instance_ = nullptr; //============================================================================== @@ -480,7 +480,7 @@ prepare_distribcell() void count_cell_instances(int32_t univ_indx) { - CellCountStorage* counter = CellCountStorage::instance(); + UniverseCellCounter* counter = UniverseCellCounter::instance(); if (counter->has_count(univ_indx)) { std::map univ_counts = counter->get_count(univ_indx); From c20e942f1ccb7deb6edd6c63d31d3575f735b484 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Wed, 6 Nov 2019 09:36:41 -0600 Subject: [PATCH 104/158] Update name of universe level counter. --- include/openmc/geometry_aux.h | 14 +++++++------- src/finalize.cpp | 2 +- src/geometry_aux.cpp | 18 +++++++++--------- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/include/openmc/geometry_aux.h b/include/openmc/geometry_aux.h index 14e119282..0e694e982 100644 --- a/include/openmc/geometry_aux.h +++ b/include/openmc/geometry_aux.h @@ -46,21 +46,21 @@ namespace openmc { auto get_count(int32_t univ); }; - struct LevelCountStorage { + struct UniverseLevelCounter { private: - LevelCountStorage() {} - LevelCountStorage(LevelCountStorage& c) {} - LevelCountStorage(const LevelCountStorage& c) {} + UniverseLevelCounter() {} + UniverseLevelCounter(UniverseLevelCounter& c) {} + UniverseLevelCounter(const UniverseLevelCounter& c) {} - static LevelCountStorage* instance_; + static UniverseLevelCounter* instance_; std::map counts; public: - static LevelCountStorage* instance() { + static UniverseLevelCounter* instance() { if (instance_ == nullptr) - instance_ = new LevelCountStorage; + instance_ = new UniverseLevelCounter; return instance_; } diff --git a/src/finalize.cpp b/src/finalize.cpp index 3b8530b21..534382382 100644 --- a/src/finalize.cpp +++ b/src/finalize.cpp @@ -137,7 +137,7 @@ int openmc_reset() { UniverseCellCounter::instance()->clear(); - LevelCountStorage::instance()->clear(); + UniverseLevelCounter::instance()->clear(); for (auto& t : model::tallies) { t->reset(); diff --git a/src/geometry_aux.cpp b/src/geometry_aux.cpp index 42fb33284..3a98d02b6 100644 --- a/src/geometry_aux.cpp +++ b/src/geometry_aux.cpp @@ -103,18 +103,18 @@ auto UniverseCellCounter::get_count(int32_t univ) { return counts[univ]; } -void LevelCountStorage::clear() { +void UniverseLevelCounter::clear() { if (instance_ != nullptr) { delete instance_; instance_ = nullptr; } } -void LevelCountStorage::set_cell_count_for_univ(int32_t univ, int count) { +void UniverseLevelCounter::set_cell_count_for_univ(int32_t univ, int count) { counts[univ] = count; } -void LevelCountStorage::increment_count_for_univ(int32_t univ) { +void UniverseLevelCounter::increment_count_for_univ(int32_t univ) { if (has_count(univ)) { counts[univ] += 1; } else { @@ -122,11 +122,11 @@ void LevelCountStorage::increment_count_for_univ(int32_t univ) { } } -bool LevelCountStorage::has_count(int32_t univ) { +bool UniverseLevelCounter::has_count(int32_t univ) { return counts.count(univ); } -void LevelCountStorage::absorb_b_into_a(int32_t a, int32_t b) { +void UniverseLevelCounter::absorb_b_into_a(int32_t a, int32_t b) { if (has_count(a)) { counts[a] += counts[b]; } else { @@ -134,16 +134,16 @@ void LevelCountStorage::absorb_b_into_a(int32_t a, int32_t b) { } } -void LevelCountStorage::set_count(int32_t univ, int count) { +void UniverseLevelCounter::set_count(int32_t univ, int count) { counts[univ] = count; } -int LevelCountStorage::get_count(int32_t univ) { +int UniverseLevelCounter::get_count(int32_t univ) { return counts[univ]; } UniverseCellCounter* UniverseCellCounter::instance_ = nullptr; -LevelCountStorage* LevelCountStorage::instance_ = nullptr; +UniverseLevelCounter* UniverseLevelCounter::instance_ = nullptr; //============================================================================== @@ -626,7 +626,7 @@ distribcell_path(int32_t target_cell, int32_t map, int32_t target_offset) int maximum_levels(int32_t univ) { - LevelCountStorage* counter = LevelCountStorage::instance(); + UniverseLevelCounter* counter = UniverseLevelCounter::instance(); if (counter->has_count(univ)) { return counter->get_count(univ); From d37c416308bb6ec13e5857ef8d3eb28ce47a1e9f Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Wed, 6 Nov 2019 15:28:06 -0600 Subject: [PATCH 105/158] Updating attribute name and placing below methods. --- include/openmc/geometry_aux.h | 15 +-- src/geometry_aux.cpp | 170 +++++++++++++++++----------------- 2 files changed, 94 insertions(+), 91 deletions(-) diff --git a/include/openmc/geometry_aux.h b/include/openmc/geometry_aux.h index 0e694e982..bf09aacec 100644 --- a/include/openmc/geometry_aux.h +++ b/include/openmc/geometry_aux.h @@ -18,10 +18,9 @@ namespace openmc { static UniverseCellCounter* instance_; - std::map> counts; - public: + // Methods static UniverseCellCounter* instance() { if (instance_ == nullptr) instance_ = new UniverseCellCounter; @@ -29,8 +28,6 @@ namespace openmc { return instance_; } - - void clear(); void set_cell_count_for_univ(int32_t univ, int32_t cell, int count); @@ -44,6 +41,9 @@ namespace openmc { void absorb_b_into_a(int32_t a, int32_t b); auto get_count(int32_t univ); + + // Members + std::map> counts_; }; struct UniverseLevelCounter { @@ -54,10 +54,10 @@ namespace openmc { static UniverseLevelCounter* instance_; - std::map counts; - public: + //Methods + static UniverseLevelCounter* instance() { if (instance_ == nullptr) instance_ = new UniverseLevelCounter; @@ -78,6 +78,9 @@ namespace openmc { void set_count(int32_t univ, int count); int get_count(int32_t univ); + + // Members + std::map counts_; }; void read_geometry_xml(); diff --git a/src/geometry_aux.cpp b/src/geometry_aux.cpp index 3a98d02b6..436528927 100644 --- a/src/geometry_aux.cpp +++ b/src/geometry_aux.cpp @@ -23,6 +23,91 @@ namespace openmc { +void UniverseCellCounter::clear() { + if (instance_ != nullptr) { + delete instance_; + instance_ = nullptr; + } +} + +void UniverseCellCounter::set_cell_count_for_univ(int32_t univ, int32_t cell, int count) { + counts_[univ][cell] = count; +} + + void UniverseCellCounter::increment_count_for_univ(int32_t univ, int32_t cell) { + if (has_count(univ,cell)) { + counts_[univ][cell] += 1; + } else { + counts_[univ][cell] = 1; + } + } + +bool UniverseCellCounter::has_count(int32_t univ, int32_t cell) { + return counts_.count(univ) && counts_[univ].count(cell); +} + +bool UniverseCellCounter::has_count(int32_t univ) { + return counts_.count(univ); +} + +void UniverseCellCounter::absorb_b_into_a(int32_t a, int32_t b) { + std::map b_map = counts_[b]; + + for (auto it : b_map) { + if (has_count(a, it.first)) { + counts_[a][it.first] += it.second; + } else { + counts_[a][it.first] = it.second; + } + } +} + +auto UniverseCellCounter::get_count(int32_t univ) { + return counts_[univ]; +} + +void UniverseLevelCounter::clear() { + if (instance_ != nullptr) { + delete instance_; + instance_ = nullptr; + } +} + +void UniverseLevelCounter::set_cell_count_for_univ(int32_t univ, int count) { + counts_[univ] = count; +} + +void UniverseLevelCounter::increment_count_for_univ(int32_t univ) { + if (has_count(univ)) { + counts_[univ] += 1; + } else { + counts_[univ] = 1; + } +} + +bool UniverseLevelCounter::has_count(int32_t univ) { + return counts_.count(univ); +} + +void UniverseLevelCounter::absorb_b_into_a(int32_t a, int32_t b) { + if (has_count(a)) { + counts_[a] += counts_[b]; + } else { + counts_[a] = counts_[b]; + } +} + +void UniverseLevelCounter::set_count(int32_t univ, int count) { + counts_[univ] = count; +} + +int UniverseLevelCounter::get_count(int32_t univ) { + return counts_[univ]; +} + +UniverseCellCounter* UniverseCellCounter::instance_ = nullptr; +UniverseLevelCounter* UniverseLevelCounter::instance_ = nullptr; + void read_geometry_xml() { #ifdef DAGMC @@ -60,91 +145,6 @@ void read_geometry_xml() model::root_universe = find_root_universe(); } -void UniverseCellCounter::clear() { - if (instance_ != nullptr) { - delete instance_; - instance_ = nullptr; - } -} - -void UniverseCellCounter::set_cell_count_for_univ(int32_t univ, int32_t cell, int count) { - counts[univ][cell] = count; -} - - void UniverseCellCounter::increment_count_for_univ(int32_t univ, int32_t cell) { - if (has_count(univ,cell)) { - counts[univ][cell] += 1; - } else { - counts[univ][cell] = 1; - } - } - -bool UniverseCellCounter::has_count(int32_t univ, int32_t cell) { - return counts.count(univ) && counts[univ].count(cell); -} - -bool UniverseCellCounter::has_count(int32_t univ) { - return counts.count(univ); -} - -void UniverseCellCounter::absorb_b_into_a(int32_t a, int32_t b) { - std::map b_map = counts[b]; - - for (auto it : b_map) { - if (has_count(a, it.first)) { - counts[a][it.first] += it.second; - } else { - counts[a][it.first] = it.second; - } - } -} - -auto UniverseCellCounter::get_count(int32_t univ) { - return counts[univ]; -} - -void UniverseLevelCounter::clear() { - if (instance_ != nullptr) { - delete instance_; - instance_ = nullptr; - } -} - -void UniverseLevelCounter::set_cell_count_for_univ(int32_t univ, int count) { - counts[univ] = count; -} - -void UniverseLevelCounter::increment_count_for_univ(int32_t univ) { - if (has_count(univ)) { - counts[univ] += 1; - } else { - counts[univ] = 1; - } -} - -bool UniverseLevelCounter::has_count(int32_t univ) { - return counts.count(univ); -} - -void UniverseLevelCounter::absorb_b_into_a(int32_t a, int32_t b) { - if (has_count(a)) { - counts[a] += counts[b]; - } else { - counts[a] = counts[b]; - } -} - -void UniverseLevelCounter::set_count(int32_t univ, int count) { - counts[univ] = count; -} - -int UniverseLevelCounter::get_count(int32_t univ) { - return counts[univ]; -} - -UniverseCellCounter* UniverseCellCounter::instance_ = nullptr; -UniverseLevelCounter* UniverseLevelCounter::instance_ = nullptr; - //============================================================================== void From 053434b99daf246f954155d9568a00eaf5764e8d Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Wed, 6 Nov 2019 15:32:00 -0600 Subject: [PATCH 106/158] Simplifying clears and absorption methods. --- src/geometry_aux.cpp | 37 ++++++------------------------------- 1 file changed, 6 insertions(+), 31 deletions(-) diff --git a/src/geometry_aux.cpp b/src/geometry_aux.cpp index 436528927..3ee0648f9 100644 --- a/src/geometry_aux.cpp +++ b/src/geometry_aux.cpp @@ -24,23 +24,16 @@ namespace openmc { void UniverseCellCounter::clear() { - if (instance_ != nullptr) { - delete instance_; - instance_ = nullptr; - } + instance_->counts_.clear(); } void UniverseCellCounter::set_cell_count_for_univ(int32_t univ, int32_t cell, int count) { counts_[univ][cell] = count; } - void UniverseCellCounter::increment_count_for_univ(int32_t univ, int32_t cell) { - if (has_count(univ,cell)) { - counts_[univ][cell] += 1; - } else { - counts_[univ][cell] = 1; - } - } +void UniverseCellCounter::increment_count_for_univ(int32_t univ, int32_t cell) { + counts_[univ][cell] += 1; +} bool UniverseCellCounter::has_count(int32_t univ, int32_t cell) { return counts_.count(univ) && counts_[univ].count(cell); @@ -52,14 +45,7 @@ bool UniverseCellCounter::has_count(int32_t univ) { void UniverseCellCounter::absorb_b_into_a(int32_t a, int32_t b) { std::map b_map = counts_[b]; - - for (auto it : b_map) { - if (has_count(a, it.first)) { - counts_[a][it.first] += it.second; - } else { - counts_[a][it.first] = it.second; - } - } + for (auto it : b_map) { counts_[a][it.first] += it.second; } } auto UniverseCellCounter::get_count(int32_t univ) { @@ -67,10 +53,7 @@ auto UniverseCellCounter::get_count(int32_t univ) { } void UniverseLevelCounter::clear() { - if (instance_ != nullptr) { - delete instance_; - instance_ = nullptr; - } + instance_->counts_.clear(); } void UniverseLevelCounter::set_cell_count_for_univ(int32_t univ, int count) { @@ -78,11 +61,7 @@ void UniverseLevelCounter::set_cell_count_for_univ(int32_t univ, int count) { } void UniverseLevelCounter::increment_count_for_univ(int32_t univ) { - if (has_count(univ)) { counts_[univ] += 1; - } else { - counts_[univ] = 1; - } } bool UniverseLevelCounter::has_count(int32_t univ) { @@ -90,11 +69,7 @@ bool UniverseLevelCounter::has_count(int32_t univ) { } void UniverseLevelCounter::absorb_b_into_a(int32_t a, int32_t b) { - if (has_count(a)) { counts_[a] += counts_[b]; - } else { - counts_[a] = counts_[b]; - } } void UniverseLevelCounter::set_count(int32_t univ, int count) { From a685e4768c3e36f89d6c0967729962b2c9e2ea8f Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Wed, 6 Nov 2019 16:03:51 -0600 Subject: [PATCH 107/158] Removing class defs in favor of STL types. --- include/openmc/geometry_aux.h | 72 +--------------------------- src/finalize.cpp | 4 +- src/geometry_aux.cpp | 88 +++++++++-------------------------- 3 files changed, 26 insertions(+), 138 deletions(-) diff --git a/include/openmc/geometry_aux.h b/include/openmc/geometry_aux.h index bf09aacec..04c377400 100644 --- a/include/openmc/geometry_aux.h +++ b/include/openmc/geometry_aux.h @@ -10,78 +10,10 @@ #include namespace openmc { - struct UniverseCellCounter { - private: - UniverseCellCounter() {} - UniverseCellCounter(UniverseCellCounter& c) {} - UniverseCellCounter(const UniverseCellCounter& c) {} - static UniverseCellCounter* instance_; + extern std::map> universe_cell_counts; + extern std::map universe_level_counts; - public: - - // Methods - static UniverseCellCounter* instance() { - if (instance_ == nullptr) - instance_ = new UniverseCellCounter; - - return instance_; - } - - void clear(); - - void set_cell_count_for_univ(int32_t univ, int32_t cell, int count); - - void increment_count_for_univ(int32_t univ, int32_t cell); - - bool has_count(int32_t univ, int32_t cell); - - bool has_count(int32_t univ); - - void absorb_b_into_a(int32_t a, int32_t b); - - auto get_count(int32_t univ); - - // Members - std::map> counts_; - }; - - struct UniverseLevelCounter { - private: - UniverseLevelCounter() {} - UniverseLevelCounter(UniverseLevelCounter& c) {} - UniverseLevelCounter(const UniverseLevelCounter& c) {} - - static UniverseLevelCounter* instance_; - - public: - - //Methods - - static UniverseLevelCounter* instance() { - if (instance_ == nullptr) - instance_ = new UniverseLevelCounter; - - return instance_; - } - - void clear(); - - void set_cell_count_for_univ(int32_t univ, int count); - - void increment_count_for_univ(int32_t univ); - - bool has_count(int32_t univ); - - void absorb_b_into_a(int32_t a, int32_t b); - - void set_count(int32_t univ, int count); - - int get_count(int32_t univ); - - // Members - std::map counts_; - }; void read_geometry_xml(); diff --git a/src/finalize.cpp b/src/finalize.cpp index 534382382..6012dfd0b 100644 --- a/src/finalize.cpp +++ b/src/finalize.cpp @@ -136,8 +136,8 @@ int openmc_finalize() int openmc_reset() { - UniverseCellCounter::instance()->clear(); - UniverseLevelCounter::instance()->clear(); + universe_cell_counts.clear(); + universe_level_counts.clear(); for (auto& t : model::tallies) { t->reset(); diff --git a/src/geometry_aux.cpp b/src/geometry_aux.cpp index 3ee0648f9..0d95ccbcc 100644 --- a/src/geometry_aux.cpp +++ b/src/geometry_aux.cpp @@ -23,66 +23,24 @@ namespace openmc { -void UniverseCellCounter::clear() { - instance_->counts_.clear(); +std::map> universe_cell_counts; +std::map universe_level_counts; + + +void update_universe_cell_count(int32_t a, int32_t b) { + auto& universe_a_counts = universe_cell_counts[a]; + const auto& universe_b_counts = universe_cell_counts[b]; + for (auto it : universe_b_counts) { + universe_a_counts[it.first] += it.second; + } } -void UniverseCellCounter::set_cell_count_for_univ(int32_t univ, int32_t cell, int count) { - counts_[univ][cell] = count; +void update_universe_level_count(int32_t a, int32_t b) { + auto& universe_a_count = universe_level_counts[a]; + const auto& universe_b_count = universe_level_counts[b]; + universe_a_count += universe_b_count; } -void UniverseCellCounter::increment_count_for_univ(int32_t univ, int32_t cell) { - counts_[univ][cell] += 1; -} - -bool UniverseCellCounter::has_count(int32_t univ, int32_t cell) { - return counts_.count(univ) && counts_[univ].count(cell); -} - -bool UniverseCellCounter::has_count(int32_t univ) { - return counts_.count(univ); -} - -void UniverseCellCounter::absorb_b_into_a(int32_t a, int32_t b) { - std::map b_map = counts_[b]; - for (auto it : b_map) { counts_[a][it.first] += it.second; } -} - -auto UniverseCellCounter::get_count(int32_t univ) { - return counts_[univ]; -} - -void UniverseLevelCounter::clear() { - instance_->counts_.clear(); -} - -void UniverseLevelCounter::set_cell_count_for_univ(int32_t univ, int count) { - counts_[univ] = count; -} - -void UniverseLevelCounter::increment_count_for_univ(int32_t univ) { - counts_[univ] += 1; -} - -bool UniverseLevelCounter::has_count(int32_t univ) { - return counts_.count(univ); -} - -void UniverseLevelCounter::absorb_b_into_a(int32_t a, int32_t b) { - counts_[a] += counts_[b]; -} - -void UniverseLevelCounter::set_count(int32_t univ, int count) { - counts_[univ] = count; -} - -int UniverseLevelCounter::get_count(int32_t univ) { - return counts_[univ]; -} - -UniverseCellCounter* UniverseCellCounter::instance_ = nullptr; -UniverseLevelCounter* UniverseLevelCounter::instance_ = nullptr; - void read_geometry_xml() { #ifdef DAGMC @@ -455,10 +413,9 @@ prepare_distribcell() void count_cell_instances(int32_t univ_indx) { - UniverseCellCounter* counter = UniverseCellCounter::instance(); - if (counter->has_count(univ_indx)) { - std::map univ_counts = counter->get_count(univ_indx); + if (universe_cell_counts.count(univ_indx)) { + std::map univ_counts = universe_cell_counts[univ_indx]; for(auto it : univ_counts) { Cell& c = *model::cells[it.first]; c.n_instances_ += it.second; @@ -467,18 +424,18 @@ count_cell_instances(int32_t univ_indx) for (int32_t cell_indx : model::universes[univ_indx]->cells_) { Cell& c = *model::cells[cell_indx]; ++c.n_instances_; - counter->increment_count_for_univ(univ_indx, cell_indx); + universe_cell_counts[univ_indx][cell_indx] += 1; if (c.type_ == FILL_UNIVERSE) { // This cell contains another universe. Recurse into that universe. count_cell_instances(c.fill_); - counter->absorb_b_into_a(univ_indx, c.fill_); + update_universe_cell_count(univ_indx, c.fill_); } else if (c.type_ == FILL_LATTICE) { // This cell contains a lattice. Recurse into the lattice universes. Lattice& lat = *model::lattices[c.fill_]; for (auto it = lat.begin(); it != lat.end(); ++it) { count_cell_instances(*it); - counter->absorb_b_into_a(univ_indx, *it); + update_universe_cell_count(univ_indx, *it); } } } @@ -601,10 +558,9 @@ distribcell_path(int32_t target_cell, int32_t map, int32_t target_offset) int maximum_levels(int32_t univ) { - UniverseLevelCounter* counter = UniverseLevelCounter::instance(); - if (counter->has_count(univ)) { - return counter->get_count(univ); + if (universe_level_counts.count(univ)) { + return universe_level_counts[univ]; } int levels_below {0}; @@ -624,7 +580,7 @@ maximum_levels(int32_t univ) } ++levels_below; - counter->set_count(univ, levels_below); + universe_level_counts[univ] = levels_below; return levels_below; } From 031047ee80a8952d7e5bad8e7ee0db3c122c700e Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Wed, 6 Nov 2019 16:07:28 -0600 Subject: [PATCH 108/158] Moving counters into the model namespace. --- include/openmc/geometry_aux.h | 3 ++- src/finalize.cpp | 4 ++-- src/geometry_aux.cpp | 27 ++++++++++++++------------- 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/include/openmc/geometry_aux.h b/include/openmc/geometry_aux.h index 04c377400..677dcf180 100644 --- a/include/openmc/geometry_aux.h +++ b/include/openmc/geometry_aux.h @@ -11,9 +11,10 @@ namespace openmc { +namespace model { extern std::map> universe_cell_counts; extern std::map universe_level_counts; - +} // namespace model void read_geometry_xml(); diff --git a/src/finalize.cpp b/src/finalize.cpp index 6012dfd0b..16ff0fbcc 100644 --- a/src/finalize.cpp +++ b/src/finalize.cpp @@ -136,8 +136,8 @@ int openmc_finalize() int openmc_reset() { - universe_cell_counts.clear(); - universe_level_counts.clear(); + model::universe_cell_counts.clear(); + model::universe_level_counts.clear(); for (auto& t : model::tallies) { t->reset(); diff --git a/src/geometry_aux.cpp b/src/geometry_aux.cpp index 0d95ccbcc..229b46b8c 100644 --- a/src/geometry_aux.cpp +++ b/src/geometry_aux.cpp @@ -23,21 +23,22 @@ namespace openmc { -std::map> universe_cell_counts; -std::map universe_level_counts; - +namespace model { + std::map> universe_cell_counts; + std::map universe_level_counts; +} // namespace model void update_universe_cell_count(int32_t a, int32_t b) { - auto& universe_a_counts = universe_cell_counts[a]; - const auto& universe_b_counts = universe_cell_counts[b]; + auto& universe_a_counts = model::universe_cell_counts[a]; + const auto& universe_b_counts = model::universe_cell_counts[b]; for (auto it : universe_b_counts) { universe_a_counts[it.first] += it.second; } } void update_universe_level_count(int32_t a, int32_t b) { - auto& universe_a_count = universe_level_counts[a]; - const auto& universe_b_count = universe_level_counts[b]; + auto& universe_a_count = model::universe_level_counts[a]; + const auto& universe_b_count = model::universe_level_counts[b]; universe_a_count += universe_b_count; } @@ -414,8 +415,8 @@ void count_cell_instances(int32_t univ_indx) { - if (universe_cell_counts.count(univ_indx)) { - std::map univ_counts = universe_cell_counts[univ_indx]; + if (model::universe_cell_counts.count(univ_indx)) { + std::map univ_counts = model::universe_cell_counts[univ_indx]; for(auto it : univ_counts) { Cell& c = *model::cells[it.first]; c.n_instances_ += it.second; @@ -424,7 +425,7 @@ count_cell_instances(int32_t univ_indx) for (int32_t cell_indx : model::universes[univ_indx]->cells_) { Cell& c = *model::cells[cell_indx]; ++c.n_instances_; - universe_cell_counts[univ_indx][cell_indx] += 1; + model::universe_cell_counts[univ_indx][cell_indx] += 1; if (c.type_ == FILL_UNIVERSE) { // This cell contains another universe. Recurse into that universe. @@ -559,8 +560,8 @@ int maximum_levels(int32_t univ) { - if (universe_level_counts.count(univ)) { - return universe_level_counts[univ]; + if (model::universe_level_counts.count(univ)) { + return model::universe_level_counts[univ]; } int levels_below {0}; @@ -580,7 +581,7 @@ maximum_levels(int32_t univ) } ++levels_below; - universe_level_counts[univ] = levels_below; + model::universe_level_counts[univ] = levels_below; return levels_below; } From f75db76c709f8598bfd395712002f8aabf746573 Mon Sep 17 00:00:00 2001 From: rockfool Date: Thu, 7 Nov 2019 10:31:57 -0500 Subject: [PATCH 109/158] address reviewers' comment on deepcopy and tests input --- openmc/model/triso.py | 12 +- tests/regression_tests/triso/inputs_true.dat | 776 +++++++++---------- 2 files changed, 394 insertions(+), 394 deletions(-) diff --git a/openmc/model/triso.py b/openmc/model/triso.py index bc34eed93..1e27e126a 100644 --- a/openmc/model/triso.py +++ b/openmc/model/triso.py @@ -54,10 +54,6 @@ class TRISO(openmc.Cell): self._surface = openmc.Sphere(r=outer_radius) super().__init__(fill=fill, region=-self._surface) self.center = np.asarray(center) - self._outer_radius = outer_radius - - def deepcopy(self): - return TRISO(outer_radius=self._outer_radius, fill=self.fill, center=self.center) @property def center(self): @@ -836,10 +832,14 @@ def create_triso_lattice(trisos, lower_left, pitch, shape, background): if idx in triso_locations: # Create copy of TRISO particle with materials preserved and # different cell/surface IDs - t_copy = t.deepcopy() + t_copy = copy.copy(t) t_copy.id = None t_copy.fill = t.fill - t_copy._surface.id = None + t_copy._surface = openmc.Sphere(r=t._surface.r, + x0=t._surface.x0, + y0=t._surface.y0, + z0=t._surface.z0) + t_copy.region = -t_copy._surface triso_locations[idx].append(t_copy) else: warnings.warn('TRISO particle is partially or completely ' diff --git a/tests/regression_tests/triso/inputs_true.dat b/tests/regression_tests/triso/inputs_true.dat index 5c03ad86b..2ea049465 100644 --- a/tests/regression_tests/triso/inputs_true.dat +++ b/tests/regression_tests/triso/inputs_true.dat @@ -1,428 +1,428 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0.3333333333333333 0.3333333333333333 0.3333333333333333 - 30 + 38 3 3 3 -0.5 -0.5 -0.5 -9 10 11 -6 7 8 -3 4 5 +17 18 19 +14 15 16 +11 12 13 -18 19 20 -15 16 17 -12 13 14 +26 27 28 +23 24 25 +20 21 22 -27 28 29 -24 25 26 -21 22 23 +35 36 37 +32 33 34 +29 30 31 - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - + - + - + From 540a3ba66abb9740680ebc515e540fc41a340b43 Mon Sep 17 00:00:00 2001 From: rockfool Date: Thu, 7 Nov 2019 11:30:49 -0500 Subject: [PATCH 110/158] clean comment for outer_radius --- openmc/model/triso.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/openmc/model/triso.py b/openmc/model/triso.py index 1e27e126a..2552623a0 100644 --- a/openmc/model/triso.py +++ b/openmc/model/triso.py @@ -41,8 +41,6 @@ class TRISO(openmc.Cell): Name of the TRISO cell center : numpy.ndarray Cartesian coordinates of the center of the TRISO particle in cm - outer_radius : float - Outer radius of TRISO particle fill : openmc.Universe Universe that contains the TRISO layers region : openmc.Region From a2bcb07e0333073a16e2035b05e967ffea571d2e Mon Sep 17 00:00:00 2001 From: Gavin Ridley Date: Thu, 7 Nov 2019 13:27:16 -0500 Subject: [PATCH 111/158] Mgxs may now be used in external linked programs --- include/openmc/hdf5_interface.h | 4 +- include/openmc/mgxs_interface.h | 38 +++++++- include/openmc/xsdata.h | 8 +- src/cross_sections.cpp | 3 +- src/initialize.cpp | 5 +- src/mgxs.cpp | 5 +- src/mgxs_interface.cpp | 159 +++++++++++++++++++++----------- src/xsdata.cpp | 30 ++---- 8 files changed, 163 insertions(+), 89 deletions(-) diff --git a/include/openmc/hdf5_interface.h b/include/openmc/hdf5_interface.h index d0474c834..ee3419fa2 100644 --- a/include/openmc/hdf5_interface.h +++ b/include/openmc/hdf5_interface.h @@ -345,7 +345,7 @@ read_dataset(hid_t obj_id, const char* name, Position& r, bool indep=false) } template -void read_dataset_as_shape(hid_t obj_id, const char* name, +inline void read_dataset_as_shape(hid_t obj_id, const char* name, xt::xtensor& arr, bool indep=false) { hid_t dset = open_dataset(obj_id, name); @@ -367,7 +367,7 @@ void read_dataset_as_shape(hid_t obj_id, const char* name, template -void read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, +inline void read_nd_vector(hid_t obj_id, const char* name, xt::xtensor& result, bool must_have=false) { if (object_exists(obj_id, name)) { diff --git a/include/openmc/mgxs_interface.h b/include/openmc/mgxs_interface.h index c72587be2..0c1091c4b 100644 --- a/include/openmc/mgxs_interface.h +++ b/include/openmc/mgxs_interface.h @@ -20,6 +20,14 @@ struct MgxsInterface int num_energy_groups; int num_delayed_groups; + // List of available names in the HDF5 file + std::vector xs_names; + std::vector xs_to_read; + std::vector> xs_temps_to_read; + + // Name of the HDF5 file which contains mgxs + std::string cross_sections_path; + std::vector nuclides_MG; std::vector macro_xs; @@ -27,12 +35,20 @@ struct MgxsInterface std::vector energy_bin_avg; std::vector rev_energy_bins; + // temperatues of each available nuclide + std::vector> nuc_temps; + MgxsInterface() = default; - // Construct from path to cross sections file - MgxsInterface(const std::string& path_cross_sections); + // Construct from path to cross sections file, as well as a list + // of XS to read and the corresponding temperatures for each XS + MgxsInterface(const std::string& path_cross_sections, + const std::vector xs_to_read, + const std::vector> xs_temps); + void setNuclidesToRead(std::vector arg_xs_to_read); + void setNuclideTemperaturesToRead(std::vector> xs_temps); - void init(const std::string& path_cross_sections); + void init(); void add_mgxs(hid_t file_id, const std::string& name, const std::vector& temperature); @@ -41,13 +57,27 @@ struct MgxsInterface std::vector> get_mat_kTs(); - void read_mg_cross_sections_header(); + // Reads just the header of the cross sections file, to find + // min & max energies as well as the available XS + void readHeader(const std::string& path_cross_sections); }; namespace data { extern MgxsInterface mgInterface; } +// Puts available XS in MGXS file to globals so that when +// materials are read, the MGXS specified in a material can +// be ensured to be present in the available data. +void putMgxsHeaderDataToGlobals(); + +// Set which nuclides and temperatures are to be read on +// mgInterface through global data +void setMgInterfaceNuclidesAndTemps(); + +// After macro XS have been read, materials can be marked as fissionable +void markFissionableMgxsMaterials(); + //============================================================================== // Mgxs tracking/transport/tallying interface methods //============================================================================== diff --git a/include/openmc/xsdata.h b/include/openmc/xsdata.h index a8aed5d17..f7ba802b8 100644 --- a/include/openmc/xsdata.h +++ b/include/openmc/xsdata.h @@ -22,6 +22,9 @@ namespace openmc { class XsData { private: + //! Number of energy and delayed neutron groups + size_t n_g, n_dg; + //! \brief Reads scattering data from the HDF5 file void scatter_from_hdf5(hid_t xsdata_grp, size_t n_ang, @@ -98,7 +101,10 @@ class XsData { //! @param scatter_format The scattering representation of the file. //! @param n_pol Number of polar angles. //! @param n_azi Number of azimuthal angles. - XsData(bool fissionable, int scatter_format, int n_pol, int n_azi); + //! @param n_groups Number of energy groups. + //! @param n_d_groups Number of delayed neutron groups. + XsData(bool fissionable, int scatter_format, int n_pol, int n_azi, + size_t n_groups, size_t n_d_groups); //! \brief Loads the XsData object from the HDF5 file //! diff --git a/src/cross_sections.cpp b/src/cross_sections.cpp index e5315b9fd..84596f615 100644 --- a/src/cross_sections.cpp +++ b/src/cross_sections.cpp @@ -155,7 +155,8 @@ void read_cross_sections_xml() if (settings::run_CE) { read_ce_cross_sections_xml(); } else { - data::mgInterface.read_mg_cross_sections_header(); + data::mgInterface.readHeader(settings::path_cross_sections); + putMgxsHeaderDataToGlobals(); } // Establish mapping between (type, material) and index in libraries diff --git a/src/initialize.cpp b/src/initialize.cpp index 203b5fe91..2d40a4392 100644 --- a/src/initialize.cpp +++ b/src/initialize.cpp @@ -260,8 +260,9 @@ void read_input_xml() read_ce_cross_sections(nuc_temps, thermal_temps); } else { // Create material macroscopic data for MGXS - data::mgInterface.init(settings::path_cross_sections); - data::mgInterface.create_macro_xs(); + setMgInterfaceNuclidesAndTemps(); + data::mgInterface.init(); + markFissionableMgxsMaterials(); } simulation::time_read_xs.stop(); } diff --git a/src/mgxs.cpp b/src/mgxs.cpp index 83adfd0b4..84381fe77 100644 --- a/src/mgxs.cpp +++ b/src/mgxs.cpp @@ -288,7 +288,8 @@ Mgxs::Mgxs(hid_t xs_id, const std::vector& temperature, // Load the more specific XsData information for (int t = 0; t < temps_to_read.size(); t++) { - xs[t] = XsData(fissionable, final_scatter_format, n_pol, n_azi); + xs[t] = XsData(fissionable, final_scatter_format, n_pol, n_azi, + num_groups, num_delayed_groups); // Get the temperature as a string and then open the HDF5 group std::string temp_str = std::to_string(temps_to_read[t]) + "K"; hid_t xsdata_grp = open_group(xs_id, temp_str.c_str()); @@ -332,7 +333,7 @@ Mgxs::Mgxs(const std::string& in_name, const std::vector& mat_kTs, // Create the xs data for each temperature for (int t = 0; t < mat_kTs.size(); t++) { xs[t] = XsData(in_fissionable, in_scatter_format, in_polar.size(), - in_azimuthal.size()); + in_azimuthal.size(), num_groups, num_delayed_groups); // Find the right temperature index to use double temp_desired = mat_kTs[t]; diff --git a/src/mgxs_interface.cpp b/src/mgxs_interface.cpp index befa94682..861926c6b 100644 --- a/src/mgxs_interface.cpp +++ b/src/mgxs_interface.cpp @@ -26,29 +26,48 @@ namespace data { MgxsInterface mgInterface; } -MgxsInterface::MgxsInterface(const std::string& path_cross_sections) +MgxsInterface::MgxsInterface(const std::string& path_cross_sections, + const std::vector xs_to_read, + const std::vector> xs_temps) { - init(path_cross_sections); + readHeader(path_cross_sections); + setNuclidesToRead(xs_to_read); + setNuclideTemperaturesToRead(xs_temps); + init(); } -void MgxsInterface::init(const std::string& path_cross_sections) +// Should these perhaps unnecessary setters be lumped into one? +void MgxsInterface::setNuclidesToRead(std::vector arg_xs_to_read) +{ + // Check to remove all duplicates + xs_to_read = arg_xs_to_read; +} +void MgxsInterface::setNuclideTemperaturesToRead(std::vector> xs_temps) { + xs_temps_to_read = xs_temps; + if (xs_to_read.size() != xs_temps.size()) + fatal_error("The list of macro XS temperatures to read does not " + "correspond in length to the number of XS names. "); +} + +void MgxsInterface::init() +{ + + // Check that at least some data was set to be read + if (xs_to_read.size() == 0) + warning("No MGXS nuclides were set to be read."); + // Check if MGXS Library exists - if (!file_exists(path_cross_sections)) { + if (!file_exists(cross_sections_path)) { // Could not find MGXS Library file - fatal_error("Cross sections HDF5 file '" + path_cross_sections + + fatal_error("Cross sections HDF5 file '" + cross_sections_path + "' does not exist."); } write_message("Loading cross section data...", 5); - // Get temperatures - std::vector> nuc_temps(data::nuclide_map.size()); - std::vector> dummy; - get_temperatures(nuc_temps, dummy); - // Open file for reading - hid_t file_id = file_open(path_cross_sections, 'r'); + hid_t file_id = file_open(cross_sections_path, 'r'); // Read filetype std::string type; @@ -68,32 +87,12 @@ void MgxsInterface::init(const std::string& path_cross_sections) // ========================================================================== // READ ALL MGXS CROSS SECTION TABLES - - std::unordered_set already_read; - - // Build vector of nuclide names - std::vector nuclide_names(data::nuclide_map.size()); - for (const auto& kv : data::nuclide_map) { - nuclide_names[kv.second] = kv.first; - } - - // Loop over all files - for (const auto& mat : model::materials) { - for (int i_nuc : mat->nuclide_) { - std::string& name = nuclide_names[i_nuc]; - - if (already_read.find(name) == already_read.end()) { - add_mgxs(file_id, name, nuc_temps[i_nuc]); - already_read.insert(name); - } - - if (nuclides_MG[i_nuc].fissionable) { - mat->fissionable_ = true; - } - } - } + for (unsigned i_nuc=0; i_nuc> MgxsInterface::get_mat_kTs() //============================================================================== -void MgxsInterface::read_mg_cross_sections_header() +void MgxsInterface::readHeader(const std::string& path_cross_sections) { + // Save name of HDF5 file to be read to struct data + cross_sections_path = path_cross_sections; + // Check if MGXS Library exists - if (!file_exists(settings::path_cross_sections)) { + if (!file_exists(cross_sections_path)) { // Could not find MGXS Library file - fatal_error("Cross sections HDF5 file '" + settings::path_cross_sections + + fatal_error("Cross sections HDF5 file '" + cross_sections_path + "' does not exist."); } write_message("Reading cross sections HDF5 file...", 5); // Open file for reading - hid_t file_id = file_open(settings::path_cross_sections, 'r', true); + hid_t file_id = file_open(cross_sections_path, 'r', true); ensure_exists(file_id, "energy_groups", true); read_attribute(file_id, "energy_groups", num_energy_groups); @@ -210,35 +212,84 @@ void MgxsInterface::read_mg_cross_sections_header() // Reverse energy bins std::copy(rev_energy_bins.crbegin(), rev_energy_bins.crend(), - std::back_inserter(data::mgInterface.energy_bins)); + std::back_inserter(energy_bins)); // Create average energies - for (int i = 0; i < data::mgInterface.energy_bins.size() - 1; ++i) { - data::mgInterface.energy_bin_avg.push_back(0.5* - (data::mgInterface.energy_bins[i] + data::mgInterface.energy_bins[i+1])); + for (int i = 0; i < energy_bins.size() - 1; ++i) { + energy_bin_avg.push_back(0.5* + (energy_bins[i] + energy_bins[i+1])); } // Add entries into libraries for MG data - auto names = group_names(file_id); - if (names.empty()) { + xs_names = group_names(file_id); + if (xs_names.empty()) { fatal_error("At least one MGXS data set must be present in mgxs " "library file!"); } - for (auto& name : names) { - Library lib {}; - lib.type_ = Library::Type::neutron; - lib.materials_.push_back(name); - data::libraries.push_back(lib); - } + // Close MGXS HDF5 file + file_close(file_id); +} +void putMgxsHeaderDataToGlobals() +{ // Get the minimum and maximum energies int neutron = static_cast(Particle::Type::neutron); data::energy_min[neutron] = data::mgInterface.energy_bins.back(); data::energy_max[neutron] = data::mgInterface.energy_bins.front(); - // Close MGXS HDF5 file - file_close(file_id); + // Save available XS names to library list, so that when + // materials are read, the specified mgxs can be confirmed + // as present + for (auto& name : data::mgInterface.xs_names) { + Library lib {}; + lib.type_ = Library::Type::neutron; + lib.materials_.push_back(name); + data::libraries.push_back(lib); + } +} + +void setMgInterfaceNuclidesAndTemps() +{ + // Get temperatures from global data + std::vector> these_nuc_temps(data::nuclide_map.size()); + std::vector> dummy; + get_temperatures(these_nuc_temps, dummy); + + // Build vector of nuclide names which are to be read + std::vector nuclide_names(data::nuclide_map.size()); + for (const auto& kv : data::nuclide_map) { + nuclide_names[kv.second] = kv.first; + } + + std::unordered_set already_read; + + // Loop over all files + for (const auto& mat : model::materials) { + for (int i_nuc : mat->nuclide_) { + std::string& name = nuclide_names[i_nuc]; + + if (already_read.find(name) == already_read.end()) { + data::mgInterface.xs_to_read.push_back(name); + data::mgInterface.xs_temps_to_read.push_back(these_nuc_temps[i_nuc]); + // DBG + std::cout << these_nuc_temps[i_nuc][0] << std::endl; + already_read.insert(name); + } + } + } +} + +void markFissionableMgxsMaterials() +{ + // Loop over all files + for (const auto& mat : model::materials) { + for (int i_nuc : mat->nuclide_) { + if (data::mgInterface.nuclides_MG[i_nuc].fissionable) { + mat->fissionable_ = true; + } + } + } } //============================================================================== diff --git a/src/xsdata.cpp b/src/xsdata.cpp index ab6fb52d0..0ee0bd0b0 100644 --- a/src/xsdata.cpp +++ b/src/xsdata.cpp @@ -24,11 +24,12 @@ namespace openmc { // XsData class methods //============================================================================== -XsData::XsData(bool fissionable, int scatter_format, int n_pol, int n_azi) +XsData::XsData(bool fissionable, int scatter_format, int n_pol, int n_azi, + size_t n_groups, size_t n_d_groups) : + n_g(n_groups), + n_dg(n_d_groups) { size_t n_ang = n_pol * n_azi; - size_t n_dg = data::mgInterface.num_delayed_groups; - size_t n_g = data::mgInterface.num_energy_groups; // check to make sure scatter format is OK before we allocate if (scatter_format != ANGLE_HISTOGRAM && scatter_format != ANGLE_TABULAR && @@ -127,9 +128,6 @@ XsData::fission_vector_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, { // Data is provided as nu-fission and chi with a beta for delayed info - size_t n_g = data::mgInterface.num_energy_groups; - size_t n_dg = data::mgInterface.num_delayed_groups; - // Get chi xt::xtensor temp_chi({n_ang, n_g}, 0.); read_nd_vector(xsdata_grp, "chi", temp_chi, true); @@ -182,9 +180,6 @@ XsData::fission_vector_no_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang) { // Data is provided separately as prompt + delayed nu-fission and chi - size_t n_g = data::mgInterface.num_energy_groups; - size_t n_dg = data::mgInterface.num_delayed_groups; - // Get chi-prompt xt::xtensor temp_chi_p({n_ang, n_g}, 0.); read_nd_vector(xsdata_grp, "chi-prompt", temp_chi_p, true); @@ -218,8 +213,6 @@ XsData::fission_vector_no_delayed_from_hdf5(hid_t xsdata_grp, size_t n_ang) // No beta is provided and there is no prompt/delay distinction. // Therefore, the code only considers the data as prompt. - size_t n_g = data::mgInterface.num_energy_groups; - // Get chi xt::xtensor temp_chi({n_ang, n_g}, 0.); read_nd_vector(xsdata_grp, "chi", temp_chi, true); @@ -241,9 +234,6 @@ XsData::fission_matrix_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, bool is_is { // Data is provided as nu-fission and chi with a beta for delayed info - size_t n_g = data::mgInterface.num_energy_groups; - size_t n_dg = data::mgInterface.num_delayed_groups; - // Get nu-fission matrix xt::xtensor temp_matrix({n_ang, n_g, n_g}, 0.); read_nd_vector(xsdata_grp, "nu-fission", temp_matrix, true); @@ -319,9 +309,6 @@ XsData::fission_matrix_no_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang) { // Data is provided separately as prompt + delayed nu-fission and chi - size_t n_g = data::mgInterface.num_energy_groups; - size_t n_dg = data::mgInterface.num_delayed_groups; - // Get the prompt nu-fission matrix xt::xtensor temp_matrix_p({n_ang, n_g, n_g}, 0.); read_nd_vector(xsdata_grp, "prompt-nu-fission", temp_matrix_p, true); @@ -353,8 +340,6 @@ XsData::fission_matrix_no_delayed_from_hdf5(hid_t xsdata_grp, size_t n_ang) // No beta is provided and there is no prompt/delay distinction. // Therefore, the code only considers the data as prompt. - size_t n_g = data::mgInterface.num_energy_groups; - // Get nu-fission matrix xt::xtensor temp_matrix({n_ang, n_g, n_g}, 0.); read_nd_vector(xsdata_grp, "nu-fission", temp_matrix, true); @@ -381,7 +366,7 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, size_t n_ang, bool is_isotropic) // as a nu-fission matrix or a set of chi and nu-fission vectors if (object_exists(xsdata_grp, "chi") || object_exists(xsdata_grp, "chi-prompt")) { - if (data::mgInterface.num_delayed_groups == 0) { + if (n_dg == 0) { fission_vector_no_delayed_from_hdf5(xsdata_grp, n_ang); } else { if (object_exists(xsdata_grp, "beta")) { @@ -391,7 +376,7 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, size_t n_ang, bool is_isotropic) } } } else { - if (data::mgInterface.num_delayed_groups == 0) { + if (n_dg == 0) { fission_matrix_no_delayed_from_hdf5(xsdata_grp, n_ang); } else { if (object_exists(xsdata_grp, "beta")) { @@ -403,7 +388,7 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, size_t n_ang, bool is_isotropic) } // Combine prompt_nu_fission and delayed_nu_fission into nu_fission - if (data::mgInterface.num_delayed_groups == 0) { + if (n_dg == 0) { nu_fission = prompt_nu_fission; } else { nu_fission = prompt_nu_fission + xt::sum(delayed_nu_fission, {1}); @@ -422,7 +407,6 @@ XsData::scatter_from_hdf5(hid_t xsdata_grp, size_t n_ang, hid_t scatt_grp = open_group(xsdata_grp, "scatter_data"); // Get the outgoing group boundary indices - size_t n_g = data::mgInterface.num_energy_groups; xt::xtensor gmin({n_ang, n_g}, 0.); read_nd_vector(scatt_grp, "g_min", gmin, true); xt::xtensor gmax({n_ang, n_g}, 0.); From bdea083a0a974365a0bb544fd275d4c2e8cd9279 Mon Sep 17 00:00:00 2001 From: Gavin Ridley Date: Thu, 7 Nov 2019 13:46:22 -0500 Subject: [PATCH 112/158] remove accidentally pasted email --- src/mgxs_interface.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mgxs_interface.cpp b/src/mgxs_interface.cpp index 861926c6b..59670cb34 100644 --- a/src/mgxs_interface.cpp +++ b/src/mgxs_interface.cpp @@ -112,7 +112,7 @@ MgxsInterface::add_mgxs(hid_t file_id, const std::string& name, + "provided MGXS Library"); } - nuclides_MG.emplace_back(xsgavin.keith.ridley@gmail.com_grp, temperature, num_energy_groups, + nuclides_MG.emplace_back(xs_grp, temperature, num_energy_groups, num_delayed_groups); close_group(xs_grp); } From 8e1de2a57741ca61287cf340928eb3226cfeb127 Mon Sep 17 00:00:00 2001 From: Gavin Ridley Date: Thu, 7 Nov 2019 14:01:04 -0500 Subject: [PATCH 113/158] match openmc style --- include/openmc/mgxs_interface.h | 12 ++++++------ src/cross_sections.cpp | 4 ++-- src/initialize.cpp | 4 ++-- src/mgxs_interface.cpp | 18 +++++++++--------- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/include/openmc/mgxs_interface.h b/include/openmc/mgxs_interface.h index 0c1091c4b..16d30606e 100644 --- a/include/openmc/mgxs_interface.h +++ b/include/openmc/mgxs_interface.h @@ -45,8 +45,8 @@ struct MgxsInterface MgxsInterface(const std::string& path_cross_sections, const std::vector xs_to_read, const std::vector> xs_temps); - void setNuclidesToRead(std::vector arg_xs_to_read); - void setNuclideTemperaturesToRead(std::vector> xs_temps); + void set_nuclides_to_read(std::vector arg_xs_to_read); + void set_nuclide_temperatures_to_read(std::vector> xs_temps); void init(); @@ -59,7 +59,7 @@ struct MgxsInterface // Reads just the header of the cross sections file, to find // min & max energies as well as the available XS - void readHeader(const std::string& path_cross_sections); + void read_header(const std::string& path_cross_sections); }; namespace data { @@ -69,14 +69,14 @@ namespace data { // Puts available XS in MGXS file to globals so that when // materials are read, the MGXS specified in a material can // be ensured to be present in the available data. -void putMgxsHeaderDataToGlobals(); +void put_mgxs_header_data_to_globals(); // Set which nuclides and temperatures are to be read on // mgInterface through global data -void setMgInterfaceNuclidesAndTemps(); +void set_mg_interface_nuclides_and_temps(); // After macro XS have been read, materials can be marked as fissionable -void markFissionableMgxsMaterials(); +void mark_fissionable_mgxs_materials(); //============================================================================== // Mgxs tracking/transport/tallying interface methods diff --git a/src/cross_sections.cpp b/src/cross_sections.cpp index 84596f615..0949a9890 100644 --- a/src/cross_sections.cpp +++ b/src/cross_sections.cpp @@ -155,8 +155,8 @@ void read_cross_sections_xml() if (settings::run_CE) { read_ce_cross_sections_xml(); } else { - data::mgInterface.readHeader(settings::path_cross_sections); - putMgxsHeaderDataToGlobals(); + data::mgInterface.read_header(settings::path_cross_sections); + put_mgxs_header_data_to_globals(); } // Establish mapping between (type, material) and index in libraries diff --git a/src/initialize.cpp b/src/initialize.cpp index 2d40a4392..513ee62f5 100644 --- a/src/initialize.cpp +++ b/src/initialize.cpp @@ -260,9 +260,9 @@ void read_input_xml() read_ce_cross_sections(nuc_temps, thermal_temps); } else { // Create material macroscopic data for MGXS - setMgInterfaceNuclidesAndTemps(); + set_mg_interface_nuclides_and_temps(); data::mgInterface.init(); - markFissionableMgxsMaterials(); + mark_fissionable_mgxs_materials(); } simulation::time_read_xs.stop(); } diff --git a/src/mgxs_interface.cpp b/src/mgxs_interface.cpp index 59670cb34..41c6519db 100644 --- a/src/mgxs_interface.cpp +++ b/src/mgxs_interface.cpp @@ -30,19 +30,19 @@ MgxsInterface::MgxsInterface(const std::string& path_cross_sections, const std::vector xs_to_read, const std::vector> xs_temps) { - readHeader(path_cross_sections); - setNuclidesToRead(xs_to_read); - setNuclideTemperaturesToRead(xs_temps); + read_header(path_cross_sections); + set_nuclides_to_read(xs_to_read); + set_nuclide_temperatures_to_read(xs_temps); init(); } // Should these perhaps unnecessary setters be lumped into one? -void MgxsInterface::setNuclidesToRead(std::vector arg_xs_to_read) +void MgxsInterface::set_nuclides_to_read(std::vector arg_xs_to_read) { // Check to remove all duplicates xs_to_read = arg_xs_to_read; } -void MgxsInterface::setNuclideTemperaturesToRead(std::vector> xs_temps) +void MgxsInterface::set_nuclide_temperatures_to_read(std::vector> xs_temps) { xs_temps_to_read = xs_temps; if (xs_to_read.size() != xs_temps.size()) @@ -182,7 +182,7 @@ std::vector> MgxsInterface::get_mat_kTs() //============================================================================== -void MgxsInterface::readHeader(const std::string& path_cross_sections) +void MgxsInterface::read_header(const std::string& path_cross_sections) { // Save name of HDF5 file to be read to struct data cross_sections_path = path_cross_sections; @@ -231,7 +231,7 @@ void MgxsInterface::readHeader(const std::string& path_cross_sections) file_close(file_id); } -void putMgxsHeaderDataToGlobals() +void put_mgxs_header_data_to_globals() { // Get the minimum and maximum energies int neutron = static_cast(Particle::Type::neutron); @@ -249,7 +249,7 @@ void putMgxsHeaderDataToGlobals() } } -void setMgInterfaceNuclidesAndTemps() +void set_mg_interface_nuclides_and_temps() { // Get temperatures from global data std::vector> these_nuc_temps(data::nuclide_map.size()); @@ -280,7 +280,7 @@ void setMgInterfaceNuclidesAndTemps() } } -void markFissionableMgxsMaterials() +void mark_fissionable_mgxs_materials() { // Loop over all files for (const auto& mat : model::materials) { From c5cef78ade2197817bc36d674c9f6f6ff32db9f5 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Thu, 7 Nov 2019 14:37:23 -0600 Subject: [PATCH 114/158] Adding memo for get_all_cells/get_all_materials. --- openmc/cell.py | 16 +++++++++++----- openmc/geometry.py | 9 +++++++-- openmc/lattice.py | 17 ++++++++++++----- openmc/universe.py | 16 +++++++++++----- 4 files changed, 41 insertions(+), 17 deletions(-) diff --git a/openmc/cell.py b/openmc/cell.py index 3de20f259..8c6b5a9f5 100644 --- a/openmc/cell.py +++ b/openmc/cell.py @@ -350,7 +350,7 @@ class Cell(IDManagerMixin): return nuclides - def get_all_cells(self): + def get_all_cells(self, memo=None): """Return all cells that are contained within this one if it is filled with a universe or lattice @@ -364,12 +364,18 @@ class Cell(IDManagerMixin): cells = OrderedDict() + if memo and id(self) in memo: + return cells + + if memo is not None: + memo.add(id(self)) + if self.fill_type in ('universe', 'lattice'): - cells.update(self.fill.get_all_cells()) + cells.update(self.fill.get_all_cells(memo)) return cells - def get_all_materials(self): + def get_all_materials(self, memo=None): """Return all materials that are contained within the cell Returns @@ -388,9 +394,9 @@ class Cell(IDManagerMixin): materials[m.id] = m else: # Append all Cells in each Cell in the Universe to the dictionary - cells = self.get_all_cells() + cells = self.get_all_cells(memo) for cell in cells.values(): - materials.update(cell.get_all_materials()) + materials.update(cell.get_all_materials(memo)) return materials diff --git a/openmc/geometry.py b/openmc/geometry.py index 89016b722..196c38845 100644 --- a/openmc/geometry.py +++ b/openmc/geometry.py @@ -273,8 +273,11 @@ class Geometry(object): Dictionary mapping cell IDs to :class:`openmc.Cell` instances """ + + memo = set() + if self.root_universe is not None: - return self.root_universe.get_all_cells() + return self.root_universe.get_all_cells(memo) else: return [] @@ -303,7 +306,9 @@ class Geometry(object): instances """ - return self.root_universe.get_all_materials() + memo = set() + + return self.root_universe.get_all_materials(memo) def get_all_material_cells(self): """Return all cells filled by a material diff --git a/openmc/lattice.py b/openmc/lattice.py index 077fb2669..f4c480230 100644 --- a/openmc/lattice.py +++ b/openmc/lattice.py @@ -332,7 +332,7 @@ class Lattice(IDManagerMixin, metaclass=ABCMeta): return nuclides - def get_all_cells(self): + def get_all_cells(self, memo=None): """Return all cells that are contained within the lattice Returns @@ -344,14 +344,21 @@ class Lattice(IDManagerMixin, metaclass=ABCMeta): """ cells = OrderedDict() + + if memo and id(self) in memo: + return cells + + if memo is not None: + memo.add(id(self)) + unique_universes = self.get_unique_universes() for universe_id, universe in unique_universes.items(): - cells.update(universe.get_all_cells()) + cells.update(universe.get_all_cells(memo)) return cells - def get_all_materials(self): + def get_all_materials(self, memo=None): """Return all materials that are contained within the lattice Returns @@ -365,9 +372,9 @@ class Lattice(IDManagerMixin, metaclass=ABCMeta): materials = OrderedDict() # Append all Cells in each Cell in the Universe to the dictionary - cells = self.get_all_cells() + cells = self.get_all_cells(memo) for cell_id, cell in cells.items(): - materials.update(cell.get_all_materials()) + materials.update(cell.get_all_materials(memo)) return materials diff --git a/openmc/universe.py b/openmc/universe.py index 418fe1236..24d1413a9 100644 --- a/openmc/universe.py +++ b/openmc/universe.py @@ -418,7 +418,7 @@ class Universe(IDManagerMixin): return nuclides - def get_all_cells(self): + def get_all_cells(self, memo=None): """Return all cells that are contained within the universe Returns @@ -431,16 +431,22 @@ class Universe(IDManagerMixin): cells = OrderedDict() + if memo and id(self) in memo: + return cells + + if memo is not None: + memo.add(id(self)) + # Add this Universe's cells to the dictionary cells.update(self._cells) # Append all Cells in each Cell in the Universe to the dictionary for cell in self._cells.values(): - cells.update(cell.get_all_cells()) + cells.update(cell.get_all_cells(memo)) return cells - def get_all_materials(self): + def get_all_materials(self, memo=None): """Return all materials that are contained within the universe Returns @@ -454,9 +460,9 @@ class Universe(IDManagerMixin): materials = OrderedDict() # Append all Cells in each Cell in the Universe to the dictionary - cells = self.get_all_cells() + cells = self.get_all_cells(memo) for cell in cells.values(): - materials.update(cell.get_all_materials()) + materials.update(cell.get_all_materials(memo)) return materials From 8478a577e34594b951be8f28009a6927fc14731c Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Thu, 7 Nov 2019 14:58:31 -0600 Subject: [PATCH 115/158] Correcting return type in Geometry object and making get_all_cells/get_all_materials consistent there. --- openmc/geometry.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/openmc/geometry.py b/openmc/geometry.py index 196c38845..2d8c57989 100644 --- a/openmc/geometry.py +++ b/openmc/geometry.py @@ -279,7 +279,7 @@ class Geometry(object): if self.root_universe is not None: return self.root_universe.get_all_cells(memo) else: - return [] + return OrderedDict() def get_all_universes(self): """Return all universes in the geometry. @@ -308,7 +308,10 @@ class Geometry(object): """ memo = set() - return self.root_universe.get_all_materials(memo) + if self.root_universe is not None: + return self.root_universe.get_all_materials(memo) + else: + return OrderedDict() def get_all_material_cells(self): """Return all cells filled by a material From 5aad0d71696021246509a59805c1ceee68b02b1b Mon Sep 17 00:00:00 2001 From: Gavin Ridley Date: Thu, 7 Nov 2019 21:34:28 -0500 Subject: [PATCH 116/158] incorporate requested PR changes --- include/openmc/mgxs_interface.h | 4 ++-- src/mgxs_interface.cpp | 15 +++++---------- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/include/openmc/mgxs_interface.h b/include/openmc/mgxs_interface.h index 16d30606e..0f4a13038 100644 --- a/include/openmc/mgxs_interface.h +++ b/include/openmc/mgxs_interface.h @@ -45,8 +45,8 @@ struct MgxsInterface MgxsInterface(const std::string& path_cross_sections, const std::vector xs_to_read, const std::vector> xs_temps); - void set_nuclides_to_read(std::vector arg_xs_to_read); - void set_nuclide_temperatures_to_read(std::vector> xs_temps); + void set_nuclides_and_temperatures(std::vector arg_xs_to_read, + std::vector> xs_temps); void init(); diff --git a/src/mgxs_interface.cpp b/src/mgxs_interface.cpp index 41c6519db..d5d379bd0 100644 --- a/src/mgxs_interface.cpp +++ b/src/mgxs_interface.cpp @@ -31,19 +31,16 @@ MgxsInterface::MgxsInterface(const std::string& path_cross_sections, const std::vector> xs_temps) { read_header(path_cross_sections); - set_nuclides_to_read(xs_to_read); - set_nuclide_temperatures_to_read(xs_temps); + set_nuclides_and_temperatures(xs_to_read, xs_temps); init(); } -// Should these perhaps unnecessary setters be lumped into one? -void MgxsInterface::set_nuclides_to_read(std::vector arg_xs_to_read) +void MgxsInterface::set_nuclides_and_temperatures( + std::vector arg_xs_to_read, + std::vector> xs_temps) { // Check to remove all duplicates xs_to_read = arg_xs_to_read; -} -void MgxsInterface::set_nuclide_temperatures_to_read(std::vector> xs_temps) -{ xs_temps_to_read = xs_temps; if (xs_to_read.size() != xs_temps.size()) fatal_error("The list of macro XS temperatures to read does not " @@ -264,7 +261,7 @@ void set_mg_interface_nuclides_and_temps() std::unordered_set already_read; - // Loop over all files + // Loop over materials to find xs and temperature to be read for (const auto& mat : model::materials) { for (int i_nuc : mat->nuclide_) { std::string& name = nuclide_names[i_nuc]; @@ -272,8 +269,6 @@ void set_mg_interface_nuclides_and_temps() if (already_read.find(name) == already_read.end()) { data::mgInterface.xs_to_read.push_back(name); data::mgInterface.xs_temps_to_read.push_back(these_nuc_temps[i_nuc]); - // DBG - std::cout << these_nuc_temps[i_nuc][0] << std::endl; already_read.insert(name); } } From 0699de3fd57263d4e75390e338678bc9a7cea571 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Fri, 8 Nov 2019 09:44:51 -0600 Subject: [PATCH 117/158] Apply @paulromano's suggestions from code review Co-Authored-By: Paul Romano --- openmc/cell.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openmc/cell.py b/openmc/cell.py index 8c6b5a9f5..039767cf8 100644 --- a/openmc/cell.py +++ b/openmc/cell.py @@ -478,8 +478,8 @@ class Cell(IDManagerMixin): XML element to be added to memo : set or None - A set of object id's representing geometry entities already - written to the xml_element. This parameter is used internally + A set of object IDs representing geometry entities already + written to ``xml_element``. This parameter is used internally and should not be specified by users. Returns From 3c4e0165be328f657a3ef76ae2f82b9ea05d5c00 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Fri, 8 Nov 2019 09:51:18 -0600 Subject: [PATCH 118/158] Updating comment. --- openmc/lattice.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openmc/lattice.py b/openmc/lattice.py index f4c480230..f0df52e74 100644 --- a/openmc/lattice.py +++ b/openmc/lattice.py @@ -1296,7 +1296,7 @@ class HexLattice(Lattice): return g < self.num_rings and 0 <= idx[2] < self.num_axial def create_xml_subelement(self, xml_element, memo=None): - # If the element does contain the Lattice subelement, then return + # If this subelement has already been written, return if memo and id(self) in memo: return if memo is not None: From 0c97807da84541093a5740f1aaa46f29fb00e3b5 Mon Sep 17 00:00:00 2001 From: Andrew Johnson Date: Tue, 5 Nov 2019 09:18:24 -0500 Subject: [PATCH 119/158] Clarify documentation on Operator diff_burnable_mats In PR #1392, it was revealed that the distribution of material volumes with ``diff_burnable_mats`` was not clear. In that PR, the Operator now divides the volume of the shared material equally across all identical and newly created instances. This commit adds some clarifying language into the Operator docstring and depletion users guide on the handling of volumes across repeated materials. --- docs/source/usersguide/depletion.rst | 4 +++- openmc/deplete/operator.py | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/source/usersguide/depletion.rst b/docs/source/usersguide/depletion.rst index 9e2693098..4a4c7b1f8 100644 --- a/docs/source/usersguide/depletion.rst +++ b/docs/source/usersguide/depletion.rst @@ -127,7 +127,9 @@ of the same material as a unique material definition with:: For our example problem, this would deplete fuel on the outer region of the problem with different reaction rates than those in the center. Materials will be depleted corresponding to their local neutron spectra, and have unique compositions at each -transport step. +transport step. The volume of the original ``fuel_3`` material must represent +the volume of **all** the ``fuel_3`` in the problem. When creating the unique +materials, this volume will be equally distributed across all material instances. .. note:: diff --git a/openmc/deplete/operator.py b/openmc/deplete/operator.py index 5ce725a67..8eb033783 100644 --- a/openmc/deplete/operator.py +++ b/openmc/deplete/operator.py @@ -82,6 +82,7 @@ class Operator(TransportOperator): in the previous results. diff_burnable_mats : bool, optional Whether to differentiate burnable materials with multiple instances. + Volumes are divided equally from the original material volume. Default: False. energy_mode : {"energy-deposition", "fission-q"} Indicator for computing system energy. ``"energy-deposition"`` will From b8d9ae0f8ead4ee9f48c194bd6d77e04eff27a8c Mon Sep 17 00:00:00 2001 From: Gavin Ridley Date: Fri, 8 Nov 2019 13:25:49 -0500 Subject: [PATCH 120/158] PR style changes --- include/openmc/mgxs_interface.h | 60 ++++++++++----------- src/cross_sections.cpp | 2 +- src/initialize.cpp | 2 +- src/material.cpp | 12 ++--- src/mgxs_interface.cpp | 92 ++++++++++++++++----------------- src/output.cpp | 2 +- src/particle.cpp | 2 +- src/particle_restart.cpp | 2 +- src/physics_mg.cpp | 6 +-- src/source.cpp | 6 +-- src/state_point.cpp | 2 +- src/summary.cpp | 2 +- src/tallies/filter_energy.cpp | 10 ++-- src/tallies/tally_scoring.cpp | 12 ++--- 14 files changed, 106 insertions(+), 106 deletions(-) diff --git a/include/openmc/mgxs_interface.h b/include/openmc/mgxs_interface.h index 0f4a13038..ce0a4a4c7 100644 --- a/include/openmc/mgxs_interface.h +++ b/include/openmc/mgxs_interface.h @@ -15,28 +15,8 @@ namespace openmc { // Global MGXS data container structure //============================================================================== -struct MgxsInterface -{ - int num_energy_groups; - int num_delayed_groups; - - // List of available names in the HDF5 file - std::vector xs_names; - std::vector xs_to_read; - std::vector> xs_temps_to_read; - - // Name of the HDF5 file which contains mgxs - std::string cross_sections_path; - - std::vector nuclides_MG; - std::vector macro_xs; - - std::vector energy_bins; - std::vector energy_bin_avg; - std::vector rev_energy_bins; - - // temperatues of each available nuclide - std::vector> nuc_temps; +struct MgxsInterface { +public: MgxsInterface() = default; @@ -45,25 +25,45 @@ struct MgxsInterface MgxsInterface(const std::string& path_cross_sections, const std::vector xs_to_read, const std::vector> xs_temps); - void set_nuclides_and_temperatures(std::vector arg_xs_to_read, - std::vector> xs_temps); + // Does things to construct after the nuclides and temperatures to + // read have been specified. void init(); + // Set which nuclides and temperatures are to be read + void set_nuclides_and_temperatures(std::vector xs_to_read, + std::vector> xs_temps); + + // Add an Mgxs object to be managed void add_mgxs(hid_t file_id, const std::string& name, const std::vector& temperature); - void create_macro_xs(); - - std::vector> get_mat_kTs(); - // Reads just the header of the cross sections file, to find // min & max energies as well as the available XS void read_header(const std::string& path_cross_sections); + + // Calculate microscopic cross sections from nuclide macro XS + void create_macro_xs(); + + // Get the kT values which are used in the OpenMC model + std::vector> get_mat_kTs(); + + int num_energy_groups_; + int num_delayed_groups_; + std::vector xs_names_; // available names in HDF5 file + std::vector xs_to_read_; // XS which appear in materials + std::vector> xs_temps_to_read_; // temperatures used + std::string cross_sections_path_; // path to MGXS h5 file + std::vector nuclides_; + std::vector macro_xs_; + std::vector energy_bins_; + std::vector energy_bin_avg_; + std::vector rev_energy_bins_; + std::vector> nuc_temps_; // all available temperatures }; namespace data { - extern MgxsInterface mgInterface; + extern MgxsInterface mg; } // Puts available XS in MGXS file to globals so that when @@ -72,7 +72,7 @@ namespace data { void put_mgxs_header_data_to_globals(); // Set which nuclides and temperatures are to be read on -// mgInterface through global data +// mg through global data void set_mg_interface_nuclides_and_temps(); // After macro XS have been read, materials can be marked as fissionable diff --git a/src/cross_sections.cpp b/src/cross_sections.cpp index 0949a9890..6245bca9f 100644 --- a/src/cross_sections.cpp +++ b/src/cross_sections.cpp @@ -155,7 +155,7 @@ void read_cross_sections_xml() if (settings::run_CE) { read_ce_cross_sections_xml(); } else { - data::mgInterface.read_header(settings::path_cross_sections); + data::mg.read_header(settings::path_cross_sections); put_mgxs_header_data_to_globals(); } diff --git a/src/initialize.cpp b/src/initialize.cpp index 513ee62f5..460db2436 100644 --- a/src/initialize.cpp +++ b/src/initialize.cpp @@ -261,7 +261,7 @@ void read_input_xml() } else { // Create material macroscopic data for MGXS set_mg_interface_nuclides_and_temps(); - data::mgInterface.init(); + data::mg.init(); mark_fissionable_mgxs_materials(); } simulation::time_read_xs.stop(); diff --git a/src/material.cpp b/src/material.cpp index e4579e10e..a5bc3dc13 100644 --- a/src/material.cpp +++ b/src/material.cpp @@ -368,7 +368,7 @@ void Material::normalize_density() // determine atomic weight ratio int i_nuc = nuclide_[i]; double awr = settings::run_CE ? - data::nuclides[i_nuc]->awr_ : data::mgInterface.nuclides_MG[i_nuc].awr; + data::nuclides[i_nuc]->awr_ : data::mg.nuclides_[i_nuc].awr; // if given weight percent, convert all values so that they are divided // by awr. thus, when a sum is done over the values, it's actually @@ -388,7 +388,7 @@ void Material::normalize_density() for (int i = 0; i < nuclide_.size(); ++i) { int i_nuc = nuclide_[i]; double awr = settings::run_CE ? - data::nuclides[i_nuc]->awr_ : data::mgInterface.nuclides_MG[i_nuc].awr; + data::nuclides[i_nuc]->awr_ : data::mg.nuclides_[i_nuc].awr; sum_percent += atom_density_(i)*awr; } sum_percent = 1.0 / sum_percent; @@ -726,7 +726,7 @@ void Material::init_bremsstrahlung() void Material::init_nuclide_index() { int n = settings::run_CE ? - data::nuclides.size() : data::mgInterface.nuclides_MG.size(); + data::nuclides.size() : data::mg.nuclides_.size(); mat_nuclide_index_.resize(n); std::fill(mat_nuclide_index_.begin(), mat_nuclide_index_.end(), C_NONE); for (int i = 0; i < nuclide_.size(); ++i) { @@ -994,11 +994,11 @@ void Material::to_hdf5(hid_t group) const } else { for (int i = 0; i < nuclide_.size(); ++i) { int i_nuc = nuclide_[i]; - if (data::mgInterface.nuclides_MG[i_nuc].awr != MACROSCOPIC_AWR) { - nuc_names.push_back(data::mgInterface.nuclides_MG[i_nuc].name); + if (data::mg.nuclides_[i_nuc].awr != MACROSCOPIC_AWR) { + nuc_names.push_back(data::mg.nuclides_[i_nuc].name); nuc_densities.push_back(atom_density_(i)); } else { - macro_names.push_back(data::mgInterface.nuclides_MG[i_nuc].name); + macro_names.push_back(data::mg.nuclides_[i_nuc].name); } } } diff --git a/src/mgxs_interface.cpp b/src/mgxs_interface.cpp index d5d379bd0..1b0f2675a 100644 --- a/src/mgxs_interface.cpp +++ b/src/mgxs_interface.cpp @@ -23,7 +23,7 @@ namespace openmc { //============================================================================== namespace data { - MgxsInterface mgInterface; + MgxsInterface mg; } MgxsInterface::MgxsInterface(const std::string& path_cross_sections, @@ -36,13 +36,13 @@ MgxsInterface::MgxsInterface(const std::string& path_cross_sections, } void MgxsInterface::set_nuclides_and_temperatures( - std::vector arg_xs_to_read, + std::vector xs_to_read, std::vector> xs_temps) { // Check to remove all duplicates - xs_to_read = arg_xs_to_read; - xs_temps_to_read = xs_temps; - if (xs_to_read.size() != xs_temps.size()) + xs_to_read_ = xs_to_read; + xs_temps_to_read_ = xs_temps; + if (xs_to_read_.size() != xs_temps.size()) fatal_error("The list of macro XS temperatures to read does not " "correspond in length to the number of XS names. "); } @@ -51,20 +51,20 @@ void MgxsInterface::init() { // Check that at least some data was set to be read - if (xs_to_read.size() == 0) + if (xs_to_read_.size() == 0) warning("No MGXS nuclides were set to be read."); // Check if MGXS Library exists - if (!file_exists(cross_sections_path)) { + if (!file_exists(cross_sections_path_)) { // Could not find MGXS Library file - fatal_error("Cross sections HDF5 file '" + cross_sections_path + + fatal_error("Cross sections HDF5 file '" + cross_sections_path_ + "' does not exist."); } write_message("Loading cross section data...", 5); // Open file for reading - hid_t file_id = file_open(cross_sections_path, 'r'); + hid_t file_id = file_open(cross_sections_path_, 'r'); // Read filetype std::string type; @@ -84,8 +84,8 @@ void MgxsInterface::init() // ========================================================================== // READ ALL MGXS CROSS SECTION TABLES - for (unsigned i_nuc=0; i_nuc atom_densities(mat->atom_density_.begin(), mat->atom_density_.end()); - // Build array of pointers to nuclides_MG's Mgxs objects needed for this + // Build array of pointers to nuclides's Mgxs objects needed for this // material std::vector mgxs_ptr; for (int i_nuclide : mat->nuclide_) { - mgxs_ptr.push_back(&nuclides_MG[i_nuclide]); + mgxs_ptr.push_back(&nuclides_[i_nuclide]); } - macro_xs.emplace_back(mat->name_, kTs[i], mgxs_ptr, atom_densities, - num_energy_groups, num_delayed_groups); + macro_xs_.emplace_back(mat->name_, kTs[i], mgxs_ptr, atom_densities, + num_energy_groups_, num_delayed_groups_); } else { // Preserve the ordering of materials by including a blank entry - macro_xs.emplace_back(); + macro_xs_.emplace_back(); } } } @@ -182,44 +182,44 @@ std::vector> MgxsInterface::get_mat_kTs() void MgxsInterface::read_header(const std::string& path_cross_sections) { // Save name of HDF5 file to be read to struct data - cross_sections_path = path_cross_sections; + cross_sections_path_ = path_cross_sections; // Check if MGXS Library exists - if (!file_exists(cross_sections_path)) { + if (!file_exists(cross_sections_path_)) { // Could not find MGXS Library file - fatal_error("Cross sections HDF5 file '" + cross_sections_path + + fatal_error("Cross sections HDF5 file '" + cross_sections_path_ + "' does not exist."); } write_message("Reading cross sections HDF5 file...", 5); // Open file for reading - hid_t file_id = file_open(cross_sections_path, 'r', true); + hid_t file_id = file_open(cross_sections_path_, 'r', true); ensure_exists(file_id, "energy_groups", true); - read_attribute(file_id, "energy_groups", num_energy_groups); + read_attribute(file_id, "energy_groups", num_energy_groups_); if (attribute_exists(file_id, "delayed_groups")) { - read_attribute(file_id, "delayed_groups", num_delayed_groups); + read_attribute(file_id, "delayed_groups", num_delayed_groups_); } else { - num_delayed_groups = 0; + num_delayed_groups_ = 0; } ensure_exists(file_id, "group structure", true); - read_attribute(file_id, "group structure", rev_energy_bins); + read_attribute(file_id, "group structure", rev_energy_bins_); // Reverse energy bins - std::copy(rev_energy_bins.crbegin(), rev_energy_bins.crend(), - std::back_inserter(energy_bins)); + std::copy(rev_energy_bins_.crbegin(), rev_energy_bins_.crend(), + std::back_inserter(energy_bins_)); // Create average energies - for (int i = 0; i < energy_bins.size() - 1; ++i) { - energy_bin_avg.push_back(0.5* - (energy_bins[i] + energy_bins[i+1])); + for (int i = 0; i < energy_bins_.size() - 1; ++i) { + energy_bin_avg_.push_back(0.5* + (energy_bins_[i] + energy_bins_[i+1])); } // Add entries into libraries for MG data - xs_names = group_names(file_id); - if (xs_names.empty()) { + xs_names_ = group_names(file_id); + if (xs_names_.empty()) { fatal_error("At least one MGXS data set must be present in mgxs " "library file!"); } @@ -232,13 +232,13 @@ void put_mgxs_header_data_to_globals() { // Get the minimum and maximum energies int neutron = static_cast(Particle::Type::neutron); - data::energy_min[neutron] = data::mgInterface.energy_bins.back(); - data::energy_max[neutron] = data::mgInterface.energy_bins.front(); + data::energy_min[neutron] = data::mg.energy_bins_.back(); + data::energy_max[neutron] = data::mg.energy_bins_.front(); // Save available XS names to library list, so that when // materials are read, the specified mgxs can be confirmed // as present - for (auto& name : data::mgInterface.xs_names) { + for (auto& name : data::mg.xs_names_) { Library lib {}; lib.type_ = Library::Type::neutron; lib.materials_.push_back(name); @@ -249,9 +249,9 @@ void put_mgxs_header_data_to_globals() void set_mg_interface_nuclides_and_temps() { // Get temperatures from global data - std::vector> these_nuc_temps(data::nuclide_map.size()); + std::vector> nuc_temps(data::nuclide_map.size()); std::vector> dummy; - get_temperatures(these_nuc_temps, dummy); + get_temperatures(nuc_temps, dummy); // Build vector of nuclide names which are to be read std::vector nuclide_names(data::nuclide_map.size()); @@ -267,8 +267,8 @@ void set_mg_interface_nuclides_and_temps() std::string& name = nuclide_names[i_nuc]; if (already_read.find(name) == already_read.end()) { - data::mgInterface.xs_to_read.push_back(name); - data::mgInterface.xs_temps_to_read.push_back(these_nuc_temps[i_nuc]); + data::mg.xs_to_read_.push_back(name); + data::mg.xs_temps_to_read_.push_back(nuc_temps[i_nuc]); already_read.insert(name); } } @@ -280,7 +280,7 @@ void mark_fissionable_mgxs_materials() // Loop over all files for (const auto& mat : model::materials) { for (int i_nuc : mat->nuclide_) { - if (data::mgInterface.nuclides_MG[i_nuc].fissionable) { + if (data::mg.nuclides_[i_nuc].fissionable) { mat->fissionable_ = true; } } @@ -295,7 +295,7 @@ void calculate_xs_c(int i_mat, int gin, double sqrtkT, Direction u, double& total_xs, double& abs_xs, double& nu_fiss_xs) { - data::mgInterface.macro_xs[i_mat].calculate_xs(gin - 1, sqrtkT, u, total_xs, abs_xs, + data::mg.macro_xs_[i_mat].calculate_xs(gin - 1, sqrtkT, u, total_xs, abs_xs, nu_fiss_xs); } @@ -313,7 +313,7 @@ get_nuclide_xs(int index, int xstype, int gin, const int* gout, } else { gout_c_p = gout; } - return data::mgInterface.nuclides_MG[index].get_xs(xstype, gin - 1, gout_c_p, mu, dg); + return data::mg.nuclides_[index].get_xs(xstype, gin - 1, gout_c_p, mu, dg); } //============================================================================== @@ -330,7 +330,7 @@ get_macro_xs(int index, int xstype, int gin, const int* gout, } else { gout_c_p = gout; } - return data::mgInterface.macro_xs[index].get_xs(xstype, gin - 1, gout_c_p, mu, dg); + return data::mg.macro_xs_[index].get_xs(xstype, gin - 1, gout_c_p, mu, dg); } //============================================================================== @@ -345,7 +345,7 @@ get_name_c(int index, int name_len, char* name) std::strcpy(name, str.c_str()); // Now get the data and copy to the C-string - str = data::mgInterface.nuclides_MG[index - 1].name; + str = data::mg.nuclides_[index - 1].name; std::strcpy(name, str.c_str()); // Finally, remove the null terminator @@ -357,7 +357,7 @@ get_name_c(int index, int name_len, char* name) double get_awr_c(int index) { - return data::mgInterface.nuclides_MG[index - 1].awr; + return data::mg.nuclides_[index - 1].awr; } } // namespace openmc diff --git a/src/output.cpp b/src/output.cpp index 8fb628e77..899bce86e 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -710,7 +710,7 @@ write_tallies() << data::nuclides[i_nuclide]->name_ << "\n"; } else { tallies_out << std::string(indent+1, ' ') - << data::mgInterface.nuclides_MG[i_nuclide].name << "\n"; + << data::mg.nuclides_[i_nuclide].name << "\n"; } } diff --git a/src/particle.cpp b/src/particle.cpp index 742f1ead3..030c8dc63 100644 --- a/src/particle.cpp +++ b/src/particle.cpp @@ -123,7 +123,7 @@ Particle::from_source(const Bank* src) } else { g_ = static_cast(src->E); g_last_ = static_cast(src->E); - E_ = data::mgInterface.energy_bin_avg[g_ - 1]; + E_ = data::mg.energy_bin_avg_[g_ - 1]; } E_last_ = E_; } diff --git a/src/particle_restart.cpp b/src/particle_restart.cpp index 87b0093d0..8672ebf84 100644 --- a/src/particle_restart.cpp +++ b/src/particle_restart.cpp @@ -52,7 +52,7 @@ void read_particle_restart(Particle& p, int& previous_run_mode) // Set energy group and average energy in multi-group mode if (!settings::run_CE) { p.g_ = p.E_; - p.E_ = data::mgInterface.energy_bin_avg[p.g_ - 1]; + p.E_ = data::mg.energy_bin_avg_[p.g_ - 1]; } // Set particle last attributes diff --git a/src/physics_mg.cpp b/src/physics_mg.cpp index e2682792f..90e76c67a 100644 --- a/src/physics_mg.cpp +++ b/src/physics_mg.cpp @@ -82,7 +82,7 @@ scatter(Particle* p) int gin = p->g_last_ - 1; int gout = p->g_ - 1; int i_mat = p->material_; - data::mgInterface.macro_xs[i_mat].sample_scatter(gin, gout, p->mu_, p->wgt_); + data::mg.macro_xs_[i_mat].sample_scatter(gin, gout, p->mu_, p->wgt_); // Adjust return value for fortran indexing // TODO: Remove when no longer needed @@ -92,7 +92,7 @@ scatter(Particle* p) p->u() = rotate_angle(p->u(), p->mu_, nullptr); // Update energy value for downstream compatability (in tallying) - p->E_ = data::mgInterface.energy_bin_avg[gout]; + p->E_ = data::mg.energy_bin_avg_[gout]; // Set event component p->event_ = EVENT_SCATTER; @@ -148,7 +148,7 @@ create_fission_sites(Particle* p, std::vector& bank) // the energy in the fission bank int dg; int gout; - data::mgInterface.macro_xs[p->material_].sample_fission_energy(p->g_ - 1, dg, gout); + data::mg.macro_xs_[p->material_].sample_fission_energy(p->g_ - 1, dg, gout); site.E = gout + 1; site.delayed_group = dg + 1; diff --git a/src/source.cpp b/src/source.cpp index f495d5572..6b5cb8aba 100644 --- a/src/source.cpp +++ b/src/source.cpp @@ -311,9 +311,9 @@ Particle::Bank sample_external_source() // If running in MG, convert site % E to group if (!settings::run_CE) { - site.E = lower_bound_index(data::mgInterface.rev_energy_bins.begin(), - data::mgInterface.rev_energy_bins.end(), site.E); - site.E = data::mgInterface.num_energy_groups - site.E; + site.E = lower_bound_index(data::mg.rev_energy_bins_.begin(), + data::mg.rev_energy_bins_.end(), site.E); + site.E = data::mg.num_energy_groups_ - site.E; } // Set the random number generator back to the tracking stream. diff --git a/src/state_point.cpp b/src/state_point.cpp index f0dcfe2b0..4c159c167 100644 --- a/src/state_point.cpp +++ b/src/state_point.cpp @@ -208,7 +208,7 @@ openmc_statepoint_write(const char* filename, bool* write_source) if (settings::run_CE) { nuclides.push_back(data::nuclides[i_nuclide]->name_); } else { - nuclides.push_back(data::mgInterface.nuclides_MG[i_nuclide].name); + nuclides.push_back(data::mg.nuclides_[i_nuclide].name); } } } diff --git a/src/summary.cpp b/src/summary.cpp index 0c6222cef..1f5f7a097 100644 --- a/src/summary.cpp +++ b/src/summary.cpp @@ -57,7 +57,7 @@ void write_nuclides(hid_t file) nuc_names.push_back(nuc->name_); awrs.push_back(nuc->awr_); } else { - const auto& nuc {data::mgInterface.nuclides_MG[i]}; + const auto& nuc {data::mg.nuclides_[i]}; if (nuc.awr != MACROSCOPIC_AWR) { nuc_names.push_back(nuc.name); awrs.push_back(nuc.awr); diff --git a/src/tallies/filter_energy.cpp b/src/tallies/filter_energy.cpp index d69b335b6..7737e4fac 100644 --- a/src/tallies/filter_energy.cpp +++ b/src/tallies/filter_energy.cpp @@ -43,10 +43,10 @@ EnergyFilter::set_bins(gsl::span bins) // (after flipping for the different ordering of the library and tallying // systems). if (!settings::run_CE) { - if (n_bins_ == data::mgInterface.num_energy_groups) { + if (n_bins_ == data::mg.num_energy_groups_) { matches_transport_groups_ = true; for (gsl::index i = 0; i < n_bins_ + 1; ++i) { - if (data::mgInterface.rev_energy_bins[i] != bins_[i]) { + if (data::mg.rev_energy_bins_[i] != bins_[i]) { matches_transport_groups_ = false; break; } @@ -61,9 +61,9 @@ const { if (p->g_ != F90_NONE && matches_transport_groups_) { if (estimator == ESTIMATOR_TRACKLENGTH) { - match.bins_.push_back(data::mgInterface.num_energy_groups - p->g_); + match.bins_.push_back(data::mg.num_energy_groups_ - p->g_); } else { - match.bins_.push_back(data::mgInterface.num_energy_groups - p->g_last_); + match.bins_.push_back(data::mg.num_energy_groups_ - p->g_last_); } match.weights_.push_back(1.0); @@ -104,7 +104,7 @@ EnergyoutFilter::get_all_bins(const Particle* p, int estimator, FilterMatch& match) const { if (p->g_ != F90_NONE && matches_transport_groups_) { - match.bins_.push_back(data::mgInterface.num_energy_groups - p->g_); + match.bins_.push_back(data::mg.num_energy_groups_ - p->g_); match.weights_.push_back(1.0); } else { diff --git a/src/tallies/tally_scoring.cpp b/src/tallies/tally_scoring.cpp index bd31960be..582e7dced 100644 --- a/src/tallies/tally_scoring.cpp +++ b/src/tallies/tally_scoring.cpp @@ -361,7 +361,7 @@ score_fission_eout(const Particle* p, int i_tally, int i_score, int score_bin) if (settings::run_CE) { E_out = bank.E; } else { - E_out = data::mgInterface.energy_bin_avg[static_cast(bank.E)]; + E_out = data::mg.energy_bin_avg_[static_cast(bank.E)]; } // Set EnergyoutFilter bin index @@ -1376,13 +1376,13 @@ score_general_mg(const Particle* p, int i_tally, int start_index, // To significantly reduce de-referencing, point matxs to the macroscopic // Mgxs for the material of interest - data::mgInterface.macro_xs[p->material_].set_angle_index(p_u); + data::mg.macro_xs_[p->material_].set_angle_index(p_u); // Do same for nucxs, point it to the microscopic nuclide data of interest if (i_nuclide >= 0) { // And since we haven't calculated this temperature index yet, do so now - data::mgInterface.nuclides_MG[i_nuclide].set_temperature_index(p->sqrtkT_); - data::mgInterface.nuclides_MG[i_nuclide].set_angle_index(p_u); + data::mg.nuclides_[i_nuclide].set_temperature_index(p->sqrtkT_); + data::mg.nuclides_[i_nuclide].set_angle_index(p_u); } for (auto i = 0; i < tally.scores_.size(); ++i) { @@ -1869,7 +1869,7 @@ score_general_mg(const Particle* p, int i_tally, int start_index, // delayed-nu-fission xs to the absorption xs for all delayed // groups score = 0.; - for (auto d = 0; d < data::mgInterface.num_delayed_groups; ++d) { + for (auto d = 0; d < data::mg.num_delayed_groups_; ++d) { if (i_nuclide >= 0) { score += p->wgt_absorb_ * flux * get_nuclide_xs(i_nuclide, MG_GET_XS_DECAY_RATE, @@ -1960,7 +1960,7 @@ score_general_mg(const Particle* p, int i_tally, int start_index, continue; } else { score = 0.; - for (auto d = 0; d < data::mgInterface.num_delayed_groups; ++d) { + for (auto d = 0; d < data::mg.num_delayed_groups_; ++d) { if (i_nuclide >= 0) { score += atom_density * flux * get_nuclide_xs(i_nuclide, MG_GET_XS_DECAY_RATE, From 2f879c8326cf79465584ad472b5fed7bae97cdc5 Mon Sep 17 00:00:00 2001 From: Gavin Ridley Date: Fri, 8 Nov 2019 13:30:41 -0500 Subject: [PATCH 121/158] underscore for xsdata class variables --- include/openmc/xsdata.h | 5 ++-- src/xsdata.cpp | 62 ++++++++++++++++++++--------------------- 2 files changed, 34 insertions(+), 33 deletions(-) diff --git a/include/openmc/xsdata.h b/include/openmc/xsdata.h index f7ba802b8..3e9fc51cc 100644 --- a/include/openmc/xsdata.h +++ b/include/openmc/xsdata.h @@ -22,8 +22,6 @@ namespace openmc { class XsData { private: - //! Number of energy and delayed neutron groups - size_t n_g, n_dg; //! \brief Reads scattering data from the HDF5 file void @@ -64,6 +62,9 @@ class XsData { void fission_matrix_no_delayed_from_hdf5(hid_t xsdata_grp, size_t n_ang); + //! Number of energy and delayed neutron groups + size_t n_g_, n_dg_; + public: // The following quantities have the following dimensions: diff --git a/src/xsdata.cpp b/src/xsdata.cpp index 0ee0bd0b0..d6b92958a 100644 --- a/src/xsdata.cpp +++ b/src/xsdata.cpp @@ -26,8 +26,8 @@ namespace openmc { XsData::XsData(bool fissionable, int scatter_format, int n_pol, int n_azi, size_t n_groups, size_t n_d_groups) : - n_g(n_groups), - n_dg(n_d_groups) + n_g_(n_groups), + n_dg_(n_d_groups) { size_t n_ang = n_pol * n_azi; @@ -37,7 +37,7 @@ XsData::XsData(bool fissionable, int scatter_format, int n_pol, int n_azi, fatal_error("Invalid scatter_format!"); } // allocate all [temperature][angle][in group] quantities - std::vector shape {n_ang, n_g}; + std::vector shape {n_ang, n_g_}; total = xt::zeros(shape); absorption = xt::zeros(shape); inverse_velocity = xt::zeros(shape); @@ -49,20 +49,20 @@ XsData::XsData(bool fissionable, int scatter_format, int n_pol, int n_azi, } // allocate decay_rate; [temperature][angle][delayed group] - shape[1] = n_dg; + shape[1] = n_dg_; decay_rate = xt::zeros(shape); if (fissionable) { - shape = {n_ang, n_dg, n_g}; + shape = {n_ang, n_dg_, n_g_}; // allocate delayed_nu_fission; [temperature][angle][delay group][in group] delayed_nu_fission = xt::zeros(shape); // chi_prompt; [temperature][angle][in group][out group] - shape = {n_ang, n_g, n_g}; + shape = {n_ang, n_g_, n_g_}; chi_prompt = xt::zeros(shape); // chi_delayed; [temperature][angle][delay group][in group][out group] - shape = {n_ang, n_dg, n_g, n_g}; + shape = {n_ang, n_dg_, n_g_, n_g_}; chi_delayed = xt::zeros(shape); } @@ -129,7 +129,7 @@ XsData::fission_vector_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, // Data is provided as nu-fission and chi with a beta for delayed info // Get chi - xt::xtensor temp_chi({n_ang, n_g}, 0.); + xt::xtensor temp_chi({n_ang, n_g_}, 0.); read_nd_vector(xsdata_grp, "chi", temp_chi, true); // Normalize chi by summing over the outgoing groups for each incoming angle @@ -142,7 +142,7 @@ XsData::fission_vector_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, xt::all()); // Get nu-fission - xt::xtensor temp_nufiss({n_ang, n_g}, 0.); + xt::xtensor temp_nufiss({n_ang, n_g_}, 0.); read_nd_vector(xsdata_grp, "nu-fission", temp_nufiss, true); // Get beta (strategy will depend upon the number of dimensions in beta) @@ -152,7 +152,7 @@ XsData::fission_vector_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, int ndim_target = 1; if (!is_isotropic) ndim_target += 2; if (beta_ndims == ndim_target) { - xt::xtensor temp_beta({n_ang, n_dg}, 0.); + xt::xtensor temp_beta({n_ang, n_dg_}, 0.); read_nd_vector(xsdata_grp, "beta", temp_beta, true); // Set prompt_nu_fission = (1. - beta_total)*nu_fission @@ -163,7 +163,7 @@ XsData::fission_vector_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, xt::view(temp_beta, xt::all(), xt::all(), xt::newaxis()) * xt::view(temp_nufiss, xt::all(), xt::newaxis(), xt::all()); } else if (beta_ndims == ndim_target + 1) { - xt::xtensor temp_beta({n_ang, n_dg, n_g}, 0.); + xt::xtensor temp_beta({n_ang, n_dg_, n_g_}, 0.); read_nd_vector(xsdata_grp, "beta", temp_beta, true); // Set prompt_nu_fission = (1. - beta_total)*nu_fission @@ -181,14 +181,14 @@ XsData::fission_vector_no_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang) // Data is provided separately as prompt + delayed nu-fission and chi // Get chi-prompt - xt::xtensor temp_chi_p({n_ang, n_g}, 0.); + xt::xtensor temp_chi_p({n_ang, n_g_}, 0.); read_nd_vector(xsdata_grp, "chi-prompt", temp_chi_p, true); // Normalize chi by summing over the outgoing groups for each incoming angle temp_chi_p /= xt::view(xt::sum(temp_chi_p, {1}), xt::all(), xt::newaxis()); // Get chi-delayed - xt::xtensor temp_chi_d({n_ang, n_dg, n_g}, 0.); + xt::xtensor temp_chi_d({n_ang, n_dg_, n_g_}, 0.); read_nd_vector(xsdata_grp, "chi-delayed", temp_chi_d, true); // Normalize chi by summing over the outgoing groups for each incoming angle @@ -214,7 +214,7 @@ XsData::fission_vector_no_delayed_from_hdf5(hid_t xsdata_grp, size_t n_ang) // Therefore, the code only considers the data as prompt. // Get chi - xt::xtensor temp_chi({n_ang, n_g}, 0.); + xt::xtensor temp_chi({n_ang, n_g_}, 0.); read_nd_vector(xsdata_grp, "chi", temp_chi, true); // Normalize chi by summing over the outgoing groups for each incoming angle @@ -235,7 +235,7 @@ XsData::fission_matrix_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, bool is_is // Data is provided as nu-fission and chi with a beta for delayed info // Get nu-fission matrix - xt::xtensor temp_matrix({n_ang, n_g, n_g}, 0.); + xt::xtensor temp_matrix({n_ang, n_g_, n_g_}, 0.); read_nd_vector(xsdata_grp, "nu-fission", temp_matrix, true); // Get beta (strategy will depend upon the number of dimensions in beta) @@ -245,7 +245,7 @@ XsData::fission_matrix_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, bool is_is int ndim_target = 1; if (!is_isotropic) ndim_target += 2; if (beta_ndims == ndim_target) { - xt::xtensor temp_beta({n_ang, n_dg}, 0.); + xt::xtensor temp_beta({n_ang, n_dg_}, 0.); read_nd_vector(xsdata_grp, "beta", temp_beta, true); xt::xtensor temp_beta_sum({n_ang}, 0.); @@ -271,10 +271,10 @@ XsData::fission_matrix_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang, bool is_is xt::view(temp_matrix, xt::all(), xt::newaxis(), xt::all(), xt::all()); } else if (beta_ndims == ndim_target + 1) { - xt::xtensor temp_beta({n_ang, n_dg, n_g}, 0.); + xt::xtensor temp_beta({n_ang, n_dg_, n_g_}, 0.); read_nd_vector(xsdata_grp, "beta", temp_beta, true); - xt::xtensor temp_beta_sum({n_ang, n_g}, 0.); + xt::xtensor temp_beta_sum({n_ang, n_g_}, 0.); temp_beta_sum = xt::sum(temp_beta, {1}); // prompt_nu_fission is the sum of this matrix over outgoing groups and @@ -310,7 +310,7 @@ XsData::fission_matrix_no_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang) // Data is provided separately as prompt + delayed nu-fission and chi // Get the prompt nu-fission matrix - xt::xtensor temp_matrix_p({n_ang, n_g, n_g}, 0.); + xt::xtensor temp_matrix_p({n_ang, n_g_, n_g_}, 0.); read_nd_vector(xsdata_grp, "prompt-nu-fission", temp_matrix_p, true); // prompt_nu_fission is the sum over outgoing groups @@ -322,7 +322,7 @@ XsData::fission_matrix_no_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang) xt::view(prompt_nu_fission, xt::all(), xt::all(), xt::newaxis()); // Get the delayed nu-fission matrix - xt::xtensor temp_matrix_d({n_ang, n_dg, n_g, n_g}, 0.); + xt::xtensor temp_matrix_d({n_ang, n_dg_, n_g_, n_g_}, 0.); read_nd_vector(xsdata_grp, "delayed-nu-fission", temp_matrix_d, true); // delayed_nu_fission is the sum over outgoing groups @@ -341,7 +341,7 @@ XsData::fission_matrix_no_delayed_from_hdf5(hid_t xsdata_grp, size_t n_ang) // Therefore, the code only considers the data as prompt. // Get nu-fission matrix - xt::xtensor temp_matrix({n_ang, n_g, n_g}, 0.); + xt::xtensor temp_matrix({n_ang, n_g_, n_g_}, 0.); read_nd_vector(xsdata_grp, "nu-fission", temp_matrix, true); // prompt_nu_fission is the sum over outgoing groups @@ -366,7 +366,7 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, size_t n_ang, bool is_isotropic) // as a nu-fission matrix or a set of chi and nu-fission vectors if (object_exists(xsdata_grp, "chi") || object_exists(xsdata_grp, "chi-prompt")) { - if (n_dg == 0) { + if (n_dg_ == 0) { fission_vector_no_delayed_from_hdf5(xsdata_grp, n_ang); } else { if (object_exists(xsdata_grp, "beta")) { @@ -376,7 +376,7 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, size_t n_ang, bool is_isotropic) } } } else { - if (n_dg == 0) { + if (n_dg_ == 0) { fission_matrix_no_delayed_from_hdf5(xsdata_grp, n_ang); } else { if (object_exists(xsdata_grp, "beta")) { @@ -388,7 +388,7 @@ XsData::fission_from_hdf5(hid_t xsdata_grp, size_t n_ang, bool is_isotropic) } // Combine prompt_nu_fission and delayed_nu_fission into nu_fission - if (n_dg == 0) { + if (n_dg_ == 0) { nu_fission = prompt_nu_fission; } else { nu_fission = prompt_nu_fission + xt::sum(delayed_nu_fission, {1}); @@ -407,9 +407,9 @@ XsData::scatter_from_hdf5(hid_t xsdata_grp, size_t n_ang, hid_t scatt_grp = open_group(xsdata_grp, "scatter_data"); // Get the outgoing group boundary indices - xt::xtensor gmin({n_ang, n_g}, 0.); + xt::xtensor gmin({n_ang, n_g_}, 0.); read_nd_vector(scatt_grp, "g_min", gmin, true); - xt::xtensor gmax({n_ang, n_g}, 0.); + xt::xtensor gmax({n_ang, n_g_}, 0.); read_nd_vector(scatt_grp, "g_max", gmax, true); // Make gmin and gmax start from 0 vice 1 as they do in the library @@ -420,7 +420,7 @@ XsData::scatter_from_hdf5(hid_t xsdata_grp, size_t n_ang, // data. size_t length = order_data * xt::sum(gmax - gmin + 1)(); - double_4dvec input_scatt(n_ang, double_3dvec(n_g)); + double_4dvec input_scatt(n_ang, double_3dvec(n_g_)); xt::xtensor temp_arr({length}, 0.); read_nd_vector(scatt_grp, "scatter_matrix", temp_arr, true); @@ -437,7 +437,7 @@ XsData::scatter_from_hdf5(hid_t xsdata_grp, size_t n_ang, // scatt data size_t temp_idx = 0; for (size_t a = 0; a < n_ang; a++) { - for (size_t gin = 0; gin < n_g; gin++) { + for (size_t gin = 0; gin < n_g_; gin++) { input_scatt[a][gin].resize(gmax(a, gin) - gmin(a, gin) + 1); for (size_t i_gout = 0; i_gout < input_scatt[a][gin].size(); i_gout++) { input_scatt[a][gin][i_gout].resize(order_dim); @@ -451,7 +451,7 @@ XsData::scatter_from_hdf5(hid_t xsdata_grp, size_t n_ang, } // Get multiplication matrix - double_3dvec temp_mult(n_ang, double_2dvec(n_g)); + double_3dvec temp_mult(n_ang, double_2dvec(n_g_)); if (object_exists(scatt_grp, "multiplicity_matrix")) { temp_arr.resize({length / order_data}); read_nd_vector(scatt_grp, "multiplicity_matrix", temp_arr); @@ -459,7 +459,7 @@ XsData::scatter_from_hdf5(hid_t xsdata_grp, size_t n_ang, // convert the flat temp_arr to a jagged array for passing to scatt data size_t temp_idx = 0; for (size_t a = 0; a < n_ang; a++) { - for (size_t gin = 0; gin < n_g; gin++) { + for (size_t gin = 0; gin < n_g_; gin++) { temp_mult[a][gin].resize(gmax(a, gin) - gmin(a, gin) + 1); for (size_t i_gout = 0; i_gout < temp_mult[a][gin].size(); i_gout++) { temp_mult[a][gin][i_gout] = temp_arr[temp_idx++]; @@ -469,7 +469,7 @@ XsData::scatter_from_hdf5(hid_t xsdata_grp, size_t n_ang, } else { // Use a default: multiplicities are 1.0. for (size_t a = 0; a < n_ang; a++) { - for (size_t gin = 0; gin < n_g; gin++) { + for (size_t gin = 0; gin < n_g_; gin++) { temp_mult[a][gin].resize(gmax(a, gin) - gmin(a, gin) + 1); for (size_t i_gout = 0; i_gout < temp_mult[a][gin].size(); i_gout++) { temp_mult[a][gin][i_gout] = 1.; From 8a8bb5f491e1257adb13fbdef8a6a632244a57cc Mon Sep 17 00:00:00 2001 From: Gavin Ridley Date: Fri, 8 Nov 2019 14:57:04 -0500 Subject: [PATCH 122/158] class, not struct --- include/openmc/mgxs_interface.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/openmc/mgxs_interface.h b/include/openmc/mgxs_interface.h index ce0a4a4c7..afd183e87 100644 --- a/include/openmc/mgxs_interface.h +++ b/include/openmc/mgxs_interface.h @@ -15,7 +15,7 @@ namespace openmc { // Global MGXS data container structure //============================================================================== -struct MgxsInterface { +class MgxsInterface { public: MgxsInterface() = default; From 2761bdbf0e72c5850f7d1509ab4007f56d5616c4 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Fri, 8 Nov 2019 14:20:03 -0600 Subject: [PATCH 123/158] Passing empty memo set directly and using object instances instead of ids in the memo. --- openmc/cell.py | 8 ++++---- openmc/geometry.py | 13 +++---------- openmc/lattice.py | 13 ++++++------- openmc/universe.py | 11 ++++++----- 4 files changed, 19 insertions(+), 26 deletions(-) diff --git a/openmc/cell.py b/openmc/cell.py index 039767cf8..ee883c796 100644 --- a/openmc/cell.py +++ b/openmc/cell.py @@ -364,11 +364,11 @@ class Cell(IDManagerMixin): cells = OrderedDict() - if memo and id(self) in memo: + if memo and self in memo: return cells if memo is not None: - memo.add(id(self)) + memo.add(self) if self.fill_type in ('universe', 'lattice'): cells.update(self.fill.get_all_cells(memo)) @@ -523,10 +523,10 @@ class Cell(IDManagerMixin): # thus far. def create_surface_elements(node, element, memo=None): if isinstance(node, Halfspace): - if memo and id(node.surface) in memo: + if memo and node.surface in memo: return if memo is not None: - memo.add(id(node.surface)) + memo.add(node.surface) xml_element.append(node.surface.to_xml_element()) elif isinstance(node, Complement): diff --git a/openmc/geometry.py b/openmc/geometry.py index 2d8c57989..5424f30e5 100644 --- a/openmc/geometry.py +++ b/openmc/geometry.py @@ -87,10 +87,8 @@ class Geometry(object): """ # Create XML representation - memo = set() - root_element = ET.Element("geometry") - self.root_universe.create_xml_subelement(root_element, memo) + self.root_universe.create_xml_subelement(root_element, memo=set()) # Sort the elements in the file root_element[:] = sorted(root_element, key=lambda x: ( @@ -273,11 +271,8 @@ class Geometry(object): Dictionary mapping cell IDs to :class:`openmc.Cell` instances """ - - memo = set() - if self.root_universe is not None: - return self.root_universe.get_all_cells(memo) + return self.root_universe.get_all_cells(memo=set()) else: return OrderedDict() @@ -306,10 +301,8 @@ class Geometry(object): instances """ - memo = set() - if self.root_universe is not None: - return self.root_universe.get_all_materials(memo) + return self.root_universe.get_all_materials(memo=set()) else: return OrderedDict() diff --git a/openmc/lattice.py b/openmc/lattice.py index f0df52e74..3377e709e 100644 --- a/openmc/lattice.py +++ b/openmc/lattice.py @@ -342,14 +342,13 @@ class Lattice(IDManagerMixin, metaclass=ABCMeta): instances """ - cells = OrderedDict() - if memo and id(self) in memo: + if memo and self in memo: return cells if memo is not None: - memo.add(id(self)) + memo.add(self) unique_universes = self.get_unique_universes() @@ -779,10 +778,10 @@ class RectLattice(Lattice): """ # If the element already contains the Lattice subelement, then return - if memo and id(self) in memo: + if memo and self in memo: return if memo is not None: - memo.add(id(self)) + memo.add(self) lattice_subelement = ET.Element("lattice") lattice_subelement.set("id", str(self._id)) @@ -1297,10 +1296,10 @@ class HexLattice(Lattice): def create_xml_subelement(self, xml_element, memo=None): # If this subelement has already been written, return - if memo and id(self) in memo: + if memo and self in memo: return if memo is not None: - memo.add(id(self)) + memo.add(self) lattice_subelement = ET.Element("hex_lattice") lattice_subelement.set("id", str(self._id)) diff --git a/openmc/universe.py b/openmc/universe.py index 24d1413a9..cbcba72c4 100644 --- a/openmc/universe.py +++ b/openmc/universe.py @@ -431,11 +431,11 @@ class Universe(IDManagerMixin): cells = OrderedDict() - if memo and id(self) in memo: + if memo and self in memo: return cells if memo is not None: - memo.add(id(self)) + memo.add(self) # Add this Universe's cells to the dictionary cells.update(self._cells) @@ -539,11 +539,12 @@ class Universe(IDManagerMixin): # Iterate over all Cells for cell_id, cell in self._cells.items(): - # If the cell was not already written, write it - if memo and id(cell) in memo: + # If the cell was already written, move on + if memo and cell in memo: continue + if memo is not None: - memo.add(id(cell)) + memo.add(cell) # Create XML subelement for this Cell cell_element = cell.create_xml_subelement(xml_element, memo) From 4394582657f5d95dd9112b44bb053c60528c4351 Mon Sep 17 00:00:00 2001 From: Patrick Shriwise Date: Fri, 8 Nov 2019 14:43:35 -0600 Subject: [PATCH 124/158] Addressing PR comments from @paulromano. --- include/openmc/geometry_aux.h | 6 +++--- src/geometry_aux.cpp | 28 ++++++++++++---------------- 2 files changed, 15 insertions(+), 19 deletions(-) diff --git a/include/openmc/geometry_aux.h b/include/openmc/geometry_aux.h index 677dcf180..800baef26 100644 --- a/include/openmc/geometry_aux.h +++ b/include/openmc/geometry_aux.h @@ -7,13 +7,13 @@ #include #include #include -#include +#include namespace openmc { namespace model { - extern std::map> universe_cell_counts; - extern std::map universe_level_counts; + extern std::unordered_map> universe_cell_counts; + extern std::unordered_map universe_level_counts; } // namespace model void read_geometry_xml(); diff --git a/src/geometry_aux.cpp b/src/geometry_aux.cpp index 229b46b8c..5ebee4aca 100644 --- a/src/geometry_aux.cpp +++ b/src/geometry_aux.cpp @@ -24,24 +24,20 @@ namespace openmc { namespace model { - std::map> universe_cell_counts; - std::map universe_level_counts; + std::unordered_map> universe_cell_counts; + std::unordered_map universe_level_counts; } // namespace model + +// adds the cell counts of universe b to universe a void update_universe_cell_count(int32_t a, int32_t b) { auto& universe_a_counts = model::universe_cell_counts[a]; const auto& universe_b_counts = model::universe_cell_counts[b]; - for (auto it : universe_b_counts) { + for (const auto& it : universe_b_counts) { universe_a_counts[it.first] += it.second; } } -void update_universe_level_count(int32_t a, int32_t b) { - auto& universe_a_count = model::universe_level_counts[a]; - const auto& universe_b_count = model::universe_level_counts[b]; - universe_a_count += universe_b_count; -} - void read_geometry_xml() { #ifdef DAGMC @@ -415,11 +411,10 @@ void count_cell_instances(int32_t univ_indx) { - if (model::universe_cell_counts.count(univ_indx)) { - std::map univ_counts = model::universe_cell_counts[univ_indx]; - for(auto it : univ_counts) { - Cell& c = *model::cells[it.first]; - c.n_instances_ += it.second; + const auto univ_counts = model::universe_cell_counts.find(univ_indx); + if (univ_counts != model::universe_cell_counts.end()) { + for (const auto& it : univ_counts->second) { + model::cells[it.first]->n_instances_ += it.second; } } else { for (int32_t cell_indx : model::universes[univ_indx]->cells_) { @@ -560,8 +555,9 @@ int maximum_levels(int32_t univ) { - if (model::universe_level_counts.count(univ)) { - return model::universe_level_counts[univ]; + const auto level_count = model::universe_level_counts.find(univ); + if (level_count != model::universe_level_counts.end()) { + return level_count->second; } int levels_below {0}; From f2a59994d68a90ba7e7f714d0a781e8a4881bd5c Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 6 Nov 2019 21:50:25 -0500 Subject: [PATCH 125/158] Show colored diffs on test results when there are failures --- setup.py | 2 +- tests/testing_harness.py | 36 ++++++++++++++++++++++++++++++------ 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/setup.py b/setup.py index aff7834d7..99db83148 100755 --- a/setup.py +++ b/setup.py @@ -69,7 +69,7 @@ kwargs = { 'pandas', 'lxml', 'uncertainties' ], 'extras_require': { - 'test': ['pytest', 'pytest-cov'], + 'test': ['pytest', 'pytest-cov', 'colorama'], 'vtk': ['vtk'], }, } diff --git a/tests/testing_harness.py b/tests/testing_harness.py index 0d3c4bec0..2266189c0 100644 --- a/tests/testing_harness.py +++ b/tests/testing_harness.py @@ -10,9 +10,25 @@ import sys import numpy as np import openmc from openmc.examples import pwr_core +from colorama import Fore, init from tests.regression_tests import config +init() + + +def colorize(diff): + """Produce colored diff for test results""" + for line in diff: + if line.startswith('+'): + yield Fore.RED + line + Fore.RESET + elif line.startswith('-'): + yield Fore.GREEN + line + Fore.RESET + elif line.startswith('^'): + yield Fore.BLUE + line + Fore.RESET + else: + yield line + class TestHarness(object): """General class for running OpenMC regression tests.""" @@ -108,11 +124,17 @@ class TestHarness(object): shutil.copyfile('results_test.dat', 'results_true.dat') def _compare_results(self): - """Make sure the current results agree with the _true standard.""" + """Make sure the current results agree with the reference.""" compare = filecmp.cmp('results_test.dat', 'results_true.dat') if not compare: + expected = open('results_true.dat').readlines() + actual = open('results_test.dat').readlines() + diff = unified_diff(expected, actual, 'results_true.dat', + 'results_test.dat') + print('Result differences:') + print(''.join(colorize(diff))) os.rename('results_test.dat', 'results_error.dat') - assert compare, 'Results do not agree.' + assert compare, 'Results do not agree' def _cleanup(self): """Delete statepoints, tally, and test files.""" @@ -325,11 +347,13 @@ class PyAPITestHarness(TestHarness): """Make sure the current inputs agree with the _true standard.""" compare = filecmp.cmp('inputs_test.dat', 'inputs_true.dat') if not compare: + expected = open('inputs_true.dat', 'r').readlines() + actual = open('inputs_error.dat', 'r').readlines() + diff = unified_diff(expected, actual, 'inputs_true.dat', + 'inputs_error.dat') + print('Input differences:') + print(''.join(colorize(diff))) os.rename('inputs_test.dat', 'inputs_error.dat') - for line in unified_diff(open('inputs_true.dat', 'r').readlines(), - open('inputs_error.dat', 'r').readlines(), - 'inputs_true.dat', 'inputs_error.dat'): - print(line, end='') assert compare, 'Input files are broken.' def _cleanup(self): From 8a449666bc36a57cb99c3847a1df9333986c8a6d Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Wed, 6 Nov 2019 21:52:49 -0500 Subject: [PATCH 126/158] Don't hash mg_tallies test results --- .../mg_tallies/results_true.dat | 1325 ++++++++++++++++- tests/regression_tests/mg_tallies/test.py | 6 +- 2 files changed, 1327 insertions(+), 4 deletions(-) diff --git a/tests/regression_tests/mg_tallies/results_true.dat b/tests/regression_tests/mg_tallies/results_true.dat index 50ec653e2..8743a290f 100644 --- a/tests/regression_tests/mg_tallies/results_true.dat +++ b/tests/regression_tests/mg_tallies/results_true.dat @@ -1 +1,1324 @@ -508cd056f2d9409a536e487512df34c683720ea45b9100316efb31c19927890c4cacd92f38817d74fcf491bbe4bdb78a0215a798d5a078e0575e3fd94cedf0bd \ No newline at end of file +k-combined: +9.934975E-01 2.679669E-02 +tally 1: +2.542000E+00 +1.343070E+00 +1.260000E-01 +3.298000E-03 +4.838111E-02 +4.857369E-04 +1.202865E-01 +3.119670E-03 +6.000347E-07 +8.163458E-14 +1.202865E-01 +3.119670E-03 +0.000000E+00 +0.000000E+00 +9.676221E+06 +1.942948E+13 +2.542000E+00 +1.343070E+00 +0.000000E+00 +0.000000E+00 +7.404202E+00 +1.141803E+01 +1.949000E+00 +8.324030E-01 +9.000000E-02 +1.762000E-03 +3.793334E-02 +3.031575E-04 +1.081691E-01 +2.457437E-03 +5.571912E-07 +6.439495E-14 +1.071378E-01 +2.411702E-03 +1.031308E-03 +1.063597E-06 +7.586669E+06 +1.212630E+13 +1.949000E+00 +8.324030E-01 +8.760860E-04 +7.675267E-07 +5.650158E+00 +7.016308E+00 +1.039000E+00 +2.447670E-01 +4.200000E-02 +4.120000E-04 +1.685968E-02 +6.389070E-05 +4.929366E-02 +5.628729E-04 +2.018053E-07 +1.119308E-14 +4.823620E-02 +5.371538E-04 +1.057461E-03 +1.118225E-06 +3.371936E+06 +2.555628E+12 +1.039000E+00 +2.447670E-01 +8.983029E-04 +8.069481E-07 +3.038326E+00 +2.108568E+00 +5.930000E-01 +7.205300E-02 +2.300000E-02 +1.110000E-04 +1.056715E-02 +2.338156E-05 +2.528379E-02 +1.491420E-04 +1.384831E-07 +6.031333E-15 +2.528379E-02 +1.491420E-04 +0.000000E+00 +0.000000E+00 +2.113430E+06 +9.352624E+11 +5.930000E-01 +7.205300E-02 +0.000000E+00 +0.000000E+00 +1.727671E+00 +6.138025E-01 +3.501000E+00 +2.515635E+00 +1.600000E-01 +5.250000E-03 +5.998847E-02 +7.320149E-04 +1.529867E-01 +4.932068E-03 +7.476127E-07 +1.267077E-13 +1.529867E-01 +4.932068E-03 +0.000000E+00 +0.000000E+00 +1.199769E+07 +2.928060E+13 +3.501000E+00 +2.515635E+00 +0.000000E+00 +0.000000E+00 +1.021925E+01 +2.143166E+01 +4.454000E+00 +4.082446E+00 +1.920000E-01 +7.726000E-03 +8.044824E-02 +1.327101E-03 +2.231973E-01 +1.024637E-02 +1.236154E-06 +3.183460E-13 +2.211081E-01 +1.008915E-02 +2.089232E-03 +2.182800E-06 +1.608965E+07 +5.308405E+13 +4.454000E+00 +4.082446E+00 +2.942322E-03 +8.657261E-06 +1.292241E+01 +3.441496E+01 +4.210000E+00 +3.829106E+00 +1.750000E-01 +6.549000E-03 +7.464456E-02 +1.228199E-03 +1.787859E-01 +7.634408E-03 +1.144154E-06 +3.572375E-13 +1.777141E-01 +7.525287E-03 +1.071750E-03 +1.148648E-06 +1.492891E+07 +4.912798E+13 +4.210000E+00 +3.829106E+00 +9.104408E-04 +8.289024E-07 +1.222119E+01 +3.220371E+01 +1.364000E+00 +3.933640E-01 +8.200000E-02 +1.378000E-03 +3.158206E-02 +2.047576E-04 +5.983520E-02 +7.581471E-04 +3.272437E-07 +2.772035E-14 +5.983520E-02 +7.581471E-04 +0.000000E+00 +0.000000E+00 +6.316412E+06 +8.190302E+12 +1.364000E+00 +3.933640E-01 +0.000000E+00 +0.000000E+00 +3.971532E+00 +3.348259E+00 +1.363000E+00 +4.205090E-01 +7.000000E-02 +1.130000E-03 +2.590153E-02 +1.476101E-04 +5.594611E-02 +6.902009E-04 +2.690262E-07 +1.501020E-14 +5.594611E-02 +6.902009E-04 +0.000000E+00 +0.000000E+00 +5.180306E+06 +5.904403E+12 +1.363000E+00 +4.205090E-01 +0.000000E+00 +0.000000E+00 +3.984609E+00 +3.608477E+00 +1.246000E+00 +3.852900E-01 +5.300000E-02 +6.650000E-04 +1.954836E-02 +9.404628E-05 +4.771133E-02 +6.866474E-04 +1.814542E-07 +1.125942E-14 +4.771133E-02 +6.866474E-04 +0.000000E+00 +0.000000E+00 +3.909672E+06 +3.761851E+12 +1.246000E+00 +3.852900E-01 +0.000000E+00 +0.000000E+00 +3.660351E+00 +3.335482E+00 +tally 2: +2.599889E+00 +1.402744E+00 +1.167830E-01 +2.830760E-03 +4.644159E-02 +4.578546E-04 +1.161040E-01 +2.861591E-03 +6.110737E-07 +8.591437E-14 +1.153679E-01 +2.825421E-03 +7.360997E-04 +1.150235E-07 +9.288319E+06 +1.831418E+13 +2.589000E+00 +1.391365E+00 +3.449004E-04 +2.525229E-08 +7.573543E+00 +1.191287E+01 +1.935337E+00 +8.143708E-01 +9.059861E-02 +1.758063E-03 +3.784648E-02 +3.023430E-04 +9.461621E-02 +1.889644E-03 +5.353929E-07 +5.956643E-14 +9.401634E-02 +1.865759E-03 +5.998671E-04 +7.595546E-08 +7.569296E+06 +1.209372E+13 +1.989000E+00 +8.632630E-01 +2.810685E-04 +1.667528E-08 +5.615484E+00 +6.866983E+00 +1.015076E+00 +2.265305E-01 +4.209446E-02 +3.711488E-04 +1.500394E-02 +4.824763E-05 +3.750984E-02 +3.015477E-04 +1.616914E-07 +8.025617E-15 +3.727203E-02 +2.977362E-04 +2.378125E-04 +1.212091E-08 +3.000787E+06 +1.929905E+12 +1.051000E+00 +2.509110E-01 +1.114274E-04 +2.661027E-09 +2.978146E+00 +1.962310E+00 +6.199894E-01 +7.878811E-02 +2.804937E-02 +1.607308E-04 +1.125386E-02 +2.891349E-05 +2.813466E-02 +1.807093E-04 +1.501221E-07 +7.165022E-15 +2.795628E-02 +1.784252E-04 +1.783738E-04 +7.263729E-09 +2.250773E+06 +1.156540E+12 +6.190000E-01 +7.822300E-02 +8.357728E-05 +1.594681E-09 +1.804831E+00 +6.709321E-01 +3.398516E+00 +2.363683E+00 +1.505108E-01 +4.655588E-03 +5.879057E-02 +7.289809E-04 +1.469764E-01 +4.556130E-03 +7.516677E-07 +1.300615E-13 +1.460446E-01 +4.498542E-03 +9.318311E-04 +1.831366E-07 +1.175811E+07 +2.915923E+13 +3.542000E+00 +2.572512E+00 +4.366106E-04 +4.020586E-08 +9.912955E+00 +2.011678E+01 +4.395956E+00 +3.964331E+00 +2.146513E-01 +9.286938E-03 +9.388516E-02 +1.784380E-03 +2.347129E-01 +1.115237E-02 +1.410768E-06 +4.182007E-13 +2.332248E-01 +1.101141E-02 +1.488081E-03 +4.482769E-07 +1.877703E+07 +7.137519E+13 +4.497000E+00 +4.157935E+00 +6.972420E-04 +9.841483E-08 +1.270142E+01 +3.319405E+01 +4.157899E+00 +3.751197E+00 +1.897379E-01 +8.038105E-03 +7.692709E-02 +1.413632E-03 +1.923177E-01 +8.835202E-03 +1.042521E-06 +3.025447E-13 +1.910984E-01 +8.723527E-03 +1.219295E-03 +3.551367E-07 +1.538542E+07 +5.654529E+13 +4.268000E+00 +3.930780E+00 +5.713023E-04 +7.796680E-08 +1.209407E+01 +3.169559E+01 +1.357524E+00 +3.878228E-01 +5.983682E-02 +7.460748E-04 +2.322979E-02 +1.144334E-04 +5.807447E-02 +7.152085E-04 +2.940107E-07 +2.024706E-14 +5.770628E-02 +7.061684E-04 +3.681924E-04 +2.874827E-08 +4.645957E+06 +4.577335E+12 +1.390000E+00 +4.083140E-01 +1.725170E-04 +6.311403E-09 +3.961412E+00 +3.308776E+00 +1.376941E+00 +4.321098E-01 +6.198249E-02 +8.400785E-04 +2.471448E-02 +1.321749E-04 +6.178621E-02 +8.260929E-04 +3.265418E-07 +2.485223E-14 +6.139448E-02 +8.156513E-04 +3.917248E-04 +3.320534E-08 +4.942896E+06 +5.286995E+12 +1.395000E+00 +4.400290E-01 +1.835431E-04 +7.289909E-09 +4.010262E+00 +3.684656E+00 +1.267762E+00 +4.052744E-01 +5.233659E-02 +6.929809E-04 +1.852753E-02 +9.379170E-05 +4.631882E-02 +5.861981E-04 +1.967460E-07 +1.534801E-14 +4.602516E-02 +5.787887E-04 +2.936615E-04 +2.356261E-08 +3.705506E+06 +3.751668E+12 +1.284000E+00 +4.070420E-01 +1.375955E-04 +5.172942E-09 +3.720938E+00 +3.496554E+00 +tally 3: +1.131330E+02 +2.561428E+03 +4.988000E+00 +4.976048E+00 +1.993967E+00 +7.956428E-01 +5.135468E+00 +5.291611E+00 +2.697394E-05 +1.462336E-10 +5.101779E+00 +5.222461E+00 +3.368875E-02 +2.575850E-04 +3.987934E+08 +3.182571E+16 +1.131330E+02 +2.561428E+03 +2.987487E-02 +1.870547E-04 +3.294536E+02 +2.172280E+04 +1.081450E+02 +2.340681E+03 +1.081450E+02 +2.340681E+03 +tally 4: +1.131330E+02 +2.561428E+03 +5.099217E+00 +5.202791E+00 +2.036481E+00 +8.305328E-01 +5.091203E+00 +5.190830E+00 +4.963770E-05 +4.951715E-10 +5.058925E+00 +5.125219E+00 +3.227825E-02 +2.086488E-04 +4.072963E+08 +3.322131E+16 +1.131330E+02 +2.561428E+03 +1.512401E-02 +4.580681E-05 +3.294536E+02 +2.172280E+04 +tally 5: +1.126689E+02 +2.540742E+03 +5.072428E+00 +5.150411E+00 +2.022883E+00 +8.201638E-01 +5.057207E+00 +5.126024E+00 +2.673439E-05 +1.438788E-10 +5.025144E+00 +5.061232E+00 +3.206271E-02 +2.060439E-04 +4.045765E+08 +3.280655E+16 +1.133620E+02 +2.571755E+03 +1.502302E-02 +4.523492E-05 +3.281376E+02 +2.155147E+04 +tally 6: +1.081450E+02 +2.340681E+03 +1.081450E+02 +2.340681E+03 +5.135468E+00 +5.291611E+00 +tally 7: +6.429000E+00 +8.307829E+00 +1.410000E+00 +3.992220E-01 +1.119414E+00 +2.516273E-01 +2.887237E+00 +1.682974E+00 +2.674702E-05 +1.437976E-10 +2.870392E+00 +1.663680E+00 +1.684448E-02 +5.768606E-05 +2.238828E+08 +1.006509E+16 +6.429000E+00 +8.307829E+00 +1.451639E-02 +4.943007E-05 +1.176869E+01 +2.783921E+01 +5.019000E+00 +5.067025E+00 +5.019000E+00 +5.067025E+00 +1.067040E+02 +2.278956E+03 +3.578000E+00 +2.562210E+00 +8.745532E-01 +1.530758E-01 +2.248231E+00 +1.013550E+00 +2.269178E-07 +1.030651E-14 +2.231387E+00 +9.980240E-01 +1.684427E-02 +8.005737E-05 +1.749106E+08 +6.123032E+15 +1.067040E+02 +2.278956E+03 +1.535848E-02 +6.943495E-05 +3.176849E+02 +2.020075E+04 +1.031260E+02 +2.128783E+03 +1.031260E+02 +2.128783E+03 +tally 8: +6.429000E+00 +8.307829E+00 +1.437899E+00 +4.155824E-01 +1.141563E+00 +2.619392E-01 +2.853907E+00 +1.637120E+00 +4.896211E-05 +4.818601E-10 +2.835814E+00 +1.616427E+00 +1.809378E-02 +6.580509E-05 +2.283126E+08 +1.047757E+16 +6.429000E+00 +8.307829E+00 +8.477865E-03 +1.444687E-05 +1.176869E+01 +2.783921E+01 +1.067040E+02 +2.278956E+03 +3.661318E+00 +2.683178E+00 +8.949183E-01 +1.603029E-01 +2.237296E+00 +1.001893E+00 +6.755918E-07 +9.135730E-14 +2.223111E+00 +9.892292E-01 +1.418446E-02 +4.027174E-05 +1.789837E+08 +6.412115E+15 +1.067040E+02 +2.278956E+03 +6.646148E-03 +8.841267E-06 +3.176849E+02 +2.020075E+04 +tally 9: +6.371628E+00 +8.173477E+00 +1.425067E+00 +4.088618E-01 +1.131376E+00 +2.577032E-01 +2.828439E+00 +1.610645E+00 +2.650833E-05 +1.414721E-10 +2.810507E+00 +1.590286E+00 +1.793232E-02 +6.474091E-05 +2.262751E+08 +1.030813E+16 +6.432000E+00 +8.315518E+00 +8.402208E-03 +1.421324E-05 +1.166367E+01 +2.738901E+01 +1.062973E+02 +2.261709E+03 +3.647362E+00 +2.662872E+00 +8.915070E-01 +1.590897E-01 +2.228767E+00 +9.943106E-01 +2.260528E-07 +1.022851E-14 +2.214637E+00 +9.817427E-01 +1.413039E-02 +3.996696E-05 +1.783014E+08 +6.363588E+15 +1.069300E+02 +2.288574E+03 +6.620813E-03 +8.774357E-06 +3.164739E+02 +2.004788E+04 +tally 10: +5.019000E+00 +5.067025E+00 +5.019000E+00 +5.067025E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +2.887237E+00 +1.682974E+00 +1.410000E+00 +3.992220E-01 +1.410000E+00 +3.992220E-01 +0.000000E+00 +0.000000E+00 +1.017160E+02 +2.071035E+03 +1.017160E+02 +2.071035E+03 +2.248231E+00 +1.013550E+00 +tally 11: +2.542000E+00 +1.343070E+00 +1.260000E-01 +3.298000E-03 +4.838111E-02 +4.857369E-04 +1.202865E-01 +3.119670E-03 +6.000347E-07 +8.163458E-14 +1.202865E-01 +3.119670E-03 +0.000000E+00 +0.000000E+00 +9.676221E+06 +1.942948E+13 +2.542000E+00 +1.343070E+00 +0.000000E+00 +0.000000E+00 +1.949000E+00 +8.324030E-01 +9.000000E-02 +1.762000E-03 +3.793334E-02 +3.031575E-04 +1.081691E-01 +2.457437E-03 +5.571912E-07 +6.439495E-14 +1.071378E-01 +2.411702E-03 +1.031308E-03 +1.063597E-06 +7.586669E+06 +1.212630E+13 +1.949000E+00 +8.324030E-01 +8.760860E-04 +7.675267E-07 +1.039000E+00 +2.447670E-01 +4.200000E-02 +4.120000E-04 +1.685968E-02 +6.389070E-05 +4.929366E-02 +5.628729E-04 +2.018053E-07 +1.119308E-14 +4.823620E-02 +5.371538E-04 +1.057461E-03 +1.118225E-06 +3.371936E+06 +2.555628E+12 +1.039000E+00 +2.447670E-01 +8.983029E-04 +8.069481E-07 +5.930000E-01 +7.205300E-02 +2.300000E-02 +1.110000E-04 +1.056715E-02 +2.338156E-05 +2.528379E-02 +1.491420E-04 +1.384831E-07 +6.031333E-15 +2.528379E-02 +1.491420E-04 +0.000000E+00 +0.000000E+00 +2.113430E+06 +9.352624E+11 +5.930000E-01 +7.205300E-02 +0.000000E+00 +0.000000E+00 +3.501000E+00 +2.515635E+00 +1.600000E-01 +5.250000E-03 +5.998847E-02 +7.320149E-04 +1.529867E-01 +4.932068E-03 +7.476127E-07 +1.267077E-13 +1.529867E-01 +4.932068E-03 +0.000000E+00 +0.000000E+00 +1.199769E+07 +2.928060E+13 +3.501000E+00 +2.515635E+00 +0.000000E+00 +0.000000E+00 +4.454000E+00 +4.082446E+00 +1.920000E-01 +7.726000E-03 +8.044824E-02 +1.327101E-03 +2.231973E-01 +1.024637E-02 +1.236154E-06 +3.183460E-13 +2.211081E-01 +1.008915E-02 +2.089232E-03 +2.182800E-06 +1.608965E+07 +5.308405E+13 +4.454000E+00 +4.082446E+00 +2.942322E-03 +8.657261E-06 +4.210000E+00 +3.829106E+00 +1.750000E-01 +6.549000E-03 +7.464456E-02 +1.228199E-03 +1.787859E-01 +7.634408E-03 +1.144154E-06 +3.572375E-13 +1.777141E-01 +7.525287E-03 +1.071750E-03 +1.148648E-06 +1.492891E+07 +4.912798E+13 +4.210000E+00 +3.829106E+00 +9.104408E-04 +8.289024E-07 +1.364000E+00 +3.933640E-01 +8.200000E-02 +1.378000E-03 +3.158206E-02 +2.047576E-04 +5.983520E-02 +7.581471E-04 +3.272437E-07 +2.772035E-14 +5.983520E-02 +7.581471E-04 +0.000000E+00 +0.000000E+00 +6.316412E+06 +8.190302E+12 +1.364000E+00 +3.933640E-01 +0.000000E+00 +0.000000E+00 +1.363000E+00 +4.205090E-01 +7.000000E-02 +1.130000E-03 +2.590153E-02 +1.476101E-04 +5.594611E-02 +6.902009E-04 +2.690262E-07 +1.501020E-14 +5.594611E-02 +6.902009E-04 +0.000000E+00 +0.000000E+00 +5.180306E+06 +5.904403E+12 +1.363000E+00 +4.205090E-01 +0.000000E+00 +0.000000E+00 +1.246000E+00 +3.852900E-01 +5.300000E-02 +6.650000E-04 +1.954836E-02 +9.404628E-05 +4.771133E-02 +6.866474E-04 +1.814542E-07 +1.125942E-14 +4.771133E-02 +6.866474E-04 +0.000000E+00 +0.000000E+00 +3.909672E+06 +3.761851E+12 +1.246000E+00 +3.852900E-01 +0.000000E+00 +0.000000E+00 +tally 12: +2.599889E+00 +1.402744E+00 +1.167830E-01 +2.830760E-03 +4.644159E-02 +4.578546E-04 +1.161040E-01 +2.861591E-03 +6.110737E-07 +8.591437E-14 +1.153679E-01 +2.825421E-03 +7.360997E-04 +1.150235E-07 +9.288319E+06 +1.831418E+13 +2.589000E+00 +1.391365E+00 +3.449004E-04 +2.525229E-08 +1.935337E+00 +8.143708E-01 +9.059861E-02 +1.758063E-03 +3.784648E-02 +3.023430E-04 +9.461621E-02 +1.889644E-03 +5.353929E-07 +5.956643E-14 +9.401634E-02 +1.865759E-03 +5.998671E-04 +7.595546E-08 +7.569296E+06 +1.209372E+13 +1.989000E+00 +8.632630E-01 +2.810685E-04 +1.667528E-08 +1.015076E+00 +2.265305E-01 +4.209446E-02 +3.711488E-04 +1.500394E-02 +4.824763E-05 +3.750984E-02 +3.015477E-04 +1.616914E-07 +8.025617E-15 +3.727203E-02 +2.977362E-04 +2.378125E-04 +1.212091E-08 +3.000787E+06 +1.929905E+12 +1.051000E+00 +2.509110E-01 +1.114274E-04 +2.661027E-09 +6.199894E-01 +7.878811E-02 +2.804937E-02 +1.607308E-04 +1.125386E-02 +2.891349E-05 +2.813466E-02 +1.807093E-04 +1.501221E-07 +7.165022E-15 +2.795628E-02 +1.784252E-04 +1.783738E-04 +7.263729E-09 +2.250773E+06 +1.156540E+12 +6.190000E-01 +7.822300E-02 +8.357728E-05 +1.594681E-09 +3.398516E+00 +2.363683E+00 +1.505108E-01 +4.655588E-03 +5.879057E-02 +7.289809E-04 +1.469764E-01 +4.556130E-03 +7.516677E-07 +1.300615E-13 +1.460446E-01 +4.498542E-03 +9.318311E-04 +1.831366E-07 +1.175811E+07 +2.915923E+13 +3.542000E+00 +2.572512E+00 +4.366106E-04 +4.020586E-08 +4.395956E+00 +3.964331E+00 +2.146513E-01 +9.286938E-03 +9.388516E-02 +1.784380E-03 +2.347129E-01 +1.115237E-02 +1.410768E-06 +4.182007E-13 +2.332248E-01 +1.101141E-02 +1.488081E-03 +4.482769E-07 +1.877703E+07 +7.137519E+13 +4.497000E+00 +4.157935E+00 +6.972420E-04 +9.841483E-08 +4.157899E+00 +3.751197E+00 +1.897379E-01 +8.038105E-03 +7.692709E-02 +1.413632E-03 +1.923177E-01 +8.835202E-03 +1.042521E-06 +3.025447E-13 +1.910984E-01 +8.723527E-03 +1.219295E-03 +3.551367E-07 +1.538542E+07 +5.654529E+13 +4.268000E+00 +3.930780E+00 +5.713023E-04 +7.796680E-08 +1.357524E+00 +3.878228E-01 +5.983682E-02 +7.460748E-04 +2.322979E-02 +1.144334E-04 +5.807447E-02 +7.152085E-04 +2.940107E-07 +2.024706E-14 +5.770628E-02 +7.061684E-04 +3.681924E-04 +2.874827E-08 +4.645957E+06 +4.577335E+12 +1.390000E+00 +4.083140E-01 +1.725170E-04 +6.311403E-09 +1.376941E+00 +4.321098E-01 +6.198249E-02 +8.400785E-04 +2.471448E-02 +1.321749E-04 +6.178621E-02 +8.260929E-04 +3.265418E-07 +2.485223E-14 +6.139448E-02 +8.156513E-04 +3.917248E-04 +3.320534E-08 +4.942896E+06 +5.286995E+12 +1.395000E+00 +4.400290E-01 +1.835431E-04 +7.289909E-09 +1.267762E+00 +4.052744E-01 +5.233659E-02 +6.929809E-04 +1.852753E-02 +9.379170E-05 +4.631882E-02 +5.861981E-04 +1.967460E-07 +1.534801E-14 +4.602516E-02 +5.787887E-04 +2.936615E-04 +2.356261E-08 +3.705506E+06 +3.751668E+12 +1.284000E+00 +4.070420E-01 +1.375955E-04 +5.172942E-09 +tally 13: +1.131330E+02 +2.561428E+03 +4.988000E+00 +4.976048E+00 +1.993967E+00 +7.956428E-01 +5.135468E+00 +5.291611E+00 +2.697394E-05 +1.462336E-10 +5.101779E+00 +5.222461E+00 +3.368875E-02 +2.575850E-04 +3.987934E+08 +3.182571E+16 +1.131330E+02 +2.561428E+03 +2.987487E-02 +1.870547E-04 +1.081450E+02 +2.340681E+03 +1.081450E+02 +2.340681E+03 +tally 14: +1.131330E+02 +2.561428E+03 +5.099217E+00 +5.202791E+00 +2.036481E+00 +8.305328E-01 +5.091203E+00 +5.190830E+00 +4.963770E-05 +4.951715E-10 +5.058925E+00 +5.125219E+00 +3.227825E-02 +2.086488E-04 +4.072963E+08 +3.322131E+16 +1.131330E+02 +2.561428E+03 +1.512401E-02 +4.580681E-05 +tally 15: +1.126689E+02 +2.540742E+03 +5.072428E+00 +5.150411E+00 +2.022883E+00 +8.201638E-01 +5.057207E+00 +5.126024E+00 +2.673439E-05 +1.438788E-10 +5.025144E+00 +5.061232E+00 +3.206271E-02 +2.060439E-04 +4.045765E+08 +3.280655E+16 +1.133620E+02 +2.571755E+03 +1.502302E-02 +4.523492E-05 +tally 16: +1.081450E+02 +2.340681E+03 +1.081450E+02 +2.340681E+03 +5.135468E+00 +5.291611E+00 +tally 17: +6.429000E+00 +8.307829E+00 +1.410000E+00 +3.992220E-01 +1.119414E+00 +2.516273E-01 +2.887237E+00 +1.682974E+00 +2.674702E-05 +1.437976E-10 +2.870392E+00 +1.663680E+00 +1.684448E-02 +5.768606E-05 +2.238828E+08 +1.006509E+16 +6.429000E+00 +8.307829E+00 +1.451639E-02 +4.943007E-05 +5.019000E+00 +5.067025E+00 +5.019000E+00 +5.067025E+00 +1.067040E+02 +2.278956E+03 +3.578000E+00 +2.562210E+00 +8.745532E-01 +1.530758E-01 +2.248231E+00 +1.013550E+00 +2.269178E-07 +1.030651E-14 +2.231387E+00 +9.980240E-01 +1.684427E-02 +8.005737E-05 +1.749106E+08 +6.123032E+15 +1.067040E+02 +2.278956E+03 +1.535848E-02 +6.943495E-05 +1.031260E+02 +2.128783E+03 +1.031260E+02 +2.128783E+03 +tally 18: +6.429000E+00 +8.307829E+00 +1.437899E+00 +4.155824E-01 +1.141563E+00 +2.619392E-01 +2.853907E+00 +1.637120E+00 +4.896211E-05 +4.818601E-10 +2.835814E+00 +1.616427E+00 +1.809378E-02 +6.580509E-05 +2.283126E+08 +1.047757E+16 +6.429000E+00 +8.307829E+00 +8.477865E-03 +1.444687E-05 +1.067040E+02 +2.278956E+03 +3.661318E+00 +2.683178E+00 +8.949183E-01 +1.603029E-01 +2.237296E+00 +1.001893E+00 +6.755918E-07 +9.135730E-14 +2.223111E+00 +9.892292E-01 +1.418446E-02 +4.027174E-05 +1.789837E+08 +6.412115E+15 +1.067040E+02 +2.278956E+03 +6.646148E-03 +8.841267E-06 +tally 19: +6.371628E+00 +8.173477E+00 +1.425067E+00 +4.088618E-01 +1.131376E+00 +2.577032E-01 +2.828439E+00 +1.610645E+00 +2.650833E-05 +1.414721E-10 +2.810507E+00 +1.590286E+00 +1.793232E-02 +6.474091E-05 +2.262751E+08 +1.030813E+16 +6.432000E+00 +8.315518E+00 +8.402208E-03 +1.421324E-05 +1.062973E+02 +2.261709E+03 +3.647362E+00 +2.662872E+00 +8.915070E-01 +1.590897E-01 +2.228767E+00 +9.943106E-01 +2.260528E-07 +1.022851E-14 +2.214637E+00 +9.817427E-01 +1.413039E-02 +3.996696E-05 +1.783014E+08 +6.363588E+15 +1.069300E+02 +2.288574E+03 +6.620813E-03 +8.774357E-06 +tally 20: +5.019000E+00 +5.067025E+00 +5.019000E+00 +5.067025E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +2.887237E+00 +1.682974E+00 +1.410000E+00 +3.992220E-01 +1.410000E+00 +3.992220E-01 +0.000000E+00 +0.000000E+00 +1.017160E+02 +2.071035E+03 +1.017160E+02 +2.071035E+03 +2.248231E+00 +1.013550E+00 diff --git a/tests/regression_tests/mg_tallies/test.py b/tests/regression_tests/mg_tallies/test.py index e1c19e6b7..f4e9693f6 100644 --- a/tests/regression_tests/mg_tallies/test.py +++ b/tests/regression_tests/mg_tallies/test.py @@ -5,7 +5,7 @@ import numpy as np import openmc from openmc.examples import slab_mg -from tests.testing_harness import HashedPyAPITestHarness +from tests.testing_harness import PyAPITestHarness def create_library(): @@ -49,7 +49,7 @@ def create_library(): mg_cross_sections_file.export_to_hdf5('2g.h5') -class MGXSTestHarness(HashedPyAPITestHarness): +class MGXSTestHarness(PyAPITestHarness): def _cleanup(self): super()._cleanup() f = '2g.h5' @@ -144,5 +144,5 @@ def test_mg_tallies(): t.nuclides = nuclides model.tallies.append(t) - harness = HashedPyAPITestHarness('statepoint.10.h5', model) + harness = MGXSTestHarness('statepoint.10.h5', model) harness.main() From 9409f0ff8f550133b608a9375da142456e7ccab4 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 7 Nov 2019 10:47:54 -0600 Subject: [PATCH 127/158] Fix delayed group indexing errors --- src/mgxs.cpp | 20 +++++++------------- src/tallies/tally_scoring.cpp | 14 +++++++------- 2 files changed, 14 insertions(+), 20 deletions(-) diff --git a/src/mgxs.cpp b/src/mgxs.cpp index 1fca66308..05ce05ac0 100644 --- a/src/mgxs.cpp +++ b/src/mgxs.cpp @@ -548,8 +548,7 @@ Mgxs::sample_fission_energy(int gin, int& dg, int& gout) double nu_fission = xs_t->nu_fission(cache[tid].a, gin); // Find the probability of having a prompt neutron - double prob_prompt = - xs_t->prompt_nu_fission(cache[tid].a, gin); + double prob_prompt = xs_t->prompt_nu_fission(cache[tid].a, gin); // sample random numbers double xi_pd = prn() * nu_fission; @@ -564,8 +563,7 @@ Mgxs::sample_fission_energy(int gin, int& dg, int& gout) // sample the outgoing energy group gout = 0; - double prob_gout = - xs_t->chi_prompt(cache[tid].a, gin, gout); + double prob_gout = xs_t->chi_prompt(cache[tid].a, gin, gout); while (prob_gout < xi_gout) { gout++; prob_gout += xs_t->chi_prompt(cache[tid].a, gin, gout); @@ -575,11 +573,9 @@ Mgxs::sample_fission_energy(int gin, int& dg, int& gout) // the neutron is delayed // get the delayed group - dg = 0; - while (xi_pd >= prob_prompt) { - dg++; - prob_prompt += - xs_t->delayed_nu_fission(cache[tid].a, dg, gin); + for (dg = 0; dg < num_delayed_groups; ++dg) { + prob_prompt += xs_t->delayed_nu_fission(cache[tid].a, dg, gin); + if (xi_pd < prob_prompt) break; } // adjust dg in case of round-off error @@ -587,12 +583,10 @@ Mgxs::sample_fission_energy(int gin, int& dg, int& gout) // sample the outgoing energy group gout = 0; - double prob_gout = - xs_t->chi_delayed(cache[tid].a, dg, gin, gout); + double prob_gout = xs_t->chi_delayed(cache[tid].a, dg, gin, gout); while (prob_gout < xi_gout) { gout++; - prob_gout += - xs_t->chi_delayed(cache[tid].a, dg, gin, gout); + prob_gout += xs_t->chi_delayed(cache[tid].a, dg, gin, gout); } } } diff --git a/src/tallies/tally_scoring.cpp b/src/tallies/tally_scoring.cpp index 37310070f..7ef05837c 100644 --- a/src/tallies/tally_scoring.cpp +++ b/src/tallies/tally_scoring.cpp @@ -1720,7 +1720,7 @@ score_general_mg(const Particle* p, int i_tally, int start_index, model::tally_filters[i_dg_filt].get())}; // Tally each delayed group bin individually for (auto d_bin = 0; d_bin < filt.n_bins(); ++d_bin) { - auto d = filt.groups()[d_bin]; + auto d = filt.groups()[d_bin] - 1; score = p->wgt_absorb_ * flux; if (i_nuclide >= 0) { score *= @@ -1802,7 +1802,7 @@ score_general_mg(const Particle* p, int i_tally, int start_index, model::tally_filters[i_dg_filt].get())}; // Tally each delayed group bin individually for (auto d_bin = 0; d_bin < filt.n_bins(); ++d_bin) { - auto d = filt.groups()[d_bin]; + auto d = filt.groups()[d_bin] - 1; if (i_nuclide >= 0) { score = flux * atom_density * get_nuclide_xs(i_nuclide, MG_GET_XS_DELAYED_NU_FISSION, @@ -1842,7 +1842,7 @@ score_general_mg(const Particle* p, int i_tally, int start_index, model::tally_filters[i_dg_filt].get())}; // Tally each delayed group bin individually for (auto d_bin = 0; d_bin < filt.n_bins(); ++d_bin) { - auto d = filt.groups()[d_bin]; + auto d = filt.groups()[d_bin] - 1; score = p->wgt_absorb_ * flux; if (i_nuclide >= 0) { score *= @@ -1902,8 +1902,8 @@ score_general_mg(const Particle* p, int i_tally, int start_index, for (auto i = 0; i < p->n_bank_; ++i) { auto i_bank = simulation::fission_bank.size() - p->n_bank_ + i; const auto& bank = simulation::fission_bank[i_bank]; - auto g = bank.delayed_group; - if (g != 0) { + auto g = bank.delayed_group - 1; + if (g != -1) { if (i_nuclide >= 0) { score += simulation::keff * atom_density * bank.wgt * flux * get_nuclide_xs(i_nuclide, MG_GET_XS_DECAY_RATE, p_g, @@ -1923,7 +1923,7 @@ score_general_mg(const Particle* p, int i_tally, int start_index, // Find the corresponding filter bin and then score for (auto d_bin = 0; d_bin < filt.n_bins(); ++d_bin) { auto d = filt.groups()[d_bin]; - if (d == g) + if (d == g + 1) score_fission_delayed_dg(i_tally, d_bin, score, score_index); } @@ -1941,7 +1941,7 @@ score_general_mg(const Particle* p, int i_tally, int start_index, model::tally_filters[i_dg_filt].get())}; // Tally each delayed group bin individually for (auto d_bin = 0; d_bin < filt.n_bins(); ++d_bin) { - auto d = filt.groups()[d_bin]; + auto d = filt.groups()[d_bin] - 1; if (i_nuclide >= 0) { score += atom_density * flux * get_nuclide_xs(i_nuclide, MG_GET_XS_DECAY_RATE, From dd7094d682533b79be7f557c9faff532890dc07d Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Thu, 7 Nov 2019 10:50:18 -0600 Subject: [PATCH 128/158] Update mg_tallies test result --- .../mg_tallies/results_true.dat | 56 +++++++++---------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/tests/regression_tests/mg_tallies/results_true.dat b/tests/regression_tests/mg_tallies/results_true.dat index 8743a290f..26a062fac 100644 --- a/tests/regression_tests/mg_tallies/results_true.dat +++ b/tests/regression_tests/mg_tallies/results_true.dat @@ -41,8 +41,8 @@ tally 1: 1.212630E+13 1.949000E+00 8.324030E-01 -8.760860E-04 -7.675267E-07 +3.122595E-04 +9.750600E-08 5.650158E+00 7.016308E+00 1.039000E+00 @@ -63,8 +63,8 @@ tally 1: 2.555628E+12 1.039000E+00 2.447670E-01 -8.983029E-04 -8.069481E-07 +3.201782E-04 +1.025141E-07 3.038326E+00 2.108568E+00 5.930000E-01 @@ -129,8 +129,8 @@ tally 1: 5.308405E+13 4.454000E+00 4.082446E+00 -2.942322E-03 -8.657261E-06 +3.894344E-03 +9.877407E-06 1.292241E+01 3.441496E+01 4.210000E+00 @@ -151,8 +151,8 @@ tally 1: 4.912798E+13 4.210000E+00 3.829106E+00 -9.104408E-04 -8.289024E-07 +3.245044E-04 +1.053031E-07 1.222119E+01 3.220371E+01 1.364000E+00 @@ -461,8 +461,8 @@ tally 3: 3.182571E+16 1.131330E+02 2.561428E+03 -2.987487E-02 -1.870547E-04 +1.464422E-02 +8.408713E-05 3.294536E+02 2.172280E+04 1.081450E+02 @@ -541,8 +541,8 @@ tally 7: 1.006509E+16 6.429000E+00 8.307829E+00 -1.451639E-02 -4.943007E-05 +3.761262E-03 +3.156399E-06 1.176869E+01 2.783921E+01 5.019000E+00 @@ -567,8 +567,8 @@ tally 7: 6.123032E+15 1.067040E+02 2.278956E+03 -1.535848E-02 -6.943495E-05 +1.088296E-02 +6.231251E-05 3.176849E+02 2.020075E+04 1.031260E+02 @@ -729,8 +729,8 @@ tally 11: 1.212630E+13 1.949000E+00 8.324030E-01 -8.760860E-04 -7.675267E-07 +3.122595E-04 +9.750600E-08 1.039000E+00 2.447670E-01 4.200000E-02 @@ -749,8 +749,8 @@ tally 11: 2.555628E+12 1.039000E+00 2.447670E-01 -8.983029E-04 -8.069481E-07 +3.201782E-04 +1.025141E-07 5.930000E-01 7.205300E-02 2.300000E-02 @@ -809,8 +809,8 @@ tally 11: 5.308405E+13 4.454000E+00 4.082446E+00 -2.942322E-03 -8.657261E-06 +3.894344E-03 +9.877407E-06 4.210000E+00 3.829106E+00 1.750000E-01 @@ -829,8 +829,8 @@ tally 11: 4.912798E+13 4.210000E+00 3.829106E+00 -9.104408E-04 -8.289024E-07 +3.245044E-04 +1.053031E-07 1.364000E+00 3.933640E-01 8.200000E-02 @@ -1111,8 +1111,8 @@ tally 13: 3.182571E+16 1.131330E+02 2.561428E+03 -2.987487E-02 -1.870547E-04 +1.464422E-02 +8.408713E-05 1.081450E+02 2.340681E+03 1.081450E+02 @@ -1185,8 +1185,8 @@ tally 17: 1.006509E+16 6.429000E+00 8.307829E+00 -1.451639E-02 -4.943007E-05 +3.761262E-03 +3.156399E-06 5.019000E+00 5.067025E+00 5.019000E+00 @@ -1209,8 +1209,8 @@ tally 17: 6.123032E+15 1.067040E+02 2.278956E+03 -1.535848E-02 -6.943495E-05 +1.088296E-02 +6.231251E-05 1.031260E+02 2.128783E+03 1.031260E+02 From 005b126f96d8a8339c523ed3968e4e726bcbe852 Mon Sep 17 00:00:00 2001 From: Gavin Ridley Date: Fri, 8 Nov 2019 18:05:32 -0500 Subject: [PATCH 129/158] can write track files in restart mode now --- src/particle_restart.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/particle_restart.cpp b/src/particle_restart.cpp index b2017bbeb..1a75d6b47 100644 --- a/src/particle_restart.cpp +++ b/src/particle_restart.cpp @@ -79,6 +79,9 @@ void run_particle_restart() int previous_run_mode; read_particle_restart(p, previous_run_mode); + // write track if that was requested on command line + if (settings::write_all_tracks) p.write_track_ = true; + // Set all tallies to 0 for now (just tracking errors) model::tallies.clear(); From 524b5344ebe4cf91fea89c08d8a9d5652378b4c9 Mon Sep 17 00:00:00 2001 From: Adam G Nelson Date: Sat, 9 Nov 2019 09:08:56 -0600 Subject: [PATCH 130/158] removed MGXS C interface methods (calculate_xs_c, get_name_c, and get_awr_c) that are no longer necessary now that the code is full C++ --- include/openmc/mgxs_interface.h | 14 ------------ src/mgxs_interface.cpp | 39 +-------------------------------- src/particle.cpp | 14 ++++++------ 3 files changed, 8 insertions(+), 59 deletions(-) diff --git a/include/openmc/mgxs_interface.h b/include/openmc/mgxs_interface.h index afd183e87..2cbe5f21d 100644 --- a/include/openmc/mgxs_interface.h +++ b/include/openmc/mgxs_interface.h @@ -82,10 +82,6 @@ void mark_fissionable_mgxs_materials(); // Mgxs tracking/transport/tallying interface methods //============================================================================== -extern "C" void -calculate_xs_c(int i_mat, int gin, double sqrtkT, Direction u, - double& total_xs, double& abs_xs, double& nu_fiss_xs); - double get_nuclide_xs(int index, int xstype, int gin, const int* gout, const double* mu, const int* dg); @@ -102,15 +98,5 @@ inline double get_macro_xs(int index, int xstype, int gin) {return get_macro_xs(index, xstype, gin, nullptr, nullptr, nullptr);} -//============================================================================== -// General Mgxs methods -//============================================================================== - -extern "C" void -get_name_c(int index, int name_len, char* name); - -extern "C" double -get_awr_c(int index); - } // namespace openmc #endif // OPENMC_MGXS_INTERFACE_H diff --git a/src/mgxs_interface.cpp b/src/mgxs_interface.cpp index 1b0f2675a..0bc61fa00 100644 --- a/src/mgxs_interface.cpp +++ b/src/mgxs_interface.cpp @@ -38,7 +38,7 @@ MgxsInterface::MgxsInterface(const std::string& path_cross_sections, void MgxsInterface::set_nuclides_and_temperatures( std::vector xs_to_read, std::vector> xs_temps) -{ +{ // Check to remove all duplicates xs_to_read_ = xs_to_read; xs_temps_to_read_ = xs_temps; @@ -291,16 +291,6 @@ void mark_fissionable_mgxs_materials() // Mgxs tracking/transport/tallying interface methods //============================================================================== -void -calculate_xs_c(int i_mat, int gin, double sqrtkT, Direction u, - double& total_xs, double& abs_xs, double& nu_fiss_xs) -{ - data::mg.macro_xs_[i_mat].calculate_xs(gin - 1, sqrtkT, u, total_xs, abs_xs, - nu_fiss_xs); -} - -//============================================================================== - double get_nuclide_xs(int index, int xstype, int gin, const int* gout, const double* mu, const int* dg) @@ -333,31 +323,4 @@ get_macro_xs(int index, int xstype, int gin, const int* gout, return data::mg.macro_xs_[index].get_xs(xstype, gin - 1, gout_c_p, mu, dg); } -//============================================================================== -// General Mgxs methods -//============================================================================== - -void -get_name_c(int index, int name_len, char* name) -{ - // First blank out our input string - std::string str(name_len - 1, ' '); - std::strcpy(name, str.c_str()); - - // Now get the data and copy to the C-string - str = data::mg.nuclides_[index - 1].name; - std::strcpy(name, str.c_str()); - - // Finally, remove the null terminator - name[std::strlen(name)] = ' '; -} - -//============================================================================== - -double -get_awr_c(int index) -{ - return data::mg.nuclides_[index - 1].awr; -} - } // namespace openmc diff --git a/src/particle.cpp b/src/particle.cpp index 030c8dc63..3ce3cf84c 100644 --- a/src/particle.cpp +++ b/src/particle.cpp @@ -203,11 +203,11 @@ Particle::transport() } } else { // Get the MG data - calculate_xs_c(material_, g_, sqrtkT_, this->u_local(), - macro_xs_.total, macro_xs_.absorption, macro_xs_.nu_fission); + data::mg.macro_xs_[material_].calculate_xs(g_ - 1, sqrtkT_, + this->u_local(), macro_xs_.total, macro_xs_.absorption, + macro_xs_.nu_fission); - // Finally, update the particle group while we have already checked - // for if multi-group + // Finally, update the particle group since we know we are multi-group g_last_ = g_; } } else { @@ -428,7 +428,7 @@ Particle::cross_surface() } return; - } else if ((surf->bc_ == BC_REFLECT || surf->bc_ == BC_WHITE) + } else if ((surf->bc_ == BC_REFLECT || surf->bc_ == BC_WHITE) && (settings::run_mode != RUN_MODE_PLOTTING)) { // ======================================================================= // PARTICLE REFLECTS FROM SURFACE @@ -458,11 +458,11 @@ Particle::cross_surface() score_surface_tally(this, model::active_meshsurf_tallies); this->r() = r; } - + Direction u = (surf->bc_ == BC_REFLECT) ? surf->reflect(this->r(), this->u()) : surf->diffuse_reflect(this->r(), this->u()); - + // Make sure new particle direction is normalized this->u() = u / u.norm(); From 2903970129d4c643072bd4a3d7d3e6cf2fbda5d3 Mon Sep 17 00:00:00 2001 From: Adam G Nelson Date: Sat, 9 Nov 2019 09:16:37 -0600 Subject: [PATCH 131/158] Added test for making an MGXS lib with nuclides, and then re-running in MG mode. Prior to this we only tested macroscopic MGXS --- .../__init__.py | 0 .../inputs_true.dat | 251 ++++++++++++++++++ .../results_true.dat | 2 + .../mgxs_library_ce_to_mg_nuclides/test.py | 85 ++++++ 4 files changed, 338 insertions(+) create mode 100644 tests/regression_tests/mgxs_library_ce_to_mg_nuclides/__init__.py create mode 100644 tests/regression_tests/mgxs_library_ce_to_mg_nuclides/inputs_true.dat create mode 100644 tests/regression_tests/mgxs_library_ce_to_mg_nuclides/results_true.dat create mode 100644 tests/regression_tests/mgxs_library_ce_to_mg_nuclides/test.py diff --git a/tests/regression_tests/mgxs_library_ce_to_mg_nuclides/__init__.py b/tests/regression_tests/mgxs_library_ce_to_mg_nuclides/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/regression_tests/mgxs_library_ce_to_mg_nuclides/inputs_true.dat b/tests/regression_tests/mgxs_library_ce_to_mg_nuclides/inputs_true.dat new file mode 100644 index 000000000..576f27966 --- /dev/null +++ b/tests/regression_tests/mgxs_library_ce_to_mg_nuclides/inputs_true.dat @@ -0,0 +1,251 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 100 + 10 + 5 + + + -0.63 -0.63 -1 0.63 0.63 1 + + + + + + + 1 + + + 0.0 0.625 20000000.0 + + + 0.0 0.625 20000000.0 + + + 3 + + + 2 + + + 3 + + + 1 2 + total + flux + tracklength + + + 1 2 + U234 U235 U238 O16 + total + tracklength + + + 1 2 + total + flux + tracklength + + + 1 2 + U234 U235 U238 O16 + absorption + tracklength + + + 1 2 + total + flux + analog + + + 1 2 7 + U234 U235 U238 O16 + nu-fission + analog + + + 1 2 + total + flux + analog + + + 1 2 7 11 + U234 U235 U238 O16 + nu-scatter + analog + + + 1 2 7 + U234 U235 U238 O16 + nu-scatter + analog + + + 1 2 7 + U234 U235 U238 O16 + scatter + analog + + + 15 2 + total + flux + tracklength + + + 15 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + total + tracklength + + + 15 2 + total + flux + tracklength + + + 15 2 + Zr90 Zr91 Zr92 Zr94 Zr96 + absorption + tracklength + + + 15 2 + total + flux + analog + + + 15 2 7 + Zr90 Zr91 Zr92 Zr94 Zr96 + nu-fission + analog + + + 15 2 + total + flux + analog + + + 15 2 7 11 + Zr90 Zr91 Zr92 Zr94 Zr96 + nu-scatter + analog + + + 15 2 7 + Zr90 Zr91 Zr92 Zr94 Zr96 + nu-scatter + analog + + + 15 2 7 + Zr90 Zr91 Zr92 Zr94 Zr96 + scatter + analog + + + 29 2 + total + flux + tracklength + + + 29 2 + H1 O16 B10 B11 + total + tracklength + + + 29 2 + total + flux + tracklength + + + 29 2 + H1 O16 B10 B11 + absorption + tracklength + + + 29 2 + total + flux + analog + + + 29 2 7 + H1 O16 B10 B11 + nu-fission + analog + + + 29 2 + total + flux + analog + + + 29 2 7 11 + H1 O16 B10 B11 + nu-scatter + analog + + + 29 2 7 + H1 O16 B10 B11 + nu-scatter + analog + + + 29 2 7 + H1 O16 B10 B11 + scatter + analog + + diff --git a/tests/regression_tests/mgxs_library_ce_to_mg_nuclides/results_true.dat b/tests/regression_tests/mgxs_library_ce_to_mg_nuclides/results_true.dat new file mode 100644 index 000000000..b494a4b4f --- /dev/null +++ b/tests/regression_tests/mgxs_library_ce_to_mg_nuclides/results_true.dat @@ -0,0 +1,2 @@ +k-combined: +5.350442E-01 1.484490E-02 diff --git a/tests/regression_tests/mgxs_library_ce_to_mg_nuclides/test.py b/tests/regression_tests/mgxs_library_ce_to_mg_nuclides/test.py new file mode 100644 index 000000000..b624140d4 --- /dev/null +++ b/tests/regression_tests/mgxs_library_ce_to_mg_nuclides/test.py @@ -0,0 +1,85 @@ +import os + +import openmc +import openmc.mgxs +from openmc.examples import pwr_pin_cell + +from tests.testing_harness import PyAPITestHarness +from tests.regression_tests import config + + +class MGXSTestHarness(PyAPITestHarness): + def __init__(self, *args, **kwargs): + # Generate inputs using parent class routine + super().__init__(*args, **kwargs) + + # Initialize a two-group structure + energy_groups = openmc.mgxs.EnergyGroups(group_edges=[0, 0.625, 20.e6]) + + # Initialize MGXS Library for a few cross section types + self.mgxs_lib = openmc.mgxs.Library(self._model.geometry) + self.mgxs_lib.by_nuclide = True + self.mgxs_lib.mgxs_types = ['total', 'absorption', 'nu-fission matrix', + 'nu-scatter matrix', 'multiplicity matrix'] + self.mgxs_lib.energy_groups = energy_groups + self.mgxs_lib.correction = None + self.mgxs_lib.legendre_order = 3 + self.mgxs_lib.domain_type = 'material' + self.mgxs_lib.build_library() + + # Initialize a tallies file + self.mgxs_lib.add_to_tallies_file(self._model.tallies, merge=False) + + def _run_openmc(self): + # Initial run + if config['mpi']: + mpi_args = [config['mpiexec'], '-n', config['mpi_np']] + openmc.run(openmc_exec=config['exe'], mpi_args=mpi_args) + else: + openmc.run(openmc_exec=config['exe']) + + # Build MG Inputs + # Get data needed to execute Library calculations. + sp = openmc.StatePoint(self._sp_name) + self.mgxs_lib.load_from_statepoint(sp) + self._model.mgxs_file, self._model.materials, \ + self._model.geometry = self.mgxs_lib.create_mg_mode() + + # Modify materials and settings so we can run in MG mode + self._model.materials.cross_sections = './mgxs.h5' + self._model.settings.energy_mode = 'multi-group' + + # Write modified input files + self._model.settings.export_to_xml() + self._model.geometry.export_to_xml() + self._model.materials.export_to_xml() + self._model.mgxs_file.export_to_hdf5() + # Dont need tallies.xml, so remove the file + if os.path.exists('tallies.xml'): + os.remove('tallies.xml') + + # Enforce closing statepoint and summary files so HDF5 + # does not throw an error during the next OpenMC execution + sp._f.close() + sp._summary._f.close() + + # Re-run MG mode. + if config['mpi']: + mpi_args = [config['mpiexec'], '-n', config['mpi_np']] + openmc.run(openmc_exec=config['exe'], mpi_args=mpi_args) + else: + openmc.run(openmc_exec=config['exe']) + + def _cleanup(self): + super()._cleanup() + f = 'mgxs.h5' + if os.path.exists(f): + os.remove(f) + + +def test_mgxs_library_ce_to_mg(): + # Set the input set to use the pincell model + model = pwr_pin_cell() + + harness = MGXSTestHarness('statepoint.10.h5', model) + harness.main() From 3ccfa08a115c70833a0ec2a7f4d3995ba0d60372 Mon Sep 17 00:00:00 2001 From: Adam G Nelson Date: Sat, 9 Nov 2019 09:24:30 -0600 Subject: [PATCH 132/158] minor change to add an inline version of Mgxs::get_xs just like @gridley did for mg.get_*_xs --- include/openmc/mgxs.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/openmc/mgxs.h b/include/openmc/mgxs.h index 313677f6c..71e8c7ec9 100644 --- a/include/openmc/mgxs.h +++ b/include/openmc/mgxs.h @@ -143,6 +143,11 @@ class Mgxs { get_xs(int xstype, int gin, const int* gout, const double* mu, const int* dg); + inline double + get_xs(int xstype, int gin) + {return get_xs(xstype, gin, nullptr, nullptr, nullptr);} + + //! \brief Samples the fission neutron energy and if prompt or delayed. //! //! @param gin Incoming energy group. From 15c7148331a3b05e28070d9b80d277e0e73ca0ea Mon Sep 17 00:00:00 2001 From: Ethan Peterson Date: Mon, 4 Nov 2019 17:27:50 -0500 Subject: [PATCH 133/158] Adding SphericalIndependent source type Applied suggestions from code review Co-Authored-By: Paul Romano --- docs/source/io_formats/settings.rst | 41 +++++- docs/source/pythonapi/stats.rst | 1 + include/openmc/distribution_spatial.h | 18 +++ openmc/stats/multivariate.py | 121 +++++++++++++++++- src/distribution_spatial.cpp | 67 ++++++++++ src/relaxng/settings.rnc | 6 +- src/relaxng/settings.rng | 24 ++++ src/source.cpp | 2 + tests/regression_tests/source/inputs_true.dat | 15 ++- .../regression_tests/source/results_true.dat | 2 +- tests/regression_tests/source/test.py | 12 +- 11 files changed, 296 insertions(+), 13 deletions(-) diff --git a/docs/source/io_formats/settings.rst b/docs/source/io_formats/settings.rst index fb55f9e51..c14767e46 100644 --- a/docs/source/io_formats/settings.rst +++ b/docs/source/io_formats/settings.rst @@ -423,12 +423,16 @@ attributes/sub-elements: :type: The type of spatial distribution. Valid options are "box", "fission", - "point", and "cartesian". A "box" spatial distribution has coordinates - sampled uniformly in a parallelepiped. A "fission" spatial distribution - samples locations from a "box" distribution but only locations in - fissionable materials are accepted. A "point" spatial distribution has - coordinates specified by a triplet. An "cartesian" spatial distribution - specifies independent distributions of x-, y-, and z-coordinates. + "point", "cartesian", and "spherical". A "box" spatial distribution has + coordinates sampled uniformly in a parallelepiped. A "fission" spatial + distribution samples locations from a "box" distribution but only + locations in fissionable materials are accepted. A "point" spatial + distribution has coordinates specified by a triplet. An "cartesian" + spatial distribution specifies independent distributions of x-, y-, and + z-coordinates. A "spherical" spatial distribution specifies independent + distributions of r-, theta-, and phi-coordinates where theta is the angle + with respect to the z-axis, phi is the azimuthal angle, and the sphere is + centered on the coordinate (x0,y0,z0). *Default*: None @@ -446,6 +450,9 @@ attributes/sub-elements: For an "cartesian" distribution, no parameters are specified. Instead, the ``x``, ``y``, and ``z`` elements must be specified. + For a "spherical" distribution, no parameters are specified. Instead, + the ``r``, ``theta``, ``phi``, and ``origin`` elements must be specified. + *Default*: None :x: @@ -466,6 +473,28 @@ attributes/sub-elements: univariate probability distribution (see the description in :ref:`univariate`). + :r: + For a "spherical" distribution, this element specifies the distribution + of r-coordinates. The necessary sub-elements/attributes are those of a + univariate probability distribution (see the description in + :ref:`univariate`). + + :theta: + For a "spherical" distribution, this element specifies the distribution + of theta-coordinates. The necessary sub-elements/attributes are those of a + univariate probability distribution (see the description in + :ref:`univariate`). + + :phi: + For a "spherical" distribution, this element specifies the distribution + of phi-coordinates. The necessary sub-elements/attributes are those of a + univariate probability distribution (see the description in + :ref:`univariate`). + + :origin: + For a "spherical" distribution, this element specifies the coordinates of + the center of the sphere. + :angle: An element specifying the angular distribution of source sites. This element has the following attributes: diff --git a/docs/source/pythonapi/stats.rst b/docs/source/pythonapi/stats.rst index 6ad0e6b03..cacbab31b 100644 --- a/docs/source/pythonapi/stats.rst +++ b/docs/source/pythonapi/stats.rst @@ -46,5 +46,6 @@ Spatial Distributions openmc.stats.Spatial openmc.stats.CartesianIndependent + openmc.stats.SphericalIndependent openmc.stats.Box openmc.stats.Point diff --git a/include/openmc/distribution_spatial.h b/include/openmc/distribution_spatial.h index 248f03588..6cf6f52d6 100644 --- a/include/openmc/distribution_spatial.h +++ b/include/openmc/distribution_spatial.h @@ -37,6 +37,24 @@ private: UPtrDist z_; //!< Distribution of z coordinates }; +//============================================================================== +//! Distribution of points specified by spherical coordinates r,theta,phi +//============================================================================== + +class SphericalIndependent : public SpatialDistribution { +public: + explicit SphericalIndependent(pugi::xml_node node); + + //! Sample a position from the distribution + //! \return Sampled position + Position sample() const; +private: + UPtrDist r_; //!< Distribution of r coordinates + UPtrDist theta_; //!< Distribution of theta coordinates + UPtrDist phi_; //!< Distribution of phi coordinates + Position origin_; //!< Cartesian coordinates of the sphere center +}; + //============================================================================== //! Uniform distribution of points over a box //============================================================================== diff --git a/openmc/stats/multivariate.py b/openmc/stats/multivariate.py index 35afc21dd..6a97e6192 100644 --- a/openmc/stats/multivariate.py +++ b/openmc/stats/multivariate.py @@ -272,6 +272,8 @@ class Spatial(metaclass=ABCMeta): distribution = get_text(elem, 'type') if distribution == 'cartesian': return CartesianIndependent.from_xml_element(elem) + elif distribution == 'spherical': + return SphericalIndependent.from_xml_element(elem) elif distribution == 'box' or distribution == 'fission': return Box.from_xml_element(elem) elif distribution == 'point': @@ -281,7 +283,7 @@ class Spatial(metaclass=ABCMeta): class CartesianIndependent(Spatial): """Spatial distribution with independent x, y, and z distributions. - This distribution allows one to specify a coordinates whose x-, y-, and z- + This distribution allows one to specify coordinates whose x-, y-, and z- components are sampled independently from one another. Parameters @@ -304,7 +306,6 @@ class CartesianIndependent(Spatial): """ - def __init__(self, x, y, z): super().__init__() self.x = x @@ -375,6 +376,122 @@ class CartesianIndependent(Spatial): return cls(x, y, z) +class SphericalIndependent(Spatial): + """Spatial distribution represented in spherical coordinates. + + This distribution allows one to specify coordinates whose :math:`r`, + :math:`\theta`, and :math:`\phi` components are sampled independently from + one another and centered on the coordinates (x0, y0, z0). + + Parameters + ---------- + r : openmc.stats.Univariate + Distribution of r-coordinates + theta : openmc.stats.Univariate + Distribution of theta-coordinates (angle relative to the z-axis) + phi : openmc.stats.Univariate + Distribution of phi-coordinates (azimuthal angle) + origin: Iterable of float, optional + coordinates (x0, y0, z0) of the center of the sphere. Defaults to + (0.0, 0.0, 0.0) + + Attributes + ---------- + r : openmc.stats.Univariate + Distribution of r-coordinates + theta : openmc.stats.Univariate + Distribution of theta-coordinates (angle relative to the z-axis) + phi : openmc.stats.Univariate + Distribution of phi-coordinates (azimuthal angle) + origin: Iterable of float, optional + coordinates (x0, y0, z0) of the center of the sphere. Defaults to + (0.0, 0.0, 0.0) + + """ + + def __init__(self, r, theta, phi, origin=(0.0, 0.0, 0.0)): + super().__init__() + self.r = r + self.theta = theta + self.phi = phi + self.origin = origin + + @property + def r(self): + return self._r + + @property + def theta(self): + return self._theta + + @property + def phi(self): + return self._phi + + @property + def origin(self): + return self._origin + + @r.setter + def r(self, r): + cv.check_type('r coordinate', r, Univariate) + self._r = r + + @theta.setter + def theta(self, theta): + cv.check_type('theta coordinate', theta, Univariate) + self._theta = theta + + @phi.setter + def phi(self, phi): + cv.check_type('phi coordinate', phi, Univariate) + self._phi = phi + + @origin.setter + def origin(self, origin): + cv.check_type('origin coordinates', origin, Iterable, Real) + origin = np.asarray(origin) + self._origin = origin + + def to_xml_element(self): + """Return XML representation of the spatial distribution + + Returns + ------- + element : xml.etree.ElementTree.Element + XML element containing spatial distribution data + + """ + element = ET.Element('space') + element.set('type', 'spherical') + element.append(self.r.to_xml_element('r')) + element.append(self.theta.to_xml_element('theta')) + element.append(self.phi.to_xml_element('phi')) + element.set("origin", ' '.join(map(str, self.origin))) + return element + + @classmethod + def from_xml_element(cls, elem): + """Generate spatial distribution from an XML element + + Parameters + ---------- + elem : xml.etree.ElementTree.Element + XML element + + Returns + ------- + openmc.stats.SphericalIndependent + Spatial distribution generated from XML element + + """ + r = Univariate.from_xml_element(elem.find('r')) + theta = Univariate.from_xml_element(elem.find('theta')) + phi = Univariate.from_xml_element(elem.find('phi')) + origin = [float(x) for x in elem.get('origin').split()] + return cls(r, theta, phi, origin=origin) + + class Box(Spatial): """Uniform distribution of coordinates in a rectangular cuboid. diff --git a/src/distribution_spatial.cpp b/src/distribution_spatial.cpp index 15098407b..e92601016 100644 --- a/src/distribution_spatial.cpp +++ b/src/distribution_spatial.cpp @@ -51,6 +51,73 @@ Position CartesianIndependent::sample() const return {x_->sample(), y_->sample(), z_->sample()}; } +//============================================================================== +// SphericalIndependent implementation +//============================================================================== + +SphericalIndependent::SphericalIndependent(pugi::xml_node node) +{ + // Read distribution for r-coordinate + if (check_for_node(node, "r")) { + pugi::xml_node node_dist = node.child("r"); + r_ = distribution_from_xml(node_dist); + } else { + // If no distribution was specified, default to a single point at r=0 + double x[] {0.0}; + double p[] {1.0}; + r_ = std::make_unique(x, p, 1); + } + + // Read distribution for theta-coordinate + if (check_for_node(node, "theta")) { + pugi::xml_node node_dist = node.child("theta"); + theta_ = distribution_from_xml(node_dist); + } else { + // If no distribution was specified, default to a single point at theta=0 + double x[] {0.0}; + double p[] {1.0}; + theta_ = std::make_unique(x, p, 1); + } + + // Read distribution for phi-coordinate + if (check_for_node(node, "phi")) { + pugi::xml_node node_dist = node.child("phi"); + phi_ = distribution_from_xml(node_dist); + } else { + // If no distribution was specified, default to a single point at phi=0 + double x[] {0.0}; + double p[] {1.0}; + phi_ = std::make_unique(x, p, 1); + } + + // Read sphere center coordinates + if (check_for_node(node, "origin")) { + auto origin = get_node_array(node, "origin"); + if (origin.size() == 3) { + origin_ = origin; + } else { + std::stringstream err_msg; + err_msg << "Origin for spherical source distribution must be length 3"; + fatal_error(err_msg); + } + } else { + // If no coordinates were specified, default to (0, 0, 0) + origin_ = {0.0, 0.0, 0.0}; + } + +} + +Position SphericalIndependent::sample() const +{ + double r = r_->sample(); + double theta = theta_->sample(); + double phi = phi_->sample(); + double x = r*sin(theta)*cos(phi) + origin_.x; + double y = r*sin(theta)*sin(phi) + origin_.y; + double z = r*cos(theta) + origin_.z; + return {x, y, z}; +} + //============================================================================== // SpatialBox implementation //============================================================================== diff --git a/src/relaxng/settings.rnc b/src/relaxng/settings.rnc index 731aa70a9..eb27d8591 100644 --- a/src/relaxng/settings.rnc +++ b/src/relaxng/settings.rnc @@ -75,7 +75,11 @@ element settings { attribute parameters { list { xsd:double+ } })? & element x { distribution }? & element y { distribution }? & - element z { distribution }? + element z { distribution }? & + element r { distribution }? & + element theta { distribution }? & + element phi { distribution }? & + element origin { list { xsd:double, xsd:double, xsd:double } }? }? & element angle { (element type { xsd:string } | attribute type { xsd:string }) & diff --git a/src/relaxng/settings.rng b/src/relaxng/settings.rng index 3ed15c3ed..0c825d0d8 100644 --- a/src/relaxng/settings.rng +++ b/src/relaxng/settings.rng @@ -348,6 +348,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/source.cpp b/src/source.cpp index 0baa21b17..3476223cd 100644 --- a/src/source.cpp +++ b/src/source.cpp @@ -86,6 +86,8 @@ SourceDistribution::SourceDistribution(pugi::xml_node node) type = get_node_value(node_space, "type", true, true); if (type == "cartesian") { space_ = UPtrSpace{new CartesianIndependent(node_space)}; + } else if (type == "spherical") { + space_ = UPtrSpace{new SphericalIndependent(node_space)}; } else if (type == "box") { space_ = UPtrSpace{new SpatialBox(node_space)}; } else if (type == "fission") { diff --git a/tests/regression_tests/source/inputs_true.dat b/tests/regression_tests/source/inputs_true.dat index 7eeefbc00..6f05eb3a7 100644 --- a/tests/regression_tests/source/inputs_true.dat +++ b/tests/regression_tests/source/inputs_true.dat @@ -41,7 +41,7 @@ - + 1.2 -2.3 0.781 @@ -50,4 +50,17 @@ 1.0 1.3894954943731377 1.93069772888325 2.6826957952797255 3.72759372031494 5.17947467923121 7.196856730011519 10.0 13.894954943731374 19.306977288832496 26.826957952797247 37.2759372031494 51.7947467923121 71.96856730011518 100.0 138.94954943731375 193.06977288832496 268.26957952797244 372.7593720314938 517.9474679231207 719.6856730011514 1000.0 1389.4954943731375 1930.6977288832495 2682.6957952797247 3727.593720314938 5179.474679231207 7196.856730011514 10000.0 13894.95494373136 19306.977288832495 26826.95795279722 37275.93720314938 51794.74679231213 71968.56730011514 100000.0 138949.5494373136 193069.77288832495 268269.5795279722 372759.3720314938 517947.4679231202 719685.6730011514 1000000.0 1389495.494373136 1930697.7288832497 2682695.7952797217 3727593.720314938 5179474.679231202 7196856.730011513 10000000.0 0.0 2.9086439299358713e-08 5.80533561806147e-08 8.67817193689187e-08 1.1515347785771536e-07 1.4305204600565115e-07 1.7036278261198208e-07 1.9697346200185813e-07 2.227747351856934e-07 2.4766057919761985e-07 2.715287327665956e-07 2.9428111652990295e-07 3.1582423606228735e-07 3.360695660646056e-07 3.549339141332686e-07 3.723397626156721e-07 3.882155871468592e-07 4.024961505584776e-07 4.151227709522976e-07 4.260435628367196e-07 4.3521365033538783e-07 4.4259535159179273e-07 4.4815833361210174e-07 4.5187973690993757e-07 4.5374426944091084e-07 4.5374426944091084e-07 4.5187973690993757e-07 4.4815833361210174e-07 4.4259535159179273e-07 4.352136503353879e-07 4.2604356283671966e-07 4.1512277095229767e-07 4.0249615055847764e-07 3.8821558714685926e-07 3.723397626156722e-07 3.5493391413326864e-07 3.360695660646057e-07 3.158242360622874e-07 2.942811165299031e-07 2.715287327665957e-07 2.4766057919762e-07 2.2277473518569352e-07 1.9697346200185819e-07 1.7036278261198226e-07 1.4305204600565126e-07 1.1515347785771556e-07 8.678171936891881e-08 5.805335618061493e-08 2.9086439299358858e-08 5.559621115282002e-23 + + + + + 0.7853981633974483 1.5707963267948966 2.356194490192345 0.3 0.4 0.3 + + + + + + 1.0 1.3894954943731377 1.93069772888325 2.6826957952797255 3.72759372031494 5.17947467923121 7.196856730011519 10.0 13.894954943731374 19.306977288832496 26.826957952797247 37.2759372031494 51.7947467923121 71.96856730011518 100.0 138.94954943731375 193.06977288832496 268.26957952797244 372.7593720314938 517.9474679231207 719.6856730011514 1000.0 1389.4954943731375 1930.6977288832495 2682.6957952797247 3727.593720314938 5179.474679231207 7196.856730011514 10000.0 13894.95494373136 19306.977288832495 26826.95795279722 37275.93720314938 51794.74679231213 71968.56730011514 100000.0 138949.5494373136 193069.77288832495 268269.5795279722 372759.3720314938 517947.4679231202 719685.6730011514 1000000.0 1389495.494373136 1930697.7288832497 2682695.7952797217 3727593.720314938 5179474.679231202 7196856.730011513 10000000.0 0.0 2.9086439299358713e-08 5.80533561806147e-08 8.67817193689187e-08 1.1515347785771536e-07 1.4305204600565115e-07 1.7036278261198208e-07 1.9697346200185813e-07 2.227747351856934e-07 2.4766057919761985e-07 2.715287327665956e-07 2.9428111652990295e-07 3.1582423606228735e-07 3.360695660646056e-07 3.549339141332686e-07 3.723397626156721e-07 3.882155871468592e-07 4.024961505584776e-07 4.151227709522976e-07 4.260435628367196e-07 4.3521365033538783e-07 4.4259535159179273e-07 4.4815833361210174e-07 4.5187973690993757e-07 4.5374426944091084e-07 4.5374426944091084e-07 4.5187973690993757e-07 4.4815833361210174e-07 4.4259535159179273e-07 4.352136503353879e-07 4.2604356283671966e-07 4.1512277095229767e-07 4.0249615055847764e-07 3.8821558714685926e-07 3.723397626156722e-07 3.5493391413326864e-07 3.360695660646057e-07 3.158242360622874e-07 2.942811165299031e-07 2.715287327665957e-07 2.4766057919762e-07 2.2277473518569352e-07 1.9697346200185819e-07 1.7036278261198226e-07 1.4305204600565126e-07 1.1515347785771556e-07 8.678171936891881e-08 5.805335618061493e-08 2.9086439299358858e-08 5.559621115282002e-23 + + diff --git a/tests/regression_tests/source/results_true.dat b/tests/regression_tests/source/results_true.dat index 6fe76c8cd..8f24644f0 100644 --- a/tests/regression_tests/source/results_true.dat +++ b/tests/regression_tests/source/results_true.dat @@ -1,2 +1,2 @@ k-combined: -2.800827E-01 7.360163E-03 +3.004769E-01 3.944044E-03 diff --git a/tests/regression_tests/source/test.py b/tests/regression_tests/source/test.py index cd468c5b8..5fd06286b 100644 --- a/tests/regression_tests/source/test.py +++ b/tests/regression_tests/source/test.py @@ -29,9 +29,16 @@ class SourceTestHarness(PyAPITestHarness): x_dist = openmc.stats.Uniform(-3., 3.) y_dist = openmc.stats.Discrete([-4., -1., 3.], [0.2, 0.3, 0.5]) z_dist = openmc.stats.Tabular([-2., 0., 2.], [0.2, 0.3, 0.2]) + r_dist = openmc.stats.Uniform(2., 3.) + theta_dist = openmc.stats.Discrete([pi/4, pi/2, 3*pi/4], + [0.3, 0.4, 0.3]) + phi_dist = openmc.stats.Uniform(0.0, 2*pi) spatial1 = openmc.stats.CartesianIndependent(x_dist, y_dist, z_dist) spatial2 = openmc.stats.Box([-4., -4., -4.], [4., 4., 4.]) spatial3 = openmc.stats.Point([1.2, -2.3, 0.781]) + spatial4 = openmc.stats.SphericalIndependent(r_dist, theta_dist, + phi_dist, + origin=(1.0, 1.0, 0.0)) mu_dist = openmc.stats.Discrete([-1., 0., 1.], [0.5, 0.25, 0.25]) phi_dist = openmc.stats.Uniform(0., 6.28318530718) @@ -48,13 +55,14 @@ class SourceTestHarness(PyAPITestHarness): source1 = openmc.Source(spatial1, angle1, energy1, strength=0.5) source2 = openmc.Source(spatial2, angle2, energy2, strength=0.3) - source3 = openmc.Source(spatial3, angle3, energy3, strength=0.2) + source3 = openmc.Source(spatial3, angle3, energy3, strength=0.1) + source4 = openmc.Source(spatial4, angle3, energy3, strength=0.1) settings = openmc.Settings() settings.batches = 10 settings.inactive = 5 settings.particles = 1000 - settings.source = [source1, source2, source3] + settings.source = [source1, source2, source3, source4] settings.export_to_xml() From 833680d6a7c61c36899e0a921a659e2a9bc8c2a1 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Fri, 19 Jul 2019 07:57:42 -0500 Subject: [PATCH 134/158] Update xtensor to 0.20.10, xtl to 0.6.7 --- CMakeLists.txt | 1 + vendor/vendor.txt | 4 + vendor/xtensor/CMakeLists.txt | 87 +- .../xtensor/include/xtensor/xaccessible.hpp | 307 ++++ .../xtensor/include/xtensor/xaccumulator.hpp | 182 +- vendor/xtensor/include/xtensor/xadapt.hpp | 524 ++++-- vendor/xtensor/include/xtensor/xarray.hpp | 90 +- vendor/xtensor/include/xtensor/xassign.hpp | 539 +++--- .../include/xtensor/xaxis_iterator.hpp | 3 +- vendor/xtensor/include/xtensor/xbroadcast.hpp | 249 +-- .../include/xtensor/xbuffer_adaptor.hpp | 839 +++++++--- vendor/xtensor/include/xtensor/xbuilder.hpp | 179 +- vendor/xtensor/include/xtensor/xcomplex.hpp | 112 +- vendor/xtensor/include/xtensor/xcontainer.hpp | 977 ++++------- vendor/xtensor/include/xtensor/xcsv.hpp | 43 +- .../xtensor/include/xtensor/xdynamic_view.hpp | 704 ++++++++ vendor/xtensor/include/xtensor/xeval.hpp | 16 +- vendor/xtensor/include/xtensor/xexception.hpp | 108 +- .../xtensor/include/xtensor/xexpression.hpp | 574 ++++++- .../include/xtensor/xexpression_holder.hpp | 281 ++++ .../include/xtensor/xexpression_traits.hpp | 166 ++ vendor/xtensor/include/xtensor/xfixed.hpp | 565 ++++--- vendor/xtensor/include/xtensor/xfunction.hpp | 936 +++++------ .../xtensor/include/xtensor/xfunctor_view.hpp | 1265 ++++++++------ vendor/xtensor/include/xtensor/xgenerator.hpp | 274 ++- vendor/xtensor/include/xtensor/xhistogram.hpp | 431 +++++ .../xtensor/include/xtensor/xindex_view.hpp | 126 +- vendor/xtensor/include/xtensor/xinfo.hpp | 3 +- vendor/xtensor/include/xtensor/xio.hpp | 197 ++- vendor/xtensor/include/xtensor/xiterable.hpp | 865 +++++++--- vendor/xtensor/include/xtensor/xiterator.hpp | 270 +-- vendor/xtensor/include/xtensor/xjson.hpp | 54 +- vendor/xtensor/include/xtensor/xlayout.hpp | 6 +- .../xtensor/include/xtensor/xmanipulation.hpp | 612 +++++++ .../xtensor/include/xtensor/xmasked_view.hpp | 647 ++++++++ vendor/xtensor/include/xtensor/xmath.hpp | 1468 +++++++++++++---- vendor/xtensor/include/xtensor/xmime.hpp | 403 +++++ vendor/xtensor/include/xtensor/xnoalias.hpp | 164 +- vendor/xtensor/include/xtensor/xnorm.hpp | 332 +++- vendor/xtensor/include/xtensor/xnpy.hpp | 61 +- .../xtensor/include/xtensor/xoffset_view.hpp | 46 +- vendor/xtensor/include/xtensor/xoperation.hpp | 558 ++++--- vendor/xtensor/include/xtensor/xoptional.hpp | 1302 +++++++++++---- .../include/xtensor/xoptional_assembly.hpp | 76 +- .../xtensor/xoptional_assembly_base.hpp | 234 +-- .../xtensor/xoptional_assembly_storage.hpp | 51 +- vendor/xtensor/include/xtensor/xpad.hpp | 209 +++ vendor/xtensor/include/xtensor/xrandom.hpp | 707 +++++++- vendor/xtensor/include/xtensor/xreducer.hpp | 1165 +++++++++---- vendor/xtensor/include/xtensor/xscalar.hpp | 377 ++--- vendor/xtensor/include/xtensor/xsemantic.hpp | 182 +- vendor/xtensor/include/xtensor/xshape.hpp | 385 ++++- vendor/xtensor/include/xtensor/xslice.hpp | 1014 +++++++++--- vendor/xtensor/include/xtensor/xsort.hpp | 849 +++++++++- vendor/xtensor/include/xtensor/xstorage.hpp | 684 +++++++- .../xtensor/include/xtensor/xstrided_view.hpp | 1033 +++--------- .../include/xtensor/xstrided_view_base.hpp | 926 ++++++----- vendor/xtensor/include/xtensor/xstrides.hpp | 369 ++++- vendor/xtensor/include/xtensor/xtensor.hpp | 489 +++++- .../include/xtensor/xtensor_config.hpp | 62 +- .../include/xtensor/xtensor_forward.hpp | 82 +- .../xtensor/include/xtensor/xtensor_simd.hpp | 172 +- vendor/xtensor/include/xtensor/xutils.hpp | 745 +++------ vendor/xtensor/include/xtensor/xvectorize.hpp | 5 +- vendor/xtensor/include/xtensor/xview.hpp | 1070 ++++++++---- .../xtensor/include/xtensor/xview_utils.hpp | 12 +- vendor/xtensor/xtensorConfig.cmake.in | 14 +- vendor/xtl/CMakeLists.txt | 25 +- vendor/xtl/include/xtl/xany.hpp | 22 +- vendor/xtl/include/xtl/xbase64.hpp | 3 +- .../xtl/include/xtl/xbasic_fixed_string.hpp | 1407 ++++++++-------- vendor/xtl/include/xtl/xclosure.hpp | 55 +- vendor/xtl/include/xtl/xcomplex.hpp | 75 +- vendor/xtl/include/xtl/xcomplex_sequence.hpp | 1 + vendor/xtl/include/xtl/xdynamic_bitset.hpp | 817 +++++---- vendor/xtl/include/xtl/xfunctional.hpp | 19 +- vendor/xtl/include/xtl/xhash.hpp | 10 +- vendor/xtl/include/xtl/xiterator_base.hpp | 77 +- vendor/xtl/include/xtl/xjson.hpp | 46 +- vendor/xtl/include/xtl/xmasked_value.hpp | 545 ++++++ vendor/xtl/include/xtl/xmasked_value_meta.hpp | 40 + vendor/xtl/include/xtl/xmeta_utils.hpp | 143 +- vendor/xtl/include/xtl/xoptional.hpp | 489 +++--- vendor/xtl/include/xtl/xoptional_meta.hpp | 140 ++ vendor/xtl/include/xtl/xsequence.hpp | 88 +- vendor/xtl/include/xtl/xspan.hpp | 20 + vendor/xtl/include/xtl/xspan_impl.hpp | 778 +++++++++ vendor/xtl/include/xtl/xtl_config.hpp | 16 +- vendor/xtl/include/xtl/xtype_traits.hpp | 278 +++- vendor/xtl/include/xtl/xvariant.hpp | 90 +- vendor/xtl/include/xtl/xvariant_impl.hpp | 790 ++++++--- vendor/xtl/xtl.pc.in | 8 + 92 files changed, 24151 insertions(+), 9313 deletions(-) create mode 100644 vendor/vendor.txt create mode 100644 vendor/xtensor/include/xtensor/xaccessible.hpp create mode 100644 vendor/xtensor/include/xtensor/xdynamic_view.hpp create mode 100644 vendor/xtensor/include/xtensor/xexpression_holder.hpp create mode 100644 vendor/xtensor/include/xtensor/xexpression_traits.hpp create mode 100644 vendor/xtensor/include/xtensor/xhistogram.hpp create mode 100644 vendor/xtensor/include/xtensor/xmanipulation.hpp create mode 100644 vendor/xtensor/include/xtensor/xmasked_view.hpp create mode 100644 vendor/xtensor/include/xtensor/xmime.hpp create mode 100644 vendor/xtensor/include/xtensor/xpad.hpp create mode 100644 vendor/xtl/include/xtl/xmasked_value.hpp create mode 100644 vendor/xtl/include/xtl/xmasked_value_meta.hpp create mode 100644 vendor/xtl/include/xtl/xoptional_meta.hpp create mode 100644 vendor/xtl/include/xtl/xspan.hpp create mode 100644 vendor/xtl/include/xtl/xspan_impl.hpp create mode 100644 vendor/xtl/xtl.pc.in diff --git a/CMakeLists.txt b/CMakeLists.txt index 6acfcf2c8..68e5bdaef 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -130,6 +130,7 @@ if (NOT (CMAKE_VERSION VERSION_LESS 3.13)) endif() add_subdirectory(vendor/xtl) +set(xtl_DIR ${CMAKE_CURRENT_BINARY_DIR}/vendor/xtl) add_subdirectory(vendor/xtensor) target_link_libraries(xtensor INTERFACE xtl) diff --git a/vendor/vendor.txt b/vendor/vendor.txt new file mode 100644 index 000000000..4291ee375 --- /dev/null +++ b/vendor/vendor.txt @@ -0,0 +1,4 @@ +gsl-lite==0.34.0 +pugixml==1.8 +xtensor==0.20.8 +xtl==0.6.5 diff --git a/vendor/xtensor/CMakeLists.txt b/vendor/xtensor/CMakeLists.txt index d4d3b355d..ce5fe9e6a 100644 --- a/vendor/xtensor/CMakeLists.txt +++ b/vendor/xtensor/CMakeLists.txt @@ -1,5 +1,6 @@ ############################################################################ -# Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht # +# Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht # +# Copyright (c) QuantStack # # # # Distributed under the terms of the BSD 3-Clause License. # # # @@ -28,16 +29,71 @@ message(STATUS "Building xtensor v${${PROJECT_NAME}_VERSION}") # Dependencies # ============ -#find_package(xtl 0.4.9 REQUIRED) +set(xtl_REQUIRED_VERSION 0.6.7) +find_package(xtl ${xtl_REQUIRED_VERSION} REQUIRED) +message(STATUS "Found xtl: ${xtl_INCLUDE_DIRS}/xtl") -#message(STATUS "Found xtl: ${xtl_INCLUDE_DIRS}/xtl") +find_package(nlohmann_json 3.1.1 QUIET) -#find_package(nlohmann_json 3.1.1) +# Optional dependencies +# ===================== + +OPTION(XTENSOR_USE_XSIMD "simd acceleration for xtensor" OFF) +OPTION(XTENSOR_USE_TBB "enable parallelization using intel TBB" OFF) +OPTION(XTENSOR_USE_OPENMP "enable parallelization using OpenMP" OFF) +if(XTENSOR_USE_TBB AND XTENSOR_USE_OPENMP) + message( + FATAL + "XTENSOR_USE_TBB and XTENSOR_USE_OPENMP cannot both be active at once" + ) +endif() + +if(XTENSOR_USE_XSIMD) + set(xsimd_REQUIRED_VERSION 7.4.0) + find_package(xsimd ${xsimd_REQUIRED_VERSION} REQUIRED) + message(STATUS "Found xsimd: ${xsimd_INCLUDE_DIRS}/xsimd") +endif() + +if(XTENSOR_USE_TBB) + set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH}" "${CMAKE_CURRENT_SOURCE_DIR}/cmake/") + find_package(TBB REQUIRED) + message(STATUS "Found intel TBB: ${TBB_INCLUDE_DIRS}") +endif() + +if(XTENSOR_USE_OPENMP) + find_package(OpenMP REQUIRED) + if (OPENMP_FOUND) + # Set openmp variables now + + # Create private target just for this lib + # https://cliutils.gitlab.io/modern-cmake/chapters/packages/OpenMP.html + # Probably not safe for cmake < 3.4 .. + find_package(Threads REQUIRED) + add_library(OpenMP::OpenMP_CXX_xtensor IMPORTED INTERFACE) + set_property( + TARGET + OpenMP::OpenMP_CXX_xtensor + PROPERTY + INTERFACE_COMPILE_OPTIONS ${OpenMP_CXX_FLAGS} + ) + # Only works if the same flag is passed to the linker; use CMake 3.9+ otherwise (Intel, AppleClang) + set_property( + TARGET + OpenMP::OpenMP_CXX_xtensor + PROPERTY + INTERFACE_LINK_LIBRARIES ${OpenMP_CXX_FLAGS} Threads::Threads) + + message(STATUS "OpenMP Found") + else() + message(FATAL "Failed to locate OpenMP") + endif() +endif() # Build # ===== set(XTENSOR_HEADERS + ${XTENSOR_INCLUDE_DIR}/xtensor/xaccessible.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xaccumulator.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xadapt.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xarray.hpp @@ -47,16 +103,19 @@ set(XTENSOR_HEADERS ${XTENSOR_INCLUDE_DIR}/xtensor/xbuffer_adaptor.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xbuilder.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xcomplex.hpp - ${XTENSOR_INCLUDE_DIR}/xtensor/xconcepts.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xcontainer.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xcsv.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xdynamic_view.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xeval.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xexception.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xexpression.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xexpression_holder.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xexpression_traits.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xfixed.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xfunction.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xfunctor_view.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xgenerator.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xhistogram.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xindex_view.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xinfo.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xio.hpp @@ -64,7 +123,10 @@ set(XTENSOR_HEADERS ${XTENSOR_INCLUDE_DIR}/xtensor/xiterator.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xjson.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xlayout.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xmanipulation.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xmasked_view.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xmath.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xmime.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xnoalias.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xnorm.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xnpy.hpp @@ -74,6 +136,7 @@ set(XTENSOR_HEADERS ${XTENSOR_INCLUDE_DIR}/xtensor/xoptional_assembly.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xoptional_assembly_base.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xoptional_assembly_storage.hpp + ${XTENSOR_INCLUDE_DIR}/xtensor/xpad.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xrandom.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xreducer.hpp ${XTENSOR_INCLUDE_DIR}/xtensor/xscalar.hpp @@ -102,13 +165,13 @@ target_link_libraries(xtensor INTERFACE xtl) OPTION(XTENSOR_ENABLE_ASSERT "xtensor bound check" OFF) OPTION(XTENSOR_CHECK_DIMENSION "xtensor dimension check" OFF) -OPTION(XTENSOR_USE_XSIMD "simd acceleration for xtensor" OFF) OPTION(BUILD_TESTS "xtensor test suite" OFF) OPTION(BUILD_BENCHMARK "xtensor benchmark" OFF) OPTION(DOWNLOAD_GTEST "build gtest from downloaded sources" OFF) OPTION(DOWNLOAD_GBENCHMARK "download google benchmark and build from source" ON) OPTION(DEFAULT_COLUMN_MAJOR "set default layout to column major" OFF) OPTION(DISABLE_VS2017 "disables the compilation of some test with Visual Studio 2017" OFF) +OPTION(CPP17 "enables C++17" OFF) if(DOWNLOAD_GTEST OR GTEST_SRC_DIR) set(BUILD_TESTS ON) @@ -122,13 +185,6 @@ if(XTENSOR_CHECK_DIMENSION) add_definitions(-DXTENSOR_ENABLE_CHECK_DIMENSION) endif() -if(XTENSOR_USE_XSIMD) - add_definitions(-DXTENSOR_USE_XSIMD) - find_package(xsimd 4.1.6 REQUIRED) - message(STATUS "Found xsimd: ${xsimd_INCLUDE_DIRS}/xsimd") - target_link_libraries(xtensor INTERFACE xsimd) -endif() - if(DEFAULT_COLUMN_MAJOR) add_definitions(-DXTENSOR_DEFAULT_LAYOUT=layout_type::column_major) endif() @@ -145,6 +201,11 @@ if(BUILD_BENCHMARK) add_subdirectory(benchmark) endif() +if(XTENSOR_USE_OPENMP) + # Link xtensor itself to OpenMP to propagate to user projects + target_link_libraries(xtensor INTERFACE OpenMP::OpenMP_CXX_xtensor) +endif() + # Installation # ============ diff --git a/vendor/xtensor/include/xtensor/xaccessible.hpp b/vendor/xtensor/include/xtensor/xaccessible.hpp new file mode 100644 index 000000000..8d8c6b3b2 --- /dev/null +++ b/vendor/xtensor/include/xtensor/xaccessible.hpp @@ -0,0 +1,307 @@ +/*************************************************************************** +* Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) QuantStack * +* * +* Distributed under the terms of the BSD 3-Clause License. * +* * +* The full license is in the file LICENSE, distributed with this software. * +****************************************************************************/ + +#ifndef XTENSOR_ACCESSIBLE_HPP +#define XTENSOR_ACCESSIBLE_HPP + +#include "xexception.hpp" +#include "xstrides.hpp" +#include "xtensor_forward.hpp" + +namespace xt +{ + /** + * @class xconst_accessible + * @brief Base class for implementation of common expression constant access methods. + * + * The xaccessible class implements constant access methods common to all expressions. + * + * @tparam D The derived type, i.e. the inheriting class for which xconst_accessible + * + * + */ + template + class xconst_accessible + { + public: + + using derived_type = D; + using inner_types = xcontainer_inner_types; + using reference = typename inner_types::reference; + using const_reference = typename inner_types::const_reference; + using size_type = typename inner_types::size_type; + + size_type size() const noexcept; + size_type dimension() const noexcept; + size_type shape(size_type index) const; + + template + const_reference at(Args... args) const; + + template + disable_integral_t operator[](const S& index) const; + template + const_reference operator[](std::initializer_list index) const; + const_reference operator[](size_type i) const; + + template + const_reference periodic(Args... args) const; + + template + bool in_bounds(Args... args) const; + + protected: + + xconst_accessible() = default; + ~xconst_accessible() = default; + + xconst_accessible(const xconst_accessible&) = default; + xconst_accessible& operator=(const xconst_accessible&) = default; + + xconst_accessible(xconst_accessible&&) = default; + xconst_accessible& operator=(xconst_accessible&&) = default; + + private: + + const derived_type& derived_cast() const noexcept; + }; + + /** + * @class xaccessible + * @brief Base class for implementation of common expression access methods. + * + * The xaccessible class implements access methods common to all expressions. + * + * @tparam D The derived type, i.e. the inheriting class for which xaccessible + * provides the interface. + */ + template + class xaccessible : public xconst_accessible + { + public: + + using base_type = xconst_accessible; + using derived_type = typename base_type::derived_type; + using reference = typename base_type::reference; + using size_type = typename base_type::size_type; + + template + reference at(Args... args); + + template + disable_integral_t operator[](const S& index); + template + reference operator[](std::initializer_list index); + reference operator[](size_type i); + + template + reference periodic(Args... args); + + using base_type::at; + using base_type::operator[]; + using base_type::periodic; + + protected: + + xaccessible() = default; + ~xaccessible() = default; + + xaccessible(const xaccessible&) = default; + xaccessible& operator=(const xaccessible&) = default; + + xaccessible(xaccessible&&) = default; + xaccessible& operator=(xaccessible&&) = default; + + private: + + derived_type& derived_cast() noexcept; + }; + + /************************************ + * xconst_accessible implementation * + ************************************/ + + /** + * Returns the size of the expression. + */ + template + inline auto xconst_accessible::size() const noexcept -> size_type + { + return compute_size(derived_cast().shape()); + } + + /** + * Returns the number of dimensions of the expression. + */ + template + inline auto xconst_accessible::dimension() const noexcept -> size_type + { + return derived_cast().shape().size(); + } + + /** + * Returns the i-th dimension of the expression. + */ + template + inline auto xconst_accessible::shape(size_type index) const -> size_type + { + return derived_cast().shape()[index]; + } + + /** + * Returns a constant reference to the element at the specified position in the expression, + * after dimension and bounds checking. + * @param args a list of indices specifying the position in the expression. Indices + * must be unsigned integers, the number of indices should be equal to the number of dimensions + * of the expression. + * @exception std::out_of_range if the number of argument is greater than the number of dimensions + * or if indices are out of bounds. + */ + template + template + inline auto xconst_accessible::at(Args... args) const -> const_reference + { + check_access(derived_cast().shape(), static_cast(args)...); + return derived_cast().operator()(args...); + } + + /** + * Returns a constant reference to the element at the specified position in the expression. + * @param index a sequence of indices specifying the position in the expression. Indices + * must be unsigned integers, the number of indices in the list should be equal or greater + * than the number of dimensions of the expression. + */ + template + template + inline auto xconst_accessible::operator[](const S& index) const + -> disable_integral_t + { + return derived_cast().element(index.cbegin(), index.cend()); + } + + template + template + inline auto xconst_accessible::operator[](std::initializer_list index) const -> const_reference + { + return derived_cast().element(index.begin(), index.end()); + } + + template + inline auto xconst_accessible::operator[](size_type i) const -> const_reference + { + return derived_cast().operator()(i); + } + + /** + * Returns a constant reference to the element at the specified position in the expression, + * after applying periodicity to the indices (negative and 'overflowing' indices are changed). + * @param args a list of indices specifying the position in the expression. Indices + * must be integers, the number of indices should be equal to the number of dimensions + * of the expression. + */ + template + template + inline auto xconst_accessible::periodic(Args... args) const -> const_reference + { + normalize_periodic(derived_cast().shape(), args...); + return derived_cast()(static_cast(args)...); + } + + /** + * Returns ``true`` only if the the specified position is a valid entry in the expression. + * @param args a list of indices specifying the position in the expression. + * @return bool + */ + template + template + inline bool xconst_accessible::in_bounds(Args... args) const + { + return check_in_bounds(derived_cast().shape(), args...); + } + + template + inline auto xconst_accessible::derived_cast() const noexcept -> const derived_type& + { + return *static_cast(this); + } + + /****************************** + * xaccessible implementation * + ******************************/ + + /** + * Returns a reference to the element at the specified position in the expression, + * after dimension and bounds checking. + * @param args a list of indices specifying the position in the expression. Indices + * must be unsigned integers, the number of indices should be equal to the number of dimensions + * of the expression. + * @exception std::out_of_range if the number of argument is greater than the number of dimensions + * or if indices are out of bounds. + */ + template + template + inline auto xaccessible::at(Args... args) -> reference + { + check_access(derived_cast().shape(), static_cast(args)...); + return derived_cast().operator()(args...); + } + + /** + * Returns a reference to the element at the specified position in the expression. + * @param index a sequence of indices specifying the position in the expression. Indices + * must be unsigned integers, the number of indices in the list should be equal or greater + * than the number of dimensions of the expression. + */ + template + template + inline auto xaccessible::operator[](const S& index) + -> disable_integral_t + { + return derived_cast().element(index.cbegin(), index.cend()); + } + + template + template + inline auto xaccessible::operator[](std::initializer_list index) -> reference + { + return derived_cast().element(index.begin(), index.end()); + } + + template + inline auto xaccessible::operator[](size_type i) -> reference + { + return derived_cast().operator()(i); + } + + /** + * Returns a reference to the element at the specified position in the expression, + * after applying periodicity to the indices (negative and 'overflowing' indices are changed). + * @param args a list of indices specifying the position in the expression. Indices + * must be integers, the number of indices should be equal to the number of dimensions + * of the expression. + */ + template + template + inline auto xaccessible::periodic(Args... args) -> reference + { + normalize_periodic(derived_cast().shape(), args...); + return derived_cast()(static_cast(args)...); + } + + + template + inline auto xaccessible::derived_cast() noexcept -> derived_type& + { + return *static_cast(this); + } + +} + +#endif + diff --git a/vendor/xtensor/include/xtensor/xaccumulator.hpp b/vendor/xtensor/include/xtensor/xaccumulator.hpp index f2b446ff3..7bba8a5ae 100644 --- a/vendor/xtensor/include/xtensor/xaccumulator.hpp +++ b/vendor/xtensor/include/xtensor/xaccumulator.hpp @@ -1,5 +1,6 @@ /*************************************************************************** -* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * @@ -21,7 +22,7 @@ namespace xt { -#define DEFAULT_STRATEGY_ACCUMULATORS evaluation_strategy::immediate +#define DEFAULT_STRATEGY_ACCUMULATORS evaluation_strategy::immediate_type /************** * accumulate * @@ -73,13 +74,13 @@ namespace xt template xarray::value_type> accumulator_impl(F&&, E&&, std::size_t, EVS) { - static_assert(!std::is_same::value, "Lazy accumulators not yet implemented."); + static_assert(!std::is_same::value, "Lazy accumulators not yet implemented."); } template xarray::value_type> accumulator_impl(F&&, E&&, EVS) { - static_assert(!std::is_same::value, "Lazy accumulators not yet implemented."); + static_assert(!std::is_same::value, "Lazy accumulators not yet implemented."); } template @@ -88,15 +89,57 @@ namespace xt using type = xarray; }; - template - struct xaccumulator_return_type, R> + template + struct xaccumulator_return_type, R> { - using type = xtensor; + using type = xarray; + }; + + template + struct xaccumulator_return_type, R> + { + using type = xtensor; + }; + + template + struct xaccumulator_return_type, L>, R> + { + using type = xtensor_fixed, L>; }; template using xaccumulator_return_type_t = typename xaccumulator_return_type::type; + template + struct fixed_compute_size; + + template + struct xaccumulator_linear_return_type + { + using type = xtensor; + }; + + template + struct xaccumulator_linear_return_type, R> + { + using type = xtensor; + }; + + template + struct xaccumulator_linear_return_type, R> + { + using type = xtensor; + }; + + template + struct xaccumulator_linear_return_type, L>, R> + { + using type = xtensor_fixed>::value>, L>; + }; + + template + using xaccumulator_linear_return_type_t = typename xaccumulator_linear_return_type::type; + template inline auto accumulator_init_with_f(F&& f, E& e, std::size_t axis) { @@ -104,7 +147,8 @@ namespace xt // e[:, 0, :, :, ...] = f(e[:, 0, :, :, ...]) // so that all "first" values are initialized in a first pass - std::size_t outer_loop_size, inner_loop_size, outer_stride, inner_stride, pos = 0; + std::size_t outer_loop_size, inner_loop_size, pos = 0; + std::size_t outer_stride, inner_stride; auto set_loop_sizes = [&outer_loop_size, &inner_loop_size](auto first, auto last, std::ptrdiff_t ax) { outer_loop_size = std::accumulate(first, first + ax, @@ -113,9 +157,10 @@ namespace xt std::size_t(1), std::multiplies()); }; + // Note: add check that strides > 0 auto set_loop_strides = [&outer_stride, &inner_stride](auto first, auto last, std::ptrdiff_t ax) { - outer_stride = ax == 0 ? 1 : *std::min_element(first, first + ax); - inner_stride = (ax == std::distance(first, last) - 1) ? 1 : *std::min_element(first + ax + 1, last); + outer_stride = static_cast(ax == 0 ? 1 : *std::min_element(first, first + ax)); + inner_stride = static_cast((ax == std::distance(first, last) - 1) ? 1 : *std::min_element(first + ax + 1, last)); }; set_loop_sizes(e.shape().begin(), e.shape().end(), static_cast(axis)); @@ -140,9 +185,9 @@ namespace xt } template - inline auto accumulator_impl(F&& f, E&& e, std::size_t axis, evaluation_strategy::immediate) + inline auto accumulator_impl(F&& f, E&& e, std::size_t axis, evaluation_strategy::immediate_type) { - using accumulate_functor = std::decay_t(f))>; + using accumulate_functor = std::decay_t(f))>; using function_return_type = typename accumulate_functor::result_type; using result_type = xaccumulator_return_type_t, function_return_type>; @@ -153,74 +198,80 @@ namespace xt result_type result = e; // assign + make a copy, we need it anyways - std::size_t inner_stride = result.strides()[axis]; - std::size_t outer_stride = 1; // this is either going row- or column-wise (strides.back / strides.front) - std::size_t outer_loop_size = 0; - std::size_t inner_loop_size = 0; - - auto set_loop_sizes = [&outer_loop_size, &inner_loop_size](auto first, auto last, std::ptrdiff_t ax) { - outer_loop_size = std::accumulate(first, - first + ax, - std::size_t(1), std::multiplies()); - - inner_loop_size = std::accumulate(first + ax, - last, - std::size_t(1), std::multiplies()); - }; - - if (result_type::static_layout == layout_type::row_major) + if(result.shape(axis) != std::size_t(0)) { - set_loop_sizes(result.shape().cbegin(), result.shape().cend(), static_cast(axis)); - } - else - { - set_loop_sizes(result.shape().cbegin(), result.shape().cend(), static_cast(axis + 1)); - std::swap(inner_loop_size, outer_loop_size); - } + std::size_t inner_stride = static_cast(result.strides()[axis]); + std::size_t outer_stride = 1; // this is either going row- or column-wise (strides.back / strides.front) + std::size_t outer_loop_size = 0; + std::size_t inner_loop_size = 0; + std::size_t init_size = e.shape()[axis] != std::size_t(1) ? std::size_t(1) : std::size_t(0); - std::size_t pos = 0; + auto set_loop_sizes = [&outer_loop_size, &inner_loop_size, init_size](auto first, auto last, std::ptrdiff_t ax) { + outer_loop_size = std::accumulate(first, + first + ax, + init_size, std::multiplies()); - inner_loop_size = inner_loop_size - inner_stride; + inner_loop_size = std::accumulate(first + ax, + last, + std::size_t(1), std::multiplies()); + }; - // activate the init loop if we have an init function other than identity - if (!std::is_same(f)), xtl::identity>::value) - { - accumulator_init_with_f(std::get<1>(f), result, axis); - } - - pos = 0; - for (std::size_t i = 0; i < outer_loop_size; ++i) - { - for (std::size_t j = 0; j < inner_loop_size; ++j) + if (result_type::static_layout == layout_type::row_major) { - result.storage()[pos + inner_stride] = std::get<0>(f)(result.storage()[pos], - result.storage()[pos + inner_stride]); - pos += outer_stride; + set_loop_sizes(result.shape().cbegin(), result.shape().cend(), static_cast(axis)); + } + else + { + set_loop_sizes(result.shape().cbegin(), result.shape().cend(), static_cast(axis + 1)); + std::swap(inner_loop_size, outer_loop_size); + } + + std::size_t pos = 0; + + inner_loop_size = inner_loop_size - inner_stride; + + // activate the init loop if we have an init function other than identity + if (!std::is_same(f))>, xtl::identity>::value) + { + accumulator_init_with_f(xt::get<1>(f), result, axis); + } + + pos = 0; + for (std::size_t i = 0; i < outer_loop_size; ++i) + { + for (std::size_t j = 0; j < inner_loop_size; ++j) + { + result.storage()[pos + inner_stride] = xt::get<0>(f)(result.storage()[pos], + result.storage()[pos + inner_stride]); + pos += outer_stride; + } + pos += inner_stride; } - pos += inner_stride; } return result; } template - inline auto accumulator_impl(F&& f, E&& e, evaluation_strategy::immediate) + inline auto accumulator_impl(F&& f, E&& e, evaluation_strategy::immediate_type) { - using accumulate_functor = std::decay_t(f))>; + using accumulate_functor = std::decay_t(f))>; using T = typename accumulate_functor::result_type; - using result_type = xtensor; + using result_type = xaccumulator_linear_return_type_t, T>; std::size_t sz = e.size(); auto result = result_type::from_shape({sz}); - auto it = e.template begin(); - - result.storage()[0] = std::get<1>(f)(*it); - ++it; - - for (std::size_t idx = 0; it != e.template end(); ++it) + if(sz != std::size_t(0)) { - result.storage()[idx + 1] = std::get<0>(f)(result.storage()[idx], *it); - ++idx; + auto it = e.template begin(); + result.storage()[0] = xt::get<1>(f)(*it); + ++it; + + for (std::size_t idx = 0; it != e.template end(); ++it) + { + result.storage()[idx + 1] = xt::get<0>(f)(result.storage()[idx], *it); + ++idx; + } } return result; } @@ -237,7 +288,7 @@ namespace xt * @return returns xarray filled with accumulated values */ template ::value, int> = 0> + XTL_REQUIRES(is_evaluation_strategy)> inline auto accumulate(F&& f, E&& e, EVS evaluation_strategy = EVS()) { // Note we need to check is_integral above in order to prohibit EVS = int, and not taking the std::size_t @@ -257,9 +308,10 @@ namespace xt * @return returns xarray filled with accumulated values */ template - inline auto accumulate(F&& f, E&& e, std::size_t axis, EVS evaluation_strategy = EVS()) + inline auto accumulate(F&& f, E&& e, std::ptrdiff_t axis, EVS evaluation_strategy = EVS()) { - return detail::accumulator_impl(std::forward(f), std::forward(e), axis, evaluation_strategy); + std::size_t ax = normalize_axis(e.dimension(), axis); + return detail::accumulator_impl(std::forward(f), std::forward(e), ax, evaluation_strategy); } } diff --git a/vendor/xtensor/include/xtensor/xadapt.hpp b/vendor/xtensor/include/xtensor/xadapt.hpp index b080bd0b7..5dac517a2 100644 --- a/vendor/xtensor/include/xtensor/xadapt.hpp +++ b/vendor/xtensor/include/xtensor/xadapt.hpp @@ -1,5 +1,6 @@ /*************************************************************************** -* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * @@ -18,6 +19,8 @@ #include "xarray.hpp" #include "xtensor.hpp" +#include "xfixed.hpp" +#include "xbuffer_adaptor.hpp" namespace xt { @@ -34,6 +37,24 @@ namespace xt template using array_size = array_size_impl>; + + template + struct default_allocator_for_ptr + { + using type = std::allocator>>>; + }; + + template + using default_allocator_for_ptr_t = typename default_allocator_for_ptr

::type; + + template + using not_an_array = xtl::negation>; + + template + using not_a_pointer = xtl::negation>; + + template + using not_a_layout = xtl::negation>; } /************************** @@ -48,9 +69,31 @@ namespace xt * @param l the layout_type of the xarray_adaptor */ template >::value, int> = 0> - xarray_adaptor, L, std::decay_t> - adapt(C&& container, const SC& shape, layout_type l = L); + XTL_REQUIRES(detail::not_an_array>, + detail::not_a_pointer)> + inline xarray_adaptor, L, std::decay_t> + adapt(C&& container, const SC& shape, layout_type l = L) + { + using return_type = xarray_adaptor, L, std::decay_t>; + return return_type(std::forward(container), shape, l); + } + + /** + * Constructs an non-owning xarray_adaptor from a pointer with the specified shape and layout. + * @param pointer the container to adapt + * @param shape the shape of the xarray_adaptor + * @param l the layout_type of the xarray_adaptor + */ + template >, + std::is_pointer)> + inline auto adapt(C&& pointer, const SC& shape, layout_type l = L) + { + using buffer_type = xbuffer_adaptor>; + using return_type = xarray_adaptor>; + std::size_t size = compute_size(shape); + return return_type(buffer_type(pointer, size), shape, l); + } /** * Constructs an xarray_adaptor of the given stl-like container, @@ -60,10 +103,16 @@ namespace xt * @param strides the strides of the xarray_adaptor */ template >::value, int> = 0, - typename std::enable_if_t>::value, int> = 0> - xarray_adaptor, layout_type::dynamic, std::decay_t> - adapt(C&& container, SC&& shape, SS&& strides); + XTL_REQUIRES(detail::not_an_array>, + detail::not_a_layout>)> + inline xarray_adaptor, layout_type::dynamic, std::decay_t> + adapt(C&& container, SC&& shape, SS&& strides) + { + using return_type = xarray_adaptor, layout_type::dynamic, std::decay_t>; + return return_type(std::forward(container), + xtl::forward_sequence(shape), + xtl::forward_sequence(strides)); + } /** * Constructs an xarray_adaptor of the given dynamically allocated C array, @@ -71,32 +120,79 @@ namespace xt * @param pointer the pointer to the beginning of the dynamic array * @param size the size of the dynamic array * @param ownership indicates whether the adaptor takes ownership of the array. - * Possible values are ``no_ownerhsip()`` or ``acquire_ownership()`` + * Possible values are ``no_ownership()`` or ``acquire_ownership()`` * @param shape the shape of the xarray_adaptor * @param l the layout_type of the xarray_adaptor * @param alloc the allocator used for allocating / deallocating the dynamic array */ - template >>>, - typename std::enable_if_t>::value, int> = 0> - xarray_adaptor, O, A>, L, SC> - adapt(P&& pointer, typename A::size_type size, O ownership, const SC& shape, layout_type l = L, const A& alloc = A()); + template , + XTL_REQUIRES(detail::not_an_array>)> + inline xarray_adaptor, O, A>, L, SC> + adapt(P&& pointer, typename A::size_type size, O ownership, const SC& shape, layout_type l = L, const A& alloc = A()) + { + (void)ownership; + using buffer_type = xbuffer_adaptor, O, A>; + using return_type = xarray_adaptor; + buffer_type buf(std::forward

(pointer), size, alloc); + return return_type(std::move(buf), shape, l); + } /** * Constructs an xarray_adaptor of the given dynamically allocated C array, - * with the specified shape and layout. + * with the specified shape and strides. * @param pointer the pointer to the beginning of the dynamic array * @param size the size of the dynamic array * @param ownership indicates whether the adaptor takes ownership of the array. - * Possible values are ``no_ownerhsip()`` or ``acquire_ownership()`` + * Possible values are ``no_ownership()`` or ``acquire_ownership()`` * @param shape the shape of the xarray_adaptor * @param strides the strides of the xarray_adaptor * @param alloc the allocator used for allocating / deallocating the dynamic array */ - template >>>, - typename std::enable_if_t>::value, int> = 0, - typename std::enable_if_t>::value, int> = 0> - xarray_adaptor, O, A>, layout_type::dynamic, std::decay_t> - adapt(P&& pointer, typename A::size_type size, O ownership, SC&& shape, SS&& strides, const A& alloc = A()); + template , + XTL_REQUIRES(detail::not_an_array>, + detail::not_a_layout>)> + inline xarray_adaptor, O, A>, layout_type::dynamic, std::decay_t> + adapt(P&& pointer, typename A::size_type size, O ownership, SC&& shape, SS&& strides, const A& alloc = A()) + { + (void)ownership; + using buffer_type = xbuffer_adaptor, O, A>; + using return_type = xarray_adaptor>; + buffer_type buf(std::forward

(pointer), size, alloc); + return return_type(std::move(buf), + xtl::forward_sequence(shape), + xtl::forward_sequence(strides)); + } + + /** + * Contructs an xarray_adaptor of the given C array allocated on the stack, with the + * specified shape and layout. + * @param c_array the C array allocated on the stack + * @param shape the shape of the xarray_adaptor + * @param l the layout_type of the xarray_adaptor + */ + template >)> + inline auto adapt(T (&c_array)[N], const SC& shape, layout_type l = L) + { + return adapt(&c_array[0], N, xt::no_ownership(), shape, l); + } + + /** + * Contructs an xarray_adaptor of the given C array allocated on the stack, with the + * specified shape and stirdes. + * @param c_array the C array allocated on the stack + * @param shape the shape of the xarray_adaptor + * @param strides the strides of the xarray_adaptor + */ + template >, + detail::not_a_layout>)> + inline auto adapt(T (&c_array)[N], SC&& shape, SS&& strides) + { + return adapt(&c_array[0], N, xt::no_ownership(), + std::forward(shape), + std::forward(strides)); + } /*************************** * xtensor_adaptor builder * @@ -109,8 +205,13 @@ namespace xt * @param l the layout_type of the xtensor_adaptor */ template - xtensor_adaptor - adapt(C&& container, layout_type l = L); + inline xtensor_adaptor + adapt(C&& container, layout_type l = L) + { + const std::array::size_type, 1> shape{container.size()}; + using return_type = xtensor_adaptor, 1, L>; + return return_type(std::forward(container), shape, l); + } /** * Constructs an xtensor_adaptor of the given stl-like container, @@ -120,9 +221,32 @@ namespace xt * @param l the layout_type of the xtensor_adaptor */ template >::value, int> = 0> - xtensor_adaptor::value, L> - adapt(C&& container, const SC& shape, layout_type l = L); + XTL_REQUIRES(detail::is_array>, + detail::not_a_pointer)> + inline xtensor_adaptor::value, L> + adapt(C&& container, const SC& shape, layout_type l = L) + { + constexpr std::size_t N = detail::array_size::value; + using return_type = xtensor_adaptor, N, L>; + return return_type(std::forward(container), shape, l); + } + + /** + * Constructs an non-owning xtensor_adaptor from a pointer with the specified shape and layout. + * @param pointer the pointer to adapt + * @param shape the shape of the xtensor_adaptor + * @param l the layout_type of the xtensor_adaptor + */ + template >, + std::is_pointer)> + inline auto adapt(C&& pointer, const SC& shape, layout_type l = L) + { + using buffer_type = xbuffer_adaptor>; + constexpr std::size_t N = detail::array_size::value; + using return_type = xtensor_adaptor; + return return_type(buffer_type(pointer, compute_size(shape)), shape, l); + } /** * Constructs an xtensor_adaptor of the given stl-like container, @@ -132,10 +256,17 @@ namespace xt * @param strides the strides of the xtensor_adaptor */ template >::value, int> = 0, - typename std::enable_if_t>::value, int> = 0> - xtensor_adaptor::value, layout_type::dynamic> - adapt(C&& container, SC&& shape, SS&& strides); + XTL_REQUIRES(detail::is_array>, + detail::not_a_layout>)> + inline xtensor_adaptor::value, layout_type::dynamic> + adapt(C&& container, SC&& shape, SS&& strides) + { + constexpr std::size_t N = detail::array_size::value; + using return_type = xtensor_adaptor, N, layout_type::dynamic>; + return return_type(std::forward(container), + xtl::forward_sequence(shape), + xtl::forward_sequence(strides)); + } /** * Constructs a 1-D xtensor_adaptor of the given dynamically allocated C array, @@ -143,145 +274,15 @@ namespace xt * @param pointer the pointer to the beginning of the dynamic array * @param size the size of the dynamic array * @param ownership indicates whether the adaptor takes ownership of the array. - * Possible values are ``no_ownerhsip()`` or ``acquire_ownership()`` + * Possible values are ``no_ownership()`` or ``acquire_ownership()`` * @param l the layout_type of the xtensor_adaptor * @param alloc the allocator used for allocating / deallocating the dynamic array */ - template >>>> - xtensor_adaptor, O, A>, 1, L> - adapt(P&& pointer, typename A::size_type size, O ownership, layout_type l = L, const A& alloc = A()); - - /** - * Constructs an xtensor_adaptor of the given dynamically allocated C array, - * with the specified shape and layout. - * @param pointer the pointer to the beginning of the dynamic array - * @param size the size of the dynamic array - * @param ownership indicates whether the adaptor takes ownership of the array. - * Possible values are ``no_ownerhsip()`` or ``acquire_ownership()`` - * @param shape the shape of the xtensor_adaptor - * @param l the layout_type of the xtensor_adaptor - * @param alloc the allocator used for allocating / deallocating the dynamic array - */ - template >>>, - typename std::enable_if_t>::value, int> = 0> - xtensor_adaptor, O, A>, detail::array_size::value, L> - adapt(P&& pointer, typename A::size_type size, O ownership, const SC& shape, layout_type l = L, const A& alloc = A()); - - /** - * Constructs an xtensor_adaptor of the given dynamically allocated C array, - * with the specified shape and strides. - * @param pointer the pointer to the beginning of the dynamic array - * @param size the size of the dynamic array - * @param ownership indicates whether the adaptor takes ownership of the array. - * Possible values are ``no_ownerhsip()`` or ``acquire_ownership()`` - * @param shape the shape of the xtensor_adaptor - * @param strides the strides of the xtensor_adaptor - * @param alloc the allocator used for allocating / deallocating the dynamic array - */ - template >>>, - typename std::enable_if_t>::value, int> = 0, - typename std::enable_if_t>::value, int> = 0> - xtensor_adaptor, O, A>, detail::array_size::value, layout_type::dynamic> - adapt(P&& pointer, typename A::size_type size, O ownership, SC&& shape, SS&& strides, const A& alloc = A()); - - /***************************************** - * xarray_adaptor builder implementation * - *****************************************/ - - // shape only - container version - template >::value, int>> - inline xarray_adaptor, L, std::decay_t> - adapt(C&& container, const SC& shape, layout_type l) - { - using return_type = xarray_adaptor, L, std::decay_t>; - return return_type(std::forward(container), shape, l); - } - - // shape and strides - container version - template >::value, int>, - typename std::enable_if_t>::value, int>> - inline xarray_adaptor, layout_type::dynamic, std::decay_t> - adapt(C&& container, SC&& shape, SS&& strides) - { - using return_type = xarray_adaptor, layout_type::dynamic, std::decay_t>; - return return_type(std::forward(container), - xtl::forward_sequence(shape), - xtl::forward_sequence(strides)); - } - - // shape only - buffer version - template >::value, int>> - inline xarray_adaptor, O, A>, L, SC> - adapt(P&& pointer, typename A::size_type size, O, const SC& shape, layout_type l, const A& alloc) - { - using buffer_type = xbuffer_adaptor, O, A>; - using return_type = xarray_adaptor; - buffer_type buf(std::forward

(pointer), size, alloc); - return return_type(std::move(buf), shape, l); - } - - // shape and strides - buffer version - template >::value, int>, - typename std::enable_if_t>::value, int>> - inline xarray_adaptor, O, A>, layout_type::dynamic, std::decay_t> - adapt(P&& pointer, typename A::size_type size, O, SC&& shape, SS&& strides, const A& alloc) - { - using buffer_type = xbuffer_adaptor, O, A>; - using return_type = xarray_adaptor>; - buffer_type buf(std::forward

(pointer), size, alloc); - return return_type(std::move(buf), - xtl::forward_sequence(shape), - xtl::forward_sequence(strides)); - } - - /****************************************** - * xtensor_adaptor builder implementation * - ******************************************/ - - // 1-D case - container version - template - inline xtensor_adaptor - adapt(C&& container, layout_type l) - { - const std::array::size_type, 1> shape{container.size()}; - using return_type = xtensor_adaptor, 1, L>; - return return_type(std::forward(container), shape, l); - } - - // shape only - container version - template >::value, int>> - inline xtensor_adaptor::value, L> - adapt(C&& container, const SC& shape, layout_type l) - { - constexpr std::size_t N = detail::array_size::value; - using return_type = xtensor_adaptor, N, L>; - return return_type(std::forward(container), shape, l); - } - - // shape and strides - container version - template >::value, int>, - typename std::enable_if_t>::value, int>> - inline xtensor_adaptor::value, layout_type::dynamic> - adapt(C&& container, SC&& shape, SS&& strides) - { - constexpr std::size_t N = detail::array_size::value; - using return_type = xtensor_adaptor, N, layout_type::dynamic>; - return return_type(std::forward(container), - xtl::forward_sequence(shape), - xtl::forward_sequence(strides)); - } - - // 1-D case - buffer version - template + template > inline xtensor_adaptor, O, A>, 1, L> - adapt(P&& pointer, typename A::size_type size, O, layout_type l, const A& alloc) + adapt(P&& pointer, typename A::size_type size, O ownership, layout_type l = L, const A& alloc = A()) { + (void)ownership; using buffer_type = xbuffer_adaptor, O, A>; using return_type = xtensor_adaptor; buffer_type buf(std::forward

(pointer), size, alloc); @@ -289,12 +290,23 @@ namespace xt return return_type(std::move(buf), shape, l); } - // shape only - buffer version - template >::value, int>> + /** + * Constructs an xtensor_adaptor of the given dynamically allocated C array, + * with the specified shape and layout. + * @param pointer the pointer to the beginning of the dynamic array + * @param size the size of the dynamic array + * @param ownership indicates whether the adaptor takes ownership of the array. + * Possible values are ``no_ownership()`` or ``acquire_ownership()`` + * @param shape the shape of the xtensor_adaptor + * @param l the layout_type of the xtensor_adaptor + * @param alloc the allocator used for allocating / deallocating the dynamic array + */ + template , + XTL_REQUIRES(detail::is_array>)> inline xtensor_adaptor, O, A>, detail::array_size::value, L> - adapt(P&& pointer, typename A::size_type size, O, const SC& shape, layout_type l, const A& alloc) + adapt(P&& pointer, typename A::size_type size, O ownership, const SC& shape, layout_type l = L, const A& alloc = A()) { + (void)ownership; using buffer_type = xbuffer_adaptor, O, A>; constexpr std::size_t N = detail::array_size::value; using return_type = xtensor_adaptor; @@ -302,21 +314,185 @@ namespace xt return return_type(std::move(buf), shape, l); } - // shape and strides - buffer version - template >::value, int>, - typename std::enable_if_t>::value, int>> + /** + * Constructs an xtensor_adaptor of the given dynamically allocated C array, + * with the specified shape and strides. + * @param pointer the pointer to the beginning of the dynamic array + * @param size the size of the dynamic array + * @param ownership indicates whether the adaptor takes ownership of the array. + * Possible values are ``no_ownership()`` or ``acquire_ownership()`` + * @param shape the shape of the xtensor_adaptor + * @param strides the strides of the xtensor_adaptor + * @param alloc the allocator used for allocating / deallocating the dynamic array + */ + template , + XTL_REQUIRES(detail::is_array>, + detail::not_a_layout>)> inline xtensor_adaptor, O, A>, detail::array_size::value, layout_type::dynamic> - adapt(P&& pointer, typename A::size_type size, O, SC&& shape, SS&& strides, const A& alloc) + adapt(P&& pointer, typename A::size_type size, O ownership, SC&& shape, SS&& strides, const A& alloc = A()) { + (void)ownership; using buffer_type = xbuffer_adaptor, O, A>; constexpr std::size_t N = detail::array_size::value; using return_type = xtensor_adaptor; buffer_type buf(std::forward

(pointer), size, alloc); return return_type(std::move(buf), - xtl::forward_sequence(shape), - xtl::forward_sequence(strides)); + xtl::forward_sequence(shape), + xtl::forward_sequence(strides)); } + + /** + * Contructs an xtensor_adaptor of the given C array allocated on the stack, with the + * specified shape and layout. + * @param c_array the C array allocated on the stack + * @param shape the shape of the xarray_adaptor + * @param l the layout_type of the xarray_adaptor + */ + template >)> + inline auto adapt(T (&c_array)[N], const SC& shape, layout_type l = L) + { + return adapt(&c_array[0], N, xt::no_ownership(), shape, l); + } + + /** + * Contructs an xtensor_adaptor of the given C array allocated on the stack, with the + * specified shape and stirdes. + * @param c_array the C array allocated on the stack + * @param shape the shape of the xarray_adaptor + * @param strides the strides of the xarray_adaptor + */ + template >, + detail::not_a_layout>)> + inline auto adapt(T (&c_array)[N], SC&& shape, SS&& strides) + { + return adapt(&c_array[0], N, xt::no_ownership(), + std::forward(shape), + std::forward(strides)); + } + /** + * Constructs an non-owning xtensor_fixed_adaptor from a pointer with the + * specified shape and layout. + * @param pointer the pointer to adapt + * @param shape the shape of the xtensor_fixed_adaptor + */ + template )> + inline auto adapt(C&& ptr, const fixed_shape& /*shape*/) + { + using buffer_type = xbuffer_adaptor>; + using return_type = xfixed_adaptor, L>; + return return_type(buffer_type(ptr, detail::fixed_compute_size>::value)); + } + +#ifndef X_OLD_CLANG + template + inline auto adapt(C&& ptr, const T(&shape)[N]) + { + using shape_type = std::array; + return adapt(std::forward(ptr), xtl::forward_sequence(shape)); + } +#else + template + inline auto adapt(C&& ptr, std::initializer_list shape) + { + using shape_type = xt::dynamic_shape; + return adapt(std::forward(ptr), xtl::forward_sequence(shape)); + } +#endif + +#ifndef X_OLD_CLANG + /** + * Adapt a smart pointer to a typed memory block (unique_ptr or shared_ptr) + * + * \code{.cpp} + * #include + * #include + * + * std::shared_ptr sptr(new double[8], std::default_delete()); + * sptr.get()[2] = 321.; + * auto xptr = adapt_smart_ptr(sptr, {4, 2}); + * xptr(1, 3) = 123.; + * std::cout << xptr; + * \endcode + * + * @param smart_ptr a smart pointer to a memory block of T[] + * @param shape The desired shape + * + * @return xtensor_adaptor for memory + */ + template + auto adapt_smart_ptr(P&& smart_ptr, const I(&shape)[N]) + { + using buffer_adaptor = xbuffer_adaptor>; + std::array fshape = xtl::forward_sequence, decltype(shape)>(shape); + return xtensor_adaptor( + buffer_adaptor(smart_ptr.get(), compute_size(fshape), + std::forward

(smart_ptr)), + std::move(fshape) + ); + } + + /** + * Adapt a smart pointer (shared_ptr or unique_ptr) + * + * This function allows to automatically adapt a shared or unique pointer to + * a given shape and operate naturally on it. Memory will be automatically + * handled by the smart pointer implementation. + * + * \code{.cpp} + * #include + * #include + * + * struct Buffer { + * Buffer(std::vector& buf) : m_buf(buf) {} + * ~Buffer() { std::cout << "deleted" << std::endl; } + * std::vector m_buf; + * }; + * + * auto data = std::vector{1,2,3,4,5,6,7,8}; + * auto shared_buf = std::make_shared(data); + * auto unique_buf = std::make_unique(data); + * + * std::cout << shared_buf.use_count() << std::endl; + * { + * auto obj = adapt_smart_ptr(shared_buf.get()->m_buf.data(), + * {2, 4}, shared_buf); + * // Use count increased to 2 + * std::cout << shared_buf.use_count() << std::endl; + * std::cout << obj << std::endl; + * } + * // Use count reset to 1 + * std::cout << shared_buf.use_count() << std::endl; + * + * { + * auto obj = adapt_smart_ptr(unique_buf.get()->m_buf.data(), + * {2, 4}, std::move(unique_buf)); + * std::cout << obj << std::endl; + * } + * \endcode + * + * @param data_ptr A pointer to a typed data block (e.g. double*) + * @param shape The desired shape + * @param smart_ptr A smart pointer to move or copy, in order to manage memory + * + * @return xtensor_adaptor on the memory + */ + template + auto adapt_smart_ptr(P&& data_ptr, const I(&shape)[N], D&& smart_ptr) + { + using buffer_adaptor = xbuffer_adaptor>; + std::array fshape = xtl::forward_sequence, decltype(shape)>(shape); + + return xtensor_adaptor( + buffer_adaptor(data_ptr, compute_size(fshape), std::forward(smart_ptr)), + std::move(fshape) + ); + } +#endif } #endif diff --git a/vendor/xtensor/include/xtensor/xarray.hpp b/vendor/xtensor/include/xtensor/xarray.hpp index 7c51f2812..69bdb474e 100644 --- a/vendor/xtensor/include/xtensor/xarray.hpp +++ b/vendor/xtensor/include/xtensor/xarray.hpp @@ -1,5 +1,6 @@ /*************************************************************************** -* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * @@ -26,13 +27,31 @@ namespace xt * xarray_container declaration * ********************************/ + namespace extension + { + template + struct xarray_container_base; + + template + struct xarray_container_base + { + using type = xtensor_empty_base; + }; + + template + using xarray_container_base_t = typename xarray_container_base::type; + } + template struct xcontainer_inner_types> { using storage_type = EC; + using reference = inner_reference_t; + using const_reference = typename storage_type::const_reference; + using size_type = typename storage_type::size_type; using shape_type = SC; - using strides_type = shape_type; - using backstrides_type = shape_type; + using strides_type = get_strides_t; + using backstrides_type = get_strides_t; using inner_shape_type = shape_type; using inner_strides_type = strides_type; using inner_backstrides_type = backstrides_type; @@ -57,17 +76,19 @@ namespace xt * @tparam L The layout_type of the container. * @tparam SC The type of the containers holding the shape and the strides. * @tparam Tag The expression tag. - * @sa xarray + * @sa xarray, xstrided_container, xcontainer */ template class xarray_container : public xstrided_container>, - public xcontainer_semantic> + public xcontainer_semantic>, + public extension::xarray_container_base_t { public: using self_type = xarray_container; using base_type = xstrided_container; using semantic_base = xcontainer_semantic; + using extension_base = extension::xarray_container_base_t; using storage_type = typename base_type::storage_type; using allocator_type = typename base_type::allocator_type; using value_type = typename base_type::value_type; @@ -80,6 +101,7 @@ namespace xt using strides_type = typename base_type::strides_type; using backstrides_type = typename base_type::backstrides_type; using inner_strides_type = typename base_type::inner_strides_type; + using inner_backstrides_type = typename base_type::inner_backstrides_type; using temporary_type = typename semantic_base::temporary_type; using expression_tag = Tag; @@ -108,6 +130,11 @@ namespace xt xarray_container(xarray_container&&) = default; xarray_container& operator=(xarray_container&&) = default; + template + explicit xarray_container(xtensor_container&& rhs); + template + xarray_container& operator=(xtensor_container&& rhs); + template xarray_container(const xexpression& e); @@ -128,13 +155,31 @@ namespace xt * xarray_adaptor declaration * ******************************/ + namespace extension + { + template + struct xarray_adaptor_base; + + template + struct xarray_adaptor_base + { + using type = xtensor_empty_base; + }; + + template + using xarray_adaptor_base_t = typename xarray_adaptor_base::type; + } + template struct xcontainer_inner_types> { using storage_type = std::remove_reference_t; + using reference = inner_reference_t; + using const_reference = typename storage_type::const_reference; + using size_type = typename storage_type::size_type; using shape_type = SC; - using strides_type = shape_type; - using backstrides_type = shape_type; + using strides_type = get_strides_t; + using backstrides_type = get_strides_t; using inner_shape_type = shape_type; using inner_strides_type = strides_type; using inner_backstrides_type = backstrides_type; @@ -162,10 +207,12 @@ namespace xt * @tparam L The layout_type of the adaptor. * @tparam SC The type of the containers holding the shape and the strides. * @tparam Tag The expression tag. + * @sa xstrided_container, xcontainer */ template class xarray_adaptor : public xstrided_container>, - public xcontainer_semantic> + public xcontainer_semantic>, + public extension::xarray_adaptor_base_t { public: @@ -174,6 +221,7 @@ namespace xt using self_type = xarray_adaptor; using base_type = xstrided_container; using semantic_base = xcontainer_semantic; + using extension_base = extension::xarray_adaptor_base_t; using storage_type = typename base_type::storage_type; using allocator_type = typename base_type::allocator_type; using shape_type = typename base_type::shape_type; @@ -210,7 +258,6 @@ namespace xt storage_type& storage_impl() noexcept; const storage_type& storage_impl() const noexcept; - friend class xcontainer>; }; @@ -386,10 +433,33 @@ namespace xt template inline xarray_container xarray_container::from_shape(S&& s) { - shape_type shape = xtl::forward_sequence(s); + shape_type shape = xtl::forward_sequence(s); return self_type(shape); } + template + template + inline xarray_container::xarray_container(xtensor_container&& rhs) + : base_type(inner_shape_type(rhs.shape().cbegin(), rhs.shape().cend()), + inner_strides_type(rhs.strides().cbegin(), rhs.strides().cend()), + inner_backstrides_type(rhs.backstrides().cbegin(), rhs.backstrides().cend()), + std::move(rhs.layout())), + m_storage(std::move(rhs.storage())) + { + } + + template + template + inline xarray_container& xarray_container::operator=(xtensor_container&& rhs) + { + this->shape_impl().assign(rhs.shape().cbegin(), rhs.shape().cend()); + this->strides_impl().assign(rhs.strides().cbegin(), rhs.strides().cend()); + this->backstrides_impl().assign(rhs.backstrides().cbegin(), rhs.backstrides().cend()); + this->mutable_layout() = rhs.layout(); + m_storage = std::move(rhs.storage()); + return *this; + } + /** * @name Extended copy semantic */ diff --git a/vendor/xtensor/include/xtensor/xassign.hpp b/vendor/xtensor/include/xtensor/xassign.hpp index 1b2f4c00d..86ea51ff3 100644 --- a/vendor/xtensor/include/xtensor/xassign.hpp +++ b/vendor/xtensor/include/xtensor/xassign.hpp @@ -1,5 +1,6 @@ /*************************************************************************** -* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * @@ -15,12 +16,16 @@ #include -#include "xconcepts.hpp" #include "xexpression.hpp" #include "xiterator.hpp" #include "xstrides.hpp" #include "xtensor_forward.hpp" #include "xutils.hpp" +#include "xfunction.hpp" + +#if defined(XTENSOR_USE_TBB) +#include +#endif namespace xt { @@ -74,7 +79,7 @@ namespace xt using base_type = xexpression_assigner_base; template - static void assign_xexpression(xexpression& e1, const xexpression& e2); + static void assign_xexpression(E1& e1, const E2& e2); template static void computed_assign(xexpression& e1, const xexpression& e2); @@ -88,15 +93,19 @@ namespace xt private: template - static bool resize(xexpression& e1, const xexpression& e2); + static bool resize(E1& e1, const E2& e2); + + template + static bool resize(E1& e1, const xfunction& e2); + }; - /***************** - * data_assigner * - *****************/ + /******************** + * stepper_assigner * + ********************/ template - class data_assigner + class stepper_assigner { public: @@ -107,7 +116,7 @@ namespace xt using size_type = typename lhs_iterator::size_type; using difference_type = typename lhs_iterator::difference_type; - data_assigner(E1& e1, const E2& e2); + stepper_assigner(E1& e1, const E2& e2); void run(); @@ -127,13 +136,45 @@ namespace xt index_type m_index; }; - /******************** - * trivial_assigner * - ********************/ + /******************* + * linear_assigner * + *******************/ template - struct trivial_assigner + class linear_assigner { + public: + + template + static void run(E1& e1, const E2& e2); + }; + + template <> + class linear_assigner + { + public: + + template + static void run(E1& e1, const E2& e2); + + private: + + template + static void run_impl(E1& e1, const E2& e2, std::true_type); + + template + static void run_impl(E1& e1, const E2& e2, std::false_type); + }; + + /************************* + * strided_loop_assigner * + *************************/ + + template + class strided_loop_assigner + { + public: + template static void run(E1& e1, const E2& e2); }; @@ -190,59 +231,28 @@ namespace xt namespace detail { template - inline bool is_trivial_broadcast(const E1& e1, const E2& e2) + constexpr bool linear_static_layout() { - return (E1::contiguous_layout && E2::contiguous_layout && (E1::static_layout == E2::static_layout)) - || e2.is_trivial_broadcast(e1.strides()); + // A row_major or column_major container with a dimension <= 1 is computed as + // layout any, leading to some performance improvements, for example when + // assigning a col-major vector to a row-major vector etc + return compute_layout(select_layout::value, + select_layout::value) != layout_type::dynamic; } - template - inline bool is_trivial_broadcast(const xview&, const E2&) + template + inline auto is_linear_assign(const E1& e1, const E2& e2) -> std::enable_if_t::value, bool> + { + return (E1::contiguous_layout && E2::contiguous_layout && linear_static_layout()) || + (e1.layout() != layout_type::dynamic && e2.has_linear_assign(e1.strides())); + } + + template + inline auto is_linear_assign(const E1&, const E2&) -> std::enable_if_t::value, bool> { return false; } - template > - struct forbid_simd_assign - { - static constexpr bool value = true; - }; - - // Double steps check for xfunction because the default - // parameter void_t of forbid_simd_assign prevents additional - // specializations. - template - struct xfunction_forbid_simd; - - template - struct forbid_simd_assign().template load_simd(typename E::size_type(0)))>> - { - static constexpr bool value = false || xfunction_forbid_simd::value; - }; - - template - struct xfunction_forbid_simd - { - static constexpr bool value = false; - }; - - template - struct xfunction_forbid_simd> - { - static constexpr bool value = xtl::disjunction< - std::integral_constant::type>::value>...>::value; - }; - - template - struct has_simd_apply : std::false_type {}; - - template - struct has_simd_apply)>> - : std::true_type - { - }; - template struct has_step_leading : std::false_type { @@ -267,25 +277,49 @@ namespace xt static constexpr bool value = true; }; - template - struct use_strided_loop> + template + struct use_strided_loop> { - static constexpr bool value = xtl::conjunction>...>::value && - has_simd_apply>::value; + static constexpr bool value = xtl::conjunction>...>::value; }; } template - struct xassign_traits + class xassign_traits { - // constexpr methods instead of constexpr data members avoid the need of difinitions at namespace - // scope of these data members (since they are odr-used). + private: + + using e1_value_type = typename E1::value_type; + using e2_value_type = typename E2::value_type; + + template + using is_bool = std::is_same; + static constexpr bool contiguous_layout() { return E1::contiguous_layout && E2::contiguous_layout; } - static constexpr bool same_type() { return std::is_same::value; } - static constexpr bool simd_size() { return xsimd::simd_traits::size > 1; } - static constexpr bool forbid_simd() { return detail::forbid_simd_assign::value; } - static constexpr bool simd_assign() { return contiguous_layout() && same_type() && simd_size() && !forbid_simd(); } - static constexpr bool simd_strided_loop() { return same_type() && simd_size() && detail::use_strided_loop::value && detail::use_strided_loop::value; } + static constexpr bool convertible_types() { return std::is_convertible::value; } + + static constexpr bool use_xsimd() { return xt_simd::simd_traits::size > 1; } + + template + static constexpr bool simd_size_impl() { return xt_simd::simd_traits::size > 1 || (is_bool::value && use_xsimd()); } + static constexpr bool simd_size() { return simd_size_impl() && simd_size_impl(); } + static constexpr bool simd_interface() { return has_simd_interface(); } + static constexpr bool simd_assign() { return convertible_types() && simd_size() && simd_interface(); } + + public: + + // constexpr methods instead of constexpr data members avoid the need of definitions at namespace + // scope of these data members (since they are odr-used). + + static constexpr bool linear_assign(const E1& e1, const E2& e2, bool trivial) { return trivial && detail::is_linear_assign(e1, e2); } + static constexpr bool strided_assign() { return detail::use_strided_loop::value && detail::use_strided_loop::value; } + static constexpr bool simd_linear_assign() { return contiguous_layout() && simd_assign(); } + static constexpr bool simd_strided_assign() { return strided_assign() && simd_assign(); } + + using requested_value_type = std::conditional_t::value, + typename E2::bool_load_type, + e2_value_type>; + }; template @@ -293,30 +327,31 @@ namespace xt { E1& de1 = e1.derived_cast(); const E2& de2 = e2.derived_cast(); + using traits = xassign_traits; - bool trivial_broadcast = trivial && detail::is_trivial_broadcast(de1, de2); - - if (trivial_broadcast) + bool linear_assign = traits::linear_assign(de1, de2, trivial); + constexpr bool simd_linear_assign = traits::simd_linear_assign(); + constexpr bool simd_strided_assign = traits::simd_strided_assign(); + if (linear_assign) { - constexpr bool simd_assign = xassign_traits::simd_assign(); - trivial_assigner::run(de1, de2); + linear_assigner::run(de1, de2); } - else if (xassign_traits::simd_strided_loop()) + else if (simd_strided_assign) { - strided_assign(de1, de2, std::integral_constant::simd_strided_loop()>{}); + strided_loop_assigner::run(de1, de2); } else { - data_assigner assigner(de1, de2); + stepper_assigner assigner(de1, de2); assigner.run(); } } template template - inline void xexpression_assigner::assign_xexpression(xexpression& e1, const xexpression& e2) + inline void xexpression_assigner::assign_xexpression(E1& e1, const E2& e2) { - bool trivial_broadcast = resize(e1, e2); + bool trivial_broadcast = resize(e1.derived_cast(), e2.derived_cast()); base_type::assign_data(e1, e2, trivial_broadcast); } @@ -331,7 +366,7 @@ namespace xt const E2& de2 = e2.derived_cast(); size_type dim = de2.dimension(); - shape_type shape = xtl::make_sequence(dim, size_type(0)); + shape_type shape = uninitialized_shape(dim); bool trivial_broadcast = de2.broadcast_shape(shape, true); if (dim > de1.dimension() || shape > de1.shape()) @@ -372,26 +407,98 @@ namespace xt } } - template - template - inline bool xexpression_assigner::resize(xexpression& e1, const xexpression& e2) + namespace detail { - using shape_type = typename E1::shape_type; - using size_type = typename E1::size_type; - const E2& de2 = e2.derived_cast(); - size_type size = de2.dimension(); - shape_type shape = xtl::make_sequence(size, size_type(0)); - bool trivial_broadcast = de2.broadcast_shape(shape, true); - e1.derived_cast().resize(std::move(shape)); - return trivial_broadcast; + template + struct static_trivial_broadcast; + + template + struct static_trivial_broadcast + { + static constexpr bool value = detail::promote_index::shape_type...>::value; + }; + + template + struct static_trivial_broadcast + { + static constexpr bool value = false; + }; } - /******************************** - * data_assigner implementation * - ********************************/ + template + template + inline bool xexpression_assigner::resize(E1& e1, const E2& e2) + { + // If our RHS is not a xfunction, we know that the RHS is at least potentially trivial + // We check the strides of the RHS in detail::is_trivial_broadcast to see if they match up! + // So we can skip a shape copy and a call to broadcast_shape(...) + e1.resize(e2.shape()); + return true; + } + + template + template + inline bool xexpression_assigner::resize(E1& e1, const xfunction& e2) + { + return xtl::mpl::static_if::shape_type>::value>( + [&](auto /*self*/) { + /* + * If the shape of the xfunction is statically known, we can compute the broadcast triviality + * at compile time plus we can resize right away. + */ + // resize in case LHS is not a fixed size container. If it is, this is a NOP + e1.resize(typename xfunction::shape_type{}); + return detail::static_trivial_broadcast::shape_type>::value, CT...>::value; + }, + /* else */ [&](auto /*self*/) + { + using index_type = xindex_type_t; + using size_type = typename E1::size_type; + size_type size = e2.dimension(); + index_type shape = uninitialized_shape(size); + bool trivial_broadcast = e2.broadcast_shape(shape, true); + e1.resize(std::move(shape)); + return trivial_broadcast; + } + ); + } + + /*********************************** + * stepper_assigner implementation * + ***********************************/ + + template + struct is_narrowing_conversion + { + using argument_type = std::decay_t; + using result_type = std::decay_t; + + static const bool value = std::is_arithmetic::value && + (sizeof(result_type) < sizeof(argument_type) || + (std::is_integral::value && std::is_floating_point::value)); + }; + + template + struct has_sign_conversion + { + using argument_type = std::decay_t; + using result_type = std::decay_t; + + static const bool value = std::is_signed::value != std::is_signed::value; + }; + + template + struct has_assign_conversion + { + using argument_type = std::decay_t; + using result_type = std::decay_t; + + static const bool value = is_narrowing_conversion::value || + has_sign_conversion::value; + }; template - inline data_assigner::data_assigner(E1& e1, const E2& e2) + inline stepper_assigner::stepper_assigner(E1& e1, const E2& e2) : m_e1(e1), m_lhs(e1.stepper_begin(e1.shape())), m_rhs(e2.stepper_begin(e1.shape())), m_index(xtl::make_sequence(e1.shape().size(), size_type(0))) @@ -399,128 +506,152 @@ namespace xt } template - inline void data_assigner::run() + inline void stepper_assigner::run() { using size_type = typename E1::size_type; using argument_type = std::decay_t; using result_type = std::decay_t; - constexpr bool is_narrowing = is_narrowing_conversion::value; + constexpr bool needs_cast = has_assign_conversion::value; size_type s = m_e1.size(); for (size_type i = 0; i < s; ++i) { - *m_lhs = conditional_cast(*m_rhs); + *m_lhs = conditional_cast(*m_rhs); stepper_tools::increment_stepper(*this, m_index, m_e1.shape()); } } template - inline void data_assigner::step(size_type i) + inline void stepper_assigner::step(size_type i) { m_lhs.step(i); m_rhs.step(i); } template - inline void data_assigner::step(size_type i, size_type n) + inline void stepper_assigner::step(size_type i, size_type n) { m_lhs.step(i, n); m_rhs.step(i, n); } template - inline void data_assigner::reset(size_type i) + inline void stepper_assigner::reset(size_type i) { m_lhs.reset(i); m_rhs.reset(i); } template - inline void data_assigner::to_end(layout_type l) + inline void stepper_assigner::to_end(layout_type l) { m_lhs.to_end(l); m_rhs.to_end(l); } - /*********************************** - * trivial_assigner implementation * - ***********************************/ + /********************************** + * linear_assigner implementation * + **********************************/ template template - inline void trivial_assigner::run(E1& e1, const E2& e2) + inline void linear_assigner::run(E1& e1, const E2& e2) { - using lhs_align_mode = xsimd::container_alignment_t; + using lhs_align_mode = xt_simd::container_alignment_t; constexpr bool is_aligned = std::is_same::value; using rhs_align_mode = std::conditional_t; - using value_type = std::common_type_t; - using simd_type = xsimd::simd_type; + using e1_value_type = typename E1::value_type; + using e2_value_type = typename E2::value_type; + using value_type = typename xassign_traits::requested_value_type; + using simd_type = xt_simd::simd_type; using size_type = typename E1::size_type; size_type size = e1.size(); - size_type simd_size = simd_type::size; + constexpr size_type simd_size = simd_type::size; + constexpr bool needs_cast = has_assign_conversion::value; - size_type align_begin = is_aligned ? 0 : xsimd::get_alignment_offset(e1.data(), size, simd_size); + size_type align_begin = is_aligned ? 0 : xt_simd::get_alignment_offset(e1.data(), size, simd_size); size_type align_end = align_begin + ((size - align_begin) & ~(simd_size - 1)); for (size_type i = 0; i < align_begin; ++i) { - e1.data_element(i) = e2.data_element(i); + e1.data_element(i) = conditional_cast(e2.data_element(i)); } + +#if defined(XTENSOR_USE_TBB) + tbb::parallel_for(align_begin, align_end, simd_size, [&](size_t i) + { + e1.template store_simd(i, e2.template load_simd(i)); + }); +#elif defined(XTENSOR_USE_OPENMP) + #pragma omp parallel for default(none) shared(align_begin, align_end, e1, e2) for (size_type i = align_begin; i < align_end; i += simd_size) { - e1.template store_simd(i, e2.template load_simd(i)); + e1.template store_simd(i, e2.template load_simd(i)); } +#else + for (size_type i = align_begin; i < align_end; i += simd_size) + { + e1.template store_simd(i, e2.template load_simd(i)); + } +#endif for (size_type i = align_end; i < size; ++i) { - e1.data_element(i) = e2.data_element(i); + e1.data_element(i) = conditional_cast(e2.data_element(i)); } } - namespace assigner_detail - { - template - inline void assign_loop(It src, Ot dst, std::size_t n) - { - for(; n > 0; --n) - { - *dst = static_cast(*src); - ++src; - ++dst; - } - } - - template - inline void trivial_assigner_run_impl(E1& e1, const E2& e2, std::true_type) - { - using size_type = typename E1::size_type; - auto src = e2.storage_cbegin(); - auto dst = e1.storage_begin(); - assign_loop(src, dst, e1.size()); - } - - template - inline void trivial_assigner_run_impl(E1&, const E2&, std::false_type) - { - XTENSOR_PRECONDITION(false, - "Internal error: trivial_assigner called with unrelated types."); - } - } - - template <> template - inline void trivial_assigner::run(E1& e1, const E2& e2) + inline void linear_assigner::run(E1& e1, const E2& e2) { - using is_convertible = std::is_convertible::value_type, - typename std::decay_t::value_type>; + using is_convertible = std::is_convertible::value_type, + typename std::decay_t::value_type>; // If the types are not compatible, this function is still instantiated but never called. // To avoid compilation problems in effectively unused code trivial_assigner_run_impl is // empty in this case. - assigner_detail::trivial_assigner_run_impl(e1, e2, is_convertible()); + run_impl(e1, e2, is_convertible()); } - /*********************** - * Strided assign loop * - ***********************/ + template + inline void linear_assigner::run_impl(E1& e1, const E2& e2, std::true_type /*is_convertible*/) + { + using value_type = typename E1::value_type; + using size_type = typename E1::size_type; + auto src = linear_begin(e2); + auto dst = linear_begin(e1); + size_type n = e1.size(); + +#if defined(XTENSOR_USE_TBB) + tbb::parallel_for(std::ptrdiff_t(0), static_cast(n), [&](std::ptrdiff_t i) + { + *(dst + i) = static_cast(*(src + i)); + }); +#elif defined(XTENSOR_USE_OPENMP) + #pragma omp parallel for default(none) shared(src, dst, n) + for (std::ptrdiff_t i = std::ptrdiff_t(0); i < static_cast(n) ; i++) + { + *(dst + i) = static_cast(*(src + i)); + } +#else + for (; n > size_type(0); --n) + { + *dst = static_cast(*src); + ++src; + ++dst; + } +#endif + } + + template + inline void linear_assigner::run_impl(E1&, const E2&, std::false_type /*is_convertible*/) + { + XTENSOR_PRECONDITION(false, + "Internal error: linear_assigner called with unrelated types."); + + } + + /**************************************** + * strided_loop_assigner implementation * + ****************************************/ namespace strided_assign_detail { @@ -614,35 +745,35 @@ namespace xt return m_cut; } - template - std::size_t operator()(const xt::xfunction& xf) + template + std::size_t operator()(const xt::xfunction& xf) { xt::for_each(*this, xf.arguments()); return m_cut; } - private: + private: std::size_t m_cut; const strides_type& m_strides; }; template - auto get_loop_sizes(const E1& e1, const E2& e2) + auto get_loop_sizes(const E1& e1, const E2& e2, bool is_row_major) { std::size_t cut = 0; - // TODO! if E1 is !contigous --> initialize cut to sensible value! - if (e1.strides().back() == 1) + // TODO! if E1 is !contiguous --> initialize cut to sensible value! + if (E1::static_layout == layout_type::row_major || is_row_major) { auto csf = check_strides_functor(e1.strides()); cut = csf(e2); } - else if (e1.strides().front() == 1) + else if (E1::static_layout == layout_type::column_major || !is_row_major) { auto csf = check_strides_functor(e1.strides()); cut = csf(e2); - } + } // can't reach here because this would have already triggered the fallback using shape_value_type = typename E1::shape_type::value_type; std::size_t outer_loop_size = static_cast( @@ -652,7 +783,7 @@ namespace xt std::accumulate(e1.shape().begin() + static_cast(cut), e1.shape().end(), shape_value_type(1), std::multiplies{})); - if (e1.strides().back() != 1) // column major mode + if (E1::static_layout == layout_type::column_major || !is_row_major) { std::swap(outer_loop_size, inner_loop_size); } @@ -661,73 +792,80 @@ namespace xt } } + template template - void strided_assign(E1& e1, const E2& e2, std::true_type /*enable*/) + inline void strided_loop_assigner::run(E1& e1, const E2& e2) { - bool fallback = false, is_row_major = true; + bool is_row_major = true; + using fallback_assigner = stepper_assigner; - std::size_t inner_loop_size, outer_loop_size, cut; - std::tie(inner_loop_size, outer_loop_size, cut) = strided_assign_detail::get_loop_sizes(e1, e2); - - if (E1::static_layout == layout_type::row_major || e1.strides().back() == 1) // row major case + if (E1::static_layout == layout_type::dynamic) { - if (cut == e1.dimension()) + layout_type dynamic_layout = e1.layout(); + switch (dynamic_layout) { - fallback = true; + case layout_type::row_major: + is_row_major = true; + break; + case layout_type::column_major: + is_row_major = false; + break; + default: + return fallback_assigner(e1, e2).run(); } } - else if (E1::static_layout == layout_type::column_major || e1.strides().front() == 1) // col major case + else if (E1::static_layout == layout_type::row_major) + { + is_row_major = true; + } + else if (E1::static_layout == layout_type::column_major) { is_row_major = false; - if (cut == 0) - { - fallback = true; - } } else { - fallback = true; + throw std::runtime_error("Illegal layout set (layout_type::any?)."); } - if (fallback) + std::size_t inner_loop_size, outer_loop_size, cut; + std::tie(inner_loop_size, outer_loop_size, cut) = strided_assign_detail::get_loop_sizes(e1, e2, is_row_major); + + if ((is_row_major && cut == e1.dimension()) || (!is_row_major && cut == 0)) { - data_assigner assigner(e1, e2); - assigner.run(); - return; + return fallback_assigner(e1, e2).run(); } // TODO can we get rid of this and use `shape_type`? - dynamic_shape idx; + dynamic_shape idx, max_shape; - using iterator_type = decltype(e1.shape().begin()); - iterator_type max_shape_begin, max_shape_end; if (is_row_major) { xt::resize_container(idx, cut); - max_shape_begin = e1.shape().begin(); - max_shape_end = e1.shape().begin() + static_cast(cut); + max_shape.assign(e1.shape().begin(), e1.shape().begin() + static_cast(cut)); } else { xt::resize_container(idx, e1.shape().size() - cut); - max_shape_begin = e1.shape().begin() + static_cast(cut); - max_shape_end = e1.shape().end(); + max_shape.assign(e1.shape().begin() + static_cast(cut), e1.shape().end()); } // add this when we have std::array index! // std::fill(idx.begin(), idx.end(), 0); - - dynamic_shape max(max_shape_begin, max_shape_end); - - using simd_type = xsimd::simd_type; + using e1_value_type = typename E1::value_type; + using e2_value_type = typename E2::value_type; + constexpr bool needs_cast = has_assign_conversion::value; + using value_type = typename xassign_traits::requested_value_type; + using simd_type = std::conditional_t::value, + xt_simd::simd_bool_type, + xt_simd::simd_type>; std::size_t simd_size = inner_loop_size / simd_type::size; std::size_t simd_rest = inner_loop_size % simd_type::size; auto fct_stepper = e2.stepper_begin(e1.shape()); auto res_stepper = e1.stepper_begin(e1.shape()); - - // TODO in 1D case this is ambigous -- could be RM or CM. + + // TODO in 1D case this is ambigous -- could be RM or CM. // Use default layout to make decision std::size_t step_dim = 0; if (!is_row_major) // row major case @@ -737,20 +875,20 @@ namespace xt for (std::size_t ox = 0; ox < outer_loop_size; ++ox) { - for (std::size_t i = 0; i < simd_size; i++) + for (std::size_t i = 0; i < simd_size; ++i) { - res_stepper.template store_simd(fct_stepper.template step_simd()); + res_stepper.template store_simd(fct_stepper.template step_simd()); } for (std::size_t i = 0; i < simd_rest; ++i) { - *(res_stepper) = *(fct_stepper); + *(res_stepper) = conditional_cast(*(fct_stepper)); res_stepper.step_leading(); fct_stepper.step_leading(); } is_row_major ? - strided_assign_detail::idx_tools::next_idx(idx, max) : - strided_assign_detail::idx_tools::next_idx(idx, max); + strided_assign_detail::idx_tools::next_idx(idx, max_shape) : + strided_assign_detail::idx_tools::next_idx(idx, max_shape); fct_stepper.to_begin(); @@ -774,8 +912,9 @@ namespace xt } } + template <> template - inline void strided_assign(E1& /*e1*/, const E2& /*e2*/, std::false_type /*disable*/) + inline void strided_loop_assigner::run(E1& /*e1*/, const E2& /*e2*/) { } } diff --git a/vendor/xtensor/include/xtensor/xaxis_iterator.hpp b/vendor/xtensor/include/xtensor/xaxis_iterator.hpp index e544791b8..3c3cfb632 100644 --- a/vendor/xtensor/include/xtensor/xaxis_iterator.hpp +++ b/vendor/xtensor/include/xtensor/xaxis_iterator.hpp @@ -1,5 +1,6 @@ /*************************************************************************** -* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * diff --git a/vendor/xtensor/include/xtensor/xbroadcast.hpp b/vendor/xtensor/include/xtensor/xbroadcast.hpp index 77c04f041..121981dae 100644 --- a/vendor/xtensor/include/xtensor/xbroadcast.hpp +++ b/vendor/xtensor/include/xtensor/xbroadcast.hpp @@ -1,5 +1,6 @@ /*************************************************************************** -* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * @@ -19,6 +20,7 @@ #include +#include "xaccessible.hpp" #include "xexpression.hpp" #include "xiterable.hpp" #include "xscalar.hpp" @@ -43,6 +45,31 @@ namespace xt auto broadcast(E&& e, const I (&s)[L]); #endif + /************************* + * xbroadcast extensions * + *************************/ + + namespace extension + { + template + struct xbroadcast_base_impl; + + template + struct xbroadcast_base_impl + { + using type = xtensor_empty_base; + }; + + template + struct xbroadcast_base + : xbroadcast_base_impl, CT, X> + { + }; + + template + using xbroadcast_base_t = typename xbroadcast_base::type; + } + /************** * xbroadcast * **************/ @@ -59,6 +86,43 @@ namespace xt using stepper = const_stepper; }; + template + struct xcontainer_inner_types> + { + using xexpression_type = std::decay_t; + using reference = typename xexpression_type::const_reference; + using const_reference = typename xexpression_type::const_reference; + using size_type = typename xexpression_type::size_type; + }; + + /***************************** + * linear_begin / linear_end * + *****************************/ + + template + XTENSOR_CONSTEXPR_RETURN auto linear_begin(xbroadcast& c) noexcept + { + return linear_begin(c.expression()); + } + + template + XTENSOR_CONSTEXPR_RETURN auto linear_end(xbroadcast& c) noexcept + { + return linear_end(c.expression()); + } + + template + XTENSOR_CONSTEXPR_RETURN auto linear_begin(const xbroadcast& c) noexcept + { + return linear_begin(c.expression()); + } + + template + XTENSOR_CONSTEXPR_RETURN auto linear_end(const xbroadcast& c) noexcept + { + return linear_end(c.expression()); + } + /** * @class xbroadcast * @brief Broadcasted xexpression to a specified shape. @@ -73,20 +137,25 @@ namespace xt * @sa broadcast */ template - class xbroadcast : public xexpression>, - public xconst_iterable> + class xbroadcast : public xsharable_expression>, + public xconst_iterable>, + public xconst_accessible>, + public extension::xbroadcast_base_t { public: using self_type = xbroadcast; using xexpression_type = std::decay_t; + using extension_base = extension::xbroadcast_base_t; + using expression_tag = typename extension_base::expression_tag; + using inner_types = xcontainer_inner_types; using value_type = typename xexpression_type::value_type; - using reference = typename xexpression_type::reference; - using const_reference = typename xexpression_type::const_reference; - using pointer = typename xexpression_type::pointer; + using reference = typename inner_types::reference; + using const_reference = typename inner_types::const_reference; + using pointer = typename xexpression_type::const_pointer; using const_pointer = typename xexpression_type::const_pointer; - using size_type = typename xexpression_type::size_type; + using size_type = typename inner_types::size_type; using difference_type = typename xexpression_type::difference_type; using iterable_base = xconst_iterable; @@ -96,41 +165,37 @@ namespace xt using stepper = typename iterable_base::stepper; using const_stepper = typename iterable_base::const_stepper; - static constexpr layout_type static_layout = xexpression_type::static_layout; - //static constexpr bool contiguous_layout = xexpression_type::contiguous_layout; + using bool_load_type = typename xexpression_type::bool_load_type; + + static constexpr layout_type static_layout = layout_type::dynamic; static constexpr bool contiguous_layout = false; template - xbroadcast(CTA&& e, S&& s); + xbroadcast(CTA&& e, const S& s); + + template + xbroadcast(CTA&& e, shape_type&& s); - size_type size() const noexcept; - size_type dimension() const noexcept; const inner_shape_type& shape() const noexcept; + size_type shape(size_type i) const noexcept; layout_type layout() const noexcept; template const_reference operator()(Args... args) const; - template - const_reference at(Args... args) const; - template const_reference unchecked(Args... args) const; - template - disable_integral_t operator[](const S& index) const; - template - const_reference operator[](std::initializer_list index) const; - const_reference operator[](size_type i) const; - template const_reference element(It first, It last) const; + const xexpression_type& expression() const noexcept; + template bool broadcast_shape(S& shape, bool reuse_cache = false) const; template - bool is_trivial_broadcast(const S& strides) const noexcept; + bool has_linear_assign(const S& strides) const noexcept; template const_stepper stepper_begin(const S& shape) const noexcept; @@ -140,6 +205,12 @@ namespace xt template ::value>> void assign_to(xexpression& e) const; + template + using rebind_t = xbroadcast; + + template + rebind_t build_broadcast(E&& e) const; + private: CT m_e; @@ -164,8 +235,7 @@ namespace xt inline auto broadcast(E&& e, const S& s) { using broadcast_type = xbroadcast, S>; - using shape_type = typename broadcast_type::shape_type; - return broadcast_type(std::forward(e), xtl::forward_sequence(s)); + return broadcast_type(std::forward(e), s); } #ifdef X_OLD_CLANG @@ -174,7 +244,7 @@ namespace xt { using broadcast_type = xbroadcast, std::vector>; using shape_type = typename broadcast_type::shape_type; - return broadcast_type(std::forward(e), xtl::forward_sequence(s)); + return broadcast_type(std::forward(e), xtl::forward_sequence(s)); } #else template @@ -182,7 +252,7 @@ namespace xt { using broadcast_type = xbroadcast, std::array>; using shape_type = typename broadcast_type::shape_type; - return broadcast_type(std::forward(e), xtl::forward_sequence(s)); + return broadcast_type(std::forward(e), xtl::forward_sequence(s)); } #endif @@ -203,8 +273,29 @@ namespace xt */ template template - inline xbroadcast::xbroadcast(CTA&& e, S&& s) - : m_e(std::forward(e)), m_shape(std::forward(s)) + inline xbroadcast::xbroadcast(CTA&& e, const S& s) + : m_e(std::forward(e)) + { + if (s.size() < m_e.dimension()) + { + throw xt::broadcast_error("Broadcast shape has fewer elements than original expression."); + } + xt::resize_container(m_shape, s.size()); + std::copy(s.begin(), s.end(), m_shape.begin()); + xt::broadcast_shape(m_e.shape(), m_shape); + } + + /** + * Constructs an xbroadcast expression broadcasting the specified + * \ref xexpression to the given shape + * + * @param e the expression to broadcast + * @param s the shape to apply + */ + template + template + inline xbroadcast::xbroadcast(CTA&& e, shape_type&& s) + : m_e(std::forward(e)), m_shape(std::move(s)) { xt::broadcast_shape(m_e.shape(), m_shape); } @@ -213,24 +304,7 @@ namespace xt /** * @name Size and shape */ - /** - * Returns the size of the expression. - */ - template - inline auto xbroadcast::size() const noexcept -> size_type - { - return compute_size(shape()); - } - - /** - * Returns the number of dimensions of the expression. - */ - template - inline auto xbroadcast::dimension() const noexcept -> size_type - { - return m_shape.size(); - } - + //@{ /** * Returns the shape of the expression. */ @@ -240,6 +314,15 @@ namespace xt return m_shape; } + /** + * Returns the shape of the expression. + */ + template + inline auto xbroadcast::shape(size_type i) const noexcept -> size_type + { + return m_shape[i]; + } + /** * Returns the layout_type of the expression. */ @@ -266,23 +349,6 @@ namespace xt return m_e(args...); } - /** - * Returns a constant reference to the element at the specified position in the expression, - * after dimension and bounds checking. - * @param args a list of indices specifying the position in the function. Indices - * must be unsigned integers, the number of indices should be equal to the number of dimensions - * of the expression. - * @exception std::out_of_range if the number of argument is greater than the number of dimensions - * or if indices are out of bounds. - */ - template - template - inline auto xbroadcast::at(Args... args) const -> const_reference - { - check_access(shape(), static_cast(args)...); - return this->operator()(args...); - } - /** * Returns a constant reference to the element at the specified position in the expression. * @param args a list of indices specifying the position in the expression. Indices @@ -309,33 +375,6 @@ namespace xt return this->operator()(args...); } - /** - * Returns a constant reference to the element at the specified position in the expression. - * @param index a sequence of indices specifying the position in the function. Indices - * must be unsigned integers, the number of indices in the sequence should be equal or greater - * than the number of dimensions of the container. - */ - template - template - inline auto xbroadcast::operator[](const S& index) const - -> disable_integral_t - { - return element(index.cbegin(), index.cend()); - } - - template - template - inline auto xbroadcast::operator[](std::initializer_list index) const -> const_reference - { - return element(index.begin(), index.end()); - } - - template - inline auto xbroadcast::operator[](size_type i) const -> const_reference - { - return operator()(i); - } - /** * Returns a constant reference to the element at the specified position in the expression. * @param first iterator starting the sequence of indices @@ -347,7 +386,16 @@ namespace xt template inline auto xbroadcast::element(It, It last) const -> const_reference { - return m_e.element(last - dimension(), last); + return m_e.element(last - this->dimension(), last); + } + + /** + * Returns a constant reference to the underlying expression of the broadcast expression. + */ + template + inline auto xbroadcast::expression() const noexcept -> const xexpression_type& + { + return m_e; } //@} @@ -369,17 +417,17 @@ namespace xt } /** - * Compares the specified strides with those of the container to see whether - * the broadcasting is trivial. - * @return a boolean indicating whether the broadcasting is trivial + * Checks whether the xbroadcast can be linearly assigned to an expression + * with the specified strides. + * @return a boolean indicating whether a linear assign is possible */ template template - inline bool xbroadcast::is_trivial_broadcast(const S& strides) const noexcept + inline bool xbroadcast::has_linear_assign(const S& strides) const noexcept { - return dimension() == m_e.dimension() && + return this->dimension() == m_e.dimension() && std::equal(m_shape.cbegin(), m_shape.cend(), m_e.shape().cbegin()) && - m_e.is_trivial_broadcast(strides); + m_e.has_linear_assign(strides); } //@} @@ -407,6 +455,13 @@ namespace xt ed.resize(m_shape); std::fill(ed.begin(), ed.end(), m_e()); } + + template + template + inline auto xbroadcast::build_broadcast(E&& e) const -> rebind_t + { + return rebind_t(std::forward(e), inner_shape_type(m_shape)); + } } #endif diff --git a/vendor/xtensor/include/xtensor/xbuffer_adaptor.hpp b/vendor/xtensor/include/xtensor/xbuffer_adaptor.hpp index d8d331685..6bec4f3be 100644 --- a/vendor/xtensor/include/xtensor/xbuffer_adaptor.hpp +++ b/vendor/xtensor/include/xtensor/xbuffer_adaptor.hpp @@ -1,5 +1,6 @@ /*************************************************************************** -* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * @@ -21,14 +22,13 @@ namespace xt { - /****************************** - * xbuffer_adator declaration * - ******************************/ struct no_ownership { }; + using smart_ownership = no_ownership; + struct acquire_ownership { }; @@ -36,9 +36,9 @@ namespace xt template >>> class xbuffer_adaptor; - /********************************* - * xbuffer_adator implementation * - *********************************/ + /******************** + * buffer_storage_t * + ********************/ namespace detail { @@ -49,6 +49,7 @@ namespace xt using self_type = xbuffer_storage; using allocator_type = A; + using destructor_type = allocator_type; using value_type = typename allocator_type::value_type; using reference = std::conditional_t>>::value, typename allocator_type::const_reference, @@ -80,6 +81,46 @@ namespace xt size_type m_size; }; + template + class xbuffer_smart_pointer + { + public: + + using self_type = xbuffer_storage; + using destructor_type = D; + using value_type = std::remove_const_t>>; + using allocator_type = std::allocator; + using reference = std::conditional_t>>::value, + typename allocator_type::const_reference, + typename allocator_type::reference>; + using const_reference = typename allocator_type::const_reference; + using pointer = std::conditional_t>>::value, + typename allocator_type::const_pointer, + typename allocator_type::pointer>; + using const_pointer = typename allocator_type::const_pointer; + using size_type = typename allocator_type::size_type; + using difference_type = typename allocator_type::difference_type; + + xbuffer_smart_pointer(); + + template + xbuffer_smart_pointer(P&& data_ptr, size_type size, DT&& destruct); + + size_type size() const noexcept; + void resize(size_type size); + + pointer data() noexcept; + const_pointer data() const noexcept; + + void swap(self_type& rhs) noexcept; + + private: + + pointer p_data; + size_type m_size; + destructor_type m_destruct; + }; + template class xbuffer_owner_storage { @@ -87,6 +128,7 @@ namespace xt using self_type = xbuffer_owner_storage; using allocator_type = A; + using destructor_type = allocator_type; using value_type = typename allocator_type::value_type; using reference = std::conditional_t>>::value, typename allocator_type::const_reference, @@ -130,10 +172,41 @@ namespace xt allocator_type m_allocator; }; + // Workaround for MSVC2015: using void_t results in some + // template instantiation caching that leads to wrong + // type deduction later in xfunction. + template + struct msvc2015_void + { + using type = void; + }; + + template + using msvc2015_void_t = typename msvc2015_void::type; + + template + struct is_lambda_type : std::false_type + { + }; + + // check if operator() is available + template + struct is_lambda_type> + : std::true_type + { + }; + + template + struct self_type + { + using type = T; + }; template struct get_buffer_storage { - using type = xbuffer_storage; + using type = xtl::mpl::eval_if_t, + self_type>, + self_type>>; }; template @@ -142,37 +215,165 @@ namespace xt using type = xbuffer_owner_storage; }; + template + struct get_buffer_storage, no_ownership> + { + using type = xbuffer_smart_pointer>; + }; + + template + struct get_buffer_storage, no_ownership> + { + using type = xbuffer_smart_pointer>; + }; + template using buffer_storage_t = typename get_buffer_storage::type; } - template - class xbuffer_adaptor : private detail::buffer_storage_t + /************************ + * xbuffer_adaptor_base * + ************************/ + + template + struct buffer_inner_types; + + template + class xbuffer_adaptor_base { public: + using self_type = xbuffer_adaptor_base; + using derived_type = D; + using inner_types = buffer_inner_types; + using value_type = typename inner_types::value_type; + using reference = typename inner_types::reference; + using const_reference = typename inner_types::const_reference; + using pointer = typename inner_types::pointer; + using const_pointer = typename inner_types::const_pointer; + using size_type = typename inner_types::size_type; + using difference_type = typename inner_types::difference_type; + using iterator = typename inner_types::iterator; + using const_iterator = typename inner_types::const_iterator; + using reverse_iterator = typename inner_types::reverse_iterator; + using const_reverse_iterator = typename inner_types::const_reverse_iterator; + using index_type = typename inner_types::index_type; + + bool empty() const noexcept; + + reference operator[](size_type i); + const_reference operator[](size_type i) const; + + reference front(); + const_reference front() const; + + reference back(); + const_reference back() const; + + iterator begin() noexcept; + iterator end() noexcept; + + const_iterator begin() const noexcept; + const_iterator end() const noexcept; + const_iterator cbegin() const noexcept; + const_iterator cend() const noexcept; + + reverse_iterator rbegin() noexcept; + reverse_iterator rend() noexcept; + + const_reverse_iterator rbegin() const noexcept; + const_reverse_iterator rend() const noexcept; + const_reverse_iterator crbegin() const noexcept; + const_reverse_iterator crend() const noexcept; + + derived_type& derived_cast() noexcept; + const derived_type& derived_cast() const noexcept; + + protected: + + xbuffer_adaptor_base() = default; + ~xbuffer_adaptor_base() = default; + + xbuffer_adaptor_base(const self_type&) = default; + self_type& operator=(const self_type&) = default; + + xbuffer_adaptor_base(self_type&&) = default; + self_type& operator=(self_type&&) = default; + }; + + template + bool operator==(const xbuffer_adaptor_base& lhs, + const xbuffer_adaptor_base& rhs); + + template + bool operator!=(const xbuffer_adaptor_base& lhs, + const xbuffer_adaptor_base& rhs); + + template + bool operator<(const xbuffer_adaptor_base& lhs, + const xbuffer_adaptor_base& rhs); + + template + bool operator<=(const xbuffer_adaptor_base& lhs, + const xbuffer_adaptor_base& rhs); + + template + bool operator>(const xbuffer_adaptor_base& lhs, + const xbuffer_adaptor_base& rhs); + + template + bool operator>=(const xbuffer_adaptor_base& lhs, + const xbuffer_adaptor_base& rhs); + + /******************* + * xbuffer_adaptor * + *******************/ + + template + struct buffer_inner_types> + { using base_type = detail::buffer_storage_t; - using self_type = xbuffer_adaptor; - using allocator_type = typename base_type::allocator_type; using value_type = typename base_type::value_type; using reference = typename base_type::reference; using const_reference = typename base_type::const_reference; using pointer = typename base_type::pointer; using const_pointer = typename base_type::const_pointer; - using temporary_type = uvector; - using size_type = typename base_type::size_type; using difference_type = typename base_type::difference_type; - using iterator = pointer; using const_iterator = const_pointer; using reverse_iterator = std::reverse_iterator; using const_reverse_iterator = std::reverse_iterator; + using index_type = size_type; + }; + + template + class xbuffer_adaptor : private detail::buffer_storage_t, + public xbuffer_adaptor_base> + { + public: + + using self_type = xbuffer_adaptor; + using base_type = detail::buffer_storage_t; + using buffer_base_type = xbuffer_adaptor_base; + using allocator_type = typename base_type::allocator_type; + using destructor_type = typename base_type::destructor_type; + using value_type = typename buffer_base_type::value_type; + using reference = typename buffer_base_type::reference; + using const_reference = typename buffer_base_type::const_reference; + using pointer = typename buffer_base_type::pointer; + using const_pointer = typename buffer_base_type::const_pointer; + using size_type = typename buffer_base_type::size_type; + using difference_type = typename buffer_base_type::difference_type; + using iterator = typename buffer_base_type::iterator; + using const_iterator = typename buffer_base_type::const_iterator; + using reverse_iterator = typename buffer_base_type::reverse_iterator; + using const_reverse_iterator = typename buffer_base_type::const_reverse_iterator; + using temporary_type = uvector; xbuffer_adaptor() = default; - template - xbuffer_adaptor(P&& data, size_type size, const allocator_type& alloc = allocator_type()); + using base_type::base_type; ~xbuffer_adaptor() = default; @@ -184,67 +385,93 @@ namespace xt self_type& operator=(temporary_type&&); - bool empty() const noexcept; using base_type::size; using base_type::resize; - - reference operator[](size_type i); - const_reference operator[](size_type i) const; - - reference front(); - const_reference front() const; - - reference back(); - const_reference back() const; - - iterator begin(); - iterator end(); - - const_iterator begin() const; - const_iterator end() const; - const_iterator cbegin() const; - const_iterator cend() const; - - reverse_iterator rbegin(); - reverse_iterator rend(); - - const_reverse_iterator rbegin() const; - const_reverse_iterator rend() const; - const_reverse_iterator crbegin() const; - const_reverse_iterator crend() const; - using base_type::data; using base_type::swap; }; - template - bool operator==(const xbuffer_adaptor& lhs, - const xbuffer_adaptor& rhs); - - template - bool operator!=(const xbuffer_adaptor& lhs, - const xbuffer_adaptor& rhs); - - template - bool operator<(const xbuffer_adaptor& lhs, - const xbuffer_adaptor& rhs); - - template - bool operator<=(const xbuffer_adaptor& lhs, - const xbuffer_adaptor& rhs); - - template - bool operator>(const xbuffer_adaptor& lhs, - const xbuffer_adaptor& rhs); - - template - bool operator>=(const xbuffer_adaptor& lhs, - const xbuffer_adaptor& rhs); - template void swap(xbuffer_adaptor& lhs, xbuffer_adaptor& rhs) noexcept; + /********************* + * xiterator_adaptor * + *********************/ + + template + class xiterator_adaptor; + + template + struct buffer_inner_types> + { + using traits = std::iterator_traits; + using const_traits = std::iterator_traits; + + using value_type = std::common_type_t; + using reference = typename traits::reference; + using const_reference = typename const_traits::reference; + using pointer = typename traits::pointer; + using const_pointer = typename const_traits::pointer; + using difference_type = std::common_type_t; + using size_type = std::make_unsigned_t; + + using iterator = I; + using const_iterator = CI; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + using index_type = difference_type; + }; + + template + class xiterator_adaptor : public xbuffer_adaptor_base> + { + public: + + using self_type = xiterator_adaptor; + using base_type = xbuffer_adaptor_base; + using value_type = typename base_type::value_type; + using allocator_type = std::allocator; + using size_type = typename base_type::size_type; + using iterator = typename base_type::iterator; + using const_iterator = typename base_type::const_iterator; + using temporary_type = uvector; + + xiterator_adaptor() = default; + xiterator_adaptor(I it, CI cit, size_type size); + + ~xiterator_adaptor() = default; + + xiterator_adaptor(const self_type&) = default; + xiterator_adaptor& operator=(const self_type&) = default; + + xiterator_adaptor(self_type&&) = default; + xiterator_adaptor& operator=(self_type&&) = default; + + xiterator_adaptor& operator=(const temporary_type& rhs); + xiterator_adaptor& operator=(temporary_type&& rhs); + + size_type size() const noexcept; + void resize(size_type size); + + iterator data() noexcept; + const_iterator data() const noexcept; + + void swap(self_type& rhs) noexcept; + + private: + + I m_it; + CI m_cit; + size_type m_size; + }; + + template + void swap(xiterator_adaptor& lhs, + xiterator_adaptor& rhs) noexcept; + /************************************ * temporary_container metafunction * ************************************/ @@ -261,6 +488,12 @@ namespace xt using type = typename xbuffer_adaptor::temporary_type; }; + template + struct temporary_container> + { + using type = typename xiterator_adaptor::temporary_type; + }; + template using temporary_container_t = typename temporary_container::type; @@ -378,7 +611,6 @@ namespace xt inline auto xbuffer_owner_storage::operator=(self_type&& rhs) -> self_type& { swap(rhs); - rhs.m_moved_from = true; return *this; } @@ -429,195 +661,320 @@ namespace xt } } + /**************************************** + * xbuffer_smart_pointer implementation * + ****************************************/ + + namespace detail + { + template + template + xbuffer_smart_pointer::xbuffer_smart_pointer(P&& data_ptr, size_type size, DT&& destruct) + : p_data(data_ptr), m_size(size), m_destruct(std::forward

(destruct)) + { + } + + template + auto xbuffer_smart_pointer::size() const noexcept -> size_type + { + return m_size; + } + + template + void xbuffer_smart_pointer::resize(size_type size) + { + if (m_size != size) + { + throw std::runtime_error("xbuffer_storage not resizable"); + } + } + + template + auto xbuffer_smart_pointer::data() noexcept -> pointer + { + return p_data; + } + template + auto xbuffer_smart_pointer::data() const noexcept -> const_pointer + { + return p_data; + } + + template + void xbuffer_smart_pointer::swap(self_type& rhs) noexcept + { + using std::swap; + swap(p_data, rhs.p_data); + swap(m_size, rhs.m_size); + swap(m_destruct, rhs.m_destruct); + } + } + + /*************************************** + * xbuffer_adaptor_base implementation * + ***************************************/ + + template + inline bool xbuffer_adaptor_base::empty() const noexcept + { + return derived_cast().size() == size_type(0); + } + + template + inline auto xbuffer_adaptor_base::operator[](size_type i) -> reference + { + return derived_cast().data()[static_cast(i)]; + } + + template + inline auto xbuffer_adaptor_base::operator[](size_type i) const -> const_reference + { + return derived_cast().data()[static_cast(i)]; + } + + template + inline auto xbuffer_adaptor_base::front() -> reference + { + return this->operator[](0); + } + + template + inline auto xbuffer_adaptor_base::front() const -> const_reference + { + return this->operator[](0); + } + + template + inline auto xbuffer_adaptor_base::back() -> reference + { + return this->operator[](derived_cast().size() - 1); + } + + template + inline auto xbuffer_adaptor_base::back() const -> const_reference + { + return this->operator[](derived_cast().size() - 1); + } + + template + inline auto xbuffer_adaptor_base::begin() noexcept -> iterator + { + return derived_cast().data(); + } + + template + inline auto xbuffer_adaptor_base::end() noexcept-> iterator + { + return derived_cast().data() + static_cast(derived_cast().size()); + } + + template + inline auto xbuffer_adaptor_base::begin() const noexcept -> const_iterator + { + return derived_cast().data(); + } + + template + inline auto xbuffer_adaptor_base::end() const noexcept -> const_iterator + { + return derived_cast().data() + static_cast(derived_cast().size()); + } + + template + inline auto xbuffer_adaptor_base::cbegin() const noexcept -> const_iterator + { + return begin(); + } + + template + inline auto xbuffer_adaptor_base::cend() const noexcept -> const_iterator + { + return end(); + } + + template + inline auto xbuffer_adaptor_base::rbegin() noexcept-> reverse_iterator + { + return reverse_iterator(end()); + } + + template + inline auto xbuffer_adaptor_base::rend() noexcept -> reverse_iterator + { + return reverse_iterator(begin()); + } + + template + inline auto xbuffer_adaptor_base::rbegin() const noexcept -> const_reverse_iterator + { + return const_reverse_iterator(end()); + } + + template + inline auto xbuffer_adaptor_base::rend() const noexcept -> const_reverse_iterator + { + return const_reverse_iterator(begin()); + } + + template + inline auto xbuffer_adaptor_base::crbegin() const noexcept -> const_reverse_iterator + { + return rbegin(); + } + + template + inline auto xbuffer_adaptor_base::crend() const noexcept -> const_reverse_iterator + { + return rend(); + } + + template + inline auto xbuffer_adaptor_base::derived_cast() noexcept -> derived_type& + { + return *static_cast(this); + } + + template + inline auto xbuffer_adaptor_base::derived_cast() const noexcept -> const derived_type& + { + return *static_cast(this); + } + + template + inline bool operator==(const xbuffer_adaptor_base& lhs, + const xbuffer_adaptor_base& rhs) + { + return lhs.derived_cast().size() == rhs.derived_cast().size() && std::equal(lhs.begin(), lhs.end(), rhs.begin()); + } + + template + inline bool operator!=(const xbuffer_adaptor_base& lhs, + const xbuffer_adaptor_base& rhs) + { + return !(lhs == rhs); + } + + template + inline bool operator<(const xbuffer_adaptor_base& lhs, + const xbuffer_adaptor_base& rhs) + { + return std::lexicographical_compare(lhs.begin(), lhs.end(), + rhs.begin(), rhs.end(), + std::less()); + } + + template + inline bool operator<=(const xbuffer_adaptor_base& lhs, + const xbuffer_adaptor_base& rhs) + { + return std::lexicographical_compare(lhs.begin(), lhs.end(), + rhs.begin(), rhs.end(), + std::less_equal()); + } + + template + inline bool operator>(const xbuffer_adaptor_base& lhs, + const xbuffer_adaptor_base& rhs) + { + return std::lexicographical_compare(lhs.begin(), lhs.end(), + rhs.begin(), rhs.end(), + std::greater()); + } + + template + inline bool operator>=(const xbuffer_adaptor_base& lhs, + const xbuffer_adaptor_base& rhs) + { + return std::lexicographical_compare(lhs.begin(), lhs.end(), + rhs.begin(), rhs.end(), + std::greater_equal()); + } + /********************************** * xbuffer_adaptor implementation * **********************************/ - template - template - inline xbuffer_adaptor::xbuffer_adaptor(P&& data, size_type size, const allocator_type& alloc) - : base_type(std::forward

(data), size, alloc) - { - } - template inline auto xbuffer_adaptor::operator=(temporary_type&& tmp) -> self_type& { base_type::resize(tmp.size()); - std::copy(tmp.cbegin(), tmp.cend(), begin()); + std::copy(tmp.cbegin(), tmp.cend(), this->begin()); return *this; } - template - bool xbuffer_adaptor::empty() const noexcept - { - return size() == 0; - } - - template - inline auto xbuffer_adaptor::operator[](size_type i) -> reference - { - return data()[i]; - } - - template - inline auto xbuffer_adaptor::operator[](size_type i) const -> const_reference - { - return data()[i]; - } - - template - inline auto xbuffer_adaptor::front() -> reference - { - return data()[0]; - } - - template - inline auto xbuffer_adaptor::front() const -> const_reference - { - return data()[0]; - } - - template - inline auto xbuffer_adaptor::back() -> reference - { - return data()[size() - 1]; - } - - template - inline auto xbuffer_adaptor::back() const -> const_reference - { - return data()[size() - 1]; - } - - template - inline auto xbuffer_adaptor::begin() -> iterator - { - return data(); - } - - template - inline auto xbuffer_adaptor::end() -> iterator - { - return data() + size(); - } - - template - inline auto xbuffer_adaptor::begin() const -> const_iterator - { - return data(); - } - - template - inline auto xbuffer_adaptor::end() const -> const_iterator - { - return data() + size(); - } - - template - inline auto xbuffer_adaptor::cbegin() const -> const_iterator - { - return begin(); - } - - template - inline auto xbuffer_adaptor::cend() const -> const_iterator - { - return end(); - } - - template - inline auto xbuffer_adaptor::rbegin() -> reverse_iterator - { - return reverse_iterator(end()); - } - - template - inline auto xbuffer_adaptor::rend() -> reverse_iterator - { - return reverse_iterator(begin()); - } - - template - inline auto xbuffer_adaptor::rbegin() const -> const_reverse_iterator - { - return const_reverse_iterator(end()); - } - - template - inline auto xbuffer_adaptor::rend() const -> const_reverse_iterator - { - return const_reverse_iterator(begin()); - } - - template - inline auto xbuffer_adaptor::crbegin() const -> const_reverse_iterator - { - return rbegin(); - } - - template - inline auto xbuffer_adaptor::crend() const -> const_reverse_iterator - { - return rend(); - } - - template - inline bool operator==(const xbuffer_adaptor& lhs, - const xbuffer_adaptor& rhs) - { - return lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin()); - } - - template - inline bool operator!=(const xbuffer_adaptor& lhs, - const xbuffer_adaptor& rhs) - { - return !(lhs == rhs); - } - - template - inline bool operator<(const xbuffer_adaptor& lhs, - const xbuffer_adaptor& rhs) - { - return std::lexicographical_compare(lhs.begin(), lhs.end(), - rhs.begin(), rhs.end(), - std::less()); - } - - template - inline bool operator<=(const xbuffer_adaptor& lhs, - const xbuffer_adaptor& rhs) - { - return std::lexicographical_compare(lhs.begin(), lhs.end(), - rhs.begin(), rhs.end(), - std::less_equal()); - } - - template - inline bool operator>(const xbuffer_adaptor& lhs, - const xbuffer_adaptor& rhs) - { - return std::lexicographical_compare(lhs.begin(), lhs.end(), - rhs.begin(), rhs.end(), - std::greater()); - } - - template - inline bool operator>=(const xbuffer_adaptor& lhs, - const xbuffer_adaptor& rhs) - { - return std::lexicographical_compare(lhs.begin(), lhs.end(), - rhs.begin(), rhs.end(), - std::greater_equal()); - } - template inline void swap(xbuffer_adaptor& lhs, xbuffer_adaptor& rhs) noexcept { lhs.swap(rhs); } + + /************************************ + * xiterator_adaptor implementation * + ************************************/ + + template + inline xiterator_adaptor::xiterator_adaptor(I it, CI cit, size_type size) + : m_it(it), m_cit(cit), m_size(size) + { + } + + template + inline auto xiterator_adaptor::operator=(const temporary_type& rhs) -> self_type& + { + resize(rhs.size()); + std::copy(rhs.cbegin(), rhs.cend(), m_it); + return *this; + } + + template + inline auto xiterator_adaptor::operator=(temporary_type&& rhs) -> self_type& + { + return (*this = rhs); + } + + template + inline auto xiterator_adaptor::size() const noexcept -> size_type + { + return m_size; + } + + template + inline void xiterator_adaptor::resize(size_type size) + { + if (m_size != size) + { + throw std::runtime_error("xiterator_adaptor not resizable"); + } + } + + template + inline auto xiterator_adaptor::data() noexcept -> iterator + { + return m_it; + } + + template + inline auto xiterator_adaptor::data() const noexcept -> const_iterator + { + return m_cit; + } + + template + inline void xiterator_adaptor::swap(self_type& rhs) noexcept + { + using std::swap; + swap(m_it, rhs.m_it); + swap(m_cit, rhs.m_cit); + swap(m_size, rhs.m_size); + } + + template + inline void swap(xiterator_adaptor& lhs, + xiterator_adaptor& rhs) noexcept + { + lhs.swap(rhs); + } } #endif diff --git a/vendor/xtensor/include/xtensor/xbuilder.hpp b/vendor/xtensor/include/xtensor/xbuilder.hpp index c3e34b8ac..dfbb2f3cd 100644 --- a/vendor/xtensor/include/xtensor/xbuilder.hpp +++ b/vendor/xtensor/include/xtensor/xbuilder.hpp @@ -1,5 +1,6 @@ /*************************************************************************** -* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * @@ -14,6 +15,7 @@ #define XTENSOR_BUILDER_HPP #include +#include #include #include #include @@ -25,6 +27,7 @@ #include #include +#include #include "xbroadcast.hpp" #include "xfunction.hpp" @@ -111,7 +114,7 @@ namespace xt inline xtensor empty(const std::array& shape) { using shape_type = typename xtensor::shape_type; - return xtensor(xtl::forward_sequence(shape)); + return xtensor(xtl::forward_sequence(shape)); } #ifndef X_OLD_CLANG @@ -119,7 +122,13 @@ namespace xt inline xtensor empty(const I(&shape)[N]) { using shape_type = typename xtensor::shape_type; - return xtensor(xtl::forward_sequence(shape)); + return xtensor(xtl::forward_sequence(shape)); + } +#else + template + inline xarray empty(const std::initializer_list& init) + { + return xarray::from_shape(init); } #endif @@ -136,9 +145,10 @@ namespace xt * @param e the xexpression from which to extract shape, value type and layout. */ template - inline typename E::temporary_type empty_like(const xexpression& e) + inline auto empty_like(const xexpression& e) { - typename E::temporary_type res(e.derived_cast().shape()); + using xtype = temporary_type_t; + auto res = xtype::from_shape(e.derived_cast().shape()); return res; } @@ -150,9 +160,11 @@ namespace xt * @param fill_value the value used to set each element of the returned xcontainer. */ template - inline typename E::temporary_type full_like(const xexpression& e, typename E::value_type fill_value) + inline auto full_like(const xexpression& e, typename E::value_type fill_value) { - typename E::temporary_type res(e.derived_cast().shape(), fill_value); + using xtype = temporary_type_t; + auto res = xtype::from_shape(e.derived_cast().shape()); + res.fill(fill_value); return res; } @@ -166,7 +178,7 @@ namespace xt * @param e the xexpression from which to extract shape, value type and layout. */ template - inline typename E::temporary_type zeros_like(const xexpression& e) + inline auto zeros_like(const xexpression& e) { return full_like(e, typename E::value_type(0)); } @@ -181,68 +193,130 @@ namespace xt * @param e the xexpression from which to extract shape, value type and layout. */ template - inline typename E::temporary_type ones_like(const xexpression& e) + inline auto ones_like(const xexpression& e) { return full_like(e, typename E::value_type(1)); } namespace detail { - template - class arange_impl + template + struct get_mult_type_impl + { + using type = T; + }; + + template + struct get_mult_type_impl> + { + using type = R; + }; + + template + using get_mult_type = typename get_mult_type_impl::type; + + // These methods should be private methods of arange_generator, however thi leads + // to ICE on VS2015 + template )> + inline void arange_assign_to(xexpression& e, U start, X step) noexcept + { + auto& de = e.derived_cast(); + U value = start; + + for (auto&& el : de.storage()) + { + el = static_cast(value); + value += step; + } + } + + template >)> + inline void arange_assign_to(xexpression& e, U start, X step) noexcept + { + auto& buf = e.derived_cast().storage(); + using size_type = decltype(buf.size()); + using mult_type = get_mult_type; + for(size_type i = 0; i < buf.size(); ++i) + { + buf[i] = static_cast(start + step * mult_type(i)); + } + } + + template + class arange_generator { public: - using value_type = T; + using value_type = R; + using step_type = S; - arange_impl(T start, T stop, T step) + arange_generator(T start, T stop, S step) : m_start(start), m_stop(stop), m_step(step) { } template - inline T operator()(Args... args) const + inline R operator()(Args... args) const { return access_impl(args...); } template - inline T element(It first, It) const + inline R element(It first, It) const { - return m_start + m_step * T(*first); + // Avoids warning when T = char (because char + char => int!) + using mult_type = get_mult_type; + return static_cast(m_start + m_step * mult_type(*first)); } template inline void assign_to(xexpression& e) const noexcept { - auto& de = e.derived_cast(); - value_type value = m_start; - - for (auto& el : de.storage()) - { - el = value; - value += m_step; - } + arange_assign_to(e, m_start, m_step); } private: - value_type m_start; - value_type m_stop; - value_type m_step; + T m_start; + T m_stop; + step_type m_step; template - inline T access_impl(T1 t, Args...) const + inline R access_impl(T1 t, Args...) const { - return m_start + m_step * T(t); + using mult_type = get_mult_type; + return static_cast(m_start + m_step * mult_type(t)); } - inline T access_impl() const + inline R access_impl() const { - return m_start; + return static_cast(m_start); } }; + template + using both_integer = xtl::conjunction, std::is_integral>; + + template >)> + inline auto arange_impl(T start, T stop, S step = 1) noexcept + { + std::size_t shape = static_cast(std::ceil((stop - start) / step)); + return detail::make_xgenerator(detail::arange_generator(start, stop, step), {shape}); + } + + template )> + inline auto arange_impl(T start, T stop, S step = 1) noexcept + { + bool empty_cond = (stop - start) / step <= 0; + std::size_t shape = 0; + if(!empty_cond) + { + shape = stop > start ? static_cast((stop - start + step - S(1)) / step) + : static_cast((start - stop - step - S(1)) / -step); + } + return detail::make_xgenerator(detail::arange_generator(start, stop, step), {shape}); + } + template class fn_impl { @@ -301,12 +375,12 @@ namespace xt inline T operator()(const It& /*begin*/, const It& end) const { using lvalue_type = typename std::iterator_traits::value_type; - return *(end - 1) == *(end - 2) + static_cast(static_cast(m_k)) ? T(1) : T(0); + return *(end - 1) == *(end - 2) + static_cast(m_k) ? T(1) : T(0); } private: - int m_k; + std::ptrdiff_t m_k; }; } @@ -348,11 +422,10 @@ namespace xt * @tparam T value_type of xexpression * @return xgenerator that generates the values on access */ - template - inline auto arange(T start, T stop, T step = 1) noexcept + template + inline auto arange(T start, T stop, S step = 1) noexcept { - std::size_t shape = static_cast(std::ceil((stop - start) / step)); - return detail::make_xgenerator(detail::arange_impl(start, stop, step), {shape}); + return detail::arange_impl(start, stop, step); } /** @@ -381,8 +454,8 @@ namespace xt inline auto linspace(T start, T stop, std::size_t num_samples = 50, bool endpoint = true) noexcept { using fp_type = std::common_type_t; - fp_type step = fp_type(stop - start) / fp_type(num_samples - (endpoint ? 1 : 0)); - return cast(detail::make_xgenerator(detail::arange_impl(fp_type(start), fp_type(stop), step), {num_samples})); + fp_type step = fp_type(stop - start) / std::fmax(fp_type(1), fp_type(num_samples - (endpoint ? 1 : 0))); + return detail::make_xgenerator(detail::arange_generator(fp_type(start), fp_type(stop), step), {num_samples}); } /** @@ -398,7 +471,7 @@ namespace xt template inline auto logspace(T start, T stop, std::size_t num_samples, T base = 10, bool endpoint = true) noexcept { - return cast(pow(std::move(base), linspace(start, stop, num_samples, endpoint))); + return pow(std::move(base), linspace(start, stop, num_samples, endpoint)); } namespace detail @@ -409,7 +482,7 @@ namespace xt public: using size_type = std::size_t; - using value_type = promote_type_t::value_type...>; + using value_type = xtl::promote_type_t::value_type...>; inline concatenate_impl(std::tuple&& t, size_type axis) : m_t(t), m_axis(axis) @@ -468,7 +541,7 @@ namespace xt public: using size_type = std::size_t; - using value_type = promote_type_t::value_type...>; + using value_type = xtl::promote_type_t::value_type...>; inline stack_impl(std::tuple&& t, size_type axis) : m_t(t), m_axis(axis) @@ -569,11 +642,28 @@ namespace xt inline auto concatenate(std::tuple&& t, std::size_t axis = 0) { using shape_type = promote_shape_t::shape_type...>; - shape_type new_shape = xtl::forward_sequence(std::get<0>(t).shape()); + using source_shape_type = decltype(std::get<0>(t).shape()); + shape_type new_shape = xtl::forward_sequence(std::get<0>(t).shape()); + + auto check_shape = [&axis, &new_shape](auto& arr) { + std::size_t s = new_shape.size(); + bool res = s == arr.dimension(); + for(std::size_t i = 0; i < s; ++i) + { + res = res && (i == axis || new_shape[i] == arr.shape(i)); + } + if(!res) + { + throw_concatenate_error(new_shape, arr.shape()); + } + }; + for_each(check_shape, t); + auto shape_at_axis = [&axis](std::size_t prev, auto& arr) -> std::size_t { return prev + arr.shape()[axis]; }; new_shape[axis] += accumulate(shape_at_axis, std::size_t(0), t) - new_shape[axis]; + return detail::make_xgenerator(detail::concatenate_impl(std::forward>(t), axis), new_shape); } @@ -620,7 +710,8 @@ namespace xt inline auto stack(std::tuple&& t, std::size_t axis = 0) { using shape_type = promote_shape_t::shape_type...>; - auto new_shape = detail::add_axis(xtl::forward_sequence(std::get<0>(t).shape()), axis, sizeof...(CT)); + using source_shape_type = decltype(std::get<0>(t).shape()); + auto new_shape = detail::add_axis(xtl::forward_sequence(std::get<0>(t).shape()), axis, sizeof...(CT)); return detail::make_xgenerator(detail::stack_impl(std::forward>(t), axis), new_shape); } diff --git a/vendor/xtensor/include/xtensor/xcomplex.hpp b/vendor/xtensor/include/xtensor/xcomplex.hpp index e47842aa1..5bae3266d 100644 --- a/vendor/xtensor/include/xtensor/xcomplex.hpp +++ b/vendor/xtensor/include/xtensor/xcomplex.hpp @@ -1,5 +1,6 @@ /*************************************************************************** -* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * @@ -20,7 +21,6 @@ namespace xt { - /****************************** * real and imag declarations * ******************************/ @@ -61,7 +61,7 @@ namespace xt template static inline decltype(auto) real(E&& e) noexcept { - return e; + return std::forward(e); } template @@ -75,15 +75,15 @@ namespace xt struct complex_expression_helper { template - static inline auto real(E&& e) noexcept + static inline decltype(auto) real(E&& e) noexcept { - return detail::complex_helper::value_type>::value>::real(e); + return detail::complex_helper::value_type>::value>::real(std::forward(e)); } template - static inline auto imag(E&& e) noexcept + static inline decltype(auto) imag(E&& e) noexcept { - return detail::complex_helper::value_type>::value>::imag(e); + return detail::complex_helper::value_type>::value>::imag(std::forward(e)); } }; @@ -132,56 +132,70 @@ namespace xt return detail::complex_expression_helper>::value>::imag(std::forward(e)); } -#define UNARY_COMPLEX_FUNCTOR(NAME) \ - template \ +#define UNARY_COMPLEX_FUNCTOR(NS, NAME) \ struct NAME##_fun \ { \ - using argument_type = T; \ - using result_type = decltype(std::NAME(std::declval())); \ - constexpr result_type operator()(const T& t) const \ + template \ + constexpr auto operator()(const T& t) const \ { \ - using std::NAME; \ + using NS::NAME; \ + return NAME(t); \ + } \ + \ + template \ + constexpr auto simd_apply(const B& t) const \ + { \ + using NS::NAME; \ return NAME(t); \ } \ } namespace math { - UNARY_COMPLEX_FUNCTOR(norm); - UNARY_COMPLEX_FUNCTOR(arg); - namespace detail { - // libc++ (OSX) conj is unfortunately broken and returns - // std::complex instead of T. template - constexpr T conj(const T& c) - { - return c; - } - - template - constexpr std::complex conj(const std::complex& c) + constexpr std::complex conj_impl(const std::complex& c) { return std::complex(c.real(), -c.imag()); } + +#ifdef XTENSOR_USE_XSIMD + template + constexpr X conj_impl(const xsimd::simd_complex_batch& z) + { + return xsimd::conj(z); + } + + template + struct not_complex_batch + : xtl::negation, T>> + { + }; + + // libc++ (OSX) conj is unfortunately broken and returns + // std::complex instead of T. + // This function must be deactivated for complex batches, + // otherwise it will be a better match than the previous one. + template )> + constexpr T conj_impl(const T& c) + { + return c; + } +#else + // libc++ (OSX) conj is unfortunately broken and returns + // std::complex instead of T. + template + constexpr T conj_impl(const T& c) + { + return c; + } +#endif } - template - struct conj_fun - { - using argument_type = T; - using result_type = decltype(detail::conj(std::declval())); - using simd_value_type = xsimd::simd_type; - constexpr result_type operator()(const T& t) const - { - return detail::conj(t); - } - constexpr simd_value_type simd_apply(const simd_value_type& t) const - { - return detail::conj(t); - } - }; + UNARY_COMPLEX_FUNCTOR(std, norm); + UNARY_COMPLEX_FUNCTOR(std, arg); + UNARY_COMPLEX_FUNCTOR(detail, conj_impl); } #undef UNARY_COMPLEX_FUNCTOR @@ -194,10 +208,8 @@ namespace xt template inline auto conj(E&& e) noexcept { - using value_type = typename std::decay_t::value_type; - using functor = math::conj_fun; - using result_type = typename functor::result_type; - using type = xfunction>; + using functor = math::conj_impl_fun; + using type = xfunction>; return type(functor(), std::forward(e)); } @@ -208,10 +220,8 @@ namespace xt template inline auto arg(E&& e) noexcept { - using value_type = typename std::decay_t::value_type; - using functor = math::arg_fun; - using result_type = typename functor::result_type; - using type = xfunction>; + using functor = math::arg_fun; + using type = xfunction>; return type(functor(), std::forward(e)); } @@ -241,10 +251,8 @@ namespace xt template inline auto norm(E&& e) noexcept { - using value_type = typename std::decay_t::value_type; - using functor = math::norm_fun; - using result_type = typename functor::result_type; - using type = xfunction>; + using functor = math::norm_fun; + using type = xfunction>; return type(functor(), std::forward(e)); } } diff --git a/vendor/xtensor/include/xtensor/xcontainer.hpp b/vendor/xtensor/include/xtensor/xcontainer.hpp index 80df1907f..129016a7b 100644 --- a/vendor/xtensor/include/xtensor/xcontainer.hpp +++ b/vendor/xtensor/include/xtensor/xcontainer.hpp @@ -1,5 +1,6 @@ /*************************************************************************** -* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * @@ -11,13 +12,13 @@ #include #include -#include #include #include #include #include +#include "xaccessible.hpp" #include "xiterable.hpp" #include "xiterator.hpp" #include "xmath.hpp" @@ -36,8 +37,6 @@ namespace xt using const_stepper = xstepper; }; -#define DL XTENSOR_DEFAULT_LAYOUT - namespace detail { template @@ -56,7 +55,6 @@ namespace xt template using allocator_type_t = typename detail::allocator_type_impl::type; - /** * @class xcontainer * @brief Base class for dense multidimensional containers. @@ -69,7 +67,8 @@ namespace xt * provides the interface. */ template - class xcontainer : private xiterable + class xcontainer : public xcontiguous_iterable, + private xaccessible { public: @@ -79,15 +78,14 @@ namespace xt using storage_type = typename inner_types::storage_type; using allocator_type = allocator_type_t>; using value_type = typename storage_type::value_type; - using reference = std::conditional_t::value, - typename storage_type::const_reference, - typename storage_type::reference>; - using const_reference = typename storage_type::const_reference; + using reference = typename inner_types::reference; + using const_reference = typename inner_types::const_reference; using pointer = typename storage_type::pointer; using const_pointer = typename storage_type::const_pointer; - using size_type = typename storage_type::size_type; + using size_type = typename inner_types::size_type; using difference_type = typename storage_type::difference_type; - using simd_value_type = xsimd::simd_type; + using simd_value_type = xt_simd::simd_type; + using bool_load_type = xt::bool_load_type; using shape_type = typename inner_types::shape_type; using strides_type = typename inner_types::strides_type; @@ -97,24 +95,31 @@ namespace xt using inner_strides_type = typename inner_types::inner_strides_type; using inner_backstrides_type = typename inner_types::inner_backstrides_type; - using iterable_base = xiterable; + using iterable_base = xcontiguous_iterable; using stepper = typename iterable_base::stepper; using const_stepper = typename iterable_base::const_stepper; + using accessible_base = xaccessible; + static constexpr layout_type static_layout = inner_types::layout; static constexpr bool contiguous_layout = static_layout != layout_type::dynamic; - using data_alignment = xsimd::container_alignment_t; - using simd_type = xsimd::simd_type; + using data_alignment = xt_simd::container_alignment_t; + using simd_type = xt_simd::simd_type; + + using storage_iterator = typename iterable_base::storage_iterator; + using const_storage_iterator = typename iterable_base::const_storage_iterator; + using reverse_storage_iterator = typename iterable_base::reverse_storage_iterator; + using const_reverse_storage_iterator = typename iterable_base::const_reverse_storage_iterator; static_assert(static_layout != layout_type::any, "Container layout can never be layout_type::any!"); size_type size() const noexcept; - constexpr size_type dimension() const noexcept; + XTENSOR_CONSTEXPR_RETURN size_type dimension() const noexcept; - constexpr const inner_shape_type& shape() const noexcept; - constexpr const inner_strides_type& strides() const noexcept; - constexpr const inner_backstrides_type& backstrides() const noexcept; + XTENSOR_CONSTEXPR_RETURN const inner_shape_type& shape() const noexcept; + XTENSOR_CONSTEXPR_RETURN const inner_strides_type& strides() const noexcept; + XTENSOR_CONSTEXPR_RETURN const inner_backstrides_type& backstrides() const noexcept; template void fill(const T& value); @@ -125,29 +130,17 @@ namespace xt template const_reference operator()(Args... args) const; - template - reference at(Args... args); - - template - const_reference at(Args... args) const; - template reference unchecked(Args... args); template const_reference unchecked(Args... args) const; - template - disable_integral_t operator[](const S& index); - template - reference operator[](std::initializer_list index); - reference operator[](size_type i); - - template - disable_integral_t operator[](const S& index) const; - template - const_reference operator[](std::initializer_list index) const; - const_reference operator[](size_type i) const; + using accessible_base::shape; + using accessible_base::at; + using accessible_base::operator[]; + using accessible_base::periodic; + using accessible_base::in_bounds; template reference element(It first, It last); @@ -165,8 +158,7 @@ namespace xt bool broadcast_shape(S& shape, bool reuse_cache = false) const; template - bool is_trivial_broadcast(const S& strides) const noexcept; - + bool has_linear_assign(const S& strides) const noexcept; template stepper stepper_begin(const S& shape) noexcept; template @@ -180,149 +172,30 @@ namespace xt reference data_element(size_type i); const_reference data_element(size_type i) const; - template - using simd_return_type = xsimd::simd_return_type; + template + using simd_return_type = xt_simd::simd_return_type; - template + template void store_simd(size_type i, const simd& e); - template - simd_return_type load_simd(size_type i) const; + template ::size> + container_simd_return_type_t + /*simd_return_type*/ load_simd(size_type i) const; -#if defined(_MSC_VER) && _MSC_VER >= 1910 - // Workaround for compiler bug in Visual Studio 2017 with respect to alias templates with non-type parameters. - template - using layout_iterator = xiterator; - template - using const_layout_iterator = xiterator; - template - using reverse_layout_iterator = std::reverse_iterator>; - template - using const_reverse_layout_iterator = std::reverse_iterator>; -#else - template - using layout_iterator = typename iterable_base::template layout_iterator; - template - using const_layout_iterator = typename iterable_base::template const_layout_iterator; - template - using reverse_layout_iterator = typename iterable_base::template reverse_layout_iterator; - template - using const_reverse_layout_iterator = typename iterable_base::template const_reverse_layout_iterator; -#endif - - template - using broadcast_iterator = typename iterable_base::template broadcast_iterator; - template - using const_broadcast_iterator = typename iterable_base::template const_broadcast_iterator; - template - using reverse_broadcast_iterator = typename iterable_base::template reverse_broadcast_iterator; - template - using const_reverse_broadcast_iterator = typename iterable_base::template const_reverse_broadcast_iterator; - - using storage_iterator = typename storage_type::iterator; - using const_storage_iterator = typename storage_type::const_iterator; - using reverse_storage_iterator = typename storage_type::reverse_iterator; - using const_reverse_storage_iterator = typename storage_type::const_reverse_iterator; - - template - using select_iterator_impl = std::conditional_t; - - template - using select_iterator = select_iterator_impl>; - template - using select_const_iterator = select_iterator_impl>; - template - using select_reverse_iterator = select_iterator_impl>; - template - using select_const_reverse_iterator = select_iterator_impl>; - - using iterator = select_iterator

; - using const_iterator = select_const_iterator
; - using reverse_iterator = select_reverse_iterator
; - using const_reverse_iterator = select_const_reverse_iterator
; - - template - select_iterator begin() noexcept; - template - select_iterator end() noexcept; - - template - select_const_iterator begin() const noexcept; - template - select_const_iterator end() const noexcept; - template - select_const_iterator cbegin() const noexcept; - template - select_const_iterator cend() const noexcept; - - template - select_reverse_iterator rbegin() noexcept; - template - select_reverse_iterator rend() noexcept; - - template - select_const_reverse_iterator rbegin() const noexcept; - template - select_const_reverse_iterator rend() const noexcept; - template - select_const_reverse_iterator crbegin() const noexcept; - template - select_const_reverse_iterator crend() const noexcept; - - template - broadcast_iterator begin(const S& shape) noexcept; - template - broadcast_iterator end(const S& shape) noexcept; - - template - const_broadcast_iterator begin(const S& shape) const noexcept; - template - const_broadcast_iterator end(const S& shape) const noexcept; - template - const_broadcast_iterator cbegin(const S& shape) const noexcept; - template - const_broadcast_iterator cend(const S& shape) const noexcept; - - - template - reverse_broadcast_iterator rbegin(const S& shape) noexcept; - template - reverse_broadcast_iterator rend(const S& shape) noexcept; - - template - const_reverse_broadcast_iterator rbegin(const S& shape) const noexcept; - template - const_reverse_broadcast_iterator rend(const S& shape) const noexcept; - template - const_reverse_broadcast_iterator crbegin(const S& shape) const noexcept; - template - const_reverse_broadcast_iterator crend(const S& shape) const noexcept; - - template storage_iterator storage_begin() noexcept; - template storage_iterator storage_end() noexcept; - template const_storage_iterator storage_begin() const noexcept; - template const_storage_iterator storage_end() const noexcept; - template const_storage_iterator storage_cbegin() const noexcept; - template const_storage_iterator storage_cend() const noexcept; - template reverse_storage_iterator storage_rbegin() noexcept; - template reverse_storage_iterator storage_rend() noexcept; - template const_reverse_storage_iterator storage_rbegin() const noexcept; - template const_reverse_storage_iterator storage_rend() const noexcept; - template const_reverse_storage_iterator storage_crbegin() const noexcept; - template const_reverse_storage_iterator storage_crend() const noexcept; using container_iterator = storage_iterator; @@ -341,8 +214,8 @@ namespace xt container_iterator data_xbegin() noexcept; const_container_iterator data_xbegin() const noexcept; - container_iterator data_xend(layout_type l) noexcept; - const_container_iterator data_xend(layout_type l) const noexcept; + container_iterator data_xend(layout_type l, size_type offset) noexcept; + const_container_iterator data_xend(layout_type l, size_type offset) const noexcept; protected: @@ -352,21 +225,19 @@ namespace xt private: - friend class xiterable; - friend class xconst_iterable; - - template - friend class xstepper; - template - It data_xend_impl(It end, layout_type l) const noexcept; + It data_xend_impl(It begin, layout_type l, size_type offset) const noexcept; inner_shape_type& mutable_shape(); inner_strides_type& mutable_strides(); inner_backstrides_type& mutable_backstrides(); - }; -#undef DL + template + friend class xstepper; + + friend class xaccessible; + friend class xconst_accessible; + }; /** * @class xstrided_container @@ -409,6 +280,9 @@ namespace xt template void reshape(S&& shape, layout_type layout = base_type::static_layout); + template + void reshape(std::initializer_list shape, layout_type layout = base_type::static_layout); + layout_type layout() const noexcept; protected: @@ -423,6 +297,7 @@ namespace xt xstrided_container& operator=(xstrided_container&&) = default; explicit xstrided_container(inner_shape_type&&, inner_strides_type&&) noexcept; + explicit xstrided_container(inner_shape_type&&, inner_strides_type&&, inner_backstrides_type&&, layout_type&&) noexcept; inner_shape_type& shape_impl() noexcept; const inner_shape_type& shape_impl() const noexcept; @@ -433,6 +308,16 @@ namespace xt inner_backstrides_type& backstrides_impl() noexcept; const inner_backstrides_type& backstrides_impl() const noexcept; + template + void reshape_impl(S&& shape, std::true_type, layout_type layout = base_type::static_layout); + template + void reshape_impl(S&& shape, std::false_type, layout_type layout = base_type::static_layout); + + layout_type& mutable_layout() noexcept + { + return m_layout; + } + private: inner_shape_type m_shape; @@ -447,9 +332,9 @@ namespace xt template template - inline It xcontainer::data_xend_impl(It end, layout_type l) const noexcept + inline It xcontainer::data_xend_impl(It begin, layout_type l, size_type offset) const noexcept { - return strided_data_end(*this, end, l); + return strided_data_end(*this, begin, l, offset); } template @@ -487,7 +372,7 @@ namespace xt * Returns the number of dimensions of the container. */ template - inline constexpr auto xcontainer::dimension() const noexcept -> size_type + XTENSOR_CONSTEXPR_RETURN auto xcontainer::dimension() const noexcept -> size_type { return shape().size(); } @@ -496,7 +381,7 @@ namespace xt * Returns the shape of the container. */ template - constexpr inline auto xcontainer::shape() const noexcept -> const inner_shape_type& + XTENSOR_CONSTEXPR_RETURN auto xcontainer::shape() const noexcept -> const inner_shape_type& { return derived_cast().shape_impl(); } @@ -505,7 +390,7 @@ namespace xt * Returns the strides of the container. */ template - constexpr inline auto xcontainer::strides() const noexcept -> const inner_strides_type& + XTENSOR_CONSTEXPR_RETURN auto xcontainer::strides() const noexcept -> const inner_strides_type& { return derived_cast().strides_impl(); } @@ -514,7 +399,7 @@ namespace xt * Returns the backstrides of the container. */ template - constexpr inline auto xcontainer::backstrides() const noexcept -> const inner_backstrides_type& + XTENSOR_CONSTEXPR_RETURN auto xcontainer::backstrides() const noexcept -> const inner_backstrides_type& { return derived_cast().backstrides_impl(); } @@ -548,7 +433,7 @@ namespace xt { XTENSOR_TRY(check_index(shape(), args...)); XTENSOR_CHECK_DIMENSION(shape(), args...); - size_type index = xt::data_offset(strides(), static_cast(args)...); + size_type index = xt::data_offset(strides(), static_cast(args)...); return storage()[index]; } @@ -564,44 +449,10 @@ namespace xt { XTENSOR_TRY(check_index(shape(), args...)); XTENSOR_CHECK_DIMENSION(shape(), args...); - size_type index = xt::data_offset(strides(), static_cast(args)...); + size_type index = xt::data_offset(strides(), static_cast(args)...); return storage()[index]; } - /** - * Returns a reference to the element at the specified position in the container, - * after dimension and bounds checking. - * @param args a list of indices specifying the position in the container. Indices - * must be unsigned integers, the number of indices should be equal to the number of dimensions - * of the container. - * @exception std::out_of_range if the number of argument is greater than the number of dimensions - * or if indices are out of bounds. - */ - template - template - inline auto xcontainer::at(Args... args) -> reference - { - check_access(shape(), static_cast(args)...); - return this->operator()(args...); - } - - /** - * Returns a constant reference to the element at the specified position in the container, - * after dimension and bounds checking. - * @param args a list of indices specifying the position in the container. Indices - * must be unsigned integers, the number of indices should be equal to the number of dimensions - * of the container. - * @exception std::out_of_range if the number of argument is greater than the number of dimensions - * or if indices are out of bounds. - */ - template - template - inline auto xcontainer::at(Args... args) const -> const_reference - { - check_access(shape(), static_cast(args)...); - return this->operator()(args...); - } - /** * Returns a reference to the element at the specified position in the container. * @param args a list of indices specifying the position in the container. Indices @@ -625,7 +476,7 @@ namespace xt template inline auto xcontainer::unchecked(Args... args) -> reference { - size_type index = xt::unchecked_data_offset(strides(), static_cast(args)...); + size_type index = xt::unchecked_data_offset(strides(), static_cast(args)...); return storage()[index]; } @@ -652,64 +503,10 @@ namespace xt template inline auto xcontainer::unchecked(Args... args) const -> const_reference { - size_type index = xt::unchecked_data_offset(strides(), static_cast(args)...); + size_type index = xt::unchecked_data_offset(strides(), static_cast(args)...); return storage()[index]; } - /** - * Returns a reference to the element at the specified position in the container. - * @param index a sequence of indices specifying the position in the container. Indices - * must be unsigned integers, the number of indices in the list should be equal or greater - * than the number of dimensions of the container. - */ - template - template - inline auto xcontainer::operator[](const S& index) - -> disable_integral_t - { - return element(index.cbegin(), index.cend()); - } - - template - template - inline auto xcontainer::operator[](std::initializer_list index) -> reference - { - return element(index.begin(), index.end()); - } - - template - inline auto xcontainer::operator[](size_type i) -> reference - { - return operator()(i); - } - - /** - * Returns a constant reference to the element at the specified position in the container. - * @param index a sequence of indices specifying the position in the container. Indices - * must be unsigned integers, the number of indices in the list should be equal or greater - * than the number of dimensions of the container. - */ - template - template - inline auto xcontainer::operator[](const S& index) const - -> disable_integral_t - { - return element(index.cbegin(), index.cend()); - } - - template - template - inline auto xcontainer::operator[](std::initializer_list index) const -> const_reference - { - return element(index.begin(), index.end()); - } - - template - inline auto xcontainer::operator[](size_type i) const -> const_reference - { - return operator()(i); - } - /** * Returns a reference to the element at the specified position in the container. * @param first iterator starting the sequence of indices @@ -809,397 +606,19 @@ namespace xt } /** - * Compares the specified strides with those of the container to see whether - * the broadcasting is trivial. - * @return a boolean indicating whether the broadcasting is trivial + * Checks whether the xcontainer can be linearly assigned to an expression + * with the specified strides. + * @return a boolean indicating whether a linear assign is possible */ template template - inline bool xcontainer::is_trivial_broadcast(const S& str) const noexcept + inline bool xcontainer::has_linear_assign(const S& str) const noexcept { return str.size() == strides().size() && std::equal(str.cbegin(), str.cend(), strides().begin()); } //@} - /**************** - * Iterator api * - ****************/ - - template - template - inline auto xcontainer::begin() noexcept -> select_iterator - { - return xtl::mpl::static_if([&](auto self) - { - return self(*this).template storage_begin(); - }, /*else*/ [&](auto self) - { - return self(*this).iterable_base::template begin(); - }); - } - - template - template - inline auto xcontainer::end() noexcept -> select_iterator - { - return xtl::mpl::static_if([&](auto self) - { - return self(*this).template storage_end(); - }, /*else*/ [&](auto self) - { - return self(*this).iterable_base::template end(); - }); - } - - template - template - inline auto xcontainer::begin() const noexcept -> select_const_iterator - { - return this->template cbegin(); - } - - template - template - inline auto xcontainer::end() const noexcept -> select_const_iterator - { - return this->template cend(); - } - - template - template - inline auto xcontainer::cbegin() const noexcept -> select_const_iterator - { - return xtl::mpl::static_if([&](auto self) - { - return self(*this).template storage_cbegin(); - }, /*else*/ [&](auto self) - { - return self(*this).iterable_base::template cbegin(); - }); - } - - template - template - inline auto xcontainer::cend() const noexcept -> select_const_iterator - { - return xtl::mpl::static_if([&](auto self) - { - return self(*this).template storage_cend(); - }, /*else*/ [&](auto self) - { - return self(*this).iterable_base::template cend(); - }); - } - - template - template - inline auto xcontainer::rbegin() noexcept -> select_reverse_iterator - { - return xtl::mpl::static_if([&](auto self) - { - return self(*this).template storage_rbegin(); - }, /*else*/ [&](auto self) - { - return self(*this).iterable_base::template rbegin(); - }); - } - - template - template - inline auto xcontainer::rend() noexcept -> select_reverse_iterator - { - return xtl::mpl::static_if([&](auto self) - { - return self(*this).template storage_rend(); - }, /*else*/ [&](auto self) - { - return self(*this).iterable_base::template rend(); - }); - } - - template - template - inline auto xcontainer::rbegin() const noexcept -> select_const_reverse_iterator - { - return this->template crbegin(); - } - - template - template - inline auto xcontainer::rend() const noexcept -> select_const_reverse_iterator - { - return this->template crend(); - } - - template - template - inline auto xcontainer::crbegin() const noexcept -> select_const_reverse_iterator - { - return xtl::mpl::static_if([&](auto self) - { - return self(*this).template storage_crbegin(); - }, /*else*/ [&](auto self) - { - return self(*this).iterable_base::template crbegin(); - }); - } - - template - template - inline auto xcontainer::crend() const noexcept -> select_const_reverse_iterator - { - return xtl::mpl::static_if([&](auto self) - { - return self(*this).template storage_crend(); - }, /*else*/ [&](auto self) - { - return self(*this).iterable_base::template crend(); - }); - } - - /***************************** - * Broadcasting iterator api * - *****************************/ - - template - template - inline auto xcontainer::begin(const S& shape) noexcept -> broadcast_iterator - { - return iterable_base::template begin(shape); - } - - template - template - inline auto xcontainer::end(const S& shape) noexcept -> broadcast_iterator - { - return iterable_base::template end(shape); - } - - template - template - inline auto xcontainer::begin(const S& shape) const noexcept -> const_broadcast_iterator - { - return iterable_base::template begin(shape); - } - - template - template - inline auto xcontainer::end(const S& shape) const noexcept -> const_broadcast_iterator - { - return iterable_base::template end(shape); - } - - template - template - inline auto xcontainer::cbegin(const S& shape) const noexcept -> const_broadcast_iterator - { - return iterable_base::template cbegin(shape); - } - - template - template - inline auto xcontainer::cend(const S& shape) const noexcept -> const_broadcast_iterator - { - return iterable_base::template cend(shape); - } - - template - template - inline auto xcontainer::rbegin(const S& shape) noexcept -> reverse_broadcast_iterator - { - return iterable_base::template rbegin(shape); - } - - template - template - inline auto xcontainer::rend(const S& shape) noexcept -> reverse_broadcast_iterator - { - return iterable_base::template rend(shape); - } - - template - template - inline auto xcontainer::rbegin(const S& shape) const noexcept -> const_reverse_broadcast_iterator - { - return iterable_base::template rbegin(shape); - } - - template - template - inline auto xcontainer::rend(const S& shape) const noexcept -> const_reverse_broadcast_iterator - { - return iterable_base::template rend(shape); - } - - template - template - inline auto xcontainer::crbegin(const S& shape) const noexcept -> const_reverse_broadcast_iterator - { - return iterable_base::template crbegin(shape); - } - - template - template - inline auto xcontainer::crend(const S& shape) const noexcept -> const_reverse_broadcast_iterator - { - return iterable_base::template crend(shape); - } - - /*********************** - * Linear iterator api * - ***********************/ - - template - template - inline auto xcontainer::storage_begin() noexcept -> storage_iterator - { - return storage().begin(); - } - - template - template - inline auto xcontainer::storage_end() noexcept -> storage_iterator - { - return storage().end(); - } - - template - template - inline auto xcontainer::storage_begin() const noexcept -> const_storage_iterator - { - return storage().begin(); - } - - template - template - inline auto xcontainer::storage_end() const noexcept -> const_storage_iterator - { - return storage().end(); - } - - template - template - inline auto xcontainer::storage_cbegin() const noexcept -> const_storage_iterator - { - return storage().cbegin(); - } - - template - template - inline auto xcontainer::storage_cend() const noexcept -> const_storage_iterator - { - return storage().cend(); - } - - template - template - inline auto xcontainer::storage_rbegin() noexcept -> reverse_storage_iterator - { - return storage().rbegin(); - } - - template - template - inline auto xcontainer::storage_rend() noexcept -> reverse_storage_iterator - { - return storage().rend(); - } - - template - template - inline auto xcontainer::storage_rbegin() const noexcept -> const_reverse_storage_iterator - { - return storage().rbegin(); - } - - template - template - inline auto xcontainer::storage_rend() const noexcept -> const_reverse_storage_iterator - { - return storage().rend(); - } - - template - template - inline auto xcontainer::storage_crbegin() const noexcept -> const_reverse_storage_iterator - { - return storage().crbegin(); - } - - template - template - inline auto xcontainer::storage_crend() const noexcept -> const_reverse_storage_iterator - { - return storage().crend(); - } - - /*************** - * stepper api * - ***************/ - - template - template - inline auto xcontainer::stepper_begin(const S& shape) noexcept -> stepper - { - size_type offset = shape.size() - dimension(); - return stepper(static_cast(this), data_xbegin(), offset); - } - - template - template - inline auto xcontainer::stepper_end(const S& shape, layout_type l) noexcept -> stepper - { - size_type offset = shape.size() - dimension(); - return stepper(static_cast(this), data_xend(l), offset); - } - - template - template - inline auto xcontainer::stepper_begin(const S& shape) const noexcept -> const_stepper - { - size_type offset = shape.size() - dimension(); - return const_stepper(static_cast(this), data_xbegin(), offset); - } - - template - template - inline auto xcontainer::stepper_end(const S& shape, layout_type l) const noexcept -> const_stepper - { - size_type offset = shape.size() - dimension(); - return const_stepper(static_cast(this), data_xend(l), offset); - } - - template - inline auto xcontainer::data_xbegin() noexcept -> container_iterator - { - return storage().begin(); - } - - template - inline auto xcontainer::data_xbegin() const noexcept -> const_container_iterator - { - return storage().begin(); - } - - template - inline auto xcontainer::data_xend(layout_type l) noexcept -> container_iterator - { - return data_xend_impl(storage().end(), l); - } - - template - inline auto xcontainer::data_xend(layout_type l) const noexcept -> const_container_iterator - { - return data_xend_impl(storage().end(), l); - } - - template - inline auto xcontainer::derived_cast() & noexcept -> derived_type& - { - return *static_cast(this); - } - template inline auto xcontainer::derived_cast() const & noexcept -> const derived_type& { @@ -1224,20 +643,160 @@ namespace xt return storage()[i]; } + /*************** + * stepper api * + ***************/ + + template + template + inline auto xcontainer::stepper_begin(const S& shape) noexcept -> stepper + { + size_type offset = shape.size() - dimension(); + return stepper(static_cast(this), data_xbegin(), offset); + } + + template + template + inline auto xcontainer::stepper_end(const S& shape, layout_type l) noexcept -> stepper + { + size_type offset = shape.size() - dimension(); + return stepper(static_cast(this), data_xend(l, offset), offset); + } + + template + template + inline auto xcontainer::stepper_begin(const S& shape) const noexcept -> const_stepper + { + size_type offset = shape.size() - dimension(); + return const_stepper(static_cast(this), data_xbegin(), offset); + } + + template + template + inline auto xcontainer::stepper_end(const S& shape, layout_type l) const noexcept -> const_stepper + { + size_type offset = shape.size() - dimension(); + return const_stepper(static_cast(this), data_xend(l, offset), offset); + } + + template + inline auto xcontainer::data_xbegin() noexcept -> container_iterator + { + return storage().begin(); + } + + template + inline auto xcontainer::data_xbegin() const noexcept -> const_container_iterator + { + return storage().cbegin(); + } + + template + inline auto xcontainer::data_xend(layout_type l, size_type offset) noexcept -> container_iterator + { + return data_xend_impl(storage().begin(), l, offset); + } + + template + inline auto xcontainer::data_xend(layout_type l, size_type offset) const noexcept -> const_container_iterator + { + return data_xend_impl(storage().cbegin(), l, offset); + } + template template inline void xcontainer::store_simd(size_type i, const simd& e) { using align_mode = driven_align_mode_t; - xsimd::store_simd(&(storage()[i]), e, align_mode()); + xt_simd::store_simd(&(storage()[i]), e, align_mode()); } template - template - inline auto xcontainer::load_simd(size_type i) const -> simd_return_type + template + inline auto xcontainer::load_simd(size_type i) const + -> container_simd_return_type_t + //-> simd_return_type { using align_mode = driven_align_mode_t; - return xsimd::load_simd(&(storage()[i]), align_mode()); + return xt_simd::load_simd(&(storage()[i]), align_mode()); + } + + template + inline auto xcontainer::storage_begin() noexcept -> storage_iterator + { + return storage().begin(); + } + + template + inline auto xcontainer::storage_end() noexcept -> storage_iterator + { + return storage().end(); + } + + template + inline auto xcontainer::storage_begin() const noexcept -> const_storage_iterator + { + return storage().begin(); + } + + template + inline auto xcontainer::storage_end() const noexcept -> const_storage_iterator + { + return storage().cend(); + } + + template + inline auto xcontainer::storage_cbegin() const noexcept -> const_storage_iterator + { + return storage().cbegin(); + } + + template + inline auto xcontainer::storage_cend() const noexcept -> const_storage_iterator + { + return storage().cend(); + } + + template + inline auto xcontainer::storage_rbegin() noexcept -> reverse_storage_iterator + { + return storage().rbegin(); + } + + template + inline auto xcontainer::storage_rend() noexcept -> reverse_storage_iterator + { + return storage().rend(); + } + + template + inline auto xcontainer::storage_rbegin() const noexcept -> const_reverse_storage_iterator + { + return storage().rbegin(); + } + + template + inline auto xcontainer::storage_rend() const noexcept -> const_reverse_storage_iterator + { + return storage().rend(); + } + + template + inline auto xcontainer::storage_crbegin() const noexcept -> const_reverse_storage_iterator + { + return storage().crbegin(); + } + + template + inline auto xcontainer::storage_crend() const noexcept -> const_reverse_storage_iterator + { + return storage().crend(); + } + + template + inline auto xcontainer::derived_cast() & noexcept -> derived_type& + { + return *static_cast(this); } /************************************* @@ -1248,7 +807,7 @@ namespace xt inline xstrided_container::xstrided_container() noexcept : base_type() { - m_shape = xtl::make_sequence(base_type::dimension(), 1); + m_shape = xtl::make_sequence(base_type::dimension(), 0); m_strides = xtl::make_sequence(base_type::dimension(), 0); m_backstrides = xtl::make_sequence(base_type::dimension(), 0); } @@ -1261,6 +820,12 @@ namespace xt adapt_strides(m_shape, m_strides, m_backstrides); } + template + inline xstrided_container::xstrided_container(inner_shape_type&& shape, inner_strides_type&& strides, inner_backstrides_type&& backstrides, layout_type&& layout) noexcept + : base_type(), m_shape(std::move(shape)), m_strides(std::move(strides)), m_backstrides(std::move(backstrides)), m_layout(std::move(layout)) + { + } + template inline auto xstrided_container::shape_impl() noexcept -> inner_shape_type& { @@ -1325,7 +890,9 @@ namespace xt } /** - * resizes the container. + * Resizes the container. + * @warning Contrary to STL containers like std::vector, resize + * does NOT preserve the container elements. * @param shape the new shape * @param force force reshaping, even if the shape stays the same (default: false) */ @@ -1333,22 +900,25 @@ namespace xt template inline void xstrided_container::resize(S&& shape, bool force) { - if (m_shape.size() != shape.size() || !std::equal(std::begin(shape), std::end(shape), std::begin(m_shape)) || force) + std::size_t dim = shape.size(); + if (m_shape.size() != dim || !std::equal(std::begin(shape), std::end(shape), std::begin(m_shape)) || force) { - if (m_layout == layout_type::dynamic || m_layout == layout_type::any) + if (D::static_layout == layout_type::dynamic && m_layout == layout_type::dynamic) { m_layout = XTENSOR_DEFAULT_LAYOUT; // fall back to default layout } - m_shape = xtl::forward_sequence(shape); - resize_container(m_strides, m_shape.size()); - resize_container(m_backstrides, m_shape.size()); - size_type data_size = compute_strides(m_shape, m_layout, m_strides, m_backstrides); + m_shape = xtl::forward_sequence(shape); + resize_container(m_strides, dim); + resize_container(m_backstrides, dim); + size_type data_size = compute_strides(m_shape, m_layout, m_strides, m_backstrides); detail::resize_data_container(this->storage(), data_size); } } /** - * resizes the container. + * Resizes the container. + * @warning Contrary to STL containers like std::vector, resize + * does NOT preserve the container elements. * @param shape the new shape * @param l the new layout_type */ @@ -1366,6 +936,8 @@ namespace xt /** * Resizes the container. + * @warning Contrary to STL containers like std::vector, resize + * does NOT preserve the container elements. * @param shape the new shape * @param strides the new strides */ @@ -1377,7 +949,7 @@ namespace xt { throw std::runtime_error("Cannot resize with custom strides when layout() is != layout_type::dynamic."); } - m_shape = xtl::forward_sequence(shape); + m_shape = xtl::forward_sequence(shape); m_strides = strides; resize_container(m_backstrides, m_strides.size()); adapt_strides(m_shape, m_strides, m_backstrides); @@ -1386,7 +958,14 @@ namespace xt } /** - * Reshapes the container and keeps old elements + * Reshapes the container and keeps old elements. The `shape` argument can have one of its value + * equal to `-1`, in this case the value is inferred from the number of elements in the container + * and the remaining values in the `shape`. + * \code{.cpp} + * xt::xarray a = { 1, 2, 3, 4, 5, 6, 7, 8 }; + * a.reshape({-1, 4}); + * //a.shape() is {2, 4} + * \endcode * @param shape the new shape (has to have same number of elements as the original container) * @param layout the layout to compute the strides (defaults to static layout of the container, * or for a container with dynamic layout to XTENSOR_DEFAULT_LAYOUT) @@ -1394,24 +973,74 @@ namespace xt template template inline void xstrided_container::reshape(S&& shape, layout_type layout) + { + reshape_impl(std::forward(shape), std::is_signed::value_type>>(), std::forward(layout)); + } + + template + template + inline void xstrided_container::reshape(std::initializer_list shape, layout_type layout) + { + using sh_type = rebind_container_t; + sh_type sh = xtl::make_sequence(shape.size()); + std::copy(shape.begin(), shape.end(), sh.begin()); + reshape_impl(std::move(sh), std::is_signed(), std::forward(layout)); + } + + template + template + inline void xstrided_container::reshape_impl(S&& shape, std::false_type /* is unsigned */, layout_type layout) { if (compute_size(shape) != this->size()) { throw std::runtime_error("Cannot reshape with incorrect number of elements. Do you mean to resize?"); } - if (layout == layout_type::dynamic || layout == layout_type::any) + if (D::static_layout == layout_type::dynamic && layout == layout_type::dynamic) { layout = XTENSOR_DEFAULT_LAYOUT; // fall back to default layout } - if (layout != base_type::static_layout && base_type::static_layout != layout_type::dynamic) + if (D::static_layout != layout_type::dynamic && layout != D::static_layout) { throw std::runtime_error("Cannot reshape with different layout if static layout != dynamic."); } m_layout = layout; - m_shape = xtl::forward_sequence(shape); + m_shape = xtl::forward_sequence(shape); resize_container(m_strides, m_shape.size()); resize_container(m_backstrides, m_shape.size()); - compute_strides(m_shape, m_layout, m_strides, m_backstrides); + compute_strides(m_shape, m_layout, m_strides, m_backstrides); + } + template + template + inline void xstrided_container::reshape_impl(S&& _shape, std::true_type /* is signed */, layout_type layout) + { + using value_type = typename std::decay_t::value_type; + if (this->size() % compute_size(_shape)) + { + throw std::runtime_error("Negative axis size cannot be inferred. Shape mismatch."); + } + std::decay_t shape = _shape; + value_type accumulator = 1; + std::size_t neg_idx = 0; + std::size_t i = 0; + for(auto it = shape.begin(); it != shape.end(); ++it, i++) + { + auto&& dim = *it; + if(dim < 0) + { + XTENSOR_ASSERT(dim == -1 && !neg_idx); + neg_idx = i; + } + accumulator *= dim; + } + if(accumulator < 0) + { + shape[neg_idx] = static_cast(this->size()) / std::abs(accumulator); + } + m_layout = layout; + m_shape = xtl::forward_sequence(shape); + resize_container(m_strides, m_shape.size()); + resize_container(m_backstrides, m_shape.size()); + compute_strides(m_shape, m_layout, m_strides, m_backstrides); } } diff --git a/vendor/xtensor/include/xtensor/xcsv.hpp b/vendor/xtensor/include/xtensor/xcsv.hpp index 4a2716d40..6a98fa449 100644 --- a/vendor/xtensor/include/xtensor/xcsv.hpp +++ b/vendor/xtensor/include/xtensor/xcsv.hpp @@ -1,5 +1,6 @@ /*************************************************************************** -* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * @@ -29,7 +30,7 @@ namespace xt using xcsv_tensor = xtensor_container, 2, layout_type::row_major>; template > - xcsv_tensor load_csv(std::istream& stream); + xcsv_tensor load_csv(std::istream& stream, const char delimiter = ',', const std::size_t skip_rows = 0, const ptrdiff_t max_rows = -1, const std::string comments = "#"); template void dump_csv(std::ostream& stream, const xexpression& e); @@ -49,6 +50,17 @@ namespace xt return res; } + template <> + inline std::string lexical_cast(const std::string& cell) + { + size_t first = cell.find_first_not_of(' '); + if (first == std::string::npos) + return cell; + + size_t last = cell.find_last_not_of(' '); + return cell.substr(first, last==std::string::npos?cell.size():last+1); + } + template <> inline float lexical_cast(const std::string& cell) { return std::stof(cell); } @@ -77,10 +89,10 @@ namespace xt inline unsigned long long lexical_cast(const std::string& cell) { return std::stoull(cell); } template - ST load_csv_row(std::istream& row_stream, OI output, std::string cell) + ST load_csv_row(std::istream& row_stream, OI output, std::string cell, const char delimiter = ',') { ST length = 0; - while (std::getline(row_stream, cell, ',')) + while (std::getline(row_stream, cell, delimiter)) { *output++ = lexical_cast(cell); ++length; @@ -94,9 +106,13 @@ namespace xt * * Returns an \ref xexpression for the parsed CSV * @param stream the input stream containing the CSV encoded values + * @param delimiter the character used to separate values. [default: ','] + * @param skip the first skip_rows lines. [default: 0] + * @param read max_rows lines of content after skip_rows lines; the default is to read all the lines. [default: -1] + * @param comments the string used to indicate the start of a comment. [default: "#"] */ template - xcsv_tensor load_csv(std::istream& stream) + xcsv_tensor load_csv(std::istream& stream, const char delimiter, const std::size_t skip_rows, const std::ptrdiff_t max_rows, const std::string comments) { using tensor_type = xcsv_tensor; using storage_type = typename tensor_type::storage_type; @@ -106,14 +122,27 @@ namespace xt using output_iterator = std::back_insert_iterator; storage_type data; - size_type nbrow = 0, nbcol = 0; + size_type nbrow = 0, nbcol = 0, nhead = 0; { output_iterator output(data); std::string row, cell; while (std::getline(stream, row)) { + if (nhead < skip_rows) + { + ++nhead; + continue; + } + if (std::equal(comments.begin(), comments.end(), row.begin())) + { + continue; + } + if (0 < max_rows && max_rows <= static_cast(nbrow)) + { + break; + } std::stringstream row_stream(row); - nbcol = detail::load_csv_row(row_stream, output, cell); + nbcol = detail::load_csv_row(row_stream, output, cell, delimiter); ++nbrow; } } diff --git a/vendor/xtensor/include/xtensor/xdynamic_view.hpp b/vendor/xtensor/include/xtensor/xdynamic_view.hpp new file mode 100644 index 000000000..345cb1420 --- /dev/null +++ b/vendor/xtensor/include/xtensor/xdynamic_view.hpp @@ -0,0 +1,704 @@ +/*************************************************************************** +* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* * +* Distributed under the terms of the BSD 3-Clause License. * +* * +* The full license is in the file LICENSE, distributed with this software. * +****************************************************************************/ + +#ifndef XTENSOR_DYNAMIC_VIEW_HPP +#define XTENSOR_DYNAMIC_VIEW_HPP + +#include +#include + +#include "xexpression.hpp" +#include "xiterable.hpp" +#include "xlayout.hpp" +#include "xsemantic.hpp" +#include "xstrided_view_base.hpp" + +namespace xt +{ + + template + class xdynamic_view; + + template + struct xcontainer_inner_types> + { + using xexpression_type = std::decay_t; + using undecay_expression = CT; + using reference = inner_reference_t; + using const_reference = typename xexpression_type::const_reference; + using size_type = typename xexpression_type::size_type; + using shape_type = std::decay_t; + using undecay_shape = S; + using storage_getter = FST; + using inner_storage_type = typename storage_getter::type; + using temporary_type = xarray, xexpression_type::static_layout>; + static constexpr layout_type layout = L; + }; + + template + struct xiterable_inner_types> + { + using inner_shape_type = S; + using inner_strides_type = inner_shape_type; + using inner_backstrides_type = inner_shape_type; + +#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ == 8 + constexpr static auto random_instantiation_var_for_gcc8_data_iface = has_data_interface>::value; + constexpr static auto random_instantiation_var_for_gcc8_has_strides = has_strides>::value; +#endif + + // TODO: implement efficient stepper specific to the dynamic_view + using const_stepper = xindexed_stepper, true>; + using stepper = xindexed_stepper, false>; + }; + + /**************************** + * xdynamic_view extensions * + ****************************/ + + namespace extension + { + template + struct xdynamic_view_base_impl; + + template + struct xdynamic_view_base_impl + { + using type = xtensor_empty_base; + }; + + template + struct xdynamic_view_base + : xdynamic_view_base_impl, CT, S, L, FST> + { + }; + + template + using xdynamic_view_base_t = typename xdynamic_view_base::type; + } + + /***************** + * xdynamic_view * + *****************/ + + namespace detail + { + template + class xfake_slice; + } + + template > + class xdynamic_view : public xview_semantic>, + public xiterable>, + public extension::xdynamic_view_base_t, + private xstrided_view_base> + { + public: + + using self_type = xdynamic_view; + using base_type = xstrided_view_base; + using semantic_base = xview_semantic; + using extension_base = extension::xdynamic_view_base_t; + using expression_tag = typename extension_base::expression_tag; + + using xexpression_type = typename base_type::xexpression_type; + using base_type::is_const; + + using value_type = typename base_type::value_type; + using reference = typename base_type::reference; + using const_reference = typename base_type::const_reference; + using pointer = typename base_type::pointer; + using const_pointer = typename base_type::const_pointer; + using size_type = typename base_type::size_type; + using difference_type = typename base_type::difference_type; + + using inner_storage_type = typename base_type::inner_storage_type; + using storage_type = typename base_type::storage_type; + + using iterable_base = xiterable; + using inner_shape_type = typename iterable_base::inner_shape_type; + using inner_strides_type = typename base_type::inner_strides_type; + using inner_backstrides_type = typename base_type::inner_backstrides_type; + + using shape_type = typename base_type::shape_type; + using strides_type = typename base_type::strides_type; + using backstrides_type = typename base_type::backstrides_type; + + using stepper = typename iterable_base::stepper; + using const_stepper = typename iterable_base::const_stepper; + + using base_type::static_layout; + using base_type::contiguous_layout; + + using temporary_type = typename xcontainer_inner_types::temporary_type; + using base_index_type = xindex_type_t; + + using simd_value_type = typename base_type::simd_value_type; + using bool_load_type = typename base_type::bool_load_type; + + using strides_vt = typename strides_type::value_type; + using slice_type = xtl::variant, xkeep_slice, xdrop_slice>; + using slice_vector_type = std::vector; + + template + xdynamic_view(CTA&& e, SA&& shape, get_strides_t&& strides, std::size_t offset, layout_type layout, + slice_vector_type&& slices, get_strides_t&& adj_strides) noexcept; + + template + self_type& operator=(const xexpression& e); + + template + disable_xexpression& operator=(const E& e); + + using base_type::size; + using base_type::dimension; + using base_type::shape; + using base_type::layout; + + // Explicitly deleting strides method to avoid compilers complaining + // about not being able to call the strides method from xstrided_view_base + // private base + const inner_strides_type& strides() const noexcept = delete; + + reference operator()(); + const_reference operator()() const; + + template + reference operator()(Args... args); + + template + const_reference operator()(Args... args) const; + + template + reference unchecked(Args... args); + + template + const_reference unchecked(Args... args) const; + + using base_type::operator[]; + using base_type::at; + using base_type::periodic; + using base_type::in_bounds; + + template + reference element(It first, It last); + + template + const_reference element(It first, It last) const; + + size_type data_offset() const noexcept; + + // Explicitly deleting data methods so has_data_interface results + // to false instead of having compilers complaining about not being + // able to call the methods from the private base + value_type* data() noexcept = delete; + const value_type* data() const noexcept = delete; + + using base_type::storage; + using base_type::expression; + using base_type::broadcast_shape; + + template + bool has_linear_assign(const O& str) const noexcept; + + template + void fill(const T& value); + + template + stepper stepper_begin(const ST& shape); + template + stepper stepper_end(const ST& shape, layout_type l); + + template + const_stepper stepper_begin(const ST& shape) const; + template + const_stepper stepper_end(const ST& shape, layout_type l) const; + + using container_iterator = std::conditional_t; + using const_container_iterator = typename storage_type::const_iterator; + + template + using rebind_t = xdynamic_view>; + + template + rebind_t build_view(E&& e) const; + + private: + + using offset_type = typename base_type::offset_type; + + slice_vector_type m_slices; + inner_strides_type m_adj_strides; + + container_iterator data_xbegin() noexcept; + const_container_iterator data_xbegin() const noexcept; + container_iterator data_xend(layout_type l, size_type offset) noexcept; + const_container_iterator data_xend(layout_type l, size_type offset) const noexcept; + + template + It data_xbegin_impl(It begin) const noexcept; + + template + It data_xend_impl(It end, layout_type l, size_type offset) const noexcept; + + void assign_temporary_impl(temporary_type&& tmp); + + template + offset_type adjust_offset(offset_type offset, T idx, Args... args) const noexcept; + offset_type adjust_offset(offset_type offset) const noexcept; + + template + offset_type adjust_offset_impl(offset_type offset, size_type idx_offset, T idx, Args... args) const noexcept; + offset_type adjust_offset_impl(offset_type offset, size_type idx_offset) const noexcept; + + template + offset_type adjust_element_offset(offset_type offset, It first, It last) const noexcept; + + template + friend class xstepper; + friend class xview_semantic; + friend class xaccessible; + friend class xconst_accessible; + }; + + /************************** + * xdynamic_view builders * + **************************/ + + template + using xdynamic_slice = xtl::variant< + T, + + xrange_adaptor, + xrange_adaptor, + xrange_adaptor, + + xrange_adaptor, + xrange_adaptor, + xrange_adaptor, + + xrange_adaptor, + xrange_adaptor, + + xrange, + xstepped_range, + + xkeep_slice, + xdrop_slice, + + xall_tag, + xellipsis_tag, + xnewaxis_tag + >; + + using xdynamic_slice_vector = std::vector>; + + template + auto dynamic_view(E&& e, const xdynamic_slice_vector& slices); + + /****************************** + * xfake_slice implementation * + ******************************/ + + namespace detail + { + template + class xfake_slice : public xslice> + { + public: + + using size_type = T; + using self_type = xfake_slice; + + xfake_slice() = default; + + size_type operator()(size_type /*i*/) const noexcept + { + return size_type(0); + } + + size_type size() const noexcept + { + return size_type(1); + } + + size_type step_size() const noexcept + { + return size_type(0); + } + + size_type step_size(std::size_t /*i*/, std::size_t /*n*/ = 1) const noexcept + { + return size_type(0); + } + + size_type revert_index(std::size_t i) const noexcept + { + return i; + } + + bool contains(size_type /*i*/) const noexcept + { + return true; + } + + bool operator==(const self_type& /*rhs*/) const noexcept + { + return true; + } + + bool operator!=(const self_type& /*rhs*/) const noexcept + { + return false; + } + }; + } + + /******************************** + * xdynamic_view implementation * + ********************************/ + + template + template + inline xdynamic_view::xdynamic_view(CTA&& e, SA&& shape, get_strides_t&& strides, + std::size_t offset, layout_type layout, + slice_vector_type&& slices, get_strides_t&& adj_strides) noexcept + : base_type(std::forward(e), std::forward(shape), std::move(strides), offset, layout), + m_slices(std::move(slices)), m_adj_strides(std::move(adj_strides)) + { + } + + template + template + inline auto xdynamic_view::operator=(const xexpression& e) -> self_type& + { + return semantic_base::operator=(e); + } + + template + template + inline auto xdynamic_view::operator=(const E& e) -> disable_xexpression& + { + std::fill(this->begin(), this->end(), e); + return *this; + } + + template + inline auto xdynamic_view::operator()() -> reference + { + return base_type::storage()[data_offset()]; + } + + template + inline auto xdynamic_view::operator()() const -> const_reference + { + return base_type::storage()[data_offset()]; + } + + template + template + inline auto xdynamic_view::operator()(Args... args) -> reference + { + XTENSOR_TRY(check_index(base_type::shape(), args...)); + XTENSOR_CHECK_DIMENSION(base_type::shape(), args...); + offset_type offset = base_type::compute_index(args...); + offset = adjust_offset(offset, args...); + return base_type::storage()[static_cast(offset)]; + } + + template + template + inline auto xdynamic_view::operator()(Args... args) const -> const_reference + { + XTENSOR_TRY(check_index(base_type::shape(), args...)); + XTENSOR_CHECK_DIMENSION(base_type::shape(), args...); + offset_type offset = base_type::compute_index(args...); + offset = adjust_offset(offset, args...); + return base_type::storage()[static_cast(offset)]; + } + + template + template + inline bool xdynamic_view::has_linear_assign(const O&) const noexcept + { + return false; + } + + template + template + inline auto xdynamic_view::unchecked(Args... args) -> reference + { + offset_type offset = base_type::compute_unchecked_index(args...); + offset = adjust_offset(args...); + return base_type::storage()[static_cast(offset)]; + } + + template + template + inline auto xdynamic_view::unchecked(Args... args) const -> const_reference + { + offset_type offset = base_type::compute_unchecked_index(args...); + offset = adjust_offset(args...); + return base_type::storage()[static_cast(offset)]; + } + + template + template + inline auto xdynamic_view::element(It first, It last) -> reference + { + XTENSOR_TRY(check_element_index(base_type::shape(), first, last)); + offset_type offset = base_type::compute_element_index(first, last); + offset = adjust_element_offset(offset, first, last); + return base_type::storage()[static_cast(offset)]; + } + + template + template + inline auto xdynamic_view::element(It first, It last) const -> const_reference + { + XTENSOR_TRY(check_element_index(base_type::shape(), first, last)); + offset_type offset = base_type::compute_element_index(first, last); + offset = adjust_element_offset(offset, first, last); + return base_type::storage()[static_cast(offset)]; + } + + template + inline auto xdynamic_view::data_offset() const noexcept -> size_type + { + size_type offset = base_type::data_offset(); + size_type sl_offset = xtl::visit([](const auto& sl) { return sl(size_type(0)); }, m_slices[0]); + return offset + sl_offset * m_adj_strides[0]; + } + + template + template + inline void xdynamic_view::fill(const T& value) + { + return std::fill(this->storage_begin(), this->storage_end(), value); + } + + template + template + inline auto xdynamic_view::stepper_begin(const ST& shape) -> stepper + { + size_type offset = shape.size() - dimension(); + return stepper(this, offset); + } + + template + template + inline auto xdynamic_view::stepper_end(const ST& shape, layout_type /*l*/) -> stepper + { + size_type offset = shape.size() - dimension(); + return stepper(this, offset, true); + } + + template + template + inline auto xdynamic_view::stepper_begin(const ST& shape) const -> const_stepper + { + size_type offset = shape.size() - dimension(); + return const_stepper(this, offset); + } + + template + template + inline auto xdynamic_view::stepper_end(const ST& shape, layout_type /*l*/) const -> const_stepper + { + size_type offset = shape.size() - dimension(); + return const_stepper(this, offset, true); + } + + template + template + inline auto xdynamic_view::build_view(E&& e) const -> rebind_t + { + inner_shape_type sh(this->shape()); + inner_strides_type str(base_type::strides()); + slice_vector_type svt(m_slices); + inner_strides_type adj_str(m_adj_strides); + return rebind_t(std::forward(e), std::move(sh), std::move(str), + base_type::data_offset(), this->layout(), std::move(svt), std::move(adj_str)); + } + + template + inline auto xdynamic_view::data_xbegin() noexcept -> container_iterator + { + return data_xbegin_impl(this->storage().begin()); + } + + template + inline auto xdynamic_view::data_xbegin() const noexcept -> const_container_iterator + { + return data_xbegin_impl(this->storage().cbegin()); + } + + template + inline auto xdynamic_view::data_xend(layout_type l, size_type offset) noexcept -> container_iterator + { + return data_xend_impl(this->storage().begin(), l, offset); + } + + template + inline auto xdynamic_view::data_xend(layout_type l, size_type offset) const noexcept -> const_container_iterator + { + return data_xend_impl(this->storage().cbegin(), l, offset); + } + + template + template + inline It xdynamic_view::data_xbegin_impl(It begin) const noexcept + { + return begin + static_cast(data_offset()); + } + + // TODO: fix the data_xend implementation and assign_temporary_impl + + template + template + inline It xdynamic_view::data_xend_impl(It begin, layout_type l, size_type offset) const noexcept + { + return strided_data_end(*this, begin + std::ptrdiff_t(data_offset()), l, offset); + } + + template + inline void xdynamic_view::assign_temporary_impl(temporary_type&& tmp) + { + std::copy(tmp.cbegin(), tmp.cend(), this->begin()); + } + + template + template + inline auto xdynamic_view::adjust_offset(offset_type offset, T idx, Args... args) const noexcept -> offset_type + { + constexpr size_type nb_args = sizeof...(Args) + 1; + size_type dim = base_type::dimension(); + offset_type res = nb_args > dim ? adjust_offset(offset, args...) : adjust_offset_impl(offset, dim - nb_args, idx, args...); + return res; + } + + template + inline auto xdynamic_view::adjust_offset(offset_type offset) const noexcept -> offset_type + { + return offset; + } + + template + template + inline auto xdynamic_view::adjust_offset_impl(offset_type offset, size_type idx_offset, T idx, Args... args) const noexcept + -> offset_type + { + offset_type sl_offset = xtl::visit([idx](const auto& sl) { + using type = typename std::decay_t::size_type; + return sl(type(idx)); + }, m_slices[idx_offset]); + offset_type res = offset + sl_offset * m_adj_strides[idx_offset]; + return adjust_offset_impl(res, idx_offset + 1, args...); + } + + template + inline auto xdynamic_view::adjust_offset_impl(offset_type offset, size_type) const noexcept + -> offset_type + { + return offset; + } + + template + template + inline auto xdynamic_view::adjust_element_offset(offset_type offset, It first, It last) const noexcept -> offset_type + { + auto dst = std::distance(first, last); + offset_type dim = static_cast(dimension()); + offset_type loop_offset = dst < dim ? dim - dst : offset_type(0); + offset_type idx_offset = dim < dst ? dst - dim : offset_type(0); + offset_type res = offset; + for (offset_type i = loop_offset; i < dim; ++i, ++first) + { + offset_type j = static_cast(first[idx_offset]); + offset_type sl_offset = xtl::visit([j](const auto& sl) { return static_cast(sl(j)); }, m_slices[static_cast(i)]); + res += sl_offset * m_adj_strides[static_cast(i)]; + } + return res; + } + + /***************************************** + * xdynamic_view builders implementation * + *****************************************/ + + namespace detail + { + template + struct adj_strides_policy + { + using slice_vector = V; + using strides_type = dynamic_shape; + + slice_vector new_slices; + strides_type new_adj_strides; + + protected: + + inline void resize(std::size_t size) + { + new_slices.resize(size); + new_adj_strides.resize(size); + } + + inline void set_fake_slice(std::size_t idx) + { + new_slices[idx] = xfake_slice(); + new_adj_strides[idx] = std::ptrdiff_t(0); + } + + template + bool fill_args(const xdynamic_slice_vector& slices, std::size_t sl_idx, + std::size_t i, std::size_t old_shape, + const ST& old_stride, + S& shape, get_strides_t& strides) + { + return fill_args_impl>(slices, sl_idx, i, old_shape, old_stride, shape, strides) + || fill_args_impl>(slices, sl_idx, i, old_shape, old_stride, shape, strides); + } + + template + bool fill_args_impl(const xdynamic_slice_vector& slices, std::size_t sl_idx, + std::size_t i, std::size_t old_shape, + const ST& old_stride, + S& shape, get_strides_t& strides) + { + auto* sl = xtl::get_if(&slices[sl_idx]); + if (sl != nullptr) + { + new_slices[i] = *sl; + auto& ns = xtl::get(new_slices[i]); + ns.normalize(old_shape); + shape[i] = static_cast(ns.size()); + strides[i] = std::ptrdiff_t(0); + new_adj_strides[i] = static_cast(old_stride); + } + return sl != nullptr; + } + }; + } + + template + inline auto dynamic_view(E&& e, const xdynamic_slice_vector& slices) + { + using view_type = xdynamic_view, dynamic_shape>; + using slice_vector = typename view_type::slice_vector_type; + using policy = detail::adj_strides_policy; + detail::strided_view_args args; + args.fill_args(e.shape(), detail::get_strides(e), detail::get_offset(e), e.layout(), slices); + return view_type(std::forward(e), std::move(args.new_shape), std::move(args.new_strides), args.new_offset, + args.new_layout, std::move(args.new_slices), std::move(args.new_adj_strides)); + } +} + +#endif diff --git a/vendor/xtensor/include/xtensor/xeval.hpp b/vendor/xtensor/include/xtensor/xeval.hpp index 18d53beea..04fc5fd26 100644 --- a/vendor/xtensor/include/xtensor/xeval.hpp +++ b/vendor/xtensor/include/xtensor/xeval.hpp @@ -1,5 +1,6 @@ /*************************************************************************** -* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * @@ -10,6 +11,7 @@ #define XTENSOR_EVAL_HPP #include "xtensor_forward.hpp" +#include "xshape.hpp" namespace xt { @@ -40,17 +42,25 @@ namespace xt /// @cond DOXYGEN_INCLUDE_SFINAE template > inline auto eval(T&& t) - -> std::enable_if_t::value && detail::is_array::value, xtensor::value>> + -> std::enable_if_t::value && detail::is_array::value && !detail::is_fixed::value, xtensor::value>> { return xtensor::value>(std::forward(t)); } template > inline auto eval(T&& t) - -> std::enable_if_t::value && !detail::is_array::value, xt::xarray> + -> std::enable_if_t::value && !detail::is_array::value && !detail::is_fixed::value, xt::xarray> { return xarray(std::forward(t)); } + + template > + inline auto eval(T&& t) + -> std::enable_if_t::value && detail::is_fixed::value && !detail::is_array::value, + xt::xtensor_fixed> + { + return xtensor_fixed(std::forward(t)); + } /// @endcond } diff --git a/vendor/xtensor/include/xtensor/xexception.hpp b/vendor/xtensor/include/xtensor/xexception.hpp index 689ce31e0..4daa90be5 100644 --- a/vendor/xtensor/include/xtensor/xexception.hpp +++ b/vendor/xtensor/include/xtensor/xexception.hpp @@ -1,5 +1,6 @@ /*************************************************************************** -* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * @@ -34,10 +35,49 @@ namespace xt template [[noreturn]] void throw_broadcast_error(const S1& lhs, const S2& rhs); + /********************* + * concatenate_error * + *********************/ + + class concatenate_error : public std::runtime_error + { + public: + + explicit concatenate_error(const char* msg) + : std::runtime_error(msg) + { + } + }; + + template + [[noreturn]] void throw_concatenate_error(const S1& lhs, const S2& rhs); + /********************************** * broadcast_error implementation * **********************************/ + namespace detail + { + template + inline std::string shape_error_message(const S1& lhs, const S2& rhs) + { + std::ostringstream buf("Incompatible dimension of arrays:", std::ios_base::ate); + + buf << "\n LHS shape = ("; + using size_type1 = typename S1::value_type; + std::ostream_iterator iter1(buf, ", "); + std::copy(lhs.cbegin(), lhs.cend(), iter1); + + buf << ")\n RHS shape = ("; + using size_type2 = typename S2::value_type; + std::ostream_iterator iter2(buf, ", "); + std::copy(rhs.cbegin(), rhs.cend(), iter2); + buf << ")"; + + return buf.str(); + } + } + #ifdef NDEBUG // Do not inline this function template @@ -49,20 +89,28 @@ namespace xt template [[noreturn]] void throw_broadcast_error(const S1& lhs, const S2& rhs) { - std::ostringstream buf("Incompatible dimension of arrays:", std::ios_base::ate); + std::string msg = detail::shape_error_message(lhs, rhs); + throw broadcast_error(msg.c_str()); + } +#endif - buf << "\n LHS shape = ("; - using size_type1 = typename S1::value_type; - std::ostream_iterator iter1(buf, ", "); - std::copy(lhs.cbegin(), lhs.cend(), iter1); + /************************************ + * concatenate_error implementation * + ************************************/ - buf << ")\n RHS shape = ("; - using size_type2 = typename S2::value_type; - std::ostream_iterator iter2(buf, ", "); - std::copy(rhs.cbegin(), rhs.cend(), iter2); - buf << ")"; - - throw broadcast_error(buf.str().c_str()); +#ifdef NDEBUG + // Do not inline this function + template + [[noreturn]] void throw_concatenate_error(const S1&, const S2&) + { + throw concatenate_error("Incompatible dimension of arrays, compile in DEBUG for more info"); + } +#else + template + [[noreturn]] void throw_concatenate_error(const S1& lhs, const S2& rhs) + { + std::string msg = detail::shape_error_message(lhs, rhs); + throw concatenate_error(msg.c_str()); } #endif @@ -97,8 +145,8 @@ namespace xt { } - template - inline void check_index_impl(const S& shape, std::size_t arg, Args... args) + template + inline void check_index_impl(const S& shape, T arg, Args... args) { if (sizeof...(Args) + 1 > shape.size()) { @@ -106,7 +154,7 @@ namespace xt } else { - if (arg >= std::size_t(shape[dim]) && shape[dim] != 1) + if (std::size_t(arg) >= std::size_t(shape[dim]) && shape[dim] != 1) { throw std::out_of_range("index " + std::to_string(arg) + " is out of bounds for axis " + std::to_string(dim) + " with size " + std::to_string(shape[dim])); @@ -127,17 +175,33 @@ namespace xt inline void check_element_index(const S& shape, It first, It last) { using value_type = typename std::iterator_traits::value_type; - auto dst = static_cast(last - first); + using size_type = typename S::size_type; + auto dst = static_cast(last - first); It efirst = last - static_cast((std::min)(shape.size(), dst)); std::size_t axis = 0; - while (efirst != last) + + if(shape.empty()) { - if (*efirst >= value_type(shape[axis]) && shape[axis] != 1) + if(first != last && *(--last) != value_type(0)) { - throw std::out_of_range("index " + std::to_string(*efirst) + " is out of bounds for axis " - + std::to_string(axis) + " with size " + std::to_string(shape[axis])); + throw std::out_of_range("index out of bound (empty array)"); + } + else + { + return; + } + } + else + { + while (efirst != last) + { + if (*efirst >= value_type(shape[axis]) && shape[axis] != 1) + { + throw std::out_of_range("index " + std::to_string(*efirst) + " is out of bounds for axis " + + std::to_string(axis) + " with size " + std::to_string(shape[axis])); + } + ++efirst, ++axis; } - ++efirst, ++axis; } } diff --git a/vendor/xtensor/include/xtensor/xexpression.hpp b/vendor/xtensor/include/xtensor/xexpression.hpp index a83ea0c58..caf914d58 100644 --- a/vendor/xtensor/include/xtensor/xexpression.hpp +++ b/vendor/xtensor/include/xtensor/xexpression.hpp @@ -1,5 +1,6 @@ /*************************************************************************** -* Copyright (c) 2016, Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht * +* Copyright (c) QuantStack * * * * Distributed under the terms of the BSD 3-Clause License. * * * @@ -14,9 +15,12 @@ #include #include +#include #include +#include "xlayout.hpp" #include "xshape.hpp" +#include "xtensor_forward.hpp" #include "xutils.hpp" namespace xt @@ -61,6 +65,43 @@ namespace xt xexpression& operator=(xexpression&&) = default; }; + /************************************ + * xsharable_expression declaration * + ************************************/ + + template + class xshared_expression; + + template + class xsharable_expression; + + namespace detail + { + template + xshared_expression make_xshared_impl(xsharable_expression&&); + } + + template + class xsharable_expression : public xexpression + { + protected: + + xsharable_expression(); + ~xsharable_expression() = default; + + xsharable_expression(const xsharable_expression&) = default; + xsharable_expression& operator=(const xsharable_expression&) = default; + + xsharable_expression(xsharable_expression&&) = default; + xsharable_expression& operator=(xsharable_expression&&) = default; + + private: + + std::shared_ptr p_shared; + + friend xshared_expression detail::make_xshared_impl(xsharable_expression&&); + }; + /****************************** * xexpression implementation * ******************************/ @@ -97,21 +138,41 @@ namespace xt } //@} - namespace detail - { - template - struct is_xexpression_impl : std::is_base_of>, std::decay_t> - { - }; + /*************************************** + * xsharable_expression implementation * + ***************************************/ - template - struct is_xexpression_impl> : std::true_type - { - }; + template + inline xsharable_expression::xsharable_expression() + : p_shared(nullptr) + { } + /** + * is_crtp_base_of + * Resembles std::is_base_of, but adresses the problem of whether _some_ instantiation + * of a CRTP templated class B is a base of class E. A CRTP templated class is correctly + * templated with the most derived type in the CRTP hierarchy. Using this assumption, + * this implementation deals with either CRTP final classes (checks for inheritance + * with E as the CRTP parameter of B) or CRTP base classes (which are singly templated + * by the most derived class, and that's pulled out to use as a templete parameter for B). + */ + + namespace detail + { + template