Actual source code: gmreig.c
1: #include <../src/ksp/ksp/impls/gmres/gmresimpl.h>
2: #include <petscblaslapack.h>
4: PetscErrorCode KSPComputeExtremeSingularValues_GMRES(KSP ksp, PetscReal *emax, PetscReal *emin)
5: {
6: KSP_GMRES *gmres = (KSP_GMRES *)ksp->data;
7: PetscInt n = gmres->it + 1, i, N = gmres->max_k + 2;
8: PetscBLASInt bn, bN, lwork, idummy, lierr;
9: PetscScalar *R = gmres->Rsvd, *work = R + N * N, sdummy = 0;
10: PetscReal *realpart = gmres->Dsvd;
12: PetscFunctionBegin;
13: PetscCall(PetscBLASIntCast(n, &bn));
14: PetscCall(PetscBLASIntCast(N, &bN));
15: PetscCall(PetscBLASIntCast(5 * N, &lwork));
16: PetscCall(PetscBLASIntCast(N, &idummy));
17: if (n <= 0) {
18: *emax = *emin = 1.0;
19: PetscFunctionReturn(PETSC_SUCCESS);
20: }
21: /* copy R matrix to work space */
22: PetscCall(PetscArraycpy(R, gmres->hh_origin, (gmres->max_k + 2) * (gmres->max_k + 1)));
24: /* zero below diagonal garbage */
25: for (i = 0; i < n; i++) R[i * N + i + 1] = 0.0;
27: /* compute Singular Values */
28: PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
29: #if !defined(PETSC_USE_COMPLEX)
30: PetscCallBLAS("LAPACKgesvd", LAPACKgesvd_("N", "N", &bn, &bn, R, &bN, realpart, &sdummy, &idummy, &sdummy, &idummy, work, &lwork, &lierr));
31: #else
32: PetscCallBLAS("LAPACKgesvd", LAPACKgesvd_("N", "N", &bn, &bn, R, &bN, realpart, &sdummy, &idummy, &sdummy, &idummy, work, &lwork, realpart + N, &lierr));
33: #endif
34: PetscCheck(!lierr, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in SVD Lapack routine %d", (int)lierr);
35: PetscCall(PetscFPTrapPop());
37: *emin = realpart[n - 1];
38: *emax = realpart[0];
39: PetscFunctionReturn(PETSC_SUCCESS);
40: }
42: PetscErrorCode KSPComputeEigenvalues_GMRES(KSP ksp, PetscInt nmax, PetscReal *r, PetscReal *c, PetscInt *neig)
43: {
44: #if !defined(PETSC_USE_COMPLEX)
45: KSP_GMRES *gmres = (KSP_GMRES *)ksp->data;
46: PetscInt n = gmres->it + 1, N = gmres->max_k + 1, i, *perm;
47: PetscBLASInt bn, bN, lwork, idummy, lierr = -1;
48: PetscScalar *R = gmres->Rsvd, *work = R + N * N;
49: PetscScalar *realpart = gmres->Dsvd, *imagpart = realpart + N, sdummy = 0;
51: PetscFunctionBegin;
52: PetscCall(PetscBLASIntCast(n, &bn));
53: PetscCall(PetscBLASIntCast(N, &bN));
54: PetscCall(PetscBLASIntCast(5 * N, &lwork));
55: PetscCall(PetscBLASIntCast(N, &idummy));
56: PetscCheck(nmax >= n, PetscObjectComm((PetscObject)ksp), PETSC_ERR_ARG_SIZ, "Not enough room in work space r and c for eigenvalues");
57: *neig = n;
59: if (!n) PetscFunctionReturn(PETSC_SUCCESS);
61: /* copy R matrix to work space */
62: PetscCall(PetscArraycpy(R, gmres->hes_origin, N * N));
64: /* compute eigenvalues */
65: PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
66: PetscCallBLAS("LAPACKgeev", LAPACKgeev_("N", "N", &bn, R, &bN, realpart, imagpart, &sdummy, &idummy, &sdummy, &idummy, work, &lwork, &lierr));
67: PetscCheck(!lierr, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in LAPACK routine %d", (int)lierr);
68: PetscCall(PetscFPTrapPop());
69: PetscCall(PetscMalloc1(n, &perm));
70: for (i = 0; i < n; i++) perm[i] = i;
71: PetscCall(PetscSortRealWithPermutation(n, realpart, perm));
72: for (i = 0; i < n; i++) {
73: r[i] = realpart[perm[i]];
74: c[i] = imagpart[perm[i]];
75: }
76: PetscCall(PetscFree(perm));
77: #else
78: KSP_GMRES *gmres = (KSP_GMRES *)ksp->data;
79: PetscInt n = gmres->it + 1, N = gmres->max_k + 1, i, *perm;
80: PetscScalar *R = gmres->Rsvd, *work = R + N * N, *eigs = work + 5 * N, sdummy;
81: PetscBLASInt bn, bN, lwork, idummy, lierr = -1;
83: PetscFunctionBegin;
84: PetscCall(PetscBLASIntCast(n, &bn));
85: PetscCall(PetscBLASIntCast(N, &bN));
86: PetscCall(PetscBLASIntCast(5 * N, &lwork));
87: PetscCall(PetscBLASIntCast(N, &idummy));
88: PetscCheck(nmax >= n, PetscObjectComm((PetscObject)ksp), PETSC_ERR_ARG_SIZ, "Not enough room in work space r and c for eigenvalues");
89: *neig = n;
91: if (!n) PetscFunctionReturn(PETSC_SUCCESS);
93: /* copy R matrix to work space */
94: PetscCall(PetscArraycpy(R, gmres->hes_origin, N * N));
96: /* compute eigenvalues */
97: PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
98: PetscCallBLAS("LAPACKgeev", LAPACKgeev_("N", "N", &bn, R, &bN, eigs, &sdummy, &idummy, &sdummy, &idummy, work, &lwork, gmres->Dsvd, &lierr));
99: PetscCheck(!lierr, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in LAPACK routine");
100: PetscCall(PetscFPTrapPop());
101: PetscCall(PetscMalloc1(n, &perm));
102: for (i = 0; i < n; i++) perm[i] = i;
103: for (i = 0; i < n; i++) r[i] = PetscRealPart(eigs[i]);
104: PetscCall(PetscSortRealWithPermutation(n, r, perm));
105: for (i = 0; i < n; i++) {
106: r[i] = PetscRealPart(eigs[perm[i]]);
107: c[i] = PetscImaginaryPart(eigs[perm[i]]);
108: }
109: PetscCall(PetscFree(perm));
110: #endif
111: PetscFunctionReturn(PETSC_SUCCESS);
112: }
114: PetscErrorCode KSPComputeRitz_GMRES(KSP ksp, PetscBool ritz, PetscBool small, PetscInt *nrit, Vec S[], PetscReal *tetar, PetscReal *tetai)
115: {
116: KSP_GMRES *gmres = (KSP_GMRES *)ksp->data;
117: PetscInt NbrRitz, nb = 0, n;
118: PetscInt i, j, *perm;
119: PetscScalar *H, *Q, *Ht; /* H Hessenberg matrix; Q matrix of eigenvectors of H */
120: PetscScalar *wr, *wi; /* Real and imaginary part of the Ritz values */
121: PetscScalar *SR, *work;
122: PetscReal *modul;
123: PetscBLASInt bn, bN, lwork, idummy;
124: PetscScalar *t, sdummy = 0;
125: Mat A;
127: PetscFunctionBegin;
128: /* Express sizes in PetscBLASInt for LAPACK routines*/
129: PetscCall(PetscBLASIntCast(gmres->fullcycle ? gmres->max_k : gmres->it + 1, &bn)); /* size of the Hessenberg matrix */
130: PetscCall(PetscBLASIntCast(gmres->max_k + 1, &bN)); /* LDA of the Hessenberg matrix */
131: PetscCall(PetscBLASIntCast(gmres->max_k + 1, &idummy));
132: PetscCall(PetscBLASIntCast(5 * (gmres->max_k + 1) * (gmres->max_k + 1), &lwork));
134: /* NbrRitz: number of (Harmonic) Ritz pairs to extract */
135: NbrRitz = PetscMin(*nrit, bn);
136: PetscCall(KSPGetOperators(ksp, &A, NULL));
137: PetscCall(MatGetSize(A, &n, NULL));
138: NbrRitz = PetscMin(NbrRitz, n);
140: PetscCall(PetscMalloc4(bN * bN, &H, bn * bn, &Q, bn, &wr, bn, &wi));
142: /* copy H matrix to work space */
143: PetscCall(PetscArraycpy(H, gmres->fullcycle ? gmres->hes_ritz : gmres->hes_origin, bN * bN));
145: /* Modify H to compute Harmonic Ritz pairs H = H + H^{-T}*h^2_{m+1,m}e_m*e_m^T */
146: if (!ritz) {
147: /* Transpose the Hessenberg matrix => Ht */
148: PetscCall(PetscMalloc1(bn * bn, &Ht));
149: for (i = 0; i < bn; i++) {
150: for (j = 0; j < bn; j++) Ht[i * bn + j] = PetscConj(H[j * bN + i]);
151: }
152: /* Solve the system H^T*t = h^2_{m+1,m}e_m */
153: PetscCall(PetscCalloc1(bn, &t));
154: /* t = h^2_{m+1,m}e_m */
155: if (gmres->fullcycle) t[bn - 1] = PetscSqr(gmres->hes_ritz[(bn - 1) * bN + bn]);
156: else t[bn - 1] = PetscSqr(gmres->hes_origin[(bn - 1) * bN + bn]);
158: /* Call the LAPACK routine dgesv to compute t = H^{-T}*t */
159: {
160: PetscBLASInt info;
161: PetscBLASInt nrhs = 1;
162: PetscBLASInt *ipiv;
163: PetscCall(PetscMalloc1(bn, &ipiv));
164: PetscCallBLAS("LAPACKgesv", LAPACKgesv_(&bn, &nrhs, Ht, &bn, ipiv, t, &bn, &info));
165: PetscCheck(!info, PetscObjectComm((PetscObject)ksp), PETSC_ERR_PLIB, "Error while calling the Lapack routine DGESV");
166: PetscCall(PetscFree(ipiv));
167: PetscCall(PetscFree(Ht));
168: }
169: /* Form H + H^{-T}*h^2_{m+1,m}e_m*e_m^T */
170: for (i = 0; i < bn; i++) H[(bn - 1) * bn + i] += t[i];
171: PetscCall(PetscFree(t));
172: }
174: /*
175: Compute (Harmonic) Ritz pairs;
176: For a real Ritz eigenvector at wr(j) Q(:,j) columns contain the real right eigenvector
177: For a complex Ritz pair of eigenvectors at wr(j), wi(j), wr(j+1), and wi(j+1), Q(:,j) + i Q(:,j+1) and Q(:,j) - i Q(:,j+1) are the two eigenvectors
178: */
179: {
180: PetscBLASInt info;
181: #if defined(PETSC_USE_COMPLEX)
182: PetscReal *rwork = NULL;
183: #endif
184: PetscCall(PetscMalloc1(lwork, &work));
185: PetscCall(PetscFPTrapPush(PETSC_FP_TRAP_OFF));
186: #if !defined(PETSC_USE_COMPLEX)
187: PetscCallBLAS("LAPACKgeev", LAPACKgeev_("N", "V", &bn, H, &bN, wr, wi, &sdummy, &idummy, Q, &bn, work, &lwork, &info));
188: #else
189: PetscCall(PetscMalloc1(2 * n, &rwork));
190: PetscCallBLAS("LAPACKgeev", LAPACKgeev_("N", "V", &bn, H, &bN, wr, &sdummy, &idummy, Q, &bn, work, &lwork, rwork, &info));
191: PetscCall(PetscFree(rwork));
192: #endif
193: PetscCheck(!info, PETSC_COMM_SELF, PETSC_ERR_LIB, "Error in LAPACK routine");
194: PetscCall(PetscFPTrapPop());
195: PetscCall(PetscFree(work));
196: }
197: /* sort the (Harmonic) Ritz values */
198: PetscCall(PetscMalloc2(bn, &modul, bn, &perm));
199: #if defined(PETSC_USE_COMPLEX)
200: for (i = 0; i < bn; i++) modul[i] = PetscAbsScalar(wr[i]);
201: #else
202: for (i = 0; i < bn; i++) modul[i] = PetscSqrtReal(wr[i] * wr[i] + wi[i] * wi[i]);
203: #endif
204: for (i = 0; i < bn; i++) perm[i] = i;
205: PetscCall(PetscSortRealWithPermutation(bn, modul, perm));
207: #if defined(PETSC_USE_COMPLEX)
208: /* sort extracted (Harmonic) Ritz pairs */
209: nb = NbrRitz;
210: PetscCall(PetscMalloc1(nb * bn, &SR));
211: for (i = 0; i < nb; i++) {
212: if (small) {
213: tetar[i] = PetscRealPart(wr[perm[i]]);
214: tetai[i] = PetscImaginaryPart(wr[perm[i]]);
215: PetscCall(PetscArraycpy(&SR[i * bn], &(Q[perm[i] * bn]), bn));
216: } else {
217: tetar[i] = PetscRealPart(wr[perm[bn - nb + i]]);
218: tetai[i] = PetscImaginaryPart(wr[perm[bn - nb + i]]);
219: PetscCall(PetscArraycpy(&SR[i * bn], &(Q[perm[bn - nb + i] * bn]), bn)); /* permute columns of Q */
220: }
221: }
222: #else
223: /* count the number of extracted (Harmonic) Ritz pairs (with complex conjugates) */
224: if (small) {
225: while (nb < NbrRitz) {
226: if (!wi[perm[nb]]) nb += 1;
227: else {
228: if (nb < NbrRitz - 1) nb += 2;
229: else break;
230: }
231: }
232: PetscCall(PetscMalloc1(nb * bn, &SR));
233: for (i = 0; i < nb; i++) {
234: tetar[i] = wr[perm[i]];
235: tetai[i] = wi[perm[i]];
236: PetscCall(PetscArraycpy(&SR[i * bn], &(Q[perm[i] * bn]), bn));
237: }
238: } else {
239: while (nb < NbrRitz) {
240: if (wi[perm[bn - nb - 1]] == 0) nb += 1;
241: else {
242: if (nb < NbrRitz - 1) nb += 2;
243: else break;
244: }
245: }
246: PetscCall(PetscMalloc1(nb * bn, &SR)); /* bn rows, nb columns */
247: for (i = 0; i < nb; i++) {
248: tetar[i] = wr[perm[bn - nb + i]];
249: tetai[i] = wi[perm[bn - nb + i]];
250: PetscCall(PetscArraycpy(&SR[i * bn], &(Q[perm[bn - nb + i] * bn]), bn)); /* permute columns of Q */
251: }
252: }
253: #endif
254: PetscCall(PetscFree2(modul, perm));
255: PetscCall(PetscFree4(H, Q, wr, wi));
257: /* Form the (Harmonic) Ritz vectors S = SR*V, columns of VV correspond to the basis of the Krylov subspace */
258: for (j = 0; j < nb; j++) PetscCall(VecMAXPBY(S[j], bn, &SR[j * bn], 0, gmres->fullcycle ? gmres->vecb : &VEC_VV(0)));
260: PetscCall(PetscFree(SR));
261: *nrit = nb;
262: PetscFunctionReturn(PETSC_SUCCESS);
263: }