Skip to content

Commit ab4c484

Browse files
authored
Merge branch 'openmc-dev:develop' into Sensitivity-Analysis
2 parents 953d626 + 3e32aed commit ab4c484

10 files changed

Lines changed: 119 additions & 26 deletions

File tree

include/openmc/constants.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,11 @@ constexpr int MAX_SAMPLE {100000};
6363
// source region in the random ray solver
6464
constexpr double MIN_HITS_PER_BATCH {1.5};
6565

66+
// The minimum flux value to be considered non-zero when computing adjoint
67+
// sources. Positive values below this cutoff will be treated as zero, so as to
68+
// prevent extremely large adjoint source terms from being generated.
69+
constexpr double ZERO_FLUX_CUTOFF {1e-22};
70+
6671
// ============================================================================
6772
// MATH AND PHYSICAL CONSTANTS
6873

openmc/dagmc.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from .surface import _BOUNDARY_TYPES
1414
from .bounding_box import BoundingBox
1515
from .utility_funcs import input_path
16+
from .plots import add_plot_params
1617

1718

1819
class DAGMCUniverse(openmc.UniverseBase):
@@ -566,6 +567,12 @@ def sync_dagmc_cells(self, mats: Iterable[openmc.Material]):
566567
fill = mats_per_id[dag_cell.fill.id] if dag_cell.fill else None
567568
self.add_cell(openmc.DAGMCCell(cell_id=dag_cell_id, fill=fill))
568569

570+
@add_plot_params
571+
def plot(self, *args, **kwargs):
572+
"""Display a slice plot of the DAGMCUniverse.
573+
"""
574+
return openmc.Geometry(self).plot(*args, **kwargs)
575+
569576

570577
class DAGMCCell(openmc.Cell):
571578
"""A cell class for DAGMC-based geometries.

openmc/data/data.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@
9494
'Yb174': 0.32025, 'Yb176': 0.12995, 'Lu175': 0.97401,
9595
'Lu176': 0.02599, 'Hf174': 0.0016, 'Hf176': 0.0526,
9696
'Hf177': 0.186, 'Hf178': 0.2728, 'Hf179': 0.1362,
97-
'Hf180': 0.3508, 'Ta180': 0.0001201, 'Ta181': 0.9998799,
97+
'Hf180': 0.3508, 'Ta180_m1': 0.0001201, 'Ta181': 0.9998799,
9898
'W180': 0.0012, 'W182': 0.265, 'W183': 0.1431,
9999
'W184': 0.3064, 'W186': 0.2843, 'Re185': 0.374,
100100
'Re187': 0.626, 'Os184': 0.0002, 'Os186': 0.0159,

openmc/element.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -144,8 +144,7 @@ def expand(self, percent, percent_type, enrichment=None,
144144
root = tree.getroot()
145145
for child in root.findall('library'):
146146
nuclide = child.attrib['materials']
147-
if re.match(r'{}\d+'.format(self), nuclide) and \
148-
'_m' not in nuclide:
147+
if re.match(r'{}\d+'.format(self), nuclide):
149148
library_nuclides.add(nuclide)
150149

151150
# Get a set of the mutual and absent nuclides. Convert to lists
@@ -185,8 +184,10 @@ def expand(self, percent, percent_type, enrichment=None,
185184
for nuclide in absent_nuclides:
186185
if nuclide in ['O17', 'O18'] and 'O16' in mutual_nuclides:
187186
abundances['O16'] += NATURAL_ABUNDANCE[nuclide]
188-
elif nuclide == 'Ta180' and 'Ta181' in mutual_nuclides:
189-
abundances['Ta181'] += NATURAL_ABUNDANCE[nuclide]
187+
elif nuclide == 'Ta180_m1' and 'Ta180' in library_nuclides:
188+
abundances['Ta180'] = NATURAL_ABUNDANCE[nuclide]
189+
elif nuclide == 'Ta180_m1' and 'Ta181' in mutual_nuclides:
190+
abundances['Ta181'] += NATURAL_ABUNDANCE[nuclide]
190191
elif nuclide == 'W180' and 'W182' in mutual_nuclides:
191192
abundances['W182'] += NATURAL_ABUNDANCE[nuclide]
192193
else:

openmc/geometry.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -754,4 +754,17 @@ def plot(self, *args, **kwargs):
754754
755755
.. versionadded:: 0.14.0
756756
"""
757-
return self.root_universe.plot(*args, **kwargs)
757+
model = openmc.Model()
758+
model.geometry = self
759+
model.materials = self.get_all_materials().values()
760+
761+
# Add placeholder materials for DAGMCUniverses
762+
universes = self.get_all_universes()
763+
for universe in universes.values():
764+
if isinstance(universe, openmc.DAGMCUniverse):
765+
for name in universe.material_names:
766+
mat_dag = openmc.Material(name=name)
767+
mat_dag.add_nuclide('H1', 1.0)
768+
model.materials.append(mat_dag)
769+
770+
return model.plot(*args, **kwargs)

