From 840d66b719d3174e7b39fc5e2a8bc03b7cdf8a1c Mon Sep 17 00:00:00 2001 From: John Tramm Date: Thu, 16 Jan 2025 15:25:36 -0600 Subject: [PATCH 01/27] implemented fw cadis (simplified implementation derived from experimental branches) --- src/physics_mg.cpp | 6 +-- src/random_ray/random_ray_simulation.cpp | 1 + src/weight_windows.cpp | 47 ++++++++++++++++++------ 3 files changed, 40 insertions(+), 14 deletions(-) diff --git a/src/physics_mg.cpp b/src/physics_mg.cpp index 3cc0532d2b1..e967afd7995 100644 --- a/src/physics_mg.cpp +++ b/src/physics_mg.cpp @@ -28,12 +28,12 @@ void collision_mg(Particle& p) // Add to the collision counter for the particle p.n_collision()++; - if (settings::weight_window_checkpoint_collision) - apply_weight_windows(p); - // Sample the reaction type sample_reaction(p); + if (settings::weight_window_checkpoint_collision) + apply_weight_windows(p); + // Display information about collision if ((settings::verbosity >= 10) || p.trace()) { write_message(fmt::format(" Energy Group = {}", p.g()), 1); diff --git a/src/random_ray/random_ray_simulation.cpp b/src/random_ray/random_ray_simulation.cpp index a9180c68e7b..a8e6d1b8229 100644 --- a/src/random_ray/random_ray_simulation.cpp +++ b/src/random_ray/random_ray_simulation.cpp @@ -173,6 +173,7 @@ void validate_random_ray_inputs() case FilterType::MATERIAL: case FilterType::MESH: case FilterType::UNIVERSE: + case FilterType::PARTICLE: break; default: fatal_error("Invalid filter specified. Only cell, cell_instance, " diff --git a/src/weight_windows.cpp b/src/weight_windows.cpp index e798a2f7abd..7d4405d843f 100644 --- a/src/weight_windows.cpp +++ b/src/weight_windows.cpp @@ -22,6 +22,7 @@ #include "openmc/particle.h" #include "openmc/particle_data.h" #include "openmc/physics_common.h" +#include "openmc/random_ray/flat_source_domain.h" #include "openmc/search.h" #include "openmc/settings.h" #include "openmc/tallies/filter_energy.h" @@ -624,20 +625,44 @@ void WeightWindows::update_magic( auto mesh_vols = this->mesh()->volumes(); int e_bins = new_bounds.shape()[0]; - for (int e = 0; e < e_bins; e++) { - // select all - auto group_view = xt::view(new_bounds, e); - // divide by volume of mesh elements - for (int i = 0; i < group_view.size(); i++) { - group_view[i] /= mesh_vols[i]; + if (settings::solver_type == MONTE_CARLO || !FlatSourceDomain::adjoint_) { + // If we are computing weight windows with forward fluxes derived from a + // Monte Carlo or random ray solve, we use the MAGIC algorithm. + for (int e = 0; e < e_bins; e++) { + // select all + auto group_view = xt::view(new_bounds, e); + + // divide by volume of mesh elements + for (int i = 0; i < group_view.size(); i++) { + group_view[i] /= mesh_vols[i]; + } + + double group_max = + *std::max_element(group_view.begin(), group_view.end()); + // normalize values in this energy group by the maximum value for this + // group + if (group_max > 0.0) + group_view /= 2.0 * group_max; + } + } else { + // If we are computing weight windows with adjoint fluxes derived from a + // random ray solve, we use the FW-CADIS algorithm. + for (int e = 0; e < e_bins; e++) { + // select all + auto group_view = xt::view(new_bounds, e); + + // divide by volume of mesh elements + for (int i = 0; i < group_view.size(); i++) { + group_view[i] /= mesh_vols[i]; + } } - double group_max = *std::max_element(group_view.begin(), group_view.end()); - // normalize values in this energy group by the maximum value for this - // group - if (group_max > 0.0) - group_view /= 2.0 * group_max; + xt::noalias(new_bounds) = 1.0 / new_bounds; + + auto max_val = xt::amax(new_bounds)(); + + xt::noalias(new_bounds) = new_bounds / (2.0 * max_val); } // make sure that values where the mean is zero are set s.t. the weight window From 6b808bb055e03229b4be3ccfdb1156ea75394a17 Mon Sep 17 00:00:00 2001 From: John Tramm Date: Thu, 16 Jan 2025 15:30:02 -0600 Subject: [PATCH 02/27] Fixed solvertype namespace issue --- src/weight_windows.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/weight_windows.cpp b/src/weight_windows.cpp index 7d4405d843f..ccdf7840f36 100644 --- a/src/weight_windows.cpp +++ b/src/weight_windows.cpp @@ -626,7 +626,8 @@ void WeightWindows::update_magic( int e_bins = new_bounds.shape()[0]; - if (settings::solver_type == MONTE_CARLO || !FlatSourceDomain::adjoint_) { + if (settings::solver_type == SolverType::MONTE_CARLO || + !FlatSourceDomain::adjoint_) { // If we are computing weight windows with forward fluxes derived from a // Monte Carlo or random ray solve, we use the MAGIC algorithm. for (int e = 0; e < e_bins; e++) { From 638c831876733e8a84c2888c8c35d8644261797f Mon Sep 17 00:00:00 2001 From: John Tramm Date: Fri, 17 Jan 2025 12:42:51 -0600 Subject: [PATCH 03/27] added initial variance reduction methods docs --- docs/source/methods/index.rst | 1 + docs/source/methods/variance_reduction.rst | 56 ++++++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 docs/source/methods/variance_reduction.rst diff --git a/docs/source/methods/index.rst b/docs/source/methods/index.rst index 08aa7d05341..75c421c8773 100644 --- a/docs/source/methods/index.rst +++ b/docs/source/methods/index.rst @@ -20,4 +20,5 @@ Theory and Methodology energy_deposition parallelization cmfd + variance_reduction random_ray \ No newline at end of file diff --git a/docs/source/methods/variance_reduction.rst b/docs/source/methods/variance_reduction.rst new file mode 100644 index 00000000000..db4ac4f643f --- /dev/null +++ b/docs/source/methods/variance_reduction.rst @@ -0,0 +1,56 @@ +.. _methods_variance_reduction: + +================== +Variance Reduction +================== + +.. _methods_variance_reduction_intro: + +------------ +Introduction +------------ + +Transport problems can sometimes infolve a significant degree of attenuation between the neutron source and a detector (tally) region, which can result in a flux differential of ten orders of magnitude (or more) throughout the simulation domain. As Monte Carlo uncertainties tend to be inversely proportional to the physical flux density, it can be extremely difficult to accurately resolve tallies in locations that are optically far from the source. This issue is particularly common in fixed source simulations, where some tally locations may not experience a single scoring event, even after billions of analog histories. + +Variance reduction techniques aim to either flatten the global uncertainty distribution, such that all regions of phase space have a fairly similar uncertainty, or to reduce the uncertainty in specific locations (such as a detector). There are two strategies available in OpenMC for variance reduction: the Monte Carlo MAGIC method, and with FW-CADIS. Both strategies work by developing a weight window mesh, which can be utilized by subsequent Monte Carlo solves to split particles heading towards areas of lower flux densities while terminating particles in higher flux regions -- all while maintaining a fair game. + +------------ +MAGIC Method +------------ + +The MAGIC method is an iterative technique that uses spatial flux information (:math:`\phi(r)`) obtained from a normal Monte Carlo solve to produce weight windows (:math:`\w(r)`) that can be utilized by a subsequent iteration of Monte Carlo. While the first generation of weight windows produced may only help to reduce variance slightly, use of these weights to generate another set of weight windows results in a progressively improving iterative scheme. + +Equation :eq:`magic` defines how the lower bound of weight windows (:math:`\w_\ell(r)`) are generated with MAGIC using forward flux information. Here, we can see that the flux at location :math:`r` is normalized by the maximum flux in any group at that location. We can also see that the weights are divided by a factor of two, which accounts for the typical :math:`5\times` factor separating the lower and upper weight window bounds in OpenMC. + +.. math:: + :label: magic + + w_\ell(r) = \frac{\phi(r)}{2\text{max}(\phi(r))} + +A major advantage of this technique is that it does not require any special transport machinery -- it simply uses multiple Monte Carlo simulations to iteratively improve a set of weight windows (which are typically defined on a mesh covering the simulation domain). The downside to this method is that as the flux differential increases between areas near and far from the source, it requires more outer Monte Carlo iterations, each of which can be highly expensive in itself. Additionally, computation of weight windows based on regular (forward) neutron flux tally information does not produce the most numerically effective set of weight windows. Nonetheless, MAGIC remains a simple and effective technique for generating weight windows. + +-------- +FW-CADIS +-------- + +As discussed in the previous section, computation of weight windows based on regular (forward) neutron flux tally information does not produce the most numerically efficient set of weight windows. It is highly preferable to generate weight windows based on spatial adjoint flux (:math:`\phi^{\dag}(r)`) information. The adjoint flux is essentially the "reverse" simulation problem, where we sample a random point and assume this is where a particle was absorbed, and then trace it backwards (upscattering in energy), until we sample the point where it was born from. + +The FW-CADIS method produces weight windows for global variance reduction given adjoint flux information throughout the entire domain. It is defined in Equation :eq:`fw_cadis`, and also involves a normalization step not shown here. + +.. math:: + :label: fw_cadis + + w_\ell(r) = \frac{1}{2\phi^{\dag}(r)} + +While the algorithm itself is quite simple, it requires estimates of the global adjoint flux distribution, which is difficult to generate directly with Monte Carlo transport. Thus, FW-CADIS typically uses an alternative solver (often deterministic) that can be more readily adapted for generating adjoint flux information, and which is often much cheaper than Monte Carlo given that maximal-fidelity is not needed for weight window generation. + +The FW-CADIS implementation in OpenMC utilizes its own internal random ray multigroup transport solver. No coupling to an external solver or library is needed for generating weight windows with OpenMC. The random ray solver is ideal for this purpose as it naturally produces a relatively uniform uncertainty distribution throughout the simulation domain that is not proportional to the physical flux density. Additionally, the random ray solver operates on the same geometry as the Monte Carlo solver (all OpenMC geometries are supported), so the user does not need to provide a second set of inputs. + +More information on the workflow is available in the user guide, but generally production of weight windows with FW-CADIS involves several stages (some of which are highly automated). These tasks include generation of approximate multigroup cross section data for use by the random ray solver, running of the random ray solver in normal (forward flux) mode to generate a source for the adjoint solver, running of the random ray solver in adjoint mode to generate adjoint flux tallies, and finally the production of weight windows via the FW-CADIS method. As is discussed in the user guide, most of these steps are automated together, making the additional burden on the user fairly small. + +The major advantage of this technique is that it typically produces much more numerically efficient weight windows as compared to those generated with MAGIC, sometimes with an improvement on the variance vs. runtime figure of merit (Equation :eq:`variance_fom`) of an order of magnitude. Another major advantage is that the cost of the random ray solver is typically negligible compared to the cost of the subsequent Monte Carlo solve itself, making it a very cheap method to deploy. The downside to this method is that it introduces a second transport method into the mix (random ray), such that there are more free input parameters for the user to know about and adjust, potentially making the method more complex to use. However, as many of the parameters have natural choices, much of this parameterization can be handled automatically behind the scenes without the need for the user to be aware of this. + +.. math:: + :label: variance_fom + + \text{FOM} = \frac{1}{\text{Time} \times \sigma^2} \ No newline at end of file From be9b2f470779d376f61127866adbeac5d1036071 Mon Sep 17 00:00:00 2001 From: John Tramm Date: Fri, 17 Jan 2025 16:46:57 -0600 Subject: [PATCH 04/27] added variance reduction user guide --- docs/source/usersguide/index.rst | 1 + docs/source/usersguide/variance_reduction.rst | 204 ++++++++++++++++++ 2 files changed, 205 insertions(+) create mode 100644 docs/source/usersguide/variance_reduction.rst diff --git a/docs/source/usersguide/index.rst b/docs/source/usersguide/index.rst index 03a77e87063..74651c0114b 100644 --- a/docs/source/usersguide/index.rst +++ b/docs/source/usersguide/index.rst @@ -25,6 +25,7 @@ essential aspects of using OpenMC to perform simulations. processing parallel volume + variance_reduction random_ray troubleshoot \ No newline at end of file diff --git a/docs/source/usersguide/variance_reduction.rst b/docs/source/usersguide/variance_reduction.rst new file mode 100644 index 00000000000..f9cf638a580 --- /dev/null +++ b/docs/source/usersguide/variance_reduction.rst @@ -0,0 +1,204 @@ +.. _variance_reduction: + +================== +Variance Reduction +================== + +Global variance reduction in OpenMC is accomplished by weight windowing techniques. OpenMC is capable of generating weight windows using either the MAGIC or FW-CADIS methods. Both techniques will produce a "weight_windows.h5" file that can be loaded and used later on. In this section, we break down the steps required to both generate and then apply weight windows. + +------------------------------------ +Generating Weight Windows with MAGIC +------------------------------------ + +As discussed in the methods section, MAGIC is an iterative method that uses flux tally information from a Monte Carlo simulation to produce weight windows for a user defined mesh. While generating the weight windows, OpenMC is capable of applying the weight windows generated from a previous batch while processing the next batch, allowing for progressive improvement in the weight window quality across iterations. + +The most typical way of generating weight windows is to define a mesh and then add a :class:`WeightWindowGenerator` object to the :attr:`openmc.Settings` object, as follows:: + + # Define weight window spatial mesh + ww_mesh = openmc.RegularMesh() + ww_mesh.dimension = (10, 10, 10) + ww_mesh.lower_left = (0.0, 0.0, 0.0) + ww_mesh.upper_right = (100.0, 100.0, 100.0) + + # Create weight window object and adjust parameters + wwg = openmc.WeightWindowGenerator(mesh=ww_mesh, max_realizations=1000) + + # Add generator to openmc.settings object + settings.weight_window_generators = wwg + settings.weight_window_checkpoints = {'collision': True, 'surface': True} + +Notably, the :attr:`max_realizations` attribute is adjusted to 1000, such that multiple iterations are used to refine the weight window parameters. + +With the :class:`WeightWindowGenerator`` object added to the :attr:`openmc.Settings` object, the rest of the problem can be defined as normal. When running, note that the second iteration and beyond may be several orders of magnitude slower than the first. As the weight windows are applied in each iteration, particles may be agressively split, resulting in a large number of secondary (split) particles being generated per initial source particle. This is not necessarily a bad thing, as the split particles are much more efficient at exploring low flux regions of phase space as compared to initial particles. Thus, even though the reported "particles/second" metric of OpenMC may be much lower when generating (or just applying) weight windows as compared to analog MC, the variance vs. runtime figure of merit is typically much more advantageous. With this in mind, the number of particles per batch may need to be adjusted downward significantly to result in reasonable runtimes when weight windows are being generated or used. + +At the end of the simulation, a "weight_windows.h5" file will be saved to disk for later use. Loading it in another subsequent simulation will be discussed in the "Using Weight Windows" section below. + +------------------------------------------------------ +Generating Weight Windows with FW-CADIS and Random Ray +------------------------------------------------------ + +Weight window generation with FW-CADIS and random ray in OpenMC uses the same exact strategy as with MAGIC. A :class:`WeightWindowGenerator` object is added to the :attr:`openmc.Settings` object, and a "weight_windows.h5" will be generated at the end of the simulation. + +The only difference is that the code must be run in random ray mode, and adjoint mode enabled. A full description of how to enable and setup random ray mode can be found in the :ref:`Random Ray User Guide +`. + +It is a long term goal for OpenMC to be able to generate FW-CADIS weight windows with only a few tweaks to an existing continuous energy Monte Carlo input deck. However, at the present time, the workflow requires several steps. A high level overview of the workflow for generation of weight windows with FW-CADIS using random ray is as follows: + +1. Produce approximate multigroup cross section data. There is more +information on generating multigroup cross sections via OpenMC in the +:ref:`multigroup materials ` user guide. An example of using OpenMC's Python +interface to generate a correctly formatted ``mgxs.h5`` input file is given +in the `OpenMC Jupyter notebook collection +`_. We recommend generation of a 2-group, material-wise MGXS library. One method for doing this is by starting with an existing XML based input deck (that has no tallies.xml file) that has been run so as to generate statepoint and summary files, and then running the following script to generate the tallies needed for MGXS generation:: + + import openmc + import openmc.mgxs as mgxs + + summary = openmc.Summary('summary.h5') + geom = summary.geometry + mats = summary.materials + + statepoint_filename = 'statepoint.40.h5' + sp = openmc.StatePoint(statepoint_filename) + + + # MGXS + groups = mgxs.EnergyGroups(mgxs.GROUP_STRUCTURES['CASMO-2']) + mgxs_lib = openmc.mgxs.Library(geom) + mgxs_lib.energy_groups = groups + mgxs_lib.correction = None + mgxs_lib.mgxs_types = ['total', 'absorption', 'nu-fission', 'fission', + '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 = geom.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 + tallies = openmc.Tallies() + mgxs_lib.add_to_tallies_file(tallies, merge=True) + + # Export + tallies.export_to_xml() + +OpenMC can then be run again with the new tallies.xml to produce the required cross section data for tallies. Tight convergence is not needed, as the accuracy of the MGXS data doesn't need to be very high for the purposes of weight window generation. Finally, the below script can be run to generate the final "mgxs.h5" file that will be needed for the multigroup random ray solve:: + + import openmc + import openmc.mgxs as mgxs + + summary = openmc.Summary('summary.h5') + geom = summary.geometry + mats = summary.materials + + statepoint_filename = 'statepoint.40.h5' + sp = openmc.StatePoint(statepoint_filename) + + groups = mgxs.EnergyGroups(mgxs.GROUP_STRUCTURES['CASMO-2']) + mgxs_lib = openmc.mgxs.Library(geom) + mgxs_lib.energy_groups = groups + mgxs_lib.correction = None + mgxs_lib.mgxs_types = ['total', 'absorption', 'nu-fission', 'fission', + '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 = geom.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() + + mgxs_lib.load_from_statepoint(sp) + + names = [] + for mat in mgxs_lib.domains: names.append(mat.name) + + # Create a MGXS File which can then be written to disk + mgxs_file = mgxs_lib.create_mg_library(xs_type='macro', xsdata_names=names) + + # Write the file to disk using the default filename of "mgxs.h5" + mgxs_file.export_to_hdf5("mgxs.h5") + +Note that the above two scripts are useful as they work for any model. In the future, our goal is for this step to be automated so that manual creation of MGXS data doesn't need to be undertaken by the user. + +2. Make a copy of your continuous energy python input file. You'll edit the new file to work in multigroup mode with random ray for producing weight windows. + +3. Adjust the material definitions in your new multigroup python file to utilise the multigroup cross sections instead of nuclide-wise continuous energy data. For instance, you might take the following material definition from your continuous energy deck:: + + fuel = openmc.Material(name='UO2 (2.4%)') + fuel.set_density('g/cm3', 10.29769) + fuel.add_nuclide('U234', 4.4843e-6) + fuel.add_nuclide('U235', 5.5815e-4) + fuel.add_nuclide('U238', 2.2408e-2) + fuel.add_nuclide('O16', 4.5829e-2) + + water = openmc.Material(name='Hot borated water') + water.set_density('g/cm3', 0.740582) + water.add_nuclide('H1', 4.9457e-2) + water.add_nuclide('O16', 2.4672e-2) + water.add_nuclide('B10', 8.0042e-6) + water.add_nuclide('B11', 3.2218e-5) + water.add_s_alpha_beta('c_H_in_H2O') + + materials = openmc.Materials([fuel, water]) + +Into multigroup materials as:: + + # Instantiate some Macroscopic Data + fuel_data = openmc.Macroscopic('UO2 (2.4%)') + water_data = openmc.Macroscopic('Hot borated water') + + # Instantiate some Materials and register the appropriate Macroscopic objects + fuel= openmc.Material(name='UO2 (2.4%)') + fuel.set_density('macro', 1.0) + fuel.add_macroscopic(fuel_data) + + water= openmc.Material(name='Hot borated water') + water.set_density('macro', 1.0) + water.add_macroscopic(water_data) + + # Instantiate a Materials collection and export to XML + materials = openmc.Materials([fuel, water]) + materials.cross_sections = "mgxs.h5" + + +4. Add standard random ray flags and settings (to the :attr:`openmc.Settings.random_ray` dictionary). More information can be found in the :ref:`Random Ray User Guide +`. + +5. Enable adjoint mode in random ray as:: + + settings.random_ray['adjoint'] = True + +6. Add in a :class:`WeightWindowGenerator` in the same manner as for MAGIC. Ensure that the selected weight window mesh does not subdivide any cells in the problem. In the future, this restriction is intended to be relaxed, but for now subdivision of cells by a mesh tally will result in undefined behavior. + +6. When running your multigroup random ray input deck, OpenMC will automatically run a forward solve following by an adjoint solve, with a "weight_windows.h5" file generated at the end. The mgxs.h5 file can be used in an identical manner as one generated with MAGIC. + +-------------------- +Using Weight Windows +-------------------- + +To use a "weight_windows.h5" weight window file with OpenMC's Monte Carlo solver, the python input just needs to load the h5 file:: + + settings.weight_window_checkpoints = {'collision': True, 'surface': True} + settings.survival_biasing = False + settings.weight_windows = openmc.hdf5_to_wws() + settings.weight_windows_on = True + From e377b6be9c4cc0738acc47031fd48378c25d55b4 Mon Sep 17 00:00:00 2001 From: John Tramm Date: Fri, 17 Jan 2025 17:01:08 -0600 Subject: [PATCH 05/27] edits to variance reduction docs --- docs/source/usersguide/variance_reduction.rst | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/docs/source/usersguide/variance_reduction.rst b/docs/source/usersguide/variance_reduction.rst index f9cf638a580..2b618674ce0 100644 --- a/docs/source/usersguide/variance_reduction.rst +++ b/docs/source/usersguide/variance_reduction.rst @@ -42,14 +42,15 @@ Weight window generation with FW-CADIS and random ray in OpenMC uses the same ex The only difference is that the code must be run in random ray mode, and adjoint mode enabled. A full description of how to enable and setup random ray mode can be found in the :ref:`Random Ray User Guide `. -It is a long term goal for OpenMC to be able to generate FW-CADIS weight windows with only a few tweaks to an existing continuous energy Monte Carlo input deck. However, at the present time, the workflow requires several steps. A high level overview of the workflow for generation of weight windows with FW-CADIS using random ray is as follows: +.. note:: + It is a long term goal for OpenMC to be able to generate FW-CADIS weight windows with only a few tweaks to an existing continuous energy Monte Carlo input deck. However, at the present time, the workflow requires several steps to generate multigroup cross section data and to configure the random ray solver. A high level overview of the current workflow for generation of weight windows with FW-CADIS using random ray is given below. 1. Produce approximate multigroup cross section data. There is more information on generating multigroup cross sections via OpenMC in the :ref:`multigroup materials ` user guide. An example of using OpenMC's Python interface to generate a correctly formatted ``mgxs.h5`` input file is given in the `OpenMC Jupyter notebook collection -`_. We recommend generation of a 2-group, material-wise MGXS library. One method for doing this is by starting with an existing XML based input deck (that has no tallies.xml file) that has been run so as to generate statepoint and summary files, and then running the following script to generate the tallies needed for MGXS generation:: +`_. We recommend generation of a 2-group, material-wise MGXS library. One method for doing this is by starting with an existing set of XML input files (that has no tallies.xml file) that has been run so as to generate statepoint and summary files, and then running the following script to generate the tallies needed for MGXS generation:: import openmc import openmc.mgxs as mgxs @@ -61,7 +62,6 @@ in the `OpenMC Jupyter notebook collection statepoint_filename = 'statepoint.40.h5' sp = openmc.StatePoint(statepoint_filename) - # MGXS groups = mgxs.EnergyGroups(mgxs.GROUP_STRUCTURES['CASMO-2']) mgxs_lib = openmc.mgxs.Library(geom) @@ -141,7 +141,7 @@ Note that the above two scripts are useful as they work for any model. In the fu 2. Make a copy of your continuous energy python input file. You'll edit the new file to work in multigroup mode with random ray for producing weight windows. -3. Adjust the material definitions in your new multigroup python file to utilise the multigroup cross sections instead of nuclide-wise continuous energy data. For instance, you might take the following material definition from your continuous energy deck:: +3. Adjust the material definitions in your new multigroup python file to utilise the multigroup cross sections instead of nuclide-wise continuous energy data. For instance, you might convert the following material definition from a continuous energy deck:: fuel = openmc.Material(name='UO2 (2.4%)') fuel.set_density('g/cm3', 10.29769) @@ -160,7 +160,7 @@ Note that the above two scripts are useful as they work for any model. In the fu materials = openmc.Materials([fuel, water]) -Into multigroup materials as:: +into multigroup materials as:: # Instantiate some Macroscopic Data fuel_data = openmc.Macroscopic('UO2 (2.4%)') @@ -187,9 +187,11 @@ Into multigroup materials as:: settings.random_ray['adjoint'] = True -6. Add in a :class:`WeightWindowGenerator` in the same manner as for MAGIC. Ensure that the selected weight window mesh does not subdivide any cells in the problem. In the future, this restriction is intended to be relaxed, but for now subdivision of cells by a mesh tally will result in undefined behavior. +If the random ray solver in OpenMC is run in adjoint mode, the FW-CADIS algorithm will be utilize if weight window generation is enabled. If adjoint mode is not enabled, then the MAGIC algorithm will be used with the available forward flux tally data. As FW-CADIS weight windows are usually more efficient, it is highly recommended to use FW-CADIS and adjoint mode. + +6. Add in a :class:`WeightWindowGenerator` in the same manner as for MAGIC generation with Monte Carlo. Ensure that the selected weight window mesh does not subdivide any cells in the problem. In the future, this restriction is intended to be relaxed, but for now subdivision of cells by a mesh tally will result in undefined behavior. -6. When running your multigroup random ray input deck, OpenMC will automatically run a forward solve following by an adjoint solve, with a "weight_windows.h5" file generated at the end. The mgxs.h5 file can be used in an identical manner as one generated with MAGIC. +7. When running your multigroup random ray input deck, OpenMC will automatically run a forward solve followed by an adjoint solve, with a "weight_windows.h5" file generated at the end. The weight_windows.h5 file can be used in an identical manner as one generated with MAGIC. -------------------- Using Weight Windows @@ -202,3 +204,4 @@ To use a "weight_windows.h5" weight window file with OpenMC's Monte Carlo solver settings.weight_windows = openmc.hdf5_to_wws() settings.weight_windows_on = True +Make sure that the :class:`WeightWindowGenerator` is not present in the file when loading existing weight windows, so as to avoid added costs of generating weight windows again. \ No newline at end of file From c56860d231025afcbaeacbbdc986b65470b46622 Mon Sep 17 00:00:00 2001 From: John Tramm Date: Fri, 17 Jan 2025 17:06:39 -0600 Subject: [PATCH 06/27] edits to variance reduction docs --- docs/source/usersguide/variance_reduction.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/source/usersguide/variance_reduction.rst b/docs/source/usersguide/variance_reduction.rst index 2b618674ce0..dcd8dd43d4c 100644 --- a/docs/source/usersguide/variance_reduction.rst +++ b/docs/source/usersguide/variance_reduction.rst @@ -29,7 +29,9 @@ The most typical way of generating weight windows is to define a mesh and then a Notably, the :attr:`max_realizations` attribute is adjusted to 1000, such that multiple iterations are used to refine the weight window parameters. -With the :class:`WeightWindowGenerator`` object added to the :attr:`openmc.Settings` object, the rest of the problem can be defined as normal. When running, note that the second iteration and beyond may be several orders of magnitude slower than the first. As the weight windows are applied in each iteration, particles may be agressively split, resulting in a large number of secondary (split) particles being generated per initial source particle. This is not necessarily a bad thing, as the split particles are much more efficient at exploring low flux regions of phase space as compared to initial particles. Thus, even though the reported "particles/second" metric of OpenMC may be much lower when generating (or just applying) weight windows as compared to analog MC, the variance vs. runtime figure of merit is typically much more advantageous. With this in mind, the number of particles per batch may need to be adjusted downward significantly to result in reasonable runtimes when weight windows are being generated or used. +With the :class:`WeightWindowGenerator` object added to the :attr:`openmc.Settings` object, the rest of the problem can be defined as normal. When running, note that the second iteration and beyond may be several orders of magnitude slower than the first. As the weight windows are applied in each iteration, particles may be agressively split, resulting in a large number of secondary (split) particles being generated per initial source particle. This is not necessarily a bad thing, as the split particles are much more efficient at exploring low flux regions of phase space as compared to initial particles. Thus, even though the reported "particles/second" metric of OpenMC may be much lower when generating (or just applying) weight windows as compared to analog MC, the variance vs. runtime figure of merit is typically much more advantageous. + +.. warning:: The number of particles per batch may need to be adjusted downward significantly to result in reasonable runtimes when weight windows are being generated or used. At the end of the simulation, a "weight_windows.h5" file will be saved to disk for later use. Loading it in another subsequent simulation will be discussed in the "Using Weight Windows" section below. @@ -187,7 +189,7 @@ into multigroup materials as:: settings.random_ray['adjoint'] = True -If the random ray solver in OpenMC is run in adjoint mode, the FW-CADIS algorithm will be utilize if weight window generation is enabled. If adjoint mode is not enabled, then the MAGIC algorithm will be used with the available forward flux tally data. As FW-CADIS weight windows are usually more efficient, it is highly recommended to use FW-CADIS and adjoint mode. +If the random ray solver in OpenMC is run in adjoint mode, the FW-CADIS algorithm will be utilized if weight window generation is enabled. If adjoint mode is not enabled, then the MAGIC algorithm will be used with the available forward flux tally data. As FW-CADIS weight windows are usually more efficient, it is highly recommended to use FW-CADIS and adjoint mode. 6. Add in a :class:`WeightWindowGenerator` in the same manner as for MAGIC generation with Monte Carlo. Ensure that the selected weight window mesh does not subdivide any cells in the problem. In the future, this restriction is intended to be relaxed, but for now subdivision of cells by a mesh tally will result in undefined behavior. From 87fd95f6ffe1db3ab20919b26d496ac3228be2d2 Mon Sep 17 00:00:00 2001 From: John Tramm Date: Tue, 21 Jan 2025 14:29:46 -0600 Subject: [PATCH 07/27] Added more docs to variance reduction, and moved the MGXS workflow out of var red section into a new section in random ray. --- docs/source/usersguide/random_ray.rst | 142 +++++++++++++++++ docs/source/usersguide/variance_reduction.rst | 144 ++---------------- 2 files changed, 151 insertions(+), 135 deletions(-) diff --git a/docs/source/usersguide/random_ray.rst b/docs/source/usersguide/random_ray.rst index 2b9cf67240b..404adfc85fb 100644 --- a/docs/source/usersguide/random_ray.rst +++ b/docs/source/usersguide/random_ray.rst @@ -447,6 +447,148 @@ in the `OpenMC Jupyter notebook collection separate materials can be defined each with a separate multigroup dataset corresponding to a given temperature. +.. _mgxs_gen: + +------------------------------------------- +Generating Multigroup Cross Sections (MGXS) +------------------------------------------- + +OpenMC is capable of generating multigroup cross sections by way of flux collapsing data based on flux solutions obtained from a continuous energy Monte Carlo solve. While it is a circular excercise in some respects to use continuous energy Monte Carlo to generate cross sections to be used by a reduced-fidelity multigroup transport solver, there are many use cases where this is nonetheless highly desirable. For instance, generation of a multigroup library may enable the same set of approximate multigroup cross section data to be used across a variety of problem types (or through a multidimensional parameter sweep of design variables) with only modest errors and at greatly reduced cost as compared to using only continuous energy Monte Carlo. + +We give here a quick summary of how to produce a multigroup cross section data file (``mgxs.h5``) from a starting point of a typical continuous energy Monte Carlo input file. Notably, continuous energy input files define materials as a mixture of nuclides with different densities, whereas multigroup materials are simply defined by which name they correspond to in a ``mgxs.h5`` library file. + +To generate the cross section data, we begin with a continuous energy Monte Carlo input deck and add in the required tallies that will be needed to generate our library. In this example, we will specify material-wise cross sections and a two group energy decomposition:: + + # Define geometry + ... + ... + geometry = openmc.Geometry() + ... + ... + + # Initialize MGXS library with a finished OpenMC geometry object + mgxs_lib = openmc.mgxs.Library(geometry) + + # Pick energy group structure + groups = mgxs.EnergyGroups(mgxs.GROUP_STRUCTURES['CASMO-2']) + mgxs_lib.energy_groups = groups + + # Disable transport correction + mgxs_lib.correction = None + + # Specify needed cross sections for random ray + mgxs_lib.mgxs_types = ['total', 'absorption', 'nu-fission', 'fission', + '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 = geom.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 + tallies = openmc.Tallies() + mgxs_lib.add_to_tallies_file(tallies, merge=True) + + # Export + tallies.export_to_xml() + + ... + +When selecting an energy decomposition, you can manually define group boundaries or pick out a group structure already known to OpenMC (a list of which can be found at :class:`openmc.mgxs.GROUP_STRUCTURES`). Once the above input deck has been run, the resulting statepoint file will contain the needed flux and reaction rate tally data so that a MGXS library file can be generated. Below is the postprocessing script needed to generate the ``mgxs.h5`` library file given a statepoint file (e.g., ``statepoint.100.h5``) file and summary file (e.g., ``summary.h5``) that resulted from running our previous example:: + + import openmc + import openmc.mgxs as mgxs + + summary = openmc.Summary('summary.h5') + geom = summary.geometry + mats = summary.materials + + statepoint_filename = 'statepoint.100.h5' + sp = openmc.StatePoint(statepoint_filename) + + groups = mgxs.EnergyGroups(mgxs.GROUP_STRUCTURES['CASMO-2']) + mgxs_lib = openmc.mgxs.Library(geom) + mgxs_lib.energy_groups = groups + mgxs_lib.correction = None + mgxs_lib.mgxs_types = ['total', 'absorption', 'nu-fission', 'fission', + '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 = geom.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() + + mgxs_lib.load_from_statepoint(sp) + + names = [] + for mat in mgxs_lib.domains: names.append(mat.name) + + # Create a MGXS File which can then be written to disk + mgxs_file = mgxs_lib.create_mg_library(xs_type='macro', xsdata_names=names) + + # Write the file to disk using the default filename of "mgxs.h5" + mgxs_file.export_to_hdf5("mgxs.h5") + +Notably, the postprocessing script needs to match the same :class:`openmc.mgxs.Library` settings that were used to generate the tallies, but otherwise is able to discern the rest of the simulation details from the statepoint and summary files. Once the postprocessing script is successfully run, the ``mgxs.h5`` file can be loaded by subsequent runs of OpenMC. + +If you want to convert continuous energy material objects in an OpenMC input deck to multigroup ones from a ``mgxs.h5`` library, you can follow the below example. Here we begin with several continuous energy materials:: + + fuel = openmc.Material(name='UO2 (2.4%)') + fuel.set_density('g/cm3', 10.29769) + fuel.add_nuclide('U234', 4.4843e-6) + fuel.add_nuclide('U235', 5.5815e-4) + fuel.add_nuclide('U238', 2.2408e-2) + fuel.add_nuclide('O16', 4.5829e-2) + + water = openmc.Material(name='Hot borated water') + water.set_density('g/cm3', 0.740582) + water.add_nuclide('H1', 4.9457e-2) + water.add_nuclide('O16', 2.4672e-2) + water.add_nuclide('B10', 8.0042e-6) + water.add_nuclide('B11', 3.2218e-5) + water.add_s_alpha_beta('c_H_in_H2O') + + materials = openmc.Materials([fuel, water]) + +and make the necessary changes to turn them into multigroup library materials as:: + + # Instantiate some Macroscopic Data + fuel_data = openmc.Macroscopic('UO2 (2.4%)') + water_data = openmc.Macroscopic('Hot borated water') + + # Instantiate some Materials and register the appropriate Macroscopic objects + fuel= openmc.Material(name='UO2 (2.4%)') + fuel.set_density('macro', 1.0) + fuel.add_macroscopic(fuel_data) + + water= openmc.Material(name='Hot borated water') + water.set_density('macro', 1.0) + water.add_macroscopic(water_data) + + # Instantiate a Materials collection and export to XML + materials = openmc.Materials([fuel, water]) + materials.cross_sections = "mgxs.h5" + -------------- Linear Sources -------------- diff --git a/docs/source/usersguide/variance_reduction.rst b/docs/source/usersguide/variance_reduction.rst index dcd8dd43d4c..2f5f8744a48 100644 --- a/docs/source/usersguide/variance_reduction.rst +++ b/docs/source/usersguide/variance_reduction.rst @@ -6,6 +6,8 @@ Variance Reduction Global variance reduction in OpenMC is accomplished by weight windowing techniques. OpenMC is capable of generating weight windows using either the MAGIC or FW-CADIS methods. Both techniques will produce a "weight_windows.h5" file that can be loaded and used later on. In this section, we break down the steps required to both generate and then apply weight windows. +.. _ww_generator: + ------------------------------------ Generating Weight Windows with MAGIC ------------------------------------ @@ -47,143 +49,15 @@ The only difference is that the code must be run in random ray mode, and adjoint .. note:: It is a long term goal for OpenMC to be able to generate FW-CADIS weight windows with only a few tweaks to an existing continuous energy Monte Carlo input deck. However, at the present time, the workflow requires several steps to generate multigroup cross section data and to configure the random ray solver. A high level overview of the current workflow for generation of weight windows with FW-CADIS using random ray is given below. -1. Produce approximate multigroup cross section data. There is more +1. Produce approximate multigroup cross section data (stored in a `mgxs.h5` library). There is more information on generating multigroup cross sections via OpenMC in the -:ref:`multigroup materials ` user guide. An example of using OpenMC's Python -interface to generate a correctly formatted ``mgxs.h5`` input file is given -in the `OpenMC Jupyter notebook collection -`_. We recommend generation of a 2-group, material-wise MGXS library. One method for doing this is by starting with an existing set of XML input files (that has no tallies.xml file) that has been run so as to generate statepoint and summary files, and then running the following script to generate the tallies needed for MGXS generation:: - - import openmc - import openmc.mgxs as mgxs - - summary = openmc.Summary('summary.h5') - geom = summary.geometry - mats = summary.materials - - statepoint_filename = 'statepoint.40.h5' - sp = openmc.StatePoint(statepoint_filename) - - # MGXS - groups = mgxs.EnergyGroups(mgxs.GROUP_STRUCTURES['CASMO-2']) - mgxs_lib = openmc.mgxs.Library(geom) - mgxs_lib.energy_groups = groups - mgxs_lib.correction = None - mgxs_lib.mgxs_types = ['total', 'absorption', 'nu-fission', 'fission', - '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 = geom.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 - tallies = openmc.Tallies() - mgxs_lib.add_to_tallies_file(tallies, merge=True) - - # Export - tallies.export_to_xml() - -OpenMC can then be run again with the new tallies.xml to produce the required cross section data for tallies. Tight convergence is not needed, as the accuracy of the MGXS data doesn't need to be very high for the purposes of weight window generation. Finally, the below script can be run to generate the final "mgxs.h5" file that will be needed for the multigroup random ray solve:: - - import openmc - import openmc.mgxs as mgxs - - summary = openmc.Summary('summary.h5') - geom = summary.geometry - mats = summary.materials - - statepoint_filename = 'statepoint.40.h5' - sp = openmc.StatePoint(statepoint_filename) - - groups = mgxs.EnergyGroups(mgxs.GROUP_STRUCTURES['CASMO-2']) - mgxs_lib = openmc.mgxs.Library(geom) - mgxs_lib.energy_groups = groups - mgxs_lib.correction = None - mgxs_lib.mgxs_types = ['total', 'absorption', 'nu-fission', 'fission', - '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 = geom.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() - - mgxs_lib.load_from_statepoint(sp) - - names = [] - for mat in mgxs_lib.domains: names.append(mat.name) - - # Create a MGXS File which can then be written to disk - mgxs_file = mgxs_lib.create_mg_library(xs_type='macro', xsdata_names=names) - - # Write the file to disk using the default filename of "mgxs.h5" - mgxs_file.export_to_hdf5("mgxs.h5") - -Note that the above two scripts are useful as they work for any model. In the future, our goal is for this step to be automated so that manual creation of MGXS data doesn't need to be undertaken by the user. +:ref:`multigroup materials ` user guide, and a specific example of generating cross section data for use with random ray in the :ref:`random ray MGXS guide `. 2. Make a copy of your continuous energy python input file. You'll edit the new file to work in multigroup mode with random ray for producing weight windows. -3. Adjust the material definitions in your new multigroup python file to utilise the multigroup cross sections instead of nuclide-wise continuous energy data. For instance, you might convert the following material definition from a continuous energy deck:: - - fuel = openmc.Material(name='UO2 (2.4%)') - fuel.set_density('g/cm3', 10.29769) - fuel.add_nuclide('U234', 4.4843e-6) - fuel.add_nuclide('U235', 5.5815e-4) - fuel.add_nuclide('U238', 2.2408e-2) - fuel.add_nuclide('O16', 4.5829e-2) +3. Adjust the material definitions in your new multigroup python file to utilise the multigroup cross sections instead of nuclide-wise continuous energy data. There is a specific example of making this conversion in the random ray in the :ref:`random ray MGXS guide `. - water = openmc.Material(name='Hot borated water') - water.set_density('g/cm3', 0.740582) - water.add_nuclide('H1', 4.9457e-2) - water.add_nuclide('O16', 2.4672e-2) - water.add_nuclide('B10', 8.0042e-6) - water.add_nuclide('B11', 3.2218e-5) - water.add_s_alpha_beta('c_H_in_H2O') - - materials = openmc.Materials([fuel, water]) - -into multigroup materials as:: - - # Instantiate some Macroscopic Data - fuel_data = openmc.Macroscopic('UO2 (2.4%)') - water_data = openmc.Macroscopic('Hot borated water') - - # Instantiate some Materials and register the appropriate Macroscopic objects - fuel= openmc.Material(name='UO2 (2.4%)') - fuel.set_density('macro', 1.0) - fuel.add_macroscopic(fuel_data) - - water= openmc.Material(name='Hot borated water') - water.set_density('macro', 1.0) - water.add_macroscopic(water_data) - - # Instantiate a Materials collection and export to XML - materials = openmc.Materials([fuel, water]) - materials.cross_sections = "mgxs.h5" - - -4. Add standard random ray flags and settings (to the :attr:`openmc.Settings.random_ray` dictionary). More information can be found in the :ref:`Random Ray User Guide -`. +4. Configure OpenMC to run in random ray mode (by adding several standard random ray input flags and settings to the :attr:`openmc.Settings.random_ray` dictionary). More information can be found in the :ref:`Random Ray User Guide `. 5. Enable adjoint mode in random ray as:: @@ -191,9 +65,9 @@ into multigroup materials as:: If the random ray solver in OpenMC is run in adjoint mode, the FW-CADIS algorithm will be utilized if weight window generation is enabled. If adjoint mode is not enabled, then the MAGIC algorithm will be used with the available forward flux tally data. As FW-CADIS weight windows are usually more efficient, it is highly recommended to use FW-CADIS and adjoint mode. -6. Add in a :class:`WeightWindowGenerator` in the same manner as for MAGIC generation with Monte Carlo. Ensure that the selected weight window mesh does not subdivide any cells in the problem. In the future, this restriction is intended to be relaxed, but for now subdivision of cells by a mesh tally will result in undefined behavior. +6. Add in a :class:`WeightWindowGenerator` in the same manner as for MAGIC generation with Monte Carlo, as in the example given above in the :ref:`MAGIC weight window generator guide `. Ensure that the selected weight window mesh does not subdivide any cells in the problem. In the future, this restriction is intended to be relaxed, but for now subdivision of cells by a mesh tally will result in undefined behavior. -7. When running your multigroup random ray input deck, OpenMC will automatically run a forward solve followed by an adjoint solve, with a "weight_windows.h5" file generated at the end. The weight_windows.h5 file can be used in an identical manner as one generated with MAGIC. +7. When running your multigroup random ray input deck, OpenMC will automatically run a forward solve followed by an adjoint solve, with a "weight_windows.h5" file generated at the end. The weight_windows.h5 file will contain FW-CADIS generated weight windows. This file can be used in identical manner as one generated with MAGIC, as described below. -------------------- Using Weight Windows @@ -206,4 +80,4 @@ To use a "weight_windows.h5" weight window file with OpenMC's Monte Carlo solver settings.weight_windows = openmc.hdf5_to_wws() settings.weight_windows_on = True -Make sure that the :class:`WeightWindowGenerator` is not present in the file when loading existing weight windows, so as to avoid added costs of generating weight windows again. \ No newline at end of file +Make sure that the :class:`WeightWindowGenerator` is not present in the file when loading existing weight windows, so as to avoid added costs of generating weight windows again. Weight window mesh information is embedded into the weight window file, so it does not need to be redfined. Monte Carlo solves that load a weight window file as above will utilize the weight windows to reduce the variance of the simulation. \ No newline at end of file From deffc12b4f516287a3979cf74fa62787d2b399c5 Mon Sep 17 00:00:00 2001 From: John Tramm Date: Wed, 22 Jan 2025 09:17:55 -0600 Subject: [PATCH 08/27] added new weight window testing harness, and added FW-CADIS random ray test --- .../weightwindows_fw_cadis/__init__.py | 0 .../weightwindows_fw_cadis/inputs_true.dat | 261 +++++++++++ .../weightwindows_fw_cadis/results_true.dat | 442 ++++++++++++++++++ .../weightwindows_fw_cadis/test.py | 33 ++ tests/testing_harness.py | 35 ++ 5 files changed, 771 insertions(+) create mode 100644 tests/regression_tests/weightwindows_fw_cadis/__init__.py create mode 100644 tests/regression_tests/weightwindows_fw_cadis/inputs_true.dat create mode 100644 tests/regression_tests/weightwindows_fw_cadis/results_true.dat create mode 100644 tests/regression_tests/weightwindows_fw_cadis/test.py diff --git a/tests/regression_tests/weightwindows_fw_cadis/__init__.py b/tests/regression_tests/weightwindows_fw_cadis/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/regression_tests/weightwindows_fw_cadis/inputs_true.dat b/tests/regression_tests/weightwindows_fw_cadis/inputs_true.dat new file mode 100644 index 00000000000..8214666a0a0 --- /dev/null +++ b/tests/regression_tests/weightwindows_fw_cadis/inputs_true.dat @@ -0,0 +1,261 @@ + + + + mgxs.h5 + + + + + + + + + + + + + + + + + + + + + 2.5 2.5 2.5 + 12 12 12 + 0.0 0.0 0.0 + +3 3 3 3 3 3 3 3 3 3 3 3 +3 3 3 3 3 3 3 3 3 3 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +1 1 2 2 2 2 2 2 2 2 3 3 +1 1 2 2 2 2 2 2 2 2 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 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +1 1 2 2 2 2 2 2 2 2 3 3 +1 1 2 2 2 2 2 2 2 2 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 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 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 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 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 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 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 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 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 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 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 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 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 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 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 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 3 3 +2 2 2 2 2 2 2 2 2 2 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 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 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 + + + + + + + + + + fixed source + 90 + 10 + 5 + + + 100.0 1.0 + + + universe + 1 + + + multi-group + + + 1 + neutron + 10 + 1 + true + magic + + + + 6 6 6 + 0.0 0.0 0.0 + 30.0 30.0 30.0 + + + 500.0 + 100.0 + + + 0.0 0.0 0.0 30.0 30.0 30.0 + + + True + True + naive + + + + + 1 + + + 2 + + + 3 + + + 3 + flux + tracklength + + + 2 + flux + tracklength + + + 1 + flux + tracklength + + + diff --git a/tests/regression_tests/weightwindows_fw_cadis/results_true.dat b/tests/regression_tests/weightwindows_fw_cadis/results_true.dat new file mode 100644 index 00000000000..e39b2e23900 --- /dev/null +++ b/tests/regression_tests/weightwindows_fw_cadis/results_true.dat @@ -0,0 +1,442 @@ +RegularMesh + ID = 1 + Name = + Dimensions = 3 + Voxels = [6 6 6] + Lower left = [0. 0. 0.] + Upper Right = [np.float64(30.0), np.float64(30.0), np.float64(30.0)] + Width = [5. 5. 5.] +Lower Bounds +1.50e-01 +1.54e-01 +1.43e-01 +1.30e-01 +1.30e-01 +1.97e-01 +1.46e-01 +1.25e-01 +1.34e-01 +1.32e-01 +1.27e-01 +3.40e-01 +1.36e-01 +1.13e-01 +1.09e-01 +1.19e-01 +1.25e-01 +3.08e-01 +1.38e-01 +1.18e-01 +9.49e-02 +1.19e-01 +1.35e-01 +1.96e-01 +1.12e-01 +9.60e-02 +9.33e-02 +9.74e-02 +1.37e-01 +2.76e-01 +4.53e-02 +1.31e-01 +2.47e-01 +7.36e-02 +1.72e-01 +1.38e-01 +1.55e-01 +1.54e-01 +1.48e-01 +1.36e-01 +1.29e-01 +1.88e-01 +1.40e-01 +1.51e-01 +1.28e-01 +1.18e-01 +1.29e-01 +2.86e-01 +1.42e-01 +1.26e-01 +1.28e-01 +1.16e-01 +1.22e-01 +2.81e-01 +1.38e-01 +1.22e-01 +1.04e-01 +9.81e-02 +1.08e-01 +1.97e-01 +1.34e-01 +1.32e-01 +1.10e-01 +8.69e-02 +1.03e-01 +1.33e-01 +2.51e-01 +3.39e-01 +1.13e-01 +6.92e-02 +1.54e-01 +5.71e-02 +1.60e-01 +1.52e-01 +1.34e-01 +1.32e-01 +1.28e-01 +2.53e-01 +1.33e-01 +1.35e-01 +1.15e-01 +1.32e-01 +1.37e-01 +3.13e-01 +1.27e-01 +1.36e-01 +1.35e-01 +1.10e-01 +1.08e-01 +8.81e-02 +1.51e-01 +1.32e-01 +1.13e-01 +9.89e-02 +9.25e-02 +5.04e-02 +1.40e-01 +1.56e-01 +1.40e-01 +9.19e-02 +6.54e-02 +2.05e-02 +3.35e-01 +1.88e-01 +3.16e-01 +1.80e-01 +5.78e-02 +5.36e-03 +1.43e-01 +1.35e-01 +1.47e-01 +1.33e-01 +1.47e-01 +4.95e-01 +1.42e-01 +1.45e-01 +1.27e-01 +1.31e-01 +1.26e-01 +1.43e-01 +1.49e-01 +1.23e-01 +1.24e-01 +1.13e-01 +9.69e-02 +1.07e-01 +1.65e-01 +1.50e-01 +1.24e-01 +1.07e-01 +8.90e-02 +8.81e-02 +1.48e-01 +1.58e-01 +1.20e-01 +7.93e-02 +7.19e-02 +3.94e-02 +2.29e-01 +1.95e-01 +2.66e-01 +1.51e-01 +3.52e-02 +3.68e-03 +1.48e-01 +1.18e-01 +1.47e-01 +1.41e-01 +1.37e-01 +2.71e-01 +1.70e-01 +1.70e-01 +1.29e-01 +1.33e-01 +1.28e-01 +2.79e-01 +1.84e-01 +1.42e-01 +1.18e-01 +1.25e-01 +1.26e-01 +1.64e-01 +1.73e-01 +1.37e-01 +1.12e-01 +9.01e-02 +1.13e-01 +1.68e-01 +1.60e-01 +1.52e-01 +1.30e-01 +8.71e-02 +7.72e-02 +3.76e-02 +1.57e-01 +9.31e-02 +1.63e-01 +6.80e-02 +6.22e-02 +3.37e-03 +2.47e-01 +2.17e-01 +1.48e-01 +2.01e-01 +1.54e-01 +5.69e-02 +2.89e-01 +3.59e-01 +1.17e-01 +8.64e-02 +3.34e-01 +1.50e-01 +5.00e-01 +2.16e-01 +1.22e-01 +1.66e-01 +1.44e-01 +4.98e-02 +4.28e-01 +1.17e-01 +8.73e-02 +1.11e-01 +1.09e-01 +9.69e-02 +3.26e-01 +2.28e-01 +2.49e-01 +3.55e-02 +1.69e-02 +3.95e-03 +1.03e-01 +4.89e-02 +1.90e-01 +4.61e-02 +9.75e-03 +3.00e-04 +Upper Bounds +7.49e-01 +7.71e-01 +7.13e-01 +6.51e-01 +6.48e-01 +9.85e-01 +7.31e-01 +6.26e-01 +6.69e-01 +6.59e-01 +6.33e-01 +1.70e+00 +6.82e-01 +5.67e-01 +5.45e-01 +5.94e-01 +6.24e-01 +1.54e+00 +6.92e-01 +5.91e-01 +4.75e-01 +5.96e-01 +6.77e-01 +9.82e-01 +5.59e-01 +4.80e-01 +4.67e-01 +4.87e-01 +6.84e-01 +1.38e+00 +2.26e-01 +6.55e-01 +1.24e+00 +3.68e-01 +8.59e-01 +6.88e-01 +7.73e-01 +7.70e-01 +7.42e-01 +6.78e-01 +6.46e-01 +9.40e-01 +7.00e-01 +7.57e-01 +6.39e-01 +5.92e-01 +6.43e-01 +1.43e+00 +7.12e-01 +6.29e-01 +6.40e-01 +5.78e-01 +6.09e-01 +1.40e+00 +6.90e-01 +6.10e-01 +5.21e-01 +4.91e-01 +5.42e-01 +9.87e-01 +6.71e-01 +6.60e-01 +5.52e-01 +4.35e-01 +5.14e-01 +6.65e-01 +1.26e+00 +1.70e+00 +5.63e-01 +3.46e-01 +7.72e-01 +2.86e-01 +8.00e-01 +7.58e-01 +6.70e-01 +6.59e-01 +6.41e-01 +1.26e+00 +6.65e-01 +6.76e-01 +5.76e-01 +6.60e-01 +6.86e-01 +1.57e+00 +6.35e-01 +6.81e-01 +6.75e-01 +5.51e-01 +5.39e-01 +4.40e-01 +7.56e-01 +6.62e-01 +5.67e-01 +4.95e-01 +4.63e-01 +2.52e-01 +6.98e-01 +7.78e-01 +6.99e-01 +4.59e-01 +3.27e-01 +1.02e-01 +1.67e+00 +9.38e-01 +1.58e+00 +9.00e-01 +2.89e-01 +2.68e-02 +7.16e-01 +6.75e-01 +7.35e-01 +6.63e-01 +7.34e-01 +2.47e+00 +7.11e-01 +7.23e-01 +6.34e-01 +6.54e-01 +6.32e-01 +7.14e-01 +7.45e-01 +6.15e-01 +6.19e-01 +5.64e-01 +4.85e-01 +5.37e-01 +8.26e-01 +7.51e-01 +6.21e-01 +5.36e-01 +4.45e-01 +4.40e-01 +7.40e-01 +7.92e-01 +5.99e-01 +3.96e-01 +3.60e-01 +1.97e-01 +1.14e+00 +9.76e-01 +1.33e+00 +7.55e-01 +1.76e-01 +1.84e-02 +7.42e-01 +5.90e-01 +7.37e-01 +7.07e-01 +6.84e-01 +1.36e+00 +8.52e-01 +8.49e-01 +6.46e-01 +6.63e-01 +6.42e-01 +1.40e+00 +9.19e-01 +7.08e-01 +5.89e-01 +6.24e-01 +6.28e-01 +8.21e-01 +8.64e-01 +6.87e-01 +5.58e-01 +4.50e-01 +5.64e-01 +8.40e-01 +7.99e-01 +7.62e-01 +6.51e-01 +4.36e-01 +3.86e-01 +1.88e-01 +7.85e-01 +4.66e-01 +8.13e-01 +3.40e-01 +3.11e-01 +1.68e-02 +1.24e+00 +1.09e+00 +7.40e-01 +1.00e+00 +7.72e-01 +2.85e-01 +1.44e+00 +1.79e+00 +5.85e-01 +4.32e-01 +1.67e+00 +7.50e-01 +2.50e+00 +1.08e+00 +6.10e-01 +8.32e-01 +7.19e-01 +2.49e-01 +2.14e+00 +5.87e-01 +4.36e-01 +5.57e-01 +5.47e-01 +4.84e-01 +1.63e+00 +1.14e+00 +1.25e+00 +1.78e-01 +8.43e-02 +1.97e-02 +5.17e-01 +2.44e-01 +9.49e-01 +2.31e-01 +4.87e-02 +1.50e-03 \ No newline at end of file diff --git a/tests/regression_tests/weightwindows_fw_cadis/test.py b/tests/regression_tests/weightwindows_fw_cadis/test.py new file mode 100644 index 00000000000..3109ae2cb8f --- /dev/null +++ b/tests/regression_tests/weightwindows_fw_cadis/test.py @@ -0,0 +1,33 @@ +import os + +import openmc +from openmc.examples import random_ray_three_region_cube + +from tests.testing_harness import WeightWindowPyAPITestHarness + + +class MGXSTestHarness(WeightWindowPyAPITestHarness): + def _cleanup(self): + super()._cleanup() + f = 'mgxs.h5' + if os.path.exists(f): + os.remove(f) + + +def test_random_ray_adjoint_fixed_source(): + model = random_ray_three_region_cube() + model.settings.random_ray['adjoint'] = True + + ww_mesh = openmc.RegularMesh() + n = 6 + width = 30.0 + ww_mesh.dimension = (n, n, n) + ww_mesh.lower_left = (0.0, 0.0, 0.0) + ww_mesh.upper_right = (width, width, width) + + wwg = openmc.WeightWindowGenerator(mesh=ww_mesh, max_realizations=model.settings.batches) + model.settings.weight_window_generators = wwg + model.settings.random_ray['volume_estimator'] = 'naive' + + harness = MGXSTestHarness('statepoint.10.h5', model) + harness.main() diff --git a/tests/testing_harness.py b/tests/testing_harness.py index 81527452b84..15f5b795961 100644 --- a/tests/testing_harness.py +++ b/tests/testing_harness.py @@ -441,6 +441,41 @@ def _compare_results(self): assert compare, 'Results do not agree' +class WeightWindowPyAPITestHarness(PyAPITestHarness): + def _get_results(self): + """Digest info in the weight window file and return as a string.""" + ww = openmc.hdf5_to_wws()[0] + + # Access the weight window bounds + lower_bound = ww.lower_ww_bounds + upper_bound = ww.upper_ww_bounds + + # Flatten both arrays + flattened_lower_bound = lower_bound.flatten() + flattened_upper_bound = upper_bound.flatten() + + # Convert each element to a string in scientific notation with 2 decimal places + formatted_lower_bound = [f'{x:.2e}' for x in flattened_lower_bound] + formatted_upper_bound = [f'{x:.2e}' for x in flattened_upper_bound] + + # Concatenate the formatted arrays + concatenated_strings = [ + "Lower Bounds"] + formatted_lower_bound + ["Upper Bounds"] + formatted_upper_bound + + # Join the concatenated strings into a single string with newline characters + final_string = '\n'.join(concatenated_strings) + + # Prepend the mesh text description and return final string + final_string = str(ww.mesh) + final_string + return final_string + + def _cleanup(self): + super()._cleanup() + f = 'weight_windows.h5' + if os.path.exists(f): + os.remove(f) + + class PlotTestHarness(TestHarness): """Specialized TestHarness for running OpenMC plotting tests.""" def __init__(self, plot_names, voxel_convert_checks=[]): From 84ce0dcf46e38dfcb887b88741d694bb8cc7099b Mon Sep 17 00:00:00 2001 From: John Tramm Date: Wed, 22 Jan 2025 09:48:39 -0600 Subject: [PATCH 09/27] altered interface for using FW-CADIS. Now the method needs to be specified instead of just running in adjoint mode. --- include/openmc/weight_windows.h | 5 +- src/weight_windows.cpp | 66 ++++++++++--------- .../weightwindows_fw_cadis/test.py | 3 +- 3 files changed, 38 insertions(+), 36 deletions(-) diff --git a/include/openmc/weight_windows.h b/include/openmc/weight_windows.h index 9852fe679d0..18b2bb252a5 100644 --- a/include/openmc/weight_windows.h +++ b/include/openmc/weight_windows.h @@ -18,7 +18,7 @@ namespace openmc { enum class WeightWindowUpdateMethod { - MAGIC, + MAGIC, FW_CADIS }; //============================================================================== @@ -223,8 +223,7 @@ class WeightWindowsGenerator { // Data members int32_t tally_idx_; //!< Index of the tally used to update the weight windows int32_t ww_idx_; //!< Index of the weight windows object being generated - std::string method_; //!< Method used to update weight window. Only "magic" - //!< is valid for now. + WeightWindowUpdateMethod method_; //!< Method used to update weight window. int32_t max_realizations_; //!< Maximum number of tally realizations int32_t update_interval_; //!< Determines how often updates occur bool on_the_fly_; //!< Whether or not to keep tally results between batches or diff --git a/src/weight_windows.cpp b/src/weight_windows.cpp index ccdf7840f36..bc53e5f7bca 100644 --- a/src/weight_windows.cpp +++ b/src/weight_windows.cpp @@ -626,8 +626,7 @@ void WeightWindows::update_magic( int e_bins = new_bounds.shape()[0]; - if (settings::solver_type == SolverType::MONTE_CARLO || - !FlatSourceDomain::adjoint_) { + if (method_ == WeightWindowUpdateMethod::MAGIC) { // If we are computing weight windows with forward fluxes derived from a // Monte Carlo or random ray solve, we use the MAGIC algorithm. for (int e = 0; e < e_bins; e++) { @@ -646,7 +645,7 @@ void WeightWindows::update_magic( if (group_max > 0.0) group_view /= 2.0 * group_max; } - } else { + } else if (method_ == WeightWindowUpdateMethod::FW_CADIS){ // If we are computing weight windows with adjoint fluxes derived from a // random ray solve, we use the FW-CADIS algorithm. for (int e = 0; e < e_bins; e++) { @@ -786,37 +785,42 @@ WeightWindowsGenerator::WeightWindowsGenerator(pugi::xml_node node) e_bounds.push_back(data::energy_max[p_type]); } - // set method and parameters for updates - method_ = get_node_value(node, "method"); - if (method_ == "magic") { - // parse non-default update parameters if specified - if (check_for_node(node, "update_parameters")) { - pugi::xml_node params_node = node.child("update_parameters"); - if (check_for_node(params_node, "value")) - tally_value_ = get_node_value(params_node, "value"); - if (check_for_node(params_node, "threshold")) - threshold_ = std::stod(get_node_value(params_node, "threshold")); - if (check_for_node(params_node, "ratio")) { - ratio_ = std::stod(get_node_value(params_node, "ratio")); - } - } - // check update parameter values - if (tally_value_ != "mean" && tally_value_ != "rel_err") { - fatal_error(fmt::format("Unsupported tally value '{}' specified for " - "weight window generation.", - tally_value_)); - } - if (threshold_ <= 0.0) - fatal_error(fmt::format("Invalid relative error threshold '{}' (<= 0.0) " - "specified for weight window generation", - ratio_)); - if (ratio_ <= 1.0) - fatal_error(fmt::format("Invalid weight window ratio '{}' (<= 1.0) " - "specified for weight window generation")); + // set method + std::string method_string = get_node_value(node, "method"); + if (method_string == "magic") { + method_ = WeightWindowUpdateMethod::MAGIC; + } else if (method_string == "fw_cadis") { + method_ = WeightWindowUpdateMethod::FW_CADIS; } else { fatal_error(fmt::format( - "Unknown weight window update method '{}' specified", method_)); + "Unknown weight window update method '{}' specified", method_string)); + } + + // parse non-default update parameters if specified + if (check_for_node(node, "update_parameters")) { + pugi::xml_node params_node = node.child("update_parameters"); + if (check_for_node(params_node, "value")) + tally_value_ = get_node_value(params_node, "value"); + if (check_for_node(params_node, "threshold")) + threshold_ = std::stod(get_node_value(params_node, "threshold")); + if (check_for_node(params_node, "ratio")) { + ratio_ = std::stod(get_node_value(params_node, "ratio")); + } + } + + // check update parameter values + if (tally_value_ != "mean" && tally_value_ != "rel_err") { + fatal_error(fmt::format("Unsupported tally value '{}' specified for " + "weight window generation.", + tally_value_)); } + if (threshold_ <= 0.0) + fatal_error(fmt::format("Invalid relative error threshold '{}' (<= 0.0) " + "specified for weight window generation", + ratio_)); + if (ratio_ <= 1.0) + fatal_error(fmt::format("Invalid weight window ratio '{}' (<= 1.0) " + "specified for weight window generation")); // create a matching weight windows object auto wws = WeightWindows::create(); diff --git a/tests/regression_tests/weightwindows_fw_cadis/test.py b/tests/regression_tests/weightwindows_fw_cadis/test.py index 3109ae2cb8f..520b8b42f7f 100644 --- a/tests/regression_tests/weightwindows_fw_cadis/test.py +++ b/tests/regression_tests/weightwindows_fw_cadis/test.py @@ -16,7 +16,6 @@ def _cleanup(self): def test_random_ray_adjoint_fixed_source(): model = random_ray_three_region_cube() - model.settings.random_ray['adjoint'] = True ww_mesh = openmc.RegularMesh() n = 6 @@ -25,7 +24,7 @@ def test_random_ray_adjoint_fixed_source(): ww_mesh.lower_left = (0.0, 0.0, 0.0) ww_mesh.upper_right = (width, width, width) - wwg = openmc.WeightWindowGenerator(mesh=ww_mesh, max_realizations=model.settings.batches) + wwg = openmc.WeightWindowGenerator(method="fw_cadis", mesh=ww_mesh, max_realizations=model.settings.batches) model.settings.weight_window_generators = wwg model.settings.random_ray['volume_estimator'] = 'naive' From 91c09d1626d488a2b4783b85e4ebf3d25081a960 Mon Sep 17 00:00:00 2001 From: John Tramm Date: Wed, 22 Jan 2025 09:52:19 -0600 Subject: [PATCH 10/27] force adjoint to be on if FW-CADIS is selected --- src/weight_windows.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/weight_windows.cpp b/src/weight_windows.cpp index bc53e5f7bca..b8ed0a0fe6b 100644 --- a/src/weight_windows.cpp +++ b/src/weight_windows.cpp @@ -791,6 +791,10 @@ WeightWindowsGenerator::WeightWindowsGenerator(pugi::xml_node node) method_ = WeightWindowUpdateMethod::MAGIC; } else if (method_string == "fw_cadis") { method_ = WeightWindowUpdateMethod::FW_CADIS; + if (solver_type != SolverType::RANDOM_RAY) { + fatal_error("FW-CADIS can only be run in random ray solver mode."); + } + FlatSourceDomain::adjoint_ = true; } else { fatal_error(fmt::format( "Unknown weight window update method '{}' specified", method_string)); From 26883f873c0b7d204cc6641ea2ae51db6725087b Mon Sep 17 00:00:00 2001 From: John Tramm Date: Wed, 22 Jan 2025 10:07:59 -0600 Subject: [PATCH 11/27] switched to check for random ray and adjoint solve to decide if we want to use fw_CADIS generation due to lack of WW Generator object access --- src/weight_windows.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/weight_windows.cpp b/src/weight_windows.cpp index b8ed0a0fe6b..ca06f1b5a10 100644 --- a/src/weight_windows.cpp +++ b/src/weight_windows.cpp @@ -626,9 +626,10 @@ void WeightWindows::update_magic( int e_bins = new_bounds.shape()[0]; - if (method_ == WeightWindowUpdateMethod::MAGIC) { + if (settings::solver_type == SolverType::MONTE_CARLO || + !FlatSourceDomain::adjoint_) { // If we are computing weight windows with forward fluxes derived from a - // Monte Carlo or random ray solve, we use the MAGIC algorithm. + // Monte Carlo or forward random ray solve, we use the MAGIC algorithm. for (int e = 0; e < e_bins; e++) { // select all auto group_view = xt::view(new_bounds, e); @@ -645,9 +646,9 @@ void WeightWindows::update_magic( if (group_max > 0.0) group_view /= 2.0 * group_max; } - } else if (method_ == WeightWindowUpdateMethod::FW_CADIS){ - // If we are computing weight windows with adjoint fluxes derived from a - // random ray solve, we use the FW-CADIS algorithm. + } else { + // If we are computing weight windows with adjoint fluxes derived from an + // adjoint random ray solve, we use the FW-CADIS algorithm. for (int e = 0; e < e_bins; e++) { // select all auto group_view = xt::view(new_bounds, e); @@ -789,6 +790,9 @@ WeightWindowsGenerator::WeightWindowsGenerator(pugi::xml_node node) std::string method_string = get_node_value(node, "method"); if (method_string == "magic") { method_ = WeightWindowUpdateMethod::MAGIC; + if (solver_type == SolverType::RANDOM_RAY && FlatSourceDomain::adjoint_) { + fatal_error("Random ray weight window generation with MAGIC cannot be done in adjoint mode."); + } } else if (method_string == "fw_cadis") { method_ = WeightWindowUpdateMethod::FW_CADIS; if (solver_type != SolverType::RANDOM_RAY) { From de80a8637a708b069ad7cb6c51ad615d7edaa012 Mon Sep 17 00:00:00 2001 From: John Tramm Date: Wed, 22 Jan 2025 10:16:52 -0600 Subject: [PATCH 12/27] updated python interface to accommodate fw_cadis, and changed test to use new format --- CMakeLists.txt | 2 ++ openmc/weight_windows.py | 16 +++++++--------- src/weight_windows.cpp | 8 +++++--- .../weightwindows_fw_cadis/inputs_true.dat | 3 +-- 4 files changed, 15 insertions(+), 14 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 575e45373ae..2c56e7b25cc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -206,6 +206,8 @@ set(CMAKE_POSITION_INDEPENDENT_CODE ON) if(OPENMC_ENABLE_PROFILE) list(APPEND cxxflags -g -fno-omit-frame-pointer) endif() + +list(APPEND cxxflags -fno-relaxed-template-template-args) if(OPENMC_ENABLE_COVERAGE) list(APPEND cxxflags --coverage) diff --git a/openmc/weight_windows.py b/openmc/weight_windows.py index 1ddbfe10fe1..0502d309f5e 100644 --- a/openmc/weight_windows.py +++ b/openmc/weight_windows.py @@ -660,9 +660,8 @@ class WeightWindowGenerator: maximum and minimum energy for the data available at runtime. particle_type : {'neutron', 'photon'} Particle type the weight windows apply to - method : {'magic'} - The weight window generation methodology applied during an update. Only - 'magic' is currently supported. + method : {'magic', 'fw_cadis'} + The weight window generation methodology applied during an update. max_realizations : int The upper limit for number of tally realizations when generating weight windows. @@ -680,9 +679,8 @@ class WeightWindowGenerator: energies in [eV] for a single bin particle_type : {'neutron', 'photon'} Particle type the weight windows apply to - method : {'magic'} - The weight window generation methodology applied during an update. Only - 'magic' is currently supported. + method : {'magic', 'fw_cadis'} + The weight window generation methodology applied during an update. max_realizations : int The upper limit for number of tally realizations when generating weight windows. @@ -767,7 +765,7 @@ def method(self) -> str: @method.setter def method(self, m: str): cv.check_type('generation method', m, str) - cv.check_value('generation method', m, {'magic'}) + cv.check_value('generation method', m, ('magic', 'fw_cadis')) self._method = m if self._update_parameters is not None: try: @@ -800,7 +798,7 @@ def update_parameters(self) -> dict: return self._update_parameters def _check_update_parameters(self, params: dict): - if self.method == 'magic': + if self.method == 'magic' or self.method == 'fw_cadis': check_params = self._MAGIC_PARAMS for key, val in params.items(): @@ -843,7 +841,7 @@ def _sanitize_update_parameters(cls, method: str, update_parameters: dict): update_parameters : dict The update parameters as-read from the XML node (keys: str, values: str) """ - if method == 'magic': + if method == 'magic' or method == 'fw_cadis': check_params = cls._MAGIC_PARAMS for param, param_type in check_params.items(): diff --git a/src/weight_windows.cpp b/src/weight_windows.cpp index ca06f1b5a10..10a7801a73f 100644 --- a/src/weight_windows.cpp +++ b/src/weight_windows.cpp @@ -790,12 +790,14 @@ WeightWindowsGenerator::WeightWindowsGenerator(pugi::xml_node node) std::string method_string = get_node_value(node, "method"); if (method_string == "magic") { method_ = WeightWindowUpdateMethod::MAGIC; - if (solver_type == SolverType::RANDOM_RAY && FlatSourceDomain::adjoint_) { - fatal_error("Random ray weight window generation with MAGIC cannot be done in adjoint mode."); + if (settings::solver_type == SolverType::RANDOM_RAY && + FlatSourceDomain::adjoint_) { + fatal_error("Random ray weight window generation with MAGIC cannot be " + "done in adjoint mode."); } } else if (method_string == "fw_cadis") { method_ = WeightWindowUpdateMethod::FW_CADIS; - if (solver_type != SolverType::RANDOM_RAY) { + if (settings::solver_type != SolverType::RANDOM_RAY) { fatal_error("FW-CADIS can only be run in random ray solver mode."); } FlatSourceDomain::adjoint_ = true; diff --git a/tests/regression_tests/weightwindows_fw_cadis/inputs_true.dat b/tests/regression_tests/weightwindows_fw_cadis/inputs_true.dat index 8214666a0a0..586bbb12026 100644 --- a/tests/regression_tests/weightwindows_fw_cadis/inputs_true.dat +++ b/tests/regression_tests/weightwindows_fw_cadis/inputs_true.dat @@ -211,7 +211,7 @@ 10 1 true - magic + fw_cadis @@ -228,7 +228,6 @@ True - True naive From 5899f29531f8dc16bb3293c00d2bc0d9e30b86f5 Mon Sep 17 00:00:00 2001 From: John Tramm Date: Wed, 22 Jan 2025 10:42:50 -0600 Subject: [PATCH 13/27] more work on updating and cleaning up the docs on variance reduction --- docs/source/io_formats/settings.rst | 2 +- docs/source/usersguide/random_ray.rst | 9 ++-- docs/source/usersguide/variance_reduction.rst | 46 +++++++++++-------- 3 files changed, 32 insertions(+), 25 deletions(-) diff --git a/docs/source/io_formats/settings.rst b/docs/source/io_formats/settings.rst index 34b73fc55c5..73ff862009e 100644 --- a/docs/source/io_formats/settings.rst +++ b/docs/source/io_formats/settings.rst @@ -1380,7 +1380,7 @@ mesh-based weight windows. *Default*: true :method: - Method used to update weight window values (currently only 'magic' is supported) + Method used to update weight window values (one of 'magic' or 'fw_cadis') *Default*: magic diff --git a/docs/source/usersguide/random_ray.rst b/docs/source/usersguide/random_ray.rst index 404adfc85fb..10ffdfde10b 100644 --- a/docs/source/usersguide/random_ray.rst +++ b/docs/source/usersguide/random_ray.rst @@ -435,10 +435,11 @@ Inputting Multigroup Cross Sections (MGXS) Multigroup cross sections for use with OpenMC's random ray solver are input the same way as with OpenMC's traditional multigroup Monte Carlo mode. There is more information on generating multigroup cross sections via OpenMC in the -:ref:`multigroup materials ` user guide. You may also wish to -use an existing multigroup library. An example of using OpenMC's Python -interface to generate a correctly formatted ``mgxs.h5`` input file is given -in the `OpenMC Jupyter notebook collection +:ref:`multigroup materials ` user guide. You may also wish to use +an existing ``mgxs.h5`` MGXS library file, or define your own given a known set +of cross section data values (e.g., as taken from a benchmark specification). An +example of using OpenMC's Python interface to generate a correctly formatted +``mgxs.h5`` input file is given in the `OpenMC Jupyter notebook collection `_. .. note:: diff --git a/docs/source/usersguide/variance_reduction.rst b/docs/source/usersguide/variance_reduction.rst index 2f5f8744a48..72a27cd64ed 100644 --- a/docs/source/usersguide/variance_reduction.rst +++ b/docs/source/usersguide/variance_reduction.rst @@ -4,7 +4,7 @@ Variance Reduction ================== -Global variance reduction in OpenMC is accomplished by weight windowing techniques. OpenMC is capable of generating weight windows using either the MAGIC or FW-CADIS methods. Both techniques will produce a "weight_windows.h5" file that can be loaded and used later on. In this section, we break down the steps required to both generate and then apply weight windows. +Global variance reduction in OpenMC is accomplished by weight windowing techniques. OpenMC is capable of generating weight windows using either the MAGIC or FW-CADIS methods. Both techniques will produce a ``weight_windows.h5`` file that can be loaded and used later on. In this section, we break down the steps required to both generate and then apply weight windows. .. _ww_generator: @@ -14,7 +14,7 @@ Generating Weight Windows with MAGIC As discussed in the methods section, MAGIC is an iterative method that uses flux tally information from a Monte Carlo simulation to produce weight windows for a user defined mesh. While generating the weight windows, OpenMC is capable of applying the weight windows generated from a previous batch while processing the next batch, allowing for progressive improvement in the weight window quality across iterations. -The most typical way of generating weight windows is to define a mesh and then add a :class:`WeightWindowGenerator` object to the :attr:`openmc.Settings` object, as follows:: +The most typical way of generating weight windows is to define a mesh and then add an :class:`openmc.WeightWindowGenerator` object to the :attr:`openmc.Settings` object, as follows:: # Define weight window spatial mesh ww_mesh = openmc.RegularMesh() @@ -23,35 +23,31 @@ The most typical way of generating weight windows is to define a mesh and then a ww_mesh.upper_right = (100.0, 100.0, 100.0) # Create weight window object and adjust parameters - wwg = openmc.WeightWindowGenerator(mesh=ww_mesh, max_realizations=1000) + wwg = openmc.WeightWindowGenerator(method='magic', mesh=ww_mesh, max_realizations=settings.batches) # Add generator to openmc.settings object settings.weight_window_generators = wwg - settings.weight_window_checkpoints = {'collision': True, 'surface': True} -Notably, the :attr:`max_realizations` attribute is adjusted to 1000, such that multiple iterations are used to refine the weight window parameters. +Notably, the :attr:`max_realizations` attribute is adjusted to the number of batches, such that all iterations are used to refine the weight window parameters. -With the :class:`WeightWindowGenerator` object added to the :attr:`openmc.Settings` object, the rest of the problem can be defined as normal. When running, note that the second iteration and beyond may be several orders of magnitude slower than the first. As the weight windows are applied in each iteration, particles may be agressively split, resulting in a large number of secondary (split) particles being generated per initial source particle. This is not necessarily a bad thing, as the split particles are much more efficient at exploring low flux regions of phase space as compared to initial particles. Thus, even though the reported "particles/second" metric of OpenMC may be much lower when generating (or just applying) weight windows as compared to analog MC, the variance vs. runtime figure of merit is typically much more advantageous. +With the :class:`openmc.WeightWindowGenerator` object added to the :attr:`openmc.Settings` object, the rest of the problem can be defined as normal. When running, note that the second iteration and beyond may be several orders of magnitude slower than the first. As the weight windows are applied in each iteration, particles may be agressively split, resulting in a large number of secondary (split) particles being generated per initial source particle. This is not necessarily a bad thing, as the split particles are much more efficient at exploring low flux regions of phase space as compared to initial particles. Thus, even though the reported "particles/second" metric of OpenMC may be much lower when generating (or just applying) weight windows as compared to analog MC, the variance vs. runtime figure of merit is typically much more advantageous. .. warning:: The number of particles per batch may need to be adjusted downward significantly to result in reasonable runtimes when weight windows are being generated or used. -At the end of the simulation, a "weight_windows.h5" file will be saved to disk for later use. Loading it in another subsequent simulation will be discussed in the "Using Weight Windows" section below. +At the end of the simulation, a ``weight_windows.h5`` file will be saved to disk for later use. Loading it in another subsequent simulation will be discussed in the "Using Weight Windows" section below. ------------------------------------------------------ Generating Weight Windows with FW-CADIS and Random Ray ------------------------------------------------------ -Weight window generation with FW-CADIS and random ray in OpenMC uses the same exact strategy as with MAGIC. A :class:`WeightWindowGenerator` object is added to the :attr:`openmc.Settings` object, and a "weight_windows.h5" will be generated at the end of the simulation. +Weight window generation with FW-CADIS and random ray in OpenMC uses the same exact strategy as with MAGIC. An :class:`openmc.WeightWindowGenerator` object is added to the :attr:`openmc.Settings` object, and a ``weight_windows.h5`` will be generated at the end of the simulation. -The only difference is that the code must be run in random ray mode, and adjoint mode enabled. A full description of how to enable and setup random ray mode can be found in the :ref:`Random Ray User Guide -`. +The only difference is that the code must be run in random ray mode. A full description of how to enable and setup random ray mode can be found in the :ref:`Random Ray User Guide `. .. note:: It is a long term goal for OpenMC to be able to generate FW-CADIS weight windows with only a few tweaks to an existing continuous energy Monte Carlo input deck. However, at the present time, the workflow requires several steps to generate multigroup cross section data and to configure the random ray solver. A high level overview of the current workflow for generation of weight windows with FW-CADIS using random ray is given below. -1. Produce approximate multigroup cross section data (stored in a `mgxs.h5` library). There is more -information on generating multigroup cross sections via OpenMC in the -:ref:`multigroup materials ` user guide, and a specific example of generating cross section data for use with random ray in the :ref:`random ray MGXS guide `. +1. Produce approximate multigroup cross section data (stored in a ``mgxs.h5`` library). There is more information on generating multigroup cross sections via OpenMC in the :ref:`multigroup materials ` user guide, and a specific example of generating cross section data for use with random ray in the :ref:`random ray MGXS guide `. 2. Make a copy of your continuous energy python input file. You'll edit the new file to work in multigroup mode with random ray for producing weight windows. @@ -59,15 +55,25 @@ information on generating multigroup cross sections via OpenMC in the 4. Configure OpenMC to run in random ray mode (by adding several standard random ray input flags and settings to the :attr:`openmc.Settings.random_ray` dictionary). More information can be found in the :ref:`Random Ray User Guide `. -5. Enable adjoint mode in random ray as:: - - settings.random_ray['adjoint'] = True +5. Add in an :class:`openmc.WeightWindowGenerator` in a similar manner as for MAGIC generation with Monte Carlo, though with the :attr:`method` attribute set to ``fw_cadis``:: + + # Define weight window spatial mesh + ww_mesh = openmc.RegularMesh() + ww_mesh.dimension = (10, 10, 10) + ww_mesh.lower_left = (0.0, 0.0, 0.0) + ww_mesh.upper_right = (100.0, 100.0, 100.0) + + # Create weight window object and adjust parameters + wwg = openmc.WeightWindowGenerator(method='fw_cadis', mesh=ww_mesh, max_realizations=settings.batches) + + # Add generator to openmc.settings object + settings.weight_window_generators = wwg -If the random ray solver in OpenMC is run in adjoint mode, the FW-CADIS algorithm will be utilized if weight window generation is enabled. If adjoint mode is not enabled, then the MAGIC algorithm will be used with the available forward flux tally data. As FW-CADIS weight windows are usually more efficient, it is highly recommended to use FW-CADIS and adjoint mode. -6. Add in a :class:`WeightWindowGenerator` in the same manner as for MAGIC generation with Monte Carlo, as in the example given above in the :ref:`MAGIC weight window generator guide `. Ensure that the selected weight window mesh does not subdivide any cells in the problem. In the future, this restriction is intended to be relaxed, but for now subdivision of cells by a mesh tally will result in undefined behavior. +.. warning:: + If using FW-CADIS weight window generation, ensure that the selected weight window mesh does not subdivide any cells in the problem. In the future, this restriction is intended to be relaxed, but for now subdivision of cells by a mesh tally will result in undefined behavior. -7. When running your multigroup random ray input deck, OpenMC will automatically run a forward solve followed by an adjoint solve, with a "weight_windows.h5" file generated at the end. The weight_windows.h5 file will contain FW-CADIS generated weight windows. This file can be used in identical manner as one generated with MAGIC, as described below. +6. When running your multigroup random ray input deck, OpenMC will automatically run a forward solve followed by an adjoint solve, with a ``weight_windows.h5`` file generated at the end. The ``weight_windows.h5`` file will contain FW-CADIS generated weight windows. This file can be used in identical manner as one generated with MAGIC, as described below. -------------------- Using Weight Windows @@ -80,4 +86,4 @@ To use a "weight_windows.h5" weight window file with OpenMC's Monte Carlo solver settings.weight_windows = openmc.hdf5_to_wws() settings.weight_windows_on = True -Make sure that the :class:`WeightWindowGenerator` is not present in the file when loading existing weight windows, so as to avoid added costs of generating weight windows again. Weight window mesh information is embedded into the weight window file, so it does not need to be redfined. Monte Carlo solves that load a weight window file as above will utilize the weight windows to reduce the variance of the simulation. \ No newline at end of file +Make sure that the :class:`openmc.WeightWindowGenerator` is not present in the file when loading existing weight windows, so as to avoid added costs of generating weight windows again and overwriting the original weight window file. Weight window mesh information is embedded into the weight window file, so the mesh does not need to be redefined. Monte Carlo solves that load a weight window file as above will utilize the weight windows to reduce the variance of the simulation. \ No newline at end of file From 0f0ca7602bf7fe83cfe1bc8d2086b95dd80cf1a0 Mon Sep 17 00:00:00 2001 From: John Tramm Date: Wed, 22 Jan 2025 10:44:00 -0600 Subject: [PATCH 14/27] Text wrapping on docs --- docs/source/methods/variance_reduction.rst | 104 +++++++++++++++--- docs/source/usersguide/variance_reduction.rst | 89 ++++++++++++--- 2 files changed, 161 insertions(+), 32 deletions(-) diff --git a/docs/source/methods/variance_reduction.rst b/docs/source/methods/variance_reduction.rst index db4ac4f643f..f136a8e4ffa 100644 --- a/docs/source/methods/variance_reduction.rst +++ b/docs/source/methods/variance_reduction.rst @@ -10,45 +10,119 @@ Variance Reduction Introduction ------------ -Transport problems can sometimes infolve a significant degree of attenuation between the neutron source and a detector (tally) region, which can result in a flux differential of ten orders of magnitude (or more) throughout the simulation domain. As Monte Carlo uncertainties tend to be inversely proportional to the physical flux density, it can be extremely difficult to accurately resolve tallies in locations that are optically far from the source. This issue is particularly common in fixed source simulations, where some tally locations may not experience a single scoring event, even after billions of analog histories. - -Variance reduction techniques aim to either flatten the global uncertainty distribution, such that all regions of phase space have a fairly similar uncertainty, or to reduce the uncertainty in specific locations (such as a detector). There are two strategies available in OpenMC for variance reduction: the Monte Carlo MAGIC method, and with FW-CADIS. Both strategies work by developing a weight window mesh, which can be utilized by subsequent Monte Carlo solves to split particles heading towards areas of lower flux densities while terminating particles in higher flux regions -- all while maintaining a fair game. +Transport problems can sometimes infolve a significant degree of attenuation +between the neutron source and a detector (tally) region, which can result in a +flux differential of ten orders of magnitude (or more) throughout the simulation +domain. As Monte Carlo uncertainties tend to be inversely proportional to the +physical flux density, it can be extremely difficult to accurately resolve +tallies in locations that are optically far from the source. This issue is +particularly common in fixed source simulations, where some tally locations may +not experience a single scoring event, even after billions of analog histories. + +Variance reduction techniques aim to either flatten the global uncertainty +distribution, such that all regions of phase space have a fairly similar +uncertainty, or to reduce the uncertainty in specific locations (such as a +detector). There are two strategies available in OpenMC for variance reduction: +the Monte Carlo MAGIC method, and with FW-CADIS. Both strategies work by +developing a weight window mesh, which can be utilized by subsequent Monte Carlo +solves to split particles heading towards areas of lower flux densities while +terminating particles in higher flux regions -- all while maintaining a fair +game. ------------ MAGIC Method ------------ -The MAGIC method is an iterative technique that uses spatial flux information (:math:`\phi(r)`) obtained from a normal Monte Carlo solve to produce weight windows (:math:`\w(r)`) that can be utilized by a subsequent iteration of Monte Carlo. While the first generation of weight windows produced may only help to reduce variance slightly, use of these weights to generate another set of weight windows results in a progressively improving iterative scheme. +The MAGIC method is an iterative technique that uses spatial flux information +(:math:`\phi(r)`) obtained from a normal Monte Carlo solve to produce weight +windows (:math:`\w(r)`) that can be utilized by a subsequent iteration of Monte +Carlo. While the first generation of weight windows produced may only help to +reduce variance slightly, use of these weights to generate another set of weight +windows results in a progressively improving iterative scheme. -Equation :eq:`magic` defines how the lower bound of weight windows (:math:`\w_\ell(r)`) are generated with MAGIC using forward flux information. Here, we can see that the flux at location :math:`r` is normalized by the maximum flux in any group at that location. We can also see that the weights are divided by a factor of two, which accounts for the typical :math:`5\times` factor separating the lower and upper weight window bounds in OpenMC. +Equation :eq:`magic` defines how the lower bound of weight windows +(:math:`\w_\ell(r)`) are generated with MAGIC using forward flux information. +Here, we can see that the flux at location :math:`r` is normalized by the +maximum flux in any group at that location. We can also see that the weights are +divided by a factor of two, which accounts for the typical :math:`5\times` +factor separating the lower and upper weight window bounds in OpenMC. .. math:: :label: magic w_\ell(r) = \frac{\phi(r)}{2\text{max}(\phi(r))} -A major advantage of this technique is that it does not require any special transport machinery -- it simply uses multiple Monte Carlo simulations to iteratively improve a set of weight windows (which are typically defined on a mesh covering the simulation domain). The downside to this method is that as the flux differential increases between areas near and far from the source, it requires more outer Monte Carlo iterations, each of which can be highly expensive in itself. Additionally, computation of weight windows based on regular (forward) neutron flux tally information does not produce the most numerically effective set of weight windows. Nonetheless, MAGIC remains a simple and effective technique for generating weight windows. +A major advantage of this technique is that it does not require any special +transport machinery -- it simply uses multiple Monte Carlo simulations to +iteratively improve a set of weight windows (which are typically defined on a +mesh covering the simulation domain). The downside to this method is that as the +flux differential increases between areas near and far from the source, it +requires more outer Monte Carlo iterations, each of which can be highly +expensive in itself. Additionally, computation of weight windows based on +regular (forward) neutron flux tally information does not produce the most +numerically effective set of weight windows. Nonetheless, MAGIC remains a simple +and effective technique for generating weight windows. -------- FW-CADIS -------- -As discussed in the previous section, computation of weight windows based on regular (forward) neutron flux tally information does not produce the most numerically efficient set of weight windows. It is highly preferable to generate weight windows based on spatial adjoint flux (:math:`\phi^{\dag}(r)`) information. The adjoint flux is essentially the "reverse" simulation problem, where we sample a random point and assume this is where a particle was absorbed, and then trace it backwards (upscattering in energy), until we sample the point where it was born from. +As discussed in the previous section, computation of weight windows based on +regular (forward) neutron flux tally information does not produce the most +numerically efficient set of weight windows. It is highly preferable to generate +weight windows based on spatial adjoint flux (:math:`\phi^{\dag}(r)`) +information. The adjoint flux is essentially the "reverse" simulation problem, +where we sample a random point and assume this is where a particle was absorbed, +and then trace it backwards (upscattering in energy), until we sample the point +where it was born from. -The FW-CADIS method produces weight windows for global variance reduction given adjoint flux information throughout the entire domain. It is defined in Equation :eq:`fw_cadis`, and also involves a normalization step not shown here. +The FW-CADIS method produces weight windows for global variance reduction given +adjoint flux information throughout the entire domain. It is defined in Equation +:eq:`fw_cadis`, and also involves a normalization step not shown here. .. math:: :label: fw_cadis w_\ell(r) = \frac{1}{2\phi^{\dag}(r)} -While the algorithm itself is quite simple, it requires estimates of the global adjoint flux distribution, which is difficult to generate directly with Monte Carlo transport. Thus, FW-CADIS typically uses an alternative solver (often deterministic) that can be more readily adapted for generating adjoint flux information, and which is often much cheaper than Monte Carlo given that maximal-fidelity is not needed for weight window generation. - -The FW-CADIS implementation in OpenMC utilizes its own internal random ray multigroup transport solver. No coupling to an external solver or library is needed for generating weight windows with OpenMC. The random ray solver is ideal for this purpose as it naturally produces a relatively uniform uncertainty distribution throughout the simulation domain that is not proportional to the physical flux density. Additionally, the random ray solver operates on the same geometry as the Monte Carlo solver (all OpenMC geometries are supported), so the user does not need to provide a second set of inputs. - -More information on the workflow is available in the user guide, but generally production of weight windows with FW-CADIS involves several stages (some of which are highly automated). These tasks include generation of approximate multigroup cross section data for use by the random ray solver, running of the random ray solver in normal (forward flux) mode to generate a source for the adjoint solver, running of the random ray solver in adjoint mode to generate adjoint flux tallies, and finally the production of weight windows via the FW-CADIS method. As is discussed in the user guide, most of these steps are automated together, making the additional burden on the user fairly small. - -The major advantage of this technique is that it typically produces much more numerically efficient weight windows as compared to those generated with MAGIC, sometimes with an improvement on the variance vs. runtime figure of merit (Equation :eq:`variance_fom`) of an order of magnitude. Another major advantage is that the cost of the random ray solver is typically negligible compared to the cost of the subsequent Monte Carlo solve itself, making it a very cheap method to deploy. The downside to this method is that it introduces a second transport method into the mix (random ray), such that there are more free input parameters for the user to know about and adjust, potentially making the method more complex to use. However, as many of the parameters have natural choices, much of this parameterization can be handled automatically behind the scenes without the need for the user to be aware of this. +While the algorithm itself is quite simple, it requires estimates of the global +adjoint flux distribution, which is difficult to generate directly with Monte +Carlo transport. Thus, FW-CADIS typically uses an alternative solver (often +deterministic) that can be more readily adapted for generating adjoint flux +information, and which is often much cheaper than Monte Carlo given that +maximal-fidelity is not needed for weight window generation. + +The FW-CADIS implementation in OpenMC utilizes its own internal random ray +multigroup transport solver. No coupling to an external solver or library is +needed for generating weight windows with OpenMC. The random ray solver is ideal +for this purpose as it naturally produces a relatively uniform uncertainty +distribution throughout the simulation domain that is not proportional to the +physical flux density. Additionally, the random ray solver operates on the same +geometry as the Monte Carlo solver (all OpenMC geometries are supported), so the +user does not need to provide a second set of inputs. + +More information on the workflow is available in the user guide, but generally +production of weight windows with FW-CADIS involves several stages (some of +which are highly automated). These tasks include generation of approximate +multigroup cross section data for use by the random ray solver, running of the +random ray solver in normal (forward flux) mode to generate a source for the +adjoint solver, running of the random ray solver in adjoint mode to generate +adjoint flux tallies, and finally the production of weight windows via the +FW-CADIS method. As is discussed in the user guide, most of these steps are +automated together, making the additional burden on the user fairly small. + +The major advantage of this technique is that it typically produces much more +numerically efficient weight windows as compared to those generated with MAGIC, +sometimes with an improvement on the variance vs. runtime figure of merit +(Equation :eq:`variance_fom`) of an order of magnitude. Another major advantage +is that the cost of the random ray solver is typically negligible compared to +the cost of the subsequent Monte Carlo solve itself, making it a very cheap +method to deploy. The downside to this method is that it introduces a second +transport method into the mix (random ray), such that there are more free input +parameters for the user to know about and adjust, potentially making the method +more complex to use. However, as many of the parameters have natural choices, +much of this parameterization can be handled automatically behind the scenes +without the need for the user to be aware of this. .. math:: :label: variance_fom diff --git a/docs/source/usersguide/variance_reduction.rst b/docs/source/usersguide/variance_reduction.rst index 72a27cd64ed..c89f422ef13 100644 --- a/docs/source/usersguide/variance_reduction.rst +++ b/docs/source/usersguide/variance_reduction.rst @@ -4,7 +4,11 @@ Variance Reduction ================== -Global variance reduction in OpenMC is accomplished by weight windowing techniques. OpenMC is capable of generating weight windows using either the MAGIC or FW-CADIS methods. Both techniques will produce a ``weight_windows.h5`` file that can be loaded and used later on. In this section, we break down the steps required to both generate and then apply weight windows. +Global variance reduction in OpenMC is accomplished by weight windowing +techniques. OpenMC is capable of generating weight windows using either the +MAGIC or FW-CADIS methods. Both techniques will produce a ``weight_windows.h5`` +file that can be loaded and used later on. In this section, we break down the +steps required to both generate and then apply weight windows. .. _ww_generator: @@ -12,9 +16,16 @@ Global variance reduction in OpenMC is accomplished by weight windowing techniqu Generating Weight Windows with MAGIC ------------------------------------ -As discussed in the methods section, MAGIC is an iterative method that uses flux tally information from a Monte Carlo simulation to produce weight windows for a user defined mesh. While generating the weight windows, OpenMC is capable of applying the weight windows generated from a previous batch while processing the next batch, allowing for progressive improvement in the weight window quality across iterations. +As discussed in the methods section, MAGIC is an iterative method that uses flux +tally information from a Monte Carlo simulation to produce weight windows for a +user defined mesh. While generating the weight windows, OpenMC is capable of +applying the weight windows generated from a previous batch while processing the +next batch, allowing for progressive improvement in the weight window quality +across iterations. -The most typical way of generating weight windows is to define a mesh and then add an :class:`openmc.WeightWindowGenerator` object to the :attr:`openmc.Settings` object, as follows:: +The most typical way of generating weight windows is to define a mesh and then +add an :class:`openmc.WeightWindowGenerator` object to the +:attr:`openmc.Settings` object, as follows:: # Define weight window spatial mesh ww_mesh = openmc.RegularMesh() @@ -28,34 +39,67 @@ The most typical way of generating weight windows is to define a mesh and then a # Add generator to openmc.settings object settings.weight_window_generators = wwg -Notably, the :attr:`max_realizations` attribute is adjusted to the number of batches, such that all iterations are used to refine the weight window parameters. - -With the :class:`openmc.WeightWindowGenerator` object added to the :attr:`openmc.Settings` object, the rest of the problem can be defined as normal. When running, note that the second iteration and beyond may be several orders of magnitude slower than the first. As the weight windows are applied in each iteration, particles may be agressively split, resulting in a large number of secondary (split) particles being generated per initial source particle. This is not necessarily a bad thing, as the split particles are much more efficient at exploring low flux regions of phase space as compared to initial particles. Thus, even though the reported "particles/second" metric of OpenMC may be much lower when generating (or just applying) weight windows as compared to analog MC, the variance vs. runtime figure of merit is typically much more advantageous. +Notably, the :attr:`max_realizations` attribute is adjusted to the number of +batches, such that all iterations are used to refine the weight window +parameters. + +With the :class:`openmc.WeightWindowGenerator` object added to the +:attr:`openmc.Settings` object, the rest of the problem can be defined as +normal. When running, note that the second iteration and beyond may be several +orders of magnitude slower than the first. As the weight windows are applied in +each iteration, particles may be agressively split, resulting in a large number +of secondary (split) particles being generated per initial source particle. This +is not necessarily a bad thing, as the split particles are much more efficient +at exploring low flux regions of phase space as compared to initial particles. +Thus, even though the reported "particles/second" metric of OpenMC may be much +lower when generating (or just applying) weight windows as compared to analog +MC, the variance vs. runtime figure of merit is typically much more +advantageous. .. warning:: The number of particles per batch may need to be adjusted downward significantly to result in reasonable runtimes when weight windows are being generated or used. -At the end of the simulation, a ``weight_windows.h5`` file will be saved to disk for later use. Loading it in another subsequent simulation will be discussed in the "Using Weight Windows" section below. +At the end of the simulation, a ``weight_windows.h5`` file will be saved to disk +for later use. Loading it in another subsequent simulation will be discussed in +the "Using Weight Windows" section below. ------------------------------------------------------ Generating Weight Windows with FW-CADIS and Random Ray ------------------------------------------------------ -Weight window generation with FW-CADIS and random ray in OpenMC uses the same exact strategy as with MAGIC. An :class:`openmc.WeightWindowGenerator` object is added to the :attr:`openmc.Settings` object, and a ``weight_windows.h5`` will be generated at the end of the simulation. +Weight window generation with FW-CADIS and random ray in OpenMC uses the same +exact strategy as with MAGIC. An :class:`openmc.WeightWindowGenerator` object is +added to the :attr:`openmc.Settings` object, and a ``weight_windows.h5`` will be +generated at the end of the simulation. -The only difference is that the code must be run in random ray mode. A full description of how to enable and setup random ray mode can be found in the :ref:`Random Ray User Guide `. +The only difference is that the code must be run in random ray mode. A full +description of how to enable and setup random ray mode can be found in the +:ref:`Random Ray User Guide `. .. note:: It is a long term goal for OpenMC to be able to generate FW-CADIS weight windows with only a few tweaks to an existing continuous energy Monte Carlo input deck. However, at the present time, the workflow requires several steps to generate multigroup cross section data and to configure the random ray solver. A high level overview of the current workflow for generation of weight windows with FW-CADIS using random ray is given below. -1. Produce approximate multigroup cross section data (stored in a ``mgxs.h5`` library). There is more information on generating multigroup cross sections via OpenMC in the :ref:`multigroup materials ` user guide, and a specific example of generating cross section data for use with random ray in the :ref:`random ray MGXS guide `. +1. Produce approximate multigroup cross section data (stored in a ``mgxs.h5`` + library). There is more information on generating multigroup cross sections + via OpenMC in the :ref:`multigroup materials ` user guide, and a + specific example of generating cross section data for use with random ray in + the :ref:`random ray MGXS guide `. -2. Make a copy of your continuous energy python input file. You'll edit the new file to work in multigroup mode with random ray for producing weight windows. +2. Make a copy of your continuous energy python input file. You'll edit the new + file to work in multigroup mode with random ray for producing weight windows. -3. Adjust the material definitions in your new multigroup python file to utilise the multigroup cross sections instead of nuclide-wise continuous energy data. There is a specific example of making this conversion in the random ray in the :ref:`random ray MGXS guide `. +3. Adjust the material definitions in your new multigroup python file to utilise + the multigroup cross sections instead of nuclide-wise continuous energy data. + There is a specific example of making this conversion in the random ray in + the :ref:`random ray MGXS guide `. -4. Configure OpenMC to run in random ray mode (by adding several standard random ray input flags and settings to the :attr:`openmc.Settings.random_ray` dictionary). More information can be found in the :ref:`Random Ray User Guide `. +4. Configure OpenMC to run in random ray mode (by adding several standard random + ray input flags and settings to the :attr:`openmc.Settings.random_ray` + dictionary). More information can be found in the :ref:`Random Ray User + Guide `. -5. Add in an :class:`openmc.WeightWindowGenerator` in a similar manner as for MAGIC generation with Monte Carlo, though with the :attr:`method` attribute set to ``fw_cadis``:: +5. Add in an :class:`openmc.WeightWindowGenerator` in a similar manner as for + MAGIC generation with Monte Carlo, though with the :attr:`method` attribute + set to ``fw_cadis``:: # Define weight window spatial mesh ww_mesh = openmc.RegularMesh() @@ -73,17 +117,28 @@ The only difference is that the code must be run in random ray mode. A full desc .. warning:: If using FW-CADIS weight window generation, ensure that the selected weight window mesh does not subdivide any cells in the problem. In the future, this restriction is intended to be relaxed, but for now subdivision of cells by a mesh tally will result in undefined behavior. -6. When running your multigroup random ray input deck, OpenMC will automatically run a forward solve followed by an adjoint solve, with a ``weight_windows.h5`` file generated at the end. The ``weight_windows.h5`` file will contain FW-CADIS generated weight windows. This file can be used in identical manner as one generated with MAGIC, as described below. +6. When running your multigroup random ray input deck, OpenMC will automatically + run a forward solve followed by an adjoint solve, with a + ``weight_windows.h5`` file generated at the end. The ``weight_windows.h5`` + file will contain FW-CADIS generated weight windows. This file can be used in + identical manner as one generated with MAGIC, as described below. -------------------- Using Weight Windows -------------------- -To use a "weight_windows.h5" weight window file with OpenMC's Monte Carlo solver, the python input just needs to load the h5 file:: +To use a "weight_windows.h5" weight window file with OpenMC's Monte Carlo +solver, the python input just needs to load the h5 file:: settings.weight_window_checkpoints = {'collision': True, 'surface': True} settings.survival_biasing = False settings.weight_windows = openmc.hdf5_to_wws() settings.weight_windows_on = True -Make sure that the :class:`openmc.WeightWindowGenerator` is not present in the file when loading existing weight windows, so as to avoid added costs of generating weight windows again and overwriting the original weight window file. Weight window mesh information is embedded into the weight window file, so the mesh does not need to be redefined. Monte Carlo solves that load a weight window file as above will utilize the weight windows to reduce the variance of the simulation. \ No newline at end of file +Make sure that the :class:`openmc.WeightWindowGenerator` is not present in the +file when loading existing weight windows, so as to avoid added costs of +generating weight windows again and overwriting the original weight window file. +Weight window mesh information is embedded into the weight window file, so the +mesh does not need to be redefined. Monte Carlo solves that load a weight window +file as above will utilize the weight windows to reduce the variance of the +simulation. \ No newline at end of file From 8a342ce197c8c54e9214de836d0ddb8ead08eb8d Mon Sep 17 00:00:00 2001 From: John Tramm Date: Wed, 22 Jan 2025 10:59:37 -0600 Subject: [PATCH 15/27] docs updates --- docs/source/methods/random_ray.rst | 2 ++ docs/source/methods/variance_reduction.rst | 33 +++++++++++----------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/docs/source/methods/random_ray.rst b/docs/source/methods/random_ray.rst index c827c351dd0..eb22b0544da 100644 --- a/docs/source/methods/random_ray.rst +++ b/docs/source/methods/random_ray.rst @@ -1060,6 +1060,8 @@ random ray and Monte Carlo, however. develop the scattering source by way of inactive batches before beginning active batches. +.. _adjoint: + ------------------------ Adjoint Flux Solver Mode ------------------------ diff --git a/docs/source/methods/variance_reduction.rst b/docs/source/methods/variance_reduction.rst index f136a8e4ffa..f80082280f9 100644 --- a/docs/source/methods/variance_reduction.rst +++ b/docs/source/methods/variance_reduction.rst @@ -93,23 +93,22 @@ information, and which is often much cheaper than Monte Carlo given that maximal-fidelity is not needed for weight window generation. The FW-CADIS implementation in OpenMC utilizes its own internal random ray -multigroup transport solver. No coupling to an external solver or library is -needed for generating weight windows with OpenMC. The random ray solver is ideal -for this purpose as it naturally produces a relatively uniform uncertainty -distribution throughout the simulation domain that is not proportional to the -physical flux density. Additionally, the random ray solver operates on the same -geometry as the Monte Carlo solver (all OpenMC geometries are supported), so the -user does not need to provide a second set of inputs. - -More information on the workflow is available in the user guide, but generally -production of weight windows with FW-CADIS involves several stages (some of -which are highly automated). These tasks include generation of approximate -multigroup cross section data for use by the random ray solver, running of the -random ray solver in normal (forward flux) mode to generate a source for the -adjoint solver, running of the random ray solver in adjoint mode to generate -adjoint flux tallies, and finally the production of weight windows via the -FW-CADIS method. As is discussed in the user guide, most of these steps are -automated together, making the additional burden on the user fairly small. +multigroup transport solver to generate the adjoint source distribution. No +coupling to any external transport is solver is necessary. The random ray solver +operates on the same geometry as the Monte Carlo solver, so no redefinition of +the simulation geometry is required. More details on how the adjoint flux is +computed are given in the :ref:`adjoint methods section `. + +More information on the workflow is available in the :ref:`user guide +`, but generally production of weight windows with FW-CADIS +involves several stages (some of which are highly automated). These tasks +include generation of approximate multigroup cross section data for use by the +random ray solver, running of the random ray solver in normal (forward flux) +mode to generate a source for the adjoint solver, running of the random ray +solver in adjoint mode to generate adjoint flux tallies, and finally the +production of weight windows via the FW-CADIS method. As is discussed in the +user guide, most of these steps are automated together, making the additional +burden on the user fairly small. The major advantage of this technique is that it typically produces much more numerically efficient weight windows as compared to those generated with MAGIC, From 08c2ab04b79d8fc47ca9b4f652bf5621e686a2fb Mon Sep 17 00:00:00 2001 From: John Tramm Date: Wed, 22 Jan 2025 11:50:14 -0600 Subject: [PATCH 16/27] took out cmakelists.txt change for clang --- CMakeLists.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2c56e7b25cc..4dedfd941e1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -207,8 +207,6 @@ if(OPENMC_ENABLE_PROFILE) list(APPEND cxxflags -g -fno-omit-frame-pointer) endif() -list(APPEND cxxflags -fno-relaxed-template-template-args) - if(OPENMC_ENABLE_COVERAGE) list(APPEND cxxflags --coverage) list(APPEND ldflags --coverage) From 4613816330a7bce107d5b4984028d6444eeb55b1 Mon Sep 17 00:00:00 2001 From: John Tramm Date: Wed, 22 Jan 2025 11:52:35 -0600 Subject: [PATCH 17/27] fixed spacing in cmakelists.txt --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4dedfd941e1..575e45373ae 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -206,7 +206,7 @@ set(CMAKE_POSITION_INDEPENDENT_CODE ON) if(OPENMC_ENABLE_PROFILE) list(APPEND cxxflags -g -fno-omit-frame-pointer) endif() - + if(OPENMC_ENABLE_COVERAGE) list(APPEND cxxflags --coverage) list(APPEND ldflags --coverage) From b322e0fbc7f8776c0aaae8ea1dc93065bdeebf09 Mon Sep 17 00:00:00 2001 From: John Tramm Date: Wed, 22 Jan 2025 11:58:20 -0600 Subject: [PATCH 18/27] ran git clang format and spaced the docs --- docs/source/usersguide/random_ray.rst | 48 ++++++++++++++++++++++----- include/openmc/weight_windows.h | 4 +-- 2 files changed, 40 insertions(+), 12 deletions(-) diff --git a/docs/source/usersguide/random_ray.rst b/docs/source/usersguide/random_ray.rst index 10ffdfde10b..0448fa66907 100644 --- a/docs/source/usersguide/random_ray.rst +++ b/docs/source/usersguide/random_ray.rst @@ -454,11 +454,27 @@ example of using OpenMC's Python interface to generate a correctly formatted Generating Multigroup Cross Sections (MGXS) ------------------------------------------- -OpenMC is capable of generating multigroup cross sections by way of flux collapsing data based on flux solutions obtained from a continuous energy Monte Carlo solve. While it is a circular excercise in some respects to use continuous energy Monte Carlo to generate cross sections to be used by a reduced-fidelity multigroup transport solver, there are many use cases where this is nonetheless highly desirable. For instance, generation of a multigroup library may enable the same set of approximate multigroup cross section data to be used across a variety of problem types (or through a multidimensional parameter sweep of design variables) with only modest errors and at greatly reduced cost as compared to using only continuous energy Monte Carlo. - -We give here a quick summary of how to produce a multigroup cross section data file (``mgxs.h5``) from a starting point of a typical continuous energy Monte Carlo input file. Notably, continuous energy input files define materials as a mixture of nuclides with different densities, whereas multigroup materials are simply defined by which name they correspond to in a ``mgxs.h5`` library file. - -To generate the cross section data, we begin with a continuous energy Monte Carlo input deck and add in the required tallies that will be needed to generate our library. In this example, we will specify material-wise cross sections and a two group energy decomposition:: +OpenMC is capable of generating multigroup cross sections by way of flux +collapsing data based on flux solutions obtained from a continuous energy Monte +Carlo solve. While it is a circular excercise in some respects to use continuous +energy Monte Carlo to generate cross sections to be used by a reduced-fidelity +multigroup transport solver, there are many use cases where this is nonetheless +highly desirable. For instance, generation of a multigroup library may enable +the same set of approximate multigroup cross section data to be used across a +variety of problem types (or through a multidimensional parameter sweep of +design variables) with only modest errors and at greatly reduced cost as +compared to using only continuous energy Monte Carlo. + +We give here a quick summary of how to produce a multigroup cross section data +file (``mgxs.h5``) from a starting point of a typical continuous energy Monte +Carlo input file. Notably, continuous energy input files define materials as a +mixture of nuclides with different densities, whereas multigroup materials are +simply defined by which name they correspond to in a ``mgxs.h5`` library file. + +To generate the cross section data, we begin with a continuous energy Monte +Carlo input deck and add in the required tallies that will be needed to generate +our library. In this example, we will specify material-wise cross sections and a +two group energy decomposition:: # Define geometry ... @@ -505,7 +521,14 @@ To generate the cross section data, we begin with a continuous energy Monte Carl ... -When selecting an energy decomposition, you can manually define group boundaries or pick out a group structure already known to OpenMC (a list of which can be found at :class:`openmc.mgxs.GROUP_STRUCTURES`). Once the above input deck has been run, the resulting statepoint file will contain the needed flux and reaction rate tally data so that a MGXS library file can be generated. Below is the postprocessing script needed to generate the ``mgxs.h5`` library file given a statepoint file (e.g., ``statepoint.100.h5``) file and summary file (e.g., ``summary.h5``) that resulted from running our previous example:: +When selecting an energy decomposition, you can manually define group boundaries +or pick out a group structure already known to OpenMC (a list of which can be +found at :class:`openmc.mgxs.GROUP_STRUCTURES`). Once the above input deck has +been run, the resulting statepoint file will contain the needed flux and +reaction rate tally data so that a MGXS library file can be generated. Below is +the postprocessing script needed to generate the ``mgxs.h5`` library file given +a statepoint file (e.g., ``statepoint.100.h5``) file and summary file (e.g., +``summary.h5``) that resulted from running our previous example:: import openmc import openmc.mgxs as mgxs @@ -550,9 +573,15 @@ When selecting an energy decomposition, you can manually define group boundaries # Write the file to disk using the default filename of "mgxs.h5" mgxs_file.export_to_hdf5("mgxs.h5") -Notably, the postprocessing script needs to match the same :class:`openmc.mgxs.Library` settings that were used to generate the tallies, but otherwise is able to discern the rest of the simulation details from the statepoint and summary files. Once the postprocessing script is successfully run, the ``mgxs.h5`` file can be loaded by subsequent runs of OpenMC. +Notably, the postprocessing script needs to match the same +:class:`openmc.mgxs.Library` settings that were used to generate the tallies, +but otherwise is able to discern the rest of the simulation details from the +statepoint and summary files. Once the postprocessing script is successfully +run, the ``mgxs.h5`` file can be loaded by subsequent runs of OpenMC. -If you want to convert continuous energy material objects in an OpenMC input deck to multigroup ones from a ``mgxs.h5`` library, you can follow the below example. Here we begin with several continuous energy materials:: +If you want to convert continuous energy material objects in an OpenMC input +deck to multigroup ones from a ``mgxs.h5`` library, you can follow the below +example. Here we begin with several continuous energy materials:: fuel = openmc.Material(name='UO2 (2.4%)') fuel.set_density('g/cm3', 10.29769) @@ -571,7 +600,8 @@ If you want to convert continuous energy material objects in an OpenMC input dec materials = openmc.Materials([fuel, water]) -and make the necessary changes to turn them into multigroup library materials as:: +and make the necessary changes to turn them into multigroup library materials +as:: # Instantiate some Macroscopic Data fuel_data = openmc.Macroscopic('UO2 (2.4%)') diff --git a/include/openmc/weight_windows.h b/include/openmc/weight_windows.h index 18b2bb252a5..28e444c64c2 100644 --- a/include/openmc/weight_windows.h +++ b/include/openmc/weight_windows.h @@ -17,9 +17,7 @@ namespace openmc { -enum class WeightWindowUpdateMethod { - MAGIC, FW_CADIS -}; +enum class WeightWindowUpdateMethod { MAGIC, FW_CADIS }; //============================================================================== // Constants From eb5bd7f4bb823b14cc924904bb66ede45d3129fa Mon Sep 17 00:00:00 2001 From: John Tramm Date: Wed, 22 Jan 2025 21:06:00 +0000 Subject: [PATCH 19/27] ran clang-format v15.0.0 on weight_windows.h --- include/openmc/weight_windows.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/openmc/weight_windows.h b/include/openmc/weight_windows.h index 28e444c64c2..4845a2d82d2 100644 --- a/include/openmc/weight_windows.h +++ b/include/openmc/weight_windows.h @@ -219,11 +219,11 @@ class WeightWindowsGenerator { void create_tally(); // Data members - int32_t tally_idx_; //!< Index of the tally used to update the weight windows - int32_t ww_idx_; //!< Index of the weight windows object being generated + int32_t tally_idx_; //!< Index of the tally used to update the weight windows + int32_t ww_idx_; //!< Index of the weight windows object being generated WeightWindowUpdateMethod method_; //!< Method used to update weight window. - int32_t max_realizations_; //!< Maximum number of tally realizations - int32_t update_interval_; //!< Determines how often updates occur + int32_t max_realizations_; //!< Maximum number of tally realizations + int32_t update_interval_; //!< Determines how often updates occur bool on_the_fly_; //!< Whether or not to keep tally results between batches or //!< realizations From b7482af326c6dc652b5139ec98451dd4ee382c8c Mon Sep 17 00:00:00 2001 From: John Tramm Date: Fri, 24 Jan 2025 08:51:51 -0600 Subject: [PATCH 20/27] Apply suggestions from @yardasol code review Co-authored-by: Olek <45364492+yardasol@users.noreply.github.com> --- docs/source/methods/variance_reduction.rst | 8 ++++---- docs/source/usersguide/variance_reduction.rst | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/source/methods/variance_reduction.rst b/docs/source/methods/variance_reduction.rst index f80082280f9..dbec8c13ac5 100644 --- a/docs/source/methods/variance_reduction.rst +++ b/docs/source/methods/variance_reduction.rst @@ -10,7 +10,7 @@ Variance Reduction Introduction ------------ -Transport problems can sometimes infolve a significant degree of attenuation +Transport problems can sometimes involve a significant degree of attenuation between the neutron source and a detector (tally) region, which can result in a flux differential of ten orders of magnitude (or more) throughout the simulation domain. As Monte Carlo uncertainties tend to be inversely proportional to the @@ -23,7 +23,7 @@ Variance reduction techniques aim to either flatten the global uncertainty distribution, such that all regions of phase space have a fairly similar uncertainty, or to reduce the uncertainty in specific locations (such as a detector). There are two strategies available in OpenMC for variance reduction: -the Monte Carlo MAGIC method, and with FW-CADIS. Both strategies work by +the Monte Carlo MAGIC method, and the FW-CADIS method. Both strategies work by developing a weight window mesh, which can be utilized by subsequent Monte Carlo solves to split particles heading towards areas of lower flux densities while terminating particles in higher flux regions -- all while maintaining a fair @@ -34,7 +34,7 @@ MAGIC Method ------------ The MAGIC method is an iterative technique that uses spatial flux information -(:math:`\phi(r)`) obtained from a normal Monte Carlo solve to produce weight +:math:`\phi(r)` obtained from a normal Monte Carlo solve to produce weight windows (:math:`\w(r)`) that can be utilized by a subsequent iteration of Monte Carlo. While the first generation of weight windows produced may only help to reduce variance slightly, use of these weights to generate another set of weight @@ -77,7 +77,7 @@ and then trace it backwards (upscattering in energy), until we sample the point where it was born from. The FW-CADIS method produces weight windows for global variance reduction given -adjoint flux information throughout the entire domain. It is defined in Equation +adjoint flux information throughout the entire domain. The weight window lower bound is defined in Equation :eq:`fw_cadis`, and also involves a normalization step not shown here. .. math:: diff --git a/docs/source/usersguide/variance_reduction.rst b/docs/source/usersguide/variance_reduction.rst index c89f422ef13..c9ed10be427 100644 --- a/docs/source/usersguide/variance_reduction.rst +++ b/docs/source/usersguide/variance_reduction.rst @@ -16,7 +16,7 @@ steps required to both generate and then apply weight windows. Generating Weight Windows with MAGIC ------------------------------------ -As discussed in the methods section, MAGIC is an iterative method that uses flux +As discussed in the :ref:`methods section `, MAGIC is an iterative method that uses flux tally information from a Monte Carlo simulation to produce weight windows for a user defined mesh. While generating the weight windows, OpenMC is capable of applying the weight windows generated from a previous batch while processing the @@ -127,7 +127,7 @@ description of how to enable and setup random ray mode can be found in the Using Weight Windows -------------------- -To use a "weight_windows.h5" weight window file with OpenMC's Monte Carlo +To use a ``weight_windows.h5`` weight window file with OpenMC's Monte Carlo solver, the python input just needs to load the h5 file:: settings.weight_window_checkpoints = {'collision': True, 'surface': True} From 47f723527f6f7415072136a2dca1cfde628c1449 Mon Sep 17 00:00:00 2001 From: John Tramm Date: Fri, 24 Jan 2025 09:16:39 -0600 Subject: [PATCH 21/27] updates to docs incorporating @yardasol review comments` --- docs/source/methods/variance_reduction.rst | 17 ++++++++------- docs/source/usersguide/random_ray.rst | 12 ++++++++--- docs/source/usersguide/variance_reduction.rst | 21 ++++++++++--------- 3 files changed, 29 insertions(+), 21 deletions(-) diff --git a/docs/source/methods/variance_reduction.rst b/docs/source/methods/variance_reduction.rst index dbec8c13ac5..d714fae4ca8 100644 --- a/docs/source/methods/variance_reduction.rst +++ b/docs/source/methods/variance_reduction.rst @@ -35,13 +35,13 @@ MAGIC Method The MAGIC method is an iterative technique that uses spatial flux information :math:`\phi(r)` obtained from a normal Monte Carlo solve to produce weight -windows (:math:`\w(r)`) that can be utilized by a subsequent iteration of Monte +windows :math:`w(r)` that can be utilized by a subsequent iteration of Monte Carlo. While the first generation of weight windows produced may only help to reduce variance slightly, use of these weights to generate another set of weight windows results in a progressively improving iterative scheme. Equation :eq:`magic` defines how the lower bound of weight windows -(:math:`\w_\ell(r)`) are generated with MAGIC using forward flux information. +:math:`w_{\ell}(r)` are generated with MAGIC using forward flux information. Here, we can see that the flux at location :math:`r` is normalized by the maximum flux in any group at that location. We can also see that the weights are divided by a factor of two, which accounts for the typical :math:`5\times` @@ -50,14 +50,14 @@ factor separating the lower and upper weight window bounds in OpenMC. .. math:: :label: magic - w_\ell(r) = \frac{\phi(r)}{2\text{max}(\phi(r))} + w_{\ell}(r) = \frac{\phi(r)}{2\text{max}(\phi(r))} A major advantage of this technique is that it does not require any special transport machinery -- it simply uses multiple Monte Carlo simulations to iteratively improve a set of weight windows (which are typically defined on a mesh covering the simulation domain). The downside to this method is that as the flux differential increases between areas near and far from the source, it -requires more outer Monte Carlo iterations, each of which can be highly +requires more outer Monte Carlo iterations, each of which can be expensive in itself. Additionally, computation of weight windows based on regular (forward) neutron flux tally information does not produce the most numerically effective set of weight windows. Nonetheless, MAGIC remains a simple @@ -70,20 +70,21 @@ FW-CADIS As discussed in the previous section, computation of weight windows based on regular (forward) neutron flux tally information does not produce the most numerically efficient set of weight windows. It is highly preferable to generate -weight windows based on spatial adjoint flux (:math:`\phi^{\dag}(r)`) +weight windows based on spatial adjoint flux :math:`\phi^{\dag}(r)` information. The adjoint flux is essentially the "reverse" simulation problem, where we sample a random point and assume this is where a particle was absorbed, and then trace it backwards (upscattering in energy), until we sample the point where it was born from. The FW-CADIS method produces weight windows for global variance reduction given -adjoint flux information throughout the entire domain. The weight window lower bound is defined in Equation -:eq:`fw_cadis`, and also involves a normalization step not shown here. +adjoint flux information throughout the entire domain. The weight window lower +bound is defined in Equation :eq:`fw_cadis`, and also involves a normalization +step not shown here. .. math:: :label: fw_cadis - w_\ell(r) = \frac{1}{2\phi^{\dag}(r)} + w_{\ell}(r) = \frac{1}{2\phi^{\dag}(r)} While the algorithm itself is quite simple, it requires estimates of the global adjoint flux distribution, which is difficult to generate directly with Monte diff --git a/docs/source/usersguide/random_ray.rst b/docs/source/usersguide/random_ray.rst index 0448fa66907..f39709ee035 100644 --- a/docs/source/usersguide/random_ray.rst +++ b/docs/source/usersguide/random_ray.rst @@ -581,7 +581,8 @@ run, the ``mgxs.h5`` file can be loaded by subsequent runs of OpenMC. If you want to convert continuous energy material objects in an OpenMC input deck to multigroup ones from a ``mgxs.h5`` library, you can follow the below -example. Here we begin with several continuous energy materials:: +example. Here we begin with the original continuous energy materials we used to +generate our MGXS library:: fuel = openmc.Material(name='UO2 (2.4%)') fuel.set_density('g/cm3', 10.29769) @@ -600,8 +601,9 @@ example. Here we begin with several continuous energy materials:: materials = openmc.Materials([fuel, water]) -and make the necessary changes to turn them into multigroup library materials -as:: +Once the ``mgxs.h5`` library file has been generated, we can then manually make +the necessary edits to the material definitions so that they load from the +multigroup library instead of defining their isotopic contents, as:: # Instantiate some Macroscopic Data fuel_data = openmc.Macroscopic('UO2 (2.4%)') @@ -620,6 +622,10 @@ as:: materials = openmc.Materials([fuel, water]) materials.cross_sections = "mgxs.h5" +In the above example, our ``fuel`` and ``water`` materials will now load MGXS +data from the ``mgxs.h5`` file instead of loading continuous energy isotopic +cross section data. + -------------- Linear Sources -------------- diff --git a/docs/source/usersguide/variance_reduction.rst b/docs/source/usersguide/variance_reduction.rst index c9ed10be427..c2688abc2d9 100644 --- a/docs/source/usersguide/variance_reduction.rst +++ b/docs/source/usersguide/variance_reduction.rst @@ -16,12 +16,12 @@ steps required to both generate and then apply weight windows. Generating Weight Windows with MAGIC ------------------------------------ -As discussed in the :ref:`methods section `, MAGIC is an iterative method that uses flux -tally information from a Monte Carlo simulation to produce weight windows for a -user defined mesh. While generating the weight windows, OpenMC is capable of -applying the weight windows generated from a previous batch while processing the -next batch, allowing for progressive improvement in the weight window quality -across iterations. +As discussed in the :ref:`methods section `, MAGIC +is an iterative method that uses flux tally information from a Monte Carlo +simulation to produce weight windows for a user defined mesh. While generating +the weight windows, OpenMC is capable of applying the weight windows generated +from a previous batch while processing the next batch, allowing for progressive +improvement in the weight window quality across iterations. The most typical way of generating weight windows is to define a mesh and then add an :class:`openmc.WeightWindowGenerator` object to the @@ -135,10 +135,11 @@ solver, the python input just needs to load the h5 file:: settings.weight_windows = openmc.hdf5_to_wws() settings.weight_windows_on = True -Make sure that the :class:`openmc.WeightWindowGenerator` is not present in the -file when loading existing weight windows, so as to avoid added costs of -generating weight windows again and overwriting the original weight window file. -Weight window mesh information is embedded into the weight window file, so the +The :class:`openmc.WeightWindowGenerator` object is not needed to load an +existing ``weight_windows.h5`` weight window file. Inclusion of a +:class:`openmc.WeightWindowGenerator` object will cause OpenMC to generate new +weight windows and thus overwrite any existing ``weight_windows.h5`` file. Note +that window mesh information is embedded into the weight window file, so the mesh does not need to be redefined. Monte Carlo solves that load a weight window file as above will utilize the weight windows to reduce the variance of the simulation. \ No newline at end of file From c49c3e4b02c67ea454fa43b113c81186426f5996 Mon Sep 17 00:00:00 2001 From: John Tramm Date: Fri, 24 Jan 2025 09:29:39 -0600 Subject: [PATCH 22/27] docs typo fix --- docs/source/usersguide/random_ray.rst | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/docs/source/usersguide/random_ray.rst b/docs/source/usersguide/random_ray.rst index f39709ee035..b6852b7ca8f 100644 --- a/docs/source/usersguide/random_ray.rst +++ b/docs/source/usersguide/random_ray.rst @@ -776,9 +776,7 @@ estimator, the following code would be used: Adjoint Flux Mode ----------------- -The adjoint flux random ray solver mode can be enabled as: -entire -:: +The adjoint flux random ray solver mode can be enabled as:: settings.random_ray['adjoint'] = True From bddc770ca87c5a0467c7acdffc7a314b9350a403 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Fri, 24 Jan 2025 14:19:28 -0600 Subject: [PATCH 23/27] Edits in documentation --- docs/source/methods/variance_reduction.rst | 74 +++++------ docs/source/usersguide/variance_reduction.rst | 119 ++++++++++-------- 2 files changed, 107 insertions(+), 86 deletions(-) diff --git a/docs/source/methods/variance_reduction.rst b/docs/source/methods/variance_reduction.rst index d714fae4ca8..353ae5077ea 100644 --- a/docs/source/methods/variance_reduction.rst +++ b/docs/source/methods/variance_reduction.rst @@ -11,8 +11,8 @@ Introduction ------------ Transport problems can sometimes involve a significant degree of attenuation -between the neutron source and a detector (tally) region, which can result in a -flux differential of ten orders of magnitude (or more) throughout the simulation +between the source and a detector (tally) region, which can result in a flux +differential of ten orders of magnitude (or more) throughout the simulation domain. As Monte Carlo uncertainties tend to be inversely proportional to the physical flux density, it can be extremely difficult to accurately resolve tallies in locations that are optically far from the source. This issue is @@ -23,22 +23,24 @@ Variance reduction techniques aim to either flatten the global uncertainty distribution, such that all regions of phase space have a fairly similar uncertainty, or to reduce the uncertainty in specific locations (such as a detector). There are two strategies available in OpenMC for variance reduction: -the Monte Carlo MAGIC method, and the FW-CADIS method. Both strategies work by -developing a weight window mesh, which can be utilized by subsequent Monte Carlo +the Monte Carlo MAGIC method and the FW-CADIS method. Both strategies work by +developing a weight window mesh that can be utilized by subsequent Monte Carlo solves to split particles heading towards areas of lower flux densities while -terminating particles in higher flux regions -- all while maintaining a fair +terminating particles in higher flux regions---all while maintaining a fair game. ------------ MAGIC Method ------------ -The MAGIC method is an iterative technique that uses spatial flux information -:math:`\phi(r)` obtained from a normal Monte Carlo solve to produce weight -windows :math:`w(r)` that can be utilized by a subsequent iteration of Monte -Carlo. While the first generation of weight windows produced may only help to -reduce variance slightly, use of these weights to generate another set of weight -windows results in a progressively improving iterative scheme. +The Method of Automatic Generation of Importances by Calculation, or `MAGIC +method `_, is an iterative +technique that uses spatial flux information :math:`\phi(r)` obtained from a +normal Monte Carlo solve to produce weight windows :math:`w(r)` that can be +utilized by a subsequent iteration of Monte Carlo. While the first generation of +weight windows produced may only help to reduce variance slightly, use of these +weights to generate another set of weight windows results in a progressively +improving iterative scheme. Equation :eq:`magic` defines how the lower bound of weight windows :math:`w_{\ell}(r)` are generated with MAGIC using forward flux information. @@ -50,18 +52,18 @@ factor separating the lower and upper weight window bounds in OpenMC. .. math:: :label: magic - w_{\ell}(r) = \frac{\phi(r)}{2\text{max}(\phi(r))} + w_{\ell}(r) = \frac{\phi(r)}{2\,\text{max}(\phi(r))} A major advantage of this technique is that it does not require any special -transport machinery -- it simply uses multiple Monte Carlo simulations to +transport machinery; it simply uses multiple Monte Carlo simulations to iteratively improve a set of weight windows (which are typically defined on a mesh covering the simulation domain). The downside to this method is that as the flux differential increases between areas near and far from the source, it -requires more outer Monte Carlo iterations, each of which can be -expensive in itself. Additionally, computation of weight windows based on -regular (forward) neutron flux tally information does not produce the most -numerically effective set of weight windows. Nonetheless, MAGIC remains a simple -and effective technique for generating weight windows. +requires more outer Monte Carlo iterations, each of which can be expensive in +itself. Additionally, computation of weight windows based on regular (forward) +neutron flux tally information does not produce the most numerically effective +set of weight windows. Nonetheless, MAGIC remains a simple and effective +technique for generating weight windows. -------- FW-CADIS @@ -76,10 +78,11 @@ where we sample a random point and assume this is where a particle was absorbed, and then trace it backwards (upscattering in energy), until we sample the point where it was born from. -The FW-CADIS method produces weight windows for global variance reduction given -adjoint flux information throughout the entire domain. The weight window lower -bound is defined in Equation :eq:`fw_cadis`, and also involves a normalization -step not shown here. +The Forward-Weighted Consistent Adjoint Driven Importance Sampling method, or +`FW-CADIS method `_, produces weight windows +for global variance reduction given adjoint flux information throughout the +entire domain. The weight window lower bound is defined in Equation +:eq:`fw_cadis`, and also involves a normalization step not shown here. .. math:: :label: fw_cadis @@ -90,8 +93,8 @@ While the algorithm itself is quite simple, it requires estimates of the global adjoint flux distribution, which is difficult to generate directly with Monte Carlo transport. Thus, FW-CADIS typically uses an alternative solver (often deterministic) that can be more readily adapted for generating adjoint flux -information, and which is often much cheaper than Monte Carlo given that -maximal-fidelity is not needed for weight window generation. +information, and which is often much cheaper than Monte Carlo given that a rough +solution is often sufficient for weight window generation. The FW-CADIS implementation in OpenMC utilizes its own internal random ray multigroup transport solver to generate the adjoint source distribution. No @@ -113,18 +116,19 @@ burden on the user fairly small. The major advantage of this technique is that it typically produces much more numerically efficient weight windows as compared to those generated with MAGIC, -sometimes with an improvement on the variance vs. runtime figure of merit -(Equation :eq:`variance_fom`) of an order of magnitude. Another major advantage -is that the cost of the random ray solver is typically negligible compared to -the cost of the subsequent Monte Carlo solve itself, making it a very cheap -method to deploy. The downside to this method is that it introduces a second -transport method into the mix (random ray), such that there are more free input -parameters for the user to know about and adjust, potentially making the method -more complex to use. However, as many of the parameters have natural choices, -much of this parameterization can be handled automatically behind the scenes -without the need for the user to be aware of this. +sometimes with an order-of-magnitude improvement in the figure of merit +(Equation :eq:`variance_fom`), which accounts for both the variance and the +execution time. Another major advantage is that the cost of the random ray +solver is typically negligible compared to the cost of the subsequent Monte +Carlo solve itself, making it a very cheap method to deploy. The downside to +this method is that it introduces a second transport method into the mix (random +ray), such that there are more free input parameters for the user to know about +and adjust, potentially making the method more complex to use. However, as many +of the parameters have natural choices, much of this parameterization can be +handled automatically behind the scenes without the need for the user to be +aware of this. .. math:: :label: variance_fom - \text{FOM} = \frac{1}{\text{Time} \times \sigma^2} \ No newline at end of file + \text{FOM} = \frac{1}{\text{Time} \times \sigma^2} diff --git a/docs/source/usersguide/variance_reduction.rst b/docs/source/usersguide/variance_reduction.rst index c2688abc2d9..f86cdef3e6a 100644 --- a/docs/source/usersguide/variance_reduction.rst +++ b/docs/source/usersguide/variance_reduction.rst @@ -18,15 +18,15 @@ Generating Weight Windows with MAGIC As discussed in the :ref:`methods section `, MAGIC is an iterative method that uses flux tally information from a Monte Carlo -simulation to produce weight windows for a user defined mesh. While generating +simulation to produce weight windows for a user-defined mesh. While generating the weight windows, OpenMC is capable of applying the weight windows generated from a previous batch while processing the next batch, allowing for progressive improvement in the weight window quality across iterations. -The most typical way of generating weight windows is to define a mesh and then -add an :class:`openmc.WeightWindowGenerator` object to the -:attr:`openmc.Settings` object, as follows:: - +The typical way of generating weight windows is to define a mesh and then add an +:class:`openmc.WeightWindowGenerator` object to an :attr:`openmc.Settings` +instance, as follows:: + # Define weight window spatial mesh ww_mesh = openmc.RegularMesh() ww_mesh.dimension = (10, 10, 10) @@ -34,29 +34,36 @@ add an :class:`openmc.WeightWindowGenerator` object to the ww_mesh.upper_right = (100.0, 100.0, 100.0) # Create weight window object and adjust parameters - wwg = openmc.WeightWindowGenerator(method='magic', mesh=ww_mesh, max_realizations=settings.batches) + wwg = openmc.WeightWindowGenerator( + method='magic', + mesh=ww_mesh, + max_realizations=settings.batches + ) - # Add generator to openmc.settings object + # Add generator to Settings instance settings.weight_window_generators = wwg Notably, the :attr:`max_realizations` attribute is adjusted to the number of batches, such that all iterations are used to refine the weight window parameters. -With the :class:`openmc.WeightWindowGenerator` object added to the -:attr:`openmc.Settings` object, the rest of the problem can be defined as -normal. When running, note that the second iteration and beyond may be several -orders of magnitude slower than the first. As the weight windows are applied in -each iteration, particles may be agressively split, resulting in a large number -of secondary (split) particles being generated per initial source particle. This -is not necessarily a bad thing, as the split particles are much more efficient -at exploring low flux regions of phase space as compared to initial particles. +With the :class:`~openmc.WeightWindowGenerator` instance added to the +:attr:`~openmc.Settings`, the rest of the problem can be defined as normal. When +running, note that the second iteration and beyond may be several orders of +magnitude slower than the first. As the weight windows are applied in each +iteration, particles may be agressively split, resulting in a large number of +secondary (split) particles being generated per initial source particle. This is +not necessarily a bad thing, as the split particles are much more efficient at +exploring low flux regions of phase space as compared to initial particles. Thus, even though the reported "particles/second" metric of OpenMC may be much lower when generating (or just applying) weight windows as compared to analog -MC, the variance vs. runtime figure of merit is typically much more -advantageous. +MC, it typically leads to an overall improvement in the figure of merit +accounting for the reduction in the variance. -.. warning:: The number of particles per batch may need to be adjusted downward significantly to result in reasonable runtimes when weight windows are being generated or used. +.. warning:: + The number of particles per batch may need to be adjusted downward + significantly to result in reasonable runtimes when weight windows are being + generated or used. At the end of the simulation, a ``weight_windows.h5`` file will be saved to disk for later use. Loading it in another subsequent simulation will be discussed in @@ -69,53 +76,63 @@ Generating Weight Windows with FW-CADIS and Random Ray Weight window generation with FW-CADIS and random ray in OpenMC uses the same exact strategy as with MAGIC. An :class:`openmc.WeightWindowGenerator` object is added to the :attr:`openmc.Settings` object, and a ``weight_windows.h5`` will be -generated at the end of the simulation. - -The only difference is that the code must be run in random ray mode. A full -description of how to enable and setup random ray mode can be found in the -:ref:`Random Ray User Guide `. +generated at the end of the simulation. The only difference is that the code +must be run in random ray mode. A full description of how to enable and setup +random ray mode can be found in the :ref:`Random Ray User Guide `. .. note:: - It is a long term goal for OpenMC to be able to generate FW-CADIS weight windows with only a few tweaks to an existing continuous energy Monte Carlo input deck. However, at the present time, the workflow requires several steps to generate multigroup cross section data and to configure the random ray solver. A high level overview of the current workflow for generation of weight windows with FW-CADIS using random ray is given below. + It is a long term goal for OpenMC to be able to generate FW-CADIS weight + windows with only a few tweaks to an existing continuous energy Monte Carlo + input deck. However, at the present time, the workflow requires several + steps to generate multigroup cross section data and to configure the random + ray solver. A high level overview of the current workflow for generation of + weight windows with FW-CADIS using random ray is given below. 1. Produce approximate multigroup cross section data (stored in a ``mgxs.h5`` library). There is more information on generating multigroup cross sections via OpenMC in the :ref:`multigroup materials ` user guide, and a specific example of generating cross section data for use with random ray in - the :ref:`random ray MGXS guide `. + the :ref:`random ray MGXS guide `. -2. Make a copy of your continuous energy python input file. You'll edit the new +2. Make a copy of your continuous energy Python input file. You'll edit the new file to work in multigroup mode with random ray for producing weight windows. -3. Adjust the material definitions in your new multigroup python file to utilise +3. Adjust the material definitions in your new multigroup python file to utilize the multigroup cross sections instead of nuclide-wise continuous energy data. - There is a specific example of making this conversion in the random ray in - the :ref:`random ray MGXS guide `. + There is a specific example of making this conversion in the :ref:`random ray + MGXS guide `. 4. Configure OpenMC to run in random ray mode (by adding several standard random ray input flags and settings to the :attr:`openmc.Settings.random_ray` dictionary). More information can be found in the :ref:`Random Ray User - Guide `. + Guide `. -5. Add in an :class:`openmc.WeightWindowGenerator` in a similar manner as for - MAGIC generation with Monte Carlo, though with the :attr:`method` attribute - set to ``fw_cadis``:: +5. Add in a :class:`~openmc.WeightWindowGenerator` in a similar manner as for + MAGIC generation with Monte Carlo and set the :attr:`method` attribute set to + ``"fw_cadis"``:: - # Define weight window spatial mesh - ww_mesh = openmc.RegularMesh() - ww_mesh.dimension = (10, 10, 10) - ww_mesh.lower_left = (0.0, 0.0, 0.0) - ww_mesh.upper_right = (100.0, 100.0, 100.0) + # Define weight window spatial mesh + ww_mesh = openmc.RegularMesh() + ww_mesh.dimension = (10, 10, 10) + ww_mesh.lower_left = (0.0, 0.0, 0.0) + ww_mesh.upper_right = (100.0, 100.0, 100.0) - # Create weight window object and adjust parameters - wwg = openmc.WeightWindowGenerator(method='fw_cadis', mesh=ww_mesh, max_realizations=settings.batches) + # Create weight window object and adjust parameters + wwg = openmc.WeightWindowGenerator( + method='fw_cadis', + mesh=ww_mesh, + max_realizations=settings.batches + ) - # Add generator to openmc.settings object - settings.weight_window_generators = wwg + # Add generator to openmc.settings object + settings.weight_window_generators = wwg .. warning:: - If using FW-CADIS weight window generation, ensure that the selected weight window mesh does not subdivide any cells in the problem. In the future, this restriction is intended to be relaxed, but for now subdivision of cells by a mesh tally will result in undefined behavior. + If using FW-CADIS weight window generation, ensure that the selected weight + window mesh does not subdivide any cells in the problem. In the future, this + restriction is intended to be relaxed, but for now subdivision of cells by a + mesh tally will result in undefined behavior. 6. When running your multigroup random ray input deck, OpenMC will automatically run a forward solve followed by an adjoint solve, with a @@ -128,18 +145,18 @@ Using Weight Windows -------------------- To use a ``weight_windows.h5`` weight window file with OpenMC's Monte Carlo -solver, the python input just needs to load the h5 file:: +solver, the Python input just needs to load the h5 file:: settings.weight_window_checkpoints = {'collision': True, 'surface': True} settings.survival_biasing = False - settings.weight_windows = openmc.hdf5_to_wws() + settings.weight_windows = openmc.hdf5_to_wws('weight_windows.h5') settings.weight_windows_on = True -The :class:`openmc.WeightWindowGenerator` object is not needed to load an -existing ``weight_windows.h5`` weight window file. Inclusion of a -:class:`openmc.WeightWindowGenerator` object will cause OpenMC to generate new -weight windows and thus overwrite any existing ``weight_windows.h5`` file. Note -that window mesh information is embedded into the weight window file, so the +The :class:`~openmc.WeightWindowGenerator` instance is not needed to load an +existing ``weight_windows.h5`` file. Inclusion of a +:class:`~openmc.WeightWindowGenerator` instance will cause OpenMC to generate +*new* weight windows and thus overwrite any existing ``weight_windows.h5`` file. +Note that the mesh information is embedded into the weight window file, so the mesh does not need to be redefined. Monte Carlo solves that load a weight window file as above will utilize the weight windows to reduce the variance of the -simulation. \ No newline at end of file +simulation. From bb776a83d9a7ec07154ec97af7fcdd95b45d5033 Mon Sep 17 00:00:00 2001 From: Paul Romano Date: Fri, 24 Jan 2025 15:58:23 -0600 Subject: [PATCH 24/27] Small changes --- docs/source/usersguide/variance_reduction.rst | 2 +- tests/regression_tests/weightwindows_fw_cadis/test.py | 3 ++- tests/testing_harness.py | 9 ++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/source/usersguide/variance_reduction.rst b/docs/source/usersguide/variance_reduction.rst index f86cdef3e6a..1f3f8c3857b 100644 --- a/docs/source/usersguide/variance_reduction.rst +++ b/docs/source/usersguide/variance_reduction.rst @@ -97,7 +97,7 @@ random ray mode can be found in the :ref:`Random Ray User Guide `. 2. Make a copy of your continuous energy Python input file. You'll edit the new file to work in multigroup mode with random ray for producing weight windows. -3. Adjust the material definitions in your new multigroup python file to utilize +3. Adjust the material definitions in your new multigroup Python file to utilize the multigroup cross sections instead of nuclide-wise continuous energy data. There is a specific example of making this conversion in the :ref:`random ray MGXS guide `. diff --git a/tests/regression_tests/weightwindows_fw_cadis/test.py b/tests/regression_tests/weightwindows_fw_cadis/test.py index 520b8b42f7f..7a4718ed5b2 100644 --- a/tests/regression_tests/weightwindows_fw_cadis/test.py +++ b/tests/regression_tests/weightwindows_fw_cadis/test.py @@ -24,7 +24,8 @@ def test_random_ray_adjoint_fixed_source(): ww_mesh.lower_left = (0.0, 0.0, 0.0) ww_mesh.upper_right = (width, width, width) - wwg = openmc.WeightWindowGenerator(method="fw_cadis", mesh=ww_mesh, max_realizations=model.settings.batches) + wwg = openmc.WeightWindowGenerator( + method="fw_cadis", mesh=ww_mesh, max_realizations=model.settings.batches) model.settings.weight_window_generators = wwg model.settings.random_ray['volume_estimator'] = 'naive' diff --git a/tests/testing_harness.py b/tests/testing_harness.py index 15f5b795961..ddae89e02e9 100644 --- a/tests/testing_harness.py +++ b/tests/testing_harness.py @@ -459,16 +459,15 @@ def _get_results(self): formatted_upper_bound = [f'{x:.2e}' for x in flattened_upper_bound] # Concatenate the formatted arrays - concatenated_strings = [ - "Lower Bounds"] + formatted_lower_bound + ["Upper Bounds"] + formatted_upper_bound + concatenated_strings = ["Lower Bounds"] + formatted_lower_bound + \ + ["Upper Bounds"] + formatted_upper_bound # Join the concatenated strings into a single string with newline characters final_string = '\n'.join(concatenated_strings) # Prepend the mesh text description and return final string - final_string = str(ww.mesh) + final_string - return final_string - + return str(ww.mesh) + final_string + def _cleanup(self): super()._cleanup() f = 'weight_windows.h5' From 5e1fb89cd7006504f85251fb7acbb98ba518de5b Mon Sep 17 00:00:00 2001 From: John Tramm Date: Mon, 27 Jan 2025 08:14:27 -0600 Subject: [PATCH 25/27] commit comments on docs from @yardasol review` --- docs/source/usersguide/variance_reduction.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/source/usersguide/variance_reduction.rst b/docs/source/usersguide/variance_reduction.rst index 1f3f8c3857b..124f342034a 100644 --- a/docs/source/usersguide/variance_reduction.rst +++ b/docs/source/usersguide/variance_reduction.rst @@ -155,8 +155,8 @@ solver, the Python input just needs to load the h5 file:: The :class:`~openmc.WeightWindowGenerator` instance is not needed to load an existing ``weight_windows.h5`` file. Inclusion of a :class:`~openmc.WeightWindowGenerator` instance will cause OpenMC to generate -*new* weight windows and thus overwrite any existing ``weight_windows.h5`` file. -Note that the mesh information is embedded into the weight window file, so the +*new* weight windows and thus overwrite the existing ``weight_windows.h5`` file. +Weight window mesh information is embedded into the weight window file, so the mesh does not need to be redefined. Monte Carlo solves that load a weight window -file as above will utilize the weight windows to reduce the variance of the +file as above will utilize weight windows to reduce the variance of the simulation. From 39e35c9d94de69b93d60876b641a5e08d0f806c7 Mon Sep 17 00:00:00 2001 From: John Tramm Date: Mon, 27 Jan 2025 08:25:02 -0600 Subject: [PATCH 26/27] refactored update_magic to update_weights, and included passing in of method type to function --- include/openmc/weight_windows.h | 3 ++- src/weight_windows.cpp | 11 +++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/include/openmc/weight_windows.h b/include/openmc/weight_windows.h index 4845a2d82d2..d528a70ef8a 100644 --- a/include/openmc/weight_windows.h +++ b/include/openmc/weight_windows.h @@ -126,7 +126,8 @@ class WeightWindows { //! threshold will be ignored \param[in] ratio Ratio of upper to lower //! weight window bounds void update_magic(const Tally* tally, const std::string& value = "mean", - double threshold = 1.0, double ratio = 5.0); + double threshold = 1.0, double ratio = 5.0, + WeightWindowUpdateMethod method = WeightWindowUpdateMethod::MAGIC); // NOTE: This is unused for now but may be used in the future //! Write weight window settings to an HDF5 file diff --git a/src/weight_windows.cpp b/src/weight_windows.cpp index 10a7801a73f..419b7620372 100644 --- a/src/weight_windows.cpp +++ b/src/weight_windows.cpp @@ -483,8 +483,8 @@ void WeightWindows::set_bounds( upper_ww_ *= ratio; } -void WeightWindows::update_magic( - const Tally* tally, const std::string& value, double threshold, double ratio) +void WeightWindows::update_weights(const Tally* tally, const std::string& value, + double threshold, double ratio, WeightWindowUpdateMethod method) { /////////////////////////// // Setup and checks @@ -626,8 +626,7 @@ void WeightWindows::update_magic( int e_bins = new_bounds.shape()[0]; - if (settings::solver_type == SolverType::MONTE_CARLO || - !FlatSourceDomain::adjoint_) { + if (method == WeightWindowUpdateMethod::MAGIC) { // If we are computing weight windows with forward fluxes derived from a // Monte Carlo or forward random ray solve, we use the MAGIC algorithm. for (int e = 0; e < e_bins; e++) { @@ -900,7 +899,7 @@ void WeightWindowsGenerator::update() const tally->n_realizations_ % update_interval_ != 0) return; - wws->update_magic(tally, tally_value_, threshold_, ratio_); + wws->update_weights(tally, tally_value_, threshold_, ratio_, method_); // if we're not doing on the fly generation, reset the tally results once // we're done with the update @@ -984,7 +983,7 @@ extern "C" int openmc_weight_windows_update_magic(int32_t ww_idx, // get the WeightWindows object const auto& wws = variance_reduction::weight_windows.at(ww_idx); - wws->update_magic(tally, value, threshold, ratio); + wws->update_weights(tally, value, threshold, ratio); return 0; } From 866b3018f23479e74b5c7bc088ef94a755f8dd06 Mon Sep 17 00:00:00 2001 From: John Tramm Date: Mon, 27 Jan 2025 08:29:26 -0600 Subject: [PATCH 27/27] finished refactor --- include/openmc/weight_windows.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/openmc/weight_windows.h b/include/openmc/weight_windows.h index d528a70ef8a..2d4d556948b 100644 --- a/include/openmc/weight_windows.h +++ b/include/openmc/weight_windows.h @@ -125,7 +125,7 @@ class WeightWindows { //! \param[in] threshold Relative error threshold. Results over this //! threshold will be ignored \param[in] ratio Ratio of upper to lower //! weight window bounds - void update_magic(const Tally* tally, const std::string& value = "mean", + void update_weights(const Tally* tally, const std::string& value = "mean", double threshold = 1.0, double ratio = 5.0, WeightWindowUpdateMethod method = WeightWindowUpdateMethod::MAGIC);