Skip to content

Commit 326d4ef

Browse files
authored
Merge branch 'openmc-dev:develop' into Sensitivity-Analysis
2 parents 8826082 + afd9d06 commit 326d4ef

File tree

6 files changed

+227
-20
lines changed

6 files changed

+227
-20
lines changed

include/openmc/tallies/tally.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,11 +237,14 @@ extern vector<unique_ptr<Tally>> tallies;
237237
extern vector<int> active_tallies;
238238
extern vector<int> active_analog_tallies;
239239
extern vector<int> active_tracklength_tallies;
240+
extern vector<int> active_timed_tracklength_tallies;
240241
extern vector<int> active_collision_tallies;
241242
extern vector<int> active_meshsurf_tallies;
242243
extern vector<int> active_surface_tallies;
243244
extern vector<int> active_pulse_height_tallies;
244245
extern vector<int> pulse_height_cells;
246+
extern vector<double> time_grid;
247+
245248
} // namespace model
246249

247250
namespace simulation {
@@ -273,6 +276,13 @@ void read_tallies_xml(pugi::xml_node root);
273276
//! batch to a new random variable
274277
void accumulate_tallies();
275278

279+
//! Determine distance to next time boundary
280+
//
281+
//! \param time Current time of particle
282+
//! \param speed Speed of particle
283+
//! \return Distance to next time boundary (or INFTY if none)
284+
double distance_to_time_boundary(double time, double speed);
285+
276286
//! Determine which tallies should be active
277287
void setup_active_tallies();
278288

include/openmc/tallies/tally_scoring.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,16 @@ void score_analog_tally_mg(Particle& p);
9191
//! \param distance The distance in [cm] traveled by the particle
9292
void score_tracklength_tally(Particle& p, double distance);
9393

94+
//! Score time filtered tallies using a tracklength estimate of the flux.
95+
//
96+
//! This is triggered at every event (surface crossing, lattice crossing, or
97+
//! collision) and thus cannot be done for tallies that require post-collision
98+
//! information.
99+
//
100+
//! \param p The particle being tracked
101+
//! \param total_distance The distance in [cm] traveled by the particle
102+
void score_timed_tracklength_tally(Particle& p, double total_distance);
103+
94104
//! Score surface or mesh-surface tallies for particle currents.
95105
//
96106
//! \param p The particle being tracked

src/particle.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,11 @@ void Particle::event_advance()
261261
this->time() += dt;
262262
this->lifetime() += dt;
263263

264+
// Score timed track-length tallies
265+
if (!model::active_timed_tracklength_tallies.empty()) {
266+
score_timed_tracklength_tally(*this, distance);
267+
}
268+
264269
// Score track-length tallies
265270
if (!model::active_tracklength_tallies.empty()) {
266271
score_tracklength_tally(*this, distance);

src/tallies/tally.cpp

Lines changed: 66 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -28,20 +28,23 @@
2828
#include "openmc/tallies/filter_legendre.h"
2929
#include "openmc/tallies/filter_mesh.h"
3030
#include "openmc/tallies/filter_meshborn.h"
31+
#include "openmc/tallies/filter_meshmaterial.h"
3132
#include "openmc/tallies/filter_meshsurface.h"
3233
#include "openmc/tallies/filter_particle.h"
3334
#include "openmc/tallies/filter_sph_harm.h"
3435
#include "openmc/tallies/filter_surface.h"
36+
#include "openmc/tallies/filter_time.h"
3537
#include "openmc/xml_interface.h"
3638

3739
#include "xtensor/xadapt.hpp"
3840
#include "xtensor/xbuilder.hpp" // for empty_like
3941
#include "xtensor/xview.hpp"
4042
#include <fmt/core.h>
4143

42-
#include <algorithm> // for max
44+
#include <algorithm> // for max, set_union
4345
#include <cassert>
44-
#include <cstddef> // for size_t
46+
#include <cstddef> // for size_t
47+
#include <iterator> // for back_inserter
4548
#include <string>
4649

4750
namespace openmc {
@@ -57,11 +60,13 @@ vector<unique_ptr<Tally>> tallies;
5760
vector<int> active_tallies;
5861
vector<int> active_analog_tallies;
5962
vector<int> active_tracklength_tallies;
63+
vector<int> active_timed_tracklength_tallies;
6064
vector<int> active_collision_tallies;
6165
vector<int> active_meshsurf_tallies;
6266
vector<int> active_surface_tallies;
6367
vector<int> active_pulse_height_tallies;
6468
vector<int> pulse_height_cells;
69+
vector<double> time_grid;
6570
} // namespace model
6671

6772
namespace simulation {
@@ -248,8 +253,8 @@ Tally::Tally(pugi::xml_node node)
248253
for (int score : scores_) {
249254
switch (score) {
250255
case SCORE_PULSE_HEIGHT:
251-
fatal_error(
252-
"For pulse-height tallies, photon transport needs to be activated.");
256+
fatal_error("For pulse-height tallies, photon transport needs to be "
257+
"activated.");
253258
break;
254259
}
255260
}
@@ -323,7 +328,8 @@ Tally::Tally(pugi::xml_node node)
323328
if (has_energyout && i_nuc == -1) {
324329
fatal_error(fmt::format(
325330
"Error on tally {}: Cannot use a "
326-
"'nuclide_density' or 'temperature' derivative on a tally with an "
331+
"'nuclide_density' or 'temperature' derivative on a tally with "
332+
"an "
327333
"outgoing energy filter and 'total' nuclide rate. Instead, tally "
328334
"each nuclide in the material individually.",
329335
id_));
@@ -548,9 +554,9 @@ void Tally::add_filter(Filter* filter)
548554

549555
void Tally::set_strides()
550556
{
551-
// Set the strides. Filters are traversed in reverse so that the last filter
552-
// has the shortest stride in memory and the first filter has the longest
553-
// stride.
557+
// Set the strides. Filters are traversed in reverse so that the last
558+
// filter has the shortest stride in memory and the first filter has the
559+
// longest stride.
554560
auto n = filters_.size();
555561
strides_.resize(n, 0);
556562
int stride = 1;
@@ -606,7 +612,8 @@ void Tally::set_scores(const vector<std::string>& scores)
606612

607613
// Iterate over the given scores.
608614
for (auto score_str : scores) {
609-
// Make sure a delayed group filter wasn't used with an incompatible score.
615+
// Make sure a delayed group filter wasn't used with an incompatible
616+
// score.
610617
if (delayedgroup_filter_ != C_NONE) {
611618
if (score_str != "delayed-nu-fission" && score_str != "decay-rate")
612619
fatal_error("Cannot tally " + score_str + "with a delayedgroup filter");
@@ -1046,8 +1053,8 @@ void reduce_tally_results()
10461053
}
10471054
}
10481055

1049-
// Note that global tallies are *always* reduced even when no_reduce option is
1050-
// on.
1056+
// Note that global tallies are *always* reduced even when no_reduce option
1057+
// is on.
10511058

10521059
// Get view of global tally values
10531060
auto& gt = simulation::global_tallies;
@@ -1126,21 +1133,59 @@ void accumulate_tallies()
11261133
}
11271134
}
11281135

1136+
double distance_to_time_boundary(double time, double speed)
1137+
{
1138+
if (model::time_grid.empty()) {
1139+
return INFTY;
1140+
} else if (time >= model::time_grid.back()) {
1141+
return INFTY;
1142+
} else {
1143+
double next_time =
1144+
*std::upper_bound(model::time_grid.begin(), model::time_grid.end(), time);
1145+
return (next_time - time) * speed;
1146+
}
1147+
}
1148+
1149+
//! Add new points to the global time grid
1150+
//
1151+
//! \param grid Vector of new time points to add
1152+
void add_to_time_grid(vector<double> grid)
1153+
{
1154+
if (grid.empty())
1155+
return;
1156+
1157+
// Create new vector with enough space to hold old and new grid points
1158+
vector<double> merged;
1159+
merged.reserve(model::time_grid.size() + grid.size());
1160+
1161+
// Merge and remove duplicates
1162+
std::set_union(model::time_grid.begin(), model::time_grid.end(), grid.begin(),
1163+
grid.end(), std::back_inserter(merged));
1164+
1165+
// Swap in the new grid
1166+
model::time_grid.swap(merged);
1167+
}
1168+
11291169
void setup_active_tallies()
11301170
{
11311171
model::active_tallies.clear();
11321172
model::active_analog_tallies.clear();
11331173
model::active_tracklength_tallies.clear();
1174+
model::active_timed_tracklength_tallies.clear();
11341175
model::active_collision_tallies.clear();
11351176
model::active_meshsurf_tallies.clear();
11361177
model::active_surface_tallies.clear();
11371178
model::active_pulse_height_tallies.clear();
1179+
model::time_grid.clear();
11381180

11391181
for (auto i = 0; i < model::tallies.size(); ++i) {
11401182
const auto& tally {*model::tallies[i]};
11411183

11421184
if (tally.active_) {
11431185
model::active_tallies.push_back(i);
1186+
bool mesh_present = (tally.get_filter<MeshFilter>() ||
1187+
tally.get_filter<MeshMaterialFilter>());
1188+
auto time_filter = tally.get_filter<TimeFilter>();
11441189
switch (tally.type_) {
11451190

11461191
case TallyType::VOLUME:
@@ -1149,7 +1194,12 @@ void setup_active_tallies()
11491194
model::active_analog_tallies.push_back(i);
11501195
break;
11511196
case TallyEstimator::TRACKLENGTH:
1152-
model::active_tracklength_tallies.push_back(i);
1197+
if (time_filter && mesh_present) {
1198+
model::active_timed_tracklength_tallies.push_back(i);
1199+
add_to_time_grid(time_filter->bins());
1200+
} else {
1201+
model::active_tracklength_tallies.push_back(i);
1202+
}
11531203
break;
11541204
case TallyEstimator::COLLISION:
11551205
model::active_collision_tallies.push_back(i);
@@ -1188,10 +1238,12 @@ void free_memory_tally()
11881238
model::active_tallies.clear();
11891239
model::active_analog_tallies.clear();
11901240
model::active_tracklength_tallies.clear();
1241+
model::active_timed_tracklength_tallies.clear();
11911242
model::active_collision_tallies.clear();
11921243
model::active_meshsurf_tallies.clear();
11931244
model::active_surface_tallies.clear();
11941245
model::active_pulse_height_tallies.clear();
1246+
model::time_grid.clear();
11951247

11961248
model::tally_map.clear();
11971249
}
@@ -1530,8 +1582,8 @@ extern "C" int openmc_tally_get_n_realizations(int32_t index, int32_t* n)
15301582
return 0;
15311583
}
15321584

1533-
//! \brief Returns a pointer to a tally results array along with its shape. This
1534-
//! allows a user to obtain in-memory tally results from Python directly.
1585+
//! \brief Returns a pointer to a tally results array along with its shape.
1586+
//! This allows a user to obtain in-memory tally results from Python directly.
15351587
extern "C" int openmc_tally_results(
15361588
int32_t index, double** results, size_t* shape)
15371589
{

src/tallies/tally_scoring.cpp

Lines changed: 54 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2405,15 +2405,13 @@ void score_analog_tally_mg(Particle& p)
24052405
match.bins_present_ = false;
24062406
}
24072407

2408-
void score_tracklength_tally(Particle& p, double distance)
2408+
void score_tracklength_tally_general(
2409+
Particle& p, double flux, const vector<int>& tallies)
24092410
{
2410-
// Determine the tracklength estimate of the flux
2411-
double flux = p.wgt() * distance;
2412-
24132411
// Set 'none' value for log union grid index
24142412
int i_log_union = C_NONE;
24152413

2416-
for (auto i_tally : model::active_tracklength_tallies) {
2414+
for (auto i_tally : tallies) {
24172415
const Tally& tally {*model::tallies[i_tally]};
24182416

24192417
// Initialize an iterator over valid filter bin combinations. If there are
@@ -2482,6 +2480,57 @@ void score_tracklength_tally(Particle& p, double distance)
24822480
match.bins_present_ = false;
24832481
}
24842482

2483+
void score_timed_tracklength_tally(Particle& p, double total_distance)
2484+
{
2485+
double speed = p.speed();
2486+
double total_dt = total_distance / speed;
2487+
2488+
// save particle last state
2489+
auto time_last = p.time_last();
2490+
auto r_last = p.r_last();
2491+
2492+
// move particle back
2493+
p.move_distance(-total_distance);
2494+
p.time() -= total_dt;
2495+
p.lifetime() -= total_dt;
2496+
2497+
double distance_traveled = 0.0;
2498+
while (distance_traveled < total_distance) {
2499+
2500+
double distance = std::min(distance_to_time_boundary(p.time(), speed),
2501+
total_distance - distance_traveled);
2502+
double dt = distance / speed;
2503+
2504+
// Save particle last state for tracklength tallies
2505+
p.time_last() = p.time();
2506+
p.r_last() = p.r();
2507+
2508+
// Advance particle in space and time
2509+
p.move_distance(distance);
2510+
p.time() += dt;
2511+
p.lifetime() += dt;
2512+
2513+
// Determine the tracklength estimate of the flux
2514+
double flux = p.wgt() * distance;
2515+
2516+
score_tracklength_tally_general(
2517+
p, flux, model::active_timed_tracklength_tallies);
2518+
distance_traveled += distance;
2519+
}
2520+
2521+
p.time_last() = time_last;
2522+
p.r_last() = r_last;
2523+
}
2524+
2525+
void score_tracklength_tally(Particle& p, double distance)
2526+
{
2527+
2528+
// Determine the tracklength estimate of the flux
2529+
double flux = p.wgt() * distance;
2530+
2531+
score_tracklength_tally_general(p, flux, model::active_tracklength_tallies);
2532+
}
2533+
24852534
void score_collision_tally(Particle& p)
24862535
{
24872536
// Determine the collision estimate of the flux

0 commit comments

Comments
 (0)