Nektar++
Loading...
Searching...
No Matches
ProcessWSS.cpp
Go to the documentation of this file.
1////////////////////////////////////////////////////////////////////////////////
2//
3// File: ProcessWSS.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: Computes wss field.
32//
33////////////////////////////////////////////////////////////////////////////////
34
35#include <iostream>
36#include <string>
37
38#include "ProcessWSS.h"
39
43
44using namespace std;
45
46namespace Nektar::FieldUtils
47{
48
51 "Computes wall shear stress field.");
52
56
60
61void ProcessWSS::v_Process(po::variables_map &vm)
62{
64
65 int i, j;
66 int nfields = m_f->m_variables.size();
67 int expdim = m_f->m_graph->GetSpaceDimension();
68 m_spacedim = expdim + m_f->m_numHomogeneousDir;
69
70 if (m_f->m_exp[0]->GetNumElmts() == 0)
71 {
72 return;
73 }
74
75 if (m_spacedim == 1)
76 {
77 ASSERTL0(false, "Error: wss for a 1D problem cannot "
78 "be computed");
79 }
80
81 // Declare arrays
82 int nshear = m_spacedim + 1;
83 int nstress = m_spacedim * m_spacedim;
84 int ngrad = m_spacedim * m_spacedim;
85
86 Array<OneD, Array<OneD, NekDouble>> velocity(nfields);
88 Array<OneD, Array<OneD, NekDouble>> stress(nstress), fstress(nstress);
90
93 Array<OneD, Array<OneD, NekDouble>> BndElmtPhys(nfields);
94 Array<OneD, Array<OneD, NekDouble>> BndElmtCoeffs(nfields);
95
96 // will resuse nfields expansions to write shear components.
97 if (nshear > nfields)
98 {
99 m_f->m_exp.resize(nshear);
100 for (i = nfields; i < nshear; ++i)
101 {
102 m_f->m_exp[nfields + i] =
103 m_f->AppendExpList(m_f->m_numHomogeneousDir);
104 }
105 }
106
107 // Create map of boundary ids for partitioned domains
109 m_f->m_exp[0]->GetGraph());
111 bcs.GetBoundaryRegions();
112
113 // when using extract we may not have defined all boundary regions
114 // so identify that here
115 std::set<int> ProcessBnd;
116 if (m_f->m_session->DefinesTag("CreateBndRegions"))
117 {
118 // evaluate bnd regions to be generated
119 vector<unsigned int> bndRegions;
121 m_f->m_session->GetTag("CreateBndRegions"), bndRegions),
122 "Failed to interpret bnd values string");
123
124 for (auto &bnd : bndRegions)
125 {
126 if (bregions.count(bnd) == 1)
127 {
128 ProcessBnd.insert(bnd);
129 }
130 }
131 }
132 else
133 {
134 for (auto &it : bregions)
135 {
136 ProcessBnd.insert(it.first);
137 }
138 }
139
140 map<int, int> BndRegionMap;
141 int cnt = 0;
142 for (auto &breg_it : bregions)
143 {
144 if (ProcessBnd.count(breg_it.first))
145 {
146 BndRegionMap[breg_it.first] = cnt++;
147 }
148 }
149
150 // Loop over boundaries to Write
151 for (int b = 0; b < m_f->m_bndRegionsToWrite.size(); ++b)
152 {
153 if (BndRegionMap.count(m_f->m_bndRegionsToWrite[b]) == 1)
154 {
155 int bnd = BndRegionMap[m_f->m_bndRegionsToWrite[b]];
156 // Get expansion list for boundary and for elements containing this
157 // bnd
158 for (i = 0; i < nshear; i++)
159 {
160 BndExp[i] = m_f->m_exp[i]->UpdateBndCondExpansion(bnd);
161 }
162
163 Array<OneD, int> ElmtID, edgeID;
164 Array<OneD, NekDouble> tmp1, tmp2;
165
166 for (i = 0; i < nfields; i++)
167 {
168 m_f->m_exp[i]->GetBndElmtExpansion(bnd, BndElmtExp[i]);
169 BndElmtPhys[i] = BndElmtExp[i]->UpdatePhys();
170 }
171
172 // Get number of points in expansions
173 int nqb = BndExp[0]->GetTotPoints();
174 int nqe = BndElmtExp[0]->GetTotPoints();
175
176 // Initialise local arrays for the velocity gradients, and
177 // stress components size of total number of quadrature
178 // points for elements in this bnd
179 for (i = 0; i < ngrad; ++i)
180 {
181 grad[i] = Array<OneD, NekDouble>(nqe);
182 }
183
184 for (i = 0; i < nstress; ++i)
185 {
186 stress[i] = Array<OneD, NekDouble>(nqe);
187 }
188
189 Array<OneD, NekDouble> div(nqe, 0.0);
190
191 // initialise arrays in the boundary
192 for (i = 0; i < nstress; ++i)
193 {
194 fstress[i] = Array<OneD, NekDouble>(nqb);
195 }
196
197 for (i = 0; i < nshear; ++i)
198 {
199 fshear[i] = Array<OneD, NekDouble>(nqb, 0.0);
200 }
201
202 // Extract Velocities
203 GetVelocity(BndElmtExp, BndElmtPhys, velocity);
204
205 // Extract viscosity coefficients
206 NekDouble lambda;
207 Array<OneD, NekDouble> mu(nqe, 0.0);
208 GetViscosity(BndElmtExp, BndElmtPhys, mu, lambda);
209
210 // Compute gradients
211 for (i = 0; i < m_spacedim; ++i)
212 {
213 if (m_spacedim == 2)
214 {
215 BndElmtExp[i]->PhysDeriv(velocity[i],
216 grad[i * m_spacedim + 0],
217 grad[i * m_spacedim + 1]);
218 }
219 else
220 {
221 BndElmtExp[i]->PhysDeriv(
222 velocity[i], grad[i * m_spacedim + 0],
223 grad[i * m_spacedim + 1], grad[i * m_spacedim + 2]);
224 }
225 // Add contribution to div(u)
226 Vmath::Vadd(nqe, grad[i * m_spacedim + i], 1, div, 1, div, 1);
227 }
228
229 // Velocity divergence scaled by lambda * mu
230 Vmath::Smul(nqe, lambda, div, 1, div, 1);
231 Vmath::Vmul(nqe, mu, 1, div, 1, div, 1);
232
233 // Compute stress component terms
234 // tau_ij = mu*(u_i,j + u_j,i) + mu*lambda*delta_ij*div(u)
235 for (i = 0; i < m_spacedim; ++i)
236 {
237 for (j = i; j < m_spacedim; ++j)
238 {
239 Vmath::Vadd(nqe, grad[i * m_spacedim + j], 1,
240 grad[j * m_spacedim + i], 1,
241 stress[i * m_spacedim + j], 1);
242
243 Vmath::Vmul(nqe, mu, 1, stress[i * m_spacedim + j], 1,
244 stress[i * m_spacedim + j], 1);
245
246 if (i == j)
247 {
248 // Add divergence term to diagonal
249 Vmath::Vadd(nqe, stress[i * m_spacedim + j], 1, div, 1,
250 stress[i * m_spacedim + j], 1);
251 }
252 else
253 {
254 // Copy to make symmetric
255 Vmath::Vcopy(nqe, stress[i * m_spacedim + j], 1,
256 stress[j * m_spacedim + i], 1);
257 }
258 }
259 }
260
261 // Get boundary stress values.
262 for (j = 0; j < nstress; ++j)
263 {
264 m_f->m_exp[0]->ExtractElmtToBndPhys(bnd, stress[j], fstress[j]);
265 }
266
267 // Get normals
269 m_f->m_exp[0]->GetBoundaryNormals(bnd, normals);
270 // Reverse normals, to get correct orientation for the body
271 for (i = 0; i < m_spacedim; ++i)
272 {
273 Vmath::Neg(nqb, normals[i], 1);
274 }
275
276 // calculate wss, and update coeffs in the boundary expansion
277 // S = tau_ij * n_j
278 for (i = 0; i < m_spacedim; ++i)
279 {
280 for (j = 0; j < m_spacedim; ++j)
281 {
282 Vmath::Vvtvp(nqb, normals[j], 1,
283 fstress[i * m_spacedim + j], 1, fshear[i], 1,
284 fshear[i], 1);
285 }
286 }
287
288 // T = S - (S.n)n
289 for (i = 0; i < m_spacedim; ++i)
290 {
291 Vmath::Vvtvp(nqb, normals[i], 1, fshear[i], 1,
292 fshear[nshear - 1], 1, fshear[nshear - 1], 1);
293 }
294 Vmath::Smul(nqb, -1.0, fshear[nshear - 1], 1, fshear[nshear - 1],
295 1);
296
297 for (i = 0; i < m_spacedim; i++)
298 {
299 Vmath::Vvtvp(nqb, normals[i], 1, fshear[nshear - 1], 1,
300 fshear[i], 1, fshear[i], 1);
301 BndExp[i]->FwdTransLocalElmt(fshear[i],
302 BndExp[i]->UpdateCoeffs());
303 }
304
305 // Tw
306 Vmath::Zero(nqb, fshear[nshear - 1], 1);
307 for (i = 0; i < m_spacedim; ++i)
308 {
309 Vmath::Vvtvp(nqb, fshear[i], 1, fshear[i], 1,
310 fshear[nshear - 1], 1, fshear[nshear - 1], 1);
311 }
312 Vmath::Vsqrt(nqb, fshear[nshear - 1], 1, fshear[nshear - 1], 1);
313 BndExp[nshear - 1]->FwdTransLocalElmt(
314 fshear[nshear - 1], BndExp[nshear - 1]->UpdateCoeffs());
315 }
316 }
317
318 if (m_spacedim == 2)
319 {
320 m_f->m_variables[0] = "Shear_x";
321 m_f->m_variables[1] = "Shear_y";
322 m_f->m_variables[2] = "Shear_mag";
323 }
324 else
325 {
326 m_f->m_variables[0] = "Shear_x";
327 m_f->m_variables[1] = "Shear_y";
328 m_f->m_variables[2] = "Shear_z";
329 m_f->m_variables[3] = "Shear_mag";
330 }
331}
332
335 const Array<OneD, Array<OneD, NekDouble>> &BndElmtPhys,
337{
339 int npoints = exp[0]->GetNpoints();
340
341 if (boost::iequals(m_f->m_variables[0], "u"))
342 {
343 // IncNavierStokesSolver
344 m_mu = m_f->m_session->GetParameter("Kinvis");
345 Vmath::Fill(npoints, m_mu, mu, 1);
346 lambda = 0;
347 }
348 else if (boost::iequals(m_f->m_variables[0], "rho") &&
349 boost::iequals(m_f->m_variables[1], "rhou"))
350 {
351 // CompressibleFlowSolver
352 std::string m_ViscosityType;
353 m_f->m_session->LoadParameter("mu", m_mu, 1.78e-05);
354 m_f->m_session->LoadParameter("lambda", lambda, -2.0 / 3.0);
355 m_f->m_session->LoadSolverInfo("ViscosityType", m_ViscosityType,
356 "Constant");
357
358 if (m_ViscosityType == "Variable")
359 {
360 // Check equation of state
361 std::string eosType;
362 bool m_idealGas;
363 m_f->m_session->LoadSolverInfo("EquationOfState", eosType,
364 "IdealGas");
365 m_idealGas = boost::iequals(eosType, "IdealGas");
366 ASSERTL0(
367 m_idealGas,
368 "Only IdealGas EOS implemented for Variable ViscosityType");
369
370 // Get relevant parameters
371 NekDouble m_gamma;
372 NekDouble m_pInf;
374 NekDouble m_gasConstant;
375 NekDouble cv_inv;
376 NekDouble m_Tref;
377 NekDouble m_TRatioSutherland;
378 m_f->m_session->LoadParameter("Gamma", m_gamma, 1.4);
379 m_f->m_session->LoadParameter("pInf", m_pInf, 101325);
380 m_f->m_session->LoadParameter("rhoInf", m_rhoInf, 1.225);
381 m_f->m_session->LoadParameter("GasConstant", m_gasConstant,
382 287.058);
383 m_f->m_session->LoadParameter("Tref", m_Tref, 288.15);
384 m_TRatioSutherland = 110.0 / m_Tref;
385
386 // Get temperature from flowfield
387 cv_inv = (m_gamma - 1.0) / m_gasConstant;
388 // e = 1/rho ( E - 1/2 ( rhou^2/rho + ... ) )
389 Array<OneD, NekDouble> tmp(npoints, 0.0);
390 Array<OneD, NekDouble> energy(npoints, 0.0);
391 Array<OneD, NekDouble> temperature(npoints, 0.0);
392
393 Vmath::Vcopy(npoints, BndElmtPhys[m_spacedim + 1], 1, energy, 1);
394 for (int i = 0; i < m_spacedim; i++)
395 {
396 // rhou^2
397 Vmath::Vmul(npoints, BndElmtPhys[i + 1], 1, BndElmtPhys[i + 1],
398 1, tmp, 1);
399 // rhou^2/rho
400 Vmath::Vdiv(npoints, tmp, 1, BndElmtPhys[0], 1, tmp, 1);
401
402 // 0.5 rhou^2/rho
403 Vmath::Smul(npoints, 0.5, tmp, 1, tmp, 1);
404 // E - 0.5 rhou^2/rho - ...
405 Vmath::Vsub(npoints, energy, 1, tmp, 1, energy, 1);
406 }
407
408 // rhou^2/rho
409 Vmath::Vdiv(npoints, energy, 1, BndElmtPhys[0], 1, energy, 1);
410
411 // T = e/Cv
412 Vmath::Smul(npoints, cv_inv, energy, 1, temperature, 1);
413
414 // Variable viscosity through the Sutherland's law
415 //
416 // WARNING, if this routine is modified the same must be done in the
417 // CompressibleFlowSolver function in VariableConverter.cpp
418 // (this class should be restructured).
419
420 const NekDouble C = m_TRatioSutherland;
421 NekDouble mu_star = m_mu;
422 NekDouble T_star = m_pInf / (m_rhoInf * m_gasConstant);
423 NekDouble ratio;
424 for (int i = 0; i < npoints; ++i)
425 {
426 ratio = temperature[i] / T_star;
427 mu[i] = mu_star * ratio * sqrt(ratio) * (1 + C) / (ratio + C);
428 }
429 }
430 else
431 {
432 Vmath::Fill(npoints, m_mu, mu, 1);
433 }
434 }
435 else
436 {
437 // Unknown
438 ASSERTL0(false, "Invalid variables for WSS");
439 }
440}
441
444 const Array<OneD, Array<OneD, NekDouble>> &BndElmtPhys,
446{
447 int npoints = exp[0]->GetNpoints();
448 if (boost::iequals(m_f->m_variables[0], "u"))
449 {
450 // IncNavierStokesSolver
451 for (int i = 0; i < m_spacedim; ++i)
452 {
453 vel[i] = Array<OneD, NekDouble>(npoints);
454 Vmath::Vcopy(npoints, BndElmtPhys[i], 1, vel[i], 1);
455 }
456 }
457 else if (boost::iequals(m_f->m_variables[0], "rho") &&
458 boost::iequals(m_f->m_variables[1], "rhou"))
459 {
460 // CompressibleFlowSolver
461 for (int i = 0; i < m_spacedim; ++i)
462 {
463 vel[i] = Array<OneD, NekDouble>(npoints);
464 Vmath::Vdiv(npoints, BndElmtPhys[i + 1], 1, BndElmtPhys[0], 1,
465 vel[i], 1);
466 }
467 }
468 else
469 {
470 // Unknown
471 ASSERTL0(false, "Could not identify velocity for WSS");
472 }
473}
474
475} // namespace Nektar::FieldUtils
NekDouble m_mu
NekDouble m_rhoInf
#define ASSERTL0(condition, msg)
FieldSharedPtr m_f
Field object.
Definition Module.h:239
This processing module sets up for the boundary field to be extracted.
void v_Process(po::variables_map &vm) override
void GetViscosity(const Array< OneD, MultiRegions::ExpListSharedPtr > exp, const Array< OneD, Array< OneD, NekDouble > > &BndElmtdPhys, Array< OneD, NekDouble > &mu, NekDouble &lambda)
static std::shared_ptr< Module > create(FieldSharedPtr f)
Creates an instance of this class.
Definition ProcessWSS.h:51
void GetVelocity(const Array< OneD, MultiRegions::ExpListSharedPtr > exp, const Array< OneD, Array< OneD, NekDouble > > &BndElmtdPhys, Array< OneD, Array< OneD, NekDouble > > &vel)
void v_Process(po::variables_map &vm) override
Write mesh to output file.
tKey RegisterCreatorFunction(tKey idKey, CreatorFunction classCreator, std::string pDesc="")
Register a class with the factory.
static bool GenerateVector(const std::string &str, std::vector< T > &out)
Takes a comma-separated string and converts it to entries in a vector.
const BoundaryRegionCollection & GetBoundaryRegions(void) const
Definition Conditions.h:273
std::shared_ptr< Field > FieldSharedPtr
Definition Field.hpp:1026
std::pair< ModuleType, std::string > ModuleKey
Definition Module.h:180
ModuleFactory & GetModuleFactory()
Definition Module.cpp:47
std::map< int, BoundaryRegionShPtr > BoundaryRegionCollection
Definition Conditions.h:249
void Vsqrt(int n, const T *x, const int incx, T *y, const int incy)
sqrt y = sqrt(x)
Definition Vmath.hpp:340
void Vmul(int n, const T *x, const int incx, const T *y, const int incy, T *z, const int incz)
Multiply vector z = x*y.
Definition Vmath.hpp:72
void Neg(int n, T *x, const int incx)
Negate x = -x.
Definition Vmath.hpp:292
void Vvtvp(int n, const T *w, const int incw, const T *x, const int incx, const T *y, const int incy, T *z, const int incz)
vvtvp (vector times vector plus vector): z = w*x + y
Definition Vmath.hpp:366
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 Smul(int n, const T alpha, const T *x, const int incx, T *y, const int incy)
Scalar multiply y = alpha*x.
Definition Vmath.hpp:100
void Vdiv(int n, const T *x, const int incx, const T *y, const int incy, T *z, const int incz)
Multiply vector z = x/y.
Definition Vmath.hpp:126
void Zero(int n, T *x, const int incx)
Zero vector.
Definition Vmath.hpp:273
void Fill(int n, const T alpha, T *x, const int incx)
Fill a vector with a constant value.
Definition Vmath.hpp:54
void Vcopy(int n, const T *x, const int incx, T *y, const int incy)
Definition Vmath.hpp:825
void Vsub(int n, const T *x, const int incx, const T *y, const int incy, T *z, const int incz)
Subtract vector z = x-y.
Definition Vmath.hpp:220
STL namespace.
scalarT< T > sqrt(scalarT< T > in)
Definition scalar.hpp:290