LCOV - code coverage report
Current view: top level - include/base - OpenMCProblemBase.h (source / functions) Hit Total Coverage
Test: neams-th-coe/cardinal: 920dc5 Lines: 8 8 100.0 %
Date: 2025-08-10 20:41:39 Functions: 1 1 100.0 %
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             : #pragma once
      20             : 
      21             : #define LIBMESH
      22             : 
      23             : #include "CardinalProblem.h"
      24             : #include "PostprocessorInterface.h"
      25             : #include "CardinalEnums.h"
      26             : 
      27             : #include "mpi.h"
      28             : #include "openmc/bank.h"
      29             : #include "openmc/capi.h"
      30             : #include "openmc/cell.h"
      31             : #include "openmc/geometry.h"
      32             : #include "openmc/geometry_aux.h"
      33             : #include "openmc/hdf5_interface.h"
      34             : #include "openmc/material.h"
      35             : #include "openmc/mesh.h"
      36             : #include "openmc/settings.h"
      37             : #include "openmc/simulation.h"
      38             : #include "openmc/source.h"
      39             : #include "openmc/state_point.h"
      40             : #include "openmc/tallies/tally.h"
      41             : #include "openmc/tallies/filter_cell_instance.h"
      42             : #include "xtensor/xview.hpp"
      43             : 
      44             : // Forward declarations to avoid cyclic dependencies.
      45             : class OpenMCNuclideDensities;
      46             : class OpenMCDomainFilterEditor;
      47             : class OpenMCTallyEditor;
      48             : 
      49             : /**
      50             :  * Base class for all MOOSE wrappings of OpenMC
      51             :  */
      52             : class OpenMCProblemBase : public CardinalProblem, public PostprocessorInterface
      53             : {
      54             : public:
      55             :   OpenMCProblemBase(const InputParameters & params);
      56             : 
      57             :   static InputParameters validParams();
      58             : 
      59             :   virtual ~OpenMCProblemBase() override;
      60             : 
      61             :   /**
      62             :    * Get the subdomain name for a given ID. If not named, we return the ID
      63             :    * @param[in] id subdomain ID
      64             :    * @return name
      65             :    */
      66             :   std::string subdomainName(const SubdomainID & id) const;
      67             : 
      68             :   /**
      69             :    * Print a full error message when catching errors from OpenMC
      70             :    * @param[in] err OpenMC error code
      71             :    * @param[in] descriptor descriptive message for error
      72             :    */
      73             :   void catchOpenMCError(const int & err, const std::string descriptor) const;
      74             : 
      75             :   /**
      76             :    * Whether the score is a reaction rate score
      77             :    * @return whether the tally from OpenMC has units of 1/src
      78             :    */
      79             :   bool isReactionRateScore(const std::string & score) const;
      80             : 
      81             :   /**
      82             :    * Whether the score is a heating-type score
      83             :    * @return whether the tally from OpenMC has units of eV/src
      84             :    */
      85             :   bool isHeatingScore(const std::string & score) const;
      86             : 
      87             :   /**
      88             :    * Add a constant monomial auxiliary variable
      89             :    * @param[in] name name of the variable
      90             :    * @param[in] block optional subdomain names on which to restrict the variable
      91             :    * @return numeric index for the variable in the auxiliary system
      92             :    */
      93             :   unsigned int addExternalVariable(const std::string & name, const std::vector<SubdomainName> * block = nullptr);
      94             : 
      95             :   /**
      96             :    * Get the scaling value applied to the [Mesh] to convert to OpenMC's centimeters units
      97             :    * @return scaling value
      98             :    */
      99     1291326 :   const Real & scaling() const { return _scaling; }
     100             : 
     101             :   /**
     102             :    * Whether the problem has user defined scaling or not.
     103             :    * @return whether the user has set the problem scaling or not
     104             :    */
     105      340000 :   bool hasScaling() const { return _specified_scaling; }
     106             : 
     107             :   /**
     108             :    * Convert from a MOOSE-type enum into a valid OpenMC tally score string
     109             :    * @param[in] score MOOSE-type enum string
     110             :    * @return OpenMC tally score string
     111             :    */
     112             :   std::string enumToTallyScore(const std::string & score) const;
     113             : 
     114             :   /**
     115             :    * Convert into a MOOSE-type enum from a valid OpenMC tally score string
     116             :    * @param[in] score OpenMC tally score string
     117             :    * @return MOOSE-type enum string
     118             :    */
     119             :   std::string tallyScoreToEnum(const std::string & score) const;
     120             : 
     121             :   /**
     122             :    * Find the geometry type in the OpenMC model
     123             :    * @param[out] has_csg_universe whether there is at least 1 CSG universe
     124             :    * @param[out] has_dag_universe whether there is at least 1 DagMC universe
     125             :    */
     126             :   virtual void geometryType(bool & has_csg_universe, bool & has_dag_universe) const;
     127             : 
     128             :   /// Whether this is the first time OpenMC is running
     129             :   bool firstSolve() const;
     130             : 
     131             :   /**
     132             :    * Convert from a MooseEnum for a trigger metric to an OpenMC enum
     133             :    * @param[in] trigger trigger metric
     134             :    * @return OpenMC enum
     135             :    */
     136             :   openmc::TriggerMetric triggerMetric(trigger::TallyTriggerTypeEnum trigger) const;
     137             :   openmc::TriggerMetric triggerMetric(std::string trigger) const;
     138             : 
     139             :   /**
     140             :    * Convert from a MooseEnum for tally estimator to an OpenMC enum
     141             :    * @param[in] estimator MOOSE estimator enum
     142             :    * @return OpenMC enum
     143             :    */
     144             :   openmc::TallyEstimator tallyEstimator(tally::TallyEstimatorEnum estimator) const;
     145             : 
     146             :   /**
     147             :    * Convert a tally estimator to a string (for output purposes).
     148             :    * @param[in] estimator OpenMC tally estimator enum
     149             :    * @return a string form of the OpenMC tally estimator enum
     150             :    */
     151             :   std::string estimatorToString(openmc::TallyEstimator estimator) const;
     152             : 
     153             :   /// Run an OpenMC simulation
     154             :   void externalSolve() override;
     155             : 
     156             :   /// Set up an OpenMC simulation.
     157             :   virtual void initialSetup() override;
     158             : 
     159             :   /// Set the 'mesh changed' adaptivity flag.
     160             :   virtual void syncSolutions(ExternalProblem::Direction direction) override;
     161             :   virtual bool adaptMesh() override;
     162             : 
     163             :   /// Import temperature and density from a properties.h5 file
     164             :   void importProperties() const;
     165             : 
     166             :   /**
     167             :    * \brief Compute the sum of a tally within each bin
     168             :    *
     169             :    * For example, suppose we have a cell tally with 4 bins, one for each of 4
     170             :    * different cells. This function will return the sum of the tally in each of
     171             :    * those bins, so the return xtensor will have a length of 4, with each value
     172             :    * representing the sum for that bin.
     173             :    *
     174             :    * @param[in] tally OpenMC tally
     175             :    * @param[in] score tally score
     176             :    * @return tally sum within each bin
     177             :    */
     178             :   xt::xtensor<double, 1> tallySum(openmc::Tally * tally, const unsigned int & score) const;
     179             : 
     180             :   /**
     181             :    * Compute the sum of a tally across all of its bins
     182             :    * @param[in] tally OpenMC tallies (multiple if repeated mesh tallies)
     183             :    * @param[in] score tally score
     184             :    * @return tally sum
     185             :    */
     186             :   double tallySumAcrossBins(std::vector<openmc::Tally *> tally, const unsigned int & score) const;
     187             : 
     188             :   /**
     189             :    * Compute the mean of a tally across all of its bins
     190             :    * @param[in] tally OpenMC tallies (multiple if repeated mesh tallies)
     191             :    * @param[in] score tally score
     192             :    * @return tally mean
     193             :    */
     194             :   double tallyMeanAcrossBins(std::vector<openmc::Tally *> tally, const unsigned int & score) const;
     195             : 
     196             :   /**
     197             :    * Type definition for storing the relevant aspects of the OpenMC geometry; the first
     198             :    * value is the cell index, while the second is the cell instance.
     199             :    */
     200             :   typedef std::pair<int32_t, int32_t> cellInfo;
     201             : 
     202             :   /**
     203             :    * Whether a cell is filled with VOID (vacuum)
     204             :    * @param[in] cell_info cell ID, instance
     205             :    * @return whether cell is void
     206             :    */
     207             :   bool cellIsVoid(const cellInfo & cell_info) const;
     208             : 
     209             :   /**
     210             :    * Whether this cell has zero instances
     211             :    * @param[in] cell_info cell info
     212             :    * @return whether this cell has zero instances
     213             :    */
     214             :   bool cellHasZeroInstances(const cellInfo & cell_info) const;
     215             : 
     216             :   /**
     217             :    * Get the material name given its index. If the material does not have a name,
     218             :    * return the ID.
     219             :    * @param[in] index
     220             :    * @return material name
     221             :    */
     222             :   std::string materialName(const int32_t index) const;
     223             : 
     224             :   /**
     225             :    * Compute relative error
     226             :    * @param[in] sum sum of scores
     227             :    * @param[in] sum_sq sum of scores squared
     228             :    * @param[in] n_realizations number of realizations
     229             :    */
     230             :   xt::xtensor<double, 1> relativeError(const xt::xtensor<double, 1> & sum,
     231             :     const xt::xtensor<double, 1> & sum_sq, const int & n_realizations) const;
     232             : 
     233             :   /**
     234             :    * Get the density conversion factor (multiplicative factor)
     235             :    * @return density conversion factor from kg/m3 to g/cm3
     236             :    */
     237             :   const Real & densityConversionFactor() const { return _density_conversion_factor; }
     238             : 
     239             :   /**
     240             :    * Get the number of particles used in the current Monte Carlo calculation
     241             :    * @return number of particles
     242             :    */
     243             :   int nParticles() const;
     244             : 
     245             :   /**
     246             :    * Total number of particles run (not multiplied by batches)
     247             :    * @return total number of particles
     248             :    */
     249          24 :   int nTotalParticles() const { return _total_n_particles; }
     250             : 
     251             :   /**
     252             :    * Get the cell ID from the cell index
     253             :    * @param[in] index cell index
     254             :    * @return cell ID
     255             :    */
     256             :   int32_t cellID(const int32_t index) const;
     257             : 
     258             :   /**
     259             :    * Get the material ID from the material index; for VOID cells, this returns -1
     260             :    * @param[in] index material index
     261             :    * @return cell material ID
     262             :    */
     263             :   int32_t materialID(const int32_t index) const;
     264             : 
     265             :   /**
     266             :    * Print point coordinates with a neater formatting than the default MOOSE printing
     267             :    * @return formatted point string
     268             :    */
     269             :   std::string printPoint(const Point & p) const;
     270             : 
     271             :   /**
     272             :    * Get a descriptive, formatted, string describing a material
     273             :    * @param[in] index material index
     274             :    * @return descriptive string
     275             :    */
     276             :   std::string printMaterial(const int32_t & index) const;
     277             : 
     278             :   /**
     279             :    * Write the source bank to HDF5 for postprocessing or for use in subsequent solves
     280             :    * @param[in] filename file name
     281             :    */
     282             :   void writeSourceBank(const std::string & filename);
     283             : 
     284             :   /**
     285             :    * Get the total (i.e. summed across all ranks, if distributed)
     286             :    * number of elements in a given block
     287             :    * @param[in] id subdomainID
     288             :    * return number of elements in block
     289             :    */
     290             :   unsigned int numElemsInSubdomain(const SubdomainID & id) const;
     291             : 
     292             :   /**
     293             :    * Whether the element is owned by this rank
     294             :    * @return whether element is owned by this rank
     295             :    */
     296             :   bool isLocalElem(const Elem * elem) const;
     297             : 
     298             :   /**
     299             :    * Get the global element ID from the local element ID
     300             :    * @param[in] id local element ID
     301             :    * @return global element ID
     302             :    */
     303    15452357 :   unsigned int globalElemID(const unsigned int & id) const { return _local_to_global_elem[id]; }
     304             : 
     305             :   /**
     306             :    * Set the cell temperature, and print helpful error message if a failure occurs; this sets
     307             :    * the temperature for the id + instance, which could be one of N cells filling the 'cell_info'
     308             :    * parent cell (which is what we actually use for error printing)
     309             :    * @param[in] id cell ID
     310             :    * @param[in] instance cell instance
     311             :    * @param[in] T temperature
     312             :    * @param[in] cell_info cell info for which we are setting interior temperature, for error printing
     313             :    */
     314             :   virtual void setCellTemperature(const int32_t & id, const int32_t & instance, const Real & T,
     315             :     const cellInfo & cell_info) const;
     316             : 
     317             :   /**
     318             :    * Set the cell density, and print helpful error message if a failure occurs
     319             :    * @param[in] density density
     320             :    * @param[in] cell_info cell info for which we are setting the density
     321             :    */
     322             :   virtual void setCellDensity(const Real & density, const cellInfo & cell_info) const;
     323             : 
     324             :   /**
     325             :    * Get a descriptive, formatted, string describing a cell
     326             :    * @param[in] cell_info cell index, instance pair
     327             :    * @param[in] brief whether to print a shorter string
     328             :    * @return descriptive string describing cell
     329             :    */
     330             :   virtual std::string printCell(const cellInfo & cell_info, const bool brief = false) const;
     331             : 
     332             :   /**
     333             :    * Get the fill of an OpenMC cell
     334             :    * @param[in] cell_info cell ID, instance
     335             :    * @param[out] fill_type fill type of the cell, one of MATERIAL, UNIVERSE, or LATTICE
     336             :    * @return indices of what is filling the cell
     337             :    */
     338             :   virtual std::vector<int32_t> cellFill(const cellInfo & cell_info, int & fill_type) const;
     339             : 
     340             :   /**
     341             :    * Whether the cell has a material fill (if so, then get the material index). Void counts
     342             :    * as a material, with a material index of -1.
     343             :    * @param[in] cell_info cell ID, instance
     344             :    * @param[out] material_index material index in the cell
     345             :    * @return whether the cell is filled by a material
     346             :    */
     347             :   bool materialFill(const cellInfo & cell_info, int32_t & material_index) const;
     348             : 
     349             :   /**
     350             :    * Calculate the number of unique OpenMC cells (each with a unique ID & instance)
     351             :    * @return number of unique OpenMC Cells in entire model
     352             :    */
     353             :   long unsigned int numCells() const;
     354             : 
     355             :   /**
     356             :    * Return all IDs of all Cardinal-mapped Tallies
     357             :    * @return all Cardinal-mapped Tally IDs
     358             :    */
     359             :   virtual std::vector<int32_t> getMappedTallyIDs() const = 0;
     360             : 
     361             :   /**
     362             :    * Whether or not the problem is tallying kinetics parameters.
     363             :    * @return if the problem is tallying kinetics parameters
     364             :    */
     365          52 :   bool computeKineticsParams() const { return _calc_kinetics_params; }
     366             : 
     367             :   /**
     368             :    * Get the tally responsible for accumulating the scores for \Lambda_{eff} and \beta_{eff}.
     369             :    * @return the global IFP tally
     370             :    */
     371             :   const openmc::Tally & getKineticsParamTally();
     372             : 
     373             : protected:
     374             :   /// Find all userobjects which are changing OpenMC data structures
     375             :   void getOpenMCUserObjects();
     376             : 
     377             :   /// Ensure that the IDs of OpenMC objects in UserObjects don't clash
     378             :   void checkOpenMCUserObjectIDs() const;
     379             : 
     380             :   /// Ensure that any tally editors don't apply to Cardinal-mapped tallies
     381             :   void checkTallyEditorIDs() const;
     382             : 
     383             :   /// Execute all filter editor userobjects
     384             :   void executeFilterEditors();
     385             : 
     386             :   /// Execute all tally editor userobjects
     387             :   void executeTallyEditors();
     388             : 
     389             :   // execute tallly and filte editors
     390             :   void executeEditors();
     391             : 
     392             :   /// Set the nuclide densities for any materials being modified via MOOSE
     393             :   void sendNuclideDensitiesToOpenMC();
     394             : 
     395             :   /// Set the tally nuclides for any tallies being modified via MOOSE
     396             :   void sendTallyNuclidesToOpenMC();
     397             : 
     398             :   /**
     399             :    * Set an auxiliary elemental variable to a specified value
     400             :    * @param[in] var_num variable number
     401             :    * @param[in] elem_ids element IDs to set
     402             :    * @param[in] value value to set
     403             :    */
     404             :   void fillElementalAuxVariable(const unsigned int & var_num,
     405             :                                 const std::vector<unsigned int> & elem_ids,
     406             :                                 const Real & value);
     407             : 
     408             :   /**
     409             :    * Get name of source bank file to write
     410             :    * @param[out] file name
     411             :    */
     412          40 :   std::string sourceBankFileName() const
     413             :   {
     414          80 :     return openmc::settings::path_output + "initial_source_" +
     415          80 :            std::to_string(_fixed_point_iteration) + ".h5";
     416             :   }
     417             : 
     418             :   /// Whether to print diagnostic information about model setup and the transfers
     419             :   const bool & _verbose;
     420             : 
     421             :   /// Power by which to normalize the OpenMC results, for k-eigenvalue mode
     422             :   const Real * _power;
     423             : 
     424             :   /// Source strength by which to normalize the OpenMC results, for fixed source mode
     425             :   const Real * _source_strength;
     426             : 
     427             :   /**
     428             :    * Whether to take the starting fission source from iteration \f$n\f$ as the
     429             :    * fission source converged from iteration \f$n-1\f$. Setting this to true will
     430             :    * in most cases lead to improved convergence of the initial source as iterations
     431             :    * progress because you don't "start from scratch" each iteration and do the same
     432             :    * identical (within a random number seed) converging of the fission source.
     433             :    */
     434             :   bool _reuse_source;
     435             : 
     436             :   /// Whether a mesh scaling was specified by the user
     437             :   const bool _specified_scaling;
     438             : 
     439             :   /**
     440             :    * Multiplicative factor to apply to the mesh in the [Mesh] block in order to convert
     441             :    * whatever units that mesh is in into OpenMC's length scale of centimeters. For instance,
     442             :    * it is commonplace to develop fuel performance models with a length scale of meters.
     443             :    * Rather than onerously convert all MOOSE inputs to which OpenMC will be coupled to units
     444             :    * of centimeters, this parameter allows us to scale the mesh we couple to OpenMC.
     445             :    * Note that this does not actually scale the mesh itself, but simply multiplies the mesh
     446             :    * coordinates by this parameter when identifying the mapping between elements and cells.
     447             :    *
     448             :    * By default, this parameter is set to 1.0, meaning that OpenMC is coupled to another
     449             :    * MOOSE application with an input written in terms of centimeters. Set this parameter to 100
     450             :    * if the coupled MOOSE application is in units of meters, for instance.
     451             :    *
     452             :    * To summarize by example - if the MOOSE application uses units of meters, with a mesh
     453             :    * named mesh.exo, then the OpenMC-wrapped input file should also use that mesh (with
     454             :    * units of meters) in its [Mesh] block (or perhaps a coarser version of that mesh if
     455             :    * the resolution of coupling does not need to match - the units just have to be the same).
     456             :    * Then, you should set 'scaling = 100.0' so that the mapping is performed correctly.
     457             :    */
     458             :   const Real & _scaling;
     459             : 
     460             :   /// Whether to skip writing statepoints from OpenMC
     461             :   const bool & _skip_statepoint;
     462             : 
     463             :   /**
     464             :    * Fixed point iteration index used in relaxation; because we sometimes run OpenMC
     465             :    * in a pseudo-transient coupling with NekRS, we simply increment this by 1 each
     466             :    * time we call openmc::run(). This uses a zero indexing, so after the first iteration,
     467             :    * we have finished iteration 0, and so on.
     468             :    */
     469             :   int _fixed_point_iteration;
     470             : 
     471             :   /// Total number of particles simulated
     472             :   unsigned int _total_n_particles;
     473             : 
     474             :   /// Total number of unique OpenMC cell IDs + instances combinations
     475             :   long unsigned int _n_openmc_cells;
     476             : 
     477             :   /**
     478             :    * Number of digits to use to display the cell ID for diagnostic messages; this is
     479             :    * estimated conservatively based on the total number of cells, even though there
     480             :    * may be distributed cells such that the maximum cell ID is far smaller than the
     481             :    * total number of cells.
     482             :    */
     483             :   int _n_cell_digits;
     484             : 
     485             :   /// OpenMC run mode
     486             :   openmc::RunMode _run_mode;
     487             : 
     488             :   /// Userobjects for changing OpenMC material compositions
     489             :   std::vector<OpenMCNuclideDensities *> _nuclide_densities_uos;
     490             : 
     491             :   /// Userobjects for creating/changing OpenMC filters
     492             :   std::vector<OpenMCDomainFilterEditor *> _filter_editor_uos;
     493             : 
     494             :   /// Userobjects for creating/changing OpenMC tallies
     495             :   std::vector<OpenMCTallyEditor *> _tally_editor_uos;
     496             : 
     497             :   /// Mapping from local element indices to global element indices for this rank
     498             :   std::vector<unsigned int> _local_to_global_elem;
     499             : 
     500             :   /// Whether or not the problem contains mesh adaptivity.
     501             :   const bool _has_adaptivity;
     502             : 
     503             :   /**
     504             :    * A flag which is set to true if OpenMC should rerun after an adaptivity cycle.
     505             :    * This is a performance optimization to avoid rerunning OpenMC if adaptivity
     506             :    * didn't refine/coarsen the mesh on the last cycle.
     507             :    */
     508             :   bool _run_on_adaptivity_cycle;
     509             : 
     510             :   /// A flag to indicate if OpenMC is calculating kinetics parameters.
     511             :   const bool _calc_kinetics_params;
     512             : 
     513             :   /// Whether to reset the seed each time a new OpenMC calculation runs
     514             :   const bool & _reset_seed;
     515             : 
     516             :   /// The initial OpenMC seed
     517             :   const int64_t _initial_seed;
     518             : 
     519             :   /// The index of a global tally to accumulate the scores required for kinetics parameters.
     520             :   int _ifp_tally_index = -1;
     521             : 
     522             :   /// The global tally used to accumulate the scores required for kinetics parameters.
     523             :   openmc::Tally * _ifp_tally = nullptr;
     524             : 
     525             :   /// Conversion unit to transfer between kg/m3 and g/cm3
     526             :   static constexpr Real _density_conversion_factor{0.001};
     527             : 
     528             :   /// ID used by OpenMC to indicate that a material fill is VOID
     529             :   static constexpr int MATERIAL_VOID{-1};
     530             : };

Generated by: LCOV version 1.14