cellPointWallModified.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-2026 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 
26 #include "cellPointWallModified.H"
27 #include "syncTools.H"
28 #include "wallPolyPatch.H"
30 
31 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
32 
33 template<class Type>
34 template<class TYPE>
37 (
38  const VolField<TYPE>& psi
39 ) const
40 {
42  << typeName << " interpolation is only defined for vector fields"
43  << exit(FatalError);
44 
45  return tmp<PointField<TYPE>>(nullptr);
46 }
47 
48 
49 template<class Type>
52 (
53  const volVectorField& psi
54 ) const
55 {
56  using namespace constant::mathematical;
57 
58  const fvMesh& mesh = psi.mesh();
59 
60  // Create the point field
62  (
64  (
65  "volPointInterpolateWallModified(" + psi.name() + ')',
67  dimensioned<Type>("zero", psi.dimensions(), Zero)
68  )
69  );
70  pointVectorField& psip = tPsip.ref();
71 
72  // Interpolate to the points with wall patches extrapolated
73  {
74  wordList patchTypes(psi.boundaryField().size());
76  {
77  if (isA<wallPolyPatch>(mesh.poly().boundary()[patchi]))
78  {
80  }
81  else
82  {
84  }
85  }
86  volVectorField psiExtrapolated
87  (
88  IOobject
89  (
90  psi.name() + "Extrapolated",
91  mesh.time().name(),
92  mesh
93  ),
94  psi,
96  );
97  psiExtrapolated.correctBoundaryConditions();
99  (
100  psiExtrapolated,
101  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 
111  {
112  const polyPatch& patch = mesh.poly().boundary()[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  // Calculate the rotation necessary from the vector to the (negative) point
147  // normal needed to make the interpolated field point into the mesh
148  scalarField theta0(mesh.nPoints(), -vGreat), theta1(mesh.nPoints(), vGreat);
149  scalar maxVHatDotN = - vGreat;
151  {
152  const polyPatch& patch = mesh.poly().boundary()[patchi];
153  if (isA<wallPolyPatch>(patch))
154  {
155  forAll(patch, patchFacei)
156  {
157  const label facei = patch.start() + patchFacei;
158  const face& f = patch[patchFacei];
159 
160  for (label i = 1; i < f.size() - 1; ++ i)
161  {
162  const triFace tri
163  (
164  tetIndices(mesh.faceOwner()[facei], facei, i)
165  .faceTriIs(mesh)
166  );
167 
168  const vector n = tri.normal(mesh.points());
169 
170  forAll(tri, triPointI)
171  {
172  const label pointi = tri[triPointI];
173 
174  const vector& v = psip[pointi];
175 
176  const scalar vHatDotN = normalised(v) & n;
177  maxVHatDotN = max(maxVHatDotN, vHatDotN);
178 
179  const vector a =
180  normalised(v ^ pointNormals[pointi]);
181 
182  const scalar C = v & n, S = (v ^ a) & n;
183 
184  const scalar theta = atan2(C, - S);
185 
186  theta0[pointi] = max(theta0[pointi], theta);
187  theta1[pointi] = min(theta1[pointi], theta + pi);
188  }
189  }
190  }
191  }
192  }
193 
194  if (debug)
195  {
196  reduce(maxVHatDotN, maxOp<scalar>());
197  Info<< typeName << ": Maximum in-to-wall dot product before = "
198  << maxVHatDotN << endl;
199  }
200 
201  syncTools::syncPointList
202  (
203  mesh,
204  theta0,
205  maxEqOp<scalar>(),
206  scalar(0)
207  );
208 
209  syncTools::syncPointList
210  (
211  mesh,
212  theta1,
213  minEqOp<scalar>(),
214  scalar(0)
215  );
216 
217  if (debug > 1)
218  {
219  pointVectorField(psip.name() + "Before", psip).write();
220  }
221 
222  // Apply the rotations so that the interpolated field points into the mesh
224  {
225  const polyPatch& patch = mesh.poly().boundary()[patchi];
226  if (isA<wallPolyPatch>(patch))
227  {
228  forAll(patch.meshPoints(), patchPointi)
229  {
230  const label pointi = patch.meshPoints()[patchPointi];
231 
232  vector& v = psip[pointi];
233 
234  if (theta0[pointi] <= 0 && theta1[pointi] >= 0)
235  {
236  continue;
237  }
238 
239  if (theta0[pointi] >= theta1[pointi])
240  {
241  v = Zero;
242  continue;
243  }
244 
245  const scalar theta =
246  theta0[pointi] > 0 ? theta0[pointi] : theta1[pointi];
247 
248  const scalar c = cos(theta), s = sin(theta);
249 
250  const scalar scale = max(c, 0); // or mag(theta)/(pi/2) ...
251 
252  const vector a = normalised(v ^ pointNormals[pointi]);
253 
254  v = scale*(tensor::I*c - (*a)*s + sqr(a)*(1 - c)) & v;
255 
256  theta0[pointi] = theta1[pointi] = 0;
257  }
258  }
259  }
260 
261  // Report the field-normal dot products
262  if (debug)
263  {
264  maxVHatDotN = - vGreat;
265 
267  {
268  const polyPatch& patch = mesh.poly().boundary()[patchi];
269  if (isA<wallPolyPatch>(patch))
270  {
271  forAll(patch, patchFacei)
272  {
273  const label facei = patch.start() + patchFacei;
274  const face& f = patch[patchFacei];
275 
276  for (label i = 1; i < f.size() - 1; ++ i)
277  {
278  const triFace tri
279  (
280  tetIndices(mesh.faceOwner()[facei], facei, i)
281  .faceTriIs(mesh)
282  );
283 
284  const vector n = tri.normal(mesh.points());
285 
286  forAll(tri, triPointI)
287  {
288  const label pointi = tri[triPointI];
289 
290  const vector& v = psip[pointi];
291 
292  const scalar vHatDotN = normalised(v) & n;
293  maxVHatDotN = max(maxVHatDotN, vHatDotN);
294  }
295  }
296  }
297  }
298  }
299 
300  reduce(maxVHatDotN, maxOp<scalar>());
301  Info<< typeName << ": Maximum in-to-wall dot product after = "
302  << maxVHatDotN << endl;
303  }
304 
305  // Write the interpolated field
306  if (debug > 1)
307  {
308  psip.write();
309  }
310 
311  return tPsip;
312 }
313 
314 
315 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
316 
317 template<class Type>
319 (
320  const VolField<Type>& psi
321 )
322 :
323  cellPoint<Type>(psi, calcPointField(psi))
324 {}
325 
326 
327 template<class Type>
329 (
331 )
332 :
333  cellPoint<Type>(i)
334 {}
335 
336 
337 // ************************************************************************* //
label n
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:449
static volPointInterpolation & New(const word &name, const fvMesh &mesh)
Construct and return the named DemandDrivenMeshObject.
Generic GeometricField class.
const word & name() const
Return name.
Definition: IOobject.H:307
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:98
const Time & time() const
Return the top-level database.
Definition: fvMesh.H:433
const polyMesh & poly() const
Return reference to polyMesh.
Definition: fvMesh.H:456
As interpolations::cellPoint, but with the point field modified on wall faces.
cellPointWallModified(const VolField< Type > &psi)
Construct from components.
Piecewise-linear interpolation method. Uses volPointInterpolation to create values on the points....
const polyBoundaryMesh & boundary() const
Return boundary mesh.
Definition: polyMesh.H:393
virtual const labelList & faceOwner() const
Return face owner.
Definition: polyMesh.C:1321
virtual const pointField & points() const
Return raw points.
Definition: polyMesh.C:1295
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
Template function which returns the un-mangled name of a given type. Useful for types which do not ha...
tmp< PointField< Type > > interpolate(const VolField< Type > &) const
Interpolate volField using inverse distance weighting.
Foam::fvMesh mesh(Foam::IOobject(regionName, runTime.name(), runTime, Foam::IOobject::MUST_READ), false)
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:334
volScalarField scalarField(fieldObject, mesh)
label patchi
gmvFile<< "tracers "<< particles.size()<< nl;forAllConstIter(lagrangian::Cloud< passiveParticle >, particles, iter){ gmvFile<< iter().position().x()<< " ";}gmvFile<< nl;forAllConstIter(lagrangian::Cloud< passiveParticle >, particles, iter){ gmvFile<< iter().position().y()<< " ";}gmvFile<< nl;forAllConstIter(lagrangian::Cloud< passiveParticle >, particles, iter){ gmvFile<< iter().position().z()<< " ";}gmvFile<< nl;forAll(lagrangianScalarNames, i){ word name=lagrangianScalarNames[i];IOField< scalar > s(IOobject(name, runTime.name(), lagrangian::cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
const volScalarField & psi
const dimensionedScalar c
Speed of light in a vacuum.
tmp< fvMatrix< Type > > S(const Pair< tmp< volScalarField::Internal >> &, const VolField< Type > &)
static const coefficient C("C", dimTemperature, 234.5)
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:63
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
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:288
String typeName(const std::type_info &info)
Return the un-mangled name given the standard type info.
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
tmp< DimensionedField< typename outerProduct< Type, Type >::type, GeoMesh, Field >> sqr(const DimensionedField< Type, GeoMesh, PrimitiveField > &df)
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)
dimensionSet normalised(const dimensionSet &)
Definition: dimensionSet.C:509
dimensioned< Type > min(const DimensionedField< Type, GeoMesh, PrimitiveField > &df)
PointField< vector > pointVectorField
tmp< DimensionedField< scalar, GeoMesh, Field > > atan2(const DimensionedField< scalar, GeoMesh, PrimitiveField1 > &dsf1, const DimensionedField< scalar, GeoMesh, PrimitiveField2 > &dsf2)
error FatalError
tmp< DimensionedField< TypeR, GeoMesh, Field > > New(const tmp< DimensionedField< TypeR, GeoMesh, Field >> &tdf1, const word &name, const dimensionSet &dimensions)
dimensionedScalar cos(const dimensionedScalar &ds)
dimensioned< Type > max(const DimensionedField< Type, GeoMesh, PrimitiveField > &df)
wordList patchTypes(nPatches)
face triFace(3)
labelList f(nPoints)