28
28
#include " openmc/tallies/filter_legendre.h"
29
29
#include " openmc/tallies/filter_mesh.h"
30
30
#include " openmc/tallies/filter_meshborn.h"
31
+ #include " openmc/tallies/filter_meshmaterial.h"
31
32
#include " openmc/tallies/filter_meshsurface.h"
32
33
#include " openmc/tallies/filter_particle.h"
33
34
#include " openmc/tallies/filter_sph_harm.h"
34
35
#include " openmc/tallies/filter_surface.h"
36
+ #include " openmc/tallies/filter_time.h"
35
37
#include " openmc/xml_interface.h"
36
38
37
39
#include " xtensor/xadapt.hpp"
38
40
#include " xtensor/xbuilder.hpp" // for empty_like
39
41
#include " xtensor/xview.hpp"
40
42
#include < fmt/core.h>
41
43
42
- #include < algorithm> // for max
44
+ #include < algorithm> // for max, set_union
43
45
#include < cassert>
44
- #include < cstddef> // for size_t
46
+ #include < cstddef> // for size_t
47
+ #include < iterator> // for back_inserter
45
48
#include < string>
46
49
47
50
namespace openmc {
@@ -57,11 +60,13 @@ vector<unique_ptr<Tally>> tallies;
57
60
vector<int > active_tallies;
58
61
vector<int > active_analog_tallies;
59
62
vector<int > active_tracklength_tallies;
63
+ vector<int > active_timed_tracklength_tallies;
60
64
vector<int > active_collision_tallies;
61
65
vector<int > active_meshsurf_tallies;
62
66
vector<int > active_surface_tallies;
63
67
vector<int > active_pulse_height_tallies;
64
68
vector<int > pulse_height_cells;
69
+ vector<double > time_grid;
65
70
} // namespace model
66
71
67
72
namespace simulation {
@@ -248,8 +253,8 @@ Tally::Tally(pugi::xml_node node)
248
253
for (int score : scores_) {
249
254
switch (score) {
250
255
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." );
253
258
break ;
254
259
}
255
260
}
@@ -323,7 +328,8 @@ Tally::Tally(pugi::xml_node node)
323
328
if (has_energyout && i_nuc == -1 ) {
324
329
fatal_error (fmt::format (
325
330
" 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 "
327
333
" outgoing energy filter and 'total' nuclide rate. Instead, tally "
328
334
" each nuclide in the material individually." ,
329
335
id_));
@@ -548,9 +554,9 @@ void Tally::add_filter(Filter* filter)
548
554
549
555
void Tally::set_strides ()
550
556
{
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.
554
560
auto n = filters_.size ();
555
561
strides_.resize (n, 0 );
556
562
int stride = 1 ;
@@ -606,7 +612,8 @@ void Tally::set_scores(const vector<std::string>& scores)
606
612
607
613
// Iterate over the given scores.
608
614
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.
610
617
if (delayedgroup_filter_ != C_NONE) {
611
618
if (score_str != " delayed-nu-fission" && score_str != " decay-rate" )
612
619
fatal_error (" Cannot tally " + score_str + " with a delayedgroup filter" );
@@ -1046,8 +1053,8 @@ void reduce_tally_results()
1046
1053
}
1047
1054
}
1048
1055
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.
1051
1058
1052
1059
// Get view of global tally values
1053
1060
auto & gt = simulation::global_tallies;
@@ -1126,21 +1133,59 @@ void accumulate_tallies()
1126
1133
}
1127
1134
}
1128
1135
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
+
1129
1169
void setup_active_tallies ()
1130
1170
{
1131
1171
model::active_tallies.clear ();
1132
1172
model::active_analog_tallies.clear ();
1133
1173
model::active_tracklength_tallies.clear ();
1174
+ model::active_timed_tracklength_tallies.clear ();
1134
1175
model::active_collision_tallies.clear ();
1135
1176
model::active_meshsurf_tallies.clear ();
1136
1177
model::active_surface_tallies.clear ();
1137
1178
model::active_pulse_height_tallies.clear ();
1179
+ model::time_grid.clear ();
1138
1180
1139
1181
for (auto i = 0 ; i < model::tallies.size (); ++i) {
1140
1182
const auto & tally {*model::tallies[i]};
1141
1183
1142
1184
if (tally.active_ ) {
1143
1185
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>();
1144
1189
switch (tally.type_ ) {
1145
1190
1146
1191
case TallyType::VOLUME:
@@ -1149,7 +1194,12 @@ void setup_active_tallies()
1149
1194
model::active_analog_tallies.push_back (i);
1150
1195
break ;
1151
1196
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
+ }
1153
1203
break ;
1154
1204
case TallyEstimator::COLLISION:
1155
1205
model::active_collision_tallies.push_back (i);
@@ -1188,10 +1238,12 @@ void free_memory_tally()
1188
1238
model::active_tallies.clear ();
1189
1239
model::active_analog_tallies.clear ();
1190
1240
model::active_tracklength_tallies.clear ();
1241
+ model::active_timed_tracklength_tallies.clear ();
1191
1242
model::active_collision_tallies.clear ();
1192
1243
model::active_meshsurf_tallies.clear ();
1193
1244
model::active_surface_tallies.clear ();
1194
1245
model::active_pulse_height_tallies.clear ();
1246
+ model::time_grid.clear ();
1195
1247
1196
1248
model::tally_map.clear ();
1197
1249
}
@@ -1530,8 +1582,8 @@ extern "C" int openmc_tally_get_n_realizations(int32_t index, int32_t* n)
1530
1582
return 0 ;
1531
1583
}
1532
1584
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.
1535
1587
extern " C" int openmc_tally_results (
1536
1588
int32_t index, double ** results, size_t * shape)
1537
1589
{
0 commit comments