LCOV - code coverage report
Current view: top level - src/userobjects - InterfaceMeshCut3DUserObject.C (source / functions) Hit Total Coverage
Test: idaholab/moose xfem: #31405 (292dce) with base fef103 Lines: 94 105 89.5 %
Date: 2025-09-04 07:58:55 Functions: 6 9 66.7 %
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 "InterfaceMeshCut3DUserObject.h"
      11             : #include "XFEMMovingInterfaceVelocityBase.h"
      12             : #include "libmesh/enum_point_locator_type.h"
      13             : 
      14             : registerMooseObject("XFEMApp", InterfaceMeshCut3DUserObject);
      15             : 
      16             : InputParameters
      17          16 : InterfaceMeshCut3DUserObject::validParams()
      18             : {
      19          16 :   InputParameters params = InterfaceMeshCutUserObjectBase::validParams();
      20          16 :   params.addClassDescription("A userobject to cut a 3D mesh using a 2D cutter mesh.");
      21          16 :   return params;
      22           0 : }
      23             : 
      24           8 : InterfaceMeshCut3DUserObject::InterfaceMeshCut3DUserObject(const InputParameters & parameters)
      25           8 :   : InterfaceMeshCutUserObjectBase(parameters)
      26             : {
      27        4672 :   for (const auto & elem : _cutter_mesh->element_ptr_range())
      28        2328 :     if (elem->type() != TRI3)
      29           0 :       mooseError("InterfaceMeshCut3DUserObject currently only supports TRI3 elements in the "
      30           8 :                  "cutting mesh.");
      31           8 : }
      32             : 
      33             : void
      34          32 : InterfaceMeshCut3DUserObject::calculateNormals()
      35             : {
      36             :   _pseudo_normal.clear();
      37             : 
      38       18272 :   for (const auto & elem : _cutter_mesh->element_ptr_range())
      39             :   {
      40        9104 :     std::vector<Point> vertices{elem->node_ref(0), elem->node_ref(1), elem->node_ref(2)};
      41             :     std::array<Point, 7> normal;
      42        9104 :     Plane elem_plane(vertices[0], vertices[1], vertices[2]);
      43        9104 :     normal[0] = 2.0 * libMesh::pi * elem_plane.unit_normal(vertices[0]);
      44             : 
      45       36416 :     for (unsigned int i = 0; i < elem->n_nodes(); i++)
      46             :     {
      47             :       Point normal_at_node(0.0);
      48       27312 :       const Node & node = elem->node_ref(i);
      49             : 
      50      176832 :       for (const auto & node_neigh_elem_id : _node_to_elem_map[node.id()])
      51             :       {
      52      149520 :         const Elem & node_neigh_elem = _cutter_mesh->elem_ref(node_neigh_elem_id);
      53             :         std::vector<Point> vertices{
      54      149520 :             node_neigh_elem.node_ref(0), node_neigh_elem.node_ref(1), node_neigh_elem.node_ref(2)};
      55      149520 :         Plane elem_plane(vertices[0], vertices[1], vertices[2]);
      56      149520 :         unsigned int j = node_neigh_elem.local_node(node.id());
      57      149520 :         Point normal_at_node_j = elem_plane.unit_normal(vertices[0]);
      58      149520 :         unsigned int m = j + 1 < 3 ? j + 1 : j + 1 - 3;
      59      149520 :         unsigned int n = j + 2 < 3 ? j + 2 : j + 2 - 3;
      60             :         Point line_1 = node_neigh_elem.node_ref(j) - node_neigh_elem.node_ref(m);
      61             :         Point line_2 = node_neigh_elem.node_ref(j) - node_neigh_elem.node_ref(n);
      62             :         Real dot = line_1 * line_2;
      63             :         Real lenSq1 = line_1 * line_1;
      64             :         Real lenSq2 = line_2 * line_2;
      65      149520 :         Real angle = std::acos(dot / std::sqrt(lenSq1 * lenSq2));
      66             :         normal_at_node += normal_at_node_j * angle;
      67      149520 :       }
      68       27312 :       normal[1 + i] = normal_at_node;
      69             :     }
      70             : 
      71       36416 :     for (unsigned int i = 0; i < elem->n_sides(); i++)
      72             :     {
      73       27312 :       std::vector<Point> vertices{elem->node_ref(0), elem->node_ref(1), elem->node_ref(2)};
      74             : 
      75       27312 :       Plane elem_plane(vertices[0], vertices[1], vertices[2]);
      76       27312 :       Point normal_at_edge = libMesh::pi * elem_plane.unit_normal(vertices[0]);
      77             : 
      78       27312 :       const Elem * neighbor = elem->neighbor_ptr(i);
      79             : 
      80       27312 :       if (neighbor != nullptr)
      81             :       {
      82             :         std::vector<Point> vertices{
      83       25648 :             neighbor->node_ref(0), neighbor->node_ref(1), neighbor->node_ref(2)};
      84             : 
      85       25648 :         Plane elem_plane(vertices[0], vertices[1], vertices[2]);
      86       25648 :         normal_at_edge += libMesh::pi * elem_plane.unit_normal(vertices[0]);
      87       25648 :       }
      88       27312 :       normal[4 + i] = normal_at_edge;
      89       27312 :     }
      90        9104 :     _pseudo_normal.insert(std::make_pair(elem->id(), normal));
      91        9136 :   }
      92          32 : }
      93             : 
      94             : Point
      95        8240 : InterfaceMeshCut3DUserObject::nodeNormal(const unsigned int & node_id)
      96             : {
      97             :   Point normal(0.0);
      98             : 
      99       52496 :   for (const auto & node_neigh_elem_id : _node_to_elem_map[node_id])
     100             :   {
     101       44256 :     const auto & elem = _cutter_mesh->elem_ref(node_neigh_elem_id);
     102       44256 :     Plane elem_plane(elem.node_ref(0), elem.node_ref(1), elem.node_ref(2));
     103       44256 :     normal += elem_plane.unit_normal(elem.node_ref(0));
     104       44256 :   }
     105             : 
     106        8240 :   unsigned int num = _node_to_elem_map[node_id].size();
     107        8240 :   return normal / num;
     108             : }
     109             : 
     110             : bool
     111           0 : InterfaceMeshCut3DUserObject::cutElementByGeometry(const Elem * /*elem*/,
     112             :                                                    std::vector<Xfem::CutEdge> & /*cut_edges*/,
     113             :                                                    std::vector<Xfem::CutNode> & /*cut_nodes*/) const
     114             : {
     115           0 :   mooseError("invalid method for 3D mesh cutting");
     116             :   return false;
     117             : }
     118             : 
     119             : bool
     120         594 : InterfaceMeshCut3DUserObject::cutElementByGeometry(const Elem * elem,
     121             :                                                    std::vector<Xfem::CutFace> & cut_faces) const
     122             : {
     123             :   mooseAssert(elem->dim() == 3, "Dimension of element to be cut must be 3");
     124             : 
     125             :   bool elem_cut = false;
     126             : 
     127        4158 :   for (unsigned int i = 0; i < elem->n_sides(); ++i)
     128             :   {
     129             :     // This returns the lowest-order type of side.
     130        3564 :     std::unique_ptr<const Elem> curr_side = elem->side_ptr(i);
     131             : 
     132             :     mooseAssert(curr_side->dim() == 2, "Side dimension must be 2");
     133             : 
     134        3564 :     unsigned int n_edges = curr_side->n_sides();
     135             : 
     136             :     std::vector<unsigned int> cut_edges;
     137             :     std::vector<Real> cut_pos;
     138             : 
     139       17820 :     for (unsigned int j = 0; j < n_edges; j++)
     140             :     {
     141             :       // This returns the lowest-order type of side.
     142       14256 :       std::unique_ptr<const Elem> curr_edge = curr_side->side_ptr(j);
     143       14256 :       if (curr_edge->type() != EDGE2)
     144           0 :         mooseError("In cutElementByGeometry face edge must be EDGE2, but type is: ",
     145           0 :                    libMesh::Utility::enum_to_string(curr_edge->type()),
     146             :                    " base element type is: ",
     147           0 :                    libMesh::Utility::enum_to_string(elem->type()));
     148             :       const Node * node1 = curr_edge->node_ptr(0);
     149             :       const Node * node2 = curr_edge->node_ptr(1);
     150             : 
     151     8449056 :       for (const auto & cut_elem : _cutter_mesh->element_ptr_range())
     152             :       {
     153             :         std::vector<Point> vertices;
     154             : 
     155    16841088 :         for (auto & node : cut_elem->node_ref_range())
     156             :         {
     157    12630816 :           Point & this_point = node;
     158    12630816 :           vertices.push_back(this_point);
     159             :         }
     160             : 
     161             :         Point intersection;
     162     4210272 :         if (Xfem::intersectWithEdge(*node1, *node2, vertices, intersection) &&
     163     4210272 :             std::find(cut_edges.begin(), cut_edges.end(), j) == cut_edges.end())
     164             :         {
     165         672 :           cut_edges.push_back(j);
     166         672 :           cut_pos.push_back(Xfem::getRelativePosition(*node1, *node2, intersection));
     167             :         }
     168     4224528 :       }
     169       14256 :     }
     170             : 
     171             :     // if two edges of an element are cut, it is considered as an element being cut
     172        3564 :     if (cut_edges.size() == 2)
     173             :     {
     174             :       elem_cut = true;
     175             :       Xfem::CutFace mycut;
     176         336 :       mycut._face_id = i;
     177         336 :       mycut._face_edge.push_back(cut_edges[0]);
     178         336 :       mycut._face_edge.push_back(cut_edges[1]);
     179         336 :       mycut._position.push_back(cut_pos[0]);
     180         336 :       mycut._position.push_back(cut_pos[1]);
     181         336 :       cut_faces.push_back(mycut);
     182             :     }
     183        3564 :   }
     184             : 
     185         594 :   return elem_cut;
     186             : }
     187             : 
     188             : bool
     189           0 : InterfaceMeshCut3DUserObject::cutFragmentByGeometry(
     190             :     std::vector<std::vector<Point>> & /*frag_edges*/,
     191             :     std::vector<Xfem::CutEdge> & /*cut_edges*/) const
     192             : {
     193           0 :   mooseError("invalid method for 3D mesh cutting");
     194             :   return false;
     195             : }
     196             : 
     197             : bool
     198           0 : InterfaceMeshCut3DUserObject::cutFragmentByGeometry(
     199             :     std::vector<std::vector<Point>> & /*frag_faces*/,
     200             :     std::vector<Xfem::CutFace> & /*cut_faces*/) const
     201             : {
     202           0 :   mooseError("cutFragmentByGeometry not yet implemented for 3D mesh cutting");
     203             :   return false;
     204             : }
     205             : 
     206             : Real
     207      110712 : InterfaceMeshCut3DUserObject::calculateSignedDistance(Point p) const
     208             : {
     209             :   std::vector<Real> distance;
     210             :   Real min_dist = std::numeric_limits<Real>::max();
     211    67443528 :   for (const auto & cut_elem : _cutter_mesh->element_ptr_range())
     212             :   {
     213             :     std::vector<Point> vertices{
     214    33611052 :         cut_elem->node_ref(0), cut_elem->node_ref(1), cut_elem->node_ref(2)};
     215             :     unsigned int region;
     216             :     Point xp;
     217    33611052 :     Real dist = Xfem::pointTriangleDistance(
     218    33611052 :         p, cut_elem->node_ref(0), cut_elem->node_ref(1), cut_elem->node_ref(2), xp, region);
     219             : 
     220    33611052 :     distance.push_back(std::abs(dist));
     221             : 
     222    33611052 :     if (dist < std::abs(min_dist))
     223             :     {
     224             :       min_dist = dist;
     225     2558078 :       Point normal = (_pseudo_normal.find(cut_elem->id())->second)[region];
     226     1279039 :       if (normal * (p - xp) < 0.0)
     227      705150 :         min_dist *= -1.0;
     228             :     }
     229    33721764 :   }
     230      110712 :   std::sort(distance.begin(), distance.end());
     231             :   Real sum_dist = 0.0;
     232      221424 :   for (std::vector<Real>::iterator it = distance.begin(); it != distance.begin() + 1; ++it)
     233      110712 :     sum_dist += *it;
     234             : 
     235      110712 :   if (min_dist < 0.0)
     236       31122 :     return -sum_dist / 1.0;
     237             :   else
     238             :     return sum_dist / 1.0;
     239      110712 : }

Generated by: LCOV version 1.14