Branch data Line data Source code
1 : : /* *****************************************************************
2 : : MESQUITE -- The Mesh Quality Improvement Toolkit
3 : :
4 : : Copyright 2004 Sandia Corporation and Argonne National
5 : : Laboratory. Under the terms of Contract DE-AC04-94AL85000
6 : : with Sandia Corporation, the U.S. Government retains certain
7 : : rights in this software.
8 : :
9 : : This library is free software; you can redistribute it and/or
10 : : modify it under the terms of the GNU Lesser General Public
11 : : License as published by the Free Software Foundation; either
12 : : version 2.1 of the License, or (at your option) any later version.
13 : :
14 : : This library is distributed in the hope that it will be useful,
15 : : but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 : : Lesser General Public License for more details.
18 : :
19 : : You should have received a copy of the GNU Lesser General Public License
20 : : (lgpl.txt) along with this library; if not, write to the Free Software
21 : : Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 : :
23 : : [email protected], [email protected], [email protected],
24 : : [email protected], [email protected], [email protected]
25 : :
26 : : ***************************************************************** */
27 : : /*!
28 : : \file PatchData.cpp
29 : :
30 : : \author Thomas Leurent
31 : : \author Michael Brewer
32 : : \date 2002-01-17
33 : : */
34 : :
35 : : #include "PatchData.hpp"
36 : : #include "MsqMeshEntity.hpp"
37 : : #include "MsqFreeVertexIndexIterator.hpp"
38 : : #include "MeshInterface.hpp"
39 : : #include "MsqTimer.hpp"
40 : : #include "MsqDebug.hpp"
41 : : #include "GlobalPatch.hpp"
42 : : #include "PatchIterator.hpp"
43 : : #include "ExtraData.hpp"
44 : : #include "Settings.hpp"
45 : : #include "MappingFunction.hpp"
46 : :
47 : : #include <list>
48 : : #include <vector>
49 : : #include <map>
50 : : #include <algorithm>
51 : : #include <numeric>
52 : : #include <functional>
53 : : #include <utility>
54 : : #include <iostream>
55 : : #include <iomanip>
56 : : using std::endl;
57 : : using std::internal;
58 : : using std::left;
59 : : using std::list;
60 : : using std::map;
61 : : using std::ostream;
62 : : using std::setfill;
63 : : using std::setw;
64 : : using std::vector;
65 : :
66 : : namespace MBMesquite
67 : : {
68 : :
69 : 30 : const Settings PatchData::defaultSettings;
70 : :
71 : 1263 : PatchData::PatchData()
72 : : : myMesh( 0 ), myDomain( 0 ), numFreeVertices( 0 ), numSlaveVertices( 0 ), haveComputedInfos( 0 ), dataList( 0 ),
73 [ + - ][ + - ]: 1263 : mSettings( &defaultSettings )
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
[ + - ][ + - ]
74 : : {
75 : 1263 : }
76 : :
77 : : // Destructor
78 : 2526 : PatchData::~PatchData()
79 : : {
80 : 1263 : notify_patch_destroyed();
81 : 1263 : }
82 : :
83 : 0 : void PatchData::get_minmax_element_unsigned_area( double& min, double& max, MsqError& err )
84 : : {
85 [ # # ][ # # ]: 0 : if( !have_computed_info( MAX_UNSIGNED_AREA ) || !have_computed_info( MIN_UNSIGNED_AREA ) )
[ # # ]
86 : : {
87 : 0 : max = 0;
88 : 0 : min = MSQ_DBL_MAX;
89 : 0 : size_t count = num_elements();
90 [ # # ]: 0 : for( size_t i = 0; i < count; ++i )
91 : : {
92 : : double vol;
93 [ # # ]: 0 : assert( i < elementArray.size() );
94 [ # # ][ # # ]: 0 : vol = elementArray[i].compute_unsigned_area( *this, err );MSQ_ERRRTN( err );
[ # # ]
95 [ # # ]: 0 : if( vol > max ) max = vol;
96 [ # # ]: 0 : if( vol < min ) min = vol;
97 : : }
98 : 0 : note_have_info( MAX_UNSIGNED_AREA );
99 : 0 : note_have_info( MIN_UNSIGNED_AREA );
100 : 0 : computedInfos[MAX_UNSIGNED_AREA] = max;
101 : 0 : computedInfos[MIN_UNSIGNED_AREA] = min;
102 : : }
103 : : else
104 : : {
105 : 0 : max = computedInfos[MAX_UNSIGNED_AREA];
106 : 0 : min = computedInfos[MIN_UNSIGNED_AREA];
107 : : }
108 : :
109 [ # # ][ # # ]: 0 : if( max <= 0 || min < 0 || min == MSQ_DBL_MAX ) MSQ_SETERR( err )( MsqError::INTERNAL_ERROR );
[ # # ][ # # ]
110 : : }
111 : :
112 : 58614 : void PatchData::get_minmax_edge_length( double& min, double& max ) const
113 : : {
114 : 58614 : min = HUGE_VAL;
115 : 58614 : max = -HUGE_VAL;
116 : :
117 [ + + ]: 296206 : for( size_t i = 0; i < num_elements(); ++i )
118 : : {
119 : 237592 : const MsqMeshEntity& elem = element_by_index( i );
120 : 237592 : const size_t* conn = elem.get_vertex_index_array();
121 : 237592 : const unsigned num_edges = TopologyInfo::edges( elem.get_element_type() );
122 [ + + ]: 1190877 : for( unsigned e = 0; e < num_edges; ++e )
123 : : {
124 : 953285 : const unsigned* edge = TopologyInfo::edge_vertices( elem.get_element_type(), e );
125 : : const double len_sqr =
126 [ + - ]: 953285 : ( vertex_by_index( conn[edge[0]] ) - vertex_by_index( conn[edge[1]] ) ).length_squared();
127 [ + + ]: 953285 : if( len_sqr < min ) min = len_sqr;
128 [ + + ]: 953285 : if( len_sqr > max ) max = len_sqr;
129 : : }
130 : : }
131 : 58614 : min = sqrt( min );
132 : 58614 : max = sqrt( max );
133 : 58614 : }
134 : :
135 : : /*
136 : : double PatchData::get_average_Lambda_3d( MsqError &err)
137 : : {
138 : : double avg;
139 : : if (have_computed_info(AVERAGE_DET3D))
140 : : {
141 : : avg = computedInfos[AVERAGE_DET3D];
142 : : }
143 : : else
144 : : {
145 : : avg =0.;
146 : : int total_num_corners =0;
147 : : Matrix3D A[MSQ_MAX_NUM_VERT_PER_ENT];
148 : : for (size_t i=0; i<elementArray.size(); ++i) {
149 : : int nve = elementArray[i].corner_count();
150 : : elementArray[i].compute_corner_matrices(*this, A, nve, err);
151 : : MSQ_ERRZERO(err);
152 : : total_num_corners += nve;
153 : : for (int c=0; c<nve; ++c) {
154 : : avg += TargetCalculator::compute_Lambda(A[c], err);
155 : : MSQ_ERRZERO(err);
156 : : }
157 : : }
158 : :
159 : : avg = avg / total_num_corners;
160 : : computedInfos[AVERAGE_DET3D] = avg;
161 : : note_have_info(AVERAGE_DET3D);
162 : : }
163 : : return avg;
164 : : }
165 : : */
166 : :
167 : : /*! \fn PatchData::reorder()
168 : : Physically reorder the vertices and elements in the PatchData to improve
169 : : the locality of reference. This method implements a Reverse Breadth First
170 : : Search order starting with the vertex furthest from the origin. Other
171 : : orderings can also be implemented.
172 : : */
173 : 56 : void PatchData::reorder()
174 : : {
175 : : size_t i, j;
176 [ + - ]: 56 : const size_t num_vertex = num_nodes();
177 [ + - ]: 56 : const size_t num_elem = num_elements();
178 : :
179 : : // Step 1: Clear any cached data that will be invalidated by this
180 : 56 : vertexNormalIndices.clear();
181 : 56 : normalData.clear();
182 : : // vertexDomainDOF.clear();
183 : :
184 : : // Step 2: Make sure we have vertex-to-element adjacencies
185 [ + - ][ + - ]: 56 : if( !vertAdjacencyArray.size() ) generate_vertex_to_element_data();
186 : :
187 : : // Step 3: Do breadth-first search
188 [ + - ]: 56 : std::vector< bool > visited( num_vertex, false );
189 [ + - ]: 112 : std::vector< size_t > vertex_order( num_vertex );
190 : 56 : std::vector< size_t >::iterator q1_beg, q1_end, q2_end;
191 : 56 : q1_beg = q1_end = q2_end = vertex_order.begin();
192 : : // Outer loop will be done once for each disconnected chunk of mesh.
193 [ + - ][ + + ]: 112 : while( q1_beg != vertex_order.end() )
194 : : {
195 : : // Find vertex furthest from the origin
196 : 56 : double max = -1.0;
197 : 56 : size_t vtx_idx = num_vertex;
198 [ + + ]: 11669 : for( i = 0; i < num_vertex; ++i )
199 [ + - ][ + - ]: 11613 : if( !visited[i] )
200 : : {
201 [ + - ][ + - ]: 11613 : double dist = vertexArray[i].length_squared();
202 [ + + ]: 11613 : if( dist > max )
203 : : {
204 : 399 : max = dist;
205 : 11613 : vtx_idx = i;
206 : : }
207 : : }
208 [ - + ]: 56 : assert( vtx_idx < num_vertex );
209 : :
210 [ + - ][ + - ]: 56 : *q2_end++ = vtx_idx;
211 : : ;
212 [ + - ]: 56 : visited[vtx_idx] = true;
213 [ + - ][ + + ]: 460 : do
214 : : {
215 : 460 : q1_end = q2_end;
216 [ + - ][ + - ]: 12073 : for( ; q1_beg != q1_end; ++q1_beg )
[ + + ]
217 : : {
218 [ + - ][ + - ]: 11613 : size_t vtx_adj_offset = vertAdjacencyOffsets[*q1_beg];
219 [ + - ][ + - ]: 11613 : size_t vtx_adj_end = vertAdjacencyOffsets[*q1_beg + 1];
220 [ + + ]: 132355 : for( i = vtx_adj_offset; i < vtx_adj_end; ++i )
221 : : {
222 [ + - ]: 120742 : size_t elem = vertAdjacencyArray[i];
223 [ - + ]: 120742 : assert( elem < elementArray.size() );
224 [ + - ][ + - ]: 120742 : size_t num_elem_verts = elementArray[elem].node_count();
225 [ + - ][ + - ]: 120742 : size_t* elem_verts = elementArray[elem].get_vertex_index_array();
226 [ + + ]: 678072 : for( j = 0; j < num_elem_verts; ++j )
227 : : {
228 : 557330 : size_t elem_vert = elem_verts[j];
229 [ + - ][ + + ]: 557330 : if( !visited[elem_vert] )
230 : : {
231 [ + - ][ + - ]: 11557 : *q2_end++ = elem_vert;
232 : : ;
233 [ + - ]: 11557 : visited[elem_vert] = true;
234 : : }
235 : : }
236 : : }
237 : : }
238 : : } while( q2_end != q1_end );
239 : : }
240 : :
241 : : // Step 4: vertex_order contains the list of current vertex indices
242 : : // in the opposite of the order that they will occur in the
243 : : // reorderd patch. The following code will construct veretx_map
244 : : // from vertex_order with the following properties
245 : : // - vertex_map will be indexed by the current vertex index and
246 : : // contain the new index of that vertex (inverse of vertex_order)
247 : : // - the vertices will be grouped by their free/slave/fixed flag.
248 [ + - ]: 112 : std::vector< size_t > vertex_map( num_vertex );
249 : 56 : const size_t fixed_vtx_offset = numFreeVertices + numSlaveVertices;
250 : 56 : size_t free_idx = 0, slave_idx = numFreeVertices, fixed_idx = fixed_vtx_offset;
251 [ + + ]: 11669 : for( i = 1; i <= num_vertex; ++i )
252 : : {
253 [ + - ]: 11613 : size_t vtx_idx = vertex_order[num_vertex - i];
254 [ + + ]: 11613 : if( vtx_idx < numFreeVertices )
255 [ + - ]: 6310 : vertex_map[vtx_idx] = free_idx++;
256 [ - + ]: 5303 : else if( vtx_idx < fixed_vtx_offset )
257 [ # # ]: 0 : vertex_map[vtx_idx] = slave_idx++;
258 : : else
259 [ + - ]: 5303 : vertex_map[vtx_idx] = fixed_idx++;
260 : : }
261 : : // make sure everything adds up
262 [ - + ]: 56 : assert( free_idx == numFreeVertices );
263 [ - + ]: 56 : assert( slave_idx == fixed_vtx_offset );
264 [ - + ]: 56 : assert( fixed_idx == num_vertex );
265 : :
266 : : // Step 5: compute element permutation
267 : : // initialize all to "num_elem" to indicate unvisited
268 [ + - ]: 112 : std::vector< size_t > element_map( num_elem, num_elem );
269 : 56 : size_t elem_idx = 0;
270 [ + + ]: 11669 : for( i = 1; i <= num_vertex; ++i )
271 : : {
272 [ + - ]: 11613 : size_t vtx_idx = vertex_order[num_vertex - i];
273 [ + - ]: 11613 : size_t vtx_adj_offset = vertAdjacencyOffsets[vtx_idx];
274 [ + - ]: 11613 : size_t vtx_adj_end = vertAdjacencyOffsets[vtx_idx + 1];
275 [ + + ]: 132355 : for( j = vtx_adj_offset; j < vtx_adj_end; ++j )
276 : : {
277 [ + - ]: 120742 : size_t elem = vertAdjacencyArray[j];
278 [ + - ][ + + ]: 120742 : if( element_map[elem] == num_elem ) element_map[elem] = elem_idx++;
[ + - ]
279 : : }
280 : : }
281 : : // make sure everything adds up
282 [ - + ]: 56 : assert( elem_idx == num_elem );
283 : :
284 : : // Step 6: Permute the vertices
285 [ + - ]: 112 : std::vector< MsqVertex > new_vertex_array( num_vertex );
286 [ + - ]: 112 : std::vector< Mesh::VertexHandle > new_vtx_handle_array( num_vertex );
287 [ + + ]: 11669 : for( i = 0; i < num_vertex; ++i )
288 : : {
289 [ + - ]: 11613 : size_t new_idx = vertex_map[i];
290 [ + - ][ + - ]: 11613 : new_vertex_array[new_idx] = vertexArray[i];
[ + - ]
291 [ + - ][ + - ]: 11613 : new_vtx_handle_array[new_idx] = vertexHandlesArray[i];
292 : : }
293 : 56 : vertexArray.swap( new_vertex_array );
294 : 56 : vertexHandlesArray.swap( new_vtx_handle_array );
295 : :
296 : : // Step 7: Permute the elements and vertex indices for the elements
297 [ + - ]: 112 : std::vector< MsqMeshEntity > new_elem_array( num_elem );
298 [ + - ]: 112 : std::vector< Mesh::ElementHandle > new_elem_handle_array( num_elem );
299 [ + + ]: 27963 : for( i = 0; i < num_elem; ++i )
300 : : {
301 [ - + ]: 27907 : assert( i < elementArray.size() );
302 [ + - ][ + - ]: 27907 : size_t vert_count = elementArray[i].node_count();
303 [ + - ][ + - ]: 27907 : size_t* conn_array = elementArray[i].get_vertex_index_array();
304 [ + + ]: 148649 : for( j = 0; j < vert_count; ++j )
305 : : {
306 [ + - ]: 120742 : conn_array[j] = vertex_map[conn_array[j]];
307 : : }
308 : :
309 [ + - ]: 27907 : size_t new_idx = element_map[i];
310 [ - + ]: 27907 : assert( new_idx < num_elem );
311 [ + - ][ + - ]: 27907 : new_elem_array[new_idx] = elementArray[i];
312 [ + - ][ + - ]: 27907 : new_elem_handle_array[new_idx] = elementHandlesArray[i];
313 : : }
314 : 56 : elementArray.swap( new_elem_array );
315 : 56 : elementHandlesArray.swap( new_elem_handle_array );
316 : :
317 : : // Step 8: Clear no-longer-valid vertex-to-element adjacency info.
318 [ + - ]: 56 : if( vertAdjacencyOffsets.size() )
319 : : {
320 : 56 : vertAdjacencyOffsets.clear();
321 : 56 : vertAdjacencyArray.clear();
322 [ + - ]: 56 : generate_vertex_to_element_data();
323 : : }
324 : :
325 [ + - ]: 112 : notify_new_patch();
326 : 56 : }
327 : :
328 : : /*!
329 : : PatchData::move_free_vertices_constrained() moves the free vertices
330 : : (see MsqVertex::is_free() ) as specified by the search direction (dk)
331 : : and scale factor (step_size). After being moved, the vertices are
332 : : projected onto the appropriate geometry. Fixed vertices are not moved
333 : : regardless of their corresponding dk direction.
334 : : It is often useful to use the create_coords_momento() function before
335 : : calling this function.
336 : : Compile with -DMSQ_DBG3 to check that fixed vertices
337 : : are not moved with that call.
338 : :
339 : : \param dk: must be a [nb_vtx] array of Vector3D that contains
340 : : the direction in which to move each vertex. Fixed vertices moving
341 : : direction should be zero, although fixed vertices will not be
342 : : moved regardless of their corresponding dk value.
343 : : \param nb_vtx is the number of vertices to move. must corresponds
344 : : to the number of vertices in the PatchData.
345 : : \param step_size will multiply the moving direction given in dk
346 : : for each vertex.
347 : : */
348 : 216870 : void PatchData::move_free_vertices_constrained( Vector3D dk[], size_t nb_vtx, double step_size, MsqError& err )
349 : : {
350 [ - + ]: 216870 : if( nb_vtx != num_free_vertices() )
351 : : {
352 : : MSQ_SETERR( err )
353 [ # # ]: 0 : ( "The directional vector must be of length numVertices.", MsqError::INVALID_ARG );
354 : 0 : return;
355 : : }
356 : :
357 : : size_t i;
358 [ + + ]: 899044 : for( i = 0; i < num_free_vertices(); ++i )
359 : : {
360 [ + - ][ + - ]: 682174 : vertexArray[i] += ( step_size * dk[i] );
361 [ - + ][ # # ]: 682174 : snap_vertex_to_domain( i, err );MSQ_ERRRTN( err );
[ - + ]
362 : : }
363 : :
364 [ + + ]: 216870 : if( numSlaveVertices )
365 : : {
366 [ - + ][ # # ]: 216870 : update_slave_node_coordinates( err );MSQ_CHKERR( err );
367 : : }
368 : : }
369 : :
370 : : /*! set_free_vertices_constrained is similar to
371 : : PatchData::move_free_vertices_constrained() except the original vertex positions
372 : : are those stored in the PatchDataVerticesMemento instead of the actual vertex
373 : : position stored in the PatchData Vertex array. The final location is stored
374 : : in the PatchData; the PatchDataVerticesMemento is unchanged.
375 : :
376 : : \param dk: must be a [nb_vtx] array of Vector3D that contains
377 : : the direction in which to move each vertex. Fixed vertices moving
378 : : direction should be zero, although fixed vertices will not be
379 : : moved regardless of their corresponding dk value.
380 : : \param nb_vtx is the number of vertices to move. must corresponds
381 : : to the number of vertices in the PatchData.
382 : : \param step_size will multiply the moving direction given in dk
383 : : for each vertex.
384 : : */
385 : 172104 : void PatchData::set_free_vertices_constrained( PatchDataVerticesMemento* memento, Vector3D dk[], size_t nb_vtx,
386 : : double step_size, MsqError& err )
387 : : {
388 [ + - ][ - + ]: 172104 : if( memento->originator != this || nb_vtx != num_free_vertices() )
[ - + ]
389 : : {
390 [ # # ]: 0 : MSQ_SETERR( err )( MsqError::INVALID_ARG );
391 : 0 : return;
392 : : }
393 : :
394 : : size_t i;
395 [ + + ]: 1429257 : for( i = 0; i < num_free_vertices(); ++i )
396 : : {
397 [ + - ][ + - ]: 1257153 : vertexArray[i] = memento->vertices[i] + ( step_size * dk[i] );
[ + - ][ + - ]
398 [ - + ][ # # ]: 1257153 : snap_vertex_to_domain( i, err );MSQ_ERRRTN( err );
[ - + ]
399 : : }
400 : :
401 [ - + ]: 172104 : if( numSlaveVertices )
402 : : {
403 [ # # ][ # # ]: 172104 : update_slave_node_coordinates( err );MSQ_CHKERR( err );
404 : : }
405 : :
406 : : // Checks that moving direction is zero for fixed vertices.
407 : : if( MSQ_DBG( 3 ) )
408 : : {
409 : : for( i = 0; i < num_nodes(); ++i )
410 : : {
411 : : if( dk[i].length_squared() != 0.0 )
412 : : {
413 : : MSQ_DBGOUT( 3 ) << "dk[" << i << "]: " << dk[i] << endl;
414 : : MSQ_DBGOUT( 3 ) << "moving a fixed vertex." << endl;
415 : : }
416 : : }
417 : : }
418 : : }
419 : :
420 : 0 : static void project_to_plane( Vector3D& vect, const Vector3D& norm )
421 : : {
422 : 0 : double len_sqr = norm % norm;
423 [ # # ][ # # ]: 0 : if( len_sqr > DBL_EPSILON ) vect -= norm * ( ( norm % vect ) / len_sqr );
424 : 0 : }
425 : :
426 : 0 : void PatchData::project_gradient( std::vector< Vector3D >& gradient, MsqError& err )
427 : : {
428 [ # # ][ # # ]: 0 : if( !domain_set() ) return;
429 : :
430 [ # # ][ # # ]: 0 : if( gradient.size() != num_free_vertices() )
431 : : {
432 [ # # ][ # # ]: 0 : MSQ_SETERR( err )( MsqError::INVALID_ARG );
433 : 0 : return;
434 : : }
435 : :
436 [ # # ]: 0 : if( normalData.empty() )
437 : : {
438 [ # # ][ # # ]: 0 : update_cached_normals( err );MSQ_ERRRTN( err );
[ # # ][ # # ]
[ # # ][ # # ]
439 : : }
440 : :
441 [ # # ]: 0 : Vector3D norm;
442 [ # # ][ # # ]: 0 : for( size_t i = 0; i < num_free_vertices(); ++i )
443 : : {
444 [ # # ]: 0 : if( vertexNormalIndices.empty() )
445 : : { // whole mesh on single 2D domain
446 [ # # ][ # # ]: 0 : norm = normalData[i];
447 [ # # ][ # # ]: 0 : project_to_plane( gradient[i], norm );
448 : : }
449 [ # # ][ # # ]: 0 : else if( vertexDomainDOF[i] == 2 )
450 : : { // vertex on surface
451 [ # # ][ # # ]: 0 : norm = normalData[vertexNormalIndices[i]];
[ # # ]
452 [ # # ][ # # ]: 0 : project_to_plane( gradient[i], norm );
453 : : }
454 [ # # ][ # # ]: 0 : else if( vertexDomainDOF[i] == 1 )
455 : : {
456 : : size_t j, num_elem;
457 [ # # ][ # # ]: 0 : const size_t* elems = get_vertex_element_adjacencies( i, num_elem, err );MSQ_ERRRTN( err );
[ # # ][ # # ]
[ # # ][ # # ]
458 [ # # ]: 0 : for( j = 0; j < num_elem; ++j )
459 : : {
460 [ # # ][ # # ]: 0 : if( 2 == TopologyInfo::dimension( element_by_index( elems[j] ).get_element_type() ) )
[ # # ][ # # ]
461 : : {
462 [ # # ][ # # ]: 0 : norm = vertexArray[i];
463 [ # # ][ # # ]: 0 : get_domain()->element_normal_at( elementHandlesArray[elems[j]], norm );
[ # # ]
464 [ # # ][ # # ]: 0 : project_to_plane( gradient[i], norm );
465 : : }
466 : : }
467 : : }
468 : : }
469 : : }
470 : :
471 : : /*! Finds the maximum movement (in the distance norm) of the vertices in a
472 : : patch. The previous vertex positions are givena as a
473 : : PatchDataVerticesMemento (memento). The distance squared which each
474 : : vertex has moved is then calculated, and the largest of those distances
475 : : is returned. This function only considers the movement of vertices
476 : : that are currently 'free'.
477 : : \param memento a memento of this patch's vertex position at some
478 : : (prior) time in the optimization.
479 : : */
480 : 827093 : double PatchData::get_max_vertex_movement_squared( PatchDataVerticesMemento* memento, MsqError& )
481 : : {
482 : 827093 : double max_dist = 0.0;
483 [ + + ]: 1887508 : for( size_t i = 0; i < memento->vertices.size(); ++i )
484 : : {
485 [ + - ]: 1060415 : double temp_dist = ( vertexArray[i] - memento->vertices[i] ).length_squared();
486 [ + + ]: 1060415 : if( temp_dist > max_dist ) max_dist = temp_dist;
487 : : }
488 : 827093 : return max_dist;
489 : : }
490 : :
491 : : /*!
492 : : */
493 : 0 : void PatchData::set_all_vertices_soft_fixed( MsqError& /*err*/ )
494 : : {
495 [ # # ]: 0 : for( size_t i = 0; i < num_free_vertices(); ++i )
496 : 0 : vertexArray[i].set_soft_fixed_flag();
497 : 0 : }
498 : :
499 : : /*!
500 : : */
501 : 49295 : void PatchData::set_free_vertices_soft_fixed( MsqError& /*err*/ )
502 : : {
503 [ + + ]: 98590 : for( size_t i = 0; i < num_free_vertices(); ++i )
504 : : {
505 [ + - ]: 49295 : if( vertexArray[i].is_free_vertex() ) vertexArray[i].set_soft_fixed_flag();
506 : : }
507 : 49295 : }
508 : :
509 : : /*!
510 : : */
511 : 776818 : void PatchData::set_all_vertices_soft_free( MsqError& /*err*/ )
512 : : {
513 [ + + ]: 7768598 : for( size_t i = 0; i < num_nodes(); ++i )
514 : 6991780 : vertexArray[i].remove_soft_fixed_flag();
515 : 776818 : }
516 : :
517 : : /*! Get coordinates of element vertices, in canonical order.
518 : :
519 : : \param elem_index The element index in the Patch
520 : : \param coords This vector will have the coordinates appended to it.
521 : : If necessary, make sure to clear the vector before calling the function.
522 : : */
523 : 0 : void PatchData::get_element_vertex_coordinates( size_t elem_index, std::vector< Vector3D >& coords, MsqError& /*err*/ )
524 : : {
525 : : // Check index
526 [ # # ]: 0 : if( elem_index >= num_elements() ) return;
527 : :
528 : : // Ask the element for its vertex indices
529 [ # # ]: 0 : assert( elem_index < elementArray.size() );
530 : 0 : const size_t* vertex_indices = elementArray[elem_index].get_vertex_index_array();
531 : :
532 : : // Get the coords for each indicated vertex
533 : 0 : size_t num_verts = elementArray[elem_index].vertex_count();
534 : 0 : coords.reserve( coords.size() + num_verts );
535 [ # # ]: 0 : for( size_t i = 0; i < num_verts; i++ )
536 [ # # ]: 0 : coords.push_back( Vector3D( vertexArray[vertex_indices[i]] ) );
537 : : }
538 : :
539 : : /*! This is an inefficient way of retrieving vertex_indices.
540 : : Use PatchData::get_element_array followed by
541 : : MsqMeshEntity::get_vertex_index_array() if you don't need
542 : : to fill an STL vector.
543 : : */
544 : 0 : void PatchData::get_element_vertex_indices( size_t elem_index, std::vector< size_t >& vertex_indices,
545 : : MsqError& /*err*/ )
546 : : {
547 : : // Ask the element for its vertex indices
548 [ # # ]: 0 : assert( elem_index < elementArray.size() );
549 : 0 : elementArray[elem_index].get_vertex_indices( vertex_indices );
550 : 0 : }
551 : :
552 : 0 : void PatchData::get_vertex_element_indices( size_t vertex_index, std::vector< size_t >& elem_indices, MsqError& err )
553 : : {
554 : : size_t count;
555 : : const size_t* ptr;
556 [ # # ]: 0 : ptr = get_vertex_element_adjacencies( vertex_index, count, err );
557 [ # # ]: 0 : elem_indices.resize( count );
558 [ # # ]: 0 : std::copy( ptr, ptr + count, elem_indices.begin() );
559 : 0 : }
560 : :
561 : 0 : void PatchData::get_vertex_element_indices( size_t vertex_index, unsigned element_dimension,
562 : : std::vector< size_t >& elem_indices, MsqError& err )
563 : : {
564 : 0 : elem_indices.clear();
565 : : size_t count;
566 : : const size_t* ptr;
567 [ # # ]: 0 : ptr = get_vertex_element_adjacencies( vertex_index, count, err );
568 [ # # ]: 0 : for( const size_t* const end = ptr + count; ptr != end; ++ptr )
569 : : {
570 [ # # ]: 0 : assert( *ptr < elementArray.size() );
571 [ # # ][ # # ]: 0 : const EntityTopology type = elementArray[*ptr].get_element_type();
572 [ # # ]: 0 : const unsigned dim = TopologyInfo::dimension( type );
573 [ # # ][ # # ]: 0 : if( dim == element_dimension ) elem_indices.push_back( *ptr );
574 : : }
575 : 0 : }
576 : :
577 : 61225 : const size_t* PatchData::get_vertex_element_adjacencies( size_t vertex_index, size_t& array_len_out, MsqError& )
578 : : {
579 : : // Make sure we've got the data
580 [ + + ]: 61225 : if( vertAdjacencyArray.empty() ) { generate_vertex_to_element_data(); }
581 : :
582 : 61225 : const size_t begin = vertAdjacencyOffsets[vertex_index];
583 : 61225 : const size_t end = vertAdjacencyOffsets[vertex_index + 1];
584 : 61225 : array_len_out = end - begin;
585 : 61225 : return &vertAdjacencyArray[begin];
586 : : }
587 : :
588 : : /*!
589 : : \brief This function fills a vector<size_t> with the indices
590 : : to vertices connected to the given vertex by an edge. If vert_indices
591 : : is not initially empty, the function will not delete the current
592 : : contents. Instead, it will append the new indices at the end of
593 : : the vector.
594 : :
595 : : */
596 : 1132545 : void PatchData::get_adjacent_vertex_indices( size_t vertex_index, std::vector< size_t >& vert_indices,
597 : : MsqError& err ) const
598 : : {
599 : 1132545 : bitMap.clear();
600 [ + - ][ + - ]: 1132545 : bitMap.resize( num_nodes(), false );
601 : :
602 : : const size_t* conn;
603 : : size_t conn_idx, curr_vtx_idx;
604 : : const unsigned* adj;
605 : : unsigned num_adj, i;
606 : 1132545 : std::vector< MsqMeshEntity >::const_iterator e;
607 [ + - ][ + - ]: 29380576 : for( e = elementArray.begin(); e != elementArray.end(); ++e )
[ + + ]
608 : : {
609 [ + - ][ + - ]: 28248031 : conn = e->get_vertex_index_array();
610 [ + - ][ + - ]: 28248031 : conn_idx = std::find( conn, conn + e->node_count(), vertex_index ) - conn;
[ + - ]
611 [ + - ][ + - ]: 28248031 : if( conn_idx == e->node_count() ) continue;
[ + + ]
612 : :
613 : : // If a higher-order node, return corners of side/face
614 : : // that node is in the center of.
615 [ + - ][ + - ]: 11157403 : EntityTopology type = e->get_element_type();
616 [ + - ][ + + ]: 11157403 : if( conn_idx >= TopologyInfo::corners( type ) && type != POLYGON )
[ - + ][ - + ]
617 : : {
618 : : unsigned dim, id;
619 [ # # ][ # # ]: 1132545 : TopologyInfo::side_from_higher_order( type, e->node_count(), conn_idx, dim, id, err );MSQ_ERRRTN( err );
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
620 [ # # ]: 0 : adj = TopologyInfo::side_vertices( type, dim, id, num_adj );
621 : : }
622 : : else
623 : : {
624 [ + - ][ + - ]: 11157403 : EntityTopology topo = e->get_element_type();
625 [ + + ]: 11157403 : if( topo == POLYGON )
626 : : {
627 [ + - ][ + - ]: 1500 : unsigned number_of_nodes = e->node_count();
628 : 1500 : num_adj = 2; // always 2 for a polygon
629 : : unsigned vert_adj[2];
630 : 1500 : vert_adj[0] = ( conn_idx + 1 ) % number_of_nodes;
631 : 1500 : vert_adj[1] = ( conn_idx + number_of_nodes - 1 ) % number_of_nodes;
632 [ + + ]: 4500 : for( i = 0; i < num_adj; ++i )
633 : : {
634 : 3000 : curr_vtx_idx = conn[vert_adj[i]]; // get index into patch vertex list
635 [ + - ][ + + ]: 3000 : if( !bitMap[curr_vtx_idx] )
636 : : {
637 [ + - ]: 1500 : vert_indices.push_back( curr_vtx_idx );
638 [ + - ]: 1500 : bitMap[curr_vtx_idx] = true;
639 : : }
640 : : }
641 : : }
642 : : else
643 : : {
644 [ + - ]: 11155903 : adj = TopologyInfo::adjacent_vertices( topo, conn_idx, num_adj );
645 [ + + ]: 41405017 : for( i = 0; i < num_adj; ++i )
646 : : {
647 : 30249114 : curr_vtx_idx = conn[adj[i]]; // get index into patch vertex list
648 [ + - ][ + + ]: 30249114 : if( !bitMap[curr_vtx_idx] )
649 : : {
650 [ + - ]: 7852599 : vert_indices.push_back( curr_vtx_idx );
651 [ + - ]: 7852599 : bitMap[curr_vtx_idx] = true;
652 : : }
653 : : }
654 : : }
655 : : }
656 : : }
657 : : }
658 : :
659 : : /*! Fills a vector of indices into the entities array. The entities
660 : : in the vector are connected the given entity (ent_ind) via an
661 : : n-diminsional entity (where 'n' is a given integer).
662 : : Thus, if n = 0, the entities must be connected via a vertex.
663 : : If n = 1, the entities must be connected via an edge.
664 : : If n = 2, the entities must be connected via a two-dimensional element.
665 : : NOTE: if n is 2 and the elements in the entity array are
666 : : two-dimensional, no entities should meet this criterion.
667 : : The adj_ents vector is cleared at the beginning of the call.
668 : :
669 : : */
670 : 0 : void PatchData::get_adjacent_entities_via_n_dim( int n, size_t ent_ind, std::vector< size_t >& adj_ents, MsqError& err )
671 : : {
672 : : // reset the vector
673 : 0 : adj_ents.clear();
674 : : // vertices of this entity (given by ent_ind)
675 [ # # ]: 0 : vector< size_t > verts;
676 : : // vector to store elements attached to the vertices in verts
677 [ # # ][ # # ]: 0 : vector< size_t > elem_on_vert[MSQ_MAX_NUM_VERT_PER_ENT];
[ # # ][ # #
# # # # ]
678 : : // length of above vectos
679 : : int length_elem_on_vert[MSQ_MAX_NUM_VERT_PER_ENT];
680 : : // get verts on this element
681 [ # # ]: 0 : get_element_vertex_indices( ent_ind, verts, err );
682 : 0 : int num_vert = verts.size();
683 : 0 : int i = 0;
684 : 0 : int j = 0;
685 [ # # ]: 0 : for( i = 0; i < num_vert; ++i )
686 : : {
687 : : // get elements on the vertices in verts and the number of vertices
688 [ # # ][ # # ]: 0 : get_vertex_element_indices( verts[i], elem_on_vert[i], err );MSQ_ERRRTN( err );
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
689 : 0 : length_elem_on_vert[i] = elem_on_vert[i].size();
690 : : }
691 : : // this_ent is the index for an entity which is a candidate to be placed
692 : : // into adj_ents
693 : : size_t this_ent;
694 : : // num of times this_ent has been found in the vectors of entity indices
695 : 0 : int counter = 0;
696 : 0 : i = 0;
697 : : // loop of each vert on ent_ind
698 [ # # ][ # # ]: 0 : while( i < num_vert )
699 : : {
700 : : // loop over each ent connected to vert
701 : 0 : j = 0;
702 [ # # ]: 0 : while( j < length_elem_on_vert[i] )
703 : : {
704 : : // get candidate element
705 [ # # ]: 0 : this_ent = elem_on_vert[i][j];
706 : : // if we haven't already consider this ent
707 [ # # ]: 0 : if( this_ent != ent_ind )
708 : : {
709 : : // if this_ent occurred earlier we would have already considered it
710 : : // so start at i and j+1
711 : 0 : int k1 = i;
712 : 0 : int k2 = j + 1;
713 : : // this_ent has occured once so far
714 : 0 : counter = 1;
715 : : // while k1 < num_vert
716 [ # # ]: 0 : while( k1 < num_vert )
717 : : {
718 : : // loop over entries in the elem on vert vector
719 [ # # ]: 0 : while( k2 < length_elem_on_vert[k1] )
720 : : {
721 : : // if it matches this_ent
722 [ # # ][ # # ]: 0 : if( elem_on_vert[k1][k2] == this_ent )
723 : : {
724 : : // mark it as 'seen', by making it the same as ent_ind
725 : : // i.e., the entity passed to us.
726 [ # # ]: 0 : elem_on_vert[k1][k2] = ent_ind;
727 : 0 : ++counter;
728 : : // do not look at remaining elems in this vector
729 : 0 : k2 += length_elem_on_vert[k1];
730 : : }
731 : : else
732 : 0 : ++k2;
733 : : }
734 : 0 : ++k1;
735 : 0 : k2 = 0;
736 : : }
737 : : // if this_ent occured enough times and isn't ent_ind
738 [ # # ][ # # ]: 0 : if( counter > n && this_ent != ent_ind ) { adj_ents.push_back( this_ent ); }
[ # # ]
739 : : }
740 : 0 : ++j;
741 : : }
742 : 0 : ++i;
743 : 0 : }
744 : : }
745 : :
746 : : /*! \fn PatchData::update_mesh(MsqError &err)
747 : :
748 : : \brief This function copies to the TSTT mesh the changes made to the
749 : : free vertices / elements of the PatchData object.
750 : :
751 : : */
752 : 829946 : void PatchData::update_mesh( MsqError& err, const TagHandle* tag )
753 : : {
754 [ - + ]: 829946 : if( !myMesh )
755 : : {
756 [ # # ]: 0 : MSQ_SETERR( err )( "Cannot update mesh on temporary patch.\n", MsqError::INTERNAL_ERROR );
757 : 0 : return;
758 : : }
759 : :
760 : 829946 : const size_t not_fixed = numFreeVertices + numSlaveVertices;
761 [ + + ]: 829946 : if( tag )
762 : : {
763 [ + + ]: 8 : for( size_t i = 0; i < not_fixed; ++i )
764 : : {
765 [ - + ][ # # ]: 4 : myMesh->tag_set_vertex_data( *tag, 1, &vertexHandlesArray[i], vertexArray[i].to_array(), err );MSQ_ERRRTN( err );
[ - + ]
766 : : }
767 : : }
768 : : else
769 : : {
770 [ + + ]: 1691143 : for( size_t i = 0; i < not_fixed; ++i )
771 : : {
772 [ - + ][ # # ]: 861201 : myMesh->vertex_set_coordinates( vertexHandlesArray[i], vertexArray[i], err );MSQ_ERRRTN( err );
[ - + ]
773 : : }
774 : : }
775 : :
776 [ + + ]: 8363532 : for( size_t i = 0; i < vertexArray.size(); ++i )
777 : : {
778 [ - + ][ # # ]: 7533586 : myMesh->vertex_set_byte( vertexHandlesArray[i], vertexArray[i].get_flags(), err );MSQ_ERRRTN( err );
[ - + ]
779 : : }
780 : : }
781 : :
782 : 182 : void PatchData::update_slave_node_coordinates( MsqError& err )
783 : : {
784 : : // update slave vertices
785 [ + - ][ - + ]: 364 : if( 0 == num_slave_vertices() ) return;
786 : :
787 : : // Set a mark on every slave vertex. We'll clear the marks as we
788 : : // set the vertex coordinates. This way we can check that all
789 : : // vertices got updated.
790 [ + - ][ + - ]: 182 : const size_t vert_end = num_free_vertices() + num_slave_vertices();
791 [ + - ][ + + ]: 4837 : for( size_t i = num_free_vertices(); i < vert_end; ++i )
792 [ + - ][ + - ]: 4655 : vertexArray[i].flags() |= MsqVertex::MSQ_MARK;
793 : :
794 : : // For each element, calculate slave vertex coordinates from
795 : : // mapping function.
796 : 182 : const int ARR_SIZE = 27;
797 : : double coeff[ARR_SIZE];
798 : : size_t index[ARR_SIZE];
799 [ + - ][ + + ]: 6863 : for( size_t i = 0; i < num_elements(); ++i )
800 : : {
801 [ + - ]: 6681 : MsqMeshEntity& elem = element_by_index( i );
802 [ + - ]: 6681 : const int num_corner = elem.vertex_count();
803 [ + - ]: 6681 : const int num_node = elem.node_count();
804 [ - + ]: 6681 : assert( num_node < ARR_SIZE );
805 : :
806 [ + - ]: 6681 : const EntityTopology type = elem.get_element_type();
807 [ + - ]: 6681 : const MappingFunction* const mf = get_mapping_function( type );
808 [ + - ][ - + ]: 6681 : if( 0 == mf || num_node == num_corner ) continue;
809 : :
810 [ + - ]: 6681 : const size_t* conn = elem.get_vertex_index_array();
811 : :
812 : : // for each higher-order non-slave node, set bit indicating
813 : : // that mapping function is a function of the non-slave node
814 : : // coordinates
815 [ + - ]: 6681 : NodeSet ho_bits = non_slave_node_set( i );
816 : :
817 : : // for each higher-order slave node
818 [ + + ]: 27255 : for( int k = num_corner; k < num_node; ++k )
819 : : {
820 [ + - ][ + + ]: 25229 : if( !is_vertex_slave( conn[k] ) ) continue;
821 : :
822 : : // check if we already did this one for an adjacent element
823 [ + - ]: 9310 : MsqVertex& vert = vertexArray[conn[k]];
824 [ + - ][ + + ]: 9310 : if( !vert.is_flag_set( MsqVertex::MSQ_MARK ) ) continue;
825 : :
826 : : // what is this node a mid node of (i.e. face 1, edge 2, etc.)
827 [ + - ][ + - ]: 4655 : Sample loc = TopologyInfo::sample_from_node( type, elem.node_count(), k, err );MSQ_ERRRTN( err );
[ + - ][ - + ]
[ # # ][ # # ]
[ - + ]
828 : :
829 : : // evaluate mapping function at logical loction of HO node.
830 : : size_t num_coeff;
831 [ + - ][ + - ]: 4655 : mf->coefficients( loc, ho_bits, coeff, index, num_coeff, err );MSQ_ERRRTN( err );
[ - + ][ # # ]
[ # # ][ - + ]
832 [ + - ][ + - ]: 4655 : mf->convert_connectivity_indices( num_node, index, num_coeff, err );MSQ_ERRRTN( err );
[ - + ][ # # ]
[ # # ][ - + ]
833 : :
834 : : // calulate new coordinates for slave node
835 [ - + ]: 4655 : assert( num_coeff > 0 );
836 [ + - ][ + - ]: 4655 : vert = coeff[0] * vertex_by_index( conn[index[0]] );
[ + - ]
837 [ + + ]: 9310 : for( size_t j = 1; j < num_coeff; ++j )
838 [ + - ][ + - ]: 4655 : vert += coeff[j] * vertex_by_index( conn[index[j]] );
[ + - ]
839 : :
840 : : // clear mark
841 [ + - ]: 4655 : vert.flags() &= ~MsqVertex::MSQ_MARK;
842 : : }
843 : : }
844 : :
845 : : // make sure we set the coordinates for every slave node
846 [ + - ][ + + ]: 4837 : for( size_t i = num_free_vertices(); i < vert_end; ++i )
847 : : {
848 [ + - ][ + - ]: 4655 : if( vertex_by_index( i ).is_flag_set( MsqVertex::MSQ_MARK ) )
[ - + ]
849 : : {
850 : : MSQ_SETERR( err )
851 : : ( MsqError::INVALID_MESH, "No element with mapping function adjacent to slave vertex %lu (%lu)\n",
852 [ # # ][ # # ]: 0 : (unsigned long)i, (unsigned long)get_vertex_handles_array()[i] );
[ # # ]
853 : : // make sure we finish with all marks cleared
854 [ # # ][ # # ]: 0 : vertexArray[i].flags() &= ~MsqVertex::MSQ_MARK;
855 : : }
856 : : }
857 : :
858 : : // snap vertices to domain
859 [ + - ][ + - ]: 182 : if( domain_set() )
860 : : {
861 [ + - ][ + + ]: 4837 : for( size_t i = num_free_vertices(); i < vert_end; ++i )
862 : : {
863 [ + - ][ + - ]: 4655 : snap_vertex_to_domain( i, err );MSQ_ERRRTN( err );
[ - + ][ # # ]
[ # # ][ - + ]
864 : : }
865 : : }
866 : : }
867 : :
868 : 0 : void PatchData::update_slave_node_coordinates( const size_t* elements, size_t num_elems, MsqError& err )
869 : : {
870 : : // update slave vertices
871 [ # # ][ # # ]: 0 : if( 0 == num_slave_vertices() ) return;
872 : :
873 : : // set a mark on each vertex so we don't update shared
874 : : // vertices more than once.
875 [ # # ]: 0 : for( size_t i = 0; i < num_elems; ++i )
876 : : {
877 [ # # ]: 0 : MsqMeshEntity& elem = element_by_index( elements[i] );
878 [ # # ]: 0 : const int num_corner = elem.vertex_count();
879 [ # # ]: 0 : const int num_node = elem.node_count();
880 [ # # ]: 0 : const size_t* conn = elem.get_vertex_index_array();
881 [ # # ]: 0 : for( int j = num_corner; j < num_node; ++j )
882 [ # # ][ # # ]: 0 : vertexArray[conn[j]].flags() |= MsqVertex::MSQ_MARK;
883 : : }
884 : :
885 : : // For each element, calculate slave vertex coordinates from
886 : : // mapping function.
887 : 0 : const int ARR_SIZE = 27;
888 : : double coeff[ARR_SIZE];
889 : : size_t index[ARR_SIZE];
890 [ # # ]: 0 : for( size_t i = 0; i < num_elems; ++i )
891 : : {
892 [ # # ]: 0 : MsqMeshEntity& elem = element_by_index( elements[i] );
893 [ # # ]: 0 : const int num_corner = elem.vertex_count();
894 [ # # ]: 0 : const int num_node = elem.node_count();
895 [ # # ]: 0 : assert( num_node < ARR_SIZE );
896 : :
897 [ # # ]: 0 : const EntityTopology type = elem.get_element_type();
898 [ # # ]: 0 : const MappingFunction* const mf = get_mapping_function( type );
899 [ # # ][ # # ]: 0 : if( 0 == mf || num_node == num_corner ) continue;
900 : :
901 [ # # ]: 0 : const size_t* conn = elem.get_vertex_index_array();
902 : :
903 : : // for each higher-order non-slave node, set bit indicating
904 : : // that mapping function is a function of the non-slave node
905 : : // coordinates
906 [ # # ]: 0 : NodeSet ho_bits = non_slave_node_set( i );
907 : :
908 : : // for each higher-order slave node
909 [ # # ]: 0 : for( int k = num_corner; k < num_node; ++k )
910 : : {
911 [ # # ][ # # ]: 0 : if( !is_vertex_slave( conn[k] ) ) continue;
912 : :
913 : : // check if we already did this one for an adjacent element
914 [ # # ]: 0 : MsqVertex& vert = vertexArray[conn[k]];
915 [ # # ][ # # ]: 0 : if( !vert.is_flag_set( MsqVertex::MSQ_MARK ) ) continue;
916 : :
917 : : // what is this node a mid node of (i.e. face 1, edge 2, etc.)
918 [ # # ][ # # ]: 0 : Sample loc = TopologyInfo::sample_from_node( type, elem.node_count(), k, err );MSQ_ERRRTN( err );
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
919 : :
920 : : // evaluate mapping function at logical loction of HO node.
921 : : size_t num_coeff;
922 [ # # ][ # # ]: 0 : mf->coefficients( loc, ho_bits, coeff, index, num_coeff, err );MSQ_ERRRTN( err );
[ # # ][ # # ]
[ # # ][ # # ]
923 [ # # ][ # # ]: 0 : mf->convert_connectivity_indices( num_node, index, num_coeff, err );MSQ_ERRRTN( err );
[ # # ][ # # ]
[ # # ][ # # ]
924 : :
925 : : // calulate new coordinates for slave node
926 [ # # ]: 0 : assert( num_coeff > 0 );
927 [ # # ][ # # ]: 0 : vert = coeff[0] * vertex_by_index( conn[index[0]] );
[ # # ]
928 [ # # ]: 0 : for( size_t j = 1; j < num_coeff; ++j )
929 [ # # ][ # # ]: 0 : vert += coeff[j] * vertex_by_index( conn[index[j]] );
[ # # ]
930 : :
931 : : // snap vertices to domain
932 [ # # ][ # # ]: 0 : if( domain_set() )
933 : : {
934 [ # # ][ # # ]: 0 : snap_vertex_to_domain( conn[k], err );MSQ_ERRRTN( err );
[ # # ][ # # ]
[ # # ][ # # ]
935 : : }
936 : :
937 : : // clear mark
938 [ # # ]: 0 : vert.flags() &= ~MsqVertex::MSQ_MARK;
939 : : }
940 : : }
941 : : }
942 : :
943 : 36783 : void PatchData::generate_vertex_to_element_data()
944 : : {
945 : : MSQ_FUNCTION_TIMER( "PatchData::generate_vertex_to_element_data" );
946 : :
947 : : // Skip if data already exists
948 [ - + ]: 73566 : if( !vertAdjacencyArray.empty() ) return;
949 : :
950 : : // Skip if patch is empty
951 [ + - ][ - + ]: 36783 : if( 0 == num_nodes() ) return;
952 : :
953 : : // Allocate offset array
954 : 36783 : vertAdjacencyOffsets.clear();
955 [ + - ][ + - ]: 36783 : vertAdjacencyOffsets.resize( num_nodes() + 1, 0 );
956 : :
957 : : // Temporarily use offsets array to hold per-vertex element count
958 : 36783 : std::vector< MsqMeshEntity >::iterator elem_iter;
959 : 36783 : const std::vector< MsqMeshEntity >::iterator elem_end = elementArray.end();
960 [ + - ][ + - ]: 270463 : for( elem_iter = elementArray.begin(); elem_iter != elem_end; ++elem_iter )
[ + + ]
961 : : {
962 [ + - ][ + - ]: 233680 : size_t* conn_iter = elem_iter->get_vertex_index_array();
963 [ + - ][ + - ]: 233680 : const size_t* conn_end = conn_iter + elem_iter->node_count();
964 [ + + ]: 1190628 : for( ; conn_iter != conn_end; ++conn_iter )
965 [ + - ]: 956948 : ++vertAdjacencyOffsets[*conn_iter];
966 : : }
967 : :
968 : : // Convert counts to end indices.
969 : : // When done, vertAdjacencyOffsets will contain, for each vertex,
970 : : // one more than the *last* index for that vertex's data in the
971 : : // adjacency array. This is *not* the final state for this data.
972 : : // See comments for next loop.
973 : 36783 : std::vector< size_t >::iterator off_iter = vertAdjacencyOffsets.begin();
974 : 36783 : const std::vector< size_t >::iterator off_end = vertAdjacencyOffsets.end();
975 [ + - ]: 36783 : size_t prev = *off_iter;
976 [ + - ]: 36783 : ++off_iter;
977 [ + - ][ + - ]: 414178 : for( ; off_iter != off_end; ++off_iter )
[ + + ]
978 : : {
979 [ + - ]: 377395 : prev += *off_iter;
980 [ + - ]: 377395 : *off_iter = prev;
981 : : }
982 : :
983 : : // Allocate space for element numbers
984 [ + - ][ + - ]: 36783 : const size_t num_vert_uses = vertAdjacencyOffsets[num_nodes() - 1];
985 [ - + ]: 36783 : assert( num_vert_uses == elemConnectivityArray.size() );
986 [ + - ]: 36783 : vertAdjacencyArray.resize( num_vert_uses );
987 : :
988 : : // Fill vertAdjacencyArray, using the indices in vertAdjacencyOffsets
989 : : // as the location to insert the next element number in
990 : : // vertAdjacencyArray. When done, vertAdjacenyOffsets will contain
991 : : // the start index for each vertex, rather than one past the last
992 : : // index.
993 [ + + ]: 270463 : for( size_t i = 0; i < elementArray.size(); ++i )
994 : : {
995 [ + - ][ + - ]: 233680 : size_t* conn_iter = elementArray[i].get_vertex_index_array();
996 [ + - ][ + - ]: 233680 : const size_t* conn_end = conn_iter + elementArray[i].node_count();
997 [ + + ]: 1190628 : for( ; conn_iter != conn_end; ++conn_iter )
998 : : {
999 [ + - ]: 956948 : const size_t array_index = --vertAdjacencyOffsets[*conn_iter];
1000 [ + - ]: 956948 : vertAdjacencyArray[array_index] = i;
1001 : : }
1002 : : }
1003 : :
1004 : : // Last entry should be number of vertex uses (one past the
1005 : : // last index of the last vertex.)
1006 [ + - ][ + - ]: 36783 : vertAdjacencyOffsets[num_nodes()] = num_vert_uses;
1007 : : }
1008 : :
1009 : 0 : void PatchData::get_subpatch( size_t center_vertex_index, unsigned num_adj_elem_layers, PatchData& subpatch,
1010 : : MsqError& err )
1011 : : {
1012 : : // Make sure we're in range
1013 [ # # ][ # # ]: 0 : if( center_vertex_index >= num_free_vertices() )
1014 : : {
1015 [ # # ][ # # ]: 0 : MSQ_SETERR( err )( "Invalid index for center vertex", MsqError::INVALID_ARG );
1016 : 0 : return;
1017 : : }
1018 : :
1019 : : // Notify any observers of the existing subpatch that the mesh
1020 : : // in the patch is to be changed.
1021 [ # # ]: 0 : subpatch.notify_new_patch();
1022 : :
1023 : : // Get list of vertices and elements in subpatch.
1024 : : // Ultimately, end up with arrays of unique, sorted indices.
1025 : : // It is important that the vertex indices be sorted so later
1026 : : // a reverse lookup can be done using a binary search (std::lower_bound).
1027 [ # # ][ # # ]: 0 : std::vector< size_t > elements, vertices, offsets;
[ # # ][ # # ]
[ # # ]
1028 [ # # ]: 0 : vertices.push_back( center_vertex_index );
1029 [ # # ]: 0 : for( unsigned i = 0; i < num_adj_elem_layers; ++i )
1030 : : {
1031 : 0 : elements.clear();
1032 [ # # ]: 0 : for( unsigned v = 0; v < vertices.size(); ++v )
1033 : : {
1034 : : size_t num_elem;
1035 [ # # ][ # # ]: 0 : const size_t* vert_elems = get_vertex_element_adjacencies( vertices[v], num_elem, err );MSQ_ERRRTN( err );
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
1036 [ # # ]: 0 : elements.insert( elements.end(), vert_elems, vert_elems + num_elem );
1037 : : }
1038 [ # # ]: 0 : std::sort( elements.begin(), elements.end() );
1039 [ # # ][ # # ]: 0 : elements.erase( std::unique( elements.begin(), elements.end() ), elements.end() );
1040 : :
1041 : 0 : vertices.clear();
1042 [ # # ]: 0 : for( unsigned e = 0; e < elements.size(); ++e )
1043 : : {
1044 [ # # ][ # # ]: 0 : MsqMeshEntity& elem = element_by_index( elements[e] );
1045 [ # # ]: 0 : size_t num_vert = elem.node_count();
1046 [ # # ]: 0 : const size_t* elem_verts = elem.get_vertex_index_array();
1047 [ # # ]: 0 : vertices.insert( vertices.end(), elem_verts, elem_verts + num_vert );
1048 : : }
1049 [ # # ]: 0 : std::sort( vertices.begin(), vertices.end() );
1050 [ # # ][ # # ]: 0 : vertices.erase( std::unique( vertices.begin(), vertices.end() ), vertices.end() );
1051 : : }
1052 : :
1053 : : // Allocate space for element connectivity info.
1054 : 0 : size_t num_vert_uses = 0;
1055 [ # # ]: 0 : for( unsigned i = 0; i < elements.size(); ++i )
1056 [ # # ][ # # ]: 0 : num_vert_uses += element_by_index( elements[i] ).node_count();
[ # # ]
1057 [ # # ]: 0 : subpatch.elementArray.resize( elements.size() );
1058 [ # # ]: 0 : subpatch.elementHandlesArray.resize( elements.size() );
1059 [ # # ]: 0 : subpatch.elemConnectivityArray.resize( num_vert_uses );
1060 [ # # ]: 0 : offsets.resize( elements.size() + 1 );
1061 : :
1062 : : // Construct element connectivity data in new patch,
1063 : : // and copy element type into new patch
1064 : 0 : size_t curr_offset = 0;
1065 [ # # ]: 0 : for( unsigned i = 0; i < elements.size(); ++i )
1066 : : {
1067 [ # # ][ # # ]: 0 : MsqMeshEntity& elem = element_by_index( elements[i] );
1068 [ # # ]: 0 : assert( i < elementArray.size() );
1069 [ # # ][ # # ]: 0 : subpatch.elementArray[i].set_element_type( elem.get_element_type() );
[ # # ]
1070 [ # # ][ # # ]: 0 : subpatch.elementHandlesArray[i] = elementHandlesArray[elements[i]];
[ # # ]
1071 [ # # ]: 0 : const size_t* verts = elem.get_vertex_index_array();
1072 [ # # ]: 0 : offsets[i] = curr_offset;
1073 [ # # ][ # # ]: 0 : for( unsigned j = 0; j < elem.node_count(); ++j )
1074 : : {
1075 [ # # ]: 0 : subpatch.elemConnectivityArray[curr_offset++] =
1076 [ # # ][ # # ]: 0 : std::lower_bound( vertices.begin(), vertices.end(), verts[j] ) - vertices.begin();
1077 : : }
1078 : : }
1079 [ # # ]: 0 : offsets[elements.size()] = curr_offset;
1080 : :
1081 : : // Store index in this patch in vertex handle array of subpatch
1082 : : // so we can determine how vertices were reordered when setting
1083 : : // vertex coordinates.
1084 : : assert( sizeof( size_t ) == sizeof( void* ) );
1085 [ # # ]: 0 : subpatch.vertexHandlesArray.resize( vertices.size() );
1086 [ # # ]: 0 : size_t* vert_handles = reinterpret_cast< size_t* >( &subpatch.vertexHandlesArray[0] );
1087 [ # # ]: 0 : std::copy( vertices.begin(), vertices.end(), vert_handles );
1088 : :
1089 : : // All vertices except vertex at center_vertex_index are fixed.
1090 [ # # ]: 0 : subpatch.byteArray.resize( vertices.size() );
1091 [ # # ]: 0 : for( size_t pi = 0; pi < vertices.size(); ++pi )
1092 : : {
1093 [ # # ][ # # ]: 0 : if( vertices[pi] == center_vertex_index )
1094 [ # # ][ # # ]: 0 : subpatch.byteArray[pi] = vertexArray[vertices[pi]].get_flags() & ~MsqVertex::MSQ_PATCH_FIXED;
[ # # ][ # # ]
1095 : : else
1096 [ # # ][ # # ]: 0 : subpatch.byteArray[pi] = vertexArray[vertices[pi]].get_flags() | MsqVertex::MSQ_PATCH_FIXED;
[ # # ][ # # ]
1097 : : }
1098 : :
1099 : : // Re-order vertices and initialize other data in subpatch
1100 [ # # ][ # # ]: 0 : subpatch.initialize_data( arrptr( offsets ), &subpatch.byteArray[0], err );MSQ_ERRRTN( err );
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
1101 : :
1102 : : // Copy vertex data into subpatch. subpatch.vertexHandlesArray contains
1103 : : // the indices into this PatchData for each vertex, as reordered by the
1104 : : // call to initialize_data.
1105 [ # # ]: 0 : subpatch.vertexArray.resize( vertices.size() );
1106 [ # # ]: 0 : for( unsigned i = 0; i < vertices.size(); ++i )
1107 : : {
1108 [ # # ]: 0 : size_t vert_index = ( size_t )( subpatch.vertexHandlesArray[i] );
1109 [ # # ]: 0 : vertices[i] = vert_index;
1110 [ # # ][ # # ]: 0 : subpatch.vertexHandlesArray[i] = vertexHandlesArray[vert_index];
1111 [ # # ][ # # ]: 0 : subpatch.vertexArray[i] = vertexArray[vert_index];
[ # # ]
1112 [ # # ][ # # ]: 0 : subpatch.vertexArray[i].flags() = subpatch.byteArray[i];
[ # # ]
1113 : : }
1114 : :
1115 : 0 : subpatch.myMesh = myMesh;
1116 : 0 : subpatch.myDomain = myDomain;
1117 : 0 : subpatch.mSettings = mSettings;
1118 : :
1119 [ # # ][ # # ]: 0 : notify_sub_patch( subpatch, arrptr( vertices ), elements.empty() ? 0 : arrptr( elements ), err );MSQ_CHKERR( err );
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
1120 : : }
1121 : :
1122 : : //! Adjust the position of the specified vertex so that it
1123 : : //! lies on its constraining domain. The actual domain constraint
1124 : : //! is managed by the TSTT mesh implementation
1125 : 2734298 : void PatchData::snap_vertex_to_domain( size_t vertex_index, MsqError& err )
1126 : : {
1127 [ + + ]: 2734298 : if( domain_set() )
1128 : : {
1129 : : // if not doing normal caching or vertex is not on a single surface
1130 [ + + ]: 1908516 : if( normalData.empty() )
1131 : 1420726 : { get_domain()->snap_to( vertexHandlesArray[vertex_index], vertexArray[vertex_index] ); }
1132 : : // entire domain is 2-D (all vertices have a single normal)
1133 [ + + ]: 487790 : else if( vertexNormalIndices.empty() )
1134 : : {
1135 [ + - ]: 1462746 : get_domain()->closest_point( vertexHandlesArray[vertex_index], Vector3D( vertexArray[vertex_index] ),
1136 [ + - ][ - + ]: 1462746 : vertexArray[vertex_index], normalData[vertex_index], err );MSQ_ERRRTN( err );
[ # # ][ - + ]
1137 : : }
1138 [ + + ]: 208 : else if( vertexNormalIndices[vertex_index] < normalData.size() )
1139 : : { // vertex has a unique normal
1140 [ + - ]: 129 : get_domain()->closest_point( vertexHandlesArray[vertex_index], Vector3D( vertexArray[vertex_index] ),
1141 : 43 : vertexArray[vertex_index], normalData[vertexNormalIndices[vertex_index]],
1142 [ + - ][ - + ]: 86 : err );MSQ_ERRRTN( err );
[ # # ][ - + ]
1143 : : }
1144 : : else
1145 : : { // vertex has multiple normals
1146 : 2734298 : get_domain()->snap_to( vertexHandlesArray[vertex_index], vertexArray[vertex_index] );
1147 : : }
1148 : : }
1149 : : }
1150 : :
1151 : 118608 : void PatchData::update_cached_normals( MsqError& err )
1152 : : {
1153 : : size_t i;
1154 : :
1155 [ + - ]: 118608 : MeshDomain* domain = get_domain();
1156 [ - + ]: 118608 : if( !domain )
1157 : : {
1158 [ # # ][ # # ]: 0 : MSQ_SETERR( err )( "No domain constraint set.", MsqError::INVALID_STATE );
1159 : 118608 : return;
1160 : : }
1161 : :
1162 : : // Determine which vertices lie on surfaces
1163 [ + - ][ + - ]: 118608 : vertexDomainDOF.resize( num_nodes() );
1164 [ + - ][ + - ]: 118608 : domain->domain_DoF( arrptr( vertexHandlesArray ), arrptr( vertexDomainDOF ), num_nodes(), err );MSQ_ERRRTN( err );
[ + - ][ + - ]
[ + - ][ - + ]
[ # # ][ # # ]
[ - + ]
1165 : :
1166 : : // Count how many vertices have a single normal
1167 : : // Sun doesn't support partial template specialization, so can't use std::count
1168 : : // size_t n = std::count( vertexDomainDOF.begin(), vertexDomainDOF.end(), 2 );
1169 : 118608 : size_t n = 0;
1170 : 118608 : std::vector< unsigned short >::iterator k;
1171 [ + - ][ + - ]: 918543 : for( k = vertexDomainDOF.begin(); k != vertexDomainDOF.end(); ++k )
[ + + ]
1172 [ + - ][ + + ]: 799935 : if( *k == 2 ) ++n;
1173 : :
1174 [ + - ]: 118608 : normalData.resize( n );
1175 : :
1176 : : // If all vertices are on a surface, pass in the existing handles array
1177 : : // and store a single normal per vertex.
1178 [ + - ][ + + ]: 118608 : if( n == num_nodes() )
1179 : : {
1180 [ + - ]: 118537 : std::copy( vertexArray.begin(), vertexArray.end(), normalData.begin() );
1181 [ + - ][ + - ]: 118537 : domain->vertex_normal_at( arrptr( vertexHandlesArray ), arrptr( normalData ), num_nodes(), err );
[ + - ][ + - ]
1182 : 118537 : vertexNormalIndices.clear();
1183 [ + - ][ - + ]: 118537 : vertexDomainDOF.clear();MSQ_ERRRTN( err );
[ # # ][ # # ]
[ - + ]
1184 : : }
1185 : : else
1186 : : {
1187 [ + - ][ + - ]: 71 : vertexNormalIndices.resize( num_nodes() );
1188 : 71 : size_t nn = 0;
1189 [ + - ][ + + ]: 498 : for( i = 0; i < num_nodes(); ++i )
1190 : : {
1191 [ + - ][ + + ]: 427 : if( vertexDomainDOF[i] == 2 )
1192 : : {
1193 [ + - ][ + - ]: 71 : normalData[nn] = vertexArray[i];
[ + - ]
1194 [ + - ][ + - ]: 71 : domain->vertex_normal_at( vertexHandlesArray[i], normalData[nn] );
[ + - ]
1195 [ + - ]: 71 : vertexNormalIndices[i] = nn;
1196 : 71 : ++nn;
1197 : : }
1198 : : else
1199 : : {
1200 [ + - ]: 356 : vertexNormalIndices[i] = n + 1;
1201 : : }
1202 : : }
1203 [ - + ]: 118608 : assert( nn == n );
1204 : : }
1205 : : }
1206 : :
1207 : 335285 : void PatchData::get_domain_normal_at_element( size_t elem_index, Vector3D& surf_norm, MsqError& err )
1208 : : {
1209 : : // check if element as a mid-face node
1210 : 335285 : const MsqMeshEntity& elem = element_by_index( elem_index );
1211 [ - + ][ # # ]: 335285 : const int mid_node = TopologyInfo::higher_order_from_side( elem.get_element_type(), elem.node_count(), 2, 0, err );MSQ_ERRRTN( err );
[ - + ]
1212 : : // if we have the mid-element vertex, get cached normal for it
1213 [ - + ]: 335285 : if( mid_node > 0 )
1214 : : {
1215 : 0 : get_domain_normal_at_vertex( elem.get_vertex_index_array()[mid_node], elementHandlesArray[elem_index],
1216 [ # # ][ # # ]: 0 : surf_norm, err );MSQ_ERRRTN( err );
[ # # ]
1217 : : }
1218 : : // otherwise query domain for normal at element centroid
1219 [ + - ]: 335285 : else if( domain_set() )
1220 : : {
1221 [ - + ]: 335285 : assert( elem_index < elementArray.size() );
1222 [ - + ][ # # ]: 335285 : elementArray[elem_index].get_centroid( surf_norm, *this, err );MSQ_ERRRTN( err );
[ - + ]
1223 : 335285 : get_domain()->element_normal_at( elementHandlesArray[elem_index], surf_norm );
1224 : : }
1225 : : else
1226 [ # # ]: 335285 : MSQ_SETERR( err )( "No domain constraint set.", MsqError::INVALID_STATE );
1227 : : }
1228 : :
1229 : 33686 : void PatchData::get_domain_normal_at_mid_edge( size_t elem_index, unsigned edge_num, Vector3D& normal, MsqError& err )
1230 : : {
1231 : : // check if element as a mid-edge node
1232 : 33686 : const MsqMeshEntity& elem = element_by_index( elem_index );
1233 : : const int mid_node =
1234 [ - + ][ # # ]: 33686 : TopologyInfo::higher_order_from_side( elem.get_element_type(), elem.node_count(), 1, edge_num, err );MSQ_ERRRTN( err );
[ - + ]
1235 : : // if we have the mid-edge vertex, get cached normal for it
1236 [ + - ]: 33686 : if( mid_node > 0 )
1237 : : {
1238 : 33686 : get_domain_normal_at_vertex( elem.get_vertex_index_array()[mid_node], elementHandlesArray[elem_index], normal,
1239 [ - + ][ # # ]: 33686 : err );MSQ_ERRRTN( err );
[ - + ]
1240 : : }
1241 : : // otherwise query domain for normal at center of edge
1242 [ # # ]: 0 : else if( domain_set() )
1243 : : {
1244 [ # # ][ # # ]: 0 : const unsigned* edge = TopologyInfo::edge_vertices( elem.get_element_type(), edge_num, err );MSQ_ERRRTN( err );
[ # # ]
1245 : 0 : const MsqVertex& v1 = vertex_by_index( elem.get_vertex_index_array()[edge[0]] );
1246 : 0 : const MsqVertex& v2 = vertex_by_index( elem.get_vertex_index_array()[edge[1]] );
1247 [ # # ][ # # ]: 0 : normal = 0.5 * ( v1 + v2 );
1248 : 0 : get_domain()->element_normal_at( elementHandlesArray[elem_index], normal );
1249 : : }
1250 : : else
1251 : : {
1252 [ # # ]: 0 : MSQ_SETERR( err )( "No domain constraint set.", MsqError::INVALID_STATE );
1253 : 33686 : return;
1254 : : }
1255 : : }
1256 : :
1257 : 0 : void PatchData::get_domain_normals_at_corners( size_t elem_index, Vector3D normals_out[], MsqError& err )
1258 : : {
1259 [ # # ]: 0 : if( !domain_set() )
1260 : : {
1261 [ # # ]: 0 : MSQ_SETERR( err )( "No domain constraint set.", MsqError::INVALID_STATE );
1262 : 0 : return;
1263 : : }
1264 : :
1265 [ # # ]: 0 : assert( elem_index < elementArray.size() );
1266 [ # # ]: 0 : if( 2 != TopologyInfo::dimension( elementArray[elem_index].get_element_type() ) )
1267 : : {
1268 [ # # ]: 0 : MSQ_SETERR( err )( "Attempt to get corners of non-surface element", MsqError::INVALID_ARG );
1269 : 0 : return;
1270 : : }
1271 : :
1272 [ # # ]: 0 : if( normalData.empty() )
1273 : : {
1274 [ # # ][ # # ]: 0 : update_cached_normals( err );MSQ_ERRRTN( err );
[ # # ]
1275 : : }
1276 : :
1277 : 0 : MsqMeshEntity& elem = elementArray[elem_index];
1278 : 0 : const unsigned count = elem.vertex_count();
1279 : 0 : const size_t* const vertex_indices = elem.get_vertex_index_array();
1280 [ # # ]: 0 : for( size_t i = 0; i < count; ++i )
1281 : : {
1282 : 0 : const size_t v = vertex_indices[i];
1283 [ # # ]: 0 : if( vertexNormalIndices.empty() ) { normals_out[i] = normalData[v]; }
1284 [ # # ]: 0 : else if( vertexNormalIndices[v] < normalData.size() )
1285 : : {
1286 : 0 : normals_out[i] = normalData[vertexNormalIndices[v]];
1287 : : }
1288 : : else
1289 : : {
1290 : 0 : normals_out[i] = vertexArray[v];
1291 : 0 : get_domain()->element_normal_at( elementHandlesArray[elem_index], normals_out[i] );
1292 : : }
1293 : : }
1294 : : }
1295 : :
1296 : 12713940 : void PatchData::get_domain_normal_at_vertex( size_t vert_index, Mesh::EntityHandle handle, Vector3D& normal,
1297 : : MsqError& err )
1298 : : {
1299 [ - + ]: 12713940 : if( !domain_set() )
1300 : : {
1301 [ # # ]: 0 : MSQ_SETERR( err )( "No domain constraint set.", MsqError::INVALID_STATE );
1302 : 0 : return;
1303 : : }
1304 : :
1305 [ + + ]: 12713940 : if( normalData.empty() )
1306 : : {
1307 [ - + ][ # # ]: 118608 : update_cached_normals( err );MSQ_ERRRTN( err );
[ - + ]
1308 : : }
1309 : :
1310 [ + + ]: 12713940 : if( vertexNormalIndices.empty() ) { normal = normalData[vert_index]; }
1311 [ + + ]: 2621 : else if( vertexNormalIndices[vert_index] < normalData.size() )
1312 : : {
1313 : 657 : normal = normalData[vertexNormalIndices[vert_index]];
1314 : : }
1315 : : else
1316 : : {
1317 : 1964 : normal = vertexArray[vert_index];
1318 : 12713940 : get_domain()->element_normal_at( handle, normal );
1319 : : }
1320 : : }
1321 : :
1322 : 12680254 : void PatchData::get_domain_normal_at_corner( size_t elem_index, unsigned corner, Vector3D& normal, MsqError& err )
1323 : : {
1324 [ - + ]: 12680254 : assert( elem_index < elementArray.size() );
1325 [ - + ]: 12680254 : if( 2 != TopologyInfo::dimension( elementArray[elem_index].get_element_type() ) )
1326 : : {
1327 [ # # ]: 0 : MSQ_SETERR( err )( "Attempt to get corners of non-surface element", MsqError::INVALID_ARG );
1328 : 12680254 : return;
1329 : : }
1330 : :
1331 : 12680254 : MsqMeshEntity& elem = elementArray[elem_index];
1332 : 12680254 : const size_t* const vertex_indices = elem.get_vertex_index_array();
1333 [ - + ][ # # ]: 12680254 : get_domain_normal_at_vertex( vertex_indices[corner], elementHandlesArray[elem_index], normal, err );MSQ_CHKERR( err );
1334 : : }
1335 : :
1336 : 328 : void PatchData::set_mesh( Mesh* ms )
1337 : : {
1338 : 328 : myMesh = ms;
1339 : : // observers should treat this the same as if the
1340 : : // instance of this object wzs being deleted.
1341 : 328 : notify_patch_destroyed();
1342 : 328 : }
1343 : :
1344 : 280 : void PatchData::set_domain( MeshDomain* d )
1345 : : {
1346 : 280 : myDomain = d;
1347 : :
1348 : : // clear all cached data from the previous domain
1349 : 280 : vertexNormalIndices.clear();
1350 : 280 : normalData.clear();
1351 : : // vertexDomainDOF.clear();
1352 : :
1353 : : // observers should treat this the same as if the
1354 : : // instance of this object wzs being deleted.
1355 : 280 : notify_patch_destroyed();
1356 : 280 : }
1357 : :
1358 : 0 : static int width( double d )
1359 : : {
1360 [ # # ]: 0 : if( d == 0.0 ) return 1;
1361 : 0 : const int max_precision = 6;
1362 : 0 : int w = (int)ceil( log10( 0.001 + fabs( d ) ) );
1363 [ # # ][ # # ]: 0 : if( w < 0 ) w = 2 + std::min( max_precision, -w );
1364 [ # # ]: 0 : if( d < 0.0 ) ++w;
1365 : 0 : return w;
1366 : : }
1367 : 0 : static int width( size_t t )
1368 : : {
1369 [ # # ]: 0 : return t ? (int)ceil( log10( (double)( 1 + t ) ) ) : 1;
1370 : : }
1371 : 0 : static int width( const void* ptr )
1372 : : {
1373 : 0 : return width( (size_t)ptr );
1374 : : }
1375 : :
1376 : 0 : ostream& operator<<( ostream& stream, const PatchData& pd )
1377 : : {
1378 : : size_t i;
1379 : 0 : int fw = 5; // width of bit flags
1380 : 0 : int hw = 6; // width of a handle
1381 : 0 : int cw = 4; // with of a coordinate value
1382 : 0 : int iw = 3; // with of an index
1383 : 0 : int tw = 3; // with of the string name of an element type
1384 : 0 : int xw = cw, yw = cw, zw = cw;
1385 : :
1386 [ # # ]: 0 : for( i = 0; i < pd.num_nodes(); ++i )
1387 : : {
1388 : 0 : int w = 2 + width( pd.vertexHandlesArray[i] );
1389 [ # # ]: 0 : if( w > hw ) hw = w;
1390 : 0 : w = width( pd.vertexArray[i].x() );
1391 [ # # ]: 0 : if( w > xw ) xw = w;
1392 : 0 : w = width( pd.vertexArray[i].y() );
1393 [ # # ]: 0 : if( w > yw ) yw = w;
1394 : 0 : w = width( pd.vertexArray[i].z() );
1395 [ # # ]: 0 : if( w > zw ) zw = w;
1396 : : }
1397 [ # # ]: 0 : for( i = 0; i < pd.num_elements(); ++i )
1398 : : {
1399 : 0 : int w = 2 + width( pd.elementHandlesArray[i] );
1400 [ # # ]: 0 : if( w > hw ) hw = w;
1401 : 0 : const char* name = TopologyInfo::short_name( pd.elementArray[i].get_element_type() );
1402 [ # # ][ # # ]: 0 : if( name && (int)strlen( name ) > tw ) tw = strlen( name );
1403 : : }
1404 [ # # ]: 0 : if( iw < (int)ceil( log10( (double)( 1 + pd.num_nodes() ) ) ) )
1405 : 0 : iw = (int)ceil( log10( (double)( 1 + pd.num_nodes() ) ) );
1406 [ # # ]: 0 : if( iw < (int)ceil( log10( (double)( 1 + pd.num_elements() ) ) ) )
1407 : 0 : iw = (int)ceil( log10( (double)( 1 + pd.num_elements() ) ) );
1408 : :
1409 : 0 : stream << "Vertices: " << endl;
1410 : 0 : stream << "Flags: C: culled, F: fixed, S: slave, P: patch vertex, M: marked" << endl;
1411 : 0 : stream << setw( iw ) << "Idx"
1412 : 0 : << " " << setw( hw ) << "Handle"
1413 : 0 : << " " << setw( cw ) << "X"
1414 : 0 : << "," << setw( cw ) << "Y"
1415 : 0 : << "," << setw( cw ) << "Z"
1416 : 0 : << " " << setw( fw ) << "Flags"
1417 : 0 : << " "
1418 : 0 : << "Adj.Elems" << endl
1419 : 0 : << setw( iw ) << setfill( '-' ) << ""
1420 : 0 : << " " << setw( hw ) << setfill( '-' ) << ""
1421 : 0 : << " " << setw( cw ) << setfill( '-' ) << ""
1422 : 0 : << "," << setw( cw ) << setfill( '-' ) << ""
1423 : 0 : << "," << setw( cw ) << setfill( '-' ) << ""
1424 : 0 : << " " << setw( fw ) << setfill( '-' ) << ""
1425 : 0 : << " " << setfill( ' ' ) << "-------------" << std::endl;
1426 [ # # ]: 0 : for( i = 0; i < pd.num_nodes(); ++i )
1427 : : {
1428 : 0 : stream << setw( iw ) << i << " " << setw( hw ) << pd.vertexHandlesArray[i] << " " << setw( cw )
1429 : 0 : << pd.vertexArray[i].x() << "," << setw( cw ) << pd.vertexArray[i].y() << "," << setw( cw )
1430 : 0 : << pd.vertexArray[i].z() << " ";
1431 [ # # ]: 0 : if( pd.vertexArray[i].is_flag_set( MsqVertex::MSQ_CULLED ) )
1432 : 0 : stream << "C";
1433 : : else
1434 : 0 : stream << " ";
1435 [ # # ]: 0 : if( pd.vertexArray[i].is_flag_set( MsqVertex::MSQ_HARD_FIXED ) )
1436 : 0 : stream << "F";
1437 : : else
1438 : 0 : stream << " ";
1439 [ # # ]: 0 : if( pd.vertexArray[i].is_flag_set( MsqVertex::MSQ_DEPENDENT ) )
1440 : 0 : stream << "S";
1441 : : else
1442 : 0 : stream << " ";
1443 [ # # ]: 0 : if( pd.vertexArray[i].is_flag_set( MsqVertex::MSQ_PATCH_FIXED ) )
1444 : 0 : stream << "f";
1445 : : else
1446 : 0 : stream << " ";
1447 [ # # ]: 0 : if( pd.vertexArray[i].is_flag_set( MsqVertex::MSQ_MARK ) )
1448 : 0 : stream << "M";
1449 : : else
1450 : 0 : stream << " ";
1451 : :
1452 [ # # ]: 0 : if( pd.vertAdjacencyArray.size() )
1453 : : {
1454 : 0 : size_t j = pd.vertAdjacencyOffsets[i];
1455 : 0 : size_t end = pd.vertAdjacencyOffsets[i + 1];
1456 [ # # ]: 0 : if( j != end ) stream << " " << pd.vertAdjacencyArray[j++];
1457 [ # # ]: 0 : for( ; j < end; ++j )
1458 : 0 : stream << "," << pd.vertAdjacencyArray[j];
1459 : : }
1460 : :
1461 : 0 : stream << endl;
1462 : : }
1463 : :
1464 : 0 : stream << "Elements: " << endl;
1465 : 0 : stream << setw( iw ) << "Idx"
1466 : 0 : << " " << setw( hw ) << "Handle"
1467 : 0 : << " " << setw( tw + 2 ) << "Type"
1468 : 0 : << " "
1469 : 0 : << "Connectivity" << std::endl
1470 : 0 : << setw( iw ) << setfill( '-' ) << ""
1471 : 0 : << " " << setw( hw ) << setfill( '-' ) << ""
1472 : 0 : << " " << setw( tw + 2 ) << setfill( '-' ) << ""
1473 : 0 : << " " << setfill( ' ' ) << "--------------------------" << std::endl;
1474 [ # # ]: 0 : for( i = 0; i < pd.num_elements(); ++i )
1475 : : {
1476 : 0 : EntityTopology type = pd.elementArray[i].get_element_type();
1477 : 0 : stream << setw( iw ) << i << " " << setw( hw ) << pd.elementHandlesArray[i] << " " << setw( tw )
1478 : 0 : << TopologyInfo::short_name( type ) << left << setw( 2 ) << pd.elementArray[i].node_count() << internal
1479 : 0 : << " " << setw( iw ) << pd.elementArray[i].get_vertex_index_array()[0];
1480 [ # # ]: 0 : for( size_t j = 1; j < pd.elementArray[i].node_count(); ++j )
1481 : 0 : stream << "," << setw( iw ) << pd.elementArray[i].get_vertex_index_array()[j];
1482 : 0 : stream << endl;
1483 : : }
1484 : 0 : stream << endl;
1485 : :
1486 [ # # ]: 0 : stream << "Mesh: " << ( pd.myMesh ? "yes" : "no" ) << endl;
1487 [ # # ]: 0 : stream << "Domain: " << ( pd.myDomain ? "yes" : "no" ) << endl;
1488 : : // stream << "mType: " << (pd.mType==PatchData::VERTICES_ON_VERTEX_PATCH?"vert-on-vert":
1489 : : // pd.mType==PatchData::ELEMENTS_ON_VERTEX_PATCH?"elem-on-vert":
1490 : : // pd.mType==PatchData::GLOBAL_PATCH?"global":"unknown") << endl;
1491 : :
1492 [ # # ]: 0 : if( pd.haveComputedInfos )
1493 : : {
1494 : 0 : stream << "ComputedInfos:" << endl;
1495 [ # # ]: 0 : if( pd.have_computed_info( PatchData::MIN_UNSIGNED_AREA ) )
1496 : 0 : stream << "\t MIN_UNSINGED_AREA = " << pd.computedInfos[PatchData::MIN_UNSIGNED_AREA] << endl;
1497 [ # # ]: 0 : if( pd.have_computed_info( PatchData::MAX_UNSIGNED_AREA ) )
1498 : 0 : stream << "\t MAX_UNSIGNED_AREA = " << pd.computedInfos[PatchData::MAX_UNSIGNED_AREA] << endl;
1499 [ # # ]: 0 : if( pd.have_computed_info( PatchData::MIN_EDGE_LENGTH ) )
1500 : 0 : stream << "\t MIN_EDGE_LENGTH = " << pd.computedInfos[PatchData::MIN_EDGE_LENGTH] << endl;
1501 [ # # ]: 0 : if( pd.have_computed_info( PatchData::MAX_EDGE_LENGTH ) )
1502 : 0 : stream << "\t MAX_EDGE_LENGTH = " << pd.computedInfos[PatchData::MAX_EDGE_LENGTH] << endl;
1503 [ # # ]: 0 : if( pd.have_computed_info( PatchData::MINMAX_SIGNED_DET2D ) )
1504 : 0 : stream << "\t MINMAX_SIGNED_DET2D = " << pd.computedInfos[PatchData::MINMAX_SIGNED_DET2D] << endl;
1505 [ # # ]: 0 : if( pd.have_computed_info( PatchData::MINMAX_SIGNED_DET3D ) )
1506 : 0 : stream << "\t MINMAX_SIGNED_DET3D = " << pd.computedInfos[PatchData::MINMAX_SIGNED_DET3D] << endl;
1507 [ # # ]: 0 : if( pd.have_computed_info( PatchData::AVERAGE_DET3D ) )
1508 : 0 : stream << "\t AVERAGE_DET3D = " << pd.computedInfos[PatchData::AVERAGE_DET3D] << endl;
1509 : : }
1510 : :
1511 : 0 : return stream << endl;
1512 : : }
1513 : :
1514 : 0 : void print_patch_data( const PatchData& pd )
1515 : : {
1516 : 0 : std::cout << pd << std::endl;
1517 : 0 : }
1518 : :
1519 : 0 : void PatchData::enslave_higher_order_nodes( const size_t* elem_offset_array, unsigned char* vertex_flags,
1520 : : MsqError& ) const
1521 : : {
1522 [ # # ]: 0 : for( size_t i = 0; i < elementArray.size(); ++i )
1523 : : {
1524 : 0 : size_t start = elem_offset_array[i];
1525 : 0 : size_t conn_len = elem_offset_array[i + 1] - start;
1526 [ # # ]: 0 : for( size_t j = elementArray[i].vertex_count(); j < conn_len; ++j )
1527 : : {
1528 : 0 : const size_t vert_idx = elemConnectivityArray[start + j];
1529 [ # # ]: 0 : assert( vert_idx < vertexHandlesArray.size() );
1530 [ # # ]: 0 : if( !( vertex_flags[vert_idx] & MsqVertex::MSQ_HARD_FIXED ) )
1531 : 0 : vertex_flags[vert_idx] |= MsqVertex::MSQ_DEPENDENT;
1532 : : }
1533 : : }
1534 : 0 : }
1535 : :
1536 : 1128315 : void PatchData::initialize_data( size_t* elem_offset_array, unsigned char* vertex_flags, MsqError& )
1537 : : {
1538 : : // Clear out data specific to patch
1539 : 1128315 : vertexNormalIndices.clear();
1540 : 1128315 : normalData.clear();
1541 : : // vertexDomainDOF.clear();
1542 : :
1543 : : // Clear any vertex->element adjacency data. It
1544 : : // is probably invalid, and certainly will be by the time
1545 : : // this function completes if the mesh contains higher-order
1546 : : // elements.
1547 : 1128315 : vertAdjacencyArray.clear();
1548 : 1128315 : vertAdjacencyOffsets.clear();
1549 : : size_t i, j;
1550 [ + + ]: 5069195 : for( i = 0; i < elementArray.size(); ++i )
1551 : : {
1552 : 3940880 : size_t start = elem_offset_array[i];
1553 : 3940880 : size_t conn_len = elem_offset_array[i + 1] - start;
1554 [ - + ]: 3940880 : assert( conn_len > 0 );
1555 : 3940880 : elementArray[i].set_connectivity( &elemConnectivityArray[start], conn_len );
1556 : : }
1557 : :
1558 : : // Use vertAdjacencyOffsets array as temporary storage.
1559 : 1128315 : vertAdjacencyOffsets.resize( vertexHandlesArray.size() + 1 );
1560 : 1128315 : size_t* vertex_index_map = arrptr( vertAdjacencyOffsets );
1561 : :
1562 : : // Count number of free vertices and initialize vertex_index_map
1563 : 1128315 : numFreeVertices = 0;
1564 [ + + ]: 10156385 : for( i = 0; i < vertexHandlesArray.size(); ++i )
1565 : : {
1566 [ + + ]: 9028070 : if( !( vertex_flags[i] & MsqVertex::MSQ_FIXED ) ) ++numFreeVertices;
1567 : 9028070 : vertex_index_map[i] = i;
1568 : : }
1569 : :
1570 : : // Re-order vertices such that all free vertices are
1571 : : // first in the list. Construct map from old to new
1572 : : // position in list for updating element connectivity.
1573 : 1128315 : i = 0;
1574 : 1128315 : j = numFreeVertices;
1575 : 989291 : for( ;; ++i, ++j )
1576 : : {
1577 : : // find next fixed vertex in the range [i,numFreeVertices)
1578 [ + + ][ + + ]: 2944869 : for( ; i < numFreeVertices && !( vertex_flags[i] & MsqVertex::MSQ_FIXED ); ++i )
1579 : : ;
1580 : : // if no more fixed vertices in the free vertex range [0,numFreeVertices)
1581 [ + + ]: 2117606 : if( i == numFreeVertices ) break;
1582 : : // find the next free vertex in the range [j,num_nodes)
1583 [ + + ]: 3664171 : for( ; vertex_flags[j] & MsqVertex::MSQ_FIXED; ++j )
1584 : : ;
1585 : : // swap fixed (i) and free (j) vertices
1586 : 989291 : vertex_index_map[i] = j;
1587 : 989291 : vertex_index_map[j] = i;
1588 : 989291 : std::swap( vertexHandlesArray[i], vertexHandlesArray[j] );
1589 : 989291 : std::swap( vertex_flags[i], vertex_flags[j] );
1590 : : }
1591 [ - + ]: 1128315 : assert( i == numFreeVertices );
1592 [ - + ]: 1128315 : assert( j <= vertexHandlesArray.size() );
1593 : :
1594 : : // Update element connectivity data for new vertex indices
1595 [ + + ]: 16993745 : for( i = 0; i < elemConnectivityArray.size(); ++i )
1596 : 15865430 : elemConnectivityArray[i] = vertex_index_map[elemConnectivityArray[i]];
1597 : :
1598 : : // Reorder vertices such that free, slave vertices
1599 : : // occur after free, non-slave vertices in list.
1600 : 1128315 : numSlaveVertices = 0;
1601 [ + + ]: 10156385 : for( i = 0; i < vertexHandlesArray.size(); ++i )
1602 : : {
1603 [ + + ][ + + ]: 9028070 : if( ( vertex_flags[i] & MsqVertex::MSQ_DEPENDENT ) && !( vertex_flags[i] & MsqVertex::MSQ_FIXED ) )
1604 : 366 : ++numSlaveVertices;
1605 : : }
1606 : 1128315 : numFreeVertices -= numSlaveVertices;
1607 : :
1608 [ + + ]: 1128418 : if( numSlaveVertices )
1609 : : {
1610 : : // re-initialize vertex index map
1611 [ + + ]: 1172 : for( i = 0; i < vertexHandlesArray.size(); ++i )
1612 : 1080 : vertex_index_map[i] = i;
1613 : :
1614 : : // Re-order free vertices such that all slave vertices are
1615 : : // last in the list. Construct map from old to new
1616 : : // position in list for updating element connectivity.
1617 : 92 : i = 0;
1618 : 92 : j = numFreeVertices;
1619 : 103 : for( ;; ++i, ++j )
1620 : : {
1621 : : // find next slave vertex in the range [i,numFreeVertices)
1622 [ + + ][ + + ]: 522 : for( ; i < numFreeVertices && !( vertex_flags[i] & MsqVertex::MSQ_DEPENDENT ); ++i )
1623 : : ;
1624 : : // if no more slave vertices in [0,numFreeVertices), then done.
1625 [ + + ]: 195 : if( i == numFreeVertices ) break;
1626 : : // find the next free (non-slave) vertex in the range
1627 : : // [numFreeVertices,numFreeVertices+numSlaveVertices)
1628 [ + + ]: 137 : for( ; vertex_flags[j] & MsqVertex::MSQ_DEPENDENT; ++j )
1629 : : ;
1630 : : // swap free (j) and slave (i) vertices
1631 : 103 : vertex_index_map[i] = j;
1632 : 103 : vertex_index_map[j] = i;
1633 : 103 : std::swap( vertexHandlesArray[i], vertexHandlesArray[j] );
1634 : 103 : std::swap( vertex_flags[i], vertex_flags[j] );
1635 : : }
1636 [ - + ]: 92 : assert( i == numFreeVertices );
1637 [ - + ]: 92 : assert( j <= numFreeVertices + numSlaveVertices );
1638 : :
1639 : : // Update element connectivity data for new vertex indices
1640 [ + + ]: 1952 : for( i = 0; i < elemConnectivityArray.size(); ++i )
1641 : 1860 : elemConnectivityArray[i] = vertex_index_map[elemConnectivityArray[i]];
1642 : : }
1643 : :
1644 : : // Clear temporary data
1645 : 1128315 : vertAdjacencyOffsets.clear();
1646 : :
1647 : 2117606 : notify_new_patch();
1648 : 1128315 : }
1649 : :
1650 : 0 : size_t PatchData::num_corners() const
1651 : : {
1652 : 0 : size_t result = 0;
1653 [ # # ]: 0 : for( unsigned i = 0; i < elementArray.size(); ++i )
1654 : 0 : result += elementArray[i].vertex_count();
1655 : 0 : return result;
1656 : : }
1657 : :
1658 : 0 : void PatchData::fill( size_t num_vertex, const double* coords, size_t num_elem, EntityTopology type,
1659 : : const size_t* connectivity, const bool* fixed, MsqError& err )
1660 : : {
1661 [ # # ]: 0 : std::vector< EntityTopology > types( num_elem );
1662 [ # # ]: 0 : std::fill( types.begin(), types.end(), type );
1663 [ # # ][ # # ]: 0 : const EntityTopology* type_ptr = num_elem ? arrptr( types ) : 0;
1664 [ # # ][ # # ]: 0 : this->fill( num_vertex, coords, num_elem, type_ptr, connectivity, fixed, err );MSQ_CHKERR( err );
[ # # ][ # # ]
[ # # ]
1665 : 0 : }
1666 : :
1667 : 0 : void PatchData::fill( size_t num_vertex, const double* coords, size_t num_elem, const EntityTopology* types,
1668 : : const size_t* conn, const bool* fixed, MsqError& err )
1669 : : {
1670 [ # # ]: 0 : std::vector< size_t > lengths( num_elem );
1671 [ # # ][ # # ]: 0 : std::transform( types, types + num_elem, lengths.begin(), std::ptr_fun( TopologyInfo::corners ) );
1672 [ # # ][ # # ]: 0 : const size_t* len_ptr = num_elem ? arrptr( lengths ) : 0;
1673 [ # # ][ # # ]: 0 : this->fill( num_vertex, coords, num_elem, types, len_ptr, conn, fixed, err );MSQ_CHKERR( err );
[ # # ][ # # ]
[ # # ]
1674 : 0 : }
1675 : :
1676 : 0 : void PatchData::fill( size_t num_vertex, const double* coords, size_t num_elem, const EntityTopology* types,
1677 : : const size_t* lengths, const size_t* conn, const bool* fixed, MsqError& err )
1678 : : {
1679 : : size_t i;
1680 : :
1681 : : // count vertex uses
1682 [ # # ]: 0 : size_t num_uses = std::accumulate( lengths, lengths + num_elem, 0 );
1683 : :
1684 : : // Allocate storage for data
1685 [ # # ]: 0 : vertexArray.resize( num_vertex );
1686 [ # # ]: 0 : vertexHandlesArray.resize( num_vertex );
1687 [ # # ]: 0 : elementArray.resize( num_elem );
1688 [ # # ]: 0 : elementHandlesArray.resize( num_elem );
1689 [ # # ]: 0 : elemConnectivityArray.resize( num_uses );
1690 : 0 : numFreeVertices = 0;
1691 : 0 : numSlaveVertices = 0;
1692 : :
1693 : : // Must call clear() first so that any stale values get
1694 : : // zero'd when we call resize.
1695 : 0 : byteArray.clear();
1696 [ # # ]: 0 : if( fixed )
1697 : : {
1698 [ # # ]: 0 : byteArray.resize( num_vertex, 0 );
1699 [ # # ]: 0 : for( i = 0; i < num_vertex; ++i )
1700 [ # # ][ # # ]: 0 : if( fixed[i] ) byteArray[i] |= ( MsqVertex::MSQ_HARD_FIXED | MsqVertex::MSQ_PATCH_FIXED );
1701 : : }
1702 : :
1703 [ # # ]: 0 : for( i = 0; i < num_elem; ++i )
1704 : : {
1705 [ # # ][ # # ]: 0 : element_by_index( i ).set_element_type( types[i] );
1706 [ # # ]: 0 : elementHandlesArray[i] = (Mesh::ElementHandle)i;
1707 : : }
1708 [ # # ]: 0 : for( i = 0; i < num_vertex; ++i )
1709 [ # # ]: 0 : vertexHandlesArray[i] = (Mesh::VertexHandle)i;
1710 : :
1711 [ # # ]: 0 : memcpy( get_connectivity_array(), conn, num_uses * sizeof( size_t ) );
1712 : :
1713 [ # # ]: 0 : std::vector< size_t > offsets( num_elem + 1 );
1714 [ # # ]: 0 : size_t sum = offsets[0] = 0;
1715 [ # # ]: 0 : for( i = 1; i <= num_elem; ++i )
1716 [ # # ]: 0 : offsets[i] = sum += lengths[i - 1];
1717 : :
1718 : : const Settings::HigherOrderSlaveMode ho_mode =
1719 [ # # ][ # # ]: 0 : mSettings ? mSettings->get_slaved_ho_node_mode() : Settings::SLAVE_ALL;
1720 [ # # # ]: 0 : switch( ho_mode )
1721 : : {
1722 : : case Settings::SLAVE_ALL:
1723 [ # # ]: 0 : byteArray.resize( num_vertex, 0 );
1724 [ # # ][ # # ]: 0 : enslave_higher_order_nodes( arrptr( offsets ), arrptr( byteArray ), err );MSQ_ERRRTN( err );
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
1725 : 0 : break;
1726 : : case Settings::SLAVE_NONE:
1727 : : // Do nothing. We clear other bits when processing the 'fixed' array above.
1728 : 0 : break;
1729 : : default:
1730 : : MSQ_SETERR( err )
1731 : : ( "Specified higher-order noded slaving scheme not supported "
1732 : : "when initializind PatchData using PatchData::fill",
1733 [ # # ][ # # ]: 0 : MsqError::NOT_IMPLEMENTED );
1734 : 0 : return;
1735 : : }
1736 : :
1737 [ # # ][ # # ]: 0 : this->initialize_data( arrptr( offsets ), arrptr( byteArray ), err );MSQ_ERRRTN( err );
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ][ # # ]
1738 : :
1739 : : // initialize_data will re-order vertex handles and
1740 : : // update element connectivity accordingly. Use
1741 : : // the values we stored in vertexHandlesArray to
1742 : : // figure out the new index of each vertex, and initialize
1743 : : // the vertex.
1744 [ # # ]: 0 : for( i = 0; i < num_vertex; ++i )
1745 [ # # ][ # # ]: 0 : vertexArray[i] = coords + 3 * (size_t)vertexHandlesArray[i];
[ # # ][ # # ]
1746 : :
1747 [ # # ][ # # ]: 0 : for( i = 0; i < num_vertex; ++i )
1748 [ # # ][ # # ]: 0 : vertexArray[i].flags() = byteArray[i];
[ # # ]
1749 : : }
1750 : :
1751 : 1128315 : void PatchData::make_handles_unique( Mesh::EntityHandle* handles, size_t& count, size_t* index_map )
1752 : : {
1753 [ - + ]: 2256630 : if( count < 2 ) { return; }
1754 : : // save this now, as we'll be changing count later
1755 : 1128315 : const size_t* index_end = index_map + count;
1756 : :
1757 [ + - ]: 1128315 : if( index_map )
1758 : : {
1759 : : // Copy input handle list into index map as a temporary
1760 : : // copy of the input list.
1761 : : assert( sizeof( Mesh::EntityHandle ) == sizeof( size_t ) );
1762 : 1128315 : memcpy( index_map, handles, count * sizeof( size_t ) );
1763 : : }
1764 : :
1765 : : // Make handles a unique list
1766 : 1128315 : std::sort( handles, handles + count );
1767 : 1128315 : Mesh::EntityHandle* end = std::unique( handles, handles + count );
1768 : 1128315 : count = end - handles;
1769 : :
1770 [ + - ]: 1128315 : if( index_map )
1771 : : {
1772 : : // Replace each handle in index_map with the index of
1773 : : // its position in the handles array
1774 : : Mesh::EntityHandle* pos;
1775 [ + + ]: 16993745 : for( size_t* iter = index_map; iter != index_end; ++iter )
1776 : : {
1777 [ + - ]: 15865430 : pos = std::lower_bound( handles, handles + count, (Mesh::EntityHandle)*iter );
1778 : 15865430 : *iter = pos - handles;
1779 : : }
1780 : : }
1781 : : }
1782 : :
1783 : 73 : void PatchData::fill_global_patch( MsqError& err )
1784 : : {
1785 [ + - ]: 73 : GlobalPatch gp;
1786 [ + - ][ + - ]: 73 : gp.set_mesh( get_mesh() );
1787 [ + - ][ + - ]: 146 : PatchIterator iter( &gp );
1788 [ + - ][ + - ]: 146 : bool b = iter.get_next_patch( *this, err );MSQ_ERRRTN( err );
[ - + ][ # # ]
[ # # ][ - + ]
1789 [ - + ][ # # ]: 73 : if( !b ) MSQ_SETERR( err )( "Empty patch in PatchData::fill_global_patch", MsqError::INVALID_MESH );
[ # # ]
1790 [ - + ][ + - ]: 146 : assert( b );
1791 : : }
1792 : :
1793 : 1128315 : void PatchData::set_mesh_entities( std::vector< Mesh::ElementHandle >& elements,
1794 : : std::vector< Mesh::VertexHandle >& free_vertices, MsqError& err )
1795 : : {
1796 [ + - ]: 1128315 : Mesh* current_mesh = get_mesh();
1797 [ - + ]: 1128315 : if( !current_mesh )
1798 : : {
1799 [ # # ][ # # ]: 0 : MSQ_SETERR( err )( "No Mesh associated with PatchData.", MsqError::INVALID_STATE );
1800 : 1128315 : return;
1801 : : }
1802 : :
1803 [ - + ]: 1128315 : if( elements.empty() )
1804 : : {
1805 [ # # ]: 0 : clear();
1806 : 0 : return;
1807 : : }
1808 : :
1809 [ + - ]: 1128315 : elementHandlesArray = elements;
1810 [ + - + - ]: 2256630 : get_mesh()->elements_get_attached_vertices( arrptr( elementHandlesArray ), elementHandlesArray.size(),
1811 [ + - ][ + - ]: 2256630 : vertexHandlesArray, offsetArray, err );MSQ_ERRRTN( err );
[ - + ][ # # ]
[ # # ][ - + ]
1812 : :
1813 : : // Construct CSR-rep element connectivity data
1814 : 1128315 : size_t num_vert = vertexHandlesArray.size();
1815 [ + - ]: 1128315 : elemConnectivityArray.resize( num_vert );
1816 [ + - ][ + - ]: 1128315 : make_handles_unique( arrptr( vertexHandlesArray ), num_vert, arrptr( elemConnectivityArray ) );
[ + - ]
1817 [ + - ]: 1128315 : vertexHandlesArray.resize( num_vert );
1818 : :
1819 : : // Get element topologies
1820 [ + - ]: 1128315 : std::vector< EntityTopology > elem_topologies( elementHandlesArray.size() );
1821 [ + - ][ + - ]: 2256630 : get_mesh()->elements_get_topologies( arrptr( elementHandlesArray ), arrptr( elem_topologies ),
1822 [ + - ][ + - ]: 2256630 : elementHandlesArray.size(), err );MSQ_ERRRTN( err );
[ + - ][ - + ]
[ # # ][ # # ]
[ - + ]
1823 : :
1824 : : // get vertex bits from mesh
1825 [ + - ]: 1128315 : byteArray.resize( vertexHandlesArray.size() );
1826 [ + - ][ + - ]: 1128315 : get_mesh()->vertices_get_byte( arrptr( vertexHandlesArray ), arrptr( byteArray ), vertexHandlesArray.size(), err );MSQ_ERRRTN( err );
[ + - ][ + - ]
[ + - ][ - + ]
[ # # ][ # # ]
[ - + ]
1827 : :
1828 : : // if free_vertices is not empty, then we need to mark as
1829 : : // fixed any vertices *not* in that list.
1830 [ + + ]: 1128315 : if( free_vertices.size() == 1 )
1831 : : {
1832 [ + + ]: 8694834 : for( size_t i = 0; i < vertexHandlesArray.size(); ++i )
1833 [ + - ][ + - ]: 7827359 : if( vertexHandlesArray[i] == free_vertices.front() )
[ + + ]
1834 [ + - ]: 867475 : byteArray[i] &= ~MsqVertex::MSQ_PATCH_FIXED;
1835 : : else
1836 [ + - ]: 6959884 : byteArray[i] |= MsqVertex::MSQ_PATCH_FIXED;
1837 : : }
1838 [ + + ]: 260840 : else if( !free_vertices.empty() )
1839 : : {
1840 : : // sort and remove duplicates from free_vertices list.
1841 [ + - ]: 2 : std::sort( free_vertices.begin(), free_vertices.end() );
1842 [ + - ][ + - ]: 2 : free_vertices.erase( std::unique( free_vertices.begin(), free_vertices.end() ), free_vertices.end() );
1843 : :
1844 [ + + ]: 1429 : for( size_t i = 0; i < vertexHandlesArray.size(); ++i )
1845 : : {
1846 [ + - ][ + - ]: 2854 : if( ( byteArray[i] & MsqVertex::MSQ_DEPENDENT ) ||
[ + - ][ + - ]
1847 [ + - ][ + - ]: 1427 : std::binary_search( free_vertices.begin(), free_vertices.end(), vertexHandlesArray[i] ) )
1848 [ + - ]: 1427 : byteArray[i] &= ~MsqVertex::MSQ_PATCH_FIXED;
1849 : : else
1850 [ # # ]: 0 : byteArray[i] |= MsqVertex::MSQ_PATCH_FIXED;
1851 : : }
1852 : : }
1853 : :
1854 : : // set element types
1855 [ + - ]: 1128315 : elementArray.resize( elementHandlesArray.size() );
1856 [ + + ]: 5069195 : for( size_t i = 0; i < elementHandlesArray.size(); ++i )
1857 [ + - ][ + - ]: 3940880 : elementArray[i].set_element_type( elem_topologies[i] );
[ + - ]
1858 : :
1859 : : // get element connectivity, group vertices by free/slave/fixed state
1860 [ + - ][ + - ]: 1128315 : initialize_data( arrptr( offsetArray ), arrptr( byteArray ), err );MSQ_ERRRTN( err );
[ + - ][ + - ]
[ - + ][ # # ]
[ # # ][ - + ]
1861 : :
1862 : : // get vertex coordinates
1863 [ + - ]: 1128315 : vertexArray.resize( vertexHandlesArray.size() );
1864 [ + - ][ + - ]: 2256630 : get_mesh()->vertices_get_coordinates( arrptr( vertexHandlesArray ), arrptr( vertexArray ),
1865 [ + - ][ + - ]: 2256630 : vertexHandlesArray.size(), err );MSQ_ERRRTN( err );
[ + - ][ - + ]
[ # # ][ # # ]
[ - + ]
1866 : :
1867 : : // set vertex flags
1868 [ + + ][ + - ]: 10156385 : for( size_t i = 0; i < vertexArray.size(); ++i )
1869 [ + - ][ + - ]: 10156385 : vertexArray[i].flags() = byteArray[i];
[ + - ]
1870 : : }
1871 : :
1872 : 0 : void PatchData::get_sample_location( size_t element_index, Sample sample, Vector3D& result, MsqError& err ) const
1873 : : {
1874 [ # # ]: 0 : const MsqMeshEntity& elem = element_by_index( element_index );
1875 [ # # ]: 0 : const NodeSet ho_bits = non_slave_node_set( element_index );
1876 [ # # ][ # # ]: 0 : const MappingFunction* const f = get_mapping_function( elem.get_element_type() );
1877 [ # # ]: 0 : if( !f )
1878 : : {
1879 [ # # ][ # # ]: 0 : MSQ_SETERR( err )( "No mapping function", MsqError::UNSUPPORTED_ELEMENT );
1880 : 0 : return;
1881 : : }
1882 : :
1883 : : double coeff[27];
1884 : : size_t num_coeff, index[27];
1885 [ # # ][ # # ]: 0 : f->coefficients( sample, ho_bits, coeff, index, num_coeff, err );MSQ_ERRRTN( err );
[ # # ][ # # ]
[ # # ][ # # ]
1886 [ # # ][ # # ]: 0 : f->convert_connectivity_indices( elem.node_count(), index, num_coeff, err );MSQ_ERRRTN( err );
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
1887 : :
1888 [ # # ]: 0 : const size_t* const conn = elem.get_vertex_index_array();
1889 [ # # ]: 0 : assert( num_coeff > 0 );
1890 [ # # ][ # # ]: 0 : result = coeff[0] * vertex_by_index( conn[index[0]] );
[ # # ]
1891 [ # # ]: 0 : for( unsigned i = 1; i < num_coeff; ++i )
1892 [ # # ][ # # ]: 0 : result += coeff[i] * vertex_by_index( conn[index[i]] );
[ # # ]
1893 : : }
1894 : :
1895 : 26228601 : NodeSet PatchData::non_slave_node_set( size_t element_index ) const
1896 : : {
1897 [ + - ]: 26228601 : const MsqMeshEntity& elem = element_by_index( element_index );
1898 [ + - ]: 26228601 : EntityTopology type = elem.get_element_type();
1899 [ + - ]: 26228601 : const size_t* conn = elem.get_vertex_index_array();
1900 [ + - ]: 26228601 : const size_t n = elem.node_count();
1901 : :
1902 [ + - ]: 26228601 : MsqError err;
1903 : : bool have_midedge, have_midface, have_midelem;
1904 [ + - ]: 26228601 : unsigned num_edge = 0, num_face = 0, num_corner = TopologyInfo::corners( type );
1905 [ + - ]: 26228601 : TopologyInfo::higher_order( type, n, have_midedge, have_midface, have_midelem, err );
1906 [ + - ]: 26228601 : num_edge = TopologyInfo::edges( type );
1907 [ + - ][ + + ]: 26228601 : if( TopologyInfo::dimension( type ) == 2 )
1908 : 16235706 : num_face = 1;
1909 : : else
1910 [ + - ]: 9992895 : num_face = TopologyInfo::faces( type );
1911 : :
1912 [ + - ]: 26228601 : NodeSet result;
1913 [ + - ]: 26228601 : result.set_all_corner_nodes( type );
1914 [ + + ]: 26228601 : if( have_midedge )
1915 : : {
1916 [ + + ]: 407212 : for( unsigned i = 0; i < num_edge; ++i )
1917 : : {
1918 [ + - ][ + - ]: 310132 : if( !( vertex_by_index( conn[num_corner + i] ).get_flags() & MsqVertex::MSQ_DEPENDENT ) )
[ + + ]
1919 [ + - ]: 251694 : result.set_mid_edge_node( i );
1920 : : }
1921 : : }
1922 [ - + ]: 26228601 : if( have_midface )
1923 : : {
1924 [ # # ]: 0 : for( unsigned i = 0; i < num_face; ++i )
1925 : : {
1926 [ # # ][ # # ]: 0 : if( !( vertex_by_index( conn[num_corner + num_edge + i] ).get_flags() & MsqVertex::MSQ_DEPENDENT ) )
[ # # ]
1927 [ # # ]: 0 : result.set_mid_face_node( i );
1928 : : }
1929 : : }
1930 [ - + ][ # # ]: 26228601 : if( have_midelem &&
[ - + ]
1931 [ # # ][ # # ]: 0 : !( vertex_by_index( conn[num_corner + num_edge + num_face] ).get_flags() & MsqVertex::MSQ_DEPENDENT ) )
1932 [ # # ]: 0 : result.set_mid_region_node();
1933 : :
1934 : 26228601 : return result;
1935 : : }
1936 : :
1937 : 450 : void PatchData::get_samples( size_t element, std::vector< Sample >& samples, MsqError& ) const
1938 : : {
1939 [ + - ]: 450 : NodeSet ns = get_samples( element );
1940 [ + - ][ + - ]: 450 : samples.resize( ns.num_nodes() );
1941 : 450 : std::vector< Sample >::iterator i = samples.begin();
1942 : :
1943 : : unsigned j;
1944 [ + - ][ + - ]: 450 : EntityTopology type = element_by_index( element ).get_element_type();
1945 [ + - ][ + + ]: 1850 : for( j = 0; j < TopologyInfo::corners( type ); ++j )
1946 [ + - ][ + + ]: 1400 : if( ns.corner_node( j ) ) *( i++ ) = Sample( 0, j );
[ + - ][ + - ]
[ + - ]
1947 [ + - ][ + + ]: 1850 : for( j = 0; j < TopologyInfo::edges( type ); ++j )
1948 [ + - ][ - + ]: 1400 : if( ns.mid_edge_node( j ) ) *( i++ ) = Sample( 1, j );
[ # # ][ # # ]
[ # # ]
1949 [ + - ][ - + ]: 450 : if( TopologyInfo::dimension( type ) == 3 )
1950 : : {
1951 [ # # ][ # # ]: 0 : for( j = 0; j < TopologyInfo::faces( type ); ++j )
1952 [ # # ][ # # ]: 0 : if( ns.mid_face_node( j ) ) *( i++ ) = Sample( 2, j );
[ # # ][ # # ]
[ # # ]
1953 [ # # ][ # # ]: 0 : if( ns.mid_region_node() ) *( i++ ) = Sample( 3, 0 );
[ # # ][ # # ]
[ # # ]
1954 : : }
1955 [ + - ][ + + ]: 450 : else if( ns.mid_face_node( 0 ) )
1956 [ + - ][ + - ]: 400 : *( i++ ) = Sample( 2, 0 );
[ + - ]
1957 : :
1958 [ + - ][ - + ]: 450 : assert( i == samples.end() );
1959 : 450 : }
1960 : :
1961 : 2 : bool PatchData::attach_extra_data( ExtraData* data )
1962 : : {
1963 [ - + ]: 2 : if( data->patchNext ) { return false; }
1964 : :
1965 [ - + ]: 2 : if( !data->patchPtr )
1966 : 0 : data->patchPtr = this;
1967 [ - + ]: 2 : else if( data->patchPtr != this )
1968 : 0 : return false;
1969 : :
1970 : 2 : data->patchNext = dataList;
1971 : 2 : dataList = data;
1972 : 2 : return true;
1973 : : }
1974 : :
1975 : 0 : bool PatchData::remove_extra_data( ExtraData* data )
1976 : : {
1977 [ # # ]: 0 : if( data->patchPtr != this ) return false;
1978 : :
1979 [ # # ]: 0 : if( dataList == data )
1980 : : {
1981 : 0 : dataList = data->patchNext;
1982 : 0 : data->patchNext = 0;
1983 : 0 : data->patchPtr = 0;
1984 : 0 : return true;
1985 : : }
1986 : :
1987 [ # # ]: 0 : for( ExtraData* iter = dataList; iter; iter = iter->patchNext )
1988 [ # # ]: 0 : if( iter->patchNext == data )
1989 : : {
1990 : 0 : iter->patchNext = data->patchNext;
1991 : 0 : data->patchNext = 0;
1992 : 0 : data->patchPtr = 0;
1993 : 0 : return true;
1994 : : }
1995 : :
1996 : 0 : return false;
1997 : : }
1998 : :
1999 : 1128371 : void PatchData::notify_new_patch()
2000 : : {
2001 [ - + ]: 1128371 : for( ExtraData* iter = dataList; iter; iter = iter->patchNext )
2002 : 0 : iter->notify_new_patch();
2003 : 1128371 : }
2004 : :
2005 : 0 : void PatchData::notify_sub_patch( PatchData& sub_patch, const size_t* vertex_map, const size_t* element_map,
2006 : : MsqError& err )
2007 : : {
2008 [ # # ]: 0 : for( ExtraData* iter = dataList; iter; iter = iter->patchNext )
2009 : : {
2010 [ # # ][ # # ]: 0 : iter->notify_sub_patch( sub_patch, vertex_map, element_map, err );MSQ_ERRRTN( err );
[ # # ]
2011 : : }
2012 : : }
2013 : :
2014 : 1871 : void PatchData::notify_patch_destroyed()
2015 : : {
2016 : : // Remove all ExtraDatas from list and notify them
2017 : : // that they are being destroyed.
2018 [ + + ]: 1873 : while( dataList )
2019 : : {
2020 : 2 : ExtraData* dead_data = dataList;
2021 : 2 : dataList = dataList->patchNext;
2022 : 2 : dead_data->patchNext = 0;
2023 : 2 : dead_data->patchPtr = 0;
2024 : 2 : dead_data->notify_patch_destroyed();
2025 : : }
2026 : 1871 : }
2027 : :
2028 [ + - ][ + - ]: 120 : } // namespace MBMesquite
|