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; }
int main( int argc, char* argv[] ) { MeshParams input_params, reference_params; bool fixed_boundary_vertices, feas_newt_solver; TerminationCriterion::TimeStepFileType write_timestep_files; std::string output_file_name; int num_iterations; parse_options( argv, argc, input_params, reference_params, output_file_name, fixed_boundary_vertices, write_timestep_files, feas_newt_solver, num_iterations ); MsqError err; MeshImpl mesh, refmesh; XYRectangle domain( input_params.w, input_params.h ); create_input_mesh( input_params, fixed_boundary_vertices, mesh, err ); CHECKERR create_input_mesh( reference_params, fixed_boundary_vertices, refmesh, err ); CHECKERR domain.setup( &mesh, err ); CHECKERR ReferenceMesh rmesh( &refmesh ); RefMeshTargetCalculator tc( &rmesh ); TShapeB1 tm; TQualityMetric qm( &tc, &tm ); PMeanPTemplate of( 1.0, &qm ); ConjugateGradient cg( &of ); cg.use_element_on_vertex_patch(); FeasibleNewton fn( &of ); fn.use_element_on_vertex_patch(); VertexMover* solver = feas_newt_solver ? (VertexMover*)&fn : (VertexMover*)&cg; TerminationCriterion inner, outer; inner.add_iteration_limit( INNER_ITERATES ); outer.add_iteration_limit( num_iterations ); if (write_timestep_files != TerminationCriterion::NOTYPE) outer.write_mesh_steps( base_name( output_file_name ).c_str(), write_timestep_files ); solver->set_inner_termination_criterion( &inner ); solver->set_outer_termination_criterion( &outer ); QualityAssessor qa( &qm ); InstructionQueue q; 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 ); CHECKERR mesh.write_vtk( output_file_name.c_str(), err ); CHECKERR // check for inverted elements int inv, unk; qa.get_inverted_element_count( inv, unk, err ); if (inv) { std::cerr << inv << " inverted elements in final mesh" << std::endl; return INVERTED_ELEMENT; } else if (unk) { std::cerr << unk << " degenerate elements in final mesh" << std::endl; return DEGENERATE_ELEMENT; } // find the free vertex std::vector<Mesh::VertexHandle> vertices; mesh.get_all_vertices( vertices, err ); if (vertices.empty()) { std::cerr << "Mesh contains no vertices" << std::endl; return USAGE_ERROR; } std::vector<unsigned short> dof( vertices.size(), 0 ); domain.domain_DoF( arrptr(vertices), arrptr(dof), vertices.size(), err ); CHECKERR int idx = std::find(dof.begin(), dof.end(), 2) - dof.begin(); const Mesh::VertexHandle free_vertex = vertices[idx]; MsqVertex coords; mesh.vertices_get_coordinates( &free_vertex, &coords,1, err ); CHECKERR // calculate optimal position for vertex const double xf = reference_params.x / reference_params.w; const double yf = reference_params.y / reference_params.h; Vector3D expect( xf * input_params.w, yf * input_params.h, 0 ); // Test that we aren't further from the expected location // than when we started. const Vector3D init( input_params.x, input_params.y, 0 ); if ((coords - expect).length() > (init - expect).length()) { std::cerr << "Vertex moved away from expected optimal position: " << "(" << coords[0] << ", " << coords[1] << std::endl; return WRONG_DIRECTION; } // check if vertex moved MIN_FRACT of the way from the original position // to the desired one in the allowed iterations const double MIN_FRACT = 0.2; // 20% of the way in 10 iterations const double fract = (coords - init).length() / (expect - init).length(); if (fract < MIN_FRACT) { std::cerr << "Vertex far from optimimal location" << std::endl << " Expected: (" << expect[0] << ", " << expect[1] << ", " << expect[2] << ")" << std::endl << " Actual: (" << coords[0] << ", " << coords[1] << ", " << coords[2] << ")" << std::endl; return FAR_FROM_TARGET; } // check if vertex is at destired location const double EPS = 5e-2; // allow a little leway if (fabs(coords[0] - expect[0]) > EPS * input_params.w || fabs(coords[1] - expect[1]) > EPS * input_params.h || fabs(expect[2] ) > EPS ) { std::cerr << "Vertex not at optimimal location" << std::endl << " Expected: (" << expect[0] << ", " << expect[1] << ", " << expect[2] << ")" << std::endl << " Actual: (" << coords[0] << ", " << coords[1] << ", " << coords[2] << ")" << std::endl; return NOT_AT_TARGET; } return 0; }
double run( QualityMetric* metric, Solver solver_type, const char* input_file, double& seconds_out, int& iterations_out ) { MsqPrintError err(cerr); IdealWeightInverseMeanRatio qa_metric; TerminationCriterion inner, outer; outer.add_iteration_limit( 1 ); inner.add_absolute_vertex_movement( 1e-4 ); inner.add_iteration_limit( 100 ); PMeanPTemplate of( 1.0, metric ); QualityAssessor qa( &qa_metric ); qa.add_quality_assessment( metric ); InstructionQueue q; SteepestDescent steep(&of); QuasiNewton quasi(&of); ConjugateGradient conj(&of); VertexMover* solver = 0; switch (solver_type) { case STEEP_DESCENT: solver = &steep; break; case QUASI_NEWT:solver = &quasi;break; case CONJ_GRAD: solver = &conj; break; } q.set_master_quality_improver( solver, err ); q.add_quality_assessor( &qa, err ); solver->set_inner_termination_criterion(&inner); solver->set_outer_termination_criterion(&outer); if (plot_file) inner.write_iterations( plot_file, err ); MeshImpl mesh; mesh.read_vtk( input_file, err ); if (err) { cerr << "Failed to read input file: \"" << input_file << '"' << endl; exit(1); } std::vector<Mesh::VertexHandle> handles; mesh.get_all_vertices( handles, err ); if (handles.empty()) { cerr << "no veritces in mesh" << endl; exit(1); } std::vector<MsqVertex> coords(handles.size()); mesh.vertices_get_coordinates( arrptr(handles), arrptr(coords), handles.size(), err ); Vector3D min(HUGE_VAL), max(-HUGE_VAL); for (size_t i = 0; i < coords.size(); ++i) { for (int j = 0; j < 3; ++j) { if (coords[i][j] < min[j]) min[j] = coords[i][j]; if (coords[i][j] > max[j]) max[j] = coords[i][j]; } } Vector3D size = max - min; PlanarDomain* domain = 0; if (size[0] < 1e-4) domain = new PlanarDomain( PlanarDomain::YZ, min[0] ); else if (size[1] < 1e-4) domain = new PlanarDomain( PlanarDomain::XZ, min[1] ); else if (size[2] < 1e-4) domain = new PlanarDomain( PlanarDomain::XY, min[2] ); Timer timer; q.run_instructions( &mesh, domain, err ); seconds_out = timer.since_birth(); if (err) { cerr << "Optimization failed." << endl << err << endl; abort(); } if (vtk_file) { MeshWriter::write_vtk( &mesh, vtk_file, err ); if (err) cerr << vtk_file << ": failed to write file." << endl; } if (gpt_file) { MeshWriter::write_gnuplot( &mesh, gpt_file, err ); if (err) cerr << gpt_file << ": failed to write file." << endl; } if (eps_file) { PlanarDomain xy(PlanarDomain::XY); MeshWriter::Projection proj( domain ? domain : &xy ); MeshWriter::write_eps( &mesh, eps_file, proj, err ); if (err) cerr << eps_file << ": failed to write file." << endl; } delete domain; iterations_out = inner.get_iteration_count(); const QualityAssessor::Assessor* a = qa.get_results( &qa_metric ); return a->get_average(); }