Actual source code: fieldsplit.c
1: #define PETSCKSP_DLL
3: /*
5: */
6: #include private/pcimpl.h
8: typedef struct _PC_FieldSplitLink *PC_FieldSplitLink;
9: struct _PC_FieldSplitLink {
10: KSP ksp;
11: Vec x,y;
12: PetscInt nfields;
13: PetscInt *fields;
14: VecScatter sctx;
15: IS is,cis;
16: PetscInt csize;
17: PC_FieldSplitLink next,previous;
18: };
20: typedef struct {
21: PCCompositeType type;
22: PetscTruth defaultsplit; /* Flag for a system with a set of 'k' scalar fields with the same layout (and bs = k) */
23: PetscInt bs; /* Block size for IS and Mat structures */
24: PetscInt nsplits; /* Number of field divisions defined */
25: Vec *x,*y,w1,w2;
26: Mat *pmat; /* The diagonal block for each split */
27: Mat *Afield; /* The rows of the matrix associated with each split */
28: PetscTruth issetup;
29: /* Only used when Schur complement preconditioning is used */
30: Mat B; /* The (0,1) block */
31: Mat C; /* The (1,0) block */
32: Mat schur; /* The Schur complement S = D - C A^{-1} B */
33: KSP kspschur; /* The solver for S */
34: PetscTruth schurpre; /* preconditioner for the Schur complement is built from pmat[1] == D */
35: PC_FieldSplitLink head;
36: } PC_FieldSplit;
38: /*
39: Notes: there is no particular reason that pmat, x, and y are stored as arrays in PC_FieldSplit instead of
40: inside PC_FieldSplitLink, just historical. If you want to be able to add new fields after already using the
41: PC you could change this.
42: */
45: static PetscErrorCode PCView_FieldSplit(PC pc,PetscViewer viewer)
46: {
47: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
48: PetscErrorCode ierr;
49: PetscTruth iascii;
50: PetscInt i,j;
51: PC_FieldSplitLink ilink = jac->head;
54: PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&iascii);
55: if (iascii) {
56: PetscViewerASCIIPrintf(viewer," FieldSplit with %s composition: total splits = %D, blocksize = %D\n",PCCompositeTypes[jac->type],jac->nsplits,jac->bs);
57: PetscViewerASCIIPrintf(viewer," Solver info for each split is in the following KSP objects:\n");
58: PetscViewerASCIIPushTab(viewer);
59: for (i=0; i<jac->nsplits; i++) {
60: if (ilink->fields) {
61: PetscViewerASCIIPrintf(viewer,"Split number %D Fields ",i);
62: PetscViewerASCIIUseTabs(viewer,PETSC_FALSE);
63: for (j=0; j<ilink->nfields; j++) {
64: if (j > 0) {
65: PetscViewerASCIIPrintf(viewer,",");
66: }
67: PetscViewerASCIIPrintf(viewer," %D",ilink->fields[j]);
68: }
69: PetscViewerASCIIPrintf(viewer,"\n");
70: PetscViewerASCIIUseTabs(viewer,PETSC_TRUE);
71: } else {
72: PetscViewerASCIIPrintf(viewer,"Split number %D Defined by IS\n",i);
73: }
74: KSPView(ilink->ksp,viewer);
75: ilink = ilink->next;
76: }
77: PetscViewerASCIIPopTab(viewer);
78: } else {
79: SETERRQ1(PETSC_ERR_SUP,"Viewer type %s not supported for PCFieldSplit",((PetscObject)viewer)->type_name);
80: }
81: return(0);
82: }
86: static PetscErrorCode PCView_FieldSplit_Schur(PC pc,PetscViewer viewer)
87: {
88: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
89: PetscErrorCode ierr;
90: PetscTruth iascii;
91: PetscInt i,j;
92: PC_FieldSplitLink ilink = jac->head;
93: KSP ksp;
96: PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&iascii);
97: if (iascii) {
98: PetscViewerASCIIPrintf(viewer," FieldSplit with Schur preconditioner, blocksize = %D\n",jac->bs);
99: PetscViewerASCIIPrintf(viewer," Split info:\n");
100: PetscViewerASCIIPushTab(viewer);
101: for (i=0; i<jac->nsplits; i++) {
102: if (ilink->fields) {
103: PetscViewerASCIIPrintf(viewer,"Split number %D Fields ",i);
104: PetscViewerASCIIUseTabs(viewer,PETSC_FALSE);
105: for (j=0; j<ilink->nfields; j++) {
106: if (j > 0) {
107: PetscViewerASCIIPrintf(viewer,",");
108: }
109: PetscViewerASCIIPrintf(viewer," %D",ilink->fields[j]);
110: }
111: PetscViewerASCIIPrintf(viewer,"\n");
112: PetscViewerASCIIUseTabs(viewer,PETSC_TRUE);
113: } else {
114: PetscViewerASCIIPrintf(viewer,"Split number %D Defined by IS\n",i);
115: }
116: ilink = ilink->next;
117: }
118: PetscViewerASCIIPrintf(viewer,"KSP solver for A block \n");
119: MatSchurComplementGetKSP(jac->schur,&ksp);
120: PetscViewerASCIIPushTab(viewer);
121: KSPView(ksp,viewer);
122: PetscViewerASCIIPopTab(viewer);
123: PetscViewerASCIIPrintf(viewer,"KSP solver for S = D - C inv(A) B \n");
124: PetscViewerASCIIPushTab(viewer);
125: KSPView(jac->kspschur,viewer);
126: PetscViewerASCIIPopTab(viewer);
127: PetscViewerASCIIPopTab(viewer);
128: } else {
129: SETERRQ1(PETSC_ERR_SUP,"Viewer type %s not supported for PCFieldSplit",((PetscObject)viewer)->type_name);
130: }
131: return(0);
132: }
136: static PetscErrorCode PCFieldSplitSetDefaults(PC pc)
137: {
138: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
139: PetscErrorCode ierr;
140: PC_FieldSplitLink ilink = jac->head;
141: PetscInt i = 0,*ifields,nfields;
142: PetscTruth flg = PETSC_FALSE,*fields,flg2;
143: char optionname[128];
146: if (!ilink) {
148: if (jac->bs <= 0) {
149: if (pc->pmat) {
150: MatGetBlockSize(pc->pmat,&jac->bs);
151: } else {
152: jac->bs = 1;
153: }
154: }
156: PetscOptionsGetTruth(((PetscObject)pc)->prefix,"-pc_fieldsplit_default",&flg,PETSC_NULL);
157: if (!flg) {
158: /* Allow user to set fields from command line, if bs was known at the time of PCSetFromOptions_FieldSplit()
159: then it is set there. This is not ideal because we should only have options set in XXSetFromOptions(). */
160: flg = PETSC_TRUE; /* switched off automatically if user sets fields manually here */
161: PetscMalloc(jac->bs*sizeof(PetscInt),&ifields);
162: while (PETSC_TRUE) {
163: sprintf(optionname,"-pc_fieldsplit_%d_fields",(int)i++);
164: nfields = jac->bs;
165: PetscOptionsGetIntArray(((PetscObject)pc)->prefix,optionname,ifields,&nfields,&flg2);
166: if (!flg2) break;
167: if (!nfields) SETERRQ(PETSC_ERR_USER,"Cannot list zero fields");
168: flg = PETSC_FALSE;
169: PCFieldSplitSetFields(pc,nfields,ifields);
170: }
171: PetscFree(ifields);
172: }
173:
174: if (flg) {
175: PetscInfo(pc,"Using default splitting of fields\n");
176: PetscMalloc(jac->bs*sizeof(PetscTruth),&fields);
177: PetscMemzero(fields,jac->bs*sizeof(PetscTruth));
178: while (ilink) {
179: for (i=0; i<ilink->nfields; i++) {
180: fields[ilink->fields[i]] = PETSC_TRUE;
181: }
182: ilink = ilink->next;
183: }
184: jac->defaultsplit = PETSC_TRUE;
185: for (i=0; i<jac->bs; i++) {
186: if (!fields[i]) {
187: PCFieldSplitSetFields(pc,1,&i);
188: } else {
189: jac->defaultsplit = PETSC_FALSE;
190: }
191: }
192: PetscFree(fields);
193: }
194: } else if (jac->nsplits == 1) {
195: if (ilink->is) {
196: IS is2;
197: PetscInt nmin,nmax;
199: MatGetOwnershipRange(pc->mat,&nmin,&nmax);
200: ISComplement(ilink->is,nmin,nmax,&is2);
201: PCFieldSplitSetIS(pc,is2);
202: ISDestroy(is2);
203: } else {
204: SETERRQ(PETSC_ERR_SUP,"Must provide at least two sets of fields to PCFieldSplit()");
205: }
206: }
207: return(0);
208: }
213: static PetscErrorCode PCSetUp_FieldSplit(PC pc)
214: {
215: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
216: PetscErrorCode ierr;
217: PC_FieldSplitLink ilink;
218: PetscInt i,nsplit,ccsize;
219: MatStructure flag = pc->flag;
220: PetscTruth sorted,getsub;
223: PCFieldSplitSetDefaults(pc);
224: nsplit = jac->nsplits;
225: ilink = jac->head;
227: /* get the matrices for each split */
228: if (!jac->issetup) {
229: PetscInt rstart,rend,nslots,bs;
231: jac->issetup = PETSC_TRUE;
233: /* This is done here instead of in PCFieldSplitSetFields() because may not have matrix at that point */
234: bs = jac->bs;
235: MatGetOwnershipRange(pc->pmat,&rstart,&rend);
236: MatGetLocalSize(pc->pmat,PETSC_NULL,&ccsize);
237: nslots = (rend - rstart)/bs;
238: for (i=0; i<nsplit; i++) {
239: if (jac->defaultsplit) {
240: ISCreateStride(((PetscObject)pc)->comm,nslots,rstart+i,nsplit,&ilink->is);
241: } else if (!ilink->is) {
242: if (ilink->nfields > 1) {
243: PetscInt *ii,j,k,nfields = ilink->nfields,*fields = ilink->fields;
244: PetscMalloc(ilink->nfields*nslots*sizeof(PetscInt),&ii);
245: for (j=0; j<nslots; j++) {
246: for (k=0; k<nfields; k++) {
247: ii[nfields*j + k] = rstart + bs*j + fields[k];
248: }
249: }
250: ISCreateGeneral(((PetscObject)pc)->comm,nslots*nfields,ii,&ilink->is);
251: PetscFree(ii);
252: } else {
253: ISCreateStride(((PetscObject)pc)->comm,nslots,rstart+ilink->fields[0],bs,&ilink->is);
254: }
255: }
256: ISGetLocalSize(ilink->is,&ilink->csize);
257: ISSorted(ilink->is,&sorted);
258: if (!sorted) SETERRQ(PETSC_ERR_USER,"Fields must be sorted when creating split");
259: ISAllGather(ilink->is,&ilink->cis);
260: ilink = ilink->next;
261: }
262: }
263:
264: ilink = jac->head;
265: if (!jac->pmat) {
266: PetscMalloc(nsplit*sizeof(Mat),&jac->pmat);
267: for (i=0; i<nsplit; i++) {
268: MatGetSubMatrix(pc->pmat,ilink->is,ilink->cis,ilink->csize,MAT_INITIAL_MATRIX,&jac->pmat[i]);
269: ilink = ilink->next;
270: }
271: } else {
272: for (i=0; i<nsplit; i++) {
273: MatGetSubMatrix(pc->pmat,ilink->is,ilink->cis,ilink->csize,MAT_REUSE_MATRIX,&jac->pmat[i]);
274: ilink = ilink->next;
275: }
276: }
278: /* extract the rows of the matrix associated with each field: used for efficient computation of residual inside algorithm */
279: MatHasOperation(pc->mat,MATOP_GET_SUBMATRIX,&getsub);
280: if (getsub && jac->type != PC_COMPOSITE_ADDITIVE && jac->type != PC_COMPOSITE_SCHUR) {
281: ilink = jac->head;
282: if (!jac->Afield) {
283: PetscMalloc(nsplit*sizeof(Mat),&jac->Afield);
284: for (i=0; i<nsplit; i++) {
285: MatGetSubMatrix(pc->mat,ilink->is,PETSC_NULL,PETSC_DECIDE,MAT_INITIAL_MATRIX,&jac->Afield[i]);
286: ilink = ilink->next;
287: }
288: } else {
289: for (i=0; i<nsplit; i++) {
290: MatGetSubMatrix(pc->mat,ilink->is,PETSC_NULL,PETSC_DECIDE,MAT_REUSE_MATRIX,&jac->Afield[i]);
291: ilink = ilink->next;
292: }
293: }
294: }
296: if (jac->type == PC_COMPOSITE_SCHUR) {
297: IS ccis;
298: PetscInt N,nlocal,nis;
299: if (nsplit != 2) SETERRQ(PETSC_ERR_ARG_INCOMP,"To use Schur complement preconditioner you must have exactly 2 fields");
301: /* need to handle case when one is resetting up the preconditioner */
302: if (jac->schur) {
303: MatGetSize(pc->mat,PETSC_NULL,&N);
304: ilink = jac->head;
305: ISComplement(ilink->cis,0,N,&ccis);
306: ISGetLocalSize(ilink->is,&nis);
307: MatGetLocalSize(pc->mat,PETSC_NULL,&nlocal);
308: nlocal = nlocal - nis;
309: MatGetSubMatrix(pc->mat,ilink->is,ccis,nlocal,MAT_REUSE_MATRIX,&jac->B);
310: ISDestroy(ccis);
311: ilink = ilink->next;
312: ISComplement(ilink->cis,0,N,&ccis);
313: ISGetLocalSize(ilink->is,&nis);
314: MatGetLocalSize(pc->mat,PETSC_NULL,&nlocal);
315: nlocal = nlocal - nis;
316: MatGetSubMatrix(pc->mat,ilink->is,ccis,nlocal,MAT_REUSE_MATRIX,&jac->C);
317: ISDestroy(ccis);
318: MatSchurComplementUpdate(jac->schur,jac->pmat[0],jac->B,jac->C,jac->pmat[1],pc->flag);
319: if (jac->schurpre) {
320: KSPSetOperators(jac->kspschur,jac->schur,jac->pmat[1],pc->flag);
321: } else {
322: KSPSetOperators(jac->kspschur,jac->schur,jac->schur,pc->flag);
323: }
325: } else {
326: KSP ksp;
328: /* extract the B and C matrices */
329: MatGetSize(pc->mat,PETSC_NULL,&N);
330: ilink = jac->head;
331: ISComplement(ilink->cis,0,N,&ccis);
332: ISGetLocalSize(ilink->is,&nis);
333: MatGetLocalSize(pc->mat,PETSC_NULL,&nlocal);
334: nlocal = nlocal - nis;
335: MatGetSubMatrix(pc->mat,ilink->is,ccis,nlocal,MAT_INITIAL_MATRIX,&jac->B);
336: ISDestroy(ccis);
337: ilink = ilink->next;
338: ISComplement(ilink->cis,0,N,&ccis);
339: ISGetLocalSize(ilink->is,&nis);
340: MatGetLocalSize(pc->mat,PETSC_NULL,&nlocal);
341: nlocal = nlocal - nis;
342: MatGetSubMatrix(pc->mat,ilink->is,ccis,nlocal,MAT_INITIAL_MATRIX,&jac->C);
343: ISDestroy(ccis);
344: MatCreateSchurComplement(jac->pmat[0],jac->B,jac->C,jac->pmat[1],&jac->schur);
345: MatSchurComplementGetKSP(jac->schur,&ksp);
346: PetscObjectIncrementTabLevel((PetscObject)ksp,(PetscObject)pc,2);
347: MatSetFromOptions(jac->schur);
349: KSPCreate(((PetscObject)pc)->comm,&jac->kspschur);
350: PetscObjectIncrementTabLevel((PetscObject)jac->kspschur,(PetscObject)pc,1);
351: if (jac->schurpre) {
352: KSPSetOperators(jac->kspschur,jac->schur,jac->pmat[1],DIFFERENT_NONZERO_PATTERN);
353: } else {
354: KSPSetOperators(jac->kspschur,jac->schur,jac->schur,DIFFERENT_NONZERO_PATTERN);
355: }
356: KSPSetOptionsPrefix(jac->kspschur,((PetscObject)pc)->prefix);
357: KSPAppendOptionsPrefix(jac->kspschur,"fieldsplit_1_");
358: /* really want setfromoptions called in PCSetFromOptions_FieldSplit(), but it is not ready yet */
359: KSPSetFromOptions(jac->kspschur);
361: PetscMalloc2(2,Vec,&jac->x,2,Vec,&jac->y);
362: MatGetVecs(jac->pmat[0],&jac->x[0],&jac->y[0]);
363: MatGetVecs(jac->pmat[1],&jac->x[1],&jac->y[1]);
364: ilink = jac->head;
365: ilink->x = jac->x[0]; ilink->y = jac->y[0];
366: ilink = ilink->next;
367: ilink->x = jac->x[1]; ilink->y = jac->y[1];
368: }
369: } else {
370: /* set up the individual PCs */
371: i = 0;
372: ilink = jac->head;
373: while (ilink) {
374: KSPSetOperators(ilink->ksp,jac->pmat[i],jac->pmat[i],flag);
375: /* really want setfromoptions called in PCSetFromOptions_FieldSplit(), but it is not ready yet */
376: KSPSetFromOptions(ilink->ksp);
377: KSPSetUp(ilink->ksp);
378: i++;
379: ilink = ilink->next;
380: }
381:
382: /* create work vectors for each split */
383: if (!jac->x) {
384: PetscMalloc2(nsplit,Vec,&jac->x,nsplit,Vec,&jac->y);
385: ilink = jac->head;
386: for (i=0; i<nsplit; i++) {
387: Vec *vl,*vr;
389: KSPGetVecs(ilink->ksp,1,&vr,1,&vl);
390: ilink->x = *vr;
391: ilink->y = *vl;
392: PetscFree(vr);
393: PetscFree(vl);
394: jac->x[i] = ilink->x;
395: jac->y[i] = ilink->y;
396: ilink = ilink->next;
397: }
398: }
399: }
402: if (!jac->head->sctx) {
403: Vec xtmp;
405: /* compute scatter contexts needed by multiplicative versions and non-default splits */
406:
407: ilink = jac->head;
408: MatGetVecs(pc->pmat,&xtmp,PETSC_NULL);
409: for (i=0; i<nsplit; i++) {
410: VecScatterCreate(xtmp,ilink->is,jac->x[i],PETSC_NULL,&ilink->sctx);
411: ilink = ilink->next;
412: }
413: VecDestroy(xtmp);
414: }
415: return(0);
416: }
418: #define FieldSplitSplitSolveAdd(ilink,xx,yy) \
419: (VecScatterBegin(ilink->sctx,xx,ilink->x,INSERT_VALUES,SCATTER_FORWARD) || \
420: VecScatterEnd(ilink->sctx,xx,ilink->x,INSERT_VALUES,SCATTER_FORWARD) || \
421: KSPSolve(ilink->ksp,ilink->x,ilink->y) || \
422: VecScatterBegin(ilink->sctx,ilink->y,yy,ADD_VALUES,SCATTER_REVERSE) || \
423: VecScatterEnd(ilink->sctx,ilink->y,yy,ADD_VALUES,SCATTER_REVERSE))
427: static PetscErrorCode PCApply_FieldSplit_Schur(PC pc,Vec x,Vec y)
428: {
429: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
430: PetscErrorCode ierr;
431: KSP ksp;
432: PC_FieldSplitLink ilinkA = jac->head, ilinkD = ilinkA->next;
435: MatSchurComplementGetKSP(jac->schur,&ksp);
437: VecScatterBegin(ilinkA->sctx,x,ilinkA->x,INSERT_VALUES,SCATTER_FORWARD);
438: VecScatterEnd(ilinkA->sctx,x,ilinkA->x,INSERT_VALUES,SCATTER_FORWARD);
439: KSPSolve(ksp,ilinkA->x,ilinkA->y);
440: MatMult(jac->C,ilinkA->y,ilinkD->x);
441: VecScale(ilinkD->x,-1.0);
442: VecScatterBegin(ilinkD->sctx,x,ilinkD->x,ADD_VALUES,SCATTER_FORWARD);
443: VecScatterEnd(ilinkD->sctx,x,ilinkD->x,ADD_VALUES,SCATTER_FORWARD);
445: KSPSolve(jac->kspschur,ilinkD->x,ilinkD->y);
446: VecScatterBegin(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);
447: VecScatterEnd(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);
449: MatMult(jac->B,ilinkD->y,ilinkA->y);
450: VecAXPY(ilinkA->x,-1.0,ilinkA->y);
451: KSPSolve(ksp,ilinkA->x,ilinkA->y);
452: VecScatterBegin(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);
453: VecScatterEnd(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);
455: return(0);
456: }
460: static PetscErrorCode PCApply_FieldSplit(PC pc,Vec x,Vec y)
461: {
462: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
463: PetscErrorCode ierr;
464: PC_FieldSplitLink ilink = jac->head;
465: PetscInt bs,cnt;
468: CHKMEMQ;
469: VecGetBlockSize(x,&bs);
470: VecSetBlockSize(x,jac->bs);
471: VecSetBlockSize(y,jac->bs);
473: if (jac->type == PC_COMPOSITE_ADDITIVE) {
474: if (jac->defaultsplit) {
475: VecStrideGatherAll(x,jac->x,INSERT_VALUES);
476: while (ilink) {
477: KSPSolve(ilink->ksp,ilink->x,ilink->y);
478: ilink = ilink->next;
479: }
480: VecStrideScatterAll(jac->y,y,INSERT_VALUES);
481: } else {
482: VecSet(y,0.0);
483: while (ilink) {
484: FieldSplitSplitSolveAdd(ilink,x,y);
485: ilink = ilink->next;
486: }
487: }
488: } else if (jac->type == PC_COMPOSITE_MULTIPLICATIVE || jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
489: if (!jac->w1) {
490: VecDuplicate(x,&jac->w1);
491: VecDuplicate(x,&jac->w2);
492: }
493: VecSet(y,0.0);
494: FieldSplitSplitSolveAdd(ilink,x,y);
495: cnt = 1;
496: while (ilink->next) {
497: ilink = ilink->next;
498: if (jac->Afield) {
499: /* compute the residual only over the part of the vector needed */
500: MatMult(jac->Afield[cnt++],y,ilink->x);
501: VecScale(ilink->x,-1.0);
502: VecScatterBegin(ilink->sctx,x,ilink->x,ADD_VALUES,SCATTER_FORWARD);
503: VecScatterEnd(ilink->sctx,x,ilink->x,ADD_VALUES,SCATTER_FORWARD);
504: KSPSolve(ilink->ksp,ilink->x,ilink->y);
505: VecScatterBegin(ilink->sctx,ilink->y,y,ADD_VALUES,SCATTER_REVERSE);
506: VecScatterEnd(ilink->sctx,ilink->y,y,ADD_VALUES,SCATTER_REVERSE);
507: } else {
508: /* compute the residual over the entire vector */
509: MatMult(pc->mat,y,jac->w1);
510: VecWAXPY(jac->w2,-1.0,jac->w1,x);
511: FieldSplitSplitSolveAdd(ilink,jac->w2,y);
512: }
513: }
514: if (jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
515: cnt -= 2;
516: while (ilink->previous) {
517: ilink = ilink->previous;
518: if (jac->Afield) {
519: /* compute the residual only over the part of the vector needed */
520: MatMult(jac->Afield[cnt--],y,ilink->x);
521: VecScale(ilink->x,-1.0);
522: VecScatterBegin(ilink->sctx,x,ilink->x,ADD_VALUES,SCATTER_FORWARD);
523: VecScatterEnd(ilink->sctx,x,ilink->x,ADD_VALUES,SCATTER_FORWARD);
524: KSPSolve(ilink->ksp,ilink->x,ilink->y);
525: VecScatterBegin(ilink->sctx,ilink->y,y,ADD_VALUES,SCATTER_REVERSE);
526: VecScatterEnd(ilink->sctx,ilink->y,y,ADD_VALUES,SCATTER_REVERSE);
527: } else {
528: MatMult(pc->mat,y,jac->w1);
529: VecWAXPY(jac->w2,-1.0,jac->w1,x);
530: FieldSplitSplitSolveAdd(ilink,jac->w2,y);
531: }
532: }
533: }
534: } else SETERRQ1(PETSC_ERR_SUP,"Unsupported or unknown composition",(int) jac->type);
535: CHKMEMQ;
536: return(0);
537: }
539: #define FieldSplitSplitSolveAddTranspose(ilink,xx,yy) \
540: (VecScatterBegin(ilink->sctx,xx,ilink->y,INSERT_VALUES,SCATTER_FORWARD) || \
541: VecScatterEnd(ilink->sctx,xx,ilink->y,INSERT_VALUES,SCATTER_FORWARD) || \
542: KSPSolveTranspose(ilink->ksp,ilink->y,ilink->x) || \
543: VecScatterBegin(ilink->sctx,ilink->x,yy,ADD_VALUES,SCATTER_REVERSE) || \
544: VecScatterEnd(ilink->sctx,ilink->x,yy,ADD_VALUES,SCATTER_REVERSE))
548: static PetscErrorCode PCApplyTranspose_FieldSplit(PC pc,Vec x,Vec y)
549: {
550: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
551: PetscErrorCode ierr;
552: PC_FieldSplitLink ilink = jac->head;
553: PetscInt bs;
556: CHKMEMQ;
557: VecGetBlockSize(x,&bs);
558: VecSetBlockSize(x,jac->bs);
559: VecSetBlockSize(y,jac->bs);
561: if (jac->type == PC_COMPOSITE_ADDITIVE) {
562: if (jac->defaultsplit) {
563: VecStrideGatherAll(x,jac->x,INSERT_VALUES);
564: while (ilink) {
565: KSPSolveTranspose(ilink->ksp,ilink->x,ilink->y);
566: ilink = ilink->next;
567: }
568: VecStrideScatterAll(jac->y,y,INSERT_VALUES);
569: } else {
570: VecSet(y,0.0);
571: while (ilink) {
572: FieldSplitSplitSolveAddTranspose(ilink,x,y);
573: ilink = ilink->next;
574: }
575: }
576: } else {
577: if (!jac->w1) {
578: VecDuplicate(x,&jac->w1);
579: VecDuplicate(x,&jac->w2);
580: }
581: VecSet(y,0.0);
582: if (jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
583: FieldSplitSplitSolveAddTranspose(ilink,x,y);
584: while (ilink->next) {
585: ilink = ilink->next;
586: MatMultTranspose(pc->mat,y,jac->w1);
587: VecWAXPY(jac->w2,-1.0,jac->w1,x);
588: FieldSplitSplitSolveAddTranspose(ilink,jac->w2,y);
589: }
590: while (ilink->previous) {
591: ilink = ilink->previous;
592: MatMultTranspose(pc->mat,y,jac->w1);
593: VecWAXPY(jac->w2,-1.0,jac->w1,x);
594: FieldSplitSplitSolveAddTranspose(ilink,jac->w2,y);
595: }
596: } else {
597: while (ilink->next) { /* get to last entry in linked list */
598: ilink = ilink->next;
599: }
600: FieldSplitSplitSolveAddTranspose(ilink,x,y);
601: while (ilink->previous) {
602: ilink = ilink->previous;
603: MatMultTranspose(pc->mat,y,jac->w1);
604: VecWAXPY(jac->w2,-1.0,jac->w1,x);
605: FieldSplitSplitSolveAddTranspose(ilink,jac->w2,y);
606: }
607: }
608: }
609: CHKMEMQ;
610: return(0);
611: }
615: static PetscErrorCode PCDestroy_FieldSplit(PC pc)
616: {
617: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
618: PetscErrorCode ierr;
619: PC_FieldSplitLink ilink = jac->head,next;
622: while (ilink) {
623: KSPDestroy(ilink->ksp);
624: if (ilink->x) {VecDestroy(ilink->x);}
625: if (ilink->y) {VecDestroy(ilink->y);}
626: if (ilink->sctx) {VecScatterDestroy(ilink->sctx);}
627: if (ilink->is) {ISDestroy(ilink->is);}
628: if (ilink->cis) {ISDestroy(ilink->cis);}
629: next = ilink->next;
630: PetscFree(ilink->fields);
631: PetscFree(ilink);
632: ilink = next;
633: }
634: PetscFree2(jac->x,jac->y);
635: if (jac->pmat) {MatDestroyMatrices(jac->nsplits,&jac->pmat);}
636: if (jac->Afield) {MatDestroyMatrices(jac->nsplits,&jac->Afield);}
637: if (jac->w1) {VecDestroy(jac->w1);}
638: if (jac->w2) {VecDestroy(jac->w2);}
639: if (jac->schur) {MatDestroy(jac->schur);}
640: if (jac->kspschur) {KSPDestroy(jac->kspschur);}
641: if (jac->B) {MatDestroy(jac->B);}
642: if (jac->C) {MatDestroy(jac->C);}
643: PetscFree(jac);
644: return(0);
645: }
649: static PetscErrorCode PCSetFromOptions_FieldSplit(PC pc)
650: {
651: PetscErrorCode ierr;
652: PetscInt i = 0,nfields,*fields,bs;
653: PetscTruth flg,set;
654: char optionname[128];
655: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
656: PCCompositeType ctype;
659: PetscOptionsHead("FieldSplit options");
660: PetscOptionsInt("-pc_fieldsplit_block_size","Blocksize that defines number of fields","PCFieldSplitSetBlockSize",jac->bs,&bs,&flg);
661: if (flg) {
662: PCFieldSplitSetBlockSize(pc,bs);
663: }
665: PetscOptionsEnum("-pc_fieldsplit_type","Type of composition","PCFieldSplitSetType",PCCompositeTypes,(PetscEnum)jac->type,(PetscEnum*)&ctype,&flg);
666: if (flg) {
667: PCFieldSplitSetType(pc,ctype);
668: }
670: /* Only setup fields once */
671: if ((jac->bs > 0) && (jac->nsplits == 0)) {
672: /* only allow user to set fields from command line if bs is already known.
673: otherwise user can set them in PCFieldSplitSetDefaults() */
674: PetscMalloc(jac->bs*sizeof(PetscInt),&fields);
675: while (PETSC_TRUE) {
676: sprintf(optionname,"-pc_fieldsplit_%d_fields",(int)i++);
677: nfields = jac->bs;
678: PetscOptionsIntArray(optionname,"Fields in this split","PCFieldSplitSetFields",fields,&nfields,&flg);
679: if (!flg) break;
680: if (!nfields) SETERRQ(PETSC_ERR_USER,"Cannot list zero fields");
681: PCFieldSplitSetFields(pc,nfields,fields);
682: }
683: PetscFree(fields);
684: }
685: PetscOptionsTruth("-pc_fieldsplit_schur_precondition","Build preconditioner for Schur complement","PCFieldSplitSchurPrecondition",jac->schurpre,&flg,&set);
686: if (set) {
687: PCFieldSplitSchurPrecondition(pc,flg);
688: }
689: PetscOptionsTail();
690: return(0);
691: }
693: /*------------------------------------------------------------------------------------*/
698: PetscErrorCode PCFieldSplitSetFields_FieldSplit(PC pc,PetscInt n,PetscInt *fields)
699: {
700: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
701: PetscErrorCode ierr;
702: PC_FieldSplitLink ilink,next = jac->head;
703: char prefix[128];
704: PetscInt i;
707: if (n <= 0) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Negative number of fields requested");
708: for (i=0; i<n; i++) {
709: if (fields[i] >= jac->bs) SETERRQ2(PETSC_ERR_ARG_OUTOFRANGE,"Field %D requested but only %D exist",fields[i],jac->bs);
710: if (fields[i] < 0) SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"Negative field %D requested",fields[i]);
711: }
712: PetscNew(struct _PC_FieldSplitLink,&ilink);
713: PetscMalloc(n*sizeof(PetscInt),&ilink->fields);
714: PetscMemcpy(ilink->fields,fields,n*sizeof(PetscInt));
715: ilink->nfields = n;
716: ilink->next = PETSC_NULL;
717: KSPCreate(((PetscObject)pc)->comm,&ilink->ksp);
718: PetscObjectIncrementTabLevel((PetscObject)ilink->ksp,(PetscObject)pc,1);
719: KSPSetType(ilink->ksp,KSPPREONLY);
721: if (((PetscObject)pc)->prefix) {
722: sprintf(prefix,"%sfieldsplit_%d_",((PetscObject)pc)->prefix,(int)jac->nsplits);
723: } else {
724: sprintf(prefix,"fieldsplit_%d_",(int)jac->nsplits);
725: }
726: KSPSetOptionsPrefix(ilink->ksp,prefix);
728: if (!next) {
729: jac->head = ilink;
730: ilink->previous = PETSC_NULL;
731: } else {
732: while (next->next) {
733: next = next->next;
734: }
735: next->next = ilink;
736: ilink->previous = next;
737: }
738: jac->nsplits++;
739: return(0);
740: }
746: PetscErrorCode PCFieldSplitGetSubKSP_FieldSplit_Schur(PC pc,PetscInt *n,KSP **subksp)
747: {
748: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
752: PetscMalloc(jac->nsplits*sizeof(KSP*),subksp);
753: MatSchurComplementGetKSP(jac->schur,*subksp);
754: (*subksp)[1] = jac->kspschur;
755: return(0);
756: }
762: PetscErrorCode PCFieldSplitGetSubKSP_FieldSplit(PC pc,PetscInt *n,KSP **subksp)
763: {
764: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
765: PetscErrorCode ierr;
766: PetscInt cnt = 0;
767: PC_FieldSplitLink ilink = jac->head;
770: PetscMalloc(jac->nsplits*sizeof(KSP*),subksp);
771: while (ilink) {
772: (*subksp)[cnt++] = ilink->ksp;
773: ilink = ilink->next;
774: }
775: if (cnt != jac->nsplits) SETERRQ2(PETSC_ERR_PLIB,"Corrupt PCFIELDSPLIT object: number splits in linked list %D in object %D",cnt,jac->nsplits);
776: *n = jac->nsplits;
777: return(0);
778: }
784: PetscErrorCode PCFieldSplitSetIS_FieldSplit(PC pc,IS is)
785: {
786: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
787: PetscErrorCode ierr;
788: PC_FieldSplitLink ilink, next = jac->head;
789: char prefix[128];
792: PetscNew(struct _PC_FieldSplitLink,&ilink);
793: ilink->is = is;
794: PetscObjectReference((PetscObject)is);
795: ilink->next = PETSC_NULL;
796: KSPCreate(((PetscObject)pc)->comm,&ilink->ksp);
797: PetscObjectIncrementTabLevel((PetscObject)ilink->ksp,(PetscObject)pc,1);
798: KSPSetType(ilink->ksp,KSPPREONLY);
800: if (((PetscObject)pc)->prefix) {
801: sprintf(prefix,"%sfieldsplit_%d_",((PetscObject)pc)->prefix,(int)jac->nsplits);
802: } else {
803: sprintf(prefix,"fieldsplit_%d_",(int)jac->nsplits);
804: }
805: KSPSetOptionsPrefix(ilink->ksp,prefix);
807: if (!next) {
808: jac->head = ilink;
809: ilink->previous = PETSC_NULL;
810: } else {
811: while (next->next) {
812: next = next->next;
813: }
814: next->next = ilink;
815: ilink->previous = next;
816: }
817: jac->nsplits++;
819: return(0);
820: }
825: /*@
826: PCFieldSplitSetFields - Sets the fields for one particular split in the field split preconditioner
828: Collective on PC
830: Input Parameters:
831: + pc - the preconditioner context
832: . n - the number of fields in this split
833: . fields - the fields in this split
835: Level: intermediate
837: Notes: Use PCFieldSplitSetIS() to set a completely general set of indices as a field.
839: The PCFieldSplitSetFields() is for defining fields as a strided blocks. For example, if the block
840: 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
841: 0xx3xx6xx9xx12 ... x1xx4xx7xx ... xx2xx5xx8xx.. 01x34x67x... 0x1x3x5x7.. x12x45x78x....
842: where the numbered entries indicate what is in the field.
844: .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetBlockSize(), PCFieldSplitSetIS()
846: @*/
847: PetscErrorCode PCFieldSplitSetFields(PC pc,PetscInt n, PetscInt *fields)
848: {
849: PetscErrorCode ierr,(*f)(PC,PetscInt,PetscInt *);
853: PetscObjectQueryFunction((PetscObject)pc,"PCFieldSplitSetFields_C",(void (**)(void))&f);
854: if (f) {
855: (*f)(pc,n,fields);
856: }
857: return(0);
858: }
862: /*@
863: PCFieldSplitSetIS - Sets the exact elements for field
865: Collective on PC
867: Input Parameters:
868: + pc - the preconditioner context
869: . is - the index set that defines the vector elements in this field
872: Notes: Use PCFieldSplitSetFields(), for fields defined by strided types.
874: Level: intermediate
876: .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetBlockSize()
878: @*/
879: PetscErrorCode PCFieldSplitSetIS(PC pc,IS is)
880: {
881: PetscErrorCode ierr,(*f)(PC,IS);
886: PetscObjectQueryFunction((PetscObject)pc,"PCFieldSplitSetIS_C",(void (**)(void))&f);
887: if (f) {
888: (*f)(pc,is);
889: }
890: return(0);
891: }
895: /*@
896: PCFieldSplitSetBlockSize - Sets the block size for defining where fields start in the
897: fieldsplit preconditioner. If not set the matrix block size is used.
899: Collective on PC
901: Input Parameters:
902: + pc - the preconditioner context
903: - bs - the block size
905: Level: intermediate
907: .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetFields()
909: @*/
910: PetscErrorCode PCFieldSplitSetBlockSize(PC pc,PetscInt bs)
911: {
912: PetscErrorCode ierr,(*f)(PC,PetscInt);
916: PetscObjectQueryFunction((PetscObject)pc,"PCFieldSplitSetBlockSize_C",(void (**)(void))&f);
917: if (f) {
918: (*f)(pc,bs);
919: }
920: return(0);
921: }
925: /*@C
926: PCFieldSplitGetSubKSP - Gets the KSP contexts for all splits
927:
928: Collective on KSP
930: Input Parameter:
931: . pc - the preconditioner context
933: Output Parameters:
934: + n - the number of split
935: - pc - the array of KSP contexts
937: Note:
938: After PCFieldSplitGetSubKSP() the array of KSPs IS to be freed by the user
939: (not the KSP just the array that contains them).
941: You must call KSPSetUp() before calling PCFieldSplitGetSubKSP().
943: Level: advanced
945: .seealso: PCFIELDSPLIT
946: @*/
947: PetscErrorCode PCFieldSplitGetSubKSP(PC pc,PetscInt *n,KSP *subksp[])
948: {
949: PetscErrorCode ierr,(*f)(PC,PetscInt*,KSP **);
954: PetscObjectQueryFunction((PetscObject)pc,"PCFieldSplitGetSubKSP_C",(void (**)(void))&f);
955: if (f) {
956: (*f)(pc,n,subksp);
957: } else {
958: SETERRQ(PETSC_ERR_ARG_WRONG,"Cannot get subksp for this type of PC");
959: }
960: return(0);
961: }
965: /*@
966: PCFieldSplitSchurPrecondition - Indicates if the Schur complement is preconditioned by a preconditioner constructed by the
967: D matrix. Otherwise no preconditioner is used.
969: Collective on PC
971: Input Parameters:
972: + pc - the preconditioner context
973: - flg - build the preconditioner
975: Options Database:
976: . -pc_fieldsplit_schur_precondition <true,false> default is true
978: Level: intermediate
980: Notes: What should we do if the user wants to provide a different matrix (like a mass matrix) to use to build the preconditioner
982: .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetFields(), PCFIELDSPLIT
984: @*/
985: PetscErrorCode PCFieldSplitSchurPrecondition(PC pc,PetscTruth flg)
986: {
987: PetscErrorCode ierr,(*f)(PC,PetscTruth);
991: PetscObjectQueryFunction((PetscObject)pc,"PCFieldSplitSchurPrecondition_C",(void (**)(void))&f);
992: if (f) {
993: (*f)(pc,flg);
994: }
995: return(0);
996: }
1001: PetscErrorCode PCFieldSplitSchurPrecondition_FieldSplit(PC pc,PetscTruth flg)
1002: {
1003: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
1006: jac->schurpre = flg;
1007: return(0);
1008: }
1013: /*@C
1014: PCFieldSplitGetSchurBlocks - Gets the all matrix blocks for the Schur complement
1015:
1016: Collective on KSP
1018: Input Parameter:
1019: . pc - the preconditioner context
1021: Output Parameters:
1022: + A - the (0,0) block
1023: . B - the (0,1) block
1024: . C - the (1,0) block
1025: - D - the (1,1) block
1027: Level: advanced
1029: .seealso: PCFIELDSPLIT
1030: @*/
1031: PetscErrorCode PCFieldSplitGetSchurBlocks(PC pc,Mat *A,Mat *B,Mat *C, Mat *D)
1032: {
1033: PC_FieldSplit *jac = (PC_FieldSplit *) pc->data;
1037: if (jac->type != PC_COMPOSITE_SCHUR) {SETERRQ(PETSC_ERR_ARG_WRONG, "FieldSplit is not using a Schur complement approach.");}
1038: if (A) *A = jac->pmat[0];
1039: if (B) *B = jac->B;
1040: if (C) *C = jac->C;
1041: if (D) *D = jac->pmat[1];
1042: return(0);
1043: }
1048: PetscErrorCode PCFieldSplitSetType_FieldSplit(PC pc,PCCompositeType type)
1049: {
1050: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
1054: jac->type = type;
1055: if (type == PC_COMPOSITE_SCHUR) {
1056: pc->ops->apply = PCApply_FieldSplit_Schur;
1057: pc->ops->view = PCView_FieldSplit_Schur;
1058: PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitGetSubKSP_C","PCFieldSplitGetSubKSP_FieldSplit_Schur",PCFieldSplitGetSubKSP_FieldSplit_Schur);
1059: PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSchurPrecondition_C","PCFieldSplitSchurPrecondition_FieldSplit",PCFieldSplitSchurPrecondition_FieldSplit);
1061: } else {
1062: pc->ops->apply = PCApply_FieldSplit;
1063: pc->ops->view = PCView_FieldSplit;
1064: PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitGetSubKSP_C","PCFieldSplitGetSubKSP_FieldSplit",PCFieldSplitGetSubKSP_FieldSplit);
1065: PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSchurPrecondition_C","",0);
1066: }
1067: return(0);
1068: }
1074: PetscErrorCode PCFieldSplitSetBlockSize_FieldSplit(PC pc,PetscInt bs)
1075: {
1076: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
1079: if (bs < 1) SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"Blocksize must be positive, you gave %D",bs);
1080: 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);
1081: jac->bs = bs;
1082: return(0);
1083: }
1088: /*@
1089: PCFieldSplitSetType - Sets the type of fieldsplit preconditioner.
1090:
1091: Collective on PC
1093: Input Parameter:
1094: . pc - the preconditioner context
1095: . type - PC_COMPOSITE_ADDITIVE, PC_COMPOSITE_MULTIPLICATIVE (default), PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE, PC_COMPOSITE_SPECIAL, PC_COMPOSITE_SCHUR
1097: Options Database Key:
1098: . -pc_fieldsplit_type <type: one of multiplicative, additive, symmetric_multiplicative, special, schur> - Sets fieldsplit preconditioner type
1100: Level: Developer
1102: .keywords: PC, set, type, composite preconditioner, additive, multiplicative
1104: .seealso: PCCompositeSetType()
1106: @*/
1107: PetscErrorCode PCFieldSplitSetType(PC pc,PCCompositeType type)
1108: {
1109: PetscErrorCode ierr,(*f)(PC,PCCompositeType);
1113: PetscObjectQueryFunction((PetscObject)pc,"PCFieldSplitSetType_C",(void (**)(void))&f);
1114: if (f) {
1115: (*f)(pc,type);
1116: }
1117: return(0);
1118: }
1120: /* -------------------------------------------------------------------------------------*/
1121: /*MC
1122: PCFIELDSPLIT - Preconditioner created by combining separate preconditioners for individual
1123: fields or groups of fields
1126: To set options on the solvers for each block append -fieldsplit_ to all the PC
1127: options database keys. For example, -fieldsplit_pc_type ilu -fieldsplit_pc_factor_levels 1
1128:
1129: To set the options on the solvers separate for each block call PCFieldSplitGetSubKSP()
1130: and set the options directly on the resulting KSP object
1132: Level: intermediate
1134: Options Database Keys:
1135: + -pc_fieldsplit_%d_fields <a,b,..> - indicates the fields to be used in the %d'th split
1136: . -pc_fieldsplit_default - automatically add any fields to additional splits that have not
1137: been supplied explicitly by -pc_fieldsplit_%d_fields
1138: . -pc_fieldsplit_block_size <bs> - size of block that defines fields (i.e. there are bs fields)
1139: . -pc_fieldsplit_type <additive,multiplicative,schur,symmetric_multiplicative>
1140: . -pc_fieldsplit_schur_precondition <true,false> default is true
1142: - Options prefix for inner solvers when using Schur complement preconditioner are -fieldsplit_0_ and -fieldsplit_1_
1143: for all other solvers they are -fieldsplit_%d_ for the dth field, use -fieldsplit_ for all fields
1146: Notes: use PCFieldSplitSetFields() to set fields defined by "strided" entries and PCFieldSplitSetIS()
1147: to define a field by an arbitrary collection of entries.
1149: If no fields are set the default is used. The fields are defined by entries strided by bs,
1150: beginning at 0 then 1, etc to bs-1. The block size can be set with PCFieldSplitSetBlockSize(),
1151: if this is not called the block size defaults to the blocksize of the second matrix passed
1152: to KSPSetOperators()/PCSetOperators().
1154: Currently for the multiplicative version, the updated residual needed for the next field
1155: solve is computed via a matrix vector product over the entire array. An optimization would be
1156: to update the residual only for the part of the right hand side associated with the next field
1157: solve. (This would involve more MatGetSubMatrix() calls or some other mechanism to compute the
1158: part of the matrix needed to just update part of the residual).
1160: For the Schur complement preconditioner if J = ( A B )
1161: ( C D )
1162: the preconditioner is
1163: (I -B inv(A)) ( inv(A) 0 ) (I 0 )
1164: (0 I ) ( 0 inv(S) ) (-C inv(A) I )
1165: where the action of inv(A) is applied using the KSP solver with prefix -fieldsplit_0_. The action of
1166: inv(S) is computed using the KSP solver with prefix -schur_. For PCFieldSplitGetKSP() when field number is
1167: 0 it returns the KSP associated with -fieldsplit_0_ while field number 1 gives -fieldsplit_1_ KSP. By default
1168: D is used to construct a preconditioner for S, use PCFieldSplitSchurPrecondition() to turn on or off this
1169: option.
1170:
1171: If only one set of indices (one IS) is provided with PCFieldSplitSetIS() then the complement of that IS
1172: is used automatically for a second block.
1174: Concepts: physics based preconditioners, block preconditioners
1176: .seealso: PCCreate(), PCSetType(), PCType (for list of available types), PC, Block_Preconditioners
1177: PCFieldSplitGetSubKSP(), PCFieldSplitSetFields(), PCFieldSplitSetType(), PCFieldSplitSetIS(), PCFieldSplitSchurPrecondition()
1178: M*/
1183: PetscErrorCode PCCreate_FieldSplit(PC pc)
1184: {
1186: PC_FieldSplit *jac;
1189: PetscNewLog(pc,PC_FieldSplit,&jac);
1190: jac->bs = -1;
1191: jac->nsplits = 0;
1192: jac->type = PC_COMPOSITE_MULTIPLICATIVE;
1193: jac->schurpre = PETSC_TRUE;
1195: pc->data = (void*)jac;
1197: pc->ops->apply = PCApply_FieldSplit;
1198: pc->ops->applytranspose = PCApplyTranspose_FieldSplit;
1199: pc->ops->setup = PCSetUp_FieldSplit;
1200: pc->ops->destroy = PCDestroy_FieldSplit;
1201: pc->ops->setfromoptions = PCSetFromOptions_FieldSplit;
1202: pc->ops->view = PCView_FieldSplit;
1203: pc->ops->applyrichardson = 0;
1205: PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitGetSubKSP_C","PCFieldSplitGetSubKSP_FieldSplit",
1206: PCFieldSplitGetSubKSP_FieldSplit);
1207: PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetFields_C","PCFieldSplitSetFields_FieldSplit",
1208: PCFieldSplitSetFields_FieldSplit);
1209: PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetIS_C","PCFieldSplitSetIS_FieldSplit",
1210: PCFieldSplitSetIS_FieldSplit);
1211: PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetType_C","PCFieldSplitSetType_FieldSplit",
1212: PCFieldSplitSetType_FieldSplit);
1213: PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetBlockSize_C","PCFieldSplitSetBlockSize_FieldSplit",
1214: PCFieldSplitSetBlockSize_FieldSplit);
1215: return(0);
1216: }
1220: /*MC
1221: Block_Preconditioners - PETSc provides support for a variety of "block preconditioners", this provides an
1222: overview of these methods.
1224: Consider the solution to ( A B ) (x_1) = (b_1)
1225: ( C D ) (x_2) (b_2)
1227: Important special cases, the Stokes equation: C = B' and D = 0 (A B) (x_1) = (b_1)
1228: B' 0) (x_2) (b_2)
1230: One of the goals of the PCFieldSplit preconditioner in PETSc is to provide a variety of preconditioners
1231: for this block system.
1232:
1233: Consider an additional matrix (Ap Bp)
1234: (Cp Dp) where some or all of the entries may be the same as
1235: in the original matrix (for example Ap == A).
1237: In the following, A^ denotes the approximate application of the inverse of A, possibly using Ap in the
1238: approximation. In PETSc this simply means one has called KSPSetOperators(ksp,A,Ap,...) or KSPSetOperators(ksp,Ap,Ap,...)
1240: Block Jacobi: x_1 = A^ b_1
1241: x_2 = D^ b_2
1243: Lower block Gauss-Seidel: x_1 = A^ b_1
1244: x_2 = D^ (b_2 - C x_1) variant x_2 = D^ (b_2 - Cp x_1)
1246: 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)
1247: Interestingly this form is not actually a symmetric matrix, the symmetric version is
1248: x_1 = A^(b_1 - B x_2) variant x_1 = A^(b_1 - Bp x_2)
1250: Level: intermediate
1252: .seealso: PCCreate(), PCSetType(), PCType (for list of available types), PC, PCFIELDSPLIT
1253: PCFieldSplitGetSubKSP(), PCFieldSplitSetFields(), PCFieldSplitSetType(), PCFieldSplitSetIS(), PCFieldSplitSchurPrecondition()
1254: M*/