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 \*---------------------------------------------------------------------------*/
28 #include "scalarList.H"
29 #include "scalarMatrices.H"
32 // * * * * * * * * * * * * * * * * Constructor * * * * * * * * * * * * * * //
34 Foam::SVD::SVD(const scalarRectangularMatrix& A, const scalar minCondition)
39 VSinvUt_(A.m(), A.n()),
42 // SVDcomp to find U_, V_ and S_ - the singular values
44 const label Um = U_.m();
45 const label Un = U_.n();
54 for (label i = 0; i < Um; i++)
62 for (label k = i; k < Un; k++)
64 scale += mag(U_[k][i]);
69 for (label k = i; k < Un; k++)
72 s += U_[k][i]*U_[k][i];
76 g = -sign(Foam::sqrt(s), f);
80 for (label j = l-1; j < Um; j++)
83 for (label k = i; k < Un; k++)
85 s += U_[k][i]*U_[k][j];
89 for (label k = i; k < A.n(); k++)
91 U_[k][j] += f*U_[k][i];
95 for (label k = i; k < Un; k++)
106 if (i+1 <= Un && i != Um)
108 for (label k = l-1; k < Um; k++)
110 scale += mag(U_[i][k]);
115 for (label k=l-1; k < Um; k++)
118 s += U_[i][k]*U_[i][k];
121 scalar f = U_[i][l-1];
122 g = -sign(Foam::sqrt(s),f);
126 for (label k = l-1; k < Um; k++)
131 for (label j = l-1; j < Un; j++)
134 for (label k = l-1; k < Um; k++)
136 s += U_[j][k]*U_[i][k];
139 for (label k = l-1; k < Um; k++)
141 U_[j][k] += s*rv1[k];
144 for (label k = l-1; k < Um; k++)
151 anorm = max(anorm, mag(S_[i]) + mag(rv1[i]));
154 for (label i = Um-1; i >= 0; i--)
160 for (label j = l; j < Um; j++)
162 V_[j][i] = (U_[i][j]/U_[i][l])/g;
165 for (label j=l; j < Um; j++)
168 for (label k = l; k < Um; k++)
170 s += U_[i][k]*V_[k][j];
173 for (label k = l; k < Um; k++)
175 V_[k][j] += s*V_[k][i];
180 for (label j = l; j < Um;j++)
182 V_[i][j] = V_[j][i] = 0.0;
191 for (label i = min(Um, Un) - 1; i >= 0; i--)
196 for (label j = l; j < Um; j++)
205 for (label j = l; j < Um; j++)
208 for (label k = l; k < Un; k++)
210 s += U_[k][i]*U_[k][j];
213 scalar f = (s/U_[i][i])*g;
215 for (label k = i; k < Un; k++)
217 U_[k][j] += f*U_[k][i];
221 for (label j = i; j < Un; j++)
228 for (label j = i; j < Un; j++)
237 for (label k = Um-1; k >= 0; k--)
239 for (label its = 0; its < 35; its++)
244 for (l = k; l >= 0; l--)
247 if (mag(rv1[l]) + anorm == anorm)
252 if (mag(S_[nm]) + anorm == anorm) break;
259 for (label i = l-1; i < k+1; i++)
264 if (mag(f) + anorm == anorm) break;
267 scalar h = sqrtSumSqr(f, g);
273 for (label j = 0; j < Un; j++)
275 scalar y = U_[j][nm];
277 U_[j][nm] = y*c + z*s;
278 U_[j][i] = z*c - y*s;
291 for (label j = 0; j < Um; j++) V_[j][k] = -V_[j][k];
300 "(scalarRectangularMatrix& A, const scalar minCondition)"
301 ) << "no convergence in 35 SVD iterations"
310 scalar f = ((y - z)*(y + z) + (g - h)*(g + h))/(2.0*h*y);
311 g = sqrtSumSqr(f, scalar(1));
312 f = ((x - z)*(x + z) + h*((y/(f + sign(g, f))) - h))/x;
316 for (label j = l; j <= nm; j++)
323 scalar z = sqrtSumSqr(f, h);
332 for (label jj = 0; jj < Um; jj++)
336 V_[jj][j] = x*c + z*s;
337 V_[jj][i] = z*c - x*s;
340 z = sqrtSumSqr(f, h);
351 for (label jj=0; jj < Un; jj++)
355 U_[jj][j] = y*c + z*s;
356 U_[jj][i] = z*c - y*s;
365 // zero singular values that are less than minCondition*maxS
366 const scalar minS = minCondition*S_[findMax(S_)];
367 for (label i = 0; i < S_.size(); i++)
371 //Info << "Removing " << S_[i] << " < " << minS << endl;
377 // now multiply out to find the pseudo inverse of A, VSinvUt_
378 multiply(VSinvUt_, V_, inv(S_), U_.T());
381 /*scalarRectangularMatrix SVDA(A.n(), A.m());
382 multiply(SVDA, U_, S_, transpose(V_));
385 for(label i = 0; i < A.n(); i++)
387 for(label j = 0; j < A.m(); j++)
389 diff = mag(A[i][j] - SVDA[i][j]);
390 if (diff > maxDiff) maxDiff = diff;
393 Info << "Maximum discrepancy between A and svd(A) = " << maxDiff << endl;
397 Info << "singular values " << S_ << endl;
403 // ************************************************************************* //