LCOV - code coverage report
Current view: top level - src/base - XFEMFuncs.C (source / functions) Hit Total Coverage
Test: idaholab/moose xfem: #31405 (292dce) with base fef103 Lines: 245 408 60.0 %
Date: 2025-09-04 07:58:55 Functions: 19 24 79.2 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.14