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