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