Loading [MathJax]/extensions/tex2jax.js
Mesh Oriented datABase  (version 5.5.1)
An array-based unstructured mesh library
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
LaplacianSmoother.cpp File Reference
#include <iostream>
#include <sstream>
#include "moab/Core.hpp"
#include "moab/Skinner.hpp"
#include "moab/CN.hpp"
#include "moab/ProgOptions.hpp"
#include "moab/CartVect.hpp"
#include "moab/NestedRefine.hpp"
#include "moab/VerdictWrapper.hpp"
#include "matrix.h"
+ Include dependency graph for LaplacianSmoother.cpp:

Go to the source code of this file.

Macros

#define WRITE_DEBUG_FILES
 
#define RC   MB_CHK_ERR( rval )
 
#define dbgprint(MSG)
 

Functions

ErrorCode perform_laplacian_smoothing (Core *mb, Range &cells, Range &verts, int dim, Tag fixed, bool use_hc=false, bool use_acc=false, int acc_method=1, int num_its=10, double rel_eps=1e-5, double alpha=0.0, double beta=0.5, int report_its=1)
 
ErrorCode hcFilter (Core *mb, moab::ParallelComm *pcomm, moab::Range &verts, int dim, Tag fixed, std::vector< double > &verts_o, std::vector< double > &verts_n, double alpha, double beta)
 
ErrorCode laplacianFilter (Core *mb, moab::ParallelComm *pcomm, moab::Range &verts, int dim, Tag fixed, std::vector< double > &verts_o, std::vector< double > &verts_n, bool use_updated=true)
 
int main (int argc, char **argv)
 

Variables

string test_file_name = string( "input/surfrandomtris-4part.h5m" )
 

Macro Definition Documentation

◆ dbgprint

#define dbgprint (   MSG)
Value:
do \ { \ if( !global_rank ) std::cerr << ( MSG ) << std::endl; \ } while( false )
Examples
LaplacianSmoother.cpp.

Definition at line 50 of file LaplacianSmoother.cpp.

◆ RC

#define RC   MB_CHK_ERR( rval )
Examples
LaplacianSmoother.cpp.

Definition at line 49 of file LaplacianSmoother.cpp.

◆ WRITE_DEBUG_FILES

#define WRITE_DEBUG_FILES

Definition at line 41 of file LaplacianSmoother.cpp.

Function Documentation

◆ hcFilter()

ErrorCode hcFilter ( Core mb,
moab::ParallelComm pcomm,
moab::Range verts,
int  dim,
Tag  fixed,
std::vector< double > &  verts_o,
std::vector< double > &  verts_n,
double  alpha,
double  beta 
)
Examples
LaplacianSmoother.cpp.

Definition at line 717 of file LaplacianSmoother.cpp.

