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