Skip to content

Commit

Permalink
Random Ray Transport (#2823)
Browse files Browse the repository at this point in the history
Co-authored-by: Gavin Ridley <[email protected]>
Co-authored-by: Paul Romano <[email protected]>
  • Loading branch information
3 people committed Apr 18, 2024
1 parent d53155d commit 5111aa2
Show file tree
Hide file tree
Showing 46 changed files with 4,512 additions and 69 deletions.
3 changes: 3 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,9 @@ list(APPEND libopenmc_SOURCES
src/progress_bar.cpp
src/random_dist.cpp
src/random_lcg.cpp
src/random_ray/random_ray_simulation.cpp
src/random_ray/random_ray.cpp
src/random_ray/flat_source_domain.cpp
src/reaction.cpp
src/reaction_product.cpp
src/scattdata.cpp
Expand Down
Binary file added docs/source/_images/2x2_fsrs.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/source/_images/2x2_materials.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
26 changes: 26 additions & 0 deletions docs/source/io_formats/settings.rst
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,32 @@ or sub-elements and can be set to either "false" or "true".

.. note:: This element is not used in the multi-group :ref:`energy_mode`.

------------------------
``<random_ray>`` Element
------------------------

The ``<random_ray>`` element enables random ray mode and contains a number of
settings relevant to the solver. Tips for selecting these parameters can be
found in the :ref:`random ray user guide <random_ray>`.

:distance_inactive:
The inactive ray length (dead zone length) in [cm].

*Default*: None

:distance_active:
The active ray length in [cm].

*Default*: None

: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
is only used to sample integrating ray starting locations and directions.

*Default*: None

----------------------------------
``<resonance_scattering>`` Element
----------------------------------
Expand Down
1 change: 1 addition & 0 deletions docs/source/methods/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@ Theory and Methodology
energy_deposition
parallelization
cmfd
random_ray
804 changes: 804 additions & 0 deletions docs/source/methods/random_ray.rst

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions docs/source/usersguide/data.rst
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,8 @@ The `official ENDF/B-VII.1 HDF5 library
multipole library, so if you are using this library, the windowed multipole data
will already be available to you.

.. _create_mgxs:

-------------------------
Multigroup Cross Sections
-------------------------
Expand Down
2 changes: 2 additions & 0 deletions docs/source/usersguide/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,6 @@ essential aspects of using OpenMC to perform simulations.
processing
parallel
volume
random_ray
troubleshoot

480 changes: 480 additions & 0 deletions docs/source/usersguide/random_ray.rst

Large diffs are not rendered by default.

203 changes: 203 additions & 0 deletions examples/pincell_random_ray/build_xml.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
import numpy as np
import openmc
import openmc.mgxs

###############################################################################
# Create multigroup data

# Instantiate the energy group data
group_edges = [1e-5, 0.0635, 10.0, 1.0e2, 1.0e3, 0.5e6, 1.0e6, 20.0e6]
groups = openmc.mgxs.EnergyGroups(group_edges)

# Instantiate the 7-group (C5G7) cross section data
uo2_xsdata = openmc.XSdata('UO2', groups)
uo2_xsdata.order = 0
uo2_xsdata.set_total(
[0.1779492, 0.3298048, 0.4803882, 0.5543674, 0.3118013, 0.3951678,
0.5644058])
uo2_xsdata.set_absorption([8.0248e-03, 3.7174e-03, 2.6769e-02, 9.6236e-02,
3.0020e-02, 1.1126e-01, 2.8278e-01])
scatter_matrix = np.array(
[[[0.1275370, 0.0423780, 0.0000094, 0.0000000, 0.0000000, 0.0000000, 0.0000000],
[0.0000000, 0.3244560, 0.0016314, 0.0000000, 0.0000000, 0.0000000, 0.0000000],
[0.0000000, 0.0000000, 0.4509400, 0.0026792, 0.0000000, 0.0000000, 0.0000000],
[0.0000000, 0.0000000, 0.0000000, 0.4525650, 0.0055664, 0.0000000, 0.0000000],
[0.0000000, 0.0000000, 0.0000000, 0.0001253, 0.2714010, 0.0102550, 0.0000000],
[0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0012968, 0.2658020, 0.0168090],
[0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0085458, 0.2730800]]])
scatter_matrix = np.rollaxis(scatter_matrix, 0, 3)
uo2_xsdata.set_scatter_matrix(scatter_matrix)
uo2_xsdata.set_fission([7.21206e-03, 8.19301e-04, 6.45320e-03,
1.85648e-02, 1.78084e-02, 8.30348e-02,
2.16004e-01])
uo2_xsdata.set_nu_fission([2.005998e-02, 2.027303e-03, 1.570599e-02,
4.518301e-02, 4.334208e-02, 2.020901e-01,
5.257105e-01])
uo2_xsdata.set_chi([5.8791e-01, 4.1176e-01, 3.3906e-04, 1.1761e-07, 0.0000e+00,
0.0000e+00, 0.0000e+00])

h2o_xsdata = openmc.XSdata('LWTR', groups)
h2o_xsdata.order = 0
h2o_xsdata.set_total([0.15920605, 0.412969593, 0.59030986, 0.58435,
0.718, 1.2544497, 2.650379])
h2o_xsdata.set_absorption([6.0105e-04, 1.5793e-05, 3.3716e-04,
1.9406e-03, 5.7416e-03, 1.5001e-02,
3.7239e-02])
scatter_matrix = np.array(
[[[0.0444777, 0.1134000, 0.0007235, 0.0000037, 0.0000001, 0.0000000, 0.0000000],
[0.0000000, 0.2823340, 0.1299400, 0.0006234, 0.0000480, 0.0000074, 0.0000010],
[0.0000000, 0.0000000, 0.3452560, 0.2245700, 0.0169990, 0.0026443, 0.0005034],
[0.0000000, 0.0000000, 0.0000000, 0.0910284, 0.4155100, 0.0637320, 0.0121390],
[0.0000000, 0.0000000, 0.0000000, 0.0000714, 0.1391380, 0.5118200, 0.0612290],
[0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0022157, 0.6999130, 0.5373200],
[0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.0000000, 0.1324400, 2.4807000]]])
scatter_matrix = np.rollaxis(scatter_matrix, 0, 3)
h2o_xsdata.set_scatter_matrix(scatter_matrix)

mg_cross_sections_file = openmc.MGXSLibrary(groups)
mg_cross_sections_file.add_xsdatas([uo2_xsdata, h2o_xsdata])
mg_cross_sections_file.export_to_hdf5()

###############################################################################
# Create materials for the problem

# Instantiate some Materials and register the appropriate macroscopic data
uo2 = openmc.Material(name='UO2 fuel')
uo2.set_density('macro', 1.0)
uo2.add_macroscopic('UO2')

water = openmc.Material(name='Water')
water.set_density('macro', 1.0)
water.add_macroscopic('LWTR')

# Instantiate a Materials collection and export to XML
materials_file = openmc.Materials([uo2, water])
materials_file.cross_sections = "mgxs.h5"
materials_file.export_to_xml()

###############################################################################
# Define problem geometry

# The geometry we will define a simplified pincell with fuel radius 0.54 cm
# surrounded by moderator (same as in the multigroup example).
# In random ray, we typically want several radial regions and azimuthal
# sectors in both the fuel and moderator areas of the pincell. This is
# due to the flat source approximation requiring that source regions are
# small compared to the typical mean free path of a neutron. Below we
# sudivide the basic pincell into 8 aziumthal sectors (pizza slices) and
# 5 concentric rings in both the fuel and moderator.

# TODO: When available in OpenMC, use cylindrical lattice instead to
# simplify definition and improve runtime performance.

pincell_base = openmc.Universe()

# These are the subdivided radii (creating 5 concentric regions in the
# fuel and moderator)
ring_radii = [0.241, 0.341, 0.418, 0.482, 0.54, 0.572, 0.612, 0.694, 0.786]
fills = [uo2, uo2, uo2, uo2, uo2, water, water, water, water, water]

# We then create cells representing the bounded rings, with special
# treatment for both the innermost and outermost cells
cells = []
for r in range(10):
cell = []
if r == 0:
outer_bound = openmc.ZCylinder(r=ring_radii[r])
cell = openmc.Cell(fill=fills[r], region=-outer_bound)
elif r == 9:
inner_bound = openmc.ZCylinder(r=ring_radii[r-1])
cell = openmc.Cell(fill=fills[r], region=+inner_bound)
else:
inner_bound = openmc.ZCylinder(r=ring_radii[r-1])
outer_bound = openmc.ZCylinder(r=ring_radii[r])
cell = openmc.Cell(fill=fills[r], region=+inner_bound & -outer_bound)
pincell_base.add_cell(cell)

# We then generate 8 planes to bound 8 azimuthal sectors
azimuthal_planes = []
for i in range(8):
angle = 2 * i * openmc.pi / 8
normal_vector = (-openmc.sin(angle), openmc.cos(angle), 0)
azimuthal_planes.append(openmc.Plane(a=normal_vector[0], b=normal_vector[1], c=normal_vector[2], d=0))

# Create a cell for each azimuthal sector using the pincell base class
azimuthal_cells = []
for i in range(8):
azimuthal_cell = openmc.Cell(name=f'azimuthal_cell_{i}')
azimuthal_cell.fill = pincell_base
azimuthal_cell.region = +azimuthal_planes[i] & -azimuthal_planes[(i+1) % 8]
azimuthal_cells.append(azimuthal_cell)

# Create the (subdivided) geometry with the azimuthal universes
pincell = openmc.Universe(cells=azimuthal_cells)

# Create a region represented as the inside of a rectangular prism
pitch = 1.26
box = openmc.model.RectangularPrism(pitch, pitch, boundary_type='reflective')
pincell_bounded = openmc.Cell(fill=pincell, region=-box, name='pincell')

# Create a geometry (specifying merge surfaces option to remove
# all the redundant cylinder/plane surfaces) and export to XML
geometry = openmc.Geometry([pincell_bounded], merge_surfaces=True)
geometry.export_to_xml()

###############################################################################
# Define problem settings

# Instantiate a Settings object, set all runtime parameters, and export to XML
settings = openmc.Settings()
settings.energy_mode = "multi-group"
settings.batches = 600
settings.inactive = 300
settings.particles = 50

# Create an initial uniform spatial source distribution for sampling rays.
# Note that this must be uniform in space and angle.
lower_left = (-pitch/2, -pitch/2, -1)
upper_right = (pitch/2, pitch/2, 1)
uniform_dist = openmc.stats.Box(lower_left, upper_right)
settings.random_ray['ray_source'] = openmc.IndependentSource(space=uniform_dist)
settings.random_ray['distance_inactive'] = 40.0
settings.random_ray['distance_active'] = 400.0

settings.export_to_xml()

###############################################################################
# Define tallies

# Create a mesh that will be used for tallying
mesh = openmc.RegularMesh()
mesh.dimension = (2, 2)
mesh.lower_left = (-pitch/2, -pitch/2)
mesh.upper_right = (pitch/2, pitch/2)

# Create a mesh filter that can be used in a tally
mesh_filter = openmc.MeshFilter(mesh)

# Let's also create a filter to measure each group
# indepdendently
energy_filter = openmc.EnergyFilter(group_edges)

# Now use the mesh filter in a tally and indicate what scores are desired
tally = openmc.Tally(name="Mesh and Energy tally")
tally.filters = [mesh_filter, energy_filter]
tally.scores = ['flux', 'fission', 'nu-fission']

# Instantiate a Tallies collection and export to XML
tallies = openmc.Tallies([tally])
tallies.export_to_xml()

###############################################################################
# Exporting to OpenMC plots.xml file
###############################################################################

plot = openmc.Plot()
plot.origin = [0, 0, 0]
plot.width = [pitch, pitch, pitch]
plot.pixels = [1000, 1000, 1]
plot.type = 'voxel'

# Instantiate a Plots collection and export to XML
plots = openmc.Plots([plot])
plots.export_to_xml()
1 change: 1 addition & 0 deletions include/openmc/boundary_condition.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ namespace openmc {

// Forward declare some types used in function arguments.
class Particle;
class RandomRay;
class Surface;

//==============================================================================
Expand Down
36 changes: 36 additions & 0 deletions include/openmc/cell.h
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,42 @@ class Cell {
std::unordered_map<int32_t, vector<int32_t>> get_contained_cells(
int32_t instance = 0, Position* hint = nullptr) const;

//! Determine the material index corresponding to a specific cell instance,
//! taking into account presence of distribcell material
//! \param[in] instance of the cell
//! \return material index
int32_t material(int32_t instance) const
{
// If distributed materials are used, then each instance has its own
// material definition. If distributed materials are not used, then
// all instances used the same material stored at material_[0]. The
// presence of distributed materials is inferred from the size of
// the material_ vector being greater than one.
if (material_.size() > 1) {
return material_[instance];
} else {
return material_[0];
}
}

//! Determine the temperature index corresponding to a specific cell instance,
//! taking into account presence of distribcell temperature
//! \param[in] instance of the cell
//! \return temperature index
double sqrtkT(int32_t instance) const
{
// If distributed materials are used, then each instance has its own
// temperature definition. If distributed materials are not used, then
// all instances used the same temperature stored at sqrtkT_[0]. The
// presence of distributed materials is inferred from the size of
// the sqrtkT_ vector being greater than one.
if (sqrtkT_.size() > 1) {
return sqrtkT_[instance];
} else {
return sqrtkT_[0];
}
}

protected:
//! Determine the path to this cell instance in the geometry hierarchy
//! \param[in] instance of the cell to find parent cells for
Expand Down
2 changes: 2 additions & 0 deletions include/openmc/constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,8 @@ enum class RunMode {
VOLUME
};

enum class SolverType { MONTE_CARLO, RANDOM_RAY };

//==============================================================================
// Geometry Constants

Expand Down
3 changes: 2 additions & 1 deletion include/openmc/mgxs.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ class Mgxs {
int num_delayed_groups; // number of delayed neutron groups
vector<XsData> xs; // Cross section data
// MGXS Incoming Flux Angular grid information
bool is_isotropic; // used to skip search for angle indices if isotropic
int n_pol;
int n_azi;
vector<double> polar;
Expand Down Expand Up @@ -85,6 +84,8 @@ class Mgxs {
std::string name; // name of dataset, e.g., UO2
double awr; // atomic weight ratio
bool fissionable; // Is this fissionable
bool is_isotropic {
true}; // used to skip search for angle indices if isotropic

Mgxs() = default;

Expand Down
4 changes: 3 additions & 1 deletion include/openmc/output.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ void print_results();

void write_tallies();

void show_time(const char* label, double secs, int indent_level = 0);

} // namespace openmc
#endif // OPENMC_OUTPUT_H

Expand All @@ -80,4 +82,4 @@ struct formatter<std::array<T, 2>> {
}
};

} // namespace fmt
} // namespace fmt
1 change: 1 addition & 0 deletions include/openmc/plot.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ class PlottableInterface {
virtual void print_info() const = 0;

const std::string& path_plot() const { return path_plot_; }
std::string& path_plot() { return path_plot_; }
int id() const { return id_; }
int level() const { return level_; }

Expand Down
Loading

0 comments on commit 5111aa2

Please sign in to comment.