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