Actual source code: fieldsplit.c
petsc-3.7.1 2016-05-15
Report Typos and Errors

      2: #include <petsc/private/pcimpl.h>     /*I "petscpc.h" I*/
      3: #include <petsc/private/kspimpl.h>
      4: #include <petscdm.h>

      7: const char *const PCFieldSplitSchurPreTypes[] = {"SELF","SELFP","A11","USER","FULL","PCFieldSplitSchurPreType","PC_FIELDSPLIT_SCHUR_PRE_",0};
      8: const char *const PCFieldSplitSchurFactTypes[] = {"DIAG","LOWER","UPPER","FULL","PCFieldSplitSchurFactType","PC_FIELDSPLIT_SCHUR_FACT_",0};

     10: PetscLogEvent KSP_Solve_FS_0,KSP_Solve_FS_1,KSP_Solve_FS_S,KSP_Solve_FS_U,KSP_Solve_FS_L,KSP_Solve_FS_2,KSP_Solve_FS_3,KSP_Solve_FS_4;

     12: typedef struct _PC_FieldSplitLink *PC_FieldSplitLink;
     13: struct _PC_FieldSplitLink {
     14:   KSP               ksp;
     15:   Vec               x,y,z;
     16:   char              *splitname;
     17:   PetscInt          nfields;
     18:   PetscInt          *fields,*fields_col;
     19:   VecScatter        sctx;
     20:   IS                is,is_col,is_orig;
     21:   PC_FieldSplitLink next,previous;
     22:   PetscLogEvent     event;
     23: };

     25: typedef struct {
     26:   PCCompositeType type;
     27:   PetscBool       defaultsplit;                    /* Flag for a system with a set of 'k' scalar fields with the same layout (and bs = k) */
     28:   PetscBool       splitdefined;                    /* Flag is set after the splits have been defined, to prevent more splits from being added */
     29:   PetscInt        bs;                              /* Block size for IS and Mat structures */
     30:   PetscInt        nsplits;                         /* Number of field divisions defined */
     31:   Vec             *x,*y,w1,w2;
     32:   Mat             *mat;                            /* The diagonal block for each split */
     33:   Mat             *pmat;                           /* The preconditioning diagonal block for each split */
     34:   Mat             *Afield;                         /* The rows of the matrix associated with each split */
     35:   PetscBool       issetup;

     37:   /* Only used when Schur complement preconditioning is used */
     38:   Mat                       B;                     /* The (0,1) block */
     39:   Mat                       C;                     /* The (1,0) block */
     40:   Mat                       schur;                 /* The Schur complement S = A11 - A10 A00^{-1} A01, the KSP here, kspinner, is H_1 in [El08] */
     41:   Mat                       schurp;                /* Assembled approximation to S built by MatSchurComplement to be used as a preconditioning matrix when solving with S */
     42:   Mat                       schur_user;            /* User-provided preconditioning matrix for the Schur complement */
     43:   PCFieldSplitSchurPreType  schurpre;              /* Determines which preconditioning matrix is used for the Schur complement */
     44:   PCFieldSplitSchurFactType schurfactorization;
     45:   KSP                       kspschur;              /* The solver for S */
     46:   KSP                       kspupper;              /* The solver for A in the upper diagonal part of the factorization (H_2 in [El08]) */
     47:   PC_FieldSplitLink         head;
     48:   PetscBool                 reset;                  /* indicates PCReset() has been last called on this object, hack */
     49:   PetscBool                 isrestrict;             /* indicates PCFieldSplitRestrictIS() has been last called on this object, hack */
     50:   PetscBool                 suboptionsset;          /* Indicates that the KSPSetFromOptions() has been called on the sub-KSPs */
     51:   PetscBool                 dm_splits;              /* Whether to use DMCreateFieldDecomposition() whenever possible */
     52:   PetscBool                 diag_use_amat;          /* Whether to extract diagonal matrix blocks from Amat, rather than Pmat (weaker than -pc_use_amat) */
     53:   PetscBool                 offdiag_use_amat;       /* Whether to extract off-diagonal matrix blocks from Amat, rather than Pmat (weaker than -pc_use_amat) */
     54: } PC_FieldSplit;

     56: /*
     57:     Notes: there is no particular reason that pmat, x, and y are stored as arrays in PC_FieldSplit instead of
     58:    inside PC_FieldSplitLink, just historical. If you want to be able to add new fields after already using the
     59:    PC you could change this.
     60: */

     62: /* This helper is so that setting a user-provided preconditioning matrix is orthogonal to choosing to use it.  This way the
     63: * application-provided FormJacobian can provide this matrix without interfering with the user's (command-line) choices. */
     64: static Mat FieldSplitSchurPre(PC_FieldSplit *jac)
     65: {
     66:   switch (jac->schurpre) {
     67:   case PC_FIELDSPLIT_SCHUR_PRE_SELF: return jac->schur;
     68:   case PC_FIELDSPLIT_SCHUR_PRE_SELFP: return jac->schurp;
     69:   case PC_FIELDSPLIT_SCHUR_PRE_A11: return jac->pmat[1];
     70:   case PC_FIELDSPLIT_SCHUR_PRE_FULL: /* We calculate this and store it in schur_user */
     71:   case PC_FIELDSPLIT_SCHUR_PRE_USER: /* Use a user-provided matrix if it is given, otherwise diagonal block */
     72:   default:
     73:     return jac->schur_user ? jac->schur_user : jac->pmat[1];
     74:   }
     75: }

     78: #include <petscdraw.h>
     81: static PetscErrorCode PCView_FieldSplit(PC pc,PetscViewer viewer)
     82: {
     83:   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
     84:   PetscErrorCode    ierr;
     85:   PetscBool         iascii,isdraw;
     86:   PetscInt          i,j;
     87:   PC_FieldSplitLink ilink = jac->head;

     90:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);
     91:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERDRAW,&isdraw);
     92:   if (iascii) {
     93:     if (jac->bs > 0) {
     94:       PetscViewerASCIIPrintf(viewer,"  FieldSplit with %s composition: total splits = %D, blocksize = %D\n",PCCompositeTypes[jac->type],jac->nsplits,jac->bs);
     95:     } else {
     96:       PetscViewerASCIIPrintf(viewer,"  FieldSplit with %s composition: total splits = %D\n",PCCompositeTypes[jac->type],jac->nsplits);
     97:     }
     98:     if (pc->useAmat) {
     99:       PetscViewerASCIIPrintf(viewer,"  using Amat (not Pmat) as operator for blocks\n");
    100:     }
    101:     if (jac->diag_use_amat) {
    102:       PetscViewerASCIIPrintf(viewer,"  using Amat (not Pmat) as operator for diagonal blocks\n");
    103:     }
    104:     if (jac->offdiag_use_amat) {
    105:       PetscViewerASCIIPrintf(viewer,"  using Amat (not Pmat) as operator for off-diagonal blocks\n");
    106:     }
    107:     PetscViewerASCIIPrintf(viewer,"  Solver info for each split is in the following KSP objects:\n");
    108:     PetscViewerASCIIPushTab(viewer);
    109:     for (i=0; i<jac->nsplits; i++) {
    110:       if (ilink->fields) {
    111:         PetscViewerASCIIPrintf(viewer,"Split number %D Fields ",i);
    112:         PetscViewerASCIIUseTabs(viewer,PETSC_FALSE);
    113:         for (j=0; j<ilink->nfields; j++) {
    114:           if (j > 0) {
    115:             PetscViewerASCIIPrintf(viewer,",");
    116:           }
    117:           PetscViewerASCIIPrintf(viewer," %D",ilink->fields[j]);
    118:         }
    119:         PetscViewerASCIIPrintf(viewer,"\n");
    120:         PetscViewerASCIIUseTabs(viewer,PETSC_TRUE);
    121:       } else {
    122:         PetscViewerASCIIPrintf(viewer,"Split number %D Defined by IS\n",i);
    123:       }
    124:       KSPView(ilink->ksp,viewer);
    125:       ilink = ilink->next;
    126:     }
    127:     PetscViewerASCIIPopTab(viewer);
    128:   }

    130:  if (isdraw) {
    131:     PetscDraw draw;
    132:     PetscReal x,y,w,wd;

    134:     PetscViewerDrawGetDraw(viewer,0,&draw);
    135:     PetscDrawGetCurrentPoint(draw,&x,&y);
    136:     w    = 2*PetscMin(1.0 - x,x);
    137:     wd   = w/(jac->nsplits + 1);
    138:     x    = x - wd*(jac->nsplits-1)/2.0;
    139:     for (i=0; i<jac->nsplits; i++) {
    140:       PetscDrawPushCurrentPoint(draw,x,y);
    141:       KSPView(ilink->ksp,viewer);
    142:       PetscDrawPopCurrentPoint(draw);
    143:       x    += wd;
    144:       ilink = ilink->next;
    145:     }
    146:   }
    147:   return(0);
    148: }

    152: static PetscErrorCode PCView_FieldSplit_Schur(PC pc,PetscViewer viewer)
    153: {
    154:   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
    155:   PetscErrorCode    ierr;
    156:   PetscBool         iascii,isdraw;
    157:   PetscInt          i,j;
    158:   PC_FieldSplitLink ilink = jac->head;

    161:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);
    162:   PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERDRAW,&isdraw);
    163:   if (iascii) {
    164:     if (jac->bs > 0) {
    165:       PetscViewerASCIIPrintf(viewer,"  FieldSplit with Schur preconditioner, blocksize = %D, factorization %s\n",jac->bs,PCFieldSplitSchurFactTypes[jac->schurfactorization]);
    166:     } else {
    167:       PetscViewerASCIIPrintf(viewer,"  FieldSplit with Schur preconditioner, factorization %s\n",PCFieldSplitSchurFactTypes[jac->schurfactorization]);
    168:     }
    169:     if (pc->useAmat) {
    170:       PetscViewerASCIIPrintf(viewer,"  using Amat (not Pmat) as operator for blocks\n");
    171:     }
    172:     switch (jac->schurpre) {
    173:     case PC_FIELDSPLIT_SCHUR_PRE_SELF:
    174:       PetscViewerASCIIPrintf(viewer,"  Preconditioner for the Schur complement formed from S itself\n");break;
    175:     case PC_FIELDSPLIT_SCHUR_PRE_SELFP:
    176:       PetscViewerASCIIPrintf(viewer,"  Preconditioner for the Schur complement formed from Sp, an assembled approximation to S, which uses (lumped, if requested) A00's diagonal's inverse\n");break;
    177:     case PC_FIELDSPLIT_SCHUR_PRE_A11:
    178:       PetscViewerASCIIPrintf(viewer,"  Preconditioner for the Schur complement formed from A11\n");break;
    179:     case PC_FIELDSPLIT_SCHUR_PRE_FULL:
    180:       PetscViewerASCIIPrintf(viewer,"  Preconditioner for the Schur complement formed from the exact Schur complement\n");break;
    181:     case PC_FIELDSPLIT_SCHUR_PRE_USER:
    182:       if (jac->schur_user) {
    183:         PetscViewerASCIIPrintf(viewer,"  Preconditioner for the Schur complement formed from user provided matrix\n");
    184:       } else {
    185:         PetscViewerASCIIPrintf(viewer,"  Preconditioner for the Schur complement formed from A11\n");
    186:       }
    187:       break;
    188:     default:
    189:       SETERRQ1(PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Invalid Schur preconditioning type: %d", jac->schurpre);
    190:     }
    191:     PetscViewerASCIIPrintf(viewer,"  Split info:\n");
    192:     PetscViewerASCIIPushTab(viewer);
    193:     for (i=0; i<jac->nsplits; i++) {
    194:       if (ilink->fields) {
    195:         PetscViewerASCIIPrintf(viewer,"Split number %D Fields ",i);
    196:         PetscViewerASCIIUseTabs(viewer,PETSC_FALSE);
    197:         for (j=0; j<ilink->nfields; j++) {
    198:           if (j > 0) {
    199:             PetscViewerASCIIPrintf(viewer,",");
    200:           }
    201:           PetscViewerASCIIPrintf(viewer," %D",ilink->fields[j]);
    202:         }
    203:         PetscViewerASCIIPrintf(viewer,"\n");
    204:         PetscViewerASCIIUseTabs(viewer,PETSC_TRUE);
    205:       } else {
    206:         PetscViewerASCIIPrintf(viewer,"Split number %D Defined by IS\n",i);
    207:       }
    208:       ilink = ilink->next;
    209:     }
    210:     PetscViewerASCIIPrintf(viewer,"KSP solver for A00 block\n");
    211:     PetscViewerASCIIPushTab(viewer);
    212:     if (jac->head) {
    213:       KSPView(jac->head->ksp,viewer);
    214:     } else  {PetscViewerASCIIPrintf(viewer,"  not yet available\n");}
    215:     PetscViewerASCIIPopTab(viewer);
    216:     if (jac->head && jac->kspupper != jac->head->ksp) {
    217:       PetscViewerASCIIPrintf(viewer,"KSP solver for upper A00 in upper triangular factor \n");
    218:       PetscViewerASCIIPushTab(viewer);
    219:       if (jac->kspupper) {KSPView(jac->kspupper,viewer);}
    220:       else {PetscViewerASCIIPrintf(viewer,"  not yet available\n");}
    221:       PetscViewerASCIIPopTab(viewer);
    222:     }
    223:     PetscViewerASCIIPrintf(viewer,"KSP solver for S = A11 - A10 inv(A00) A01 \n");
    224:     PetscViewerASCIIPushTab(viewer);
    225:     if (jac->kspschur) {
    226:       KSPView(jac->kspschur,viewer);
    227:     } else {
    228:       PetscViewerASCIIPrintf(viewer,"  not yet available\n");
    229:     }
    230:     PetscViewerASCIIPopTab(viewer);
    231:     PetscViewerASCIIPopTab(viewer);
    232:   } else if (isdraw && jac->head) {
    233:     PetscDraw draw;
    234:     PetscReal x,y,w,wd,h;
    235:     PetscInt  cnt = 2;
    236:     char      str[32];

    238:     PetscViewerDrawGetDraw(viewer,0,&draw);
    239:     PetscDrawGetCurrentPoint(draw,&x,&y);
    240:     if (jac->kspupper != jac->head->ksp) cnt++;
    241:     w  = 2*PetscMin(1.0 - x,x);
    242:     wd = w/(cnt + 1);

    244:     PetscSNPrintf(str,32,"Schur fact. %s",PCFieldSplitSchurFactTypes[jac->schurfactorization]);
    245:     PetscDrawStringBoxed(draw,x,y,PETSC_DRAW_RED,PETSC_DRAW_BLACK,str,NULL,&h);
    246:     y   -= h;
    247:     if (jac->schurpre == PC_FIELDSPLIT_SCHUR_PRE_USER &&  !jac->schur_user) {
    248:       PetscSNPrintf(str,32,"Prec. for Schur from %s",PCFieldSplitSchurPreTypes[PC_FIELDSPLIT_SCHUR_PRE_A11]);
    249:     } else {
    250:       PetscSNPrintf(str,32,"Prec. for Schur from %s",PCFieldSplitSchurPreTypes[jac->schurpre]);
    251:     }
    252:     PetscDrawStringBoxed(draw,x+wd*(cnt-1)/2.0,y,PETSC_DRAW_RED,PETSC_DRAW_BLACK,str,NULL,&h);
    253:     y   -= h;
    254:     x    = x - wd*(cnt-1)/2.0;

    256:     PetscDrawPushCurrentPoint(draw,x,y);
    257:     KSPView(jac->head->ksp,viewer);
    258:     PetscDrawPopCurrentPoint(draw);
    259:     if (jac->kspupper != jac->head->ksp) {
    260:       x   += wd;
    261:       PetscDrawPushCurrentPoint(draw,x,y);
    262:       KSPView(jac->kspupper,viewer);
    263:       PetscDrawPopCurrentPoint(draw);
    264:     }
    265:     x   += wd;
    266:     PetscDrawPushCurrentPoint(draw,x,y);
    267:     KSPView(jac->kspschur,viewer);
    268:     PetscDrawPopCurrentPoint(draw);
    269:   }
    270:   return(0);
    271: }

    275: /* Precondition: jac->bs is set to a meaningful value */
    276: static PetscErrorCode PCFieldSplitSetRuntimeSplits_Private(PC pc)
    277: {
    279:   PC_FieldSplit  *jac = (PC_FieldSplit*)pc->data;
    280:   PetscInt       i,nfields,*ifields,nfields_col,*ifields_col;
    281:   PetscBool      flg,flg_col;
    282:   char           optionname[128],splitname[8],optionname_col[128];

    285:   PetscMalloc1(jac->bs,&ifields);
    286:   PetscMalloc1(jac->bs,&ifields_col);
    287:   for (i=0,flg=PETSC_TRUE;; i++) {
    288:     PetscSNPrintf(splitname,sizeof(splitname),"%D",i);
    289:     PetscSNPrintf(optionname,sizeof(optionname),"-pc_fieldsplit_%D_fields",i);
    290:     PetscSNPrintf(optionname_col,sizeof(optionname_col),"-pc_fieldsplit_%D_fields_col",i);
    291:     nfields     = jac->bs;
    292:     nfields_col = jac->bs;
    293:     PetscOptionsGetIntArray(((PetscObject)pc)->options,((PetscObject)pc)->prefix,optionname,ifields,&nfields,&flg);
    294:     PetscOptionsGetIntArray(((PetscObject)pc)->options,((PetscObject)pc)->prefix,optionname_col,ifields_col,&nfields_col,&flg_col);
    295:     if (!flg) break;
    296:     else if (flg && !flg_col) {
    297:       if (!nfields) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Cannot list zero fields");
    298:       PCFieldSplitSetFields(pc,splitname,nfields,ifields,ifields);
    299:     } else {
    300:       if (!nfields || !nfields_col) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Cannot list zero fields");
    301:       if (nfields != nfields_col) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Number of row and column fields must match");
    302:       PCFieldSplitSetFields(pc,splitname,nfields,ifields,ifields_col);
    303:     }
    304:   }
    305:   if (i > 0) {
    306:     /* Makes command-line setting of splits take precedence over setting them in code.
    307:        Otherwise subsequent calls to PCFieldSplitSetIS() or PCFieldSplitSetFields() would
    308:        create new splits, which would probably not be what the user wanted. */
    309:     jac->splitdefined = PETSC_TRUE;
    310:   }
    311:   PetscFree(ifields);
    312:   PetscFree(ifields_col);
    313:   return(0);
    314: }

    318: static PetscErrorCode PCFieldSplitSetDefaults(PC pc)
    319: {
    320:   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
    321:   PetscErrorCode    ierr;
    322:   PC_FieldSplitLink ilink              = jac->head;
    323:   PetscBool         fieldsplit_default = PETSC_FALSE,stokes = PETSC_FALSE,coupling = PETSC_FALSE;
    324:   PetscInt          i;

    327:   /*
    328:    Kinda messy, but at least this now uses DMCreateFieldDecomposition() even with jac->reset.
    329:    Should probably be rewritten.
    330:    */
    331:   if (!ilink || jac->reset) {
    332:     PetscOptionsGetBool(((PetscObject)pc)->options,((PetscObject)pc)->prefix,"-pc_fieldsplit_detect_saddle_point",&stokes,NULL);
    333:     PetscOptionsGetBool(((PetscObject)pc)->options,((PetscObject)pc)->prefix,"-pc_fieldsplit_detect_coupling",&coupling,NULL);
    334:     if (pc->dm && jac->dm_splits && !stokes && !coupling) {
    335:       PetscInt  numFields, f, i, j;
    336:       char      **fieldNames;
    337:       IS        *fields;
    338:       DM        *dms;
    339:       DM        subdm[128];
    340:       PetscBool flg;

    342:       DMCreateFieldDecomposition(pc->dm, &numFields, &fieldNames, &fields, &dms);
    343:       /* Allow the user to prescribe the splits */
    344:       for (i = 0, flg = PETSC_TRUE;; i++) {
    345:         PetscInt ifields[128];
    346:         IS       compField;
    347:         char     optionname[128], splitname[8];
    348:         PetscInt nfields = numFields;

    350:         PetscSNPrintf(optionname, sizeof(optionname), "-pc_fieldsplit_%D_fields", i);
    351:         PetscOptionsGetIntArray(((PetscObject)pc)->options,((PetscObject)pc)->prefix, optionname, ifields, &nfields, &flg);
    352:         if (!flg) break;
    353:         if (numFields > 128) SETERRQ1(PetscObjectComm((PetscObject)pc),PETSC_ERR_SUP,"Cannot currently support %d > 128 fields", numFields);
    354:         DMCreateSubDM(pc->dm, nfields, ifields, &compField, &subdm[i]);
    355:         if (nfields == 1) {
    356:           PCFieldSplitSetIS(pc, fieldNames[ifields[0]], compField);
    357:           /* PetscPrintf(PetscObjectComm((PetscObject)pc), "%s Field Indices:", fieldNames[ifields[0]]);
    358:              ISView(compField, NULL); */
    359:         } else {
    360:           PetscSNPrintf(splitname, sizeof(splitname), "%D", i);
    361:           PCFieldSplitSetIS(pc, splitname, compField);
    362:           /* PetscPrintf(PetscObjectComm((PetscObject)pc), "%s Field Indices:", splitname);
    363:              ISView(compField, NULL); */
    364:         }
    365:         ISDestroy(&compField);
    366:         for (j = 0; j < nfields; ++j) {
    367:           f    = ifields[j];
    368:           PetscFree(fieldNames[f]);
    369:           ISDestroy(&fields[f]);
    370:         }
    371:       }
    372:       if (i == 0) {
    373:         for (f = 0; f < numFields; ++f) {
    374:           PCFieldSplitSetIS(pc, fieldNames[f], fields[f]);
    375:           PetscFree(fieldNames[f]);
    376:           ISDestroy(&fields[f]);
    377:         }
    378:       } else {
    379:         for (j=0; j<numFields; j++) {
    380:           DMDestroy(dms+j);
    381:         }
    382:         PetscFree(dms);
    383:         PetscMalloc1(i, &dms);
    384:         for (j = 0; j < i; ++j) dms[j] = subdm[j];
    385:       }
    386:       PetscFree(fieldNames);
    387:       PetscFree(fields);
    388:       if (dms) {
    389:         PetscInfo(pc, "Setting up physics based fieldsplit preconditioner using the embedded DM\n");
    390:         for (ilink = jac->head, i = 0; ilink; ilink = ilink->next, ++i) {
    391:           const char *prefix;
    392:           PetscObjectGetOptionsPrefix((PetscObject)(ilink->ksp),&prefix);
    393:           PetscObjectSetOptionsPrefix((PetscObject)(dms[i]), prefix);
    394:           KSPSetDM(ilink->ksp, dms[i]);
    395:           KSPSetDMActive(ilink->ksp, PETSC_FALSE);
    396:           PetscObjectIncrementTabLevel((PetscObject)dms[i],(PetscObject)ilink->ksp,0);
    397:           DMDestroy(&dms[i]);
    398:         }
    399:         PetscFree(dms);
    400:       }
    401:     } else {
    402:       if (jac->bs <= 0) {
    403:         if (pc->pmat) {
    404:           MatGetBlockSize(pc->pmat,&jac->bs);
    405:         } else jac->bs = 1;
    406:       }

    408:       if (stokes) {
    409:         IS       zerodiags,rest;
    410:         PetscInt nmin,nmax;

    412:         MatGetOwnershipRange(pc->mat,&nmin,&nmax);
    413:         MatFindZeroDiagonals(pc->mat,&zerodiags);
    414:         ISComplement(zerodiags,nmin,nmax,&rest);
    415:         if (jac->reset) {
    416:           jac->head->is       = rest;
    417:           jac->head->next->is = zerodiags;
    418:         } else {
    419:           PCFieldSplitSetIS(pc,"0",rest);
    420:           PCFieldSplitSetIS(pc,"1",zerodiags);
    421:         }
    422:         ISDestroy(&zerodiags);
    423:         ISDestroy(&rest);
    424:       } else if (coupling) {
    425:         IS       coupling,rest;
    426:         PetscInt nmin,nmax;

    428:         MatGetOwnershipRange(pc->mat,&nmin,&nmax);
    429:         MatFindOffBlockDiagonalEntries(pc->mat,&coupling);
    430:         ISCreateStride(PetscObjectComm((PetscObject)pc->mat),nmax-nmin,nmin,1,&rest);
    431:         ISSetIdentity(rest);
    432:         if (jac->reset) {
    433:           jac->head->is       = rest;
    434:           jac->head->next->is = coupling;
    435:         } else {
    436:           PCFieldSplitSetIS(pc,"0",rest);
    437:           PCFieldSplitSetIS(pc,"1",coupling);
    438:         }
    439:         ISDestroy(&coupling);
    440:         ISDestroy(&rest);
    441:       } else {
    442:         if (jac->reset && !jac->isrestrict) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_SUP,"Cases not yet handled when PCReset() was used");
    443:         PetscOptionsGetBool(((PetscObject)pc)->options,((PetscObject)pc)->prefix,"-pc_fieldsplit_default",&fieldsplit_default,NULL);
    444:         if (!fieldsplit_default) {
    445:           /* Allow user to set fields from command line,  if bs was known at the time of PCSetFromOptions_FieldSplit()
    446:            then it is set there. This is not ideal because we should only have options set in XXSetFromOptions(). */
    447:           PCFieldSplitSetRuntimeSplits_Private(pc);
    448:           if (jac->splitdefined) {PetscInfo(pc,"Splits defined using the options database\n");}
    449:         }
    450:         if ((fieldsplit_default || !jac->splitdefined) && !jac->isrestrict) {
    451:           PetscInfo(pc,"Using default splitting of fields\n");
    452:           for (i=0; i<jac->bs; i++) {
    453:             char splitname[8];
    454:             PetscSNPrintf(splitname,sizeof(splitname),"%D",i);
    455:             PCFieldSplitSetFields(pc,splitname,1,&i,&i);
    456:           }
    457:           jac->defaultsplit = PETSC_TRUE;
    458:         }
    459:       }
    460:     }
    461:   } else if (jac->nsplits == 1) {
    462:     if (ilink->is) {
    463:       IS       is2;
    464:       PetscInt nmin,nmax;

    466:       MatGetOwnershipRange(pc->mat,&nmin,&nmax);
    467:       ISComplement(ilink->is,nmin,nmax,&is2);
    468:       PCFieldSplitSetIS(pc,"1",is2);
    469:       ISDestroy(&is2);
    470:     } else SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_SUP,"Must provide at least two sets of fields to PCFieldSplit()");
    471:   }

    474:   if (jac->nsplits < 2) SETERRQ1(PetscObjectComm((PetscObject)pc),PETSC_ERR_PLIB,"Unhandled case, must have at least two fields, not %d", jac->nsplits);
    475:   return(0);
    476: }

    478: PETSC_EXTERN PetscErrorCode PetscOptionsFindPairPrefix_Private(PetscOptions,const char pre[], const char name[], char *value[], PetscBool *flg);

    482: static PetscErrorCode PCSetUp_FieldSplit(PC pc)
    483: {
    484:   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
    485:   PetscErrorCode    ierr;
    486:   PC_FieldSplitLink ilink;
    487:   PetscInt          i,nsplit;
    488:   PetscBool         sorted, sorted_col;

    491:   PCFieldSplitSetDefaults(pc);
    492:   nsplit = jac->nsplits;
    493:   ilink  = jac->head;

    495:   /* get the matrices for each split */
    496:   if (!jac->issetup) {
    497:     PetscInt rstart,rend,nslots,bs;

    499:     jac->issetup = PETSC_TRUE;

    501:     /* This is done here instead of in PCFieldSplitSetFields() because may not have matrix at that point */
    502:     if (jac->defaultsplit || !ilink->is) {
    503:       if (jac->bs <= 0) jac->bs = nsplit;
    504:     }
    505:     bs     = jac->bs;
    506:     MatGetOwnershipRange(pc->pmat,&rstart,&rend);
    507:     nslots = (rend - rstart)/bs;
    508:     for (i=0; i<nsplit; i++) {
    509:       if (jac->defaultsplit) {
    510:         ISCreateStride(PetscObjectComm((PetscObject)pc),nslots,rstart+i,nsplit,&ilink->is);
    511:         ISDuplicate(ilink->is,&ilink->is_col);
    512:       } else if (!ilink->is) {
    513:         if (ilink->nfields > 1) {
    514:           PetscInt *ii,*jj,j,k,nfields = ilink->nfields,*fields = ilink->fields,*fields_col = ilink->fields_col;
    515:           PetscMalloc1(ilink->nfields*nslots,&ii);
    516:           PetscMalloc1(ilink->nfields*nslots,&jj);
    517:           for (j=0; j<nslots; j++) {
    518:             for (k=0; k<nfields; k++) {
    519:               ii[nfields*j + k] = rstart + bs*j + fields[k];
    520:               jj[nfields*j + k] = rstart + bs*j + fields_col[k];
    521:             }
    522:           }
    523:           ISCreateGeneral(PetscObjectComm((PetscObject)pc),nslots*nfields,ii,PETSC_OWN_POINTER,&ilink->is);
    524:           ISCreateGeneral(PetscObjectComm((PetscObject)pc),nslots*nfields,jj,PETSC_OWN_POINTER,&ilink->is_col);
    525:           ISSetBlockSize(ilink->is, nfields);
    526:           ISSetBlockSize(ilink->is_col, nfields);
    527:         } else {
    528:           ISCreateStride(PetscObjectComm((PetscObject)pc),nslots,rstart+ilink->fields[0],bs,&ilink->is);
    529:           ISCreateStride(PetscObjectComm((PetscObject)pc),nslots,rstart+ilink->fields_col[0],bs,&ilink->is_col);
    530:        }
    531:       }
    532:       ISSorted(ilink->is,&sorted);
    533:       if (ilink->is_col) { ISSorted(ilink->is_col,&sorted_col); }
    534:       if (!sorted || !sorted_col) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Fields must be sorted when creating split");
    535:       ilink = ilink->next;
    536:     }
    537:   }

    539:   ilink = jac->head;
    540:   if (!jac->pmat) {
    541:     Vec xtmp;

    543:     MatCreateVecs(pc->pmat,&xtmp,NULL);
    544:     PetscMalloc1(nsplit,&jac->pmat);
    545:     PetscMalloc2(nsplit,&jac->x,nsplit,&jac->y);
    546:     for (i=0; i<nsplit; i++) {
    547:       MatNullSpace sp;

    549:       /* Check for preconditioning matrix attached to IS */
    550:       PetscObjectQuery((PetscObject) ilink->is, "pmat", (PetscObject*) &jac->pmat[i]);
    551:       if (jac->pmat[i]) {
    552:         PetscObjectReference((PetscObject) jac->pmat[i]);
    553:         if (jac->type == PC_COMPOSITE_SCHUR) {
    554:           jac->schur_user = jac->pmat[i];

    556:           PetscObjectReference((PetscObject) jac->schur_user);
    557:         }
    558:       } else {
    559:         const char *prefix;
    560:         MatGetSubMatrix(pc->pmat,ilink->is,ilink->is_col,MAT_INITIAL_MATRIX,&jac->pmat[i]);
    561:         KSPGetOptionsPrefix(ilink->ksp,&prefix);
    562:         MatSetOptionsPrefix(jac->pmat[i],prefix);
    563:         MatViewFromOptions(jac->pmat[i],NULL,"-mat_view");
    564:       }
    565:       /* create work vectors for each split */
    566:       MatCreateVecs(jac->pmat[i],&jac->x[i],&jac->y[i]);
    567:       ilink->x = jac->x[i]; ilink->y = jac->y[i]; ilink->z = NULL;
    568:       /* compute scatter contexts needed by multiplicative versions and non-default splits */
    569:       VecScatterCreate(xtmp,ilink->is,jac->x[i],NULL,&ilink->sctx);
    570:       PetscObjectQuery((PetscObject) ilink->is, "nearnullspace", (PetscObject*) &sp);
    571:       if (sp) {
    572:         MatSetNearNullSpace(jac->pmat[i], sp);
    573:       }
    574:       ilink = ilink->next;
    575:     }
    576:     VecDestroy(&xtmp);
    577:   } else {
    578:     for (i=0; i<nsplit; i++) {
    579:       Mat pmat;

    581:       /* Check for preconditioning matrix attached to IS */
    582:       PetscObjectQuery((PetscObject) ilink->is, "pmat", (PetscObject*) &pmat);
    583:       if (!pmat) {
    584:         MatGetSubMatrix(pc->pmat,ilink->is,ilink->is_col,MAT_REUSE_MATRIX,&jac->pmat[i]);
    585:       }
    586:       ilink = ilink->next;
    587:     }
    588:   }
    589:   if (jac->diag_use_amat) {
    590:     ilink = jac->head;
    591:     if (!jac->mat) {
    592:       PetscMalloc1(nsplit,&jac->mat);
    593:       for (i=0; i<nsplit; i++) {
    594:         MatGetSubMatrix(pc->mat,ilink->is,ilink->is_col,MAT_INITIAL_MATRIX,&jac->mat[i]);
    595:         ilink = ilink->next;
    596:       }
    597:     } else {
    598:       for (i=0; i<nsplit; i++) {
    599:         if (jac->mat[i]) {MatGetSubMatrix(pc->mat,ilink->is,ilink->is_col,MAT_REUSE_MATRIX,&jac->mat[i]);}
    600:         ilink = ilink->next;
    601:       }
    602:     }
    603:   } else {
    604:     jac->mat = jac->pmat;
    605:   }

    607:   /* Check for null space attached to IS */
    608:   ilink = jac->head;
    609:   for (i=0; i<nsplit; i++) {
    610:     MatNullSpace sp;

    612:     PetscObjectQuery((PetscObject) ilink->is, "nullspace", (PetscObject*) &sp);
    613:     if (sp) {
    614:       MatSetNullSpace(jac->mat[i], sp);
    615:     }
    616:     ilink = ilink->next;
    617:   }

    619:   if (jac->type != PC_COMPOSITE_ADDITIVE  && jac->type != PC_COMPOSITE_SCHUR) {
    620:     /* extract the rows of the matrix associated with each field: used for efficient computation of residual inside algorithm */
    621:     /* FIXME: Can/should we reuse jac->mat whenever (jac->diag_use_amat) is true? */
    622:     ilink = jac->head;
    623:     if (nsplit == 2 && jac->type == PC_COMPOSITE_MULTIPLICATIVE) {
    624:       /* special case need where Afield[0] is not needed and only certain columns of Afield[1] are needed since update is only on those rows of the solution */
    625:       if (!jac->Afield) {
    626:         PetscCalloc1(nsplit,&jac->Afield);
    627:         MatGetSubMatrix(pc->mat,ilink->next->is,ilink->is,MAT_INITIAL_MATRIX,&jac->Afield[1]);
    628:       } else {
    629:         MatGetSubMatrix(pc->mat,ilink->next->is,ilink->is,MAT_REUSE_MATRIX,&jac->Afield[1]);
    630:       }
    631:     } else {
    632:       if (!jac->Afield) {
    633:         PetscMalloc1(nsplit,&jac->Afield);
    634:         for (i=0; i<nsplit; i++) {
    635:           MatGetSubMatrix(pc->mat,ilink->is,NULL,MAT_INITIAL_MATRIX,&jac->Afield[i]);
    636:           ilink = ilink->next;
    637:         }
    638:       } else {
    639:         for (i=0; i<nsplit; i++) {
    640:           MatGetSubMatrix(pc->mat,ilink->is,NULL,MAT_REUSE_MATRIX,&jac->Afield[i]);
    641:           ilink = ilink->next;
    642:         }
    643:       }
    644:     }
    645:   }

    647:   if (jac->type == PC_COMPOSITE_SCHUR) {
    648:     IS          ccis;
    649:     PetscInt    rstart,rend;
    650:     char        lscname[256];
    651:     PetscObject LSC_L;

    653:     if (nsplit != 2) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_INCOMP,"To use Schur complement preconditioner you must have exactly 2 fields");

    655:     /* When extracting off-diagonal submatrices, we take complements from this range */
    656:     MatGetOwnershipRangeColumn(pc->mat,&rstart,&rend);

    658:     /* need to handle case when one is resetting up the preconditioner */
    659:     if (jac->schur) {
    660:       KSP kspA = jac->head->ksp, kspInner = NULL, kspUpper = jac->kspupper;

    662:       MatSchurComplementGetKSP(jac->schur, &kspInner);
    663:       ilink = jac->head;
    664:       ISComplement(ilink->is_col,rstart,rend,&ccis);
    665:       if (jac->offdiag_use_amat) {
    666:         MatGetSubMatrix(pc->mat,ilink->is,ccis,MAT_REUSE_MATRIX,&jac->B);
    667:       } else {
    668:         MatGetSubMatrix(pc->pmat,ilink->is,ccis,MAT_REUSE_MATRIX,&jac->B);
    669:       }
    670:       ISDestroy(&ccis);
    671:       ilink = ilink->next;
    672:       ISComplement(ilink->is_col,rstart,rend,&ccis);
    673:       if (jac->offdiag_use_amat) {
    674:         MatGetSubMatrix(pc->mat,ilink->is,ccis,MAT_REUSE_MATRIX,&jac->C);
    675:       } else {
    676:         MatGetSubMatrix(pc->pmat,ilink->is,ccis,MAT_REUSE_MATRIX,&jac->C);
    677:       }
    678:       ISDestroy(&ccis);
    679:       MatSchurComplementUpdateSubMatrices(jac->schur,jac->mat[0],jac->pmat[0],jac->B,jac->C,jac->mat[1]);
    680:       if (jac->schurpre == PC_FIELDSPLIT_SCHUR_PRE_SELFP) {
    681:         MatDestroy(&jac->schurp);
    682:         MatSchurComplementGetPmat(jac->schur,MAT_INITIAL_MATRIX,&jac->schurp);
    683:       }
    684:       if (kspA != kspInner) {
    685:         KSPSetOperators(kspA,jac->mat[0],jac->pmat[0]);
    686:       }
    687:       if (kspUpper != kspA) {
    688:         KSPSetOperators(kspUpper,jac->mat[0],jac->pmat[0]);
    689:       }
    690:       KSPSetOperators(jac->kspschur,jac->schur,FieldSplitSchurPre(jac));
    691:     } else {
    692:       const char   *Dprefix;
    693:       char         schurprefix[256], schurmatprefix[256];
    694:       char         schurtestoption[256];
    695:       MatNullSpace sp;
    696:       PetscBool    flg;

    698:       /* extract the A01 and A10 matrices */
    699:       ilink = jac->head;
    700:       ISComplement(ilink->is_col,rstart,rend,&ccis);
    701:       if (jac->offdiag_use_amat) {
    702:         MatGetSubMatrix(pc->mat,ilink->is,ccis,MAT_INITIAL_MATRIX,&jac->B);
    703:       } else {
    704:         MatGetSubMatrix(pc->pmat,ilink->is,ccis,MAT_INITIAL_MATRIX,&jac->B);
    705:       }
    706:       ISDestroy(&ccis);
    707:       ilink = ilink->next;
    708:       ISComplement(ilink->is_col,rstart,rend,&ccis);
    709:       if (jac->offdiag_use_amat) {
    710:         MatGetSubMatrix(pc->mat,ilink->is,ccis,MAT_INITIAL_MATRIX,&jac->C);
    711:       } else {
    712:         MatGetSubMatrix(pc->pmat,ilink->is,ccis,MAT_INITIAL_MATRIX,&jac->C);
    713:       }
    714:       ISDestroy(&ccis);

    716:       /* Use mat[0] (diagonal block of Amat) preconditioned by pmat[0] to define Schur complement */
    717:       MatCreate(((PetscObject)jac->mat[0])->comm,&jac->schur);
    718:       MatSetType(jac->schur,MATSCHURCOMPLEMENT);
    719:       MatSchurComplementSetSubMatrices(jac->schur,jac->mat[0],jac->pmat[0],jac->B,jac->C,jac->mat[1]);
    720:       PetscSNPrintf(schurmatprefix, sizeof(schurmatprefix), "%sfieldsplit_%s_", ((PetscObject)pc)->prefix ? ((PetscObject)pc)->prefix : "", ilink->splitname);
    721:       /* Note that the inner KSP is NOT going to inherit this prefix, and if it did, it would be reset just below.  Is that what we want? */
    722:       MatSetOptionsPrefix(jac->schur,schurmatprefix);
    723:       MatSetFromOptions(jac->schur);
    724:       MatGetNullSpace(jac->mat[1], &sp);
    725:       if (sp) {
    726:         MatSetNullSpace(jac->schur, sp);
    727:       }

    729:       PetscSNPrintf(schurtestoption, sizeof(schurtestoption), "-fieldsplit_%s_inner_", ilink->splitname);
    730:       PetscOptionsFindPairPrefix_Private(((PetscObject)pc)->options,((PetscObject)pc)->prefix, schurtestoption, NULL, &flg);
    731:       if (flg) {
    732:         DM  dmInner;
    733:         KSP kspInner;

    735:         MatSchurComplementGetKSP(jac->schur, &kspInner);
    736:         PetscSNPrintf(schurprefix, sizeof(schurprefix), "%sfieldsplit_%s_inner_", ((PetscObject)pc)->prefix ? ((PetscObject)pc)->prefix : "", ilink->splitname);
    737:         /* Indent this deeper to emphasize the "inner" nature of this solver. */
    738:         PetscObjectIncrementTabLevel((PetscObject)kspInner, (PetscObject) pc, 2);
    739:         KSPSetOptionsPrefix(kspInner, schurprefix);

    741:         /* Set DM for new solver */
    742:         KSPGetDM(jac->head->ksp, &dmInner);
    743:         KSPSetDM(kspInner, dmInner);
    744:         KSPSetDMActive(kspInner, PETSC_FALSE);
    745:       } else {
    746:          /* Use the outer solver for the inner solve, but revert the KSPPREONLY from PCFieldSplitSetFields_FieldSplit or
    747:           * PCFieldSplitSetIS_FieldSplit. We don't want KSPPREONLY because it makes the Schur complement inexact,
    748:           * preventing Schur complement reduction to be an accurate solve. Usually when an iterative solver is used for
    749:           * S = D - C A_inner^{-1} B, we expect S to be defined using an accurate definition of A_inner^{-1}, so we make
    750:           * GMRES the default. Note that it is also common to use PREONLY for S, in which case S may not be used
    751:           * directly, and the user is responsible for setting an inexact method for fieldsplit's A^{-1}. */
    752:         KSPSetType(jac->head->ksp,KSPGMRES);
    753:         MatSchurComplementSetKSP(jac->schur,jac->head->ksp);
    754:       }
    755:       KSPSetOperators(jac->head->ksp,jac->mat[0],jac->pmat[0]);
    756:       KSPSetFromOptions(jac->head->ksp);
    757:       MatSetFromOptions(jac->schur);

    759:       PetscSNPrintf(schurtestoption, sizeof(schurtestoption), "-fieldsplit_%s_upper_", ilink->splitname);
    760:       PetscOptionsFindPairPrefix_Private(((PetscObject)pc)->options,((PetscObject)pc)->prefix, schurtestoption, NULL, &flg);
    761:       if (flg) {
    762:         DM dmInner;

    764:         PetscSNPrintf(schurprefix, sizeof(schurprefix), "%sfieldsplit_%s_upper_", ((PetscObject)pc)->prefix ? ((PetscObject)pc)->prefix : "", ilink->splitname);
    765:         KSPCreate(PetscObjectComm((PetscObject)pc), &jac->kspupper);
    766:         KSPSetErrorIfNotConverged(jac->kspupper,pc->erroriffailure);
    767:         KSPSetOptionsPrefix(jac->kspupper, schurprefix);
    768:         KSPGetDM(jac->head->ksp, &dmInner);
    769:         KSPSetDM(jac->kspupper, dmInner);
    770:         KSPSetDMActive(jac->kspupper, PETSC_FALSE);
    771:         KSPSetFromOptions(jac->kspupper);
    772:         KSPSetOperators(jac->kspupper,jac->mat[0],jac->pmat[0]);
    773:         VecDuplicate(jac->head->x, &jac->head->z);
    774:       } else {
    775:         jac->kspupper = jac->head->ksp;
    776:         PetscObjectReference((PetscObject) jac->head->ksp);
    777:       }

    779:       if (jac->schurpre == PC_FIELDSPLIT_SCHUR_PRE_SELFP) {
    780:         MatSchurComplementGetPmat(jac->schur,MAT_INITIAL_MATRIX,&jac->schurp);
    781:       }
    782:       KSPCreate(PetscObjectComm((PetscObject)pc),&jac->kspschur);
    783:       KSPSetErrorIfNotConverged(jac->kspschur,pc->erroriffailure);
    784:       PetscLogObjectParent((PetscObject)pc,(PetscObject)jac->kspschur);
    785:       PetscObjectIncrementTabLevel((PetscObject)jac->kspschur,(PetscObject)pc,1);
    786:       if (jac->schurpre == PC_FIELDSPLIT_SCHUR_PRE_SELF) {
    787:         PC pcschur;
    788:         KSPGetPC(jac->kspschur,&pcschur);
    789:         PCSetType(pcschur,PCNONE);
    790:         /* Note: This is bad if there exist preconditioners for MATSCHURCOMPLEMENT */
    791:       } else if (jac->schurpre == PC_FIELDSPLIT_SCHUR_PRE_FULL) {
    792:         MatSchurComplementComputeExplicitOperator(jac->schur, &jac->schur_user);
    793:       }
    794:       KSPSetOperators(jac->kspschur,jac->schur,FieldSplitSchurPre(jac));
    795:       KSPGetOptionsPrefix(jac->head->next->ksp, &Dprefix);
    796:       KSPSetOptionsPrefix(jac->kspschur,         Dprefix);
    797:       /* propogate DM */
    798:       {
    799:         DM sdm;
    800:         KSPGetDM(jac->head->next->ksp, &sdm);
    801:         if (sdm) {
    802:           KSPSetDM(jac->kspschur, sdm);
    803:           KSPSetDMActive(jac->kspschur, PETSC_FALSE);
    804:         }
    805:       }
    806:       /* really want setfromoptions called in PCSetFromOptions_FieldSplit(), but it is not ready yet */
    807:       /* need to call this every time, since the jac->kspschur is freshly created, otherwise its options never get set */
    808:       KSPSetFromOptions(jac->kspschur);
    809:     }

    811:     /* HACK: special support to forward L and Lp matrices that might be used by PCLSC */
    812:     PetscSNPrintf(lscname,sizeof(lscname),"%s_LSC_L",ilink->splitname);
    813:     PetscObjectQuery((PetscObject)pc->mat,lscname,(PetscObject*)&LSC_L);
    814:     if (!LSC_L) {PetscObjectQuery((PetscObject)pc->pmat,lscname,(PetscObject*)&LSC_L);}
    815:     if (LSC_L) {PetscObjectCompose((PetscObject)jac->schur,"LSC_L",(PetscObject)LSC_L);}
    816:     PetscSNPrintf(lscname,sizeof(lscname),"%s_LSC_Lp",ilink->splitname);
    817:     PetscObjectQuery((PetscObject)pc->pmat,lscname,(PetscObject*)&LSC_L);
    818:     if (!LSC_L) {PetscObjectQuery((PetscObject)pc->mat,lscname,(PetscObject*)&LSC_L);}
    819:     if (LSC_L) {PetscObjectCompose((PetscObject)jac->schur,"LSC_Lp",(PetscObject)LSC_L);}
    820:   } else {
    821:     /* set up the individual splits' PCs */
    822:     i     = 0;
    823:     ilink = jac->head;
    824:     while (ilink) {
    825:       KSPSetOperators(ilink->ksp,jac->mat[i],jac->pmat[i]);
    826:       /* really want setfromoptions called in PCSetFromOptions_FieldSplit(), but it is not ready yet */
    827:       if (!jac->suboptionsset) {KSPSetFromOptions(ilink->ksp);}
    828:       i++;
    829:       ilink = ilink->next;
    830:     }
    831:   }

    833:   jac->suboptionsset = PETSC_TRUE;
    834:   return(0);
    835: }

    837: #define FieldSplitSplitSolveAdd(ilink,xx,yy) \
    838:   (VecScatterBegin(ilink->sctx,xx,ilink->x,INSERT_VALUES,SCATTER_FORWARD) || \
    839:    VecScatterEnd(ilink->sctx,xx,ilink->x,INSERT_VALUES,SCATTER_FORWARD) || \
    840:    PetscLogEventBegin(ilink->event,ilink->ksp,ilink->x,ilink->y,NULL) ||\
    841:    KSPSolve(ilink->ksp,ilink->x,ilink->y) ||                               \
    842:    PetscLogEventEnd(ilink->event,ilink->ksp,ilink->x,ilink->y,NULL) ||\
    843:    VecScatterBegin(ilink->sctx,ilink->y,yy,ADD_VALUES,SCATTER_REVERSE) ||  \
    844:    VecScatterEnd(ilink->sctx,ilink->y,yy,ADD_VALUES,SCATTER_REVERSE))

    848: static PetscErrorCode PCApply_FieldSplit_Schur(PC pc,Vec x,Vec y)
    849: {
    850:   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
    851:   PetscErrorCode    ierr;
    852:   PC_FieldSplitLink ilinkA = jac->head, ilinkD = ilinkA->next;
    853:   KSP               kspA   = ilinkA->ksp, kspLower = kspA, kspUpper = jac->kspupper;

    856:   switch (jac->schurfactorization) {
    857:   case PC_FIELDSPLIT_SCHUR_FACT_DIAG:
    858:     /* [A00 0; 0 -S], positive definite, suitable for MINRES */
    859:     VecScatterBegin(ilinkA->sctx,x,ilinkA->x,INSERT_VALUES,SCATTER_FORWARD);
    860:     VecScatterBegin(ilinkD->sctx,x,ilinkD->x,INSERT_VALUES,SCATTER_FORWARD);
    861:     VecScatterEnd(ilinkA->sctx,x,ilinkA->x,INSERT_VALUES,SCATTER_FORWARD);
    862:     PetscLogEventBegin(ilinkA->event,kspA,ilinkA->x,ilinkA->y,NULL);
    863:     KSPSolve(kspA,ilinkA->x,ilinkA->y);
    864:     PetscLogEventEnd(ilinkA->event,kspA,ilinkA->x,ilinkA->y,NULL);
    865:     VecScatterBegin(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);
    866:     VecScatterEnd(ilinkD->sctx,x,ilinkD->x,INSERT_VALUES,SCATTER_FORWARD);
    867:     PetscLogEventBegin(KSP_Solve_FS_S,jac->kspschur,ilinkD->x,ilinkD->y,NULL);
    868:     KSPSolve(jac->kspschur,ilinkD->x,ilinkD->y);
    869:     PetscLogEventEnd(KSP_Solve_FS_S,jac->kspschur,ilinkD->x,ilinkD->y,NULL);
    870:     VecScale(ilinkD->y,-1.);
    871:     VecScatterBegin(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);
    872:     VecScatterEnd(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);
    873:     VecScatterEnd(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);
    874:     break;
    875:   case PC_FIELDSPLIT_SCHUR_FACT_LOWER:
    876:     /* [A00 0; A10 S], suitable for left preconditioning */
    877:     VecScatterBegin(ilinkA->sctx,x,ilinkA->x,INSERT_VALUES,SCATTER_FORWARD);
    878:     VecScatterEnd(ilinkA->sctx,x,ilinkA->x,INSERT_VALUES,SCATTER_FORWARD);
    879:     PetscLogEventBegin(ilinkA->event,kspA,ilinkA->x,ilinkA->y,NULL);
    880:     KSPSolve(kspA,ilinkA->x,ilinkA->y);
    881:     PetscLogEventEnd(ilinkA->event,kspA,ilinkA->x,ilinkA->y,NULL);
    882:     MatMult(jac->C,ilinkA->y,ilinkD->x);
    883:     VecScale(ilinkD->x,-1.);
    884:     VecScatterBegin(ilinkD->sctx,x,ilinkD->x,ADD_VALUES,SCATTER_FORWARD);
    885:     VecScatterBegin(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);
    886:     VecScatterEnd(ilinkD->sctx,x,ilinkD->x,ADD_VALUES,SCATTER_FORWARD);
    887:     PetscLogEventBegin(KSP_Solve_FS_S,jac->kspschur,ilinkD->x,ilinkD->y,NULL);
    888:     KSPSolve(jac->kspschur,ilinkD->x,ilinkD->y);
    889:     PetscLogEventEnd(KSP_Solve_FS_S,jac->kspschur,ilinkD->x,ilinkD->y,NULL);
    890:     VecScatterBegin(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);
    891:     VecScatterEnd(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);
    892:     VecScatterEnd(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);
    893:     break;
    894:   case PC_FIELDSPLIT_SCHUR_FACT_UPPER:
    895:     /* [A00 A01; 0 S], suitable for right preconditioning */
    896:     VecScatterBegin(ilinkD->sctx,x,ilinkD->x,INSERT_VALUES,SCATTER_FORWARD);
    897:     VecScatterEnd(ilinkD->sctx,x,ilinkD->x,INSERT_VALUES,SCATTER_FORWARD);
    898:     PetscLogEventBegin(KSP_Solve_FS_S,jac->kspschur,ilinkD->x,ilinkD->y,NULL);
    899:     KSPSolve(jac->kspschur,ilinkD->x,ilinkD->y);
    900:     PetscLogEventEnd(KSP_Solve_FS_S,jac->kspschur,ilinkD->x,ilinkD->y,NULL);    MatMult(jac->B,ilinkD->y,ilinkA->x);
    901:     VecScale(ilinkA->x,-1.);
    902:     VecScatterBegin(ilinkA->sctx,x,ilinkA->x,ADD_VALUES,SCATTER_FORWARD);
    903:     VecScatterBegin(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);
    904:     VecScatterEnd(ilinkA->sctx,x,ilinkA->x,ADD_VALUES,SCATTER_FORWARD);
    905:     PetscLogEventBegin(ilinkA->event,kspA,ilinkA->x,ilinkA->y,NULL);
    906:     KSPSolve(kspA,ilinkA->x,ilinkA->y);
    907:     PetscLogEventEnd(ilinkA->event,kspA,ilinkA->x,ilinkA->y,NULL);
    908:     VecScatterBegin(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);
    909:     VecScatterEnd(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);
    910:     VecScatterEnd(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);
    911:     break;
    912:   case PC_FIELDSPLIT_SCHUR_FACT_FULL:
    913:     /* [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 */
    914:     VecScatterBegin(ilinkA->sctx,x,ilinkA->x,INSERT_VALUES,SCATTER_FORWARD);
    915:     VecScatterEnd(ilinkA->sctx,x,ilinkA->x,INSERT_VALUES,SCATTER_FORWARD);
    916:     PetscLogEventBegin(KSP_Solve_FS_L,kspLower,ilinkA->x,ilinkA->y,NULL);
    917:     KSPSolve(kspLower,ilinkA->x,ilinkA->y);
    918:     PetscLogEventEnd(KSP_Solve_FS_L,kspLower,ilinkA->x,ilinkA->y,NULL);
    919:     MatMult(jac->C,ilinkA->y,ilinkD->x);
    920:     VecScale(ilinkD->x,-1.0);
    921:     VecScatterBegin(ilinkD->sctx,x,ilinkD->x,ADD_VALUES,SCATTER_FORWARD);
    922:     VecScatterEnd(ilinkD->sctx,x,ilinkD->x,ADD_VALUES,SCATTER_FORWARD);

    924:     PetscLogEventBegin(KSP_Solve_FS_S,jac->kspschur,ilinkD->x,ilinkD->y,NULL);
    925:     KSPSolve(jac->kspschur,ilinkD->x,ilinkD->y);
    926:     PetscLogEventEnd(KSP_Solve_FS_S,jac->kspschur,ilinkD->x,ilinkD->y,NULL);
    927:     VecScatterBegin(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);
    928:     VecScatterEnd(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);

    930:     if (kspUpper == kspA) {
    931:       MatMult(jac->B,ilinkD->y,ilinkA->y);
    932:       VecAXPY(ilinkA->x,-1.0,ilinkA->y);
    933:       PetscLogEventBegin(ilinkA->event,kspA,ilinkA->x,ilinkA->y,NULL);
    934:       KSPSolve(kspA,ilinkA->x,ilinkA->y);
    935:       PetscLogEventEnd(ilinkA->event,kspA,ilinkA->x,ilinkA->y,NULL);
    936:     } else {
    937:       PetscLogEventBegin(ilinkA->event,kspA,ilinkA->x,ilinkA->y,NULL);
    938:       KSPSolve(kspA,ilinkA->x,ilinkA->y);
    939:       PetscLogEventEnd(ilinkA->event,kspA,ilinkA->x,ilinkA->y,NULL);
    940:       MatMult(jac->B,ilinkD->y,ilinkA->x);
    941:       PetscLogEventBegin(KSP_Solve_FS_U,kspUpper,ilinkA->x,ilinkA->z,NULL);
    942:       KSPSolve(kspUpper,ilinkA->x,ilinkA->z);
    943:       PetscLogEventEnd(KSP_Solve_FS_U,kspUpper,ilinkA->x,ilinkA->z,NULL);
    944:       VecAXPY(ilinkA->y,-1.0,ilinkA->z);
    945:     }
    946:     VecScatterBegin(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);
    947:     VecScatterEnd(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);
    948:   }
    949:   return(0);
    950: }

    954: static PetscErrorCode PCApply_FieldSplit(PC pc,Vec x,Vec y)
    955: {
    956:   PC_FieldSplit      *jac = (PC_FieldSplit*)pc->data;
    957:   PetscErrorCode     ierr;
    958:   PC_FieldSplitLink  ilink = jac->head;
    959:   PetscInt           cnt,bs;
    960:   KSPConvergedReason reason;

    963:   if (jac->type == PC_COMPOSITE_ADDITIVE) {
    964:     if (jac->defaultsplit) {
    965:       VecGetBlockSize(x,&bs);
    966:       if (jac->bs > 0 && bs != jac->bs) SETERRQ2(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Blocksize of x vector %D does not match fieldsplit blocksize %D",bs,jac->bs);
    967:       VecGetBlockSize(y,&bs);
    968:       if (jac->bs > 0 && bs != jac->bs) SETERRQ2(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Blocksize of y vector %D does not match fieldsplit blocksize %D",bs,jac->bs);
    969:       VecStrideGatherAll(x,jac->x,INSERT_VALUES);
    970:       while (ilink) {
    971:         PetscLogEventBegin(ilink->event,ilink->ksp,ilink->x,ilink->y,NULL);
    972:         KSPSolve(ilink->ksp,ilink->x,ilink->y);
    973:         PetscLogEventEnd(ilink->event,ilink->ksp,ilink->x,ilink->y,NULL);
    974:         KSPGetConvergedReason(ilink->ksp,&reason);
    975:         if (reason == KSP_DIVERGED_PCSETUP_FAILED) {
    976:           pc->failedreason = PC_SUBPC_ERROR;
    977:         }
    978:         ilink = ilink->next;
    979:       }
    980:       VecStrideScatterAll(jac->y,y,INSERT_VALUES);
    981:     } else {
    982:       VecSet(y,0.0);
    983:       while (ilink) {
    984:         FieldSplitSplitSolveAdd(ilink,x,y);
    985:         KSPGetConvergedReason(ilink->ksp,&reason);
    986:         if (reason == KSP_DIVERGED_PCSETUP_FAILED) {
    987:           pc->failedreason = PC_SUBPC_ERROR;
    988:         }
    989:         ilink = ilink->next;
    990:       }
    991:     }
    992:   } else if (jac->type == PC_COMPOSITE_MULTIPLICATIVE && jac->nsplits == 2) {
    993:     VecSet(y,0.0);
    994:     /* solve on first block for first block variables */
    995:     VecScatterBegin(ilink->sctx,x,ilink->x,INSERT_VALUES,SCATTER_FORWARD);
    996:     VecScatterEnd(ilink->sctx,x,ilink->x,INSERT_VALUES,SCATTER_FORWARD);
    997:     PetscLogEventBegin(ilink->event,ilink->ksp,ilink->x,ilink->y,NULL);
    998:     KSPSolve(ilink->ksp,ilink->x,ilink->y);
    999:     PetscLogEventEnd(ilink->event,ilink->ksp,ilink->x,ilink->y,NULL);
    1000:     KSPGetConvergedReason(ilink->ksp,&reason);
    1001:     if (reason == KSP_DIVERGED_PCSETUP_FAILED) {
    1002:       pc->failedreason = PC_SUBPC_ERROR;
    1003:     }
    1004:     VecScatterBegin(ilink->sctx,ilink->y,y,ADD_VALUES,SCATTER_REVERSE);
    1005:     VecScatterEnd(ilink->sctx,ilink->y,y,ADD_VALUES,SCATTER_REVERSE);

    1007:     /* compute the residual only onto second block variables using first block variables */
    1008:     MatMult(jac->Afield[1],ilink->y,ilink->next->x);
    1009:     ilink = ilink->next;
    1010:     VecScale(ilink->x,-1.0);
    1011:     VecScatterBegin(ilink->sctx,x,ilink->x,ADD_VALUES,SCATTER_FORWARD);
    1012:     VecScatterEnd(ilink->sctx,x,ilink->x,ADD_VALUES,SCATTER_FORWARD);

    1014:     /* solve on second block variables */
    1015:     PetscLogEventBegin(ilink->event,ilink->ksp,ilink->x,ilink->y,NULL);
    1016:     KSPSolve(ilink->ksp,ilink->x,ilink->y);
    1017:     PetscLogEventEnd(ilink->event,ilink->ksp,ilink->x,ilink->y,NULL);
    1018:     KSPGetConvergedReason(ilink->ksp,&reason);
    1019:     if (reason == KSP_DIVERGED_PCSETUP_FAILED) {
    1020:       pc->failedreason = PC_SUBPC_ERROR;
    1021:     }
    1022:     VecScatterBegin(ilink->sctx,ilink->y,y,ADD_VALUES,SCATTER_REVERSE);
    1023:     VecScatterEnd(ilink->sctx,ilink->y,y,ADD_VALUES,SCATTER_REVERSE);
    1024:   } else if (jac->type == PC_COMPOSITE_MULTIPLICATIVE || jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
    1025:     if (!jac->w1) {
    1026:       VecDuplicate(x,&jac->w1);
    1027:       VecDuplicate(x,&jac->w2);
    1028:     }
    1029:     VecSet(y,0.0);
    1030:     FieldSplitSplitSolveAdd(ilink,x,y);
    1031:     KSPGetConvergedReason(ilink->ksp,&reason);
    1032:     if (reason == KSP_DIVERGED_PCSETUP_FAILED) {
    1033:       pc->failedreason = PC_SUBPC_ERROR;
    1034:     }
    1035:     cnt  = 1;
    1036:     while (ilink->next) {
    1037:       ilink = ilink->next;
    1038:       /* compute the residual only over the part of the vector needed */
    1039:       MatMult(jac->Afield[cnt++],y,ilink->x);
    1040:       VecScale(ilink->x,-1.0);
    1041:       VecScatterBegin(ilink->sctx,x,ilink->x,ADD_VALUES,SCATTER_FORWARD);
    1042:       VecScatterEnd(ilink->sctx,x,ilink->x,ADD_VALUES,SCATTER_FORWARD);
    1043:       PetscLogEventBegin(ilink->event,ilink->ksp,ilink->x,ilink->y,NULL);
    1044:       KSPSolve(ilink->ksp,ilink->x,ilink->y);
    1045:       PetscLogEventEnd(ilink->event,ilink->ksp,ilink->x,ilink->y,NULL);
    1046:       KSPGetConvergedReason(ilink->ksp,&reason);
    1047:       if (reason == KSP_DIVERGED_PCSETUP_FAILED) {
    1048:         pc->failedreason = PC_SUBPC_ERROR;
    1049:       }
    1050:       VecScatterBegin(ilink->sctx,ilink->y,y,ADD_VALUES,SCATTER_REVERSE);
    1051:       VecScatterEnd(ilink->sctx,ilink->y,y,ADD_VALUES,SCATTER_REVERSE);
    1052:     }
    1053:     if (jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
    1054:       cnt -= 2;
    1055:       while (ilink->previous) {
    1056:         ilink = ilink->previous;
    1057:         /* compute the residual only over the part of the vector needed */
    1058:         MatMult(jac->Afield[cnt--],y,ilink->x);
    1059:         VecScale(ilink->x,-1.0);
    1060:         VecScatterBegin(ilink->sctx,x,ilink->x,ADD_VALUES,SCATTER_FORWARD);
    1061:         VecScatterEnd(ilink->sctx,x,ilink->x,ADD_VALUES,SCATTER_FORWARD);
    1062:         PetscLogEventBegin(ilink->event,ilink->ksp,ilink->x,ilink->y,NULL);
    1063:         KSPSolve(ilink->ksp,ilink->x,ilink->y);
    1064:         PetscLogEventEnd(ilink->event,ilink->ksp,ilink->x,ilink->y,NULL);
    1065:         KSPGetConvergedReason(ilink->ksp,&reason);
    1066:         if (reason == KSP_DIVERGED_PCSETUP_FAILED) {
    1067:           pc->failedreason = PC_SUBPC_ERROR;
    1068:         }
    1069:         VecScatterBegin(ilink->sctx,ilink->y,y,ADD_VALUES,SCATTER_REVERSE);
    1070:         VecScatterEnd(ilink->sctx,ilink->y,y,ADD_VALUES,SCATTER_REVERSE);
    1071:       }
    1072:     }
    1073:   } else SETERRQ1(PetscObjectComm((PetscObject)pc),PETSC_ERR_SUP,"Unsupported or unknown composition",(int) jac->type);
    1074:   return(0);
    1075: }

    1077: #define FieldSplitSplitSolveAddTranspose(ilink,xx,yy) \
    1078:   (VecScatterBegin(ilink->sctx,xx,ilink->y,INSERT_VALUES,SCATTER_FORWARD) || \
    1079:    VecScatterEnd(ilink->sctx,xx,ilink->y,INSERT_VALUES,SCATTER_FORWARD) || \
    1080:    PetscLogEventBegin(ilink->event,ilink->ksp,ilink->y,ilink->x,NULL) || \
    1081:    KSPSolveTranspose(ilink->ksp,ilink->y,ilink->x) ||                  \
    1082:    PetscLogEventBegin(ilink->event,ilink->ksp,ilink->y,ilink->x,NULL) || \
    1083:    VecScatterBegin(ilink->sctx,ilink->x,yy,ADD_VALUES,SCATTER_REVERSE) || \
    1084:    VecScatterEnd(ilink->sctx,ilink->x,yy,ADD_VALUES,SCATTER_REVERSE))

    1088: static PetscErrorCode PCApplyTranspose_FieldSplit(PC pc,Vec x,Vec y)
    1089: {
    1090:   PC_FieldSplit      *jac = (PC_FieldSplit*)pc->data;
    1091:   PetscErrorCode     ierr;
    1092:   PC_FieldSplitLink  ilink = jac->head;
    1093:   PetscInt           bs;
    1094:   KSPConvergedReason reason;

    1097:   if (jac->type == PC_COMPOSITE_ADDITIVE) {
    1098:     if (jac->defaultsplit) {
    1099:       VecGetBlockSize(x,&bs);
    1100:       if (jac->bs > 0 && bs != jac->bs) SETERRQ2(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Blocksize of x vector %D does not match fieldsplit blocksize %D",bs,jac->bs);
    1101:       VecGetBlockSize(y,&bs);
    1102:       if (jac->bs > 0 && bs != jac->bs) SETERRQ2(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Blocksize of y vector %D does not match fieldsplit blocksize %D",bs,jac->bs);
    1103:       VecStrideGatherAll(x,jac->x,INSERT_VALUES);
    1104:       while (ilink) {
    1105:         PetscLogEventBegin(ilink->event,ilink->ksp,ilink->x,ilink->y,NULL);
    1106:         KSPSolveTranspose(ilink->ksp,ilink->x,ilink->y);
    1107:         PetscLogEventEnd(ilink->event,ilink->ksp,ilink->x,ilink->y,NULL);
    1108:         KSPGetConvergedReason(ilink->ksp,&reason);
    1109:         if (reason == KSP_DIVERGED_PCSETUP_FAILED) {
    1110:           pc->failedreason = PC_SUBPC_ERROR;
    1111:         }
    1112:         ilink = ilink->next;
    1113:       }
    1114:       VecStrideScatterAll(jac->y,y,INSERT_VALUES);
    1115:     } else {
    1116:       VecSet(y,0.0);
    1117:       while (ilink) {
    1118:         FieldSplitSplitSolveAddTranspose(ilink,x,y);
    1119:         KSPGetConvergedReason(ilink->ksp,&reason);
    1120:         if (reason == KSP_DIVERGED_PCSETUP_FAILED) {
    1121:           pc->failedreason = PC_SUBPC_ERROR;
    1122:         }
    1123:         ilink = ilink->next;
    1124:       }
    1125:     }
    1126:   } else {
    1127:     if (!jac->w1) {
    1128:       VecDuplicate(x,&jac->w1);
    1129:       VecDuplicate(x,&jac->w2);
    1130:     }
    1131:     VecSet(y,0.0);
    1132:     if (jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
    1133:       FieldSplitSplitSolveAddTranspose(ilink,x,y);
    1134:       KSPGetConvergedReason(ilink->ksp,&reason);
    1135:       if (reason == KSP_DIVERGED_PCSETUP_FAILED) {
    1136:         pc->failedreason = PC_SUBPC_ERROR;
    1137:       }
    1138:       while (ilink->next) {
    1139:         ilink = ilink->next;
    1140:         MatMultTranspose(pc->mat,y,jac->w1);
    1141:         VecWAXPY(jac->w2,-1.0,jac->w1,x);
    1142:         FieldSplitSplitSolveAddTranspose(ilink,jac->w2,y);
    1143:       }
    1144:       while (ilink->previous) {
    1145:         ilink = ilink->previous;
    1146:         MatMultTranspose(pc->mat,y,jac->w1);
    1147:         VecWAXPY(jac->w2,-1.0,jac->w1,x);
    1148:         FieldSplitSplitSolveAddTranspose(ilink,jac->w2,y);
    1149:       }
    1150:     } else {
    1151:       while (ilink->next) {   /* get to last entry in linked list */
    1152:         ilink = ilink->next;
    1153:       }
    1154:       FieldSplitSplitSolveAddTranspose(ilink,x,y);
    1155:       KSPGetConvergedReason(ilink->ksp,&reason);
    1156:       if (reason == KSP_DIVERGED_PCSETUP_FAILED) {
    1157:         pc->failedreason = PC_SUBPC_ERROR;
    1158:       }
    1159:       while (ilink->previous) {
    1160:         ilink = ilink->previous;
    1161:         MatMultTranspose(pc->mat,y,jac->w1);
    1162:         VecWAXPY(jac->w2,-1.0,jac->w1,x);
    1163:         FieldSplitSplitSolveAddTranspose(ilink,jac->w2,y);
    1164:       }
    1165:     }
    1166:   }
    1167:   return(0);
    1168: }

    1172: static PetscErrorCode PCReset_FieldSplit(PC pc)
    1173: {
    1174:   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
    1175:   PetscErrorCode    ierr;
    1176:   PC_FieldSplitLink ilink = jac->head,next;

    1179:   while (ilink) {
    1180:     KSPReset(ilink->ksp);
    1181:     VecDestroy(&ilink->x);
    1182:     VecDestroy(&ilink->y);
    1183:     VecDestroy(&ilink->z);
    1184:     VecScatterDestroy(&ilink->sctx);
    1185:     if (!ilink->is_orig) {             /* save the original IS */
    1186:       PetscObjectReference((PetscObject)ilink->is);
    1187:       ilink->is_orig = ilink->is;
    1188:     }
    1189:     ISDestroy(&ilink->is);
    1190:     ISDestroy(&ilink->is_col);
    1191:     next  = ilink->next;
    1192:     ilink = next;
    1193:   }
    1194:   PetscFree2(jac->x,jac->y);
    1195:   if (jac->mat && jac->mat != jac->pmat) {
    1196:     MatDestroyMatrices(jac->nsplits,&jac->mat);
    1197:   } else if (jac->mat) {
    1198:     jac->mat = NULL;
    1199:   }
    1200:   if (jac->pmat) {MatDestroyMatrices(jac->nsplits,&jac->pmat);}
    1201:   if (jac->Afield) {MatDestroyMatrices(jac->nsplits,&jac->Afield);}
    1202:   VecDestroy(&jac->w1);
    1203:   VecDestroy(&jac->w2);
    1204:   MatDestroy(&jac->schur);
    1205:   MatDestroy(&jac->schurp);
    1206:   MatDestroy(&jac->schur_user);
    1207:   KSPDestroy(&jac->kspschur);
    1208:   KSPDestroy(&jac->kspupper);
    1209:   MatDestroy(&jac->B);
    1210:   MatDestroy(&jac->C);
    1211:   jac->reset = PETSC_TRUE;
    1212:   jac->isrestrict = PETSC_FALSE;
    1213:   return(0);
    1214: }

    1218: static PetscErrorCode PCDestroy_FieldSplit(PC pc)
    1219: {
    1220:   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
    1221:   PetscErrorCode    ierr;
    1222:   PC_FieldSplitLink ilink = jac->head,next;

    1225:   PCReset_FieldSplit(pc);
    1226:   while (ilink) {
    1227:     KSPDestroy(&ilink->ksp);
    1228:     ISDestroy(&ilink->is_orig);
    1229:     next  = ilink->next;
    1230:     PetscFree(ilink->splitname);
    1231:     PetscFree(ilink->fields);
    1232:     PetscFree(ilink->fields_col);
    1233:     PetscFree(ilink);
    1234:     ilink = next;
    1235:   }
    1236:   PetscFree2(jac->x,jac->y);
    1237:   PetscFree(pc->data);
    1238:   PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitGetSubKSP_C",NULL);
    1239:   PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitSetFields_C",NULL);
    1240:   PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitSetIS_C",NULL);
    1241:   PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitSetType_C",NULL);
    1242:   PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitSetBlockSize_C",NULL);
    1243:   PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitSetSchurPre_C",NULL);
    1244:   PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitGetSchurPre_C",NULL);
    1245:   PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitSetSchurFactType_C",NULL);
    1246:   PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitRestrictIS_C",NULL);
    1247:   return(0);
    1248: }

    1252: static PetscErrorCode PCSetFromOptions_FieldSplit(PetscOptionItems *PetscOptionsObject,PC pc)
    1253: {
    1254:   PetscErrorCode  ierr;
    1255:   PetscInt        bs;
    1256:   PetscBool       flg,stokes = PETSC_FALSE;
    1257:   PC_FieldSplit   *jac = (PC_FieldSplit*)pc->data;
    1258:   PCCompositeType ctype;

    1261:   PetscOptionsHead(PetscOptionsObject,"FieldSplit options");
    1262:   PetscOptionsBool("-pc_fieldsplit_dm_splits","Whether to use DMCreateFieldDecomposition() for splits","PCFieldSplitSetDMSplits",jac->dm_splits,&jac->dm_splits,NULL);
    1263:   PetscOptionsInt("-pc_fieldsplit_block_size","Blocksize that defines number of fields","PCFieldSplitSetBlockSize",jac->bs,&bs,&flg);
    1264:   if (flg) {
    1265:     PCFieldSplitSetBlockSize(pc,bs);
    1266:   }
    1267:   jac->diag_use_amat = pc->useAmat;
    1268:   PetscOptionsBool("-pc_fieldsplit_diag_use_amat","Use Amat (not Pmat) to extract diagonal fieldsplit blocks", "PCFieldSplitSetDiagUseAmat",jac->diag_use_amat,&jac->diag_use_amat,NULL);
    1269:   jac->offdiag_use_amat = pc->useAmat;
    1270:   PetscOptionsBool("-pc_fieldsplit_off_diag_use_amat","Use Amat (not Pmat) to extract off-diagonal fieldsplit blocks", "PCFieldSplitSetOffDiagUseAmat",jac->offdiag_use_amat,&jac->offdiag_use_amat,NULL);
    1271:   /* FIXME: No programmatic equivalent to the following. */
    1272:   PetscOptionsGetBool(((PetscObject)pc)->options,((PetscObject)pc)->prefix,"-pc_fieldsplit_detect_saddle_point",&stokes,NULL);
    1273:   if (stokes) {
    1274:     PCFieldSplitSetType(pc,PC_COMPOSITE_SCHUR);
    1275:     jac->schurpre = PC_FIELDSPLIT_SCHUR_PRE_SELF;
    1276:   }

    1278:   PetscOptionsEnum("-pc_fieldsplit_type","Type of composition","PCFieldSplitSetType",PCCompositeTypes,(PetscEnum)jac->type,(PetscEnum*)&ctype,&flg);
    1279:   if (flg) {
    1280:     PCFieldSplitSetType(pc,ctype);
    1281:   }
    1282:   /* Only setup fields once */
    1283:   if ((jac->bs > 0) && (jac->nsplits == 0)) {
    1284:     /* only allow user to set fields from command line if bs is already known.
    1285:        otherwise user can set them in PCFieldSplitSetDefaults() */
    1286:     PCFieldSplitSetRuntimeSplits_Private(pc);
    1287:     if (jac->splitdefined) {PetscInfo(pc,"Splits defined using the options database\n");}
    1288:   }
    1289:   if (jac->type == PC_COMPOSITE_SCHUR) {
    1290:     PetscOptionsGetEnum(((PetscObject)pc)->options,((PetscObject)pc)->prefix,"-pc_fieldsplit_schur_factorization_type",PCFieldSplitSchurFactTypes,(PetscEnum*)&jac->schurfactorization,&flg);
    1291:     if (flg) {PetscInfo(pc,"Deprecated use of -pc_fieldsplit_schur_factorization_type\n");}
    1292:     PetscOptionsEnum("-pc_fieldsplit_schur_fact_type","Which off-diagonal parts of the block factorization to use","PCFieldSplitSetSchurFactType",PCFieldSplitSchurFactTypes,(PetscEnum)jac->schurfactorization,(PetscEnum*)&jac->schurfactorization,NULL);
    1293:     PetscOptionsEnum("-pc_fieldsplit_schur_precondition","How to build preconditioner for Schur complement","PCFieldSplitSetSchurPre",PCFieldSplitSchurPreTypes,(PetscEnum)jac->schurpre,(PetscEnum*)&jac->schurpre,NULL);
    1294:   }
    1295:   PetscOptionsTail();
    1296:   return(0);
    1297: }

    1299: /*------------------------------------------------------------------------------------*/

    1303: static PetscErrorCode  PCFieldSplitSetFields_FieldSplit(PC pc,const char splitname[],PetscInt n,const PetscInt *fields,const PetscInt *fields_col)
    1304: {
    1305:   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
    1306:   PetscErrorCode    ierr;
    1307:   PC_FieldSplitLink ilink,next = jac->head;
    1308:   char              prefix[128];
    1309:   PetscInt          i;

    1312:   if (jac->splitdefined) {
    1313:     PetscInfo1(pc,"Ignoring new split \"%s\" because the splits have already been defined\n",splitname);
    1314:     return(0);
    1315:   }
    1316:   for (i=0; i<n; i++) {
    1317:     if (fields[i] >= jac->bs) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Field %D requested but only %D exist",fields[i],jac->bs);
    1318:     if (fields[i] < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Negative field %D requested",fields[i]);
    1319:   }
    1320:   PetscNew(&ilink);
    1321:   if (splitname) {
    1322:     PetscStrallocpy(splitname,&ilink->splitname);
    1323:   } else {
    1324:     PetscMalloc1(3,&ilink->splitname);
    1325:     PetscSNPrintf(ilink->splitname,2,"%s",jac->nsplits);
    1326:   }
    1327:   ilink->event = jac->nsplits < 5 ? KSP_Solve_FS_0 + jac->nsplits : KSP_Solve_FS_0 + 4; /* Any split great than 4 gets logged in the 4th split */
    1328:   PetscMalloc1(n,&ilink->fields);
    1329:   PetscMemcpy(ilink->fields,fields,n*sizeof(PetscInt));
    1330:   PetscMalloc1(n,&ilink->fields_col);
    1331:   PetscMemcpy(ilink->fields_col,fields_col,n*sizeof(PetscInt));

    1333:   ilink->nfields = n;
    1334:   ilink->next    = NULL;
    1335:   KSPCreate(PetscObjectComm((PetscObject)pc),&ilink->ksp);
    1336:   KSPSetErrorIfNotConverged(ilink->ksp,pc->erroriffailure);
    1337:   PetscObjectIncrementTabLevel((PetscObject)ilink->ksp,(PetscObject)pc,1);
    1338:   KSPSetType(ilink->ksp,KSPPREONLY);
    1339:   PetscLogObjectParent((PetscObject)pc,(PetscObject)ilink->ksp);

    1341:   PetscSNPrintf(prefix,sizeof(prefix),"%sfieldsplit_%s_",((PetscObject)pc)->prefix ? ((PetscObject)pc)->prefix : "",ilink->splitname);
    1342:   KSPSetOptionsPrefix(ilink->ksp,prefix);

    1344:   if (!next) {
    1345:     jac->head       = ilink;
    1346:     ilink->previous = NULL;
    1347:   } else {
    1348:     while (next->next) {
    1349:       next = next->next;
    1350:     }
    1351:     next->next      = ilink;
    1352:     ilink->previous = next;
    1353:   }
    1354:   jac->nsplits++;
    1355:   return(0);
    1356: }

    1360: static PetscErrorCode  PCFieldSplitGetSubKSP_FieldSplit_Schur(PC pc,PetscInt *n,KSP **subksp)
    1361: {
    1362:   PC_FieldSplit  *jac = (PC_FieldSplit*)pc->data;

    1366:   PetscMalloc1(jac->nsplits,subksp);
    1367:   MatSchurComplementGetKSP(jac->schur,*subksp);

    1369:   (*subksp)[1] = jac->kspschur;
    1370:   if (n) *n = jac->nsplits;
    1371:   return(0);
    1372: }

    1376: static PetscErrorCode  PCFieldSplitGetSubKSP_FieldSplit(PC pc,PetscInt *n,KSP **subksp)
    1377: {
    1378:   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
    1379:   PetscErrorCode    ierr;
    1380:   PetscInt          cnt   = 0;
    1381:   PC_FieldSplitLink ilink = jac->head;

    1384:   PetscMalloc1(jac->nsplits,subksp);
    1385:   while (ilink) {
    1386:     (*subksp)[cnt++] = ilink->ksp;
    1387:     ilink            = ilink->next;
    1388:   }
    1389:   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);
    1390:   if (n) *n = jac->nsplits;
    1391:   return(0);
    1392: }

    1396: /*@C
    1397:     PCFieldSplitRestrictIS - Restricts the fieldsplit ISs to be within a given IS.

    1399:     Input Parameters:
    1400: +   pc  - the preconditioner context
    1401: +   is - the index set that defines the indices to which the fieldsplit is to be restricted

    1403:     Level: advanced

    1405: @*/
    1406: PetscErrorCode  PCFieldSplitRestrictIS(PC pc,IS isy)
    1407: {

    1413:   PetscTryMethod(pc,"PCFieldSplitRestrictIS_C",(PC,IS),(pc,isy));
    1414:   return(0);
    1415: }

    1420: static PetscErrorCode  PCFieldSplitRestrictIS_FieldSplit(PC pc, IS isy)
    1421: {
    1422:   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
    1423:   PetscErrorCode    ierr;
    1424:   PC_FieldSplitLink ilink = jac->head, next;
    1425:   PetscInt          localsize,size,sizez,i;
    1426:   const PetscInt    *ind, *indz;
    1427:   PetscInt          *indc, *indcz;
    1428:   PetscBool         flg;

    1431:   ISGetLocalSize(isy,&localsize);
    1432:   MPI_Scan(&localsize,&size,1,MPIU_INT,MPI_SUM,PetscObjectComm((PetscObject)isy));
    1433:   size -= localsize;
    1434:   while(ilink) {
    1435:     IS isrl,isr;
    1436:     PC subpc;
    1437:     if (jac->reset) {
    1438:       ISEmbed(ilink->is_orig, isy, PETSC_TRUE, &isrl);
    1439:     } else {
    1440:       ISEmbed(ilink->is, isy, PETSC_TRUE, &isrl);
    1441:     }
    1442:     ISGetLocalSize(isrl,&localsize);
    1443:     PetscMalloc1(localsize,&indc);
    1444:     ISGetIndices(isrl,&ind);
    1445:     PetscMemcpy(indc,ind,localsize*sizeof(PetscInt));
    1446:     ISRestoreIndices(isrl,&ind);
    1447:     ISDestroy(&isrl);
    1448:     for (i=0; i<localsize; i++) *(indc+i) += size;
    1449:     ISCreateGeneral(PetscObjectComm((PetscObject)isy),localsize,indc,PETSC_OWN_POINTER,&isr);
    1450:     PetscObjectReference((PetscObject)isr);
    1451:     ISDestroy(&ilink->is);
    1452:     ilink->is     = isr;
    1453:     PetscObjectReference((PetscObject)isr);
    1454:     ISDestroy(&ilink->is_col);
    1455:     ilink->is_col = isr;
    1456:     ISDestroy(&isr);
    1457:     KSPGetPC(ilink->ksp, &subpc);
    1458:     PetscObjectTypeCompare((PetscObject)subpc,PCFIELDSPLIT,&flg);
    1459:     if(flg) {
    1460:       IS iszl,isz;
    1461:       MPI_Comm comm;
    1462:       if (jac->reset) {
    1463:         ISGetLocalSize(ilink->is_orig,&localsize);
    1464:         comm = PetscObjectComm((PetscObject)ilink->is_orig);
    1465:         ISEmbed(isy, ilink->is_orig, PETSC_TRUE, &iszl);
    1466:       } else {
    1467:         ISGetLocalSize(ilink->is,&localsize);
    1468:         comm = PetscObjectComm((PetscObject)ilink->is);
    1469:         ISEmbed(isy, ilink->is, PETSC_TRUE, &iszl);
    1470:       }
    1471:       MPI_Scan(&localsize,&sizez,1,MPIU_INT,MPI_SUM,comm);
    1472:       sizez -= localsize;
    1473:       ISGetLocalSize(iszl,&localsize);
    1474:       PetscMalloc1(localsize,&indcz);
    1475:       ISGetIndices(iszl,&indz);
    1476:       PetscMemcpy(indcz,indz,localsize*sizeof(PetscInt));
    1477:       ISRestoreIndices(iszl,&indz);
    1478:       ISDestroy(&iszl);
    1479:       for (i=0; i<localsize; i++) *(indcz+i) += sizez;
    1480:       ISCreateGeneral(comm,localsize,indcz,PETSC_OWN_POINTER,&isz);
    1481:       PCFieldSplitRestrictIS(subpc,isz);
    1482:       ISDestroy(&isz);
    1483:     }
    1484:     next = ilink->next;
    1485:     ilink = next;
    1486:   }
    1487:   jac->isrestrict = PETSC_TRUE;
    1488:   return(0);
    1489: }

    1493: static PetscErrorCode  PCFieldSplitSetIS_FieldSplit(PC pc,const char splitname[],IS is)
    1494: {
    1495:   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
    1496:   PetscErrorCode    ierr;
    1497:   PC_FieldSplitLink ilink, next = jac->head;
    1498:   char              prefix[128];

    1501:   if (jac->splitdefined) {
    1502:     PetscInfo1(pc,"Ignoring new split \"%s\" because the splits have already been defined\n",splitname);
    1503:     return(0);
    1504:   }
    1505:   PetscNew(&ilink);
    1506:   if (splitname) {
    1507:     PetscStrallocpy(splitname,&ilink->splitname);
    1508:   } else {
    1509:     PetscMalloc1(8,&ilink->splitname);
    1510:     PetscSNPrintf(ilink->splitname,7,"%D",jac->nsplits);
    1511:   }
    1512:   ilink->event = jac->nsplits < 5 ? KSP_Solve_FS_0 + jac->nsplits : KSP_Solve_FS_0 + 4; /* Any split great than 4 gets logged in the 4th split */
    1513:   PetscObjectReference((PetscObject)is);
    1514:   ISDestroy(&ilink->is);
    1515:   ilink->is     = is;
    1516:   PetscObjectReference((PetscObject)is);
    1517:   ISDestroy(&ilink->is_col);
    1518:   ilink->is_col = is;
    1519:   ilink->next   = NULL;
    1520:   KSPCreate(PetscObjectComm((PetscObject)pc),&ilink->ksp);
    1521:   KSPSetErrorIfNotConverged(ilink->ksp,pc->erroriffailure);
    1522:   PetscObjectIncrementTabLevel((PetscObject)ilink->ksp,(PetscObject)pc,1);
    1523:   KSPSetType(ilink->ksp,KSPPREONLY);
    1524:   PetscLogObjectParent((PetscObject)pc,(PetscObject)ilink->ksp);

    1526:   PetscSNPrintf(prefix,sizeof(prefix),"%sfieldsplit_%s_",((PetscObject)pc)->prefix ? ((PetscObject)pc)->prefix : "",ilink->splitname);
    1527:   KSPSetOptionsPrefix(ilink->ksp,prefix);

    1529:   if (!next) {
    1530:     jac->head       = ilink;
    1531:     ilink->previous = NULL;
    1532:   } else {
    1533:     while (next->next) {
    1534:       next = next->next;
    1535:     }
    1536:     next->next      = ilink;
    1537:     ilink->previous = next;
    1538:   }
    1539:   jac->nsplits++;
    1540:   return(0);
    1541: }

    1545: /*@
    1546:     PCFieldSplitSetFields - Sets the fields for one particular split in the field split preconditioner

    1548:     Logically Collective on PC

    1550:     Input Parameters:
    1551: +   pc  - the preconditioner context
    1552: .   splitname - name of this split, if NULL the number of the split is used
    1553: .   n - the number of fields in this split
    1554: -   fields - the fields in this split

    1556:     Level: intermediate

    1558:     Notes: Use PCFieldSplitSetIS() to set a completely general set of indices as a field.

    1560:      The PCFieldSplitSetFields() is for defining fields as strided blocks. For example, if the block
    1561:      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
    1562:      0xx3xx6xx9xx12 ... x1xx4xx7xx ... xx2xx5xx8xx.. 01x34x67x... 0x1x3x5x7.. x12x45x78x....
    1563:      where the numbered entries indicate what is in the field.

    1565:      This function is called once per split (it creates a new split each time).  Solve options
    1566:      for this split will be available under the prefix -fieldsplit_SPLITNAME_.

    1568:      Developer Note: This routine does not actually create the IS representing the split, that is delayed
    1569:      until PCSetUp_FieldSplit(), because information about the vector/matrix layouts may not be
    1570:      available when this routine is called.

    1572: .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetBlockSize(), PCFieldSplitSetIS()

    1574: @*/
    1575: PetscErrorCode  PCFieldSplitSetFields(PC pc,const char splitname[],PetscInt n,const PetscInt *fields,const PetscInt *fields_col)
    1576: {

    1582:   if (n < 1) SETERRQ2(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_OUTOFRANGE,"Provided number of fields %D in split \"%s\" not positive",n,splitname);
    1584:   PetscTryMethod(pc,"PCFieldSplitSetFields_C",(PC,const char[],PetscInt,const PetscInt*,const PetscInt*),(pc,splitname,n,fields,fields_col));
    1585:   return(0);
    1586: }

    1590: /*@
    1591:     PCFieldSplitSetDiagUseAmat - set flag indicating whether to extract diagonal blocks from Amat (rather than Pmat)

    1593:     Logically Collective on PC

    1595:     Input Parameters:
    1596: +   pc  - the preconditioner object
    1597: -   flg - boolean flag indicating whether or not to use Amat to extract the diagonal blocks from

    1599:     Options Database:
    1600: .     -pc_fieldsplit_diag_use_amat

    1602:     Level: intermediate

    1604: .seealso: PCFieldSplitGetDiagUseAmat(), PCFieldSplitSetOffDiagUseAmat(), PCFIELDSPLIT

    1606: @*/
    1607: PetscErrorCode  PCFieldSplitSetDiagUseAmat(PC pc,PetscBool flg)
    1608: {
    1609:   PC_FieldSplit  *jac = (PC_FieldSplit*)pc->data;
    1610:   PetscBool      isfs;

    1615:   PetscObjectTypeCompare((PetscObject)pc,PCFIELDSPLIT,&isfs);
    1616:   if (!isfs) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"PC not of type %s",PCFIELDSPLIT);
    1617:   jac->diag_use_amat = flg;
    1618:   return(0);
    1619: }

    1623: /*@
    1624:     PCFieldSplitGetDiagUseAmat - get the flag indicating whether to extract diagonal blocks from Amat (rather than Pmat)

    1626:     Logically Collective on PC

    1628:     Input Parameters:
    1629: .   pc  - the preconditioner object

    1631:     Output Parameters:
    1632: .   flg - boolean flag indicating whether or not to use Amat to extract the diagonal blocks from

    1635:     Level: intermediate

    1637: .seealso: PCFieldSplitSetDiagUseAmat(), PCFieldSplitGetOffDiagUseAmat(), PCFIELDSPLIT

    1639: @*/
    1640: PetscErrorCode  PCFieldSplitGetDiagUseAmat(PC pc,PetscBool *flg)
    1641: {
    1642:   PC_FieldSplit  *jac = (PC_FieldSplit*)pc->data;
    1643:   PetscBool      isfs;

    1649:   PetscObjectTypeCompare((PetscObject)pc,PCFIELDSPLIT,&isfs);
    1650:   if (!isfs) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"PC not of type %s",PCFIELDSPLIT);
    1651:   *flg = jac->diag_use_amat;
    1652:   return(0);
    1653: }

    1657: /*@
    1658:     PCFieldSplitSetOffDiagUseAmat - set flag indicating whether to extract off-diagonal blocks from Amat (rather than Pmat)

    1660:     Logically Collective on PC

    1662:     Input Parameters:
    1663: +   pc  - the preconditioner object
    1664: -   flg - boolean flag indicating whether or not to use Amat to extract the off-diagonal blocks from

    1666:     Options Database:
    1667: .     -pc_fieldsplit_off_diag_use_amat

    1669:     Level: intermediate

    1671: .seealso: PCFieldSplitGetOffDiagUseAmat(), PCFieldSplitSetDiagUseAmat(), PCFIELDSPLIT

    1673: @*/
    1674: PetscErrorCode  PCFieldSplitSetOffDiagUseAmat(PC pc,PetscBool flg)
    1675: {
    1676:   PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
    1677:   PetscBool      isfs;

    1682:   PetscObjectTypeCompare((PetscObject)pc,PCFIELDSPLIT,&isfs);
    1683:   if (!isfs) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"PC not of type %s",PCFIELDSPLIT);
    1684:   jac->offdiag_use_amat = flg;
    1685:   return(0);
    1686: }

    1690: /*@
    1691:     PCFieldSplitGetOffDiagUseAmat - get the flag indicating whether to extract off-diagonal blocks from Amat (rather than Pmat)

    1693:     Logically Collective on PC

    1695:     Input Parameters:
    1696: .   pc  - the preconditioner object

    1698:     Output Parameters:
    1699: .   flg - boolean flag indicating whether or not to use Amat to extract the off-diagonal blocks from

    1702:     Level: intermediate

    1704: .seealso: PCFieldSplitSetOffDiagUseAmat(), PCFieldSplitGetDiagUseAmat(), PCFIELDSPLIT

    1706: @*/
    1707: PetscErrorCode  PCFieldSplitGetOffDiagUseAmat(PC pc,PetscBool *flg)
    1708: {
    1709:   PC_FieldSplit  *jac = (PC_FieldSplit*)pc->data;
    1710:   PetscBool      isfs;

    1716:   PetscObjectTypeCompare((PetscObject)pc,PCFIELDSPLIT,&isfs);
    1717:   if (!isfs) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"PC not of type %s",PCFIELDSPLIT);
    1718:   *flg = jac->offdiag_use_amat;
    1719:   return(0);
    1720: }

    1726: /*@C
    1727:     PCFieldSplitSetIS - Sets the exact elements for field

    1729:     Logically Collective on PC

    1731:     Input Parameters:
    1732: +   pc  - the preconditioner context
    1733: .   splitname - name of this split, if NULL the number of the split is used
    1734: -   is - the index set that defines the vector elements in this field

    1737:     Notes:
    1738:     Use PCFieldSplitSetFields(), for fields defined by strided types.

    1740:     This function is called once per split (it creates a new split each time).  Solve options
    1741:     for this split will be available under the prefix -fieldsplit_SPLITNAME_.

    1743:     Level: intermediate

    1745: .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetBlockSize()

    1747: @*/
    1748: PetscErrorCode  PCFieldSplitSetIS(PC pc,const char splitname[],IS is)
    1749: {

    1756:   PetscUseMethod(pc,"PCFieldSplitSetIS_C",(PC,const char[],IS),(pc,splitname,is));
    1757:   return(0);
    1758: }

    1762: /*@
    1763:     PCFieldSplitGetIS - Retrieves the elements for a field as an IS

    1765:     Logically Collective on PC

    1767:     Input Parameters:
    1768: +   pc  - the preconditioner context
    1769: -   splitname - name of this split

    1771:     Output Parameter:
    1772: -   is - the index set that defines the vector elements in this field, or NULL if the field is not found

    1774:     Level: intermediate

    1776: .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetIS()

    1778: @*/
    1779: PetscErrorCode PCFieldSplitGetIS(PC pc,const char splitname[],IS *is)
    1780: {

    1787:   {
    1788:     PC_FieldSplit     *jac  = (PC_FieldSplit*) pc->data;
    1789:     PC_FieldSplitLink ilink = jac->head;
    1790:     PetscBool         found;

    1792:     *is = NULL;
    1793:     while (ilink) {
    1794:       PetscStrcmp(ilink->splitname, splitname, &found);
    1795:       if (found) {
    1796:         *is = ilink->is;
    1797:         break;
    1798:       }
    1799:       ilink = ilink->next;
    1800:     }
    1801:   }
    1802:   return(0);
    1803: }

    1807: /*@
    1808:     PCFieldSplitSetBlockSize - Sets the block size for defining where fields start in the
    1809:       fieldsplit preconditioner. If not set the matrix block size is used.

    1811:     Logically Collective on PC

    1813:     Input Parameters:
    1814: +   pc  - the preconditioner context
    1815: -   bs - the block size

    1817:     Level: intermediate

    1819: .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetFields()

    1821: @*/
    1822: PetscErrorCode  PCFieldSplitSetBlockSize(PC pc,PetscInt bs)
    1823: {

    1829:   PetscTryMethod(pc,"PCFieldSplitSetBlockSize_C",(PC,PetscInt),(pc,bs));
    1830:   return(0);
    1831: }

    1835: /*@C
    1836:    PCFieldSplitGetSubKSP - Gets the KSP contexts for all splits

    1838:    Collective on KSP

    1840:    Input Parameter:
    1841: .  pc - the preconditioner context

    1843:    Output Parameters:
    1844: +  n - the number of splits
    1845: -  pc - the array of KSP contexts

    1847:    Note:
    1848:    After PCFieldSplitGetSubKSP() the array of KSPs IS to be freed by the user
    1849:    (not the KSP just the array that contains them).

    1851:    You must call KSPSetUp() before calling PCFieldSplitGetSubKSP().

    1853:    Fortran Usage: You must pass in a KSP array that is large enough to contain all the local KSPs.
    1854:       You can call PCFieldSplitGetSubKSP(pc,n,NULL_OBJECT,ierr) to determine how large the
    1855:       KSP array must be.

    1858:    Level: advanced

    1860: .seealso: PCFIELDSPLIT
    1861: @*/
    1862: PetscErrorCode  PCFieldSplitGetSubKSP(PC pc,PetscInt *n,KSP *subksp[])
    1863: {

    1869:   PetscUseMethod(pc,"PCFieldSplitGetSubKSP_C",(PC,PetscInt*,KSP **),(pc,n,subksp));
    1870:   return(0);
    1871: }

    1875: /*@
    1876:     PCFieldSplitSetSchurPre -  Indicates if the Schur complement is preconditioned by a preconditioner constructed by the
    1877:       A11 matrix. Otherwise no preconditioner is used.

    1879:     Collective on PC

    1881:     Input Parameters:
    1882: +   pc      - the preconditioner context
    1883: .   ptype   - which matrix to use for preconditioning the Schur complement: PC_FIELDSPLIT_SCHUR_PRE_A11 (default), PC_FIELDSPLIT_SCHUR_PRE_SELF, PC_FIELDSPLIT_PRE_USER
    1884: -   userpre - matrix to use for preconditioning, or NULL

    1886:     Options Database:
    1887: .     -pc_fieldsplit_schur_precondition <self,selfp,user,a11,full> default is a11

    1889:     Notes:
    1890: $    If ptype is
    1891: $        user then the preconditioner for the Schur complement is generated from the user provided matrix (pre argument
    1892: $             to this function).
    1893: $        a11 then the preconditioner for the Schur complement is generated from the block diagonal part of the preconditioner
    1894: $             matrix associated with the Schur complement (i.e. A11), not he Schur complement matrix
    1895: $        full then the preconditioner for the Schur complement is generated from the exact Schur complement matrix representation computed internally by PFIELDSPLIT (this is expensive)
    1896: $        self the preconditioner for the Schur complement is generated from the symbolic representation of the Schur complement matrix:
    1897: $             The only preconditioner that currently works with this symbolic respresentation matrix object is the PCLSC
    1898: $             preconditioner
    1899: $        selfp then the preconditioning for the Schur complement is generated from an explicitly-assembled approximation Sp = A11 - A10 inv(diag(A00)) A01
    1900: $             This is only a good preconditioner when diag(A00) is a good preconditioner for A00. Optionally, A00 can be
    1901: $             lumped before extracting the diagonal: -fieldsplit_1_mat_schur_complement_ainv_type lump

    1903:      When solving a saddle point problem, where the A11 block is identically zero, using a11 as the ptype only makes sense
    1904:     with the additional option -fieldsplit_1_pc_type none. Usually for saddle point problems one would use a ptype of self and
    1905:     -fieldsplit_1_pc_type lsc which uses the least squares commutator to compute a preconditioner for the Schur complement.

    1907:     Level: intermediate

    1909: .seealso: PCFieldSplitGetSchurPre(), PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetFields(), PCFieldSplitSchurPreType,
    1910:           MatSchurComplementSetAinvType(), PCLSC

    1912: @*/
    1913: PetscErrorCode PCFieldSplitSetSchurPre(PC pc,PCFieldSplitSchurPreType ptype,Mat pre)
    1914: {

    1919:   PetscTryMethod(pc,"PCFieldSplitSetSchurPre_C",(PC,PCFieldSplitSchurPreType,Mat),(pc,ptype,pre));
    1920:   return(0);
    1921: }
    1922: PetscErrorCode PCFieldSplitSchurPrecondition(PC pc,PCFieldSplitSchurPreType ptype,Mat pre) {return PCFieldSplitSetSchurPre(pc,ptype,pre);} /* Deprecated name */

    1926: /*@
    1927:     PCFieldSplitGetSchurPre - For Schur complement fieldsplit, determine how the Schur complement will be
    1928:     preconditioned.  See PCFieldSplitSetSchurPre() for details.

    1930:     Logically Collective on PC

    1932:     Input Parameters:
    1933: .   pc      - the preconditioner context

    1935:     Output Parameters:
    1936: +   ptype   - which matrix to use for preconditioning the Schur complement: PC_FIELDSPLIT_SCHUR_PRE_A11, PC_FIELDSPLIT_SCHUR_PRE_SELF, PC_FIELDSPLIT_PRE_USER
    1937: -   userpre - matrix to use for preconditioning (with PC_FIELDSPLIT_PRE_USER), or NULL

    1939:     Level: intermediate

    1941: .seealso: PCFieldSplitSetSchurPre(), PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetFields(), PCFieldSplitSchurPreType, PCLSC

    1943: @*/
    1944: PetscErrorCode PCFieldSplitGetSchurPre(PC pc,PCFieldSplitSchurPreType *ptype,Mat *pre)
    1945: {

    1950:   PetscUseMethod(pc,"PCFieldSplitGetSchurPre_C",(PC,PCFieldSplitSchurPreType*,Mat*),(pc,ptype,pre));
    1951:   return(0);
    1952: }

    1956: /*@
    1957:     PCFieldSplitSchurGetS -  extract the MatSchurComplement object used by this PC in case it needs to be configured separately

    1959:     Not collective

    1961:     Input Parameter:
    1962: .   pc      - the preconditioner context

    1964:     Output Parameter:
    1965: .   S       - the Schur complement matrix

    1967:     Notes:
    1968:     This matrix should not be destroyed using MatDestroy(); rather, use PCFieldSplitSchurRestoreS().

    1970:     Level: advanced

    1972: .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSchurPreType, PCFieldSplitSetSchurPre(), MatSchurComplement, PCFieldSplitSchurRestoreS()

    1974: @*/
    1975: PetscErrorCode  PCFieldSplitSchurGetS(PC pc,Mat *S)
    1976: {
    1978:   const char*    t;
    1979:   PetscBool      isfs;
    1980:   PC_FieldSplit  *jac;

    1984:   PetscObjectGetType((PetscObject)pc,&t);
    1985:   PetscStrcmp(t,PCFIELDSPLIT,&isfs);
    1986:   if (!isfs) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Expected PC of type PCFIELDSPLIT, got %s instead",t);
    1987:   jac = (PC_FieldSplit*)pc->data;
    1988:   if (jac->type != PC_COMPOSITE_SCHUR) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Expected PCFIELDSPLIT of type SCHUR, got %D instead",jac->type);
    1989:   if (S) *S = jac->schur;
    1990:   return(0);
    1991: }

    1995: /*@
    1996:     PCFieldSplitSchurRestoreS -  restores the MatSchurComplement object used by this PC

    1998:     Not collective

    2000:     Input Parameters:
    2001: +   pc      - the preconditioner context
    2002: .   S       - the Schur complement matrix

    2004:     Level: advanced

    2006: .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSchurPreType, PCFieldSplitSetSchurPre(), MatSchurComplement, PCFieldSplitSchurGetS()

    2008: @*/
    2009: PetscErrorCode  PCFieldSplitSchurRestoreS(PC pc,Mat *S)
    2010: {
    2012:   const char*    t;
    2013:   PetscBool      isfs;
    2014:   PC_FieldSplit  *jac;

    2018:   PetscObjectGetType((PetscObject)pc,&t);
    2019:   PetscStrcmp(t,PCFIELDSPLIT,&isfs);
    2020:   if (!isfs) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Expected PC of type PCFIELDSPLIT, got %s instead",t);
    2021:   jac = (PC_FieldSplit*)pc->data;
    2022:   if (jac->type != PC_COMPOSITE_SCHUR) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Expected PCFIELDSPLIT of type SCHUR, got %D instead",jac->type);
    2023:   if (!S || *S != jac->schur) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"MatSchurComplement restored is not the same as gotten");
    2024:   return(0);
    2025: }

    2030: static PetscErrorCode  PCFieldSplitSetSchurPre_FieldSplit(PC pc,PCFieldSplitSchurPreType ptype,Mat pre)
    2031: {
    2032:   PC_FieldSplit  *jac = (PC_FieldSplit*)pc->data;

    2036:   jac->schurpre = ptype;
    2037:   if (ptype == PC_FIELDSPLIT_SCHUR_PRE_USER && pre) {
    2038:     MatDestroy(&jac->schur_user);
    2039:     jac->schur_user = pre;
    2040:     PetscObjectReference((PetscObject)jac->schur_user);
    2041:   }
    2042:   return(0);
    2043: }

    2047: static PetscErrorCode  PCFieldSplitGetSchurPre_FieldSplit(PC pc,PCFieldSplitSchurPreType *ptype,Mat *pre)
    2048: {
    2049:   PC_FieldSplit  *jac = (PC_FieldSplit*)pc->data;

    2052:   *ptype = jac->schurpre;
    2053:   *pre   = jac->schur_user;
    2054:   return(0);
    2055: }

    2059: /*@
    2060:     PCFieldSplitSetSchurFactType -  sets which blocks of the approximate block factorization to retain

    2062:     Collective on PC

    2064:     Input Parameters:
    2065: +   pc  - the preconditioner context
    2066: -   ftype - which blocks of factorization to retain, PC_FIELDSPLIT_SCHUR_FACT_FULL is default

    2068:     Options Database:
    2069: .     -pc_fieldsplit_schur_fact_type <diag,lower,upper,full> default is full

    2072:     Level: intermediate

    2074:     Notes:
    2075:     The FULL factorization is

    2077: $   (A   B)  = (1       0) (A   0) (1  Ainv*B)
    2078: $   (C   D)    (C*Ainv  1) (0   S) (0     1  )

    2080:     where S = D - C*Ainv*B. In practice, the full factorization is applied via block triangular solves with the grouping L*(D*U). UPPER uses D*U, LOWER uses L*D,
    2081:     and DIAG is the diagonal part with the sign of S flipped (because this makes the preconditioner positive definite for many formulations, thus allowing the use of KSPMINRES).

    2083:     If applied exactly, FULL factorization is a direct solver. The preconditioned operator with LOWER or UPPER has all eigenvalues equal to 1 and minimal polynomial
    2084:     of degree 2, so KSPGMRES converges in 2 iterations. If the iteration count is very low, consider using KSPFGMRES or KSPGCR which can use one less preconditioner
    2085:     application in this case. Note that the preconditioned operator may be highly non-normal, so such fast convergence may not be observed in practice. With DIAG,
    2086:     the preconditioned operator has three distinct nonzero eigenvalues and minimal polynomial of degree at most 4, so KSPGMRES converges in at most 4 iterations.

    2088:     For symmetric problems in which A is positive definite and S is negative definite, DIAG can be used with KSPMINRES. Note that a flexible method like KSPFGMRES
    2089:     or KSPGCR must be used if the fieldsplit preconditioner is nonlinear (e.g. a few iterations of a Krylov method is used inside a split).

    2091:     References:
    2092: +   1. - Murphy, Golub, and Wathen, A note on preconditioning indefinite linear systems, SIAM J. Sci. Comput., 21 (2000).
    2093: -   2. - Ipsen, A note on preconditioning nonsymmetric matrices, SIAM J. Sci. Comput., 23 (2001).

    2095: .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetFields(), PCFieldSplitSchurPreType
    2096: @*/
    2097: PetscErrorCode  PCFieldSplitSetSchurFactType(PC pc,PCFieldSplitSchurFactType ftype)
    2098: {

    2103:   PetscTryMethod(pc,"PCFieldSplitSetSchurFactType_C",(PC,PCFieldSplitSchurFactType),(pc,ftype));
    2104:   return(0);
    2105: }

    2109: static PetscErrorCode PCFieldSplitSetSchurFactType_FieldSplit(PC pc,PCFieldSplitSchurFactType ftype)
    2110: {
    2111:   PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;

    2114:   jac->schurfactorization = ftype;
    2115:   return(0);
    2116: }

    2120: /*@C
    2121:    PCFieldSplitGetSchurBlocks - Gets all matrix blocks for the Schur complement

    2123:    Collective on KSP

    2125:    Input Parameter:
    2126: .  pc - the preconditioner context

    2128:    Output Parameters:
    2129: +  A00 - the (0,0) block
    2130: .  A01 - the (0,1) block
    2131: .  A10 - the (1,0) block
    2132: -  A11 - the (1,1) block

    2134:    Level: advanced

    2136: .seealso: PCFIELDSPLIT
    2137: @*/
    2138: PetscErrorCode  PCFieldSplitGetSchurBlocks(PC pc,Mat *A00,Mat *A01,Mat *A10, Mat *A11)
    2139: {
    2140:   PC_FieldSplit *jac = (PC_FieldSplit*) pc->data;

    2144:   if (jac->type != PC_COMPOSITE_SCHUR) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONG, "FieldSplit is not using a Schur complement approach.");
    2145:   if (A00) *A00 = jac->pmat[0];
    2146:   if (A01) *A01 = jac->B;
    2147:   if (A10) *A10 = jac->C;
    2148:   if (A11) *A11 = jac->pmat[1];
    2149:   return(0);
    2150: }

    2154: static PetscErrorCode  PCFieldSplitSetType_FieldSplit(PC pc,PCCompositeType type)
    2155: {
    2156:   PC_FieldSplit  *jac = (PC_FieldSplit*)pc->data;

    2160:   jac->type = type;
    2161:   if (type == PC_COMPOSITE_SCHUR) {
    2162:     pc->ops->apply = PCApply_FieldSplit_Schur;
    2163:     pc->ops->view  = PCView_FieldSplit_Schur;

    2165:     PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitGetSubKSP_C",PCFieldSplitGetSubKSP_FieldSplit_Schur);
    2166:     PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitSetSchurPre_C",PCFieldSplitSetSchurPre_FieldSplit);
    2167:     PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitGetSchurPre_C",PCFieldSplitGetSchurPre_FieldSplit);
    2168:     PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitSetSchurFactType_C",PCFieldSplitSetSchurFactType_FieldSplit);

    2170:   } else {
    2171:     pc->ops->apply = PCApply_FieldSplit;
    2172:     pc->ops->view  = PCView_FieldSplit;

    2174:     PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitGetSubKSP_C",PCFieldSplitGetSubKSP_FieldSplit);
    2175:     PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitSetSchurPre_C",0);
    2176:     PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitGetSchurPre_C",0);
    2177:     PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitSetSchurFactType_C",0);
    2178:   }
    2179:   return(0);
    2180: }

    2184: static PetscErrorCode  PCFieldSplitSetBlockSize_FieldSplit(PC pc,PetscInt bs)
    2185: {
    2186:   PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;

    2189:   if (bs < 1) SETERRQ1(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_OUTOFRANGE,"Blocksize must be positive, you gave %D",bs);
    2190:   if (jac->bs > 0 && jac->bs != bs) SETERRQ2(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Cannot change fieldsplit blocksize from %D to %D after it has been set",jac->bs,bs);
    2191:   jac->bs = bs;
    2192:   return(0);
    2193: }

    2197: /*@
    2198:    PCFieldSplitSetType - Sets the type of fieldsplit preconditioner.

    2200:    Collective on PC

    2202:    Input Parameter:
    2203: .  pc - the preconditioner context
    2204: .  type - PC_COMPOSITE_ADDITIVE, PC_COMPOSITE_MULTIPLICATIVE (default), PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE, PC_COMPOSITE_SPECIAL, PC_COMPOSITE_SCHUR

    2206:    Options Database Key:
    2207: .  -pc_fieldsplit_type <type: one of multiplicative, additive, symmetric_multiplicative, special, schur> - Sets fieldsplit preconditioner type

    2209:    Level: Intermediate

    2211: .keywords: PC, set, type, composite preconditioner, additive, multiplicative

    2213: .seealso: PCCompositeSetType()

    2215: @*/
    2216: PetscErrorCode  PCFieldSplitSetType(PC pc,PCCompositeType type)
    2217: {

    2222:   PetscTryMethod(pc,"PCFieldSplitSetType_C",(PC,PCCompositeType),(pc,type));
    2223:   return(0);
    2224: }

    2228: /*@
    2229:   PCFieldSplitGetType - Gets the type of fieldsplit preconditioner.

    2231:   Not collective

    2233:   Input Parameter:
    2234: . pc - the preconditioner context

    2236:   Output Parameter:
    2237: . type - PC_COMPOSITE_ADDITIVE, PC_COMPOSITE_MULTIPLICATIVE (default), PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE, PC_COMPOSITE_SPECIAL, PC_COMPOSITE_SCHUR

    2239:   Level: Intermediate

    2241: .keywords: PC, set, type, composite preconditioner, additive, multiplicative
    2242: .seealso: PCCompositeSetType()
    2243: @*/
    2244: PetscErrorCode PCFieldSplitGetType(PC pc, PCCompositeType *type)
    2245: {
    2246:   PC_FieldSplit *jac = (PC_FieldSplit*) pc->data;

    2251:   *type = jac->type;
    2252:   return(0);
    2253: }

    2257: /*@
    2258:    PCFieldSplitSetDMSplits - Flags whether DMCreateFieldDecomposition() should be used to define the splits, whenever possible.

    2260:    Logically Collective

    2262:    Input Parameters:
    2263: +  pc   - the preconditioner context
    2264: -  flg  - boolean indicating whether to use field splits defined by the DM

    2266:    Options Database Key:
    2267: .  -pc_fieldsplit_dm_splits

    2269:    Level: Intermediate

    2271: .keywords: PC, DM, composite preconditioner, additive, multiplicative

    2273: .seealso: PCFieldSplitGetDMSplits()

    2275: @*/
    2276: PetscErrorCode  PCFieldSplitSetDMSplits(PC pc,PetscBool flg)
    2277: {
    2278:   PC_FieldSplit  *jac = (PC_FieldSplit*)pc->data;
    2279:   PetscBool      isfs;

    2285:   PetscObjectTypeCompare((PetscObject)pc,PCFIELDSPLIT,&isfs);
    2286:   if (isfs) {
    2287:     jac->dm_splits = flg;
    2288:   }
    2289:   return(0);
    2290: }

    2295: /*@
    2296:    PCFieldSplitGetDMSplits - Returns flag indicating whether DMCreateFieldDecomposition() should be used to define the splits, whenever possible.

    2298:    Logically Collective

    2300:    Input Parameter:
    2301: .  pc   - the preconditioner context

    2303:    Output Parameter:
    2304: .  flg  - boolean indicating whether to use field splits defined by the DM

    2306:    Level: Intermediate

    2308: .keywords: PC, DM, composite preconditioner, additive, multiplicative

    2310: .seealso: PCFieldSplitSetDMSplits()

    2312: @*/
    2313: PetscErrorCode  PCFieldSplitGetDMSplits(PC pc,PetscBool* flg)
    2314: {
    2315:   PC_FieldSplit  *jac = (PC_FieldSplit*)pc->data;
    2316:   PetscBool      isfs;

    2322:   PetscObjectTypeCompare((PetscObject)pc,PCFIELDSPLIT,&isfs);
    2323:   if (isfs) {
    2324:     if(flg) *flg = jac->dm_splits;
    2325:   }
    2326:   return(0);
    2327: }

    2329: /* -------------------------------------------------------------------------------------*/
    2330: /*MC
    2331:    PCFIELDSPLIT - Preconditioner created by combining separate preconditioners for individual
    2332:                   fields or groups of fields. See the users manual section "Solving Block Matrices" for more details.

    2334:      To set options on the solvers for each block append -fieldsplit_ to all the PC
    2335:         options database keys. For example, -fieldsplit_pc_type ilu -fieldsplit_pc_factor_levels 1

    2337:      To set the options on the solvers separate for each block call PCFieldSplitGetSubKSP()
    2338:          and set the options directly on the resulting KSP object

    2340:    Level: intermediate

    2342:    Options Database Keys:
    2343: +   -pc_fieldsplit_%d_fields <a,b,..> - indicates the fields to be used in the %d'th split
    2344: .   -pc_fieldsplit_default - automatically add any fields to additional splits that have not
    2345:                               been supplied explicitly by -pc_fieldsplit_%d_fields
    2346: .   -pc_fieldsplit_block_size <bs> - size of block that defines fields (i.e. there are bs fields)
    2347: .   -pc_fieldsplit_type <additive,multiplicative,symmetric_multiplicative,schur> - type of relaxation or factorization splitting
    2348: .   -pc_fieldsplit_schur_precondition <self,selfp,user,a11,full> - default is a11; see PCFieldSplitSetSchurPre()
    2349: .   -pc_fieldsplit_detect_saddle_point - automatically finds rows with zero or negative diagonal and uses Schur complement with no preconditioner as the solver

    2351: -    Options prefix for inner solvers when using Schur complement preconditioner are -fieldsplit_0_ and -fieldsplit_1_
    2352:      for all other solvers they are -fieldsplit_%d_ for the dth field, use -fieldsplit_ for all fields

    2354:    Notes:
    2355:     Use PCFieldSplitSetFields() to set fields defined by "strided" entries and PCFieldSplitSetIS()
    2356:      to define a field by an arbitrary collection of entries.

    2358:       If no fields are set the default is used. The fields are defined by entries strided by bs,
    2359:       beginning at 0 then 1, etc to bs-1. The block size can be set with PCFieldSplitSetBlockSize(),
    2360:       if this is not called the block size defaults to the blocksize of the second matrix passed
    2361:       to KSPSetOperators()/PCSetOperators().

    2363: $     For the Schur complement preconditioner if J = ( A00 A01 )
    2364: $                                                    ( A10 A11 )
    2365: $     the preconditioner using full factorization is
    2366: $              ( I   -ksp(A00) A01 ) ( inv(A00)     0  ) (     I          0  )
    2367: $              ( 0         I       ) (   0      ksp(S) ) ( -A10 ksp(A00)  I  )
    2368:      where the action of inv(A00) is applied using the KSP solver with prefix -fieldsplit_0_.  S is the Schur complement
    2369: $              S = A11 - A10 ksp(A00) A01
    2370:      which is usually dense and not stored explicitly.  The action of ksp(S) is computed using the KSP solver with prefix -fieldsplit_splitname_ (where splitname was given
    2371:      in providing the SECOND split or 1 if not give). For PCFieldSplitGetKSP() when field number is 0,
    2372:      it returns the KSP associated with -fieldsplit_0_ while field number 1 gives -fieldsplit_1_ KSP. By default
    2373:      A11 is used to construct a preconditioner for S, use PCFieldSplitSetSchurPre() for all the possible ways to construct the preconditioner for S.

    2375:      The factorization type is set using -pc_fieldsplit_schur_fact_type <diag, lower, upper, full>. The full is shown above,
    2376:      diag gives
    2377: $              ( inv(A00)     0   )
    2378: $              (   0      -ksp(S) )
    2379:      note that slightly counter intuitively there is a negative in front of the ksp(S) so that the preconditioner is positive definite. The lower factorization is the inverse of
    2380: $              (  A00   0 )
    2381: $              (  A10   S )
    2382:      where the inverses of A00 and S are applied using KSPs. The upper factorization is the inverse of
    2383: $              ( A00 A01 )
    2384: $              (  0   S  )
    2385:      where again the inverses of A00 and S are applied using KSPs.

    2387:      If only one set of indices (one IS) is provided with PCFieldSplitSetIS() then the complement of that IS
    2388:      is used automatically for a second block.

    2390:      The fieldsplit preconditioner cannot currently be used with the BAIJ or SBAIJ data formats if the blocksize is larger than 1.
    2391:      Generally it should be used with the AIJ format.

    2393:      The forms of these preconditioners are closely related if not identical to forms derived as "Distributive Iterations", see,
    2394:      for example, page 294 in "Principles of Computational Fluid Dynamics" by Pieter Wesseling. Note that one can also use PCFIELDSPLIT
    2395:      inside a smoother resulting in "Distributive Smoothers".

    2397:    Concepts: physics based preconditioners, block preconditioners

    2399:    There is a nice discussion of block preconditioners in

    2401: [El08] A taxonomy and comparison of parallel block multi-level preconditioners for the incompressible Navier-Stokes equations
    2402:        Howard Elman, V.E. Howle, John Shadid, Robert Shuttleworth, Ray Tuminaro, Journal of Computational Physics 227 (2008) 1790--1808
    2403:        http://chess.cs.umd.edu/~elman/papers/tax.pdf

    2405:    The Constrained Pressure Preconditioner (CPR) does not appear to be currently implementable directly with PCFIELDSPLIT. CPR solves first the Schur complemented pressure equation, updates the
    2406:    residual on all variables and then applies a simple ILU like preconditioner on all the variables. So it is very much like the full Schur complement with selfp representing the Schur complement but instead
    2407:    of backsolving for the saturations in the last step it solves a full coupled (ILU) system for updates to all the variables.

    2409: .seealso:  PCCreate(), PCSetType(), PCType (for list of available types), PC, Block_Preconditioners, PCLSC,
    2410:            PCFieldSplitGetSubKSP(), PCFieldSplitSetFields(), PCFieldSplitSetType(), PCFieldSplitSetIS(), PCFieldSplitSetSchurPre(),
    2411:            MatSchurComplementSetAinvType()
    2412: M*/

    2416: PETSC_EXTERN PetscErrorCode PCCreate_FieldSplit(PC pc)
    2417: {
    2419:   PC_FieldSplit  *jac;

    2422:   PetscNewLog(pc,&jac);

    2424:   jac->bs                 = -1;
    2425:   jac->nsplits            = 0;
    2426:   jac->type               = PC_COMPOSITE_MULTIPLICATIVE;
    2427:   jac->schurpre           = PC_FIELDSPLIT_SCHUR_PRE_USER; /* Try user preconditioner first, fall back on diagonal */
    2428:   jac->schurfactorization = PC_FIELDSPLIT_SCHUR_FACT_FULL;
    2429:   jac->dm_splits          = PETSC_TRUE;

    2431:   pc->data = (void*)jac;

    2433:   pc->ops->apply           = PCApply_FieldSplit;
    2434:   pc->ops->applytranspose  = PCApplyTranspose_FieldSplit;
    2435:   pc->ops->setup           = PCSetUp_FieldSplit;
    2436:   pc->ops->reset           = PCReset_FieldSplit;
    2437:   pc->ops->destroy         = PCDestroy_FieldSplit;
    2438:   pc->ops->setfromoptions  = PCSetFromOptions_FieldSplit;
    2439:   pc->ops->view            = PCView_FieldSplit;
    2440:   pc->ops->applyrichardson = 0;

    2442:   PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitGetSubKSP_C",PCFieldSplitGetSubKSP_FieldSplit);
    2443:   PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitSetFields_C",PCFieldSplitSetFields_FieldSplit);
    2444:   PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitSetIS_C",PCFieldSplitSetIS_FieldSplit);
    2445:   PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitSetType_C",PCFieldSplitSetType_FieldSplit);
    2446:   PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitSetBlockSize_C",PCFieldSplitSetBlockSize_FieldSplit);
    2447:   PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitRestrictIS_C",PCFieldSplitRestrictIS_FieldSplit);
    2448:   return(0);
    2449: }