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: }