MOAB: Mesh Oriented datABase
(version 5.4.1)
|
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