LCOV - code coverage report
Current view: top level - src/userobjects - NodalNormalsPreprocessor.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 2bf808 Lines: 65 66 98.5 %
Date: 2025-07-17 01:28:37 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       14640 : NodalNormalsPreprocessor::validParams()
      27             : {
      28       14640 :   InputParameters params = ElementUserObject::validParams();
      29       14640 :   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       14640 :   params.addRequiredParam<std::vector<BoundaryName>>(
      33             :       "surface_boundary", "The list of boundary IDs where nodal normals are computed");
      34       14640 :   params.addParam<BoundaryName>("corner_boundary",
      35             :                                 "Node set ID which contains the nodes that are in 'corners'.");
      36       14640 :   params.addPrivateParam<FEFamily>("fe_family", LAGRANGE);
      37       14640 :   params.addPrivateParam<Order>("fe_order", FIRST);
      38             : 
      39       14640 :   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      277664 : hasBoundary(const std::vector<BoundaryID> & boundary_ids1,
      49             :             const std::vector<BoundaryID> & boundary_ids2)
      50             : {
      51      565324 :   for (auto id1 : boundary_ids1)
      52             :   {
      53      377580 :     if (id1 == Moose::ANY_BOUNDARY_ID)
      54       89920 :       return true;
      55             : 
      56      665496 :     for (auto id2 : boundary_ids2)
      57      377836 :       if (id1 == id2 || id2 == Moose::ANY_BOUNDARY_ID)
      58       89920 :         return true;
      59             :   }
      60      187744 :   return false;
      61             : }
      62             : 
      63         195 : NodalNormalsPreprocessor::NodalNormalsPreprocessor(const InputParameters & parameters)
      64             :   : ElementUserObject(parameters),
      65         390 :     _aux(_fe_problem.getAuxiliarySystem()),
      66         195 :     _fe_type(getParam<Order>("fe_order"), getParam<FEFamily>("fe_family")),
      67         195 :     _has_corners(isParamValid("corner_boundary")),
      68         195 :     _boundaries(_mesh.getBoundaryIDs(getParam<std::vector<BoundaryName>>("surface_boundary"))),
      69         390 :     _corner_boundary_id(_has_corners
      70         195 :                             ? _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        5784 : NodalNormalsPreprocessor::initialize()
      78             : {
      79        5784 :   NumericVector<Number> & sln = _aux.solution();
      80        5784 :   _aux.system().zero_variable(sln, _aux.getVariable(_tid, "nodal_normal_x").number());
      81        5784 :   _aux.system().zero_variable(sln, _aux.getVariable(_tid, "nodal_normal_y").number());
      82        5784 :   _aux.system().zero_variable(sln, _aux.getVariable(_tid, "nodal_normal_z").number());
      83             :   // After zero variables, we should close the solution
      84        5784 :   sln.close();
      85        5784 : }
      86             : 
      87             : void
      88      103584 : NodalNormalsPreprocessor::execute()
      89             : {
      90      103584 :   NumericVector<Number> & sln = _aux.solution();
      91             : 
      92             :   // Get a reference to our BoundaryInfo object for later use...
      93      103584 :   BoundaryInfo & boundary_info = _mesh.getMesh().get_boundary_info();
      94             : 
      95             :   // Container to catch IDs handed back by BoundaryInfo.
      96      103584 :   std::vector<BoundaryID> node_boundary_ids;
      97             : 
      98             :   // Loop through each node on the current element
      99     1319584 :   for (unsigned int i = 0; i < _current_elem->n_nodes(); i++)
     100             :   {
     101             :     // Extract a pointer to a node
     102     1216000 :     const Node * node = _current_elem->node_ptr(i);
     103             : 
     104             :     // Only continue if the node is on a boundary
     105     1216000 :     if (_mesh.isBoundaryNode(node->id()))
     106             :     {
     107             :       // List of IDs for the boundary
     108      277664 :       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      367584 :       if (hasBoundary(node_boundary_ids, _boundaries) &&
     114       89920 :           (!_has_corners || !boundary_info.has_boundary_id(node, _corner_boundary_id)))
     115             :       {
     116             :         // Perform the caluation of the normal
     117       60608 :         if (node->n_dofs(_aux.number(),
     118       60608 :                          _fe_problem
     119      121216 :                              .getVariable(_tid,
     120             :                                           "nodal_normal_x",
     121             :                                           Moose::VarKindType::VAR_AUXILIARY,
     122             :                                           Moose::VarFieldType::VAR_FIELD_STANDARD)
     123       60608 :                              .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       52160 :               node->dof_number(_aux.number(),
     128       52160 :                                _fe_problem
     129      104320 :                                    .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       52160 :               node->dof_number(_aux.number(),
     137       52160 :                                _fe_problem
     138      104320 :                                    .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       52160 :               node->dof_number(_aux.number(),
     146       52160 :                                _fe_problem
     147      104320 :                                    .getVariable(_tid,
     148             :                                                 "nodal_normal_z",
     149             :                                                 Moose::VarKindType::VAR_AUXILIARY,
     150             :                                                 Moose::VarFieldType::VAR_FIELD_STANDARD)
     151             :                                    .number(),
     152             :                                0);
     153             : 
     154      427648 :           for (unsigned int qp = 0; qp < _qrule->n_points(); qp++)
     155             :           {
     156      375488 :             std::scoped_lock lock(_nodal_normals_mutex);
     157             : 
     158      375488 :             sln.add(dof_x, _JxW[qp] * _grad_phi[i][qp](0));
     159      375488 :             sln.add(dof_y, _JxW[qp] * _grad_phi[i][qp](1));
     160      375488 :             sln.add(dof_z, _JxW[qp] * _grad_phi[i][qp](2));
     161      375488 :           }
     162             :         }
     163             :       }
     164             :     }
     165             :   }
     166      103584 : }
     167             : 
     168             : void
     169        5302 : NodalNormalsPreprocessor::finalize()
     170             : {
     171        5302 :   _aux.solution().close();
     172        5302 : }

Generated by: LCOV version 1.14