Nektar++
Loading...
Searching...
No Matches
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: Solving the absolute flow in a moving body frame,
32// by adding (U0 + Omega X (x - x0)) . grad u - Omega X u
33// as the body force.
34// U0 is the translational velocity of the body frame.
35// Omega is the angular velocity.
36// x0 is the rotation pivot in the body frame.
37// All vectors use the basis of the body frame.
38// Translational motion is allowed for all dimensions.
39// Rotation is not allowed for 1D, 2DH1D, 3DH2D.
40// Rotation in z direction is allowed for 2D and 3DH1D.
41// Rotation in 3 directions are allowed for 3D.
42// TODO: add suport for 3D rotation using Quaternion
43///////////////////////////////////////////////////////////////////////////////
44
49
50namespace Nektar::SolverUtils
51{
52
55 "MovingReferenceFrame", ForcingMovingReferenceFrame::create,
56 "Moving Frame");
57
58/**
59 * @brief
60 * @param pSession
61 * @param pEquation
62 */
65 const std::weak_ptr<EquationSystem> &pEquation)
66 : Forcing(pSession, pEquation)
67{
68}
69
73
74/**
75 * @brief Initialise the forcing module
76 * @param pFields
77 * @param pNumForcingFields
78 * @param pForce
79 */
82 [[maybe_unused]] const unsigned int &pNumForcingFields,
83 [[maybe_unused]] const TiXmlElement *pForce)
84{
85 m_session->MatchSolverInfo("Homogeneous", "1D", m_isH1d, false);
86 m_session->MatchSolverInfo("Homogeneous", "2D", m_isH2d, false);
87 bool singleMode, halfMode;
88 m_session->MatchSolverInfo("ModeType", "SingleMode", singleMode, false);
89 m_session->MatchSolverInfo("ModeType", "HalfMode", halfMode, false);
90 if (singleMode || halfMode)
91 {
92 m_isH1d = false;
93 }
94 int expdim = m_isH2d ? 1 : pFields[0]->GetGraph()->GetMeshDimension();
95 m_spacedim = expdim + (m_isH1d ? 1 : 0) + (m_isH2d ? 2 : 0);
96 m_hasPlane0 = true;
97 if (m_isH1d)
98 {
99 m_hasPlane0 = pFields[0]->GetZIDs()[0] == 0;
100 }
101}
102
103/**
104 * @brief Adds the body force, -Omega X u.
105 * @param fields
106 * @param inarray
107 * @param outarray
108 * @param time
109 */
112 const Array<OneD, Array<OneD, NekDouble>> &inarray,
114 [[maybe_unused]] const NekDouble &time)
115{
116 // If there is no rotation, body force is zero,
117 // nothing needs to be done here.
118 if (m_hasRotation)
119 {
120 int npoints = fields[0]->GetNpoints();
121 addRotation(npoints, outarray, -1., inarray, outarray);
122 }
123}
124
125/**
126 * @brief outarray = inarray0 + angVelScale Omega x inarray1
127 */
129 int nPnts, // number of points
130 const Array<OneD, Array<OneD, NekDouble>> &inarray0, NekDouble angVelScale,
131 const Array<OneD, Array<OneD, NekDouble>> &inarray1,
133{
134 ASSERTL0(&inarray1 != &outarray, "inarray1 and outarray "
135 "should not be the same.");
136
137 // TODO: In case of having support for all three components of Omega,
138 // they should be transformed into the rotating frame first!
139
140 // In case that the inarray0 and outarry are different, to avoid using
141 // un-initialized array, copy the array first
142 if (&inarray0 != &outarray)
143 {
144 ASSERTL0(inarray0.size() == outarray.size(),
145 "inarray0 and outarray must have same dimentions");
146 for (int i = 0; i < inarray0.size(); ++i)
147 {
148 Vmath::Vcopy(nPnts, inarray0[i], 1, outarray[i], 1);
149 }
150 }
151
152 if (m_spacedim >= 2 && m_hasOmega[2])
153 {
154 NekDouble cp = m_omegaxyz[2] * angVelScale;
155 NekDouble cm = -1. * cp;
156
157 Vmath::Svtvp(nPnts, cm, inarray1[1], 1, outarray[0], 1, outarray[0], 1);
158 Vmath::Svtvp(nPnts, cp, inarray1[0], 1, outarray[1], 1, outarray[1], 1);
159 }
160
161 if (m_spacedim == 3 && m_hasOmega[0])
162 {
163 NekDouble cp = m_omegaxyz[0] * angVelScale;
164 NekDouble cm = -1. * cp;
165
166 Vmath::Svtvp(nPnts, cp, inarray1[1], 1, outarray[2], 1, outarray[2], 1);
167 Vmath::Svtvp(nPnts, cm, inarray1[2], 1, outarray[1], 1, outarray[1], 1);
168 }
169
170 if (m_spacedim == 3 && m_hasOmega[1])
171 {
172 NekDouble cp = m_omegaxyz[1] * angVelScale;
173 NekDouble cm = -1. * cp;
174
175 Vmath::Svtvp(nPnts, cp, inarray1[2], 1, outarray[0], 1, outarray[0], 1);
176 Vmath::Svtvp(nPnts, cm, inarray1[0], 1, outarray[2], 1, outarray[2], 1);
177 }
178}
179
180/**
181 * @brief Compute the moving frame velocity at given time
182 */
185 const Array<OneD, Array<OneD, NekDouble>> &inarray,
187 [[maybe_unused]] const NekDouble &time)
188{
189 UpdateMRFStatus(fields[0]);
190 int npoints = fields[0]->GetNpoints();
191 if (m_isH2d && fields[0]->GetWaveSpace())
192 {
193 for (int i = 0; i < m_spacedim; ++i)
194 {
195 if (m_hasVel[i])
196 {
197 Array<OneD, NekDouble> tmpphys(npoints, -m_velxyz[i]);
198 Array<OneD, NekDouble> tmpcoef(npoints);
199 fields[0]->HomogeneousFwdTrans(npoints, tmpphys, tmpcoef);
200 Vmath::Vadd(npoints, tmpcoef, 1, inarray[i], 1, outarray[i], 1);
201 }
202 else if (&inarray != &outarray)
203 {
204 Vmath::Vcopy(npoints, inarray[i], 1, outarray[i], 1);
205 }
206 }
207 }
208 else
209 {
210 int npoints0 = npoints;
211 if (m_isH1d && fields[0]->GetWaveSpace())
212 {
213 npoints0 = m_hasPlane0 ? fields[0]->GetPlane(0)->GetNpoints() : 0;
214 }
215 for (int i = 0; i < m_spacedim; ++i)
216 {
217 if (m_hasVel[i])
218 {
219 Vmath::Sadd(npoints0, -m_velxyz[i], inarray[i], 1, outarray[i],
220 1);
221 if (&inarray != &outarray && npoints != npoints0)
222 {
223 Array<OneD, NekDouble> tmp = outarray[i] + npoints0;
224 Vmath::Vcopy(npoints - npoints0, inarray[i] + npoints0, 1,
225 tmp, 1);
226 }
227 }
228 else if (&inarray != &outarray)
229 {
230 Vmath::Vcopy(npoints, inarray[i], 1, outarray[i], 1);
231 }
232 }
233 if (m_hasRotation)
234 {
235 addRotation(npoints0, outarray, -1., m_coords, outarray);
236 }
237 }
238}
239
242{
243 if (m_velxyz.size() == 0)
244 {
245 // initialize variables
248 m_hasVel = Array<OneD, bool>(3, false);
249 m_hasOmega = Array<OneD, bool>(3, false);
250 m_hasRotation = false;
252
253 // initialise pivot point for fluid interface
254 auto equ = m_equ.lock();
255 ASSERTL0(equ, "Weak pointer to the equation system is expired");
256 m_FluidEq = std::dynamic_pointer_cast<FluidInterface>(equ);
257 m_FluidEq->GetMovingFramePivot(m_pivotPoint);
258 std::set<int> moveDoFs;
259 m_FluidEq->GetMovableDoFs(moveDoFs);
260 for (int i = 0; i < 3; ++i)
261 {
262 if (moveDoFs.find(i) != moveDoFs.end())
263 {
264 m_hasVel[i] = true;
265 }
266 if (moveDoFs.find(i + 3) != moveDoFs.end())
267 {
268 m_hasOmega[i] = true;
269 m_hasRotation = true;
270 }
271 }
272 // account for the effect of rotation
273 // Omega_X results in having v and w even if not defined by user
274 // Omega_Y results in having u and w even if not defined by user
275 // Omega_Z results in having u and v even if not defined by user
276 for (int i = 0; i < 3; ++i)
277 {
278 int j = (i + 1) % 3;
279 int k = (i + 2) % 3;
280 if (m_hasOmega[i])
281 {
282 m_hasVel[j] = true;
283 m_hasVel[k] = true;
284 }
285 }
286 if (m_hasRotation)
287 {
288 int npoints = field->GetNpoints();
290 for (int j = 0; j < m_spacedim; ++j)
291 {
292 m_coords[j] = Array<OneD, NekDouble>(npoints);
293 }
294 field->GetCoords(m_coords[0], m_coords[1], m_coords[2]);
295 // move the origin to the pivot point
296 for (int i = 0; i < m_spacedim; ++i)
297 {
298 Vmath::Sadd(npoints, -m_pivotPoint[i], m_coords[i], 1,
299 m_coords[i], 1);
300 }
301 }
302 }
303 Array<OneD, NekDouble> vel(6, 0.0);
304 m_FluidEq->GetMovingFrameVelocities(vel);
305 Vmath::Vcopy(3, vel, 1, m_velxyz, 1);
306 Vmath::Vcopy(3, vel + 3, 1, m_omegaxyz, 1);
307}
308
309} // namespace Nektar::SolverUtils
#define ASSERTL0(condition, msg)
tKey RegisterCreatorFunction(tKey idKey, CreatorFunction classCreator, std::string pDesc="")
Register a class with the factory.
Defines a forcing term to be explicitly applied.
Definition Forcing.h:71
const std::weak_ptr< EquationSystem > m_equ
Weak pointer to equation system using this forcing.
Definition Forcing.h:125
LibUtilities::SessionReaderSharedPtr m_session
Session reader.
Definition Forcing.h:123
SOLVER_UTILS_EXPORT void v_PreApply(const Array< OneD, MultiRegions::ExpListSharedPtr > &fields, const Array< OneD, Array< OneD, NekDouble > > &inarray, Array< OneD, Array< OneD, NekDouble > > &outarray, const NekDouble &time) override
Compute the moving frame velocity at given time.
void UpdateMRFStatus(MultiRegions::ExpListSharedPtr field)
std::shared_ptr< Nektar::SolverUtils::FluidInterface > m_FluidEq
void addRotation(int npoints, const Array< OneD, Array< OneD, NekDouble > > &inarray0, NekDouble angVelScale, const Array< OneD, Array< OneD, NekDouble > > &inarray1, Array< OneD, Array< OneD, NekDouble > > &outarray)
outarray = inarray0 + angVelScale Omega x inarray1
ForcingMovingReferenceFrame(const LibUtilities::SessionReaderSharedPtr &pSession, const std::weak_ptr< EquationSystem > &pEquation)
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) override
Adds the body force, -Omega X u.
SOLVER_UTILS_EXPORT void v_InitObject(const Array< OneD, MultiRegions::ExpListSharedPtr > &pFields, const unsigned int &pNumForcingFields, const TiXmlElement *pForce) override
Initialise the forcing module.
static SOLVER_UTILS_EXPORT ForcingSharedPtr create(const LibUtilities::SessionReaderSharedPtr &pSession, const std::weak_ptr< EquationSystem > &pEquation, const Array< OneD, MultiRegions::ExpListSharedPtr > &pFields, const unsigned int &pNumForcingFields, const TiXmlElement *pForce)
Creates an instance of this class.
std::shared_ptr< SessionReader > SessionReaderSharedPtr
std::shared_ptr< ExpList > ExpListSharedPtr
Shared pointer to an ExpList object.
ForcingFactory & GetForcingFactory()
Declaration of the forcing factory singleton.
Definition Forcing.cpp:41
void Svtvp(int n, const T alpha, const T *x, const int incx, const T *y, const int incy, T *z, const int incz)
Svtvp (scalar times vector plus vector): z = alpha*x + y.
Definition Vmath.hpp:396
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.hpp:180
void Sadd(int n, const T alpha, const T *x, const int incx, T *y, const int incy)
Add vector y = alpha + x.
Definition Vmath.hpp:194
void Vcopy(int n, const T *x, const int incx, T *y, const int incy)
Definition Vmath.hpp:825