Mesh Oriented datABase  (version 5.6.0)
An array-based unstructured mesh library
LloydSmoother.cpp
Go to the documentation of this file.
1 #include "moab/LloydSmoother.hpp"
2 #include "moab/Skinner.hpp"
3 #include "moab/CN.hpp"
4 #include "moab/CartVect.hpp"
5 #include "moab/BoundBox.hpp"
6 
7 #ifdef MOAB_HAVE_MPI
8 #include "moab/ParallelComm.hpp"
10 #endif
11 
12 #include <iostream>
13 
14 namespace moab
15 {
16 
17 LloydSmoother::LloydSmoother( Interface* impl, ParallelComm* pc, Range& elms, Tag ctag, Tag ftag, double at, double rt )
18  : mbImpl( impl ), myPcomm( pc ), myElems( elms ), coordsTag( ctag ), fixedTag( ftag ), absTol( at ), relTol( rt ),
19  reportIts( 0 ), numIts( 0 ), iCreatedTag( false )
20 {
21 }
22 
24 {
25  if( iCreatedTag && fixedTag )
26  {
28  MB_CHK_SET_ERR_RET( rval, "Failed to delete the fixed tag" );
29  }
30 }
31 
33 {
34  if( myElems.empty() )
35  {
36  MB_SET_ERR( MB_FAILURE, "No elements specified to Lloyd smoother" );
37  }
39  {
40  MB_SET_ERR( MB_FAILURE, "Elements of unequal dimension specified to Lloyd smoother" );
41  }
42 
43  int dim = mbImpl->dimension_from_handle( *myElems.begin() );
44 
45  // first figure out tolerance to use
46  if( 0 > absTol )
47  {
48  // no tolerance set - get one relative to bounding box around elements
49  BoundBox bb;
50  MB_CHK_SET_ERR( bb.update( *mbImpl, myElems ), "Failed to compute bounding box around elements" );
51  absTol = relTol * bb.diagonal_length();
52  }
53 
54  // initialize if we need to
55  MB_CHK_SET_ERR( initialize(), "Failed to initialize" );
56 
57  // get all vertices
58  Range verts;
60  "Failed to get all vertices" );
61 
62  // perform Lloyd relaxation:
63  // 1. setup: set vertex centroids from vertex coords; filter to owned verts; get fixed tags
64 
65  // get all verts coords into tag; don't need to worry about filtering out fixed verts,
66  // we'll just be setting to their fixed coords
67  std::vector< double > vcentroids( 3 * verts.size() );
68  if( !coordsTag )
69  {
70  MB_CHK_SET_ERR( mbImpl->get_coords( verts, &vcentroids[0] ), "Failed to get vert coords" );
71  }
72  else
73  {
74  MB_CHK_SET_ERR( mbImpl->tag_get_data( coordsTag, verts, &vcentroids[0] ),
75  "Failed to get vert coords tag values" );
76  }
77 
78  Tag centroid;
80  "Couldn't get tag handle" );
81  MB_CHK_SET_ERR( mbImpl->tag_set_data( centroid, verts, &vcentroids[0] ), "Failed setting centroid tag" );
82 
83  Range owned_verts, shared_owned_verts;
84 #ifdef MOAB_HAVE_MPI
85  // filter verts down to owned ones and get fixed tag for them
86  if( myPcomm && myPcomm->size() > 1 )
87  {
88  MB_CHK_SET_ERR( myPcomm->filter_pstatus( verts, PSTATUS_NOT_OWNED, PSTATUS_NOT, -1, &owned_verts ),
89  "Failed to filter on pstatus" );
90  // get shared owned verts, for exchanging tags
91  MB_CHK_SET_ERR( myPcomm->filter_pstatus( owned_verts, PSTATUS_SHARED, PSTATUS_AND, -1, &shared_owned_verts ),
92  "Failed to filter for shared owned" );
93  // workaround: if no shared owned verts, put a non-shared one in the list, to prevent
94  // exchanging tags for all shared entities
95  if( shared_owned_verts.empty() ) shared_owned_verts.insert( *verts.begin() );
96  }
97  else
98  owned_verts = verts;
99 #else
100  owned_verts = verts;
101 #endif
102 
103  std::vector< unsigned char > fix_tag( owned_verts.size() );
104  MB_CHK_SET_ERR( mbImpl->tag_get_data( fixedTag, owned_verts, &fix_tag[0] ), "Failed to get fixed tag" );
105 
106  // now fill vcentroids array with positions of just owned vertices, since those are the ones
107  // we're actually computing
108  vcentroids.resize( 3 * owned_verts.size() );
109  MB_CHK_SET_ERR( mbImpl->tag_get_data( centroid, owned_verts, &vcentroids[0] ), "Failed to get centroid tag" );
110 
111  // some declarations for later iterations
112  std::vector< double > fcentroids( 3 * myElems.size() ); // fcentroids for element centroids
113  std::vector< double > ctag(
114  3 * CN::MAX_NODES_PER_ELEMENT ); // temporary coordinate storage for verts bounding an element
115  const EntityHandle* conn; // const ptr & size to elem connectivity
116  int nconn;
117  Range::iterator eit, vit; // for iterating over elems, verts
118  int e, v; // for indexing into centroid vectors
119  std::vector< EntityHandle > adj_elems; // used in vertex iteration
120 
121  // 2. while !converged
122  double resid = DBL_MAX;
123  numIts = 0;
124  while( resid > absTol )
125  {
126  numIts++;
127  resid = 0.0;
128 
129  // 2a. foreach elem: centroid = sum(vertex centroids)/num_verts_in_cell
130  for( eit = myElems.begin(), e = 0; eit != myElems.end(); ++eit, e++ )
131  {
132  // get verts for this elem
133  MB_CHK_SET_ERR( mbImpl->get_connectivity( *eit, conn, nconn ), "Failed to get connectivity" );
134  // get centroid tags for those verts
135  MB_CHK_SET_ERR( mbImpl->tag_get_data( centroid, conn, nconn, &ctag[0] ), "Failed to get centroid" );
136  fcentroids[3 * e + 0] = fcentroids[3 * e + 1] = fcentroids[3 * e + 2] = 0.0;
137  for( v = 0; v < nconn; v++ )
138  {
139  fcentroids[3 * e + 0] += ctag[3 * v + 0];
140  fcentroids[3 * e + 1] += ctag[3 * v + 1];
141  fcentroids[3 * e + 2] += ctag[3 * v + 2];
142  }
143  for( v = 0; v < 3; v++ )
144  fcentroids[3 * e + v] /= nconn;
145  }
146  MB_CHK_SET_ERR( mbImpl->tag_set_data( centroid, myElems, &fcentroids[0] ), "Failed to set elem centroid" );
147 
148  // 2b. foreach owned vertex:
149  for( vit = owned_verts.begin(), v = 0; vit != owned_verts.end(); ++vit, v++ )
150  {
151  // if !fixed
152  if( fix_tag[v] ) continue;
153  // vertex centroid = sum(cell centroids)/ncells
154  adj_elems.clear();
155  MB_CHK_SET_ERR( mbImpl->get_adjacencies( &( *vit ), 1, dim, false, adj_elems ), "Failed getting adjs" );
156  MB_CHK_SET_ERR( mbImpl->tag_get_data( centroid, &adj_elems[0], adj_elems.size(), &fcentroids[0] ),
157  "Failed to get elem centroid" );
158  double vnew[] = { 0.0, 0.0, 0.0 };
159  for( e = 0; e < (int)adj_elems.size(); e++ )
160  {
161  vnew[0] += fcentroids[3 * e + 0];
162  vnew[1] += fcentroids[3 * e + 1];
163  vnew[2] += fcentroids[3 * e + 2];
164  }
165  for( e = 0; e < 3; e++ )
166  vnew[e] /= adj_elems.size();
167  double delta = ( CartVect( vnew ) - CartVect( &vcentroids[3 * v] ) ).length();
168  resid = ( v ? std::max( resid, delta ) : delta );
169  for( e = 0; e < 3; e++ )
170  vcentroids[3 * v + e] = vnew[e];
171  }
172 
173  // set the centroid tag; having them only in vcentroids array isn't enough, as vertex
174  // centroids are accessed randomly in loop over faces
175  MB_CHK_SET_ERR( mbImpl->tag_set_data( centroid, owned_verts, &vcentroids[0] ),
176  "Failed to set vertex centroid" );
177 
178 #ifdef MOAB_HAVE_MPI
179  // 2c. exchange tags on owned verts
180  if( myPcomm && myPcomm->size() > 1 )
181  {
182  MB_CHK_SET_ERR( myPcomm->exchange_tags( centroid, shared_owned_verts ), "Failed to exchange tags" );
183  }
184 #endif
185 
186  if( reportIts && !( numIts % reportIts ) )
187  {
188  double global_max = resid;
189 #ifdef MOAB_HAVE_MPI
190  // global reduce for maximum delta, then report it
191  if( myPcomm && myPcomm->size() > 1 )
192  MPI_Reduce( &resid, &global_max, 1, MPI_DOUBLE, MPI_MAX, 0, myPcomm->comm() );
193  if( !myPcomm || !myPcomm->rank() )
194 #endif
195  std::cout << "Max residual = " << global_max << std::endl;
196  }
197 
198  } // end while
199 
200  // write the tag back onto vertex coordinates
201  if( !coordsTag )
202  {
203  MB_CHK_SET_ERR( mbImpl->set_coords( owned_verts, &vcentroids[0] ), "Failed to set vertex coords" );
204  }
205  else
206  {
207  MB_CHK_SET_ERR( mbImpl->tag_set_data( coordsTag, owned_verts, &vcentroids[0] ),
208  "Failed to set vert coords tag values" );
209  }
210 
211  return MB_SUCCESS;
212 }
213 
215 {
216  // first, check for tag; if we don't have it, make one and mark skin as fixed
217  if( !fixedTag )
218  {
219  unsigned char fixed = 0x0;
221  "Trouble making fixed tag" );
222  iCreatedTag = true;
223 
224  // get the skin; get facets, because we might need to filter on shared entities
225  Skinner skinner( mbImpl );
226  Range skin, skin_verts;
227  MB_CHK_SET_ERR( skinner.find_skin( 0, myElems, false, skin ), "Unable to find skin" );
228 
229 #ifdef MOAB_HAVE_MPI
230  // need to do a little extra if we're working in parallel
231  if( myPcomm )
232  {
233  // filter out ghost and interface facets
235  "Failed to filter on shared status" );
236  }
237 #endif
238  // get the vertices from those entities
239  MB_CHK_SET_ERR( mbImpl->get_adjacencies( skin, 0, false, skin_verts, Interface::UNION ),
240  "Trouble getting vertices" );
241 
242  // mark them fixed
243  std::vector< unsigned char > marks( skin_verts.size(), 0x1 );
244  MB_CHK_SET_ERR( mbImpl->tag_set_data( fixedTag, skin_verts, &marks[0] ), "Unable to set tag on skin" );
245  }
246 
247  return MB_SUCCESS;
248 }
249 
250 } // namespace moab