Nektar++
BLMesh.cpp
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // File: TetMesh.cpp
4 //
5 // For more information, please see: http://www.nektar.info/
6 //
7 // The MIT License
8 //
9 // Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
10 // Department of Aeronautics, Imperial College London (UK), and Scientific
11 // Computing and Imaging Institute, University of Utah (USA).
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining a
14 // copy of this software and associated documentation files (the "Software"),
15 // to deal in the Software without restriction, including without limitation
16 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
17 // and/or sell copies of the Software, and to permit persons to whom the
18 // Software is furnished to do so, subject to the following conditions:
19 //
20 // The above copyright notice and this permission notice shall be included
21 // in all copies or substantial portions of the Software.
22 //
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29 // DEALINGS IN THE SOFTWARE.
30 //
31 // Description: tet meshing methods
32 //
33 ////////////////////////////////////////////////////////////////////////////////
34 
35 #include <boost/geometry.hpp>
36 #include <boost/geometry/geometries/box.hpp>
37 #include <boost/geometry/geometries/point.hpp>
38 #include <boost/geometry/index/rtree.hpp>
39 
41 
44 
47 
48 #include <algorithm>
49 
50 namespace bg = boost::geometry;
51 namespace bgi = boost::geometry::index;
52 
53 typedef bg::model::point<double, 3, bg::cs::cartesian> point;
54 typedef bg::model::box<point> box;
55 typedef std::pair<box, unsigned int> boxI;
56 
57 using namespace std;
58 namespace Nektar
59 {
60 namespace NekMeshUtils
61 {
62 
64 {
65  NekDouble xmin = numeric_limits<double>::max(),
66  xmax = -1.0 * numeric_limits<double>::max(),
67  ymin = numeric_limits<double>::max(),
68  ymax = -1.0 * numeric_limits<double>::max(),
69  zmin = numeric_limits<double>::max(),
70  zmax = -1.0 * numeric_limits<double>::max();
71 
72  vector<NodeSharedPtr> ns = el->GetVertexList();
73  for (int i = 0; i < ns.size(); i++)
74  {
75  xmin = min(xmin, ns[i]->m_x);
76  xmax = max(xmax, ns[i]->m_x);
77  ymin = min(ymin, ns[i]->m_y);
78  ymax = max(ymax, ns[i]->m_y);
79  zmin = min(zmin, ns[i]->m_z);
80  zmax = max(zmax, ns[i]->m_z);
81  }
82 
83  return box(point(xmin - ov, ymin - ov, zmin - ov),
84  point(xmax + ov, ymax + ov, zmax + ov));
85 }
86 
87 inline box GetBox(vector<ElementSharedPtr> els, NekDouble ov)
88 {
89  NekDouble xmin = numeric_limits<double>::max(),
90  xmax = -1.0 * numeric_limits<double>::max(),
91  ymin = numeric_limits<double>::max(),
92  ymax = -1.0 * numeric_limits<double>::max(),
93  zmin = numeric_limits<double>::max(),
94  zmax = -1.0 * numeric_limits<double>::max();
95 
96  for (int j = 0; j < els.size(); j++)
97  {
98  vector<NodeSharedPtr> ns = els[j]->GetVertexList();
99  for (int i = 0; i < ns.size(); i++)
100  {
101  xmin = min(xmin, ns[i]->m_x);
102  xmax = max(xmax, ns[i]->m_x);
103  ymin = min(ymin, ns[i]->m_y);
104  ymax = max(ymax, ns[i]->m_y);
105  zmin = min(zmin, ns[i]->m_z);
106  zmax = max(zmax, ns[i]->m_z);
107  }
108  }
109 
110  return box(point(xmin - ov, ymin - ov, zmin - ov),
111  point(xmax + ov, ymax + ov, zmax + ov));
112 }
113 
115 {
116  return box(point(n->m_x - ov, n->m_y - ov, n->m_z - ov),
117  point(n->m_x + ov, n->m_y + ov, n->m_z + ov));
118 }
119 
121 {
122  Setup();
123 
124  BuildElements();
125 
126  GrowLayers();
127 
128  Shrink();
129 
130  map<NodeSharedPtr, blInfoSharedPtr>::iterator bit;
131  for (bit = m_blData.begin(); bit != m_blData.end(); bit++)
132  {
133  vector<blInfoSharedPtr> infos = m_nToNInfo[bit->first];
134  for (int i = 0; i < infos.size(); i++)
135  {
136  if (bit->second->bl > infos[i]->bl + 1)
137  {
138  cout << "non smooth error " << bit->second->bl << " "
139  << infos[i]->bl << endl;
140  }
141  }
142  }
143 
144  for (int i = 0; i < m_mesh->m_element[3].size(); i++)
145  {
146  ElementSharedPtr el = m_mesh->m_element[3][i];
147  if (!IsPrismValid(el))
148  {
149  cout << "validity error " << el->GetId() << endl;
150  }
151  }
152 
153  /*m_mesh->m_element[2] = m_psuedoSurface;
154  m_mesh->m_element[3].clear();
155  m_mesh->m_expDim = 2;*/
156 }
157 
158 map<NodeSharedPtr, NodeSharedPtr> BLMesh::GetSymNodes()
159 {
160  map<NodeSharedPtr, NodeSharedPtr> ret;
161 
162  map<NodeSharedPtr, blInfoSharedPtr>::iterator bit;
163  for (bit = m_blData.begin(); bit != m_blData.end(); bit++)
164  {
165  if (!bit->second->onSym)
166  {
167  continue;
168  }
169  CADSurfSharedPtr s = m_mesh->m_cad->GetSurf(bit->second->symsurf);
170  Array<OneD, NekDouble> loc = bit->second->pNode->GetLoc();
171  Array<OneD, NekDouble> uv = s->locuv(loc);
172  bit->second->pNode->SetCADSurf(s, uv);
173  ret[bit->first] = bit->second->pNode;
174  }
175  return ret;
176 }
177 
179 {
180  vector<NodeSharedPtr> ns1 = el->GetVertexList();
181  Array<OneD, NekDouble> N1 = el->Normal(true);
182 
184  V[0] = n->m_x - ns1[0]->m_x;
185  V[1] = n->m_y - ns1[0]->m_y;
186  V[2] = n->m_z - ns1[0]->m_z;
187 
188  NekDouble Vmag = sqrt(V[0] * V[0] + V[1] * V[1] + V[2] * V[2]);
189 
190  NekDouble ang = (N1[0] * V[0] + N1[1] * V[1] + N1[2] * V[2]) / Vmag;
191 
192  return ang > 0.17;
193 }
194 
195 void BLMesh::GrowLayers()
196 {
197  map<NodeSharedPtr, blInfoSharedPtr>::iterator bit;
198 
199  // setup up a tree which is formed of boxes of each surface plus some
200  // extra room (ideal bl thick)
201 
202  // in each iteration a tree is made for all the triangles in each surface
203  // when considering to stop a bounary layer growing, it first
204  // looks at the top tree to find surfaces which are canditates
205  // it then searches the subtrees for each triangle canditate
206  // it then does a distance calcation.
207  // if a boundary layer should be close to that from another surface, it
208  // should stop
209 
210  map<int, vector<ElementSharedPtr>> psElements;
211  for (int i = 0; i < m_mesh->m_element[2].size(); i++)
212  {
213  ElementSharedPtr el = m_mesh->m_element[2][i];
214  vector<unsigned int>::iterator f =
215  find(m_blsurfs.begin(), m_blsurfs.end(), el->m_parentCAD->GetId());
216 
217  vector<unsigned int>::iterator s = find(
218  m_symSurfs.begin(), m_symSurfs.end(), el->m_parentCAD->GetId());
219 
220  if (f == m_blsurfs.end() && s == m_symSurfs.end())
221  {
222  psElements[el->m_parentCAD->GetId()].push_back(el);
223  }
224  }
225  for (int i = 0; i < m_psuedoSurface.size(); i++)
226  {
227  psElements[m_psuedoSurface[i]->m_parentCAD->GetId()].push_back(
228  m_psuedoSurface[i]);
229  }
230 
231  bgi::rtree<boxI, bgi::quadratic<16>> TopTree;
232  map<int, bgi::rtree<boxI, bgi::quadratic<16>>> SubTrees;
233 
234  // ofstream file;
235  // file.open("pts.3D");
236  // file << "x y z value" << endl;
237 
238  for (int l = 1; l < m_layer; l++)
239  {
240  NekDouble delta = (m_layerT[l] - m_layerT[l - 1]);
241  TopTree.clear();
242  SubTrees.clear();
243  map<int, vector<ElementSharedPtr>>::iterator it;
244  for (it = psElements.begin(); it != psElements.end(); it++)
245  {
246  TopTree.insert(make_pair(GetBox(it->second, m_bl), it->first));
247  vector<boxI> toInsert;
248  for (int i = 0; i < it->second.size(); i++)
249  {
250  toInsert.push_back(make_pair(GetBox(it->second[i], m_bl), i));
251  }
252  SubTrees[it->first].insert(toInsert.begin(), toInsert.end());
253  }
254 
255  for (bit = m_blData.begin(); bit != m_blData.end(); bit++)
256  {
257  if (bit->second->stopped)
258  {
259  continue;
260  }
261 
262  vector<boxI> results;
263  TopTree.query(bgi::intersects(point(bit->second->pNode->m_x,
264  bit->second->pNode->m_y,
265  bit->second->pNode->m_z)),
266  back_inserter(results));
267  set<int> surfs;
268  for (int i = 0; i < results.size(); i++)
269  {
270  set<int>::iterator f =
271  bit->second->surfs.find(results[i].second);
272  if (f == bit->second->surfs.end())
273  {
274  // hit
275  surfs.insert(results[i].second);
276  }
277  }
278 
279  set<int>::iterator iit;
280  bool hit = false;
281  for (iit = surfs.begin(); iit != surfs.end(); iit++)
282  {
283  results.clear();
284  SubTrees[*iit].query(
285  bgi::intersects(GetBox(bit->second->pNode, m_bl)),
286  back_inserter(results));
287  for (int i = 0; i < results.size(); i++)
288  {
289  if (Infont(bit->second->pNode,
290  psElements[*iit][results[i].second]))
291  {
292  NekDouble prox =
293  Proximity(bit->second->pNode,
294  psElements[*iit][results[i].second]);
295  if (prox < delta * 2.5)
296  {
297  hit = true;
298  // cout << "hit" << endl;
299  bit->second->stopped = true;
300  /*file << bit->first->m_x << " " << bit->first->m_y
301  << " " << bit->first->m_z << " " << l << endl;
302  file << bit->second->pNode->m_x << " " <<
303  bit->second->pNode->m_y << " " <<
304  bit->second->pNode->m_z << " " << l << endl;
305  m_mesh->m_element[2].clear();
306  m_mesh->m_expDim--;
307  m_mesh->m_element[2].push_back(psElements[*iit][results[i].second]);*/
308  break;
309  // return;
310  }
311  }
312  }
313  if (hit)
314  break;
315  }
316  }
317 
318  // if after proximity scanning all is okay, advance the layer
319  for (bit = m_blData.begin(); bit != m_blData.end(); bit++)
320  {
321  if (bit->second->stopped)
322  {
323  continue;
324  }
325 
326  // test the smoothness
327  bool shouldStop = false;
328  vector<blInfoSharedPtr> ne = m_nToNInfo[bit->first];
329  for (int i = 0; i < ne.size(); i++)
330  {
331  if (ne[i]->bl < bit->second->bl)
332  {
333  shouldStop = true;
334  break;
335  }
336  }
337  if (shouldStop)
338  {
339  bit->second->stopped = true;
340  continue;
341  }
342 
343  bit->second->AlignNode(m_layerT[l]);
344  bit->second->bl = l;
345  }
346  }
347  // file.close();
348 }
349 
350 inline bool sign(NekDouble a, NekDouble b)
351 {
352  return (a * b > 0.0);
353 }
354 
356 {
357  return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
358 }
359 
360 NekDouble BLMesh::Proximity(NodeSharedPtr n, ElementSharedPtr el)
361 {
362  vector<NodeSharedPtr> ns = el->GetVertexList();
363  Array<OneD, NekDouble> B = ns[0]->GetLoc();
365  E0[0] = ns[1]->m_x - ns[0]->m_x;
366  E0[1] = ns[1]->m_y - ns[0]->m_y;
367  E0[2] = ns[1]->m_z - ns[0]->m_z;
369  E1[0] = ns[2]->m_x - ns[0]->m_x;
370  E1[1] = ns[2]->m_y - ns[0]->m_y;
371  E1[2] = ns[2]->m_z - ns[0]->m_z;
372  Array<OneD, NekDouble> P = n->GetLoc();
373 
374  NekDouble a = Dot(E0, E0);
375  NekDouble b = Dot(E0, E1);
376  NekDouble c = Dot(E1, E1);
377 
379  Vmath::Vsub(3, B, 1, P, 1, BP, 1);
380 
381  NekDouble d = Dot(E0, BP);
382  NekDouble e = Dot(E1, BP);
383 
384  NekDouble det = a * c - b * b;
385  NekDouble s = b * e - c * d, t = b * d - a * e;
386 
387  if (s + t <= det)
388  {
389  if (s < 0)
390  {
391  if (t < 0)
392  {
393  t = 0;
394  s = 0;
395  }
396  else
397  {
398  s = 0;
399  t = (e >= 0 ? 0 : (-e >= c ? 1 : -e / c));
400  }
401  }
402  else if (t < 0)
403  {
404  t = 0;
405  s = (d >= 0 ? 0 : (-d >= a ? 1 : -d / a));
406  }
407  else
408  {
409  NekDouble invDet = 1.0 / det;
410  s *= invDet;
411  t *= invDet;
412  }
413  }
414  else
415  {
416  if (s < 0)
417  {
418  s = 0;
419  t = 1;
420  }
421  else if (t < 0)
422  {
423  s = 1;
424  t = 0;
425  }
426  else
427  {
428  NekDouble numer = c + e - b - d;
429  if (numer <= 0)
430  {
431  s = 0;
432  }
433  else
434  {
435  NekDouble denom = a - 2 * b + c;
436  s = (numer >= denom ? 1 : numer / denom);
437  }
438  t = 1 - s;
439  }
440  }
441 
442  NodeSharedPtr point = std::shared_ptr<Node>(
443  new Node(0, B[0] + s * E0[0] + t * E1[0], B[1] + s * E0[1] + t * E1[1],
444  B[2] + s * E0[2] + t * E1[2]));
445 
446  return n->Distance(point);
447 }
448 
449 bool BLMesh::TestIntersectionEl(ElementSharedPtr e1, ElementSharedPtr e2)
450 {
451  vector<NodeSharedPtr> ns1 = e1->GetVertexList();
452  vector<NodeSharedPtr> ns2 = e2->GetVertexList();
453  if (ns1[0] == ns2[0] || ns1[0] == ns2[1] || ns1[0] == ns2[2] ||
454  ns1[1] == ns2[0] || ns1[1] == ns2[1] || ns1[1] == ns2[2] ||
455  ns1[2] == ns2[0] || ns1[2] == ns2[1] || ns1[2] == ns2[2])
456  {
457  return false;
458  }
459 
460  Array<OneD, NekDouble> N1(3), N2(3);
461  NekDouble d1, d2;
462 
463  N1[0] = (ns1[1]->m_y - ns1[0]->m_y) * (ns1[2]->m_z - ns1[0]->m_z) -
464  (ns1[2]->m_y - ns1[0]->m_y) * (ns1[1]->m_z - ns1[0]->m_z);
465  N1[1] = -1.0 * ((ns1[1]->m_x - ns1[0]->m_x) * (ns1[2]->m_z - ns1[0]->m_z) -
466  (ns1[2]->m_x - ns1[0]->m_x) * (ns1[1]->m_z - ns1[0]->m_z));
467  N1[2] = (ns1[1]->m_x - ns1[0]->m_x) * (ns1[2]->m_y - ns1[0]->m_y) -
468  (ns1[2]->m_x - ns1[0]->m_x) * (ns1[1]->m_y - ns1[0]->m_y);
469 
470  N2[0] = (ns2[1]->m_y - ns2[0]->m_y) * (ns2[2]->m_z - ns2[0]->m_z) -
471  (ns2[2]->m_y - ns2[0]->m_y) * (ns2[1]->m_z - ns2[0]->m_z);
472  N2[1] = -1.0 * ((ns2[1]->m_x - ns2[0]->m_x) * (ns2[2]->m_z - ns2[0]->m_z) -
473  (ns2[2]->m_x - ns2[0]->m_x) * (ns2[1]->m_z - ns2[0]->m_z));
474  N2[2] = (ns2[1]->m_x - ns2[0]->m_x) * (ns2[2]->m_y - ns2[0]->m_y) -
475  (ns2[2]->m_x - ns2[0]->m_x) * (ns2[1]->m_y - ns2[0]->m_y);
476 
477  d1 = -1.0 *
478  (N1[0] * ns1[0]->m_x + N1[1] * ns1[0]->m_y + N1[2] * ns1[0]->m_z);
479  d2 = -1.0 *
480  (N2[0] * ns2[0]->m_x + N2[1] * ns2[0]->m_y + N2[2] * ns2[0]->m_z);
481 
482  Array<OneD, NekDouble> dv1(3), dv2(3);
483 
484  dv1[0] =
485  N2[0] * ns1[0]->m_x + N2[1] * ns1[0]->m_y + N2[2] * ns1[0]->m_z + d2;
486  dv1[1] =
487  N2[0] * ns1[1]->m_x + N2[1] * ns1[1]->m_y + N2[2] * ns1[1]->m_z + d2;
488  dv1[2] =
489  N2[0] * ns1[2]->m_x + N2[1] * ns1[2]->m_y + N2[2] * ns1[2]->m_z + d2;
490 
491  dv2[0] =
492  N1[0] * ns2[0]->m_x + N1[1] * ns2[0]->m_y + N1[2] * ns2[0]->m_z + d1;
493  dv2[1] =
494  N1[0] * ns2[1]->m_x + N1[1] * ns2[1]->m_y + N1[2] * ns2[1]->m_z + d1;
495  dv2[2] =
496  N1[0] * ns2[2]->m_x + N1[1] * ns2[2]->m_y + N1[2] * ns2[2]->m_z + d1;
497 
498  if (sign(dv1[0], dv1[1]) && sign(dv1[1], dv1[2]))
499  {
500  return false;
501  }
502  if (sign(dv2[0], dv2[1]) && sign(dv2[1], dv2[2]))
503  {
504  return false;
505  }
506 
508  D[0] = N1[1] * N2[2] - N1[2] * N2[1];
509  D[1] = -1.0 * (N1[0] * N2[2] - N1[2] * N2[0]);
510  D[2] = N1[0] * N2[1] - N1[0] * N2[1];
511 
512  int base1 = 0, base2 = 0;
513  if (!sign(dv2[0], dv2[1]) && sign(dv2[1], dv2[2]))
514  {
515  base2 = 0;
516  }
517  else if (!sign(dv2[1], dv2[2]) && sign(dv2[2], dv2[0]))
518  {
519  base2 = 1;
520  }
521  else if (!sign(dv2[2], dv2[0]) && sign(dv2[0], dv2[1]))
522  {
523  base2 = 2;
524  }
525  else
526  {
527  cout << "base not set" << endl;
528  }
529 
530  if (!sign(dv1[0], dv1[1]) && sign(dv1[1], dv1[2]))
531  {
532  base1 = 0;
533  }
534  else if (!sign(dv1[1], dv1[2]) && sign(dv1[2], dv1[0]))
535  {
536  base1 = 1;
537  }
538  else if (!sign(dv1[2], dv1[0]) && sign(dv1[0], dv1[1]))
539  {
540  base1 = 2;
541  }
542  else
543  {
544  cout << "base not set" << endl;
545  }
546 
547  Array<OneD, NekDouble> p1(3), p2(3);
548 
549  p1[0] = D[0] * ns1[0]->m_x + D[1] * ns1[0]->m_y + D[2] * ns1[0]->m_z;
550  p1[1] = D[0] * ns1[1]->m_x + D[1] * ns1[1]->m_y + D[2] * ns1[1]->m_z;
551  p1[2] = D[0] * ns1[2]->m_x + D[1] * ns1[2]->m_y + D[2] * ns1[2]->m_z;
552 
553  p2[0] = D[0] * ns2[0]->m_x + D[1] * ns2[0]->m_y + D[2] * ns2[0]->m_z;
554  p2[1] = D[0] * ns2[1]->m_x + D[1] * ns2[1]->m_y + D[2] * ns2[1]->m_z;
555  p2[2] = D[0] * ns2[2]->m_x + D[1] * ns2[2]->m_y + D[2] * ns2[2]->m_z;
556 
557  NekDouble t11, t12, t21, t22;
558  int o1 = 0, o2 = 0;
559  if (base1 == 0)
560  {
561  o1 = 1;
562  o2 = 2;
563  }
564  else if (base1 == 1)
565  {
566  o1 = 2;
567  o2 = 0;
568  }
569  else if (base1 == 2)
570  {
571  o1 = 0;
572  o2 = 1;
573  }
574 
575  t11 = p1[o1] + (p1[base1] - p1[o1]) * dv1[o1] / (dv1[o1] - dv1[base1]);
576  t12 = p1[o2] + (p1[base1] - p1[o2]) * dv1[o2] / (dv1[o2] - dv1[base1]);
577 
578  if (base2 == 0)
579  {
580  o1 = 1;
581  o2 = 2;
582  }
583  else if (base2 == 1)
584  {
585  o1 = 2;
586  o2 = 0;
587  }
588  else if (base2 == 2)
589  {
590  o1 = 0;
591  o2 = 1;
592  }
593 
594  t21 = p2[o1] + (p2[base2] - p2[o1]) * dv2[o1] / (dv2[o1] - dv2[base2]);
595  t22 = p2[o2] + (p2[base2] - p2[o2]) * dv2[o2] / (dv2[o2] - dv2[base2]);
596 
597  if (t11 > t12)
598  {
599  swap(t11, t12);
600  }
601  if (t21 > t22)
602  {
603  swap(t21, t22);
604  }
605 
606  if (t21 < t11)
607  {
608  swap(t11, t21);
609  swap(t12, t22);
610  }
611 
612  if (!sign(t21 - t11, t22 - t11) || !sign(t21 - t12, t22 - t12))
613  {
614  return true;
615  }
616 
617  return false;
618 }
619 
620 void BLMesh::Shrink()
621 {
622  map<NodeSharedPtr, blInfoSharedPtr>::iterator bit;
623  bool smsh = true;
624  while (smsh)
625  {
626  smsh = false;
627 
628  vector<ElementSharedPtr> inv;
629  for (int i = 0; i < m_mesh->m_element[3].size(); i++)
630  {
631  ElementSharedPtr el = m_mesh->m_element[3][i];
632  if (!IsPrismValid(el))
633  {
634  inv.push_back(el);
635  }
636  }
637 
638  smsh = (inv.size() > 0);
639 
640  for (int i = 0; i < inv.size(); i++)
641  {
642  ElementSharedPtr t = m_priToTri[inv[i]];
643  vector<blInfoSharedPtr> bls;
644  vector<NodeSharedPtr> ns = t->GetVertexList();
645  for (int j = 0; j < ns.size(); j++)
646  {
647  bls.push_back(m_blData[ns[j]]);
648  }
649  bool repeat = true;
650  while (repeat)
651  {
652  repeat = false;
653  int mx = 0;
654  for (int j = 0; j < 3; j++)
655  {
656  mx = max(mx, bls[j]->bl);
657  }
658  ASSERTL0(mx > 0, "shrinking to nothing");
659  for (int j = 0; j < 3; j++)
660  {
661  if (bls[j]->bl < mx)
662  {
663  continue;
664  }
665  bls[j]->bl--;
666  bls[j]->AlignNode(m_layerT[bls[j]->bl]);
667  }
668  if (!IsPrismValid(inv[i]))
669  {
670  repeat = true;
671  }
672  }
673  }
674 
675  bool repeat = true;
676  while (repeat)
677  {
678  repeat = false;
679  for (bit = m_blData.begin(); bit != m_blData.end(); bit++)
680  {
681  vector<blInfoSharedPtr> infos = m_nToNInfo[bit->first];
682  for (int i = 0; i < infos.size(); i++)
683  {
684  if (bit->second->bl > infos[i]->bl + 1)
685  {
686  bit->second->bl--;
687  bit->second->AlignNode(m_layerT[bit->second->bl]);
688  repeat = true;
689  }
690  }
691  }
692  }
693  }
694 }
695 
696 bool BLMesh::IsPrismValid(ElementSharedPtr el)
697 {
698  NekDouble mn = numeric_limits<double>::max();
699  NekDouble mx = -1.0 * numeric_limits<double>::max();
700  vector<NodeSharedPtr> ns = el->GetVertexList();
701  NekVector<NekDouble> X(6), Y(6), Z(6);
702  for (int j = 0; j < ns.size(); j++)
703  {
704  X(j) = ns[j]->m_x;
705  Y(j) = ns[j]->m_y;
706  Z(j) = ns[j]->m_z;
707  }
708  NekVector<NekDouble> x1(6), y1(6), z1(6), x2(6), y2(6), z2(6), x3(6), y3(6),
709  z3(6);
710 
711  x1 = m_deriv[0] * X;
712  y1 = m_deriv[0] * Y;
713  z1 = m_deriv[0] * Z;
714  x2 = m_deriv[1] * X;
715  y2 = m_deriv[1] * Y;
716  z2 = m_deriv[1] * Z;
717  x3 = m_deriv[2] * X;
718  y3 = m_deriv[2] * Y;
719  z3 = m_deriv[2] * Z;
720 
721  for (int j = 0; j < 6; j++)
722  {
723  DNekMat dxdz(3, 3, 1.0, eFULL);
724  dxdz(0, 0) = x1(j);
725  dxdz(0, 1) = x2(j);
726  dxdz(0, 2) = x3(j);
727  dxdz(1, 0) = y1(j);
728  dxdz(1, 1) = y2(j);
729  dxdz(1, 2) = y3(j);
730  dxdz(2, 0) = z1(j);
731  dxdz(2, 1) = z2(j);
732  dxdz(2, 2) = z3(j);
733 
734  NekDouble jacDet =
735  dxdz(0, 0) * (dxdz(1, 1) * dxdz(2, 2) - dxdz(2, 1) * dxdz(1, 2)) -
736  dxdz(0, 1) * (dxdz(1, 0) * dxdz(2, 2) - dxdz(2, 0) * dxdz(1, 2)) +
737  dxdz(0, 2) * (dxdz(1, 0) * dxdz(2, 1) - dxdz(2, 0) * dxdz(1, 1));
738  mn = min(mn, jacDet);
739  mx = max(mx, jacDet);
740  }
741 
742  /*SpatialDomains::GeometrySharedPtr geom = el->GetGeom(3);
743  SpatialDomains::GeomFactorsSharedPtr gfac = geom->GetGeomFactors();
744 
745  cout << mn << " " << mx << " " << (mn > 0) << " " << gfac->IsValid() <<
746  endl;*/
747 
748  return mn > 0;
749 }
750 
751 void BLMesh::BuildElements()
752 {
753  // make prisms
754  map<CADOrientation::Orientation, vector<int>> baseTri;
755  map<CADOrientation::Orientation, vector<int>> topTri;
756 
757  vector<int> tmp;
758  // back-base
759  tmp.push_back(0);
760  tmp.push_back(4);
761  tmp.push_back(1);
762  baseTri[CADOrientation::eBackwards] = tmp;
763  tmp.clear();
764  // for-base
765  tmp.push_back(0);
766  tmp.push_back(1);
767  tmp.push_back(4);
768  baseTri[CADOrientation::eForwards] = tmp;
769  // back-top
770  tmp.clear();
771  tmp.push_back(3);
772  tmp.push_back(5);
773  tmp.push_back(2);
774  topTri[CADOrientation::eBackwards] = tmp;
775  // for-top
776  tmp.clear();
777  tmp.push_back(3);
778  tmp.push_back(2);
779  tmp.push_back(5);
780  topTri[CADOrientation::eForwards] = tmp;
781 
782  ElmtConfig pconf(LibUtilities::ePrism, 1, false, false);
783  ElmtConfig tconf(LibUtilities::eTriangle, 1, false, false);
784 
785  for (int i = 0; i < m_mesh->m_element[2].size(); i++)
786  {
787  ElementSharedPtr el = m_mesh->m_element[2][i];
788  vector<unsigned int>::iterator f =
789  find(m_blsurfs.begin(), m_blsurfs.end(), el->m_parentCAD->GetId());
790 
791  if (f == m_blsurfs.end())
792  {
793  // if this triangle is not in bl surfs continue
794  continue;
795  }
796 
797  vector<NodeSharedPtr> tn(3); // nodes for pseduo surface
798  vector<NodeSharedPtr> pn(6); // all prism nodes
799  vector<NodeSharedPtr> n = el->GetVertexList();
800  CADOrientation::Orientation o = el->m_parentCAD->Orientation();
801 
802  for (int j = 0; j < 3; j++)
803  {
804  pn[baseTri[o][j]] = n[j];
805  pn[topTri[o][j]] = m_blData[n[j]]->pNode;
806  tn[j] = m_blData[n[j]]->pNode;
807  }
808 
809  vector<int> tags;
810  tags.push_back(m_id);
812  LibUtilities::ePrism, pconf, pn, tags);
813  E->SetId(i);
814 
815  m_mesh->m_element[3].push_back(E);
816 
817  // tag of this element doesnt matter so can just be 1
819  LibUtilities::eTriangle, tconf, tn, tags);
820  m_psuedoSurface.push_back(T);
821 
822  T->m_parentCAD = el->m_parentCAD;
823 
824  m_priToTri[E] = el;
825  }
826 }
827 
828 NekDouble BLMesh::Visability(vector<ElementSharedPtr> tris,
830 {
831  NekDouble mn = numeric_limits<double>::max();
832 
833  for (int i = 0; i < tris.size(); i++)
834  {
835  Array<OneD, NekDouble> tmp = tris[i]->Normal(true);
836  NekDouble dt = tmp[0] * N[0] + tmp[1] * N[1] + tmp[2] * N[2];
837  mn = min(mn, dt);
838  }
839  return mn;
840 }
841 
842 Array<OneD, NekDouble> BLMesh::GetNormal(vector<ElementSharedPtr> tris)
843 {
844  // compile list of normals
845  vector<Array<OneD, NekDouble>> N;
846  for (int i = 0; i < tris.size(); i++)
847  {
848  N.push_back(tris[i]->Normal(true));
849  }
850 
851  vector<NekDouble> w(N.size());
852  Array<OneD, NekDouble> Np(3, 0.0);
853 
854  for (int i = 0; i < N.size(); i++)
855  {
856  w[i] = 1.0 / N.size();
857  }
858 
859  for (int i = 0; i < N.size(); i++)
860  {
861  Np[0] += w[i] * N[i][0];
862  Np[1] += w[i] * N[i][1];
863  Np[2] += w[i] * N[i][2];
864  }
865  NekDouble mag = sqrt(Np[0] * Np[0] + Np[1] * Np[1] + Np[2] * Np[2]);
866  Np[0] /= mag;
867  Np[1] /= mag;
868  Np[2] /= mag;
869 
870  Array<OneD, NekDouble> Ninital = Np;
871 
872  NekDouble dot = 0.0;
873  int ct = 0;
874  vector<NekDouble> a(N.size());
875  while (fabs(dot - 1) > 1e-6)
876  {
877  ct++;
878  Array<OneD, NekDouble> Nplast(3);
879  Nplast[0] = Np[0];
880  Nplast[1] = Np[1];
881  Nplast[2] = Np[2];
882 
883  NekDouble aSum = 0.0;
884  for (int i = 0; i < N.size(); i++)
885  {
886  NekDouble dot2 =
887  Np[0] * N[i][0] + Np[1] * N[i][1] + Np[2] * N[i][2];
888  if (fabs(dot2 - 1) < 1e-9)
889  {
890  a[i] = dot2 / fabs(dot2) * 1e-9;
891  }
892  else
893  {
894  a[i] = acos(dot2);
895  }
896 
897  aSum += a[i];
898  }
899 
900  NekDouble wSum = 0.0;
901  for (int i = 0; i < N.size(); i++)
902  {
903  w[i] = w[i] * a[i] / aSum;
904  wSum += w[i];
905  }
906 
907  for (int i = 0; i < N.size(); i++)
908  {
909  w[i] = w[i] / wSum;
910  }
911 
912  Array<OneD, NekDouble> NpN(3, 0.0);
913  for (int i = 0; i < N.size(); i++)
914  {
915  NpN[0] += w[i] * N[i][0];
916  NpN[1] += w[i] * N[i][1];
917  NpN[2] += w[i] * N[i][2];
918  }
919  mag = sqrt(NpN[0] * NpN[0] + NpN[1] * NpN[1] + NpN[2] * NpN[2]);
920  NpN[0] /= mag;
921  NpN[1] /= mag;
922  NpN[2] /= mag;
923 
924  Np[0] = 0.8 * NpN[0] + (1.0 - 0.8) * Np[0];
925  Np[1] = 0.8 * NpN[1] + (1.0 - 0.8) * Np[1];
926  Np[2] = 0.8 * NpN[2] + (1.0 - 0.8) * Np[2];
927  mag = sqrt(Np[0] * Np[0] + Np[1] * Np[1] + Np[2] * Np[2]);
928  Np[0] /= mag;
929  Np[1] /= mag;
930  Np[2] /= mag;
931 
932  dot = Np[0] * Nplast[0] + Np[1] * Nplast[1] + Np[2] * Nplast[2];
933 
934  if (ct > 100000)
935  {
936  cout << "run out of iterations" << endl;
937  Np = Ninital;
938  break;
939  }
940  }
941 
942  return Np;
943 }
944 
945 void BLMesh::Setup()
946 {
947  NekDouble a = 2.0 * (1.0 - m_prog) / (1.0 - pow(m_prog, m_layer + 1));
948  m_layerT = Array<OneD, NekDouble>(m_layer);
949  m_layerT[0] = a * m_prog * m_bl;
950  for (int i = 1; i < m_layer; i++)
951  {
952  m_layerT[i] = m_layerT[i - 1] + a * pow(m_prog, i) * m_bl;
953  }
954 
955  if (m_mesh->m_verbose)
956  {
957  cout << "First layer height " << m_layerT[0] << endl;
958  }
959 
960  // this sets up all the boundary layer normals data holder
961  set<int> symSurfs;
962  NodeSet::iterator it;
963  int ct = 0;
964  int failed = 0;
965 
966  // ofstream file1;
967  // file1.open("pts.3D");
968  // file1 << "X Y Z value" << endl;
969  for (it = m_mesh->m_vertexSet.begin(); it != m_mesh->m_vertexSet.end();
970  it++, ct++)
971  {
972  vector<CADSurfSharedPtr> ss = (*it)->GetCADSurfs();
973  vector<unsigned int> surfs;
974  for (int i = 0; i < ss.size(); i++)
975  {
976  surfs.push_back(ss[i]->GetId());
977  }
978  sort(surfs.begin(), surfs.end());
979  vector<unsigned int> inter, diff;
980 
981  set_intersection(m_blsurfs.begin(), m_blsurfs.end(), surfs.begin(),
982  surfs.end(), back_inserter(inter));
983  set_symmetric_difference(inter.begin(), inter.end(), surfs.begin(),
984  surfs.end(), back_inserter(diff));
985 
986  // is somewhere on a bl surface
987  if (inter.size() > 0)
988  {
989  // initialise a new bl boudnary node
990  blInfoSharedPtr bln = std::shared_ptr<blInfo>(new blInfo);
991  bln->oNode = (*it);
992  bln->stopped = false;
993 
994  // file1 << (*it)->m_x << " " << (*it)->m_y << " " << (*it)->m_z <<
995  // " " << ss.size() << endl;
996 
997  if (diff.size() > 0)
998  {
999  // if the diff size is greater than 1 there is a curve that
1000  // needs remeshing
1001  ASSERTL0(diff.size() <= 1, "not setup for curve bl refinement");
1002  symSurfs.insert(diff[0]);
1003  bln->symsurf = diff[0];
1004  bln->onSym = true;
1005  }
1006  else
1007  {
1008  bln->onSym = false;
1009  }
1010 
1011  m_blData[(*it)] = bln;
1012  }
1013  }
1014  // file1.close();
1015 
1016  // need a map from vertex idx to surface elements
1017  // but do not care about triangles which are not in the bl
1018  for (int i = 0; i < m_mesh->m_element[2].size(); i++)
1019  {
1020  vector<unsigned int>::iterator f =
1021  find(m_blsurfs.begin(), m_blsurfs.end(),
1022  m_mesh->m_element[2][i]->m_parentCAD->GetId());
1023 
1024  if (f == m_blsurfs.end())
1025  {
1026  // if this triangle is not in bl surfs continue
1027  continue;
1028  }
1029 
1030  vector<NodeSharedPtr> ns = m_mesh->m_element[2][i]->GetVertexList();
1031  for (int j = 0; j < ns.size(); j++)
1032  {
1033  m_blData[ns[j]]->els.push_back(m_mesh->m_element[2][i]);
1034  m_blData[ns[j]]->surfs.insert(
1035  m_mesh->m_element[2][i]->m_parentCAD->GetId());
1036  }
1037  }
1038 
1039  map<NodeSharedPtr, blInfoSharedPtr>::iterator bit;
1040  for (bit = m_blData.begin(); bit != m_blData.end(); bit++)
1041  {
1042  // calculate mesh normal
1043  bit->second->N = GetNormal(bit->second->els);
1044 
1045  if (Visability(bit->second->els, bit->second->N) < 0.0)
1046  {
1047  cerr << "failed " << bit->first->m_x << " " << bit->first->m_y
1048  << " " << bit->first->m_z << " "
1049  << Visability(bit->second->els, bit->second->N) << endl;
1050  failed++;
1051  }
1052 
1053  Array<OneD, NekDouble> loc = bit->first->GetLoc();
1054  for (int k = 0; k < 3; k++)
1055  {
1056  loc[k] += bit->second->N[k] * m_layerT[0];
1057  }
1058 
1059  bit->second->pNode = std::shared_ptr<Node>(
1060  new Node(m_mesh->m_numNodes++, loc[0], loc[1], loc[2]));
1061  bit->second->bl = 0;
1062  }
1063 
1064  m_symSurfs = vector<unsigned int>(symSurfs.begin(), symSurfs.end());
1065 
1066  // now need to enforce that all symmetry plane nodes have their normal
1067  // forced onto the symmetry surface
1068  for (bit = m_blData.begin(); bit != m_blData.end(); bit++)
1069  {
1070  if (!bit->second->onSym)
1071  {
1072  continue;
1073  }
1074 
1075  Array<OneD, NekDouble> loc = bit->second->pNode->GetLoc();
1077  m_mesh->m_cad->GetSurf(bit->second->symsurf)->locuv(loc);
1078 
1080  m_mesh->m_cad->GetSurf(bit->second->symsurf)->P(uv);
1081 
1083  N[0] = nl[0] - bit->first->m_x;
1084  N[1] = nl[1] - bit->first->m_y;
1085  N[2] = nl[2] - bit->first->m_z;
1086 
1087  NekDouble mag = sqrt(N[0] * N[0] + N[1] * N[1] + N[2] * N[2]);
1088  N[0] /= mag;
1089  N[1] /= mag;
1090  N[2] /= mag;
1091 
1092  bit->second->N = N;
1093  bit->second->AlignNode(m_layerT[0]);
1094  }
1095 
1096  // now smooth all the normals by distance weighted average
1097  // keep normals on curves constant
1098  for (bit = m_blData.begin(); bit != m_blData.end(); bit++)
1099  {
1100  set<int> added;
1101  added.insert(bit->first->m_id);
1102  for (int i = 0; i < bit->second->els.size(); i++)
1103  {
1104  vector<NodeSharedPtr> ns = bit->second->els[i]->GetVertexList();
1105  for (int j = 0; j < ns.size(); j++)
1106  {
1107  set<int>::iterator t = added.find(ns[j]->m_id);
1108  if (t == added.end())
1109  {
1110  m_nToNInfo[bit->first].push_back(m_blData[ns[j]]);
1111  }
1112  }
1113  }
1114  }
1115 
1116  for (int l = 0; l < 10; l++)
1117  {
1118  for (bit = m_blData.begin(); bit != m_blData.end(); bit++)
1119  {
1120  if (bit->first->GetNumCADSurf() > 1)
1121  {
1122  continue;
1123  }
1124 
1125  Array<OneD, NekDouble> sumV(3, 0.0);
1126  vector<blInfoSharedPtr> data = m_nToNInfo[bit->first];
1127  NekDouble Dtotal = 0.0;
1128  for (int i = 0; i < data.size(); i++)
1129  {
1130  NekDouble d = bit->first->Distance(data[i]->oNode);
1131  Dtotal += d;
1132  sumV[0] += data[i]->N[0] / d;
1133  sumV[1] += data[i]->N[1] / d;
1134  sumV[2] += data[i]->N[2] / d;
1135  }
1136  sumV[0] *= Dtotal;
1137  sumV[1] *= Dtotal;
1138  sumV[2] *= Dtotal;
1139  NekDouble mag =
1140  sqrt(sumV[0] * sumV[0] + sumV[1] * sumV[1] + sumV[2] * sumV[2]);
1141  sumV[0] /= mag;
1142  sumV[1] /= mag;
1143  sumV[2] /= mag;
1144 
1146 
1147  N[0] = (1.0 - 0.8) * bit->second->N[0] + 0.8 * sumV[0];
1148  N[1] = (1.0 - 0.8) * bit->second->N[1] + 0.8 * sumV[1];
1149  N[2] = (1.0 - 0.8) * bit->second->N[2] + 0.8 * sumV[2];
1150 
1151  mag = sqrt(N[0] * N[0] + N[1] * N[1] + N[2] * N[2]);
1152  N[0] /= mag;
1153  N[1] /= mag;
1154  N[2] /= mag;
1155 
1156  bit->second->N = N;
1157  bit->second->AlignNode(m_layerT[0]);
1158  }
1159  }
1160 
1161  /*ofstream file;
1162  file.open("bl.lines");
1163  for(bit = m_blData.begin(); bit != m_blData.end(); bit++)
1164  {
1165  NekDouble l = 0.05;
1166  file << bit->first->m_x << ", " << bit->first->m_y << ", " <<
1167  bit->first->m_z << endl;
1168  file << bit->first->m_x + bit->second->N[0]*l << ", "
1169  << bit->first->m_y + bit->second->N[1]*l << ", "
1170  << bit->first->m_z + bit->second->N[2]*l << endl;
1171  file << endl;
1172  }
1173  file.close();*/
1174 
1175  ASSERTL0(failed == 0, "some normals failed to generate");
1176 
1178 
1179  Array<OneD, NekDouble> u1, v1, w1;
1180  LibUtilities::PointsManager()[pkey1]->GetPoints(u1, v1, w1);
1181 
1182  LibUtilities::NodalUtilPrism nodalPrism(1, u1, v1, w1);
1183 
1184  NekMatrix<NekDouble> Vandermonde = *nodalPrism.GetVandermonde();
1185  NekMatrix<NekDouble> VandermondeI = Vandermonde;
1186  VandermondeI.Invert();
1187 
1188  m_deriv[0] = *nodalPrism.GetVandermondeForDeriv(0) * VandermondeI;
1189  m_deriv[1] = *nodalPrism.GetVandermondeForDeriv(1) * VandermondeI;
1190  m_deriv[2] = *nodalPrism.GetVandermondeForDeriv(2) * VandermondeI;
1191 }
1192 } // namespace NekMeshUtils
1193 } // namespace Nektar
static NekDouble ang(NekDouble x, NekDouble y)
Definition: Interpreter.cpp:91
std::shared_ptr< CADSurf > CADSurfSharedPtr
Definition: CADCurve.h:51
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:216
Basic information about an element.
Definition: ElementConfig.h:49
#define sign(a, b)
return the sign(b)*a
Definition: Polylib.cpp:16
STL namespace.
ElementFactory & GetElementFactory()
Definition: Element.cpp:44
std::shared_ptr< Node > NodeSharedPtr
Definition: CADVert.h:49
SharedMatrix GetVandermondeForDeriv(int dir)
Return the Vandermonde matrix of the derivative of the basis functions for the nodal distribution...
Definition: NodalUtil.cpp:134
bg::model::box< point > box
Definition: BLMesh.cpp:54
tBaseSharedPtr CreateInstance(tKey idKey, tParam... args)
Create an instance of the class referred to by idKey.
Definition: NekFactory.hpp:144
bool Infont(NodeSharedPtr n, ElementSharedPtr el)
Definition: BLMesh.cpp:178
std::shared_ptr< blInfo > blInfoSharedPtr
Definition: BLMesh.h:102
std::shared_ptr< Element > ElementSharedPtr
Definition: Edge.h:49
PointsManagerT & PointsManager(void)
Defines a specification for a set of points.
Definition: Points.h:59
double NekDouble
box GetBox(NodeSharedPtr n, NekDouble ov)
Definition: BLMesh.cpp:114
Specialisation of the NodalUtil class to support nodal prismatic elements.
Definition: NodalUtil.h:263
bg::model::point< double, 3, bg::cs::cartesian > point
Definition: BLMesh.cpp:53
T Dot(int n, const T *w, const T *x)
vvtvp (vector times vector times vector): z = w*x*y
Definition: Vmath.cpp:917
void Vsub(int n, const T *x, const int incx, const T *y, const int incy, T *z, const int incz)
Subtract vector z = x-y.
Definition: Vmath.cpp:346
std::pair< box, unsigned int > boxI
Definition: BLMesh.cpp:55
SharedMatrix GetVandermonde()
Return the Vandermonde matrix for the nodal distribution.
Definition: NodalUtil.cpp:101
InputIterator find(InputIterator first, InputIterator last, InputIterator startingpoint, const EqualityComparable &value)
Definition: StdRegions.hpp:358
3D electrostatically spaced points on a Prism
Definition: PointsType.h:75