libMesh/libmesh: coverage diff

Base 54e0d5 Head #4551 36f69e
Total Total +/- New
Rate 65.99% 66.01% +0.01% 100.00%
Hits 79562 79647 +85 106
Misses 40996 41015 +19 0
Filename Stmts Miss Cover
src/geom/cell_hex.C +13 +1 +3.29%
src/geom/elem.C +61 +4 +0.77%
src/geom/elem_quality.C +6 +6 -0.36%
src/geom/face_quad.C +24 +5 +4.59%
src/mesh/distributed_mesh.C 0 +2 -0.25%
src/mesh/mesh_triangle_holes.C 0 +1 -0.28%
TOTAL +104 +19 +0.01%
code
coverage unchanged
code
coverage increased
code
coverage decreased
+
line added or modified

src/geom/cell_hex.C

502  
503  
504  
505 +
506  
507  
508 +
509 +
510  
511  
512  
513 +
514 +
515 +
516  
517 +
518  
519  
520  
521 +
522 +
523  
524  
525  
526 +
527 +
528 +
529 +
530  
531  
532  
      // which is Knupp's algebraic skew (1 is ideal).
      // See: C. J. Stimpson et al., "The Verdict Geometric Quality
      // Library," Sandia report SAND2007-1751, 2007.
    case SKEW_ANGLE:
      {
        const Point
          x0 = point(0), x1 = point(1), x2 = point(2), x3 = point(3),
          x4 = point(4), x5 = point(5), x6 = point(6), x7 = point(7);

        // Principal axes, one per logical (xi, eta, zeta) direction.
        const Point
          X1 = (x1 - x0) + (x2 - x3) + (x5 - x4) + (x6 - x7),
          X2 = (x3 - x0) + (x2 - x1) + (x7 - x4) + (x6 - x5),
          X3 = (x4 - x0) + (x5 - x1) + (x6 - x2) + (x7 - x3);

        const Real n1 = X1.norm(), n2 = X2.norm(), n3 = X3.norm();

        // Degenerate element: return 0 (the Verdict convention) if any
        // principal axis has zero length.
        if (n1 == 0. || n2 == 0. || n3 == 0.)
          return 0.;

        // Normalize, then take the largest |cos| among the three
        // pairs of principal axes.
        const Point X1h = X1 / n1, X2h = X2 / n2, X3h = X3 / n3;
        return std::max({std::abs(X1h * X2h),
                         std::abs(X1h * X3h),
                         std::abs(X2h * X3h)});
      }
#endif // LIBMESH_DIM >= 3

553  
554  
555  
556 +
557  
558  
559  
560  
561 +
562  
563  
564  
      bounds.second = 4.;
      break;

    case SKEW_ANGLE:
      bounds.first  = 0.;
      bounds.second = 0.5;
      break;

    case SKEW:
    case SHEAR:
    case SHAPE:
      bounds.first  = 0.3;

src/geom/elem.C

724  
725  
726  
727  
728  
729  
730  
731  
732  
733  
734  
735  
736  



Real Elem::length(const unsigned int n1,
                  const unsigned int n2) const
{
  libmesh_assert_less ( n1, this->n_vertices() );
  libmesh_assert_less ( n2, this->n_vertices() );

  return (this->point(n1) - this->point(n2)).norm();
}


