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: 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///////////////////////////////////////////////////////////////////////////////
43
44#include <boost/core/ignore_unused.hpp>
45
50
51using namespace std;
52
53namespace Nektar
54{
55namespace SolverUtils
56{
57
60 "MovingReferenceFrame", ForcingMovingReferenceFrame::create,
61 "Moving Frame");
62
63/**
64 * @brief
65 * @param pSession
66 * @param pEquation
67 */
70 const std::weak_ptr<EquationSystem> &pEquation)
71 : Forcing(pSession, pEquation)
72{
73}
74
75/**
76 * @brief Initialise the forcing module
77 * @param pFields
78 * @param pNumForcingFields
79 * @param pForce
80 */
83 const unsigned int &pNumForcingFields, const TiXmlElement *pForce)
84{
85 boost::ignore_unused(pNumForcingFields);
86 m_session->MatchSolverInfo("Homogeneous", "1D", m_isH1d, false);
87 m_session->MatchSolverInfo("Homogeneous", "2D", m_isH2d, false);
88 bool singleMode, halfMode;
89 m_session->MatchSolverInfo("ModeType", "SingleMode", singleMode, false);
90 m_session->MatchSolverInfo("ModeType", "HalfMode", halfMode, false);
91 if (singleMode || halfMode)
92 {
93 m_isH1d = false;
94 }
95
96 int npoints = pFields[0]->GetNpoints();
97 int expdim = m_isH2d ? 1 : pFields[0]->GetGraph()->GetMeshDimension();
98 m_spacedim = expdim + (m_isH1d ? 1 : 0) + (m_isH2d ? 2 : 0);
100
101 m_hasPlane0 = true;
102 if (m_isH1d)
103 {
104 m_hasPlane0 = pFields[0]->GetZIDs()[0] == 0;
105 }
106
107 // linear velocities
108 const TiXmlElement *funcNameElmt;
109
110 funcNameElmt = pForce->FirstChildElement("LinearVelocity");
111 ASSERTL0(funcNameElmt, "Requires LinearVelocity tag specifying function "
112 "name which prescribes velocity of the moving "
113 "frame.");
114
115 m_velFuncName = funcNameElmt->GetText();
116 ASSERTL0(m_session->DefinesFunction(m_velFuncName),
117 "Function '" + m_velFuncName + "' is not defined in the session.");
118
119 // angular velocities
120 // Initiate the rotation to false, will be updated later if rotation defined
121 m_hasRotation = false;
122 funcNameElmt = pForce->FirstChildElement("AngularVelocity");
123 if (funcNameElmt)
124 {
125 m_omegaFuncName = funcNameElmt->GetText();
126 ASSERTL0(m_session->DefinesFunction(m_omegaFuncName),
127 "Function '" + m_omegaFuncName +
128 "' is not defined in the session.");
129 m_hasRotation = true;
130 }
131
132 // initiate the linear velocity values in both local and inertial frames
133 for (int i = 0; i < 3; ++i)
134 {
135 m_velXYZ[i] = 0.;
136 m_velxyz[i] = 0.;
137 }
138
139 // initiate the angular velocity values in both local and inertial frames
140 for (int i = 0; i < 3; ++i)
141 {
142 m_omegaXYZ[i] = 0;
143 m_omegaxyz[i] = 0;
144 }
145
146 // initiate the available frame velocities all to false
147 // this will be updated after reading the frame velocities and checking
148 // for the rotation
149 for (int i = 0; i < 3; ++i)
150 {
151 m_hasVel[i] = false;
152 m_hasOmega[i] = false;
153 }
154
155 // initiate the rotation angle to zero
156 // m_theta = {theta_X, theta_Y, theta_Z}
158
159 // initialize theta from the metadata of restart file or zero
161
162 // Initialize theta with the data from NS class
163 // This ensure correct moving coordinate orientation with respect to the
164 // stationary inertial frame when we restart the simulation
165 auto equ = m_equ.lock();
166 ASSERTL0(equ, "Weak pointer to the equation system is expired");
167 auto FluidEq = std::dynamic_pointer_cast<FluidInterface>(equ);
168 // Set the angles
169 FluidEq->SetMovingFrameAngles(m_theta);
170
171 // initiate the rotation matrix to zero,
172 // Note that the rotation matrix is assumed for the rotation around z axis
173 // TODO: Generalize this for the 3D case with possiblity of rotation around
174 // each of axis. Probabley we only can support rotation around one axis. In
175 // that case the generalization means the user can provide Omega for one of
176 // x, y or z axis. Not sure how complicated to consider a general axis of
177 // rotation
178 //
179 // Note that these rotation matrices should be extrinsic rotations
180 m_ProjMatX = bn::ublas::zero_matrix<NekDouble>(3, 3);
181 m_ProjMatY = bn::ublas::zero_matrix<NekDouble>(3, 3);
182 m_ProjMatZ = bn::ublas::zero_matrix<NekDouble>(3, 3);
183 // populate the rotation matrix R(z)
184 {
185 NekDouble sn, cs;
186 sn = sin(m_theta[2]);
187 cs = cos(m_theta[2]);
188
189 m_ProjMatZ(0, 0) = cs;
190 m_ProjMatZ(0, 1) = sn;
191 m_ProjMatZ(1, 0) = -1. * sn;
192 m_ProjMatZ(1, 1) = cs;
193 m_ProjMatZ(2, 2) = 1.0;
194 }
195
196 // frame linear velocity
197 for (int i = 0; i < m_spacedim; ++i)
198 {
199 std::string s_FieldStr = m_session->GetVariable(i);
200
201 if (m_session->DefinesFunction(m_velFuncName, s_FieldStr))
202 {
203 m_velFunction[i] =
204 m_session->GetFunction(m_velFuncName, s_FieldStr);
205 m_hasVel[i] = true;
206 }
207 }
208 if (expdim == 1)
209 {
210 return;
211 }
212
213 // initialize the poivot coordinate with a default at origin
215 if (m_hasRotation)
216 {
217 // frame angular velocity
218 std::vector<std::string> angularVar = {"Omega_x", "Omega_y", "Omega_z"};
219 for (int i = 0; i < 3; ++i)
220 {
221 std::string s_FieldStr = angularVar[i];
222 if (m_session->DefinesFunction(m_omegaFuncName, s_FieldStr))
223 {
224 // m_hasRotation = true;
225 m_omegaFunction[i] =
226 m_session->GetFunction(m_omegaFuncName, s_FieldStr);
227 m_hasOmega[i] = true;
228 // m_hasVel[m_spacedim+i]=true;
229 }
230 }
231
232 // for now only support Omega_z
233 // TODO: add the support for general rotation
234 for (int i = 0; i < 2; ++i)
235 {
236 ASSERTL0(!m_hasOmega[i], "Currently only Omega_z is supported");
237 }
238
239 // Reading the pivot point coordinate for rotation
240 const TiXmlElement *pivotElmt = pForce->FirstChildElement("PivotPoint");
241 // if not defined, zero would be the default
242 if (pivotElmt)
243 {
244 std::stringstream pivotPointStream;
245 std::string pivotPointStr = pivotElmt->GetText();
246 pivotPointStream.str(pivotPointStr);
247
248 for (int j = 0; j < m_spacedim; ++j)
249 {
250 pivotPointStream >> pivotPointStr;
251 if (!pivotPointStr.empty())
252 {
253 LibUtilities::Equation equ(m_session->GetInterpreter(),
254 pivotPointStr);
255 m_pivotPoint[j] = equ.Evaluate();
256 }
257 }
258 }
259
261 for (int j = 0; j < m_spacedim; ++j)
262 {
263 m_coords[j] = Array<OneD, NekDouble>(npoints);
264 }
265 pFields[0]->GetCoords(m_coords[0], m_coords[1], m_coords[2]);
266 // move the origin to the pivot point
267 for (int i = 0; i < m_spacedim; ++i)
268 {
269 Vmath::Sadd(npoints, -m_pivotPoint[i], m_coords[i], 1, m_coords[i],
270 1);
271 }
272
273 // account for the effect of rotation
274 // Omega_X results in having v and w even if not defined by user
275 // Omega_Y results in having u and w even if not defined by user
276 // Omega_Z results in having u and v even if not defined by user
277 //
278 for (int i = 0; i < 3; ++i)
279 {
280 int j = (i + 1) % 3;
281 int k = (i + 2) % 3;
282
283 if (m_hasOmega[i])
284 {
285 m_hasVel[j] = true;
286 m_hasVel[k] = true;
287 }
288 }
289 }
290}
291
292/**
293 * @brief Updates the forcing array with the current required forcing.
294 * @param pFields
295 * @param time
296 */
298{
299 // compute the velociites whos functions are provided in inertial frame
300 for (auto it : m_velFunction)
301 {
302 m_velXYZ[it.first] = it.second->Evaluate(0., 0., 0., time);
303 }
304 for (auto it : m_omegaFunction)
305 {
306 m_omegaXYZ[it.first] = it.second->Evaluate(0., 0., 0., time);
307 }
308 // include the effect of rotation
309 if (m_hasRotation)
310 {
311 UpdateTheta(time);
312
313 // transform the translation velocities to the moving frame
314 bn::ublas::vector<NekDouble> v0 = bn::ublas::zero_vector<NekDouble>(3);
315 bn::ublas::vector<NekDouble> v1 = bn::ublas::zero_vector<NekDouble>(3);
316 for (int i = 0; i < m_spacedim; ++i)
317 {
318 v0(i) = m_velXYZ[i];
319 }
320 v1 = bn::ublas::prec_prod(m_ProjMatZ, v0);
321 for (int i = 0; i < 3; ++i)
322 {
323 m_velxyz[i] = v1(i);
324 }
325
326 // transform the angular velocities to moving frame
327 v0 = bn::ublas::zero_vector<NekDouble>(3);
328 v1 = bn::ublas::zero_vector<NekDouble>(3);
329 for (auto it : m_omegaXYZ)
330 {
331 v0(it.first) = it.second;
332 }
333 v1 = bn::ublas::prec_prod(m_ProjMatZ, v0);
334 for (int i = 0; i < 3; ++i)
335 {
336 m_omegaxyz[i] = v1(i);
337 }
338 }
339 else
340 {
341 // for translation only,
342 for (int i = 0; i < m_spacedim; ++i)
343 {
344 m_velxyz[i] = m_velXYZ[i];
345 }
346 }
347
348 // set the velocities and rotation matrix for enforcement of boundary
349 // conditions in the Incompressible Naveri-Stokes
350 Array<OneD, NekDouble> vel(6, 0.0);
351 // save the linear and angular velocities to be used in enforcing bc
352 for (int i = 0; i < 3; ++i)
353 {
354 vel[i] = m_velxyz[i];
355 vel[i + 3] = m_omegaxyz[i];
356 }
357
358 auto equ = m_equ.lock();
359 ASSERTL0(equ, "Weak pointer to the equation system is expired");
360 auto FluidEq = std::dynamic_pointer_cast<FluidInterface>(equ);
361 // update the frame velocities
362 FluidEq->SetMovingFrameVelocities(vel);
363 // update the projection matrix
364 FluidEq->SetMovingFrameProjectionMat(m_ProjMatZ);
365 // update the frame angle (with respect to the inertial frame)
366 // this angle is used to update the meta data,
367 // on the other hand, for boundary conditions the projection matrix is used
368 FluidEq->SetMovingFrameAngles(m_theta);
369}
370
372{
373
374 NekDouble dt = m_session->GetParameter("TimeStep");
375 NekDouble t1 = time + dt;
376 std::map<int, NekDouble> Omega;
377
378 // Calculate angular velocities at dt
379 // TODO: Generalize to the case with a general 3D rotation support
380 for (int i = 0; i < 3; ++i)
381 {
382 if (m_hasOmega[i])
383 {
384 Omega[i] = 0.5 * (m_omegaXYZ[i] +
385 m_omegaFunction[i]->Evaluate(0., 0., 0., t1));
386 }
387 }
388
389 // Using the Omega_z
390 m_theta[2] += (Omega[2] * dt);
391
392 // update the rotation matrix
393 {
394 NekDouble sn, cs;
395 sn = sin(m_theta[2]);
396 cs = cos(m_theta[2]);
397
398 m_ProjMatZ(0, 0) = cs;
399 m_ProjMatZ(0, 1) = sn;
400 m_ProjMatZ(1, 0) = -sn;
401 m_ProjMatZ(1, 1) = cs;
402 m_ProjMatZ(2, 2) = 1.0;
403 }
404}
405
406/**
407 * @brief Adds the body force, -Omega X u.
408 * @param fields
409 * @param inarray
410 * @param outarray
411 * @param time
412 */
415 const Array<OneD, Array<OneD, NekDouble>> &inarray,
416 Array<OneD, Array<OneD, NekDouble>> &outarray, const NekDouble &time)
417{
418 boost::ignore_unused(time);
419 // If there is no rotation, body force is zero,
420 // nothing needs to be done here.
421 if (!m_hasRotation)
422 {
423 return;
424 }
425 // frame velocities are already updated in pre_Apply
426 int npoints = fields[0]->GetNpoints();
427 boost::ignore_unused(npoints);
428 addRotation(npoints, outarray, -1., inarray, outarray);
429}
430
431/**
432 * @brief outarray = inarray0 + angVelScale Omega x inarray1
433 */
435 int nPnts, // number of points
436 const Array<OneD, Array<OneD, NekDouble>> &inarray0, NekDouble angVelScale,
437 const Array<OneD, Array<OneD, NekDouble>> &inarray1,
439{
440 ASSERTL0(&inarray1 != &outarray, "inarray1 and outarray "
441 "should not be the same.");
442
443 // TODO: In case of having support for all three components of Omega,
444 // they should be transformed into the rotating frame first!
445
446 // In case that the inarray0 and outarry are different, to avoid using
447 // un-initialized array, copy the array first
448 if (&inarray0 != &outarray)
449 {
450 ASSERTL0(inarray0.size() == outarray.size(),
451 "inarray0 and outarray must have same dimentions");
452 for (int i = 0; i < inarray0.size(); ++i)
453 {
454 Vmath::Vcopy(nPnts, inarray0[i], 1, outarray[i], 1);
455 }
456 }
457
458 if (m_spacedim >= 2 && m_hasOmega[2])
459 {
460 NekDouble cp = m_omegaxyz[2] * angVelScale;
461 NekDouble cm = -1. * cp;
462
463 Vmath::Svtvp(nPnts, cm, inarray1[1], 1, outarray[0], 1, outarray[0], 1);
464 Vmath::Svtvp(nPnts, cp, inarray1[0], 1, outarray[1], 1, outarray[1], 1);
465 }
466
467 if (m_spacedim == 3 && m_hasOmega[0])
468 {
469 NekDouble cp = m_omegaxyz[0] * angVelScale;
470 NekDouble cm = -1. * cp;
471
472 Vmath::Svtvp(nPnts, cp, inarray1[1], 1, outarray[2], 1, outarray[2], 1);
473 Vmath::Svtvp(nPnts, cm, inarray1[2], 1, outarray[1], 1, outarray[1], 1);
474 }
475
476 if (m_spacedim == 3 && m_hasOmega[1])
477 {
478 NekDouble cp = m_omegaxyz[1] * angVelScale;
479 NekDouble cm = -1. * cp;
480
481 Vmath::Svtvp(nPnts, cp, inarray1[2], 1, outarray[0], 1, outarray[0], 1);
482 Vmath::Svtvp(nPnts, cm, inarray1[0], 1, outarray[2], 1, outarray[2], 1);
483 }
484}
485
488 const Array<OneD, Array<OneD, NekDouble>> &inarray,
489 Array<OneD, Array<OneD, NekDouble>> &outarray, const NekDouble &time)
490{
491 Update(time);
492 int npoints = fields[0]->GetNpoints();
493 if (m_isH2d && fields[0]->GetWaveSpace())
494 {
495 for (int i = 0; i < m_spacedim; ++i)
496 {
497 if (m_hasVel[i])
498 {
499 Array<OneD, NekDouble> tmpphys(npoints, -m_velxyz[i]);
500 Array<OneD, NekDouble> tmpcoef(npoints);
501 fields[0]->HomogeneousFwdTrans(npoints, tmpphys, tmpcoef);
502 Vmath::Vadd(npoints, tmpcoef, 1, inarray[i], 1, outarray[i], 1);
503 }
504 else if (&inarray != &outarray)
505 {
506 Vmath::Vcopy(npoints, inarray[i], 1, outarray[i], 1);
507 }
508 }
509 }
510 else
511 {
512 int npoints0 = npoints;
513 if (m_isH1d && fields[0]->GetWaveSpace())
514 {
515 npoints0 = m_hasPlane0 ? fields[0]->GetPlane(0)->GetNpoints() : 0;
516 }
517 for (int i = 0; i < m_spacedim; ++i)
518 {
519 if (m_hasVel[i])
520 {
521 Vmath::Sadd(npoints0, -m_velxyz[i], inarray[i], 1, outarray[i],
522 1);
523 if (&inarray != &outarray && npoints != npoints0)
524 {
525 Array<OneD, NekDouble> tmp = outarray[i] + npoints0;
526 Vmath::Vcopy(npoints - npoints0, inarray[i] + npoints0, 1,
527 tmp, 1);
528 }
529 }
530 else if (&inarray != &outarray)
531 {
532 Vmath::Vcopy(npoints, inarray[i], 1, outarray[i], 1);
533 }
534 }
535 if (m_hasRotation)
536 {
537 addRotation(npoints0, outarray, -1., m_coords, outarray);
538 }
539 }
540}
541
545{
546 std::map<std::string, std::string> fieldMetaDataMap;
547
548 // initialize theta to zero
549 for (auto &t : theta)
550 {
551 t = 0.0;
552 }
553
554 if (m_session->DefinesFunction("InitialConditions"))
555 {
556 for (int i = 0; i < pFields.size(); ++i)
557 {
559
560 vType = m_session->GetFunctionType("InitialConditions",
561 m_session->GetVariable(i));
562
564 {
565 std::string filename = m_session->GetFunctionFilename(
566 "InitialConditions", m_session->GetVariable(i));
567
568 fs::path pfilename(filename);
569
570 // redefine path for parallel file which is in directory
571 if (fs::is_directory(pfilename))
572 {
573 fs::path metafile("Info.xml");
574 fs::path fullpath = pfilename / metafile;
575 filename = LibUtilities::PortablePath(fullpath);
576 }
579 fld->ImportFieldMetaData(filename, fieldMetaDataMap);
580
581 // check to see if theta is defined
582 if (fieldMetaDataMap != LibUtilities::NullFieldMetaDataMap)
583 {
584 std::vector<std::string> vSuffix = {"_x", "_y", "_z"};
585
586 for (int j = 0; j < 3; ++j)
587 {
588 std::string sTheta = "Theta" + vSuffix[j];
589 auto iter = fieldMetaDataMap.find(sTheta);
590 if (iter != fieldMetaDataMap.end())
591 {
592 theta[j] =
593 boost::lexical_cast<NekDouble>(iter->second);
594 }
595 }
596
597 break;
598 }
599
600 break;
601 }
602 }
603 }
604}
605
606} // namespace SolverUtils
607} // namespace Nektar
const NekDouble Omega
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:215
static std::shared_ptr< FieldIO > CreateForFile(const LibUtilities::SessionReaderSharedPtr session, const std::string &filename)
Construct a FieldIO object for a given input filename.
Definition: FieldIO.cpp:226
tKey RegisterCreatorFunction(tKey idKey, CreatorFunction classCreator, std::string pDesc="")
Register a class with the factory.
Definition: NekFactory.hpp:198
Defines a forcing term to be explicitly applied.
Definition: Forcing.h:73
int m_NumVariable
Number of variables.
Definition: Forcing.h:123
const std::weak_ptr< EquationSystem > m_equ
Weak pointer to equation system using this forcing.
Definition: Forcing.h:119
LibUtilities::SessionReaderSharedPtr m_session
Session reader.
Definition: Forcing.h:117
virtual 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
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
std::map< int, LibUtilities::EquationSharedPtr > m_omegaFunction
void CheckForRestartTheta(const Array< OneD, MultiRegions::ExpListSharedPtr > &pFields, Array< OneD, NekDouble > &theta)
ForcingMovingReferenceFrame(const LibUtilities::SessionReaderSharedPtr &pSession, const std::weak_ptr< EquationSystem > &pEquation)
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) override
Adds the body force, -Omega X u.
virtual SOLVER_UTILS_EXPORT void v_InitObject(const Array< OneD, MultiRegions::ExpListSharedPtr > &pFields, const unsigned int &pNumForcingFields, const TiXmlElement *pForce) override
Initialise the forcing module.
std::map< int, LibUtilities::EquationSharedPtr > m_velFunction
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.
void Update(const NekDouble &time)
Updates the forcing array with the current required forcing.
std::shared_ptr< FieldIO > FieldIOSharedPtr
Definition: FieldIO.h:327
std::string PortablePath(const boost::filesystem::path &path)
create portable path on different platforms for boost::filesystem path
Definition: FileSystem.cpp:45
std::shared_ptr< SessionReader > SessionReaderSharedPtr
static FieldMetaDataMap NullFieldMetaDataMap
Definition: FieldIO.h:53
ForcingFactory & GetForcingFactory()
Declaration of the forcing factory singleton.
Definition: Forcing.cpp:44
The above copyright notice and this permission notice shall be included.
Definition: CoupledSolver.h:2
double NekDouble
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.cpp:617
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:354
void Sadd(int n, const T alpha, const T *x, const int incx, T *y, const int incy)
Add scalar y = alpha + x.
Definition: Vmath.cpp:379
void Vcopy(int n, const T *x, const int incx, T *y, const int incy)
Definition: Vmath.cpp:1191