726 { 727  ErrorCode rval; 728  std::vector< double > verts_hc( verts_o.size() ); 729  std::vector< int > fix_tag( verts.size() ); 730  731  // Perform Laplacian Smooth 732  rval = laplacianFilter( mb, pcomm, verts, dim, fixed, verts_o, verts_n ); 733  RC; 734  735  // Compute Differences 736  for( unsigned index = 0; index < verts_o.size(); ++index ) 737  { 738  verts_hc[index] = verts_n[index] - ( alpha * verts_n[index] + ( 1.0 - alpha ) * verts_o[index] ); 739  } 740  741  // filter verts down to owned ones and get fixed tag for them 742  Range owned_verts; 743 #ifdef MOAB_HAVE_MPI 744  if( pcomm->size() > 1 ) 745  { 746  rval = pcomm->filter_pstatus( verts, PSTATUS_NOT_OWNED, PSTATUS_NOT, -1, &owned_verts ); 747  if( rval != MB_SUCCESS ) return rval; 748  } 749  else 750 #endif 751  owned_verts = verts; 752  753  rval = mb->tag_get_data( fixed, owned_verts, &fix_tag[0] ); 754  RC; 755  756  int vindex = 0; 757  for( Range::const_iterator vit = owned_verts.begin(); vit != owned_verts.end(); ++vit, vindex++ ) 758  { 759  // if !fixed 760  if( fix_tag[vindex] ) continue; 761  762  const int index = verts.index( *vit ) * 3; 763  764  moab::Range adjverts, adjelems; 765  // Find the neighboring vertices (1-ring neighborhood) 766  rval = mb->get_adjacencies( &( *vit ), 1, dim, false, adjelems ); 767  RC; 768  rval = mb->get_connectivity( adjelems, adjverts ); 769  RC; 770  adjverts.erase( *vit ); 771  772  const int nadjs = adjverts.size(); 773  double delta[3] = { 0.0, 0.0, 0.0 }; 774  775  for( int j = 0; j < nadjs; ++j ) 776  { 777  const int joffset = verts.index( adjverts[j] ) * 3; 778  delta[0] += verts_hc[joffset + 0]; 779  delta[1] += verts_hc[joffset + 1]; 780  delta[2] += verts_hc[joffset + 2]; 781  } 782  783  verts_n[index + 0] -= beta * verts_hc[index + 0] + ( ( 1.0 - beta ) / nadjs ) * delta[0]; 784  verts_n[index + 1] -= beta * verts_hc[index + 1] + ( ( 1.0 - beta ) / nadjs ) * delta[1]; 785  verts_n[index + 2] -= beta * verts_hc[index + 2] + ( ( 1.0 - beta ) / nadjs ) * delta[2]; 786  } 787  788  return MB_SUCCESS; 789 }

References moab::Range::begin(), dim, moab::Range::end(), moab::Range::erase(), ErrorCode, moab::ParallelComm::filter_pstatus(), moab::Core::get_adjacencies(), moab::Core::get_connectivity(), moab::Range::index(), laplacianFilter(), mb, MB_SUCCESS, PSTATUS_NOT, PSTATUS_NOT_OWNED, RC, moab::Range::size(), moab::ParallelComm::size(), and moab::Core::tag_get_data().

Referenced by perform_laplacian_smoothing().

◆ laplacianFilter()

ErrorCode laplacianFilter ( Core mb,
moab::ParallelComm pcomm,
moab::Range verts,
int  dim,
Tag  fixed,
std::vector< double > &  verts_o,
std::vector< double > &  verts_n,
bool  use_updated = true 
)
Examples
LaplacianSmoother.cpp.

Definition at line 632 of file LaplacianSmoother.cpp.

640 { 641  ErrorCode rval; 642  std::vector< int > fix_tag( verts.size() ); 643  double* data; 644  645  memcpy( &verts_n[0], &verts_o[0], sizeof( double ) * verts_o.size() ); 646  647  if( use_updated ) 648  data = &verts_n[0]; 649  else 650  data = &verts_o[0]; 651  652  // filter verts down to owned ones and get fixed tag for them 653  Range owned_verts; 654  if( pcomm->size() > 1 ) 655  { 656 #ifdef MOAB_HAVE_MPI 657  rval = pcomm->filter_pstatus( verts, PSTATUS_NOT_OWNED, PSTATUS_NOT, -1, &owned_verts ); 658  if( rval != MB_SUCCESS ) return rval; 659 #endif 660  } 661  else 662  owned_verts = verts; 663  664  rval = mb->tag_get_data( fixed, owned_verts, &fix_tag[0] ); 665  RC; 666  667  int vindex = 0; 668  for( Range::const_iterator vit = owned_verts.begin(); vit != owned_verts.end(); ++vit, vindex++ ) 669  { 670  // if !fixed 671  if( fix_tag[vindex] ) continue; 672  673  const int index = verts.index( *vit ) * 3; 674  675  moab::Range adjverts, adjelems; 676  // Find the neighboring vertices (1-ring neighborhood) 677  rval = mb->get_adjacencies( &( *vit ), 1, dim, false, adjelems ); 678  RC; 679  rval = mb->get_connectivity( adjelems, adjverts ); 680  RC; 681  adjverts.erase( *vit ); 682  683  const int nadjs = adjverts.size(); 684  if( nadjs ) 685  { 686  double delta[3] = { 0.0, 0.0, 0.0 }; 687  688  // Add the vertices and divide by the number of vertices 689  for( int j = 0; j < nadjs; ++j ) 690  { 691  const int joffset = verts.index( adjverts[j] ) * 3; 692  delta[0] += data[joffset + 0]; 693  delta[1] += data[joffset + 1]; 694  delta[2] += data[joffset + 2]; 695  } 696  697  verts_n[index + 0] = delta[0] / nadjs; 698  verts_n[index + 1] = delta[1] / nadjs; 699  verts_n[index + 2] = delta[2] / nadjs; 700  } 701  } 702  703  return MB_SUCCESS; 704 }

References moab::Range::begin(), dim, moab::Range::end(), moab::Range::erase(), ErrorCode, moab::ParallelComm::filter_pstatus(), moab::Core::get_adjacencies(), moab::Core::get_connectivity(), moab::Range::index(), mb, MB_SUCCESS, PSTATUS_NOT, PSTATUS_NOT_OWNED, RC, moab::Range::size(), moab::ParallelComm::size(), and moab::Core::tag_get_data().

Referenced by hcFilter(), and perform_laplacian_smoothing().

◆ main()

int main ( int  argc,
char **  argv 
)
Examples
LaplacianSmoother.cpp.

Definition at line 89 of file LaplacianSmoother.cpp.

90 { 91  int num_its = 10; 92  int num_ref = 0; 93  int num_dim = 2; 94  int report_its = 1; 95  int num_degree = 2; 96  bool use_hc = false; 97  bool use_acc = false; 98  int acc_method = 1; 99  double alpha = 0.5, beta = 0.0; 100  double rel_eps = 1e-5; 101  const int nghostrings = 1; 102  ProgOptions opts; 103  ErrorCode rval; 104  std::stringstream sstr; 105  int global_rank; 106  107  MPI_Init( &argc, &argv ); 108  MPI_Comm_rank( MPI_COMM_WORLD, &global_rank ); 109  110  // Decipher program options from user 111  opts.addOpt< int >( std::string( "niter,n" ), 112  std::string( "Number of Laplacian smoothing iterations (default=10)" ), &num_its ); 113  opts.addOpt< double >( std::string( "eps,e" ), 114  std::string( "Tolerance for the Laplacian smoothing error (default=1e-5)" ), &rel_eps ); 115  opts.addOpt< double >( std::string( "alpha" ), 116  std::string( "Tolerance for the Laplacian smoothing error (default=0.0)" ), &alpha ); 117  opts.addOpt< double >( std::string( "beta" ), 118  std::string( "Tolerance for the Laplacian smoothing error (default=0.5)" ), &beta ); 119  opts.addOpt< int >( std::string( "dim,d" ), std::string( "Topological dimension of the mesh (default=2)" ), 120  &num_dim ); 121  opts.addOpt< std::string >( std::string( "file,f" ), 122  std::string( "Input mesh file to smoothen (default=surfrandomtris-4part.h5m)" ), 123  &test_file_name ); 124  opts.addOpt< int >( 125  std::string( "nrefine,r" ), 126  std::string( "Number of uniform refinements to perform and apply smoothing cycles (default=1)" ), &num_ref ); 127  opts.addOpt< int >( std::string( "ndegree,p" ), std::string( "Degree of uniform refinement (default=2)" ), 128  &num_degree ); 129  opts.addOpt< void >( std::string( "humphrey,c" ), 130  std::string( "Use Humphrey’s Classes algorithm to reduce shrinkage of " 131  "Laplacian smoother (default=false)" ), 132  &use_hc ); 133  opts.addOpt< void >( std::string( "aitken,d" ), 134  std::string( "Use Aitken \\delta^2 acceleration to improve convergence of " 135  "Lapalace smoothing algorithm (default=false)" ), 136  &use_acc ); 137  opts.addOpt< int >( std::string( "acc,a" ), 138  std::string( "Type of vector Aitken process to use for acceleration (default=1)" ), 139  &acc_method ); 140  141  opts.parseCommandLine( argc, argv ); 142  143  // get MOAB and ParallelComm instances 144  Core* mb = new Core; 145  if( NULL == mb ) return 1; 146  int global_size = 1; 147  148  // get the ParallelComm instance 149  ParallelComm* pcomm = new ParallelComm( mb, MPI_COMM_WORLD ); 150  global_size = pcomm->size(); 151  152  string roptions, woptions; 153  if( global_size > 1 ) 154  { // if reading in parallel, need to tell it how 155  sstr.str( "" ); 156  sstr << "PARALLEL=READ_PART;PARTITION=PARALLEL_PARTITION;PARALLEL_RESOLVE_SHARED_ENTS;" 157  "PARALLEL_GHOSTS=" 158  << num_dim << ".0." << nghostrings << ";DEBUG_IO=0;DEBUG_PIO=0"; 159  roptions = sstr.str(); 160  woptions = "PARALLEL=WRITE_PART"; 161  } 162  163  // read the file 164  moab::EntityHandle fileset, currset; 165  rval = mb->create_meshset( MESHSET_SET, fileset ); 166  RC; 167  currset = fileset; 168  rval = mb->load_file( test_file_name.c_str(), &fileset, roptions.c_str() ); 169  RC; 170  171  std::vector< EntityHandle > hsets( num_ref + 1, fileset ); 172  if( num_ref ) 173  { 174  // Perform uniform refinement of the smoothed mesh 175 #ifdef MOAB_HAVE_MPI 176  NestedRefine* uref = new NestedRefine( mb, pcomm, currset ); 177 #else 178  NestedRefine* uref = new NestedRefine( mb, 0, currset ); 179 #endif 180  181  std::vector< int > num_degrees( num_ref, num_degree ); 182  rval = uref->generate_mesh_hierarchy( num_ref, &num_degrees[0], hsets ); 183  RC; 184  185  // Now exchange 1 layer of ghost elements, using vertices as bridge 186  // (we could have done this as part of reading process, using the PARALLEL_GHOSTS read 187  // option) 188  rval = uref->exchange_ghosts( hsets, nghostrings ); 189  RC; 190  191  delete uref; 192  } 193  194  for( int iref = 0; iref <= num_ref; ++iref ) 195  { 196  197  // specify which set we are currently working on 198  currset = hsets[iref]; 199  200  // make tag to specify fixed vertices, since it's input to the algorithm; use a default 201  // value of non-fixed so we only need to set the fixed tag for skin vertices 202  Tag fixed; 203  int def_val = 0; 204  rval = mb->tag_get_handle( "fixed", 1, MB_TYPE_INTEGER, fixed, MB_TAG_CREAT | MB_TAG_DENSE, &def_val ); 205  RC; 206  207  // get all vertices and cells 208  Range verts, cells, skin_verts; 209  rval = mb->get_entities_by_type( currset, MBVERTEX, verts ); 210  RC; 211  rval = mb->get_entities_by_dimension( currset, num_dim, cells ); 212  RC; 213  dbgprint( "Found " << verts.size() << " vertices and " << cells.size() << " elements" ); 214  215  // get the skin vertices of those cells and mark them as fixed; we don't want to fix the 216  // vertices on a part boundary, but since we exchanged a layer of ghost cells, those 217  // vertices aren't on the skin locally ok to mark non-owned skin vertices too, I won't move 218  // those anyway use MOAB's skinner class to find the skin 219  Skinner skinner( mb ); 220  rval = skinner.find_skin( currset, cells, true, skin_verts ); 221  RC; // 'true' param indicates we want vertices back, not cells 222  223  std::vector< int > fix_tag( skin_verts.size(), 1 ); // initialized to 1 to indicate fixed 224  rval = mb->tag_set_data( fixed, skin_verts, &fix_tag[0] ); 225  RC; 226  // exchange tags on owned verts for fixed points 227  if( global_size > 1 ) 228  { 229 #ifdef MOAB_HAVE_MPI 230  rval = pcomm->exchange_tags( fixed, skin_verts ); 231  RC; 232 #endif 233  } 234  235  // now perform the Laplacian relaxation 236  rval = perform_laplacian_smoothing( mb, cells, verts, num_dim, fixed, use_hc, use_acc, acc_method, num_its, 237  rel_eps, alpha, beta, report_its ); 238  RC; 239  240  // output file, using parallel write 241  sstr.str( "" ); 242  sstr << "LaplacianSmoother_" << iref << ".h5m"; 243  rval = mb->write_file( sstr.str().c_str(), "H5M", woptions.c_str(), &currset, 1 ); 244  RC; 245  246  // delete fixed tag, since we created it here 247  rval = mb->tag_delete( fixed ); 248  RC; 249  } 250  251  delete pcomm; 252  // delete MOAB instance 253  delete mb; 254  255  MPI_Finalize(); 256  return 0; 257 }

References ProgOptions::addOpt(), moab::Core::create_meshset(), dbgprint, ErrorCode, moab::NestedRefine::exchange_ghosts(), moab::ParallelComm::exchange_tags(), moab::Skinner::find_skin(), moab::NestedRefine::generate_mesh_hierarchy(), moab::Core::get_entities_by_dimension(), moab::Core::get_entities_by_type(), moab::Core::load_file(), mb, MB_TAG_CREAT, MB_TAG_DENSE, MB_TYPE_INTEGER, MBVERTEX, MESHSET_SET, ProgOptions::parseCommandLine(), perform_laplacian_smoothing(), RC, moab::Range::size(), moab::ParallelComm::size(), moab::Core::tag_delete(), moab::Core::tag_get_handle(), moab::Core::tag_set_data(), test_file_name, and moab::Core::write_file().

◆ perform_laplacian_smoothing()

ErrorCode perform_laplacian_smoothing ( Core mb,
Range cells,
Range verts,
int  dim,
Tag  fixed,
bool  use_hc = false,
bool  use_acc = false,
int  acc_method = 1,
int  num_its = 10,
double  rel_eps = 1e-5,
double  alpha = 0.0,
double  beta = 0.5,
int  report_its = 1 
)
Examples
LaplacianSmoother.cpp.

Definition at line 259 of file LaplacianSmoother.cpp.

272 { 273  ErrorCode rval; 274  int global_rank = 0, global_size = 1; 275  int nacc = 2; /* nacc_method: 1 = Method 2 from [1], 2 = Method 3 from [1] */ 276  std::vector< double > verts_acc1, verts_acc2, verts_acc3; 277  double rat_theta = rel_eps, rat_alpha = rel_eps, rat_alphaprev = rel_eps; 278 #ifdef MOAB_HAVE_MPI 279  const char* woptions = "PARALLEL=WRITE_PART"; 280 #else 281  const char* woptions = ""; 282 #endif 283  std::vector< int > fix_tag( verts.size() ); 284  285  rval = mb->tag_get_data( fixed, verts, &fix_tag[0] ); 286  RC; 287  288 #ifdef MOAB_HAVE_MPI 289  ParallelComm* pcomm = ParallelComm::get_pcomm( mb, 0 ); 290  global_rank = pcomm->rank(); 291  global_size = pcomm->size(); 292 #endif 293  294  dbgprint( "-- Starting smoothing cycle --" ); 295  // perform Laplacian relaxation: 296  // 1. setup: set vertex centroids from vertex coords; filter to owned verts; get fixed tags 297  298  // get all verts coords into tag; don't need to worry about filtering out fixed verts, 299  // we'll just be setting to their fixed coords 300  std::vector< double > verts_o, verts_n; 301  verts_o.resize( 3 * verts.size(), 0.0 ); 302  verts_n.resize( 3 * verts.size(), 0.0 ); 303  // std::vector<const void*> vdata(1); 304  // vdata[0] = &verts_n[0]; 305  // const int vdatasize = verts_n.size(); 306  void* vdata = &verts_n[0]; 307  rval = mb->get_coords( verts, &verts_o[0] ); 308  RC; 309  const int nbytes = sizeof( double ) * verts_o.size(); 310  311  Tag errt, vpost; 312  double def_val[3] = { 0.0, 0.0, 0.0 }; 313  rval = mb->tag_get_handle( "error", 1, MB_TYPE_DOUBLE, errt, MB_TAG_CREAT | MB_TAG_DENSE, def_val ); 314  RC; 315  rval = mb->tag_get_handle( "vpos", 3, MB_TYPE_DOUBLE, vpost, MB_TAG_CREAT | MB_TAG_DENSE, def_val ); 316  RC; 317  // rval = mb->tag_set_by_ptr(vpost, verts, vdata); RC; 318  319  if( use_acc ) 320  { 321  verts_acc1.resize( verts_o.size(), 0.0 ); 322  verts_acc2.resize( verts_o.size(), 0.0 ); 323  verts_acc3.resize( verts_o.size(), 0.0 ); 324  memcpy( &verts_acc1[0], &verts_o[0], nbytes ); 325  memcpy( &verts_acc2[0], &verts_o[0], nbytes ); 326  memcpy( &verts_acc3[0], &verts_o[0], nbytes ); 327  } 328  329  // Filter verts down to owned ones and get fixed tag for them 330  Range owned_verts, shared_owned_verts; 331  if( global_size > 1 ) 332  { 333 #ifdef MOAB_HAVE_MPI 334  rval = pcomm->filter_pstatus( verts, PSTATUS_NOT_OWNED, PSTATUS_NOT, -1, &owned_verts );MB_CHK_ERR( rval ); 335 #endif 336  } 337  else 338  owned_verts = verts; 339  340 #ifdef MOAB_HAVE_MPI 341  // Get shared owned verts, for exchanging tags 342  rval = pcomm->get_shared_entities( -1, shared_owned_verts, 0, false, true );MB_CHK_ERR( rval ); 343  // Workaround: if no shared owned verts, put a non-shared one in the list, to prevent exchanging 344  // tags for all shared entities 345  if( shared_owned_verts.empty() ) shared_owned_verts.insert( *verts.begin() ); 346 #endif 347  348 #ifdef WRITE_DEBUG_FILES 349  { 350  // output file, using parallel write 351  std::stringstream sstr; 352  sstr << "LaplacianSmootherIterate_0.h5m"; 353  rval = mb->write_file( sstr.str().c_str(), NULL, woptions ); 354  RC; 355  } 356 #endif 357  358  bool check_metrics = true; 359  VerdictWrapper vw( mb ); 360  vw.set_size( 1. ); // for relative size measures; maybe it should be user input 361  362  double mxdelta = 0.0, global_max = 0.0; 363  // 2. for num_its iterations: 364  for( int nit = 0; nit < num_its; nit++ ) 365  { 366  367  mxdelta = 0.0; 368  369  // 2a. Apply Laplacian Smoothing Filter to Mesh 370  if( use_hc ) 371  { 372  rval = hcFilter( mb, pcomm, verts, dim, fixed, verts_o, verts_n, alpha, beta ); 373  RC; 374  } 375  else 376  { 377  rval = laplacianFilter( mb, pcomm, verts, dim, fixed, verts_o, verts_n ); 378  RC; 379  } 380  381  if( check_metrics ) 382  { 383  bool smooth_success = true; 384  std::vector< double > coords; 385  double jac = 0.0; 386  int num_nodes = 0; 387  for( unsigned ic = 0; ic < cells.size(); ++ic ) 388  { 389  EntityHandle ecell = cells[ic]; 390  EntityType etype = mb->type_from_handle( ecell ); 391  Range everts; 392  rval = mb->get_connectivity( &ecell, 1, everts, num_nodes ); 393  RC; 394  coords.resize( num_nodes * 3, 0.0 ); 395  for( int iv = 0; iv < num_nodes; ++iv ) 396  { 397  const int offset = mb->id_from_handle( everts[iv] ) * 3; 398  for( int ii = 0; ii < 3; ++ii ) 399  coords[iv * 3 + ii] = verts_n[offset + ii]; 400  } 401  rval = vw.quality_measure( ecell, MB_SHAPE, jac, num_nodes, etype, &coords[0] ); 402  RC; 403  if( jac < 1e-8 ) 404  { 405  dbgprint( "Inverted element " << ic << " with jacobian = " << jac << "." ); 406  smooth_success = false; 407  break; 408  } 409  } 410  411  if( !smooth_success ) 412  { 413  verts_o.swap( verts_n ); 414  dbgprint( "Found element inversions during smoothing. Stopping iterations." ); 415  break; 416  } 417  } 418  419  if( use_acc ) 420  { 421  422  // if (acc_method < 5 || nit <= 3) { 423  // memcpy( &verts_acc1[0], &verts_acc2[0], nbytes ); 424  // memcpy( &verts_acc2[0], &verts_acc3[0], nbytes ); 425  // memcpy( &verts_acc3[0], &verts_n[0], nbytes ); 426  // } 427  428  rat_alphaprev = rat_alpha; 429  for( unsigned i = 0; i < verts_n.size(); ++i ) 430  { 431  rat_alpha = 432  std::max( rat_alpha, 433  std::abs( ( verts_acc3[i] - verts_acc2[i] ) * ( verts_acc2[i] - verts_acc1[i] ) ) / 434  ( ( verts_acc2[i] - verts_acc1[i] ) * ( verts_acc2[i] - verts_acc1[i] ) ) ); 435  } 436  rat_theta = std::abs( rat_alpha / rat_alphaprev - 1.0 ); 437  438  if( nit > 3 && ( nit % nacc ) && rat_theta < 1.0 ) 439  { 440  441  if( acc_method == 1 ) 442  { /* Method 2 from ACCELERATION OF VECTOR SEQUENCES: 443  http://onlinelibrary.wiley.com/doi/10.1002/cnm.1630020409/pdf */ 444  double vnorm = 0.0, den, acc_alpha = 0.0, acc_gamma = 0.0; 445  for( unsigned i = 0; i < verts_n.size(); ++i ) 446  { 447  den = ( verts_acc3[i] - 2.0 * verts_acc2[i] + verts_acc1[i] ); 448  vnorm += den * den; 449  acc_alpha += ( verts_acc3[i] - verts_acc2[i] ) * ( verts_acc3[i] - verts_acc2[i] ); 450  acc_gamma += ( verts_acc2[i] - verts_acc1[i] ) * ( verts_acc2[i] - verts_acc1[i] ); 451  } 452  for( unsigned i = 0; i < verts_n.size(); ++i ) 453  { 454  verts_n[i] = verts_acc2[i] + ( acc_gamma * ( verts_acc3[i] - verts_acc2[i] ) - 455  acc_alpha * ( verts_acc2[i] - verts_acc1[i] ) ) / 456  vnorm; 457  } 458  } 459  else if( acc_method == 2 ) 460  { /* Method 3 from ACCELERATION OF VECTOR SEQUENCES: 461  http://onlinelibrary.wiley.com/doi/10.1002/cnm.1630020409/pdf */ 462  double vnorm = 0.0, num = 0.0, den = 0.0, mu = 0.0; 463  for( unsigned i = 0; i < verts_n.size(); ++i ) 464  { 465  num += 466  ( verts_acc3[i] - verts_acc2[i] ) * ( verts_acc3[i] - 2.0 * verts_acc2[i] + verts_acc1[i] ); 467  den = ( verts_acc3[i] - 2.0 * verts_acc2[i] + verts_acc1[i] ); 468  vnorm += den * den; 469  } 470  mu = num / vnorm; 471  for( unsigned i = 0; i < verts_n.size(); ++i ) 472  { 473  verts_n[i] = verts_acc3[i] + mu * ( verts_acc2[i] - verts_acc3[i] ); 474  } 475  } 476  else if( acc_method == 3 ) 477  { /* Method 5 from ACCELERATION OF VECTOR SEQUENCES: 478  http://onlinelibrary.wiley.com/doi/10.1002/cnm.1630020409/pdf */ 479  double num = 0.0, den = 0.0, mu = 0.0; 480  for( unsigned i = 0; i < verts_n.size(); ++i ) 481  { 482  num += ( verts_acc3[i] - verts_acc2[i] ) * ( verts_acc2[i] - verts_acc1[i] ); 483  den += 484  ( verts_acc2[i] - verts_acc1[i] ) * ( verts_acc3[i] - 2.0 * verts_acc2[i] + verts_acc1[i] ); 485  } 486  mu = num / den; 487  for( unsigned i = 0; i < verts_n.size(); ++i ) 488  { 489  verts_n[i] = verts_acc3[i] - mu * ( verts_acc3[i] - verts_acc2[i] ); 490  } 491  } 492  else if( acc_method == 4 ) 493  { /* Method 8 from ACCELERATION OF VECTOR SEQUENCES: 494  http://onlinelibrary.wiley.com/doi/10.1002/cnm.1630020409/pdf */ 495  double num = 0.0, den = 0.0, lambda = 0.0; 496  for( unsigned i = 0; i < verts_n.size(); ++i ) 497  { 498  num += ( verts_acc3[i] - verts_acc2[i] ) * ( verts_acc3[i] - verts_acc2[i] ); 499  den += ( verts_acc2[i] - verts_acc1[i] ) * ( verts_acc2[i] - verts_acc1[i] ); 500  } 501  lambda = std::sqrt( num / den ); 502  for( unsigned i = 0; i < verts_n.size(); ++i ) 503  { 504  verts_n[i] = verts_acc3[i] - lambda / ( lambda - 1.0 ) * ( verts_acc3[i] - verts_acc2[i] ); 505  } 506  } 507  else if( acc_method == 5 ) 508  { /* Minimum polynomial extrapolation of vector sequenes : 509  https://en.wikipedia.org/wiki/Minimum_polynomial_extrapolation */ 510  /* Pseudo-code 511  U=x(:,2:end-1)-x(:,1:end-2); 512  c=-pinv(U)*(x(:,end)-x(:,end-1)); 513  c(end+1,1)=1; 514  s=(x(:,2:end)*c)/sum(c); 515  */ 516  Matrix U( verts_n.size(), 2 ); 517  Vector res( verts_n.size() ); 518  for( unsigned ir = 0; ir < verts_n.size(); ir++ ) 519  { 520  U( ir, 0 ) = verts_acc2[ir] - verts_acc1[ir]; 521  U( ir, 1 ) = verts_acc3[ir] - verts_acc2[ir]; 522  res[ir] = -( verts_n[ir] - verts_acc3[ir] ); 523  } 524  // U.print(); 525  // Vector acc = QR(U).solve(res); 526  Vector acc = solve( U, res ); 527  double accsum = acc[0] + acc[1] + 1.0; 528  for( unsigned ir = 0; ir < verts_n.size(); ir++ ) 529  { 530  verts_n[ir] = ( verts_acc1[ir] * acc[0] + verts_acc2[ir] * acc[1] + verts_acc3[ir] ) / accsum; 531  } 532  533  memcpy( &verts_acc1[0], &verts_acc2[0], nbytes ); 534  memcpy( &verts_acc2[0], &verts_acc3[0], nbytes ); 535  memcpy( &verts_acc3[0], &verts_n[0], nbytes ); 536  } 537  else 538  { 539  int offset = 0; 540  for( Range::const_iterator vit = verts.begin(); vit != verts.end(); ++vit, offset += 3 ) 541  { 542  // if !fixed 543  if( fix_tag[offset / 3] ) continue; 544  545  CartVect num1 = ( CartVect( &verts_acc3[offset] ) - CartVect( &verts_acc2[offset] ) ); 546  CartVect num2 = ( CartVect( &verts_acc3[offset] ) - 2.0 * CartVect( &verts_acc2[offset] ) + 547  CartVect( &verts_acc1[offset] ) ); 548  549  num1.scale( num2 ); 550  const double mu = num1.length_squared() / num2.length_squared(); 551  552  verts_n[offset + 0] = 553  verts_acc3[offset + 0] + mu * ( verts_acc2[offset + 0] - verts_acc3[offset + 0] ); 554  verts_n[offset + 1] = 555  verts_acc3[offset + 1] + mu * ( verts_acc2[offset + 1] - verts_acc3[offset + 1] ); 556  verts_n[offset + 2] = 557  verts_acc3[offset + 2] + mu * ( verts_acc2[offset + 2] - verts_acc3[offset + 2] ); 558  } 559  } 560  } 561  memcpy( &verts_acc1[0], &verts_acc2[0], nbytes ); 562  memcpy( &verts_acc2[0], &verts_acc3[0], nbytes ); 563  memcpy( &verts_acc3[0], &verts_n[0], nbytes ); 564  } 565  566  // 2b. foreach owned vertex: compute change in coordinate norm 567  for( unsigned v = 0; v < verts.size(); ++v ) 568  { 569  double delta = ( CartVect( &verts_n[3 * v] ) - CartVect( &verts_o[3 * v] ) ).length(); 570  mxdelta = std::max( delta, mxdelta ); 571  EntityHandle vh = verts[v]; 572  rval = mb->tag_set_data( errt, &vh, 1, &mxdelta ); 573  RC; 574  } 575  576  // global reduce for maximum delta, then report it 577  global_max = mxdelta; 578 #ifdef MOAB_HAVE_MPI 579  if( global_size > 1 ) MPI_Allreduce( &mxdelta, &global_max, 1, MPI_DOUBLE, MPI_MAX, pcomm->comm() ); 580 #endif 581  582  if( !( nit % report_its ) ) 583  { 584  dbgprint( "\tIterate " << nit << ": Global Max delta = " << global_max << "." ); 585  } 586  587 #ifdef WRITE_DEBUG_FILES 588  { 589  // write the tag back onto vertex coordinates 590  rval = mb->set_coords( verts, &verts_n[0] ); 591  RC; 592  // output VTK file for debugging purposes 593  std::stringstream sstr; 594  sstr << "LaplacianSmootherIterate_" << nit + 1 << ".h5m"; 595  rval = mb->write_file( sstr.str().c_str(), NULL, woptions ); 596  RC; 597  } 598 #endif 599  600 #ifdef MOAB_HAVE_MPI 601  // 2c. exchange tags on owned verts 602  if( global_size > 1 ) 603  { 604  rval = mb->tag_set_data( vpost, owned_verts, vdata ); 605  RC; 606  rval = pcomm->exchange_tags( vpost, shared_owned_verts ); 607  RC; 608  } 609 #endif 610  611  if( global_max < rel_eps ) 612  break; 613  else 614  { 615  std::copy( verts_n.begin(), verts_n.end(), verts_o.begin() ); 616  } 617  } 618  619  // write the tag back onto vertex coordinates 620  rval = mb->set_coords( verts, &verts_n[0] ); 621  RC; 622  623  dbgprint( "-- Final iterate error = " << global_max << ".\n" ); 624  return MB_SUCCESS; 625 }

References moab::Range::begin(), moab::ParallelComm::comm(), dbgprint, dim, moab::Range::empty(), moab::Range::end(), ErrorCode, moab::ParallelComm::exchange_tags(), moab::ParallelComm::filter_pstatus(), moab::Core::get_connectivity(), moab::Core::get_coords(), moab::ParallelComm::get_pcomm(), moab::ParallelComm::get_shared_entities(), hcFilter(), moab::Core::id_from_handle(), moab::Range::insert(), laplacianFilter(), length(), moab::CartVect::length_squared(), mb, MB_CHK_ERR, moab::MB_SHAPE, MB_SUCCESS, MB_TAG_CREAT, MB_TAG_DENSE, MB_TYPE_DOUBLE, PSTATUS_NOT, PSTATUS_NOT_OWNED, moab::VerdictWrapper::quality_measure(), moab::ParallelComm::rank(), RC, moab::CartVect::scale(), moab::Core::set_coords(), moab::VerdictWrapper::set_size(), moab::Range::size(), moab::ParallelComm::size(), moab::Core::tag_get_data(), moab::Core::tag_get_handle(), moab::Core::tag_set_data(), moab::Core::type_from_handle(), and moab::Core::write_file().

Referenced by main().

Variable Documentation

◆ test_file_name

string test_file_name = string( "input/surfrandomtris-4part.h5m" )
Examples
LaplacianSmoother.cpp.

Definition at line 46 of file LaplacianSmoother.cpp.

Referenced by main().