1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 1991-2009 OpenCFD Ltd.
7 -------------------------------------------------------------------------------
9 This file is part of OpenFOAM.
11 OpenFOAM is free software; you can redistribute it and/or modify it
12 under the terms of the GNU General Public License as published by the
13 Free Software Foundation; either version 2 of the License, or (at your
14 option) any later version.
16 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 You should have received a copy of the GNU General Public License
22 along with OpenFOAM; if not, write to the Free Software Foundation,
23 Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 \*---------------------------------------------------------------------------*/
27 #include "leastSquaresVectors.H"
28 #include "surfaceFields.H"
29 #include "volFields.H"
31 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
35 defineTypeNameAndDebug(leastSquaresVectors, 0);
39 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
41 Foam::leastSquaresVectors::leastSquaresVectors(const fvMesh& mesh)
43 MeshObject<fvMesh, leastSquaresVectors>(mesh),
49 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
51 Foam::leastSquaresVectors::~leastSquaresVectors()
53 deleteDemandDrivenData(pVectorsPtr_);
54 deleteDemandDrivenData(nVectorsPtr_);
58 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
60 void Foam::leastSquaresVectors::makeLeastSquaresVectors() const
64 Info<< "leastSquaresVectors::makeLeastSquaresVectors() :"
65 << "Constructing least square gradient vectors"
69 const fvMesh& mesh = mesh_;
71 pVectorsPtr_ = new surfaceVectorField
76 mesh_.pointsInstance(),
83 dimensionedVector("zero", dimless/dimLength, vector::zero)
85 surfaceVectorField& lsP = *pVectorsPtr_;
87 nVectorsPtr_ = new surfaceVectorField
92 mesh_.pointsInstance(),
99 dimensionedVector("zero", dimless/dimLength, vector::zero)
101 surfaceVectorField& lsN = *nVectorsPtr_;
103 // Set local references to mesh data
104 const unallocLabelList& owner = mesh_.owner();
105 const unallocLabelList& neighbour = mesh_.neighbour();
107 const volVectorField& C = mesh.C();
108 const surfaceScalarField& w = mesh.weights();
109 const surfaceScalarField& magSf = mesh.magSf();
112 // Set up temporary storage for the dd tensor (before inversion)
113 symmTensorField dd(mesh_.nCells(), symmTensor::zero);
117 label own = owner[facei];
118 label nei = neighbour[facei];
120 vector d = C[nei] - C[own];
121 symmTensor wdd = (magSf[facei]/magSqr(d))*sqr(d);
123 dd[own] += (1 - w[facei])*wdd;
124 dd[nei] += w[facei]*wdd;
128 forAll(lsP.boundaryField(), patchi)
130 const fvsPatchScalarField& pw = w.boundaryField()[patchi];
131 const fvsPatchScalarField& pMagSf = magSf.boundaryField()[patchi];
133 const fvPatch& p = pw.patch();
134 const unallocLabelList& faceCells = p.patch().faceCells();
136 // Build the d-vectors
138 mesh.Sf().boundaryField()[patchi]
140 mesh.magSf().boundaryField()[patchi]
141 *mesh.deltaCoeffs().boundaryField()[patchi]
144 if (!mesh.orthogonal())
146 pd -= mesh.correctionVectors().boundaryField()[patchi]
147 /mesh.deltaCoeffs().boundaryField()[patchi];
152 forAll(pd, patchFacei)
154 const vector& d = pd[patchFacei];
156 dd[faceCells[patchFacei]] +=
157 ((1 - pw[patchFacei])*pMagSf[patchFacei]/magSqr(d))*sqr(d);
162 forAll(pd, patchFacei)
164 const vector& d = pd[patchFacei];
166 dd[faceCells[patchFacei]] +=
167 (pMagSf[patchFacei]/magSqr(d))*sqr(d);
173 // Invert the dd tensor
174 symmTensorField invDd = inv(dd);
177 // Revisit all faces and calculate the lsP and lsN vectors
180 label own = owner[facei];
181 label nei = neighbour[facei];
183 vector d = C[nei] - C[own];
184 scalar magSfByMagSqrd = magSf[facei]/magSqr(d);
186 lsP[facei] = (1 - w[facei])*magSfByMagSqrd*(invDd[own] & d);
187 lsN[facei] = -w[facei]*magSfByMagSqrd*(invDd[nei] & d);
190 forAll(lsP.boundaryField(), patchi)
192 fvsPatchVectorField& patchLsP = lsP.boundaryField()[patchi];
194 const fvsPatchScalarField& pw = w.boundaryField()[patchi];
195 const fvsPatchScalarField& pMagSf = magSf.boundaryField()[patchi];
197 const fvPatch& p = pw.patch();
198 const unallocLabelList& faceCells = p.faceCells();
200 // Build the d-vectors
202 mesh.Sf().boundaryField()[patchi]
204 mesh.magSf().boundaryField()[patchi]
205 *mesh.deltaCoeffs().boundaryField()[patchi]
208 if (!mesh.orthogonal())
210 pd -= mesh.correctionVectors().boundaryField()[patchi]
211 /mesh.deltaCoeffs().boundaryField()[patchi];
217 forAll(pd, patchFacei)
219 const vector& d = pd[patchFacei];
221 patchLsP[patchFacei] =
222 ((1 - pw[patchFacei])*pMagSf[patchFacei]/magSqr(d))
223 *(invDd[faceCells[patchFacei]] & d);
228 forAll(pd, patchFacei)
230 const vector& d = pd[patchFacei];
232 patchLsP[patchFacei] =
233 pMagSf[patchFacei]*(1.0/magSqr(d))
234 *(invDd[faceCells[patchFacei]] & d);
240 // For 3D meshes check the determinant of the dd tensor and switch to
241 // Gauss if it is less than 3
242 /* Currently the det(dd[celli]) criterion is incorrect: dd is weighted by Sf
243 if (mesh.nGeometricD() == 3)
247 const cellList& cells = mesh.cells();
248 const scalarField& V = mesh.V();
249 const surfaceVectorField& Sf = mesh.Sf();
250 const surfaceScalarField& w = mesh.weights();
254 if (det(dd[celli]) < 3)
258 const cell& c = cells[celli];
262 label facei = c[cellFacei];
264 if (mesh.isInternalFace(facei))
266 scalar wf = max(min(w[facei], 0.8), 0.2);
268 if (celli == owner[facei])
270 lsP[facei] = (1 - wf)*Sf[facei]/V[celli];
274 lsN[facei] = -wf*Sf[facei]/V[celli];
279 label patchi = mesh.boundaryMesh().whichPatch(facei);
281 if (mesh.boundary()[patchi].size())
284 facei - mesh.boundaryMesh()[patchi].start();
286 if (mesh.boundary()[patchi].coupled())
292 w.boundaryField()[patchi][patchFacei],
298 lsP.boundaryField()[patchi][patchFacei] =
300 *Sf.boundaryField()[patchi][patchFacei]
305 lsP.boundaryField()[patchi][patchFacei] =
306 Sf.boundaryField()[patchi][patchFacei]
317 InfoIn("leastSquaresVectors::makeLeastSquaresVectors()")
318 << "number of bad cells switched to Gauss = " << nBadCells
326 Info<< "leastSquaresVectors::makeLeastSquaresVectors() :"
327 << "Finished constructing least square gradient vectors"
333 const Foam::surfaceVectorField& Foam::leastSquaresVectors::pVectors() const
337 makeLeastSquaresVectors();
340 return *pVectorsPtr_;
344 const Foam::surfaceVectorField& Foam::leastSquaresVectors::nVectors() const
348 makeLeastSquaresVectors();
351 return *nVectorsPtr_;
355 bool Foam::leastSquaresVectors::movePoints()
357 deleteDemandDrivenData(pVectorsPtr_);
358 deleteDemandDrivenData(nVectorsPtr_);
364 // ************************************************************************* //