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