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: PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitGetSubKSP_C","",PETSC_NULL);
823: PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetFields_C","",PETSC_NULL);
824: PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetIS_C","",PETSC_NULL);
825: PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetType_C","",PETSC_NULL);
826: PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetBlockSize_C","",PETSC_NULL);
827: return(0);
828: }
832: static PetscErrorCode PCSetFromOptions_FieldSplit(PC pc)
833: {
834: PetscErrorCode ierr;
835: PetscInt bs;
836: PetscBool flg,stokes = PETSC_FALSE;
837: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
838: PCCompositeType ctype;
841: PetscOptionsHead("FieldSplit options");
842: PetscOptionsBool("-pc_fieldsplit_real_diagonal","Use diagonal blocks of the operator","PCFieldSplitSetRealDiagonal",jac->realdiagonal,&jac->realdiagonal,PETSC_NULL);
843: PetscOptionsInt("-pc_fieldsplit_block_size","Blocksize that defines number of fields","PCFieldSplitSetBlockSize",jac->bs,&bs,&flg);
844: if (flg) {
845: PCFieldSplitSetBlockSize(pc,bs);
846: }
848: PetscOptionsGetBool(((PetscObject)pc)->prefix,"-pc_fieldsplit_detect_saddle_point",&stokes,PETSC_NULL);
849: if (stokes) {
850: PCFieldSplitSetType(pc,PC_COMPOSITE_SCHUR);
851: jac->schurpre = PC_FIELDSPLIT_SCHUR_PRE_SELF;
852: }
854: PetscOptionsEnum("-pc_fieldsplit_type","Type of composition","PCFieldSplitSetType",PCCompositeTypes,(PetscEnum)jac->type,(PetscEnum*)&ctype,&flg);
855: if (flg) {
856: PCFieldSplitSetType(pc,ctype);
857: }
859: /* Only setup fields once */
860: if ((jac->bs > 0) && (jac->nsplits == 0)) {
861: /* only allow user to set fields from command line if bs is already known.
862: otherwise user can set them in PCFieldSplitSetDefaults() */
863: PCFieldSplitSetRuntimeSplits_Private(pc);
864: if (jac->splitdefined) {PetscInfo(pc,"Splits defined using the options database\n");}
865: }
866: if (jac->type == PC_COMPOSITE_SCHUR) {
867: PetscOptionsEnum("-pc_fieldsplit_schur_factorization_type","Factorization to use","None",PCFieldSplitSchurFactorizationTypes,(PetscEnum)jac->schurfactorization,(PetscEnum*)&jac->schurfactorization,PETSC_NULL);
868: PetscOptionsEnum("-pc_fieldsplit_schur_precondition","How to build preconditioner for Schur complement","PCFieldSplitSchurPrecondition",PCFieldSplitSchurPreTypes,(PetscEnum)jac->schurpre,(PetscEnum*)&jac->schurpre,PETSC_NULL);
869: }
870: PetscOptionsTail();
871: return(0);
872: }
874: /*------------------------------------------------------------------------------------*/
876: EXTERN_C_BEGIN
879: PetscErrorCode PCFieldSplitSetFields_FieldSplit(PC pc,const char splitname[],PetscInt n,const PetscInt *fields)
880: {
881: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
882: PetscErrorCode ierr;
883: PC_FieldSplitLink ilink,next = jac->head;
884: char prefix[128];
885: PetscInt i;
888: if (jac->splitdefined) {
889: PetscInfo1(pc,"Ignoring new split \"%s\" because the splits have already been defined\n",splitname);
890: return(0);
891: }
892: for (i=0; i<n; i++) {
893: if (fields[i] >= jac->bs) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Field %D requested but only %D exist",fields[i],jac->bs);
894: if (fields[i] < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Negative field %D requested",fields[i]);
895: }
896: PetscNew(struct _PC_FieldSplitLink,&ilink);
897: if (splitname) {
898: PetscStrallocpy(splitname,&ilink->splitname);
899: } else {
900: PetscMalloc(3*sizeof(char),&ilink->splitname);
901: PetscSNPrintf(ilink->splitname,2,"%s",jac->nsplits);
902: }
903: PetscMalloc(n*sizeof(PetscInt),&ilink->fields);
904: PetscMemcpy(ilink->fields,fields,n*sizeof(PetscInt));
905: ilink->nfields = n;
906: ilink->next = PETSC_NULL;
907: KSPCreate(((PetscObject)pc)->comm,&ilink->ksp);
908: PetscObjectIncrementTabLevel((PetscObject)ilink->ksp,(PetscObject)pc,1);
909: KSPSetType(ilink->ksp,KSPPREONLY);
910: PetscLogObjectParent((PetscObject)pc,(PetscObject)ilink->ksp);
912: PetscSNPrintf(prefix,sizeof prefix,"%sfieldsplit_%s_",((PetscObject)pc)->prefix?((PetscObject)pc)->prefix:"",ilink->splitname);
913: KSPSetOptionsPrefix(ilink->ksp,prefix);
915: if (!next) {
916: jac->head = ilink;
917: ilink->previous = PETSC_NULL;
918: } else {
919: while (next->next) {
920: next = next->next;
921: }
922: next->next = ilink;
923: ilink->previous = next;
924: }
925: jac->nsplits++;
926: return(0);
927: }
928: EXTERN_C_END
930: EXTERN_C_BEGIN
933: PetscErrorCode PCFieldSplitGetSubKSP_FieldSplit_Schur(PC pc,PetscInt *n,KSP **subksp)
934: {
935: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
939: PetscMalloc(jac->nsplits*sizeof(KSP),subksp);
940: MatSchurComplementGetKSP(jac->schur,*subksp);
941: (*subksp)[1] = jac->kspschur;
942: if (n) *n = jac->nsplits;
943: return(0);
944: }
945: EXTERN_C_END
947: EXTERN_C_BEGIN
950: PetscErrorCode PCFieldSplitGetSubKSP_FieldSplit(PC pc,PetscInt *n,KSP **subksp)
951: {
952: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
953: PetscErrorCode ierr;
954: PetscInt cnt = 0;
955: PC_FieldSplitLink ilink = jac->head;
958: PetscMalloc(jac->nsplits*sizeof(KSP),subksp);
959: while (ilink) {
960: (*subksp)[cnt++] = ilink->ksp;
961: ilink = ilink->next;
962: }
963: 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);
964: if (n) *n = jac->nsplits;
965: return(0);
966: }
967: EXTERN_C_END
969: EXTERN_C_BEGIN
972: PetscErrorCode PCFieldSplitSetIS_FieldSplit(PC pc,const char splitname[],IS is)
973: {
974: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
975: PetscErrorCode ierr;
976: PC_FieldSplitLink ilink, next = jac->head;
977: char prefix[128];
980: if (jac->splitdefined) {
981: PetscInfo1(pc,"Ignoring new split \"%s\" because the splits have already been defined\n",splitname);
982: return(0);
983: }
984: PetscNew(struct _PC_FieldSplitLink,&ilink);
985: if (splitname) {
986: PetscStrallocpy(splitname,&ilink->splitname);
987: } else {
988: PetscMalloc(3*sizeof(char),&ilink->splitname);
989: PetscSNPrintf(ilink->splitname,3,"%D",jac->nsplits);
990: }
991: ilink->is = is;
992: PetscObjectReference((PetscObject)is);
993: ilink->next = PETSC_NULL;
994: KSPCreate(((PetscObject)pc)->comm,&ilink->ksp);
995: PetscObjectIncrementTabLevel((PetscObject)ilink->ksp,(PetscObject)pc,1);
996: KSPSetType(ilink->ksp,KSPPREONLY);
997: PetscLogObjectParent((PetscObject)pc,(PetscObject)ilink->ksp);
999: PetscSNPrintf(prefix,sizeof prefix,"%sfieldsplit_%s_",((PetscObject)pc)->prefix?((PetscObject)pc)->prefix:"",ilink->splitname);
1000: KSPSetOptionsPrefix(ilink->ksp,prefix);
1002: if (!next) {
1003: jac->head = ilink;
1004: ilink->previous = PETSC_NULL;
1005: } else {
1006: while (next->next) {
1007: next = next->next;
1008: }
1009: next->next = ilink;
1010: ilink->previous = next;
1011: }
1012: jac->nsplits++;
1014: return(0);
1015: }
1016: EXTERN_C_END
1020: /*@
1021: PCFieldSplitSetFields - Sets the fields for one particular split in the field split preconditioner
1023: Logically Collective on PC
1025: Input Parameters:
1026: + pc - the preconditioner context
1027: . splitname - name of this split, if PETSC_NULL the number of the split is used
1028: . n - the number of fields in this split
1029: - fields - the fields in this split
1031: Level: intermediate
1033: Notes: Use PCFieldSplitSetIS() to set a completely general set of indices as a field.
1035: The PCFieldSplitSetFields() is for defining fields as a strided blocks. For example, if the block
1036: 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
1037: 0xx3xx6xx9xx12 ... x1xx4xx7xx ... xx2xx5xx8xx.. 01x34x67x... 0x1x3x5x7.. x12x45x78x....
1038: where the numbered entries indicate what is in the field.
1040: This function is called once per split (it creates a new split each time). Solve options
1041: for this split will be available under the prefix -fieldsplit_SPLITNAME_.
1043: .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetBlockSize(), PCFieldSplitSetIS()
1045: @*/
1046: PetscErrorCode PCFieldSplitSetFields(PC pc,const char splitname[],PetscInt n,const PetscInt *fields)
1047: {
1053: if (n < 1) SETERRQ2(((PetscObject)pc)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Provided number of fields %D in split \"%s\" not positive",n,splitname);
1055: PetscTryMethod(pc,"PCFieldSplitSetFields_C",(PC,const char[],PetscInt,const PetscInt *),(pc,splitname,n,fields));
1056: return(0);
1057: }
1061: /*@
1062: PCFieldSplitSetIS - Sets the exact elements for field
1064: Logically Collective on PC
1066: Input Parameters:
1067: + pc - the preconditioner context
1068: . splitname - name of this split, if PETSC_NULL the number of the split is used
1069: - is - the index set that defines the vector elements in this field
1072: Notes:
1073: Use PCFieldSplitSetFields(), for fields defined by strided types.
1075: This function is called once per split (it creates a new split each time). Solve options
1076: for this split will be available under the prefix -fieldsplit_SPLITNAME_.
1078: Level: intermediate
1080: .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetBlockSize()
1082: @*/
1083: PetscErrorCode PCFieldSplitSetIS(PC pc,const char splitname[],IS is)
1084: {
1091: PetscTryMethod(pc,"PCFieldSplitSetIS_C",(PC,const char[],IS),(pc,splitname,is));
1092: return(0);
1093: }
1097: /*@
1098: PCFieldSplitGetIS - Retrieves the elements for a field as an IS
1100: Logically Collective on PC
1102: Input Parameters:
1103: + pc - the preconditioner context
1104: - splitname - name of this split
1106: Output Parameter:
1107: - is - the index set that defines the vector elements in this field, or PETSC_NULL if the field is not found
1109: Level: intermediate
1111: .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetIS()
1113: @*/
1114: PetscErrorCode PCFieldSplitGetIS(PC pc,const char splitname[],IS *is)
1115: {
1122: {
1123: PC_FieldSplit *jac = (PC_FieldSplit *) pc->data;
1124: PC_FieldSplitLink ilink = jac->head;
1125: PetscBool found;
1127: *is = PETSC_NULL;
1128: while(ilink) {
1129: PetscStrcmp(ilink->splitname, splitname, &found);
1130: if (found) {
1131: *is = ilink->is;
1132: break;
1133: }
1134: ilink = ilink->next;
1135: }
1136: }
1137: return(0);
1138: }
1142: /*@
1143: PCFieldSplitSetBlockSize - Sets the block size for defining where fields start in the
1144: fieldsplit preconditioner. If not set the matrix block size is used.
1146: Logically Collective on PC
1148: Input Parameters:
1149: + pc - the preconditioner context
1150: - bs - the block size
1152: Level: intermediate
1154: .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetFields()
1156: @*/
1157: PetscErrorCode PCFieldSplitSetBlockSize(PC pc,PetscInt bs)
1158: {
1164: PetscTryMethod(pc,"PCFieldSplitSetBlockSize_C",(PC,PetscInt),(pc,bs));
1165: return(0);
1166: }
1170: /*@C
1171: PCFieldSplitGetSubKSP - Gets the KSP contexts for all splits
1172:
1173: Collective on KSP
1175: Input Parameter:
1176: . pc - the preconditioner context
1178: Output Parameters:
1179: + n - the number of splits
1180: - pc - the array of KSP contexts
1182: Note:
1183: After PCFieldSplitGetSubKSP() the array of KSPs IS to be freed by the user
1184: (not the KSP just the array that contains them).
1186: You must call KSPSetUp() before calling PCFieldSplitGetSubKSP().
1188: Level: advanced
1190: .seealso: PCFIELDSPLIT
1191: @*/
1192: PetscErrorCode PCFieldSplitGetSubKSP(PC pc,PetscInt *n,KSP *subksp[])
1193: {
1199: PetscUseMethod(pc,"PCFieldSplitGetSubKSP_C",(PC,PetscInt*,KSP **),(pc,n,subksp));
1200: return(0);
1201: }
1205: /*@
1206: PCFieldSplitSchurPrecondition - Indicates if the Schur complement is preconditioned by a preconditioner constructed by the
1207: A11 matrix. Otherwise no preconditioner is used.
1209: Collective on PC
1211: Input Parameters:
1212: + pc - the preconditioner context
1213: . ptype - which matrix to use for preconditioning the Schur complement, PC_FIELDSPLIT_SCHUR_PRE_DIAG (diag) is default
1214: - userpre - matrix to use for preconditioning, or PETSC_NULL
1216: Options Database:
1217: . -pc_fieldsplit_schur_precondition <self,user,diag> default is diag
1219: Notes:
1220: $ If ptype is
1221: $ user then the preconditioner for the Schur complement is generated by the provided matrix (pre argument
1222: $ to this function).
1223: $ diag then the preconditioner for the Schur complement is generated by the block diagonal part of the original
1224: $ matrix associated with the Schur complement (i.e. A11)
1225: $ self the preconditioner for the Schur complement is generated from the Schur complement matrix itself:
1226: $ The only preconditioner that currently works directly with the Schur complement matrix object is the PCLSC
1227: $ preconditioner
1229: When solving a saddle point problem, where the A11 block is identically zero, using diag as the ptype only makes sense
1230: with the additional option -fieldsplit_1_pc_type none. Usually for saddle point problems one would use a ptype of self and
1231: -fieldsplit_1_pc_type lsc which uses the least squares commutator compute a preconditioner for the Schur complement.
1232:
1233: Developer Notes: This is a terrible name, gives no good indication of what the function does and should also have Set in
1234: the name since it sets a proceedure to use.
1235:
1236: Level: intermediate
1238: .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetFields(), PCFieldSplitSchurPreType, PCLSC
1240: @*/
1241: PetscErrorCode PCFieldSplitSchurPrecondition(PC pc,PCFieldSplitSchurPreType ptype,Mat pre)
1242: {
1247: PetscTryMethod(pc,"PCFieldSplitSchurPrecondition_C",(PC,PCFieldSplitSchurPreType,Mat),(pc,ptype,pre));
1248: return(0);
1249: }
1251: EXTERN_C_BEGIN
1254: PetscErrorCode PCFieldSplitSchurPrecondition_FieldSplit(PC pc,PCFieldSplitSchurPreType ptype,Mat pre)
1255: {
1256: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
1257: PetscErrorCode ierr;
1260: jac->schurpre = ptype;
1261: if (pre) {
1262: MatDestroy(&jac->schur_user);
1263: jac->schur_user = pre;
1264: PetscObjectReference((PetscObject)jac->schur_user);
1265: }
1266: return(0);
1267: }
1268: EXTERN_C_END
1272: /*@C
1273: PCFieldSplitGetSchurBlocks - Gets all matrix blocks for the Schur complement
1274:
1275: Collective on KSP
1277: Input Parameter:
1278: . pc - the preconditioner context
1280: Output Parameters:
1281: + A00 - the (0,0) block
1282: . A01 - the (0,1) block
1283: . A10 - the (1,0) block
1284: - A11 - the (1,1) block
1286: Level: advanced
1288: .seealso: PCFIELDSPLIT
1289: @*/
1290: PetscErrorCode PCFieldSplitGetSchurBlocks(PC pc,Mat *A00,Mat *A01,Mat *A10, Mat *A11)
1291: {
1292: PC_FieldSplit *jac = (PC_FieldSplit *) pc->data;
1296: if (jac->type != PC_COMPOSITE_SCHUR) SETERRQ(((PetscObject)pc)->comm,PETSC_ERR_ARG_WRONG, "FieldSplit is not using a Schur complement approach.");
1297: if (A00) *A00 = jac->pmat[0];
1298: if (A01) *A01 = jac->B;
1299: if (A10) *A10 = jac->C;
1300: if (A11) *A11 = jac->pmat[1];
1301: return(0);
1302: }
1304: EXTERN_C_BEGIN
1307: PetscErrorCode PCFieldSplitSetType_FieldSplit(PC pc,PCCompositeType type)
1308: {
1309: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
1313: jac->type = type;
1314: if (type == PC_COMPOSITE_SCHUR) {
1315: pc->ops->apply = PCApply_FieldSplit_Schur;
1316: pc->ops->view = PCView_FieldSplit_Schur;
1317: PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitGetSubKSP_C","PCFieldSplitGetSubKSP_FieldSplit_Schur",PCFieldSplitGetSubKSP_FieldSplit_Schur);
1318: PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSchurPrecondition_C","PCFieldSplitSchurPrecondition_FieldSplit",PCFieldSplitSchurPrecondition_FieldSplit);
1320: } else {
1321: pc->ops->apply = PCApply_FieldSplit;
1322: pc->ops->view = PCView_FieldSplit;
1323: PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitGetSubKSP_C","PCFieldSplitGetSubKSP_FieldSplit",PCFieldSplitGetSubKSP_FieldSplit);
1324: PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSchurPrecondition_C","",0);
1325: }
1326: return(0);
1327: }
1328: EXTERN_C_END
1330: EXTERN_C_BEGIN
1333: PetscErrorCode PCFieldSplitSetBlockSize_FieldSplit(PC pc,PetscInt bs)
1334: {
1335: PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
1338: if (bs < 1) SETERRQ1(((PetscObject)pc)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Blocksize must be positive, you gave %D",bs);
1339: 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);
1340: jac->bs = bs;
1341: return(0);
1342: }
1343: EXTERN_C_END
1347: /*@
1348: PCFieldSplitSetType - Sets the type of fieldsplit preconditioner.
1349:
1350: Collective on PC
1352: Input Parameter:
1353: . pc - the preconditioner context
1354: . type - PC_COMPOSITE_ADDITIVE, PC_COMPOSITE_MULTIPLICATIVE (default), PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE, PC_COMPOSITE_SPECIAL, PC_COMPOSITE_SCHUR
1356: Options Database Key:
1357: . -pc_fieldsplit_type <type: one of multiplicative, additive, symmetric_multiplicative, special, schur> - Sets fieldsplit preconditioner type
1359: Level: Developer
1361: .keywords: PC, set, type, composite preconditioner, additive, multiplicative
1363: .seealso: PCCompositeSetType()
1365: @*/
1366: PetscErrorCode PCFieldSplitSetType(PC pc,PCCompositeType type)
1367: {
1372: PetscTryMethod(pc,"PCFieldSplitSetType_C",(PC,PCCompositeType),(pc,type));
1373: return(0);
1374: }
1376: /* -------------------------------------------------------------------------------------*/
1377: /*MC
1378: PCFIELDSPLIT - Preconditioner created by combining separate preconditioners for individual
1379: fields or groups of fields. See the users manual section "Solving Block Matrices" for more details.
1381: To set options on the solvers for each block append -fieldsplit_ to all the PC
1382: options database keys. For example, -fieldsplit_pc_type ilu -fieldsplit_pc_factor_levels 1
1383:
1384: To set the options on the solvers separate for each block call PCFieldSplitGetSubKSP()
1385: and set the options directly on the resulting KSP object
1387: Level: intermediate
1389: Options Database Keys:
1390: + -pc_fieldsplit_%d_fields <a,b,..> - indicates the fields to be used in the %d'th split
1391: . -pc_fieldsplit_default - automatically add any fields to additional splits that have not
1392: been supplied explicitly by -pc_fieldsplit_%d_fields
1393: . -pc_fieldsplit_block_size <bs> - size of block that defines fields (i.e. there are bs fields)
1394: . -pc_fieldsplit_type <additive,multiplicative,schur,symmetric_multiplicative>
1395: . -pc_fieldsplit_schur_precondition <true,false> default is true
1396: . -pc_fieldsplit_detect_saddle_point - automatically finds rows with zero or negative diagonal and uses Schur complement with no preconditioner as the solver
1398: - Options prefix for inner solvers when using Schur complement preconditioner are -fieldsplit_0_ and -fieldsplit_1_
1399: for all other solvers they are -fieldsplit_%d_ for the dth field, use -fieldsplit_ for all fields
1401: Notes: use PCFieldSplitSetFields() to set fields defined by "strided" entries and PCFieldSplitSetIS()
1402: to define a field by an arbitrary collection of entries.
1404: If no fields are set the default is used. The fields are defined by entries strided by bs,
1405: beginning at 0 then 1, etc to bs-1. The block size can be set with PCFieldSplitSetBlockSize(),
1406: if this is not called the block size defaults to the blocksize of the second matrix passed
1407: to KSPSetOperators()/PCSetOperators().
1409: For the Schur complement preconditioner if J = ( A00 A01 )
1410: ( A10 A11 )
1411: the preconditioner is
1412: (I -B ksp(A00)) ( inv(A00) 0 (I 0 )
1413: (0 I ) ( 0 ksp(S) ) (-A10 ksp(A00) I )
1414: where the action of inv(A00) is applied using the KSP solver with prefix -fieldsplit_0_. The action of
1415: 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).
1416: For PCFieldSplitGetKSP() when field number is
1417: 0 it returns the KSP associated with -fieldsplit_0_ while field number 1 gives -fieldsplit_1_ KSP. By default
1418: A11 is used to construct a preconditioner for S, use PCFieldSplitSchurPrecondition() to turn on or off this
1419: option. You can use the preconditioner PCLSC to precondition the Schur complement with -fieldsplit_1_pc_type lsc
1420:
1421: If only one set of indices (one IS) is provided with PCFieldSplitSetIS() then the complement of that IS
1422: is used automatically for a second block.
1424: The fieldsplit preconditioner cannot currently be used with the BAIJ or SBAIJ data formats if the blocksize is larger than 1.
1425: Generally it should be used with the AIJ format.
1427: The forms of these preconditioners are closely related if not identical to forms derived as "Distributive Iterations", see,
1428: for example, page 294 in "Principles of Computational Fluid Dynamics" by Pieter Wesseling. Note that one can also use PCFIELDSPLIT
1429: inside a smoother resulting in "Distributive Smoothers".
1431: Concepts: physics based preconditioners, block preconditioners
1433: .seealso: PCCreate(), PCSetType(), PCType (for list of available types), PC, Block_Preconditioners, PCLSC,
1434: PCFieldSplitGetSubKSP(), PCFieldSplitSetFields(), PCFieldSplitSetType(), PCFieldSplitSetIS(), PCFieldSplitSchurPrecondition()
1435: M*/
1437: EXTERN_C_BEGIN
1440: PetscErrorCode PCCreate_FieldSplit(PC pc)
1441: {
1443: PC_FieldSplit *jac;
1446: PetscNewLog(pc,PC_FieldSplit,&jac);
1447: jac->bs = -1;
1448: jac->nsplits = 0;
1449: jac->type = PC_COMPOSITE_MULTIPLICATIVE;
1450: jac->schurpre = PC_FIELDSPLIT_SCHUR_PRE_USER; /* Try user preconditioner first, fall back on diagonal */
1451: jac->schurfactorization = PC_FIELDSPLIT_SCHUR_FACTORIZATION_FULL;
1453: pc->data = (void*)jac;
1455: pc->ops->apply = PCApply_FieldSplit;
1456: pc->ops->applytranspose = PCApplyTranspose_FieldSplit;
1457: pc->ops->setup = PCSetUp_FieldSplit;
1458: pc->ops->reset = PCReset_FieldSplit;
1459: pc->ops->destroy = PCDestroy_FieldSplit;
1460: pc->ops->setfromoptions = PCSetFromOptions_FieldSplit;
1461: pc->ops->view = PCView_FieldSplit;
1462: pc->ops->applyrichardson = 0;
1464: PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitGetSubKSP_C","PCFieldSplitGetSubKSP_FieldSplit",
1465: PCFieldSplitGetSubKSP_FieldSplit);
1466: PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetFields_C","PCFieldSplitSetFields_FieldSplit",
1467: PCFieldSplitSetFields_FieldSplit);
1468: PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetIS_C","PCFieldSplitSetIS_FieldSplit",
1469: PCFieldSplitSetIS_FieldSplit);
1470: PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetType_C","PCFieldSplitSetType_FieldSplit",
1471: PCFieldSplitSetType_FieldSplit);
1472: PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetBlockSize_C","PCFieldSplitSetBlockSize_FieldSplit",
1473: PCFieldSplitSetBlockSize_FieldSplit);
1474: return(0);
1475: }
1476: EXTERN_C_END