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