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 : }
|