/*========================================================================= Module: V_EdgeMetric.cpp Copyright 2003,2006,2019 National Technology & Engineering Solutions of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S. Government retains certain rights in this software. See LICENSE for details. =========================================================================*/ /*! * \brief Unittests for verdict element quality metrics * * \date 7/26/2017 * * \author Matt Staten */ #include "verdict.h" #include "gtest/gtest.h" #include <cmath> #include <functional> #include <iostream> #include <vector> #define MAX_NODES_PER_ELEMENT 27 // 7 significant figures for doubles, use 5 to make tests less sensitive // #define VERDICT_SIGNIFICANT_FIG 5 // absolute and relative tolerances for comparing floating point answers #define VERDICT_ABSOLUTE_TOL 1e-05 #define VERDICT_RELATIVE_TOL 1e-05 struct metric_and_answer { std::function<double(int, double[][3])> mFunction; double mAnswer; }; struct test_case { const char* mTestName; std::vector<metric_and_answer> mTestData; int mNumNodes; double mCoords[MAX_NODES_PER_ELEMENT][3]; }; void runtest(test_case& this_testcase) { const char* testname = this_testcase.mTestName; int num_nodes = this_testcase.mNumNodes; size_t itest = 0; for (metric_and_answer& data : this_testcase.mTestData) { itest++; // Compute the answer from the verdict library const double calculated_answer = data.mFunction(num_nodes, this_testcase.mCoords); const double expected_answer = data.mAnswer; // list the current subcase, otherwise there is no way to tell which metric failed std::cout << "Test case \"" << testname << "\" #" << itest << " Calculated = " << calculated_answer << " Expected = " << expected_answer << std::endl; EXPECT_NEAR(calculated_answer, expected_answer, std::abs(expected_answer) * VERDICT_RELATIVE_TOL + VERDICT_ABSOLUTE_TOL); // old test using strings /* std::stringstream expected; expected.setf(std::ios::scientific, std::ios::floatfield); expected.precision(VERDICT_SIGNIFICANT_FIG); expected << data.mAnswer; std::stringstream answer; answer.setf(std::ios::scientific, std::ios::floatfield); answer.precision(VERDICT_SIGNIFICANT_FIG); answer << answer_from_lib; // for expected values of zero, we only care about absolute tolerance, not relative tolerance, std::string expected_v_str = expected.str(); std::string answer_v_str = answer.str(); if ( std::abs(answer_from_lib) < VERDICT_ABSOLUTE_TOL ) { std::stringstream expected_abs; expected_abs.setf(std::ios::scientific, std::ios::floatfield); expected_abs.precision(VERDICT_SIGNIFICANT_FIG); expected_abs << 1. + data.mAnswer; expected_v_str = expected_abs.str(); std::stringstream answer_abs; answer_abs.setf(std::ios::scientific, std::ios::floatfield); answer_abs.precision(VERDICT_SIGNIFICANT_FIG); answer_abs << 1. + answer_from_lib; answer_v_str = answer_abs.str(); } EXPECT_EQ(expected_v_str, answer_v_str); if (expected_v_str!= answer_v_str) { std::cout << std::endl; std::cout << "Test case \"" << testname << "\" #" << itest << " FAILED" << std::endl; std::cout << "answer calculated was " << answer.str() << " ( " << answer_v_str << " ) " << std::endl << "answer expected was " << expected.str() << " ( " << expected_v_str << " ) " << std::endl << std::endl; EXPECT_TRUE(false); } else { std::cout << "Test case \"" << testname << "\" #" << itest << " passed" << std::endl; } */ } } TEST(verdict, tet_incircle_right) { test_case testcase = { "tet_incircle_right", { { verdict::tet_inradius, 0.5 - 1. / std::sqrt(12) } }, 4, { { 0, 0, 0 }, { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 } } }; runtest(testcase); } TEST(verdict, tet_incircle_right2) { test_case testcase = { "tet_incircle_right2", { { verdict::tet_inradius, 2.0 * (0.5 - 1. / std::sqrt(12)) } }, 4, { { 0, 0, 0 }, { 2, 0, 0 }, { 0, 2, 0 }, { 0, 0, 2 } } }; runtest(testcase); } TEST(verdict, tet_incircle_equilateral) { const double pi = verdict::VERDICT_PI; // equilateral tet, with side length 1 double l2 = std::sin(30 * pi / 180) / std::sin(120 * pi / 180); double h = std::sqrt(1 - l2 * l2); test_case testcase = { "tet_incircle_equilateral", { { verdict::tet_inradius, std::sqrt(6.) / 12. } }, 4, { { 0, 0, 0 }, { 1, 0, 0 }, { std::cos(60 * pi / 180), std::sin(60 * pi / 180), 0 }, { l2 * std::cos(30 * pi / 180), l2 * std::sin(30 * pi / 180), h } } }; runtest(testcase); } TEST(verdict, tet_incircle_equilateral2) { const double pi = 2. * std::asin(1.); // equilateral tet, with side length 2 double l2 = 2. * std::sin(30 * pi / 180) / std::sin(120 * pi / 180); double h = std::sqrt(4. - l2 * l2); test_case testcase = { "tet_incircle_equilateral2", { { verdict::tet_inradius, 2 * std::sqrt(6.) / 12. } }, 4, { { 0, 0, 0 }, { 2, 0, 0 }, { 2 * std::cos(60 * pi / 180), 2 * std::sin(60 * pi / 180), 0 }, { l2 * std::cos(30 * pi / 180), l2 * std::sin(30 * pi / 180), h } } }; runtest(testcase); } TEST(verdict, tet_incircle_flat) { test_case testcase = { "tet_incircle_flat", { { verdict::tet_inradius, 0.0 } }, 4, { { 0, 0, 0 }, { 1, 0, 0 }, { 0, 1, 0 }, { 0.5, 0.5, 0 } } }; runtest(testcase); } TEST(verdict, tet_incircle_inverted) { test_case testcase = { "tet_incircle_inverted", { { verdict::tet_inradius, -0.5 + 1. / std::sqrt(12) } }, 4, { { 0, 0, 0 }, { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, -1 } } }; runtest(testcase); } TEST(verdict, tet_incircle_too_few_nodes) { test_case testcase = { "tet_incircle_too_few_nodes", { { verdict::tet_inradius, 0. } }, 3, // not enough nodes { { 0, 0, 0 }, { 1, 0, 0 }, { 0, 1, 0 }, } }; runtest(testcase); } TEST(verdict, tet_incircle_regression) { test_case testcase = { "tet_incircle_regression", { { verdict::tet_inradius, 3.2723844167 } }, 4, { // some arbitrary vectors, ensure verdict returns the value it used to { 12, 44, 13.3 }, { 17, 0.003, 66 }, { 3, 33, 234 }, { 14, -123, 21 }, } }; runtest(testcase); } TEST(verdict, tet_incircle_regression2) { test_case testcase = { "tet_incircle_regression2", { { verdict::tet_inradius, 2 * 3.27238441675 } }, 4, { // some arbitrary vectors, ensure verdict returns the value it used to { 2 * 12, 2 * 44, 2 * 13.3 }, { 2 * 17, 2 * 0.003, 2 * 66 }, { 2 * 3, 2 * 33, 2 * 234 }, { 2 * 14, 2 * -123, 2 * 21 }, } }; runtest(testcase); } TEST(verdict, tet_equiangle_skew_1) { test_case testcase = { "tet_equiangle_skew_1", { { verdict::tet_equiangle_skew, 0.25 }, { verdict::tet_equivolume_skew, 0.5 } }, 4, { { 0, 0, 0 }, { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 } } }; runtest(testcase); } TEST(verdict, edge_calc_1) { test_case testcase = { "edge_calc_1", { { verdict::edge_length, 1.732050807568877 } }, 2, { { 0, 0, 0 }, { 1, 1, 1 } } }; runtest(testcase); } TEST(verdict, edge_calc_2) { test_case testcase = { "edge_calc_2", { { verdict::edge_length, 1.0 } }, 2, { { 0, 0, 0 }, { 1, 0, 0 } } }; runtest(testcase); } TEST(verdict, edge_calc_3) { test_case testcase = { "edge_calc_3", { { verdict::edge_length, 0.0 } }, 2, { { 0, 0, 0 }, { 0, 0, 0 } } }; runtest(testcase); } TEST(verdict, wedge_simple) { test_case testcase = { "wedge_simple", { { verdict::wedge_volume, 0.5 }, { verdict::wedge_equiangle_skew, 0.25 }, { verdict::wedge_edge_ratio, std::sqrt(2.) }, { verdict::wedge_max_aspect_frobenius, 1.1357042248 }, { verdict::wedge_mean_aspect_frobenius, 1.0978474174 }, { verdict::wedge_distortion, 1 }, { verdict::wedge_max_stretch, 1 } }, 6, { { 0, 0, 0 }, { -1, 1, 0 }, { -1, 0, 0 }, { 0, 0, 1 }, { -1, 1, 1 }, { -1, 0, 1 } } }; runtest(testcase); } TEST(verdict, wedge_singularity) { test_case testcase = { "wedge_singularity", { { verdict::wedge_volume, 0.0 }, { verdict::wedge_equiangle_skew, 1 }, /* 3 */ { verdict::wedge_edge_ratio, verdict::VERDICT_DBL_MAX }, /* 4 */ { verdict::wedge_max_aspect_frobenius, verdict::VERDICT_DBL_MAX }, /* 5 */ { verdict::wedge_mean_aspect_frobenius, verdict::VERDICT_DBL_MAX }, /* 6 */ { verdict::wedge_distortion, verdict::VERDICT_DBL_MAX }, /* 7 */ { verdict::wedge_max_stretch, verdict::VERDICT_DBL_MAX } }, 6, { { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 } } }; runtest(testcase); } TEST(verdict, tri_simple) { test_case testcase = { "tri_simple", { { verdict::tri_area, 10.8253175 }, { verdict::tri_aspect_ratio, 1 }, { verdict::tri_condition, 1.0 }, { verdict::tri_distortion, 1.0 }, { verdict::tri_minimum_angle, 60 }, { verdict::tri_maximum_angle, 60 }, { verdict::tri_shape, 1.0 }, /* 8 */ { verdict::tri_edge_ratio, 1 }, /* 9 */ { verdict::tri_aspect_frobenius, 1 }, /* 10 */ { verdict::tri_equiangle_skew, 1.8069363487e-09 }, /* 11 */ { verdict::tri_normalized_inradius, 1.0 } }, 3, { { 0, 0, 0 }, { 5, 0, 0 }, { 2.5, 4.330127, 0 } } }; runtest(testcase); } TEST(verdict, tri_singular) { test_case testcase = { "tri_singular", { { verdict::tri_area, 0.43301270185 }, { verdict::tri_aspect_ratio, 1 }, { verdict::tri_condition, 1 }, { verdict::tri_distortion, 1 }, { verdict::tri_minimum_angle, 60 }, { verdict::tri_maximum_angle, 60 }, { verdict::tri_shape, 1 }, /* 8 */ { verdict::tri_edge_ratio, 1 }, /* 9 */ { verdict::tri_aspect_frobenius, 1 }, /* 10 */ { verdict::tri_equiangle_skew, 4.0316550098e-11 }, /* 11 */ { verdict::tri_normalized_inradius, 1.0 } }, 3, { { 0, 0, 0 }, { 0.5, 0.8660254037, 0 }, { 1, 0, 0 } } }; runtest(testcase); } // tri_distortion is not well covered, we need to test it with a six noded triangle */ TEST(verdict, tri_six_nodes) { test_case testcase = { "tri_six_nodes", { { verdict::tri_area, 0.54772255751 }, { verdict::tri_aspect_ratio, 1.3268079265 }, { verdict::tri_condition, 1.1173381066 }, { verdict::tri_distortion, -3.3198288345 }, { verdict::tri_minimum_angle, 45.406778838 }, { verdict::tri_maximum_angle, 85.823122909 }, { verdict::tri_shape, 0.89498424344 }, /* 8 */ { verdict::tri_edge_ratio, 1.4005493428 }, /* 9 */ { verdict::tri_aspect_frobenius, 1.1173381066 }, /* 10 */ { verdict::tri_equiangle_skew, 0.24322035270 }, /* 11 */ { verdict::tri_normalized_inradius, 0.603527 } }, 6, { { 0, 0, 0 }, { 1, 0, 0.2 }, { 0, 1, 0.4 }, { 0, 0.5, 0.1 }, { 0.5, 0.5, 0.3 }, { 0.5, 0, 0.2 } } }; runtest(testcase); } TEST(verdict, quad_simple1) { test_case testcase = { "quad_simple1", { { verdict::quad_skew, 0 } }, 4, { { 0, 0, 0 }, { 1, 0, 0 }, { 1, 7, 0 }, { 0, 7, 0 } } }; runtest(testcase); } TEST(verdict, quad_simple2) { test_case testcase = { "quad_simple2", { /* 1 */ { verdict::quad_aspect_ratio, 1.4299641718 }, /* 2 */ { verdict::quad_skew, 0.092450032704 }, /* 3 */ { verdict::quad_taper, 0.74535599250 }, /* 4 */ { verdict::quad_warpage, 0.008 }, /* 5 */ { verdict::quad_area, 2.6925824036 }, /* 6 */ { verdict::quad_stretch, 0.57735026919 }, /* 7 */ { verdict::quad_minimum_angle, 56.789089239 }, /* 8 */ { verdict::quad_maximum_angle, 90 }, /* 9 */ { verdict::quad_condition, 2.3079277745 }, /* 10 */ { verdict::quad_jacobian, 1.1141720291 }, /* 11 */ { verdict::quad_shear, 0.55708601453 }, /* 12 */ { verdict::quad_shape, 0.43328912241 }, /* 13 */ { verdict::quad_distortion, 0.56267957295 }, /* 14 */ { verdict::quad_equiangle_skew, 0.36901011957 }, /* 15 */ { verdict::quad_radius_ratio, 1.7320508076 }, /* 16 */ { verdict::quad_med_aspect_frobenius, 1.2274682929 }, /* 17 */ { verdict::quad_max_aspect_frobenius, 1.3416407865 }, /* 18 */ { verdict::quad_oddy, 1.6000000000 } }, 4, { { 2, 0, 0 }, // 1 { 1, 1, 2 }, // 2 { 0, 1, 0 }, // 3 { 0, 0, 0 }, // 0 } }; runtest(testcase); } TEST(verdict, quad_chevron) { test_case testcase = { "quad_chevron", { /* 1 */ { verdict::quad_aspect_ratio, 1.5317000291 }, /* 2 */ { verdict::quad_skew, 6.5193481489e-01 }, /* 3 */ { verdict::quad_taper, 9.8606743061e-01 }, /* 4 */ { verdict::quad_warpage, -9.9459686559e-01 }, /* 5 */ { verdict::quad_area, 3.5562234182 }, /* 6 */ { verdict::quad_stretch, 7.4945733623e-01 }, /* 7 */ { verdict::quad_minimum_angle, 19.319495622 }, /* 8 */ { verdict::quad_maximum_angle, 226.10065328 }, /* 9 */ { verdict::quad_condition, verdict::VERDICT_DBL_MAX }, /* 10 */ { verdict::quad_jacobian, -3.4157021569 }, /* 11 */ { verdict::quad_shear, 0 }, /* 12 */ { verdict::quad_shape, 0 }, /* 13 */ { verdict::quad_distortion, -9.0249845339e-01 }, /* 14 */ { verdict::quad_equiangle_skew, 1.5122294809 }, /* 15 */ { verdict::quad_radius_ratio, 2.9914983186 }, /* 16 */ { verdict::quad_med_aspect_frobenius, 1.8922421445 }, /* 17 */ { verdict::quad_max_aspect_frobenius, 3.5710779160 }, /* 18 */ { verdict::quad_oddy, 23.505194964 } }, 4, { // reflex angle at node 2 { 1, 1, 1 }, // 1 { 3, 1, 2 }, // 2 { 5, 0.8, 1.3 }, // 3 { 2, 1.1, 3.7 }, // 0 } }; runtest(testcase); } TEST(verdict, quad_collapsed) { test_case testcase = { "quad_collapsed", { /* 1 */ { verdict::quad_aspect_ratio, verdict::VERDICT_DBL_MAX }, /* 2 */ { verdict::quad_skew, 1 }, /* 3 */ { verdict::quad_taper, 0 }, /* 4 */ { verdict::quad_warpage, 0 }, /* 5 */ { verdict::quad_area, 0 }, /* 6 */ { verdict::quad_stretch, 4.7140452079e-01 }, /* 7 */ { verdict::quad_minimum_angle, 0 }, /* 8 */ { verdict::quad_maximum_angle, 180 }, /* 9 */ { verdict::quad_condition, verdict::VERDICT_DBL_MAX }, /* 10 */ { verdict::quad_jacobian, 0 }, /* 11 */ { verdict::quad_shear, 0 }, /* 12 */ { verdict::quad_shape, 0 }, /* 13 */ { verdict::quad_distortion, 0 }, /* 14 */ { verdict::quad_equiangle_skew, 1 }, /* 15 */ { verdict::quad_radius_ratio, verdict::VERDICT_DBL_MAX }, /* 16 */ { verdict::quad_med_aspect_frobenius, verdict::VERDICT_DBL_MAX }, /* 17 */ { verdict::quad_max_aspect_frobenius, verdict::VERDICT_DBL_MAX }, /* 18 */ { verdict::quad_oddy, verdict::VERDICT_DBL_MAX } }, 4, { // colinear nodes { 3, 1, 1 }, // 1 { 6, 1, 2 }, // 2 { 12, 1, 4 }, // 3 { 9, 1, 3 }, // 0 } }; runtest(testcase); } TEST(verdict, quad_bowtie) { test_case testcase = { "quad_bowtie", { /* 1 */ { verdict::quad_aspect_ratio, 2.0295276589 }, /* 2 */ { verdict::quad_skew, 6.0840291338e-01 }, /* 3 */ { verdict::quad_taper, 4.9416251426e+00 }, /* 4 */ { verdict::quad_warpage, -9.9972444493e-01 }, /* 5 */ { verdict::quad_area, 3.4869452964e+00 }, /* 6 */ { verdict::quad_stretch, 1.7893591011e+00 }, /* 7 */ { verdict::quad_minimum_angle, 2.0794246576e+01 }, /* 8 */ { verdict::quad_maximum_angle, 3.2636439841e+02 }, /* 9 */ { verdict::quad_condition, verdict::VERDICT_DBL_MAX }, /* 10 */ { verdict::quad_jacobian, -2.2480385649e+01 }, /* 11 */ { verdict::quad_shear, 0 }, /* 12 */ { verdict::quad_shape, 0 }, /* 13 */ { verdict::quad_distortion, -2.3654968475e+00 }, /* 14 */ { verdict::quad_equiangle_skew, 2.6262710934e+00 }, /* 15 */ { verdict::quad_radius_ratio, 2.7490501584e+00 }, /* 16 */ { verdict::quad_med_aspect_frobenius, 2.3523244623e+00 }, /* 17 */ { verdict::quad_max_aspect_frobenius, 2.8418376590e+00 }, /* 18 */ { verdict::quad_oddy, 1.4152082560e+01 } }, 4, { { -1, -1, -1 }, // 1 { 6, 2, -1.1 }, // 2 { 3, -2.5, -1.15 }, // 3 { 4.5, 4.3, -0.9 }, // 0 } }; runtest(testcase); } TEST(verdict, tet_test1) { test_case testcase = { "tet_test1", { { verdict::tet_volume, 166.66666667 }, { verdict::tet_condition, 1.2247448714 }, { verdict::tet_jacobian, 1000 }, { verdict::tet_shape, 0.83994736660 }, { verdict::tet_distortion, 1 }, /* 6 */ { verdict::tet_edge_ratio, std::sqrt(2.) }, /* 7 */ { verdict::tet_radius_ratio, 1.3660254038 }, /* 8 */ { verdict::tet_aspect_ratio, 1.3660254038 }, /* 9 */ { verdict::tet_aspect_frobenius, 1.1905507890 }, /* 10 */ { verdict::tet_minimum_angle, 54.735610317 }, /* 11 */ { verdict::tet_collapse_ratio, 0.40824829046 }, /* 12 */ { verdict::tet_equivolume_skew, 0.5 }, /* 13 */ { verdict::tet_normalized_inradius, 0.61401440738235424 } }, 4, { { -5, -5, -5 }, { -5, 5, -5 }, { -5, -5, 5 }, { 5, -5, -5 }, } }; runtest(testcase); } TEST(verdict, tet_test2_singular) { test_case testcase = { "tet_test2_singular", { { verdict::tet_volume, 0 }, { verdict::tet_condition, verdict::VERDICT_DBL_MAX }, { verdict::tet_jacobian, 0 }, { verdict::tet_shape, 0 }, { verdict::tet_distortion, 1 }, /* 6 */ { verdict::tet_edge_ratio, verdict::VERDICT_DBL_MAX }, /* 7 */ { verdict::tet_radius_ratio, verdict::VERDICT_DBL_MAX }, /* 8 */ { verdict::tet_aspect_ratio, verdict::VERDICT_DBL_MAX }, /* 9 */ { verdict::tet_aspect_frobenius, verdict::VERDICT_DBL_MAX }, /* 10 */ { verdict::tet_minimum_angle, verdict::VERDICT_DBL_MAX }, /* 11 */ { verdict::tet_collapse_ratio, verdict::VERDICT_DBL_MAX }, /* 12 */ { verdict::tet_equivolume_skew, verdict::VERDICT_DBL_MAX }, /* 13 */ { verdict::tet_normalized_inradius, verdict::VERDICT_DBL_MAX } }, 4, { // all points are 0, so the tet has zero edge length, volume, etc. { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 } } }; runtest(testcase); } TEST(verdict, tet10_test1) { test_case testcase = { "tet10_test1", { /* 0 */ { verdict::tet_distortion, 1 }, /* 1 */ { verdict::tet_normalized_inradius, 0.61401440738235424 }, }, 10, { { -5, 5, 5 }, { -5, -5, -5 }, { 5, -5, 5 }, { -5, -5, 5 }, { -5, 0, 0 }, { 0, -5, 0 }, { 0, 0, 5 }, { -5, 0, 5 }, { -5, -5, 0 }, { 0, -5, 5 }, } }; runtest(testcase); } TEST(verdict, tet10_test2_singular) { test_case testcase = { "tet10_test2_singular", { /* 0 */ { verdict::tet_distortion, verdict::VERDICT_DBL_MAX }, /* 1 */ { verdict::tet_normalized_inradius, verdict::VERDICT_DBL_MAX }, }, 10, { { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, } }; runtest(testcase); } TEST(verdict, hex_test1) { test_case testcase = { "hex_test1_regression", { { verdict::hex_skew, 0.24588970374 }, { verdict::hex_taper, 0.17845765256 }, { verdict::hex_volume, 0.81566666667 }, { verdict::hex_stretch, 0.62097029970 }, { verdict::hex_diagonal, 0.68962192988 }, { verdict::hex_dimension, 0.52459420058 }, { verdict::hex_condition, 1.2730598257 }, // same as verdict::hex_max_aspect_frobenius { verdict::hex_med_aspect_frobenius, 1.1435711972 }, { verdict::hex_jacobian, 0.477 }, { verdict::hex_shear, 0.77784951012 }, { verdict::hex_shape, 0.78978528102 }, { verdict::hex_distortion, 0.58479771148 }, { verdict::hex_nodal_jacobian_ratio, 0.42513368984 }, { verdict::hex_oddy, 2.0988338297 }, { verdict::hex_edge_ratio, 1.7944358445 }, { verdict::hex_equiangle_skew, 0.37159771083 } }, 8, { { -.2, -.7, -.3 }, // 1 { -.7, .4, -.6 }, // 2 { -.5, .5, .3 }, // 3 { -.3, -.5, .5 }, // 0 { .5, -.8, -.2 }, // 5 { .4, .4, -.6 }, // 6 { .2, .5, .2 }, // 7 { .5, -.3, .8 } // 4 } }; runtest(testcase); } TEST(verdict, hex_test2_perfect_cube) { test_case testcase = { "hex_test2_perfect_cube", { { verdict::hex_skew, 0. }, { verdict::hex_taper, 0. }, { verdict::hex_volume, 1.0 }, { verdict::hex_stretch, 1.0 }, { verdict::hex_diagonal, 1.0 }, { verdict::hex_dimension, 1. / std::sqrt(3.) }, { verdict::hex_condition, 1.0 }, { verdict::hex_med_aspect_frobenius, 1 }, { verdict::hex_jacobian, 1.0 }, { verdict::hex_shear, 1.0 }, { verdict::hex_shape, 1.0 }, { verdict::hex_distortion, 1.0 }, { verdict::hex_nodal_jacobian_ratio, 1.0 }, { verdict::hex_oddy, 0. }, { verdict::hex_edge_ratio, 1 }, { verdict::hex_equiangle_skew, 0 } }, 8, { // perfect unit hex { 0, 0, 0 }, { 1, 0, 0 }, { 1, 1, 0 }, { 0, 1, 0 }, { 0, 0, 1 }, { 1, 0, 1 }, { 1, 1, 1 }, { 0, 1, 1 } } }; runtest(testcase); } TEST(verdict, hex_test3_flat) { test_case testcase = { "hex_test3_flat", { { verdict::hex_skew, verdict::VERDICT_DBL_MAX }, { verdict::hex_taper, verdict::VERDICT_DBL_MAX }, { verdict::hex_volume, 0. }, { verdict::hex_stretch, 0.19245008973 }, { verdict::hex_diagonal, 1.0 }, { verdict::hex_dimension, 0. }, { verdict::hex_condition, verdict::VERDICT_DBL_MAX }, { verdict::hex_med_aspect_frobenius, verdict::VERDICT_DBL_MAX }, { verdict::hex_jacobian, 0 }, { verdict::hex_shear, 0 }, { verdict::hex_shape, 0 }, { verdict::hex_distortion, verdict::VERDICT_DBL_MAX }, { verdict::hex_nodal_jacobian_ratio, -verdict::VERDICT_DBL_MAX }, { verdict::hex_oddy, verdict::VERDICT_DBL_MAX }, { verdict::hex_edge_ratio, 1.0 / std::sqrt(0.02) }, { verdict::hex_equiangle_skew, 0.5 } }, 8, { // squashed flat { 0, 0, 0 }, { 1, 0, 0 }, { 1, 1, 0 }, { 0, 1, 0 }, { 0.1, 0.1, 0 }, { 0.9, 0.1, 0 }, { 0.9, 0.9, 0 }, { 0.1, 0.9, 0 } } }; runtest(testcase); } TEST(verdict, hex_test4_inside_out) { test_case testcase = { "hex_test4_inside_out", { // != indicates a value that is different than the right-side-out perfect cube /* 1 */ { verdict::hex_skew, 0 }, /* 2 */ { verdict::hex_taper, 0 }, /* 3 */ { verdict::hex_volume, -1. }, // != /* 4 */ { verdict::hex_stretch, 1 }, /* 5 */ { verdict::hex_diagonal, 1.0 }, /* 6 */ { verdict::hex_dimension, 1. / std::sqrt(3.) }, /* 7 */ { verdict::hex_condition, verdict::VERDICT_DBL_MAX }, // != /* 8 */ { verdict::hex_med_aspect_frobenius, verdict::VERDICT_DBL_MAX }, // != /* 9 */ { verdict::hex_jacobian, -1. }, // != /* 10 */ { verdict::hex_shear, 0 }, // != /* 11 */ { verdict::hex_shape, 0 }, // != /* 12 */ { verdict::hex_distortion, 1.0 }, /* 13 */ { verdict::hex_nodal_jacobian_ratio, -verdict::VERDICT_DBL_MAX }, // != /* 14 */ { verdict::hex_oddy, verdict::VERDICT_DBL_MAX }, // != /* 15 */ { verdict::hex_edge_ratio, 1.0 }, /* 16 */ { verdict::hex_equiangle_skew, 0 } }, 8, { // perfect unit hex, but ordered inside out! { 0, 0, 1 }, { 1, 0, 1 }, { 1, 1, 1 }, { 0, 1, 1 }, { 0, 0, 0 }, { 1, 0, 0 }, { 1, 1, 0 }, { 0, 1, 0 } } }; runtest(testcase); } TEST(verdict, hex27_test1) { test_case testcase = { "hex27_test1", { { verdict::hex_jacobian, 0.56021468927 } }, 27, { { -0.5, -0.5, 0.5 }, { -0.5, -0.5, -0.5 }, { -0.5, 0.5, -0.5 }, { -0.5, 0.5, 0.5 }, { 0.5, -0.5, 0.5 }, { 0.5, -0.5, -0.5 }, { 0.5, 0.5, -0.5 }, { 0.5, 0.5, 0.5 }, { -0.59093, -0.554599, 0.031478 }, { -0.551216, -0.052901, -0.59258 }, { -0.589451, 0.534972, -0.00525 }, { -0.575503, -0.008395, 0.604191 }, { 0.035399, -0.527937, 0.582587 }, { -0.015396, -0.537798, -0.606826 }, { -0.027222, 0.51188, -0.576597 }, { -0.006207, 0.565371, 0.585294 }, { 0.562112, -0.548542, -0.000139 }, { 0.570746, 0.008609, -0.595057 }, { 0.563111, 0.550215, -0.024469 }, { 0.537894, 0.050161, 0.606614 }, { -0.02166575, -0.0022401, 0.0023115 }, { -0.610022, -0.053727, -0.007623 }, { 0.593828, -0.007149, -0.019913 }, { 0.019742, 0.031299, 0.64416 }, { 0.033398, -0.032358, -0.596668 }, { 0.021178, -0.581132, 0.013062 }, { 0.000338, 0.60863, -0.017854 } } }; runtest(testcase); } TEST(verdict, hex20_test1) { test_case testcase = { "hex20_test1", { { verdict::hex_jacobian, 1 }, { verdict::hex_distortion, 3.4668482987e-01 }, }, 20, { { -0.5, -0.5, 0.5 }, { -0.5, -0.5, -0.5 }, { -0.5, 0.5, -0.5 }, { -0.5, 0.5, 0.5 }, { 0.5, -0.5, 0.5 }, { 0.5, -0.5, -0.5 }, { 0.5, 0.5, -0.5 }, { 0.5, 0.5, 0.5 }, { -0.59093, -0.554599, 0.031478 }, { -0.551216, -0.052901, -0.59258 }, { -0.589451, 0.534972, -0.00525 }, { -0.575503, -0.008395, 0.604191 }, { 0.035399, -0.527937, 0.582587 }, { -0.015396, -0.537798, -0.606826 }, { -0.027222, 0.51188, -0.576597 }, { -0.006207, 0.565371, 0.585294 }, { 0.562112, -0.548542, -0.000139 }, { 0.570746, 0.008609, -0.595057 }, { 0.563111, 0.550215, -0.024469 }, { 0.537894, 0.050161, 0.606614 } } }; runtest(testcase); } TEST(verdict, wedge_21_test1) { test_case testcase = { "wedge21_test1", { { verdict::wedge_jacobian, 0.99999775 } }, 21, { { 0, 0, -1 }, { 1, 0, -1 }, { 0, 1, -1 }, { 0, 0, 1 }, { 1, 0, 1 }, { 0, 1, 1 }, { 0.5, 0, -1 }, { 0.5, 0.5, -1 }, { 0, 0.5, -1 }, { 0, 0, 0 }, { 1, 0, 0 }, { 0, 1, 0 }, { 0.5, 0, 1 }, { 0.5, 0.5, 1 }, { 0, 0.5, 1 }, { .333333, .333333, 0 }, { .333333, .333333, -1 }, { .333333, .333333, 1 }, { .5, .5, 0 }, { 0, .5, 0 }, { 0.5, 0, 0 } } }; runtest(testcase); } TEST(verdict, tet15_test1) { test_case testcase = { "tet15_test1", { { verdict::tet_jacobian, 2.0 } }, 15, { { 0, 0, 0 }, { 0, 2, 0 }, { 1, 1, 0 }, { 6.12323399573677e-17, 1, -1 }, { 0, 1, 0 }, { 0.5, 1.5, 0 }, { 0.5, 0.5, 0 }, { 3.06161699786838e-17, 0.5, -0.5 }, { 3.06161699786838e-17, 1.5, -0.5 }, { 0.707106781186548, 1, -0.707106781186547 }, { 0.301776695296637, 1, -0.301776695296637 }, { 0.333333333333333, 1, 0 }, { 0.425380791638466, 1.33333333333333, -0.425380791638466 }, { 0.425380791638466, 0.666666666666667, -0.425380791638466 }, { 2.04107799857892e-17, 1, -0.333333333333333 } } }; runtest(testcase); } TEST(verdict, knife_test1) { test_case testcase = { "knife_test1", { { verdict::knife_volume, 2. / 3. } }, 7, { { 0, 0, 0 }, { 1, 0, 0 }, { 1, 1, 0 }, { 0, 1, 0 }, { 0, 0, 1 }, { 0.5, 0.5, 1 }, { 1, 1, 1 } } }; runtest(testcase); } TEST(verdict, tet_meanRatio_perfect_tet) { test_case testcase = { "tet_meanRatio_perfect_tet", { { verdict::tet_mean_ratio, 1.0 }, }, 4, { { 0, 0, 0 }, { 0, 1, 1 }, { 1, 0, 1 }, { 1, 1, 0 }, } }; runtest(testcase); } TEST(verdict, tet_meanRatio_degenerate_tet) { test_case testcase = { "tet_meanRatio_degenerate_tet", { { verdict::tet_mean_ratio, 0.0 }, }, 4, { { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, { 0, 0, 0 }, } }; runtest(testcase); } TEST(verdict, tet_meanRatio_unit_right_angle_tet) { test_case testcase = { "tet_meanRatio_unit_right_angle_tet", { { verdict::tet_mean_ratio, 0.839947 }, }, 4, { { 0, 0, 0 }, { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, 1 }, } }; runtest(testcase); } TEST(verdict, tet_meanRatio_nearly_flat_right_angle_tet) { test_case testcase = { "tet_meanRatio_nearly_flat_right_angle_tet", { { verdict::tet_mean_ratio, 0.0584774 }, }, 4, { { 0, 0, 0 }, { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, .01 }, } }; runtest(testcase); } TEST(verdict, tet_meanRatio_inverted_nearly_flat_right_angle_tet) { test_case testcase = { "tet_meanRatio_nearly_flat_right_angle_tet", { { verdict::tet_mean_ratio, -0.0584774 }, }, 4, { { 0, 0, 0 }, { 1, 0, 0 }, { 0, 1, 0 }, { 0, 0, -.01 }, } }; runtest(testcase); } TEST(verdict, tet_normalized_inradius_perfect_tet10) { test_case testcase = { "tet_normalized_subtet_perfect_tet", { { verdict::tet_normalized_inradius, 1.0 }, }, 10, { { 0.000000, 0.000000, 0.000000 }, { 0.000000, 1.000000, 1.000000 }, { 1.000000, 0.000000, 1.000000 }, { 1.000000, 1.000000, 0.000000 }, { 0.000000, 0.500000, 0.500000 }, { 0.500000, 0.500000, 1.000000 }, { 0.500000, 0.000000, 0.500000 }, { 0.500000, 0.500000, 0.000000 }, { 0.500000, 1.000000, 0.500000 }, { 1.000000, 0.500000, 0.500000 }, } }; runtest(testcase); } TEST(verdict, tet_normalized_inradius_deformed_tet10) { test_case testcase = { "tet_normalized_subtet_perfect_tet", { { verdict::tet_normalized_inradius, 0.49373899958502704 }, }, 10, { { -0.05, -0.1, 0.125 }, { 0.9, 0.025, -0.075 }, { -0.1, 1.025, -0.075 }, { 0.125, 0.1, 1.025 }, { 0.525, 0.025, -0.05 }, { 0.5, 0.525, 0.05 }, { 0.125, 0.45, -0.075 }, { 0.1, 0.075, 0.575 }, { 0.475, -0.075, 0.55 }, { -0.075, 0.6, 0.45 }, } }; runtest(testcase); } TEST(verdict, tet8_volume) { test_case testcase = { "Volume of tet8 element", { { verdict::tet_volume, 0.2103399378 }, }, 8, { { -0.05, -0.1, 0.125 }, { 0.9, 0.025, -0.075 }, { -0.1, 1.025, -0.075 }, { 0.125, 0.1, 1.025 }, { 0.224518, 0.314238, 0.088176 }, { 0.450716, 0.495582, 0.292855 }, { 0.026687, 0.383860, 0.337325 }, { 0.362298, -0.064834, 0.403524 }, } }; runtest(testcase); } TEST(verdict, tet10_volume) { test_case testcase = { "Volume of tet10 element", { { verdict::tet_volume, 0.153515625 }, }, 10, { { -0.05, -0.1, 0.125 }, { 0.9, 0.025, -0.075 }, { -0.1, 1.025, -0.075 }, { 0.125, 0.1, 1.025 }, { 0.525, 0.025, -0.05 }, { 0.5, 0.525, 0.05 }, { 0.125, 0.45, -0.075 }, { 0.1, 0.075, 0.575 }, { 0.475, -0.075, 0.55 }, { -0.075, 0.6, 0.45 }, } }; runtest(testcase); } TEST(verdict, tet14_volume) { test_case testcase = { "Volume of tet14 element", { { verdict::tet_volume, 0.1680788275 }, }, 14, { { -0.05, -0.1, 0.125 }, { 0.9, 0.025, -0.075 }, { -0.1, 1.025, -0.075 }, { 0.125, 0.1, 1.025 }, { 0.525, 0.025, -0.05 }, { 0.5, 0.525, 0.05 }, { 0.125, 0.45, -0.075 }, { 0.1, 0.075, 0.575 }, { 0.475, -0.075, 0.55 }, { -0.075, 0.6, 0.45 }, { 0.392383, 0.4289156667, -0.007145333333 }, { 0.3433533333, 0.4255263333, 0.2706586667 }, { 0.02896466667, 0.2684996667, 0.4035243333 }, { 0.299518, 0.005904333333, 0.4548423333 }, } }; runtest(testcase); } TEST(verdict, tet15_volume) { test_case testcase = { "Volume of tet15 element", { { verdict::tet_volume, 0.1680788275 }, }, 15, { { -0.05, -0.1, 0.125 }, { 0.9, 0.025, -0.075 }, { -0.1, 1.025, -0.075 }, { 0.125, 0.1, 1.025 }, { 0.525, 0.025, -0.05 }, { 0.5, 0.525, 0.05 }, { 0.125, 0.45, -0.075 }, { 0.1, 0.075, 0.575 }, { 0.475, -0.075, 0.55 }, { -0.075, 0.6, 0.45 }, { 0.303125, 0.26875, 0.25 }, { 0.392383, 0.4289156667, -0.007145333333 }, { 0.3433533333, 0.4255263333, 0.2706586667 }, { 0.02896466667, 0.2684996667, 0.4035243333 }, { 0.299518, 0.005904333333, 0.4548423333 }, } }; runtest(testcase); } TEST(verdict, hex20_volume) { test_case testcase = { "Volume of hex20 element", { { verdict::hex_volume, 0.9425 }, }, 20, { { -0.5, -0.5, 0.5 }, { -0.5, -0.5, -0.5 }, { -0.5, 0.5, -0.5 }, { -0.5, 0.5, 0.4 }, { 0.5, -0.5, 0.5 }, { 0.5, -0.5, -0.5 }, { 0.6, 0.7, -0.5 }, { 0.5, 0.5, 0.5 }, { -0.5, -0.5, 0.0 }, { -0.5, 0.0, -0.5 }, { -0.5, 0.5, 0.0 }, { -0.5, 0.0, 0.5 }, { 0.3, -0.5, 0.5 }, { 0.0, -0.5, -0.5 }, { 0.0, 0.5, -0.5 }, { 0.0, 0.4, 0.5 }, { 0.3, -0.5, 0.0 }, { 0.6, 0.0, -0.5 }, { 0.5, 0.5, 0.0 }, { 0.5, 0.0, 0.4 }, } }; runtest(testcase); } TEST(verdict, hex27_volume) { test_case testcase = { "Volume of hex27 element", { { verdict::hex_volume, 1.242167 }, }, 27, { { -0.5, -0.5, 0.5 }, { -0.5, -0.5, -0.5 }, { -0.5, 0.5, -0.6 }, { -0.5, 0.5, 0.4 }, { 0.5, -0.5, 0.5 }, { 0.5, -0.5, -0.5 }, { 0.6, 0.7, -0.5 }, { 0.5, 0.5, 0.5 }, { -0.5, -0.5, 0.0 }, { -0.5, 0.0, -0.5 }, { -0.5, 0.5, 0.0 }, { -0.5, 0.0, 0.5 }, { 0.3, -0.5, 0.5 }, { 0.0, -0.5, -0.5 }, { 0.0, 0.5, -0.5 }, { 0.0, 0.5, 0.8 }, { 0.8, -0.5, 0.0 }, { 0.5, 0.0, -0.5 }, { 0.7, 0.5, 0.0 }, { 0.5, 0.0, 0.6 }, { 0.0, 0.0, 0.0 }, { -0.5, 0.0, 0.0 }, { 0.5, 0.0, 0.0 }, { 0.0, 0.0, 0.5 }, { 0.0, 0.0, -0.5 }, { 0.0, -0.5, 0.0 }, { 0.3, 0.8, 0.0 } } }; runtest(testcase); }