MOAB: Mesh Oriented datABase  (version 5.4.1)
2d_target_test.cpp
Go to the documentation of this file.
00001 /* *****************************************************************
00002     MESQUITE -- The Mesh Quality Improvement Toolkit
00003 
00004     Copyright 2006 Sandia National Laboratories.  Developed at the
00005     University of Wisconsin--Madison under SNL contract number
00006     624796.  The U.S. Government and the University of Wisconsin
00007     retian certain rights to this software.
00008 
00009     This library is free software; you can redistribute it and/or
00010     modify it under the terms of the GNU Lesser General Public
00011     License as published by the Free Software Foundation; either
00012     version 2.1 of the License, or (at your option) any later version.
00013 
00014     This library is distributed in the hope that it will be useful,
00015     but WITHOUT ANY WARRANTY; without even the implied warranty of
00016     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017     Lesser General Public License for more details.
00018 
00019     You should have received a copy of the GNU Lesser General Public License
00020     (lgpl.txt) along with this library; if not, write to the Free Software
00021     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00022 
00023     (2006) [email protected]
00024 
00025   ***************************************************************** */
00026 
00027 #include "Mesquite.hpp"
00028 #include <iostream>
00029 using std::cerr;
00030 using std::cout;
00031 using std::endl;
00032 using std::ostream;
00033 #include <memory>
00034 using std::unique_ptr;
00035 #include <cctype>
00036 
00037 #include "MeshImpl.hpp"
00038 #include "MsqError.hpp"
00039 #include "InstructionQueue.hpp"
00040 #include "TerminationCriterion.hpp"
00041 #include "QualityAssessor.hpp"
00042 #include "PMeanPTemplate.hpp"
00043 #include "PatchPowerMeanP.hpp"
00044 #include "ConjugateGradient.hpp"
00045 #include "PlanarDomain.hpp"
00046 #include "IdealShapeTarget.hpp"
00047 #include "ConditionNumberQualityMetric.hpp"
00048 #include "ReferenceMesh.hpp"
00049 #include "RefMeshTargetCalculator.hpp"
00050 #include "TestUtil.hpp"
00051 
00052 #include "TQualityMetric.hpp"
00053 #include "ElementPMeanP.hpp"
00054 #include "VertexPMeanP.hpp"
00055 
00056 #include "TSquared.hpp"
00057 #include "TShapeNB1.hpp"
00058 #include "TShapeB1.hpp"
00059 #include "TShapeOrientNB1.hpp"
00060 #include "TShapeOrientNB2.hpp"
00061 #include "TShapeOrientB1.hpp"
00062 #include "TShapeSize2DNB1.hpp"
00063 #include "TShapeSizeB1.hpp"
00064 #include "TShapeSize2DB2.hpp"
00065 #include "TShapeSizeB3.hpp"
00066 #include "TShapeSizeOrientNB1.hpp"
00067 #include "TShapeSizeOrientB1.hpp"
00068 #include "TShapeSizeOrientB2.hpp"
00069 
00070 using namespace MBMesquite;
00071 
00072 static const struct
00073 {
00074     TMetric* u;
00075     const char* n;
00076 } metrics[] = { { new TSquared, "TSquared" },
00077                 { new TShapeNB1, "Shape" },
00078                 { new TShapeB1, "ShapeBarrier" },
00079                 { new TShapeOrientNB1, "ShapeOrient1" },
00080                 { new TShapeOrientNB2, "ShapeOrient2" },
00081                 { new TShapeOrientB1, "ShapeOrientBarrier" },
00082                 { new TShapeSize2DNB1, "ShapeSize" },
00083                 { new TShapeSizeB1, "ShapeSizeBarrier1" },
00084                 { new TShapeSize2DB2, "ShapeSizeBarrier2" },
00085                 { new TShapeSizeB3, "ShapeSizeBarrier3" },
00086                 { new TShapeSizeOrientB1, "ShapeSizeOrient1" },
00087                 { new TShapeSizeOrientB1, "ShapeSizeOrientBarrier1" },
00088                 { new TShapeSizeOrientB2, "ShapeSizeOrientBarrier2" },
00089                 { 0, 0 } };
00090 
00091 enum AveragingScheme
00092 {
00093     NONE = 0,
00094     ELEMENT,
00095     VERTEX,
00096     PATCH
00097 };
00098 const char* const averaging_names[] = { "none", "element", "vertex", "patch" };
00099 
00100 // default values
00101 const double DEFAULT_OF_POWER            = 1.0;
00102 const unsigned DEFAULT_METRIC_IDX        = 0;
00103 const AveragingScheme DEFAULT_AVG_SCHEME = NONE;
00104 std::string DEFAULT_INPUT_FILE           = TestDir + "unittest/mesquite/2D/vtk/quads/untangled/quads_4by2_bad.vtk";
00105 std::string DEFAULT_OUTPUT_FILE          = "./out.vtk";
00106 
00107 static PlanarDomain make_domain( Mesh* mesh, MsqError& );
00108 
00109 static int do_smoother( const char* input_file,
00110                         const char* output_file,
00111                         const char* ref_mesh_file,
00112                         double of_power,
00113                         unsigned metric_idx,
00114                         AveragingScheme avg_scheme )
00115 {
00116     MsqPrintError err( cerr );
00117 
00118     TMetric* const target_metric = metrics[metric_idx].u;
00119     cout << "Input file:  " << input_file << endl;
00120     cout << "Metric:      ";
00121     if( avg_scheme != NONE ) cout << averaging_names[avg_scheme] << " average of ";
00122     cout << metrics[metric_idx].n << endl;
00123     cout << "Of Power:    " << of_power << endl;
00124 
00125     unique_ptr< TargetCalculator > tc;
00126     unique_ptr< MeshImpl > ref_mesh_impl;
00127     unique_ptr< ReferenceMesh > ref_mesh;
00128     if( ref_mesh_file )
00129     {
00130         ref_mesh_impl.reset( new MeshImpl );
00131         ref_mesh_impl->read_vtk( ref_mesh_file, err );
00132         if( MSQ_CHKERR( err ) ) return 2;
00133         ref_mesh.reset( new ReferenceMesh( ref_mesh_impl.get() ) );
00134         tc.reset( new RefMeshTargetCalculator( ref_mesh.get() ) );
00135     }
00136     else
00137     {
00138         tc.reset( new IdealShapeTarget() );
00139     }
00140 
00141     TQualityMetric jacobian_metric( tc.get(), target_metric );
00142     ElementPMeanP elem_avg( of_power, &jacobian_metric );
00143     VertexPMeanP vtx_avg( of_power, &jacobian_metric );
00144     QualityMetric* mmetrics[] = { &jacobian_metric, &elem_avg, &vtx_avg, &jacobian_metric };
00145     QualityMetric* metric     = mmetrics[avg_scheme];
00146 
00147     TerminationCriterion outer, inner;
00148     outer.add_iteration_limit( 1 );
00149     inner.add_absolute_vertex_movement( 1e-4 );
00150     inner.add_iteration_limit( 100 );
00151 
00152     PMeanPTemplate obj1( of_power, metric );
00153     PatchPowerMeanP obj2( of_power, metric );
00154     ObjectiveFunction& objective = *( ( avg_scheme == PATCH ) ? (ObjectiveFunction*)&obj2 : (ObjectiveFunction*)&obj1 );
00155 
00156     ConjugateGradient solver( &objective, err );
00157     if( MSQ_CHKERR( err ) ) return 1;
00158     solver.set_inner_termination_criterion( &inner );
00159     solver.set_outer_termination_criterion( &outer );
00160     solver.use_global_patch();
00161 
00162     ConditionNumberQualityMetric qm_metric;
00163     QualityAssessor before_assessor;
00164     QualityAssessor after_assessor;
00165     before_assessor.add_quality_assessment( metric, 10 );
00166     before_assessor.add_quality_assessment( &qm_metric );
00167     after_assessor.add_quality_assessment( metric, 10 );
00168 
00169     InstructionQueue q;
00170     q.add_quality_assessor( &before_assessor, err );
00171     q.set_master_quality_improver( &solver, err );
00172     q.add_quality_assessor( &after_assessor, err );
00173 
00174     MeshImpl mesh;
00175     mesh.read_vtk( input_file, err );
00176     if( MSQ_CHKERR( err ) ) return 2;
00177     PlanarDomain geom = make_domain( &mesh, err );
00178     if( MSQ_CHKERR( err ) ) return 1;
00179     MeshDomainAssoc mesh_and_domain = MeshDomainAssoc( &mesh, &geom );
00180     q.run_instructions( &mesh_and_domain, err );
00181     if( MSQ_CHKERR( err ) ) return 3;
00182     mesh.write_vtk( output_file, err );
00183     if( MSQ_CHKERR( err ) ) return 2;
00184     cout << "Wrote: " << output_file << endl;
00185 
00186     before_assessor.scale_histograms( &after_assessor );
00187 
00188     return 0;
00189 }
00190 
00191 static PlanarDomain make_domain( Mesh* mesh, MsqError& err )
00192 {
00193     // calculate bounding box of mesh vertices
00194     Vector3D minimum( HUGE_VAL, HUGE_VAL, HUGE_VAL );
00195     Vector3D maximum( -HUGE_VAL, -HUGE_VAL, -HUGE_VAL );
00196     std::vector< Mesh::VertexHandle > vertices;
00197     mesh->get_all_vertices( vertices, err );
00198     if( MSQ_CHKERR( err ) )
00199     {
00200         return PlanarDomain( minimum, maximum );
00201     }
00202     if( vertices.empty() )
00203     {
00204         std::cerr << "Mesh contains no vertices" << std::endl;
00205         exit( 1 );
00206     }
00207     std::vector< MsqVertex > coords( vertices.size() );
00208     mesh->vertices_get_coordinates( arrptr( vertices ), arrptr( coords ), vertices.size(), err );
00209     if( MSQ_CHKERR( err ) )
00210     {
00211         return PlanarDomain( minimum, maximum );
00212     }
00213     std::vector< MsqVertex >::const_iterator i;
00214     for( i = coords.begin(); i != coords.end(); ++i )
00215     {
00216         const MsqVertex& v = *i;
00217         for( unsigned j = 0; j < 3; ++j )
00218         {
00219             if( v[j] < minimum[j] ) minimum[j] = v[j];
00220             if( v[j] > maximum[j] ) maximum[j] = v[j];
00221         }
00222     }
00223 
00224     // Look for a "zero" plane
00225     int k;
00226     maximum -= minimum;
00227     for( k = 2; k >= 0 && maximum[k] > 1e-6; --k )
00228         ;
00229     if( k < 0 )
00230     {
00231         MSQ_SETERR( err )( "Cannot determine plane of mesh.", MsqError::INVALID_STATE );
00232         return PlanarDomain( minimum, maximum );
00233     }
00234 
00235     Vector3D point( 0.0, 0.0, 0.0 ), normal( 0.0, 0.0, 0.0 );
00236     normal[k] = 1.0;
00237     point[k]  = minimum[k];
00238     return PlanarDomain( normal, point );
00239 }
00240 
00241 static void usage( const char* argv0, bool help = false )
00242 {
00243     ostream& str = help ? cout : cerr;
00244     str << argv0 << " [-p <power>] [-m metric_name] [-a averaging] [-e]"
00245         << " -r [ref_mesh] [input_file] [output_file]" << endl
00246         << argv0 << " <-l|-h>" << std::endl;
00247     if( help )
00248     {
00249         str << "     -p  : specify exponent value for p-mean^p OF template (default: " << DEFAULT_OF_POWER << ")"
00250             << endl
00251             << "     -m  : specify 2D target metric to use (default: " << metrics[DEFAULT_METRIC_IDX].n << ")" << endl
00252             << "     -a  : specify metric averaging scheme (default: " << averaging_names[DEFAULT_AVG_SCHEME] << ")"
00253             << endl
00254             << "              (none,vertex,element,patch)" << endl
00255             << "     -e  : sample at mid-edge points (default is corners only)" << endl
00256             << "     -r  : use reference mesh instead of ideal elements for targets" << endl
00257             << "     -l  : list available metrics" << endl
00258             << "     -h  : this help output" << endl
00259             << " default input file:  " << DEFAULT_INPUT_FILE << endl
00260             << " default output file: " << DEFAULT_OUTPUT_FILE << endl
00261             << endl;
00262     }
00263     exit( !help );
00264 }
00265 
00266 static void check_next_arg( int argc, char* argv[], int& i )
00267 {
00268     if( i == argc )
00269     {
00270         cerr << "Expected argument following \"" << argv[i] << '"' << endl;
00271         usage( argv[0] );
00272     }
00273     ++i;
00274 }
00275 
00276 static double parse_double( int argc, char* argv[], int& i )
00277 {
00278     check_next_arg( argc, argv, i );
00279     char* endptr;
00280     double result = strtod( argv[i], &endptr );
00281     if( endptr == argv[i] || *endptr )
00282     {
00283         cerr << "Expected real number following \"" << argv[i - 1] << '"' << endl;
00284         usage( argv[0] );
00285     }
00286     return result;
00287 }
00288 
00289 static int comp_string_start( const char* p, const char* s )
00290 {
00291     int i;
00292     for( i = 0; p[i]; ++i )
00293         if( tolower( p[i] ) != tolower( s[i] ) ) return 0;
00294     return s[i] ? -1 : 1;
00295 }
00296 
00297 static AveragingScheme parse_averaging( int argc, char* argv[], int& i )
00298 {
00299     check_next_arg( argc, argv, i );
00300     for( unsigned j = 0; j < 4; ++j )
00301         if( comp_string_start( argv[i], averaging_names[j] ) ) return (AveragingScheme)j;
00302     cerr << "Expected one of { ";
00303     for( unsigned j = 0; j < 4; ++j )
00304         cerr << '"' << averaging_names[j] << "\" ";
00305     cerr << "} following \"" << argv[i - 1] << '"' << endl;
00306     usage( argv[0] );
00307     return NONE;
00308 }
00309 
00310 static unsigned parse_metric( int argc, char* argv[], int& i )
00311 {
00312     check_next_arg( argc, argv, i );
00313     unsigned part = 0, all = 0, count = 0, have_all = 0;
00314     for( unsigned j = 0; metrics[j].u; ++j )
00315     {
00316         if( unsigned k = comp_string_start( argv[i], metrics[j].n ) )
00317         {
00318             if( k > 0 )
00319             {
00320                 all      = j;
00321                 have_all = 1;
00322             }
00323             else
00324             {
00325                 part = j;
00326                 ++count;
00327             }
00328         }
00329     }
00330 
00331     if( have_all ) return all;
00332 
00333     if( count )
00334     {
00335         if( count == 1 ) return part;
00336         cerr << "Ambiguous metric name: \"" << argv[i] << '"' << endl;
00337         usage( argv[0] );
00338     }
00339 
00340     cerr << "Invalid metric name following \"" << argv[i - 1] << "\" option" << endl;
00341     usage( argv[0] );
00342     return (unsigned)-1;
00343 }
00344 
00345 static void list_metrics()
00346 {
00347     cout << "Available metrics:" << endl;
00348     for( unsigned j = 0; metrics[j].u; ++j )
00349         cout << "\t" << metrics[j].n << endl;
00350     exit( 0 );
00351 }
00352 
00353 int main( int argc, char* argv[] )
00354 {
00355     MsqPrintError err( cout );
00356 
00357     // CL settings
00358     double of_power            = DEFAULT_OF_POWER;
00359     unsigned metric_idx        = DEFAULT_METRIC_IDX;
00360     AveragingScheme avg_scheme = DEFAULT_AVG_SCHEME;
00361     const char* input_file     = 0;
00362     const char* output_file    = 0;
00363     const char* ref_mesh_file  = 0;
00364 
00365     bool proc_opts = true;
00366     for( int i = 1; i < argc; ++i )
00367     {
00368         if( !proc_opts || argv[i][0] != '-' )
00369         {
00370             if( output_file )
00371             {
00372                 cerr << "Unexpected file name: \"" << argv[i] << '"' << endl;
00373                 usage( argv[0] );
00374             }
00375             else if( input_file )
00376                 output_file = argv[i];
00377             else
00378                 input_file = argv[i];
00379             continue;
00380         }
00381 
00382         if( !argv[i][1] || argv[i][2] )
00383         {
00384             cerr << "Invalid option: \"" << argv[i] << '"' << endl;
00385             usage( argv[0] );
00386         }
00387 
00388         switch( argv[i][1] )
00389         {
00390             case 'p':
00391                 of_power = parse_double( argc, argv, i );
00392                 break;
00393             case 'm':
00394                 metric_idx = parse_metric( argc, argv, i );
00395                 break;
00396             case 'a':
00397                 avg_scheme = parse_averaging( argc, argv, i );
00398                 break;
00399             case 'r':
00400                 check_next_arg( argc, argv, i );
00401                 ref_mesh_file = argv[i];
00402                 break;
00403             case '-':
00404                 proc_opts = false;
00405                 break;
00406             case 'h':
00407                 usage( argv[0], true );
00408                 break;
00409             case 'l':
00410                 list_metrics();
00411                 break;
00412             default:
00413                 cerr << "Invalid option: \"" << argv[i] << '"' << endl;
00414                 usage( argv[0] );
00415         }
00416     }
00417 
00418     if( !input_file ) input_file = DEFAULT_INPUT_FILE.c_str();
00419     if( !output_file ) output_file = DEFAULT_OUTPUT_FILE.c_str();
00420 
00421     return do_smoother( input_file, output_file, ref_mesh_file, of_power, metric_idx, avg_scheme );
00422 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines