LCOV - code coverage report
Current view: top level - src/userobjects - GeometricCutUserObject.C (source / functions) Hit Total Coverage
Test: idaholab/moose xfem: #31730 (e8b711) with base e0c998 Lines: 119 127 93.7 %
Date: 2025-10-29 16:56:32 Functions: 15 16 93.8 %
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 "GeometricCutUserObject.h"
      11             : 
      12             : // MOOSE includes
      13             : #include "MooseError.h"
      14             : #include "XFEM.h"
      15             : #include "DataIO.h"
      16             : #include "EFAElement2D.h"
      17             : #include "EFAElement3D.h"
      18             : #include "XFEMElementPairLocator.h"
      19             : #include "DisplacedProblem.h"
      20             : 
      21             : InputParameters
      22        1001 : GeometricCutUserObject::validParams()
      23             : {
      24        1001 :   InputParameters params = CrackFrontPointsProvider::validParams();
      25        1001 :   params.addClassDescription("Base UserObject class for XFEM Geometric Cuts");
      26        2002 :   params.addParam<bool>("heal_always", false, "Heal previous cuts at every time step");
      27        1001 :   ExecFlagEnum & exec = params.set<ExecFlagEnum>("execute_on");
      28        1001 :   exec.addAvailableFlags(EXEC_XFEM_MARK);
      29        2002 :   params.setDocString("execute_on", exec.getDocString());
      30        1001 :   params.set<ExecFlagEnum>("execute_on") = EXEC_XFEM_MARK;
      31        1001 :   params.set<int>("execution_order_group") = 1;
      32        1001 :   return params;
      33           0 : }
      34             : 
      35         501 : GeometricCutUserObject::GeometricCutUserObject(const InputParameters & parameters,
      36         501 :                                                const bool uses_mesh)
      37        1002 :   : CrackFrontPointsProvider(parameters, uses_mesh), _heal_always(getParam<bool>("heal_always"))
      38             : {
      39        1503 :   _xfem = MooseSharedNamespace::dynamic_pointer_cast<XFEM>(_fe_problem.getXFEM());
      40         501 :   if (_xfem == nullptr)
      41           0 :     mooseError("Problem casting to XFEM in GeometricCutUserObject");
      42             : 
      43         501 :   _xfem->addGeometricCut(this);
      44             : 
      45         501 :   auto new_xfem_epl = std::make_shared<XFEMElementPairLocator>(_xfem, _interface_id);
      46        1002 :   _fe_problem.geomSearchData().addElementPairLocator(_interface_id, new_xfem_epl);
      47             : 
      48        1002 :   if (_fe_problem.getDisplacedProblem() != nullptr)
      49             :   {
      50         245 :     auto new_xfem_epl2 = std::make_shared<XFEMElementPairLocator>(_xfem, _interface_id, true);
      51         980 :     _fe_problem.getDisplacedProblem()->geomSearchData().addElementPairLocator(_interface_id,
      52             :                                                                               new_xfem_epl2);
      53             :   }
      54         501 : }
      55             : 
      56             : void
      57        1557 : GeometricCutUserObject::initialize()
      58             : {
      59             :   _marked_elems_2d.clear();
      60             :   _marked_elems_3d.clear();
      61        1557 : }
      62             : 
      63             : void
      64      347335 : GeometricCutUserObject::execute()
      65             : {
      66      347335 :   if (_current_elem->dim() == 2)
      67             :   {
      68             :     std::vector<Xfem::CutEdge> elem_cut_edges;
      69             :     std::vector<Xfem::CutNode> elem_cut_nodes;
      70             :     std::vector<Xfem::CutEdge> frag_cut_edges;
      71             :     std::vector<std::vector<Point>> frag_edges;
      72             : 
      73      323947 :     EFAElement2D * EFAElem = _xfem->getEFAElem2D(_current_elem);
      74             : 
      75             :     // Don't cut again if elem has been already cut twice
      76      323947 :     if (!EFAElem->isFinalCut())
      77             :     {
      78             :       // get fragment edges
      79      323827 :       _xfem->getFragmentEdges(_current_elem, EFAElem, frag_edges);
      80             : 
      81             :       // mark cut edges for the element and its fragment
      82      323827 :       bool cut = cutElementByGeometry(_current_elem, elem_cut_edges, elem_cut_nodes);
      83      323827 :       if (EFAElem->numFragments() > 0)
      84       17024 :         cut |= cutFragmentByGeometry(frag_edges, frag_cut_edges);
      85             : 
      86      323827 :       if (cut)
      87             :       {
      88             :         Xfem::GeomMarkedElemInfo2D gmei2d;
      89       18433 :         gmei2d._elem_cut_edges = elem_cut_edges;
      90       18433 :         gmei2d._elem_cut_nodes = elem_cut_nodes;
      91       18433 :         gmei2d._frag_cut_edges = frag_cut_edges;
      92       18433 :         gmei2d._frag_edges = frag_edges;
      93       18433 :         _marked_elems_2d[_current_elem->id()].push_back(gmei2d);
      94       18433 :       }
      95             :     }
      96      323947 :   }
      97       23388 :   else if (_current_elem->dim() == 3)
      98             :   {
      99             :     std::vector<Xfem::CutFace> elem_cut_faces;
     100             :     std::vector<Xfem::CutFace> frag_cut_faces;
     101             :     std::vector<std::vector<Point>> frag_faces;
     102             : 
     103       23388 :     EFAElement3D * EFAElem = _xfem->getEFAElem3D(_current_elem);
     104             : 
     105             :     // Don't cut again if elem has been already cut twice
     106       23388 :     if (!EFAElem->isFinalCut())
     107             :     {
     108             :       // get fragment edges
     109       23388 :       _xfem->getFragmentFaces(_current_elem, EFAElem, frag_faces);
     110             : 
     111             :       // mark cut faces for the element and its fragment
     112       23388 :       bool cut = cutElementByGeometry(_current_elem, elem_cut_faces);
     113             :       // TODO: This would be done for branching, which is not yet supported in 3D
     114             :       // if (EFAElem->numFragments() > 0)
     115             :       //  cut |= cutFragmentByGeometry(frag_faces, frag_cut_faces, _t);
     116             : 
     117       23388 :       if (cut)
     118             :       {
     119             :         Xfem::GeomMarkedElemInfo3D gmei3d;
     120        4098 :         gmei3d._elem_cut_faces = elem_cut_faces;
     121        4098 :         gmei3d._frag_cut_faces = frag_cut_faces;
     122        4098 :         gmei3d._frag_faces = frag_faces;
     123        4098 :         _marked_elems_3d[_current_elem->id()].push_back(gmei3d);
     124        4098 :       }
     125             :     }
     126       23388 :   }
     127      347335 : }
     128             : 
     129             : bool
     130         922 : GeometricCutUserObject::isCutterMeshChanged() const
     131             : {
     132         922 :   return false;
     133             : }
     134             : 
     135             : void
     136           0 : GeometricCutUserObject::threadJoin(const UserObject & y)
     137             : {
     138             :   const auto & gcuo = static_cast<const GeometricCutUserObject &>(y);
     139             : 
     140           0 :   for (const auto & it : gcuo._marked_elems_2d)
     141             :   {
     142             :     mooseAssert(_marked_elems_2d.find(it.first) == _marked_elems_2d.end(),
     143             :                 "Element already inserted in map from a different thread");
     144           0 :     _marked_elems_2d[it.first] = it.second;
     145             :   }
     146           0 :   for (const auto & it : gcuo._marked_elems_3d)
     147             :   {
     148             :     mooseAssert(_marked_elems_3d.find(it.first) == _marked_elems_3d.end(),
     149             :                 "Element already inserted in map from a different thread");
     150           0 :     _marked_elems_3d[it.first] = it.second;
     151             :   }
     152           0 : }
     153             : 
     154             : // custom data load and data store methods for structs with std::vector members
     155             : template <>
     156             : inline void
     157        4049 : dataStore(std::ostream & stream, Xfem::CutFace & cf, void * context)
     158             : {
     159        4049 :   dataStore(stream, cf._face_id, context);
     160        4049 :   dataStore(stream, cf._face_edge, context);
     161        4049 :   dataStore(stream, cf._position, context);
     162        4049 : }
     163             : 
     164             : template <>
     165             : inline void
     166        4049 : dataLoad(std::istream & stream, Xfem::CutFace & cf, void * context)
     167             : {
     168        4049 :   dataLoad(stream, cf._face_id, context);
     169        4049 :   dataLoad(stream, cf._face_edge, context);
     170        4049 :   dataLoad(stream, cf._position, context);
     171        4049 : }
     172             : 
     173             : template <>
     174             : inline void
     175        6255 : dataStore(std::ostream & stream, Xfem::GeomMarkedElemInfo2D & gmei, void * context)
     176             : {
     177        6255 :   dataStore(stream, gmei._elem_cut_edges, context);
     178        6255 :   dataStore(stream, gmei._elem_cut_nodes, context);
     179        6255 :   dataStore(stream, gmei._frag_cut_edges, context);
     180        6255 :   dataStore(stream, gmei._frag_edges, context);
     181        6255 : }
     182             : 
     183             : template <>
     184             : inline void
     185        6753 : dataLoad(std::istream & stream, Xfem::GeomMarkedElemInfo2D & gmei, void * context)
     186             : {
     187        6753 :   dataLoad(stream, gmei._elem_cut_edges, context);
     188        6753 :   dataLoad(stream, gmei._elem_cut_nodes, context);
     189        6753 :   dataLoad(stream, gmei._frag_cut_edges, context);
     190        6753 :   dataLoad(stream, gmei._frag_edges, context);
     191        6753 : }
     192             : 
     193             : template <>
     194             : inline void
     195        1190 : dataStore(std::ostream & stream, Xfem::GeomMarkedElemInfo3D & gmei, void * context)
     196             : {
     197        1190 :   dataStore(stream, gmei._elem_cut_faces, context);
     198        1190 :   dataStore(stream, gmei._frag_cut_faces, context);
     199        1190 :   dataStore(stream, gmei._frag_faces, context);
     200        1190 : }
     201             : 
     202             : template <>
     203             : inline void
     204        1190 : dataLoad(std::istream & stream, Xfem::GeomMarkedElemInfo3D & gmei, void * context)
     205             : {
     206        1190 :   dataLoad(stream, gmei._elem_cut_faces, context);
     207        1190 :   dataLoad(stream, gmei._frag_cut_faces, context);
     208        1190 :   dataLoad(stream, gmei._frag_faces, context);
     209        1190 : }
     210             : 
     211             : void
     212        1144 : GeometricCutUserObject::serialize(std::string & serialized_buffer)
     213             : {
     214             :   // stream for serializing the _marked_elems_2d and _marked_elems_3d data structures to a byte
     215             :   // stream
     216        1144 :   std::ostringstream oss;
     217        1144 :   dataStore(oss, _marked_elems_2d, this);
     218        1144 :   dataStore(oss, _marked_elems_3d, this);
     219             : 
     220             :   // Populate the passed in string pointer with the string stream's buffer contents
     221        1144 :   serialized_buffer.assign(oss.str());
     222        1144 : }
     223             : 
     224             : void
     225        1144 : GeometricCutUserObject::deserialize(std::vector<std::string> & serialized_buffers)
     226             : {
     227             :   mooseAssert(serialized_buffers.size() == _app.n_processors(),
     228             :               "Unexpected size of serialized_buffers: " << serialized_buffers.size());
     229             : 
     230             :   // The input string stream used for deserialization
     231        1144 :   std::istringstream iss;
     232             : 
     233             :   // Loop over all datastructures for all processors to perfrom the gather operation
     234        3696 :   for (unsigned int rank = 0; rank < serialized_buffers.size(); ++rank)
     235             :   {
     236             :     // skip the current processor (its data is already in the structures)
     237        2552 :     if (rank == processor_id())
     238        1144 :       continue;
     239             : 
     240             :     // populate the stream with a new buffer and reset stream state
     241        1408 :     iss.clear();
     242             :     iss.str(serialized_buffers[rank]);
     243             : 
     244             :     // Load the communicated data into temporary structures
     245             :     std::map<unsigned int, std::vector<Xfem::GeomMarkedElemInfo2D>> other_marked_elems_2d;
     246             :     std::map<unsigned int, std::vector<Xfem::GeomMarkedElemInfo3D>> other_marked_elems_3d;
     247        1408 :     dataLoad(iss, other_marked_elems_2d, this);
     248        1408 :     dataLoad(iss, other_marked_elems_3d, this);
     249             : 
     250             :     // merge the data in with the current processor's data
     251        1408 :     _marked_elems_2d.insert(other_marked_elems_2d.begin(), other_marked_elems_2d.end());
     252        1408 :     _marked_elems_3d.insert(other_marked_elems_3d.begin(), other_marked_elems_3d.end());
     253             :   }
     254        1144 : }
     255             : 
     256             : void
     257        2172 : GeometricCutUserObject::finalize()
     258             : {
     259             :   // for single processor runs we do not need to do anything here
     260        2172 :   if (_app.n_processors() > 1)
     261             :   {
     262             :     // create send buffer
     263             :     std::string send_buffer;
     264             : 
     265             :     // create byte buffers for the streams received from all processors
     266             :     std::vector<std::string> recv_buffers;
     267             : 
     268             :     // pack the complex datastructures into the string stream
     269        1144 :     serialize(send_buffer);
     270             : 
     271             :     // broadcast serialized data to and receive from all processors
     272        1144 :     _communicator.allgather(send_buffer, recv_buffers);
     273             : 
     274             :     // unpack the received data and merge it into the local data structures
     275        1144 :     deserialize(recv_buffers);
     276        1144 :   }
     277             : 
     278       27358 :   for (const auto & it : _marked_elems_2d)
     279       50372 :     for (const auto & gmei : it.second)
     280       25186 :       _xfem->addGeomMarkedElem2D(it.first, gmei, _interface_id);
     281             : 
     282        7460 :   for (const auto & it : _marked_elems_3d)
     283       10576 :     for (const auto & gmei : it.second)
     284        5288 :       _xfem->addGeomMarkedElem3D(it.first, gmei, _interface_id);
     285             : 
     286             :   _marked_elems_2d.clear();
     287             :   _marked_elems_3d.clear();
     288        2172 : }
     289             : 
     290             : CutSubdomainID
     291        2625 : GeometricCutUserObject::getCutSubdomainID(const Elem * elem) const
     292             : {
     293        2625 :   return _xfem->getCutSubdomainID(this, elem);
     294             : }

Generated by: LCOV version 1.14