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 #include "demandDrivenData.H"
33 #include "faPatchFields.H"
34 
35 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
36 
37 namespace Foam
38 {
40 }
41 
42 // * * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * //
43 
45 {
47  deleteDemandDrivenData(weightingFactors_);
48  deleteDemandDrivenData(differenceFactors_);
49  deleteDemandDrivenData(correctionVectors_);
50  deleteDemandDrivenData(skewCorrectionVectors_);
51 }
52 
53 
54 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
55 
57 :
58  faMesh_(fam),
59  lPN_(nullptr),
60  weightingFactors_(nullptr),
61  differenceFactors_(nullptr),
62  correctionVectors_(nullptr),
63  skewCorrectionVectors_(nullptr),
64  orthogonal_(false),
65  skew_(true)
66 {}
67 
68 
69 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
70 
72 {
73  clearOut();
74 }
75 
76 
77 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
78 
80 {
81  if (!lPN_)
82  {
83  makeLPN();
84  }
85 
86  return (*lPN_);
87 }
88 
89 
91 {
92  if (!weightingFactors_)
93  {
94  makeWeights();
95  }
96 
97  return (*weightingFactors_);
98 }
99 
100 
102 {
103  if (!differenceFactors_)
104  {
105  makeDeltaCoeffs();
106  }
107 
108  return (*differenceFactors_);
109 }
110 
111 
113 {
114  if (orthogonal_ == false && !correctionVectors_)
115  {
116  makeCorrectionVectors();
117  }
118 
119  return orthogonal_;
120 }
121 
122 
124 {
125  if (orthogonal())
126  {
128  << "cannot return correctionVectors; mesh is orthogonal"
130  }
131 
132  return (*correctionVectors_);
133 }
134 
135 
137 {
138  if (skew_ == true && !skewCorrectionVectors_)
139  {
140  makeSkewCorrectionVectors();
141  }
142 
143  return skew_;
144 }
145 
146 
149 {
150  if (!skew())
151  {
153  << "cannot return skewCorrectionVectors; mesh is now skewed"
155  }
156 
157  return (*skewCorrectionVectors_);
158 }
159 
160 
162 {
164  deleteDemandDrivenData(weightingFactors_);
165  deleteDemandDrivenData(differenceFactors_);
166 
167  orthogonal_ = false;
168  deleteDemandDrivenData(correctionVectors_);
169 
170  skew_ = true;
171  deleteDemandDrivenData(skewCorrectionVectors_);
172 
173  return true;
174 }
175 
176 
177 const Foam::vector& Foam::edgeInterpolation::skewCorr(const label edgeI) const
178 {
179  #ifdef FA_SKEW_CORRECTION
180 
181  return
182  (
183  skewCorrectionVectors_
184  ? (*skewCorrectionVectors_)[edgeI]
185  : pTraits<vector>::zero
186  );
187 
188  #else
189 
190  return (*skewCorrectionVectors_)[edgeI];
191 
192  #endif
193 }
194 
195 
196 void Foam::edgeInterpolation::makeLPN() const
197 {
199  << "Constructing geodesic distance between points P and N"
200  << endl;
201 
202 
203  lPN_ = new edgeScalarField
204  (
205  IOobject
206  (
207  "lPN",
208  faMesh_.time().constant(),
209  faMesh_(),
212  false
213  ),
214  mesh(),
215  dimLength
216  );
217  edgeScalarField& lPN = *lPN_;
218 
219  // Set local references to mesh data
220  const edgeVectorField& edgeCentres = mesh().edgeCentres();
221  const areaVectorField& faceCentres = mesh().areaCentres();
222  const labelUList& owner = mesh().owner();
223  const labelUList& neighbour = mesh().neighbour();
224 
225  scalarField& lPNIn = lPN.primitiveFieldRef();
226 
227  // Calculate skewness correction vectors if necessary
228  (void) skew();
229 
230  forAll(owner, edgeI)
231  {
232  const vector& skewCorrEdge = skewCorr(edgeI);
233 
234  scalar lPE =
235  mag
236  (
237  edgeCentres[edgeI]
238  - skewCorrEdge
239  - faceCentres[owner[edgeI]]
240  );
241 
242  scalar lEN =
243  mag
244  (
245  faceCentres[neighbour[edgeI]]
246  - edgeCentres[edgeI]
247  + skewCorrEdge
248  );
249 
250  lPNIn[edgeI] = (lPE + lEN);
251 
252  // Do not allow any mag(val) < SMALL
253  if (mag(lPNIn[edgeI]) < SMALL)
254  {
255  lPNIn[edgeI] = SMALL;
256  }
257  }
258 
259 
260  forAll(lPN.boundaryField(), patchI)
261  {
262  mesh().boundary()[patchI].makeDeltaCoeffs
263  (
264  lPN.boundaryFieldRef()[patchI]
265  );
266 
267  lPN.boundaryFieldRef()[patchI] = 1.0/lPN.boundaryField()[patchI];
268  }
269 
270 
272  << "Finished constructing geodesic distance PN"
273  << endl;
274 }
275 
276 
277 void Foam::edgeInterpolation::makeWeights() const
278 {
280  << "Constructing weighting factors for edge interpolation"
281  << endl;
282 
283 
284  weightingFactors_ = new edgeScalarField
285  (
286  IOobject
287  (
288  "weightingFactors",
289  mesh()().pointsInstance(),
290  mesh()(),
293  false
294  ),
295  mesh(),
297  );
298  edgeScalarField& weightingFactors = *weightingFactors_;
299 
300 
301  // Set local references to mesh data
302  const edgeVectorField& edgeCentres = mesh().edgeCentres();
303  const areaVectorField& faceCentres = mesh().areaCentres();
304  const labelUList& owner = mesh().owner();
305  const labelUList& neighbour = mesh().neighbour();
306 
307  scalarField& weightingFactorsIn = weightingFactors.primitiveFieldRef();
308 
309  // Calculate skewness correction vectors if necessary
310  (void) skew();
311 
312  forAll(owner, edgeI)
313  {
314  const vector& skewCorrEdge = skewCorr(edgeI);
315 
316  scalar lPE =
317  mag
318  (
319  edgeCentres[edgeI]
320  - skewCorrEdge
321  - faceCentres[owner[edgeI]]
322  );
323 
324  scalar lEN =
325  mag
326  (
327  faceCentres[neighbour[edgeI]]
328  - edgeCentres[edgeI]
329  + skewCorrEdge
330  );
331 
332  // weight = (0,1]
333  const scalar lPN = lPE + lEN;
334  if (mag(lPN) > SMALL)
335  {
336  weightingFactorsIn[edgeI] = lEN/lPN;
337  }
338  }
339 
340  forAll(mesh().boundary(), patchI)
341  {
342  mesh().boundary()[patchI].makeWeights
343  (
344  weightingFactors.boundaryFieldRef()[patchI]
345  );
346  }
347 
349  << "Finished constructing weighting factors for face interpolation"
350  << endl;
351 }
352 
353 
354 void Foam::edgeInterpolation::makeDeltaCoeffs() const
355 {
357  << "Constructing differencing factors array for edge gradient"
358  << endl;
359 
360  // Force the construction of the weighting factors
361  // needed to make sure deltaCoeffs are calculated for parallel runs.
362  weights();
363 
364  differenceFactors_ = new edgeScalarField
365  (
366  IOobject
367  (
368  "differenceFactors_",
369  mesh()().pointsInstance(),
370  mesh()(),
373  false
374  ),
375  mesh(),
377  );
378  edgeScalarField& DeltaCoeffs = *differenceFactors_;
379  scalarField& dc = DeltaCoeffs.primitiveFieldRef();
380 
381  // Set local references to mesh data
382  const edgeVectorField& edgeCentres = mesh().edgeCentres();
383  const areaVectorField& faceCentres = mesh().areaCentres();
384  const labelUList& owner = mesh().owner();
385  const labelUList& neighbour = mesh().neighbour();
386  const edgeVectorField& lengths = mesh().Le();
387 
388  const edgeList& edges = mesh().edges();
389  const pointField& points = mesh().points();
390 
391  // Calculate skewness correction vectors if necessary
392  (void) skew();
393 
394  forAll(owner, edgeI)
395  {
396  // Edge normal - area normal
397  vector edgeNormal =
398  normalised(lengths[edgeI] ^ edges[edgeI].vec(points));
399 
400  // Unit delta vector
401  vector unitDelta =
402  faceCentres[neighbour[edgeI]]
403  - faceCentres[owner[edgeI]];
404 
405  unitDelta.removeCollinear(edgeNormal);
406  unitDelta.normalise();
407 
408 
409  const vector& skewCorrEdge = skewCorr(edgeI);
410 
411  scalar lPE =
412  mag
413  (
414  edgeCentres[edgeI]
415  - skewCorrEdge
416  - faceCentres[owner[edgeI]]
417  );
418 
419  scalar lEN =
420  mag
421  (
422  faceCentres[neighbour[edgeI]]
423  - edgeCentres[edgeI]
424  + skewCorrEdge
425  );
426 
427  scalar lPN = lPE + lEN;
428 
429 
430  // Edge normal - area tangent
431  edgeNormal = normalised(lengths[edgeI]);
432 
433  // Do not allow any mag(val) < SMALL
434  const scalar alpha = lPN*(unitDelta & edgeNormal);
435  if (mag(alpha) > SMALL)
436  {
437  dc[edgeI] = scalar(1)/max(alpha, 0.05*lPN);
438  }
439  }
440 
441 
442  forAll(DeltaCoeffs.boundaryField(), patchI)
443  {
444  mesh().boundary()[patchI].makeDeltaCoeffs
445  (
446  DeltaCoeffs.boundaryFieldRef()[patchI]
447  );
448  }
449 }
450 
451 
452 void Foam::edgeInterpolation::makeCorrectionVectors() const
453 {
455  << "Constructing non-orthogonal correction vectors"
456  << endl;
457 
458  correctionVectors_ = new edgeVectorField
459  (
460  IOobject
461  (
462  "correctionVectors",
463  mesh()().pointsInstance(),
464  mesh()(),
467  false
468  ),
469  mesh(),
470  dimless
471  );
472  edgeVectorField& CorrVecs = *correctionVectors_;
473 
474  // Set local references to mesh data
475  const areaVectorField& faceCentres = mesh().areaCentres();
476 
477  const labelUList& owner = mesh().owner();
478  const labelUList& neighbour = mesh().neighbour();
479 
480  const edgeVectorField& lengths = mesh().Le();
481 
482  const edgeList& edges = mesh().edges();
483  const pointField& points = mesh().points();
484 
485  scalarField deltaCoeffs(owner.size(), SMALL);
486 
487  vectorField& CorrVecsIn = CorrVecs.primitiveFieldRef();
488 
489  forAll(owner, edgeI)
490  {
491  // Edge normal - area normal
492  vector edgeNormal =
493  normalised(lengths[edgeI] ^ edges[edgeI].vec(points));
494 
495  // Unit delta vector
496  vector unitDelta =
497  faceCentres[neighbour[edgeI]]
498  - faceCentres[owner[edgeI]];
499 
500  unitDelta.removeCollinear(edgeNormal);
501  unitDelta.normalise();
502 
503  // Edge normal - area tangent
504  edgeNormal = normalised(lengths[edgeI]);
505 
506  // Do not allow any mag(val) < SMALL
507  const scalar alpha = unitDelta & edgeNormal;
508  if (mag(alpha) > SMALL)
509  {
510  deltaCoeffs[edgeI] = scalar(1)/alpha;
511  }
512 
513  // Edge correction vector
514  CorrVecsIn[edgeI] =
515  edgeNormal
516  - deltaCoeffs[edgeI]*unitDelta;
517  }
518 
519 
520  edgeVectorField::Boundary& CorrVecsbf = CorrVecs.boundaryFieldRef();
521 
522  forAll(CorrVecs.boundaryField(), patchI)
523  {
524  mesh().boundary()[patchI].makeCorrectionVectors(CorrVecsbf[patchI]);
525  }
526 
527  scalar NonOrthogCoeff = 0.0;
528 
529  if (owner.size() > 0)
530  {
531  scalarField sinAlpha(deltaCoeffs*mag(CorrVecs.internalField()));
532 
533  forAll(sinAlpha, edgeI)
534  {
535  sinAlpha[edgeI] = max(-1, min(sinAlpha[edgeI], 1));
536  }
537 
538  NonOrthogCoeff = max(Foam::asin(sinAlpha)*180.0/M_PI);
539  }
540 
541  reduce(NonOrthogCoeff, maxOp<scalar>());
542 
544  << "non-orthogonality coefficient = " << NonOrthogCoeff << " deg."
545  << endl;
546 
547  if (NonOrthogCoeff < 0.1)
548  {
549  orthogonal_ = true;
550  deleteDemandDrivenData(correctionVectors_);
551  }
552  else
553  {
554  orthogonal_ = false;
555  }
556 
558  << "Finished constructing non-orthogonal correction vectors"
559  << endl;
560 }
561 
562 
563 void Foam::edgeInterpolation::makeSkewCorrectionVectors() const
564 {
566  << "Constructing skew correction vectors"
567  << endl;
568 
569  skewCorrectionVectors_ = new edgeVectorField
570  (
571  IOobject
572  (
573  "skewCorrectionVectors",
574  mesh()().pointsInstance(),
575  mesh()(),
578  false
579  ),
580  mesh(),
582  );
583  edgeVectorField& SkewCorrVecs = *skewCorrectionVectors_;
584 
585  // Set local references to mesh data
586  const areaVectorField& C = mesh().areaCentres();
587  const edgeVectorField& Ce = mesh().edgeCentres();
588 
589  const labelUList& owner = mesh().owner();
590  const labelUList& neighbour = mesh().neighbour();
591 
592  const pointField& points = mesh().points();
593  const edgeList& edges = mesh().edges();
594 
595 
596  forAll(neighbour, edgeI)
597  {
598  const vector& P = C[owner[edgeI]];
599  const vector& N = C[neighbour[edgeI]];
600  const vector& S = points[edges[edgeI].start()];
601 
602  // (T:Eq. 5.4)
603  const vector d(N - P);
604  const vector e(edges[edgeI].vec(points));
605  const vector de(d^e);
606  const scalar alpha = magSqr(de);
607 
608  if (alpha < SMALL)
609  {
610  // Too small - skew correction remains zero
611  continue;
612  }
613  const scalar beta = -((d^(S - P)) & de)/alpha;
614 
615  // (T:Eq. 5.3)
616  const vector E(S + beta*e);
617 
618  SkewCorrVecs[edgeI] = Ce[edgeI] - E;
619  }
620 
621 
622  edgeVectorField::Boundary& bSkewCorrVecs =
623  SkewCorrVecs.boundaryFieldRef();
624 
625  forAll(SkewCorrVecs.boundaryField(), patchI)
626  {
627  faePatchVectorField& patchSkewCorrVecs = bSkewCorrVecs[patchI];
628 
629  if (patchSkewCorrVecs.coupled())
630  {
631  const labelUList& edgeFaces =
632  mesh().boundary()[patchI].edgeFaces();
633 
634  const edgeList::subList patchEdges =
635  mesh().boundary()[patchI].patchSlice(edges);
636 
637  vectorField ngbC(C.boundaryField()[patchI].patchNeighbourField());
638 
639  forAll(patchSkewCorrVecs, edgeI)
640  {
641  const vector& P = C[edgeFaces[edgeI]];
642  const vector& N = ngbC[edgeI];
643  const vector& S = points[patchEdges[edgeI].start()];
644 
645  // (T:Eq. 5.4)
646  const vector d(N - P);
647  const vector e(patchEdges[edgeI].vec(points));
648  const vector de(d^e);
649  const scalar alpha = magSqr(de);
650 
651  if (alpha < SMALL)
652  {
653  // Too small - skew correction remains zero
654  continue;
655  }
656  const scalar beta = -((d^(S - P)) & de)/alpha;
657 
658  const vector E(S + beta*e);
659 
660  patchSkewCorrVecs[edgeI] =
661  Ce.boundaryField()[patchI][edgeI] - E;
662  }
663  }
664  }
665 
666  #ifdef FA_SKEW_CORRECTION
667 
668  constexpr scalar maxSkewRatio = 0.1;
669  scalar skewCoeff = 0;
670 
671  forAll(own, edgeI)
672  {
673  const scalar magSkew = mag(skewCorrVecs[edgeI]);
674 
675  const scalar lPN =
676  mag
677  (
678  Ce[edgeI]
679  - skewCorrVecs[edgeI]
680  - C[owner[edgeI]]
681  )
682  + mag
683  (
684  C[neighbour[edgeI]]
685  - Ce[edgeI]
686  + skewCorrVecs[edgeI]
687  );
688 
689  const scalar ratio = magSkew/lPN;
690 
691  if (skewCoeff < ratio)
692  {
693  skewCoeff = ratio;
694 
695  if (skewCoeff > maxSkewRatio)
696  {
697  break;
698  }
699  }
700  }
701 
703  << "skew coefficient = " << skewCoeff << endl;
704 
705  if (skewCoeff < maxSkewRatio)
706  {
707  deleteDemandDrivenData(skewCorrectionVectors_);
708  }
709 
710  #endif
711 
712  skew_ = bool(skewCorrectionVectors_);
713 
714 
716  << "Finished constructing skew correction vectors"
717  << endl;
718 }
719 
720 
721 // ************************************************************************* //
Finite area mesh (used for 2-D non-Euclidian finite area method) defined using a patch of faces on a ...
Definition: faMesh.H:88
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:578
dimensionedTensor skew(const dimensionedTensor &dt)
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:487
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:122
Ignore writing from objectRegistry::writeObject()
quaternion normalised(const quaternion &q)
Return the normalised (unit) quaternion of the given quaternion.
Definition: quaternionI.H:673
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:80
const labelUList & neighbour() const
Internal face neighbour.
Definition: fvMesh.H:545
virtual const pointField & points() const
Return raw points.
Definition: polyMesh.C:1066
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:413
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:38
const dimensionedScalar e
Elementary charge.
Definition: createFields.H:11
dynamicFvMesh & mesh
const pointField & points
List< edge > edgeList
A List of edges.
Definition: edgeList.H:60
void clearOut()
Clear all geometry and addressing.
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:58
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:46
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:26
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
~edgeInterpolation()
Destructor.
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:537
const edgeList & edges() const
Return mesh edges. Uses calcEdges.
Template functions to aid in the implementation of demand driven data.
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.
void reduce(const List< UPstream::commsStruct > &comms, T &value, const BinaryOp &bop, const int tag, const label comm)
Reduce inplace (cf. MPI Allreduce) using specified communication schedule.
faePatchField< vector > faePatchVectorField
dimensionedScalar beta("beta", dimless/dimTemperature, laminarTransport)
Field< vector > vectorField
Specialisation of Field<T> for vector.
edgeInterpolation(const faMesh &)
Construct given an faMesh.
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:133
void deleteDemandDrivenData(DataPtr &dataPtr)
Calculate the matrix for the second temporal derivative.
GeometricField< vector, faPatchField, areaMesh > areaVectorField
Definition: areaFieldsFwd.H:81
const Boundary & boundaryField() const noexcept
Return const-reference to the boundary field.
dimensioned< typename typeOfMag< Type >::type > magSqr(const dimensioned< Type > &dt)
Namespace for OpenFOAM.
const fvBoundaryMesh & boundary() const
Return reference to boundary mesh.
Definition: fvMesh.C:705
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:157