LCOV - code coverage report
Current view: top level - src/geomsearch - GeometricSearchData.C (source / functions) Hit Total Coverage
Test: idaholab/moose framework: 2bf808 Lines: 141 154 91.6 %
Date: 2025-07-17 01:28:37 Functions: 16 18 88.9 %
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 "GeometricSearchData.h"
      11             : // Moose includes
      12             : #include "NearestNodeLocator.h"
      13             : #include "PenetrationLocator.h"
      14             : #include "ElementPairLocator.h"
      15             : #include "SubProblem.h"
      16             : #include "MooseMesh.h"
      17             : #include "Assembly.h"
      18             : 
      19             : #include "libmesh/elem.h"
      20             : #include "libmesh/node.h"
      21             : #include "libmesh/int_range.h"
      22             : 
      23       60037 : GeometricSearchData::GeometricSearchData(SubProblem & subproblem, MooseMesh & mesh)
      24       60037 :   : _subproblem(subproblem), _mesh(mesh), _first(true)
      25             : {
      26             :   // do a check on the boundary IDs to see if any conflict will rise from computing QP node set IDs
      27       60037 :   const auto & nodeset_ids = _mesh.meshNodesetIds();
      28      293257 :   for (const auto id : nodeset_ids)
      29      233220 :     if (nodeset_ids.find(-id - 1) != nodeset_ids.end())
      30           0 :       mooseError("Your mesh contains nodesets with negative IDs that interfere with QP nodeset IDs "
      31             :                  "potentially generated by the GeometricSearch system.");
      32       60037 : }
      33             : 
      34       55724 : GeometricSearchData::~GeometricSearchData()
      35             : {
      36       57400 :   for (auto & it : _penetration_locators)
      37        1676 :     delete it.second;
      38             : 
      39       57484 :   for (auto & it : _nearest_node_locators)
      40        1760 :     delete it.second;
      41       55724 : }
      42             : 
      43             : void
      44      265480 : GeometricSearchData::update(GeometricSearchType type)
      45             : {
      46      265480 :   if (type == ALL || type == QUADRATURE || type == NEAREST_NODE)
      47             :   {
      48      265480 :     if (_first) // Only do this once
      49             :     {
      50       57268 :       _first = false;
      51             : 
      52       57402 :       for (const auto & it : _secondary_to_qsecondary)
      53         134 :         generateQuadratureNodes(it.first, it.second);
      54             : 
      55             :       // reinit on displaced mesh before update
      56       57268 :       for (const auto & epl_it : _element_pair_locators)
      57             :       {
      58           0 :         ElementPairLocator & epl = *(epl_it.second);
      59           0 :         epl.reinit();
      60             :       }
      61             :     }
      62             : 
      63             :     // Update the position of quadrature nodes first
      64      285344 :     for (const auto & qbnd : _quadrature_boundaries)
      65       19864 :       updateQuadratureNodes(qbnd);
      66             :   }
      67             : 
      68      265480 :   if (type == ALL || type == NEAREST_NODE)
      69             :   {
      70      437586 :     for (const auto & nnl_it : _nearest_node_locators)
      71             :     {
      72      172106 :       NearestNodeLocator * nnl = nnl_it.second;
      73      172106 :       nnl->findNodes();
      74             :     }
      75             :   }
      76             : 
      77      265480 :   if (type == ALL || type == PENETRATION)
      78             :   {
      79      378242 :     for (const auto & pl_it : _penetration_locators)
      80             :     {
      81      170034 :       PenetrationLocator * pl = pl_it.second;
      82      170034 :       pl->detectPenetration();
      83             :     }
      84             :   }
      85             : 
      86      265476 :   if (type == ALL || type == PENETRATION)
      87             :   {
      88      208208 :     for (auto & elem_pair_locator_pair : _element_pair_locators)
      89             :     {
      90           0 :       ElementPairLocator & epl = (*elem_pair_locator_pair.second);
      91           0 :       epl.update();
      92             :     }
      93             :   }
      94      265476 : }
      95             : 
      96             : void
      97        6777 : GeometricSearchData::reinit()
      98             : {
      99        6777 :   _mesh.clearQuadratureNodes();
     100             :   // Update the position of quadrature nodes first
     101        6832 :   for (const auto & qbnd : _quadrature_boundaries)
     102          55 :     reinitQuadratureNodes(qbnd);
     103             : 
     104        6909 :   for (const auto & nnl_it : _nearest_node_locators)
     105             :   {
     106         132 :     NearestNodeLocator * nnl = nnl_it.second;
     107         132 :     nnl->reinit();
     108             :   }
     109             : 
     110        6887 :   for (const auto & pl_it : _penetration_locators)
     111             :   {
     112         110 :     PenetrationLocator * pl = pl_it.second;
     113         110 :     pl->reinit();
     114             :   }
     115             : 
     116        6777 :   for (const auto & epl_it : _element_pair_locators)
     117             :   {
     118           0 :     ElementPairLocator & epl = *(epl_it.second);
     119           0 :     epl.reinit();
     120             :   }
     121        6777 : }
     122             : 
     123             : void
     124         858 : GeometricSearchData::clearNearestNodeLocators()
     125             : {
     126        1716 :   for (const auto & nnl_it : _nearest_node_locators)
     127             :   {
     128         858 :     NearestNodeLocator * nnl = nnl_it.second;
     129         858 :     nnl->reinit();
     130             :   }
     131         858 : }
     132             : 
     133             : Real
     134         330 : GeometricSearchData::maxPatchPercentage()
     135             : {
     136         330 :   Real max = 0.0;
     137             : 
     138         990 :   for (const auto & nnl_it : _nearest_node_locators)
     139             :   {
     140         660 :     NearestNodeLocator * nnl = nnl_it.second;
     141             : 
     142         660 :     if (nnl->_max_patch_percentage > max)
     143         319 :       max = nnl->_max_patch_percentage;
     144             :   }
     145             : 
     146         330 :   return max;
     147             : }
     148             : 
     149             : PenetrationLocator &
     150       12585 : GeometricSearchData::getPenetrationLocator(const BoundaryName & primary,
     151             :                                            const BoundaryName & secondary,
     152             :                                            Order order)
     153             : {
     154       12585 :   auto primary_id = _mesh.getBoundaryID(primary);
     155       12585 :   auto secondary_id = _mesh.getBoundaryID(secondary);
     156             : 
     157       12585 :   _subproblem.addGhostedBoundary(primary_id);
     158       12585 :   _subproblem.addGhostedBoundary(secondary_id);
     159             : 
     160             :   PenetrationLocator * pl =
     161       12585 :       _penetration_locators[std::pair<BoundaryID, BoundaryID>(primary_id, secondary_id)];
     162             : 
     163       12585 :   if (!pl)
     164             :   {
     165           0 :     pl = new PenetrationLocator(_subproblem,
     166             :                                 *this,
     167             :                                 _mesh,
     168             :                                 primary_id,
     169             :                                 secondary_id,
     170             :                                 order,
     171        1574 :                                 getNearestNodeLocator(primary_id, secondary_id));
     172        1574 :     _penetration_locators[std::pair<BoundaryID, BoundaryID>(primary_id, secondary_id)] = pl;
     173             :   }
     174             : 
     175       12585 :   return *pl;
     176             : }
     177             : 
     178             : PenetrationLocator &
     179         120 : GeometricSearchData::getQuadraturePenetrationLocator(const BoundaryName & primary,
     180             :                                                      const BoundaryName & secondary,
     181             :                                                      Order order)
     182             : {
     183         120 :   const auto primary_id = _mesh.getBoundaryID(primary);
     184         120 :   const auto secondary_id = _mesh.getBoundaryID(secondary);
     185             : 
     186         120 :   _subproblem.addGhostedBoundary(primary_id);
     187         120 :   _subproblem.addGhostedBoundary(secondary_id);
     188             : 
     189             :   // Generate a new boundary id (we use the negative numbers and subtract 1 to disambiguate id=0)
     190         120 :   const auto qsecondary_id = -secondary_id - 1;
     191             : 
     192         120 :   _secondary_to_qsecondary[secondary_id] = qsecondary_id;
     193             : 
     194             :   PenetrationLocator * pl =
     195         120 :       _penetration_locators[std::pair<BoundaryID, BoundaryID>(primary_id, qsecondary_id)];
     196             : 
     197         120 :   if (!pl)
     198             :   {
     199           0 :     pl = new PenetrationLocator(_subproblem,
     200             :                                 *this,
     201             :                                 _mesh,
     202             :                                 primary_id,
     203             :                                 qsecondary_id,
     204             :                                 order,
     205         110 :                                 getQuadratureNearestNodeLocator(primary_id, secondary_id));
     206         110 :     _penetration_locators[std::pair<BoundaryID, BoundaryID>(primary_id, qsecondary_id)] = pl;
     207             :   }
     208             : 
     209         120 :   return *pl;
     210             : }
     211             : 
     212             : NearestNodeLocator &
     213          78 : GeometricSearchData::getNearestNodeLocator(const BoundaryName & primary,
     214             :                                            const BoundaryName & secondary)
     215             : {
     216          78 :   const auto primary_id = _mesh.getBoundaryID(primary);
     217          78 :   const auto secondary_id = _mesh.getBoundaryID(secondary);
     218             : 
     219          78 :   _subproblem.addGhostedBoundary(primary_id);
     220          78 :   _subproblem.addGhostedBoundary(secondary_id);
     221             : 
     222          78 :   return getNearestNodeLocator(primary_id, secondary_id);
     223             : }
     224             : 
     225             : NearestNodeLocator &
     226        1788 : GeometricSearchData::getNearestNodeLocator(const BoundaryID primary_id,
     227             :                                            const BoundaryID secondary_id)
     228             : {
     229             :   NearestNodeLocator * nnl =
     230        1788 :       _nearest_node_locators[std::pair<BoundaryID, BoundaryID>(primary_id, secondary_id)];
     231             : 
     232        1788 :   _subproblem.addGhostedBoundary(primary_id);
     233        1788 :   _subproblem.addGhostedBoundary(secondary_id);
     234             : 
     235        1788 :   if (!nnl)
     236             :   {
     237        1768 :     nnl = new NearestNodeLocator(_subproblem, _mesh, primary_id, secondary_id);
     238        1768 :     _nearest_node_locators[std::pair<BoundaryID, BoundaryID>(primary_id, secondary_id)] = nnl;
     239             :   }
     240             : 
     241        1788 :   return *nnl;
     242             : }
     243             : 
     244             : NearestNodeLocator &
     245          26 : GeometricSearchData::getQuadratureNearestNodeLocator(const BoundaryName & primary,
     246             :                                                      const BoundaryName & secondary)
     247             : {
     248          26 :   const auto primary_id = _mesh.getBoundaryID(primary);
     249          26 :   const auto secondary_id = _mesh.getBoundaryID(secondary);
     250             : 
     251          26 :   _subproblem.addGhostedBoundary(primary_id);
     252          26 :   _subproblem.addGhostedBoundary(secondary_id);
     253             : 
     254          26 :   return getQuadratureNearestNodeLocator(primary_id, secondary_id);
     255             : }
     256             : 
     257             : NearestNodeLocator &
     258         136 : GeometricSearchData::getQuadratureNearestNodeLocator(const BoundaryID primary_id,
     259             :                                                      const BoundaryID secondary_id)
     260             : {
     261             :   // Generate a new boundary id (we use the negative numbers and subtract 1 to disambiguate id=0)
     262         136 :   const auto qsecondary_id = -secondary_id - 1;
     263             : 
     264         136 :   _secondary_to_qsecondary[secondary_id] = qsecondary_id;
     265         136 :   return getNearestNodeLocator(primary_id, qsecondary_id);
     266             : }
     267             : 
     268             : void
     269         189 : GeometricSearchData::generateQuadratureNodes(const BoundaryID secondary_id,
     270             :                                              const BoundaryID qsecondary_id,
     271             :                                              bool reiniting)
     272             : {
     273             :   // Have we already generated quadrature nodes for this boundary id?
     274         189 :   if (_quadrature_boundaries.find(secondary_id) != _quadrature_boundaries.end())
     275             :   {
     276          55 :     if (!reiniting)
     277           0 :       return;
     278             :   }
     279             :   else
     280         134 :     _quadrature_boundaries.insert(secondary_id);
     281             : 
     282         189 :   const MooseArray<Point> & points_face = _subproblem.assembly(0, 0).qPointsFace();
     283             : 
     284         189 :   ConstBndElemRange & range = *_mesh.getBoundaryElementRange();
     285       34364 :   for (const auto & belem : range)
     286             :   {
     287       34175 :     const Elem * elem = belem->_elem;
     288       34175 :     const auto side = belem->_side;
     289       34175 :     const auto boundary_id = belem->_bnd_id;
     290             : 
     291       34175 :     if (elem->processor_id() == _subproblem.processor_id())
     292             :     {
     293       25463 :       if (boundary_id == (BoundaryID)secondary_id)
     294             :       {
     295             :         // All we should need to do here is reinit the underlying libMesh::FE object because that
     296             :         // will get us the correct points for the current element and side
     297        4796 :         _subproblem.setCurrentSubdomainID(elem, 0);
     298        4796 :         _subproblem.assembly(0, 0).reinit(elem, side);
     299             : 
     300       10151 :         for (const auto qp : index_range(points_face))
     301        5355 :           _mesh.addQuadratureNode(elem, side, qp, qsecondary_id, points_face[qp]);
     302             :       }
     303             :     }
     304             :   }
     305             : }
     306             : 
     307             : void
     308           0 : GeometricSearchData::addElementPairLocator(const BoundaryID interface_id,
     309             :                                            std::shared_ptr<ElementPairLocator> epl)
     310             : {
     311           0 :   _element_pair_locators[interface_id] = epl;
     312           0 : }
     313             : 
     314             : void
     315       19864 : GeometricSearchData::updateQuadratureNodes(const BoundaryID secondary_id)
     316             : {
     317       19864 :   const MooseArray<Point> & points_face = _subproblem.assembly(0, 0).qPointsFace();
     318             : 
     319       19864 :   ConstBndElemRange & range = *_mesh.getBoundaryElementRange();
     320     3933239 :   for (const auto & belem : range)
     321             :   {
     322     3913375 :     const Elem * elem = belem->_elem;
     323     3913375 :     const auto side = belem->_side;
     324     3913375 :     const auto boundary_id = belem->_bnd_id;
     325             : 
     326     3913375 :     if (elem->processor_id() == _subproblem.processor_id())
     327             :     {
     328     3047406 :       if (boundary_id == (BoundaryID)secondary_id)
     329             :       {
     330             :         // All we should need to do here is reinit the underlying libMesh::FE object because that
     331             :         // will get us the correct points for the current element and side
     332       40267 :         _subproblem.setCurrentSubdomainID(elem, 0);
     333       40267 :         _subproblem.assembly(0, 0).reinit(elem, side);
     334             : 
     335      112327 :         for (const auto qp : index_range(points_face))
     336       72060 :           (*_mesh.getQuadratureNode(elem, side, qp)) = points_face[qp];
     337             :       }
     338             :     }
     339             :   }
     340       19864 : }
     341             : 
     342             : void
     343          55 : GeometricSearchData::reinitQuadratureNodes(const BoundaryID /*secondary_id*/)
     344             : {
     345             :   // Regenerate the quadrature nodes
     346         110 :   for (const auto & it : _secondary_to_qsecondary)
     347          55 :     generateQuadratureNodes(it.first, it.second, /*reiniting=*/true);
     348          55 : }
     349             : 
     350             : void
     351         660 : GeometricSearchData::updateGhostedElems()
     352             : {
     353        1320 :   for (const auto & nnl_it : _nearest_node_locators)
     354             :   {
     355         660 :     NearestNodeLocator * nnl = nnl_it.second;
     356         660 :     nnl->updateGhostedElems();
     357             :   }
     358         660 : }

Generated by: LCOV version 1.14