https://mooseframework.inl.gov
Loading...
Searching...
No Matches
XFEMFuncs.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 "XFEMFuncs.h"
11
12#include "MooseError.h"
13#include "Conversion.h"
14
15namespace Xfem
16{
17
18void
19dunavant_rule2(const Real * wts,
20 const Real * a,
21 const Real * b,
22 const unsigned int * permutation_ids,
23 unsigned int n_wts,
24 std::vector<Point> & points,
25 std::vector<Real> & weights)
26{
27 // see libmesh/src/quadrature/quadrature_gauss.C
28 // Figure out how many total points by summing up the entries
29 // in the permutation_ids array, and resize the _points and _weights
30 // vectors appropriately.
31 unsigned int total_pts = 0;
32 for (unsigned int p = 0; p < n_wts; ++p)
33 total_pts += permutation_ids[p];
34
35 // Resize point and weight vectors appropriately.
36 points.resize(total_pts);
37 weights.resize(total_pts);
38
39 // Always insert into the points & weights vector relative to the offset
40 unsigned int offset = 0;
41 for (unsigned int p = 0; p < n_wts; ++p)
42 {
43 switch (permutation_ids[p])
44 {
45 case 1:
46 {
47 // The point has only a single permutation (the centroid!)
48 // So we don't even need to look in the a or b arrays.
49 points[offset + 0] = Point(1.0L / 3.0L, 1.0L / 3.0L);
50 weights[offset + 0] = wts[p];
51
52 offset += 1;
53 break;
54 }
55
56 case 3:
57 {
58 // For this type of rule, don't need to look in the b array.
59 points[offset + 0] = Point(a[p], a[p]); // (a,a)
60 points[offset + 1] = Point(a[p], 1.L - 2.L * a[p]); // (a,1-2a)
61 points[offset + 2] = Point(1.L - 2.L * a[p], a[p]); // (1-2a,a)
62
63 for (unsigned int j = 0; j < 3; ++j)
64 weights[offset + j] = wts[p];
65
66 offset += 3;
67 break;
68 }
69
70 case 6:
71 {
72 // This type of point uses all 3 arrays...
73 points[offset + 0] = Point(a[p], b[p]);
74 points[offset + 1] = Point(b[p], a[p]);
75 points[offset + 2] = Point(a[p], 1.L - a[p] - b[p]);
76 points[offset + 3] = Point(1.L - a[p] - b[p], a[p]);
77 points[offset + 4] = Point(b[p], 1.L - a[p] - b[p]);
78 points[offset + 5] = Point(1.L - a[p] - b[p], b[p]);
79
80 for (unsigned int j = 0; j < 6; ++j)
81 weights[offset + j] = wts[p];
82
83 offset += 6;
84 break;
85 }
86
87 default:
88 mooseError("Unknown permutation id: ", permutation_ids[p], "!");
89 }
90 }
91}
92
93void
94stdQuadr2D(unsigned int nen, unsigned int iord, std::vector<std::vector<Real>> & sg2)
95{
96 // Purpose: get Guass integration points for 2D quad and tri elems
97 // N.B. only works for n_qp <= 6
98
99 Real lr4[4] = {-1.0, 1.0, -1.0, 1.0}; // libmesh order
100 Real lz4[4] = {-1.0, -1.0, 1.0, 1.0};
101 Real lr9[9] = {-1.0, 0.0, 1.0, -1.0, 0.0, 1.0, -1.0, 0.0, 1.0}; // libmesh order
102 Real lz9[9] = {-1.0, -1.0, -1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0};
103 Real lw9[9] = {25.0, 40.0, 25.0, 40.0, 64.0, 40.0, 25.0, 40.0, 25.0};
104
105 if (nen == 4) // 2d quad element
106 {
107 if (iord == 1) // 1-point Gauss
108 {
109 sg2.resize(1);
110 sg2[0].resize(3);
111 sg2[0][0] = 0.0;
112 sg2[0][1] = 0.0;
113 sg2[0][2] = 4.0;
114 }
115 else if (iord == 2) // 2x2-point Gauss
116 {
117 sg2.resize(4);
118 for (unsigned int i = 0; i < 4; ++i)
119 sg2[i].resize(3);
120 for (unsigned int i = 0; i < 4; ++i)
121 {
122 sg2[i][0] = (1 / sqrt(3)) * lr4[i];
123 sg2[i][1] = (1 / sqrt(3)) * lz4[i];
124 sg2[i][2] = 1.0;
125 }
126 }
127 else if (iord == 3) // 3x3-point Gauss
128 {
129 sg2.resize(9);
130 for (unsigned int i = 0; i < 9; ++i)
131 sg2[i].resize(3);
132 for (unsigned int i = 0; i < 9; ++i)
133 {
134 sg2[i][0] = sqrt(0.6) * lr9[i];
135 sg2[i][1] = sqrt(0.6) * lz9[i];
136 sg2[i][2] = (1.0 / 81.0) * lw9[i];
137 }
138 }
139 else
140 mooseError("Invalid quadrature order = " + Moose::stringify(iord) + " for quad elements");
141 }
142 else if (nen == 3) // triangle
143 {
144 if (iord == 1) // one-point Gauss
145 {
146 sg2.resize(1);
147 sg2[0].resize(4);
148 sg2[0][0] = 1.0 / 3.0;
149 sg2[0][1] = 1.0 / 3.0;
150 sg2[0][2] = 1.0 / 3.0;
151 sg2[0][3] = 0.5;
152 }
153 else if (iord == 2) // three-point Gauss
154 {
155 sg2.resize(3);
156 for (unsigned int i = 0; i < 3; ++i)
157 sg2[i].resize(4);
158 sg2[0][0] = 2.0 / 3.0;
159 sg2[0][1] = 1.0 / 6.0;
160 sg2[0][2] = 1.0 / 6.0;
161 sg2[0][3] = 1.0 / 6.0;
162 sg2[1][0] = 1.0 / 6.0;
163 sg2[1][1] = 2.0 / 3.0;
164 sg2[1][2] = 1.0 / 6.0;
165 sg2[1][3] = 1.0 / 6.0;
166 sg2[2][0] = 1.0 / 6.0;
167 sg2[2][1] = 1.0 / 6.0;
168 sg2[2][2] = 2.0 / 3.0;
169 sg2[2][3] = 1.0 / 6.0;
170 }
171 else if (iord == 3) // four-point Gauss
172 {
173 sg2.resize(4);
174 for (unsigned int i = 0; i < 4; ++i)
175 sg2[i].resize(4);
176 sg2[0][0] = 1.5505102572168219018027159252941e-01;
177 sg2[0][1] = 1.7855872826361642311703513337422e-01;
178 sg2[0][2] = 1.0 - sg2[0][0] - sg2[0][1];
179 sg2[0][3] = 1.5902069087198858469718450103758e-01;
180
181 sg2[1][0] = 6.4494897427831780981972840747059e-01;
182 sg2[1][1] = 7.5031110222608118177475598324603e-02;
183 sg2[1][2] = 1.0 - sg2[1][0] - sg2[1][1];
184 sg2[1][3] = 9.0979309128011415302815498962418e-02;
185
186 sg2[2][0] = 1.5505102572168219018027159252941e-01;
187 sg2[2][1] = 6.6639024601470138670269327409637e-01;
188 sg2[2][2] = 1.0 - sg2[2][0] - sg2[2][1];
189 sg2[2][3] = 1.5902069087198858469718450103758e-01;
190
191 sg2[3][0] = 6.4494897427831780981972840747059e-01;
192 sg2[3][1] = 2.8001991549907407200279599420481e-01;
193 sg2[3][2] = 1.0 - sg2[3][0] - sg2[3][1];
194 sg2[3][3] = 9.0979309128011415302815498962418e-02;
195 }
196 else if (iord == 4) // six-point Guass
197 {
198 const unsigned int n_wts = 2;
199 const Real wts[n_wts] = {1.1169079483900573284750350421656140e-01L,
200 5.4975871827660933819163162450105264e-02L};
201
202 const Real a[n_wts] = {4.4594849091596488631832925388305199e-01L,
203 9.1576213509770743459571463402201508e-02L};
204
205 const Real b[n_wts] = {0., 0.}; // not used
206 const unsigned int permutation_ids[n_wts] = {3, 3};
207
208 std::vector<Point> points;
209 std::vector<Real> weights;
210 dunavant_rule2(wts, a, b, permutation_ids, n_wts, points, weights); // 6 total points
211
212 sg2.resize(6);
213 for (unsigned int i = 0; i < 6; ++i)
214 sg2[i].resize(4);
215 for (unsigned int i = 0; i < 6; ++i)
216 {
217 sg2[i][0] = points[i](0);
218 sg2[i][1] = points[i](1);
219 sg2[i][2] = 1.0 - points[i](0) - points[i](1);
220 sg2[i][3] = weights[i];
221 }
222 }
223 else
224 mooseError("Invalid quadrature order = " + Moose::stringify(iord) + " for triangle elements");
225 }
226 else
227 mooseError("Invalid 2D element type");
228}
229
230void
231wissmannPoints(unsigned int nqp, std::vector<std::vector<Real>> & wss)
232{
233 if (nqp == 6)
234 {
235 wss.resize(6);
236 for (unsigned int i = 0; i < 6; ++i)
237 wss[i].resize(3);
238 wss[0][0] = 0.0;
239 wss[0][1] = 0.0;
240 wss[0][2] = 1.1428571428571428;
241
242 wss[1][0] = 0.0;
243 wss[1][1] = 9.6609178307929590e-01;
244 wss[1][2] = 4.3956043956043956e-01;
245
246 wss[2][0] = 8.5191465330460049e-01;
247 wss[2][1] = 4.5560372783619284e-01;
248 wss[2][2] = 5.6607220700753210e-01;
249
250 wss[3][0] = -wss[2][0];
251 wss[3][1] = wss[2][1];
252 wss[3][2] = wss[2][2];
253
254 wss[4][0] = 6.3091278897675402e-01;
255 wss[4][1] = -7.3162995157313452e-01;
256 wss[4][2] = 6.4271900178367668e-01;
257
258 wss[5][0] = -wss[4][0];
259 wss[5][1] = wss[4][1];
260 wss[5][2] = wss[4][2];
261 }
262 else
263 mooseError("Unknown Wissmann quadrature type");
264}
265
266void
267shapeFunc2D(unsigned int nen,
268 std::vector<Real> & ss,
269 std::vector<Point> & xl,
270 std::vector<std::vector<Real>> & shp,
271 Real & xsj,
272 bool natl_flg)
273{
274 // Get shape functions and derivatives
275 Real s[4] = {-0.5, 0.5, 0.5, -0.5};
276 Real t[4] = {-0.5, -0.5, 0.5, 0.5};
277
278 if (nen == 4) // quad element
279 {
280 Real xs[2][2] = {{0.0, 0.0}, {0.0, 0.0}};
281 Real sx[2][2] = {{0.0, 0.0}, {0.0, 0.0}};
282 for (unsigned int i = 0; i < 4; ++i)
283 {
284 shp[i][2] = (0.5 + s[i] * ss[0]) * (0.5 + t[i] * ss[1]);
285 shp[i][0] = s[i] * (0.5 + t[i] * ss[1]);
286 shp[i][1] = t[i] * (0.5 + s[i] * ss[0]);
287 }
288 for (unsigned int i = 0; i < 2; ++i) // x, y
289 {
290 for (unsigned int j = 0; j < 2; ++j) // xi, eta
291 {
292 xs[i][j] = 0.0;
293 for (unsigned int k = 0; k < nen; ++k)
294 xs[i][j] += xl[k](i) * shp[k][j];
295 }
296 }
297 xsj = xs[0][0] * xs[1][1] - xs[0][1] * xs[1][0]; // det(j)
298 if (natl_flg == false) // get global derivatives
299 {
300 Real temp = 1.0 / xsj;
301 sx[0][0] = xs[1][1] * temp; // inv(j)
302 sx[1][1] = xs[0][0] * temp;
303 sx[0][1] = -xs[0][1] * temp;
304 sx[1][0] = -xs[1][0] * temp;
305 for (unsigned int i = 0; i < nen; ++i)
306 {
307 temp = shp[i][0] * sx[0][0] + shp[i][1] * sx[1][0];
308 shp[i][1] = shp[i][0] * sx[0][1] + shp[i][1] * sx[1][1];
309 shp[i][0] = temp;
310 }
311 }
312 }
313 else if (nen == 3) // triangle element
314 {
315 // x1*(y2 - y3) + x2*(y3 - y1) + x3*(y1 - y2)
316 Point x13 = xl[2] - xl[0];
317 Point x23 = xl[2] - xl[1];
318 Point cross_prod = x13.cross(x23);
319 xsj = cross_prod.norm();
320 Real xsjr = 1.0;
321 if (xsj != 0.0)
322 xsjr = 1.0 / xsj;
323 // xsj *= 0.5; // we do not have this 0.5 here because in stdQuad2D the sum of all weights in
324 // tri is 0.5
325 shp[0][2] = ss[0];
326 shp[1][2] = ss[1];
327 shp[2][2] = ss[2];
328 if (natl_flg == false) // need global drivatives
329 {
330 shp[0][0] = (xl[1](1) - xl[2](1)) * xsjr;
331 shp[0][1] = (xl[2](0) - xl[1](0)) * xsjr;
332 shp[1][0] = (xl[2](1) - xl[0](1)) * xsjr;
333 shp[1][1] = (xl[0](0) - xl[2](0)) * xsjr;
334 shp[2][0] = (xl[0](1) - xl[1](1)) * xsjr;
335 shp[2][1] = (xl[1](0) - xl[0](0)) * xsjr;
336 }
337 else
338 {
339 shp[0][0] = 1.0;
340 shp[0][1] = 0.0;
341 shp[1][0] = 0.0;
342 shp[1][1] = 1.0;
343 shp[2][0] = -1.0;
344 shp[2][1] = -1.0;
345 }
346 }
347 else
348 mooseError("ShapeFunc2D only works for linear quads and tris!");
349}
350
351double
352r8vec_norm(int n, double a[])
353{
354 // John Burkardt geometry.cpp
355 double v = 0.0;
356 for (int i = 0; i < n; ++i)
357 v = v + a[i] * a[i];
358 v = std::sqrt(v);
359 return v;
360}
361
362void
363r8vec_copy(int n, double a1[], double a2[])
364{
365 // John Burkardt geometry.cpp
366 for (int i = 0; i < n; ++i)
367 a2[i] = a1[i];
368 return;
369}
370
371bool
372r8vec_eq(int n, double a1[], double a2[])
373{
374 // John Burkardt geometry.cpp
375 for (int i = 0; i < n; ++i)
376 if (a1[i] != a2[i])
377 return false;
378 return true;
379}
380
381double
382r8vec_dot_product(int n, double a1[], double a2[])
383{
384 // John Burkardt geometry.cpp
385 double value = 0.0;
386 for (int i = 0; i < n; ++i)
387 value += a1[i] * a2[i];
388 return value;
389}
390
391bool
392line_exp_is_degenerate_nd(int dim_num, double p1[], double p2[])
393{
394 // John Burkardt geometry.cpp
395 bool value;
396 value = r8vec_eq(dim_num, p1, p2);
397 return value;
398}
399
400int
402 double pp[3], double normal[3], double p1[3], double p2[3], double pint[3])
403{
404// John Burkardt geometry.cpp
405// Parameters:
406//
407// Input, double PP[3], a point on the plane.
408//
409// Input, double NORMAL[3], a normal vector to the plane.
410//
411// Input, double P1[3], P2[3], two distinct points on the line.
412//
413// Output, double PINT[3], the coordinates of a
414// common point of the plane and line, when IVAL is 1 or 2.
415//
416// Output, integer PLANE_NORMAL_LINE_EXP_INT_3D, the kind of intersection;
417// 0, the line and plane seem to be parallel and separate;
418// 1, the line and plane intersect at a single point;
419// 2, the line and plane seem to be parallel and joined.
420#define DIM_NUM 3
421
422 double direction[DIM_NUM];
423 int ival;
424 double temp;
425 double temp2;
426 //
427 // Make sure the line is not degenerate.
428 if (line_exp_is_degenerate_nd(DIM_NUM, p1, p2))
429 mooseError("PLANE_NORMAL_LINE_EXP_INT_3D - Fatal error! The line is degenerate.");
430 //
431 // Make sure the plane normal vector is a unit vector.
432 temp = r8vec_norm(DIM_NUM, normal);
433 if (temp == 0.0)
434 mooseError("PLANE_NORMAL_LINE_EXP_INT_3D - Fatal error! The normal vector of the plane is "
435 "degenerate.");
436
437 for (unsigned int i = 0; i < DIM_NUM; ++i)
438 normal[i] = normal[i] / temp;
439 //
440 // Determine the unit direction vector of the line.
441 for (unsigned int i = 0; i < DIM_NUM; ++i)
442 direction[i] = p2[i] - p1[i];
443 temp = r8vec_norm(DIM_NUM, direction);
444
445 for (unsigned int i = 0; i < DIM_NUM; ++i)
446 direction[i] = direction[i] / temp;
447 //
448 // If the normal and direction vectors are orthogonal, then
449 // we have a special case to deal with.
450 if (r8vec_dot_product(DIM_NUM, normal, direction) == 0.0)
451 {
452 temp = 0.0;
453 for (unsigned int i = 0; i < DIM_NUM; ++i)
454 temp = temp + normal[i] * (p1[i] - pp[i]);
455
456 if (temp == 0.0)
457 {
458 ival = 2;
459 r8vec_copy(DIM_NUM, p1, pint);
460 }
461 else
462 {
463 ival = 0;
464 for (unsigned int i = 0; i < DIM_NUM; ++i)
465 pint[i] = 1.0e20; // dummy huge value
466 }
467 return ival;
468 }
469 //
470 // Determine the distance along the direction vector to the intersection point.
471 temp = 0.0;
472 for (unsigned int i = 0; i < DIM_NUM; ++i)
473 temp = temp + normal[i] * (pp[i] - p1[i]);
474 temp2 = 0.0;
475 for (unsigned int i = 0; i < DIM_NUM; ++i)
476 temp2 = temp2 + normal[i] * direction[i];
477
478 ival = 1;
479 for (unsigned int i = 0; i < DIM_NUM; ++i)
480 pint[i] = p1[i] + temp * direction[i] / temp2;
481
482 return ival;
483#undef DIM_NUM
484}
485
486double
488 double coord[], int order_max, int face_num, int node[], int /*node_num*/, int order[])
489//
490// Purpose:
491//
492// POLYHEDRON_VOLUME_3D computes the volume of a polyhedron in 3D.
493//
494// Licensing:
495//
496// This code is distributed under the GNU LGPL license.
497//
498// Modified:
499//
500// 21 August 2003
501//
502// Author:
503//
504// John Burkardt
505//
506// Parameters:
507//
508// Input, double COORD[NODE_NUM*3], the 3D coordinates of the vertices.
509// The vertices may be listed in any order.
510//
511// Input, int ORDER_MAX, the maximum number of vertices that make
512// up a face of the polyhedron.
513//
514// Input, int FACE_NUM, the number of faces of the polyhedron.
515//
516// Input, int NODE[FACE_NUM*ORDER_MAX]. Face I is defined by
517// the vertices NODE(I,1) through NODE(I,ORDER(I)). These vertices
518// are listed in neighboring order.
519//
520// Input, int NODE_NUM, the number of points stored in COORD.
521//
522// Input, int ORDER[FACE_NUM], the number of vertices making up
523// each face.
524//
525// Output, double POLYHEDRON_VOLUME_3D, the volume of the polyhedron.
526//
527{
528#define DIM_NUM 3
529
530 int face;
531 int n1;
532 int n2;
533 int n3;
534 double term;
535 int v;
536 double volume;
537 double x1;
538 double x2;
539 double x3;
540 double y1;
541 double y2;
542 double y3;
543 double z1;
544 double z2;
545 double z3;
546 //
547 volume = 0.0;
548 //
549 // Triangulate each face.
550 //
551 for (face = 0; face < face_num; face++)
552 {
553 n3 = node[order[face] - 1 + face * order_max];
554 x3 = coord[0 + n3 * 3];
555 y3 = coord[1 + n3 * 3];
556 z3 = coord[2 + n3 * 3];
557
558 for (v = 0; v < order[face] - 2; v++)
559 {
560 n1 = node[v + face * order_max];
561 x1 = coord[0 + n1 * 3];
562 y1 = coord[1 + n1 * 3];
563 z1 = coord[2 + n1 * 3];
564
565 n2 = node[v + 1 + face * order_max];
566 x2 = coord[0 + n2 * 3];
567 y2 = coord[1 + n2 * 3];
568 z2 = coord[2 + n2 * 3];
569
570 term =
571 x1 * y2 * z3 - x1 * y3 * z2 + x2 * y3 * z1 - x2 * y1 * z3 + x3 * y1 * z2 - x3 * y2 * z1;
572
573 volume = volume + term;
574 }
575 }
576
577 volume = volume / 6.0;
578
579 return volume;
580#undef DIM_NUM
581}
582
583void
584i4vec_zero(int n, int a[])
585//
586// Purpose:
587//
588// I4VEC_ZERO zeroes an I4VEC.
589//
590// Licensing:
591//
592// This code is distributed under the GNU LGPL license.
593//
594// Modified:
595//
596// 01 August 2005
597//
598// Author:
599//
600// John Burkardt
601//
602// Parameters:
603//
604// Input, int N, the number of entries in the vector.
605//
606// Output, int A[N], a vector of zeroes.
607//
608{
609 int i;
610
611 for (i = 0; i < n; i++)
612 {
613 a[i] = 0;
614 }
615 return;
616}
617
618void
620{
621 Real len = p.norm();
622 if (len > tol)
623 p = (1.0 / len) * p;
624 else
625 p.zero();
626}
627
628void
630{
631 Real len = p.norm();
632 if (len > tol)
633 p *= (1.0 / len);
634}
635
636double
637r8_acos(double c)
638//
639// Purpose:
640//
641// R8_ACOS computes the arc cosine function, with argument truncation.
642//
643// Discussion:
644//
645// If you call your system ACOS routine with an input argument that is
646// outside the range [-1.0, 1.0 ], you may get an unpleasant surprise.
647// This routine truncates arguments outside the range.
648//
649// Licensing:
650//
651// This code is distributed under the GNU LGPL license.
652//
653// Modified:
654//
655// 13 June 2002
656//
657// Author:
658//
659// John Burkardt
660//
661// Parameters:
662//
663// Input, double C, the argument, the cosine of an angle.
664//
665// Output, double R8_ACOS, an angle whose cosine is C.
666//
667{
668#define PI 3.141592653589793
669
670 double value;
671
672 if (c <= -1.0)
673 {
674 value = PI;
675 }
676 else if (1.0 <= c)
677 {
678 value = 0.0;
679 }
680 else
681 {
682 value = acos(c);
683 }
684 return value;
685#undef PI
686}
687
688double
689angle_rad_3d(double p1[3], double p2[3], double p3[3])
690//
691// Purpose:
692//
693// ANGLE_RAD_3D returns the angle between two vectors in 3D.
694//
695// Discussion:
696//
697// The routine always computes the SMALLER of the two angles between
698// two vectors. Thus, if the vectors make an (exterior) angle of 200
699// degrees, the (interior) angle of 160 is reported.
700//
701// X dot Y = Norm(X) * Norm(Y) * Cos ( Angle(X,Y) )
702//
703// Licensing:
704//
705// This code is distributed under the GNU LGPL license.
706//
707// Modified:
708//
709// 20 June 2005
710//
711// Author:
712//
713// John Burkardt
714//
715// Parameters:
716//
717// Input, double P1[3], P2[3], P3[3], points defining an angle.
718// The rays are P1 - P2 and P3 - P2.
719//
720// Output, double ANGLE_RAD_3D, the angle between the two vectors, in radians.
721// This value will always be between 0 and PI. If either vector has
722// zero length, then the angle is returned as zero.
723//
724{
725#define DIM_NUM 3
726
727 double dot;
728 int i;
729 double v1norm;
730 double v2norm;
731 double value;
732
733 v1norm = 0.0;
734 for (i = 0; i < DIM_NUM; i++)
735 {
736 v1norm = v1norm + pow(p1[i] - p2[i], 2);
737 }
738 v1norm = sqrt(v1norm);
739
740 if (v1norm == 0.0)
741 {
742 value = 0.0;
743 return value;
744 }
745
746 v2norm = 0.0;
747 for (i = 0; i < DIM_NUM; i++)
748 {
749 v2norm = v2norm + pow(p3[i] - p2[i], 2);
750 }
751 v2norm = sqrt(v2norm);
752
753 if (v2norm == 0.0)
754 {
755 value = 0.0;
756 return value;
757 }
758
759 dot = 0.0;
760 for (i = 0; i < DIM_NUM; i++)
761 {
762 dot = dot + (p1[i] - p2[i]) * (p3[i] - p2[i]);
763 }
764
765 value = r8_acos(dot / (v1norm * v2norm));
766
767 return value;
768#undef DIM_NUM
769}
770
771bool
772intersectSegmentWithCutLine(const Point & segment_point1,
773 const Point & segment_point2,
774 const std::pair<Point, Point> & cutting_line_points,
775 const Real & cutting_line_fraction,
776 Real & segment_intersection_fraction)
777{
778 // Use the algorithm described here to determine whether a line segment is intersected
779 // by a cutting line, and to compute the fraction along that line where the intersection
780 // occurs:
781 // http://stackoverflow.com/questions/563198/how-do-you-detect-where-two-line-segments-intersect
782
783 bool cut_segment = false;
784 Point seg_dir = segment_point2 - segment_point1;
785 Point cut_dir = cutting_line_points.second - cutting_line_points.first;
786 Point cut_start_to_seg_start = segment_point1 - cutting_line_points.first;
787
788 Real cut_dir_cross_seg_dir = crossProduct2D(cut_dir, seg_dir);
789
790 if (std::abs(cut_dir_cross_seg_dir) > Xfem::tol)
791 {
792 // Fraction of the distance along the cutting segment where it intersects the edge segment
793 Real cut_int_frac = crossProduct2D(cut_start_to_seg_start, seg_dir) / cut_dir_cross_seg_dir;
794
795 if (cut_int_frac >= 0.0 && cut_int_frac <= cutting_line_fraction)
796 { // Cutting segment intersects the line of the edge segment, but the intersection point may be
797 // outside the segment
798 Real int_frac = crossProduct2D(cut_start_to_seg_start, cut_dir) / cut_dir_cross_seg_dir;
799 if (int_frac >= 0.0 && int_frac <= 1.0)
800 {
801 cut_segment = true;
802 segment_intersection_fraction = int_frac;
803 }
804 }
805 }
806 return cut_segment;
807}
808
809Real
810crossProduct2D(const Point & point_a, const Point & point_b)
811{
812 return (point_a(0) * point_b(1) - point_b(0) * point_a(1));
813}
814
815Real
816pointSegmentDistance(const Point & x0, const Point & x1, const Point & x2, Point & xp)
817{
818 Point dx = x2 - x1;
819 Real m2 = dx * dx;
820 if (m2 == 0)
821 mooseError("In XFEMFuncs::pointSegmentDistance(), x0 and x1 should be two different points.");
822 // find parameter coordinate of closest point on segment
823 Real s12 = (x2 - x0) * dx / m2;
824 if (s12 < 0)
825 s12 = 0;
826 else if (s12 > 1)
827 s12 = 1;
828 // and find the distance
829 xp = s12 * x1 + (1 - s12) * x2;
830 return std::sqrt((x0 - xp) * (x0 - xp));
831}
832
833Real
834pointTriangleDistance(const Point & x0,
835 const Point & x1,
836 const Point & x2,
837 const Point & x3,
838 Point & xp,
839 unsigned int & region)
840{
841 Point x13 = x1 - x3, x23 = x2 - x3, x03 = x0 - x3;
842 Real m13 = x13 * x13, m23 = x23 * x23, d = x13 * x23;
843 Real invdet = 1.0 / std::max(m13 * m23 - d * d, 1e-30);
844 Real a = x13 * x03, b = x23 * x03;
845
846 Real w23 = invdet * (m23 * a - d * b);
847 Real w31 = invdet * (m13 * b - d * a);
848 Real w12 = 1 - w23 - w31;
849 if (w23 >= 0 && w31 >= 0 && w12 >= 0)
850 { // if we're inside the triangle
851 region = 0;
852 xp = w23 * x1 + w31 * x2 + w12 * x3;
853 return std::sqrt((x0 - xp) * (x0 - xp));
854 }
855 else
856 {
857 if (w23 > 0) // this rules out edge 2-3 for us
858 {
859 Point xp1, xp2;
860 Real distance_12 = pointSegmentDistance(x0, x1, x2, xp1);
861 Real distance_13 = pointSegmentDistance(x0, x1, x3, xp2);
862 Real distance_1 = std::sqrt((x0 - x1) * (x0 - x1));
863 if (std::min(distance_12, distance_13) < distance_1)
864 {
865 if (distance_12 < distance_13)
866 {
867 region = 4;
868 xp = xp1;
869 return distance_12;
870 }
871 else
872 {
873 region = 6;
874 xp = xp2;
875 return distance_13;
876 }
877 }
878 else
879 {
880 region = 1;
881 xp = x1;
882 return distance_1;
883 }
884 }
885 else if (w31 > 0) // this rules out edge 1-3
886 {
887 Point xp1, xp2;
888 Real distance_12 = pointSegmentDistance(x0, x1, x2, xp1);
889 Real distance_23 = pointSegmentDistance(x0, x2, x3, xp2);
890 Real distance_2 = std::sqrt((x0 - x2) * (x0 - x2));
891 if (std::min(distance_12, distance_23) < distance_2)
892 {
893 if (distance_12 < distance_23)
894 {
895 region = 4;
896 xp = xp1;
897 return distance_12;
898 }
899 else
900 {
901 region = 5;
902 xp = xp2;
903 return distance_23;
904 }
905 }
906 else
907 {
908 region = 2;
909 xp = x2;
910 return distance_2;
911 }
912 }
913 else // w12 must be >0, ruling out edge 1-2
914 {
915 Point xp1, xp2;
916 Real distance_23 = pointSegmentDistance(x0, x2, x3, xp1);
917 Real distance_31 = pointSegmentDistance(x0, x3, x1, xp2);
918 Real distance_3 = std::sqrt((x0 - x3) * (x0 - x3));
919 if (std::min(distance_23, distance_31) < distance_3)
920 {
921 if (distance_23 < distance_31)
922 {
923 region = 5;
924 xp = xp1;
925 return distance_23;
926 }
927 else
928 {
929 region = 6;
930 xp = xp2;
931 return distance_31;
932 }
933 }
934 else
935 {
936 region = 3;
937 xp = x3;
938 return distance_3;
939 }
940 }
941 }
942 mooseError("Cannot find closest location in XFEMFuncs::pointTriangleDistance().");
943}
944
945bool
946intersectWithEdge(const Point & p1,
947 const Point & p2,
948 const std::vector<Point> & vertices,
949 Point & pint)
950{
951 bool has_intersection = false;
952
953 if (vertices.size() != 3)
954 mooseError("The number of vertices of cutting element must be 3.");
955
956 Plane elem_plane(vertices[0], vertices[1], vertices[2]);
957 Point point = vertices[0];
958 Point normal = elem_plane.unit_normal(point);
959
960 std::array<Real, 3> plane_point = {{point(0), point(1), point(2)}};
961 std::array<Real, 3> planenormal = {{normal(0), normal(1), normal(2)}};
962 std::array<Real, 3> edge_point1 = {{p1(0), p1(1), p1(2)}};
963 std::array<Real, 3> edge_point2 = {{p2(0), p2(1), p2(2)}};
964 std::array<Real, 3> cut_point = {{0.0, 0.0, 0.0}};
965
967 &plane_point[0], &planenormal[0], &edge_point1[0], &edge_point2[0], &cut_point[0]) == 1)
968 {
969 Point temp_p(cut_point[0], cut_point[1], cut_point[2]);
970 if (isInsideCutPlane(vertices, temp_p) && isInsideEdge(p1, p2, temp_p))
971 {
972 pint = temp_p;
973 has_intersection = true;
974 }
975 }
976
977 return has_intersection;
978}
979
980bool
981isInsideEdge(const Point & p1, const Point & p2, const Point & p)
982{
983 Real dotp1 = (p1 - p) * (p2 - p1);
984 Real dotp2 = (p2 - p) * (p2 - p1);
985 return (dotp1 * dotp2 <= 0.0);
986}
987
988Real
989getRelativePosition(const Point & p1, const Point & p2, const Point & p)
990{
991 Real full_len = (p2 - p1).norm();
992 Real len_p1_p = (p - p1).norm();
993 return len_p1_p / full_len;
994}
995
996bool
997isInsideCutPlane(const std::vector<Point> & vertices, const Point & p)
998{
999 unsigned int n_node = vertices.size();
1000
1001 if (n_node != 3)
1002 mooseError("The number of vertices of cutting element must be 3.");
1003
1004 Plane elem_plane(vertices[0], vertices[1], vertices[2]);
1005 Point normal = elem_plane.unit_normal(vertices[0]);
1006
1007 bool inside = false;
1008 unsigned int counter = 0;
1009
1010 for (unsigned int i = 0; i < n_node; ++i)
1011 {
1012 unsigned int iplus1 = (i < n_node - 1 ? i + 1 : 0);
1013 Point middle2p = p - 0.5 * (vertices[i] + vertices[iplus1]);
1014 const Point side_tang = vertices[iplus1] - vertices[i];
1015 Point side_norm = side_tang.cross(normal);
1016
1017 normalizePoint(middle2p);
1018 normalizePoint(side_norm);
1019
1020 if (middle2p * side_norm <= 0)
1021 counter += 1;
1022 }
1023
1024 if (counter == n_node)
1025 inside = true;
1026 return inside;
1027}
1028
1029} // namespace XFEM
ExpressionBuilder::EBTerm pow(const ExpressionBuilder::EBTerm &left, T exponent)
const Real p
const double v
void mooseError(Args &&... args)
std::string stringify(const T &t)
Definition XFEM.h:26
void i4vec_zero(int n, int a[])
Definition XFEMFuncs.C:584
double polyhedron_volume_3d(double coord[], int order_max, int face_num, int node[], int node_num, int order[])
Definition XFEMFuncs.C:487
double angle_rad_3d(double p1[3], double p2[3], double p3[3])
Definition XFEMFuncs.C:689
void wissmannPoints(unsigned int nqp, std::vector< std::vector< Real > > &wss)
Definition XFEMFuncs.C:231
double r8_acos(double c)
Definition XFEMFuncs.C:637
bool intersectSegmentWithCutLine(const Point &segment_point1, const Point &segment_point2, const std::pair< Point, Point > &cutting_line_points, const Real &cutting_line_fraction, Real &segment_intersection_fraction)
Determine whether a line segment is intersected by a cutting line, and compute the fraction along tha...
Real crossProduct2D(const Point &point_a, const Point &point_b)
Compute the cross product of two vectors, provided as Point objects, which have nonzero components on...
void stdQuadr2D(unsigned int nen, unsigned int iord, std::vector< std::vector< Real > > &sg2)
Definition XFEMFuncs.C:94
Real getRelativePosition(const Point &p1, const Point &p2, const Point &p)
Get the relative position of p from p1 respect to the total length of the line segment.
bool intersectWithEdge(const Point &p1, const Point &p2, const std::vector< Point > &vertices, Point &pint)
check if a line intersects with an element defined by vertices calculate the distance from a point to...
void shapeFunc2D(unsigned int nen, std::vector< Real > &ss, std::vector< Point > &xl, std::vector< std::vector< Real > > &shp, Real &xsj, bool natl_flg)
double r8vec_norm(int n, double a[])
Definition XFEMFuncs.C:352
void dunavant_rule2(const Real *wts, const Real *a, const Real *b, const unsigned int *permutation_ids, unsigned int n_wts, std::vector< Point > &points, std::vector< Real > &weights)
bool r8vec_eq(int n, double a1[], double a2[])
Definition XFEMFuncs.C:372
int plane_normal_line_exp_int_3d(double pp[3], double normal[3], double p1[3], double p2[3], double pint[3])
Definition XFEMFuncs.C:401
bool isInsideEdge(const Point &p1, const Point &p2, const Point &p)
check if point is inside the straight edge p1-p2
double r8vec_dot_product(int n, double a1[], double a2[])
Definition XFEMFuncs.C:382
bool line_exp_is_degenerate_nd(int dim_num, double p1[], double p2[])
Definition XFEMFuncs.C:392
bool isInsideCutPlane(const std::vector< Point > &vertices, const Point &p)
Check if point p is inside a plane.
Real pointSegmentDistance(const Point &x0, const Point &x1, const Point &x2, Point &xp)
Calculate the signed distance from a point to a line segment.
Real pointTriangleDistance(const Point &x0, const Point &x1, const Point &x2, const Point &x3, Point &xp, unsigned int &region)
Calculate the signed distance from a point to a triangle.
void normalizePoint(Point &p)
static const double tol
Definition XFEMFuncs.h:23
void r8vec_copy(int n, double a1[], double a2[])
Definition XFEMFuncs.C:363