MOAB: Mesh Oriented datABase  (version 5.4.1)
VertexMover.cpp
Go to the documentation of this file.
00001 /* *****************************************************************
00002     MESQUITE -- The Mesh Quality Improvement Toolkit
00003 
00004     Copyright 2004 Sandia Corporation and Argonne National
00005     Laboratory.  Under the terms of Contract DE-AC04-94AL85000
00006     with Sandia Corporation, the U.S. Government retains certain
00007     rights in 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     [email protected], [email protected], [email protected],
00024     [email protected], [email protected], [email protected]
00025 
00026   ***************************************************************** */
00027 /*!
00028   \file   VertexMover.cpp
00029   \brief
00030 
00031   The VertexMover Class is the base class for all the smoothing algorythms
00032 
00033   \author Thomas Leurent
00034   \date   2002-01-17
00035 */
00036 
00037 #include "VertexMover.hpp"
00038 #include "NonGradient.hpp"
00039 #include "QualityMetric.hpp"
00040 #include "TQualityMetric.hpp"
00041 #include "TMetricBarrier.hpp"
00042 #include "AWMetricBarrier.hpp"
00043 #include "ElementMaxQM.hpp"
00044 #include "ElementAvgQM.hpp"
00045 #include "ElementPMeanP.hpp"
00046 #include "PlanarDomain.hpp"
00047 #include "ObjectiveFunctionTemplate.hpp"
00048 #include "MaxTemplate.hpp"
00049 #include "MsqTimer.hpp"
00050 #include "MsqDebug.hpp"
00051 #include "PatchSet.hpp"
00052 #include "PatchData.hpp"
00053 #include "ParallelHelperInterface.hpp"
00054 #include <algorithm>
00055 
00056 namespace MBMesquite
00057 {
00058 
00059 extern int get_parallel_rank();
00060 extern int get_parallel_size();
00061 extern void parallel_barrier();
00062 
00063 VertexMover::VertexMover( ObjectiveFunction* OF ) : QualityImprover(), objFuncEval( OF ), jacobiOpt( false ) {}
00064 
00065 VertexMover::~VertexMover() {}
00066 
00067 /*
00068 
00069     +-----------+
00070     |Reset Outer|
00071     |Criterion  |
00072     +-----------+
00073           |
00074           V
00075           +
00076         /   \
00077        /Outer\  YES
00078 +--> <Criterion>-----> DONE
00079 |      \Done?/
00080 |       \   /
00081 |         +
00082 |         |NO
00083 |         V
00084 |   +-----------+
00085 1   |Reset Mesh |
00086 |   | Iteration |
00087 |   +-----------+
00088 |         |
00089 |         V
00090 |         +
00091 |       /  \
00092 |   NO /Next\
00093 +-----<Patch > <-----+
00094        \    /        |
00095         \  /         |
00096           +          |
00097        YES|          |
00098           V          |
00099     +-----------+    |
00100     |Reset Inner|    |
00101     |Criterion  |    2
00102     +-----------+    |
00103           |          |
00104           V          |
00105           +          |
00106         /   \        |
00107        /Inner\  YES  |
00108 +--> <Criterion>-----+    --------------+
00109 |      \Done?/                          |
00110 |       \   /                           |
00111 |         +                             |
00112 |         |NO                           |
00113 |         V                          Inside
00114 3   +-----------+                    Smoother
00115 |   |   Smooth  |                       |
00116 |   |   Patch   |                       |
00117 |   +-----------+                       |
00118 |         |                             |
00119 ----------+               --------------+
00120 
00121 */
00122 
00123 /*! \brief Improves the quality of the MeshSet, calling some
00124     methods specified in a class derived from VertexMover
00125 
00126     \param const MeshSet &: this MeshSet is looped over. Only the
00127     mutable data members are changed (such as currentVertexInd).
00128   */
00129 double VertexMover::loop_over_mesh( MeshDomainAssoc* mesh_and_domain, const Settings* settings, MsqError& err )
00130 {
00131     Mesh* mesh         = mesh_and_domain->get_mesh();
00132     MeshDomain* domain = mesh_and_domain->get_domain();
00133 
00134     TagHandle coord_tag      = 0;  // store uncommitted coords for jacobi optimization
00135     TagHandle* coord_tag_ptr = 0;
00136 
00137     TerminationCriterion* outer_crit = 0;
00138     TerminationCriterion* inner_crit = 0;
00139 
00140     // Clear culling flag, set hard fixed flag, etc on all vertices
00141     initialize_vertex_byte( mesh_and_domain, settings, err );
00142     MSQ_ERRZERO( err );
00143 
00144     // Get the patch data to use for the first iteration
00145     OFEvaluator& obj_func = get_objective_function_evaluator();
00146 
00147     // Check for impromer use of MaxTemplate
00148     ObjectiveFunctionTemplate* maxt_ptr = dynamic_cast< MaxTemplate* >( obj_func.get_objective_function() );
00149     if( maxt_ptr )
00150     {
00151         QualityImprover* ngqi_ptr = dynamic_cast< NonGradient* >( this );
00152         if( !ngqi_ptr )
00153             std::cout << "Warning: MaxTemplate results in non-differentiable objective function." << std::endl
00154                       << "   Therefore, it is best to use the NonGradient solver. Other Mesquite" << std::endl
00155                       << "   solvers require derivative information." << std::endl;
00156     }
00157 
00158     PatchData patch;
00159     patch.set_mesh( mesh );
00160     patch.set_domain( domain );
00161     if( settings ) patch.attach_settings( settings );
00162     bool one_patch = false, inner_crit_terminated, all_culled;
00163     std::vector< Mesh::VertexHandle > patch_vertices;
00164     std::vector< Mesh::ElementHandle > patch_elements;
00165     bool valid;
00166 
00167     PatchSet* patch_set = get_patch_set();
00168     if( !patch_set )
00169     {
00170         MSQ_SETERR( err )( "No PatchSet for QualityImprover!", MsqError::INVALID_STATE );
00171         return 0.0;
00172     }
00173     patch_set->set_mesh( mesh );
00174 
00175     std::vector< PatchSet::PatchHandle > patch_list;
00176     patch_set->get_patch_handles( patch_list, err );
00177     MSQ_ERRZERO( err );
00178 
00179     // check for inverted elements when using a barrietr target metric
00180     TQualityMetric* tqm_ptr        = NULL;
00181     TMetricBarrier* tm_ptr         = NULL;
00182     AWMetricBarrier* awm_ptr       = NULL;
00183     ElemSampleQM* sample_qm_ptr    = NULL;
00184     QualityMetric* qm_ptr          = NULL;
00185     TQualityMetric* pmeanp_ptr     = NULL;
00186     ElementMaxQM* elem_max_ptr     = NULL;
00187     ElementAvgQM* elem_avg_ptr     = NULL;
00188     ElementPMeanP* elem_pmeanp_ptr = NULL;
00189 
00190     ObjectiveFunctionTemplate* of_ptr = dynamic_cast< ObjectiveFunctionTemplate* >( obj_func.get_objective_function() );
00191     if( of_ptr ) qm_ptr = of_ptr->get_quality_metric();
00192     if( qm_ptr )
00193     {
00194         pmeanp_ptr      = dynamic_cast< TQualityMetric* >( qm_ptr );  // PMeanP case
00195         elem_max_ptr    = dynamic_cast< ElementMaxQM* >( qm_ptr );
00196         elem_avg_ptr    = dynamic_cast< ElementAvgQM* >( qm_ptr );
00197         elem_pmeanp_ptr = dynamic_cast< ElementPMeanP* >( qm_ptr );
00198     }
00199     if( elem_max_ptr )
00200         sample_qm_ptr = elem_max_ptr->get_quality_metric();
00201     else if( elem_pmeanp_ptr )
00202         sample_qm_ptr = elem_pmeanp_ptr->get_quality_metric();
00203     else if( elem_avg_ptr )
00204         sample_qm_ptr = elem_avg_ptr->get_quality_metric();
00205     else if( pmeanp_ptr )
00206     {
00207         tm_ptr  = dynamic_cast< TMetricBarrier* >( pmeanp_ptr->get_target_metric() );
00208         awm_ptr = dynamic_cast< AWMetricBarrier* >( pmeanp_ptr->get_target_metric() );
00209     }
00210 
00211     if( sample_qm_ptr || pmeanp_ptr )
00212     {
00213         if( !pmeanp_ptr )
00214         {
00215             tqm_ptr = dynamic_cast< TQualityMetric* >( sample_qm_ptr );
00216             if( tqm_ptr )
00217             {
00218                 tm_ptr  = dynamic_cast< TMetricBarrier* >( tqm_ptr->get_target_metric() );
00219                 awm_ptr = dynamic_cast< AWMetricBarrier* >( tqm_ptr->get_target_metric() );
00220             }
00221         }
00222         else
00223         {
00224             tqm_ptr = dynamic_cast< TQualityMetric* >( pmeanp_ptr );
00225         }
00226 
00227         if( tqm_ptr && ( tm_ptr || awm_ptr ) )
00228         {
00229             // check for inverted elements
00230             this->initialize( patch, err );
00231             std::vector< size_t > handles;
00232 
00233             // set up patch data
00234             std::vector< PatchSet::PatchHandle >::iterator patch_iter = patch_list.begin();
00235             while( patch_iter != patch_list.end() )
00236             {
00237                 do
00238                 {
00239                     patch_set->get_patch( *patch_iter, patch_elements, patch_vertices, err );
00240                     if( MSQ_CHKERR( err ) ) goto ERROR;
00241                     ++patch_iter;
00242                 } while( patch_elements.empty() && patch_iter != patch_list.end() );
00243 
00244                 patch.set_mesh_entities( patch_elements, patch_vertices, err );
00245                 if( MSQ_CHKERR( err ) ) goto ERROR;
00246 
00247                 qm_ptr->get_evaluations( patch, handles, true, err );  // MSQ_ERRFALSE(err);
00248 
00249                 // do actual check for inverted elements
00250                 std::vector< size_t >::const_iterator i;
00251                 double tvalue;
00252                 for( i = handles.begin(); i != handles.end(); ++i )
00253                 {
00254                     bool result = tqm_ptr->evaluate( patch, *i, tvalue, err );
00255                     if( MSQ_CHKERR( err ) || !result ) return false;  // inverted element detected
00256                 }
00257             }
00258         }
00259     }
00260 
00261     // Get termination criteria
00262     outer_crit = this->get_outer_termination_criterion();
00263     inner_crit = this->get_inner_termination_criterion();
00264     if( outer_crit == 0 )
00265     {
00266         MSQ_SETERR( err )( "Termination Criterion pointer is Null", MsqError::INVALID_STATE );
00267         return 0.;
00268     }
00269     if( inner_crit == 0 )
00270     {
00271         MSQ_SETERR( err )
00272         ( "Termination Criterion pointer for inner loop is Null", MsqError::INVALID_STATE );
00273         return 0.;
00274     }
00275 
00276     // Set Termination Criterion defaults if no other Criterion is set
00277     if( !outer_crit->criterion_is_set() ) outer_crit->add_iteration_limit( 1 );
00278     if( !inner_crit->criterion_is_set() ) inner_crit->add_iteration_limit( 10 );
00279 
00280     // If using a local patch, suppress output of inner termination criterion
00281     if( patch_list.size() > 1 )
00282         inner_crit->set_debug_output_level( 3 );
00283     else
00284         one_patch = true;
00285 
00286     if( jacobiOpt )
00287     {
00288         coord_tag = get_jacobi_coord_tag( mesh, err );
00289         MSQ_ERRZERO( err );
00290         coord_tag_ptr = &coord_tag;
00291     }
00292 
00293     // Initialize outer loop
00294 
00295     this->initialize( patch, err );
00296     if( MSQ_CHKERR( err ) ) goto ERROR;
00297 
00298     valid = obj_func.initialize( mesh_and_domain, settings, patch_set, err );
00299     if( MSQ_CHKERR( err ) ) goto ERROR;
00300     if( !valid )
00301     {
00302         MSQ_SETERR( err )
00303         ( "ObjectiveFunction initialization failed.  Mesh "
00304           "invalid at one or more sample points.",
00305           MsqError::INVALID_MESH );
00306         goto ERROR;
00307     }
00308 
00309     outer_crit->reset_outer( mesh, domain, obj_func, settings, err );
00310     if( MSQ_CHKERR( err ) ) goto ERROR;
00311 
00312     // if only one patch, get the patch now
00313     if( one_patch )
00314     {
00315         patch_set->get_patch( patch_list[0], patch_elements, patch_vertices, err );
00316         if( MSQ_CHKERR( err ) ) goto ERROR;
00317         patch.set_mesh_entities( patch_elements, patch_vertices, err );
00318         if( MSQ_CHKERR( err ) ) goto ERROR;
00319     }
00320 
00321     // Loop until outer termination criterion is met
00322     inner_crit_terminated = false;
00323     while( !outer_crit->terminate() )
00324     {
00325         if( inner_crit_terminated )
00326         {
00327             MSQ_SETERR( err )
00328             ( "Inner termiation criterion satisfied for all patches "
00329               "without meeting outer termination criterion.  This is "
00330               "an infinite loop.  Aborting.",
00331               MsqError::INVALID_STATE );
00332             break;
00333         }
00334         inner_crit_terminated = true;
00335         all_culled            = true;
00336 
00337         int num_patches = 0;
00338         // Loop over each patch
00339         std::vector< PatchSet::PatchHandle >::iterator p_iter = patch_list.begin();
00340         while( p_iter != patch_list.end() )
00341         {
00342             if( !one_patch )
00343             {  // if only one patch (global) re-use the previous one
00344                 // loop until we get a non-empty patch.  patch will be empty
00345                 // for culled vertices with element-on-vertex patches
00346                 do
00347                 {
00348                     patch_set->get_patch( *p_iter, patch_elements, patch_vertices, err );
00349                     if( MSQ_CHKERR( err ) ) goto ERROR;
00350                     ++p_iter;
00351                 } while( patch_elements.empty() && p_iter != patch_list.end() );
00352 
00353                 if( patch_elements.empty() )
00354                 {  // no more non-culled vertices
00355                     if( 0 ) std::cout << "P[" << get_parallel_rank() << "] tmp srk all vertices culled." << std::endl;
00356                     break;
00357                 }
00358 
00359                 all_culled = false;
00360                 patch.set_mesh_entities( patch_elements, patch_vertices, err );
00361                 if( MSQ_CHKERR( err ) ) goto ERROR;
00362             }
00363             else
00364             {
00365                 ++p_iter;
00366                 all_culled = false;
00367             }
00368 
00369             ++num_patches;
00370 
00371             // Initialize for inner iteration
00372 
00373             this->initialize_mesh_iteration( patch, err );
00374             if( MSQ_CHKERR( err ) ) goto ERROR;
00375 
00376             obj_func.reset();
00377 
00378             outer_crit->reset_patch( patch, err );
00379             if( MSQ_CHKERR( err ) ) goto ERROR;
00380 
00381             inner_crit->reset_inner( patch, obj_func, err );
00382             if( MSQ_CHKERR( err ) ) goto ERROR;
00383 
00384             inner_crit->reset_patch( patch, err );
00385             if( MSQ_CHKERR( err ) ) goto ERROR;
00386 
00387             // Don't even call optimizer if inner termination
00388             // criterion has already been met.
00389             if( !inner_crit->terminate() )
00390             {
00391                 inner_crit_terminated = false;
00392 
00393                 // Call optimizer - should loop on inner_crit->terminate()
00394                 this->optimize_vertex_positions( patch, err );
00395                 if( MSQ_CHKERR( err ) ) goto ERROR;
00396 
00397                 // Update for changes during inner iteration
00398                 // (during optimizer loop)
00399 
00400                 outer_crit->accumulate_patch( patch, err );
00401                 if( MSQ_CHKERR( err ) ) goto ERROR;
00402 
00403                 inner_crit->cull_vertices( patch, obj_func, err );
00404                 if( MSQ_CHKERR( err ) ) goto ERROR;
00405 
00406                 // FIXME
00407                 if( 0 )
00408                 {
00409                     inner_crit->cull_vertices_global( patch, mesh, domain, settings, obj_func, err );
00410                     if( MSQ_CHKERR( err ) ) goto ERROR;
00411                 }
00412 
00413                 patch.update_mesh( err, coord_tag_ptr );
00414                 if( MSQ_CHKERR( err ) ) goto ERROR;
00415             }
00416         }
00417 
00418         if( jacobiOpt ) commit_jacobi_coords( coord_tag, mesh, err );
00419 
00420         this->terminate_mesh_iteration( patch, err );
00421         if( MSQ_CHKERR( err ) ) goto ERROR;
00422 
00423         outer_crit->accumulate_outer( mesh, domain, obj_func, settings, err );
00424         if( MSQ_CHKERR( err ) ) goto ERROR;
00425 
00426         if( all_culled ) break;
00427     }
00428 
00429 ERROR:
00430     if( jacobiOpt ) mesh->tag_delete( coord_tag, err );
00431 
00432     // call the criteria's cleanup funtions.
00433     if( outer_crit ) outer_crit->cleanup( mesh, domain, err );
00434     if( inner_crit ) inner_crit->cleanup( mesh, domain, err );
00435     // call the optimization cleanup function.
00436     this->cleanup();
00437 
00438     return 0.;
00439 }
00440 
00441 static void checkpoint_bytes( Mesh* mesh, std::vector< unsigned char >& saved_bytes, MsqError& err )
00442 {
00443     std::vector< Mesh::VertexHandle > vertexHandlesArray;
00444     mesh->get_all_vertices( vertexHandlesArray, err );MSQ_ERRRTN( err );
00445     saved_bytes.resize( vertexHandlesArray.size() );
00446     mesh->vertices_get_byte( &vertexHandlesArray[0], &saved_bytes[0], vertexHandlesArray.size(), err );MSQ_ERRRTN( err );
00447 }
00448 
00449 static void restore_bytes( Mesh* mesh, std::vector< unsigned char >& saved_bytes, MsqError& err )
00450 {
00451     std::vector< Mesh::VertexHandle > vertexHandlesArray;
00452     mesh->get_all_vertices( vertexHandlesArray, err );MSQ_ERRRTN( err );
00453     mesh->vertices_set_byte( &vertexHandlesArray[0], &saved_bytes[0], vertexHandlesArray.size(), err );MSQ_ERRRTN( err );
00454 }
00455 
00456 static void save_or_restore_debug_state( bool save )
00457 {
00458     static bool debug[3] = { false, false, false };
00459     if( save )
00460     {
00461         debug[0] = MsqDebug::get( 1 );
00462         debug[1] = MsqDebug::get( 2 );
00463         debug[2] = MsqDebug::get( 3 );
00464     }
00465     else
00466     {
00467         if( debug[0] ) MsqDebug::enable( 1 );
00468         if( debug[1] ) MsqDebug::enable( 2 );
00469         if( debug[2] ) MsqDebug::enable( 3 );
00470     }
00471 }
00472 
00473 /*! \brief Improves the quality of the MeshSet, calling some
00474     methods specified in a class derived from VertexMover
00475 
00476     \param const MeshSet &: this MeshSet is looped over. Only the
00477     mutable data members are changed (such as currentVertexInd).
00478   */
00479 double VertexMover::loop_over_mesh( ParallelMesh* mesh, MeshDomain* domain, const Settings* settings, MsqError& err )
00480 {
00481     std::vector< size_t > junk;
00482     Mesh::VertexHandle vertex_handle;
00483     TagHandle coord_tag      = 0;  // store uncommitted coords for jacobi optimization
00484     TagHandle* coord_tag_ptr = 0;
00485     int outer_iter           = 0;
00486     int inner_iter           = 0;
00487     bool one_patch           = false;
00488 
00489     // Clear culling flag, set hard fixed flag, etc on all vertices
00490     MeshDomainAssoc mesh_and_domain = MeshDomainAssoc( (Mesh*)mesh, 0 );
00491     initialize_vertex_byte( &mesh_and_domain, settings, err );
00492     MSQ_ERRZERO( err );
00493 
00494     // Get the patch data to use for the first iteration
00495     OFEvaluator& obj_func = get_objective_function_evaluator();
00496 
00497     PatchData patch;
00498     patch.set_mesh( (Mesh*)mesh );
00499     patch.set_domain( domain );
00500     patch.attach_settings( settings );
00501 
00502     ParallelHelper* helper = mesh->get_parallel_helper();
00503     if( !helper )
00504     {
00505         MSQ_SETERR( err )( "No ParallelHelper instance", MsqError::INVALID_STATE );
00506         return 0;
00507     }
00508 
00509     helper->smoothing_init( err );
00510     MSQ_ERRZERO( err );
00511 
00512     bool inner_crit_terminated, all_culled;
00513     std::vector< Mesh::VertexHandle > patch_vertices;
00514     std::vector< Mesh::ElementHandle > patch_elements;
00515     std::vector< Mesh::VertexHandle > fixed_vertices;
00516     std::vector< Mesh::VertexHandle > free_vertices;
00517 
00518     // Get termination criteria
00519     TerminationCriterion* outer_crit = this->get_outer_termination_criterion();
00520     TerminationCriterion* inner_crit = this->get_inner_termination_criterion();
00521     if( outer_crit == 0 )
00522     {
00523         MSQ_SETERR( err )( "Termination Criterion pointer is Null", MsqError::INVALID_STATE );
00524         return 0.;
00525     }
00526     if( inner_crit == 0 )
00527     {
00528         MSQ_SETERR( err )
00529         ( "Termination Criterion pointer for inner loop is Null", MsqError::INVALID_STATE );
00530         return 0.;
00531     }
00532 
00533     PatchSet* patch_set = get_patch_set();
00534     if( !patch_set )
00535     {
00536         MSQ_SETERR( err )( "No PatchSet for QualityImprover!", MsqError::INVALID_STATE );
00537         return 0.0;
00538     }
00539     patch_set->set_mesh( (Mesh*)mesh );
00540 
00541     std::vector< PatchSet::PatchHandle > patch_list;
00542     patch_set->get_patch_handles( patch_list, err );
00543     MSQ_ERRZERO( err );
00544 
00545     if( patch_list.size() > 1 )
00546         inner_crit->set_debug_output_level( 3 );
00547     else
00548         one_patch = true;
00549 
00550     if( jacobiOpt )
00551     {
00552         coord_tag = get_jacobi_coord_tag( mesh, err );
00553         MSQ_ERRZERO( err );
00554         coord_tag_ptr = &coord_tag;
00555     }
00556 
00557     // parallel error checking
00558     MsqError perr;
00559     bool pdone = false;
00560 
00561 #define PERROR_COND continue
00562 
00563     // Initialize outer loop
00564 
00565     this->initialize( patch, err );
00566     if( MSQ_CHKERR( err ) )
00567     {
00568         MSQ_SETERR( perr )( "initialize patch", MsqError::INVALID_STATE );
00569     }  // goto ERROR;
00570 
00571     MeshDomainAssoc mesh_and_domain2 = MeshDomainAssoc( (Mesh*)mesh, domain );
00572     obj_func.initialize( &mesh_and_domain2, settings, patch_set, err );
00573     if( MSQ_CHKERR( err ) )
00574     {
00575         MSQ_SETERR( perr )( "initialize obj_func", MsqError::INVALID_STATE );
00576     }  // goto ERROR;
00577 
00578     outer_crit->reset_outer( (Mesh*)mesh, domain, obj_func, settings, err );
00579     if( MSQ_CHKERR( err ) )
00580     {
00581         MSQ_SETERR( perr )( "reset_outer", MsqError::INVALID_STATE );
00582     }  // goto ERROR;
00583 
00584     // Loop until outer termination criterion is met
00585     inner_crit_terminated = false;
00586     all_culled            = false;
00587     for( ;; )
00588     {
00589         if( 0 )
00590             std::cout << "P[" << get_parallel_rank() << "] tmp srk inner_iter= " << inner_iter
00591                       << " outer_iter= " << outer_iter << std::endl;
00592 
00593         // PERROR:
00594 
00595         if( MSQ_CHKERR( perr ) )
00596         {
00597             std::cout << "P[" << get_parallel_rank() << "] VertexMover::loop_over_mesh found parallel error: " << perr
00598                       << "\n quitting... pdone= " << pdone << std::endl;
00599             pdone = true;
00600         }
00601 
00602         helper->communicate_any_true( pdone, err );
00603 
00604         if( 0 )
00605             std::cout << "P[" << get_parallel_rank() << "] tmp srk inner_iter= " << inner_iter
00606                       << " outer_iter= " << outer_iter << " pdone= " << pdone << std::endl;
00607 
00608         if( pdone )
00609         {
00610             std::cout << "P[" << get_parallel_rank()
00611                       << "] VertexMover::loop_over_mesh found parallel error, quitting... pdone= " << pdone
00612                       << std::endl;
00613             MSQ_SETERR( err )( "PARALLEL ERROR", MsqError::PARALLEL_ERROR );
00614             break;
00615         }
00616 
00617         ++outer_iter;
00618 
00619         /// [email protected] 1/19/12: the logic here was changed so that all proc's must agree
00620         ///   on the values used for outer and inner termination before the iteration is stopped.
00621         ///   Previously, the ParallelHelper::communicate_all_true method returned true if any
00622         ///   proc sent it a true value, which seems to be a bug, at least in the name of the
00623         ///   method. The method has been changed to return true only if all proc's values are true.
00624         ///   In the previous version, this meant that if any proc hit its inner or outer
00625         ///   termination criterion, the loop was exited, and thus some parts of the mesh
00626         ///   are potentially left unconverged.  Also, if the outer criterion was satisfied on
00627         ///   part of the mesh (say a uniform part), the iterations were not executed at all.
00628         /// Also, changed name of "did_some" to "inner_crit_terminated", and flipped its boolean
00629         ///   value to be consistent with the name - for readability and for correctness since
00630         ///   we want to communicate a true value through the helper.
00631 
00632         bool outer_crit_terminated       = outer_crit->terminate();
00633         bool outer_crit_terminated_local = outer_crit_terminated;
00634         helper->communicate_all_true( outer_crit_terminated, err );
00635 
00636         bool inner_crit_terminated_local = inner_crit_terminated;
00637         helper->communicate_all_true( inner_crit_terminated, err );
00638 
00639         bool all_culled_local = all_culled;
00640         helper->communicate_all_true( all_culled, err );
00641 
00642         bool done = all_culled || outer_crit_terminated;
00643         if( inner_crit_terminated )
00644         {
00645             MSQ_SETERR( err )
00646             ( "Inner termination criterion satisfied for all patches "
00647               "without meeting outer termination criterion.  This is "
00648               "an infinite loop.  Aborting.",
00649               MsqError::INVALID_STATE );
00650             done = true;
00651             helper->communicate_any_true( done, err );
00652         }
00653 
00654         bool local_done = done;
00655 
00656         helper->communicate_all_true( done, err );
00657 
00658         if( 0 )
00659             std::cout << "P[" << get_parallel_rank() << "] tmp srk done= " << done << " local_done= " << local_done
00660                       << " all_culled= " << all_culled << " outer_crit->terminate()= " << outer_crit->terminate()
00661                       << " outer_term= " << outer_crit_terminated
00662                       << " outer_term_local= " << outer_crit_terminated_local
00663                       << " inner_crit_terminated = " << inner_crit_terminated
00664                       << " inner_crit_terminated_local = " << inner_crit_terminated_local
00665                       << " all_culled = " << all_culled << " all_culled_local = " << all_culled_local << std::endl;
00666 
00667         if( MSQ_CHKERR( err ) )
00668         {
00669             MSQ_SETERR( perr )( "loop start", MsqError::INVALID_STATE );
00670         }  // goto ERROR;
00671 
00672         if( done ) break;
00673 
00674         inner_crit_terminated = true;
00675         all_culled            = true;
00676 
00677         ///*** smooth the interior ***////
00678 
00679         // get the fixed vertices (i.e. the ones *not* part of the first independent set)
00680         helper->compute_first_independent_set( fixed_vertices );
00681 
00682         // sort the fixed vertices
00683         std::sort( fixed_vertices.begin(), fixed_vertices.end() );
00684 
00685         // Loop over each patch
00686         if( 0 && MSQ_DBG( 2 ) )
00687             std::cout << "P[" << get_parallel_rank() << "] tmp srk number of patches = " << patch_list.size()
00688                       << " inner_iter= " << inner_iter << " outer_iter= " << outer_iter
00689                       << " inner.globalInvertedCount = " << inner_crit->globalInvertedCount
00690                       << " outer.globalInvertedCount = " << outer_crit->globalInvertedCount
00691                       << " inner.patchInvertedCount = " << inner_crit->patchInvertedCount
00692                       << " outer.patchInvertedCount = " << outer_crit->patchInvertedCount << std::endl;
00693 
00694         save_or_restore_debug_state( true );
00695         // MsqDebug::disable_all();
00696 
00697         int num_patches = 0;
00698 
00699         std::vector< PatchSet::PatchHandle >::iterator p_iter = patch_list.begin();
00700         while( p_iter != patch_list.end() )
00701         {
00702 
00703             // loop until we get a non-empty patch.  patch will be empty
00704             // for culled vertices with element-on-vertex patches
00705             do
00706             {
00707                 patch_set->get_patch( *p_iter, patch_elements, patch_vertices, err );
00708                 if( MSQ_CHKERR( err ) )
00709                 {
00710                     MSQ_SETERR( perr )( "get_patch", MsqError::INVALID_STATE );
00711                     PERROR_COND;
00712                 }  // goto ERROR;
00713                 ++p_iter;
00714             } while( patch_elements.empty() && p_iter != patch_list.end() );
00715 
00716             if( patch_elements.empty() )
00717             {  // no more non-culled vertices
00718                 if( 0 ) std::cout << "P[" << get_parallel_rank() << "] tmp srk all vertices culled." << std::endl;
00719                 break;
00720             }
00721 
00722             if( patch_vertices.empty() )  // global patch hack (means all mesh vertices)
00723             {
00724                 mesh->get_all_vertices( patch_vertices, err );
00725             }
00726 
00727             free_vertices.clear();
00728 
00729             for( size_t i = 0; i < patch_vertices.size(); ++i )
00730                 if( !std::binary_search( fixed_vertices.begin(), fixed_vertices.end(), patch_vertices[i] ) )
00731                     free_vertices.push_back( patch_vertices[i] );
00732 
00733             if( free_vertices.empty() )
00734             {  // all vertices were fixed -> skip patch
00735                 continue;
00736             }
00737 
00738             ++num_patches;
00739             all_culled = false;
00740             patch.set_mesh_entities( patch_elements, free_vertices, err );
00741             if( MSQ_CHKERR( err ) )
00742             {
00743                 MSQ_SETERR( perr )( "set_mesh_entities", MsqError::INVALID_STATE );
00744                 PERROR_COND;
00745             }  // goto ERROR;
00746 
00747             // Initialize for inner iteration
00748 
00749             this->initialize_mesh_iteration( patch, err );
00750             if( MSQ_CHKERR( err ) )
00751             {
00752                 MSQ_SETERR( perr )( "initialize_mesh_iteration", MsqError::INVALID_STATE );
00753                 PERROR_COND;
00754             }  // goto ERROR;
00755 
00756             obj_func.reset();
00757 
00758             outer_crit->reset_patch( patch, err );
00759             if( MSQ_CHKERR( err ) )
00760             {
00761                 MSQ_SETERR( perr )( "reset_patch outer", MsqError::INVALID_STATE );
00762                 PERROR_COND;
00763             }  // goto ERROR;
00764 
00765             inner_crit->reset_inner( patch, obj_func, err );
00766             if( MSQ_CHKERR( err ) )
00767             {
00768                 MSQ_SETERR( perr )( "reset_inner", MsqError::INVALID_STATE );
00769                 PERROR_COND;
00770             }  // goto ERROR;
00771 
00772             inner_crit->reset_patch( patch, err );
00773             if( MSQ_CHKERR( err ) )
00774             {
00775                 MSQ_SETERR( perr )( "inner reset_patch", MsqError::INVALID_STATE );
00776                 PERROR_COND;
00777             }  // goto ERROR;
00778 
00779             // Don't even call optimizer if inner termination
00780             // criterion has already been met.
00781             if( !inner_crit->terminate() )
00782             {
00783                 inner_crit_terminated = false;
00784                 if( one_patch ) ++inner_iter;
00785 
00786                 // Call optimizer - should loop on inner_crit->terminate()
00787                 // size_t num_vert=patch.num_free_vertices();
00788                 // std::cout << "P[" << get_parallel_rank() << "] tmp srk VertexMover num_vert= " <<
00789                 // num_vert << std::endl;
00790 
00791                 this->optimize_vertex_positions( patch, err );
00792                 if( MSQ_CHKERR( err ) )
00793                 {
00794                     MSQ_SETERR( perr )( "optimize_vertex_positions", MsqError::INVALID_STATE );
00795                     PERROR_COND;
00796                 }  // goto ERROR;
00797 
00798                 // Update for changes during inner iteration
00799                 // (during optimizer loop)
00800 
00801                 outer_crit->accumulate_patch( patch, err );
00802                 if( MSQ_CHKERR( err ) )
00803                 {
00804                     MSQ_SETERR( perr )( "outer accumulate_patch", MsqError::INVALID_STATE );
00805                     PERROR_COND;
00806                 }  // goto ERROR;
00807 
00808                 inner_crit->cull_vertices( patch, obj_func, err );
00809                 if( MSQ_CHKERR( err ) )
00810                 {
00811                     MSQ_SETERR( perr )( "inner cull_vertices", MsqError::INVALID_STATE );
00812                     PERROR_COND;
00813                 }  // goto ERROR;
00814 
00815                 // experimental...
00816                 if( 0 )
00817                 {
00818                     inner_crit->cull_vertices_global( patch, mesh, domain, settings, obj_func, err );
00819                     if( MSQ_CHKERR( err ) )
00820                     {
00821                         MSQ_SETERR( perr )( "cull_vertices_global", MsqError::INVALID_STATE );
00822                         PERROR_COND;
00823                     }  // goto ERROR;
00824                 }
00825 
00826                 patch.update_mesh( err, coord_tag_ptr );
00827                 if( MSQ_CHKERR( err ) )
00828                 {
00829                     MSQ_SETERR( perr )( "update_mesh", MsqError::INVALID_STATE );
00830                     PERROR_COND;
00831                 }  // goto ERROR;
00832             }
00833         }  // while(p_iter....
00834 
00835         save_or_restore_debug_state( false );
00836 
00837         if( 1 )
00838         {
00839             bool pdone_inner = false;
00840 
00841             if( MSQ_CHKERR( perr ) )
00842             {
00843                 std::cout << "P[" << get_parallel_rank()
00844                           << "] VertexMover::loop_over_mesh found parallel error: " << perr
00845                           << "\n quitting... pdone_inner= " << pdone_inner << std::endl;
00846                 pdone_inner = true;
00847             }
00848 
00849             helper->communicate_any_true( pdone_inner, err );
00850 
00851             if( 0 )
00852                 std::cout << "P[" << get_parallel_rank() << "] tmp srk inner_iter= " << inner_iter
00853                           << " outer_iter= " << outer_iter << " pdone_inner= " << pdone_inner << std::endl;
00854 
00855             if( pdone_inner )
00856             {
00857                 if( 0 )
00858                     std::cout << "P[" << get_parallel_rank()
00859                               << "] tmp srk found parallel error, quitting... pdone_inner= " << pdone_inner
00860                               << std::endl;
00861                 MSQ_SETERR( err )( "PARALLEL ERROR", MsqError::PARALLEL_ERROR );
00862                 break;
00863             }
00864         }
00865 
00866         /// [email protected] save vertex bytes since boundary smoothing changes them
00867         std::vector< unsigned char > saved_bytes;
00868         checkpoint_bytes( mesh, saved_bytes, err );
00869         if( MSQ_CHKERR( err ) )
00870         {
00871             MSQ_SETERR( perr )( "checkpoint_bytes ", MsqError::INVALID_STATE );
00872             PERROR_COND;
00873         }  // goto ERROR;
00874 
00875         helper->communicate_first_independent_set( err );
00876         if( MSQ_CHKERR( err ) )
00877         {
00878             MSQ_SETERR( perr )( "communicate_first_independent_set ", MsqError::INVALID_STATE );
00879             PERROR_COND;
00880         }  // goto ERROR;
00881 
00882         ///*** smooth the boundary ***////
00883         save_or_restore_debug_state( true );
00884         MsqDebug::disable_all();
00885 
00886         while( helper->compute_next_independent_set() )
00887         {
00888             // Loop over all boundary elements
00889             while( helper->get_next_partition_boundary_vertex( vertex_handle ) )
00890             {
00891 
00892                 patch_vertices.clear();
00893                 patch_vertices.push_back( vertex_handle );
00894                 patch_elements.clear();
00895                 mesh->vertices_get_attached_elements( &vertex_handle, 1, patch_elements, junk, err );
00896 
00897                 all_culled = false;
00898                 patch.set_mesh_entities( patch_elements, patch_vertices, err );
00899 
00900                 if( MSQ_CHKERR( err ) )
00901                 {
00902                     MSQ_SETERR( perr )( "set_mesh_entities 2 ", MsqError::INVALID_STATE );
00903                     PERROR_COND;
00904                 }  // goto ERROR;
00905 
00906                 // Initialize for inner iteration
00907 
00908                 this->initialize_mesh_iteration( patch, err );
00909                 if( MSQ_CHKERR( err ) )
00910                 {
00911                     MSQ_SETERR( perr )( " initialize_mesh_iteration 2", MsqError::INVALID_STATE );
00912                     PERROR_COND;
00913                 }  // goto ERROR;
00914 
00915                 obj_func.reset();
00916 
00917                 outer_crit->reset_patch( patch, err );
00918                 if( MSQ_CHKERR( err ) )
00919                 {
00920                     MSQ_SETERR( perr )( "outer reset_patch 2 ", MsqError::INVALID_STATE );
00921                     PERROR_COND;
00922                 }  // goto ERROR;
00923 
00924                 inner_crit->reset_inner( patch, obj_func, err );
00925                 if( MSQ_CHKERR( err ) )
00926                 {
00927                     MSQ_SETERR( perr )( " inner reset_inner 2", MsqError::INVALID_STATE );
00928                     PERROR_COND;
00929                 }  // goto ERROR;
00930 
00931                 inner_crit->reset_patch( patch, err );
00932                 if( MSQ_CHKERR( err ) )
00933                 {
00934                     MSQ_SETERR( perr )( " inner_crit reset_patch 2", MsqError::INVALID_STATE );
00935                     PERROR_COND;
00936                 }  // goto ERROR;
00937 
00938                 // Don't even call optimizer if inner termination
00939                 // criterion has already been met.
00940                 if( !inner_crit->terminate() )
00941                 {
00942                     inner_crit_terminated = false;
00943 
00944                     // Call optimizer - should loop on inner_crit->terminate()
00945                     this->optimize_vertex_positions( patch, err );
00946                     if( MSQ_CHKERR( err ) )
00947                     {
00948                         MSQ_SETERR( perr )
00949                         ( " optimize_vertex_positions 2", MsqError::INVALID_STATE );
00950                         PERROR_COND;
00951                     }  // goto ERROR;
00952 
00953                     // Update for changes during inner iteration
00954                     // (during optimizer loop)
00955 
00956                     outer_crit->accumulate_patch( patch, err );
00957                     if( MSQ_CHKERR( err ) )
00958                     {
00959                         MSQ_SETERR( perr )( " outer accumulate_patch 2", MsqError::INVALID_STATE );
00960                         PERROR_COND;
00961                     }  // goto ERROR;
00962 
00963                     inner_crit->cull_vertices( patch, obj_func, err );
00964                     if( MSQ_CHKERR( err ) )
00965                     {
00966                         MSQ_SETERR( perr )( " inner cull_vertices", MsqError::INVALID_STATE );
00967                         PERROR_COND;
00968                     }  // goto ERROR;
00969 
00970                     // FIXME
00971                     if( 0 )
00972                     {
00973                         inner_crit->cull_vertices_global( patch, mesh, domain, settings, obj_func, err );
00974                         if( MSQ_CHKERR( err ) )
00975                         {
00976                             MSQ_SETERR( perr )
00977                             ( " cull_vertices_global 2 ", MsqError::INVALID_STATE );
00978                             PERROR_COND;
00979                         }  // goto ERROR;
00980                     }
00981 
00982                     patch.update_mesh( err, coord_tag_ptr );
00983                     if( MSQ_CHKERR( err ) )
00984                     {
00985                         MSQ_SETERR( perr )( " update_mesh 2", MsqError::INVALID_STATE );
00986                         PERROR_COND;
00987                     }  // goto ERROR;
00988                 }
00989             }
00990             helper->communicate_next_independent_set( err );
00991             if( MSQ_CHKERR( err ) )
00992             {
00993                 MSQ_SETERR( perr )
00994                 ( " communicate_next_independent_set 2", MsqError::INVALID_STATE );
00995                 PERROR_COND;
00996             }  // goto ERROR;
00997         }      // while(helper->compute_next_independent_set())
00998 
00999         save_or_restore_debug_state( false );
01000 
01001         // if (!get_parallel_rank())
01002         // std::cout << "P[" << get_parallel_rank() << "] tmp srk num_patches= " << num_patches <<
01003         // std::endl;
01004 
01005         /// [email protected] restore vertex bytes since boundary smoothing changes them
01006         restore_bytes( mesh, saved_bytes, err );
01007         if( MSQ_CHKERR( err ) )
01008         {
01009             MSQ_SETERR( perr )( " restore_bytes", MsqError::INVALID_STATE );
01010             PERROR_COND;
01011         }  // goto ERROR;
01012 
01013         if( jacobiOpt ) commit_jacobi_coords( coord_tag, mesh, err );
01014 
01015         this->terminate_mesh_iteration( patch, err );
01016         if( MSQ_CHKERR( err ) )
01017         {
01018             MSQ_SETERR( perr )( " terminate_mesh_iteration", MsqError::INVALID_STATE );
01019             PERROR_COND;
01020         }  // goto ERROR;
01021 
01022         outer_crit->accumulate_outer( mesh, domain, obj_func, settings, err );
01023         if( MSQ_CHKERR( err ) )
01024         {
01025             MSQ_SETERR( perr )( " outer_crit accumulate_outer", MsqError::INVALID_STATE );
01026             PERROR_COND;
01027         }  // goto ERROR;
01028     }
01029 
01030     // ERROR:
01031 
01032     if( MSQ_CHKERR( err ) )
01033     {
01034         std::cout << "P[" << get_parallel_rank() << "] VertexMover::loop_over_mesh error = " << err.error_message()
01035                   << std::endl;
01036     }
01037 
01038     if( jacobiOpt ) mesh->tag_delete( coord_tag, err );
01039 
01040     // call the criteria's cleanup funtions.
01041     outer_crit->cleanup( mesh, domain, err );MSQ_CHKERR( err );
01042     inner_crit->cleanup( mesh, domain, err );MSQ_CHKERR( err );
01043     // call the optimization cleanup function.
01044     this->cleanup();
01045     // close the helper
01046     helper->smoothing_close( err );MSQ_CHKERR( err );
01047 
01048     return 0.;
01049 }
01050 
01051 void VertexMover::initialize_queue( MeshDomainAssoc* mesh_and_domain, const Settings* settings, MsqError& err )
01052 {
01053     QualityImprover::initialize_queue( mesh_and_domain, settings, err );MSQ_ERRRTN( err );
01054     objFuncEval.initialize_queue( mesh_and_domain, settings, err );MSQ_ERRRTN( err );
01055 }
01056 
01057 TagHandle VertexMover::get_jacobi_coord_tag( Mesh* mesh, MsqError& err )
01058 {
01059     // Get tag handle
01060     const char tagname[] = "msq_jacobi_temp_coords";
01061     TagHandle tag        = mesh->tag_create( tagname, Mesh::DOUBLE, 3, 0, err );
01062     MSQ_ERRZERO( err );
01063     /* VertexMover will always delete the tag when it is done, so it is probably
01064        best not to accept an existing tag
01065   if (err.error_code() == TAG_ALREADY_EXISTS) {
01066     err.clear();
01067     tag = tag_get( tagname, err ); MSQ_ERRZERO(err);
01068     std::string name;
01069     Mesh::TagType type;
01070     unsigned length;
01071     mesh->tag_properties( tag, name, type, length, err ); MSQ_ERRZERO(err);
01072     if (type != Mesh::DOUBLE || length != 3) {
01073       MSQ_SETERR(err)(TAG_ALREADY_EXISTS,
01074                      "Tag \"%s\" already exists with invalid type",
01075                      tagname);
01076       return 0;
01077     }
01078   }
01079     */
01080 
01081     // Initialize tag value with initial vertex coordinates so that
01082     // vertices that never get moved end up with the correct coords.
01083     std::vector< Mesh::VertexHandle > vertices;
01084     mesh->get_all_vertices( vertices, err );
01085     MSQ_ERRZERO( err );
01086     // remove fixed vertices
01087     // to avoid really huge arrays (especially since we need to copy
01088     // coords out of annoying MsqVertex class to double array), work
01089     // in blocks
01090     const size_t blocksize = 4096;
01091     std::vector< bool > fixed( blocksize );
01092     MsqVertex coords[blocksize];
01093     double tag_data[3 * blocksize];
01094     for( size_t i = 0; i < vertices.size(); i += blocksize )
01095     {
01096         size_t count = std::min( blocksize, vertices.size() - i );
01097         // remove fixed vertices
01098         mesh->vertices_get_fixed_flag( &vertices[i], fixed, count, err );
01099         MSQ_ERRZERO( err );
01100         size_t w = 0;
01101         for( size_t j = 0; j < count; ++j )
01102             if( !fixed[j] ) vertices[i + w++] = vertices[i + j];
01103         count = w;
01104         // store tag data for free vertices
01105         mesh->vertices_get_coordinates( &vertices[i], coords, count, err );
01106         MSQ_ERRZERO( err );
01107         for( size_t j = 0; j < count; ++j )
01108         {
01109             tag_data[3 * j]     = coords[j][0];
01110             tag_data[3 * j + 1] = coords[j][1];
01111             tag_data[3 * j + 2] = coords[j][2];
01112         }
01113         mesh->tag_set_vertex_data( tag, count, &vertices[i], tag_data, err );
01114         MSQ_ERRZERO( err );
01115     }
01116 
01117     return tag;
01118 }
01119 
01120 void VertexMover::commit_jacobi_coords( TagHandle tag, Mesh* mesh, MsqError& err )
01121 {
01122     Vector3D coords;
01123     std::vector< Mesh::VertexHandle > vertices;
01124     mesh->get_all_vertices( vertices, err );MSQ_ERRRTN( err );
01125     std::vector< bool > fixed( vertices.size() );
01126     mesh->vertices_get_fixed_flag( &vertices[0], fixed, vertices.size(), err );
01127     for( size_t i = 0; i < vertices.size(); ++i )
01128     {
01129         if( !fixed[i] )
01130         {
01131             mesh->tag_get_vertex_data( tag, 1, &vertices[i], coords.to_array(), err );MSQ_ERRRTN( err );
01132             mesh->vertex_set_coordinates( vertices[i], coords, err );MSQ_ERRRTN( err );
01133         }
01134     }
01135 }
01136 
01137 }  // namespace MBMesquite
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines