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