Nektar++
Octree.cpp
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // File: octree.h
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: cad object methods.
32 //
33 ////////////////////////////////////////////////////////////////////////////////
34 
35 #include "Octree.h"
39 
42 
43 #include <boost/algorithm/string.hpp>
44 
45 using namespace std;
46 namespace Nektar
47 {
48 namespace NekMeshUtils
49 {
50 
51 void Octree::Process()
52 {
53  Array<OneD, NekDouble> boundingBox = m_mesh->m_cad->GetBoundingBox();
54 
55  // build curvature samples
56  CompileSourcePointList();
57 
58  if (m_mesh->m_verbose)
59  {
60  cout << "\tCurvature samples: " << m_SPList.size() << endl;
61  }
62 
63  // make master octant based on the bounding box of the domain
64  m_dim = max((boundingBox[1] - boundingBox[0]) / 2.0,
65  (boundingBox[3] - boundingBox[2]) / 2.0);
66 
67  m_dim = max(m_dim, (boundingBox[5] - boundingBox[4]) / 2.0);
68 
69  m_centroid = Array<OneD, NekDouble>(3);
70  m_centroid[0] = (boundingBox[1] + boundingBox[0]) / 2.0;
71  m_centroid[1] = (boundingBox[3] + boundingBox[2]) / 2.0;
72  m_centroid[2] = (boundingBox[5] + boundingBox[4]) / 2.0;
73 
75  0, m_centroid[0], m_centroid[1], m_centroid[2], m_dim, m_SPList);
76 
77  // begin recersive subdivision
78  SubDivide();
79 
80  m_octants.clear();
81  m_masteroct->CompileLeaves(m_octants);
82 
83  if (m_mesh->m_verbose)
84  {
85  cout << "\tOctants: " << m_octants.size() << endl;
86  }
87 
88  SmoothSurfaceOctants();
89 
90  PropagateDomain();
91 
92  SmoothAllOctants();
93 
94  if (m_mesh->m_verbose)
95  {
96  int elem = CountElemt();
97  cout << "\tPredicted mesh: " << elem << endl;
98  }
99 }
100 
102 {
103  // starting at master octant 0 move through succsesive m_octants which
104  // contain the point loc until a leaf is found
105  // first search through sourcepoints
106 
107  NekDouble tmp = numeric_limits<double>::max();
108 
109  for (int i = 0; i < m_lsources.size(); i++)
110  {
111  if (m_lsources[i].withinRange(loc))
112  {
113  tmp = min(m_lsources[i].delta, tmp);
114  }
115  }
116 
117  OctantSharedPtr n = m_masteroct;
118  int quad = 0;
119 
120  bool found = false;
121 
122  while (!found)
123  {
124  Array<OneD, NekDouble> octloc = n->GetLoc();
125 
126  if (!(loc[0] < octloc[0]) && // forward
127  !(loc[1] < octloc[1]) && // forward
128  !(loc[2] < octloc[2])) // forward
129  {
130  quad = 0;
131  }
132  else if (!(loc[0] < octloc[0]) && // forward
133  !(loc[1] < octloc[1]) && // forward
134  !(loc[2] > octloc[2])) // back
135  {
136  quad = 1;
137  }
138  else if (!(loc[0] < octloc[0]) && // forward
139  !(loc[1] > octloc[1]) && // back
140  !(loc[2] < octloc[2])) // forward
141  {
142  quad = 2;
143  }
144  else if (!(loc[0] < octloc[0]) && // forward
145  !(loc[1] > octloc[1]) && // back
146  !(loc[2] > octloc[2])) // back
147  {
148  quad = 3;
149  }
150  else if (!(loc[0] > octloc[0]) && // back
151  !(loc[1] < octloc[1]) && // forward
152  !(loc[2] < octloc[2])) // forward
153  {
154  quad = 4;
155  }
156  else if (!(loc[0] > octloc[0]) && // back
157  !(loc[1] < octloc[1]) && // forward
158  !(loc[2] > octloc[2])) // back
159  {
160  quad = 5;
161  }
162  else if (!(loc[0] > octloc[0]) && // back
163  !(loc[1] > octloc[1]) && // back
164  !(loc[2] < octloc[2])) // forward
165  {
166  quad = 6;
167  }
168  else if (!(loc[0] > octloc[0]) && // back
169  !(loc[1] > octloc[1]) && // back
170  !(loc[2] > octloc[2])) // back
171  {
172  quad = 7;
173  }
174  else
175  {
176  ASSERTL0(false, "Cannot locate quadrant");
177  }
178 
179  n = n->GetChild(quad);
180 
181  if (n->IsLeaf())
182  {
183  found = true;
184  }
185  }
186 
187  return min(n->GetDelta(), tmp);
188 }
189 
190 NekDouble Octree::GetMinDelta()
191 {
192  NekDouble tmp = numeric_limits<double>::max();
193 
194  for (int i = 0; i < m_lsources.size(); i++)
195  {
196  tmp = min(m_lsources[i].delta, tmp);
197  }
198  return min(m_minDelta, tmp);
199 }
200 
201 void Octree::WriteOctree(string nm)
202 {
203  MeshSharedPtr oct = std::shared_ptr<Mesh>(new Mesh());
204  oct->m_expDim = 3;
205  oct->m_spaceDim = 3;
206  oct->m_nummode = 2;
207 
208  for (int i = 0; i < m_octants.size(); i++)
209  {
210  /*if(m_octants[i]->GetLocation() != eOnBoundary)
211  {
212  continue;
213  }*/
214 
215  vector<NodeSharedPtr> ns(8);
216 
217  ns[0] = std::shared_ptr<Node>(new Node(0, m_octants[i]->FX(eBack),
218  m_octants[i]->FX(eDown),
219  m_octants[i]->FX(eRight)));
220 
221  ns[1] = std::shared_ptr<Node>(new Node(0, m_octants[i]->FX(eForward),
222  m_octants[i]->FX(eDown),
223  m_octants[i]->FX(eRight)));
224 
225  ns[2] = std::shared_ptr<Node>(new Node(0, m_octants[i]->FX(eForward),
226  m_octants[i]->FX(eUp),
227  m_octants[i]->FX(eRight)));
228 
229  ns[3] = std::shared_ptr<Node>(new Node(0, m_octants[i]->FX(eBack),
230  m_octants[i]->FX(eUp),
231  m_octants[i]->FX(eRight)));
232 
233  ns[4] = std::shared_ptr<Node>(new Node(0, m_octants[i]->FX(eBack),
234  m_octants[i]->FX(eDown),
235  m_octants[i]->FX(eLeft)));
236 
237  ns[5] = std::shared_ptr<Node>(new Node(0, m_octants[i]->FX(eForward),
238  m_octants[i]->FX(eDown),
239  m_octants[i]->FX(eLeft)));
240 
241  ns[6] = std::shared_ptr<Node>(new Node(0, m_octants[i]->FX(eForward),
242  m_octants[i]->FX(eUp),
243  m_octants[i]->FX(eLeft)));
244 
245  ns[7] = std::shared_ptr<Node>(new Node(0, m_octants[i]->FX(eBack),
246  m_octants[i]->FX(eUp),
247  m_octants[i]->FX(eLeft)));
248 
249  vector<int> tags;
250  tags.push_back(0);
251  ElmtConfig conf(LibUtilities::eHexahedron, 1, false, false);
253  LibUtilities::eHexahedron, conf, ns, tags);
254  oct->m_element[3].push_back(E);
255  }
256 
257  ModuleSharedPtr mod =
259  mod->RegisterConfig("outfile", nm);
260  mod->ProcessVertices();
261  mod->ProcessEdges();
262  mod->ProcessFaces();
263  mod->ProcessElements();
264  mod->ProcessComposites();
265  mod->Process();
266 }
267 
268 void Octree::SubDivide()
269 {
270  bool repeat;
271  int ct = 1;
272 
273  m_numoct = 1;
274  m_masteroct->Subdivide(m_masteroct, m_numoct);
275 
276  if (m_mesh->m_verbose)
277  {
278  cout << "\tSubdivide iteration: ";
279  }
280 
281  do
282  {
283  if (m_mesh->m_verbose)
284  {
285  cout << "\r ";
286  cout << "\r";
287  cout << "\tSubdivide iteration: " << ct;
288  cout.flush();
289  }
290  ct++;
291  repeat = false;
292  m_octants.clear();
293  // grab a list of the leaves curently in the octree
294  m_masteroct->CompileLeaves(m_octants);
295 
296  VerifyNeigbours();
297 
298  // neeed to create a divide list, in the first list will be m_octants
299  // which need to
300  // subdivide based on curvature,
301  // in the next list will be ocants which need to subdivide to make sure
302  // level criteria is statisified for the previous list and so on
303  // the list will keep building till no more lists are required.
304  // the list will then be iterated through backwards to subdivide all the
305  // sublists in turn.
306  vector<vector<OctantSharedPtr> > dividelist;
307  set<int> inlist;
308  // build initial list
309  {
310  vector<OctantSharedPtr> sublist;
311  for (int i = 0; i < m_octants.size(); i++)
312  {
313  if (m_octants[i]->NeedDivide() &&
314  m_octants[i]->DX() / 4.0 > m_minDelta)
315  {
316  sublist.push_back(m_octants[i]);
317  inlist.insert(m_octants[i]->GetId());
318  repeat = true; // if there is a subdivision this whole
319  // process needs to be repeated
320  }
321  }
322  dividelist.push_back(sublist);
323  }
324  // then loop over building sublists until no more are required
325  int ct2 = 0;
326  while (true)
327  {
328  ct2++;
329  vector<OctantSharedPtr> newsublist,
330  previouslist = dividelist.back();
331  for (int i = 0; i < previouslist.size(); i++)
332  {
333  map<OctantFace, vector<OctantSharedPtr> > nlist =
334  previouslist[i]->GetNeigbours();
335  map<OctantFace, vector<OctantSharedPtr> >::iterator it;
336  for (it = nlist.begin(); it != nlist.end(); it++)
337  {
338  for (int j = 0; j < it->second.size(); j++)
339  {
340  if (previouslist[i]->DX() < it->second[j]->DX())
341  {
342  set<int>::iterator s =
343  inlist.find(it->second[j]->GetId());
344  if (s == inlist.end())
345  {
346  inlist.insert(it->second[j]->GetId());
347  newsublist.push_back(it->second[j]);
348  }
349  }
350  }
351  }
352  }
353  if (newsublist.size() == 0)
354  {
355  break;
356  }
357  else
358  {
359  dividelist.push_back(newsublist);
360  }
361  }
362 
363  vector<vector<OctantSharedPtr> >::reverse_iterator rit;
364  for (rit = dividelist.rbegin(); rit != dividelist.rend(); rit++)
365  {
366  vector<OctantSharedPtr> currentlist = *rit;
367  for (int i = 0; i < currentlist.size(); i++)
368  {
369  currentlist[i]->Subdivide(currentlist[i], m_numoct);
370  }
371  }
372  } while (repeat);
373 
374  if (m_mesh->m_verbose)
375  {
376  cout << endl;
377  }
378 }
379 
380 bool Octree::VerifyNeigbours()
381 {
382  // check all octant links to their neighbours
383  // at all times in the subdivision the set of neigbours must
384  // conform to a set of criteria such as smoothness in size
385  // this checks that
386  bool error = false;
387  for (int i = 0; i < m_octants.size(); i++)
388  {
389  bool valid = true;
390  map<OctantFace, vector<OctantSharedPtr> > nlist =
391  m_octants[i]->GetNeigbours();
392  map<OctantFace, vector<OctantSharedPtr> >::iterator it;
393  for (it = nlist.begin(); it != nlist.end(); it++)
394  {
395  if (it->second.size() == 0)
396  {
397  NekDouble expectedfx = 0.0;
398  switch (it->first)
399  {
400  case eUp:
401  expectedfx = m_centroid[1] + m_dim;
402  break;
403  case eDown:
404  expectedfx = m_centroid[1] - m_dim;
405  break;
406  case eLeft:
407  expectedfx = m_centroid[2] + m_dim;
408  break;
409  case eRight:
410  expectedfx = m_centroid[2] - m_dim;
411  break;
412  case eForward:
413  expectedfx = m_centroid[0] + m_dim;
414  break;
415  case eBack:
416  expectedfx = m_centroid[0] - m_dim;
417  break;
418  }
419  if (fabs(m_octants[i]->FX(it->first) - expectedfx) > 1E-6)
420  {
421  valid = false;
422  cout << "wall neigbour error" << endl;
423  cout << expectedfx << " " << m_octants[i]->FX(it->first)
424  << " " << it->first << endl;
425  }
426  }
427  else if (it->second.size() == 1)
428  {
429  if (!(m_octants[i]->DX() == it->second[0]->DX() ||
430  it->second[0]->DX() == 2.0 * m_octants[i]->DX()))
431  {
432  valid = false;
433  cout << " 1 neigbour error" << endl;
434  cout << m_octants[i]->DX() << " " << it->second[0]->DX()
435  << endl;
436  }
437  }
438  else if (it->second.size() == 4)
439  {
440  if (!(m_octants[i]->DX() / 2.0 == it->second[0]->DX()))
441  {
442  valid = false;
443  cout << "4 neibour error" << endl;
444  cout << m_octants[i]->DX() << " " << it->second[0]->DX()
445  << endl;
446  }
447  }
448  }
449  if (!valid)
450  {
451  error = true;
452  cout << "invalid neigbour config" << endl;
453  }
454  }
455  return !error;
456 }
457 
458 void Octree::SmoothSurfaceOctants()
459 {
460  // for all the m_octants which are surface containing and know their delta
461  // specification, look over all neighbours and ensure the specification
462  // between them is smooth
463  int ct = 0;
464 
465  do
466  {
467  ct = 0;
468  for (int i = 0; i < m_octants.size(); i++)
469  {
470  OctantSharedPtr oct = m_octants[i];
471 
472  if (oct->IsDeltaKnown())
473  {
474  vector<OctantSharedPtr> check;
475  map<OctantFace, vector<OctantSharedPtr> > nList =
476  oct->GetNeigbours();
477  map<OctantFace, vector<OctantSharedPtr> >::iterator it;
478 
479  for (it = nList.begin(); it != nList.end(); it++)
480  {
481  for (int j = 0; j < it->second.size(); j++)
482  {
483  if (it->second[j]->IsDeltaKnown() &&
484  it->second[j]->GetDelta() < oct->GetDelta() &&
485  ddx(oct, it->second[j]) > 0.2)
486  {
487  check.push_back(it->second[j]);
488  }
489  }
490  }
491 
492  // for each neighbour listed in check_id, figure out the
493  // smoothed
494  // delta, and asign the miminum of these to nodes[i].GetDelta()
495  if (check.size() > 0)
496  {
497  NekDouble deltaSM = numeric_limits<double>::max();
498  for (int j = 0; j < check.size(); j++)
499  {
500  NekDouble r = oct->Distance(check[j]);
501 
502  if (0.199 * r + check[j]->GetDelta() < deltaSM)
503  {
504  deltaSM = 0.199 * r + check[j]->GetDelta();
505  }
506  }
507  oct->SetDelta(deltaSM);
508  ct += 1;
509  }
510  }
511  }
512  } while (ct > 0);
513 }
514 
515 void Octree::PropagateDomain()
516 {
517  // until all m_octants know their delta specifcation and orientaion
518  // look over all m_octants and if their neighours know either their
519  // orientation
520  // or specifcation calculate one for this octant
521  int ct = 0;
522 
523  do
524  {
525  ct = 0;
526  for (int i = 0; i < m_octants.size(); i++)
527  {
528  OctantSharedPtr oct = m_octants[i];
529 
530  if (!oct->IsDeltaKnown())
531  { // if delta has not been asigned
532  vector<OctantSharedPtr> known;
533  map<OctantFace, vector<OctantSharedPtr> > nList =
534  oct->GetNeigbours();
535  map<OctantFace, vector<OctantSharedPtr> >::iterator it;
536 
537  for (it = nList.begin(); it != nList.end(); it++)
538  {
539  for (int j = 0; j < it->second.size(); j++)
540  {
541  if (it->second[j]->IsDeltaKnown())
542  {
543  known.push_back(it->second[j]);
544  }
545  }
546  }
547 
548  if (known.size() > 0)
549  {
550  vector<NekDouble> deltaPrime;
551  for (int j = 0; j < known.size(); j++)
552  {
553  NekDouble r = oct->Distance(known[j]);
554 
555  if (0.199 * r + known[j]->GetDelta() < m_maxDelta)
556  {
557  deltaPrime.push_back(0.199 * r +
558  known[j]->GetDelta());
559  }
560  else
561  {
562  deltaPrime.push_back(m_maxDelta);
563  }
564  }
565  NekDouble min = numeric_limits<double>::max();
566  for (int j = 0; j < deltaPrime.size(); j++)
567  {
568  if (deltaPrime[j] < min)
569  {
570  min = deltaPrime[j];
571  }
572  }
573  oct->SetDelta(min);
574  ct += 1;
575  deltaPrime.clear();
576  }
577  known.clear();
578  }
579 
580  if (oct->GetLocation() == eUnknown)
581  { // if the node does not know its location
582  vector<OctantSharedPtr> known;
583  map<OctantFace, vector<OctantSharedPtr> > nList =
584  oct->GetNeigbours();
585  map<OctantFace, vector<OctantSharedPtr> >::iterator it;
586 
587  for (it = nList.begin(); it != nList.end(); it++)
588  {
589  for (int j = 0; j < it->second.size(); j++)
590  {
591  if (it->second[j]->GetLocation() != eUnknown)
592  {
593  known.push_back(it->second[j]);
594  }
595  }
596  }
597 
598  if (known.size() > 0)
599  {
600  vector<OctantSharedPtr> isNotOnBound;
601  for (int j = 0; j < known.size(); j++)
602  {
603  if (known[j]->GetLocation() != eOnBoundary)
604  {
605  isNotOnBound.push_back(known[j]);
606  }
607  }
608 
609  if (isNotOnBound.size() > 0)
610  {
611  oct->SetLocation(isNotOnBound[0]->GetLocation());
612  }
613  else
614  {
615  NekDouble dist = numeric_limits<double>::max();
616 
617  OctantSharedPtr closest;
618 
619  bool f = false;
620  for (int j = 0; j < known.size(); j++)
621  {
622  if (oct->Distance(known[j]) < dist)
623  {
624  closest = known[j];
625  dist = oct->Distance(known[j]);
626  f = true;
627  }
628  }
629  ASSERTL0(f, "closest never set");
630 
631  SPBaseSharedPtr sp = closest->GetABoundPoint();
632 
633  Array<OneD, NekDouble> octloc, sploc, vec(3), uv, N;
634  int surf;
635  sp->GetCAD(surf, uv);
636  N = m_mesh->m_cad->GetSurf(surf)->N(uv);
637 
638  octloc = oct->GetLoc();
639  sploc = sp->GetLoc();
640 
641  vec[0] = octloc[0] - sploc[0];
642  vec[1] = octloc[1] - sploc[1];
643  vec[2] = octloc[2] - sploc[2];
644 
645  NekDouble dot =
646  vec[0] * N[0] + vec[1] * N[1] + vec[2] * N[2];
647 
648  if (dot <= 0.0)
649  {
650  oct->SetLocation(eOutside);
651  ct += 1;
652  }
653  else
654  {
655  oct->SetLocation(eInside);
656  ct += 1;
657  }
658  }
659  }
660  known.clear();
661  }
662  }
663 
664  } while (ct > 0);
665 
666  for (int i = 0; i < m_octants.size(); i++)
667  {
668  if (!m_octants[i]->IsDeltaKnown())
669  {
670  m_octants[i]->SetDelta(m_maxDelta);
671  }
672  }
673 }
674 
675 void Octree::SmoothAllOctants()
676 {
677  // until no more changes occur smooth the mesh specification between all
678  // m_octants not particualrly strictly
679  int ct = 0;
680 
681  do
682  {
683  ct = 0;
684  for (int i = 0; i < m_octants.size(); i++)
685  {
686  OctantSharedPtr oct = m_octants[i];
687 
688  vector<OctantSharedPtr> check;
689  map<OctantFace, vector<OctantSharedPtr> > nList =
690  oct->GetNeigbours();
691  map<OctantFace, vector<OctantSharedPtr> >::iterator it;
692  for (it = nList.begin(); it != nList.end(); it++)
693  {
694  for (int j = 0; j < it->second.size(); j++)
695  {
696  if (it->second[j]->GetDelta() < oct->GetDelta() &&
697  ddx(oct, it->second[j]) > 0.2)
698  {
699  check.push_back(it->second[j]);
700  }
701  }
702  }
703 
704  if (check.size() > 0)
705  {
706  NekDouble deltaSM = numeric_limits<double>::max();
707  for (int j = 0; j < check.size(); j++)
708  {
709  NekDouble r = oct->Distance(check[j]);
710 
711  if (0.199 * r + check[j]->GetDelta() < deltaSM)
712  {
713  deltaSM = 0.199 * r + check[j]->GetDelta();
714  }
715  }
716  oct->SetDelta(deltaSM);
717  ct += 1;
718  }
719  }
720 
721  } while (ct > 0);
722 }
723 
724 int Octree::CountElemt()
725 {
726  // by considering the volume of a tet evaluate the number of elements in the
727  // mesh
728 
729  NekDouble total = 0.0;
730 
731  Array<OneD, NekDouble> boundingBox = m_mesh->m_cad->GetBoundingBox();
732 
733  for (int i = 0; i < m_octants.size(); i++)
734  {
735  OctantSharedPtr oct = m_octants[i];
736  if (oct->GetLocation() == eInside)
737  {
738  total += 8.0 * oct->DX() * oct->DX() * oct->DX() /
739  (oct->GetDelta() * oct->GetDelta() * oct->GetDelta() /
740  6.0 / sqrt(2));
741  }
742  else if (oct->GetLocation() == eOnBoundary)
743  {
744  NekDouble vol = 1.0;
745  if (oct->FX(eBack) < boundingBox[1] &&
746  oct->FX(eForward) > boundingBox[0])
747  {
748  // then there is some over lap in x
749  NekDouble min, max;
750  if (oct->FX(eBack) > boundingBox[0])
751  {
752  min = oct->FX(eBack);
753  }
754  else
755  {
756  min = boundingBox[0];
757  }
758  if (boundingBox[1] < oct->FX(eForward))
759  {
760  max = boundingBox[1];
761  }
762  else
763  {
764  max = oct->FX(eForward);
765  }
766  vol *= (max - min);
767  }
768  else
769  {
770  vol *= 0.0;
771  }
772 
773  if (oct->FX(eDown) < boundingBox[3] &&
774  oct->FX(eUp) > boundingBox[2])
775  {
776  // then there is some over lap in x
777  NekDouble min, max;
778  if (oct->FX(eDown) > boundingBox[2])
779  {
780  min = oct->FX(eDown);
781  }
782  else
783  {
784  min = boundingBox[2];
785  }
786  if (boundingBox[3] < oct->FX(eUp))
787  {
788  max = boundingBox[3];
789  }
790  else
791  {
792  max = oct->FX(eUp);
793  }
794  vol *= (max - min);
795  }
796  else
797  {
798  vol *= 0.0;
799  }
800 
801  if (oct->FX(eRight) < boundingBox[5] &&
802  oct->FX(eLeft) > boundingBox[4])
803  {
804  // then there is some over lap in x
805  NekDouble min, max;
806  if (oct->FX(eRight) > boundingBox[4])
807  {
808  min = oct->FX(eRight);
809  }
810  else
811  {
812  min = boundingBox[4];
813  }
814  if (boundingBox[5] < oct->FX(eLeft))
815  {
816  max = boundingBox[5];
817  }
818  else
819  {
820  max = oct->FX(eLeft);
821  }
822  vol *= (max - min);
823  }
824  else
825  {
826  vol *= 0.0;
827  }
828  total += vol / 2.0 / (oct->GetDelta() * oct->GetDelta() *
829  oct->GetDelta() / 6.0 / sqrt(2));
830  }
831  }
832 
833  return int(total);
834 }
835 
836 void Octree::CompileSourcePointList()
837 {
838  int totalEnt = 0;
839  if(m_mesh->m_cad->Is2D())
840  {
841  totalEnt += m_mesh->m_cad->GetNumCurve();
842  for (int i = 1; i <= m_mesh->m_cad->GetNumCurve(); i++)
843  {
844  if (m_mesh->m_verbose)
845  {
846  LibUtilities::PrintProgressbar(i, totalEnt,
847  "\tCompiling source points");
848  }
849 
850  CADCurveSharedPtr curve = m_mesh->m_cad->GetCurve(i);
851  Array<OneD, NekDouble> bds = curve->GetBounds();
852  //this works assuming the curves are not distorted
853  int samples = ceil(curve->Length(bds[0],bds[1]) / m_minDelta) * 2;
854  samples = max(40, samples);
855  NekDouble dt = (bds[1] - bds[0]) / (samples + 1);
856  for (int j = 1; j < samples - 1; j++) // dont want first and last point
857  {
858  NekDouble t = bds[0] + dt * j;
859  NekDouble C = curve->Curvature(t);
860 
861  Array<OneD, NekDouble> loc = curve->P(t);
862 
863  vector<pair<CADSurfSharedPtr, CADOrientation::Orientation> > ss =
864  curve->GetAdjSurf();
865  Array<OneD, NekDouble> uv = ss[0].first->locuv(loc);
866 
867  if (C != 0.0)
868  {
869  NekDouble del = 2.0 * (1.0 / C) * sqrt(m_eps * (2.0 - m_eps));
870 
871  if (del > m_maxDelta)
872  {
873  del = m_maxDelta;
874  }
875  if (del < m_minDelta)
876  {
877  del = m_minDelta;
878  }
879 
880  CPointSharedPtr newCPoint =
882  ss[0].first->GetId(), uv, loc, del);
883 
884  m_SPList.push_back(newCPoint);
885  }
886  else
887  {
888  BPointSharedPtr newBPoint =
890  ss[0].first->GetId(), uv, loc);
891 
892  m_SPList.push_back(newBPoint);
893  }
894  }
895  }
896  }
897  else
898  {
899  totalEnt = m_mesh->m_cad->GetNumSurf();
900  for (int i = 1; i <= totalEnt; i++)
901  {
902  if (m_mesh->m_verbose)
903  {
904  LibUtilities::PrintProgressbar(i, totalEnt,
905  "\tCompiling source points");
906  }
907 
908  CADSurfSharedPtr surf = m_mesh->m_cad->GetSurf(i);
909  Array<OneD, NekDouble> bounds = surf->GetBounds();
910 
911  // to figure out the amount of curvature sampling to be conducted on
912  // each parameter plane the surface is first sampled with a 40x40
913  // grid the real space lengths of this grid are analyzed to find the
914  // largest stretching in the u and v directions
915  // this stretching is then considered with the mindelta user input
916  // to find a number of sampling points in each direction which
917  // ensures that in the final octree each surface octant will have at
918  // least one sample point within its volume.
919  // the 40x40 grid is used to ensure each surface has a minimum of
920  // 40x40 samples.
921  NekDouble du = (bounds[1] - bounds[0]) / (40 - 1);
922  NekDouble dv = (bounds[3] - bounds[2]) / (40 - 1);
923 
924  NekDouble DeltaU = 0.0;
925  NekDouble DeltaV = 0.0;
926 
927  Array<TwoD, Array<OneD, NekDouble> > samplepoints(40, 40);
928 
929  for (int j = 0; j < 40; j++)
930  {
931  for (int k = 0; k < 40; k++)
932  {
934  uv[0] = k * du + bounds[0];
935  uv[1] = j * dv + bounds[2];
936  if (j == 40 - 1)
937  uv[1] = bounds[3];
938  if (k == 40 - 1)
939  uv[0] = bounds[1];
940  samplepoints[k][j] = surf->P(uv);
941  }
942  }
943 
944  for (int j = 0; j < 40 - 1; j++)
945  {
946  for (int k = 0; k < 40 - 1; k++)
947  {
948  NekDouble deltau = sqrt(
949  (samplepoints[k][j][0] - samplepoints[k + 1][j][0]) *
950  (samplepoints[k][j][0] - samplepoints[k + 1][j][0]) +
951  (samplepoints[k][j][1] - samplepoints[k + 1][j][1]) *
952  (samplepoints[k][j][1] - samplepoints[k + 1][j][1]) +
953  (samplepoints[k][j][2] - samplepoints[k + 1][j][2]) *
954  (samplepoints[k][j][2] - samplepoints[k + 1][j][2]));
955  NekDouble deltav = sqrt(
956  (samplepoints[k][j][0] - samplepoints[k][j + 1][0]) *
957  (samplepoints[k][j][0] - samplepoints[k][j + 1][0]) +
958  (samplepoints[k][j][1] - samplepoints[k][j + 1][1]) *
959  (samplepoints[k][j][1] - samplepoints[k][j + 1][1]) +
960  (samplepoints[k][j][2] - samplepoints[k][j + 1][2]) *
961  (samplepoints[k][j][2] - samplepoints[k][j + 1][2]));
962 
963  if (deltau > DeltaU)
964  DeltaU = deltau;
965  if (deltav > DeltaV)
966  DeltaV = deltav;
967  }
968  }
969 
970  // these are the acutal number of sample points in each parametric
971  // direction
972  int nu = ceil(DeltaU * 40 / m_minDelta) * 2;
973  int nv = ceil(DeltaV * 40 / m_minDelta) * 2;
974  nu = max(40, nu);
975  nv = max(40, nv);
976 
977  for (int j = 0; j < nu; j++)
978  {
979  for (int k = 0; k < nv; k++)
980  {
982  uv[0] = (bounds[1] - bounds[0]) / (nu - 1) * j + bounds[0];
983  uv[1] = (bounds[3] - bounds[2]) / (nv - 1) * k + bounds[2];
984 
985  // this prevents round off error at the end of the surface
986  // may not be neseercary but works
987  if (j == nu - 1)
988  uv[0] = bounds[1];
989  if (k == nv - 1)
990  uv[1] = bounds[3];
991 
992  NekDouble C = surf->Curvature(uv);
993 
994  // create new point based on smallest R, flat surfaces have
995  // k=0 but still need a point for element estimation
996  if (C != 0.0)
997  {
998  NekDouble del =
999  2.0 * (1.0 / C) * sqrt(m_eps * (2.0 - m_eps));
1000 
1001  if (del > m_maxDelta)
1002  {
1003  del = m_maxDelta;
1004  }
1005  if (del < m_minDelta)
1006  {
1007  del = m_minDelta;
1008  }
1009 
1010  CPointSharedPtr newCPoint =
1012  surf->GetId(), uv, surf->P(uv), del);
1013 
1014  m_SPList.push_back(newCPoint);
1015  }
1016  else
1017  {
1018  BPointSharedPtr newBPoint =
1020  surf->GetId(), uv, surf->P(uv));
1021 
1022  m_SPList.push_back(newBPoint);
1023  }
1024  }
1025  }
1026  }
1027  }
1028  if (m_mesh->m_verbose)
1029  {
1030  cout << endl;
1031  }
1032 
1033  if (m_refinement.size() > 0)
1034  {
1035  if (m_mesh->m_verbose)
1036  {
1037  cout << "\t\tModifying based on refinement lines" << endl;
1038  }
1039  // now deal with the user defined spacing
1040  vector<string> lines;
1041 
1042  boost::split(lines, m_refinement, boost::is_any_of(":"));
1043 
1044  for (int i = 0; i < lines.size(); i++)
1045  {
1046  vector<NekDouble> data;
1047  ParseUtils::GenerateVector(lines[i], data);
1048 
1049  Array<OneD, NekDouble> x1(3), x2(3);
1050 
1051  x1[0] = data[0];
1052  x1[1] = data[1];
1053  x1[2] = data[2];
1054  x2[0] = data[3];
1055  x2[1] = data[4];
1056  x2[2] = data[5];
1057 
1058  m_lsources.push_back(linesource(x1, x2, data[6], data[7]));
1059  }
1060 
1061  // this takes any existing sourcepoints within the influence range
1062  // and modifies them
1063  /*for (int i = 0; i < m_SPList.size(); i++)
1064  {
1065  for (int j = 0; j < m_lsources.size(); j++)
1066  {
1067  if (m_lsources[j].withinRange(m_SPList[i]->GetLoc()))
1068  {
1069  if(m_SPList[i]->GetType() == ePBoundary)
1070  {
1071  BPointSharedPtr bp =
1072  std::dynamic_pointer_cast<BPoint>
1073  (m_SPList[i]);
1074 
1075  m_SPList[i] = bp->ChangeType();
1076 
1077  }
1078  m_SPList[i]->SetDelta(m_lsources[j].delta);
1079  }
1080  }
1081  }*/
1082  /// TODO add extra source points from the line souce to the octree
1083  }
1084 }
1085 
1087 {
1088  return fabs(i->GetDelta() - j->GetDelta()) / i->Distance(j);
1089 }
1090 }
1091 }
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
std::shared_ptr< BPoint > BPointSharedPtr
int PrintProgressbar(const int position, const int goal, const std::string message, int lastprogress=-1)
Prints a progressbar.
Definition: Progressbar.hpp:67
General purpose memory allocation routines with the ability to allocate from thread specific memory p...
std::shared_ptr< Module > ModuleSharedPtr
STL namespace.
std::shared_ptr< Mesh > MeshSharedPtr
Shared pointer to a mesh.
Definition: Mesh.h:156
ElementFactory & GetElementFactory()
Definition: Element.cpp:44
tBaseSharedPtr CreateInstance(tKey idKey, tParam... args)
Create an instance of the class referred to by idKey.
Definition: NekFactory.hpp:144
std::pair< ModuleType, std::string > ModuleKey
std::shared_ptr< Element > ElementSharedPtr
Definition: Edge.h:49
std::shared_ptr< CADCurve > CADCurveSharedPtr
Definition: CADCurve.h:219
std::shared_ptr< CPoint > CPointSharedPtr
double NekDouble
std::shared_ptr< Octant > OctantSharedPtr
Definition: Octant.h:73
std::shared_ptr< SPBase > SPBaseSharedPtr
ModuleFactory & GetModuleFactory()