Local adjoint source for Random Ray (#3717)

This commit is contained in:
Jack Fletcher 2026-04-28 17:10:03 -04:00 committed by GitHub
parent 1116c4bdc0
commit 368ea069ca
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
77 changed files with 2663 additions and 462 deletions

View file

@ -597,7 +597,7 @@ found in the :ref:`random ray user guide <random_ray>`.
*Default*: None
:source:
:ray_source:
Specifies the starting ray distribution, and follows the format for
:ref:`source_element`. It must be uniform in space and angle and cover the
full domain. It does not represent a physical neutron or photon source -- it
@ -605,6 +605,35 @@ found in the :ref:`random ray user guide <random_ray>`.
*Default*: None
:adjoint_source:
Specifies an adjoint fixed source for adjoint transport simulations, and
follows the format for :ref:`source_element`. The distributions which make
up the adjoint source are subject to the same restrictions as forward
fixed sources in Random Ray mode.
*Default*: None
:adjoint:
Specifies whether to perform adjoint transport. The default is 'False',
corresponding to forward transport.
*Default*: None
:volume_estimator:
Specifies choice of volume estimator for the random ray solver. Options
are 'naive', 'simulation_averaged', or 'hybrid'. The default is 'hybrid'.
*Default*: None
:volume_normalized_flux_tallies:
Specifies whether to normalize flux tallies by volume (bool). The
default is 'False'. When enabled, flux tallies will be reported in units
of cm/cm^3. When disabled, flux tallies will be reported in units of cm
(i.e., total distance traveled by neutrons in the spatial tally
region).
*Default*: None
:sample_method:
Specifies the method for sampling the starting ray distribution. This
element can be set to "prng" or "halton".
@ -1696,6 +1725,14 @@ mesh-based weight windows.
The ratio of the lower to upper weight window bounds.
*Default*: 5.0
For FW-CADIS:
:targets:
A sequence of IDs corresponding to the tallies which cover phase
space regions of interest for local variance reduction.
*Default*: None
---------------------------------------
``<weight_window_checkpoints>`` Element

View file

@ -1081,28 +1081,32 @@ lifetimes.
In OpenMC, the random ray adjoint solver is implemented simply by transposing
the scattering matrix, swapping :math:`\nu\Sigma_f` and :math:`\chi`, and then
running a normal transport solve. When no external fixed source is present, no
additional changes are needed in the transport process. However, if an external
fixed forward source is present in the simulation problem, then an additional
step is taken to compute the accompanying fixed adjoint source. In OpenMC, the
adjoint flux does *not* represent a response function for a particular detector
region. Rather, the adjoint flux is the global response, making it appropriate
for use with weight window generation schemes for global variance reduction.
Thus, if using a fixed source, the external source for the adjoint mode is
simply computed as being :math:`1 / \phi`, where :math:`\phi` is the forward
scalar flux that results from a normal forward solve (which OpenMC will run
first automatically when in adjoint mode). The adjoint external source will be
computed for each source region in the simulation mesh, independent of any
tallies. The adjoint external source is always flat, even when a linear
scattering and fission source shape is used. When in adjoint mode, all reported
results (e.g., tallies, eigenvalues, etc.) are derived from the adjoint flux,
even when the physical meaning is not necessarily obvious. These values are
still reported, though we emphasize that the primary use case for adjoint mode
is for producing adjoint flux tallies to support subsequent perturbation studies
and weight window generation.
running a normal transport solve. When no external fixed forward source is
present, or if an adjoint fixed source is specifically provided, no additional
changes are needed in the transport process. This adjoint source can
correspond, for example, to a detector response function in a particular
region. However, if an external fixed forward source is present in the
simulation problem without an adjoint fixed source, an additional step is taken
to compute the accompanying forward-weighted adjoint source. In this case, the
adjoint flux does *not* represent the importance of locations in phase space to
detector response; rather, the "response" in question is a uniform distribution
of Monte Carlo particle density, making the importance provided by the adjoint
flux appropriate for use with weight window generation schemes for global
variance reduction. Thus, if using a fixed source, the forward-weighted
external source for adjoint mode is simply computed as being :math:`1 / \phi`,
where :math:`\phi` is the forward scalar flux that results from a normal
forward solve (which OpenMC will run first automatically when in adjoint mode).
The adjoint external source will be computed for each source region in the
simulation mesh, independent of any tallies. The adjoint external source is
always flat, even when a linear scattering and fission source shape is used.
Note that the adjoint :math:`k_{eff}` is statistically the same as the forward
:math:`k_{eff}`, despite the flux distributions taking different shapes.
When in adjoint mode, all reported results (e.g., tallies, eigenvalues, etc.)
are derived from the adjoint flux, even when the physical meaning is not
necessarily obvious. These values are still reported, though we emphasize that
the primary use case for adjoint mode is for producing adjoint flux tallies to
support subsequent perturbation studies and weight window generation. Note
however that the adjoint :math:`k_{eff}` is statistically the same as the
forward :math:`k_{eff}`, despite the flux distributions taking different shapes.
---------------------------
Fundamental Sources of Bias

View file

@ -82,8 +82,8 @@ where it was born from.
The Forward-Weighted Consistent Adjoint Driven Importance Sampling method, or
`FW-CADIS method <https://doi.org/10.13182/NSE12-33>`_, produces weight windows
for global variance reduction given adjoint flux information throughout the
entire domain. The weight window lower bound is defined in Equation
for global or local 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::
@ -135,6 +135,18 @@ aware of this.
\text{FOM} = \frac{1}{\text{Time} \times \sigma^2}
Finally, one unique capability of the FW-CADIS weight window generator is to
produce weight windows for local variance reduction, given a list of the
responses of interest. This is controlled by optionally specifying target
tallies from the :class:`openmc.model.Model` to the
:class:`openmc.WeightWindowGenerator`, as illustrated in the
:ref:`user guide<variance_reduction>`. If target tallies for local variance
reduction are supplied, then the adjoint sources are only populated after the
initial forward simulation in the source regions associated with those tallies.
In other regions, the adjoint source term is instead set to zero. The Random
Ray solver then determines the adjoint flux map used to generate FW-CADIS
weight windows following the usual technique.
.. _methods_source_biasing:
--------------

View file

@ -944,6 +944,8 @@ as::
which will greatly improve the quality of the linear source term in 2D
simulations.
.. _usersguide_random_ray_run_modes:
---------------------------------
Fixed Source and Eigenvalue Modes
---------------------------------
@ -1073,22 +1075,47 @@ The adjoint flux random ray solver mode can be enabled as::
settings.random_ray['adjoint'] = True
When enabled, OpenMC will first run a forward transport simulation followed by
an adjoint transport simulation. The purpose of the forward solve is to compute
the adjoint external source when an external source is present in the
simulation. Simulation settings (e.g., number of rays, batches, etc.) will be
identical for both simulations. At the conclusion of the run, all results (e.g.,
tallies, plots, etc.) will be derived from the adjoint flux rather than the
forward flux but are not labeled any differently. The initial forward flux
solution will not be stored or available in the final statepoint file. Those
wishing to do analysis requiring both the forward and adjoint solutions will
need to run two separate simulations and load both statepoint files.
When enabled, OpenMC will first run a forward transport simulation if there are
no user-specified adjoint sources present, followed by an adjoint transport
simulation. Fixed adjoint sources can be specified on the
:attr:`openmc.Settings.random_ray` dictionary as follows::
# Geometry definition
...
detector_cell = openmc.Cell(fill=detector_mat, name='cell where detector will be')
...
# Define fixed adjoint neutron source
strengths = [1.0]
midpoints = [1.0e-4]
energy_distribution = openmc.stats.Discrete(x=midpoints, p=strengths)
adj_source = openmc.IndependentSource(
energy=energy_distribution,
constraints={'domains': [detector_cell]}
)
# Add to random_ray dict
settings.random_ray['adjoint_source'] = adj_source
The same constraints apply to the user-defined adjoint source as to the forward
source, described in the :ref:`Fixed Source and Eigenvalue section
<usersguide_random_ray_run_modes>`. If this source is not provided, a forward
solve must take place to compute the adjoint external source when a forward
external source is present in the problem. Simulation settings (e.g., number of
rays, batches, etc.) will be identical for both calculations. At the
conclusion of the run, all results (e.g., tallies, plots, etc.) will be
derived from the adjoint flux rather than the forward flux but are not labeled
any differently. The initial forward flux solution will not be stored or
available in the final statepoint file. Those wishing to do analysis requiring
both the forward and adjoint solutions will need to run two separate
simulations and load both statepoint files.
.. note::
When adjoint mode is selected, OpenMC will always perform a full forward
solve and then run a full adjoint solve immediately afterwards. Statepoint
and tally results will be derived from the adjoint flux, but will not be
labeled any differently.
Use of the automated
:ref:`FW-CADIS weight window generator<usersguide_fw_cadis>` is not
currently compatible with user-defined adjoint sources. Instead, the
initial forward calculation is used to assign "forward-weighted" adjoint
sources to the tally regions of interest.
---------------------------------------
Putting it All Together: Example Inputs

View file

@ -4,26 +4,27 @@
Variance Reduction
==================
Global variance reduction in OpenMC is accomplished by weight windowing
or source biasing techniques, the latter of which additionally provides a
local variance reduction capability. 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
Global and local variance reduction are possible in OpenMC through both weight
windowing and source biasing techniques. OpenMC is capable of generating weight
windows using either the MAGIC or FW-CADIS methods, the latter with an optional
capability for local variance reduction. Both techniques will produce a
``weight_windows.h5`` file that can be loaded and used later on. In
this section, we first break down the steps required to generate and apply
weight windows, then describe how source biasing may be applied.
.. _ww_generator:
------------------------------------
Generating Weight Windows with MAGIC
------------------------------------
-------------------------------------------
Generating Global Weight Windows with MAGIC
-------------------------------------------
As discussed in the :ref:`methods section <methods_variance_reduction>`, 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.
simulation to produce weight windows for a user-defined mesh with the objective
of global variance reduction. 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 typical way of generating weight windows is to define a mesh and then add an
:class:`openmc.WeightWindowGenerator` object to an :attr:`openmc.Settings`
@ -71,15 +72,20 @@ 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
------------------------------------------------------
.. _usersguide_fw_cadis:
----------------------------------------------------------------------
Generating Global or Local 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
exact strategy as with MAGIC. Using FW-CADIS, however, also enables
local variance reduction in fixed source problems through the :attr:`targets`
attribute, which is described later in this section. To enable FW-CADIS, 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 procedural 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 <random_ray>`.
.. note::
@ -90,7 +96,7 @@ random ray mode can be found in the :ref:`Random Ray User Guide <random_ray>`.
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. Begin by making a deepy copy of your continuous energy Python model and then
1. Begin by making a deep copy of your continuous energy Python model and then
convert the copy to be multigroup and use the random ray transport solver.
The conversion process can largely be automated as described in more detail
in the :ref:`random ray quick start guide <quick_start>`, summarized below::
@ -148,7 +154,53 @@ random ray mode can be found in the :ref:`Random Ray User Guide <random_ray>`.
assigning to ``model.settings.random_ray['source_region_meshes']``) and for
weight window generation.
3. When running your multigroup random ray input deck, OpenMC will automatically
3. (Optional) If local variance reduction is desired in a fixed-source problem,
populate the :attr:`targets` attribute with an :class:`openmc.Tallies`
instance or an iterable of tally IDs indicating the tallies of interest for
variance reduction::
# Build a new example and WWG for local variance reduction
from openmc.examples import random_ray_three_region_cube_with_detectors
new_model = random_ray_three_region_cube_with_detectors()
ww_mesh = openmc.RegularMesh()
n = 7
width = 35.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(
method="fw_cadis",
mesh=ww_mesh,
max_realizations=new_model.settings.batches
)
new_model.settings.weight_window_generators = wwg
new_model.settings.random_ray['volume_estimator'] = 'naive'
# Get the tallies of interest
target_tallies = openmc.Tallies()
for tally in list(new_model.tallies):
if tally.name in {"Detector 1 Tally", "Detector 2 Tally"}:
target_tallies.append(tally)
# Add to WeightWindowGenerator
wwg.targets = target_tallies
.. warning::
The tallies designated as FW-CADIS targets to the
:class:`~openmc.WeightWindowGenerator` must be present under the
:class:`~openmc.model.Model.tallies` attribute of the
:class:`~openmc.model.Model` as well in order to be recognized as valid
local variance reduction targets. This check is performed when the
:func:`openmc.model.Model.export_to_model_xml` or
:func:`openmc.model.Model.export_to_xml` functions are called, meaning
that the standalone :func:`openmc.Settings.export_to_xml` and
:func:`openmc.Tallies.export_to_xml` methods should not be used with
FW-CADIS local variance reduction.
4. 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

View file

@ -40,9 +40,10 @@ public:
void random_ray_tally();
virtual void accumulate_iteration_flux();
void output_to_vtk() const;
void convert_external_sources();
void convert_external_sources(bool use_adjoint_sources);
void count_external_source_regions();
void set_adjoint_sources();
void set_fw_adjoint_sources();
void set_local_adjoint_sources();
void flux_swap();
virtual double evaluate_flux_at_point(Position r, int64_t sr, int g) const;
double compute_fixed_source_normalization_factor() const;
@ -76,6 +77,7 @@ public:
// Static Data members
static bool volume_normalized_flux_tallies_;
static bool adjoint_; // If the user wants outputs based on the adjoint flux
static bool fw_cadis_local_;
static double
diagonal_stabilization_rho_; // Adjusts strength of diagonal stabilization
// for transport corrected MGXS data
@ -84,6 +86,8 @@ public:
static std::unordered_map<int, vector<std::pair<Source::DomainType, int>>>
mesh_domain_map_;
static std::vector<size_t> fw_cadis_local_targets_;
//----------------------------------------------------------------------------
// Static data members
static RandomRayVolumeEstimator volume_estimator_;

View file

@ -20,8 +20,9 @@ public:
//----------------------------------------------------------------------------
// Methods
void apply_fixed_sources_and_mesh_domains();
void prepare_fixed_sources_adjoint();
void prepare_adjoint_simulation();
void prepare_fw_fixed_sources_adjoint();
void prepare_local_fixed_sources_adjoint();
void prepare_adjoint_simulation(bool fw_adjoint);
void simulate();
void output_simulation_results() const;
void instability_check(
@ -34,15 +35,9 @@ public:
// Accessors
FlatSourceDomain* domain() const { return domain_.get(); }
//----------------------------------------------------------------------------
// Public data members
// Flag for adjoint simulation;
bool adjoint_needed_;
private:
//----------------------------------------------------------------------------
// Private data members
// Data members
// Contains all flat source region data
unique_ptr<FlatSourceDomain> domain_;
@ -57,9 +52,6 @@ private:
// Number of energy groups
int negroups_;
// Toggle for first simulation
bool is_first_simulation_;
}; // class RandomRaySimulation
//============================================================================
@ -67,7 +59,6 @@ private:
//============================================================================
void validate_random_ray_inputs();
void print_adjoint_header();
void openmc_finalize_random_ray();
} // namespace openmc

View file

@ -43,6 +43,7 @@ class Source;
namespace model {
extern vector<unique_ptr<Source>> external_sources;
extern vector<unique_ptr<Source>> adjoint_sources;
// Probability distribution for selecting external sources
extern DiscreteIndex external_sources_probability;

View file

@ -223,6 +223,9 @@ public:
double threshold_ {1.0}; //<! Relative error threshold for values used to
// update weight windows
double ratio_ {5.0}; //<! ratio of lower to upper weight window bounds
// Local FW-CADIS target tallies
std::vector<size_t> targets_;
};
//==============================================================================

View file

@ -1310,3 +1310,312 @@ def random_ray_three_region_cube() -> openmc.Model:
model.tallies = tallies
return model
def random_ray_three_region_cube_with_detectors() -> openmc.Model:
"""Create a three region cube model with two external tally regions.
This is an adaptation of the simple monoenergetic problem of a cube with
three concentric cubic regions. The innermost region is near void (with
Sigma_t around 10^-5) and contains an external isotropic source term, the
middle region is a mild scatterer (with Sigma_t around 10^-3), and the
outer region of the cube is a scatterer and absorber (with Sigma_t around
1).
Two cubic "detector" regions are found outside this geometry, one along the
y-axis near z=0, and the other in the upper right corner of the system.
The size of each detector is scaled to be equal to that of the source
region. The model returned by this function contains cell tallies on each
detector.
Returns
-------
model : openmc.Model
A three region cube model
"""
model = openmc.Model()
###########################################################################
# Helper function creates a 3 region cube with different fills in each region
def fill_cube(N, n_1, n_2, fill_1, fill_2, fill_3):
cube = [[[0 for _ in range(N)] for _ in range(N)] for _ in range(N)]
for i in range(N):
for j in range(N):
for k in range(N):
if i < n_1 and j >= (N-n_1) and k < n_1:
cube[i][j][k] = fill_1
elif i < n_2 and j >= (N-n_2) and k < n_2:
cube[i][j][k] = fill_2
else:
cube[i][j][k] = fill_3
return cube
###########################################################################
# Create multigroup data
# Instantiate the energy group data
ebins = [1e-5, 20.0e6]
groups = openmc.mgxs.EnergyGroups(group_edges=ebins)
cavity_sigma_a = 4.0e-5
cavity_sigma_s = 3.0e-3
cavity_mat_data = openmc.XSdata('cavity', groups)
cavity_mat_data.order = 0
cavity_mat_data.set_total([cavity_sigma_a + cavity_sigma_s])
cavity_mat_data.set_absorption([cavity_sigma_a])
cavity_mat_data.set_scatter_matrix(
np.rollaxis(np.array([[[cavity_sigma_s]]]), 0, 3))
absorber_sigma_a = 0.50
absorber_sigma_s = 0.50
absorber_mat_data = openmc.XSdata('absorber', groups)
absorber_mat_data.order = 0
absorber_mat_data.set_total([absorber_sigma_a + absorber_sigma_s])
absorber_mat_data.set_absorption([absorber_sigma_a])
absorber_mat_data.set_scatter_matrix(
np.rollaxis(np.array([[[absorber_sigma_s]]]), 0, 3))
multiplier = 0.01
source_sigma_a = cavity_sigma_a * multiplier
source_sigma_s = cavity_sigma_s * multiplier
source_mat_data = openmc.XSdata('source', groups)
source_mat_data.order = 0
source_mat_data.set_total([source_sigma_a + source_sigma_s])
source_mat_data.set_absorption([source_sigma_a])
source_mat_data.set_scatter_matrix(
np.rollaxis(np.array([[[source_sigma_s]]]), 0, 3))
mg_cross_sections_file = openmc.MGXSLibrary(groups)
mg_cross_sections_file.add_xsdatas(
[source_mat_data, cavity_mat_data, absorber_mat_data])
mg_cross_sections_file.export_to_hdf5()
###########################################################################
# Create materials for the problem
# Instantiate some Macroscopic Data
source_data = openmc.Macroscopic('source')
cavity_data = openmc.Macroscopic('cavity')
absorber_data = openmc.Macroscopic('absorber')
# Instantiate some Materials and register the appropriate Macroscopic objects
source_mat = openmc.Material(name='source')
source_mat.set_density('macro', 1.0)
source_mat.add_macroscopic(source_data)
cavity_mat = openmc.Material(name='cavity')
cavity_mat.set_density('macro', 1.0)
cavity_mat.add_macroscopic(cavity_data)
absorber_mat = openmc.Material(name='absorber')
absorber_mat.set_density('macro', 1.0)
absorber_mat.add_macroscopic(absorber_data)
# Instantiate a Materials collection
materials_file = openmc.Materials([source_mat, cavity_mat, absorber_mat])
materials_file.cross_sections = "mgxs.h5"
###########################################################################
# Define problem geometry
source_cell = openmc.Cell(fill=source_mat, name='infinite source region')
cavity_cell = openmc.Cell(fill=cavity_mat, name='cube cavity region')
absorber_cell = openmc.Cell(
fill=absorber_mat, name='absorber region')
source_universe = openmc.Universe(name='source universe')
source_universe.add_cells([source_cell])
cavity_universe = openmc.Universe()
cavity_universe.add_cells([cavity_cell])
absorber_universe = openmc.Universe()
absorber_universe.add_cells([absorber_cell])
absorber_width = 30.0
n_base = 6
# This variable can be increased above 1 to refine the FSR mesh resolution further
refinement_level = 2
n = n_base * refinement_level
pitch = absorber_width / n
pattern = fill_cube(n, 1*refinement_level, 5*refinement_level,
source_universe, cavity_universe, absorber_universe)
lattice = openmc.RectLattice()
lattice.lower_left = [0.0, 0.0, 0.0]
lattice.pitch = [pitch, pitch, pitch]
lattice.universes = pattern
lattice_cell = openmc.Cell(fill=lattice)
lattice_uni = openmc.Universe()
lattice_uni.add_cells([lattice_cell])
x_low = openmc.XPlane(x0=0.0, boundary_type='reflective')
x_high = openmc.XPlane(x0=absorber_width)
y_low = openmc.YPlane(y0=0.0, boundary_type='reflective')
y_high = openmc.YPlane(y0=absorber_width)
z_low = openmc.ZPlane(z0=0.0, boundary_type='reflective')
z_high = openmc.ZPlane(z0=absorber_width)
cube_domain = openmc.Cell(fill=lattice_uni, region=+x_low & -
x_high & +y_low & -y_high & +z_low & -z_high, name='full domain')
detect_width = absorber_width / n_base
outer_width = absorber_width + detect_width
x_outer = openmc.XPlane(x0=outer_width, boundary_type='vacuum')
y_outer = openmc.YPlane(y0=outer_width, boundary_type='vacuum')
z_outer = openmc.ZPlane(z0=outer_width, boundary_type='vacuum')
detector1_right = openmc.XPlane(x0=detect_width)
detector1_top = openmc.ZPlane(z0=detect_width)
detector1_region = (
+x_low & -detector1_right &
+y_high & -y_outer &
+z_low & -detector1_top
)
detector1 = openmc.Cell(
name='detector 1',
fill=absorber_mat,
region=detector1_region
)
detector2_region = (
+x_high & -x_outer &
+y_high & -y_outer &
+z_high & -z_outer
)
detector2 = openmc.Cell(
name='detector 2',
fill=absorber_mat,
region=detector2_region
)
external_x = (
+x_high & +y_low & +z_low & -x_outer &
((-y_outer & -z_high) | (-y_high & +z_high & -z_outer))
)
external_y = (
+y_high & -y_outer &
(
(+detector1_right & -x_high & +z_low & -z_outer) |
(-detector1_right & +x_low & +detector1_top & -z_outer) |
(+x_high & -x_outer & +z_low & -z_high)
)
)
external_z = (
+x_low & +y_low & +z_high & -z_outer &
((-y_outer & -x_high) | (-y_high & +x_high & -x_outer))
)
external_cell = openmc.Cell(fill=cavity_mat,
region=(external_x | external_y | external_z),
name='outside cube')
root = openmc.Universe(
name='root universe',
cells=[cube_domain, detector1, detector2, external_cell]
)
# Create a geometry with the two cells and export to XML
geometry = openmc.Geometry(root)
###########################################################################
# Define problem settings
# Instantiate a Settings object, set all runtime parameters, and export to XML
settings = openmc.Settings()
settings.energy_mode = "multi-group"
settings.inactive = 5
settings.batches = 10
settings.particles = 500
settings.run_mode = 'fixed source'
# Create an initial uniform spatial source for ray integration
lower_left_ray = [0.0, 0.0, 0.0]
upper_right_ray = [outer_width, outer_width, outer_width]
uniform_dist_ray = openmc.stats.Box(
lower_left_ray, upper_right_ray, only_fissionable=False)
rr_source = openmc.IndependentSource(space=uniform_dist_ray)
settings.random_ray['distance_active'] = 800.0
settings.random_ray['distance_inactive'] = 100.0
settings.random_ray['ray_source'] = rr_source
settings.random_ray['volume_normalized_flux_tallies'] = True
# Create a rectilinear source region mesh
sr_mesh = openmc.RegularMesh()
sr_mesh.dimension = (14, 14, 14)
sr_mesh.lower_left = (0.0, 0.0, 0.0)
sr_mesh.upper_right = (outer_width, outer_width, outer_width)
settings.random_ray['source_region_meshes'] = [(sr_mesh, [root])]
# Create the neutron source in the bottom right of the moderator
# Good - fast group appears largest (besides most thermal)
strengths = [1.0]
midpoints = [100.0]
energy_distribution = openmc.stats.Discrete(x=midpoints, p=strengths)
source = openmc.IndependentSource(energy=energy_distribution, constraints={
'domains': [source_universe]}, strength=3.14)
settings.source = [source]
###########################################################################
# Define tallies
estimator = 'tracklength'
detector1_filter = openmc.CellFilter(detector1)
detector1_tally = openmc.Tally(name="Detector 1 Tally")
detector1_tally.filters = [detector1_filter]
detector1_tally.scores = ['flux']
detector1_tally.estimator = estimator
detector2_filter = openmc.CellFilter(detector2)
detector2_tally = openmc.Tally(name="Detector 2 Tally")
detector2_tally.filters = [detector2_filter]
detector2_tally.scores = ['flux']
detector2_tally.estimator = estimator
absorber_filter = openmc.MaterialFilter(absorber_mat)
absorber_tally = openmc.Tally(name="Absorber Tally")
absorber_tally.filters = [absorber_filter]
absorber_tally.scores = ['flux']
absorber_tally.estimator = estimator
cavity_filter = openmc.MaterialFilter(cavity_mat)
cavity_tally = openmc.Tally(name="Cavity Tally")
cavity_tally.filters = [cavity_filter]
cavity_tally.scores = ['flux']
cavity_tally.estimator = estimator
source_filter = openmc.MaterialFilter(source_mat)
source_tally = openmc.Tally(name="Source Tally")
source_tally.filters = [source_filter]
source_tally.scores = ['flux']
source_tally.estimator = estimator
# Instantiate a Tallies collection and export to XML
tallies = openmc.Tallies([detector1_tally,
detector2_tally,
absorber_tally,
cavity_tally,
source_tally])
###########################################################################
# Assmble Model
model.geometry = geometry
model.materials = materials_file
model.settings = settings
model.tallies = tallies
return model

View file

@ -265,6 +265,46 @@ class Model:
denom_tally = openmc.Tally(name='IFP denominator')
denom_tally.scores = ['ifp-denominator']
self.tallies.append(denom_tally)
# TODO: This should also be incorporated into lower-level calls in
# settings.py, but it requires information about the tallies currently
# on the active Model
def _assign_fw_cadis_tally_IDs(self):
# Verify that all tallies assigned as targets on WeightWindowGenerators
# exist within model.tallies. If this is the case, convert the .targets
# attribute of each WeightWindowGenerator to a sequence of tally IDs.
if len(self.settings.weight_window_generators) == 0:
return
# List of valid tally IDs
reference_tally_ids = np.asarray([tal.id for tal in self.tallies])
for wwg in self.settings.weight_window_generators:
# Only proceeds if the "targets" attribute is an openmc.Tallies,
# which means it hasn't been checked against model.tallies.
if isinstance(wwg.targets, openmc.Tallies):
id_vec = []
for tal in wwg.targets:
# check against model tallies for equivalence
id_next = None
for reference_tal in self.tallies:
if tal == reference_tal:
id_next = reference_tal.id
break
if id_next == None:
raise RuntimeError(
f'Local FW-CADIS target tally {tal.id} not found on model.tallies!')
else:
id_vec.append(id_next)
wwg.targets = id_vec
elif isinstance(wwg.targets, np.ndarray):
invalid = wwg.targets[~np.isin(wwg.targets, reference_tally_ids)]
if len(invalid) > 0:
raise RuntimeError(
f'Local FW-CADIS target tally IDs {invalid} not found on model.tallies!')
@classmethod
def from_xml(
@ -576,6 +616,7 @@ class Model:
if not d.is_dir():
d.mkdir(parents=True, exist_ok=True)
self._assign_fw_cadis_tally_IDs()
self.settings.export_to_xml(d)
self.geometry.export_to_xml(d, remove_surfs=remove_surfs)
@ -634,6 +675,9 @@ class Model:
"set the Geometry.merge_surfaces attribute instead.")
self.geometry.merge_surfaces = True
# Link FW-CADIS WeightWindowGenerator target tallies, if present
self._assign_fw_cadis_tally_IDs()
# provide a memo to track which meshes have been written
mesh_memo = set()
settings_element = self.settings.to_xml_element(mesh_memo)

View file

@ -236,6 +236,9 @@ class Settings:
stabilization, which may be desirable as stronger diagonal stabilization
also tends to dampen the convergence rate of the solver, thus requiring
more iterations to converge.
:adjoint_source:
Source object used to define localized adjoint source/detector response
function.
.. versionadded:: 0.15.0
resonance_scattering : dict
@ -1421,6 +1424,14 @@ class Settings:
cv.check_type('diagonal stabilization rho', value, Real)
cv.check_greater_than('diagonal stabilization rho',
value, 0.0, True)
elif key == 'adjoint_source':
if not isinstance(value, MutableSequence):
value = [value]
for source in value:
if not isinstance(source, SourceBase):
raise ValueError(
f'Invalid adjoint source type: {type(source)}. '
'Expected openmc.SourceBase.')
else:
raise ValueError(f'Unable to set random ray to "{key}" which is '
'unsupported by OpenMC')
@ -1973,11 +1984,12 @@ class Settings:
element = ET.SubElement(root, "random_ray")
for key, value in self._random_ray.items():
if key == 'ray_source' and isinstance(value, SourceBase):
subelement = ET.SubElement(element, 'ray_source')
source_element = value.to_xml_element()
if source_element.find('bias') is not None:
raise RuntimeError(
"Ray source distributions should not be biased.")
element.append(source_element)
subelement.append(source_element)
elif key == 'source_region_meshes':
subelement = ET.SubElement(element, 'source_region_meshes')
@ -1995,8 +2007,20 @@ class Settings:
path = f"./mesh[@id='{mesh.id}']"
if root.find(path) is None:
root.append(mesh.to_xml_element())
if mesh_memo is not None:
if mesh_memo is not None:
mesh_memo.add(mesh.id)
elif key == 'adjoint_source':
subelement = ET.SubElement(element, 'adjoint_source')
# Check that all entries are valid SourceBase instances, in case
# the random_ray setter was not used to populate dict entries.
if not isinstance(value, MutableSequence):
value = [value]
for source in value:
if not isinstance(source, SourceBase):
raise ValueError(
f'Invalid adjoint source type: {type(source)}. '
'Expected openmc.SourceBase.')
subelement.append(source.to_xml_element())
elif isinstance(value, bool):
subelement = ET.SubElement(element, key)
subelement.text = str(value).lower()
@ -2443,8 +2467,9 @@ class Settings:
for child in elem:
if child.tag in ('distance_inactive', 'distance_active', 'diagonal_stabilization_rho'):
self.random_ray[child.tag] = float(child.text)
elif child.tag == 'source':
source = SourceBase.from_xml_element(child)
elif child.tag == 'ray_source':
source_element = child.find('source')
source = SourceBase.from_xml_element(source_element)
if child.find('bias') is not None:
raise RuntimeError(
"Ray source distributions should not be biased.")
@ -2461,6 +2486,12 @@ class Settings:
self.random_ray['adjoint'] = (
child.text in ('true', '1')
)
elif child.tag == 'adjoint_source':
self.random_ray['adjoint_source'] = []
for subelem in child.findall('source'):
src = SourceBase.from_xml_element(subelem)
# add newly constructed source object to the list
self.random_ray['adjoint_source'].append(src)
elif child.tag == 'sample_method':
self.random_ray['sample_method'] = child.text
elif child.tag == 'source_region_meshes':

View file

@ -16,6 +16,23 @@ from scipy.stats import chi2, norm
import openmc
import openmc.checkvalue as cv
from openmc.filter import (
Filter,
DistribcellFilter,
EnergyFunctionFilter,
DelayedGroupFilter,
FilterMeta,
MeshFilter,
MeshBornFilter,
)
from openmc.arithmetic import (
CrossFilter,
AggregateFilter,
CrossScore,
AggregateScore,
CrossNuclide,
AggregateNuclide,
)
from ._sparse_compat import lil_array
from ._xml import clean_indentation, get_elem_list, get_text
from .mixin import IDManagerMixin
@ -31,9 +48,9 @@ _PRODUCT_TYPES = ['tensor', 'entrywise']
# The following indicate acceptable types when setting Tally.scores,
# Tally.nuclides, and Tally.filters
_SCORE_CLASSES = (str, openmc.CrossScore, openmc.AggregateScore)
_NUCLIDE_CLASSES = (str, openmc.CrossNuclide, openmc.AggregateNuclide)
_FILTER_CLASSES = (openmc.Filter, openmc.CrossFilter, openmc.AggregateFilter)
_SCORE_CLASSES = (str, CrossScore, AggregateScore)
_NUCLIDE_CLASSES = (str, CrossNuclide, AggregateNuclide)
_FILTER_CLASSES = (Filter, CrossFilter, AggregateFilter)
# Valid types of estimators
ESTIMATOR_TYPES = {'tracklength', 'collision', 'analog'}
@ -421,7 +438,7 @@ class Tally(IDManagerMixin):
self._num_realizations = int(group['n_realizations'][()])
for filt in self.filters:
if isinstance(filt, openmc.DistribcellFilter):
if isinstance(filt, DistribcellFilter):
filter_group = f[f'tallies/filters/filter {filt.id}']
filt._num_bins = int(filter_group['n_bins'][()])
@ -1089,8 +1106,8 @@ class Tally(IDManagerMixin):
return False
# Return False if only one tally has a delayed group filter
tally1_dg = self.contains_filter(openmc.DelayedGroupFilter)
tally2_dg = other.contains_filter(openmc.DelayedGroupFilter)
tally1_dg = self.contains_filter(DelayedGroupFilter)
tally2_dg = other.contains_filter(DelayedGroupFilter)
if tally1_dg != tally2_dg:
return False
@ -1602,7 +1619,7 @@ class Tally(IDManagerMixin):
# Also check to see if the desired filter is wrapped up in an
# aggregate
elif isinstance(test_filter, openmc.AggregateFilter):
elif isinstance(test_filter, AggregateFilter):
if isinstance(test_filter.aggregate_filter, filter_type):
return test_filter
@ -1704,7 +1721,7 @@ class Tally(IDManagerMixin):
"""
cv.check_type('filters', filters, Iterable, openmc.FilterMeta)
cv.check_type('filters', filters, Iterable, FilterMeta)
cv.check_type('filter_bins', filter_bins, Iterable, tuple)
# If user did not specify any specific Filters, use them all
@ -1787,7 +1804,7 @@ class Tally(IDManagerMixin):
"""
for score in scores:
if not isinstance(score, (str, openmc.CrossScore)):
if not isinstance(score, (str, CrossScore)):
msg = f'Unable to get score indices for score "{score}" in ' \
f'ID="{self.id}" since it is not a string or CrossScore ' \
'Tally'
@ -1984,9 +2001,9 @@ class Tally(IDManagerMixin):
column_name = 'score'
for score in self.scores:
if isinstance(score, (str, openmc.CrossScore)):
if isinstance(score, (str, CrossScore)):
scores.append(str(score))
elif isinstance(score, openmc.AggregateScore):
elif isinstance(score, AggregateScore):
scores.append(score.name)
column_name = f'{score.aggregate_op}(score)'
@ -2086,7 +2103,7 @@ class Tally(IDManagerMixin):
for i, f in enumerate(self.filters):
if expand_dims:
# Mesh filter indices are backwards so we need to flip them
if type(f) in {openmc.MeshFilter, openmc.MeshBornFilter}:
if type(f) in {MeshFilter, MeshBornFilter}:
fshape = f.shape[::-1]
new_shape += fshape
idx0, idx1 = i, i + len(fshape) - 1
@ -2273,7 +2290,7 @@ class Tally(IDManagerMixin):
else:
all_filters = [self_copy.filters, other_copy.filters]
for self_filter, other_filter in product(*all_filters):
new_filter = openmc.CrossFilter(self_filter, other_filter,
new_filter = CrossFilter(self_filter, other_filter,
binary_op)
new_tally.filters.append(new_filter)
@ -2284,7 +2301,7 @@ class Tally(IDManagerMixin):
else:
all_nuclides = [self_copy.nuclides, other_copy.nuclides]
for self_nuclide, other_nuclide in product(*all_nuclides):
new_nuclide = openmc.CrossNuclide(self_nuclide, other_nuclide,
new_nuclide = CrossNuclide(self_nuclide, other_nuclide,
binary_op)
new_tally.nuclides.append(new_nuclide)
@ -2295,9 +2312,9 @@ class Tally(IDManagerMixin):
if score1 == score2:
return score1
else:
return openmc.CrossScore(score1, score2, binary_op)
return CrossScore(score1, score2, binary_op)
else:
return openmc.CrossScore(score1, score2, binary_op)
return CrossScore(score1, score2, binary_op)
# Add scores to the new tally
if score_product == 'entrywise':
@ -2506,16 +2523,16 @@ class Tally(IDManagerMixin):
# Construct lists of tuples for the bins in each of the two filters
filters = [type(filter1), type(filter2)]
if isinstance(filter1, openmc.DistribcellFilter):
if isinstance(filter1, DistribcellFilter):
filter1_bins = [b for b in range(filter1.num_bins)]
elif isinstance(filter1, openmc.EnergyFunctionFilter):
elif isinstance(filter1, EnergyFunctionFilter):
filter1_bins = [None]
else:
filter1_bins = filter1.bins
if isinstance(filter2, openmc.DistribcellFilter):
if isinstance(filter2, DistribcellFilter):
filter2_bins = [b for b in range(filter2.num_bins)]
elif isinstance(filter2, openmc.EnergyFunctionFilter):
elif isinstance(filter2, EnergyFunctionFilter):
filter2_bins = [None]
else:
filter2_bins = filter2.bins
@ -2648,11 +2665,11 @@ class Tally(IDManagerMixin):
raise ValueError(msg)
# Check that the scores are valid
if not isinstance(score1, (str, openmc.CrossScore)):
if not isinstance(score1, (str, CrossScore)):
msg = 'Unable to swap score1 "{}" in Tally ID="{}" since it is ' \
'not a string or CrossScore'.format(score1, self.id)
raise ValueError(msg)
elif not isinstance(score2, (str, openmc.CrossScore)):
elif not isinstance(score2, (str, CrossScore)):
msg = 'Unable to swap score2 "{}" in Tally ID="{}" since it is ' \
'not a string or CrossScore'.format(score2, self.id)
raise ValueError(msg)
@ -3296,7 +3313,7 @@ class Tally(IDManagerMixin):
new_filter.bins = [f.bins[i] for i in bin_indices]
# Set number of bins manually for mesh/distribcell filters
if filter_type is openmc.DistribcellFilter:
if filter_type is DistribcellFilter:
new_filter._num_bins = f._num_bins
# Replace existing filter with new one
@ -3362,16 +3379,16 @@ class Tally(IDManagerMixin):
std_dev = self.get_reshaped_data(value='std_dev')
# Sum across any filter bins specified by the user
if isinstance(filter_type, openmc.FilterMeta):
if isinstance(filter_type, FilterMeta):
find_filter = self.find_filter(filter_type)
# If user did not specify filter bins, sum across all bins
if len(filter_bins) == 0:
bin_indices = np.arange(find_filter.num_bins)
if isinstance(find_filter, openmc.DistribcellFilter):
if isinstance(find_filter, DistribcellFilter):
filter_bins = np.arange(find_filter.num_bins)
elif isinstance(find_filter, openmc.EnergyFunctionFilter):
elif isinstance(find_filter, EnergyFunctionFilter):
filter_bins = [None]
else:
filter_bins = find_filter.bins
@ -3400,7 +3417,7 @@ class Tally(IDManagerMixin):
# Add AggregateFilter to the tally sum
if not remove_filter:
filter_sum = openmc.AggregateFilter(self_filter,
filter_sum = AggregateFilter(self_filter,
[tuple(filter_bins)], 'sum')
tally_sum.filters.append(filter_sum)
@ -3423,7 +3440,7 @@ class Tally(IDManagerMixin):
std_dev = np.sqrt(std_dev)
# Add AggregateNuclide to the tally sum
nuclide_sum = openmc.AggregateNuclide(nuclides, 'sum')
nuclide_sum = AggregateNuclide(nuclides, 'sum')
tally_sum.nuclides.append(nuclide_sum)
# Add a copy of this tally's nuclides to the tally sum
@ -3441,7 +3458,7 @@ class Tally(IDManagerMixin):
std_dev = np.sqrt(std_dev)
# Add AggregateScore to the tally sum
score_sum = openmc.AggregateScore(scores, 'sum')
score_sum = AggregateScore(scores, 'sum')
tally_sum.scores.append(score_sum)
# Add a copy of this tally's scores to the tally sum
@ -3514,16 +3531,16 @@ class Tally(IDManagerMixin):
std_dev = self.get_reshaped_data(value='std_dev')
# Average across any filter bins specified by the user
if isinstance(filter_type, openmc.FilterMeta):
if isinstance(filter_type, FilterMeta):
find_filter = self.find_filter(filter_type)
# If user did not specify filter bins, average across all bins
if len(filter_bins) == 0:
bin_indices = np.arange(find_filter.num_bins)
if isinstance(find_filter, openmc.DistribcellFilter):
if isinstance(find_filter, DistribcellFilter):
filter_bins = np.arange(find_filter.num_bins)
elif isinstance(find_filter, openmc.EnergyFunctionFilter):
elif isinstance(find_filter, EnergyFunctionFilter):
filter_bins = [None]
else:
filter_bins = find_filter.bins
@ -3553,7 +3570,7 @@ class Tally(IDManagerMixin):
# Add AggregateFilter to the tally avg
if not remove_filter:
filter_sum = openmc.AggregateFilter(self_filter,
filter_sum = AggregateFilter(self_filter,
[tuple(filter_bins)], 'avg')
tally_avg.filters.append(filter_sum)
@ -3577,7 +3594,7 @@ class Tally(IDManagerMixin):
std_dev = np.sqrt(std_dev)
# Add AggregateNuclide to the tally avg
nuclide_avg = openmc.AggregateNuclide(nuclides, 'avg')
nuclide_avg = AggregateNuclide(nuclides, 'avg')
tally_avg.nuclides.append(nuclide_avg)
# Add a copy of this tally's nuclides to the tally avg
@ -3596,7 +3613,7 @@ class Tally(IDManagerMixin):
std_dev = np.sqrt(std_dev)
# Add AggregateScore to the tally avg
score_sum = openmc.AggregateScore(scores, 'avg')
score_sum = AggregateScore(scores, 'avg')
tally_avg.scores.append(score_sum)
# Add a copy of this tally's scores to the tally avg
@ -3786,7 +3803,7 @@ class Tallies(cv.CheckedList):
already_written = memo if memo else set()
for tally in self:
for f in tally.filters:
if isinstance(f, openmc.MeshFilter):
if isinstance(f, MeshFilter):
if f.mesh.id in already_written:
continue
if len(f.mesh.name) > 0:
@ -3881,7 +3898,7 @@ class Tallies(cv.CheckedList):
# Read filter elements
filters = {}
for e in elem.findall('filter'):
filter = openmc.Filter.from_xml_element(e, meshes=meshes)
filter = Filter.from_xml_element(e, meshes=meshes)
filters[filter.id] = filter
# Read derivative elements

View file

@ -11,6 +11,7 @@ import h5py
import openmc
from openmc.mesh import MeshBase, RectilinearMesh, CylindricalMesh, SphericalMesh, UnstructuredMesh
from openmc.tallies import Tallies
import openmc.checkvalue as cv
from openmc.checkvalue import PathLike
from ._xml import get_elem_list, get_text, clean_indentation
@ -499,6 +500,8 @@ class WeightWindowGenerator:
Particle type the weight windows apply to
method : {'magic', 'fw_cadis'}
The weight window generation methodology applied during an update.
targets : :class:`openmc.Tallies` or iterable of int
Target tallies for local variance reduction via FW-CADIS.
max_realizations : int
The upper limit for number of tally realizations when generating weight
windows.
@ -518,6 +521,8 @@ class WeightWindowGenerator:
Particle type the weight windows apply to
method : {'magic', 'fw_cadis'}
The weight window generation methodology applied during an update.
targets : :class:`openmc.Tallies` or numpy.ndarray
Target tallies for local variance reduction via FW-CADIS.
max_realizations : int
The upper limit for number of tally realizations when generating weight
windows.
@ -529,7 +534,7 @@ class WeightWindowGenerator:
Whether or not to apply weight windows on the fly.
"""
_MAGIC_PARAMS = {'value': str, 'threshold': float, 'ratio': float}
_WWG_PARAMS = {'value': str, 'threshold': float, 'ratio': float}
def __init__(
self,
@ -537,6 +542,7 @@ class WeightWindowGenerator:
energy_bounds: Sequence[float] | None = None,
particle_type: str | int | openmc.ParticleType = 'neutron',
method: str = 'magic',
targets: openmc.Tallies | Iterable[int] | None = None,
max_realizations: int = 1,
update_interval: int = 1,
on_the_fly: bool = True
@ -549,6 +555,7 @@ class WeightWindowGenerator:
self.energy_bounds = energy_bounds
self.particle_type = particle_type
self.method = method
self.targets = targets
self.max_realizations = max_realizations
self.update_interval = update_interval
self.on_the_fly = on_the_fly
@ -611,6 +618,22 @@ class WeightWindowGenerator:
self._check_update_parameters()
except (TypeError, KeyError):
warnings.warn(f'Update parameters are invalid for the "{m}" method.')
@property
def targets(self) -> openmc.Tallies:
return self._targets
@targets.setter
def targets(self, t):
if t is None:
self._targets = t
else:
cv.check_type('Local FW-CADIS target tallies', t, Iterable)
cv.check_greater_than('Local FW-CADIS target tallies', len(t), 0)
if not isinstance(t, openmc.Tallies):
cv.check_iterable_type('Local FW-CADIS target tallies', t, int)
t = np.asarray(list(t), dtype=int)
self._targets = t
@property
def max_realizations(self) -> int:
@ -638,13 +661,13 @@ class WeightWindowGenerator:
def _check_update_parameters(self, params: dict):
if self.method == 'magic' or self.method == 'fw_cadis':
check_params = self._MAGIC_PARAMS
check_params = self._WWG_PARAMS
for key, val in params.items():
if key not in check_params:
raise ValueError(f'Invalid param "{key}" for {self.method} '
'weight window generation')
cv.check_type(f'weight window generation param: "{key}"', val, self._MAGIC_PARAMS[key])
cv.check_type(f'weight window generation param: "{key}"', val, self._WWG_PARAMS[key])
@update_parameters.setter
def update_parameters(self, params: dict):
@ -681,7 +704,7 @@ class WeightWindowGenerator:
The update parameters as-read from the XML node (keys: str, values: str)
"""
if method == 'magic' or method == 'fw_cadis':
check_params = cls._MAGIC_PARAMS
check_params = cls._WWG_PARAMS
for param, param_type in check_params.items():
if param in update_parameters:
@ -707,6 +730,20 @@ class WeightWindowGenerator:
otf_elem.text = str(self.on_the_fly).lower()
method_elem = ET.SubElement(element, 'method')
method_elem.text = self.method
if self.targets is not None:
if self.method != 'fw_cadis':
raise ValueError(
"FW-CADIS update method is required in order to use " \
"target tallies for WeightWindowGenerator.")
elif isinstance(self.targets, openmc.Tallies):
raise RuntimeError(
"FW-CADIS target tallies must be checked to ensure they are " \
"present on model.tallies. Use model.export_to_xml() or " \
"model.export_to_model_xml() to link FW-CADIS target tallies.")
else:
targets_elem = ET.SubElement(element, 'targets')
targets_elem.text = ' '.join(str(tally_id) for tally_id in self.targets)
if self.update_parameters is not None:
self._update_parameters_subelement(element)
@ -733,8 +770,8 @@ class WeightWindowGenerator:
mesh_id = int(get_text(elem, 'mesh'))
mesh = meshes[mesh_id]
energy_bounds = get_elem_list(elem, "energy_bounds, float")
energy_bounds = get_elem_list(elem, "energy_bounds", float)
particle_type = get_text(elem, 'particle_type')
wwg = cls(mesh, energy_bounds, particle_type)
@ -743,6 +780,14 @@ class WeightWindowGenerator:
wwg.update_interval = int(get_text(elem, 'update_interval'))
wwg.on_the_fly = bool(get_text(elem, 'on_the_fly'))
wwg.method = get_text(elem, 'method')
targets_elem = elem.find('targets')
if targets_elem is not None:
if wwg.method != 'fw_cadis':
raise ValueError(
"FW-CADIS update method is required in order to use " \
"target tallies for WeightWindowGenerator.")
else:
wwg.targets = get_elem_list(elem, "targets")
if elem.find('update_parameters') is not None:
update_parameters = {}

View file

@ -31,9 +31,11 @@ RandomRayVolumeEstimator FlatSourceDomain::volume_estimator_ {
RandomRayVolumeEstimator::HYBRID};
bool FlatSourceDomain::volume_normalized_flux_tallies_ {false};
bool FlatSourceDomain::adjoint_ {false};
bool FlatSourceDomain::fw_cadis_local_ {false};
double FlatSourceDomain::diagonal_stabilization_rho_ {1.0};
std::unordered_map<int, vector<std::pair<Source::DomainType, int>>>
FlatSourceDomain::mesh_domain_map_;
std::vector<size_t> FlatSourceDomain::fw_cadis_local_targets_;
FlatSourceDomain::FlatSourceDomain() : negroups_(data::mg.num_energy_groups_)
{
@ -1000,7 +1002,9 @@ void FlatSourceDomain::output_to_vtk() const
void FlatSourceDomain::apply_external_source_to_source_region(
int src_idx, SourceRegionHandle& srh)
{
auto s = model::external_sources[src_idx].get();
auto s = (adjoint_ && !model::adjoint_sources.empty())
? model::adjoint_sources[src_idx].get()
: model::external_sources[src_idx].get();
auto is = dynamic_cast<IndependentSource*>(s);
auto discrete = dynamic_cast<Discrete*>(is->energy());
double strength_factor = is->strength();
@ -1071,13 +1075,17 @@ void FlatSourceDomain::count_external_source_regions()
}
}
void FlatSourceDomain::convert_external_sources()
void FlatSourceDomain::convert_external_sources(bool use_adjoint_sources)
{
// Determine whether forward or (local) adjoint sources are desired
const auto& sources =
use_adjoint_sources ? model::adjoint_sources : model::external_sources;
// Loop over external sources
for (int es = 0; es < model::external_sources.size(); es++) {
for (int es = 0; es < sources.size(); es++) {
// Extract source information
Source* s = model::external_sources[es].get();
Source* s = sources[es].get();
IndependentSource* is = dynamic_cast<IndependentSource*>(s);
Discrete* energy = dynamic_cast<Discrete*>(is->energy());
const std::unordered_set<int32_t>& domain_ids = is->domain_ids();
@ -1223,7 +1231,7 @@ void FlatSourceDomain::flatten_xs()
}
}
void FlatSourceDomain::set_adjoint_sources()
void FlatSourceDomain::set_fw_adjoint_sources()
{
// Set the adjoint external source to 1/forward_flux. If the forward flux is
// negative, zero, or extremely close to zero, set the adjoint source to zero,
@ -1252,6 +1260,10 @@ void FlatSourceDomain::set_adjoint_sources()
source_regions_.external_source(sr, g) = 0.0;
} else {
source_regions_.external_source(sr, g) = 1.0 / flux;
if (!std::isfinite(source_regions_.external_source(sr, g))) {
// If the flux is NaN or Inf, set the adjoint source to zero
source_regions_.external_source(sr, g) = 0.0;
}
}
if (flux > 0.0) {
source_regions_.external_source_present(sr) = 1;
@ -1283,6 +1295,7 @@ void FlatSourceDomain::set_adjoint_sources()
source_regions_.external_source_present(sr) = 0;
}
}
// Divide the fixed source term by sigma t (to save time when applying each
// iteration)
#pragma omp parallel for
@ -1297,8 +1310,86 @@ void FlatSourceDomain::set_adjoint_sources()
sigma_t_[(material * ntemperature_ + temp) * negroups_ + g] *
source_regions_.density_mult(sr);
source_regions_.external_source(sr, g) /= sigma_t;
if (!std::isfinite(source_regions_.external_source(sr, g))) {
// If the flux is NaN or Inf, set the adjoint source to zero
source_regions_.external_source(sr, g) = 0.0;
}
}
}
if (fw_cadis_local_) {
// Only external sources that have a non-mesh type tally task should remain
// non-zero. Everything else gets zero'd out.
#pragma omp parallel for
for (int64_t sr = 0; sr < n_source_regions(); sr++) {
// If there is already no external source, don't need to do anything
if (source_regions_.external_source_present(sr) == 0) {
continue;
}
// If there is an adjoint source term here, then we need to check it.
// We will track if ANY group has a valid local FW-CADIS source term
bool has_any_sources = false;
// Now, loop over groups
for (int g = 0; g < negroups_; g++) {
// If there are no tally tasks associated with this source element
// then it is not a local FW-CADIS source, so we continue to the next
// group
if (source_regions_.tally_task(sr, g).empty()) {
source_regions_.external_source(sr, g) = 0.0;
continue;
}
// If there are tally tasks, we can through them and check if
// any of them are local FW-CADIS targets.
// We track if ANY of the tasks are local FW-CADIS target tallies
bool local_fw_cadis_target_region = false;
// Now we loop through
for (const auto& task : source_regions_.tally_task(sr, g)) {
Tally& tally {*model::tallies[task.tally_idx]};
const auto t_id = tally.id();
// Search for target tallies
if (std::find(fw_cadis_local_targets_.begin(),
fw_cadis_local_targets_.end(),
t_id) != fw_cadis_local_targets_.end()) {
local_fw_cadis_target_region = true;
break;
}
}
// If ANY of the tasks is a local FW-CADIS target,
// Then we keep the source term and set that this
// source region has a valid FW-CADIS source term.
// Otherwise, we zero out the source term.
if (local_fw_cadis_target_region) {
has_any_sources = true;
} else {
source_regions_.external_source(sr, g) = 0.0;
}
} // End loop over groups
// If there were any valid FW-CADIS source terms for any
// of the groups, then the SR as a whole counts as a source
if (has_any_sources) {
source_regions_.external_source_present(sr) = 1;
} else {
source_regions_.external_source_present(sr) = 0;
}
} // End loop over source regions
} // End local FW-CADIS logic
}
void FlatSourceDomain::set_local_adjoint_sources()
{
// Set the external source to user-specified adjoint sources.
convert_external_sources(true);
}
void FlatSourceDomain::transpose_scattering_matrix()

View file

@ -168,14 +168,12 @@ void validate_random_ray_inputs()
"constrained by domain id (cell, material, or universe) in "
"random ray mode.");
} else if (is->domain_ids().size() > 0 && sp) {
// If both a domain constraint and a non-default point source location
// are specified, notify user that domain constraint takes precedence.
if (sp->r().x == 0.0 && sp->r().y == 0.0 && sp->r().z == 0.0) {
warning("Fixed source has both a domain constraint and a point "
"type spatial distribution. The domain constraint takes "
"precedence in random ray mode -- point source coordinate "
"will be ignored.");
}
// If both a domain constraint and a point source location are
// specified, notify user that domain constraint takes precedence.
warning("Fixed source has both a domain constraint and a point "
"type spatial distribution. The domain constraint takes "
"precedence in random ray mode -- point source coordinate "
"will be ignored.");
}
// Check that a discrete energy distribution was used
@ -189,6 +187,56 @@ void validate_random_ray_inputs()
}
}
// Validate adjoint sources
///////////////////////////////////////////////////////////////////
if (FlatSourceDomain::adjoint_ && !model::adjoint_sources.empty()) {
for (int i = 0; i < model::adjoint_sources.size(); i++) {
Source* s = model::adjoint_sources[i].get();
// Check for independent source
IndependentSource* is = dynamic_cast<IndependentSource*>(s);
if (!is) {
fatal_error(
"Only IndependentSource adjoint source types are allowed in "
"random ray mode");
}
// Check for isotropic source
UnitSphereDistribution* angle_dist = is->angle();
Isotropic* id = dynamic_cast<Isotropic*>(angle_dist);
if (!id) {
fatal_error(
"Invalid source definition -- only isotropic adjoint sources are "
"allowed in random ray mode.");
}
// Validate that a domain ID was specified OR that it is a point source
auto sp = dynamic_cast<SpatialPoint*>(is->space());
if (is->domain_ids().size() == 0 && !sp) {
fatal_error("Adjoint sources must be point source or spatially "
"constrained by domain id (cell, material, or universe) in "
"random ray mode.");
} else if (is->domain_ids().size() > 0 && sp) {
// If both a domain constraint and a point source location are
// specified, notify user that domain constraint takes precedence.
warning("Adjoint source has both a domain constraint and a point "
"type spatial distribution. The domain constraint takes "
"precedence in random ray mode -- point source coordinate "
"will be ignored.");
}
// Check that a discrete energy distribution was used
Distribution* d = is->energy();
Discrete* dd = dynamic_cast<Discrete*>(d);
if (!dd) {
fatal_error(
"Only discrete (multigroup) energy distributions are allowed for "
"adjoint sources in random ray mode.");
}
}
}
// Validate plotting files
///////////////////////////////////////////////////////////////////
for (int p = 0; p < model::plots.size(); p++) {
@ -232,20 +280,22 @@ void validate_random_ray_inputs()
warning(
"Linear sources may result in negative fluxes in small source regions "
"generated by mesh subdivision. Negative sources may result in low "
"quality FW-CADIS weight windows. We recommend you use flat source mode "
"when generating weight windows with an overlaid mesh tally.");
"quality FW-CADIS weight windows. We recommend you use flat source "
"mode when generating weight windows with an overlaid mesh tally.");
}
}
void print_adjoint_header()
void openmc_finalize_random_ray()
{
if (!FlatSourceDomain::adjoint_)
// If we're going to do an adjoint simulation afterwards, report that this
// is the initial forward flux solve.
header("FORWARD FLUX SOLVE", 3);
else
// Otherwise report that we are doing the adjoint simulation
header("ADJOINT FLUX SOLVE", 3);
FlatSourceDomain::volume_estimator_ = RandomRayVolumeEstimator::HYBRID;
FlatSourceDomain::volume_normalized_flux_tallies_ = false;
FlatSourceDomain::adjoint_ = false;
FlatSourceDomain::fw_cadis_local_ = false;
FlatSourceDomain::fw_cadis_local_targets_.clear();
FlatSourceDomain::mesh_domain_map_.clear();
RandomRay::ray_source_.reset();
RandomRay::source_shape_ = RandomRaySourceShape::FLAT;
RandomRay::sample_method_ = RandomRaySampleMethod::PRNG;
}
//==============================================================================
@ -278,16 +328,6 @@ RandomRaySimulation::RandomRaySimulation()
// Convert OpenMC native MGXS into a more efficient format
// internal to the random ray solver
domain_->flatten_xs();
// Check if adjoint calculation is needed. If it is, we will run the forward
// calculation first and then the adjoint calculation later.
adjoint_needed_ = FlatSourceDomain::adjoint_;
// Adjoint is always false for the forward calculation
FlatSourceDomain::adjoint_ = false;
// The first simulation is run after initialization
is_first_simulation_ = true;
}
void RandomRaySimulation::apply_fixed_sources_and_mesh_domains()
@ -295,30 +335,52 @@ void RandomRaySimulation::apply_fixed_sources_and_mesh_domains()
domain_->apply_meshes();
if (settings::run_mode == RunMode::FIXED_SOURCE) {
// Transfer external source user inputs onto random ray source regions
domain_->convert_external_sources();
domain_->convert_external_sources(false);
domain_->count_external_source_regions();
}
}
void RandomRaySimulation::prepare_fixed_sources_adjoint()
void RandomRaySimulation::prepare_fw_fixed_sources_adjoint()
{
// Prepare adjoint fixed sources using forward flux
domain_->source_regions_.adjoint_reset();
if (settings::run_mode == RunMode::FIXED_SOURCE) {
domain_->set_adjoint_sources();
domain_->set_fw_adjoint_sources();
}
}
void RandomRaySimulation::prepare_adjoint_simulation()
void RandomRaySimulation::prepare_local_fixed_sources_adjoint()
{
// Configure the domain for adjoint simulation
FlatSourceDomain::adjoint_ = true;
if (settings::run_mode == RunMode::FIXED_SOURCE) {
domain_->set_local_adjoint_sources();
}
}
void RandomRaySimulation::prepare_adjoint_simulation(bool fw_adjoint)
{
reset_timers();
if (mpi::master)
header("ADJOINT FLUX SOLVE", 3);
if (fw_adjoint) {
// Forward simulation has already been run;
// Configure the domain for adjoint simulation and
// re-initialize OpenMC general data structures
FlatSourceDomain::adjoint_ = true;
openmc_simulation_init();
prepare_fw_fixed_sources_adjoint();
} else {
// Initialize adjoint fixed sources
domain_->apply_meshes();
prepare_local_fixed_sources_adjoint();
domain_->count_external_source_regions();
}
// Reset k-eff
domain_->k_eff_ = 1.0;
// Initialize adjoint fixed sources, if present
prepare_fixed_sources_adjoint();
// Transpose scattering matrix
domain_->transpose_scattering_matrix();
@ -328,18 +390,6 @@ void RandomRaySimulation::prepare_adjoint_simulation()
void RandomRaySimulation::simulate()
{
if (!is_first_simulation_) {
if (mpi::master && adjoint_needed_)
openmc::print_adjoint_header();
// Reset the timers and reinitialize the general OpenMC datastructures if
// this is after the first simulation
reset_timers();
// Initialize OpenMC general data structures
openmc_simulation_init();
}
// Begin main simulation timer
simulation::time_total.start();
@ -435,7 +485,7 @@ void RandomRaySimulation::simulate()
// End main simulation timer
simulation::time_total.stop();
// Normalize and save the final flux
// Normalize and save the final forward flux
double source_normalization_factor =
domain_->compute_fixed_source_normalization_factor() /
(settings::n_batches - settings::n_inactive);
@ -451,11 +501,6 @@ void RandomRaySimulation::simulate()
// Output all simulation results
output_simulation_results();
// Toggle that the simulation object has been initialized after the first
// simulation
if (is_first_simulation_)
is_first_simulation_ = false;
}
void RandomRaySimulation::output_simulation_results() const
@ -622,17 +667,6 @@ void RandomRaySimulation::print_results_random_ray(
}
}
void openmc_finalize_random_ray()
{
FlatSourceDomain::volume_estimator_ = RandomRayVolumeEstimator::HYBRID;
FlatSourceDomain::volume_normalized_flux_tallies_ = false;
FlatSourceDomain::adjoint_ = false;
FlatSourceDomain::mesh_domain_map_.clear();
RandomRay::ray_source_.reset();
RandomRay::source_shape_ = RandomRaySourceShape::FLAT;
RandomRay::sample_method_ = RandomRaySampleMethod::PRNG;
}
} // namespace openmc
//==============================================================================
@ -645,12 +679,25 @@ void openmc_run_random_ray()
// Run forward simulation
//////////////////////////////////////////////////////////
if (openmc::mpi::master) {
if (openmc::FlatSourceDomain::adjoint_) {
openmc::FlatSourceDomain::adjoint_ = false;
openmc::print_adjoint_header();
openmc::FlatSourceDomain::adjoint_ = true;
}
// Check if adjoint calculation is needed, and if local adjoint source(s)
// are present. If an adjoint calculation is needed and no sources are
// specified, we will run a forward calculation first to calculate adjoint
// sources for global variance reduction, then perform an adjoint
// calculation later.
bool adjoint_needed = openmc::FlatSourceDomain::adjoint_;
bool fw_adjoint = openmc::model::adjoint_sources.empty() && adjoint_needed;
// If we're going to do an adjoint simulation with forward-weighted adjoint
// sources afterwards, report that this is the initial forward flux solve.
if (!adjoint_needed || fw_adjoint) {
// Configure the domain for forward simulation
openmc::FlatSourceDomain::adjoint_ = false;
if (adjoint_needed && openmc::mpi::master)
openmc::header("FORWARD FLUX SOLVE", 3);
} else {
// Configure domain for adjoint simulation (later)
openmc::FlatSourceDomain::adjoint_ = true;
}
// Initialize OpenMC general data structures
@ -663,21 +710,25 @@ void openmc_run_random_ray()
// Initialize Random Ray Simulation Object
openmc::RandomRaySimulation sim;
// Initialize fixed sources, if present
sim.apply_fixed_sources_and_mesh_domains();
if (!adjoint_needed || fw_adjoint) {
// Initialize fixed sources, if present
sim.apply_fixed_sources_and_mesh_domains();
// Run initial random ray simulation
sim.simulate();
// Execute random ray simulation
sim.simulate();
}
//////////////////////////////////////////////////////////
// Run adjoint simulation (if enabled)
//////////////////////////////////////////////////////////
if (sim.adjoint_needed_) {
// Setup for adjoint simulation
sim.prepare_adjoint_simulation();
// Run adjoint simulation
sim.simulate();
if (!adjoint_needed) {
return;
}
// Setup for adjoint simulation
sim.prepare_adjoint_simulation(fw_adjoint);
// Execute random ray simulation
sim.simulate();
}

View file

@ -280,8 +280,9 @@ void get_run_parameters(pugi::xml_node node_base)
} else {
fatal_error("Specify random ray inactive distance in settings XML");
}
if (check_for_node(random_ray_node, "source")) {
xml_node source_node = random_ray_node.child("source");
if (check_for_node(random_ray_node, "ray_source")) {
xml_node ray_source_node = random_ray_node.child("ray_source");
xml_node source_node = ray_source_node.child("source");
// Get point to list of <source> elements and make sure there is at least
// one
RandomRay::ray_source_ = Source::create(source_node);
@ -369,6 +370,13 @@ void get_run_parameters(pugi::xml_node node_base)
"between 0 and 1");
}
}
if (check_for_node(random_ray_node, "adjoint_source")) {
pugi::xml_node adj_source_node = random_ray_node.child("adjoint_source");
for (pugi::xml_node source_node : adj_source_node.children("source")) {
// Find any local adjoint sources
model::adjoint_sources.push_back(Source::create(source_node));
}
}
}
}
@ -1276,6 +1284,16 @@ void read_settings_xml(pugi::xml_node root)
break;
}
}
// If any weight window generators have local FW-CADIS target tallies,
// user-defined adjoint sources cannot be used at the same time.
if (!model::adjoint_sources.empty()) {
for (const auto& wwg : variance_reduction::weight_windows_generators) {
if (!wwg->targets_.empty()) {
fatal_error("Cannot use both user-defined adjoint sources and "
"FW-CADIS target tallies at the same time.");
}
}
}
}
// Set up weight window checkpoints

View file

@ -62,6 +62,8 @@ namespace model {
vector<unique_ptr<Source>> external_sources;
vector<unique_ptr<Source>> adjoint_sources;
DiscreteIndex external_sources_probability;
} // namespace model
@ -710,6 +712,7 @@ SourceSite sample_external_source(uint64_t* seed)
void free_memory_source()
{
model::external_sources.clear();
model::adjoint_sources.clear();
reset_source_rejection_counters();
}

View file

@ -621,7 +621,7 @@ void WeightWindows::update_weights(const Tally* tally, const std::string& value,
}
}
} else {
// For FW-CADIS, weight windows are inversely proportional to the adjoint
// For (FW-)CADIS, weight windows are inversely proportional to the adjoint
// fluxes. We normalize the weight windows across all energy groups.
#pragma omp parallel for collapse(2) schedule(static)
for (int e = 0; e < e_bins; e++) {
@ -801,6 +801,13 @@ WeightWindowsGenerator::WeightWindowsGenerator(pugi::xml_node node)
fatal_error("FW-CADIS can only be run in random ray solver mode.");
}
FlatSourceDomain::adjoint_ = true;
if (check_for_node(node, "targets")) {
FlatSourceDomain::fw_cadis_local_ = true;
targets_ = get_node_array<size_t>(node, "targets");
FlatSourceDomain::fw_cadis_local_targets_.insert(
std::end(FlatSourceDomain::fw_cadis_local_targets_),
std::begin(targets_), std::end(targets_));
}
} else {
fatal_error(fmt::format(
"Unknown weight window update method '{}' specified", method_string));

View file

@ -207,11 +207,13 @@
<random_ray>
<distance_active>500.0</distance_active>
<distance_inactive>100.0</distance_inactive>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>0.0 0.0 0.0 30.0 30.0 30.0</parameters>
</space>
</source>
<ray_source>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>0.0 0.0 0.0 30.0 30.0 30.0</parameters>
</space>
</source>
</ray_source>
<volume_normalized_flux_tallies>true</volume_normalized_flux_tallies>
<adjoint>true</adjoint>
<volume_estimator>naive</volume_estimator>

View file

@ -80,11 +80,13 @@
<random_ray>
<distance_active>100.0</distance_active>
<distance_inactive>20.0</distance_inactive>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>-1.26 -1.26 -1 1.26 1.26 1</parameters>
</space>
</source>
<ray_source>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>-1.26 -1.26 -1 1.26 1.26 1</parameters>
</space>
</source>
</ray_source>
<volume_normalized_flux_tallies>true</volume_normalized_flux_tallies>
<adjoint>true</adjoint>
</random_ray>

View file

@ -0,0 +1,293 @@
<?xml version='1.0' encoding='utf-8'?>
<model>
<materials>
<cross_sections>mgxs.h5</cross_sections>
<material id="1" name="source">
<density value="1.0" units="macro"/>
<macroscopic name="source"/>
</material>
<material id="2" name="cavity">
<density value="1.0" units="macro"/>
<macroscopic name="cavity"/>
</material>
<material id="3" name="absorber">
<density value="1.0" units="macro"/>
<macroscopic name="absorber"/>
</material>
</materials>
<geometry>
<cell id="1" name="infinite source region" material="1" universe="1"/>
<cell id="2" name="cube cavity region" material="2" universe="2"/>
<cell id="3" name="absorber region" material="3" universe="3"/>
<cell id="4" fill="4" universe="5"/>
<cell id="5" name="full domain" fill="5" region="1 -2 3 -4 5 -6" universe="6"/>
<cell id="6" name="detector 1" material="3" region="1 -10 4 -8 5 -11" universe="6"/>
<cell id="7" name="detector 2" material="3" region="2 -7 4 -8 6 -9" universe="6"/>
<cell id="8" name="outside cube" material="2" region="(2 3 5 -7 ((-8 -6) | (-4 6 -9))) | (4 -8 ((10 -2 5 -9) | (-10 1 11 -9) | (2 -7 5 -6))) | (1 3 6 -9 ((-8 -2) | (-4 2 -7)))" universe="6"/>
<lattice id="4">
<pitch>2.5 2.5 2.5</pitch>
<dimension>12 12 12</dimension>
<lower_left>0.0 0.0 0.0</lower_left>
<universes>
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 </universes>
</lattice>
<surface id="1" type="x-plane" boundary="reflective" coeffs="0.0"/>
<surface id="2" type="x-plane" coeffs="30.0"/>
<surface id="3" type="y-plane" boundary="reflective" coeffs="0.0"/>
<surface id="4" type="y-plane" coeffs="30.0"/>
<surface id="5" type="z-plane" boundary="reflective" coeffs="0.0"/>
<surface id="6" type="z-plane" coeffs="30.0"/>
<surface id="7" type="x-plane" boundary="vacuum" coeffs="35.0"/>
<surface id="8" type="y-plane" boundary="vacuum" coeffs="35.0"/>
<surface id="9" type="z-plane" boundary="vacuum" coeffs="35.0"/>
<surface id="10" type="x-plane" coeffs="5.0"/>
<surface id="11" type="z-plane" coeffs="5.0"/>
</geometry>
<settings>
<run_mode>fixed source</run_mode>
<particles>500</particles>
<batches>10</batches>
<inactive>5</inactive>
<source type="independent" strength="3.14" particle="neutron">
<energy type="discrete">
<parameters>100.0 1.0</parameters>
</energy>
<constraints>
<domain_type>universe</domain_type>
<domain_ids>1</domain_ids>
</constraints>
</source>
<energy_mode>multi-group</energy_mode>
<random_ray>
<distance_active>800.0</distance_active>
<distance_inactive>100.0</distance_inactive>
<ray_source>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>0.0 0.0 0.0 35.0 35.0 35.0</parameters>
</space>
</source>
</ray_source>
<volume_normalized_flux_tallies>true</volume_normalized_flux_tallies>
<source_region_meshes>
<mesh id="1">
<domain id="6" type="universe"/>
</mesh>
</source_region_meshes>
<adjoint>true</adjoint>
<adjoint_source>
<source type="independent" strength="3.14" particle="neutron">
<energy type="discrete">
<parameters>100.0 1.0</parameters>
</energy>
<constraints>
<domain_type>cell</domain_type>
<domain_ids>6 7</domain_ids>
</constraints>
</source>
</adjoint_source>
<volume_estimator>naive</volume_estimator>
</random_ray>
<mesh id="1">
<dimension>14 14 14</dimension>
<lower_left>0.0 0.0 0.0</lower_left>
<upper_right>35.0 35.0 35.0</upper_right>
</mesh>
</settings>
<tallies>
<filter id="1" type="cell">
<bins>6</bins>
</filter>
<filter id="2" type="cell">
<bins>7</bins>
</filter>
<filter id="3" type="material">
<bins>3</bins>
</filter>
<filter id="4" type="material">
<bins>2</bins>
</filter>
<filter id="5" type="material">
<bins>1</bins>
</filter>
<tally id="1" name="Detector 1 Tally">
<filters>1</filters>
<scores>flux</scores>
<estimator>tracklength</estimator>
</tally>
<tally id="2" name="Detector 2 Tally">
<filters>2</filters>
<scores>flux</scores>
<estimator>tracklength</estimator>
</tally>
<tally id="3" name="Absorber Tally">
<filters>3</filters>
<scores>flux</scores>
<estimator>tracklength</estimator>
</tally>
<tally id="4" name="Cavity Tally">
<filters>4</filters>
<scores>flux</scores>
<estimator>tracklength</estimator>
</tally>
<tally id="5" name="Source Tally">
<filters>5</filters>
<scores>flux</scores>
<estimator>tracklength</estimator>
</tally>
</tallies>
</model>

View file

@ -0,0 +1,15 @@
tally 1:
2.215273E+01
9.815738E+01
tally 2:
1.873933E+01
7.023420E+01
tally 3:
4.802282E-01
4.612707E-02
tally 4:
2.516720E-01
1.271063E-02
tally 5:
1.169938E-02
3.277334E-05

View file

@ -0,0 +1,35 @@
import os
import openmc
from openmc.examples import random_ray_three_region_cube_with_detectors
from tests.testing_harness import TolerantPyAPITestHarness
class MGXSTestHarness(TolerantPyAPITestHarness):
def _cleanup(self):
super()._cleanup()
f = 'mgxs.h5'
if os.path.exists(f):
os.remove(f)
def test_random_ray_adjoint_local():
model = random_ray_three_region_cube_with_detectors()
detector1_cells = model.geometry.get_cells_by_name("detector 1")
detector2_cells = model.geometry.get_cells_by_name("detector 2")
detector_cells = detector1_cells + detector2_cells
strengths = [1.0]
midpoints = [100.0]
energy_distribution = openmc.stats.Discrete(x=midpoints, p=strengths)
adj_source = openmc.IndependentSource(energy=energy_distribution, constraints={
'domains': detector_cells}, strength=3.14)
model.settings.random_ray['adjoint'] = True
model.settings.random_ray['adjoint_source'] = adj_source
model.settings.random_ray['volume_estimator'] = 'naive'
harness = MGXSTestHarness('statepoint.10.h5', model)
harness.main()

View file

@ -41,11 +41,13 @@
</source>
<energy_mode>multi-group</energy_mode>
<random_ray>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>-0.63 -0.63 -1.0 0.63 0.63 1.0</parameters>
</space>
</source>
<ray_source>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>-0.63 -0.63 -1.0 0.63 0.63 1.0</parameters>
</space>
</source>
</ray_source>
<distance_inactive>30.0</distance_inactive>
<distance_active>150.0</distance_active>
<source_region_meshes>

View file

@ -41,11 +41,13 @@
</source>
<energy_mode>multi-group</energy_mode>
<random_ray>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>-0.63 -0.63 -1.0 0.63 0.63 1.0</parameters>
</space>
</source>
<ray_source>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>-0.63 -0.63 -1.0 0.63 0.63 1.0</parameters>
</space>
</source>
</ray_source>
<distance_inactive>30.0</distance_inactive>
<distance_active>150.0</distance_active>
<source_region_meshes>

View file

@ -41,11 +41,13 @@
</source>
<energy_mode>multi-group</energy_mode>
<random_ray>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>-0.63 -0.63 -1.0 0.63 0.63 1.0</parameters>
</space>
</source>
<ray_source>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>-0.63 -0.63 -1.0 0.63 0.63 1.0</parameters>
</space>
</source>
</ray_source>
<distance_inactive>30.0</distance_inactive>
<distance_active>150.0</distance_active>
<source_region_meshes>

View file

@ -41,11 +41,13 @@
</source>
<energy_mode>multi-group</energy_mode>
<random_ray>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>-0.63 -0.63 -1.0 0.63 0.63 1.0</parameters>
</space>
</source>
<ray_source>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>-0.63 -0.63 -1.0 0.63 0.63 1.0</parameters>
</space>
</source>
</ray_source>
<distance_inactive>30.0</distance_inactive>
<distance_active>150.0</distance_active>
<source_region_meshes>

View file

@ -41,11 +41,13 @@
</source>
<energy_mode>multi-group</energy_mode>
<random_ray>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>-0.63 -0.63 -1.0 0.63 0.63 1.0</parameters>
</space>
</source>
<ray_source>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>-0.63 -0.63 -1.0 0.63 0.63 1.0</parameters>
</space>
</source>
</ray_source>
<distance_inactive>30.0</distance_inactive>
<distance_active>150.0</distance_active>
<source_region_meshes>

View file

@ -41,11 +41,13 @@
</source>
<energy_mode>multi-group</energy_mode>
<random_ray>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>-0.63 -0.63 -1.0 0.63 0.63 1.0</parameters>
</space>
</source>
<ray_source>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>-0.63 -0.63 -1.0 0.63 0.63 1.0</parameters>
</space>
</source>
</ray_source>
<distance_inactive>30.0</distance_inactive>
<distance_active>150.0</distance_active>
<source_region_meshes>

View file

@ -38,11 +38,13 @@
</source>
<energy_mode>multi-group</energy_mode>
<random_ray>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>-0.63 -0.63 -1.0 0.63 0.63 1.0</parameters>
</space>
</source>
<ray_source>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>-0.63 -0.63 -1.0 0.63 0.63 1.0</parameters>
</space>
</source>
</ray_source>
<distance_inactive>30.0</distance_inactive>
<distance_active>150.0</distance_active>
<source_region_meshes>

View file

@ -41,11 +41,13 @@
</source>
<energy_mode>multi-group</energy_mode>
<random_ray>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>-0.63 -0.63 -1.0 0.63 0.63 1.0</parameters>
</space>
</source>
<ray_source>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>-0.63 -0.63 -1.0 0.63 0.63 1.0</parameters>
</space>
</source>
</ray_source>
<distance_inactive>30.0</distance_inactive>
<distance_active>150.0</distance_active>
<source_region_meshes>

View file

@ -38,11 +38,13 @@
</source>
<energy_mode>multi-group</energy_mode>
<random_ray>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>-0.63 -0.63 -1.0 0.63 0.63 1.0</parameters>
</space>
</source>
<ray_source>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>-0.63 -0.63 -1.0 0.63 0.63 1.0</parameters>
</space>
</source>
</ray_source>
<distance_inactive>30.0</distance_inactive>
<distance_active>150.0</distance_active>
<source_region_meshes>

View file

@ -41,11 +41,13 @@
</source>
<energy_mode>multi-group</energy_mode>
<random_ray>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>-0.63 -0.63 -1.0 0.63 0.63 1.0</parameters>
</space>
</source>
<ray_source>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>-0.63 -0.63 -1.0 0.63 0.63 1.0</parameters>
</space>
</source>
</ray_source>
<distance_inactive>30.0</distance_inactive>
<distance_active>150.0</distance_active>
<source_region_meshes>

View file

@ -47,11 +47,13 @@
<temperature_range>200.0 400.0</temperature_range>
<temperature_tolerance>200.0</temperature_tolerance>
<random_ray>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>-0.63 -0.63 -1.0 0.63 0.63 1.0</parameters>
</space>
</source>
<ray_source>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>-0.63 -0.63 -1.0 0.63 0.63 1.0</parameters>
</space>
</source>
</ray_source>
<distance_inactive>30.0</distance_inactive>
<distance_active>150.0</distance_active>
<source_region_meshes>

View file

@ -47,11 +47,13 @@
<temperature_range>200.0 400.0</temperature_range>
<temperature_tolerance>200.0</temperature_tolerance>
<random_ray>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>-0.63 -0.63 -1.0 0.63 0.63 1.0</parameters>
</space>
</source>
<ray_source>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>-0.63 -0.63 -1.0 0.63 0.63 1.0</parameters>
</space>
</source>
</ray_source>
<distance_inactive>30.0</distance_inactive>
<distance_active>150.0</distance_active>
<source_region_meshes>

View file

@ -47,11 +47,13 @@
<temperature_range>200.0 400.0</temperature_range>
<temperature_tolerance>200.0</temperature_tolerance>
<random_ray>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>-0.63 -0.63 -1.0 0.63 0.63 1.0</parameters>
</space>
</source>
<ray_source>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>-0.63 -0.63 -1.0 0.63 0.63 1.0</parameters>
</space>
</source>
</ray_source>
<distance_inactive>30.0</distance_inactive>
<distance_active>150.0</distance_active>
<source_region_meshes>

View file

@ -86,11 +86,13 @@
<random_ray>
<distance_active>100.0</distance_active>
<distance_inactive>20.0</distance_inactive>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>-1.26 -1.26 -1 1.26 1.26 1</parameters>
</space>
</source>
<ray_source>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>-1.26 -1.26 -1 1.26 1.26 1</parameters>
</space>
</source>
</ray_source>
<volume_normalized_flux_tallies>true</volume_normalized_flux_tallies>
</random_ray>
</settings>

View file

@ -207,11 +207,13 @@
<random_ray>
<distance_active>500.0</distance_active>
<distance_inactive>100.0</distance_inactive>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>0.0 0.0 0.0 30.0 30.0 30.0</parameters>
</space>
</source>
<ray_source>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>0.0 0.0 0.0 30.0 30.0 30.0</parameters>
</space>
</source>
</ray_source>
<volume_normalized_flux_tallies>true</volume_normalized_flux_tallies>
</random_ray>
</settings>

View file

@ -89,11 +89,13 @@
<random_ray>
<distance_active>100.0</distance_active>
<distance_inactive>20.0</distance_inactive>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>-1.26 -1.26 -1 1.26 1.26 1</parameters>
</space>
</source>
<ray_source>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>-1.26 -1.26 -1 1.26 1.26 1</parameters>
</space>
</source>
</ray_source>
<volume_normalized_flux_tallies>true</volume_normalized_flux_tallies>
</random_ray>
</settings>

View file

@ -41,11 +41,13 @@
</source>
<energy_mode>multi-group</energy_mode>
<random_ray>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>-0.63 -0.63 -1.0 0.63 0.63 1.0</parameters>
</space>
</source>
<ray_source>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>-0.63 -0.63 -1.0 0.63 0.63 1.0</parameters>
</space>
</source>
</ray_source>
<distance_inactive>30.0</distance_inactive>
<distance_active>150.0</distance_active>
<source_region_meshes>

View file

@ -6,11 +6,13 @@
<inactive>5</inactive>
<energy_mode>multi-group</energy_mode>
<random_ray>
<source particle="neutron" strength="1.0" type="independent">
<space type="box">
<parameters>0.0 0.0 0.0 100.0 100.0 100.0</parameters>
</space>
</source>
<ray_source>
<source particle="neutron" strength="1.0" type="independent">
<space type="box">
<parameters>0.0 0.0 0.0 100.0 100.0 100.0</parameters>
</space>
</source>
</ray_source>
<distance_inactive>40.0</distance_inactive>
<distance_active>400.0</distance_active>
</random_ray>

View file

@ -207,11 +207,13 @@
<random_ray>
<distance_active>500.0</distance_active>
<distance_inactive>100.0</distance_inactive>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>0.0 0.0 0.0 30.0 30.0 30.0</parameters>
</space>
</source>
<ray_source>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>0.0 0.0 0.0 30.0 30.0 30.0</parameters>
</space>
</source>
</ray_source>
<volume_normalized_flux_tallies>true</volume_normalized_flux_tallies>
</random_ray>
</settings>

View file

@ -207,11 +207,13 @@
<random_ray>
<distance_active>500.0</distance_active>
<distance_inactive>100.0</distance_inactive>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>0.0 0.0 0.0 30.0 30.0 30.0</parameters>
</space>
</source>
<ray_source>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>0.0 0.0 0.0 30.0 30.0 30.0</parameters>
</space>
</source>
</ray_source>
<volume_normalized_flux_tallies>true</volume_normalized_flux_tallies>
</random_ray>
</settings>

View file

@ -207,11 +207,13 @@
<random_ray>
<distance_active>500.0</distance_active>
<distance_inactive>100.0</distance_inactive>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>0.0 0.0 0.0 30.0 30.0 30.0</parameters>
</space>
</source>
<ray_source>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>0.0 0.0 0.0 30.0 30.0 30.0</parameters>
</space>
</source>
</ray_source>
<volume_normalized_flux_tallies>true</volume_normalized_flux_tallies>
</random_ray>
</settings>

View file

@ -207,11 +207,13 @@
<random_ray>
<distance_active>500.0</distance_active>
<distance_inactive>100.0</distance_inactive>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>0.0 0.0 0.0 30.0 30.0 30.0</parameters>
</space>
</source>
<ray_source>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>0.0 0.0 0.0 30.0 30.0 30.0</parameters>
</space>
</source>
</ray_source>
<volume_normalized_flux_tallies>true</volume_normalized_flux_tallies>
<source_shape>linear</source_shape>
</random_ray>

View file

@ -207,11 +207,13 @@
<random_ray>
<distance_active>500.0</distance_active>
<distance_inactive>100.0</distance_inactive>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>0.0 0.0 0.0 30.0 30.0 30.0</parameters>
</space>
</source>
<ray_source>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>0.0 0.0 0.0 30.0 30.0 30.0</parameters>
</space>
</source>
</ray_source>
<volume_normalized_flux_tallies>true</volume_normalized_flux_tallies>
<source_shape>linear_xy</source_shape>
</random_ray>

View file

@ -207,11 +207,13 @@
<random_ray>
<distance_active>500.0</distance_active>
<distance_inactive>100.0</distance_inactive>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>0.0 0.0 0.0 30.0 30.0 30.0</parameters>
</space>
</source>
<ray_source>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>0.0 0.0 0.0 30.0 30.0 30.0</parameters>
</space>
</source>
</ray_source>
<volume_normalized_flux_tallies>true</volume_normalized_flux_tallies>
<source_region_meshes>
<mesh id="1">

View file

@ -207,11 +207,13 @@
<random_ray>
<distance_active>500.0</distance_active>
<distance_inactive>100.0</distance_inactive>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>0.0 0.0 0.0 30.0 30.0 30.0</parameters>
</space>
</source>
<ray_source>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>0.0 0.0 0.0 30.0 30.0 30.0</parameters>
</space>
</source>
</ray_source>
<volume_normalized_flux_tallies>true</volume_normalized_flux_tallies>
<source_region_meshes>
<mesh id="1">

View file

@ -207,11 +207,13 @@
<random_ray>
<distance_active>500.0</distance_active>
<distance_inactive>100.0</distance_inactive>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>0.0 0.0 0.0 30.0 30.0 30.0</parameters>
</space>
</source>
<ray_source>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>0.0 0.0 0.0 30.0 30.0 30.0</parameters>
</space>
</source>
</ray_source>
<volume_normalized_flux_tallies>false</volume_normalized_flux_tallies>
</random_ray>
</settings>

View file

@ -207,11 +207,13 @@
<random_ray>
<distance_active>500.0</distance_active>
<distance_inactive>100.0</distance_inactive>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>0.0 0.0 0.0 30.0 30.0 30.0</parameters>
</space>
</source>
<ray_source>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>0.0 0.0 0.0 30.0 30.0 30.0</parameters>
</space>
</source>
</ray_source>
<volume_normalized_flux_tallies>true</volume_normalized_flux_tallies>
</random_ray>
</settings>

View file

@ -110,11 +110,13 @@
<random_ray>
<distance_active>40.0</distance_active>
<distance_inactive>40.0</distance_inactive>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>-1.26 -1.26 -1 1.26 1.26 1</parameters>
</space>
</source>
<ray_source>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>-1.26 -1.26 -1 1.26 1.26 1</parameters>
</space>
</source>
</ray_source>
<volume_normalized_flux_tallies>false</volume_normalized_flux_tallies>
<source_shape>flat</source_shape>
</random_ray>

View file

@ -110,11 +110,13 @@
<random_ray>
<distance_active>40.0</distance_active>
<distance_inactive>40.0</distance_inactive>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>-1.26 -1.26 -1 1.26 1.26 1</parameters>
</space>
</source>
<ray_source>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>-1.26 -1.26 -1 1.26 1.26 1</parameters>
</space>
</source>
</ray_source>
<volume_normalized_flux_tallies>false</volume_normalized_flux_tallies>
<source_shape>linear_xy</source_shape>
</random_ray>

View file

@ -80,11 +80,13 @@
<random_ray>
<distance_active>100.0</distance_active>
<distance_inactive>20.0</distance_inactive>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>-1.26 -1.26 -1 1.26 1.26 1</parameters>
</space>
</source>
<ray_source>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>-1.26 -1.26 -1 1.26 1.26 1</parameters>
</space>
</source>
</ray_source>
<volume_normalized_flux_tallies>true</volume_normalized_flux_tallies>
<sample_method>halton</sample_method>
</random_ray>

View file

@ -80,11 +80,13 @@
<random_ray>
<distance_active>100.0</distance_active>
<distance_inactive>20.0</distance_inactive>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>-1.26 -1.26 -1 1.26 1.26 1</parameters>
</space>
</source>
<ray_source>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>-1.26 -1.26 -1 1.26 1.26 1</parameters>
</space>
</source>
</ray_source>
<volume_normalized_flux_tallies>true</volume_normalized_flux_tallies>
</random_ray>
</settings>

View file

@ -80,11 +80,13 @@
<random_ray>
<distance_active>100.0</distance_active>
<distance_inactive>20.0</distance_inactive>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>-1.26 -1.26 -1 1.26 1.26 1</parameters>
</space>
</source>
<ray_source>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>-1.26 -1.26 -1 1.26 1.26 1</parameters>
</space>
</source>
</ray_source>
<volume_normalized_flux_tallies>true</volume_normalized_flux_tallies>
<source_region_meshes>
<mesh id="2">

View file

@ -80,11 +80,13 @@
<random_ray>
<distance_active>100.0</distance_active>
<distance_inactive>20.0</distance_inactive>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>-1.26 -1.26 -1 1.26 1.26 1</parameters>
</space>
</source>
<ray_source>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>-1.26 -1.26 -1 1.26 1.26 1</parameters>
</space>
</source>
</ray_source>
<volume_normalized_flux_tallies>true</volume_normalized_flux_tallies>
<source_shape>linear</source_shape>
</random_ray>

View file

@ -80,11 +80,13 @@
<random_ray>
<distance_active>100.0</distance_active>
<distance_inactive>20.0</distance_inactive>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>-1.26 -1.26 -1 1.26 1.26 1</parameters>
</space>
</source>
<ray_source>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>-1.26 -1.26 -1 1.26 1.26 1</parameters>
</space>
</source>
</ray_source>
<volume_normalized_flux_tallies>true</volume_normalized_flux_tallies>
<source_shape>linear_xy</source_shape>
</random_ray>

View file

@ -207,11 +207,13 @@
<random_ray>
<distance_active>500.0</distance_active>
<distance_inactive>100.0</distance_inactive>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>0.0 0.0 0.0 30.0 30.0 30.0</parameters>
</space>
</source>
<ray_source>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>0.0 0.0 0.0 30.0 30.0 30.0</parameters>
</space>
</source>
</ray_source>
<volume_normalized_flux_tallies>true</volume_normalized_flux_tallies>
</random_ray>
</settings>

View file

@ -206,11 +206,13 @@
<random_ray>
<distance_active>500.0</distance_active>
<distance_inactive>100.0</distance_inactive>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>0.0 0.0 0.0 30.0 30.0 30.0</parameters>
</space>
</source>
<ray_source>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>0.0 0.0 0.0 30.0 30.0 30.0</parameters>
</space>
</source>
</ray_source>
<volume_normalized_flux_tallies>true</volume_normalized_flux_tallies>
<source_region_meshes>
<mesh id="1">

View file

@ -37,11 +37,13 @@
<random_ray>
<distance_inactive>100.0</distance_inactive>
<distance_active>400.0</distance_active>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>0.0 -5.0 -5.0 40.0 5.0 5.0</parameters>
</space>
</source>
<ray_source>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>0.0 -5.0 -5.0 40.0 5.0 5.0</parameters>
</space>
</source>
</ray_source>
<source_shape>flat</source_shape>
<sample_method>s2</sample_method>
<source_region_meshes>

View file

@ -207,11 +207,13 @@
<random_ray>
<distance_active>500.0</distance_active>
<distance_inactive>100.0</distance_inactive>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>0.0 0.0 0.0 30.0 30.0 30.0</parameters>
</space>
</source>
<ray_source>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>0.0 0.0 0.0 30.0 30.0 30.0</parameters>
</space>
</source>
</ray_source>
<volume_normalized_flux_tallies>true</volume_normalized_flux_tallies>
<source_shape>flat</source_shape>
</random_ray>

View file

@ -207,11 +207,13 @@
<random_ray>
<distance_active>500.0</distance_active>
<distance_inactive>100.0</distance_inactive>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>0.0 0.0 0.0 30.0 30.0 30.0</parameters>
</space>
</source>
<ray_source>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>0.0 0.0 0.0 30.0 30.0 30.0</parameters>
</space>
</source>
</ray_source>
<volume_normalized_flux_tallies>true</volume_normalized_flux_tallies>
<source_shape>linear</source_shape>
</random_ray>

View file

@ -207,11 +207,13 @@
<random_ray>
<distance_active>500.0</distance_active>
<distance_inactive>100.0</distance_inactive>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>0.0 0.0 0.0 30.0 30.0 30.0</parameters>
</space>
</source>
<ray_source>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>0.0 0.0 0.0 30.0 30.0 30.0</parameters>
</space>
</source>
</ray_source>
<volume_normalized_flux_tallies>true</volume_normalized_flux_tallies>
<volume_estimator>hybrid</volume_estimator>
</random_ray>

View file

@ -207,11 +207,13 @@
<random_ray>
<distance_active>500.0</distance_active>
<distance_inactive>100.0</distance_inactive>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>0.0 0.0 0.0 30.0 30.0 30.0</parameters>
</space>
</source>
<ray_source>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>0.0 0.0 0.0 30.0 30.0 30.0</parameters>
</space>
</source>
</ray_source>
<volume_normalized_flux_tallies>true</volume_normalized_flux_tallies>
<volume_estimator>naive</volume_estimator>
</random_ray>

View file

@ -207,11 +207,13 @@
<random_ray>
<distance_active>500.0</distance_active>
<distance_inactive>100.0</distance_inactive>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>0.0 0.0 0.0 30.0 30.0 30.0</parameters>
</space>
</source>
<ray_source>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>0.0 0.0 0.0 30.0 30.0 30.0</parameters>
</space>
</source>
</ray_source>
<volume_normalized_flux_tallies>true</volume_normalized_flux_tallies>
<volume_estimator>simulation_averaged</volume_estimator>
</random_ray>

View file

@ -207,11 +207,13 @@
<random_ray>
<distance_active>500.0</distance_active>
<distance_inactive>100.0</distance_inactive>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>0.0 0.0 0.0 30.0 30.0 30.0</parameters>
</space>
</source>
<ray_source>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>0.0 0.0 0.0 30.0 30.0 30.0</parameters>
</space>
</source>
</ray_source>
<volume_normalized_flux_tallies>true</volume_normalized_flux_tallies>
<source_shape>linear</source_shape>
<volume_estimator>hybrid</volume_estimator>

View file

@ -207,11 +207,13 @@
<random_ray>
<distance_active>500.0</distance_active>
<distance_inactive>100.0</distance_inactive>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>0.0 0.0 0.0 30.0 30.0 30.0</parameters>
</space>
</source>
<ray_source>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>0.0 0.0 0.0 30.0 30.0 30.0</parameters>
</space>
</source>
</ray_source>
<volume_normalized_flux_tallies>true</volume_normalized_flux_tallies>
<source_shape>linear</source_shape>
<volume_estimator>naive</volume_estimator>

View file

@ -207,11 +207,13 @@
<random_ray>
<distance_active>500.0</distance_active>
<distance_inactive>100.0</distance_inactive>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>0.0 0.0 0.0 30.0 30.0 30.0</parameters>
</space>
</source>
<ray_source>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>0.0 0.0 0.0 30.0 30.0 30.0</parameters>
</space>
</source>
</ray_source>
<volume_normalized_flux_tallies>true</volume_normalized_flux_tallies>
<source_shape>linear</source_shape>
<volume_estimator>simulation_averaged</volume_estimator>

View file

@ -222,11 +222,13 @@
<random_ray>
<distance_active>500.0</distance_active>
<distance_inactive>100.0</distance_inactive>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>0.0 0.0 0.0 30.0 30.0 30.0</parameters>
</space>
</source>
<ray_source>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>0.0 0.0 0.0 30.0 30.0 30.0</parameters>
</space>
</source>
</ray_source>
<volume_normalized_flux_tallies>true</volume_normalized_flux_tallies>
<volume_estimator>naive</volume_estimator>
</random_ray>

View file

@ -0,0 +1,273 @@
<?xml version='1.0' encoding='utf-8'?>
<model>
<materials>
<cross_sections>mgxs.h5</cross_sections>
<material id="1" name="source">
<density value="1.0" units="macro"/>
<macroscopic name="source"/>
</material>
<material id="2" name="cavity">
<density value="1.0" units="macro"/>
<macroscopic name="cavity"/>
</material>
<material id="3" name="absorber">
<density value="1.0" units="macro"/>
<macroscopic name="absorber"/>
</material>
</materials>
<geometry>
<cell id="1" name="infinite source region" material="1" universe="1"/>
<cell id="2" name="cube cavity region" material="2" universe="2"/>
<cell id="3" name="absorber region" material="3" universe="3"/>
<cell id="4" fill="4" universe="5"/>
<cell id="5" name="full domain" fill="5" region="1 -2 3 -4 5 -6" universe="6"/>
<cell id="6" name="detector 1" material="3" region="1 -10 4 -8 5 -11" universe="6"/>
<cell id="7" name="detector 2" material="3" region="2 -7 4 -8 6 -9" universe="6"/>
<cell id="8" name="outside cube" material="2" region="(2 3 5 -7 ((-8 -6) | (-4 6 -9))) | (4 -8 ((10 -2 5 -9) | (-10 1 11 -9) | (2 -7 5 -6))) | (1 3 6 -9 ((-8 -2) | (-4 2 -7)))" universe="6"/>
<lattice id="4">
<pitch>2.5 2.5 2.5</pitch>
<dimension>12 12 12</dimension>
<lower_left>0.0 0.0 0.0</lower_left>
<universes>
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 </universes>
</lattice>
<surface id="1" type="x-plane" boundary="reflective" coeffs="0.0"/>
<surface id="2" type="x-plane" coeffs="30.0"/>
<surface id="3" type="y-plane" boundary="reflective" coeffs="0.0"/>
<surface id="4" type="y-plane" coeffs="30.0"/>
<surface id="5" type="z-plane" boundary="reflective" coeffs="0.0"/>
<surface id="6" type="z-plane" coeffs="30.0"/>
<surface id="7" type="x-plane" boundary="vacuum" coeffs="35.0"/>
<surface id="8" type="y-plane" boundary="vacuum" coeffs="35.0"/>
<surface id="9" type="z-plane" boundary="vacuum" coeffs="35.0"/>
<surface id="10" type="x-plane" coeffs="5.0"/>
<surface id="11" type="z-plane" coeffs="5.0"/>
</geometry>
<settings>
<run_mode>fixed source</run_mode>
<particles>500</particles>
<batches>10</batches>
<inactive>5</inactive>
<source type="independent" strength="3.14" particle="neutron">
<energy type="discrete">
<parameters>100.0 1.0</parameters>
</energy>
<constraints>
<domain_type>universe</domain_type>
<domain_ids>1</domain_ids>
</constraints>
</source>
<energy_mode>multi-group</energy_mode>
<weight_window_generators>
<weight_windows_generator>
<mesh>2</mesh>
<particle_type>neutron</particle_type>
<max_realizations>10</max_realizations>
<update_interval>1</update_interval>
<on_the_fly>true</on_the_fly>
<method>fw_cadis</method>
<targets>1 2</targets>
</weight_windows_generator>
</weight_window_generators>
<mesh id="2">
<dimension>7 7 7</dimension>
<lower_left>0.0 0.0 0.0</lower_left>
<upper_right>35.0 35.0 35.0</upper_right>
</mesh>
<random_ray>
<distance_active>800.0</distance_active>
<distance_inactive>100.0</distance_inactive>
<ray_source>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>0.0 0.0 0.0 35.0 35.0 35.0</parameters>
</space>
</source>
</ray_source>
<volume_normalized_flux_tallies>true</volume_normalized_flux_tallies>
<source_region_meshes>
<mesh id="1">
<domain id="6" type="universe"/>
</mesh>
</source_region_meshes>
<volume_estimator>naive</volume_estimator>
</random_ray>
<mesh id="1">
<dimension>14 14 14</dimension>
<lower_left>0.0 0.0 0.0</lower_left>
<upper_right>35.0 35.0 35.0</upper_right>
</mesh>
</settings>
<tallies>
<filter id="1" type="cell">
<bins>6</bins>
</filter>
<filter id="2" type="cell">
<bins>7</bins>
</filter>
<tally id="1" name="Detector 1 Tally">
<filters>1</filters>
<scores>flux</scores>
<estimator>tracklength</estimator>
</tally>
<tally id="2" name="Detector 2 Tally">
<filters>2</filters>
<scores>flux</scores>
<estimator>tracklength</estimator>
</tally>
</tallies>
</model>

View file

@ -0,0 +1,696 @@
RegularMesh
ID = 2
Name =
Dimensions = 3
Voxels = [7 7 7]
Lower left = [0. 0. 0.]
Upper Right = [np.float64(35.0), np.float64(35.0), np.float64(35.0)]
Width = [5. 5. 5.]
Lower Bounds
1.52e-01
1.53e-01
1.78e-01
1.97e-01
2.41e-01
3.94e-01
2.26e-03
1.43e-01
1.58e-01
1.75e-01
1.86e-01
2.06e-01
4.83e-02
2.11e-03
1.31e-01
1.37e-01
1.61e-01
1.76e-01
2.04e-01
1.15e-01
5.04e-03
1.05e-01
1.31e-01
1.49e-01
1.72e-01
1.81e-01
4.24e-02
5.31e-03
6.79e-02
9.98e-02
1.56e-01
1.68e-01
1.78e-01
1.39e-02
5.49e-03
2.69e-03
6.66e-03
2.36e-02
1.65e-02
1.71e-02
1.12e-02
1.94e-03
1.12e-04
5.43e-04
1.23e-03
1.51e-03
1.51e-03
1.31e-03
1.21e-03
1.52e-01
1.60e-01
1.81e-01
2.03e-01
2.16e-01
2.58e-02
2.07e-03
1.45e-01
1.59e-01
1.84e-01
2.07e-01
2.14e-01
8.82e-02
2.92e-03
1.36e-01
1.53e-01
1.61e-01
1.92e-01
2.28e-01
1.82e-01
2.70e-03
1.18e-01
1.42e-01
1.52e-01
1.81e-01
1.98e-01
2.87e-02
6.46e-03
1.00e-01
1.41e-01
1.80e-01
1.73e-01
2.05e-01
1.09e-01
3.29e-03
5.37e-03
1.44e-02
4.53e-02
2.16e-02
7.53e-02
2.38e-02
1.38e-03
4.52e-04
1.11e-03
1.39e-03
1.33e-03
1.26e-03
1.22e-03
9.78e-04
1.83e-01
1.77e-01
1.83e-01
2.03e-01
2.27e-01
7.70e-02
3.55e-03
1.63e-01
1.80e-01
1.87e-01
1.86e-01
2.20e-01
4.43e-02
2.00e-03
1.68e-01
1.60e-01
1.63e-01
1.78e-01
2.12e-01
9.86e-02
2.96e-03
1.56e-01
1.59e-01
1.63e-01
1.72e-01
1.81e-01
7.15e-02
1.77e-03
1.58e-01
1.80e-01
1.87e-01
1.66e-01
1.66e-01
1.22e-02
2.65e-03
2.11e-02
3.01e-02
4.85e-02
1.48e-02
4.67e-02
5.38e-03
1.01e-03
8.10e-04
8.55e-04
1.43e-03
1.63e-03
1.05e-03
1.04e-03
6.84e-04
2.01e-01
2.17e-01
2.26e-01
2.37e-01
2.45e-01
3.25e-02
2.68e-02
2.09e-01
2.09e-01
2.07e-01
2.02e-01
2.15e-01
2.42e-02
2.97e-03
2.01e-01
1.94e-01
1.93e-01
1.80e-01
1.72e-01
1.32e-02
1.54e-03
1.84e-01
1.87e-01
1.63e-01
1.49e-01
1.50e-01
6.42e-02
1.91e-03
1.93e-01
2.15e-01
1.93e-01
1.42e-01
1.22e-01
7.21e-03
9.37e-04
1.67e-02
5.33e-02
5.24e-02
1.13e-02
1.23e-02
4.44e-03
6.14e-04
7.25e-04
6.85e-04
8.30e-04
9.75e-04
6.78e-04
5.52e-04
5.29e-04
2.82e-01
2.73e-01
2.85e-01
2.57e-01
2.70e-01
2.24e-02
2.57e-03
2.52e-01
2.49e-01
2.38e-01
2.53e-01
2.37e-01
1.48e-02
2.30e-03
2.18e-01
2.22e-01
2.20e-01
1.96e-01
1.80e-01
1.93e-02
1.53e-03
2.21e-01
2.39e-01
1.99e-01
1.67e-01
1.45e-01
1.11e-02
8.58e-04
2.57e-01
2.32e-01
1.89e-01
1.26e-01
8.31e-02
8.12e-03
6.25e-04
8.53e-02
7.87e-02
1.53e-02
1.22e-02
7.53e-03
1.75e-03
3.39e-04
1.08e-03
8.97e-04
6.11e-04
5.24e-04
4.33e-04
2.49e-04
2.36e-04
4.78e-01
1.38e-01
5.00e-01
2.99e-02
3.12e-02
1.07e-01
1.42e-03
3.01e-01
4.37e-02
1.79e-01
2.39e-01
7.54e-02
1.13e-02
1.17e-03
3.44e-01
2.30e-01
5.55e-02
5.69e-02
1.70e-02
8.02e-03
8.18e-04
1.77e-01
6.57e-02
6.14e-02
3.20e-02
1.32e-02
6.75e-03
6.17e-04
3.49e-02
1.65e-02
1.95e-02
8.71e-03
9.02e-03
2.07e-03
3.41e-04
7.97e-02
2.60e-02
1.65e-02
6.67e-03
2.61e-03
5.74e-04
1.41e-04
1.62e-03
1.49e-03
8.36e-04
3.95e-04
2.37e-04
1.32e-04
5.59e-05
1.07e-03
9.93e-04
1.63e-03
6.02e-03
1.30e-03
2.86e-03
2.98e-03
1.02e-03
1.31e-03
1.39e-03
2.62e-03
1.69e-03
2.40e-03
3.96e-03
1.26e-03
1.78e-03
1.30e-03
1.06e-03
1.79e-03
1.40e-03
3.18e-03
1.93e-03
1.72e-03
1.78e-03
8.41e-04
8.66e-04
8.00e-04
1.01e-03
1.54e-03
1.30e-03
1.11e-03
9.80e-04
5.02e-04
3.11e-04
3.49e-04
1.24e-03
1.66e-03
8.20e-04
5.29e-04
3.62e-04
1.27e-04
6.03e-05
6.28e-04
6.20e-04
5.01e-04
4.28e-04
2.95e-04
5.38e-05
6.24e-06
Upper Bounds
7.61e-01
7.65e-01
8.88e-01
9.87e-01
1.21e+00
1.97e+00
1.13e-02
7.17e-01
7.88e-01
8.74e-01
9.32e-01
1.03e+00
2.41e-01
1.06e-02
6.53e-01
6.86e-01
8.03e-01
8.82e-01
1.02e+00
5.77e-01
2.52e-02
5.23e-01
6.53e-01
7.46e-01
8.58e-01
9.06e-01
2.12e-01
2.66e-02
3.40e-01
4.99e-01
7.82e-01
8.41e-01
8.89e-01
6.94e-02
2.75e-02
1.34e-02
3.33e-02
1.18e-01
8.26e-02
8.54e-02
5.62e-02
9.71e-03
5.62e-04
2.72e-03
6.16e-03
7.54e-03
7.55e-03
6.53e-03
6.05e-03
7.58e-01
7.99e-01
9.04e-01
1.01e+00
1.08e+00
1.29e-01
1.03e-02
7.25e-01
7.95e-01
9.18e-01
1.03e+00
1.07e+00
4.41e-01
1.46e-02
6.80e-01
7.67e-01
8.04e-01
9.61e-01
1.14e+00
9.09e-01
1.35e-02
5.92e-01
7.08e-01
7.60e-01
9.05e-01
9.92e-01
1.43e-01
3.23e-02
5.02e-01
7.06e-01
9.01e-01
8.64e-01
1.02e+00
5.44e-01
1.64e-02
2.68e-02
7.22e-02
2.27e-01
1.08e-01
3.77e-01
1.19e-01
6.91e-03
2.26e-03
5.54e-03
6.95e-03
6.66e-03
6.32e-03
6.08e-03
4.89e-03
9.15e-01
8.87e-01
9.13e-01
1.02e+00
1.13e+00
3.85e-01
1.78e-02
8.13e-01
9.00e-01
9.37e-01
9.28e-01
1.10e+00
2.22e-01
9.99e-03
8.40e-01
8.02e-01
8.17e-01
8.90e-01
1.06e+00
4.93e-01
1.48e-02
7.81e-01
7.93e-01
8.16e-01
8.61e-01
9.05e-01
3.58e-01
8.84e-03
7.91e-01
9.00e-01
9.34e-01
8.31e-01
8.31e-01
6.09e-02
1.33e-02
1.06e-01
1.50e-01
2.43e-01
7.38e-02
2.33e-01
2.69e-02
5.07e-03
4.05e-03
4.28e-03
7.13e-03
8.17e-03
5.26e-03
5.20e-03
3.42e-03
1.01e+00
1.09e+00
1.13e+00
1.18e+00
1.22e+00
1.62e-01
1.34e-01
1.05e+00
1.04e+00
1.03e+00
1.01e+00
1.07e+00
1.21e-01
1.49e-02
1.00e+00
9.68e-01
9.64e-01
9.01e-01
8.62e-01
6.59e-02
7.71e-03
9.19e-01
9.37e-01
8.13e-01
7.43e-01
7.51e-01
3.21e-01
9.55e-03
9.63e-01
1.07e+00
9.67e-01
7.12e-01
6.10e-01
3.60e-02
4.68e-03
8.33e-02
2.66e-01
2.62e-01
5.67e-02
6.16e-02
2.22e-02
3.07e-03
3.63e-03
3.42e-03
4.15e-03
4.88e-03
3.39e-03
2.76e-03
2.65e-03
1.41e+00
1.36e+00
1.42e+00
1.28e+00
1.35e+00
1.12e-01
1.28e-02
1.26e+00
1.24e+00
1.19e+00
1.26e+00
1.18e+00
7.42e-02
1.15e-02
1.09e+00
1.11e+00
1.10e+00
9.79e-01
9.01e-01
9.64e-02
7.63e-03
1.11e+00
1.19e+00
9.95e-01
8.35e-01
7.23e-01
5.53e-02
4.29e-03
1.28e+00
1.16e+00
9.47e-01
6.30e-01
4.16e-01
4.06e-02
3.13e-03
4.27e-01
3.94e-01
7.67e-02
6.12e-02
3.77e-02
8.74e-03
1.70e-03
5.41e-03
4.48e-03
3.06e-03
2.62e-03
2.16e-03
1.25e-03
1.18e-03
2.39e+00
6.90e-01
2.50e+00
1.50e-01
1.56e-01
5.36e-01
7.11e-03
1.50e+00
2.18e-01
8.93e-01
1.20e+00
3.77e-01
5.66e-02
5.84e-03
1.72e+00
1.15e+00
2.77e-01
2.84e-01
8.51e-02
4.01e-02
4.09e-03
8.84e-01
3.28e-01
3.07e-01
1.60e-01
6.60e-02
3.37e-02
3.08e-03
1.74e-01
8.27e-02
9.77e-02
4.36e-02
4.51e-02
1.03e-02
1.71e-03
3.98e-01
1.30e-01
8.25e-02
3.33e-02
1.30e-02
2.87e-03
7.05e-04
8.08e-03
7.43e-03
4.18e-03
1.97e-03
1.18e-03
6.58e-04
2.80e-04
5.36e-03
4.96e-03
8.16e-03
3.01e-02
6.48e-03
1.43e-02
1.49e-02
5.08e-03
6.57e-03
6.95e-03
1.31e-02
8.44e-03
1.20e-02
1.98e-02
6.30e-03
8.90e-03
6.49e-03
5.28e-03
8.94e-03
7.00e-03
1.59e-02
9.64e-03
8.62e-03
8.88e-03
4.21e-03
4.33e-03
4.00e-03
5.04e-03
7.71e-03
6.51e-03
5.56e-03
4.90e-03
2.51e-03
1.55e-03
1.75e-03
6.19e-03
8.31e-03
4.10e-03
2.65e-03
1.81e-03
6.34e-04
3.01e-04
3.14e-03
3.10e-03
2.51e-03
2.14e-03
1.47e-03
2.69e-04
3.12e-05

View file

@ -0,0 +1,42 @@
import os
import openmc
from openmc.examples import random_ray_three_region_cube_with_detectors
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_weight_windows_fw_cadis_local():
model = random_ray_three_region_cube_with_detectors()
for tally in list(model.tallies):
if tally.name in {"Source Tally", "Absorber Tally", "Cavity Tally"}:
# leave only the tallies of interest
model.tallies.remove(tally)
ww_mesh = openmc.RegularMesh()
n = 7
width = 35.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(
method="fw_cadis",
targets=model.tallies,
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()

View file

@ -222,11 +222,13 @@
<random_ray>
<distance_active>500.0</distance_active>
<distance_inactive>100.0</distance_inactive>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>0.0 0.0 0.0 30.0 30.0 30.0</parameters>
</space>
</source>
<ray_source>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>0.0 0.0 0.0 30.0 30.0 30.0</parameters>
</space>
</source>
</ray_source>
<volume_normalized_flux_tallies>true</volume_normalized_flux_tallies>
<source_region_meshes>
<mesh id="1">

View file

@ -222,11 +222,13 @@
<random_ray>
<distance_active>500.0</distance_active>
<distance_inactive>100.0</distance_inactive>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>0.0 0.0 0.0 30.0 30.0 30.0</parameters>
</space>
</source>
<ray_source>
<source type="independent" strength="1.0" particle="neutron">
<space type="box">
<parameters>0.0 0.0 0.0 30.0 30.0 30.0</parameters>
</space>
</source>
</ray_source>
<volume_normalized_flux_tallies>true</volume_normalized_flux_tallies>
<source_region_meshes>
<mesh id="1">