| 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% |
codecodecode+
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; |
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 |
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" |
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; |
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); |
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 |