FitData.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) 2011-2016 OpenFOAM Foundation
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 
28 #include "FitData.H"
29 #include "surfaceFields.H"
30 #include "volFields.H"
31 #include "SVD.H"
32 
33 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
34 
35 template<class Form, class ExtendedStencil, class Polynomial>
37 (
38  const fvMesh& mesh,
39  const ExtendedStencil& stencil,
40  const bool linearCorrection,
41  const scalar linearLimitFactor,
42  const scalar centralWeight
43 )
44 :
46  stencil_(stencil),
47  linearCorrection_(linearCorrection),
48  linearLimitFactor_(linearLimitFactor),
49  centralWeight_(centralWeight),
50  #ifdef SPHERICAL_GEOMETRY
51  dim_(2),
52  #else
53  dim_(mesh.nGeometricD()),
54  #endif
55  minSize_(Polynomial::nTerms(dim_))
56 {
57  // Check input
58  if (linearLimitFactor <= SMALL || linearLimitFactor > 3)
59  {
61  << "linearLimitFactor requested = " << linearLimitFactor
62  << " should be between zero and 3"
63  << exit(FatalError);
64  }
65 }
66 
67 
68 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
69 
70 template<class FitDataType, class ExtendedStencil, class Polynomial>
72 (
73  vector& idir, // value changed in return
74  vector& jdir, // value changed in return
75  vector& kdir, // value changed in return
76  const label facei
77 )
78 {
79  const fvMesh& mesh = this->mesh();
80 
81  idir = normalised(mesh.faceAreas()[facei]);
82 
83  #ifndef SPHERICAL_GEOMETRY
84  if (mesh.nGeometricD() <= 2) // find the normal direction
85  {
86  if (mesh.geometricD()[0] == -1)
87  {
88  kdir = vector(1, 0, 0);
89  }
90  else if (mesh.geometricD()[1] == -1)
91  {
92  kdir = vector(0, 1, 0);
93  }
94  else
95  {
96  kdir = vector(0, 0, 1);
97  }
98  }
99  else // 3D so find a direction in the plane of the face
100  {
101  const face& f = mesh.faces()[facei];
102  kdir = mesh.points()[f[0]] - mesh.faceCentres()[facei];
103  }
104  #else
105  // Spherical geometry so kdir is the radial direction
106  kdir = mesh.faceCentres()[facei];
107  #endif
108 
109  if (mesh.nGeometricD() == 3)
110  {
111  // Remove the idir component from kdir and normalise
112  kdir -= (idir & kdir)*idir;
113 
114  scalar magk = mag(kdir);
115 
116  if (magk < SMALL)
117  {
119  << exit(FatalError);
120  }
121  else
122  {
123  kdir /= magk;
124  }
125  }
126 
127  jdir = kdir ^ idir;
128 }
129 
130 
131 template<class FitDataType, class ExtendedStencil, class Polynomial>
133 (
134  scalarList& coeffsi,
135  const List<point>& C,
136  const scalar wLin,
137  const label facei
138 )
139 {
140  vector idir(1,0,0);
141  vector jdir(0,1,0);
142  vector kdir(0,0,1);
143  findFaceDirs(idir, jdir, kdir, facei);
144 
145  // Setup the point weights
146  scalarList wts(C.size(), scalar(1));
147  wts[0] = centralWeight_;
148  if (linearCorrection_)
149  {
150  wts[1] = centralWeight_;
151  }
152 
153  // Reference point
154  point p0 = this->mesh().faceCentres()[facei];
155 
156  // Info<< "Face " << facei << " at " << p0 << " stencil points at:\n"
157  // << C - p0 << endl;
158 
159  // p0 -> p vector in the face-local coordinate system
160  vector d;
161 
162  // Local coordinate scaling
163  scalar scale = 1;
164 
165  // Matrix of the polynomial components
166  scalarRectangularMatrix B(C.size(), minSize_, Zero);
167 
168  forAll(C, ip)
169  {
170  const point& p = C[ip];
171 
172  d.x() = (p - p0)&idir;
173  d.y() = (p - p0)&jdir;
174  #ifndef SPHERICAL_GEOMETRY
175  d.z() = (p - p0)&kdir;
176  #else
177  d.z() = mag(p) - mag(p0);
178  #endif
179 
180  if (ip == 0)
181  {
182  scale = cmptMax(cmptMag((d)));
183  }
184 
185  // Scale the radius vector
186  d /= scale;
187 
188  Polynomial::addCoeffs
189  (
190  B[ip],
191  d,
192  wts[ip],
193  dim_
194  );
195  }
196 
197  // Additional weighting for constant and linear terms
198  for (label i = 0; i < B.m(); i++)
199  {
200  B(i, 0) *= wts[0];
201  B(i, 1) *= wts[0];
202  }
203 
204  // Set the fit
205  label stencilSize = C.size();
206  coeffsi.setSize(stencilSize);
207 
208  bool goodFit = false;
209  for (int iIt = 0; iIt < 8 && !goodFit; iIt++)
210  {
211  SVD svd(B, SMALL);
212  scalarRectangularMatrix invB(svd.VSinvUt());
213 
214  scalar maxCoeff = 0;
215  label maxCoeffi = 0;
216 
217  for (label i=0; i<stencilSize; i++)
218  {
219  coeffsi[i] = wts[0]*wts[i]*invB(0, i);
220  if (mag(coeffsi[i]) > maxCoeff)
221  {
222  maxCoeff = mag(coeffsi[i]);
223  maxCoeffi = i;
224  }
225  }
226 
227  if (linearCorrection_)
228  {
229  goodFit =
230  (mag(coeffsi[0] - wLin) < linearLimitFactor_*wLin)
231  && (mag(coeffsi[1] - (1 - wLin)) < linearLimitFactor_*(1 - wLin))
232  && maxCoeffi <= 1;
233  }
234  else
235  {
236  // Upwind: weight on face is 1.
237  goodFit =
238  (mag(coeffsi[0] - 1.0) < linearLimitFactor_*1.0)
239  && maxCoeffi <= 1;
240  }
241 
242  // if (goodFit && iIt > 0)
243  // {
244  // Info<< "FitData<Polynomial>::calcFit"
245  // << "(const List<point>& C, const label facei" << nl
246  // << "Can now fit face " << facei << " iteration " << iIt
247  // << " with sum of weights " << sum(coeffsi) << nl
248  // << " Weights " << coeffsi << nl
249  // << " Linear weights " << wLin << " " << 1 - wLin << nl
250  // << " sing vals " << svd.S() << endl;
251  // }
252 
253  if (!goodFit) // (not good fit so increase weight in the centre and
254  // weight for constant and linear terms)
255  {
256  // if (iIt == 7)
257  // {
258  // WarningInFunction
259  // << "Cannot fit face " << facei << " iteration " << iIt
260  // << " with sum of weights " << sum(coeffsi) << nl
261  // << " Weights " << coeffsi << nl
262  // << " Linear weights " << wLin << " " << 1 - wLin << nl
263  // << " sing vals " << svd.S() << endl;
264  // }
265 
266  wts[0] *= 10;
267  if (linearCorrection_)
268  {
269  wts[1] *= 10;
270  }
271 
272  for (label j = 0; j < B.n(); j++)
273  {
274  B(0, j) *= 10;
275  B(1, j) *= 10;
276  }
277 
278  for (label i = 0; i < B.m(); i++)
279  {
280  B(i, 0) *= 10;
281  B(i, 1) *= 10;
282  }
283  }
284  }
285 
286  if (goodFit)
287  {
288  if (linearCorrection_)
289  {
290  // Remove the uncorrected linear coefficients
291  coeffsi[0] -= wLin;
292  coeffsi[1] -= 1 - wLin;
293  }
294  else
295  {
296  // Remove the uncorrected upwind coefficients
297  coeffsi[0] -= 1.0;
298  }
299  }
300  else
301  {
302  // if (debug)
303  // {
305  << "Could not fit face " << facei
306  << " Weights = " << coeffsi
307  << ", reverting to linear." << nl
308  << " Linear weights " << wLin << " " << 1 - wLin << endl;
309  // }
310 
311  coeffsi = 0;
312  }
313 }
314 
315 
316 template<class FitDataType, class ExtendedStencil, class Polynomial>
318 {
319  calcFit();
320  return true;
321 }
322 
323 // ************************************************************************* //
volFields.H
Foam::Vector::x
const Cmpt & x() const
Access to the vector x component.
Definition: VectorI.H:73
p
volScalarField & p
Definition: createFieldRefs.H:8
SVD.H
Foam::Zero
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:131
B
static const Foam::dimensionedScalar B("", Foam::dimless, 18.678)
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:369
surfaceFields.H
Foam::surfaceFields.
Foam::FitData::findFaceDirs
void findFaceDirs(vector &idir, vector &jdir, vector &kdir, const label faci)
Find the normal direction (i) and j and k directions for face faci.
Definition: FitData.C:72
Foam::Vector::z
const Cmpt & z() const
Access to the vector z component.
Definition: VectorI.H:85
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:296
Foam::cmptMag
void cmptMag(FieldField< Field, Type > &cf, const FieldField< Field, Type > &f)
Definition: FieldFieldFunctions.C:400
Foam::cmptMax
void cmptMax(FieldField< Field, typename FieldField< Field, Type >::cmptType > &cf, const FieldField< Field, Type > &f)
Definition: FieldFieldFunctions.C:253
Foam::SVD::VSinvUt
scalarRectangularMatrix VSinvUt() const
Return the matrix product V S^(-1) U^T (the pseudo inverse)
Definition: SVD.C:387
Foam::List::setSize
void setSize(const label n)
Alias for resize()
Definition: List.H:222
Foam::RectangularMatrix< scalar >
Foam::FitData::movePoints
bool movePoints()
Recalculate weights (but not stencil) when the mesh moves.
Definition: FitData.C:317
Foam::FatalError
error FatalError
mesh
dynamicFvMesh & mesh
Definition: createDynamicFvMesh.H:6
Foam::fvMesh
Mesh data needed to do the Finite Volume discretisation.
Definition: fvMesh.H:85
Foam::vector
Vector< scalar > vector
A scalar version of the templated Vector.
Definition: vector.H:51
Foam::exit
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:130
Foam::normalised
VectorSpace< Form, Cmpt, Ncmpts > normalised(const VectorSpace< Form, Cmpt, Ncmpts > &vs)
Definition: VectorSpaceI.H:487
Foam::FitData::FitData
FitData(const fvMesh &mesh, const ExtendedStencil &stencil, const bool linearCorrection, const scalar linearLimitFactor, const scalar centralWeight)
Construct from components.
Definition: FitData.C:37
FitData.H
Foam::Vector::y
const Cmpt & y() const
Access to the vector y component.
Definition: VectorI.H:79
FatalErrorInFunction
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:453
Foam::FitData::calcFit
virtual void calcFit()=0
Calculate the fit for all the faces.
Foam::nl
constexpr char nl
Definition: Ostream.H:404
f
labelList f(nPoints)
Foam::Vector< scalar >
Foam::List< scalar >
Foam::mag
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
Foam::SVD
Singular value decomposition of a rectangular matrix.
Definition: SVD.H:53
Foam::MeshObject
Templated abstract base-class for optional mesh objects used to automate their allocation to the mesh...
Definition: MeshObject.H:88
Foam::face
A face is a list of labels corresponding to mesh vertices.
Definition: face.H:72
p0
const volScalarField & p0
Definition: EEqn.H:36
Foam::C
Graphite solid properties.
Definition: C.H:50
WarningInFunction
#define WarningInFunction
Report a warning using Foam::Warning.
Definition: messageStream.H:328