Actual source code: fieldsplit.c
petsc-3.3-p2 2012-07-13
2: #include <petsc-private/pcimpl.h> /*I "petscpc.h" I*/
3: #include <petscdmcomposite.h> /*I "petscdmcomposite.h" I*/
5: const char *const PCFieldSplitSchurPreTypes[] = {"SELF","DIAG","USER","PCFieldSplitSchurPreType","PC_FIELDSPLIT_SCHUR_PRE_",0};
6: const char *const PCFieldSplitSchurFactTypes[] = {"DIAG","LOWER","UPPER","FULL","PCFieldSplitSchurFactType","PC_FIELDSPLIT_SCHUR_FACT_",0};
8: typedef struct _PC_FieldSplitLink *PC_FieldSplitLink;
9: struct _PC_FieldSplitLink {
10: KSP ksp;
11: Vec x,y;
12: char *splitname;
13: PetscInt nfields;
14: PetscInt *fields,*fields_col;
15: VecScatter sctx;
16: IS is,is_col;
17: PC_FieldSplitLink next,previous;
18: };
20: typedef struct {
21: PCCompositeType type;
22: PetscBool defaultsplit; /* Flag for a system with a set of 'k' scalar fields with the same layout (and bs = k) */
23: PetscBool splitdefined; /* Flag is set after the splits have been defined, to prevent more splits from being added */
24: PetscBool 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: PetscBool 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 = A11 - A10 A00^{-1} A01 */
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: PCFieldSplitSchurFactType schurfactorization;
39: KSP kspschur; /* The solver for S */
40: PC_FieldSplitLink head;
41: PetscBool reset; /* indicates PCReset() has been last called on this object, hack */
42: PetscBool suboptionsset; /* Indicates that the KSPSetFromOptions() has been called on the sub-KSPs */
43: } PC_FieldSplit;
45: /*
46: Notes: there is no particular reason that pmat, x, and y are stored as arrays in PC_FieldSplit instead of
47: inside PC_FieldSplitLink, just historical. If you want to be able to add new fields after already using the
48: PC you could change this.
49: */
51: /* This helper is so that setting a user-provided preconditioning matrix is orthogonal to choosing to use it. This way the
52: * application-provided FormJacobian can provide this matrix without interfering with the user's (command-line) choices. */
53: static Mat FieldSplitSchurPre(PC_FieldSplit *jac)
54: {
55: switch (jac->schurpre) {
56: case PC_FIELDSPLIT_SCHUR_PRE_SELF: return jac->schur;
57: case PC_FIELDSPLIT_SCHUR_PRE_DIAG: return jac->pmat[1];
58: case PC_FIELDSPLIT_SCHUR_PRE_USER: /* Use a user-provided matrix if it is given, otherwise diagonal block */
59: default:
60: return jac->schur_user ? jac->schur_user : jac->pmat[1];
61: }
62: }
67: static PetscErrorCode PCView_FieldSplit(PC pc,PetscViewer viewer)
68: {
69: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
70: PetscErrorCode ierr;
71: PetscBool iascii;
72: PetscInt i,j;
73: PC_FieldSplitLink ilink = jac->head;
76: PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);
77: if (iascii) {
78: if (jac->bs > 0) {
79: PetscViewerASCIIPrintf(viewer," FieldSplit with %s composition: total splits = %D, blocksize = %D\n",PCCompositeTypes[jac->type],jac->nsplits,jac->bs);
80: } else {
81: PetscViewerASCIIPrintf(viewer," FieldSplit with %s composition: total splits = %D\n",PCCompositeTypes[jac->type],jac->nsplits);
82: }
83: if (jac->realdiagonal) {
84: PetscViewerASCIIPrintf(viewer," using actual matrix for blocks rather than preconditioner matrix\n");
85: }
86: PetscViewerASCIIPrintf(viewer," Solver info for each split is in the following KSP objects:\n");
87: PetscViewerASCIIPushTab(viewer);
88: for (i=0; i<jac->nsplits; i++) {
89: if (ilink->fields) {
90: PetscViewerASCIIPrintf(viewer,"Split number %D Fields ",i);
91: PetscViewerASCIIUseTabs(viewer,PETSC_FALSE);
92: for (j=0; j<ilink->nfields; j++) {
93: if (j > 0) {
94: PetscViewerASCIIPrintf(viewer,",");
95: }
96: PetscViewerASCIIPrintf(viewer," %D",ilink->fields[j]);
97: }
98: PetscViewerASCIIPrintf(viewer,"\n");
99: PetscViewerASCIIUseTabs(viewer,PETSC_TRUE);
100: } else {
101: PetscViewerASCIIPrintf(viewer,"Split number %D Defined by IS\n",i);
102: }
103: KSPView(ilink->ksp,viewer);
104: ilink = ilink->next;
105: }
106: PetscViewerASCIIPopTab(viewer);
107: } else {
108: SETERRQ1(((PetscObject)pc)->comm,PETSC_ERR_SUP,"Viewer type %s not supported for PCFieldSplit",((PetscObject)viewer)->type_name);
109: }
110: return(0);
111: }
115: static PetscErrorCode PCView_FieldSplit_Schur(PC pc,PetscViewer viewer)
116: {
117: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
118: PetscErrorCode ierr;
119: PetscBool iascii;
120: PetscInt i,j;
121: PC_FieldSplitLink ilink = jac->head;
122: KSP ksp;
125: PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);
126: if (iascii) {
127: if (jac->bs > 0) {
128: PetscViewerASCIIPrintf(viewer," FieldSplit with Schur preconditioner, blocksize = %D, factorization %s\n",jac->bs,PCFieldSplitSchurFactTypes[jac->schurfactorization]);
129: } else {
130: PetscViewerASCIIPrintf(viewer," FieldSplit with Schur preconditioner, factorization %s\n",PCFieldSplitSchurFactTypes[jac->schurfactorization]);
131: }
132: if (jac->realdiagonal) {
133: PetscViewerASCIIPrintf(viewer," using actual matrix for blocks rather than preconditioner matrix\n");
134: }
135: switch(jac->schurpre) {
136: case PC_FIELDSPLIT_SCHUR_PRE_SELF:
137: PetscViewerASCIIPrintf(viewer," Preconditioner for the Schur complement formed from S itself\n");break;
138: case PC_FIELDSPLIT_SCHUR_PRE_DIAG:
139: PetscViewerASCIIPrintf(viewer," Preconditioner for the Schur complement formed from the block diagonal part of A11\n");break;
140: case PC_FIELDSPLIT_SCHUR_PRE_USER:
141: if (jac->schur_user) {
142: PetscViewerASCIIPrintf(viewer," Preconditioner for the Schur complement formed from user provided matrix\n");
143: } else {
144: PetscViewerASCIIPrintf(viewer," Preconditioner for the Schur complement formed from the block diagonal part of A11\n");
145: }
146: break;
147: default:
148: SETERRQ1(((PetscObject) pc)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid Schur preconditioning type: %d", jac->schurpre);
149: }
150: PetscViewerASCIIPrintf(viewer," Split info:\n");
151: PetscViewerASCIIPushTab(viewer);
152: for (i=0; i<jac->nsplits; i++) {
153: if (ilink->fields) {
154: PetscViewerASCIIPrintf(viewer,"Split number %D Fields ",i);
155: PetscViewerASCIIUseTabs(viewer,PETSC_FALSE);
156: for (j=0; j<ilink->nfields; j++) {
157: if (j > 0) {
158: PetscViewerASCIIPrintf(viewer,",");
159: }
160: PetscViewerASCIIPrintf(viewer," %D",ilink->fields[j]);
161: }
162: PetscViewerASCIIPrintf(viewer,"\n");
163: PetscViewerASCIIUseTabs(viewer,PETSC_TRUE);
164: } else {
165: PetscViewerASCIIPrintf(viewer,"Split number %D Defined by IS\n",i);
166: }
167: ilink = ilink->next;
168: }
169: PetscViewerASCIIPrintf(viewer,"KSP solver for A00 block \n");
170: PetscViewerASCIIPushTab(viewer);
171: if (jac->schur) {
172: MatSchurComplementGetKSP(jac->schur,&ksp);
173: KSPView(ksp,viewer);
174: } else {
175: PetscViewerASCIIPrintf(viewer," not yet available\n");
176: }
177: PetscViewerASCIIPopTab(viewer);
178: PetscViewerASCIIPrintf(viewer,"KSP solver for S = A11 - A10 inv(A00) A01 \n");
179: PetscViewerASCIIPushTab(viewer);
180: if (jac->kspschur) {
181: KSPView(jac->kspschur,viewer);
182: } else {
183: PetscViewerASCIIPrintf(viewer," not yet available\n");
184: }
185: PetscViewerASCIIPopTab(viewer);
186: PetscViewerASCIIPopTab(viewer);
187: } else {
188: SETERRQ1(((PetscObject)pc)->comm,PETSC_ERR_SUP,"Viewer type %s not supported for PCFieldSplit",((PetscObject)viewer)->type_name);
189: }
190: return(0);
191: }
195: /* Precondition: jac->bs is set to a meaningful value */
196: static PetscErrorCode PCFieldSplitSetRuntimeSplits_Private(PC pc)
197: {
199: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
200: PetscInt i,nfields,*ifields,nfields_col,*ifields_col;
201: PetscBool flg,flg_col;
202: char optionname[128],splitname[8],optionname_col[128];
205: PetscMalloc(jac->bs*sizeof(PetscInt),&ifields);
206: PetscMalloc(jac->bs*sizeof(PetscInt),&ifields_col);
207: for (i=0,flg=PETSC_TRUE; ; i++) {
208: PetscSNPrintf(splitname,sizeof splitname,"%D",i);
209: PetscSNPrintf(optionname,sizeof optionname,"-pc_fieldsplit_%D_fields",i);
210: PetscSNPrintf(optionname_col,sizeof optionname_col,"-pc_fieldsplit_%D_fields_col",i);
211: nfields = jac->bs;
212: nfields_col = jac->bs;
213: PetscOptionsGetIntArray(((PetscObject)pc)->prefix,optionname,ifields,&nfields,&flg);
214: PetscOptionsGetIntArray(((PetscObject)pc)->prefix,optionname_col,ifields_col,&nfields_col,&flg_col);
215: if (!flg) break;
216: else if (flg && !flg_col) {
217: if (!nfields) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Cannot list zero fields");
218: PCFieldSplitSetFields(pc,splitname,nfields,ifields,ifields);
219: }
220: else {
221: if (!nfields || !nfields_col) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Cannot list zero fields");
222: if (nfields != nfields_col) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Number of row and column fields must match");
223: PCFieldSplitSetFields(pc,splitname,nfields,ifields,ifields_col);
224: }
225: }
226: if (i > 0) {
227: /* Makes command-line setting of splits take precedence over setting them in code.
228: Otherwise subsequent calls to PCFieldSplitSetIS() or PCFieldSplitSetFields() would
229: create new splits, which would probably not be what the user wanted. */
230: jac->splitdefined = PETSC_TRUE;
231: }
232: PetscFree(ifields);
233: PetscFree(ifields_col);
234: return(0);
235: }
239: static PetscErrorCode PCFieldSplitSetDefaults(PC pc)
240: {
241: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
242: PetscErrorCode ierr;
243: PC_FieldSplitLink ilink = jac->head;
244: PetscBool flg = PETSC_FALSE,stokes = PETSC_FALSE;
245: PetscInt i;
248: if (!ilink) {
249: PetscOptionsGetBool(((PetscObject)pc)->prefix,"-pc_fieldsplit_detect_saddle_point",&stokes,PETSC_NULL);
250: if (pc->dm && !stokes) {
251: PetscInt numFields, f;
252: char **fieldNames;
253: IS *fields;
254: DM *dms;
255: DMCreateFieldDecomposition(pc->dm, &numFields, &fieldNames, &fields, &dms);
256: for(f = 0; f < numFields; ++f) {
257: PCFieldSplitSetIS(pc, fieldNames[f], fields[f]);
258: PetscFree(fieldNames[f]);
259: ISDestroy(&fields[f]);
260: }
261: PetscFree(fieldNames);
262: PetscFree(fields);
263: if(dms) {
264: PetscInfo(pc,"Setting up physics based fieldsplit preconditioner using the embedded DM\n");
265: for (ilink=jac->head,i=0; ilink; ilink=ilink->next,i++) {
266: KSPSetDM(ilink->ksp, dms[i]);
267: KSPSetDMActive(ilink->ksp, PETSC_FALSE);
268: DMDestroy(&dms[i]);
269: }
270: PetscFree(dms);
271: }
272: } else {
273: if (jac->bs <= 0) {
274: if (pc->pmat) {
275: MatGetBlockSize(pc->pmat,&jac->bs);
276: } else {
277: jac->bs = 1;
278: }
279: }
281: PetscOptionsGetBool(((PetscObject)pc)->prefix,"-pc_fieldsplit_default",&flg,PETSC_NULL);
282: if (stokes) {
283: IS zerodiags,rest;
284: PetscInt nmin,nmax;
286: MatGetOwnershipRange(pc->mat,&nmin,&nmax);
287: MatFindZeroDiagonals(pc->mat,&zerodiags);
288: ISComplement(zerodiags,nmin,nmax,&rest);
289: PCFieldSplitSetIS(pc,"0",rest);
290: PCFieldSplitSetIS(pc,"1",zerodiags);
291: ISDestroy(&zerodiags);
292: ISDestroy(&rest);
293: } else {
294: if (!flg) {
295: /* Allow user to set fields from command line, if bs was known at the time of PCSetFromOptions_FieldSplit()
296: then it is set there. This is not ideal because we should only have options set in XXSetFromOptions(). */
297: PCFieldSplitSetRuntimeSplits_Private(pc);
298: if (jac->splitdefined) {PetscInfo(pc,"Splits defined using the options database\n");}
299: }
300: if (flg || !jac->splitdefined) {
301: PetscInfo(pc,"Using default splitting of fields\n");
302: for (i=0; i<jac->bs; i++) {
303: char splitname[8];
304: PetscSNPrintf(splitname,sizeof splitname,"%D",i);
305: PCFieldSplitSetFields(pc,splitname,1,&i,&i);
306: }
307: jac->defaultsplit = PETSC_TRUE;
308: }
309: }
310: }
311: } else if (jac->nsplits == 1) {
312: if (ilink->is) {
313: IS is2;
314: PetscInt nmin,nmax;
316: MatGetOwnershipRange(pc->mat,&nmin,&nmax);
317: ISComplement(ilink->is,nmin,nmax,&is2);
318: PCFieldSplitSetIS(pc,"1",is2);
319: ISDestroy(&is2);
320: } else SETERRQ(((PetscObject) pc)->comm,PETSC_ERR_SUP,"Must provide at least two sets of fields to PCFieldSplit()");
321: } else if (jac->reset) {
322: /* PCReset() has been called on this PC, ilink exists but all IS and Vec data structures in it must be rebuilt
323: This is basically the !ilink portion of code above copied from above and the allocation of the ilinks removed
324: since they already exist. This should be totally rewritten */
325: PetscOptionsGetBool(((PetscObject)pc)->prefix,"-pc_fieldsplit_detect_saddle_point",&stokes,PETSC_NULL);
326: if (pc->dm && !stokes) {
327: PetscBool dmcomposite;
328: PetscObjectTypeCompare((PetscObject)pc->dm,DMCOMPOSITE,&dmcomposite);
329: if (dmcomposite) {
330: PetscInt nDM;
331: IS *fields;
332: DM *dms;
333: PetscInfo(pc,"Setting up physics based fieldsplit preconditioner using the embedded DM\n");
334: DMCompositeGetNumberDM(pc->dm,&nDM);
335: DMCompositeGetGlobalISs(pc->dm,&fields);
336: PetscMalloc(nDM*sizeof(DM),&dms);
337: DMCompositeGetEntriesArray(pc->dm,dms);
338: for (i=0; i<nDM; i++) {
339: KSPSetDM(ilink->ksp,dms[i]);
340: KSPSetDMActive(ilink->ksp,PETSC_FALSE);
341: ilink->is = fields[i];
342: ilink = ilink->next;
343: }
344: PetscFree(fields);
345: PetscFree(dms);
346: }
347: } else {
348: PetscOptionsGetBool(((PetscObject)pc)->prefix,"-pc_fieldsplit_default",&flg,PETSC_NULL);
349: if (stokes) {
350: IS zerodiags,rest;
351: PetscInt nmin,nmax;
353: MatGetOwnershipRange(pc->mat,&nmin,&nmax);
354: MatFindZeroDiagonals(pc->mat,&zerodiags);
355: ISComplement(zerodiags,nmin,nmax,&rest);
356: ISDestroy(&ilink->is);
357: ISDestroy(&ilink->next->is);
358: ilink->is = rest;
359: ilink->next->is = zerodiags;
360: } else SETERRQ(((PetscObject)pc)->comm,PETSC_ERR_SUP,"Cases not yet handled when PCReset() was used");
361: }
362: }
364: if (jac->nsplits < 2) SETERRQ1(((PetscObject) pc)->comm,PETSC_ERR_PLIB,"Unhandled case, must have at least two fields, not %d", jac->nsplits);
365: return(0);
366: }
370: static PetscErrorCode PCSetUp_FieldSplit(PC pc)
371: {
372: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
373: PetscErrorCode ierr;
374: PC_FieldSplitLink ilink;
375: PetscInt i,nsplit;
376: MatStructure flag = pc->flag;
377: PetscBool sorted, sorted_col;
380: PCFieldSplitSetDefaults(pc);
381: nsplit = jac->nsplits;
382: ilink = jac->head;
384: /* get the matrices for each split */
385: if (!jac->issetup) {
386: PetscInt rstart,rend,nslots,bs;
388: jac->issetup = PETSC_TRUE;
390: /* This is done here instead of in PCFieldSplitSetFields() because may not have matrix at that point */
391: if (jac->defaultsplit || !ilink->is) {
392: if (jac->bs <= 0) jac->bs = nsplit;
393: }
394: bs = jac->bs;
395: MatGetOwnershipRange(pc->pmat,&rstart,&rend);
396: nslots = (rend - rstart)/bs;
397: for (i=0; i<nsplit; i++) {
398: if (jac->defaultsplit) {
399: ISCreateStride(((PetscObject)pc)->comm,nslots,rstart+i,nsplit,&ilink->is);
400: ISDuplicate(ilink->is,&ilink->is_col);
401: } else if (!ilink->is) {
402: if (ilink->nfields > 1) {
403: PetscInt *ii,*jj,j,k,nfields = ilink->nfields,*fields = ilink->fields,*fields_col = ilink->fields_col;
404: PetscMalloc(ilink->nfields*nslots*sizeof(PetscInt),&ii);
405: PetscMalloc(ilink->nfields*nslots*sizeof(PetscInt),&jj);
406: for (j=0; j<nslots; j++) {
407: for (k=0; k<nfields; k++) {
408: ii[nfields*j + k] = rstart + bs*j + fields[k];
409: jj[nfields*j + k] = rstart + bs*j + fields_col[k];
410: }
411: }
412: ISCreateGeneral(((PetscObject)pc)->comm,nslots*nfields,ii,PETSC_OWN_POINTER,&ilink->is);
413: ISCreateGeneral(((PetscObject)pc)->comm,nslots*nfields,jj,PETSC_OWN_POINTER,&ilink->is_col);
414: } else {
415: ISCreateStride(((PetscObject)pc)->comm,nslots,rstart+ilink->fields[0],bs,&ilink->is);
416: ISCreateStride(((PetscObject)pc)->comm,nslots,rstart+ilink->fields_col[0],bs,&ilink->is_col);
417: }
418: }
419: ISSorted(ilink->is,&sorted);
420: if (ilink->is_col) { ISSorted(ilink->is_col,&sorted_col); }
421: if (!sorted || !sorted_col) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Fields must be sorted when creating split");
422: ilink = ilink->next;
423: }
424: }
426: ilink = jac->head;
427: if (!jac->pmat) {
428: Vec xtmp;
430: MatGetVecs(pc->pmat,&xtmp,PETSC_NULL);
431: PetscMalloc(nsplit*sizeof(Mat),&jac->pmat);
432: PetscMalloc2(nsplit,Vec,&jac->x,nsplit,Vec,&jac->y);
433: for (i=0; i<nsplit; i++) {
434: MatNullSpace sp;
436: /* Check for preconditioning matrix attached to IS */
437: PetscObjectQuery((PetscObject) ilink->is, "pmat", (PetscObject *) &jac->pmat[i]);
438: if (jac->pmat[i]) {
439: PetscObjectReference((PetscObject) jac->pmat[i]);
440: if (jac->type == PC_COMPOSITE_SCHUR) {
441: jac->schur_user = jac->pmat[i];
442: PetscObjectReference((PetscObject) jac->schur_user);
443: }
444: } else {
445: MatGetSubMatrix(pc->pmat,ilink->is,ilink->is_col,MAT_INITIAL_MATRIX,&jac->pmat[i]);
446: }
447: /* create work vectors for each split */
448: MatGetVecs(jac->pmat[i],&jac->x[i],&jac->y[i]);
449: ilink->x = jac->x[i]; ilink->y = jac->y[i];
450: /* compute scatter contexts needed by multiplicative versions and non-default splits */
451: VecScatterCreate(xtmp,ilink->is,jac->x[i],PETSC_NULL,&ilink->sctx);
452: /* HACK: Check for the constant null space */
453: MatGetNullSpace(pc->pmat, &sp);
454: if (sp) {
455: MatNullSpace subsp;
456: Vec ftmp, gtmp;
457: PetscReal norm;
458: PetscInt N;
460: MatGetVecs(pc->pmat, >mp, PETSC_NULL);
461: MatGetVecs(jac->pmat[i], &ftmp, PETSC_NULL);
462: VecGetSize(ftmp, &N);
463: VecSet(ftmp, 1.0/N);
464: VecScatterBegin(ilink->sctx, ftmp, gtmp, INSERT_VALUES, SCATTER_REVERSE);
465: VecScatterEnd(ilink->sctx, ftmp, gtmp, INSERT_VALUES, SCATTER_REVERSE);
466: MatNullSpaceRemove(sp, gtmp, PETSC_NULL);
467: VecNorm(gtmp, NORM_2, &norm);
468: if (norm < 1.0e-10) {
469: MatNullSpaceCreate(((PetscObject)pc)->comm, PETSC_TRUE, 0, PETSC_NULL, &subsp);
470: MatSetNullSpace(jac->pmat[i], subsp);
471: MatNullSpaceDestroy(&subsp);
472: }
473: VecDestroy(&ftmp);
474: VecDestroy(>mp);
475: }
476: /* Check for null space attached to IS */
477: PetscObjectQuery((PetscObject) ilink->is, "nearnullspace", (PetscObject *) &sp);
478: if (sp) {
479: MatSetNearNullSpace(jac->pmat[i], sp);
480: }
481: ilink = ilink->next;
482: }
483: VecDestroy(&xtmp);
484: } else {
485: for (i=0; i<nsplit; i++) {
486: Mat pmat;
488: /* Check for preconditioning matrix attached to IS */
489: PetscObjectQuery((PetscObject) ilink->is, "pmat", (PetscObject *) &pmat);
490: if (!pmat) {
491: MatGetSubMatrix(pc->pmat,ilink->is,ilink->is_col,MAT_REUSE_MATRIX,&jac->pmat[i]);
492: }
493: ilink = ilink->next;
494: }
495: }
496: if (jac->realdiagonal) {
497: ilink = jac->head;
498: if (!jac->mat) {
499: PetscMalloc(nsplit*sizeof(Mat),&jac->mat);
500: for (i=0; i<nsplit; i++) {
501: MatGetSubMatrix(pc->mat,ilink->is,ilink->is_col,MAT_INITIAL_MATRIX,&jac->mat[i]);
502: ilink = ilink->next;
503: }
504: } else {
505: for (i=0; i<nsplit; i++) {
506: if (jac->mat[i]) {MatGetSubMatrix(pc->mat,ilink->is,ilink->is_col,MAT_REUSE_MATRIX,&jac->mat[i]);}
507: ilink = ilink->next;
508: }
509: }
510: } else {
511: jac->mat = jac->pmat;
512: }
514: if (jac->type != PC_COMPOSITE_ADDITIVE && jac->type != PC_COMPOSITE_SCHUR) {
515: /* extract the rows of the matrix associated with each field: used for efficient computation of residual inside algorithm */
516: ilink = jac->head;
517: if (!jac->Afield) {
518: PetscMalloc(nsplit*sizeof(Mat),&jac->Afield);
519: for (i=0; i<nsplit; i++) {
520: MatGetSubMatrix(pc->mat,ilink->is,PETSC_NULL,MAT_INITIAL_MATRIX,&jac->Afield[i]);
521: ilink = ilink->next;
522: }
523: } else {
524: for (i=0; i<nsplit; i++) {
525: MatGetSubMatrix(pc->mat,ilink->is,PETSC_NULL,MAT_REUSE_MATRIX,&jac->Afield[i]);
526: ilink = ilink->next;
527: }
528: }
529: }
531: if (jac->type == PC_COMPOSITE_SCHUR) {
532: IS ccis;
533: PetscInt rstart,rend;
534: char lscname[256];
535: PetscObject LSC_L;
536: if (nsplit != 2) SETERRQ(((PetscObject)pc)->comm,PETSC_ERR_ARG_INCOMP,"To use Schur complement preconditioner you must have exactly 2 fields");
538: /* When extracting off-diagonal submatrices, we take complements from this range */
539: MatGetOwnershipRangeColumn(pc->mat,&rstart,&rend);
541: /* need to handle case when one is resetting up the preconditioner */
542: if (jac->schur) {
543: ilink = jac->head;
544: ISComplement(ilink->is_col,rstart,rend,&ccis);
545: MatGetSubMatrix(pc->mat,ilink->is,ccis,MAT_REUSE_MATRIX,&jac->B);
546: ISDestroy(&ccis);
547: ilink = ilink->next;
548: ISComplement(ilink->is_col,rstart,rend,&ccis);
549: MatGetSubMatrix(pc->mat,ilink->is,ccis,MAT_REUSE_MATRIX,&jac->C);
550: ISDestroy(&ccis);
551: MatSchurComplementUpdate(jac->schur,jac->mat[0],jac->pmat[0],jac->B,jac->C,jac->mat[1],pc->flag);
552: KSPSetOperators(jac->kspschur,jac->schur,FieldSplitSchurPre(jac),pc->flag);
554: } else {
555: KSP ksp;
556: char schurprefix[256];
557: MatNullSpace sp;
559: /* extract the A01 and A10 matrices */
560: ilink = jac->head;
561: ISComplement(ilink->is_col,rstart,rend,&ccis);
562: MatGetSubMatrix(pc->mat,ilink->is,ccis,MAT_INITIAL_MATRIX,&jac->B);
563: ISDestroy(&ccis);
564: ilink = ilink->next;
565: ISComplement(ilink->is_col,rstart,rend,&ccis);
566: MatGetSubMatrix(pc->mat,ilink->is,ccis,MAT_INITIAL_MATRIX,&jac->C);
567: ISDestroy(&ccis);
568: /* Use mat[0] (diagonal block of the real matrix) preconditioned by pmat[0] */
569: MatCreateSchurComplement(jac->mat[0],jac->pmat[0],jac->B,jac->C,jac->mat[1],&jac->schur);
570: MatGetNullSpace(jac->pmat[1], &sp);
571: if (sp) {MatSetNullSpace(jac->schur, sp);}
572: /* set tabbing and options prefix of KSP inside the MatSchur */
573: MatSchurComplementGetKSP(jac->schur,&ksp);
574: PetscObjectIncrementTabLevel((PetscObject)ksp,(PetscObject)pc,2);
575: PetscSNPrintf(schurprefix,sizeof schurprefix,"%sfieldsplit_%s_",((PetscObject)pc)->prefix?((PetscObject)pc)->prefix:"",jac->head->splitname);
576: KSPSetOptionsPrefix(ksp,schurprefix);
577: /* Need to call this everytime because new matrix is being created */
578: MatSetFromOptions(jac->schur);
579: MatSetUp(jac->schur);
581: KSPCreate(((PetscObject)pc)->comm,&jac->kspschur);
582: PetscLogObjectParent((PetscObject)pc,(PetscObject)jac->kspschur);
583: PetscObjectIncrementTabLevel((PetscObject)jac->kspschur,(PetscObject)pc,1);
584: KSPSetOperators(jac->kspschur,jac->schur,FieldSplitSchurPre(jac),DIFFERENT_NONZERO_PATTERN);
585: if (jac->schurpre == PC_FIELDSPLIT_SCHUR_PRE_SELF) {
586: PC pc;
587: KSPGetPC(jac->kspschur,&pc);
588: PCSetType(pc,PCNONE);
589: /* Note: This is bad if there exist preconditioners for MATSCHURCOMPLEMENT */
590: }
591: PetscSNPrintf(schurprefix,sizeof schurprefix,"%sfieldsplit_%s_",((PetscObject)pc)->prefix?((PetscObject)pc)->prefix:"",ilink->splitname);
592: KSPSetOptionsPrefix(jac->kspschur,schurprefix);
593: /* really want setfromoptions called in PCSetFromOptions_FieldSplit(), but it is not ready yet */
594: /* need to call this every time, since the jac->kspschur is freshly created, otherwise its options never get set */
595: KSPSetFromOptions(jac->kspschur);
596: }
598: /* HACK: special support to forward L and Lp matrices that might be used by PCLSC */
599: PetscSNPrintf(lscname,sizeof lscname,"%s_LSC_L",ilink->splitname);
600: PetscObjectQuery((PetscObject)pc->mat,lscname,(PetscObject*)&LSC_L);
601: if (!LSC_L) {PetscObjectQuery((PetscObject)pc->pmat,lscname,(PetscObject*)&LSC_L);}
602: if (LSC_L) {PetscObjectCompose((PetscObject)jac->schur,"LSC_L",(PetscObject)LSC_L);}
603: PetscSNPrintf(lscname,sizeof lscname,"%s_LSC_Lp",ilink->splitname);
604: PetscObjectQuery((PetscObject)pc->pmat,lscname,(PetscObject*)&LSC_L);
605: if (!LSC_L) {PetscObjectQuery((PetscObject)pc->mat,lscname,(PetscObject*)&LSC_L);}
606: if (LSC_L) {PetscObjectCompose((PetscObject)jac->schur,"LSC_Lp",(PetscObject)LSC_L);}
607: } else {
608: /* set up the individual PCs */
609: i = 0;
610: ilink = jac->head;
611: while (ilink) {
612: KSPSetOperators(ilink->ksp,jac->mat[i],jac->pmat[i],flag);
613: /* really want setfromoptions called in PCSetFromOptions_FieldSplit(), but it is not ready yet */
614: if (!jac->suboptionsset) {KSPSetFromOptions(ilink->ksp);}
615: KSPSetUp(ilink->ksp);
616: i++;
617: ilink = ilink->next;
618: }
619: }
621: jac->suboptionsset = PETSC_TRUE;
622: return(0);
623: }
625: #define FieldSplitSplitSolveAdd(ilink,xx,yy) \
626: (VecScatterBegin(ilink->sctx,xx,ilink->x,INSERT_VALUES,SCATTER_FORWARD) || \
627: VecScatterEnd(ilink->sctx,xx,ilink->x,INSERT_VALUES,SCATTER_FORWARD) || \
628: KSPSolve(ilink->ksp,ilink->x,ilink->y) || \
629: VecScatterBegin(ilink->sctx,ilink->y,yy,ADD_VALUES,SCATTER_REVERSE) || \
630: VecScatterEnd(ilink->sctx,ilink->y,yy,ADD_VALUES,SCATTER_REVERSE))
634: static PetscErrorCode PCApply_FieldSplit_Schur(PC pc,Vec x,Vec y)
635: {
636: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
637: PetscErrorCode ierr;
638: KSP ksp;
639: PC_FieldSplitLink ilinkA = jac->head, ilinkD = ilinkA->next;
642: MatSchurComplementGetKSP(jac->schur,&ksp);
644: switch (jac->schurfactorization) {
645: case PC_FIELDSPLIT_SCHUR_FACT_DIAG:
646: /* [A00 0; 0 -S], positive definite, suitable for MINRES */
647: VecScatterBegin(ilinkA->sctx,x,ilinkA->x,INSERT_VALUES,SCATTER_FORWARD);
648: VecScatterBegin(ilinkD->sctx,x,ilinkD->x,INSERT_VALUES,SCATTER_FORWARD);
649: VecScatterEnd(ilinkA->sctx,x,ilinkA->x,INSERT_VALUES,SCATTER_FORWARD);
650: KSPSolve(ksp,ilinkA->x,ilinkA->y);
651: VecScatterBegin(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);
652: VecScatterEnd(ilinkD->sctx,x,ilinkD->x,INSERT_VALUES,SCATTER_FORWARD);
653: KSPSolve(jac->kspschur,ilinkD->x,ilinkD->y);
654: VecScale(ilinkD->y,-1.);
655: VecScatterBegin(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);
656: VecScatterEnd(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);
657: VecScatterEnd(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);
658: break;
659: case PC_FIELDSPLIT_SCHUR_FACT_LOWER:
660: /* [A00 0; A10 S], suitable for left preconditioning */
661: VecScatterBegin(ilinkA->sctx,x,ilinkA->x,INSERT_VALUES,SCATTER_FORWARD);
662: VecScatterEnd(ilinkA->sctx,x,ilinkA->x,INSERT_VALUES,SCATTER_FORWARD);
663: KSPSolve(ksp,ilinkA->x,ilinkA->y);
664: MatMult(jac->C,ilinkA->y,ilinkD->x);
665: VecScale(ilinkD->x,-1.);
666: VecScatterBegin(ilinkD->sctx,x,ilinkD->x,ADD_VALUES,SCATTER_FORWARD);
667: VecScatterBegin(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);
668: VecScatterEnd(ilinkD->sctx,x,ilinkD->x,ADD_VALUES,SCATTER_FORWARD);
669: KSPSolve(jac->kspschur,ilinkD->x,ilinkD->y);
670: VecScatterBegin(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);
671: VecScatterEnd(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);
672: VecScatterEnd(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);
673: break;
674: case PC_FIELDSPLIT_SCHUR_FACT_UPPER:
675: /* [A00 A01; 0 S], suitable for right preconditioning */
676: VecScatterBegin(ilinkD->sctx,x,ilinkD->x,INSERT_VALUES,SCATTER_FORWARD);
677: VecScatterEnd(ilinkD->sctx,x,ilinkD->x,INSERT_VALUES,SCATTER_FORWARD);
678: KSPSolve(jac->kspschur,ilinkD->x,ilinkD->y);
679: MatMult(jac->B,ilinkD->y,ilinkA->x);
680: VecScale(ilinkA->x,-1.);
681: VecScatterBegin(ilinkA->sctx,x,ilinkA->x,ADD_VALUES,SCATTER_FORWARD);
682: VecScatterBegin(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);
683: VecScatterEnd(ilinkA->sctx,x,ilinkA->x,ADD_VALUES,SCATTER_FORWARD);
684: KSPSolve(ksp,ilinkA->x,ilinkA->y);
685: VecScatterBegin(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);
686: VecScatterEnd(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);
687: VecScatterEnd(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);
688: break;
689: case PC_FIELDSPLIT_SCHUR_FACT_FULL:
690: /* [1 0; A10 A00^{-1} 1] [A00 0; 0 S] [1 A00^{-1}A01; 0 1], an exact solve if applied exactly, needs one extra solve with A */
691: VecScatterBegin(ilinkA->sctx,x,ilinkA->x,INSERT_VALUES,SCATTER_FORWARD);
692: VecScatterEnd(ilinkA->sctx,x,ilinkA->x,INSERT_VALUES,SCATTER_FORWARD);
693: KSPSolve(ksp,ilinkA->x,ilinkA->y);
694: MatMult(jac->C,ilinkA->y,ilinkD->x);
695: VecScale(ilinkD->x,-1.0);
696: VecScatterBegin(ilinkD->sctx,x,ilinkD->x,ADD_VALUES,SCATTER_FORWARD);
697: VecScatterEnd(ilinkD->sctx,x,ilinkD->x,ADD_VALUES,SCATTER_FORWARD);
699: KSPSolve(jac->kspschur,ilinkD->x,ilinkD->y);
700: VecScatterBegin(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);
701: VecScatterEnd(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);
703: MatMult(jac->B,ilinkD->y,ilinkA->y);
704: VecAXPY(ilinkA->x,-1.0,ilinkA->y);
705: KSPSolve(ksp,ilinkA->x,ilinkA->y);
706: VecScatterBegin(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);
707: VecScatterEnd(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);
708: }
709: return(0);
710: }
714: static PetscErrorCode PCApply_FieldSplit(PC pc,Vec x,Vec y)
715: {
716: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
717: PetscErrorCode ierr;
718: PC_FieldSplitLink ilink = jac->head;
719: PetscInt cnt,bs;
722: CHKMEMQ;
723: if (jac->type == PC_COMPOSITE_ADDITIVE) {
724: if (jac->defaultsplit) {
725: VecGetBlockSize(x,&bs);
726: if (jac->bs > 0 && bs != jac->bs) SETERRQ2(((PetscObject)pc)->comm,PETSC_ERR_ARG_WRONGSTATE,"Blocksize of x vector %D does not match fieldsplit blocksize %D",bs,jac->bs);
727: VecGetBlockSize(y,&bs);
728: if (jac->bs > 0 && bs != jac->bs) SETERRQ2(((PetscObject)pc)->comm,PETSC_ERR_ARG_WRONGSTATE,"Blocksize of y vector %D does not match fieldsplit blocksize %D",bs,jac->bs);
729: VecStrideGatherAll(x,jac->x,INSERT_VALUES);
730: while (ilink) {
731: KSPSolve(ilink->ksp,ilink->x,ilink->y);
732: ilink = ilink->next;
733: }
734: VecStrideScatterAll(jac->y,y,INSERT_VALUES);
735: } else {
736: VecSet(y,0.0);
737: while (ilink) {
738: FieldSplitSplitSolveAdd(ilink,x,y);
739: ilink = ilink->next;
740: }
741: }
742: } else if (jac->type == PC_COMPOSITE_MULTIPLICATIVE || jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
743: if (!jac->w1) {
744: VecDuplicate(x,&jac->w1);
745: VecDuplicate(x,&jac->w2);
746: }
747: VecSet(y,0.0);
748: FieldSplitSplitSolveAdd(ilink,x,y);
749: cnt = 1;
750: while (ilink->next) {
751: ilink = ilink->next;
752: /* compute the residual only over the part of the vector needed */
753: MatMult(jac->Afield[cnt++],y,ilink->x);
754: VecScale(ilink->x,-1.0);
755: VecScatterBegin(ilink->sctx,x,ilink->x,ADD_VALUES,SCATTER_FORWARD);
756: VecScatterEnd(ilink->sctx,x,ilink->x,ADD_VALUES,SCATTER_FORWARD);
757: KSPSolve(ilink->ksp,ilink->x,ilink->y);
758: VecScatterBegin(ilink->sctx,ilink->y,y,ADD_VALUES,SCATTER_REVERSE);
759: VecScatterEnd(ilink->sctx,ilink->y,y,ADD_VALUES,SCATTER_REVERSE);
760: }
761: if (jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
762: cnt -= 2;
763: while (ilink->previous) {
764: ilink = ilink->previous;
765: /* compute the residual only over the part of the vector needed */
766: MatMult(jac->Afield[cnt--],y,ilink->x);
767: VecScale(ilink->x,-1.0);
768: VecScatterBegin(ilink->sctx,x,ilink->x,ADD_VALUES,SCATTER_FORWARD);
769: VecScatterEnd(ilink->sctx,x,ilink->x,ADD_VALUES,SCATTER_FORWARD);
770: KSPSolve(ilink->ksp,ilink->x,ilink->y);
771: VecScatterBegin(ilink->sctx,ilink->y,y,ADD_VALUES,SCATTER_REVERSE);
772: VecScatterEnd(ilink->sctx,ilink->y,y,ADD_VALUES,SCATTER_REVERSE);
773: }
774: }
775: } else SETERRQ1(((PetscObject)pc)->comm,PETSC_ERR_SUP,"Unsupported or unknown composition",(int) jac->type);
776: CHKMEMQ;
777: return(0);
778: }
780: #define FieldSplitSplitSolveAddTranspose(ilink,xx,yy) \
781: (VecScatterBegin(ilink->sctx,xx,ilink->y,INSERT_VALUES,SCATTER_FORWARD) || \
782: VecScatterEnd(ilink->sctx,xx,ilink->y,INSERT_VALUES,SCATTER_FORWARD) || \
783: KSPSolveTranspose(ilink->ksp,ilink->y,ilink->x) || \
784: VecScatterBegin(ilink->sctx,ilink->x,yy,ADD_VALUES,SCATTER_REVERSE) || \
785: VecScatterEnd(ilink->sctx,ilink->x,yy,ADD_VALUES,SCATTER_REVERSE))
789: static PetscErrorCode PCApplyTranspose_FieldSplit(PC pc,Vec x,Vec y)
790: {
791: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
792: PetscErrorCode ierr;
793: PC_FieldSplitLink ilink = jac->head;
794: PetscInt bs;
797: CHKMEMQ;
798: if (jac->type == PC_COMPOSITE_ADDITIVE) {
799: if (jac->defaultsplit) {
800: VecGetBlockSize(x,&bs);
801: if (jac->bs > 0 && bs != jac->bs) SETERRQ2(((PetscObject)pc)->comm,PETSC_ERR_ARG_WRONGSTATE,"Blocksize of x vector %D does not match fieldsplit blocksize %D",bs,jac->bs);
802: VecGetBlockSize(y,&bs);
803: if (jac->bs > 0 && bs != jac->bs) SETERRQ2(((PetscObject)pc)->comm,PETSC_ERR_ARG_WRONGSTATE,"Blocksize of y vector %D does not match fieldsplit blocksize %D",bs,jac->bs);
804: VecStrideGatherAll(x,jac->x,INSERT_VALUES);
805: while (ilink) {
806: KSPSolveTranspose(ilink->ksp,ilink->x,ilink->y);
807: ilink = ilink->next;
808: }
809: VecStrideScatterAll(jac->y,y,INSERT_VALUES);
810: } else {
811: VecSet(y,0.0);
812: while (ilink) {
813: FieldSplitSplitSolveAddTranspose(ilink,x,y);
814: ilink = ilink->next;
815: }
816: }
817: } else {
818: if (!jac->w1) {
819: VecDuplicate(x,&jac->w1);
820: VecDuplicate(x,&jac->w2);
821: }
822: VecSet(y,0.0);
823: if (jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
824: FieldSplitSplitSolveAddTranspose(ilink,x,y);
825: while (ilink->next) {
826: ilink = ilink->next;
827: MatMultTranspose(pc->mat,y,jac->w1);
828: VecWAXPY(jac->w2,-1.0,jac->w1,x);
829: FieldSplitSplitSolveAddTranspose(ilink,jac->w2,y);
830: }
831: while (ilink->previous) {
832: ilink = ilink->previous;
833: MatMultTranspose(pc->mat,y,jac->w1);
834: VecWAXPY(jac->w2,-1.0,jac->w1,x);
835: FieldSplitSplitSolveAddTranspose(ilink,jac->w2,y);
836: }
837: } else {
838: while (ilink->next) { /* get to last entry in linked list */
839: ilink = ilink->next;
840: }
841: FieldSplitSplitSolveAddTranspose(ilink,x,y);
842: while (ilink->previous) {
843: ilink = ilink->previous;
844: MatMultTranspose(pc->mat,y,jac->w1);
845: VecWAXPY(jac->w2,-1.0,jac->w1,x);
846: FieldSplitSplitSolveAddTranspose(ilink,jac->w2,y);
847: }
848: }
849: }
850: CHKMEMQ;
851: return(0);
852: }
856: static PetscErrorCode PCReset_FieldSplit(PC pc)
857: {
858: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
859: PetscErrorCode ierr;
860: PC_FieldSplitLink ilink = jac->head,next;
863: while (ilink) {
864: KSPReset(ilink->ksp);
865: VecDestroy(&ilink->x);
866: VecDestroy(&ilink->y);
867: VecScatterDestroy(&ilink->sctx);
868: ISDestroy(&ilink->is);
869: ISDestroy(&ilink->is_col);
870: next = ilink->next;
871: ilink = next;
872: }
873: PetscFree2(jac->x,jac->y);
874: if (jac->mat && jac->mat != jac->pmat) {
875: MatDestroyMatrices(jac->nsplits,&jac->mat);
876: } else if (jac->mat) {
877: jac->mat = PETSC_NULL;
878: }
879: if (jac->pmat) {MatDestroyMatrices(jac->nsplits,&jac->pmat);}
880: if (jac->Afield) {MatDestroyMatrices(jac->nsplits,&jac->Afield);}
881: VecDestroy(&jac->w1);
882: VecDestroy(&jac->w2);
883: MatDestroy(&jac->schur);
884: MatDestroy(&jac->schur_user);
885: KSPDestroy(&jac->kspschur);
886: MatDestroy(&jac->B);
887: MatDestroy(&jac->C);
888: jac->reset = PETSC_TRUE;
889: return(0);
890: }
894: static PetscErrorCode PCDestroy_FieldSplit(PC pc)
895: {
896: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
897: PetscErrorCode ierr;
898: PC_FieldSplitLink ilink = jac->head,next;
901: PCReset_FieldSplit(pc);
902: while (ilink) {
903: KSPDestroy(&ilink->ksp);
904: next = ilink->next;
905: PetscFree(ilink->splitname);
906: PetscFree(ilink->fields);
907: PetscFree(ilink->fields_col);
908: PetscFree(ilink);
909: ilink = next;
910: }
911: PetscFree2(jac->x,jac->y);
912: PetscFree(pc->data);
913: PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitGetSubKSP_C","",PETSC_NULL);
914: PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetFields_C","",PETSC_NULL);
915: PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetIS_C","",PETSC_NULL);
916: PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetType_C","",PETSC_NULL);
917: PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetBlockSize_C","",PETSC_NULL);
918: PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSchurPrecondition_C","",PETSC_NULL);
919: PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetSchurFactType_C","",PETSC_NULL);
920: return(0);
921: }
925: static PetscErrorCode PCSetFromOptions_FieldSplit(PC pc)
926: {
927: PetscErrorCode ierr;
928: PetscInt bs;
929: PetscBool flg,stokes = PETSC_FALSE;
930: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
931: PCCompositeType ctype;
932: DM ddm;
933: char ddm_name[1025];
936: PetscOptionsHead("FieldSplit options");
937: if(pc->dm) {
938: /* Allow the user to request a decomposition DM by name */
939: PetscStrncpy(ddm_name, "", 1024);
940: PetscOptionsString("-pc_fieldsplit_decomposition", "Name of the DM defining the composition", "PCSetDM", ddm_name, ddm_name,1024,&flg);
941: if(flg) {
942: DMCreateFieldDecompositionDM(pc->dm, ddm_name, &ddm);
943: if(!ddm) {
944: SETERRQ1(((PetscObject)pc)->comm, PETSC_ERR_ARG_WRONGSTATE, "Uknown field decomposition name %s", ddm_name);
945: }
946: PetscInfo(pc,"Using field decomposition DM defined using options database\n");
947: PCSetDM(pc,ddm);
948: }
949: }
950: PetscOptionsBool("-pc_fieldsplit_real_diagonal","Use diagonal blocks of the operator","PCFieldSplitSetRealDiagonal",jac->realdiagonal,&jac->realdiagonal,PETSC_NULL);
951: PetscOptionsInt("-pc_fieldsplit_block_size","Blocksize that defines number of fields","PCFieldSplitSetBlockSize",jac->bs,&bs,&flg);
952: if (flg) {
953: PCFieldSplitSetBlockSize(pc,bs);
954: }
956: PetscOptionsGetBool(((PetscObject)pc)->prefix,"-pc_fieldsplit_detect_saddle_point",&stokes,PETSC_NULL);
957: if (stokes) {
958: PCFieldSplitSetType(pc,PC_COMPOSITE_SCHUR);
959: jac->schurpre = PC_FIELDSPLIT_SCHUR_PRE_SELF;
960: }
962: PetscOptionsEnum("-pc_fieldsplit_type","Type of composition","PCFieldSplitSetType",PCCompositeTypes,(PetscEnum)jac->type,(PetscEnum*)&ctype,&flg);
963: if (flg) {
964: PCFieldSplitSetType(pc,ctype);
965: }
966: /* Only setup fields once */
967: if ((jac->bs > 0) && (jac->nsplits == 0)) {
968: /* only allow user to set fields from command line if bs is already known.
969: otherwise user can set them in PCFieldSplitSetDefaults() */
970: PCFieldSplitSetRuntimeSplits_Private(pc);
971: if (jac->splitdefined) {PetscInfo(pc,"Splits defined using the options database\n");}
972: }
973: if (jac->type == PC_COMPOSITE_SCHUR) {
974: PetscOptionsGetEnum(((PetscObject)pc)->prefix,"-pc_fieldsplit_schur_factorization_type",PCFieldSplitSchurFactTypes,(PetscEnum*)&jac->schurfactorization,&flg);
975: if (flg) {PetscInfo(pc,"Deprecated use of -pc_fieldsplit_schur_factorization_type\n");}
976: PetscOptionsEnum("-pc_fieldsplit_schur_fact_type","Which off-diagonal parts of the block factorization to use","PCFieldSplitSetSchurFactType",PCFieldSplitSchurFactTypes,(PetscEnum)jac->schurfactorization,(PetscEnum*)&jac->schurfactorization,PETSC_NULL);
977: PetscOptionsEnum("-pc_fieldsplit_schur_precondition","How to build preconditioner for Schur complement","PCFieldSplitSchurPrecondition",PCFieldSplitSchurPreTypes,(PetscEnum)jac->schurpre,(PetscEnum*)&jac->schurpre,PETSC_NULL);
978: }
979: PetscOptionsTail();
980: return(0);
981: }
983: /*------------------------------------------------------------------------------------*/
985: EXTERN_C_BEGIN
988: PetscErrorCode PCFieldSplitSetFields_FieldSplit(PC pc,const char splitname[],PetscInt n,const PetscInt *fields,const PetscInt *fields_col)
989: {
990: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
991: PetscErrorCode ierr;
992: PC_FieldSplitLink ilink,next = jac->head;
993: char prefix[128];
994: PetscInt i;
997: if (jac->splitdefined) {
998: PetscInfo1(pc,"Ignoring new split \"%s\" because the splits have already been defined\n",splitname);
999: return(0);
1000: }
1001: for (i=0; i<n; i++) {
1002: if (fields[i] >= jac->bs) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Field %D requested but only %D exist",fields[i],jac->bs);
1003: if (fields[i] < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Negative field %D requested",fields[i]);
1004: }
1005: PetscNew(struct _PC_FieldSplitLink,&ilink);
1006: if (splitname) {
1007: PetscStrallocpy(splitname,&ilink->splitname);
1008: } else {
1009: PetscMalloc(3*sizeof(char),&ilink->splitname);
1010: PetscSNPrintf(ilink->splitname,2,"%s",jac->nsplits);
1011: }
1012: PetscMalloc(n*sizeof(PetscInt),&ilink->fields);
1013: PetscMemcpy(ilink->fields,fields,n*sizeof(PetscInt));
1014: PetscMalloc(n*sizeof(PetscInt),&ilink->fields_col);
1015: PetscMemcpy(ilink->fields_col,fields_col,n*sizeof(PetscInt));
1016: ilink->nfields = n;
1017: ilink->next = PETSC_NULL;
1018: KSPCreate(((PetscObject)pc)->comm,&ilink->ksp);
1019: PetscObjectIncrementTabLevel((PetscObject)ilink->ksp,(PetscObject)pc,1);
1020: KSPSetType(ilink->ksp,KSPPREONLY);
1021: PetscLogObjectParent((PetscObject)pc,(PetscObject)ilink->ksp);
1023: PetscSNPrintf(prefix,sizeof prefix,"%sfieldsplit_%s_",((PetscObject)pc)->prefix?((PetscObject)pc)->prefix:"",ilink->splitname);
1024: KSPSetOptionsPrefix(ilink->ksp,prefix);
1026: if (!next) {
1027: jac->head = ilink;
1028: ilink->previous = PETSC_NULL;
1029: } else {
1030: while (next->next) {
1031: next = next->next;
1032: }
1033: next->next = ilink;
1034: ilink->previous = next;
1035: }
1036: jac->nsplits++;
1037: return(0);
1038: }
1039: EXTERN_C_END
1041: EXTERN_C_BEGIN
1044: PetscErrorCode PCFieldSplitGetSubKSP_FieldSplit_Schur(PC pc,PetscInt *n,KSP **subksp)
1045: {
1046: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
1050: PetscMalloc(jac->nsplits*sizeof(KSP),subksp);
1051: MatSchurComplementGetKSP(jac->schur,*subksp);
1052: (*subksp)[1] = jac->kspschur;
1053: if (n) *n = jac->nsplits;
1054: return(0);
1055: }
1056: EXTERN_C_END
1058: EXTERN_C_BEGIN
1061: PetscErrorCode PCFieldSplitGetSubKSP_FieldSplit(PC pc,PetscInt *n,KSP **subksp)
1062: {
1063: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
1064: PetscErrorCode ierr;
1065: PetscInt cnt = 0;
1066: PC_FieldSplitLink ilink = jac->head;
1069: PetscMalloc(jac->nsplits*sizeof(KSP),subksp);
1070: while (ilink) {
1071: (*subksp)[cnt++] = ilink->ksp;
1072: ilink = ilink->next;
1073: }
1074: if (cnt != jac->nsplits) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Corrupt PCFIELDSPLIT object: number of splits in linked list %D does not match number in object %D",cnt,jac->nsplits);
1075: if (n) *n = jac->nsplits;
1076: return(0);
1077: }
1078: EXTERN_C_END
1080: EXTERN_C_BEGIN
1083: PetscErrorCode PCFieldSplitSetIS_FieldSplit(PC pc,const char splitname[],IS is)
1084: {
1085: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
1086: PetscErrorCode ierr;
1087: PC_FieldSplitLink ilink, next = jac->head;
1088: char prefix[128];
1091: if (jac->splitdefined) {
1092: PetscInfo1(pc,"Ignoring new split \"%s\" because the splits have already been defined\n",splitname);
1093: return(0);
1094: }
1095: PetscNew(struct _PC_FieldSplitLink,&ilink);
1096: if (splitname) {
1097: PetscStrallocpy(splitname,&ilink->splitname);
1098: } else {
1099: PetscMalloc(8*sizeof(char),&ilink->splitname);
1100: PetscSNPrintf(ilink->splitname,7,"%D",jac->nsplits);
1101: }
1102: PetscObjectReference((PetscObject)is);
1103: ISDestroy(&ilink->is);
1104: ilink->is = is;
1105: PetscObjectReference((PetscObject)is);
1106: ISDestroy(&ilink->is_col);
1107: ilink->is_col = is;
1108: ilink->next = PETSC_NULL;
1109: KSPCreate(((PetscObject)pc)->comm,&ilink->ksp);
1110: PetscObjectIncrementTabLevel((PetscObject)ilink->ksp,(PetscObject)pc,1);
1111: KSPSetType(ilink->ksp,KSPPREONLY);
1112: PetscLogObjectParent((PetscObject)pc,(PetscObject)ilink->ksp);
1114: PetscSNPrintf(prefix,sizeof prefix,"%sfieldsplit_%s_",((PetscObject)pc)->prefix?((PetscObject)pc)->prefix:"",ilink->splitname);
1115: KSPSetOptionsPrefix(ilink->ksp,prefix);
1117: if (!next) {
1118: jac->head = ilink;
1119: ilink->previous = PETSC_NULL;
1120: } else {
1121: while (next->next) {
1122: next = next->next;
1123: }
1124: next->next = ilink;
1125: ilink->previous = next;
1126: }
1127: jac->nsplits++;
1129: return(0);
1130: }
1131: EXTERN_C_END
1135: /*@
1136: PCFieldSplitSetFields - Sets the fields for one particular split in the field split preconditioner
1138: Logically Collective on PC
1140: Input Parameters:
1141: + pc - the preconditioner context
1142: . splitname - name of this split, if PETSC_NULL the number of the split is used
1143: . n - the number of fields in this split
1144: - fields - the fields in this split
1146: Level: intermediate
1148: Notes: Use PCFieldSplitSetIS() to set a completely general set of indices as a field.
1150: The PCFieldSplitSetFields() is for defining fields as a strided blocks. For example, if the block
1151: 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
1152: 0xx3xx6xx9xx12 ... x1xx4xx7xx ... xx2xx5xx8xx.. 01x34x67x... 0x1x3x5x7.. x12x45x78x....
1153: where the numbered entries indicate what is in the field.
1155: This function is called once per split (it creates a new split each time). Solve options
1156: for this split will be available under the prefix -fieldsplit_SPLITNAME_.
1158: Developer Note: This routine does not actually create the IS representing the split, that is delayed
1159: until PCSetUp_FieldSplit(), because information about the vector/matrix layouts may not be
1160: available when this routine is called.
1162: .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetBlockSize(), PCFieldSplitSetIS()
1164: @*/
1165: PetscErrorCode PCFieldSplitSetFields(PC pc,const char splitname[],PetscInt n,const PetscInt *fields,const PetscInt *fields_col)
1166: {
1172: if (n < 1) SETERRQ2(((PetscObject)pc)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Provided number of fields %D in split \"%s\" not positive",n,splitname);
1174: PetscTryMethod(pc,"PCFieldSplitSetFields_C",(PC,const char[],PetscInt,const PetscInt *,const PetscInt *),(pc,splitname,n,fields,fields_col));
1175: return(0);
1176: }
1180: /*@
1181: PCFieldSplitSetIS - Sets the exact elements for field
1183: Logically Collective on PC
1185: Input Parameters:
1186: + pc - the preconditioner context
1187: . splitname - name of this split, if PETSC_NULL the number of the split is used
1188: - is - the index set that defines the vector elements in this field
1191: Notes:
1192: Use PCFieldSplitSetFields(), for fields defined by strided types.
1194: This function is called once per split (it creates a new split each time). Solve options
1195: for this split will be available under the prefix -fieldsplit_SPLITNAME_.
1197: Level: intermediate
1199: .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetBlockSize()
1201: @*/
1202: PetscErrorCode PCFieldSplitSetIS(PC pc,const char splitname[],IS is)
1203: {
1210: PetscTryMethod(pc,"PCFieldSplitSetIS_C",(PC,const char[],IS),(pc,splitname,is));
1211: return(0);
1212: }
1216: /*@
1217: PCFieldSplitGetIS - Retrieves the elements for a field as an IS
1219: Logically Collective on PC
1221: Input Parameters:
1222: + pc - the preconditioner context
1223: - splitname - name of this split
1225: Output Parameter:
1226: - is - the index set that defines the vector elements in this field, or PETSC_NULL if the field is not found
1228: Level: intermediate
1230: .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetIS()
1232: @*/
1233: PetscErrorCode PCFieldSplitGetIS(PC pc,const char splitname[],IS *is)
1234: {
1241: {
1242: PC_FieldSplit *jac = (PC_FieldSplit *) pc->data;
1243: PC_FieldSplitLink ilink = jac->head;
1244: PetscBool found;
1246: *is = PETSC_NULL;
1247: while(ilink) {
1248: PetscStrcmp(ilink->splitname, splitname, &found);
1249: if (found) {
1250: *is = ilink->is;
1251: break;
1252: }
1253: ilink = ilink->next;
1254: }
1255: }
1256: return(0);
1257: }
1261: /*@
1262: PCFieldSplitSetBlockSize - Sets the block size for defining where fields start in the
1263: fieldsplit preconditioner. If not set the matrix block size is used.
1265: Logically Collective on PC
1267: Input Parameters:
1268: + pc - the preconditioner context
1269: - bs - the block size
1271: Level: intermediate
1273: .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetFields()
1275: @*/
1276: PetscErrorCode PCFieldSplitSetBlockSize(PC pc,PetscInt bs)
1277: {
1283: PetscTryMethod(pc,"PCFieldSplitSetBlockSize_C",(PC,PetscInt),(pc,bs));
1284: return(0);
1285: }
1289: /*@C
1290: PCFieldSplitGetSubKSP - Gets the KSP contexts for all splits
1291:
1292: Collective on KSP
1294: Input Parameter:
1295: . pc - the preconditioner context
1297: Output Parameters:
1298: + n - the number of splits
1299: - pc - the array of KSP contexts
1301: Note:
1302: After PCFieldSplitGetSubKSP() the array of KSPs IS to be freed by the user
1303: (not the KSP just the array that contains them).
1305: You must call KSPSetUp() before calling PCFieldSplitGetSubKSP().
1307: Level: advanced
1309: .seealso: PCFIELDSPLIT
1310: @*/
1311: PetscErrorCode PCFieldSplitGetSubKSP(PC pc,PetscInt *n,KSP *subksp[])
1312: {
1318: PetscUseMethod(pc,"PCFieldSplitGetSubKSP_C",(PC,PetscInt*,KSP **),(pc,n,subksp));
1319: return(0);
1320: }
1324: /*@
1325: PCFieldSplitSchurPrecondition - Indicates if the Schur complement is preconditioned by a preconditioner constructed by the
1326: A11 matrix. Otherwise no preconditioner is used.
1328: Collective on PC
1330: Input Parameters:
1331: + pc - the preconditioner context
1332: . ptype - which matrix to use for preconditioning the Schur complement, PC_FIELDSPLIT_SCHUR_PRE_DIAG (diag) is default
1333: - userpre - matrix to use for preconditioning, or PETSC_NULL
1335: Options Database:
1336: . -pc_fieldsplit_schur_precondition <self,user,diag> default is diag
1338: Notes:
1339: $ If ptype is
1340: $ user then the preconditioner for the Schur complement is generated by the provided matrix (pre argument
1341: $ to this function).
1342: $ diag then the preconditioner for the Schur complement is generated by the block diagonal part of the original
1343: $ matrix associated with the Schur complement (i.e. A11)
1344: $ self the preconditioner for the Schur complement is generated from the Schur complement matrix itself:
1345: $ The only preconditioner that currently works directly with the Schur complement matrix object is the PCLSC
1346: $ preconditioner
1348: When solving a saddle point problem, where the A11 block is identically zero, using diag as the ptype only makes sense
1349: with the additional option -fieldsplit_1_pc_type none. Usually for saddle point problems one would use a ptype of self and
1350: -fieldsplit_1_pc_type lsc which uses the least squares commutator compute a preconditioner for the Schur complement.
1351:
1352: Developer Notes: This is a terrible name, gives no good indication of what the function does and should also have Set in
1353: the name since it sets a proceedure to use.
1354:
1355: Level: intermediate
1357: .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetFields(), PCFieldSplitSchurPreType, PCLSC
1359: @*/
1360: PetscErrorCode PCFieldSplitSchurPrecondition(PC pc,PCFieldSplitSchurPreType ptype,Mat pre)
1361: {
1366: PetscTryMethod(pc,"PCFieldSplitSchurPrecondition_C",(PC,PCFieldSplitSchurPreType,Mat),(pc,ptype,pre));
1367: return(0);
1368: }
1370: EXTERN_C_BEGIN
1373: PetscErrorCode PCFieldSplitSchurPrecondition_FieldSplit(PC pc,PCFieldSplitSchurPreType ptype,Mat pre)
1374: {
1375: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
1376: PetscErrorCode ierr;
1379: jac->schurpre = ptype;
1380: if (pre) {
1381: MatDestroy(&jac->schur_user);
1382: jac->schur_user = pre;
1383: PetscObjectReference((PetscObject)jac->schur_user);
1384: }
1385: return(0);
1386: }
1387: EXTERN_C_END
1391: /*@
1392: PCFieldSplitSetSchurFactType - sets which blocks of the approximate block factorization to retain
1394: Collective on PC
1396: Input Parameters:
1397: + pc - the preconditioner context
1398: - ftype - which blocks of factorization to retain, PC_FIELDSPLIT_SCHUR_FACT_FULL is default
1400: Options Database:
1401: . -pc_fieldsplit_schur_fact_type <diag,lower,upper,full> default is full
1404: Level: intermediate
1406: Notes:
1407: The FULL factorization is
1409: $ (A B) = (1 0) (A 0) (1 Ainv*B)
1410: $ (C D) (C*Ainv 1) (0 S) (0 1 )
1412: where S = D - C*Ainv*B. In practice, the full factorization is applied via block triangular solves with the grouping L*(D*U). UPPER uses D*U, LOWER uses L*D,
1413: and DIAG is the diagonal part with the sign of S flipped (because this makes the preconditioner positive definite for many formulations, thus allowing the use of KSPMINRES).
1415: If applied exactly, FULL factorization is a direct solver. The preconditioned operator with LOWER or UPPER has all eigenvalues equal to 1 and minimal polynomial
1416: of degree 2, so KSPGMRES converges in 2 iterations. If the iteration count is very low, consider using KSPFGMRES or KSPGCR which can use one less preconditioner
1417: application in this case. Note that the preconditioned operator may be highly non-normal, so such fast convergence may not be observed in practice. With DIAG,
1418: the preconditioned operator has three distinct nonzero eigenvalues and minimal polynomial of degree at most 4, so KSPGMRES converges in at most 4 iterations.
1420: For symmetric problems in which A is positive definite and S is negative definite, DIAG can be used with KSPMINRES. Note that a flexible method like KSPFGMRES
1421: or KSPGCR must be used if the fieldsplit preconditioner is nonlinear (e.g. a few iterations of a Krylov method is used inside a split).
1423: References:
1424: Murphy, Golub, and Wathen, A note on preconditioning indefinite linear systems, SIAM J. Sci. Comput., 21 (2000) pp. 1969-1972.
1426: Ipsen, A note on preconditioning nonsymmetric matrices, SIAM J. Sci. Comput., 23 (2001), pp. 1050-1051.
1428: .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetFields(), PCFieldSplitSchurPreType
1429: @*/
1430: PetscErrorCode PCFieldSplitSetSchurFactType(PC pc,PCFieldSplitSchurFactType ftype)
1431: {
1436: PetscTryMethod(pc,"PCFieldSplitSetSchurFactType_C",(PC,PCFieldSplitSchurFactType),(pc,ftype));
1437: return(0);
1438: }
1443: {
1444: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
1447: jac->schurfactorization = ftype;
1448: return(0);
1449: }
1453: /*@C
1454: PCFieldSplitGetSchurBlocks - Gets all matrix blocks for the Schur complement
1455:
1456: Collective on KSP
1458: Input Parameter:
1459: . pc - the preconditioner context
1461: Output Parameters:
1462: + A00 - the (0,0) block
1463: . A01 - the (0,1) block
1464: . A10 - the (1,0) block
1465: - A11 - the (1,1) block
1467: Level: advanced
1469: .seealso: PCFIELDSPLIT
1470: @*/
1471: PetscErrorCode PCFieldSplitGetSchurBlocks(PC pc,Mat *A00,Mat *A01,Mat *A10, Mat *A11)
1472: {
1473: PC_FieldSplit *jac = (PC_FieldSplit *) pc->data;
1477: if (jac->type != PC_COMPOSITE_SCHUR) SETERRQ(((PetscObject)pc)->comm,PETSC_ERR_ARG_WRONG, "FieldSplit is not using a Schur complement approach.");
1478: if (A00) *A00 = jac->pmat[0];
1479: if (A01) *A01 = jac->B;
1480: if (A10) *A10 = jac->C;
1481: if (A11) *A11 = jac->pmat[1];
1482: return(0);
1483: }
1485: EXTERN_C_BEGIN
1488: PetscErrorCode PCFieldSplitSetType_FieldSplit(PC pc,PCCompositeType type)
1489: {
1490: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
1494: jac->type = type;
1495: if (type == PC_COMPOSITE_SCHUR) {
1496: pc->ops->apply = PCApply_FieldSplit_Schur;
1497: pc->ops->view = PCView_FieldSplit_Schur;
1498: PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitGetSubKSP_C","PCFieldSplitGetSubKSP_FieldSplit_Schur",PCFieldSplitGetSubKSP_FieldSplit_Schur);
1499: PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSchurPrecondition_C","PCFieldSplitSchurPrecondition_FieldSplit",PCFieldSplitSchurPrecondition_FieldSplit);
1500: PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetSchurFactType_C","PCFieldSplitSetSchurFactType_FieldSplit",PCFieldSplitSetSchurFactType_FieldSplit);
1502: } else {
1503: pc->ops->apply = PCApply_FieldSplit;
1504: pc->ops->view = PCView_FieldSplit;
1505: PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitGetSubKSP_C","PCFieldSplitGetSubKSP_FieldSplit",PCFieldSplitGetSubKSP_FieldSplit);
1506: PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSchurPrecondition_C","",0);
1507: PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetSchurFactType_C","",0);
1508: }
1509: return(0);
1510: }
1511: EXTERN_C_END
1513: EXTERN_C_BEGIN
1516: PetscErrorCode PCFieldSplitSetBlockSize_FieldSplit(PC pc,PetscInt bs)
1517: {
1518: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
1521: if (bs < 1) SETERRQ1(((PetscObject)pc)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Blocksize must be positive, you gave %D",bs);
1522: if (jac->bs > 0 && jac->bs != bs) SETERRQ2(((PetscObject)pc)->comm,PETSC_ERR_ARG_WRONGSTATE,"Cannot change fieldsplit blocksize from %D to %D after it has been set",jac->bs,bs);
1523: jac->bs = bs;
1524: return(0);
1525: }
1526: EXTERN_C_END
1530: /*@
1531: PCFieldSplitSetType - Sets the type of fieldsplit preconditioner.
1532:
1533: Collective on PC
1535: Input Parameter:
1536: . pc - the preconditioner context
1537: . type - PC_COMPOSITE_ADDITIVE, PC_COMPOSITE_MULTIPLICATIVE (default), PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE, PC_COMPOSITE_SPECIAL, PC_COMPOSITE_SCHUR
1539: Options Database Key:
1540: . -pc_fieldsplit_type <type: one of multiplicative, additive, symmetric_multiplicative, special, schur> - Sets fieldsplit preconditioner type
1542: Level: Intermediate
1544: .keywords: PC, set, type, composite preconditioner, additive, multiplicative
1546: .seealso: PCCompositeSetType()
1548: @*/
1549: PetscErrorCode PCFieldSplitSetType(PC pc,PCCompositeType type)
1550: {
1555: PetscTryMethod(pc,"PCFieldSplitSetType_C",(PC,PCCompositeType),(pc,type));
1556: return(0);
1557: }
1561: /*@
1562: PCFieldSplitGetType - Gets the type of fieldsplit preconditioner.
1564: Not collective
1566: Input Parameter:
1567: . pc - the preconditioner context
1569: Output Parameter:
1570: . type - PC_COMPOSITE_ADDITIVE, PC_COMPOSITE_MULTIPLICATIVE (default), PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE, PC_COMPOSITE_SPECIAL, PC_COMPOSITE_SCHUR
1572: Level: Intermediate
1574: .keywords: PC, set, type, composite preconditioner, additive, multiplicative
1575: .seealso: PCCompositeSetType()
1576: @*/
1577: PetscErrorCode PCFieldSplitGetType(PC pc, PCCompositeType *type)
1578: {
1579: PC_FieldSplit *jac = (PC_FieldSplit *) pc->data;
1584: *type = jac->type;
1585: return(0);
1586: }
1588: /* -------------------------------------------------------------------------------------*/
1589: /*MC
1590: PCFIELDSPLIT - Preconditioner created by combining separate preconditioners for individual
1591: fields or groups of fields. See the users manual section "Solving Block Matrices" for more details.
1593: To set options on the solvers for each block append -fieldsplit_ to all the PC
1594: options database keys. For example, -fieldsplit_pc_type ilu -fieldsplit_pc_factor_levels 1
1595:
1596: To set the options on the solvers separate for each block call PCFieldSplitGetSubKSP()
1597: and set the options directly on the resulting KSP object
1599: Level: intermediate
1601: Options Database Keys:
1602: + -pc_fieldsplit_%d_fields <a,b,..> - indicates the fields to be used in the %d'th split
1603: . -pc_fieldsplit_default - automatically add any fields to additional splits that have not
1604: been supplied explicitly by -pc_fieldsplit_%d_fields
1605: . -pc_fieldsplit_block_size <bs> - size of block that defines fields (i.e. there are bs fields)
1606: . -pc_fieldsplit_type <additive,multiplicative,symmetric_multiplicative,schur> - type of relaxation or factorization splitting
1607: . -pc_fieldsplit_schur_precondition <self,user,diag> - default is diag
1608: . -pc_fieldsplit_detect_saddle_point - automatically finds rows with zero or negative diagonal and uses Schur complement with no preconditioner as the solver
1610: - Options prefix for inner solvers when using Schur complement preconditioner are -fieldsplit_0_ and -fieldsplit_1_
1611: for all other solvers they are -fieldsplit_%d_ for the dth field, use -fieldsplit_ for all fields
1613: Notes:
1614: Use PCFieldSplitSetFields() to set fields defined by "strided" entries and PCFieldSplitSetIS()
1615: to define a field by an arbitrary collection of entries.
1617: If no fields are set the default is used. The fields are defined by entries strided by bs,
1618: beginning at 0 then 1, etc to bs-1. The block size can be set with PCFieldSplitSetBlockSize(),
1619: if this is not called the block size defaults to the blocksize of the second matrix passed
1620: to KSPSetOperators()/PCSetOperators().
1622: $ For the Schur complement preconditioner if J = ( A00 A01 )
1623: $ ( A10 A11 )
1624: $ the preconditioner using full factorization is
1625: $ ( I -A10 ksp(A00) ) ( inv(A00) 0 ) ( I 0 )
1626: $ ( 0 I ) ( 0 ksp(S) ) ( -A10 ksp(A00) I )
1627: where the action of inv(A00) is applied using the KSP solver with prefix -fieldsplit_0_. The action of
1628: ksp(S) is computed using the KSP solver with prefix -fieldsplit_splitname_ (where splitname was given
1629: in providing the SECOND split or 1 if not give). For PCFieldSplitGetKSP() when field number is 0,
1630: it returns the KSP associated with -fieldsplit_0_ while field number 1 gives -fieldsplit_1_ KSP. By default
1631: A11 is used to construct a preconditioner for S, use PCFieldSplitSchurPrecondition() to turn on or off this
1632: option. You can use the preconditioner PCLSC to precondition the Schur complement with -fieldsplit_1_pc_type lsc. The
1633: factorization type is set using -pc_fieldsplit_schur_fact_type <diag, lower, upper, full>. The full is shown above,
1634: diag gives
1635: $ ( inv(A00) 0 )
1636: $ ( 0 -ksp(S) )
1637: note that slightly counter intuitively there is a negative in front of the ksp(S) so that the preconditioner is positive definite. The lower factorization is the inverse of
1638: $ ( A00 0 )
1639: $ ( A10 S )
1640: where the inverses of A00 and S are applied using KSPs. The upper factorization is the inverse of
1641: $ ( A00 A01 )
1642: $ ( 0 S )
1643: where again the inverses of A00 and S are applied using KSPs.
1645: If only one set of indices (one IS) is provided with PCFieldSplitSetIS() then the complement of that IS
1646: is used automatically for a second block.
1648: The fieldsplit preconditioner cannot currently be used with the BAIJ or SBAIJ data formats if the blocksize is larger than 1.
1649: Generally it should be used with the AIJ format.
1651: The forms of these preconditioners are closely related if not identical to forms derived as "Distributive Iterations", see,
1652: for example, page 294 in "Principles of Computational Fluid Dynamics" by Pieter Wesseling. Note that one can also use PCFIELDSPLIT
1653: inside a smoother resulting in "Distributive Smoothers".
1655: Concepts: physics based preconditioners, block preconditioners
1657: .seealso: PCCreate(), PCSetType(), PCType (for list of available types), PC, Block_Preconditioners, PCLSC,
1658: PCFieldSplitGetSubKSP(), PCFieldSplitSetFields(), PCFieldSplitSetType(), PCFieldSplitSetIS(), PCFieldSplitSchurPrecondition()
1659: M*/
1661: EXTERN_C_BEGIN
1664: PetscErrorCode PCCreate_FieldSplit(PC pc)
1665: {
1667: PC_FieldSplit *jac;
1670: PetscNewLog(pc,PC_FieldSplit,&jac);
1671: jac->bs = -1;
1672: jac->nsplits = 0;
1673: jac->type = PC_COMPOSITE_MULTIPLICATIVE;
1674: jac->schurpre = PC_FIELDSPLIT_SCHUR_PRE_USER; /* Try user preconditioner first, fall back on diagonal */
1675: jac->schurfactorization = PC_FIELDSPLIT_SCHUR_FACT_FULL;
1677: pc->data = (void*)jac;
1679: pc->ops->apply = PCApply_FieldSplit;
1680: pc->ops->applytranspose = PCApplyTranspose_FieldSplit;
1681: pc->ops->setup = PCSetUp_FieldSplit;
1682: pc->ops->reset = PCReset_FieldSplit;
1683: pc->ops->destroy = PCDestroy_FieldSplit;
1684: pc->ops->setfromoptions = PCSetFromOptions_FieldSplit;
1685: pc->ops->view = PCView_FieldSplit;
1686: pc->ops->applyrichardson = 0;
1688: PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitGetSubKSP_C","PCFieldSplitGetSubKSP_FieldSplit",
1689: PCFieldSplitGetSubKSP_FieldSplit);
1690: PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetFields_C","PCFieldSplitSetFields_FieldSplit",
1691: PCFieldSplitSetFields_FieldSplit);
1692: PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetIS_C","PCFieldSplitSetIS_FieldSplit",
1693: PCFieldSplitSetIS_FieldSplit);
1694: PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetType_C","PCFieldSplitSetType_FieldSplit",
1695: PCFieldSplitSetType_FieldSplit);
1696: PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetBlockSize_C","PCFieldSplitSetBlockSize_FieldSplit",
1697: PCFieldSplitSetBlockSize_FieldSplit);
1698: return(0);
1699: }
1700: EXTERN_C_END