xref: /petsc/src/ksp/pc/impls/fieldsplit/fieldsplit.c (revision bc59fbc54ac8b63d9331f83ad670091a818dfe89)
1dba47a55SKris Buschelman 
26356e834SBarry Smith #include "private/pcimpl.h"     /*I "petscpc.h" I*/
30971522cSBarry Smith 
4f7c28744SJed Brown const char *const PCFieldSplitSchurPreTypes[] = {"SELF","DIAG","USER","PCFieldSplitSchurPreType","PC_FIELDSPLIT_SCHUR_PRE_",0};
5f7c28744SJed Brown const char *const PCFieldSplitSchurFactorizationTypes[] = {"DIAG","LOWER","UPPER","FULL","PCFieldSplitSchurFactorizationType","PC_FIELDSPLIT_SCHUR_FACTORIZATION_",0};
6c5d2311dSJed Brown 
7c5d2311dSJed Brown typedef enum {
8c5d2311dSJed Brown   PC_FIELDSPLIT_SCHUR_FACTORIZATION_DIAG,
9c5d2311dSJed Brown   PC_FIELDSPLIT_SCHUR_FACTORIZATION_LOWER,
10c5d2311dSJed Brown   PC_FIELDSPLIT_SCHUR_FACTORIZATION_UPPER,
11c5d2311dSJed Brown   PC_FIELDSPLIT_SCHUR_FACTORIZATION_FULL
12c5d2311dSJed Brown } PCFieldSplitSchurFactorizationType;
13084e4875SJed Brown 
140971522cSBarry Smith typedef struct _PC_FieldSplitLink *PC_FieldSplitLink;
150971522cSBarry Smith struct _PC_FieldSplitLink {
1669a612a9SBarry Smith   KSP               ksp;
170971522cSBarry Smith   Vec               x,y;
18db4c96c1SJed Brown   char              *splitname;
190971522cSBarry Smith   PetscInt          nfields;
200971522cSBarry Smith   PetscInt          *fields;
211b9fc7fcSBarry Smith   VecScatter        sctx;
224aa3045dSJed Brown   IS                is;
2351f519a2SBarry Smith   PC_FieldSplitLink next,previous;
240971522cSBarry Smith };
250971522cSBarry Smith 
260971522cSBarry Smith typedef struct {
2768dd23aaSBarry Smith   PCCompositeType                    type;
28ace3abfcSBarry Smith   PetscBool                          defaultsplit; /* Flag for a system with a set of 'k' scalar fields with the same layout (and bs = k) */
29ace3abfcSBarry Smith   PetscBool                          splitdefined; /* Flag is set after the splits have been defined, to prevent more splits from being added */
30ace3abfcSBarry Smith   PetscBool                          realdiagonal; /* Flag to use the diagonal blocks of mat preconditioned by pmat, instead of just pmat */
3130ad9308SMatthew Knepley   PetscInt                           bs;           /* Block size for IS and Mat structures */
3230ad9308SMatthew Knepley   PetscInt                           nsplits;      /* Number of field divisions defined */
3379416396SBarry Smith   Vec                                *x,*y,w1,w2;
34519d70e2SJed Brown   Mat                                *mat;         /* The diagonal block for each split */
35519d70e2SJed Brown   Mat                                *pmat;        /* The preconditioning diagonal block for each split */
3630ad9308SMatthew Knepley   Mat                                *Afield;      /* The rows of the matrix associated with each split */
37ace3abfcSBarry Smith   PetscBool                          issetup;
3830ad9308SMatthew Knepley   /* Only used when Schur complement preconditioning is used */
3930ad9308SMatthew Knepley   Mat                                B;            /* The (0,1) block */
4030ad9308SMatthew Knepley   Mat                                C;            /* The (1,0) block */
41a04f6461SBarry Smith   Mat                                schur;        /* The Schur complement S = A11 - A10 A00^{-1} A01 */
42084e4875SJed Brown   Mat                                schur_user;   /* User-provided preconditioning matrix for the Schur complement */
43084e4875SJed Brown   PCFieldSplitSchurPreType           schurpre; /* Determines which preconditioning matrix is used for the Schur complement */
44c5d2311dSJed Brown   PCFieldSplitSchurFactorizationType schurfactorization;
4530ad9308SMatthew Knepley   KSP                                kspschur;     /* The solver for S */
4697bbdb24SBarry Smith   PC_FieldSplitLink                  head;
470971522cSBarry Smith } PC_FieldSplit;
480971522cSBarry Smith 
4916913363SBarry Smith /*
5016913363SBarry Smith     Notes: there is no particular reason that pmat, x, and y are stored as arrays in PC_FieldSplit instead of
5116913363SBarry Smith    inside PC_FieldSplitLink, just historical. If you want to be able to add new fields after already using the
5216913363SBarry Smith    PC you could change this.
5316913363SBarry Smith */
54084e4875SJed Brown 
55e6cab6aaSJed Brown /* This helper is so that setting a user-provided preconditioning matrix is orthogonal to choosing to use it.  This way the
56084e4875SJed Brown * application-provided FormJacobian can provide this matrix without interfering with the user's (command-line) choices. */
57084e4875SJed Brown static Mat FieldSplitSchurPre(PC_FieldSplit *jac)
58084e4875SJed Brown {
59084e4875SJed Brown   switch (jac->schurpre) {
60084e4875SJed Brown     case PC_FIELDSPLIT_SCHUR_PRE_SELF: return jac->schur;
61084e4875SJed Brown     case PC_FIELDSPLIT_SCHUR_PRE_DIAG: return jac->pmat[1];
62084e4875SJed Brown     case PC_FIELDSPLIT_SCHUR_PRE_USER: /* Use a user-provided matrix if it is given, otherwise diagonal block */
63084e4875SJed Brown     default:
64084e4875SJed Brown       return jac->schur_user ? jac->schur_user : jac->pmat[1];
65084e4875SJed Brown   }
66084e4875SJed Brown }
67084e4875SJed Brown 
68084e4875SJed Brown 
690971522cSBarry Smith #undef __FUNCT__
700971522cSBarry Smith #define __FUNCT__ "PCView_FieldSplit"
710971522cSBarry Smith static PetscErrorCode PCView_FieldSplit(PC pc,PetscViewer viewer)
720971522cSBarry Smith {
730971522cSBarry Smith   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
740971522cSBarry Smith   PetscErrorCode    ierr;
75ace3abfcSBarry Smith   PetscBool         iascii;
760971522cSBarry Smith   PetscInt          i,j;
775a9f2f41SSatish Balay   PC_FieldSplitLink ilink = jac->head;
780971522cSBarry Smith 
790971522cSBarry Smith   PetscFunctionBegin;
802692d6eeSBarry Smith   ierr = PetscTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
810971522cSBarry Smith   if (iascii) {
8251f519a2SBarry Smith     ierr = PetscViewerASCIIPrintf(viewer,"  FieldSplit with %s composition: total splits = %D, blocksize = %D\n",PCCompositeTypes[jac->type],jac->nsplits,jac->bs);CHKERRQ(ierr);
8369a612a9SBarry Smith     ierr = PetscViewerASCIIPrintf(viewer,"  Solver info for each split is in the following KSP objects:\n");CHKERRQ(ierr);
840971522cSBarry Smith     ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
850971522cSBarry Smith     for (i=0; i<jac->nsplits; i++) {
861ab39975SBarry Smith       if (ilink->fields) {
870971522cSBarry Smith 	ierr = PetscViewerASCIIPrintf(viewer,"Split number %D Fields ",i);CHKERRQ(ierr);
8879416396SBarry Smith 	ierr = PetscViewerASCIIUseTabs(viewer,PETSC_FALSE);CHKERRQ(ierr);
895a9f2f41SSatish Balay 	for (j=0; j<ilink->nfields; j++) {
9079416396SBarry Smith 	  if (j > 0) {
9179416396SBarry Smith 	    ierr = PetscViewerASCIIPrintf(viewer,",");CHKERRQ(ierr);
9279416396SBarry Smith 	  }
935a9f2f41SSatish Balay 	  ierr = PetscViewerASCIIPrintf(viewer," %D",ilink->fields[j]);CHKERRQ(ierr);
940971522cSBarry Smith 	}
950971522cSBarry Smith 	ierr = PetscViewerASCIIPrintf(viewer,"\n");CHKERRQ(ierr);
9679416396SBarry Smith         ierr = PetscViewerASCIIUseTabs(viewer,PETSC_TRUE);CHKERRQ(ierr);
971ab39975SBarry Smith       } else {
981ab39975SBarry Smith 	ierr = PetscViewerASCIIPrintf(viewer,"Split number %D Defined by IS\n",i);CHKERRQ(ierr);
991ab39975SBarry Smith       }
1005a9f2f41SSatish Balay       ierr = KSPView(ilink->ksp,viewer);CHKERRQ(ierr);
1015a9f2f41SSatish Balay       ilink = ilink->next;
1020971522cSBarry Smith     }
1030971522cSBarry Smith     ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
1040971522cSBarry Smith   } else {
10565e19b50SBarry Smith     SETERRQ1(((PetscObject)pc)->comm,PETSC_ERR_SUP,"Viewer type %s not supported for PCFieldSplit",((PetscObject)viewer)->type_name);
1060971522cSBarry Smith   }
1070971522cSBarry Smith   PetscFunctionReturn(0);
1080971522cSBarry Smith }
1090971522cSBarry Smith 
1100971522cSBarry Smith #undef __FUNCT__
1113b224e63SBarry Smith #define __FUNCT__ "PCView_FieldSplit_Schur"
1123b224e63SBarry Smith static PetscErrorCode PCView_FieldSplit_Schur(PC pc,PetscViewer viewer)
1133b224e63SBarry Smith {
1143b224e63SBarry Smith   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
1153b224e63SBarry Smith   PetscErrorCode    ierr;
116ace3abfcSBarry Smith   PetscBool         iascii;
1173b224e63SBarry Smith   PetscInt          i,j;
1183b224e63SBarry Smith   PC_FieldSplitLink ilink = jac->head;
1193b224e63SBarry Smith   KSP               ksp;
1203b224e63SBarry Smith 
1213b224e63SBarry Smith   PetscFunctionBegin;
1222692d6eeSBarry Smith   ierr = PetscTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
1233b224e63SBarry Smith   if (iascii) {
124c5d2311dSJed Brown     ierr = PetscViewerASCIIPrintf(viewer,"  FieldSplit with Schur preconditioner, blocksize = %D, factorization %s\n",jac->bs,PCFieldSplitSchurFactorizationTypes[jac->schurfactorization]);CHKERRQ(ierr);
1253b224e63SBarry Smith     ierr = PetscViewerASCIIPrintf(viewer,"  Split info:\n");CHKERRQ(ierr);
1263b224e63SBarry Smith     ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
1273b224e63SBarry Smith     for (i=0; i<jac->nsplits; i++) {
1283b224e63SBarry Smith       if (ilink->fields) {
1293b224e63SBarry Smith 	ierr = PetscViewerASCIIPrintf(viewer,"Split number %D Fields ",i);CHKERRQ(ierr);
1303b224e63SBarry Smith 	ierr = PetscViewerASCIIUseTabs(viewer,PETSC_FALSE);CHKERRQ(ierr);
1313b224e63SBarry Smith 	for (j=0; j<ilink->nfields; j++) {
1323b224e63SBarry Smith 	  if (j > 0) {
1333b224e63SBarry Smith 	    ierr = PetscViewerASCIIPrintf(viewer,",");CHKERRQ(ierr);
1343b224e63SBarry Smith 	  }
1353b224e63SBarry Smith 	  ierr = PetscViewerASCIIPrintf(viewer," %D",ilink->fields[j]);CHKERRQ(ierr);
1363b224e63SBarry Smith 	}
1373b224e63SBarry Smith 	ierr = PetscViewerASCIIPrintf(viewer,"\n");CHKERRQ(ierr);
1383b224e63SBarry Smith         ierr = PetscViewerASCIIUseTabs(viewer,PETSC_TRUE);CHKERRQ(ierr);
1393b224e63SBarry Smith       } else {
1403b224e63SBarry Smith 	ierr = PetscViewerASCIIPrintf(viewer,"Split number %D Defined by IS\n",i);CHKERRQ(ierr);
1413b224e63SBarry Smith       }
1423b224e63SBarry Smith       ilink = ilink->next;
1433b224e63SBarry Smith     }
144435f959eSBarry Smith     ierr = PetscViewerASCIIPrintf(viewer,"KSP solver for A00 block \n");CHKERRQ(ierr);
1453b224e63SBarry Smith     ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
14612cae6f2SJed Brown     if (jac->schur) {
14712cae6f2SJed Brown       ierr = MatSchurComplementGetKSP(jac->schur,&ksp);CHKERRQ(ierr);
1483b224e63SBarry Smith       ierr = KSPView(ksp,viewer);CHKERRQ(ierr);
14912cae6f2SJed Brown     } else {
15012cae6f2SJed Brown       ierr = PetscViewerASCIIPrintf(viewer,"  not yet available\n");CHKERRQ(ierr);
15112cae6f2SJed Brown     }
1523b224e63SBarry Smith     ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
153435f959eSBarry Smith     ierr = PetscViewerASCIIPrintf(viewer,"KSP solver for S = A11 - A10 inv(A00) A01 \n");CHKERRQ(ierr);
1543b224e63SBarry Smith     ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
15512cae6f2SJed Brown     if (jac->kspschur) {
1563b224e63SBarry Smith       ierr = KSPView(jac->kspschur,viewer);CHKERRQ(ierr);
15712cae6f2SJed Brown     } else {
15812cae6f2SJed Brown       ierr = PetscViewerASCIIPrintf(viewer,"  not yet available\n");CHKERRQ(ierr);
15912cae6f2SJed Brown     }
1603b224e63SBarry Smith     ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
1613b224e63SBarry Smith     ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
1623b224e63SBarry Smith   } else {
16365e19b50SBarry Smith     SETERRQ1(((PetscObject)pc)->comm,PETSC_ERR_SUP,"Viewer type %s not supported for PCFieldSplit",((PetscObject)viewer)->type_name);
1643b224e63SBarry Smith   }
1653b224e63SBarry Smith   PetscFunctionReturn(0);
1663b224e63SBarry Smith }
1673b224e63SBarry Smith 
1683b224e63SBarry Smith #undef __FUNCT__
1696c924f48SJed Brown #define __FUNCT__ "PCFieldSplitSetRuntimeSplits_Private"
1706c924f48SJed Brown /* Precondition: jac->bs is set to a meaningful value */
1716c924f48SJed Brown static PetscErrorCode PCFieldSplitSetRuntimeSplits_Private(PC pc)
1726c924f48SJed Brown {
1736c924f48SJed Brown   PetscErrorCode ierr;
1746c924f48SJed Brown   PC_FieldSplit  *jac = (PC_FieldSplit*)pc->data;
1756c924f48SJed Brown   PetscInt       i,nfields,*ifields;
176ace3abfcSBarry Smith   PetscBool      flg;
1776c924f48SJed Brown   char           optionname[128],splitname[8];
1786c924f48SJed Brown 
1796c924f48SJed Brown   PetscFunctionBegin;
1806c924f48SJed Brown   ierr = PetscMalloc(jac->bs*sizeof(PetscInt),&ifields);CHKERRQ(ierr);
1816c924f48SJed Brown   for (i=0,flg=PETSC_TRUE; ; i++) {
1826c924f48SJed Brown     ierr = PetscSNPrintf(splitname,sizeof splitname,"%D",i);CHKERRQ(ierr);
1836c924f48SJed Brown     ierr = PetscSNPrintf(optionname,sizeof optionname,"-pc_fieldsplit_%D_fields",i);CHKERRQ(ierr);
1846c924f48SJed Brown     nfields = jac->bs;
1856c924f48SJed Brown     ierr    = PetscOptionsGetIntArray(((PetscObject)pc)->prefix,optionname,ifields,&nfields,&flg);CHKERRQ(ierr);
1866c924f48SJed Brown     if (!flg) break;
1876c924f48SJed Brown     if (!nfields) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Cannot list zero fields");
1886c924f48SJed Brown     ierr = PCFieldSplitSetFields(pc,splitname,nfields,ifields);CHKERRQ(ierr);
1896c924f48SJed Brown   }
1906c924f48SJed Brown   if (i > 0) {
1916c924f48SJed Brown     /* Makes command-line setting of splits take precedence over setting them in code.
1926c924f48SJed Brown        Otherwise subsequent calls to PCFieldSplitSetIS() or PCFieldSplitSetFields() would
1936c924f48SJed Brown        create new splits, which would probably not be what the user wanted. */
1946c924f48SJed Brown     jac->splitdefined = PETSC_TRUE;
1956c924f48SJed Brown   }
1966c924f48SJed Brown   ierr = PetscFree(ifields);CHKERRQ(ierr);
1976c924f48SJed Brown   PetscFunctionReturn(0);
1986c924f48SJed Brown }
1996c924f48SJed Brown 
2006c924f48SJed Brown #undef __FUNCT__
20169a612a9SBarry Smith #define __FUNCT__ "PCFieldSplitSetDefaults"
20269a612a9SBarry Smith static PetscErrorCode PCFieldSplitSetDefaults(PC pc)
2030971522cSBarry Smith {
2040971522cSBarry Smith   PC_FieldSplit     *jac  = (PC_FieldSplit*)pc->data;
2050971522cSBarry Smith   PetscErrorCode    ierr;
2065a9f2f41SSatish Balay   PC_FieldSplitLink ilink = jac->head;
2076ce1633cSBarry Smith   PetscBool         flg = PETSC_FALSE,stokes = PETSC_FALSE;
2086c924f48SJed Brown   PetscInt          i;
2090971522cSBarry Smith 
2100971522cSBarry Smith   PetscFunctionBegin;
211d32f9abdSBarry Smith   if (!ilink) {
2128b8307b2SJed Brown     if (pc->dm) {
2138b8307b2SJed Brown       PetscBool dmcomposite;
2148b8307b2SJed Brown       ierr = PetscTypeCompare((PetscObject)pc->dm,DMCOMPOSITE,&dmcomposite);CHKERRQ(ierr);
2158b8307b2SJed Brown       if (dmcomposite) {
2168b8307b2SJed Brown         PetscInt nDM;
2178b8307b2SJed Brown         IS       *fields;
2188b8307b2SJed Brown         ierr = PetscInfo(pc,"Setting up physics based fieldsplit preconditioner using the embedded DM\n");CHKERRQ(ierr);
2198b8307b2SJed Brown         ierr = DMCompositeGetNumberDM(pc->dm,&nDM);CHKERRQ(ierr);
2208b8307b2SJed Brown         ierr = DMCompositeGetGlobalISs(pc->dm,&fields);CHKERRQ(ierr);
2218b8307b2SJed Brown         for (i=0; i<nDM; i++) {
2228b8307b2SJed Brown           char splitname[8];
2238b8307b2SJed Brown           ierr = PetscSNPrintf(splitname,sizeof splitname,"%D",i);CHKERRQ(ierr);
2248b8307b2SJed Brown           ierr = PCFieldSplitSetIS(pc,splitname,fields[i]);CHKERRQ(ierr);
2258b8307b2SJed Brown           ierr = ISDestroy(fields[i]);CHKERRQ(ierr);
2268b8307b2SJed Brown         }
2278b8307b2SJed Brown         ierr = PetscFree(fields);CHKERRQ(ierr);
2288b8307b2SJed Brown       }
22966ffff09SJed Brown     } else {
230521d7252SBarry Smith       if (jac->bs <= 0) {
231704ba839SBarry Smith         if (pc->pmat) {
232521d7252SBarry Smith           ierr   = MatGetBlockSize(pc->pmat,&jac->bs);CHKERRQ(ierr);
233704ba839SBarry Smith         } else {
234704ba839SBarry Smith           jac->bs = 1;
235704ba839SBarry Smith         }
236521d7252SBarry Smith       }
237d32f9abdSBarry Smith 
238acfcf0e5SJed Brown       ierr = PetscOptionsGetBool(((PetscObject)pc)->prefix,"-pc_fieldsplit_default",&flg,PETSC_NULL);CHKERRQ(ierr);
239435f959eSBarry Smith       ierr = PetscOptionsGetBool(((PetscObject)pc)->prefix,"-pc_fieldsplit_detect_saddle_point",&stokes,PETSC_NULL);CHKERRQ(ierr);
2406ce1633cSBarry Smith       if (stokes) {
2416ce1633cSBarry Smith         IS       zerodiags,rest;
2426ce1633cSBarry Smith         PetscInt nmin,nmax;
2436ce1633cSBarry Smith 
2446ce1633cSBarry Smith         ierr = MatGetOwnershipRange(pc->mat,&nmin,&nmax);CHKERRQ(ierr);
2456ce1633cSBarry Smith         ierr = MatFindZeroDiagonals(pc->mat,&zerodiags);CHKERRQ(ierr);
2466ce1633cSBarry Smith         ierr = ISComplement(zerodiags,nmin,nmax,&rest);CHKERRQ(ierr);
2476ce1633cSBarry Smith         ierr = PCFieldSplitSetIS(pc,"0",rest);CHKERRQ(ierr);
2486ce1633cSBarry Smith         ierr = PCFieldSplitSetIS(pc,"1",zerodiags);CHKERRQ(ierr);
2496ce1633cSBarry Smith         ierr = ISDestroy(zerodiags);CHKERRQ(ierr);
2506ce1633cSBarry Smith         ierr = ISDestroy(rest);CHKERRQ(ierr);
2516ce1633cSBarry Smith       } else {
252d32f9abdSBarry Smith         if (!flg) {
253d32f9abdSBarry Smith           /* Allow user to set fields from command line,  if bs was known at the time of PCSetFromOptions_FieldSplit()
254d32f9abdSBarry Smith            then it is set there. This is not ideal because we should only have options set in XXSetFromOptions(). */
2556c924f48SJed Brown           ierr = PCFieldSplitSetRuntimeSplits_Private(pc);CHKERRQ(ierr);
2566c924f48SJed Brown           if (jac->splitdefined) {ierr = PetscInfo(pc,"Splits defined using the options database\n");CHKERRQ(ierr);}
257d32f9abdSBarry Smith         }
2586c924f48SJed Brown         if (flg || !jac->splitdefined) {
259d32f9abdSBarry Smith           ierr = PetscInfo(pc,"Using default splitting of fields\n");CHKERRQ(ierr);
260db4c96c1SJed Brown           for (i=0; i<jac->bs; i++) {
2616c924f48SJed Brown             char splitname[8];
2626c924f48SJed Brown             ierr = PetscSNPrintf(splitname,sizeof splitname,"%D",i);CHKERRQ(ierr);
263db4c96c1SJed Brown             ierr = PCFieldSplitSetFields(pc,splitname,1,&i);CHKERRQ(ierr);
26479416396SBarry Smith           }
26597bbdb24SBarry Smith           jac->defaultsplit = PETSC_TRUE;
266521d7252SBarry Smith         }
26766ffff09SJed Brown       }
2686ce1633cSBarry Smith     }
269edf189efSBarry Smith   } else if (jac->nsplits == 1) {
270edf189efSBarry Smith     if (ilink->is) {
271edf189efSBarry Smith       IS       is2;
272edf189efSBarry Smith       PetscInt nmin,nmax;
273edf189efSBarry Smith 
274edf189efSBarry Smith       ierr = MatGetOwnershipRange(pc->mat,&nmin,&nmax);CHKERRQ(ierr);
275edf189efSBarry Smith       ierr = ISComplement(ilink->is,nmin,nmax,&is2);CHKERRQ(ierr);
276db4c96c1SJed Brown       ierr = PCFieldSplitSetIS(pc,"1",is2);CHKERRQ(ierr);
277edf189efSBarry Smith       ierr = ISDestroy(is2);CHKERRQ(ierr);
278e7e72b3dSBarry Smith     } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Must provide at least two sets of fields to PCFieldSplit()");
279edf189efSBarry Smith   }
280e7e72b3dSBarry Smith   if (jac->nsplits < 2) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unhandled case, must have at least two fields");
28169a612a9SBarry Smith   PetscFunctionReturn(0);
28269a612a9SBarry Smith }
28369a612a9SBarry Smith 
28469a612a9SBarry Smith 
28569a612a9SBarry Smith #undef __FUNCT__
28669a612a9SBarry Smith #define __FUNCT__ "PCSetUp_FieldSplit"
28769a612a9SBarry Smith static PetscErrorCode PCSetUp_FieldSplit(PC pc)
28869a612a9SBarry Smith {
28969a612a9SBarry Smith   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
29069a612a9SBarry Smith   PetscErrorCode    ierr;
2915a9f2f41SSatish Balay   PC_FieldSplitLink ilink;
292cf502942SBarry Smith   PetscInt          i,nsplit,ccsize;
29369a612a9SBarry Smith   MatStructure      flag = pc->flag;
294ace3abfcSBarry Smith   PetscBool         sorted;
29569a612a9SBarry Smith 
29669a612a9SBarry Smith   PetscFunctionBegin;
29769a612a9SBarry Smith   ierr   = PCFieldSplitSetDefaults(pc);CHKERRQ(ierr);
29897bbdb24SBarry Smith   nsplit = jac->nsplits;
2995a9f2f41SSatish Balay   ilink  = jac->head;
30097bbdb24SBarry Smith 
30197bbdb24SBarry Smith   /* get the matrices for each split */
302704ba839SBarry Smith   if (!jac->issetup) {
3031b9fc7fcSBarry Smith     PetscInt rstart,rend,nslots,bs;
30497bbdb24SBarry Smith 
305704ba839SBarry Smith     jac->issetup = PETSC_TRUE;
306704ba839SBarry Smith 
307704ba839SBarry Smith     /* This is done here instead of in PCFieldSplitSetFields() because may not have matrix at that point */
30851f519a2SBarry Smith     bs     = jac->bs;
30997bbdb24SBarry Smith     ierr   = MatGetOwnershipRange(pc->pmat,&rstart,&rend);CHKERRQ(ierr);
310cf502942SBarry Smith     ierr   = MatGetLocalSize(pc->pmat,PETSC_NULL,&ccsize);CHKERRQ(ierr);
3111b9fc7fcSBarry Smith     nslots = (rend - rstart)/bs;
3121b9fc7fcSBarry Smith     for (i=0; i<nsplit; i++) {
3131b9fc7fcSBarry Smith       if (jac->defaultsplit) {
314704ba839SBarry Smith         ierr = ISCreateStride(((PetscObject)pc)->comm,nslots,rstart+i,nsplit,&ilink->is);CHKERRQ(ierr);
315704ba839SBarry Smith       } else if (!ilink->is) {
316ccb205f8SBarry Smith         if (ilink->nfields > 1) {
3175a9f2f41SSatish Balay           PetscInt   *ii,j,k,nfields = ilink->nfields,*fields = ilink->fields;
3185a9f2f41SSatish Balay           ierr = PetscMalloc(ilink->nfields*nslots*sizeof(PetscInt),&ii);CHKERRQ(ierr);
3191b9fc7fcSBarry Smith           for (j=0; j<nslots; j++) {
3201b9fc7fcSBarry Smith             for (k=0; k<nfields; k++) {
3211b9fc7fcSBarry Smith               ii[nfields*j + k] = rstart + bs*j + fields[k];
32297bbdb24SBarry Smith             }
32397bbdb24SBarry Smith           }
324d67e408aSBarry Smith           ierr = ISCreateGeneral(((PetscObject)pc)->comm,nslots*nfields,ii,PETSC_OWN_POINTER,&ilink->is);CHKERRQ(ierr);
325ccb205f8SBarry Smith         } else {
326704ba839SBarry Smith           ierr = ISCreateStride(((PetscObject)pc)->comm,nslots,rstart+ilink->fields[0],bs,&ilink->is);CHKERRQ(ierr);
327ccb205f8SBarry Smith         }
3283e197d65SBarry Smith       }
329704ba839SBarry Smith       ierr = ISSorted(ilink->is,&sorted);CHKERRQ(ierr);
330e32f2f54SBarry Smith       if (!sorted) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Fields must be sorted when creating split");
331704ba839SBarry Smith       ilink = ilink->next;
3321b9fc7fcSBarry Smith     }
3331b9fc7fcSBarry Smith   }
3341b9fc7fcSBarry Smith 
335704ba839SBarry Smith   ilink  = jac->head;
33697bbdb24SBarry Smith   if (!jac->pmat) {
337cf502942SBarry Smith     ierr = PetscMalloc(nsplit*sizeof(Mat),&jac->pmat);CHKERRQ(ierr);
338cf502942SBarry Smith     for (i=0; i<nsplit; i++) {
3394aa3045dSJed Brown       ierr = MatGetSubMatrix(pc->pmat,ilink->is,ilink->is,MAT_INITIAL_MATRIX,&jac->pmat[i]);CHKERRQ(ierr);
340704ba839SBarry Smith       ilink = ilink->next;
341cf502942SBarry Smith     }
34297bbdb24SBarry Smith   } else {
343cf502942SBarry Smith     for (i=0; i<nsplit; i++) {
3444aa3045dSJed Brown       ierr = MatGetSubMatrix(pc->pmat,ilink->is,ilink->is,MAT_REUSE_MATRIX,&jac->pmat[i]);CHKERRQ(ierr);
345704ba839SBarry Smith       ilink = ilink->next;
346cf502942SBarry Smith     }
34797bbdb24SBarry Smith   }
348519d70e2SJed Brown   if (jac->realdiagonal) {
349519d70e2SJed Brown     ilink = jac->head;
350519d70e2SJed Brown     if (!jac->mat) {
351519d70e2SJed Brown       ierr = PetscMalloc(nsplit*sizeof(Mat),&jac->mat);CHKERRQ(ierr);
352519d70e2SJed Brown       for (i=0; i<nsplit; i++) {
353519d70e2SJed Brown         ierr = MatGetSubMatrix(pc->mat,ilink->is,ilink->is,MAT_INITIAL_MATRIX,&jac->mat[i]);CHKERRQ(ierr);
354519d70e2SJed Brown         ilink = ilink->next;
355519d70e2SJed Brown       }
356519d70e2SJed Brown     } else {
357519d70e2SJed Brown       for (i=0; i<nsplit; i++) {
358519d70e2SJed Brown         ierr = MatGetSubMatrix(pc->mat,ilink->is,ilink->is,MAT_REUSE_MATRIX,&jac->mat[i]);CHKERRQ(ierr);
359519d70e2SJed Brown         ilink = ilink->next;
360519d70e2SJed Brown       }
361519d70e2SJed Brown     }
362519d70e2SJed Brown   } else {
363519d70e2SJed Brown     jac->mat = jac->pmat;
364519d70e2SJed Brown   }
36597bbdb24SBarry Smith 
3666c8605c2SJed Brown   if (jac->type != PC_COMPOSITE_ADDITIVE  && jac->type != PC_COMPOSITE_SCHUR) {
36768dd23aaSBarry Smith     /* extract the rows of the matrix associated with each field: used for efficient computation of residual inside algorithm */
36868dd23aaSBarry Smith     ilink  = jac->head;
36968dd23aaSBarry Smith     if (!jac->Afield) {
37068dd23aaSBarry Smith       ierr = PetscMalloc(nsplit*sizeof(Mat),&jac->Afield);CHKERRQ(ierr);
37168dd23aaSBarry Smith       for (i=0; i<nsplit; i++) {
3724aa3045dSJed Brown         ierr = MatGetSubMatrix(pc->mat,ilink->is,PETSC_NULL,MAT_INITIAL_MATRIX,&jac->Afield[i]);CHKERRQ(ierr);
37368dd23aaSBarry Smith         ilink = ilink->next;
37468dd23aaSBarry Smith       }
37568dd23aaSBarry Smith     } else {
37668dd23aaSBarry Smith       for (i=0; i<nsplit; i++) {
3774aa3045dSJed Brown         ierr = MatGetSubMatrix(pc->mat,ilink->is,PETSC_NULL,MAT_REUSE_MATRIX,&jac->Afield[i]);CHKERRQ(ierr);
37868dd23aaSBarry Smith         ilink = ilink->next;
37968dd23aaSBarry Smith       }
38068dd23aaSBarry Smith     }
38168dd23aaSBarry Smith   }
38268dd23aaSBarry Smith 
3833b224e63SBarry Smith   if (jac->type == PC_COMPOSITE_SCHUR) {
3843b224e63SBarry Smith     IS       ccis;
3854aa3045dSJed Brown     PetscInt rstart,rend;
386e7e72b3dSBarry Smith     if (nsplit != 2) SETERRQ(((PetscObject)pc)->comm,PETSC_ERR_ARG_INCOMP,"To use Schur complement preconditioner you must have exactly 2 fields");
38768dd23aaSBarry Smith 
388e6cab6aaSJed Brown     /* When extracting off-diagonal submatrices, we take complements from this range */
389e6cab6aaSJed Brown     ierr  = MatGetOwnershipRangeColumn(pc->mat,&rstart,&rend);CHKERRQ(ierr);
390e6cab6aaSJed Brown 
3913b224e63SBarry Smith     /* need to handle case when one is resetting up the preconditioner */
3923b224e63SBarry Smith     if (jac->schur) {
3933b224e63SBarry Smith       ilink = jac->head;
3944aa3045dSJed Brown       ierr  = ISComplement(ilink->is,rstart,rend,&ccis);CHKERRQ(ierr);
3954aa3045dSJed Brown       ierr  = MatGetSubMatrix(pc->mat,ilink->is,ccis,MAT_REUSE_MATRIX,&jac->B);CHKERRQ(ierr);
3963b224e63SBarry Smith       ierr  = ISDestroy(ccis);CHKERRQ(ierr);
3973b224e63SBarry Smith       ilink = ilink->next;
3984aa3045dSJed Brown       ierr  = ISComplement(ilink->is,rstart,rend,&ccis);CHKERRQ(ierr);
3994aa3045dSJed Brown       ierr  = MatGetSubMatrix(pc->mat,ilink->is,ccis,MAT_REUSE_MATRIX,&jac->C);CHKERRQ(ierr);
4003b224e63SBarry Smith       ierr  = ISDestroy(ccis);CHKERRQ(ierr);
401519d70e2SJed Brown       ierr  = MatSchurComplementUpdate(jac->schur,jac->mat[0],jac->pmat[0],jac->B,jac->C,jac->pmat[1],pc->flag);CHKERRQ(ierr);
402084e4875SJed Brown       ierr  = KSPSetOperators(jac->kspschur,jac->schur,FieldSplitSchurPre(jac),pc->flag);CHKERRQ(ierr);
4033b224e63SBarry Smith 
4043b224e63SBarry Smith      } else {
4051cee3971SBarry Smith       KSP ksp;
4066c924f48SJed Brown       char schurprefix[256];
4073b224e63SBarry Smith 
408a04f6461SBarry Smith       /* extract the A01 and A10 matrices */
4093b224e63SBarry Smith       ilink = jac->head;
4104aa3045dSJed Brown       ierr  = ISComplement(ilink->is,rstart,rend,&ccis);CHKERRQ(ierr);
4114aa3045dSJed Brown       ierr  = MatGetSubMatrix(pc->mat,ilink->is,ccis,MAT_INITIAL_MATRIX,&jac->B);CHKERRQ(ierr);
4123b224e63SBarry Smith       ierr  = ISDestroy(ccis);CHKERRQ(ierr);
4133b224e63SBarry Smith       ilink = ilink->next;
4144aa3045dSJed Brown       ierr  = ISComplement(ilink->is,rstart,rend,&ccis);CHKERRQ(ierr);
4154aa3045dSJed Brown       ierr  = MatGetSubMatrix(pc->mat,ilink->is,ccis,MAT_INITIAL_MATRIX,&jac->C);CHKERRQ(ierr);
4163b224e63SBarry Smith       ierr  = ISDestroy(ccis);CHKERRQ(ierr);
417084e4875SJed Brown       /* Better would be to use 'mat[0]' (diagonal block of the real matrix) preconditioned by pmat[0] */
418519d70e2SJed Brown       ierr  = MatCreateSchurComplement(jac->mat[0],jac->pmat[0],jac->B,jac->C,jac->mat[1],&jac->schur);CHKERRQ(ierr);
419a04f6461SBarry Smith       /* set tabbing and options prefix of KSP inside the MatSchur */
4201cee3971SBarry Smith       ierr  = MatSchurComplementGetKSP(jac->schur,&ksp);CHKERRQ(ierr);
421e69d4d44SBarry Smith       ierr  = PetscObjectIncrementTabLevel((PetscObject)ksp,(PetscObject)pc,2);CHKERRQ(ierr);
422a04f6461SBarry Smith       ierr  = PetscSNPrintf(schurprefix,sizeof schurprefix,"%sfieldsplit_%s_",((PetscObject)pc)->prefix?((PetscObject)pc)->prefix:"",jac->head->splitname);CHKERRQ(ierr);
423a04f6461SBarry Smith       ierr  = KSPSetOptionsPrefix(ksp,schurprefix);CHKERRQ(ierr);
4243b224e63SBarry Smith       ierr  = MatSetFromOptions(jac->schur);CHKERRQ(ierr);
4253b224e63SBarry Smith 
4263b224e63SBarry Smith       ierr  = KSPCreate(((PetscObject)pc)->comm,&jac->kspschur);CHKERRQ(ierr);
4279005cf84SBarry Smith       ierr  = PetscLogObjectParent((PetscObject)pc,(PetscObject)jac->kspschur);CHKERRQ(ierr);
4281cee3971SBarry Smith       ierr  = PetscObjectIncrementTabLevel((PetscObject)jac->kspschur,(PetscObject)pc,1);CHKERRQ(ierr);
429084e4875SJed Brown       ierr  = KSPSetOperators(jac->kspschur,jac->schur,FieldSplitSchurPre(jac),DIFFERENT_NONZERO_PATTERN);CHKERRQ(ierr);
430084e4875SJed Brown       if (jac->schurpre == PC_FIELDSPLIT_SCHUR_PRE_SELF) {
431084e4875SJed Brown         PC pc;
432cd5f4a64SJed Brown         ierr = KSPGetPC(jac->kspschur,&pc);CHKERRQ(ierr);
433084e4875SJed Brown         ierr = PCSetType(pc,PCNONE);CHKERRQ(ierr);
434084e4875SJed Brown         /* Note: This is bad if there exist preconditioners for MATSCHURCOMPLEMENT */
435e69d4d44SBarry Smith       }
4366c924f48SJed Brown       ierr = PetscSNPrintf(schurprefix,sizeof schurprefix,"%sfieldsplit_%s_",((PetscObject)pc)->prefix?((PetscObject)pc)->prefix:"",ilink->splitname);CHKERRQ(ierr);
4376c924f48SJed Brown       ierr  = KSPSetOptionsPrefix(jac->kspschur,schurprefix);CHKERRQ(ierr);
4383b224e63SBarry Smith       /* really want setfromoptions called in PCSetFromOptions_FieldSplit(), but it is not ready yet */
4393b224e63SBarry Smith       ierr = KSPSetFromOptions(jac->kspschur);CHKERRQ(ierr);
4403b224e63SBarry Smith 
4413b224e63SBarry Smith       ierr = PetscMalloc2(2,Vec,&jac->x,2,Vec,&jac->y);CHKERRQ(ierr);
4423b224e63SBarry Smith       ierr = MatGetVecs(jac->pmat[0],&jac->x[0],&jac->y[0]);CHKERRQ(ierr);
4433b224e63SBarry Smith       ierr = MatGetVecs(jac->pmat[1],&jac->x[1],&jac->y[1]);CHKERRQ(ierr);
4443b224e63SBarry Smith       ilink = jac->head;
4453b224e63SBarry Smith       ilink->x = jac->x[0]; ilink->y = jac->y[0];
4463b224e63SBarry Smith       ilink = ilink->next;
4473b224e63SBarry Smith       ilink->x = jac->x[1]; ilink->y = jac->y[1];
4483b224e63SBarry Smith     }
4493b224e63SBarry Smith   } else {
45097bbdb24SBarry Smith     /* set up the individual PCs */
45197bbdb24SBarry Smith     i    = 0;
4525a9f2f41SSatish Balay     ilink = jac->head;
4535a9f2f41SSatish Balay     while (ilink) {
454519d70e2SJed Brown       ierr = KSPSetOperators(ilink->ksp,jac->mat[i],jac->pmat[i],flag);CHKERRQ(ierr);
4553b224e63SBarry Smith       /* really want setfromoptions called in PCSetFromOptions_FieldSplit(), but it is not ready yet */
4565a9f2f41SSatish Balay       ierr = KSPSetFromOptions(ilink->ksp);CHKERRQ(ierr);
4575a9f2f41SSatish Balay       ierr = KSPSetUp(ilink->ksp);CHKERRQ(ierr);
45897bbdb24SBarry Smith       i++;
4595a9f2f41SSatish Balay       ilink = ilink->next;
4600971522cSBarry Smith     }
46197bbdb24SBarry Smith 
46297bbdb24SBarry Smith     /* create work vectors for each split */
4631b9fc7fcSBarry Smith     if (!jac->x) {
46497bbdb24SBarry Smith       ierr = PetscMalloc2(nsplit,Vec,&jac->x,nsplit,Vec,&jac->y);CHKERRQ(ierr);
4655a9f2f41SSatish Balay       ilink = jac->head;
46697bbdb24SBarry Smith       for (i=0; i<nsplit; i++) {
467906ed7ccSBarry Smith         Vec *vl,*vr;
468906ed7ccSBarry Smith 
469906ed7ccSBarry Smith         ierr      = KSPGetVecs(ilink->ksp,1,&vr,1,&vl);CHKERRQ(ierr);
470906ed7ccSBarry Smith         ilink->x  = *vr;
471906ed7ccSBarry Smith         ilink->y  = *vl;
472906ed7ccSBarry Smith         ierr      = PetscFree(vr);CHKERRQ(ierr);
473906ed7ccSBarry Smith         ierr      = PetscFree(vl);CHKERRQ(ierr);
4745a9f2f41SSatish Balay         jac->x[i] = ilink->x;
4755a9f2f41SSatish Balay         jac->y[i] = ilink->y;
4765a9f2f41SSatish Balay         ilink     = ilink->next;
47797bbdb24SBarry Smith       }
4783b224e63SBarry Smith     }
4793b224e63SBarry Smith   }
4803b224e63SBarry Smith 
4813b224e63SBarry Smith 
482d0f46423SBarry Smith   if (!jac->head->sctx) {
4833b224e63SBarry Smith     Vec xtmp;
4843b224e63SBarry Smith 
48579416396SBarry Smith     /* compute scatter contexts needed by multiplicative versions and non-default splits */
4861b9fc7fcSBarry Smith 
4875a9f2f41SSatish Balay     ilink = jac->head;
4881b9fc7fcSBarry Smith     ierr = MatGetVecs(pc->pmat,&xtmp,PETSC_NULL);CHKERRQ(ierr);
4891b9fc7fcSBarry Smith     for (i=0; i<nsplit; i++) {
490704ba839SBarry Smith       ierr = VecScatterCreate(xtmp,ilink->is,jac->x[i],PETSC_NULL,&ilink->sctx);CHKERRQ(ierr);
4915a9f2f41SSatish Balay       ilink = ilink->next;
4921b9fc7fcSBarry Smith     }
4931b9fc7fcSBarry Smith     ierr = VecDestroy(xtmp);CHKERRQ(ierr);
4941b9fc7fcSBarry Smith   }
4950971522cSBarry Smith   PetscFunctionReturn(0);
4960971522cSBarry Smith }
4970971522cSBarry Smith 
4985a9f2f41SSatish Balay #define FieldSplitSplitSolveAdd(ilink,xx,yy) \
499ca9f406cSSatish Balay     (VecScatterBegin(ilink->sctx,xx,ilink->x,INSERT_VALUES,SCATTER_FORWARD) || \
500ca9f406cSSatish Balay      VecScatterEnd(ilink->sctx,xx,ilink->x,INSERT_VALUES,SCATTER_FORWARD) || \
5015a9f2f41SSatish Balay      KSPSolve(ilink->ksp,ilink->x,ilink->y) || \
502ca9f406cSSatish Balay      VecScatterBegin(ilink->sctx,ilink->y,yy,ADD_VALUES,SCATTER_REVERSE) || \
503ca9f406cSSatish Balay      VecScatterEnd(ilink->sctx,ilink->y,yy,ADD_VALUES,SCATTER_REVERSE))
50479416396SBarry Smith 
5050971522cSBarry Smith #undef __FUNCT__
5063b224e63SBarry Smith #define __FUNCT__ "PCApply_FieldSplit_Schur"
5073b224e63SBarry Smith static PetscErrorCode PCApply_FieldSplit_Schur(PC pc,Vec x,Vec y)
5083b224e63SBarry Smith {
5093b224e63SBarry Smith   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
5103b224e63SBarry Smith   PetscErrorCode    ierr;
5113b224e63SBarry Smith   KSP               ksp;
5123b224e63SBarry Smith   PC_FieldSplitLink ilinkA = jac->head, ilinkD = ilinkA->next;
5133b224e63SBarry Smith 
5143b224e63SBarry Smith   PetscFunctionBegin;
5153b224e63SBarry Smith   ierr = MatSchurComplementGetKSP(jac->schur,&ksp);CHKERRQ(ierr);
5163b224e63SBarry Smith 
517c5d2311dSJed Brown   switch (jac->schurfactorization) {
518c5d2311dSJed Brown     case PC_FIELDSPLIT_SCHUR_FACTORIZATION_DIAG:
519a04f6461SBarry Smith       /* [A00 0; 0 -S], positive definite, suitable for MINRES */
520c5d2311dSJed Brown       ierr = VecScatterBegin(ilinkA->sctx,x,ilinkA->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
521c5d2311dSJed Brown       ierr = VecScatterBegin(ilinkD->sctx,x,ilinkD->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
522c5d2311dSJed Brown       ierr = VecScatterEnd(ilinkA->sctx,x,ilinkA->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
523c5d2311dSJed Brown       ierr = KSPSolve(ksp,ilinkA->x,ilinkA->y);CHKERRQ(ierr);
524c5d2311dSJed Brown       ierr = VecScatterBegin(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
525c5d2311dSJed Brown       ierr = VecScatterEnd(ilinkD->sctx,x,ilinkD->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
526c5d2311dSJed Brown       ierr = KSPSolve(jac->kspschur,ilinkD->x,ilinkD->y);CHKERRQ(ierr);
527c5d2311dSJed Brown       ierr = VecScale(ilinkD->y,-1.);CHKERRQ(ierr);
528c5d2311dSJed Brown       ierr = VecScatterBegin(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
529c5d2311dSJed Brown       ierr = VecScatterEnd(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
530c5d2311dSJed Brown       ierr = VecScatterEnd(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
531c5d2311dSJed Brown       break;
532c5d2311dSJed Brown     case PC_FIELDSPLIT_SCHUR_FACTORIZATION_LOWER:
533a04f6461SBarry Smith       /* [A00 0; A10 S], suitable for left preconditioning */
534c5d2311dSJed Brown       ierr = VecScatterBegin(ilinkA->sctx,x,ilinkA->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
535c5d2311dSJed Brown       ierr = VecScatterEnd(ilinkA->sctx,x,ilinkA->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
536c5d2311dSJed Brown       ierr = KSPSolve(ksp,ilinkA->x,ilinkA->y);CHKERRQ(ierr);
537c5d2311dSJed Brown       ierr = MatMult(jac->C,ilinkA->y,ilinkD->x);CHKERRQ(ierr);
538c5d2311dSJed Brown       ierr = VecScale(ilinkD->x,-1.);CHKERRQ(ierr);
539c5d2311dSJed Brown       ierr = VecScatterBegin(ilinkD->sctx,x,ilinkD->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
540c5d2311dSJed Brown       ierr = VecScatterBegin(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
541c5d2311dSJed Brown       ierr = VecScatterEnd(ilinkD->sctx,x,ilinkD->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
542c5d2311dSJed Brown       ierr = KSPSolve(jac->kspschur,ilinkD->x,ilinkD->y);CHKERRQ(ierr);
543c5d2311dSJed Brown       ierr = VecScatterBegin(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
544c5d2311dSJed Brown       ierr = VecScatterEnd(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
545c5d2311dSJed Brown       ierr = VecScatterEnd(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
546c5d2311dSJed Brown       break;
547c5d2311dSJed Brown     case PC_FIELDSPLIT_SCHUR_FACTORIZATION_UPPER:
548a04f6461SBarry Smith       /* [A00 A01; 0 S], suitable for right preconditioning */
549c5d2311dSJed Brown       ierr = VecScatterBegin(ilinkD->sctx,x,ilinkD->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
550c5d2311dSJed Brown       ierr = VecScatterEnd(ilinkD->sctx,x,ilinkD->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
551c5d2311dSJed Brown       ierr = KSPSolve(jac->kspschur,ilinkD->x,ilinkD->y);CHKERRQ(ierr);
552c5d2311dSJed Brown       ierr = MatMult(jac->B,ilinkD->y,ilinkA->x);CHKERRQ(ierr);
553c5d2311dSJed Brown       ierr = VecScale(ilinkA->x,-1.);CHKERRQ(ierr);
554c5d2311dSJed Brown       ierr = VecScatterBegin(ilinkA->sctx,x,ilinkA->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
555c5d2311dSJed Brown       ierr = VecScatterBegin(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
556c5d2311dSJed Brown       ierr = VecScatterEnd(ilinkA->sctx,x,ilinkA->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
557c5d2311dSJed Brown       ierr = KSPSolve(ksp,ilinkA->x,ilinkA->y);CHKERRQ(ierr);
558c5d2311dSJed Brown       ierr = VecScatterBegin(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
559c5d2311dSJed Brown       ierr = VecScatterEnd(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
560c5d2311dSJed Brown       ierr = VecScatterEnd(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
561c5d2311dSJed Brown       break;
562c5d2311dSJed Brown     case PC_FIELDSPLIT_SCHUR_FACTORIZATION_FULL:
563a04f6461SBarry Smith       /* [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 */
5643b224e63SBarry Smith       ierr = VecScatterBegin(ilinkA->sctx,x,ilinkA->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
5653b224e63SBarry Smith       ierr = VecScatterEnd(ilinkA->sctx,x,ilinkA->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
5663b224e63SBarry Smith       ierr = KSPSolve(ksp,ilinkA->x,ilinkA->y);CHKERRQ(ierr);
5673b224e63SBarry Smith       ierr = MatMult(jac->C,ilinkA->y,ilinkD->x);CHKERRQ(ierr);
5683b224e63SBarry Smith       ierr = VecScale(ilinkD->x,-1.0);CHKERRQ(ierr);
5693b224e63SBarry Smith       ierr = VecScatterBegin(ilinkD->sctx,x,ilinkD->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
5703b224e63SBarry Smith       ierr = VecScatterEnd(ilinkD->sctx,x,ilinkD->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
5713b224e63SBarry Smith 
5723b224e63SBarry Smith       ierr = KSPSolve(jac->kspschur,ilinkD->x,ilinkD->y);CHKERRQ(ierr);
5733b224e63SBarry Smith       ierr = VecScatterBegin(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
5743b224e63SBarry Smith       ierr = VecScatterEnd(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
5753b224e63SBarry Smith 
5763b224e63SBarry Smith       ierr = MatMult(jac->B,ilinkD->y,ilinkA->y);CHKERRQ(ierr);
5773b224e63SBarry Smith       ierr = VecAXPY(ilinkA->x,-1.0,ilinkA->y);CHKERRQ(ierr);
5783b224e63SBarry Smith       ierr = KSPSolve(ksp,ilinkA->x,ilinkA->y);CHKERRQ(ierr);
5793b224e63SBarry Smith       ierr = VecScatterBegin(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
5803b224e63SBarry Smith       ierr = VecScatterEnd(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
581c5d2311dSJed Brown   }
5823b224e63SBarry Smith   PetscFunctionReturn(0);
5833b224e63SBarry Smith }
5843b224e63SBarry Smith 
5853b224e63SBarry Smith #undef __FUNCT__
5860971522cSBarry Smith #define __FUNCT__ "PCApply_FieldSplit"
5870971522cSBarry Smith static PetscErrorCode PCApply_FieldSplit(PC pc,Vec x,Vec y)
5880971522cSBarry Smith {
5890971522cSBarry Smith   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
5900971522cSBarry Smith   PetscErrorCode    ierr;
5915a9f2f41SSatish Balay   PC_FieldSplitLink ilink = jac->head;
592af93645bSJed Brown   PetscInt          cnt;
5930971522cSBarry Smith 
5940971522cSBarry Smith   PetscFunctionBegin;
59551f519a2SBarry Smith   CHKMEMQ;
59651f519a2SBarry Smith   ierr = VecSetBlockSize(x,jac->bs);CHKERRQ(ierr);
59751f519a2SBarry Smith   ierr = VecSetBlockSize(y,jac->bs);CHKERRQ(ierr);
59851f519a2SBarry Smith 
59979416396SBarry Smith   if (jac->type == PC_COMPOSITE_ADDITIVE) {
6001b9fc7fcSBarry Smith     if (jac->defaultsplit) {
6010971522cSBarry Smith       ierr = VecStrideGatherAll(x,jac->x,INSERT_VALUES);CHKERRQ(ierr);
6025a9f2f41SSatish Balay       while (ilink) {
6035a9f2f41SSatish Balay         ierr = KSPSolve(ilink->ksp,ilink->x,ilink->y);CHKERRQ(ierr);
6045a9f2f41SSatish Balay         ilink = ilink->next;
6050971522cSBarry Smith       }
6060971522cSBarry Smith       ierr = VecStrideScatterAll(jac->y,y,INSERT_VALUES);CHKERRQ(ierr);
6071b9fc7fcSBarry Smith     } else {
608efb30889SBarry Smith       ierr = VecSet(y,0.0);CHKERRQ(ierr);
6095a9f2f41SSatish Balay       while (ilink) {
6105a9f2f41SSatish Balay         ierr = FieldSplitSplitSolveAdd(ilink,x,y);CHKERRQ(ierr);
6115a9f2f41SSatish Balay         ilink = ilink->next;
6121b9fc7fcSBarry Smith       }
6131b9fc7fcSBarry Smith     }
61416913363SBarry Smith   } else if (jac->type == PC_COMPOSITE_MULTIPLICATIVE || jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
61579416396SBarry Smith     if (!jac->w1) {
61679416396SBarry Smith       ierr = VecDuplicate(x,&jac->w1);CHKERRQ(ierr);
61779416396SBarry Smith       ierr = VecDuplicate(x,&jac->w2);CHKERRQ(ierr);
61879416396SBarry Smith     }
619efb30889SBarry Smith     ierr = VecSet(y,0.0);CHKERRQ(ierr);
6205a9f2f41SSatish Balay     ierr = FieldSplitSplitSolveAdd(ilink,x,y);CHKERRQ(ierr);
6213e197d65SBarry Smith     cnt = 1;
6225a9f2f41SSatish Balay     while (ilink->next) {
6235a9f2f41SSatish Balay       ilink = ilink->next;
6243e197d65SBarry Smith       /* compute the residual only over the part of the vector needed */
6253e197d65SBarry Smith       ierr = MatMult(jac->Afield[cnt++],y,ilink->x);CHKERRQ(ierr);
6263e197d65SBarry Smith       ierr = VecScale(ilink->x,-1.0);CHKERRQ(ierr);
6273e197d65SBarry Smith       ierr = VecScatterBegin(ilink->sctx,x,ilink->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
6283e197d65SBarry Smith       ierr = VecScatterEnd(ilink->sctx,x,ilink->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
6293e197d65SBarry Smith       ierr = KSPSolve(ilink->ksp,ilink->x,ilink->y);CHKERRQ(ierr);
6303e197d65SBarry Smith       ierr = VecScatterBegin(ilink->sctx,ilink->y,y,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
6313e197d65SBarry Smith       ierr = VecScatterEnd(ilink->sctx,ilink->y,y,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
6323e197d65SBarry Smith     }
63351f519a2SBarry Smith     if (jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
63411755939SBarry Smith       cnt -= 2;
63551f519a2SBarry Smith       while (ilink->previous) {
63651f519a2SBarry Smith         ilink = ilink->previous;
63711755939SBarry Smith         /* compute the residual only over the part of the vector needed */
63811755939SBarry Smith         ierr = MatMult(jac->Afield[cnt--],y,ilink->x);CHKERRQ(ierr);
63911755939SBarry Smith         ierr = VecScale(ilink->x,-1.0);CHKERRQ(ierr);
64011755939SBarry Smith         ierr = VecScatterBegin(ilink->sctx,x,ilink->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
64111755939SBarry Smith         ierr = VecScatterEnd(ilink->sctx,x,ilink->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
64211755939SBarry Smith         ierr = KSPSolve(ilink->ksp,ilink->x,ilink->y);CHKERRQ(ierr);
64311755939SBarry Smith         ierr = VecScatterBegin(ilink->sctx,ilink->y,y,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
64411755939SBarry Smith         ierr = VecScatterEnd(ilink->sctx,ilink->y,y,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
64551f519a2SBarry Smith       }
64611755939SBarry Smith     }
64765e19b50SBarry Smith   } else SETERRQ1(((PetscObject)pc)->comm,PETSC_ERR_SUP,"Unsupported or unknown composition",(int) jac->type);
64851f519a2SBarry Smith   CHKMEMQ;
6490971522cSBarry Smith   PetscFunctionReturn(0);
6500971522cSBarry Smith }
6510971522cSBarry Smith 
652421e10b8SBarry Smith #define FieldSplitSplitSolveAddTranspose(ilink,xx,yy) \
653ca9f406cSSatish Balay     (VecScatterBegin(ilink->sctx,xx,ilink->y,INSERT_VALUES,SCATTER_FORWARD) || \
654ca9f406cSSatish Balay      VecScatterEnd(ilink->sctx,xx,ilink->y,INSERT_VALUES,SCATTER_FORWARD) || \
655421e10b8SBarry Smith      KSPSolveTranspose(ilink->ksp,ilink->y,ilink->x) || \
656ca9f406cSSatish Balay      VecScatterBegin(ilink->sctx,ilink->x,yy,ADD_VALUES,SCATTER_REVERSE) || \
657ca9f406cSSatish Balay      VecScatterEnd(ilink->sctx,ilink->x,yy,ADD_VALUES,SCATTER_REVERSE))
658421e10b8SBarry Smith 
659421e10b8SBarry Smith #undef __FUNCT__
6608c03b21aSDmitry Karpeev #define __FUNCT__ "PCApplyTranspose_FieldSplit"
661421e10b8SBarry Smith static PetscErrorCode PCApplyTranspose_FieldSplit(PC pc,Vec x,Vec y)
662421e10b8SBarry Smith {
663421e10b8SBarry Smith   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
664421e10b8SBarry Smith   PetscErrorCode    ierr;
665421e10b8SBarry Smith   PC_FieldSplitLink ilink = jac->head;
666421e10b8SBarry Smith 
667421e10b8SBarry Smith   PetscFunctionBegin;
668421e10b8SBarry Smith   CHKMEMQ;
669421e10b8SBarry Smith   ierr = VecSetBlockSize(x,jac->bs);CHKERRQ(ierr);
670421e10b8SBarry Smith   ierr = VecSetBlockSize(y,jac->bs);CHKERRQ(ierr);
671421e10b8SBarry Smith 
672421e10b8SBarry Smith   if (jac->type == PC_COMPOSITE_ADDITIVE) {
673421e10b8SBarry Smith     if (jac->defaultsplit) {
674421e10b8SBarry Smith       ierr = VecStrideGatherAll(x,jac->x,INSERT_VALUES);CHKERRQ(ierr);
675421e10b8SBarry Smith       while (ilink) {
676421e10b8SBarry Smith 	ierr = KSPSolveTranspose(ilink->ksp,ilink->x,ilink->y);CHKERRQ(ierr);
677421e10b8SBarry Smith 	ilink = ilink->next;
678421e10b8SBarry Smith       }
679421e10b8SBarry Smith       ierr = VecStrideScatterAll(jac->y,y,INSERT_VALUES);CHKERRQ(ierr);
680421e10b8SBarry Smith     } else {
681421e10b8SBarry Smith       ierr = VecSet(y,0.0);CHKERRQ(ierr);
682421e10b8SBarry Smith       while (ilink) {
683421e10b8SBarry Smith         ierr = FieldSplitSplitSolveAddTranspose(ilink,x,y);CHKERRQ(ierr);
684421e10b8SBarry Smith 	ilink = ilink->next;
685421e10b8SBarry Smith       }
686421e10b8SBarry Smith     }
687421e10b8SBarry Smith   } else {
688421e10b8SBarry Smith     if (!jac->w1) {
689421e10b8SBarry Smith       ierr = VecDuplicate(x,&jac->w1);CHKERRQ(ierr);
690421e10b8SBarry Smith       ierr = VecDuplicate(x,&jac->w2);CHKERRQ(ierr);
691421e10b8SBarry Smith     }
692421e10b8SBarry Smith     ierr = VecSet(y,0.0);CHKERRQ(ierr);
693421e10b8SBarry Smith     if (jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
694421e10b8SBarry Smith       ierr = FieldSplitSplitSolveAddTranspose(ilink,x,y);CHKERRQ(ierr);
695421e10b8SBarry Smith       while (ilink->next) {
696421e10b8SBarry Smith         ilink = ilink->next;
6979989ab13SBarry Smith         ierr  = MatMultTranspose(pc->mat,y,jac->w1);CHKERRQ(ierr);
698421e10b8SBarry Smith         ierr  = VecWAXPY(jac->w2,-1.0,jac->w1,x);CHKERRQ(ierr);
699421e10b8SBarry Smith         ierr  = FieldSplitSplitSolveAddTranspose(ilink,jac->w2,y);CHKERRQ(ierr);
700421e10b8SBarry Smith       }
701421e10b8SBarry Smith       while (ilink->previous) {
702421e10b8SBarry Smith         ilink = ilink->previous;
7039989ab13SBarry Smith         ierr  = MatMultTranspose(pc->mat,y,jac->w1);CHKERRQ(ierr);
704421e10b8SBarry Smith         ierr  = VecWAXPY(jac->w2,-1.0,jac->w1,x);CHKERRQ(ierr);
705421e10b8SBarry Smith         ierr  = FieldSplitSplitSolveAddTranspose(ilink,jac->w2,y);CHKERRQ(ierr);
706421e10b8SBarry Smith       }
707421e10b8SBarry Smith     } else {
708421e10b8SBarry Smith       while (ilink->next) {   /* get to last entry in linked list */
709421e10b8SBarry Smith 	ilink = ilink->next;
710421e10b8SBarry Smith       }
711421e10b8SBarry Smith       ierr = FieldSplitSplitSolveAddTranspose(ilink,x,y);CHKERRQ(ierr);
712421e10b8SBarry Smith       while (ilink->previous) {
713421e10b8SBarry Smith 	ilink = ilink->previous;
7149989ab13SBarry Smith 	ierr  = MatMultTranspose(pc->mat,y,jac->w1);CHKERRQ(ierr);
715421e10b8SBarry Smith 	ierr  = VecWAXPY(jac->w2,-1.0,jac->w1,x);CHKERRQ(ierr);
716421e10b8SBarry Smith 	ierr  = FieldSplitSplitSolveAddTranspose(ilink,jac->w2,y);CHKERRQ(ierr);
717421e10b8SBarry Smith       }
718421e10b8SBarry Smith     }
719421e10b8SBarry Smith   }
720421e10b8SBarry Smith   CHKMEMQ;
721421e10b8SBarry Smith   PetscFunctionReturn(0);
722421e10b8SBarry Smith }
723421e10b8SBarry Smith 
7240971522cSBarry Smith #undef __FUNCT__
7250971522cSBarry Smith #define __FUNCT__ "PCDestroy_FieldSplit"
7260971522cSBarry Smith static PetscErrorCode PCDestroy_FieldSplit(PC pc)
7270971522cSBarry Smith {
7280971522cSBarry Smith   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
7290971522cSBarry Smith   PetscErrorCode    ierr;
7305a9f2f41SSatish Balay   PC_FieldSplitLink ilink = jac->head,next;
7310971522cSBarry Smith 
7320971522cSBarry Smith   PetscFunctionBegin;
7335a9f2f41SSatish Balay   while (ilink) {
7345a9f2f41SSatish Balay     ierr = KSPDestroy(ilink->ksp);CHKERRQ(ierr);
7355a9f2f41SSatish Balay     if (ilink->x) {ierr = VecDestroy(ilink->x);CHKERRQ(ierr);}
7365a9f2f41SSatish Balay     if (ilink->y) {ierr = VecDestroy(ilink->y);CHKERRQ(ierr);}
7375a9f2f41SSatish Balay     if (ilink->sctx) {ierr = VecScatterDestroy(ilink->sctx);CHKERRQ(ierr);}
738704ba839SBarry Smith     if (ilink->is) {ierr = ISDestroy(ilink->is);CHKERRQ(ierr);}
7395a9f2f41SSatish Balay     next = ilink->next;
7407e8c30b6SJed Brown     ierr = PetscFree(ilink->splitname);CHKERRQ(ierr);
741704ba839SBarry Smith     ierr = PetscFree(ilink->fields);CHKERRQ(ierr);
742704ba839SBarry Smith     ierr = PetscFree(ilink);CHKERRQ(ierr);
7435a9f2f41SSatish Balay     ilink = next;
7440971522cSBarry Smith   }
74505b42c5fSBarry Smith   ierr = PetscFree2(jac->x,jac->y);CHKERRQ(ierr);
746519d70e2SJed Brown   if (jac->mat && jac->mat != jac->pmat) {ierr = MatDestroyMatrices(jac->nsplits,&jac->mat);CHKERRQ(ierr);}
74797bbdb24SBarry Smith   if (jac->pmat) {ierr = MatDestroyMatrices(jac->nsplits,&jac->pmat);CHKERRQ(ierr);}
74868dd23aaSBarry Smith   if (jac->Afield) {ierr = MatDestroyMatrices(jac->nsplits,&jac->Afield);CHKERRQ(ierr);}
74979416396SBarry Smith   if (jac->w1) {ierr = VecDestroy(jac->w1);CHKERRQ(ierr);}
75079416396SBarry Smith   if (jac->w2) {ierr = VecDestroy(jac->w2);CHKERRQ(ierr);}
7513b224e63SBarry Smith   if (jac->schur) {ierr = MatDestroy(jac->schur);CHKERRQ(ierr);}
752084e4875SJed Brown   if (jac->schur_user) {ierr = MatDestroy(jac->schur_user);CHKERRQ(ierr);}
753d0f46423SBarry Smith   if (jac->kspschur) {ierr = KSPDestroy(jac->kspschur);CHKERRQ(ierr);}
7543b224e63SBarry Smith   if (jac->B) {ierr = MatDestroy(jac->B);CHKERRQ(ierr);}
7553b224e63SBarry Smith   if (jac->C) {ierr = MatDestroy(jac->C);CHKERRQ(ierr);}
7560971522cSBarry Smith   ierr = PetscFree(jac);CHKERRQ(ierr);
7570971522cSBarry Smith   PetscFunctionReturn(0);
7580971522cSBarry Smith }
7590971522cSBarry Smith 
7600971522cSBarry Smith #undef __FUNCT__
7610971522cSBarry Smith #define __FUNCT__ "PCSetFromOptions_FieldSplit"
7620971522cSBarry Smith static PetscErrorCode PCSetFromOptions_FieldSplit(PC pc)
7630971522cSBarry Smith {
7641b9fc7fcSBarry Smith   PetscErrorCode  ierr;
7656c924f48SJed Brown   PetscInt        bs;
766*bc59fbc5SBarry Smith   PetscBool       flg,stokes = PETSC_FALSE;
7679dcbbd2bSBarry Smith   PC_FieldSplit   *jac = (PC_FieldSplit*)pc->data;
7683b224e63SBarry Smith   PCCompositeType ctype;
7691b9fc7fcSBarry Smith 
7700971522cSBarry Smith   PetscFunctionBegin;
7711b9fc7fcSBarry Smith   ierr = PetscOptionsHead("FieldSplit options");CHKERRQ(ierr);
772acfcf0e5SJed Brown   ierr = PetscOptionsBool("-pc_fieldsplit_real_diagonal","Use diagonal blocks of the operator","PCFieldSplitSetRealDiagonal",jac->realdiagonal,&jac->realdiagonal,PETSC_NULL);CHKERRQ(ierr);
77351f519a2SBarry Smith   ierr = PetscOptionsInt("-pc_fieldsplit_block_size","Blocksize that defines number of fields","PCFieldSplitSetBlockSize",jac->bs,&bs,&flg);CHKERRQ(ierr);
77451f519a2SBarry Smith   if (flg) {
77551f519a2SBarry Smith     ierr = PCFieldSplitSetBlockSize(pc,bs);CHKERRQ(ierr);
77651f519a2SBarry Smith   }
777704ba839SBarry Smith 
778435f959eSBarry Smith   ierr = PetscOptionsGetBool(((PetscObject)pc)->prefix,"-pc_fieldsplit_detect_saddle_point",&stokes,PETSC_NULL);CHKERRQ(ierr);
779c0adfefeSBarry Smith   if (stokes) {
780c0adfefeSBarry Smith     ierr = PCFieldSplitSetType(pc,PC_COMPOSITE_SCHUR);CHKERRQ(ierr);
781c0adfefeSBarry Smith     jac->schurpre = PC_FIELDSPLIT_SCHUR_PRE_SELF;
782c0adfefeSBarry Smith   }
783c0adfefeSBarry Smith 
7843b224e63SBarry Smith   ierr = PetscOptionsEnum("-pc_fieldsplit_type","Type of composition","PCFieldSplitSetType",PCCompositeTypes,(PetscEnum)jac->type,(PetscEnum*)&ctype,&flg);CHKERRQ(ierr);
7853b224e63SBarry Smith   if (flg) {
7863b224e63SBarry Smith     ierr = PCFieldSplitSetType(pc,ctype);CHKERRQ(ierr);
7873b224e63SBarry Smith   }
788d32f9abdSBarry Smith 
789c30613efSMatthew Knepley   /* Only setup fields once */
790c30613efSMatthew Knepley   if ((jac->bs > 0) && (jac->nsplits == 0)) {
791d32f9abdSBarry Smith     /* only allow user to set fields from command line if bs is already known.
792d32f9abdSBarry Smith        otherwise user can set them in PCFieldSplitSetDefaults() */
7936c924f48SJed Brown     ierr = PCFieldSplitSetRuntimeSplits_Private(pc);CHKERRQ(ierr);
7946c924f48SJed Brown     if (jac->splitdefined) {ierr = PetscInfo(pc,"Splits defined using the options database\n");CHKERRQ(ierr);}
795d32f9abdSBarry Smith   }
796c5d2311dSJed Brown   if (jac->type == PC_COMPOSITE_SCHUR) {
797c5d2311dSJed Brown     ierr = PetscOptionsEnum("-pc_fieldsplit_schur_factorization_type","Factorization to use","None",PCFieldSplitSchurFactorizationTypes,(PetscEnum)jac->schurfactorization,(PetscEnum*)&jac->schurfactorization,PETSC_NULL);CHKERRQ(ierr);
798084e4875SJed Brown     ierr = PetscOptionsEnum("-pc_fieldsplit_schur_precondition","How to build preconditioner for Schur complement","PCFieldSplitSchurPrecondition",PCFieldSplitSchurPreTypes,(PetscEnum)jac->schurpre,(PetscEnum*)&jac->schurpre,PETSC_NULL);CHKERRQ(ierr);
799c5d2311dSJed Brown   }
8001b9fc7fcSBarry Smith   ierr = PetscOptionsTail();CHKERRQ(ierr);
8010971522cSBarry Smith   PetscFunctionReturn(0);
8020971522cSBarry Smith }
8030971522cSBarry Smith 
8040971522cSBarry Smith /*------------------------------------------------------------------------------------*/
8050971522cSBarry Smith 
8060971522cSBarry Smith EXTERN_C_BEGIN
8070971522cSBarry Smith #undef __FUNCT__
8080971522cSBarry Smith #define __FUNCT__ "PCFieldSplitSetFields_FieldSplit"
8097087cfbeSBarry Smith PetscErrorCode  PCFieldSplitSetFields_FieldSplit(PC pc,const char splitname[],PetscInt n,const PetscInt *fields)
8100971522cSBarry Smith {
81197bbdb24SBarry Smith   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
8120971522cSBarry Smith   PetscErrorCode    ierr;
8135a9f2f41SSatish Balay   PC_FieldSplitLink ilink,next = jac->head;
81469a612a9SBarry Smith   char              prefix[128];
81551f519a2SBarry Smith   PetscInt          i;
8160971522cSBarry Smith 
8170971522cSBarry Smith   PetscFunctionBegin;
8186c924f48SJed Brown   if (jac->splitdefined) {
8196c924f48SJed Brown     ierr = PetscInfo1(pc,"Ignoring new split \"%s\" because the splits have already been defined\n",splitname);CHKERRQ(ierr);
8206c924f48SJed Brown     PetscFunctionReturn(0);
8216c924f48SJed Brown   }
82251f519a2SBarry Smith   for (i=0; i<n; i++) {
823e32f2f54SBarry Smith     if (fields[i] >= jac->bs) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Field %D requested but only %D exist",fields[i],jac->bs);
824e32f2f54SBarry Smith     if (fields[i] < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Negative field %D requested",fields[i]);
82551f519a2SBarry Smith   }
826704ba839SBarry Smith   ierr = PetscNew(struct _PC_FieldSplitLink,&ilink);CHKERRQ(ierr);
827a04f6461SBarry Smith   if (splitname) {
828db4c96c1SJed Brown     ierr = PetscStrallocpy(splitname,&ilink->splitname);CHKERRQ(ierr);
829a04f6461SBarry Smith   } else {
830a04f6461SBarry Smith     ierr = PetscMalloc(3*sizeof(char),&ilink->splitname);CHKERRQ(ierr);
831a04f6461SBarry Smith     ierr = PetscSNPrintf(ilink->splitname,2,"%s",jac->nsplits);CHKERRQ(ierr);
832a04f6461SBarry Smith   }
833704ba839SBarry Smith   ierr = PetscMalloc(n*sizeof(PetscInt),&ilink->fields);CHKERRQ(ierr);
8345a9f2f41SSatish Balay   ierr = PetscMemcpy(ilink->fields,fields,n*sizeof(PetscInt));CHKERRQ(ierr);
8355a9f2f41SSatish Balay   ilink->nfields = n;
8365a9f2f41SSatish Balay   ilink->next    = PETSC_NULL;
8377adad957SLisandro Dalcin   ierr           = KSPCreate(((PetscObject)pc)->comm,&ilink->ksp);CHKERRQ(ierr);
8381cee3971SBarry Smith   ierr           = PetscObjectIncrementTabLevel((PetscObject)ilink->ksp,(PetscObject)pc,1);CHKERRQ(ierr);
8395a9f2f41SSatish Balay   ierr           = KSPSetType(ilink->ksp,KSPPREONLY);CHKERRQ(ierr);
8409005cf84SBarry Smith   ierr           = PetscLogObjectParent((PetscObject)pc,(PetscObject)ilink->ksp);CHKERRQ(ierr);
84169a612a9SBarry Smith 
842a04f6461SBarry Smith   ierr = PetscSNPrintf(prefix,sizeof prefix,"%sfieldsplit_%s_",((PetscObject)pc)->prefix?((PetscObject)pc)->prefix:"",ilink->splitname);CHKERRQ(ierr);
8435a9f2f41SSatish Balay   ierr = KSPSetOptionsPrefix(ilink->ksp,prefix);CHKERRQ(ierr);
8440971522cSBarry Smith 
8450971522cSBarry Smith   if (!next) {
8465a9f2f41SSatish Balay     jac->head       = ilink;
84751f519a2SBarry Smith     ilink->previous = PETSC_NULL;
8480971522cSBarry Smith   } else {
8490971522cSBarry Smith     while (next->next) {
8500971522cSBarry Smith       next = next->next;
8510971522cSBarry Smith     }
8525a9f2f41SSatish Balay     next->next      = ilink;
85351f519a2SBarry Smith     ilink->previous = next;
8540971522cSBarry Smith   }
8550971522cSBarry Smith   jac->nsplits++;
8560971522cSBarry Smith   PetscFunctionReturn(0);
8570971522cSBarry Smith }
8580971522cSBarry Smith EXTERN_C_END
8590971522cSBarry Smith 
860e69d4d44SBarry Smith EXTERN_C_BEGIN
861e69d4d44SBarry Smith #undef __FUNCT__
862e69d4d44SBarry Smith #define __FUNCT__ "PCFieldSplitGetSubKSP_FieldSplit_Schur"
8637087cfbeSBarry Smith PetscErrorCode  PCFieldSplitGetSubKSP_FieldSplit_Schur(PC pc,PetscInt *n,KSP **subksp)
864e69d4d44SBarry Smith {
865e69d4d44SBarry Smith   PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
866e69d4d44SBarry Smith   PetscErrorCode ierr;
867e69d4d44SBarry Smith 
868e69d4d44SBarry Smith   PetscFunctionBegin;
869519d70e2SJed Brown   ierr = PetscMalloc(jac->nsplits*sizeof(KSP),subksp);CHKERRQ(ierr);
870e69d4d44SBarry Smith   ierr = MatSchurComplementGetKSP(jac->schur,*subksp);CHKERRQ(ierr);
871e69d4d44SBarry Smith   (*subksp)[1] = jac->kspschur;
872084e4875SJed Brown   *n = jac->nsplits;
873e69d4d44SBarry Smith   PetscFunctionReturn(0);
874e69d4d44SBarry Smith }
875e69d4d44SBarry Smith EXTERN_C_END
8760971522cSBarry Smith 
8770971522cSBarry Smith EXTERN_C_BEGIN
8780971522cSBarry Smith #undef __FUNCT__
87969a612a9SBarry Smith #define __FUNCT__ "PCFieldSplitGetSubKSP_FieldSplit"
8807087cfbeSBarry Smith PetscErrorCode  PCFieldSplitGetSubKSP_FieldSplit(PC pc,PetscInt *n,KSP **subksp)
8810971522cSBarry Smith {
8820971522cSBarry Smith   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
8830971522cSBarry Smith   PetscErrorCode    ierr;
8840971522cSBarry Smith   PetscInt          cnt = 0;
8855a9f2f41SSatish Balay   PC_FieldSplitLink ilink = jac->head;
8860971522cSBarry Smith 
8870971522cSBarry Smith   PetscFunctionBegin;
88869a612a9SBarry Smith   ierr = PetscMalloc(jac->nsplits*sizeof(KSP*),subksp);CHKERRQ(ierr);
8895a9f2f41SSatish Balay   while (ilink) {
8905a9f2f41SSatish Balay     (*subksp)[cnt++] = ilink->ksp;
8915a9f2f41SSatish Balay     ilink = ilink->next;
8920971522cSBarry Smith   }
893e32f2f54SBarry Smith   if (cnt != jac->nsplits) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Corrupt PCFIELDSPLIT object: number splits in linked list %D in object %D",cnt,jac->nsplits);
8940971522cSBarry Smith   *n = jac->nsplits;
8950971522cSBarry Smith   PetscFunctionReturn(0);
8960971522cSBarry Smith }
8970971522cSBarry Smith EXTERN_C_END
8980971522cSBarry Smith 
899704ba839SBarry Smith EXTERN_C_BEGIN
900704ba839SBarry Smith #undef __FUNCT__
901704ba839SBarry Smith #define __FUNCT__ "PCFieldSplitSetIS_FieldSplit"
9027087cfbeSBarry Smith PetscErrorCode  PCFieldSplitSetIS_FieldSplit(PC pc,const char splitname[],IS is)
903704ba839SBarry Smith {
904704ba839SBarry Smith   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
905704ba839SBarry Smith   PetscErrorCode    ierr;
906704ba839SBarry Smith   PC_FieldSplitLink ilink, next = jac->head;
907704ba839SBarry Smith   char              prefix[128];
908704ba839SBarry Smith 
909704ba839SBarry Smith   PetscFunctionBegin;
9106c924f48SJed Brown   if (jac->splitdefined) {
9116c924f48SJed Brown     ierr = PetscInfo1(pc,"Ignoring new split \"%s\" because the splits have already been defined\n",splitname);CHKERRQ(ierr);
9126c924f48SJed Brown     PetscFunctionReturn(0);
9136c924f48SJed Brown   }
91416913363SBarry Smith   ierr = PetscNew(struct _PC_FieldSplitLink,&ilink);CHKERRQ(ierr);
915a04f6461SBarry Smith   if (splitname) {
916db4c96c1SJed Brown     ierr = PetscStrallocpy(splitname,&ilink->splitname);CHKERRQ(ierr);
917a04f6461SBarry Smith   } else {
918a04f6461SBarry Smith     ierr = PetscMalloc(3*sizeof(char),&ilink->splitname);CHKERRQ(ierr);
919a04f6461SBarry Smith     ierr = PetscSNPrintf(ilink->splitname,2,"%s",jac->nsplits);CHKERRQ(ierr);
920a04f6461SBarry Smith   }
9211ab39975SBarry Smith   ilink->is      = is;
9221ab39975SBarry Smith   ierr           = PetscObjectReference((PetscObject)is);CHKERRQ(ierr);
923704ba839SBarry Smith   ilink->next    = PETSC_NULL;
924704ba839SBarry Smith   ierr           = KSPCreate(((PetscObject)pc)->comm,&ilink->ksp);CHKERRQ(ierr);
9251cee3971SBarry Smith   ierr           = PetscObjectIncrementTabLevel((PetscObject)ilink->ksp,(PetscObject)pc,1);CHKERRQ(ierr);
926704ba839SBarry Smith   ierr           = KSPSetType(ilink->ksp,KSPPREONLY);CHKERRQ(ierr);
9279005cf84SBarry Smith   ierr           = PetscLogObjectParent((PetscObject)pc,(PetscObject)ilink->ksp);CHKERRQ(ierr);
928704ba839SBarry Smith 
929a04f6461SBarry Smith   ierr = PetscSNPrintf(prefix,sizeof prefix,"%sfieldsplit_%s_",((PetscObject)pc)->prefix?((PetscObject)pc)->prefix:"",ilink->splitname);CHKERRQ(ierr);
930704ba839SBarry Smith   ierr = KSPSetOptionsPrefix(ilink->ksp,prefix);CHKERRQ(ierr);
931704ba839SBarry Smith 
932704ba839SBarry Smith   if (!next) {
933704ba839SBarry Smith     jac->head       = ilink;
934704ba839SBarry Smith     ilink->previous = PETSC_NULL;
935704ba839SBarry Smith   } else {
936704ba839SBarry Smith     while (next->next) {
937704ba839SBarry Smith       next = next->next;
938704ba839SBarry Smith     }
939704ba839SBarry Smith     next->next      = ilink;
940704ba839SBarry Smith     ilink->previous = next;
941704ba839SBarry Smith   }
942704ba839SBarry Smith   jac->nsplits++;
943704ba839SBarry Smith 
944704ba839SBarry Smith   PetscFunctionReturn(0);
945704ba839SBarry Smith }
946704ba839SBarry Smith EXTERN_C_END
947704ba839SBarry Smith 
9480971522cSBarry Smith #undef __FUNCT__
9490971522cSBarry Smith #define __FUNCT__ "PCFieldSplitSetFields"
9500971522cSBarry Smith /*@
9510971522cSBarry Smith     PCFieldSplitSetFields - Sets the fields for one particular split in the field split preconditioner
9520971522cSBarry Smith 
953ad4df100SBarry Smith     Logically Collective on PC
9540971522cSBarry Smith 
9550971522cSBarry Smith     Input Parameters:
9560971522cSBarry Smith +   pc  - the preconditioner context
957a04f6461SBarry Smith .   splitname - name of this split, if PETSC_NULL the number of the split is used
9580971522cSBarry Smith .   n - the number of fields in this split
959db4c96c1SJed Brown -   fields - the fields in this split
9600971522cSBarry Smith 
9610971522cSBarry Smith     Level: intermediate
9620971522cSBarry Smith 
963d32f9abdSBarry Smith     Notes: Use PCFieldSplitSetIS() to set a completely general set of indices as a field.
964d32f9abdSBarry Smith 
965d32f9abdSBarry Smith      The PCFieldSplitSetFields() is for defining fields as a strided blocks. For example, if the block
966d32f9abdSBarry Smith      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
967d32f9abdSBarry Smith      0xx3xx6xx9xx12 ... x1xx4xx7xx ... xx2xx5xx8xx.. 01x34x67x... 0x1x3x5x7.. x12x45x78x....
968d32f9abdSBarry Smith      where the numbered entries indicate what is in the field.
969d32f9abdSBarry Smith 
970db4c96c1SJed Brown      This function is called once per split (it creates a new split each time).  Solve options
971db4c96c1SJed Brown      for this split will be available under the prefix -fieldsplit_SPLITNAME_.
972db4c96c1SJed Brown 
973d32f9abdSBarry Smith .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetBlockSize(), PCFieldSplitSetIS()
9740971522cSBarry Smith 
9750971522cSBarry Smith @*/
9767087cfbeSBarry Smith PetscErrorCode  PCFieldSplitSetFields(PC pc,const char splitname[],PetscInt n,const PetscInt *fields)
9770971522cSBarry Smith {
9784ac538c5SBarry Smith   PetscErrorCode ierr;
9790971522cSBarry Smith 
9800971522cSBarry Smith   PetscFunctionBegin;
9810700a824SBarry Smith   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
982db4c96c1SJed Brown   PetscValidCharPointer(splitname,2);
983db4c96c1SJed Brown   if (n < 1) SETERRQ2(((PetscObject)pc)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Provided number of fields %D in split \"%s\" not positive",n,splitname);
984db4c96c1SJed Brown   PetscValidIntPointer(fields,3);
9854ac538c5SBarry Smith   ierr = PetscTryMethod(pc,"PCFieldSplitSetFields_C",(PC,const char[],PetscInt,const PetscInt *),(pc,splitname,n,fields));CHKERRQ(ierr);
9860971522cSBarry Smith   PetscFunctionReturn(0);
9870971522cSBarry Smith }
9880971522cSBarry Smith 
9890971522cSBarry Smith #undef __FUNCT__
990704ba839SBarry Smith #define __FUNCT__ "PCFieldSplitSetIS"
991704ba839SBarry Smith /*@
992704ba839SBarry Smith     PCFieldSplitSetIS - Sets the exact elements for field
993704ba839SBarry Smith 
994ad4df100SBarry Smith     Logically Collective on PC
995704ba839SBarry Smith 
996704ba839SBarry Smith     Input Parameters:
997704ba839SBarry Smith +   pc  - the preconditioner context
998a04f6461SBarry Smith .   splitname - name of this split, if PETSC_NULL the number of the split is used
999db4c96c1SJed Brown -   is - the index set that defines the vector elements in this field
1000704ba839SBarry Smith 
1001d32f9abdSBarry Smith 
1002a6ffb8dbSJed Brown     Notes:
1003a6ffb8dbSJed Brown     Use PCFieldSplitSetFields(), for fields defined by strided types.
1004a6ffb8dbSJed Brown 
1005db4c96c1SJed Brown     This function is called once per split (it creates a new split each time).  Solve options
1006db4c96c1SJed Brown     for this split will be available under the prefix -fieldsplit_SPLITNAME_.
1007d32f9abdSBarry Smith 
1008704ba839SBarry Smith     Level: intermediate
1009704ba839SBarry Smith 
1010704ba839SBarry Smith .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetBlockSize()
1011704ba839SBarry Smith 
1012704ba839SBarry Smith @*/
10137087cfbeSBarry Smith PetscErrorCode  PCFieldSplitSetIS(PC pc,const char splitname[],IS is)
1014704ba839SBarry Smith {
10154ac538c5SBarry Smith   PetscErrorCode ierr;
1016704ba839SBarry Smith 
1017704ba839SBarry Smith   PetscFunctionBegin;
10180700a824SBarry Smith   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
1019db4c96c1SJed Brown   PetscValidCharPointer(splitname,2);
1020db4c96c1SJed Brown   PetscValidHeaderSpecific(is,IS_CLASSID,3);
10214ac538c5SBarry Smith   ierr = PetscTryMethod(pc,"PCFieldSplitSetIS_C",(PC,const char[],IS),(pc,splitname,is));CHKERRQ(ierr);
1022704ba839SBarry Smith   PetscFunctionReturn(0);
1023704ba839SBarry Smith }
1024704ba839SBarry Smith 
1025704ba839SBarry Smith #undef __FUNCT__
102651f519a2SBarry Smith #define __FUNCT__ "PCFieldSplitSetBlockSize"
102751f519a2SBarry Smith /*@
102851f519a2SBarry Smith     PCFieldSplitSetBlockSize - Sets the block size for defining where fields start in the
102951f519a2SBarry Smith       fieldsplit preconditioner. If not set the matrix block size is used.
103051f519a2SBarry Smith 
1031ad4df100SBarry Smith     Logically Collective on PC
103251f519a2SBarry Smith 
103351f519a2SBarry Smith     Input Parameters:
103451f519a2SBarry Smith +   pc  - the preconditioner context
103551f519a2SBarry Smith -   bs - the block size
103651f519a2SBarry Smith 
103751f519a2SBarry Smith     Level: intermediate
103851f519a2SBarry Smith 
103951f519a2SBarry Smith .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetFields()
104051f519a2SBarry Smith 
104151f519a2SBarry Smith @*/
10427087cfbeSBarry Smith PetscErrorCode  PCFieldSplitSetBlockSize(PC pc,PetscInt bs)
104351f519a2SBarry Smith {
10444ac538c5SBarry Smith   PetscErrorCode ierr;
104551f519a2SBarry Smith 
104651f519a2SBarry Smith   PetscFunctionBegin;
10470700a824SBarry Smith   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
1048c5eb9154SBarry Smith   PetscValidLogicalCollectiveInt(pc,bs,2);
10494ac538c5SBarry Smith   ierr = PetscTryMethod(pc,"PCFieldSplitSetBlockSize_C",(PC,PetscInt),(pc,bs));CHKERRQ(ierr);
105051f519a2SBarry Smith   PetscFunctionReturn(0);
105151f519a2SBarry Smith }
105251f519a2SBarry Smith 
105351f519a2SBarry Smith #undef __FUNCT__
105469a612a9SBarry Smith #define __FUNCT__ "PCFieldSplitGetSubKSP"
10550971522cSBarry Smith /*@C
105669a612a9SBarry Smith    PCFieldSplitGetSubKSP - Gets the KSP contexts for all splits
10570971522cSBarry Smith 
105869a612a9SBarry Smith    Collective on KSP
10590971522cSBarry Smith 
10600971522cSBarry Smith    Input Parameter:
10610971522cSBarry Smith .  pc - the preconditioner context
10620971522cSBarry Smith 
10630971522cSBarry Smith    Output Parameters:
10640971522cSBarry Smith +  n - the number of split
106569a612a9SBarry Smith -  pc - the array of KSP contexts
10660971522cSBarry Smith 
10670971522cSBarry Smith    Note:
1068d32f9abdSBarry Smith    After PCFieldSplitGetSubKSP() the array of KSPs IS to be freed by the user
1069d32f9abdSBarry Smith    (not the KSP just the array that contains them).
10700971522cSBarry Smith 
107169a612a9SBarry Smith    You must call KSPSetUp() before calling PCFieldSplitGetSubKSP().
10720971522cSBarry Smith 
10730971522cSBarry Smith    Level: advanced
10740971522cSBarry Smith 
10750971522cSBarry Smith .seealso: PCFIELDSPLIT
10760971522cSBarry Smith @*/
10777087cfbeSBarry Smith PetscErrorCode  PCFieldSplitGetSubKSP(PC pc,PetscInt *n,KSP *subksp[])
10780971522cSBarry Smith {
10794ac538c5SBarry Smith   PetscErrorCode ierr;
10800971522cSBarry Smith 
10810971522cSBarry Smith   PetscFunctionBegin;
10820700a824SBarry Smith   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
10830971522cSBarry Smith   PetscValidIntPointer(n,2);
10844ac538c5SBarry Smith   ierr = PetscUseMethod(pc,"PCFieldSplitGetSubKSP_C",(PC,PetscInt*,KSP **),(pc,n,subksp));CHKERRQ(ierr);
10850971522cSBarry Smith   PetscFunctionReturn(0);
10860971522cSBarry Smith }
10870971522cSBarry Smith 
1088e69d4d44SBarry Smith #undef __FUNCT__
1089e69d4d44SBarry Smith #define __FUNCT__ "PCFieldSplitSchurPrecondition"
1090e69d4d44SBarry Smith /*@
1091e69d4d44SBarry Smith     PCFieldSplitSchurPrecondition -  Indicates if the Schur complement is preconditioned by a preconditioner constructed by the
1092a04f6461SBarry Smith       A11 matrix. Otherwise no preconditioner is used.
1093e69d4d44SBarry Smith 
1094e69d4d44SBarry Smith     Collective on PC
1095e69d4d44SBarry Smith 
1096e69d4d44SBarry Smith     Input Parameters:
1097e69d4d44SBarry Smith +   pc  - the preconditioner context
1098084e4875SJed Brown .   ptype - which matrix to use for preconditioning the Schur complement
1099084e4875SJed Brown -   userpre - matrix to use for preconditioning, or PETSC_NULL
1100084e4875SJed Brown 
1101084e4875SJed Brown     Notes:
1102a04f6461SBarry Smith     The default is to use the block on the diagonal of the preconditioning matrix.  This is A11, in the (1,1) position.
1103084e4875SJed Brown     There are currently no preconditioners that work directly with the Schur complement so setting
1104084e4875SJed Brown     PC_FIELDSPLIT_SCHUR_PRE_SELF is observationally equivalent to -fieldsplit_1_pc_type none.
1105e69d4d44SBarry Smith 
1106e69d4d44SBarry Smith     Options Database:
1107084e4875SJed Brown .     -pc_fieldsplit_schur_precondition <self,user,diag> default is diag
1108e69d4d44SBarry Smith 
1109e69d4d44SBarry Smith     Level: intermediate
1110e69d4d44SBarry Smith 
1111084e4875SJed Brown .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetFields(), PCFieldSplitSchurPreType
1112e69d4d44SBarry Smith 
1113e69d4d44SBarry Smith @*/
11147087cfbeSBarry Smith PetscErrorCode  PCFieldSplitSchurPrecondition(PC pc,PCFieldSplitSchurPreType ptype,Mat pre)
1115e69d4d44SBarry Smith {
11164ac538c5SBarry Smith   PetscErrorCode ierr;
1117e69d4d44SBarry Smith 
1118e69d4d44SBarry Smith   PetscFunctionBegin;
11190700a824SBarry Smith   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
11204ac538c5SBarry Smith   ierr = PetscTryMethod(pc,"PCFieldSplitSchurPrecondition_C",(PC,PCFieldSplitSchurPreType,Mat),(pc,ptype,pre));CHKERRQ(ierr);
1121e69d4d44SBarry Smith   PetscFunctionReturn(0);
1122e69d4d44SBarry Smith }
1123e69d4d44SBarry Smith 
1124e69d4d44SBarry Smith EXTERN_C_BEGIN
1125e69d4d44SBarry Smith #undef __FUNCT__
1126e69d4d44SBarry Smith #define __FUNCT__ "PCFieldSplitSchurPrecondition_FieldSplit"
11277087cfbeSBarry Smith PetscErrorCode  PCFieldSplitSchurPrecondition_FieldSplit(PC pc,PCFieldSplitSchurPreType ptype,Mat pre)
1128e69d4d44SBarry Smith {
1129e69d4d44SBarry Smith   PC_FieldSplit  *jac = (PC_FieldSplit*)pc->data;
1130084e4875SJed Brown   PetscErrorCode  ierr;
1131e69d4d44SBarry Smith 
1132e69d4d44SBarry Smith   PetscFunctionBegin;
1133084e4875SJed Brown   jac->schurpre = ptype;
1134084e4875SJed Brown   if (pre) {
1135084e4875SJed Brown     if (jac->schur_user) {ierr = MatDestroy(jac->schur_user);CHKERRQ(ierr);}
1136084e4875SJed Brown     jac->schur_user = pre;
1137084e4875SJed Brown     ierr = PetscObjectReference((PetscObject)jac->schur_user);CHKERRQ(ierr);
1138084e4875SJed Brown   }
1139e69d4d44SBarry Smith   PetscFunctionReturn(0);
1140e69d4d44SBarry Smith }
1141e69d4d44SBarry Smith EXTERN_C_END
1142e69d4d44SBarry Smith 
114330ad9308SMatthew Knepley #undef __FUNCT__
114430ad9308SMatthew Knepley #define __FUNCT__ "PCFieldSplitGetSchurBlocks"
114530ad9308SMatthew Knepley /*@C
11468c03b21aSDmitry Karpeev    PCFieldSplitGetSchurBlocks - Gets all matrix blocks for the Schur complement
114730ad9308SMatthew Knepley 
114830ad9308SMatthew Knepley    Collective on KSP
114930ad9308SMatthew Knepley 
115030ad9308SMatthew Knepley    Input Parameter:
115130ad9308SMatthew Knepley .  pc - the preconditioner context
115230ad9308SMatthew Knepley 
115330ad9308SMatthew Knepley    Output Parameters:
1154a04f6461SBarry Smith +  A00 - the (0,0) block
1155a04f6461SBarry Smith .  A01 - the (0,1) block
1156a04f6461SBarry Smith .  A10 - the (1,0) block
1157a04f6461SBarry Smith -  A11 - the (1,1) block
115830ad9308SMatthew Knepley 
115930ad9308SMatthew Knepley    Level: advanced
116030ad9308SMatthew Knepley 
116130ad9308SMatthew Knepley .seealso: PCFIELDSPLIT
116230ad9308SMatthew Knepley @*/
1163a04f6461SBarry Smith PetscErrorCode  PCFieldSplitGetSchurBlocks(PC pc,Mat *A00,Mat *A01,Mat *A10, Mat *A11)
116430ad9308SMatthew Knepley {
116530ad9308SMatthew Knepley   PC_FieldSplit *jac = (PC_FieldSplit *) pc->data;
116630ad9308SMatthew Knepley 
116730ad9308SMatthew Knepley   PetscFunctionBegin;
11680700a824SBarry Smith   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
1169c1235816SBarry Smith   if (jac->type != PC_COMPOSITE_SCHUR) SETERRQ(((PetscObject)pc)->comm,PETSC_ERR_ARG_WRONG, "FieldSplit is not using a Schur complement approach.");
1170a04f6461SBarry Smith   if (A00) *A00 = jac->pmat[0];
1171a04f6461SBarry Smith   if (A01) *A01 = jac->B;
1172a04f6461SBarry Smith   if (A10) *A10 = jac->C;
1173a04f6461SBarry Smith   if (A11) *A11 = jac->pmat[1];
117430ad9308SMatthew Knepley   PetscFunctionReturn(0);
117530ad9308SMatthew Knepley }
117630ad9308SMatthew Knepley 
117779416396SBarry Smith EXTERN_C_BEGIN
117879416396SBarry Smith #undef __FUNCT__
117979416396SBarry Smith #define __FUNCT__ "PCFieldSplitSetType_FieldSplit"
11807087cfbeSBarry Smith PetscErrorCode  PCFieldSplitSetType_FieldSplit(PC pc,PCCompositeType type)
118179416396SBarry Smith {
118279416396SBarry Smith   PC_FieldSplit  *jac = (PC_FieldSplit*)pc->data;
1183e69d4d44SBarry Smith   PetscErrorCode ierr;
118479416396SBarry Smith 
118579416396SBarry Smith   PetscFunctionBegin;
118679416396SBarry Smith   jac->type = type;
11873b224e63SBarry Smith   if (type == PC_COMPOSITE_SCHUR) {
11883b224e63SBarry Smith     pc->ops->apply = PCApply_FieldSplit_Schur;
11893b224e63SBarry Smith     pc->ops->view  = PCView_FieldSplit_Schur;
1190e69d4d44SBarry Smith     ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitGetSubKSP_C","PCFieldSplitGetSubKSP_FieldSplit_Schur",PCFieldSplitGetSubKSP_FieldSplit_Schur);CHKERRQ(ierr);
1191e69d4d44SBarry Smith     ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSchurPrecondition_C","PCFieldSplitSchurPrecondition_FieldSplit",PCFieldSplitSchurPrecondition_FieldSplit);CHKERRQ(ierr);
1192e69d4d44SBarry Smith 
11933b224e63SBarry Smith   } else {
11943b224e63SBarry Smith     pc->ops->apply = PCApply_FieldSplit;
11953b224e63SBarry Smith     pc->ops->view  = PCView_FieldSplit;
1196e69d4d44SBarry Smith     ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitGetSubKSP_C","PCFieldSplitGetSubKSP_FieldSplit",PCFieldSplitGetSubKSP_FieldSplit);CHKERRQ(ierr);
11979e7d6b0aSBarry Smith     ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSchurPrecondition_C","",0);CHKERRQ(ierr);
11983b224e63SBarry Smith   }
119979416396SBarry Smith   PetscFunctionReturn(0);
120079416396SBarry Smith }
120179416396SBarry Smith EXTERN_C_END
120279416396SBarry Smith 
120351f519a2SBarry Smith EXTERN_C_BEGIN
120451f519a2SBarry Smith #undef __FUNCT__
120551f519a2SBarry Smith #define __FUNCT__ "PCFieldSplitSetBlockSize_FieldSplit"
12067087cfbeSBarry Smith PetscErrorCode  PCFieldSplitSetBlockSize_FieldSplit(PC pc,PetscInt bs)
120751f519a2SBarry Smith {
120851f519a2SBarry Smith   PC_FieldSplit  *jac = (PC_FieldSplit*)pc->data;
120951f519a2SBarry Smith 
121051f519a2SBarry Smith   PetscFunctionBegin;
121165e19b50SBarry Smith   if (bs < 1) SETERRQ1(((PetscObject)pc)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Blocksize must be positive, you gave %D",bs);
121265e19b50SBarry Smith   if (jac->bs > 0 && jac->bs != bs) SETERRQ2(((PetscObject)pc)->comm,PETSC_ERR_ARG_WRONGSTATE,"Cannot change fieldsplit blocksize from %D to %D after it has been set",jac->bs,bs);
121351f519a2SBarry Smith   jac->bs = bs;
121451f519a2SBarry Smith   PetscFunctionReturn(0);
121551f519a2SBarry Smith }
121651f519a2SBarry Smith EXTERN_C_END
121751f519a2SBarry Smith 
121879416396SBarry Smith #undef __FUNCT__
121979416396SBarry Smith #define __FUNCT__ "PCFieldSplitSetType"
1220bc08b0f1SBarry Smith /*@
122179416396SBarry Smith    PCFieldSplitSetType - Sets the type of fieldsplit preconditioner.
122279416396SBarry Smith 
122379416396SBarry Smith    Collective on PC
122479416396SBarry Smith 
122579416396SBarry Smith    Input Parameter:
122679416396SBarry Smith .  pc - the preconditioner context
122781540f2fSBarry Smith .  type - PC_COMPOSITE_ADDITIVE, PC_COMPOSITE_MULTIPLICATIVE (default), PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE, PC_COMPOSITE_SPECIAL, PC_COMPOSITE_SCHUR
122879416396SBarry Smith 
122979416396SBarry Smith    Options Database Key:
1230a4efd8eaSMatthew Knepley .  -pc_fieldsplit_type <type: one of multiplicative, additive, symmetric_multiplicative, special, schur> - Sets fieldsplit preconditioner type
123179416396SBarry Smith 
123279416396SBarry Smith    Level: Developer
123379416396SBarry Smith 
123479416396SBarry Smith .keywords: PC, set, type, composite preconditioner, additive, multiplicative
123579416396SBarry Smith 
123679416396SBarry Smith .seealso: PCCompositeSetType()
123779416396SBarry Smith 
123879416396SBarry Smith @*/
12397087cfbeSBarry Smith PetscErrorCode  PCFieldSplitSetType(PC pc,PCCompositeType type)
124079416396SBarry Smith {
12414ac538c5SBarry Smith   PetscErrorCode ierr;
124279416396SBarry Smith 
124379416396SBarry Smith   PetscFunctionBegin;
12440700a824SBarry Smith   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
12454ac538c5SBarry Smith   ierr = PetscTryMethod(pc,"PCFieldSplitSetType_C",(PC,PCCompositeType),(pc,type));CHKERRQ(ierr);
124679416396SBarry Smith   PetscFunctionReturn(0);
124779416396SBarry Smith }
124879416396SBarry Smith 
12490971522cSBarry Smith /* -------------------------------------------------------------------------------------*/
12500971522cSBarry Smith /*MC
1251a8c7a070SBarry Smith    PCFIELDSPLIT - Preconditioner created by combining separate preconditioners for individual
1252a04f6461SBarry Smith                   fields or groups of fields. See the users manual section "Solving Block Matrices" for more details.
12530971522cSBarry Smith 
1254edf189efSBarry Smith      To set options on the solvers for each block append -fieldsplit_ to all the PC
1255edf189efSBarry Smith         options database keys. For example, -fieldsplit_pc_type ilu -fieldsplit_pc_factor_levels 1
12560971522cSBarry Smith 
1257a8c7a070SBarry Smith      To set the options on the solvers separate for each block call PCFieldSplitGetSubKSP()
125869a612a9SBarry Smith          and set the options directly on the resulting KSP object
12590971522cSBarry Smith 
12600971522cSBarry Smith    Level: intermediate
12610971522cSBarry Smith 
126279416396SBarry Smith    Options Database Keys:
126381540f2fSBarry Smith +   -pc_fieldsplit_%d_fields <a,b,..> - indicates the fields to be used in the %d'th split
126481540f2fSBarry Smith .   -pc_fieldsplit_default - automatically add any fields to additional splits that have not
126581540f2fSBarry Smith                               been supplied explicitly by -pc_fieldsplit_%d_fields
126681540f2fSBarry Smith .   -pc_fieldsplit_block_size <bs> - size of block that defines fields (i.e. there are bs fields)
126781540f2fSBarry Smith .   -pc_fieldsplit_type <additive,multiplicative,schur,symmetric_multiplicative>
1268e69d4d44SBarry Smith .   -pc_fieldsplit_schur_precondition <true,false> default is true
1269435f959eSBarry Smith .   -pc_fieldsplit_detect_saddle_point - automatically finds rows with zero or negative diagonal and uses Schur complement with no preconditioner as the solver
127079416396SBarry Smith 
1271edf189efSBarry Smith -    Options prefix for inner solvers when using Schur complement preconditioner are -fieldsplit_0_ and -fieldsplit_1_
12723b224e63SBarry Smith      for all other solvers they are -fieldsplit_%d_ for the dth field, use -fieldsplit_ for all fields
12733b224e63SBarry Smith 
1274d32f9abdSBarry Smith    Notes: use PCFieldSplitSetFields() to set fields defined by "strided" entries and PCFieldSplitSetIS()
1275d32f9abdSBarry Smith      to define a field by an arbitrary collection of entries.
1276d32f9abdSBarry Smith 
1277d32f9abdSBarry Smith       If no fields are set the default is used. The fields are defined by entries strided by bs,
1278d32f9abdSBarry Smith       beginning at 0 then 1, etc to bs-1. The block size can be set with PCFieldSplitSetBlockSize(),
1279d32f9abdSBarry Smith       if this is not called the block size defaults to the blocksize of the second matrix passed
1280d32f9abdSBarry Smith       to KSPSetOperators()/PCSetOperators().
1281d32f9abdSBarry Smith 
1282a04f6461SBarry Smith      For the Schur complement preconditioner if J = ( A00 A01 )
1283a04f6461SBarry Smith                                                     ( A10 A11 )
1284e69d4d44SBarry Smith      the preconditioner is
1285a04f6461SBarry Smith               (I   -B ksp(A00)) ( inv(A00)   0  (I         0  )
1286a04f6461SBarry Smith               (0    I       ) (   0    ksp(S) ) (-A10 ksp(A00) I  )
1287a04f6461SBarry Smith      where the action of inv(A00) is applied using the KSP solver with prefix -fieldsplit_0_. The action of
1288a04f6461SBarry Smith      ksp(S) is computed using the KSP solver with prefix -fieldsplit_splitname_ (where splitname was given in providing the SECOND split or 1 if not give).
1289a04f6461SBarry Smith      For PCFieldSplitGetKSP() when field number is
1290edf189efSBarry Smith      0 it returns the KSP associated with -fieldsplit_0_ while field number 1 gives -fieldsplit_1_ KSP. By default
1291a04f6461SBarry Smith      A11 is used to construct a preconditioner for S, use PCFieldSplitSchurPrecondition() to turn on or off this
12927e8cb189SBarry Smith      option. You can use the preconditioner PCLSC to precondition the Schur complement with -fieldsplit_1_pc_type lsc
1293e69d4d44SBarry Smith 
1294edf189efSBarry Smith      If only one set of indices (one IS) is provided with PCFieldSplitSetIS() then the complement of that IS
1295edf189efSBarry Smith      is used automatically for a second block.
1296edf189efSBarry Smith 
1297a541d17aSBarry Smith    Concepts: physics based preconditioners, block preconditioners
12980971522cSBarry Smith 
12997e8cb189SBarry Smith .seealso:  PCCreate(), PCSetType(), PCType (for list of available types), PC, Block_Preconditioners, PCLSC,
1300e69d4d44SBarry Smith            PCFieldSplitGetSubKSP(), PCFieldSplitSetFields(), PCFieldSplitSetType(), PCFieldSplitSetIS(), PCFieldSplitSchurPrecondition()
13010971522cSBarry Smith M*/
13020971522cSBarry Smith 
13030971522cSBarry Smith EXTERN_C_BEGIN
13040971522cSBarry Smith #undef __FUNCT__
13050971522cSBarry Smith #define __FUNCT__ "PCCreate_FieldSplit"
13067087cfbeSBarry Smith PetscErrorCode  PCCreate_FieldSplit(PC pc)
13070971522cSBarry Smith {
13080971522cSBarry Smith   PetscErrorCode ierr;
13090971522cSBarry Smith   PC_FieldSplit  *jac;
13100971522cSBarry Smith 
13110971522cSBarry Smith   PetscFunctionBegin;
131238f2d2fdSLisandro Dalcin   ierr = PetscNewLog(pc,PC_FieldSplit,&jac);CHKERRQ(ierr);
13130971522cSBarry Smith   jac->bs        = -1;
13140971522cSBarry Smith   jac->nsplits   = 0;
13153e197d65SBarry Smith   jac->type      = PC_COMPOSITE_MULTIPLICATIVE;
1316e6cab6aaSJed Brown   jac->schurpre  = PC_FIELDSPLIT_SCHUR_PRE_USER; /* Try user preconditioner first, fall back on diagonal */
1317c5d2311dSJed Brown   jac->schurfactorization = PC_FIELDSPLIT_SCHUR_FACTORIZATION_FULL;
131851f519a2SBarry Smith 
13190971522cSBarry Smith   pc->data     = (void*)jac;
13200971522cSBarry Smith 
13210971522cSBarry Smith   pc->ops->apply             = PCApply_FieldSplit;
1322421e10b8SBarry Smith   pc->ops->applytranspose    = PCApplyTranspose_FieldSplit;
13230971522cSBarry Smith   pc->ops->setup             = PCSetUp_FieldSplit;
13240971522cSBarry Smith   pc->ops->destroy           = PCDestroy_FieldSplit;
13250971522cSBarry Smith   pc->ops->setfromoptions    = PCSetFromOptions_FieldSplit;
13260971522cSBarry Smith   pc->ops->view              = PCView_FieldSplit;
13270971522cSBarry Smith   pc->ops->applyrichardson   = 0;
13280971522cSBarry Smith 
132969a612a9SBarry Smith   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitGetSubKSP_C","PCFieldSplitGetSubKSP_FieldSplit",
133069a612a9SBarry Smith                     PCFieldSplitGetSubKSP_FieldSplit);CHKERRQ(ierr);
13310971522cSBarry Smith   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetFields_C","PCFieldSplitSetFields_FieldSplit",
13320971522cSBarry Smith                     PCFieldSplitSetFields_FieldSplit);CHKERRQ(ierr);
1333704ba839SBarry Smith   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetIS_C","PCFieldSplitSetIS_FieldSplit",
1334704ba839SBarry Smith                     PCFieldSplitSetIS_FieldSplit);CHKERRQ(ierr);
133579416396SBarry Smith   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetType_C","PCFieldSplitSetType_FieldSplit",
133679416396SBarry Smith                     PCFieldSplitSetType_FieldSplit);CHKERRQ(ierr);
133751f519a2SBarry Smith   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetBlockSize_C","PCFieldSplitSetBlockSize_FieldSplit",
133851f519a2SBarry Smith                     PCFieldSplitSetBlockSize_FieldSplit);CHKERRQ(ierr);
13390971522cSBarry Smith   PetscFunctionReturn(0);
13400971522cSBarry Smith }
13410971522cSBarry Smith EXTERN_C_END
13420971522cSBarry Smith 
13430971522cSBarry Smith 
1344a541d17aSBarry Smith 
1345