edgeInterpolation.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) 2016-2017 Wikki Ltd
9  Copyright (C) 2020-2022 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
12  This file is part of OpenFOAM.
13 
14  OpenFOAM is free software: you can redistribute it and/or modify it
15  under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26 
27 \*---------------------------------------------------------------------------*/
28 
29 #include "faMesh.H"
30 #include "areaFields.H"
31 #include "edgeFields.H"
32 
33 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
34 
35 namespace Foam
36 {
38 }
39 
40 
41 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
42 
44 :
45  faMesh_(fam),
46  orthogonal_(false),
47  skew_(true)
48 {}
49 
50 
51 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
52 
54 {
55  if (!lPNptr_)
56  {
57  makeLPN();
58  }
59 
60  return (*lPNptr_);
61 }
62 
63 
65 {
66  if (!weightingFactorsPtr_)
67  {
68  makeWeights();
69  }
70 
71  return (*weightingFactorsPtr_);
72 }
73 
74 
76 {
77  if (!differenceFactorsPtr_)
78  {
79  makeDeltaCoeffs();
80  }
81 
82  return (*differenceFactorsPtr_);
83 }
84 
85 
87 {
88  if (orthogonal_ == false && !correctionVectorsPtr_)
89  {
90  makeCorrectionVectors();
91  }
92 
93  return orthogonal_;
94 }
95 
96 
98 {
99  if (orthogonal())
100  {
102  << "cannot return correctionVectors; mesh is orthogonal"
104  }
105 
106  return (*correctionVectorsPtr_);
107 }
108 
109 
111 {
112  if (skew_ == true && !skewCorrectionVectorsPtr_)
113  {
114  makeSkewCorrectionVectors();
115  }
116 
117  return skew_;
118 }
119 
120 
123 {
124  if (!skew())
125  {
127  << "cannot return skewCorrectionVectors; mesh is now skewed"
129  }
130 
131  return (*skewCorrectionVectorsPtr_);
132 }
133 
134 
136 {
137  lPNptr_.reset(nullptr);
138  weightingFactorsPtr_.reset(nullptr);
139  differenceFactorsPtr_.reset(nullptr);
140 
141  orthogonal_ = false;
142  correctionVectorsPtr_.reset(nullptr);
143 
144  skew_ = true;
145  skewCorrectionVectorsPtr_.reset(nullptr);
146 
147  return true;
148 }
149 
150 
151 const Foam::vector& Foam::edgeInterpolation::skewCorr(const label edgeI) const
152 {
153  #ifdef FA_SKEW_CORRECTION
154 
155  return
156  (
157  skewCorrectionVectorsPtr_
158  ? (*skewCorrectionVectorsPtr_)[edgeI]
159  : pTraits<vector>::zero
160  );
161 
162  #else
163 
164  return (*skewCorrectionVectorsPtr_)[edgeI];
165 
166  #endif
167 }
168 
169 
170 void Foam::edgeInterpolation::makeLPN() const
171 {
173  << "Constructing geodesic distance between points P and N"
174  << endl;
175 
176 
177  lPNptr_ = std::make_unique<edgeScalarField>
178  (
179  IOobject
180  (
181  "lPN",
182  mesh().time().constant(),
183  mesh().thisDb(),
187  ),
188  mesh(),
189  dimLength
190  );
191  edgeScalarField& lPN = *lPNptr_;
192 
193  // Set local references to mesh data
194  const edgeVectorField& edgeCentres = mesh().edgeCentres();
195  const areaVectorField& faceCentres = mesh().areaCentres();
196  const labelUList& owner = mesh().owner();
197  const labelUList& neighbour = mesh().neighbour();
198 
199  scalarField& lPNIn = lPN.primitiveFieldRef();
200 
201  // Calculate skewness correction vectors if necessary
202  (void) skew();
203 
204  forAll(owner, edgeI)
205  {
206  const vector& skewCorrEdge = skewCorr(edgeI);
207 
208  scalar lPE =
209  mag
210  (
211  edgeCentres[edgeI]
212  - skewCorrEdge
213  - faceCentres[owner[edgeI]]
214  );
215 
216  scalar lEN =
217  mag
218  (
219  faceCentres[neighbour[edgeI]]
220  - edgeCentres[edgeI]
221  + skewCorrEdge
222  );
223 
224  lPNIn[edgeI] = (lPE + lEN);
225 
226  // Do not allow any mag(val) < SMALL
227  if (mag(lPNIn[edgeI]) < SMALL)
228  {
229  lPNIn[edgeI] = SMALL;
230  }
231  }
232 
233 
234  forAll(lPN.boundaryField(), patchI)
235  {
236  mesh().boundary()[patchI].makeDeltaCoeffs
237  (
238  lPN.boundaryFieldRef()[patchI]
239  );
240 
241  lPN.boundaryFieldRef()[patchI] = 1.0/lPN.boundaryField()[patchI];
242  }
243 
244 
246  << "Finished constructing geodesic distance PN"
247  << endl;
248 }
249 
250 
251 void Foam::edgeInterpolation::makeWeights() const
252 {
254  << "Constructing weighting factors for edge interpolation"
255  << endl;
256 
257 
258  weightingFactorsPtr_ = std::make_unique<edgeScalarField>
259  (
260  IOobject
261  (
262  "weightingFactors",
263  mesh().pointsInstance(),
264  mesh().thisDb(),
268  ),
269  mesh(),
271  );
272  edgeScalarField& weightingFactors = *weightingFactorsPtr_;
273 
274 
275  // Set local references to mesh data
276  const edgeVectorField& edgeCentres = mesh().edgeCentres();
277  const areaVectorField& faceCentres = mesh().areaCentres();
278  const labelUList& owner = mesh().owner();
279  const labelUList& neighbour = mesh().neighbour();
280 
281  scalarField& weightingFactorsIn = weightingFactors.primitiveFieldRef();
282 
283  // Calculate skewness correction vectors if necessary
284  (void) skew();
285 
286  forAll(owner, edgeI)
287  {
288  const vector& skewCorrEdge = skewCorr(edgeI);
289 
290  scalar lPE =
291  mag
292  (
293  edgeCentres[edgeI]
294  - skewCorrEdge
295  - faceCentres[owner[edgeI]]
296  );
297 
298  scalar lEN =
299  mag
300  (
301  faceCentres[neighbour[edgeI]]
302  - edgeCentres[edgeI]
303  + skewCorrEdge
304  );
305 
306  // weight = (0,1]
307  const scalar lPN = lPE + lEN;
308  if (mag(lPN) > SMALL)
309  {
310  weightingFactorsIn[edgeI] = lEN/lPN;
311  }
312  }
313 
314  forAll(mesh().boundary(), patchI)
315  {
316  mesh().boundary()[patchI].makeWeights
317  (
318  weightingFactors.boundaryFieldRef()[patchI]
319  );
320  }
321 
323  << "Finished constructing weighting factors for face interpolation"
324  << endl;
325 }
326 
327 
328 void Foam::edgeInterpolation::makeDeltaCoeffs() const
329 {
331  << "Constructing differencing factors array for edge gradient"
332  << endl;
333 
334  // Force the construction of the weighting factors
335  // needed to make sure deltaCoeffs are calculated for parallel runs.
336  weights();
337 
338  differenceFactorsPtr_ = std::make_unique<edgeScalarField>
339  (
340  IOobject
341  (
342  "differenceFactors",
343  mesh().pointsInstance(),
344  mesh().thisDb(),
348  ),
349  mesh(),
351  );
352  edgeScalarField& DeltaCoeffs = *differenceFactorsPtr_;
353  scalarField& dc = DeltaCoeffs.primitiveFieldRef();
354 
355  // Set local references to mesh data
356  const edgeVectorField& edgeCentres = mesh().edgeCentres();
357  const areaVectorField& faceCentres = mesh().areaCentres();
358  const labelUList& owner = mesh().owner();
359  const labelUList& neighbour = mesh().neighbour();
360  const edgeVectorField& lengths = mesh().Le();
361 
362  const edgeList& edges = mesh().edges();
363  const pointField& points = mesh().points();
364 
365  // Calculate skewness correction vectors if necessary
366  (void) skew();
367 
368  forAll(owner, edgeI)
369  {
370  // Edge normal - area normal
371  vector edgeNormal =
372  normalised(lengths[edgeI] ^ edges[edgeI].vec(points));
373 
374  // Unit delta vector
375  vector unitDelta =
376  faceCentres[neighbour[edgeI]]
377  - faceCentres[owner[edgeI]];
378 
379  unitDelta.removeCollinear(edgeNormal);
380  unitDelta.normalise();
381 
382 
383  const vector& skewCorrEdge = skewCorr(edgeI);
384 
385  scalar lPE =
386  mag
387  (
388  edgeCentres[edgeI]
389  - skewCorrEdge
390  - faceCentres[owner[edgeI]]
391  );
392 
393  scalar lEN =
394  mag
395  (
396  faceCentres[neighbour[edgeI]]
397  - edgeCentres[edgeI]
398  + skewCorrEdge
399  );
400 
401  scalar lPN = lPE + lEN;
402 
403 
404  // Edge normal - area tangent
405  edgeNormal = normalised(lengths[edgeI]);
406 
407  // Do not allow any mag(val) < SMALL
408  const scalar alpha = lPN*(unitDelta & edgeNormal);
409  if (mag(alpha) > SMALL)
410  {
411  dc[edgeI] = scalar(1)/max(alpha, 0.05*lPN);
412  }
413  }
414 
415 
416  forAll(DeltaCoeffs.boundaryField(), patchI)
417  {
418  mesh().boundary()[patchI].makeDeltaCoeffs
419  (
420  DeltaCoeffs.boundaryFieldRef()[patchI]
421  );
422  }
423 }
424 
425 
426 void Foam::edgeInterpolation::makeCorrectionVectors() const
427 {
429  << "Constructing non-orthogonal correction vectors"
430  << endl;
431 
432  correctionVectorsPtr_ = std::make_unique<edgeVectorField>
433  (
434  IOobject
435  (
436  "correctionVectors",
437  mesh().pointsInstance(),
438  mesh().thisDb(),
442  ),
443  mesh(),
444  dimless
445  );
446  edgeVectorField& CorrVecs = *correctionVectorsPtr_;
447 
448  // Set local references to mesh data
449  const areaVectorField& faceCentres = mesh().areaCentres();
450 
451  const labelUList& owner = mesh().owner();
452  const labelUList& neighbour = mesh().neighbour();
453 
454  const edgeVectorField& lengths = mesh().Le();
455 
456  const edgeList& edges = mesh().edges();
457  const pointField& points = mesh().points();
458 
459  scalarField deltaCoeffs(owner.size(), SMALL);
460 
461  vectorField& CorrVecsIn = CorrVecs.primitiveFieldRef();
462 
463  forAll(owner, edgeI)
464  {
465  // Edge normal - area normal
466  vector edgeNormal =
467  normalised(lengths[edgeI] ^ edges[edgeI].vec(points));
468 
469  // Unit delta vector
470  vector unitDelta =
471  faceCentres[neighbour[edgeI]]
472  - faceCentres[owner[edgeI]];
473 
474  unitDelta.removeCollinear(edgeNormal);
475  unitDelta.normalise();
476 
477  // Edge normal - area tangent
478  edgeNormal = normalised(lengths[edgeI]);
479 
480  // Do not allow any mag(val) < SMALL
481  const scalar alpha = unitDelta & edgeNormal;
482  if (mag(alpha) > SMALL)
483  {
484  deltaCoeffs[edgeI] = scalar(1)/alpha;
485  }
486 
487  // Edge correction vector
488  CorrVecsIn[edgeI] =
489  edgeNormal
490  - deltaCoeffs[edgeI]*unitDelta;
491  }
492 
493 
494  edgeVectorField::Boundary& CorrVecsbf = CorrVecs.boundaryFieldRef();
495 
496  forAll(CorrVecs.boundaryField(), patchI)
497  {
498  mesh().boundary()[patchI].makeCorrectionVectors(CorrVecsbf[patchI]);
499  }
500 
501  scalar NonOrthogCoeff = 0.0;
502 
503  if (owner.size() > 0)
504  {
505  scalarField sinAlpha(deltaCoeffs*mag(CorrVecs.internalField()));
506  sinAlpha.clamp_range(-1, 1);
507 
508  NonOrthogCoeff = max(Foam::asin(sinAlpha)*180.0/M_PI);
509  }
510 
511  reduce(NonOrthogCoeff, maxOp<scalar>());
512 
514  << "non-orthogonality coefficient = " << NonOrthogCoeff << " deg."
515  << endl;
516 
517  if (NonOrthogCoeff < 0.1)
518  {
519  orthogonal_ = true;
520  correctionVectorsPtr_.reset(nullptr);
521  }
522  else
523  {
524  orthogonal_ = false;
525  }
526 
528  << "Finished constructing non-orthogonal correction vectors"
529  << endl;
530 }
531 
532 
533 void Foam::edgeInterpolation::makeSkewCorrectionVectors() const
534 {
536  << "Constructing skew correction vectors"
537  << endl;
538 
539  skewCorrectionVectorsPtr_ = std::make_unique<edgeVectorField>
540  (
541  IOobject
542  (
543  "skewCorrectionVectors",
544  mesh().pointsInstance(),
545  mesh().thisDb(),
549  ),
550  mesh(),
552  );
553  edgeVectorField& SkewCorrVecs = *skewCorrectionVectorsPtr_;
554 
555  // Set local references to mesh data
556  const areaVectorField& C = mesh().areaCentres();
557  const edgeVectorField& Ce = mesh().edgeCentres();
558 
559  const labelUList& owner = mesh().owner();
560  const labelUList& neighbour = mesh().neighbour();
561 
562  const pointField& points = mesh().points();
563  const edgeList& edges = mesh().edges();
564 
565 
566  forAll(neighbour, edgeI)
567  {
568  const vector& P = C[owner[edgeI]];
569  const vector& N = C[neighbour[edgeI]];
570  const vector& S = points[edges[edgeI].start()];
571 
572  // (T:Eq. 5.4)
573  const vector d(N - P);
574  const vector e(edges[edgeI].vec(points));
575  const vector de(d^e);
576  const scalar alpha = magSqr(de);
577 
578  if (alpha < SMALL)
579  {
580  // Too small - skew correction remains zero
581  continue;
582  }
583  const scalar beta = -((d^(S - P)) & de)/alpha;
584 
585  // (T:Eq. 5.3)
586  const vector E(S + beta*e);
587 
588  SkewCorrVecs[edgeI] = Ce[edgeI] - E;
589  }
590 
591 
592  edgeVectorField::Boundary& bSkewCorrVecs =
593  SkewCorrVecs.boundaryFieldRef();
594 
595  forAll(SkewCorrVecs.boundaryField(), patchI)
596  {
597  faePatchVectorField& patchSkewCorrVecs = bSkewCorrVecs[patchI];
598 
599  if (patchSkewCorrVecs.coupled())
600  {
601  const labelUList& edgeFaces =
602  mesh().boundary()[patchI].edgeFaces();
603 
604  const edgeList::subList patchEdges =
605  mesh().boundary()[patchI].patchSlice(edges);
606 
607  vectorField ngbC(C.boundaryField()[patchI].patchNeighbourField());
608 
609  forAll(patchSkewCorrVecs, edgeI)
610  {
611  const vector& P = C[edgeFaces[edgeI]];
612  const vector& N = ngbC[edgeI];
613  const vector& S = points[patchEdges[edgeI].start()];
614 
615  // (T:Eq. 5.4)
616  const vector d(N - P);
617  const vector e(patchEdges[edgeI].vec(points));
618  const vector de(d^e);
619  const scalar alpha = magSqr(de);
620 
621  if (alpha < SMALL)
622  {
623  // Too small - skew correction remains zero
624  continue;
625  }
626  const scalar beta = -((d^(S - P)) & de)/alpha;
627 
628  const vector E(S + beta*e);
629 
630  patchSkewCorrVecs[edgeI] =
631  Ce.boundaryField()[patchI][edgeI] - E;
632  }
633  }
634  }
635 
636  #ifdef FA_SKEW_CORRECTION
637 
638  constexpr scalar maxSkewRatio = 0.1;
639  scalar skewCoeff = 0;
640 
641  forAll(own, edgeI)
642  {
643  const scalar magSkew = mag(skewCorrVecs[edgeI]);
644 
645  const scalar lPN =
646  mag
647  (
648  Ce[edgeI]
649  - skewCorrVecs[edgeI]
650  - C[owner[edgeI]]
651  )
652  + mag
653  (
654  C[neighbour[edgeI]]
655  - Ce[edgeI]
656  + skewCorrVecs[edgeI]
657  );
658 
659  const scalar ratio = magSkew/lPN;
660 
661  if (skewCoeff < ratio)
662  {
663  skewCoeff = ratio;
664 
665  if (skewCoeff > maxSkewRatio)
666  {
667  break;
668  }
669  }
670  }
671 
673  << "skew coefficient = " << skewCoeff << endl;
674 
675  if (skewCoeff < maxSkewRatio)
676  {
677  skewCorrectionVectorsPtr_.reset(nullptr);
678  }
679 
680  #endif
681 
682  skew_ = bool(skewCorrectionVectorsPtr_);
683 
684 
686  << "Finished constructing skew correction vectors"
687  << endl;
688 }
689 
690 
691 // ************************************************************************* //
Finite area mesh (used for 2-D non-Euclidian finite area method) defined using a patch of faces on a ...
Definition: faMesh.H:133
faceListList boundary
const edgeVectorField & skewCorrectionVectors() const
Return reference to skew vectors array.
const edgeScalarField & weights() const
Return reference to weighting factors array.
const edgeScalarField & deltaCoeffs() const
Return reference to difference factors array.
const edgeVectorField & correctionVectors() const
Return reference to non-orthogonality correction vectors array.
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:608
List< edge > edgeList
List of edge.
Definition: edgeList.H:32
dimensionedTensor skew(const dimensionedTensor &dt)
edgeInterpolation(const edgeInterpolation &)=delete
No copy construct.
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:40
dimensioned< vector > dimensionedVector
Dimensioned vector obtained from generic dimensioned type.
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:531
Face to edge interpolation scheme. Included in faMesh.
Vector< Cmpt > & normalise(const scalar tol=ROOTVSMALL)
Inplace normalise the vector by its magnitude.
Definition: VectorI.H:114
GeometricBoundaryField< Type, PatchField, GeoMesh > Boundary
Type of boundary fields.
SubList< edge > subList
Declare type of subList.
Definition: List.H:144
Ignore writing from objectRegistry::writeObject()
quaternion normalised(const quaternion &q)
Return the normalised (unit) quaternion of the given quaternion.
Definition: quaternionI.H:674
const dimensionSet dimless
Dimensionless.
bool movePoints() const
Do what is necessary if the mesh has moved.
const edgeScalarField & lPN() const
Return reference to PN geodesic distance.
dimensionedScalar asin(const dimensionedScalar &ds)
UList< label > labelUList
A UList of labels.
Definition: UList.H:78
const labelUList & neighbour() const
Internal face neighbour.
Definition: fvMesh.H:580
virtual const pointField & points() const
Return raw points.
Definition: polyMesh.C:1078
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:421
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:38
const dimensionedScalar e
Elementary charge.
Definition: createFields.H:11
dynamicFvMesh & mesh
const pointField & points
Info<< nl<< "Wrote faMesh in vtk format: "<< writer.output().name()<< nl;}{ const Field< vector > edgeCentres(faMeshTools::flattenEdgeField(aMesh.edgeCentres(), true))
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
#define DebugInFunction
Report an information message using Foam::Info.
GeometricField< vector, faePatchField, edgeMesh > edgeVectorField
Definition: edgeFieldsFwd.H:60
bool orthogonal() const
Return whether mesh is orthogonal or not.
Vector< scalar > vector
Definition: vector.H:57
GeometricField< scalar, faePatchField, edgeMesh > edgeScalarField
Definition: edgeFieldsFwd.H:43
errorManip< error > abort(error &err)
Definition: errorManip.H:139
A Vector of values with scalar precision, where scalar is float/double depending on the compilation f...
defineTypeNameAndDebug(combustionModel, 0)
volScalarField & C
bool skew() const
Return whether mesh is skew or not.
const Vector< label > N(dict.get< Vector< label >>("N"))
const labelUList & owner() const
Internal face owner. Note bypassing virtual mechanism so.
Definition: fvMesh.H:572
const edgeList & edges() const
Return mesh edges. Uses calcEdges.
const dimensionSet dimLength(0, 1, 0, 0, 0, 0, 0)
Definition: dimensionSets.H:50
dimensioned< scalar > dimensionedScalar
Dimensioned scalar obtained from generic dimensioned type.
Nothing to be read.
faePatchField< vector > faePatchVectorField
const fvBoundaryMesh & boundary() const noexcept
Return reference to boundary mesh.
Definition: fvMesh.H:395
dimensionedScalar beta("beta", dimless/dimTemperature, laminarTransport)
Field< vector > vectorField
Specialisation of Field<T> for vector.
const dimensionedScalar alpha
Fine-structure constant: default SI units: [].
Vector< Cmpt > & removeCollinear(const Vector< Cmpt > &unitVec)
Inplace removal of components that are collinear to the given unit vector.
Definition: VectorI.H:136
Calculate the matrix for the second temporal derivative.
GeometricField< vector, faPatchField, areaMesh > areaVectorField
Definition: areaFieldsFwd.H:76
const Boundary & boundaryField() const noexcept
Return const-reference to the boundary field.
Do not request registration (bool: false)
void reduce(T &value, const BinaryOp &bop, const int tag=UPstream::msgType(), const label comm=UPstream::worldComm)
Reduce inplace (cf. MPI Allreduce) using linear/tree communication schedule.
dimensioned< typename typeOfMag< Type >::type > magSqr(const dimensioned< Type > &dt)
Namespace for OpenFOAM.
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:127