2013  
2014  
2015  
2016 +
2017  
2018  
2019  
2020 +
2021 +
2022 +
2023  
2024  
2025  
2026  
2027 +
2028 +
2029  
2030 +
2031  
2032  
2033 +
2034  
2035  
2036  
2037 +
2038 +
2039  
2040  
2041 +
2042 +
2043  
2044 +
2045 +
2046 +
2047 +
2048 +
2049  
2050  
2051  
2052 +
2053 +
2054 +
2055  
2056 +
2057 +
2058  
2059  
2060  
2061  
2062 +
2063 +
2064  
2065 +
2066 +
2067 +
2068  
2069 +
2070  
2071  
2072  
      // available to this per-element method, so we use the reference
      // element instead. Unlike the standard Verdict metric, J is not
      // squared here.
    case SIZE:
      {
        // 1D elements don't have interior corners, so this metric does
        // not really apply to them.
        const auto N = this->dim();
        if (N < 2)
          return 1.;

        // Average the nodal Jacobian determinant over the corner
        // nodes. This uses the same nodal Jacobian construction as the
        // JACOBIAN metric above.
        Real sum_node_area = 0.;
        unsigned int n_corners = 0;

        for (auto n : this->node_index_range())
          {
            // Get list of edge ids adjacent to this node.
            auto adjacent_edge_ids = this->edges_adjacent_to_node(n);

            // Skip any nodes that don't have dim() adjacent edges (see
            // the JACOBIAN metric above for the Pyramid apex caveat).
            if (adjacent_edge_ids.size() != N)
              continue;

            // Construct oriented edges pointing away from node n.
            std::vector<Point> oriented_edges(N);
            for (auto i : make_range(N))
              {
                auto node_0 = this->local_edge_node(adjacent_edge_ids[i], 0);
                auto node_1 = this->local_edge_node(adjacent_edge_ids[i], 1);
                if (node_0 != n)
                  std::swap(node_0, node_1);
                oriented_edges[i] = this->point(node_1) - this->point(node_0);
              }

            // Unscaled nodal area (2D) or volume (3D).
            Real node_area = (N == 2) ?
              cross_norm(oriented_edges[0], oriented_edges[1]) :
              std::abs(triple_product(oriented_edges[0], oriented_edges[1], oriented_edges[2]));

            sum_node_area += node_area;
            ++n_corners;
          }

        // No usable corners, or a degenerate (zero-size) element: return
        // 0 (the lowest quality).
        if (n_corners == 0)
          return 0.;

        const Real J = sum_node_area / n_corners;
        if (J == 0.)
          return 0.;

        return std::min(J, Real(1) / J);
      }

      // Maximum condition number of the nodal Jacobian matrix over the
2080  
2081  
2082  
2083 +
2084  
2085  
2086  
2087 +
2088 +
2089 +
2090  
2091  
2092  
2093 +
2094  
2095 +
2096  
2097  
2098 +
2099  
2100  
2101  
2102 +
2103 +
2104  
2105  
2106  
2107 +
2108 +
2109  
2110 +
2111 +
2112 +
2113 +
2114 +
2115  
2116  
2117  
2118 +
2119 +
2120 +
2121  
2122  
2123  
2124 +
2125  
2126 +
2127  
2128  
2129 +
2130 +
2131  
2132  
2133 +
2134  
2135  
2136  
2137 +
2138  
2139  
2140 +
2141 +
2142  
2143  
2144  
2145 +
2146 +
2147 +
2148  
2149  
2150 +
2151 +
2152  
2153  
2154 +
2155  
2156  
2157  
      // determinant) has an infinite condition number, reported as 0
      // following the convention used elsewhere (e.g. EDGE_LENGTH_RATIO)
      // that 0 stands in for infinity.
    case CONDITION:
      {
        // 1D elements don't have interior corners, so this metric does
        // not really apply to them.
        const auto N = this->dim();
        if (N < 2)
          return 1.;

        // kappa >= 1 for every matrix, so 1 is both the ideal value and
        // a safe floor for the running maximum.
        Real max_cond = 1.;

        for (auto n : this->node_index_range())
          {
            // Get list of edge ids adjacent to this node.
            auto adjacent_edge_ids = this->edges_adjacent_to_node(n);

            // Skip any nodes that don't have dim() adjacent edges (see
            // the JACOBIAN metric above for the Pyramid apex caveat).
            if (adjacent_edge_ids.size() != N)
              continue;

            // Construct oriented edges pointing away from node n; these
            // are the columns of the nodal Jacobian A.
            std::vector<Point> e(N);
            for (auto i : make_range(N))
              {
                auto node_0 = this->local_edge_node(adjacent_edge_ids[i], 0);
                auto node_1 = this->local_edge_node(adjacent_edge_ids[i], 1);
                if (node_0 != n)
                  std::swap(node_0, node_1);
                e[i] = this->point(node_1) - this->point(node_0);
              }

            // Squared Frobenius norm of A.
            Real frob_A_sq = 0.;
            for (auto i : make_range(N))
              frob_A_sq += e[i].norm_sq();

            // |det(A)| and the squared Frobenius norm of A^{-1}.
            Real abs_det, frob_Ainv_sq;
            if (N == 2)
              {
                abs_det = cross_norm(e[0], e[1]);

                // Degenerate corner: infinite condition number.
                if (abs_det == 0.)
                  return 0.;

                // For a 2x2 matrix, |A^{-1}|_F = |A|_F / |det|.
                frob_Ainv_sq = frob_A_sq / (abs_det * abs_det);
              }
            else
              {
                abs_det = std::abs(triple_product(e[0], e[1], e[2]));

                // Degenerate corner: infinite condition number.
                if (abs_det == 0.)
                  return 0.;

                // The rows of A^{-1} are (e1 x e2), (e2 x e0), (e0 x e1),
                // each divided by det(A).
                frob_Ainv_sq = (e[1].cross(e[2]).norm_sq() +
                                e[2].cross(e[0]).norm_sq() +
                                e[0].cross(e[1]).norm_sq()) / (abs_det * abs_det);
              }

            const Real kappa = std::sqrt(frob_A_sq * frob_Ainv_sq) / N;
            max_cond = std::max(max_cond, kappa);
          }

        return max_cond;
      }

      // Return 1 if we made it here

