1
22
23 #include <iostream>
24 #include <sstream>
25 #include "moab/Core.hpp"
26 #ifdef MOAB_HAVE_MPI
27 #include "moab/ParallelComm.hpp"
28 #include "MBParallelConventions.h"
29 #endif
30 #include "moab/Skinner.hpp"
31 #include "moab/CN.hpp"
32 #include "moab/ProgOptions.hpp"
33 #include "moab/CartVect.hpp"
34 #include "moab/NestedRefine.hpp"
35 #include "moab/VerdictWrapper.hpp"
36 #include "matrix.h"
37
38 using namespace moab;
39 using namespace std;
40
41 #define WRITE_DEBUG_FILES
42
43 #ifdef MESH_DIR
44 string test_file_name = string( MESH_DIR ) + string( "/surfrandomtris-4part.h5m" );
45 #else
46 string test_file_name = string( "input/surfrandomtris-4part.h5m" );
47 #endif
48
49 #define RC MB_CHK_ERR( rval )
50 #define dbgprint( MSG ) \
51 do \
52 { \
53 if( !global_rank ) std::cerr << ( MSG ) << std::endl; \
54 } while( false )
55
56 ErrorCode perform_laplacian_smoothing( Core* mb,
57 Range& cells,
58 Range& verts,
59 int dim,
60 Tag fixed,
61 bool use_hc = false,
62 bool use_acc = false,
63 int acc_method = 1,
64 int num_its = 10,
65 double rel_eps = 1e-5,
66 double alpha = 0.0,
67 double beta = 0.5,
68 int report_its = 1 );
69
70 ErrorCode hcFilter( Core* mb,
71 moab::ParallelComm* pcomm,
72 moab::Range& verts,
73 int dim,
74 Tag fixed,
75 std::vector< double >& verts_o,
76 std::vector< double >& verts_n,
77 double alpha,
78 double beta );
79
80 ErrorCode laplacianFilter( Core* mb,
81 moab::ParallelComm* pcomm,
82 moab::Range& verts,
83 int dim,
84 Tag fixed,
85 std::vector< double >& verts_o,
86 std::vector< double >& verts_n,
87 bool use_updated = true );
88
89 int main( int argc, char** argv )
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
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
144 Core* mb = new Core;
145 if( NULL == mb ) return 1;
146 int global_size = 1;
147
148
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 {
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
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
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
186
187
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
198 currset = hsets[iref];
199
200
201
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
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
216
217
218
219 Skinner skinner( mb );
220 rval = skinner.find_skin( currset, cells, true, skin_verts );
221 RC;
222
223 std::vector< int > fix_tag( skin_verts.size(), 1 );
224 rval = mb->tag_set_data( fixed, skin_verts, &fix_tag[0] );
225 RC;
226
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
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
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
247 rval = mb->tag_delete( fixed );
248 RC;
249 }
250
251 delete pcomm;
252
253 delete mb;
254
255 MPI_Finalize();
256 return 0;
257 }
258
259 ErrorCode perform_laplacian_smoothing( Core* mb,
260 Range& cells,
261 Range& verts,
262 int dim,
263 Tag fixed,
264 bool use_hc,
265 bool use_acc,
266 int acc_method,
267 int num_its,
268 double rel_eps,
269 double alpha,
270 double beta,
271 int report_its )
272 {
273 ErrorCode rval;
274 int global_rank = 0, global_size = 1;
275 int nacc = 2;
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
296
297
298
299
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
304
305
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
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
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
342 rval = pcomm->get_shared_entities( -1, shared_owned_verts, 0, false, true );MB_CHK_ERR( rval );
343
344
345 if( shared_owned_verts.empty() ) shared_owned_verts.insert( *verts.begin() );
346 #endif
347
348 #ifdef WRITE_DEBUG_FILES
349 {
350
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. );
361
362 double mxdelta = 0.0, global_max = 0.0;
363
364 for( int nit = 0; nit < num_its; nit++ )
365 {
366
367 mxdelta = 0.0;
368
369
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
423
424
425
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 {
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 {
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 {
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 {
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 {
510
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
525
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
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
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
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
590 rval = mb->set_coords( verts, &verts_n[0] );
591 RC;
592
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
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
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 }
626
627
632 ErrorCode laplacianFilter( Core* mb,
633 moab::ParallelComm* pcomm,
634 moab::Range& verts,
635 int dim,
636 Tag fixed,
637 std::vector< double >& verts_o,
638 std::vector< double >& verts_n,
639 bool use_updated )
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
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
671 if( fix_tag[vindex] ) continue;
672
673 const int index = verts.index( *vit ) * 3;
674
675 moab::Range adjverts, adjelems;
676
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
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 }
705
706
717 ErrorCode hcFilter( Core* mb,
718 moab::ParallelComm* pcomm,
719 moab::Range& verts,
720 int dim,
721 Tag fixed,
722 std::vector< double >& verts_o,
723 std::vector< double >& verts_n,
724 double alpha,
725 double beta )
726 {
727 ErrorCode rval;
728 std::vector< double > verts_hc( verts_o.size() );
729 std::vector< int > fix_tag( verts.size() );
730
731
732 rval = laplacianFilter( mb, pcomm, verts, dim, fixed, verts_o, verts_n );
733 RC;
734
735
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
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
760 if( fix_tag[vindex] ) continue;
761
762 const int index = verts.index( *vit ) * 3;
763
764 moab::Range adjverts, adjelems;
765
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 }