Actual source code: fieldsplit.c
2: #include <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 PCFieldSplitSchurFactorizationTypes[] = {"DIAG","LOWER","UPPER","FULL","PCFieldSplitSchurFactorizationType","PC_FIELDSPLIT_SCHUR_FACTORIZATION_",0};
8: typedef enum {
9: PC_FIELDSPLIT_SCHUR_FACTORIZATION_DIAG,
10: PC_FIELDSPLIT_SCHUR_FACTORIZATION_LOWER,
11: PC_FIELDSPLIT_SCHUR_FACTORIZATION_UPPER,
12: PC_FIELDSPLIT_SCHUR_FACTORIZATION_FULL
13: } PCFieldSplitSchurFactorizationType;
15: typedef struct _PC_FieldSplitLink *PC_FieldSplitLink;
16: struct _PC_FieldSplitLink {
17: KSP ksp;
18: Vec x,y;
19: char *splitname;
20: PetscInt nfields;
21: PetscInt *fields;
22: VecScatter sctx;
23: IS is;
24: PC_FieldSplitLink next,previous;
25: };
27: typedef struct {
28: PCCompositeType type;
29: PetscBool defaultsplit; /* Flag for a system with a set of 'k' scalar fields with the same layout (and bs = k) */
30: PetscBool splitdefined; /* Flag is set after the splits have been defined, to prevent more splits from being added */
31: PetscBool realdiagonal; /* Flag to use the diagonal blocks of mat preconditioned by pmat, instead of just pmat */
32: PetscInt bs; /* Block size for IS and Mat structures */
33: PetscInt nsplits; /* Number of field divisions defined */
34: Vec *x,*y,w1,w2;
35: Mat *mat; /* The diagonal block for each split */
36: Mat *pmat; /* The preconditioning diagonal block for each split */
37: Mat *Afield; /* The rows of the matrix associated with each split */
38: PetscBool issetup;
39: /* Only used when Schur complement preconditioning is used */
40: Mat B; /* The (0,1) block */
41: Mat C; /* The (1,0) block */
42: Mat schur; /* The Schur complement S = A11 - A10 A00^{-1} A01 */
43: Mat schur_user; /* User-provided preconditioning matrix for the Schur complement */
44: PCFieldSplitSchurPreType schurpre; /* Determines which preconditioning matrix is used for the Schur complement */
45: PCFieldSplitSchurFactorizationType schurfactorization;
46: KSP kspschur; /* The solver for S */
47: PC_FieldSplitLink head;
48: PetscBool reset; /* indicates PCReset() has been last called on this object, hack */
49: PetscBool suboptionsset; /* Indicates that the KSPSetFromOptions() has been called on the sub-KSPs */
50: } PC_FieldSplit;
52: /*
53: Notes: there is no particular reason that pmat, x, and y are stored as arrays in PC_FieldSplit instead of
54: inside PC_FieldSplitLink, just historical. If you want to be able to add new fields after already using the
55: PC you could change this.
56: */
58: /* This helper is so that setting a user-provided preconditioning matrix is orthogonal to choosing to use it. This way the
59: * application-provided FormJacobian can provide this matrix without interfering with the user's (command-line) choices. */
60: static Mat FieldSplitSchurPre(PC_FieldSplit *jac)
61: {
62: switch (jac->schurpre) {
63: case PC_FIELDSPLIT_SCHUR_PRE_SELF: return jac->schur;
64: case PC_FIELDSPLIT_SCHUR_PRE_DIAG: return jac->pmat[1];
65: case PC_FIELDSPLIT_SCHUR_PRE_USER: /* Use a user-provided matrix if it is given, otherwise diagonal block */
66: default:
67: return jac->schur_user ? jac->schur_user : jac->pmat[1];
68: }
69: }
74: static PetscErrorCode PCView_FieldSplit(PC pc,PetscViewer viewer)
75: {
76: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
77: PetscErrorCode ierr;
78: PetscBool iascii;
79: PetscInt i,j;
80: PC_FieldSplitLink ilink = jac->head;
83: PetscTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);
84: if (iascii) {
85: PetscViewerASCIIPrintf(viewer," FieldSplit with %s composition: total splits = %D, blocksize = %D\n",PCCompositeTypes[jac->type],jac->nsplits,jac->bs);
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: PetscTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);
126: if (iascii) {
127: PetscViewerASCIIPrintf(viewer," FieldSplit with Schur preconditioner, blocksize = %D, factorization %s\n",jac->bs,PCFieldSplitSchurFactorizationTypes[jac->schurfactorization]);
128: PetscViewerASCIIPrintf(viewer," Split info:\n");
129: PetscViewerASCIIPushTab(viewer);
130: for (i=0; i<jac->nsplits; i++) {
131: if (ilink->fields) {
132: PetscViewerASCIIPrintf(viewer,"Split number %D Fields ",i);
133: PetscViewerASCIIUseTabs(viewer,PETSC_FALSE);
134: for (j=0; j<ilink->nfields; j++) {
135: if (j > 0) {
136: PetscViewerASCIIPrintf(viewer,",");
137: }
138: PetscViewerASCIIPrintf(viewer," %D",ilink->fields[j]);
139: }
140: PetscViewerASCIIPrintf(viewer,"\n");
141: PetscViewerASCIIUseTabs(viewer,PETSC_TRUE);
142: } else {
143: PetscViewerASCIIPrintf(viewer,"Split number %D Defined by IS\n",i);
144: }
145: ilink = ilink->next;
146: }
147: PetscViewerASCIIPrintf(viewer,"KSP solver for A00 block \n");
148: PetscViewerASCIIPushTab(viewer);
149: if (jac->schur) {
150: MatSchurComplementGetKSP(jac->schur,&ksp);
151: KSPView(ksp,viewer);
152: } else {
153: PetscViewerASCIIPrintf(viewer," not yet available\n");
154: }
155: PetscViewerASCIIPopTab(viewer);
156: PetscViewerASCIIPrintf(viewer,"KSP solver for S = A11 - A10 inv(A00) A01 \n");
157: PetscViewerASCIIPushTab(viewer);
158: if (jac->kspschur) {
159: KSPView(jac->kspschur,viewer);
160: } else {
161: PetscViewerASCIIPrintf(viewer," not yet available\n");
162: }
163: PetscViewerASCIIPopTab(viewer);
164: PetscViewerASCIIPopTab(viewer);
165: } else {
166: SETERRQ1(((PetscObject)pc)->comm,PETSC_ERR_SUP,"Viewer type %s not supported for PCFieldSplit",((PetscObject)viewer)->type_name);
167: }
168: return(0);
169: }
173: /* Precondition: jac->bs is set to a meaningful value */
174: static PetscErrorCode PCFieldSplitSetRuntimeSplits_Private(PC pc)
175: {
177: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
178: PetscInt i,nfields,*ifields;
179: PetscBool flg;
180: char optionname[128],splitname[8];
183: PetscMalloc(jac->bs*sizeof(PetscInt),&ifields);
184: for (i=0,flg=PETSC_TRUE; ; i++) {
185: PetscSNPrintf(splitname,sizeof splitname,"%D",i);
186: PetscSNPrintf(optionname,sizeof optionname,"-pc_fieldsplit_%D_fields",i);
187: nfields = jac->bs;
188: PetscOptionsGetIntArray(((PetscObject)pc)->prefix,optionname,ifields,&nfields,&flg);
189: if (!flg) break;
190: if (!nfields) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Cannot list zero fields");
191: PCFieldSplitSetFields(pc,splitname,nfields,ifields);
192: }
193: if (i > 0) {
194: /* Makes command-line setting of splits take precedence over setting them in code.
195: Otherwise subsequent calls to PCFieldSplitSetIS() or PCFieldSplitSetFields() would
196: create new splits, which would probably not be what the user wanted. */
197: jac->splitdefined = PETSC_TRUE;
198: }
199: PetscFree(ifields);
200: return(0);
201: }
205: static PetscErrorCode PCFieldSplitSetDefaults(PC pc)
206: {
207: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
208: PetscErrorCode ierr;
209: PC_FieldSplitLink ilink = jac->head;
210: PetscBool flg = PETSC_FALSE,stokes = PETSC_FALSE;
211: PetscInt i;
214: if (!ilink) {
215: PetscOptionsGetBool(((PetscObject)pc)->prefix,"-pc_fieldsplit_detect_saddle_point",&stokes,PETSC_NULL);
216: if (pc->dm && !stokes) {
217: PetscBool dmcomposite;
218: PetscTypeCompare((PetscObject)pc->dm,DMCOMPOSITE,&dmcomposite);
219: if (dmcomposite) {
220: PetscInt nDM;
221: IS *fields;
222: PetscInfo(pc,"Setting up physics based fieldsplit preconditioner using the embedded DM\n");
223: DMCompositeGetNumberDM(pc->dm,&nDM);
224: DMCompositeGetGlobalISs(pc->dm,&fields);
225: for (i=0; i<nDM; i++) {
226: char splitname[8];
227: PetscSNPrintf(splitname,sizeof splitname,"%D",i);
228: PCFieldSplitSetIS(pc,splitname,fields[i]);
229: ISDestroy(&fields[i]);
230: }
231: PetscFree(fields);
232: }
233: } else {
234: if (jac->bs <= 0) {
235: if (pc->pmat) {
236: MatGetBlockSize(pc->pmat,&jac->bs);
237: } else {
238: jac->bs = 1;
239: }
240: }
242: PetscOptionsGetBool(((PetscObject)pc)->prefix,"-pc_fieldsplit_default",&flg,PETSC_NULL);
243: if (stokes) {
244: IS zerodiags,rest;
245: PetscInt nmin,nmax;
247: MatGetOwnershipRange(pc->mat,&nmin,&nmax);
248: MatFindZeroDiagonals(pc->mat,&zerodiags);
249: ISComplement(zerodiags,nmin,nmax,&rest);
250: PCFieldSplitSetIS(pc,"0",rest);
251: PCFieldSplitSetIS(pc,"1",zerodiags);
252: ISDestroy(&zerodiags);
253: ISDestroy(&rest);
254: } else {
255: if (!flg) {
256: /* Allow user to set fields from command line, if bs was known at the time of PCSetFromOptions_FieldSplit()
257: then it is set there. This is not ideal because we should only have options set in XXSetFromOptions(). */
258: PCFieldSplitSetRuntimeSplits_Private(pc);
259: if (jac->splitdefined) {PetscInfo(pc,"Splits defined using the options database\n");}
260: }
261: if (flg || !jac->splitdefined) {
262: PetscInfo(pc,"Using default splitting of fields\n");
263: for (i=0; i<jac->bs; i++) {
264: char splitname[8];
265: PetscSNPrintf(splitname,sizeof splitname,"%D",i);
266: PCFieldSplitSetFields(pc,splitname,1,&i);
267: }
268: jac->defaultsplit = PETSC_TRUE;
269: }
270: }
271: }
272: } else if (jac->nsplits == 1) {
273: if (ilink->is) {
274: IS is2;
275: PetscInt nmin,nmax;
277: MatGetOwnershipRange(pc->mat,&nmin,&nmax);
278: ISComplement(ilink->is,nmin,nmax,&is2);
279: PCFieldSplitSetIS(pc,"1",is2);
280: ISDestroy(&is2);
281: } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Must provide at least two sets of fields to PCFieldSplit()");
282: } else if (jac->reset) {
283: /* PCReset() has been called on this PC, ilink exists but all IS and Vec data structures in it must be rebuilt
284: This is basically the !ilink portion of code above copied from above and the allocation of the ilinks removed
285: since they already exist. This should be totally rewritten */
286: PetscOptionsGetBool(((PetscObject)pc)->prefix,"-pc_fieldsplit_detect_saddle_point",&stokes,PETSC_NULL);
287: if (pc->dm && !stokes) {
288: PetscBool dmcomposite;
289: PetscTypeCompare((PetscObject)pc->dm,DMCOMPOSITE,&dmcomposite);
290: if (dmcomposite) {
291: PetscInt nDM;
292: IS *fields;
293: PetscInfo(pc,"Setting up physics based fieldsplit preconditioner using the embedded DM\n");
294: DMCompositeGetNumberDM(pc->dm,&nDM);
295: DMCompositeGetGlobalISs(pc->dm,&fields);
296: for (i=0; i<nDM; i++) {
297: ilink->is = fields[i];
298: ilink = ilink->next;
299: }
300: PetscFree(fields);
301: }
302: } else {
303: PetscOptionsGetBool(((PetscObject)pc)->prefix,"-pc_fieldsplit_default",&flg,PETSC_NULL);
304: if (stokes) {
305: IS zerodiags,rest;
306: PetscInt nmin,nmax;
308: MatGetOwnershipRange(pc->mat,&nmin,&nmax);
309: MatFindZeroDiagonals(pc->mat,&zerodiags);
310: ISComplement(zerodiags,nmin,nmax,&rest);
311: ISDestroy(&ilink->is);
312: ISDestroy(&ilink->next->is);
313: ilink->is = rest;
314: ilink->next->is = zerodiags;
315: } else SETERRQ(((PetscObject)pc)->comm,PETSC_ERR_SUP,"Cases not yet handled when PCReset() was used");
316: }
317: }
319: if (jac->nsplits < 2) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unhandled case, must have at least two fields");
320: return(0);
321: }
325: static PetscErrorCode PCSetUp_FieldSplit(PC pc)
326: {
327: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
328: PetscErrorCode ierr;
329: PC_FieldSplitLink ilink;
330: PetscInt i,nsplit,ccsize;
331: MatStructure flag = pc->flag;
332: PetscBool sorted;
335: PCFieldSplitSetDefaults(pc);
336: nsplit = jac->nsplits;
337: ilink = jac->head;
339: /* get the matrices for each split */
340: if (!jac->issetup) {
341: PetscInt rstart,rend,nslots,bs;
343: jac->issetup = PETSC_TRUE;
345: /* This is done here instead of in PCFieldSplitSetFields() because may not have matrix at that point */
346: bs = jac->bs;
347: MatGetOwnershipRange(pc->pmat,&rstart,&rend);
348: MatGetLocalSize(pc->pmat,PETSC_NULL,&ccsize);
349: nslots = (rend - rstart)/bs;
350: for (i=0; i<nsplit; i++) {
351: if (jac->defaultsplit) {
352: ISCreateStride(((PetscObject)pc)->comm,nslots,rstart+i,nsplit,&ilink->is);
353: } else if (!ilink->is) {
354: if (ilink->nfields > 1) {
355: PetscInt *ii,j,k,nfields = ilink->nfields,*fields = ilink->fields;
356: PetscMalloc(ilink->nfields*nslots*sizeof(PetscInt),&ii);
357: for (j=0; j<nslots; j++) {
358: for (k=0; k<nfields; k++) {
359: ii[nfields*j + k] = rstart + bs*j + fields[k];
360: }
361: }
362: ISCreateGeneral(((PetscObject)pc)->comm,nslots*nfields,ii,PETSC_OWN_POINTER,&ilink->is);
363: } else {
364: ISCreateStride(((PetscObject)pc)->comm,nslots,rstart+ilink->fields[0],bs,&ilink->is);
365: }
366: }
367: ISSorted(ilink->is,&sorted);
368: if (!sorted) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Fields must be sorted when creating split");
369: ilink = ilink->next;
370: }
371: }
372:
373: ilink = jac->head;
374: if (!jac->pmat) {
375: PetscMalloc(nsplit*sizeof(Mat),&jac->pmat);
376: for (i=0; i<nsplit; i++) {
377: MatGetSubMatrix(pc->pmat,ilink->is,ilink->is,MAT_INITIAL_MATRIX,&jac->pmat[i]);
378: ilink = ilink->next;
379: }
380: } else {
381: for (i=0; i<nsplit; i++) {
382: MatGetSubMatrix(pc->pmat,ilink->is,ilink->is,MAT_REUSE_MATRIX,&jac->pmat[i]);
383: ilink = ilink->next;
384: }
385: }
386: if (jac->realdiagonal) {
387: ilink = jac->head;
388: if (!jac->mat) {
389: PetscMalloc(nsplit*sizeof(Mat),&jac->mat);
390: for (i=0; i<nsplit; i++) {
391: MatGetSubMatrix(pc->mat,ilink->is,ilink->is,MAT_INITIAL_MATRIX,&jac->mat[i]);
392: ilink = ilink->next;
393: }
394: } else {
395: for (i=0; i<nsplit; i++) {
396: if (jac->mat[i]) {MatGetSubMatrix(pc->mat,ilink->is,ilink->is,MAT_REUSE_MATRIX,&jac->mat[i]);}
397: ilink = ilink->next;
398: }
399: }
400: } else {
401: jac->mat = jac->pmat;
402: }
404: if (jac->type != PC_COMPOSITE_ADDITIVE && jac->type != PC_COMPOSITE_SCHUR) {
405: /* extract the rows of the matrix associated with each field: used for efficient computation of residual inside algorithm */
406: ilink = jac->head;
407: if (!jac->Afield) {
408: PetscMalloc(nsplit*sizeof(Mat),&jac->Afield);
409: for (i=0; i<nsplit; i++) {
410: MatGetSubMatrix(pc->mat,ilink->is,PETSC_NULL,MAT_INITIAL_MATRIX,&jac->Afield[i]);
411: ilink = ilink->next;
412: }
413: } else {
414: for (i=0; i<nsplit; i++) {
415: MatGetSubMatrix(pc->mat,ilink->is,PETSC_NULL,MAT_REUSE_MATRIX,&jac->Afield[i]);
416: ilink = ilink->next;
417: }
418: }
419: }
421: if (jac->type == PC_COMPOSITE_SCHUR) {
422: IS ccis;
423: PetscInt rstart,rend;
424: if (nsplit != 2) SETERRQ(((PetscObject)pc)->comm,PETSC_ERR_ARG_INCOMP,"To use Schur complement preconditioner you must have exactly 2 fields");
426: /* When extracting off-diagonal submatrices, we take complements from this range */
427: MatGetOwnershipRangeColumn(pc->mat,&rstart,&rend);
429: /* need to handle case when one is resetting up the preconditioner */
430: if (jac->schur) {
431: ilink = jac->head;
432: ISComplement(ilink->is,rstart,rend,&ccis);
433: MatGetSubMatrix(pc->mat,ilink->is,ccis,MAT_REUSE_MATRIX,&jac->B);
434: ISDestroy(&ccis);
435: ilink = ilink->next;
436: ISComplement(ilink->is,rstart,rend,&ccis);
437: MatGetSubMatrix(pc->mat,ilink->is,ccis,MAT_REUSE_MATRIX,&jac->C);
438: ISDestroy(&ccis);
439: MatSchurComplementUpdate(jac->schur,jac->mat[0],jac->pmat[0],jac->B,jac->C,jac->pmat[1],pc->flag);
440: KSPSetOperators(jac->kspschur,jac->schur,FieldSplitSchurPre(jac),pc->flag);
442: } else {
443: KSP ksp;
444: char schurprefix[256];
446: /* extract the A01 and A10 matrices */
447: ilink = jac->head;
448: ISComplement(ilink->is,rstart,rend,&ccis);
449: MatGetSubMatrix(pc->mat,ilink->is,ccis,MAT_INITIAL_MATRIX,&jac->B);
450: ISDestroy(&ccis);
451: ilink = ilink->next;
452: ISComplement(ilink->is,rstart,rend,&ccis);
453: MatGetSubMatrix(pc->mat,ilink->is,ccis,MAT_INITIAL_MATRIX,&jac->C);
454: ISDestroy(&ccis);
455: /* Use mat[0] (diagonal block of the real matrix) preconditioned by pmat[0] */
456: MatCreateSchurComplement(jac->mat[0],jac->pmat[0],jac->B,jac->C,jac->mat[1],&jac->schur);
457: /* set tabbing and options prefix of KSP inside the MatSchur */
458: MatSchurComplementGetKSP(jac->schur,&ksp);
459: PetscObjectIncrementTabLevel((PetscObject)ksp,(PetscObject)pc,2);
460: PetscSNPrintf(schurprefix,sizeof schurprefix,"%sfieldsplit_%s_",((PetscObject)pc)->prefix?((PetscObject)pc)->prefix:"",jac->head->splitname);
461: KSPSetOptionsPrefix(ksp,schurprefix);
462: /* Need to call this everytime because new matrix is being created */
463: MatSetFromOptions(jac->schur);
465: KSPCreate(((PetscObject)pc)->comm,&jac->kspschur);
466: PetscLogObjectParent((PetscObject)pc,(PetscObject)jac->kspschur);
467: PetscObjectIncrementTabLevel((PetscObject)jac->kspschur,(PetscObject)pc,1);
468: KSPSetOperators(jac->kspschur,jac->schur,FieldSplitSchurPre(jac),DIFFERENT_NONZERO_PATTERN);
469: if (jac->schurpre == PC_FIELDSPLIT_SCHUR_PRE_SELF) {
470: PC pc;
471: KSPGetPC(jac->kspschur,&pc);
472: PCSetType(pc,PCNONE);
473: /* Note: This is bad if there exist preconditioners for MATSCHURCOMPLEMENT */
474: }
475: PetscSNPrintf(schurprefix,sizeof schurprefix,"%sfieldsplit_%s_",((PetscObject)pc)->prefix?((PetscObject)pc)->prefix:"",ilink->splitname);
476: KSPSetOptionsPrefix(jac->kspschur,schurprefix);
477: /* really want setfromoptions called in PCSetFromOptions_FieldSplit(), but it is not ready yet */
478: /* need to call this every time, since the jac->kspschur is freshly created, otherwise its options never get set */
479: KSPSetFromOptions(jac->kspschur);
481: PetscMalloc2(2,Vec,&jac->x,2,Vec,&jac->y);
482: MatGetVecs(jac->pmat[0],&jac->x[0],&jac->y[0]);
483: MatGetVecs(jac->pmat[1],&jac->x[1],&jac->y[1]);
484: ilink = jac->head;
485: ilink->x = jac->x[0]; ilink->y = jac->y[0];
486: ilink = ilink->next;
487: ilink->x = jac->x[1]; ilink->y = jac->y[1];
488: }
489: } else {
490: /* set up the individual PCs */
491: i = 0;
492: ilink = jac->head;
493: while (ilink) {
494: KSPSetOperators(ilink->ksp,jac->mat[i],jac->pmat[i],flag);
495: /* really want setfromoptions called in PCSetFromOptions_FieldSplit(), but it is not ready yet */
496: if (!jac->suboptionsset) {KSPSetFromOptions(ilink->ksp);}
497: KSPSetUp(ilink->ksp);
498: i++;
499: ilink = ilink->next;
500: }
501:
502: /* create work vectors for each split */
503: if (!jac->x) {
504: PetscMalloc2(nsplit,Vec,&jac->x,nsplit,Vec,&jac->y);
505: ilink = jac->head;
506: for (i=0; i<nsplit; i++) {
507: Vec *vl,*vr;
509: KSPGetVecs(ilink->ksp,1,&vr,1,&vl);
510: ilink->x = *vr;
511: ilink->y = *vl;
512: PetscFree(vr);
513: PetscFree(vl);
514: jac->x[i] = ilink->x;
515: jac->y[i] = ilink->y;
516: ilink = ilink->next;
517: }
518: }
519: }
522: if (!jac->head->sctx) {
523: Vec xtmp;
525: /* compute scatter contexts needed by multiplicative versions and non-default splits */
526:
527: ilink = jac->head;
528: MatGetVecs(pc->pmat,&xtmp,PETSC_NULL);
529: for (i=0; i<nsplit; i++) {
530: VecScatterCreate(xtmp,ilink->is,jac->x[i],PETSC_NULL,&ilink->sctx);
531: ilink = ilink->next;
532: }
533: VecDestroy(&xtmp);
534: }
535: jac->suboptionsset = PETSC_TRUE;
536: return(0);
537: }
539: #define FieldSplitSplitSolveAdd(ilink,xx,yy) \
540: (VecScatterBegin(ilink->sctx,xx,ilink->x,INSERT_VALUES,SCATTER_FORWARD) || \
541: VecScatterEnd(ilink->sctx,xx,ilink->x,INSERT_VALUES,SCATTER_FORWARD) || \
542: KSPSolve(ilink->ksp,ilink->x,ilink->y) || \
543: VecScatterBegin(ilink->sctx,ilink->y,yy,ADD_VALUES,SCATTER_REVERSE) || \
544: VecScatterEnd(ilink->sctx,ilink->y,yy,ADD_VALUES,SCATTER_REVERSE))
548: static PetscErrorCode PCApply_FieldSplit_Schur(PC pc,Vec x,Vec y)
549: {
550: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
551: PetscErrorCode ierr;
552: KSP ksp;
553: PC_FieldSplitLink ilinkA = jac->head, ilinkD = ilinkA->next;
556: MatSchurComplementGetKSP(jac->schur,&ksp);
558: switch (jac->schurfactorization) {
559: case PC_FIELDSPLIT_SCHUR_FACTORIZATION_DIAG:
560: /* [A00 0; 0 -S], positive definite, suitable for MINRES */
561: VecScatterBegin(ilinkA->sctx,x,ilinkA->x,INSERT_VALUES,SCATTER_FORWARD);
562: VecScatterBegin(ilinkD->sctx,x,ilinkD->x,INSERT_VALUES,SCATTER_FORWARD);
563: VecScatterEnd(ilinkA->sctx,x,ilinkA->x,INSERT_VALUES,SCATTER_FORWARD);
564: KSPSolve(ksp,ilinkA->x,ilinkA->y);
565: VecScatterBegin(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);
566: VecScatterEnd(ilinkD->sctx,x,ilinkD->x,INSERT_VALUES,SCATTER_FORWARD);
567: KSPSolve(jac->kspschur,ilinkD->x,ilinkD->y);
568: VecScale(ilinkD->y,-1.);
569: VecScatterBegin(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);
570: VecScatterEnd(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);
571: VecScatterEnd(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);
572: break;
573: case PC_FIELDSPLIT_SCHUR_FACTORIZATION_LOWER:
574: /* [A00 0; A10 S], suitable for left preconditioning */
575: VecScatterBegin(ilinkA->sctx,x,ilinkA->x,INSERT_VALUES,SCATTER_FORWARD);
576: VecScatterEnd(ilinkA->sctx,x,ilinkA->x,INSERT_VALUES,SCATTER_FORWARD);
577: KSPSolve(ksp,ilinkA->x,ilinkA->y);
578: MatMult(jac->C,ilinkA->y,ilinkD->x);
579: VecScale(ilinkD->x,-1.);
580: VecScatterBegin(ilinkD->sctx,x,ilinkD->x,ADD_VALUES,SCATTER_FORWARD);
581: VecScatterBegin(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);
582: VecScatterEnd(ilinkD->sctx,x,ilinkD->x,ADD_VALUES,SCATTER_FORWARD);
583: KSPSolve(jac->kspschur,ilinkD->x,ilinkD->y);
584: VecScatterBegin(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);
585: VecScatterEnd(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);
586: VecScatterEnd(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);
587: break;
588: case PC_FIELDSPLIT_SCHUR_FACTORIZATION_UPPER:
589: /* [A00 A01; 0 S], suitable for right preconditioning */
590: VecScatterBegin(ilinkD->sctx,x,ilinkD->x,INSERT_VALUES,SCATTER_FORWARD);
591: VecScatterEnd(ilinkD->sctx,x,ilinkD->x,INSERT_VALUES,SCATTER_FORWARD);
592: KSPSolve(jac->kspschur,ilinkD->x,ilinkD->y);
593: MatMult(jac->B,ilinkD->y,ilinkA->x);
594: VecScale(ilinkA->x,-1.);
595: VecScatterBegin(ilinkA->sctx,x,ilinkA->x,ADD_VALUES,SCATTER_FORWARD);
596: VecScatterBegin(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);
597: VecScatterEnd(ilinkA->sctx,x,ilinkA->x,ADD_VALUES,SCATTER_FORWARD);
598: KSPSolve(ksp,ilinkA->x,ilinkA->y);
599: VecScatterBegin(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);
600: VecScatterEnd(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);
601: VecScatterEnd(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);
602: break;
603: case PC_FIELDSPLIT_SCHUR_FACTORIZATION_FULL:
604: /* [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 */
605: VecScatterBegin(ilinkA->sctx,x,ilinkA->x,INSERT_VALUES,SCATTER_FORWARD);
606: VecScatterEnd(ilinkA->sctx,x,ilinkA->x,INSERT_VALUES,SCATTER_FORWARD);
607: KSPSolve(ksp,ilinkA->x,ilinkA->y);
608: MatMult(jac->C,ilinkA->y,ilinkD->x);
609: VecScale(ilinkD->x,-1.0);
610: VecScatterBegin(ilinkD->sctx,x,ilinkD->x,ADD_VALUES,SCATTER_FORWARD);
611: VecScatterEnd(ilinkD->sctx,x,ilinkD->x,ADD_VALUES,SCATTER_FORWARD);
613: KSPSolve(jac->kspschur,ilinkD->x,ilinkD->y);
614: VecScatterBegin(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);
615: VecScatterEnd(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);
617: MatMult(jac->B,ilinkD->y,ilinkA->y);
618: VecAXPY(ilinkA->x,-1.0,ilinkA->y);
619: KSPSolve(ksp,ilinkA->x,ilinkA->y);
620: VecScatterBegin(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);
621: VecScatterEnd(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);
622: }
623: return(0);
624: }
628: static PetscErrorCode PCApply_FieldSplit(PC pc,Vec x,Vec y)
629: {
630: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
631: PetscErrorCode ierr;
632: PC_FieldSplitLink ilink = jac->head;
633: PetscInt cnt;
636: CHKMEMQ;
637: VecSetBlockSize(x,jac->bs);
638: VecSetBlockSize(y,jac->bs);
640: if (jac->type == PC_COMPOSITE_ADDITIVE) {
641: if (jac->defaultsplit) {
642: VecStrideGatherAll(x,jac->x,INSERT_VALUES);
643: while (ilink) {
644: KSPSolve(ilink->ksp,ilink->x,ilink->y);
645: ilink = ilink->next;
646: }
647: VecStrideScatterAll(jac->y,y,INSERT_VALUES);
648: } else {
649: VecSet(y,0.0);
650: while (ilink) {
651: FieldSplitSplitSolveAdd(ilink,x,y);
652: ilink = ilink->next;
653: }
654: }
655: } else if (jac->type == PC_COMPOSITE_MULTIPLICATIVE || jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
656: if (!jac->w1) {
657: VecDuplicate(x,&jac->w1);
658: VecDuplicate(x,&jac->w2);
659: }
660: VecSet(y,0.0);
661: FieldSplitSplitSolveAdd(ilink,x,y);
662: cnt = 1;
663: while (ilink->next) {
664: ilink = ilink->next;
665: /* compute the residual only over the part of the vector needed */
666: MatMult(jac->Afield[cnt++],y,ilink->x);
667: VecScale(ilink->x,-1.0);
668: VecScatterBegin(ilink->sctx,x,ilink->x,ADD_VALUES,SCATTER_FORWARD);
669: VecScatterEnd(ilink->sctx,x,ilink->x,ADD_VALUES,SCATTER_FORWARD);
670: KSPSolve(ilink->ksp,ilink->x,ilink->y);
671: VecScatterBegin(ilink->sctx,ilink->y,y,ADD_VALUES,SCATTER_REVERSE);
672: VecScatterEnd(ilink->sctx,ilink->y,y,ADD_VALUES,SCATTER_REVERSE);
673: }
674: if (jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
675: cnt -= 2;
676: while (ilink->previous) {
677: ilink = ilink->previous;
678: /* compute the residual only over the part of the vector needed */
679: MatMult(jac->Afield[cnt--],y,ilink->x);
680: VecScale(ilink->x,-1.0);
681: VecScatterBegin(ilink->sctx,x,ilink->x,ADD_VALUES,SCATTER_FORWARD);
682: VecScatterEnd(ilink->sctx,x,ilink->x,ADD_VALUES,SCATTER_FORWARD);
683: KSPSolve(ilink->ksp,ilink->x,ilink->y);
684: VecScatterBegin(ilink->sctx,ilink->y,y,ADD_VALUES,SCATTER_REVERSE);
685: VecScatterEnd(ilink->sctx,ilink->y,y,ADD_VALUES,SCATTER_REVERSE);
686: }
687: }
688: } else SETERRQ1(((PetscObject)pc)->comm,PETSC_ERR_SUP,"Unsupported or unknown composition",(int) jac->type);
689: CHKMEMQ;
690: return(0);
691: }
693: #define FieldSplitSplitSolveAddTranspose(ilink,xx,yy) \
694: (VecScatterBegin(ilink->sctx,xx,ilink->y,INSERT_VALUES,SCATTER_FORWARD) || \
695: VecScatterEnd(ilink->sctx,xx,ilink->y,INSERT_VALUES,SCATTER_FORWARD) || \
696: KSPSolveTranspose(ilink->ksp,ilink->y,ilink->x) || \
697: VecScatterBegin(ilink->sctx,ilink->x,yy,ADD_VALUES,SCATTER_REVERSE) || \
698: VecScatterEnd(ilink->sctx,ilink->x,yy,ADD_VALUES,SCATTER_REVERSE))
702: static PetscErrorCode PCApplyTranspose_FieldSplit(PC pc,Vec x,Vec y)
703: {
704: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
705: PetscErrorCode ierr;
706: PC_FieldSplitLink ilink = jac->head;
709: CHKMEMQ;
710: VecSetBlockSize(x,jac->bs);
711: VecSetBlockSize(y,jac->bs);
713: if (jac->type == PC_COMPOSITE_ADDITIVE) {
714: if (jac->defaultsplit) {
715: VecStrideGatherAll(x,jac->x,INSERT_VALUES);
716: while (ilink) {
717: KSPSolveTranspose(ilink->ksp,ilink->x,ilink->y);
718: ilink = ilink->next;
719: }
720: VecStrideScatterAll(jac->y,y,INSERT_VALUES);
721: } else {
722: VecSet(y,0.0);
723: while (ilink) {
724: FieldSplitSplitSolveAddTranspose(ilink,x,y);
725: ilink = ilink->next;
726: }
727: }
728: } else {
729: if (!jac->w1) {
730: VecDuplicate(x,&jac->w1);
731: VecDuplicate(x,&jac->w2);
732: }
733: VecSet(y,0.0);
734: if (jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
735: FieldSplitSplitSolveAddTranspose(ilink,x,y);
736: while (ilink->next) {
737: ilink = ilink->next;
738: MatMultTranspose(pc->mat,y,jac->w1);
739: VecWAXPY(jac->w2,-1.0,jac->w1,x);
740: FieldSplitSplitSolveAddTranspose(ilink,jac->w2,y);
741: }
742: while (ilink->previous) {
743: ilink = ilink->previous;
744: MatMultTranspose(pc->mat,y,jac->w1);
745: VecWAXPY(jac->w2,-1.0,jac->w1,x);
746: FieldSplitSplitSolveAddTranspose(ilink,jac->w2,y);
747: }
748: } else {
749: while (ilink->next) { /* get to last entry in linked list */
750: ilink = ilink->next;
751: }
752: FieldSplitSplitSolveAddTranspose(ilink,x,y);
753: while (ilink->previous) {
754: ilink = ilink->previous;
755: MatMultTranspose(pc->mat,y,jac->w1);
756: VecWAXPY(jac->w2,-1.0,jac->w1,x);
757: FieldSplitSplitSolveAddTranspose(ilink,jac->w2,y);
758: }
759: }
760: }
761: CHKMEMQ;
762: return(0);
763: }
767: static PetscErrorCode PCReset_FieldSplit(PC pc)
768: {
769: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
770: PetscErrorCode ierr;
771: PC_FieldSplitLink ilink = jac->head,next;
774: while (ilink) {
775: KSPReset(ilink->ksp);
776: VecDestroy(&ilink->x);
777: VecDestroy(&ilink->y);
778: VecScatterDestroy(&ilink->sctx);
779: ISDestroy(&ilink->is);
780: next = ilink->next;
781: ilink = next;
782: }
783: PetscFree2(jac->x,jac->y);
784: if (jac->mat && jac->mat != jac->pmat) {
785: MatDestroyMatrices(jac->nsplits,&jac->mat);
786: } else if (jac->mat) {
787: jac->mat = PETSC_NULL;
788: }
789: if (jac->pmat) {MatDestroyMatrices(jac->nsplits,&jac->pmat);}
790: if (jac->Afield) {MatDestroyMatrices(jac->nsplits,&jac->Afield);}
791: VecDestroy(&jac->w1);
792: VecDestroy(&jac->w2);
793: MatDestroy(&jac->schur);
794: MatDestroy(&jac->schur_user);
795: KSPDestroy(&jac->kspschur);
796: MatDestroy(&jac->B);
797: MatDestroy(&jac->C);
798: jac->reset = PETSC_TRUE;
799: return(0);
800: }
804: static PetscErrorCode PCDestroy_FieldSplit(PC pc)
805: {
806: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
807: PetscErrorCode ierr;
808: PC_FieldSplitLink ilink = jac->head,next;
811: PCReset_FieldSplit(pc);
812: while (ilink) {
813: KSPDestroy(&ilink->ksp);
814: next = ilink->next;
815: PetscFree(ilink->splitname);
816: PetscFree(ilink->fields);
817: PetscFree(ilink);
818: ilink = next;
819: }
820: PetscFree2(jac->x,jac->y);
821: PetscFree(pc->data);
822: return(0);
823: }
827: static PetscErrorCode PCSetFromOptions_FieldSplit(PC pc)
828: {
829: PetscErrorCode ierr;
830: PetscInt bs;
831: PetscBool flg,stokes = PETSC_FALSE;
832: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
833: PCCompositeType ctype;
836: PetscOptionsHead("FieldSplit options");
837: PetscOptionsBool("-pc_fieldsplit_real_diagonal","Use diagonal blocks of the operator","PCFieldSplitSetRealDiagonal",jac->realdiagonal,&jac->realdiagonal,PETSC_NULL);
838: PetscOptionsInt("-pc_fieldsplit_block_size","Blocksize that defines number of fields","PCFieldSplitSetBlockSize",jac->bs,&bs,&flg);
839: if (flg) {
840: PCFieldSplitSetBlockSize(pc,bs);
841: }
843: PetscOptionsGetBool(((PetscObject)pc)->prefix,"-pc_fieldsplit_detect_saddle_point",&stokes,PETSC_NULL);
844: if (stokes) {
845: PCFieldSplitSetType(pc,PC_COMPOSITE_SCHUR);
846: jac->schurpre = PC_FIELDSPLIT_SCHUR_PRE_SELF;
847: }
849: PetscOptionsEnum("-pc_fieldsplit_type","Type of composition","PCFieldSplitSetType",PCCompositeTypes,(PetscEnum)jac->type,(PetscEnum*)&ctype,&flg);
850: if (flg) {
851: PCFieldSplitSetType(pc,ctype);
852: }
854: /* Only setup fields once */
855: if ((jac->bs > 0) && (jac->nsplits == 0)) {
856: /* only allow user to set fields from command line if bs is already known.
857: otherwise user can set them in PCFieldSplitSetDefaults() */
858: PCFieldSplitSetRuntimeSplits_Private(pc);
859: if (jac->splitdefined) {PetscInfo(pc,"Splits defined using the options database\n");}
860: }
861: if (jac->type == PC_COMPOSITE_SCHUR) {
862: PetscOptionsEnum("-pc_fieldsplit_schur_factorization_type","Factorization to use","None",PCFieldSplitSchurFactorizationTypes,(PetscEnum)jac->schurfactorization,(PetscEnum*)&jac->schurfactorization,PETSC_NULL);
863: PetscOptionsEnum("-pc_fieldsplit_schur_precondition","How to build preconditioner for Schur complement","PCFieldSplitSchurPrecondition",PCFieldSplitSchurPreTypes,(PetscEnum)jac->schurpre,(PetscEnum*)&jac->schurpre,PETSC_NULL);
864: }
865: PetscOptionsTail();
866: return(0);
867: }
869: /*------------------------------------------------------------------------------------*/
874: PetscErrorCode PCFieldSplitSetFields_FieldSplit(PC pc,const char splitname[],PetscInt n,const PetscInt *fields)
875: {
876: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
877: PetscErrorCode ierr;
878: PC_FieldSplitLink ilink,next = jac->head;
879: char prefix[128];
880: PetscInt i;
883: if (jac->splitdefined) {
884: PetscInfo1(pc,"Ignoring new split \"%s\" because the splits have already been defined\n",splitname);
885: return(0);
886: }
887: for (i=0; i<n; i++) {
888: if (fields[i] >= jac->bs) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Field %D requested but only %D exist",fields[i],jac->bs);
889: if (fields[i] < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Negative field %D requested",fields[i]);
890: }
891: PetscNew(struct _PC_FieldSplitLink,&ilink);
892: if (splitname) {
893: PetscStrallocpy(splitname,&ilink->splitname);
894: } else {
895: PetscMalloc(3*sizeof(char),&ilink->splitname);
896: PetscSNPrintf(ilink->splitname,2,"%s",jac->nsplits);
897: }
898: PetscMalloc(n*sizeof(PetscInt),&ilink->fields);
899: PetscMemcpy(ilink->fields,fields,n*sizeof(PetscInt));
900: ilink->nfields = n;
901: ilink->next = PETSC_NULL;
902: KSPCreate(((PetscObject)pc)->comm,&ilink->ksp);
903: PetscObjectIncrementTabLevel((PetscObject)ilink->ksp,(PetscObject)pc,1);
904: KSPSetType(ilink->ksp,KSPPREONLY);
905: PetscLogObjectParent((PetscObject)pc,(PetscObject)ilink->ksp);
907: PetscSNPrintf(prefix,sizeof prefix,"%sfieldsplit_%s_",((PetscObject)pc)->prefix?((PetscObject)pc)->prefix:"",ilink->splitname);
908: KSPSetOptionsPrefix(ilink->ksp,prefix);
910: if (!next) {
911: jac->head = ilink;
912: ilink->previous = PETSC_NULL;
913: } else {
914: while (next->next) {
915: next = next->next;
916: }
917: next->next = ilink;
918: ilink->previous = next;
919: }
920: jac->nsplits++;
921: return(0);
922: }
928: PetscErrorCode PCFieldSplitGetSubKSP_FieldSplit_Schur(PC pc,PetscInt *n,KSP **subksp)
929: {
930: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
934: PetscMalloc(jac->nsplits*sizeof(KSP),subksp);
935: MatSchurComplementGetKSP(jac->schur,*subksp);
936: (*subksp)[1] = jac->kspschur;
937: if (n) *n = jac->nsplits;
938: return(0);
939: }
945: PetscErrorCode PCFieldSplitGetSubKSP_FieldSplit(PC pc,PetscInt *n,KSP **subksp)
946: {
947: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
948: PetscErrorCode ierr;
949: PetscInt cnt = 0;
950: PC_FieldSplitLink ilink = jac->head;
953: PetscMalloc(jac->nsplits*sizeof(KSP),subksp);
954: while (ilink) {
955: (*subksp)[cnt++] = ilink->ksp;
956: ilink = ilink->next;
957: }
958: 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);
959: if (n) *n = jac->nsplits;
960: return(0);
961: }
967: PetscErrorCode PCFieldSplitSetIS_FieldSplit(PC pc,const char splitname[],IS is)
968: {
969: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
970: PetscErrorCode ierr;
971: PC_FieldSplitLink ilink, next = jac->head;
972: char prefix[128];
975: if (jac->splitdefined) {
976: PetscInfo1(pc,"Ignoring new split \"%s\" because the splits have already been defined\n",splitname);
977: return(0);
978: }
979: PetscNew(struct _PC_FieldSplitLink,&ilink);
980: if (splitname) {
981: PetscStrallocpy(splitname,&ilink->splitname);
982: } else {
983: PetscMalloc(3*sizeof(char),&ilink->splitname);
984: PetscSNPrintf(ilink->splitname,2,"%s",jac->nsplits);
985: }
986: ilink->is = is;
987: PetscObjectReference((PetscObject)is);
988: ilink->next = PETSC_NULL;
989: KSPCreate(((PetscObject)pc)->comm,&ilink->ksp);
990: PetscObjectIncrementTabLevel((PetscObject)ilink->ksp,(PetscObject)pc,1);
991: KSPSetType(ilink->ksp,KSPPREONLY);
992: PetscLogObjectParent((PetscObject)pc,(PetscObject)ilink->ksp);
994: PetscSNPrintf(prefix,sizeof prefix,"%sfieldsplit_%s_",((PetscObject)pc)->prefix?((PetscObject)pc)->prefix:"",ilink->splitname);
995: KSPSetOptionsPrefix(ilink->ksp,prefix);
997: if (!next) {
998: jac->head = ilink;
999: ilink->previous = PETSC_NULL;
1000: } else {
1001: while (next->next) {
1002: next = next->next;
1003: }
1004: next->next = ilink;
1005: ilink->previous = next;
1006: }
1007: jac->nsplits++;
1009: return(0);
1010: }
1015: /*@
1016: PCFieldSplitSetFields - Sets the fields for one particular split in the field split preconditioner
1018: Logically Collective on PC
1020: Input Parameters:
1021: + pc - the preconditioner context
1022: . splitname - name of this split, if PETSC_NULL the number of the split is used
1023: . n - the number of fields in this split
1024: - fields - the fields in this split
1026: Level: intermediate
1028: Notes: Use PCFieldSplitSetIS() to set a completely general set of indices as a field.
1030: The PCFieldSplitSetFields() is for defining fields as a strided blocks. For example, if the block
1031: 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
1032: 0xx3xx6xx9xx12 ... x1xx4xx7xx ... xx2xx5xx8xx.. 01x34x67x... 0x1x3x5x7.. x12x45x78x....
1033: where the numbered entries indicate what is in the field.
1035: This function is called once per split (it creates a new split each time). Solve options
1036: for this split will be available under the prefix -fieldsplit_SPLITNAME_.
1038: .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetBlockSize(), PCFieldSplitSetIS()
1040: @*/
1041: PetscErrorCode PCFieldSplitSetFields(PC pc,const char splitname[],PetscInt n,const PetscInt *fields)
1042: {
1048: if (n < 1) SETERRQ2(((PetscObject)pc)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Provided number of fields %D in split \"%s\" not positive",n,splitname);
1050: PetscTryMethod(pc,"PCFieldSplitSetFields_C",(PC,const char[],PetscInt,const PetscInt *),(pc,splitname,n,fields));
1051: return(0);
1052: }
1056: /*@
1057: PCFieldSplitSetIS - Sets the exact elements for field
1059: Logically Collective on PC
1061: Input Parameters:
1062: + pc - the preconditioner context
1063: . splitname - name of this split, if PETSC_NULL the number of the split is used
1064: - is - the index set that defines the vector elements in this field
1067: Notes:
1068: Use PCFieldSplitSetFields(), for fields defined by strided types.
1070: This function is called once per split (it creates a new split each time). Solve options
1071: for this split will be available under the prefix -fieldsplit_SPLITNAME_.
1073: Level: intermediate
1075: .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetBlockSize()
1077: @*/
1078: PetscErrorCode PCFieldSplitSetIS(PC pc,const char splitname[],IS is)
1079: {
1086: PetscTryMethod(pc,"PCFieldSplitSetIS_C",(PC,const char[],IS),(pc,splitname,is));
1087: return(0);
1088: }
1092: /*@
1093: PCFieldSplitGetIS - Retrieves the elements for a field as an IS
1095: Logically Collective on PC
1097: Input Parameters:
1098: + pc - the preconditioner context
1099: - splitname - name of this split
1101: Output Parameter:
1102: - is - the index set that defines the vector elements in this field, or PETSC_NULL if the field is not found
1104: Level: intermediate
1106: .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetIS()
1108: @*/
1109: PetscErrorCode PCFieldSplitGetIS(PC pc,const char splitname[],IS *is)
1110: {
1117: {
1118: PC_FieldSplit *jac = (PC_FieldSplit *) pc->data;
1119: PC_FieldSplitLink ilink = jac->head;
1120: PetscBool found;
1122: *is = PETSC_NULL;
1123: while(ilink) {
1124: PetscStrcmp(ilink->splitname, splitname, &found);
1125: if (found) {
1126: *is = ilink->is;
1127: break;
1128: }
1129: ilink = ilink->next;
1130: }
1131: }
1132: return(0);
1133: }
1137: /*@
1138: PCFieldSplitSetBlockSize - Sets the block size for defining where fields start in the
1139: fieldsplit preconditioner. If not set the matrix block size is used.
1141: Logically Collective on PC
1143: Input Parameters:
1144: + pc - the preconditioner context
1145: - bs - the block size
1147: Level: intermediate
1149: .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetFields()
1151: @*/
1152: PetscErrorCode PCFieldSplitSetBlockSize(PC pc,PetscInt bs)
1153: {
1159: PetscTryMethod(pc,"PCFieldSplitSetBlockSize_C",(PC,PetscInt),(pc,bs));
1160: return(0);
1161: }
1165: /*@C
1166: PCFieldSplitGetSubKSP - Gets the KSP contexts for all splits
1167:
1168: Collective on KSP
1170: Input Parameter:
1171: . pc - the preconditioner context
1173: Output Parameters:
1174: + n - the number of splits
1175: - pc - the array of KSP contexts
1177: Note:
1178: After PCFieldSplitGetSubKSP() the array of KSPs IS to be freed by the user
1179: (not the KSP just the array that contains them).
1181: You must call KSPSetUp() before calling PCFieldSplitGetSubKSP().
1183: Level: advanced
1185: .seealso: PCFIELDSPLIT
1186: @*/
1187: PetscErrorCode PCFieldSplitGetSubKSP(PC pc,PetscInt *n,KSP *subksp[])
1188: {
1194: PetscUseMethod(pc,"PCFieldSplitGetSubKSP_C",(PC,PetscInt*,KSP **),(pc,n,subksp));
1195: return(0);
1196: }
1200: /*@
1201: PCFieldSplitSchurPrecondition - Indicates if the Schur complement is preconditioned by a preconditioner constructed by the
1202: A11 matrix. Otherwise no preconditioner is used.
1204: Collective on PC
1206: Input Parameters:
1207: + pc - the preconditioner context
1208: . ptype - which matrix to use for preconditioning the Schur complement, PC_FIELDSPLIT_SCHUR_PRE_DIAG (diag) is default
1209: - userpre - matrix to use for preconditioning, or PETSC_NULL
1211: Options Database:
1212: . -pc_fieldsplit_schur_precondition <self,user,diag> default is diag
1214: Notes:
1215: $ If ptype is
1216: $ user then the preconditioner for the Schur complement is generated by the provided matrix (pre argument
1217: $ to this function).
1218: $ diag then the preconditioner for the Schur complement is generated by the block diagonal part of the original
1219: $ matrix associated with the Schur complement (i.e. A11)
1220: $ self the preconditioner for the Schur complement is generated from the Schur complement matrix itself:
1221: $ The only preconditioner that currently works directly with the Schur complement matrix object is the PCLSC
1222: $ preconditioner
1224: When solving a saddle point problem, where the A11 block is identically zero, using diag as the ptype only makes sense
1225: with the additional option -fieldsplit_1_pc_type none. Usually for saddle point problems one would use a ptype of self and
1226: -fieldsplit_1_pc_type lsc which uses the least squares commutator compute a preconditioner for the Schur complement.
1227:
1228: Developer Notes: This is a terrible name, gives no good indication of what the function does and should also have Set in
1229: the name since it sets a proceedure to use.
1230:
1231: Level: intermediate
1233: .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetFields(), PCFieldSplitSchurPreType, PCLSC
1235: @*/
1236: PetscErrorCode PCFieldSplitSchurPrecondition(PC pc,PCFieldSplitSchurPreType ptype,Mat pre)
1237: {
1242: PetscTryMethod(pc,"PCFieldSplitSchurPrecondition_C",(PC,PCFieldSplitSchurPreType,Mat),(pc,ptype,pre));
1243: return(0);
1244: }
1249: PetscErrorCode PCFieldSplitSchurPrecondition_FieldSplit(PC pc,PCFieldSplitSchurPreType ptype,Mat pre)
1250: {
1251: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
1252: PetscErrorCode ierr;
1255: jac->schurpre = ptype;
1256: if (pre) {
1257: MatDestroy(&jac->schur_user);
1258: jac->schur_user = pre;
1259: PetscObjectReference((PetscObject)jac->schur_user);
1260: }
1261: return(0);
1262: }
1267: /*@C
1268: PCFieldSplitGetSchurBlocks - Gets all matrix blocks for the Schur complement
1269:
1270: Collective on KSP
1272: Input Parameter:
1273: . pc - the preconditioner context
1275: Output Parameters:
1276: + A00 - the (0,0) block
1277: . A01 - the (0,1) block
1278: . A10 - the (1,0) block
1279: - A11 - the (1,1) block
1281: Level: advanced
1283: .seealso: PCFIELDSPLIT
1284: @*/
1285: PetscErrorCode PCFieldSplitGetSchurBlocks(PC pc,Mat *A00,Mat *A01,Mat *A10, Mat *A11)
1286: {
1287: PC_FieldSplit *jac = (PC_FieldSplit *) pc->data;
1291: if (jac->type != PC_COMPOSITE_SCHUR) SETERRQ(((PetscObject)pc)->comm,PETSC_ERR_ARG_WRONG, "FieldSplit is not using a Schur complement approach.");
1292: if (A00) *A00 = jac->pmat[0];
1293: if (A01) *A01 = jac->B;
1294: if (A10) *A10 = jac->C;
1295: if (A11) *A11 = jac->pmat[1];
1296: return(0);
1297: }
1302: PetscErrorCode PCFieldSplitSetType_FieldSplit(PC pc,PCCompositeType type)
1303: {
1304: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
1308: jac->type = type;
1309: if (type == PC_COMPOSITE_SCHUR) {
1310: pc->ops->apply = PCApply_FieldSplit_Schur;
1311: pc->ops->view = PCView_FieldSplit_Schur;
1312: PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitGetSubKSP_C","PCFieldSplitGetSubKSP_FieldSplit_Schur",PCFieldSplitGetSubKSP_FieldSplit_Schur);
1313: PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSchurPrecondition_C","PCFieldSplitSchurPrecondition_FieldSplit",PCFieldSplitSchurPrecondition_FieldSplit);
1315: } else {
1316: pc->ops->apply = PCApply_FieldSplit;
1317: pc->ops->view = PCView_FieldSplit;
1318: PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitGetSubKSP_C","PCFieldSplitGetSubKSP_FieldSplit",PCFieldSplitGetSubKSP_FieldSplit);
1319: PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSchurPrecondition_C","",0);
1320: }
1321: return(0);
1322: }
1328: PetscErrorCode PCFieldSplitSetBlockSize_FieldSplit(PC pc,PetscInt bs)
1329: {
1330: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
1333: if (bs < 1) SETERRQ1(((PetscObject)pc)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Blocksize must be positive, you gave %D",bs);
1334: 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);
1335: jac->bs = bs;
1336: return(0);
1337: }
1342: /*@
1343: PCFieldSplitSetType - Sets the type of fieldsplit preconditioner.
1344:
1345: Collective on PC
1347: Input Parameter:
1348: . pc - the preconditioner context
1349: . type - PC_COMPOSITE_ADDITIVE, PC_COMPOSITE_MULTIPLICATIVE (default), PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE, PC_COMPOSITE_SPECIAL, PC_COMPOSITE_SCHUR
1351: Options Database Key:
1352: . -pc_fieldsplit_type <type: one of multiplicative, additive, symmetric_multiplicative, special, schur> - Sets fieldsplit preconditioner type
1354: Level: Developer
1356: .keywords: PC, set, type, composite preconditioner, additive, multiplicative
1358: .seealso: PCCompositeSetType()
1360: @*/
1361: PetscErrorCode PCFieldSplitSetType(PC pc,PCCompositeType type)
1362: {
1367: PetscTryMethod(pc,"PCFieldSplitSetType_C",(PC,PCCompositeType),(pc,type));
1368: return(0);
1369: }
1371: /* -------------------------------------------------------------------------------------*/
1372: /*MC
1373: PCFIELDSPLIT - Preconditioner created by combining separate preconditioners for individual
1374: fields or groups of fields. See the users manual section "Solving Block Matrices" for more details.
1376: To set options on the solvers for each block append -fieldsplit_ to all the PC
1377: options database keys. For example, -fieldsplit_pc_type ilu -fieldsplit_pc_factor_levels 1
1378:
1379: To set the options on the solvers separate for each block call PCFieldSplitGetSubKSP()
1380: and set the options directly on the resulting KSP object
1382: Level: intermediate
1384: Options Database Keys:
1385: + -pc_fieldsplit_%d_fields <a,b,..> - indicates the fields to be used in the %d'th split
1386: . -pc_fieldsplit_default - automatically add any fields to additional splits that have not
1387: been supplied explicitly by -pc_fieldsplit_%d_fields
1388: . -pc_fieldsplit_block_size <bs> - size of block that defines fields (i.e. there are bs fields)
1389: . -pc_fieldsplit_type <additive,multiplicative,schur,symmetric_multiplicative>
1390: . -pc_fieldsplit_schur_precondition <true,false> default is true
1391: . -pc_fieldsplit_detect_saddle_point - automatically finds rows with zero or negative diagonal and uses Schur complement with no preconditioner as the solver
1393: - Options prefix for inner solvers when using Schur complement preconditioner are -fieldsplit_0_ and -fieldsplit_1_
1394: for all other solvers they are -fieldsplit_%d_ for the dth field, use -fieldsplit_ for all fields
1396: Notes: use PCFieldSplitSetFields() to set fields defined by "strided" entries and PCFieldSplitSetIS()
1397: to define a field by an arbitrary collection of entries.
1399: If no fields are set the default is used. The fields are defined by entries strided by bs,
1400: beginning at 0 then 1, etc to bs-1. The block size can be set with PCFieldSplitSetBlockSize(),
1401: if this is not called the block size defaults to the blocksize of the second matrix passed
1402: to KSPSetOperators()/PCSetOperators().
1404: For the Schur complement preconditioner if J = ( A00 A01 )
1405: ( A10 A11 )
1406: the preconditioner is
1407: (I -B ksp(A00)) ( inv(A00) 0 (I 0 )
1408: (0 I ) ( 0 ksp(S) ) (-A10 ksp(A00) I )
1409: where the action of inv(A00) is applied using the KSP solver with prefix -fieldsplit_0_. The action of
1410: ksp(S) is computed using the KSP solver with prefix -fieldsplit_splitname_ (where splitname was given in providing the SECOND split or 1 if not give).
1411: For PCFieldSplitGetKSP() when field number is
1412: 0 it returns the KSP associated with -fieldsplit_0_ while field number 1 gives -fieldsplit_1_ KSP. By default
1413: A11 is used to construct a preconditioner for S, use PCFieldSplitSchurPrecondition() to turn on or off this
1414: option. You can use the preconditioner PCLSC to precondition the Schur complement with -fieldsplit_1_pc_type lsc
1415:
1416: If only one set of indices (one IS) is provided with PCFieldSplitSetIS() then the complement of that IS
1417: is used automatically for a second block.
1419: The fieldsplit preconditioner cannot currently be used with the BAIJ or SBAIJ data formats if the blocksize is larger than 1.
1420: Generally it should be used with the AIJ format.
1422: The forms of these preconditioners are closely related if not identical to forms derived as "Distributive Iterations", see,
1423: for example, page 294 in "Principles of Computational Fluid Dynamics" by Pieter Wesseling. Note that one can also use PCFIELDSPLIT
1424: inside a smoother resulting in "Distributive Smoothers".
1426: Concepts: physics based preconditioners, block preconditioners
1428: .seealso: PCCreate(), PCSetType(), PCType (for list of available types), PC, Block_Preconditioners, PCLSC,
1429: PCFieldSplitGetSubKSP(), PCFieldSplitSetFields(), PCFieldSplitSetType(), PCFieldSplitSetIS(), PCFieldSplitSchurPrecondition()
1430: M*/
1435: PetscErrorCode PCCreate_FieldSplit(PC pc)
1436: {
1438: PC_FieldSplit *jac;
1441: PetscNewLog(pc,PC_FieldSplit,&jac);
1442: jac->bs = -1;
1443: jac->nsplits = 0;
1444: jac->type = PC_COMPOSITE_MULTIPLICATIVE;
1445: jac->schurpre = PC_FIELDSPLIT_SCHUR_PRE_USER; /* Try user preconditioner first, fall back on diagonal */
1446: jac->schurfactorization = PC_FIELDSPLIT_SCHUR_FACTORIZATION_FULL;
1448: pc->data = (void*)jac;
1450: pc->ops->apply = PCApply_FieldSplit;
1451: pc->ops->applytranspose = PCApplyTranspose_FieldSplit;
1452: pc->ops->setup = PCSetUp_FieldSplit;
1453: pc->ops->reset = PCReset_FieldSplit;
1454: pc->ops->destroy = PCDestroy_FieldSplit;
1455: pc->ops->setfromoptions = PCSetFromOptions_FieldSplit;
1456: pc->ops->view = PCView_FieldSplit;
1457: pc->ops->applyrichardson = 0;
1459: PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitGetSubKSP_C","PCFieldSplitGetSubKSP_FieldSplit",
1460: PCFieldSplitGetSubKSP_FieldSplit);
1461: PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetFields_C","PCFieldSplitSetFields_FieldSplit",
1462: PCFieldSplitSetFields_FieldSplit);
1463: PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetIS_C","PCFieldSplitSetIS_FieldSplit",
1464: PCFieldSplitSetIS_FieldSplit);
1465: PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetType_C","PCFieldSplitSetType_FieldSplit",
1466: PCFieldSplitSetType_FieldSplit);
1467: PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetBlockSize_C","PCFieldSplitSetBlockSize_FieldSplit",
1468: PCFieldSplitSetBlockSize_FieldSplit);
1469: return(0);
1470: }