src/geom/elem_quality.C

58  
59  
60  
61 +
62 +
63 +
64  
65  
66  
      its_name = "Skew";
      break;

    case SKEW_ANGLE:
      its_name = "Skew Angle";
      break;

    case SHEAR:
      its_name = "Shear";
173  
174  
175  
176 +
177 +
178  
179 +
180  
181  
182  
           << '\n'
           << "Suggested ranges:\n"
           << "Hexes: (0.3 -> 1)\n"
           << "Quads: (0.3 -> 1)";
      break;

    case SKEW_ANGLE:
      desc << "Maximum |cos A|, where A\n"
           << "is the angle between edges\n"
           << "at element center.\n"

src/geom/face_quad.C

331  
332  
333  
334 +
335  
336 +
337 +
338 +
339 +
340  
341  
342 +
343 +
344  
345  
346  
347 +
348 +
349  
350 +
351 +
352  
353  
354  
      // and return the smallest (worst) such ratio. The value lies in
      // (0, 1], with 1 indicating no taper, i.e. both pairs of opposite
      // edges are equal in length (as for any parallelogram).
    case TAPER:
      {
        const Real d01 = this->length(0,1);
        const Real d12 = this->length(1,2);
        const Real d23 = this->length(2,3);
        const Real d03 = this->length(0,3);

        // Longer length of each opposite-edge pair.
        const Real max0 = std::max(d01, d23);
        const Real max1 = std::max(d12, d03);

        // Degenerate element with a zero-length pair of opposite edges:
        // return 0 (the lowest quality).
        if (max0 == 0. || max1 == 0.)
          return 0.;

        return std::min(std::min(d01, d23) / max0,
                        std::min(d12, d03) / max1);
      }

    case SHAPE:
436  
437  
438  
439 +
440  
441 +
442 +
443  
444  
445 +
446 +
447  
448 +
449  
450  
451  
452 +
453 +
454  
455 +
456  
457  
458  
      // which is Knupp's algebraic skew (1 is ideal).
      // See: C. J. Stimpson et al., "The Verdict Geometric Quality
      // Library," Sandia report SAND2007-1751, 2007.
    case SKEW_ANGLE:
      {
        const Point x0 = this->point(0), x1 = this->point(1),
                    x2 = this->point(2), x3 = this->point(3);

        // Principal axes: midpoint-to-midpoint of opposite edges.
        const Point X1 = (x1 - x0) + (x2 - x3);
        const Point X2 = (x3 - x0) + (x2 - x1);

        const Real n1 = X1.norm(), n2 = X2.norm();

        // Degenerate element: return 0 (the Verdict convention) if
        // either principal axis has zero length.
        if (n1 == 0. || n2 == 0.)
          return 0.;

        return std::abs((X1 * X2) / (n1 * n2));
      }

      // This test returns 0 if a Quad:
596  
597  
598  
599 +
600 +
601 +
602 +
603  
604  
605  
      bounds.second = 1.;
      break;

    case SKEW_ANGLE:
      bounds.first  = 0.;
      bounds.second = 0.5;
      break;

    case DISTORTION:
      bounds.first  = 0.6;

src/mesh/distributed_mesh.C

1609  
1610  
1611  
1612  
1613  
1614  
1615  
1616  
1617  
1618  
1619  
1620  
1621  
1622  
                      sender_could_become_owner)
                    {
                      if (it != repartitioned_node_pids.end() &&
                          pid < it->second)
                        it->second = pid;
                      else
                        repartitioned_node_pids[n] = pid;
                    }
                  else
                    if (it == repartitioned_node_pids.end())
                      repartitioned_node_pids[n] =
                        DofObject::invalid_processor_id;

                  repartitioned_node_sets_to_push[pid].insert(n);

src/mesh/mesh_triangle_holes.C

276  
277  
278  
279  
280  
281  
282  
    {
      ray_target = inside - Point(1);
      intersection_distances =
        this->find_ray_intersections(inside, ray_target);
    }

  // I'd make this an assert, but I'm not 100% confident we can't