LCOV - code coverage report
Current view: top level - src/base - XFEMCutElem3D.C (source / functions) Hit Total Coverage
Test: idaholab/moose xfem: #31405 (292dce) with base fef103 Lines: 126 135 93.3 %
Date: 2025-09-04 07:58:55 Functions: 12 14 85.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 "XFEMCutElem3D.h"
      11             : 
      12             : #include "EFANode.h"
      13             : #include "EFAFace.h"
      14             : #include "EFAFragment3D.h"
      15             : #include "EFAFuncs.h"
      16             : #include "XFEMFuncs.h"
      17             : #include "MooseError.h"
      18             : 
      19             : #include "libmesh/mesh.h"
      20             : #include "libmesh/elem.h"
      21             : #include "libmesh/node.h"
      22             : 
      23        2560 : XFEMCutElem3D::XFEMCutElem3D(Elem * elem,
      24             :                              const EFAElement3D * const CEMelem,
      25             :                              unsigned int n_qpoints,
      26        2560 :                              unsigned int n_sides)
      27        2560 :   : XFEMCutElem(elem, n_qpoints, n_sides), _efa_elem3d(CEMelem, true)
      28             : {
      29        2560 :   computePhysicalVolumeFraction();
      30        2560 :   computeMomentFittingWeights();
      31        2560 : }
      32             : 
      33        5120 : XFEMCutElem3D::~XFEMCutElem3D() {}
      34             : 
      35             : Point
      36     2549066 : XFEMCutElem3D::getNodeCoordinates(EFANode * CEMnode, MeshBase * displaced_mesh) const
      37             : {
      38             :   Point node_coor(0.0, 0.0, 0.0);
      39             :   std::vector<EFANode *> master_nodes;
      40             :   std::vector<Point> master_points;
      41             :   std::vector<double> master_weights;
      42             : 
      43     2549066 :   _efa_elem3d.getMasterInfo(CEMnode, master_nodes, master_weights);
      44     7503566 :   for (unsigned int i = 0; i < master_nodes.size(); ++i)
      45             :   {
      46     4954500 :     if (master_nodes[i]->category() == EFANode::N_CATEGORY_LOCAL_INDEX)
      47             :     {
      48     4954500 :       Node * node = _nodes[master_nodes[i]->id()];
      49     4954500 :       if (displaced_mesh)
      50     2536608 :         node = displaced_mesh->node_ptr(node->id());
      51     4954500 :       Point node_p((*node)(0), (*node)(1), (*node)(2));
      52     4954500 :       master_points.push_back(node_p);
      53             :     }
      54             :     else
      55           0 :       mooseError("master nodes must be local");
      56             :   }
      57     7503566 :   for (unsigned int i = 0; i < master_nodes.size(); ++i)
      58             :     node_coor += master_weights[i] * master_points[i];
      59     2549066 :   return node_coor;
      60     2549066 : }
      61             : 
      62             : void
      63       54720 : XFEMCutElem3D::computePhysicalVolumeFraction()
      64             : {
      65             :   Real frag_vol = 0.0;
      66             : 
      67             :   // collect fragment info needed by polyhedron_volume_3d()
      68             :   std::vector<std::vector<unsigned int>> frag_face_indices;
      69             :   std::vector<EFANode *> frag_nodes;
      70       54720 :   _efa_elem3d.getFragment(0)->getNodeInfo(frag_face_indices, frag_nodes);
      71       54720 :   int face_num = frag_face_indices.size();
      72       54720 :   int node_num = frag_nodes.size();
      73             : 
      74             :   int order_max = 0;
      75       54720 :   int * order = new int[face_num];
      76      330581 :   for (int i = 0; i < face_num; ++i)
      77             :   {
      78      275861 :     if (frag_face_indices[i].size() > (unsigned int)order_max)
      79       60272 :       order_max = frag_face_indices[i].size();
      80      275861 :     order[i] = frag_face_indices[i].size();
      81             :   }
      82             : 
      83       54720 :   double * coord = new double[3 * node_num];
      84      387554 :   for (unsigned int i = 0; i < frag_nodes.size(); ++i)
      85             :   {
      86      332834 :     Point p = getNodeCoordinates(frag_nodes[i]);
      87      332834 :     coord[3 * i + 0] = p(0);
      88      332834 :     coord[3 * i + 1] = p(1);
      89      332834 :     coord[3 * i + 2] = p(2);
      90             :   }
      91             : 
      92       54720 :   int * node = new int[face_num * order_max];
      93       54720 :   Xfem::i4vec_zero(face_num * order_max, node);
      94      330581 :   for (int i = 0; i < face_num; ++i)
      95     1274371 :     for (unsigned int j = 0; j < frag_face_indices[i].size(); ++j)
      96      998510 :       node[order_max * i + j] = frag_face_indices[i][j];
      97             : 
      98             :   // compute fragment volume and volume fraction
      99       54720 :   frag_vol = Xfem::polyhedron_volume_3d(coord, order_max, face_num, node, node_num, order);
     100       54720 :   _physical_volfrac = frag_vol / _elem_volume;
     101             : 
     102       54720 :   delete[] order;
     103       54720 :   delete[] coord;
     104       54720 :   delete[] node;
     105       54720 : }
     106             : 
     107             : void
     108          60 : XFEMCutElem3D::computePhysicalFaceAreaFraction(unsigned int side)
     109             : {
     110             :   Real frag_surf = 0.0;
     111             : 
     112             :   std::vector<std::vector<unsigned int>> frag_face_indices;
     113             :   std::vector<EFANode *> frag_nodes;
     114          60 :   _efa_elem3d.getFragment(0)->getNodeInfo(frag_face_indices, frag_nodes);
     115          60 :   int face_num = frag_face_indices.size();
     116             : 
     117          60 :   EFAFace * efa_face = _efa_elem3d.getFace(side);
     118             :   bool contains_all = true;
     119             : 
     120             :   /// find a fragment surface which is covered by element side
     121         180 :   for (int i = 0; i < face_num; ++i)
     122             :   {
     123             :     contains_all = true;
     124         420 :     for (unsigned int j = 0; j < frag_face_indices[i].size(); ++j)
     125             :     {
     126         360 :       EFANode * efa_node = frag_nodes[frag_face_indices[i][j]];
     127         360 :       if (!efa_face->containsNode(efa_node))
     128             :       {
     129             :         contains_all = false;
     130             :         break;
     131             :       }
     132             :     }
     133             : 
     134         180 :     if (contains_all)
     135             :     {
     136         300 :       for (unsigned int j = 0; j < frag_face_indices[i].size(); ++j)
     137             :       {
     138         240 :         unsigned int m = ((j + 1) == frag_face_indices[i].size()) ? 0 : j + 1;
     139         240 :         Point edge_p1 = getNodeCoordinates(frag_nodes[frag_face_indices[i][j]]);
     140         240 :         Point edge_p2 = getNodeCoordinates(frag_nodes[frag_face_indices[i][m]]);
     141             : 
     142         240 :         frag_surf += 0.5 * (edge_p1(0) - edge_p2(0)) * (edge_p1(1) + edge_p2(1));
     143             :       }
     144          60 :       _physical_areafrac[side] = std::abs(frag_surf) / _elem_side_area[side];
     145             :       return;
     146             :     }
     147             :   }
     148           0 :   _physical_areafrac[side] = 1.0;
     149          60 : }
     150             : 
     151             : void
     152        2560 : XFEMCutElem3D::computeMomentFittingWeights()
     153             : {
     154             :   // TODO: 3D moment fitting method nod coded yet - use volume fraction for now
     155        2560 :   _new_weights.resize(_n_qpoints, _physical_volfrac);
     156        2560 : }
     157             : 
     158             : Point
     159      297688 : XFEMCutElem3D::getCutPlaneOrigin(unsigned int plane_id, MeshBase * displaced_mesh) const
     160             : {
     161             :   Point orig(0.0, 0.0, 0.0);
     162             :   std::vector<std::vector<EFANode *>> cut_plane_nodes;
     163     1786398 :   for (unsigned int i = 0; i < _efa_elem3d.getFragment(0)->numFaces(); ++i)
     164             :   {
     165     1488710 :     if (_efa_elem3d.getFragment(0)->isFaceInterior(i))
     166             :     {
     167      297688 :       EFAFace * face = _efa_elem3d.getFragment(0)->getFace(i);
     168             :       std::vector<EFANode *> node_line;
     169     1323896 :       for (unsigned int j = 0; j < face->numNodes(); ++j)
     170     1026208 :         node_line.push_back(face->getNode(j));
     171      297688 :       cut_plane_nodes.push_back(node_line);
     172      297688 :     }
     173             :   }
     174      297688 :   if (cut_plane_nodes.size() == 0)
     175           0 :     mooseError("no cut plane found in this element");
     176      297688 :   if (plane_id < cut_plane_nodes.size()) // valid plane_id
     177             :   {
     178             :     std::vector<Point> cut_plane_points;
     179      674888 :     for (unsigned int i = 0; i < cut_plane_nodes[plane_id].size(); ++i)
     180     1046912 :       cut_plane_points.push_back(getNodeCoordinates(cut_plane_nodes[plane_id][i], displaced_mesh));
     181             : 
     182      674888 :     for (unsigned int i = 0; i < cut_plane_points.size(); ++i)
     183             :       orig += cut_plane_points[i];
     184      151432 :     orig /= cut_plane_points.size();
     185      151432 :   }
     186      297688 :   return orig;
     187      297688 : }
     188             : 
     189             : Point
     190      444142 : XFEMCutElem3D::getCutPlaneNormal(unsigned int plane_id, MeshBase * displaced_mesh) const
     191             : {
     192             :   Point normal(0.0, 0.0, 0.0);
     193             :   std::vector<std::vector<EFANode *>> cut_plane_nodes;
     194     2809320 :   for (unsigned int i = 0; i < _efa_elem3d.getFragment(0)->numFaces(); ++i)
     195             :   {
     196     2365178 :     if (_efa_elem3d.getFragment(0)->isFaceInterior(i))
     197             :     {
     198      444142 :       EFAFace * face = _efa_elem3d.getFragment(0)->getFace(i);
     199             :       std::vector<EFANode *> node_line;
     200     2054770 :       for (unsigned int j = 0; j < face->numNodes(); ++j)
     201     1610628 :         node_line.push_back(face->getNode(j));
     202      444142 :       cut_plane_nodes.push_back(node_line);
     203      444142 :     }
     204             :   }
     205      444142 :   if (cut_plane_nodes.size() == 0)
     206           0 :     mooseError("no cut plane found in this element");
     207      444142 :   if (plane_id < cut_plane_nodes.size()) // valid plane_id
     208             :   {
     209             :     std::vector<Point> cut_plane_points;
     210     1405762 :     for (unsigned int i = 0; i < cut_plane_nodes[plane_id].size(); ++i)
     211     2215752 :       cut_plane_points.push_back(getNodeCoordinates(cut_plane_nodes[plane_id][i], displaced_mesh));
     212             : 
     213             :     Point center(0.0, 0.0, 0.0);
     214     1405762 :     for (unsigned int i = 0; i < cut_plane_points.size(); ++i)
     215             :       center += cut_plane_points[i];
     216      297886 :     center /= cut_plane_points.size();
     217             : 
     218     1405762 :     for (unsigned int i = 0; i < cut_plane_points.size(); ++i)
     219             :     {
     220     1107876 :       unsigned int iplus1 = i < cut_plane_points.size() - 1 ? i + 1 : 0;
     221             :       Point ray1 = cut_plane_points[i] - center;
     222     1107876 :       Point ray2 = cut_plane_points[iplus1] - center;
     223     1107876 :       normal += ray1.cross(ray2);
     224             :     }
     225             :     normal /= cut_plane_points.size();
     226      297886 :   }
     227      444142 :   Xfem::normalizePoint(normal);
     228      444142 :   return normal;
     229      444142 : }
     230             : 
     231             : void
     232           0 : XFEMCutElem3D::getCrackTipOriginAndDirection(unsigned /*tip_id*/,
     233             :                                              Point & /*origin*/,
     234             :                                              Point & /*direction*/) const
     235             : {
     236             :   // TODO: not implemented for 3D
     237           0 :   mooseError("getCrackTipOriginAndDirection not yet implemented for XFEMCutElem3D");
     238             : }
     239             : 
     240             : void
     241           0 : XFEMCutElem3D::getFragmentFaces(std::vector<std::vector<Point>> & /*frag_faces*/,
     242             :                                 MeshBase * /*displaced_mesh*/) const
     243             : {
     244             :   // TODO: not implemented for 3D
     245           0 :   mooseError("getFragmentFaces not yet implemented for XFEMCutElem3D");
     246             : }
     247             : 
     248             : const EFAElement *
     249      848922 : XFEMCutElem3D::getEFAElement() const
     250             : {
     251      848922 :   return &_efa_elem3d;
     252             : }
     253             : 
     254             : unsigned int
     255        5176 : XFEMCutElem3D::numCutPlanes() const
     256             : {
     257             :   unsigned int counter = 0;
     258       36318 :   for (unsigned int i = 0; i < _efa_elem3d.getFragment(0)->numFaces(); ++i)
     259       31142 :     if (_efa_elem3d.getFragment(0)->isFaceInterior(i))
     260        5176 :       counter += 1;
     261        5176 :   return counter;
     262             : }
     263             : 
     264             : void
     265      146454 : XFEMCutElem3D::getIntersectionInfo(unsigned int plane_id,
     266             :                                    Point & normal,
     267             :                                    std::vector<Point> & intersectionPoints,
     268             :                                    MeshBase * displaced_mesh) const
     269             : {
     270      146454 :   intersectionPoints.clear();
     271             :   std::vector<std::vector<EFANode *>> cut_plane_nodes;
     272     1022922 :   for (unsigned int i = 0; i < _efa_elem3d.getFragment(0)->numFaces(); ++i)
     273             :   {
     274      876468 :     if (_efa_elem3d.getFragment(0)->isFaceInterior(i))
     275             :     {
     276      146454 :       EFAFace * face = _efa_elem3d.getFragment(0)->getFace(i);
     277             :       std::vector<EFANode *> node_line;
     278      730874 :       for (unsigned int j = 0; j < face->numNodes(); ++j)
     279      584420 :         node_line.push_back(face->getNode(j));
     280      146454 :       cut_plane_nodes.push_back(node_line);
     281      146454 :     }
     282             :   }
     283      146454 :   if (cut_plane_nodes.size() == 0)
     284           0 :     mooseError("No cut plane found in this element");
     285             : 
     286      146454 :   if (plane_id < cut_plane_nodes.size()) // valid plane_id
     287             :   {
     288      146454 :     intersectionPoints.resize(cut_plane_nodes[plane_id].size());
     289      730874 :     for (unsigned int i = 0; i < cut_plane_nodes[plane_id].size(); ++i)
     290      584420 :       intersectionPoints[i] = getNodeCoordinates(cut_plane_nodes[plane_id][i], displaced_mesh);
     291             :   }
     292             : 
     293      146454 :   normal = getCutPlaneNormal(plane_id, displaced_mesh);
     294      146454 : }

Generated by: LCOV version 1.14