35 #include "moab/VerdictWrapper.hpp"
41 #define WRITE_DEBUG_FILES
49 #define RC MB_CHK_ERR( rval )
50 #define dbgprint( MSG ) \
53 if( !global_rank ) std::cerr << ( MSG ) << std::endl; \
65 double rel_eps = 1e-5,
75 std::vector< double >& verts_o,
76 std::vector< double >& verts_n,
85 std::vector< double >& verts_o,
86 std::vector< double >& verts_n,
87 bool use_updated =
true );
89 int main(
int argc,
char** argv )
99 double alpha = 0.5, beta = 0.0;
100 double rel_eps = 1e-5;
101 const int nghostrings = 1;
104 std::stringstream sstr;
107 MPI_Init( &argc, &argv );
108 MPI_Comm_rank( MPI_COMM_WORLD, &global_rank );
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)" ),
121 opts.
addOpt< std::string >( std::string(
"file,f" ),
122 std::string(
"Input mesh file to smoothen (default=surfrandomtris-4part.h5m)" ),
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)" ),
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)" ),
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)" ),
137 opts.
addOpt<
int >( std::string(
"acc,a" ),
138 std::string(
"Type of vector Aitken process to use for acceleration (default=1)" ),
145 if( NULL ==
mb )
return 1;
150 global_size = pcomm->
size();
152 string roptions, woptions;
153 if( global_size > 1 )
156 sstr <<
"PARALLEL=READ_PART;PARTITION=PARALLEL_PARTITION;PARALLEL_RESOLVE_SHARED_ENTS;"
158 << num_dim <<
".0." << nghostrings <<
";DEBUG_IO=0;DEBUG_PIO=0";
159 roptions = sstr.str();
160 woptions =
"PARALLEL=WRITE_PART";
171 std::vector< EntityHandle > hsets( num_ref + 1, fileset );
181 std::vector< int > num_degrees( num_ref, num_degree );
194 for(
int iref = 0; iref <= num_ref; ++iref )
198 currset = hsets[iref];
208 Range verts, cells, skin_verts;
213 dbgprint(
"Found " << verts.
size() <<
" vertices and " << cells.
size() <<
" elements" );
220 rval = skinner.
find_skin( currset, cells,
true, skin_verts );
223 std::vector< int > fix_tag( skin_verts.
size(), 1 );
227 if( global_size > 1 )
237 rel_eps, alpha, beta, report_its );
242 sstr <<
"LaplacianSmoother_" << iref <<
".h5m";
243 rval =
mb->
write_file( sstr.str().c_str(),
"H5M", woptions.c_str(), &currset, 1 );
274 int global_rank = 0, global_size = 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;
279 const char* woptions =
"PARALLEL=WRITE_PART";
281 const char* woptions =
"";
283 std::vector< int > fix_tag( verts.
size() );
290 global_rank = pcomm->
rank();
291 global_size = pcomm->
size();
294 dbgprint(
"-- Starting smoothing cycle --" );
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 );
306 void* vdata = &verts_n[0];
309 const int nbytes =
sizeof( double ) * verts_o.size();
312 double def_val[3] = { 0.0, 0.0, 0.0 };
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 );
330 Range owned_verts, shared_owned_verts;
331 if( global_size > 1 )
345 if( shared_owned_verts.
empty() ) shared_owned_verts.
insert( *verts.
begin() );
348 #ifdef WRITE_DEBUG_FILES
351 std::stringstream sstr;
352 sstr <<
"LaplacianSmootherIterate_0.h5m";
353 rval =
mb->
write_file( sstr.str().c_str(), NULL, woptions );
358 bool check_metrics =
true;
362 double mxdelta = 0.0, global_max = 0.0;
364 for(
int nit = 0; nit < num_its; nit++ )
372 rval =
hcFilter(
mb, pcomm, verts,
dim, fixed, verts_o, verts_n, alpha, beta );
383 bool smooth_success =
true;
384 std::vector< double > coords;
387 for(
unsigned ic = 0; ic < cells.
size(); ++ic )
394 coords.resize( num_nodes * 3, 0.0 );
395 for(
int iv = 0; iv < num_nodes; ++iv )
398 for(
int ii = 0; ii < 3; ++ii )
399 coords[iv * 3 + ii] = verts_n[offset + ii];
405 dbgprint(
"Inverted element " << ic <<
" with jacobian = " << jac <<
"." );
406 smooth_success =
false;
411 if( !smooth_success )
413 verts_o.swap( verts_n );
414 dbgprint(
"Found element inversions during smoothing. Stopping iterations." );
428 rat_alphaprev = rat_alpha;
429 for(
unsigned i = 0; i < verts_n.size(); ++i )
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] ) ) );
436 rat_theta = std::abs( rat_alpha / rat_alphaprev - 1.0 );
438 if( nit > 3 && ( nit % nacc ) && rat_theta < 1.0 )
441 if( acc_method == 1 )
444 double vnorm = 0.0, den, acc_alpha = 0.0, acc_gamma = 0.0;
445 for(
unsigned i = 0; i < verts_n.size(); ++i )
447 den = ( verts_acc3[i] - 2.0 * verts_acc2[i] + verts_acc1[i] );
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] );
452 for(
unsigned i = 0; i < verts_n.size(); ++i )
454 verts_n[i] = verts_acc2[i] + ( acc_gamma * ( verts_acc3[i] - verts_acc2[i] ) -
455 acc_alpha * ( verts_acc2[i] - verts_acc1[i] ) ) /
459 else if( acc_method == 2 )
462 double vnorm = 0.0, num = 0.0, den = 0.0, mu = 0.0;
463 for(
unsigned i = 0; i < verts_n.size(); ++i )
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] );
471 for(
unsigned i = 0; i < verts_n.size(); ++i )
473 verts_n[i] = verts_acc3[i] + mu * ( verts_acc2[i] - verts_acc3[i] );
476 else if( acc_method == 3 )
479 double num = 0.0, den = 0.0, mu = 0.0;
480 for(
unsigned i = 0; i < verts_n.size(); ++i )
482 num += ( verts_acc3[i] - verts_acc2[i] ) * ( verts_acc2[i] - verts_acc1[i] );
484 ( verts_acc2[i] - verts_acc1[i] ) * ( verts_acc3[i] - 2.0 * verts_acc2[i] + verts_acc1[i] );
487 for(
unsigned i = 0; i < verts_n.size(); ++i )
489 verts_n[i] = verts_acc3[i] - mu * ( verts_acc3[i] - verts_acc2[i] );
492 else if( acc_method == 4 )
495 double num = 0.0, den = 0.0, lambda = 0.0;
496 for(
unsigned i = 0; i < verts_n.size(); ++i )
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] );
501 lambda = std::sqrt( num / den );
502 for(
unsigned i = 0; i < verts_n.size(); ++i )
504 verts_n[i] = verts_acc3[i] - lambda / ( lambda - 1.0 ) * ( verts_acc3[i] - verts_acc2[i] );
507 else if( acc_method == 5 )
516 Matrix U( verts_n.size(), 2 );
517 Vector res( verts_n.size() );
518 for(
unsigned ir = 0; ir < verts_n.size(); ir++ )
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] );
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++ )
530 verts_n[ir] = ( verts_acc1[ir] * acc[0] + verts_acc2[ir] * acc[1] + verts_acc3[ir] ) / accsum;
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 );
543 if( fix_tag[offset / 3] )
continue;
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] );
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 );
567 for(
unsigned v = 0; v < verts.
size(); ++v )
570 mxdelta = std::max( delta, mxdelta );
577 global_max = mxdelta;
579 if( global_size > 1 ) MPI_Allreduce( &mxdelta, &global_max, 1, MPI_DOUBLE, MPI_MAX, pcomm->
comm() );
582 if( !( nit % report_its ) )
584 dbgprint(
"\tIterate " << nit <<
": Global Max delta = " << global_max <<
"." );
587 #ifdef WRITE_DEBUG_FILES
593 std::stringstream sstr;
594 sstr <<
"LaplacianSmootherIterate_" << nit + 1 <<
".h5m";
595 rval =
mb->
write_file( sstr.str().c_str(), NULL, woptions );
602 if( global_size > 1 )
611 if( global_max < rel_eps )
615 std::copy( verts_n.begin(), verts_n.end(), verts_o.begin() );
623 dbgprint(
"-- Final iterate error = " << global_max <<
".\n" );
637 std::vector< double >& verts_o,
638 std::vector< double >& verts_n,
642 std::vector< int > fix_tag( verts.
size() );
645 memcpy( &verts_n[0], &verts_o[0],
sizeof(
double ) * verts_o.size() );
654 if( pcomm->
size() > 1 )
671 if( fix_tag[vindex] )
continue;
673 const int index = verts.
index( *vit ) * 3;
681 adjverts.
erase( *vit );
683 const int nadjs = adjverts.
size();
686 double delta[3] = { 0.0, 0.0, 0.0 };
689 for(
int j = 0; j < nadjs; ++j )
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];
697 verts_n[index + 0] = delta[0] / nadjs;
698 verts_n[index + 1] = delta[1] / nadjs;
699 verts_n[index + 2] = delta[2] / nadjs;
722 std::vector< double >& verts_o,
723 std::vector< double >& verts_n,
728 std::vector< double > verts_hc( verts_o.size() );
729 std::vector< int > fix_tag( verts.
size() );
736 for(
unsigned index = 0; index < verts_o.size(); ++index )
738 verts_hc[index] = verts_n[index] - ( alpha * verts_n[index] + ( 1.0 - alpha ) * verts_o[index] );
744 if( pcomm->
size() > 1 )
760 if( fix_tag[vindex] )
continue;
762 const int index = verts.
index( *vit ) * 3;
770 adjverts.
erase( *vit );
772 const int nadjs = adjverts.
size();
773 double delta[3] = { 0.0, 0.0, 0.0 };
775 for(
int j = 0; j < nadjs; ++j )
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];
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];