• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

openmc-dev / openmc / 13591584831

28 Feb 2025 03:46PM UTC coverage: 85.051% (+0.3%) from 84.722%
13591584831

Pull #3067

github

web-flow
Merge 08055e996 into c26fde666
Pull Request #3067: Implement user-configurable random number stride

36 of 44 new or added lines in 8 files covered. (81.82%)

3588 existing lines in 111 files now uncovered.

51062 of 60037 relevant lines covered (85.05%)

32650986.73 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

87.45
/src/random_ray/random_ray_simulation.cpp
1
#include "openmc/random_ray/random_ray_simulation.h"
2

3
#include "openmc/eigenvalue.h"
4
#include "openmc/geometry.h"
5
#include "openmc/message_passing.h"
6
#include "openmc/mgxs_interface.h"
7
#include "openmc/output.h"
8
#include "openmc/plot.h"
9
#include "openmc/random_ray/flat_source_domain.h"
10
#include "openmc/random_ray/random_ray.h"
11
#include "openmc/simulation.h"
12
#include "openmc/source.h"
13
#include "openmc/tallies/filter.h"
14
#include "openmc/tallies/tally.h"
15
#include "openmc/tallies/tally_scoring.h"
16
#include "openmc/timer.h"
17

18
namespace openmc {
19

20
//==============================================================================
21
// Non-member functions
22
//==============================================================================
23

24
void openmc_run_random_ray()
425✔
25
{
26
  //////////////////////////////////////////////////////////
27
  // Run forward simulation
28
  //////////////////////////////////////////////////////////
29

30
  // Check if adjoint calculation is needed. If it is, we will run the forward
31
  // calculation first and then the adjoint calculation later.
32
  bool adjoint_needed = FlatSourceDomain::adjoint_;
425✔
33

34
  // Configure the domain for forward simulation
35
  FlatSourceDomain::adjoint_ = false;
425✔
36

37
  // If we're going to do an adjoint simulation afterwards, report that this is
38
  // the initial forward flux solve.
39
  if (adjoint_needed && mpi::master)
425✔
40
    header("FORWARD FLUX SOLVE", 3);
36✔
41

42
  // Initialize OpenMC general data structures
43
  openmc_simulation_init();
425✔
44

45
  // Validate that inputs meet requirements for random ray mode
46
  if (mpi::master)
425✔
47
    validate_random_ray_inputs();
300✔
48

49
  // Declare forward flux so that it can be saved for later adjoint simulation
50
  vector<double> forward_flux;
425✔
51

52
  {
53
    // Initialize Random Ray Simulation Object
54
    RandomRaySimulation sim;
425✔
55

56
    // Initialize fixed sources, if present
57
    sim.prepare_fixed_sources();
425✔
58

59
    // Begin main simulation timer
60
    simulation::time_total.start();
425✔
61

62
    // Execute random ray simulation
63
    sim.simulate();
425✔
64

65
    // End main simulation timer
66
    simulation::time_total.stop();
425✔
67

68
    // Normalize and save the final forward flux
69
    sim.domain()->serialize_final_fluxes(forward_flux);
425✔
70

71
    double source_normalization_factor =
72
      sim.domain()->compute_fixed_source_normalization_factor() /
425✔
73
      (settings::n_batches - settings::n_inactive);
425✔
74

75
#pragma omp parallel for
225✔
76
    for (uint64_t i = 0; i < forward_flux.size(); i++) {
346,600✔
77
      forward_flux[i] *= source_normalization_factor;
346,400✔
78
    }
79

80
    // Finalize OpenMC
81
    openmc_simulation_finalize();
425✔
82

83
    // Reduce variables across MPI ranks
84
    sim.reduce_simulation_statistics();
425✔
85

86
    // Output all simulation results
87
    sim.output_simulation_results();
425✔
88
  }
425✔
89

90
  //////////////////////////////////////////////////////////
91
  // Run adjoint simulation (if enabled)
92
  //////////////////////////////////////////////////////////
93

94
  if (adjoint_needed) {
425✔
95
    reset_timers();
51✔
96

97
    // Configure the domain for adjoint simulation
98
    FlatSourceDomain::adjoint_ = true;
51✔
99

100
    if (mpi::master)
51✔
101
      header("ADJOINT FLUX SOLVE", 3);
36✔
102

103
    // Initialize OpenMC general data structures
104
    openmc_simulation_init();
51✔
105

106
    // Initialize Random Ray Simulation Object
107
    RandomRaySimulation adjoint_sim;
51✔
108

109
    // Initialize adjoint fixed sources, if present
110
    adjoint_sim.prepare_fixed_sources_adjoint(forward_flux);
51✔
111

112
    // Transpose scattering matrix
113
    adjoint_sim.domain()->transpose_scattering_matrix();
51✔
114

115
    // Swap nu_sigma_f and chi
116
    adjoint_sim.domain()->nu_sigma_f_.swap(adjoint_sim.domain()->chi_);
51✔
117

118
    // Begin main simulation timer
119
    simulation::time_total.start();
51✔
120

121
    // Execute random ray simulation
122
    adjoint_sim.simulate();
51✔
123

124
    // End main simulation timer
125
    simulation::time_total.stop();
51✔
126

127
    // Finalize OpenMC
128
    openmc_simulation_finalize();
51✔
129

130
    // Reduce variables across MPI ranks
131
    adjoint_sim.reduce_simulation_statistics();
51✔
132

133
    // Output all simulation results
134
    adjoint_sim.output_simulation_results();
51✔
135
  }
51✔
136
}
425✔
137

138
// Enforces restrictions on inputs in random ray mode.  While there are
139
// many features that don't make sense in random ray mode, and are therefore
140
// unsupported, we limit our testing/enforcement operations only to inputs
141
// that may cause erroneous/misleading output or crashes from the solver.
142
void validate_random_ray_inputs()
300✔
143
{
144
  // Validate tallies
145
  ///////////////////////////////////////////////////////////////////
146
  for (auto& tally : model::tallies) {
1,008✔
147

148
    // Validate score types
149
    for (auto score_bin : tally->scores_) {
1,584✔
150
      switch (score_bin) {
876✔
151
      case SCORE_FLUX:
876✔
152
      case SCORE_TOTAL:
153
      case SCORE_FISSION:
154
      case SCORE_NU_FISSION:
155
      case SCORE_EVENTS:
156
        break;
876✔
UNCOV
157
      default:
×
UNCOV
158
        fatal_error(
×
159
          "Invalid score specified. Only flux, total, fission, nu-fission, and "
160
          "event scores are supported in random ray mode.");
161
      }
162
    }
163

164
    // Validate filter types
165
    for (auto f : tally->filters()) {
1,524✔
166
      auto& filter = *model::tally_filters[f];
816✔
167

168
      switch (filter.type()) {
816✔
169
      case FilterType::CELL:
816✔
170
      case FilterType::CELL_INSTANCE:
171
      case FilterType::DISTRIBCELL:
172
      case FilterType::ENERGY:
173
      case FilterType::MATERIAL:
174
      case FilterType::MESH:
175
      case FilterType::UNIVERSE:
176
      case FilterType::PARTICLE:
177
        break;
816✔
UNCOV
178
      default:
×
179
        fatal_error("Invalid filter specified. Only cell, cell_instance, "
×
180
                    "distribcell, energy, material, mesh, and universe filters "
181
                    "are supported in random ray mode.");
182
      }
183
    }
184
  }
185

186
  // Validate MGXS data
187
  ///////////////////////////////////////////////////////////////////
188
  for (auto& material : data::mg.macro_xs_) {
1,092✔
189
    if (!material.is_isotropic) {
792✔
UNCOV
190
      fatal_error("Anisotropic MGXS detected. Only isotropic XS data sets "
×
191
                  "supported in random ray mode.");
192
    }
193
    if (material.get_xsdata().size() > 1) {
792✔
UNCOV
194
      fatal_error("Non-isothermal MGXS detected. Only isothermal XS data sets "
×
195
                  "supported in random ray mode.");
196
    }
197
    for (int g = 0; g < data::mg.num_energy_groups_; g++) {
2,592✔
198
      if (material.exists_in_model) {
1,800✔
199
        // Temperature and angle indices, if using multiple temperature
200
        // data sets and/or anisotropic data sets.
201
        // TODO: Currently assumes we are only using single temp/single angle
202
        // data.
203
        const int t = 0;
1,752✔
204
        const int a = 0;
1,752✔
205
        double sigma_t =
206
          material.get_xs(MgxsType::TOTAL, g, NULL, NULL, NULL, t, a);
1,752✔
207
        if (sigma_t <= 0.0) {
1,752✔
208
          fatal_error("No zero or negative total macroscopic cross sections "
×
209
                      "allowed in random ray mode. If the intention is to make "
210
                      "a void material, use a cell fill of 'None' instead.");
211
        }
212
      }
213
    }
214
  }
215

216
  // Validate ray source
217
  ///////////////////////////////////////////////////////////////////
218

219
  // Check for independent source
220
  IndependentSource* is =
221
    dynamic_cast<IndependentSource*>(RandomRay::ray_source_.get());
300✔
222
  if (!is) {
300✔
UNCOV
223
    fatal_error("Invalid ray source definition. Ray source must provided and "
×
224
                "be of type IndependentSource.");
225
  }
226

227
  // Check for box source
228
  SpatialDistribution* space_dist = is->space();
300✔
229
  SpatialBox* sb = dynamic_cast<SpatialBox*>(space_dist);
300✔
230
  if (!sb) {
300✔
UNCOV
231
    fatal_error(
×
232
      "Invalid ray source definition -- only box sources are allowed.");
233
  }
234

235
  // Check that box source is not restricted to fissionable areas
236
  if (sb->only_fissionable()) {
300✔
UNCOV
237
    fatal_error(
×
238
      "Invalid ray source definition -- fissionable spatial distribution "
239
      "not allowed.");
240
  }
241

242
  // Check for isotropic source
243
  UnitSphereDistribution* angle_dist = is->angle();
300✔
244
  Isotropic* id = dynamic_cast<Isotropic*>(angle_dist);
300✔
245
  if (!id) {
300✔
UNCOV
246
    fatal_error("Invalid ray source definition -- only isotropic sources are "
×
247
                "allowed.");
248
  }
249

250
  // Validate external sources
251
  ///////////////////////////////////////////////////////////////////
252
  if (settings::run_mode == RunMode::FIXED_SOURCE) {
300✔
253
    if (model::external_sources.size() < 1) {
228✔
UNCOV
254
      fatal_error("Must provide a particle source (in addition to ray source) "
×
255
                  "in fixed source random ray mode.");
256
    }
257

258
    for (int i = 0; i < model::external_sources.size(); i++) {
456✔
259
      Source* s = model::external_sources[i].get();
228✔
260

261
      // Check for independent source
262
      IndependentSource* is = dynamic_cast<IndependentSource*>(s);
228✔
263

264
      if (!is) {
228✔
UNCOV
265
        fatal_error(
×
266
          "Only IndependentSource external source types are allowed in "
267
          "random ray mode");
268
      }
269

270
      // Check for isotropic source
271
      UnitSphereDistribution* angle_dist = is->angle();
228✔
272
      Isotropic* id = dynamic_cast<Isotropic*>(angle_dist);
228✔
273
      if (!id) {
228✔
UNCOV
274
        fatal_error(
×
275
          "Invalid source definition -- only isotropic external sources are "
276
          "allowed in random ray mode.");
277
      }
278

279
      // Validate that a domain ID was specified
280
      if (is->domain_ids().size() == 0) {
228✔
UNCOV
281
        fatal_error("Fixed sources must be specified by domain "
×
282
                    "id (cell, material, or universe) in random ray mode.");
283
      }
284

285
      // Check that a discrete energy distribution was used
286
      Distribution* d = is->energy();
228✔
287
      Discrete* dd = dynamic_cast<Discrete*>(d);
228✔
288
      if (!dd) {
228✔
UNCOV
289
        fatal_error(
×
290
          "Only discrete (multigroup) energy distributions are allowed for "
291
          "external sources in random ray mode.");
292
      }
293
    }
294
  }
295

296
  // Validate plotting files
297
  ///////////////////////////////////////////////////////////////////
298
  for (int p = 0; p < model::plots.size(); p++) {
300✔
299

300
    // Get handle to OpenMC plot object
UNCOV
301
    Plot* openmc_plot = dynamic_cast<Plot*>(model::plots[p].get());
×
302

303
    // Random ray plots only support voxel plots
UNCOV
304
    if (!openmc_plot) {
×
UNCOV
305
      warning(fmt::format(
×
306
        "Plot {} will not be used for end of simulation data plotting -- only "
307
        "voxel plotting is allowed in random ray mode.",
308
        p));
UNCOV
309
      continue;
×
UNCOV
310
    } else if (openmc_plot->type_ != Plot::PlotType::voxel) {
×
UNCOV
311
      warning(fmt::format(
×
312
        "Plot {} will not be used for end of simulation data plotting -- only "
313
        "voxel plotting is allowed in random ray mode.",
314
        p));
UNCOV
315
      continue;
×
316
    }
317
  }
318

319
  // Warn about slow MPI domain replication, if detected
320
  ///////////////////////////////////////////////////////////////////
321
#ifdef OPENMC_MPI
322
  if (mpi::n_procs > 1) {
125✔
323
    warning(
125✔
324
      "Domain replication in random ray is supported, but suffers from poor "
325
      "scaling of source all-reduce operations. Performance may severely "
326
      "degrade beyond just a few MPI ranks. Domain decomposition may be "
327
      "implemented in the future to provide efficient scaling.");
328
  }
329
#endif
330
}
300✔
331

332
//==============================================================================
333
// RandomRaySimulation implementation
334
//==============================================================================
335

336
RandomRaySimulation::RandomRaySimulation()
476✔
337
  : negroups_(data::mg.num_energy_groups_)
476✔
338
{
339
  // There are no source sites in random ray mode, so be sure to disable to
340
  // ensure we don't attempt to write source sites to statepoint
341
  settings::source_write = false;
476✔
342

343
  // Random ray mode does not have an inner loop over generations within a
344
  // batch, so set the current gen to 1
345
  simulation::current_gen = 1;
476✔
346

347
  switch (RandomRay::source_shape_) {
476✔
348
  case RandomRaySourceShape::FLAT:
323✔
349
    domain_ = make_unique<FlatSourceDomain>();
323✔
350
    break;
323✔
351
  case RandomRaySourceShape::LINEAR:
153✔
352
  case RandomRaySourceShape::LINEAR_XY:
353
    domain_ = make_unique<LinearSourceDomain>();
153✔
354
    break;
153✔
UNCOV
355
  default:
×
UNCOV
356
    fatal_error("Unknown random ray source shape");
×
357
  }
358

359
  // Convert OpenMC native MGXS into a more efficient format
360
  // internal to the random ray solver
361
  domain_->flatten_xs();
476✔
362
}
476✔
363

364
void RandomRaySimulation::prepare_fixed_sources()
425✔
365
{
366
  if (settings::run_mode == RunMode::FIXED_SOURCE) {
425✔
367
    // Transfer external source user inputs onto random ray source regions
368
    domain_->convert_external_sources();
323✔
369
    domain_->count_external_source_regions();
323✔
370
  }
371
}
425✔
372

373
void RandomRaySimulation::prepare_fixed_sources_adjoint(
51✔
374
  vector<double>& forward_flux)
375
{
376
  if (settings::run_mode == RunMode::FIXED_SOURCE) {
51✔
377
    domain_->set_adjoint_sources(forward_flux);
34✔
378
  }
379
}
51✔
380

381
void RandomRaySimulation::simulate()
476✔
382
{
383
  // Random ray power iteration loop
384
  while (simulation::current_batch < settings::n_batches) {
13,736✔
385

386
    // Initialize the current batch
387
    initialize_batch();
13,260✔
388
    initialize_generation();
13,260✔
389

390
    // Reset total starting particle weight used for normalizing tallies
391
    simulation::total_weight = 1.0;
13,260✔
392

393
    // Update source term (scattering + fission)
394
    domain_->update_neutron_source(k_eff_);
13,260✔
395

396
    // Reset scalar fluxes, iteration volume tallies, and region hit flags to
397
    // zero
398
    domain_->batch_reset();
13,260✔
399

400
    // Start timer for transport
401
    simulation::time_transport.start();
13,260✔
402

403
// Transport sweep over all random rays for the iteration
404
#pragma omp parallel for schedule(dynamic)                                     \
7,020✔
405
  reduction(+ : total_geometric_intersections_)
7,020✔
406
    for (int i = 0; i < simulation::work_per_rank; i++) {
394,440✔
407
      RandomRay ray(i, domain_.get());
388,200✔
408
      total_geometric_intersections_ +=
388,200✔
409
        ray.transport_history_based_single_ray();
388,200✔
410
    }
388,200✔
411

412
    simulation::time_transport.stop();
13,260✔
413

414
    // If using multiple MPI ranks, perform all reduce on all transport results
415
    domain_->all_reduce_replicated_source_regions();
13,260✔
416

417
    // Normalize scalar flux and update volumes
418
    domain_->normalize_scalar_flux_and_volumes(
13,260✔
419
      settings::n_particles * RandomRay::distance_active_);
420

421
    // Add source to scalar flux, compute number of FSR hits
422
    int64_t n_hits = domain_->add_source_to_scalar_flux();
13,260✔
423

424
    if (settings::run_mode == RunMode::EIGENVALUE) {
13,260✔
425
      // Compute random ray k-eff
426
      k_eff_ = domain_->compute_k_eff(k_eff_);
2,210✔
427

428
      // Store random ray k-eff into OpenMC's native k-eff variable
429
      global_tally_tracklength = k_eff_;
2,210✔
430
    }
431

432
    // Execute all tallying tasks, if this is an active batch
433
    if (simulation::current_batch > settings::n_inactive) {
13,260✔
434

435
      // Add this iteration's scalar flux estimate to final accumulated estimate
436
      domain_->accumulate_iteration_flux();
5,355✔
437

438
      if (mpi::master) {
5,355✔
439
        // Generate mapping between source regions and tallies
440
        if (!domain_->mapped_all_tallies_) {
3,780✔
441
          domain_->convert_source_regions_to_tallies();
336✔
442
        }
443

444
        // Use above mapping to contribute FSR flux data to appropriate tallies
445
        domain_->random_ray_tally();
3,780✔
446
      }
447
    }
448

449
    // Set phi_old = phi_new
450
    domain_->flux_swap();
13,260✔
451

452
    // Check for any obvious insabilities/nans/infs
453
    instability_check(n_hits, k_eff_, avg_miss_rate_);
13,260✔
454

455
    // Finalize the current batch
456
    finalize_generation();
13,260✔
457
    finalize_batch();
13,260✔
458
  } // End random ray power iteration loop
459
}
476✔
460

461
void RandomRaySimulation::reduce_simulation_statistics()
476✔
462
{
463
  // Reduce number of intersections
464
#ifdef OPENMC_MPI
465
  if (mpi::n_procs > 1) {
280✔
466
    uint64_t total_geometric_intersections_reduced = 0;
280✔
467
    MPI_Reduce(&total_geometric_intersections_,
280✔
468
      &total_geometric_intersections_reduced, 1, MPI_UNSIGNED_LONG, MPI_SUM, 0,
469
      mpi::intracomm);
470
    total_geometric_intersections_ = total_geometric_intersections_reduced;
280✔
471
  }
472
#endif
473
}
476✔
474

475
void RandomRaySimulation::output_simulation_results() const
476✔
476
{
477
  // Print random ray results
478
  if (mpi::master) {
476✔
479
    print_results_random_ray(total_geometric_intersections_,
672✔
480
      avg_miss_rate_ / settings::n_batches, negroups_,
336✔
481
      domain_->n_source_regions_, domain_->n_external_source_regions_);
336✔
482
    if (model::plots.size() > 0) {
336✔
UNCOV
483
      domain_->output_to_vtk();
×
484
    }
485
  }
486
}
476✔
487

488
// Apply a few sanity checks to catch obvious cases of numerical instability.
489
// Instability typically only occurs if ray density is extremely low.
490
void RandomRaySimulation::instability_check(
13,260✔
491
  int64_t n_hits, double k_eff, double& avg_miss_rate) const
492
{
493
  double percent_missed = ((domain_->n_source_regions_ - n_hits) /
13,260✔
494
                            static_cast<double>(domain_->n_source_regions_)) *
13,260✔
495
                          100.0;
13,260✔
496
  avg_miss_rate += percent_missed;
13,260✔
497

498
  if (mpi::master) {
13,260✔
499
    if (percent_missed > 10.0) {
9,360✔
UNCOV
500
      warning(fmt::format(
×
501
        "Very high FSR miss rate detected ({:.3f}%). Instability may occur. "
502
        "Increase ray density by adding more rays and/or active distance.",
503
        percent_missed));
504
    } else if (percent_missed > 1.0) {
9,360✔
UNCOV
505
      warning(
×
UNCOV
506
        fmt::format("Elevated FSR miss rate detected ({:.3f}%). Increasing "
×
507
                    "ray density by adding more rays and/or active "
508
                    "distance may improve simulation efficiency.",
509
          percent_missed));
510
    }
511

512
    if (k_eff > 10.0 || k_eff < 0.01 || !(std::isfinite(k_eff))) {
9,360✔
UNCOV
513
      fatal_error("Instability detected");
×
514
    }
515
  }
516
}
13,260✔
517

518
// Print random ray simulation results
519
void RandomRaySimulation::print_results_random_ray(
336✔
520
  uint64_t total_geometric_intersections, double avg_miss_rate, int negroups,
521
  int64_t n_source_regions, int64_t n_external_source_regions) const
522
{
523
  using namespace simulation;
524

525
  if (settings::verbosity >= 6) {
336✔
526
    double total_integrations = total_geometric_intersections * negroups;
336✔
527
    double time_per_integration =
528
      simulation::time_transport.elapsed() / total_integrations;
336✔
529
    double misc_time = time_total.elapsed() - time_update_src.elapsed() -
336✔
530
                       time_transport.elapsed() - time_tallies.elapsed() -
336✔
531
                       time_bank_sendrecv.elapsed();
336✔
532

533
    header("Simulation Statistics", 4);
336✔
534
    fmt::print(
336✔
535
      " Total Iterations                  = {}\n", settings::n_batches);
536
    fmt::print(" Flat Source Regions (FSRs)        = {}\n", n_source_regions);
336✔
537
    fmt::print(
280✔
538
      " FSRs Containing External Sources  = {}\n", n_external_source_regions);
539
    fmt::print(" Total Geometric Intersections     = {:.4e}\n",
280✔
540
      static_cast<double>(total_geometric_intersections));
336✔
541
    fmt::print("   Avg per Iteration               = {:.4e}\n",
280✔
542
      static_cast<double>(total_geometric_intersections) / settings::n_batches);
336✔
543
    fmt::print("   Avg per Iteration per FSR       = {:.2f}\n",
280✔
544
      static_cast<double>(total_geometric_intersections) /
336✔
545
        static_cast<double>(settings::n_batches) / n_source_regions);
672✔
546
    fmt::print(" Avg FSR Miss Rate per Iteration   = {:.4f}%\n", avg_miss_rate);
336✔
547
    fmt::print(" Energy Groups                     = {}\n", negroups);
336✔
548
    fmt::print(
280✔
549
      " Total Integrations                = {:.4e}\n", total_integrations);
550
    fmt::print("   Avg per Iteration               = {:.4e}\n",
280✔
551
      total_integrations / settings::n_batches);
336✔
552

553
    std::string estimator;
336✔
554
    switch (domain_->volume_estimator_) {
336✔
555
    case RandomRayVolumeEstimator::SIMULATION_AVERAGED:
24✔
556
      estimator = "Simulation Averaged";
24✔
557
      break;
24✔
558
    case RandomRayVolumeEstimator::NAIVE:
72✔
559
      estimator = "Naive";
72✔
560
      break;
72✔
561
    case RandomRayVolumeEstimator::HYBRID:
240✔
562
      estimator = "Hybrid";
240✔
563
      break;
240✔
UNCOV
564
    default:
×
UNCOV
565
      fatal_error("Invalid volume estimator type");
×
566
    }
567
    fmt::print(" Volume Estimator Type             = {}\n", estimator);
280✔
568

569
    std::string adjoint_true = (FlatSourceDomain::adjoint_) ? "ON" : "OFF";
1,008✔
570
    fmt::print(" Adjoint Flux Mode                 = {}\n", adjoint_true);
280✔
571

572
    header("Timing Statistics", 4);
336✔
573
    show_time("Total time for initialization", time_initialize.elapsed());
336✔
574
    show_time("Reading cross sections", time_read_xs.elapsed(), 1);
336✔
575
    show_time("Total simulation time", time_total.elapsed());
336✔
576
    show_time("Transport sweep only", time_transport.elapsed(), 1);
336✔
577
    show_time("Source update only", time_update_src.elapsed(), 1);
336✔
578
    show_time("Tally conversion only", time_tallies.elapsed(), 1);
336✔
579
    show_time("MPI source reductions only", time_bank_sendrecv.elapsed(), 1);
336✔
580
    show_time("Other iteration routines", misc_time, 1);
336✔
581
    if (settings::run_mode == RunMode::EIGENVALUE) {
336✔
582
      show_time("Time in inactive batches", time_inactive.elapsed());
84✔
583
    }
584
    show_time("Time in active batches", time_active.elapsed());
336✔
585
    show_time("Time writing statepoints", time_statepoint.elapsed());
336✔
586
    show_time("Total time for finalization", time_finalize.elapsed());
336✔
587
    show_time("Time per integration", time_per_integration);
336✔
588
  }
336✔
589

590
  if (settings::verbosity >= 4 && settings::run_mode == RunMode::EIGENVALUE) {
336✔
591
    header("Results", 4);
84✔
592
    fmt::print(" k-effective                       = {:.5f} +/- {:.5f}\n",
84✔
593
      simulation::keff, simulation::keff_std);
594
  }
595
}
336✔
596

597
} // namespace openmc
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc