Actual source code: pipegcr.c
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;
81: /* !!PS We have not checked these routines for use with complex numbers. The inner products
82: are likely not defined correctly for that case */
83: if (PetscDefined(USE_COMPLEX) && !PetscDefined(SKIP_COMPLEX)) SETERRQ(PETSC_COMM_WORLD,PETSC_ERR_SUP,"PIPEFGMRES has not been implemented for use with complex scalars");
85: KSPGetOperators(ksp, &A, &B);
86: x = ksp->vec_sol;
87: b = ksp->vec_rhs;
88: r = ksp->work[0];
89: z = ksp->work[1];
90: w = ksp->work[2]; /* w = Az = AB(r) (pipelining intermediate) */
91: m = ksp->work[3]; /* m = B(w) = B(Az) = B(AB(r)) (pipelining intermediate) */
92: n = ksp->work[4]; /* n = AB(w) = AB(Az) = AB(AB(r)) (pipelining intermediate) */
93: p = pipegcr->pvecs[0];
94: s = pipegcr->svecs[0];
95: q = pipegcr->qvecs[0];
96: t = pipegcr->unroll_w ? pipegcr->tvecs[0] : NULL;
98: redux = pipegcr->redux;
99: dots = pipegcr->dots;
100: etas = pipegcr->etas;
101: betas = dots; /* dots takes the result of all dot products of which the betas are a subset */
103: /* cycle initial residual */
104: KSP_MatMult(ksp,A,x,r);
105: VecAYPX(r,-1.0,b); /* r <- b - Ax */
106: KSP_PCApply(ksp,r,z); /* z <- B(r) */
107: KSP_MatMult(ksp,A,z,w); /* w <- Az */
109: /* initialization of other variables and pipelining intermediates */
110: VecCopy(z,p);
111: KSP_MatMult(ksp,A,p,s);
113: /* overlap initial computation of delta, gamma */
114: redux[0] = w;
115: redux[1] = r;
116: VecMDotBegin(w,2,redux,dots); /* Start split reductions for gamma = (w,r), delta = (w,w) */
117: PetscCommSplitReductionBegin(PetscObjectComm((PetscObject)s)); /* perform asynchronous reduction */
118: KSP_PCApply(ksp,s,q); /* q = B(s) */
119: if (pipegcr->unroll_w) {
120: KSP_MatMult(ksp,A,q,t); /* t = Aq */
121: }
122: VecMDotEnd(w,2,redux,dots); /* Finish split reduction */
123: delta = PetscRealPart(dots[0]);
124: etas[0] = delta;
125: gamma = dots[1];
126: alpha = gamma/delta;
128: i = 0;
129: do {
130: PetscObjectSAWsTakeAccess((PetscObject)ksp);
131: ksp->its++;
132: PetscObjectSAWsGrantAccess((PetscObject)ksp);
134: /* update solution, residuals, .. */
135: VecAXPY(x,+alpha,p);
136: VecAXPY(r,-alpha,s);
137: VecAXPY(z,-alpha,q);
138: if (pipegcr->unroll_w) {
139: VecAXPY(w,-alpha,t);
140: } else {
141: KSP_MatMult(ksp,A,z,w);
142: }
144: /* Computations of current iteration done */
145: i++;
147: if (pipegcr->modifypc) {
148: (*pipegcr->modifypc)(ksp,ksp->its,ksp->rnorm,pipegcr->modifypc_ctx);
149: }
151: /* If needbe, allocate a new chunk of vectors */
152: KSPAllocateVectors_PIPEGCR(ksp,i+1,pipegcr->vecb);
154: /* Note that we wrap around and start clobbering old vectors */
155: idx = i % (pipegcr->mmax+1);
156: p = pipegcr->pvecs[idx];
157: s = pipegcr->svecs[idx];
158: q = pipegcr->qvecs[idx];
159: if (pipegcr->unroll_w) {
160: t = pipegcr->tvecs[idx];
161: }
162: eta = pipegcr->etas+idx;
164: /* number of old directions to orthogonalize against */
165: switch(pipegcr->truncstrat) {
166: case KSP_FCD_TRUNC_TYPE_STANDARD:
167: mi = pipegcr->mmax;
168: break;
169: case KSP_FCD_TRUNC_TYPE_NOTAY:
170: mi = ((i-1) % pipegcr->mmax)+1;
171: break;
172: default:
173: SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Unrecognized Truncation Strategy");
174: }
176: /* Pick old p,s,q,zeta in a way suitable for VecMDot */
177: for (k=PetscMax(0,i-mi),j=0;k<i;j++,k++) {
178: kdx = k % (pipegcr->mmax+1);
179: pipegcr->pold[j] = pipegcr->pvecs[kdx];
180: pipegcr->sold[j] = pipegcr->svecs[kdx];
181: pipegcr->qold[j] = pipegcr->qvecs[kdx];
182: if (pipegcr->unroll_w) {
183: pipegcr->told[j] = pipegcr->tvecs[kdx];
184: }
185: redux[j] = pipegcr->svecs[kdx];
186: }
187: /* If the above loop is not run redux contains only r and w => all beta_k = 0, only gamma, delta != 0 */
188: redux[j] = r;
189: redux[j+1] = w;
191: /* Dot products */
192: /* Start split reductions for beta_k = (w,s_k), gamma = (w,r), delta = (w,w) */
193: VecMDotBegin(w,j+2,redux,dots);
194: PetscCommSplitReductionBegin(PetscObjectComm((PetscObject)w));
196: /* B(w-r) + u stabilization */
197: VecWAXPY(n,-1.0,r,w); /* m = u + B(w-r): (a) ntmp = w-r */
198: KSP_PCApply(ksp,n,m); /* m = u + B(w-r): (b) mtmp = B(ntmp) = B(w-r) */
199: VecAXPY(m,1.0,z); /* m = u + B(w-r): (c) m = z + mtmp */
200: if (pipegcr->unroll_w) {
201: KSP_MatMult(ksp,A,m,n); /* n = Am */
202: }
204: /* Finish split reductions for beta_k = (w,s_k), gamma = (w,r), delta = (w,w) */
205: VecMDotEnd(w,j+2,redux,dots);
206: gamma = dots[j];
207: delta = PetscRealPart(dots[j+1]);
209: /* compute new residual norm.
210: this cannot be done before this point so that the natural norm
211: is available for free and the communication involved is overlapped */
212: switch (ksp->normtype) {
213: case KSP_NORM_PRECONDITIONED:
214: VecNorm(z,NORM_2,&rnorm); /* ||r|| <- sqrt(z'*z) */
215: break;
216: case KSP_NORM_UNPRECONDITIONED:
217: VecNorm(r,NORM_2,&rnorm); /* ||r|| <- sqrt(r'*r) */
218: break;
219: case KSP_NORM_NATURAL:
220: rnorm = PetscSqrtReal(PetscAbsScalar(gamma)); /* ||r|| <- sqrt(r,w) */
221: break;
222: case KSP_NORM_NONE:
223: rnorm = 0.0;
224: break;
225: default: SETERRQ1(PetscObjectComm((PetscObject)ksp),PETSC_ERR_SUP,"%s",KSPNormTypes[ksp->normtype]);
226: }
228: /* Check for convergence */
229: PetscObjectSAWsTakeAccess((PetscObject)ksp);
230: ksp->rnorm = rnorm;
231: PetscObjectSAWsGrantAccess((PetscObject)ksp);
232: KSPLogResidualHistory(ksp,rnorm);
233: KSPMonitor(ksp,ksp->its,rnorm);
234: (*ksp->converged)(ksp,ksp->its,rnorm,&ksp->reason,ksp->cnvP);
235: if (ksp->reason) return(0);
237: /* compute new eta and scale beta */
238: *eta = 0.;
239: for (k=PetscMax(0,i-mi),j=0;k<i;j++,k++) {
240: kdx = k % (pipegcr->mmax+1);
241: betas[j] /= -etas[kdx]; /* betak /= etak */
242: *eta -= ((PetscReal)(PetscAbsScalar(betas[j])*PetscAbsScalar(betas[j]))) * etas[kdx];
243: /* etaitmp = -betaik^2 * etak */
244: }
245: *eta += delta; /* etai = delta -betaik^2 * etak */
247: /* check breakdown of eta = (s,s) */
248: if (*eta < 0.) {
249: pipegcr->norm_breakdown = PETSC_TRUE;
250: PetscInfo1(ksp,"Restart due to square root breakdown at it = \n",ksp->its);
251: break;
252: } else {
253: alpha= gamma/(*eta); /* alpha = gamma/etai */
254: }
256: /* project out stored search directions using classical G-S */
257: VecCopy(z,p);
258: VecCopy(w,s);
259: VecCopy(m,q);
260: if (pipegcr->unroll_w) {
261: VecCopy(n,t);
262: VecMAXPY(t,j,betas,pipegcr->told); /* ti <- n - sum_k beta_k t_k */
263: }
264: VecMAXPY(p,j,betas,pipegcr->pold); /* pi <- ui - sum_k beta_k p_k */
265: VecMAXPY(s,j,betas,pipegcr->sold); /* si <- wi - sum_k beta_k s_k */
266: VecMAXPY(q,j,betas,pipegcr->qold); /* qi <- m - sum_k beta_k q_k */
268: } while (ksp->its < ksp->max_it);
269: if (ksp->its >= ksp->max_it) ksp->reason = KSP_DIVERGED_ITS;
270: return(0);
271: }
273: static PetscErrorCode KSPSolve_PIPEGCR(KSP ksp)
274: {
275: KSP_PIPEGCR *pipegcr = (KSP_PIPEGCR*)ksp->data;
277: Mat A, B;
278: Vec x,b,r,z,w;
279: PetscScalar gamma;
280: PetscReal rnorm=0.0;
281: PetscBool issym;
284: PetscCitationsRegister(citation,&cited);
286: KSPGetOperators(ksp, &A, &B);
287: x = ksp->vec_sol;
288: b = ksp->vec_rhs;
289: r = ksp->work[0];
290: z = ksp->work[1];
291: w = ksp->work[2]; /* w = Az = AB(r) (pipelining intermediate) */
293: /* compute initial residual */
294: if (!ksp->guess_zero) {
295: KSP_MatMult(ksp,A,x,r);
296: VecAYPX(r,-1.0,b); /* r <- b - Ax */
297: } else {
298: VecCopy(b,r); /* r <- b */
299: }
301: /* initial residual norm */
302: KSP_PCApply(ksp,r,z); /* z <- B(r) */
303: KSP_MatMult(ksp,A,z,w); /* w <- Az */
304: VecDot(r,w,&gamma); /* gamma = (r,w) */
306: switch (ksp->normtype) {
307: case KSP_NORM_PRECONDITIONED:
308: VecNorm(z,NORM_2,&rnorm); /* ||r|| <- sqrt(z'*z) */
309: break;
310: case KSP_NORM_UNPRECONDITIONED:
311: VecNorm(r,NORM_2,&rnorm); /* ||r|| <- sqrt(r'*r) */
312: break;
313: case KSP_NORM_NATURAL:
314: rnorm = PetscSqrtReal(PetscAbsScalar(gamma)); /* ||r|| <- sqrt(r,w) */
315: break;
316: case KSP_NORM_NONE:
317: rnorm = 0.0;
318: break;
319: default: SETERRQ1(PetscObjectComm((PetscObject)ksp),PETSC_ERR_SUP,"%s",KSPNormTypes[ksp->normtype]);
320: }
322: /* Is A symmetric? */
323: PetscObjectTypeCompareAny((PetscObject)A,&issym,MATSBAIJ,MATSEQSBAIJ,MATMPISBAIJ,"");
324: if (!issym) {
325: PetscInfo(A,"Matrix type is not any of MATSBAIJ,MATSEQSBAIJ,MATMPISBAIJ. Is matrix A symmetric (as required by CR methods)?");
326: }
328: /* logging */
329: PetscObjectSAWsTakeAccess((PetscObject)ksp);
330: ksp->its = 0;
331: ksp->rnorm0 = rnorm;
332: PetscObjectSAWsGrantAccess((PetscObject)ksp);
333: KSPLogResidualHistory(ksp,ksp->rnorm0);
334: KSPMonitor(ksp,ksp->its,ksp->rnorm0);
335: (*ksp->converged)(ksp,ksp->its,ksp->rnorm0,&ksp->reason,ksp->cnvP);
336: if (ksp->reason) return(0);
338: do {
339: KSPSolve_PIPEGCR_cycle(ksp);
340: if (ksp->reason) return(0);
341: if (pipegcr->norm_breakdown) {
342: pipegcr->n_restarts++;
343: pipegcr->norm_breakdown = PETSC_FALSE;
344: }
345: } while (ksp->its < ksp->max_it);
347: if (ksp->its >= ksp->max_it) ksp->reason = KSP_DIVERGED_ITS;
348: return(0);
349: }
351: static PetscErrorCode KSPView_PIPEGCR(KSP ksp, PetscViewer viewer)
352: {
353: KSP_PIPEGCR *pipegcr = (KSP_PIPEGCR*)ksp->data;
355: PetscBool isascii,isstring;
356: const char *truncstr;
359: PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII, &isascii);
360: PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERSTRING,&isstring);
362: if (pipegcr->truncstrat == KSP_FCD_TRUNC_TYPE_STANDARD) {
363: truncstr = "Using standard truncation strategy";
364: } else if (pipegcr->truncstrat == KSP_FCD_TRUNC_TYPE_NOTAY) {
365: truncstr = "Using Notay's truncation strategy";
366: } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Undefined FCD truncation strategy");
368: if (isascii) {
369: PetscViewerASCIIPrintf(viewer," max previous directions = %D\n",pipegcr->mmax);
370: PetscViewerASCIIPrintf(viewer," preallocated %D directions\n",PetscMin(pipegcr->nprealloc,pipegcr->mmax+1));
371: PetscViewerASCIIPrintf(viewer," %s\n",truncstr);
372: PetscViewerASCIIPrintf(viewer," w unrolling = %D \n", pipegcr->unroll_w);
373: PetscViewerASCIIPrintf(viewer," restarts performed = %D \n", pipegcr->n_restarts);
374: } else if (isstring) {
375: PetscViewerStringSPrintf(viewer, "max previous directions = %D, preallocated %D directions, %s truncation strategy", pipegcr->mmax,pipegcr->nprealloc,truncstr);
376: }
377: return(0);
378: }
380: static PetscErrorCode KSPSetUp_PIPEGCR(KSP ksp)
381: {
382: KSP_PIPEGCR *pipegcr = (KSP_PIPEGCR*)ksp->data;
384: Mat A;
385: PetscBool diagonalscale;
386: const PetscInt nworkstd = 5;
389: PCGetDiagonalScale(ksp->pc,&diagonalscale);
390: if (diagonalscale) SETERRQ1(PetscObjectComm((PetscObject)ksp),PETSC_ERR_SUP,"Krylov method %s does not support diagonal scaling",((PetscObject)ksp)->type_name);
392: KSPGetOperators(ksp, &A, NULL);
394: /* Allocate "standard" work vectors */
395: KSPSetWorkVecs(ksp,nworkstd);
397: /* Allocated space for pointers to additional work vectors
398: note that mmax is the number of previous directions, so we add 1 for the current direction */
399: 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));
400: if (pipegcr->unroll_w) {
401: PetscMalloc3(pipegcr->mmax+1,&(pipegcr->tvecs),pipegcr->mmax+1,&(pipegcr->ptvecs),pipegcr->mmax+2,&(pipegcr->told));
402: }
403: PetscMalloc4(pipegcr->mmax+2,&(pipegcr->pold),pipegcr->mmax+2,&(pipegcr->sold),pipegcr->mmax+2,&(pipegcr->qold),pipegcr->mmax+2,&(pipegcr->chunksizes));
404: PetscMalloc3(pipegcr->mmax+2,&(pipegcr->dots),pipegcr->mmax+1,&(pipegcr->etas),pipegcr->mmax+2,&(pipegcr->redux));
405: /* If the requested number of preallocated vectors is greater than mmax reduce nprealloc */
406: if (pipegcr->nprealloc > pipegcr->mmax+1) {
407: PetscInfo2(NULL,"Requested nprealloc=%d is greater than m_max+1=%d. Resetting nprealloc = m_max+1.\n",pipegcr->nprealloc, pipegcr->mmax+1);
408: }
410: /* Preallocate additional work vectors */
411: KSPAllocateVectors_PIPEGCR(ksp,pipegcr->nprealloc,pipegcr->nprealloc);
413: PetscLogObjectMemory(
414: (PetscObject)ksp,
415: (pipegcr->mmax + 1) * 4 * sizeof(Vec*) + /* old dirs */
416: (pipegcr->mmax + 1) * 4 * sizeof(Vec**) + /* old pdirs */
417: (pipegcr->mmax + 1) * 4 * sizeof(Vec*) + /* p/s/qold/told */
418: (pipegcr->mmax + 1) * sizeof(PetscInt) + /* chunksizes */
419: (pipegcr->mmax + 2) * sizeof(Vec*) + /* redux */
420: (pipegcr->mmax + 2) * sizeof(PetscScalar) + /* dots */
421: (pipegcr->mmax + 1) * sizeof(PetscReal) /* etas */);
422: return(0);
423: }
425: static PetscErrorCode KSPReset_PIPEGCR(KSP ksp)
426: {
428: KSP_PIPEGCR *pipegcr = (KSP_PIPEGCR*)ksp->data;
431: if (pipegcr->modifypc_destroy) {
432: (*pipegcr->modifypc_destroy)(pipegcr->modifypc_ctx);
433: }
434: return(0);
435: }
437: static PetscErrorCode KSPDestroy_PIPEGCR(KSP ksp)
438: {
440: PetscInt i;
441: KSP_PIPEGCR *pipegcr = (KSP_PIPEGCR*)ksp->data;
444: VecDestroyVecs(ksp->nwork,&ksp->work); /* Destroy "standard" work vecs */
446: /* Destroy vectors for old directions and the arrays that manage pointers to them */
447: if (pipegcr->nvecs) {
448: for (i=0;i<pipegcr->nchunks;i++) {
449: VecDestroyVecs(pipegcr->chunksizes[i],&pipegcr->ppvecs[i]);
450: VecDestroyVecs(pipegcr->chunksizes[i],&pipegcr->psvecs[i]);
451: VecDestroyVecs(pipegcr->chunksizes[i],&pipegcr->pqvecs[i]);
452: if (pipegcr->unroll_w) {
453: VecDestroyVecs(pipegcr->chunksizes[i],&pipegcr->ptvecs[i]);
454: }
455: }
456: }
458: PetscFree6(pipegcr->pvecs,pipegcr->ppvecs,pipegcr->svecs,pipegcr->psvecs,pipegcr->qvecs,pipegcr->pqvecs);
459: PetscFree4(pipegcr->pold,pipegcr->sold,pipegcr->qold,pipegcr->chunksizes);
460: PetscFree3(pipegcr->dots,pipegcr->etas,pipegcr->redux);
461: if (pipegcr->unroll_w) {
462: PetscFree3(pipegcr->tvecs,pipegcr->ptvecs,pipegcr->told);
463: }
465: KSPReset_PIPEGCR(ksp);
466: KSPDestroyDefault(ksp);
467: return(0);
468: }
470: /*@
471: KSPPIPEGCRSetUnrollW - Set to PETSC_TRUE to use PIPEGCR with unrolling of the w vector
473: Logically Collective on ksp
475: Input Parameters:
476: + ksp - the Krylov space context
477: - unroll_w - use unrolling
479: Level: intermediate
481: Options Database:
482: . -ksp_pipegcr_unroll_w
484: .seealso: KSPPIPEGCR, KSPPIPEGCRSetTruncationType(), KSPPIPEGCRSetNprealloc(),KSPPIPEGCRGetUnrollW()
485: @*/
486: PetscErrorCode KSPPIPEGCRSetUnrollW(KSP ksp,PetscBool unroll_w)
487: {
488: KSP_PIPEGCR *pipegcr=(KSP_PIPEGCR*)ksp->data;
493: pipegcr->unroll_w=unroll_w;
494: return(0);
495: }
497: /*@
498: KSPPIPEGCRGetUnrollW - Get information on PIPEGCR unrolling the w vector
500: Logically Collective on ksp
502: Input Parameter:
503: . ksp - the Krylov space context
505: Output Parameter:
506: . unroll_w - PIPEGCR uses unrolling (bool)
508: Level: intermediate
510: Options Database:
511: . -ksp_pipegcr_unroll_w
513: .seealso: KSPPIPEGCR, KSPPIPEGCRGetTruncationType(), KSPPIPEGCRGetNprealloc(),KSPPIPEGCRSetUnrollW()
514: @*/
515: PetscErrorCode KSPPIPEGCRGetUnrollW(KSP ksp,PetscBool *unroll_w)
516: {
517: KSP_PIPEGCR *pipegcr=(KSP_PIPEGCR*)ksp->data;
521: *unroll_w=pipegcr->unroll_w;
522: return(0);
523: }
525: /*@
526: KSPPIPEGCRSetMmax - set the maximum number of previous directions PIPEGCR will store for orthogonalization
528: Note: mmax + 1 directions are stored (mmax previous ones along with a current one)
529: and whether all are used in each iteration also depends on the truncation strategy
530: (see KSPPIPEGCRSetTruncationType)
532: Logically Collective on ksp
534: Input Parameters:
535: + ksp - the Krylov space context
536: - mmax - the maximum number of previous directions to orthogonalize againt
538: Level: intermediate
540: Options Database:
541: . -ksp_pipegcr_mmax <N>
543: .seealso: KSPPIPEGCR, KSPPIPEGCRSetTruncationType(), KSPPIPEGCRSetNprealloc()
544: @*/
545: PetscErrorCode KSPPIPEGCRSetMmax(KSP ksp,PetscInt mmax)
546: {
547: KSP_PIPEGCR *pipegcr=(KSP_PIPEGCR*)ksp->data;
552: pipegcr->mmax=mmax;
553: return(0);
554: }
556: /*@
557: KSPPIPEGCRGetMmax - get the maximum number of previous directions PIPEGCR will store
559: Note: PIPEGCR stores mmax+1 directions at most (mmax previous ones, and one current one)
561: Not Collective
563: Input Parameter:
564: . ksp - the Krylov space context
566: Output Parameter:
567: . mmax - the maximum number of previous directons allowed for orthogonalization
569: Options Database:
570: . -ksp_pipegcr_mmax <N>
572: Level: intermediate
574: .seealso: KSPPIPEGCR, KSPPIPEGCRGetTruncationType(), KSPPIPEGCRGetNprealloc(), KSPPIPEGCRSetMmax()
575: @*/
577: PetscErrorCode KSPPIPEGCRGetMmax(KSP ksp,PetscInt *mmax)
578: {
579: KSP_PIPEGCR *pipegcr=(KSP_PIPEGCR*)ksp->data;
583: *mmax=pipegcr->mmax;
584: return(0);
585: }
587: /*@
588: KSPPIPEGCRSetNprealloc - set the number of directions to preallocate with PIPEGCR
590: Logically Collective on ksp
592: Input Parameters:
593: + ksp - the Krylov space context
594: - nprealloc - the number of vectors to preallocate
596: Level: advanced
598: Options Database:
599: . -ksp_pipegcr_nprealloc <N>
601: .seealso: KSPPIPEGCR, KSPPIPEGCRGetTruncationType(), KSPPIPEGCRGetNprealloc()
602: @*/
603: PetscErrorCode KSPPIPEGCRSetNprealloc(KSP ksp,PetscInt nprealloc)
604: {
605: KSP_PIPEGCR *pipegcr=(KSP_PIPEGCR*)ksp->data;
610: pipegcr->nprealloc = nprealloc;
611: return(0);
612: }
614: /*@
615: KSPPIPEGCRGetNprealloc - get the number of directions preallocate by PIPEGCR
617: Not Collective
619: Input Parameter:
620: . ksp - the Krylov space context
622: Output Parameter:
623: . nprealloc - the number of directions preallocated
625: Options Database:
626: . -ksp_pipegcr_nprealloc <N>
628: Level: advanced
630: .seealso: KSPPIPEGCR, KSPPIPEGCRGetTruncationType(), KSPPIPEGCRSetNprealloc()
631: @*/
632: PetscErrorCode KSPPIPEGCRGetNprealloc(KSP ksp,PetscInt *nprealloc)
633: {
634: KSP_PIPEGCR *pipegcr=(KSP_PIPEGCR*)ksp->data;
638: *nprealloc = pipegcr->nprealloc;
639: return(0);
640: }
642: /*@
643: KSPPIPEGCRSetTruncationType - specify how many of its stored previous directions PIPEGCR uses during orthoganalization
645: Logically Collective on ksp
647: KSP_FCD_TRUNC_TYPE_STANDARD uses all (up to mmax) stored directions
648: KSP_FCD_TRUNC_TYPE_NOTAY uses the last max(1,mod(i,mmax)) directions at iteration i=0,1,..
650: Input Parameters:
651: + ksp - the Krylov space context
652: - truncstrat - the choice of strategy
654: Level: intermediate
656: Options Database:
657: . -ksp_pipegcr_truncation_type <standard,notay> - which stored basis vectors to orthogonalize against
659: .seealso: KSPPIPEGCR, KSPPIPEGCRSetTruncationType, KSPPIPEGCRTruncationType, KSPFCDTruncationType
660: @*/
661: PetscErrorCode KSPPIPEGCRSetTruncationType(KSP ksp,KSPFCDTruncationType truncstrat)
662: {
663: KSP_PIPEGCR *pipegcr=(KSP_PIPEGCR*)ksp->data;
668: pipegcr->truncstrat=truncstrat;
669: return(0);
670: }
672: /*@
673: KSPPIPEGCRGetTruncationType - get the truncation strategy employed by PIPEGCR
675: Not Collective
677: KSP_FCD_TRUNC_TYPE_STANDARD uses all (up to mmax) stored directions
678: KSP_FCD_TRUNC_TYPE_NOTAY uses the last max(1,mod(i,mmax)) directions at iteration i=0,1,..
680: Input Parameter:
681: . ksp - the Krylov space context
683: Output Parameter:
684: . truncstrat - the strategy type
686: Options Database:
687: . -ksp_pipegcr_truncation_type <standard,notay> - which stored basis vectors to orthogonalize against
689: Level: intermediate
691: .seealso: KSPPIPEGCR, KSPPIPEGCRSetTruncationType, KSPPIPEGCRTruncationType, KSPFCDTruncationType
692: @*/
693: PetscErrorCode KSPPIPEGCRGetTruncationType(KSP ksp,KSPFCDTruncationType *truncstrat)
694: {
695: KSP_PIPEGCR *pipegcr=(KSP_PIPEGCR*)ksp->data;
699: *truncstrat=pipegcr->truncstrat;
700: return(0);
701: }
703: static PetscErrorCode KSPSetFromOptions_PIPEGCR(PetscOptionItems *PetscOptionsObject,KSP ksp)
704: {
706: KSP_PIPEGCR *pipegcr = (KSP_PIPEGCR*)ksp->data;
707: PetscInt mmax,nprealloc;
708: PetscBool flg;
711: PetscOptionsHead(PetscOptionsObject,"KSP PIPEGCR options");
712: PetscOptionsInt("-ksp_pipegcr_mmax","Number of search directions to storue","KSPPIPEGCRSetMmax",pipegcr->mmax,&mmax,&flg);
713: if (flg) {KSPPIPEGCRSetMmax(ksp,mmax);}
714: PetscOptionsInt("-ksp_pipegcr_nprealloc","Number of directions to preallocate","KSPPIPEGCRSetNprealloc",pipegcr->nprealloc,&nprealloc,&flg);
715: if (flg) {KSPPIPEGCRSetNprealloc(ksp,nprealloc);}
716: PetscOptionsEnum("-ksp_pipegcr_truncation_type","Truncation approach for directions","KSPFCGSetTruncationType",KSPFCDTruncationTypes,(PetscEnum)pipegcr->truncstrat,(PetscEnum*)&pipegcr->truncstrat,NULL);
717: PetscOptionsBool("-ksp_pipegcr_unroll_w","Use unrolling of w","KSPPIPEGCRSetUnrollW",pipegcr->unroll_w,&pipegcr->unroll_w,NULL);
718: PetscOptionsTail();
719: return(0);
720: }
723: typedef PetscErrorCode (*KSPPIPEGCRModifyPCFunction)(KSP,PetscInt,PetscReal,void*);
724: typedef PetscErrorCode (*KSPPIPEGCRDestroyFunction)(void*);
726: static PetscErrorCode KSPPIPEGCRSetModifyPC_PIPEGCR(KSP ksp,KSPPIPEGCRModifyPCFunction function,void *data,KSPPIPEGCRDestroyFunction destroy)
727: {
728: KSP_PIPEGCR *pipegcr = (KSP_PIPEGCR*)ksp->data;
732: pipegcr->modifypc = function;
733: pipegcr->modifypc_destroy = destroy;
734: pipegcr->modifypc_ctx = data;
735: return(0);
736: }
738: /*@C
739: KSPPIPEGCRSetModifyPC - Sets the routine used by PIPEGCR to modify the preconditioner.
741: Logically Collective on ksp
743: Input Parameters:
744: + ksp - iterative context obtained from KSPCreate()
745: . function - user defined function to modify the preconditioner
746: . ctx - user provided context for the modify preconditioner function
747: - destroy - the function to use to destroy the user provided application context.
749: Calling Sequence of function:
750: PetscErrorCode function (KSP ksp, PetscInt n, PetscReal rnorm, void *ctx)
752: ksp - iterative context
753: n - the total number of PIPEGCR iterations that have occurred
754: rnorm - 2-norm residual value
755: ctx - the user provided application context
757: Level: intermediate
759: Notes:
760: The default modifypc routine is KSPPIPEGCRModifyPCNoChange()
762: .seealso: KSPPIPEGCRModifyPCNoChange()
764: @*/
765: PetscErrorCode KSPPIPEGCRSetModifyPC(KSP ksp,PetscErrorCode (*function)(KSP,PetscInt,PetscReal,void*),void *data,PetscErrorCode (*destroy)(void*))
766: {
770: PetscUseMethod(ksp,"KSPPIPEGCRSetModifyPC_C",(KSP,PetscErrorCode (*)(KSP,PetscInt,PetscReal,void*),void *data,PetscErrorCode (*)(void*)),(ksp,function,data,destroy));
771: return(0);
772: }
774: /*MC
775: KSPPIPEGCR - Implements a Pipelined Generalized Conjugate Residual method.
777: Options Database Keys:
778: + -ksp_pipegcr_mmax <N> - the max number of Krylov directions to orthogonalize against
779: . -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)
780: . -ksp_pipegcr_nprealloc <N> - the number of vectors to preallocated for storing Krylov directions. Once exhausted new directions are allocated blockwise (default: 5)
781: - -ksp_pipegcr_truncation_type <standard,notay> - which previous search directions to orthogonalize against
783: Notes:
784: The PIPEGCR Krylov method supports non-symmetric matrices and permits the use of a preconditioner
785: which may vary from one iteration to the next. Users can can define a method to vary the
786: preconditioner between iterates via KSPPIPEGCRSetModifyPC().
787: Restarts are solves with x0 not equal to zero. When a restart occurs, the initial starting
788: solution is given by the current estimate for x which was obtained by the last restart
789: iterations of the PIPEGCR algorithm.
790: The method implemented requires at most the storage of 4 x mmax + 5 vectors, roughly twice as much as GCR.
792: Only supports left preconditioning.
794: 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.
796: Reference:
797: P. Sanan, S.M. Schnepp, and D.A. May,
798: "Pipelined, Flexible Krylov Subspace Methods,"
799: SIAM Journal on Scientific Computing 2016 38:5, C441-C470,
800: DOI: 10.1137/15M1049130
802: Level: intermediate
804: .seealso: KSPCreate(), KSPSetType(), KSPType (for list of available types), KSP,
805: KSPPIPEFGMRES, KSPPIPECG, KSPPIPECR, KSPPIPEFCG,KSPPIPEGCRSetTruncationType(),KSPPIPEGCRSetNprealloc(),KSPPIPEGCRSetUnrollW(),KSPPIPEGCRSetMmax()
807: M*/
808: PETSC_EXTERN PetscErrorCode KSPCreate_PIPEGCR(KSP ksp)
809: {
811: KSP_PIPEGCR *pipegcr;
814: PetscNewLog(ksp,&pipegcr);
815: pipegcr->mmax = KSPPIPEGCR_DEFAULT_MMAX;
816: pipegcr->nprealloc = KSPPIPEGCR_DEFAULT_NPREALLOC;
817: pipegcr->nvecs = 0;
818: pipegcr->vecb = KSPPIPEGCR_DEFAULT_VECB;
819: pipegcr->nchunks = 0;
820: pipegcr->truncstrat = KSPPIPEGCR_DEFAULT_TRUNCSTRAT;
821: pipegcr->n_restarts = 0;
822: pipegcr->unroll_w = KSPPIPEGCR_DEFAULT_UNROLL_W;
824: ksp->data = (void*)pipegcr;
826: /* natural norm is for free, precond+unprecond norm require non-overlapped reduction */
827: KSPSetSupportedNorm(ksp,KSP_NORM_NATURAL,PC_LEFT,2);
828: KSPSetSupportedNorm(ksp,KSP_NORM_PRECONDITIONED,PC_LEFT,1);
829: KSPSetSupportedNorm(ksp,KSP_NORM_UNPRECONDITIONED,PC_LEFT,1);
830: KSPSetSupportedNorm(ksp,KSP_NORM_NONE,PC_LEFT,1);
832: ksp->ops->setup = KSPSetUp_PIPEGCR;
833: ksp->ops->solve = KSPSolve_PIPEGCR;
834: ksp->ops->reset = KSPReset_PIPEGCR;
835: ksp->ops->destroy = KSPDestroy_PIPEGCR;
836: ksp->ops->view = KSPView_PIPEGCR;
837: ksp->ops->setfromoptions = KSPSetFromOptions_PIPEGCR;
838: ksp->ops->buildsolution = KSPBuildSolutionDefault;
839: ksp->ops->buildresidual = KSPBuildResidualDefault;
841: PetscObjectComposeFunction((PetscObject)ksp,"KSPPIPEGCRSetModifyPC_C",KSPPIPEGCRSetModifyPC_PIPEGCR);
842: return(0);
843: }