xref: /petsc/src/ksp/pc/impls/fieldsplit/fieldsplit.c (revision 8b8307b2cbff7ae63ec0459e534a4a6ccda2943f)
1dba47a55SKris Buschelman #define PETSCKSP_DLL
2dba47a55SKris Buschelman 
36356e834SBarry Smith #include "private/pcimpl.h"     /*I "petscpc.h" I*/
40971522cSBarry Smith 
5f7c28744SJed Brown const char *const PCFieldSplitSchurPreTypes[] = {"SELF","DIAG","USER","PCFieldSplitSchurPreType","PC_FIELDSPLIT_SCHUR_PRE_",0};
6f7c28744SJed Brown const char *const PCFieldSplitSchurFactorizationTypes[] = {"DIAG","LOWER","UPPER","FULL","PCFieldSplitSchurFactorizationType","PC_FIELDSPLIT_SCHUR_FACTORIZATION_",0};
7c5d2311dSJed Brown 
8c5d2311dSJed Brown typedef enum {
9c5d2311dSJed Brown   PC_FIELDSPLIT_SCHUR_FACTORIZATION_DIAG,
10c5d2311dSJed Brown   PC_FIELDSPLIT_SCHUR_FACTORIZATION_LOWER,
11c5d2311dSJed Brown   PC_FIELDSPLIT_SCHUR_FACTORIZATION_UPPER,
12c5d2311dSJed Brown   PC_FIELDSPLIT_SCHUR_FACTORIZATION_FULL
13c5d2311dSJed Brown } PCFieldSplitSchurFactorizationType;
14084e4875SJed Brown 
150971522cSBarry Smith typedef struct _PC_FieldSplitLink *PC_FieldSplitLink;
160971522cSBarry Smith struct _PC_FieldSplitLink {
1769a612a9SBarry Smith   KSP               ksp;
180971522cSBarry Smith   Vec               x,y;
19db4c96c1SJed Brown   char              *splitname;
200971522cSBarry Smith   PetscInt          nfields;
210971522cSBarry Smith   PetscInt          *fields;
221b9fc7fcSBarry Smith   VecScatter        sctx;
234aa3045dSJed Brown   IS                is;
2451f519a2SBarry Smith   PC_FieldSplitLink next,previous;
250971522cSBarry Smith };
260971522cSBarry Smith 
270971522cSBarry Smith typedef struct {
2868dd23aaSBarry Smith   PCCompositeType   type;
29ace3abfcSBarry Smith   PetscBool         defaultsplit; /* Flag for a system with a set of 'k' scalar fields with the same layout (and bs = k) */
30ace3abfcSBarry Smith   PetscBool         splitdefined; /* Flag is set after the splits have been defined, to prevent more splits from being added */
31ace3abfcSBarry Smith   PetscBool         realdiagonal; /* Flag to use the diagonal blocks of mat preconditioned by pmat, instead of just pmat */
3230ad9308SMatthew Knepley   PetscInt          bs;           /* Block size for IS and Mat structures */
3330ad9308SMatthew Knepley   PetscInt          nsplits;      /* Number of field divisions defined */
3479416396SBarry Smith   Vec               *x,*y,w1,w2;
35519d70e2SJed Brown   Mat               *mat;         /* The diagonal block for each split */
36519d70e2SJed Brown   Mat               *pmat;        /* The preconditioning diagonal block for each split */
3730ad9308SMatthew Knepley   Mat               *Afield;      /* The rows of the matrix associated with each split */
38ace3abfcSBarry Smith   PetscBool         issetup;
3930ad9308SMatthew Knepley   /* Only used when Schur complement preconditioning is used */
4030ad9308SMatthew Knepley   Mat               B;            /* The (0,1) block */
4130ad9308SMatthew Knepley   Mat               C;            /* The (1,0) block */
4230ad9308SMatthew Knepley   Mat               schur;        /* The Schur complement S = D - C A^{-1} B */
43084e4875SJed Brown   Mat               schur_user;   /* User-provided preconditioning matrix for the Schur complement */
44084e4875SJed Brown   PCFieldSplitSchurPreType schurpre; /* Determines which preconditioning matrix is used for the Schur complement */
45c5d2311dSJed Brown   PCFieldSplitSchurFactorizationType schurfactorization;
4630ad9308SMatthew Knepley   KSP               kspschur;     /* The solver for S */
4797bbdb24SBarry Smith   PC_FieldSplitLink head;
480971522cSBarry Smith } PC_FieldSplit;
490971522cSBarry Smith 
5016913363SBarry Smith /*
5116913363SBarry Smith     Notes: there is no particular reason that pmat, x, and y are stored as arrays in PC_FieldSplit instead of
5216913363SBarry Smith    inside PC_FieldSplitLink, just historical. If you want to be able to add new fields after already using the
5316913363SBarry Smith    PC you could change this.
5416913363SBarry Smith */
55084e4875SJed Brown 
56e6cab6aaSJed Brown /* This helper is so that setting a user-provided preconditioning matrix is orthogonal to choosing to use it.  This way the
57084e4875SJed Brown * application-provided FormJacobian can provide this matrix without interfering with the user's (command-line) choices. */
58084e4875SJed Brown static Mat FieldSplitSchurPre(PC_FieldSplit *jac)
59084e4875SJed Brown {
60084e4875SJed Brown   switch (jac->schurpre) {
61084e4875SJed Brown     case PC_FIELDSPLIT_SCHUR_PRE_SELF: return jac->schur;
62084e4875SJed Brown     case PC_FIELDSPLIT_SCHUR_PRE_DIAG: return jac->pmat[1];
63084e4875SJed Brown     case PC_FIELDSPLIT_SCHUR_PRE_USER: /* Use a user-provided matrix if it is given, otherwise diagonal block */
64084e4875SJed Brown     default:
65084e4875SJed Brown       return jac->schur_user ? jac->schur_user : jac->pmat[1];
66084e4875SJed Brown   }
67084e4875SJed Brown }
68084e4875SJed Brown 
69084e4875SJed Brown 
700971522cSBarry Smith #undef __FUNCT__
710971522cSBarry Smith #define __FUNCT__ "PCView_FieldSplit"
720971522cSBarry Smith static PetscErrorCode PCView_FieldSplit(PC pc,PetscViewer viewer)
730971522cSBarry Smith {
740971522cSBarry Smith   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
750971522cSBarry Smith   PetscErrorCode    ierr;
76ace3abfcSBarry Smith   PetscBool         iascii;
770971522cSBarry Smith   PetscInt          i,j;
785a9f2f41SSatish Balay   PC_FieldSplitLink ilink = jac->head;
790971522cSBarry Smith 
800971522cSBarry Smith   PetscFunctionBegin;
812692d6eeSBarry Smith   ierr = PetscTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
820971522cSBarry Smith   if (iascii) {
8351f519a2SBarry Smith     ierr = PetscViewerASCIIPrintf(viewer,"  FieldSplit with %s composition: total splits = %D, blocksize = %D\n",PCCompositeTypes[jac->type],jac->nsplits,jac->bs);CHKERRQ(ierr);
8469a612a9SBarry Smith     ierr = PetscViewerASCIIPrintf(viewer,"  Solver info for each split is in the following KSP objects:\n");CHKERRQ(ierr);
850971522cSBarry Smith     ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
860971522cSBarry Smith     for (i=0; i<jac->nsplits; i++) {
871ab39975SBarry Smith       if (ilink->fields) {
880971522cSBarry Smith 	ierr = PetscViewerASCIIPrintf(viewer,"Split number %D Fields ",i);CHKERRQ(ierr);
8979416396SBarry Smith 	ierr = PetscViewerASCIIUseTabs(viewer,PETSC_FALSE);CHKERRQ(ierr);
905a9f2f41SSatish Balay 	for (j=0; j<ilink->nfields; j++) {
9179416396SBarry Smith 	  if (j > 0) {
9279416396SBarry Smith 	    ierr = PetscViewerASCIIPrintf(viewer,",");CHKERRQ(ierr);
9379416396SBarry Smith 	  }
945a9f2f41SSatish Balay 	  ierr = PetscViewerASCIIPrintf(viewer," %D",ilink->fields[j]);CHKERRQ(ierr);
950971522cSBarry Smith 	}
960971522cSBarry Smith 	ierr = PetscViewerASCIIPrintf(viewer,"\n");CHKERRQ(ierr);
9779416396SBarry Smith         ierr = PetscViewerASCIIUseTabs(viewer,PETSC_TRUE);CHKERRQ(ierr);
981ab39975SBarry Smith       } else {
991ab39975SBarry Smith 	ierr = PetscViewerASCIIPrintf(viewer,"Split number %D Defined by IS\n",i);CHKERRQ(ierr);
1001ab39975SBarry Smith       }
1015a9f2f41SSatish Balay       ierr = KSPView(ilink->ksp,viewer);CHKERRQ(ierr);
1025a9f2f41SSatish Balay       ilink = ilink->next;
1030971522cSBarry Smith     }
1040971522cSBarry Smith     ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
1050971522cSBarry Smith   } else {
10665e19b50SBarry Smith     SETERRQ1(((PetscObject)pc)->comm,PETSC_ERR_SUP,"Viewer type %s not supported for PCFieldSplit",((PetscObject)viewer)->type_name);
1070971522cSBarry Smith   }
1080971522cSBarry Smith   PetscFunctionReturn(0);
1090971522cSBarry Smith }
1100971522cSBarry Smith 
1110971522cSBarry Smith #undef __FUNCT__
1123b224e63SBarry Smith #define __FUNCT__ "PCView_FieldSplit_Schur"
1133b224e63SBarry Smith static PetscErrorCode PCView_FieldSplit_Schur(PC pc,PetscViewer viewer)
1143b224e63SBarry Smith {
1153b224e63SBarry Smith   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
1163b224e63SBarry Smith   PetscErrorCode    ierr;
117ace3abfcSBarry Smith   PetscBool         iascii;
1183b224e63SBarry Smith   PetscInt          i,j;
1193b224e63SBarry Smith   PC_FieldSplitLink ilink = jac->head;
1203b224e63SBarry Smith   KSP               ksp;
1213b224e63SBarry Smith 
1223b224e63SBarry Smith   PetscFunctionBegin;
1232692d6eeSBarry Smith   ierr = PetscTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
1243b224e63SBarry Smith   if (iascii) {
125c5d2311dSJed Brown     ierr = PetscViewerASCIIPrintf(viewer,"  FieldSplit with Schur preconditioner, blocksize = %D, factorization %s\n",jac->bs,PCFieldSplitSchurFactorizationTypes[jac->schurfactorization]);CHKERRQ(ierr);
1263b224e63SBarry Smith     ierr = PetscViewerASCIIPrintf(viewer,"  Split info:\n");CHKERRQ(ierr);
1273b224e63SBarry Smith     ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
1283b224e63SBarry Smith     for (i=0; i<jac->nsplits; i++) {
1293b224e63SBarry Smith       if (ilink->fields) {
1303b224e63SBarry Smith 	ierr = PetscViewerASCIIPrintf(viewer,"Split number %D Fields ",i);CHKERRQ(ierr);
1313b224e63SBarry Smith 	ierr = PetscViewerASCIIUseTabs(viewer,PETSC_FALSE);CHKERRQ(ierr);
1323b224e63SBarry Smith 	for (j=0; j<ilink->nfields; j++) {
1333b224e63SBarry Smith 	  if (j > 0) {
1343b224e63SBarry Smith 	    ierr = PetscViewerASCIIPrintf(viewer,",");CHKERRQ(ierr);
1353b224e63SBarry Smith 	  }
1363b224e63SBarry Smith 	  ierr = PetscViewerASCIIPrintf(viewer," %D",ilink->fields[j]);CHKERRQ(ierr);
1373b224e63SBarry Smith 	}
1383b224e63SBarry Smith 	ierr = PetscViewerASCIIPrintf(viewer,"\n");CHKERRQ(ierr);
1393b224e63SBarry Smith         ierr = PetscViewerASCIIUseTabs(viewer,PETSC_TRUE);CHKERRQ(ierr);
1403b224e63SBarry Smith       } else {
1413b224e63SBarry Smith 	ierr = PetscViewerASCIIPrintf(viewer,"Split number %D Defined by IS\n",i);CHKERRQ(ierr);
1423b224e63SBarry Smith       }
1433b224e63SBarry Smith       ilink = ilink->next;
1443b224e63SBarry Smith     }
1453b224e63SBarry Smith     ierr = PetscViewerASCIIPrintf(viewer,"KSP solver for A block \n");CHKERRQ(ierr);
1463b224e63SBarry Smith     ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
14712cae6f2SJed Brown     if (jac->schur) {
14812cae6f2SJed Brown       ierr = MatSchurComplementGetKSP(jac->schur,&ksp);CHKERRQ(ierr);
1493b224e63SBarry Smith       ierr = KSPView(ksp,viewer);CHKERRQ(ierr);
15012cae6f2SJed Brown     } else {
15112cae6f2SJed Brown       ierr = PetscViewerASCIIPrintf(viewer,"  not yet available\n");CHKERRQ(ierr);
15212cae6f2SJed Brown     }
1533b224e63SBarry Smith     ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
1543b224e63SBarry Smith     ierr = PetscViewerASCIIPrintf(viewer,"KSP solver for S = D - C inv(A) B \n");CHKERRQ(ierr);
1553b224e63SBarry Smith     ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
15612cae6f2SJed Brown     if (jac->kspschur) {
1573b224e63SBarry Smith       ierr = KSPView(jac->kspschur,viewer);CHKERRQ(ierr);
15812cae6f2SJed Brown     } else {
15912cae6f2SJed Brown       ierr = PetscViewerASCIIPrintf(viewer,"  not yet available\n");CHKERRQ(ierr);
16012cae6f2SJed Brown     }
1613b224e63SBarry Smith     ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
1623b224e63SBarry Smith     ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
1633b224e63SBarry Smith   } else {
16465e19b50SBarry Smith     SETERRQ1(((PetscObject)pc)->comm,PETSC_ERR_SUP,"Viewer type %s not supported for PCFieldSplit",((PetscObject)viewer)->type_name);
1653b224e63SBarry Smith   }
1663b224e63SBarry Smith   PetscFunctionReturn(0);
1673b224e63SBarry Smith }
1683b224e63SBarry Smith 
1693b224e63SBarry Smith #undef __FUNCT__
1706c924f48SJed Brown #define __FUNCT__ "PCFieldSplitSetRuntimeSplits_Private"
1716c924f48SJed Brown /* Precondition: jac->bs is set to a meaningful value */
1726c924f48SJed Brown static PetscErrorCode PCFieldSplitSetRuntimeSplits_Private(PC pc)
1736c924f48SJed Brown {
1746c924f48SJed Brown   PetscErrorCode ierr;
1756c924f48SJed Brown   PC_FieldSplit  *jac = (PC_FieldSplit*)pc->data;
1766c924f48SJed Brown   PetscInt       i,nfields,*ifields;
177ace3abfcSBarry Smith   PetscBool      flg;
1786c924f48SJed Brown   char           optionname[128],splitname[8];
1796c924f48SJed Brown 
1806c924f48SJed Brown   PetscFunctionBegin;
1816c924f48SJed Brown   ierr = PetscMalloc(jac->bs*sizeof(PetscInt),&ifields);CHKERRQ(ierr);
1826c924f48SJed Brown   for (i=0,flg=PETSC_TRUE; ; i++) {
1836c924f48SJed Brown     ierr = PetscSNPrintf(splitname,sizeof splitname,"%D",i);CHKERRQ(ierr);
1846c924f48SJed Brown     ierr = PetscSNPrintf(optionname,sizeof optionname,"-pc_fieldsplit_%D_fields",i);CHKERRQ(ierr);
1856c924f48SJed Brown     nfields = jac->bs;
1866c924f48SJed Brown     ierr    = PetscOptionsGetIntArray(((PetscObject)pc)->prefix,optionname,ifields,&nfields,&flg);CHKERRQ(ierr);
1876c924f48SJed Brown     if (!flg) break;
1886c924f48SJed Brown     if (!nfields) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Cannot list zero fields");
1896c924f48SJed Brown     ierr = PCFieldSplitSetFields(pc,splitname,nfields,ifields);CHKERRQ(ierr);
1906c924f48SJed Brown   }
1916c924f48SJed Brown   if (i > 0) {
1926c924f48SJed Brown     /* Makes command-line setting of splits take precedence over setting them in code.
1936c924f48SJed Brown        Otherwise subsequent calls to PCFieldSplitSetIS() or PCFieldSplitSetFields() would
1946c924f48SJed Brown        create new splits, which would probably not be what the user wanted. */
1956c924f48SJed Brown     jac->splitdefined = PETSC_TRUE;
1966c924f48SJed Brown   }
1976c924f48SJed Brown   ierr = PetscFree(ifields);CHKERRQ(ierr);
1986c924f48SJed Brown   PetscFunctionReturn(0);
1996c924f48SJed Brown }
2006c924f48SJed Brown 
2016c924f48SJed Brown #undef __FUNCT__
20269a612a9SBarry Smith #define __FUNCT__ "PCFieldSplitSetDefaults"
20369a612a9SBarry Smith static PetscErrorCode PCFieldSplitSetDefaults(PC pc)
2040971522cSBarry Smith {
2050971522cSBarry Smith   PC_FieldSplit     *jac  = (PC_FieldSplit*)pc->data;
2060971522cSBarry Smith   PetscErrorCode    ierr;
2075a9f2f41SSatish Balay   PC_FieldSplitLink ilink = jac->head;
208ace3abfcSBarry Smith   PetscBool         flg = PETSC_FALSE;
2096c924f48SJed Brown   PetscInt          i;
2100971522cSBarry Smith 
2110971522cSBarry Smith   PetscFunctionBegin;
212d32f9abdSBarry Smith   if (!ilink) {
213*8b8307b2SJed Brown     if (pc->dm) {
214*8b8307b2SJed Brown       PetscBool dmcomposite;
215*8b8307b2SJed Brown       ierr = PetscTypeCompare((PetscObject)pc->dm,DMCOMPOSITE,&dmcomposite);CHKERRQ(ierr);
216*8b8307b2SJed Brown       if (dmcomposite) {
217*8b8307b2SJed Brown         PetscInt nDM;
218*8b8307b2SJed Brown         IS       *fields;
219*8b8307b2SJed Brown         ierr = PetscInfo(pc,"Setting up physics based fieldsplit preconditioner using the embedded DM\n");CHKERRQ(ierr);
220*8b8307b2SJed Brown         ierr = DMCompositeGetNumberDM(pc->dm,&nDM);CHKERRQ(ierr);
221*8b8307b2SJed Brown         ierr = DMCompositeGetGlobalISs(pc->dm,&fields);CHKERRQ(ierr);
222*8b8307b2SJed Brown         for (i=0; i<nDM; i++) {
223*8b8307b2SJed Brown           char splitname[8];
224*8b8307b2SJed Brown           ierr = PetscSNPrintf(splitname,sizeof splitname,"%D",i);CHKERRQ(ierr);
225*8b8307b2SJed Brown           ierr = PCFieldSplitSetIS(pc,splitname,fields[i]);CHKERRQ(ierr);
226*8b8307b2SJed Brown           ierr = ISDestroy(fields[i]);CHKERRQ(ierr);
227*8b8307b2SJed Brown         }
228*8b8307b2SJed Brown         ierr = PetscFree(fields);CHKERRQ(ierr);
229*8b8307b2SJed Brown       }
230*8b8307b2SJed Brown     }
231521d7252SBarry Smith     if (jac->bs <= 0) {
232704ba839SBarry Smith       if (pc->pmat) {
233521d7252SBarry Smith         ierr   = MatGetBlockSize(pc->pmat,&jac->bs);CHKERRQ(ierr);
234704ba839SBarry Smith       } else {
235704ba839SBarry Smith         jac->bs = 1;
236704ba839SBarry Smith       }
237521d7252SBarry Smith     }
238d32f9abdSBarry Smith 
239acfcf0e5SJed Brown     ierr = PetscOptionsGetBool(((PetscObject)pc)->prefix,"-pc_fieldsplit_default",&flg,PETSC_NULL);CHKERRQ(ierr);
240d32f9abdSBarry Smith     if (!flg) {
241d32f9abdSBarry Smith       /* Allow user to set fields from command line,  if bs was known at the time of PCSetFromOptions_FieldSplit()
242d32f9abdSBarry Smith          then it is set there. This is not ideal because we should only have options set in XXSetFromOptions(). */
2436c924f48SJed Brown       ierr = PCFieldSplitSetRuntimeSplits_Private(pc);CHKERRQ(ierr);
2446c924f48SJed Brown       if (jac->splitdefined) {ierr = PetscInfo(pc,"Splits defined using the options database\n");CHKERRQ(ierr);}
245d32f9abdSBarry Smith     }
2466c924f48SJed Brown     if (flg || !jac->splitdefined) {
247d32f9abdSBarry Smith       ierr = PetscInfo(pc,"Using default splitting of fields\n");CHKERRQ(ierr);
248db4c96c1SJed Brown       for (i=0; i<jac->bs; i++) {
2496c924f48SJed Brown         char splitname[8];
2506c924f48SJed Brown         ierr = PetscSNPrintf(splitname,sizeof splitname,"%D",i);CHKERRQ(ierr);
251db4c96c1SJed Brown         ierr = PCFieldSplitSetFields(pc,splitname,1,&i);CHKERRQ(ierr);
25279416396SBarry Smith       }
25397bbdb24SBarry Smith       jac->defaultsplit = PETSC_TRUE;
254521d7252SBarry Smith     }
255edf189efSBarry Smith   } else if (jac->nsplits == 1) {
256edf189efSBarry Smith     if (ilink->is) {
257edf189efSBarry Smith       IS       is2;
258edf189efSBarry Smith       PetscInt nmin,nmax;
259edf189efSBarry Smith 
260edf189efSBarry Smith       ierr = MatGetOwnershipRange(pc->mat,&nmin,&nmax);CHKERRQ(ierr);
261edf189efSBarry Smith       ierr = ISComplement(ilink->is,nmin,nmax,&is2);CHKERRQ(ierr);
262db4c96c1SJed Brown       ierr = PCFieldSplitSetIS(pc,"1",is2);CHKERRQ(ierr);
263edf189efSBarry Smith       ierr = ISDestroy(is2);CHKERRQ(ierr);
264e7e72b3dSBarry Smith     } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Must provide at least two sets of fields to PCFieldSplit()");
265edf189efSBarry Smith   }
266e7e72b3dSBarry Smith   if (jac->nsplits < 2) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unhandled case, must have at least two fields");
26769a612a9SBarry Smith   PetscFunctionReturn(0);
26869a612a9SBarry Smith }
26969a612a9SBarry Smith 
27069a612a9SBarry Smith 
27169a612a9SBarry Smith #undef __FUNCT__
27269a612a9SBarry Smith #define __FUNCT__ "PCSetUp_FieldSplit"
27369a612a9SBarry Smith static PetscErrorCode PCSetUp_FieldSplit(PC pc)
27469a612a9SBarry Smith {
27569a612a9SBarry Smith   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
27669a612a9SBarry Smith   PetscErrorCode    ierr;
2775a9f2f41SSatish Balay   PC_FieldSplitLink ilink;
278cf502942SBarry Smith   PetscInt          i,nsplit,ccsize;
27969a612a9SBarry Smith   MatStructure      flag = pc->flag;
280ace3abfcSBarry Smith   PetscBool         sorted;
28169a612a9SBarry Smith 
28269a612a9SBarry Smith   PetscFunctionBegin;
28369a612a9SBarry Smith   ierr   = PCFieldSplitSetDefaults(pc);CHKERRQ(ierr);
28497bbdb24SBarry Smith   nsplit = jac->nsplits;
2855a9f2f41SSatish Balay   ilink  = jac->head;
28697bbdb24SBarry Smith 
28797bbdb24SBarry Smith   /* get the matrices for each split */
288704ba839SBarry Smith   if (!jac->issetup) {
2891b9fc7fcSBarry Smith     PetscInt rstart,rend,nslots,bs;
29097bbdb24SBarry Smith 
291704ba839SBarry Smith     jac->issetup = PETSC_TRUE;
292704ba839SBarry Smith 
293704ba839SBarry Smith     /* This is done here instead of in PCFieldSplitSetFields() because may not have matrix at that point */
29451f519a2SBarry Smith     bs     = jac->bs;
29597bbdb24SBarry Smith     ierr   = MatGetOwnershipRange(pc->pmat,&rstart,&rend);CHKERRQ(ierr);
296cf502942SBarry Smith     ierr   = MatGetLocalSize(pc->pmat,PETSC_NULL,&ccsize);CHKERRQ(ierr);
2971b9fc7fcSBarry Smith     nslots = (rend - rstart)/bs;
2981b9fc7fcSBarry Smith     for (i=0; i<nsplit; i++) {
2991b9fc7fcSBarry Smith       if (jac->defaultsplit) {
300704ba839SBarry Smith         ierr = ISCreateStride(((PetscObject)pc)->comm,nslots,rstart+i,nsplit,&ilink->is);CHKERRQ(ierr);
301704ba839SBarry Smith       } else if (!ilink->is) {
302ccb205f8SBarry Smith         if (ilink->nfields > 1) {
3035a9f2f41SSatish Balay           PetscInt   *ii,j,k,nfields = ilink->nfields,*fields = ilink->fields;
3045a9f2f41SSatish Balay           ierr = PetscMalloc(ilink->nfields*nslots*sizeof(PetscInt),&ii);CHKERRQ(ierr);
3051b9fc7fcSBarry Smith           for (j=0; j<nslots; j++) {
3061b9fc7fcSBarry Smith             for (k=0; k<nfields; k++) {
3071b9fc7fcSBarry Smith               ii[nfields*j + k] = rstart + bs*j + fields[k];
30897bbdb24SBarry Smith             }
30997bbdb24SBarry Smith           }
310d67e408aSBarry Smith           ierr = ISCreateGeneral(((PetscObject)pc)->comm,nslots*nfields,ii,PETSC_OWN_POINTER,&ilink->is);CHKERRQ(ierr);
311ccb205f8SBarry Smith         } else {
312704ba839SBarry Smith           ierr = ISCreateStride(((PetscObject)pc)->comm,nslots,rstart+ilink->fields[0],bs,&ilink->is);CHKERRQ(ierr);
313ccb205f8SBarry Smith         }
3143e197d65SBarry Smith       }
315704ba839SBarry Smith       ierr = ISSorted(ilink->is,&sorted);CHKERRQ(ierr);
316e32f2f54SBarry Smith       if (!sorted) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Fields must be sorted when creating split");
317704ba839SBarry Smith       ilink = ilink->next;
3181b9fc7fcSBarry Smith     }
3191b9fc7fcSBarry Smith   }
3201b9fc7fcSBarry Smith 
321704ba839SBarry Smith   ilink  = jac->head;
32297bbdb24SBarry Smith   if (!jac->pmat) {
323cf502942SBarry Smith     ierr = PetscMalloc(nsplit*sizeof(Mat),&jac->pmat);CHKERRQ(ierr);
324cf502942SBarry Smith     for (i=0; i<nsplit; i++) {
3254aa3045dSJed Brown       ierr = MatGetSubMatrix(pc->pmat,ilink->is,ilink->is,MAT_INITIAL_MATRIX,&jac->pmat[i]);CHKERRQ(ierr);
326704ba839SBarry Smith       ilink = ilink->next;
327cf502942SBarry Smith     }
32897bbdb24SBarry Smith   } else {
329cf502942SBarry Smith     for (i=0; i<nsplit; i++) {
3304aa3045dSJed Brown       ierr = MatGetSubMatrix(pc->pmat,ilink->is,ilink->is,MAT_REUSE_MATRIX,&jac->pmat[i]);CHKERRQ(ierr);
331704ba839SBarry Smith       ilink = ilink->next;
332cf502942SBarry Smith     }
33397bbdb24SBarry Smith   }
334519d70e2SJed Brown   if (jac->realdiagonal) {
335519d70e2SJed Brown     ilink = jac->head;
336519d70e2SJed Brown     if (!jac->mat) {
337519d70e2SJed Brown       ierr = PetscMalloc(nsplit*sizeof(Mat),&jac->mat);CHKERRQ(ierr);
338519d70e2SJed Brown       for (i=0; i<nsplit; i++) {
339519d70e2SJed Brown         ierr = MatGetSubMatrix(pc->mat,ilink->is,ilink->is,MAT_INITIAL_MATRIX,&jac->mat[i]);CHKERRQ(ierr);
340519d70e2SJed Brown         ilink = ilink->next;
341519d70e2SJed Brown       }
342519d70e2SJed Brown     } else {
343519d70e2SJed Brown       for (i=0; i<nsplit; i++) {
344519d70e2SJed Brown         ierr = MatGetSubMatrix(pc->mat,ilink->is,ilink->is,MAT_REUSE_MATRIX,&jac->mat[i]);CHKERRQ(ierr);
345519d70e2SJed Brown         ilink = ilink->next;
346519d70e2SJed Brown       }
347519d70e2SJed Brown     }
348519d70e2SJed Brown   } else {
349519d70e2SJed Brown     jac->mat = jac->pmat;
350519d70e2SJed Brown   }
35197bbdb24SBarry Smith 
3526c8605c2SJed Brown   if (jac->type != PC_COMPOSITE_ADDITIVE  && jac->type != PC_COMPOSITE_SCHUR) {
35368dd23aaSBarry Smith     /* extract the rows of the matrix associated with each field: used for efficient computation of residual inside algorithm */
35468dd23aaSBarry Smith     ilink  = jac->head;
35568dd23aaSBarry Smith     if (!jac->Afield) {
35668dd23aaSBarry Smith       ierr = PetscMalloc(nsplit*sizeof(Mat),&jac->Afield);CHKERRQ(ierr);
35768dd23aaSBarry Smith       for (i=0; i<nsplit; i++) {
3584aa3045dSJed Brown         ierr = MatGetSubMatrix(pc->mat,ilink->is,PETSC_NULL,MAT_INITIAL_MATRIX,&jac->Afield[i]);CHKERRQ(ierr);
35968dd23aaSBarry Smith         ilink = ilink->next;
36068dd23aaSBarry Smith       }
36168dd23aaSBarry Smith     } else {
36268dd23aaSBarry Smith       for (i=0; i<nsplit; i++) {
3634aa3045dSJed Brown         ierr = MatGetSubMatrix(pc->mat,ilink->is,PETSC_NULL,MAT_REUSE_MATRIX,&jac->Afield[i]);CHKERRQ(ierr);
36468dd23aaSBarry Smith         ilink = ilink->next;
36568dd23aaSBarry Smith       }
36668dd23aaSBarry Smith     }
36768dd23aaSBarry Smith   }
36868dd23aaSBarry Smith 
3693b224e63SBarry Smith   if (jac->type == PC_COMPOSITE_SCHUR) {
3703b224e63SBarry Smith     IS       ccis;
3714aa3045dSJed Brown     PetscInt rstart,rend;
372e7e72b3dSBarry Smith     if (nsplit != 2) SETERRQ(((PetscObject)pc)->comm,PETSC_ERR_ARG_INCOMP,"To use Schur complement preconditioner you must have exactly 2 fields");
37368dd23aaSBarry Smith 
374e6cab6aaSJed Brown     /* When extracting off-diagonal submatrices, we take complements from this range */
375e6cab6aaSJed Brown     ierr  = MatGetOwnershipRangeColumn(pc->mat,&rstart,&rend);CHKERRQ(ierr);
376e6cab6aaSJed Brown 
3773b224e63SBarry Smith     /* need to handle case when one is resetting up the preconditioner */
3783b224e63SBarry Smith     if (jac->schur) {
3793b224e63SBarry Smith       ilink = jac->head;
3804aa3045dSJed Brown       ierr  = ISComplement(ilink->is,rstart,rend,&ccis);CHKERRQ(ierr);
3814aa3045dSJed Brown       ierr  = MatGetSubMatrix(pc->mat,ilink->is,ccis,MAT_REUSE_MATRIX,&jac->B);CHKERRQ(ierr);
3823b224e63SBarry Smith       ierr  = ISDestroy(ccis);CHKERRQ(ierr);
3833b224e63SBarry Smith       ilink = ilink->next;
3844aa3045dSJed Brown       ierr  = ISComplement(ilink->is,rstart,rend,&ccis);CHKERRQ(ierr);
3854aa3045dSJed Brown       ierr  = MatGetSubMatrix(pc->mat,ilink->is,ccis,MAT_REUSE_MATRIX,&jac->C);CHKERRQ(ierr);
3863b224e63SBarry Smith       ierr  = ISDestroy(ccis);CHKERRQ(ierr);
387519d70e2SJed Brown       ierr  = MatSchurComplementUpdate(jac->schur,jac->mat[0],jac->pmat[0],jac->B,jac->C,jac->pmat[1],pc->flag);CHKERRQ(ierr);
388084e4875SJed Brown       ierr  = KSPSetOperators(jac->kspschur,jac->schur,FieldSplitSchurPre(jac),pc->flag);CHKERRQ(ierr);
3893b224e63SBarry Smith 
3903b224e63SBarry Smith      } else {
3911cee3971SBarry Smith       KSP ksp;
3926c924f48SJed Brown       char schurprefix[256];
3933b224e63SBarry Smith 
3943b224e63SBarry Smith       /* extract the B and C matrices */
3953b224e63SBarry Smith       ilink = jac->head;
3964aa3045dSJed Brown       ierr  = ISComplement(ilink->is,rstart,rend,&ccis);CHKERRQ(ierr);
3974aa3045dSJed Brown       ierr  = MatGetSubMatrix(pc->mat,ilink->is,ccis,MAT_INITIAL_MATRIX,&jac->B);CHKERRQ(ierr);
3983b224e63SBarry Smith       ierr  = ISDestroy(ccis);CHKERRQ(ierr);
3993b224e63SBarry Smith       ilink = ilink->next;
4004aa3045dSJed Brown       ierr  = ISComplement(ilink->is,rstart,rend,&ccis);CHKERRQ(ierr);
4014aa3045dSJed Brown       ierr  = MatGetSubMatrix(pc->mat,ilink->is,ccis,MAT_INITIAL_MATRIX,&jac->C);CHKERRQ(ierr);
4023b224e63SBarry Smith       ierr  = ISDestroy(ccis);CHKERRQ(ierr);
403084e4875SJed Brown       /* Better would be to use 'mat[0]' (diagonal block of the real matrix) preconditioned by pmat[0] */
404519d70e2SJed Brown       ierr  = MatCreateSchurComplement(jac->mat[0],jac->pmat[0],jac->B,jac->C,jac->mat[1],&jac->schur);CHKERRQ(ierr);
4051cee3971SBarry Smith       ierr  = MatSchurComplementGetKSP(jac->schur,&ksp);CHKERRQ(ierr);
406e69d4d44SBarry Smith       ierr  = PetscObjectIncrementTabLevel((PetscObject)ksp,(PetscObject)pc,2);CHKERRQ(ierr);
4073b224e63SBarry Smith       ierr  = MatSetFromOptions(jac->schur);CHKERRQ(ierr);
4083b224e63SBarry Smith 
4093b224e63SBarry Smith       ierr  = KSPCreate(((PetscObject)pc)->comm,&jac->kspschur);CHKERRQ(ierr);
4109005cf84SBarry Smith       ierr  = PetscLogObjectParent((PetscObject)pc,(PetscObject)jac->kspschur);CHKERRQ(ierr);
4111cee3971SBarry Smith       ierr  = PetscObjectIncrementTabLevel((PetscObject)jac->kspschur,(PetscObject)pc,1);CHKERRQ(ierr);
412084e4875SJed Brown       ierr  = KSPSetOperators(jac->kspschur,jac->schur,FieldSplitSchurPre(jac),DIFFERENT_NONZERO_PATTERN);CHKERRQ(ierr);
413084e4875SJed Brown       if (jac->schurpre == PC_FIELDSPLIT_SCHUR_PRE_SELF) {
414084e4875SJed Brown         PC pc;
415cd5f4a64SJed Brown         ierr = KSPGetPC(jac->kspschur,&pc);CHKERRQ(ierr);
416084e4875SJed Brown         ierr = PCSetType(pc,PCNONE);CHKERRQ(ierr);
417084e4875SJed Brown         /* Note: This is bad if there exist preconditioners for MATSCHURCOMPLEMENT */
418e69d4d44SBarry Smith       }
4196c924f48SJed Brown       ierr = PetscSNPrintf(schurprefix,sizeof schurprefix,"%sfieldsplit_%s_",((PetscObject)pc)->prefix?((PetscObject)pc)->prefix:"",ilink->splitname);CHKERRQ(ierr);
4206c924f48SJed Brown       ierr  = KSPSetOptionsPrefix(jac->kspschur,schurprefix);CHKERRQ(ierr);
4213b224e63SBarry Smith       /* really want setfromoptions called in PCSetFromOptions_FieldSplit(), but it is not ready yet */
4223b224e63SBarry Smith       ierr = KSPSetFromOptions(jac->kspschur);CHKERRQ(ierr);
4233b224e63SBarry Smith 
4243b224e63SBarry Smith       ierr = PetscMalloc2(2,Vec,&jac->x,2,Vec,&jac->y);CHKERRQ(ierr);
4253b224e63SBarry Smith       ierr = MatGetVecs(jac->pmat[0],&jac->x[0],&jac->y[0]);CHKERRQ(ierr);
4263b224e63SBarry Smith       ierr = MatGetVecs(jac->pmat[1],&jac->x[1],&jac->y[1]);CHKERRQ(ierr);
4273b224e63SBarry Smith       ilink = jac->head;
4283b224e63SBarry Smith       ilink->x = jac->x[0]; ilink->y = jac->y[0];
4293b224e63SBarry Smith       ilink = ilink->next;
4303b224e63SBarry Smith       ilink->x = jac->x[1]; ilink->y = jac->y[1];
4313b224e63SBarry Smith     }
4323b224e63SBarry Smith   } else {
43397bbdb24SBarry Smith     /* set up the individual PCs */
43497bbdb24SBarry Smith     i    = 0;
4355a9f2f41SSatish Balay     ilink = jac->head;
4365a9f2f41SSatish Balay     while (ilink) {
437519d70e2SJed Brown       ierr = KSPSetOperators(ilink->ksp,jac->mat[i],jac->pmat[i],flag);CHKERRQ(ierr);
4383b224e63SBarry Smith       /* really want setfromoptions called in PCSetFromOptions_FieldSplit(), but it is not ready yet */
4395a9f2f41SSatish Balay       ierr = KSPSetFromOptions(ilink->ksp);CHKERRQ(ierr);
4405a9f2f41SSatish Balay       ierr = KSPSetUp(ilink->ksp);CHKERRQ(ierr);
44197bbdb24SBarry Smith       i++;
4425a9f2f41SSatish Balay       ilink = ilink->next;
4430971522cSBarry Smith     }
44497bbdb24SBarry Smith 
44597bbdb24SBarry Smith     /* create work vectors for each split */
4461b9fc7fcSBarry Smith     if (!jac->x) {
44797bbdb24SBarry Smith       ierr = PetscMalloc2(nsplit,Vec,&jac->x,nsplit,Vec,&jac->y);CHKERRQ(ierr);
4485a9f2f41SSatish Balay       ilink = jac->head;
44997bbdb24SBarry Smith       for (i=0; i<nsplit; i++) {
450906ed7ccSBarry Smith         Vec *vl,*vr;
451906ed7ccSBarry Smith 
452906ed7ccSBarry Smith         ierr      = KSPGetVecs(ilink->ksp,1,&vr,1,&vl);CHKERRQ(ierr);
453906ed7ccSBarry Smith         ilink->x  = *vr;
454906ed7ccSBarry Smith         ilink->y  = *vl;
455906ed7ccSBarry Smith         ierr      = PetscFree(vr);CHKERRQ(ierr);
456906ed7ccSBarry Smith         ierr      = PetscFree(vl);CHKERRQ(ierr);
4575a9f2f41SSatish Balay         jac->x[i] = ilink->x;
4585a9f2f41SSatish Balay         jac->y[i] = ilink->y;
4595a9f2f41SSatish Balay         ilink     = ilink->next;
46097bbdb24SBarry Smith       }
4613b224e63SBarry Smith     }
4623b224e63SBarry Smith   }
4633b224e63SBarry Smith 
4643b224e63SBarry Smith 
465d0f46423SBarry Smith   if (!jac->head->sctx) {
4663b224e63SBarry Smith     Vec xtmp;
4673b224e63SBarry Smith 
46879416396SBarry Smith     /* compute scatter contexts needed by multiplicative versions and non-default splits */
4691b9fc7fcSBarry Smith 
4705a9f2f41SSatish Balay     ilink = jac->head;
4711b9fc7fcSBarry Smith     ierr = MatGetVecs(pc->pmat,&xtmp,PETSC_NULL);CHKERRQ(ierr);
4721b9fc7fcSBarry Smith     for (i=0; i<nsplit; i++) {
473704ba839SBarry Smith       ierr = VecScatterCreate(xtmp,ilink->is,jac->x[i],PETSC_NULL,&ilink->sctx);CHKERRQ(ierr);
4745a9f2f41SSatish Balay       ilink = ilink->next;
4751b9fc7fcSBarry Smith     }
4761b9fc7fcSBarry Smith     ierr = VecDestroy(xtmp);CHKERRQ(ierr);
4771b9fc7fcSBarry Smith   }
4780971522cSBarry Smith   PetscFunctionReturn(0);
4790971522cSBarry Smith }
4800971522cSBarry Smith 
4815a9f2f41SSatish Balay #define FieldSplitSplitSolveAdd(ilink,xx,yy) \
482ca9f406cSSatish Balay     (VecScatterBegin(ilink->sctx,xx,ilink->x,INSERT_VALUES,SCATTER_FORWARD) || \
483ca9f406cSSatish Balay      VecScatterEnd(ilink->sctx,xx,ilink->x,INSERT_VALUES,SCATTER_FORWARD) || \
4845a9f2f41SSatish Balay      KSPSolve(ilink->ksp,ilink->x,ilink->y) || \
485ca9f406cSSatish Balay      VecScatterBegin(ilink->sctx,ilink->y,yy,ADD_VALUES,SCATTER_REVERSE) || \
486ca9f406cSSatish Balay      VecScatterEnd(ilink->sctx,ilink->y,yy,ADD_VALUES,SCATTER_REVERSE))
48779416396SBarry Smith 
4880971522cSBarry Smith #undef __FUNCT__
4893b224e63SBarry Smith #define __FUNCT__ "PCApply_FieldSplit_Schur"
4903b224e63SBarry Smith static PetscErrorCode PCApply_FieldSplit_Schur(PC pc,Vec x,Vec y)
4913b224e63SBarry Smith {
4923b224e63SBarry Smith   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
4933b224e63SBarry Smith   PetscErrorCode    ierr;
4943b224e63SBarry Smith   KSP               ksp;
4953b224e63SBarry Smith   PC_FieldSplitLink ilinkA = jac->head, ilinkD = ilinkA->next;
4963b224e63SBarry Smith 
4973b224e63SBarry Smith   PetscFunctionBegin;
4983b224e63SBarry Smith   ierr = MatSchurComplementGetKSP(jac->schur,&ksp);CHKERRQ(ierr);
4993b224e63SBarry Smith 
500c5d2311dSJed Brown   switch (jac->schurfactorization) {
501c5d2311dSJed Brown     case PC_FIELDSPLIT_SCHUR_FACTORIZATION_DIAG:
502c5d2311dSJed Brown       /* [A 0; 0 -S], positive definite, suitable for MINRES */
503c5d2311dSJed Brown       ierr = VecScatterBegin(ilinkA->sctx,x,ilinkA->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
504c5d2311dSJed Brown       ierr = VecScatterBegin(ilinkD->sctx,x,ilinkD->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
505c5d2311dSJed Brown       ierr = VecScatterEnd(ilinkA->sctx,x,ilinkA->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
506c5d2311dSJed Brown       ierr = KSPSolve(ksp,ilinkA->x,ilinkA->y);CHKERRQ(ierr);
507c5d2311dSJed Brown       ierr = VecScatterBegin(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
508c5d2311dSJed Brown       ierr = VecScatterEnd(ilinkD->sctx,x,ilinkD->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
509c5d2311dSJed Brown       ierr = KSPSolve(jac->kspschur,ilinkD->x,ilinkD->y);CHKERRQ(ierr);
510c5d2311dSJed Brown       ierr = VecScale(ilinkD->y,-1.);CHKERRQ(ierr);
511c5d2311dSJed Brown       ierr = VecScatterBegin(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
512c5d2311dSJed Brown       ierr = VecScatterEnd(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
513c5d2311dSJed Brown       ierr = VecScatterEnd(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
514c5d2311dSJed Brown       break;
515c5d2311dSJed Brown     case PC_FIELDSPLIT_SCHUR_FACTORIZATION_LOWER:
516c5d2311dSJed Brown       /* [A 0; C S], suitable for left preconditioning */
517c5d2311dSJed Brown       ierr = VecScatterBegin(ilinkA->sctx,x,ilinkA->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
518c5d2311dSJed Brown       ierr = VecScatterEnd(ilinkA->sctx,x,ilinkA->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
519c5d2311dSJed Brown       ierr = KSPSolve(ksp,ilinkA->x,ilinkA->y);CHKERRQ(ierr);
520c5d2311dSJed Brown       ierr = MatMult(jac->C,ilinkA->y,ilinkD->x);CHKERRQ(ierr);
521c5d2311dSJed Brown       ierr = VecScale(ilinkD->x,-1.);CHKERRQ(ierr);
522c5d2311dSJed Brown       ierr = VecScatterBegin(ilinkD->sctx,x,ilinkD->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
523c5d2311dSJed Brown       ierr = VecScatterBegin(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
524c5d2311dSJed Brown       ierr = VecScatterEnd(ilinkD->sctx,x,ilinkD->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
525c5d2311dSJed Brown       ierr = KSPSolve(jac->kspschur,ilinkD->x,ilinkD->y);CHKERRQ(ierr);
526c5d2311dSJed Brown       ierr = VecScatterBegin(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
527c5d2311dSJed Brown       ierr = VecScatterEnd(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
528c5d2311dSJed Brown       ierr = VecScatterEnd(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
529c5d2311dSJed Brown       break;
530c5d2311dSJed Brown     case PC_FIELDSPLIT_SCHUR_FACTORIZATION_UPPER:
531c5d2311dSJed Brown       /* [A B; 0 S], suitable for right preconditioning */
532c5d2311dSJed Brown       ierr = VecScatterBegin(ilinkD->sctx,x,ilinkD->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
533c5d2311dSJed Brown       ierr = VecScatterEnd(ilinkD->sctx,x,ilinkD->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
534c5d2311dSJed Brown       ierr = KSPSolve(jac->kspschur,ilinkD->x,ilinkD->y);CHKERRQ(ierr);
535c5d2311dSJed Brown       ierr = MatMult(jac->B,ilinkD->y,ilinkA->x);CHKERRQ(ierr);
536c5d2311dSJed Brown       ierr = VecScale(ilinkA->x,-1.);CHKERRQ(ierr);
537c5d2311dSJed Brown       ierr = VecScatterBegin(ilinkA->sctx,x,ilinkA->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
538c5d2311dSJed Brown       ierr = VecScatterBegin(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
539c5d2311dSJed Brown       ierr = VecScatterEnd(ilinkA->sctx,x,ilinkA->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
540c5d2311dSJed Brown       ierr = KSPSolve(ksp,ilinkA->x,ilinkA->y);CHKERRQ(ierr);
541c5d2311dSJed Brown       ierr = VecScatterBegin(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
542c5d2311dSJed Brown       ierr = VecScatterEnd(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
543c5d2311dSJed Brown       ierr = VecScatterEnd(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
544c5d2311dSJed Brown       break;
545c5d2311dSJed Brown     case PC_FIELDSPLIT_SCHUR_FACTORIZATION_FULL:
546c5d2311dSJed Brown       /* [1 0; CA^{-1} 1] [A 0; 0 S] [1 A^{-1}B; 0 1], an exact solve if applied exactly, needs one extra solve with A */
5473b224e63SBarry Smith       ierr = VecScatterBegin(ilinkA->sctx,x,ilinkA->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
5483b224e63SBarry Smith       ierr = VecScatterEnd(ilinkA->sctx,x,ilinkA->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
5493b224e63SBarry Smith       ierr = KSPSolve(ksp,ilinkA->x,ilinkA->y);CHKERRQ(ierr);
5503b224e63SBarry Smith       ierr = MatMult(jac->C,ilinkA->y,ilinkD->x);CHKERRQ(ierr);
5513b224e63SBarry Smith       ierr = VecScale(ilinkD->x,-1.0);CHKERRQ(ierr);
5523b224e63SBarry Smith       ierr = VecScatterBegin(ilinkD->sctx,x,ilinkD->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
5533b224e63SBarry Smith       ierr = VecScatterEnd(ilinkD->sctx,x,ilinkD->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
5543b224e63SBarry Smith 
5553b224e63SBarry Smith       ierr = KSPSolve(jac->kspschur,ilinkD->x,ilinkD->y);CHKERRQ(ierr);
5563b224e63SBarry Smith       ierr = VecScatterBegin(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
5573b224e63SBarry Smith       ierr = VecScatterEnd(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
5583b224e63SBarry Smith 
5593b224e63SBarry Smith       ierr = MatMult(jac->B,ilinkD->y,ilinkA->y);CHKERRQ(ierr);
5603b224e63SBarry Smith       ierr = VecAXPY(ilinkA->x,-1.0,ilinkA->y);CHKERRQ(ierr);
5613b224e63SBarry Smith       ierr = KSPSolve(ksp,ilinkA->x,ilinkA->y);CHKERRQ(ierr);
5623b224e63SBarry Smith       ierr = VecScatterBegin(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
5633b224e63SBarry Smith       ierr = VecScatterEnd(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
564c5d2311dSJed Brown   }
5653b224e63SBarry Smith   PetscFunctionReturn(0);
5663b224e63SBarry Smith }
5673b224e63SBarry Smith 
5683b224e63SBarry Smith #undef __FUNCT__
5690971522cSBarry Smith #define __FUNCT__ "PCApply_FieldSplit"
5700971522cSBarry Smith static PetscErrorCode PCApply_FieldSplit(PC pc,Vec x,Vec y)
5710971522cSBarry Smith {
5720971522cSBarry Smith   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
5730971522cSBarry Smith   PetscErrorCode    ierr;
5745a9f2f41SSatish Balay   PC_FieldSplitLink ilink = jac->head;
575af93645bSJed Brown   PetscInt          cnt;
5760971522cSBarry Smith 
5770971522cSBarry Smith   PetscFunctionBegin;
57851f519a2SBarry Smith   CHKMEMQ;
57951f519a2SBarry Smith   ierr = VecSetBlockSize(x,jac->bs);CHKERRQ(ierr);
58051f519a2SBarry Smith   ierr = VecSetBlockSize(y,jac->bs);CHKERRQ(ierr);
58151f519a2SBarry Smith 
58279416396SBarry Smith   if (jac->type == PC_COMPOSITE_ADDITIVE) {
5831b9fc7fcSBarry Smith     if (jac->defaultsplit) {
5840971522cSBarry Smith       ierr = VecStrideGatherAll(x,jac->x,INSERT_VALUES);CHKERRQ(ierr);
5855a9f2f41SSatish Balay       while (ilink) {
5865a9f2f41SSatish Balay         ierr = KSPSolve(ilink->ksp,ilink->x,ilink->y);CHKERRQ(ierr);
5875a9f2f41SSatish Balay         ilink = ilink->next;
5880971522cSBarry Smith       }
5890971522cSBarry Smith       ierr = VecStrideScatterAll(jac->y,y,INSERT_VALUES);CHKERRQ(ierr);
5901b9fc7fcSBarry Smith     } else {
591efb30889SBarry Smith       ierr = VecSet(y,0.0);CHKERRQ(ierr);
5925a9f2f41SSatish Balay       while (ilink) {
5935a9f2f41SSatish Balay         ierr = FieldSplitSplitSolveAdd(ilink,x,y);CHKERRQ(ierr);
5945a9f2f41SSatish Balay         ilink = ilink->next;
5951b9fc7fcSBarry Smith       }
5961b9fc7fcSBarry Smith     }
59716913363SBarry Smith   } else if (jac->type == PC_COMPOSITE_MULTIPLICATIVE || jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
59879416396SBarry Smith     if (!jac->w1) {
59979416396SBarry Smith       ierr = VecDuplicate(x,&jac->w1);CHKERRQ(ierr);
60079416396SBarry Smith       ierr = VecDuplicate(x,&jac->w2);CHKERRQ(ierr);
60179416396SBarry Smith     }
602efb30889SBarry Smith     ierr = VecSet(y,0.0);CHKERRQ(ierr);
6035a9f2f41SSatish Balay     ierr = FieldSplitSplitSolveAdd(ilink,x,y);CHKERRQ(ierr);
6043e197d65SBarry Smith     cnt = 1;
6055a9f2f41SSatish Balay     while (ilink->next) {
6065a9f2f41SSatish Balay       ilink = ilink->next;
6073e197d65SBarry Smith       /* compute the residual only over the part of the vector needed */
6083e197d65SBarry Smith       ierr = MatMult(jac->Afield[cnt++],y,ilink->x);CHKERRQ(ierr);
6093e197d65SBarry Smith       ierr = VecScale(ilink->x,-1.0);CHKERRQ(ierr);
6103e197d65SBarry Smith       ierr = VecScatterBegin(ilink->sctx,x,ilink->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
6113e197d65SBarry Smith       ierr = VecScatterEnd(ilink->sctx,x,ilink->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
6123e197d65SBarry Smith       ierr = KSPSolve(ilink->ksp,ilink->x,ilink->y);CHKERRQ(ierr);
6133e197d65SBarry Smith       ierr = VecScatterBegin(ilink->sctx,ilink->y,y,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
6143e197d65SBarry Smith       ierr = VecScatterEnd(ilink->sctx,ilink->y,y,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
6153e197d65SBarry Smith     }
61651f519a2SBarry Smith     if (jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
61711755939SBarry Smith       cnt -= 2;
61851f519a2SBarry Smith       while (ilink->previous) {
61951f519a2SBarry Smith         ilink = ilink->previous;
62011755939SBarry Smith         /* compute the residual only over the part of the vector needed */
62111755939SBarry Smith         ierr = MatMult(jac->Afield[cnt--],y,ilink->x);CHKERRQ(ierr);
62211755939SBarry Smith         ierr = VecScale(ilink->x,-1.0);CHKERRQ(ierr);
62311755939SBarry Smith         ierr = VecScatterBegin(ilink->sctx,x,ilink->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
62411755939SBarry Smith         ierr = VecScatterEnd(ilink->sctx,x,ilink->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
62511755939SBarry Smith         ierr = KSPSolve(ilink->ksp,ilink->x,ilink->y);CHKERRQ(ierr);
62611755939SBarry Smith         ierr = VecScatterBegin(ilink->sctx,ilink->y,y,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
62711755939SBarry Smith         ierr = VecScatterEnd(ilink->sctx,ilink->y,y,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
62851f519a2SBarry Smith       }
62911755939SBarry Smith     }
63065e19b50SBarry Smith   } else SETERRQ1(((PetscObject)pc)->comm,PETSC_ERR_SUP,"Unsupported or unknown composition",(int) jac->type);
63151f519a2SBarry Smith   CHKMEMQ;
6320971522cSBarry Smith   PetscFunctionReturn(0);
6330971522cSBarry Smith }
6340971522cSBarry Smith 
635421e10b8SBarry Smith #define FieldSplitSplitSolveAddTranspose(ilink,xx,yy) \
636ca9f406cSSatish Balay     (VecScatterBegin(ilink->sctx,xx,ilink->y,INSERT_VALUES,SCATTER_FORWARD) || \
637ca9f406cSSatish Balay      VecScatterEnd(ilink->sctx,xx,ilink->y,INSERT_VALUES,SCATTER_FORWARD) || \
638421e10b8SBarry Smith      KSPSolveTranspose(ilink->ksp,ilink->y,ilink->x) || \
639ca9f406cSSatish Balay      VecScatterBegin(ilink->sctx,ilink->x,yy,ADD_VALUES,SCATTER_REVERSE) || \
640ca9f406cSSatish Balay      VecScatterEnd(ilink->sctx,ilink->x,yy,ADD_VALUES,SCATTER_REVERSE))
641421e10b8SBarry Smith 
642421e10b8SBarry Smith #undef __FUNCT__
643421e10b8SBarry Smith #define __FUNCT__ "PCApply_FieldSplit"
644421e10b8SBarry Smith static PetscErrorCode PCApplyTranspose_FieldSplit(PC pc,Vec x,Vec y)
645421e10b8SBarry Smith {
646421e10b8SBarry Smith   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
647421e10b8SBarry Smith   PetscErrorCode    ierr;
648421e10b8SBarry Smith   PC_FieldSplitLink ilink = jac->head;
649421e10b8SBarry Smith 
650421e10b8SBarry Smith   PetscFunctionBegin;
651421e10b8SBarry Smith   CHKMEMQ;
652421e10b8SBarry Smith   ierr = VecSetBlockSize(x,jac->bs);CHKERRQ(ierr);
653421e10b8SBarry Smith   ierr = VecSetBlockSize(y,jac->bs);CHKERRQ(ierr);
654421e10b8SBarry Smith 
655421e10b8SBarry Smith   if (jac->type == PC_COMPOSITE_ADDITIVE) {
656421e10b8SBarry Smith     if (jac->defaultsplit) {
657421e10b8SBarry Smith       ierr = VecStrideGatherAll(x,jac->x,INSERT_VALUES);CHKERRQ(ierr);
658421e10b8SBarry Smith       while (ilink) {
659421e10b8SBarry Smith 	ierr = KSPSolveTranspose(ilink->ksp,ilink->x,ilink->y);CHKERRQ(ierr);
660421e10b8SBarry Smith 	ilink = ilink->next;
661421e10b8SBarry Smith       }
662421e10b8SBarry Smith       ierr = VecStrideScatterAll(jac->y,y,INSERT_VALUES);CHKERRQ(ierr);
663421e10b8SBarry Smith     } else {
664421e10b8SBarry Smith       ierr = VecSet(y,0.0);CHKERRQ(ierr);
665421e10b8SBarry Smith       while (ilink) {
666421e10b8SBarry Smith         ierr = FieldSplitSplitSolveAddTranspose(ilink,x,y);CHKERRQ(ierr);
667421e10b8SBarry Smith 	ilink = ilink->next;
668421e10b8SBarry Smith       }
669421e10b8SBarry Smith     }
670421e10b8SBarry Smith   } else {
671421e10b8SBarry Smith     if (!jac->w1) {
672421e10b8SBarry Smith       ierr = VecDuplicate(x,&jac->w1);CHKERRQ(ierr);
673421e10b8SBarry Smith       ierr = VecDuplicate(x,&jac->w2);CHKERRQ(ierr);
674421e10b8SBarry Smith     }
675421e10b8SBarry Smith     ierr = VecSet(y,0.0);CHKERRQ(ierr);
676421e10b8SBarry Smith     if (jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
677421e10b8SBarry Smith       ierr = FieldSplitSplitSolveAddTranspose(ilink,x,y);CHKERRQ(ierr);
678421e10b8SBarry Smith       while (ilink->next) {
679421e10b8SBarry Smith         ilink = ilink->next;
6809989ab13SBarry Smith         ierr  = MatMultTranspose(pc->mat,y,jac->w1);CHKERRQ(ierr);
681421e10b8SBarry Smith         ierr  = VecWAXPY(jac->w2,-1.0,jac->w1,x);CHKERRQ(ierr);
682421e10b8SBarry Smith         ierr  = FieldSplitSplitSolveAddTranspose(ilink,jac->w2,y);CHKERRQ(ierr);
683421e10b8SBarry Smith       }
684421e10b8SBarry Smith       while (ilink->previous) {
685421e10b8SBarry Smith         ilink = ilink->previous;
6869989ab13SBarry Smith         ierr  = MatMultTranspose(pc->mat,y,jac->w1);CHKERRQ(ierr);
687421e10b8SBarry Smith         ierr  = VecWAXPY(jac->w2,-1.0,jac->w1,x);CHKERRQ(ierr);
688421e10b8SBarry Smith         ierr  = FieldSplitSplitSolveAddTranspose(ilink,jac->w2,y);CHKERRQ(ierr);
689421e10b8SBarry Smith       }
690421e10b8SBarry Smith     } else {
691421e10b8SBarry Smith       while (ilink->next) {   /* get to last entry in linked list */
692421e10b8SBarry Smith 	ilink = ilink->next;
693421e10b8SBarry Smith       }
694421e10b8SBarry Smith       ierr = FieldSplitSplitSolveAddTranspose(ilink,x,y);CHKERRQ(ierr);
695421e10b8SBarry Smith       while (ilink->previous) {
696421e10b8SBarry Smith 	ilink = ilink->previous;
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     }
702421e10b8SBarry Smith   }
703421e10b8SBarry Smith   CHKMEMQ;
704421e10b8SBarry Smith   PetscFunctionReturn(0);
705421e10b8SBarry Smith }
706421e10b8SBarry Smith 
7070971522cSBarry Smith #undef __FUNCT__
7080971522cSBarry Smith #define __FUNCT__ "PCDestroy_FieldSplit"
7090971522cSBarry Smith static PetscErrorCode PCDestroy_FieldSplit(PC pc)
7100971522cSBarry Smith {
7110971522cSBarry Smith   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
7120971522cSBarry Smith   PetscErrorCode    ierr;
7135a9f2f41SSatish Balay   PC_FieldSplitLink ilink = jac->head,next;
7140971522cSBarry Smith 
7150971522cSBarry Smith   PetscFunctionBegin;
7165a9f2f41SSatish Balay   while (ilink) {
7175a9f2f41SSatish Balay     ierr = KSPDestroy(ilink->ksp);CHKERRQ(ierr);
7185a9f2f41SSatish Balay     if (ilink->x) {ierr = VecDestroy(ilink->x);CHKERRQ(ierr);}
7195a9f2f41SSatish Balay     if (ilink->y) {ierr = VecDestroy(ilink->y);CHKERRQ(ierr);}
7205a9f2f41SSatish Balay     if (ilink->sctx) {ierr = VecScatterDestroy(ilink->sctx);CHKERRQ(ierr);}
721704ba839SBarry Smith     if (ilink->is) {ierr = ISDestroy(ilink->is);CHKERRQ(ierr);}
7225a9f2f41SSatish Balay     next = ilink->next;
7237e8c30b6SJed Brown     ierr = PetscFree(ilink->splitname);CHKERRQ(ierr);
724704ba839SBarry Smith     ierr = PetscFree(ilink->fields);CHKERRQ(ierr);
725704ba839SBarry Smith     ierr = PetscFree(ilink);CHKERRQ(ierr);
7265a9f2f41SSatish Balay     ilink = next;
7270971522cSBarry Smith   }
72805b42c5fSBarry Smith   ierr = PetscFree2(jac->x,jac->y);CHKERRQ(ierr);
729519d70e2SJed Brown   if (jac->mat && jac->mat != jac->pmat) {ierr = MatDestroyMatrices(jac->nsplits,&jac->mat);CHKERRQ(ierr);}
73097bbdb24SBarry Smith   if (jac->pmat) {ierr = MatDestroyMatrices(jac->nsplits,&jac->pmat);CHKERRQ(ierr);}
73168dd23aaSBarry Smith   if (jac->Afield) {ierr = MatDestroyMatrices(jac->nsplits,&jac->Afield);CHKERRQ(ierr);}
73279416396SBarry Smith   if (jac->w1) {ierr = VecDestroy(jac->w1);CHKERRQ(ierr);}
73379416396SBarry Smith   if (jac->w2) {ierr = VecDestroy(jac->w2);CHKERRQ(ierr);}
7343b224e63SBarry Smith   if (jac->schur) {ierr = MatDestroy(jac->schur);CHKERRQ(ierr);}
735084e4875SJed Brown   if (jac->schur_user) {ierr = MatDestroy(jac->schur_user);CHKERRQ(ierr);}
736d0f46423SBarry Smith   if (jac->kspschur) {ierr = KSPDestroy(jac->kspschur);CHKERRQ(ierr);}
7373b224e63SBarry Smith   if (jac->B) {ierr = MatDestroy(jac->B);CHKERRQ(ierr);}
7383b224e63SBarry Smith   if (jac->C) {ierr = MatDestroy(jac->C);CHKERRQ(ierr);}
7390971522cSBarry Smith   ierr = PetscFree(jac);CHKERRQ(ierr);
7400971522cSBarry Smith   PetscFunctionReturn(0);
7410971522cSBarry Smith }
7420971522cSBarry Smith 
7430971522cSBarry Smith #undef __FUNCT__
7440971522cSBarry Smith #define __FUNCT__ "PCSetFromOptions_FieldSplit"
7450971522cSBarry Smith static PetscErrorCode PCSetFromOptions_FieldSplit(PC pc)
7460971522cSBarry Smith {
7471b9fc7fcSBarry Smith   PetscErrorCode  ierr;
7486c924f48SJed Brown   PetscInt        bs;
749ace3abfcSBarry Smith   PetscBool       flg;
7509dcbbd2bSBarry Smith   PC_FieldSplit   *jac = (PC_FieldSplit*)pc->data;
7513b224e63SBarry Smith   PCCompositeType ctype;
7521b9fc7fcSBarry Smith 
7530971522cSBarry Smith   PetscFunctionBegin;
7541b9fc7fcSBarry Smith   ierr = PetscOptionsHead("FieldSplit options");CHKERRQ(ierr);
755acfcf0e5SJed Brown   ierr = PetscOptionsBool("-pc_fieldsplit_real_diagonal","Use diagonal blocks of the operator","PCFieldSplitSetRealDiagonal",jac->realdiagonal,&jac->realdiagonal,PETSC_NULL);CHKERRQ(ierr);
75651f519a2SBarry Smith   ierr = PetscOptionsInt("-pc_fieldsplit_block_size","Blocksize that defines number of fields","PCFieldSplitSetBlockSize",jac->bs,&bs,&flg);CHKERRQ(ierr);
75751f519a2SBarry Smith   if (flg) {
75851f519a2SBarry Smith     ierr = PCFieldSplitSetBlockSize(pc,bs);CHKERRQ(ierr);
75951f519a2SBarry Smith   }
760704ba839SBarry Smith 
7613b224e63SBarry Smith   ierr = PetscOptionsEnum("-pc_fieldsplit_type","Type of composition","PCFieldSplitSetType",PCCompositeTypes,(PetscEnum)jac->type,(PetscEnum*)&ctype,&flg);CHKERRQ(ierr);
7623b224e63SBarry Smith   if (flg) {
7633b224e63SBarry Smith     ierr = PCFieldSplitSetType(pc,ctype);CHKERRQ(ierr);
7643b224e63SBarry Smith   }
765d32f9abdSBarry Smith 
766c30613efSMatthew Knepley   /* Only setup fields once */
767c30613efSMatthew Knepley   if ((jac->bs > 0) && (jac->nsplits == 0)) {
768d32f9abdSBarry Smith     /* only allow user to set fields from command line if bs is already known.
769d32f9abdSBarry Smith        otherwise user can set them in PCFieldSplitSetDefaults() */
7706c924f48SJed Brown     ierr = PCFieldSplitSetRuntimeSplits_Private(pc);CHKERRQ(ierr);
7716c924f48SJed Brown     if (jac->splitdefined) {ierr = PetscInfo(pc,"Splits defined using the options database\n");CHKERRQ(ierr);}
772d32f9abdSBarry Smith   }
773c5d2311dSJed Brown   if (jac->type == PC_COMPOSITE_SCHUR) {
774c5d2311dSJed Brown     ierr = PetscOptionsEnum("-pc_fieldsplit_schur_factorization_type","Factorization to use","None",PCFieldSplitSchurFactorizationTypes,(PetscEnum)jac->schurfactorization,(PetscEnum*)&jac->schurfactorization,PETSC_NULL);CHKERRQ(ierr);
775084e4875SJed 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);
776c5d2311dSJed Brown   }
7771b9fc7fcSBarry Smith   ierr = PetscOptionsTail();CHKERRQ(ierr);
7780971522cSBarry Smith   PetscFunctionReturn(0);
7790971522cSBarry Smith }
7800971522cSBarry Smith 
7810971522cSBarry Smith /*------------------------------------------------------------------------------------*/
7820971522cSBarry Smith 
7830971522cSBarry Smith EXTERN_C_BEGIN
7840971522cSBarry Smith #undef __FUNCT__
7850971522cSBarry Smith #define __FUNCT__ "PCFieldSplitSetFields_FieldSplit"
7866685144eSJed Brown PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitSetFields_FieldSplit(PC pc,const char splitname[],PetscInt n,const PetscInt *fields)
7870971522cSBarry Smith {
78897bbdb24SBarry Smith   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
7890971522cSBarry Smith   PetscErrorCode    ierr;
7905a9f2f41SSatish Balay   PC_FieldSplitLink ilink,next = jac->head;
79169a612a9SBarry Smith   char              prefix[128];
79251f519a2SBarry Smith   PetscInt          i;
7930971522cSBarry Smith 
7940971522cSBarry Smith   PetscFunctionBegin;
7956c924f48SJed Brown   if (jac->splitdefined) {
7966c924f48SJed Brown     ierr = PetscInfo1(pc,"Ignoring new split \"%s\" because the splits have already been defined\n",splitname);CHKERRQ(ierr);
7976c924f48SJed Brown     PetscFunctionReturn(0);
7986c924f48SJed Brown   }
79951f519a2SBarry Smith   for (i=0; i<n; i++) {
800e32f2f54SBarry 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);
801e32f2f54SBarry Smith     if (fields[i] < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Negative field %D requested",fields[i]);
80251f519a2SBarry Smith   }
803704ba839SBarry Smith   ierr = PetscNew(struct _PC_FieldSplitLink,&ilink);CHKERRQ(ierr);
804db4c96c1SJed Brown   ierr = PetscStrallocpy(splitname,&ilink->splitname);CHKERRQ(ierr);
805704ba839SBarry Smith   ierr = PetscMalloc(n*sizeof(PetscInt),&ilink->fields);CHKERRQ(ierr);
8065a9f2f41SSatish Balay   ierr = PetscMemcpy(ilink->fields,fields,n*sizeof(PetscInt));CHKERRQ(ierr);
8075a9f2f41SSatish Balay   ilink->nfields = n;
8085a9f2f41SSatish Balay   ilink->next    = PETSC_NULL;
8097adad957SLisandro Dalcin   ierr           = KSPCreate(((PetscObject)pc)->comm,&ilink->ksp);CHKERRQ(ierr);
8101cee3971SBarry Smith   ierr           = PetscObjectIncrementTabLevel((PetscObject)ilink->ksp,(PetscObject)pc,1);CHKERRQ(ierr);
8115a9f2f41SSatish Balay   ierr           = KSPSetType(ilink->ksp,KSPPREONLY);CHKERRQ(ierr);
8129005cf84SBarry Smith   ierr           = PetscLogObjectParent((PetscObject)pc,(PetscObject)ilink->ksp);CHKERRQ(ierr);
81369a612a9SBarry Smith 
8146c924f48SJed Brown   ierr = PetscSNPrintf(prefix,sizeof prefix,"%sfieldsplit_%s_",((PetscObject)pc)->prefix?((PetscObject)pc)->prefix:"",splitname);CHKERRQ(ierr);
8155a9f2f41SSatish Balay   ierr = KSPSetOptionsPrefix(ilink->ksp,prefix);CHKERRQ(ierr);
8160971522cSBarry Smith 
8170971522cSBarry Smith   if (!next) {
8185a9f2f41SSatish Balay     jac->head       = ilink;
81951f519a2SBarry Smith     ilink->previous = PETSC_NULL;
8200971522cSBarry Smith   } else {
8210971522cSBarry Smith     while (next->next) {
8220971522cSBarry Smith       next = next->next;
8230971522cSBarry Smith     }
8245a9f2f41SSatish Balay     next->next      = ilink;
82551f519a2SBarry Smith     ilink->previous = next;
8260971522cSBarry Smith   }
8270971522cSBarry Smith   jac->nsplits++;
8280971522cSBarry Smith   PetscFunctionReturn(0);
8290971522cSBarry Smith }
8300971522cSBarry Smith EXTERN_C_END
8310971522cSBarry Smith 
832e69d4d44SBarry Smith EXTERN_C_BEGIN
833e69d4d44SBarry Smith #undef __FUNCT__
834e69d4d44SBarry Smith #define __FUNCT__ "PCFieldSplitGetSubKSP_FieldSplit_Schur"
835e69d4d44SBarry Smith PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitGetSubKSP_FieldSplit_Schur(PC pc,PetscInt *n,KSP **subksp)
836e69d4d44SBarry Smith {
837e69d4d44SBarry Smith   PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
838e69d4d44SBarry Smith   PetscErrorCode ierr;
839e69d4d44SBarry Smith 
840e69d4d44SBarry Smith   PetscFunctionBegin;
841519d70e2SJed Brown   ierr = PetscMalloc(jac->nsplits*sizeof(KSP),subksp);CHKERRQ(ierr);
842e69d4d44SBarry Smith   ierr = MatSchurComplementGetKSP(jac->schur,*subksp);CHKERRQ(ierr);
843e69d4d44SBarry Smith   (*subksp)[1] = jac->kspschur;
844084e4875SJed Brown   *n = jac->nsplits;
845e69d4d44SBarry Smith   PetscFunctionReturn(0);
846e69d4d44SBarry Smith }
847e69d4d44SBarry Smith EXTERN_C_END
8480971522cSBarry Smith 
8490971522cSBarry Smith EXTERN_C_BEGIN
8500971522cSBarry Smith #undef __FUNCT__
85169a612a9SBarry Smith #define __FUNCT__ "PCFieldSplitGetSubKSP_FieldSplit"
852dba47a55SKris Buschelman PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitGetSubKSP_FieldSplit(PC pc,PetscInt *n,KSP **subksp)
8530971522cSBarry Smith {
8540971522cSBarry Smith   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
8550971522cSBarry Smith   PetscErrorCode    ierr;
8560971522cSBarry Smith   PetscInt          cnt = 0;
8575a9f2f41SSatish Balay   PC_FieldSplitLink ilink = jac->head;
8580971522cSBarry Smith 
8590971522cSBarry Smith   PetscFunctionBegin;
86069a612a9SBarry Smith   ierr = PetscMalloc(jac->nsplits*sizeof(KSP*),subksp);CHKERRQ(ierr);
8615a9f2f41SSatish Balay   while (ilink) {
8625a9f2f41SSatish Balay     (*subksp)[cnt++] = ilink->ksp;
8635a9f2f41SSatish Balay     ilink = ilink->next;
8640971522cSBarry Smith   }
865e32f2f54SBarry 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);
8660971522cSBarry Smith   *n = jac->nsplits;
8670971522cSBarry Smith   PetscFunctionReturn(0);
8680971522cSBarry Smith }
8690971522cSBarry Smith EXTERN_C_END
8700971522cSBarry Smith 
871704ba839SBarry Smith EXTERN_C_BEGIN
872704ba839SBarry Smith #undef __FUNCT__
873704ba839SBarry Smith #define __FUNCT__ "PCFieldSplitSetIS_FieldSplit"
874db4c96c1SJed Brown PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitSetIS_FieldSplit(PC pc,const char splitname[],IS is)
875704ba839SBarry Smith {
876704ba839SBarry Smith   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
877704ba839SBarry Smith   PetscErrorCode    ierr;
878704ba839SBarry Smith   PC_FieldSplitLink ilink, next = jac->head;
879704ba839SBarry Smith   char              prefix[128];
880704ba839SBarry Smith 
881704ba839SBarry Smith   PetscFunctionBegin;
8826c924f48SJed Brown   if (jac->splitdefined) {
8836c924f48SJed Brown     ierr = PetscInfo1(pc,"Ignoring new split \"%s\" because the splits have already been defined\n",splitname);CHKERRQ(ierr);
8846c924f48SJed Brown     PetscFunctionReturn(0);
8856c924f48SJed Brown   }
88616913363SBarry Smith   ierr = PetscNew(struct _PC_FieldSplitLink,&ilink);CHKERRQ(ierr);
887db4c96c1SJed Brown   ierr = PetscStrallocpy(splitname,&ilink->splitname);CHKERRQ(ierr);
8881ab39975SBarry Smith   ilink->is      = is;
8891ab39975SBarry Smith   ierr           = PetscObjectReference((PetscObject)is);CHKERRQ(ierr);
890704ba839SBarry Smith   ilink->next    = PETSC_NULL;
891704ba839SBarry Smith   ierr           = KSPCreate(((PetscObject)pc)->comm,&ilink->ksp);CHKERRQ(ierr);
8921cee3971SBarry Smith   ierr           = PetscObjectIncrementTabLevel((PetscObject)ilink->ksp,(PetscObject)pc,1);CHKERRQ(ierr);
893704ba839SBarry Smith   ierr           = KSPSetType(ilink->ksp,KSPPREONLY);CHKERRQ(ierr);
8949005cf84SBarry Smith   ierr           = PetscLogObjectParent((PetscObject)pc,(PetscObject)ilink->ksp);CHKERRQ(ierr);
895704ba839SBarry Smith 
8966c924f48SJed Brown   ierr = PetscSNPrintf(prefix,sizeof prefix,"%sfieldsplit_%s_",((PetscObject)pc)->prefix?((PetscObject)pc)->prefix:"",splitname);CHKERRQ(ierr);
897704ba839SBarry Smith   ierr = KSPSetOptionsPrefix(ilink->ksp,prefix);CHKERRQ(ierr);
898704ba839SBarry Smith 
899704ba839SBarry Smith   if (!next) {
900704ba839SBarry Smith     jac->head       = ilink;
901704ba839SBarry Smith     ilink->previous = PETSC_NULL;
902704ba839SBarry Smith   } else {
903704ba839SBarry Smith     while (next->next) {
904704ba839SBarry Smith       next = next->next;
905704ba839SBarry Smith     }
906704ba839SBarry Smith     next->next      = ilink;
907704ba839SBarry Smith     ilink->previous = next;
908704ba839SBarry Smith   }
909704ba839SBarry Smith   jac->nsplits++;
910704ba839SBarry Smith 
911704ba839SBarry Smith   PetscFunctionReturn(0);
912704ba839SBarry Smith }
913704ba839SBarry Smith EXTERN_C_END
914704ba839SBarry Smith 
9150971522cSBarry Smith #undef __FUNCT__
9160971522cSBarry Smith #define __FUNCT__ "PCFieldSplitSetFields"
9170971522cSBarry Smith /*@
9180971522cSBarry Smith     PCFieldSplitSetFields - Sets the fields for one particular split in the field split preconditioner
9190971522cSBarry Smith 
920ad4df100SBarry Smith     Logically Collective on PC
9210971522cSBarry Smith 
9220971522cSBarry Smith     Input Parameters:
9230971522cSBarry Smith +   pc  - the preconditioner context
924db4c96c1SJed Brown .   splitname - name of this split
9250971522cSBarry Smith .   n - the number of fields in this split
926db4c96c1SJed Brown -   fields - the fields in this split
9270971522cSBarry Smith 
9280971522cSBarry Smith     Level: intermediate
9290971522cSBarry Smith 
930d32f9abdSBarry Smith     Notes: Use PCFieldSplitSetIS() to set a completely general set of indices as a field.
931d32f9abdSBarry Smith 
932d32f9abdSBarry Smith      The PCFieldSplitSetFields() is for defining fields as a strided blocks. For example, if the block
933d32f9abdSBarry 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
934d32f9abdSBarry Smith      0xx3xx6xx9xx12 ... x1xx4xx7xx ... xx2xx5xx8xx.. 01x34x67x... 0x1x3x5x7.. x12x45x78x....
935d32f9abdSBarry Smith      where the numbered entries indicate what is in the field.
936d32f9abdSBarry Smith 
937db4c96c1SJed Brown      This function is called once per split (it creates a new split each time).  Solve options
938db4c96c1SJed Brown      for this split will be available under the prefix -fieldsplit_SPLITNAME_.
939db4c96c1SJed Brown 
940d32f9abdSBarry Smith .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetBlockSize(), PCFieldSplitSetIS()
9410971522cSBarry Smith 
9420971522cSBarry Smith @*/
9436685144eSJed Brown PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitSetFields(PC pc,const char splitname[],PetscInt n,const PetscInt *fields)
9440971522cSBarry Smith {
9454ac538c5SBarry Smith   PetscErrorCode ierr;
9460971522cSBarry Smith 
9470971522cSBarry Smith   PetscFunctionBegin;
9480700a824SBarry Smith   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
949db4c96c1SJed Brown   PetscValidCharPointer(splitname,2);
950db4c96c1SJed Brown   if (n < 1) SETERRQ2(((PetscObject)pc)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Provided number of fields %D in split \"%s\" not positive",n,splitname);
951db4c96c1SJed Brown   PetscValidIntPointer(fields,3);
9524ac538c5SBarry Smith   ierr = PetscTryMethod(pc,"PCFieldSplitSetFields_C",(PC,const char[],PetscInt,const PetscInt *),(pc,splitname,n,fields));CHKERRQ(ierr);
9530971522cSBarry Smith   PetscFunctionReturn(0);
9540971522cSBarry Smith }
9550971522cSBarry Smith 
9560971522cSBarry Smith #undef __FUNCT__
957704ba839SBarry Smith #define __FUNCT__ "PCFieldSplitSetIS"
958704ba839SBarry Smith /*@
959704ba839SBarry Smith     PCFieldSplitSetIS - Sets the exact elements for field
960704ba839SBarry Smith 
961ad4df100SBarry Smith     Logically Collective on PC
962704ba839SBarry Smith 
963704ba839SBarry Smith     Input Parameters:
964704ba839SBarry Smith +   pc  - the preconditioner context
965db4c96c1SJed Brown .   splitname - name of this split
966db4c96c1SJed Brown -   is - the index set that defines the vector elements in this field
967704ba839SBarry Smith 
968d32f9abdSBarry Smith 
969a6ffb8dbSJed Brown     Notes:
970a6ffb8dbSJed Brown     Use PCFieldSplitSetFields(), for fields defined by strided types.
971a6ffb8dbSJed Brown 
972db4c96c1SJed Brown     This function is called once per split (it creates a new split each time).  Solve options
973db4c96c1SJed Brown     for this split will be available under the prefix -fieldsplit_SPLITNAME_.
974d32f9abdSBarry Smith 
975704ba839SBarry Smith     Level: intermediate
976704ba839SBarry Smith 
977704ba839SBarry Smith .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetBlockSize()
978704ba839SBarry Smith 
979704ba839SBarry Smith @*/
980db4c96c1SJed Brown PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitSetIS(PC pc,const char splitname[],IS is)
981704ba839SBarry Smith {
9824ac538c5SBarry Smith   PetscErrorCode ierr;
983704ba839SBarry Smith 
984704ba839SBarry Smith   PetscFunctionBegin;
9850700a824SBarry Smith   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
986db4c96c1SJed Brown   PetscValidCharPointer(splitname,2);
987db4c96c1SJed Brown   PetscValidHeaderSpecific(is,IS_CLASSID,3);
9884ac538c5SBarry Smith   ierr = PetscTryMethod(pc,"PCFieldSplitSetIS_C",(PC,const char[],IS),(pc,splitname,is));CHKERRQ(ierr);
989704ba839SBarry Smith   PetscFunctionReturn(0);
990704ba839SBarry Smith }
991704ba839SBarry Smith 
992704ba839SBarry Smith #undef __FUNCT__
99351f519a2SBarry Smith #define __FUNCT__ "PCFieldSplitSetBlockSize"
99451f519a2SBarry Smith /*@
99551f519a2SBarry Smith     PCFieldSplitSetBlockSize - Sets the block size for defining where fields start in the
99651f519a2SBarry Smith       fieldsplit preconditioner. If not set the matrix block size is used.
99751f519a2SBarry Smith 
998ad4df100SBarry Smith     Logically Collective on PC
99951f519a2SBarry Smith 
100051f519a2SBarry Smith     Input Parameters:
100151f519a2SBarry Smith +   pc  - the preconditioner context
100251f519a2SBarry Smith -   bs - the block size
100351f519a2SBarry Smith 
100451f519a2SBarry Smith     Level: intermediate
100551f519a2SBarry Smith 
100651f519a2SBarry Smith .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetFields()
100751f519a2SBarry Smith 
100851f519a2SBarry Smith @*/
100951f519a2SBarry Smith PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitSetBlockSize(PC pc,PetscInt bs)
101051f519a2SBarry Smith {
10114ac538c5SBarry Smith   PetscErrorCode ierr;
101251f519a2SBarry Smith 
101351f519a2SBarry Smith   PetscFunctionBegin;
10140700a824SBarry Smith   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
1015c5eb9154SBarry Smith   PetscValidLogicalCollectiveInt(pc,bs,2);
10164ac538c5SBarry Smith   ierr = PetscTryMethod(pc,"PCFieldSplitSetBlockSize_C",(PC,PetscInt),(pc,bs));CHKERRQ(ierr);
101751f519a2SBarry Smith   PetscFunctionReturn(0);
101851f519a2SBarry Smith }
101951f519a2SBarry Smith 
102051f519a2SBarry Smith #undef __FUNCT__
102169a612a9SBarry Smith #define __FUNCT__ "PCFieldSplitGetSubKSP"
10220971522cSBarry Smith /*@C
102369a612a9SBarry Smith    PCFieldSplitGetSubKSP - Gets the KSP contexts for all splits
10240971522cSBarry Smith 
102569a612a9SBarry Smith    Collective on KSP
10260971522cSBarry Smith 
10270971522cSBarry Smith    Input Parameter:
10280971522cSBarry Smith .  pc - the preconditioner context
10290971522cSBarry Smith 
10300971522cSBarry Smith    Output Parameters:
10310971522cSBarry Smith +  n - the number of split
103269a612a9SBarry Smith -  pc - the array of KSP contexts
10330971522cSBarry Smith 
10340971522cSBarry Smith    Note:
1035d32f9abdSBarry Smith    After PCFieldSplitGetSubKSP() the array of KSPs IS to be freed by the user
1036d32f9abdSBarry Smith    (not the KSP just the array that contains them).
10370971522cSBarry Smith 
103869a612a9SBarry Smith    You must call KSPSetUp() before calling PCFieldSplitGetSubKSP().
10390971522cSBarry Smith 
10400971522cSBarry Smith    Level: advanced
10410971522cSBarry Smith 
10420971522cSBarry Smith .seealso: PCFIELDSPLIT
10430971522cSBarry Smith @*/
1044dba47a55SKris Buschelman PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitGetSubKSP(PC pc,PetscInt *n,KSP *subksp[])
10450971522cSBarry Smith {
10464ac538c5SBarry Smith   PetscErrorCode ierr;
10470971522cSBarry Smith 
10480971522cSBarry Smith   PetscFunctionBegin;
10490700a824SBarry Smith   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
10500971522cSBarry Smith   PetscValidIntPointer(n,2);
10514ac538c5SBarry Smith   ierr = PetscUseMethod(pc,"PCFieldSplitGetSubKSP_C",(PC,PetscInt*,KSP **),(pc,n,subksp));CHKERRQ(ierr);
10520971522cSBarry Smith   PetscFunctionReturn(0);
10530971522cSBarry Smith }
10540971522cSBarry Smith 
1055e69d4d44SBarry Smith #undef __FUNCT__
1056e69d4d44SBarry Smith #define __FUNCT__ "PCFieldSplitSchurPrecondition"
1057e69d4d44SBarry Smith /*@
1058e69d4d44SBarry Smith     PCFieldSplitSchurPrecondition -  Indicates if the Schur complement is preconditioned by a preconditioner constructed by the
1059e69d4d44SBarry Smith       D matrix. Otherwise no preconditioner is used.
1060e69d4d44SBarry Smith 
1061e69d4d44SBarry Smith     Collective on PC
1062e69d4d44SBarry Smith 
1063e69d4d44SBarry Smith     Input Parameters:
1064e69d4d44SBarry Smith +   pc  - the preconditioner context
1065084e4875SJed Brown .   ptype - which matrix to use for preconditioning the Schur complement
1066084e4875SJed Brown -   userpre - matrix to use for preconditioning, or PETSC_NULL
1067084e4875SJed Brown 
1068084e4875SJed Brown     Notes:
1069084e4875SJed Brown     The default is to use the block on the diagonal of the preconditioning matrix.  This is D, in the (1,1) position.
1070084e4875SJed Brown     There are currently no preconditioners that work directly with the Schur complement so setting
1071084e4875SJed Brown     PC_FIELDSPLIT_SCHUR_PRE_SELF is observationally equivalent to -fieldsplit_1_pc_type none.
1072e69d4d44SBarry Smith 
1073e69d4d44SBarry Smith     Options Database:
1074084e4875SJed Brown .     -pc_fieldsplit_schur_precondition <self,user,diag> default is diag
1075e69d4d44SBarry Smith 
1076e69d4d44SBarry Smith     Level: intermediate
1077e69d4d44SBarry Smith 
1078084e4875SJed Brown .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetFields(), PCFieldSplitSchurPreType
1079e69d4d44SBarry Smith 
1080e69d4d44SBarry Smith @*/
1081084e4875SJed Brown PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitSchurPrecondition(PC pc,PCFieldSplitSchurPreType ptype,Mat pre)
1082e69d4d44SBarry Smith {
10834ac538c5SBarry Smith   PetscErrorCode ierr;
1084e69d4d44SBarry Smith 
1085e69d4d44SBarry Smith   PetscFunctionBegin;
10860700a824SBarry Smith   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
10874ac538c5SBarry Smith   ierr = PetscTryMethod(pc,"PCFieldSplitSchurPrecondition_C",(PC,PCFieldSplitSchurPreType,Mat),(pc,ptype,pre));CHKERRQ(ierr);
1088e69d4d44SBarry Smith   PetscFunctionReturn(0);
1089e69d4d44SBarry Smith }
1090e69d4d44SBarry Smith 
1091e69d4d44SBarry Smith EXTERN_C_BEGIN
1092e69d4d44SBarry Smith #undef __FUNCT__
1093e69d4d44SBarry Smith #define __FUNCT__ "PCFieldSplitSchurPrecondition_FieldSplit"
1094084e4875SJed Brown PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitSchurPrecondition_FieldSplit(PC pc,PCFieldSplitSchurPreType ptype,Mat pre)
1095e69d4d44SBarry Smith {
1096e69d4d44SBarry Smith   PC_FieldSplit  *jac = (PC_FieldSplit*)pc->data;
1097084e4875SJed Brown   PetscErrorCode  ierr;
1098e69d4d44SBarry Smith 
1099e69d4d44SBarry Smith   PetscFunctionBegin;
1100084e4875SJed Brown   jac->schurpre = ptype;
1101084e4875SJed Brown   if (pre) {
1102084e4875SJed Brown     if (jac->schur_user) {ierr = MatDestroy(jac->schur_user);CHKERRQ(ierr);}
1103084e4875SJed Brown     jac->schur_user = pre;
1104084e4875SJed Brown     ierr = PetscObjectReference((PetscObject)jac->schur_user);CHKERRQ(ierr);
1105084e4875SJed Brown   }
1106e69d4d44SBarry Smith   PetscFunctionReturn(0);
1107e69d4d44SBarry Smith }
1108e69d4d44SBarry Smith EXTERN_C_END
1109e69d4d44SBarry Smith 
111030ad9308SMatthew Knepley #undef __FUNCT__
111130ad9308SMatthew Knepley #define __FUNCT__ "PCFieldSplitGetSchurBlocks"
111230ad9308SMatthew Knepley /*@C
111330ad9308SMatthew Knepley    PCFieldSplitGetSchurBlocks - Gets the all matrix blocks for the Schur complement
111430ad9308SMatthew Knepley 
111530ad9308SMatthew Knepley    Collective on KSP
111630ad9308SMatthew Knepley 
111730ad9308SMatthew Knepley    Input Parameter:
111830ad9308SMatthew Knepley .  pc - the preconditioner context
111930ad9308SMatthew Knepley 
112030ad9308SMatthew Knepley    Output Parameters:
112130ad9308SMatthew Knepley +  A - the (0,0) block
112230ad9308SMatthew Knepley .  B - the (0,1) block
112330ad9308SMatthew Knepley .  C - the (1,0) block
112430ad9308SMatthew Knepley -  D - the (1,1) block
112530ad9308SMatthew Knepley 
112630ad9308SMatthew Knepley    Level: advanced
112730ad9308SMatthew Knepley 
112830ad9308SMatthew Knepley .seealso: PCFIELDSPLIT
112930ad9308SMatthew Knepley @*/
113030ad9308SMatthew Knepley PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitGetSchurBlocks(PC pc,Mat *A,Mat *B,Mat *C, Mat *D)
113130ad9308SMatthew Knepley {
113230ad9308SMatthew Knepley   PC_FieldSplit *jac = (PC_FieldSplit *) pc->data;
113330ad9308SMatthew Knepley 
113430ad9308SMatthew Knepley   PetscFunctionBegin;
11350700a824SBarry Smith   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
1136c1235816SBarry Smith   if (jac->type != PC_COMPOSITE_SCHUR) SETERRQ(((PetscObject)pc)->comm,PETSC_ERR_ARG_WRONG, "FieldSplit is not using a Schur complement approach.");
113730ad9308SMatthew Knepley   if (A) *A = jac->pmat[0];
113830ad9308SMatthew Knepley   if (B) *B = jac->B;
113930ad9308SMatthew Knepley   if (C) *C = jac->C;
114030ad9308SMatthew Knepley   if (D) *D = jac->pmat[1];
114130ad9308SMatthew Knepley   PetscFunctionReturn(0);
114230ad9308SMatthew Knepley }
114330ad9308SMatthew Knepley 
114479416396SBarry Smith EXTERN_C_BEGIN
114579416396SBarry Smith #undef __FUNCT__
114679416396SBarry Smith #define __FUNCT__ "PCFieldSplitSetType_FieldSplit"
1147dba47a55SKris Buschelman PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitSetType_FieldSplit(PC pc,PCCompositeType type)
114879416396SBarry Smith {
114979416396SBarry Smith   PC_FieldSplit  *jac = (PC_FieldSplit*)pc->data;
1150e69d4d44SBarry Smith   PetscErrorCode ierr;
115179416396SBarry Smith 
115279416396SBarry Smith   PetscFunctionBegin;
115379416396SBarry Smith   jac->type = type;
11543b224e63SBarry Smith   if (type == PC_COMPOSITE_SCHUR) {
11553b224e63SBarry Smith     pc->ops->apply = PCApply_FieldSplit_Schur;
11563b224e63SBarry Smith     pc->ops->view  = PCView_FieldSplit_Schur;
1157e69d4d44SBarry Smith     ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitGetSubKSP_C","PCFieldSplitGetSubKSP_FieldSplit_Schur",PCFieldSplitGetSubKSP_FieldSplit_Schur);CHKERRQ(ierr);
1158e69d4d44SBarry Smith     ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSchurPrecondition_C","PCFieldSplitSchurPrecondition_FieldSplit",PCFieldSplitSchurPrecondition_FieldSplit);CHKERRQ(ierr);
1159e69d4d44SBarry Smith 
11603b224e63SBarry Smith   } else {
11613b224e63SBarry Smith     pc->ops->apply = PCApply_FieldSplit;
11623b224e63SBarry Smith     pc->ops->view  = PCView_FieldSplit;
1163e69d4d44SBarry Smith     ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitGetSubKSP_C","PCFieldSplitGetSubKSP_FieldSplit",PCFieldSplitGetSubKSP_FieldSplit);CHKERRQ(ierr);
11649e7d6b0aSBarry Smith     ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSchurPrecondition_C","",0);CHKERRQ(ierr);
11653b224e63SBarry Smith   }
116679416396SBarry Smith   PetscFunctionReturn(0);
116779416396SBarry Smith }
116879416396SBarry Smith EXTERN_C_END
116979416396SBarry Smith 
117051f519a2SBarry Smith EXTERN_C_BEGIN
117151f519a2SBarry Smith #undef __FUNCT__
117251f519a2SBarry Smith #define __FUNCT__ "PCFieldSplitSetBlockSize_FieldSplit"
117351f519a2SBarry Smith PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitSetBlockSize_FieldSplit(PC pc,PetscInt bs)
117451f519a2SBarry Smith {
117551f519a2SBarry Smith   PC_FieldSplit  *jac = (PC_FieldSplit*)pc->data;
117651f519a2SBarry Smith 
117751f519a2SBarry Smith   PetscFunctionBegin;
117865e19b50SBarry Smith   if (bs < 1) SETERRQ1(((PetscObject)pc)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Blocksize must be positive, you gave %D",bs);
117965e19b50SBarry 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);
118051f519a2SBarry Smith   jac->bs = bs;
118151f519a2SBarry Smith   PetscFunctionReturn(0);
118251f519a2SBarry Smith }
118351f519a2SBarry Smith EXTERN_C_END
118451f519a2SBarry Smith 
118579416396SBarry Smith #undef __FUNCT__
118679416396SBarry Smith #define __FUNCT__ "PCFieldSplitSetType"
1187bc08b0f1SBarry Smith /*@
118879416396SBarry Smith    PCFieldSplitSetType - Sets the type of fieldsplit preconditioner.
118979416396SBarry Smith 
119079416396SBarry Smith    Collective on PC
119179416396SBarry Smith 
119279416396SBarry Smith    Input Parameter:
119379416396SBarry Smith .  pc - the preconditioner context
119481540f2fSBarry Smith .  type - PC_COMPOSITE_ADDITIVE, PC_COMPOSITE_MULTIPLICATIVE (default), PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE, PC_COMPOSITE_SPECIAL, PC_COMPOSITE_SCHUR
119579416396SBarry Smith 
119679416396SBarry Smith    Options Database Key:
1197a4efd8eaSMatthew Knepley .  -pc_fieldsplit_type <type: one of multiplicative, additive, symmetric_multiplicative, special, schur> - Sets fieldsplit preconditioner type
119879416396SBarry Smith 
119979416396SBarry Smith    Level: Developer
120079416396SBarry Smith 
120179416396SBarry Smith .keywords: PC, set, type, composite preconditioner, additive, multiplicative
120279416396SBarry Smith 
120379416396SBarry Smith .seealso: PCCompositeSetType()
120479416396SBarry Smith 
120579416396SBarry Smith @*/
1206dba47a55SKris Buschelman PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitSetType(PC pc,PCCompositeType type)
120779416396SBarry Smith {
12084ac538c5SBarry Smith   PetscErrorCode ierr;
120979416396SBarry Smith 
121079416396SBarry Smith   PetscFunctionBegin;
12110700a824SBarry Smith   PetscValidHeaderSpecific(pc,PC_CLASSID,1);
12124ac538c5SBarry Smith   ierr = PetscTryMethod(pc,"PCFieldSplitSetType_C",(PC,PCCompositeType),(pc,type));CHKERRQ(ierr);
121379416396SBarry Smith   PetscFunctionReturn(0);
121479416396SBarry Smith }
121579416396SBarry Smith 
12160971522cSBarry Smith /* -------------------------------------------------------------------------------------*/
12170971522cSBarry Smith /*MC
1218a8c7a070SBarry Smith    PCFIELDSPLIT - Preconditioner created by combining separate preconditioners for individual
12190971522cSBarry Smith                   fields or groups of fields
12200971522cSBarry Smith 
12210971522cSBarry Smith 
1222edf189efSBarry Smith      To set options on the solvers for each block append -fieldsplit_ to all the PC
1223edf189efSBarry Smith         options database keys. For example, -fieldsplit_pc_type ilu -fieldsplit_pc_factor_levels 1
12240971522cSBarry Smith 
1225a8c7a070SBarry Smith      To set the options on the solvers separate for each block call PCFieldSplitGetSubKSP()
122669a612a9SBarry Smith          and set the options directly on the resulting KSP object
12270971522cSBarry Smith 
12280971522cSBarry Smith    Level: intermediate
12290971522cSBarry Smith 
123079416396SBarry Smith    Options Database Keys:
123181540f2fSBarry Smith +   -pc_fieldsplit_%d_fields <a,b,..> - indicates the fields to be used in the %d'th split
123281540f2fSBarry Smith .   -pc_fieldsplit_default - automatically add any fields to additional splits that have not
123381540f2fSBarry Smith                               been supplied explicitly by -pc_fieldsplit_%d_fields
123481540f2fSBarry Smith .   -pc_fieldsplit_block_size <bs> - size of block that defines fields (i.e. there are bs fields)
123581540f2fSBarry Smith .    -pc_fieldsplit_type <additive,multiplicative,schur,symmetric_multiplicative>
1236e69d4d44SBarry Smith .    -pc_fieldsplit_schur_precondition <true,false> default is true
123779416396SBarry Smith 
1238edf189efSBarry Smith -    Options prefix for inner solvers when using Schur complement preconditioner are -fieldsplit_0_ and -fieldsplit_1_
12393b224e63SBarry Smith      for all other solvers they are -fieldsplit_%d_ for the dth field, use -fieldsplit_ for all fields
12403b224e63SBarry Smith 
12413b224e63SBarry Smith 
1242d32f9abdSBarry Smith    Notes: use PCFieldSplitSetFields() to set fields defined by "strided" entries and PCFieldSplitSetIS()
1243d32f9abdSBarry Smith      to define a field by an arbitrary collection of entries.
1244d32f9abdSBarry Smith 
1245d32f9abdSBarry Smith       If no fields are set the default is used. The fields are defined by entries strided by bs,
1246d32f9abdSBarry Smith       beginning at 0 then 1, etc to bs-1. The block size can be set with PCFieldSplitSetBlockSize(),
1247d32f9abdSBarry Smith       if this is not called the block size defaults to the blocksize of the second matrix passed
1248d32f9abdSBarry Smith       to KSPSetOperators()/PCSetOperators().
1249d32f9abdSBarry Smith 
1250d32f9abdSBarry Smith       Currently for the multiplicative version, the updated residual needed for the next field
1251d32f9abdSBarry Smith      solve is computed via a matrix vector product over the entire array. An optimization would be
1252d32f9abdSBarry Smith      to update the residual only for the part of the right hand side associated with the next field
1253d32f9abdSBarry Smith      solve. (This would involve more MatGetSubMatrix() calls or some other mechanism to compute the
1254d32f9abdSBarry Smith      part of the matrix needed to just update part of the residual).
1255d32f9abdSBarry Smith 
1256e69d4d44SBarry Smith      For the Schur complement preconditioner if J = ( A B )
1257e69d4d44SBarry Smith                                                     ( C D )
1258e69d4d44SBarry Smith      the preconditioner is
1259e69d4d44SBarry Smith               (I   -B inv(A)) ( inv(A)   0    ) (I         0  )
1260e69d4d44SBarry Smith               (0    I       ) (   0    inv(S) ) (-C inv(A) I  )
1261edf189efSBarry Smith      where the action of inv(A) is applied using the KSP solver with prefix -fieldsplit_0_. The action of
1262e69d4d44SBarry Smith      inv(S) is computed using the KSP solver with prefix -schur_. For PCFieldSplitGetKSP() when field number is
1263edf189efSBarry Smith      0 it returns the KSP associated with -fieldsplit_0_ while field number 1 gives -fieldsplit_1_ KSP. By default
1264e69d4d44SBarry Smith      D is used to construct a preconditioner for S, use PCFieldSplitSchurPrecondition() to turn on or off this
1265e69d4d44SBarry Smith      option.
1266e69d4d44SBarry Smith 
1267edf189efSBarry Smith      If only one set of indices (one IS) is provided with PCFieldSplitSetIS() then the complement of that IS
1268edf189efSBarry Smith      is used automatically for a second block.
1269edf189efSBarry Smith 
1270a541d17aSBarry Smith    Concepts: physics based preconditioners, block preconditioners
12710971522cSBarry Smith 
1272a541d17aSBarry Smith .seealso:  PCCreate(), PCSetType(), PCType (for list of available types), PC, Block_Preconditioners
1273e69d4d44SBarry Smith            PCFieldSplitGetSubKSP(), PCFieldSplitSetFields(), PCFieldSplitSetType(), PCFieldSplitSetIS(), PCFieldSplitSchurPrecondition()
12740971522cSBarry Smith M*/
12750971522cSBarry Smith 
12760971522cSBarry Smith EXTERN_C_BEGIN
12770971522cSBarry Smith #undef __FUNCT__
12780971522cSBarry Smith #define __FUNCT__ "PCCreate_FieldSplit"
1279dba47a55SKris Buschelman PetscErrorCode PETSCKSP_DLLEXPORT PCCreate_FieldSplit(PC pc)
12800971522cSBarry Smith {
12810971522cSBarry Smith   PetscErrorCode ierr;
12820971522cSBarry Smith   PC_FieldSplit  *jac;
12830971522cSBarry Smith 
12840971522cSBarry Smith   PetscFunctionBegin;
128538f2d2fdSLisandro Dalcin   ierr = PetscNewLog(pc,PC_FieldSplit,&jac);CHKERRQ(ierr);
12860971522cSBarry Smith   jac->bs        = -1;
12870971522cSBarry Smith   jac->nsplits   = 0;
12883e197d65SBarry Smith   jac->type      = PC_COMPOSITE_MULTIPLICATIVE;
1289e6cab6aaSJed Brown   jac->schurpre  = PC_FIELDSPLIT_SCHUR_PRE_USER; /* Try user preconditioner first, fall back on diagonal */
1290c5d2311dSJed Brown   jac->schurfactorization = PC_FIELDSPLIT_SCHUR_FACTORIZATION_FULL;
129151f519a2SBarry Smith 
12920971522cSBarry Smith   pc->data     = (void*)jac;
12930971522cSBarry Smith 
12940971522cSBarry Smith   pc->ops->apply             = PCApply_FieldSplit;
1295421e10b8SBarry Smith   pc->ops->applytranspose    = PCApplyTranspose_FieldSplit;
12960971522cSBarry Smith   pc->ops->setup             = PCSetUp_FieldSplit;
12970971522cSBarry Smith   pc->ops->destroy           = PCDestroy_FieldSplit;
12980971522cSBarry Smith   pc->ops->setfromoptions    = PCSetFromOptions_FieldSplit;
12990971522cSBarry Smith   pc->ops->view              = PCView_FieldSplit;
13000971522cSBarry Smith   pc->ops->applyrichardson   = 0;
13010971522cSBarry Smith 
130269a612a9SBarry Smith   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitGetSubKSP_C","PCFieldSplitGetSubKSP_FieldSplit",
130369a612a9SBarry Smith                     PCFieldSplitGetSubKSP_FieldSplit);CHKERRQ(ierr);
13040971522cSBarry Smith   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetFields_C","PCFieldSplitSetFields_FieldSplit",
13050971522cSBarry Smith                     PCFieldSplitSetFields_FieldSplit);CHKERRQ(ierr);
1306704ba839SBarry Smith   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetIS_C","PCFieldSplitSetIS_FieldSplit",
1307704ba839SBarry Smith                     PCFieldSplitSetIS_FieldSplit);CHKERRQ(ierr);
130879416396SBarry Smith   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetType_C","PCFieldSplitSetType_FieldSplit",
130979416396SBarry Smith                     PCFieldSplitSetType_FieldSplit);CHKERRQ(ierr);
131051f519a2SBarry Smith   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetBlockSize_C","PCFieldSplitSetBlockSize_FieldSplit",
131151f519a2SBarry Smith                     PCFieldSplitSetBlockSize_FieldSplit);CHKERRQ(ierr);
13120971522cSBarry Smith   PetscFunctionReturn(0);
13130971522cSBarry Smith }
13140971522cSBarry Smith EXTERN_C_END
13150971522cSBarry Smith 
13160971522cSBarry Smith 
1317a541d17aSBarry Smith /*MC
1318a541d17aSBarry Smith    Block_Preconditioners - PETSc provides support for a variety of "block preconditioners", this provides an
1319a541d17aSBarry Smith           overview of these methods.
1320a541d17aSBarry Smith 
1321a541d17aSBarry Smith       Consider the solution to ( A B ) (x_1)  =  (b_1)
1322a541d17aSBarry Smith                                ( C D ) (x_2)     (b_2)
1323a541d17aSBarry Smith 
1324a541d17aSBarry Smith       Important special cases, the Stokes equation: C = B' and D = 0  (A   B) (x_1) = (b_1)
1325a541d17aSBarry Smith                                                                        B'  0) (x_2)   (b_2)
1326a541d17aSBarry Smith 
1327a541d17aSBarry Smith       One of the goals of the PCFieldSplit preconditioner in PETSc is to provide a variety of preconditioners
1328a541d17aSBarry Smith       for this block system.
1329a541d17aSBarry Smith 
1330a541d17aSBarry Smith       Consider an additional matrix (Ap  Bp)
1331a541d17aSBarry Smith                                     (Cp  Dp) where some or all of the entries may be the same as
1332a541d17aSBarry Smith       in the original matrix (for example Ap == A).
1333a541d17aSBarry Smith 
1334a541d17aSBarry Smith       In the following, A^ denotes the approximate application of the inverse of A, possibly using Ap in the
1335a541d17aSBarry Smith       approximation. In PETSc this simply means one has called KSPSetOperators(ksp,A,Ap,...) or KSPSetOperators(ksp,Ap,Ap,...)
1336a541d17aSBarry Smith 
1337a541d17aSBarry Smith       Block Jacobi:   x_1 = A^ b_1
1338a541d17aSBarry Smith                       x_2 = D^ b_2
1339a541d17aSBarry Smith 
1340a541d17aSBarry Smith       Lower block Gauss-Seidel:   x_1 = A^ b_1
1341a541d17aSBarry Smith                             x_2 = D^ (b_2 - C x_1)       variant x_2 = D^ (b_2 - Cp x_1)
1342a541d17aSBarry Smith 
1343a541d17aSBarry Smith       Symmetric Gauss-Seidel:  x_1 = x_1 + A^(b_1 - A x_1 - B x_2)    variant  x_1 = x_1 + A^(b_1 - Ap x_1 - Bp x_2)
1344a541d17aSBarry Smith           Interestingly this form is not actually a symmetric matrix, the symmetric version is
1345a541d17aSBarry Smith                               x_1 = A^(b_1 - B x_2)      variant x_1 = A^(b_1 - Bp x_2)
1346a541d17aSBarry Smith 
13470bc0a719SBarry Smith    Level: intermediate
13480bc0a719SBarry Smith 
1349a541d17aSBarry Smith .seealso:  PCCreate(), PCSetType(), PCType (for list of available types), PC, PCFIELDSPLIT
1350a541d17aSBarry Smith            PCFieldSplitGetSubKSP(), PCFieldSplitSetFields(), PCFieldSplitSetType(), PCFieldSplitSetIS(), PCFieldSplitSchurPrecondition()
1351a541d17aSBarry Smith M*/
1352