LCOV - code coverage report
Current view: top level - src/meshgenerators - SideSetsAroundSubdomainGenerator.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: #32971 (54bef8) with base c6cf66 Lines: 87 90 96.7 %
Date: 2026-05-29 20:35:17 Functions: 4 4 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 "SideSetsAroundSubdomainGenerator.h"
      11             : #include "InputParameters.h"
      12             : #include "MooseTypes.h"
      13             : #include "MeshTraversingUtils.h"
      14             : #include "MooseMeshUtils.h"
      15             : #include "CastUniquePointer.h"
      16             : 
      17             : #include "libmesh/mesh.h"
      18             : #include "libmesh/remote_elem.h"
      19             : #include "libmesh/point.h"
      20             : #include "libmesh/fe_base.h"
      21             : 
      22             : registerMooseObject("MooseApp", SideSetsAroundSubdomainGenerator);
      23             : 
      24             : InputParameters
      25        5143 : SideSetsAroundSubdomainGenerator::validParams()
      26             : {
      27        5143 :   InputParameters params = SideSetsGeneratorBase::validParams();
      28             : 
      29       30858 :   params.renameParam("included_subdomains", "block", "The blocks around which to create sidesets");
      30       10286 :   params.makeParamRequired<std::vector<SubdomainName>>("block");
      31             : 
      32             :   // Not implemented, but could be implemented
      33       10286 :   params.suppressParameter<std::vector<BoundaryName>>("included_boundaries");
      34       10286 :   params.suppressParameter<std::vector<BoundaryName>>("excluded_boundaries");
      35       10286 :   params.suppressParameter<std::vector<SubdomainName>>("included_neighbors");
      36             : 
      37        5143 :   params.addClassDescription(
      38             :       "Adds element faces that are on the exterior of the given block to the sidesets specified");
      39             : 
      40        5143 :   return params;
      41           0 : }
      42             : 
      43        1038 : SideSetsAroundSubdomainGenerator::SideSetsAroundSubdomainGenerator(
      44        1038 :     const InputParameters & parameters)
      45        1038 :   : SideSetsGeneratorBase(parameters)
      46             : {
      47        1038 : }
      48             : 
      49             : std::unique_ptr<MeshBase>
      50         969 : SideSetsAroundSubdomainGenerator::generate()
      51             : {
      52         969 :   std::unique_ptr<MeshBase> mesh = std::move(_input);
      53             : 
      54             :   // construct the FE object so we can compute normals of faces
      55         969 :   setup(*mesh);
      56             : 
      57             :   // Create the boundary IDs from the list of names provided (the true flag creates ids from unknown
      58             :   // names)
      59             :   std::vector<boundary_id_type> boundary_ids =
      60         966 :       MooseMeshUtils::getBoundaryIDs(*mesh, _boundary_names, true);
      61             : 
      62             :   // Get a reference to our BoundaryInfo object for later use
      63         966 :   BoundaryInfo & boundary_info = mesh->get_boundary_info();
      64             : 
      65             :   // Prepare to query about sides adjacent to remote elements if we're
      66             :   // on a distributed mesh
      67         966 :   const processor_id_type my_n_proc = mesh->n_processors();
      68         966 :   const processor_id_type my_proc_id = mesh->processor_id();
      69             :   typedef std::vector<std::pair<dof_id_type, unsigned int>> vec_type;
      70         966 :   std::vector<vec_type> queries(my_n_proc);
      71             : 
      72             :   // Request to compute normal vectors
      73         966 :   const std::vector<Point> & face_normals = _fe_face->get_normals();
      74             : 
      75             :   // Loop over the elements
      76       91315 :   for (const auto & elem : mesh->active_element_ptr_range())
      77             :   {
      78             :     // We only need to loop over elements in the source subdomain
      79      180698 :     if (_check_subdomains &&
      80       90349 :         !MeshTraversingUtils::elementSubdomainIdInList(elem, _included_subdomain_ids))
      81       48187 :       continue;
      82             : 
      83      214840 :     for (const auto side : make_range(elem->n_sides()))
      84             :     {
      85      172678 :       const auto * neighbor = elem->neighbor_ptr(side);
      86             : 
      87             :       // On a replicated mesh, we add all subdomain sides ourselves.
      88             :       // On a distributed mesh, we may have missed sides which
      89             :       // neighbor remote elements.  We should query any such cases.
      90      172678 :       if (neighbor == remote_elem)
      91             :       {
      92         126 :         queries[elem->processor_id()].push_back(std::make_pair(elem->id(), side));
      93             :       }
      94      172552 :       else if (elemSideOnBoundary(elem, side))
      95             :       {
      96       32832 :         _fe_face->reinit(elem, side);
      97             :         // We'll just use the normal of the first qp
      98       32832 :         const Point & face_normal = face_normals[0];
      99             :         // Add the boundaries, if appropriate
     100       32832 :         if (elemSideSatisfiesRequirements(elem, side, *mesh, _normal, face_normal))
     101             :         {
     102        9540 :           if (_replace)
     103           0 :             boundary_info.remove_side(elem, side);
     104       19080 :           for (const auto & boundary_id : boundary_ids)
     105        9540 :             boundary_info.add_side(elem, side, boundary_id);
     106             :         }
     107             :       }
     108             :     }
     109         966 :   }
     110             : 
     111         966 :   if (!mesh->is_serial())
     112             :   {
     113          40 :     const auto queries_tag = mesh->comm().get_unique_tag(),
     114          40 :                replies_tag = mesh->comm().get_unique_tag();
     115             : 
     116         120 :     std::vector<Parallel::Request> side_requests(my_n_proc - 1), reply_requests(my_n_proc - 1);
     117             : 
     118             :     // Make all requests
     119         180 :     for (processor_id_type p = 0; p != my_n_proc; ++p)
     120             :     {
     121         140 :       if (p == my_proc_id)
     122          40 :         continue;
     123             : 
     124         100 :       Parallel::Request & request = side_requests[p - (p > my_proc_id)];
     125             : 
     126         100 :       mesh->comm().send(p, queries[p], request, queries_tag);
     127             :     }
     128             : 
     129             :     // Reply to all requests
     130          40 :     std::vector<vec_type> responses(my_n_proc - 1);
     131             : 
     132         140 :     for (processor_id_type p = 1; p != my_n_proc; ++p)
     133             :     {
     134         100 :       vec_type query;
     135             : 
     136         100 :       Parallel::Status status(mesh->comm().probe(Parallel::any_source, queries_tag));
     137         100 :       const processor_id_type source_pid = cast_int<processor_id_type>(status.source());
     138             : 
     139         100 :       mesh->comm().receive(source_pid, query, queries_tag);
     140             : 
     141         100 :       Parallel::Request & request = reply_requests[p - 1];
     142             : 
     143         226 :       for (const auto & q : query)
     144             :       {
     145         126 :         const Elem * elem = mesh->elem_ptr(q.first);
     146         126 :         const unsigned int side = q.second;
     147             : 
     148         126 :         _fe_face->reinit(elem, side);
     149             :         // We'll just use the normal of the first qp
     150         126 :         const Point & face_normal = _fe_face->get_normals()[0];
     151         138 :         if (elemSideOnBoundary(elem, side) &&
     152          12 :             elemSideSatisfiesRequirements(elem, side, *mesh, _normal, face_normal))
     153           3 :           responses[p - 1].push_back(std::make_pair(elem->id(), side));
     154             :       }
     155             : 
     156         100 :       mesh->comm().send(source_pid, responses[p - 1], request, replies_tag);
     157         100 :     }
     158             : 
     159             :     // Process all incoming replies
     160         140 :     for (processor_id_type p = 1; p != my_n_proc; ++p)
     161             :     {
     162         100 :       Parallel::Status status(this->comm().probe(Parallel::any_source, replies_tag));
     163         100 :       const processor_id_type source_pid = cast_int<processor_id_type>(status.source());
     164             : 
     165         100 :       vec_type response;
     166             : 
     167         100 :       this->comm().receive(source_pid, response, replies_tag);
     168             : 
     169         103 :       for (const auto & r : response)
     170             :       {
     171           3 :         const Elem * elem = mesh->elem_ptr(r.first);
     172           3 :         const unsigned int side = r.second;
     173             : 
     174           3 :         if (_replace)
     175           0 :           boundary_info.remove_side(elem, side);
     176           6 :         for (const auto & boundary_id : boundary_ids)
     177           3 :           boundary_info.add_side(elem, side, boundary_id);
     178             :       }
     179         100 :     }
     180             : 
     181          40 :     Parallel::wait(side_requests);
     182          40 :     Parallel::wait(reply_requests);
     183          40 :   }
     184             : 
     185             :   // Assign the supplied names to the newly created side sets
     186        1932 :   for (unsigned int i = 0; i < boundary_ids.size(); ++i)
     187         966 :     boundary_info.sideset_name(boundary_ids[i]) = _boundary_names[i];
     188             : 
     189         966 :   mesh->unset_is_prepared();
     190        1932 :   return dynamic_pointer_cast<MeshBase>(mesh);
     191         966 : }
     192             : 
     193             : bool
     194      172678 : SideSetsAroundSubdomainGenerator::elemSideOnBoundary(const Elem * const elem,
     195             :                                                      const unsigned int side) const
     196             : {
     197      172678 :   const auto neighbor = elem->neighbor_ptr(side);
     198      172678 :   return (neighbor == nullptr) || (elem->subdomain_id() != neighbor->subdomain_id());
     199             : }

Generated by: LCOV version 1.14