Nektar++
FieldUtils/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 FieldUtils
47 {
48 
49 /**
50  * @brief Interpolate from one expansion to an other
51  *
52  * @param expInField input field
53  * @param expOutField output field
54  *
55  *
56  * In and output fields must have the same dimension and number of fields.
57  * Weights are currently not stored for later use.
58  * The interpolation is performed by evaluating the expInField at the quadrature
59  * points of expOutField, so only eNoMethod is supported.
60  * If both expansions use the same mesh, use LibUtilities/Foundations/Interp.h
61  * instead.
62  */
63 void Interpolator::Interpolate(
64  const vector<MultiRegions::ExpListSharedPtr> expInField,
65  vector<MultiRegions::ExpListSharedPtr> &expOutField, NekDouble def_value)
66 {
67  ASSERTL0(expInField.size() == expOutField.size(),
68  "number of fields does not match");
69  ASSERTL0(expInField[0]->GetCoordim(0) <= GetDim(),
70  "too many dimesions in inField");
71  ASSERTL0(expOutField[0]->GetCoordim(0) <= GetDim(),
72  "too many dimesions in outField");
73  ASSERTL0(GetInterpMethod() == LibUtilities::eNoMethod,
74  "only direct evaluation supported for this interpolation");
75 
76  m_expInField = expInField;
77  m_expOutField = expOutField;
78 
79  int nFields = max((int)expInField.size(), (int)m_expOutField.size());
80  int nOutPts = m_expOutField[0]->GetTotPoints();
81  int outNumHomDir = 0;
82  if (m_expOutField[0]->GetExpType() == MultiRegions::e3DH1D ||
83  m_expOutField[0]->GetExpType() == MultiRegions::e2DH1D)
84  {
85  outNumHomDir = 1;
86  }
87  else if (m_expOutField[0]->GetExpType() == MultiRegions::e3DH2D)
88  {
89  outNumHomDir = 2;
90  }
91  int outDim = m_expOutField[0]->GetCoordim(0) + outNumHomDir;
92 
93  // create intermediate Ptsfield that wraps the expOutField
95  for (int i = 0; i < outDim; ++i)
96  {
97  pts[i] = Array<OneD, NekDouble>(nOutPts);
98  }
99  if (outDim == 1)
100  {
101  m_expOutField[0]->GetCoords(pts[0]);
102  }
103  else if (outDim == 2)
104  {
105  m_expOutField[0]->GetCoords(pts[0], pts[1]);
106  }
107  else if (outDim == 3)
108  {
109  m_expOutField[0]->GetCoords(pts[0], pts[1], pts[2]);
110  }
111 
114  for (int f = 0; f < expOutField.size(); ++f)
115  {
116  tmpPts->AddField(m_expOutField[f]->GetPhys(), "DefaultVar");
117  }
118 
119  // interpolate m_ptsInField to this intermediate field
120  Interpolate(m_expInField, tmpPts, def_value);
121 
122  // write the intermediate fields data into our expOutField
123  for (int i = 0; i < nFields; i++)
124  {
125  int ptsi = outDim + i;
126  for (int j = 0; j < nOutPts; ++j)
127  {
128  m_expOutField[i]->UpdatePhys()[j] = tmpPts->GetPointVal(ptsi, j);
129  }
130  }
131 }
132 
133 /**
134  * @brief Interpolate from an expansion to a pts field
135  *
136  * @param expInField input field
137  * @param ptsOutField output field
138  *
139  * In and output fields must have the same dimension and number of fields.
140  * Weights are currently not stored for later use.
141  * The interpolation is performed by evaluating the expInField at the points
142  * of ptsOutField, so only eNoMethod is supported.
143  */
144 void Interpolator::Interpolate(
145  const vector<MultiRegions::ExpListSharedPtr> expInField,
146  LibUtilities::PtsFieldSharedPtr &ptsOutField, NekDouble def_value)
147 {
148  ASSERTL0(expInField.size() == ptsOutField->GetNFields(),
149  "number of fields does not match");
150  ASSERTL0(expInField[0]->GetCoordim(0) <= GetDim(),
151  "too many dimesions in inField");
152  ASSERTL0(ptsOutField->GetDim() <= GetDim(),
153  "too many dimesions in outField");
154  ASSERTL0(ptsOutField->GetDim() >= expInField[0]->GetCoordim(0),
155  "too few dimesions in outField");
156  ASSERTL0(GetInterpMethod() == LibUtilities::eNoMethod,
157  "only direct evaluation supported for this interpolation");
158  ASSERTL0(expInField[0]->GetExpType() != MultiRegions::e3DH2D,
159  "interpolation from 3DH2D expansion unsupported");
160 
161  m_expInField = expInField;
162  m_ptsOutField = ptsOutField;
163 
164  int nInDim = expInField[0]->GetCoordim(0);
165  int nOutPts = m_ptsOutField->GetNpoints();
166  int lastProg = 0;
167 
168  int elmtid = -1;
169  for (int i = 0; i < nOutPts; ++i)
170  {
171  Array<OneD, NekDouble> Lcoords(nInDim, 0.0);
172  Array<OneD, NekDouble> coords(3, 0.0);
173  for (int j = 0; j < m_ptsOutField->GetDim(); ++j)
174  {
175  coords[j] = m_ptsOutField->GetPointVal(j, i);
176  }
177 
178  // Obtain Element and LocalCoordinate to interpolate.
179  elmtid = m_expInField[0]->GetExpIndex(
180  coords, Lcoords, NekConstants::kGeomFactorsTol, true, elmtid,
182 
183  // we use kGeomFactorsTol as tolerance, while StdPhysEvaluate has
184  // kNekZeroTol hardcoded, so we need to limit Lcoords to not produce
185  // a ton of warnings
186  for (int j = 0; j < nInDim; ++j)
187  {
188  Lcoords[j] = std::max(Lcoords[j], -1.0);
189  Lcoords[j] = std::min(Lcoords[j], 1.0);
190  }
191 
192  if (elmtid >= 0)
193  {
194  int offset = m_expInField[0]->GetPhys_Offset(elmtid);
195 
196  for (int f = 0; f < m_expInField.size(); ++f)
197  {
198  NekDouble value;
199  if (m_expInField[f]->GetExpType() == MultiRegions::e3DH1D ||
200  m_expInField[f]->GetExpType() == MultiRegions::e2DH1D)
201  {
202  ASSERTL0(m_expInField[f]->GetWaveSpace(),
203  "interpolation from 3DH1D/2DH1D requires field in "
204  "wavespace");
205  NekDouble lHom = m_expInField[f]->GetHomoLen();
206  NekDouble BetaT =
207  2. * M_PI * fmod(coords[nInDim], lHom) / lHom;
208  int nPlanes =
209  m_expInField[f]->GetHomogeneousBasis()->GetZ().size();
210  NekDouble coeff = 0.;
212  m_expInField[f]->GetZIDs();
213  value = 0.;
214  for (size_t n = 0; n < planes.size(); ++n)
215  {
216  auto planeExp = m_expInField[f]->GetPlane(planes[n]);
217  coeff = planeExp->GetExp(elmtid)->StdPhysEvaluate(
218  Lcoords, planeExp->GetPhys() + offset);
219  if (planes[n] == 0)
220  {
221  value += coeff;
222  }
223  else if (planes[n] == 1)
224  {
225  value += cos(0.5 * nPlanes * BetaT) * coeff;
226  }
227  else if (planes[n] % 2 == 0)
228  {
229  NekDouble phase = (planes[n] >> 1) * BetaT;
230  value += cos(phase) * coeff;
231  }
232  else
233  {
234  NekDouble phase = (planes[n] >> 1) * BetaT;
235  value += -sin(phase) * coeff;
236  }
237  }
238  }
239  else
240  {
241  value = m_expInField[f]->GetExp(elmtid)->StdPhysEvaluate(
242  Lcoords, m_expInField[f]->GetPhys() + offset);
243  }
244 
245  if ((boost::math::isnan)(value))
246  {
247  ASSERTL0(false, "new value is not a number");
248  }
249  else
250  {
251  m_ptsOutField->SetPointVal(m_ptsOutField->GetDim() + f, i,
252  value);
253  }
254  }
255  }
256  else
257  {
258  for (int f = 0; f < m_expInField.size(); ++f)
259  {
260  m_ptsOutField->SetPointVal(m_ptsOutField->GetDim() + f, i,
261  def_value);
262  }
263  }
264 
265  int progress = int(100 * i / nOutPts);
266  if (m_progressCallback && progress > lastProg)
267  {
268  m_progressCallback(i, nOutPts);
269  lastProg = progress;
270  }
271  }
272 }
273 
274 /**
275  * @brief Interpolate from a pts field to an expansion
276  *
277  * @param ptsInField input field
278  * @param expOutField output field
279  *
280  * In and output fields must have the same dimension and number of fields.
281  */
282 void Interpolator::Interpolate(
283  const LibUtilities::PtsFieldSharedPtr ptsInField,
284  vector<MultiRegions::ExpListSharedPtr> &expOutField)
285 {
286  ASSERTL0(expOutField.size() == ptsInField->GetNFields(),
287  "number of fields does not match");
288  ASSERTL0(ptsInField->GetDim() <= GetDim(), "too many dimesions in inField");
289  ASSERTL0(expOutField[0]->GetCoordim(0) <= GetDim(),
290  "too many dimesions in outField");
291 
292  m_ptsInField = ptsInField;
293  m_expOutField = expOutField;
294 
295  int nFields = max((int)ptsInField->GetNFields(), (int)m_expOutField.size());
296  int nOutPts = m_expOutField[0]->GetTotPoints();
297  int outNumHomDir = 0;
298  if (m_expOutField[0]->GetExpType() == MultiRegions::e3DH1D ||
299  m_expOutField[0]->GetExpType() == MultiRegions::e2DH1D)
300  {
301  outNumHomDir = 1;
302  }
303  else if (m_expOutField[0]->GetExpType() == MultiRegions::e3DH2D)
304  {
305  outNumHomDir = 2;
306  }
307  int outDim = m_expOutField[0]->GetCoordim(0) + outNumHomDir;
308 
309  // create intermediate Ptsfield that wraps the expOutField
311  for (int i = 0; i < outDim; ++i)
312  {
313  pts[i] = Array<OneD, NekDouble>(nOutPts);
314  }
315  if (outDim == 1)
316  {
317  m_expOutField[0]->GetCoords(pts[0]);
318  }
319  else if (outDim == 2)
320  {
321  m_expOutField[0]->GetCoords(pts[0], pts[1]);
322  }
323  else if (outDim == 3)
324  {
325  m_expOutField[0]->GetCoords(pts[0], pts[1], pts[2]);
326  }
327 
330  for (int f = 0; f < expOutField.size(); ++f)
331  {
332  tmpPts->AddField(m_expOutField[f]->GetPhys(),
333  m_ptsInField->GetFieldName(f));
334  }
335 
336  // interpolate m_ptsInField to this intermediate field
337  LibUtilities::Interpolator::Interpolate(m_ptsInField, tmpPts);
338 
339  // write the intermediate fields data into our expOutField
340  for (int i = 0; i < nFields; i++)
341  {
342  int ptsi = outDim + i;
343  for (int j = 0; j < nOutPts; ++j)
344  {
345  m_expOutField[i]->UpdatePhys()[j] = tmpPts->GetPointVal(ptsi, j);
346  }
347  }
348 }
349 
350 void Interpolator::Interpolate(const LibUtilities::PtsFieldSharedPtr ptsInField,
351  LibUtilities::PtsFieldSharedPtr &ptsOutField)
352 {
353  LibUtilities::Interpolator::Interpolate(ptsInField, ptsOutField);
354 }
355 
356 } // namespace FieldUtils
357 } // namespace Nektar
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:215
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 kGeomFactorsTol
The above copyright notice and this permission notice shall be included.
Definition: CoupledSolver.h:1
double NekDouble