openmc/model/model.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -986,7 +986,16 @@ def plot(
986986
y_min = (origin[y] - 0.5*width[1]) * axis_scaling_factor[axis_units]
987987
y_max = (origin[y] + 0.5*width[1]) * axis_scaling_factor[axis_units]
988988

989+
# Determine whether any materials contains macroscopic data and if so,
990+
# set energy mode accordingly
991+
_energy_mode = self.settings._energy_mode
992+
for mat in self.geometry.get_all_materials().values():
993+
if mat._macroscopic is not None:
994+
self.settings.energy_mode = 'multi-group'
995+
break
996+
989997
with TemporaryDirectory() as tmpdir:
998+
_plot_seed = self.settings.plot_seed
990999
if seed is not None:
9911000
self.settings.plot_seed = seed
9921001

@@ -1007,6 +1016,11 @@ def plot(
10071016
# Run OpenMC in geometry plotting mode
10081017
self.plot_geometry(False, cwd=tmpdir, openmc_exec=openmc_exec)
10091018

1019+
# Undo changes to model
1020+
self.plots.pop()
1021+
self.settings._plot_seed = _plot_seed
1022+
self.settings._energy_mode = _energy_mode
1023+
10101024
# Read image from file
10111025
img_path = Path(tmpdir) / f'plot_{plot.id}.png'
10121026
if not img_path.is_file():

openmc/universe.py

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -337,14 +337,6 @@ def plot(self, *args, **kwargs):
337337
"""
338338
model = openmc.Model()
339339
model.geometry = openmc.Geometry(self)
340-
341-
# Determine whether any materials contains macroscopic data and if
342-
# so, set energy mode accordingly
343-
for mat in self.get_all_materials().values():
344-
if mat._macroscopic is not None:
345-
model.settings.energy_mode = 'multi-group'
346-
break
347-
348340
return model.plot(*args, **kwargs)
349341

350342
def get_nuclides(self):

src/random_ray/flat_source_domain.cpp

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,13 @@ int64_t FlatSourceDomain::add_source_to_scalar_flux()
304304
set_flux_to_source(sr, g);
305305
}
306306
}
307+
// Halt if NaN implosion is detected
308+
if (!std::isfinite(source_regions_.scalar_flux_new(sr, g))) {
309+
fatal_error("A source region scalar flux is not finite. "
310+
"This indicates a numerical instability in the "
311+
"simulation. Consider increasing ray density or adjusting "
312+
"the source region mesh.");
313+
}
307314
}
308315
}
309316

@@ -1154,16 +1161,21 @@ void FlatSourceDomain::flatten_xs()
11541161
m.get_xs(MgxsType::TOTAL, g_out, NULL, NULL, NULL, t, a);
11551162
sigma_t_.push_back(sigma_t);
11561163

1157-
double nu_Sigma_f =
1164+
double nu_sigma_f =
11581165
m.get_xs(MgxsType::NU_FISSION, g_out, NULL, NULL, NULL, t, a);
1159-
nu_sigma_f_.push_back(nu_Sigma_f);
1166+
nu_sigma_f_.push_back(nu_sigma_f);
11601167

11611168
double sigma_f =
11621169
m.get_xs(MgxsType::FISSION, g_out, NULL, NULL, NULL, t, a);
11631170
sigma_f_.push_back(sigma_f);
11641171

11651172
double chi =
11661173
m.get_xs(MgxsType::CHI_PROMPT, g_out, &g_out, NULL, NULL, t, a);
1174+
if (!std::isfinite(chi)) {
1175+
// MGXS interface may return NaN in some cases, such as when material
1176+
// is fissionable but has very small sigma_f.
1177+
chi = 0.0;
1178+
}
11671179
chi_.push_back(chi);
11681180

11691181
for (int g_in = 0; g_in < negroups_; g_in++) {
@@ -1191,17 +1203,30 @@ void FlatSourceDomain::flatten_xs()
11911203

11921204
void FlatSourceDomain::set_adjoint_sources(const vector<double>& forward_flux)
11931205
{
1194-
// Set the external source to 1/forward_flux. If the forward flux is negative
1195-
// or zero, set the adjoint source to zero, as this is likely a very small
1196-
// source region that we don't need to bother trying to vector particles
1197-
// towards. Flux negativity in random ray is not related to the flux being
1198-
// small in magnitude, but rather due to the source region being physically
1199-
// small in volume and thus having a noisy flux estimate.
1206+
// Set the adjoint external source to 1/forward_flux. If the forward flux is
1207+
// negative, zero, or extremely close to zero, set the adjoint source to zero,
1208+
// as this is likely a very small source region that we don't need to bother
1209+
// trying to vector particles towards. In the case of flux "being extremely
1210+
// close to zero", we define this as being a fixed fraction of the maximum
1211+
// forward flux, below which we assume the flux would be physically
1212+
// undetectable.
1213+
1214+
// First, find the maximum forward flux value
1215+
double max_flux = 0.0;
1216+
#pragma omp parallel for reduction(max : max_flux)
1217+
for (int64_t se = 0; se < n_source_elements(); se++) {
1218+
double flux = forward_flux[se];
1219+
if (flux > max_flux) {
1220+
max_flux = flux;
1221+
}
1222+
}
1223+
1224+
// Then, compute the adjoint source for each source region
12001225
#pragma omp parallel for
12011226
for (int64_t sr = 0; sr < n_source_regions(); sr++) {
12021227
for (int g = 0; g < negroups_; g++) {
12031228
double flux = forward_flux[sr * negroups_ + g];
1204-
if (flux <= 0.0) {
1229+
if (flux <= ZERO_FLUX_CUTOFF * max_flux) {
12051230
source_regions_.external_source(sr, g) = 0.0;
12061231
} else {
12071232
source_regions_.external_source(sr, g) = 1.0 / flux;

tests/unit_tests/dagmc/test_plot.py

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77
not openmc.lib._dagmc_enabled(), reason="DAGMC CAD geometry is not enabled."
88
)
99

10-
def test_plotting_dagmc_geometry(request):
11-
"""Test plotting a DAGMC geometry with OpenMC. This is different to CSG
12-
geometry plotting as the path to the DAGMC file needs handling."""
10+
def test_plotting_dagmc_model(request):
11+
"""Test plotting a DAGMC model with OpenMC. This is different to CSG
12+
model plotting as the path to the DAGMC file needs handling."""
1313

1414
dag_universe = openmc.DAGMCUniverse(request.path.parent / 'dagmc.h5m')
1515
csg_with_dag_inside = dag_universe.bounded_universe()
@@ -30,3 +30,32 @@ def test_plotting_dagmc_geometry(request):
3030
model.settings.particles = 50
3131

3232
model.plot()
33+
34+
35+
def test_plotting_dagmc_universe(request):
36+
"""Test plotting a DAGMCUniverse with OpenMC. This is different to plotting
37+
UniverseBase as the materials are not defined withing the DAGMCUniverse."""
38+
39+
dag_universe = openmc.DAGMCUniverse(request.path.parent / 'dagmc.h5m')
40+
dag_universe.plot()
41+
42+
43+
def test_plotting_geometry_filled_with_dagmc_universe(request):
44+
"""Test plotting a geometry with OpenMC. This is an edge case when plotting
45+
geometry as often geometry objects don't include a DAGMCUniverse. The
46+
inclusion of a DAGMCUniverse requires special handling for the materials."""
47+
48+
dag_universe = openmc.DAGMCUniverse(request.path.parent / 'dagmc.h5m', auto_geom_ids=True)
49+
50+
sphere1 = openmc.Sphere(r=50.0)
51+
sphere2 = openmc.Sphere(r=60.0, boundary_type='vacuum')
52+
53+
# Adding a material to the CSG Universe to check all materials are accounted for
54+
csg_material = openmc.Material(name='csg_material')
55+
csg_material.add_nuclide("H1", 1.0)
56+
57+
cell1 = openmc.Cell(fill=dag_universe, region=-sphere1)
58+
cell2 = openmc.Cell(fill=csg_material, region=+sphere1 & -sphere2)
59+
60+
geometry = openmc.Geometry([cell1, cell2])
61+
geometry.plot()

tests/unit_tests/test_element.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,13 @@ def test_expand_no_isotopes():
4444
element.expand(100.0, 'ao')
4545

4646

47+
def test_expand_ta():
48+
ref = {'Ta180': 0.01201, 'Ta181': 99.98799}
49+
element = openmc.Element('Ta')
50+
for isotope in element.expand(100.0, 'ao'):
51+
assert isotope[1] == approx(ref[isotope[0]])
52+
53+
4754
def test_expand_exceptions():
4855
""" Test that correct exceptions are raised for invalid input """
4956

0 commit comments

Comments
 (0)