//VERTEX BOUND void TerminationCriterionTest::test_vertex_bound() { MsqPrintError err(std::cout); PatchData pd; create_twelve_hex_patch( pd, err ); ASSERT_NO_ERROR(err); // get bounding dimension for patch double maxcoord = 0.0; for (size_t i = 0; i < pd.num_nodes(); ++i) for (int d = 0; d < 3; ++d) if (fabs(pd.vertex_by_index(i)[d]) > maxcoord) maxcoord = fabs(pd.vertex_by_index(i)[d]); // add a little bit for rounding error maxcoord += 1e-5; TerminationCriterion tc; tc.add_bounded_vertex_movement( maxcoord ); tc.reset_inner( pd, ofEval, err ); ASSERT_NO_ERROR(err); tc.reset_patch( pd, err ); ASSERT_NO_ERROR(err); CPPUNIT_ASSERT(!tc.terminate()); int idx = pd.num_free_vertices() - 1; Vector3D pos = pd.vertex_by_index(idx); pos[0] = 2*maxcoord; pd.set_vertex_coordinates( pos, idx, err ); ASSERT_NO_ERROR(err); tc.accumulate_inner( pd, 0.0, 0, err ); ASSERT_NO_ERROR(err); tc.accumulate_patch( pd, err ); ASSERT_NO_ERROR(err); CPPUNIT_ASSERT(tc.terminate()); }
void TerminationCriterionTest::test_vertex_movement_common( bool absolute ) { MsqPrintError err(std::cout); PatchData pd; create_twelve_hex_patch( pd, err ); ASSERT_NO_ERROR(err); const double LIMIT = 1e-4; TerminationCriterion tc; if (absolute) tc.add_absolute_vertex_movement( LIMIT ); else tc.add_relative_vertex_movement( LIMIT ); tc.reset_inner( pd, ofEval, err ); ASSERT_NO_ERROR(err); tc.reset_patch( pd, err ); ASSERT_NO_ERROR(err); CPPUNIT_ASSERT(!tc.terminate()); const double FIRST_STEP=10.0; // move a vertex by 10 units and check that it did not meet criterion pd.move_vertex( Vector3D(FIRST_STEP,0,0), 0, err ); ASSERT_NO_ERROR(err); tc.accumulate_inner( pd, 0.0, 0, err ); ASSERT_NO_ERROR(err); tc.accumulate_patch( pd, err ); ASSERT_NO_ERROR(err); CPPUNIT_ASSERT(!tc.terminate()); double test_limit = LIMIT; if (!absolute) test_limit *= FIRST_STEP; int idx = 0; for (double step = FIRST_STEP; step > test_limit; step *= 0.09) { idx = (idx + 1) % pd.num_free_vertices(); pd.move_vertex( Vector3D(step,0,0), idx, err ); ASSERT_NO_ERROR(err); tc.accumulate_inner( pd, 0.0, 0, err ); ASSERT_NO_ERROR(err); tc.accumulate_patch( pd, err ); ASSERT_NO_ERROR(err); CPPUNIT_ASSERT(!tc.terminate()); } idx = (idx + 1) % pd.num_free_vertices(); pd.move_vertex( Vector3D(0.5*test_limit,0,0), idx, err ); ASSERT_NO_ERROR(err); tc.accumulate_inner( pd, 0.0, 0, err ); ASSERT_NO_ERROR(err); tc.accumulate_patch( pd, err ); ASSERT_NO_ERROR(err); CPPUNIT_ASSERT(tc.terminate()); }
void TerminationCriterionTest::test_gradient_common( bool absolute, bool L2 ) { MsqPrintError err(std::cout); PatchData pd; create_twelve_hex_patch( pd, err ); ASSERT_NO_ERROR(err); const double LIMIT = 1e-4; TerminationCriterion tc; if (absolute) { if (L2) tc.add_absolute_gradient_L2_norm( LIMIT ); else tc.add_absolute_gradient_inf_norm( LIMIT ); } else { if (L2) tc.add_relative_gradient_L2_norm( LIMIT ); else tc.add_relative_gradient_inf_norm( LIMIT ); } double (*func_ptr)(const Vector3D*, int) = L2 ? &lenfunc : &maxfunc; double junk, value = 1; objFunc.mGrad = Vector3D(value,value,value); tc.reset_inner( pd, ofEval, err ); ASSERT_NO_ERROR(err); tc.reset_patch( pd, err ); ASSERT_NO_ERROR(err); std::vector<Vector3D> grad; ofEval.evaluate( pd, junk, grad, err ); ASSERT_NO_ERROR(err); double limit = LIMIT; if (!absolute) limit *= func_ptr(arrptr(grad),pd.num_free_vertices()); while (func_ptr(arrptr(grad),pd.num_free_vertices()) > limit) { CPPUNIT_ASSERT(!tc.terminate()); value *= 0.1; objFunc.mGrad = Vector3D(value,value,value); ofEval.evaluate( pd, junk, grad, err ); ASSERT_NO_ERROR(err); tc.accumulate_inner( pd, 0.0, arrptr(grad), err ); ASSERT_NO_ERROR(err); tc.accumulate_patch( pd, err ); ASSERT_NO_ERROR(err); } CPPUNIT_ASSERT(tc.terminate()); }
void TerminationCriterionTest::test_quality_common( bool absolute, bool successive ) { MsqPrintError err(std::cout); PatchData pd; ASSERT_NO_ERROR(err); const double LIMIT = 1e-4; TerminationCriterion tc; bool (*func_ptr)(double, double, double, double); if (absolute) { if (successive) { tc.add_absolute_successive_improvement( LIMIT ); func_ptr = &limit_absolute_sucessive; } else { tc.add_absolute_quality_improvement( LIMIT ); func_ptr = &limit_absolute_quality; } } else { if (successive) { tc.add_relative_successive_improvement( LIMIT ); func_ptr = &limit_relative_sucessive; } else { tc.add_relative_quality_improvement( LIMIT ); func_ptr = &limit_relative_quality; } } const double INIT_VALUE = 10.0; objFunc.mValue = INIT_VALUE; tc.reset_inner( pd, ofEval, err ); ASSERT_NO_ERROR(err); tc.reset_patch( pd, err ); ASSERT_NO_ERROR(err); double prev = HUGE_VAL; while (!func_ptr(INIT_VALUE,prev,objFunc.mValue,LIMIT)) { CPPUNIT_ASSERT(!tc.terminate()); prev = objFunc.mValue; objFunc.mValue *= 0.1; tc.accumulate_inner( pd, objFunc.mValue, 0, err ); ASSERT_NO_ERROR(err); tc.accumulate_patch( pd, err ); ASSERT_NO_ERROR(err); } CPPUNIT_ASSERT(tc.terminate()); }
//UNTANGLED void TerminationCriterionTest::test_untangled_mesh() { MsqPrintError err(std::cout); PatchData pd; create_twelve_hex_patch( pd, err ); ASSERT_NO_ERROR(err); // get two opposite vertices in first hexahedral element int vtx1 = pd.element_by_index(0).get_vertex_index_array()[0]; int vtx2 = pd.element_by_index(0).get_vertex_index_array()[7]; Vector3D saved_coords = pd.vertex_by_index(vtx2); Vector3D opposite_coords = pd.vertex_by_index(vtx1); // invert the element pd.move_vertex( 2*(opposite_coords-saved_coords), vtx2, err ); ASSERT_NO_ERROR(err); int inverted, samples; pd.element_by_index(0).check_element_orientation( pd, inverted, samples, err ); ASSERT_NO_ERROR(err); CPPUNIT_ASSERT(inverted > 0); // check initial termination criterion TerminationCriterion tc; tc.add_untangled_mesh(); tc.reset_inner( pd, ofEval, err ); ASSERT_NO_ERROR(err); tc.reset_patch( pd, err ); ASSERT_NO_ERROR(err); CPPUNIT_ASSERT(!tc.terminate()); // fix the element pd.set_vertex_coordinates( saved_coords, vtx2, err ); ASSERT_NO_ERROR(err); pd.element_by_index(0).check_element_orientation( pd, inverted, samples, err ); ASSERT_NO_ERROR(err); CPPUNIT_ASSERT_EQUAL(0,inverted); // check that TC recognized untangled mesh tc.accumulate_inner( pd, 0.0, 0, err ); ASSERT_NO_ERROR(err); tc.accumulate_patch( pd, err ); ASSERT_NO_ERROR(err); CPPUNIT_ASSERT(tc.terminate()); }
//CPU TIME void TerminationCriterionTest::test_cpu_time_common( bool inner ) { MsqPrintError err(std::cout); PatchData pd; double LIMIT = 0.5; TerminationCriterion tc; tc.add_cpu_time(LIMIT); if (inner) tc.reset_inner( pd, ofEval, err ); else tc.reset_outer( 0, 0, ofEval, 0, err ); ASSERT_NO_ERROR(err); tc.reset_patch( pd, err ); ASSERT_NO_ERROR(err); Timer timer; while (timer.since_birth() < 0.5*LIMIT) { CPPUNIT_ASSERT(!tc.terminate()); tc.accumulate_patch( pd, err ); ASSERT_NO_ERROR(err); if (inner) tc.accumulate_inner( pd, 0, 0, err ); else tc.accumulate_outer( 0, 0, ofEval, 0, err ); ASSERT_NO_ERROR(err); } while (timer.since_birth() < 1.1*LIMIT); tc.accumulate_patch( pd, err ); ASSERT_NO_ERROR(err); if (inner) tc.accumulate_inner( pd, 0, 0, err ); else tc.accumulate_outer( 0, 0, ofEval, 0, err ); ASSERT_NO_ERROR(err); CPPUNIT_ASSERT(tc.terminate()); }
//NUMBER OF ITERATES void TerminationCriterionTest::test_number_of_iterates_inner() { MsqPrintError err(std::cout); PatchData pd; const int LIMIT = 2; TerminationCriterion tc; tc.add_iteration_limit(LIMIT); tc.reset_inner( pd, ofEval, err ); ASSERT_NO_ERROR(err); tc.reset_patch( pd, err ); ASSERT_NO_ERROR(err); for (int i = 0; i < LIMIT; ++i) { CPPUNIT_ASSERT(!tc.terminate()); CPPUNIT_ASSERT_EQUAL( i, tc.get_iteration_count() ); tc.accumulate_patch( pd, err ); ASSERT_NO_ERROR(err); tc.accumulate_inner( pd, 0, 0, err ); ASSERT_NO_ERROR(err); } CPPUNIT_ASSERT_EQUAL( 2, tc.get_iteration_count() ); CPPUNIT_ASSERT(tc.terminate()); }
void TerminationCriterionTest::test_absolute_vertex_movement_edge_length() { MsqPrintError err(std::cout); // define two-tet mesh where tets share a face double coords[] = { 0, -5, 0, 0, 5, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1 }; const unsigned long conn[] = { 4, 3, 2, 0, 2, 3, 4, 1 }; int fixed[5] = {0}; ArrayMesh mesh( 3, 5, coords, fixed, 2, TETRAHEDRON, conn ); // calculate beta const double LIMIT = 1e-4; // desired absolute limit MeshUtil tool(&mesh); SimpleStats len; tool.edge_length_distribution( len, err ); ASSERT_NO_ERROR(err); const double beta = LIMIT / (len.average() - len.standard_deviation()); // initialize termination criterion TerminationCriterion tc; tc.add_absolute_vertex_movement_edge_length( beta ); MeshDomainAssoc mesh_and_domain2 = MeshDomainAssoc(&mesh, 0); tc.initialize_queue( &mesh_and_domain2, 0, err ); ASSERT_NO_ERROR(err); // get a patch data PatchData pd; pd.set_mesh( &mesh ); pd.fill_global_patch( err ); ASSERT_NO_ERROR(err); // test termination criteiorn tc.reset_inner( pd, ofEval, err ); ASSERT_NO_ERROR(err); tc.reset_patch( pd, err ); ASSERT_NO_ERROR(err); CPPUNIT_ASSERT(!tc.terminate()); const double FIRST_STEP=10.0; // move a vertex by 10 units and check that it did not meet criterion pd.move_vertex( Vector3D(FIRST_STEP,0,0), 0, err ); ASSERT_NO_ERROR(err); tc.accumulate_inner( pd, 0.0, 0, err ); ASSERT_NO_ERROR(err); tc.accumulate_patch( pd, err ); ASSERT_NO_ERROR(err); CPPUNIT_ASSERT(!tc.terminate()); double test_limit = LIMIT; int idx = 0; for (double step = FIRST_STEP; step > test_limit; step *= 0.09) { idx = (idx + 1) % pd.num_free_vertices(); pd.move_vertex( Vector3D(step,0,0), idx, err ); ASSERT_NO_ERROR(err); tc.accumulate_inner( pd, 0.0, 0, err ); ASSERT_NO_ERROR(err); tc.accumulate_patch( pd, err ); ASSERT_NO_ERROR(err); CPPUNIT_ASSERT(!tc.terminate()); } idx = (idx + 1) % pd.num_free_vertices(); pd.move_vertex( Vector3D(0.5*test_limit,0,0), idx, err ); ASSERT_NO_ERROR(err); tc.accumulate_inner( pd, 0.0, 0, err ); ASSERT_NO_ERROR(err); tc.accumulate_patch( pd, err ); ASSERT_NO_ERROR(err); CPPUNIT_ASSERT(tc.terminate()); }