MOAB: Mesh Oriented datABase
(version 5.4.1)
|
#include <VertexMover.hpp>
Public Member Functions | |
virtual | ~VertexMover () |
virtual void | initialize_queue (MeshDomainAssoc *mesh_and_domain, const Settings *settings, MsqError &err) |
virtual double | loop_over_mesh (MeshDomainAssoc *mesh_and_domain, const Settings *settings, MsqError &err) |
Improves the quality of the MeshSet, calling some methods specified in a class derived from VertexMover. | |
virtual double | loop_over_mesh (ParallelMesh *mesh, MeshDomain *domain, const Settings *settings, MsqError &err) |
Improves the quality of the MeshSet, calling some methods specified in a class derived from VertexMover. | |
void | do_nash_game_optimization () |
Do Nash-game type optimization. | |
bool | is_nash_game_optimization () const |
Check if optmizer will do Nash-game type optimization. | |
void | do_block_coordinate_descent_optimization () |
Do block coordinate descent optimization. | |
bool | is_block_coordinate_descent_optimization () const |
Check if optmizer will do block coordinate descent type optimization. | |
void | do_jacobi_optimization () |
Use Jacobi iteration for optimization. | |
bool | is_jacobi_optimization () const |
Check if optimization will use Jacobi iteration. | |
void | do_gauss_optimization () |
Use Gauss-Seidel iteration for optimization. | |
bool | is_gauss_optimization () const |
Check if optimization will use Gauss-Seidel iteration. | |
Protected Member Functions | |
VertexMover (ObjectiveFunction *OF=NULL) | |
virtual void | initialize (PatchData &pd, MsqError &err)=0 |
virtual void | cleanup ()=0 |
virtual void | optimize_vertex_positions (PatchData &pd, MsqError &err)=0 |
virtual void | initialize_mesh_iteration (PatchData &pd, MsqError &err)=0 |
virtual void | terminate_mesh_iteration (PatchData &, MsqError &err)=0 |
OFEvaluator & | get_objective_function_evaluator () |
Static Protected Member Functions | |
static TagHandle | get_jacobi_coord_tag (Mesh *mesh, MsqError &err) |
static void | commit_jacobi_coords (TagHandle tag, Mesh *mesh, MsqError &err) |
Private Attributes | |
OFEvaluator | objFuncEval |
bool | jacobiOpt |
Base class for all Vertex Movers.
Definition at line 55 of file VertexMover.hpp.
MBMesquite::VertexMover::VertexMover | ( | ObjectiveFunction * | OF = NULL | ) | [protected] |
Definition at line 63 of file VertexMover.cpp.
: QualityImprover(), objFuncEval( OF ), jacobiOpt( false ) {}
MBMesquite::VertexMover::~VertexMover | ( | ) | [virtual] |
Definition at line 65 of file VertexMover.cpp.
{}
virtual void MBMesquite::VertexMover::cleanup | ( | ) | [protected, pure virtual] |
Implemented in TCTFauxOptimizer, MBMesquite::NonGradient, MBMesquite::NonSmoothDescent, MBMesquite::FeasibleNewton, MBMesquite::SteepestDescent, MBMesquite::ConjugateGradient, MBMesquite::Randomize, MBMesquite::QuasiNewton, MBMesquite::TrustRegion, UnOptimizer, MBMesquite::NullImprover, and MBMesquite::RelaxationSmoother.
Referenced by loop_over_mesh().
void MBMesquite::VertexMover::commit_jacobi_coords | ( | TagHandle | tag, |
Mesh * | mesh, | ||
MsqError & | err | ||
) | [static, protected] |
Definition at line 1120 of file VertexMover.cpp.
References fixed, MBMesquite::Mesh::get_all_vertices(), MSQ_ERRRTN, MBMesquite::Mesh::tag_get_vertex_data(), MBMesquite::Vector3D::to_array(), MBMesquite::Mesh::vertex_set_coordinates(), and MBMesquite::Mesh::vertices_get_fixed_flag().
Referenced by loop_over_mesh().
{ Vector3D coords; std::vector< Mesh::VertexHandle > vertices; mesh->get_all_vertices( vertices, err );MSQ_ERRRTN( err ); std::vector< bool > fixed( vertices.size() ); mesh->vertices_get_fixed_flag( &vertices[0], fixed, vertices.size(), err ); for( size_t i = 0; i < vertices.size(); ++i ) { if( !fixed[i] ) { mesh->tag_get_vertex_data( tag, 1, &vertices[i], coords.to_array(), err );MSQ_ERRRTN( err ); mesh->vertex_set_coordinates( vertices[i], coords, err );MSQ_ERRRTN( err ); } } }
void MBMesquite::VertexMover::do_block_coordinate_descent_optimization | ( | ) | [inline] |
Do block coordinate descent optimization.
Opposite of do_nash_game()
.
Definition at line 92 of file VertexMover.hpp.
Referenced by BCDTest::compare_bcd(), and run_global_smoother().
void MBMesquite::VertexMover::do_gauss_optimization | ( | ) | [inline] |
Use Gauss-Seidel iteration for optimization.
Default, opposite of do_jacobi_optimization()
Definition at line 128 of file VertexMover.hpp.
Referenced by MBMesquite::UntangleWrapper::run_wrapper().
{ jacobiOpt = false; }
void MBMesquite::VertexMover::do_jacobi_optimization | ( | ) | [inline] |
Use Jacobi iteration for optimization.
Opposite of do_gauss_optimization()
Definition at line 110 of file VertexMover.hpp.
Referenced by main(), run_quality_optimizer(), and MBMesquite::UntangleWrapper::run_wrapper().
{ jacobiOpt = true; }
void MBMesquite::VertexMover::do_nash_game_optimization | ( | ) | [inline] |
Do Nash-game type optimization.
Default, opposite of do_block_coordinate_descent()
.
Definition at line 74 of file VertexMover.hpp.
{ objFuncEval.do_nash_game(); }
TagHandle MBMesquite::VertexMover::get_jacobi_coord_tag | ( | Mesh * | mesh, |
MsqError & | err | ||
) | [static, protected] |
Definition at line 1057 of file VertexMover.cpp.
References MBMesquite::Mesh::DOUBLE, fixed, MBMesquite::Mesh::get_all_vertices(), MSQ_ERRZERO, MBMesquite::Mesh::tag_create(), MBMesquite::Mesh::tag_set_vertex_data(), tagname, MBMesquite::Mesh::vertices_get_coordinates(), and MBMesquite::Mesh::vertices_get_fixed_flag().
Referenced by loop_over_mesh().
{ // Get tag handle const char tagname[] = "msq_jacobi_temp_coords"; TagHandle tag = mesh->tag_create( tagname, Mesh::DOUBLE, 3, 0, err ); MSQ_ERRZERO( err ); /* VertexMover will always delete the tag when it is done, so it is probably best not to accept an existing tag if (err.error_code() == TAG_ALREADY_EXISTS) { err.clear(); tag = tag_get( tagname, err ); MSQ_ERRZERO(err); std::string name; Mesh::TagType type; unsigned length; mesh->tag_properties( tag, name, type, length, err ); MSQ_ERRZERO(err); if (type != Mesh::DOUBLE || length != 3) { MSQ_SETERR(err)(TAG_ALREADY_EXISTS, "Tag \"%s\" already exists with invalid type", tagname); return 0; } } */ // Initialize tag value with initial vertex coordinates so that // vertices that never get moved end up with the correct coords. std::vector< Mesh::VertexHandle > vertices; mesh->get_all_vertices( vertices, err ); MSQ_ERRZERO( err ); // remove fixed vertices // to avoid really huge arrays (especially since we need to copy // coords out of annoying MsqVertex class to double array), work // in blocks const size_t blocksize = 4096; std::vector< bool > fixed( blocksize ); MsqVertex coords[blocksize]; double tag_data[3 * blocksize]; for( size_t i = 0; i < vertices.size(); i += blocksize ) { size_t count = std::min( blocksize, vertices.size() - i ); // remove fixed vertices mesh->vertices_get_fixed_flag( &vertices[i], fixed, count, err ); MSQ_ERRZERO( err ); size_t w = 0; for( size_t j = 0; j < count; ++j ) if( !fixed[j] ) vertices[i + w++] = vertices[i + j]; count = w; // store tag data for free vertices mesh->vertices_get_coordinates( &vertices[i], coords, count, err ); MSQ_ERRZERO( err ); for( size_t j = 0; j < count; ++j ) { tag_data[3 * j] = coords[j][0]; tag_data[3 * j + 1] = coords[j][1]; tag_data[3 * j + 2] = coords[j][2]; } mesh->tag_set_vertex_data( tag, count, &vertices[i], tag_data, err ); MSQ_ERRZERO( err ); } return tag; }
OFEvaluator& MBMesquite::VertexMover::get_objective_function_evaluator | ( | ) | [inline, protected] |
Definition at line 151 of file VertexMover.hpp.
Referenced by MBMesquite::NonGradient::evaluate(), MBMesquite::ConjugateGradient::get_step(), loop_over_mesh(), MBMesquite::QuasiNewton::optimize_vertex_positions(), MBMesquite::TrustRegion::optimize_vertex_positions(), MBMesquite::ConjugateGradient::optimize_vertex_positions(), MBMesquite::SteepestDescent::optimize_vertex_positions(), and MBMesquite::FeasibleNewton::optimize_vertex_positions().
{ return objFuncEval; }
virtual void MBMesquite::VertexMover::initialize | ( | PatchData & | pd, |
MsqError & | err | ||
) | [protected, pure virtual] |
Implemented in TCTFauxOptimizer, MBMesquite::NonGradient, MBMesquite::NonSmoothDescent, MBMesquite::FeasibleNewton, MBMesquite::SteepestDescent, MBMesquite::ConjugateGradient, MBMesquite::Randomize, MBMesquite::QuasiNewton, MBMesquite::TrustRegion, MBMesquite::NullImprover, UnOptimizer, and MBMesquite::RelaxationSmoother.
Referenced by loop_over_mesh().
virtual void MBMesquite::VertexMover::initialize_mesh_iteration | ( | PatchData & | pd, |
MsqError & | err | ||
) | [protected, pure virtual] |
Implemented in TCTFauxOptimizer, MBMesquite::NonGradient, MBMesquite::NonSmoothDescent, MBMesquite::FeasibleNewton, MBMesquite::SteepestDescent, MBMesquite::ConjugateGradient, MBMesquite::Randomize, MBMesquite::QuasiNewton, MBMesquite::TrustRegion, MBMesquite::NullImprover, UnOptimizer, and MBMesquite::RelaxationSmoother.
Referenced by loop_over_mesh().
void MBMesquite::VertexMover::initialize_queue | ( | MeshDomainAssoc * | mesh_and_domain, |
const Settings * | settings, | ||
MsqError & | err | ||
) | [virtual] |
Called for all instructions in queue before loop_over_mesh is called for any insetruction in queue. Default behavior is to do nothing.
Reimplemented from MBMesquite::QualityImprover.
Definition at line 1051 of file VertexMover.cpp.
References MBMesquite::OFEvaluator::initialize_queue(), MSQ_ERRRTN, and objFuncEval.
{ QualityImprover::initialize_queue( mesh_and_domain, settings, err );MSQ_ERRRTN( err ); objFuncEval.initialize_queue( mesh_and_domain, settings, err );MSQ_ERRRTN( err ); }
bool MBMesquite::VertexMover::is_block_coordinate_descent_optimization | ( | ) | const [inline] |
Check if optmizer will do block coordinate descent type optimization.
Default, opposite of is_nash_game_optimization()
.
Definition at line 101 of file VertexMover.hpp.
{ return objFuncEval.is_block_coordinate_descent(); }
bool MBMesquite::VertexMover::is_gauss_optimization | ( | ) | const [inline] |
Check if optimization will use Gauss-Seidel iteration.
Default, opposite of is_jacobi_optimization()
Definition at line 137 of file VertexMover.hpp.
{ return !jacobiOpt; }
bool MBMesquite::VertexMover::is_jacobi_optimization | ( | ) | const [inline] |
Check if optimization will use Jacobi iteration.
Opposite of is_gauss_optimization()
Definition at line 119 of file VertexMover.hpp.
{ return jacobiOpt; }
bool MBMesquite::VertexMover::is_nash_game_optimization | ( | ) | const [inline] |
Check if optmizer will do Nash-game type optimization.
Default, opposite of is_block_coordinate_descent_optimization()
.
Definition at line 83 of file VertexMover.hpp.
{ return objFuncEval.is_nash_game(); }
double MBMesquite::VertexMover::loop_over_mesh | ( | MeshDomainAssoc * | mesh_and_domain, |
const Settings * | settings, | ||
MsqError & | err | ||
) | [virtual] |
Improves the quality of the MeshSet, calling some methods specified in a class derived from VertexMover.
const | MeshSet &: this MeshSet is looped over. Only the mutable data members are changed (such as currentVertexInd). |
Implements MBMesquite::Instruction.
Definition at line 129 of file VertexMover.cpp.
References MBMesquite::TerminationCriterion::accumulate_outer(), MBMesquite::TerminationCriterion::accumulate_patch(), MBMesquite::TerminationCriterion::add_iteration_limit(), MBMesquite::PatchData::attach_settings(), cleanup(), MBMesquite::TerminationCriterion::cleanup(), commit_jacobi_coords(), coord_tag, MBMesquite::TerminationCriterion::criterion_is_set(), MBMesquite::TerminationCriterion::cull_vertices(), MBMesquite::TerminationCriterion::cull_vertices_global(), ERROR, MBMesquite::TMPQualityMetric::evaluate(), MBMesquite::MeshDomainAssoc::get_domain(), MBMesquite::QualityMetric::get_evaluations(), MBMesquite::QualityImprover::get_inner_termination_criterion(), get_jacobi_coord_tag(), MBMesquite::MeshDomainAssoc::get_mesh(), MBMesquite::OFEvaluator::get_objective_function(), get_objective_function_evaluator(), MBMesquite::QualityImprover::get_outer_termination_criterion(), MBMesquite::get_parallel_rank(), MBMesquite::PatchSet::get_patch(), MBMesquite::PatchSet::get_patch_handles(), MBMesquite::QualityImprover::get_patch_set(), MBMesquite::ElementAvgQM::get_quality_metric(), MBMesquite::ElementMaxQM::get_quality_metric(), MBMesquite::ElementPMeanP::get_quality_metric(), MBMesquite::ObjectiveFunctionTemplate::get_quality_metric(), MBMesquite::TQualityMetric::get_target_metric(), MBMesquite::OFEvaluator::initialize(), initialize(), initialize_mesh_iteration(), MBMesquite::Instruction::initialize_vertex_byte(), MBMesquite::MsqError::INVALID_MESH, MBMesquite::MsqError::INVALID_STATE, jacobiOpt, mesh, MSQ_CHKERR, MSQ_ERRZERO, MSQ_SETERR, optimize_vertex_positions(), MBMesquite::OFEvaluator::reset(), MBMesquite::TerminationCriterion::reset_inner(), MBMesquite::TerminationCriterion::reset_outer(), MBMesquite::TerminationCriterion::reset_patch(), MBMesquite::TerminationCriterion::set_debug_output_level(), MBMesquite::PatchData::set_domain(), MBMesquite::PatchSet::set_mesh(), MBMesquite::PatchData::set_mesh(), MBMesquite::PatchData::set_mesh_entities(), MBMesquite::Mesh::tag_delete(), MBMesquite::TerminationCriterion::terminate(), terminate_mesh_iteration(), and MBMesquite::PatchData::update_mesh().
{ Mesh* mesh = mesh_and_domain->get_mesh(); MeshDomain* domain = mesh_and_domain->get_domain(); TagHandle coord_tag = 0; // store uncommitted coords for jacobi optimization TagHandle* coord_tag_ptr = 0; TerminationCriterion* outer_crit = 0; TerminationCriterion* inner_crit = 0; // Clear culling flag, set hard fixed flag, etc on all vertices initialize_vertex_byte( mesh_and_domain, settings, err ); MSQ_ERRZERO( err ); // Get the patch data to use for the first iteration OFEvaluator& obj_func = get_objective_function_evaluator(); // Check for impromer use of MaxTemplate ObjectiveFunctionTemplate* maxt_ptr = dynamic_cast< MaxTemplate* >( obj_func.get_objective_function() ); if( maxt_ptr ) { QualityImprover* ngqi_ptr = dynamic_cast< NonGradient* >( this ); if( !ngqi_ptr ) std::cout << "Warning: MaxTemplate results in non-differentiable objective function." << std::endl << " Therefore, it is best to use the NonGradient solver. Other Mesquite" << std::endl << " solvers require derivative information." << std::endl; } PatchData patch; patch.set_mesh( mesh ); patch.set_domain( domain ); if( settings ) patch.attach_settings( settings ); bool one_patch = false, inner_crit_terminated, all_culled; std::vector< Mesh::VertexHandle > patch_vertices; std::vector< Mesh::ElementHandle > patch_elements; bool valid; 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 ); // check for inverted elements when using a barrietr target metric TQualityMetric* tqm_ptr = NULL; TMetricBarrier* tm_ptr = NULL; AWMetricBarrier* awm_ptr = NULL; ElemSampleQM* sample_qm_ptr = NULL; QualityMetric* qm_ptr = NULL; TQualityMetric* pmeanp_ptr = NULL; ElementMaxQM* elem_max_ptr = NULL; ElementAvgQM* elem_avg_ptr = NULL; ElementPMeanP* elem_pmeanp_ptr = NULL; ObjectiveFunctionTemplate* of_ptr = dynamic_cast< ObjectiveFunctionTemplate* >( obj_func.get_objective_function() ); if( of_ptr ) qm_ptr = of_ptr->get_quality_metric(); if( qm_ptr ) { pmeanp_ptr = dynamic_cast< TQualityMetric* >( qm_ptr ); // PMeanP case elem_max_ptr = dynamic_cast< ElementMaxQM* >( qm_ptr ); elem_avg_ptr = dynamic_cast< ElementAvgQM* >( qm_ptr ); elem_pmeanp_ptr = dynamic_cast< ElementPMeanP* >( qm_ptr ); } if( elem_max_ptr ) sample_qm_ptr = elem_max_ptr->get_quality_metric(); else if( elem_pmeanp_ptr ) sample_qm_ptr = elem_pmeanp_ptr->get_quality_metric(); else if( elem_avg_ptr ) sample_qm_ptr = elem_avg_ptr->get_quality_metric(); else if( pmeanp_ptr ) { tm_ptr = dynamic_cast< TMetricBarrier* >( pmeanp_ptr->get_target_metric() ); awm_ptr = dynamic_cast< AWMetricBarrier* >( pmeanp_ptr->get_target_metric() ); } if( sample_qm_ptr || pmeanp_ptr ) { if( !pmeanp_ptr ) { tqm_ptr = dynamic_cast< TQualityMetric* >( sample_qm_ptr ); if( tqm_ptr ) { tm_ptr = dynamic_cast< TMetricBarrier* >( tqm_ptr->get_target_metric() ); awm_ptr = dynamic_cast< AWMetricBarrier* >( tqm_ptr->get_target_metric() ); } } else { tqm_ptr = dynamic_cast< TQualityMetric* >( pmeanp_ptr ); } if( tqm_ptr && ( tm_ptr || awm_ptr ) ) { // check for inverted elements this->initialize( patch, err ); std::vector< size_t > handles; // set up patch data std::vector< PatchSet::PatchHandle >::iterator patch_iter = patch_list.begin(); while( patch_iter != patch_list.end() ) { do { patch_set->get_patch( *patch_iter, patch_elements, patch_vertices, err ); if( MSQ_CHKERR( err ) ) goto ERROR; ++patch_iter; } while( patch_elements.empty() && patch_iter != patch_list.end() ); patch.set_mesh_entities( patch_elements, patch_vertices, err ); if( MSQ_CHKERR( err ) ) goto ERROR; qm_ptr->get_evaluations( patch, handles, true, err ); // MSQ_ERRFALSE(err); // do actual check for inverted elements std::vector< size_t >::const_iterator i; double tvalue; for( i = handles.begin(); i != handles.end(); ++i ) { bool result = tqm_ptr->evaluate( patch, *i, tvalue, err ); if( MSQ_CHKERR( err ) || !result ) return false; // inverted element detected } } } } // Get termination criteria outer_crit = this->get_outer_termination_criterion(); 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.; } // Set Termination Criterion defaults if no other Criterion is set if( !outer_crit->criterion_is_set() ) outer_crit->add_iteration_limit( 1 ); if( !inner_crit->criterion_is_set() ) inner_crit->add_iteration_limit( 10 ); // 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; if( jacobiOpt ) { coord_tag = get_jacobi_coord_tag( mesh, err ); MSQ_ERRZERO( err ); coord_tag_ptr = &coord_tag; } // Initialize outer loop this->initialize( patch, err ); if( MSQ_CHKERR( err ) ) goto ERROR; valid = obj_func.initialize( mesh_and_domain, settings, patch_set, err ); if( MSQ_CHKERR( err ) ) goto ERROR; if( !valid ) { MSQ_SETERR( err ) ( "ObjectiveFunction initialization failed. Mesh " "invalid at one or more sample points.", MsqError::INVALID_MESH ); 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 inner_crit_terminated = false; while( !outer_crit->terminate() ) { if( inner_crit_terminated ) { 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; } inner_crit_terminated = true; all_culled = true; int num_patches = 0; // 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 if( 0 ) std::cout << "P[" << get_parallel_rank() << "] tmp srk all vertices culled." << std::endl; 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; } ++num_patches; // 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() ) { inner_crit_terminated = false; // 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; // FIXME if( 0 ) { inner_crit->cull_vertices_global( patch, mesh, domain, settings, obj_func, err ); if( MSQ_CHKERR( err ) ) goto ERROR; } patch.update_mesh( err, coord_tag_ptr ); if( MSQ_CHKERR( err ) ) goto ERROR; } } if( jacobiOpt ) commit_jacobi_coords( coord_tag, mesh, err ); 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: if( jacobiOpt ) mesh->tag_delete( coord_tag, err ); // call the criteria's cleanup funtions. if( outer_crit ) outer_crit->cleanup( mesh, domain, err ); if( inner_crit ) inner_crit->cleanup( mesh, domain, err ); // call the optimization cleanup function. this->cleanup(); return 0.; }
double MBMesquite::VertexMover::loop_over_mesh | ( | ParallelMesh * | mesh, |
MeshDomain * | domain, | ||
const Settings * | settings, | ||
MsqError & | err | ||
) | [virtual] |
Improves the quality of the MeshSet, calling some methods specified in a class derived from VertexMover.
const | MeshSet &: this MeshSet is looped over. Only the mutable data members are changed (such as currentVertexInd). |
[email protected] 1/19/12: the logic here was changed so that all proc's must agree on the values used for outer and inner termination before the iteration is stopped. Previously, the ParallelHelper::communicate_all_true method returned true if any proc sent it a true value, which seems to be a bug, at least in the name of the method. The method has been changed to return true only if all proc's values are true. In the previous version, this meant that if any proc hit its inner or outer termination criterion, the loop was exited, and thus some parts of the mesh are potentially left unconverged. Also, if the outer criterion was satisfied on part of the mesh (say a uniform part), the iterations were not executed at all. Also, changed name of "did_some" to "inner_crit_terminated", and flipped its boolean value to be consistent with the name - for readability and for correctness since we want to communicate a true value through the helper.
*** smooth the interior ***////
[email protected] save vertex bytes since boundary smoothing changes them
*** smooth the boundary ***////
[email protected] restore vertex bytes since boundary smoothing changes them
Reimplemented from MBMesquite::Instruction.
Definition at line 479 of file VertexMover.cpp.
References MBMesquite::TerminationCriterion::accumulate_outer(), MBMesquite::TerminationCriterion::accumulate_patch(), MBMesquite::PatchData::attach_settings(), MBMesquite::checkpoint_bytes(), cleanup(), MBMesquite::TerminationCriterion::cleanup(), commit_jacobi_coords(), MBMesquite::ParallelHelper::communicate_all_true(), MBMesquite::ParallelHelper::communicate_any_true(), MBMesquite::ParallelHelper::communicate_first_independent_set(), MBMesquite::ParallelHelper::communicate_next_independent_set(), MBMesquite::ParallelHelper::compute_first_independent_set(), MBMesquite::ParallelHelper::compute_next_independent_set(), coord_tag, MBMesquite::TerminationCriterion::cull_vertices(), MBMesquite::TerminationCriterion::cull_vertices_global(), MBMesquite::MsqDebug::disable_all(), MBMesquite::MsqError::error_message(), MBMesquite::Mesh::get_all_vertices(), MBMesquite::QualityImprover::get_inner_termination_criterion(), get_jacobi_coord_tag(), MBMesquite::ParallelHelper::get_next_partition_boundary_vertex(), get_objective_function_evaluator(), MBMesquite::QualityImprover::get_outer_termination_criterion(), MBMesquite::get_parallel_rank(), MBMesquite::PatchSet::get_patch(), MBMesquite::PatchSet::get_patch_handles(), MBMesquite::QualityImprover::get_patch_set(), MBMesquite::TerminationCriterion::globalInvertedCount, MBMesquite::OFEvaluator::initialize(), initialize(), initialize_mesh_iteration(), MBMesquite::Instruction::initialize_vertex_byte(), MBMesquite::MsqError::INVALID_STATE, jacobiOpt, MSQ_CHKERR, MSQ_DBG, MSQ_ERRZERO, MSQ_SETERR, optimize_vertex_positions(), MBMesquite::MsqError::PARALLEL_ERROR, MBMesquite::TerminationCriterion::patchInvertedCount, PERROR_COND, MBMesquite::OFEvaluator::reset(), MBMesquite::TerminationCriterion::reset_inner(), MBMesquite::TerminationCriterion::reset_outer(), MBMesquite::TerminationCriterion::reset_patch(), MBMesquite::restore_bytes(), MBMesquite::save_or_restore_debug_state(), MBMesquite::TerminationCriterion::set_debug_output_level(), MBMesquite::PatchData::set_domain(), MBMesquite::PatchSet::set_mesh(), MBMesquite::PatchData::set_mesh(), MBMesquite::PatchData::set_mesh_entities(), MBMesquite::ParallelHelper::smoothing_close(), MBMesquite::ParallelHelper::smoothing_init(), MBMesquite::Mesh::tag_delete(), MBMesquite::TerminationCriterion::terminate(), terminate_mesh_iteration(), MBMesquite::PatchData::update_mesh(), and MBMesquite::Mesh::vertices_get_attached_elements().
{ std::vector< size_t > junk; Mesh::VertexHandle vertex_handle; TagHandle coord_tag = 0; // store uncommitted coords for jacobi optimization TagHandle* coord_tag_ptr = 0; int outer_iter = 0; int inner_iter = 0; bool one_patch = false; // Clear culling flag, set hard fixed flag, etc on all vertices MeshDomainAssoc mesh_and_domain = MeshDomainAssoc( (Mesh*)mesh, 0 ); initialize_vertex_byte( &mesh_and_domain, settings, err ); MSQ_ERRZERO( err ); // 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 inner_crit_terminated, 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 ); if( patch_list.size() > 1 ) inner_crit->set_debug_output_level( 3 ); else one_patch = true; if( jacobiOpt ) { coord_tag = get_jacobi_coord_tag( mesh, err ); MSQ_ERRZERO( err ); coord_tag_ptr = &coord_tag; } // parallel error checking MsqError perr; bool pdone = false; #define PERROR_COND continue // Initialize outer loop this->initialize( patch, err ); if( MSQ_CHKERR( err ) ) { MSQ_SETERR( perr )( "initialize patch", MsqError::INVALID_STATE ); } // goto ERROR; MeshDomainAssoc mesh_and_domain2 = MeshDomainAssoc( (Mesh*)mesh, domain ); obj_func.initialize( &mesh_and_domain2, settings, patch_set, err ); if( MSQ_CHKERR( err ) ) { MSQ_SETERR( perr )( "initialize obj_func", MsqError::INVALID_STATE ); } // goto ERROR; outer_crit->reset_outer( (Mesh*)mesh, domain, obj_func, settings, err ); if( MSQ_CHKERR( err ) ) { MSQ_SETERR( perr )( "reset_outer", MsqError::INVALID_STATE ); } // goto ERROR; // Loop until outer termination criterion is met inner_crit_terminated = false; all_culled = false; for( ;; ) { if( 0 ) std::cout << "P[" << get_parallel_rank() << "] tmp srk inner_iter= " << inner_iter << " outer_iter= " << outer_iter << std::endl; // PERROR: if( MSQ_CHKERR( perr ) ) { std::cout << "P[" << get_parallel_rank() << "] VertexMover::loop_over_mesh found parallel error: " << perr << "\n quitting... pdone= " << pdone << std::endl; pdone = true; } helper->communicate_any_true( pdone, err ); if( 0 ) std::cout << "P[" << get_parallel_rank() << "] tmp srk inner_iter= " << inner_iter << " outer_iter= " << outer_iter << " pdone= " << pdone << std::endl; if( pdone ) { std::cout << "P[" << get_parallel_rank() << "] VertexMover::loop_over_mesh found parallel error, quitting... pdone= " << pdone << std::endl; MSQ_SETERR( err )( "PARALLEL ERROR", MsqError::PARALLEL_ERROR ); break; } ++outer_iter; /// [email protected] 1/19/12: the logic here was changed so that all proc's must agree /// on the values used for outer and inner termination before the iteration is stopped. /// Previously, the ParallelHelper::communicate_all_true method returned true if any /// proc sent it a true value, which seems to be a bug, at least in the name of the /// method. The method has been changed to return true only if all proc's values are true. /// In the previous version, this meant that if any proc hit its inner or outer /// termination criterion, the loop was exited, and thus some parts of the mesh /// are potentially left unconverged. Also, if the outer criterion was satisfied on /// part of the mesh (say a uniform part), the iterations were not executed at all. /// Also, changed name of "did_some" to "inner_crit_terminated", and flipped its boolean /// value to be consistent with the name - for readability and for correctness since /// we want to communicate a true value through the helper. bool outer_crit_terminated = outer_crit->terminate(); bool outer_crit_terminated_local = outer_crit_terminated; helper->communicate_all_true( outer_crit_terminated, err ); bool inner_crit_terminated_local = inner_crit_terminated; helper->communicate_all_true( inner_crit_terminated, err ); bool all_culled_local = all_culled; helper->communicate_all_true( all_culled, err ); bool done = all_culled || outer_crit_terminated; if( inner_crit_terminated ) { MSQ_SETERR( err ) ( "Inner termination criterion satisfied for all patches " "without meeting outer termination criterion. This is " "an infinite loop. Aborting.", MsqError::INVALID_STATE ); done = true; helper->communicate_any_true( done, err ); } bool local_done = done; helper->communicate_all_true( done, err ); if( 0 ) std::cout << "P[" << get_parallel_rank() << "] tmp srk done= " << done << " local_done= " << local_done << " all_culled= " << all_culled << " outer_crit->terminate()= " << outer_crit->terminate() << " outer_term= " << outer_crit_terminated << " outer_term_local= " << outer_crit_terminated_local << " inner_crit_terminated = " << inner_crit_terminated << " inner_crit_terminated_local = " << inner_crit_terminated_local << " all_culled = " << all_culled << " all_culled_local = " << all_culled_local << std::endl; if( MSQ_CHKERR( err ) ) { MSQ_SETERR( perr )( "loop start", MsqError::INVALID_STATE ); } // goto ERROR; if( done ) break; inner_crit_terminated = true; 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 if( 0 && MSQ_DBG( 2 ) ) std::cout << "P[" << get_parallel_rank() << "] tmp srk number of patches = " << patch_list.size() << " inner_iter= " << inner_iter << " outer_iter= " << outer_iter << " inner.globalInvertedCount = " << inner_crit->globalInvertedCount << " outer.globalInvertedCount = " << outer_crit->globalInvertedCount << " inner.patchInvertedCount = " << inner_crit->patchInvertedCount << " outer.patchInvertedCount = " << outer_crit->patchInvertedCount << std::endl; save_or_restore_debug_state( true ); // MsqDebug::disable_all(); int num_patches = 0; 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 ) ) { MSQ_SETERR( perr )( "get_patch", MsqError::INVALID_STATE ); PERROR_COND; } // goto ERROR; ++p_iter; } while( patch_elements.empty() && p_iter != patch_list.end() ); if( patch_elements.empty() ) { // no more non-culled vertices if( 0 ) std::cout << "P[" << get_parallel_rank() << "] tmp srk all vertices culled." << std::endl; 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; } ++num_patches; all_culled = false; patch.set_mesh_entities( patch_elements, free_vertices, err ); if( MSQ_CHKERR( err ) ) { MSQ_SETERR( perr )( "set_mesh_entities", MsqError::INVALID_STATE ); PERROR_COND; } // goto ERROR; // Initialize for inner iteration this->initialize_mesh_iteration( patch, err ); if( MSQ_CHKERR( err ) ) { MSQ_SETERR( perr )( "initialize_mesh_iteration", MsqError::INVALID_STATE ); PERROR_COND; } // goto ERROR; obj_func.reset(); outer_crit->reset_patch( patch, err ); if( MSQ_CHKERR( err ) ) { MSQ_SETERR( perr )( "reset_patch outer", MsqError::INVALID_STATE ); PERROR_COND; } // goto ERROR; inner_crit->reset_inner( patch, obj_func, err ); if( MSQ_CHKERR( err ) ) { MSQ_SETERR( perr )( "reset_inner", MsqError::INVALID_STATE ); PERROR_COND; } // goto ERROR; inner_crit->reset_patch( patch, err ); if( MSQ_CHKERR( err ) ) { MSQ_SETERR( perr )( "inner reset_patch", MsqError::INVALID_STATE ); PERROR_COND; } // goto ERROR; // Don't even call optimizer if inner termination // criterion has already been met. if( !inner_crit->terminate() ) { inner_crit_terminated = false; if( one_patch ) ++inner_iter; // Call optimizer - should loop on inner_crit->terminate() // size_t num_vert=patch.num_free_vertices(); // std::cout << "P[" << get_parallel_rank() << "] tmp srk VertexMover num_vert= " << // num_vert << std::endl; this->optimize_vertex_positions( patch, err ); if( MSQ_CHKERR( err ) ) { MSQ_SETERR( perr )( "optimize_vertex_positions", MsqError::INVALID_STATE ); PERROR_COND; } // goto ERROR; // Update for changes during inner iteration // (during optimizer loop) outer_crit->accumulate_patch( patch, err ); if( MSQ_CHKERR( err ) ) { MSQ_SETERR( perr )( "outer accumulate_patch", MsqError::INVALID_STATE ); PERROR_COND; } // goto ERROR; inner_crit->cull_vertices( patch, obj_func, err ); if( MSQ_CHKERR( err ) ) { MSQ_SETERR( perr )( "inner cull_vertices", MsqError::INVALID_STATE ); PERROR_COND; } // goto ERROR; // experimental... if( 0 ) { inner_crit->cull_vertices_global( patch, mesh, domain, settings, obj_func, err ); if( MSQ_CHKERR( err ) ) { MSQ_SETERR( perr )( "cull_vertices_global", MsqError::INVALID_STATE ); PERROR_COND; } // goto ERROR; } patch.update_mesh( err, coord_tag_ptr ); if( MSQ_CHKERR( err ) ) { MSQ_SETERR( perr )( "update_mesh", MsqError::INVALID_STATE ); PERROR_COND; } // goto ERROR; } } // while(p_iter.... save_or_restore_debug_state( false ); if( 1 ) { bool pdone_inner = false; if( MSQ_CHKERR( perr ) ) { std::cout << "P[" << get_parallel_rank() << "] VertexMover::loop_over_mesh found parallel error: " << perr << "\n quitting... pdone_inner= " << pdone_inner << std::endl; pdone_inner = true; } helper->communicate_any_true( pdone_inner, err ); if( 0 ) std::cout << "P[" << get_parallel_rank() << "] tmp srk inner_iter= " << inner_iter << " outer_iter= " << outer_iter << " pdone_inner= " << pdone_inner << std::endl; if( pdone_inner ) { if( 0 ) std::cout << "P[" << get_parallel_rank() << "] tmp srk found parallel error, quitting... pdone_inner= " << pdone_inner << std::endl; MSQ_SETERR( err )( "PARALLEL ERROR", MsqError::PARALLEL_ERROR ); break; } } /// [email protected] save vertex bytes since boundary smoothing changes them std::vector< unsigned char > saved_bytes; checkpoint_bytes( mesh, saved_bytes, err ); if( MSQ_CHKERR( err ) ) { MSQ_SETERR( perr )( "checkpoint_bytes ", MsqError::INVALID_STATE ); PERROR_COND; } // goto ERROR; helper->communicate_first_independent_set( err ); if( MSQ_CHKERR( err ) ) { MSQ_SETERR( perr )( "communicate_first_independent_set ", MsqError::INVALID_STATE ); PERROR_COND; } // goto ERROR; ///*** smooth the boundary ***//// save_or_restore_debug_state( true ); MsqDebug::disable_all(); 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 ) ) { MSQ_SETERR( perr )( "set_mesh_entities 2 ", MsqError::INVALID_STATE ); PERROR_COND; } // goto ERROR; // Initialize for inner iteration this->initialize_mesh_iteration( patch, err ); if( MSQ_CHKERR( err ) ) { MSQ_SETERR( perr )( " initialize_mesh_iteration 2", MsqError::INVALID_STATE ); PERROR_COND; } // goto ERROR; obj_func.reset(); outer_crit->reset_patch( patch, err ); if( MSQ_CHKERR( err ) ) { MSQ_SETERR( perr )( "outer reset_patch 2 ", MsqError::INVALID_STATE ); PERROR_COND; } // goto ERROR; inner_crit->reset_inner( patch, obj_func, err ); if( MSQ_CHKERR( err ) ) { MSQ_SETERR( perr )( " inner reset_inner 2", MsqError::INVALID_STATE ); PERROR_COND; } // goto ERROR; inner_crit->reset_patch( patch, err ); if( MSQ_CHKERR( err ) ) { MSQ_SETERR( perr )( " inner_crit reset_patch 2", MsqError::INVALID_STATE ); PERROR_COND; } // goto ERROR; // Don't even call optimizer if inner termination // criterion has already been met. if( !inner_crit->terminate() ) { inner_crit_terminated = false; // Call optimizer - should loop on inner_crit->terminate() this->optimize_vertex_positions( patch, err ); if( MSQ_CHKERR( err ) ) { MSQ_SETERR( perr ) ( " optimize_vertex_positions 2", MsqError::INVALID_STATE ); PERROR_COND; } // goto ERROR; // Update for changes during inner iteration // (during optimizer loop) outer_crit->accumulate_patch( patch, err ); if( MSQ_CHKERR( err ) ) { MSQ_SETERR( perr )( " outer accumulate_patch 2", MsqError::INVALID_STATE ); PERROR_COND; } // goto ERROR; inner_crit->cull_vertices( patch, obj_func, err ); if( MSQ_CHKERR( err ) ) { MSQ_SETERR( perr )( " inner cull_vertices", MsqError::INVALID_STATE ); PERROR_COND; } // goto ERROR; // FIXME if( 0 ) { inner_crit->cull_vertices_global( patch, mesh, domain, settings, obj_func, err ); if( MSQ_CHKERR( err ) ) { MSQ_SETERR( perr ) ( " cull_vertices_global 2 ", MsqError::INVALID_STATE ); PERROR_COND; } // goto ERROR; } patch.update_mesh( err, coord_tag_ptr ); if( MSQ_CHKERR( err ) ) { MSQ_SETERR( perr )( " update_mesh 2", MsqError::INVALID_STATE ); PERROR_COND; } // goto ERROR; } } helper->communicate_next_independent_set( err ); if( MSQ_CHKERR( err ) ) { MSQ_SETERR( perr ) ( " communicate_next_independent_set 2", MsqError::INVALID_STATE ); PERROR_COND; } // goto ERROR; } // while(helper->compute_next_independent_set()) save_or_restore_debug_state( false ); // if (!get_parallel_rank()) // std::cout << "P[" << get_parallel_rank() << "] tmp srk num_patches= " << num_patches << // std::endl; /// [email protected] restore vertex bytes since boundary smoothing changes them restore_bytes( mesh, saved_bytes, err ); if( MSQ_CHKERR( err ) ) { MSQ_SETERR( perr )( " restore_bytes", MsqError::INVALID_STATE ); PERROR_COND; } // goto ERROR; if( jacobiOpt ) commit_jacobi_coords( coord_tag, mesh, err ); this->terminate_mesh_iteration( patch, err ); if( MSQ_CHKERR( err ) ) { MSQ_SETERR( perr )( " terminate_mesh_iteration", MsqError::INVALID_STATE ); PERROR_COND; } // goto ERROR; outer_crit->accumulate_outer( mesh, domain, obj_func, settings, err ); if( MSQ_CHKERR( err ) ) { MSQ_SETERR( perr )( " outer_crit accumulate_outer", MsqError::INVALID_STATE ); PERROR_COND; } // goto ERROR; } // ERROR: if( MSQ_CHKERR( err ) ) { std::cout << "P[" << get_parallel_rank() << "] VertexMover::loop_over_mesh error = " << err.error_message() << std::endl; } if( jacobiOpt ) mesh->tag_delete( coord_tag, err ); // 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.; }
virtual void MBMesquite::VertexMover::optimize_vertex_positions | ( | PatchData & | pd, |
MsqError & | err | ||
) | [protected, pure virtual] |
Implemented in TCTFauxOptimizer, MBMesquite::NonGradient, MBMesquite::NonSmoothDescent, MBMesquite::FeasibleNewton, MBMesquite::SteepestDescent, MBMesquite::ConjugateGradient, MBMesquite::Randomize, MBMesquite::LaplacianSmoother, MBMesquite::QuasiNewton, MBMesquite::TrustRegion, MBMesquite::NullImprover, UnOptimizer, MBMesquite::RelaxationSmoother, and MBMesquite::SmartLaplacianSmoother.
Referenced by loop_over_mesh().
virtual void MBMesquite::VertexMover::terminate_mesh_iteration | ( | PatchData & | , |
MsqError & | err | ||
) | [protected, pure virtual] |
Implemented in TCTFauxOptimizer, MBMesquite::NonGradient, MBMesquite::NonSmoothDescent, MBMesquite::FeasibleNewton, MBMesquite::SteepestDescent, MBMesquite::ConjugateGradient, MBMesquite::Randomize, MBMesquite::QuasiNewton, MBMesquite::TrustRegion, MBMesquite::NullImprover, UnOptimizer, and MBMesquite::RelaxationSmoother.
Referenced by loop_over_mesh().
bool MBMesquite::VertexMover::jacobiOpt [private] |
Definition at line 161 of file VertexMover.hpp.
Referenced by loop_over_mesh().
Definition at line 160 of file VertexMover.hpp.
Referenced by initialize_queue().