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