Actual source code: fieldsplit.c
1: #define PETSCKSP_DLL
3: /*
5: */
6: #include private/pcimpl.h
8: const char *PCFieldSplitSchurPreTypes[] = {"self","diag","user","PCFieldSplitSchurPreType","PC_FIELDSPLIT_SCHUR_PRE_",0};
10: typedef struct _PC_FieldSplitLink *PC_FieldSplitLink;
11: struct _PC_FieldSplitLink {
12: KSP ksp;
13: Vec x,y;
14: PetscInt nfields;
15: PetscInt *fields;
16: VecScatter sctx;
17: IS is;
18: PC_FieldSplitLink next,previous;
19: };
21: typedef struct {
22: PCCompositeType type;
23: PetscTruth defaultsplit; /* Flag for a system with a set of 'k' scalar fields with the same layout (and bs = k) */
24: PetscTruth realdiagonal; /* Flag to use the diagonal blocks of mat preconditioned by pmat, instead of just pmat */
25: PetscInt bs; /* Block size for IS and Mat structures */
26: PetscInt nsplits; /* Number of field divisions defined */
27: Vec *x,*y,w1,w2;
28: Mat *mat; /* The diagonal block for each split */
29: Mat *pmat; /* The preconditioning diagonal block for each split */
30: Mat *Afield; /* The rows of the matrix associated with each split */
31: PetscTruth issetup;
32: /* Only used when Schur complement preconditioning is used */
33: Mat B; /* The (0,1) block */
34: Mat C; /* The (1,0) block */
35: Mat schur; /* The Schur complement S = D - C A^{-1} B */
36: Mat schur_user; /* User-provided preconditioning matrix for the Schur complement */
37: PCFieldSplitSchurPreType schurpre; /* Determines which preconditioning matrix is used for the Schur complement */
38: KSP kspschur; /* The solver for S */
39: PC_FieldSplitLink head;
40: } PC_FieldSplit;
42: /*
43: Notes: there is no particular reason that pmat, x, and y are stored as arrays in PC_FieldSplit instead of
44: inside PC_FieldSplitLink, just historical. If you want to be able to add new fields after already using the
45: PC you could change this.
46: */
48: /* This helper is so that setting a user-provided preconditioning matrix is orthogonal to choosing to use it. This way the
49: * application-provided FormJacobian can provide this matrix without interfering with the user's (command-line) choices. */
50: static Mat FieldSplitSchurPre(PC_FieldSplit *jac)
51: {
52: switch (jac->schurpre) {
53: case PC_FIELDSPLIT_SCHUR_PRE_SELF: return jac->schur;
54: case PC_FIELDSPLIT_SCHUR_PRE_DIAG: return jac->pmat[1];
55: case PC_FIELDSPLIT_SCHUR_PRE_USER: /* Use a user-provided matrix if it is given, otherwise diagonal block */
56: default:
57: return jac->schur_user ? jac->schur_user : jac->pmat[1];
58: }
59: }
64: static PetscErrorCode PCView_FieldSplit(PC pc,PetscViewer viewer)
65: {
66: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
67: PetscErrorCode ierr;
68: PetscTruth iascii;
69: PetscInt i,j;
70: PC_FieldSplitLink ilink = jac->head;
73: PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&iascii);
74: if (iascii) {
75: PetscViewerASCIIPrintf(viewer," FieldSplit with %s composition: total splits = %D, blocksize = %D\n",PCCompositeTypes[jac->type],jac->nsplits,jac->bs);
76: PetscViewerASCIIPrintf(viewer," Solver info for each split is in the following KSP objects:\n");
77: PetscViewerASCIIPushTab(viewer);
78: for (i=0; i<jac->nsplits; i++) {
79: if (ilink->fields) {
80: PetscViewerASCIIPrintf(viewer,"Split number %D Fields ",i);
81: PetscViewerASCIIUseTabs(viewer,PETSC_FALSE);
82: for (j=0; j<ilink->nfields; j++) {
83: if (j > 0) {
84: PetscViewerASCIIPrintf(viewer,",");
85: }
86: PetscViewerASCIIPrintf(viewer," %D",ilink->fields[j]);
87: }
88: PetscViewerASCIIPrintf(viewer,"\n");
89: PetscViewerASCIIUseTabs(viewer,PETSC_TRUE);
90: } else {
91: PetscViewerASCIIPrintf(viewer,"Split number %D Defined by IS\n",i);
92: }
93: KSPView(ilink->ksp,viewer);
94: ilink = ilink->next;
95: }
96: PetscViewerASCIIPopTab(viewer);
97: } else {
98: SETERRQ1(PETSC_ERR_SUP,"Viewer type %s not supported for PCFieldSplit",((PetscObject)viewer)->type_name);
99: }
100: return(0);
101: }
105: static PetscErrorCode PCView_FieldSplit_Schur(PC pc,PetscViewer viewer)
106: {
107: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
108: PetscErrorCode ierr;
109: PetscTruth iascii;
110: PetscInt i,j;
111: PC_FieldSplitLink ilink = jac->head;
112: KSP ksp;
115: PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&iascii);
116: if (iascii) {
117: PetscViewerASCIIPrintf(viewer," FieldSplit with Schur preconditioner, blocksize = %D\n",jac->bs);
118: PetscViewerASCIIPrintf(viewer," Split info:\n");
119: PetscViewerASCIIPushTab(viewer);
120: for (i=0; i<jac->nsplits; i++) {
121: if (ilink->fields) {
122: PetscViewerASCIIPrintf(viewer,"Split number %D Fields ",i);
123: PetscViewerASCIIUseTabs(viewer,PETSC_FALSE);
124: for (j=0; j<ilink->nfields; j++) {
125: if (j > 0) {
126: PetscViewerASCIIPrintf(viewer,",");
127: }
128: PetscViewerASCIIPrintf(viewer," %D",ilink->fields[j]);
129: }
130: PetscViewerASCIIPrintf(viewer,"\n");
131: PetscViewerASCIIUseTabs(viewer,PETSC_TRUE);
132: } else {
133: PetscViewerASCIIPrintf(viewer,"Split number %D Defined by IS\n",i);
134: }
135: ilink = ilink->next;
136: }
137: PetscViewerASCIIPrintf(viewer,"KSP solver for A block \n");
138: PetscViewerASCIIPushTab(viewer);
139: if (jac->schur) {
140: MatSchurComplementGetKSP(jac->schur,&ksp);
141: KSPView(ksp,viewer);
142: } else {
143: PetscViewerASCIIPrintf(viewer," not yet available\n");
144: }
145: PetscViewerASCIIPopTab(viewer);
146: PetscViewerASCIIPrintf(viewer,"KSP solver for S = D - C inv(A) B \n");
147: PetscViewerASCIIPushTab(viewer);
148: if (jac->kspschur) {
149: KSPView(jac->kspschur,viewer);
150: } else {
151: PetscViewerASCIIPrintf(viewer," not yet available\n");
152: }
153: PetscViewerASCIIPopTab(viewer);
154: PetscViewerASCIIPopTab(viewer);
155: } else {
156: SETERRQ1(PETSC_ERR_SUP,"Viewer type %s not supported for PCFieldSplit",((PetscObject)viewer)->type_name);
157: }
158: return(0);
159: }
163: static PetscErrorCode PCFieldSplitSetDefaults(PC pc)
164: {
165: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
166: PetscErrorCode ierr;
167: PC_FieldSplitLink ilink = jac->head;
168: PetscInt i = 0,*ifields,nfields;
169: PetscTruth flg = PETSC_FALSE,*fields,flg2;
170: char optionname[128];
173: if (!ilink) {
175: if (jac->bs <= 0) {
176: if (pc->pmat) {
177: MatGetBlockSize(pc->pmat,&jac->bs);
178: } else {
179: jac->bs = 1;
180: }
181: }
183: PetscOptionsGetTruth(((PetscObject)pc)->prefix,"-pc_fieldsplit_default",&flg,PETSC_NULL);
184: if (!flg) {
185: /* Allow user to set fields from command line, if bs was known at the time of PCSetFromOptions_FieldSplit()
186: then it is set there. This is not ideal because we should only have options set in XXSetFromOptions(). */
187: flg = PETSC_TRUE; /* switched off automatically if user sets fields manually here */
188: PetscMalloc(jac->bs*sizeof(PetscInt),&ifields);
189: while (PETSC_TRUE) {
190: sprintf(optionname,"-pc_fieldsplit_%d_fields",(int)i++);
191: nfields = jac->bs;
192: PetscOptionsGetIntArray(((PetscObject)pc)->prefix,optionname,ifields,&nfields,&flg2);
193: if (!flg2) break;
194: if (!nfields) SETERRQ(PETSC_ERR_USER,"Cannot list zero fields");
195: flg = PETSC_FALSE;
196: PCFieldSplitSetFields(pc,nfields,ifields);
197: }
198: PetscFree(ifields);
199: }
200:
201: if (flg) {
202: PetscInfo(pc,"Using default splitting of fields\n");
203: PetscMalloc(jac->bs*sizeof(PetscTruth),&fields);
204: PetscMemzero(fields,jac->bs*sizeof(PetscTruth));
205: while (ilink) {
206: for (i=0; i<ilink->nfields; i++) {
207: fields[ilink->fields[i]] = PETSC_TRUE;
208: }
209: ilink = ilink->next;
210: }
211: jac->defaultsplit = PETSC_TRUE;
212: for (i=0; i<jac->bs; i++) {
213: if (!fields[i]) {
214: PCFieldSplitSetFields(pc,1,&i);
215: } else {
216: jac->defaultsplit = PETSC_FALSE;
217: }
218: }
219: PetscFree(fields);
220: }
221: } else if (jac->nsplits == 1) {
222: if (ilink->is) {
223: IS is2;
224: PetscInt nmin,nmax;
226: MatGetOwnershipRange(pc->mat,&nmin,&nmax);
227: ISComplement(ilink->is,nmin,nmax,&is2);
228: PCFieldSplitSetIS(pc,is2);
229: ISDestroy(is2);
230: } else {
231: SETERRQ(PETSC_ERR_SUP,"Must provide at least two sets of fields to PCFieldSplit()");
232: }
233: }
234: if (jac->nsplits < 2) {
235: SETERRQ(PETSC_ERR_PLIB,"Unhandled case, must have at least two fields");
236: }
237: return(0);
238: }
243: static PetscErrorCode PCSetUp_FieldSplit(PC pc)
244: {
245: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
246: PetscErrorCode ierr;
247: PC_FieldSplitLink ilink;
248: PetscInt i,nsplit,ccsize;
249: MatStructure flag = pc->flag;
250: PetscTruth sorted;
253: PCFieldSplitSetDefaults(pc);
254: nsplit = jac->nsplits;
255: ilink = jac->head;
257: /* get the matrices for each split */
258: if (!jac->issetup) {
259: PetscInt rstart,rend,nslots,bs;
261: jac->issetup = PETSC_TRUE;
263: /* This is done here instead of in PCFieldSplitSetFields() because may not have matrix at that point */
264: bs = jac->bs;
265: MatGetOwnershipRange(pc->pmat,&rstart,&rend);
266: MatGetLocalSize(pc->pmat,PETSC_NULL,&ccsize);
267: nslots = (rend - rstart)/bs;
268: for (i=0; i<nsplit; i++) {
269: if (jac->defaultsplit) {
270: ISCreateStride(((PetscObject)pc)->comm,nslots,rstart+i,nsplit,&ilink->is);
271: } else if (!ilink->is) {
272: if (ilink->nfields > 1) {
273: PetscInt *ii,j,k,nfields = ilink->nfields,*fields = ilink->fields;
274: PetscMalloc(ilink->nfields*nslots*sizeof(PetscInt),&ii);
275: for (j=0; j<nslots; j++) {
276: for (k=0; k<nfields; k++) {
277: ii[nfields*j + k] = rstart + bs*j + fields[k];
278: }
279: }
280: ISCreateGeneral(((PetscObject)pc)->comm,nslots*nfields,ii,&ilink->is);
281: PetscFree(ii);
282: } else {
283: ISCreateStride(((PetscObject)pc)->comm,nslots,rstart+ilink->fields[0],bs,&ilink->is);
284: }
285: }
286: ISSorted(ilink->is,&sorted);
287: if (!sorted) SETERRQ(PETSC_ERR_USER,"Fields must be sorted when creating split");
288: ilink = ilink->next;
289: }
290: }
291:
292: ilink = jac->head;
293: if (!jac->pmat) {
294: PetscMalloc(nsplit*sizeof(Mat),&jac->pmat);
295: for (i=0; i<nsplit; i++) {
296: MatGetSubMatrix(pc->pmat,ilink->is,ilink->is,MAT_INITIAL_MATRIX,&jac->pmat[i]);
297: ilink = ilink->next;
298: }
299: } else {
300: for (i=0; i<nsplit; i++) {
301: MatGetSubMatrix(pc->pmat,ilink->is,ilink->is,MAT_REUSE_MATRIX,&jac->pmat[i]);
302: ilink = ilink->next;
303: }
304: }
305: if (jac->realdiagonal) {
306: ilink = jac->head;
307: if (!jac->mat) {
308: PetscMalloc(nsplit*sizeof(Mat),&jac->mat);
309: for (i=0; i<nsplit; i++) {
310: MatGetSubMatrix(pc->mat,ilink->is,ilink->is,MAT_INITIAL_MATRIX,&jac->mat[i]);
311: ilink = ilink->next;
312: }
313: } else {
314: for (i=0; i<nsplit; i++) {
315: MatGetSubMatrix(pc->mat,ilink->is,ilink->is,MAT_REUSE_MATRIX,&jac->mat[i]);
316: ilink = ilink->next;
317: }
318: }
319: } else {
320: jac->mat = jac->pmat;
321: }
323: if (jac->type != PC_COMPOSITE_ADDITIVE && jac->type != PC_COMPOSITE_SCHUR) {
324: /* extract the rows of the matrix associated with each field: used for efficient computation of residual inside algorithm */
325: ilink = jac->head;
326: if (!jac->Afield) {
327: PetscMalloc(nsplit*sizeof(Mat),&jac->Afield);
328: for (i=0; i<nsplit; i++) {
329: MatGetSubMatrix(pc->mat,ilink->is,PETSC_NULL,MAT_INITIAL_MATRIX,&jac->Afield[i]);
330: ilink = ilink->next;
331: }
332: } else {
333: for (i=0; i<nsplit; i++) {
334: MatGetSubMatrix(pc->mat,ilink->is,PETSC_NULL,MAT_REUSE_MATRIX,&jac->Afield[i]);
335: ilink = ilink->next;
336: }
337: }
338: }
340: if (jac->type == PC_COMPOSITE_SCHUR) {
341: IS ccis;
342: PetscInt rstart,rend;
343: if (nsplit != 2) SETERRQ(PETSC_ERR_ARG_INCOMP,"To use Schur complement preconditioner you must have exactly 2 fields");
345: /* When extracting off-diagonal submatrices, we take complements from this range */
346: MatGetOwnershipRangeColumn(pc->mat,&rstart,&rend);
348: /* need to handle case when one is resetting up the preconditioner */
349: if (jac->schur) {
350: ilink = jac->head;
351: ISComplement(ilink->is,rstart,rend,&ccis);
352: MatGetSubMatrix(pc->mat,ilink->is,ccis,MAT_REUSE_MATRIX,&jac->B);
353: ISDestroy(ccis);
354: ilink = ilink->next;
355: ISComplement(ilink->is,rstart,rend,&ccis);
356: MatGetSubMatrix(pc->mat,ilink->is,ccis,MAT_REUSE_MATRIX,&jac->C);
357: ISDestroy(ccis);
358: MatSchurComplementUpdate(jac->schur,jac->mat[0],jac->pmat[0],jac->B,jac->C,jac->pmat[1],pc->flag);
359: KSPSetOperators(jac->kspschur,jac->schur,FieldSplitSchurPre(jac),pc->flag);
361: } else {
362: KSP ksp;
364: /* extract the B and C matrices */
365: ilink = jac->head;
366: ISComplement(ilink->is,rstart,rend,&ccis);
367: MatGetSubMatrix(pc->mat,ilink->is,ccis,MAT_INITIAL_MATRIX,&jac->B);
368: ISDestroy(ccis);
369: ilink = ilink->next;
370: ISComplement(ilink->is,rstart,rend,&ccis);
371: MatGetSubMatrix(pc->mat,ilink->is,ccis,MAT_INITIAL_MATRIX,&jac->C);
372: ISDestroy(ccis);
373: /* Better would be to use 'mat[0]' (diagonal block of the real matrix) preconditioned by pmat[0] */
374: MatCreateSchurComplement(jac->mat[0],jac->pmat[0],jac->B,jac->C,jac->mat[1],&jac->schur);
375: MatSchurComplementGetKSP(jac->schur,&ksp);
376: PetscObjectIncrementTabLevel((PetscObject)ksp,(PetscObject)pc,2);
377: MatSetFromOptions(jac->schur);
379: KSPCreate(((PetscObject)pc)->comm,&jac->kspschur);
380: PetscObjectIncrementTabLevel((PetscObject)jac->kspschur,(PetscObject)pc,1);
381: KSPSetOperators(jac->kspschur,jac->schur,FieldSplitSchurPre(jac),DIFFERENT_NONZERO_PATTERN);
382: if (jac->schurpre == PC_FIELDSPLIT_SCHUR_PRE_SELF) {
383: PC pc;
384: KSPGetPC(jac->kspschur,&pc);
385: PCSetType(pc,PCNONE);
386: /* Note: This is bad if there exist preconditioners for MATSCHURCOMPLEMENT */
387: }
388: KSPSetOptionsPrefix(jac->kspschur,((PetscObject)pc)->prefix);
389: KSPAppendOptionsPrefix(jac->kspschur,"fieldsplit_1_");
390: /* really want setfromoptions called in PCSetFromOptions_FieldSplit(), but it is not ready yet */
391: KSPSetFromOptions(jac->kspschur);
393: PetscMalloc2(2,Vec,&jac->x,2,Vec,&jac->y);
394: MatGetVecs(jac->pmat[0],&jac->x[0],&jac->y[0]);
395: MatGetVecs(jac->pmat[1],&jac->x[1],&jac->y[1]);
396: ilink = jac->head;
397: ilink->x = jac->x[0]; ilink->y = jac->y[0];
398: ilink = ilink->next;
399: ilink->x = jac->x[1]; ilink->y = jac->y[1];
400: }
401: } else {
402: /* set up the individual PCs */
403: i = 0;
404: ilink = jac->head;
405: while (ilink) {
406: KSPSetOperators(ilink->ksp,jac->mat[i],jac->pmat[i],flag);
407: /* really want setfromoptions called in PCSetFromOptions_FieldSplit(), but it is not ready yet */
408: KSPSetFromOptions(ilink->ksp);
409: KSPSetUp(ilink->ksp);
410: i++;
411: ilink = ilink->next;
412: }
413:
414: /* create work vectors for each split */
415: if (!jac->x) {
416: PetscMalloc2(nsplit,Vec,&jac->x,nsplit,Vec,&jac->y);
417: ilink = jac->head;
418: for (i=0; i<nsplit; i++) {
419: Vec *vl,*vr;
421: KSPGetVecs(ilink->ksp,1,&vr,1,&vl);
422: ilink->x = *vr;
423: ilink->y = *vl;
424: PetscFree(vr);
425: PetscFree(vl);
426: jac->x[i] = ilink->x;
427: jac->y[i] = ilink->y;
428: ilink = ilink->next;
429: }
430: }
431: }
434: if (!jac->head->sctx) {
435: Vec xtmp;
437: /* compute scatter contexts needed by multiplicative versions and non-default splits */
438:
439: ilink = jac->head;
440: MatGetVecs(pc->pmat,&xtmp,PETSC_NULL);
441: for (i=0; i<nsplit; i++) {
442: VecScatterCreate(xtmp,ilink->is,jac->x[i],PETSC_NULL,&ilink->sctx);
443: ilink = ilink->next;
444: }
445: VecDestroy(xtmp);
446: }
447: return(0);
448: }
450: #define FieldSplitSplitSolveAdd(ilink,xx,yy) \
451: (VecScatterBegin(ilink->sctx,xx,ilink->x,INSERT_VALUES,SCATTER_FORWARD) || \
452: VecScatterEnd(ilink->sctx,xx,ilink->x,INSERT_VALUES,SCATTER_FORWARD) || \
453: KSPSolve(ilink->ksp,ilink->x,ilink->y) || \
454: VecScatterBegin(ilink->sctx,ilink->y,yy,ADD_VALUES,SCATTER_REVERSE) || \
455: VecScatterEnd(ilink->sctx,ilink->y,yy,ADD_VALUES,SCATTER_REVERSE))
459: static PetscErrorCode PCApply_FieldSplit_Schur(PC pc,Vec x,Vec y)
460: {
461: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
462: PetscErrorCode ierr;
463: KSP ksp;
464: PC_FieldSplitLink ilinkA = jac->head, ilinkD = ilinkA->next;
467: MatSchurComplementGetKSP(jac->schur,&ksp);
469: VecScatterBegin(ilinkA->sctx,x,ilinkA->x,INSERT_VALUES,SCATTER_FORWARD);
470: VecScatterEnd(ilinkA->sctx,x,ilinkA->x,INSERT_VALUES,SCATTER_FORWARD);
471: KSPSolve(ksp,ilinkA->x,ilinkA->y);
472: MatMult(jac->C,ilinkA->y,ilinkD->x);
473: VecScale(ilinkD->x,-1.0);
474: VecScatterBegin(ilinkD->sctx,x,ilinkD->x,ADD_VALUES,SCATTER_FORWARD);
475: VecScatterEnd(ilinkD->sctx,x,ilinkD->x,ADD_VALUES,SCATTER_FORWARD);
477: KSPSolve(jac->kspschur,ilinkD->x,ilinkD->y);
478: VecScatterBegin(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);
479: VecScatterEnd(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);
481: MatMult(jac->B,ilinkD->y,ilinkA->y);
482: VecAXPY(ilinkA->x,-1.0,ilinkA->y);
483: KSPSolve(ksp,ilinkA->x,ilinkA->y);
484: VecScatterBegin(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);
485: VecScatterEnd(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);
487: return(0);
488: }
492: static PetscErrorCode PCApply_FieldSplit(PC pc,Vec x,Vec y)
493: {
494: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
495: PetscErrorCode ierr;
496: PC_FieldSplitLink ilink = jac->head;
497: PetscInt cnt;
500: CHKMEMQ;
501: VecSetBlockSize(x,jac->bs);
502: VecSetBlockSize(y,jac->bs);
504: if (jac->type == PC_COMPOSITE_ADDITIVE) {
505: if (jac->defaultsplit) {
506: VecStrideGatherAll(x,jac->x,INSERT_VALUES);
507: while (ilink) {
508: KSPSolve(ilink->ksp,ilink->x,ilink->y);
509: ilink = ilink->next;
510: }
511: VecStrideScatterAll(jac->y,y,INSERT_VALUES);
512: } else {
513: VecSet(y,0.0);
514: while (ilink) {
515: FieldSplitSplitSolveAdd(ilink,x,y);
516: ilink = ilink->next;
517: }
518: }
519: } else if (jac->type == PC_COMPOSITE_MULTIPLICATIVE || jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
520: if (!jac->w1) {
521: VecDuplicate(x,&jac->w1);
522: VecDuplicate(x,&jac->w2);
523: }
524: VecSet(y,0.0);
525: FieldSplitSplitSolveAdd(ilink,x,y);
526: cnt = 1;
527: while (ilink->next) {
528: ilink = ilink->next;
529: /* compute the residual only over the part of the vector needed */
530: MatMult(jac->Afield[cnt++],y,ilink->x);
531: VecScale(ilink->x,-1.0);
532: VecScatterBegin(ilink->sctx,x,ilink->x,ADD_VALUES,SCATTER_FORWARD);
533: VecScatterEnd(ilink->sctx,x,ilink->x,ADD_VALUES,SCATTER_FORWARD);
534: KSPSolve(ilink->ksp,ilink->x,ilink->y);
535: VecScatterBegin(ilink->sctx,ilink->y,y,ADD_VALUES,SCATTER_REVERSE);
536: VecScatterEnd(ilink->sctx,ilink->y,y,ADD_VALUES,SCATTER_REVERSE);
537: }
538: if (jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
539: cnt -= 2;
540: while (ilink->previous) {
541: ilink = ilink->previous;
542: /* compute the residual only over the part of the vector needed */
543: MatMult(jac->Afield[cnt--],y,ilink->x);
544: VecScale(ilink->x,-1.0);
545: VecScatterBegin(ilink->sctx,x,ilink->x,ADD_VALUES,SCATTER_FORWARD);
546: VecScatterEnd(ilink->sctx,x,ilink->x,ADD_VALUES,SCATTER_FORWARD);
547: KSPSolve(ilink->ksp,ilink->x,ilink->y);
548: VecScatterBegin(ilink->sctx,ilink->y,y,ADD_VALUES,SCATTER_REVERSE);
549: VecScatterEnd(ilink->sctx,ilink->y,y,ADD_VALUES,SCATTER_REVERSE);
550: }
551: }
552: } else SETERRQ1(PETSC_ERR_SUP,"Unsupported or unknown composition",(int) jac->type);
553: CHKMEMQ;
554: return(0);
555: }
557: #define FieldSplitSplitSolveAddTranspose(ilink,xx,yy) \
558: (VecScatterBegin(ilink->sctx,xx,ilink->y,INSERT_VALUES,SCATTER_FORWARD) || \
559: VecScatterEnd(ilink->sctx,xx,ilink->y,INSERT_VALUES,SCATTER_FORWARD) || \
560: KSPSolveTranspose(ilink->ksp,ilink->y,ilink->x) || \
561: VecScatterBegin(ilink->sctx,ilink->x,yy,ADD_VALUES,SCATTER_REVERSE) || \
562: VecScatterEnd(ilink->sctx,ilink->x,yy,ADD_VALUES,SCATTER_REVERSE))
566: static PetscErrorCode PCApplyTranspose_FieldSplit(PC pc,Vec x,Vec y)
567: {
568: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
569: PetscErrorCode ierr;
570: PC_FieldSplitLink ilink = jac->head;
573: CHKMEMQ;
574: VecSetBlockSize(x,jac->bs);
575: VecSetBlockSize(y,jac->bs);
577: if (jac->type == PC_COMPOSITE_ADDITIVE) {
578: if (jac->defaultsplit) {
579: VecStrideGatherAll(x,jac->x,INSERT_VALUES);
580: while (ilink) {
581: KSPSolveTranspose(ilink->ksp,ilink->x,ilink->y);
582: ilink = ilink->next;
583: }
584: VecStrideScatterAll(jac->y,y,INSERT_VALUES);
585: } else {
586: VecSet(y,0.0);
587: while (ilink) {
588: FieldSplitSplitSolveAddTranspose(ilink,x,y);
589: ilink = ilink->next;
590: }
591: }
592: } else {
593: if (!jac->w1) {
594: VecDuplicate(x,&jac->w1);
595: VecDuplicate(x,&jac->w2);
596: }
597: VecSet(y,0.0);
598: if (jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
599: FieldSplitSplitSolveAddTranspose(ilink,x,y);
600: while (ilink->next) {
601: ilink = ilink->next;
602: MatMultTranspose(pc->mat,y,jac->w1);
603: VecWAXPY(jac->w2,-1.0,jac->w1,x);
604: FieldSplitSplitSolveAddTranspose(ilink,jac->w2,y);
605: }
606: while (ilink->previous) {
607: ilink = ilink->previous;
608: MatMultTranspose(pc->mat,y,jac->w1);
609: VecWAXPY(jac->w2,-1.0,jac->w1,x);
610: FieldSplitSplitSolveAddTranspose(ilink,jac->w2,y);
611: }
612: } else {
613: while (ilink->next) { /* get to last entry in linked list */
614: ilink = ilink->next;
615: }
616: FieldSplitSplitSolveAddTranspose(ilink,x,y);
617: while (ilink->previous) {
618: ilink = ilink->previous;
619: MatMultTranspose(pc->mat,y,jac->w1);
620: VecWAXPY(jac->w2,-1.0,jac->w1,x);
621: FieldSplitSplitSolveAddTranspose(ilink,jac->w2,y);
622: }
623: }
624: }
625: CHKMEMQ;
626: return(0);
627: }
631: static PetscErrorCode PCDestroy_FieldSplit(PC pc)
632: {
633: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
634: PetscErrorCode ierr;
635: PC_FieldSplitLink ilink = jac->head,next;
638: while (ilink) {
639: KSPDestroy(ilink->ksp);
640: if (ilink->x) {VecDestroy(ilink->x);}
641: if (ilink->y) {VecDestroy(ilink->y);}
642: if (ilink->sctx) {VecScatterDestroy(ilink->sctx);}
643: if (ilink->is) {ISDestroy(ilink->is);}
644: next = ilink->next;
645: PetscFree(ilink->fields);
646: PetscFree(ilink);
647: ilink = next;
648: }
649: PetscFree2(jac->x,jac->y);
650: if (jac->mat && jac->mat != jac->pmat) {MatDestroyMatrices(jac->nsplits,&jac->mat);}
651: if (jac->pmat) {MatDestroyMatrices(jac->nsplits,&jac->pmat);}
652: if (jac->Afield) {MatDestroyMatrices(jac->nsplits,&jac->Afield);}
653: if (jac->w1) {VecDestroy(jac->w1);}
654: if (jac->w2) {VecDestroy(jac->w2);}
655: if (jac->schur) {MatDestroy(jac->schur);}
656: if (jac->schur_user) {MatDestroy(jac->schur_user);}
657: if (jac->kspschur) {KSPDestroy(jac->kspschur);}
658: if (jac->B) {MatDestroy(jac->B);}
659: if (jac->C) {MatDestroy(jac->C);}
660: PetscFree(jac);
661: return(0);
662: }
666: static PetscErrorCode PCSetFromOptions_FieldSplit(PC pc)
667: {
668: PetscErrorCode ierr;
669: PetscInt i = 0,nfields,*fields,bs;
670: PetscTruth flg;
671: char optionname[128];
672: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
673: PCCompositeType ctype;
676: PetscOptionsHead("FieldSplit options");
677: PetscOptionsTruth("-pc_fieldsplit_real_diagonal","Use diagonal blocks of the operator","PCFieldSplitSetRealDiagonal",jac->realdiagonal,&jac->realdiagonal,PETSC_NULL);
678: PetscOptionsInt("-pc_fieldsplit_block_size","Blocksize that defines number of fields","PCFieldSplitSetBlockSize",jac->bs,&bs,&flg);
679: if (flg) {
680: PCFieldSplitSetBlockSize(pc,bs);
681: }
683: PetscOptionsEnum("-pc_fieldsplit_type","Type of composition","PCFieldSplitSetType",PCCompositeTypes,(PetscEnum)jac->type,(PetscEnum*)&ctype,&flg);
684: if (flg) {
685: PCFieldSplitSetType(pc,ctype);
686: }
688: /* Only setup fields once */
689: if ((jac->bs > 0) && (jac->nsplits == 0)) {
690: /* only allow user to set fields from command line if bs is already known.
691: otherwise user can set them in PCFieldSplitSetDefaults() */
692: PetscMalloc(jac->bs*sizeof(PetscInt),&fields);
693: while (PETSC_TRUE) {
694: sprintf(optionname,"-pc_fieldsplit_%d_fields",(int)i++);
695: nfields = jac->bs;
696: PetscOptionsIntArray(optionname,"Fields in this split","PCFieldSplitSetFields",fields,&nfields,&flg);
697: if (!flg) break;
698: if (!nfields) SETERRQ(PETSC_ERR_USER,"Cannot list zero fields");
699: PCFieldSplitSetFields(pc,nfields,fields);
700: }
701: PetscFree(fields);
702: }
703: PetscOptionsEnum("-pc_fieldsplit_schur_precondition","How to build preconditioner for Schur complement","PCFieldSplitSchurPrecondition",PCFieldSplitSchurPreTypes,(PetscEnum)jac->schurpre,(PetscEnum*)&jac->schurpre,PETSC_NULL);
704: PetscOptionsTail();
705: return(0);
706: }
708: /*------------------------------------------------------------------------------------*/
713: PetscErrorCode PCFieldSplitSetFields_FieldSplit(PC pc,PetscInt n,PetscInt *fields)
714: {
715: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
716: PetscErrorCode ierr;
717: PC_FieldSplitLink ilink,next = jac->head;
718: char prefix[128];
719: PetscInt i;
722: if (n <= 0) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Negative number of fields requested");
723: for (i=0; i<n; i++) {
724: if (fields[i] >= jac->bs) SETERRQ2(PETSC_ERR_ARG_OUTOFRANGE,"Field %D requested but only %D exist",fields[i],jac->bs);
725: if (fields[i] < 0) SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"Negative field %D requested",fields[i]);
726: }
727: PetscNew(struct _PC_FieldSplitLink,&ilink);
728: PetscMalloc(n*sizeof(PetscInt),&ilink->fields);
729: PetscMemcpy(ilink->fields,fields,n*sizeof(PetscInt));
730: ilink->nfields = n;
731: ilink->next = PETSC_NULL;
732: KSPCreate(((PetscObject)pc)->comm,&ilink->ksp);
733: PetscObjectIncrementTabLevel((PetscObject)ilink->ksp,(PetscObject)pc,1);
734: KSPSetType(ilink->ksp,KSPPREONLY);
736: if (((PetscObject)pc)->prefix) {
737: sprintf(prefix,"%sfieldsplit_%d_",((PetscObject)pc)->prefix,(int)jac->nsplits);
738: } else {
739: sprintf(prefix,"fieldsplit_%d_",(int)jac->nsplits);
740: }
741: KSPSetOptionsPrefix(ilink->ksp,prefix);
743: if (!next) {
744: jac->head = ilink;
745: ilink->previous = PETSC_NULL;
746: } else {
747: while (next->next) {
748: next = next->next;
749: }
750: next->next = ilink;
751: ilink->previous = next;
752: }
753: jac->nsplits++;
754: return(0);
755: }
761: PetscErrorCode PCFieldSplitGetSubKSP_FieldSplit_Schur(PC pc,PetscInt *n,KSP **subksp)
762: {
763: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
767: PetscMalloc(jac->nsplits*sizeof(KSP),subksp);
768: MatSchurComplementGetKSP(jac->schur,*subksp);
769: (*subksp)[1] = jac->kspschur;
770: *n = jac->nsplits;
771: return(0);
772: }
778: PetscErrorCode PCFieldSplitGetSubKSP_FieldSplit(PC pc,PetscInt *n,KSP **subksp)
779: {
780: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
781: PetscErrorCode ierr;
782: PetscInt cnt = 0;
783: PC_FieldSplitLink ilink = jac->head;
786: PetscMalloc(jac->nsplits*sizeof(KSP*),subksp);
787: while (ilink) {
788: (*subksp)[cnt++] = ilink->ksp;
789: ilink = ilink->next;
790: }
791: if (cnt != jac->nsplits) SETERRQ2(PETSC_ERR_PLIB,"Corrupt PCFIELDSPLIT object: number splits in linked list %D in object %D",cnt,jac->nsplits);
792: *n = jac->nsplits;
793: return(0);
794: }
800: PetscErrorCode PCFieldSplitSetIS_FieldSplit(PC pc,IS is)
801: {
802: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
803: PetscErrorCode ierr;
804: PC_FieldSplitLink ilink, next = jac->head;
805: char prefix[128];
808: PetscNew(struct _PC_FieldSplitLink,&ilink);
809: ilink->is = is;
810: PetscObjectReference((PetscObject)is);
811: ilink->next = PETSC_NULL;
812: KSPCreate(((PetscObject)pc)->comm,&ilink->ksp);
813: PetscObjectIncrementTabLevel((PetscObject)ilink->ksp,(PetscObject)pc,1);
814: KSPSetType(ilink->ksp,KSPPREONLY);
816: if (((PetscObject)pc)->prefix) {
817: sprintf(prefix,"%sfieldsplit_%d_",((PetscObject)pc)->prefix,(int)jac->nsplits);
818: } else {
819: sprintf(prefix,"fieldsplit_%d_",(int)jac->nsplits);
820: }
821: KSPSetOptionsPrefix(ilink->ksp,prefix);
823: if (!next) {
824: jac->head = ilink;
825: ilink->previous = PETSC_NULL;
826: } else {
827: while (next->next) {
828: next = next->next;
829: }
830: next->next = ilink;
831: ilink->previous = next;
832: }
833: jac->nsplits++;
835: return(0);
836: }
841: /*@
842: PCFieldSplitSetFields - Sets the fields for one particular split in the field split preconditioner
844: Collective on PC
846: Input Parameters:
847: + pc - the preconditioner context
848: . n - the number of fields in this split
849: . fields - the fields in this split
851: Level: intermediate
853: Notes: Use PCFieldSplitSetIS() to set a completely general set of indices as a field.
855: The PCFieldSplitSetFields() is for defining fields as a strided blocks. For example, if the block
856: size is three then one can define a field as 0, or 1 or 2 or 0,1 or 0,2 or 1,2 which mean
857: 0xx3xx6xx9xx12 ... x1xx4xx7xx ... xx2xx5xx8xx.. 01x34x67x... 0x1x3x5x7.. x12x45x78x....
858: where the numbered entries indicate what is in the field.
860: .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetBlockSize(), PCFieldSplitSetIS()
862: @*/
863: PetscErrorCode PCFieldSplitSetFields(PC pc,PetscInt n, PetscInt *fields)
864: {
865: PetscErrorCode ierr,(*f)(PC,PetscInt,PetscInt *);
869: PetscObjectQueryFunction((PetscObject)pc,"PCFieldSplitSetFields_C",(void (**)(void))&f);
870: if (f) {
871: (*f)(pc,n,fields);
872: }
873: return(0);
874: }
878: /*@
879: PCFieldSplitSetIS - Sets the exact elements for field
881: Collective on PC
883: Input Parameters:
884: + pc - the preconditioner context
885: . is - the index set that defines the vector elements in this field
888: Notes: Use PCFieldSplitSetFields(), for fields defined by strided types.
890: Level: intermediate
892: .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetBlockSize()
894: @*/
895: PetscErrorCode PCFieldSplitSetIS(PC pc,IS is)
896: {
897: PetscErrorCode ierr,(*f)(PC,IS);
902: PetscObjectQueryFunction((PetscObject)pc,"PCFieldSplitSetIS_C",(void (**)(void))&f);
903: if (f) {
904: (*f)(pc,is);
905: }
906: return(0);
907: }
911: /*@
912: PCFieldSplitSetBlockSize - Sets the block size for defining where fields start in the
913: fieldsplit preconditioner. If not set the matrix block size is used.
915: Collective on PC
917: Input Parameters:
918: + pc - the preconditioner context
919: - bs - the block size
921: Level: intermediate
923: .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetFields()
925: @*/
926: PetscErrorCode PCFieldSplitSetBlockSize(PC pc,PetscInt bs)
927: {
928: PetscErrorCode ierr,(*f)(PC,PetscInt);
932: PetscObjectQueryFunction((PetscObject)pc,"PCFieldSplitSetBlockSize_C",(void (**)(void))&f);
933: if (f) {
934: (*f)(pc,bs);
935: }
936: return(0);
937: }
941: /*@C
942: PCFieldSplitGetSubKSP - Gets the KSP contexts for all splits
943:
944: Collective on KSP
946: Input Parameter:
947: . pc - the preconditioner context
949: Output Parameters:
950: + n - the number of split
951: - pc - the array of KSP contexts
953: Note:
954: After PCFieldSplitGetSubKSP() the array of KSPs IS to be freed by the user
955: (not the KSP just the array that contains them).
957: You must call KSPSetUp() before calling PCFieldSplitGetSubKSP().
959: Level: advanced
961: .seealso: PCFIELDSPLIT
962: @*/
963: PetscErrorCode PCFieldSplitGetSubKSP(PC pc,PetscInt *n,KSP *subksp[])
964: {
965: PetscErrorCode ierr,(*f)(PC,PetscInt*,KSP **);
970: PetscObjectQueryFunction((PetscObject)pc,"PCFieldSplitGetSubKSP_C",(void (**)(void))&f);
971: if (f) {
972: (*f)(pc,n,subksp);
973: } else {
974: SETERRQ(PETSC_ERR_ARG_WRONG,"Cannot get subksp for this type of PC");
975: }
976: return(0);
977: }
981: /*@
982: PCFieldSplitSchurPrecondition - Indicates if the Schur complement is preconditioned by a preconditioner constructed by the
983: D matrix. Otherwise no preconditioner is used.
985: Collective on PC
987: Input Parameters:
988: + pc - the preconditioner context
989: . ptype - which matrix to use for preconditioning the Schur complement
990: - userpre - matrix to use for preconditioning, or PETSC_NULL
992: Notes:
993: The default is to use the block on the diagonal of the preconditioning matrix. This is D, in the (1,1) position.
994: There are currently no preconditioners that work directly with the Schur complement so setting
995: PC_FIELDSPLIT_SCHUR_PRE_SELF is observationally equivalent to -fieldsplit_1_pc_type none.
997: Options Database:
998: . -pc_fieldsplit_schur_precondition <self,user,diag> default is diag
1000: Level: intermediate
1002: .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetFields(), PCFieldSplitSchurPreType
1004: @*/
1005: PetscErrorCode PCFieldSplitSchurPrecondition(PC pc,PCFieldSplitSchurPreType ptype,Mat pre)
1006: {
1007: PetscErrorCode ierr,(*f)(PC,PCFieldSplitSchurPreType,Mat);
1011: PetscObjectQueryFunction((PetscObject)pc,"PCFieldSplitSchurPrecondition_C",(void (**)(void))&f);
1012: if (f) {
1013: (*f)(pc,ptype,pre);
1014: }
1015: return(0);
1016: }
1021: PetscErrorCode PCFieldSplitSchurPrecondition_FieldSplit(PC pc,PCFieldSplitSchurPreType ptype,Mat pre)
1022: {
1023: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
1024: PetscErrorCode ierr;
1027: jac->schurpre = ptype;
1028: if (pre) {
1029: if (jac->schur_user) {MatDestroy(jac->schur_user);}
1030: jac->schur_user = pre;
1031: PetscObjectReference((PetscObject)jac->schur_user);
1032: }
1033: return(0);
1034: }
1039: /*@C
1040: PCFieldSplitGetSchurBlocks - Gets the all matrix blocks for the Schur complement
1041:
1042: Collective on KSP
1044: Input Parameter:
1045: . pc - the preconditioner context
1047: Output Parameters:
1048: + A - the (0,0) block
1049: . B - the (0,1) block
1050: . C - the (1,0) block
1051: - D - the (1,1) block
1053: Level: advanced
1055: .seealso: PCFIELDSPLIT
1056: @*/
1057: PetscErrorCode PCFieldSplitGetSchurBlocks(PC pc,Mat *A,Mat *B,Mat *C, Mat *D)
1058: {
1059: PC_FieldSplit *jac = (PC_FieldSplit *) pc->data;
1063: if (jac->type != PC_COMPOSITE_SCHUR) {SETERRQ(PETSC_ERR_ARG_WRONG, "FieldSplit is not using a Schur complement approach.");}
1064: if (A) *A = jac->pmat[0];
1065: if (B) *B = jac->B;
1066: if (C) *C = jac->C;
1067: if (D) *D = jac->pmat[1];
1068: return(0);
1069: }
1074: PetscErrorCode PCFieldSplitSetType_FieldSplit(PC pc,PCCompositeType type)
1075: {
1076: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
1080: jac->type = type;
1081: if (type == PC_COMPOSITE_SCHUR) {
1082: pc->ops->apply = PCApply_FieldSplit_Schur;
1083: pc->ops->view = PCView_FieldSplit_Schur;
1084: PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitGetSubKSP_C","PCFieldSplitGetSubKSP_FieldSplit_Schur",PCFieldSplitGetSubKSP_FieldSplit_Schur);
1085: PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSchurPrecondition_C","PCFieldSplitSchurPrecondition_FieldSplit",PCFieldSplitSchurPrecondition_FieldSplit);
1087: } else {
1088: pc->ops->apply = PCApply_FieldSplit;
1089: pc->ops->view = PCView_FieldSplit;
1090: PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitGetSubKSP_C","PCFieldSplitGetSubKSP_FieldSplit",PCFieldSplitGetSubKSP_FieldSplit);
1091: PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSchurPrecondition_C","",0);
1092: }
1093: return(0);
1094: }
1100: PetscErrorCode PCFieldSplitSetBlockSize_FieldSplit(PC pc,PetscInt bs)
1101: {
1102: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
1105: if (bs < 1) SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"Blocksize must be positive, you gave %D",bs);
1106: if (jac->bs > 0 && jac->bs != bs) SETERRQ2(PETSC_ERR_ARG_WRONGSTATE,"Cannot change fieldsplit blocksize from %D to %D after it has been set",jac->bs,bs);
1107: jac->bs = bs;
1108: return(0);
1109: }
1114: /*@
1115: PCFieldSplitSetType - Sets the type of fieldsplit preconditioner.
1116:
1117: Collective on PC
1119: Input Parameter:
1120: . pc - the preconditioner context
1121: . type - PC_COMPOSITE_ADDITIVE, PC_COMPOSITE_MULTIPLICATIVE (default), PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE, PC_COMPOSITE_SPECIAL, PC_COMPOSITE_SCHUR
1123: Options Database Key:
1124: . -pc_fieldsplit_type <type: one of multiplicative, additive, symmetric_multiplicative, special, schur> - Sets fieldsplit preconditioner type
1126: Level: Developer
1128: .keywords: PC, set, type, composite preconditioner, additive, multiplicative
1130: .seealso: PCCompositeSetType()
1132: @*/
1133: PetscErrorCode PCFieldSplitSetType(PC pc,PCCompositeType type)
1134: {
1135: PetscErrorCode ierr,(*f)(PC,PCCompositeType);
1139: PetscObjectQueryFunction((PetscObject)pc,"PCFieldSplitSetType_C",(void (**)(void))&f);
1140: if (f) {
1141: (*f)(pc,type);
1142: }
1143: return(0);
1144: }
1146: /* -------------------------------------------------------------------------------------*/
1147: /*MC
1148: PCFIELDSPLIT - Preconditioner created by combining separate preconditioners for individual
1149: fields or groups of fields
1152: To set options on the solvers for each block append -fieldsplit_ to all the PC
1153: options database keys. For example, -fieldsplit_pc_type ilu -fieldsplit_pc_factor_levels 1
1154:
1155: To set the options on the solvers separate for each block call PCFieldSplitGetSubKSP()
1156: and set the options directly on the resulting KSP object
1158: Level: intermediate
1160: Options Database Keys:
1161: + -pc_fieldsplit_%d_fields <a,b,..> - indicates the fields to be used in the %d'th split
1162: . -pc_fieldsplit_default - automatically add any fields to additional splits that have not
1163: been supplied explicitly by -pc_fieldsplit_%d_fields
1164: . -pc_fieldsplit_block_size <bs> - size of block that defines fields (i.e. there are bs fields)
1165: . -pc_fieldsplit_type <additive,multiplicative,schur,symmetric_multiplicative>
1166: . -pc_fieldsplit_schur_precondition <true,false> default is true
1168: - Options prefix for inner solvers when using Schur complement preconditioner are -fieldsplit_0_ and -fieldsplit_1_
1169: for all other solvers they are -fieldsplit_%d_ for the dth field, use -fieldsplit_ for all fields
1172: Notes: use PCFieldSplitSetFields() to set fields defined by "strided" entries and PCFieldSplitSetIS()
1173: to define a field by an arbitrary collection of entries.
1175: If no fields are set the default is used. The fields are defined by entries strided by bs,
1176: beginning at 0 then 1, etc to bs-1. The block size can be set with PCFieldSplitSetBlockSize(),
1177: if this is not called the block size defaults to the blocksize of the second matrix passed
1178: to KSPSetOperators()/PCSetOperators().
1180: Currently for the multiplicative version, the updated residual needed for the next field
1181: solve is computed via a matrix vector product over the entire array. An optimization would be
1182: to update the residual only for the part of the right hand side associated with the next field
1183: solve. (This would involve more MatGetSubMatrix() calls or some other mechanism to compute the
1184: part of the matrix needed to just update part of the residual).
1186: For the Schur complement preconditioner if J = ( A B )
1187: ( C D )
1188: the preconditioner is
1189: (I -B inv(A)) ( inv(A) 0 ) (I 0 )
1190: (0 I ) ( 0 inv(S) ) (-C inv(A) I )
1191: where the action of inv(A) is applied using the KSP solver with prefix -fieldsplit_0_. The action of
1192: inv(S) is computed using the KSP solver with prefix -schur_. For PCFieldSplitGetKSP() when field number is
1193: 0 it returns the KSP associated with -fieldsplit_0_ while field number 1 gives -fieldsplit_1_ KSP. By default
1194: D is used to construct a preconditioner for S, use PCFieldSplitSchurPrecondition() to turn on or off this
1195: option.
1196:
1197: If only one set of indices (one IS) is provided with PCFieldSplitSetIS() then the complement of that IS
1198: is used automatically for a second block.
1200: Concepts: physics based preconditioners, block preconditioners
1202: .seealso: PCCreate(), PCSetType(), PCType (for list of available types), PC, Block_Preconditioners
1203: PCFieldSplitGetSubKSP(), PCFieldSplitSetFields(), PCFieldSplitSetType(), PCFieldSplitSetIS(), PCFieldSplitSchurPrecondition()
1204: M*/
1209: PetscErrorCode PCCreate_FieldSplit(PC pc)
1210: {
1212: PC_FieldSplit *jac;
1215: PetscNewLog(pc,PC_FieldSplit,&jac);
1216: jac->bs = -1;
1217: jac->nsplits = 0;
1218: jac->type = PC_COMPOSITE_MULTIPLICATIVE;
1219: jac->schurpre = PC_FIELDSPLIT_SCHUR_PRE_USER; /* Try user preconditioner first, fall back on diagonal */
1221: pc->data = (void*)jac;
1223: pc->ops->apply = PCApply_FieldSplit;
1224: pc->ops->applytranspose = PCApplyTranspose_FieldSplit;
1225: pc->ops->setup = PCSetUp_FieldSplit;
1226: pc->ops->destroy = PCDestroy_FieldSplit;
1227: pc->ops->setfromoptions = PCSetFromOptions_FieldSplit;
1228: pc->ops->view = PCView_FieldSplit;
1229: pc->ops->applyrichardson = 0;
1231: PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitGetSubKSP_C","PCFieldSplitGetSubKSP_FieldSplit",
1232: PCFieldSplitGetSubKSP_FieldSplit);
1233: PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetFields_C","PCFieldSplitSetFields_FieldSplit",
1234: PCFieldSplitSetFields_FieldSplit);
1235: PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetIS_C","PCFieldSplitSetIS_FieldSplit",
1236: PCFieldSplitSetIS_FieldSplit);
1237: PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetType_C","PCFieldSplitSetType_FieldSplit",
1238: PCFieldSplitSetType_FieldSplit);
1239: PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetBlockSize_C","PCFieldSplitSetBlockSize_FieldSplit",
1240: PCFieldSplitSetBlockSize_FieldSplit);
1241: return(0);
1242: }
1246: /*MC
1247: Block_Preconditioners - PETSc provides support for a variety of "block preconditioners", this provides an
1248: overview of these methods.
1250: Consider the solution to ( A B ) (x_1) = (b_1)
1251: ( C D ) (x_2) (b_2)
1253: Important special cases, the Stokes equation: C = B' and D = 0 (A B) (x_1) = (b_1)
1254: B' 0) (x_2) (b_2)
1256: One of the goals of the PCFieldSplit preconditioner in PETSc is to provide a variety of preconditioners
1257: for this block system.
1258:
1259: Consider an additional matrix (Ap Bp)
1260: (Cp Dp) where some or all of the entries may be the same as
1261: in the original matrix (for example Ap == A).
1263: In the following, A^ denotes the approximate application of the inverse of A, possibly using Ap in the
1264: approximation. In PETSc this simply means one has called KSPSetOperators(ksp,A,Ap,...) or KSPSetOperators(ksp,Ap,Ap,...)
1266: Block Jacobi: x_1 = A^ b_1
1267: x_2 = D^ b_2
1269: Lower block Gauss-Seidel: x_1 = A^ b_1
1270: x_2 = D^ (b_2 - C x_1) variant x_2 = D^ (b_2 - Cp x_1)
1272: Symmetric Gauss-Seidel: x_1 = x_1 + A^(b_1 - A x_1 - B x_2) variant x_1 = x_1 + A^(b_1 - Ap x_1 - Bp x_2)
1273: Interestingly this form is not actually a symmetric matrix, the symmetric version is
1274: x_1 = A^(b_1 - B x_2) variant x_1 = A^(b_1 - Bp x_2)
1276: Level: intermediate
1278: .seealso: PCCreate(), PCSetType(), PCType (for list of available types), PC, PCFIELDSPLIT
1279: PCFieldSplitGetSubKSP(), PCFieldSplitSetFields(), PCFieldSplitSetType(), PCFieldSplitSetIS(), PCFieldSplitSchurPrecondition()
1280: M*/