interpolationCellPointWallModified.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration | Website: https://openfoam.org
5  \\ / A nd | Copyright (C) 2011-2022 OpenFOAM Foundation
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
11  OpenFOAM is free software: you can redistribute it and/or modify it
12  under the terms of the GNU General Public License as published by
13  the Free Software Foundation, either version 3 of the License, or
14  (at your option) any later version.
15 
16  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19  for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
23 
24 \*---------------------------------------------------------------------------*/
25 
27 #include "syncTools.H"
28 #include "volPointInterpolation.H"
29 #include "wallPolyPatch.H"
31 
32 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
33 
34 template<class Type>
35 template<class TYPE>
38 (
39  const VolField<TYPE>& psi
40 ) const
41 {
43  << typeName << " interpolation is only defined for vector fields"
44  << exit(FatalError);
45 
46  return tmp<PointField<TYPE>>(nullptr);
47 }
48 
49 
50 template<class Type>
53 (
54  const volVectorField& psi
55 ) const
56 {
57  using namespace constant::mathematical;
58 
59  const fvMesh& mesh = psi.mesh();
60 
61 
62  // Create the point field
64  (
66  (
67  "volPointInterpolateWallModified(" + psi.name() + ')',
68  pointMesh::New(mesh),
69  dimensioned<Type>("zero", psi.dimensions(), Zero)
70  )
71  );
72  pointVectorField& psip = tPsip.ref();
73 
74 
75  // Interpolate to the points with wall patches extrapolated
76  {
77  wordList patchTypes(psi.boundaryField().size());
79  {
80  if (isA<wallPolyPatch>(mesh.boundaryMesh()[patchi]))
81  {
82  patchTypes[patchi] = zeroGradientFvPatchVectorField::typeName;
83  }
84  else
85  {
86  patchTypes[patchi] = calculatedFvPatchVectorField::typeName;
87  }
88  }
89  volVectorField psiExtrapolated
90  (
91  IOobject
92  (
93  psi.name() + "Extrapolated",
94  mesh.time().name(),
95  mesh
96  ),
97  psi,
99  );
100  psiExtrapolated.correctBoundaryConditions();
101  volPointInterpolation::New(mesh).interpolate(psiExtrapolated, psip);
102  }
103 
104 
105  // Generate point normals across the entire boundary
106  pointField pointNormals(mesh.nPoints(), vector::zero);
107  {
108  scalarField pointCount(mesh.nPoints(), 0);
109 
110  forAll(mesh.boundaryMesh(), patchi)
111  {
112  const polyPatch& patch = mesh.boundaryMesh()[patchi];
113 
114  forAll(patch, patchFacei)
115  {
116  const face& f = patch[patchFacei];
117  const vector& n = patch.faceNormals()[patchFacei];
118 
119  forAll(f, i)
120  {
121  pointNormals[f[i]] += n;
122  pointCount[f[i]] += 1;
123  }
124  }
125  }
126 
127  syncTools::syncPointList
128  (
129  mesh,
130  pointNormals,
131  plusEqOp<vector>(),
132  vector::zero
133  );
134 
135  syncTools::syncPointList
136  (
137  mesh,
138  pointCount,
139  plusEqOp<scalar>(),
140  scalar(0)
141  );
142 
143  pointNormals /= max(pointCount, small);
144  }
145 
146 
147  // Calculate the rotation necessary from the vector to the (negative) point
148  // normal needed to make the interpolated field point into the mesh
149  scalarField theta0(mesh.nPoints(), -vGreat), theta1(mesh.nPoints(), vGreat);
150  scalar maxVHatDotN = - vGreat;
151  forAll(mesh.boundaryMesh(), patchi)
152  {
153  const polyPatch& patch = mesh.boundaryMesh()[patchi];
154  if (isA<wallPolyPatch>(patch))
155  {
156  forAll(patch, patchFacei)
157  {
158  const label facei = patch.start() + patchFacei;
159  const face& f = patch[patchFacei];
160 
161  for (label i = 1; i < f.size() - 1; ++ i)
162  {
163  const triFace tri
164  (
165  tetIndices(mesh.faceOwner()[facei], facei, i)
166  .faceTriIs(mesh)
167  );
168 
169  const vector n = tri.normal(mesh.points());
170 
171  forAll(tri, triPointI)
172  {
173  const label pointi = tri[triPointI];
174 
175  const vector& v = psip[pointi];
176 
177  const scalar vHatDotN = normalised(v) & n;
178  maxVHatDotN = max(maxVHatDotN, vHatDotN);
179 
180  const vector a =
181  normalised(v ^ pointNormals[pointi]);
182 
183  const scalar C = v & n, S = (v ^ a) & n;
184 
185  const scalar theta = atan2(C, - S);
186 
187  theta0[pointi] = max(theta0[pointi], theta);
188  theta1[pointi] = min(theta1[pointi], theta + pi);
189  }
190  }
191  }
192  }
193  }
194 
195  if (debug)
196  {
197  reduce(maxVHatDotN, maxOp<scalar>());
198  Info<< typeName << ": Maximum in-to-wall dot product before = "
199  << maxVHatDotN << endl;
200  }
201 
202  syncTools::syncPointList
203  (
204  mesh,
205  theta0,
206  maxEqOp<scalar>(),
207  scalar(0)
208  );
209 
210  syncTools::syncPointList
211  (
212  mesh,
213  theta1,
214  minEqOp<scalar>(),
215  scalar(0)
216  );
217 
218 
219  if (debug > 1)
220  {
221  pointVectorField(psip.name() + "Before", psip).write();
222  }
223 
224 
225  // Apply the rotations so that the interpolated field points into the mesh
226  forAll(mesh.boundaryMesh(), patchi)
227  {
228  const polyPatch& patch = mesh.boundaryMesh()[patchi];
229  if (isA<wallPolyPatch>(patch))
230  {
231  forAll(patch.meshPoints(), patchPointi)
232  {
233  const label pointi = patch.meshPoints()[patchPointi];
234 
235  vector& v = psip[pointi];
236 
237  if (theta0[pointi] <= 0 && theta1[pointi] >= 0)
238  {
239  continue;
240  }
241 
242  if (theta0[pointi] >= theta1[pointi])
243  {
244  v = Zero;
245  continue;
246  }
247 
248  const scalar theta =
249  theta0[pointi] > 0 ? theta0[pointi] : theta1[pointi];
250 
251  const scalar c = cos(theta), s = sin(theta);
252 
253  const scalar scale = max(c, 0); // or mag(theta)/(pi/2) ...
254 
255  const vector a = normalised(v ^ pointNormals[pointi]);
256 
257  v = scale*(tensor::I*c - (*a)*s + sqr(a)*(1 - c)) & v;
258 
259  theta0[pointi] = theta1[pointi] = 0;
260  }
261  }
262  }
263 
264 
265  // Report the field-normal dot products
266  if (debug)
267  {
268  maxVHatDotN = - vGreat;
269 
270  forAll(mesh.boundaryMesh(), patchi)
271  {
272  const polyPatch& patch = mesh.boundaryMesh()[patchi];
273  if (isA<wallPolyPatch>(patch))
274  {
275  forAll(patch, patchFacei)
276  {
277  const label facei = patch.start() + patchFacei;
278  const face& f = patch[patchFacei];
279 
280  for (label i = 1; i < f.size() - 1; ++ i)
281  {
282  const triFace tri
283  (
284  tetIndices(mesh.faceOwner()[facei], facei, i)
285  .faceTriIs(mesh)
286  );
287 
288  const vector n = tri.normal(mesh.points());
289 
290  forAll(tri, triPointI)
291  {
292  const label pointi = tri[triPointI];
293 
294  const vector& v = psip[pointi];
295 
296  const scalar vHatDotN = normalised(v) & n;
297  maxVHatDotN = max(maxVHatDotN, vHatDotN);
298  }
299  }
300  }
301  }
302  }
303 
304  reduce(maxVHatDotN, maxOp<scalar>());
305  Info<< typeName << ": Maximum in-to-wall dot product after = "
306  << maxVHatDotN << endl;
307  }
308 
309 
310  // Write the interpolated field
311  if (debug > 1)
312  {
313  psip.write();
314  }
315 
316 
317  return tPsip;
318 }
319 
320 
321 // * * * * * * * * * * * * * * * * Constructor * * * * * * * * * * * * * * * //
322 
323 template<class Type>
326 (
327  const VolField<Type>& psi
328 )
329 :
330  interpolationCellPoint<Type>(psi, calcPointField(psi))
331 {}
332 
333 
334 template<class Type>
337 (
339 )
340 :
341  interpolationCellPoint<Type>(i)
342 {}
343 
344 
345 // ************************************************************************* //
static const Foam::dimensionedScalar C("C", Foam::dimTemperature, 234.5)
label n
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:434
Generic GeometricField class.
Internal & ref()
Return a reference to the dimensioned internal field.
const word & name() const
Return name.
Definition: IOobject.H:310
Generic dimensioned Type class.
const word & name() const
Return const reference to name.
Mesh data needed to do the Finite Volume discretisation.
Definition: fvMesh.H:101
const Time & time() const
Return the top-level database.
Definition: fvMesh.H:406
As interpolationCellPoint, but with the point field modified on wall faces.
interpolationCellPointWallModified(const VolField< Type > &psi)
Construct from components.
Given cell centre values and point (vertex) values decompose into tetrahedra and linear interpolate w...
virtual const labelList & faceOwner() const
Return face owner.
Definition: polyMesh.C:1387
const polyBoundaryMesh & boundaryMesh() const
Return boundary mesh.
Definition: polyMesh.H:403
virtual const pointField & points() const
Return raw points.
Definition: polyMesh.C:1361
label nPoints() const
virtual bool write(const bool write=true) const
Write using setting from DB.
A class for managing temporary objects.
Definition: tmp.H:55
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:306
volScalarField scalarField(fieldObject, mesh)
label patchi
gmvFile<< "tracers "<< particles.size()<< nl;forAllConstIter(Cloud< passiveParticle >, particles, iter){ gmvFile<< iter().position().x()<< " ";}gmvFile<< nl;forAllConstIter(Cloud< passiveParticle >, particles, iter){ gmvFile<< iter().position().y()<< " ";}gmvFile<< nl;forAllConstIter(Cloud< passiveParticle >, particles, iter){ gmvFile<< iter().position().z()<< " ";}gmvFile<< nl;forAll(lagrangianScalarNames, i){ word name=lagrangianScalarNames[i];IOField< scalar > s(IOobject(name, runTime.name(), cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
const volScalarField & psi
autoPtr< CompressibleMomentumTransportModel > New(const volScalarField &rho, const volVectorField &U, const surfaceScalarField &phi, const viscosity &viscosity)
const dimensionedScalar c
Speed of light in a vacuum.
tmp< fvMatrix< Type > > S(const Pair< tmp< volScalarField::Internal >> &, const VolField< Type > &)
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
static const zero Zero
Definition: zero.H:97
VolField< vector > volVectorField
Definition: volFieldsFwd.H:62
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Definition: label.H:59
dimensionedSymmTensor sqr(const dimensionedVector &dv)
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
dimensionedScalar sin(const dimensionedScalar &ds)
messageStream Info
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:42
static const Identity< scalar > I
Definition: Identity.H:93
layerAndWeight min(const layerAndWeight &a, const layerAndWeight &b)
dimensionedScalar atan2(const dimensionedScalar &x, const dimensionedScalar &y)
Vector< scalar > vector
A scalar version of the templated Vector.
Definition: vector.H:49
void reduce(const List< UPstream::commsStruct > &comms, T &Value, const BinaryOp &bop, const int tag, const label comm)
layerAndWeight max(const layerAndWeight &a, const layerAndWeight &b)
PointField< vector > pointVectorField
Form normalised(const VectorSpace< Form, Cmpt, Ncmpts > &vs)
Definition: VectorSpaceI.H:413
error FatalError
dimensionedScalar cos(const dimensionedScalar &ds)
wordList patchTypes(nPatches)
face triFace(3)
labelList f(nPoints)