59 #include "moab/VerdictWrapper.hpp"
65 #define WRITE_DEBUG_FILES
73 #define RC MB_CHK_ERR( rval )
74 #define dbgprint( MSG ) \
77 if( !global_rank ) std::cerr << ( MSG ) << std::endl; \
89 double rel_eps = 1e-5,
99 std::vector< double >& verts_o,
100 std::vector< double >& verts_n,
109 std::vector< double >& verts_o,
110 std::vector< double >& verts_n,
111 bool use_updated =
true );
113 int main(
int argc,
char** argv )
121 bool use_acc =
false;
123 double alpha = 0.5, beta = 0.0;
124 double rel_eps = 1e-5;
125 const int nghostrings = 1;
128 std::stringstream sstr;
131 MPI_Init( &argc, &argv );
132 MPI_Comm_rank( MPI_COMM_WORLD, &global_rank );
135 opts.
addOpt<
int >( std::string(
"niter,n" ),
136 std::string(
"Number of Laplacian smoothing iterations (default=10)" ), &num_its );
137 opts.
addOpt<
double >( std::string(
"eps,e" ),
138 std::string(
"Tolerance for the Laplacian smoothing error (default=1e-5)" ), &rel_eps );
139 opts.
addOpt<
double >( std::string(
"alpha" ),
140 std::string(
"Tolerance for the Laplacian smoothing error (default=0.0)" ), &alpha );
141 opts.
addOpt<
double >( std::string(
"beta" ),
142 std::string(
"Tolerance for the Laplacian smoothing error (default=0.5)" ), &beta );
143 opts.
addOpt<
int >( std::string(
"dim,d" ), std::string(
"Topological dimension of the mesh (default=2)" ),
145 opts.
addOpt< std::string >( std::string(
"file,f" ),
146 std::string(
"Input mesh file to smoothen (default=surfrandomtris-4part.h5m)" ),
149 std::string(
"nrefine,r" ),
150 std::string(
"Number of uniform refinements to perform and apply smoothing cycles (default=1)" ), &num_ref );
151 opts.
addOpt<
int >( std::string(
"ndegree,p" ), std::string(
"Degree of uniform refinement (default=2)" ),
153 opts.
addOpt<
void >( std::string(
"humphrey,c" ),
154 std::string(
"Use Humphrey’s Classes algorithm to reduce shrinkage of "
155 "Laplacian smoother (default=false)" ),
157 opts.
addOpt<
void >( std::string(
"aitken,d" ),
158 std::string(
"Use Aitken \\delta^2 acceleration to improve convergence of "
159 "Lapalace smoothing algorithm (default=false)" ),
161 opts.
addOpt<
int >( std::string(
"acc,a" ),
162 std::string(
"Type of vector Aitken process to use for acceleration (default=1)" ),
169 if( NULL ==
mb )
return 1;
174 global_size = pcomm->
size();
176 string roptions, woptions;
177 if( global_size > 1 )
180 sstr <<
"PARALLEL=READ_PART;PARTITION=PARALLEL_PARTITION;PARALLEL_RESOLVE_SHARED_ENTS;"
182 << num_dim <<
".0." << nghostrings <<
";DEBUG_IO=0;DEBUG_PIO=0";
183 roptions = sstr.str();
184 woptions =
"PARALLEL=WRITE_PART";
195 std::vector< EntityHandle > hsets( num_ref + 1, fileset );
205 std::vector< int > num_degrees( num_ref, num_degree );
218 for(
int iref = 0; iref <= num_ref; ++iref )
222 currset = hsets[iref];
232 Range verts, cells, skin_verts;
237 dbgprint(
"Found " << verts.
size() <<
" vertices and " << cells.
size() <<
" elements" );
244 rval = skinner.
find_skin( currset, cells,
true, skin_verts );
247 std::vector< int > fix_tag( skin_verts.
size(), 1 );
251 if( global_size > 1 )
261 rel_eps, alpha, beta, report_its );
266 sstr <<
"LaplacianSmoother_" << iref <<
".h5m";
267 rval =
mb->
write_file( sstr.str().c_str(),
"H5M", woptions.c_str(), &currset, 1 );
298 int global_rank = 0, global_size = 1;
300 std::vector< double > verts_acc1, verts_acc2, verts_acc3;
301 double rat_theta = rel_eps, rat_alpha = rel_eps, rat_alphaprev = rel_eps;
303 const char* woptions =
"PARALLEL=WRITE_PART";
305 const char* woptions =
"";
307 std::vector< int > fix_tag( verts.
size() );
314 global_rank = pcomm->
rank();
315 global_size = pcomm->
size();
318 dbgprint(
"-- Starting smoothing cycle --" );
324 std::vector< double > verts_o, verts_n;
325 verts_o.resize( 3 * verts.
size(), 0.0 );
326 verts_n.resize( 3 * verts.
size(), 0.0 );
330 void* vdata = &verts_n[0];
333 const int nbytes =
sizeof( double ) * verts_o.size();
336 double def_val[3] = { 0.0, 0.0, 0.0 };
345 verts_acc1.resize( verts_o.size(), 0.0 );
346 verts_acc2.resize( verts_o.size(), 0.0 );
347 verts_acc3.resize( verts_o.size(), 0.0 );
348 memcpy( &verts_acc1[0], &verts_o[0], nbytes );
349 memcpy( &verts_acc2[0], &verts_o[0], nbytes );
350 memcpy( &verts_acc3[0], &verts_o[0], nbytes );
354 Range owned_verts, shared_owned_verts;
355 if( global_size > 1 )
369 if( shared_owned_verts.
empty() ) shared_owned_verts.
insert( *verts.
begin() );
372 #ifdef WRITE_DEBUG_FILES
375 std::stringstream sstr;
376 sstr <<
"LaplacianSmootherIterate_0.h5m";
377 rval =
mb->
write_file( sstr.str().c_str(), NULL, woptions );
382 bool check_metrics =
true;
386 double mxdelta = 0.0, global_max = 0.0;
388 for(
int nit = 0; nit < num_its; nit++ )
396 rval =
hcFilter(
mb, pcomm, verts, dim, fixed, verts_o, verts_n, alpha, beta );
407 bool smooth_success =
true;
408 std::vector< double > coords;
411 for(
unsigned ic = 0; ic < cells.
size(); ++ic )
418 coords.resize( num_nodes * 3, 0.0 );
419 for(
int iv = 0; iv < num_nodes; ++iv )
422 for(
int ii = 0; ii < 3; ++ii )
423 coords[iv * 3 + ii] = verts_n[offset + ii];
429 dbgprint(
"Inverted element " << ic <<
" with jacobian = " << jac <<
"." );
430 smooth_success =
false;
435 if( !smooth_success )
437 verts_o.swap( verts_n );
438 dbgprint(
"Found element inversions during smoothing. Stopping iterations." );
452 rat_alphaprev = rat_alpha;
453 for(
unsigned i = 0; i < verts_n.size(); ++i )
457 std::abs( ( verts_acc3[i] - verts_acc2[i] ) * ( verts_acc2[i] - verts_acc1[i] ) ) /
458 ( ( verts_acc2[i] - verts_acc1[i] ) * ( verts_acc2[i] - verts_acc1[i] ) ) );
460 rat_theta = std::abs( rat_alpha / rat_alphaprev - 1.0 );
462 if( nit > 3 && ( nit % nacc ) && rat_theta < 1.0 )
465 if( acc_method == 1 )
468 double vnorm = 0.0, den, acc_alpha = 0.0, acc_gamma = 0.0;
469 for(
unsigned i = 0; i < verts_n.size(); ++i )
471 den = ( verts_acc3[i] - 2.0 * verts_acc2[i] + verts_acc1[i] );
473 acc_alpha += ( verts_acc3[i] - verts_acc2[i] ) * ( verts_acc3[i] - verts_acc2[i] );
474 acc_gamma += ( verts_acc2[i] - verts_acc1[i] ) * ( verts_acc2[i] - verts_acc1[i] );
476 for(
unsigned i = 0; i < verts_n.size(); ++i )
478 verts_n[i] = verts_acc2[i] + ( acc_gamma * ( verts_acc3[i] - verts_acc2[i] ) -
479 acc_alpha * ( verts_acc2[i] - verts_acc1[i] ) ) /
483 else if( acc_method == 2 )
486 double vnorm = 0.0, num = 0.0, den = 0.0, mu = 0.0;
487 for(
unsigned i = 0; i < verts_n.size(); ++i )
490 ( verts_acc3[i] - verts_acc2[i] ) * ( verts_acc3[i] - 2.0 * verts_acc2[i] + verts_acc1[i] );
491 den = ( verts_acc3[i] - 2.0 * verts_acc2[i] + verts_acc1[i] );
495 for(
unsigned i = 0; i < verts_n.size(); ++i )
497 verts_n[i] = verts_acc3[i] + mu * ( verts_acc2[i] - verts_acc3[i] );
500 else if( acc_method == 3 )
503 double num = 0.0, den = 0.0, mu = 0.0;
504 for(
unsigned i = 0; i < verts_n.size(); ++i )
506 num += ( verts_acc3[i] - verts_acc2[i] ) * ( verts_acc2[i] - verts_acc1[i] );
508 ( verts_acc2[i] - verts_acc1[i] ) * ( verts_acc3[i] - 2.0 * verts_acc2[i] + verts_acc1[i] );
511 for(
unsigned i = 0; i < verts_n.size(); ++i )
513 verts_n[i] = verts_acc3[i] - mu * ( verts_acc3[i] - verts_acc2[i] );
516 else if( acc_method == 4 )
519 double num = 0.0, den = 0.0, lambda = 0.0;
520 for(
unsigned i = 0; i < verts_n.size(); ++i )
522 num += ( verts_acc3[i] - verts_acc2[i] ) * ( verts_acc3[i] - verts_acc2[i] );
523 den += ( verts_acc2[i] - verts_acc1[i] ) * ( verts_acc2[i] - verts_acc1[i] );
525 lambda = std::sqrt( num / den );
526 for(
unsigned i = 0; i < verts_n.size(); ++i )
528 verts_n[i] = verts_acc3[i] - lambda / ( lambda - 1.0 ) * ( verts_acc3[i] - verts_acc2[i] );
531 else if( acc_method == 5 )
540 Matrix U( verts_n.size(), 2 );
541 Vector res( verts_n.size() );
542 for(
unsigned ir = 0; ir < verts_n.size(); ir++ )
544 U( ir, 0 ) = verts_acc2[ir] - verts_acc1[ir];
545 U( ir, 1 ) = verts_acc3[ir] - verts_acc2[ir];
546 res[ir] = -( verts_n[ir] - verts_acc3[ir] );
550 Vector acc = solve( U, res );
551 double accsum = acc[0] + acc[1] + 1.0;
552 for(
unsigned ir = 0; ir < verts_n.size(); ir++ )
554 verts_n[ir] = ( verts_acc1[ir] * acc[0] + verts_acc2[ir] * acc[1] + verts_acc3[ir] ) / accsum;
557 memcpy( &verts_acc1[0], &verts_acc2[0], nbytes );
558 memcpy( &verts_acc2[0], &verts_acc3[0], nbytes );
559 memcpy( &verts_acc3[0], &verts_n[0], nbytes );
567 if( fix_tag[offset / 3] )
continue;
576 verts_n[offset + 0] =
577 verts_acc3[offset + 0] + mu * ( verts_acc2[offset + 0] - verts_acc3[offset + 0] );
578 verts_n[offset + 1] =
579 verts_acc3[offset + 1] + mu * ( verts_acc2[offset + 1] - verts_acc3[offset + 1] );
580 verts_n[offset + 2] =
581 verts_acc3[offset + 2] + mu * ( verts_acc2[offset + 2] - verts_acc3[offset + 2] );
585 memcpy( &verts_acc1[0], &verts_acc2[0], nbytes );
586 memcpy( &verts_acc2[0], &verts_acc3[0], nbytes );
587 memcpy( &verts_acc3[0], &verts_n[0], nbytes );
591 for(
unsigned v = 0; v < verts.
size(); ++v )
594 mxdelta = std::max( delta, mxdelta );
601 global_max = mxdelta;
603 if( global_size > 1 ) MPI_Allreduce( &mxdelta, &global_max, 1, MPI_DOUBLE, MPI_MAX, pcomm->
comm() );
606 if( !( nit % report_its ) )
608 dbgprint(
"\tIterate " << nit <<
": Global Max delta = " << global_max <<
"." );
611 #ifdef WRITE_DEBUG_FILES
617 std::stringstream sstr;
618 sstr <<
"LaplacianSmootherIterate_" << nit + 1 <<
".h5m";
619 rval =
mb->
write_file( sstr.str().c_str(), NULL, woptions );
626 if( global_size > 1 )
635 if( global_max < rel_eps )
639 std::copy( verts_n.begin(), verts_n.end(), verts_o.begin() );
647 dbgprint(
"-- Final iterate error = " << global_max <<
".\n" );
661 std::vector< double >& verts_o,
662 std::vector< double >& verts_n,
666 std::vector< int > fix_tag( verts.
size() );
669 memcpy( &verts_n[0], &verts_o[0],
sizeof(
double ) * verts_o.size() );
678 if( pcomm->
size() > 1 )
695 if( fix_tag[vindex] )
continue;
705 adjverts.
erase( *vit );
707 const int nadjs = adjverts.
size();
710 double delta[3] = { 0.0, 0.0, 0.0 };
713 for(
int j = 0; j < nadjs; ++j )
715 const int joffset = verts.
index( adjverts[j] ) * 3;
716 delta[0] += data[joffset + 0];
717 delta[1] += data[joffset + 1];
718 delta[2] += data[joffset + 2];
721 verts_n[
index + 0] = delta[0] / nadjs;
722 verts_n[
index + 1] = delta[1] / nadjs;
723 verts_n[
index + 2] = delta[2] / nadjs;
746 std::vector< double >& verts_o,
747 std::vector< double >& verts_n,
752 std::vector< double > verts_hc( verts_o.size() );
753 std::vector< int > fix_tag( verts.
size() );
762 verts_hc[
index] = verts_n[
index] - ( alpha * verts_n[
index] + ( 1.0 - alpha ) * verts_o[
index] );
768 if( pcomm->
size() > 1 )
784 if( fix_tag[vindex] )
continue;
794 adjverts.
erase( *vit );
796 const int nadjs = adjverts.
size();
797 double delta[3] = { 0.0, 0.0, 0.0 };
799 for(
int j = 0; j < nadjs; ++j )
801 const int joffset = verts.
index( adjverts[j] ) * 3;
802 delta[0] += verts_hc[joffset + 0];
803 delta[1] += verts_hc[joffset + 1];
804 delta[2] += verts_hc[joffset + 2];
807 verts_n[
index + 0] -= beta * verts_hc[
index + 0] + ( ( 1.0 - beta ) / nadjs ) * delta[0];
808 verts_n[
index + 1] -= beta * verts_hc[
index + 1] + ( ( 1.0 - beta ) / nadjs ) * delta[1];
809 verts_n[
index + 2] -= beta * verts_hc[
index + 2] + ( ( 1.0 - beta ) / nadjs ) * delta[2];