LCOV - code coverage report
Current view: top level - src/meshgenerators - ExtraNodesetGenerator.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 2bf808 Lines: 77 85 90.6 %
Date: 2025-07-17 01:28:37 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 "ExtraNodesetGenerator.h"
      11             : #include "MooseMesh.h"
      12             : #include "Conversion.h"
      13             : #include "MooseMeshUtils.h"
      14             : #include "CastUniquePointer.h"
      15             : 
      16             : #include "libmesh/elem.h"
      17             : 
      18             : registerMooseObject("MooseApp", ExtraNodesetGenerator);
      19             : 
      20             : InputParameters
      21       14753 : ExtraNodesetGenerator::validParams()
      22             : {
      23       14753 :   InputParameters params = MeshGenerator::validParams();
      24             : 
      25       14753 :   params.addRequiredParam<MeshGeneratorName>("input", "The mesh we want to modify");
      26       14753 :   params.addRequiredParam<std::vector<BoundaryName>>("new_boundary",
      27             :                                                      "The names of the boundaries to create");
      28             : 
      29       14753 :   params.addParam<std::vector<unsigned int>>("nodes",
      30             :                                              "The nodes you want to be in the nodeset "
      31             :                                              "(Either this parameter or \"coord\" must be "
      32             :                                              "supplied).");
      33       14753 :   params.addParam<std::vector<std::vector<Real>>>(
      34             :       "coord",
      35             :       {},
      36             :       "The nodes with coordinates you want to be in the "
      37             :       "nodeset. Separate multple coords with ';' (Either this parameter or \"nodes\" must be "
      38             :       "supplied).");
      39       14753 :   params.addParam<Real>(
      40             :       "tolerance", TOLERANCE, "The tolerance in which two nodes are considered identical");
      41       14753 :   params.addParam<bool>("use_closest_node", false, "Use the node closest to the coordinate.");
      42       14753 :   params.addClassDescription(
      43             :       "Creates a new node set and a new boundary made with the nodes the user provides.");
      44             : 
      45       14753 :   return params;
      46           0 : }
      47             : 
      48         244 : ExtraNodesetGenerator::ExtraNodesetGenerator(const InputParameters & parameters)
      49         244 :   : MeshGenerator(parameters), _input(getMesh("input"))
      50             : {
      51         244 : }
      52             : 
      53             : std::unique_ptr<MeshBase>
      54         232 : ExtraNodesetGenerator::generate()
      55             : {
      56         232 :   std::unique_ptr<MeshBase> mesh = std::move(_input);
      57             : 
      58             :   // Get the BoundaryIDs from the mesh
      59         232 :   std::vector<BoundaryName> boundary_names = getParam<std::vector<BoundaryName>>("new_boundary");
      60             :   std::vector<boundary_id_type> boundary_ids =
      61         232 :       MooseMeshUtils::getBoundaryIDs(*mesh, boundary_names, true);
      62             : 
      63             :   // Get a reference to our BoundaryInfo object
      64         232 :   BoundaryInfo & boundary_info = mesh->get_boundary_info();
      65             : 
      66             :   // add nodes with their ids
      67         232 :   if (isParamValid("nodes"))
      68         294 :     for (const auto & node_id : getParam<std::vector<unsigned int>>("nodes"))
      69             :     {
      70             :       // Our mesh may be distributed and this node may not exist on this process
      71         147 :       if (!mesh->query_node_ptr(node_id))
      72           0 :         continue;
      73             : 
      74         294 :       for (const auto & boundary_id : boundary_ids)
      75         147 :         boundary_info.add_node(node_id, boundary_id);
      76             :     }
      77             : 
      78             :   // add nodes with their coordinates
      79         232 :   const auto dim = mesh->mesh_dimension();
      80             : 
      81         232 :   std::unique_ptr<libMesh::PointLocatorBase> locator = mesh->sub_point_locator();
      82         232 :   locator->enable_out_of_mesh_mode();
      83             : 
      84         232 :   const auto tolerance = getParam<Real>("tolerance");
      85         232 :   const bool use_closest_node = getParam<bool>("use_closest_node");
      86         232 :   const auto coords = getParam<std::vector<std::vector<Real>>>("coord");
      87         232 :   if (use_closest_node && coords.empty())
      88           0 :     paramError("coord", "A coordinate should be specified to use 'use_closest_node'");
      89         353 :   for (const auto & c : coords)
      90             :   {
      91         125 :     Point p;
      92         125 :     if (c.size() < dim)
      93           0 :       paramError("coord",
      94             :                  "Coordinate ",
      95           0 :                  Moose::stringify(c),
      96             :                  " does not have enough components for a ",
      97             :                  dim,
      98             :                  "D mesh.");
      99             : 
     100         125 :     if (c.size() > 3)
     101           0 :       paramError("coord",
     102             :                  "Coordinate ",
     103           0 :                  Moose::stringify(c),
     104             :                  " has too many components. Did you maybe forget to separate multiple coordinates "
     105             :                  "with a ';'?");
     106             : 
     107         375 :     for (unsigned int j = 0; j < c.size(); ++j)
     108         250 :       p(j) = c[j];
     109             : 
     110             :     // locate candidate element
     111         125 :     bool on_node = false;
     112         125 :     bool found_elem = false;
     113         125 :     const Elem * elem = (*locator)(p);
     114         125 :     if (elem)
     115             :     {
     116          98 :       found_elem = true;
     117         282 :       for (unsigned int j = 0; j < elem->n_nodes(); ++j)
     118             :       {
     119         275 :         const Node * node = elem->node_ptr(j);
     120         275 :         if (p.absolute_fuzzy_equals(*node, tolerance))
     121             :         {
     122         182 :           for (const auto & boundary_id : boundary_ids)
     123          91 :             boundary_info.add_node(node, boundary_id);
     124             : 
     125          91 :           on_node = true;
     126          91 :           break;
     127             :         }
     128             :       }
     129             :     }
     130             : 
     131             :     // If we are on a distributed mesh, then any particular processor
     132             :     // may be unable to find any particular node, but *some* processor
     133             :     // should have found it.
     134         125 :     if (!mesh->is_replicated())
     135             :     {
     136          46 :       this->comm().max(found_elem);
     137          46 :       this->comm().max(on_node);
     138             :     }
     139             : 
     140             :     // only search for closest node if it is not found on a node
     141         125 :     if (use_closest_node && !on_node)
     142             :     {
     143             :       // these are always true when using closest node
     144          30 :       found_elem = true;
     145          30 :       on_node = true;
     146          30 :       Real dmin(std::numeric_limits<Real>::max());
     147          30 :       dof_id_type dmin_id(std::numeric_limits<dof_id_type>::max());
     148             :       // find this processors closest node and save distance and the node id
     149        5112 :       for (const auto & node_iter : as_range(mesh->local_nodes_begin(), mesh->local_nodes_end()))
     150             :       {
     151        2541 :         Real dist = (*node_iter - p).norm_sq();
     152        2541 :         if (dist < dmin)
     153             :         {
     154         451 :           dmin = dist;
     155         451 :           dmin_id = node_iter->id();
     156             :         }
     157          30 :       }
     158             : 
     159             :       // get proc id with the global closest node and then communicate that procs closest node_id
     160             :       processor_id_type dmin_proc_id;
     161          30 :       this->comm().minloc(dmin, dmin_proc_id);
     162          30 :       this->comm().broadcast(dmin_id, dmin_proc_id);
     163             : 
     164          30 :       const Node * node = mesh->query_node_ptr(dmin_id);
     165          30 :       if (node)
     166          42 :         for (const auto & boundary_id : boundary_ids)
     167          21 :           boundary_info.add_node(node, boundary_id);
     168             :     }
     169             : 
     170         125 :     if (!found_elem)
     171           4 :       mooseError("Unable to locate the following point within the domain, please check its "
     172             :                  "coordinates:\n",
     173             :                  p);
     174             : 
     175         121 :     if (!on_node)
     176           0 :       mooseError("No node found at point:\n",
     177             :                  p,
     178             :                  "\nSet use_closest_node=true if you want to find the closest node.");
     179             :   }
     180             : 
     181         456 :   for (unsigned int i = 0; i < boundary_ids.size(); ++i)
     182         228 :     boundary_info.nodeset_name(boundary_ids[i]) = boundary_names[i];
     183             : 
     184             :   // This is a terrible hack that we'll want to remove once BMBBG isn't terrible
     185         228 :   if (!_app.getMeshGeneratorSystem().hasBreakMeshByBlockGenerator())
     186         228 :     mesh->set_isnt_prepared();
     187         456 :   return dynamic_pointer_cast<MeshBase>(mesh);
     188         228 : }

Generated by: LCOV version 1.14