LCOV - code coverage report
Current view: top level - src/meshgenerators - CoarseMeshExtraElementIDGenerator.C (source / functions) Hit Total Coverage
Test: idaholab/moose reactor: #31405 (292dce) with base fef103 Lines: 79 80 98.8 %
Date: 2025-09-04 07:56:24 Functions: 3 3 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //* This file is part of the MOOSE framework
       2             : //* https://mooseframework.inl.gov
       3             : //*
       4             : //* All rights reserved, see COPYRIGHT for full restrictions
       5             : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
       6             : //*
       7             : //* Licensed under LGPL 2.1, please see LICENSE for details
       8             : //* https://www.gnu.org/licenses/lgpl-2.1.html
       9             : 
      10             : #include "CoarseMeshExtraElementIDGenerator.h"
      11             : #include "MooseMeshUtils.h"
      12             : 
      13             : #include "libmesh/enum_point_locator_type.h"
      14             : #include "libmesh/elem.h"
      15             : #include "libmesh/mesh_serializer.h"
      16             : 
      17             : using namespace libMesh;
      18             : 
      19             : registerMooseObject("ReactorApp", CoarseMeshExtraElementIDGenerator);
      20             : 
      21             : InputParameters
      22         114 : CoarseMeshExtraElementIDGenerator::validParams()
      23             : {
      24         114 :   InputParameters params = MeshGenerator::validParams();
      25         228 :   params.addRequiredParam<MeshGeneratorName>(
      26             :       "input", "Name of an existing mesh generator to which we assign coarse element IDs");
      27         228 :   params.addRequiredParam<MeshGeneratorName>(
      28             :       "coarse_mesh", "Name of an existing mesh generator as the coarse mesh");
      29         228 :   params.addRequiredParam<std::string>(
      30             :       "extra_element_id_name", "Name for the extra element ID that is added to the input mesh");
      31         228 :   params.addParam<std::string>(
      32             :       "coarse_mesh_extra_element_id",
      33             :       "Name for the extra element ID that is copied from the coarse mesh (default to element ID)");
      34         114 :   params.addParam<std::vector<SubdomainName>>(
      35         114 :       "subdomains", std::vector<SubdomainName>(), "Subdomains to apply extra element IDs to.");
      36         228 :   params.addParam<bool>("enforce_mesh_embedding",
      37         228 :                         false,
      38             :                         "True to error out when the input mesh is not embedded in the coarse mesh");
      39             : 
      40         114 :   params.addClassDescription("Assign coarse element IDs for elements on a "
      41             :                              "mesh based on a coarse mesh.");
      42         114 :   return params;
      43           0 : }
      44             : 
      45          57 : CoarseMeshExtraElementIDGenerator::CoarseMeshExtraElementIDGenerator(const InputParameters & params)
      46             :   : MeshGenerator(params),
      47          57 :     _input(getMesh("input")),
      48          57 :     _coarse_mesh(getMesh("coarse_mesh")),
      49         114 :     _coarse_id_name(getParam<std::string>("extra_element_id_name")),
      50         114 :     _using_coarse_element_id(isParamValid("coarse_mesh_extra_element_id")),
      51         171 :     _embedding_necessary(getParam<bool>("enforce_mesh_embedding"))
      52             : {
      53          57 : }
      54             : 
      55             : std::unique_ptr<MeshBase>
      56          57 : CoarseMeshExtraElementIDGenerator::generate()
      57             : {
      58          57 :   std::unique_ptr<MeshBase> mesh = std::move(_input);
      59             : 
      60             :   unsigned int coarse_id;
      61          57 :   const bool already_has_id = mesh->has_elem_integer(_coarse_id_name);
      62          57 :   if (!already_has_id)
      63          92 :     coarse_id = mesh->add_elem_integer(_coarse_id_name);
      64             :   else
      65          11 :     coarse_id = mesh->get_elem_integer_index(_coarse_id_name);
      66             : 
      67             :   // Get the requested subdomain IDs
      68             :   std::set<SubdomainID> included_subdomains;
      69             :   std::set<SubdomainName> bad_subdomains;
      70         140 :   for (const auto & snm : getParam<std::vector<SubdomainName>>("subdomains"))
      71             :   {
      72          26 :     auto sid = MooseMeshUtils::getSubdomainID(snm, *mesh);
      73          26 :     if (!MooseMeshUtils::hasSubdomainID(*mesh, sid))
      74           4 :       bad_subdomains.insert(snm);
      75             :     else
      76          22 :       included_subdomains.insert(sid);
      77             :   }
      78          57 :   if (!bad_subdomains.empty())
      79           2 :     paramError("subdomains",
      80             :                "The requested subdomains do not exist on the fine mesh: ",
      81           2 :                Moose::stringify(bad_subdomains));
      82             : 
      83             :   // If we are not going through the entire mesh and the ID already exists, we need to offset the
      84             :   // assigned ID so that we don't copy ones that are already there
      85             :   dof_id_type id_offset = 0;
      86          55 :   if (already_has_id && !included_subdomains.empty())
      87             :   {
      88        1818 :     for (auto & elem : mesh->active_element_ptr_range())
      89             :     {
      90         900 :       dof_id_type elem_id = elem->get_extra_integer(coarse_id);
      91         900 :       if (elem_id != DofObject::invalid_id && elem_id > id_offset)
      92             :         id_offset = elem_id;
      93           9 :     }
      94           9 :     id_offset++;
      95             :   }
      96             : 
      97          55 :   std::unique_ptr<MeshBase> coarse_mesh = std::move(_coarse_mesh);
      98             : 
      99             :   bool using_subdomain_id = false;
     100             :   unsigned int id_for_assignment = 0;
     101          55 :   if (_using_coarse_element_id)
     102             :   {
     103          20 :     const auto & id_name = getParam<std::string>("coarse_mesh_extra_element_id");
     104          20 :     if (id_name == "subdomain_id")
     105             :       using_subdomain_id = true;
     106             :     else
     107             :     {
     108             :       using_subdomain_id = false;
     109          11 :       if (!coarse_mesh->has_elem_integer(id_name))
     110           2 :         paramError("coarse_mesh_extra_element_id",
     111             :                    "The extra element ID does not exist on the coarse mesh");
     112             :       else
     113           9 :         id_for_assignment = coarse_mesh->get_elem_integer_index(id_name);
     114             :     }
     115             :   }
     116             : 
     117             :   // a relative tolerance on checking if fine mesh is embedded in the coarse mesh
     118          53 :   Real aeps = 0.01;
     119             : 
     120             :   // The coarse mesh is serialized for distributed mesh to avoid boundary issues.
     121             :   // As it is coarse this should be cheap. This will be a null operation for a replicated mesh.
     122          53 :   MeshSerializer tm(*coarse_mesh);
     123             : 
     124             :   // build a point_locator on coarse mesh
     125             :   std::unique_ptr<PointLocatorBase> point_locator =
     126          53 :       PointLocatorBase::build(TREE_ELEMENTS, *coarse_mesh);
     127          53 :   point_locator->enable_out_of_mesh_mode();
     128             : 
     129             :   // loop through fine mesh elements and get element's centroid
     130             :   auto elem_range = included_subdomains.empty()
     131          53 :                         ? mesh->active_element_ptr_range()
     132          73 :                         : mesh->active_subdomain_set_elements_ptr_range(included_subdomains);
     133        5569 :   for (auto & elem : elem_range)
     134             :   {
     135             :     // Get the centroid of the fine elem
     136        2764 :     Point centroid = elem->true_centroid();
     137             : 
     138             :     // Find coarse elem
     139        2764 :     const Elem * coarse_elem = (*point_locator)(centroid);
     140        2764 :     if (!coarse_elem)
     141           2 :       mooseError("Could not find a coarse element containing a fine element with centroid ",
     142             :                  centroid);
     143             : 
     144             :     // get id from the coarse element
     145             :     dof_id_type elem_id;
     146        2762 :     if (_using_coarse_element_id)
     147             :     {
     148        1152 :       if (using_subdomain_id)
     149         576 :         elem_id = coarse_elem->subdomain_id();
     150             :       else
     151         576 :         elem_id = coarse_elem->get_extra_integer(id_for_assignment);
     152             :     }
     153             :     else
     154             :       elem_id = coarse_elem->id();
     155        2762 :     elem_id += id_offset;
     156             : 
     157             :     // Check if the fine elem is nested in the coarse element
     158       13798 :     for (unsigned int n = 0; n < elem->n_nodes(); n++)
     159             :     {
     160             :       // Get the node: we need to manually move it towards the centroid to
     161             :       // ensure that nothing weird happes due to round-off
     162       11040 :       Point current_node = elem->point(n);
     163       11040 :       current_node.add_scaled(current_node, -aeps);
     164       11040 :       current_node.add_scaled(centroid, aeps);
     165             : 
     166             :       // Get the element this node is in and check if it is the same
     167             :       // as the coarse elem; however check if node_elem is valid as it
     168             :       // might not be in case the sub element it outside the coarse domain
     169       11040 :       const Elem * node_elem = (*point_locator)(current_node);
     170       11040 :       if (!node_elem)
     171           2 :         mooseError("Could not find a coarse element containing a node of fine element at ",
     172             :                    elem->point(n));
     173             : 
     174             :       // get another id from the coarse element with this node
     175             :       dof_id_type node_elem_id;
     176       11038 :       if (_using_coarse_element_id)
     177             :       {
     178        4608 :         if (using_subdomain_id)
     179        2304 :           node_elem_id = node_elem->subdomain_id();
     180             :         else
     181        2304 :           node_elem_id = node_elem->get_extra_integer(id_for_assignment);
     182             :       }
     183             :       else
     184             :         node_elem_id = node_elem->id();
     185             : 
     186       11038 :       if (node_elem_id != elem_id)
     187        3114 :         if (_embedding_necessary)
     188           2 :           mooseError(
     189             :               "Input mesh is not nested in the coarse mesh in CoarseMeshExtraElementIDGenerator.");
     190             :     }
     191             : 
     192        2758 :     elem->set_extra_integer(coarse_id, elem_id);
     193             :   }
     194             : 
     195          47 :   return mesh;
     196          47 : }

Generated by: LCOV version 1.14