Nektar++
ProcessBodyFittedVelocity.cpp
Go to the documentation of this file.
1////////////////////////////////////////////////////////////////////////////////
2//
3// File: ProcessBodyFittedVelocity.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: Generate the body-fitted coordinate system and compute the
32// body-fitted velocity components.
33//
34////////////////////////////////////////////////////////////////////////////////
35
36#include <iostream>
37#include <string>
38
43
44#include "ProcessMapping.h"
46
49
50using namespace std;
51
52namespace Nektar
53{
54namespace FieldUtils
55{
56
59 ModuleKey(eProcessModule, "bodyFittedVelocity"),
61 "Convert the velocity components from the Cartesian coordinate into "
62 "the body-fitted coordinate.");
63
66{
67 f->m_writeBndFld =
68 false; // turned on in the father class ProcessBoundaryExtract
69
70 // bnd is read from father class ProcessBoundaryExtract
71 m_config["assistDir"] =
72 ConfigOption(false, "0.0,0.0,1.0",
73 "The normal direction of the assistant plane, where \
74 the first body-fitted coordinate direction is located. \
75 The assistance plane is defined in point normal form. \
76 Default = [0,0,1]");
77 m_config["checkAngle"] =
78 ConfigOption(true, "0", "The flag for checking the distance vector \
79 perpendicular to the nearest element or not. It \
80 does not need to be turned on if geometry is \
81 smooth and there is no special consideration of \
82 the body-fitted coordinate system. It would be \
83 helpful to set up a desired coordinate system \
84 based on the surface with with sharp corners, \
85 such as at the presence of a step or gap. \
86 Default = false.");
87 m_config["distTol"] = ConfigOption(
88 false, "1.0e-12", "The distance tolerence to properly find out the \
89 nearest boundary element. It works together with \
90 the CHECKANGLE option to set up the body-fitted \
91 coordinate system near the corner. \
92 Default = 1.0e-12.");
93 m_config["bfcOut"] = ConfigOption(
94 true, "1", "The flag control whether the body-fitted coordinate \
95 system will be output. Default = true.");
96}
97
99{
100}
101
102/*Note
103 * This module converts the velocity components into the body-fitted coordinate.
104 * It works for both incompressible and compressible cases.
105 * The only requirement is the [u,v] fields the 2D case or [u,v,w] fields for
106 * 2.5D/3D case exist in the input fld fild.
107 * The input cases can be 2D, 2.5D and 3D.
108 * The data will be exported with .fld extension.
109 *
110 * Mapping is not supported at the moment
111 *
112 * The user defined parameters are: bnd, fixedDir
113 * - "bnd" for the wall reference id, which is defiend in the father class
114 * "ProcessBoundaryExtract".
115 * - "fixedDir" is the dorection at which the velocity component is not rotated.
116 */
117void ProcessBodyFittedVelocity::v_Process(po::variables_map &vm)
118{
120
121 // Get dim to store data
122 const int nFields = m_f->m_variables.size();
123 const int nCoordDim = m_f->m_exp[0]->GetCoordim(0);
124 const int nSpaceDim = nCoordDim + m_f->m_numHomogeneousDir;
125 const int nAddFields = nSpaceDim + 1; // distanceToWall, u_bfc, v_bfc, w_bfc
126
127 // Tolerence setting
128 // To include more elmts for further check
129 const NekDouble distTol = m_config["distTol"].as<NekDouble>();
130 const NekDouble geoTol = 1.0e-12; // To check if two pnts are too close
131 const NekDouble dirTol = 1.0e-4; // To check if two unit vecs are parallel
132 const NekDouble iterTol = 1.0e-12; // To check if locCoord iter convergence
133
134 const bool isCheckAngle = m_config["checkAngle"].as<bool>();
135 const bool isOutputBfc = m_config["bfcOut"].as<bool>();
136
137 // Get the assist vector
138 vector<NekDouble> assistDir;
139 ASSERTL0(ParseUtils::GenerateVector(m_config["assistDir"].as<string>(),
140 assistDir),
141 "Failed to interpret assistance direction");
142
143 Array<OneD, NekDouble> assistVec(3); // Save the assist vector
144 for (int i = 0; i < 3; ++i)
145 {
146 assistVec[i] = (assistDir.size() > i) ? assistDir[i] : 0.0;
147 }
148 if (nCoordDim == 2)
149 {
150 assistVec[0] = 0.0;
151 assistVec[1] = 0.0;
152 }
153
154 NekDouble norm = sqrt(Vmath::Dot(3, assistVec, 1, assistVec, 1));
155 if (norm < geoTol)
156 {
157 ASSERTL0(false, "Error. The amplitude of assist vector is smaller than \
158 the geometry tolerence 1.0e-12.");
159 }
160 Vmath::Smul(3, 1.0 / norm, assistVec, 1, assistVec, 1);
161
162 // Get the bnd id
163 // We only use the first one [0], check ProcessBoundaryExtract for more info
165 m_f->m_exp[0]->GetGraph());
167 bcs.GetBoundaryRegions();
168 map<int, int> BndRegionMap;
169 int cnt = 0;
170 for (auto &breg_it : bregions)
171 {
172 BndRegionMap[breg_it.first] = cnt++;
173 }
174 int bnd = BndRegionMap[m_f->m_bndRegionsToWrite[0]];
175
176 // Generate the distance array and three arrays for directional vectors
177 // bfcsDir[i][j][k]
178 // i - dir vec: 0-main tangential, 1-normal, (2-minor tangential)
179 // j - component: 0-x, 1-y, (2-z)
180 // k - point id
181 int npoints = m_f->m_exp[0]->GetNpoints();
182 Array<OneD, NekDouble> distance(npoints, 9999);
184 for (int i = 0; i < nSpaceDim; ++i)
185 {
186 bfcsDir[i] = Array<OneD, Array<OneD, NekDouble>>(nSpaceDim);
187
188 for (int j = 0; j < nSpaceDim; ++j)
189 {
190 bfcsDir[i][j] = Array<OneD, NekDouble>(npoints);
191 }
192 }
193
194 // Key function. At each quadrature point inside the domian, compute the
195 // body-fitted coordinate system with respect to the input bnd id
196 GenPntwiseBodyFittedCoordSys(bnd, assistVec, distance, bfcsDir,
197 isCheckAngle, distTol, iterTol, dirTol,
198 geoTol);
199
200 // Compute the velocity
201 Array<OneD, Array<OneD, NekDouble>> vel_car(nSpaceDim); // Cartesian
202 Array<OneD, Array<OneD, NekDouble>> vel_bfc(nSpaceDim); // body-fiitted
203 Array<OneD, NekDouble> vel_tmp(npoints);
204
205 for (int i = 0; i < nSpaceDim; ++i)
206 {
207 vel_bfc[i] = Array<OneD, NekDouble>(npoints, 0.0);
208 }
209
210 // Get the velocity in Cartesian coordinate system
212
213 // Project the velocity into the body-fitted coordinate system
214 for (int i = 0; i < nSpaceDim; ++i) // loop for bfc velocity
215 {
216 for (int j = 0; j < nSpaceDim; ++j)
217 {
218 Vmath::Vmul(npoints, vel_car[j], 1, bfcsDir[i][j], 1, vel_tmp, 1);
219 Vmath::Vadd(npoints, vel_tmp, 1, vel_bfc[i], 1, vel_bfc[i], 1);
220 }
221 }
222
223 // Add var names
224 m_f->m_variables.push_back("distanceToWall");
225 m_f->m_variables.push_back("u_bfc");
226 m_f->m_variables.push_back("v_bfc");
227 if (nSpaceDim == 3)
228 {
229 m_f->m_variables.push_back("w_bfc");
230 }
231 else if (nSpaceDim == 1)
232 {
233 ASSERTL0(false, "Velocity in 1D case is already in the body fitted \
234 coordinate. The dimension should be 2 or 3.");
235 }
236
237 // Add the new fields (distance + u,v,w_bfc)
238 // copy distance
239 m_f->m_exp.resize(nFields + nAddFields);
240
241 m_f->m_exp[nFields] = m_f->AppendExpList(m_f->m_numHomogeneousDir);
242 Vmath::Vcopy(npoints, distance, 1, m_f->m_exp[nFields]->UpdatePhys(), 1);
243 m_f->m_exp[nFields]->FwdTransLocalElmt(distance,
244 m_f->m_exp[nFields]->UpdateCoeffs());
245
246 // copy vel_bfc
247 for (int i = 1; i < nAddFields; ++i)
248 {
249 m_f->m_exp[nFields + i] = m_f->AppendExpList(m_f->m_numHomogeneousDir);
250 Vmath::Vcopy(npoints, vel_bfc[i - 1], 1,
251 m_f->m_exp[nFields + i]->UpdatePhys(), 1);
252 m_f->m_exp[nFields + i]->FwdTransLocalElmt(
253 vel_bfc[i - 1], m_f->m_exp[nFields + i]->UpdateCoeffs());
254 }
255
256 // Output the the body-fitted coordinate into the file
257 // The filter will read the coordiante through file
258 // bfcsDir[i][j][k]
259 // i - dir vec: 0-main tangential, 1-normal, (2-minor tangential)
260 // j - component: 0-x, 1-y, (2-z)
261 // k - point id
262 if (isOutputBfc)
263 {
264 m_f->m_variables.push_back("bfc_dir0_x");
265 m_f->m_variables.push_back("bfc_dir0_y");
266 if (nSpaceDim == 3)
267 {
268 m_f->m_variables.push_back("bfc_dir0_z");
269 }
270 m_f->m_variables.push_back("bfc_dir1_x");
271 m_f->m_variables.push_back("bfc_dir1_y");
272 if (nSpaceDim == 3)
273 {
274 m_f->m_variables.push_back("bfc_dir1_z");
275
276 m_f->m_variables.push_back("bfc_dir2_x");
277 m_f->m_variables.push_back("bfc_dir2_y");
278 m_f->m_variables.push_back("bfc_dir2_z");
279 }
280
281 int nAddFields_coord = (nSpaceDim == 3) ? 9 : 4;
282 m_f->m_exp.resize(nFields + nAddFields + nAddFields_coord);
283
284 cnt = 0;
285 for (int i = 0; i < nSpaceDim; ++i)
286 {
287 for (int j = 0; j < nSpaceDim; ++j)
288 {
289
290 m_f->m_exp[nFields + nAddFields + cnt] =
291 m_f->AppendExpList(m_f->m_numHomogeneousDir);
292
294 npoints, bfcsDir[i][j], 1,
295 m_f->m_exp[nFields + nAddFields + cnt]->UpdatePhys(), 1);
296 m_f->m_exp[nFields + nAddFields + cnt]->FwdTransLocalElmt(
297 bfcsDir[i][j],
298 m_f->m_exp[nFields + nAddFields + cnt]->UpdateCoeffs());
299
300 ++cnt;
301 }
302 }
303 }
304}
305
306/**
307 * @brief Compute the point-to-point distance to find the estimated cloest
308 * element.
309 * @param pts Global coordinate of the quadrature points in the inner
310 * element.
311 * @param pId Id of the inner point of interest in the current loop.
312 * @param bndPts Global coordinate of the quadrature points in the boundary
313 * element.
314 */
316 const Array<OneD, Array<OneD, NekDouble>> &pts, const int pId,
317 const Array<OneD, Array<OneD, NekDouble>> &bndPts)
318{
319 const int nCoordDim = pts.size();
320
321 NekDouble dist = 9999, dist_tmp;
322
323 for (int i = 0; i < bndPts[0].size(); ++i)
324 {
325 // Compute distance
326 dist_tmp = 0.0;
327 for (int j = 0; j < nCoordDim; ++j)
328 {
329 dist_tmp +=
330 (bndPts[j][i] - pts[j][pId]) * (bndPts[j][i] - pts[j][pId]);
331 }
332 dist_tmp = sqrt(dist_tmp);
333
334 if (dist_tmp < dist)
335 {
336 dist = dist_tmp;
337 }
338 }
339
340 return dist;
341}
342
343/**
344 * @brief Compute the local coordinate for the nearest point on the given
345 * 2D boundary element to the input point.
346 * @param inGloCoord Global coordinate for the input point.
347 * @param bndGeom Geometry of the boundary element to search from.
348 * @param pts Global coordinate of the quadrature points in the boundary
349 * element.
350 * @param locCoord Local coordinate of the result.
351 * @param gloCoord Global coordinate of the result.
352 * @param dist Distance from the input point to the boundary element.
353 * @param iterTol Iteration tolerence.
354 * @param iterMax Max iteration steps.
355 */
357 const Array<OneD, const NekDouble> &inGloCoord,
359 const Array<OneD, Array<OneD, NekDouble>> &pts,
361 NekDouble &dist, const NekDouble iterTol, const int iterMax)
362{
363
364 // Initial settings
365 Array<OneD, NekDouble> etaLR(2); // range [-1,1]
366 etaLR[0] = -1.0; // left
367 etaLR[1] = 1.0; // right
368 NekDouble tmpLx, tmpLy, tmpRx, tmpRy; // tmp values for L/R
369 NekDouble distL2, distR2; // distance square
370
371 StdRegions::StdExpansionSharedPtr bndXmap = bndGeom->GetXmap();
372 locCoord[0] = -2.0;
373 int cnt = 0;
374 bool isConverge = false;
375 while (cnt < iterMax)
376 {
377 tmpLx = bndXmap->PhysEvaluate(etaLR, pts[0]);
378 tmpLy = bndXmap->PhysEvaluate(etaLR, pts[1]);
379 tmpRx = bndXmap->PhysEvaluate(etaLR + 1, pts[0]);
380 tmpRy = bndXmap->PhysEvaluate(etaLR + 1, pts[1]);
381
382 distL2 = (tmpLx - inGloCoord[0]) * (tmpLx - inGloCoord[0]) +
383 (tmpLy - inGloCoord[1]) * (tmpLy - inGloCoord[1]);
384 distR2 = (tmpRx - inGloCoord[0]) * (tmpRx - inGloCoord[0]) +
385 (tmpRy - inGloCoord[1]) * (tmpRy - inGloCoord[1]);
386
387 if (distL2 >= distR2)
388 {
389 etaLR[0] = 0.5 * (etaLR[0] + etaLR[1]);
390 }
391 else
392 {
393 etaLR[1] = 0.5 * (etaLR[0] + etaLR[1]);
394 }
395
396 if ((etaLR[1] - etaLR[0]) < iterTol)
397 {
398 locCoord[0] = 0.5 * (etaLR[0] + etaLR[1]);
399 gloCoord[0] = 0.5 * (tmpLx + tmpRx);
400 gloCoord[1] = 0.5 * (tmpLy + tmpRy);
401 dist = sqrt(0.5 * (distL2 + distR2));
402 isConverge = true;
403 break;
404 }
405
406 ++cnt;
407 }
408
409 // Warning if failed
410 if (cnt >= iterMax)
411 {
412 WARNINGL1(false, "Bisection iteration is not converged");
413 }
414
415 return isConverge;
416}
417
418/**
419 * @brief Compute the local coordinate for the nearest point on the given
420 * boundary element to the input point. The locCoord is the position to
421 * set up the body-fitted coordinate. This function works as a driver.
422 * @param inGloCoord Global coordinate for the input point.
423 * @param bndGeom Geometry of the boundary element to search from.
424 * @param locCoord Local coordinate of the result.
425 * @param gloCoord Global coordinate of the result.
426 * @param dist Distance from the input point to the boundary element.
427 * @param iterTol Iteration tolerence.
428 * @param iterMax Max iteration steps.
429 */
431 const Array<OneD, const NekDouble> &inGloCoord,
433 Array<OneD, NekDouble> &gloCoord, NekDouble &dist, const NekDouble iterTol,
434 const int iterMax)
435{
436 bool isConverge = false;
437 const int nCoordDim = m_f->m_exp[0]->GetCoordim(0); // =2 for 2.5D cases
438
439 StdRegions::StdExpansionSharedPtr bndXmap = bndGeom->GetXmap();
440 int nBndPts = bndXmap->GetTotPoints();
441
442 Array<OneD, Array<OneD, const NekDouble>> bndCoeffs(nCoordDim);
443 Array<OneD, Array<OneD, NekDouble>> bndPts(nCoordDim);
444 for (int i = 0; i < nCoordDim; ++i)
445 {
446 bndPts[i] = Array<OneD, NekDouble>(nBndPts);
447 bndCoeffs[i] = bndGeom->GetCoeffs(i);
448 bndXmap->BwdTrans(bndCoeffs[i], bndPts[i]);
449 }
450
451 // Compute the locCoord for the pnt on the bnd elmt
452 if (nCoordDim == 2)
453 {
454 // Bisection search
456 inGloCoord, bndGeom, bndPts, locCoord, gloCoord, dist, iterTol,
457 iterMax);
458 }
459 else
460 {
461 // Bi-bisection search
462 ASSERTL0(false, "Not available at the moment.");
463 }
464
465 return isConverge;
466}
467
468/**
469 * @brief Compute the normalized cross product for two 2D vectors.
470 * vec3 = vec1 x vec2
471 */
473 const Array<OneD, NekDouble> &vec1, const Array<OneD, NekDouble> &vec2,
475{
476 vec3[0] = vec1[1] * vec2[2] - vec1[2] * vec2[1];
477 vec3[1] = vec1[2] * vec2[0] - vec1[0] * vec2[2];
478 vec3[2] = vec1[0] * vec2[1] - vec1[1] * vec2[0];
479
480 NekDouble coef;
481 coef =
482 1.0 / sqrt(vec3[0] * vec3[0] + vec3[1] * vec3[1] + vec3[2] * vec3[2]);
483
484 vec3[0] = vec3[0] * coef;
485 vec3[1] = vec3[1] * coef;
486 vec3[2] = vec3[2] * coef;
487}
488
489/**
490 * @brief At each quadrature point inside the domian, compute the body-fitted
491 * coordinate system with respect to the input boundary id.
492 * @param targetBndId Target boundary id.
493 * @param assistVec Unit assistant vector, the cross product of inward-
494 * pointing wall normalId and wihch gives of the main
495 * tangential direction of the body-fitted system.
496 * @param bfcsDir Pointwise body-fitted coordinate system.
497 * @param isPerpendicularCondition Flag for using perpendicular check or not
498 * @param distTol Distance tolerence. Used to find the boundary elements
499 * for local coordinate iteration.
500 * @param iterTol Iteration tolerence. Used to check iteration convergence.
501 * @param dirTol Direction tolerencce. Used to check if the inner product
502 * of two unit vectors is cloes enough to 1.0.
503 * @param geoTol Geometry tolerence. Used as the relative tolerence for
504 * local coord and distance absolute tolerence.
505 */
507 const int targetBndId, const Array<OneD, NekDouble> assistVec,
508 Array<OneD, NekDouble> &distance,
510 const bool isCheckAngle, const NekDouble distTol, const NekDouble iterTol,
511 const NekDouble dirTol, const NekDouble geoTol)
512{
513
514 const int nFields = m_f->m_variables.size();
515 const int nCoordDim = m_f->m_exp[0]->GetCoordim(0);
516 const int nSpaceDim = nCoordDim + m_f->m_numHomogeneousDir;
517 const int nBndLcoordDim = nCoordDim - 1;
518
519 // Get expansion list for boundary
521 for (int i = 0; i < nFields; ++i)
522 {
523 BndExp[i] = m_f->m_exp[i]->UpdateBndCondExpansion(targetBndId);
524 }
525
526 const int nElmts = m_f->m_exp[0]->GetNumElmts(); // num of inner element
527 const int nBndElmts = BndExp[0]->GetNumElmts(); // num of bnd element
528
529 // Use the outward-pointing normal at quardrature pts on bnd elmt as dir ref
531 m_f->m_exp[0]->GetBoundaryNormals(targetBndId, normalQ);
532
533 // Vars in the loop
536 Array<OneD, Array<OneD, NekDouble>> bndCoeffs(nCoordDim);
537 Array<OneD, Array<OneD, NekDouble>> bndPts(nCoordDim);
538
539 int nPts, nBndPts;
540 NekDouble dist_tmp, dist_bak;
541 bool isConverge;
542 vector<int> bndElmtIds;
543 int bndElmtId, bndElmtId_bak;
544 int phys_offset, bnd_phys_offset;
545
546 Array<OneD, NekDouble> inGloCoord(3, 0.0); // inner pnt
547 Array<OneD, NekDouble> locCoord(nBndLcoordDim), locCoord_tmp(nBndLcoordDim);
548 Array<OneD, NekDouble> gloCoord(3, 0.0), gloCoord_tmp(3, 0.0);
549 Array<OneD, NekDouble> normal(3), normalRef(3);
550 Array<OneD, NekDouble> tangential1(3),
551 tangential2(3); // 1 - main, 2 - minor
552 Array<OneD, NekDouble> normalChk(3);
553 ProcessWallNormalData wnd(m_f); // wallNormalData object to use its routine
554
555 // backup for angle check
556 Array<OneD, NekDouble> locCoord_bak(nBndLcoordDim), gloCoord_bak(3, 0.0);
557
558 //-------------------------------------------------------------------------
559 // Loop all the quadrature points of the field, and find out the closest
560 // point on the bnd for each of them. The bnd element contains this bnd
561 // point is recorded.
562
563 // Loop inner element
564 for (int eId = 0; eId < nElmts; ++eId) // element id, nElmts
565 {
566 // Get inner points
567 nPts = m_f->m_exp[0]->GetExp(eId)->GetTotPoints();
569 for (int i = 0; i < nCoordDim; ++i)
570 {
571 pts[i] = Array<OneD, NekDouble>(nPts, 0.0);
572 }
573
574 if (nCoordDim == 2)
575 {
576 m_f->m_exp[0]->GetExp(eId)->GetCoords(pts[0], pts[1]);
577 }
578 else if (nCoordDim == 3)
579 {
580 m_f->m_exp[0]->GetExp(eId)->GetCoords(pts[0], pts[1], pts[2]);
581 }
582
583 // Get the offset for the current elmt
584 phys_offset = m_f->m_exp[0]->GetPhys_Offset(eId);
585
586 // Loop points in the inner element
587 for (int pId = 0; pId < nPts; ++pId)
588 {
589
590 // Compute the distance from the pnt (bnd elmt) to the inner pnt
591 // Step 1 - Estimate search
592 // - Find the closest quadrature pnt among all the bnd elmt;
593 // - The bnd elmt which contains this pnt is saved for Step 2.
594 // * If the quadtature pnt is on the edge or corner of the bnd
595 // elmt, there will be more than one bnd elmt which contains
596 // this point.
597
598 bndElmtIds.clear(); // clear the bnd elmt id vec for a new inner pnt
599
600 // Loop bnd elmt to find the elmt to build body-fitted coord sys
601 for (int beId = 0; beId < nBndElmts; ++beId)
602 {
603 // Get geomery and points
604 bndGeom = BndExp[0]->GetExp(beId)->GetGeom();
605 bndXmap = bndGeom->GetXmap();
606 nBndPts = bndXmap->GetTotPoints();
607
608 for (int i = 0; i < nCoordDim; ++i)
609 {
610 bndPts[i] = Array<OneD, NekDouble>(nBndPts);
611 bndCoeffs[i] = bndGeom->GetCoeffs(i); // 0/1/2 for x/y/z
612 bndXmap->BwdTrans(bndCoeffs[i], bndPts[i]);
613 }
614
615 // Compute the distance (estimate)
616 dist_tmp = PntToBndElmtPntDistance(pts, pId, bndPts);
617
618 if ((dist_tmp < (distance[phys_offset + pId] - geoTol)) &&
619 (dist_tmp < (distance[phys_offset + pId] - distTol)))
620 {
621 // Find a closer quadrature point from a different bnd elmt
622 // Update distance and bnd elmt id vector
623 distance[phys_offset + pId] = dist_tmp;
624 bndElmtIds.clear();
625 bndElmtIds.push_back(beId);
626 }
627 else if ((dist_tmp < (distance[phys_offset + pId] + geoTol)) ||
628 (dist_tmp < (distance[phys_offset + pId] + distTol)))
629 {
630 // The same quadrature point from a different bnd elmt is
631 // found for the other time.
632 // Keep the distance and add the bnd elmt id to the vector
633 bndElmtIds.push_back(beId);
634 }
635
636 } // end of bnd elmt loop
637
638 // Step 2 - Accurate search
639 // - Find the accurate distance and locCoord for the nearest pnt
640 // (to the inner point) on the bnd elmt
641 // - This process will be repeated on all the bnd elmts in the bnd
642 // elmt id vector.
643
644 // Generate the coordinate for the inner point
645 for (int i = 0; i < nCoordDim; ++i)
646 {
647 inGloCoord[i] = pts[i][pId];
648 }
649
650 // reset the dist to make sure the condition for if will be
651 // satisfied
652 distance[phys_offset + pId] = 9999;
653 bndElmtId = -1;
654 dist_bak = 9999;
655 bndElmtId_bak = -1;
656
657 // Compute the accurate distance and locCoord
658 for (int i = 0; i < bndElmtIds.size(); ++i)
659 {
660 // Iterate on each of the possible bnd elmt to get the locCoord
661 // and the smallest dist
662 bndGeom = BndExp[0]->GetExp(bndElmtIds[i])->GetGeom();
663
665 inGloCoord, bndGeom, locCoord_tmp, gloCoord_tmp, dist_tmp,
666 iterTol, 51);
667
668 if (!isConverge)
669 {
670 WARNINGL1(false, "Bisection iteration is not converged!!!");
671 }
672
673 // Perpendicular check (angle check)
674 // When activated (distance > geoTol)
675 // if the pnt-to-pnt vector is not parallel with the wall
676 // normal, this bnd will be skipped. It is helpful to avoid
677 // confusion when there are cornors
678 if (isCheckAngle && (dist_tmp > geoTol)) // skip pts on the bnd
679 {
680 // Generate the scaled vector
681 Vmath::Vcopy(nCoordDim, gloCoord_tmp, 1, normalChk, 1);
682 Vmath::Neg(nCoordDim, normalChk, 1);
683 Vmath::Vadd(nCoordDim, inGloCoord, 1, normalChk, 1,
684 normalChk, 1);
685 Vmath::Smul(nCoordDim,
686 1.0 / sqrt(Vmath::Dot(nCoordDim, normalChk, 1,
687 normalChk, 1)),
688 normalChk, 1, normalChk, 1);
689
690 // Get normal based on the locCoord_tmp
691 wnd.GetNormals(bndGeom, locCoord_tmp, normal);
692
693 // Reverse the direction to make it point into the field
694 bnd_phys_offset = BndExp[0]->GetPhys_Offset(bndElmtIds[i]);
695 for (int j = 0; j < nCoordDim; ++j)
696 {
697 normalRef[j] = normalQ[j][bnd_phys_offset];
698 }
699
700 if (Vmath::Dot(nCoordDim, normal, normalRef) > 0.0)
701 {
702 Vmath::Neg(nCoordDim, normal, 1);
703 }
704
705 // Check if the current bnd elmt convers this inner pnt
706 if (Vmath::Dot(nCoordDim, normalChk, 1, normal, 1) <
707 (1 - dirTol))
708 {
709 // If not covered, save the nearest result as backup
710 // Then skip
711 if (dist_tmp < dist_bak)
712 {
713 bndElmtId_bak = bndElmtIds[i];
714 dist_bak = dist_tmp;
715
716 for (int j = 0; j < nBndLcoordDim; ++j)
717 {
718 locCoord_bak[j] = locCoord_tmp[j];
719 }
720
721 for (int j = 0; j < 3; ++j)
722 {
723 gloCoord_bak[j] = gloCoord_tmp[j];
724 }
725 }
726
727 continue; // Skip current bnd elmt
728 }
729 }
730
731 // No violation occurs, update the current result
732 // This section must be executed at least once if there the
733 // angle check is turned off. It means the following
734 // (bndElmtId == -1) can only be caused by angle check.
735 if (dist_tmp < distance[phys_offset + pId])
736 {
737 bndElmtId = bndElmtIds[i];
738 distance[phys_offset + pId] = dist_tmp;
739
740 for (int j = 0; j < nBndLcoordDim; ++j)
741 {
742 locCoord[j] = locCoord_tmp[j];
743 }
744
745 for (int j = 0; j < 3; ++j)
746 {
747 gloCoord[j] = gloCoord_tmp[j];
748 }
749 }
750 }
751
752 // Check if the bnd elmt is found. If not, use nearest one.
753 if (bndElmtId == -1)
754 {
755 if (bndElmtIds.size() == 0)
756 {
757 ASSERTL0(false, "No boundary element is found to be the \
758 possible nearest element. Please check.");
759 }
760
761 distance[phys_offset + pId] = dist_bak;
762 bndElmtId = bndElmtId_bak;
763
764 for (int i = 0; i < nBndLcoordDim; ++i)
765 {
766 locCoord[i] = locCoord_bak[i];
767 }
768
769 for (int i = 0; i < 3; ++i)
770 {
771 gloCoord[i] = gloCoord_bak[i];
772 }
773
774 WARNINGL1(false,
775 "The boundary element is not found under given \
776 tolerence. Please check and reset the \
777 tolerence, or just turn off the angle check. \
778 If you would like to continue, the nearest \
779 boundary element is used.");
780 }
781
782 // Get the wall normal using the function in wallNormalData class
783 bndGeom = BndExp[0]->GetExp(bndElmtId)->GetGeom();
784 wnd.GetNormals(bndGeom, locCoord, normal);
785
786 // Get ref normal for outward-point dir
787 bnd_phys_offset = BndExp[0]->GetPhys_Offset(bndElmtId);
788 for (int i = 0; i < nCoordDim; ++i)
789 {
790 normalRef[i] = normalQ[i][bnd_phys_offset];
791 }
792
793 // Correct the normal direction to make sure it points inward
794 if (Vmath::Dot(nCoordDim, normal, normalRef) > 0.0)
795 {
796 Vmath::Neg(nCoordDim, normal, 1);
797 }
798
799 // The main tagential direction is defined to be overlapped with the
800 // intersection line of the tangantial plane and the assistant
801 // plane, whose normal is the input assistDir. Both plane is defined
802 // using the point normal form, where the point is the nearest point
803 // on the boundary (gloCoord), and the vectors are the normal
804 // (pointing out) and the assistant direction (assistDir).
805 // Therefore, the main tangantial direction can be obtained by the
806 // cross product of the two vectors, since the two vectors has the
807 // same starting point and the tangantial direction is perpendicular
808 // to both of them.
809 ScaledCrosssProduct(normal, assistVec, tangential1);
810
811 // Save the direction vectors
812 for (int i = 0; i < nSpaceDim; ++i)
813 {
814 bfcsDir[0][i][phys_offset + pId] = tangential1[i];
815 bfcsDir[1][i][phys_offset + pId] = normal[i];
816 }
817
818 if (nSpaceDim == 3)
819 {
820 ScaledCrosssProduct(tangential1, normal, tangential2);
821 for (int i = 0; i < 3; ++i)
822 {
823 bfcsDir[2][i][phys_offset + pId] = tangential2[i];
824 }
825 }
826
827 } // end of inner pts loop
828
829 } // end of inner elmt loop
830}
831
832/**
833 * @brief Get velocity and convert to Cartesian system, if it is still in
834 * transformed system. It is copied and modified from from
835 * ProcessGrad.cpp
836 */
839{
840 int spacedim = m_f->m_exp[0]->GetCoordim(0) + m_f->m_numHomogeneousDir;
841 int nfields = m_f->m_variables.size();
842 int npoints = m_f->m_exp[0]->GetNpoints();
843 int var_offset = 0;
844
845 // Check type of the fields and set variable offset
846 vector<string> vars = m_f->m_exp[0]->GetSession()->GetVariables();
847 if (boost::iequals(vars[0], "rho") && boost::iequals(vars[1], "rhou"))
848 {
849 var_offset = spacedim + 2;
850 }
851
852 // Get mapping
854
855 // Get velocity and convert to Cartesian system,
856 // if it is still in transformed system
857 if (m_f->m_fieldMetaDataMap.count("MappingCartesianVel"))
858 {
859 if (m_f->m_fieldMetaDataMap["MappingCartesianVel"] == "False")
860 {
861 // Initialize arrays and copy velocity
862 for (int i = 0; i < spacedim; ++i)
863 {
864 vel[i] = Array<OneD, NekDouble>(npoints);
865 if (m_f->m_exp[0]->GetWaveSpace())
866 {
867 m_f->m_exp[0]->HomogeneousBwdTrans(
868 npoints, m_f->m_exp[var_offset + i]->GetPhys(), vel[i]);
869 }
870 else
871 {
872 Vmath::Vcopy(npoints, m_f->m_exp[var_offset + i]->GetPhys(),
873 1, vel[i], 1);
874 }
875 }
876 // Convert velocity to cartesian system
877 mapping->ContravarToCartesian(vel, vel);
878 // Convert back to wavespace if necessary
879 if (m_f->m_exp[0]->GetWaveSpace())
880 {
881 for (int i = 0; i < spacedim; ++i)
882 {
883 m_f->m_exp[0]->HomogeneousFwdTrans(npoints, vel[i], vel[i]);
884 }
885 }
886 }
887 else
888 {
889 for (int i = 0; i < spacedim; ++i)
890 {
891 vel[i] = Array<OneD, NekDouble>(npoints);
892 Vmath::Vcopy(npoints, m_f->m_exp[var_offset + i]->GetPhys(), 1,
893 vel[i], 1);
894 }
895 }
896 }
897 else
898 {
899 for (int i = 0; i < spacedim && i < nfields; ++i)
900 {
901 vel[i] = Array<OneD, NekDouble>(npoints);
902 Vmath::Vcopy(npoints, m_f->m_exp[var_offset + i]->GetPhys(), 1,
903 vel[i], 1);
904 }
905 }
906}
907
908} // namespace FieldUtils
909} // namespace Nektar
#define WARNINGL1(condition, msg)
Definition: ErrorUtil.hpp:250
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:215
FieldSharedPtr m_f
Field object.
Definition: Module.h:234
std::map< std::string, ConfigOption > m_config
List of configuration values.
Definition: Module.h:263
virtual void v_Process(po::variables_map &vm) override
Write mesh to output file.
void GenPntwiseBodyFittedCoordSys(const int targetBndId, const Array< OneD, NekDouble > assistVec, Array< OneD, NekDouble > &distance, Array< OneD, Array< OneD, Array< OneD, NekDouble > > > &bfcsDir, const bool isCheckAngle, const NekDouble distTol=1.0e-12, const NekDouble iterTol=1.0e-12, const NekDouble dirTol=1.0e-4, const NekDouble geoTol=1.0e-12)
At each quadrature point inside the domian, compute the body-fitted coordinate system with respect to...
void GetVelAndConvertToCartSys(Array< OneD, Array< OneD, NekDouble > > &vel)
Get velocity and convert to Cartesian system, if it is still in transformed system....
void ScaledCrosssProduct(const Array< OneD, NekDouble > &vec1, const Array< OneD, NekDouble > &vec2, Array< OneD, NekDouble > &vec3)
Compute the normalized cross product for two 2D vectors. vec3 = vec1 x vec2.
bool LocCoordForNearestPntOnBndElmt_2D(const Array< OneD, const NekDouble > &inGloCoord, SpatialDomains::GeometrySharedPtr bndGeom, const Array< OneD, Array< OneD, NekDouble > > &pts, Array< OneD, NekDouble > &locCoord, Array< OneD, NekDouble > &gloCoord, NekDouble &dist, const NekDouble iterTol=1.0e-12, const int iterMax=51)
Compute the local coordinate for the nearest point on the given 2D boundary element to the input poin...
static std::shared_ptr< Module > create(FieldSharedPtr f)
Creates an instance of this class.
NekDouble PntToBndElmtPntDistance(const Array< OneD, Array< OneD, NekDouble > > &pts, const int pId, const Array< OneD, Array< OneD, NekDouble > > &bndPts)
Compute the local coordinate for the nearest point on the given 2D boundary element to the input poin...
bool LocCoordForNearestPntOnBndElmt(const Array< OneD, const NekDouble > &inGloCoord, SpatialDomains::GeometrySharedPtr bndGeom, Array< OneD, NekDouble > &locCoord, Array< OneD, NekDouble > &gloCoord, NekDouble &dist, const NekDouble iterTol=1.0e-12, const int iterMax=51)
Compute the local coordinate for the nearest point on the given boundary element to the input point....
This processing module sets up for the boundary field to be extracted.
virtual void v_Process(po::variables_map &vm) override
static GlobalMapping::MappingSharedPtr GetMapping(FieldSharedPtr f)
This processing module calculates the wall shear stress and adds it as an extra-field to the output f...
void GetNormals(SpatialDomains::GeometrySharedPtr bndGeom, const Array< OneD, const NekDouble > &locCoord, Array< OneD, NekDouble > &normals)
Get the normals for a given locCoord.
tKey RegisterCreatorFunction(tKey idKey, CreatorFunction classCreator, std::string pDesc="")
Register a class with the factory.
Definition: NekFactory.hpp:198
static bool GenerateVector(const std::string &str, std::vector< T > &out)
Takes a comma-separated string and converts it to entries in a vector.
Definition: ParseUtils.cpp:131
const BoundaryRegionCollection & GetBoundaryRegions(void) const
Definition: Conditions.h:234
std::shared_ptr< Field > FieldSharedPtr
Definition: Field.hpp:991
std::pair< ModuleType, std::string > ModuleKey
Definition: Module.h:317
ModuleFactory & GetModuleFactory()
Definition: Module.cpp:49
GLOBAL_MAPPING_EXPORT typedef std::shared_ptr< Mapping > MappingSharedPtr
A shared pointer to a Mapping object.
Definition: Mapping.h:53
std::map< int, BoundaryRegionShPtr > BoundaryRegionCollection
Definition: Conditions.h:210
std::shared_ptr< Geometry > GeometrySharedPtr
Definition: Geometry.h:54
std::shared_ptr< StdExpansion > StdExpansionSharedPtr
The above copyright notice and this permission notice shall be included.
Definition: CoupledSolver.h:2
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.cpp:207
void Neg(int n, T *x, const int incx)
Negate x = -x.
Definition: Vmath.cpp:513
T Dot(int n, const T *w, const T *x)
dot (vector times vector): z = w*x
Definition: Vmath.cpp:1095
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 Smul(int n, const T alpha, const T *x, const int incx, T *y, const int incy)
Scalar multiply y = alpha*x.
Definition: Vmath.cpp:245
void Vcopy(int n, const T *x, const int incx, T *y, const int incy)
Definition: Vmath.cpp:1191
scalarT< T > sqrt(scalarT< T > in)
Definition: scalar.hpp:294
Represents a command-line configuration option.
Definition: Module.h:131