int main( int argc, char* argv[] ) { parse_options( argv, argc ); MeshImpl mesh; XYRectangle domain( max_x - min_x, max_y - min_y, min_x, min_y ); MsqError err; create_input_mesh( input_x, mesh, err ); if (MSQ_CHKERR(err)) { std::cerr << err << std::endl; return 2; } domain.setup( &mesh, err ); if (MSQ_CHKERR(err)) { std::cerr << err << std::endl; return 2; } QualityMetric* metric = 0; if (mMetric == 'c') metric = new ConditionNumberQualityMetric; else metric = new IdealWeightInverseMeanRatio; LPtoPTemplate function( 1, metric ); VertexMover* solver = 0; if (mSolver == 'j') solver = new ConjugateGradient( &function ); else solver = new FeasibleNewton( &function ); if (PatchSetUser* psu = dynamic_cast<PatchSetUser*>(solver)) psu->use_global_patch(); TerminationCriterion inner; inner.add_absolute_vertex_movement( 1e-4 ); inner.write_mesh_steps( "synchronous", TerminationCriterion::GNUPLOT ); solver->set_inner_termination_criterion( &inner ); InstructionQueue q; QualityAssessor qa( metric, 10 ); q.add_quality_assessor( &qa, err ); q.set_master_quality_improver( solver, err ); q.add_quality_assessor( &qa, err ); MeshDomainAssoc mesh_and_domain = MeshDomainAssoc(&mesh, &domain); q.run_instructions( &mesh_and_domain, err ); delete solver; delete metric; if (MSQ_CHKERR(err)) { std::cerr << err << std::endl; return 3; } mesh.write_vtk( outputFile, err ); if (MSQ_CHKERR(err)) { std::cerr << err << std::endl; return 2; } return 0; }
//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_number_of_iterates_outer() { MsqPrintError err(std::cout); PatchData pd; const int LIMIT = 2; TerminationCriterion tc; tc.add_iteration_limit(LIMIT); tc.reset_outer( 0, 0, ofEval, 0, 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_outer( 0, 0, ofEval, 0, err ); ASSERT_NO_ERROR(err); } CPPUNIT_ASSERT_EQUAL( 2, tc.get_iteration_count() ); 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()); }
//! Constructor sets the instructions in the queue. LaplacianIQ() { MsqError err; // creates a mean ratio quality metric ... inverseMeanRatio = new IdealWeightInverseMeanRatio(err); // creates the laplacian smoother procedures lapl1 = new LaplacianSmoother(err); mQA = new QualityAssessor(inverseMeanRatio,QualityAssessor::MAXIMUM, err); //**************Set stopping criterion**************** mTerm = new TerminationCriterion(); mTerm->add_criterion_type_with_int(TerminationCriterion::NUMBER_OF_ITERATES,10,err); lapl1->set_outer_termination_criterion(mTerm); // sets a culling method on the first QualityImprover lapl1->add_culling_method(PatchData::NO_BOUNDARY_VTX); // adds 1 pass of pass1 this->add_quality_assessor(mQA,err); MSQ_CHKERR(err); this->set_master_quality_improver(lapl1, err); MSQ_CHKERR(err); this->add_quality_assessor(mQA,err); MSQ_CHKERR(err); }
int main( int argc, char* argv[] ) { const char* input_file = DEFAULT_INPUT_FILE; const char* output_file_base = 0; bool expect_output_base = false; for (int i = 1; i < argc; ++i) { if (expect_output_base) { output_file_base = argv[i]; expect_output_base = false; } else if (!strcmp(argv[i],"-o")) expect_output_base = true; else if (input_file != DEFAULT_INPUT_FILE) usage(argv[0]); else input_file = argv[i]; } if (expect_output_base) usage(argv[0]); MsqPrintError err(std::cerr); SlaveBoundaryVertices slaver(1); TShapeNB1 tmetric; IdealShapeTarget target; TQualityMetric metric( &target, &tmetric ); PMeanPTemplate of( 1.0, &metric ); SteepestDescent improver( &of ); TerminationCriterion inner; inner.add_absolute_vertex_movement( 1e-3 ); improver.set_inner_termination_criterion( &inner ); QualityAssessor assess( &metric ); InstructionQueue q; q.set_master_quality_improver( &improver, err ); q.add_quality_assessor( &assess, err ); TriLagrangeShape trishape; QuadLagrangeShape quadshape; q.set_mapping_function( &trishape ); q.set_mapping_function( &quadshape ); const int NUM_MODES = 4; Settings::HigherOrderSlaveMode modes[NUM_MODES] = { Settings::SLAVE_NONE, Settings::SLAVE_ALL, Settings::SLAVE_CALCULATED, Settings::SLAVE_FLAG }; std::string names[NUM_MODES] = { "NONE", "ALL", "CALCULATED", "FLAG" }; MeshImpl meshes[NUM_MODES]; std::vector<MeshDomainAssoc> meshes_and_domains; bool have_slaved_flag = true; std::vector<bool> flag(1); for (int i = 0; i < NUM_MODES; ++i) { std::cout << std::endl << "-----------------------------------------------" << std::endl << " Mode: " << names[i] << std::endl << "-----------------------------------------------" << std::endl; meshes[i].read_vtk( input_file, err ); if (err) return 1; if (modes[i] == Settings::SLAVE_CALCULATED) { q.add_vertex_slaver( &slaver, err ); } else if (modes[i] == Settings::SLAVE_FLAG) { std::vector<Mesh::VertexHandle> verts; meshes[i].get_all_vertices( verts, err ); if (err) return 1; meshes[i].vertices_get_slaved_flag( arrptr(verts), flag, 1, err ); if (err) { have_slaved_flag = false; std::cout << "Skipped because input file does not contain slaved attribute" << std::endl; err.clear(); continue; } } if (have_slaved_flag && modes[i] == Settings::SLAVE_FLAG) { if (!check_no_slaved_corners( meshes[i], err ) || err) return 1; if (!check_global_patch_slaved( meshes[i], err ) || err) return 1; } PlanarDomain plane; plane.fit_vertices( &meshes[i], err ); if (err) return 1; q.set_slaved_ho_node_mode( modes[i] ); meshes_and_domains.push_back(MeshDomainAssoc(&meshes[i], &plane)); q.run_instructions( &meshes_and_domains[i], err ); if (err) return 1; if (modes[i] == Settings::SLAVE_CALCULATED) { q.remove_vertex_slaver( &slaver, err ); } if (output_file_base) { tag_patch_slaved( meshes[i], modes[i], err ); std::string name(output_file_base); name += "-"; name += names[i]; name += ".vtk"; meshes[i].write_vtk( name.c_str(), err ); if (err) return 1; } } int exit_code = 0; if (input_file == DEFAULT_INPUT_FILE) { for (int i = 0; i < NUM_MODES; ++i) { std::cout << std::endl << "-----------------------------------------------" << std::endl << " Mode: " << names[i] << std::endl << "-----------------------------------------------" << std::endl; exit_code += check_slaved_coords( meshes[i], modes[i], names[i], have_slaved_flag, err ); if (err) return 1; } // flags should correspond to same slaved nodes as calculated, // so resulting meshes should be identical. if (have_slaved_flag) { int flag_idx = std::find( modes, modes+NUM_MODES, Settings::SLAVE_FLAG ) - modes; int calc_idx = std::find( modes, modes+NUM_MODES, Settings::SLAVE_CALCULATED ) - modes; exit_code += compare_node_coords( meshes[flag_idx], meshes[calc_idx], err ); if (err) return 1; } } return exit_code; }
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()); }
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_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()); }
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()); }
//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()); }
void run_test( Grouping grouping, int of_power, Weight w, const string filename ) { MsqError err; IdentityTarget target; TSquared target_metric; AffineMapMetric qual_metric( &target, &target_metric ); ElementPMeanP elem_metric( of_power, &qual_metric ); QualityMetric* qm_ptr = (grouping == ELEMENT) ? (QualityMetric*)&elem_metric : (QualityMetric*)&qual_metric; PMeanPTemplate OF( of_power, qm_ptr ); ConjugateGradient solver( &OF ); TerminationCriterion tc; TerminationCriterion itc; tc.add_absolute_vertex_movement( 1e-4 ); itc.add_iteration_limit( 2 ); #ifdef USE_GLOBAL_PATCH solver.use_global_patch(); solver.set_inner_termination_criterion( &tc ); #else solver.use_element_on_vertex_patch(); solver.set_inner_termination_criterion( &itc ); solver.set_outer_termination_criterion( &tc ); #endif MeshImpl mesh, expected_mesh; mesh.read_vtk( SRCDIR "/initial.vtk", err ); CHKERR(err) // expected_mesh.read_vtk( (filename + ".vtk").c_str(), err ); CHKERR(err) PlanarDomain plane( PlanarDomain::XY ); MeshDomainAssoc mesh_and_domain = MeshDomainAssoc(&mesh, &plane); MetricWeight mw( &qual_metric ); InverseMetricWeight imw( &qual_metric ); WeightReader reader; if (w == METRIC) { TargetWriter writer( 0, &mw ); InstructionQueue tq; tq.add_target_calculator( &writer, err ); tq.run_instructions( &mesh_and_domain, err ); CHKERR(err); qual_metric.set_weight_calculator( &reader ); } else if (w == INV_METRIC) { TargetWriter writer( 0, &imw ); InstructionQueue tq; tq.add_target_calculator( &writer, err ); tq.run_instructions( &mesh_and_domain, err ); CHKERR(err); qual_metric.set_weight_calculator( &reader ); } InstructionQueue q; q.set_master_quality_improver( &solver, err ); q.run_instructions( &mesh_and_domain, err ); CHKERR(err) /* vector<Mesh::VertexHandle> vemain.cpprts; vector<MsqVertex> mesh_coords, expected_coords; mesh.get_all_vertices( verts, err ); CHKERR(err) mesh_coords.resize(verts.size()); mesh.vertices_get_coordinates( arrptr(verts), arrptr(mesh_coords), verts.size(), err ); CHKERR(err) expected_mesh.get_all_vertices( verts, err ); CHKERR(err) expected_coords.resize(verts.size()); expected_mesh.vertices_get_coordinates( arrptr(verts), arrptr(expected_coords), verts.size(), err ); CHKERR(err) if (expected_coords.size() != mesh_coords.size()) { cerr << "Invlid expected mesh. Vertex count doesn't match" << endl; exit(1); } unsigned error_count = 0; for (size_t i = 0; i < mesh_coords.size(); ++i) if ((expected_coords[i] - mesh_coords[i]).length_squared() > epsilon*epsilon) ++error_count; if (!error_count) cout << filename << " : SUCCESS" << endl; else cout << filename << " : FAILURE (" << error_count << " vertices differ by more than " << epsilon << ")" << endl; */ if (write_results) mesh.write_vtk( (filename + ".results.vtk").c_str(), err ); CHKERR(err) }
int main( int argc, char* argv[] ) { const double default_fraction = 0.05; const double zero = 0.0; int one = 1; CLArgs::ToggleArg allow_invalid( false ); CLArgs::DoubleRangeArg rand_percent( default_fraction, &zero, 0 ); CLArgs::IntRangeArg unoptimize( 0, &one, 0 ); CLArgs args( "vtkrandom", "Randomize mesh vertex locations.", "Read VTK file, randomize locations of containded vertices, and re-write file." ); args.toggle_flag( INVALID_FLAG, "Allow inverted elements in output", &allow_invalid ); args.double_flag( PERCENT_FLAG, "fract", "Randomize fraction", &rand_percent ); args.int_flag( UNOPTIMIZE_FLAG, "N", "Use UnOptimizer with N passes rather than Randomize", &unoptimize ); add_domain_args( args ); args.add_required_arg( "input_file" ); args.add_required_arg( "output_file" ); std::vector<std::string> files; if (!args.parse_options( argc, argv, files, std::cerr )) { args.print_usage( std::cerr ); exit(1); } std::string input_file = files[0]; std::string output_file = files[1]; MsqError err; MeshImpl mesh; mesh.read_vtk( input_file.c_str(), err ); if (err) { std::cerr << "ERROR READING FILE: " << input_file << std::endl << err << std::endl; return 2; } MeshDomain* domain = process_domain_args( &mesh ); TerminationCriterion tc; QualityAssessor qa( false ); InstructionQueue q; Randomize op( rand_percent.value() ); IdealWeightInverseMeanRatio metric; PMeanPTemplate of( 1, &metric ); UnOptimizer op2( &of ); if (unoptimize.seen()) { tc.add_iteration_limit( unoptimize.value() ); op2.set_outer_termination_criterion( &tc ); q.add_preconditioner( &op, err ); q.set_master_quality_improver( &op2, err ); } else { q.set_master_quality_improver( &op, err ); } q.add_quality_assessor( &qa, err ); q.run_instructions( &mesh, domain, err ); if (err) { std::cerr << err << std::endl; return 3; } int inverted, junk; if (qa.get_inverted_element_count( inverted, junk, err ) && inverted ) { if (allow_invalid.value()) std::cerr << "Warning: output mesh contains " << inverted << " inverted elements" << std::endl; else { std::cerr << "Error: output mesh contains " << inverted << " inverted elements" << std::endl; return 4; } } mesh.write_vtk( output_file.c_str(), err ); if (err) { std::cerr << "ERROR WRITING FILE: " << output_file << std::endl << err << std::endl; return 2; } return 0; }