geometricElementTransformPointSmoother.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2024-2025 OpenCFD Ltd.
9 -------------------------------------------------------------------------------
10 License
11  This file is part of OpenFOAM.
12 
13  OpenFOAM is free software: you can redistribute it and/or modify it
14  under the terms of the GNU General Public License as published by
15  the Free Software Foundation, either version 3 of the License, or
16  (at your option) any later version.
17 
18  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
19  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21  for more details.
22 
23  You should have received a copy of the GNU General Public License
24  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
25 
26 \*---------------------------------------------------------------------------*/
27 
29 #include "cellPointConnectivity.H"
31 
32 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
33 
34 namespace Foam
35 {
36 namespace pointSmoothers
37 {
38  defineTypeNameAndDebug(geometricElementTransformPointSmoother, 0);
40  (
41  pointSmoother,
42  geometricElementTransformPointSmoother,
43  dictionary
44  );
45 }
46 }
47 
48 
49 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
50 
51 Foam::scalar
52 Foam::pointSmoothers::geometricElementTransformPointSmoother::cellQuality
53 (
54  const polyMesh& mesh,
55  const pointField& currentPoints,
56  const cellPointConnectivity& connectivity,
57  const label celli
58 )
59 {
60  const cell& cFaces = mesh.cells()[celli];
61  const labelList cPoints(cFaces.labels(mesh.faces()));
62 
63  // Calculate a transformed point for each cell point
64 
65  scalar cellQ = 0.0;
66  label nTets = 0;
67 
68  forAll(cPoints, cPointi)
69  {
70  const label pointi(cPoints[cPointi]);
71  const point& pt = currentPoints[pointi];
72  const labelList& pPoints
73  (
74  connectivity.cellPointPoints()[celli][cPointi]
75  );
76  if (pPoints.size() != 3)
77  {
78  WarningInFunction<< "Cell:" << celli
79  << " point:" << pointi
80  << " connected points:" << pPoints << endl;
81  }
82  else
83  {
84  const Tensor<scalar> mA
85  (
86  currentPoints[pPoints[0]] - pt,
87  currentPoints[pPoints[1]] - pt,
88  currentPoints[pPoints[2]] - pt
89  );
90  const scalar sigma(det(mA));
91 
92  if (sigma < ROOTVSMALL)
93  {
94  return 0;
95  }
96 
97  // 3 * pow(sigma, 2.0/3.0)/magSqr(mA)
98  const scalar tetQ =
99  scalar(3) * Foam::cbrt(Foam::sqr(sigma)) / magSqr(mA);
100  cellQ += tetQ;
101  nTets++;
102  }
103  }
104 
105  return cellQ/nTets;
106 }
107 
108 
109 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
110 
113 (
114  const polyMesh& mesh,
115  const dictionary& dict
116 )
117 :
119  transformationParameter_
120  (
121  dict.get<scalar>("transformationParameter")
122  )
123 {}
124 
125 
126 // * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
127 
129 (
130  const labelList& facesToMove,
131  const pointField& oldPoints,
132  const pointField& currentPoints,
133  const pointField& faceCentres,
134  const vectorField& faceAreas,
135  const pointField& cellCentres,
136  const scalarField& cellVolumes,
137  vectorField& pointDisplacement
138 ) const
139 {
140  // Lookup or generate the cell-point connectivity/
141  const cellPointConnectivity& connectivity =
143  (
144  mesh()
145  );
146 
147  // Number of points used in each average
148  labelField counts(mesh().nPoints(), -1);
149 
150  // Reset the displacements which are about to be calculated
151  reset(facesToMove, counts, pointDisplacement);
152 
153  // Identify the cells which are to be moved
154  labelHashSet cellsToMove(facesToMove.size()*2/3);
155  forAll(facesToMove, faceToMoveI)
156  {
157  const label faceI(facesToMove[faceToMoveI]);
158 
159  cellsToMove.insert(mesh().faceOwner()[faceI]);
160 
161  if (mesh().isInternalFace(faceI))
162  {
163  cellsToMove.insert(mesh().faceNeighbour()[faceI]);
164  }
165  }
166 
167  // Transformed point field
168  pointField transformedPoints(currentPoints);
169 
170  // Calculate the internal transformations
171  for (const label cellI : cellsToMove)
172  {
173  const cell& cFaces
174  (
175  mesh().cells()[cellI]
176  );
177  const labelList cPoints
178  (
179  cFaces.labels(mesh().faces())
180  );
181  const edgeList cEdges
182  (
183  cFaces.edges(mesh().faces())
184  );
185 
186  // Calculate a transformed point for each cell point
187  forAll(cPoints, cPointI)
188  {
189  const label pointI(cPoints[cPointI]);
190 
191  if (counts[pointI] == -1) continue;
192 
193  const labelList& pPoints
194  (
195  connectivity.cellPointPoints()[cellI][cPointI]
196  );
197  const labelList& pFaces
198  (
199  connectivity.cellPointFaces()[cellI][cPointI]
200  );
201  const label nPPoints(pPoints.size());
202 
203  // Initial guess of the dual face centre
204  vector dualAverage(vector::zero);
205  forAll(pPoints, pPointI)
206  {
207  dualAverage +=
208  currentPoints[pPoints[pPointI]]
209  + faceCentres[pFaces[pPointI]];
210  }
211  dualAverage /= 2*nPPoints;
212 
213  // Calculate the dual face centre and normal
214  vector dualNormal(vector::zero);
215  forAll(pPoints, pPointI)
216  {
217  const label nextPPointI((pPointI + 1) % nPPoints);
218 
219  point edgeCentre
220  (
221  0.5
222  *(
223  currentPoints[pPoints[pPointI]]
224  + currentPoints[pointI]
225  )
226  );
227  point nextFaceCentre
228  (
229  faceCentres[pFaces[nextPPointI]]
230  );
231  point nextEdgeCentre
232  (
233  0.5
234  *(
235  currentPoints[pPoints[nextPPointI]]
236  + currentPoints[pointI]
237  )
238  );
239 
240  dualNormal +=
241  (nextFaceCentre - edgeCentre)
242  ^(edgeCentre - dualAverage);
243  dualNormal +=
244  (nextEdgeCentre - nextFaceCentre)
245  ^(nextFaceCentre - dualAverage);
246  }
247  vector dualNormalHat(dualNormal/max(mag(dualNormal), ROOTVSMALL));
248 
249  scalar sumA(0);
250  vector sumAc(vector::zero);
251  forAll(pPoints, pPointI)
252  {
253  const label nextPPointI((pPointI + 1) % nPPoints);
254 
255  point edgeCentre
256  (
257  0.5
258  *(
259  currentPoints[pPoints[pPointI]]
260  + currentPoints[pointI]
261  )
262  );
263  point nextFaceCentre
264  (
265  faceCentres[pFaces[nextPPointI]]
266  );
267  point nextEdgeCentre
268  (
269  0.5
270  *(
271  currentPoints[pPoints[nextPPointI]]
272  + currentPoints[pointI]
273  )
274  );
275 
276  vector c1 = edgeCentre + nextFaceCentre + dualAverage;
277  vector c2 = nextFaceCentre + nextEdgeCentre + dualAverage;
278 
279  vector n1 =
280  (nextFaceCentre - edgeCentre)
281  ^(edgeCentre - dualAverage);
282  vector n2 =
283  (nextEdgeCentre - nextFaceCentre)
284  ^(nextFaceCentre - dualAverage);
285 
286  scalar a1 = n1 & dualNormalHat;
287  scalar a2 = n2 & dualNormalHat;
288 
289  sumA += a1 + a2;
290  sumAc += a1*c1 + a2*c2;
291  }
292 
293  const vector dualCentre(sumAc/max(sumA, ROOTVSMALL)/3);
294 
295  // Calculate the transformed point
296  transformedPoints[pointI] =
297  dualCentre
298  + transformationParameter_
299  *dualNormal/sqrt(max(mag(dualNormal), ROOTVSMALL));
300  }
301 
302  // Length scale
303  scalar lengthScale(0), transformedLengthScale(0);
304  forAll(cEdges, cEdgeI)
305  {
306  lengthScale +=
307  cEdges[cEdgeI].mag(currentPoints);
308  transformedLengthScale +=
309  cEdges[cEdgeI].mag(transformedPoints);
310  }
311  lengthScale /= cEdges.size();
312  transformedLengthScale /= cEdges.size();
313 
314  const scalar lengthScaleRatio =
315  (
316  (transformedLengthScale > SMALL)
317  ? lengthScale/transformedLengthScale
318  : scalar(0)
319  );
320 
321  // Add the displacement to the average
322  forAll(cPoints, cPointI)
323  {
324  const label pointI(cPoints[cPointI]);
325 
326  if (counts[pointI] == -1) continue;
327 
328  const vector newPoint
329  (
330  cellCentres[cellI]
331  + lengthScaleRatio
332  *(
333  transformedPoints[pointI]
334  - cellCentres[cellI]
335  )
336  );
337 
338  ++ counts[pointI];
339 
340  pointDisplacement[pointI] += newPoint - oldPoints[pointI];
341  }
342  }
343 
344  // Reset all the boundary faces
345  reset(facesToMove, counts, pointDisplacement, false);
346 
347  // Calculate the boundary transformations
348  forAll(facesToMove, faceToMoveI)
349  {
350  const label faceI(facesToMove[faceToMoveI]);
351 
352  if (!isInternalOrProcessorFace(faceI))
353  {
354  const labelList& fPoints(mesh().faces()[faceI]);
355 
356  // Face normal
357  vector faceNormalHat(faceAreas[faceI]);
358  faceNormalHat /= max(SMALL, mag(faceNormalHat));
359 
360  // Calculate a transformed point for each face point
361  forAll(fPoints, fPointI)
362  {
363  const label pointI(fPoints[fPointI]);
364 
365  const label fPointIPrev
366  (
367  (fPointI - 1 + fPoints.size()) % fPoints.size()
368  );
369  const label fPointINext
370  (
371  (fPointI + 1) % fPoints.size()
372  );
373 
374  const vector dualCentre
375  (
376  currentPoints[pointI]/2
377  + (
378  currentPoints[fPoints[fPointINext]]
379  + currentPoints[fPoints[fPointIPrev]]
380  )/4
381  );
382  const vector dualNormal
383  (
384  (
385  currentPoints[fPoints[fPointINext]]
386  - currentPoints[fPoints[fPointIPrev]]
387  )/2
388  ^faceNormalHat
389  );
390 
391  transformedPoints[pointI] =
392  dualCentre
393  + transformationParameter_
394  *dualNormal/sqrt(max(mag(dualNormal), ROOTVSMALL));
395  }
396 
397  // Length scale
398  scalar lengthScale(0), transformedLengthScale(0);
399  forAll(fPoints, fPointI)
400  {
401  const label fPointINext((fPointI + 1)%fPoints.size());
402 
403  const label pointI(fPoints[fPointI]);
404  const label pointINext(fPoints[fPointINext]);
405 
406  lengthScale += mag
407  (
408  currentPoints[pointINext] - currentPoints[pointI]
409  );
410  transformedLengthScale += mag
411  (
412  transformedPoints[pointINext] - transformedPoints[pointI]
413  );
414  }
415  lengthScale /= fPoints.size();
416  transformedLengthScale /= fPoints.size();
417 
418  const scalar lengthScaleRatio
419  (
420  (transformedLengthScale > SMALL)
421  ? lengthScale/transformedLengthScale
422  : scalar(0)
423  );
424 
425  // Add the displacement to the average
426  forAll(fPoints, fPointI)
427  {
428  const label pointI(fPoints[fPointI]);
429 
430  const vector newPoint
431  (
432  faceCentres[faceI]
433  + lengthScaleRatio
434  *(
435  transformedPoints[pointI]
436  - faceCentres[faceI]
437  )
438  );
439 
440  ++ counts[pointI];
441 
442  pointDisplacement[pointI] += newPoint - oldPoints[pointI];
443  }
444  }
445  }
446 
447  // Average
448  average(facesToMove, counts, pointDisplacement);
449 }
450 
451 
453 Foam::pointSmoothers::geometricElementTransformPointSmoother::cellQuality
454 (
455  const polyMesh& mesh,
456  const pointField& currentPoints
457 )
458 {
459  const cellPointConnectivity& connectivity =
461  (
462  mesh
463  );
464 
466  scalarField& fld = tfld.ref();
467 
468  forAll(fld, celli)
469  {
470  fld[celli] = cellQuality(mesh, currentPoints, connectivity, celli);
471  }
472 
473  return tfld;
474 }
475 
476 
477 // ************************************************************************* //
List< ReturnType > get(const UPtrList< T > &list, const AccessOp &aop)
List of values generated by applying the access operation to each list item.
dictionary dict
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:114
Class calculates cell quality measures.
Definition: cellQuality.H:47
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
A list of keyword definitions, which are a keyword followed by a number of values (eg...
Definition: dictionary.H:129
Abstract base class for point smoothing methods. Handles parallel communication via reset and average...
Definition: pointSmoother.H:50
List< edge > edgeList
List of edge.
Definition: edgeList.H:32
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:40
dimensionedSymmTensor sqr(const dimensionedVector &dv)
static FOAM_NO_DANGLING_REFERENCE const Type & New(const Mesh &mesh, Args &&... args)
Get existing or create MeshObject registered with typeName.
const dimensionedScalar c2
Second radiation constant: default SI units: [m.K].
dimensionedScalar sqrt(const dimensionedScalar &ds)
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:529
const cellList & cells() const
dimensionedScalar det(const dimensionedSphericalTensor &dt)
dimensionedScalar sigma("sigma", dimMass/sqr(dimTime), transportProperties)
Macros for easy insertion into run-time selection tables.
geometricElementTransformPointSmoother(const polyMesh &mesh, const dictionary &dict)
Construct from a dictionary and a mesh.
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:286
dimensioned< Type > average(const DimensionedField< Type, GeoMesh > &f1, const label comm)
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:38
dynamicFvMesh & mesh
const cellShapeList & cells
virtual void calculate(const labelList &facesToMove, const pointField &oldPoints, const pointField &currentPoints, const pointField &faceCentres, const vectorField &faceAreas, const pointField &cellCentres, const scalarField &cellVolumes, vectorField &pointDisplacement) const
Calculate the point displacements.
const polyMesh & mesh() const noexcept
Access the mesh.
addToRunTimeSelectionTable(pointSmoother, equipotentialPointSmoother, dictionary)
label nPoints
const labelListListList & cellPointFaces() const
Access the point-face connections.
dimensionedScalar cbrt(const dimensionedScalar &ds)
This class provides ordered connectivity for each point of each cell. Lists are available of the poin...
Info<< "Finished reading KIVA file"<< endl;cellShapeList cellShapes(nPoints);labelList cellZoning(nPoints, -1);const cellModel &hex=cellModel::ref(cellModel::HEX);labelList hexLabels(8);label activeCells=0;labelList pointMap(nPoints);forAll(pointMap, i){ pointMap[i]=i;}for(label i=0;i< nPoints;i++){ if(f[i] > 0.0) { hexLabels[0]=i;hexLabels[1]=i1tab[i];hexLabels[2]=i3tab[i1tab[i]];hexLabels[3]=i3tab[i];hexLabels[4]=i8tab[i];hexLabels[5]=i1tab[i8tab[i]];hexLabels[6]=i3tab[i1tab[i8tab[i]]];hexLabels[7]=i3tab[i8tab[i]];cellShapes[activeCells].reset(hex, hexLabels);edgeList edges=cellShapes[activeCells].edges();forAll(edges, ei) { if(edges[ei].mag(points)< SMALL) { label start=pointMap[edges[ei].start()];while(start !=pointMap[start]) { start=pointMap[start];} label end=pointMap[edges[ei].end()];while(end !=pointMap[end]) { end=pointMap[end];} pointMap[start]=pointMap[end]=Foam::min(start, end);} } cellZoning[activeCells]=idreg[i];activeCells++;}}cellShapes.setSize(activeCells);cellZoning.setSize(activeCells);forAll(cellShapes, celli){ cellShape &cs=cellShapes[celli];forAll(cs, i) { cs[i]=pointMap[cs[i]];} cs.collapse();}label bcIDs[11]={-1, 0, 2, 4, -1, 5, -1, 6, 7, 8, 9};constexpr label nBCs=12;const word *kivaPatchTypes[nBCs]={ &wallPolyPatch::typeName, &wallPolyPatch::typeName, &wallPolyPatch::typeName, &wallPolyPatch::typeName, &symmetryPolyPatch::typeName, &wedgePolyPatch::typeName, &polyPatch::typeName, &polyPatch::typeName, &polyPatch::typeName, &polyPatch::typeName, &symmetryPolyPatch::typeName, &oldCyclicPolyPatch::typeName};enum patchTypeNames{ PISTON, VALVE, LINER, CYLINDERHEAD, AXIS, WEDGE, INFLOW, OUTFLOW, PRESIN, PRESOUT, SYMMETRYPLANE, CYCLIC};const char *kivaPatchNames[nBCs]={ "piston", "valve", "liner", "cylinderHead", "axis", "wedge", "inflow", "outflow", "presin", "presout", "symmetryPlane", "cyclic"};List< DynamicList< face > > pFaces[nBCs]
Definition: readKivaGrid.H:233
Vector< scalar > vector
Definition: vector.H:57
virtual const faceList & faces() const
Return raw faces.
Definition: polyMesh.C:1088
gmvFile<< "tracers "<< particles.size()<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().x()<< ' ';}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().y()<< ' ';}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().z()<< ' ';}gmvFile<< nl;for(const word &name :lagrangianScalarNames){ IOField< scalar > fld(IOobject(name, runTime.timeName(), cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
vector point
Point is a vector.
Definition: point.H:37
#define WarningInFunction
Report a warning using Foam::Warning.
limits reset(1/(limits.max()+VSMALL), 1/(limits.min()+VSMALL))
const dimensionedScalar c1
First radiation constant: default SI units: [W/m2].
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:75
List< label > labelList
A List of labels.
Definition: List.H:61
A class for managing temporary objects.
Definition: HashPtrTable.H:50
dimensioned< typename typeOfMag< Type >::type > magSqr(const dimensioned< Type > &dt)
defineTypeNameAndDebug(equipotentialPointSmoother, 0)
Namespace for OpenFOAM.
const labelListListList & cellPointPoints() const
Access the point-point connections.