bool PatchPowerMeanP::initialize_block_coordinate_descent( Mesh* mesh, MeshDomain* domain, const Settings* settings, PatchSet* patch_set, MsqError& err ) { clear(); PatchIterator patches( patch_set ); PatchData pd; pd.set_mesh( mesh ); pd.set_domain( domain ); if (settings) pd.attach_settings(settings); bool result = true; while (patches.get_next_patch( pd, err ) && !MSQ_CHKERR(err)) { double value; bool b = evaluate( ObjectiveFunction::ACCUMULATE, pd, value, false, err ); MSQ_ERRZERO(err); result = result && b; } return result; }
void write_gnuplot( Mesh* mesh, const char* out_filebase, MsqError &err) { // loads a global patch PatchData pd; pd.set_mesh( mesh ); pd.fill_global_patch( err ); MSQ_ERRRTN(err); write_gnuplot( pd, out_filebase, err ); }
int check_global_patch_slaved( Mesh& mesh, MsqError& err ) { Settings s; s.set_slaved_ho_node_mode( Settings::SLAVE_FLAG ); MeshDomainAssoc mesh_and_domain = MeshDomainAssoc(&mesh, 0); Instruction::initialize_vertex_byte( &mesh_and_domain, &s, err ); MSQ_ERRZERO(err); PatchData pd; pd.attach_settings( &s ); pd.set_mesh( &mesh ); pd.fill_global_patch( err ); MSQ_ERRZERO(err); std::vector<bool> fixed, slaved; mesh.vertices_get_fixed_flag( pd.get_vertex_handles_array(), fixed, pd.num_nodes(), err ); MSQ_ERRZERO(err); mesh.vertices_get_slaved_flag( pd.get_vertex_handles_array(), slaved, pd.num_nodes(), err ); MSQ_ERRZERO(err); const size_t first_free = 0; const size_t first_slaved = pd.num_free_vertices(); const size_t first_fixed = pd.num_free_vertices() + pd.num_slave_vertices(); int error_count = 0; for (size_t i = first_free; i < first_slaved; ++i) { if (fixed[i]) { std::cerr << "Vertex " << (size_t)pd.get_vertex_handles_array()[i] << " is fixed in mesh but free in PatchData" << std::endl; ++error_count; } if (slaved[i]) { std::cerr << "Vertex " << (size_t)pd.get_vertex_handles_array()[i] << " is slaved in mesh but free in PatchData" << std::endl; ++error_count; } } for (size_t i = first_slaved; i < first_fixed; ++i) { if (fixed[i]) { std::cerr << "Vertex " << (size_t)pd.get_vertex_handles_array()[i] << " is fixed in mesh but slaved in PatchData" << std::endl; ++error_count; } else if (!slaved[i]) { std::cerr << "Vertex " << (size_t)pd.get_vertex_handles_array()[i] << " is free in Mesh but slaved in PatchData" << std::endl; ++error_count; } } for (size_t i = first_fixed; i < pd.num_nodes(); ++i) { if (!fixed[i]) { std::cerr << "Vertex " << (size_t)pd.get_vertex_handles_array()[i] << " is not fixed in mesh but is in PatchData" << std::endl; ++error_count; } } return 0 == error_count; }
void write_gnuplot( Mesh* mesh, std::vector<Mesh::ElementHandle>& elems, const char* out_filebase, MsqError &err) { // loads a global patch PatchData pd; pd.set_mesh( mesh ); std::vector<Mesh::VertexHandle> verts; pd.set_mesh_entities( elems, verts, err ); MSQ_ERRRTN(err); write_gnuplot( pd, out_filebase, err ); }
void write_svg( Mesh* mesh, const char* filename, Projection proj, MsqError& err ) { // Get a global patch PatchData pd; pd.set_mesh( mesh ); pd.fill_global_patch( err ); MSQ_ERRRTN(err); Transform2D transf( &pd, proj, 400, 400, true ); // Open the file ofstream file(filename); if (!file) { MSQ_SETERR(err)(MsqError::FILE_ACCESS); return; } // Write header file << "<?xml version=\"1.0\" standalone=\"no\"?>" << endl; file << "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" " << "\"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">" << endl; file << endl; file << "<svg width=\"" << transf.max_horizontal() << "\" height=\"" << transf.max_vertical() << "\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\">" << endl; // Write mesh edges EdgeIterator iter( &pd, err ); MSQ_ERRRTN(err); while( !iter.is_at_end() ) { int s_w, s_h, e_w, e_h; transf.transform( iter.start(), s_w, s_h ); transf.transform( iter.end (), e_w, e_h ); file << "<line " << "x1=\"" << s_w << "\" " << "y1=\"" << s_h << "\" " << "x2=\"" << e_w << "\" " << "y2=\"" << e_h << "\" " << " style=\"stroke:rgb(99,99,99);stroke-width:2\"" << "/>" << endl; iter.step( err ); MSQ_ERRRTN(err); } // Write footer file << "</svg>" << endl; }
bool ObjectiveFunctionTemplate::initialize_block_coordinate_descent( Mesh* mesh, MeshDomain* domain, const Settings* settings, PatchSet* , MsqError& err ) { std::auto_ptr<PatchSet> patch_set; switch (get_quality_metric()->get_metric_type()) { case QualityMetric::VERTEX_BASED: patch_set = std::auto_ptr<PatchSet>(new VertexPatches( 1, false )); break; case QualityMetric::ELEMENT_BASED: patch_set = std::auto_ptr<PatchSet>(new ElementPatches); break; default: MSQ_SETERR(err)("Cannot initialize for BCD for unknown metric type", MsqError::INVALID_STATE); return false; } clear(); patch_set->set_mesh( mesh ); PatchIterator patches( patch_set.get() ); PatchData pd; pd.set_mesh( mesh ); pd.set_domain( domain ); if (settings) pd.attach_settings( settings ); bool result = true; while (patches.get_next_patch( pd, err ) && !MSQ_CHKERR(err)) { double value; bool b = evaluate( ObjectiveFunction::ACCUMULATE, pd, value, false, err ); MSQ_ERRZERO(err); result = result && b; } return result; }
void tag_patch_slaved( Mesh& mesh, Settings::HigherOrderSlaveMode mode, MsqError& err ) { int zero = 0; TagHandle tag = mesh.tag_create( "pd_slaved", Mesh::INT, 1, &zero, err ); MSQ_ERRRTN(err); Settings s; s.set_slaved_ho_node_mode( mode ); PatchData pd; pd.attach_settings( &s ); pd.set_mesh( &mesh ); pd.fill_global_patch( err ); MSQ_ERRRTN(err); const Mesh::VertexHandle* verts = pd.get_vertex_handles_array() + pd.num_free_vertices(); std::vector<int> ones( pd.num_slave_vertices(), 1 ); mesh.tag_set_vertex_data( tag, pd.num_slave_vertices(), verts, arrptr(ones), err ); MSQ_ERRRTN(err); }
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()); }
/*!This function is activated when cullingGlobalPatch is true. It supplies cull_vertices with a single vertex-based patch at a time. If the patch satisfies the culling criterion, it's free vertices are then soft-fixed. */ bool TerminationCriterion::cull_vertices_global(PatchData &global_patch, Mesh *mesh, MeshDomain *domain, const Settings *settings, OFEvaluator& of_eval, MsqError &err) { if (!cullingGlobalPatch) return false; //PRINT_INFO("CULLING_METHOD FLAG = %i",cullingMethodFlag); //cull_bool will be changed to true if the criterion is satisfied bool cull_bool=false; std::vector<Mesh::VertexHandle> mesh_vertices; //std::vector<Mesh::VertexHandle> patch_vertices; //std::vector<Mesh::ElementHandle> patch_elements; //std::vector<Mesh::VertexHandle> fixed_vertices; //std::vector<Mesh::VertexHandle> free_vertices; // FIXME, verify global_patch is a global patch... how, is this right? mesh->get_all_vertices(mesh_vertices, err); size_t mesh_num_nodes = mesh_vertices.size(); size_t global_patch_num_nodes = global_patch.num_nodes() ; if (0) std::cout << "tmp srk mesh_num_nodes= " << mesh_num_nodes << " global_patch_num_nodes= " << global_patch_num_nodes << std::endl; if (mesh_num_nodes != global_patch_num_nodes) { std::cout << "tmp srk cull_vertices_global found non global patch" << std::endl; exit(123); return false; } PatchData patch; patch.set_mesh( (Mesh*) mesh ); patch.set_domain( domain ); patch.attach_settings( settings ); const MsqVertex* global_patch_vertex_array = global_patch.get_vertex_array( err ); Mesh::VertexHandle* global_patch_vertex_handles = global_patch.get_vertex_handles_array(); int num_culled = 0; for (unsigned iv=0; iv < global_patch_num_nodes; iv++) { // form a patch for this vertex; if it is culled, set it to be soft fixed Mesh::VertexHandle vert = global_patch_vertex_handles[iv]; std::vector<Mesh::ElementHandle> elements; std::vector<size_t> offsets; mesh->vertices_get_attached_elements(&vert, 1, elements, offsets, err); std::set<Mesh::VertexHandle> patch_free_vertices_set; for (unsigned ie=0; ie < elements.size(); ie++) { std::vector<Mesh::VertexHandle> vert_handles; std::vector<size_t> v_offsets; mesh->elements_get_attached_vertices(&elements[ie], 1, vert_handles, v_offsets, err); for (unsigned jv=0; jv < vert_handles.size(); jv++) { unsigned char bt; mesh->vertex_get_byte(vert_handles[jv], &bt, err); MsqVertex v; v.set_flags(bt); if (v.is_free_vertex()) patch_free_vertices_set.insert(vert_handles[jv]); } } std::vector<Mesh::VertexHandle> patch_free_vertices_vector(patch_free_vertices_set.begin(), patch_free_vertices_set.end()); //std::vector<unsigned char> byte_vector(patch_vertices_vector.size()); //mesh->vertices_get_byte(&vert_handles[0], &byte_vector[0], vert_handles.size(), err); patch.set_mesh_entities( elements, patch_free_vertices_vector, err ); if (cull_vertices(patch, of_eval, err)) { //std::cout << "tmp srk cull_vertices_global found culled patch" << std::endl; Mesh::VertexHandle* patch_vertex_handles = patch.get_vertex_handles_array(); const MsqVertex* patch_vertex_array = patch.get_vertex_array( err ); for (unsigned jv=0; jv < patch.num_nodes(); jv++) { if (patch_vertex_handles[jv] == global_patch_vertex_handles[iv]) { if (patch_vertex_array[jv].is_flag_set(MsqVertex::MSQ_CULLED)) { global_patch.set_vertex_culled(iv); ++num_culled; cull_bool = true; //std::cout << "tmp srk cull_vertices_global found culled vertex" << std::endl; } } } } } if (0) std::cout << "tmp srk cull_vertices_global found " << num_culled << " culled vertices out of " << global_patch_num_nodes << std::endl; return cull_bool; }
void write_eps( Mesh* mesh, const char* filename, Projection proj, MsqError& err, int width, int height ) { // Get a global patch PatchData pd; pd.set_mesh( mesh ); pd.fill_global_patch( err ); MSQ_ERRRTN(err); Transform2D transf( &pd, proj, width, height, false ); // Open the file ofstream s(filename); if (!s) { MSQ_SETERR(err)(MsqError::FILE_ACCESS); return; } // Write header s << "%!PS-Adobe-2.0 EPSF-2.0" << endl; s << "%%Creator: Mesquite" << endl; s << "%%Title: Mesquite " << endl; s << "%%DocumentData: Clean7Bit" << endl; s << "%%Origin: 0 0" << endl; s << "%%BoundingBox: 0 0 " << transf.max_horizontal() << ' ' << transf.max_vertical() << endl; s << "%%Pages: 1" << endl; s << "%%BeginProlog" << endl; s << "save" << endl; s << "countdictstack" << endl; s << "mark" << endl; s << "newpath" << endl; s << "/showpage {} def" << endl; s << "/setpagedevice {pop} def" << endl; s << "%%EndProlog" << endl; s << "%%Page: 1 1" << endl; s << "1 setlinewidth" << endl; s << "0.0 setgray" << endl; // Write mesh edges EdgeIterator iter( &pd, err ); MSQ_ERRRTN(err); while( !iter.is_at_end() ) { int s_w, s_h, e_w, e_h; transf.transform( iter.start(), s_w, s_h ); transf.transform( iter.end (), e_w, e_h ); s << "newpath" << endl; s << s_w << ' ' << s_h << " moveto" << endl; if (!iter.mid()) { s << e_w << ' ' << e_h << " lineto" << endl; } else { write_eps_quadratic_edge( s, transf, iter.start(), *iter.mid(), iter.end() ); // draw rings at mid-edge node location //transf.transform( *(iter.mid()), w1, h1 ); //s << w1+2 << ' ' << h1 << " moveto" << endl; //s << w1 << ' ' << h1 << " 2 0 360 arc" << endl; } s << "stroke" << endl; iter.step(err); MSQ_ERRRTN(err); } // Write footer s << "%%Trailer" << endl; s << "cleartomark" << endl; s << "countdictstack" << endl; s << "exch sub { end } repeat" << endl; s << "restore" << endl; s << "%%EOF" << endl; }
/*! \brief Improves the quality of the MeshSet, calling some methods specified in a class derived from VertexMover \param const MeshSet &: this MeshSet is looped over. Only the mutable data members are changed (such as currentVertexInd). */ double VertexMover::loop_over_mesh( ParallelMesh* mesh, MeshDomain* domain, const Settings* settings, MsqError& err ) { std::vector<size_t> junk; Mesh::VertexHandle vertex_handle; // Get the patch data to use for the first iteration OFEvaluator& obj_func = get_objective_function_evaluator(); PatchData patch; patch.set_mesh( (Mesh*) mesh ); patch.set_domain( domain ); patch.attach_settings( settings ); ParallelHelper* helper = mesh->get_parallel_helper(); if (!helper) { MSQ_SETERR(err)("No ParallelHelper instance", MsqError::INVALID_STATE); return 0; } helper->smoothing_init(err); MSQ_ERRZERO(err); bool did_some, all_culled; std::vector<Mesh::VertexHandle> patch_vertices; std::vector<Mesh::ElementHandle> patch_elements; std::vector<Mesh::VertexHandle> fixed_vertices; std::vector<Mesh::VertexHandle> free_vertices; // Get termination criteria TerminationCriterion* outer_crit=this->get_outer_termination_criterion(); TerminationCriterion* inner_crit=this->get_inner_termination_criterion(); if(outer_crit == 0){ MSQ_SETERR(err)("Termination Criterion pointer is Null", MsqError::INVALID_STATE); return 0.; } if(inner_crit == 0){ MSQ_SETERR(err)("Termination Criterion pointer for inner loop is Null", MsqError::INVALID_STATE); return 0.; } PatchSet* patch_set = get_patch_set(); if (!patch_set) { MSQ_SETERR(err)("No PatchSet for QualityImprover!", MsqError::INVALID_STATE); return 0.0; } patch_set->set_mesh( (Mesh*)mesh ); std::vector<PatchSet::PatchHandle> patch_list; patch_set->get_patch_handles( patch_list, err ); MSQ_ERRZERO(err); // Initialize outer loop this->initialize(patch, err); if (MSQ_CHKERR(err)) goto ERROR; obj_func.initialize( (Mesh*)mesh, domain, settings, patch_set, err ); if (MSQ_CHKERR(err)) goto ERROR; outer_crit->reset_outer( (Mesh*)mesh, domain, obj_func, settings, err); if (MSQ_CHKERR(err)) goto ERROR; // Loop until outer termination criterion is met did_some = true; while (!outer_crit->terminate()) { if (!did_some) { MSQ_SETERR(err)("Inner termiation criterion satisfied for all patches " "without meeting outer termination criterion. This is " "an infinite loop. Aborting.", MsqError::INVALID_STATE); break; } did_some = false; all_culled = true; ///*** smooth the interior ***//// // get the fixed vertices (i.e. the ones *not* part of the first independent set) helper->compute_first_independent_set(fixed_vertices); // sort the fixed vertices std::sort(fixed_vertices.begin(), fixed_vertices.end()); // Loop over each patch std::vector<PatchSet::PatchHandle>::iterator p_iter = patch_list.begin(); while( p_iter != patch_list.end() ) { // loop until we get a non-empty patch. patch will be empty // for culled vertices with element-on-vertex patches do { patch_set->get_patch( *p_iter, patch_elements, patch_vertices, err ); if (MSQ_CHKERR(err)) goto ERROR; ++p_iter; } while (patch_elements.empty() && p_iter != patch_list.end()) ; if (patch_elements.empty()) { // no more non-culled vertices break; } if (patch_vertices.empty()) // global patch hack (means all mesh vertices) { mesh->get_all_vertices(patch_vertices, err); } free_vertices.clear(); for (size_t i = 0; i < patch_vertices.size(); ++i) if (!std::binary_search(fixed_vertices.begin(), fixed_vertices.end(), patch_vertices[i])) free_vertices.push_back(patch_vertices[i]); if (free_vertices.empty()) { // all vertices were fixed -> skip patch continue; } all_culled = false; patch.set_mesh_entities( patch_elements, free_vertices, err ); if (MSQ_CHKERR(err)) goto ERROR; // Initialize for inner iteration this->initialize_mesh_iteration(patch, err); if (MSQ_CHKERR(err)) goto ERROR; obj_func.reset(); outer_crit->reset_patch( patch, err ); if (MSQ_CHKERR(err)) goto ERROR; inner_crit->reset_inner( patch, obj_func, err ); if (MSQ_CHKERR(err)) goto ERROR; inner_crit->reset_patch( patch, err ); if (MSQ_CHKERR(err)) goto ERROR; // Don't even call optimizer if inner termination // criterion has already been met. if (!inner_crit->terminate()) { did_some = true; // Call optimizer - should loop on inner_crit->terminate() this->optimize_vertex_positions( patch, err ); if (MSQ_CHKERR(err)) goto ERROR; // Update for changes during inner iteration // (during optimizer loop) outer_crit->accumulate_patch( patch, err ); if (MSQ_CHKERR(err)) goto ERROR; inner_crit->cull_vertices( patch, obj_func, err ); if (MSQ_CHKERR(err)) goto ERROR; patch.update_mesh( err ); if (MSQ_CHKERR(err)) goto ERROR; } } helper->communicate_first_independent_set(err); if (MSQ_CHKERR(err)) goto ERROR; ///*** smooth the boundary ***//// while (helper->compute_next_independent_set()) { // Loop over all boundary elements while(helper->get_next_partition_boundary_vertex(vertex_handle)) { patch_vertices.clear(); patch_vertices.push_back(vertex_handle); patch_elements.clear(); mesh->vertices_get_attached_elements( &vertex_handle, 1, patch_elements, junk, err ); all_culled = false; patch.set_mesh_entities( patch_elements, patch_vertices, err ); if (MSQ_CHKERR(err)) goto ERROR; // Initialize for inner iteration this->initialize_mesh_iteration(patch, err); if (MSQ_CHKERR(err)) goto ERROR; obj_func.reset(); outer_crit->reset_patch( patch, err ); if (MSQ_CHKERR(err)) goto ERROR; inner_crit->reset_inner( patch, obj_func, err ); if (MSQ_CHKERR(err)) goto ERROR; inner_crit->reset_patch( patch, err ); if (MSQ_CHKERR(err)) goto ERROR; // Don't even call optimizer if inner termination // criterion has already been met. if (!inner_crit->terminate()) { did_some = true; // Call optimizer - should loop on inner_crit->terminate() this->optimize_vertex_positions( patch, err ); if (MSQ_CHKERR(err)) goto ERROR; // Update for changes during inner iteration // (during optimizer loop) outer_crit->accumulate_patch( patch, err ); if (MSQ_CHKERR(err)) goto ERROR; inner_crit->cull_vertices( patch, obj_func, err ); if (MSQ_CHKERR(err)) goto ERROR; patch.update_mesh( err ); if (MSQ_CHKERR(err)) goto ERROR; } } helper->communicate_next_independent_set(err); if (MSQ_CHKERR(err)) goto ERROR; } this->terminate_mesh_iteration(patch, err); if (MSQ_CHKERR(err)) goto ERROR; outer_crit->accumulate_outer( mesh, domain, obj_func, settings, err ); if (MSQ_CHKERR(err)) goto ERROR; if (all_culled) break; } ERROR: //call the criteria's cleanup funtions. outer_crit->cleanup(mesh,domain,err); MSQ_CHKERR(err); inner_crit->cleanup(mesh,domain,err); MSQ_CHKERR(err); //call the optimization cleanup function. this->cleanup(); // close the helper helper->smoothing_close(err); MSQ_CHKERR(err); return 0.; }
/*! \brief Improves the quality of the MeshSet, calling some methods specified in a class derived from VertexMover \param const MeshSet &: this MeshSet is looped over. Only the mutable data members are changed (such as currentVertexInd). */ double VertexMover::loop_over_mesh( Mesh* mesh, MeshDomain* domain, const Settings* settings, MsqError& err ) { // Get the patch data to use for the first iteration OFEvaluator& obj_func = get_objective_function_evaluator(); PatchData patch; patch.set_mesh( mesh ); patch.set_domain( domain ); if (settings) patch.attach_settings( settings ); bool one_patch = false, did_some, all_culled; std::vector<Mesh::VertexHandle> patch_vertices; std::vector<Mesh::ElementHandle> patch_elements; PatchSet* patch_set = get_patch_set(); if (!patch_set) { MSQ_SETERR(err)("No PatchSet for QualityImprover!", MsqError::INVALID_STATE); return 0.0; } patch_set->set_mesh( mesh ); std::vector<PatchSet::PatchHandle> patch_list; patch_set->get_patch_handles( patch_list, err ); MSQ_ERRZERO(err); // Get termination criteria TerminationCriterion* outer_crit=this->get_outer_termination_criterion(); TerminationCriterion* inner_crit=this->get_inner_termination_criterion(); if(outer_crit == 0){ MSQ_SETERR(err)("Termination Criterion pointer is Null", MsqError::INVALID_STATE); return 0.; } if(inner_crit == 0){ MSQ_SETERR(err)("Termination Criterion pointer for inner loop is Null", MsqError::INVALID_STATE); return 0.; } // If using a local patch, suppress output of inner termination criterion if (patch_list.size() > 1) inner_crit->set_debug_output_level(3); else one_patch = true; // Initialize outer loop this->initialize(patch, err); if (MSQ_CHKERR(err)) goto ERROR; obj_func.initialize( mesh, domain, settings, patch_set, err ); if (MSQ_CHKERR(err)) goto ERROR; outer_crit->reset_outer(mesh, domain, obj_func, settings, err); if (MSQ_CHKERR(err)) goto ERROR; // if only one patch, get the patch now if (one_patch) { patch_set->get_patch( patch_list[0], patch_elements, patch_vertices, err ); if (MSQ_CHKERR(err)) goto ERROR; patch.set_mesh_entities( patch_elements, patch_vertices, err ); if (MSQ_CHKERR(err)) goto ERROR; } // Loop until outer termination criterion is met did_some = true; while (!outer_crit->terminate()) { if (!did_some) { MSQ_SETERR(err)("Inner termiation criterion satisfied for all patches " "without meeting outer termination criterion. This is " "an infinite loop. Aborting.", MsqError::INVALID_STATE); break; } did_some = false; all_culled = true; // Loop over each patch std::vector<PatchSet::PatchHandle>::iterator p_iter = patch_list.begin(); while( p_iter != patch_list.end() ) { if (!one_patch) { // if only one patch (global) re-use the previous one // loop until we get a non-empty patch. patch will be empty // for culled vertices with element-on-vertex patches do { patch_set->get_patch( *p_iter, patch_elements, patch_vertices, err ); if (MSQ_CHKERR(err)) goto ERROR; ++p_iter; } while (patch_elements.empty() && p_iter != patch_list.end()) ; if (patch_elements.empty()) { // no more non-culled vertices break; } all_culled = false; patch.set_mesh_entities( patch_elements, patch_vertices, err ); if (MSQ_CHKERR(err)) goto ERROR; } else { ++p_iter; all_culled = false; } // Initialize for inner iteration this->initialize_mesh_iteration(patch, err); if (MSQ_CHKERR(err)) goto ERROR; obj_func.reset(); outer_crit->reset_patch( patch, err ); if (MSQ_CHKERR(err)) goto ERROR; inner_crit->reset_inner( patch, obj_func, err ); if (MSQ_CHKERR(err)) goto ERROR; inner_crit->reset_patch( patch, err ); if (MSQ_CHKERR(err)) goto ERROR; // Don't even call optimizer if inner termination // criterion has already been met. if (!inner_crit->terminate()) { did_some = true; // Call optimizer - should loop on inner_crit->terminate() this->optimize_vertex_positions( patch, err ); if (MSQ_CHKERR(err)) goto ERROR; // Update for changes during inner iteration // (during optimizer loop) outer_crit->accumulate_patch( patch, err ); if (MSQ_CHKERR(err)) goto ERROR; inner_crit->cull_vertices( patch, obj_func, err ); if (MSQ_CHKERR(err)) goto ERROR; patch.update_mesh( err ); if (MSQ_CHKERR(err)) goto ERROR; } } this->terminate_mesh_iteration(patch, err); if (MSQ_CHKERR(err)) goto ERROR; outer_crit->accumulate_outer( mesh, domain, obj_func, settings, err ); if (MSQ_CHKERR(err)) goto ERROR; if (all_culled) break; } ERROR: //call the criteria's cleanup funtions. outer_crit->cleanup(mesh,domain,err); inner_crit->cleanup(mesh,domain,err); //call the optimization cleanup function. this->cleanup(); return 0.; }
double TargetWriter::loop_over_mesh( MeshDomainAssoc* mesh_and_domain, const Settings* settings, MsqError& err ) { Mesh* mesh = mesh_and_domain->get_mesh(); MeshDomain* domain = mesh_and_domain->get_domain(); PatchData patch; patch.set_mesh( mesh ); patch.set_domain( domain ); if (settings) patch.attach_settings( settings ); ElementPatches patch_set; patch_set.set_mesh( mesh ); std::vector<PatchSet::PatchHandle> patches; std::vector<PatchSet::PatchHandle>::iterator p; std::vector<Mesh::VertexHandle> patch_verts; std::vector<Mesh::ElementHandle> patch_elems; patch_set.get_patch_handles( patches, err ); MSQ_ERRZERO(err); std::vector< MsqMatrix<3,3> > targets3d; std::vector< MsqMatrix<3,2> > targets2dorient; std::vector< MsqMatrix<2,2> > targets2d; std::vector< double > weights; std::vector< Sample > samples; for (p = patches.begin(); p != patches.end(); ++p) { patch_verts.clear(); patch_elems.clear(); patch_set.get_patch( *p, patch_elems, patch_verts, err ); MSQ_ERRZERO(err); patch.set_mesh_entities( patch_elems, patch_verts, err ); MSQ_ERRZERO(err); assert(patch.num_elements() == 1); MsqMeshEntity& elem = patch.element_by_index(0); EntityTopology type = elem.get_element_type(); patch.get_samples( 0, samples, err ); MSQ_ERRZERO(err); if (samples.empty()) continue; if (targetCalc) { const unsigned dim = TopologyInfo::dimension(type); if (dim == 3) { targets3d.resize( samples.size() ); for (unsigned i = 0; i < samples.size(); ++i) { targetCalc->get_3D_target( patch, 0, samples[i], targets3d[i], err ); MSQ_ERRZERO(err); if (DBL_EPSILON > det(targets3d[i])) { MSQ_SETERR(err)("Inverted 3D target", MsqError::INVALID_ARG); return 0.0; } } TagHandle tag = get_target_tag( 3, samples.size(), mesh, err ); MSQ_ERRZERO(err); mesh->tag_set_element_data( tag, 1, patch.get_element_handles_array(), arrptr(targets3d), err ); MSQ_ERRZERO(err); } else if(targetCalc->have_surface_orient()) { targets2dorient.resize( samples.size() ); for (unsigned i = 0; i < samples.size(); ++i) { targetCalc->get_surface_target( patch, 0, samples[i], targets2dorient[i], err ); MSQ_ERRZERO(err); MsqMatrix<3,1> cross = targets2dorient[i].column(0) * targets2dorient[i].column(1); if (DBL_EPSILON > (cross%cross)) { MSQ_SETERR(err)("Degenerate 2D target", MsqError::INVALID_ARG); return 0.0; } } TagHandle tag = get_target_tag( 2, samples.size(), mesh, err ); MSQ_ERRZERO(err); mesh->tag_set_element_data( tag, 1, patch.get_element_handles_array(), arrptr(targets2dorient), err ); MSQ_ERRZERO(err); } else { targets2d.resize( samples.size() ); for (unsigned i = 0; i < samples.size(); ++i) { targetCalc->get_2D_target( patch, 0, samples[i], targets2d[i], err ); MSQ_ERRZERO(err); if (DBL_EPSILON > det(targets2d[i])) { MSQ_SETERR(err)("Degenerate/Inverted 2D target", MsqError::INVALID_ARG); return 0.0; } } TagHandle tag = get_target_tag( 2, samples.size(), mesh, err ); MSQ_ERRZERO(err); mesh->tag_set_element_data( tag, 1, patch.get_element_handles_array(), arrptr(targets2d), err ); MSQ_ERRZERO(err); } } if (weightCalc) { weights.resize( samples.size() ); for (unsigned i = 0; i < samples.size(); ++i) { weights[i] = weightCalc->get_weight( patch, 0, samples[i], err ); MSQ_ERRZERO(err); } TagHandle tag = get_weight_tag( samples.size(), mesh, err ); MSQ_ERRZERO(err); mesh->tag_set_element_data( tag, 1, patch.get_element_handles_array(), arrptr(weights), err ); MSQ_ERRZERO(err); } } return 0.0; }