Actual source code: pipegcr.c
petsc-3.13.6 2020-09-29
1: /*
2: Contributed by Sascha M. Schnepp and Patrick Sanan
3: */
5: #include "petscsys.h"
6: #include <../src/ksp/ksp/impls/gcr/pipegcr/pipegcrimpl.h>
8: static PetscBool cited = PETSC_FALSE;
9: static const char citation[] =
10: "@article{SSM2016,\n"
11: " author = {P. Sanan and S.M. Schnepp and D.A. May},\n"
12: " title = {Pipelined, Flexible Krylov Subspace Methods},\n"
13: " journal = {SIAM Journal on Scientific Computing},\n"
14: " volume = {38},\n"
15: " number = {5},\n"
16: " pages = {C441-C470},\n"
17: " year = {2016},\n"
18: " doi = {10.1137/15M1049130},\n"
19: " URL = {http://dx.doi.org/10.1137/15M1049130},\n"
20: " eprint = {http://dx.doi.org/10.1137/15M1049130}\n"
21: "}\n";
23: #define KSPPIPEGCR_DEFAULT_MMAX 15
24: #define KSPPIPEGCR_DEFAULT_NPREALLOC 5
25: #define KSPPIPEGCR_DEFAULT_VECB 5
26: #define KSPPIPEGCR_DEFAULT_TRUNCSTRAT KSP_FCD_TRUNC_TYPE_NOTAY
27: #define KSPPIPEGCR_DEFAULT_UNROLL_W PETSC_TRUE
29: #include <petscksp.h>
31: static PetscErrorCode KSPAllocateVectors_PIPEGCR(KSP ksp, PetscInt nvecsneeded, PetscInt chunksize)
32: {
33: PetscErrorCode ierr;
34: PetscInt i;
35: KSP_PIPEGCR *pipegcr;
36: PetscInt nnewvecs, nvecsprev;
39: pipegcr = (KSP_PIPEGCR*)ksp->data;
41: /* Allocate enough new vectors to add chunksize new vectors, reach nvecsneedtotal, or to reach mmax+1, whichever is smallest */
42: if(pipegcr->nvecs < PetscMin(pipegcr->mmax+1,nvecsneeded)){
43: nvecsprev = pipegcr->nvecs;
44: nnewvecs = PetscMin(PetscMax(nvecsneeded-pipegcr->nvecs,chunksize),pipegcr->mmax+1-pipegcr->nvecs);
45: KSPCreateVecs(ksp,nnewvecs,&pipegcr->ppvecs[pipegcr->nchunks],0,NULL);
46: PetscLogObjectParents((PetscObject)ksp,nnewvecs,pipegcr->ppvecs[pipegcr->nchunks]);
47: KSPCreateVecs(ksp,nnewvecs,&pipegcr->psvecs[pipegcr->nchunks],0,NULL);
48: PetscLogObjectParents((PetscObject)ksp,nnewvecs,pipegcr->psvecs[pipegcr->nchunks]);
49: KSPCreateVecs(ksp,nnewvecs,&pipegcr->pqvecs[pipegcr->nchunks],0,NULL);
50: PetscLogObjectParents((PetscObject)ksp,nnewvecs,pipegcr->pqvecs[pipegcr->nchunks]);
51: if (pipegcr->unroll_w) {
52: KSPCreateVecs(ksp,nnewvecs,&pipegcr->ptvecs[pipegcr->nchunks],0,NULL);
53: PetscLogObjectParents((PetscObject)ksp,nnewvecs,pipegcr->ptvecs[pipegcr->nchunks]);
54: }
55: pipegcr->nvecs += nnewvecs;
56: for(i=0;i<nnewvecs;i++){
57: pipegcr->qvecs[nvecsprev+i] = pipegcr->pqvecs[pipegcr->nchunks][i];
58: pipegcr->pvecs[nvecsprev+i] = pipegcr->ppvecs[pipegcr->nchunks][i];
59: pipegcr->svecs[nvecsprev+i] = pipegcr->psvecs[pipegcr->nchunks][i];
60: if (pipegcr->unroll_w) {
61: pipegcr->tvecs[nvecsprev+i] = pipegcr->ptvecs[pipegcr->nchunks][i];
62: }
63: }
64: pipegcr->chunksizes[pipegcr->nchunks] = nnewvecs;
65: pipegcr->nchunks++;
66: }
67: return(0);
68: }
70: static PetscErrorCode KSPSolve_PIPEGCR_cycle(KSP ksp)
71: {
72: KSP_PIPEGCR *pipegcr = (KSP_PIPEGCR*)ksp->data;
74: Mat A, B;
75: Vec x,r,b,z,w,m,n,p,s,q,t,*redux;
76: PetscInt i,j,k,idx,kdx,mi;
77: PetscScalar alpha=0.0,gamma,*betas,*dots;
78: PetscReal rnorm=0.0, delta,*eta,*etas;
82: /* !!PS We have not checked these routines for use with complex numbers. The inner products
83: are likely not defined correctly for that case */
84: #if (defined(PETSC_USE_COMPLEX) && !defined(PETSC_SKIP_COMPLEX))
85: SETERRQ(PETSC_COMM_WORLD,PETSC_ERR_SUP,"PIPEGCR has not been implemented for use with complex scalars");
86: #endif
88: KSPGetOperators(ksp, &A, &B);
89: x = ksp->vec_sol;
90: b = ksp->vec_rhs;
91: r = ksp->work[0];
92: z = ksp->work[1];
93: w = ksp->work[2]; /* w = Az = AB(r) (pipelining intermediate) */
94: m = ksp->work[3]; /* m = B(w) = B(Az) = B(AB(r)) (pipelining intermediate) */
95: n = ksp->work[4]; /* n = AB(w) = AB(Az) = AB(AB(r)) (pipelining intermediate) */
96: p = pipegcr->pvecs[0];
97: s = pipegcr->svecs[0];
98: q = pipegcr->qvecs[0];
99: t = pipegcr->unroll_w ? pipegcr->tvecs[0] : NULL;
101: redux = pipegcr->redux;
102: dots = pipegcr->dots;
103: etas = pipegcr->etas;
104: betas = dots; /* dots takes the result of all dot products of which the betas are a subset */
106: /* cycle initial residual */
107: KSP_MatMult(ksp,A,x,r);
108: VecAYPX(r,-1.0,b); /* r <- b - Ax */
109: KSP_PCApply(ksp,r,z); /* z <- B(r) */
110: KSP_MatMult(ksp,A,z,w); /* w <- Az */
112: /* initialization of other variables and pipelining intermediates */
113: VecCopy(z,p);
114: KSP_MatMult(ksp,A,p,s);
116: /* overlap initial computation of delta, gamma */
117: redux[0] = w;
118: redux[1] = r;
119: VecMDotBegin(w,2,redux,dots); /* Start split reductions for gamma = (w,r), delta = (w,w) */
120: PetscCommSplitReductionBegin(PetscObjectComm((PetscObject)s)); /* perform asynchronous reduction */
121: KSP_PCApply(ksp,s,q); /* q = B(s) */
122: if (pipegcr->unroll_w) {
123: KSP_MatMult(ksp,A,q,t); /* t = Aq */
124: }
125: VecMDotEnd(w,2,redux,dots); /* Finish split reduction */
126: delta = PetscRealPart(dots[0]);
127: etas[0] = delta;
128: gamma = dots[1];
129: alpha = gamma/delta;
131: i = 0;
132: do {
133: PetscObjectSAWsTakeAccess((PetscObject)ksp);
134: ksp->its++;
135: PetscObjectSAWsGrantAccess((PetscObject)ksp);
137: /* update solution, residuals, .. */
138: VecAXPY(x,+alpha,p);
139: VecAXPY(r,-alpha,s);
140: VecAXPY(z,-alpha,q);
141: if(pipegcr->unroll_w){
142: VecAXPY(w,-alpha,t);
143: } else {
144: KSP_MatMult(ksp,A,z,w);
145: }
147: /* Computations of current iteration done */
148: i++;
150: if (pipegcr->modifypc) {
151: (*pipegcr->modifypc)(ksp,ksp->its,ksp->rnorm,pipegcr->modifypc_ctx);
152: }
154: /* If needbe, allocate a new chunk of vectors */
155: KSPAllocateVectors_PIPEGCR(ksp,i+1,pipegcr->vecb);
157: /* Note that we wrap around and start clobbering old vectors */
158: idx = i % (pipegcr->mmax+1);
159: p = pipegcr->pvecs[idx];
160: s = pipegcr->svecs[idx];
161: q = pipegcr->qvecs[idx];
162: if (pipegcr->unroll_w) {
163: t = pipegcr->tvecs[idx];
164: }
165: eta = pipegcr->etas+idx;
167: /* number of old directions to orthogonalize against */
168: switch(pipegcr->truncstrat){
169: case KSP_FCD_TRUNC_TYPE_STANDARD:
170: mi = pipegcr->mmax;
171: break;
172: case KSP_FCD_TRUNC_TYPE_NOTAY:
173: mi = ((i-1) % pipegcr->mmax)+1;
174: break;
175: default:
176: SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Unrecognized Truncation Strategy");
177: }
179: /* Pick old p,s,q,zeta in a way suitable for VecMDot */
180: for(k=PetscMax(0,i-mi),j=0;k<i;j++,k++){
181: kdx = k % (pipegcr->mmax+1);
182: pipegcr->pold[j] = pipegcr->pvecs[kdx];
183: pipegcr->sold[j] = pipegcr->svecs[kdx];
184: pipegcr->qold[j] = pipegcr->qvecs[kdx];
185: if (pipegcr->unroll_w) {
186: pipegcr->told[j] = pipegcr->tvecs[kdx];
187: }
188: redux[j] = pipegcr->svecs[kdx];
189: }
190: /* If the above loop is not run redux contains only r and w => all beta_k = 0, only gamma, delta != 0 */
191: redux[j] = r;
192: redux[j+1] = w;
194: /* Dot products */
195: /* Start split reductions for beta_k = (w,s_k), gamma = (w,r), delta = (w,w) */
196: VecMDotBegin(w,j+2,redux,dots);
197: PetscCommSplitReductionBegin(PetscObjectComm((PetscObject)w));
199: /* B(w-r) + u stabilization */
200: VecWAXPY(n,-1.0,r,w); /* m = u + B(w-r): (a) ntmp = w-r */
201: KSP_PCApply(ksp,n,m); /* m = u + B(w-r): (b) mtmp = B(ntmp) = B(w-r) */
202: VecAXPY(m,1.0,z); /* m = u + B(w-r): (c) m = z + mtmp */
203: if(pipegcr->unroll_w){
204: KSP_MatMult(ksp,A,m,n); /* n = Am */
205: }
207: /* Finish split reductions for beta_k = (w,s_k), gamma = (w,r), delta = (w,w) */
208: VecMDotEnd(w,j+2,redux,dots);
209: gamma = dots[j];
210: delta = PetscRealPart(dots[j+1]);
212: /* compute new residual norm.
213: this cannot be done before this point so that the natural norm
214: is available for free and the communication involved is overlapped */
215: switch (ksp->normtype) {
216: case KSP_NORM_PRECONDITIONED:
217: VecNorm(z,NORM_2,&rnorm); /* ||r|| <- sqrt(z'*z) */
218: break;
219: case KSP_NORM_UNPRECONDITIONED:
220: VecNorm(r,NORM_2,&rnorm); /* ||r|| <- sqrt(r'*r) */
221: break;
222: case KSP_NORM_NATURAL:
223: rnorm = PetscSqrtReal(PetscAbsScalar(gamma)); /* ||r|| <- sqrt(r,w) */
224: break;
225: case KSP_NORM_NONE:
226: rnorm = 0.0;
227: break;
228: default: SETERRQ1(PetscObjectComm((PetscObject)ksp),PETSC_ERR_SUP,"%s",KSPNormTypes[ksp->normtype]);
229: }
231: /* Check for convergence */
232: PetscObjectSAWsTakeAccess((PetscObject)ksp);
233: ksp->rnorm = rnorm;
234: PetscObjectSAWsGrantAccess((PetscObject)ksp);
235: KSPLogResidualHistory(ksp,rnorm);
236: KSPMonitor(ksp,ksp->its,rnorm);
237: (*ksp->converged)(ksp,ksp->its+1,rnorm,&ksp->reason,ksp->cnvP);
238: if (ksp->reason) break;
240: /* compute new eta and scale beta */
241: *eta = 0.;
242: for(k=PetscMax(0,i-mi),j=0;k<i;j++,k++){
243: kdx = k % (pipegcr->mmax+1);
244: betas[j] /= -etas[kdx]; /* betak /= etak */
245: *eta -= ((PetscReal)(PetscAbsScalar(betas[j])*PetscAbsScalar(betas[j]))) * etas[kdx];
246: /* etaitmp = -betaik^2 * etak */
247: }
248: *eta += delta; /* etai = delta -betaik^2 * etak */
250: /* check breakdown of eta = (s,s) */
251: if(*eta < 0.) {
252: pipegcr->norm_breakdown = PETSC_TRUE;
253: PetscInfo1(ksp,"Restart due to square root breakdown at it = \n",ksp->its);
254: break;
255: } else {
256: alpha= gamma/(*eta); /* alpha = gamma/etai */
257: }
259: /* project out stored search directions using classical G-S */
260: VecCopy(z,p);
261: VecCopy(w,s);
262: VecCopy(m,q);
263: if(pipegcr->unroll_w){
264: VecCopy(n,t);
265: VecMAXPY(t,j,betas,pipegcr->told); /* ti <- n - sum_k beta_k t_k */
266: }
267: VecMAXPY(p,j,betas,pipegcr->pold); /* pi <- ui - sum_k beta_k p_k */
268: VecMAXPY(s,j,betas,pipegcr->sold); /* si <- wi - sum_k beta_k s_k */
269: VecMAXPY(q,j,betas,pipegcr->qold); /* qi <- m - sum_k beta_k q_k */
271: } while (ksp->its < ksp->max_it);
272: return(0);
273: }
275: static PetscErrorCode KSPSolve_PIPEGCR(KSP ksp)
276: {
277: KSP_PIPEGCR *pipegcr = (KSP_PIPEGCR*)ksp->data;
279: Mat A, B;
280: Vec x,b,r,z,w;
281: PetscScalar gamma;
282: PetscReal rnorm=0.0;
283: PetscBool issym;
286: PetscCitationsRegister(citation,&cited);
288: KSPGetOperators(ksp, &A, &B);
289: x = ksp->vec_sol;
290: b = ksp->vec_rhs;
291: r = ksp->work[0];
292: z = ksp->work[1];
293: w = ksp->work[2]; /* w = Az = AB(r) (pipelining intermediate) */
295: /* compute initial residual */
296: if (!ksp->guess_zero) {
297: KSP_MatMult(ksp,A,x,r);
298: VecAYPX(r,-1.0,b); /* r <- b - Ax */
299: } else {
300: VecCopy(b,r); /* r <- b */
301: }
303: /* initial residual norm */
304: KSP_PCApply(ksp,r,z); /* z <- B(r) */
305: KSP_MatMult(ksp,A,z,w); /* w <- Az */
306: VecDot(r,w,&gamma); /* gamma = (r,w) */
308: switch (ksp->normtype) {
309: case KSP_NORM_PRECONDITIONED:
310: VecNorm(z,NORM_2,&rnorm); /* ||r|| <- sqrt(z'*z) */
311: break;
312: case KSP_NORM_UNPRECONDITIONED:
313: VecNorm(r,NORM_2,&rnorm); /* ||r|| <- sqrt(r'*r) */
314: break;
315: case KSP_NORM_NATURAL:
316: rnorm = PetscSqrtReal(PetscAbsScalar(gamma)); /* ||r|| <- sqrt(r,w) */
317: break;
318: case KSP_NORM_NONE:
319: rnorm = 0.0;
320: break;
321: default: SETERRQ1(PetscObjectComm((PetscObject)ksp),PETSC_ERR_SUP,"%s",KSPNormTypes[ksp->normtype]);
322: }
324: /* Is A symmetric? */
325: PetscObjectTypeCompareAny((PetscObject)A,&issym,MATSBAIJ,MATSEQSBAIJ,MATMPISBAIJ,"");
326: if (!issym) {
327: PetscInfo(A,"Matrix type is not any of MATSBAIJ,MATSEQSBAIJ,MATMPISBAIJ. Is matrix A symmetric (as required by CR methods)?");
328: }
330: /* logging */
331: PetscObjectSAWsTakeAccess((PetscObject)ksp);
332: ksp->its = 0;
333: ksp->rnorm0 = rnorm;
334: PetscObjectSAWsGrantAccess((PetscObject)ksp);
335: KSPLogResidualHistory(ksp,ksp->rnorm0);
336: KSPMonitor(ksp,ksp->its,ksp->rnorm0);
337: (*ksp->converged)(ksp,ksp->its,ksp->rnorm0,&ksp->reason,ksp->cnvP);
338: if (ksp->reason) return(0);
340: do {
341: KSPSolve_PIPEGCR_cycle(ksp);
342: if (ksp->reason) break;
343: if (pipegcr->norm_breakdown) {
344: pipegcr->n_restarts++;
345: pipegcr->norm_breakdown = PETSC_FALSE;
346: }
347: } while (ksp->its < ksp->max_it);
349: if (ksp->its >= ksp->max_it) ksp->reason = KSP_DIVERGED_ITS;
350: return(0);
351: }
353: static PetscErrorCode KSPView_PIPEGCR(KSP ksp, PetscViewer viewer)
354: {
355: KSP_PIPEGCR *pipegcr = (KSP_PIPEGCR*)ksp->data;
357: PetscBool isascii,isstring;
358: const char *truncstr;
361: PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII, &isascii);
362: PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERSTRING,&isstring);
364: if(pipegcr->truncstrat == KSP_FCD_TRUNC_TYPE_STANDARD){
365: truncstr = "Using standard truncation strategy";
366: } else if(pipegcr->truncstrat == KSP_FCD_TRUNC_TYPE_NOTAY){
367: truncstr = "Using Notay's truncation strategy";
368: } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Undefined FCD truncation strategy");
369:
371: if (isascii) {
372: PetscViewerASCIIPrintf(viewer," max previous directions = %D\n",pipegcr->mmax);
373: PetscViewerASCIIPrintf(viewer," preallocated %D directions\n",PetscMin(pipegcr->nprealloc,pipegcr->mmax+1));
374: PetscViewerASCIIPrintf(viewer," %s\n",truncstr);
375: PetscViewerASCIIPrintf(viewer," w unrolling = %D \n", pipegcr->unroll_w);
376: PetscViewerASCIIPrintf(viewer," restarts performed = %D \n", pipegcr->n_restarts);
377: } else if (isstring) {
378: PetscViewerStringSPrintf(viewer, "max previous directions = %D, preallocated %D directions, %s truncation strategy", pipegcr->mmax,pipegcr->nprealloc,truncstr);
379: }
380: return(0);
381: }
384: static PetscErrorCode KSPSetUp_PIPEGCR(KSP ksp)
385: {
386: KSP_PIPEGCR *pipegcr = (KSP_PIPEGCR*)ksp->data;
388: Mat A;
389: PetscBool diagonalscale;
390: const PetscInt nworkstd = 5;
393: PCGetDiagonalScale(ksp->pc,&diagonalscale);
394: if (diagonalscale) SETERRQ1(PetscObjectComm((PetscObject)ksp),PETSC_ERR_SUP,"Krylov method %s does not support diagonal scaling",((PetscObject)ksp)->type_name);
396: KSPGetOperators(ksp, &A, NULL);
398: /* Allocate "standard" work vectors */
399: KSPSetWorkVecs(ksp,nworkstd);
401: /* Allocated space for pointers to additional work vectors
402: note that mmax is the number of previous directions, so we add 1 for the current direction */
403: PetscMalloc6(pipegcr->mmax+1,&(pipegcr->pvecs),pipegcr->mmax+1,&(pipegcr->ppvecs),pipegcr->mmax+1,&(pipegcr->svecs), pipegcr->mmax+1,&(pipegcr->psvecs),pipegcr->mmax+1,&(pipegcr->qvecs),pipegcr->mmax+1,&(pipegcr->pqvecs));
404: if (pipegcr->unroll_w) {
405: PetscMalloc3(pipegcr->mmax+1,&(pipegcr->tvecs),pipegcr->mmax+1,&(pipegcr->ptvecs),pipegcr->mmax+2,&(pipegcr->told));
406: }
407: PetscMalloc4(pipegcr->mmax+2,&(pipegcr->pold),pipegcr->mmax+2,&(pipegcr->sold),pipegcr->mmax+2,&(pipegcr->qold),pipegcr->mmax+2,&(pipegcr->chunksizes));
408: PetscMalloc3(pipegcr->mmax+2,&(pipegcr->dots),pipegcr->mmax+1,&(pipegcr->etas),pipegcr->mmax+2,&(pipegcr->redux));
409: /* If the requested number of preallocated vectors is greater than mmax reduce nprealloc */
410: if(pipegcr->nprealloc > pipegcr->mmax+1){
411: PetscInfo2(NULL,"Requested nprealloc=%d is greater than m_max+1=%d. Resetting nprealloc = m_max+1.\n",pipegcr->nprealloc, pipegcr->mmax+1);
412: }
414: /* Preallocate additional work vectors */
415: KSPAllocateVectors_PIPEGCR(ksp,pipegcr->nprealloc,pipegcr->nprealloc);
417: PetscLogObjectMemory(
418: (PetscObject)ksp,
419: (pipegcr->mmax + 1) * 4 * sizeof(Vec*) + /* old dirs */
420: (pipegcr->mmax + 1) * 4 * sizeof(Vec**) + /* old pdirs */
421: (pipegcr->mmax + 1) * 4 * sizeof(Vec*) + /* p/s/qold/told */
422: (pipegcr->mmax + 1) * sizeof(PetscInt) + /* chunksizes */
423: (pipegcr->mmax + 2) * sizeof(Vec*) + /* redux */
424: (pipegcr->mmax + 2) * sizeof(PetscScalar) + /* dots */
425: (pipegcr->mmax + 1) * sizeof(PetscReal) /* etas */
426: );
427: return(0);
428: }
430: static PetscErrorCode KSPReset_PIPEGCR(KSP ksp)
431: {
433: KSP_PIPEGCR *pipegcr = (KSP_PIPEGCR*)ksp->data;
436: if (pipegcr->modifypc_destroy) {
437: (*pipegcr->modifypc_destroy)(pipegcr->modifypc_ctx);
438: }
439: return(0);
440: }
442: static PetscErrorCode KSPDestroy_PIPEGCR(KSP ksp)
443: {
445: PetscInt i;
446: KSP_PIPEGCR *pipegcr = (KSP_PIPEGCR*)ksp->data;
449: VecDestroyVecs(ksp->nwork,&ksp->work); /* Destroy "standard" work vecs */
451: /* Destroy vectors for old directions and the arrays that manage pointers to them */
452: if(pipegcr->nvecs){
453: for(i=0;i<pipegcr->nchunks;i++){
454: VecDestroyVecs(pipegcr->chunksizes[i],&pipegcr->ppvecs[i]);
455: VecDestroyVecs(pipegcr->chunksizes[i],&pipegcr->psvecs[i]);
456: VecDestroyVecs(pipegcr->chunksizes[i],&pipegcr->pqvecs[i]);
457: if (pipegcr->unroll_w) {
458: VecDestroyVecs(pipegcr->chunksizes[i],&pipegcr->ptvecs[i]);
459: }
460: }
461: }
463: PetscFree6(pipegcr->pvecs,pipegcr->ppvecs,pipegcr->svecs,pipegcr->psvecs,pipegcr->qvecs,pipegcr->pqvecs);
464: PetscFree4(pipegcr->pold,pipegcr->sold,pipegcr->qold,pipegcr->chunksizes);
465: PetscFree3(pipegcr->dots,pipegcr->etas,pipegcr->redux);
466: if (pipegcr->unroll_w) {
467: PetscFree3(pipegcr->tvecs,pipegcr->ptvecs,pipegcr->told);
468: }
470: KSPReset_PIPEGCR(ksp);
471: KSPDestroyDefault(ksp);
472: return(0);
473: }
475: /*@
476: KSPPIPEGCRSetUnrollW - Set to PETSC_TRUE to use PIPEGCR with unrolling of the w vector
478: Logically Collective on ksp
480: Input Parameters:
481: + ksp - the Krylov space context
482: - unroll_w - use unrolling
484: Level: intermediate
486: Options Database:
487: . -ksp_pipegcr_unroll_w
489: .seealso: KSPPIPEGCR, KSPPIPEGCRSetTruncationType(), KSPPIPEGCRSetNprealloc(),KSPPIPEGCRGetUnrollW()
490: @*/
491: PetscErrorCode KSPPIPEGCRSetUnrollW(KSP ksp,PetscBool unroll_w)
492: {
493: KSP_PIPEGCR *pipegcr=(KSP_PIPEGCR*)ksp->data;
498: pipegcr->unroll_w=unroll_w;
499: return(0);
500: }
502: /*@
503: KSPPIPEGCRGetUnrollW - Get information on PIPEGCR unrolling the w vector
505: Logically Collective on ksp
507: Input Parameter:
508: . ksp - the Krylov space context
510: Output Parameter:
511: . unroll_w - PIPEGCR uses unrolling (bool)
513: Level: intermediate
515: Options Database:
516: . -ksp_pipegcr_unroll_w
518: .seealso: KSPPIPEGCR, KSPPIPEGCRGetTruncationType(), KSPPIPEGCRGetNprealloc(),KSPPIPEGCRSetUnrollW()
519: @*/
520: PetscErrorCode KSPPIPEGCRGetUnrollW(KSP ksp,PetscBool *unroll_w)
521: {
522: KSP_PIPEGCR *pipegcr=(KSP_PIPEGCR*)ksp->data;
526: *unroll_w=pipegcr->unroll_w;
527: return(0);
528: }
530: /*@
531: KSPPIPEGCRSetMmax - set the maximum number of previous directions PIPEGCR will store for orthogonalization
533: Note: mmax + 1 directions are stored (mmax previous ones along with a current one)
534: and whether all are used in each iteration also depends on the truncation strategy
535: (see KSPPIPEGCRSetTruncationType)
537: Logically Collective on ksp
539: Input Parameters:
540: + ksp - the Krylov space context
541: - mmax - the maximum number of previous directions to orthogonalize againt
543: Level: intermediate
545: Options Database:
546: . -ksp_pipegcr_mmax <N>
548: .seealso: KSPPIPEGCR, KSPPIPEGCRSetTruncationType(), KSPPIPEGCRSetNprealloc()
549: @*/
550: PetscErrorCode KSPPIPEGCRSetMmax(KSP ksp,PetscInt mmax)
551: {
552: KSP_PIPEGCR *pipegcr=(KSP_PIPEGCR*)ksp->data;
557: pipegcr->mmax=mmax;
558: return(0);
559: }
561: /*@
562: KSPPIPEGCRGetMmax - get the maximum number of previous directions PIPEGCR will store
564: Note: PIPEGCR stores mmax+1 directions at most (mmax previous ones, and one current one)
566: Not Collective
568: Input Parameter:
569: . ksp - the Krylov space context
571: Output Parameter:
572: . mmax - the maximum number of previous directons allowed for orthogonalization
574: Options Database:
575: . -ksp_pipegcr_mmax <N>
577: Level: intermediate
579: .seealso: KSPPIPEGCR, KSPPIPEGCRGetTruncationType(), KSPPIPEGCRGetNprealloc(), KSPPIPEGCRSetMmax()
580: @*/
582: PetscErrorCode KSPPIPEGCRGetMmax(KSP ksp,PetscInt *mmax)
583: {
584: KSP_PIPEGCR *pipegcr=(KSP_PIPEGCR*)ksp->data;
588: *mmax=pipegcr->mmax;
589: return(0);
590: }
592: /*@
593: KSPPIPEGCRSetNprealloc - set the number of directions to preallocate with PIPEGCR
595: Logically Collective on ksp
597: Input Parameters:
598: + ksp - the Krylov space context
599: - nprealloc - the number of vectors to preallocate
601: Level: advanced
603: Options Database:
604: . -ksp_pipegcr_nprealloc <N>
606: .seealso: KSPPIPEGCR, KSPPIPEGCRGetTruncationType(), KSPPIPEGCRGetNprealloc()
607: @*/
608: PetscErrorCode KSPPIPEGCRSetNprealloc(KSP ksp,PetscInt nprealloc)
609: {
610: KSP_PIPEGCR *pipegcr=(KSP_PIPEGCR*)ksp->data;
615: pipegcr->nprealloc = nprealloc;
616: return(0);
617: }
619: /*@
620: KSPPIPEGCRGetNprealloc - get the number of directions preallocate by PIPEGCR
622: Not Collective
624: Input Parameter:
625: . ksp - the Krylov space context
627: Output Parameter:
628: . nprealloc - the number of directions preallocated
630: Options Database:
631: . -ksp_pipegcr_nprealloc <N>
633: Level: advanced
635: .seealso: KSPPIPEGCR, KSPPIPEGCRGetTruncationType(), KSPPIPEGCRSetNprealloc()
636: @*/
637: PetscErrorCode KSPPIPEGCRGetNprealloc(KSP ksp,PetscInt *nprealloc)
638: {
639: KSP_PIPEGCR *pipegcr=(KSP_PIPEGCR*)ksp->data;
643: *nprealloc = pipegcr->nprealloc;
644: return(0);
645: }
647: /*@
648: KSPPIPEGCRSetTruncationType - specify how many of its stored previous directions PIPEGCR uses during orthoganalization
650: Logically Collective on ksp
652: KSP_FCD_TRUNC_TYPE_STANDARD uses all (up to mmax) stored directions
653: KSP_FCD_TRUNC_TYPE_NOTAY uses the last max(1,mod(i,mmax)) directions at iteration i=0,1,..
655: Input Parameters:
656: + ksp - the Krylov space context
657: - truncstrat - the choice of strategy
659: Level: intermediate
661: Options Database:
662: . -ksp_pipegcr_truncation_type <standard,notay> - which stored basis vectors to orthogonalize against
664: .seealso: KSPPIPEGCR, KSPPIPEGCRSetTruncationType, KSPPIPEGCRTruncationType, KSPFCDTruncationType
665: @*/
666: PetscErrorCode KSPPIPEGCRSetTruncationType(KSP ksp,KSPFCDTruncationType truncstrat)
667: {
668: KSP_PIPEGCR *pipegcr=(KSP_PIPEGCR*)ksp->data;
673: pipegcr->truncstrat=truncstrat;
674: return(0);
675: }
677: /*@
678: KSPPIPEGCRGetTruncationType - get the truncation strategy employed by PIPEGCR
680: Not Collective
682: KSP_FCD_TRUNC_TYPE_STANDARD uses all (up to mmax) stored directions
683: KSP_FCD_TRUNC_TYPE_NOTAY uses the last max(1,mod(i,mmax)) directions at iteration i=0,1,..
685: Input Parameter:
686: . ksp - the Krylov space context
688: Output Parameter:
689: . truncstrat - the strategy type
691: Options Database:
692: . -ksp_pipegcr_truncation_type <standard,notay> - which stored basis vectors to orthogonalize against
694: Level: intermediate
696: .seealso: KSPPIPEGCR, KSPPIPEGCRSetTruncationType, KSPPIPEGCRTruncationType, KSPFCDTruncationType
697: @*/
698: PetscErrorCode KSPPIPEGCRGetTruncationType(KSP ksp,KSPFCDTruncationType *truncstrat)
699: {
700: KSP_PIPEGCR *pipegcr=(KSP_PIPEGCR*)ksp->data;
704: *truncstrat=pipegcr->truncstrat;
705: return(0);
706: }
708: static PetscErrorCode KSPSetFromOptions_PIPEGCR(PetscOptionItems *PetscOptionsObject,KSP ksp)
709: {
711: KSP_PIPEGCR *pipegcr = (KSP_PIPEGCR*)ksp->data;
712: PetscInt mmax,nprealloc;
713: PetscBool flg;
716: PetscOptionsHead(PetscOptionsObject,"KSP PIPEGCR options");
717: PetscOptionsInt("-ksp_pipegcr_mmax","Number of search directions to storue","KSPPIPEGCRSetMmax",pipegcr->mmax,&mmax,&flg);
718: if (flg) KSPPIPEGCRSetMmax(ksp,mmax);
719: PetscOptionsInt("-ksp_pipegcr_nprealloc","Number of directions to preallocate","KSPPIPEGCRSetNprealloc",pipegcr->nprealloc,&nprealloc,&flg);
720: if (flg) { KSPPIPEGCRSetNprealloc(ksp,nprealloc); }
721: PetscOptionsEnum("-ksp_pipegcr_truncation_type","Truncation approach for directions","KSPFCGSetTruncationType",KSPFCDTruncationTypes,(PetscEnum)pipegcr->truncstrat,(PetscEnum*)&pipegcr->truncstrat,NULL);
722: PetscOptionsBool("-ksp_pipegcr_unroll_w","Use unrolling of w","KSPPIPEGCRSetUnrollW",pipegcr->unroll_w,&pipegcr->unroll_w,NULL);
723: PetscOptionsTail();
724: return(0);
725: }
728: typedef PetscErrorCode (*KSPPIPEGCRModifyPCFunction)(KSP,PetscInt,PetscReal,void*);
729: typedef PetscErrorCode (*KSPPIPEGCRDestroyFunction)(void*);
731: static PetscErrorCode KSPPIPEGCRSetModifyPC_PIPEGCR(KSP ksp,KSPPIPEGCRModifyPCFunction function,void *data,KSPPIPEGCRDestroyFunction destroy)
732: {
733: KSP_PIPEGCR *pipegcr = (KSP_PIPEGCR*)ksp->data;
737: pipegcr->modifypc = function;
738: pipegcr->modifypc_destroy = destroy;
739: pipegcr->modifypc_ctx = data;
740: return(0);
741: }
743: /*@C
744: KSPPIPEGCRSetModifyPC - Sets the routine used by PIPEGCR to modify the preconditioner.
746: Logically Collective on ksp
748: Input Parameters:
749: + ksp - iterative context obtained from KSPCreate()
750: . function - user defined function to modify the preconditioner
751: . ctx - user provided contex for the modify preconditioner function
752: - destroy - the function to use to destroy the user provided Section 1.5 Writing Application Codes with PETSc context.
754: Calling Sequence of function:
755: PetscErrorCode function (KSP ksp, PetscInt n, PetscReal rnorm, void *ctx)
757: ksp - iterative context
758: n - the total number of PIPEGCR iterations that have occurred
759: rnorm - 2-norm residual value
760: ctx - the user provided Section 1.5 Writing Application Codes with PETSc context
762: Level: intermediate
764: Notes:
765: The default modifypc routine is KSPPIPEGCRModifyPCNoChange()
767: .seealso: KSPPIPEGCRModifyPCNoChange()
769: @*/
770: PetscErrorCode KSPPIPEGCRSetModifyPC(KSP ksp,PetscErrorCode (*function)(KSP,PetscInt,PetscReal,void*),void *data,PetscErrorCode (*destroy)(void*))
771: {
775: PetscUseMethod(ksp,"KSPPIPEGCRSetModifyPC_C",(KSP,PetscErrorCode (*)(KSP,PetscInt,PetscReal,void*),void *data,PetscErrorCode (*)(void*)),(ksp,function,data,destroy));
776: return(0);
777: }
779: /*MC
780: KSPPIPEGCR - Implements a Pipelined Generalized Conjugate Residual method.
782: Options Database Keys:
783: + -ksp_pipegcr_mmax <N> - the max number of Krylov directions to orthogonalize against
784: . -ksp_pipegcr_unroll_w - unroll w at the storage cost of a maximum of (mmax+1) extra vectors with the benefit of better pipelining (default: PETSC_TRUE)
785: . -ksp_pipegcr_nprealloc <N> - the number of vectors to preallocated for storing Krylov directions. Once exhausted new directions are allocated blockwise (default: 5)
786: - -ksp_pipegcr_truncation_type <standard,notay> - which previous search directions to orthogonalize against
789: Notes:
790: The PIPEGCR Krylov method supports non-symmetric matrices and permits the use of a preconditioner
791: which may vary from one iteration to the next. Users can can define a method to vary the
792: preconditioner between iterates via KSPPIPEGCRSetModifyPC().
793: Restarts are solves with x0 not equal to zero. When a restart occurs, the initial starting
794: solution is given by the current estimate for x which was obtained by the last restart
795: iterations of the PIPEGCR algorithm.
796: The method implemented requires at most the storage of 4 x mmax + 5 vectors, roughly twice as much as GCR.
798: Only supports left preconditioning.
800: The natural "norm" for this method is (u,Au), where u is the preconditioned residual. This norm is available at no additional computational cost, as with standard CG. Choosing preconditioned or unpreconditioned norm types involves a blocking reduction which prevents any benefit from pipelining.
802: Reference:
803: P. Sanan, S.M. Schnepp, and D.A. May,
804: "Pipelined, Flexible Krylov Subspace Methods,"
805: SIAM Journal on Scientific Computing 2016 38:5, C441-C470,
806: DOI: 10.1137/15M1049130
808: Level: intermediate
810: .seealso: KSPCreate(), KSPSetType(), KSPType (for list of available types), KSP,
811: KSPPIPEFGMRES, KSPPIPECG, KSPPIPECR, KSPPIPEFCG,KSPPIPEGCRSetTruncationType(),KSPPIPEGCRSetNprealloc(),KSPPIPEGCRSetUnrollW(),KSPPIPEGCRSetMmax()
814: M*/
815: PETSC_EXTERN PetscErrorCode KSPCreate_PIPEGCR(KSP ksp)
816: {
818: KSP_PIPEGCR *pipegcr;
821: PetscNewLog(ksp,&pipegcr);
822: pipegcr->mmax = KSPPIPEGCR_DEFAULT_MMAX;
823: pipegcr->nprealloc = KSPPIPEGCR_DEFAULT_NPREALLOC;
824: pipegcr->nvecs = 0;
825: pipegcr->vecb = KSPPIPEGCR_DEFAULT_VECB;
826: pipegcr->nchunks = 0;
827: pipegcr->truncstrat = KSPPIPEGCR_DEFAULT_TRUNCSTRAT;
828: pipegcr->n_restarts = 0;
829: pipegcr->unroll_w = KSPPIPEGCR_DEFAULT_UNROLL_W;
831: ksp->data = (void*)pipegcr;
833: /* natural norm is for free, precond+unprecond norm require non-overlapped reduction */
834: KSPSetSupportedNorm(ksp,KSP_NORM_NATURAL,PC_LEFT,2);
835: KSPSetSupportedNorm(ksp,KSP_NORM_PRECONDITIONED,PC_LEFT,1);
836: KSPSetSupportedNorm(ksp,KSP_NORM_UNPRECONDITIONED,PC_LEFT,1);
837: KSPSetSupportedNorm(ksp,KSP_NORM_NONE,PC_LEFT,1);
839: ksp->ops->setup = KSPSetUp_PIPEGCR;
840: ksp->ops->solve = KSPSolve_PIPEGCR;
841: ksp->ops->reset = KSPReset_PIPEGCR;
842: ksp->ops->destroy = KSPDestroy_PIPEGCR;
843: ksp->ops->view = KSPView_PIPEGCR;
844: ksp->ops->setfromoptions = KSPSetFromOptions_PIPEGCR;
845: ksp->ops->buildsolution = KSPBuildSolutionDefault;
846: ksp->ops->buildresidual = KSPBuildResidualDefault;
848: PetscObjectComposeFunction((PetscObject)ksp,"KSPPIPEGCRSetModifyPC_C",KSPPIPEGCRSetModifyPC_PIPEGCR);
849: return(0);
850: }