LCOV - code coverage report
Current view: top level - src/base - OpenMCProblemBase.C (source / functions) Hit Total Coverage
Test: neams-th-coe/cardinal: faa471 Lines: 388 450 86.2 %
Date: 2026-08-05 13:00:46 Functions: 52 59 88.1 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /********************************************************************/
       2             : /*                  SOFTWARE COPYRIGHT NOTIFICATION                 */
       3             : /*                             Cardinal                             */
       4             : /*                                                                  */
       5             : /*                  (c) 2021 UChicago Argonne, LLC                  */
       6             : /*                        ALL RIGHTS RESERVED                       */
       7             : /*                                                                  */
       8             : /*                 Prepared by UChicago Argonne, LLC                */
       9             : /*               Under Contract No. DE-AC02-06CH11357               */
      10             : /*                With the U. S. Department of Energy               */
      11             : /*                                                                  */
      12             : /*             Prepared by Battelle Energy Alliance, LLC            */
      13             : /*               Under Contract No. DE-AC07-05ID14517               */
      14             : /*                With the U. S. Department of Energy               */
      15             : /*                                                                  */
      16             : /*                 See LICENSE for full restrictions                */
      17             : /********************************************************************/
      18             : 
      19             : #ifdef ENABLE_OPENMC_COUPLING
      20             : 
      21             : #include "OpenMCProblemBase.h"
      22             : 
      23             : #include "CardinalAppTypes.h"
      24             : #include "AddTallyAction.h"
      25             : #include "SetupMGXSAction.h"
      26             : #include "AddModelModifiersAction.h"
      27             : 
      28             : #include "OpenMCNuclideDensities.h"
      29             : #include "OpenMCDomainFilterEditor.h"
      30             : #include "OpenMCTallyEditor.h"
      31             : #include "OpenMCCellTransform.h"
      32             : #include "CriticalitySearchBase.h"
      33             : #include "ModelModifiersBase.h"
      34             : 
      35             : // For filtering \beta_eff by DNP group.
      36             : #include "openmc/tallies/filter_delayedgroup.h"
      37             : #include "openmc/random_lcg.h"
      38             : #include "openmc/mgxs_interface.h"
      39             : // For random ray settings.
      40             : #include "openmc/random_ray/random_ray.h"
      41             : 
      42             : InputParameters
      43        4761 : OpenMCProblemBase::validParams()
      44             : {
      45        4761 :   InputParameters params = CardinalProblem::validParams();
      46        9522 :   params.addParam<PostprocessorName>(
      47             :       "power", "Power (Watts) to normalize the OpenMC tallies; only used for k-eigenvalue mode");
      48        9522 :   params.addParam<PostprocessorName>(
      49             :       "source_strength",
      50             :       "Neutrons/second to normalize the OpenMC tallies; only used for fixed source mode");
      51        9522 :   params.addParam<bool>("verbose", false, "Whether to print diagnostic information");
      52             : 
      53        9522 :   params.addParam<MooseEnum>("tally_type", getTallyTypeEnum(), "Type of tally to use in OpenMC");
      54             : 
      55       14283 :   params.addRangeCheckedParam<Real>(
      56             :       "scaling",
      57        9522 :       1.0,
      58             :       "scaling > 0.0",
      59             :       "Scaling factor to apply to [Mesh] to get to units of centimeters that OpenMC expects; "
      60             :       "setting 'scaling = 100.0', for instance, indicates that the [Mesh] is in units of meters");
      61             : 
      62             :   // interfaces to directly set some OpenMC parameters
      63        9522 :   params.addRangeCheckedParam<unsigned int>(
      64             :       "openmc_verbosity",
      65             :       "openmc_verbosity >= 1 & openmc_verbosity <= 10",
      66             :       "OpenMC verbosity level; this overrides the setting in the XML files. Note that we cannot "
      67             :       "influence the verbosity of OpenMC's initialization routines, since these are run before "
      68             :       "Cardinal is initialized.");
      69        9522 :   params.addRangeCheckedParam<unsigned int>(
      70             :       "inactive_batches",
      71             :       "inactive_batches >= 0",
      72             :       "Number of inactive batches to run in OpenMC; this overrides the setting in the XML files.");
      73        9522 :   params.addParam<PostprocessorName>("particles",
      74             :                                      "Number of particles to run in each OpenMC batch; this "
      75             :                                      "overrides the setting in the XML files.");
      76        9522 :   params.addRangeCheckedParam<unsigned int>(
      77             :       "batches",
      78             :       "batches > 0",
      79             :       "Number of batches to run in OpenMC; this overrides the setting in the XML files.");
      80             : 
      81        9522 :   params.addParam<bool>("reuse_source",
      82        9522 :                         false,
      83             :                         "Whether to take the initial fission source "
      84             :                         "for interation n to be the converged source bank from iteration n-1");
      85        9522 :   params.addParam<bool>(
      86             :       "skip_statepoint",
      87        9522 :       false,
      88             :       "Whether to skip writing any statepoint files from OpenMC; this is a performance "
      89             :       "optimization for scenarios where you may not want the statepoint files anyways");
      90        9522 :   params.addParam<bool>(
      91             :       "reset_seed",
      92        9522 :       false,
      93             :       "Whether to reset OpenMC's seed to the initial starting seed before each OpenMC solve");
      94             : 
      95        9522 :   params.addParam<FileName>(
      96             :       "xml_directory", "./", "The directory in which to look for OpenMC XML files.");
      97             : 
      98             :   // Kinetics parameters.
      99        9522 :   params.addParam<bool>("calc_kinetics_params",
     100        9522 :                         false,
     101             :                         "Whether or not Cardinal should enable the calculation of kinetics "
     102             :                         "parameters (Lambda effective and beta effective).");
     103        9522 :   params.addParam<unsigned int>(
     104             :       "ifp_generations",
     105             :       openmc::DEFAULT_IFP_N_GENERATION,
     106             :       "The number of generations to use with the method of iterated fission probabilities.");
     107             : 
     108             :   // Random ray settings. These are only valid if Cardinal is running the random ray solver.
     109        9522 :   params.addRangeCheckedParam<Real>(
     110             :       "inactive_distance",
     111             :       "inactive_distance >= 0",
     112             :       "The inactive length (distance a ray travels before beginning to accumulate tallies) used "
     113             :       "for random ray; this overrides the setting in the XML files.");
     114        9522 :   params.addRangeCheckedParam<Real>(
     115             :       "active_distance",
     116             :       "active_distance > 0",
     117             :       "The active length (distance a ray travels while accumulating tallies) used "
     118             :       "for random ray; this overrides the setting in the XML files.");
     119        4761 :   return params;
     120           0 : }
     121             : 
     122        2399 : OpenMCProblemBase::OpenMCProblemBase(const InputParameters & params)
     123             :   : CardinalProblem(params),
     124             :     PostprocessorInterface(this),
     125        2399 :     _verbose(getParam<bool>("verbose")),
     126        4798 :     _reuse_source(getParam<bool>("reuse_source")),
     127        2399 :     _specified_scaling(params.isParamSetByUser("scaling")),
     128        4798 :     _scaling(getParam<Real>("scaling")),
     129        4798 :     _skip_statepoint(getParam<bool>("skip_statepoint")),
     130        2399 :     _fixed_point_iteration(-1),
     131        2399 :     _total_n_particles(0),
     132        2399 :     _has_adaptivity(getMooseApp().actionWarehouse().hasActions("set_adaptivity_options")),
     133        2399 :     _run_on_adaptivity_cycle(true),
     134        4798 :     _calc_kinetics_params(getParam<bool>("calc_kinetics_params")),
     135        4798 :     _reset_seed(getParam<bool>("reset_seed")),
     136        2399 :     _initial_seed(openmc::openmc_get_seed()),
     137        7197 :     _xml_directory(getParam<FileName>("xml_directory"))
     138             : {
     139        4798 :   if (isParamValid("tally_type"))
     140           0 :     mooseError("The tally system used by OpenMCProblemBase derived classes has been deprecated. "
     141             :                "Please add tallies with the [Tallies] block instead.");
     142             : 
     143             :   // ensure that any mapped cells have their distribcell indices generated in OpenMC
     144        2399 :   if (!openmc::settings::material_cell_offsets)
     145             :   {
     146           0 :     mooseWarning("Distributed properties for material cells are disabled "
     147             :                  "in the OpenMC settings. Enabling...");
     148           0 :     openmc::settings::material_cell_offsets = true;
     149           0 :     openmc::prepare_distribcell();
     150             :   }
     151             : 
     152             :   // ensure that unsupported run modes are not used, while also checking for
     153             :   // necessary/unused input parameters for the valid run modes
     154        2399 :   _run_mode = openmc::settings::run_mode;
     155        2399 :   const auto & tally_actions = getMooseApp().actionWarehouse().getActions<AddTallyAction>();
     156        2399 :   const auto & mgxs_actions = getMooseApp().actionWarehouse().getActions<SetupMGXSAction>();
     157        2399 :   switch (_run_mode)
     158             :   {
     159             :     case openmc::RunMode::EIGENVALUE:
     160             :     {
     161             :       // Jumping through hoops to see if we're going to add tallies down the line.
     162        2245 :       if (tally_actions.size() > 0 || mgxs_actions.size() > 0)
     163             :       {
     164        3472 :         checkRequiredParam(params, "power", "running in k-eigenvalue mode");
     165        1736 :         _power = &getPostprocessorValue("power");
     166             :       }
     167             :       else
     168        1018 :         checkUnusedParam(params, "power", "no tallies have been added");
     169             : 
     170        4490 :       checkUnusedParam(params, "source_strength", "running in k-eigenvalue mode");
     171        2245 :       break;
     172             :     }
     173             :     case openmc::RunMode::FIXED_SOURCE:
     174             :     {
     175         148 :       if (tally_actions.size() > 0 || mgxs_actions.size() > 0)
     176             :       {
     177         280 :         checkRequiredParam(params, "source_strength", "running in fixed source mode");
     178         140 :         _source_strength = &getPostprocessorValue("source_strength");
     179             :       }
     180             :       else
     181          16 :         checkUnusedParam(params, "source_strength", "no tallies have been added");
     182             : 
     183         148 :       if (!runRandomRay())
     184         232 :         checkUnusedParam(
     185             :             params, "inactive_batches", "running in fixed source mode with the Monte Carlo solver");
     186         296 :       checkUnusedParam(params, "reuse_source", "running in fixed source mode");
     187         296 :       checkUnusedParam(params, "power", "running in fixed source mode");
     188         148 :       _reuse_source = false;
     189         148 :       break;
     190             :     }
     191           6 :     case openmc::RunMode::PLOTTING:
     192             :     case openmc::RunMode::PARTICLE:
     193             :     case openmc::RunMode::VOLUME:
     194           6 :       mooseError("Running OpenMC in plotting, particle, and volume modes is not supported through "
     195             :                  "Cardinal! Please just run using the OpenMC executable (e.g., openmc --plot for "
     196             :                  "plot mode).");
     197           0 :     default:
     198           0 :       mooseError("Unhandled openmc::RunMode enum in OpenMCInitAction!");
     199             :   }
     200             : 
     201        2393 :   _n_cell_digits = std::to_string(openmc::model::cells.size()).length();
     202             : 
     203        2393 :   if (openmc::settings::libmesh_comm)
     204           0 :     mooseWarning("libMesh communicator already set in OpenMC.");
     205             : 
     206        2393 :   openmc::settings::libmesh_comm = &_mesh.comm();
     207             : 
     208        4786 :   if (isParamValid("openmc_verbosity"))
     209           0 :     openmc::settings::verbosity = getParam<unsigned int>("openmc_verbosity");
     210             : 
     211        4786 :   if (isParamValid("inactive_batches"))
     212         250 :     openmc::settings::n_inactive = getParam<unsigned int>("inactive_batches");
     213             : 
     214        4786 :   if (isParamValid("particles"))
     215         161 :     _particles = &getPostprocessorValue("particles");
     216             : 
     217        2393 :   if (!runRandomRay())
     218             :   {
     219        4524 :     checkUnusedParam(params, "inactive_distance", "not running in random ray mode");
     220        4524 :     checkUnusedParam(params, "active_distance", "not running in random ray mode");
     221             :   }
     222             : 
     223        4786 :   if (isParamValid("inactive_distance"))
     224          64 :     openmc::RandomRay::distance_inactive_ = getParam<Real>("inactive_distance");
     225             : 
     226        4786 :   if (isParamValid("active_distance"))
     227          64 :     openmc::RandomRay::distance_active_ = getParam<Real>("active_distance");
     228             : 
     229        4786 :   if (isParamValid("batches"))
     230             :   {
     231         163 :     auto xml_n_batches = openmc::settings::n_batches; // user XML setting
     232             : 
     233             :     // the getParam<unsigned int>("batches") param overrides OpenMC XML
     234             :     // IMPORTANT because openmc::settings:statepoint_batch is a C++ set,
     235             :     // we need to remove this first in the case that xml_n_batches matches
     236             :     // getParam<unsigned int>("batches") otherwise there will be no batch
     237             :     // at which Cardinal writes a statepoint
     238             :     openmc::settings::statepoint_batch.erase(xml_n_batches);
     239             : 
     240         326 :     int err = openmc_set_n_batches(getParam<unsigned int>("batches"),
     241             :                                    true /* set the max batches */,
     242         163 :                                    true /* add the last batch for statepoint writing */);
     243         324 :     catchOpenMCError(err, "set the number of batches");
     244             :   }
     245             : 
     246             :   // The OpenMC wrapping doesn't require material properties itself, but we might
     247             :   // define them on some blocks of the domain for other auxiliary kernel purposes
     248             :   setMaterialCoverageCheck(false);
     249             : 
     250             :   // If the user requests kinetics parameters, make sure it's enabled in OpenMC.
     251        2391 :   if (_calc_kinetics_params)
     252             :   {
     253          23 :     if (_run_mode != openmc::RunMode::EIGENVALUE)
     254           2 :       paramError("calc_kinetics_params",
     255             :                  "Kinetic parameters can only be calculated in k-eigenvalue mode!");
     256             : 
     257          21 :     if (runRandomRay())
     258           2 :       paramError("calc_kinetics_params",
     259             :                  "Kinetic parameters cannot be calculated when using the random ray solver!");
     260             : 
     261          19 :     openmc::settings::ifp_on = true;
     262          19 :     openmc::settings::ifp_parameter = openmc::IFPParameter::Both;
     263             : 
     264          38 :     openmc::settings::ifp_n_generation = getParam<unsigned int>("ifp_generations");
     265          19 :     if (openmc::settings::ifp_n_generation > openmc::settings::n_inactive)
     266           2 :       paramError("ifp_generations",
     267             :                  "'ifp_generations' must be less than or equal to the number of inactive batches!");
     268             :   }
     269        2385 : }
     270             : 
     271        2015 : OpenMCProblemBase::~OpenMCProblemBase() { openmc_finalize(); }
     272             : 
     273             : void
     274           0 : OpenMCProblemBase::fillElementalAuxVariable(const unsigned int & var_num,
     275             :                                             const std::vector<unsigned int> & elem_ids,
     276             :                                             const Real & value)
     277             : {
     278           0 :   auto & solution = _aux->solution();
     279           0 :   auto sys_number = _aux->number();
     280             : 
     281             :   // loop over all the elements and set the specified variable to the specified value
     282           0 :   for (const auto & e : elem_ids)
     283             :   {
     284           0 :     auto elem_ptr = _mesh.queryElemPtr(e);
     285             : 
     286           0 :     if (!isLocalElem(elem_ptr))
     287           0 :       continue;
     288             : 
     289           0 :     auto dof_idx = elem_ptr->dof_number(sys_number, var_num, 0);
     290           0 :     solution.set(dof_idx, value);
     291             :   }
     292           0 : }
     293             : 
     294             : int
     295        5496 : OpenMCProblemBase::nParticles() const
     296             : {
     297        5496 :   return openmc::settings::n_particles;
     298             : }
     299             : 
     300             : std::string
     301        7982 : OpenMCProblemBase::materialName(const int32_t index) const
     302             : {
     303             :   // OpenMC uses -1 to indicate void materials, which don't have a name. So we return
     304             :   // one ourselves, or else openmc_material_get_name will throw an error.
     305        7982 :   if (index == -1)
     306          51 :     return "VOID";
     307             : 
     308             :   const char * name;
     309        7931 :   int err = openmc_material_get_name(index, &name);
     310        7931 :   catchOpenMCError(err, "get material name for material with index " + std::to_string(index));
     311             : 
     312        7931 :   std::string n = name;
     313             : 
     314             :   // if the material does not have a name, just return the ID instead
     315        7931 :   if (n.empty())
     316        7460 :     n = std::to_string(materialID(index));
     317             : 
     318        7931 :   return n;
     319             : }
     320             : 
     321             : int32_t
     322    20133831 : OpenMCProblemBase::cellID(const int32_t index) const
     323             : {
     324             :   int32_t id;
     325    20133831 :   int err = openmc_cell_get_id(index, &id);
     326    20133831 :   catchOpenMCError(err, "get ID for cell with index " + std::to_string(index));
     327    20133831 :   return id;
     328             : }
     329             : 
     330             : int32_t
     331     1303570 : OpenMCProblemBase::materialID(const int32_t index) const
     332             : {
     333     1303570 :   if (index == openmc::MATERIAL_VOID)
     334             :     return -1;
     335             : 
     336             :   int32_t id;
     337     1297666 :   int err = openmc_material_get_id(index, &id);
     338     1297666 :   catchOpenMCError(err, "get ID for material with index " + std::to_string(index));
     339     1297666 :   return id;
     340             : }
     341             : 
     342             : std::string
     343           0 : OpenMCProblemBase::printMaterial(const int32_t & index) const
     344             : {
     345           0 :   int32_t id = materialID(index);
     346           0 :   std::stringstream msg;
     347           0 :   msg << "material " << id;
     348           0 :   return msg.str();
     349           0 : }
     350             : 
     351             : std::string
     352          10 : OpenMCProblemBase::printPoint(const Point & p) const
     353             : {
     354          10 :   std::stringstream msg;
     355          10 :   msg << "(" << std::setprecision(6) << std::setw(7) << p(0) << ", " << std::setprecision(6)
     356          10 :       << std::setw(7) << p(1) << ", " << std::setprecision(6) << std::setw(7) << p(2) << ")";
     357          10 :   return msg.str();
     358          10 : }
     359             : 
     360             : bool
     361        2795 : OpenMCProblemBase::firstSolve() const
     362             : {
     363        2795 :   return _fixed_point_iteration < 0;
     364             : }
     365             : 
     366             : void
     367        2747 : OpenMCProblemBase::externalSolve()
     368             : {
     369        5494 :   TIME_SECTION("solveOpenMC", 1, "Solving OpenMC", false);
     370             : 
     371             :   // Check to see if this is a steady solve. If so, we can skip extra OpenMC runs
     372             :   // once the mesh stops getting adapted.
     373        2747 :   if (_has_adaptivity && !_run_on_adaptivity_cycle)
     374             :   {
     375          18 :     _console << " Skipping running OpenMC as the mesh has not changed!" << std::endl;
     376             :     return;
     377             :   }
     378             : 
     379        2729 :   _console << " Running OpenMC with " << nParticles() << " particles per batch..." << std::endl;
     380             : 
     381             :   // apply a new starting fission source
     382        2729 :   if (_reuse_source && !firstSolve())
     383             :   {
     384          16 :     openmc::free_memory_source();
     385          16 :     openmc::model::external_sources.push_back(
     386          48 :         std::make_unique<openmc::FileSource>(sourceBankFileName()));
     387             :   }
     388             : 
     389             :   // update tallies as needed before starting the OpenMC run
     390        2729 :   executeEditors();
     391             : 
     392        2723 :   if (_reset_seed)
     393             :   {
     394          56 :     openmc_hard_reset();
     395          56 :     openmc_set_seed(_initial_seed);
     396             :   }
     397             : 
     398             :   int err = 0;
     399        2723 :   if (!firstSolve())
     400             :   {
     401         694 :     err = openmc_reset_timers();
     402         694 :     if (err)
     403           0 :       mooseError(openmc_err_msg);
     404             :   }
     405             : 
     406        2723 :   if (_criticality_search)
     407         960 :     _criticality_search->searchForCriticality([&]() { this->critSearchStep(); });
     408             :   else
     409             :   {
     410        2647 :     if (runRandomRay())
     411         143 :       openmc_run_random_ray();
     412             :     else
     413        2504 :       err = openmc_run();
     414             : 
     415        2647 :     if (err)
     416           0 :       mooseError(openmc_err_msg);
     417             :   }
     418             : 
     419        2719 :   _total_n_particles += nParticles();
     420             : 
     421        2719 :   _fixed_point_iteration++;
     422             : 
     423             :   // save the latest fission source for re-use in the next iteration
     424        2719 :   if (_reuse_source)
     425          48 :     writeSourceBank(sourceBankFileName());
     426        2737 : }
     427             : 
     428             : void
     429        2128 : OpenMCProblemBase::initialSetup()
     430             : {
     431        2128 :   CardinalProblem::initialSetup();
     432             : 
     433             :   // Initialize the IFP parameters tally.
     434        2128 :   if (_calc_kinetics_params)
     435             :   {
     436             :     // For \Lambda_eff, \beta_{eff}, and the denominator of \beta_{eff,i}
     437          17 :     _ifp_common_tally_index = openmc::model::tallies.size();
     438          17 :     _ifp_common_tally = openmc::Tally::create();
     439          17 :     _ifp_common_tally->set_scores({"ifp-time-numerator", "ifp-denominator", "ifp-beta-numerator"});
     440          17 :     _ifp_common_tally->estimator_ = openmc::TallyEstimator::COLLISION;
     441             : 
     442             :     // For \beta_{eff,i}. A separate tally is required when sieving by delayed group to compute
     443             :     // standard deviations and relative errors correctly for the total \beta_eff (due to covariances
     444             :     // between delayed groups).
     445          17 :     _ifp_mg_beta_tally_index = openmc::model::tallies.size();
     446          17 :     _ifp_mg_beta_tally = openmc::Tally::create();
     447          17 :     _ifp_mg_beta_tally->set_scores({"ifp-beta-numerator"});
     448          17 :     _ifp_mg_beta_tally->estimator_ = openmc::TallyEstimator::COLLISION;
     449             : 
     450             :     auto dnp_grp_filter =
     451          17 :         dynamic_cast<openmc::DelayedGroupFilter *>(openmc::Filter::create("delayedgroup"));
     452          17 :     std::vector<int> grps{1, 2, 3, 4, 5, 6};
     453          17 :     dnp_grp_filter->set_groups(openmc::span<int>(grps));
     454             : 
     455          17 :     std::vector<openmc::Filter *> df{dnp_grp_filter};
     456          17 :     _ifp_mg_beta_tally->set_filters({df});
     457          17 :   }
     458             : 
     459             :   // Find a criticality search object
     460        2128 :   TheWarehouse::Query query = theWarehouse().query().condition<AttribSystem>("CriticalitySearch");
     461             :   std::vector<CriticalitySearchBase *> objs;
     462             :   query.queryInto(objs);
     463             : 
     464        2128 :   if (objs.size() > 1)
     465           0 :     mooseError("Cannot have more than one CriticalitySearch object");
     466             : 
     467        2128 :   if (objs.size())
     468          76 :     _criticality_search = objs[0];
     469             : 
     470             :   // Find model modifier objects
     471        2128 :   TheWarehouse::Query mm_query = theWarehouse().query().condition<AttribSystem>("ModelModifiers");
     472             :   std::vector<ModelModifiersBase *> mm_objs;
     473             :   mm_query.queryInto(mm_objs);
     474        2160 :   for (const auto & m : mm_objs)
     475          32 :     m->modifyOpenMCModel();
     476        2128 : }
     477             : 
     478             : void
     479        5502 : OpenMCProblemBase::syncSolutions(ExternalProblem::Direction direction)
     480             : {
     481             :   // Always run OpenMC on the first timestep in a steady solve with adaptivity. This
     482             :   // ensures that OpenMC runs at least once during each Picard iteration.
     483        5502 :   _run_on_adaptivity_cycle |= (timeStep() == 1 && !isTransient());
     484        5502 : }
     485             : 
     486             : bool
     487         704 : OpenMCProblemBase::adaptMesh()
     488             : {
     489         704 :   _run_on_adaptivity_cycle = CardinalProblem::adaptMesh() || isTransient();
     490         704 :   return _run_on_adaptivity_cycle;
     491             : }
     492             : 
     493             : void
     494          24 : OpenMCProblemBase::writeSourceBank(const std::string & filename)
     495             : {
     496          24 :   hid_t file_id = openmc::file_open(filename, 'w', true);
     497             :   openmc::write_attribute(file_id, "filetype", "source");
     498          24 :   openmc::write_attribute(file_id, "version", openmc::VERSION_STATEPOINT);
     499          24 :   openmc::write_source_bank(
     500             :       file_id, openmc::simulation::source_bank, openmc::simulation::work_index);
     501          24 :   openmc::file_close(file_id);
     502          24 : }
     503             : 
     504             : unsigned int
     505        2751 : OpenMCProblemBase::numElemsInSubdomain(const SubdomainID & id) const
     506             : {
     507        2751 :   unsigned int n = 0;
     508     7179057 :   for (unsigned int e = 0; e < _mesh.nElem(); ++e)
     509             :   {
     510     7176306 :     const auto * elem = _mesh.queryElemPtr(e);
     511             : 
     512     7176306 :     if (!isLocalElem(elem) || !elem->active())
     513     3390864 :       continue;
     514             : 
     515             :     const auto subdomain_id = elem->subdomain_id();
     516     3785442 :     if (id == subdomain_id)
     517     1549656 :       n += 1;
     518             :   }
     519             : 
     520        2751 :   _communicator.sum(n);
     521             : 
     522        2751 :   return n;
     523             : }
     524             : 
     525             : bool
     526    22962160 : OpenMCProblemBase::isLocalElem(const Elem * elem) const
     527             : {
     528    22962160 :   if (!elem)
     529             :   {
     530             :     // we should only not be able to find an element if the mesh is distributed
     531             :     libmesh_assert(!_mesh.getMesh().is_serial());
     532             :     return false;
     533             :   }
     534             : 
     535    14714078 :   if (elem->processor_id() == _communicator.rank())
     536    11868880 :     return true;
     537             : 
     538             :   return false;
     539             : }
     540             : 
     541             : bool
     542           4 : OpenMCProblemBase::cellHasZeroInstances(const cellInfo & cell_info) const
     543             : {
     544           4 :   auto n = openmc::model::cells.at(cell_info.first)->n_instances();
     545           4 :   return !n;
     546             : }
     547             : 
     548             : void
     549    11393840 : OpenMCProblemBase::setCellTemperature(const int32_t & index,
     550             :                                       const int32_t & instance,
     551             :                                       const Real & T,
     552             :                                       const cellInfo & cell_info) const
     553             : {
     554    11393840 :   int err = openmc_cell_set_temperature(index, T, &instance, false);
     555    11393840 :   if (err)
     556             :   {
     557             :     std::string descriptor =
     558          12 :         "set cell " + printCell(cell_info) + " to temperature " + Moose::stringify(T) + " (K)";
     559             : 
     560             :     // special error message if cell has zero instances
     561           4 :     if (cellHasZeroInstances(cell_info))
     562           0 :       mooseError("Failed to set the temperature for cell " + printCell(cell_info) +
     563             :                  " with zero instances.");
     564             : 
     565          12 :     mooseError("In attempting to set cell " + printCell(cell_info) + " to temperature " +
     566           4 :                    Moose::stringify(T) + " (K), OpenMC reported:\n\n",
     567           4 :                std::string(openmc_err_msg) + "\n\n" +
     568             :                    "If you are trying to debug a model setup, you can set 'initial_properties = "
     569             :                    "xml' to use the initial temperature and density in the OpenMC XML files for "
     570             :                    "OpenMC's first run.");
     571             :   }
     572    11393836 : }
     573             : 
     574             : std::vector<int32_t>
     575     1740161 : OpenMCProblemBase::cellFill(const cellInfo & cell_info, int & fill_type) const
     576             : {
     577     1740161 :   int32_t * materials = nullptr;
     578     1740161 :   int n_materials = 0;
     579             : 
     580     1740161 :   int err = openmc_cell_get_fill(cell_info.first, &fill_type, &materials, &n_materials);
     581     3480322 :   catchOpenMCError(err, "get fill of cell " + printCell(cell_info));
     582             : 
     583             :   std::vector<int32_t> material_indices;
     584     1740161 :   material_indices.assign(materials, materials + n_materials);
     585     1740161 :   return material_indices;
     586           0 : }
     587             : 
     588             : bool
     589     1740161 : OpenMCProblemBase::materialFill(const cellInfo & cell_info, int32_t & material_index) const
     590             : {
     591             :   int fill_type;
     592     1740161 :   auto material_indices = cellFill(cell_info, fill_type);
     593             : 
     594     1740161 :   if (fill_type != static_cast<int>(openmc::Fill::MATERIAL))
     595             :     return false;
     596             : 
     597             :   // The number of materials in a cell is either 1, or equal to the number of instances
     598             :   // (if distributed materials were used).
     599     1740161 :   if (material_indices.size() == 1)
     600     1331009 :     material_index = material_indices[0];
     601             :   else
     602      409152 :     material_index = material_indices[cell_info.second];
     603             : 
     604             :   return true;
     605     1740161 : }
     606             : 
     607             : const Real
     608     1335860 : OpenMCProblemBase::densityConversionFactor() const
     609             : {
     610             :   // The density field variables are assumed to be in units of kg/m3, which must be
     611             :   // converted to g/cm3 for OpenMC (the conversion factor is _density_conversion_factor).
     612             :   // However, when running in multi-group mode OpenMC expects unitless density multipliers.
     613             :   // To go between the field variable density and density multipliers, the superclass
     614             :   // (OpenMCCellAverageProblem) asks users to specify a reference density (the density
     615             :   // in kg/m3 used to generate multi-group cross sections). This divides the field variable
     616             :   // density to get the unitless density multiplier expected by OpenMC.
     617             :   //
     618             :   // Therefore, in multi-group mode converting from kg/m3 to g/cm3 is no longer required
     619             :   // and we can return unity instead.
     620     1335860 :   return openmc::settings::run_CE ? _density_conversion_factor : 1.0;
     621             : }
     622             : 
     623             : void
     624        2650 : OpenMCProblemBase::setCellDensity(const int32_t & index,
     625             :                                   const int32_t & instance,
     626             :                                   const Real & density,
     627             :                                   const cellInfo & cell_info) const
     628             : {
     629             :   // OpenMC technically allows a density of >= 0.0, but we can impose a tighter
     630             :   // check here with a better error message than the Excepts() in material->set_density
     631             :   // because it could be a very common mistake to forget to set an initial condition
     632             :   // for density if OpenMC runs first
     633        2650 :   if (density <= 0.0)
     634           4 :     mooseError("Densities less than or equal to zero cannot be set in the OpenMC model!\n\n cell " +
     635           4 :                printCell(cell_info) + " set to density " + Moose::stringify(density) + " (kg/m3)");
     636             : 
     637             :   // Compute the density. We multiply density by 0.001 to convert from kg/m3
     638             :   // (the units assumed in the 'density' auxvariable as well as the MOOSE fluid
     639             :   // properties module) to g/cm3
     640        2648 :   int err = openmc_cell_set_density(index, densityConversionFactor() * density, &instance, false);
     641             : 
     642        2648 :   if (err)
     643             :   {
     644             :     // special error message if cell has zero instances
     645           0 :     if (cellHasZeroInstances(cell_info))
     646           0 :       mooseError("Failed to set the density for cell " + printCell(cell_info) +
     647             :                  " with zero instances.");
     648             : 
     649           0 :     mooseError("In attempting to set cell " + printCell(cell_info) + " to density " +
     650           0 :                    Moose::stringify(density) + " (kg/m3), OpenMC reported:\n\n",
     651           0 :                std::string(openmc_err_msg) + "\n\n" +
     652             :                    "If you are trying to debug a model setup, you can set 'initial_properties = "
     653             :                    "xml' to use the initial temperature and density in the OpenMC XML files for "
     654             :                    "OpenMC's first run.");
     655             :   }
     656        2648 : }
     657             : 
     658             : std::string
     659     7178996 : OpenMCProblemBase::printCell(const cellInfo & cell_info, const bool brief) const
     660             : {
     661     7178996 :   int32_t id = cellID(cell_info.first);
     662             : 
     663     7178996 :   std::stringstream msg;
     664     7178996 :   if (!brief)
     665     7164297 :     msg << "id ";
     666             : 
     667    14357992 :   msg << std::setw(_n_cell_digits) << Moose::stringify(id) << ", instance "
     668    14357992 :       << std::setw(_n_cell_digits) << Moose::stringify(cell_info.second) << " (of "
     669     7178996 :       << std::setw(_n_cell_digits)
     670    28715984 :       << Moose::stringify(openmc::model::cells.at(cell_info.first)->n_instances()) << ")";
     671             : 
     672     7178996 :   return msg.str();
     673     7178996 : }
     674             : 
     675             : void
     676           2 : OpenMCProblemBase::importProperties() const
     677             : {
     678           2 :   _console << "Reading temperature and density from properties.h5" << std::endl;
     679             : 
     680           2 :   int err = openmc_properties_import("properties.h5");
     681           2 :   catchOpenMCError(err, "load temperature and density from a properties.h5 file");
     682           0 : }
     683             : 
     684             : OMCTensor
     685        4416 : OpenMCProblemBase::relativeError(const OMCTensor & sum,
     686             :                                  const OMCTensor & sum_sq,
     687             :                                  const int & n_realizations) const
     688             : {
     689        4416 :   auto rel_err = openmc::tensor::zeros<double>({sum.size()});
     690             : 
     691      480270 :   for (unsigned int i = 0; i < sum.size(); ++i)
     692             :   {
     693      475854 :     auto mean = sum(i) / n_realizations;
     694      475854 :     auto std_dev = std::sqrt((sum_sq(i) / n_realizations - mean * mean) / (n_realizations - 1));
     695      475854 :     rel_err[i] = mean != 0.0 ? std_dev / std::abs(mean) : 0.0;
     696             :   }
     697             : 
     698        4416 :   return rel_err;
     699             : }
     700             : 
     701             : Real
     702         456 : OpenMCProblemBase::relativeError(const Real & sum,
     703             :                                  const Real & sum_sq,
     704             :                                  const int & n_realizations) const
     705             : {
     706         456 :   auto mean = sum / n_realizations;
     707         456 :   auto std_dev = std::sqrt((sum_sq / n_realizations - mean * mean) / (n_realizations - 1));
     708         456 :   return mean != 0.0 ? std_dev / std::abs(mean) : 0.0;
     709             : }
     710             : 
     711             : OMCTensor
     712        6372 : OpenMCProblemBase::tallySum(const openmc::Tally * tally, const unsigned int & score) const
     713             : {
     714        6372 :   return OMCTensor(tally->results_.slice(
     715       12744 :       openmc::tensor::all, score, static_cast<int>(openmc::TallyResult::SUM)));
     716             : }
     717             : 
     718             : double
     719        2338 : OpenMCProblemBase::tallySumAcrossBins(std::vector<const openmc::Tally *> tally,
     720             :                                       const unsigned int & score) const
     721             : {
     722             :   double sum = 0.0;
     723             : 
     724        4676 :   for (const auto & t : tally)
     725             :   {
     726        2338 :     auto mean = tallySum(t, score);
     727        2338 :     sum += mean.sum();
     728             :   }
     729             : 
     730        2338 :   return sum;
     731             : }
     732             : 
     733             : double
     734           0 : OpenMCProblemBase::tallyMeanAcrossBins(std::vector<const openmc::Tally *> tally,
     735             :                                        const unsigned int & score) const
     736             : {
     737             :   int n = 0;
     738           0 :   for (const auto & t : tally)
     739           0 :     n += t->n_realizations_;
     740             : 
     741           0 :   return tallySumAcrossBins(tally, score) / n;
     742             : }
     743             : 
     744             : bool
     745       15594 : OpenMCProblemBase::runRandomRay() const
     746             : {
     747       15594 :   return openmc::settings::solver_type == openmc::SolverType::RANDOM_RAY;
     748             : }
     749             : 
     750             : std::string
     751        2763 : OpenMCProblemBase::enumToTallyScore(const std::string & score) const
     752             : {
     753             :   // the MultiMooseEnum is all caps, but the MooseEnum is already the correct case,
     754             :   // so we need to treat these as separate
     755        2763 :   std::string s = score;
     756        2763 :   if (std::all_of(
     757       20372 :           s.begin(), s.end(), [](unsigned char c) { return !std::isalpha(c) || std::isupper(c); }))
     758             :   {
     759       22077 :     std::transform(s.begin(), s.end(), s.begin(), [](unsigned char c) { return std::tolower(c); });
     760             : 
     761             :     // we need to revert back to some letters being uppercase for certain scores
     762        2234 :     if (s == "h3_production")
     763             :       s = "H3_production";
     764             :   }
     765             : 
     766             :   // MOOSE enums use underscores, OpenMC uses dashes
     767             :   std::replace(s.begin(), s.end(), '_', '-');
     768        2763 :   return s;
     769             : }
     770             : 
     771             : std::string
     772           0 : OpenMCProblemBase::tallyScoreToEnum(const std::string & score) const
     773             : {
     774             :   // MOOSE enums use underscores, OpenMC uses dashes
     775           0 :   std::string s = score;
     776             :   std::replace(s.begin(), s.end(), '-', '_');
     777           0 :   return s;
     778             : }
     779             : 
     780             : openmc::TallyEstimator
     781         306 : OpenMCProblemBase::tallyEstimator(tally::TallyEstimatorEnum estimator) const
     782             : {
     783             :   switch (estimator)
     784             :   {
     785             :     case tally::tracklength:
     786             :       return openmc::TallyEstimator::TRACKLENGTH;
     787             :     case tally::collision:
     788             :       return openmc::TallyEstimator::COLLISION;
     789             :     case tally::analog:
     790             :       return openmc::TallyEstimator::ANALOG;
     791           0 :     default:
     792           0 :       mooseError("Unhandled TallyEstimatorEnum!");
     793             :   }
     794             : }
     795             : 
     796             : std::string
     797           0 : OpenMCProblemBase::estimatorToString(openmc::TallyEstimator estimator) const
     798             : {
     799           0 :   switch (estimator)
     800             :   {
     801             :     case openmc::TallyEstimator::TRACKLENGTH:
     802           0 :       return "tracklength";
     803             :     case openmc::TallyEstimator::COLLISION:
     804           0 :       return "collision";
     805             :     case openmc::TallyEstimator::ANALOG:
     806           0 :       return "analog";
     807           0 :     default:
     808           0 :       mooseError("Unhandled TallyEstimatorEnum!");
     809             :   }
     810             : }
     811             : 
     812             : openmc::TriggerMetric
     813         128 : OpenMCProblemBase::triggerMetric(std::string trigger) const
     814             : {
     815         128 :   if (trigger == "variance")
     816             :     return openmc::TriggerMetric::variance;
     817         128 :   else if (trigger == "std_dev")
     818             :     return openmc::TriggerMetric::standard_deviation;
     819         128 :   else if (trigger == "rel_err")
     820             :     return openmc::TriggerMetric::relative_error;
     821           0 :   else if (trigger == "none")
     822             :     return openmc::TriggerMetric::not_active;
     823             :   else
     824           0 :     mooseError("Unhandled TallyTriggerTypeEnum: ", trigger);
     825             : }
     826             : 
     827             : openmc::TriggerMetric
     828        3004 : OpenMCProblemBase::triggerMetric(trigger::TallyTriggerTypeEnum trigger) const
     829             : {
     830             :   switch (trigger)
     831             :   {
     832             :     case trigger::variance:
     833             :       return openmc::TriggerMetric::variance;
     834             :     case trigger::std_dev:
     835             :       return openmc::TriggerMetric::standard_deviation;
     836             :     case trigger::rel_err:
     837             :       return openmc::TriggerMetric::relative_error;
     838             :     case trigger::none:
     839             :       return openmc::TriggerMetric::not_active;
     840           0 :     default:
     841           0 :       mooseError("Unhandled TallyTriggerTypeEnum!");
     842             :   }
     843             : }
     844             : 
     845             : bool
     846           0 : OpenMCProblemBase::cellIsVoid(const cellInfo & cell_info) const
     847             : {
     848             :   // material_index will be unchanged if the cell is filled by a universe or lattice.
     849             :   // Otherwise, this will get set to the material index in the cell.
     850           0 :   int32_t material_index = 0;
     851           0 :   materialFill(cell_info, material_index);
     852           0 :   return material_index == MATERIAL_VOID;
     853             : }
     854             : 
     855             : void
     856        1221 : OpenMCProblemBase::geometryType(bool & has_csg_universe, bool & has_dag_universe) const
     857             : {
     858        1221 :   has_csg_universe = false;
     859        1221 :   has_dag_universe = false;
     860             : 
     861             :   // Loop over universes and check if type is DAGMC
     862        6504 :   for (const auto & universe : openmc::model::universes)
     863             :   {
     864        5283 :     if (universe->geom_type() == openmc::GeometryType::DAG)
     865          68 :       has_dag_universe = true;
     866        5215 :     else if (universe->geom_type() == openmc::GeometryType::CSG)
     867        5215 :       has_csg_universe = true;
     868             :     else
     869           0 :       mooseError("Unhandled GeometryType enum!");
     870             :   }
     871        1221 : }
     872             : 
     873             : long unsigned int
     874        3040 : OpenMCProblemBase::numCells() const
     875             : {
     876             :   long unsigned int n_openmc_cells = 0;
     877       96039 :   for (const auto & c : openmc::model::cells)
     878       92999 :     n_openmc_cells += c->n_instances();
     879             : 
     880        3040 :   return n_openmc_cells;
     881             : }
     882             : 
     883             : const openmc::Tally &
     884         228 : OpenMCProblemBase::getCommonKineticsTally()
     885             : {
     886         228 :   if (!_ifp_common_tally)
     887           0 :     mooseError("Internal error: kinetics parameters have not been enabled.");
     888             : 
     889         228 :   return *_ifp_common_tally;
     890             : }
     891             : 
     892             : const openmc::Tally &
     893         198 : OpenMCProblemBase::getMGBetaTally()
     894             : {
     895         198 :   return *_ifp_mg_beta_tally;
     896             : }
     897             : 
     898             : bool
     899      192614 : OpenMCProblemBase::isReactionRateScore(const std::string & score) const
     900             : {
     901             :   const std::set<std::string> viable_scores = {"H3-production",
     902             :                                                "total",
     903             :                                                "absorption",
     904             :                                                "scatter",
     905             :                                                "nu-scatter",
     906             :                                                "fission",
     907             :                                                "nu-fission",
     908             :                                                "prompt-nu-fission",
     909      192614 :                                                "delayed-nu-fission"};
     910      192614 :   return viable_scores.count(score);
     911             : }
     912             : 
     913             : bool
     914      479906 : OpenMCProblemBase::isHeatingScore(const std::string & score) const
     915             : {
     916             :   const std::set<std::string> viable_scores = {
     917      479906 :       "heating", "heating-local", "kappa-fission", "fission-q-prompt", "fission-q-recoverable"};
     918      479906 :   return viable_scores.count(score);
     919             : }
     920             : 
     921             : bool
     922         202 : OpenMCProblemBase::validRandomRayScore(const std::string & score) const
     923             : {
     924             :   const std::set<std::string> viable_scores = {
     925         202 :       "flux", "total", "fission", "nu-fission", "kappa-fission"};
     926         202 :   return viable_scores.count(score);
     927             : }
     928             : 
     929             : unsigned int
     930       10290 : OpenMCProblemBase::addExternalVariable(const std::string & name,
     931             :                                        const std::string & system,
     932             :                                        const std::vector<SubdomainName> * block)
     933             : {
     934       10290 :   auto var_params = _factory.getValidParams("MooseVariable");
     935       20580 :   var_params.set<MooseEnum>("family") = "MONOMIAL";
     936       20580 :   var_params.set<MooseEnum>("order") = "CONSTANT";
     937             : 
     938       10290 :   if (block)
     939       13228 :     var_params.set<std::vector<SubdomainName>>("block") = *block;
     940             : 
     941       10290 :   checkDuplicateVariableName(name, system);
     942       20572 :   addAuxVariable("MooseVariable", name, var_params);
     943       20572 :   return _aux->getFieldVariable<Real>(0, name).number();
     944       10286 : }
     945             : 
     946             : std::string
     947        6210 : OpenMCProblemBase::subdomainName(const SubdomainID & id) const
     948             : {
     949        6210 :   std::string name = _mesh.getSubdomainName(id);
     950        6210 :   if (name.empty())
     951       11792 :     name = std::to_string(id);
     952        6210 :   return name;
     953             : }
     954             : 
     955             : void
     956        2128 : OpenMCProblemBase::getOpenMCUserObjects()
     957             : {
     958        2128 :   _cell_transform_uos.clear();
     959             : 
     960        2128 :   TheWarehouse::Query uo_query = theWarehouse().query().condition<AttribSystem>("UserObject");
     961             :   std::vector<UserObject *> userobjs;
     962             :   uo_query.queryInto(userobjs);
     963             : 
     964       11124 :   for (const auto & u : userobjs)
     965             :   {
     966        8996 :     OpenMCNuclideDensities * c = dynamic_cast<OpenMCNuclideDensities *>(u);
     967        8996 :     if (c)
     968          44 :       _nuclide_densities_uos.push_back(c);
     969             : 
     970        8996 :     OpenMCTallyEditor * e = dynamic_cast<OpenMCTallyEditor *>(u);
     971        8996 :     if (e)
     972          60 :       _tally_editor_uos.push_back(e);
     973             : 
     974        8996 :     OpenMCDomainFilterEditor * f = dynamic_cast<OpenMCDomainFilterEditor *>(u);
     975        8996 :     if (f)
     976          28 :       _filter_editor_uos.push_back(f);
     977             : 
     978        8996 :     OpenMCCellTransform * t = dynamic_cast<OpenMCCellTransform *>(u);
     979        8996 :     if (t)
     980          54 :       _cell_transform_uos.push_back(t);
     981             :   }
     982             : 
     983        2128 :   checkOpenMCUserObjectIDs();
     984        2124 : }
     985             : 
     986             : bool
     987        2175 : OpenMCProblemBase::hasCellTransform() const
     988             : {
     989        2175 :   return !_cell_transform_uos.empty();
     990             : }
     991             : 
     992             : void
     993        2128 : OpenMCProblemBase::checkOpenMCUserObjectIDs() const
     994             : {
     995             :   std::set<int32_t> tally_ids;
     996        2186 :   for (const auto & te : _tally_editor_uos)
     997             :   {
     998          60 :     int32_t tally_id = te->tallyId();
     999             :     if (tally_ids.count(tally_id) != 0)
    1000           2 :       te->duplicateTallyError(tally_id);
    1001          58 :     tally_ids.insert(tally_id);
    1002             :   }
    1003             : 
    1004             :   std::set<int32_t> filter_ids;
    1005        2152 :   for (const auto & fe : _filter_editor_uos)
    1006             :   {
    1007          28 :     int32_t filter_id = fe->filterId();
    1008             :     if (filter_ids.count(filter_id) != 0)
    1009           2 :       fe->duplicateFilterError(filter_id);
    1010          26 :     filter_ids.insert(filter_id);
    1011             :   }
    1012        2124 : }
    1013             : 
    1014             : void
    1015        2189 : OpenMCProblemBase::checkTallyEditorIDs() const
    1016             : {
    1017        2189 :   std::vector<int32_t> mapped_tally_ids = getMappedTallyIDs();
    1018             : 
    1019        2243 :   for (const auto & te : _tally_editor_uos)
    1020             :   {
    1021          56 :     int32_t tally_id = te->tallyId();
    1022             : 
    1023             :     // ensure that the TallyEditor IDs don't apply to any mapped tally objects
    1024          56 :     if (std::find(mapped_tally_ids.begin(), mapped_tally_ids.end(), tally_id) !=
    1025             :         mapped_tally_ids.end())
    1026           2 :       te->mappedTallyError(tally_id);
    1027             :   }
    1028        2187 : }
    1029             : 
    1030             : void
    1031        2729 : OpenMCProblemBase::executeFilterEditors()
    1032             : {
    1033        2729 :   executeControls(EXEC_FILTER_EDITORS);
    1034             : 
    1035        2729 :   if (!_filter_editor_uos.size())
    1036             :     return;
    1037             : 
    1038          24 :   _console << "Executing filter editors..." << std::endl;
    1039          48 :   for (const auto & fe : _filter_editor_uos)
    1040          24 :     fe->execute();
    1041             : }
    1042             : 
    1043             : void
    1044        2729 : OpenMCProblemBase::executeTallyEditors()
    1045             : {
    1046        2729 :   executeControls(EXEC_TALLY_EDITORS);
    1047             : 
    1048        2729 :   if (!_tally_editor_uos.size())
    1049             :     return;
    1050             : 
    1051          54 :   _console << "Executing tally editors..." << std::endl;
    1052         102 :   for (const auto & te : _tally_editor_uos)
    1053          54 :     te->execute();
    1054             : }
    1055             : 
    1056             : void
    1057        2729 : OpenMCProblemBase::executeEditors()
    1058             : {
    1059        2729 :   executeFilterEditors();
    1060        2729 :   executeTallyEditors();
    1061        2723 : }
    1062             : 
    1063             : void
    1064        3555 : OpenMCProblemBase::sendNuclideDensitiesToOpenMC()
    1065             : {
    1066        3555 :   if (_nuclide_densities_uos.size() == 0)
    1067             :     return;
    1068             : 
    1069             :   // We could probably put this somewhere better, but it's good for now
    1070          44 :   executeControls(EXEC_SEND_OPENMC_DENSITIES);
    1071             : 
    1072          44 :   _console << "Sending nuclide compositions to OpenMC... ";
    1073          84 :   for (const auto & uo : _nuclide_densities_uos)
    1074          44 :     uo->setValue();
    1075             : }
    1076             : 
    1077             : Real
    1078           8 : OpenMCProblemBase::tallyNormalizationValue() const
    1079             : {
    1080           8 :   return _run_mode == openmc::RunMode::FIXED_SOURCE ? *_source_strength : *_power;
    1081             : }
    1082             : 
    1083             : #endif

Generated by: LCOV version 1.14