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