LCOV - code coverage report
Current view: top level - include/userobjects - MoabSkinner.h (source / functions) Hit Total Coverage
Test: neams-th-coe/cardinal: be601f Lines: 8 10 80.0 %
Date: 2025-07-15 20:50:38 Functions: 7 9 77.8 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : #pragma once
       2             : 
       3             : #include "GeneralUserObject.h"
       4             : #include "MaterialBase.h"
       5             : #include "MooseMesh.h"
       6             : 
       7             : #include "moab/Core.hpp"
       8             : #include "moab/Skinner.hpp"
       9             : #include "moab/GeomTopoTool.hpp"
      10             : #include "MBTagConventions.hpp"
      11             : 
      12             : /**
      13             :  * \brief Skins the [Mesh] according to individual bins for temperature, density, and subdomain ID
      14             :  *
      15             :  * Skins a [Mesh] according to temperature, density, and subdomain. The MOAB surfaces bounding
      16             :  * those grouped elements are then generated, providing geometry information needed for DAGMC
      17             :  * to then track particles on this new geometry.
      18             :  */
      19             : class MoabSkinner : public GeneralUserObject
      20             : {
      21             : public:
      22             :   MoabSkinner(const InputParameters & parameters);
      23             : 
      24             :   static InputParameters validParams();
      25             : 
      26             :   virtual void execute() override;
      27             : 
      28             :   virtual void initialize() override;
      29             : 
      30             :   virtual void finalize() override;
      31             : 
      32           0 :   virtual void threadJoin(const UserObject & /* uo */) override {}
      33             : 
      34             :   /**
      35             :    * Wrap the error handling in MOAB to print errors to user
      36             :    * @param[in] input MOAB error code
      37             :    * @return error mode
      38             :    */
      39             :   virtual moab::ErrorCode check(const moab::ErrorCode input) const;
      40             : 
      41             :   std::string materialName(const unsigned int & block, const unsigned int & density, const unsigned int & temp) const;
      42             : 
      43             :   /// Perform the skinning operation
      44             :   virtual void update();
      45             : 
      46             :   /**
      47             :    * Set the names to be used for naming the subdomains in the skinned mesh;
      48             :    * there should be one name per subdomain.
      49             :    * @param[in] names names for subdomains
      50             :    */
      51          13 :   virtual void setMaterialNames(std::vector<std::string> names) { _material_names = names; }
      52             : 
      53             :   /**
      54             :    * Get the total number of bins
      55             :    * @return total number of bins
      56             :    */
      57             :   unsigned int nBins() const;
      58             : 
      59             :   /**
      60             :    * Get the bin index for the temperature
      61             :    * @param[in] elem element
      62             :    * @return temperature bin index
      63             :    */
      64             :   virtual unsigned int getTemperatureBin(const Elem * const elem) const;
      65             : 
      66             :   /**
      67             :    * Get the bin index for the density
      68             :    * @param[in] elem element
      69             :    * @return density bin index
      70             :    */
      71             :   virtual unsigned int getDensityBin(const Elem * const elem) const;
      72             : 
      73             :   /**
      74             :    * Get the bin index for the subdomain
      75             :    * @param[in] elem element
      76             :    * @return subdomain bin index
      77             :    */
      78       48580 :   virtual unsigned int getSubdomainBin(const Elem * const elem) const
      79             :   {
      80       48580 :     return _blocks.at(elem->subdomain_id());
      81             :   }
      82             : 
      83             :   /**
      84             :    * Override the user parameter for use_displaced
      85             :    * @param[in] use whether to use the displaced mesh
      86             :    */
      87             :   void setUseDisplacedMesh(const bool & use);
      88             : 
      89             :   /**
      90             :    * Set the length multiplier to get from [Mesh] units into centimeters
      91             :    * @param[in] scale multiplier
      92             :    */
      93          14 :   virtual void setScaling(const Real & scale) { _scaling = scale; }
      94             : 
      95             :   /**
      96             :    * Set the verbosity level
      97             :    * @param[in] verbose whether to print diagnostic information
      98             :    */
      99          14 :   virtual void setVerbosity(const bool & verbose) { _verbose = verbose; }
     100             : 
     101             :   /**
     102             :    * Indicate whether this userobject is run by itself (for testing purposes)
     103             :    * or controlled by some other class.
     104             :    */
     105          14 :   virtual void makeDependentOnExternalAction() { _standalone = false; }
     106             : 
     107             :   /**
     108             :    * Get variable number in the auxiliary system
     109             :    * @param[in] name variable name
     110             :    * @param[in] param_name parameter name, for printing a helpful error message
     111             :    * @return variable number
     112             :    */
     113             :   unsigned int getAuxiliaryVariableNumber(const std::string & name,
     114             :                                           const std::string & param_name) const;
     115             : 
     116             :   /// Clear mesh data
     117             :   void reset();
     118             : 
     119             :   /**
     120             :    * Get total bin index given individual indices for the temperature, density, and subdomain bins
     121             :    * @param[in] temp_bin temperature bin
     122             :    * @param[in] density_bin density bin
     123             :    * @param[in] subdomain_bin subdomain ID bin
     124             :    * @return total bin index
     125             :    */
     126             :   virtual unsigned int getBin(const unsigned int & temp_bin,
     127             :                               const unsigned int & density_bin,
     128             :                               const unsigned int & subdomain_bin) const;
     129             : 
     130             :   /**
     131             :    * Whether the skinner builds a graveyard
     132             :    * @return whether a graveyard is built
     133             :    */
     134           0 :   virtual const bool & hasGraveyard() const { return _build_graveyard; }
     135             : 
     136             :   /**
     137             :    * Set the graveyard setting
     138             :    * @param[in] build whether to build a graveyard
     139             :    */
     140             :   void setGraveyard(bool build);
     141             : 
     142             :   /**
     143             :    * Number of density bins; if greater than 1, this means we must be re-generating
     144             :    * OpenMC materials during the course of the simulation.
     145             :    * @return number of density bins
     146             :    */
     147          29 :   virtual unsigned int nDensityBins() const { return _n_density_bins; }
     148             : 
     149             :   /**
     150             :    * Whether density skinning is applied
     151             :    * @return using density skinning
     152             :    */
     153          17 :   virtual bool hasDensitySkinning() const { return _bin_by_density; }
     154             : 
     155             :   /**
     156             :    * Get pointer to underlying moab interface
     157             :    * @return pointer to moab interface
     158             :    */
     159             :   const std::shared_ptr<moab::Interface> & moabPtr() const { return _moab; }
     160             : 
     161             : protected:
     162             :   std::unique_ptr<NumericVector<Number>> _serialized_solution;
     163             : 
     164             :   /// MOAB interface
     165             :   std::shared_ptr<moab::Interface> _moab;
     166             : 
     167             :   /// Whether to print diagnostic information
     168             :   bool _verbose;
     169             : 
     170             :   /// Name of the temperature variable
     171             :   const std::string & _temperature_name;
     172             : 
     173             :   /// Lower bound of temperature bins
     174             :   const Real & _temperature_min;
     175             : 
     176             :   /// Upper bound of temperature bins
     177             :   const Real & _temperature_max;
     178             : 
     179             :   /// Number of temperature bins
     180             :   const unsigned int & _n_temperature_bins;
     181             : 
     182             :   /// Temperature bin width
     183             :   const Real _temperature_bin_width;
     184             : 
     185             :   /// Whether elements are binned by density (in addition to temperature and block)
     186             :   const bool _bin_by_density;
     187             : 
     188             :   /// Material names corresponding to each subdomain. These are used to name the
     189             :   /// new skinned volumes in MOAB
     190             :   std::vector<std::string> _material_names;
     191             : 
     192             :   /// Faceting tolerence needed by DAGMC
     193             :   const Real & _faceting_tol;
     194             : 
     195             :   /// Geometry tolerence needed by DAGMC
     196             :   const Real & _geom_tol;
     197             : 
     198             :   /// Multiplier on bounding box for inner surface of graveyard
     199             :   const Real & _graveyard_scale_inner;
     200             : 
     201             :   /// Multiplier on bounding box for outer surface of graveyard
     202             :   const Real & _graveyard_scale_outer;
     203             : 
     204             :   /// Whether to output the MOAB mesh skins to a .h5m file
     205             :   const bool & _output_skins;
     206             : 
     207             :   /// Whether to output the MOAB mesh to a .h5m file
     208             :   const bool & _output_full;
     209             : 
     210             :   /**
     211             :    * Whether to build a graveyard as two additional cube surfaces surrounding the mesh.
     212             :    * This is only needed if the skinned geometry is fed into a Monte Carlo code.
     213             :    */
     214             :   bool _build_graveyard;
     215             : 
     216             :   /// Whether the skinned mesh should be generated from a displaced mesh
     217             :   bool _use_displaced;
     218             : 
     219             :   /// Length multiplier to get from [Mesh] units into OpenMC's centimeters
     220             :   Real _scaling;
     221             : 
     222             :   /// Count number of times output files have been written
     223             :   unsigned int _n_write;
     224             : 
     225             :   /// Whether this class runs by itself, or is controlled by an external class
     226             :   bool _standalone;
     227             : 
     228             :   /// Encode the whether the surface normal faces into or out of the volume
     229             :   enum Sense
     230             :   {
     231             :     BACKWARDS = -1,
     232             :     FORWARDS = 1
     233             :   };
     234             : 
     235             :   /// Encode MOAB information about volumes needed when creating surfaces
     236             :   struct VolData
     237             :   {
     238             :     moab::EntityHandle vol;
     239             :     Sense sense;
     240             :   };
     241             : 
     242             :   /// Moose mesh
     243             :   MooseMesh & getMooseMesh();
     244             :   /**
     245             :    * Copy the libMesh [Mesh] into a MOAB mesh. This first loops through all of the
     246             :    * nodes, and rebuilds each as a MOAB vertex. Then, we loop over all of the elements
     247             :    * and rebuild each as a TET4 (if the libMesh mesh has TET10 elements, they are each
     248             :    * rebuilt into 8 TET4 elements).
     249             :    */
     250             :   void createMOABElems();
     251             : 
     252             :   /// Helper method to create MOAB tags
     253             :   virtual void createTags();
     254             : 
     255             :   /**
     256             :    * Helper method to create MOAB group entity set
     257             :    * @param[in] id ID for the group
     258             :    * @param[in] name name for the group
     259             :    * @param[in] group_set group of entities
     260             :    */
     261             :   void createGroup(const unsigned int & id, const std::string & name, moab::EntityHandle & group_set);
     262             : 
     263             :   /// Helper method to create MOAB volume entity set
     264             :   void createVol(const unsigned int & id, moab::EntityHandle & volume_set, moab::EntityHandle group_set);
     265             : 
     266             :   /// Helper method to create MOAB surface entity set
     267             :   void createSurf(const unsigned int & id,
     268             :                   moab::EntityHandle & surface_set,
     269             :                   moab::Range & faces,
     270             :                   const std::vector<VolData> & voldata);
     271             : 
     272             :   /// Helper method to create MOAB surfaces with no overlaps
     273             :   void createSurfaces(moab::Range & reversed, VolData & voldata, unsigned int & surf_id);
     274             : 
     275             :   /**
     276             :    * Create a MOAB surface from a bounding box
     277             :    */
     278             :   void createSurfaceFromBox(const BoundingBox & box,
     279             :                             const VolData & voldata,
     280             :                             unsigned int & surf_id,
     281             :                             bool normalout,
     282             :                             const Real & factor);
     283             : 
     284             :   /**
     285             :    * Create MOAB nodes from a bounding box
     286             :    * @param[in] box bounding box
     287             :    * @param[in] factor multiplicative factor to resize the bounding box sides
     288             :    * @return nodes
     289             :    */
     290             :   std::vector<moab::EntityHandle> createNodesFromBox(const BoundingBox & box,
     291             :                                                      const Real & factor) const;
     292             : 
     293             :   /// Create 3 tri faces stemming from one corner of a cude (an open tetrahedron)
     294             :   void createCornerTris(const std::vector<moab::EntityHandle> & verts,
     295             :                         unsigned int corner,
     296             :                         unsigned int v1,
     297             :                         unsigned int v2,
     298             :                         unsigned int v3,
     299             :                         bool normalout,
     300             :                         moab::Range & surface_tris);
     301             : 
     302             :   /// Create MOAB tri surface element
     303             :   moab::EntityHandle createTri(const std::vector<moab::EntityHandle> & vertices,
     304             :                                unsigned int v1,
     305             :                                unsigned int v2,
     306             :                                unsigned int v3);
     307             : 
     308             :   /// Add parent-child metadata relating a surface to its volume
     309             :   void updateSurfData(moab::EntityHandle surface_set, const VolData & data);
     310             : 
     311             :   /// Generic method to set the tags that DAGMC requires
     312             :   void
     313             :   setTags(moab::EntityHandle ent, std::string name, std::string category, unsigned int id, int dim);
     314             : 
     315             :   /// Helper function to wrap moab::tag_set_data for a string
     316             :   void setTagData(moab::Tag tag, moab::EntityHandle ent, std::string data, unsigned int SIZE);
     317             : 
     318             :   /// Helper function to wrap moab::tag_set_data for a generic pointer
     319             :   void setTagData(moab::Tag tag, moab::EntityHandle ent, void * data);
     320             : 
     321             :   /**
     322             :    * Get the node numberings for the MOAB TET4 elements to build for each [Mesh] element
     323             :    * @param[in] type element type
     324             :    */
     325             :   const std::vector<std::vector<unsigned int>> & getTetSets(ElemType type) const;
     326             : 
     327             :   /**
     328             :    * \brief Build a graveyard volume around the domain
     329             :    *
     330             :    * The graveyard is a containing volume which bounds the volume of interest. This is
     331             :    * only needed if the skinned geometry is going to be input into a Monte Carlo solver. For
     332             :    * performance reasons, a cubic shell is optimal. So, here we build two cubic surfaces,
     333             :    * both larger than the bounding box of the "actual" geometry. We name this region
     334             :    * "mat:Graveyard", so that when OpenMC parses the geometry it knows to assign "void"
     335             :    * to this region, and set vacuum BCs on the outer surfaces of the cubic shell. The
     336             :    * remaining space between the "actual" geometry and the inner graveyard surface is
     337             :    * treated as the implicit complement of the rest of the geometry (e.g. a transmissive region).
     338             :    */
     339             :   void buildGraveyard(unsigned int & vol_id, unsigned int & surf_id);
     340             : 
     341             :   /// Store a mapping from [Mesh] subdomain IDs to an index, to be used for binning by block ID
     342             :   virtual void findBlocks();
     343             : 
     344             :   /// Sort all the elements in the [Mesh] into bins for temperature, density, and subdomain.
     345             :   virtual void sortElemsByResults();
     346             : 
     347             :   /// Group the binned elems into local temperature regions and find their surfaces
     348             :   void findSurfaces();
     349             : 
     350             :   /// Group a given bin into local regions
     351             :   /// NB elems in param is a copy, localElems is a reference
     352             :   void groupLocalElems(std::set<dof_id_type> elems, std::vector<moab::Range> & localElems);
     353             : 
     354             :   /// Clear MOAB entity sets
     355             :   bool resetMOAB();
     356             : 
     357             :   /// Find the surfaces for the provided range and add to group
     358             :   void findSurface(const moab::Range & region,
     359             :                    moab::EntityHandle group,
     360             :                    unsigned int & vol_id,
     361             :                    unsigned int & surf_id,
     362             :                    moab::EntityHandle & volume_set);
     363             : 
     364             :   /// Write MOAB volume and/or skin meshes to file
     365             :   virtual void write();
     366             : 
     367             :   /// Moab skinner for finding temperature surfaces
     368             :   std::unique_ptr<moab::Skinner> skinner;
     369             : 
     370             :   /// Topology tool for setting surface sense
     371             :   std::unique_ptr<moab::GeomTopoTool> gtt;
     372             : 
     373             :   /// Map from libmesh id to MOAB element entity handles
     374             :   std::map<dof_id_type, std::vector<moab::EntityHandle>> _id_to_elem_handles;
     375             : 
     376             :   /// Save the first tet entity handle
     377             :   moab::EntityHandle offset;
     378             : 
     379             :   /// Name of the MOOSE variable containing the density
     380             :   std::string _density_name;
     381             : 
     382             :   /// Lower bound of density bins
     383             :   Real _density_min;
     384             : 
     385             :   /// Upper bound of density bins
     386             :   Real _density_max;
     387             : 
     388             :   /// Density bin width
     389             :   Real _density_bin_width;
     390             : 
     391             :   /// Number of density bins
     392             :   unsigned int _n_density_bins;
     393             : 
     394             :   /// Number of block bins
     395             :   unsigned int _n_block_bins;
     396             : 
     397             :   /// Mapping from total bin ID to a set of elements sorted into that bin
     398             :   std::vector<std::set<dof_id_type>> _elem_bins;
     399             : 
     400             :   /// Blocks in the [Mesh]
     401             :   std::map<SubdomainID, unsigned int> _blocks;
     402             : 
     403             :   /// Entity handle to represent the set of all tets
     404             :   moab::EntityHandle _all_tets;
     405             : 
     406             :   /// Save some topological data: map from surface handle to vol handle and sense
     407             :   std::map<moab::EntityHandle, std::vector<VolData>> surfsToVols;
     408             : 
     409             :   /// Tag for dimension for geometry
     410             :   moab::Tag geometry_dimension_tag;
     411             : 
     412             :   /// Tag for entitiy set ID
     413             :   moab::Tag id_tag;
     414             : 
     415             :   /// Tag for faceting tolerance
     416             :   moab::Tag faceting_tol_tag;
     417             : 
     418             :   /// Tag needed by DAGMC
     419             :   moab::Tag geometry_resabs_tag;
     420             : 
     421             :   /// Tag for type of entity set
     422             :   moab::Tag category_tag;
     423             : 
     424             :   /// Tag for name of entity set
     425             :   moab::Tag name_tag;
     426             : 
     427             :   /// Bounds of the temperature bins
     428             :   std::vector<Real> _temperature_bin_bounds;
     429             : 
     430             :   /// Bounds of the density bins
     431             :   std::vector<Real> _density_bin_bounds;
     432             : 
     433             :   /// Node ordering for a TET4 MOAB element, based on libMesh node numberings
     434             :   std::vector<std::vector<unsigned int>> _tet4_nodes;
     435             : 
     436             :   /**
     437             :    * Node ordering for eight TET4 MOAB elements, based on libMesh node numberings
     438             :    * for a TET10 element. We re-build the libMesh element into first-order MOAB elements.
     439             :    */
     440             :   std::vector<std::vector<unsigned int>> _tet10_nodes;
     441             : 
     442             :   /// Auxiliary variable number for temperature
     443             :   unsigned int _temperature_var_num;
     444             : 
     445             :   /// Auxiliary variable number for density
     446             :   unsigned int _density_var_num;
     447             : 
     448             :   /// Number of nodes per MOAB tet (which are first order, so TET4)
     449             :   const unsigned int NODES_PER_MOAB_TET = 4;
     450             : 
     451             :   /// Tolerance to use for comparing values to bin bounds
     452             :   const Real BIN_TOLERANCE = 1e-6;
     453             : };

Generated by: LCOV version 1.14