https://mooseframework.inl.gov
GeometricCutUserObject.C
Go to the documentation of this file.
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 
23 {
25  params.addClassDescription("Base UserObject class for XFEM Geometric Cuts");
26  params.addParam<bool>("heal_always", false, "Heal previous cuts at every time step");
27  ExecFlagEnum & exec = params.set<ExecFlagEnum>("execute_on");
29  params.setDocString("execute_on", exec.getDocString());
30  params.set<ExecFlagEnum>("execute_on") = EXEC_XFEM_MARK;
31 
32  return params;
33 }
34 
36  const bool uses_mesh)
37  : CrackFrontPointsProvider(parameters, uses_mesh), _heal_always(getParam<bool>("heal_always"))
38 {
39  _xfem = MooseSharedNamespace::dynamic_pointer_cast<XFEM>(_fe_problem.getXFEM());
40  if (_xfem == nullptr)
41  mooseError("Problem casting to XFEM in GeometricCutUserObject");
42 
43  _xfem->addGeometricCut(this);
44 
45  auto new_xfem_epl = std::make_shared<XFEMElementPairLocator>(_xfem, _interface_id);
47 
48  if (_fe_problem.getDisplacedProblem() != nullptr)
49  {
50  auto new_xfem_epl2 = std::make_shared<XFEMElementPairLocator>(_xfem, _interface_id, true);
51  _fe_problem.getDisplacedProblem()->geomSearchData().addElementPairLocator(_interface_id,
52  new_xfem_epl2);
53  }
54 }
55 
56 void
58 {
59  _marked_elems_2d.clear();
60  _marked_elems_3d.clear();
61 }
62 
63 void
65 {
66  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  EFAElement2D * EFAElem = _xfem->getEFAElem2D(_current_elem);
74 
75  // Don't cut again if elem has been already cut twice
76  if (!EFAElem->isFinalCut())
77  {
78  // get fragment edges
79  _xfem->getFragmentEdges(_current_elem, EFAElem, frag_edges);
80 
81  // mark cut edges for the element and its fragment
82  bool cut = cutElementByGeometry(_current_elem, elem_cut_edges, elem_cut_nodes);
83  if (EFAElem->numFragments() > 0)
84  cut |= cutFragmentByGeometry(frag_edges, frag_cut_edges);
85 
86  if (cut)
87  {
89  gmei2d._elem_cut_edges = elem_cut_edges;
90  gmei2d._elem_cut_nodes = elem_cut_nodes;
91  gmei2d._frag_cut_edges = frag_cut_edges;
92  gmei2d._frag_edges = frag_edges;
93  _marked_elems_2d[_current_elem->id()].push_back(gmei2d);
94  }
95  }
96  }
97  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  EFAElement3D * EFAElem = _xfem->getEFAElem3D(_current_elem);
104 
105  // Don't cut again if elem has been already cut twice
106  if (!EFAElem->isFinalCut())
107  {
108  // get fragment edges
109  _xfem->getFragmentFaces(_current_elem, EFAElem, frag_faces);
110 
111  // mark cut faces for the element and its fragment
112  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  if (cut)
118  {
120  gmei3d._elem_cut_faces = elem_cut_faces;
121  gmei3d._frag_cut_faces = frag_cut_faces;
122  gmei3d._frag_faces = frag_faces;
123  _marked_elems_3d[_current_elem->id()].push_back(gmei3d);
124  }
125  }
126  }
127 }
128 
129 void
131 {
132  const auto & gcuo = static_cast<const GeometricCutUserObject &>(y);
133 
134  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  _marked_elems_2d[it.first] = it.second;
139  }
140  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  _marked_elems_3d[it.first] = it.second;
145  }
146 }
147 
148 // custom data load and data store methods for structs with std::vector members
149 template <>
150 inline void
151 dataStore(std::ostream & stream, Xfem::CutFace & cf, void * context)
152 {
153  dataStore(stream, cf._face_id, context);
154  dataStore(stream, cf._face_edge, context);
155  dataStore(stream, cf._position, context);
156 }
157 
158 template <>
159 inline void
160 dataLoad(std::istream & stream, Xfem::CutFace & cf, void * context)
161 {
162  dataLoad(stream, cf._face_id, context);
163  dataLoad(stream, cf._face_edge, context);
164  dataLoad(stream, cf._position, context);
165 }
166 
167 template <>
168 inline void
169 dataStore(std::ostream & stream, Xfem::GeomMarkedElemInfo2D & gmei, void * context)
170 {
171  dataStore(stream, gmei._elem_cut_edges, context);
172  dataStore(stream, gmei._elem_cut_nodes, context);
173  dataStore(stream, gmei._frag_cut_edges, context);
174  dataStore(stream, gmei._frag_edges, context);
175 }
176 
177 template <>
178 inline void
179 dataLoad(std::istream & stream, Xfem::GeomMarkedElemInfo2D & gmei, void * context)
180 {
181  dataLoad(stream, gmei._elem_cut_edges, context);
182  dataLoad(stream, gmei._elem_cut_nodes, context);
183  dataLoad(stream, gmei._frag_cut_edges, context);
184  dataLoad(stream, gmei._frag_edges, context);
185 }
186 
187 template <>
188 inline void
189 dataStore(std::ostream & stream, Xfem::GeomMarkedElemInfo3D & gmei, void * context)
190 {
191  dataStore(stream, gmei._elem_cut_faces, context);
192  dataStore(stream, gmei._frag_cut_faces, context);
193  dataStore(stream, gmei._frag_faces, context);
194 }
195 
196 template <>
197 inline void
198 dataLoad(std::istream & stream, Xfem::GeomMarkedElemInfo3D & gmei, void * context)
199 {
200  dataLoad(stream, gmei._elem_cut_faces, context);
201  dataLoad(stream, gmei._frag_cut_faces, context);
202  dataLoad(stream, gmei._frag_faces, context);
203 }
204 
205 void
206 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  std::ostringstream oss;
211  dataStore(oss, _marked_elems_2d, this);
212  dataStore(oss, _marked_elems_3d, this);
213 
214  // Populate the passed in string pointer with the string stream's buffer contents
215  serialized_buffer.assign(oss.str());
216 }
217 
218 void
219 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  std::istringstream iss;
226 
227  // Loop over all datastructures for all processors to perfrom the gather operation
228  for (unsigned int rank = 0; rank < serialized_buffers.size(); ++rank)
229  {
230  // skip the current processor (its data is already in the structures)
231  if (rank == processor_id())
232  continue;
233 
234  // populate the stream with a new buffer and reset stream state
235  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  dataLoad(iss, other_marked_elems_2d, this);
242  dataLoad(iss, other_marked_elems_3d, this);
243 
244  // merge the data in with the current processor's data
245  _marked_elems_2d.insert(other_marked_elems_2d.begin(), other_marked_elems_2d.end());
246  _marked_elems_3d.insert(other_marked_elems_3d.begin(), other_marked_elems_3d.end());
247  }
248 }
249 
250 void
252 {
253  // for single processor runs we do not need to do anything here
254  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  serialize(send_buffer);
264 
265  // broadcast serialized data to and receive from all processors
266  _communicator.allgather(send_buffer, recv_buffers);
267 
268  // unpack the received data and merge it into the local data structures
269  deserialize(recv_buffers);
270  }
271 
272  for (const auto & it : _marked_elems_2d)
273  for (const auto & gmei : it.second)
274  _xfem->addGeomMarkedElem2D(it.first, gmei, _interface_id);
275 
276  for (const auto & it : _marked_elems_3d)
277  for (const auto & gmei : it.second)
278  _xfem->addGeomMarkedElem3D(it.first, gmei, _interface_id);
279 
280  _marked_elems_2d.clear();
281  _marked_elems_3d.clear();
282 }
283 
286 {
287  return _xfem->getCutSubdomainID(this, elem);
288 }
std::map< unsigned int, std::vector< Xfem::GeomMarkedElemInfo2D > > _marked_elems_2d
Containers with information about all 2D and 3D elements marked for cutting by this object...
void allgather(const T &send_data, std::vector< T, A > &recv_data) const
virtual void initialize() override
Data structure describing geometrically described cut through 3D element.
static InputParameters validParams()
Factory constructor, takes parameters so that all derived classes can be built using the same constru...
void dataLoad(std::istream &stream, Xfem::CutFace &cf, void *context)
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
void setDocString(const std::string &name, const std::string &doc)
unsigned int _interface_id
Associated interface id.
virtual void finalize() override
T & set(const std::string &name, bool quiet_mode=false)
virtual void threadJoin(const UserObject &y) override
void addAvailableFlags(const ExecFlagType &flag, Args... flags)
const std::vector< double > y
GeometricCutUserObject(const InputParameters &parameters, const bool uses_mesh=false)
const Parallel::Communicator & _communicator
std::vector< Real > _position
Fractional distance along the cut edges where the cut is located.
void dataStore(std::ostream &stream, Xfem::CutFace &cf, void *context)
virtual unsigned int numFragments() const
Definition: EFAElement2D.C:207
This is the XFEM class.
Definition: XFEM.h:107
virtual void execute() override
std::vector< CutNode > _elem_cut_nodes
Container for data about all cut nodes in this element.
Data structure defining a cut through a face.
std::vector< CutEdge > _elem_cut_edges
Container for data about all cut edges in this element.
unsigned int CutSubdomainID
Definition: XFEMAppTypes.h:18
virtual GeometricSearchData & geomSearchData() override
static InputParameters validParams()
virtual bool cutFragmentByGeometry(std::vector< std::vector< Point >> &frag_edges, std::vector< Xfem::CutEdge > &cut_edges) const =0
Check to see whether a fragment of a 2D element should be cut based on geometric conditions.
std::vector< std::vector< Point > > _frag_edges
Container for data about all cut edges in cut fragments in this element.
processor_id_type n_processors() const
void addElementPairLocator(BoundaryID interface_id, std::shared_ptr< ElementPairLocator > epl)
Base class for crack front points provider.
virtual bool isFinalCut() const
Definition: EFAElement2D.C:796
void deserialize(std::vector< std::string > &serialized_buffers)
std::vector< CutEdge > _frag_cut_edges
Container for data about all cut fragments in this element.
Data structure describing geometrically described cut through 2D element.
virtual CutSubdomainID getCutSubdomainID(const Node *) const
Get CutSubdomainID telling which side the node belongs to relative to the cut.
void serialize(std::string &serialized_buffer)
Methods to pack/unpack the _marked_elems_2d and _marked_elems_3d data into a structure suitable for p...
const ExecFlagType EXEC_XFEM_MARK
Exec flag used to execute MooseObjects while elements are being marked for cutting by XFEM...
Definition: XFEMAppTypes.C:13
std::shared_ptr< XFEM > _xfem
Pointer to the XFEM controller object.
virtual std::shared_ptr< const DisplacedProblem > getDisplacedProblem() const
const Elem *const & _current_elem
FEProblemBase & _fe_problem
std::shared_ptr< XFEMInterface > getXFEM()
void mooseError(Args &&... args) const
void addClassDescription(const std::string &doc_string)
std::vector< CutFace > _frag_cut_faces
Container for data about all faces this element&#39;s fragment.
std::vector< std::vector< Point > > _frag_faces
Container for data about all cut faces in cut fragments in this element.
processor_id_type processor_id() const
std::vector< CutFace > _elem_cut_faces
Container for data about all cut faces in this element.
virtual bool cutElementByGeometry(const Elem *elem, std::vector< Xfem::CutEdge > &cut_edges, std::vector< Xfem::CutNode > &cut_nodes) const =0
Check to see whether a specified 2D element should be cut based on geometric conditions.
std::vector< unsigned int > _face_edge
IDs of all cut faces.
unsigned int _face_id
ID of the cut face.
std::map< unsigned int, std::vector< Xfem::GeomMarkedElemInfo3D > > _marked_elems_3d
virtual bool isFinalCut() const
Definition: EFAElement3D.C:825