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