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

Generated by: LCOV version 1.14