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"
9 #include "MBParallelConventions.h"
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
23 LloydSmoother::~LloydSmoother()
24 {
25 if( iCreatedTag && fixedTag )
26 {
27 ErrorCode rval = mbImpl->tag_delete( fixedTag );MB_CHK_SET_ERR_RET( rval, "Failed to delete the fixed tag" );
28 }
29 }
30
31 ErrorCode LloydSmoother::perform_smooth()
32 {
33 ErrorCode rval;
34
35 if( myElems.empty() )
36 {
37 MB_SET_ERR( MB_FAILURE, "No elements specified to Lloyd smoother" );
38 }
39 else if( mbImpl->dimension_from_handle( *myElems.begin() ) != mbImpl->dimension_from_handle( *myElems.rbegin() ) )
40 {
41 MB_SET_ERR( MB_FAILURE, "Elements of unequal dimension specified to Lloyd smoother" );
42 }
43
44 int dim = mbImpl->dimension_from_handle( *myElems.begin() );
45
46
47 if( 0 > absTol )
48 {
49
50 BoundBox bb;
51 rval = bb.update( *mbImpl, myElems );MB_CHK_SET_ERR( rval, "Failed to compute bounding box around elements" );
52 absTol = relTol * bb.diagonal_length();
53 }
54
55
56 rval = initialize();MB_CHK_SET_ERR( rval, "Failed to initialize" );
57
58
59 Range verts;
60 rval = mbImpl->get_adjacencies( myElems, 0, false, verts, Interface::UNION );MB_CHK_SET_ERR( rval, "Failed to get all vertices" );
61
62
63
64
65
66
67 std::vector< double > vcentroids( 3 * verts.size() );
68 if( !coordsTag )
69 {
70 rval = mbImpl->get_coords( verts, &vcentroids[0] );MB_CHK_SET_ERR( rval, "Failed to get vert coords" );
71 }
72 else
73 {
74 rval = mbImpl->tag_get_data( coordsTag, verts, &vcentroids[0] );MB_CHK_SET_ERR( rval, "Failed to get vert coords tag values" );
75 }
76
77 Tag centroid;
78 rval = mbImpl->tag_get_handle( "", 3, MB_TYPE_DOUBLE, centroid, MB_TAG_CREAT | MB_TAG_DENSE );MB_CHK_SET_ERR( rval, "Couldn't get tag handle" );
79 rval = mbImpl->tag_set_data( centroid, verts, &vcentroids[0] );MB_CHK_SET_ERR( rval, "Failed setting centroid tag" );
80
81 Range owned_verts, shared_owned_verts;
82 #ifdef MOAB_HAVE_MPI
83
84 if( myPcomm && myPcomm->size() > 1 )
85 {
86 rval = myPcomm->filter_pstatus( verts, PSTATUS_NOT_OWNED, PSTATUS_NOT, -1, &owned_verts );MB_CHK_SET_ERR( rval, "Failed to filter on pstatus" );
87
88 rval = myPcomm->filter_pstatus( owned_verts, PSTATUS_SHARED, PSTATUS_AND, -1, &shared_owned_verts );MB_CHK_SET_ERR( rval, "Failed to filter for shared owned" );
89
90
91 if( shared_owned_verts.empty() ) shared_owned_verts.insert( *verts.begin() );
92 }
93 else
94 owned_verts = verts;
95 #else
96 owned_verts = verts;
97 #endif
98
99 std::vector< unsigned char > fix_tag( owned_verts.size() );
100 rval = mbImpl->tag_get_data( fixedTag, owned_verts, &fix_tag[0] );MB_CHK_SET_ERR( rval, "Failed to get fixed tag" );
101
102
103
104 vcentroids.resize( 3 * owned_verts.size() );
105 rval = mbImpl->tag_get_data( centroid, owned_verts, &vcentroids[0] );MB_CHK_SET_ERR( rval, "Failed to get centroid tag" );
106
107
108 std::vector< double > fcentroids( 3 * myElems.size() );
109 std::vector< double > ctag(
110 3 * CN::MAX_NODES_PER_ELEMENT );
111 const EntityHandle* conn;
112 int nconn;
113 Range::iterator eit, vit;
114 int e, v;
115 std::vector< EntityHandle > adj_elems;
116
117
118 double resid = DBL_MAX;
119 numIts = 0;
120 while( resid > absTol )
121 {
122 numIts++;
123 resid = 0.0;
124
125
126 for( eit = myElems.begin(), e = 0; eit != myElems.end(); ++eit, e++ )
127 {
128
129 rval = mbImpl->get_connectivity( *eit, conn, nconn );MB_CHK_SET_ERR( rval, "Failed to get connectivity" );
130
131 rval = mbImpl->tag_get_data( centroid, conn, nconn, &ctag[0] );MB_CHK_SET_ERR( rval, "Failed to get centroid" );
132 fcentroids[3 * e + 0] = fcentroids[3 * e + 1] = fcentroids[3 * e + 2] = 0.0;
133 for( v = 0; v < nconn; v++ )
134 {
135 fcentroids[3 * e + 0] += ctag[3 * v + 0];
136 fcentroids[3 * e + 1] += ctag[3 * v + 1];
137 fcentroids[3 * e + 2] += ctag[3 * v + 2];
138 }
139 for( v = 0; v < 3; v++ )
140 fcentroids[3 * e + v] /= nconn;
141 }
142 rval = mbImpl->tag_set_data( centroid, myElems, &fcentroids[0] );MB_CHK_SET_ERR( rval, "Failed to set elem centroid" );
143
144
145 for( vit = owned_verts.begin(), v = 0; vit != owned_verts.end(); ++vit, v++ )
146 {
147
148 if( fix_tag[v] ) continue;
149
150 adj_elems.clear();
151 rval = mbImpl->get_adjacencies( &( *vit ), 1, dim, false, adj_elems );MB_CHK_SET_ERR( rval, "Failed getting adjs" );
152 rval = mbImpl->tag_get_data( centroid, &adj_elems[0], adj_elems.size(), &fcentroids[0] );MB_CHK_SET_ERR( rval, "Failed to get elem centroid" );
153 double vnew[] = { 0.0, 0.0, 0.0 };
154 for( e = 0; e < (int)adj_elems.size(); e++ )
155 {
156 vnew[0] += fcentroids[3 * e + 0];
157 vnew[1] += fcentroids[3 * e + 1];
158 vnew[2] += fcentroids[3 * e + 2];
159 }
160 for( e = 0; e < 3; e++ )
161 vnew[e] /= adj_elems.size();
162 double delta = ( CartVect( vnew ) - CartVect( &vcentroids[3 * v] ) ).length();
163 resid = ( v ? std::max( resid, delta ) : delta );
164 for( e = 0; e < 3; e++ )
165 vcentroids[3 * v + e] = vnew[e];
166 }
167
168
169
170 rval = mbImpl->tag_set_data( centroid, owned_verts, &vcentroids[0] );MB_CHK_SET_ERR( rval, "Failed to set vertex centroid" );
171
172 #ifdef MOAB_HAVE_MPI
173
174 if( myPcomm && myPcomm->size() > 1 )
175 {
176 rval = myPcomm->exchange_tags( centroid, shared_owned_verts );MB_CHK_SET_ERR( rval, "Failed to exchange tags" );
177 }
178 #endif
179
180 if( reportIts && !( numIts % reportIts ) )
181 {
182 double global_max = resid;
183 #ifdef MOAB_HAVE_MPI
184
185 if( myPcomm && myPcomm->size() > 1 )
186 MPI_Reduce( &resid, &global_max, 1, MPI_DOUBLE, MPI_MAX, 0, myPcomm->comm() );
187 if( !myPcomm || !myPcomm->rank() )
188 #endif
189 std::cout << "Max residual = " << global_max << std::endl;
190 }
191
192 }
193
194
195 if( !coordsTag )
196 {
197 rval = mbImpl->set_coords( owned_verts, &vcentroids[0] );MB_CHK_SET_ERR( rval, "Failed to set vertex coords" );
198 }
199 else
200 {
201 rval = mbImpl->tag_set_data( coordsTag, owned_verts, &vcentroids[0] );MB_CHK_SET_ERR( rval, "Failed to set vert coords tag values" );
202 }
203
204 return MB_SUCCESS;
205 }
206
207 ErrorCode LloydSmoother::initialize()
208 {
209 ErrorCode rval = MB_SUCCESS;
210
211
212 if( !fixedTag )
213 {
214 unsigned char fixed = 0x0;
215 rval = mbImpl->tag_get_handle( "", 1, MB_TYPE_OPAQUE, fixedTag, MB_TAG_DENSE | MB_TAG_CREAT, &fixed );MB_CHK_SET_ERR( rval, "Trouble making fixed tag" );
216 iCreatedTag = true;
217
218
219 Skinner skinner( mbImpl );
220 Range skin, skin_verts;
221 rval = skinner.find_skin( 0, myElems, false, skin );MB_CHK_SET_ERR( rval, "Unable to find skin" );
222
223 #ifdef MOAB_HAVE_MPI
224
225 if( myPcomm )
226 {
227
228 rval = myPcomm->filter_pstatus( skin, PSTATUS_GHOST | PSTATUS_INTERFACE, PSTATUS_NOT );MB_CHK_SET_ERR( rval, "Failed to filter on shared status" );
229 }
230 #endif
231
232 rval = mbImpl->get_adjacencies( skin, 0, false, skin_verts, Interface::UNION );MB_CHK_SET_ERR( rval, "Trouble getting vertices" );
233
234
235 std::vector< unsigned char > marks( skin_verts.size(), 0x1 );
236 rval = mbImpl->tag_set_data( fixedTag, skin_verts, &marks[0] );MB_CHK_SET_ERR( rval, "Unable to set tag on skin" );
237 }
238
239 return MB_SUCCESS;
240 }
241
242 }