Nektar++
FilterBodyFittedVelocity.cpp
Go to the documentation of this file.
1///////////////////////////////////////////////////////////////////////////////
2//
3// File FilterBodyFittedVelocity.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: Read the body-fitted coordinate system from the file output by
32// FieldConvert module bodyFittedVelocity and compute local max/
33// min/original body-fitted velocity compinents.
34//
35///////////////////////////////////////////////////////////////////////////////
36
39
41
44
45using std::cout;
46using std::endl;
47
48namespace Nektar::SolverUtils
49{
52 "BodyFittedVelocity", FilterBodyFittedVelocity::create);
53
56 const std::weak_ptr<EquationSystem> &pEquation, const ParamMap &pParams)
57 : FilterFieldConvert(pSession, pEquation, pParams)
58{
59 // Load sampling frequency
60 auto it = pParams.find("SampleFrequency");
61 if (it == pParams.end())
62 {
64 }
65 else
66 {
67 LibUtilities::Equation equ(m_session->GetInterpreter(), it->second);
68 m_sampleFrequency = round(equ.Evaluate());
69 }
70
71 // Load flag for filter type
72 it = pParams.find("OriginalOrMaxOrMin");
73 if (it == pParams.end())
74 {
76 }
77 else
78 {
79 std::string sOptionType = it->second.c_str();
80 if (boost::iequals(sOptionType, "maximum") ||
81 boost::iequals(sOptionType, "max"))
82 {
84 }
85 else if (boost::iequals(sOptionType, "minumun") ||
86 boost::iequals(sOptionType, "min"))
87 {
89 }
90 else if (boost::iequals(sOptionType, "original"))
91 {
93 }
94 else
95 {
96 WARNINGL0(false, "Detailed filter type is not found, use original");
98 }
99 }
100
101 // Load bodyFittedCoordinate from a file generated by FieldConvert -m
102 // bodyFittedVelocity
103 it = pParams.find("BodyFittedCoordinateFile");
104 ASSERTL0(it->second.length() > 0,
105 "Missing parameter 'BodyFittedCoordinateFile'.");
106
107 if (it->second.find_last_of('.') != std::string::npos)
108 {
109
110 m_bodyFittedCooriateFile = it->second;
111 }
112 else
113 {
114 std::stringstream outname;
115 outname << it->second << ".fld";
116 m_bodyFittedCooriateFile = outname.str();
117 }
118
120}
121
123{
124}
125
128 const NekDouble &time)
129{
130 // Initialise output arrays
132
133 // Generate the body-fitted coordinate system and distance field
134 // bfcsDir[i][j][k]
135 // i - dir vec: 0-main tangential, 1-normal, (2-minor tangential)
136 // j - component: 0-x, 1-y, (2-z)
137 // k - point id
138 const int npoints = pFields[0]->GetTotPoints();
140 for (int i = 0; i < m_spaceDim; ++i)
141 {
143 for (int j = 0; j < m_spaceDim; ++j)
144 {
145 m_bfcsDir[i][j] = Array<OneD, NekDouble>(npoints);
146 }
147 }
148
149 // Initialize the body fitted coordinate in the file
150 // m_bfsVars holds the var names for the coordinate system and will be
151 // used to find corresponding field to load from the input file.
152 // Ref: FilterFieldConvert.cpp (v_Initialise) & ProcessInterpField.cpp
153 // (Process)
154 m_bfsVars.resize(m_spaceDim * m_spaceDim); // 4 or 9
155 if (m_spaceDim == 2)
156 {
157 m_bfsVars[0] = "bfc_dir0_x";
158 m_bfsVars[1] = "bfc_dir0_y";
159 m_bfsVars[2] = "bfc_dir1_x";
160 m_bfsVars[3] = "bfc_dir1_y";
161 }
162 else
163 {
164 m_bfsVars[0] = "bfc_dir0_x";
165 m_bfsVars[1] = "bfc_dir0_y";
166 m_bfsVars[2] = "bfc_dir0_z";
167 m_bfsVars[3] = "bfc_dir1_x";
168 m_bfsVars[4] = "bfc_dir1_y";
169 m_bfsVars[5] = "bfc_dir1_z";
170 m_bfsVars[6] = "bfc_dir2_x";
171 m_bfsVars[7] = "bfc_dir2_y";
172 m_bfsVars[8] = "bfc_dir2_z";
173 }
174
175 // Load file
176 std::vector<LibUtilities::FieldDefinitionsSharedPtr> fieldDef;
177 std::vector<std::vector<NekDouble>> fieldData;
178 LibUtilities::FieldMetaDataMap fieldMetaData;
181 fld->Import(m_bodyFittedCooriateFile, fieldDef, fieldData, fieldMetaData);
182
183 // Get a tmp array to hold the coeffs from the input file
184 Array<OneD, NekDouble> tmp_coeffs;
185 tmp_coeffs = Array<OneD, NekDouble>(pFields[0]->GetNcoeffs(), 0.0);
186
187 // Extract data and convert to physical space
188 for (int k = 0; k < m_bfsVars.size(); ++k)
189 {
190 // In the fieldDef, for example fieldDef[0] is the quad and
191 // fieldDef[1] is the tri region
192 // Each of fieldDef[i] contains all the fields we expected in an fld
193 for (int i = 0; i < fieldData.size(); ++i)
194 {
195 pFields[0]->ExtractDataToCoeffs(fieldDef[i], fieldData[i],
196 m_bfsVars[k], tmp_coeffs);
197 }
198
199 // Bwd transorm the data and put them into m_bfcsDir[][]
200 int ii, jj;
201 jj = k % m_spaceDim;
202 ii = k / m_spaceDim;
203
204 pFields[0]->BwdTrans(tmp_coeffs, m_bfcsDir[ii][jj]);
205 }
206
207 // Allocate storage
209 m_curFieldsVels.resize(m_spaceDim); // m_spaceDim = m_nAddFields-1
211
212 for (int n = 0; n < m_spaceDim; ++n)
213 {
215 m_curFieldsVels[n] = Array<OneD, NekDouble>(npoints, 0.0);
216 m_outFieldsVels[n] = Array<OneD, NekDouble>(npoints, 0.0);
217 }
218
219 // Allocate storage for rho,p,T
221 {
222 m_curFieldsThermalVars.resize(3);
223 m_outFieldsThermalVars.resize(3);
224
225 for (int n = 0; n < 3; ++n)
226 {
229 }
230 }
231
232 // m_outFields contains the initialization values
233 // 2d: rho,rhou,rhov,E,u,v,p,T,s,a,Mach,Sensor,distanceToWall,u_bfc,v_bfc
234 if (m_initialized)
235 {
236 for (int n = 0; n < m_spaceDim; ++n)
237 {
238 pFields[0]->BwdTrans(m_outFields[m_nVars + 1 + n],
239 m_outFieldsVels[n]);
240 if (pFields[0]->GetWaveSpace())
241 {
242 pFields[0]->HomogeneousBwdTrans(npoints, m_outFieldsVels[n],
243 m_outFieldsVels[n]);
244 }
245 }
246
248 {
249 // For cfs, initialize thermal vars
250 // shift_thermal for [rho, p, T] in m_outFields
251 int shift_thermal[3] = {0, m_spaceDim * 2 + 2, m_spaceDim * 2 + 3};
252
253 for (int n = 0; n < 3; ++n)
254 {
255 pFields[0]->BwdTrans(m_outFields[shift_thermal[n]],
257 if (pFields[0]->GetWaveSpace())
258 {
259 pFields[0]->HomogeneousBwdTrans(npoints,
262 }
263 }
264 }
265 }
266 else
267 {
268 ASSERTL0(false, "Restart file is expectd. It can be generated by \
269 FieldConvert in serial. For example: \
270 FieldConvert -m bodyFittedVelocity:bnd=0:bfcOut=1 \
271 mesh.xml session.xml baseflow.fld bfvFile.fld");
272 }
273}
274
277{
278 // Fill in the var names using the routine in base class
280
281 // Check type of problem
282 std::vector<std::string> varNames =
283 pFields[0]->GetSession()->GetVariables();
284 if (boost::iequals(varNames[0], "u") && boost::iequals(varNames[1], "v"))
285 {
287 m_spaceDim = pFields.size() - 1;
288 }
289 else if (boost::iequals(varNames[0], "rho") &&
290 boost::iequals(varNames[1], "rhou"))
291 {
293 m_spaceDim = pFields.size() - 2;
294 }
295 else
296 {
297 WARNINGL0(false, "Problem type is not claear. Please check");
299 m_spaceDim = 2;
300 }
301
302 m_nVars = m_variables.size(); // Include extra vars
303 m_nFields = pFields.size(); // Conservative vars for cfs
304 m_nAddFields = 3;
305
306 // Fill in the body-fitted velocity names
307 // bfc represents body-fitted coordinate
308 m_variables.push_back("distanceToWall");
309 m_variables.push_back("u_bfc");
310 m_variables.push_back("v_bfc");
311 if (m_spaceDim == 3)
312 {
313 m_variables.push_back("w_bfc");
314 ++m_nAddFields;
315 }
316 else if (m_spaceDim != 2)
317 {
318 ASSERTL0(false, "Unsupported dimension");
319 }
320}
321
322// m_curFieldsVels_Car is the velocity in Cartesian coordinate system in current
323// step
324// m_curFieldsVels is the velocity in body-fittd coordinate system in
325// current step
326// m_outFieldsVels is the velocity in body-fittd coordinate
327// sysetm for output
328// m_outFields is the coefficients for output
329//
330// Before execusion, the fields are expected to be initialized so that
331// m_outFields and m_outFieldsVels are not empty.
332//
333// *** Note ***
334// In order to get the amplitude field, take the difference of
335// max (perturbed) and max (perturbation-free) for a better result.
336// The difference of max (perturbed) and original (perturbation-free)
337// contains noises for unknown reasons at the moment.
340 std::vector<Array<OneD, NekDouble>> &fieldcoeffs,
341 [[maybe_unused]] const NekDouble &time)
342{
343 // Use shift_vel to get the current u,v,w in Cartesian coordinate
344 // cfs_2D:
345 // rho,rhou,rhov,E,u,v,p,T,s,a,Mach,Sensor,distanceToWall,u_bfc,v_bfc
346 // inc_2D: u,v,p
347 int shift_vel = (m_problemType == eCompressible) ? (m_spaceDim + 2) : 0;
348
349 // Get current u,v,w in Cartesian coordinate
350 for (int n = 0; n < m_spaceDim; ++n)
351 {
352 pFields[0]->BwdTrans(fieldcoeffs[shift_vel + n],
354 if (pFields[0]->GetWaveSpace())
355 {
356 pFields[0]->HomogeneousBwdTrans(pFields[0]->GetNpoints(),
359 }
360 }
361
362 // Project the velocity into the body-fitted coordinate system
363 int npoints = pFields[0]->GetTotPoints();
364 Array<OneD, NekDouble> vel_tmp(npoints);
365
366 for (int i = 0; i < m_spaceDim; ++i) // loop for bfc velocity
367 {
368 Vmath::Zero(npoints, m_curFieldsVels[i], 1);
369
370 for (int j = 0; j < m_spaceDim; ++j)
371 {
372 Vmath::Vmul(npoints, m_curFieldsVels_Car[j], 1, m_bfcsDir[i][j], 1,
373 vel_tmp, 1);
374 Vmath::Vadd(npoints, vel_tmp, 1, m_curFieldsVels[i], 1,
375 m_curFieldsVels[i], 1);
376 }
377 }
378
379 // Get max/min/original for the u/v/w_bfc field
380 for (int n = 0; n < m_spaceDim; ++n)
381 {
382 size_t length = m_outFieldsVels[n].size();
383
384 if (m_filterType == eMax)
385 {
386 // Compute max
387 for (int i = 0; i < length; ++i)
388 {
389 if (m_curFieldsVels[n][i] > m_outFieldsVels[n][i])
390 {
391 m_outFieldsVels[n][i] = m_curFieldsVels[n][i];
392 }
393 }
394 }
395 else if (m_filterType == eMin)
396 {
397 // Compute min
398 for (int i = 0; i < length; ++i)
399 {
400 if (m_curFieldsVels[n][i] < m_outFieldsVels[n][i])
401 {
402 m_outFieldsVels[n][i] = m_curFieldsVels[n][i];
403 }
404 }
405 }
406 else
407 {
408 // Original field
410 }
411 }
412
413 // Forward transform and put into m_outFields
414 for (int n = 0; n < m_spaceDim; ++n)
415 {
416 pFields[0]->FwdTransLocalElmt(m_outFieldsVels[n],
417 m_outFields[m_nVars + 1 + n]);
418 }
419
420 // Process the thermal variables for compressible flows
422 {
423 // Get current rho,p,T fields
424 // shift_thermal for [rho, p, T] in fieldcoeffs
425 int shift_thermal[3] = {0, m_spaceDim * 2 + 2, m_spaceDim * 2 + 3};
426
427 for (int n = 0; n < 3; ++n)
428 {
429 pFields[0]->BwdTrans(fieldcoeffs[shift_thermal[n]],
431 if (pFields[0]->GetWaveSpace())
432 {
433 pFields[0]->HomogeneousBwdTrans(pFields[0]->GetNpoints(),
436 }
437 }
438
439 // Get max/min/original for the rho/p/T fields
440 for (int n = 0; n < 3; ++n)
441 {
442 size_t length = m_outFieldsThermalVars[n].size();
443
444 if (m_filterType == eMax)
445 {
446 // Compute max
447 for (int i = 0; i < length; ++i)
448 {
449 if (m_curFieldsThermalVars[n][i] >
451 {
454 }
455 }
456 }
457 else if (m_filterType == eMin)
458 {
459 // Compute min
460 for (int i = 0; i < length; ++i)
461 {
462 if (m_curFieldsThermalVars[n][i] <
464 {
467 }
468 }
469 }
470 else
471 {
472 // Original field
474 }
475 }
476
477 // Forward transform and put into m_outFields
478 for (int n = 0; n < 3; ++n)
479 {
480 pFields[0]->FwdTransLocalElmt(m_outFieldsThermalVars[n],
481 m_outFields[shift_thermal[n]]);
482 }
483 }
484}
485
488 &pFields,
489 [[maybe_unused]] const NekDouble &time)
490{
491 m_fieldMetaData["NumberOfFieldDumps"] = std::to_string(m_numSamples);
492}
493
495{
496 return 1.0;
497}
498
499} // namespace Nektar::SolverUtils
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:208
#define WARNINGL0(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:224
tKey RegisterCreatorFunction(tKey idKey, CreatorFunction classCreator, std::string pDesc="")
Register a class with the factory.
Definition: NekFactory.hpp:197
static FilterSharedPtr create(const LibUtilities::SessionReaderSharedPtr &pSession, const std::weak_ptr< EquationSystem > &pEquation, const std::map< std::string, std::string > &pParams)
Creates an instance of this class.
std::vector< Array< OneD, NekDouble > > m_outFieldsVels
void v_ProcessSample(const Array< OneD, const MultiRegions::ExpListSharedPtr > &pFields, std::vector< Array< OneD, NekDouble > > &fieldcoeffs, const NekDouble &time) override
Array< OneD, Array< OneD, Array< OneD, NekDouble > > > m_bfcsDir
std::vector< Array< OneD, NekDouble > > m_curFieldsVels
SOLVER_UTILS_EXPORT FilterBodyFittedVelocity(const LibUtilities::SessionReaderSharedPtr &pSession, const std::weak_ptr< EquationSystem > &pEquation, const ParamMap &pParams)
std::vector< Array< OneD, NekDouble > > m_curFieldsThermalVars
void v_Initialise(const Array< OneD, const MultiRegions::ExpListSharedPtr > &pFields, const NekDouble &time) override
static std::string className
Name of the class.
std::vector< Array< OneD, NekDouble > > m_curFieldsVels_Car
void v_FillVariablesName(const Array< OneD, const MultiRegions::ExpListSharedPtr > &pFields) override
std::vector< Array< OneD, NekDouble > > m_outFieldsThermalVars
void v_PrepareOutput(const Array< OneD, const MultiRegions::ExpListSharedPtr > &pFields, const NekDouble &time) override
virtual SOLVER_UTILS_EXPORT void v_FillVariablesName(const Array< OneD, const MultiRegions::ExpListSharedPtr > &pFields)
LibUtilities::FieldMetaDataMap m_fieldMetaData
std::vector< Array< OneD, NekDouble > > m_outFields
SOLVER_UTILS_EXPORT void v_Initialise(const Array< OneD, const MultiRegions::ExpListSharedPtr > &pFields, const NekDouble &time) override
LibUtilities::SessionReaderSharedPtr m_session
Definition: Filter.h:83
std::map< std::string, std::string > ParamMap
Definition: Filter.h:65
std::shared_ptr< FieldIO > FieldIOSharedPtr
Definition: FieldIO.h:322
std::map< std::string, std::string > FieldMetaDataMap
Definition: FieldIO.h:50
std::shared_ptr< SessionReader > SessionReaderSharedPtr
FilterFactory & GetFilterFactory()
Definition: Filter.cpp:39
double NekDouble
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 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 Zero(int n, T *x, const int incx)
Zero vector.
Definition: Vmath.hpp:273