diff --git a/docs/source/io_formats/materials.rst b/docs/source/io_formats/materials.rst index 92b0165a43c..d0049b30312 100644 --- a/docs/source/io_formats/materials.rst +++ b/docs/source/io_formats/materials.rst @@ -49,8 +49,9 @@ Each ``material`` element can have the following attributes or sub-elements: ` is used. :density: - An element with attributes/sub-elements called ``value`` and ``units``. The - ``value`` attribute is the numeric value of the density while the ``units`` + An element with attributes/sub-elements called ``value``, ``units``, and + (optionally) ``value_timeseries``. The ``value`` attribute is the numeric + value of the density while the ``units`` can be "g/cm3", "kg/m3", "atom/b-cm", "atom/cm3", or "sum". The "sum" unit indicates that values appearing in ``ao`` or ``wo`` attributes for ```` and ```` sub-elements are to be interpreted as absolute nuclide/element @@ -59,14 +60,21 @@ Each ``material`` element can have the following attributes or sub-elements: a ``macroscopic`` quantity to indicate that the density is already included in the library and thus not needed here. However, if a value is provided for the ``value``, then this is treated as a number density multiplier on - the macroscopic cross sections in the multi-group data. This can be used, - for example, when perturbing the density slightly. + the macroscopic cross sections in the multi-group data. This can be used, + for example, when perturbing the density slightly. The ``value_timeseries`` + element indicates a material density changing in time. This can be used to + simulate various benchmark problems in kinetic simulations. The + ``value_timeseries`` attribute is assumed to use the same units specified + in the ``units`` attribute. *Default*: None .. note:: A ``macroscopic`` quantity can not be used in conjunction with a ``nuclide``, ``element``, or ``sab`` quantity. + .. note:: The ``value_timeseries`` attribute cannot be used with ``sum`` + densities. + :nuclide: An element with attributes/sub-elements called ``name``, and ``ao`` or ``wo``. The ``name`` attribute is the name of the cross-section for a diff --git a/docs/source/io_formats/settings.rst b/docs/source/io_formats/settings.rst index b7874fcf2f8..08e108d7e33 100644 --- a/docs/source/io_formats/settings.rst +++ b/docs/source/io_formats/settings.rst @@ -321,6 +321,18 @@ the estimated eigenvalue. It has the following attributes/sub-elements: .. note:: See section on the :ref:`trigger` for more information. +------------------------------------- +```` Element +------------------------------------- + +The ```` element indicates whether to run a static or +time-dependent simulation (with no feedbacks). If this element is set to +"true", a kinetic simulation will be run; otherwise a static simulation is run. + + *Default*: false + +.. _kinetic_simulation: + --------------------------- ```` Element --------------------------- @@ -585,6 +597,25 @@ found in the :ref:`random ray user guide `. *Default*: 1.0 +If a kinetic simulation is active, two additional settings are available: + + :bd_order: + Order for backwards difference approximation used in numerically estimating + time derivatives. The backwards difference approximation is stable for + orders less than or equal to 6, and is relatively straightforward to + implement. The default value of 3 balances higher precision with speed. + + *Default*: 3 + + :time_derivative_method: + The method used to resolve the angular flux time-derivative in the time-dependent + characteristic equation. The ``isotropic`` method utilizes an isotropic approximation + to resolve the angular flux time derivative. The ``propagation`` method + uses a technique called Time Derivative Propagation to resolve the angular + flux time derivative. + + *Default*: ``isotropic`` + ---------------------------------- ```` Element ---------------------------------- @@ -1286,6 +1317,32 @@ despite not being bounded on both sides. .. _trace: +--------------------------------- +```` Element +--------------------------------- + +The ```` element can be used specify for how long and +at what resolution to run a kinetic simulation. This element has the +following attributes/sub-elements: + + :n_timesteps: + The number of timesteps. Must be specified by the user. + + :dt: + Time step size. Must be specified by the user. + + :timestep_units: + Time step units. Available options are ``ms`` for milliseconds, ``s`` for seconds, + and ``min`` for minutes. + + *Default*: ``s`` + + .. note:: This element is required if the :ref:`kinetic_simulation` is ``true``. + + *Default*: None + +.. _timestep_parameters: + ------------------- ```` Element ------------------- diff --git a/docs/source/io_formats/statepoint.rst b/docs/source/io_formats/statepoint.rst index 2309643dc89..edb8a9a3f82 100644 --- a/docs/source/io_formats/statepoint.rst +++ b/docs/source/io_formats/statepoint.rst @@ -28,6 +28,10 @@ The current version of the statepoint file format is 18.1. 'continuous-energy' or 'multi-group'. - **run_mode** (*char[]*) -- Run mode used, either 'eigenvalue' or 'fixed source'. + - **solver_type** (*char[]*) -- Solver used, either 'monte carlo' or + 'random ray'. + - **kinetic_simulation** (*int*) -- Flag indicating whether a kinetic (1) + or static (0) simulation was run. - **n_particles** (*int8_t*) -- Number of particles used per generation. - **n_batches** (*int*) -- Number of batches to simulate. - **current_batch** (*int*) -- The number of batches already simulated. @@ -49,6 +53,10 @@ The current version of the statepoint file format is 18.1. combined estimate of k-effective. - **n_realizations** (*int*) -- Number of realizations for global tallies. + - **n_energy_groups** (*int*) -- Number of energy groups used if + **energy_mode** is 'multi-group'. + - **n_delay_groups** (*int*) -- Number of delay groups used if + **energy_mode** is 'multi-group'. - **global_tallies** (*double[][2]*) -- Accumulated sum and sum-of-squares for each global tally. - **source_bank** (Compound type) -- Source bank information for each @@ -197,3 +205,16 @@ All values are given in seconds and are measured on the master process. tally results and evaluating their statistics. - **writing statepoints** (*double*) -- Time spent writing statepoint files + + If random ray mode is used, the following times are also recorded: + - **source_update** (*double*) -- Time spent updating the neutron source. + - **precursor_update** (*double*) -- Time spent updating the precursors + (only written for kinetic simulations). + +**/timestep_data/** + +Time step information for kinetic simulation. All values are given in seconds. + +:Datasets: - **dt** (*double*) -- Length of the time step. + - **current_timestep** (*int*) -- Numbered time step. + - **current_time** (*double*) -- Simulated elapsed time. diff --git a/docs/source/methods/random_ray.rst b/docs/source/methods/random_ray.rst index 5e17316aa1c..318f9aa0484 100644 --- a/docs/source/methods/random_ray.rst +++ b/docs/source/methods/random_ray.rst @@ -87,6 +87,8 @@ derivations are reproduced here verbatim. Several extensions are also made to add clarity, particularly on the topic of OpenMC's treatment of cell volumes in the random ray solver. +.. _usersguide_moc: + ~~~~~~~~~~~~~~~~~~~~~~~~~ Method of Characteristics ~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1059,6 +1061,315 @@ random ray and Monte Carlo, however. develop the scattering source by way of inactive batches before beginning active batches. +.. _usersguide_kinetic_random_ray: + +------------------ +Kinetic Random Ray +------------------ + +One can derive equations for time-dependent cases by following similar steps +shown in the derivation for the :ref:`Method of +Charactersistics`. This process stars with the time-dependent +form of neutron transport equation, + +.. math:: + :label: transport-td + + \frac{1}{v(E)} \frac{\partial}{\partial t} + \psi(\mathbf{r},\mathbf{\Omega},E,t) = -\mathbf{\Omega}\cdot + \nabla\psi(\mathbf{r},\mathbf{\Omega},E,t) - \Sigma_{t}(\mathbf{r}, E, + t)\psi(\mathbf{r},\mathbf{\Omega},E,t) + Q(\mathbf{r},\mathbf{\Omega},E,t) + +The neutron source, :math:`Q(\mathbf{r},\mathbf{\Omega},E,t)`, is composed of several +neutron producing sources: + +.. math:: + :label: source-td + + Q(\mathbf{r},\mathbf{\Omega},E,t) = F_{p}(\mathbf{r},E,t) + + S(\mathbf{r},\mathbf{\Omega},E,t) +D(\mathbf{r},E,t) + +where the prompt neutron source (:math:`F_{p}(\mathbf{r},E,t)`), the scattering +neutron source (:math:`S(\mathbf{r},\mathbf{\Omega},E,t)`), and the delayed +neutron source (:math:`D(\mathbf{r},E,t)`) are given by: + + +.. math:: + + \begin{align} + F_{p}(\mathbf{r},E,t) &= \frac{\chi^p(E)}{4\pi} \int_0^\infty \int_{4\pi} + \nu_{p}\Sigma_{f}(\mathbf{r},E^\prime,t) + \psi(\mathbf{r},\mathbf{\Omega}^\prime,E^\prime,t) \: + d\mathbf{\Omega}^\prime \: dE^\prime\nonumber\\ + S(\mathbf{r},\mathbf{\Omega},E,t) &= \int_0^\infty\int_{4\pi} + \Sigma_{s}(\mathbf{r},\mathbf{\Omega}^\prime\rightarrow\mathbf{\Omega},E^\prime\rightarrow + E,t) + \psi(\mathbf{r},\mathbf{\Omega}^\prime,E^\prime,t) \: + d\mathbf{\Omega}^\prime \: dE^\prime\nonumber\\ + D(\mathbf{r},E,t) &= \sum_m \frac{\chi^d_m(E)}{4\pi} \lambda_m + C_m(\mathbf{r}, t)\nonumber + \end{align} + +The :math:`C_m(\mathbf{r}, t)` term is the number of delayed neutron precursors of delayed +group :math:`m`, governed by + + +.. math:: + :label: dnp-eq + + \frac{\partial}{\partial t} C_m(\mathbf{r}, t) = \int_0^\infty\int_{4\pi} + \nu_{d,m} \Sigma_{f}(\mathbf{r},E^\prime,t) + \psi(\mathbf{r},\mathbf{\Omega}^\prime,E^\prime,t) \: + d\mathbf{\Omega}^\prime \: dE^\prime - \lambda_m C_m(\mathbf{r},t) + +The new variables in Equations :eq:`transport-td`, :eq:`source-td`, and +:eq:`dnp-eq` are + + +.. math:: + + \begin{align*} + v(E) &= \text{ neutron speed at energy $E$ [cm s$^{-1}$]},\\ + t &= \text{ time [s]},\\ + \beta &= \sum_m \beta_m = \text{ total delayed neutron fraction [-]},\\ + \nu_{p} &= (1-\beta) \nu = \text{ prompt neutron yield [-]}, \\ + \nu_{d,m} &= \beta_{m} \nu = \text{ delayed neutron yield [-]}, \\ + \chi^p(E) &= \text{ prompt fission neutron spectrum [-]},\\ + \chi^d_m(E) &= \text{ delayed fission neutron spectrum [-],},\\ + \lambda_m &= \text{ decay constant for precursor group $m$ [s$^{-1}$]},\\ + \beta_m &= \text{ delayed neutron fraction for precursor group $m$ [-]} + .\end{align*} + +Applying the characteristic transform to Equation :eq:`transport-td` yields the +time-dependent characteristic equation: + + +.. math:: + :label: char-td + + \frac{1}{v(E)} \frac{\partial}{\partial t} \psi(s,\mathbf{\Omega},E,t) = + -\frac{\partial}{\partial s} \psi(s,\mathbf{\Omega},E,t) - + \Sigma_{t}(s,E,t)\psi(s,\mathbf{\Omega},E,t) + Q(s,\mathbf{\Omega},E,t) + +A similar integrating factor is used to obtain a partial solution of the +time-dependent characteristic equation: + + +.. math:: + :label: moc_td_final_sub + + \psi(s,\mathbf{\Omega},E,t) = \psi(\mathbf{r}_0,\mathbf{\Omega},E,t) + e^{-\int_0^s ds^{\prime} \Sigma_t(s^{\prime},E,t)} + \mathcal{I}_{Q} - + \mathcal{I}_{\frac{\partial}{\partial t} \psi} + +where + + +.. math:: + + \begin{aligned} + \mathcal{I}_{Q} &= \int_0^{s} ds^{\prime\prime} + Q(s^{\prime\prime},\mathbf{\Omega},E,t) e^{\int_{s^{\prime\prime}}^{s'} + ds^{\prime} \Sigma_{t}(s^{\prime},E,t)}\\ + \mathcal{I}_{\frac{\partial}{\partial t} \psi} &= -\frac{1}{v(E)} + \int_0^{s} ds^{\prime\prime} \frac{\partial}{\partial t} + \psi(s^{\prime\prime},\mathbf{\Omega},E,t) e^{\int_{s^{\prime\prime}}^{s} + ds^{\prime} \Sigma_{t}(s^{\prime},E,t)} + \end{aligned} + +Rearranging terms in Equation :eq:`moc_td_final_sub` to solve in terms of +:math:`\Delta \psi_{r,g}(t) = \psi_{r,g}(0,t) - \psi_{r,g}(\ell_r, t)`, and +applying the same energy and spatial discretizations used for the static +case, results in a characteristic equation of the form yields + + +.. math:: + :label: moc_td_final + + \Delta \psi_{r,g}(t) = \psi_{r,g}(0,t) e^{-\Sigma_{t,i,g}(t) \ell_r} - \mathcal{I}_{Q} + \mathcal{I}_{\frac{\partial}{\partial t} \psi} + +The :math:`\mathcal{I}_Q` term is resolved by the analytic shape assumed for +the source term (flat, linear, quadratic, etc.). Applying a flat source approximation +to Equation :eq:`moc_td_final` results in a characteristic equation of the form: + + +.. math:: + :label: moc_td_final_flat + + \Delta \psi_{r,g}(t) = \left(\psi_{r,g}(0,t) - + \frac{Q_{i,g}(t)}{\Sigma_{t,i,g}(t)} \right) (1 - e^{-\Sigma_{t,i,g}(t) + \ell_r}) + \mathcal{I}_{\frac{\partial}{\partial t} \psi} + +The corresponding flat source term is + + +.. math:: + :label: source_td_final_flat + + Q_{i,g}(t) = \frac{1}{4\pi} \left(F_{p,i,g}(t) + S_{i,g}(t) + + D_{i,g}(t)\right) + + +where + +.. math:: + + \begin{align} + F_{p,i,g}(t) &= \chi_g^p\sum_{g'=1}^G + \nu_{p}\Sigma_{f,g',w}(t)\phi_{i,g'}(t)\nonumber\\ + S_{i,g}(t) &= \sum_{g'=1}^G + \Sigma_{s,i,g'\rightarrow g}(t) \phi_{i,g'}(t)\nonumber\\ + D_{i,g}(t) &= \sum_m \chi^d_{g,m} \lambda_m C_{i,m}(t)\nonumber + \end{align} + + +The same approximations applied to the precursor equation (Eq. :eq:`dnp-eq`) yields + + +.. math:: + :label: dnp-eq-final-flat + + \frac{\partial}{\partial t} C_{i,m}(t) = \sum_{g=1}^G + \nu_{d,m}\Sigma_{f,i,g}(t)\phi_{i,g}(t) - \lambda_m C_{i,m}(t) + +The most straightforward approach to resolve the +:math:`\mathcal{I}_{\frac{\partial}{\partial t} \psi}` term would be to +numerically estimate the derivative using a finite difference approximation. +This approach works for the Method of Characteristics and has been shown to +yield accurate answers (see `Hoffman `_), but requires storage of +angular fluxes which can be very expensive. Additionally, the stochastic +quadrature used in the random ray method ensures each time step has a different +spatial domain, making direct finite differencing of angular fluxes impossible. +Two alternative methods have been implemented into OpenMC: + +~~~~~~~~~~~~~~~~~~~~~~~ +Isotropic Approximation +~~~~~~~~~~~~~~~~~~~~~~~ +A commonly used approach to avoid storage of angular fluxes is to make an +isotropic approximation on the angular flux time derivative: + + +.. math:: + + \frac{\partial}{\partial t} \psi_{r,g}(s,t) \approx \frac{1}{4\pi} \frac{d}{d t} \phi_{g}(s,t) + + +This approximation incurs inaccuracies close to strongly absorbing regions due +to the strong flux anisotropies introduced by neutron absorption (i.e. no +neutrons will be emitted from the absorber). This will result in scalar flux +values higher than they should be near absorbing regions. The benefit is that +it is fast, requiring minimal new computation to numerically compute the scalar +flux time derivative. The isotropic approximation resolves the +:math:`\mathcal{I}_{\frac{\partial}{\partial t} \psi}` term to + + +.. math:: + :label: ical-isotropic + + \mathcal{I}_{\frac{\partial}{\partial t} \psi} \approx \frac{1}{4\pi v_g} + \frac{d}{d t} \phi_{i,g}(t) \frac{1 - e^{-\Sigma_{t,i,g}(t) \ell_r}}{\Sigma_{t,i,g}(t)} + +Applying Equation :eq:`ical-isotropic` to Equation :eq:`moc_td_final_flat` yields + + +.. math:: + :label: char-td-isotropic + + \Delta \psi(t) = \left(\psi_{r,g}(0, t) - \frac{Q_{i,g}(t)}{\Sigma_{t,i,g}(t)} + \frac{1}{4\pi v_g \Sigma_{t,i,g}(t)} \frac{d}{d t} \phi_{i,g}(t)\right) (1 - e^{-\Sigma_{t,i,g}(t) \ell_r}) + + +This approach was first applied to the random ray method by `Kraus +`_. + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Source Derivative Propagation +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Source Derivative Propagation is a method developed by `Hoffman +`_ to solve the angular flux storage issue while also providing +a higher fidelity approximation storing angular fluxes. This method works by +forming a characteristic equation for the *angular flux time-derivative* which +is solved in the same way as the standard characteristic equation. The +time-derivative characteristic equation provides an analytical solution for +:math:`\frac{d}{d t} \psi_{r,i}(s,t)`. The time derivative characteristic +equation is formed by taking the time derivative of Equation +:eq:`moc_td_final_flat` and assuming :math:`\frac{d}{d t} \Sigma_{t,i,g}(t) +\approx 0`. The resulting :math:`\frac{\partial^2}{\partial t^2} \psi_{r,g}(s,t)` term +can be resolved with a second-order isotropic approximation, yielding: + + +.. math:: + :label: char-td-derivative-sdp + + \Delta \frac{\partial}{\partial t} \psi_{r,g}(s,t) = + \left(\frac{\partial}{\partial t} \psi_{r,g}(0, t) - \frac{T^{1}_{i,g}(t)}{\Sigma_{t,i,g}(t)} \right) + (1 - e^{-\Sigma_{t,i,g}(t)s}) + +where + + +.. math:: + :label: operator-T1 + + T^{1}_{i,g}(t) \equiv \frac{d Q_{i,g}}{d t} + -\frac{1}{4\pi v_g}\frac{d^2 \phi_{i,g}}{d t^2} + +Equation :eq:`char-td-derivative-sdp` can be rearranged to solve for +:math:`\frac{\partial}{\partial t} \psi_{r,g}(s,t)` and used to solve +:math:`\mathcal{I}_{\frac{\partial}{\partial t} \psi}` as: + + +.. math:: + + \mathcal{I}_{\frac{\partial}{\partial t} \psi} = + \frac{1}{v_g}\frac{T^{1}_{i,g}(t)}{(\Sigma_{t,i,g}(t))^{2}} (1 - + e^{-\Sigma_{t,i,g}(t) s}) + + \frac{s}{v_g} \left(\frac{\partial}{\partial t} \psi_{r,g}(0, t) - \frac{T^{1}_{i,g}(t)}{\Sigma_{t,i,g}(t)} \right) e^{-\Sigma_{t,i,g}(t)s} + +which can be substituted into Equation :eq:`moc_td_final_flat` to get + + +.. math:: + :label: char-td-sdp + + \begin{aligned} + \Delta \psi(t) = \bigg(\psi_{r,g}(0, t) - \frac{Q_{i,g}(t)}{\Sigma{t,i,g}(t)} + &+ \frac{1}{v_g} \frac{T^{1}_{i,g}(t)}{(\Sigma_{t,i,g}(t))^{2}}\bigg) (1 - + e^{-\Sigma_t,i,g(t) \ell_r})\\ &+ \frac{s}{v_g} + \bigg(\frac{\partial}{\partial t} \psi_{r,g}(0, t) - + \frac{T^{1}_{i,g}(t)}{\Sigma_{t,i,g}(t)} \bigg) e^{-\Sigma_{t,i,g}(t)s} + \end{aligned} + + +Equations :eq:`char-td-derivative-sdp` and :eq:`char-td-sdp` are solved in +sequence during flux propagation. The avoidance of a first-order isotropic +approximation may make Source Derivative Propagation more accurate in problems +with strongly absorbing regions. + + +~~~~~~~~~~~~~~~~~~ +Initial Conditions +~~~~~~~~~~~~~~~~~~ +An initial condition for a kinetic simulation may be obtained obtained by +running a static eigenvalue simulation. To bake-in the initial steady +state, the prompt fission source in the total source term (Eq. +:eq:`source_td_final_flat`) and the delayed fission source in the precursor +integration (Eq. :eq:`dnp-eq-final-flat`) are divided by +:math:`k_\text{eff}`. `Kraus `_ found that utilizing a single +value of :math:`k_\text{eff}` for the initial condition results in a biased +flux. This bias is due applying :math:`k_\text{eff}` computed on the initial +quadrature to source terms on a subsequent (different) quadrature. There are +two approaches to resolving this bias: + +1. Recomputing :math:`k_\text{eff}`: This approach recomputed + :math:`k_\text{eff}` of the unperturbed system used to scale the fission + source on the current quadrature. +2. Time-consistent seed: This approach resets the PRNG seed at the beginning of + each time step so the resulting quadrature is the same in each time step. + +The time-consistent seed approach results in lower variance and shorter run +times than the :math:`k_\text{eff}` recomputation approach, so is the approach +used in OpenMC's implementation of the time-dependent Random Ray Method. + .. _adjoint: ------------------------ @@ -1158,6 +1469,8 @@ in random ray particle transport are: .. _Cosgrove-2023: https://doi.org/10.1080/00295639.2023.2270618 .. _Ferrer-2016: https://doi.org/10.13182/NSE15-6 .. _Gunow-2018: https://dspace.mit.edu/handle/1721.1/119030 +.. _Hoffman-2013: https://doi.org/10.1016/j.jcp.2015.10.039 +.. _Kraus-2025: https://doi.org/10.1080/00295639.2025.2456413 .. only:: html diff --git a/docs/source/usersguide/index.rst b/docs/source/usersguide/index.rst index 5f8e0197e70..12e5555cfb9 100644 --- a/docs/source/usersguide/index.rst +++ b/docs/source/usersguide/index.rst @@ -29,4 +29,5 @@ essential aspects of using OpenMC to perform simulations. volume variance_reduction random_ray + kinetic troubleshoot diff --git a/docs/source/usersguide/kinetic.rst b/docs/source/usersguide/kinetic.rst new file mode 100644 index 00000000000..ec32c82d590 --- /dev/null +++ b/docs/source/usersguide/kinetic.rst @@ -0,0 +1,90 @@ +.. _random_ray: + +=================== +Kinetic Simulations +=================== + +Much of OpenMC's existing infrastructure assumes a system is at a steady state. +Users interested in reactor transients should use the kinetic simulation +capability. Kinetic simulations can be enabled as:: + + settings.kinetic_simulation = True + +Kinetic simulations require the user to specify time step settings using the +``settings.timestep_parameters`` object. As an example, a 10 second long +simulation using 1 millisecond time steps can be set as:: + + settings.timestep_parameters = {'n_timesteps': 1000, + 'dt': 1, + 'timestep_units': 'ms'} + +.. note:: + When running kineic simulations, OpenMC will generate a statepoint file for + each time step named ``openmc_td_simulation_{i}.h5``, where ``i`` is the + index of the time step. + +Currently, only material density transients can be simulated. A density +transient can be specified using the Python API:: + + water = openmc.Material(name='water') + + # Linear ramp transient + densities = np.linspace(1, 0.95, 1000) + + water.set_density('macro', 1.0, density_timeseries=densities) + +.. note:: + Kinetic simulations are currently only supported in eigenvalue mode using the Random Ray solver. + +---------------------- +Random Ray Quick Start +---------------------- + +Random Ray's :ref:`automatic setup workflow ` can +be utilized to quickly generate models for kinetic simulations, however +slight modifications are needed: + +1. The `kinetic` flag should be set to `True`, and the number of delay groups must be + specified via `num_delay_groups` in the call to :meth:`openmc.Model.convert_to_multigroup`. + Take care to not specify more delay groups than the cross section library you + are using supports, as this will cause all sorts of problems when you try to run + the simulation. +2. By default, a time step size of 1 ms is chosen to accurately resolve delayed + neutron precursor dynamics, but the number of time steps must be manually + set in `openmc.Settings.timestep_parameters['n_timesteps']`. +3. Material density timeseries' must be manually added. + +An example process of converting an existing continuous energy +Monte Carlo model to a random ray model for kinetic simulations +is show below:: + + # Define continuous energy model as normal + model = openmc.Model() + ... + + # Convert model to kinetic multigroup (will auto-generate MGXS library if needed) + # Most cross-section libraries support 6 delay groups + model.convert_to_multigroup(kinetic=True, num_delayed_groups=6) + + # Add required manual kinetic simulation settigns + model.settings.timestep_parameters['n_timesteps'] = 5 + + # Add a material density timeseries to material 0 in the model + density_timeseries = np.linspace(1, 0.95, 100) + model.materials[0].set_density('macro', density=1.0, density_timeseries=density_timeseries) + + # Convert model to random ray and initialize random ray parameters + # to reasonable defaults based on the specifics of the geometry + model.convert_to_random_ray() + + # (Optional) Overlay source region decomposition mesh to improve fidelity of the + # random ray solver. Adjust 'n' for fidelity vs runtime. + n = 100 + mesh = openmc.RegularMesh() + mesh.dimension = (n, n, n) + mesh.lower_left = model.geometry.bounding_box.lower_left + mesh.upper_right = model.geometry.bounding_box.upper_right + model.settings.random_ray['source_region_meshes'] = [(mesh, [model.geometry.root_universe])] + + # (Optional) Increase the number of rays/batch, to reduce uncertainty + model.settings.particles = 500 diff --git a/docs/source/usersguide/random_ray.rst b/docs/source/usersguide/random_ray.rst index 382381a9eea..111d58065c9 100644 --- a/docs/source/usersguide/random_ray.rst +++ b/docs/source/usersguide/random_ray.rst @@ -640,7 +640,7 @@ model to use these multigroup cross sections. An example is given below:: # Assume we already have a working continuous energy model model.convert_to_multigroup( method="material_wise", - groups="CASMO-2", + energy_groups="CASMO-2", nparticles=2000, overwrite_mgxs_library=False, mgxs_path="mgxs.h5", @@ -707,6 +707,11 @@ generation and use an existing library file. with a :math:`\rho` default value of 1.0, which can be adjusted with the ``settings.random_ray['diagonal_stabilization_rho']`` parameter. +.. note:: + Cross sections for kinetic simulations may be generating by passing the + ``kinetic`` parameter as ``True``. Delay groups may be specified with an additional + parameter, ``num_delayed_group``, which by default is zero. + When generating MGXS data with either the ``stochastic_slab`` or ``infinite_medium`` methods, by default the simulation will use a uniform source distribution spread evenly over all energy groups. This ensures that all energy diff --git a/include/openmc/constants.h b/include/openmc/constants.h index bba260c3a4b..b3659ce4689 100644 --- a/include/openmc/constants.h +++ b/include/openmc/constants.h @@ -285,6 +285,7 @@ enum class MgxsType { PROMPT_NU_FISSION, DELAYED_NU_FISSION, NU_FISSION, + CHI, CHI_PROMPT, CHI_DELAYED }; @@ -326,7 +327,10 @@ enum TallyScore { SCORE_PULSE_HEIGHT = -17, // pulse-height SCORE_IFP_TIME_NUM = -18, // IFP lifetime numerator SCORE_IFP_BETA_NUM = -19, // IFP delayed fraction numerator - SCORE_IFP_DENOM = -20 // IFP common denominator + SCORE_IFP_DENOM = -20, // IFP common denominator + SCORE_PRECURSORS = -21 // delyaed neutron precursor concentration + // + }; // Global tally parameters @@ -366,6 +370,7 @@ enum class SolverType { MONTE_CARLO, RANDOM_RAY }; enum class RandomRayVolumeEstimator { NAIVE, SIMULATION_AVERAGED, HYBRID }; enum class RandomRaySourceShape { FLAT, LINEAR, LINEAR_XY }; enum class RandomRaySampleMethod { PRNG, HALTON }; +enum class RandomRayTimeMethod { ISOTROPIC, PROPAGATION }; //============================================================================== // Geometry Constants diff --git a/include/openmc/material.h b/include/openmc/material.h index e36946c71b6..eeb490058ec 100644 --- a/include/openmc/material.h +++ b/include/openmc/material.h @@ -204,6 +204,10 @@ class Material { unique_ptr ttb_; + // Time dependent data + vector + density_timeseries_; //!< Total atom density timeseries in [atom/b-cm] + private: //---------------------------------------------------------------------------- // Private methods diff --git a/include/openmc/random_ray/bd_utilities.h b/include/openmc/random_ray/bd_utilities.h new file mode 100644 index 00000000000..785ea061a75 --- /dev/null +++ b/include/openmc/random_ray/bd_utilities.h @@ -0,0 +1,80 @@ +#ifndef OPENMC_RANDOM_RAY_BD_UTILITIES_H +#define OPENMC_RANDOM_RAY_BD_UTILITIES_H + +#include +#include +#include + +#include "openmc/error.h" +#include "openmc/vector.h" + +namespace openmc { + +//---------------------------------------------------------------------------- +// Helper Variables +// Coefficients come from Table 3 in Fornberg (1988) +// DOI: 10.1090/S0025-5718-1988-0935077-0 +// Note that the signs are flipped compared to the citation, as the author was +// formulating weights for a forward difference +const std::map> bd_coefficients_first_order_ = { + {1, {1.0, -1.0}}, {2, {1.5, -2.0, 0.5}}, + {3, {1.833333333333333, -3.0, 1.5, -0.333333333333333}}, + {4, {2.083333333333333, -4.0, 3.0, -1.333333333333333, 0.25}}, + {5, {2.283333333333333, -5.0, 5.0, -3.333333333333333, 1.25, -0.2}}, + {6, {2.45, -6.0, 7.5, -6.666666666666667, 3.75, -1.2, 0.166666666666667}}}; + +// Coefficients come from Table 3 in Fornberg (1988) +// DOI: 10.1090/S0025-5718-1988-0935077-0 +const std::map> bd_coefficients_second_order_ = { + {1, {1.0, -2.0, 1.0}}, {2, {2.0, -5.0, 4, -1}}, + {3, {2.916666666666667, -8.666666666666667, 9.5, -4.666666666666667, + 0.916666666666667}}, + {4, {3.75, -12.833333333333333, 17.833333333333333, -13.0, 5.083333333333333, + -0.833333333333333}}, + {5, {4.511111111111111, -17.4, 29.25, -28.222222222222222, 16.5, -5.4, + 0.761111111111111}}, + {6, {5.211111111111111, -22.3, 43.95, -52.722222222222222, 41.0, -20.1, + 5.661111111111111, -0.7}}}; + +// Take RHS derivative to solve for the current timestep +template +T rhs_backwards_difference( + std::deque& bd_vector, int bd_order, double dt, int derivative_order = 1) +{ + vector bd_coeffs; + int n_bd_terms; + double time_factor; + if (derivative_order == 1) { + bd_coeffs = bd_coefficients_first_order_.at(bd_order); + time_factor = 1 / dt; + n_bd_terms = bd_order; + } else if (derivative_order == 2) { + bd_coeffs = bd_coefficients_second_order_.at(bd_order); + n_bd_terms = bd_order + 1; + time_factor = 1 / (dt * dt); + } else { + fatal_error("Only first or second order bd derivatives are allowed."); + } + T rhs_bd = 0.0; + for (int i = 0; i < n_bd_terms; i++) + rhs_bd += bd_coeffs[i + 1] * bd_vector[i]; + rhs_bd *= time_factor; + return rhs_bd; +} + +template +void add_value_to_bd_vector(std::deque& bd_vector, T& new_value, + bool increment_not_initialize, int initialize_size) +{ + bd_vector.push_front(new_value); + if (increment_not_initialize) { + bd_vector.pop_back(); + } else { + for (int i = 1; i < initialize_size; i++) + bd_vector.push_front(new_value); + } +} + +} // namespace openmc + +#endif // OPENMC_RANDOM_RAY_BD_UTILITIES_H diff --git a/include/openmc/random_ray/flat_source_domain.h b/include/openmc/random_ray/flat_source_domain.h index 4df4e5d8d32..61e0ab0dd57 100644 --- a/include/openmc/random_ray/flat_source_domain.h +++ b/include/openmc/random_ray/flat_source_domain.h @@ -39,6 +39,7 @@ class FlatSourceDomain { void reset_tally_volumes(); void random_ray_tally(); virtual void accumulate_iteration_flux(); + void accumulate_iteration_source(); void output_to_vtk() const; void convert_external_sources(); void count_external_source_regions(); @@ -49,6 +50,7 @@ class FlatSourceDomain { void flatten_xs(); void transpose_scattering_matrix(); void serialize_final_fluxes(vector& flux); + void serialize_final_sources(vector& source); void apply_meshes(); void apply_mesh_to_cell_instances(int32_t i_cell, int32_t mesh_idx, int target_material_id, const vector& instances, @@ -72,6 +74,31 @@ class FlatSourceDomain { int64_t lookup_mesh_bin(int64_t sr, Position r) const; int lookup_mesh_idx(int64_t sr) const; + //---------------------------------------------------------------------------- + // Methods for kinetic simulations + void compute_single_T1(SourceRegionHandle& srh); + + void compute_single_delayed_fission_source(SourceRegionHandle& srh); + void compute_single_precursors(SourceRegionHandle& srh); + void compute_all_precursors(); + + void serialize_final_precursors(vector& precursors); + void serialize_final_delayed_fission_source( + vector& delayed_fission_source); + + void precursors_swap(); + void accumulate_iteration_quantities(); + void normalize_final_quantities(); + void propagate_final_quantities(); + void store_time_step_quantities(bool increment_not_initialize = true); + void compute_rhs_bd_quantities(); + void update_material_density(int i); + + int64_t n_delay_elements() const + { + return source_regions_.n_source_regions() * ndgroups_; + } + //---------------------------------------------------------------------------- // Static Data members static bool volume_normalized_flux_tallies_; @@ -90,7 +117,10 @@ class FlatSourceDomain { //---------------------------------------------------------------------------- // Public Data members - double k_eff_ {1.0}; // Eigenvalue + double k_eff_ {1.0}; // Eigenvalue + double + fission_rate_; // The system's fission rate (per cm^3), in eigenvalue mode + bool mapped_all_tallies_ {false}; // If all source regions have been visited int64_t n_external_source_regions_ {0}; // Total number of source regions with @@ -149,6 +179,24 @@ class FlatSourceDomain { // technique. bool is_transport_stabilization_needed_ {false}; + //--------------------------------------------------------------------------- + // Public Data Members for kinetic simulations + + // 2D arrays stored in 1D representing values for all materials x + // delay_groups + vector lambda_; + + // 3D arrays stored in 1D representing values for all materials x energy + // groups x delay groups + vector nu_d_sigma_f_; + vector chi_d_; + + // 2D arrays stored in 1D representing values for all materials x energy + // groups + vector nu_p_sigma_f_; + vector chi_p_; + vector inverse_vbar_; + protected: //---------------------------------------------------------------------------- // Methods @@ -165,14 +213,12 @@ class FlatSourceDomain { //---------------------------------------------------------------------------- // Private data members int negroups_; // Number of energy groups in simulation + int ndgroups_; // Number of delay groups in simulation double simulation_volume_; // Total physical volume of the simulation domain, as // defined by the 3D box of the random ray source - double - fission_rate_; // The system's fission rate (per cm^3), in eigenvalue mode - // Volumes for each tally and bin/score combination. This intermediate data // structure is used when tallying quantities that must be normalized by // volume (i.e., flux). The vector is index by tally index, while the inner 2D diff --git a/include/openmc/random_ray/random_ray.h b/include/openmc/random_ray/random_ray.h index 40c67ef9549..0d28aef2fd8 100644 --- a/include/openmc/random_ray/random_ray.h +++ b/include/openmc/random_ray/random_ray.h @@ -50,12 +50,32 @@ class RandomRay : public Particle { static RandomRaySourceShape source_shape_; // Flag for linear source static RandomRaySampleMethod sample_method_; // Flag for sampling method + static double avg_miss_rate_; // Average ray miss rate per + // iteration for reporting + static int64_t n_source_regions_; // Total number of source regions + static int64_t + n_external_source_regions_; // Total number of source regions with + // non-zero external source terms + static uint64_t total_geometric_intersections_; // Tracks the total number of + // geometric intersections by + // all rays for reporting + + // Kinetic simulation variables + static int bd_order_; // Order of backwards difference approximation for + // time-derivatives + static RandomRayTimeMethod + time_method_; // Method for resolving angular flux time derivative term for + // flux propogation + //---------------------------------------------------------------------------- // Public data members vector angular_flux_; - bool ray_trace_only_ {false}; // If true, only perform geometry operations + //--------------------------------------------------------------------------- + // Public data members for kinetic simulations + vector angular_flux_prime_; + private: //---------------------------------------------------------------------------- // Private data members @@ -70,6 +90,7 @@ class RandomRay : public Particle { double distance_travelled_ {0}; bool is_active_ {false}; bool is_alive_ {true}; + }; // class RandomRay } // namespace openmc diff --git a/include/openmc/random_ray/random_ray_simulation.h b/include/openmc/random_ray/random_ray_simulation.h index 3dec48bf266..ff93c9bf93a 100644 --- a/include/openmc/random_ray/random_ray_simulation.h +++ b/include/openmc/random_ray/random_ray_simulation.h @@ -19,16 +19,18 @@ class RandomRaySimulation { //---------------------------------------------------------------------------- // Methods - void compute_segment_correction_factors(); void apply_fixed_sources_and_mesh_domains(); void prepare_fixed_sources_adjoint(); + void print_random_ray_headers(); + void run_single_simulation(); + void random_ray_adjoint(); + void kinetic_initial_condition(); + void kinetic_single_time_step(int i); void simulate(); void output_simulation_results() const; void instability_check( int64_t n_hits, double k_eff, double& avg_miss_rate) const; - void print_results_random_ray(uint64_t total_geometric_intersections, - double avg_miss_rate, int negroups, int64_t n_source_regions, - int64_t n_external_source_regions) const; + void print_results_random_ray() const; //---------------------------------------------------------------------------- // Accessors @@ -36,7 +38,7 @@ class RandomRaySimulation { private: //---------------------------------------------------------------------------- - // Data members + // Data Members // Contains all flat source region data unique_ptr domain_; @@ -51,6 +53,22 @@ class RandomRaySimulation { // Number of energy groups int negroups_; + // Number of delay groups + int ndgroups_; + + // Toggle for first simulation + bool is_first_simulation_; + + // Flag for adjoint simulation; + bool adjoint_needed_; + + //---------------------------------------------------------------------------- + // Data Members for kinetic simulations + + double static_avg_k_eff_; + vector static_k_eff_; + vector static_fission_rate_; + }; // class RandomRaySimulation //============================================================================ @@ -61,6 +79,16 @@ void openmc_run_random_ray(); void validate_random_ray_inputs(); void openmc_reset_random_ray(); +//! Write data related to randaom ray to statepoint +//! \param[in] group HDF5 group +void write_random_ray_hdf5(hid_t group); +void print_random_ray_headers(bool& adjoint_needed); + +// Functions for kinetic simulations +void set_time_dependent_settings(); +void rename_time_step_file( + std::string base_filename, std::string extension, int i); + } // namespace openmc #endif // OPENMC_RANDOM_RAY_SIMULATION_H diff --git a/include/openmc/random_ray/source_region.h b/include/openmc/random_ray/source_region.h index 0f5a747fff8..e9781b2dfa3 100644 --- a/include/openmc/random_ray/source_region.h +++ b/include/openmc/random_ray/source_region.h @@ -1,6 +1,8 @@ #ifndef OPENMC_RANDOM_RAY_SOURCE_REGION_H #define OPENMC_RANDOM_RAY_SOURCE_REGION_H +#include + #include "openmc/openmp_interface.h" #include "openmc/position.h" #include "openmc/random_ray/moment_matrix.h" @@ -141,6 +143,7 @@ class SourceRegionHandle { //---------------------------------------------------------------------------- // Public Data members int negroups_; + int ndgroups_; bool is_numerical_fp_artifact_ {false}; bool is_linear_ {false}; @@ -176,6 +179,7 @@ class SourceRegionHandle { double* scalar_flux_old_; double* scalar_flux_new_; float* source_; + float* source_final_; float* external_source_; double* scalar_flux_final_; @@ -189,6 +193,38 @@ class SourceRegionHandle { // associated with it, necessitating the use of a jagged array. vector* tally_task_; + //--------------------------------------------------------------------------- + // Public Data Members for kinetic simulations + + // Energy group-wise 1D time-derivative arrays + double* T1_; + + // Delay group-wise 1D arrays + double* delayed_fission_source_; + double* precursors_old_; + double* precursors_new_; + double* precursors_final_; + + // Energy group-wise 2D BD arrays (g x time step) + std::deque* scalar_flux_bd_; + std::deque* precursors_bd_; + + // Delay group-wise 2D BD arrays (dg x time step) + std::deque* source_bd_; + + // Energy group-wise 1D RHS BD arrays + double* scalar_flux_rhs_bd_; + float* source_rhs_bd_; + double* scalar_flux_rhs_bd_2_; + + // Delay group-wise 1D RHS BD arrays + double* precursors_rhs_bd_; + + // 2D array representing values for all delay groups x tally + // tasks. Each group may have a different number of tally tasks + // associated with it, necessitating the use of a jagged array. + vector* tally_delay_task_; + //---------------------------------------------------------------------------- // Public Accessors @@ -274,6 +310,9 @@ class SourceRegionHandle { float& source(int g) { return source_[g]; } const float source(int g) const { return source_[g]; } + float& source_final(int g) { return source_final_[g]; } + const float source_final(int g) const { return source_final_[g]; } + float& external_source(int g) { return external_source_[g]; } const float external_source(int g) const { return external_source_[g]; } @@ -301,13 +340,75 @@ class SourceRegionHandle { vector& tally_task(int g) { return tally_task_[g]; } const vector& tally_task(int g) const { return tally_task_[g]; } + //--------------------------------------------------------------------------- + // Public Accessors for kinetic simulations + double& T1(int g) { return T1_[g]; } + const double T1(int g) const { return T1_[g]; } + + double& delayed_fission_source(int dg) { return delayed_fission_source_[dg]; } + const double delayed_fission_source(int dg) const + { + return delayed_fission_source_[dg]; + } + + double& precursors_old(int dg) { return precursors_old_[dg]; } + const double precursors_old(int dg) const { return precursors_old_[dg]; } + + double& precursors_new(int dg) { return precursors_new_[dg]; } + const double precursors_new(int dg) const { return precursors_new_[dg]; } + + double& precursors_final(int dg) { return precursors_final_[dg]; } + const double precursors_final(int dg) const { return precursors_final_[dg]; } + + std::deque& scalar_flux_bd(int g) { return scalar_flux_bd_[g]; } + const std::deque& scalar_flux_bd(int g) const + { + return scalar_flux_bd_[g]; + } + + std::deque& precursors_bd(int dg) { return precursors_bd_[dg]; } + const std::deque& precursors_bd(int dg) const + { + return precursors_bd_[dg]; + } + + std::deque& source_bd(int g) { return source_bd_[g]; } + const std::deque& source_bd(int g) const { return source_bd_[g]; } + + double& scalar_flux_rhs_bd(int g) { return scalar_flux_rhs_bd_[g]; } + const double scalar_flux_rhs_bd(int g) const + { + return scalar_flux_rhs_bd_[g]; + } + + float& source_rhs_bd(int g) { return source_rhs_bd_[g]; } + const float source_rhs_bd(int g) const { return source_rhs_bd_[g]; } + + double& scalar_flux_rhs_bd_2(int g) { return scalar_flux_rhs_bd_2_[g]; } + const double scalar_flux_rhs_bd_2(int g) const + { + return scalar_flux_rhs_bd_2_[g]; + } + + double& precursors_rhs_bd(int dg) { return precursors_rhs_bd_[dg]; } + const double precursors_rhs_bd(int dg) const + { + return precursors_rhs_bd_[dg]; + } + + vector& tally_delay_task(int dg) { return tally_delay_task_[dg]; } + const vector& tally_delay_task(int dg) const + { + return tally_delay_task_[dg]; + } + }; // class SourceRegionHandle class SourceRegion { public: //---------------------------------------------------------------------------- // Constructors - SourceRegion(int negroups, bool is_linear); + SourceRegion(int negroups, int ndgroups, bool is_linear); SourceRegion() = default; //---------------------------------------------------------------------------- @@ -362,7 +463,9 @@ class SourceRegion { vector external_source_; //!< The external source term vector scalar_flux_final_; //!< The scalar flux accumulated over all //!< active iterations (used for plotting, - //!< or computing adjoint sources) + //!< computing adjoint sources, or + //!< computing an initial condition for a + //!< kinetic simulation) vector source_gradients_; //!< The linear source gradients vector @@ -378,14 +481,82 @@ class SourceRegion { // tasks. Each group may have a different number of tally tasks // associated with it, necessitating the use of a jagged array. vector> tally_task_; + + //---------------------------------------------------------------------------- + // Public Data Members for kinetic simulations + + // Energy group-wise 1D time-dependent arrrays + vector source_final_; //!< The total source accumulated over all + //!< active iterations (used for SDP) + + // Energy group-wise 1D derivative arrays + vector T1_; //!< The combined sourcetime derivative and 2nd order + //!< scalar flux time derivative (used for SDP) + // Delay group-wise 1D arrays + vector delayed_fission_source_; //!< The delayed fission source binned + //!< by delay group + vector precursors_old_; //!< The precursor density from the previous + //!< iteration. + vector + precursors_new_; //!< The precursor density for the current iteration + vector + precursors_final_; //!< The precursor density accumulated over all + //!< active iterations (used for computing + //!< the time derivative of precursor population) + + // Energy group-wise 2D BD arrays (g x time step) + vector> + scalar_flux_bd_; //!< The final scalar flux in each energy group from a + //!< finite number of previous time steps (used for + //!< computing the first order (and second order, for SDP) + //!< scalar flux time derivative) + vector> + precursors_bd_; //!< The final scalar flux in each energy group from a + //!< finite number of previous time steps (used for + //!< computing the first order source time derivative for + //!< SDP) + + // Delay group-wise 2D BD arrays (dg x time step) + vector> + source_bd_; //!< The final precursor population in each energy group from a + //!< finite number of previous time steps (used for computing + //!< the first order precursor time derivative) + + // Energy group-wise 1D RHS BD arrays + vector + scalar_flux_rhs_bd_; //!< RHS dervative for the scalar flux from previous + //!< timesteps. Used to compute the total scalar flux + //!< time derivative for both TI and SDP time-dependent + //!< simulations + vector source_rhs_bd_; //!< RHS derivative for the neutron source from + //!< previous timesteps Used for compute the + //!< total neutron source derivative for SDP + vector + scalar_flux_rhs_bd_2_; //!< 2nd order RHS derivative for the scalar flux + //!< from previous timesteps. Used to compute the + //!< total 2nd order scalar flux time derivative for + //!< SDP. + + // Delay group-wise 1D RHS BD arrays + vector + precursors_rhs_bd_; //!< RHS derivative for the precursors from previous + //!< timesteps. Used to compute the total precursor time + //!< derivative for solving the precursor equation using + //!< backwards differences. + + // 2D array representing values for all delay groups x tally + // tasks. Each group may have a different number of tally tasks + // associated with it, necessitating the use of a jagged array. + vector> tally_delay_task_; + }; // class SourceRegion class SourceRegionContainer { public: //---------------------------------------------------------------------------- // Constructors - SourceRegionContainer(int negroups, bool is_linear) - : negroups_(negroups), is_linear_(is_linear) + SourceRegionContainer(int negroups, int ndgroups, bool is_linear) + : negroups_(negroups), ndgroups_(ndgroups), is_linear_(is_linear) {} SourceRegionContainer() = default; @@ -560,6 +731,14 @@ class SourceRegionContainer { float& source(int64_t se) { return source_[se]; } const float source(int64_t se) const { return source_[se]; } + float& source_final(int64_t sr, int g) { return source_final_[index(sr, g)]; } + const float source_final(int64_t sr, int g) const + { + return source_final_[index(sr, g)]; + } + float& source_final(int64_t se) { return source_final_[se]; } + const float source_final(int64_t se) const { return source_final_[se]; } + float& external_source(int64_t sr, int g) { return external_source_[index(sr, g)]; @@ -601,6 +780,178 @@ class SourceRegionContainer { int64_t& parent_sr(int64_t sr) { return parent_sr_[sr]; } const int64_t parent_sr(int64_t sr) const { return parent_sr_[sr]; } + //--------------------------------------- + // For kinetic simulations + double& T1(int64_t sr, int g) { return T1_[index(sr, g)]; } + const double& T1(int64_t sr, int g) const { return T1_[index(sr, g)]; } + double& T1(int64_t se) { return T1_[se]; } + const double& T1(int64_t se) const { return T1_[se]; } + + double& precursors_old(int64_t sr, int dg) + { + return precursors_old_[dindex(sr, dg)]; + } + const double& precursors_old(int64_t sr, int dg) const + { + return precursors_old_[dindex(sr, dg)]; + } + double& precursors_old(int64_t de) { return precursors_old_[de]; } + const double& precursors_old(int64_t de) const { return precursors_old_[de]; } + + double& precursors_new(int64_t sr, int dg) + { + return precursors_new_[dindex(sr, dg)]; + } + const double& precursors_new(int64_t sr, int dg) const + { + return precursors_new_[dindex(sr, dg)]; + } + double& precursors_new(int64_t de) { return precursors_new_[de]; } + const double& precursors_new(int64_t de) const { return precursors_new_[de]; } + + double& precursors_final(int64_t sr, int dg) + { + return precursors_final_[dindex(sr, dg)]; + } + const double& precursors_final(int64_t sr, int dg) const + { + return precursors_final_[dindex(sr, dg)]; + } + double& precursors_final(int64_t de) { return precursors_final_[de]; } + const double& precursors_final(int64_t de) const + { + return precursors_final_[de]; + } + + double& delayed_fission_source(int64_t sr, int dg) + { + return delayed_fission_source_[dindex(sr, dg)]; + } + const double& delayed_fission_source(int64_t sr, int dg) const + { + return delayed_fission_source_[dindex(sr, dg)]; + } + double& delayed_fission_source(int64_t de) + { + return delayed_fission_source_[de]; + } + const double& delayed_fission_source(int64_t de) const + { + return delayed_fission_source_[de]; + } + + std::deque& scalar_flux_bd(int64_t sr, int g) + { + return scalar_flux_bd_[index(sr, g)]; + } + const std::deque& scalar_flux_bd(int64_t sr, int g) const + { + return scalar_flux_bd_[index(sr, g)]; + } + std::deque& scalar_flux_bd(int64_t se) { return scalar_flux_bd_[se]; } + const std::deque& scalar_flux_bd(int64_t se) const + { + return scalar_flux_bd_[se]; + } + + std::deque& precursors_bd(int64_t sr, int dg) + { + return precursors_bd_[dindex(sr, dg)]; + } + const std::deque& precursors_bd(int64_t sr, int dg) const + { + return precursors_bd_[dindex(sr, dg)]; + } + std::deque& precursors_bd(int64_t de) { return precursors_bd_[de]; } + const std::deque& precursors_bd(int64_t de) const + { + return precursors_bd_[de]; + } + + std::deque& source_bd(int64_t sr, int g) + { + return source_bd_[index(sr, g)]; + } + const std::deque& source_bd(int64_t sr, int g) const + { + return source_bd_[index(sr, g)]; + } + std::deque& source_bd(int64_t se) { return source_bd_[se]; } + const std::deque& source_bd(int64_t se) const + { + return source_bd_[se]; + } + + double& scalar_flux_rhs_bd(int64_t sr, int g) + { + return scalar_flux_rhs_bd_[index(sr, g)]; + } + const double& scalar_flux_rhs_bd(int64_t sr, int g) const + { + return scalar_flux_rhs_bd_[index(sr, g)]; + } + double& scalar_flux_rhs_bd(int64_t se) { return scalar_flux_rhs_bd_[se]; } + const double& scalar_flux_rhs_bd(int64_t se) const + { + return scalar_flux_rhs_bd_[se]; + } + + double& precursors_rhs_bd(int64_t sr, int dg) + { + return precursors_rhs_bd_[dindex(sr, dg)]; + } + const double& precursors_rhs_bd(int64_t sr, int dg) const + { + return precursors_rhs_bd_[dindex(sr, dg)]; + } + double& precursors_rhs_bd(int64_t de) { return precursors_rhs_bd_[de]; } + const double& precursors_rhs_bd(int64_t de) const + { + return precursors_rhs_bd_[de]; + } + + float& source_rhs_bd(int64_t sr, int g) + { + return source_rhs_bd_[index(sr, g)]; + } + const float& source_rhs_bd(int64_t sr, int g) const + { + return source_rhs_bd_[index(sr, g)]; + } + float& source_rhs_bd(int64_t se) { return source_rhs_bd_[se]; } + const float& source_rhs_bd(int64_t se) const { return source_rhs_bd_[se]; } + + double& scalar_flux_rhs_bd_2(int64_t sr, int g) + { + return scalar_flux_rhs_bd_2_[index(sr, g)]; + } + const double& scalar_flux_rhs_bd_2(int64_t sr, int g) const + { + return scalar_flux_rhs_bd_2_[index(sr, g)]; + } + double& scalar_flux_rhs_bd_2(int64_t se) { return scalar_flux_rhs_bd_2_[se]; } + const double& scalar_flux_rhs_bd_2(int64_t se) const + { + return scalar_flux_rhs_bd_2_[se]; + } + + vector& tally_delay_task(int64_t sr, int dg) + { + return tally_delay_task_[dindex(sr, dg)]; + } + const vector& tally_delay_task(int64_t sr, int dg) const + { + return tally_delay_task_[dindex(sr, dg)]; + } + vector& tally_delay_task(int64_t de) + { + return tally_delay_task_[de]; + } + const vector& tally_delay_task(int64_t de) const + { + return tally_delay_task_[de]; + } + //---------------------------------------------------------------------------- // Public Methods @@ -616,11 +967,22 @@ class SourceRegionContainer { SourceRegionHandle get_source_region_handle(int64_t sr); void adjoint_reset(); + //--------------------------------------------------------------------------- + // Public Methods for kinetic simulations + + int64_t n_delay_elements() const { return n_source_regions_ * ndgroups_; } + int& ndgroups() { return ndgroups_; } + const int ndgroups() const { return ndgroups_; } + + void precursors_swap(); + void time_step_reset(); + private: //---------------------------------------------------------------------------- // Private Data Members int64_t n_source_regions_ {0}; int negroups_ {0}; + int ndgroups_ {0}; bool is_linear_ {false}; // SoA storage for scalar fields (one item per source region) @@ -653,6 +1015,7 @@ class SourceRegionContainer { vector scalar_flux_new_; vector scalar_flux_final_; vector source_; + vector source_final_; vector external_source_; vector source_gradients_; @@ -667,11 +1030,44 @@ class SourceRegionContainer { // dimension. vector> tally_task_; + //--------------------------------------------------------------------------- + // Private Data Members for kinetic simulations + + // SoA energy group-wise 2D derivative arrays flattened to 1D + vector T1_; + + // SoA delay group-wise 2D arrays flattened to 1D + vector delayed_fission_source_; + vector precursors_old_; + vector precursors_new_; + vector precursors_final_; + + // SoA energy group-wise 3D BD arrays (sr x g/dg X timestep) flattened to 2D + vector> scalar_flux_bd_; + vector> precursors_bd_; + vector> source_bd_; + + // SoA energy group-wise 2D RHS BD arrays flattened to 1D + vector scalar_flux_rhs_bd_; + vector source_rhs_bd_; + vector scalar_flux_rhs_bd_2_; + + // SoA delay group-wise 2D RHS BD arrays flattened to 1D + vector precursors_rhs_bd_; + + // SoA 3D array representing values for all source regions x delay groups x + // tally tasks. The outer two dimensions (source regions and delay groups) + // are flattened to 1D. Each group may have a different number of tally tasks + // associated with it, necessitating the use of a jagged array for the inner + // dimension. + vector> tally_delay_task_; + //---------------------------------------------------------------------------- // Private Methods // Helper function for indexing inline int index(int64_t sr, int g) const { return sr * negroups_ + g; } + inline int dindex(int64_t sr, int dg) const { return sr * ndgroups_ + dg; } }; } // namespace openmc diff --git a/include/openmc/settings.h b/include/openmc/settings.h index b369c99fef8..f4372a2eca3 100644 --- a/include/openmc/settings.h +++ b/include/openmc/settings.h @@ -71,6 +71,8 @@ extern "C" bool entropy_on; //!< calculate Shannon entropy? extern "C" bool event_based; //!< use event-based mode (instead of history-based) extern bool ifp_on; //!< Use IFP for kinetics parameters? +extern bool kinetic_simulation; //!< Flag determining if the simulation is + //!< kinetic or static extern bool legendre_to_tabular; //!< convert Legendre distributions to tabular? extern bool material_cell_offsets; //!< create material cells offsets? extern "C" bool output_summary; //!< write summary.h5? @@ -198,6 +200,9 @@ extern "C" int verbosity; //!< How verbose to make output extern double weight_cutoff; //!< Weight cutoff for Russian roulette extern double weight_survive; //!< Survival weight after Russian roulette +// Timestep variables for kinetic simulation +extern int n_timesteps; //!< number of timesteps +extern double dt; //!< fixed timestep size } // namespace settings //============================================================================== diff --git a/include/openmc/simulation.h b/include/openmc/simulation.h index 9a6cf1b2131..2e310726fb8 100644 --- a/include/openmc/simulation.h +++ b/include/openmc/simulation.h @@ -49,6 +49,15 @@ extern const RegularMesh* ufs_mesh; extern vector k_generation; extern vector work_index; +//----------------------------------------------------------------------------- +// Global variables for kinetic simulations +extern bool + is_initial_condition; //!< if eigenvalue/fixed source sim is an initial + //!< condition for a kinetic simulation +extern int current_timestep; // !< current time step in kinetic simulation +extern double current_time; // !< current time in kinetic simulation +extern bool k_eff_correction; // !< flag to indicate if the simulation is meant + // to correct batchwise k_effs } // namespace simulation //============================================================================== diff --git a/include/openmc/timer.h b/include/openmc/timer.h index d928aad4560..bcb2a7e644a 100644 --- a/include/openmc/timer.h +++ b/include/openmc/timer.h @@ -33,6 +33,9 @@ extern Timer time_event_collision; extern Timer time_event_death; extern Timer time_update_src; +extern Timer time_update_bd_vectors; +extern Timer time_compute_precursors; + } // namespace simulation //============================================================================== diff --git a/include/openmc/xsdata.h b/include/openmc/xsdata.h index feafde68dd3..134f738fa08 100644 --- a/include/openmc/xsdata.h +++ b/include/openmc/xsdata.h @@ -83,6 +83,9 @@ class XsData { // delayed_nu_fission has the following dimensions: // [angle][delayed group][incoming group] xt::xtensor delayed_nu_fission; + // chi has the following dimensions: + // [angle][incoming group][outgoing group] + xt::xtensor chi; // chi_prompt has the following dimensions: // [angle][incoming group][outgoing group] xt::xtensor chi_prompt; diff --git a/openmc/examples.py b/openmc/examples.py index 01dd9d01f97..19c2e3e73d1 100644 --- a/openmc/examples.py +++ b/openmc/examples.py @@ -4,6 +4,8 @@ import openmc +C5G7_N_DG = 8 +PINCELL_PITCH = 1.26 def pwr_pin_cell() -> openmc.Model: @@ -656,30 +658,46 @@ def slab_mg(num_regions=1, mat_names=None, mgxslib_name='2g.h5') -> openmc.Model return model -def random_ray_lattice() -> openmc.Model: - """Create a 2x2 PWR pincell asymmetrical lattic eexample. +def _generate_c5g7_materials(kinetic) -> openmc.Materials: + """Generate materials utilizing multi-group cross sections based on the + the C5G7 Benchmark. - This model is a 2x2 reflective lattice of fuel pins with one of the lattice - locations having just moderator instead of a fuel pin. It uses 7 group - cross section data. + Parameters + ---------- + kinetic : bool + Flag to generate cross sections for kinetic simulations. Returns ------- - model : openmc.Model - A PWR 2x2 lattice model - + materials : openmc.Materials + Materials object containing UO2 and water materials. + + Data Sources + ------------ + Prompt and delated fission cross sections, prompt and delayed fission + spectra, decay constants, delayed neutron fractions, and velocity data come + from: + Hou et al., "OECD/NEA benchmark for time-dependnet neutron + transport calculations without homogeniztaion" + DOI: 10.1016/j.nucengdes.2017.02.008 + + All other cross section data are from: + Lewis et al., "Benchmark specification for determinisitc 2D/3D MOX fuel + assembly transport calculations without spatial homogenization" """ - model = openmc.Model() - - ########################################################################### - # Create MGXS data for the problem - # Instantiate the energy group data group_edges = [1e-5, 0.0635, 10.0, 1.0e2, 1.0e3, 0.5e6, 1.0e6, 20.0e6] groups = openmc.mgxs.EnergyGroups(group_edges) + # Number of delayed groups for a time-dependent simulation + # Delayed cross section values + # come from Hou et al., "OECD/NEA benchmark for time-dependnet neutron + # transport calculations without homogeniztaion" + # DOI: 10.1016/j.nucengdes.2017.02.008 + n_dg = C5G7_N_DG if kinetic else 0 + # Instantiate the 7-group (C5G7) cross section data - uo2_xsdata = openmc.XSdata('UO2', groups) + uo2_xsdata = openmc.XSdata('UO2', groups, num_delayed_groups=n_dg) uo2_xsdata.order = 0 uo2_xsdata.set_total( [0.1779492, 0.3298048, 0.4803882, 0.5543674, 0.3118013, 0.3951678, @@ -704,13 +722,68 @@ def random_ray_lattice() -> openmc.Model: uo2_xsdata.set_fission([7.21206e-03, 8.19301e-04, 6.45320e-03, 1.85648e-02, 1.78084e-02, 8.30348e-02, 2.16004e-01]) - uo2_xsdata.set_nu_fission([2.005998e-02, 2.027303e-03, 1.570599e-02, - 4.518301e-02, 4.334208e-02, 2.020901e-01, - 5.257105e-01]) + nu_fission = np.array([2.005998e-02, 2.027303e-03, 1.570599e-02, + 4.518301e-02, 4.334208e-02, 2.020901e-01, + 5.257105e-01]) + uo2_xsdata.set_nu_fission(nu_fission) uo2_xsdata.set_chi([5.8791e-01, 4.1176e-01, 3.3906e-04, 1.1761e-07, 0.0000e+00, 0.0000e+00, 0.0000e+00]) - h2o_xsdata = openmc.XSdata('LWTR', groups) + # Delayed and prompt cross sections for time-dependent simulation + if kinetic: + + # Table A2 in Hou et. al + beta = np.array([[2.13333e-04, 2.13333e-04, 2.13333e-04, 2.13333e-04, 2.13333e-04, 2.13333e-04, 2.13333e-04], + [1.04514e-03, 1.04514e-03, 1.04514e-03, 1.04514e-03, + 1.04514e-03, 1.04514e-03, 1.04514e-03], + [6.03969e-04, 6.03969e-04, 6.03969e-04, 6.03969e-04, + 6.03969e-04, 6.03969e-04, 6.03969e-04], + [1.33963e-03, 1.33963e-03, 1.33963e-03, 1.33963e-03, + 1.33963e-03, 1.33963e-03, 1.33963e-03], + [2.29386e-03, 2.29386e-03, 2.29386e-03, 2.29386e-03, + 2.29386e-03, 2.29386e-03, 2.29386e-03], + [7.05174e-04, 7.05174e-04, 7.05174e-04, 7.05174e-04, + 7.05174e-04, 7.05174e-04, 7.05174e-04], + [6.00381e-04, 6.00381e-04, 6.00381e-04, 6.00381e-04, + 6.00381e-04, 6.00381e-04, 6.00381e-04], + [2.07736e-04, 2.07736e-04, 2.07736e-04, 2.07736e-04, 2.07736e-04, 2.07736e-04, 2.07736e-04]]) + # the actual tot is 7.009223e-03 + beta_tot = 7.00922e-03 + + # Table A2 in Hou et. al + uo2_xsdata.set_decay_rate([1.247e-02, 2.829e-02, 4.252e-02, + 1.330e-01, 2.925e-01, 6.665e-01, + 1.635e+00, 3.555e+00]) + # Derived from manipulating eq. B-3 in Hou et al. + # chi_prompt = (chi - np.sum(chi_delayed * beta, 0)) / (1 - beta_tot) + uo2_xsdata.set_chi_prompt([5.91741e-01, 4.07977e-01, 2.91169e-04, + 1.18440e-07, 0.00000e+00, 0.00000e+00, + 0.00000e+00]) + # Table A3 in Hou et al. + chi_delayed = np.array([[0.00075, 0.98512, 0.01413, 0.0000e+00, 0.0000e+00, 0.0000e+00, 0.0000e+00], + [0.03049, 0.96907, 0.00044, 0.0000e+00, + 0.0000e+00, 0.0000e+00, 0.0000e+00], + [0.00457, 0.97401, 0.02142, 0.0000e+00, + 0.0000e+00, 0.0000e+00, 0.0000e+00], + [0.02002, 0.97271, 0.00727, 0.0000e+00, + 0.0000e+00, 0.0000e+00, 0.0000e+00], + [0.05601, 0.93818, 0.00581, 0.0000e+00, + 0.0000e+00, 0.0000e+00, 0.0000e+00], + [0.06098, 0.93444, 0.00458, 0.0000e+00, + 0.0000e+00, 0.0000e+00, 0.0000e+00], + [0.10635, 0.88298, 0.01067, 0.0000e+00, + 0.0000e+00, 0.0000e+00, 0.0000e+00], + [0.09346, 0.9026, 0.00394, 0.0000e+00, 0.0000e+00, 0.0000e+00, 0.0000e+00]]) + uo2_xsdata.set_chi_delayed(chi_delayed) + # Table A4 in Hou et al. + velocities = np.array([2.23466e+09, 5.07347e+08, 3.86595e+07, + 5.13931e+06, 1.67734e+06, 7.28603e+05, 2.92902e+05]) + uo2_xsdata.set_inverse_velocity(1 / velocities) + # We need to set these so XsData::fission_matrix_beta_from_hdf5 is set + uo2_xsdata.set_prompt_nu_fission((1 - beta_tot) * nu_fission) + uo2_xsdata.set_delayed_nu_fission(beta * nu_fission) + + h2o_xsdata = openmc.XSdata('LWTR', groups, num_delayed_groups=n_dg) h2o_xsdata.order = 0 h2o_xsdata.set_total([0.15920605, 0.412969593, 0.59030986, 0.58435, 0.718, 1.2544497, 2.650379]) @@ -733,7 +806,13 @@ def random_ray_lattice() -> openmc.Model: scatter_matrix = np.rollaxis(scatter_matrix, 0, 3) h2o_xsdata.set_scatter_matrix(scatter_matrix) - mg_cross_sections = openmc.MGXSLibrary(groups) + if kinetic: + # Table A4 in Hou et al. + velocities = np.array([2.23517E+09, 4.98880E+08, 3.84974E+07, + 5.12639E+06, 1.67542E+06, 7.26031E+05, 2.81629E+05]) + h2o_xsdata.set_inverse_velocity(1 / velocities) + + mg_cross_sections = openmc.MGXSLibrary(groups, num_delayed_groups=n_dg) mg_cross_sections.add_xsdatas([uo2_xsdata, h2o_xsdata]) mg_cross_sections.export_to_hdf5('mgxs.h5') @@ -745,21 +824,40 @@ def random_ray_lattice() -> openmc.Model: uo2.set_density('macro', 1.0) uo2.add_macroscopic('UO2') + if kinetic: + densities = np.linspace(1, 0.95, 100) + else: + densities = None + water = openmc.Material(name='Water') - water.set_density('macro', 1.0) + water.set_density('macro', 1.0, densities) water.add_macroscopic('LWTR') # Instantiate a Materials collection and export to XML materials = openmc.Materials([uo2, water]) materials.cross_sections = "mgxs.h5" + return materials - ########################################################################### - # Define problem geometry - ######################################## - # Define an unbounded pincell universe +def _generate_random_ray_pin_cell(uo2, water) -> openmc.Universe: + """Create a random ray pin cell universe. Helper function for + random_ray_pin_cell() and random_ray_lattice() - pitch = 1.26 + Parameters + ---------- + uo2 : openmc.Material + UO2 material + water : openmc.Material + Water material + + Returns + ------- + pincell : openmc.Universe + Universe containing an unbounded pin cell + + """ + ######################################## + # Define an unbounded pin cell universe # Create a surface for the fuel outer radius fuel_or = openmc.ZCylinder(r=0.54, name='Fuel OR') @@ -781,7 +879,7 @@ def random_ray_lattice() -> openmc.Model: moderator_c = openmc.Cell( fill=water, region=+outer_ring_b, name='moderator outer c') - # Create pincell universe + # Create pin cell universe pincell_base = openmc.Universe() # Register Cells with Universe @@ -801,22 +899,159 @@ def random_ray_lattice() -> openmc.Model: for i in range(8): azimuthal_cell = openmc.Cell(name=f'azimuthal_cell_{i}') azimuthal_cell.fill = pincell_base - azimuthal_cell.region = +azimuthal_planes[i] & -azimuthal_planes[(i+1) % 8] + azimuthal_cell.region = + \ + azimuthal_planes[i] & -azimuthal_planes[(i+1) % 8] azimuthal_cells.append(azimuthal_cell) # Create a geometry with the azimuthal universes pincell = openmc.Universe(cells=azimuthal_cells, name='pincell') + return pincell + + +def random_ray_pin_cell(kinetic=False) -> openmc.Model: + """Create a PWR pin cell example using C5G7 cross section data. + cross section data. + + Parameters + ---------- + kinetic : bool + Flag to generate kinetic simulation model or not. + + Returns + ------- + model : openmc.Model + A PWR pin cell model + + """ + model = openmc.Model() + + ########################################################################### + # Create Materials for the problem + materials = _generate_c5g7_materials(kinetic) + uo2 = materials[0] + water = materials[1] + + ########################################################################### + # Define problem geometry + pincell = _generate_random_ray_pin_cell(uo2, water) + + ######################################## + # Define cell containing lattice and other stuff + box = openmc.model.RectangularPrism( + PINCELL_PITCH, PINCELL_PITCH, boundary_type='reflective') + + pincell = openmc.Cell(fill=pincell, region=-box, name='pincell') + + # Create a geometry with the top-level cell + geometry = openmc.Geometry([pincell]) + + ########################################################################### + # Define problem settings + + # Instantiate a Settings object, set all runtime parameters, and export to XML + settings = openmc.Settings() + settings.energy_mode = "multi-group" + settings.batches = 400 + settings.inactive = 200 + settings.particles = 100 + + # Create an initial uniform spatial source distribution over fissionable zones + lower_left = (-PINCELL_PITCH / 2, -PINCELL_PITCH / 2, -1) + upper_right = (PINCELL_PITCH / 2, PINCELL_PITCH / 2, 1) + uniform_dist = openmc.stats.Box(lower_left, upper_right) + rr_source = openmc.IndependentSource(space=uniform_dist) + + settings.random_ray['distance_active'] = 100.0 + settings.random_ray['distance_inactive'] = 20.0 + settings.random_ray['ray_source'] = rr_source + settings.random_ray['volume_normalized_flux_tallies'] = True + if kinetic: + settings.random_ray['bd_order'] = 3 + settings.kinetic_simulation = True + settings.timestep_parameters = { + "dt": 0.01, + "n_timesteps": 20, + "timestep_units": "s", + } + + ########################################################################### + # Define tallies + # Now use the mesh filter in a tally and indicate what scores are desired + tally = openmc.Tally(name="Pin tally") + tally.scores = ['flux', 'fission', 'nu-fission'] + tally.estimator = 'analog' + + # Instantiate a Tallies collection and export to XML + tallies = openmc.Tallies([tally]) + + if kinetic: + delay_filter = openmc.DelayedGroupFilter(np.arange(1, C5G7_N_DG+1, 1)) + tally = openmc.Tally(name="Delayed tally") + tally.filters = [delay_filter] + tally.scores += ['precursors'] + tallies.append(tally) + + ########################################################################### + # Exporting to OpenMC model + ########################################################################### + + model.geometry = geometry + model.materials = materials + model.settings = settings + model.tallies = tallies + return model + + +def random_ray_lattice(kinetic=False) -> openmc.Model: + """Create a 2x2 PWR pin cell asymmetrical lattice example. + + This model is a 2x2 reflective lattice of fuel pins with one of the lattice + locations having just moderator instead of a fuel pin. It uses C5G7 + cross section data. + + Parameters + ---------- + kinetic : bool + Flag to generate a kinetic simulation model or not. + + Returns + ------- + model : openmc.Model + A PWR 2x2 lattice model + + """ + model = openmc.Model() + + ########################################################################### + # Create Materials for the problem + materials = _generate_c5g7_materials(kinetic) + uo2 = materials[0] + water = materials[1] + + ########################################################################### + # Define problem geometry + pincell = _generate_random_ray_pin_cell(uo2, water) + ######################################## # Define a moderator lattice universe - moderator_infinite = openmc.Cell(fill=water, name='moderator infinite') + moderator_infinite = openmc.Cell(name='moderator infinite') + if kinetic: + water_reflector = water.clone() + water_reflector.name = 'Water Reflector' + water_reflector.set_density('macro', 1.0) + materials.append(water_reflector) + moderator_infinite.fill = water_reflector + else: + moderator_infinite.fill = water + mu = openmc.Universe() mu.add_cells([moderator_infinite]) lattice = openmc.RectLattice() - lattice.lower_left = [-pitch/2.0, -pitch/2.0] - lattice.pitch = [pitch/10.0, pitch/10.0] + lattice.lower_left = [-PINCELL_PITCH/2.0, -PINCELL_PITCH/2.0] + lattice.pitch = [PINCELL_PITCH/10.0, PINCELL_PITCH/10.0] lattice.universes = np.full((10, 10), mu) mod_lattice_cell = openmc.Cell(fill=lattice) @@ -828,8 +1063,8 @@ def random_ray_lattice() -> openmc.Model: ######################################## # Define 2x2 outer lattice lattice2x2 = openmc.RectLattice() - lattice2x2.lower_left = (-pitch, -pitch) - lattice2x2.pitch = (pitch, pitch) + lattice2x2.lower_left = (-PINCELL_PITCH, -PINCELL_PITCH) + lattice2x2.pitch = (PINCELL_PITCH, PINCELL_PITCH) lattice2x2.universes = [ [pincell, pincell], [pincell, mod_lattice_uni] @@ -838,7 +1073,7 @@ def random_ray_lattice() -> openmc.Model: ######################################## # Define cell containing lattice and other stuff box = openmc.model.RectangularPrism( - pitch*2, pitch*2, boundary_type='reflective') + PINCELL_PITCH*2, PINCELL_PITCH*2, boundary_type='reflective') assembly = openmc.Cell(fill=lattice2x2, region=-box, name='assembly') @@ -856,8 +1091,8 @@ def random_ray_lattice() -> openmc.Model: settings.particles = 100 # Create an initial uniform spatial source distribution over fissionable zones - lower_left = (-pitch, -pitch, -1) - upper_right = (pitch, pitch, 1) + lower_left = (-PINCELL_PITCH, -PINCELL_PITCH, -1) + upper_right = (PINCELL_PITCH, PINCELL_PITCH, 1) uniform_dist = openmc.stats.Box(lower_left, upper_right) rr_source = openmc.IndependentSource(space=uniform_dist) @@ -865,6 +1100,14 @@ def random_ray_lattice() -> openmc.Model: settings.random_ray['distance_inactive'] = 20.0 settings.random_ray['ray_source'] = rr_source settings.random_ray['volume_normalized_flux_tallies'] = True + if kinetic: + settings.random_ray['bd_order'] = 3 + settings.kinetic_simulation = True + settings.timestep_parameters = { + "dt": 0.01, + "n_timesteps": 2, + "timestep_units": "s", + } ########################################################################### # Define tallies @@ -872,8 +1115,8 @@ def random_ray_lattice() -> openmc.Model: # Create a mesh that will be used for tallying mesh = openmc.RegularMesh() mesh.dimension = (2, 2) - mesh.lower_left = (-pitch, -pitch) - mesh.upper_right = (pitch, pitch) + mesh.lower_left = (-PINCELL_PITCH, -PINCELL_PITCH) + mesh.upper_right = (PINCELL_PITCH, PINCELL_PITCH) # Create a mesh filter that can be used in a tally mesh_filter = openmc.MeshFilter(mesh) @@ -891,6 +1134,13 @@ def random_ray_lattice() -> openmc.Model: # Instantiate a Tallies collection and export to XML tallies = openmc.Tallies([tally]) + if kinetic: + delay_filter = openmc.DelayedGroupFilter(np.arange(1, C5G7_N_DG+1, 1)) + tally = openmc.Tally(name="Mesh delayed tally") + tally.filters = [mesh_filter, delay_filter] + tally.scores += ['precursors'] + tallies.append(tally) + ########################################################################### # Exporting to OpenMC model ########################################################################### diff --git a/openmc/material.py b/openmc/material.py index 735a0574326..f4343a50739 100644 --- a/openmc/material.py +++ b/openmc/material.py @@ -89,6 +89,12 @@ class Material(IDManagerMixin): Temperature of the material in Kelvin. density : float Density of the material (units defined separately) + density_timeseries : list of float + Density timeseries of the material for time-dependent simulations. Units + assumed to be the same as `density_units`. Must be have size equal to + :attr:`openmc.Settings.time_dependent['n_timesteps']`. + + .. versionadded:: 0.16.0 density_units : str Units used for `density`. Can be one of 'g/cm3', 'g/cc', 'kg/m3', 'atom/b-cm', 'atom/cm3', 'sum', or 'macro'. The 'macro' unit only @@ -137,6 +143,7 @@ def __init__( name: str = "", temperature: float | None = None, density: float | None = None, + density_timeseries: list[float] | None = None, density_units: str = "sum", depletable: bool | None = False, volume: float | None = None, @@ -148,6 +155,7 @@ def __init__( self.name = name self.temperature = temperature self._density = None + self._density_timeseries = None self._density_units = density_units self._depletable = depletable self._paths = None @@ -175,7 +183,6 @@ def __init__( if components is not None: self.add_components(components, percent_type=percent_type) - def __repr__(self) -> str: string = 'Material\n' string += '{: <16}=\t{}\n'.format('\tID', self._id) @@ -185,13 +192,19 @@ def __repr__(self) -> str: string += '{: <16}=\t{}'.format('\tDensity', self._density) string += f' [{self._density_units}]\n' + if self._density_timeseries is not None: + string += '{: <16}\n'.format('\tDensity Timeseries') + dens_ts_string = " ".join(str(x) for x in self._density_timeseries) + string += '{: <16}\n'.format(dens_ts_string) + string += '{: <16}=\t{} [cm^3]\n'.format('\tVolume', self._volume) string += '{: <16}=\t{}\n'.format('\tDepletable', self._depletable) string += '{: <16}\n'.format('\tS(a,b) Tables') if self._ncrystal_cfg: - string += '{: <16}=\t{}\n'.format('\tNCrystal conf', self._ncrystal_cfg) + string += '{: <16}=\t{}\n'.format('\tNCrystal conf', + self._ncrystal_cfg) for sab in self._sab: string += '{: <16}=\t{}\n'.format('\tS(a,b)', sab) @@ -235,6 +248,10 @@ def temperature(self, temperature: Real | None): def density(self) -> float | None: return self._density + @property + def density_timeseries(self) -> list[str] | None: + return self._density_timeseries + @property def density_units(self) -> str: return self._density_units @@ -318,7 +335,7 @@ def fissionable_mass(self) -> float: Z = openmc.data.zam(nuc)[0] if Z >= 90: density += 1e24 * atoms_per_bcm * openmc.data.atomic_mass(nuc) \ - / openmc.data.AVOGADRO + / openmc.data.AVOGADRO return density*self.volume @property @@ -367,7 +384,8 @@ def get_decay_photon_energy( cv.check_value('units', units, {'Bq', 'Bq/g', 'Bq/kg', 'Bq/cm3'}) if exclude_nuclides is not None and include_nuclides is not None: - raise ValueError("Cannot specify both exclude_nuclides and include_nuclides") + raise ValueError( + "Cannot specify both exclude_nuclides and include_nuclides") if units == 'Bq': multiplier = volume if volume is not None else self.volume @@ -447,6 +465,7 @@ def from_hdf5(cls, group: h5py.Group) -> Material: material.add_s_alpha_beta(name) # Set the Material's density to atom/b-cm as used by OpenMC + # TODO: Add support for density_timeseries material.set_density(density=density, units='atom/b-cm') if 'nuclides' in group: @@ -497,12 +516,12 @@ def from_ncrystal(cls, cfg, **kwargs) -> Material: nc_mat = NCrystal.createInfo(cfg) def openmc_natabund(Z): - #nc_mat.getFlattenedComposition might need natural abundancies. - #This call-back function is used so NCrystal can flatten composition - #using OpenMC's natural abundancies. In practice this function will - #only get invoked in the unlikely case where a material is specified - #by referring both to natural elements and specific isotopes of the - #same element. + # nc_mat.getFlattenedComposition might need natural abundancies. + # This call-back function is used so NCrystal can flatten composition + # using OpenMC's natural abundancies. In practice this function will + # only get invoked in the unlikely case where a material is specified + # by referring both to natural elements and specific isotopes of the + # same element. elem_name = openmc.data.ATOMIC_SYMBOL[Z] return [ (int(iso_name[len(elem_name):]), abund) @@ -523,6 +542,7 @@ def openmc_natabund(Z): else: material.add_element(elemname, frac) + # TODO: add support for density_timeseries material.set_density('g/cm3', nc_mat.getDensity()) material._ncrystal_cfg = NCrystal.normaliseCfg(cfg) @@ -545,9 +565,11 @@ def add_volume_information(self, volume_calc): raise ValueError('No volume information found for material ID={}.' .format(self.id)) else: - raise ValueError(f'No volume information found for material ID={self.id}.') + raise ValueError( + f'No volume information found for material ID={self.id}.') - def set_density(self, units: str, density: float | None = None): + def set_density(self, units: str, density: float | None = None, + density_timeseries: list[float] | None = None): """Set the density of the material Parameters @@ -557,7 +579,11 @@ def set_density(self, units: str, density: float | None = None): density : float, optional Value of the density. Must be specified unless units is given as 'sum'. + density_timeseries : list of float, optional + Timeseries of density. Can only be specified if units are not given + as 'sum'. + .. versionadded:: 0.16.0 """ cv.check_value('density units', units, DENSITY_UNITS) @@ -568,6 +594,10 @@ def set_density(self, units: str, density: float | None = None): msg = 'Density "{}" for Material ID="{}" is ignored ' \ 'because the unit is "sum"'.format(density, self.id) warnings.warn(msg) + if density_timeseries is not None: + msg = 'Density timeseries cannot be used when ' \ + 'using "sum" density units.' + raise ValueError(msg) else: if density is None: msg = 'Unable to set the density for Material ID="{}" ' \ @@ -578,6 +608,14 @@ def set_density(self, units: str, density: float | None = None): cv.check_type(f'the density for Material ID="{self.id}"', density, Real) self._density = density + if density_timeseries is not None: + cv.check_type(f'the density timeseries for Material ID="{self.id}"', + density_timeseries, Iterable, Real) + [cv.check_greater_than(f'an element in density timeseries for Material ID="{self.id}"', + x, 0.0) for x in density_timeseries] + self._density_timeseries = density_timeseries + else: + self._density_timeseries = None def add_nuclide(self, nuclide: str, percent: float, percent_type: str = 'ao'): """Add a nuclide to the material @@ -599,7 +637,8 @@ def add_nuclide(self, nuclide: str, percent: float, percent_type: str = 'ao'): if self._macroscopic is not None: msg = 'Unable to add a Nuclide to Material ID="{}" as a ' \ - 'macroscopic data-set has already been added'.format(self._id) + 'macroscopic data-set has already been added'.format( + self._id) raise ValueError(msg) if self._ncrystal_cfg is not None: @@ -836,7 +875,8 @@ def add_element(self, element: str, percent: float, percent_type: str = 'ao', if self._macroscopic is not None: msg = 'Unable to add an Element to Material ID="{}" as a ' \ - 'macroscopic data-set has already been added'.format(self._id) + 'macroscopic data-set has already been added'.format( + self._id) raise ValueError(msg) if enrichment is not None and enrichment_target is None: @@ -925,10 +965,10 @@ def add_elements_from_formula(self, formula: str, percent_type: str = 'ao', msg = f'Formula entry {token} not an element symbol.' raise ValueError(msg) elif token not in ['(', ')', ''] and not token.isdigit(): - msg = 'Formula must be made from a sequence of ' \ - 'element symbols, integers, and brackets. ' \ - '{} is not an allowable entry.'.format(token) - raise ValueError(msg) + msg = 'Formula must be made from a sequence of ' \ + 'element symbols, integers, and brackets. ' \ + '{} is not an allowable entry.'.format(token) + raise ValueError(msg) # Checks that the number of opening and closing brackets are equal if formula.count('(') != formula.count(')'): @@ -990,12 +1030,13 @@ def add_s_alpha_beta(self, name: str, fraction: float = 1.0): if self._macroscopic is not None: msg = 'Unable to add an S(a,b) table to Material ID="{}" as a ' \ - 'macroscopic data-set has already been added'.format(self._id) + 'macroscopic data-set has already been added'.format( + self._id) raise ValueError(msg) if not isinstance(name, str): msg = 'Unable to add an S(a,b) table to Material ID="{}" with a ' \ - 'non-string table name "{}"'.format(self._id, name) + 'non-string table name "{}"'.format(self._id, name) raise ValueError(msg) cv.check_type('S(a,b) fraction', fraction, Real) @@ -1132,7 +1173,7 @@ def get_nuclide_atom_densities(self, nuclide: str | None = None) -> dict[str, fl if not percent_in_atom: for n, nuc in enumerate(nucs): nuc_densities[n] *= self.average_molar_mass / \ - openmc.data.atomic_mass(nuc) + openmc.data.atomic_mass(nuc) # Now that we have the atomic amounts, lets finish calculating densities sum_percent = np.sum(nuc_densities) @@ -1141,7 +1182,7 @@ def get_nuclide_atom_densities(self, nuclide: str | None = None) -> dict[str, fl # Convert the mass density to an atom density if not density_in_atom: density = -density / self.average_molar_mass * 1.e-24 \ - * openmc.data.AVOGADRO + * openmc.data.AVOGADRO nuc_densities = density * nuc_densities @@ -1181,7 +1222,8 @@ def get_element_atom_densities(self, element: str | None = None) -> dict[str, fl # Accumulate densities for each nuclide for nuclide, density in nuc_densities.items(): - nuc_element = openmc.data.ATOMIC_SYMBOL[openmc.data.zam(nuclide)[0]] + nuc_element = openmc.data.ATOMIC_SYMBOL[openmc.data.zam(nuclide)[ + 0]] if element is None or element == nuc_element: if nuc_element not in densities: densities[nuc_element] = 0.0 @@ -1189,11 +1231,10 @@ def get_element_atom_densities(self, element: str | None = None) -> dict[str, fl # If specific element was requested, make sure it is present if element is not None and element not in densities: - raise ValueError(f'Element {element} not found in material.') + raise ValueError(f'Element {element} not found in material.') return densities - def get_activity(self, units: str = 'Bq/cm3', by_nuclide: bool = False, volume: float | None = None) -> dict[str, float] | float: """Returns the activity of the material or of each nuclide within. @@ -1223,7 +1264,8 @@ def get_activity(self, units: str = 'Bq/cm3', by_nuclide: bool = False, of the material is returned as a float. """ - cv.check_value('units', units, {'Bq', 'Bq/g', 'Bq/kg', 'Bq/cm3', 'Ci', 'Ci/m3'}) + cv.check_value('units', units, { + 'Bq', 'Bq/g', 'Bq/kg', 'Bq/cm3', 'Ci', 'Ci/m3'}) cv.check_type('by_nuclide', by_nuclide, bool) if volume is None: @@ -1296,7 +1338,8 @@ def get_decay_heat(self, units: str = 'W', by_nuclide: bool = False, decay_erg = openmc.data.decay_energy(nuclide) inv_seconds = openmc.data.decay_constant(nuclide) decay_erg *= openmc.data.JOULE_PER_EV - decayheat[nuclide] = inv_seconds * decay_erg * 1e24 * atoms_per_bcm * multiplier + decayheat[nuclide] = inv_seconds * decay_erg * \ + 1e24 * atoms_per_bcm * multiplier return decayheat if by_nuclide else sum(decayheat.values()) @@ -1347,7 +1390,7 @@ def get_mass_density(self, nuclide: str | None = None) -> float: mass_density = 0.0 for nuc, atoms_per_bcm in self.get_nuclide_atom_densities(nuclide=nuclide).items(): density_i = 1e24 * atoms_per_bcm * openmc.data.atomic_mass(nuc) \ - / openmc.data.AVOGADRO + / openmc.data.AVOGADRO mass_density += density_i return mass_density @@ -1530,12 +1573,13 @@ def _get_macroscopic_xml(self, macroscopic: str) -> ET.Element: def _get_nuclides_xml( self, nuclides: Iterable[NuclideTuple], - nuclides_to_ignore: Iterable[str] | None = None)-> list[ET.Element]: + nuclides_to_ignore: Iterable[str] | None = None) -> list[ET.Element]: xml_elements = [] # Remove any nuclides to ignore from the XML export if nuclides_to_ignore: - nuclides = [nuclide for nuclide in nuclides if nuclide.name not in nuclides_to_ignore] + nuclides = [ + nuclide for nuclide in nuclides if nuclide.name not in nuclides_to_ignore] xml_elements = [self._get_nuclide_xml(nuclide) for nuclide in nuclides] @@ -1572,9 +1616,11 @@ def to_xml_element( if self._ncrystal_cfg: if self._sab: - raise ValueError("NCrystal materials are not compatible with S(a,b).") + raise ValueError( + "NCrystal materials are not compatible with S(a,b).") if self._macroscopic is not None: - raise ValueError("NCrystal materials are not compatible with macroscopic cross sections.") + raise ValueError( + "NCrystal materials are not compatible with macroscopic cross sections.") element.set("cfg", str(self._ncrystal_cfg)) @@ -1588,8 +1634,14 @@ def to_xml_element( if self._density_units != 'sum': subelement.set("value", str(self._density)) subelement.set("units", self._density_units) + if self._density_timeseries is not None: + timeseries_text = " ".join(str(x) + for x in self._density_timeseries) + subelement.set("value_timeseries", timeseries_text) + else: - raise ValueError(f'Density has not been set for material {self.id}!') + raise ValueError( + f'Density has not been set for material {self.id}!') if self._macroscopic is None: # Create nuclide XML subelements @@ -1615,6 +1667,7 @@ def to_xml_element( return element + # TODO: add support for density_timeseries @classmethod def mix_materials(cls, materials, fracs: Iterable[float], percent_type: str = 'ao', **kwargs) -> Material: @@ -1689,17 +1742,18 @@ def mix_materials(cls, materials, fracs: Iterable[float], nuc_per_cc = wgt*1.e24*atoms_per_bcm nuclides_per_cc[nuc] += nuc_per_cc mass_per_cc[nuc] += nuc_per_cc*openmc.data.atomic_mass(nuc) / \ - openmc.data.AVOGADRO + openmc.data.AVOGADRO # Create the new material with the desired name if "name" not in kwargs: kwargs["name"] = '-'.join([f'{m.name}({f})' for m, f in - zip(materials, fracs)]) + zip(materials, fracs)]) new_mat = cls(**kwargs) # Compute atom fractions of nuclides and add them to the new material - tot_nuclides_per_cc = np.sum([dens for dens in nuclides_per_cc.values()]) + tot_nuclides_per_cc = np.sum( + [dens for dens in nuclides_per_cc.values()]) for nuc, atom_dens in nuclides_per_cc.items(): new_mat.add_nuclide(nuc, atom_dens/tot_nuclides_per_cc, 'ao') @@ -1771,7 +1825,12 @@ def from_xml_element(cls, elem: ET.Element) -> Material: mat.set_density(units) else: value = float(get_text(density, 'value')) - mat.set_density(units, value) + text = get_text(density, 'value_timeseries') + if text is not None: + density_timeseries = [float(x) for x in text.split()] + else: + density_timeseries = None + mat.set_density(units, value, density_timeseries) # Check for isotropic scattering nuclides isotropic = get_elem_list(elem, "isotropic", str) @@ -1841,7 +1900,6 @@ def deplete( return depleted_materials_dict[self.id] - def mean_free_path(self, energy: float) -> float: """Calculate the mean free path of neutrons in the material at a given energy. @@ -1984,7 +2042,8 @@ def _write_xml(self, file, header=True, level=0, spaces_per_level=2, # Write the elements. for material in sorted(set(self), key=lambda x: x.id): - element = material.to_xml_element(nuclides_to_ignore=nuclides_to_ignore) + element = material.to_xml_element( + nuclides_to_ignore=nuclides_to_ignore) clean_indentation(element, level=level+1) element.tail = element.tail.strip(' ') file.write((level+1)*spaces_per_level*' ') @@ -2070,7 +2129,6 @@ def from_xml(cls, path: PathLike = 'materials.xml') -> Materials: return cls.from_xml_element(root) - def deplete( self, multigroup_fluxes: Sequence[Sequence[float]], diff --git a/openmc/model/model.py b/openmc/model/model.py index 6e4c1c5856d..53e68463f79 100644 --- a/openmc/model/model.py +++ b/openmc/model/model.py @@ -259,7 +259,8 @@ def add_kinetics_parameters_tallies(self, num_groups: int | None = None): beta_tally = openmc.Tally(name='IFP beta numerator') beta_tally.scores = ['ifp-beta-numerator'] if num_groups is not None: - beta_tally.filters = [openmc.DelayedGroupFilter(list(range(1, num_groups + 1)))] + beta_tally.filters = [openmc.DelayedGroupFilter( + list(range(1, num_groups + 1)))] self.tallies.append(beta_tally) if not any('ifp-denominator' in t.scores for t in self.tallies): denom_tally = openmc.Tally(name='IFP denominator') @@ -523,7 +524,8 @@ def deplete( check_value('method', method, dep.integrators.integrator_by_name.keys()) integrator_class = dep.integrators.integrator_by_name[method] - integrator = integrator_class(depletion_operator, **integrator_kwargs) + integrator = integrator_class( + depletion_operator, **integrator_kwargs) # Now perform the depletion with openmc.lib.quiet_dll(output): @@ -583,7 +585,8 @@ def export_to_xml(self, directory: PathLike = '.', remove_surfs: bool = False, # for all materials in the geometry and use that to automatically build # a collection. if self.materials: - self.materials.export_to_xml(d, nuclides_to_ignore=nuclides_to_ignore) + self.materials.export_to_xml( + d, nuclides_to_ignore=nuclides_to_ignore) else: materials = openmc.Materials(self.geometry.get_all_materials() .values()) @@ -622,7 +625,8 @@ def export_to_model_xml(self, path: PathLike = 'model.xml', remove_surfs: bool = if not xml_path.exists(): xml_path.mkdir(parents=True, exist_ok=True) elif not xml_path.is_dir(): - raise FileExistsError(f"File exists and is not a directory: '{xml_path}'") + raise FileExistsError( + f"File exists and is not a directory: '{xml_path}'") xml_path /= 'model.xml' # if this is an XML file location and the file's parent directory does # not exist, create it before continuing @@ -723,18 +727,18 @@ def import_properties(self, filename: PathLike): lib_cell.set_temperature(temperature[0]) if group['density']: - density = group['density'][()] - if density.size > 1: - cell.density = [rho for rho in density] - else: - cell.density = density - if self.is_initialized: - lib_cell = openmc.lib.cells[cell_id] - if density.size > 1: - for i, rho in enumerate(density): - lib_cell.set_density(rho, i) - else: - lib_cell.set_density(density[0]) + density = group['density'][()] + if density.size > 1: + cell.density = [rho for rho in density] + else: + cell.density = density + if self.is_initialized: + lib_cell = openmc.lib.cells[cell_id] + if density.size > 1: + for i, rho in enumerate(density): + lib_cell.set_density(rho, i) + else: + lib_cell.set_density(density[0]) # Make sure number of materials matches mats_group = fh['materials'] @@ -996,7 +1000,6 @@ def calculate_volumes( openmc.lib.materials[domain_id].volume = \ vol_calc.volumes[domain_id].n - def _set_plot_defaults( self, origin: Sequence[float] | None, @@ -1179,8 +1182,8 @@ def plot( # Convert ID map to RGB image img = id_map_to_rgb( - id_map=id_map, - color_by=color_by, + id_map=id_map, + color_by=color_by, colors=colors, overlap_color=overlap_color ) @@ -1217,7 +1220,7 @@ def plot( extent=(x_min, x_max, y_min, y_max), **contour_kwargs ) - + # If only showing outline, set the axis limits and aspect explicitly if outline == 'only': axes.set_xlim(x_min, x_max) @@ -1620,7 +1623,8 @@ def differentiate_mats(self, diff_volume_method: str = None, depletable_only: bo Default is True, only depletable materials will be differentiated. If False, all materials will be differentiated. """ - check_value('volume differentiation method', diff_volume_method, ("divide equally", "match cell", None)) + check_value('volume differentiation method', + diff_volume_method, ("divide equally", "match cell", None)) # Count the number of instances for each cell and material self.geometry.determine_paths(instances_only=True) @@ -1668,7 +1672,8 @@ def differentiate_mats(self, diff_volume_method: str = None, depletable_only: bo # Clone materials if cell.num_instances > 1: - cell.fill = [mat.clone() for _ in range(cell.num_instances)] + cell.fill = [mat.clone() + for _ in range(cell.num_instances)] else: cell.fill = mat.clone() @@ -1685,9 +1690,100 @@ def differentiate_mats(self, diff_volume_method: str = None, depletable_only: bo self.geometry.get_all_materials().values() ) + def _auto_generate_mgxs_lib( + self, + model: openmc.model.model, + energy_groups: openmc.mgxs.EnergyGroups, + correction: str | none, + directory: pathlike, + kinetic: bool | None = None, + num_delayed_groups: int = 0, + ) -> openmc.mgxs.Library: + """ + Automatically generate a multi-group cross section libray from a model + with the specified group structure. + + Parameters + ---------- + energy_groups : openmc.mgxs.EnergyGroups + Energy group structure for the MGXS. + nparticles : int + Number of particles to simulate per batch when generating MGXS. + mgxs_path : str + Filename for the MGXS HDF5 file. + correction : str + Transport correction to apply to the MGXS. Options are None and + "P0". + directory : str + Directory to run the simulation in, so as to contain XML files. + kinetic : bool, optional + Flag to indicate if kinetic simulation cross sections are needed. + num_delayed_groups : int, optional + Number of delayed groups for kinetic simulations. + + Returns + ------- + mgxs_lib : openmc.mgxs.Library + OpenMC MGXS Library object + """ + + # Initialize MGXS library with a finished OpenMC geometry object + mgxs_lib = openmc.mgxs.Library(model.geometry) + + # Pick energy group structure + mgxs_lib.energy_groups = energy_groups + + if (kinetic): + mgxs_lib.num_delayed_groups = num_delayed_groups + + # Disable transport correction + mgxs_lib.correction = correction + + # Specify needed cross sections for random ray + if correction == 'P0': + mgxs_lib.mgxs_types = [ + 'nu-transport', 'absorption', 'nu-fission', 'fission', + 'consistent nu-scatter matrix', 'multiplicity matrix', 'chi' + ] + elif correction is None: + mgxs_lib.mgxs_types = [ + 'total', 'absorption', 'nu-fission', 'fission', + 'consistent nu-scatter matrix', 'multiplicity matrix', 'chi' + ] + if kinetic: + mgxs_lib.mgxs_types += ['chi-prompt', 'chi-delayed', + 'decay-rate', 'inverse-velocity', 'beta'] + + # Specify a "cell" domain type for the cross section tally filters + mgxs_lib.domain_type = "material" + + # Specify the cell domains over which to compute multi-group cross sections + mgxs_lib.domains = model.geometry.get_all_materials().values() + + # Do not compute cross sections on a nuclide-by-nuclide basis + mgxs_lib.by_nuclide = False + + # Check the library - if no errors are raised, then the library is satisfactory. + mgxs_lib.check_library_for_openmc_mgxs() + + # Construct all tallies needed for the multi-group cross section library + mgxs_lib.build_library() + + # Create a "tallies.xml" file for the MGXS Library + mgxs_lib.add_to_tallies(model.tallies, merge=True) + + # Run + statepoint_filename = model.run(cwd=directory) + + # Load MGXS + with openmc.StatePoint(statepoint_filename) as sp: + mgxs_lib.load_from_statepoint(sp) + + return mgxs_lib + def _create_mgxs_sources( self, - groups: openmc.mgxs.EnergyGroups, + energy_groups: openmc.mgxs.EnergyGroups, spatial_dist: openmc.stats.Spatial, source_energy: openmc.stats.Univariate | None = None, ) -> list[openmc.IndependentSource]: @@ -1709,7 +1805,7 @@ def _create_mgxs_sources( Parameters ---------- - groups : openmc.mgxs.EnergyGroups + energy_groups : openmc.mgxs.EnergyGroups Energy group structure for the MGXS. spatial_dist : openmc.stats.Spatial Spatial distribution to use for all sources. @@ -1725,13 +1821,14 @@ def _create_mgxs_sources( # Make a discrete source that is uniform over the bins of the group structure midpoints = [] strengths = [] - for i in range(groups.num_groups): - bounds = groups.get_group_bounds(i+1) + for i in range(energy_groups.num_groups): + bounds = energy_groups.get_group_bounds(i+1) midpoints.append((bounds[0] + bounds[1]) / 2.0) strengths.append(1.0) uniform_energy = openmc.stats.Discrete(x=midpoints, p=strengths) - uniform_distribution = openmc.IndependentSource(spatial_dist, energy=uniform_energy, strength=0.01) + uniform_distribution = openmc.IndependentSource( + spatial_dist, energy=uniform_energy, strength=0.01) sources = [uniform_distribution] # If the user provided an energy distribution, use that @@ -1772,12 +1869,14 @@ def _create_mgxs_sources( def _generate_infinite_medium_mgxs( self, - groups: openmc.mgxs.EnergyGroups, + energy_groups: openmc.mgxs.EnergyGroups, nparticles: int, mgxs_path: PathLike, correction: str | None, directory: PathLike, source_energy: openmc.stats.Univariate | None = None, + kinetic: bool | None = None, + num_delayed_groups: int = 0, ): """Generate a MGXS library by running multiple OpenMC simulations, each representing an infinite medium simulation of a single isolated @@ -1802,7 +1901,7 @@ def _generate_infinite_medium_mgxs( Parameters ---------- - groups : openmc.mgxs.EnergyGroups + energy_groups : openmc.mgxs.EnergyGroups Energy group structure for the MGXS. nparticles : int Number of particles to simulate per batch when generating MGXS. @@ -1816,6 +1915,11 @@ def _generate_infinite_medium_mgxs( source_energy : openmc.stats.Univariate, optional Energy distribution to use when generating MGXS data, replacing any existing sources in the model. + kinetic : bool, optional + Flag to indicate if kinetic simulation cross sections are needed. + num_delayed_groups : int, optional + Number of delayed groups for kinetic simulations. + """ mgxs_sets = [] for material in self.materials: @@ -1829,7 +1933,7 @@ def _generate_infinite_medium_mgxs( model.settings.particles = nparticles model.settings.source = self._create_mgxs_sources( - groups, + energy_groups, spatial_dist=openmc.stats.Point(), source_energy=source_energy ) @@ -1844,63 +1948,21 @@ def _generate_infinite_medium_mgxs( 100000.0, 100000.0, boundary_type='reflective') name = material.name infinite_cell = openmc.Cell(name=name, fill=material, region=-box) - infinite_universe = openmc.Universe(name=name, cells=[infinite_cell]) + infinite_universe = openmc.Universe( + name=name, cells=[infinite_cell]) model.geometry.root_universe = infinite_universe # Add MGXS Tallies - - # Initialize MGXS library with a finished OpenMC geometry object - mgxs_lib = openmc.mgxs.Library(model.geometry) - - # Pick energy group structure - mgxs_lib.energy_groups = groups - - # Disable transport correction - mgxs_lib.correction = correction - - # Specify needed cross sections for random ray - if correction == 'P0': - mgxs_lib.mgxs_types = [ - 'nu-transport', 'absorption', 'nu-fission', 'fission', - 'consistent nu-scatter matrix', 'multiplicity matrix', 'chi' - ] - elif correction is None: - mgxs_lib.mgxs_types = [ - 'total', 'absorption', 'nu-fission', 'fission', - 'consistent nu-scatter matrix', 'multiplicity matrix', 'chi' - ] - - # Specify a "cell" domain type for the cross section tally filters - mgxs_lib.domain_type = "material" - - # Specify the cell domains over which to compute multi-group cross sections - mgxs_lib.domains = model.geometry.get_all_materials().values() - - # Do not compute cross sections on a nuclide-by-nuclide basis - mgxs_lib.by_nuclide = False - - # Check the library - if no errors are raised, then the library is satisfactory. - mgxs_lib.check_library_for_openmc_mgxs() - - # Construct all tallies needed for the multi-group cross section library - mgxs_lib.build_library() - - # Create a "tallies.xml" file for the MGXS Library - mgxs_lib.add_to_tallies(model.tallies, merge=True) - - # Run - statepoint_filename = model.run(cwd=directory) - - # Load MGXS - with openmc.StatePoint(statepoint_filename) as sp: - mgxs_lib.load_from_statepoint(sp) + mgxs_lib = self._auto_generate_mgxs_lib( + model, energy_groups, correction, directory, kinetic, num_delayed_groups) # Create a MGXS File which can then be written to disk mgxs_set = mgxs_lib.get_xsdata(domain=material, xsdata_name=name) mgxs_sets.append(mgxs_set) # Write the file to disk - mgxs_file = openmc.MGXSLibrary(energy_groups=groups) + mgxs_file = openmc.MGXSLibrary( + energy_groups=energy_groups, num_delayed_groups=num_delayed_groups) for mgxs_set in mgxs_sets: mgxs_file.add_xsdata(mgxs_set) mgxs_file.export_to_hdf5(mgxs_path) @@ -1981,12 +2043,14 @@ def _create_stochastic_slab_geometry( def _generate_stochastic_slab_mgxs( self, - groups: openmc.mgxs.EnergyGroups, + energy_groups: openmc.mgxs.EnergyGroups, nparticles: int, mgxs_path: PathLike, correction: str | None, directory: PathLike, source_energy: openmc.stats.Univariate | None = None, + kinetic: bool | None = None, + num_delayed_groups: int = 0, ) -> None: """Generate MGXS assuming a stochastic "sandwich" of materials in a layered slab geometry. While geometry-specific spatial shielding effects are not @@ -2000,7 +2064,7 @@ def _generate_stochastic_slab_mgxs( Parameters ---------- - groups : openmc.mgxs.EnergyGroups + energy_groups : openmc.mgxs.EnergyGroups Energy group structure for the MGXS. nparticles : int Number of particles to simulate per batch when generating MGXS. @@ -2028,6 +2092,11 @@ def _generate_stochastic_slab_mgxs( no sources are defined on the model and the run mode is 'eigenvalue', then a default Watt spectrum source (strength = 0.99) is added. + kinetic : bool, optional + Flag to indicate if kinetic simulation cross sections are needed. + num_delayed_groups : int, optional + Number of delayed groups for kinetic simulations. + """ model = openmc.Model() model.materials = self.materials @@ -2044,7 +2113,7 @@ def _generate_stochastic_slab_mgxs( # Define the sources model.settings.source = self._create_mgxs_sources( - groups, + energy_groups, spatial_dist=spatial_distribution, source_energy=source_energy ) @@ -2055,62 +2124,25 @@ def _generate_stochastic_slab_mgxs( model.settings.output = {'summary': True, 'tallies': False} # Add MGXS Tallies - - # Initialize MGXS library with a finished OpenMC geometry object - mgxs_lib = openmc.mgxs.Library(model.geometry) - - # Pick energy group structure - mgxs_lib.energy_groups = groups - - # Disable transport correction - mgxs_lib.correction = correction - - # Specify needed cross sections for random ray - if correction == 'P0': - mgxs_lib.mgxs_types = ['nu-transport', 'absorption', 'nu-fission', 'fission', - 'consistent nu-scatter matrix', 'multiplicity matrix', 'chi'] - elif correction is None: - mgxs_lib.mgxs_types = ['total', 'absorption', 'nu-fission', 'fission', - 'consistent nu-scatter matrix', 'multiplicity matrix', 'chi'] - - # Specify a "cell" domain type for the cross section tally filters - mgxs_lib.domain_type = "material" - - # Specify the cell domains over which to compute multi-group cross sections - mgxs_lib.domains = model.geometry.get_all_materials().values() - - # Do not compute cross sections on a nuclide-by-nuclide basis - mgxs_lib.by_nuclide = False - - # Check the library - if no errors are raised, then the library is satisfactory. - mgxs_lib.check_library_for_openmc_mgxs() - - # Construct all tallies needed for the multi-group cross section library - mgxs_lib.build_library() - - # Create a "tallies.xml" file for the MGXS Library - mgxs_lib.add_to_tallies(model.tallies, merge=True) - - # Run - statepoint_filename = model.run(cwd=directory) - - # Load MGXS - with openmc.StatePoint(statepoint_filename) as sp: - mgxs_lib.load_from_statepoint(sp) + mgxs_lib = self._auto_generate_mgxs_lib( + model, energy_groups, correction, directory, kinetic, num_delayed_groups) names = [mat.name for mat in mgxs_lib.domains] # Create a MGXS File which can then be written to disk - mgxs_file = mgxs_lib.create_mg_library(xs_type='macro', xsdata_names=names) + mgxs_file = mgxs_lib.create_mg_library( + xs_type='macro', xsdata_names=names) mgxs_file.export_to_hdf5(mgxs_path) def _generate_material_wise_mgxs( self, - groups: openmc.mgxs.EnergyGroups, + energy_groups: openmc.mgxs.EnergyGroups, nparticles: int, mgxs_path: PathLike, correction: str | None, directory: PathLike, + kinetic: bool | None = None, + num_delayed_groups: int = 0, ) -> None: """Generate a material-wise MGXS library for the model by running the original continuous energy OpenMC simulation of the full material @@ -2124,7 +2156,7 @@ def _generate_material_wise_mgxs( Parameters ---------- - groups : openmc.mgxs.EnergyGroups + energy_groups : openmc.mgxs.EnergyGroups Energy group structure for the MGXS. nparticles : int Number of particles to simulate per batch when generating MGXS. @@ -2135,6 +2167,11 @@ def _generate_material_wise_mgxs( "P0". directory : PathLike Directory to run the simulation in, so as to contain XML files. + kinetic : bool, optional + Flag to indicate if kinetic simulation cross sections are needed. + num_delayed_groups : int, optional + Number of delayed groups for kinetic simulations. + """ model = copy.deepcopy(self) model.tallies = openmc.Tallies() @@ -2146,52 +2183,8 @@ def _generate_material_wise_mgxs( model.settings.output = {'summary': True, 'tallies': False} # Add MGXS Tallies - - # Initialize MGXS library with a finished OpenMC geometry object - mgxs_lib = openmc.mgxs.Library(model.geometry) - - # Pick energy group structure - mgxs_lib.energy_groups = groups - - # Disable transport correction - mgxs_lib.correction = correction - - # Specify needed cross sections for random ray - if correction == 'P0': - mgxs_lib.mgxs_types = [ - 'nu-transport', 'absorption', 'nu-fission', 'fission', - 'consistent nu-scatter matrix', 'multiplicity matrix', 'chi' - ] - elif correction is None: - mgxs_lib.mgxs_types = [ - 'total', 'absorption', 'nu-fission', 'fission', - 'consistent nu-scatter matrix', 'multiplicity matrix', 'chi' - ] - - # Specify a "cell" domain type for the cross section tally filters - mgxs_lib.domain_type = "material" - - # Specify the cell domains over which to compute multi-group cross sections - mgxs_lib.domains = model.geometry.get_all_materials().values() - - # Do not compute cross sections on a nuclide-by-nuclide basis - mgxs_lib.by_nuclide = False - - # Check the library - if no errors are raised, then the library is satisfactory. - mgxs_lib.check_library_for_openmc_mgxs() - - # Construct all tallies needed for the multi-group cross section library - mgxs_lib.build_library() - - # Create a "tallies.xml" file for the MGXS Library - mgxs_lib.add_to_tallies(model.tallies, merge=True) - - # Run - statepoint_filename = model.run(cwd=directory) - - # Load MGXS - with openmc.StatePoint(statepoint_filename) as sp: - mgxs_lib.load_from_statepoint(sp) + mgxs_lib = self._auto_generate_mgxs_lib( + model, energy_groups, correction, directory, kinetic, num_delayed_groups) names = [mat.name for mat in mgxs_lib.domains] @@ -2203,12 +2196,14 @@ def _generate_material_wise_mgxs( def convert_to_multigroup( self, method: str = "material_wise", - groups: str = "CASMO-2", + energy_groups: str = "CASMO-2", nparticles: int = 2000, overwrite_mgxs_library: bool = False, mgxs_path: PathLike = "mgxs.h5", correction: str | None = None, source_energy: openmc.stats.Univariate | None = None, + kinetic: bool | None = None, + num_delayed_groups: int = 0, ): """Convert all materials from continuous energy to multigroup. @@ -2219,7 +2214,7 @@ def convert_to_multigroup( ---------- method : {"material_wise", "stochastic_slab", "infinite_medium"}, optional Method to generate the MGXS. - groups : openmc.mgxs.EnergyGroups or str, optional + energy_groups : openmc.mgxs.EnergyGroups or str, optional Energy group structure for the MGXS or the name of the group structure (based on keys from openmc.mgxs.GROUP_STRUCTURES). nparticles : int, optional @@ -2249,9 +2244,13 @@ def convert_to_multigroup( 'eigenvalue', then a default Watt spectrum source (strength = 0.99) is added. Note that this argument is only used when using the "stochastic_slab" or "infinite_medium" MGXS generation methods. + kinetic : bool, optional + Flag to indicate if kinetic simulation cross sections are needed. + num_delayed_groups : int, optional + Number of delayed groups for kinetic simulations. """ - if isinstance(groups, str): - groups = openmc.mgxs.EnergyGroups(groups) + if isinstance(energy_groups, str): + energy_groups = openmc.mgxs.EnergyGroups(energy_groups) # Do all work (including MGXS generation) in a temporary directory # to avoid polluting the working directory with residual XML files @@ -2278,13 +2277,13 @@ def convert_to_multigroup( if not Path(mgxs_path).is_file() or overwrite_mgxs_library: if method == "infinite_medium": self._generate_infinite_medium_mgxs( - groups, nparticles, mgxs_path, correction, tmpdir, source_energy) + energy_groups, nparticles, mgxs_path, correction, tmpdir, source_energy, kinetic, num_delayed_groups) elif method == "material_wise": self._generate_material_wise_mgxs( - groups, nparticles, mgxs_path, correction, tmpdir) + energy_groups, nparticles, mgxs_path, correction, tmpdir, kinetic, num_delayed_groups) elif method == "stochastic_slab": self._generate_stochastic_slab_mgxs( - groups, nparticles, mgxs_path, correction, tmpdir, source_energy) + energy_groups, nparticles, mgxs_path, correction, tmpdir, source_energy, kinetic, num_delayed_groups) else: raise ValueError( f'MGXS generation method "{method}" not recognized') @@ -2301,6 +2300,17 @@ def convert_to_multigroup( self.settings.energy_mode = 'multi-group' + # If making a set the time step size to 0.01 + if kinetic: + self.settings.kinetic_simulation = True + warnings.warn("Kinetic model. Currently, only the random ray solver" + " supports kinetic simulations. The number of time" + " steps to run and material density transient using " + " openmc.Settings.timestep_parameters['n_timesteps'] " + " and openmc.Material.set_density(), respectively.") + self.settings.timestep_parameters = { + 'dt': 0.01, 'timestep_units': 's'} + def convert_to_random_ray(self): """Convert a multigroup model to use random ray. @@ -2617,5 +2627,3 @@ def function_calls(self) -> int: def total_batches(self) -> int: """Total number of active batches used across all evaluations.""" return sum(self.batches) - - diff --git a/openmc/settings.py b/openmc/settings.py index 76e191c5e02..d6d7e6c7922 100644 --- a/openmc/settings.py +++ b/openmc/settings.py @@ -125,6 +125,8 @@ class Settings: type are 'variance', 'std_dev', and 'rel_err'. The threshold value should be a float indicating the variance, standard deviation, or relative error used. + kinetic_simulation : bool + Flag for whether or not to run a kinetic simulation log_grid_bins : int Number of bins for logarithmic energy grid search material_cell_offsets : bool @@ -224,6 +226,15 @@ class Settings: stabilization, which may be desirable as stronger diagonal stabilization also tends to dampen the convergence rate of the solver, thus requiring more iterations to converge. + Additional options are available when running a kinetic simulation: + + :bd_order: + Indicates the integer order of backwards difference approximation used to + numerically compute time derivatives. + :time_derivative_method: + Method for resolving :math:`\\frac{\\partial}{\\partial t} + \\psi_{r,g}(s,t)` in the time-dependent charactersitic equation. + Options are 'isotropic' (default), or 'propagation'. .. versionadded:: 0.15.0 resonance_scattering : dict @@ -308,6 +319,18 @@ class Settings: sections be loaded at all temperatures within the range. 'multipole' is a boolean indicating whether or not the windowed multipole method should be used to evaluate resolved resonance cross sections. + timestep_parameters : dict + Time step parameters for kinetic simulations. Acceptable keys are: + :dt: + Fixed timestep size. + :n_timesteps: + Numeber of timesteps. + :timestep_units: + `ms`,`s`, `min`. Units for timesteps. `ms` means miliseconds, `s` + means seconds, `min` means minutes. + + .. versionadded:: 0.16 + trace : tuple or list Show detailed information about a single particle, indicated by three integers: the batch number, generation number, and particle number @@ -377,6 +400,8 @@ def __init__(self, **kwargs): self._max_write_lost_particles = None self._particles = None self._keff_trigger = None + self._kinetic_simulation = None + self._timestep_parameters = {} # Energy mode subelement self._energy_mode = None @@ -586,6 +611,39 @@ def keff_trigger(self, keff_trigger: dict): self._keff_trigger = keff_trigger + @property + def kinetic_simulation(self) -> bool: + return self._kinetic_simulation + + @kinetic_simulation.setter + def kinetic_simulation(self, value: bool): + cv.check_type('kinetic simulation', value, bool) + self._kinetic_simulation = value + + @property + def timestep_parameters(self) -> dict: + return self._timestep_parameters + + @timestep_parameters.setter + def timestep_parameters(self, timestep_parameters: dict): + if not isinstance(timestep_parameters, Mapping): + raise ValueError(f'Unable to set timestep_parameters from "{timestep_parameters}" ' + 'which is not a dict.') + for key, value in timestep_parameters.items(): + if key == 'dt': + cv.check_type('dt', value, Real) + cv.check_greater_than('dt', value, 0) + elif key == 'n_timesteps': + cv.check_type('n_timesteps', value, Integral) + cv.check_greater_than('n_timesteps', value, 0) + elif key == 'timestep_units': + cv.check_value( + 'timestep units', value, ('ms', 's', 'min')) + else: + raise ValueError(f'Unable to set time dependent to "{key}" which is ' + 'unsupported by OpenMC') + self._timestep_parameters = timestep_parameters + @property def energy_mode(self) -> str: return self._energy_mode @@ -1345,6 +1403,14 @@ def random_ray(self, random_ray: dict): cv.check_type('diagonal stabilization rho', value, Real) cv.check_greater_than('diagonal stabilization rho', value, 0.0, True) + elif self.run_mode == 'time dependent': + if key == 'bd_order': + cv.check_type('BD order', value, Integer) + cv.check_greater_than('BD order', value, 0) + cv.check_less_than('BD order', value, 7) + elif key == 'time_derivative method': + cv.check_value('time derivative method', value, + ('isotropic', 'propagation')) else: raise ValueError(f'Unable to set random ray to "{key}" which is ' 'unsupported by OpenMC') @@ -1382,7 +1448,8 @@ def free_gas_threshold(self) -> float | None: def free_gas_threshold(self, free_gas_threshold: float | None): if free_gas_threshold is not None: cv.check_type('free gas threshold', free_gas_threshold, Real) - cv.check_greater_than('free gas threshold', free_gas_threshold, 0.0) + cv.check_greater_than('free gas threshold', + free_gas_threshold, 0.0) self._free_gas_threshold = free_gas_threshold def _create_run_mode_subelement(self, root): @@ -1431,6 +1498,18 @@ def _create_keff_trigger_subelement(self, root): subelement = ET.SubElement(element, key) subelement.text = str(value).lower() + def _create_kinetic_simulation_subelement(self, root): + if self._kinetic_simulation is not None: + elem = ET.SubElement(root, "kinetic_simulation") + elem.text = str(self._kinetic_simulation).lower() + + def _create_timestep_parameters_subelement(self, root): + if self._timestep_parameters: + element = ET.SubElement(root, "timestep_parameters") + for key, value in self._timestep_parameters.items(): + subelement = ET.SubElement(element, key) + subelement.text = str(value) + def _create_energy_mode_subelement(self, root): if self._energy_mode is not None: element = ET.SubElement(root, "energy_mode") @@ -1889,7 +1968,8 @@ def _create_random_ray_subelement(self, root, mesh_memo=None): domain_elem.set( 'type', domain.__class__.__name__.lower()) if mesh_memo is not None and mesh.id not in mesh_memo: - domain_elem.set('type', domain.__class__.__name__.lower()) + domain_elem.set( + 'type', domain.__class__.__name__.lower()) # See if a element already exists -- if not, add it path = f"./mesh[@id='{mesh.id}']" if root.find(path) is None: @@ -1972,6 +2052,23 @@ def _keff_trigger_from_xml_element(self, root): threshold = float(get_text(elem, 'threshold')) self.keff_trigger = {'type': trigger, 'threshold': threshold} + def _kinetic_simulation_from_xml_element(self, root): + text = get_text(root, 'kinetic_simulation') + if text is not None: + self.kinetic_simulation = text in ('true', '1') + + def _timestep_parameters_from_xml_element(self, root): + elem = root.find('timestep_parameters') + if elem is not None: + self.timestep_parameters = {} + for child in elem: + if child.tag == 'n_timesteps': + self.timestep_parameters[child.tag] = int(child.text) + elif child.tag == 'timestep_units': + self.timestep_parameters['timestep_units'] = child.text + elif child.tag == 'dt': + self.timestep_parameters['dt'] = float(child.text) + def _source_from_xml_element(self, root, meshes=None): for elem in root.findall('source'): src = SourceBase.from_xml_element(elem, meshes) @@ -2360,6 +2457,10 @@ def _random_ray_from_xml_element(self, root, meshes=None): domains.append(domain) self.random_ray['source_region_meshes'].append( (mesh, domains)) + elif child.tag == 'bd_order': + self.random_ray['bd_order'] = int(child.text) + elif child.tag == 'time_derivative_method': + self.random_ray['time_derivative_method'] = child.text def _use_decay_photons_from_xml_element(self, root): text = get_text(root, 'use_decay_photons') @@ -2396,6 +2497,8 @@ def to_xml_element(self, mesh_memo=None): self._create_max_write_lost_particles_subelement(element) self._create_generations_per_batch_subelement(element) self._create_keff_trigger_subelement(element) + self._create_kinetic_simulation_subelement(element) + self._create_timestep_parameters_subelement(element) self._create_source_subelement(element, mesh_memo) self._create_output_subelement(element) self._create_statepoint_subelement(element) @@ -2509,6 +2612,8 @@ def from_xml_element(cls, elem, meshes=None): settings._max_write_lost_particles_from_xml_element(elem) settings._generations_per_batch_from_xml_element(elem) settings._keff_trigger_from_xml_element(elem) + settings._kinetic_simulation_from_xml_element(elem) + settings._timestep_parameters_from_xml_element(elem) settings._source_from_xml_element(elem, meshes) settings._volume_calcs_from_xml_element(elem) settings._output_from_xml_element(elem) diff --git a/openmc/statepoint.py b/openmc/statepoint.py index a10ec3a839d..175388839c1 100644 --- a/openmc/statepoint.py +++ b/openmc/statepoint.py @@ -17,7 +17,8 @@ _VERSION_STATEPOINT = 18 -KineticsParameters = namedtuple("KineticsParameters", ["generation_time", "beta_effective"]) +KineticsParameters = namedtuple( + "KineticsParameters", ["generation_time", "beta_effective"]) class StatePoint: @@ -57,6 +58,10 @@ class StatePoint: Number of batches simulated date_and_time : datetime.datetime Date and time at which statepoint was written + energy_mode : str + 'continuous-energy', 'multi-group' + + .. versionadded:: 0.16.0 entropy : numpy.ndarray Shannon entropy of fission source at each batch filters : dict @@ -85,6 +90,14 @@ class StatePoint: .. versionadded:: 0.13.1 meshes : dict Dictionary whose keys are mesh IDs and whose values are MeshBase objects + n_energy_groups : int + Number of energy groups used in a multi-group simulation. + + .. versionadded:: 0.16.0 + n_delay_groups : int + Number of delay groups used in a multi-group simulation. + + .. versionadded:: 0.16.0 n_batches : int Number of batches n_inactive : int @@ -97,6 +110,14 @@ class StatePoint: Working directory for simulation photon_transport : bool Indicate whether photon transport is active + random_ray : dict + Dictionary whose keys are the following strings used to describing + various random ray metrics. These include simulation settings (e.g. + 'source_shape', 'volume_estimator', 'volume_normalized_flux_tallies', + etc.) and performance metrics (e.g. 'avg_miss_rate', + 'n_source_regions', 'n_integrations', etc.) + + .. versionadded:: 0.16.0 run_mode : str Simulation run mode, e.g. 'eigenvalue' runtime : dict @@ -106,6 +127,10 @@ class StatePoint: Pseudorandom number generator seed stride : int Number of random numbers allocated for each particle history + solver_type : str + 'monte carlo', 'random ray' + + .. versionadded:: 0.16.0 source : numpy.ndarray of compound datatype Array of source sites. The compound datatype has fields 'r', 'u', 'E', 'wgt', 'delayed_group', 'surf_id', and 'particle', corresponding to @@ -152,12 +177,14 @@ def __init__(self, filepath, autolink=True): # Automatically link in a summary file if one exists if autolink: - path_summary = os.path.join(os.path.dirname(filename), 'summary.h5') + path_summary = os.path.join( + os.path.dirname(filename), 'summary.h5') if os.path.exists(path_summary): su = openmc.Summary(path_summary) self.link_with_summary(su) - path_volume = os.path.join(os.path.dirname(filename), 'volume_*.h5') + path_volume = os.path.join( + os.path.dirname(filename), 'volume_*.h5') for path_i in glob.glob(path_volume): if re.search(r'volume_\d+\.h5', path_i): vol = openmc.VolumeCalculation.from_hdf5(path_i) @@ -210,9 +237,13 @@ def date_and_time(self): s = self._f.attrs['date_and_time'].decode() return datetime.strptime(s, '%Y-%m-%d %H:%M:%S') + @property + def energy_mode(self): + return self._f['energy_mode'][()].decode() + @property def entropy(self): - if self.run_mode == 'eigenvalue': + if self.run_mode == 'eigenvalue' or self.run_mode == 'time dependent': return self._f['entropy'][()] else: return None @@ -233,7 +264,7 @@ def filters(self): @property def generations_per_batch(self): - if self.run_mode == 'eigenvalue': + if self.run_mode == 'eigenvalue' or self.run_mode == 'time dependent': return self._f['generations_per_batch'][()] else: return None @@ -247,8 +278,8 @@ def global_tallies(self): ('mean', 'f8'), ('std_dev', 'f8')]) gt['name'] = ['k-collision', 'k-absorption', 'k-tracklength', 'leakage'] - gt['sum'] = data[:,1] - gt['sum_sq'] = data[:,2] + gt['sum'] = data[:, 1] + gt['sum_sq'] = data[:, 2] # Calculate mean and sample standard deviation of mean n = self.n_realizations @@ -275,7 +306,7 @@ def k_generation(self): @property def keff(self): - if self.run_mode == 'eigenvalue': + if self.run_mode == 'eigenvalue' or self.run_mode == 'time dependent': return ufloat(*self._f['k_combined'][()]) else: return None @@ -323,13 +354,27 @@ def meshes(self): return self._meshes + @property + def n_energy_groups(self): + if self.energy_mode == 'multi-group': + return self._f['n_energy_groups'][()] + else: + return None + + @property + def n_delay_groups(self): + if self.energy_mode == 'multi-group': + return self._f['n_delay_groups'][()] + else: + return None + @property def n_batches(self): return self._f['n_batches'][()] @property def n_inactive(self): - if self.run_mode == 'eigenvalue': + if self.run_mode == 'eigenvalue' or self.run_mode == 'time dependent': return self._f['n_inactive'][()] else: return None @@ -350,6 +395,21 @@ def path(self): def photon_transport(self): return self._f.attrs['photon_transport'] > 0 + @property + def random_ray(self): + if self.solver_type == 'random ray': + rr = {} + for name, dataset in self._f['random_ray'].items(): + data = dataset[()] + if type(data) == np.bytes_: + data = data.decode() + if name in ['adjoint', 'volume_normalized_flux_tallies']: + data = data > 0 + rr[name] = data + return rr + else: + return None + @property def run_mode(self): return self._f['run_mode'][()].decode() @@ -367,6 +427,10 @@ def seed(self): def stride(self): return self._f['stride'][()] + @property + def solver_type(self): + return self._f['solver_type'][()].decode() + @property def source(self): return self._f['source_bank'][()] if self.source_present else None @@ -428,15 +492,18 @@ def tallies(self): # Create Tally object and assign basic properties tally = openmc.Tally(tally_id) tally._sp_filename = Path(self._f.filename) - tally.name = group['name'][()].decode() if 'name' in group else '' + tally.name = group['name'][()].decode( + ) if 'name' in group else '' # Check if tally has multiply_density attribute if "multiply_density" in group.attrs: - tally.multiply_density = group.attrs["multiply_density"].item() > 0 + tally.multiply_density = group.attrs["multiply_density"].item( + ) > 0 # Check if tally has higher_moments attribute if 'higher_moments' in group.attrs: - tally.higher_moments = bool(group.attrs['higher_moments'][()]) + tally.higher_moments = bool( + group.attrs['higher_moments'][()]) # Read the number of realizations n_realizations = group['n_realizations'][()] @@ -464,7 +531,8 @@ def tallies(self): nuclide_names = group['nuclides'][()] # Add all nuclides to the Tally - tally.nuclides = [name.decode().strip() for name in nuclide_names] + tally.nuclides = [name.decode().strip() + for name in nuclide_names] # Add the scores to the Tally scores = group['score_bins'][()] @@ -709,7 +777,7 @@ def link_with_summary(self, summary): if not isinstance(summary, openmc.Summary): msg = f'Unable to link statepoint with "{summary}" which is not a' \ - 'Summary object' + 'Summary object' raise ValueError(msg) cells = summary.geometry.get_all_cells() diff --git a/src/material.cpp b/src/material.cpp index 54caa38409a..156b149caa1 100644 --- a/src/material.cpp +++ b/src/material.cpp @@ -77,6 +77,32 @@ Material::Material(pugi::xml_node node) std::string units; if (density_node) { units = get_node_value(density_node, "units"); + if (settings::kinetic_simulation) { + if (check_for_node(density_node, "value_timeseries")) { + if (units == "sum") { + fatal_error("Use of density_timeseries is incompatible with 'sum'" + "density unit"); + } else { + density_timeseries_ = + get_node_array(density_node, "value_timeseries"); + if (density_timeseries_.size() >= settings::n_timesteps) { + warning(fmt::format( + "Material {} has a density_timeseries (size={}) longer than " + "n_timesteps ({}). Only the first {} entries of the density " + "timeseries " + "will be simulated.", + this->id(), density_timeseries_.size(), settings::n_timesteps, + settings::n_timesteps)); + } else { + fatal_error( + fmt::format("Material {} has a density_timeseries (size={}) " + "shorter than n_timesteps ({}). Not all " + "time steps can be simulated. Aborting.", + this->id(), density_timeseries_.size(), settings::n_timesteps)); + } + } + } + } if (units == "sum") { sum_density = true; } else if (units == "macro") { @@ -92,18 +118,51 @@ Material::Material(pugi::xml_node node) std::to_string(id_) + "."); } + double scale_factor; if (units == "g/cc" || units == "g/cm3") { density_ = -val; + scale_factor = 1.0; } else if (units == "kg/m3") { density_ = -1.0e-3 * val; + scale_factor = -1.0e-3; } else if (units == "atom/b-cm") { density_ = val; + scale_factor = 1.0; } else if (units == "atom/cc" || units == "atom/cm3") { density_ = 1.0e-24 * val; + scale_factor = 1.0e-24; } else { fatal_error("Unknown units '" + units + "' specified on material " + std::to_string(id_) + "."); } + // Scale density_timeseries_ to the same units as density_ + if (density_timeseries_.size() > 0) { + for (double& p : density_timeseries_) { + if (p <= 0) { + fatal_error( + "Zero or negative value detected in material timeseries. This " + "will break any time-dependent simulations. Please fix the " + "density timeseries in your input file. Aborting..."); + } + p *= scale_factor; + } + + // Check that all elements are the same sign. + vector zero_vector; + for (int i = 0; i < density_timeseries_.size(); i++) { + zero_vector.push_back(i); + } + if (!(density_timeseries_ >= zero_vector || + density_timeseries_ <= zero_vector)) { + fatal_error( + "Cannot mix atom and weight percents for density timeseries " + "in material " + + std::to_string(id_)); + } else if ((density_timeseries_ >= zero_vector && density_ <= 0) || + (density_timeseries_ <= zero_vector && density_ >= 0)) { + fatal_error("density_timeseries_ must be same type as density_"); + } + } } } else { fatal_error("Must specify element in material " + @@ -371,6 +430,8 @@ Material& Material::clone() mat->ncrystal_mat_ = ncrystal_mat_.clone(); mat->atom_density_ = atom_density_; mat->density_ = density_; + if (settings::kinetic_simulation) + mat->density_timeseries_ = density_timeseries_; mat->density_gpcc_ = density_gpcc_; mat->volume_ = volume_; mat->fissionable() = fissionable_; @@ -449,6 +510,9 @@ void Material::normalize_density() } sum_percent = 1.0 / sum_percent; density_ = -density_ * N_AVOGADRO / MASS_NEUTRON * sum_percent; + + for (double& p : density_timeseries_) + p = -p * N_AVOGADRO / MASS_NEUTRON * sum_percent; } // Calculate nuclide atom densities diff --git a/src/mgxs.cpp b/src/mgxs.cpp index a2c479f2156..e02dbbddc9f 100644 --- a/src/mgxs.cpp +++ b/src/mgxs.cpp @@ -434,31 +434,38 @@ double Mgxs::get_xs(MgxsType xstype, int gin, const int* gout, const double* mu, { XsData* xs_t = &xs[t]; double val; + std::string mgxs_type; switch (xstype) { case MgxsType::TOTAL: val = xs_t->total(a, gin); + mgxs_type = "total"; break; case MgxsType::NU_FISSION: val = fissionable ? xs_t->nu_fission(a, gin) : 0.; + mgxs_type = "nu-fission"; break; case MgxsType::ABSORPTION: val = xs_t->absorption(a, gin); - ; + mgxs_type = "absorption"; break; case MgxsType::FISSION: val = fissionable ? xs_t->fission(a, gin) : 0.; + mgxs_type = "fission"; break; case MgxsType::KAPPA_FISSION: val = fissionable ? xs_t->kappa_fission(a, gin) : 0.; + mgxs_type = "kappa-fission"; break; case MgxsType::NU_SCATTER: case MgxsType::SCATTER: case MgxsType::NU_SCATTER_FMU: case MgxsType::SCATTER_FMU: val = xs_t->scatter[a]->get_xs(xstype, gin, gout, mu); + mgxs_type = "scatter_data"; break; case MgxsType::PROMPT_NU_FISSION: val = fissionable ? xs_t->prompt_nu_fission(a, gin) : 0.; + mgxs_type = "prompt-nu-fission"; break; case MgxsType::DELAYED_NU_FISSION: if (fissionable) { @@ -473,6 +480,23 @@ double Mgxs::get_xs(MgxsType xstype, int gin, const int* gout, const double* mu, } else { val = 0.; } + mgxs_type = "delayed-nu-fission"; + break; + case MgxsType::CHI: + if (fissionable) { + if (gout != nullptr) { + val = xs_t->chi(a, gin, *gout); + } else { + // provide an outgoing group-wise sum + val = 0.; + for (int g = 0; g < xs_t->chi.shape()[2]; g++) { + val += xs_t->chi(a, gin, g); + } + } + } else { + val = 0.; + } + mgxs_type = "chi"; break; case MgxsType::CHI_PROMPT: if (fissionable) { @@ -488,6 +512,7 @@ double Mgxs::get_xs(MgxsType xstype, int gin, const int* gout, const double* mu, } else { val = 0.; } + mgxs_type = "chi-prompt"; break; case MgxsType::CHI_DELAYED: if (fissionable) { @@ -515,9 +540,11 @@ double Mgxs::get_xs(MgxsType xstype, int gin, const int* gout, const double* mu, } else { val = 0.; } + mgxs_type = "chi-delayed"; break; case MgxsType::INVERSE_VELOCITY: val = xs_t->inverse_velocity(a, gin); + mgxs_type = "inverse-velocity"; break; case MgxsType::DECAY_RATE: if (dg != nullptr) { @@ -525,10 +552,20 @@ double Mgxs::get_xs(MgxsType xstype, int gin, const int* gout, const double* mu, } else { val = xs_t->decay_rate(a, 0); } + mgxs_type = "decay-rate"; break; default: val = 0.; } + // TODO: need to add more robust handling of zero-values cross sections that + // produce NANs on normalization + if (val != val) { + warning( + fmt::format("The {} cross section for this material has a nan present " + "(possibly due to a division by zero). Setting to zero...", + mgxs_type)); + val = 0; + } return val; } diff --git a/src/output.cpp b/src/output.cpp index 80e2b10ab89..e954923a3e2 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -598,6 +598,7 @@ const std::unordered_map score_names = { {SCORE_IFP_TIME_NUM, "IFP lifetime numerator"}, {SCORE_IFP_BETA_NUM, "IFP delayed fraction numerator"}, {SCORE_IFP_DENOM, "IFP common denominator"}, + {SCORE_PRECURSORS, "Precursor Population"}, }; //! Create an ASCII output file showing all tally results. diff --git a/src/random_ray/flat_source_domain.cpp b/src/random_ray/flat_source_domain.cpp index ec14795dd2d..e22a34ac607 100644 --- a/src/random_ray/flat_source_domain.cpp +++ b/src/random_ray/flat_source_domain.cpp @@ -1,4 +1,5 @@ #include "openmc/random_ray/flat_source_domain.h" +#include "openmc/random_ray/bd_utilities.h" #include "openmc/cell.h" #include "openmc/constants.h" @@ -17,7 +18,9 @@ #include "openmc/timer.h" #include "openmc/weight_windows.h" +#include #include +#include namespace openmc { @@ -34,7 +37,10 @@ double FlatSourceDomain::diagonal_stabilization_rho_ {1.0}; std::unordered_map>> FlatSourceDomain::mesh_domain_map_; -FlatSourceDomain::FlatSourceDomain() : negroups_(data::mg.num_energy_groups_) +FlatSourceDomain::FlatSourceDomain() + : negroups_(data::mg.num_energy_groups_), + ndgroups_(data::mg.num_delayed_groups_) + { // Count the number of source regions, compute the cell offset // indices, and store the material type The reason for the offsets is that @@ -52,7 +58,7 @@ FlatSourceDomain::FlatSourceDomain() : negroups_(data::mg.num_energy_groups_) // Initialize source regions. bool is_linear = RandomRay::source_shape_ != RandomRaySourceShape::FLAT; - source_regions_ = SourceRegionContainer(negroups_, is_linear); + source_regions_ = SourceRegionContainer(negroups_, ndgroups_, is_linear); // Initialize tally volumes if (volume_normalized_flux_tallies_) { @@ -89,6 +95,12 @@ void FlatSourceDomain::batch_reset() for (int64_t se = 0; se < n_source_elements(); se++) { source_regions_.scalar_flux_new(se) = 0.0; } + + if (settings::kinetic_simulation && settings::create_delayed_neutrons) { +#pragma omp parallel for + for (int64_t de = 0; de < n_delay_elements(); de++) + source_regions_.precursors_new(de) = 0.0; + } } void FlatSourceDomain::accumulate_iteration_flux() @@ -115,24 +127,61 @@ void FlatSourceDomain::update_single_neutron_source(SourceRegionHandle& srh) double sigma_t = sigma_t_[material * negroups_ + g_out]; double scatter_source = 0.0; double fission_source = 0.0; + double total_source = 0.0; for (int g_in = 0; g_in < negroups_; g_in++) { double scalar_flux = srh.scalar_flux_old(g_in); double sigma_s = sigma_s_[material * negroups_ * negroups_ + g_out * negroups_ + g_in]; - double nu_sigma_f = nu_sigma_f_[material * negroups_ + g_in]; - double chi = chi_[material * negroups_ + g_out]; - + double nu_sigma_f; + double chi; + if (settings::kinetic_simulation && !simulation::is_initial_condition) { + nu_sigma_f = nu_p_sigma_f_[material * negroups_ + g_in]; + chi = chi_p_[material * negroups_ + g_out]; + } else { + nu_sigma_f = nu_sigma_f_[material * negroups_ + g_in]; + chi = chi_[material * negroups_ + g_out]; + } scatter_source += sigma_s * scalar_flux; if (settings::create_fission_neutrons) { fission_source += nu_sigma_f * scalar_flux * chi; } } - srh.source(g_out) = - (scatter_source + fission_source * inverse_k_eff) / sigma_t; + total_source = (scatter_source + fission_source * inverse_k_eff); + + if (settings::kinetic_simulation && !simulation::is_initial_condition) { + // Add delayed source for kinetic simulation if delayed neutrons are + // turned on + if (settings::create_delayed_neutrons) { + double delayed_source = 0.0; + for (int dg = 0; dg < ndgroups_; dg++) { + double chi_d = + chi_d_[material * negroups_ * ndgroups_ + dg * negroups_ + g_out]; + double lambda = lambda_[material * ndgroups_ + dg]; + double precursors = srh.precursors_old(dg); + delayed_source += chi_d * precursors * lambda; + } + total_source += delayed_source; + } + // Add derivative of scalar flux to source (only works for isotropic + // method) + if (RandomRay::time_method_ == RandomRayTimeMethod::ISOTROPIC) { + double inverse_vbar = inverse_vbar_[material * negroups_ + g_out]; + double scalar_flux_rhs_bd = srh.scalar_flux_rhs_bd(g_out); + double A0 = + (bd_coefficients_first_order_.at(RandomRay::bd_order_))[0] / + settings::dt; + double scalar_flux = srh.scalar_flux_old(g_out); + double scalar_flux_time_derivative = + A0 * scalar_flux + scalar_flux_rhs_bd; + total_source -= scalar_flux_time_derivative * inverse_vbar; + } + } + srh.source(g_out) = total_source / sigma_t; } } + // TODO: Add control flow for k-eigenvalue forward-weighted adjoint // Add external source if in fixed source mode if (settings::run_mode == RunMode::FIXED_SOURCE) { for (int g = 0; g < negroups_; g++) { @@ -151,6 +200,10 @@ void FlatSourceDomain::update_all_neutron_sources() for (int64_t sr = 0; sr < n_source_regions(); sr++) { SourceRegionHandle srh = source_regions_.get_source_region_handle(sr); update_single_neutron_source(srh); + if (settings::kinetic_simulation && !simulation::is_initial_condition && + RandomRay::time_method_ == RandomRayTimeMethod::PROPAGATION) { + compute_single_T1(srh); + } } simulation::time_update_src.stop(); @@ -190,6 +243,7 @@ void FlatSourceDomain::set_flux_to_flux_plus_source( int64_t sr, double volume, int g) { int material = source_regions_.material(sr); + // TODO: Implement support for time-dependent void transport if (material == MATERIAL_VOID) { source_regions_.scalar_flux_new(sr, g) /= volume; if (settings::run_mode == RunMode::FIXED_SOURCE) { @@ -201,6 +255,17 @@ void FlatSourceDomain::set_flux_to_flux_plus_source( double sigma_t = sigma_t_[source_regions_.material(sr) * negroups_ + g]; source_regions_.scalar_flux_new(sr, g) /= (sigma_t * volume); source_regions_.scalar_flux_new(sr, g) += source_regions_.source(sr, g); + if (settings::kinetic_simulation && !simulation::is_initial_condition && + RandomRay::time_method_ == RandomRayTimeMethod::PROPAGATION) { + double inverse_vbar = + inverse_vbar_[source_regions_.material(sr) * negroups_ + g]; + double scalar_flux_rhs_bd = source_regions_.scalar_flux_rhs_bd(sr, g); + double A0 = (bd_coefficients_first_order_.at(RandomRay::bd_order_))[0] / + settings::dt; + source_regions_.scalar_flux_new(sr, g) -= + scalar_flux_rhs_bd * inverse_vbar / sigma_t; + source_regions_.scalar_flux_new(sr, g) /= 1 + A0 * inverse_vbar / sigma_t; + } } } @@ -479,6 +544,10 @@ void FlatSourceDomain::convert_source_regions_to_tallies(int64_t start_sr_id) // Loop over scores for (int score = 0; score < tally.scores_.size(); score++) { auto score_bin = tally.scores_[score]; + // Skip precursor score. These must be scored by delay group via + // tally_delay_task. + if (score_bin == SCORE_PRECURSORS) + break; // If a valid tally, filter, and score combination has been found, // then add it to the list of tally tasks for this source element. TallyTask task(i_tally, filter_index, score, score_bin); @@ -494,6 +563,63 @@ void FlatSourceDomain::convert_source_regions_to_tallies(int64_t start_sr_id) for (auto& match : p.filter_matches()) match.bins_present_ = false; } + // Loop over delayed groups (so as to support tallying delayed quantities) + if (settings::kinetic_simulation && settings::create_delayed_neutrons) { + for (int dg = 0; dg < ndgroups_; dg++) { + + // Set particle to the current delay group + p.delayed_group() = dg; + + int64_t delay_element = sr * ndgroups_ + dg; + + // If this task has already been populated, we don't need to do + // it again. + if (source_regions_.tally_delay_task(sr, dg).size() > 0) { + continue; + } + + // Loop over all active tallies. This logic is essentially identical + // to what happens when scanning for applicable tallies during + // MC transport. + // Loop over all active tallies. This logic is essentially identical + for (int i_tally = 0; i_tally < model::tallies.size(); i_tally++) { + Tally& tally {*model::tallies[i_tally]}; + + // Initialize an iterator over valid filter bin combinations. + // If there are no valid combinations, use a continue statement + // to ensure we skip the assume_separate break below. + auto filter_iter = FilterBinIter(tally, p); + auto end = FilterBinIter(tally, true, &p.filter_matches()); + if (filter_iter == end) + continue; + + // Loop over filter bins. + for (; filter_iter != end; ++filter_iter) { + auto filter_index = filter_iter.index_; + auto filter_weight = filter_iter.weight_; + + // Loop over scores + for (int score = 0; score < tally.scores_.size(); score++) { + auto score_bin = tally.scores_[score]; + // We only want to score precursors + if (score_bin != SCORE_PRECURSORS) + break; + // If a valid tally, filter, and score combination has been found, + // then add it to the list of tally tasks for this source element. + TallyTask task(i_tally, filter_index + dg, score, score_bin); + source_regions_.tally_delay_task(sr, dg).push_back(task); + + // Also add this task to the list of volume tasks for this source + // region. + source_regions_.volume_task(sr).insert(task); + } + } + } + // Reset all the filter matches for the next tally event. + for (auto& match : p.filter_matches()) + match.bins_present_ = false; + } + } } openmc::simulation::time_tallies.stop(); @@ -592,6 +718,7 @@ double FlatSourceDomain::compute_fixed_source_normalization_factor() const // tally function simply traverses the mapping data structure and executes // the scoring operations to OpenMC's native tally result arrays. +// TODO: Add support for prompt and delayed nu fission tallies void FlatSourceDomain::random_ray_tally() { openmc::simulation::time_tallies.start(); @@ -634,18 +761,21 @@ void FlatSourceDomain::random_ray_tally() case SCORE_TOTAL: if (material != MATERIAL_VOID) { + double sigma_t = sigma_t_[material * negroups_ + g]; score = flux * volume * sigma_t_[material * negroups_ + g]; } break; case SCORE_FISSION: if (material != MATERIAL_VOID) { + double sigma_f = sigma_f_[material * negroups_ + g]; score = flux * volume * sigma_f_[material * negroups_ + g]; } break; case SCORE_NU_FISSION: if (material != MATERIAL_VOID) { + double nu_sigma_f = nu_sigma_f_[material * negroups_ + g]; score = flux * volume * nu_sigma_f_[material * negroups_ + g]; } break; @@ -654,10 +784,22 @@ void FlatSourceDomain::random_ray_tally() score = 1.0; break; + case SCORE_PRECURSORS: + // Score precursors in tally_delay_tasks + if (settings::kinetic_simulation && + settings::create_delayed_neutrons) { + break; + } else { + fatal_error("Invalid score specified in tallies.xml. Precursors " + "are only supported in random ray mode for kinetic " + "simulations when delayed neutrons are turned on."); + } + default: fatal_error("Invalid score specified in tallies.xml. Only flux, " "total, fission, nu-fission, and events are supported in " - "random ray mode."); + "random ray mode (precursors are supported in kinetic " + "simulations when delayed neutrons are turned on)."); break; } // Apply score to the appropriate tally bin @@ -667,13 +809,51 @@ void FlatSourceDomain::random_ray_tally() score; } } + if (settings::kinetic_simulation && settings::create_delayed_neutrons) { + for (int dg = 0; dg < ndgroups_; dg++) { + // Determine numerical score value + for (auto& task : source_regions_.tally_delay_task(sr, dg)) { + double score = 0.0; + switch (task.score_type) { + + // Certain scores already tallied + case SCORE_FLUX: + case SCORE_TOTAL: + case SCORE_FISSION: + case SCORE_NU_FISSION: + case SCORE_EVENTS: + break; + + case SCORE_PRECURSORS: + score = source_regions_.precursors_new(sr, dg) * + source_normalization_factor * volume; + break; + + default: + fatal_error( + "Invalid score specified in tallies.xml. Only flux, " + "total, fission, nu-fission, and events are supported in " + "random ray mode (precursors are supported in kinetic " + "simulations when delayed neutrons are turned on)."); + break; + } + + // Apply score to the appropriate tally bin + Tally& tally {*model::tallies[task.tally_idx]}; +#pragma omp atomic + tally.results_(task.filter_idx, task.score_idx, TallyResult::VALUE) += + score; + } + } + } - // For flux tallies, the total volume of the spatial region is needed - // for normalizing the flux. We store this volume in a separate tensor. - // We only contribute to each volume tally bin once per FSR. + // For flux and precursor tallies, the total volume of the spatial region is + // needed for normalizing the tally. We store this volume in a separate + // tensor. We only contribute to each volume tally bin once per FSR. if (volume_normalized_flux_tallies_) { for (const auto& task : source_regions_.volume_task(sr)) { - if (task.score_type == SCORE_FLUX) { + if (task.score_type == SCORE_FLUX || + task.score_type == SCORE_PRECURSORS) { #pragma omp atomic tally_volumes_[task.tally_idx](task.filter_idx, task.score_idx) += volume; @@ -682,11 +862,11 @@ void FlatSourceDomain::random_ray_tally() } } // end FSR loop - // Normalize any flux scores by the total volume of the FSRs scoring to that - // bin. To do this, we loop over all tallies, and then all filter bins, - // and then scores. For each score, we check the tally data structure to - // see what index that score corresponds to. If that score is a flux score, - // then we divide it by volume. + // Normalize any flux or precursor scores by the total volume of the FSRs + // scoring to that bin. To do this, we loop over all tallies, and then all + // filter bins, and then scores. For each score, we check the tally data + // structure to see what index that score corresponds to. If that score is a + // flux or precursor score, then we divide it by volume. if (volume_normalized_flux_tallies_) { for (int i = 0; i < model::tallies.size(); i++) { Tally& tally {*model::tallies[i]}; @@ -694,7 +874,7 @@ void FlatSourceDomain::random_ray_tally() for (int bin = 0; bin < tally.n_filter_bins(); bin++) { for (int score_idx = 0; score_idx < tally.n_scores(); score_idx++) { auto score_type = tally.scores_[score_idx]; - if (score_type == SCORE_FLUX) { + if (score_type == SCORE_FLUX || score_type == SCORE_PRECURSORS) { double vol = tally_volumes_[i](bin, score_idx); if (vol > 0.0) { tally.results_(bin, score_idx, TallyResult::VALUE) /= vol; @@ -1143,8 +1323,7 @@ void FlatSourceDomain::flatten_xs() m.get_xs(MgxsType::FISSION, g_out, NULL, NULL, NULL, t, a); sigma_f_.push_back(sigma_f); - double chi = - m.get_xs(MgxsType::CHI_PROMPT, g_out, &g_out, NULL, NULL, t, a); + double chi = m.get_xs(MgxsType::CHI, g_out, &g_out, NULL, NULL, t, a); if (!std::isfinite(chi)) { // MGXS interface may return NaN in some cases, such as when material // is fissionable but has very small sigma_f. @@ -1162,6 +1341,25 @@ void FlatSourceDomain::flatten_xs() if (g_out == g_in && sigma_s < 0.0) is_transport_stabilization_needed_ = true; } + // Prompt cross-sections for kinetic simulations + if (settings::kinetic_simulation) { + double chi_p = + m.get_xs(MgxsType::CHI_PROMPT, g_out, &g_out, NULL, NULL, t, a); + if (!std::isfinite(chi_p)) { + // MGXS interface may return NaN in some cases, such as when + // material is fissionable but has very small sigma_f. + chi_p = 0.0; + } + chi_p_.push_back(chi_p); + + double inverse_vbar = + m.get_xs(MgxsType::INVERSE_VELOCITY, g_out, NULL, NULL, NULL, t, a); + inverse_vbar_.push_back(inverse_vbar); + + double nu_p_Sigma_f = m.get_xs( + MgxsType::PROMPT_NU_FISSION, g_out, NULL, NULL, NULL, t, a); + nu_p_sigma_f_.push_back(nu_p_Sigma_f); + } } else { sigma_t_.push_back(0); nu_sigma_f_.push_back(0); @@ -1170,6 +1368,40 @@ void FlatSourceDomain::flatten_xs() for (int g_in = 0; g_in < negroups_; g_in++) { sigma_s_.push_back(0); } + if (settings::kinetic_simulation) { + chi_p_.push_back(0); + inverse_vbar_.push_back(0); + nu_p_sigma_f_.push_back(0); + } + } + } + // Delayed cross sections for time-dependent simulations + if (settings::kinetic_simulation) { + for (int dg = 0; dg < ndgroups_; dg++) { + if (m.exists_in_model) { + double lambda = + m.get_xs(MgxsType::DECAY_RATE, 0, NULL, NULL, &dg, t, a); + lambda_.push_back(lambda); + for (int g_out = 0; g_out < negroups_; g_out++) { + double nu_d_Sigma_f = m.get_xs( + MgxsType::DELAYED_NU_FISSION, g_out, NULL, NULL, &dg, t, a); + nu_d_sigma_f_.push_back(nu_d_Sigma_f); + double chi_d = + m.get_xs(MgxsType::CHI_DELAYED, g_out, &g_out, NULL, &dg, t, a); + if (!std::isfinite(chi_d)) { + // MGXS interface may return NaN in some cases, such as when + // material is fissionable but has very small sigma_f. + chi_d = 0.0; + } + chi_d_.push_back(chi_d); + } + } else { + lambda_.push_back(0); + for (int g_out = 0; g_out < negroups_; g_out++) { + nu_d_sigma_f_.push_back(0); + chi_d_.push_back(0); + } + } } } } @@ -1279,6 +1511,17 @@ void FlatSourceDomain::serialize_final_fluxes(vector& flux) } } +void FlatSourceDomain::serialize_final_sources(vector& source) +{ + // Ensure array is correct size + source.resize(n_source_regions() * negroups_); + // Serialize the final sources for output +#pragma omp parallel for + for (int64_t se = 0; se < n_source_elements(); se++) { + source[se] = source_regions_.source_final(se); + } +} + void FlatSourceDomain::apply_mesh_to_cell_instances(int32_t i_cell, int32_t mesh_idx, int target_material_id, const vector& instances, bool is_target_void) @@ -1474,8 +1717,8 @@ SourceRegionHandle FlatSourceDomain::get_subdivided_source_region_handle( // Call the basic constructor for the source region and store in the parallel // map. bool is_linear = RandomRay::source_shape_ != RandomRaySourceShape::FLAT; - SourceRegion* sr_ptr = - discovered_source_regions_.emplace(sr_key, {negroups_, is_linear}); + SourceRegion* sr_ptr = discovered_source_regions_.emplace( + sr_key, {negroups_, ndgroups_, is_linear}); SourceRegionHandle handle {*sr_ptr}; // Determine the material @@ -1531,6 +1774,10 @@ SourceRegionHandle FlatSourceDomain::get_subdivided_source_region_handle( // Compute the combined source term update_single_neutron_source(handle); + if (settings::kinetic_simulation && !simulation::is_initial_condition && + RandomRay::time_method_ == RandomRayTimeMethod::PROPAGATION) { + compute_single_T1(handle); + } // Unlock the parallel map. Note: we may be tempted to release // this lock earlier, and then just use the source region's lock to protect @@ -1677,4 +1924,285 @@ int64_t FlatSourceDomain::lookup_mesh_bin(int64_t sr, Position r) const return mesh_bin; } +//------------------------------------------------------------------------------ +// Methods for kinetic simulations + +// Generates new estimate of k_dynamic based on the fraction between this +// timestep's estimate of neutron production and loss. (previous timestep +// fission vs current timestep fission?) +// TODO: implement compute_k_dynamic + +// Compute new estimate of scattering + fission (+ precursor decay for +// kinetic simulations) sources in each source region based on the flux +// estimate from the previous iteration. + +// T1 calculation +void FlatSourceDomain::compute_single_T1(SourceRegionHandle& srh) +{ + double A0 = + (bd_coefficients_first_order_.at(RandomRay::bd_order_))[0] / settings::dt; + double B0 = (bd_coefficients_second_order_.at(RandomRay::bd_order_))[0] / + (settings::dt * settings::dt); + int material = srh.material(); + for (int g = 0; g < negroups_; g++) { + double inverse_vbar = inverse_vbar_[material * negroups_ + g]; + double sigma_t = 1.0; + if (material != MATERIAL_VOID) + sigma_t = sigma_t_[material * negroups_ + g]; + + // Multiply out sigma_t to correctly compute the derivative term + float source_time_derivative = + A0 * srh.source(g) * sigma_t + srh.source_rhs_bd(g); + + double scalar_flux_time_derivative_2 = + B0 * srh.scalar_flux_old(g) + srh.scalar_flux_rhs_bd_2(g); + scalar_flux_time_derivative_2 *= inverse_vbar; + + // Divide by sigma_t to save time during transport + srh.T1(g) = + (source_time_derivative - scalar_flux_time_derivative_2) / sigma_t; + } +} + +void FlatSourceDomain::compute_single_delayed_fission_source( + SourceRegionHandle& srh) +{ + + // Reset all delayed fission sources to zero (important for void regions) + for (int dg = 0; dg < ndgroups_; dg++) { + srh.delayed_fission_source(dg) = 0.0; + } + + int material = srh.material(); + if (material != MATERIAL_VOID) { + double inverse_k_eff = 1.0 / k_eff_; + for (int dg = 0; dg < ndgroups_; dg++) { + // We cannot have delayed neutrons if there is no delayed data + double lambda = lambda_[material * ndgroups_ + dg]; + if (lambda != 0.0) { + for (int g = 0; g < negroups_; g++) { + double scalar_flux = scalar_flux = srh.scalar_flux_new(g); + double nu_d_sigma_f = nu_d_sigma_f_[material * negroups_ * ndgroups_ + + dg * negroups_ + g]; + srh.delayed_fission_source(dg) += nu_d_sigma_f * scalar_flux; + } + srh.delayed_fission_source(dg) *= inverse_k_eff; + } + } + } +} + +void FlatSourceDomain::compute_single_precursors(SourceRegionHandle& srh) +{ + // Reset all precursors to zero (important for void regions) + for (int dg = 0; dg < ndgroups_; dg++) { + srh.precursors_new(dg) = 0.0; + } + + int material = srh.material(); + if (material != MATERIAL_VOID) { + for (int dg = 0; dg < ndgroups_; dg++) { + double lambda = lambda_[material * ndgroups_ + dg]; + if (lambda != 0.0) { + double delayed_fission_source = srh.delayed_fission_source(dg); + if (simulation::is_initial_condition) { + srh.precursors_new(dg) = delayed_fission_source / lambda; + } else { + double precursor_rhs_bd = srh.precursors_rhs_bd(dg); + srh.precursors_new(dg) = delayed_fission_source - precursor_rhs_bd; + double A0 = + (bd_coefficients_first_order_.at(RandomRay::bd_order_))[0] / + settings::dt; + srh.precursors_new(dg) /= A0 + lambda; + } + } + } + } +} + +void FlatSourceDomain::compute_all_precursors() +{ + simulation::time_compute_precursors.start(); + +#pragma omp parallel for + for (int64_t sr = 0; sr < n_source_regions(); sr++) { + SourceRegionHandle srh = source_regions_.get_source_region_handle(sr); + compute_single_delayed_fission_source(srh); + compute_single_precursors(srh); + } + + simulation::time_compute_precursors.start(); +} + +void FlatSourceDomain::serialize_final_precursors(vector& precursors) +{ + // Ensure array is correct size + precursors.resize(n_source_regions() * ndgroups_); +// Serialize the precursors for output +#pragma omp parallel for + for (int64_t de = 0; de < n_delay_elements(); de++) { + precursors[de] = source_regions_.precursors_final(de); + } +} + +void FlatSourceDomain::precursors_swap() +{ + source_regions_.precursors_swap(); +} + +void FlatSourceDomain::accumulate_iteration_quantities() +{ + accumulate_iteration_flux(); + if (settings::kinetic_simulation) { +#pragma omp parallel for + for (int64_t sr = 0; sr < n_source_regions(); sr++) { + for (int g = 0; g < negroups_; g++) { + if (RandomRay::time_method_ == RandomRayTimeMethod::PROPAGATION) { + source_regions_.source_final(sr, g) += source_regions_.source(sr, g); + } + } + if (settings::create_delayed_neutrons) { + for (int dg = 0; dg < ndgroups_; dg++) { + source_regions_.precursors_final(sr, dg) += + source_regions_.precursors_new(sr, dg); + } + } + } + } +} + +void FlatSourceDomain::normalize_final_quantities() +{ + double normalization_factor = + 1.0 / (settings::n_batches - settings::n_inactive); + double source_normalization_factor; + if (!settings::kinetic_simulation || + settings::kinetic_simulation && + simulation::current_timestep == settings::n_timesteps) + source_normalization_factor = + compute_fixed_source_normalization_factor() * normalization_factor; + else + // The source normalization should only be applied to internal quantities at + // the end of time stepping in preparation for an adjoint solve. + source_normalization_factor = 1.0 * normalization_factor; + +#pragma omp parallel for + for (int64_t sr = 0; sr < n_source_regions(); sr++) { + for (int g = 0; g < negroups_; g++) { + source_regions_.scalar_flux_final(sr, g) *= source_normalization_factor; + if (RandomRay::time_method_ == RandomRayTimeMethod::PROPAGATION) { + source_regions_.source_final(sr, g) *= source_normalization_factor; + } + } + if (settings::kinetic_simulation) { + for (int dg = 0; dg < ndgroups_; dg++) { + source_regions_.precursors_final(sr, dg) *= source_normalization_factor; + } + } + } +} + +void FlatSourceDomain::propagate_final_quantities() +{ +#pragma omp parallel for + for (int64_t sr = 0; sr < n_source_regions(); sr++) { + for (int g = 0; g < negroups_; g++) { + source_regions_.scalar_flux_old(sr, g) = + source_regions_.scalar_flux_final(sr, g); + } + if (settings::create_delayed_neutrons) { + for (int dg = 0; dg < ndgroups_; dg++) { + source_regions_.precursors_old(sr, dg) = + source_regions_.precursors_final(sr, dg); + } + } + } +} + +void FlatSourceDomain::store_time_step_quantities(bool increment_not_initialize) +{ +#pragma omp parallel for + for (int64_t sr = 0; sr < n_source_regions(); sr++) { + for (int g = 0; g < negroups_; g++) { + int j = 0; + if (RandomRay::time_method_ == RandomRayTimeMethod::PROPAGATION) + j = 1; + add_value_to_bd_vector(source_regions_.scalar_flux_bd(sr, g), + source_regions_.scalar_flux_final(sr, g), increment_not_initialize, + RandomRay::bd_order_ + j); + if (RandomRay::time_method_ == RandomRayTimeMethod::PROPAGATION) { + // TODO: add support for void regions + // Multiply out sigma_t to store the base source + double sigma_t = sigma_t = + sigma_t_[source_regions_.material(sr) * negroups_ + g]; + float source = source_regions_.source_final(sr, g) * sigma_t; + add_value_to_bd_vector(source_regions_.source_bd(sr, g), source, + increment_not_initialize, RandomRay::bd_order_); + } + } + if (settings::create_delayed_neutrons) { + for (int dg = 0; dg < ndgroups_; dg++) { + add_value_to_bd_vector(source_regions_.precursors_bd(sr, dg), + source_regions_.precursors_final(sr, dg), increment_not_initialize, + RandomRay::bd_order_); + } + } + } +} + +void FlatSourceDomain::compute_rhs_bd_quantities() +{ +#pragma omp parallel for + for (int64_t sr = 0; sr < n_source_regions(); sr++) { + for (int g = 0; g < negroups_; g++) { + source_regions_.scalar_flux_rhs_bd(sr, g) = + rhs_backwards_difference(source_regions_.scalar_flux_bd(sr, g), + RandomRay::bd_order_, settings::dt); + + if (RandomRay::time_method_ == RandomRayTimeMethod::PROPAGATION) { + source_regions_.source_rhs_bd(sr, g) = rhs_backwards_difference( + source_regions_.source_bd(sr, g), RandomRay::bd_order_, settings::dt); + + source_regions_.scalar_flux_rhs_bd_2(sr, g) = + rhs_backwards_difference(source_regions_.scalar_flux_bd(sr, g), + RandomRay::bd_order_, settings::dt, 2); + } + } + if (settings::create_delayed_neutrons) { + for (int dg = 0; dg < ndgroups_; dg++) { + source_regions_.precursors_rhs_bd(sr, dg) = + rhs_backwards_difference(source_regions_.precursors_bd(sr, dg), + RandomRay::bd_order_, settings::dt); + } + } + } +} + +// Update material density and cross sections +void FlatSourceDomain::update_material_density(int i) +{ +#pragma omp parallel for + for (int j = 0; j < model::materials.size(); j++) { + auto& mat {model::materials[j]}; + if (mat->density_timeseries_.size() != 0) { + double density_factor = mat->density_timeseries_[i] / mat->density_; + mat->density_ = mat->density_timeseries_[i]; + for (int g_out = 0; g_out < negroups_; g_out++) { + for (int dg = 0; dg < ndgroups_; dg++) { + nu_d_sigma_f_[j * negroups_ * ndgroups_ + dg * negroups_ + g_out] *= + density_factor; + } + nu_p_sigma_f_[j * negroups_ + g_out] *= density_factor; + sigma_t_[j * negroups_ + g_out] *= density_factor; + nu_sigma_f_[j * negroups_ + g_out] *= density_factor; + sigma_f_[j * negroups_ + g_out] *= density_factor; + for (int g_in = 0; g_in < negroups_; g_in++) { + sigma_s_[j * negroups_ * negroups_ + g_out * negroups_ + g_in] *= + density_factor; + } + } + } + } +} + } // namespace openmc diff --git a/src/random_ray/random_ray.cpp b/src/random_ray/random_ray.cpp index c19d136a4a2..4ab73d7c156 100644 --- a/src/random_ray/random_ray.cpp +++ b/src/random_ray/random_ray.cpp @@ -239,10 +239,21 @@ unique_ptr RandomRay::ray_source_; RandomRaySourceShape RandomRay::source_shape_ {RandomRaySourceShape::FLAT}; RandomRaySampleMethod RandomRay::sample_method_ {RandomRaySampleMethod::PRNG}; +double RandomRay::avg_miss_rate_; +int64_t RandomRay::n_source_regions_; +int64_t RandomRay::n_external_source_regions_; +uint64_t RandomRay::total_geometric_intersections_; + +// Kinetic simulation variables +int RandomRay::bd_order_ {3}; // order 3 BD balances accuracy with speed nicely +RandomRayTimeMethod RandomRay::time_method_ {RandomRayTimeMethod::ISOTROPIC}; + RandomRay::RandomRay() : angular_flux_(data::mg.num_energy_groups_), delta_psi_(data::mg.num_energy_groups_), - negroups_(data::mg.num_energy_groups_) + negroups_(data::mg.num_energy_groups_), + angular_flux_prime_(data::mg.num_energy_groups_) + { if (source_shape_ == RandomRaySourceShape::LINEAR || source_shape_ == RandomRaySourceShape::LINEAR_XY) { @@ -400,6 +411,7 @@ void RandomRay::attenuate_flux_inner( break; case RandomRaySourceShape::LINEAR: case RandomRaySourceShape::LINEAR_XY: + // TODO: time-dependent linear source regions if (srh.material() == MATERIAL_VOID) { attenuate_flux_linear_source_void(srh, distance, is_active, r); } else { @@ -439,6 +451,19 @@ void RandomRay::attenuate_flux_flat_source( float tau = sigma_t * distance; float exponential = cjosey_exponential(tau); // exponential = 1 - exp(-tau) float new_delta_psi = (angular_flux_[g] - srh.source(g)) * exponential; + if (settings::kinetic_simulation && !simulation::is_initial_condition && + RandomRay::time_method_ == RandomRayTimeMethod::PROPAGATION) { + float T1 = srh.T1(g); + + // Source Derivative Propogation terms for Characteristic Equation + float inverse_vbar = domain_->inverse_vbar_[material * negroups_ + g]; + new_delta_psi += T1 * inverse_vbar * exponential / sigma_t; + new_delta_psi += distance * inverse_vbar * (angular_flux_prime_[g] - T1) * + (1 - exponential); + + // Time Derivative Characteristic Equation + angular_flux_prime_[g] -= (angular_flux_prime_[g] - T1) * exponential; + } delta_psi_[g] = new_delta_psi; angular_flux_[g] -= new_delta_psi; } @@ -476,6 +501,7 @@ void RandomRay::attenuate_flux_flat_source( } // Alternative flux attenuation function for true void regions. +// TODO: Implement support for time dependent voids void RandomRay::attenuate_flux_flat_source_void( SourceRegionHandle& srh, double distance, bool is_active, Position r) { @@ -812,6 +838,13 @@ void RandomRay::initialize_ray(uint64_t ray_id, FlatSourceDomain* domain) for (int g = 0; g < negroups_; g++) { angular_flux_[g] = srh.source(g); } + if (settings::kinetic_simulation && !simulation::is_initial_condition && + RandomRay::time_method_ == RandomRayTimeMethod::PROPAGATION) { + for (int g = 0; g < negroups_; g++) { + // T1 + angular_flux_prime_[g] = srh.T1(g); + } + } } } diff --git a/src/random_ray/random_ray_simulation.cpp b/src/random_ray/random_ray_simulation.cpp index d475b2593ea..901148ad224 100644 --- a/src/random_ray/random_ray_simulation.cpp +++ b/src/random_ray/random_ray_simulation.cpp @@ -28,17 +28,10 @@ void openmc_run_random_ray() // Run forward simulation ////////////////////////////////////////////////////////// - // Check if adjoint calculation is needed. If it is, we will run the forward - // calculation first and then the adjoint calculation later. - bool adjoint_needed = FlatSourceDomain::adjoint_; - - // Configure the domain for forward simulation - FlatSourceDomain::adjoint_ = false; - - // If we're going to do an adjoint simulation afterwards, report that this is - // the initial forward flux solve. - if (adjoint_needed && mpi::master) - header("FORWARD FLUX SOLVE", 3); + if (mpi::master) { + bool adjoint_needed = FlatSourceDomain::adjoint_; + print_random_ray_headers(adjoint_needed); + } // Initialize OpenMC general data structures openmc_simulation_init(); @@ -53,76 +46,27 @@ void openmc_run_random_ray() // Initialize fixed sources, if present sim.apply_fixed_sources_and_mesh_domains(); - // Begin main simulation timer - simulation::time_total.start(); - - // Execute random ray simulation - sim.simulate(); - - // End main simulation timer - simulation::time_total.stop(); + // Run initial random ray simulation + sim.run_single_simulation(); - // Normalize and save the final forward flux - double source_normalization_factor = - sim.domain()->compute_fixed_source_normalization_factor() / - (settings::n_batches - settings::n_inactive); + if (settings::kinetic_simulation) { + // Second steady state simulation to correct the batchwise k-eff + sim.kinetic_initial_condition(); -#pragma omp parallel for - for (uint64_t se = 0; se < sim.domain()->n_source_elements(); se++) { - sim.domain()->source_regions_.scalar_flux_final(se) *= - source_normalization_factor; + warning( + "Time-dependent explicit void treatment has not yet been " + "implemented. Use caution when interpreting results from models with " + "voids, as they may contain large inaccuracies."); + // Timestepping loop + for (int i = 0; i < settings::n_timesteps; i++) + sim.kinetic_single_time_step(i); } - // Finalize OpenMC - openmc_simulation_finalize(); - - // Output all simulation results - sim.output_simulation_results(); - ////////////////////////////////////////////////////////// // Run adjoint simulation (if enabled) ////////////////////////////////////////////////////////// - if (!adjoint_needed) { - return; - } - - reset_timers(); - - // Configure the domain for adjoint simulation - FlatSourceDomain::adjoint_ = true; - - if (mpi::master) - header("ADJOINT FLUX SOLVE", 3); - - // Initialize OpenMC general data structures - openmc_simulation_init(); - - sim.domain()->k_eff_ = 1.0; - - // Initialize adjoint fixed sources, if present - sim.prepare_fixed_sources_adjoint(); - - // Transpose scattering matrix - sim.domain()->transpose_scattering_matrix(); - - // Swap nu_sigma_f and chi - sim.domain()->nu_sigma_f_.swap(sim.domain()->chi_); - - // Begin main simulation timer - simulation::time_total.start(); - - // Execute random ray simulation - sim.simulate(); - - // End main simulation timer - simulation::time_total.stop(); - - // Finalize OpenMC - openmc_simulation_finalize(); - - // Output all simulation results - sim.output_simulation_results(); + sim.random_ray_adjoint(); } // Enforces restrictions on inputs in random ray mode. While there are @@ -144,10 +88,22 @@ void validate_random_ray_inputs() case SCORE_NU_FISSION: case SCORE_EVENTS: break; + + // TODO: add support for prompt and delayed fission + case SCORE_PRECURSORS: { + if (settings::kinetic_simulation && settings::create_delayed_neutrons) { + break; + } else { + fatal_error("Invalid score specified in tallies.xml. Precursors can " + "only be scored for kinetic simulations."); + } + } default: fatal_error( "Invalid score specified. Only flux, total, fission, nu-fission, and " - "event scores are supported in random ray mode."); + "event scores are supported in random ray mode. (precursors are " + "supported for " + "kinetic simulations when delayed neutrons are turned on)."); } } @@ -165,15 +121,25 @@ void validate_random_ray_inputs() case FilterType::UNIVERSE: case FilterType::PARTICLE: break; + case FilterType::DELAYED_GROUP: + if (settings::kinetic_simulation) { + break; + } else { + fatal_error("Invalid filter specified in tallies.xml. Kinetic " + "simulations is required " + "to tally with a delayed_group filter."); + } default: fatal_error("Invalid filter specified. Only cell, cell_instance, " "distribcell, energy, material, mesh, and universe filters " - "are supported in random ray mode."); + "are supported in random ray mode (delayed_group is " + "supported for kinetic simulations)."); } } } - // Validate MGXS data + // TODO: validate kinetic data is present + // Validate MGXS data /////////////////////////////////////////////////////////////////// for (auto& material : data::mg.macro_xs_) { if (!material.is_isotropic) { @@ -351,6 +317,103 @@ void openmc_reset_random_ray() RandomRay::ray_source_.reset(); RandomRay::source_shape_ = RandomRaySourceShape::FLAT; RandomRay::sample_method_ = RandomRaySampleMethod::PRNG; + RandomRay::bd_order_ = 3; + RandomRay::time_method_ = RandomRayTimeMethod::ISOTROPIC; +} + +void write_random_ray_hdf5(hid_t group) +{ + hid_t random_ray_group = create_group(group, "random_ray"); + switch (RandomRay::source_shape_) { + case RandomRaySourceShape::FLAT: + write_dataset(random_ray_group, "source_shape", "flat"); + break; + case RandomRaySourceShape::LINEAR: + write_dataset(random_ray_group, "source_shape", "linear"); + break; + case RandomRaySourceShape::LINEAR_XY: + write_dataset(random_ray_group, "source_shape", "linear xy"); + break; + default: + break; + } + + switch (FlatSourceDomain::volume_estimator_) { + case RandomRayVolumeEstimator::SIMULATION_AVERAGED: + write_dataset(random_ray_group, "volume_estimator", "simulation averaged"); + break; + case RandomRayVolumeEstimator::NAIVE: + write_dataset(random_ray_group, "volume_estimator", "naive"); + break; + case RandomRayVolumeEstimator::HYBRID: + write_dataset(random_ray_group, "volume_estimator", "hybrid"); + break; + default: + break; + } + + write_dataset( + random_ray_group, "distance_active", RandomRay::distance_active_); + write_dataset( + random_ray_group, "distance_inactive", RandomRay::distance_inactive_); + write_dataset(random_ray_group, "volume_normalized_flux_tallies", + FlatSourceDomain::volume_normalized_flux_tallies_); + write_dataset(random_ray_group, "adjoint_mode", FlatSourceDomain::adjoint_); + + write_dataset(random_ray_group, "avg_miss_rate", RandomRay::avg_miss_rate_); + write_dataset( + random_ray_group, "n_source_regions", RandomRay::n_source_regions_); + write_dataset(random_ray_group, "n_external_source_regions", + RandomRay::n_external_source_regions_); + write_dataset(random_ray_group, "n_geometric_intersections", + RandomRay::total_geometric_intersections_); + int64_t n_integrations = + RandomRay::total_geometric_intersections_ * data::mg.num_energy_groups_; + write_dataset(random_ray_group, "n_integrations", n_integrations); + + if (settings::kinetic_simulation && !simulation::is_initial_condition) { + write_dataset(random_ray_group, "bd_order", RandomRay::bd_order_); + switch (RandomRay::time_method_) { + case RandomRayTimeMethod::ISOTROPIC: + write_dataset(random_ray_group, "time_method", "isotropic"); + break; + case RandomRayTimeMethod::PROPAGATION: + write_dataset(random_ray_group, "time_method", "propogation"); + break; + default: + break; + } + } + close_group(random_ray_group); +} + +void print_random_ray_headers(bool& adjoint_needed) +{ + // If we're going to do an adjoint simulation afterwards, report that this is + // the initial forward flux solve. + if (adjoint_needed && !FlatSourceDomain::adjoint_) + header("FORWARD FLUX SOLVE", 3); + + // Otherwise report that we are doing the adjoint simulation + if (adjoint_needed && FlatSourceDomain::adjoint_) + header("ADJOINT FLUX SOLVE", 3); +} + +//----------------------------------------------------------------------------- +// Non-member functions for kinetic simulations + +void rename_time_step_file( + std::string base_filename, std::string extension, int i) +{ + // Rename file + std::string old_filename_ = + fmt::format("{0}{1}{2}", settings::path_output, base_filename, extension); + std::string new_filename_ = fmt::format( + "{0}{1}_{2}{3}", settings::path_output, base_filename, i, extension); + + const char* old_fname = old_filename_.c_str(); + const char* new_fname = new_filename_.c_str(); + std::rename(old_fname, new_fname); } //============================================================================== @@ -358,7 +421,8 @@ void openmc_reset_random_ray() //============================================================================== RandomRaySimulation::RandomRaySimulation() - : negroups_(data::mg.num_energy_groups_) + : negroups_(data::mg.num_energy_groups_), + ndgroups_(data::mg.num_delayed_groups_) { // There are no source sites in random ray mode, so be sure to disable to // ensure we don't attempt to write source sites to statepoint @@ -383,6 +447,25 @@ RandomRaySimulation::RandomRaySimulation() // Convert OpenMC native MGXS into a more efficient format // internal to the random ray solver domain_->flatten_xs(); + + // Check if adjoint calculation is needed. If it is, we will run the forward + // calculation first and then the adjoint calculation later. + adjoint_needed_ = FlatSourceDomain::adjoint_; + + // Adjoint is always false for the forward calculation + FlatSourceDomain::adjoint_ = false; + + // The first simulation is run after initialization + is_first_simulation_ = true; + + // Initialize vectors used for baking in the initial condition during time + // stepping + if (settings::kinetic_simulation) { + // Initialize vars used for time-consistent seed approach + static_avg_k_eff_; + static_k_eff_; + static_fission_rate_; + } } void RandomRaySimulation::apply_fixed_sources_and_mesh_domains() @@ -403,6 +486,139 @@ void RandomRaySimulation::prepare_fixed_sources_adjoint() } } +void RandomRaySimulation::print_random_ray_headers() +{ + openmc::print_random_ray_headers(adjoint_needed_); +} + +void RandomRaySimulation::run_single_simulation() +{ + if (!is_first_simulation_) { + if (mpi::master) + print_random_ray_headers(); + + // Reset the timers and reinitialize the general OpenMC datastructures if + // this is after the first simulation + reset_timers(); + + // Initialize OpenMC general data structures + openmc_simulation_init(); + } + + // Begin main simulation timer + simulation::time_total.start(); + + // Execute random ray simulation + simulate(); + + // End main simulation timer + simulation::time_total.stop(); + + // Normalize and save the final forward quantities + domain_->normalize_final_quantities(); + + // Finalize OpenMC + openmc_simulation_finalize(); + + // Output all simulation results + output_simulation_results(); + + // Toggle that the simulation object has been initialized after the first + // simulation + if (is_first_simulation_) + is_first_simulation_ = false; +} + +void RandomRaySimulation::random_ray_adjoint() +{ + if (!adjoint_needed_) { + return; + } + + // Configure the domain for adjoint simulation + FlatSourceDomain::adjoint_ = true; + + // Reset k-eff + domain_->k_eff_ = 1.0; + + // Initialize adjoint fixed sources, if present + prepare_fixed_sources_adjoint(); + + // Transpose scattering matrix + domain_->transpose_scattering_matrix(); + + // Swap nu_sigma_f and chi + domain_->nu_sigma_f_.swap(domain_->chi_); + + // Run a single simulation + run_single_simulation(); +} + +void RandomRaySimulation::kinetic_initial_condition() +{ + // Set flag for k_eff correction + simulation::k_eff_correction = true; + + static_avg_k_eff_ = simulation::keff; + domain_->k_eff_ = static_avg_k_eff_; + domain_->source_regions_.adjoint_reset(); + domain_->propagate_final_quantities(); + domain_->source_regions_.time_step_reset(); + + // Run the initial condition + run_single_simulation(); + + // Initialize the BD arrays + domain_->store_time_step_quantities(false); + + // Store k-eff corrected initial condition statepoints + rename_time_step_file( + fmt::format("statepoint.{0}", settings::n_batches), ".h5", 0); + if (settings::output_tallies) { + rename_time_step_file("tallies", ".out", 0); + } + + // Set flags for kinetic simulation + simulation::is_initial_condition = false; + simulation::k_eff_correction = false; + + // Set starting time as zero + simulation::current_time = 0; +} + +// TODO: Add support for time-dependent restart +void RandomRaySimulation::kinetic_single_time_step(int i) +{ + // Increment time step + simulation::current_timestep = i + 1; + simulation::current_time += settings::dt; + + // Propogate results of previous simulation + domain_->k_eff_ = static_avg_k_eff_; + domain_->source_regions_.adjoint_reset(); + domain_->propagate_final_quantities(); + domain_->source_regions_.time_step_reset(); + + // Compute RHS backward differences + domain_->compute_rhs_bd_quantities(); + + // Update time dependent cross section based on the density + domain_->update_material_density(i); + + // Run the simulation for the current time step + run_single_simulation(); + + // Rename statepoint and tallies file for the current time step + rename_time_step_file(fmt::format("statepoint.{0}", settings::n_batches), + ".h5", simulation::current_timestep); + if (settings::output_tallies) { + rename_time_step_file("tallies", ".out", simulation::current_timestep); + } + + // Store final quantities for the current time step + domain_->store_time_step_quantities(); +} + void RandomRaySimulation::simulate() { // Random ray power iteration loop @@ -418,7 +634,7 @@ void RandomRaySimulation::simulate() // Reset total starting particle weight used for normalizing tallies simulation::total_weight = 1.0; - // Update source term (scattering + fission) + // Update source term (scattering + fission (+ delayed if kinetic)) domain_->update_all_neutron_sources(); // Reset scalar fluxes, iteration volume tallies, and region hit flags @@ -462,18 +678,33 @@ void RandomRaySimulation::simulate() if (settings::run_mode == RunMode::EIGENVALUE) { // Compute random ray k-eff - domain_->compute_k_eff(); + if (!settings::kinetic_simulation || + settings::kinetic_simulation && simulation::is_initial_condition) { + domain_->compute_k_eff(); + if (simulation::k_eff_correction) { + static_fission_rate_.push_back(domain_->fission_rate_); + static_k_eff_.push_back(domain_->k_eff_); + } + } else { + domain_->k_eff_ = static_k_eff_[simulation::current_batch - 1]; + domain_->fission_rate_ = + static_fission_rate_[simulation::current_batch - 1]; + } // Store random ray k-eff into OpenMC's native k-eff variable global_tally_tracklength = domain_->k_eff_; } + // Compute precursors if delayed neutrons are turned on + if (settings::kinetic_simulation && settings::create_delayed_neutrons) + domain_->compute_all_precursors(); + // Execute all tallying tasks, if this is an active batch if (simulation::current_batch > settings::n_inactive) { // Add this iteration's scalar flux estimate to final accumulated // estimate - domain_->accumulate_iteration_flux(); + domain_->accumulate_iteration_quantities(); // Use above mapping to contribute FSR flux data to appropriate // tallies @@ -482,11 +713,20 @@ void RandomRaySimulation::simulate() // Set phi_old = phi_new domain_->flux_swap(); + if (settings::kinetic_simulation && settings::create_delayed_neutrons) { + domain_->precursors_swap(); + } // Check for any obvious insabilities/nans/infs instability_check(n_hits, domain_->k_eff_, avg_miss_rate_); } // End MPI master work + // Store simulation metrics + RandomRay::avg_miss_rate_ = avg_miss_rate_ / settings::n_batches; + RandomRay::total_geometric_intersections_ = total_geometric_intersections_; + RandomRay::n_external_source_regions_ = domain_->n_external_source_regions_; + RandomRay::n_source_regions_ = domain_->n_source_regions(); + // Finalize the current batch finalize_generation(); finalize_batch(); @@ -499,9 +739,7 @@ void RandomRaySimulation::output_simulation_results() const { // Print random ray results if (mpi::master) { - print_results_random_ray(total_geometric_intersections_, - avg_miss_rate_ / settings::n_batches, negroups_, - domain_->n_source_regions(), domain_->n_external_source_regions_); + print_results_random_ray(); if (model::plots.size() > 0) { domain_->output_to_vtk(); } @@ -539,20 +777,22 @@ void RandomRaySimulation::instability_check( } // Print random ray simulation results -void RandomRaySimulation::print_results_random_ray( - uint64_t total_geometric_intersections, double avg_miss_rate, int negroups, - int64_t n_source_regions, int64_t n_external_source_regions) const +void RandomRaySimulation::print_results_random_ray() const { using namespace simulation; if (settings::verbosity >= 6) { - double total_integrations = total_geometric_intersections * negroups; + double total_integrations = + RandomRay::total_geometric_intersections_ * negroups_; double time_per_integration = simulation::time_transport.elapsed() / total_integrations; double misc_time = time_total.elapsed() - time_update_src.elapsed() - time_transport.elapsed() - time_tallies.elapsed() - time_bank_sendrecv.elapsed(); + if (settings::kinetic_simulation && !simulation::is_initial_condition) { + misc_time -= time_update_bd_vectors.elapsed(); + } header("Simulation Statistics", 4); fmt::print( " Total Iterations = {}\n", settings::n_batches); @@ -562,18 +802,24 @@ void RandomRaySimulation::print_results_random_ray( RandomRay::distance_inactive_); fmt::print(" Active Distance = {} cm\n", RandomRay::distance_active_); - fmt::print(" Source Regions (SRs) = {}\n", n_source_regions); - fmt::print( - " SRs Containing External Sources = {}\n", n_external_source_regions); + fmt::print(" Source Regions (SRs) = {}\n", + RandomRay::n_source_regions_); + fmt::print(" SRs Containing External Sources = {}\n", + RandomRay::n_external_source_regions_); fmt::print(" Total Geometric Intersections = {:.4e}\n", - static_cast(total_geometric_intersections)); + static_cast(RandomRay::total_geometric_intersections_)); fmt::print(" Avg per Iteration = {:.4e}\n", - static_cast(total_geometric_intersections) / settings::n_batches); + static_cast(RandomRay::total_geometric_intersections_) / + settings::n_batches); fmt::print(" Avg per Iteration per SR = {:.2f}\n", - static_cast(total_geometric_intersections) / - static_cast(settings::n_batches) / n_source_regions); - fmt::print(" Avg SR Miss Rate per Iteration = {:.4f}%\n", avg_miss_rate); - fmt::print(" Energy Groups = {}\n", negroups); + static_cast(RandomRay::total_geometric_intersections_) / + static_cast(settings::n_batches) / + RandomRay::n_source_regions_); + fmt::print(" Avg SR Miss Rate per Iteration = {:.4f}%\n", + RandomRay::avg_miss_rate_); + fmt::print(" Energy Groups = {}\n", negroups_); + if (settings::kinetic_simulation) + fmt::print(" Delay Groups = {}\n", ndgroups_); fmt::print( " Total Integrations = {:.4e}\n", total_integrations); fmt::print(" Avg per Iteration = {:.4e}\n", @@ -624,6 +870,15 @@ void RandomRaySimulation::print_results_random_ray( } else { fmt::print(" Transport XS Stabilization Used = NO\n"); } + if (settings::kinetic_simulation && !simulation::is_initial_condition) { + std::string time_method = + (RandomRay::time_method_ == RandomRayTimeMethod::ISOTROPIC) + ? "ISOTROPIC" + : "PROPAGATION"; + fmt::print(" Time Method = {}\n", time_method); + fmt::print( + " Backwards Difference Order = {}\n", RandomRay::bd_order_); + } header("Timing Statistics", 4); show_time("Total time for initialization", time_initialize.elapsed()); @@ -631,6 +886,11 @@ void RandomRaySimulation::print_results_random_ray( show_time("Total simulation time", time_total.elapsed()); show_time("Transport sweep only", time_transport.elapsed(), 1); show_time("Source update only", time_update_src.elapsed(), 1); + if (settings::kinetic_simulation && settings::create_delayed_neutrons) { + show_time( + "Precursor computation only", time_compute_precursors.elapsed(), 1); + misc_time -= time_compute_precursors.elapsed(); + } show_time("Tally conversion only", time_tallies.elapsed(), 1); show_time("MPI source reductions only", time_bank_sendrecv.elapsed(), 1); show_time("Other iteration routines", misc_time, 1); diff --git a/src/random_ray/source_region.cpp b/src/random_ray/source_region.cpp index 3b06f0ed09f..99143eab87e 100644 --- a/src/random_ray/source_region.cpp +++ b/src/random_ray/source_region.cpp @@ -1,4 +1,5 @@ #include "openmc/random_ray/source_region.h" +#include "openmc/random_ray/random_ray.h" #include "openmc/error.h" #include "openmc/message_passing.h" @@ -23,19 +24,31 @@ SourceRegionHandle::SourceRegionHandle(SourceRegion& sr) volume_task_(&sr.volume_task_), mesh_(&sr.mesh_), parent_sr_(&sr.parent_sr_), scalar_flux_old_(sr.scalar_flux_old_.data()), scalar_flux_new_(sr.scalar_flux_new_.data()), source_(sr.source_.data()), + source_final_(sr.source_.data()), external_source_(sr.external_source_.data()), scalar_flux_final_(sr.scalar_flux_final_.data()), source_gradients_(sr.source_gradients_.data()), flux_moments_old_(sr.flux_moments_old_.data()), flux_moments_new_(sr.flux_moments_new_.data()), flux_moments_t_(sr.flux_moments_t_.data()), - tally_task_(sr.tally_task_.data()) + tally_task_(sr.tally_task_.data()), T1_(sr.T1_.data()), + delayed_fission_source_(sr.delayed_fission_source_.data()), + precursors_old_(sr.precursors_old_.data()), + precursors_new_(sr.precursors_new_.data()), + precursors_final_(sr.precursors_final_.data()), + scalar_flux_bd_(sr.scalar_flux_bd_.data()), + source_bd_(sr.source_bd_.data()), precursors_bd_(sr.precursors_bd_.data()), + scalar_flux_rhs_bd_(sr.scalar_flux_rhs_bd_.data()), + source_rhs_bd_(sr.source_rhs_bd_.data()), + scalar_flux_rhs_bd_2_(sr.scalar_flux_rhs_bd_2_.data()), + precursors_rhs_bd_(sr.precursors_rhs_bd_.data()), + tally_delay_task_(sr.tally_delay_task_.data()) {} //============================================================================== // SourceRegion implementation //============================================================================== -SourceRegion::SourceRegion(int negroups, bool is_linear) +SourceRegion::SourceRegion(int negroups, int ndgroups, bool is_linear) { if (settings::run_mode == RunMode::EIGENVALUE) { // If in eigenvalue mode, set starting flux to guess of 1 @@ -58,6 +71,33 @@ SourceRegion::SourceRegion(int negroups, bool is_linear) flux_moments_new_.resize(negroups); flux_moments_t_.resize(negroups); } + if (settings::kinetic_simulation) { + scalar_flux_bd_.resize(negroups); + scalar_flux_rhs_bd_.resize(negroups); + + // Source Derivative Propogation arrays + if (RandomRay::time_method_ == RandomRayTimeMethod::PROPAGATION) { + source_final_.assign(negroups, 0.0); + + T1_.assign(negroups, 0.0); + + source_bd_.resize(negroups); + source_rhs_bd_.resize(negroups); + scalar_flux_rhs_bd_2_.resize(negroups); + } + + if (settings::create_delayed_neutrons) { + delayed_fission_source_.assign(ndgroups, 0.0); + precursors_old_.assign(ndgroups, 0.0); + precursors_new_.assign(ndgroups, 0.0); + precursors_final_.assign(ndgroups, 0.0); + + precursors_bd_.resize(ndgroups); + precursors_rhs_bd_.resize(ndgroups); + + tally_delay_task_.resize(ndgroups); + } + } } //============================================================================== @@ -114,6 +154,37 @@ void SourceRegionContainer::push_back(const SourceRegion& sr) // Tally tasks tally_task_.emplace_back(sr.tally_task_[g]); + + // Energy-dependent fields for kinetic simulations + if (settings::kinetic_simulation) { + scalar_flux_bd_.push_back(sr.scalar_flux_bd_[g]); + scalar_flux_rhs_bd_.push_back(sr.scalar_flux_rhs_bd_[g]); + + // Source Derivative Propogation arrays + if (RandomRay::time_method_ == RandomRayTimeMethod::PROPAGATION) { + source_final_.push_back(sr.source_final_[g]); + + T1_.push_back(sr.T1_[g]); + + source_bd_.push_back(sr.source_bd_[g]); + source_rhs_bd_.push_back(sr.source_rhs_bd_[g]); + scalar_flux_rhs_bd_2_.push_back(sr.scalar_flux_rhs_bd_2_[g]); + } + } + } + // Delay group-dependent fields for kinetic simulations + if (settings::kinetic_simulation && settings::create_delayed_neutrons) { + for (int dg = 0; dg < ndgroups_; dg++) { + delayed_fission_source_.push_back(sr.delayed_fission_source_[dg]); + precursors_old_.push_back(sr.precursors_old_[dg]); + precursors_new_.push_back(sr.precursors_new_[dg]); + precursors_final_.push_back(sr.precursors_final_[dg]); + tally_delay_task_.emplace_back(sr.tally_delay_task_[dg]); + + // Backward difference arrays + precursors_bd_.push_back(sr.precursors_bd_[dg]); + precursors_rhs_bd_.push_back(sr.precursors_rhs_bd_[dg]); + } } } @@ -161,6 +232,33 @@ void SourceRegionContainer::assign( tally_task_.clear(); volume_task_.clear(); + // Clear existing data for kinetic simulatons + if (settings::kinetic_simulation) { + scalar_flux_bd_.clear(); + scalar_flux_rhs_bd_.clear(); + + if (RandomRay::time_method_ == RandomRayTimeMethod::PROPAGATION) { + source_final_.clear(); + + T1_.clear(); + + source_bd_.clear(); + source_rhs_bd_.clear(); + scalar_flux_rhs_bd_2_.clear(); + } + + if (settings::create_delayed_neutrons) { + precursors_bd_.clear(); + precursors_rhs_bd_.clear(); + + delayed_fission_source_.clear(); + precursors_old_.clear(); + precursors_new_.clear(); + precursors_final_.clear(); + tally_delay_task_.clear(); + } + } + // Fill with copies of source_region for (int i = 0; i < n_source_regions; ++i) { push_back(source_region); @@ -218,6 +316,33 @@ SourceRegionHandle SourceRegionContainer::get_source_region_handle(int64_t sr) handle.flux_moments_t_ = &flux_moments_t(sr, 0); } + if (settings::kinetic_simulation) { + handle.scalar_flux_bd_ = &scalar_flux_bd(sr, 0); + handle.scalar_flux_rhs_bd_ = &scalar_flux_rhs_bd(sr, 0); + + if (RandomRay::time_method_ == RandomRayTimeMethod::PROPAGATION) { + handle.source_final_ = &source_final(sr, 0); + + handle.T1_ = &T1(sr, 0); + + handle.source_bd_ = &source_bd(sr, 0); + handle.source_rhs_bd_ = &source_rhs_bd(sr, 0); + handle.scalar_flux_rhs_bd_2_ = &scalar_flux_rhs_bd_2(sr, 0); + } + + if (settings::create_delayed_neutrons) { + handle.delayed_fission_source_ = &delayed_fission_source(sr, 0); + handle.precursors_old_ = &precursors_old(sr, 0); + handle.precursors_new_ = &precursors_new(sr, 0); + handle.precursors_final_ = &precursors_final(sr, 0); + + handle.precursors_bd_ = &precursors_bd(sr, 0); + handle.precursors_rhs_bd_ = &precursors_rhs_bd(sr, 0); + + handle.tally_delay_task_ = &tally_delay_task(sr, 0); + } + } + return handle; } @@ -256,6 +381,43 @@ void SourceRegionContainer::adjoint_reset() MomentArray {0.0, 0.0, 0.0}); std::fill(flux_moments_t_.begin(), flux_moments_t_.end(), MomentArray {0.0, 0.0, 0.0}); + // Reset arrays for kinetic adjoint simulations + if (settings::kinetic_simulation && !simulation::is_initial_condition) { + if (settings::create_delayed_neutrons) { + std::fill( + delayed_fission_source_.begin(), delayed_fission_source_.end(), 0.0); + std::fill(precursors_old_.begin(), precursors_old_.end(), 0.0); + std::fill(precursors_new_.begin(), precursors_new_.end(), 0.0); + std::fill(precursors_rhs_bd_.begin(), precursors_rhs_bd_.end(), 0.0); + } + + // BD Vectors + std::fill(scalar_flux_rhs_bd_.begin(), scalar_flux_rhs_bd_.end(), 0.0); + + if (RandomRay::time_method_ == RandomRayTimeMethod::PROPAGATION) { + std::fill(T1_.begin(), T1_.end(), 0.0); + + std::fill(source_rhs_bd_.begin(), source_rhs_bd_.end(), 0.0); + std::fill( + scalar_flux_rhs_bd_2_.begin(), scalar_flux_rhs_bd_2_.end(), 0.0); + } + } +} + +//----------------------------------------------------------------------------- +// Methods for kinetic simulations + +void SourceRegionContainer::precursors_swap() +{ + precursors_old_.swap(precursors_new_); +} + +void SourceRegionContainer::time_step_reset() +{ + std::fill(scalar_flux_final_.begin(), scalar_flux_final_.end(), 0.0); + std::fill(precursors_final_.begin(), precursors_final_.end(), 0.0); + if (RandomRay::time_method_ == RandomRayTimeMethod::PROPAGATION) + std::fill(source_final_.begin(), source_final_.end(), 0.0); } } // namespace openmc diff --git a/src/reaction.cpp b/src/reaction.cpp index d96790c6d43..cb931e5677c 100644 --- a/src/reaction.cpp +++ b/src/reaction.cpp @@ -205,6 +205,7 @@ std::unordered_map REACTION_NAME_MAP { {SCORE_IFP_TIME_NUM, "ifp-time-numerator"}, {SCORE_IFP_BETA_NUM, "ifp-beta-numerator"}, {SCORE_IFP_DENOM, "ifp-denominator"}, + {SCORE_PRECURSORS, "precursors"}, // Normal ENDF-based reactions {TOTAL_XS, "(n,total)"}, {ELASTIC, "(n,elastic)"}, diff --git a/src/settings.cpp b/src/settings.cpp index 5b472468fc4..c3bfad37532 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -56,6 +56,7 @@ bool delayed_photon_scaling {true}; bool entropy_on {false}; bool event_based {false}; bool ifp_on {false}; +bool kinetic_simulation {false}; bool legendre_to_tabular {true}; bool material_cell_offsets {true}; bool output_summary {true}; @@ -149,6 +150,10 @@ int verbosity {-1}; double weight_cutoff {0.25}; double weight_survive {1.0}; +// Timestep variables for kinetic simulation +int n_timesteps; +double dt; + } // namespace settings //============================================================================== @@ -254,6 +259,52 @@ void get_run_parameters(pugi::xml_node node_base) } } + // Kinetic variables + if (check_for_node(node_base, "kinetic_simulation")) { + kinetic_simulation = get_node_value_bool(node_base, "kinetic_simulation"); + if (solver_type != SolverType::RANDOM_RAY) { + fatal_error("Unsupported solver selected for kinetic simulation. Kinetic " + "simulations currently only support the random ray solver."); + } + if (run_mode != RunMode::EIGENVALUE) { + fatal_error( + "Unsupported run mode selected for kinetic simulation. Kinetic " + "simulations currently only support run mode based on an eigenvalue " + "simulation establishing an initial condition."); + } + } + + // Get timestep parameters for kinetic simulations + if (kinetic_simulation) { + xml_node ts_node = node_base.child("timestep_parameters"); + if (check_for_node(ts_node, "n_timesteps")) { + n_timesteps = std::stoi(get_node_value(ts_node, "n_timesteps")); + } else { + fatal_error("Specify number of timesteps in settings XML"); + } + if (check_for_node(ts_node, "timestep_units")) { + std::string units = get_node_value(ts_node, "timestep_units"); + if (check_for_node(ts_node, "dt")) { + dt = std::stod(get_node_value(ts_node, "dt")); + double factor_to_seconds; + if (units == "ms") { + factor_to_seconds = 1e-3; + } else if (units == "s") { + factor_to_seconds = 1.0; + } else if (units == "min") { + factor_to_seconds = 1 / 60; + } else { + fatal_error("Invalid timestep unit, " + units); + } + dt *= factor_to_seconds; + } else { + fatal_error("Specify dt in settings XML"); + } + } else { + fatal_error("Specify timestep units in settings XML"); + } + } + // Random ray variables if (solver_type == SolverType::RANDOM_RAY) { xml_node random_ray_node = node_base.child("random_ray"); @@ -305,8 +356,16 @@ void get_run_parameters(pugi::xml_node node_base) RandomRay::source_shape_ = RandomRaySourceShape::FLAT; } else if (temp_str == "linear") { RandomRay::source_shape_ = RandomRaySourceShape::LINEAR; + if (settings::kinetic_simulation) { + fatal_error( + "linear source shapes unimplemented for kinetic simulations."); + } } else if (temp_str == "linear_xy") { RandomRay::source_shape_ = RandomRaySourceShape::LINEAR_XY; + if (settings::kinetic_simulation) { + fatal_error( + "linear_xy source shapes unimplemented for kinetic simulations."); + } } else { fatal_error("Unrecognized source shape: " + temp_str); } @@ -363,6 +422,28 @@ void get_run_parameters(pugi::xml_node node_base) "between 0 and 1"); } } + if (kinetic_simulation) { + if (check_for_node(random_ray_node, "bd_order")) { + static int n = std::stod(get_node_value(random_ray_node, "bd_order")); + if (n < 1 || n > 6) { + fatal_error("Specified BD order of " + std::to_string(n) + + ". BD order must be between 1 and 6"); + } else { + RandomRay::bd_order_ = n; + } + } + if (check_for_node(random_ray_node, "time_derivative_method")) { + std::string temp_str = + get_node_value(random_ray_node, "time_derivative_method", true, true); + if (temp_str == "isotropic") { + RandomRay::time_method_ = RandomRayTimeMethod::ISOTROPIC; + } else if (temp_str == "propagation") { + RandomRay::time_method_ = RandomRayTimeMethod::PROPAGATION; + } else { + fatal_error("Unrecognized time derivative method: " + temp_str); + } + } + } } } diff --git a/src/simulation.cpp b/src/simulation.cpp index b536ae5881f..7fd325593d0 100644 --- a/src/simulation.cpp +++ b/src/simulation.cpp @@ -139,6 +139,19 @@ int openmc_simulation_init() // Display header if (mpi::master) { + if (settings::kinetic_simulation) { + if (simulation::is_initial_condition) { + if (simulation::k_eff_correction) + header("KINETIC SIMULATION INITIAL CONDITION (K-EFF CORRECTION)", 3); + else + header("KINETIC SIMULATION INITIAL CONDITION", 3); + } else { + std::string message = fmt::format( + "KINETIC SIMULATION TIME STEP {0}", simulation::current_timestep); + const char* msg = message.c_str(); + header(msg, 3); + } + } if (settings::run_mode == RunMode::FIXED_SOURCE) { if (settings::solver_type == SolverType::MONTE_CARLO) { header("FIXED SOURCE TRANSPORT SIMULATION", 3); @@ -323,6 +336,11 @@ const RegularMesh* ufs_mesh {nullptr}; vector k_generation; vector work_index; +bool is_initial_condition {true}; +int current_timestep; +double current_time; +bool k_eff_correction {false}; + } // namespace simulation //============================================================================== diff --git a/src/state_point.cpp b/src/state_point.cpp index 8ccebeb05a7..294cd45c7f6 100644 --- a/src/state_point.cpp +++ b/src/state_point.cpp @@ -22,6 +22,7 @@ #include "openmc/mgxs_interface.h" #include "openmc/nuclide.h" #include "openmc/output.h" +#include "openmc/random_ray/random_ray_simulation.h" #include "openmc/settings.h" #include "openmc/simulation.h" #include "openmc/tallies/derivative.h" @@ -96,6 +97,10 @@ extern "C" int openmc_statepoint_write(const char* filename, bool* write_source) // Write run information write_dataset(file_id, "energy_mode", settings::run_CE ? "continuous-energy" : "multi-group"); + if (!settings::run_CE) { + write_dataset(file_id, "n_energy_groups", data::mg.num_energy_groups_); + write_dataset(file_id, "n_delay_groups", data::mg.num_delayed_groups_); + } switch (settings::run_mode) { case RunMode::FIXED_SOURCE: write_dataset(file_id, "run_mode", "fixed source"); @@ -106,10 +111,32 @@ extern "C" int openmc_statepoint_write(const char* filename, bool* write_source) default: break; } + switch (settings::solver_type) { + case SolverType::MONTE_CARLO: + write_dataset(file_id, "solver_type", "monte carlo"); + break; + case SolverType::RANDOM_RAY: + write_dataset(file_id, "solver_type", "random ray"); + write_random_ray_hdf5(file_id); + break; + default: + break; + } write_attribute(file_id, "photon_transport", settings::photon_transport); write_dataset(file_id, "n_particles", settings::n_particles); write_dataset(file_id, "n_batches", settings::n_batches); + write_dataset(file_id, "kinetic_simulation", + settings::kinetic_simulation ? true : false); + if (settings::kinetic_simulation) { + hid_t timestep_group = create_group(file_id, "timestep_data"); + write_dataset(timestep_group, "dt", settings::dt); + write_dataset( + timestep_group, "current_timestep", simulation::current_timestep); + write_dataset(timestep_group, "current_time", simulation::current_time); + close_group(timestep_group); + } + // Write out current batch number write_dataset(file_id, "current_batch", simulation::current_batch); @@ -315,6 +342,13 @@ extern "C" int openmc_statepoint_write(const char* filename, bool* write_source) write_dataset(runtime_group, "inactive batches", time_inactive.elapsed()); } write_dataset(runtime_group, "active batches", time_active.elapsed()); + if (settings::solver_type == SolverType::RANDOM_RAY) { + write_dataset(runtime_group, "source_update", time_update_src.elapsed()); + if (settings::kinetic_simulation) { + write_dataset( + runtime_group, "precursor_update", time_compute_precursors.elapsed()); + } + } if (settings::run_mode == RunMode::EIGENVALUE) { write_dataset( runtime_group, "synchronizing fission bank", time_bank.elapsed()); diff --git a/src/tallies/tally.cpp b/src/tallies/tally.cpp index 6eef1da9cfd..6d798bc9385 100644 --- a/src/tallies/tally.cpp +++ b/src/tallies/tally.cpp @@ -564,7 +564,7 @@ void Tally::set_scores(const vector& scores) // score. if (delayedgroup_filter_ != C_NONE) { if (score_str != "delayed-nu-fission" && score_str != "decay-rate" && - score_str != "ifp-beta-numerator") + score_str != "ifp-beta-numerator" && score_str != "precursors") fatal_error("Cannot tally " + score_str + "with a delayedgroup filter"); } @@ -657,6 +657,20 @@ void Tally::set_scores(const vector& scores) case SCORE_IFP_DENOM: estimator_ = TallyEstimator::COLLISION; break; + + case SCORE_PRECURSORS: + if (!settings::kinetic_simulation) + fatal_error("Can only tally precursors in kinetic simulations."); + if (!nuclides_.empty()) + if (!(nuclides_.size() == 1 && nuclides_[0] == -1)) + fatal_error("Cannot tally precursors for an individual nuclide."); + if (energyout_present) + fatal_error("Cannot tally precursors with an outgoing energy filter."); + // TODO: make this more robust: allow for tallying + // in eigenvalue and fixed source calculations by detecting + // delayed fission, delayed chi, and lambda cross sections (mg and ce) + // Also enable support for monte carlo solves + break; } scores_.push_back(score); diff --git a/src/timer.cpp b/src/timer.cpp index 6d692d4fbf6..15bca0de48c 100644 --- a/src/timer.cpp +++ b/src/timer.cpp @@ -28,6 +28,10 @@ Timer time_event_collision; Timer time_event_death; Timer time_update_src; +// Timers for kinetic simulations +Timer time_update_bd_vectors; +Timer time_compute_precursors; + } // namespace simulation //============================================================================== @@ -87,6 +91,9 @@ void reset_timers() simulation::time_event_collision.reset(); simulation::time_event_death.reset(); simulation::time_update_src.reset(); + + simulation::time_update_bd_vectors.reset(); + simulation::time_compute_precursors.reset(); } } // namespace openmc diff --git a/src/xsdata.cpp b/src/xsdata.cpp index 1929f51e6fa..5ce320b6400 100644 --- a/src/xsdata.cpp +++ b/src/xsdata.cpp @@ -56,8 +56,9 @@ XsData::XsData(bool fissionable, AngleDistributionType scatter_format, // allocate delayed_nu_fission; [temperature][angle][delay group][in group] delayed_nu_fission = xt::zeros(shape); - // chi_prompt; [temperature][angle][in group][out group] + // chi and chi_prompt; [temperature][angle][in group][out group] shape = {n_ang, n_g_, n_g_}; + chi = xt::zeros(shape); chi_prompt = xt::zeros(shape); // chi_delayed; [temperature][angle][delay group][in group][out group] @@ -133,8 +134,13 @@ void XsData::fission_vector_beta_from_hdf5( // Normalize chi by summing over the outgoing groups for each incoming angle temp_chi /= xt::view(xt::sum(temp_chi, {1}), xt::all(), xt::newaxis()); + // Store chi in chi + chi = xt::view(temp_chi, xt::all(), xt::newaxis(), xt::all()); + // Now every incoming group in prompt_chi and delayed_chi is the normalized // chi we just made + // TODO: This is incorrect!! This makes chi_prompt and chi_delayed identical + // to chi. chi_prompt = xt::view(temp_chi, xt::all(), xt::newaxis(), xt::all()); chi_delayed = xt::view(temp_chi, xt::all(), xt::newaxis(), xt::newaxis(), xt::all()); @@ -176,25 +182,37 @@ void XsData::fission_vector_beta_from_hdf5( void 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 + // If chi is included in the dataset, we should store it! + if (object_exists(xsdata_grp, "chi")) { + 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 + temp_chi /= xt::view(xt::sum(temp_chi, {1}), xt::all(), xt::newaxis()); + // Now every incoming group in self.chi is the normalized chi we just made + chi = xt::view(temp_chi, xt::all(), xt::newaxis(), xt::all()); + } + // Data is provided separately as prompt + delayed nu-fission and chi // Get chi-prompt 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 + // Normalize chi-prompt 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.); read_nd_vector(xsdata_grp, "chi-delayed", temp_chi_d, true); - // Normalize chi by summing over the outgoing groups for each incoming angle + // Normalize chi-delayed by summing over the outgoing groups for each incoming + // angle temp_chi_d /= xt::view(xt::sum(temp_chi_d, {2}), xt::all(), xt::all(), xt::newaxis()); // Now assign the prompt and delayed chis by replicating for each incoming // group + // chi_prompt = xt::view(temp_chi_p, xt::all(), xt::newaxis(), xt::all()); chi_delayed = xt::view(temp_chi_d, xt::all(), xt::all(), xt::newaxis(), xt::all()); @@ -204,6 +222,7 @@ void XsData::fission_vector_no_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang) read_nd_vector(xsdata_grp, "delayed-nu-fission", delayed_nu_fission, true); } +// TODO: Add machinery to read chi void 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. @@ -217,6 +236,7 @@ void XsData::fission_vector_no_delayed_from_hdf5(hid_t xsdata_grp, size_t n_ang) temp_chi /= xt::view(xt::sum(temp_chi, {1}), xt::all(), xt::newaxis()); // Now every incoming group in self.chi is the normalized chi we just made + chi = xt::view(temp_chi, xt::all(), xt::newaxis(), xt::all()); chi_prompt = xt::view(temp_chi, xt::all(), xt::newaxis(), xt::all()); // Get nu-fission directly @@ -225,6 +245,7 @@ void XsData::fission_vector_no_delayed_from_hdf5(hid_t xsdata_grp, size_t n_ang) //============================================================================== +// TODO: Add machinery to read chi void XsData::fission_matrix_beta_from_hdf5( hid_t xsdata_grp, size_t n_ang, bool is_isotropic) { @@ -303,6 +324,7 @@ void XsData::fission_matrix_beta_from_hdf5( xt::sum(chi_delayed, {3}), xt::all(), xt::all(), xt::all(), xt::newaxis()); } +// TODO: Add machinery to read chi void 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 @@ -326,12 +348,13 @@ void XsData::fission_matrix_no_beta_from_hdf5(hid_t xsdata_grp, size_t n_ang) // delayed_nu_fission is the sum over outgoing groups delayed_nu_fission = xt::sum(temp_matrix_d, {3}); - // chi_prompt is this matrix but normalized over outgoing groups, which we - // have already stored in prompt_nu_fission + // chi_delayed is this matrix but normalized over outgoing groups, which we + // have already stored in delayed_nu_fission chi_delayed = temp_matrix_d / xt::view(delayed_nu_fission, xt::all(), xt::all(), xt::all(), xt::newaxis()); } +// TODO: Add machinery to read chi void 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. @@ -525,6 +548,10 @@ void XsData::combine( kappa_fission += scalar * that->kappa_fission; fission += scalar * that->fission; delayed_nu_fission += scalar * that->delayed_nu_fission; + // This may throw an error in some cases. Need a check for if + // chi exists! + chi += scalar * that->chi; + chi_prompt += scalar * xt::view(xt::sum(that->prompt_nu_fission, {1}), xt::all(), xt::newaxis(), xt::newaxis()) * @@ -537,8 +564,9 @@ void XsData::combine( decay_rate += scalar * that->decay_rate; } - // Ensure the chi_prompt and chi_delayed are normalized to 1 for each + // Ensure chi, chi_prompt, and chi_delayed are normalized to 1 for each // azimuthal angle and delayed group (for chi_delayed) + chi /= xt::view(xt::sum(chi, {2}), xt::all(), xt::all(), xt::newaxis()); chi_prompt /= xt::view(xt::sum(chi_prompt, {2}), xt::all(), xt::all(), xt::newaxis()); chi_delayed /= xt::view( diff --git a/tests/cpp_unit_tests/CMakeLists.txt b/tests/cpp_unit_tests/CMakeLists.txt index 5f87db9eac2..661b30f6cb6 100644 --- a/tests/cpp_unit_tests/CMakeLists.txt +++ b/tests/cpp_unit_tests/CMakeLists.txt @@ -1,4 +1,5 @@ set(TEST_NAMES + test_bd_utilities test_distribution test_file_utils test_tally diff --git a/tests/cpp_unit_tests/test_bd_utilities.cpp b/tests/cpp_unit_tests/test_bd_utilities.cpp new file mode 100644 index 00000000000..4d51fbd2068 --- /dev/null +++ b/tests/cpp_unit_tests/test_bd_utilities.cpp @@ -0,0 +1,53 @@ +#include "openmc/random_ray/bd_utilities.h" +#include "openmc/random_ray/random_ray_simulation.h" +#include "openmc/vector.h" +#include +#include + +#include +#include +#include + +using namespace openmc; + +TEST_CASE("Test rhs_backwards_difference") +{ + vector> ref_rhs_bd_first_order {{-68.59, -36.1}, + {-108.02, -56.0}, {-134.66666666666663, -69.33333333333331}, + {-154.66666666666666, -79.33333333333331}, + {-170.66666666666666, -87.33333333333331}, {-184.0, -94.0}}; + + vector> ref_rhs_bd_second_order { + {-788.5999999999999, -397.9999999999999}, {-1588.0, -797.9999999999999}, + {-2321.3333333333344, -1164.6666666666667}, {-2988.0, -1497.9999999999989}, + {-3596.88888888889, -1802.4444444444416}, + {-4156.888888888892, -2082.444444444443}}; + + int vector_size = 2; + double dt = 0.1; + // Two functions t^2 and t^3 across x = 2, 1.9, 1.8, 1.7, 1.6, 1.5, 1.4, 1.3 + vector> test_bd_vector { + {6.859, 5.832, 4.913, 4.096, 3.375, 2.744, 2.197}, + {3.61, 3.24, 2.89, 2.56, 2.25, 1.96, 1.69}}; + vector test_rhs_bd {0.0, 0.0}; + for (int i = 0; i < 6; i++) { + int o = i + 1; + double d0 = rhs_backwards_difference(test_bd_vector[0], o, dt); + double d1 = rhs_backwards_difference(test_bd_vector[1], o, dt); + test_rhs_bd[0] = d0; + test_rhs_bd[1] = d1; + REQUIRE_THAT( + test_rhs_bd, Catch::Matchers::Approx(ref_rhs_bd_first_order[i])); + } + for (int i = 0; i < 6; i++) { + int o = i + 1; + double rhs_d0 = + rhs_backwards_difference(test_bd_vector[0], o, dt, 2); + double rhs_d1 = + rhs_backwards_difference(test_bd_vector[1], o, dt, 2); + test_rhs_bd[0] = rhs_d0; + test_rhs_bd[1] = rhs_d1; + REQUIRE_THAT( + test_rhs_bd, Catch::Matchers::Approx(ref_rhs_bd_second_order[i])); + } +} diff --git a/tests/regression_tests/random_ray_auto_convert/test.py b/tests/regression_tests/random_ray_auto_convert/test.py index 99a931dce86..ea25ffbd2da 100644 --- a/tests/regression_tests/random_ray_auto_convert/test.py +++ b/tests/regression_tests/random_ray_auto_convert/test.py @@ -27,7 +27,7 @@ def test_random_ray_auto_convert(method): # Convert to a multi-group model model.convert_to_multigroup( - method=method, groups='CASMO-2', nparticles=100, + method=method, energy_groups='CASMO-2', nparticles=100, overwrite_mgxs_library=False, mgxs_path="mgxs.h5" ) diff --git a/tests/regression_tests/random_ray_auto_convert_kinetic/__init__.py b/tests/regression_tests/random_ray_auto_convert_kinetic/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/regression_tests/random_ray_auto_convert_kinetic/infinite_medium/isotropic/inputs_true.dat b/tests/regression_tests/random_ray_auto_convert_kinetic/infinite_medium/isotropic/inputs_true.dat new file mode 100644 index 00000000000..e048a7d4dc1 --- /dev/null +++ b/tests/regression_tests/random_ray_auto_convert_kinetic/infinite_medium/isotropic/inputs_true.dat @@ -0,0 +1,70 @@ + + + + mgxs.h5 + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 100 + 10 + 5 + true + +
0.01
+ s + 5 +
+ + + -0.63 -0.63 -1 0.63 0.63 1 + + + true + + + multi-group + + + + -0.63 -0.63 -1.0 0.63 0.63 1.0 + + + 30.0 + 150.0 + + + + + + isotropic + + + 8 8 + -0.63 -0.63 + 0.63 0.63 + +
+
diff --git a/tests/regression_tests/random_ray_auto_convert_kinetic/infinite_medium/isotropic/results_true_0.dat b/tests/regression_tests/random_ray_auto_convert_kinetic/infinite_medium/isotropic/results_true_0.dat new file mode 100644 index 00000000000..3c8808a0c82 --- /dev/null +++ b/tests/regression_tests/random_ray_auto_convert_kinetic/infinite_medium/isotropic/results_true_0.dat @@ -0,0 +1,2 @@ +k-combined: +5.824689E-01 1.309494E-02 diff --git a/tests/regression_tests/random_ray_auto_convert_kinetic/infinite_medium/isotropic/results_true_1.dat b/tests/regression_tests/random_ray_auto_convert_kinetic/infinite_medium/isotropic/results_true_1.dat new file mode 100644 index 00000000000..3c8808a0c82 --- /dev/null +++ b/tests/regression_tests/random_ray_auto_convert_kinetic/infinite_medium/isotropic/results_true_1.dat @@ -0,0 +1,2 @@ +k-combined: +5.824689E-01 1.309494E-02 diff --git a/tests/regression_tests/random_ray_auto_convert_kinetic/infinite_medium/isotropic/results_true_2.dat b/tests/regression_tests/random_ray_auto_convert_kinetic/infinite_medium/isotropic/results_true_2.dat new file mode 100644 index 00000000000..3c8808a0c82 --- /dev/null +++ b/tests/regression_tests/random_ray_auto_convert_kinetic/infinite_medium/isotropic/results_true_2.dat @@ -0,0 +1,2 @@ +k-combined: +5.824689E-01 1.309494E-02 diff --git a/tests/regression_tests/random_ray_auto_convert_kinetic/infinite_medium/isotropic/results_true_3.dat b/tests/regression_tests/random_ray_auto_convert_kinetic/infinite_medium/isotropic/results_true_3.dat new file mode 100644 index 00000000000..3c8808a0c82 --- /dev/null +++ b/tests/regression_tests/random_ray_auto_convert_kinetic/infinite_medium/isotropic/results_true_3.dat @@ -0,0 +1,2 @@ +k-combined: +5.824689E-01 1.309494E-02 diff --git a/tests/regression_tests/random_ray_auto_convert_kinetic/infinite_medium/isotropic/results_true_4.dat b/tests/regression_tests/random_ray_auto_convert_kinetic/infinite_medium/isotropic/results_true_4.dat new file mode 100644 index 00000000000..3c8808a0c82 --- /dev/null +++ b/tests/regression_tests/random_ray_auto_convert_kinetic/infinite_medium/isotropic/results_true_4.dat @@ -0,0 +1,2 @@ +k-combined: +5.824689E-01 1.309494E-02 diff --git a/tests/regression_tests/random_ray_auto_convert_kinetic/infinite_medium/isotropic/results_true_5.dat b/tests/regression_tests/random_ray_auto_convert_kinetic/infinite_medium/isotropic/results_true_5.dat new file mode 100644 index 00000000000..3c8808a0c82 --- /dev/null +++ b/tests/regression_tests/random_ray_auto_convert_kinetic/infinite_medium/isotropic/results_true_5.dat @@ -0,0 +1,2 @@ +k-combined: +5.824689E-01 1.309494E-02 diff --git a/tests/regression_tests/random_ray_auto_convert_kinetic/infinite_medium/propagation/inputs_true.dat b/tests/regression_tests/random_ray_auto_convert_kinetic/infinite_medium/propagation/inputs_true.dat new file mode 100644 index 00000000000..092e3952f5e --- /dev/null +++ b/tests/regression_tests/random_ray_auto_convert_kinetic/infinite_medium/propagation/inputs_true.dat @@ -0,0 +1,70 @@ + + + + mgxs.h5 + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 100 + 10 + 5 + true + +
0.01
+ s + 5 +
+ + + -0.63 -0.63 -1 0.63 0.63 1 + + + true + + + multi-group + + + + -0.63 -0.63 -1.0 0.63 0.63 1.0 + + + 30.0 + 150.0 + + + + + + propagation + + + 8 8 + -0.63 -0.63 + 0.63 0.63 + +
+
diff --git a/tests/regression_tests/random_ray_auto_convert_kinetic/infinite_medium/propagation/results_true_0.dat b/tests/regression_tests/random_ray_auto_convert_kinetic/infinite_medium/propagation/results_true_0.dat new file mode 100644 index 00000000000..3c8808a0c82 --- /dev/null +++ b/tests/regression_tests/random_ray_auto_convert_kinetic/infinite_medium/propagation/results_true_0.dat @@ -0,0 +1,2 @@ +k-combined: +5.824689E-01 1.309494E-02 diff --git a/tests/regression_tests/random_ray_auto_convert_kinetic/infinite_medium/propagation/results_true_1.dat b/tests/regression_tests/random_ray_auto_convert_kinetic/infinite_medium/propagation/results_true_1.dat new file mode 100644 index 00000000000..3c8808a0c82 --- /dev/null +++ b/tests/regression_tests/random_ray_auto_convert_kinetic/infinite_medium/propagation/results_true_1.dat @@ -0,0 +1,2 @@ +k-combined: +5.824689E-01 1.309494E-02 diff --git a/tests/regression_tests/random_ray_auto_convert_kinetic/infinite_medium/propagation/results_true_2.dat b/tests/regression_tests/random_ray_auto_convert_kinetic/infinite_medium/propagation/results_true_2.dat new file mode 100644 index 00000000000..3c8808a0c82 --- /dev/null +++ b/tests/regression_tests/random_ray_auto_convert_kinetic/infinite_medium/propagation/results_true_2.dat @@ -0,0 +1,2 @@ +k-combined: +5.824689E-01 1.309494E-02 diff --git a/tests/regression_tests/random_ray_auto_convert_kinetic/infinite_medium/propagation/results_true_3.dat b/tests/regression_tests/random_ray_auto_convert_kinetic/infinite_medium/propagation/results_true_3.dat new file mode 100644 index 00000000000..3c8808a0c82 --- /dev/null +++ b/tests/regression_tests/random_ray_auto_convert_kinetic/infinite_medium/propagation/results_true_3.dat @@ -0,0 +1,2 @@ +k-combined: +5.824689E-01 1.309494E-02 diff --git a/tests/regression_tests/random_ray_auto_convert_kinetic/infinite_medium/propagation/results_true_4.dat b/tests/regression_tests/random_ray_auto_convert_kinetic/infinite_medium/propagation/results_true_4.dat new file mode 100644 index 00000000000..3c8808a0c82 --- /dev/null +++ b/tests/regression_tests/random_ray_auto_convert_kinetic/infinite_medium/propagation/results_true_4.dat @@ -0,0 +1,2 @@ +k-combined: +5.824689E-01 1.309494E-02 diff --git a/tests/regression_tests/random_ray_auto_convert_kinetic/infinite_medium/propagation/results_true_5.dat b/tests/regression_tests/random_ray_auto_convert_kinetic/infinite_medium/propagation/results_true_5.dat new file mode 100644 index 00000000000..3c8808a0c82 --- /dev/null +++ b/tests/regression_tests/random_ray_auto_convert_kinetic/infinite_medium/propagation/results_true_5.dat @@ -0,0 +1,2 @@ +k-combined: +5.824689E-01 1.309494E-02 diff --git a/tests/regression_tests/random_ray_auto_convert_kinetic/material_wise/isotropic/inputs_true.dat b/tests/regression_tests/random_ray_auto_convert_kinetic/material_wise/isotropic/inputs_true.dat new file mode 100644 index 00000000000..e048a7d4dc1 --- /dev/null +++ b/tests/regression_tests/random_ray_auto_convert_kinetic/material_wise/isotropic/inputs_true.dat @@ -0,0 +1,70 @@ + + + + mgxs.h5 + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 100 + 10 + 5 + true + +
0.01
+ s + 5 +
+ + + -0.63 -0.63 -1 0.63 0.63 1 + + + true + + + multi-group + + + + -0.63 -0.63 -1.0 0.63 0.63 1.0 + + + 30.0 + 150.0 + + + + + + isotropic + + + 8 8 + -0.63 -0.63 + 0.63 0.63 + +
+
diff --git a/tests/regression_tests/random_ray_auto_convert_kinetic/material_wise/isotropic/results_true_0.dat b/tests/regression_tests/random_ray_auto_convert_kinetic/material_wise/isotropic/results_true_0.dat new file mode 100644 index 00000000000..df7374c145b --- /dev/null +++ b/tests/regression_tests/random_ray_auto_convert_kinetic/material_wise/isotropic/results_true_0.dat @@ -0,0 +1,2 @@ +k-combined: +7.247257E-01 3.323600E-03 diff --git a/tests/regression_tests/random_ray_auto_convert_kinetic/material_wise/isotropic/results_true_1.dat b/tests/regression_tests/random_ray_auto_convert_kinetic/material_wise/isotropic/results_true_1.dat new file mode 100644 index 00000000000..df7374c145b --- /dev/null +++ b/tests/regression_tests/random_ray_auto_convert_kinetic/material_wise/isotropic/results_true_1.dat @@ -0,0 +1,2 @@ +k-combined: +7.247257E-01 3.323600E-03 diff --git a/tests/regression_tests/random_ray_auto_convert_kinetic/material_wise/isotropic/results_true_2.dat b/tests/regression_tests/random_ray_auto_convert_kinetic/material_wise/isotropic/results_true_2.dat new file mode 100644 index 00000000000..df7374c145b --- /dev/null +++ b/tests/regression_tests/random_ray_auto_convert_kinetic/material_wise/isotropic/results_true_2.dat @@ -0,0 +1,2 @@ +k-combined: +7.247257E-01 3.323600E-03 diff --git a/tests/regression_tests/random_ray_auto_convert_kinetic/material_wise/isotropic/results_true_3.dat b/tests/regression_tests/random_ray_auto_convert_kinetic/material_wise/isotropic/results_true_3.dat new file mode 100644 index 00000000000..df7374c145b --- /dev/null +++ b/tests/regression_tests/random_ray_auto_convert_kinetic/material_wise/isotropic/results_true_3.dat @@ -0,0 +1,2 @@ +k-combined: +7.247257E-01 3.323600E-03 diff --git a/tests/regression_tests/random_ray_auto_convert_kinetic/material_wise/isotropic/results_true_4.dat b/tests/regression_tests/random_ray_auto_convert_kinetic/material_wise/isotropic/results_true_4.dat new file mode 100644 index 00000000000..df7374c145b --- /dev/null +++ b/tests/regression_tests/random_ray_auto_convert_kinetic/material_wise/isotropic/results_true_4.dat @@ -0,0 +1,2 @@ +k-combined: +7.247257E-01 3.323600E-03 diff --git a/tests/regression_tests/random_ray_auto_convert_kinetic/material_wise/isotropic/results_true_5.dat b/tests/regression_tests/random_ray_auto_convert_kinetic/material_wise/isotropic/results_true_5.dat new file mode 100644 index 00000000000..df7374c145b --- /dev/null +++ b/tests/regression_tests/random_ray_auto_convert_kinetic/material_wise/isotropic/results_true_5.dat @@ -0,0 +1,2 @@ +k-combined: +7.247257E-01 3.323600E-03 diff --git a/tests/regression_tests/random_ray_auto_convert_kinetic/material_wise/propagation/inputs_true.dat b/tests/regression_tests/random_ray_auto_convert_kinetic/material_wise/propagation/inputs_true.dat new file mode 100644 index 00000000000..092e3952f5e --- /dev/null +++ b/tests/regression_tests/random_ray_auto_convert_kinetic/material_wise/propagation/inputs_true.dat @@ -0,0 +1,70 @@ + + + + mgxs.h5 + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 100 + 10 + 5 + true + +
0.01
+ s + 5 +
+ + + -0.63 -0.63 -1 0.63 0.63 1 + + + true + + + multi-group + + + + -0.63 -0.63 -1.0 0.63 0.63 1.0 + + + 30.0 + 150.0 + + + + + + propagation + + + 8 8 + -0.63 -0.63 + 0.63 0.63 + +
+
diff --git a/tests/regression_tests/random_ray_auto_convert_kinetic/material_wise/propagation/results_true_0.dat b/tests/regression_tests/random_ray_auto_convert_kinetic/material_wise/propagation/results_true_0.dat new file mode 100644 index 00000000000..df7374c145b --- /dev/null +++ b/tests/regression_tests/random_ray_auto_convert_kinetic/material_wise/propagation/results_true_0.dat @@ -0,0 +1,2 @@ +k-combined: +7.247257E-01 3.323600E-03 diff --git a/tests/regression_tests/random_ray_auto_convert_kinetic/material_wise/propagation/results_true_1.dat b/tests/regression_tests/random_ray_auto_convert_kinetic/material_wise/propagation/results_true_1.dat new file mode 100644 index 00000000000..df7374c145b --- /dev/null +++ b/tests/regression_tests/random_ray_auto_convert_kinetic/material_wise/propagation/results_true_1.dat @@ -0,0 +1,2 @@ +k-combined: +7.247257E-01 3.323600E-03 diff --git a/tests/regression_tests/random_ray_auto_convert_kinetic/material_wise/propagation/results_true_2.dat b/tests/regression_tests/random_ray_auto_convert_kinetic/material_wise/propagation/results_true_2.dat new file mode 100644 index 00000000000..df7374c145b --- /dev/null +++ b/tests/regression_tests/random_ray_auto_convert_kinetic/material_wise/propagation/results_true_2.dat @@ -0,0 +1,2 @@ +k-combined: +7.247257E-01 3.323600E-03 diff --git a/tests/regression_tests/random_ray_auto_convert_kinetic/material_wise/propagation/results_true_3.dat b/tests/regression_tests/random_ray_auto_convert_kinetic/material_wise/propagation/results_true_3.dat new file mode 100644 index 00000000000..df7374c145b --- /dev/null +++ b/tests/regression_tests/random_ray_auto_convert_kinetic/material_wise/propagation/results_true_3.dat @@ -0,0 +1,2 @@ +k-combined: +7.247257E-01 3.323600E-03 diff --git a/tests/regression_tests/random_ray_auto_convert_kinetic/material_wise/propagation/results_true_4.dat b/tests/regression_tests/random_ray_auto_convert_kinetic/material_wise/propagation/results_true_4.dat new file mode 100644 index 00000000000..df7374c145b --- /dev/null +++ b/tests/regression_tests/random_ray_auto_convert_kinetic/material_wise/propagation/results_true_4.dat @@ -0,0 +1,2 @@ +k-combined: +7.247257E-01 3.323600E-03 diff --git a/tests/regression_tests/random_ray_auto_convert_kinetic/material_wise/propagation/results_true_5.dat b/tests/regression_tests/random_ray_auto_convert_kinetic/material_wise/propagation/results_true_5.dat new file mode 100644 index 00000000000..df7374c145b --- /dev/null +++ b/tests/regression_tests/random_ray_auto_convert_kinetic/material_wise/propagation/results_true_5.dat @@ -0,0 +1,2 @@ +k-combined: +7.247257E-01 3.323600E-03 diff --git a/tests/regression_tests/random_ray_auto_convert_kinetic/stochastic_slab/isotropic/inputs_true.dat b/tests/regression_tests/random_ray_auto_convert_kinetic/stochastic_slab/isotropic/inputs_true.dat new file mode 100644 index 00000000000..e048a7d4dc1 --- /dev/null +++ b/tests/regression_tests/random_ray_auto_convert_kinetic/stochastic_slab/isotropic/inputs_true.dat @@ -0,0 +1,70 @@ + + + + mgxs.h5 + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 100 + 10 + 5 + true + +
0.01
+ s + 5 +
+ + + -0.63 -0.63 -1 0.63 0.63 1 + + + true + + + multi-group + + + + -0.63 -0.63 -1.0 0.63 0.63 1.0 + + + 30.0 + 150.0 + + + + + + isotropic + + + 8 8 + -0.63 -0.63 + 0.63 0.63 + +
+
diff --git a/tests/regression_tests/random_ray_auto_convert_kinetic/stochastic_slab/isotropic/results_true_0.dat b/tests/regression_tests/random_ray_auto_convert_kinetic/stochastic_slab/isotropic/results_true_0.dat new file mode 100644 index 00000000000..718ed9f63b2 --- /dev/null +++ b/tests/regression_tests/random_ray_auto_convert_kinetic/stochastic_slab/isotropic/results_true_0.dat @@ -0,0 +1,2 @@ +k-combined: +4.474813E-01 1.434056E-02 diff --git a/tests/regression_tests/random_ray_auto_convert_kinetic/stochastic_slab/isotropic/results_true_1.dat b/tests/regression_tests/random_ray_auto_convert_kinetic/stochastic_slab/isotropic/results_true_1.dat new file mode 100644 index 00000000000..718ed9f63b2 --- /dev/null +++ b/tests/regression_tests/random_ray_auto_convert_kinetic/stochastic_slab/isotropic/results_true_1.dat @@ -0,0 +1,2 @@ +k-combined: +4.474813E-01 1.434056E-02 diff --git a/tests/regression_tests/random_ray_auto_convert_kinetic/stochastic_slab/isotropic/results_true_2.dat b/tests/regression_tests/random_ray_auto_convert_kinetic/stochastic_slab/isotropic/results_true_2.dat new file mode 100644 index 00000000000..718ed9f63b2 --- /dev/null +++ b/tests/regression_tests/random_ray_auto_convert_kinetic/stochastic_slab/isotropic/results_true_2.dat @@ -0,0 +1,2 @@ +k-combined: +4.474813E-01 1.434056E-02 diff --git a/tests/regression_tests/random_ray_auto_convert_kinetic/stochastic_slab/isotropic/results_true_3.dat b/tests/regression_tests/random_ray_auto_convert_kinetic/stochastic_slab/isotropic/results_true_3.dat new file mode 100644 index 00000000000..718ed9f63b2 --- /dev/null +++ b/tests/regression_tests/random_ray_auto_convert_kinetic/stochastic_slab/isotropic/results_true_3.dat @@ -0,0 +1,2 @@ +k-combined: +4.474813E-01 1.434056E-02 diff --git a/tests/regression_tests/random_ray_auto_convert_kinetic/stochastic_slab/isotropic/results_true_4.dat b/tests/regression_tests/random_ray_auto_convert_kinetic/stochastic_slab/isotropic/results_true_4.dat new file mode 100644 index 00000000000..718ed9f63b2 --- /dev/null +++ b/tests/regression_tests/random_ray_auto_convert_kinetic/stochastic_slab/isotropic/results_true_4.dat @@ -0,0 +1,2 @@ +k-combined: +4.474813E-01 1.434056E-02 diff --git a/tests/regression_tests/random_ray_auto_convert_kinetic/stochastic_slab/isotropic/results_true_5.dat b/tests/regression_tests/random_ray_auto_convert_kinetic/stochastic_slab/isotropic/results_true_5.dat new file mode 100644 index 00000000000..718ed9f63b2 --- /dev/null +++ b/tests/regression_tests/random_ray_auto_convert_kinetic/stochastic_slab/isotropic/results_true_5.dat @@ -0,0 +1,2 @@ +k-combined: +4.474813E-01 1.434056E-02 diff --git a/tests/regression_tests/random_ray_auto_convert_kinetic/stochastic_slab/propagation/inputs_true.dat b/tests/regression_tests/random_ray_auto_convert_kinetic/stochastic_slab/propagation/inputs_true.dat new file mode 100644 index 00000000000..092e3952f5e --- /dev/null +++ b/tests/regression_tests/random_ray_auto_convert_kinetic/stochastic_slab/propagation/inputs_true.dat @@ -0,0 +1,70 @@ + + + + mgxs.h5 + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 100 + 10 + 5 + true + +
0.01
+ s + 5 +
+ + + -0.63 -0.63 -1 0.63 0.63 1 + + + true + + + multi-group + + + + -0.63 -0.63 -1.0 0.63 0.63 1.0 + + + 30.0 + 150.0 + + + + + + propagation + + + 8 8 + -0.63 -0.63 + 0.63 0.63 + +
+
diff --git a/tests/regression_tests/random_ray_auto_convert_kinetic/stochastic_slab/propagation/results_true_0.dat b/tests/regression_tests/random_ray_auto_convert_kinetic/stochastic_slab/propagation/results_true_0.dat new file mode 100644 index 00000000000..718ed9f63b2 --- /dev/null +++ b/tests/regression_tests/random_ray_auto_convert_kinetic/stochastic_slab/propagation/results_true_0.dat @@ -0,0 +1,2 @@ +k-combined: +4.474813E-01 1.434056E-02 diff --git a/tests/regression_tests/random_ray_auto_convert_kinetic/stochastic_slab/propagation/results_true_1.dat b/tests/regression_tests/random_ray_auto_convert_kinetic/stochastic_slab/propagation/results_true_1.dat new file mode 100644 index 00000000000..718ed9f63b2 --- /dev/null +++ b/tests/regression_tests/random_ray_auto_convert_kinetic/stochastic_slab/propagation/results_true_1.dat @@ -0,0 +1,2 @@ +k-combined: +4.474813E-01 1.434056E-02 diff --git a/tests/regression_tests/random_ray_auto_convert_kinetic/stochastic_slab/propagation/results_true_2.dat b/tests/regression_tests/random_ray_auto_convert_kinetic/stochastic_slab/propagation/results_true_2.dat new file mode 100644 index 00000000000..718ed9f63b2 --- /dev/null +++ b/tests/regression_tests/random_ray_auto_convert_kinetic/stochastic_slab/propagation/results_true_2.dat @@ -0,0 +1,2 @@ +k-combined: +4.474813E-01 1.434056E-02 diff --git a/tests/regression_tests/random_ray_auto_convert_kinetic/stochastic_slab/propagation/results_true_3.dat b/tests/regression_tests/random_ray_auto_convert_kinetic/stochastic_slab/propagation/results_true_3.dat new file mode 100644 index 00000000000..718ed9f63b2 --- /dev/null +++ b/tests/regression_tests/random_ray_auto_convert_kinetic/stochastic_slab/propagation/results_true_3.dat @@ -0,0 +1,2 @@ +k-combined: +4.474813E-01 1.434056E-02 diff --git a/tests/regression_tests/random_ray_auto_convert_kinetic/stochastic_slab/propagation/results_true_4.dat b/tests/regression_tests/random_ray_auto_convert_kinetic/stochastic_slab/propagation/results_true_4.dat new file mode 100644 index 00000000000..718ed9f63b2 --- /dev/null +++ b/tests/regression_tests/random_ray_auto_convert_kinetic/stochastic_slab/propagation/results_true_4.dat @@ -0,0 +1,2 @@ +k-combined: +4.474813E-01 1.434056E-02 diff --git a/tests/regression_tests/random_ray_auto_convert_kinetic/stochastic_slab/propagation/results_true_5.dat b/tests/regression_tests/random_ray_auto_convert_kinetic/stochastic_slab/propagation/results_true_5.dat new file mode 100644 index 00000000000..718ed9f63b2 --- /dev/null +++ b/tests/regression_tests/random_ray_auto_convert_kinetic/stochastic_slab/propagation/results_true_5.dat @@ -0,0 +1,2 @@ +k-combined: +4.474813E-01 1.434056E-02 diff --git a/tests/regression_tests/random_ray_auto_convert_kinetic/test.py b/tests/regression_tests/random_ray_auto_convert_kinetic/test.py new file mode 100644 index 00000000000..34ed2012b1e --- /dev/null +++ b/tests/regression_tests/random_ray_auto_convert_kinetic/test.py @@ -0,0 +1,70 @@ +import os + +import openmc +from openmc.examples import pwr_pin_cell +from openmc import RegularMesh +from openmc.utility_funcs import change_directory +import pytest +import numpy as np + +from tests.testing_harness import KineticTolerantPyAPITestHarness + + +class KineticMGXSTestHarness(KineticTolerantPyAPITestHarness): + def _cleanup(self): + super()._cleanup() + f = 'mgxs.h5' + if os.path.exists(f): + os.remove(f) + + +@pytest.mark.parametrize("generation_method, time_method", [("material_wise", "isotropic"), + ("stochastic_slab", + "isotropic"), + ("infinite_medium", + "isotropic"), + ("material_wise", + "propagation"), + ("stochastic_slab", + "propagation"), + ("infinite_medium", + "propagation"), + ]) +def test_random_ray_auto_convert(generation_method, time_method): + with change_directory(f'{generation_method}/{time_method}'): + openmc.reset_auto_ids() + + # Start with a normal continuous energy model + model = pwr_pin_cell() + + # Convert to a multi-group model + model.convert_to_multigroup( + method=generation_method, energy_groups='CASMO-2', nparticles=30, + overwrite_mgxs_library=False, mgxs_path="mgxs.h5", kinetic=True, + num_delayed_groups=6 + ) + + model.settings.timestep_parameters['n_timesteps'] = 5 + density_timeseries = np.linspace(1, 0.95, 100) + model.materials[2].set_density( + 'macro', density=1.0, density_timeseries=density_timeseries) + + # Convert to a random ray model + model.convert_to_random_ray() + + # Set the number of particles + model.settings.particles = 100 + + # Overlay an basic 8x8 mesh + n = 8 + mesh = RegularMesh() + mesh.dimension = (n, n) + bbox = model.geometry.bounding_box + mesh.lower_left = (bbox.lower_left[0], bbox.lower_left[1]) + mesh.upper_right = (bbox.upper_right[0], bbox.upper_right[1]) + model.settings.random_ray['source_region_meshes'] = [ + (mesh, [model.geometry.root_universe])] + model.settings.random_ray['time_derivative_method'] = time_method + + harness = KineticMGXSTestHarness("statepoint.10", 6, model) + harness.main() diff --git a/tests/regression_tests/random_ray_auto_convert_source_energy/test.py b/tests/regression_tests/random_ray_auto_convert_source_energy/test.py index bb9119d8953..1e0ab315eec 100644 --- a/tests/regression_tests/random_ray_auto_convert_source_energy/test.py +++ b/tests/regression_tests/random_ray_auto_convert_source_energy/test.py @@ -38,7 +38,7 @@ def test_random_ray_auto_convert_source_energy(method, source_type): # Convert to a multi-group model model.convert_to_multigroup( - method=method, groups='CASMO-8', nparticles=100, + method=method, energy_groups='CASMO-8', nparticles=100, overwrite_mgxs_library=False, mgxs_path="mgxs.h5", source_energy=source_energy ) diff --git a/tests/regression_tests/random_ray_diagonal_stabilization/test.py b/tests/regression_tests/random_ray_diagonal_stabilization/test.py index 8d36e1d2581..2acc1915334 100644 --- a/tests/regression_tests/random_ray_diagonal_stabilization/test.py +++ b/tests/regression_tests/random_ray_diagonal_stabilization/test.py @@ -23,7 +23,7 @@ def test_random_ray_diagonal_stabilization(): # MGXS data with some negatives on the diagonal, in order # to trigger diagonal correction. model.convert_to_multigroup( - method='material_wise', groups='CASMO-70', nparticles=13, + method='material_wise', energy_groups='CASMO-70', nparticles=13, overwrite_mgxs_library=True, mgxs_path="mgxs.h5", correction='P0' ) diff --git a/tests/regression_tests/random_ray_diagonal_stabilization_kinetic/__init__.py b/tests/regression_tests/random_ray_diagonal_stabilization_kinetic/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/regression_tests/random_ray_diagonal_stabilization_kinetic/isotropic/inputs_true.dat b/tests/regression_tests/random_ray_diagonal_stabilization_kinetic/isotropic/inputs_true.dat new file mode 100644 index 00000000000..3a4b82d3d00 --- /dev/null +++ b/tests/regression_tests/random_ray_diagonal_stabilization_kinetic/isotropic/inputs_true.dat @@ -0,0 +1,71 @@ + + + + mgxs.h5 + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 100 + 20 + 15 + true + +
0.01
+ s + 5 +
+ + + -0.63 -0.63 -1 0.63 0.63 1 + + + true + + + multi-group + + + + -0.63 -0.63 -1.0 0.63 0.63 1.0 + + + 30.0 + 150.0 + + + + + + isotropic + 0.5 + + + 8 8 + -0.63 -0.63 + 0.63 0.63 + +
+
diff --git a/tests/regression_tests/random_ray_diagonal_stabilization_kinetic/isotropic/results_true_0.dat b/tests/regression_tests/random_ray_diagonal_stabilization_kinetic/isotropic/results_true_0.dat new file mode 100644 index 00000000000..ccadbb12596 --- /dev/null +++ b/tests/regression_tests/random_ray_diagonal_stabilization_kinetic/isotropic/results_true_0.dat @@ -0,0 +1,2 @@ +k-combined: +1.072871E+00 6.955844E-03 diff --git a/tests/regression_tests/random_ray_diagonal_stabilization_kinetic/isotropic/results_true_1.dat b/tests/regression_tests/random_ray_diagonal_stabilization_kinetic/isotropic/results_true_1.dat new file mode 100644 index 00000000000..ccadbb12596 --- /dev/null +++ b/tests/regression_tests/random_ray_diagonal_stabilization_kinetic/isotropic/results_true_1.dat @@ -0,0 +1,2 @@ +k-combined: +1.072871E+00 6.955844E-03 diff --git a/tests/regression_tests/random_ray_diagonal_stabilization_kinetic/isotropic/results_true_2.dat b/tests/regression_tests/random_ray_diagonal_stabilization_kinetic/isotropic/results_true_2.dat new file mode 100644 index 00000000000..ccadbb12596 --- /dev/null +++ b/tests/regression_tests/random_ray_diagonal_stabilization_kinetic/isotropic/results_true_2.dat @@ -0,0 +1,2 @@ +k-combined: +1.072871E+00 6.955844E-03 diff --git a/tests/regression_tests/random_ray_diagonal_stabilization_kinetic/isotropic/results_true_3.dat b/tests/regression_tests/random_ray_diagonal_stabilization_kinetic/isotropic/results_true_3.dat new file mode 100644 index 00000000000..ccadbb12596 --- /dev/null +++ b/tests/regression_tests/random_ray_diagonal_stabilization_kinetic/isotropic/results_true_3.dat @@ -0,0 +1,2 @@ +k-combined: +1.072871E+00 6.955844E-03 diff --git a/tests/regression_tests/random_ray_diagonal_stabilization_kinetic/isotropic/results_true_4.dat b/tests/regression_tests/random_ray_diagonal_stabilization_kinetic/isotropic/results_true_4.dat new file mode 100644 index 00000000000..ccadbb12596 --- /dev/null +++ b/tests/regression_tests/random_ray_diagonal_stabilization_kinetic/isotropic/results_true_4.dat @@ -0,0 +1,2 @@ +k-combined: +1.072871E+00 6.955844E-03 diff --git a/tests/regression_tests/random_ray_diagonal_stabilization_kinetic/isotropic/results_true_5.dat b/tests/regression_tests/random_ray_diagonal_stabilization_kinetic/isotropic/results_true_5.dat new file mode 100644 index 00000000000..ccadbb12596 --- /dev/null +++ b/tests/regression_tests/random_ray_diagonal_stabilization_kinetic/isotropic/results_true_5.dat @@ -0,0 +1,2 @@ +k-combined: +1.072871E+00 6.955844E-03 diff --git a/tests/regression_tests/random_ray_diagonal_stabilization_kinetic/propagation/inputs_true.dat b/tests/regression_tests/random_ray_diagonal_stabilization_kinetic/propagation/inputs_true.dat new file mode 100644 index 00000000000..e85b97b2685 --- /dev/null +++ b/tests/regression_tests/random_ray_diagonal_stabilization_kinetic/propagation/inputs_true.dat @@ -0,0 +1,71 @@ + + + + mgxs.h5 + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 100 + 20 + 15 + true + +
0.01
+ s + 5 +
+ + + -0.63 -0.63 -1 0.63 0.63 1 + + + true + + + multi-group + + + + -0.63 -0.63 -1.0 0.63 0.63 1.0 + + + 30.0 + 150.0 + + + + + + propagation + 0.5 + + + 8 8 + -0.63 -0.63 + 0.63 0.63 + +
+
diff --git a/tests/regression_tests/random_ray_diagonal_stabilization_kinetic/propagation/results_true_0.dat b/tests/regression_tests/random_ray_diagonal_stabilization_kinetic/propagation/results_true_0.dat new file mode 100644 index 00000000000..ccadbb12596 --- /dev/null +++ b/tests/regression_tests/random_ray_diagonal_stabilization_kinetic/propagation/results_true_0.dat @@ -0,0 +1,2 @@ +k-combined: +1.072871E+00 6.955844E-03 diff --git a/tests/regression_tests/random_ray_diagonal_stabilization_kinetic/propagation/results_true_1.dat b/tests/regression_tests/random_ray_diagonal_stabilization_kinetic/propagation/results_true_1.dat new file mode 100644 index 00000000000..ccadbb12596 --- /dev/null +++ b/tests/regression_tests/random_ray_diagonal_stabilization_kinetic/propagation/results_true_1.dat @@ -0,0 +1,2 @@ +k-combined: +1.072871E+00 6.955844E-03 diff --git a/tests/regression_tests/random_ray_diagonal_stabilization_kinetic/propagation/results_true_2.dat b/tests/regression_tests/random_ray_diagonal_stabilization_kinetic/propagation/results_true_2.dat new file mode 100644 index 00000000000..ccadbb12596 --- /dev/null +++ b/tests/regression_tests/random_ray_diagonal_stabilization_kinetic/propagation/results_true_2.dat @@ -0,0 +1,2 @@ +k-combined: +1.072871E+00 6.955844E-03 diff --git a/tests/regression_tests/random_ray_diagonal_stabilization_kinetic/propagation/results_true_3.dat b/tests/regression_tests/random_ray_diagonal_stabilization_kinetic/propagation/results_true_3.dat new file mode 100644 index 00000000000..ccadbb12596 --- /dev/null +++ b/tests/regression_tests/random_ray_diagonal_stabilization_kinetic/propagation/results_true_3.dat @@ -0,0 +1,2 @@ +k-combined: +1.072871E+00 6.955844E-03 diff --git a/tests/regression_tests/random_ray_diagonal_stabilization_kinetic/propagation/results_true_4.dat b/tests/regression_tests/random_ray_diagonal_stabilization_kinetic/propagation/results_true_4.dat new file mode 100644 index 00000000000..ccadbb12596 --- /dev/null +++ b/tests/regression_tests/random_ray_diagonal_stabilization_kinetic/propagation/results_true_4.dat @@ -0,0 +1,2 @@ +k-combined: +1.072871E+00 6.955844E-03 diff --git a/tests/regression_tests/random_ray_diagonal_stabilization_kinetic/propagation/results_true_5.dat b/tests/regression_tests/random_ray_diagonal_stabilization_kinetic/propagation/results_true_5.dat new file mode 100644 index 00000000000..ccadbb12596 --- /dev/null +++ b/tests/regression_tests/random_ray_diagonal_stabilization_kinetic/propagation/results_true_5.dat @@ -0,0 +1,2 @@ +k-combined: +1.072871E+00 6.955844E-03 diff --git a/tests/regression_tests/random_ray_diagonal_stabilization_kinetic/test.py b/tests/regression_tests/random_ray_diagonal_stabilization_kinetic/test.py new file mode 100644 index 00000000000..7fe140d5a13 --- /dev/null +++ b/tests/regression_tests/random_ray_diagonal_stabilization_kinetic/test.py @@ -0,0 +1,74 @@ +import os + +import openmc +from openmc.examples import pwr_pin_cell +from openmc import RegularMesh +from openmc.utility_funcs import change_directory +import numpy as np +import pytest + +from tests.testing_harness import KineticTolerantPyAPITestHarness + + +class KineticMGXSTestHarness(KineticTolerantPyAPITestHarness): + def _cleanup(self): + super()._cleanup() + f = 'mgxs.h5' + if os.path.exists(f): + os.remove(f) + + +@pytest.mark.parametrize("time_method", ["isotropic", + "propagation"]) +def test_random_ray_diagonal_stabilization(time_method): + with change_directory(time_method): + openmc.reset_auto_ids() + + # Start with a normal continuous energy model + model = pwr_pin_cell() + + # Convert to a multi-group model, with 70 group XS + # and transport correction enabled. This will generate + # MGXS data with some negatives on the diagonal, in order + # to trigger diagonal correction. + model.convert_to_multigroup( + method='material_wise', energy_groups='CASMO-70', nparticles=30, + overwrite_mgxs_library=True, mgxs_path="mgxs.h5", correction='P0', + kinetic=True, num_delayed_groups=6 + ) + + model.settings.timestep_parameters['n_timesteps'] = 5 + density_timeseries = np.linspace(1, 0.95, 100) + model.materials[2].set_density( + 'macro', density=1.0, density_timeseries=density_timeseries) + + # Convert to a random ray model + model.convert_to_random_ray() + + # Set the number of particles + model.settings.particles = 100 + + # Overlay an 8x8 mesh + n = 8 + mesh = RegularMesh() + mesh.dimension = (n, n) + bbox = model.geometry.bounding_box + mesh.lower_left = (bbox.lower_left[0], bbox.lower_left[1]) + mesh.upper_right = (bbox.upper_right[0], bbox.upper_right[1]) + model.settings.random_ray['source_region_meshes'] = [ + (mesh, [model.geometry.root_universe])] + model.settings.random_ray['time_derivative_method'] = time_method + + # Explicitly set the diagonal stabilization rho (default is otherwise 1.0). + # Note that if we set this to 0.0 (thus distabling stabilization), the + # problem should fail due to instability, so this is actually a good test + # problem. + model.settings.random_ray['diagonal_stabilization_rho'] = 0.5 + + # If rho was 0.0, the instability would cause failure after iteration 14, + # so we go a little past that. + model.settings.inactive = 15 + model.settings.batches = 20 + + harness = KineticMGXSTestHarness('statepoint.20', 6, model) + harness.main() diff --git a/tests/regression_tests/random_ray_k_eff_kinetic/__init__.py b/tests/regression_tests/random_ray_k_eff_kinetic/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/regression_tests/random_ray_k_eff_kinetic/isotropic/inputs_true.dat b/tests/regression_tests/random_ray_k_eff_kinetic/isotropic/inputs_true.dat new file mode 100644 index 00000000000..503ecabaa68 --- /dev/null +++ b/tests/regression_tests/random_ray_k_eff_kinetic/isotropic/inputs_true.dat @@ -0,0 +1,86 @@ + + + + mgxs.h5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 100 + 400 + 200 + true + +
0.01
+ 5 + s +
+ multi-group + + 100.0 + 20.0 + + + -0.63 -0.63 -1 0.63 0.63 1 + + + true + 3 + isotropic + +
+ + + 1 2 3 4 5 6 7 8 + + + flux fission nu-fission + analog + + + 1 + precursors + + +
diff --git a/tests/regression_tests/random_ray_k_eff_kinetic/isotropic/results_true_0.dat b/tests/regression_tests/random_ray_k_eff_kinetic/isotropic/results_true_0.dat new file mode 100644 index 00000000000..3a18ad9c134 --- /dev/null +++ b/tests/regression_tests/random_ray_k_eff_kinetic/isotropic/results_true_0.dat @@ -0,0 +1,26 @@ +k-combined: +1.325787E+00 5.102917E-04 +tally 1: +2.630331E+03 +3.459322E+04 +1.079948E+02 +5.831610E+01 +2.651573E+02 +3.515523E+02 +tally 2: +1.077582E+00 +5.805919E-03 +2.327022E+00 +2.707515E-02 +8.947059E-01 +4.002493E-03 +6.344423E-01 +2.012585E-03 +4.939693E-01 +1.220028E-03 +6.664308E-02 +2.220650E-05 +2.312960E-02 +2.674892E-06 +3.680705E-03 +6.773796E-08 diff --git a/tests/regression_tests/random_ray_k_eff_kinetic/isotropic/results_true_1.dat b/tests/regression_tests/random_ray_k_eff_kinetic/isotropic/results_true_1.dat new file mode 100644 index 00000000000..46dba4d56f4 --- /dev/null +++ b/tests/regression_tests/random_ray_k_eff_kinetic/isotropic/results_true_1.dat @@ -0,0 +1,26 @@ +k-combined: +1.325787E+00 5.102917E-04 +tally 1: +2.630190E+03 +3.458951E+04 +1.079890E+02 +5.830986E+01 +2.651431E+02 +3.515147E+02 +tally 2: +1.077582E+00 +5.805916E-03 +2.327021E+00 +2.707513E-02 +8.947056E-01 +4.002491E-03 +6.344421E-01 +2.012584E-03 +4.939691E-01 +1.220027E-03 +6.664304E-02 +2.220648E-05 +2.312958E-02 +2.674887E-06 +3.680701E-03 +6.773779E-08 diff --git a/tests/regression_tests/random_ray_k_eff_kinetic/isotropic/results_true_2.dat b/tests/regression_tests/random_ray_k_eff_kinetic/isotropic/results_true_2.dat new file mode 100644 index 00000000000..59ce5cb6cf3 --- /dev/null +++ b/tests/regression_tests/random_ray_k_eff_kinetic/isotropic/results_true_2.dat @@ -0,0 +1,26 @@ +k-combined: +1.325787E+00 5.102917E-04 +tally 1: +2.628842E+03 +3.455405E+04 +1.078945E+02 +5.820788E+01 +2.649118E+02 +3.509018E+02 +tally 2: +1.077582E+00 +5.805915E-03 +2.327021E+00 +2.707512E-02 +8.947054E-01 +4.002489E-03 +6.344416E-01 +2.012581E-03 +4.939683E-01 +1.220024E-03 +6.664281E-02 +2.220632E-05 +2.312938E-02 +2.674842E-06 +3.680634E-03 +6.773532E-08 diff --git a/tests/regression_tests/random_ray_k_eff_kinetic/isotropic/results_true_3.dat b/tests/regression_tests/random_ray_k_eff_kinetic/isotropic/results_true_3.dat new file mode 100644 index 00000000000..c237ebd2591 --- /dev/null +++ b/tests/regression_tests/random_ray_k_eff_kinetic/isotropic/results_true_3.dat @@ -0,0 +1,26 @@ +k-combined: +1.325787E+00 5.102917E-04 +tally 1: +2.626019E+03 +3.447990E+04 +1.077393E+02 +5.804055E+01 +2.645315E+02 +3.498950E+02 +tally 2: +1.077582E+00 +5.805913E-03 +2.327020E+00 +2.707510E-02 +8.947048E-01 +4.002483E-03 +6.344403E-01 +2.012572E-03 +4.939660E-01 +1.220012E-03 +6.664210E-02 +2.220585E-05 +2.312878E-02 +2.674703E-06 +3.680428E-03 +6.772777E-08 diff --git a/tests/regression_tests/random_ray_k_eff_kinetic/isotropic/results_true_4.dat b/tests/regression_tests/random_ray_k_eff_kinetic/isotropic/results_true_4.dat new file mode 100644 index 00000000000..2a14986689a --- /dev/null +++ b/tests/regression_tests/random_ray_k_eff_kinetic/isotropic/results_true_4.dat @@ -0,0 +1,26 @@ +k-combined: +1.325787E+00 5.102917E-04 +tally 1: +2.621893E+03 +3.437163E+04 +1.075306E+02 +5.781591E+01 +2.640198E+02 +3.485426E+02 +tally 2: +1.077581E+00 +5.805908E-03 +2.327017E+00 +2.707505E-02 +8.947036E-01 +4.002472E-03 +6.344375E-01 +2.012555E-03 +4.939613E-01 +1.219989E-03 +6.664066E-02 +2.220489E-05 +2.312757E-02 +2.674422E-06 +3.680017E-03 +6.771264E-08 diff --git a/tests/regression_tests/random_ray_k_eff_kinetic/isotropic/results_true_5.dat b/tests/regression_tests/random_ray_k_eff_kinetic/isotropic/results_true_5.dat new file mode 100644 index 00000000000..e66542145b7 --- /dev/null +++ b/tests/regression_tests/random_ray_k_eff_kinetic/isotropic/results_true_5.dat @@ -0,0 +1,26 @@ +k-combined: +1.325787E+00 5.102917E-04 +tally 1: +2.616580E+03 +3.423247E+04 +1.072732E+02 +5.753947E+01 +2.633886E+02 +3.468780E+02 +tally 2: +1.077581E+00 +5.805900E-03 +2.327014E+00 +2.707497E-02 +8.947015E-01 +4.002454E-03 +6.344330E-01 +2.012526E-03 +4.939535E-01 +1.219950E-03 +6.663827E-02 +2.220330E-05 +2.312556E-02 +2.673959E-06 +3.679343E-03 +6.768783E-08 diff --git a/tests/regression_tests/random_ray_k_eff_kinetic/propagation/inputs_true.dat b/tests/regression_tests/random_ray_k_eff_kinetic/propagation/inputs_true.dat new file mode 100644 index 00000000000..55e6e96a613 --- /dev/null +++ b/tests/regression_tests/random_ray_k_eff_kinetic/propagation/inputs_true.dat @@ -0,0 +1,86 @@ + + + + mgxs.h5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + eigenvalue + 100 + 400 + 200 + true + +
0.01
+ 5 + s +
+ multi-group + + 100.0 + 20.0 + + + -0.63 -0.63 -1 0.63 0.63 1 + + + true + 3 + propagation + +
+ + + 1 2 3 4 5 6 7 8 + + + flux fission nu-fission + analog + + + 1 + precursors + + +
diff --git a/tests/regression_tests/random_ray_k_eff_kinetic/propagation/results_true_0.dat b/tests/regression_tests/random_ray_k_eff_kinetic/propagation/results_true_0.dat new file mode 100644 index 00000000000..3a18ad9c134 --- /dev/null +++ b/tests/regression_tests/random_ray_k_eff_kinetic/propagation/results_true_0.dat @@ -0,0 +1,26 @@ +k-combined: +1.325787E+00 5.102917E-04 +tally 1: +2.630331E+03 +3.459322E+04 +1.079948E+02 +5.831610E+01 +2.651573E+02 +3.515523E+02 +tally 2: +1.077582E+00 +5.805919E-03 +2.327022E+00 +2.707515E-02 +8.947059E-01 +4.002493E-03 +6.344423E-01 +2.012585E-03 +4.939693E-01 +1.220028E-03 +6.664308E-02 +2.220650E-05 +2.312960E-02 +2.674892E-06 +3.680705E-03 +6.773796E-08 diff --git a/tests/regression_tests/random_ray_k_eff_kinetic/propagation/results_true_1.dat b/tests/regression_tests/random_ray_k_eff_kinetic/propagation/results_true_1.dat new file mode 100644 index 00000000000..46dba4d56f4 --- /dev/null +++ b/tests/regression_tests/random_ray_k_eff_kinetic/propagation/results_true_1.dat @@ -0,0 +1,26 @@ +k-combined: +1.325787E+00 5.102917E-04 +tally 1: +2.630190E+03 +3.458951E+04 +1.079890E+02 +5.830986E+01 +2.651431E+02 +3.515147E+02 +tally 2: +1.077582E+00 +5.805916E-03 +2.327021E+00 +2.707513E-02 +8.947056E-01 +4.002491E-03 +6.344421E-01 +2.012584E-03 +4.939691E-01 +1.220027E-03 +6.664304E-02 +2.220648E-05 +2.312958E-02 +2.674887E-06 +3.680701E-03 +6.773779E-08 diff --git a/tests/regression_tests/random_ray_k_eff_kinetic/propagation/results_true_2.dat b/tests/regression_tests/random_ray_k_eff_kinetic/propagation/results_true_2.dat new file mode 100644 index 00000000000..59ce5cb6cf3 --- /dev/null +++ b/tests/regression_tests/random_ray_k_eff_kinetic/propagation/results_true_2.dat @@ -0,0 +1,26 @@ +k-combined: +1.325787E+00 5.102917E-04 +tally 1: +2.628842E+03 +3.455405E+04 +1.078945E+02 +5.820788E+01 +2.649118E+02 +3.509018E+02 +tally 2: +1.077582E+00 +5.805915E-03 +2.327021E+00 +2.707512E-02 +8.947054E-01 +4.002489E-03 +6.344416E-01 +2.012581E-03 +4.939683E-01 +1.220024E-03 +6.664281E-02 +2.220632E-05 +2.312938E-02 +2.674842E-06 +3.680634E-03 +6.773532E-08 diff --git a/tests/regression_tests/random_ray_k_eff_kinetic/propagation/results_true_3.dat b/tests/regression_tests/random_ray_k_eff_kinetic/propagation/results_true_3.dat new file mode 100644 index 00000000000..c237ebd2591 --- /dev/null +++ b/tests/regression_tests/random_ray_k_eff_kinetic/propagation/results_true_3.dat @@ -0,0 +1,26 @@ +k-combined: +1.325787E+00 5.102917E-04 +tally 1: +2.626019E+03 +3.447990E+04 +1.077393E+02 +5.804055E+01 +2.645315E+02 +3.498950E+02 +tally 2: +1.077582E+00 +5.805913E-03 +2.327020E+00 +2.707510E-02 +8.947048E-01 +4.002483E-03 +6.344403E-01 +2.012572E-03 +4.939660E-01 +1.220012E-03 +6.664210E-02 +2.220585E-05 +2.312878E-02 +2.674703E-06 +3.680428E-03 +6.772777E-08 diff --git a/tests/regression_tests/random_ray_k_eff_kinetic/propagation/results_true_4.dat b/tests/regression_tests/random_ray_k_eff_kinetic/propagation/results_true_4.dat new file mode 100644 index 00000000000..99def7858bf --- /dev/null +++ b/tests/regression_tests/random_ray_k_eff_kinetic/propagation/results_true_4.dat @@ -0,0 +1,26 @@ +k-combined: +1.325787E+00 5.102917E-04 +tally 1: +2.621893E+03 +3.437163E+04 +1.075306E+02 +5.781591E+01 +2.640198E+02 +3.485427E+02 +tally 2: +1.077581E+00 +5.805908E-03 +2.327017E+00 +2.707505E-02 +8.947036E-01 +4.002472E-03 +6.344375E-01 +2.012555E-03 +4.939613E-01 +1.219989E-03 +6.664066E-02 +2.220489E-05 +2.312757E-02 +2.674422E-06 +3.680017E-03 +6.771264E-08 diff --git a/tests/regression_tests/random_ray_k_eff_kinetic/propagation/results_true_5.dat b/tests/regression_tests/random_ray_k_eff_kinetic/propagation/results_true_5.dat new file mode 100644 index 00000000000..e66542145b7 --- /dev/null +++ b/tests/regression_tests/random_ray_k_eff_kinetic/propagation/results_true_5.dat @@ -0,0 +1,26 @@ +k-combined: +1.325787E+00 5.102917E-04 +tally 1: +2.616580E+03 +3.423247E+04 +1.072732E+02 +5.753947E+01 +2.633886E+02 +3.468780E+02 +tally 2: +1.077581E+00 +5.805900E-03 +2.327014E+00 +2.707497E-02 +8.947015E-01 +4.002454E-03 +6.344330E-01 +2.012526E-03 +4.939535E-01 +1.219950E-03 +6.663827E-02 +2.220330E-05 +2.312556E-02 +2.673959E-06 +3.679343E-03 +6.768783E-08 diff --git a/tests/regression_tests/random_ray_k_eff_kinetic/test.py b/tests/regression_tests/random_ray_k_eff_kinetic/test.py new file mode 100644 index 00000000000..2037554d295 --- /dev/null +++ b/tests/regression_tests/random_ray_k_eff_kinetic/test.py @@ -0,0 +1,30 @@ +import os + +import openmc +from openmc.utility_funcs import change_directory +from openmc.examples import random_ray_pin_cell +import pytest + +from tests.testing_harness import KineticTolerantPyAPITestHarness + + +class KineticMGXSTestHarness(KineticTolerantPyAPITestHarness): + def _cleanup(self): + super()._cleanup() + f = 'mgxs.h5' + if os.path.exists(f): + os.remove(f) + + +@pytest.mark.parametrize("time_method", ["isotropic", + "propagation"]) +def test_random_ray_time_dependent(time_method): + with change_directory(time_method): + openmc.reset_auto_ids() + model = random_ray_pin_cell(kinetic=True) + model.settings.timestep_parameters['n_timesteps'] = 5 + model.settings.random_ray['time_method'] = time_method + model.settings.batches = 400 + model.settings.inactive = 200 + harness = KineticMGXSTestHarness('statepoint.400', 6, model) + harness.main() diff --git a/tests/regression_tests/random_ray_k_eff_mesh_kinetic/__init__.py b/tests/regression_tests/random_ray_k_eff_mesh_kinetic/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/regression_tests/random_ray_k_eff_mesh_kinetic/isotropic/inputs_true.dat b/tests/regression_tests/random_ray_k_eff_mesh_kinetic/isotropic/inputs_true.dat new file mode 100644 index 00000000000..1790a1edbeb --- /dev/null +++ b/tests/regression_tests/random_ray_k_eff_mesh_kinetic/isotropic/inputs_true.dat @@ -0,0 +1,138 @@ + + + + mgxs.h5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0.126 0.126 + 10 10 + -0.63 -0.63 + +3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 + + + 1.26 1.26 + 2 2 + -1.26 -1.26 + +2 2 +2 5 + + + + + + + + + + + + + + + + + + + + + eigenvalue + 100 + 400 + 200 + true + +
0.01
+ 5 + s +
+ multi-group + + 100.0 + 20.0 + + + -1.26 -1.26 -1 1.26 1.26 1 + + + true + 3 + isotropic + + + + + + + + 40 40 + -1.26 -1.26 + 1.26 1.26 + +
+ + + 2 2 + -1.26 -1.26 + 1.26 1.26 + + + 1 + + + 1e-05 0.0635 10.0 100.0 1000.0 500000.0 1000000.0 20000000.0 + + + 1 2 3 4 5 6 7 8 + + + 1 2 + flux fission nu-fission + analog + + + 1 3 + precursors + + +
diff --git a/tests/regression_tests/random_ray_k_eff_mesh_kinetic/isotropic/results_error_2.dat b/tests/regression_tests/random_ray_k_eff_mesh_kinetic/isotropic/results_error_2.dat new file mode 100644 index 00000000000..3d87c1ff778 --- /dev/null +++ b/tests/regression_tests/random_ray_k_eff_mesh_kinetic/isotropic/results_error_2.dat @@ -0,0 +1,236 @@ +k-combined: +1.311387E+00 6.434473E-04 +tally 1: +6.841002E+01 +2.340263E+01 +2.539209E+01 +3.224884E+00 +6.179927E+01 +1.910222E+01 +4.345795E+01 +9.443438E+00 +6.461264E+00 +2.087627E-01 +1.572542E+01 +1.236581E+00 +2.958149E+01 +4.375353E+00 +9.580602E-01 +4.589460E-03 +2.331727E+00 +2.718512E-02 +3.771759E+01 +7.113168E+00 +1.255942E+00 +7.887213E-03 +3.056711E+00 +4.671898E-02 +9.755563E+01 +4.758560E+01 +1.145481E+00 +6.560664E-03 +2.787906E+00 +3.886227E-02 +2.112846E+02 +2.232138E+02 +3.224201E-01 +5.198159E-04 +7.978060E-01 +3.182731E-03 +1.123398E+02 +6.311270E+01 +1.523334E+00 +1.160869E-02 +4.237076E+00 +8.981014E-02 +1.130415E+02 +6.389267E+01 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +5.351354E+01 +1.431862E+01 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +3.116478E+01 +4.856241E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +4.109112E+01 +8.442486E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +9.834626E+01 +4.836011E+01 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.891192E+02 +1.788363E+02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +9.689929E+01 +4.696147E+01 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +5.902247E+01 +1.741950E+01 +2.183516E+01 +2.384443E+00 +5.314240E+01 +1.412397E+01 +4.083553E+01 +8.337955E+00 +6.069953E+00 +1.842363E-01 +1.477305E+01 +1.091302E+00 +2.914979E+01 +4.248577E+00 +9.449213E-01 +4.464435E-03 +2.299749E+00 +2.644455E-02 +3.706648E+01 +6.869692E+00 +1.234866E+00 +7.624718E-03 +3.005416E+00 +4.516412E-02 +9.764189E+01 +4.766978E+01 +1.147278E+00 +6.581260E-03 +2.792280E+00 +3.898427E-02 +2.155703E+02 +2.323588E+02 +3.288490E-01 +5.407413E-04 +8.137138E-01 +3.310853E-03 +1.141283E+02 +6.513702E+01 +1.543766E+00 +1.192054E-02 +4.293907E+00 +9.222278E-02 +6.827719E+01 +2.331160E+01 +2.541921E+01 +3.231700E+00 +6.186528E+01 +1.914259E+01 +4.341541E+01 +9.424932E+00 +6.474517E+00 +2.096181E-01 +1.575768E+01 +1.241648E+00 +2.957222E+01 +4.372617E+00 +9.605956E-01 +4.613787E-03 +2.337897E+00 +2.732922E-02 +3.770489E+01 +7.108388E+00 +1.259270E+00 +7.929065E-03 +3.064812E+00 +4.696688E-02 +9.756404E+01 +4.759381E+01 +1.148934E+00 +6.600271E-03 +2.796309E+00 +3.909688E-02 +2.114029E+02 +2.234627E+02 +3.234836E-01 +5.232451E-04 +8.004376E-01 +3.203727E-03 +1.123686E+02 +6.314288E+01 +1.527536E+00 +1.167216E-02 +4.248764E+00 +9.030121E-02 +tally 2: +3.727211E-01 +6.946052E-04 +8.048854E-01 +3.239203E-03 +3.094668E-01 +4.788484E-04 +2.194454E-01 +2.407815E-04 +1.708581E-01 +1.459624E-04 +2.305119E-02 +2.656788E-06 +8.000435E-03 +3.200348E-07 +1.273182E-03 +8.104960E-09 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +3.327638E-01 +5.536589E-04 +7.185983E-01 +2.581918E-03 +2.762906E-01 +3.816826E-04 +1.959200E-01 +1.919231E-04 +1.525414E-01 +1.163444E-04 +2.058001E-02 +2.117684E-06 +7.142754E-03 +2.550947E-07 +1.136691E-03 +6.460334E-09 +3.721891E-01 +6.926238E-04 +8.037366E-01 +3.229963E-03 +3.090251E-01 +4.774825E-04 +2.191322E-01 +2.400946E-04 +1.706142E-01 +1.455461E-04 +2.301829E-02 +2.649209E-06 +7.989016E-03 +3.191219E-07 +1.271365E-03 +8.081840E-09 diff --git a/tests/regression_tests/random_ray_k_eff_mesh_kinetic/isotropic/results_true_0.dat b/tests/regression_tests/random_ray_k_eff_mesh_kinetic/isotropic/results_true_0.dat new file mode 100644 index 00000000000..b7863f78005 --- /dev/null +++ b/tests/regression_tests/random_ray_k_eff_mesh_kinetic/isotropic/results_true_0.dat @@ -0,0 +1,236 @@ +k-combined: +1.311387E+00 6.434473E-04 +tally 1: +6.829734E+01 +2.332560E+01 +2.535005E+01 +3.214213E+00 +6.169695E+01 +1.903901E+01 +4.338057E+01 +9.409840E+00 +6.449747E+00 +2.080191E-01 +1.569739E+01 +1.232177E+00 +2.952526E+01 +4.358735E+00 +9.562385E-01 +4.572024E-03 +2.327293E+00 +2.708184E-02 +3.764580E+01 +7.086116E+00 +1.253550E+00 +7.857205E-03 +3.050891E+00 +4.654123E-02 +9.736564E+01 +4.740043E+01 +1.143250E+00 +6.535133E-03 +2.782476E+00 +3.871104E-02 +2.108671E+02 +2.223325E+02 +3.217847E-01 +5.177688E-04 +7.962336E-01 +3.170197E-03 +1.121239E+02 +6.287031E+01 +1.520419E+00 +1.156430E-02 +4.228968E+00 +8.946678E-02 +1.128474E+02 +6.367345E+01 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +5.341703E+01 +1.426702E+01 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +3.110513E+01 +4.837669E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +4.101197E+01 +8.409994E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +9.815385E+01 +4.817107E+01 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.887447E+02 +1.781287E+02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +9.671216E+01 +4.678026E+01 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +5.892637E+01 +1.736282E+01 +2.179942E+01 +2.376644E+00 +5.305542E+01 +1.407777E+01 +4.076286E+01 +8.308305E+00 +6.059136E+00 +1.835802E-01 +1.474673E+01 +1.087416E+00 +2.909448E+01 +4.232468E+00 +9.431274E-01 +4.447499E-03 +2.295383E+00 +2.634424E-02 +3.699617E+01 +6.843656E+00 +1.232522E+00 +7.595798E-03 +2.999711E+00 +4.499282E-02 +9.745207E+01 +4.748461E+01 +1.145047E+00 +6.555693E-03 +2.786851E+00 +3.883283E-02 +2.151446E+02 +2.314420E+02 +3.282013E-01 +5.386136E-04 +8.121113E-01 +3.297825E-03 +1.139091E+02 +6.488702E+01 +1.540814E+00 +1.187500E-02 +4.285697E+00 +9.187046E-02 +6.816479E+01 +2.323491E+01 +2.537715E+01 +3.221014E+00 +6.176291E+01 +1.907929E+01 +4.333813E+01 +9.391406E+00 +6.462978E+00 +2.088716E-01 +1.572960E+01 +1.237227E+00 +2.951601E+01 +4.356011E+00 +9.587693E-01 +4.596260E-03 +2.333452E+00 +2.722540E-02 +3.763313E+01 +7.081357E+00 +1.256873E+00 +7.898901E-03 +3.058977E+00 +4.678821E-02 +9.737405E+01 +4.740862E+01 +1.146696E+00 +6.574588E-03 +2.790864E+00 +3.894475E-02 +2.109852E+02 +2.225806E+02 +3.228462E-01 +5.211850E-04 +7.988604E-01 +3.191114E-03 +1.121527E+02 +6.290039E+01 +1.524613E+00 +1.162754E-02 +4.240634E+00 +8.995597E-02 +tally 2: +3.727239E-01 +6.947125E-04 +8.048913E-01 +3.239702E-03 +3.094690E-01 +4.789219E-04 +2.194466E-01 +2.408177E-04 +1.708586E-01 +1.459836E-04 +2.305111E-02 +2.657139E-06 +8.000274E-03 +3.200666E-07 +1.273116E-03 +8.105247E-09 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +3.327663E-01 +5.537155E-04 +7.186034E-01 +2.582180E-03 +2.762925E-01 +3.817212E-04 +1.959210E-01 +1.919420E-04 +1.525418E-01 +1.163551E-04 +2.057993E-02 +2.117853E-06 +7.142610E-03 +2.551067E-07 +1.136632E-03 +6.460228E-09 +3.721919E-01 +6.927141E-04 +8.037423E-01 +3.230382E-03 +3.090272E-01 +4.775443E-04 +2.191334E-01 +2.401250E-04 +1.706146E-01 +1.455636E-04 +2.301820E-02 +2.649495E-06 +7.988854E-03 +3.191459E-07 +1.271298E-03 +8.081932E-09 diff --git a/tests/regression_tests/random_ray_k_eff_mesh_kinetic/isotropic/results_true_1.dat b/tests/regression_tests/random_ray_k_eff_mesh_kinetic/isotropic/results_true_1.dat new file mode 100644 index 00000000000..25731b9a04d --- /dev/null +++ b/tests/regression_tests/random_ray_k_eff_mesh_kinetic/isotropic/results_true_1.dat @@ -0,0 +1,236 @@ +k-combined: +1.311387E+00 6.434473E-04 +tally 1: +6.835752E+01 +2.336672E+01 +2.537238E+01 +3.219879E+00 +6.175130E+01 +1.907257E+01 +4.341875E+01 +9.426410E+00 +6.455423E+00 +2.083854E-01 +1.571121E+01 +1.234346E+00 +2.955121E+01 +4.366400E+00 +9.570789E-01 +4.580063E-03 +2.329338E+00 +2.712946E-02 +3.767887E+01 +7.098572E+00 +1.254652E+00 +7.871018E-03 +3.053571E+00 +4.662305E-02 +9.745113E+01 +4.748370E+01 +1.144254E+00 +6.546614E-03 +2.784919E+00 +3.877905E-02 +2.110519E+02 +2.227224E+02 +3.220667E-01 +5.186767E-04 +7.969314E-01 +3.175756E-03 +1.122226E+02 +6.298103E+01 +1.521757E+00 +1.158467E-02 +4.232690E+00 +8.962434E-02 +1.129469E+02 +6.378582E+01 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +5.346406E+01 +1.429216E+01 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +3.113246E+01 +4.846176E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +4.104800E+01 +8.424776E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +9.824002E+01 +4.825568E+01 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.889102E+02 +1.784412E+02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +9.679727E+01 +4.686264E+01 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +5.897826E+01 +1.739342E+01 +2.181861E+01 +2.380831E+00 +5.310214E+01 +1.410257E+01 +4.079873E+01 +8.322934E+00 +6.064468E+00 +1.839035E-01 +1.475970E+01 +1.089331E+00 +2.912005E+01 +4.239911E+00 +9.439562E-01 +4.455320E-03 +2.297400E+00 +2.639056E-02 +3.702868E+01 +6.855687E+00 +1.233605E+00 +7.609152E-03 +3.002347E+00 +4.507192E-02 +9.753763E+01 +4.756803E+01 +1.146053E+00 +6.567210E-03 +2.789297E+00 +3.890105E-02 +2.153331E+02 +2.318478E+02 +3.284889E-01 +5.395577E-04 +8.128227E-01 +3.303606E-03 +1.140093E+02 +6.500127E+01 +1.542170E+00 +1.189591E-02 +4.289468E+00 +9.203221E-02 +6.822483E+01 +2.327586E+01 +2.539950E+01 +3.226689E+00 +6.181730E+01 +1.911291E+01 +4.337627E+01 +9.407943E+00 +6.468666E+00 +2.092394E-01 +1.574344E+01 +1.239405E+00 +2.954195E+01 +4.363671E+00 +9.596119E-01 +4.604342E-03 +2.335503E+00 +2.727327E-02 +3.766620E+01 +7.093806E+00 +1.257977E+00 +7.912788E-03 +3.061664E+00 +4.687047E-02 +9.745954E+01 +4.749190E+01 +1.147703E+00 +6.586137E-03 +2.793314E+00 +3.901316E-02 +2.111701E+02 +2.229707E+02 +3.231290E-01 +5.220983E-04 +7.995600E-01 +3.196706E-03 +1.122513E+02 +6.301114E+01 +1.525955E+00 +1.164801E-02 +4.244366E+00 +9.011434E-02 +tally 2: +3.727210E-01 +6.946049E-04 +8.048851E-01 +3.239200E-03 +3.094666E-01 +4.788479E-04 +2.194451E-01 +2.407807E-04 +1.708575E-01 +1.459614E-04 +2.305100E-02 +2.656744E-06 +8.000275E-03 +3.200220E-07 +1.273127E-03 +8.104266E-09 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +3.327638E-01 +5.536587E-04 +7.185980E-01 +2.581916E-03 +2.762905E-01 +3.816822E-04 +1.959196E-01 +1.919225E-04 +1.525408E-01 +1.163435E-04 +2.057984E-02 +2.117649E-06 +7.142612E-03 +2.550845E-07 +1.136643E-03 +6.459783E-09 +3.721891E-01 +6.926236E-04 +8.037363E-01 +3.229960E-03 +3.090249E-01 +4.774820E-04 +2.191319E-01 +2.400939E-04 +1.706136E-01 +1.455450E-04 +2.301810E-02 +2.649166E-06 +7.988856E-03 +3.191091E-07 +1.271310E-03 +8.081148E-09 diff --git a/tests/regression_tests/random_ray_k_eff_mesh_kinetic/isotropic/results_true_2.dat b/tests/regression_tests/random_ray_k_eff_mesh_kinetic/isotropic/results_true_2.dat new file mode 100644 index 00000000000..3d87c1ff778 --- /dev/null +++ b/tests/regression_tests/random_ray_k_eff_mesh_kinetic/isotropic/results_true_2.dat @@ -0,0 +1,236 @@ +k-combined: +1.311387E+00 6.434473E-04 +tally 1: +6.841002E+01 +2.340263E+01 +2.539209E+01 +3.224884E+00 +6.179927E+01 +1.910222E+01 +4.345795E+01 +9.443438E+00 +6.461264E+00 +2.087627E-01 +1.572542E+01 +1.236581E+00 +2.958149E+01 +4.375353E+00 +9.580602E-01 +4.589460E-03 +2.331727E+00 +2.718512E-02 +3.771759E+01 +7.113168E+00 +1.255942E+00 +7.887213E-03 +3.056711E+00 +4.671898E-02 +9.755563E+01 +4.758560E+01 +1.145481E+00 +6.560664E-03 +2.787906E+00 +3.886227E-02 +2.112846E+02 +2.232138E+02 +3.224201E-01 +5.198159E-04 +7.978060E-01 +3.182731E-03 +1.123398E+02 +6.311270E+01 +1.523334E+00 +1.160869E-02 +4.237076E+00 +8.981014E-02 +1.130415E+02 +6.389267E+01 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +5.351354E+01 +1.431862E+01 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +3.116478E+01 +4.856241E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +4.109112E+01 +8.442486E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +9.834626E+01 +4.836011E+01 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.891192E+02 +1.788363E+02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +9.689929E+01 +4.696147E+01 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +5.902247E+01 +1.741950E+01 +2.183516E+01 +2.384443E+00 +5.314240E+01 +1.412397E+01 +4.083553E+01 +8.337955E+00 +6.069953E+00 +1.842363E-01 +1.477305E+01 +1.091302E+00 +2.914979E+01 +4.248577E+00 +9.449213E-01 +4.464435E-03 +2.299749E+00 +2.644455E-02 +3.706648E+01 +6.869692E+00 +1.234866E+00 +7.624718E-03 +3.005416E+00 +4.516412E-02 +9.764189E+01 +4.766978E+01 +1.147278E+00 +6.581260E-03 +2.792280E+00 +3.898427E-02 +2.155703E+02 +2.323588E+02 +3.288490E-01 +5.407413E-04 +8.137138E-01 +3.310853E-03 +1.141283E+02 +6.513702E+01 +1.543766E+00 +1.192054E-02 +4.293907E+00 +9.222278E-02 +6.827719E+01 +2.331160E+01 +2.541921E+01 +3.231700E+00 +6.186528E+01 +1.914259E+01 +4.341541E+01 +9.424932E+00 +6.474517E+00 +2.096181E-01 +1.575768E+01 +1.241648E+00 +2.957222E+01 +4.372617E+00 +9.605956E-01 +4.613787E-03 +2.337897E+00 +2.732922E-02 +3.770489E+01 +7.108388E+00 +1.259270E+00 +7.929065E-03 +3.064812E+00 +4.696688E-02 +9.756404E+01 +4.759381E+01 +1.148934E+00 +6.600271E-03 +2.796309E+00 +3.909688E-02 +2.114029E+02 +2.234627E+02 +3.234836E-01 +5.232451E-04 +8.004376E-01 +3.203727E-03 +1.123686E+02 +6.314288E+01 +1.527536E+00 +1.167216E-02 +4.248764E+00 +9.030121E-02 +tally 2: +3.727211E-01 +6.946052E-04 +8.048854E-01 +3.239203E-03 +3.094668E-01 +4.788484E-04 +2.194454E-01 +2.407815E-04 +1.708581E-01 +1.459624E-04 +2.305119E-02 +2.656788E-06 +8.000435E-03 +3.200348E-07 +1.273182E-03 +8.104960E-09 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +3.327638E-01 +5.536589E-04 +7.185983E-01 +2.581918E-03 +2.762906E-01 +3.816826E-04 +1.959200E-01 +1.919231E-04 +1.525414E-01 +1.163444E-04 +2.058001E-02 +2.117684E-06 +7.142754E-03 +2.550947E-07 +1.136691E-03 +6.460334E-09 +3.721891E-01 +6.926238E-04 +8.037366E-01 +3.229963E-03 +3.090251E-01 +4.774825E-04 +2.191322E-01 +2.400946E-04 +1.706142E-01 +1.455461E-04 +2.301829E-02 +2.649209E-06 +7.989016E-03 +3.191219E-07 +1.271365E-03 +8.081840E-09 diff --git a/tests/regression_tests/random_ray_k_eff_mesh_kinetic/isotropic/results_true_3.dat b/tests/regression_tests/random_ray_k_eff_mesh_kinetic/isotropic/results_true_3.dat new file mode 100644 index 00000000000..f5d2338864e --- /dev/null +++ b/tests/regression_tests/random_ray_k_eff_mesh_kinetic/isotropic/results_true_3.dat @@ -0,0 +1,236 @@ +k-combined: +1.311387E+00 6.434473E-04 +tally 1: +6.846308E+01 +2.343895E+01 +2.541200E+01 +3.229943E+00 +6.184772E+01 +1.913218E+01 +4.349756E+01 +9.460661E+00 +6.467166E+00 +2.091442E-01 +1.573979E+01 +1.238841E+00 +2.961209E+01 +4.384409E+00 +9.590517E-01 +4.598964E-03 +2.334140E+00 +2.724142E-02 +3.775670E+01 +7.127929E+00 +1.257245E+00 +7.903591E-03 +3.059883E+00 +4.681599E-02 +9.766116E+01 +4.768861E+01 +1.146720E+00 +6.574867E-03 +2.790922E+00 +3.894640E-02 +2.115194E+02 +2.237102E+02 +3.227768E-01 +5.209666E-04 +7.986886E-01 +3.189776E-03 +1.124581E+02 +6.324566E+01 +1.524925E+00 +1.163294E-02 +4.241501E+00 +8.999779E-02 +1.131371E+02 +6.400074E+01 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +5.356354E+01 +1.434539E+01 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +3.119742E+01 +4.866419E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +4.113468E+01 +8.460394E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +9.845352E+01 +4.846566E+01 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.893301E+02 +1.792354E+02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +9.700220E+01 +4.706127E+01 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +5.906713E+01 +1.744587E+01 +2.185187E+01 +2.388094E+00 +5.318307E+01 +1.414559E+01 +4.087272E+01 +8.353147E+00 +6.075495E+00 +1.845728E-01 +1.478654E+01 +1.093296E+00 +2.917985E+01 +4.257342E+00 +9.458963E-01 +4.473653E-03 +2.302122E+00 +2.649915E-02 +3.710467E+01 +6.883857E+00 +1.236140E+00 +7.640460E-03 +3.008517E+00 +4.525737E-02 +9.774718E+01 +4.777263E+01 +1.148515E+00 +6.595464E-03 +2.795291E+00 +3.906841E-02 +2.158096E+02 +2.328751E+02 +3.292123E-01 +5.419369E-04 +8.146129E-01 +3.318173E-03 +1.142483E+02 +6.527411E+01 +1.545376E+00 +1.194541E-02 +4.298386E+00 +9.241523E-02 +6.833010E+01 +2.334774E+01 +2.543913E+01 +3.236766E+00 +6.191375E+01 +1.917260E+01 +4.345497E+01 +9.442115E+00 +6.480429E+00 +2.100011E-01 +1.577207E+01 +1.243917E+00 +2.960280E+01 +4.381666E+00 +9.615896E-01 +4.623340E-03 +2.340316E+00 +2.738581E-02 +3.774398E+01 +7.123136E+00 +1.260577E+00 +7.945526E-03 +3.067991E+00 +4.706439E-02 +9.766957E+01 +4.769682E+01 +1.150177E+00 +6.614557E-03 +2.799334E+00 +3.918151E-02 +2.116379E+02 +2.239597E+02 +3.238415E-01 +5.244036E-04 +8.013232E-01 +3.210820E-03 +1.124869E+02 +6.327591E+01 +1.529132E+00 +1.169655E-02 +4.253202E+00 +9.048993E-02 +tally 2: +3.727212E-01 +6.946055E-04 +8.048859E-01 +3.239206E-03 +3.094670E-01 +4.788493E-04 +2.194460E-01 +2.407828E-04 +1.708591E-01 +1.459642E-04 +2.305151E-02 +2.656862E-06 +8.000704E-03 +3.200564E-07 +1.273273E-03 +8.106118E-09 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +3.327639E-01 +5.536592E-04 +7.185987E-01 +2.581921E-03 +2.762909E-01 +3.816833E-04 +1.959205E-01 +1.919242E-04 +1.525423E-01 +1.163458E-04 +2.058029E-02 +2.117742E-06 +7.142994E-03 +2.551118E-07 +1.136772E-03 +6.461253E-09 +3.721892E-01 +6.926241E-04 +8.037371E-01 +3.229967E-03 +3.090254E-01 +4.774833E-04 +2.191328E-01 +2.400960E-04 +1.706153E-01 +1.455479E-04 +2.301861E-02 +2.649283E-06 +7.989285E-03 +3.191434E-07 +1.271455E-03 +8.082994E-09 diff --git a/tests/regression_tests/random_ray_k_eff_mesh_kinetic/isotropic/results_true_4.dat b/tests/regression_tests/random_ray_k_eff_mesh_kinetic/isotropic/results_true_4.dat new file mode 100644 index 00000000000..c40bfbeff1b --- /dev/null +++ b/tests/regression_tests/random_ray_k_eff_mesh_kinetic/isotropic/results_true_4.dat @@ -0,0 +1,236 @@ +k-combined: +1.311387E+00 6.434473E-04 +tally 1: +6.851748E+01 +2.347622E+01 +2.543241E+01 +3.235134E+00 +6.189740E+01 +1.916293E+01 +4.353803E+01 +9.478273E+00 +6.473195E+00 +2.095344E-01 +1.575446E+01 +1.241152E+00 +2.964327E+01 +4.393647E+00 +9.600620E-01 +4.608659E-03 +2.336599E+00 +2.729885E-02 +3.779657E+01 +7.142988E+00 +1.258573E+00 +7.920299E-03 +3.063115E+00 +4.691496E-02 +9.776864E+01 +4.779363E+01 +1.147982E+00 +6.589347E-03 +2.793994E+00 +3.903218E-02 +2.117585E+02 +2.242162E+02 +3.231400E-01 +5.221396E-04 +7.995873E-01 +3.196958E-03 +1.125787E+02 +6.338133E+01 +1.526546E+00 +1.165769E-02 +4.246011E+00 +9.018927E-02 +1.132349E+02 +6.411143E+01 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +5.361459E+01 +1.437275E+01 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +3.123068E+01 +4.876801E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +4.117905E+01 +8.478656E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +9.856276E+01 +4.857326E+01 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.895448E+02 +1.796421E+02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +9.710707E+01 +4.716308E+01 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +5.911296E+01 +1.747295E+01 +2.186901E+01 +2.391843E+00 +5.322479E+01 +1.416780E+01 +4.091071E+01 +8.368683E+00 +6.081156E+00 +1.849170E-01 +1.480032E+01 +1.095334E+00 +2.921048E+01 +4.266284E+00 +9.468900E-01 +4.483057E-03 +2.304541E+00 +2.655486E-02 +3.714360E+01 +6.898309E+00 +1.237438E+00 +7.656521E-03 +3.011678E+00 +4.535250E-02 +9.785441E+01 +4.787751E+01 +1.149776E+00 +6.609946E-03 +2.798358E+00 +3.915419E-02 +2.160533E+02 +2.334013E+02 +3.295823E-01 +5.431557E-04 +8.155283E-01 +3.325636E-03 +1.143707E+02 +6.541399E+01 +1.547017E+00 +1.197080E-02 +4.302951E+00 +9.261162E-02 +6.838436E+01 +2.338484E+01 +2.545955E+01 +3.241965E+00 +6.196345E+01 +1.920339E+01 +4.349538E+01 +9.459686E+00 +6.486469E+00 +2.103927E-01 +1.578677E+01 +1.246237E+00 +2.963397E+01 +4.390897E+00 +9.626025E-01 +4.633085E-03 +2.342782E+00 +2.744353E-02 +3.778382E+01 +7.138181E+00 +1.261908E+00 +7.962318E-03 +3.071232E+00 +4.716386E-02 +9.777704E+01 +4.780184E+01 +1.151442E+00 +6.629123E-03 +2.802415E+00 +3.926779E-02 +2.118771E+02 +2.244662E+02 +3.242060E-01 +5.255844E-04 +8.022250E-01 +3.218051E-03 +1.126075E+02 +6.341165E+01 +1.530758E+00 +1.172145E-02 +4.257726E+00 +9.068250E-02 +tally 2: +3.727213E-01 +6.946060E-04 +8.048865E-01 +3.239212E-03 +3.094674E-01 +4.788505E-04 +2.194469E-01 +2.407847E-04 +1.708606E-01 +1.459668E-04 +2.305197E-02 +2.656966E-06 +8.001084E-03 +3.200867E-07 +1.273400E-03 +8.107735E-09 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +3.327641E-01 +5.536596E-04 +7.185993E-01 +2.581925E-03 +2.762912E-01 +3.816842E-04 +1.959213E-01 +1.919257E-04 +1.525436E-01 +1.163478E-04 +2.058070E-02 +2.117825E-06 +7.143330E-03 +2.551359E-07 +1.136885E-03 +6.462534E-09 +3.721894E-01 +6.926247E-04 +8.037378E-01 +3.229972E-03 +3.090257E-01 +4.774846E-04 +2.191337E-01 +2.400979E-04 +1.706168E-01 +1.455504E-04 +2.301907E-02 +2.649387E-06 +7.989664E-03 +3.191736E-07 +1.271582E-03 +8.084606E-09 diff --git a/tests/regression_tests/random_ray_k_eff_mesh_kinetic/isotropic/results_true_5.dat b/tests/regression_tests/random_ray_k_eff_mesh_kinetic/isotropic/results_true_5.dat new file mode 100644 index 00000000000..934aa0bb4e0 --- /dev/null +++ b/tests/regression_tests/random_ray_k_eff_mesh_kinetic/isotropic/results_true_5.dat @@ -0,0 +1,236 @@ +k-combined: +1.311387E+00 6.434473E-04 +tally 1: +6.857313E+01 +2.351436E+01 +2.545329E+01 +3.240447E+00 +6.194820E+01 +1.919440E+01 +4.357930E+01 +9.496249E+00 +6.479343E+00 +2.099326E-01 +1.576943E+01 +1.243511E+00 +2.967500E+01 +4.403058E+00 +9.610902E-01 +4.618536E-03 +2.339101E+00 +2.735735E-02 +3.783713E+01 +7.158328E+00 +1.259925E+00 +7.937318E-03 +3.066405E+00 +4.701577E-02 +9.787794E+01 +4.790055E+01 +1.149266E+00 +6.604089E-03 +2.797118E+00 +3.911950E-02 +2.120015E+02 +2.247312E+02 +3.235092E-01 +5.233335E-04 +8.005010E-01 +3.204269E-03 +1.127013E+02 +6.351950E+01 +1.528196E+00 +1.168290E-02 +4.250600E+00 +9.038432E-02 +1.133347E+02 +6.422456E+01 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +5.366664E+01 +1.440067E+01 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +3.126452E+01 +4.887375E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +4.122419E+01 +8.497255E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +9.867383E+01 +4.868280E+01 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.897631E+02 +1.800561E+02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +9.721376E+01 +4.726677E+01 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +5.915985E+01 +1.750069E+01 +2.188655E+01 +2.395681E+00 +5.326748E+01 +1.419053E+01 +4.094945E+01 +8.384540E+00 +6.086930E+00 +1.852683E-01 +1.481437E+01 +1.097415E+00 +2.924165E+01 +4.275395E+00 +9.479013E-01 +4.492638E-03 +2.307002E+00 +2.661161E-02 +3.718322E+01 +6.913032E+00 +1.238760E+00 +7.672882E-03 +3.014894E+00 +4.544942E-02 +9.796347E+01 +4.798428E+01 +1.151057E+00 +6.624691E-03 +2.801478E+00 +3.924154E-02 +2.163011E+02 +2.339368E+02 +3.299585E-01 +5.443962E-04 +8.164591E-01 +3.333231E-03 +1.144952E+02 +6.555647E+01 +1.548688E+00 +1.199666E-02 +4.307596E+00 +9.281167E-02 +6.843986E+01 +2.342281E+01 +2.548043E+01 +3.247285E+00 +6.201427E+01 +1.923491E+01 +4.353660E+01 +9.477621E+00 +6.492628E+00 +2.107925E-01 +1.580176E+01 +1.248604E+00 +2.966568E+01 +4.400301E+00 +9.636332E-01 +4.643013E-03 +2.345290E+00 +2.750234E-02 +3.782436E+01 +7.153506E+00 +1.263263E+00 +7.979425E-03 +3.074529E+00 +4.726518E-02 +9.788634E+01 +4.790877E+01 +1.152730E+00 +6.643954E-03 +2.805548E+00 +3.935564E-02 +2.121203E+02 +2.249818E+02 +3.245765E-01 +5.267864E-04 +8.031417E-01 +3.225410E-03 +1.127302E+02 +6.354990E+01 +1.532413E+00 +1.174680E-02 +4.262329E+00 +9.087867E-02 +tally 2: +3.727215E-01 +6.946067E-04 +8.048874E-01 +3.239219E-03 +3.094679E-01 +4.788521E-04 +2.194480E-01 +2.407872E-04 +1.708625E-01 +1.459700E-04 +2.305255E-02 +2.657101E-06 +8.001572E-03 +3.201258E-07 +1.273562E-03 +8.109799E-09 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +3.327642E-01 +5.536601E-04 +7.186001E-01 +2.581931E-03 +2.762917E-01 +3.816855E-04 +1.959223E-01 +1.919277E-04 +1.525453E-01 +1.163504E-04 +2.058122E-02 +2.117932E-06 +7.143764E-03 +2.551668E-07 +1.137028E-03 +6.464168E-09 +3.721896E-01 +6.926253E-04 +8.037386E-01 +3.229979E-03 +3.090263E-01 +4.774861E-04 +2.191348E-01 +2.401004E-04 +1.706187E-01 +1.455537E-04 +2.301965E-02 +2.649522E-06 +7.990151E-03 +3.192126E-07 +1.271744E-03 +8.086663E-09 diff --git a/tests/regression_tests/random_ray_k_eff_mesh_kinetic/propagation/inputs_true.dat b/tests/regression_tests/random_ray_k_eff_mesh_kinetic/propagation/inputs_true.dat new file mode 100644 index 00000000000..4040f8f18be --- /dev/null +++ b/tests/regression_tests/random_ray_k_eff_mesh_kinetic/propagation/inputs_true.dat @@ -0,0 +1,138 @@ + + + + mgxs.h5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0.126 0.126 + 10 10 + -0.63 -0.63 + +10 10 10 10 10 10 10 10 10 10 +10 10 10 10 10 10 10 10 10 10 +10 10 10 10 10 10 10 10 10 10 +10 10 10 10 10 10 10 10 10 10 +10 10 10 10 10 10 10 10 10 10 +10 10 10 10 10 10 10 10 10 10 +10 10 10 10 10 10 10 10 10 10 +10 10 10 10 10 10 10 10 10 10 +10 10 10 10 10 10 10 10 10 10 +10 10 10 10 10 10 10 10 10 10 + + + 1.26 1.26 + 2 2 + -1.26 -1.26 + +9 9 +9 12 + + + + + + + + + + + + + + + + + + + + + eigenvalue + 100 + 400 + 200 + true + +
0.01
+ 5 + s +
+ multi-group + + 100.0 + 20.0 + + + -1.26 -1.26 -1 1.26 1.26 1 + + + true + 3 + propagation + + + + + + + + 40 40 + -1.26 -1.26 + 1.26 1.26 + +
+ + + 2 2 + -1.26 -1.26 + 1.26 1.26 + + + 3 + + + 1e-05 0.0635 10.0 100.0 1000.0 500000.0 1000000.0 20000000.0 + + + 1 2 3 4 5 6 7 8 + + + 4 5 + flux fission nu-fission + analog + + + 4 6 + precursors + + +
diff --git a/tests/regression_tests/random_ray_k_eff_mesh_kinetic/propagation/results_error_2.dat b/tests/regression_tests/random_ray_k_eff_mesh_kinetic/propagation/results_error_2.dat new file mode 100644 index 00000000000..3d87c1ff778 --- /dev/null +++ b/tests/regression_tests/random_ray_k_eff_mesh_kinetic/propagation/results_error_2.dat @@ -0,0 +1,236 @@ +k-combined: +1.311387E+00 6.434473E-04 +tally 1: +6.841002E+01 +2.340263E+01 +2.539209E+01 +3.224884E+00 +6.179927E+01 +1.910222E+01 +4.345795E+01 +9.443438E+00 +6.461264E+00 +2.087627E-01 +1.572542E+01 +1.236581E+00 +2.958149E+01 +4.375353E+00 +9.580602E-01 +4.589460E-03 +2.331727E+00 +2.718512E-02 +3.771759E+01 +7.113168E+00 +1.255942E+00 +7.887213E-03 +3.056711E+00 +4.671898E-02 +9.755563E+01 +4.758560E+01 +1.145481E+00 +6.560664E-03 +2.787906E+00 +3.886227E-02 +2.112846E+02 +2.232138E+02 +3.224201E-01 +5.198159E-04 +7.978060E-01 +3.182731E-03 +1.123398E+02 +6.311270E+01 +1.523334E+00 +1.160869E-02 +4.237076E+00 +8.981014E-02 +1.130415E+02 +6.389267E+01 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +5.351354E+01 +1.431862E+01 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +3.116478E+01 +4.856241E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +4.109112E+01 +8.442486E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +9.834626E+01 +4.836011E+01 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.891192E+02 +1.788363E+02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +9.689929E+01 +4.696147E+01 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +5.902247E+01 +1.741950E+01 +2.183516E+01 +2.384443E+00 +5.314240E+01 +1.412397E+01 +4.083553E+01 +8.337955E+00 +6.069953E+00 +1.842363E-01 +1.477305E+01 +1.091302E+00 +2.914979E+01 +4.248577E+00 +9.449213E-01 +4.464435E-03 +2.299749E+00 +2.644455E-02 +3.706648E+01 +6.869692E+00 +1.234866E+00 +7.624718E-03 +3.005416E+00 +4.516412E-02 +9.764189E+01 +4.766978E+01 +1.147278E+00 +6.581260E-03 +2.792280E+00 +3.898427E-02 +2.155703E+02 +2.323588E+02 +3.288490E-01 +5.407413E-04 +8.137138E-01 +3.310853E-03 +1.141283E+02 +6.513702E+01 +1.543766E+00 +1.192054E-02 +4.293907E+00 +9.222278E-02 +6.827719E+01 +2.331160E+01 +2.541921E+01 +3.231700E+00 +6.186528E+01 +1.914259E+01 +4.341541E+01 +9.424932E+00 +6.474517E+00 +2.096181E-01 +1.575768E+01 +1.241648E+00 +2.957222E+01 +4.372617E+00 +9.605956E-01 +4.613787E-03 +2.337897E+00 +2.732922E-02 +3.770489E+01 +7.108388E+00 +1.259270E+00 +7.929065E-03 +3.064812E+00 +4.696688E-02 +9.756404E+01 +4.759381E+01 +1.148934E+00 +6.600271E-03 +2.796309E+00 +3.909688E-02 +2.114029E+02 +2.234627E+02 +3.234836E-01 +5.232451E-04 +8.004376E-01 +3.203727E-03 +1.123686E+02 +6.314288E+01 +1.527536E+00 +1.167216E-02 +4.248764E+00 +9.030121E-02 +tally 2: +3.727211E-01 +6.946052E-04 +8.048854E-01 +3.239203E-03 +3.094668E-01 +4.788484E-04 +2.194454E-01 +2.407815E-04 +1.708581E-01 +1.459624E-04 +2.305119E-02 +2.656788E-06 +8.000435E-03 +3.200348E-07 +1.273182E-03 +8.104960E-09 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +3.327638E-01 +5.536589E-04 +7.185983E-01 +2.581918E-03 +2.762906E-01 +3.816826E-04 +1.959200E-01 +1.919231E-04 +1.525414E-01 +1.163444E-04 +2.058001E-02 +2.117684E-06 +7.142754E-03 +2.550947E-07 +1.136691E-03 +6.460334E-09 +3.721891E-01 +6.926238E-04 +8.037366E-01 +3.229963E-03 +3.090251E-01 +4.774825E-04 +2.191322E-01 +2.400946E-04 +1.706142E-01 +1.455461E-04 +2.301829E-02 +2.649209E-06 +7.989016E-03 +3.191219E-07 +1.271365E-03 +8.081840E-09 diff --git a/tests/regression_tests/random_ray_k_eff_mesh_kinetic/propagation/results_true_0.dat b/tests/regression_tests/random_ray_k_eff_mesh_kinetic/propagation/results_true_0.dat new file mode 100644 index 00000000000..b7863f78005 --- /dev/null +++ b/tests/regression_tests/random_ray_k_eff_mesh_kinetic/propagation/results_true_0.dat @@ -0,0 +1,236 @@ +k-combined: +1.311387E+00 6.434473E-04 +tally 1: +6.829734E+01 +2.332560E+01 +2.535005E+01 +3.214213E+00 +6.169695E+01 +1.903901E+01 +4.338057E+01 +9.409840E+00 +6.449747E+00 +2.080191E-01 +1.569739E+01 +1.232177E+00 +2.952526E+01 +4.358735E+00 +9.562385E-01 +4.572024E-03 +2.327293E+00 +2.708184E-02 +3.764580E+01 +7.086116E+00 +1.253550E+00 +7.857205E-03 +3.050891E+00 +4.654123E-02 +9.736564E+01 +4.740043E+01 +1.143250E+00 +6.535133E-03 +2.782476E+00 +3.871104E-02 +2.108671E+02 +2.223325E+02 +3.217847E-01 +5.177688E-04 +7.962336E-01 +3.170197E-03 +1.121239E+02 +6.287031E+01 +1.520419E+00 +1.156430E-02 +4.228968E+00 +8.946678E-02 +1.128474E+02 +6.367345E+01 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +5.341703E+01 +1.426702E+01 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +3.110513E+01 +4.837669E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +4.101197E+01 +8.409994E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +9.815385E+01 +4.817107E+01 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.887447E+02 +1.781287E+02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +9.671216E+01 +4.678026E+01 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +5.892637E+01 +1.736282E+01 +2.179942E+01 +2.376644E+00 +5.305542E+01 +1.407777E+01 +4.076286E+01 +8.308305E+00 +6.059136E+00 +1.835802E-01 +1.474673E+01 +1.087416E+00 +2.909448E+01 +4.232468E+00 +9.431274E-01 +4.447499E-03 +2.295383E+00 +2.634424E-02 +3.699617E+01 +6.843656E+00 +1.232522E+00 +7.595798E-03 +2.999711E+00 +4.499282E-02 +9.745207E+01 +4.748461E+01 +1.145047E+00 +6.555693E-03 +2.786851E+00 +3.883283E-02 +2.151446E+02 +2.314420E+02 +3.282013E-01 +5.386136E-04 +8.121113E-01 +3.297825E-03 +1.139091E+02 +6.488702E+01 +1.540814E+00 +1.187500E-02 +4.285697E+00 +9.187046E-02 +6.816479E+01 +2.323491E+01 +2.537715E+01 +3.221014E+00 +6.176291E+01 +1.907929E+01 +4.333813E+01 +9.391406E+00 +6.462978E+00 +2.088716E-01 +1.572960E+01 +1.237227E+00 +2.951601E+01 +4.356011E+00 +9.587693E-01 +4.596260E-03 +2.333452E+00 +2.722540E-02 +3.763313E+01 +7.081357E+00 +1.256873E+00 +7.898901E-03 +3.058977E+00 +4.678821E-02 +9.737405E+01 +4.740862E+01 +1.146696E+00 +6.574588E-03 +2.790864E+00 +3.894475E-02 +2.109852E+02 +2.225806E+02 +3.228462E-01 +5.211850E-04 +7.988604E-01 +3.191114E-03 +1.121527E+02 +6.290039E+01 +1.524613E+00 +1.162754E-02 +4.240634E+00 +8.995597E-02 +tally 2: +3.727239E-01 +6.947125E-04 +8.048913E-01 +3.239702E-03 +3.094690E-01 +4.789219E-04 +2.194466E-01 +2.408177E-04 +1.708586E-01 +1.459836E-04 +2.305111E-02 +2.657139E-06 +8.000274E-03 +3.200666E-07 +1.273116E-03 +8.105247E-09 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +3.327663E-01 +5.537155E-04 +7.186034E-01 +2.582180E-03 +2.762925E-01 +3.817212E-04 +1.959210E-01 +1.919420E-04 +1.525418E-01 +1.163551E-04 +2.057993E-02 +2.117853E-06 +7.142610E-03 +2.551067E-07 +1.136632E-03 +6.460228E-09 +3.721919E-01 +6.927141E-04 +8.037423E-01 +3.230382E-03 +3.090272E-01 +4.775443E-04 +2.191334E-01 +2.401250E-04 +1.706146E-01 +1.455636E-04 +2.301820E-02 +2.649495E-06 +7.988854E-03 +3.191459E-07 +1.271298E-03 +8.081932E-09 diff --git a/tests/regression_tests/random_ray_k_eff_mesh_kinetic/propagation/results_true_1.dat b/tests/regression_tests/random_ray_k_eff_mesh_kinetic/propagation/results_true_1.dat new file mode 100644 index 00000000000..25731b9a04d --- /dev/null +++ b/tests/regression_tests/random_ray_k_eff_mesh_kinetic/propagation/results_true_1.dat @@ -0,0 +1,236 @@ +k-combined: +1.311387E+00 6.434473E-04 +tally 1: +6.835752E+01 +2.336672E+01 +2.537238E+01 +3.219879E+00 +6.175130E+01 +1.907257E+01 +4.341875E+01 +9.426410E+00 +6.455423E+00 +2.083854E-01 +1.571121E+01 +1.234346E+00 +2.955121E+01 +4.366400E+00 +9.570789E-01 +4.580063E-03 +2.329338E+00 +2.712946E-02 +3.767887E+01 +7.098572E+00 +1.254652E+00 +7.871018E-03 +3.053571E+00 +4.662305E-02 +9.745113E+01 +4.748370E+01 +1.144254E+00 +6.546614E-03 +2.784919E+00 +3.877905E-02 +2.110519E+02 +2.227224E+02 +3.220667E-01 +5.186767E-04 +7.969314E-01 +3.175756E-03 +1.122226E+02 +6.298103E+01 +1.521757E+00 +1.158467E-02 +4.232690E+00 +8.962434E-02 +1.129469E+02 +6.378582E+01 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +5.346406E+01 +1.429216E+01 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +3.113246E+01 +4.846176E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +4.104800E+01 +8.424776E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +9.824002E+01 +4.825568E+01 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.889102E+02 +1.784412E+02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +9.679727E+01 +4.686264E+01 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +5.897826E+01 +1.739342E+01 +2.181861E+01 +2.380831E+00 +5.310214E+01 +1.410257E+01 +4.079873E+01 +8.322934E+00 +6.064468E+00 +1.839035E-01 +1.475970E+01 +1.089331E+00 +2.912005E+01 +4.239911E+00 +9.439562E-01 +4.455320E-03 +2.297400E+00 +2.639056E-02 +3.702868E+01 +6.855687E+00 +1.233605E+00 +7.609152E-03 +3.002347E+00 +4.507192E-02 +9.753763E+01 +4.756803E+01 +1.146053E+00 +6.567210E-03 +2.789297E+00 +3.890105E-02 +2.153331E+02 +2.318478E+02 +3.284889E-01 +5.395577E-04 +8.128227E-01 +3.303606E-03 +1.140093E+02 +6.500127E+01 +1.542170E+00 +1.189591E-02 +4.289468E+00 +9.203221E-02 +6.822483E+01 +2.327586E+01 +2.539950E+01 +3.226689E+00 +6.181730E+01 +1.911291E+01 +4.337627E+01 +9.407943E+00 +6.468666E+00 +2.092394E-01 +1.574344E+01 +1.239405E+00 +2.954195E+01 +4.363671E+00 +9.596119E-01 +4.604342E-03 +2.335503E+00 +2.727327E-02 +3.766620E+01 +7.093806E+00 +1.257977E+00 +7.912788E-03 +3.061664E+00 +4.687047E-02 +9.745954E+01 +4.749190E+01 +1.147703E+00 +6.586137E-03 +2.793314E+00 +3.901316E-02 +2.111701E+02 +2.229707E+02 +3.231290E-01 +5.220983E-04 +7.995600E-01 +3.196706E-03 +1.122513E+02 +6.301114E+01 +1.525955E+00 +1.164801E-02 +4.244366E+00 +9.011434E-02 +tally 2: +3.727210E-01 +6.946049E-04 +8.048851E-01 +3.239200E-03 +3.094666E-01 +4.788479E-04 +2.194451E-01 +2.407807E-04 +1.708575E-01 +1.459614E-04 +2.305100E-02 +2.656744E-06 +8.000275E-03 +3.200220E-07 +1.273127E-03 +8.104266E-09 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +3.327638E-01 +5.536587E-04 +7.185980E-01 +2.581916E-03 +2.762905E-01 +3.816822E-04 +1.959196E-01 +1.919225E-04 +1.525408E-01 +1.163435E-04 +2.057984E-02 +2.117649E-06 +7.142612E-03 +2.550845E-07 +1.136643E-03 +6.459783E-09 +3.721891E-01 +6.926236E-04 +8.037363E-01 +3.229960E-03 +3.090249E-01 +4.774820E-04 +2.191319E-01 +2.400939E-04 +1.706136E-01 +1.455450E-04 +2.301810E-02 +2.649166E-06 +7.988856E-03 +3.191091E-07 +1.271310E-03 +8.081148E-09 diff --git a/tests/regression_tests/random_ray_k_eff_mesh_kinetic/propagation/results_true_2.dat b/tests/regression_tests/random_ray_k_eff_mesh_kinetic/propagation/results_true_2.dat new file mode 100644 index 00000000000..3d87c1ff778 --- /dev/null +++ b/tests/regression_tests/random_ray_k_eff_mesh_kinetic/propagation/results_true_2.dat @@ -0,0 +1,236 @@ +k-combined: +1.311387E+00 6.434473E-04 +tally 1: +6.841002E+01 +2.340263E+01 +2.539209E+01 +3.224884E+00 +6.179927E+01 +1.910222E+01 +4.345795E+01 +9.443438E+00 +6.461264E+00 +2.087627E-01 +1.572542E+01 +1.236581E+00 +2.958149E+01 +4.375353E+00 +9.580602E-01 +4.589460E-03 +2.331727E+00 +2.718512E-02 +3.771759E+01 +7.113168E+00 +1.255942E+00 +7.887213E-03 +3.056711E+00 +4.671898E-02 +9.755563E+01 +4.758560E+01 +1.145481E+00 +6.560664E-03 +2.787906E+00 +3.886227E-02 +2.112846E+02 +2.232138E+02 +3.224201E-01 +5.198159E-04 +7.978060E-01 +3.182731E-03 +1.123398E+02 +6.311270E+01 +1.523334E+00 +1.160869E-02 +4.237076E+00 +8.981014E-02 +1.130415E+02 +6.389267E+01 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +5.351354E+01 +1.431862E+01 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +3.116478E+01 +4.856241E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +4.109112E+01 +8.442486E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +9.834626E+01 +4.836011E+01 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.891192E+02 +1.788363E+02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +9.689929E+01 +4.696147E+01 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +5.902247E+01 +1.741950E+01 +2.183516E+01 +2.384443E+00 +5.314240E+01 +1.412397E+01 +4.083553E+01 +8.337955E+00 +6.069953E+00 +1.842363E-01 +1.477305E+01 +1.091302E+00 +2.914979E+01 +4.248577E+00 +9.449213E-01 +4.464435E-03 +2.299749E+00 +2.644455E-02 +3.706648E+01 +6.869692E+00 +1.234866E+00 +7.624718E-03 +3.005416E+00 +4.516412E-02 +9.764189E+01 +4.766978E+01 +1.147278E+00 +6.581260E-03 +2.792280E+00 +3.898427E-02 +2.155703E+02 +2.323588E+02 +3.288490E-01 +5.407413E-04 +8.137138E-01 +3.310853E-03 +1.141283E+02 +6.513702E+01 +1.543766E+00 +1.192054E-02 +4.293907E+00 +9.222278E-02 +6.827719E+01 +2.331160E+01 +2.541921E+01 +3.231700E+00 +6.186528E+01 +1.914259E+01 +4.341541E+01 +9.424932E+00 +6.474517E+00 +2.096181E-01 +1.575768E+01 +1.241648E+00 +2.957222E+01 +4.372617E+00 +9.605956E-01 +4.613787E-03 +2.337897E+00 +2.732922E-02 +3.770489E+01 +7.108388E+00 +1.259270E+00 +7.929065E-03 +3.064812E+00 +4.696688E-02 +9.756404E+01 +4.759381E+01 +1.148934E+00 +6.600271E-03 +2.796309E+00 +3.909688E-02 +2.114029E+02 +2.234627E+02 +3.234836E-01 +5.232451E-04 +8.004376E-01 +3.203727E-03 +1.123686E+02 +6.314288E+01 +1.527536E+00 +1.167216E-02 +4.248764E+00 +9.030121E-02 +tally 2: +3.727211E-01 +6.946052E-04 +8.048854E-01 +3.239203E-03 +3.094668E-01 +4.788484E-04 +2.194454E-01 +2.407815E-04 +1.708581E-01 +1.459624E-04 +2.305119E-02 +2.656788E-06 +8.000435E-03 +3.200348E-07 +1.273182E-03 +8.104960E-09 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +3.327638E-01 +5.536589E-04 +7.185983E-01 +2.581918E-03 +2.762906E-01 +3.816826E-04 +1.959200E-01 +1.919231E-04 +1.525414E-01 +1.163444E-04 +2.058001E-02 +2.117684E-06 +7.142754E-03 +2.550947E-07 +1.136691E-03 +6.460334E-09 +3.721891E-01 +6.926238E-04 +8.037366E-01 +3.229963E-03 +3.090251E-01 +4.774825E-04 +2.191322E-01 +2.400946E-04 +1.706142E-01 +1.455461E-04 +2.301829E-02 +2.649209E-06 +7.989016E-03 +3.191219E-07 +1.271365E-03 +8.081840E-09 diff --git a/tests/regression_tests/random_ray_k_eff_mesh_kinetic/propagation/results_true_3.dat b/tests/regression_tests/random_ray_k_eff_mesh_kinetic/propagation/results_true_3.dat new file mode 100644 index 00000000000..f5d2338864e --- /dev/null +++ b/tests/regression_tests/random_ray_k_eff_mesh_kinetic/propagation/results_true_3.dat @@ -0,0 +1,236 @@ +k-combined: +1.311387E+00 6.434473E-04 +tally 1: +6.846308E+01 +2.343895E+01 +2.541200E+01 +3.229943E+00 +6.184772E+01 +1.913218E+01 +4.349756E+01 +9.460661E+00 +6.467166E+00 +2.091442E-01 +1.573979E+01 +1.238841E+00 +2.961209E+01 +4.384409E+00 +9.590517E-01 +4.598964E-03 +2.334140E+00 +2.724142E-02 +3.775670E+01 +7.127929E+00 +1.257245E+00 +7.903591E-03 +3.059883E+00 +4.681599E-02 +9.766116E+01 +4.768861E+01 +1.146720E+00 +6.574867E-03 +2.790922E+00 +3.894640E-02 +2.115194E+02 +2.237102E+02 +3.227768E-01 +5.209666E-04 +7.986886E-01 +3.189776E-03 +1.124581E+02 +6.324566E+01 +1.524925E+00 +1.163294E-02 +4.241501E+00 +8.999779E-02 +1.131371E+02 +6.400074E+01 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +5.356354E+01 +1.434539E+01 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +3.119742E+01 +4.866419E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +4.113468E+01 +8.460394E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +9.845352E+01 +4.846566E+01 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.893301E+02 +1.792354E+02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +9.700220E+01 +4.706127E+01 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +5.906713E+01 +1.744587E+01 +2.185187E+01 +2.388094E+00 +5.318307E+01 +1.414559E+01 +4.087272E+01 +8.353147E+00 +6.075495E+00 +1.845728E-01 +1.478654E+01 +1.093296E+00 +2.917985E+01 +4.257342E+00 +9.458963E-01 +4.473653E-03 +2.302122E+00 +2.649915E-02 +3.710467E+01 +6.883857E+00 +1.236140E+00 +7.640460E-03 +3.008517E+00 +4.525737E-02 +9.774718E+01 +4.777263E+01 +1.148515E+00 +6.595464E-03 +2.795291E+00 +3.906841E-02 +2.158096E+02 +2.328751E+02 +3.292123E-01 +5.419369E-04 +8.146129E-01 +3.318173E-03 +1.142483E+02 +6.527411E+01 +1.545376E+00 +1.194541E-02 +4.298386E+00 +9.241523E-02 +6.833010E+01 +2.334774E+01 +2.543913E+01 +3.236766E+00 +6.191375E+01 +1.917260E+01 +4.345497E+01 +9.442115E+00 +6.480429E+00 +2.100011E-01 +1.577207E+01 +1.243917E+00 +2.960280E+01 +4.381666E+00 +9.615896E-01 +4.623340E-03 +2.340316E+00 +2.738581E-02 +3.774398E+01 +7.123136E+00 +1.260577E+00 +7.945526E-03 +3.067991E+00 +4.706439E-02 +9.766957E+01 +4.769682E+01 +1.150177E+00 +6.614557E-03 +2.799334E+00 +3.918151E-02 +2.116379E+02 +2.239597E+02 +3.238415E-01 +5.244036E-04 +8.013232E-01 +3.210820E-03 +1.124869E+02 +6.327591E+01 +1.529132E+00 +1.169655E-02 +4.253202E+00 +9.048993E-02 +tally 2: +3.727212E-01 +6.946055E-04 +8.048859E-01 +3.239206E-03 +3.094670E-01 +4.788493E-04 +2.194460E-01 +2.407828E-04 +1.708591E-01 +1.459642E-04 +2.305151E-02 +2.656862E-06 +8.000704E-03 +3.200564E-07 +1.273273E-03 +8.106118E-09 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +3.327639E-01 +5.536592E-04 +7.185987E-01 +2.581921E-03 +2.762909E-01 +3.816833E-04 +1.959205E-01 +1.919242E-04 +1.525423E-01 +1.163458E-04 +2.058029E-02 +2.117742E-06 +7.142994E-03 +2.551118E-07 +1.136772E-03 +6.461253E-09 +3.721892E-01 +6.926241E-04 +8.037371E-01 +3.229967E-03 +3.090254E-01 +4.774833E-04 +2.191328E-01 +2.400960E-04 +1.706153E-01 +1.455479E-04 +2.301861E-02 +2.649283E-06 +7.989285E-03 +3.191434E-07 +1.271455E-03 +8.082994E-09 diff --git a/tests/regression_tests/random_ray_k_eff_mesh_kinetic/propagation/results_true_4.dat b/tests/regression_tests/random_ray_k_eff_mesh_kinetic/propagation/results_true_4.dat new file mode 100644 index 00000000000..c40bfbeff1b --- /dev/null +++ b/tests/regression_tests/random_ray_k_eff_mesh_kinetic/propagation/results_true_4.dat @@ -0,0 +1,236 @@ +k-combined: +1.311387E+00 6.434473E-04 +tally 1: +6.851748E+01 +2.347622E+01 +2.543241E+01 +3.235134E+00 +6.189740E+01 +1.916293E+01 +4.353803E+01 +9.478273E+00 +6.473195E+00 +2.095344E-01 +1.575446E+01 +1.241152E+00 +2.964327E+01 +4.393647E+00 +9.600620E-01 +4.608659E-03 +2.336599E+00 +2.729885E-02 +3.779657E+01 +7.142988E+00 +1.258573E+00 +7.920299E-03 +3.063115E+00 +4.691496E-02 +9.776864E+01 +4.779363E+01 +1.147982E+00 +6.589347E-03 +2.793994E+00 +3.903218E-02 +2.117585E+02 +2.242162E+02 +3.231400E-01 +5.221396E-04 +7.995873E-01 +3.196958E-03 +1.125787E+02 +6.338133E+01 +1.526546E+00 +1.165769E-02 +4.246011E+00 +9.018927E-02 +1.132349E+02 +6.411143E+01 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +5.361459E+01 +1.437275E+01 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +3.123068E+01 +4.876801E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +4.117905E+01 +8.478656E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +9.856276E+01 +4.857326E+01 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.895448E+02 +1.796421E+02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +9.710707E+01 +4.716308E+01 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +5.911296E+01 +1.747295E+01 +2.186901E+01 +2.391843E+00 +5.322479E+01 +1.416780E+01 +4.091071E+01 +8.368683E+00 +6.081156E+00 +1.849170E-01 +1.480032E+01 +1.095334E+00 +2.921048E+01 +4.266284E+00 +9.468900E-01 +4.483057E-03 +2.304541E+00 +2.655486E-02 +3.714360E+01 +6.898309E+00 +1.237438E+00 +7.656521E-03 +3.011678E+00 +4.535250E-02 +9.785441E+01 +4.787751E+01 +1.149776E+00 +6.609946E-03 +2.798358E+00 +3.915419E-02 +2.160533E+02 +2.334013E+02 +3.295823E-01 +5.431557E-04 +8.155283E-01 +3.325636E-03 +1.143707E+02 +6.541399E+01 +1.547017E+00 +1.197080E-02 +4.302951E+00 +9.261162E-02 +6.838436E+01 +2.338484E+01 +2.545955E+01 +3.241965E+00 +6.196345E+01 +1.920339E+01 +4.349538E+01 +9.459686E+00 +6.486469E+00 +2.103927E-01 +1.578677E+01 +1.246237E+00 +2.963397E+01 +4.390897E+00 +9.626025E-01 +4.633085E-03 +2.342782E+00 +2.744353E-02 +3.778382E+01 +7.138181E+00 +1.261908E+00 +7.962318E-03 +3.071232E+00 +4.716386E-02 +9.777704E+01 +4.780184E+01 +1.151442E+00 +6.629123E-03 +2.802415E+00 +3.926779E-02 +2.118771E+02 +2.244662E+02 +3.242060E-01 +5.255844E-04 +8.022250E-01 +3.218051E-03 +1.126075E+02 +6.341165E+01 +1.530758E+00 +1.172145E-02 +4.257726E+00 +9.068250E-02 +tally 2: +3.727213E-01 +6.946060E-04 +8.048865E-01 +3.239212E-03 +3.094674E-01 +4.788505E-04 +2.194469E-01 +2.407847E-04 +1.708606E-01 +1.459668E-04 +2.305197E-02 +2.656966E-06 +8.001084E-03 +3.200867E-07 +1.273400E-03 +8.107735E-09 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +3.327641E-01 +5.536596E-04 +7.185993E-01 +2.581925E-03 +2.762912E-01 +3.816842E-04 +1.959213E-01 +1.919257E-04 +1.525436E-01 +1.163478E-04 +2.058070E-02 +2.117825E-06 +7.143330E-03 +2.551359E-07 +1.136885E-03 +6.462534E-09 +3.721894E-01 +6.926247E-04 +8.037378E-01 +3.229972E-03 +3.090257E-01 +4.774846E-04 +2.191337E-01 +2.400979E-04 +1.706168E-01 +1.455504E-04 +2.301907E-02 +2.649387E-06 +7.989664E-03 +3.191736E-07 +1.271582E-03 +8.084606E-09 diff --git a/tests/regression_tests/random_ray_k_eff_mesh_kinetic/propagation/results_true_5.dat b/tests/regression_tests/random_ray_k_eff_mesh_kinetic/propagation/results_true_5.dat new file mode 100644 index 00000000000..934aa0bb4e0 --- /dev/null +++ b/tests/regression_tests/random_ray_k_eff_mesh_kinetic/propagation/results_true_5.dat @@ -0,0 +1,236 @@ +k-combined: +1.311387E+00 6.434473E-04 +tally 1: +6.857313E+01 +2.351436E+01 +2.545329E+01 +3.240447E+00 +6.194820E+01 +1.919440E+01 +4.357930E+01 +9.496249E+00 +6.479343E+00 +2.099326E-01 +1.576943E+01 +1.243511E+00 +2.967500E+01 +4.403058E+00 +9.610902E-01 +4.618536E-03 +2.339101E+00 +2.735735E-02 +3.783713E+01 +7.158328E+00 +1.259925E+00 +7.937318E-03 +3.066405E+00 +4.701577E-02 +9.787794E+01 +4.790055E+01 +1.149266E+00 +6.604089E-03 +2.797118E+00 +3.911950E-02 +2.120015E+02 +2.247312E+02 +3.235092E-01 +5.233335E-04 +8.005010E-01 +3.204269E-03 +1.127013E+02 +6.351950E+01 +1.528196E+00 +1.168290E-02 +4.250600E+00 +9.038432E-02 +1.133347E+02 +6.422456E+01 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +5.366664E+01 +1.440067E+01 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +3.126452E+01 +4.887375E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +4.122419E+01 +8.497255E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +9.867383E+01 +4.868280E+01 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +1.897631E+02 +1.800561E+02 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +9.721376E+01 +4.726677E+01 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +5.915985E+01 +1.750069E+01 +2.188655E+01 +2.395681E+00 +5.326748E+01 +1.419053E+01 +4.094945E+01 +8.384540E+00 +6.086930E+00 +1.852683E-01 +1.481437E+01 +1.097415E+00 +2.924165E+01 +4.275395E+00 +9.479013E-01 +4.492638E-03 +2.307002E+00 +2.661161E-02 +3.718322E+01 +6.913032E+00 +1.238760E+00 +7.672882E-03 +3.014894E+00 +4.544942E-02 +9.796347E+01 +4.798428E+01 +1.151057E+00 +6.624691E-03 +2.801478E+00 +3.924154E-02 +2.163011E+02 +2.339368E+02 +3.299585E-01 +5.443962E-04 +8.164591E-01 +3.333231E-03 +1.144952E+02 +6.555647E+01 +1.548688E+00 +1.199666E-02 +4.307596E+00 +9.281167E-02 +6.843986E+01 +2.342281E+01 +2.548043E+01 +3.247285E+00 +6.201427E+01 +1.923491E+01 +4.353660E+01 +9.477621E+00 +6.492628E+00 +2.107925E-01 +1.580176E+01 +1.248604E+00 +2.966568E+01 +4.400301E+00 +9.636332E-01 +4.643013E-03 +2.345290E+00 +2.750234E-02 +3.782436E+01 +7.153506E+00 +1.263263E+00 +7.979425E-03 +3.074529E+00 +4.726518E-02 +9.788634E+01 +4.790877E+01 +1.152730E+00 +6.643954E-03 +2.805548E+00 +3.935564E-02 +2.121203E+02 +2.249818E+02 +3.245765E-01 +5.267864E-04 +8.031417E-01 +3.225410E-03 +1.127302E+02 +6.354990E+01 +1.532413E+00 +1.174680E-02 +4.262329E+00 +9.087867E-02 +tally 2: +3.727215E-01 +6.946067E-04 +8.048874E-01 +3.239219E-03 +3.094679E-01 +4.788521E-04 +2.194480E-01 +2.407872E-04 +1.708625E-01 +1.459700E-04 +2.305255E-02 +2.657101E-06 +8.001572E-03 +3.201258E-07 +1.273562E-03 +8.109799E-09 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +0.000000E+00 +3.327642E-01 +5.536601E-04 +7.186001E-01 +2.581931E-03 +2.762917E-01 +3.816855E-04 +1.959223E-01 +1.919277E-04 +1.525453E-01 +1.163504E-04 +2.058122E-02 +2.117932E-06 +7.143764E-03 +2.551668E-07 +1.137028E-03 +6.464168E-09 +3.721896E-01 +6.926253E-04 +8.037386E-01 +3.229979E-03 +3.090263E-01 +4.774861E-04 +2.191348E-01 +2.401004E-04 +1.706187E-01 +1.455537E-04 +2.301965E-02 +2.649522E-06 +7.990151E-03 +3.192126E-07 +1.271744E-03 +8.086663E-09 diff --git a/tests/regression_tests/random_ray_k_eff_mesh_kinetic/test.py b/tests/regression_tests/random_ray_k_eff_mesh_kinetic/test.py new file mode 100644 index 00000000000..1b082ca6078 --- /dev/null +++ b/tests/regression_tests/random_ray_k_eff_mesh_kinetic/test.py @@ -0,0 +1,45 @@ +import os + +import openmc +from openmc.utility_funcs import change_directory +from openmc.examples import random_ray_lattice +import pytest + +from tests.testing_harness import KineticTolerantPyAPITestHarness + + +class KineticMGXSTestHarness(KineticTolerantPyAPITestHarness): + def _cleanup(self): + super()._cleanup() + f = 'mgxs.h5' + if os.path.exists(f): + os.remove(f) + + +@pytest.mark.parametrize("time_method", ["isotropic", + "propagation"]) +def test_random_ray_k_eff_mesh(time_method): + with change_directory(time_method): + model = random_ray_lattice(kinetic=True) + model.settings.timestep_parameters['n_timesteps'] = 5 + model.settings.random_ray['time_method'] = time_method + model.settings.batches = 400 + model.settings.inactive = 200 + + # The model already has some geometrical subdivisions + # up to a 10x10 grid in the moderator region. So, we + # increase the resolution 40x40 applied over the full + # 2x2 lattice. + pitch = 1.26 + dim = 40 + mesh = openmc.RegularMesh() + mesh.dimension = (dim, dim) + mesh.lower_left = (-pitch, -pitch) + mesh.upper_right = (pitch, pitch) + + root = model.geometry.root_universe + + model.settings.random_ray['source_region_meshes'] = [(mesh, [root])] + + harness = KineticMGXSTestHarness('statepoint.400', 6, model) + harness.main() diff --git a/tests/testing_harness.py b/tests/testing_harness.py index 1ad91b7a89f..0adcc6c2825 100644 --- a/tests/testing_harness.py +++ b/tests/testing_harness.py @@ -87,6 +87,11 @@ def _get_results(self, hash_output=False): """Digest info in the statepoint and return as a string.""" # Read the statepoint file. statepoint = glob.glob(self._sp_name)[0] + return self._write_tallies(statepoint, hash_output) + + def _write_tallies(self, statepoint, hash_output): + """Get tally sum and sum_sq data from statepoint file + as a string""" with openmc.StatePoint(statepoint) as sp: outstr = '' if sp.run_mode == 'eigenvalue': @@ -285,6 +290,110 @@ def _cleanup(self): os.remove(f) +class KineticTestHarness(TestHarness): + """General class for running OpenMC regression tests for kinetic simulations.""" + + def __init__(self, statepoint_base, n_timesteps): + self._sp_base = statepoint_base + self._n_timesteps = n_timesteps + + def main(self): + """Accept commandline arguments and either run or update tests.""" + if config['update']: + self.update_results() + else: + self.execute_test() + + def execute_test(self): + """Run kinetic OpenMC test with the appropriate arguments and check the outputs.""" + try: + self._run_openmc() + self._harness_timestep_loop("test") + finally: + self._cleanup() + + def update_results(self): + """Update the results_true for each timestep using the current version of OpenMC.""" + try: + self._run_openmc() + self._harness_timestep_loop("update") + finally: + self._cleanup() + + def _harness_timestep_loop(self, loop_type): + """Test the results of each timestep""" + statepoint = glob.glob(self._sp_base + "*") + assert len(statepoint) == self._n_timesteps, f"Found {len(statepoint)} statepoint files exist" \ + f" but expected {self._n_timesteps}." + for i in range(self._n_timesteps): + self._test_output_created(i) + results = self._get_results(i) + self._write_results(results, i) + if loop_type == "test": + self._compare_results(i) + elif loop_type == "update": + self._overwrite_results(i) + else: + raise ValueError( + f"Invalid loop_type ({loop_type}) passed to _harness_timestep_loop") + + def _test_output_created(self, index): + """Make sure statepoint.* and tallies.out have been created for the current timestep.""" + statepoint = glob.glob(self._sp_base + f"_{index}*") + assert statepoint[0].endswith('h5'), \ + f"Statepoint file {statepoint[0]} is not a HDF5 file." + if os.path.exists('tallies.xml'): + assert os.path.exists(f"tallies_{index}.out"), \ + f"Tally output file tallies_{index}.out does not exist." + + def _get_results(self, index, hash_output=False): + """Digest info in the statepoints and return as a string.""" + # Read the statepoint files. + statepoint = glob.glob(self._sp_base + f"_{index}*")[0] + return self._write_tallies(statepoint, hash_output) + + @property + def statepoint_name(self, i): + return self._sp_base + f"_{i}.h5" + + def _write_results(self, results_string, index): + """Write the results to an ASCII file.""" + with open(f'results_test_{index}.dat', 'w') as fh: + fh.write(results_string) + + def _overwrite_results(self, index): + """Overwrite the results_true with the results_test.""" + shutil.copyfile(f'results_test_{index}.dat', + f'results_true_{index}.dat') + + def _compare_results(self, index): + """Make sure the current results agree with the reference.""" + compare = filecmp.cmp( + f'results_test_{index}.dat', 'results_true_{index}.dat') + if not compare: + expected = open(f'results_true_{index}.dat').readlines() + actual = open(f'results_test_{index}.dat').readlines() + diff = unified_diff(expected, actual, f'results_true_{index}.dat', + f'results_test_{index}.dat') + print(f'Timestep {index} result differences:') + print(''.join(colorize(diff))) + os.rename(f'results_test_{index}.dat', + f'results_error_{index}.dat') + assert compare, 'Results do not agree' + + def _cleanup(self): + """Delete statepoints, tally, and test files.""" + output = glob.glob('statepoint.*.h5') + output += ['summary.h5', 'tallies.out'] + output += glob.glob('tallies_*.out') + output += glob.glob('results_test_*.dat') + output += glob.glob('volume_*.h5') + output += glob.glob(f'{self._sp_base}_*.h5') + for f in output: + if os.path.exists(f): + os.remove(f) + + class PyAPITestHarness(TestHarness): def __init__(self, statepoint_name, model=None, inputs_true=None): super().__init__(statepoint_name) @@ -487,6 +596,74 @@ def _cleanup(self): os.remove(f) +class KineticPyAPITestHarness(KineticTestHarness, PyAPITestHarness): + def __init__(self, statepoint_base, n_timesteps, model, inputs_true=None): + super().__init__(statepoint_base, n_timesteps) + self._model = model + self._model.plots = [] + + self.inputs_true = "inputs_true.dat" if not inputs_true else inputs_true + + def execute_test(self): + """Build input XMLs, run OpenMC, and verify correct results.""" + try: + self._build_inputs() + inputs = self._get_inputs() + self._write_inputs(inputs) + self._compare_inputs() + self._run_openmc() + self._harness_timestep_loop("test") + finally: + self._cleanup() + + def update_results(self): + """Update results_true.dat and inputs_true.dat""" + try: + self._build_inputs() + inputs = self._get_inputs() + self._write_inputs(inputs) + self._overwrite_inputs() + self._run_openmc() + self._harness_timestep_loop("update") + finally: + self._cleanup() + + def _cleanup(self): + """Delete XMLs, statepoints, tally, and test files.""" + super()._cleanup() + output = ['materials.xml', 'geometry.xml', 'settings.xml', + 'tallies.xml', 'plots.xml', 'inputs_test.dat', 'model.xml'] + for f in output: + if os.path.exists(f): + os.remove(f) + + +class KineticTolerantPyAPITestHarness(KineticPyAPITestHarness, TolerantPyAPITestHarness): + """Specialized harness for running kinetic simulation tests in that involve + significant levels of floating point non-associativity when using shared + memory parallelism due to single precision usage (e.g., as in the random + ray solver). + + """ + + def _compare_results(self, i): + """Make sure the current results agree with the reference.""" + self._compare_files( + f'results_test_{i}.dat', f'results_true_{i}.dat', 1e-6, i) + + def _compare_files(self, file_test, file_true, tol, index): + compare = self._are_files_equal(file_test, file_true, 1e-6) + if not compare: + expected = open(file_true).readlines() + actual = open(file_test).readlines() + diff = unified_diff(expected, actual, file_true, + file_test) + print('Result differences:') + print(''.join(colorize(diff))) + os.rename(file_test, f'results_error_{index}.dat') + assert compare, 'Results do not agree' + + class PlotTestHarness(TestHarness): """Specialized TestHarness for running OpenMC plotting tests.""" diff --git a/tests/unit_tests/test_material.py b/tests/unit_tests/test_material.py index 764c98d41ae..e3f1167149f 100644 --- a/tests/unit_tests/test_material.py +++ b/tests/unit_tests/test_material.py @@ -252,6 +252,8 @@ def test_density(): m.set_density(unit, 1.0) with pytest.raises(ValueError): m.set_density('g/litre', 1.0) + with pytest.raises(ValueError): + m.set_density('sum', 1.0, [1,1,1]) def test_salphabeta(): @@ -499,14 +501,18 @@ def test_from_xml(run_in_tmpdir): m2.set_density('kg/m3', 10.0) m3 = openmc.Material(3) m3.add_nuclide('N14', 0.02) + m4 = openmc.Material(4) + m4.add_nuclide('C12', 1.0) + m4.set_density('g/cc', 12, [12, 14, 14, 14, 12]) + - mats = openmc.Materials([m1, m2, m3]) + mats = openmc.Materials([m1, m2, m3, m4]) mats.cross_sections = 'fake_path.xml' mats.export_to_xml() # Regenerate materials from XML mats = openmc.Materials.from_xml() - assert len(mats) == 3 + assert len(mats) == 4 m1 = mats[0] assert m1.id == 1 assert m1.name == 'water' @@ -519,6 +525,7 @@ def test_from_xml(run_in_tmpdir): assert m2.density == 10.0 assert m2.density_units == 'kg/m3' assert mats[2].density_units == 'sum' + assert np.all(m4.density_timeseries == [12, 14, 14, 14, 12]) def test_mix_materials(): diff --git a/tests/unit_tests/test_settings.py b/tests/unit_tests/test_settings.py index fe618fd2d65..4cf41e92b9a 100644 --- a/tests/unit_tests/test_settings.py +++ b/tests/unit_tests/test_settings.py @@ -1,8 +1,9 @@ +import pytest import openmc import openmc.stats - -def test_export_to_xml(run_in_tmpdir): +@pytest.mark.parametrize("kinetic_simulation", [True, False]) +def test_export_to_xml(run_in_tmpdir, kinetic_simulation): s = openmc.Settings(run_mode='fixed source', batches=1000, seed=17) s.generations_per_batch = 10 s.inactive = 100 @@ -10,6 +11,13 @@ def test_export_to_xml(run_in_tmpdir): s.max_lost_particles = 5 s.rel_max_lost_particles = 1e-4 s.keff_trigger = {'type': 'std_dev', 'threshold': 0.001} + s.kinetic_simulation = kinetic_simulation + if kinetic_simulation: + s.timestep_parameters = { + 'dt': 0.1, + 'n_timesteps': 41, + 'timestep_units': 's', + } s.energy_mode = 'continuous-energy' s.max_order = 5 s.max_tracks = 1234 @@ -77,6 +85,9 @@ def test_export_to_xml(run_in_tmpdir): 'adjoint': False, 'sample_method': 'halton' } + if kinetic_simulation: + s.random_ray['bd_order'] = 3 + s.random_ray['time_derivative_method'] = 'propagation' s.max_particle_events = 100 s.max_secondaries = 1_000_000 s.source_rejection_fraction = 0.01 @@ -95,6 +106,11 @@ def test_export_to_xml(run_in_tmpdir): assert s.max_lost_particles == 5 assert s.rel_max_lost_particles == 1e-4 assert s.keff_trigger == {'type': 'std_dev', 'threshold': 0.001} + assert s.kinetic_simulation == kinetic_simulation + if kinetic_simulation: + assert s.timestep_parameters['dt'] == 0.1 + assert s.timestep_parameters['n_timesteps'] == 41 + assert s.timestep_parameters['timestep_units'] == 's' assert s.energy_mode == 'continuous-energy' assert s.max_order == 5 assert s.max_tracks == 1234 @@ -169,6 +185,9 @@ def test_export_to_xml(run_in_tmpdir): assert s.random_ray['volume_normalized_flux_tallies'] assert not s.random_ray['adjoint'] assert s.random_ray['sample_method'] == 'halton' + if kinetic_simulation: + assert s.random_ray['bd_order'] == 3 + assert s.random_ray['time_derivative_method'] == 'propagation' assert s.max_secondaries == 1_000_000 assert s.source_rejection_fraction == 0.01 assert s.free_gas_threshold == 800.0 diff --git a/tests/unit_tests/weightwindows/test_ww_gen.py b/tests/unit_tests/weightwindows/test_ww_gen.py index a4456e6809a..928596832c0 100644 --- a/tests/unit_tests/weightwindows/test_ww_gen.py +++ b/tests/unit_tests/weightwindows/test_ww_gen.py @@ -367,7 +367,7 @@ def test_ww_generation_with_dagmc(run_in_tmpdir): method="stochastic_slab", overwrite_mgxs_library=True, nparticles=10, - groups="CASMO-2" + energy_groups="CASMO-2" ) rr_model.convert_to_random_ray()