This example demonstrates mesh optimization using the Mesquite library. It shows how to load meshes using both native MOAB and iMesh interfaces, apply various mesh optimization algorithms from Mesquite, use different quality metrics (aspect ratio, condition number, etc.), perform global and local mesh smoothing, handle geometry constraints using domain definitions, and measure mesh quality before and after optimization. The example demonstrates integration between MOAB and Mesquite for advanced mesh optimization and quality improvement.
#include "Mesquite.hpp"
#include "MsqIBase.hpp"
#include "MsqIGeom.hpp"
#include "MsqIMesh.hpp"
#include "MBiMesh.hpp"
#include "MeshImpl.hpp"
#include "FacetModifyEngine.hpp"
#include "MsqError.hpp"
#include "InstructionQueue.hpp"
#include "PatchData.hpp"
#include "TerminationCriterion.hpp"
#include "QualityAssessor.hpp"
#include "SphericalDomain.hpp"
#include "PlanarDomain.hpp"
#include "MeshWriter.hpp"
#ifdef MOAB_HAVE_MPI
#endif
#include "IdealWeightInverseMeanRatio.hpp"
#include "TMPQualityMetric.hpp"
#include "AspectRatioGammaQualityMetric.hpp"
#include "ConditionNumberQualityMetric.hpp"
#include "VertexConditionNumberQualityMetric.hpp"
#include "MultiplyQualityMetric.hpp"
#include "LPtoPTemplate.hpp"
#include "LInfTemplate.hpp"
#include "PMeanPTemplate.hpp"
#include "SteepestDescent.hpp"
#include "FeasibleNewton.hpp"
#include "QuasiNewton.hpp"
#include "ConjugateGradient.hpp"
#include "SmartLaplacianSmoother.hpp"
#include "Randomize.hpp"
#include "ReferenceMesh.hpp"
#include "RefMeshTargetCalculator.hpp"
#include "TShapeB1.hpp"
#include "TQualityMetric.hpp"
#include "IdealShapeTarget.hpp"
#include <sys/stat.h>
#include <iostream>
using std::cerr;
using std::cout;
using std::endl;
#include "iBase.h"
using namespace MBMesquite;
static int print_iGeom_error(
const char* desc,
int err, iGeom_Instance geom,
const char* file,
int line )
{
std::cerr << "ERROR: " << desc << std::endl
<< " Error code: " << err << std::endl
<<
" Error desc: " <<
buffer << std::endl
<< " At : " << file << ':' << line << std::endl;
return -1;
}
static int print_iMesh_error(
const char* desc,
int err, iMesh_Instance mesh,
const char* file,
int line )
{
std::cerr << "ERROR: " << desc << std::endl
<< " Error code: " << err << std::endl
<<
" Error desc: " <<
buffer << std::endl
<< " At : " << file << ':' << line << std::endl;
return -1;
}
#define CHECK_IGEOM( STR ) \
if( err != iBase_SUCCESS ) return print_iGeom_error( STR, err, geom, __FILE__, __LINE__ )
#define CHECK_IMESH( STR ) \
if( err != iBase_SUCCESS ) return print_iMesh_error( STR, err, instance, __FILE__, __LINE__ )
int get_imesh_mesh( MBMesquite::Mesh**,
const char* file_name,
int dimension );
int get_native_mesh( MBMesquite::Mesh**,
const char* file_name,
int dimension );
int run_local_smoother2( MeshDomainAssoc& mesh_and_domain, MsqError& err,
double OF_value = 1e-3 );
{
return ( stat( name.c_str(), &
buffer ) == 0 );
}
int main(
int argc,
char* argv[] )
{
MBMesquite::MsqPrintError err( cout );
std::string file_name, geometry_file_name;
bool use_native = false;
int dimension = 2;
#ifdef MOAB_HAVE_MPI
#endif
opts.
addOpt<
void >( std::string(
"native,N" ), std::string(
"Use native representation (default=false)" ),
&use_native );
opts.
addOpt<
int >( std::string(
"dim,d" ), std::string(
"Topological dimension of the mesh (default=2)" ),
&dimension );
opts.
addOpt< std::string >( std::string(
"input_geo,i" ),
std::string( "Input file name for the geometry (pattern=*.stl, *.facet)" ),
&geometry_file_name );
opts.
addOpt< std::string >( std::string(
"input_mesh,m" ),
std::string( "Input file name for the mesh (pattern=*.vtk, *.h5m)" ), &file_name );
if( !geometry_file_name.length() )
{
cout << "No file specified: Using defaults.\n";
}
cout << "\t Mesh filename = " << file_name << endl;
cout << "\t Geometry filename = " << geometry_file_name << endl;
MeshDomain* plane;
int ierr;
if( !
file_exists( geometry_file_name ) ) geometry_file_name =
"";
Mesh* mesh = 0;
if( use_native )
{
}
else
{
}
if( !mesh )
{
std::cerr << "Failed to load input file. Aborting." << std::endl;
return 1;
}
MeshDomainAssoc mesh_and_domain( mesh, plane );
if( err ) return 1;
double reps = 5e-2;
for( int iter = 0; iter < 5; iter++ )
{
if( !( iter % 2 ) )
{
reps * 10 );
if( err ) return 1;
}
err );
if( err ) return 1;
reps *= 0.01;
}
if( err ) return 1;
delete mesh;
delete plane;
#ifdef MOAB_HAVE_MPI
#endif
return 0;
}
{
Mesh* mesh = mesh_and_domain.get_mesh();
MeshDomain* domain = mesh_and_domain.get_domain();
InstructionQueue queue1;
IdealWeightInverseMeanRatio* mean_ratio = new IdealWeightInverseMeanRatio( err );
if( err ) return 1;
mean_ratio->set_averaging_method( QualityMetric::RMS, err );
if( err ) return 1;
LPtoPTemplate* obj_func = new LPtoPTemplate( mean_ratio, 1, err );
if( err ) return 1;
SteepestDescent* pass1 = new SteepestDescent( obj_func );
pass1->use_element_on_vertex_patch();
pass1->do_block_coordinate_descent_optimization();
pass1->use_global_patch();
if( err ) return 1;
QualityAssessor stop_qa( mean_ratio );
TerminationCriterion tc_inner;
tc_inner.add_absolute_vertex_movement( OF_value );
if( err ) return 1;
TerminationCriterion tc_outer;
tc_inner.add_iteration_limit( 10 );
tc_outer.add_iteration_limit( 5 );
tc_outer.set_debug_output_level( 3 );
tc_inner.set_debug_output_level( 3 );
pass1->set_inner_termination_criterion( &tc_inner );
pass1->set_outer_termination_criterion( &tc_outer );
queue1.add_quality_assessor( &stop_qa, err );
if( err ) return 1;
queue1.set_master_quality_improver( pass1, err );
if( err ) return 1;
queue1.add_quality_assessor( &stop_qa, err );
if( err ) return 1;
if( domain )
{
queue1.run_instructions( &mesh_and_domain, err );
}
else
{
queue1.run_instructions( mesh, err );
}
if( err ) return 1;
if( ierr ) return 1;
cout << "Wrote \"feasible-newton-result.vtk\"" << endl;
return 0;
}
{
reinterpret_cast< MBiMesh* >( dynamic_cast< MsqIMesh* >( mesh )->get_imesh_instance() )->mbImpl;
return 0;
}
int run_local_smoother( MeshDomainAssoc& mesh_and_domain, MsqError& err,
double OF_value )
{
Mesh* mesh = mesh_and_domain.get_mesh();
reinterpret_cast< MBiMesh* >( dynamic_cast< MsqIMesh* >( mesh )->get_imesh_instance() )->mbImpl;
lloyd.perform_smooth();
if( ierr ) return 1;
cout << "Wrote \"smart-laplacian-result.vtk\"" << endl;
return 0;
}
{
Mesh* mesh = mesh_and_domain.get_mesh();
MeshDomain* domain = mesh_and_domain.get_domain();
InstructionQueue queue1;
ConditionNumberQualityMetric* mean_ratio = new ConditionNumberQualityMetric();
if( err ) return 1;
mean_ratio->set_averaging_method( QualityMetric::RMS, err );
if( err ) return 1;
LPtoPTemplate* obj_func = new LPtoPTemplate( mean_ratio, 1, err );
if( err ) return 1;
if( false )
{
InstructionQueue qtmp;
Randomize rand( -0.005 );
TerminationCriterion sc_rand;
sc_rand.add_iteration_limit( 2 );
rand.set_outer_termination_criterion( &sc_rand );
qtmp.set_master_quality_improver( &rand, err );
if( err ) return 1;
if( domain )
{
qtmp.run_instructions( &mesh_and_domain, err );
}
else
{
qtmp.run_instructions( mesh, err );
}
if( err ) return 1;
}
SmartLaplacianSmoother* pass1 = new SmartLaplacianSmoother( obj_func );
QualityAssessor stop_qa( mean_ratio );
TerminationCriterion tc_inner;
tc_inner.add_absolute_vertex_movement( OF_value );
TerminationCriterion tc_outer;
tc_outer.add_iteration_limit( 10 );
pass1->set_inner_termination_criterion( &tc_inner );
pass1->set_outer_termination_criterion( &tc_outer );
queue1.add_quality_assessor( &stop_qa, err );
if( err ) return 1;
queue1.set_master_quality_improver( pass1, err );
if( err ) return 1;
queue1.add_quality_assessor( &stop_qa, err );
if( err ) return 1;
if( domain )
{
queue1.run_instructions( &mesh_and_domain, err );
}
else
{
queue1.run_instructions( mesh, err );
}
if( err ) return 1;
if( ierr ) return 1;
cout << "Wrote \"smart-laplacian-result.vtk\"" << endl;
return 0;
}
{
Mesh* mesh = mesh_and_domain.get_mesh();
MeshDomain* domain = mesh_and_domain.get_domain();
InstructionQueue q;
const double eps = 0.01;
IdealShapeTarget w;
TShapeB1 mu;
TQualityMetric metric( &w, &mu );
PMeanPTemplate func( 1.0, &metric );
SteepestDescent solver( &func );
solver.use_element_on_vertex_patch();
solver.do_jacobi_optimization();
TerminationCriterion
inner, outer;
inner.add_absolute_vertex_movement( 0.5 * eps );
outer.add_absolute_vertex_movement( 0.5 * eps );
QualityAssessor qa( &metric );
q.add_quality_assessor( &qa, err );
if( err ) return 1;
q.set_master_quality_improver( &solver, err );
if( err ) return 1;
q.add_quality_assessor( &qa, err );
if( err ) return 1;
if( domain )
{
q.run_instructions( &mesh_and_domain, err );
}
else
{
q.run_instructions( mesh, err );
}
if( err ) return 1;
if( ierr ) return 1;
cout << "Wrote \"ideal-shape-result.vtk\"" << endl;
print_timing_diagnostics( cout );
return 0;
}
{
double OF_value = 0.01;
Mesh* mesh = mesh_and_domain.get_mesh();
MeshDomain* domain = mesh_and_domain.get_domain();
InstructionQueue queue1;
ConditionNumberQualityMetric* mean_ratio = new ConditionNumberQualityMetric();
mean_ratio->set_averaging_method( QualityMetric::SUM_OF_RATIOS_SQUARED, err );
if( err ) return 1;
LPtoPTemplate* obj_func = new LPtoPTemplate( mean_ratio, 1, err );
if( err ) return 1;
ConjugateGradient* pass1 = new ConjugateGradient( obj_func, err );
pass1->use_global_patch();
QualityAssessor stop_qa( mean_ratio );
TerminationCriterion tc_inner;
tc_inner.add_absolute_vertex_movement( OF_value );
if( err ) return 1;
TerminationCriterion tc_outer;
tc_inner.add_iteration_limit( 20 );
tc_outer.add_iteration_limit( 5 );
pass1->set_inner_termination_criterion( &tc_inner );
pass1->set_outer_termination_criterion( &tc_outer );
pass1->set_debugging_level( 3 );
queue1.add_quality_assessor( &stop_qa, err );
if( err ) return 1;
queue1.set_master_quality_improver( pass1, err );
if( err ) return 1;
queue1.add_quality_assessor( &stop_qa, err );
if( err ) return 1;
if( domain )
{
queue1.run_instructions( &mesh_and_domain, err );
}
else
{
queue1.run_instructions( mesh, err );
}
if( err ) return 1;
if( ierr ) return 1;
cout << "Wrote \"solution-mesh-result.vtk\"" << endl;
print_timing_diagnostics( cout );
return 0;
}
int get_imesh_mesh( MBMesquite::Mesh** mesh,
const char* file_name,
int dimension )
{
int err;
iMesh_Instance instance = 0;
iMesh_newMesh( NULL, &instance, &err, 0 );
iBase_EntitySetHandle root_set;
iMesh_getRootSet( instance, &root_set, &err );
iMesh_load( instance, root_set, file_name, 0, &err, strlen( file_name ), 0 );
iBase_TagHandle fixed_tag;
iMesh_getTagHandle( instance, "fixed", &fixed_tag, &err, strlen( "fixed" ) );
{
int def_val = 0;
err = 0;
"Getting tag handle failed" );
std::cout <<
"Found " << verts.
size() <<
" vertices and " << cells.
size() <<
" elements" << std::endl;
MB_CHK_SET_ERR( skinner.find_skin( currset, cells,
true, skin_verts ),
"Finding the skin of the mesh failed" );
std::vector< int > fix_tag( skin_verts.
size(), 1 );
std::cout <<
"Found " << skin_verts.
size() <<
" vertices on the skin of the domain." << std::endl;
iMesh_getTagHandle( instance, "fixed", &fixed_tag, &err, strlen( "fixed" ) );
double def_val_dbl = 0.0;
"Getting tag handle failed" );
for(
unsigned i = 0; i < cells.
size() / 4; i++ )
for(
unsigned i = cells.
size() / 4; i < 2 * cells.
size() / 4; i++ )
for(
unsigned i = 2 * cells.
size() / 4; i < 3 * cells.
size() / 4; i++ )
for(
unsigned i = 3 * cells.
size() / 4; i < cells.
size(); i++ )
}
MsqError ierr;
MBMesquite::MsqIMesh* imesh =
new MBMesquite::MsqIMesh( instance, root_set, ( dimension == 3 ? iBase_REGION : iBase_FACE ), ierr,
&fixed_tag );
if( MSQ_CHKERR( ierr ) )
{
delete imesh;
cerr << err << endl;
err = iBase_FAILURE;
return 0;
}
*mesh = imesh;
return iBase_SUCCESS;
}
{
MsqError err;
MBMesquite::MeshImpl* imesh = new MBMesquite::MeshImpl();
imesh->read_vtk( file_name, err );
if( err )
{
cerr << err << endl;
exit( 3 );
}
*mesh = imesh;
return iBase_SUCCESS;
}
{
if( filename == 0 || strlen( filename ) == 0 )
{
*odomain = new PlanarDomain( PlanarDomain::XY );
return 0;
}
int err;
iGeom_Instance geom;
iGeom_newGeom( "", &geom, &err, 0 );
#ifdef MOAB_HAVE_CGM_FACET
FacetModifyEngine::set_modify_enabled( CUBIT_TRUE );
#endif
iGeom_load( geom, filename, 0, &err, strlen( filename ), 0 );
iBase_EntitySetHandle root_set;
iGeom_getRootSet( geom, &root_set, &err );
std::cout << "Model contents: " << std::endl;
const char* gtype[] = { "vertices: ", "edges: ", "faces: ", "regions: " };
int nents[4];
for( int i = 0; i <= 3; ++i )
{
iGeom_getNumOfType( geom, root_set, i, &nents[i], &err );
CHECK_IGEOM(
"Error: problem getting entities after gLoad." );
std::cout << gtype[i] << nents[i] << std::endl;
}
iBase_EntityHandle* hd_geom_ents;
int csize = 0, sizealloc = 0;
if( nents[3] > 0 )
{
hd_geom_ents = (iBase_EntityHandle*)malloc( sizeof( iBase_EntityHandle ) * nents[2] );
csize = nents[2];
iGeom_getEntities( geom, root_set, 2, &hd_geom_ents, &csize, &sizealloc, &err );
}
else
{
hd_geom_ents = (iBase_EntityHandle*)malloc( sizeof( iBase_EntityHandle ) * nents[1] );
csize = nents[1];
iGeom_getEntities( geom, root_set, 1, &hd_geom_ents, &csize, &sizealloc, &err );
}
*odomain = new MsqIGeom( geom, hd_geom_ents[0] );
return iBase_SUCCESS;
}