LCOV - code coverage report
Current view: top level - src/userobjects - NodalNormalsPreprocessor.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: #32971 (54bef8) with base c6cf66 Lines: 65 66 98.5 %
Date: 2026-05-29 20:35:17 Functions: 6 6 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             : // MOOSE includes
      11             : #include "NodalNormalsPreprocessor.h"
      12             : 
      13             : #include "Assembly.h"
      14             : #include "AuxiliarySystem.h"
      15             : #include "MooseMesh.h"
      16             : #include "MooseVariableFE.h"
      17             : 
      18             : #include "libmesh/numeric_vector.h"
      19             : #include "libmesh/quadrature.h"
      20             : 
      21             : std::mutex NodalNormalsPreprocessor::_nodal_normals_mutex;
      22             : 
      23             : registerMooseObject("MooseApp", NodalNormalsPreprocessor);
      24             : 
      25             : InputParameters
      26        3436 : NodalNormalsPreprocessor::validParams()
      27             : {
      28        3436 :   InputParameters params = ElementUserObject::validParams();
      29        6872 :   params.addClassDescription(
      30             :       "An object that prepares MOOSE for computing nodal normal vectors. This object is "
      31             :       "automatically created via the \\[NodalNormals\\] input block.");
      32       13744 :   params.addRequiredParam<std::vector<BoundaryName>>(
      33             :       "surface_boundary", "The list of boundary IDs where nodal normals are computed");
      34       10308 :   params.addParam<BoundaryName>("corner_boundary",
      35             :                                 "Node set ID which contains the nodes that are in 'corners'.");
      36        6872 :   params.addPrivateParam<FEFamily>("fe_family", LAGRANGE);
      37        6872 :   params.addPrivateParam<Order>("fe_order", FIRST);
      38             : 
      39        3436 :   return params;
      40           0 : }
      41             : 
      42             : /**
      43             :  * Local function to check to see if any intersection occurs between two vectors. Neither can be
      44             :  * assumed to be sorted but both are generally very short (just 1 or 2 entries) so doing an explicit
      45             :  * double loop is probably the easiest.
      46             :  */
      47             : bool
      48      277928 : hasBoundary(const std::vector<BoundaryID> & boundary_ids1,
      49             :             const std::vector<BoundaryID> & boundary_ids2)
      50             : {
      51      565990 :   for (auto id1 : boundary_ids1)
      52             :   {
      53      378066 :     if (id1 == Moose::ANY_BOUNDARY_ID)
      54       90004 :       return true;
      55             : 
      56      666384 :     for (auto id2 : boundary_ids2)
      57      378322 :       if (id1 == id2 || id2 == Moose::ANY_BOUNDARY_ID)
      58       90004 :         return true;
      59             :   }
      60      187924 :   return false;
      61             : }
      62             : 
      63         195 : NodalNormalsPreprocessor::NodalNormalsPreprocessor(const InputParameters & parameters)
      64             :   : ElementUserObject(parameters),
      65         390 :     _aux(_fe_problem.getAuxiliarySystem()),
      66         780 :     _fe_type(getParam<Order>("fe_order"), getParam<FEFamily>("fe_family")),
      67         390 :     _has_corners(isParamValid("corner_boundary")),
      68         390 :     _boundaries(_mesh.getBoundaryIDs(getParam<std::vector<BoundaryName>>("surface_boundary"))),
      69         390 :     _corner_boundary_id(_has_corners
      70         338 :                             ? _mesh.getBoundaryID(getParam<BoundaryName>("corner_boundary"))
      71             :                             : static_cast<BoundaryID>(-1)),
      72         390 :     _grad_phi(_assembly.feGradPhi<Real>(_fe_type))
      73             : {
      74         195 : }
      75             : 
      76             : void
      77        5792 : NodalNormalsPreprocessor::initialize()
      78             : {
      79        5792 :   NumericVector<Number> & sln = _aux.solution();
      80       11584 :   _aux.system().zero_variable(sln, _aux.getVariable(_tid, "nodal_normal_x").number());
      81       11584 :   _aux.system().zero_variable(sln, _aux.getVariable(_tid, "nodal_normal_y").number());
      82       11584 :   _aux.system().zero_variable(sln, _aux.getVariable(_tid, "nodal_normal_z").number());
      83             :   // After zero variables, we should close the solution
      84        5792 :   sln.close();
      85        5792 : }
      86             : 
      87             : void
      88      103620 : NodalNormalsPreprocessor::execute()
      89             : {
      90      103620 :   NumericVector<Number> & sln = _aux.solution();
      91             : 
      92             :   // Get a reference to our BoundaryInfo object for later use...
      93      103620 :   BoundaryInfo & boundary_info = _mesh.getMesh().get_boundary_info();
      94             : 
      95             :   // Container to catch IDs handed back by BoundaryInfo.
      96      103620 :   std::vector<BoundaryID> node_boundary_ids;
      97             : 
      98             :   // Loop through each node on the current element
      99     1319884 :   for (unsigned int i = 0; i < _current_elem->n_nodes(); i++)
     100             :   {
     101             :     // Extract a pointer to a node
     102     1216264 :     const Node * node = _current_elem->node_ptr(i);
     103             : 
     104             :     // Only continue if the node is on a boundary
     105     1216264 :     if (_mesh.isBoundaryNode(node->id()))
     106             :     {
     107             :       // List of IDs for the boundary
     108      277928 :       boundary_info.boundary_ids(node, node_boundary_ids);
     109             : 
     110             :       // Perform the calculation, the node must be:
     111             :       //    (1) On a boundary to which the object is restricted
     112             :       //    (2) Not on a corner of the boundary
     113      367932 :       if (hasBoundary(node_boundary_ids, _boundaries) &&
     114       90004 :           (!_has_corners || !boundary_info.has_boundary_id(node, _corner_boundary_id)))
     115             :       {
     116             :         // Perform the caluation of the normal
     117       60636 :         if (node->n_dofs(_aux.number(),
     118       60636 :                          _fe_problem
     119      181908 :                              .getVariable(_tid,
     120             :                                           "nodal_normal_x",
     121             :                                           Moose::VarKindType::VAR_AUXILIARY,
     122             :                                           Moose::VarFieldType::VAR_FIELD_STANDARD)
     123       60636 :                              .number()) > 0)
     124             :         {
     125             :           // but it is not a corner node, they will be treated differently later on
     126             :           dof_id_type dof_x =
     127       52188 :               node->dof_number(_aux.number(),
     128       52188 :                                _fe_problem
     129      156564 :                                    .getVariable(_tid,
     130             :                                                 "nodal_normal_x",
     131             :                                                 Moose::VarKindType::VAR_AUXILIARY,
     132             :                                                 Moose::VarFieldType::VAR_FIELD_STANDARD)
     133             :                                    .number(),
     134             :                                0);
     135             :           dof_id_type dof_y =
     136       52188 :               node->dof_number(_aux.number(),
     137       52188 :                                _fe_problem
     138      156564 :                                    .getVariable(_tid,
     139             :                                                 "nodal_normal_y",
     140             :                                                 Moose::VarKindType::VAR_AUXILIARY,
     141             :                                                 Moose::VarFieldType::VAR_FIELD_STANDARD)
     142             :                                    .number(),
     143             :                                0);
     144             :           dof_id_type dof_z =
     145       52188 :               node->dof_number(_aux.number(),
     146       52188 :                                _fe_problem
     147      156564 :                                    .getVariable(_tid,
     148             :                                                 "nodal_normal_z",
     149             :                                                 Moose::VarKindType::VAR_AUXILIARY,
     150             :                                                 Moose::VarFieldType::VAR_FIELD_STANDARD)
     151             :                                    .number(),
     152             :                                0);
     153             : 
     154      427852 :           for (unsigned int qp = 0; qp < _qrule->n_points(); qp++)
     155             :           {
     156      375664 :             std::scoped_lock lock(_nodal_normals_mutex);
     157             : 
     158      375664 :             sln.add(dof_x, _JxW[qp] * _grad_phi[i][qp](0));
     159      375664 :             sln.add(dof_y, _JxW[qp] * _grad_phi[i][qp](1));
     160      375664 :             sln.add(dof_z, _JxW[qp] * _grad_phi[i][qp](2));
     161      375664 :           }
     162             :         }
     163             :       }
     164             :     }
     165             :   }
     166      103620 : }
     167             : 
     168             : void
     169        5310 : NodalNormalsPreprocessor::finalize()
     170             : {
     171        5310 :   _aux.solution().close();
     172        5310 : }

Generated by: LCOV version 1.14