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

Generated by: LCOV version 1.14