Nektar++
LibUtilities/BasicUtils/Interpolator.cpp
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // File: Interpolator.cpp
4 //
5 // For more information, please see: http://www.nektar.info/
6 //
7 // The MIT License
8 //
9 // Copyright (c) 2016 Kilian Lackhove
10 // Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
11 // Department of Aeronautics, Imperial College London (UK), and Scientific
12 // Computing and Imaging Institute, University of Utah (USA).
13 //
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: Interpolator
33 //
34 ////////////////////////////////////////////////////////////////////////////////
35 
37 #include <boost/geometry.hpp>
38 
39 using namespace std;
40 
41 namespace bg = boost::geometry;
42 namespace bgi = boost::geometry::index;
43 
44 namespace Nektar
45 {
46 namespace LibUtilities
47 {
48 
49 /**
50  * @brief Compute interpolation weights without doing any interpolation
51  *
52  * @param ptsInField input field
53  * @param ptsOutField output field
54  * @param reuseTree if an r-tree has been constructed already, reuse it
55  * (e.g. for repeated calls over the same input points).
56  *
57  * In and output fields must have the same dimension. The most suitable
58  * algorithm is chosen automatically if it wasnt set explicitly.
59  */
60 void Interpolator::CalcWeights(const LibUtilities::PtsFieldSharedPtr ptsInField,
62  bool reuseTree)
63 {
64  ASSERTL0(ptsInField->GetDim() <= m_dim, "too many dimesions in inField");
65  ASSERTL0(ptsOutField->GetDim() <= m_dim, "too many dimesions in outField");
66 
67  m_ptsInField = ptsInField;
68  m_ptsOutField = ptsOutField;
69 
70  size_t nOutPts = m_ptsOutField->GetNpoints();
71  int lastProg = 0;
72 
73  // set a default method
74  if (m_method == eNoMethod)
75  {
76  if (m_ptsInField->GetDim() == 3)
77  {
78  m_method = eNearestNeighbour;
79  }
80  else if (m_ptsInField->GetDim() == 1 || m_coordId >= 0)
81  {
82  m_method = eQuadratic;
83  }
84  else
85  {
86  m_method = eShepard;
87  }
88  }
89 
90  if ((!m_rtree || !reuseTree) && m_method != eQuadratic)
91  {
92  SetupTree();
93  }
94 
95  switch (m_method)
96  {
97  case eNearestNeighbour:
98  {
99  m_weights = Array<TwoD, NekDouble>(nOutPts, 1, 0.0);
100  m_neighInds =
101  Array<TwoD, unsigned int>(nOutPts, 1, (unsigned int)0);
102 
103  for (size_t i = 0; i < nOutPts; ++i)
104  {
105  Array<OneD, NekDouble> tmp(m_dim, 0.0);
106  for (size_t j = 0; j < m_ptsOutField->GetDim(); ++j)
107  {
108  tmp[j] = m_ptsOutField->GetPointVal(j, i);
109  }
110  PtsPoint searchPt(i, tmp, 1E30);
111 
112  CalcW_NNeighbour(searchPt);
113 
114  int progress = int(100 * i / nOutPts);
115  if (m_progressCallback && progress > lastProg)
116  {
117  m_progressCallback(i, nOutPts);
118  lastProg = progress;
119  }
120  }
121 
122  break;
123  }
124 
125  case eQuadratic:
126  {
127  ASSERTL0(m_ptsInField->GetDim() == 1 || m_coordId >= 0,
128  "not implemented");
129 
130  m_weights = Array<TwoD, NekDouble>(nOutPts, 3, 0.0);
131  m_neighInds =
132  Array<TwoD, unsigned int>(nOutPts, 3, (unsigned int)0);
133 
134  for (size_t i = 0; i < nOutPts; ++i)
135  {
136  Array<OneD, NekDouble> tmp(m_dim, 0.0);
137  for (size_t j = 0; j < m_ptsOutField->GetDim(); ++j)
138  {
139  tmp[j] = m_ptsOutField->GetPointVal(j, i);
140  }
141  PtsPoint searchPt(i, tmp, 1E30);
142 
143  if (m_ptsInField->GetNpoints() <= 2)
144  {
145  CalcW_Linear(searchPt, m_coordId);
146  }
147  else
148  {
149  CalcW_Quadratic(searchPt, m_coordId);
150  }
151 
152  int progress = int(100 * i / nOutPts);
153  if (m_progressCallback && progress > lastProg)
154  {
155  m_progressCallback(i, nOutPts);
156  lastProg = progress;
157  }
158  }
159 
160  break;
161  }
162 
163  case eShepard:
164  {
165  int numPts = m_ptsInField->GetDim();
166  numPts = 1 << numPts; // 2 ^ numPts
167  numPts = min(numPts, int(m_ptsInField->GetNpoints() / 2));
168 
169  m_weights = Array<TwoD, NekDouble>(nOutPts, numPts, 0.0);
170  m_neighInds =
171  Array<TwoD, unsigned int>(nOutPts, numPts, (unsigned int)0);
172 
173  for (size_t i = 0; i < nOutPts; ++i)
174  {
175  Array<OneD, NekDouble> tmp(m_dim, 0.0);
176  for (size_t j = 0; j < m_ptsOutField->GetDim(); ++j)
177  {
178  tmp[j] = m_ptsOutField->GetPointVal(j, i);
179  }
180  PtsPoint searchPt(i, tmp, 1E30);
181 
182  CalcW_Shepard(searchPt, numPts);
183 
184  int progress = int(100 * i / nOutPts);
185  if (m_progressCallback && progress > lastProg)
186  {
187  m_progressCallback(i, nOutPts);
188  lastProg = progress;
189  }
190  }
191 
192  break;
193  }
194 
195  case eGauss:
196  {
197  ASSERTL0(m_filtWidth > NekConstants::kNekZeroTol,
198  "No filter width set");
199  // use m_filtWidth as FWHM
200  NekDouble sigma = m_filtWidth * 0.4246609001;
201 
202  m_maxPts = min(m_maxPts, int(m_ptsInField->GetNpoints() / 2));
203 
204  m_weights = Array<TwoD, NekDouble>(nOutPts, m_maxPts, 0.0);
205  m_neighInds =
206  Array<TwoD, unsigned int>(nOutPts, m_maxPts, (unsigned int)0);
207 
208  for (size_t i = 0; i < nOutPts; ++i)
209  {
210  Array<OneD, NekDouble> tmp(m_dim, 0.0);
211  for (size_t j = 0; j < m_ptsOutField->GetDim(); ++j)
212  {
213  tmp[j] = m_ptsOutField->GetPointVal(j, i);
214  }
215  PtsPoint searchPt(i, tmp, 1E30);
216 
217  CalcW_Gauss(searchPt, sigma, m_maxPts);
218 
219  int progress = int(100 * i / nOutPts);
220  if (m_progressCallback && progress > lastProg)
221  {
222  m_progressCallback(i, nOutPts);
223  lastProg = progress;
224  }
225  }
226 
227  break;
228  }
229 
230  default:
231  NEKERROR(ErrorUtil::efatal, "Invalid interpolation m_method");
232  break;
233  }
234 }
235 
236 /**
237  * @brief Interpolate from a pts field to a pts field
238  *
239  * @param ptsInField input field
240  * @param ptsOutField output field
241  *
242  * In and output fields must have the same dimension and number of fields.
243  * The most suitable algorithm is chosen automatically if it wasnt set
244  * explicitly.
245  */
246 void Interpolator::Interpolate(const LibUtilities::PtsFieldSharedPtr ptsInField,
247  LibUtilities::PtsFieldSharedPtr &ptsOutField)
248 {
249  ASSERTL0(ptsInField->GetNFields() == ptsOutField->GetNFields(),
250  "number of fields does not match");
251  ASSERTL0(ptsInField->GetDim() <= m_dim, "too many dimesions in inField");
252  ASSERTL0(ptsOutField->GetDim() <= m_dim, "too many dimesions in outField");
253 
254  m_ptsInField = ptsInField;
255  m_ptsOutField = ptsOutField;
256 
257  if (m_weights.GetRows() == 0)
258  {
259  CalcWeights(m_ptsInField, m_ptsOutField);
260  }
261 
262  ASSERTL0(m_weights.GetRows() == m_ptsOutField->GetNpoints(),
263  "weights dimension mismatch");
264 
265  size_t nFields = m_ptsOutField->GetNFields();
266  size_t nOutPts = m_ptsOutField->GetNpoints();
267  size_t inDim = m_ptsInField->GetDim();
268 
269  // interpolate points and transform
270  for (size_t i = 0; i < nFields; ++i)
271  {
272  for (size_t j = 0; j < nOutPts; ++j)
273  {
274  size_t nPts = m_weights.GetColumns();
275 
276  // skip if there were no neighbours found for this point
277  if (nPts == 0)
278  {
279  continue;
280  }
281 
282  NekDouble val = 0.0;
283  for (size_t k = 0; k < nPts; ++k)
284  {
285  size_t nIdx = m_neighInds[j][k];
286  val += m_weights[j][k] *
287  m_ptsInField->GetPointVal(inDim + i, nIdx);
288  }
289  m_ptsOutField->SetPointVal(m_ptsOutField->GetDim() + i, j, val);
290  }
291  }
292 }
293 
294 int Interpolator::GetDim() const
295 {
296  return m_dim;
297 }
298 
299 int Interpolator::GetCoordId() const
300 {
301  return m_coordId;
302 }
303 
304 NekDouble Interpolator::GetFiltWidth() const
305 {
306  return m_filtWidth;
307 }
308 
309 InterpMethod Interpolator::GetInterpMethod() const
310 {
311  return m_method;
312 }
313 
314 LibUtilities::PtsFieldSharedPtr Interpolator::GetInField() const
315 {
316  return m_ptsInField;
317 }
318 
319 LibUtilities::PtsFieldSharedPtr Interpolator::GetOutField() const
320 {
321  return m_ptsOutField;
322 }
323 
324 void Interpolator::PrintStatistics()
325 {
326  int meanN = 0;
327  for (int i = 0; i < m_neighInds.GetRows(); ++i)
328  {
329  for (int j = 0; j < m_neighInds.GetColumns(); ++j)
330  {
331  if (m_neighInds[i][j] > 0)
332  {
333  meanN += 1;
334  }
335  }
336  }
337 
338  cout << "Number of points: " << m_neighInds.GetRows() << endl;
339  if (m_neighInds.GetRows() > 0)
340  {
341  cout << "mean Number of Neighbours per point: "
342  << meanN / m_neighInds.GetRows() << endl;
343  }
344 }
345 
346 /**
347  * @brief Computes interpolation weights using gaussian interpolation
348  *
349  * @param searchPt point for which the weights are computed
350  * @param sigma standard deviation of the gauss function
351  *
352  * Performs an interpolation using gauss weighting. Ideal for filtering fields.
353  * The filter width should be half the FWHM (= 1.1774 sigma) and must be set in
354  * the constructor of the Interpolator class.
355  */
356 void Interpolator::CalcW_Gauss(const PtsPoint &searchPt, const NekDouble sigma,
357  const int maxPts)
358 {
359  // find nearest neighbours
360  vector<PtsPoint> neighbourPts;
361  FindNeighbours(searchPt, neighbourPts, 4 * sigma, maxPts);
362  size_t numPts = neighbourPts.size();
363 
364  // handle the cases that there was no or just one point within 4 * sigma
365  if (numPts == 0)
366  {
367  return;
368  }
369  if (numPts == 1)
370  {
371  m_neighInds[searchPt.idx][0] = neighbourPts.front().idx;
372  m_weights[searchPt.idx][0] = 1.0;
373 
374  return;
375  }
376 
377  NekDouble sigmaNew = 0.25 * neighbourPts.back().dist;
378 
379  for (size_t i = 0; i < numPts; i++)
380  {
381  m_neighInds[searchPt.idx][i] = neighbourPts.at(i).idx;
382  }
383 
384  NekDouble wSum = 0.0;
385  NekDouble ts2 = 2.0 * sigmaNew * sigmaNew;
386  for (size_t i = 0; i < numPts; ++i)
387  {
388  m_weights[searchPt.idx][i] =
389  exp(-1.0 * neighbourPts[i].dist * neighbourPts[i].dist / ts2);
390  wSum += m_weights[searchPt.idx][i];
391  }
392 
393  for (size_t i = 0; i < numPts; ++i)
394  {
395  m_weights[searchPt.idx][i] = m_weights[searchPt.idx][i] / wSum;
396  }
397 }
398 
399 /**
400  * @brief Computes interpolation weights using linear interpolation
401  *
402  * @param searchPt point for which the weights are computed
403  * @param m_coordId coordinate id along which the interpolation should be
404  * performed
405  *
406  * Currently, only implemented for 1D
407  */
408 void Interpolator::CalcW_Linear(const PtsPoint &searchPt, int m_coordId)
409 {
410  int npts = m_ptsInField->GetNpoints();
411  int i;
412 
413  NekDouble coord = searchPt.coords[m_coordId];
414 
415  for (i = 0; i < npts - 1; ++i)
416  {
417  if ((m_ptsInField->GetPointVal(0, i) <=
418  (coord + NekConstants::kNekZeroTol)) &&
419  (coord <=
420  (m_ptsInField->GetPointVal(0, i + 1) + NekConstants::kNekZeroTol)))
421  {
422  NekDouble pdiff = m_ptsInField->GetPointVal(0, i + 1) -
423  m_ptsInField->GetPointVal(0, i);
424 
425  m_neighInds[searchPt.idx][0] = i;
426  m_neighInds[searchPt.idx][1] = i + 1;
427 
428  m_weights[searchPt.idx][0] =
429  (m_ptsInField->GetPointVal(0, i + 1) - coord) / pdiff;
430  m_weights[searchPt.idx][1] =
431  (coord - m_ptsInField->GetPointVal(0, i)) / pdiff;
432 
433  break;
434  }
435  }
436  ASSERTL0(i != npts - 1, "Failed to find coordinate " +
437  boost::lexical_cast<string>(coord) +
438  " within provided input points");
439 }
440 
441 /**
442  * @brief Computes interpolation weights using nearest neighbour interpolation
443  *
444  * @param searchPt point for which the weights are computed
445  * @param m_coordId coordinate id along which the interpolation should be
446  * performed
447  *
448  */
449 void Interpolator::CalcW_NNeighbour(const PtsPoint &searchPt)
450 {
451  // find nearest neighbours
452  vector<PtsPoint> neighbourPts;
453  // TODO: we currently dont handle the case when there are more than one
454  // most distant points (of same distance)
455  FindNNeighbours(searchPt, neighbourPts, 1);
456 
457  m_neighInds[searchPt.idx][0] = neighbourPts[0].idx;
458  m_weights[searchPt.idx][0] = 1.0;
459 }
460 
461 /**
462  * @brief Computes interpolation weights using linear interpolation
463  *
464  * @param searchPt point for which the weights are computed
465  * @param m_coordId coordinate id along which the interpolation should be
466  * performed
467  *
468  * The algorithm is based on Shepard, D. (1968). A two-dimensional interpolation
469  * function for irregularly-spaced data. Proceedings of the 1968 23rd ACM
470  * National Conference. pp. 517–524.
471  *
472  * In order to save memory, for n dimesnions, only 2^n points are considered.
473  * Contrary to Shepard, we use a fixed number of points with fixed weighting
474  * factors 1/d^n.
475  */
476 void Interpolator::CalcW_Shepard(const PtsPoint &searchPt, int numPts)
477 {
478  // find nearest neighbours
479  vector<PtsPoint> neighbourPts;
480  FindNNeighbours(searchPt, neighbourPts, numPts);
481 
482  for (int i = 0; i < neighbourPts.size(); i++)
483  {
484  m_neighInds[searchPt.idx][i] = neighbourPts[i].idx;
485  }
486 
487  // In case d < kVertexTheSameDouble ( d^2 < kNekSqrtTol), use the exact
488  // point and return
489  for (int i = 0; i < neighbourPts.size(); ++i)
490  {
491  if (neighbourPts[i].dist <= NekConstants::kNekZeroTol)
492  {
493  m_weights[searchPt.idx][i] = 1.0;
494  return;
495  }
496  }
497 
498  NekDouble wSum = 0.0;
499  for (int i = 0; i < neighbourPts.size(); ++i)
500  {
501  m_weights[searchPt.idx][i] = 1 / pow(double(neighbourPts[i].dist),
502  double(m_ptsInField->GetDim()));
503  wSum += m_weights[searchPt.idx][i];
504  }
505 
506  for (int i = 0; i < neighbourPts.size(); ++i)
507  {
508  m_weights[searchPt.idx][i] = m_weights[searchPt.idx][i] / wSum;
509  }
510 }
511 
512 /**
513  * @brief Computes interpolation weights using quadratic interpolation
514  *
515  * @param searchPt point for which the weights are computed
516  * @param m_coordId coordinate id along which the interpolation should be
517  * performed
518  *
519  * Currently, only implemented for 1D. Falls back to linear interpolation if
520  * only 2
521  * values are available.
522  */
523 void Interpolator::CalcW_Quadratic(const PtsPoint &searchPt, int m_coordId)
524 {
525  int npts = m_ptsInField->GetNpoints();
526  int i;
527 
528  NekDouble coord = searchPt.coords[m_coordId];
529 
530  for (i = 0; i < npts - 1; ++i)
531  {
532  if ((m_ptsInField->GetPointVal(0, i) <=
533  (coord + NekConstants::kNekZeroTol)) &&
534  (coord <=
535  (m_ptsInField->GetPointVal(0, i + 1) + NekConstants::kNekZeroTol)))
536  {
537  NekDouble pdiff = m_ptsInField->GetPointVal(0, i + 1) -
538  m_ptsInField->GetPointVal(0, i);
539  NekDouble h1, h2, h3;
540 
541  if (i < npts - 2)
542  {
543  // forwards stencil
544  NekDouble pdiff2 = m_ptsInField->GetPointVal(0, i + 2) -
545  m_ptsInField->GetPointVal(0, i + 1);
546 
547  h1 = (m_ptsInField->GetPointVal(0, i + 1) - coord) *
548  (m_ptsInField->GetPointVal(0, i + 2) - coord) /
549  (pdiff * (pdiff + pdiff2));
550  h2 = (coord - m_ptsInField->GetPointVal(0, i)) *
551  (m_ptsInField->GetPointVal(0, i + 2) - coord) /
552  (pdiff * pdiff2);
553  h3 = (coord - m_ptsInField->GetPointVal(0, i)) *
554  (coord - m_ptsInField->GetPointVal(0, i + 1)) /
555  ((pdiff + pdiff2) * pdiff2);
556 
557  m_neighInds[searchPt.idx][0] = i;
558  m_neighInds[searchPt.idx][1] = i + 1;
559  m_neighInds[searchPt.idx][2] = i + 2;
560  }
561  else
562  {
563  // backwards stencil
564  NekDouble pdiff2 = m_ptsInField->GetPointVal(0, i) -
565  m_ptsInField->GetPointVal(0, i - 1);
566 
567  h1 = (m_ptsInField->GetPointVal(0, i + 1) - coord) *
568  (coord - m_ptsInField->GetPointVal(0, i - 1)) /
569  (pdiff * pdiff2);
570  h2 = (coord - m_ptsInField->GetPointVal(0, i)) *
571  (coord - m_ptsInField->GetPointVal(0, i - 1)) /
572  (pdiff * (pdiff + pdiff2));
573  h3 = (m_ptsInField->GetPointVal(0, i) - coord) *
574  (m_ptsInField->GetPointVal(0, i + 1) - coord) /
575  ((pdiff + pdiff2) * pdiff);
576 
577  m_neighInds[searchPt.idx][0] = i;
578  m_neighInds[searchPt.idx][1] = i + 1;
579  m_neighInds[searchPt.idx][2] = i - 1;
580  }
581 
582  m_weights[searchPt.idx][0] = h1;
583  m_weights[searchPt.idx][1] = h2;
584  m_weights[searchPt.idx][2] = h3;
585 
586  break;
587  }
588  }
589  ASSERTL0(i != npts - 1, "Failed to find coordinate " +
590  boost::lexical_cast<string>(coord) +
591  " within provided input points");
592 }
593 
594 void Interpolator::SetupTree()
595 {
596  std::vector<PtsPointPair> inPoints;
597  for (int i = 0; i < m_ptsInField->GetNpoints(); ++i)
598  {
599  Array<OneD, NekDouble> coords(3, 0.0);
600  for (int j = 0; j < m_ptsInField->GetDim(); ++j)
601  {
602  coords[j] = m_ptsInField->GetPointVal(j, i);
603  }
604  inPoints.push_back(
605  PtsPointPair(BPoint(coords[0], coords[1], coords[2]), i));
606  }
608  m_rtree->insert(inPoints.begin(), inPoints.end());
609 
610  // remove duplicates from tree
611  for (auto &it : inPoints)
612  {
613  std::vector<PtsPointPair> result;
614 
615  // find nearest 2 points (2 because one of these might be the one we
616  // are
617  // checking)
618  m_rtree->query(bgi::nearest(it.first, 2), std::back_inserter(result));
619 
620  // in case any of these 2 points is too close, remove the current
621  // point
622  // from the tree
623  for (auto &it2 : result)
624  {
625  if (it.second != it2.second &&
626  bg::distance(it.first, it2.first) <= NekConstants::kNekZeroTol)
627  {
628  m_rtree->remove(it);
629  break;
630  }
631  }
632  }
633 }
634 
635 /**
636  * @brief Finds the neares neighbours of a point
637  *
638  * @param searchPt point for which the neighbours are searched
639  * @param neighbourPts possible neighbour points
640  * @param numPts limits the number of neighbours found to the numPts
641  * nearest ones
642  *
643  */
644 void Interpolator::FindNNeighbours(const PtsPoint &searchPt,
645  vector<PtsPoint> &neighbourPts,
646  const unsigned int numPts)
647 {
648  std::vector<PtsPointPair> result;
649  BPoint searchBPoint(searchPt.coords[0], searchPt.coords[1],
650  searchPt.coords[2]);
651  m_rtree->query(bgi::nearest(searchBPoint, numPts),
652  std::back_inserter(result));
653 
654  // massage into or own format
655  for (int i = 0; i < result.size(); ++i)
656  {
657  int idx = result[i].second;
658  Array<OneD, NekDouble> coords(m_dim, 0.0);
659  for (int j = 0; j < m_ptsInField->GetDim(); ++j)
660  {
661  coords[j] = m_ptsInField->GetPointVal(j, idx);
662  }
663  NekDouble d = bg::distance(searchBPoint, result[i].first);
664  neighbourPts.push_back(PtsPoint(idx, coords, d));
665  }
666 
667  sort(neighbourPts.begin(), neighbourPts.end());
668 }
669 
670 /**
671  * @brief Finds the neares neighbours of a point
672  *
673  * @param searchPt point for which the neighbours are searched
674  * @param neighbourPts possible neighbour points
675  * @param dist limits the distance of the neighbours
676  *
677  */
678 void Interpolator::FindNeighbours(const PtsPoint &searchPt,
679  vector<PtsPoint> &neighbourPts,
680  const NekDouble dist,
681  const unsigned int maxPts)
682 {
683  BPoint searchBPoint(searchPt.coords[0], searchPt.coords[1],
684  searchPt.coords[2]);
685  BPoint bbMin(searchPt.coords[0] - dist, searchPt.coords[1] - dist,
686  searchPt.coords[2] - dist);
687  BPoint bbMax(searchPt.coords[0] + dist, searchPt.coords[1] + dist,
688  searchPt.coords[2] + dist);
689  bg::model::box<BPoint> bbox(bbMin, bbMax);
690 
691  // find points within the distance box
692  std::vector<PtsPointPair> result;
693  if (maxPts >= 1)
694  {
695  m_rtree->query(bgi::within(bbox) && bgi::nearest(searchBPoint, maxPts),
696  std::back_inserter(result));
697  }
698  else
699  {
700  m_rtree->query(bgi::within(bbox), std::back_inserter(result));
701  }
702 
703  // massage into or own format
704  for (int i = 0; i < result.size(); ++i)
705  {
706  int idx = result[i].second;
707  Array<OneD, NekDouble> coords(m_dim, 0.0);
708  for (int j = 0; j < m_ptsInField->GetDim(); ++j)
709  {
710  coords[j] = m_ptsInField->GetPointVal(j, idx);
711  }
712  NekDouble d = bg::distance(searchBPoint, result[i].first);
713 
714  // discard points beyonf dist
715  if (d <= dist)
716  {
717  neighbourPts.push_back(PtsPoint(idx, coords, d));
718  }
719  }
720 
721  sort(neighbourPts.begin(), neighbourPts.end());
722 }
723 } // namespace LibUtilities
724 } // namespace Nektar
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:215
#define NEKERROR(type, msg)
Assert Level 0 – Fundamental assert which is used whether in FULLDEBUG, DEBUG or OPT compilation mode...
Definition: ErrorUtil.hpp:209
boost::geometry::model::point< NekDouble, m_dim, boost::geometry::cs::cartesian > BPoint
General purpose memory allocation routines with the ability to allocate from thread specific memory p...
std::shared_ptr< PtsField > PtsFieldSharedPtr
Definition: PtsField.h:190
static const NekDouble kNekZeroTol
The above copyright notice and this permission notice shall be included.
Definition: CoupledSolver.h:2
double NekDouble