Line data Source code
1 : /*
2 : - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3 : SLEPc - Scalable Library for Eigenvalue Problem Computations
4 : Copyright (c) 2002-, Universitat Politecnica de Valencia, Spain
5 :
6 : This file is part of SLEPc.
7 : SLEPc is distributed under a 2-clause BSD license (see LICENSE).
8 : - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
9 : */
10 : /*
11 : SLEPc singular value solver: "cyclic"
12 :
13 : Method: Uses a Hermitian eigensolver for H(A) = [ 0 A ; A^T 0 ]
14 : */
15 :
16 : #include <slepc/private/svdimpl.h> /*I "slepcsvd.h" I*/
17 : #include <slepc/private/bvimpl.h>
18 : #include "cyclic.h"
19 :
20 2842 : static PetscErrorCode MatMult_Cyclic(Mat B,Vec x,Vec y)
21 : {
22 2842 : SVD_CYCLIC_SHELL *ctx;
23 2842 : const PetscScalar *px;
24 2842 : PetscScalar *py;
25 2842 : PetscInt m;
26 :
27 2842 : PetscFunctionBegin;
28 2842 : PetscCall(MatShellGetContext(B,&ctx));
29 2842 : PetscCall(MatGetLocalSize(ctx->A,&m,NULL));
30 2842 : PetscCall(VecGetArrayRead(x,&px));
31 2842 : PetscCall(VecGetArrayWrite(y,&py));
32 2842 : PetscCall(VecPlaceArray(ctx->x1,px));
33 2842 : PetscCall(VecPlaceArray(ctx->x2,px+m));
34 2842 : PetscCall(VecPlaceArray(ctx->y1,py));
35 2842 : PetscCall(VecPlaceArray(ctx->y2,py+m));
36 2842 : PetscCall(MatMult(ctx->A,ctx->x2,ctx->y1));
37 2842 : PetscCall(MatMult(ctx->AT,ctx->x1,ctx->y2));
38 2842 : PetscCall(VecResetArray(ctx->x1));
39 2842 : PetscCall(VecResetArray(ctx->x2));
40 2842 : PetscCall(VecResetArray(ctx->y1));
41 2842 : PetscCall(VecResetArray(ctx->y2));
42 2842 : PetscCall(VecRestoreArrayRead(x,&px));
43 2842 : PetscCall(VecRestoreArrayWrite(y,&py));
44 2842 : PetscFunctionReturn(PETSC_SUCCESS);
45 : }
46 :
47 0 : static PetscErrorCode MatGetDiagonal_Cyclic(Mat B,Vec diag)
48 : {
49 0 : PetscFunctionBegin;
50 0 : PetscCall(VecSet(diag,0.0));
51 0 : PetscFunctionReturn(PETSC_SUCCESS);
52 : }
53 :
54 27 : static PetscErrorCode MatDestroy_Cyclic(Mat B)
55 : {
56 27 : SVD_CYCLIC_SHELL *ctx;
57 :
58 27 : PetscFunctionBegin;
59 27 : PetscCall(MatShellGetContext(B,&ctx));
60 27 : PetscCall(VecDestroy(&ctx->x1));
61 27 : PetscCall(VecDestroy(&ctx->x2));
62 27 : PetscCall(VecDestroy(&ctx->y1));
63 27 : PetscCall(VecDestroy(&ctx->y2));
64 27 : if (ctx->misaligned) {
65 0 : PetscCall(VecDestroy(&ctx->wx2));
66 0 : PetscCall(VecDestroy(&ctx->wy2));
67 : }
68 27 : PetscCall(PetscFree(ctx));
69 27 : PetscFunctionReturn(PETSC_SUCCESS);
70 : }
71 :
72 : /*
73 : Builds cyclic matrix C = | 0 A |
74 : | AT 0 |
75 : */
76 42 : static PetscErrorCode SVDCyclicGetCyclicMat(SVD svd,Mat A,Mat AT,Mat *C)
77 : {
78 42 : SVD_CYCLIC *cyclic = (SVD_CYCLIC*)svd->data;
79 42 : SVD_CYCLIC_SHELL *ctx;
80 42 : PetscInt i,M,N,m,n,Istart,Iend;
81 42 : VecType vtype;
82 42 : Mat Zm,Zn;
83 : #if defined(PETSC_HAVE_CUDA) || defined(PETSC_HAVE_HIP)
84 : PetscBool gpu;
85 : const PetscInt *ranges;
86 : PetscMPIInt size;
87 : #endif
88 :
89 42 : PetscFunctionBegin;
90 42 : PetscCall(MatGetSize(A,&M,&N));
91 42 : PetscCall(MatGetLocalSize(A,&m,&n));
92 :
93 42 : if (cyclic->explicitmatrix) {
94 15 : PetscCheck(svd->expltrans,PetscObjectComm((PetscObject)svd),PETSC_ERR_SUP,"Cannot use explicit cyclic matrix with implicit transpose");
95 15 : PetscCall(MatCreate(PetscObjectComm((PetscObject)svd),&Zm));
96 15 : PetscCall(MatSetSizes(Zm,m,m,M,M));
97 15 : PetscCall(MatSetFromOptions(Zm));
98 15 : PetscCall(MatGetOwnershipRange(Zm,&Istart,&Iend));
99 2957 : for (i=Istart;i<Iend;i++) PetscCall(MatSetValue(Zm,i,i,0.0,INSERT_VALUES));
100 15 : PetscCall(MatAssemblyBegin(Zm,MAT_FINAL_ASSEMBLY));
101 15 : PetscCall(MatAssemblyEnd(Zm,MAT_FINAL_ASSEMBLY));
102 15 : PetscCall(MatCreate(PetscObjectComm((PetscObject)svd),&Zn));
103 15 : PetscCall(MatSetSizes(Zn,n,n,N,N));
104 15 : PetscCall(MatSetFromOptions(Zn));
105 15 : PetscCall(MatGetOwnershipRange(Zn,&Istart,&Iend));
106 1524 : for (i=Istart;i<Iend;i++) PetscCall(MatSetValue(Zn,i,i,0.0,INSERT_VALUES));
107 15 : PetscCall(MatAssemblyBegin(Zn,MAT_FINAL_ASSEMBLY));
108 15 : PetscCall(MatAssemblyEnd(Zn,MAT_FINAL_ASSEMBLY));
109 15 : PetscCall(MatCreateTile(1.0,Zm,1.0,A,1.0,AT,1.0,Zn,C));
110 15 : PetscCall(MatDestroy(&Zm));
111 15 : PetscCall(MatDestroy(&Zn));
112 : } else {
113 27 : PetscCall(PetscNew(&ctx));
114 27 : ctx->A = A;
115 27 : ctx->AT = AT;
116 27 : ctx->swapped = svd->swapped;
117 27 : PetscCall(MatCreateVecsEmpty(A,&ctx->x2,&ctx->x1));
118 27 : PetscCall(MatCreateVecsEmpty(A,&ctx->y2,&ctx->y1));
119 27 : PetscCall(MatCreateShell(PetscObjectComm((PetscObject)svd),m+n,m+n,M+N,M+N,ctx,C));
120 27 : PetscCall(MatShellSetOperation(*C,MATOP_GET_DIAGONAL,(void(*)(void))MatGetDiagonal_Cyclic));
121 27 : PetscCall(MatShellSetOperation(*C,MATOP_DESTROY,(void(*)(void))MatDestroy_Cyclic));
122 : #if defined(PETSC_HAVE_CUDA)
123 : PetscCall(PetscObjectTypeCompareAny((PetscObject)(svd->swapped?AT:A),&gpu,MATSEQAIJCUSPARSE,MATMPIAIJCUSPARSE,""));
124 : if (gpu) PetscCall(MatShellSetOperation(*C,MATOP_MULT,(void(*)(void))MatMult_Cyclic_CUDA));
125 : else
126 : #elif defined(PETSC_HAVE_HIP)
127 : PetscCall(PetscObjectTypeCompareAny((PetscObject)(svd->swapped?AT:A),&gpu,MATSEQAIJHIPSPARSE,MATMPIAIJHIPSPARSE,""));
128 : if (gpu) PetscCall(MatShellSetOperation(*C,MATOP_MULT,(void(*)(void))MatMult_Cyclic_HIP));
129 : else
130 : #endif
131 27 : PetscCall(MatShellSetOperation(*C,MATOP_MULT,(void(*)(void))MatMult_Cyclic));
132 27 : PetscCall(MatGetVecType(A,&vtype));
133 27 : PetscCall(MatSetVecType(*C,vtype));
134 : #if defined(PETSC_HAVE_CUDA) || defined(PETSC_HAVE_HIP)
135 : if (gpu) {
136 : /* check alignment of bottom block */
137 : PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)ctx->x1),&size));
138 : PetscCall(VecGetOwnershipRanges(ctx->x1,&ranges));
139 : for (i=0;i<size;i++) {
140 : ctx->misaligned = (((ranges[i+1]-ranges[i])*sizeof(PetscScalar))%16)? PETSC_TRUE: PETSC_FALSE;
141 : if (ctx->misaligned) break;
142 : }
143 : if (ctx->misaligned) { /* create work vectors for MatMult */
144 : PetscCall(VecDuplicate(ctx->x2,&ctx->wx2));
145 : PetscCall(VecDuplicate(ctx->y2,&ctx->wy2));
146 : }
147 : }
148 : #endif
149 : }
150 42 : PetscFunctionReturn(PETSC_SUCCESS);
151 : }
152 :
153 6635 : static PetscErrorCode MatMult_ECross(Mat B,Vec x,Vec y)
154 : {
155 6635 : SVD_CYCLIC_SHELL *ctx;
156 6635 : const PetscScalar *px;
157 6635 : PetscScalar *py;
158 6635 : PetscInt mn,m,n;
159 :
160 6635 : PetscFunctionBegin;
161 6635 : PetscCall(MatShellGetContext(B,&ctx));
162 6635 : PetscCall(MatGetLocalSize(ctx->A,NULL,&n));
163 6635 : PetscCall(VecGetLocalSize(y,&mn));
164 6635 : m = mn-n;
165 6635 : PetscCall(VecGetArrayRead(x,&px));
166 6635 : PetscCall(VecGetArrayWrite(y,&py));
167 6635 : PetscCall(VecPlaceArray(ctx->x1,px));
168 6635 : PetscCall(VecPlaceArray(ctx->x2,px+m));
169 6635 : PetscCall(VecPlaceArray(ctx->y1,py));
170 6635 : PetscCall(VecPlaceArray(ctx->y2,py+m));
171 6635 : PetscCall(VecCopy(ctx->x1,ctx->y1));
172 6635 : PetscCall(MatMult(ctx->A,ctx->x2,ctx->w));
173 6635 : PetscCall(MatMult(ctx->AT,ctx->w,ctx->y2));
174 6635 : PetscCall(VecResetArray(ctx->x1));
175 6635 : PetscCall(VecResetArray(ctx->x2));
176 6635 : PetscCall(VecResetArray(ctx->y1));
177 6635 : PetscCall(VecResetArray(ctx->y2));
178 6635 : PetscCall(VecRestoreArrayRead(x,&px));
179 6635 : PetscCall(VecRestoreArrayWrite(y,&py));
180 6635 : PetscFunctionReturn(PETSC_SUCCESS);
181 : }
182 :
183 5 : static PetscErrorCode MatGetDiagonal_ECross(Mat B,Vec d)
184 : {
185 5 : SVD_CYCLIC_SHELL *ctx;
186 5 : PetscScalar *pd;
187 5 : PetscMPIInt len;
188 5 : PetscInt mn,m,n,N,i,j,start,end,ncols;
189 5 : PetscScalar *work1,*work2,*diag;
190 5 : const PetscInt *cols;
191 5 : const PetscScalar *vals;
192 :
193 5 : PetscFunctionBegin;
194 5 : PetscCall(MatShellGetContext(B,&ctx));
195 5 : PetscCall(MatGetLocalSize(ctx->A,NULL,&n));
196 5 : PetscCall(VecGetLocalSize(d,&mn));
197 5 : m = mn-n;
198 5 : PetscCall(VecGetArrayWrite(d,&pd));
199 5 : PetscCall(VecPlaceArray(ctx->y1,pd));
200 5 : PetscCall(VecSet(ctx->y1,1.0));
201 5 : PetscCall(VecResetArray(ctx->y1));
202 5 : PetscCall(VecPlaceArray(ctx->y2,pd+m));
203 5 : if (!ctx->diag) {
204 : /* compute diagonal from rows and store in ctx->diag */
205 5 : PetscCall(VecDuplicate(ctx->y2,&ctx->diag));
206 5 : PetscCall(MatGetSize(ctx->A,NULL,&N));
207 5 : PetscCall(PetscCalloc2(N,&work1,N,&work2));
208 5 : if (ctx->swapped) {
209 0 : PetscCall(MatGetOwnershipRange(ctx->AT,&start,&end));
210 0 : for (i=start;i<end;i++) {
211 0 : PetscCall(MatGetRow(ctx->AT,i,&ncols,NULL,&vals));
212 0 : for (j=0;j<ncols;j++) work1[i] += vals[j]*vals[j];
213 0 : PetscCall(MatRestoreRow(ctx->AT,i,&ncols,NULL,&vals));
214 : }
215 : } else {
216 5 : PetscCall(MatGetOwnershipRange(ctx->A,&start,&end));
217 111 : for (i=start;i<end;i++) {
218 106 : PetscCall(MatGetRow(ctx->A,i,&ncols,&cols,&vals));
219 806 : for (j=0;j<ncols;j++) work1[cols[j]] += vals[j]*vals[j];
220 106 : PetscCall(MatRestoreRow(ctx->A,i,&ncols,&cols,&vals));
221 : }
222 : }
223 5 : PetscCall(PetscMPIIntCast(N,&len));
224 15 : PetscCallMPI(MPIU_Allreduce(work1,work2,len,MPIU_SCALAR,MPIU_SUM,PetscObjectComm((PetscObject)B)));
225 5 : PetscCall(VecGetOwnershipRange(ctx->diag,&start,&end));
226 5 : PetscCall(VecGetArrayWrite(ctx->diag,&diag));
227 100 : for (i=start;i<end;i++) diag[i-start] = work2[i];
228 5 : PetscCall(VecRestoreArrayWrite(ctx->diag,&diag));
229 5 : PetscCall(PetscFree2(work1,work2));
230 : }
231 5 : PetscCall(VecCopy(ctx->diag,ctx->y2));
232 5 : PetscCall(VecResetArray(ctx->y2));
233 5 : PetscCall(VecRestoreArrayWrite(d,&pd));
234 5 : PetscFunctionReturn(PETSC_SUCCESS);
235 : }
236 :
237 5 : static PetscErrorCode MatDestroy_ECross(Mat B)
238 : {
239 5 : SVD_CYCLIC_SHELL *ctx;
240 :
241 5 : PetscFunctionBegin;
242 5 : PetscCall(MatShellGetContext(B,&ctx));
243 5 : PetscCall(VecDestroy(&ctx->x1));
244 5 : PetscCall(VecDestroy(&ctx->x2));
245 5 : PetscCall(VecDestroy(&ctx->y1));
246 5 : PetscCall(VecDestroy(&ctx->y2));
247 5 : PetscCall(VecDestroy(&ctx->diag));
248 5 : PetscCall(VecDestroy(&ctx->w));
249 5 : if (ctx->misaligned) {
250 0 : PetscCall(VecDestroy(&ctx->wx2));
251 0 : PetscCall(VecDestroy(&ctx->wy2));
252 : }
253 5 : PetscCall(PetscFree(ctx));
254 5 : PetscFunctionReturn(PETSC_SUCCESS);
255 : }
256 :
257 : /*
258 : Builds extended cross product matrix C = | I_m 0 |
259 : | 0 AT*A |
260 : t is an auxiliary Vec used to take the dimensions of the upper block
261 : */
262 10 : static PetscErrorCode SVDCyclicGetECrossMat(SVD svd,Mat A,Mat AT,Mat *C,Vec t)
263 : {
264 10 : SVD_CYCLIC *cyclic = (SVD_CYCLIC*)svd->data;
265 10 : SVD_CYCLIC_SHELL *ctx;
266 10 : PetscInt i,M,N,m,n,Istart,Iend;
267 10 : VecType vtype;
268 10 : Mat Id,Zm,Zn,ATA;
269 : #if defined(PETSC_HAVE_CUDA) || defined(PETSC_HAVE_HIP)
270 : PetscBool gpu;
271 : const PetscInt *ranges;
272 : PetscMPIInt size;
273 : #endif
274 :
275 10 : PetscFunctionBegin;
276 10 : PetscCall(MatGetSize(A,NULL,&N));
277 10 : PetscCall(MatGetLocalSize(A,NULL,&n));
278 10 : PetscCall(VecGetSize(t,&M));
279 10 : PetscCall(VecGetLocalSize(t,&m));
280 :
281 10 : if (cyclic->explicitmatrix) {
282 5 : PetscCheck(svd->expltrans,PetscObjectComm((PetscObject)svd),PETSC_ERR_SUP,"Cannot use explicit cyclic matrix with implicit transpose");
283 5 : PetscCall(MatCreateConstantDiagonal(PetscObjectComm((PetscObject)svd),m,m,M,M,1.0,&Id));
284 5 : PetscCall(MatCreate(PetscObjectComm((PetscObject)svd),&Zm));
285 5 : PetscCall(MatSetSizes(Zm,m,n,M,N));
286 5 : PetscCall(MatSetFromOptions(Zm));
287 5 : PetscCall(MatGetOwnershipRange(Zm,&Istart,&Iend));
288 394 : for (i=Istart;i<Iend;i++) {
289 389 : if (i<N) PetscCall(MatSetValue(Zm,i,i,0.0,INSERT_VALUES));
290 : }
291 5 : PetscCall(MatAssemblyBegin(Zm,MAT_FINAL_ASSEMBLY));
292 5 : PetscCall(MatAssemblyEnd(Zm,MAT_FINAL_ASSEMBLY));
293 5 : PetscCall(MatCreate(PetscObjectComm((PetscObject)svd),&Zn));
294 5 : PetscCall(MatSetSizes(Zn,n,m,N,M));
295 5 : PetscCall(MatSetFromOptions(Zn));
296 5 : PetscCall(MatGetOwnershipRange(Zn,&Istart,&Iend));
297 404 : for (i=Istart;i<Iend;i++) {
298 399 : if (i<m) PetscCall(MatSetValue(Zn,i,i,0.0,INSERT_VALUES));
299 : }
300 5 : PetscCall(MatAssemblyBegin(Zn,MAT_FINAL_ASSEMBLY));
301 5 : PetscCall(MatAssemblyEnd(Zn,MAT_FINAL_ASSEMBLY));
302 5 : PetscCall(MatProductCreate(AT,A,NULL,&ATA));
303 5 : PetscCall(MatProductSetType(ATA,MATPRODUCT_AB));
304 5 : PetscCall(MatProductSetFromOptions(ATA));
305 5 : PetscCall(MatProductSymbolic(ATA));
306 5 : PetscCall(MatProductNumeric(ATA));
307 5 : PetscCall(MatCreateTile(1.0,Id,1.0,Zm,1.0,Zn,1.0,ATA,C));
308 5 : PetscCall(MatDestroy(&Id));
309 5 : PetscCall(MatDestroy(&Zm));
310 5 : PetscCall(MatDestroy(&Zn));
311 5 : PetscCall(MatDestroy(&ATA));
312 : } else {
313 5 : PetscCall(PetscNew(&ctx));
314 5 : ctx->A = A;
315 5 : ctx->AT = AT;
316 5 : ctx->swapped = svd->swapped;
317 5 : PetscCall(VecDuplicateEmpty(t,&ctx->x1));
318 5 : PetscCall(VecDuplicateEmpty(t,&ctx->y1));
319 5 : PetscCall(MatCreateVecsEmpty(A,&ctx->x2,NULL));
320 5 : PetscCall(MatCreateVecsEmpty(A,&ctx->y2,NULL));
321 5 : PetscCall(MatCreateVecs(A,NULL,&ctx->w));
322 5 : PetscCall(MatCreateShell(PetscObjectComm((PetscObject)svd),m+n,m+n,M+N,M+N,ctx,C));
323 5 : PetscCall(MatShellSetOperation(*C,MATOP_GET_DIAGONAL,(void(*)(void))MatGetDiagonal_ECross));
324 5 : PetscCall(MatShellSetOperation(*C,MATOP_DESTROY,(void(*)(void))MatDestroy_ECross));
325 : #if defined(PETSC_HAVE_CUDA)
326 : PetscCall(PetscObjectTypeCompareAny((PetscObject)(svd->swapped?AT:A),&gpu,MATSEQAIJCUSPARSE,MATMPIAIJCUSPARSE,""));
327 : if (gpu) PetscCall(MatShellSetOperation(*C,MATOP_MULT,(void(*)(void))MatMult_ECross_CUDA));
328 : else
329 : #elif defined(PETSC_HAVE_HIP)
330 : PetscCall(PetscObjectTypeCompareAny((PetscObject)(svd->swapped?AT:A),&gpu,MATSEQAIJHIPSPARSE,MATMPIAIJHIPSPARSE,""));
331 : if (gpu) PetscCall(MatShellSetOperation(*C,MATOP_MULT,(void(*)(void))MatMult_ECross_HIP));
332 : else
333 : #endif
334 5 : PetscCall(MatShellSetOperation(*C,MATOP_MULT,(void(*)(void))MatMult_ECross));
335 5 : PetscCall(MatGetVecType(A,&vtype));
336 5 : PetscCall(MatSetVecType(*C,vtype));
337 : #if defined(PETSC_HAVE_CUDA) || defined(PETSC_HAVE_HIP)
338 : if (gpu) {
339 : /* check alignment of bottom block */
340 : PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)ctx->x1),&size));
341 : PetscCall(VecGetOwnershipRanges(ctx->x1,&ranges));
342 : for (i=0;i<size;i++) {
343 : ctx->misaligned = (((ranges[i+1]-ranges[i])*sizeof(PetscScalar))%16)? PETSC_TRUE: PETSC_FALSE;
344 : if (ctx->misaligned) break;
345 : }
346 : if (ctx->misaligned) { /* create work vectors for MatMult */
347 : PetscCall(VecDuplicate(ctx->x2,&ctx->wx2));
348 : PetscCall(VecDuplicate(ctx->y2,&ctx->wy2));
349 : }
350 : }
351 : #endif
352 : }
353 10 : PetscFunctionReturn(PETSC_SUCCESS);
354 : }
355 :
356 : /* Convergence test relative to the norm of R (used in GSVD only) */
357 136 : static PetscErrorCode EPSConv_Cyclic(EPS eps,PetscScalar eigr,PetscScalar eigi,PetscReal res,PetscReal *errest,void *ctx)
358 : {
359 136 : SVD svd = (SVD)ctx;
360 :
361 136 : PetscFunctionBegin;
362 136 : *errest = res/PetscMax(svd->nrma,svd->nrmb);
363 136 : PetscFunctionReturn(PETSC_SUCCESS);
364 : }
365 :
366 42 : static PetscErrorCode SVDSetUp_Cyclic(SVD svd)
367 : {
368 42 : SVD_CYCLIC *cyclic = (SVD_CYCLIC*)svd->data;
369 42 : PetscInt M,N,m,n,p,k,i,isl,offset,nev,ncv,mpd,maxit;
370 42 : PetscReal tol;
371 42 : const PetscScalar *isa,*oa;
372 42 : PetscScalar *va;
373 42 : EPSProblemType ptype;
374 42 : PetscBool trackall,issinv;
375 42 : Vec v,t;
376 42 : ST st;
377 42 : Mat Omega;
378 42 : MatType Atype;
379 :
380 42 : PetscFunctionBegin;
381 42 : PetscCall(MatGetSize(svd->A,&M,&N));
382 42 : PetscCall(MatGetLocalSize(svd->A,&m,&n));
383 42 : if (!cyclic->eps) PetscCall(SVDCyclicGetEPS(svd,&cyclic->eps));
384 42 : PetscCall(MatDestroy(&cyclic->C));
385 42 : PetscCall(MatDestroy(&cyclic->D));
386 42 : if (svd->isgeneralized) {
387 10 : if (svd->which==SVD_SMALLEST) { /* alternative pencil */
388 0 : PetscCall(MatCreateVecs(svd->B,NULL,&t));
389 0 : PetscCall(SVDCyclicGetCyclicMat(svd,svd->B,svd->BT,&cyclic->C));
390 0 : PetscCall(SVDCyclicGetECrossMat(svd,svd->A,svd->AT,&cyclic->D,t));
391 : } else {
392 10 : PetscCall(MatCreateVecs(svd->A,NULL,&t));
393 10 : PetscCall(SVDCyclicGetCyclicMat(svd,svd->A,svd->AT,&cyclic->C));
394 10 : PetscCall(SVDCyclicGetECrossMat(svd,svd->B,svd->BT,&cyclic->D,t));
395 : }
396 10 : PetscCall(VecDestroy(&t));
397 10 : PetscCall(EPSSetOperators(cyclic->eps,cyclic->C,cyclic->D));
398 10 : PetscCall(EPSGetProblemType(cyclic->eps,&ptype));
399 10 : if (!ptype) PetscCall(EPSSetProblemType(cyclic->eps,EPS_GHEP));
400 32 : } else if (svd->ishyperbolic) {
401 7 : PetscCall(SVDCyclicGetCyclicMat(svd,svd->A,svd->AT,&cyclic->C));
402 7 : PetscCall(MatCreateVecs(cyclic->C,&v,NULL));
403 7 : PetscCall(VecSet(v,1.0));
404 7 : PetscCall(VecGetArrayRead(svd->omega,&oa));
405 7 : PetscCall(VecGetArray(v,&va));
406 7 : if (svd->swapped) PetscCall(PetscArraycpy(va+m,oa,n));
407 5 : else PetscCall(PetscArraycpy(va,oa,m));
408 7 : PetscCall(VecRestoreArrayRead(svd->omega,&oa));
409 7 : PetscCall(VecRestoreArray(v,&va));
410 7 : PetscCall(MatGetType(svd->OP,&Atype));
411 7 : PetscCall(MatCreate(PetscObjectComm((PetscObject)svd),&Omega));
412 7 : PetscCall(MatSetSizes(Omega,m+n,m+n,M+N,M+N));
413 7 : PetscCall(MatSetType(Omega,Atype));
414 7 : PetscCall(MatDiagonalSet(Omega,v,INSERT_VALUES));
415 7 : PetscCall(EPSSetOperators(cyclic->eps,cyclic->C,Omega));
416 7 : PetscCall(EPSSetProblemType(cyclic->eps,EPS_GHIEP));
417 7 : PetscCall(MatDestroy(&Omega));
418 7 : PetscCall(VecDestroy(&v));
419 : } else {
420 25 : PetscCall(SVDCyclicGetCyclicMat(svd,svd->A,svd->AT,&cyclic->C));
421 25 : PetscCall(EPSSetOperators(cyclic->eps,cyclic->C,NULL));
422 25 : PetscCall(EPSSetProblemType(cyclic->eps,EPS_HEP));
423 : }
424 42 : if (!cyclic->usereps) {
425 41 : if (svd->which == SVD_LARGEST) {
426 39 : PetscCall(EPSGetST(cyclic->eps,&st));
427 39 : PetscCall(PetscObjectTypeCompare((PetscObject)st,STSINVERT,&issinv));
428 39 : if (issinv) PetscCall(EPSSetWhichEigenpairs(cyclic->eps,EPS_TARGET_MAGNITUDE));
429 38 : else if (svd->ishyperbolic) PetscCall(EPSSetWhichEigenpairs(cyclic->eps,EPS_LARGEST_MAGNITUDE));
430 31 : else PetscCall(EPSSetWhichEigenpairs(cyclic->eps,EPS_LARGEST_REAL));
431 : } else {
432 2 : if (svd->isgeneralized) { /* computes sigma^{-1} via alternative pencil */
433 0 : PetscCall(EPSSetWhichEigenpairs(cyclic->eps,EPS_LARGEST_REAL));
434 : } else {
435 2 : if (svd->ishyperbolic) PetscCall(EPSSetWhichEigenpairs(cyclic->eps,EPS_TARGET_MAGNITUDE));
436 2 : else PetscCall(EPSSetEigenvalueComparison(cyclic->eps,SlepcCompareSmallestPosReal,NULL));
437 2 : PetscCall(EPSSetTarget(cyclic->eps,0.0));
438 : }
439 : }
440 41 : PetscCall(EPSGetDimensions(cyclic->eps,&nev,&ncv,&mpd));
441 41 : PetscCheck(nev==1 || nev>=2*svd->nsv,PetscObjectComm((PetscObject)svd),PETSC_ERR_ARG_WRONG,"The number of requested eigenvalues %" PetscInt_FMT " must be at least 2*%" PetscInt_FMT,nev,svd->nsv);
442 41 : nev = PetscMax(nev,2*svd->nsv);
443 41 : if (ncv==PETSC_DETERMINE && svd->ncv!=PETSC_DETERMINE) ncv = PetscMax(3*svd->nsv,svd->ncv);
444 41 : if (mpd==PETSC_DETERMINE && svd->mpd!=PETSC_DETERMINE) mpd = svd->mpd;
445 41 : PetscCall(EPSSetDimensions(cyclic->eps,nev,ncv,mpd));
446 41 : PetscCall(EPSGetTolerances(cyclic->eps,&tol,&maxit));
447 47 : if (tol==(PetscReal)PETSC_DETERMINE) tol = svd->tol==(PetscReal)PETSC_DETERMINE? SLEPC_DEFAULT_TOL/10.0: svd->tol;
448 41 : if (maxit==PETSC_DETERMINE) maxit = svd->max_it;
449 41 : PetscCall(EPSSetTolerances(cyclic->eps,tol,maxit));
450 41 : switch (svd->conv) {
451 3 : case SVD_CONV_ABS:
452 3 : PetscCall(EPSSetConvergenceTest(cyclic->eps,EPS_CONV_ABS));break;
453 28 : case SVD_CONV_REL:
454 28 : PetscCall(EPSSetConvergenceTest(cyclic->eps,EPS_CONV_REL));break;
455 10 : case SVD_CONV_NORM:
456 10 : if (svd->isgeneralized) {
457 10 : if (!svd->nrma) PetscCall(MatNorm(svd->OP,NORM_INFINITY,&svd->nrma));
458 10 : if (!svd->nrmb) PetscCall(MatNorm(svd->OPb,NORM_INFINITY,&svd->nrmb));
459 10 : PetscCall(EPSSetConvergenceTestFunction(cyclic->eps,EPSConv_Cyclic,svd,NULL));
460 : } else {
461 0 : PetscCall(EPSSetConvergenceTest(cyclic->eps,EPS_CONV_NORM));break;
462 : }
463 : break;
464 0 : case SVD_CONV_MAXIT:
465 0 : SETERRQ(PetscObjectComm((PetscObject)svd),PETSC_ERR_SUP,"Maxit convergence test not supported in this solver");
466 0 : case SVD_CONV_USER:
467 0 : SETERRQ(PetscObjectComm((PetscObject)svd),PETSC_ERR_SUP,"User-defined convergence test not supported in this solver");
468 : }
469 1 : }
470 42 : SVDCheckUnsupported(svd,SVD_FEATURE_STOPPING);
471 : /* Transfer the trackall option from svd to eps */
472 42 : PetscCall(SVDGetTrackAll(svd,&trackall));
473 42 : PetscCall(EPSSetTrackAll(cyclic->eps,trackall));
474 : /* Transfer the initial subspace from svd to eps */
475 42 : if (svd->nini<0 || svd->ninil<0) {
476 8 : for (i=0;i<-PetscMin(svd->nini,svd->ninil);i++) {
477 4 : PetscCall(MatCreateVecs(cyclic->C,&v,NULL));
478 4 : PetscCall(VecGetArrayWrite(v,&va));
479 4 : if (svd->isgeneralized) PetscCall(MatGetLocalSize(svd->B,&p,NULL));
480 4 : k = (svd->isgeneralized && svd->which==SVD_SMALLEST)? p: m; /* size of upper block row */
481 4 : if (i<-svd->ninil) {
482 4 : PetscCall(VecGetArrayRead(svd->ISL[i],&isa));
483 4 : if (svd->isgeneralized) {
484 1 : PetscCall(VecGetLocalSize(svd->ISL[i],&isl));
485 1 : PetscCheck(isl==m+p,PetscObjectComm((PetscObject)svd),PETSC_ERR_SUP,"Size mismatch for left initial vector");
486 1 : offset = (svd->which==SVD_SMALLEST)? m: 0;
487 1 : PetscCall(PetscArraycpy(va,isa+offset,k));
488 : } else {
489 3 : PetscCall(VecGetLocalSize(svd->ISL[i],&isl));
490 3 : PetscCheck(isl==k,PetscObjectComm((PetscObject)svd),PETSC_ERR_SUP,"Size mismatch for left initial vector");
491 3 : PetscCall(PetscArraycpy(va,isa,k));
492 : }
493 4 : PetscCall(VecRestoreArrayRead(svd->IS[i],&isa));
494 0 : } else PetscCall(PetscArrayzero(&va,k));
495 4 : if (i<-svd->nini) {
496 4 : PetscCall(VecGetLocalSize(svd->IS[i],&isl));
497 4 : PetscCheck(isl==n,PetscObjectComm((PetscObject)svd),PETSC_ERR_SUP,"Size mismatch for right initial vector");
498 4 : PetscCall(VecGetArrayRead(svd->IS[i],&isa));
499 4 : PetscCall(PetscArraycpy(va+k,isa,n));
500 4 : PetscCall(VecRestoreArrayRead(svd->IS[i],&isa));
501 0 : } else PetscCall(PetscArrayzero(va+k,n));
502 4 : PetscCall(VecRestoreArrayWrite(v,&va));
503 4 : PetscCall(VecDestroy(&svd->IS[i]));
504 4 : svd->IS[i] = v;
505 : }
506 4 : svd->nini = PetscMin(svd->nini,svd->ninil);
507 4 : PetscCall(EPSSetInitialSpace(cyclic->eps,-svd->nini,svd->IS));
508 4 : PetscCall(SlepcBasisDestroy_Private(&svd->nini,&svd->IS));
509 4 : PetscCall(SlepcBasisDestroy_Private(&svd->ninil,&svd->ISL));
510 : }
511 42 : PetscCall(EPSSetUp(cyclic->eps));
512 42 : PetscCall(EPSGetDimensions(cyclic->eps,NULL,&svd->ncv,&svd->mpd));
513 42 : svd->ncv = PetscMin(svd->ncv,PetscMin(M,N));
514 42 : PetscCall(EPSGetTolerances(cyclic->eps,NULL,&svd->max_it));
515 42 : if (svd->tol==(PetscReal)PETSC_DETERMINE) svd->tol = SLEPC_DEFAULT_TOL;
516 :
517 42 : svd->leftbasis = PETSC_TRUE;
518 42 : PetscCall(SVDAllocateSolution(svd,0));
519 42 : PetscFunctionReturn(PETSC_SUCCESS);
520 : }
521 :
522 8497 : static PetscErrorCode SVDCyclicCheckEigenvalue(SVD svd,PetscScalar er,PetscScalar ei,PetscReal *sigma,PetscBool *isreal)
523 : {
524 8497 : PetscFunctionBegin;
525 8497 : if (svd->ishyperbolic && PetscDefined(USE_COMPLEX) && PetscAbsReal(PetscImaginaryPart(er))>10*PetscAbsReal(PetscRealPart(er))) {
526 228 : *sigma = PetscImaginaryPart(er);
527 228 : if (isreal) *isreal = PETSC_FALSE;
528 8269 : } else if (svd->ishyperbolic && !PetscDefined(USE_COMPLEX) && PetscAbsScalar(ei)>10*PetscAbsScalar(er)) {
529 : *sigma = PetscRealPart(ei);
530 : if (isreal) *isreal = PETSC_FALSE;
531 : } else {
532 8269 : *sigma = PetscRealPart(er);
533 8269 : if (isreal) *isreal = PETSC_TRUE;
534 : }
535 8497 : PetscFunctionReturn(PETSC_SUCCESS);
536 : }
537 :
538 42 : static PetscErrorCode SVDSolve_Cyclic(SVD svd)
539 : {
540 42 : SVD_CYCLIC *cyclic = (SVD_CYCLIC*)svd->data;
541 42 : PetscInt i,j,nconv;
542 42 : PetscScalar er,ei;
543 42 : PetscReal sigma;
544 :
545 42 : PetscFunctionBegin;
546 42 : PetscCall(EPSSolve(cyclic->eps));
547 42 : PetscCall(EPSGetConverged(cyclic->eps,&nconv));
548 42 : PetscCall(EPSGetIterationNumber(cyclic->eps,&svd->its));
549 42 : PetscCall(EPSGetConvergedReason(cyclic->eps,(EPSConvergedReason*)&svd->reason));
550 671 : for (i=0,j=0;i<nconv;i++) {
551 629 : PetscCall(EPSGetEigenvalue(cyclic->eps,i,&er,&ei));
552 629 : PetscCall(SVDCyclicCheckEigenvalue(svd,er,ei,&sigma,NULL));
553 629 : if (sigma>0.0) {
554 428 : if (svd->isgeneralized && svd->which==SVD_SMALLEST) svd->sigma[j] = 1.0/sigma;
555 428 : else svd->sigma[j] = sigma;
556 428 : j++;
557 : }
558 : }
559 42 : svd->nconv = j;
560 42 : PetscFunctionReturn(PETSC_SUCCESS);
561 : }
562 :
563 21 : static PetscErrorCode SVDComputeVectors_Cyclic_Standard(SVD svd)
564 : {
565 21 : SVD_CYCLIC *cyclic = (SVD_CYCLIC*)svd->data;
566 21 : PetscInt i,j,m,nconv;
567 21 : PetscScalar er,ei;
568 21 : PetscReal sigma;
569 21 : const PetscScalar *px;
570 21 : Vec x,x1,x2;
571 :
572 21 : PetscFunctionBegin;
573 21 : PetscCall(MatCreateVecs(cyclic->C,&x,NULL));
574 21 : PetscCall(MatGetLocalSize(svd->A,&m,NULL));
575 21 : PetscCall(MatCreateVecsEmpty(svd->A,&x2,&x1));
576 21 : PetscCall(EPSGetConverged(cyclic->eps,&nconv));
577 188 : for (i=0,j=0;i<nconv;i++) {
578 167 : PetscCall(EPSGetEigenpair(cyclic->eps,i,&er,&ei,x,NULL));
579 167 : PetscCall(SVDCyclicCheckEigenvalue(svd,er,ei,&sigma,NULL));
580 167 : if (sigma<0.0) continue;
581 155 : PetscCall(VecGetArrayRead(x,&px));
582 155 : PetscCall(VecPlaceArray(x1,px));
583 155 : PetscCall(VecPlaceArray(x2,px+m));
584 155 : PetscCall(BVInsertVec(svd->U,j,x1));
585 155 : PetscCall(BVScaleColumn(svd->U,j,PETSC_SQRT2));
586 155 : PetscCall(BVInsertVec(svd->V,j,x2));
587 155 : PetscCall(BVScaleColumn(svd->V,j,PETSC_SQRT2));
588 155 : PetscCall(VecResetArray(x1));
589 155 : PetscCall(VecResetArray(x2));
590 155 : PetscCall(VecRestoreArrayRead(x,&px));
591 155 : j++;
592 : }
593 21 : PetscCall(VecDestroy(&x));
594 21 : PetscCall(VecDestroy(&x1));
595 21 : PetscCall(VecDestroy(&x2));
596 21 : PetscFunctionReturn(PETSC_SUCCESS);
597 : }
598 :
599 10 : static PetscErrorCode SVDComputeVectors_Cyclic_Generalized(SVD svd)
600 : {
601 10 : SVD_CYCLIC *cyclic = (SVD_CYCLIC*)svd->data;
602 10 : PetscInt i,j,m,p,nconv;
603 10 : PetscScalar *dst,er,ei;
604 10 : PetscReal sigma;
605 10 : const PetscScalar *src,*px;
606 10 : Vec u,v,x,x1,x2,uv;
607 :
608 10 : PetscFunctionBegin;
609 10 : PetscCall(MatGetLocalSize(svd->A,&m,NULL));
610 10 : PetscCall(MatGetLocalSize(svd->B,&p,NULL));
611 10 : PetscCall(MatCreateVecs(cyclic->C,&x,NULL));
612 10 : if (svd->which==SVD_SMALLEST) PetscCall(MatCreateVecsEmpty(svd->B,&x1,&x2));
613 10 : else PetscCall(MatCreateVecsEmpty(svd->A,&x2,&x1));
614 10 : PetscCall(MatCreateVecs(svd->A,NULL,&u));
615 10 : PetscCall(MatCreateVecs(svd->B,NULL,&v));
616 10 : PetscCall(EPSGetConverged(cyclic->eps,&nconv));
617 80 : for (i=0,j=0;i<nconv;i++) {
618 70 : PetscCall(EPSGetEigenpair(cyclic->eps,i,&er,&ei,x,NULL));
619 70 : PetscCall(SVDCyclicCheckEigenvalue(svd,er,ei,&sigma,NULL));
620 70 : if (sigma<0.0) continue;
621 70 : if (svd->which==SVD_SMALLEST) {
622 : /* evec_i = 1/sqrt(2)*[ v_i; w_i ], w_i = x_i/c_i */
623 0 : PetscCall(VecGetArrayRead(x,&px));
624 0 : PetscCall(VecPlaceArray(x2,px));
625 0 : PetscCall(VecPlaceArray(x1,px+p));
626 0 : PetscCall(VecCopy(x2,v));
627 0 : PetscCall(VecScale(v,PETSC_SQRT2)); /* v_i = sqrt(2)*evec_i_1 */
628 0 : PetscCall(VecScale(x1,PETSC_SQRT2)); /* w_i = sqrt(2)*evec_i_2 */
629 0 : PetscCall(MatMult(svd->A,x1,u)); /* A*w_i = u_i */
630 0 : PetscCall(VecScale(x1,1.0/PetscSqrtScalar(1.0+sigma*sigma))); /* x_i = w_i*c_i */
631 0 : PetscCall(BVInsertVec(svd->V,j,x1));
632 0 : PetscCall(VecResetArray(x2));
633 0 : PetscCall(VecResetArray(x1));
634 0 : PetscCall(VecRestoreArrayRead(x,&px));
635 : } else {
636 : /* evec_i = 1/sqrt(2)*[ u_i; w_i ], w_i = x_i/s_i */
637 70 : PetscCall(VecGetArrayRead(x,&px));
638 70 : PetscCall(VecPlaceArray(x1,px));
639 70 : PetscCall(VecPlaceArray(x2,px+m));
640 70 : PetscCall(VecCopy(x1,u));
641 70 : PetscCall(VecScale(u,PETSC_SQRT2)); /* u_i = sqrt(2)*evec_i_1 */
642 70 : PetscCall(VecScale(x2,PETSC_SQRT2)); /* w_i = sqrt(2)*evec_i_2 */
643 70 : PetscCall(MatMult(svd->B,x2,v)); /* B*w_i = v_i */
644 70 : PetscCall(VecScale(x2,1.0/PetscSqrtScalar(1.0+sigma*sigma))); /* x_i = w_i*s_i */
645 70 : PetscCall(BVInsertVec(svd->V,j,x2));
646 70 : PetscCall(VecResetArray(x1));
647 70 : PetscCall(VecResetArray(x2));
648 70 : PetscCall(VecRestoreArrayRead(x,&px));
649 : }
650 : /* copy [u;v] to U[j] */
651 70 : PetscCall(BVGetColumn(svd->U,j,&uv));
652 70 : PetscCall(VecGetArrayWrite(uv,&dst));
653 70 : PetscCall(VecGetArrayRead(u,&src));
654 70 : PetscCall(PetscArraycpy(dst,src,m));
655 70 : PetscCall(VecRestoreArrayRead(u,&src));
656 70 : PetscCall(VecGetArrayRead(v,&src));
657 70 : PetscCall(PetscArraycpy(dst+m,src,p));
658 70 : PetscCall(VecRestoreArrayRead(v,&src));
659 70 : PetscCall(VecRestoreArrayWrite(uv,&dst));
660 70 : PetscCall(BVRestoreColumn(svd->U,j,&uv));
661 70 : j++;
662 : }
663 10 : PetscCall(VecDestroy(&x));
664 10 : PetscCall(VecDestroy(&x1));
665 10 : PetscCall(VecDestroy(&x2));
666 10 : PetscCall(VecDestroy(&u));
667 10 : PetscCall(VecDestroy(&v));
668 10 : PetscFunctionReturn(PETSC_SUCCESS);
669 : }
670 :
671 : #if defined(PETSC_USE_COMPLEX)
672 : /* VecMaxAbs: returns the entry of x that has max(abs(x(i))), using w as a workspace vector */
673 4 : static PetscErrorCode VecMaxAbs(Vec x,Vec w,PetscScalar *v)
674 : {
675 4 : PetscMPIInt size,rank,root;
676 4 : const PetscScalar *xx;
677 4 : const PetscInt *ranges;
678 4 : PetscReal val;
679 4 : PetscInt p;
680 :
681 4 : PetscFunctionBegin;
682 4 : PetscCall(VecCopy(x,w));
683 4 : PetscCall(VecAbs(w));
684 4 : PetscCall(VecMax(w,&p,&val));
685 4 : PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)x),&size));
686 4 : PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)x),&rank));
687 4 : PetscCall(VecGetOwnershipRanges(x,&ranges));
688 4 : for (root=0;root<size;root++) if (p>=ranges[root] && p<ranges[root+1]) break;
689 4 : if (rank==root) {
690 4 : PetscCall(VecGetArrayRead(x,&xx));
691 4 : *v = xx[p-ranges[root]];
692 4 : PetscCall(VecRestoreArrayRead(x,&xx));
693 : }
694 8 : PetscCallMPI(MPI_Bcast(v,1,MPIU_SCALAR,root,PetscObjectComm((PetscObject)x)));
695 4 : PetscFunctionReturn(PETSC_SUCCESS);
696 : }
697 : #endif
698 :
699 7 : static PetscErrorCode SVDComputeVectors_Cyclic_Hyperbolic(SVD svd)
700 : {
701 7 : SVD_CYCLIC *cyclic = (SVD_CYCLIC*)svd->data;
702 7 : PetscInt i,j,m,n,nconv;
703 7 : PetscScalar er,ei;
704 7 : PetscReal sigma,nrm;
705 7 : PetscBool isreal;
706 7 : const PetscScalar *px;
707 7 : Vec u,x,xi=NULL,x1,x2,x1i=NULL,x2i;
708 7 : BV U=NULL,V=NULL;
709 : #if !defined(PETSC_USE_COMPLEX)
710 : const PetscScalar *pxi;
711 : PetscReal nrmr,nrmi;
712 : #else
713 7 : PetscScalar alpha;
714 : #endif
715 :
716 7 : PetscFunctionBegin;
717 7 : PetscCall(MatCreateVecs(cyclic->C,&x,svd->ishyperbolic?&xi:NULL));
718 7 : PetscCall(MatGetLocalSize(svd->A,&m,NULL));
719 7 : PetscCall(MatCreateVecsEmpty(svd->OP,&x2,&x1));
720 : #if defined(PETSC_USE_COMPLEX)
721 7 : PetscCall(MatCreateVecs(svd->OP,&x2i,&x1i));
722 : #else
723 : PetscCall(MatCreateVecsEmpty(svd->OP,&x2i,&x1i));
724 : #endif
725 : /* set-up Omega-normalization of U */
726 7 : U = svd->swapped? svd->V: svd->U;
727 7 : V = svd->swapped? svd->U: svd->V;
728 7 : PetscCall(BVGetSizes(U,&n,NULL,NULL));
729 7 : PetscCall(BV_SetMatrixDiagonal(U,svd->omega,svd->A));
730 7 : PetscCall(EPSGetConverged(cyclic->eps,&nconv));
731 388 : for (i=0,j=0;i<nconv;i++) {
732 381 : PetscCall(EPSGetEigenpair(cyclic->eps,i,&er,&ei,x,xi));
733 381 : PetscCall(SVDCyclicCheckEigenvalue(svd,er,ei,&sigma,&isreal));
734 381 : if (sigma<0.0) continue;
735 192 : PetscCall(VecGetArrayRead(x,&px));
736 192 : if (svd->swapped) {
737 14 : PetscCall(VecPlaceArray(x2,px));
738 14 : PetscCall(VecPlaceArray(x1,px+m));
739 : } else {
740 178 : PetscCall(VecPlaceArray(x1,px));
741 178 : PetscCall(VecPlaceArray(x2,px+n));
742 : }
743 : #if defined(PETSC_USE_COMPLEX)
744 192 : PetscCall(BVInsertVec(U,j,x1));
745 192 : PetscCall(BVInsertVec(V,j,x2));
746 192 : if (!isreal) {
747 4 : PetscCall(VecMaxAbs(x1,x1i,&alpha));
748 4 : PetscCall(BVScaleColumn(U,j,PetscAbsScalar(alpha)/alpha));
749 4 : PetscCall(BVScaleColumn(V,j,PetscAbsScalar(alpha)/(alpha*PETSC_i)));
750 : }
751 : #else
752 : PetscCall(VecGetArrayRead(xi,&pxi));
753 : if (svd->swapped) {
754 : PetscCall(VecPlaceArray(x2i,pxi));
755 : PetscCall(VecPlaceArray(x1i,pxi+m));
756 : } else {
757 : PetscCall(VecPlaceArray(x1i,pxi));
758 : PetscCall(VecPlaceArray(x2i,pxi+n));
759 : }
760 : PetscCall(VecNorm(x2,NORM_2,&nrmr));
761 : PetscCall(VecNorm(x2i,NORM_2,&nrmi));
762 : if (nrmi>nrmr) {
763 : if (isreal) {
764 : PetscCall(BVInsertVec(U,j,x1i));
765 : PetscCall(BVInsertVec(V,j,x2i));
766 : } else {
767 : PetscCall(BVInsertVec(U,j,x1));
768 : PetscCall(BVInsertVec(V,j,x2i));
769 : }
770 : } else {
771 : if (isreal) {
772 : PetscCall(BVInsertVec(U,j,x1));
773 : PetscCall(BVInsertVec(V,j,x2));
774 : } else {
775 : PetscCall(BVInsertVec(U,j,x1i));
776 : PetscCall(BVScaleColumn(U,j,-1.0));
777 : PetscCall(BVInsertVec(V,j,x2));
778 : }
779 : }
780 : PetscCall(VecResetArray(x1i));
781 : PetscCall(VecResetArray(x2i));
782 : PetscCall(VecRestoreArrayRead(xi,&pxi));
783 : #endif
784 192 : PetscCall(VecResetArray(x1));
785 192 : PetscCall(VecResetArray(x2));
786 192 : PetscCall(VecRestoreArrayRead(x,&px));
787 192 : PetscCall(BVGetColumn(U,j,&u));
788 192 : PetscCall(VecPointwiseMult(u,u,svd->omega));
789 192 : PetscCall(BVRestoreColumn(U,j,&u));
790 192 : PetscCall(BVNormColumn(U,j,NORM_2,&nrm));
791 192 : PetscCall(BVScaleColumn(U,j,1.0/PetscAbs(nrm)));
792 192 : svd->sign[j] = PetscSign(nrm);
793 192 : PetscCall(BVNormColumn(V,j,NORM_2,&nrm));
794 192 : PetscCall(BVScaleColumn(V,j,1.0/nrm));
795 192 : j++;
796 : }
797 7 : PetscCall(VecDestroy(&x));
798 7 : PetscCall(VecDestroy(&x1));
799 7 : PetscCall(VecDestroy(&x2));
800 7 : PetscCall(VecDestroy(&xi));
801 7 : PetscCall(VecDestroy(&x1i));
802 7 : PetscCall(VecDestroy(&x2i));
803 7 : PetscFunctionReturn(PETSC_SUCCESS);
804 : }
805 :
806 38 : static PetscErrorCode SVDComputeVectors_Cyclic(SVD svd)
807 : {
808 38 : PetscFunctionBegin;
809 38 : switch (svd->problem_type) {
810 21 : case SVD_STANDARD:
811 21 : PetscCall(SVDComputeVectors_Cyclic_Standard(svd));
812 : break;
813 10 : case SVD_GENERALIZED:
814 10 : PetscCall(SVDComputeVectors_Cyclic_Generalized(svd));
815 : break;
816 7 : case SVD_HYPERBOLIC:
817 7 : PetscCall(SVDComputeVectors_Cyclic_Hyperbolic(svd));
818 : break;
819 0 : default:
820 0 : SETERRQ(PetscObjectComm((PetscObject)svd),PETSC_ERR_ARG_WRONG,"Unknown singular value problem type");
821 : }
822 38 : PetscFunctionReturn(PETSC_SUCCESS);
823 : }
824 :
825 509 : static PetscErrorCode EPSMonitor_Cyclic(EPS eps,PetscInt its,PetscInt nconv,PetscScalar *eigr,PetscScalar *eigi,PetscReal *errest,PetscInt nest,void *ctx)
826 : {
827 509 : PetscInt i,j;
828 509 : SVD svd = (SVD)ctx;
829 509 : PetscScalar er,ei;
830 509 : PetscReal sigma;
831 509 : ST st;
832 :
833 509 : PetscFunctionBegin;
834 509 : nconv = 0;
835 509 : PetscCall(EPSGetST(eps,&st));
836 7759 : for (i=0,j=0;i<PetscMin(nest,svd->ncv);i++) {
837 7250 : er = eigr[i]; ei = eigi[i];
838 7250 : PetscCall(STBackTransform(st,1,&er,&ei));
839 7250 : PetscCall(SVDCyclicCheckEigenvalue(svd,er,ei,&sigma,NULL));
840 7250 : if (sigma>0.0) {
841 4713 : svd->sigma[j] = sigma;
842 4713 : svd->errest[j] = errest[i];
843 4713 : if (errest[i] && errest[i] < svd->tol) nconv++;
844 4713 : j++;
845 : }
846 : }
847 509 : nest = j;
848 509 : PetscCall(SVDMonitor(svd,its,nconv,svd->sigma,svd->errest,nest));
849 509 : PetscFunctionReturn(PETSC_SUCCESS);
850 : }
851 :
852 30 : static PetscErrorCode SVDSetFromOptions_Cyclic(SVD svd,PetscOptionItems *PetscOptionsObject)
853 : {
854 30 : PetscBool set,val;
855 30 : SVD_CYCLIC *cyclic = (SVD_CYCLIC*)svd->data;
856 30 : ST st;
857 :
858 30 : PetscFunctionBegin;
859 30 : PetscOptionsHeadBegin(PetscOptionsObject,"SVD Cyclic Options");
860 :
861 30 : PetscCall(PetscOptionsBool("-svd_cyclic_explicitmatrix","Use cyclic explicit matrix","SVDCyclicSetExplicitMatrix",cyclic->explicitmatrix,&val,&set));
862 30 : if (set) PetscCall(SVDCyclicSetExplicitMatrix(svd,val));
863 :
864 30 : PetscOptionsHeadEnd();
865 :
866 30 : if (!cyclic->eps) PetscCall(SVDCyclicGetEPS(svd,&cyclic->eps));
867 30 : if (!cyclic->explicitmatrix && !cyclic->usereps) {
868 : /* use as default an ST with shell matrix and Jacobi */
869 18 : PetscCall(EPSGetST(cyclic->eps,&st));
870 18 : PetscCall(STSetMatMode(st,ST_MATMODE_SHELL));
871 : }
872 30 : PetscCall(EPSSetFromOptions(cyclic->eps));
873 30 : PetscFunctionReturn(PETSC_SUCCESS);
874 : }
875 :
876 19 : static PetscErrorCode SVDCyclicSetExplicitMatrix_Cyclic(SVD svd,PetscBool explicitmat)
877 : {
878 19 : SVD_CYCLIC *cyclic = (SVD_CYCLIC*)svd->data;
879 :
880 19 : PetscFunctionBegin;
881 19 : if (cyclic->explicitmatrix != explicitmat) {
882 12 : cyclic->explicitmatrix = explicitmat;
883 12 : svd->state = SVD_STATE_INITIAL;
884 : }
885 19 : PetscFunctionReturn(PETSC_SUCCESS);
886 : }
887 :
888 : /*@
889 : SVDCyclicSetExplicitMatrix - Indicate if the eigensolver operator
890 : H(A) = [ 0 A ; A^T 0 ] must be computed explicitly.
891 :
892 : Logically Collective
893 :
894 : Input Parameters:
895 : + svd - singular value solver
896 : - explicitmat - boolean flag indicating if H(A) is built explicitly
897 :
898 : Options Database Key:
899 : . -svd_cyclic_explicitmatrix <boolean> - Indicates the boolean flag
900 :
901 : Level: advanced
902 :
903 : .seealso: SVDCyclicGetExplicitMatrix()
904 : @*/
905 19 : PetscErrorCode SVDCyclicSetExplicitMatrix(SVD svd,PetscBool explicitmat)
906 : {
907 19 : PetscFunctionBegin;
908 19 : PetscValidHeaderSpecific(svd,SVD_CLASSID,1);
909 57 : PetscValidLogicalCollectiveBool(svd,explicitmat,2);
910 19 : PetscTryMethod(svd,"SVDCyclicSetExplicitMatrix_C",(SVD,PetscBool),(svd,explicitmat));
911 19 : PetscFunctionReturn(PETSC_SUCCESS);
912 : }
913 :
914 1 : static PetscErrorCode SVDCyclicGetExplicitMatrix_Cyclic(SVD svd,PetscBool *explicitmat)
915 : {
916 1 : SVD_CYCLIC *cyclic = (SVD_CYCLIC*)svd->data;
917 :
918 1 : PetscFunctionBegin;
919 1 : *explicitmat = cyclic->explicitmatrix;
920 1 : PetscFunctionReturn(PETSC_SUCCESS);
921 : }
922 :
923 : /*@
924 : SVDCyclicGetExplicitMatrix - Returns the flag indicating if H(A) is built explicitly.
925 :
926 : Not Collective
927 :
928 : Input Parameter:
929 : . svd - singular value solver
930 :
931 : Output Parameter:
932 : . explicitmat - the mode flag
933 :
934 : Level: advanced
935 :
936 : .seealso: SVDCyclicSetExplicitMatrix()
937 : @*/
938 1 : PetscErrorCode SVDCyclicGetExplicitMatrix(SVD svd,PetscBool *explicitmat)
939 : {
940 1 : PetscFunctionBegin;
941 1 : PetscValidHeaderSpecific(svd,SVD_CLASSID,1);
942 1 : PetscAssertPointer(explicitmat,2);
943 1 : PetscUseMethod(svd,"SVDCyclicGetExplicitMatrix_C",(SVD,PetscBool*),(svd,explicitmat));
944 1 : PetscFunctionReturn(PETSC_SUCCESS);
945 : }
946 :
947 1 : static PetscErrorCode SVDCyclicSetEPS_Cyclic(SVD svd,EPS eps)
948 : {
949 1 : SVD_CYCLIC *cyclic = (SVD_CYCLIC*)svd->data;
950 :
951 1 : PetscFunctionBegin;
952 1 : PetscCall(PetscObjectReference((PetscObject)eps));
953 1 : PetscCall(EPSDestroy(&cyclic->eps));
954 1 : cyclic->eps = eps;
955 1 : cyclic->usereps = PETSC_TRUE;
956 1 : svd->state = SVD_STATE_INITIAL;
957 1 : PetscFunctionReturn(PETSC_SUCCESS);
958 : }
959 :
960 : /*@
961 : SVDCyclicSetEPS - Associate an eigensolver object (EPS) to the
962 : singular value solver.
963 :
964 : Collective
965 :
966 : Input Parameters:
967 : + svd - singular value solver
968 : - eps - the eigensolver object
969 :
970 : Level: advanced
971 :
972 : .seealso: SVDCyclicGetEPS()
973 : @*/
974 1 : PetscErrorCode SVDCyclicSetEPS(SVD svd,EPS eps)
975 : {
976 1 : PetscFunctionBegin;
977 1 : PetscValidHeaderSpecific(svd,SVD_CLASSID,1);
978 1 : PetscValidHeaderSpecific(eps,EPS_CLASSID,2);
979 1 : PetscCheckSameComm(svd,1,eps,2);
980 1 : PetscTryMethod(svd,"SVDCyclicSetEPS_C",(SVD,EPS),(svd,eps));
981 1 : PetscFunctionReturn(PETSC_SUCCESS);
982 : }
983 :
984 31 : static PetscErrorCode SVDCyclicGetEPS_Cyclic(SVD svd,EPS *eps)
985 : {
986 31 : SVD_CYCLIC *cyclic = (SVD_CYCLIC*)svd->data;
987 :
988 31 : PetscFunctionBegin;
989 31 : if (!cyclic->eps) {
990 31 : PetscCall(EPSCreate(PetscObjectComm((PetscObject)svd),&cyclic->eps));
991 31 : PetscCall(PetscObjectIncrementTabLevel((PetscObject)cyclic->eps,(PetscObject)svd,1));
992 31 : PetscCall(EPSSetOptionsPrefix(cyclic->eps,((PetscObject)svd)->prefix));
993 31 : PetscCall(EPSAppendOptionsPrefix(cyclic->eps,"svd_cyclic_"));
994 31 : PetscCall(PetscObjectSetOptions((PetscObject)cyclic->eps,((PetscObject)svd)->options));
995 31 : PetscCall(EPSSetWhichEigenpairs(cyclic->eps,EPS_LARGEST_REAL));
996 31 : PetscCall(EPSMonitorSet(cyclic->eps,EPSMonitor_Cyclic,svd,NULL));
997 : }
998 31 : *eps = cyclic->eps;
999 31 : PetscFunctionReturn(PETSC_SUCCESS);
1000 : }
1001 :
1002 : /*@
1003 : SVDCyclicGetEPS - Retrieve the eigensolver object (EPS) associated
1004 : to the singular value solver.
1005 :
1006 : Collective
1007 :
1008 : Input Parameter:
1009 : . svd - singular value solver
1010 :
1011 : Output Parameter:
1012 : . eps - the eigensolver object
1013 :
1014 : Level: advanced
1015 :
1016 : .seealso: SVDCyclicSetEPS()
1017 : @*/
1018 31 : PetscErrorCode SVDCyclicGetEPS(SVD svd,EPS *eps)
1019 : {
1020 31 : PetscFunctionBegin;
1021 31 : PetscValidHeaderSpecific(svd,SVD_CLASSID,1);
1022 31 : PetscAssertPointer(eps,2);
1023 31 : PetscUseMethod(svd,"SVDCyclicGetEPS_C",(SVD,EPS*),(svd,eps));
1024 31 : PetscFunctionReturn(PETSC_SUCCESS);
1025 : }
1026 :
1027 1 : static PetscErrorCode SVDView_Cyclic(SVD svd,PetscViewer viewer)
1028 : {
1029 1 : SVD_CYCLIC *cyclic = (SVD_CYCLIC*)svd->data;
1030 1 : PetscBool isascii;
1031 :
1032 1 : PetscFunctionBegin;
1033 1 : PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii));
1034 1 : if (isascii) {
1035 1 : if (!cyclic->eps) PetscCall(SVDCyclicGetEPS(svd,&cyclic->eps));
1036 1 : PetscCall(PetscViewerASCIIPrintf(viewer," %s matrix\n",cyclic->explicitmatrix?"explicit":"implicit"));
1037 1 : PetscCall(PetscViewerASCIIPushTab(viewer));
1038 1 : PetscCall(EPSView(cyclic->eps,viewer));
1039 1 : PetscCall(PetscViewerASCIIPopTab(viewer));
1040 : }
1041 1 : PetscFunctionReturn(PETSC_SUCCESS);
1042 : }
1043 :
1044 33 : static PetscErrorCode SVDReset_Cyclic(SVD svd)
1045 : {
1046 33 : SVD_CYCLIC *cyclic = (SVD_CYCLIC*)svd->data;
1047 :
1048 33 : PetscFunctionBegin;
1049 33 : PetscCall(EPSReset(cyclic->eps));
1050 33 : PetscCall(MatDestroy(&cyclic->C));
1051 33 : PetscCall(MatDestroy(&cyclic->D));
1052 33 : PetscFunctionReturn(PETSC_SUCCESS);
1053 : }
1054 :
1055 32 : static PetscErrorCode SVDDestroy_Cyclic(SVD svd)
1056 : {
1057 32 : SVD_CYCLIC *cyclic = (SVD_CYCLIC*)svd->data;
1058 :
1059 32 : PetscFunctionBegin;
1060 32 : PetscCall(EPSDestroy(&cyclic->eps));
1061 32 : PetscCall(PetscFree(svd->data));
1062 32 : PetscCall(PetscObjectComposeFunction((PetscObject)svd,"SVDCyclicSetEPS_C",NULL));
1063 32 : PetscCall(PetscObjectComposeFunction((PetscObject)svd,"SVDCyclicGetEPS_C",NULL));
1064 32 : PetscCall(PetscObjectComposeFunction((PetscObject)svd,"SVDCyclicSetExplicitMatrix_C",NULL));
1065 32 : PetscCall(PetscObjectComposeFunction((PetscObject)svd,"SVDCyclicGetExplicitMatrix_C",NULL));
1066 32 : PetscFunctionReturn(PETSC_SUCCESS);
1067 : }
1068 :
1069 32 : SLEPC_EXTERN PetscErrorCode SVDCreate_Cyclic(SVD svd)
1070 : {
1071 32 : SVD_CYCLIC *cyclic;
1072 :
1073 32 : PetscFunctionBegin;
1074 32 : PetscCall(PetscNew(&cyclic));
1075 32 : svd->data = (void*)cyclic;
1076 32 : svd->ops->solve = SVDSolve_Cyclic;
1077 32 : svd->ops->solveg = SVDSolve_Cyclic;
1078 32 : svd->ops->solveh = SVDSolve_Cyclic;
1079 32 : svd->ops->setup = SVDSetUp_Cyclic;
1080 32 : svd->ops->setfromoptions = SVDSetFromOptions_Cyclic;
1081 32 : svd->ops->destroy = SVDDestroy_Cyclic;
1082 32 : svd->ops->reset = SVDReset_Cyclic;
1083 32 : svd->ops->view = SVDView_Cyclic;
1084 32 : svd->ops->computevectors = SVDComputeVectors_Cyclic;
1085 32 : PetscCall(PetscObjectComposeFunction((PetscObject)svd,"SVDCyclicSetEPS_C",SVDCyclicSetEPS_Cyclic));
1086 32 : PetscCall(PetscObjectComposeFunction((PetscObject)svd,"SVDCyclicGetEPS_C",SVDCyclicGetEPS_Cyclic));
1087 32 : PetscCall(PetscObjectComposeFunction((PetscObject)svd,"SVDCyclicSetExplicitMatrix_C",SVDCyclicSetExplicitMatrix_Cyclic));
1088 32 : PetscCall(PetscObjectComposeFunction((PetscObject)svd,"SVDCyclicGetExplicitMatrix_C",SVDCyclicGetExplicitMatrix_Cyclic));
1089 32 : PetscFunctionReturn(PETSC_SUCCESS);
1090 : }
|