Newer
Older
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 1991-2009 OpenCFD Ltd.
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
\\/ M anipulation |
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
\*---------------------------------------------------------------------------*/
#include "FitData.H"
#include "surfaceFields.H"
#include "volFields.H"
#include "SVD.H"
#include "syncTools.H"
#include "extendedStencil.H"
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
template<class Form, class extendedStencil, class Polynomial>
Foam::FitData<Form, extendedStencil, Polynomial>::FitData
(
const fvMesh& mesh,
const extendedStencil& stencil,
const scalar linearLimitFactor,
const scalar centralWeight
)
:
MeshObject<fvMesh, Form>(mesh),
stencil_(stencil),
linearLimitFactor_(linearLimitFactor),
centralWeight_(centralWeight),
# ifdef SPHERICAL_GEOMETRY
dim_(2),
# else
dim_(mesh.nGeometricD()),
# endif
minSize_(Polynomial::nTerms(dim_))
{
// Check input
if (linearLimitFactor <= SMALL || linearLimitFactor > 3)
{
<< "linearLimitFactor requested = " << linearLimitFactor
<< " should be between zero and 3"
<< exit(FatalError);
}
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class FitDataType, class ExtendedStencil, class Polynomial>
void Foam::FitData<FitDataType, ExtendedStencil, Polynomial>::findFaceDirs
(
vector& idir, // value changed in return
vector& jdir, // value changed in return
vector& kdir, // value changed in return
const label facei
)
{
const fvMesh& mesh = this->mesh();
idir = mesh.faceAreas()[facei];
idir /= mag(idir);
# ifndef SPHERICAL_GEOMETRY
if (mesh.nGeometricD() <= 2) // find the normal direction
{
{
kdir = vector(1, 0, 0);
}
{
kdir = vector(0, 1, 0);
}
else
{
kdir = vector(0, 0, 1);
}
}
else // 3D so find a direction in the plane of the face
{
const face& f = mesh.faces()[facei];
kdir = mesh.points()[f[0]] - mesh.faceCentres()[facei];
}
# else
// Spherical geometry so kdir is the radial direction
kdir = mesh.faceCentres()[facei];
# endif
if (mesh.nGeometricD() == 3)
{
// Remove the idir component from kdir and normalise
kdir -= (idir & kdir)*idir;
scalar magk = mag(kdir);
if (magk < SMALL)
{
FatalErrorIn("findFaceDirs(..)") << " calculated kdir = zero"
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
<< exit(FatalError);
}
else
{
kdir /= magk;
}
}
jdir = kdir ^ idir;
}
template<class FitDataType, class ExtendedStencil, class Polynomial>
void Foam::FitData<FitDataType, ExtendedStencil, Polynomial>::calcFit
(
scalarList& coeffsi,
const List<point>& C,
const scalar wLin,
const label facei
)
{
vector idir(1,0,0);
vector jdir(0,1,0);
vector kdir(0,0,1);
findFaceDirs(idir, jdir, kdir, facei);
// Setup the point weights
scalarList wts(C.size(), scalar(1));
wts[0] = centralWeight_;
wts[1] = centralWeight_;
// Reference point
point p0 = this->mesh().faceCentres()[facei];
// Info << "Face " << facei << " at " << p0 << " stencil points at:\n"
// << C - p0 << endl;
// p0 -> p vector in the face-local coordinate system
vector d;
// Local coordinate scaling
scalar scale = 1;
// Matrix of the polynomial components
scalarRectangularMatrix B(C.size(), minSize_, scalar(0));
for(label ip = 0; ip < C.size(); ip++)
{
const point& p = C[ip];
d.x() = (p - p0)&idir;
d.y() = (p - p0)&jdir;
# ifndef SPHERICAL_GEOMETRY
d.z() = (p - p0)&kdir;
# else
d.z() = mag(p) - mag(p0);
# endif
if (ip == 0)
{
scale = cmptMax(cmptMag((d)));
}
// Scale the radius vector
d /= scale;
Polynomial::addCoeffs
(
B[ip],
d,
wts[ip],
dim_
);
}
// Additional weighting for constant and linear terms
for(label i = 0; i < B.n(); i++)
{
B[i][0] *= wts[0];
B[i][1] *= wts[0];
}
// Set the fit
label stencilSize = C.size();
coeffsi.setSize(stencilSize);
bool goodFit = false;
for(int iIt = 0; iIt < 8 && !goodFit; iIt++)
{
SVD svd(B, SMALL);
scalar maxCoeff = 0;
label maxCoeffi = 0;
for(label i=0; i<stencilSize; i++)
{
if (mag(coeffsi[i]) > maxCoeff)
{
maxCoeff = mag(coeffsi[i]);
maxCoeffi = i;
}
}
goodFit =
(mag(coeffsi[0] - wLin) < linearLimitFactor_*wLin)
&& (mag(coeffsi[1] - (1 - wLin)) < linearLimitFactor_*(1 - wLin))
&& maxCoeffi <= 1;
// if (goodFit && iIt > 0)
// {
// Info << "FitData<Polynomial>::calcFit"
// << "(const List<point>& C, const label facei" << nl
// << "Can now fit face " << facei << " iteration " << iIt
// << " with sum of weights " << sum(coeffsi) << nl
// << " Weights " << coeffsi << nl
// << " Linear weights " << wLin << " " << 1 - wLin << nl
// << " sing vals " << svd.S() << endl;
// }
if (!goodFit) // (not good fit so increase weight in the centre and weight
// for constant and linear terms)
{
// if (iIt == 7)
// {
// WarningIn
// (
// "FitData<Polynomial>::calcFit"
// "(const List<point>& C, const label facei"
// ) << "Cannot fit face " << facei << " iteration " << iIt
// << " with sum of weights " << sum(coeffsi) << nl
// << " Weights " << coeffsi << nl
// << " Linear weights " << wLin << " " << 1 - wLin << nl
// << " sing vals " << svd.S() << endl;
// }
wts[0] *= 10;
wts[1] *= 10;
for(label j = 0; j < B.m(); j++)
{
B[0][j] *= 10;
B[1][j] *= 10;
}
for(label i = 0; i < B.n(); i++)
{
B[i][0] *= 10;
B[i][1] *= 10;
}
}
}
if (goodFit)
{
// Remove the uncorrected linear ocefficients
coeffsi[0] -= wLin;
coeffsi[1] -= 1 - wLin;
}
else
{
// if (debug)
// {
WarningIn
(
) << "Could not fit face " << facei
<< " Weights = " << coeffsi
<< ", reverting to linear." << nl
<< " Linear weights " << wLin << " " << 1 - wLin << endl;
// }
coeffsi = 0;
}
}
template<class FitDataType, class ExtendedStencil, class Polynomial>
bool Foam::FitData<FitDataType, ExtendedStencil, Polynomial>::movePoints()
{
calcFit();
return true;
}
// ************************************************************************* //