Nektar++
ProcessWallNormalData.cpp
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // File: ProcessWallNormalData.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: Get the wall-normal data at a given origin.
32 //
33 ////////////////////////////////////////////////////////////////////////////////
34 
35 #include <iostream>
36 #include <string>
37 
39 #include <MultiRegions/ExpList.h>
42 
43 #include "ProcessWallNormalData.h"
44 
45 
46 using namespace std;
47 
48 namespace Nektar
49 {
50 namespace FieldUtils
51 {
52 
53 ModuleKey ProcessWallNormalData::className = GetModuleFactory().RegisterCreatorFunction(
54  ModuleKey(eProcessModule, "wallNormalData"),
55  ProcessWallNormalData::create,
56  "Export data in wall-normal direction from a single point on the wall.");
57 
58 ProcessWallNormalData::ProcessWallNormalData(FieldSharedPtr f) : ProcessBoundaryExtract(f)
59 {
60  f->m_writeBndFld = false; // turned on in upstream ProcessBoundaryExtract
61 
62  m_config["xorig"] = ConfigOption(false, "0.5,0.0,0.0",
63  "The point to be projected onto the wall to get the \
64  sampling origin. default=[0.5,0,0]");
65  m_config["projDir"] = ConfigOption(false, "0.0,1.0,0.0",
66  "The direction to project the point onto the wall to \
67  get the sampling origin. default=[0,1,0]");
68  m_config["maxDist"] = ConfigOption(false, "1.0",
69  "Distance to limit projection distance to find the \
70  desired sampling origin. defalut=1.0");
71  m_config["distH"] = ConfigOption(false, "0.01",
72  "Sampling distance along the wall normal at the \
73  sampling origin. default=0.1");
74  m_config["nptsH"] = ConfigOption(false, "5",
75  "Number of sampling points along the wall normal. \
76  default=5");
77  m_config["d"] = ConfigOption(false, "0.1",
78  "The parameter that controls the sampling points' \
79  distribution. d should be in the range (0,inf). d \
80  in (0,0.95] gives controled points; d in (0.95,inf) \
81  gives evenly spaced points");
82 }
83 
85 {
86 }
87 
88 
89 /*Note
90 * This module is used to get field data in the wall-normal direction.
91 * The input cases can be 2D, 2.5D and 3D.
92 * The data will be exported with .pts extension.
93 *
94 * The user defined parameters are: bnd, xorig, searchDir, maxDist, distH,
95 * nptsH, and d.
96 * - bnd=0 is the boundary id. This boundary should contain the desired origin.
97 * - xorig="x,y,z" are the coordinates of the input sampling origin. They are
98 * used as the references to get exact origin on the wall.
99 * - projDir="0,1,0" is the projection direction to find the point on the wall
100 * - maxDist=1.0 is the distance that constrains the projection on the wall.
101 * The projection distance should be smaller than this distance. This
102 * parameter is set in case the boundary is wavey so that multiple
103 * projections exist at the same time.
104 * - distH=0.01 is the sampling depth in the wall-normal direction.
105 * - nptsH=11 is the number of sampling points along wall-normal direction.
106 * - d=0.1 is a destribution control parameter of the sampling points. It
107 * should be in the range (0,inf). d in range (0,0.95] for controlled array.
108 * d>0.95 gives evenly spaced array.
109 */
110 void ProcessWallNormalData::Process(po::variables_map &vm)
111 {
113 
114  // Get dim to store data
115  const int nfields = m_f->m_variables.size();
116  const int nCoordDim = m_f->m_exp[0]->GetCoordim(0);
117  m_spacedim = nCoordDim + m_f->m_numHomogeneousDir;
118  const int nBndLcoordDim = nCoordDim - 1;
119  const int totVars = m_spacedim + m_f->m_variables.size();
120 
121 
122  // Initialize the sampling parameters
123  std::vector<NekDouble> xorig, searchDir;
124  ASSERTL0(ParseUtils::GenerateVector(m_config["xorig"].as<string>(), xorig),
125  "Failed to interpret origin coordinates string");
126  ASSERTL0(ParseUtils::GenerateVector(m_config["projDir"].as<string>(), searchDir),
127  "Failed to interpret search direction string");
128  const NekDouble maxDist = m_config["maxDist"].as<NekDouble>();
129  const NekDouble distH = m_config["distH"].as<NekDouble>();
130  const int nptsH = m_config["nptsH"].as<int>();
131  const NekDouble delta = m_config["d"].as<NekDouble>();
132 
133 
134  Array<OneD, NekDouble> orig(3), projDir(3); // gloCoord of the origin
135  for (int i=0; i<3; ++i)
136  {
137  orig[i] = (xorig.size()>=(i+1)) ? xorig[i] : 0.0;
138  projDir[i] = (searchDir.size()>=(i+1)) ? searchDir[i] : 0.0;
139  }
140  if (nCoordDim==2)
141  {
142  projDir[2] = 0.0;
143  }
144  Vmath::Smul(3, 1.0/sqrt(Vmath::Dot(3, projDir, 1, projDir, 1)),
145  projDir, 1, projDir, 1);
146 
147  // Update z according to the closest plane in 2.5D cases
148  if (m_f->m_numHomogeneousDir==1)
149  {
150  int nPlanes = m_f->m_exp[0]->GetHomogeneousBasis()->GetZ().size();
151  NekDouble lHom = m_f->m_exp[0]->GetHomoLen();
152  if (orig[2]<0.0 || orig[2]>lHom)
153  {
154  orig[2] = 0.0;
155  }
156  else
157  {
158  NekDouble dZ = lHom / nPlanes;
159  NekDouble zTmp, zCur=0.0, distTmp, distCur = 999.0;
160  for(int i=0; i<=nPlanes; ++i)
161  {
162  zTmp = dZ * i;
163  distTmp = fabs(orig[2] - zTmp);
164  if(distTmp < distCur)
165  {
166  distCur = distTmp;
167  zCur = zTmp;
168  if(i==nPlanes)
169  {
170  zCur = 0.0;
171  }
172  }
173  }
174  orig[2] = zCur;
175  }
176  }
177 
178 
179  // Get the bnd id
181  m_f->m_exp[0]->GetGraph());
183  bcs.GetBoundaryRegions();
184  map<int, int> BndRegionMap;
185  int cnt = 0;
186  for (auto &breg_it : bregions)
187  {
188  BndRegionMap[breg_it.first] = cnt++;
189  }
190  int bnd = BndRegionMap[m_f->m_bndRegionsToWrite[0]];
191 
192  // Get expansion list for boundary
194  for (int i = 0; i < nfields; ++i) {
195  BndExp[i] = m_f->m_exp[i]->UpdateBndCondExpansion(bnd);
196  }
197 
198 
199  //-------------------------------------------------------------------------
200  // Find the element that contains the origin, and give the precise origin
202  Array<OneD, NekDouble> locCoord(nBndLcoordDim, -999.0);
203  NekDouble projDist;
204  int elmtid;
205  bool isInside = false;
206 
207  // Search and get precise locCoord
208  const int nElmts = BndExp[0]->GetNumElmts();
209  for (elmtid=0; elmtid<nElmts; ++elmtid) //nElmts
210  {
211  bndGeom = BndExp[0]->GetExp(elmtid)->GetGeom();
212  isInside = BndElmtContainsPoint(bndGeom, orig, projDir, locCoord,
213  projDist, maxDist);
214  if (isInside)
215  {
216  break;
217  }
218 
219  }
220  ASSERTL0(isInside, "Failed to find the sampling origin on the boundary.");
221 
222 
223  // Then Update the precise sampling position
224  StdRegions::StdExpansionSharedPtr bndXmap = bndGeom->GetXmap();
225  const int npts = bndXmap->GetTotPoints();
226  Array<OneD, Array<OneD, NekDouble> > pts(nCoordDim);
227  Array<OneD, Array<OneD, const NekDouble> > bndCoeffs(nCoordDim);
228 
229  for (int i=0; i<nCoordDim; ++i)
230  {
231  pts[i] = Array<OneD, NekDouble>(npts);
232  bndCoeffs[i] = bndGeom->GetCoeffs(i); // 0/1/2 for x/y/z
233  bndXmap->BwdTrans(bndCoeffs[i], pts[i]);
234  orig[i] = bndXmap->PhysEvaluate(locCoord, pts[i]); // Update wall point
235  }
236 
237 
238  // Get outward-pointing normal vectors for all quadrature points on bnd
239  // Use these normals as diretion references
241  m_f->m_exp[0]->GetBoundaryNormals(bnd, normalsQ);
242 
243  // Get the normals in the element
244  // Set point key to get point id
245  Array<OneD, LibUtilities::PointsKey> from_key(nBndLcoordDim);
246  int from_nPtsPerElmt = 1;
247  for (int i=0; i<nBndLcoordDim; ++i)
248  {
249  from_key[i] = BndExp[0]->GetExp(elmtid)->GetBasis(i)->GetPointsKey();
250  from_nPtsPerElmt *= from_key[i].GetNumPoints();
251  }
252 
253  //Get ref normal
254  Array< OneD, NekDouble > normalsRef(3, 0.0);
255  int refId = elmtid*from_nPtsPerElmt + 0; // the 1st normal in the bnd elmt
256  for(int i=0;i<m_spacedim; ++i)
257  {
258  normalsRef[i] = normalsQ[i][refId];
259  }
260 
261  // Get the precise normals and correct the direction to be inward
262  Array< OneD, NekDouble > normals(3, 0.0);
263  GetNormals(bndGeom, locCoord, normals);
264 
265  if(Vmath::Dot(3, normals, normalsRef) > 0.0)
266  {
267  Vmath::Neg(3, normals, 1);
268  }
269 
270  // Output the info if -v is set
271  if (m_f->m_verbose)
272  {
273  cout << "------ wallNormalData module ------\n";
274  cout << "Input point:\n";
275  cout << " - [Px,Py,Pz] = [" << xorig[0] << ", " << xorig[1];
276  if (xorig.size()>=3)
277  {
278  cout << ", " << xorig[2] << "]\n";
279  }
280  else
281  {
282  cout << ", " << 0.0 << "]\n";
283  }
284  cout << "Projection direction:\n";
285  cout << " - [vx,vy,vz] = ["
286  << projDir[0] << ", " << projDir[1] << ", " << projDir[2] << "]\n";
287  cout << "Sampling origin on the wall:\n";
288  cout << " - [Ox,Oy,Oz] = ["
289  << orig[0] << ", " << orig[1] << ", " << orig[2] << "]\n";
290  cout << "Normals at the origin:\n";
291  cout << " - [nx,ny,nz] = ["
292  << normals[0] << ", " << normals[1] << ", " << normals[2] << "]\n";
293  cout << "Ref normals (at quadrature points in the projected element):\n";
294  for (int i=0; i<from_nPtsPerElmt; ++i)
295  {
296  cout << " - " << i << ": [nx,ny,nz] = ["
297  << -normalsQ[0][elmtid*from_nPtsPerElmt+i] << ", "
298  << -normalsQ[1][elmtid*from_nPtsPerElmt+i];
299  if (m_spacedim==3)
300  {
301  cout << ", " << -normalsQ[2][elmtid*from_nPtsPerElmt+i] << "]\n";
302  }
303  else
304  {
305  cout << "]\n";
306  }
307  }
308  cout << endl;
309  }
310 
311 
312  //-------------------------------------------------------------------------
313  // Set the depth of sampling array
314  Array<OneD, NekDouble> h(nptsH, 0.0);
315  if (delta > 0 && delta <= 0.95)
316  {
317  // Use expression in Agrawal's paper:
318  // h = 1-tanh((1-ksi)*atanh(sqrt(1-delta)))/sqrt(1-delta), ksi in [0,1]
319  NekDouble tmp1;
320  const NekDouble tmp2 = 1.0/(static_cast<NekDouble>(nptsH)-1.0);
321  const NekDouble tmp3 = sqrt(1.0-delta);
322  const NekDouble tmp4 = atanh(tmp3);
323  const NekDouble tmp5 = 1.0/tmp3;
324  for (int i=1; i<nptsH; ++i)
325  {
326  tmp1 = 1.0 - i * tmp2; // tmp1 = 1-ksi
327  h[i] = 1 - tanh(tmp1*tmp4)*tmp5;
328  h[i] *= distH; // physical distance in normal direction
329  }
330  }
331  else if (delta > 0.95)
332  {
333  // Evenly spaced array
334  const NekDouble tmp1 = 1.0/(static_cast<NekDouble>(nptsH)-1.0);
335  for (int i=1; i<nptsH; ++i)
336  {
337  h[i] = i * tmp1;
338  h[i] *= distH; // physical distance in normal direction
339  }
340 
341  }
342  else{
343  ASSERTL0(false, "Input error. Delta needs to be greater than 0.0.");
344  }
345 
346  // Set pts coordinates and interpoate the data
347  Array<OneD, Array<OneD, NekDouble> > ptsH(totVars);
348  for (int i=0; i<totVars; ++i)
349  {
350  ptsH[i] = Array<OneD, NekDouble>(nptsH, 0.0);
351  }
352 
353  for(int i=0; i<m_spacedim; ++i)
354  {
355  for(int j=0; j<nptsH; ++j)
356  {
357  ptsH[i][j] = orig[i] + h[j] * normals[i]; // x0+dist*nx
358  }
359  }
360 
362  m_spacedim, m_f->m_variables, ptsH, LibUtilities::NullPtsInfoMap);
363 
364  Interpolator interp;
365  interp.Interpolate(m_f->m_exp, m_f->m_fieldPts, NekConstants::kNekUnsetDouble);
366 }
367 
368 
369 
370 /**
371  * @brief Project a single point along the given direction to a plane
372  * @param gloCoord Global coordinate of the point. size=3.
373  * @param projDir Projection direction, which is also the normal vector of
374  * the target plane. size=3, norm=1.
375  * @param distToOrig The distance from the origin (0,0,0) to the target plane
376  * @param projGloCoord The global coordinate of the projecion result.
377  */
379  const Array<OneD, const NekDouble > & gloCoord,
380  const Array<OneD, const NekDouble > & projDir,
381  const NekDouble distToOrig,
382  Array<OneD, NekDouble > & projGloCoord)
383 {
384  NekDouble tmp1;
385  Array<OneD, NekDouble > tmp2(3);
386 
387  tmp1 = Vmath::Dot(3, gloCoord, 1, projDir, 1); // |xn| = x dot n
388  Vmath::Smul(3, distToOrig-tmp1, projDir, 1, tmp2, 1); // d_xn = (dist-|xn|) n
389  Vmath::Vadd(3, gloCoord, 1, tmp2, 1, projGloCoord,1); // x' = x + d_xn
390 }
391 
392 
393 /**
394  * @brief Project the vertices of the elmt along the given direction to a plane
395  * @param pts Global coordinate of the vertices of the elmt. size=2/3.
396  * @param projDir Projection direction, which is also the normal vector of
397  * the target plane. size=3, norm=1.
398  * @param distToOrig The distance from the origin (0,0,0) to the target plane.
399  * @param projPts The global coordinate of the projecion result.
400  */
402  const Array<OneD, const Array<OneD, NekDouble> > & pts,
403  const Array<OneD, const NekDouble > & projDir,
404  const NekDouble distToOrig,
405  Array<OneD, Array<OneD, NekDouble> > & projPts)
406 {
407  const int nCoordDim = pts.size(); // 2 for 2.5D cases
408  const int npts = pts[0].size();
409 
410  NekDouble tmp1;
411  Array<OneD, NekDouble > singlePnt(nCoordDim), tmp2(nCoordDim);
412 
413  for (int i=0; i<npts; ++i)
414  {
415  // Get a point
416  for (int j=0; j<nCoordDim; ++j)
417  {
418  singlePnt[j] = pts[j][i];
419  }
420 
421  // Projection
422  tmp1 = Vmath::Dot(nCoordDim, singlePnt, 1, projDir, 1);
423  Vmath::Smul(nCoordDim, distToOrig-tmp1, projDir, 1, tmp2, 1);
424  Vmath::Vadd(nCoordDim, singlePnt, 1, tmp2, 1, singlePnt,1);
425 
426  // Save to projPts
427  for (int j=0; j<nCoordDim; ++j)
428  {
429  projPts[j][i] = singlePnt[j];
430  }
431  }
432 
433 }
434 
435 
436 /**
437  * @brief Determine if the projected point is inside the projected element.
438  * @param projGloCoord The global coordinate of the projected single point.
439  * @param projPts The global coordinate of the projected vertices,size=2/3
440  * @param projDir Projection direction, which is used as the reference
441  * direction in the 3D routine. size=3, norm=1.
442  * @param paralTol Tolerence to check if two vectors are parallel.
443  * @param angleTol Tolerence to check if the total angle is 2*pi.
444  * @return Inside (true) or not (false)
445  */
447  const Array<OneD, const NekDouble > & projGloCoord,
448  const Array<OneD, const Array<OneD, NekDouble> > & projPts,
449  const NekDouble paralTol)
450 {
451  const NekDouble npts = projPts[0].size();
452 
453  Array<OneD, NekDouble> vec1(2, 0.0), vec2(2, 0.0);
454 
455  vec1[0] = projPts[0][0] - projGloCoord[0];
456  vec1[1] = projPts[1][0] - projGloCoord[1];
457  vec2[0] = projPts[0][npts-1] - projGloCoord[0];
458  vec2[1] = projPts[1][npts-1] - projGloCoord[1];
459 
460  Vmath::Smul(2, 1.0/sqrt(Vmath::Dot(2, vec1, 1, vec1, 1)),
461  vec1, 1, vec1, 1);
462  Vmath::Smul(2, 1.0/sqrt(Vmath::Dot(2, vec2, 1, vec2, 1)),
463  vec2, 1, vec2, 1);
464 
465  if( (fabs(vec1[0]+vec2[0]) + fabs(vec1[1]+vec2[1])) < paralTol )
466  {
467  // On the line segement, true
468  return true;
469  }
470  else
471  {
472  return false;
473  }
474 
475 }
476 
477 
479  const Array<OneD, const NekDouble > & projGloCoord,
480  const Array<OneD, const Array<OneD, NekDouble> > & projPts,
481  const Array<OneD, const NekDouble > & projDir,
482  const NekDouble paralTol,
483  const NekDouble angleTol)
484 {
485 
486  //Generate a polygen (quad), re-order the points on the edge
487  const NekDouble npts = projPts[0].size();
488  const int nptsEdge = sqrt(npts); // num of points on edge for geo representation
489  const int nptsPolygon = 4*nptsEdge-4;
490  Array<OneD, Array<OneD, NekDouble> > ptsPolygon(3);
491  for (int i=0; i<3; ++i)
492  {
493  ptsPolygon[i] = Array<OneD, NekDouble>(nptsPolygon);
494 
495  for(int j=0; j<nptsEdge; ++j)
496  {
497  ptsPolygon[i][j] = projPts[i][j];
498  }
499  for(int j=0; j<nptsEdge-2; ++j)
500  {
501  ptsPolygon[i][nptsEdge+j] = projPts[i][(j+2)*nptsEdge-1];
502  }
503  for(int j=0; j<nptsEdge; ++j)
504  {
505  ptsPolygon[i][2*nptsEdge-2+j] = projPts[i][npts-1-j];
506  }
507  for(int j=0; j<nptsEdge-2; ++j)
508  {
509  ptsPolygon[i][3*nptsEdge-2+j] = projPts[i][nptsEdge*(nptsEdge-j-2)];
510  }
511  }
512 
513 
514  // Determine relation using angle method (sum=2*pi)
515  NekDouble angleCos, angleAbs, angleSign, angleSum = 0.0;
516  Array<OneD, NekDouble> vec1(3, 0.0), vec2(3, 0.0), vec3(3, 0.0);
517  int id1, id2;
518 
519  for(int i=0; i<nptsPolygon; ++i)
520  {
521  id1 = i;
522  id2 = (id1==(nptsPolygon-1)) ? 0 : (id1+1);
523 
524  for (int j=0; j<3; ++j)
525  {
526  vec1[j] = ptsPolygon[j][id1] - projGloCoord[j];
527  vec2[j] = ptsPolygon[j][id2] - projGloCoord[j];
528  }
529 
530  Vmath::Smul(3, 1.0/sqrt(Vmath::Dot(3, vec1, 1, vec1, 1)),
531  vec1, 1, vec1, 1);
532  Vmath::Smul(3, 1.0/sqrt(Vmath::Dot(3, vec2, 1, vec2, 1)),
533  vec2, 1, vec2, 1);
534 
535 
536  if( ( fabs(vec1[0]+vec2[0]) + fabs(vec1[1]+vec2[1]) +
537  fabs(vec1[2]+vec2[2]) ) < paralTol )
538  {
539  // On the line segement, true
540  // This branch is used to aviod angle=pi but angleSign=-1 (not 1)
541  return true;
542  }
543  else
544  {
545  // Off the line segement, compute angle
546  // vec3 = vec1 x vec2, not scaled
547  vec3[0] = vec1[1]*vec2[2] - vec1[2]*vec2[1];
548  vec3[1] = vec1[2]*vec2[0] - vec1[0]*vec2[2];
549  vec3[2] = vec1[0]*vec2[1] - vec1[1]*vec2[0];
550 
551  // Use the projDir as reference direction (positive)
552  angleSign = Vmath::Dot(3, vec3, 1, projDir, 1) > 0.0 ? 1.0 : -1.0;
553  angleCos = Vmath::Dot(3, vec1, 1, vec2, 1);
554 
555  // Avoid error in using acos()
556  if(angleCos>1.0)
557  {
558  angleCos=1.0;
559  }
560  else if(angleCos<-1.0)
561  {
562  angleCos=-1.0;
563  }
564 
565  angleAbs = acos(angleCos);
566  angleSum += angleSign * angleAbs;
567  }
568  }
569 
570  // Check
571  angleSum = fabs(angleSum);
572  if( fabs(angleSum-2.0*M_PI) < angleTol )
573  {
574  return true;
575  }
576  else
577  {
578  return false;
579  }
580 
581 }
582 
583 
584 /**
585  * @brief Use iteration to get the locCoord. This routine should be used after
586  * we have checked the projected point is inside the projected element.
587  * @param bndGeom Geometry to get the xmap.
588  * @param gloCoord Global coordinate of the point. size=3.
589  * @param pts Global coordinate of the vertices of the elmt. size=2/3.
590  * @param dieUse The main direction(s) used to compute local coordinate
591  * @param locCoord Iteration results for local coordinate(s)
592  * @param dist Returned distance in physical space if the collapsed
593  * locCoord is out of range [-1,1].
594  * @param iterTol Tolerence for iteration.
595  * @param iterMax Maximum iteration steps
596  * @return Converged (true) or not (false)
597  */
600  const Array<OneD, const NekDouble > & gloCoord,
601  const Array<OneD, const Array<OneD, NekDouble> > & pts,
602  const Array<OneD, const int > & dirUse,
603  Array<OneD, NekDouble > & locCoord,
604  const NekDouble iterTol,
605  const int iterMax)
606 {
607  // Initial settings
608  Array<OneD, NekDouble> etaLR(2); // range [-1,1]
609  etaLR[0] = -1.0; // left
610  etaLR[1] = 1.0; // right
611  NekDouble tmpL, tmpR; // tmp values for L/R
612 
613  StdRegions::StdExpansionSharedPtr bndXmap = bndGeom->GetXmap();
614  locCoord[0] = -2.0;
615  int cnt = 0;
616  bool isConverge = false;
617  while(cnt<iterMax)
618  {
619  tmpL = bndXmap->PhysEvaluate(etaLR , pts[dirUse[0]]);
620  tmpR = bndXmap->PhysEvaluate(etaLR+1, pts[dirUse[0]]);
621 
622  if (fabs(gloCoord[dirUse[0]]-tmpL) >= fabs(gloCoord[dirUse[0]]-tmpR))
623  {
624  etaLR[0] = 0.5 * (etaLR[0]+etaLR[1]);
625  }
626  else
627  {
628  etaLR[1] = 0.5 * (etaLR[0]+etaLR[1]);
629  }
630 
631  if ((etaLR[1]-etaLR[0]) < iterTol)
632  {
633  locCoord[0] = 0.5 * (etaLR[0]+etaLR[1]);
634  isConverge = true;
635  break;
636  }
637 
638  ++cnt;
639  }
640 
641  // Warning if failed
642  if(cnt >= iterMax)
643  {
644  WARNINGL1(false, "Bisection iteration is not converged");
645  }
646 
647  return isConverge;
648 }
649 
650 
653  const Array<OneD, const NekDouble> & gloCoord,
654  const Array<OneD, const Array<OneD, NekDouble> > & pts,
655  const Array<OneD, const int > & dirUse,
656  Array<OneD, NekDouble> & locCoord,
657  NekDouble & dist,
658  const NekDouble iterTol,
659  const int iterMax)
660 {
661 
662  const NekDouble LcoordDiv = 15.0;
663 
664  StdRegions::StdExpansionSharedPtr bndXmap = bndGeom->GetXmap();
665 
667  bndGeom->GetMetricInfo()->GetJac(bndXmap->GetPointsKeys());
668  NekDouble scaledTol = Vmath::Vsum(Jac.size(), Jac, 1) /
669  ((NekDouble)Jac.size());
670  scaledTol *= iterTol;
671 
672 
673  // Set the gloCoord used to compute locCoord
674  const int dir1 = dirUse[0];
675  const int dir2 = dirUse[1];
676 
677  Array<OneD, NekDouble> Dx1D1(pts[dir1].size());
678  Array<OneD, NekDouble> Dx1D2(pts[dir1].size());
679  Array<OneD, NekDouble> Dx2D1(pts[dir1].size());
680  Array<OneD, NekDouble> Dx2D2(pts[dir1].size());
681 
682  // Ideally this will be stored in m_geomfactors
683  bndXmap->PhysDeriv(pts[dir1], Dx1D1, Dx1D2);
684  bndXmap->PhysDeriv(pts[dir2], Dx2D1, Dx2D2);
685 
686  // Initial the locCoord, in [-1,1]
687  locCoord[0] = 0.0;
688  locCoord[1] = 0.0;
689 
690  NekDouble x1map, x2map, F1, F2;
691  NekDouble derx1_1, derx1_2, derx2_1, derx2_2, jac;
692  NekDouble resid;
693  int cnt = 0;
694  bool isConverge = false;
695 
696 
697  F1 = F2 = 2000; // Starting value of Function
698  while (cnt++ < iterMax)
699  {
700  x1map = bndXmap->PhysEvaluate(locCoord, pts[dir1]);
701  x2map = bndXmap->PhysEvaluate(locCoord, pts[dir2]);
702 
703  F1 = gloCoord[dir1] - x1map;
704  F2 = gloCoord[dir2] - x2map;
705 
706  if (F1 * F1 + F2 * F2 < scaledTol)
707  {
708  resid = sqrt(F1 * F1 + F2 * F2);
709  isConverge = true;
710  break;
711  }
712 
713  // Interpolate derivative metric at locCoord
714  derx1_1 = bndXmap->PhysEvaluate(locCoord, Dx1D1);
715  derx1_2 = bndXmap->PhysEvaluate(locCoord, Dx1D2);
716  derx2_1 = bndXmap->PhysEvaluate(locCoord, Dx2D1);
717  derx2_2 = bndXmap->PhysEvaluate(locCoord, Dx2D2);
718 
719  jac = derx2_2 * derx1_1 - derx2_1 * derx1_2;
720 
721  // Use analytical inverse of derivitives which are
722  // also similar to those of metric factors.
723  locCoord[0] = locCoord[0] + ( derx2_2 * (gloCoord[dir1] - x1map) -
724  derx1_2 * (gloCoord[dir2] - x2map)) / jac;
725 
726  locCoord[1] = locCoord[1] + (-derx2_1 * (gloCoord[dir1] - x1map) +
727  derx1_1 * (gloCoord[dir2] - x2map)) / jac;
728 
729 
730  // locCoord have diverged so stop iteration
731  if( !(std::isfinite(locCoord[0]) && std::isfinite(locCoord[1])) )
732  {
733  dist = 1e16;
734  std::ostringstream ss;
735  ss << "nan or inf found in NewtonIterForLocCoordOnProjBndElmt in element "
736  << bndGeom->GetGlobalID();
737  WARNINGL1(false, ss.str());
738  return false;
739  }
740  if (fabs(locCoord[0]) > LcoordDiv || fabs(locCoord[1]) > LcoordDiv)
741  {
742  break;
743  }
744  }
745 
746  // Check distance for collapsed coordinate
747  Array<OneD, NekDouble> eta(2);
748  bndXmap->LocCoordToLocCollapsed(locCoord, eta);
749 
750  if(bndGeom->ClampLocCoords(eta, 0.0))
751  {
752  // calculate the global point corresponding to locCoord
753  x1map = bndXmap->PhysEvaluate(eta, pts[dir1]);
754  x2map = bndXmap->PhysEvaluate(eta, pts[dir2]);
755 
756  F1 = gloCoord[dir1] - x1map;
757  F2 = gloCoord[dir2] - x2map;
758 
759  dist = sqrt(F1 * F1 + F2 * F2);
760  }
761  else
762  {
763  dist = 0.0;
764  }
765 
766  // Warning if failed
767  if (cnt >= iterMax)
768  {
769  Array<OneD, NekDouble> collCoords(2);
770  bndXmap->LocCoordToLocCollapsed(locCoord, collCoords);
771 
772  // if coordinate is inside element dump error!
773  if ((collCoords[0] >= -1.0 && collCoords[0] <= 1.0) &&
774  (collCoords[1] >= -1.0 && collCoords[1] <= 1.0))
775  {
776  std::ostringstream ss;
777 
778  ss << "Reached MaxIterations (" << iterMax
779  << ") in Newton iteration ";
780  ss << "Init value (" << setprecision(4) << 0 << "," << 0
781  << ","
782  << ") ";
783  ss << "Fin value (" << locCoord[0] << "," << locCoord[1] << ","
784  << ") ";
785  ss << "Resid = " << resid << " Tolerance = " << sqrt(scaledTol);
786 
787  WARNINGL1(cnt < iterMax, ss.str());
788  }
789  }
790 
791  return isConverge;
792 
793 }
794 
795 
796 /**
797  * @brief Check if a point can be projected onto an oundary element in a given
798  * direction. If yes, give the local coordinates of the projected point.
799  * we have checked the projected point is inside the projected element.
800  * @param bndGeom Pointer to the geometry of the boundary element.
801  * @param gloCoord Global coordinate of the point. size=3.
802  * @param projDir Projection direction, which is used as the reference
803  * direction in the 3D routine. size=3, norm=1.
804  * @param locCoord Iteration results for local coordinates (if inside).
805  * @param projDist Projection distance betweem the point to the wall point.
806  * @param maxDist Disntance to check if the wall point is desired.
807  * @param iterTol Tolerence for iteration.
808  * @return Inside (true) or not (false)
809  */
812  const Array<OneD, const NekDouble > & gloCoord,
813  const Array<OneD, const NekDouble > & projDir,
814  Array< OneD, NekDouble > & locCoord,
815  NekDouble & projDist,
816  const NekDouble maxDist,
817  const NekDouble iterTol)
818 {
819  // Get variables
820  StdRegions::StdExpansionSharedPtr bndXmap = bndGeom->GetXmap();
821  const int npts = bndXmap->GetTotPoints();
822  const int nCoordDim = m_f->m_exp[0]->GetCoordim(0); // =2 for 2.5D cases
823 
824  Array<OneD, Array<OneD, const NekDouble> > bndCoeffs(nCoordDim);
825  Array<OneD, Array<OneD, NekDouble> > pts(nCoordDim);
826  Array<OneD, Array<OneD, NekDouble> > projPts(nCoordDim);
827  Array<OneD, NekDouble > projGloCoord(3, 0.0);
828 
829  for (int i=0; i<nCoordDim; ++i)
830  {
831  pts[i] = Array<OneD, NekDouble>(npts);
832  projPts[i] = Array<OneD, NekDouble>(npts);
833  bndCoeffs[i] = bndGeom->GetCoeffs(i); // 0/1/2 for x/y/z
834  bndXmap->BwdTrans(bndCoeffs[i], pts[i]);
835  }
836 
837  // Project the point and vertices of the element in the input direction
838  ProjectPoint(gloCoord, projDir, 0.0, projGloCoord);
839  ProjectVertices(pts, projDir, 0.0, projPts);
840 
841 
842  // Set the main direction(s) and the minor direction
843  // The gloCoord for minor direction will not be used for locCoord iteration
844  // dirUse[0] is the main dir for 2D/2.5D cases, dirUse[1]/[2] is the minor one
845  // dirUse[0] and dirUse[1] are the main dir for 3D cases, dirUse[2] is hte minor one
846  int dirMaxId = 0; // id to get the dir with largest projDir component
847  for (int i=1; i<nCoordDim; ++i)
848  {
849  if (fabs(projDir[i])>fabs(projDir[dirMaxId]))
850  {
851  dirMaxId = i;
852  }
853  }
854 
855  Array<OneD, int > dirUse(3, 0);
856  if (nCoordDim==2)
857  {
858  // 2D or 2.5D cases
859  if (dirMaxId==0)
860  {
861  dirUse[0] = 1;
862  dirUse[1] = 0;
863  dirUse[2] = 2;
864  }
865  else
866  {
867  dirUse[0] = 0;
868  dirUse[1] = 1;
869  dirUse[2] = 2;
870  }
871  }
872  else
873  {
874  // 3D cases
875  if (dirMaxId==0)
876  {
877  dirUse[0] = 1;
878  dirUse[1] = 2;
879  dirUse[2] = 0;
880  }
881  else if (dirMaxId==1)
882  {
883  dirUse[0] = 2;
884  dirUse[1] = 0;
885  dirUse[2] = 1;
886  }
887  else
888  {
889  dirUse[0] = 0;
890  dirUse[1] = 1;
891  dirUse[2] = 2;
892  }
893 
894  }
895 
896 
897  // Check if the projected point is in the projected elmt
898  // If yes, then compute the locCoord and check if desired point is found
899  if(nCoordDim==2)
900  {
901  if (isInProjectedArea2D(projGloCoord, projPts, 1.0e-12))
902  {
903  bool isConverge, isDesired;
904 
905  isConverge = BisectionForLocCoordOnBndElmt(bndGeom, projGloCoord,
906  projPts, dirUse, locCoord, iterTol);
907 
908  Array<OneD, NekDouble > tmp(2, 0.0);
909  tmp[0] = bndXmap->PhysEvaluate(locCoord, pts[0]) - gloCoord[0];
910  tmp[1] = bndXmap->PhysEvaluate(locCoord, pts[1]) - gloCoord[1];
911  projDist = Vmath::Dot(2, tmp, 1, projDir, 1); // can be negative
912 
913  isDesired = (projDist > 0.0) && (projDist < maxDist);
914 
915  return isConverge && isDesired;
916  }
917  else
918  {
919  return false;
920  }
921 
922  }
923  else
924  {
925  if (isInProjectedArea3D(projGloCoord, projPts, projDir, 1.0e-12, 1.0e-6))
926  {
927  NekDouble dist;
928  bool isConverge, isDesired;
929 
930  isConverge = NewtonIterForLocCoordOnBndElmt(bndGeom, projGloCoord,
931  projPts, dirUse, locCoord, dist, iterTol);
932 
933  if (dist>iterTol)
934  {
935  std::ostringstream ss;
936  ss << "Collapsed locCoord out of range.\n"
937  << "Newton iteration gives the distance: " << dist;
938  WARNINGL1(false, ss.str());
939  }
940 
941  Array<OneD, NekDouble > tmp(3, 0.0);
942  tmp[0] = bndXmap->PhysEvaluate(locCoord, pts[0]) - gloCoord[0];
943  tmp[1] = bndXmap->PhysEvaluate(locCoord, pts[1]) - gloCoord[1];
944  tmp[2] = bndXmap->PhysEvaluate(locCoord, pts[2]) - gloCoord[2];
945  projDist = Vmath::Dot(3, tmp, 1, projDir, 1); // can be negative
946 
947  isDesired = (projDist > 0.0) && (projDist < maxDist);
948 
949  return isConverge && isDesired;
950  }
951  else
952  {
953  return false;
954  }
955 
956  }
957 
958 }
959 
960 
961 /**
962  * @brief Get the normals for a given locCoord
963  * @param bndGeom Pointer to the geometry of the boundary element.
964  * @param locCoord Iteration results for local coordinates (if inside).
965  * @param normals Wall normal as the result
966  */
969  const Array<OneD, const NekDouble > & locCoord,
970  Array< OneD, NekDouble > & normals)
971 {
972  const int nCoordDim = m_f->m_exp[0]->GetCoordim(0); // =2 for 2.5D cases
973  StdRegions::StdExpansionSharedPtr bndXmap = bndGeom->GetXmap();
976  int npts = bndXmap->GetTotPoints();
977 
978  // Get pts in the element
979  for (int i=0; i<nCoordDim; ++i)
980  {
981  pts[i] = Array<OneD, NekDouble>(npts);
982  bndCoeffs[i] = bndGeom->GetCoeffs(i); // 0/1/2 for x/y/z
983  bndXmap->BwdTrans(bndCoeffs[i], pts[i]);
984  }
985 
986  // Get the outward-pointing normals according to the given locCoord
987  if(nCoordDim==2)
988  {
989  Array<OneD, NekDouble> DxD1(pts[0].size());
990  Array<OneD, NekDouble> DyD1(pts[0].size());
991 
992  bndXmap->PhysDeriv(pts[0], DxD1);
993  bndXmap->PhysDeriv(pts[1], DyD1);
994 
995  NekDouble dxd1, dyd1, norm;
996  dxd1 = bndXmap->PhysEvaluate(locCoord, DxD1);
997  dyd1 = bndXmap->PhysEvaluate(locCoord, DyD1);
998  norm = sqrt(dxd1*dxd1 + dyd1*dyd1);
999 
1000  normals[0] = dyd1/norm;
1001  normals[1] = -dxd1/norm;
1002  normals[2] = 0.0;
1003  }
1004  else
1005  {
1006  Array<OneD, NekDouble> DxD1(pts[0].size());
1007  Array<OneD, NekDouble> DxD2(pts[0].size());
1008  Array<OneD, NekDouble> DyD1(pts[0].size());
1009  Array<OneD, NekDouble> DyD2(pts[0].size());
1010  Array<OneD, NekDouble> DzD1(pts[0].size());
1011  Array<OneD, NekDouble> DzD2(pts[0].size());
1012 
1013  bndXmap->PhysDeriv(pts[0], DxD1, DxD2);
1014  bndXmap->PhysDeriv(pts[1], DyD1, DyD2);
1015  bndXmap->PhysDeriv(pts[2], DzD1, DzD2);
1016 
1017  NekDouble dxd1, dyd1, dzd1, dxd2, dyd2, dzd2;
1018  dxd1 = bndXmap->PhysEvaluate(locCoord, DxD1);
1019  dxd2 = bndXmap->PhysEvaluate(locCoord, DxD2);
1020  dyd1 = bndXmap->PhysEvaluate(locCoord, DyD1);
1021  dyd2 = bndXmap->PhysEvaluate(locCoord, DyD2);
1022  dzd1 = bndXmap->PhysEvaluate(locCoord, DzD1);
1023  dzd2 = bndXmap->PhysEvaluate(locCoord, DzD2);
1024 
1025  NekDouble n1, n2, n3, norm;
1026  n1 = dyd1*dzd2 - dyd2*dzd1;
1027  n2 = dzd1*dxd2 - dzd2*dxd1;
1028  n3 = dxd1*dyd2 - dxd2*dyd1;
1029  norm = sqrt(n1*n1 + n2*n2 + n3*n3);
1030 
1031  normals[0] = n1/norm;
1032  normals[1] = n2/norm;
1033  normals[2] = n3/norm;
1034  }
1035 
1036 }
1037 
1038 
1039 
1040 }
1041 }
#define WARNINGL1(condition, msg)
Definition: ErrorUtil.hpp:251
#define ASSERTL0(condition, msg)
Definition: ErrorUtil.hpp:216
A class that contains algorithms for interpolation between pts fields, expansions and different meshe...
FIELD_UTILS_EXPORT void Interpolate(const std::vector< MultiRegions::ExpListSharedPtr > expInField, std::vector< MultiRegions::ExpListSharedPtr > &expOutField, NekDouble def_value=0.0)
Interpolate from an expansion to an expansion.
FieldSharedPtr m_f
Field object.
Definition: Module.h:230
std::map< std::string, ConfigOption > m_config
List of configuration values.
Definition: Module.h:233
This processing module sets up for the boundary field to be extracted.
virtual void Process(po::variables_map &vm)
void ProjectPoint(const Array< OneD, const NekDouble > &gloCoord, const Array< OneD, const NekDouble > &projDir, const NekDouble distToOrig, Array< OneD, NekDouble > &projGloCoord)
Project a single point along the given direction to a plane.
virtual void Process(po::variables_map &vm)
Write mesh to output file.
bool BndElmtContainsPoint(SpatialDomains::GeometrySharedPtr bndGeom, const Array< OneD, const NekDouble > &gloCoord, const Array< OneD, const NekDouble > &projDir, Array< OneD, NekDouble > &locCoord, NekDouble &projDist, const NekDouble maxDist=1.0, const NekDouble iterTol=1.0e-8)
Check if a point can be projected onto an oundary element in a given direction. If yes,...
bool NewtonIterForLocCoordOnBndElmt(SpatialDomains::GeometrySharedPtr bndGeom, const Array< OneD, const NekDouble > &gloCoord, const Array< OneD, const Array< OneD, NekDouble > > &pts, const Array< OneD, const int > &dirUse, Array< OneD, NekDouble > &locCoord, NekDouble &dist, const NekDouble iterTol=1.0e-8, const int iterMax=51)
bool isInProjectedArea2D(const Array< OneD, const NekDouble > &projGloCoord, const Array< OneD, const Array< OneD, NekDouble > > &projPts, const NekDouble paralTol=1.0e-12)
Determine if the projected point is inside the projected element.
bool isInProjectedArea3D(const Array< OneD, const NekDouble > &projGloCoord, const Array< OneD, const Array< OneD, NekDouble > > &projPts, const Array< OneD, const NekDouble > &projDir, const NekDouble paralTol=1.0e-12, const NekDouble angleTol=1.0e-6)
bool BisectionForLocCoordOnBndElmt(SpatialDomains::GeometrySharedPtr bndGeom, const Array< OneD, const NekDouble > &gloCoord, const Array< OneD, const Array< OneD, NekDouble > > &pts, const Array< OneD, const int > &dirUse, Array< OneD, NekDouble > &locCoord, const NekDouble iterTol=1.0e-8, const int iterMax=51)
Use iteration to get the locCoord. This routine should be used after we have checked the projected po...
void GetNormals(SpatialDomains::GeometrySharedPtr bndGeom, const Array< OneD, const NekDouble > &locCoord, Array< OneD, NekDouble > &normals)
Get the normals for a given locCoord.
void ProjectVertices(const Array< OneD, const Array< OneD, NekDouble > > &pts, const Array< OneD, const NekDouble > &projDir, const NekDouble distToOrig, Array< OneD, Array< OneD, NekDouble > > &projPts)
Project a single point along the given direction to a plane.
tKey RegisterCreatorFunction(tKey idKey, CreatorFunction classCreator, std::string pDesc="")
Register a class with the factory.
Definition: NekFactory.hpp:200
static std::shared_ptr< DataType > AllocateSharedPtr(const Args &...args)
Allocate a shared pointer from the memory pool.
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:135
const BoundaryRegionCollection & GetBoundaryRegions(void) const
Definition: Conditions.h:238
std::shared_ptr< Field > FieldSharedPtr
Definition: Field.hpp:989
std::pair< ModuleType, std::string > ModuleKey
Definition: Module.h:290
ModuleFactory & GetModuleFactory()
Definition: Module.cpp:49
static std::map< PtsInfo, int > NullPtsInfoMap
Definition: PtsField.h:70
static const NekDouble kNekUnsetDouble
std::map< int, BoundaryRegionShPtr > BoundaryRegionCollection
Definition: Conditions.h:217
std::shared_ptr< Geometry > GeometrySharedPtr
Definition: Geometry.h:53
std::shared_ptr< StdExpansion > StdExpansionSharedPtr
The above copyright notice and this permission notice shall be included.
Definition: CoupledSolver.h:1
double NekDouble
void Neg(int n, T *x, const int incx)
Negate x = -x.
Definition: Vmath.cpp:461
T Vsum(int n, const T *x, const int incx)
Subtract return sum(x)
Definition: Vmath.cpp:846
T Dot(int n, const T *w, const T *x)
vvtvp (vector times vector times vector): z = w*x*y
Definition: Vmath.cpp:1038
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:322
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:225
scalarT< T > sqrt(scalarT< T > in)
Definition: scalar.hpp:267
Represents a command-line configuration option.
Definition: Module.h:134