Nektar++
ForcingMovingReferenceFrame.cpp
Go to the documentation of this file.
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 // File: ForcingMovingReferenceFrame.cpp
4 //
5 // For more information, please see: http://www.nektar.info
6 //
7 // The MIT License
8 //
9 // Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
10 // Department of Aeronautics, Imperial College London (UK), and Scientific
11 // Computing and Imaging Institute, University of Utah (USA).
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining a
14 // copy of this software and associated documentation files (the "Software"),
15 // to deal in the Software without restriction, including without limitation
16 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
17 // and/or sell copies of the Software, and to permit persons to whom the
18 // Software is furnished to do so, subject to the following conditions:
19 //
20 // The above copyright notice and this permission notice shall be included
21 // in all copies or substantial portions of the Software.
22 //
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29 // DEALINGS IN THE SOFTWARE.
30 //
31 // Description: Allows for a moving frame of reference, through adding c * du/dx
32 // to the body force, where c is the frame velocity vector
33 //
34 ///////////////////////////////////////////////////////////////////////////////
35 
36 #include <boost/core/ignore_unused.hpp>
37 
39 #include <MultiRegions/ExpList.h>
41 
42 using namespace std;
43 
44 namespace Nektar
45 {
46 namespace SolverUtils
47 {
48 
49 std::string ForcingMovingReferenceFrame::classNameBody = GetForcingFactory().
50  RegisterCreatorFunction("MovingReferenceFrame",
51  ForcingMovingReferenceFrame::create,
52  "Moving Frame");
53 std::string ForcingMovingReferenceFrame::classNameField = GetForcingFactory().
54  RegisterCreatorFunction("Field",
55  ForcingMovingReferenceFrame::create,
56  "Field Forcing");
57 
58 /**
59  * @brief
60  * @param pSession
61  * @param pEquation
62  */
63 ForcingMovingReferenceFrame::ForcingMovingReferenceFrame(
65  const std::weak_ptr<EquationSystem> &pEquation)
66  : Forcing(pSession, pEquation)
67 {
68 }
69 
70 
71 /**
72  * @brief Initialise the forcing module
73  * @param pFields
74  * @param pNumForcingFields
75  * @param pForce
76  */
79  const unsigned int &pNumForcingFields,
80  const TiXmlElement *pForce)
81 {
82  boost::ignore_unused(pNumForcingFields);
83 
84  int npoints = pFields[0]->GetNpoints();
85  int expdim = pFields[0]->GetGraph()->GetMeshDimension();
86  bool isH1d;
87  bool isH2d;
88  m_session->MatchSolverInfo("Homogeneous", "1D", isH1d, false);
89  m_session->MatchSolverInfo("Homogeneous", "2D", isH2d, false);
90  m_spacedim = expdim + (isH1d ? 1 : 0) + (isH2d ? 2 : 0);
92 
93  const TiXmlElement *funcNameElmt = pForce->FirstChildElement(
94  "FRAMEVELOCITY");
95  ASSERTL0(funcNameElmt, "Requires FRAMEVELOCITY tag specifying function "
96  "name which prescribes velocity of the moving "
97  "frame.");
98 
99  m_funcName = funcNameElmt->GetText();
100  ASSERTL0(m_session->DefinesFunction(m_funcName),
101  "Function '" + m_funcName + "' not defined.");
102 
103  m_session->MatchSolverInfo("ModeType", "SingleMode", m_SingleMode, false);
104  m_session->MatchSolverInfo("ModeType", "HalfMode", m_HalfMode, false);
105  bool homogeneous = pFields[0]->GetExpType() == MultiRegions::e3DH1D ||
106  pFields[0]->GetExpType() == MultiRegions::e3DH2D;
107  m_transform = (m_SingleMode || m_HalfMode || homogeneous);
108 
109  m_homogen_dealiasing = m_session->DefinesSolverInfo("dealiasing");
110 
113  for (int i = 0; i < m_spacedim; ++i)
114  {
115  m_Forcing[i] = Array<OneD, NekDouble>(npoints, 0.0);
116 
117  std::string s_FieldStr = m_session->GetVariable(i);
118 
119  ASSERTL0(m_session->DefinesFunction(m_funcName, s_FieldStr),
120  "Variable '" + s_FieldStr + "' not defined.");
121  auto ep = m_session->GetFunction(m_funcName, s_FieldStr);
122  m_frameVelocity[i] = ep->Evaluate();
123  }
124 
126  for (int i = 0; i < m_spacedim * m_spacedim; ++i)
127  {
128  m_grad[i] = Array<OneD, NekDouble>(npoints);
129  }
130 
131  Update(pFields, 0.0);
132 }
133 
134 
135 /**
136  * @brief Calculates the gradient of the velocity fields.
137  * @param pFields
138  */
141 {
142  int npoints = pFields[0]->GetNpoints();
143  auto tmp = Array<OneD, NekDouble>(npoints);
144 
145  // Evaluate Grad(u)
146  switch (m_spacedim)
147  {
148  case 1:
149  // du/dx
150  pFields[0]->PhysDeriv(pFields[0]->GetPhys(), m_grad[0]);
151  break;
152  case 2:
153  // du/dx du/dy
154  pFields[0]->PhysDeriv(pFields[0]->GetPhys(), m_grad[0],
155  m_grad[1]);
156  // dv/dx dv/dy
157  pFields[1]->PhysDeriv(pFields[1]->GetPhys(), m_grad[2],
158  m_grad[3]);
159  break;
160  case 3:
161  if (pFields[0]->GetWaveSpace() == true &&
162  pFields[0]->GetExpType() == MultiRegions::e3DH1D)
163  {
164  // take d/dx, d/dy gradients in physical Fourier space
165  pFields[0]->PhysDeriv(pFields[0]->GetPhys(),
166  m_grad[0], m_grad[1]);
167  pFields[1]->PhysDeriv(pFields[1]->GetPhys(),
168  m_grad[3], m_grad[4]);
169 
170  pFields[0]->HomogeneousBwdTrans(pFields[2]->GetPhys(),
171  tmp);
172  pFields[0]->PhysDeriv(tmp, m_grad[6],
173  m_grad[7]);
174 
175  // Take d/dz derivative using wave space field
176  pFields[0]->PhysDeriv(MultiRegions::DirCartesianMap[2],
177  pFields[0]->GetPhys(), tmp);
178  pFields[0]->HomogeneousBwdTrans(tmp, m_grad[2]);
179  pFields[0]->PhysDeriv(MultiRegions::DirCartesianMap[2],
180  pFields[1]->GetPhys(), tmp);
181  pFields[0]->HomogeneousBwdTrans(tmp, m_grad[5]);
182  pFields[0]->PhysDeriv(MultiRegions::DirCartesianMap[2],
183  pFields[2]->GetPhys(), tmp);
184  pFields[0]->HomogeneousBwdTrans(tmp, m_grad[8]);
185  }
186  else if (pFields[0]->GetWaveSpace() == true &&
187  pFields[0]->GetExpType() == MultiRegions::e3DH2D)
188  {
189  // take d/dx, gradients in physical Fourier space
190  pFields[0]->PhysDeriv(pFields[0]->GetPhys(),
191  m_grad[0]);
192  pFields[1]->PhysDeriv(pFields[1]->GetPhys(),
193  m_grad[3]);
194 
195  pFields[0]->HomogeneousBwdTrans(pFields[2]->GetPhys(),
196  tmp);
197  pFields[0]->PhysDeriv(tmp, m_grad[6]);
198 
199  // Take d/dy derivative using wave space field
200  pFields[0]->PhysDeriv(MultiRegions::DirCartesianMap[1],
201  pFields[0]->GetPhys(), tmp);
202  pFields[0]->HomogeneousBwdTrans(tmp, m_grad[1]);
203  pFields[0]->PhysDeriv(MultiRegions::DirCartesianMap[1],
204  pFields[1]->GetPhys(), tmp);
205  pFields[0]->HomogeneousBwdTrans(tmp, m_grad[4]);
206  pFields[0]->PhysDeriv(MultiRegions::DirCartesianMap[1],
207  pFields[2]->GetPhys(), tmp);
208  pFields[0]->HomogeneousBwdTrans(tmp, m_grad[7]);
209 
210  // Take d/dz derivative using wave space field
211  pFields[0]->PhysDeriv(MultiRegions::DirCartesianMap[2],
212  pFields[0]->GetPhys(), tmp);
213  pFields[0]->HomogeneousBwdTrans(tmp, m_grad[2]);
214  pFields[0]->PhysDeriv(MultiRegions::DirCartesianMap[2],
215  pFields[1]->GetPhys(), tmp);
216  pFields[0]->HomogeneousBwdTrans(tmp, m_grad[5]);
217  pFields[0]->PhysDeriv(MultiRegions::DirCartesianMap[2],
218  pFields[2]->GetPhys(), tmp);
219  pFields[0]->HomogeneousBwdTrans(tmp, m_grad[8]);
220  }
221  else
222  {
223  pFields[0]->PhysDeriv(pFields[0]->GetPhys(),
224  m_grad[0], m_grad[1],
225  m_grad[2]);
226  pFields[1]->PhysDeriv(pFields[1]->GetPhys(),
227  m_grad[3], m_grad[4],
228  m_grad[5]);
229  pFields[2]->PhysDeriv(pFields[2]->GetPhys(),
230  m_grad[6], m_grad[7],
231  m_grad[8]);
232  }
233  break;
234  default:
235  ASSERTL0(false, "dimension unknown");
236  }
237 
238 }
239 
240 
241 /**
242  * @brief Updates the forcing array with the current required forcing.
243  * @param pFields
244  * @param time
245  */
248  const NekDouble &time)
249 {
250  boost::ignore_unused(time);
251 
252  int npoints = pFields[0]->GetNpoints();
253  Array<OneD, NekDouble> tmp(npoints, 0.0);
254 
255  CalculateGradient(pFields);
256 
257  switch (m_spacedim)
258  {
259  case 1:
260  // - cu * du/dx
261  Vmath::Smul(npoints, -1.0 * m_frameVelocity[0],
262  m_grad[0], 1, m_Forcing[0], 1);
263  break;
264  case 2:
265  // - cu * du/dx - cv * du/dy
266  Vmath::Smul(npoints, -1.0 * m_frameVelocity[0],
267  m_grad[0], 1, m_Forcing[0], 1);
268  Vmath::Smul(npoints, -1.0 * m_frameVelocity[1],
269  m_grad[1], 1, tmp, 1);
270  Vmath::Vadd(npoints, m_Forcing[0], 1, tmp, 1, m_Forcing[0],
271  1);
272  // - cu * dv/dx - cv * dv/dy
273  Vmath::Smul(npoints, -1.0 * m_frameVelocity[0],
274  m_grad[2], 1, m_Forcing[1], 1);
275  Vmath::Smul(npoints, -1.0 * m_frameVelocity[1],
276  m_grad[3], 1, tmp, 1);
277  Vmath::Vadd(npoints, m_Forcing[1], 1, tmp, 1, m_Forcing[1],
278  1);
279  break;
280  case 3:
281  //How do I deal with Homogeneous expansion?
282  // - cu * du/dx - cv * du/dy - cz * du/dz
283  Vmath::Smul(npoints, -1.0 * m_frameVelocity[0],
284  m_grad[0], 1, m_Forcing[0], 1);
285  Vmath::Smul(npoints, -1.0 * m_frameVelocity[1],
286  m_grad[1], 1, tmp, 1);
287  Vmath::Vadd(npoints, m_Forcing[0], 1, tmp, 1, m_Forcing[0],
288  1);
289  Vmath::Smul(npoints, -1.0 * m_frameVelocity[2],
290  m_grad[2], 1, tmp, 1);
291  Vmath::Vadd(npoints, m_Forcing[0], 1, tmp, 1, m_Forcing[0],
292  1);
293  // - cu * dv/dx - cv * dv/dy - cz * dv/dz
294  Vmath::Smul(npoints, -1.0 * m_frameVelocity[0],
295  m_grad[3], 1, m_Forcing[1], 1);
296  Vmath::Smul(npoints, -1.0 * m_frameVelocity[1],
297  m_grad[4], 1, tmp, 1);
298  Vmath::Vadd(npoints, m_Forcing[1], 1, tmp, 1, m_Forcing[1],
299  1);
300  Vmath::Smul(npoints, -1.0 * m_frameVelocity[2],
301  m_grad[5], 1, tmp, 1);
302  Vmath::Vadd(npoints, m_Forcing[1], 1, tmp, 1, m_Forcing[1],
303  1);
304  // - cu * dw/dx - cv * dw/dy - cz * dw/dz
305  Vmath::Smul(npoints, -1.0 * m_frameVelocity[0],
306  m_grad[6], 1, m_Forcing[2], 1);
307  Vmath::Smul(npoints, -1.0 * m_frameVelocity[1],
308  m_grad[7], 1, tmp, 1);
309  Vmath::Vadd(npoints, m_Forcing[2], 1, tmp, 1, m_Forcing[2],
310  1);
311  Vmath::Smul(npoints, -1.0 * m_frameVelocity[2],
312  m_grad[8], 1, tmp, 1);
313  Vmath::Vadd(npoints, m_Forcing[2], 1, tmp, 1, m_Forcing[2],
314  1);
315  break;
316  default:
317  ASSERTL0(false, "dimension unknown");
318  }
319 
320  // If singleMode or halfMode, transform the forcing term to be in
321  // physical space in the plane, but Fourier space in the homogeneous
322  // direction
323  if (m_transform)
324  {
325  for (int i = 0; i < m_spacedim; ++i)
326  {
327  pFields[0]->HomogeneousFwdTrans(m_Forcing[i], m_Forcing[i]);
328  }
329  }
330 }
331 
332 
333 /**
334  * @brief Apply the forcing term
335  * @param fields
336  * @param inarray
337  * @param outarray
338  * @param time
339  */
342  const Array<OneD, Array<OneD, NekDouble> > &inarray,
343  Array<OneD, Array<OneD, NekDouble> > &outarray,
344  const NekDouble &time)
345 {
346  boost::ignore_unused(inarray);
347 
348  Update(fields, time);
349 
350  for (int i = 0; i < m_spacedim; i++)
351  {
352  Vmath::Vadd(outarray[i].num_elements(), outarray[i], 1,
353  m_Forcing[i], 1, outarray[i], 1);
354  }
355 }
356 
357 
358 }
359 }
360 
void CalculateGradient(const Array< OneD, MultiRegions::ExpListSharedPtr > &pFields)
Calculates the gradient of the velocity fields.
Array< OneD, Array< OneD, NekDouble > > m_Forcing
Evaluated forcing function.
Definition: Forcing.h:107
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:216
void Update(const Array< OneD, MultiRegions::ExpListSharedPtr > &pFields, const NekDouble &time)
Updates the forcing array with the current required forcing.
virtual SOLVER_UTILS_EXPORT void v_InitObject(const Array< OneD, MultiRegions::ExpListSharedPtr > &pFields, const unsigned int &pNumForcingFields, const TiXmlElement *pForce)
Initialise the forcing module.
ForcingFactory & GetForcingFactory()
Declaration of the forcing factory singleton.
Definition: Forcing.cpp:44
STL namespace.
void Smul(int n, const T alpha, const T *x, const int incx, T *y, const int incy)
Scalar multiply y = alpha*y.
Definition: Vmath.cpp:216
double NekDouble
LibUtilities::SessionReaderSharedPtr m_session
Session reader.
Definition: Forcing.h:103
MultiRegions::Direction const DirCartesianMap[]
Definition: ExpList.h:88
int m_NumVariable
Number of variables.
Definition: Forcing.h:109
virtual SOLVER_UTILS_EXPORT void v_Apply(const Array< OneD, MultiRegions::ExpListSharedPtr > &fields, const Array< OneD, Array< OneD, NekDouble > > &inarray, Array< OneD, Array< OneD, NekDouble > > &outarray, const NekDouble &time)
Apply the forcing term.
Defines a forcing term to be explicitly applied.
Definition: Forcing.h:72
std::shared_ptr< SessionReader > SessionReaderSharedPtr
void Vadd(int n, const T *x, const int incx, const T *y, const int incy, T *z, const int incz)
Add vector z = x+y.
Definition: Vmath.cpp:302