MueLu  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
MueLu_VisualizationHelpers_def.hpp
Go to the documentation of this file.
1 // @HEADER
2 //
3 // ***********************************************************************
4 //
5 // MueLu: A package for multigrid based preconditioning
6 // Copyright 2012 Sandia Corporation
7 //
8 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
9 // the U.S. Government retains certain rights in this software.
10 //
11 // Redistribution and use in source and binary forms, with or without
12 // modification, are permitted provided that the following conditions are
13 // met:
14 //
15 // 1. Redistributions of source code must retain the above copyright
16 // notice, this list of conditions and the following disclaimer.
17 //
18 // 2. Redistributions in binary form must reproduce the above copyright
19 // notice, this list of conditions and the following disclaimer in the
20 // documentation and/or other materials provided with the distribution.
21 //
22 // 3. Neither the name of the Corporation nor the names of the
23 // contributors may be used to endorse or promote products derived from
24 // this software without specific prior written permission.
25 //
26 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
27 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
30 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
31 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
32 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
33 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 //
38 // Questions? Contact
39 // Jonathan Hu (jhu@sandia.gov)
40 // Andrey Prokopenko (aprokop@sandia.gov)
41 // Ray Tuminaro (rstumin@sandia.gov)
42 //
43 // ***********************************************************************
44 //
45 // @HEADER
46 
47 #ifndef MUELU_VISUALIZATIONHELPERS_DEF_HPP_
48 #define MUELU_VISUALIZATIONHELPERS_DEF_HPP_
49 
50 #include <Xpetra_Matrix.hpp>
51 #include <Xpetra_CrsMatrixWrap.hpp>
52 #include <Xpetra_ImportFactory.hpp>
53 #include <Xpetra_MultiVectorFactory.hpp>
55 #include "MueLu_Level.hpp"
56 #include "MueLu_Graph.hpp"
57 #include "MueLu_Monitor.hpp"
58 #include <vector>
59 #include <list>
60 #include <algorithm>
61 #include <string>
62 
63 #ifdef HAVE_MUELU_CGAL
64 #include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
65 #include <CGAL/convex_hull_2.h>
66 #include <CGAL/Polyhedron_3.h>
67 #include <CGAL/convex_hull_3.h>
68 #endif
69 
70 
71 namespace MueLu {
72 
73  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
75  RCP<ParameterList> validParamList = rcp(new ParameterList());
76 
77  validParamList->set< std::string > ("visualization: output filename", "viz%LEVELID", "filename for VTK-style visualization output");
78  validParamList->set< int > ("visualization: output file: time step", 0, "time step variable for output file name");// Remove me?
79  validParamList->set< int > ("visualization: output file: iter", 0, "nonlinear iteration variable for output file name");//Remove me?
80  validParamList->set<std::string> ("visualization: style", "Point Cloud", "style of aggregate visualization for VTK output. Can be 'Point Cloud', 'Jacks', 'Convex Hulls'");
81  validParamList->set<bool> ("visualization: build colormap", false, "Whether to build a random color map in a separate xml file.");
82  validParamList->set<bool> ("visualization: fine graph edges", false, "Whether to draw all fine node connections along with the aggregates.");
83 
84  return validParamList;
85  }
86 
87  template<class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
88  void VisualizationHelpers<Scalar, LocalOrdinal, GlobalOrdinal, Node>::doPointCloud(std::vector<int>& vertices, std::vector<int>& geomSizes, LO /* numLocalAggs */, LO numFineNodes) {
89  vertices.reserve(numFineNodes);
90  geomSizes.reserve(numFineNodes);
91  for(LocalOrdinal i = 0; i < numFineNodes; i++)
92  {
93  vertices.push_back(i);
94  geomSizes.push_back(1);
95  }
96  }
97 
98  template<class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
99  void VisualizationHelpers<Scalar, LocalOrdinal, GlobalOrdinal, Node>::doJacks(std::vector<int>& vertices, std::vector<int>& geomSizes, LO numLocalAggs, LO numFineNodes, const std::vector<bool>& isRoot, const ArrayRCP<LO>& vertex2AggId) {
100  //For each aggregate, find the root node then connect it with the other nodes in the aggregate
101  //Doesn't matter the order, as long as all edges are found.
102  vertices.reserve(vertices.size() + 3 * (numFineNodes - numLocalAggs));
103  geomSizes.reserve(vertices.size() + 2 * (numFineNodes - numLocalAggs));
104  int root = 0;
105  for(int i = 0; i < numLocalAggs; i++) //TODO: Replace this O(n^2) with a better way
106  {
107  while(!isRoot[root])
108  root++;
109  int numInAggFound = 0;
110  for(int j = 0; j < numFineNodes; j++)
111  {
112  if(j == root) //don't make a connection from the root to itself
113  {
114  numInAggFound++;
115  continue;
116  }
117  if(vertex2AggId[root] == vertex2AggId[j])
118  {
119  vertices.push_back(root);
120  vertices.push_back(j);
121  geomSizes.push_back(2);
122  //Also draw the free endpoint explicitly for the current line
123  vertices.push_back(j);
124  geomSizes.push_back(1);
125  numInAggFound++;
126  //if(numInAggFound == aggSizes_[vertex2AggId_[root]]) //don't spend more time looking if done with that root
127  // break;
128  }
129  }
130  root++; //get set up to look for the next root
131  }
132  }
133 
134  template<class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
135  void VisualizationHelpers<Scalar, LocalOrdinal, GlobalOrdinal, Node>::doConvexHulls2D(std::vector<int>& vertices, std::vector<int>& geomSizes, LO numLocalAggs, LO numFineNodes, const std::vector<bool>& /* isRoot */, const ArrayRCP<LO>& vertex2AggId, const Teuchos::ArrayRCP<const typename Teuchos::ScalarTraits<Scalar>::coordinateType>& xCoords, const Teuchos::ArrayRCP<const typename Teuchos::ScalarTraits<Scalar>::coordinateType>& yCoords) {
136 
137  // This algorithm is based on Andrew's Monotone Chain variant of the Graham Scan for Convex Hulls. It adds
138  // a colinearity check which we'll need for our viz.
139  for(int agg = 0; agg < numLocalAggs; agg++) {
140  std::vector<int> aggNodes;
141  for(int i = 0; i < numFineNodes; i++) {
142  if(vertex2AggId[i] == agg)
143  aggNodes.push_back(i);
144  }
145 
146  //have a list of nodes in the aggregate
148  "CoarseningVisualization::doConvexHulls2D: aggregate contains zero nodes!");
149  if(aggNodes.size() == 1) {
150  vertices.push_back(aggNodes.front());
151  geomSizes.push_back(1);
152  continue;
153  }
154  if(aggNodes.size() == 2) {
155  vertices.push_back(aggNodes.front());
156  vertices.push_back(aggNodes.back());
157  geomSizes.push_back(2);
158  continue;
159  }
160  else {
161  int N = (int) aggNodes.size();
162  using MyPair = std::pair<myVec2,int>;
163  std::vector<MyPair> pointsAndIndex(N);
164  for(int i=0; i<N; i++) {
165  pointsAndIndex[i] = std::make_pair(myVec2(xCoords[aggNodes[i]], yCoords[aggNodes[i]]),i);
166  }
167 
168  // Sort by x coordinate
169  std::sort(pointsAndIndex.begin(),pointsAndIndex.end(),[](const MyPair &a, const MyPair &b) {
170  return a.first.x < b.first.x || (a.first.x == b.first.x && a.first.y < b.first.y);
171  });
172 
173 
174  // Colinearity check
175  bool colinear=true;
176  for(int i=0; i<N; i++) {
177  if(ccw(pointsAndIndex[i].first,pointsAndIndex[(i+1)%N].first,pointsAndIndex[(i+2)%N].first)!=0) {
178  colinear=false;
179  break;
180  }
181  }
182 
183  if(colinear) {
184  vertices.push_back(aggNodes[pointsAndIndex.front().second]);
185  vertices.push_back(aggNodes[pointsAndIndex.back().second]);
186  geomSizes.push_back(2);
187  }
188  else {
189  std::vector<int> hull(2*N);
190  int count=0;
191 
192  // Build lower hull
193  for(int i=0; i<N; i++) {
194  while (count >=2 && ccw(pointsAndIndex[hull[count-2]].first,pointsAndIndex[hull[count-1]].first,pointsAndIndex[i].first)<=0) {
195  count--;
196  }
197  hull[count++] = i;
198  }
199 
200  // Build the upper hull
201  int t=count+1;
202  for(int i=N-1; i>0; i--) {
203  while(count >= t && ccw(pointsAndIndex[hull[count-2]].first,pointsAndIndex[hull[count-1]].first,pointsAndIndex[i-1].first)<=0) {
204  count--;
205  }
206  hull[count++]=i-1;
207  }
208 
209  // Remove the duplicated point
210  hull.resize(count-1);
211 
212  // Verify: Check that hull retains CCW order
213  for(int i=0; i<(int)hull.size(); i++) {
214  TEUCHOS_TEST_FOR_EXCEPTION(ccw(pointsAndIndex[hull[i]].first,pointsAndIndex[hull[(i+1)%hull.size()]].first,pointsAndIndex[hull[(i+1)%hull.size()]].first) == 1, Exceptions::RuntimeError,"CoarseningVisualization::doConvexHulls2D: counter-clockwise verification fails");
215  }
216 
217  // We now need to undo the indices from the sorting
218  for(int i=0; i<(int)hull.size(); i++) {
219  hull[i] = aggNodes[pointsAndIndex[hull[i]].second];
220  }
221 
222  vertices.reserve(vertices.size() + hull.size());
223  for(size_t i = 0; i < hull.size(); i++) {
224  vertices.push_back(hull[i]);
225  }
226  geomSizes.push_back(hull.size());
227  }//else colinear
228  }//else 3 + nodes
229  }
230  }
231 
232 #ifdef HAVE_MUELU_CGAL
233  template<class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
234  void VisualizationHelpers<Scalar, LocalOrdinal, GlobalOrdinal, Node>::doCGALConvexHulls2D(std::vector<int>& vertices, std::vector<int>& geomSizes, LO numLocalAggs, LO numFineNodes, const std::vector<bool>& isRoot, const ArrayRCP<LO>& vertex2AggId, const Teuchos::ArrayRCP<const typename Teuchos::ScalarTraits<Scalar>::coordinateType>& xCoords, const Teuchos::ArrayRCP<const typename Teuchos::ScalarTraits<Scalar>::coordinateType>& yCoords) {
235 
236  typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
237  typedef K::Point_2 Point_2;
238 
239  for(int agg = 0; agg < numLocalAggs; agg++) {
240  std::vector<int> aggNodes;
241  std::vector<Point_2> aggPoints;
242  for(int i = 0; i < numFineNodes; i++) {
243  if(vertex2AggId[i] == agg) {
244  Point_2 p(xCoords[i], yCoords[i]);
245  aggPoints.push_back(p);
246  aggNodes.push_back(i);
247  }
248  }
249  //have a list of nodes in the aggregate
251  "CoarseningVisualization::doCGALConvexHulls2D: aggregate contains zero nodes!");
252  if(aggNodes.size() == 1) {
253  vertices.push_back(aggNodes.front());
254  geomSizes.push_back(1);
255  continue;
256  }
257  if(aggNodes.size() == 2) {
258  vertices.push_back(aggNodes.front());
259  vertices.push_back(aggNodes.back());
260  geomSizes.push_back(2);
261  continue;
262  }
263  //check if all points are collinear, need to explicitly draw a line in that case.
264  bool collinear = true; //assume true at first, if a segment not parallel to others then clear
265  {
266  std::vector<int>::iterator it = aggNodes.begin();
267  myVec3 firstPoint(xCoords[*it], yCoords[*it], 0);
268  it++;
269  myVec3 secondPoint(xCoords[*it], yCoords[*it], 0);
270  it++; //it now points to third node in the aggregate
271  myVec3 norm1(-(secondPoint.y - firstPoint.y), secondPoint.x - firstPoint.x, 0);
272  do {
273  myVec3 thisNorm(yCoords[*it] - firstPoint.y, firstPoint.x - xCoords[*it], 0);
274  //rotate one of the vectors by 90 degrees so that dot product is 0 if the two are parallel
275  double temp = thisNorm.x;
276  thisNorm.x = thisNorm.y;
277  thisNorm.y = temp;
278  double comp = dotProduct(norm1, thisNorm);
279  if(-1e-8 > comp || comp > 1e-8) {
280  collinear = false;
281  break;
282  }
283  it++;
284  }
285  while(it != aggNodes.end());
286  }
287  if(collinear)
288  {
289  //find the most distant two points in the plane and use as endpoints of line representing agg
290  std::vector<int>::iterator min = aggNodes.begin(); //min X then min Y where x is a tie
291  std::vector<int>::iterator max = aggNodes.begin(); //max X then max Y where x is a tie
292  for(std::vector<int>::iterator it = ++aggNodes.begin(); it != aggNodes.end(); it++) {
293  if(xCoords[*it] < xCoords[*min])
294  min = it;
295  else if(xCoords[*it] == xCoords[*min]) {
296  if(yCoords[*it] < yCoords[*min])
297  min = it;
298  }
299  if(xCoords[*it] > xCoords[*max])
300  max = it;
301  else if(xCoords[*it] == xCoords[*max]) {
302  if(yCoords[*it] > yCoords[*max])
303  max = it;
304  }
305  }
306  //Just set up a line between nodes *min and *max
307  vertices.push_back(*min);
308  vertices.push_back(*max);
309  geomSizes.push_back(2);
310  continue; //jump to next aggregate in loop
311  }
312  // aggregate has more than 2 points and is not collinear
313  {
314  std::vector<Point_2> result;
315  CGAL::convex_hull_2( aggPoints.begin(), aggPoints.end(), std::back_inserter(result) );
316  // loop over all result points and find the corresponding node id
317  for (size_t r = 0; r < result.size(); r++) {
318  // loop over all aggregate nodes and find corresponding node id
319  for(size_t l = 0; l < aggNodes.size(); l++)
320  {
321  if(fabs(result[r].x() - xCoords[aggNodes[l]]) < 1e-12 &&
322  fabs(result[r].y() - yCoords[aggNodes[l]]) < 1e-12)
323  {
324  vertices.push_back(aggNodes[l]);
325  break;
326  }
327  }
328 
329  }
330  geomSizes.push_back(result.size());
331  }
332  }
333  }
334 
335 #endif
336 
337  template<class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
338  void VisualizationHelpers<Scalar, LocalOrdinal, GlobalOrdinal, Node>::doConvexHulls3D(std::vector<int>& vertices, std::vector<int>& geomSizes, LO numLocalAggs, LO numFineNodes, const std::vector<bool>& /* isRoot */, const ArrayRCP<LO>& vertex2AggId, const Teuchos::ArrayRCP<const typename Teuchos::ScalarTraits<Scalar>::coordinateType>& xCoords, const Teuchos::ArrayRCP<const typename Teuchos::ScalarTraits<Scalar>::coordinateType>& yCoords, const Teuchos::ArrayRCP<const typename Teuchos::ScalarTraits<Scalar>::coordinateType>& zCoords) {
339  //Use 3D quickhull algo.
340  //Vector of node indices representing triangle vertices
341  //Note: Calculate the hulls first since will only include point data for points in the hulls
342  //Effectively the size() of vertIndices after each hull is added to it
343  typedef std::list<int>::iterator Iter;
344  for(int agg = 0; agg < numLocalAggs; agg++) {
345  std::list<int> aggNodes; //At first, list of all nodes in the aggregate. As nodes are enclosed or included by/in hull, remove them
346  for(int i = 0; i < numFineNodes; i++) {
347  if(vertex2AggId[i] == agg)
348  aggNodes.push_back(i);
349  }
350  //First, check anomalous cases
352  "CoarseningVisualization::doConvexHulls3D: aggregate contains zero nodes!");
353  if(aggNodes.size() == 1) {
354  vertices.push_back(aggNodes.front());
355  geomSizes.push_back(1);
356  continue;
357  } else if(aggNodes.size() == 2) {
358  vertices.push_back(aggNodes.front());
359  vertices.push_back(aggNodes.back());
360  geomSizes.push_back(2);
361  continue;
362  }
363  //check for collinearity
364  bool areCollinear = true;
365  {
366  Iter it = aggNodes.begin();
367  myVec3 firstVec(xCoords[*it], yCoords[*it], zCoords[*it]);
368  myVec3 comp;
369  {
370  it++;
371  myVec3 secondVec(xCoords[*it], yCoords[*it], zCoords[*it]); //cross this with other vectors to compare
372  comp = vecSubtract(secondVec, firstVec);
373  it++;
374  }
375  for(; it != aggNodes.end(); it++) {
376  myVec3 thisVec(xCoords[*it], yCoords[*it], zCoords[*it]);
377  myVec3 cross = crossProduct(vecSubtract(thisVec, firstVec), comp);
378  if(mymagnitude(cross) > 1e-10) {
379  areCollinear = false;
380  break;
381  }
382  }
383  }
384  if(areCollinear)
385  {
386  //find the endpoints of segment describing all the points
387  //compare x, if tie compare y, if tie compare z
388  Iter min = aggNodes.begin();
389  Iter max = aggNodes.begin();
390  Iter it = ++aggNodes.begin();
391  for(; it != aggNodes.end(); it++) {
392  if(xCoords[*it] < xCoords[*min]) min = it;
393  else if(xCoords[*it] == xCoords[*min]) {
394  if(yCoords[*it] < yCoords[*min]) min = it;
395  else if(yCoords[*it] == yCoords[*min]) {
396  if(zCoords[*it] < zCoords[*min]) min = it;
397  }
398  }
399  if(xCoords[*it] > xCoords[*max]) max = it;
400  else if(xCoords[*it] == xCoords[*max]) {
401  if(yCoords[*it] > yCoords[*max]) max = it;
402  else if(yCoords[*it] == yCoords[*max]) {
403  if(zCoords[*it] > zCoords[*max])
404  max = it;
405  }
406  }
407  }
408  vertices.push_back(*min);
409  vertices.push_back(*max);
410  geomSizes.push_back(2);
411  continue;
412  }
413  bool areCoplanar = true;
414  {
415  //number of points is known to be >= 3
416  Iter vert = aggNodes.begin();
417  myVec3 v1(xCoords[*vert], yCoords[*vert], zCoords[*vert]);
418  vert++;
419  myVec3 v2(xCoords[*vert], yCoords[*vert], zCoords[*vert]);
420  vert++;
421  myVec3 v3(xCoords[*vert], yCoords[*vert], zCoords[*vert]);
422  vert++;
423  //Make sure the first three points aren't also collinear (need a non-degenerate triangle to get a normal)
424  while(mymagnitude(crossProduct(vecSubtract(v1, v2), vecSubtract(v1, v3))) < 1e-10) {
425  //Replace the third point with the next point
426  v3 = myVec3(xCoords[*vert], yCoords[*vert], zCoords[*vert]);
427  vert++;
428  }
429  for(; vert != aggNodes.end(); vert++) {
430  myVec3 pt(xCoords[*vert], yCoords[*vert], zCoords[*vert]);
431  if(fabs(pointDistFromTri(pt, v1, v2, v3)) > 1e-12) {
432  areCoplanar = false;
433  break;
434  }
435  }
436  if(areCoplanar) {
437  //do 2D convex hull
438  myVec3 planeNorm = getNorm(v1, v2, v3);
439  planeNorm.x = fabs(planeNorm.x);
440  planeNorm.y = fabs(planeNorm.y);
441  planeNorm.z = fabs(planeNorm.z);
442  std::vector<myVec2> points;
443  std::vector<int> nodes;
444  if(planeNorm.x >= planeNorm.y && planeNorm.x >= planeNorm.z) {
445  //project points to yz plane to make hull
446  for(Iter it = aggNodes.begin(); it != aggNodes.end(); it++) {
447  nodes.push_back(*it);
448  points.push_back(myVec2(yCoords[*it], zCoords[*it]));
449  }
450  }
451  if(planeNorm.y >= planeNorm.x && planeNorm.y >= planeNorm.z) {
452  //use xz
453  for(Iter it = aggNodes.begin(); it != aggNodes.end(); it++) {
454  nodes.push_back(*it);
455  points.push_back(myVec2(xCoords[*it], zCoords[*it]));
456  }
457  }
458  if(planeNorm.z >= planeNorm.x && planeNorm.z >= planeNorm.y) {
459  for(Iter it = aggNodes.begin(); it != aggNodes.end(); it++) {
460  nodes.push_back(*it);
461  points.push_back(myVec2(xCoords[*it], yCoords[*it]));
462  }
463  }
464  std::vector<int> convhull2d = giftWrap(points, nodes, xCoords, yCoords);
465  geomSizes.push_back(convhull2d.size());
466  vertices.reserve(vertices.size() + convhull2d.size());
467  for(size_t i = 0; i < convhull2d.size(); i++)
468  vertices.push_back(convhull2d[i]);
469  continue;
470  }
471  }
472  Iter exIt = aggNodes.begin(); //iterator to be used for searching for min/max x/y/z
473  int extremeSix[] = {*exIt, *exIt, *exIt, *exIt, *exIt, *exIt}; //nodes with minimumX, maxX, minY ...
474  exIt++;
475  for(; exIt != aggNodes.end(); exIt++) {
476  Iter it = exIt;
477  if(xCoords[*it] < xCoords[extremeSix[0]] ||
478  (xCoords[*it] == xCoords[extremeSix[0]] && yCoords[*it] < yCoords[extremeSix[0]]) ||
479  (xCoords[*it] == xCoords[extremeSix[0]] && yCoords[*it] == yCoords[extremeSix[0]] && zCoords[*it] < zCoords[extremeSix[0]]))
480  extremeSix[0] = *it;
481  if(xCoords[*it] > xCoords[extremeSix[1]] ||
482  (xCoords[*it] == xCoords[extremeSix[1]] && yCoords[*it] > yCoords[extremeSix[1]]) ||
483  (xCoords[*it] == xCoords[extremeSix[1]] && yCoords[*it] == yCoords[extremeSix[1]] && zCoords[*it] > zCoords[extremeSix[1]]))
484  extremeSix[1] = *it;
485  if(yCoords[*it] < yCoords[extremeSix[2]] ||
486  (yCoords[*it] == yCoords[extremeSix[2]] && zCoords[*it] < zCoords[extremeSix[2]]) ||
487  (yCoords[*it] == yCoords[extremeSix[2]] && zCoords[*it] == zCoords[extremeSix[2]] && xCoords[*it] < xCoords[extremeSix[2]]))
488  extremeSix[2] = *it;
489  if(yCoords[*it] > yCoords[extremeSix[3]] ||
490  (yCoords[*it] == yCoords[extremeSix[3]] && zCoords[*it] > zCoords[extremeSix[3]]) ||
491  (yCoords[*it] == yCoords[extremeSix[3]] && zCoords[*it] == zCoords[extremeSix[3]] && xCoords[*it] > xCoords[extremeSix[3]]))
492  extremeSix[3] = *it;
493  if(zCoords[*it] < zCoords[extremeSix[4]] ||
494  (zCoords[*it] == zCoords[extremeSix[4]] && xCoords[*it] < xCoords[extremeSix[4]]) ||
495  (zCoords[*it] == zCoords[extremeSix[4]] && xCoords[*it] == xCoords[extremeSix[4]] && yCoords[*it] < yCoords[extremeSix[4]]))
496  extremeSix[4] = *it;
497  if(zCoords[*it] > zCoords[extremeSix[5]] ||
498  (zCoords[*it] == zCoords[extremeSix[5]] && xCoords[*it] > xCoords[extremeSix[5]]) ||
499  (zCoords[*it] == zCoords[extremeSix[5]] && xCoords[*it] == xCoords[extremeSix[5]] && yCoords[*it] > zCoords[extremeSix[5]]))
500  extremeSix[5] = *it;
501  }
502  myVec3 extremeVectors[6];
503  for(int i = 0; i < 6; i++) {
504  myVec3 thisExtremeVec(xCoords[extremeSix[i]], yCoords[extremeSix[i]], zCoords[extremeSix[i]]);
505  extremeVectors[i] = thisExtremeVec;
506  }
507  double maxDist = 0;
508  int base1 = 0; //ints from 0-5: which pair out of the 6 extreme points are the most distant? (indices in extremeSix and extremeVectors)
509  int base2 = 0;
510  for(int i = 0; i < 5; i++) {
511  for(int j = i + 1; j < 6; j++) {
512  double thisDist = distance(extremeVectors[i], extremeVectors[j]);
513  if(thisDist > maxDist) {
514  maxDist = thisDist;
515  base1 = i;
516  base2 = j;
517  }
518  }
519  }
520  std::list<myTriangle> hullBuilding; //each Triangle is a triplet of nodes (int IDs) that form a triangle
521  //remove base1 and base2 iters from aggNodes, they are known to be in the hull
522  aggNodes.remove(extremeSix[base1]);
523  aggNodes.remove(extremeSix[base2]);
524  //extremeSix[base1] and [base2] still have the myVec3 representation
525  myTriangle tri;
526  tri.v1 = extremeSix[base1];
527  tri.v2 = extremeSix[base2];
528  //Now find the point that is furthest away from the line between base1 and base2
529  maxDist = 0;
530  //need the vectors to do "quadruple product" formula
531  myVec3 b1 = extremeVectors[base1];
532  myVec3 b2 = extremeVectors[base2];
533  Iter thirdNode;
534  for(Iter node = aggNodes.begin(); node != aggNodes.end(); node++) {
535  myVec3 nodePos(xCoords[*node], yCoords[*node], zCoords[*node]);
536  double dist = mymagnitude(crossProduct(vecSubtract(nodePos, b1), vecSubtract(nodePos, b2))) / mymagnitude(vecSubtract(b2, b1));
537  if(dist > maxDist) {
538  maxDist = dist;
539  thirdNode = node;
540  }
541  }
542  //Now know the last node in the first triangle
543  tri.v3 = *thirdNode;
544  hullBuilding.push_back(tri);
545  myVec3 b3(xCoords[*thirdNode], yCoords[*thirdNode], zCoords[*thirdNode]);
546  aggNodes.erase(thirdNode);
547  //Find the fourth node (most distant from triangle) to form tetrahedron
548  maxDist = 0;
549  int fourthVertex = -1;
550  for(Iter node = aggNodes.begin(); node != aggNodes.end(); node++) {
551  myVec3 thisNode(xCoords[*node], yCoords[*node], zCoords[*node]);
552  double nodeDist = pointDistFromTri(thisNode, b1, b2, b3);
553  if(nodeDist > maxDist) {
554  maxDist = nodeDist;
555  fourthVertex = *node;
556  }
557  }
558  aggNodes.remove(fourthVertex);
559  myVec3 b4(xCoords[fourthVertex], yCoords[fourthVertex], zCoords[fourthVertex]);
560  //Add three new triangles to hullBuilding to form the first tetrahedron
561  //use tri to hold the triangle info temporarily before being added to list
562  tri = hullBuilding.front();
563  tri.v1 = fourthVertex;
564  hullBuilding.push_back(tri);
565  tri = hullBuilding.front();
566  tri.v2 = fourthVertex;
567  hullBuilding.push_back(tri);
568  tri = hullBuilding.front();
569  tri.v3 = fourthVertex;
570  hullBuilding.push_back(tri);
571  //now orient all four triangles so that the vertices are oriented clockwise (so getNorm_ points outward for each)
572  myVec3 barycenter((b1.x + b2.x + b3.x + b4.x) / 4.0, (b1.y + b2.y + b3.y + b4.y) / 4.0, (b1.z + b2.z + b3.z + b4.z) / 4.0);
573  for(std::list<myTriangle>::iterator tetTri = hullBuilding.begin(); tetTri != hullBuilding.end(); tetTri++) {
574  myVec3 triVert1(xCoords[tetTri->v1], yCoords[tetTri->v1], zCoords[tetTri->v1]);
575  myVec3 triVert2(xCoords[tetTri->v2], yCoords[tetTri->v2], zCoords[tetTri->v2]);
576  myVec3 triVert3(xCoords[tetTri->v3], yCoords[tetTri->v3], zCoords[tetTri->v3]);
577  myVec3 trinorm = getNorm(triVert1, triVert2, triVert3);
578  myVec3 ptInPlane = tetTri == hullBuilding.begin() ? b1 : b4; //first triangle definitely has b1 in it, other three definitely have b4
579  if(isInFront(barycenter, ptInPlane, trinorm)) {
580  //don't want the faces of the tetrahedron to face inwards (towards barycenter) so reverse orientation
581  //by swapping two vertices
582  int temp = tetTri->v1;
583  tetTri->v1 = tetTri->v2;
584  tetTri->v2 = temp;
585  }
586  }
587  //now, have starting polyhedron in hullBuilding (all faces are facing outwards according to getNorm_) and remaining nodes to process are in aggNodes
588  //recursively, for each triangle, make a list of the points that are 'in front' of the triangle. Find the point with the maximum distance from the triangle.
589  //Add three new triangles, each sharing one edge with the original triangle but now with the most distant point as a vertex. Remove the most distant point from
590  //the list of all points that need to be processed. Also from that list remove all points that are in front of the original triangle but not in front of all three
591  //new triangles, since they are now enclosed in the hull.
592  //Construct point lists for each face of the tetrahedron individually.
593  myVec3 trinorms[4]; //normals to the four tetrahedron faces, now oriented outwards
594  int index = 0;
595  for(std::list<myTriangle>::iterator tetTri = hullBuilding.begin(); tetTri != hullBuilding.end(); tetTri++) {
596  myVec3 triVert1(xCoords[tetTri->v1], yCoords[tetTri->v1], zCoords[tetTri->v1]);
597  myVec3 triVert2(xCoords[tetTri->v2], yCoords[tetTri->v2], zCoords[tetTri->v2]);
598  myVec3 triVert3(xCoords[tetTri->v3], yCoords[tetTri->v3], zCoords[tetTri->v3]);
599  trinorms[index] = getNorm(triVert1, triVert2, triVert3);
600  index++;
601  }
602  std::list<int> startPoints1;
603  std::list<int> startPoints2;
604  std::list<int> startPoints3;
605  std::list<int> startPoints4;
606  //scope this so that 'point' is not in function scope
607  {
608  Iter point = aggNodes.begin();
609  while(!aggNodes.empty()) //this removes points one at a time as they are put in startPointsN or are already done
610  {
611  myVec3 pointVec(xCoords[*point], yCoords[*point], zCoords[*point]);
612  //Note: Because of the way the tetrahedron faces are constructed above,
613  //face 1 definitely contains b1 and faces 2-4 definitely contain b4.
614  if(isInFront(pointVec, b1, trinorms[0])) {
615  startPoints1.push_back(*point);
616  point = aggNodes.erase(point);
617  } else if(isInFront(pointVec, b4, trinorms[1])) {
618  startPoints2.push_back(*point);
619  point = aggNodes.erase(point);
620  } else if(isInFront(pointVec, b4, trinorms[2])) {
621  startPoints3.push_back(*point);
622  point = aggNodes.erase(point);
623  } else if(isInFront(pointVec, b4, trinorms[3])) {
624  startPoints4.push_back(*point);
625  point = aggNodes.erase(point);
626  } else {
627  point = aggNodes.erase(point); //points here are already inside tetrahedron.
628  }
629  }
630  //Call processTriangle for each triangle in the initial tetrahedron, one at a time.
631  }
632  typedef std::list<myTriangle>::iterator TriIter;
633  TriIter firstTri = hullBuilding.begin();
634  myTriangle start1 = *firstTri;
635  firstTri++;
636  myTriangle start2 = *firstTri;
637  firstTri++;
638  myTriangle start3 = *firstTri;
639  firstTri++;
640  myTriangle start4 = *firstTri;
641  //kick off depth-first recursive filling of hullBuilding list with all triangles in the convex hull
642  if(!startPoints1.empty())
643  processTriangle(hullBuilding, start1, startPoints1, barycenter, xCoords, yCoords, zCoords);
644  if(!startPoints2.empty())
645  processTriangle(hullBuilding, start2, startPoints2, barycenter, xCoords, yCoords, zCoords);
646  if(!startPoints3.empty())
647  processTriangle(hullBuilding, start3, startPoints3, barycenter, xCoords, yCoords, zCoords);
648  if(!startPoints4.empty())
649  processTriangle(hullBuilding, start4, startPoints4, barycenter, xCoords, yCoords, zCoords);
650  //hullBuilding now has all triangles that make up this hull.
651  //Dump hullBuilding info into the list of all triangles for the scene.
652  vertices.reserve(vertices.size() + 3 * hullBuilding.size());
653  for(TriIter hullTri = hullBuilding.begin(); hullTri != hullBuilding.end(); hullTri++) {
654  vertices.push_back(hullTri->v1);
655  vertices.push_back(hullTri->v2);
656  vertices.push_back(hullTri->v3);
657  geomSizes.push_back(3);
658  }
659  }
660  }
661 
662 #ifdef HAVE_MUELU_CGAL
663  template<class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
664  void VisualizationHelpers<Scalar, LocalOrdinal, GlobalOrdinal, Node>::doCGALConvexHulls3D(std::vector<int>& vertices, std::vector<int>& geomSizes, LO numLocalAggs, LO numFineNodes, const std::vector<bool>& isRoot, const ArrayRCP<LO>& vertex2AggId, const Teuchos::ArrayRCP<const typename Teuchos::ScalarTraits<Scalar>::coordinateType>& xCoords, const Teuchos::ArrayRCP<const typename Teuchos::ScalarTraits<Scalar>::coordinateType>& yCoords, const Teuchos::ArrayRCP<const typename Teuchos::ScalarTraits<Scalar>::coordinateType>& zCoords) {
665 
666  typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
667  typedef K::Point_3 Point_3;
668  typedef CGAL::Polyhedron_3<K> Polyhedron_3;
669  typedef std::vector<int>::iterator Iter;
670  for(int agg = 0; agg < numLocalAggs; agg++) {
671  std::vector<int> aggNodes;
672  std::vector<Point_3> aggPoints;
673  for(int i = 0; i < numFineNodes; i++) {
674  if(vertex2AggId[i] == agg) {
675  Point_3 p(xCoords[i], yCoords[i], zCoords[i]);
676  aggPoints.push_back(p);
677  aggNodes.push_back(i);
678  }
679  }
680  //First, check anomalous cases
682  "CoarseningVisualization::doCGALConvexHulls3D: aggregate contains zero nodes!");
683  if(aggNodes.size() == 1) {
684  vertices.push_back(aggNodes.front());
685  geomSizes.push_back(1);
686  continue;
687  } else if(aggNodes.size() == 2) {
688  vertices.push_back(aggNodes.front());
689  vertices.push_back(aggNodes.back());
690  geomSizes.push_back(2);
691  continue;
692  }
693  //check for collinearity
694  bool areCollinear = true;
695  {
696  Iter it = aggNodes.begin();
697  myVec3 firstVec(xCoords[*it], yCoords[*it], zCoords[*it]);
698  myVec3 comp;
699  {
700  it++;
701  myVec3 secondVec(xCoords[*it], yCoords[*it], zCoords[*it]); //cross this with other vectors to compare
702  comp = vecSubtract(secondVec, firstVec);
703  it++;
704  }
705  for(; it != aggNodes.end(); it++) {
706  myVec3 thisVec(xCoords[*it], yCoords[*it], zCoords[*it]);
707  myVec3 cross = crossProduct(vecSubtract(thisVec, firstVec), comp);
708  if(mymagnitude(cross) > 1e-8) {
709  areCollinear = false;
710  break;
711  }
712  }
713  }
714  if(areCollinear)
715  {
716  //find the endpoints of segment describing all the points
717  //compare x, if tie compare y, if tie compare z
718  Iter min = aggNodes.begin();
719  Iter max = aggNodes.begin();
720  Iter it = ++aggNodes.begin();
721  for(; it != aggNodes.end(); it++) {
722  if(xCoords[*it] < xCoords[*min]) min = it;
723  else if(xCoords[*it] == xCoords[*min]) {
724  if(yCoords[*it] < yCoords[*min]) min = it;
725  else if(yCoords[*it] == yCoords[*min]) {
726  if(zCoords[*it] < zCoords[*min]) min = it;
727  }
728  }
729  if(xCoords[*it] > xCoords[*max]) max = it;
730  else if(xCoords[*it] == xCoords[*max]) {
731  if(yCoords[*it] > yCoords[*max]) max = it;
732  else if(yCoords[*it] == yCoords[*max]) {
733  if(zCoords[*it] > zCoords[*max])
734  max = it;
735  }
736  }
737  }
738  vertices.push_back(*min);
739  vertices.push_back(*max);
740  geomSizes.push_back(2);
741  continue;
742  }
743  // do not handle coplanar or general case here. Just let's use CGAL
744  {
745  Polyhedron_3 result;
746  CGAL::convex_hull_3( aggPoints.begin(), aggPoints.end(), result);
747 
748  // loop over all facets
749  Polyhedron_3::Facet_iterator fi;
750  for (fi = result.facets_begin(); fi != result.facets_end(); fi++) {
751  int cntVertInAgg = 0;
752  Polyhedron_3::Halfedge_around_facet_const_circulator hit = fi->facet_begin();
753  do {
754  const Point_3 & pp = hit->vertex()->point();
755  // loop over all aggregate nodes and find corresponding node id
756  for(size_t l = 0; l < aggNodes.size(); l++)
757  {
758  if(fabs(pp.x() - xCoords[aggNodes[l]]) < 1e-12 &&
759  fabs(pp.y() - yCoords[aggNodes[l]]) < 1e-12 &&
760  fabs(pp.z() - zCoords[aggNodes[l]]) < 1e-12)
761  {
762  vertices.push_back(aggNodes[l]);
763  cntVertInAgg++;
764  break;
765  }
766  }
767  } while (++hit != fi->facet_begin());
768  geomSizes.push_back(cntVertInAgg);
769  }
770  }
771  }
772 
773  }
774 #endif
775 
776  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
780 
781  std::vector<std::pair<int, int> > vert1; //vertices (node indices)
782 
784  for(LocalOrdinal locRow = 0; locRow < LocalOrdinal(G->GetNodeNumVertices()); locRow++) {
785  neighbors = G->getNeighborVertices(locRow);
786  //Add those local indices (columns) to the list of connections (which are pairs of the form (localM, localN))
787  for(int gEdge = 0; gEdge < int(neighbors.size()); ++gEdge) {
788  vert1.push_back(std::pair<int, int>(locRow, neighbors[gEdge]));
789  }
790  }
791  for(size_t i = 0; i < vert1.size(); i ++) {
792  if(vert1[i].first > vert1[i].second) {
793  int temp = vert1[i].first;
794  vert1[i].first = vert1[i].second;
795  vert1[i].second = temp;
796  }
797  }
798  std::sort(vert1.begin(), vert1.end());
799  std::vector<std::pair<int, int> >::iterator newEnd = unique(vert1.begin(), vert1.end()); //remove duplicate edges
800  vert1.erase(newEnd, vert1.end());
801  //std::vector<int> points1;
802  vertices.reserve(2 * vert1.size());
803  geomSizes.reserve(vert1.size());
804  for(size_t i = 0; i < vert1.size(); i++) {
805  vertices.push_back(vert1[i].first);
806  vertices.push_back(vert1[i].second);
807  geomSizes.push_back(2);
808  }
809  }
810 
811  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
813  {
814  const double ccw_zero_threshold=1e-8;
815  double val = (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x);
816  return (val > ccw_zero_threshold) ? 1 : ( (val < -ccw_zero_threshold) ? -1 : 0);
817  }
818 
819  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
821  {
822  return myVec3(v1.y * v2.z - v1.z * v2.y, v1.z * v2.x - v1.x * v2.z, v1.x * v2.y - v1.y * v2.x);
823  }
824 
825  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
827  {
828  return v1.x * v2.x + v1.y * v2.y;
829  }
830 
831  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
833  {
834  return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z;
835  }
836 
837  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
839  {
840  myVec3 rel(point.x - inPlane.x, point.y - inPlane.y, point.z - inPlane.z); //position of the point relative to the plane
841  return dotProduct(rel, n) > 1e-12 ? true : false;
842  }
843 
844  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
846  {
847  return sqrt(dotProduct(vec, vec));
848  }
849 
850  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
852  {
853  return sqrt(dotProduct(vec, vec));
854  }
855 
856  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
858  {
859  return mymagnitude(vecSubtract(p1, p2));
860  }
861 
862 
863  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
865  {
866  return mymagnitude(vecSubtract(p1, p2));
867  }
868 
869  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
871  {
872  return myVec2(v1.x - v2.x, v1.y - v2.y);
873  }
874 
875  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
877  {
878  return myVec3(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z);
879  }
880 
881  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
882  myVec2 VisualizationHelpers<Scalar, LocalOrdinal, GlobalOrdinal, Node>::getNorm(myVec2 v) //"normal" to a 2D vector - just rotate 90 degrees to left
883  {
884  return myVec2(v.y, -v.x);
885  }
886 
887  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
888  myVec3 VisualizationHelpers<Scalar, LocalOrdinal, GlobalOrdinal, Node>::getNorm(myVec3 v1, myVec3 v2, myVec3 v3) //normal to face of triangle (will be outward rel. to polyhedron) (v1, v2, v3 are in CCW order when normal is toward viewpoint)
889  {
890  return crossProduct(vecSubtract(v2, v1), vecSubtract(v3, v1));
891  }
892 
893  //get minimum distance from 'point' to plane containing v1, v2, v3 (or the triangle with v1, v2, v3 as vertices)
894  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
896  {
897  using namespace std;
898  myVec3 norm = getNorm(v1, v2, v3);
899  //must normalize the normal vector
900  double normScl = mymagnitude(norm);
901  double rv = 0.0;
902  if (normScl > 1e-8) {
903  norm.x /= normScl;
904  norm.y /= normScl;
905  norm.z /= normScl;
906  rv = fabs(dotProduct(norm, vecSubtract(point, v1)));
907  } else {
908  // triangle is degenerated
909  myVec3 test1 = vecSubtract(v3, v1);
910  myVec3 test2 = vecSubtract(v2, v1);
911  bool useTest1 = mymagnitude(test1) > 0.0 ? true : false;
912  bool useTest2 = mymagnitude(test2) > 0.0 ? true : false;
913  if(useTest1 == true) {
914  double normScl1 = mymagnitude(test1);
915  test1.x /= normScl1;
916  test1.y /= normScl1;
917  test1.z /= normScl1;
918  rv = fabs(dotProduct(test1, vecSubtract(point, v1)));
919  } else if (useTest2 == true) {
920  double normScl2 = mymagnitude(test2);
921  test2.x /= normScl2;
922  test2.y /= normScl2;
923  test2.z /= normScl2;
924  rv = fabs(dotProduct(test2, vecSubtract(point, v1)));
925  } else {
927  "VisualizationHelpers::pointDistFromTri: Could not determine the distance of a point to a triangle.");
928  }
929 
930  }
931  return rv;
932  }
933 
934  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
935  std::vector<myTriangle> VisualizationHelpers<Scalar, LocalOrdinal, GlobalOrdinal, Node>::processTriangle(std::list<myTriangle>& tris, myTriangle tri, std::list<int>& pointsInFront, myVec3& barycenter, const Teuchos::ArrayRCP<const typename Teuchos::ScalarTraits<Scalar>::coordinateType>& xCoords, const Teuchos::ArrayRCP<const typename Teuchos::ScalarTraits<Scalar>::coordinateType>& yCoords, const Teuchos::ArrayRCP<const typename Teuchos::ScalarTraits<Scalar>::coordinateType>& zCoords) {
936  //*tri is in the tris list, and is the triangle to process here. tris is a complete list of all triangles in the hull so far. pointsInFront is only a list of the nodes in front of tri. Need coords also.
937  //precondition: each triangle is already oriented so that getNorm_(v1, v2, v3) points outward (away from interior of hull)
938  //First find the point furthest from triangle.
939  using namespace std;
940  typedef std::list<int>::iterator Iter;
941  typedef std::list<myTriangle>::iterator TriIter;
942  typedef list<pair<int, int> >::iterator EdgeIter;
943  double maxDist = 0;
944  //Need vector representations of triangle's vertices
945  myVec3 v1(xCoords[tri.v1], yCoords[tri.v1], zCoords[tri.v1]);
946  myVec3 v2(xCoords[tri.v2], yCoords[tri.v2], zCoords[tri.v2]);
947  myVec3 v3(xCoords[tri.v3], yCoords[tri.v3], zCoords[tri.v3]);
948  myVec3 farPointVec; //useful to have both the point's coordinates and it's position in the list
949  Iter farPoint = pointsInFront.begin();
950  for(Iter point = pointsInFront.begin(); point != pointsInFront.end(); point++)
951  {
952  myVec3 pointVec(xCoords[*point], yCoords[*point], zCoords[*point]);
953  double dist = pointDistFromTri(pointVec, v1, v2, v3);
954  if(dist > maxDist)
955  {
956  dist = maxDist;
957  farPointVec = pointVec;
958  farPoint = point;
959  }
960  }
961  //Find all the triangles that the point is in front of (can be more than 1)
962  //At the same time, remove them from tris, as every one will be replaced later
963  vector<myTriangle> visible; //use a list of iterators so that the underlying object is still in tris
964  for(TriIter it = tris.begin(); it != tris.end();)
965  {
966  myVec3 vec1(xCoords[it->v1], yCoords[it->v1], zCoords[it->v1]);
967  myVec3 vec2(xCoords[it->v2], yCoords[it->v2], zCoords[it->v2]);
968  myVec3 vec3(xCoords[it->v3], yCoords[it->v3], zCoords[it->v3]);
969  myVec3 norm = getNorm(vec1, vec2, vec3);
970  if(isInFront(farPointVec, vec1, norm))
971  {
972  visible.push_back(*it);
973  it = tris.erase(it);
974  }
975  else
976  it++;
977  }
978  //Figure out what triangles need to be destroyed/created
979  //First create a list of edges (as std::pair<int, int>, where the two ints are the node endpoints)
980  list<pair<int, int> > horizon;
981  //For each triangle, add edges to the list iff the edge only appears once in the set of all
982  //Have members of horizon have the lower node # first, and the higher one second
983  for(vector<myTriangle>::iterator it = visible.begin(); it != visible.end(); it++)
984  {
985  pair<int, int> e1(it->v1, it->v2);
986  pair<int, int> e2(it->v2, it->v3);
987  pair<int, int> e3(it->v1, it->v3);
988  //"sort" the pair values
989  if(e1.first > e1.second)
990  {
991  int temp = e1.first;
992  e1.first = e1.second;
993  e1.second = temp;
994  }
995  if(e2.first > e2.second)
996  {
997  int temp = e2.first;
998  e2.first = e2.second;
999  e2.second = temp;
1000  }
1001  if(e3.first > e3.second)
1002  {
1003  int temp = e3.first;
1004  e3.first = e3.second;
1005  e3.second = temp;
1006  }
1007  horizon.push_back(e1);
1008  horizon.push_back(e2);
1009  horizon.push_back(e3);
1010  }
1011  //sort based on lower node first, then higher node (lexicographical ordering built in to pair)
1012  horizon.sort();
1013  //Remove all edges from horizon, except those that appear exactly once
1014  {
1015  EdgeIter it = horizon.begin();
1016  while(it != horizon.end())
1017  {
1018  int occur = count(horizon.begin(), horizon.end(), *it);
1019  if(occur > 1)
1020  {
1021  pair<int, int> removeVal = *it;
1022  while(removeVal == *it && !(it == horizon.end()))
1023  it = horizon.erase(it);
1024  }
1025  else
1026  it++;
1027  }
1028  }
1029  //Now make a list of new triangles being created, each of which take 2 vertices from an edge and one from farPoint
1030  list<myTriangle> newTris;
1031  for(EdgeIter it = horizon.begin(); it != horizon.end(); it++)
1032  {
1033  myTriangle t(it->first, it->second, *farPoint);
1034  newTris.push_back(t);
1035  }
1036  //Ensure every new triangle is oriented outwards, using the barycenter of the initial tetrahedron
1037  vector<myTriangle> trisToProcess;
1038  vector<list<int> > newFrontPoints;
1039  for(TriIter it = newTris.begin(); it != newTris.end(); it++)
1040  {
1041  myVec3 t1(xCoords[it->v1], yCoords[it->v1], zCoords[it->v1]);
1042  myVec3 t2(xCoords[it->v2], yCoords[it->v2], zCoords[it->v2]);
1043  myVec3 t3(xCoords[it->v3], yCoords[it->v3], zCoords[it->v3]);
1044  if(isInFront(barycenter, t1, getNorm(t1, t2, t3)))
1045  {
1046  //need to swap two vertices to flip orientation of triangle
1047  int temp = it->v1;
1048  myVec3 tempVec = t1;
1049  it->v1 = it->v2;
1050  t1 = t2;
1051  it->v2 = temp;
1052  t2 = tempVec;
1053  }
1054  myVec3 outwardNorm = getNorm(t1, t2, t3); //now definitely points outwards
1055  //Add the triangle to tris
1056  tris.push_back(*it);
1057  trisToProcess.push_back(tris.back());
1058  //Make a list of the points that are in front of nextToProcess, to be passed in for processing
1059  list<int> newInFront;
1060  for(Iter point = pointsInFront.begin(); point != pointsInFront.end();)
1061  {
1062  myVec3 pointVec(xCoords[*point], yCoords[*point], zCoords[*point]);
1063  if(isInFront(pointVec, t1, outwardNorm))
1064  {
1065  newInFront.push_back(*point);
1066  point = pointsInFront.erase(point);
1067  }
1068  else
1069  point++;
1070  }
1071  newFrontPoints.push_back(newInFront);
1072  }
1073  vector<myTriangle> allRemoved; //list of all invalid iterators that were erased by calls to processmyTriangle below
1074  for(int i = 0; i < int(trisToProcess.size()); i++)
1075  {
1076  if(!newFrontPoints[i].empty())
1077  {
1078  //Comparing the 'triangle to process' to the one for this call prevents infinite recursion/stack overflow.
1079  //TODO: Why was it doing that? Rounding error? Make more robust fix. But this does work for the time being.
1080  if(find(allRemoved.begin(), allRemoved.end(), trisToProcess[i]) == allRemoved.end() && !(trisToProcess[i] == tri))
1081  {
1082  vector<myTriangle> removedList = processTriangle(tris, trisToProcess[i], newFrontPoints[i], barycenter, xCoords, yCoords, zCoords);
1083  for(int j = 0; j < int(removedList.size()); j++)
1084  allRemoved.push_back(removedList[j]);
1085  }
1086  }
1087  }
1088  return visible;
1089  }
1090 
1091  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1092  std::vector<int> VisualizationHelpers<Scalar, LocalOrdinal, GlobalOrdinal, Node>::giftWrap(std::vector<myVec2>& points, std::vector<int>& nodes, const Teuchos::ArrayRCP<const typename Teuchos::ScalarTraits<Scalar>::coordinateType> & xCoords, const Teuchos::ArrayRCP<const typename Teuchos::ScalarTraits<Scalar>::coordinateType> & yCoords) {
1094  "CoarseningVisualization::giftWrap: Gift wrap algorithm input has to have at least 3 points!");
1095 
1096 #if 1 // TAW's version to determine "minimal" node
1097  // determine minimal x and y coordinates
1098  double min_x =points[0].x;
1099  double min_y =points[0].y;
1100  for(std::vector<int>::iterator it = nodes.begin(); it != nodes.end(); it++) {
1101  int i = it - nodes.begin();
1102  if(points[i].x < min_x) min_x = points[i].x;
1103  if(points[i].y < min_y) min_y = points[i].y;
1104  }
1105  // create dummy min coordinates
1106  min_x -= 1.0;
1107  min_y -= 1.0;
1108  myVec2 dummy_min(min_x, min_y);
1109 
1110  // loop over all nodes and determine nodes with minimal distance to (min_x, min_y)
1111  std::vector<int> hull;
1112  myVec2 min = points[0];
1113  double mindist = distance(min,dummy_min);
1114  std::vector<int>::iterator minNode = nodes.begin();
1115  for(std::vector<int>::iterator it = nodes.begin(); it != nodes.end(); it++) {
1116  int i = it - nodes.begin();
1117  if(distance(points[i],dummy_min) < mindist) {
1118  mindist = distance(points[i],dummy_min);
1119  min = points[i];
1120  minNode = it;
1121  }
1122  }
1123  hull.push_back(*minNode);
1124 #else // Brian's code
1125  std::vector<int> hull;
1126  std::vector<int>::iterator minNode = nodes.begin();
1127  myVec2 min = points[0];
1128  for(std::vector<int>::iterator it = nodes.begin(); it != nodes.end(); it++)
1129  {
1130  int i = it - nodes.begin();
1131  if(points[i].x < min.x || (fabs(points[i].x - min.x) < 1e-10 && points[i].y < min.y))
1132  {
1133  min = points[i];
1134  minNode = it;
1135  }
1136  }
1137  hull.push_back(*minNode);
1138 #endif
1139 
1140  bool includeMin = false;
1141  //int debug_it = 0;
1142  while(1)
1143  {
1144  std::vector<int>::iterator leftMost = nodes.begin();
1145  if(!includeMin && leftMost == minNode)
1146  {
1147  leftMost++;
1148  }
1149  std::vector<int>::iterator it = leftMost;
1150  it++;
1151  for(; it != nodes.end(); it++)
1152  {
1153  if(it == minNode && !includeMin) //don't compare to min on very first sweep
1154  continue;
1155  if(*it == hull.back())
1156  continue;
1157  //see if it is in front of line containing nodes thisHull.back() and leftMost
1158  //first get the left normal of leftMost - thisHull.back() (<dy, -dx>)
1159  myVec2 leftMostVec = points[leftMost - nodes.begin()];
1160  myVec2 lastVec(xCoords[hull.back()], yCoords[hull.back()]);
1161  myVec2 testNorm = getNorm(vecSubtract(leftMostVec, lastVec));
1162  //now dot testNorm with *it - leftMost. If dot is positive, leftMost becomes it. If dot is zero, take one further from thisHull.back().
1163  myVec2 itVec(xCoords[*it], yCoords[*it]);
1164  double dotProd = dotProduct(testNorm, vecSubtract(itVec, lastVec));
1165  if(-1e-8 < dotProd && dotProd < 1e-8)
1166  {
1167  //thisHull.back(), it and leftMost are collinear.
1168  //Just sum the differences in x and differences in y for each and compare to get further one, don't need distance formula
1169  myVec2 itDist = vecSubtract(itVec, lastVec);
1170  myVec2 leftMostDist = vecSubtract(leftMostVec, lastVec);
1171  if(fabs(itDist.x) + fabs(itDist.y) > fabs(leftMostDist.x) + fabs(leftMostDist.y)) {
1172  leftMost = it;
1173  }
1174  }
1175  else if(dotProd > 0) {
1176  leftMost = it;
1177 
1178  }
1179  }
1180  //if leftMost is min, then the loop is complete.
1181  if(*leftMost == *minNode)
1182  break;
1183  hull.push_back(*leftMost);
1184  includeMin = true; //have found second point (the one after min) so now include min in the searches
1185  //debug_it ++;
1186  //if(debug_it > 100) exit(0); //break;
1187  }
1188  return hull;
1189  }
1190 
1191  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1192  std::vector<int> VisualizationHelpers<Scalar, LocalOrdinal, GlobalOrdinal, Node>::makeUnique(std::vector<int>& vertices) const
1193  {
1194  using namespace std;
1195  vector<int> uniqueNodes = vertices;
1196  sort(uniqueNodes.begin(), uniqueNodes.end());
1197  vector<int>::iterator newUniqueFineEnd = unique(uniqueNodes.begin(), uniqueNodes.end());
1198  uniqueNodes.erase(newUniqueFineEnd, uniqueNodes.end());
1199  //uniqueNodes is now a sorted list of the nodes whose info actually goes in file
1200  //Now replace values in vertices with locations of the old values in uniqueFine
1201  for(int i = 0; i < int(vertices.size()); i++)
1202  {
1203  int lo = 0;
1204  int hi = uniqueNodes.size() - 1;
1205  int mid = 0;
1206  int search = vertices[i];
1207  while(lo <= hi)
1208  {
1209  mid = lo + (hi - lo) / 2;
1210  if(uniqueNodes[mid] == search)
1211  break;
1212  else if(uniqueNodes[mid] > search)
1213  hi = mid - 1;
1214  else
1215  lo = mid + 1;
1216  }
1217  if(uniqueNodes[mid] != search)
1218  throw runtime_error("Issue in makeUnique_() - a point wasn't found in list.");
1219  vertices[i] = mid;
1220  }
1221  return uniqueNodes;
1222  }
1223 
1224  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1225  std::string VisualizationHelpers<Scalar, LocalOrdinal, GlobalOrdinal, Node>::replaceAll(std::string result, const std::string& replaceWhat, const std::string& replaceWithWhat) const {
1226  while(1) {
1227  const int pos = result.find(replaceWhat);
1228  if (pos == -1)
1229  break;
1230  result.replace(pos, replaceWhat.size(), replaceWithWhat);
1231  }
1232  return result;
1233  }
1234 
1235  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1236  std::string VisualizationHelpers<Scalar, LocalOrdinal, GlobalOrdinal, Node>::getFileName(int numProcs, int myRank, int level, const Teuchos::ParameterList & pL) const {
1237  std::string filenameToWrite = getBaseFileName(numProcs, level, pL);
1238  filenameToWrite = this->replaceAll(filenameToWrite, "%PROCID", toString(myRank));
1239  return filenameToWrite;
1240  }
1241 
1242  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1244  std::string filenameToWrite = pL.get<std::string>("visualization: output filename");
1245  int timeStep = pL.get<int>("visualization: output file: time step");
1246  int iter = pL.get<int>("visualization: output file: iter");
1247 
1248  if(filenameToWrite.rfind(".vtu") == std::string::npos)
1249  filenameToWrite.append(".vtu");
1250  if(numProcs > 1 && filenameToWrite.rfind("%PROCID") == std::string::npos) //filename can't be identical between processsors in parallel problem
1251  filenameToWrite.insert(filenameToWrite.rfind(".vtu"), "-proc%PROCID");
1252 
1253  filenameToWrite = this->replaceAll(filenameToWrite, "%LEVELID", toString(level));
1254  filenameToWrite = this->replaceAll(filenameToWrite, "%TIMESTEP", toString(timeStep));
1255  filenameToWrite = this->replaceAll(filenameToWrite, "%ITER", toString(iter));
1256  return filenameToWrite;
1257  }
1258 
1259  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1260  std::string VisualizationHelpers<Scalar, LocalOrdinal, GlobalOrdinal, Node>::getPVTUFileName(int numProcs, int /* myRank */, int level, const Teuchos::ParameterList & pL) const {
1261  std::string filenameToWrite = getBaseFileName(numProcs, level, pL);
1262  std::string masterStem = filenameToWrite.substr(0, filenameToWrite.rfind(".vtu"));
1263  masterStem = this->replaceAll(masterStem, "%PROCID", "");
1264  std::string pvtuFilename = masterStem + "-master.pvtu";
1265  return pvtuFilename;
1266  }
1267 
1268  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1269  void VisualizationHelpers<Scalar, LocalOrdinal, GlobalOrdinal, Node>::writeFileVTKOpening(std::ofstream & fout, std::vector<int> & uniqueFine, std::vector<int> & geomSizesFine) const {
1270  std::string styleName = "PointCloud"; // TODO adapt this
1271 
1272  std::string indent = " ";
1273  fout << "<!--" << styleName << " Aggregates Visualization-->" << std::endl;
1274  fout << "<VTKFile type=\"UnstructuredGrid\" byte_order=\"LittleEndian\">" << std::endl;
1275  fout << " <UnstructuredGrid>" << std::endl;
1276  fout << " <Piece NumberOfPoints=\"" << uniqueFine.size() << "\" NumberOfCells=\"" << geomSizesFine.size() << "\">" << std::endl;
1277  fout << " <PointData Scalars=\"Node Aggregate Processor\">" << std::endl;
1278  }
1279 
1280  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1281  void VisualizationHelpers<Scalar, LocalOrdinal, GlobalOrdinal, Node>::writeFileVTKNodes(std::ofstream & fout, std::vector<int> & uniqueFine, Teuchos::RCP<const Map> & nodeMap) const {
1282  std::string indent = " ";
1283  fout << " <DataArray type=\"Int32\" Name=\"Node\" format=\"ascii\">" << std::endl;
1284  indent = " ";
1285  bool localIsGlobal = GlobalOrdinal(nodeMap->getGlobalNumElements()) == GlobalOrdinal(nodeMap->getNodeNumElements());
1286  for(size_t i = 0; i < uniqueFine.size(); i++)
1287  {
1288  if(localIsGlobal)
1289  {
1290  fout << uniqueFine[i] << " "; //if all nodes are on this processor, do not map from local to global
1291  }
1292  else
1293  fout << nodeMap->getGlobalElement(uniqueFine[i]) << " ";
1294  if(i % 10 == 9)
1295  fout << std::endl << indent;
1296  }
1297  fout << std::endl;
1298  fout << " </DataArray>" << std::endl;
1299  }
1300 
1301  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1302  void VisualizationHelpers<Scalar, LocalOrdinal, GlobalOrdinal, Node>::writeFileVTKData(std::ofstream & fout, std::vector<int> & uniqueFine, LocalOrdinal myAggOffset, ArrayRCP<LocalOrdinal> & vertex2AggId, int myRank) const {
1303  std::string indent = " ";
1304  fout << " <DataArray type=\"Int32\" Name=\"Aggregate\" format=\"ascii\">" << std::endl;
1305  fout << indent;
1306  for(int i = 0; i < int(uniqueFine.size()); i++)
1307  {
1308  fout << myAggOffset + vertex2AggId[uniqueFine[i]] << " ";
1309  if(i % 10 == 9)
1310  fout << std::endl << indent;
1311  }
1312  fout << std::endl;
1313  fout << " </DataArray>" << std::endl;
1314  fout << " <DataArray type=\"Int32\" Name=\"Processor\" format=\"ascii\">" << std::endl;
1315  fout << indent;
1316  for(int i = 0; i < int(uniqueFine.size()); i++)
1317  {
1318  fout << myRank << " ";
1319  if(i % 20 == 19)
1320  fout << std::endl << indent;
1321  }
1322  fout << std::endl;
1323  fout << " </DataArray>" << std::endl;
1324  fout << " </PointData>" << std::endl;
1325  }
1326 
1327  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1329  std::string indent = " ";
1330  fout << " <Points>" << std::endl;
1331  fout << " <DataArray type=\"Float64\" NumberOfComponents=\"3\" format=\"ascii\">" << std::endl;
1332  fout << indent;
1333  for(int i = 0; i < int(uniqueFine.size()); i++)
1334  {
1335  fout << fx[uniqueFine[i]] << " " << fy[uniqueFine[i]] << " ";
1336  if(dim == 2)
1337  fout << "0 ";
1338  else
1339  fout << fz[uniqueFine[i]] << " ";
1340  if(i % 3 == 2)
1341  fout << std::endl << indent;
1342  }
1343  fout << std::endl;
1344  fout << " </DataArray>" << std::endl;
1345  fout << " </Points>" << std::endl;
1346  }
1347 
1348  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1349  void VisualizationHelpers<Scalar, LocalOrdinal, GlobalOrdinal, Node>::writeFileVTKCells(std::ofstream & fout, std::vector<int> & /* uniqueFine */, std::vector<LocalOrdinal> & vertices, std::vector<LocalOrdinal> & geomSize) const {
1350  std::string indent = " ";
1351  fout << " <Cells>" << std::endl;
1352  fout << " <DataArray type=\"Int32\" Name=\"connectivity\" format=\"ascii\">" << std::endl;
1353  fout << indent;
1354  for(int i = 0; i < int(vertices.size()); i++)
1355  {
1356  fout << vertices[i] << " ";
1357  if(i % 10 == 9)
1358  fout << std::endl << indent;
1359  }
1360  fout << std::endl;
1361  fout << " </DataArray>" << std::endl;
1362  fout << " <DataArray type=\"Int32\" Name=\"offsets\" format=\"ascii\">" << std::endl;
1363  fout << indent;
1364  int accum = 0;
1365  for(int i = 0; i < int(geomSize.size()); i++)
1366  {
1367  accum += geomSize[i];
1368  fout << accum << " ";
1369  if(i % 10 == 9)
1370  fout << std::endl << indent;
1371  }
1372  fout << std::endl;
1373  fout << " </DataArray>" << std::endl;
1374  fout << " <DataArray type=\"Int32\" Name=\"types\" format=\"ascii\">" << std::endl;
1375  fout << indent;
1376  for(int i = 0; i < int(geomSize.size()); i++)
1377  {
1378  switch(geomSize[i])
1379  {
1380  case 1:
1381  fout << "1 "; //Point
1382  break;
1383  case 2:
1384  fout << "3 "; //Line
1385  break;
1386  case 3:
1387  fout << "5 "; //Triangle
1388  break;
1389  default:
1390  fout << "7 "; //Polygon
1391  }
1392  if(i % 30 == 29)
1393  fout << std::endl << indent;
1394  }
1395  fout << std::endl;
1396  fout << " </DataArray>" << std::endl;
1397  fout << " </Cells>" << std::endl;
1398  }
1399 
1400  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1402  fout << " </Piece>" << std::endl;
1403  fout << " </UnstructuredGrid>" << std::endl;
1404  fout << "</VTKFile>" << std::endl;
1405  }
1406 
1407 
1408  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1409  void VisualizationHelpers<Scalar, LocalOrdinal, GlobalOrdinal, Node>::writePVTU(std::ofstream& pvtu, std::string baseFname, int numProcs, bool bFineEdges, bool /* bCoarseEdges */) const {
1410  //If using vtk, filenameToWrite now contains final, correct ***.vtu filename (for the current proc)
1411  //So the root proc will need to use its own filenameToWrite to make a list of the filenames of all other procs to put in
1412  //pvtu file.
1413  pvtu << "<VTKFile type=\"PUnstructuredGrid\" byte_order=\"LittleEndian\">" << std::endl;
1414  pvtu << " <PUnstructuredGrid GhostLevel=\"0\">" << std::endl;
1415  pvtu << " <PPointData Scalars=\"Node Aggregate Processor\">" << std::endl;
1416  pvtu << " <PDataArray type=\"Int32\" Name=\"Node\"/>" << std::endl;
1417  pvtu << " <PDataArray type=\"Int32\" Name=\"Aggregate\"/>" << std::endl;
1418  pvtu << " <PDataArray type=\"Int32\" Name=\"Processor\"/>" << std::endl;
1419  pvtu << " </PPointData>" << std::endl;
1420  pvtu << " <PPoints>" << std::endl;
1421  pvtu << " <PDataArray type=\"Float64\" NumberOfComponents=\"3\"/>" << std::endl;
1422  pvtu << " </PPoints>" << std::endl;
1423  for(int i = 0; i < numProcs; i++) {
1424  //specify the piece for each proc (the replaceAll expression matches what the filenames will be on other procs)
1425  pvtu << " <Piece Source=\"" << replaceAll(baseFname, "%PROCID", toString(i)) << "\"/>" << std::endl;
1426  }
1427  //reference files with graph pieces, if applicable
1428  if(bFineEdges)
1429  {
1430  for(int i = 0; i < numProcs; i++)
1431  {
1432  std::string fn = replaceAll(baseFname, "%PROCID", toString(i));
1433  pvtu << " <Piece Source=\"" << fn.insert(fn.rfind(".vtu"), "-finegraph") << "\"/>" << std::endl;
1434  }
1435  }
1436  /*if(doCoarseGraphEdges_)
1437  {
1438  for(int i = 0; i < numProcs; i++)
1439  {
1440  std::string fn = replaceAll(baseFname, "%PROCID", toString(i));
1441  pvtu << " <Piece Source=\"" << fn.insert(fn.rfind(".vtu"), "-coarsegraph") << "\"/>" << std::endl;
1442  }
1443  }*/
1444  pvtu << " </PUnstructuredGrid>" << std::endl;
1445  pvtu << "</VTKFile>" << std::endl;
1446  pvtu.close();
1447  }
1448 
1449  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1451  try {
1452  std::ofstream color("random-colormap.xml");
1453  color << "<ColorMap name=\"MueLu-Random\" space=\"RGB\">" << std::endl;
1454  //Give -1, -2, -3 distinctive colors (so that the style functions can have constrasted geometry types)
1455  //Do red, orange, yellow to constrast with cool color spectrum for other types
1456  color << " <Point x=\"" << -1 << "\" o=\"1\" r=\"1\" g=\"0\" b=\"0\"/>" << std::endl;
1457  color << " <Point x=\"" << -2 << "\" o=\"1\" r=\"1\" g=\"0.6\" b=\"0\"/>" << std::endl;
1458  color << " <Point x=\"" << -3 << "\" o=\"1\" r=\"1\" g=\"1\" b=\"0\"/>" << std::endl;
1459  srand(time(NULL));
1460  for(int i = 0; i < 5000; i += 4) {
1461  color << " <Point x=\"" << i << "\" o=\"1\" r=\"" << (rand() % 50) / 256.0 << "\" g=\"" << (rand() % 256) / 256.0 << "\" b=\"" << (rand() % 256) / 256.0 << "\"/>" << std::endl;
1462  }
1463  color << "</ColorMap>" << std::endl;
1464  color.close();
1465  }
1466  catch(std::exception& e) {
1468  "VisualizationHelpers::buildColormap: Error while building colormap file: " << e.what());
1469  }
1470  }
1471 
1472 } // namespace MueLu
1473 
1474 #endif /* MUELU_VISUALIZATIONHELPERS_DEF_HPP_ */
static void doPointCloud(std::vector< int > &vertices, std::vector< int > &geomSizes, LO numLocalAggs, LO numFineNodes)
MueLu::DefaultLocalOrdinal LocalOrdinal
std::string toString(const T &what)
Little helper function to convert non-string types to strings.
std::string getPVTUFileName(int numProcs, int myRank, int level, const Teuchos::ParameterList &pL) const
void writeFileVTKOpening(std::ofstream &fout, std::vector< int > &uniqueFine, std::vector< int > &geomSizesFine) const
void writeFileVTKCoordinates(std::ofstream &fout, std::vector< int > &uniqueFine, Teuchos::ArrayRCP< const typename Teuchos::ScalarTraits< Scalar >::coordinateType > &fx, Teuchos::ArrayRCP< const typename Teuchos::ScalarTraits< Scalar >::coordinateType > &fy, Teuchos::ArrayRCP< const typename Teuchos::ScalarTraits< Scalar >::coordinateType > &fz, int dim) const
std::string replaceAll(std::string result, const std::string &replaceWhat, const std::string &replaceWithWhat) const
static void doConvexHulls2D(std::vector< int > &vertices, std::vector< int > &geomSizes, LO numLocalAggs, LO numFineNodes, const std::vector< bool > &isRoot, const ArrayRCP< LO > &vertex2AggId, const Teuchos::ArrayRCP< const typename Teuchos::ScalarTraits< Scalar >::coordinateType > &xCoords, const Teuchos::ArrayRCP< const typename Teuchos::ScalarTraits< Scalar >::coordinateType > &yCoords)
static void doCGALConvexHulls3D(std::vector< int > &vertices, std::vector< int > &geomSizes, LO numLocalAggs, LO numFineNodes, const std::vector< bool > &isRoot, const ArrayRCP< LO > &vertex2AggId, const Teuchos::ArrayRCP< const typename Teuchos::ScalarTraits< Scalar >::coordinateType > &xCoords, const Teuchos::ArrayRCP< const typename Teuchos::ScalarTraits< Scalar >::coordinateType > &yCoords, const Teuchos::ArrayRCP< const typename Teuchos::ScalarTraits< Scalar >::coordinateType > &zCoords)
T & get(const std::string &name, T def_value)
void writeFileVTKData(std::ofstream &fout, std::vector< int > &uniqueFine, LocalOrdinal myAggOffset, ArrayRCP< LocalOrdinal > &vertex2AggId, int myRank) const
static void doCGALConvexHulls2D(std::vector< int > &vertices, std::vector< int > &geomSizes, LO numLocalAggs, LO numFineNodes, const std::vector< bool > &isRoot, const ArrayRCP< LO > &vertex2AggId, const Teuchos::ArrayRCP< const typename Teuchos::ScalarTraits< Scalar >::coordinateType > &xCoords, const Teuchos::ArrayRCP< const typename Teuchos::ScalarTraits< Scalar >::coordinateType > &yCoords)
virtual size_t GetNodeNumVertices() const =0
Return number of vertices owned by the calling node.
ParameterList & set(std::string const &name, T const &value, std::string const &docString="", RCP< const ParameterEntryValidator > const &validator=null)
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
std::vector< int > makeUnique(std::vector< int > &vertices) const
replaces node indices in vertices with compressed unique indices, and returns list of unique points ...
size_type size() const
std::string getFileName(int numProcs, int myRank, int level, const Teuchos::ParameterList &pL) const
void writeFileVTKNodes(std::ofstream &fout, std::vector< int > &uniqueFine, Teuchos::RCP< const Map > &nodeMap) const
RCP< ParameterList > GetValidParameterList() const
static int ccw(const myVec2 &a, const myVec2 &b, const myVec2 &c)
static double pointDistFromTri(myVec3 point, myVec3 v1, myVec3 v2, myVec3 v3)
static double dotProduct(myVec2 v1, myVec2 v2)
void writePVTU(std::ofstream &pvtu, std::string baseFname, int numProcs, bool bFineEdges=false, bool bCoarseEdges=false) const
std::string getBaseFileName(int numProcs, int level, const Teuchos::ParameterList &pL) const
static void doConvexHulls3D(std::vector< int > &vertices, std::vector< int > &geomSizes, LO numLocalAggs, LO numFineNodes, const std::vector< bool > &isRoot, const ArrayRCP< LO > &vertex2AggId, const Teuchos::ArrayRCP< const typename Teuchos::ScalarTraits< Scalar >::coordinateType > &xCoords, const Teuchos::ArrayRCP< const typename Teuchos::ScalarTraits< Scalar >::coordinateType > &yCoords, const Teuchos::ArrayRCP< const typename Teuchos::ScalarTraits< Scalar >::coordinateType > &zCoords)
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
MueLu::DefaultGlobalOrdinal GlobalOrdinal
static void doGraphEdges(std::vector< int > &vertices, std::vector< int > &geomSizes, Teuchos::RCP< GraphBase > &G, Teuchos::ArrayRCP< const typename Teuchos::ScalarTraits< Scalar >::coordinateType > &fx, Teuchos::ArrayRCP< const typename Teuchos::ScalarTraits< Scalar >::coordinateType > &fy, Teuchos::ArrayRCP< const typename Teuchos::ScalarTraits< Scalar >::coordinateType > &fz)
static void doJacks(std::vector< int > &vertices, std::vector< int > &geomSizes, LO numLocalAggs, LO numFineNodes, const std::vector< bool > &isRoot, const ArrayRCP< LO > &vertex2AggId)
static myVec3 crossProduct(myVec3 v1, myVec3 v2)
TransListIter iter
static myVec2 vecSubtract(myVec2 v1, myVec2 v2)
static double distance(myVec2 p1, myVec2 p2)
void writeFileVTKCells(std::ofstream &fout, std::vector< int > &uniqueFine, std::vector< LocalOrdinal > &vertices, std::vector< LocalOrdinal > &geomSize) const
static bool isInFront(myVec3 point, myVec3 inPlane, myVec3 n)
Exception throws to report errors in the internal logical of the program.
static std::vector< myTriangle > processTriangle(std::list< myTriangle > &tris, myTriangle tri, std::list< int > &pointsInFront, myVec3 &barycenter, const Teuchos::ArrayRCP< const typename Teuchos::ScalarTraits< Scalar >::coordinateType > &xCoords, const Teuchos::ArrayRCP< const typename Teuchos::ScalarTraits< Scalar >::coordinateType > &yCoords, const Teuchos::ArrayRCP< const typename Teuchos::ScalarTraits< Scalar >::coordinateType > &zCoords)
void replaceAll(std::string &str, const std::string &from, const std::string &to)
virtual Teuchos::ArrayView< const LocalOrdinal > getNeighborVertices(LocalOrdinal v) const =0
Return the list of vertices adjacent to the vertex &#39;v&#39;.
static std::vector< int > giftWrap(std::vector< myVec2 > &points, std::vector< int > &nodes, const Teuchos::ArrayRCP< const typename Teuchos::ScalarTraits< Scalar >::coordinateType > &xCoords, const Teuchos::ArrayRCP< const typename Teuchos::ScalarTraits< Scalar >::coordinateType > &yCoords)
void writeFileVTKClosing(std::ofstream &fout) const