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