Skip to content

Commit e4f55a5

Browse files
Fix weight modification for uniform source sampling (#3395)
Co-authored-by: Patrick Shriwise <pshriwise@gmail.com>
1 parent dc619ea commit e4f55a5

File tree

6 files changed

+34
-23
lines changed

6 files changed

+34
-23
lines changed

openmc/deplete/d1s.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,9 @@ def apply_time_correction(
141141
time_correction_factors : dict
142142
Time correction factors as returned by :func:`time_correction_factors`
143143
index : int, optional
144-
Index to use for the correction factors
144+
Index of the time of interest. If N timesteps are provided in
145+
:func:`time_correction_factors`, there are N + 1 times to select from.
146+
The default is -1 which corresponds to the final time.
145147
sum_nuclides : bool
146148
Whether to sum over the parent nuclides
147149

openmc/source.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ def constraints(self, constraints: dict[str, Any] | None):
110110
cv.check_value('rejection strategy', value, ('resample', 'kill'))
111111
self._constraints['rejection_strategy'] = value
112112
else:
113-
raise ValueError('Unknown key in constraints dictionary: {key}')
113+
raise ValueError(f'Unknown key in constraints dictionary: {key}')
114114

115115
@abstractmethod
116116
def populate_xml_element(self, element):

src/settings.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -620,13 +620,6 @@ void read_settings_xml(pugi::xml_node root)
620620
model::external_sources.push_back(make_unique<FileSource>(path));
621621
}
622622

623-
// Build probability mass function for sampling external sources
624-
vector<double> source_strengths;
625-
for (auto& s : model::external_sources) {
626-
source_strengths.push_back(s->strength());
627-
}
628-
model::external_sources_probability.assign(source_strengths);
629-
630623
// If no source specified, default to isotropic point source at origin with
631624
// Watt spectrum. No default source is needed in random ray mode.
632625
if (model::external_sources.empty() &&
@@ -639,6 +632,13 @@ void read_settings_xml(pugi::xml_node root)
639632
UPtrDist {new Discrete(T, p, 1)}));
640633
}
641634

635+
// Build probability mass function for sampling external sources
636+
vector<double> source_strengths;
637+
for (auto& s : model::external_sources) {
638+
source_strengths.push_back(s->strength());
639+
}
640+
model::external_sources_probability.assign(source_strengths);
641+
642642
// Check if we want to write out source
643643
if (check_for_node(root, "write_initial_source")) {
644644
write_initial_source = get_node_value_bool(root, "write_initial_source");

src/source.cpp

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -613,9 +613,10 @@ SourceSite sample_external_source(uint64_t* seed)
613613
{
614614
// Sample from among multiple source distributions
615615
int i = 0;
616-
if (model::external_sources.size() > 1) {
616+
int n_sources = model::external_sources.size();
617+
if (n_sources > 1) {
617618
if (settings::uniform_source_sampling) {
618-
i = prn(seed) * model::external_sources.size();
619+
i = prn(seed) * n_sources;
619620
} else {
620621
i = model::external_sources_probability.sample(seed);
621622
}
@@ -624,9 +625,13 @@ SourceSite sample_external_source(uint64_t* seed)
624625
// Sample source site from i-th source distribution
625626
SourceSite site {model::external_sources[i]->sample_with_constraints(seed)};
626627

627-
// Set particle creation weight
628-
if (settings::uniform_source_sampling) {
629-
site.wgt *= model::external_sources[i]->strength();
628+
// For uniform source sampling, multiply the weight by the ratio of the actual
629+
// probability of sampling source i to the biased probability of sampling
630+
// source i, which is (strength_i / total_strength) / (1 / n)
631+
if (n_sources > 1 && settings::uniform_source_sampling) {
632+
double total_strength = model::external_sources_probability.integral();
633+
site.wgt *=
634+
model::external_sources[i]->strength() * n_sources / total_strength;
630635
}
631636

632637
// If running in MG, convert site.E to group

src/tallies/tally.cpp

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -815,11 +815,8 @@ void Tally::accumulate()
815815
if (mpi::master || !settings::reduce_tallies) {
816816
// Calculate total source strength for normalization
817817
double total_source = 0.0;
818-
if (settings::run_mode == RunMode::FIXED_SOURCE &&
819-
!settings::uniform_source_sampling) {
820-
for (const auto& s : model::external_sources) {
821-
total_source += s->strength();
822-
}
818+
if (settings::run_mode == RunMode::FIXED_SOURCE) {
819+
total_source = model::external_sources_probability.integral();
823820
} else {
824821
total_source = 1.0;
825822
}

tests/unit_tests/test_uniform_source_sampling.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,15 @@ def sphere_model():
1414

1515
model.settings.particles = 100
1616
model.settings.batches = 1
17-
model.settings.source = openmc.IndependentSource(
17+
src1 = openmc.IndependentSource(
1818
energy=openmc.stats.delta_function(1.0e3),
19-
strength=100.0
19+
strength=75.0
2020
)
21+
src2 = openmc.IndependentSource(
22+
energy=openmc.stats.delta_function(1.0e3),
23+
strength=25.0
24+
)
25+
model.settings.source = [src1, src2]
2126
model.settings.run_mode = "fixed source"
2227
model.settings.surf_source_write = {
2328
"max_particles": 100,
@@ -42,11 +47,13 @@ def test_source_weight(run_in_tmpdir, sphere_model):
4247
sphere_model.settings.uniform_source_sampling = True
4348
sphere_model.run()
4449
particles = openmc.ParticleList.from_hdf5('surface_source.h5')
45-
strength = sphere_model.settings.source[0].strength
46-
assert set(p.wgt for p in particles) == {strength}
50+
assert set(p.wgt for p in particles) == {0.5, 1.5}
4751

4852

4953
def test_tally_mean(run_in_tmpdir, sphere_model):
54+
# Use only one source
55+
sphere_model.settings.source.pop()
56+
5057
# Run without uniform source sampling
5158
sphere_model.settings.uniform_source_sampling = False
5259
sp_file = sphere_model.run()

0 commit comments

Comments
 (0)