Nektar++
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
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 // License for the specific language governing rights and limitations under
15 // Permission is hereby granted, free of charge, to any person obtaining a
16 // copy of this software and associated documentation files (the "Software"),
17 // to deal in the Software without restriction, including without limitation
18 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
19 // and/or sell copies of the Software, and to permit persons to whom the
20 // Software is furnished to do so, subject to the following conditions:
21 //
22 // The above copyright notice and this permission notice shall be included
23 // in all copies or substantial portions of the Software.
24 //
25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
26 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
28 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
30 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
31 // DEALINGS IN THE SOFTWARE.
32 //
33 // Description: Interpolator
34 //
35 ////////////////////////////////////////////////////////////////////////////////
36 
37 #include <boost/geometry.hpp>
39 
40 using namespace std;
41 
42 namespace bg = boost::geometry;
43 namespace bgi = boost::geometry::index;
44 
45 namespace Nektar
46 {
47 namespace FieldUtils
48 {
49 
50 /**
51  * @brief Compute interpolation weights without doing any interpolation
52  *
53  * @param ptsInField input field
54  * @param ptsOutField output field
55  *
56  * In and output fields must have the same dimension. The most suitable
57  * algorithm is chosen automatically if it wasnt set explicitly.
58  */
59 void Interpolator::CalcWeights(const LibUtilities::PtsFieldSharedPtr ptsInField,
61 {
62  ASSERTL0(ptsInField->GetDim() <= m_dim, "too many dimesions in inField");
63  ASSERTL0(ptsOutField->GetDim() <= m_dim, "too many dimesions in outField");
64 
65  m_ptsInField = ptsInField;
66  m_ptsOutField = ptsOutField;
67 
68  int nOutPts = m_ptsOutField->GetNpoints();
69  int lastProg = 0;
70 
71  // set a default method
72  if (m_method == eNoMethod)
73  {
74  if (m_ptsInField->GetDim() == 1 || m_coordId >= 0)
75  {
76  m_method = eQuadratic;
77  }
78  else
79  {
80  m_method = eShepard;
81  }
82  }
83 
84  if (m_method != eQuadratic)
85  {
86  SetupTree();
87  }
88 
89  switch (m_method)
90  {
91  case eNearestNeighbour:
92  {
93  m_weights = Array<TwoD, float>(nOutPts, 1, 0.0);
94  m_neighInds = Array<TwoD, unsigned int>(nOutPts, 1, (unsigned int) 0);
95 
96  for (int i = 0; i < nOutPts; ++i)
97  {
98  Array<OneD, NekDouble> tmp(m_dim, 0.0);
99  for (int j = 0; j < m_ptsOutField->GetDim(); ++j)
100  {
101  tmp[j] = m_ptsOutField->GetPointVal(j, i);
102  }
103  PtsPoint searchPt(i, tmp, 1E30);
104 
105  CalcW_NNeighbour(searchPt);
106 
107  int progress = int(100 * i / nOutPts);
108  if (m_progressCallback && progress > lastProg)
109  {
110  m_progressCallback(i, nOutPts);
111  lastProg = progress;
112  }
113  }
114 
115  break;
116  }
117 
118  case eQuadratic:
119  {
120  ASSERTL0(m_ptsInField->GetDim() == 1 || m_coordId >= 0,
121  "not implemented");
122 
123  m_weights = Array<TwoD, float>(nOutPts, 3, 0.0);
124  m_neighInds = Array<TwoD, unsigned int>(nOutPts, 3, (unsigned int) 0);
125 
126  if (m_ptsInField->GetDim() == 1)
127  {
128  m_coordId = 0;
129  }
130 
131  for (int i = 0; i < nOutPts; ++i)
132  {
133  Array<OneD, NekDouble> tmp(m_dim, 0.0);
134  for (int j = 0; j < m_ptsOutField->GetDim(); ++j)
135  {
136  tmp[j] = m_ptsOutField->GetPointVal(j, i);
137  }
138  PtsPoint searchPt(i, tmp, 1E30);
139 
140  if (m_ptsInField->GetNpoints() <= 2)
141  {
142  CalcW_Linear(searchPt, m_coordId);
143  }
144  else
145  {
146  CalcW_Quadratic(searchPt, m_coordId);
147  }
148 
149  int progress = int(100 * i / nOutPts);
150  if (m_progressCallback && progress > lastProg)
151  {
152  m_progressCallback(i, nOutPts);
153  lastProg = progress;
154  }
155  }
156 
157  break;
158  }
159 
160  case eShepard:
161  {
162  int numPts = pow(double(2), m_ptsInField->GetDim());
163  numPts = min(numPts, int(m_ptsInField->GetNpoints() / 2));
164 
165  m_weights = Array<TwoD, float>(nOutPts, numPts, 0.0);
166  m_neighInds = Array<TwoD, unsigned int>(nOutPts, numPts, (unsigned int) 0);
167 
168  for (int i = 0; i < nOutPts; ++i)
169  {
170  Array<OneD, NekDouble> tmp(m_dim, 0.0);
171  for (int j = 0; j < m_ptsOutField->GetDim(); ++j)
172  {
173  tmp[j] = m_ptsOutField->GetPointVal(j, i);
174  }
175  PtsPoint searchPt(i, tmp, 1E30);
176 
177  CalcW_Shepard(searchPt, numPts);
178 
179  int progress = int(100 * i / nOutPts);
180  if (m_progressCallback && progress > lastProg)
181  {
182  m_progressCallback(i, nOutPts);
183  lastProg = progress;
184  }
185  }
186 
187  break;
188  }
189 
190  case eGauss:
191  {
192  ASSERTL0(m_filtWidth > NekConstants::kNekZeroTol,
193  "No filter width set");
194  // use m_filtWidth as FWHM
195  NekDouble sigma = m_filtWidth * 0.4246609001;
196 
197  m_maxPts = min(m_maxPts, int(m_ptsInField->GetNpoints() / 2));
198 
199  m_weights = Array<TwoD, float>(nOutPts, m_maxPts, 0.0);
200  m_neighInds = Array<TwoD, unsigned int>(nOutPts, m_maxPts, (unsigned int) 0);
201 
202  for (int i = 0; i < nOutPts; ++i)
203  {
204  Array<OneD, NekDouble> tmp(m_dim, 0.0);
205  for (int j = 0; j < m_ptsOutField->GetDim(); ++j)
206  {
207  tmp[j] = m_ptsOutField->GetPointVal(j, i);
208  }
209  PtsPoint searchPt(i, tmp, 1E30);
210 
211  CalcW_Gauss(searchPt, sigma, m_maxPts);
212 
213  int progress = int(100 * i / nOutPts);
214  if (m_progressCallback && progress > lastProg)
215  {
216  m_progressCallback(i, nOutPts);
217  lastProg = progress;
218  }
219  }
220 
221  break;
222  }
223 
224  default:
225  ASSERTL0(false, "Invalid interpolation m_method");
226  break;
227  }
228 }
229 
230 /**
231  * @brief Interpolate from a pts field to a pts field
232  *
233  * @param ptsInField input field
234  * @param ptsOutField output field
235  *
236  * In and output fields must have the same dimension and number of fields.
237  * The most suitable algorithm is chosen automatically if it wasnt set
238  * explicitly.
239  */
240 void Interpolator::Interpolate(const LibUtilities::PtsFieldSharedPtr ptsInField,
241  LibUtilities::PtsFieldSharedPtr &ptsOutField)
242 {
243  ASSERTL0(ptsInField->GetNFields() == ptsOutField->GetNFields(),
244  "number of fields does not match");
245  ASSERTL0(ptsInField->GetDim() <= m_dim, "too many dimesions in inField");
246  ASSERTL0(ptsOutField->GetDim() <= m_dim, "too many dimesions in outField");
247 
248  m_ptsInField = ptsInField;
249  m_ptsOutField = ptsOutField;
250 
251  if (m_weights.GetRows() == 0)
252  {
253  CalcWeights(m_ptsInField, m_ptsOutField);
254  }
255 
256  ASSERTL0(m_weights.GetRows() == m_ptsOutField->GetNpoints(),
257  "weights dimension mismatch");
258 
259  int nFields = m_ptsOutField->GetNFields();
260  int nOutPts = m_ptsOutField->GetNpoints();
261  int inDim = m_ptsInField->GetDim();
262 
263  // interpolate points and transform
264  for (int i = 0; i < nFields; ++i)
265  {
266  for (int j = 0; j < nOutPts; ++j)
267  {
268  int nPts = m_weights.GetColumns();
269 
270  // skip if there were no neighbours found for this point
271  if (nPts == 0)
272  {
273  continue;
274  }
275 
276  NekDouble val = 0.0;
277  for (int k = 0; k < nPts; ++k)
278  {
279  unsigned int nIdx = m_neighInds[j][k];
280  val += m_weights[j][k] *
281  m_ptsInField->GetPointVal(inDim + i, nIdx);
282  }
283  m_ptsOutField->SetPointVal(m_ptsOutField->GetDim() + i, j, val);
284  }
285  }
286 }
287 
288 /**
289  * @brief Interpolate from one expansion to an other
290  *
291  * @param expInField input field
292  * @param expOutField output field
293  *
294  *
295  * In and output fields must have the same dimension and number of fields.
296  * Weights are currently not stored for later use.
297  * The interpolation is performed by evaluating the expInField at the quadrature
298  * points of expOutField, so only eNoMethod is supported.
299  * If both expansions use the same mesh, use LibUtilities/Foundations/Interp.h
300  * instead.
301  */
302 void Interpolator::Interpolate(
303  const vector<MultiRegions::ExpListSharedPtr> expInField,
304  vector<MultiRegions::ExpListSharedPtr> &expOutField,
305  NekDouble def_value)
306 {
307  ASSERTL0(expInField.size() == expOutField.size(),
308  "number of fields does not match");
309  ASSERTL0(expInField[0]->GetCoordim(0) <= m_dim,
310  "too many dimesions in inField");
311  ASSERTL0(expOutField[0]->GetCoordim(0) <= m_dim,
312  "too many dimesions in outField")
313  ASSERTL0(m_method == eNoMethod,
314  "only direct evaluation supported for this interpolation");
315 
316  m_expInField = expInField;
317  m_expOutField = expOutField;
318 
319  int nInDim = expInField[0]->GetCoordim(0);
320  int nOutPts = m_expOutField[0]->GetTotPoints();
321  int nOutDim = m_expOutField[0]->GetCoordim(0);
322  int lastProg = 0;
323 
324  Array<OneD, NekDouble> Lcoords(nInDim, 0.0);
325  Array<OneD, NekDouble> Scoords(nOutDim, 0.0);
326  Array<OneD, Array<OneD, NekDouble> > coords(nOutDim);
327  for (int i = 0; i < nOutDim; ++i)
328  {
329  coords[i] = Array<OneD, NekDouble>(nOutPts);
330  }
331  if (nOutDim == 1)
332  {
333  m_expOutField[0]->GetCoords(coords[0]);
334  }
335  else if (nOutDim == 2)
336  {
337  m_expOutField[0]->GetCoords(coords[0], coords[1]);
338  }
339  else if (nOutDim == 3)
340  {
341  m_expOutField[0]->GetCoords(coords[0], coords[1], coords[2]);
342  }
343 
344  for (int i = 0; i < nOutPts; ++i)
345  {
346  for (int j = 0; j < nOutDim; ++j)
347  {
348  Scoords[j] = coords[j][i];
349  }
350 
351  // Obtain Element and LocalCoordinate to interpolate
352  int elmtid = m_expInField[0]->GetExpIndex(Scoords, Lcoords,
354 
355  if (elmtid >= 0)
356  {
357  int offset = m_expInField[0]->GetPhys_Offset(elmtid);
358 
359  for (int f = 0; f < m_expInField.size(); ++f)
360  {
361  NekDouble value =
362  m_expInField[f]->GetExp(elmtid)->StdPhysEvaluate(
363  Lcoords, m_expInField[f]->GetPhys() + offset);
364 
365  if ((boost::math::isnan)(value))
366  {
367  ASSERTL0(false, "new value is not a number");
368  }
369  else
370  {
371  m_expOutField[f]->UpdatePhys()[i] = value;
372  }
373  }
374  }
375  else
376  {
377  for (int f = 0; f < m_expInField.size(); ++f)
378  {
379  m_expOutField[f]->UpdatePhys()[i] = def_value;
380  }
381  }
382 
383  int progress = int(100 * i / nOutPts);
384  if (m_progressCallback && progress > lastProg)
385  {
386  m_progressCallback(i, nOutPts);
387  lastProg = progress;
388  }
389  }
390 }
391 
392 /**
393  * @brief Interpolate from an expansion to a pts field
394  *
395  * @param expInField input field
396  * @param ptsOutField output field
397  *
398  * In and output fields must have the same dimension and number of fields.
399  * Weights are currently not stored for later use.
400  * The interpolation is performed by evaluating the expInField at the points
401  * of ptsOutField, so only eNoMethod is supported.
402  */
403 void Interpolator::Interpolate(
404  const vector<MultiRegions::ExpListSharedPtr> expInField,
405  LibUtilities::PtsFieldSharedPtr &ptsOutField,
406  NekDouble def_value)
407 {
408  ASSERTL0(expInField.size() == ptsOutField->GetNFields(),
409  "number of fields does not match");
410  ASSERTL0(expInField[0]->GetCoordim(0) <= m_dim,
411  "too many dimesions in inField");
412  ASSERTL0(ptsOutField->GetDim() <= m_dim, "too many dimesions in outField");
413  ASSERTL0(m_method == eNoMethod,
414  "only direct evaluation supported for this interpolation");
415 
416  m_expInField = expInField;
417  m_ptsOutField = ptsOutField;
418 
419  int nInDim = expInField[0]->GetCoordim(0);
420  int nOutPts = m_ptsOutField->GetNpoints();
421  int lastProg = 0;
422 
423  for (int i = 0; i < nOutPts; ++i)
424  {
425  Array<OneD, NekDouble> Lcoords(nInDim, 0.0);
426  Array<OneD, NekDouble> coords(m_ptsOutField->GetDim(), 0.0);
427  for (int j = 0; j < m_ptsOutField->GetDim(); ++j)
428  {
429  coords[j] = m_ptsOutField->GetPointVal(j, i);
430  }
431 
432  // Obtain Element and LocalCoordinate to interpolate
433  int elmtid = m_expInField[0]->GetExpIndex(coords, Lcoords,
435 
436  if (elmtid >= 0)
437  {
438  int offset = m_expInField[0]->GetPhys_Offset(elmtid);
439 
440  for (int f = 0; f < m_expInField.size(); ++f)
441  {
442  NekDouble value =
443  m_expInField[f]->GetExp(elmtid)->StdPhysEvaluate(
444  Lcoords, m_expInField[f]->GetPhys() + offset);
445 
446  if ((boost::math::isnan)(value))
447  {
448  ASSERTL0(false, "new value is not a number");
449  }
450  else
451  {
452  m_ptsOutField->SetPointVal(m_ptsOutField->GetDim() + f, i,
453  value);
454  }
455  }
456  }
457  else
458  {
459  for (int f = 0; f < m_expInField.size(); ++f)
460  {
461  m_ptsOutField->SetPointVal(m_ptsOutField->GetDim() + f, i,
462  def_value);
463  }
464  }
465 
466  int progress = int(100 * i / nOutPts);
467  if (m_progressCallback && progress > lastProg)
468  {
469  m_progressCallback(i, nOutPts);
470  lastProg = progress;
471  }
472  }
473 }
474 
475 /**
476  * @brief Interpolate from a pts field to an expansion
477  *
478  * @param ptsInField input field
479  * @param expOutField output field
480  *
481  * In and output fields must have the same dimension and number of fields.
482  */
483 void Interpolator::Interpolate(
484  const LibUtilities::PtsFieldSharedPtr ptsInField,
485  vector<MultiRegions::ExpListSharedPtr> &expOutField)
486 {
487  ASSERTL0(expOutField.size() == ptsInField->GetNFields(),
488  "number of fields does not match");
489  ASSERTL0(ptsInField->GetDim() <= m_dim, "too many dimesions in inField");
490  ASSERTL0(expOutField[0]->GetCoordim(0) <= m_dim,
491  "too many dimesions in outField");
492 
493  m_ptsInField = ptsInField;
494  m_expOutField = expOutField;
495 
496  int nFields = max((int)ptsInField->GetNFields(), (int)m_expOutField.size());
497  int nOutPts = m_expOutField[0]->GetTotPoints();
498  int outDim = m_expOutField[0]->GetCoordim(0);
499 
500  // create intermediate Ptsfield that wraps the expOutField
502  for (int i = 0; i < outDim; ++i)
503  {
504  pts[i] = Array<OneD, NekDouble>(nOutPts);
505  }
506  if (outDim == 1)
507  {
508  m_expOutField[0]->GetCoords(pts[0]);
509  }
510  else if (outDim == 2)
511  {
512  m_expOutField[0]->GetCoords(pts[0], pts[1]);
513  }
514  else if (outDim == 3)
515  {
516  m_expOutField[0]->GetCoords(pts[0], pts[1], pts[2]);
517  }
518 
521  for (int f = 0; f < expOutField.size(); ++f)
522  {
523  tmpPts->AddField(m_expOutField[f]->GetCoeffs(),
524  m_ptsInField->GetFieldName(f));
525  }
526 
527  // interpolate m_ptsInField to this intermediate field
528  Interpolate(m_ptsInField, tmpPts);
529 
530  // write the intermediate fields data into our expOutField
531  for (int i = 0; i < nFields; i++)
532  {
533  for (int j = 0; j < nOutPts; ++j)
534  {
535  m_expOutField[i]->UpdatePhys()[j] = tmpPts->GetPointVal(i, j);
536  }
537  }
538 }
539 
540 int Interpolator::GetDim() const
541 {
542  return m_dim;
543 }
544 
545 int Interpolator::GetCoordId() const
546 {
547  return m_coordId;
548 }
549 
550 NekDouble Interpolator::GetFiltWidth() const
551 {
552  return m_filtWidth;
553 }
554 
555 InterpMethod Interpolator::GetInterpMethod() const
556 {
557  return m_method;
558 }
559 
560 LibUtilities::PtsFieldSharedPtr Interpolator::GetInField() const
561 {
562  return m_ptsInField;
563 }
564 
565 LibUtilities::PtsFieldSharedPtr Interpolator::GetOutField() const
566 {
567  return m_ptsOutField;
568 }
569 
570 void Interpolator::PrintStatistics()
571 {
572  int meanN = 0;
573  for (int i = 0; i < m_neighInds.GetRows(); ++i)
574  {
575  for (int j = 0; j < m_neighInds.GetColumns(); ++j)
576  {
577  if (m_neighInds[i][j] > 0)
578  {
579  meanN +=1;
580  }
581  }
582  }
583 
584  cout << "Number of points: " << m_neighInds.GetRows() << endl;
585  cout << "mean Number of Neighbours per point: "
586  << meanN / m_neighInds.GetRows() << endl;
587 }
588 
589 /**
590  * @brief Computes interpolation weights using gaussian interpolation
591  *
592  * @param searchPt point for which the weights are computed
593  * @param sigma standard deviation of the gauss function
594  *
595  * Performs an interpolation using gauss weighting. Ideal for filtering fields.
596  * The filter width should be half the FWHM (= 1.1774 sigma) and must be set in
597  * the constructor of the Interpolator class.
598  */
599 void Interpolator::CalcW_Gauss(const PtsPoint &searchPt,
600  const NekDouble sigma,
601  const int maxPts)
602 {
603  // find nearest neighbours
604  vector<PtsPoint> neighbourPts;
605  FindNeighbours(searchPt, neighbourPts, 4 * sigma, maxPts);
606  int numPts = neighbourPts.size();
607 
608  // handle the cases that there was no or just one point within 4 * sigma
609  if (numPts == 0)
610  {
611  return;
612  }
613  if (numPts == 1)
614  {
615  m_neighInds[searchPt.idx][0] = neighbourPts.front().idx;
616  m_weights[searchPt.idx][0] = 1.0;
617 
618  return;
619  }
620 
621  NekDouble sigmaNew = 0.25 * neighbourPts.back().dist;
622 
623  for (int i = 0; i < numPts; i++)
624  {
625  m_neighInds[searchPt.idx][i] = neighbourPts.at(i).idx;
626  }
627 
628  NekDouble wSum = 0.0;
629  NekDouble ts2 = 2 * sigmaNew * sigmaNew;
630  for (int i = 0; i < numPts; ++i)
631  {
632  m_weights[searchPt.idx][i] =
633  exp(-1 * pow(neighbourPts[i].dist, double(2.0)) / ts2);
634  wSum += m_weights[searchPt.idx][i];
635  }
636 
637  for (int i = 0; i < numPts; ++i)
638  {
639  m_weights[searchPt.idx][i] = m_weights[searchPt.idx][i] / wSum;
640  }
641 }
642 
643 /**
644  * @brief Computes interpolation weights using linear interpolation
645  *
646  * @param searchPt point for which the weights are computed
647  * @param m_coordId coordinate id along which the interpolation should be
648  * performed
649  *
650  * Currently, only implemented for 1D
651  */
652 void Interpolator::CalcW_Linear(const PtsPoint &searchPt, int m_coordId)
653 {
654  int npts = m_ptsInField->GetNpoints();
655  int i;
656 
657  NekDouble coord = searchPt.coords[m_coordId];
658 
659  for (i = 0; i < npts - 1; ++i)
660  {
661  if ((m_ptsInField->GetPointVal(0, i) <=
662  (coord + NekConstants::kNekZeroTol)) &&
663  (coord <=
664  (m_ptsInField->GetPointVal(0, i + 1) + NekConstants::kNekZeroTol)))
665  {
666  NekDouble pdiff = m_ptsInField->GetPointVal(0, i + 1) -
667  m_ptsInField->GetPointVal(0, i);
668 
669  m_neighInds[searchPt.idx][0] = i;
670  m_neighInds[searchPt.idx][1] = i + 1;
671 
672  m_weights[searchPt.idx][0] =
673  (m_ptsInField->GetPointVal(0, i + 1) - coord) / pdiff;
674  m_weights[searchPt.idx][1] =
675  (coord - m_ptsInField->GetPointVal(0, i)) / pdiff;
676 
677  break;
678  }
679  }
680  ASSERTL0(i != npts - 1, "Failed to find coordinate " +
681  boost::lexical_cast<string>(coord) +
682  " within provided input points");
683 };
684 
685 /**
686  * @brief Computes interpolation weights using nearest neighbour interpolation
687  *
688  * @param searchPt point for which the weights are computed
689  * @param m_coordId coordinate id along which the interpolation should be
690  * performed
691  *
692  */
693 void Interpolator::CalcW_NNeighbour(const PtsPoint &searchPt)
694 {
695  // find nearest neighbours
696  vector<PtsPoint> neighbourPts;
697  // TODO: we currently dont handle the case when there are more than one
698  // most distant points (of same distance)
699  FindNNeighbours(searchPt, neighbourPts, 1);
700 
701  m_neighInds[searchPt.idx][0] = neighbourPts[0].idx;
702  m_weights[searchPt.idx][0] = 1.0;
703 }
704 
705 /**
706 * @brief Computes interpolation weights using linear interpolation
707 *
708 * @param searchPt point for which the weights are computed
709 * @param m_coordId coordinate id along which the interpolation should be
710 * performed
711 *
712 * The algorithm is based on Shepard, D. (1968). A two-dimensional interpolation
713 * function for irregularly-spaced data. Proceedings of the 1968 23rd ACM
714 * National Conference. pp. 517–524.
715 *
716 * In order to save memory, for n dimesnions, only 2^n points are considered.
717 * Contrary to Shepard, we use a fixed number of points with fixed weighting
718 * factors 1/d^n.
719 */
720 void Interpolator::CalcW_Shepard(const PtsPoint &searchPt, int numPts)
721 {
722  // find nearest neighbours
723  vector<PtsPoint> neighbourPts;
724  FindNNeighbours(searchPt, neighbourPts, numPts);
725 
726  for (int i = 0; i < neighbourPts.size(); i++)
727  {
728  m_neighInds[searchPt.idx][i] = neighbourPts[i].idx;
729  }
730 
731  // In case d < kVertexTheSameDouble ( d^2 < kNekSqrtTol), use the exact
732  // point and return
733  for (int i = 0; i < neighbourPts.size(); ++i)
734  {
735  if (neighbourPts[i].dist <= NekConstants::kNekZeroTol)
736  {
737  m_weights[searchPt.idx][i] = 1.0;
738  return;
739  }
740  }
741 
742  NekDouble wSum = 0.0;
743  for (int i = 0; i < neighbourPts.size(); ++i)
744  {
745  m_weights[searchPt.idx][i] = 1 / pow(double(neighbourPts[i].dist),
746  double(m_ptsInField->GetDim()));
747  wSum += m_weights[searchPt.idx][i];
748  }
749 
750  for (int i = 0; i < neighbourPts.size(); ++i)
751  {
752  m_weights[searchPt.idx][i] = m_weights[searchPt.idx][i] / wSum;
753  }
754 }
755 
756 /**
757  * @brief Computes interpolation weights using quadratic interpolation
758  *
759  * @param searchPt point for which the weights are computed
760  * @param m_coordId coordinate id along which the interpolation should be
761  * performed
762  *
763  * Currently, only implemented for 1D. Falls back to linear interpolation if
764  * only 2
765  * values are available.
766  */
767 void Interpolator::CalcW_Quadratic(const PtsPoint &searchPt, int m_coordId)
768 {
769  int npts = m_ptsInField->GetNpoints();
770  int i;
771 
772  NekDouble coord = searchPt.coords[m_coordId];
773 
774  for (i = 0; i < npts - 1; ++i)
775  {
776  if ((m_ptsInField->GetPointVal(0, i) <=
777  (coord + NekConstants::kNekZeroTol)) &&
778  (coord <=
779  (m_ptsInField->GetPointVal(0, i + 1) + NekConstants::kNekZeroTol)))
780  {
781  NekDouble pdiff = m_ptsInField->GetPointVal(0, i + 1) -
782  m_ptsInField->GetPointVal(0, i);
783  NekDouble h1, h2, h3;
784 
785  if (i < npts - 2)
786  {
787  // forwards stencil
788  NekDouble pdiff2 = m_ptsInField->GetPointVal(0, i + 2) -
789  m_ptsInField->GetPointVal(0, i + 1);
790 
791  h1 = (m_ptsInField->GetPointVal(0, i + 1) - coord) *
792  (m_ptsInField->GetPointVal(0, i + 2) - coord) /
793  (pdiff * (pdiff + pdiff2));
794  h2 = (coord - m_ptsInField->GetPointVal(0, i)) *
795  (m_ptsInField->GetPointVal(0, i + 2) - coord) /
796  (pdiff * pdiff2);
797  h3 = (coord - m_ptsInField->GetPointVal(0, i)) *
798  (coord - m_ptsInField->GetPointVal(0, i + 1)) /
799  ((pdiff + pdiff2) * pdiff2);
800 
801  m_neighInds[searchPt.idx][0] = i;
802  m_neighInds[searchPt.idx][1] = i + 1;
803  m_neighInds[searchPt.idx][2] = i + 2;
804  }
805  else
806  {
807  // backwards stencil
808  NekDouble pdiff2 = m_ptsInField->GetPointVal(0, i) -
809  m_ptsInField->GetPointVal(0, i - 1);
810 
811  h1 = (m_ptsInField->GetPointVal(0, i + 1) - coord) *
812  (coord - m_ptsInField->GetPointVal(0, i - 1)) /
813  (pdiff * pdiff2);
814  h2 = (coord - m_ptsInField->GetPointVal(0, i)) *
815  (coord - m_ptsInField->GetPointVal(0, i - 1)) /
816  (pdiff * (pdiff + pdiff2));
817  h3 = (m_ptsInField->GetPointVal(0, i) - coord) *
818  (m_ptsInField->GetPointVal(0, i + 1) - coord) /
819  ((pdiff + pdiff2) * pdiff);
820 
821  m_neighInds[searchPt.idx][0] = i;
822  m_neighInds[searchPt.idx][1] = i + 1;
823  m_neighInds[searchPt.idx][2] = i - 1;
824  }
825 
826  m_weights[searchPt.idx][0] = h1;
827  m_weights[searchPt.idx][1] = h2;
828  m_weights[searchPt.idx][2] = h3;
829 
830  break;
831  }
832  }
833  ASSERTL0(i != npts - 1, "Failed to find coordinate " +
834  boost::lexical_cast<string>(coord) +
835  " within provided input points");
836 };
837 
838 void Interpolator::SetupTree()
839 {
840  std::vector<PtsPointPair> inPoints;
841  for (int i = 0; i < m_ptsInField->GetNpoints(); ++i)
842  {
843  Array<OneD, NekDouble> coords(3, 0.0);
844  for (int j = 0; j < m_ptsInField->GetDim(); ++j)
845  {
846  coords[j] = m_ptsInField->GetPointVal(j, i);
847  }
848  inPoints.push_back(
849  PtsPointPair(BPoint(coords[0], coords[1], coords[2]), i));
850  }
852  m_rtree->insert(inPoints.begin(), inPoints.end());
853 
854  // remove duplicates from tree
855  for (std::vector<PtsPointPair>::iterator it = inPoints.begin();
856  it != inPoints.end(); ++it)
857  {
858  std::vector<PtsPointPair> result;
859 
860  // find nearest 2 points (2 because one of these might be the one we
861  // are
862  // checking)
863  m_rtree->query(bgi::nearest((*it).first, 2),
864  std::back_inserter(result));
865 
866  // in case any of these 2 points is too close, remove the current
867  // point
868  // from the tree
869  for (std::vector<PtsPointPair>::iterator it2 = result.begin();
870  it2 != result.end(); ++it2)
871  {
872  if ((*it).second != (*it2).second &&
873  bg::distance((*it).first, (*it2).first) <=
875  {
876  m_rtree->remove(*it);
877  break;
878  }
879  }
880  }
881 }
882 
883 /**
884  * @brief Finds the neares neighbours of a point
885  *
886  * @param searchPt point for which the neighbours are searched
887  * @param neighbourPts possible neighbour points
888  * @param numPts limits the number of neighbours found to the numPts
889  * nearest ones
890  *
891  */
892 void Interpolator::FindNNeighbours(const PtsPoint &searchPt,
893  vector<PtsPoint> &neighbourPts,
894  const unsigned int numPts)
895 {
896  std::vector<PtsPointPair> result;
897  BPoint searchBPoint(searchPt.coords[0], searchPt.coords[1],
898  searchPt.coords[2]);
899  m_rtree->query(bgi::nearest(searchBPoint, numPts),
900  std::back_inserter(result));
901 
902  // massage into or own format
903  for (int i = 0; i < result.size(); ++i)
904  {
905  int idx = result[i].second;
906  Array<OneD, NekDouble> coords(m_dim, 0.0);
907  for (int j = 0; j < m_ptsInField->GetDim(); ++j)
908  {
909  coords[j] = m_ptsInField->GetPointVal(j, idx);
910  }
911  NekDouble d = bg::distance(searchBPoint, result[i].first);
912  neighbourPts.push_back(PtsPoint(idx, coords, d));
913  }
914 
915  sort(neighbourPts.begin(), neighbourPts.end());
916 }
917 
918 /**
919  * @brief Finds the neares neighbours of a point
920  *
921  * @param searchPt point for which the neighbours are searched
922  * @param neighbourPts possible neighbour points
923  * @param dist limits the distance of the neighbours
924  *
925  */
926 void Interpolator::FindNeighbours(const PtsPoint &searchPt,
927  vector<PtsPoint> &neighbourPts,
928  const NekDouble dist,
929  const unsigned int maxPts)
930 {
931  BPoint searchBPoint(searchPt.coords[0], searchPt.coords[1],
932  searchPt.coords[2]);
933  BPoint bbMin(searchPt.coords[0] - dist, searchPt.coords[1] - dist,
934  searchPt.coords[2] - dist);
935  BPoint bbMax(searchPt.coords[0] + dist, searchPt.coords[1] + dist,
936  searchPt.coords[2] + dist);
937  bg::model::box<BPoint> bbox(bbMin, bbMax);
938 
939  // find points within the distance box
940  std::vector<PtsPointPair> result;
941  if (maxPts >= 1)
942  {
943  m_rtree->query(bgi::within(bbox) && bgi::nearest(searchBPoint, maxPts),
944  std::back_inserter(result));
945  }
946  else
947  {
948  m_rtree->query(bgi::within(bbox), std::back_inserter(result));
949  }
950 
951  // massage into or own format
952  for (int i = 0; i < result.size(); ++i)
953  {
954  int idx = result[i].second;
955  Array<OneD, NekDouble> coords(m_dim, 0.0);
956  for (int j = 0; j < m_ptsInField->GetDim(); ++j)
957  {
958  coords[j] = m_ptsInField->GetPointVal(j, idx);
959  }
960  NekDouble d = bg::distance(searchBPoint, result[i].first);
961 
962  // discard points beyonf dist
963  if (d <= dist)
964  {
965  neighbourPts.push_back(PtsPoint(idx, coords, d));
966  }
967  }
968 
969  sort(neighbourPts.begin(), neighbourPts.end());
970 }
971 }
972 }
std::pair< BPoint, unsigned int > PtsPointPair
Definition: Interpolator.h:183
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:198
General purpose memory allocation routines with the ability to allocate from thread specific memory p...
STL namespace.
boost::geometry::model::point< NekDouble, m_dim, boost::geometry::cs::cartesian > BPoint
Definition: Interpolator.h:182
boost::shared_ptr< PtsField > PtsFieldSharedPtr
Definition: PtsField.h:178
static const NekDouble kNekZeroTol
static std::string npts
Definition: InputFld.cpp:43
double NekDouble
StandardMatrixTag boost::call_traits< LhsDataType >::const_reference rhs typedef NekMatrix< LhsDataType, StandardMatrixTag >::iterator iterator