https://mooseframework.inl.gov
Loading...
Searching...
No Matches
XFEMCutElem2D.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 "XFEMCutElem2D.h"
11
12#include "EFANode.h"
13#include "EFAEdge.h"
14#include "EFAFragment2D.h"
15#include "XFEMFuncs.h"
16#include "MooseError.h"
17
18#include "libmesh/mesh.h"
19#include "libmesh/elem.h"
20#include "libmesh/node.h"
21#include "libmesh/petsc_macro.h"
22#include "petscblaslapack.h"
23
25 const EFAElement2D * const CEMelem,
26 unsigned int n_qpoints,
27 unsigned int n_sides)
28 : XFEMCutElem(elem, n_qpoints, n_sides), _efa_elem2d(CEMelem, true)
29{
31}
32
34
35Point
36XFEMCutElem2D::getNodeCoordinates(EFANode * CEMnode, MeshBase * displaced_mesh) const
37{
38 Point node_coor(0.0, 0.0, 0.0);
39 std::vector<EFANode *> master_nodes;
40 std::vector<Point> master_points;
41 std::vector<double> master_weights;
42
43 _efa_elem2d.getMasterInfo(CEMnode, master_nodes, master_weights);
44 for (unsigned int i = 0; i < master_nodes.size(); ++i)
45 {
46 if (master_nodes[i]->category() == EFANode::N_CATEGORY_LOCAL_INDEX)
47 {
48 Node * node = _nodes[master_nodes[i]->id()];
49 if (displaced_mesh)
50 node = displaced_mesh->node_ptr(node->id());
51 Point node_p((*node)(0), (*node)(1), 0.0);
52 master_points.push_back(node_p);
53 }
54 else
55 mooseError("master nodes must be local");
56 }
57 for (unsigned int i = 0; i < master_nodes.size(); ++i)
58 node_coor += master_weights[i] * master_points[i];
59 return node_coor;
60}
61
62void
64{
65 Real frag_vol = 0.0;
66
67 // Calculate area of entire element and fragment using the formula:
68 // A = 1/2 sum_{i=0}^{n-1} (x_i y_{i+1} - x_{i+1} y{i})
69
70 for (unsigned int i = 0; i < _efa_elem2d.getFragment(0)->numEdges(); ++i)
71 {
74 frag_vol += 0.5 * (edge_p1(0) - edge_p2(0)) * (edge_p1(1) + edge_p2(1));
75 }
77}
78
79void
81{
82 Real frag_surf = 0.0;
83
84 EFAEdge * edge = _efa_elem2d.getEdge(side);
85
86 for (unsigned int i = 0; i < _efa_elem2d.getFragment(0)->numEdges(); ++i)
87 {
88 EFANode * node_1 = _efa_elem2d.getFragmentEdge(0, i)->getNode(0);
89 EFANode * node_2 = _efa_elem2d.getFragmentEdge(0, i)->getNode(1);
90
92 if (edge->containsNode(node_1) && edge->containsNode(node_2))
93 {
94 Point edge_p1 = getNodeCoordinates(node_1);
95 Point edge_p2 = getNodeCoordinates(node_2);
96 frag_surf = (edge_p1 - edge_p2).norm();
97 _physical_areafrac[side] = frag_surf / _elem_side_area[side];
98 return;
99 }
100 }
101 _physical_areafrac[side] = 1.0;
102}
103
104void
106{
107 // Purpose: calculate new weights via moment-fitting method
108 std::vector<Point> elem_nodes(_n_nodes, Point(0.0, 0.0, 0.0));
109 std::vector<std::vector<Real>> wsg;
110
111 for (unsigned int i = 0; i < _n_nodes; ++i)
112 elem_nodes[i] = (*_nodes[i]);
113
114 if (_efa_elem2d.isPartial() && _n_qpoints <= 6) // ONLY work for <= 6 q_points
115 {
116 std::vector<std::vector<Real>> tsg;
117 getPhysicalQuadraturePoints(tsg); // get tsg - QPs within partial element
119 _n_nodes, _n_qpoints, elem_nodes, tsg, wsg); // get wsg - QPs from moment-fitting
120 _new_weights.resize(wsg.size(), 1.0);
121 for (unsigned int i = 0; i < wsg.size(); ++i)
122 _new_weights[i] = wsg[i][2]; // weight multiplier
123 }
124 else
126}
127
128Point
129XFEMCutElem2D::getCutPlaneOrigin(unsigned int plane_id, MeshBase * displaced_mesh) const
130{
131 Point orig(0.0, 0.0, 0.0);
132 std::vector<std::vector<EFANode *>> cut_line_nodes;
133 for (unsigned int i = 0; i < _efa_elem2d.getFragment(0)->numEdges(); ++i)
134 {
136 {
137 std::vector<EFANode *> node_line(2, nullptr);
138 node_line[0] = _efa_elem2d.getFragmentEdge(0, i)->getNode(0);
139 node_line[1] = _efa_elem2d.getFragmentEdge(0, i)->getNode(1);
140 cut_line_nodes.push_back(node_line);
141 }
142 }
143 if (cut_line_nodes.size() == 0)
144 mooseError("no cut line found in this element");
145 if (plane_id < cut_line_nodes.size()) // valid plane_id
146 orig = getNodeCoordinates(cut_line_nodes[plane_id][0], displaced_mesh);
147 return orig;
148}
149
150Point
151XFEMCutElem2D::getCutPlaneNormal(unsigned int plane_id, MeshBase * displaced_mesh) const
152{
153 Point normal(0.0, 0.0, 0.0);
154 std::vector<std::vector<EFANode *>> cut_line_nodes;
155 for (unsigned int i = 0; i < _efa_elem2d.getFragment(0)->numEdges(); ++i)
156 {
158 {
159 std::vector<EFANode *> node_line(2, nullptr);
160 node_line[0] = _efa_elem2d.getFragmentEdge(0, i)->getNode(0);
161 node_line[1] = _efa_elem2d.getFragmentEdge(0, i)->getNode(1);
162 cut_line_nodes.push_back(node_line);
163 }
164 }
165 if (cut_line_nodes.size() == 0)
166 mooseError("no cut line found in this element");
167 if (plane_id < cut_line_nodes.size()) // valid plane_id
168 {
169 Point cut_line_p1 = getNodeCoordinates(cut_line_nodes[plane_id][0], displaced_mesh);
170 Point cut_line_p2 = getNodeCoordinates(cut_line_nodes[plane_id][1], displaced_mesh);
171 Point cut_line = cut_line_p2 - cut_line_p1;
172 Real len = std::sqrt(cut_line.norm_sq());
173 cut_line /= len;
174 normal = Point(cut_line(1), -cut_line(0), 0.0);
175 }
176 return normal;
177}
178
179void
181 Point & origin,
182 Point & direction) const
183{
184 // TODO: two cut plane case is not working
185 std::vector<EFANode *> cut_line_nodes;
186 for (unsigned int i = 0; i < _efa_elem2d.getFragment(0)->numEdges(); ++i)
187 {
189 {
190 std::vector<EFANode *> node_line(2, nullptr);
191 node_line[0] = _efa_elem2d.getFragmentEdge(0, i)->getNode(0);
192 node_line[1] = _efa_elem2d.getFragmentEdge(0, i)->getNode(1);
193 if (node_line[1]->id() == tip_id)
194 {
195 cut_line_nodes.push_back(node_line[0]);
196 cut_line_nodes.push_back(node_line[1]);
197 }
198 else if (node_line[0]->id() == tip_id)
199 {
200 node_line[1] = node_line[0];
201 node_line[0] = _efa_elem2d.getFragmentEdge(0, i)->getNode(1);
202 cut_line_nodes.push_back(node_line[0]);
203 cut_line_nodes.push_back(node_line[1]);
204 }
205 }
206 }
207 if (cut_line_nodes.size() == 0)
208 mooseError("no cut line found in this element");
209
210 Point cut_line_p1 = getNodeCoordinates(cut_line_nodes[0]);
211 Point cut_line_p2 = getNodeCoordinates(cut_line_nodes[1]);
212 Point cut_line = cut_line_p2 - cut_line_p1;
213 Real len = std::sqrt(cut_line.norm_sq());
214 cut_line /= len;
215 origin = cut_line_p2;
216 direction = Point(cut_line(0), cut_line(1), 0.0);
217}
218
219void
220XFEMCutElem2D::getFragmentFaces(std::vector<std::vector<Point>> & frag_faces,
221 MeshBase * displaced_mesh) const
222{
223 frag_faces.clear();
224 for (unsigned int i = 0; i < _efa_elem2d.getFragment(0)->numEdges(); ++i)
225 {
226 std::vector<Point> edge_points(2, Point(0.0, 0.0, 0.0));
227 edge_points[0] =
228 getNodeCoordinates(_efa_elem2d.getFragmentEdge(0, i)->getNode(0), displaced_mesh);
229 edge_points[1] =
230 getNodeCoordinates(_efa_elem2d.getFragmentEdge(0, i)->getNode(1), displaced_mesh);
231 frag_faces.push_back(edge_points);
232 }
233}
234
235const EFAElement *
237{
238 return &_efa_elem2d;
239}
240
241unsigned int
243{
244 unsigned int counter = 0;
245 for (unsigned int i = 0; i < _efa_elem2d.getFragment(0)->numEdges(); ++i)
247 counter += 1;
248 return counter;
249}
250
251void
252XFEMCutElem2D::getPhysicalQuadraturePoints(std::vector<std::vector<Real>> & tsg)
253{
254 // Get the coords for parial element nodes
256 unsigned int nnd_pe = frag->numEdges();
257 std::vector<Point> frag_points(nnd_pe, Point(0.0, 0.0, 0.0)); // nodal coord of partial elem
258 Real jac = 0.0;
259
260 for (unsigned int j = 0; j < nnd_pe; ++j)
261 frag_points[j] = getNodeCoordinates(frag->getEdge(j)->getNode(0));
262
263 // Get centroid coords for partial elements
264 Point xcrd(0.0, 0.0, 0.0);
265 for (unsigned int j = 0; j < nnd_pe; ++j)
266 xcrd += frag_points[j];
267 xcrd *= (1.0 / nnd_pe);
268
269 // Get tsg - the physical coords of Gaussian Q-points for partial elements
270 if ((nnd_pe == 3) || (nnd_pe == 4)) // partial element is a triangle or quad
271 {
272 std::vector<std::vector<Real>> sg2;
273 std::vector<std::vector<Real>> shape(nnd_pe, std::vector<Real>(3, 0.0));
274 Xfem::stdQuadr2D(nnd_pe, 2, sg2);
275 for (unsigned int l = 0; l < sg2.size(); ++l)
276 {
277 Xfem::shapeFunc2D(nnd_pe, sg2[l], frag_points, shape, jac, true); // Get shape
278 std::vector<Real> tsg_line(3, 0.0);
279 for (unsigned int k = 0; k < nnd_pe; ++k)
280 {
281 tsg_line[0] += shape[k][2] * frag_points[k](0);
282 tsg_line[1] += shape[k][2] * frag_points[k](1);
283 }
284 if (nnd_pe == 3) // tri partial elem
285 tsg_line[2] = sg2[l][3] * jac; // total weights
286 else // quad partial elem
287 tsg_line[2] = sg2[l][2] * jac; // total weights
288 tsg.push_back(tsg_line);
289 }
290 }
291 else if (nnd_pe >= 5) // partial element is a polygon
292 {
293 for (unsigned int j = 0; j < nnd_pe; ++j) // loop all sub-tris
294 {
295 std::vector<std::vector<Real>> shape(3, std::vector<Real>(3, 0.0));
296 std::vector<Point> subtri_points(3, Point(0.0, 0.0, 0.0)); // sub-tri nodal coords
297
298 int jplus1 = j < nnd_pe - 1 ? j + 1 : 0;
299 subtri_points[0] = xcrd;
300 subtri_points[1] = frag_points[j];
301 subtri_points[2] = frag_points[jplus1];
302
303 std::vector<std::vector<Real>> sg2;
304 Xfem::stdQuadr2D(3, 2, sg2); // get sg2
305 for (unsigned int l = 0; l < sg2.size(); ++l) // loop all int pts on a sub-tri
306 {
307 Xfem::shapeFunc2D(3, sg2[l], subtri_points, shape, jac, true); // Get shape
308 std::vector<Real> tsg_line(3, 0.0);
309 for (unsigned int k = 0; k < 3; ++k) // loop sub-tri nodes
310 {
311 tsg_line[0] += shape[k][2] * subtri_points[k](0);
312 tsg_line[1] += shape[k][2] * subtri_points[k](1);
313 }
314 tsg_line[2] = sg2[l][3] * jac;
315 tsg.push_back(tsg_line);
316 }
317 }
318 }
319 else
320 mooseError("Invalid partial element!");
321}
322
323void
325 unsigned int nqp,
326 std::vector<Point> & elem_nodes,
327 std::vector<std::vector<Real>> & tsg,
328 std::vector<std::vector<Real>> & wsg)
329{
330 // Get physical coords for the new six-point rule
331 std::vector<std::vector<Real>> shape(nen, std::vector<Real>(3, 0.0));
332 std::vector<std::vector<Real>> wss;
333
334 if (nen == 4)
335 {
336 wss.resize(_qp_points.size());
337 for (unsigned int i = 0; i < _qp_points.size(); i++)
338 {
339 wss[i].resize(3);
340 wss[i][0] = _qp_points[i](0);
341 wss[i][1] = _qp_points[i](1);
342 wss[i][2] = _qp_weights[i];
343 }
344 }
345 else if (nen == 3)
346 {
347 wss.resize(_qp_points.size());
348 for (unsigned int i = 0; i < _qp_points.size(); i++)
349 {
350 wss[i].resize(4);
351 wss[i][0] = _qp_points[i](0);
352 wss[i][1] = _qp_points[i](1);
353 wss[i][2] = 1.0 - _qp_points[i](0) - _qp_points[i](1);
354 wss[i][3] = _qp_weights[i];
355 }
356 }
357 else
358 mooseError("Invalid element");
359
360 wsg.resize(wss.size());
361 for (unsigned int i = 0; i < wsg.size(); ++i)
362 wsg[i].resize(3, 0.0);
363 Real jac = 0.0;
364 std::vector<Real> old_weights(wss.size(), 0.0);
365
366 for (unsigned int l = 0; l < wsg.size(); ++l)
367 {
368 Xfem::shapeFunc2D(nen, wss[l], elem_nodes, shape, jac, true); // Get shape
369 if (nen == 4) // 2D quad elem
370 old_weights[l] = wss[l][2] * jac; // weights for total element
371 else if (nen == 3) // 2D triangle elem
372 old_weights[l] = wss[l][3] * jac;
373 else
374 mooseError("Invalid element!");
375 for (unsigned int k = 0; k < nen; ++k) // physical coords of Q-pts
376 {
377 wsg[l][0] += shape[k][2] * elem_nodes[k](0);
378 wsg[l][1] += shape[k][2] * elem_nodes[k](1);
379 }
380 }
381
382 // Compute weights via moment fitting
383 Real * A;
384 A = new Real[wsg.size() * wsg.size()];
385 unsigned ind = 0;
386 for (unsigned int i = 0; i < wsg.size(); ++i)
387 {
388 A[ind] = 1.0; // const
389 if (nqp > 1)
390 A[1 + ind] = wsg[i][0]; // x
391 if (nqp > 2)
392 A[2 + ind] = wsg[i][1]; // y
393 if (nqp > 3)
394 A[3 + ind] = wsg[i][0] * wsg[i][1]; // x*y
395 if (nqp > 4)
396 A[4 + ind] = wsg[i][0] * wsg[i][0]; // x^2
397 if (nqp > 5)
398 A[5 + ind] = wsg[i][1] * wsg[i][1]; // y^2
399 if (nqp > 6)
400 mooseError("Q-points of more than 6 are not allowed now!");
401 ind = ind + nqp;
402 }
403
404 Real * b;
405 b = new Real[wsg.size()];
406 for (unsigned int i = 0; i < wsg.size(); ++i)
407 b[i] = 0.0;
408 for (unsigned int i = 0; i < tsg.size(); ++i)
409 {
410 b[0] += tsg[i][2];
411 if (nqp > 1)
412 b[1] += tsg[i][2] * tsg[i][0];
413 if (nqp > 2)
414 b[2] += tsg[i][2] * tsg[i][1];
415 if (nqp > 3)
416 b[3] += tsg[i][2] * tsg[i][0] * tsg[i][1];
417 if (nqp > 4)
418 b[4] += tsg[i][2] * tsg[i][0] * tsg[i][0];
419 if (nqp > 5)
420 b[5] += tsg[i][2] * tsg[i][1] * tsg[i][1];
421 if (nqp > 6)
422 mooseError("Q-points of more than 6 are not allowed now!");
423 }
424
425 PetscBLASInt nrhs = 1;
426 PetscBLASInt info;
427 PetscBLASInt n = wsg.size();
428 std::vector<PetscBLASInt> ipiv(n);
429
430 LAPACKgesv_(&n, &nrhs, A, &n, &ipiv[0], b, &n, &info);
431
432 for (unsigned int i = 0; i < wsg.size(); ++i)
433 wsg[i][2] = b[i] / old_weights[i]; // get the multiplier
434
435 // delete arrays
436 delete[] A;
437 delete[] b;
438}
439
440void
442 Point & normal,
443 std::vector<Point> & intersectionPoints,
444 MeshBase * displaced_mesh) const
445{
446 intersectionPoints.resize(2); // 2D: the intersection line is straight and can be represented by
447 // two ending points.(may have issues with double cuts case!)
448
449 std::vector<std::vector<EFANode *>> cut_line_nodes;
450 for (unsigned int i = 0; i < _efa_elem2d.getFragment(0)->numEdges(); ++i)
451 {
453 {
454 std::vector<EFANode *> node_line(2, nullptr);
455 node_line[0] = _efa_elem2d.getFragmentEdge(0, i)->getNode(0);
456 node_line[1] = _efa_elem2d.getFragmentEdge(0, i)->getNode(1);
457 cut_line_nodes.push_back(node_line);
458 }
459 }
460 if (cut_line_nodes.size() == 0)
461 mooseError("No cut line found in this element");
462
463 if (plane_id < cut_line_nodes.size()) // valid plane_id
464 {
465 intersectionPoints[0] = getNodeCoordinates(cut_line_nodes[plane_id][0], displaced_mesh);
466 intersectionPoints[1] = getNodeCoordinates(cut_line_nodes[plane_id][1], displaced_mesh);
467 }
468
469 normal = getCutPlaneNormal(plane_id, displaced_mesh);
470}
void mooseError(Args &&... args)
EFANode * getNode(unsigned int index) const
Definition EFAEdge.C:181
EFAFragment2D * getFragment(unsigned int frag_id) const
virtual bool isPartial() const
virtual void getMasterInfo(EFANode *node, std::vector< EFANode * > &master_nodes, std::vector< double > &master_weights) const
EFAEdge * getEdge(unsigned int edge_id) const
EFAEdge * getFragmentEdge(unsigned int frag_id, unsigned int edge_id) const
bool isEdgeInterior(unsigned int edge_id) const
EFAEdge * getEdge(unsigned int edge_id) const
unsigned int numEdges() const
@ N_CATEGORY_LOCAL_INDEX
Definition EFANode.h:23
virtual void computePhysicalFaceAreaFraction(unsigned int side)
Computes the surface area fraction of the element side.
virtual Point getCutPlaneOrigin(unsigned int plane_id, MeshBase *displaced_mesh=nullptr) const
virtual void computePhysicalVolumeFraction()
Computes the volume fraction of the element fragment.
EFAElement2D _efa_elem2d
virtual Point getCutPlaneNormal(unsigned int plane_id, MeshBase *displaced_mesh=nullptr) const
virtual const EFAElement * getEFAElement() const
void getPhysicalQuadraturePoints(std::vector< std::vector< Real > > &tsg)
virtual void computeMomentFittingWeights()
virtual Point getNodeCoordinates(EFANode *node, MeshBase *displaced_mesh=nullptr) const
void solveMomentFitting(unsigned int nen, unsigned int nqp, std::vector< Point > &elem_nodes, std::vector< std::vector< Real > > &tsg, std::vector< std::vector< Real > > &wsg)
virtual void getFragmentFaces(std::vector< std::vector< Point > > &frag_faces, MeshBase *displaced_mesh=nullptr) const
virtual void getIntersectionInfo(unsigned int plane_id, Point &normal, std::vector< Point > &intersectionPoints, MeshBase *displaced_mesh=nullptr) const
virtual unsigned int numCutPlanes() const
virtual void getCrackTipOriginAndDirection(unsigned tip_id, Point &origin, Point &direction) const
XFEMCutElem2D(Elem *elem, const EFAElement2D *const CEMelem, unsigned int n_qpoints, unsigned int n_sides)
Constructor initializes XFEMCutElem2D object.
Real _physical_volfrac
Definition XFEMCutElem.h:50
std::vector< Real > _qp_weights
Definition XFEMCutElem.h:47
std::vector< Real > _new_weights
quadrature weights from volume fraction and moment fitting
Definition XFEMCutElem.h:55
unsigned int _n_nodes
Definition XFEMCutElem.h:42
Real _elem_volume
Definition XFEMCutElem.h:48
std::vector< Node * > _nodes
Definition XFEMCutElem.h:45
std::vector< Point > _qp_points
Definition XFEMCutElem.h:46
std::vector< Real > _physical_areafrac
Definition XFEMCutElem.h:51
unsigned int _n_qpoints
Definition XFEMCutElem.h:43
std::vector< Real > _elem_side_area
Definition XFEMCutElem.h:49
dof_id_type id() const
virtual const Node * node_ptr(const dof_id_type i) const=0
auto norm_sq() const
void stdQuadr2D(unsigned int nen, unsigned int iord, std::vector< std::vector< Real > > &sg2)
Definition XFEMFuncs.C:96
void shapeFunc2D(unsigned int nen, std::vector< Real > &ss, std::vector< Point > &xl, std::vector< std::vector< Real > > &shp, Real &xsj, bool natl_flg)
Definition XFEMFuncs.C:269
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real