xref: /petsc/src/ksp/pc/impls/fieldsplit/fieldsplit.c (revision 519d70e2a74db75ed96f96ce3425e9b7f0fc2470) !
1dba47a55SKris Buschelman #define PETSCKSP_DLL
2dba47a55SKris Buschelman 
30971522cSBarry Smith /*
40971522cSBarry Smith 
50971522cSBarry Smith */
66356e834SBarry Smith #include "private/pcimpl.h"     /*I "petscpc.h" I*/
70971522cSBarry Smith 
8084e4875SJed Brown const char *PCFieldSplitSchurPreTypes[] = {"self","diag","user","PCFieldSplitSchurPreType","PC_FIELDSPLIT_SCHUR_PRE_",0};
9084e4875SJed Brown 
100971522cSBarry Smith typedef struct _PC_FieldSplitLink *PC_FieldSplitLink;
110971522cSBarry Smith struct _PC_FieldSplitLink {
1269a612a9SBarry Smith   KSP               ksp;
130971522cSBarry Smith   Vec               x,y;
140971522cSBarry Smith   PetscInt          nfields;
150971522cSBarry Smith   PetscInt          *fields;
161b9fc7fcSBarry Smith   VecScatter        sctx;
174aa3045dSJed Brown   IS                is;
1851f519a2SBarry Smith   PC_FieldSplitLink next,previous;
190971522cSBarry Smith };
200971522cSBarry Smith 
210971522cSBarry Smith typedef struct {
2268dd23aaSBarry Smith   PCCompositeType   type;
23a4efd8eaSMatthew Knepley   PetscTruth        defaultsplit; /* Flag for a system with a set of 'k' scalar fields with the same layout (and bs = k) */
24*519d70e2SJed Brown   PetscTruth        realdiagonal; /* Flag to use the diagonal blocks of mat preconditioned by pmat, instead of just pmat */
2530ad9308SMatthew Knepley   PetscInt          bs;           /* Block size for IS and Mat structures */
2630ad9308SMatthew Knepley   PetscInt          nsplits;      /* Number of field divisions defined */
2779416396SBarry Smith   Vec               *x,*y,w1,w2;
28*519d70e2SJed Brown   Mat               *mat;         /* The diagonal block for each split */
29*519d70e2SJed Brown   Mat               *pmat;        /* The preconditioning diagonal block for each split */
3030ad9308SMatthew Knepley   Mat               *Afield;      /* The rows of the matrix associated with each split */
31704ba839SBarry Smith   PetscTruth        issetup;
3230ad9308SMatthew Knepley   /* Only used when Schur complement preconditioning is used */
3330ad9308SMatthew Knepley   Mat               B;            /* The (0,1) block */
3430ad9308SMatthew Knepley   Mat               C;            /* The (1,0) block */
3530ad9308SMatthew Knepley   Mat               schur;        /* The Schur complement S = D - C A^{-1} B */
36084e4875SJed Brown   Mat               schur_user;   /* User-provided preconditioning matrix for the Schur complement */
37084e4875SJed Brown   PCFieldSplitSchurPreType schurpre; /* Determines which preconditioning matrix is used for the Schur complement */
3830ad9308SMatthew Knepley   KSP               kspschur;     /* The solver for S */
3997bbdb24SBarry Smith   PC_FieldSplitLink head;
400971522cSBarry Smith } PC_FieldSplit;
410971522cSBarry Smith 
4216913363SBarry Smith /*
4316913363SBarry Smith     Notes: there is no particular reason that pmat, x, and y are stored as arrays in PC_FieldSplit instead of
4416913363SBarry Smith    inside PC_FieldSplitLink, just historical. If you want to be able to add new fields after already using the
4516913363SBarry Smith    PC you could change this.
4616913363SBarry Smith */
47084e4875SJed Brown 
48e6cab6aaSJed Brown /* This helper is so that setting a user-provided preconditioning matrix is orthogonal to choosing to use it.  This way the
49084e4875SJed Brown * application-provided FormJacobian can provide this matrix without interfering with the user's (command-line) choices. */
50084e4875SJed Brown static Mat FieldSplitSchurPre(PC_FieldSplit *jac)
51084e4875SJed Brown {
52084e4875SJed Brown   switch (jac->schurpre) {
53084e4875SJed Brown     case PC_FIELDSPLIT_SCHUR_PRE_SELF: return jac->schur;
54084e4875SJed Brown     case PC_FIELDSPLIT_SCHUR_PRE_DIAG: return jac->pmat[1];
55084e4875SJed Brown     case PC_FIELDSPLIT_SCHUR_PRE_USER: /* Use a user-provided matrix if it is given, otherwise diagonal block */
56084e4875SJed Brown     default:
57084e4875SJed Brown       return jac->schur_user ? jac->schur_user : jac->pmat[1];
58084e4875SJed Brown   }
59084e4875SJed Brown }
60084e4875SJed Brown 
61084e4875SJed Brown 
620971522cSBarry Smith #undef __FUNCT__
630971522cSBarry Smith #define __FUNCT__ "PCView_FieldSplit"
640971522cSBarry Smith static PetscErrorCode PCView_FieldSplit(PC pc,PetscViewer viewer)
650971522cSBarry Smith {
660971522cSBarry Smith   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
670971522cSBarry Smith   PetscErrorCode    ierr;
680971522cSBarry Smith   PetscTruth        iascii;
690971522cSBarry Smith   PetscInt          i,j;
705a9f2f41SSatish Balay   PC_FieldSplitLink ilink = jac->head;
710971522cSBarry Smith 
720971522cSBarry Smith   PetscFunctionBegin;
730971522cSBarry Smith   ierr = PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&iascii);CHKERRQ(ierr);
740971522cSBarry Smith   if (iascii) {
7551f519a2SBarry Smith     ierr = PetscViewerASCIIPrintf(viewer,"  FieldSplit with %s composition: total splits = %D, blocksize = %D\n",PCCompositeTypes[jac->type],jac->nsplits,jac->bs);CHKERRQ(ierr);
7669a612a9SBarry Smith     ierr = PetscViewerASCIIPrintf(viewer,"  Solver info for each split is in the following KSP objects:\n");CHKERRQ(ierr);
770971522cSBarry Smith     ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
780971522cSBarry Smith     for (i=0; i<jac->nsplits; i++) {
791ab39975SBarry Smith       if (ilink->fields) {
800971522cSBarry Smith 	ierr = PetscViewerASCIIPrintf(viewer,"Split number %D Fields ",i);CHKERRQ(ierr);
8179416396SBarry Smith 	ierr = PetscViewerASCIIUseTabs(viewer,PETSC_FALSE);CHKERRQ(ierr);
825a9f2f41SSatish Balay 	for (j=0; j<ilink->nfields; j++) {
8379416396SBarry Smith 	  if (j > 0) {
8479416396SBarry Smith 	    ierr = PetscViewerASCIIPrintf(viewer,",");CHKERRQ(ierr);
8579416396SBarry Smith 	  }
865a9f2f41SSatish Balay 	  ierr = PetscViewerASCIIPrintf(viewer," %D",ilink->fields[j]);CHKERRQ(ierr);
870971522cSBarry Smith 	}
880971522cSBarry Smith 	ierr = PetscViewerASCIIPrintf(viewer,"\n");CHKERRQ(ierr);
8979416396SBarry Smith         ierr = PetscViewerASCIIUseTabs(viewer,PETSC_TRUE);CHKERRQ(ierr);
901ab39975SBarry Smith       } else {
911ab39975SBarry Smith 	ierr = PetscViewerASCIIPrintf(viewer,"Split number %D Defined by IS\n",i);CHKERRQ(ierr);
921ab39975SBarry Smith       }
935a9f2f41SSatish Balay       ierr = KSPView(ilink->ksp,viewer);CHKERRQ(ierr);
945a9f2f41SSatish Balay       ilink = ilink->next;
950971522cSBarry Smith     }
960971522cSBarry Smith     ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
970971522cSBarry Smith   } else {
980971522cSBarry Smith     SETERRQ1(PETSC_ERR_SUP,"Viewer type %s not supported for PCFieldSplit",((PetscObject)viewer)->type_name);
990971522cSBarry Smith   }
1000971522cSBarry Smith   PetscFunctionReturn(0);
1010971522cSBarry Smith }
1020971522cSBarry Smith 
1030971522cSBarry Smith #undef __FUNCT__
1043b224e63SBarry Smith #define __FUNCT__ "PCView_FieldSplit_Schur"
1053b224e63SBarry Smith static PetscErrorCode PCView_FieldSplit_Schur(PC pc,PetscViewer viewer)
1063b224e63SBarry Smith {
1073b224e63SBarry Smith   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
1083b224e63SBarry Smith   PetscErrorCode    ierr;
1093b224e63SBarry Smith   PetscTruth        iascii;
1103b224e63SBarry Smith   PetscInt          i,j;
1113b224e63SBarry Smith   PC_FieldSplitLink ilink = jac->head;
1123b224e63SBarry Smith   KSP               ksp;
1133b224e63SBarry Smith 
1143b224e63SBarry Smith   PetscFunctionBegin;
1153b224e63SBarry Smith   ierr = PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&iascii);CHKERRQ(ierr);
1163b224e63SBarry Smith   if (iascii) {
1173b224e63SBarry Smith     ierr = PetscViewerASCIIPrintf(viewer,"  FieldSplit with Schur preconditioner, blocksize = %D\n",jac->bs);CHKERRQ(ierr);
1183b224e63SBarry Smith     ierr = PetscViewerASCIIPrintf(viewer,"  Split info:\n");CHKERRQ(ierr);
1193b224e63SBarry Smith     ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
1203b224e63SBarry Smith     for (i=0; i<jac->nsplits; i++) {
1213b224e63SBarry Smith       if (ilink->fields) {
1223b224e63SBarry Smith 	ierr = PetscViewerASCIIPrintf(viewer,"Split number %D Fields ",i);CHKERRQ(ierr);
1233b224e63SBarry Smith 	ierr = PetscViewerASCIIUseTabs(viewer,PETSC_FALSE);CHKERRQ(ierr);
1243b224e63SBarry Smith 	for (j=0; j<ilink->nfields; j++) {
1253b224e63SBarry Smith 	  if (j > 0) {
1263b224e63SBarry Smith 	    ierr = PetscViewerASCIIPrintf(viewer,",");CHKERRQ(ierr);
1273b224e63SBarry Smith 	  }
1283b224e63SBarry Smith 	  ierr = PetscViewerASCIIPrintf(viewer," %D",ilink->fields[j]);CHKERRQ(ierr);
1293b224e63SBarry Smith 	}
1303b224e63SBarry Smith 	ierr = PetscViewerASCIIPrintf(viewer,"\n");CHKERRQ(ierr);
1313b224e63SBarry Smith         ierr = PetscViewerASCIIUseTabs(viewer,PETSC_TRUE);CHKERRQ(ierr);
1323b224e63SBarry Smith       } else {
1333b224e63SBarry Smith 	ierr = PetscViewerASCIIPrintf(viewer,"Split number %D Defined by IS\n",i);CHKERRQ(ierr);
1343b224e63SBarry Smith       }
1353b224e63SBarry Smith       ilink = ilink->next;
1363b224e63SBarry Smith     }
1373b224e63SBarry Smith     ierr = PetscViewerASCIIPrintf(viewer,"KSP solver for A block \n");CHKERRQ(ierr);
1383b224e63SBarry Smith     ierr = MatSchurComplementGetKSP(jac->schur,&ksp);CHKERRQ(ierr);
1393b224e63SBarry Smith     ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
1403b224e63SBarry Smith     ierr = KSPView(ksp,viewer);CHKERRQ(ierr);
1413b224e63SBarry Smith     ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
1423b224e63SBarry Smith     ierr = PetscViewerASCIIPrintf(viewer,"KSP solver for S = D - C inv(A) B \n");CHKERRQ(ierr);
1433b224e63SBarry Smith     ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr);
1443b224e63SBarry Smith     ierr = KSPView(jac->kspschur,viewer);CHKERRQ(ierr);
1453b224e63SBarry Smith     ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
1463b224e63SBarry Smith     ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr);
1473b224e63SBarry Smith   } else {
1483b224e63SBarry Smith     SETERRQ1(PETSC_ERR_SUP,"Viewer type %s not supported for PCFieldSplit",((PetscObject)viewer)->type_name);
1493b224e63SBarry Smith   }
1503b224e63SBarry Smith   PetscFunctionReturn(0);
1513b224e63SBarry Smith }
1523b224e63SBarry Smith 
1533b224e63SBarry Smith #undef __FUNCT__
15469a612a9SBarry Smith #define __FUNCT__ "PCFieldSplitSetDefaults"
15569a612a9SBarry Smith static PetscErrorCode PCFieldSplitSetDefaults(PC pc)
1560971522cSBarry Smith {
1570971522cSBarry Smith   PC_FieldSplit     *jac  = (PC_FieldSplit*)pc->data;
1580971522cSBarry Smith   PetscErrorCode    ierr;
1595a9f2f41SSatish Balay   PC_FieldSplitLink ilink = jac->head;
160d32f9abdSBarry Smith   PetscInt          i = 0,*ifields,nfields;
161d32f9abdSBarry Smith   PetscTruth        flg = PETSC_FALSE,*fields,flg2;
162d32f9abdSBarry Smith   char              optionname[128];
1630971522cSBarry Smith 
1640971522cSBarry Smith   PetscFunctionBegin;
165d32f9abdSBarry Smith   if (!ilink) {
166d32f9abdSBarry Smith 
167521d7252SBarry Smith     if (jac->bs <= 0) {
168704ba839SBarry Smith       if (pc->pmat) {
169521d7252SBarry Smith         ierr   = MatGetBlockSize(pc->pmat,&jac->bs);CHKERRQ(ierr);
170704ba839SBarry Smith       } else {
171704ba839SBarry Smith         jac->bs = 1;
172704ba839SBarry Smith       }
173521d7252SBarry Smith     }
174d32f9abdSBarry Smith 
175d32f9abdSBarry Smith     ierr = PetscOptionsGetTruth(((PetscObject)pc)->prefix,"-pc_fieldsplit_default",&flg,PETSC_NULL);CHKERRQ(ierr);
176d32f9abdSBarry Smith     if (!flg) {
177d32f9abdSBarry Smith       /* Allow user to set fields from command line,  if bs was known at the time of PCSetFromOptions_FieldSplit()
178d32f9abdSBarry Smith          then it is set there. This is not ideal because we should only have options set in XXSetFromOptions(). */
179d32f9abdSBarry Smith       flg = PETSC_TRUE; /* switched off automatically if user sets fields manually here */
180d32f9abdSBarry Smith       ierr = PetscMalloc(jac->bs*sizeof(PetscInt),&ifields);CHKERRQ(ierr);
181d32f9abdSBarry Smith       while (PETSC_TRUE) {
182d32f9abdSBarry Smith         sprintf(optionname,"-pc_fieldsplit_%d_fields",(int)i++);
183d32f9abdSBarry Smith         nfields = jac->bs;
184d32f9abdSBarry Smith         ierr    = PetscOptionsGetIntArray(((PetscObject)pc)->prefix,optionname,ifields,&nfields,&flg2);CHKERRQ(ierr);
185d32f9abdSBarry Smith         if (!flg2) break;
186d32f9abdSBarry Smith         if (!nfields) SETERRQ(PETSC_ERR_USER,"Cannot list zero fields");
187d32f9abdSBarry Smith         flg = PETSC_FALSE;
188d32f9abdSBarry Smith         ierr = PCFieldSplitSetFields(pc,nfields,ifields);CHKERRQ(ierr);
189d32f9abdSBarry Smith       }
190d32f9abdSBarry Smith       ierr = PetscFree(ifields);CHKERRQ(ierr);
191d32f9abdSBarry Smith     }
192d32f9abdSBarry Smith 
193d32f9abdSBarry Smith     if (flg) {
194d32f9abdSBarry Smith       ierr = PetscInfo(pc,"Using default splitting of fields\n");CHKERRQ(ierr);
19579416396SBarry Smith       ierr = PetscMalloc(jac->bs*sizeof(PetscTruth),&fields);CHKERRQ(ierr);
19679416396SBarry Smith       ierr = PetscMemzero(fields,jac->bs*sizeof(PetscTruth));CHKERRQ(ierr);
1975a9f2f41SSatish Balay       while (ilink) {
1985a9f2f41SSatish Balay 	for (i=0; i<ilink->nfields; i++) {
1995a9f2f41SSatish Balay 	  fields[ilink->fields[i]] = PETSC_TRUE;
200521d7252SBarry Smith 	}
2015a9f2f41SSatish Balay 	ilink = ilink->next;
20279416396SBarry Smith       }
20397bbdb24SBarry Smith       jac->defaultsplit = PETSC_TRUE;
20479416396SBarry Smith       for (i=0; i<jac->bs; i++) {
20579416396SBarry Smith 	if (!fields[i]) {
20679416396SBarry Smith 	  ierr = PCFieldSplitSetFields(pc,1,&i);CHKERRQ(ierr);
20779416396SBarry Smith 	} else {
20879416396SBarry Smith 	  jac->defaultsplit = PETSC_FALSE;
20979416396SBarry Smith 	}
21079416396SBarry Smith       }
21168dd23aaSBarry Smith       ierr = PetscFree(fields);CHKERRQ(ierr);
212521d7252SBarry Smith     }
213edf189efSBarry Smith   } else if (jac->nsplits == 1) {
214edf189efSBarry Smith     if (ilink->is) {
215edf189efSBarry Smith       IS       is2;
216edf189efSBarry Smith       PetscInt nmin,nmax;
217edf189efSBarry Smith 
218edf189efSBarry Smith       ierr = MatGetOwnershipRange(pc->mat,&nmin,&nmax);CHKERRQ(ierr);
219edf189efSBarry Smith       ierr = ISComplement(ilink->is,nmin,nmax,&is2);CHKERRQ(ierr);
220edf189efSBarry Smith       ierr = PCFieldSplitSetIS(pc,is2);CHKERRQ(ierr);
221edf189efSBarry Smith       ierr = ISDestroy(is2);CHKERRQ(ierr);
222edf189efSBarry Smith     } else {
223edf189efSBarry Smith       SETERRQ(PETSC_ERR_SUP,"Must provide at least two sets of fields to PCFieldSplit()");
224edf189efSBarry Smith     }
225d32f9abdSBarry Smith   }
22669a612a9SBarry Smith   PetscFunctionReturn(0);
22769a612a9SBarry Smith }
22869a612a9SBarry Smith 
22969a612a9SBarry Smith 
23069a612a9SBarry Smith #undef __FUNCT__
23169a612a9SBarry Smith #define __FUNCT__ "PCSetUp_FieldSplit"
23269a612a9SBarry Smith static PetscErrorCode PCSetUp_FieldSplit(PC pc)
23369a612a9SBarry Smith {
23469a612a9SBarry Smith   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
23569a612a9SBarry Smith   PetscErrorCode    ierr;
2365a9f2f41SSatish Balay   PC_FieldSplitLink ilink;
237cf502942SBarry Smith   PetscInt          i,nsplit,ccsize;
23869a612a9SBarry Smith   MatStructure      flag = pc->flag;
23968dd23aaSBarry Smith   PetscTruth        sorted,getsub;
24069a612a9SBarry Smith 
24169a612a9SBarry Smith   PetscFunctionBegin;
24269a612a9SBarry Smith   ierr   = PCFieldSplitSetDefaults(pc);CHKERRQ(ierr);
24397bbdb24SBarry Smith   nsplit = jac->nsplits;
2445a9f2f41SSatish Balay   ilink  = jac->head;
24597bbdb24SBarry Smith 
24697bbdb24SBarry Smith   /* get the matrices for each split */
247704ba839SBarry Smith   if (!jac->issetup) {
2481b9fc7fcSBarry Smith     PetscInt rstart,rend,nslots,bs;
24997bbdb24SBarry Smith 
250704ba839SBarry Smith     jac->issetup = PETSC_TRUE;
251704ba839SBarry Smith 
252704ba839SBarry Smith     /* This is done here instead of in PCFieldSplitSetFields() because may not have matrix at that point */
25351f519a2SBarry Smith     bs     = jac->bs;
25497bbdb24SBarry Smith     ierr   = MatGetOwnershipRange(pc->pmat,&rstart,&rend);CHKERRQ(ierr);
255cf502942SBarry Smith     ierr   = MatGetLocalSize(pc->pmat,PETSC_NULL,&ccsize);CHKERRQ(ierr);
2561b9fc7fcSBarry Smith     nslots = (rend - rstart)/bs;
2571b9fc7fcSBarry Smith     for (i=0; i<nsplit; i++) {
2581b9fc7fcSBarry Smith       if (jac->defaultsplit) {
259704ba839SBarry Smith         ierr = ISCreateStride(((PetscObject)pc)->comm,nslots,rstart+i,nsplit,&ilink->is);CHKERRQ(ierr);
260704ba839SBarry Smith       } else if (!ilink->is) {
261ccb205f8SBarry Smith         if (ilink->nfields > 1) {
2625a9f2f41SSatish Balay           PetscInt   *ii,j,k,nfields = ilink->nfields,*fields = ilink->fields;
2635a9f2f41SSatish Balay           ierr = PetscMalloc(ilink->nfields*nslots*sizeof(PetscInt),&ii);CHKERRQ(ierr);
2641b9fc7fcSBarry Smith           for (j=0; j<nslots; j++) {
2651b9fc7fcSBarry Smith             for (k=0; k<nfields; k++) {
2661b9fc7fcSBarry Smith               ii[nfields*j + k] = rstart + bs*j + fields[k];
26797bbdb24SBarry Smith             }
26897bbdb24SBarry Smith           }
269704ba839SBarry Smith           ierr = ISCreateGeneral(((PetscObject)pc)->comm,nslots*nfields,ii,&ilink->is);CHKERRQ(ierr);
270ccb205f8SBarry Smith           ierr = PetscFree(ii);CHKERRQ(ierr);
271ccb205f8SBarry Smith         } else {
272704ba839SBarry Smith           ierr = ISCreateStride(((PetscObject)pc)->comm,nslots,rstart+ilink->fields[0],bs,&ilink->is);CHKERRQ(ierr);
273ccb205f8SBarry Smith         }
2743e197d65SBarry Smith       }
275704ba839SBarry Smith       ierr = ISSorted(ilink->is,&sorted);CHKERRQ(ierr);
2761b9fc7fcSBarry Smith       if (!sorted) SETERRQ(PETSC_ERR_USER,"Fields must be sorted when creating split");
277704ba839SBarry Smith       ilink = ilink->next;
2781b9fc7fcSBarry Smith     }
2791b9fc7fcSBarry Smith   }
2801b9fc7fcSBarry Smith 
281704ba839SBarry Smith   ilink  = jac->head;
28297bbdb24SBarry Smith   if (!jac->pmat) {
283cf502942SBarry Smith     ierr = PetscMalloc(nsplit*sizeof(Mat),&jac->pmat);CHKERRQ(ierr);
284cf502942SBarry Smith     for (i=0; i<nsplit; i++) {
2854aa3045dSJed Brown       ierr = MatGetSubMatrix(pc->pmat,ilink->is,ilink->is,MAT_INITIAL_MATRIX,&jac->pmat[i]);CHKERRQ(ierr);
286704ba839SBarry Smith       ilink = ilink->next;
287cf502942SBarry Smith     }
28897bbdb24SBarry Smith   } else {
289cf502942SBarry Smith     for (i=0; i<nsplit; i++) {
2904aa3045dSJed Brown       ierr = MatGetSubMatrix(pc->pmat,ilink->is,ilink->is,MAT_REUSE_MATRIX,&jac->pmat[i]);CHKERRQ(ierr);
291704ba839SBarry Smith       ilink = ilink->next;
292cf502942SBarry Smith     }
29397bbdb24SBarry Smith   }
294*519d70e2SJed Brown   if (jac->realdiagonal) {
295*519d70e2SJed Brown     ilink = jac->head;
296*519d70e2SJed Brown     if (!jac->mat) {
297*519d70e2SJed Brown       ierr = PetscMalloc(nsplit*sizeof(Mat),&jac->mat);CHKERRQ(ierr);
298*519d70e2SJed Brown       for (i=0; i<nsplit; i++) {
299*519d70e2SJed Brown         ierr = MatGetSubMatrix(pc->mat,ilink->is,ilink->is,MAT_INITIAL_MATRIX,&jac->mat[i]);CHKERRQ(ierr);
300*519d70e2SJed Brown         ilink = ilink->next;
301*519d70e2SJed Brown       }
302*519d70e2SJed Brown     } else {
303*519d70e2SJed Brown       for (i=0; i<nsplit; i++) {
304*519d70e2SJed Brown         ierr = MatGetSubMatrix(pc->mat,ilink->is,ilink->is,MAT_REUSE_MATRIX,&jac->mat[i]);CHKERRQ(ierr);
305*519d70e2SJed Brown         ilink = ilink->next;
306*519d70e2SJed Brown       }
307*519d70e2SJed Brown     }
308*519d70e2SJed Brown   } else {
309*519d70e2SJed Brown     jac->mat = jac->pmat;
310*519d70e2SJed Brown   }
31197bbdb24SBarry Smith 
312e6cab6aaSJed Brown   if (jac->type != PC_COMPOSITE_SCHUR) {
31368dd23aaSBarry Smith     /* extract the rows of the matrix associated with each field: used for efficient computation of residual inside algorithm */
31468dd23aaSBarry Smith     ierr = MatHasOperation(pc->mat,MATOP_GET_SUBMATRIX,&getsub);CHKERRQ(ierr);
3153b224e63SBarry Smith     if (getsub && jac->type != PC_COMPOSITE_ADDITIVE  && jac->type != PC_COMPOSITE_SCHUR) {
31668dd23aaSBarry Smith       ilink  = jac->head;
31768dd23aaSBarry Smith       if (!jac->Afield) {
31868dd23aaSBarry Smith         ierr = PetscMalloc(nsplit*sizeof(Mat),&jac->Afield);CHKERRQ(ierr);
31968dd23aaSBarry Smith         for (i=0; i<nsplit; i++) {
3204aa3045dSJed Brown           ierr = MatGetSubMatrix(pc->mat,ilink->is,PETSC_NULL,MAT_INITIAL_MATRIX,&jac->Afield[i]);CHKERRQ(ierr);
32168dd23aaSBarry Smith           ilink = ilink->next;
32268dd23aaSBarry Smith         }
32368dd23aaSBarry Smith       } else {
32468dd23aaSBarry Smith         for (i=0; i<nsplit; i++) {
3254aa3045dSJed Brown           ierr = MatGetSubMatrix(pc->mat,ilink->is,PETSC_NULL,MAT_REUSE_MATRIX,&jac->Afield[i]);CHKERRQ(ierr);
32668dd23aaSBarry Smith           ilink = ilink->next;
32768dd23aaSBarry Smith         }
32868dd23aaSBarry Smith       }
32968dd23aaSBarry Smith     }
330e6cab6aaSJed Brown   }
33168dd23aaSBarry Smith 
3323b224e63SBarry Smith   if (jac->type == PC_COMPOSITE_SCHUR) {
3333b224e63SBarry Smith     IS       ccis;
3344aa3045dSJed Brown     PetscInt rstart,rend;
3353b224e63SBarry Smith     if (nsplit != 2) SETERRQ(PETSC_ERR_ARG_INCOMP,"To use Schur complement preconditioner you must have exactly 2 fields");
33668dd23aaSBarry Smith 
337e6cab6aaSJed Brown     /* When extracting off-diagonal submatrices, we take complements from this range */
338e6cab6aaSJed Brown     ierr  = MatGetOwnershipRangeColumn(pc->mat,&rstart,&rend);CHKERRQ(ierr);
339e6cab6aaSJed Brown 
3403b224e63SBarry Smith     /* need to handle case when one is resetting up the preconditioner */
3413b224e63SBarry Smith     if (jac->schur) {
3423b224e63SBarry Smith       ilink = jac->head;
3434aa3045dSJed Brown       ierr  = ISComplement(ilink->is,rstart,rend,&ccis);CHKERRQ(ierr);
3444aa3045dSJed Brown       ierr  = MatGetSubMatrix(pc->mat,ilink->is,ccis,MAT_REUSE_MATRIX,&jac->B);CHKERRQ(ierr);
3453b224e63SBarry Smith       ierr  = ISDestroy(ccis);CHKERRQ(ierr);
3463b224e63SBarry Smith       ilink = ilink->next;
3474aa3045dSJed Brown       ierr  = ISComplement(ilink->is,rstart,rend,&ccis);CHKERRQ(ierr);
3484aa3045dSJed Brown       ierr  = MatGetSubMatrix(pc->mat,ilink->is,ccis,MAT_REUSE_MATRIX,&jac->C);CHKERRQ(ierr);
3493b224e63SBarry Smith       ierr  = ISDestroy(ccis);CHKERRQ(ierr);
350*519d70e2SJed Brown       ierr  = MatSchurComplementUpdate(jac->schur,jac->mat[0],jac->pmat[0],jac->B,jac->C,jac->pmat[1],pc->flag);CHKERRQ(ierr);
351084e4875SJed Brown       ierr  = KSPSetOperators(jac->kspschur,jac->schur,FieldSplitSchurPre(jac),pc->flag);CHKERRQ(ierr);
3523b224e63SBarry Smith 
3533b224e63SBarry Smith      } else {
3541cee3971SBarry Smith       KSP ksp;
3553b224e63SBarry Smith 
3563b224e63SBarry Smith       /* extract the B and C matrices */
3573b224e63SBarry Smith       ilink = jac->head;
3584aa3045dSJed Brown       ierr  = ISComplement(ilink->is,rstart,rend,&ccis);CHKERRQ(ierr);
3594aa3045dSJed Brown       ierr  = MatGetSubMatrix(pc->mat,ilink->is,ccis,MAT_INITIAL_MATRIX,&jac->B);CHKERRQ(ierr);
3603b224e63SBarry Smith       ierr  = ISDestroy(ccis);CHKERRQ(ierr);
3613b224e63SBarry Smith       ilink = ilink->next;
3624aa3045dSJed Brown       ierr  = ISComplement(ilink->is,rstart,rend,&ccis);CHKERRQ(ierr);
3634aa3045dSJed Brown       ierr  = MatGetSubMatrix(pc->mat,ilink->is,ccis,MAT_INITIAL_MATRIX,&jac->C);CHKERRQ(ierr);
3643b224e63SBarry Smith       ierr  = ISDestroy(ccis);CHKERRQ(ierr);
365084e4875SJed Brown       /* Better would be to use 'mat[0]' (diagonal block of the real matrix) preconditioned by pmat[0] */
366*519d70e2SJed Brown       ierr  = MatCreateSchurComplement(jac->mat[0],jac->pmat[0],jac->B,jac->C,jac->mat[1],&jac->schur);CHKERRQ(ierr);
3671cee3971SBarry Smith       ierr  = MatSchurComplementGetKSP(jac->schur,&ksp);CHKERRQ(ierr);
368e69d4d44SBarry Smith       ierr  = PetscObjectIncrementTabLevel((PetscObject)ksp,(PetscObject)pc,2);CHKERRQ(ierr);
3693b224e63SBarry Smith       ierr  = MatSetFromOptions(jac->schur);CHKERRQ(ierr);
3703b224e63SBarry Smith 
3713b224e63SBarry Smith       ierr  = KSPCreate(((PetscObject)pc)->comm,&jac->kspschur);CHKERRQ(ierr);
3721cee3971SBarry Smith       ierr  = PetscObjectIncrementTabLevel((PetscObject)jac->kspschur,(PetscObject)pc,1);CHKERRQ(ierr);
373084e4875SJed Brown       ierr  = KSPSetOperators(jac->kspschur,jac->schur,FieldSplitSchurPre(jac),DIFFERENT_NONZERO_PATTERN);CHKERRQ(ierr);
374084e4875SJed Brown       if (jac->schurpre == PC_FIELDSPLIT_SCHUR_PRE_SELF) {
375084e4875SJed Brown         PC pc;
376084e4875SJed Brown         ierr = KSPGetPC(ksp,&pc);CHKERRQ(ierr);
377084e4875SJed Brown         ierr = PCSetType(pc,PCNONE);CHKERRQ(ierr);
378084e4875SJed Brown         /* Note: This is bad if there exist preconditioners for MATSCHURCOMPLEMENT */
379e69d4d44SBarry Smith       }
3803b224e63SBarry Smith       ierr  = KSPSetOptionsPrefix(jac->kspschur,((PetscObject)pc)->prefix);CHKERRQ(ierr);
381edf189efSBarry Smith       ierr  = KSPAppendOptionsPrefix(jac->kspschur,"fieldsplit_1_");CHKERRQ(ierr);
3823b224e63SBarry Smith       /* really want setfromoptions called in PCSetFromOptions_FieldSplit(), but it is not ready yet */
3833b224e63SBarry Smith       ierr = KSPSetFromOptions(jac->kspschur);CHKERRQ(ierr);
3843b224e63SBarry Smith 
3853b224e63SBarry Smith       ierr = PetscMalloc2(2,Vec,&jac->x,2,Vec,&jac->y);CHKERRQ(ierr);
3863b224e63SBarry Smith       ierr = MatGetVecs(jac->pmat[0],&jac->x[0],&jac->y[0]);CHKERRQ(ierr);
3873b224e63SBarry Smith       ierr = MatGetVecs(jac->pmat[1],&jac->x[1],&jac->y[1]);CHKERRQ(ierr);
3883b224e63SBarry Smith       ilink = jac->head;
3893b224e63SBarry Smith       ilink->x = jac->x[0]; ilink->y = jac->y[0];
3903b224e63SBarry Smith       ilink = ilink->next;
3913b224e63SBarry Smith       ilink->x = jac->x[1]; ilink->y = jac->y[1];
3923b224e63SBarry Smith     }
3933b224e63SBarry Smith   } else {
39497bbdb24SBarry Smith     /* set up the individual PCs */
39597bbdb24SBarry Smith     i    = 0;
3965a9f2f41SSatish Balay     ilink = jac->head;
3975a9f2f41SSatish Balay     while (ilink) {
398*519d70e2SJed Brown       ierr = KSPSetOperators(ilink->ksp,jac->mat[i],jac->pmat[i],flag);CHKERRQ(ierr);
3993b224e63SBarry Smith       /* really want setfromoptions called in PCSetFromOptions_FieldSplit(), but it is not ready yet */
4005a9f2f41SSatish Balay       ierr = KSPSetFromOptions(ilink->ksp);CHKERRQ(ierr);
4015a9f2f41SSatish Balay       ierr = KSPSetUp(ilink->ksp);CHKERRQ(ierr);
40297bbdb24SBarry Smith       i++;
4035a9f2f41SSatish Balay       ilink = ilink->next;
4040971522cSBarry Smith     }
40597bbdb24SBarry Smith 
40697bbdb24SBarry Smith     /* create work vectors for each split */
4071b9fc7fcSBarry Smith     if (!jac->x) {
40897bbdb24SBarry Smith       ierr = PetscMalloc2(nsplit,Vec,&jac->x,nsplit,Vec,&jac->y);CHKERRQ(ierr);
4095a9f2f41SSatish Balay       ilink = jac->head;
41097bbdb24SBarry Smith       for (i=0; i<nsplit; i++) {
411906ed7ccSBarry Smith         Vec *vl,*vr;
412906ed7ccSBarry Smith 
413906ed7ccSBarry Smith         ierr      = KSPGetVecs(ilink->ksp,1,&vr,1,&vl);CHKERRQ(ierr);
414906ed7ccSBarry Smith         ilink->x  = *vr;
415906ed7ccSBarry Smith         ilink->y  = *vl;
416906ed7ccSBarry Smith         ierr      = PetscFree(vr);CHKERRQ(ierr);
417906ed7ccSBarry Smith         ierr      = PetscFree(vl);CHKERRQ(ierr);
4185a9f2f41SSatish Balay         jac->x[i] = ilink->x;
4195a9f2f41SSatish Balay         jac->y[i] = ilink->y;
4205a9f2f41SSatish Balay         ilink     = ilink->next;
42197bbdb24SBarry Smith       }
4223b224e63SBarry Smith     }
4233b224e63SBarry Smith   }
4243b224e63SBarry Smith 
4253b224e63SBarry Smith 
426d0f46423SBarry Smith   if (!jac->head->sctx) {
4273b224e63SBarry Smith     Vec xtmp;
4283b224e63SBarry Smith 
42979416396SBarry Smith     /* compute scatter contexts needed by multiplicative versions and non-default splits */
4301b9fc7fcSBarry Smith 
4315a9f2f41SSatish Balay     ilink = jac->head;
4321b9fc7fcSBarry Smith     ierr = MatGetVecs(pc->pmat,&xtmp,PETSC_NULL);CHKERRQ(ierr);
4331b9fc7fcSBarry Smith     for (i=0; i<nsplit; i++) {
434704ba839SBarry Smith       ierr = VecScatterCreate(xtmp,ilink->is,jac->x[i],PETSC_NULL,&ilink->sctx);CHKERRQ(ierr);
4355a9f2f41SSatish Balay       ilink = ilink->next;
4361b9fc7fcSBarry Smith     }
4371b9fc7fcSBarry Smith     ierr = VecDestroy(xtmp);CHKERRQ(ierr);
4381b9fc7fcSBarry Smith   }
4390971522cSBarry Smith   PetscFunctionReturn(0);
4400971522cSBarry Smith }
4410971522cSBarry Smith 
4425a9f2f41SSatish Balay #define FieldSplitSplitSolveAdd(ilink,xx,yy) \
443ca9f406cSSatish Balay     (VecScatterBegin(ilink->sctx,xx,ilink->x,INSERT_VALUES,SCATTER_FORWARD) || \
444ca9f406cSSatish Balay      VecScatterEnd(ilink->sctx,xx,ilink->x,INSERT_VALUES,SCATTER_FORWARD) || \
4455a9f2f41SSatish Balay      KSPSolve(ilink->ksp,ilink->x,ilink->y) || \
446ca9f406cSSatish Balay      VecScatterBegin(ilink->sctx,ilink->y,yy,ADD_VALUES,SCATTER_REVERSE) || \
447ca9f406cSSatish Balay      VecScatterEnd(ilink->sctx,ilink->y,yy,ADD_VALUES,SCATTER_REVERSE))
44879416396SBarry Smith 
4490971522cSBarry Smith #undef __FUNCT__
4503b224e63SBarry Smith #define __FUNCT__ "PCApply_FieldSplit_Schur"
4513b224e63SBarry Smith static PetscErrorCode PCApply_FieldSplit_Schur(PC pc,Vec x,Vec y)
4523b224e63SBarry Smith {
4533b224e63SBarry Smith   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
4543b224e63SBarry Smith   PetscErrorCode    ierr;
4553b224e63SBarry Smith   KSP               ksp;
4563b224e63SBarry Smith   PC_FieldSplitLink ilinkA = jac->head, ilinkD = ilinkA->next;
4573b224e63SBarry Smith 
4583b224e63SBarry Smith   PetscFunctionBegin;
4593b224e63SBarry Smith   ierr = MatSchurComplementGetKSP(jac->schur,&ksp);CHKERRQ(ierr);
4603b224e63SBarry Smith 
4613b224e63SBarry Smith   ierr = VecScatterBegin(ilinkA->sctx,x,ilinkA->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
4623b224e63SBarry Smith   ierr = VecScatterEnd(ilinkA->sctx,x,ilinkA->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
4633b224e63SBarry Smith   ierr = KSPSolve(ksp,ilinkA->x,ilinkA->y);CHKERRQ(ierr);
4643b224e63SBarry Smith   ierr = MatMult(jac->C,ilinkA->y,ilinkD->x);CHKERRQ(ierr);
4653b224e63SBarry Smith   ierr = VecScale(ilinkD->x,-1.0);CHKERRQ(ierr);
4663b224e63SBarry Smith   ierr = VecScatterBegin(ilinkD->sctx,x,ilinkD->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
4673b224e63SBarry Smith   ierr = VecScatterEnd(ilinkD->sctx,x,ilinkD->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
4683b224e63SBarry Smith 
4693b224e63SBarry Smith   ierr = KSPSolve(jac->kspschur,ilinkD->x,ilinkD->y);CHKERRQ(ierr);
4703b224e63SBarry Smith   ierr = VecScatterBegin(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
4713b224e63SBarry Smith   ierr = VecScatterEnd(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
4723b224e63SBarry Smith 
4733b224e63SBarry Smith   ierr = MatMult(jac->B,ilinkD->y,ilinkA->y);CHKERRQ(ierr);
4743b224e63SBarry Smith   ierr = VecAXPY(ilinkA->x,-1.0,ilinkA->y);CHKERRQ(ierr);
4753b224e63SBarry Smith   ierr = KSPSolve(ksp,ilinkA->x,ilinkA->y);CHKERRQ(ierr);
4763b224e63SBarry Smith   ierr = VecScatterBegin(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
4773b224e63SBarry Smith   ierr = VecScatterEnd(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
4783b224e63SBarry Smith 
4793b224e63SBarry Smith   PetscFunctionReturn(0);
4803b224e63SBarry Smith }
4813b224e63SBarry Smith 
4823b224e63SBarry Smith #undef __FUNCT__
4830971522cSBarry Smith #define __FUNCT__ "PCApply_FieldSplit"
4840971522cSBarry Smith static PetscErrorCode PCApply_FieldSplit(PC pc,Vec x,Vec y)
4850971522cSBarry Smith {
4860971522cSBarry Smith   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
4870971522cSBarry Smith   PetscErrorCode    ierr;
4885a9f2f41SSatish Balay   PC_FieldSplitLink ilink = jac->head;
4893e197d65SBarry Smith   PetscInt          bs,cnt;
4900971522cSBarry Smith 
4910971522cSBarry Smith   PetscFunctionBegin;
49251f519a2SBarry Smith   CHKMEMQ;
493e25d487eSBarry Smith   ierr = VecGetBlockSize(x,&bs);CHKERRQ(ierr);
49451f519a2SBarry Smith   ierr = VecSetBlockSize(x,jac->bs);CHKERRQ(ierr);
49551f519a2SBarry Smith   ierr = VecSetBlockSize(y,jac->bs);CHKERRQ(ierr);
49651f519a2SBarry Smith 
49779416396SBarry Smith   if (jac->type == PC_COMPOSITE_ADDITIVE) {
4981b9fc7fcSBarry Smith     if (jac->defaultsplit) {
4990971522cSBarry Smith       ierr = VecStrideGatherAll(x,jac->x,INSERT_VALUES);CHKERRQ(ierr);
5005a9f2f41SSatish Balay       while (ilink) {
5015a9f2f41SSatish Balay         ierr = KSPSolve(ilink->ksp,ilink->x,ilink->y);CHKERRQ(ierr);
5025a9f2f41SSatish Balay         ilink = ilink->next;
5030971522cSBarry Smith       }
5040971522cSBarry Smith       ierr = VecStrideScatterAll(jac->y,y,INSERT_VALUES);CHKERRQ(ierr);
5051b9fc7fcSBarry Smith     } else {
506efb30889SBarry Smith       ierr = VecSet(y,0.0);CHKERRQ(ierr);
5075a9f2f41SSatish Balay       while (ilink) {
5085a9f2f41SSatish Balay         ierr = FieldSplitSplitSolveAdd(ilink,x,y);CHKERRQ(ierr);
5095a9f2f41SSatish Balay         ilink = ilink->next;
5101b9fc7fcSBarry Smith       }
5111b9fc7fcSBarry Smith     }
51216913363SBarry Smith   } else if (jac->type == PC_COMPOSITE_MULTIPLICATIVE || jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
51379416396SBarry Smith     if (!jac->w1) {
51479416396SBarry Smith       ierr = VecDuplicate(x,&jac->w1);CHKERRQ(ierr);
51579416396SBarry Smith       ierr = VecDuplicate(x,&jac->w2);CHKERRQ(ierr);
51679416396SBarry Smith     }
517efb30889SBarry Smith     ierr = VecSet(y,0.0);CHKERRQ(ierr);
5185a9f2f41SSatish Balay     ierr = FieldSplitSplitSolveAdd(ilink,x,y);CHKERRQ(ierr);
5193e197d65SBarry Smith     cnt = 1;
5205a9f2f41SSatish Balay     while (ilink->next) {
5215a9f2f41SSatish Balay       ilink = ilink->next;
5223e197d65SBarry Smith       if (jac->Afield) {
5233e197d65SBarry Smith         /* compute the residual only over the part of the vector needed */
5243e197d65SBarry Smith         ierr = MatMult(jac->Afield[cnt++],y,ilink->x);CHKERRQ(ierr);
5253e197d65SBarry Smith         ierr = VecScale(ilink->x,-1.0);CHKERRQ(ierr);
5263e197d65SBarry Smith         ierr = VecScatterBegin(ilink->sctx,x,ilink->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
5273e197d65SBarry Smith         ierr = VecScatterEnd(ilink->sctx,x,ilink->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
5283e197d65SBarry Smith         ierr = KSPSolve(ilink->ksp,ilink->x,ilink->y);CHKERRQ(ierr);
5293e197d65SBarry Smith         ierr = VecScatterBegin(ilink->sctx,ilink->y,y,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
5303e197d65SBarry Smith         ierr = VecScatterEnd(ilink->sctx,ilink->y,y,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
5313e197d65SBarry Smith       } else {
5323e197d65SBarry Smith         /* compute the residual over the entire vector */
5331ab39975SBarry Smith 	ierr = MatMult(pc->mat,y,jac->w1);CHKERRQ(ierr);
534efb30889SBarry Smith 	ierr = VecWAXPY(jac->w2,-1.0,jac->w1,x);CHKERRQ(ierr);
5355a9f2f41SSatish Balay 	ierr = FieldSplitSplitSolveAdd(ilink,jac->w2,y);CHKERRQ(ierr);
53679416396SBarry Smith       }
5373e197d65SBarry Smith     }
53851f519a2SBarry Smith     if (jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
53911755939SBarry Smith       cnt -= 2;
54051f519a2SBarry Smith       while (ilink->previous) {
54151f519a2SBarry Smith         ilink = ilink->previous;
54211755939SBarry Smith         if (jac->Afield) {
54311755939SBarry Smith 	  /* compute the residual only over the part of the vector needed */
54411755939SBarry Smith 	  ierr = MatMult(jac->Afield[cnt--],y,ilink->x);CHKERRQ(ierr);
54511755939SBarry Smith 	  ierr = VecScale(ilink->x,-1.0);CHKERRQ(ierr);
54611755939SBarry Smith 	  ierr = VecScatterBegin(ilink->sctx,x,ilink->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
54711755939SBarry Smith 	  ierr = VecScatterEnd(ilink->sctx,x,ilink->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr);
54811755939SBarry Smith 	  ierr = KSPSolve(ilink->ksp,ilink->x,ilink->y);CHKERRQ(ierr);
54911755939SBarry Smith 	  ierr = VecScatterBegin(ilink->sctx,ilink->y,y,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
55011755939SBarry Smith 	  ierr = VecScatterEnd(ilink->sctx,ilink->y,y,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr);
55111755939SBarry Smith         } else {
5521ab39975SBarry Smith 	  ierr  = MatMult(pc->mat,y,jac->w1);CHKERRQ(ierr);
55351f519a2SBarry Smith 	  ierr  = VecWAXPY(jac->w2,-1.0,jac->w1,x);CHKERRQ(ierr);
55451f519a2SBarry Smith 	  ierr  = FieldSplitSplitSolveAdd(ilink,jac->w2,y);CHKERRQ(ierr);
55579416396SBarry Smith         }
55651f519a2SBarry Smith       }
55711755939SBarry Smith     }
55816913363SBarry Smith   } else SETERRQ1(PETSC_ERR_SUP,"Unsupported or unknown composition",(int) jac->type);
55951f519a2SBarry Smith   CHKMEMQ;
5600971522cSBarry Smith   PetscFunctionReturn(0);
5610971522cSBarry Smith }
5620971522cSBarry Smith 
563421e10b8SBarry Smith #define FieldSplitSplitSolveAddTranspose(ilink,xx,yy) \
564ca9f406cSSatish Balay     (VecScatterBegin(ilink->sctx,xx,ilink->y,INSERT_VALUES,SCATTER_FORWARD) || \
565ca9f406cSSatish Balay      VecScatterEnd(ilink->sctx,xx,ilink->y,INSERT_VALUES,SCATTER_FORWARD) || \
566421e10b8SBarry Smith      KSPSolveTranspose(ilink->ksp,ilink->y,ilink->x) || \
567ca9f406cSSatish Balay      VecScatterBegin(ilink->sctx,ilink->x,yy,ADD_VALUES,SCATTER_REVERSE) || \
568ca9f406cSSatish Balay      VecScatterEnd(ilink->sctx,ilink->x,yy,ADD_VALUES,SCATTER_REVERSE))
569421e10b8SBarry Smith 
570421e10b8SBarry Smith #undef __FUNCT__
571421e10b8SBarry Smith #define __FUNCT__ "PCApply_FieldSplit"
572421e10b8SBarry Smith static PetscErrorCode PCApplyTranspose_FieldSplit(PC pc,Vec x,Vec y)
573421e10b8SBarry Smith {
574421e10b8SBarry Smith   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
575421e10b8SBarry Smith   PetscErrorCode    ierr;
576421e10b8SBarry Smith   PC_FieldSplitLink ilink = jac->head;
577421e10b8SBarry Smith   PetscInt          bs;
578421e10b8SBarry Smith 
579421e10b8SBarry Smith   PetscFunctionBegin;
580421e10b8SBarry Smith   CHKMEMQ;
581421e10b8SBarry Smith   ierr = VecGetBlockSize(x,&bs);CHKERRQ(ierr);
582421e10b8SBarry Smith   ierr = VecSetBlockSize(x,jac->bs);CHKERRQ(ierr);
583421e10b8SBarry Smith   ierr = VecSetBlockSize(y,jac->bs);CHKERRQ(ierr);
584421e10b8SBarry Smith 
585421e10b8SBarry Smith   if (jac->type == PC_COMPOSITE_ADDITIVE) {
586421e10b8SBarry Smith     if (jac->defaultsplit) {
587421e10b8SBarry Smith       ierr = VecStrideGatherAll(x,jac->x,INSERT_VALUES);CHKERRQ(ierr);
588421e10b8SBarry Smith       while (ilink) {
589421e10b8SBarry Smith 	ierr = KSPSolveTranspose(ilink->ksp,ilink->x,ilink->y);CHKERRQ(ierr);
590421e10b8SBarry Smith 	ilink = ilink->next;
591421e10b8SBarry Smith       }
592421e10b8SBarry Smith       ierr = VecStrideScatterAll(jac->y,y,INSERT_VALUES);CHKERRQ(ierr);
593421e10b8SBarry Smith     } else {
594421e10b8SBarry Smith       ierr = VecSet(y,0.0);CHKERRQ(ierr);
595421e10b8SBarry Smith       while (ilink) {
596421e10b8SBarry Smith         ierr = FieldSplitSplitSolveAddTranspose(ilink,x,y);CHKERRQ(ierr);
597421e10b8SBarry Smith 	ilink = ilink->next;
598421e10b8SBarry Smith       }
599421e10b8SBarry Smith     }
600421e10b8SBarry Smith   } else {
601421e10b8SBarry Smith     if (!jac->w1) {
602421e10b8SBarry Smith       ierr = VecDuplicate(x,&jac->w1);CHKERRQ(ierr);
603421e10b8SBarry Smith       ierr = VecDuplicate(x,&jac->w2);CHKERRQ(ierr);
604421e10b8SBarry Smith     }
605421e10b8SBarry Smith     ierr = VecSet(y,0.0);CHKERRQ(ierr);
606421e10b8SBarry Smith     if (jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) {
607421e10b8SBarry Smith       ierr = FieldSplitSplitSolveAddTranspose(ilink,x,y);CHKERRQ(ierr);
608421e10b8SBarry Smith       while (ilink->next) {
609421e10b8SBarry Smith         ilink = ilink->next;
6109989ab13SBarry Smith         ierr  = MatMultTranspose(pc->mat,y,jac->w1);CHKERRQ(ierr);
611421e10b8SBarry Smith         ierr  = VecWAXPY(jac->w2,-1.0,jac->w1,x);CHKERRQ(ierr);
612421e10b8SBarry Smith         ierr  = FieldSplitSplitSolveAddTranspose(ilink,jac->w2,y);CHKERRQ(ierr);
613421e10b8SBarry Smith       }
614421e10b8SBarry Smith       while (ilink->previous) {
615421e10b8SBarry Smith         ilink = ilink->previous;
6169989ab13SBarry Smith         ierr  = MatMultTranspose(pc->mat,y,jac->w1);CHKERRQ(ierr);
617421e10b8SBarry Smith         ierr  = VecWAXPY(jac->w2,-1.0,jac->w1,x);CHKERRQ(ierr);
618421e10b8SBarry Smith         ierr  = FieldSplitSplitSolveAddTranspose(ilink,jac->w2,y);CHKERRQ(ierr);
619421e10b8SBarry Smith       }
620421e10b8SBarry Smith     } else {
621421e10b8SBarry Smith       while (ilink->next) {   /* get to last entry in linked list */
622421e10b8SBarry Smith 	ilink = ilink->next;
623421e10b8SBarry Smith       }
624421e10b8SBarry Smith       ierr = FieldSplitSplitSolveAddTranspose(ilink,x,y);CHKERRQ(ierr);
625421e10b8SBarry Smith       while (ilink->previous) {
626421e10b8SBarry Smith 	ilink = ilink->previous;
6279989ab13SBarry Smith 	ierr  = MatMultTranspose(pc->mat,y,jac->w1);CHKERRQ(ierr);
628421e10b8SBarry Smith 	ierr  = VecWAXPY(jac->w2,-1.0,jac->w1,x);CHKERRQ(ierr);
629421e10b8SBarry Smith 	ierr  = FieldSplitSplitSolveAddTranspose(ilink,jac->w2,y);CHKERRQ(ierr);
630421e10b8SBarry Smith       }
631421e10b8SBarry Smith     }
632421e10b8SBarry Smith   }
633421e10b8SBarry Smith   CHKMEMQ;
634421e10b8SBarry Smith   PetscFunctionReturn(0);
635421e10b8SBarry Smith }
636421e10b8SBarry Smith 
6370971522cSBarry Smith #undef __FUNCT__
6380971522cSBarry Smith #define __FUNCT__ "PCDestroy_FieldSplit"
6390971522cSBarry Smith static PetscErrorCode PCDestroy_FieldSplit(PC pc)
6400971522cSBarry Smith {
6410971522cSBarry Smith   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
6420971522cSBarry Smith   PetscErrorCode    ierr;
6435a9f2f41SSatish Balay   PC_FieldSplitLink ilink = jac->head,next;
6440971522cSBarry Smith 
6450971522cSBarry Smith   PetscFunctionBegin;
6465a9f2f41SSatish Balay   while (ilink) {
6475a9f2f41SSatish Balay     ierr = KSPDestroy(ilink->ksp);CHKERRQ(ierr);
6485a9f2f41SSatish Balay     if (ilink->x) {ierr = VecDestroy(ilink->x);CHKERRQ(ierr);}
6495a9f2f41SSatish Balay     if (ilink->y) {ierr = VecDestroy(ilink->y);CHKERRQ(ierr);}
6505a9f2f41SSatish Balay     if (ilink->sctx) {ierr = VecScatterDestroy(ilink->sctx);CHKERRQ(ierr);}
651704ba839SBarry Smith     if (ilink->is) {ierr = ISDestroy(ilink->is);CHKERRQ(ierr);}
6525a9f2f41SSatish Balay     next = ilink->next;
653704ba839SBarry Smith     ierr = PetscFree(ilink->fields);CHKERRQ(ierr);
654704ba839SBarry Smith     ierr = PetscFree(ilink);CHKERRQ(ierr);
6555a9f2f41SSatish Balay     ilink = next;
6560971522cSBarry Smith   }
65705b42c5fSBarry Smith   ierr = PetscFree2(jac->x,jac->y);CHKERRQ(ierr);
658*519d70e2SJed Brown   if (jac->mat && jac->mat != jac->pmat) {ierr = MatDestroyMatrices(jac->nsplits,&jac->mat);CHKERRQ(ierr);}
65997bbdb24SBarry Smith   if (jac->pmat) {ierr = MatDestroyMatrices(jac->nsplits,&jac->pmat);CHKERRQ(ierr);}
66068dd23aaSBarry Smith   if (jac->Afield) {ierr = MatDestroyMatrices(jac->nsplits,&jac->Afield);CHKERRQ(ierr);}
66179416396SBarry Smith   if (jac->w1) {ierr = VecDestroy(jac->w1);CHKERRQ(ierr);}
66279416396SBarry Smith   if (jac->w2) {ierr = VecDestroy(jac->w2);CHKERRQ(ierr);}
6633b224e63SBarry Smith   if (jac->schur) {ierr = MatDestroy(jac->schur);CHKERRQ(ierr);}
664084e4875SJed Brown   if (jac->schur_user) {ierr = MatDestroy(jac->schur_user);CHKERRQ(ierr);}
665d0f46423SBarry Smith   if (jac->kspschur) {ierr = KSPDestroy(jac->kspschur);CHKERRQ(ierr);}
6663b224e63SBarry Smith   if (jac->B) {ierr = MatDestroy(jac->B);CHKERRQ(ierr);}
6673b224e63SBarry Smith   if (jac->C) {ierr = MatDestroy(jac->C);CHKERRQ(ierr);}
6680971522cSBarry Smith   ierr = PetscFree(jac);CHKERRQ(ierr);
6690971522cSBarry Smith   PetscFunctionReturn(0);
6700971522cSBarry Smith }
6710971522cSBarry Smith 
6720971522cSBarry Smith #undef __FUNCT__
6730971522cSBarry Smith #define __FUNCT__ "PCSetFromOptions_FieldSplit"
6740971522cSBarry Smith static PetscErrorCode PCSetFromOptions_FieldSplit(PC pc)
6750971522cSBarry Smith {
6761b9fc7fcSBarry Smith   PetscErrorCode  ierr;
67751f519a2SBarry Smith   PetscInt        i = 0,nfields,*fields,bs;
678084e4875SJed Brown   PetscTruth      flg;
6791b9fc7fcSBarry Smith   char            optionname[128];
6809dcbbd2bSBarry Smith   PC_FieldSplit   *jac = (PC_FieldSplit*)pc->data;
6813b224e63SBarry Smith   PCCompositeType ctype;
6821b9fc7fcSBarry Smith 
6830971522cSBarry Smith   PetscFunctionBegin;
6841b9fc7fcSBarry Smith   ierr = PetscOptionsHead("FieldSplit options");CHKERRQ(ierr);
685*519d70e2SJed Brown   ierr = PetscOptionsTruth("-pc_fieldsplit_real_diagonal","Use diagonal blocks of the operator","PCFieldSplitSetRealDiagonal",jac->realdiagonal,&jac->realdiagonal,PETSC_NULL);CHKERRQ(ierr);
68651f519a2SBarry Smith   ierr = PetscOptionsInt("-pc_fieldsplit_block_size","Blocksize that defines number of fields","PCFieldSplitSetBlockSize",jac->bs,&bs,&flg);CHKERRQ(ierr);
68751f519a2SBarry Smith   if (flg) {
68851f519a2SBarry Smith     ierr = PCFieldSplitSetBlockSize(pc,bs);CHKERRQ(ierr);
68951f519a2SBarry Smith   }
690704ba839SBarry Smith 
6913b224e63SBarry Smith   ierr = PetscOptionsEnum("-pc_fieldsplit_type","Type of composition","PCFieldSplitSetType",PCCompositeTypes,(PetscEnum)jac->type,(PetscEnum*)&ctype,&flg);CHKERRQ(ierr);
6923b224e63SBarry Smith   if (flg) {
6933b224e63SBarry Smith     ierr = PCFieldSplitSetType(pc,ctype);CHKERRQ(ierr);
6943b224e63SBarry Smith   }
695d32f9abdSBarry Smith 
696c30613efSMatthew Knepley   /* Only setup fields once */
697c30613efSMatthew Knepley   if ((jac->bs > 0) && (jac->nsplits == 0)) {
698d32f9abdSBarry Smith     /* only allow user to set fields from command line if bs is already known.
699d32f9abdSBarry Smith        otherwise user can set them in PCFieldSplitSetDefaults() */
70051f519a2SBarry Smith     ierr = PetscMalloc(jac->bs*sizeof(PetscInt),&fields);CHKERRQ(ierr);
7011b9fc7fcSBarry Smith     while (PETSC_TRUE) {
70213f74950SBarry Smith       sprintf(optionname,"-pc_fieldsplit_%d_fields",(int)i++);
70351f519a2SBarry Smith       nfields = jac->bs;
7041b9fc7fcSBarry Smith       ierr    = PetscOptionsIntArray(optionname,"Fields in this split","PCFieldSplitSetFields",fields,&nfields,&flg);CHKERRQ(ierr);
7051b9fc7fcSBarry Smith       if (!flg) break;
7061b9fc7fcSBarry Smith       if (!nfields) SETERRQ(PETSC_ERR_USER,"Cannot list zero fields");
7071b9fc7fcSBarry Smith       ierr = PCFieldSplitSetFields(pc,nfields,fields);CHKERRQ(ierr);
7081b9fc7fcSBarry Smith     }
70951f519a2SBarry Smith     ierr = PetscFree(fields);CHKERRQ(ierr);
710d32f9abdSBarry Smith   }
711084e4875SJed 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);
7121b9fc7fcSBarry Smith   ierr = PetscOptionsTail();CHKERRQ(ierr);
7130971522cSBarry Smith   PetscFunctionReturn(0);
7140971522cSBarry Smith }
7150971522cSBarry Smith 
7160971522cSBarry Smith /*------------------------------------------------------------------------------------*/
7170971522cSBarry Smith 
7180971522cSBarry Smith EXTERN_C_BEGIN
7190971522cSBarry Smith #undef __FUNCT__
7200971522cSBarry Smith #define __FUNCT__ "PCFieldSplitSetFields_FieldSplit"
721dba47a55SKris Buschelman PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitSetFields_FieldSplit(PC pc,PetscInt n,PetscInt *fields)
7220971522cSBarry Smith {
72397bbdb24SBarry Smith   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
7240971522cSBarry Smith   PetscErrorCode    ierr;
7255a9f2f41SSatish Balay   PC_FieldSplitLink ilink,next = jac->head;
72669a612a9SBarry Smith   char              prefix[128];
72751f519a2SBarry Smith   PetscInt          i;
7280971522cSBarry Smith 
7290971522cSBarry Smith   PetscFunctionBegin;
7300971522cSBarry Smith   if (n <= 0) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Negative number of fields requested");
73151f519a2SBarry Smith   for (i=0; i<n; i++) {
73251f519a2SBarry Smith     if (fields[i] >= jac->bs) SETERRQ2(PETSC_ERR_ARG_OUTOFRANGE,"Field %D requested but only %D exist",fields[i],jac->bs);
73351f519a2SBarry Smith     if (fields[i] < 0) SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"Negative field %D requested",fields[i]);
73451f519a2SBarry Smith   }
735704ba839SBarry Smith   ierr = PetscNew(struct _PC_FieldSplitLink,&ilink);CHKERRQ(ierr);
736704ba839SBarry Smith   ierr = PetscMalloc(n*sizeof(PetscInt),&ilink->fields);CHKERRQ(ierr);
7375a9f2f41SSatish Balay   ierr = PetscMemcpy(ilink->fields,fields,n*sizeof(PetscInt));CHKERRQ(ierr);
7385a9f2f41SSatish Balay   ilink->nfields = n;
7395a9f2f41SSatish Balay   ilink->next    = PETSC_NULL;
7407adad957SLisandro Dalcin   ierr           = KSPCreate(((PetscObject)pc)->comm,&ilink->ksp);CHKERRQ(ierr);
7411cee3971SBarry Smith   ierr           = PetscObjectIncrementTabLevel((PetscObject)ilink->ksp,(PetscObject)pc,1);CHKERRQ(ierr);
7425a9f2f41SSatish Balay   ierr           = KSPSetType(ilink->ksp,KSPPREONLY);CHKERRQ(ierr);
74369a612a9SBarry Smith 
7447adad957SLisandro Dalcin   if (((PetscObject)pc)->prefix) {
7457adad957SLisandro Dalcin     sprintf(prefix,"%sfieldsplit_%d_",((PetscObject)pc)->prefix,(int)jac->nsplits);
74669a612a9SBarry Smith   } else {
74713f74950SBarry Smith     sprintf(prefix,"fieldsplit_%d_",(int)jac->nsplits);
74869a612a9SBarry Smith   }
7495a9f2f41SSatish Balay   ierr = KSPSetOptionsPrefix(ilink->ksp,prefix);CHKERRQ(ierr);
7500971522cSBarry Smith 
7510971522cSBarry Smith   if (!next) {
7525a9f2f41SSatish Balay     jac->head       = ilink;
75351f519a2SBarry Smith     ilink->previous = PETSC_NULL;
7540971522cSBarry Smith   } else {
7550971522cSBarry Smith     while (next->next) {
7560971522cSBarry Smith       next = next->next;
7570971522cSBarry Smith     }
7585a9f2f41SSatish Balay     next->next      = ilink;
75951f519a2SBarry Smith     ilink->previous = next;
7600971522cSBarry Smith   }
7610971522cSBarry Smith   jac->nsplits++;
7620971522cSBarry Smith   PetscFunctionReturn(0);
7630971522cSBarry Smith }
7640971522cSBarry Smith EXTERN_C_END
7650971522cSBarry Smith 
766e69d4d44SBarry Smith EXTERN_C_BEGIN
767e69d4d44SBarry Smith #undef __FUNCT__
768e69d4d44SBarry Smith #define __FUNCT__ "PCFieldSplitGetSubKSP_FieldSplit_Schur"
769e69d4d44SBarry Smith PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitGetSubKSP_FieldSplit_Schur(PC pc,PetscInt *n,KSP **subksp)
770e69d4d44SBarry Smith {
771e69d4d44SBarry Smith   PC_FieldSplit *jac = (PC_FieldSplit*)pc->data;
772e69d4d44SBarry Smith   PetscErrorCode ierr;
773e69d4d44SBarry Smith 
774e69d4d44SBarry Smith   PetscFunctionBegin;
775*519d70e2SJed Brown   ierr = PetscMalloc(jac->nsplits*sizeof(KSP),subksp);CHKERRQ(ierr);
776e69d4d44SBarry Smith   ierr = MatSchurComplementGetKSP(jac->schur,*subksp);CHKERRQ(ierr);
777e69d4d44SBarry Smith   (*subksp)[1] = jac->kspschur;
778084e4875SJed Brown   *n = jac->nsplits;
779e69d4d44SBarry Smith   PetscFunctionReturn(0);
780e69d4d44SBarry Smith }
781e69d4d44SBarry Smith EXTERN_C_END
7820971522cSBarry Smith 
7830971522cSBarry Smith EXTERN_C_BEGIN
7840971522cSBarry Smith #undef __FUNCT__
78569a612a9SBarry Smith #define __FUNCT__ "PCFieldSplitGetSubKSP_FieldSplit"
786dba47a55SKris Buschelman PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitGetSubKSP_FieldSplit(PC pc,PetscInt *n,KSP **subksp)
7870971522cSBarry Smith {
7880971522cSBarry Smith   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
7890971522cSBarry Smith   PetscErrorCode    ierr;
7900971522cSBarry Smith   PetscInt          cnt = 0;
7915a9f2f41SSatish Balay   PC_FieldSplitLink ilink = jac->head;
7920971522cSBarry Smith 
7930971522cSBarry Smith   PetscFunctionBegin;
79469a612a9SBarry Smith   ierr = PetscMalloc(jac->nsplits*sizeof(KSP*),subksp);CHKERRQ(ierr);
7955a9f2f41SSatish Balay   while (ilink) {
7965a9f2f41SSatish Balay     (*subksp)[cnt++] = ilink->ksp;
7975a9f2f41SSatish Balay     ilink = ilink->next;
7980971522cSBarry Smith   }
7990971522cSBarry Smith   if (cnt != jac->nsplits) SETERRQ2(PETSC_ERR_PLIB,"Corrupt PCFIELDSPLIT object: number splits in linked list %D in object %D",cnt,jac->nsplits);
8000971522cSBarry Smith   *n = jac->nsplits;
8010971522cSBarry Smith   PetscFunctionReturn(0);
8020971522cSBarry Smith }
8030971522cSBarry Smith EXTERN_C_END
8040971522cSBarry Smith 
805704ba839SBarry Smith EXTERN_C_BEGIN
806704ba839SBarry Smith #undef __FUNCT__
807704ba839SBarry Smith #define __FUNCT__ "PCFieldSplitSetIS_FieldSplit"
808704ba839SBarry Smith PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitSetIS_FieldSplit(PC pc,IS is)
809704ba839SBarry Smith {
810704ba839SBarry Smith   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
811704ba839SBarry Smith   PetscErrorCode    ierr;
812704ba839SBarry Smith   PC_FieldSplitLink ilink, next = jac->head;
813704ba839SBarry Smith   char              prefix[128];
814704ba839SBarry Smith 
815704ba839SBarry Smith   PetscFunctionBegin;
81616913363SBarry Smith   ierr = PetscNew(struct _PC_FieldSplitLink,&ilink);CHKERRQ(ierr);
8171ab39975SBarry Smith   ilink->is      = is;
8181ab39975SBarry Smith   ierr           = PetscObjectReference((PetscObject)is);CHKERRQ(ierr);
819704ba839SBarry Smith   ilink->next    = PETSC_NULL;
820704ba839SBarry Smith   ierr           = KSPCreate(((PetscObject)pc)->comm,&ilink->ksp);CHKERRQ(ierr);
8211cee3971SBarry Smith   ierr           = PetscObjectIncrementTabLevel((PetscObject)ilink->ksp,(PetscObject)pc,1);CHKERRQ(ierr);
822704ba839SBarry Smith   ierr           = KSPSetType(ilink->ksp,KSPPREONLY);CHKERRQ(ierr);
823704ba839SBarry Smith 
824704ba839SBarry Smith   if (((PetscObject)pc)->prefix) {
825704ba839SBarry Smith     sprintf(prefix,"%sfieldsplit_%d_",((PetscObject)pc)->prefix,(int)jac->nsplits);
826704ba839SBarry Smith   } else {
827704ba839SBarry Smith     sprintf(prefix,"fieldsplit_%d_",(int)jac->nsplits);
828704ba839SBarry Smith   }
829704ba839SBarry Smith   ierr = KSPSetOptionsPrefix(ilink->ksp,prefix);CHKERRQ(ierr);
830704ba839SBarry Smith 
831704ba839SBarry Smith   if (!next) {
832704ba839SBarry Smith     jac->head       = ilink;
833704ba839SBarry Smith     ilink->previous = PETSC_NULL;
834704ba839SBarry Smith   } else {
835704ba839SBarry Smith     while (next->next) {
836704ba839SBarry Smith       next = next->next;
837704ba839SBarry Smith     }
838704ba839SBarry Smith     next->next      = ilink;
839704ba839SBarry Smith     ilink->previous = next;
840704ba839SBarry Smith   }
841704ba839SBarry Smith   jac->nsplits++;
842704ba839SBarry Smith 
843704ba839SBarry Smith   PetscFunctionReturn(0);
844704ba839SBarry Smith }
845704ba839SBarry Smith EXTERN_C_END
846704ba839SBarry Smith 
8470971522cSBarry Smith #undef __FUNCT__
8480971522cSBarry Smith #define __FUNCT__ "PCFieldSplitSetFields"
8490971522cSBarry Smith /*@
8500971522cSBarry Smith     PCFieldSplitSetFields - Sets the fields for one particular split in the field split preconditioner
8510971522cSBarry Smith 
8520971522cSBarry Smith     Collective on PC
8530971522cSBarry Smith 
8540971522cSBarry Smith     Input Parameters:
8550971522cSBarry Smith +   pc  - the preconditioner context
8560971522cSBarry Smith .   n - the number of fields in this split
8570971522cSBarry Smith .   fields - the fields in this split
8580971522cSBarry Smith 
8590971522cSBarry Smith     Level: intermediate
8600971522cSBarry Smith 
861d32f9abdSBarry Smith     Notes: Use PCFieldSplitSetIS() to set a completely general set of indices as a field.
862d32f9abdSBarry Smith 
863d32f9abdSBarry Smith      The PCFieldSplitSetFields() is for defining fields as a strided blocks. For example, if the block
864d32f9abdSBarry 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
865d32f9abdSBarry Smith      0xx3xx6xx9xx12 ... x1xx4xx7xx ... xx2xx5xx8xx.. 01x34x67x... 0x1x3x5x7.. x12x45x78x....
866d32f9abdSBarry Smith      where the numbered entries indicate what is in the field.
867d32f9abdSBarry Smith 
868d32f9abdSBarry Smith .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetBlockSize(), PCFieldSplitSetIS()
8690971522cSBarry Smith 
8700971522cSBarry Smith @*/
871dba47a55SKris Buschelman PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitSetFields(PC pc,PetscInt n, PetscInt *fields)
8720971522cSBarry Smith {
8730971522cSBarry Smith   PetscErrorCode ierr,(*f)(PC,PetscInt,PetscInt *);
8740971522cSBarry Smith 
8750971522cSBarry Smith   PetscFunctionBegin;
8760971522cSBarry Smith   PetscValidHeaderSpecific(pc,PC_COOKIE,1);
8770971522cSBarry Smith   ierr = PetscObjectQueryFunction((PetscObject)pc,"PCFieldSplitSetFields_C",(void (**)(void))&f);CHKERRQ(ierr);
8780971522cSBarry Smith   if (f) {
8790971522cSBarry Smith     ierr = (*f)(pc,n,fields);CHKERRQ(ierr);
8800971522cSBarry Smith   }
8810971522cSBarry Smith   PetscFunctionReturn(0);
8820971522cSBarry Smith }
8830971522cSBarry Smith 
8840971522cSBarry Smith #undef __FUNCT__
885704ba839SBarry Smith #define __FUNCT__ "PCFieldSplitSetIS"
886704ba839SBarry Smith /*@
887704ba839SBarry Smith     PCFieldSplitSetIS - Sets the exact elements for field
888704ba839SBarry Smith 
889704ba839SBarry Smith     Collective on PC
890704ba839SBarry Smith 
891704ba839SBarry Smith     Input Parameters:
892704ba839SBarry Smith +   pc  - the preconditioner context
893704ba839SBarry Smith .   is - the index set that defines the vector elements in this field
894704ba839SBarry Smith 
895d32f9abdSBarry Smith 
896d32f9abdSBarry Smith     Notes: Use PCFieldSplitSetFields(), for fields defined by strided types.
897d32f9abdSBarry Smith 
898704ba839SBarry Smith     Level: intermediate
899704ba839SBarry Smith 
900704ba839SBarry Smith .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetBlockSize()
901704ba839SBarry Smith 
902704ba839SBarry Smith @*/
903704ba839SBarry Smith PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitSetIS(PC pc,IS is)
904704ba839SBarry Smith {
905704ba839SBarry Smith   PetscErrorCode ierr,(*f)(PC,IS);
906704ba839SBarry Smith 
907704ba839SBarry Smith   PetscFunctionBegin;
908704ba839SBarry Smith   PetscValidHeaderSpecific(pc,PC_COOKIE,1);
909704ba839SBarry Smith   PetscValidHeaderSpecific(is,IS_COOKIE,1);
910704ba839SBarry Smith   ierr = PetscObjectQueryFunction((PetscObject)pc,"PCFieldSplitSetIS_C",(void (**)(void))&f);CHKERRQ(ierr);
911704ba839SBarry Smith   if (f) {
912704ba839SBarry Smith     ierr = (*f)(pc,is);CHKERRQ(ierr);
913704ba839SBarry Smith   }
914704ba839SBarry Smith   PetscFunctionReturn(0);
915704ba839SBarry Smith }
916704ba839SBarry Smith 
917704ba839SBarry Smith #undef __FUNCT__
91851f519a2SBarry Smith #define __FUNCT__ "PCFieldSplitSetBlockSize"
91951f519a2SBarry Smith /*@
92051f519a2SBarry Smith     PCFieldSplitSetBlockSize - Sets the block size for defining where fields start in the
92151f519a2SBarry Smith       fieldsplit preconditioner. If not set the matrix block size is used.
92251f519a2SBarry Smith 
92351f519a2SBarry Smith     Collective on PC
92451f519a2SBarry Smith 
92551f519a2SBarry Smith     Input Parameters:
92651f519a2SBarry Smith +   pc  - the preconditioner context
92751f519a2SBarry Smith -   bs - the block size
92851f519a2SBarry Smith 
92951f519a2SBarry Smith     Level: intermediate
93051f519a2SBarry Smith 
93151f519a2SBarry Smith .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetFields()
93251f519a2SBarry Smith 
93351f519a2SBarry Smith @*/
93451f519a2SBarry Smith PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitSetBlockSize(PC pc,PetscInt bs)
93551f519a2SBarry Smith {
93651f519a2SBarry Smith   PetscErrorCode ierr,(*f)(PC,PetscInt);
93751f519a2SBarry Smith 
93851f519a2SBarry Smith   PetscFunctionBegin;
93951f519a2SBarry Smith   PetscValidHeaderSpecific(pc,PC_COOKIE,1);
94051f519a2SBarry Smith   ierr = PetscObjectQueryFunction((PetscObject)pc,"PCFieldSplitSetBlockSize_C",(void (**)(void))&f);CHKERRQ(ierr);
94151f519a2SBarry Smith   if (f) {
94251f519a2SBarry Smith     ierr = (*f)(pc,bs);CHKERRQ(ierr);
94351f519a2SBarry Smith   }
94451f519a2SBarry Smith   PetscFunctionReturn(0);
94551f519a2SBarry Smith }
94651f519a2SBarry Smith 
94751f519a2SBarry Smith #undef __FUNCT__
94869a612a9SBarry Smith #define __FUNCT__ "PCFieldSplitGetSubKSP"
9490971522cSBarry Smith /*@C
95069a612a9SBarry Smith    PCFieldSplitGetSubKSP - Gets the KSP contexts for all splits
9510971522cSBarry Smith 
95269a612a9SBarry Smith    Collective on KSP
9530971522cSBarry Smith 
9540971522cSBarry Smith    Input Parameter:
9550971522cSBarry Smith .  pc - the preconditioner context
9560971522cSBarry Smith 
9570971522cSBarry Smith    Output Parameters:
9580971522cSBarry Smith +  n - the number of split
95969a612a9SBarry Smith -  pc - the array of KSP contexts
9600971522cSBarry Smith 
9610971522cSBarry Smith    Note:
962d32f9abdSBarry Smith    After PCFieldSplitGetSubKSP() the array of KSPs IS to be freed by the user
963d32f9abdSBarry Smith    (not the KSP just the array that contains them).
9640971522cSBarry Smith 
96569a612a9SBarry Smith    You must call KSPSetUp() before calling PCFieldSplitGetSubKSP().
9660971522cSBarry Smith 
9670971522cSBarry Smith    Level: advanced
9680971522cSBarry Smith 
9690971522cSBarry Smith .seealso: PCFIELDSPLIT
9700971522cSBarry Smith @*/
971dba47a55SKris Buschelman PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitGetSubKSP(PC pc,PetscInt *n,KSP *subksp[])
9720971522cSBarry Smith {
97369a612a9SBarry Smith   PetscErrorCode ierr,(*f)(PC,PetscInt*,KSP **);
9740971522cSBarry Smith 
9750971522cSBarry Smith   PetscFunctionBegin;
9760971522cSBarry Smith   PetscValidHeaderSpecific(pc,PC_COOKIE,1);
9770971522cSBarry Smith   PetscValidIntPointer(n,2);
97869a612a9SBarry Smith   ierr = PetscObjectQueryFunction((PetscObject)pc,"PCFieldSplitGetSubKSP_C",(void (**)(void))&f);CHKERRQ(ierr);
9790971522cSBarry Smith   if (f) {
98069a612a9SBarry Smith     ierr = (*f)(pc,n,subksp);CHKERRQ(ierr);
9810971522cSBarry Smith   } else {
98269a612a9SBarry Smith     SETERRQ(PETSC_ERR_ARG_WRONG,"Cannot get subksp for this type of PC");
9830971522cSBarry Smith   }
9840971522cSBarry Smith   PetscFunctionReturn(0);
9850971522cSBarry Smith }
9860971522cSBarry Smith 
987e69d4d44SBarry Smith #undef __FUNCT__
988e69d4d44SBarry Smith #define __FUNCT__ "PCFieldSplitSchurPrecondition"
989e69d4d44SBarry Smith /*@
990e69d4d44SBarry Smith     PCFieldSplitSchurPrecondition -  Indicates if the Schur complement is preconditioned by a preconditioner constructed by the
991e69d4d44SBarry Smith       D matrix. Otherwise no preconditioner is used.
992e69d4d44SBarry Smith 
993e69d4d44SBarry Smith     Collective on PC
994e69d4d44SBarry Smith 
995e69d4d44SBarry Smith     Input Parameters:
996e69d4d44SBarry Smith +   pc  - the preconditioner context
997084e4875SJed Brown .   ptype - which matrix to use for preconditioning the Schur complement
998084e4875SJed Brown -   userpre - matrix to use for preconditioning, or PETSC_NULL
999084e4875SJed Brown 
1000084e4875SJed Brown     Notes:
1001084e4875SJed Brown     The default is to use the block on the diagonal of the preconditioning matrix.  This is D, in the (1,1) position.
1002084e4875SJed Brown     There are currently no preconditioners that work directly with the Schur complement so setting
1003084e4875SJed Brown     PC_FIELDSPLIT_SCHUR_PRE_SELF is observationally equivalent to -fieldsplit_1_pc_type none.
1004e69d4d44SBarry Smith 
1005e69d4d44SBarry Smith     Options Database:
1006084e4875SJed Brown .     -pc_fieldsplit_schur_precondition <self,user,diag> default is diag
1007e69d4d44SBarry Smith 
1008e69d4d44SBarry Smith     Level: intermediate
1009e69d4d44SBarry Smith 
1010084e4875SJed Brown .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetFields(), PCFieldSplitSchurPreType
1011e69d4d44SBarry Smith 
1012e69d4d44SBarry Smith @*/
1013084e4875SJed Brown PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitSchurPrecondition(PC pc,PCFieldSplitSchurPreType ptype,Mat pre)
1014e69d4d44SBarry Smith {
1015084e4875SJed Brown   PetscErrorCode ierr,(*f)(PC,PCFieldSplitSchurPreType,Mat);
1016e69d4d44SBarry Smith 
1017e69d4d44SBarry Smith   PetscFunctionBegin;
1018e69d4d44SBarry Smith   PetscValidHeaderSpecific(pc,PC_COOKIE,1);
1019e69d4d44SBarry Smith   ierr = PetscObjectQueryFunction((PetscObject)pc,"PCFieldSplitSchurPrecondition_C",(void (**)(void))&f);CHKERRQ(ierr);
1020e69d4d44SBarry Smith   if (f) {
1021084e4875SJed Brown     ierr = (*f)(pc,ptype,pre);CHKERRQ(ierr);
1022e69d4d44SBarry Smith   }
1023e69d4d44SBarry Smith   PetscFunctionReturn(0);
1024e69d4d44SBarry Smith }
1025e69d4d44SBarry Smith 
1026e69d4d44SBarry Smith EXTERN_C_BEGIN
1027e69d4d44SBarry Smith #undef __FUNCT__
1028e69d4d44SBarry Smith #define __FUNCT__ "PCFieldSplitSchurPrecondition_FieldSplit"
1029084e4875SJed Brown PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitSchurPrecondition_FieldSplit(PC pc,PCFieldSplitSchurPreType ptype,Mat pre)
1030e69d4d44SBarry Smith {
1031e69d4d44SBarry Smith   PC_FieldSplit  *jac = (PC_FieldSplit*)pc->data;
1032084e4875SJed Brown   PetscErrorCode  ierr;
1033e69d4d44SBarry Smith 
1034e69d4d44SBarry Smith   PetscFunctionBegin;
1035084e4875SJed Brown   jac->schurpre = ptype;
1036084e4875SJed Brown   if (pre) {
1037084e4875SJed Brown     if (jac->schur_user) {ierr = MatDestroy(jac->schur_user);CHKERRQ(ierr);}
1038084e4875SJed Brown     jac->schur_user = pre;
1039084e4875SJed Brown     ierr = PetscObjectReference((PetscObject)jac->schur_user);CHKERRQ(ierr);
1040084e4875SJed Brown   }
1041e69d4d44SBarry Smith   PetscFunctionReturn(0);
1042e69d4d44SBarry Smith }
1043e69d4d44SBarry Smith EXTERN_C_END
1044e69d4d44SBarry Smith 
104530ad9308SMatthew Knepley #undef __FUNCT__
104630ad9308SMatthew Knepley #define __FUNCT__ "PCFieldSplitGetSchurBlocks"
104730ad9308SMatthew Knepley /*@C
104830ad9308SMatthew Knepley    PCFieldSplitGetSchurBlocks - Gets the all matrix blocks for the Schur complement
104930ad9308SMatthew Knepley 
105030ad9308SMatthew Knepley    Collective on KSP
105130ad9308SMatthew Knepley 
105230ad9308SMatthew Knepley    Input Parameter:
105330ad9308SMatthew Knepley .  pc - the preconditioner context
105430ad9308SMatthew Knepley 
105530ad9308SMatthew Knepley    Output Parameters:
105630ad9308SMatthew Knepley +  A - the (0,0) block
105730ad9308SMatthew Knepley .  B - the (0,1) block
105830ad9308SMatthew Knepley .  C - the (1,0) block
105930ad9308SMatthew Knepley -  D - the (1,1) block
106030ad9308SMatthew Knepley 
106130ad9308SMatthew Knepley    Level: advanced
106230ad9308SMatthew Knepley 
106330ad9308SMatthew Knepley .seealso: PCFIELDSPLIT
106430ad9308SMatthew Knepley @*/
106530ad9308SMatthew Knepley PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitGetSchurBlocks(PC pc,Mat *A,Mat *B,Mat *C, Mat *D)
106630ad9308SMatthew Knepley {
106730ad9308SMatthew Knepley   PC_FieldSplit *jac = (PC_FieldSplit *) pc->data;
106830ad9308SMatthew Knepley 
106930ad9308SMatthew Knepley   PetscFunctionBegin;
107030ad9308SMatthew Knepley   PetscValidHeaderSpecific(pc,PC_COOKIE,1);
1071cf8ad460SMatthew Knepley   if (jac->type != PC_COMPOSITE_SCHUR) {SETERRQ(PETSC_ERR_ARG_WRONG, "FieldSplit is not using a Schur complement approach.");}
107230ad9308SMatthew Knepley   if (A) *A = jac->pmat[0];
107330ad9308SMatthew Knepley   if (B) *B = jac->B;
107430ad9308SMatthew Knepley   if (C) *C = jac->C;
107530ad9308SMatthew Knepley   if (D) *D = jac->pmat[1];
107630ad9308SMatthew Knepley   PetscFunctionReturn(0);
107730ad9308SMatthew Knepley }
107830ad9308SMatthew Knepley 
107979416396SBarry Smith EXTERN_C_BEGIN
108079416396SBarry Smith #undef __FUNCT__
108179416396SBarry Smith #define __FUNCT__ "PCFieldSplitSetType_FieldSplit"
1082dba47a55SKris Buschelman PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitSetType_FieldSplit(PC pc,PCCompositeType type)
108379416396SBarry Smith {
108479416396SBarry Smith   PC_FieldSplit  *jac = (PC_FieldSplit*)pc->data;
1085e69d4d44SBarry Smith   PetscErrorCode ierr;
108679416396SBarry Smith 
108779416396SBarry Smith   PetscFunctionBegin;
108879416396SBarry Smith   jac->type = type;
10893b224e63SBarry Smith   if (type == PC_COMPOSITE_SCHUR) {
10903b224e63SBarry Smith     pc->ops->apply = PCApply_FieldSplit_Schur;
10913b224e63SBarry Smith     pc->ops->view  = PCView_FieldSplit_Schur;
1092e69d4d44SBarry Smith     ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitGetSubKSP_C","PCFieldSplitGetSubKSP_FieldSplit_Schur",PCFieldSplitGetSubKSP_FieldSplit_Schur);CHKERRQ(ierr);
1093e69d4d44SBarry Smith     ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSchurPrecondition_C","PCFieldSplitSchurPrecondition_FieldSplit",PCFieldSplitSchurPrecondition_FieldSplit);CHKERRQ(ierr);
1094e69d4d44SBarry Smith 
10953b224e63SBarry Smith   } else {
10963b224e63SBarry Smith     pc->ops->apply = PCApply_FieldSplit;
10973b224e63SBarry Smith     pc->ops->view  = PCView_FieldSplit;
1098e69d4d44SBarry Smith     ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitGetSubKSP_C","PCFieldSplitGetSubKSP_FieldSplit",PCFieldSplitGetSubKSP_FieldSplit);CHKERRQ(ierr);
10999e7d6b0aSBarry Smith     ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSchurPrecondition_C","",0);CHKERRQ(ierr);
11003b224e63SBarry Smith   }
110179416396SBarry Smith   PetscFunctionReturn(0);
110279416396SBarry Smith }
110379416396SBarry Smith EXTERN_C_END
110479416396SBarry Smith 
110551f519a2SBarry Smith EXTERN_C_BEGIN
110651f519a2SBarry Smith #undef __FUNCT__
110751f519a2SBarry Smith #define __FUNCT__ "PCFieldSplitSetBlockSize_FieldSplit"
110851f519a2SBarry Smith PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitSetBlockSize_FieldSplit(PC pc,PetscInt bs)
110951f519a2SBarry Smith {
111051f519a2SBarry Smith   PC_FieldSplit  *jac = (PC_FieldSplit*)pc->data;
111151f519a2SBarry Smith 
111251f519a2SBarry Smith   PetscFunctionBegin;
111351f519a2SBarry Smith   if (bs < 1) SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"Blocksize must be positive, you gave %D",bs);
111451f519a2SBarry Smith   if (jac->bs > 0 && jac->bs != bs) SETERRQ2(PETSC_ERR_ARG_WRONGSTATE,"Cannot change fieldsplit blocksize from %D to %D after it has been set",jac->bs,bs);
111551f519a2SBarry Smith   jac->bs = bs;
111651f519a2SBarry Smith   PetscFunctionReturn(0);
111751f519a2SBarry Smith }
111851f519a2SBarry Smith EXTERN_C_END
111951f519a2SBarry Smith 
112079416396SBarry Smith #undef __FUNCT__
112179416396SBarry Smith #define __FUNCT__ "PCFieldSplitSetType"
1122bc08b0f1SBarry Smith /*@
112379416396SBarry Smith    PCFieldSplitSetType - Sets the type of fieldsplit preconditioner.
112479416396SBarry Smith 
112579416396SBarry Smith    Collective on PC
112679416396SBarry Smith 
112779416396SBarry Smith    Input Parameter:
112879416396SBarry Smith .  pc - the preconditioner context
112981540f2fSBarry Smith .  type - PC_COMPOSITE_ADDITIVE, PC_COMPOSITE_MULTIPLICATIVE (default), PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE, PC_COMPOSITE_SPECIAL, PC_COMPOSITE_SCHUR
113079416396SBarry Smith 
113179416396SBarry Smith    Options Database Key:
1132a4efd8eaSMatthew Knepley .  -pc_fieldsplit_type <type: one of multiplicative, additive, symmetric_multiplicative, special, schur> - Sets fieldsplit preconditioner type
113379416396SBarry Smith 
113479416396SBarry Smith    Level: Developer
113579416396SBarry Smith 
113679416396SBarry Smith .keywords: PC, set, type, composite preconditioner, additive, multiplicative
113779416396SBarry Smith 
113879416396SBarry Smith .seealso: PCCompositeSetType()
113979416396SBarry Smith 
114079416396SBarry Smith @*/
1141dba47a55SKris Buschelman PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitSetType(PC pc,PCCompositeType type)
114279416396SBarry Smith {
114379416396SBarry Smith   PetscErrorCode ierr,(*f)(PC,PCCompositeType);
114479416396SBarry Smith 
114579416396SBarry Smith   PetscFunctionBegin;
114679416396SBarry Smith   PetscValidHeaderSpecific(pc,PC_COOKIE,1);
114779416396SBarry Smith   ierr = PetscObjectQueryFunction((PetscObject)pc,"PCFieldSplitSetType_C",(void (**)(void))&f);CHKERRQ(ierr);
114879416396SBarry Smith   if (f) {
114979416396SBarry Smith     ierr = (*f)(pc,type);CHKERRQ(ierr);
115079416396SBarry Smith   }
115179416396SBarry Smith   PetscFunctionReturn(0);
115279416396SBarry Smith }
115379416396SBarry Smith 
11540971522cSBarry Smith /* -------------------------------------------------------------------------------------*/
11550971522cSBarry Smith /*MC
1156a8c7a070SBarry Smith    PCFIELDSPLIT - Preconditioner created by combining separate preconditioners for individual
11570971522cSBarry Smith                   fields or groups of fields
11580971522cSBarry Smith 
11590971522cSBarry Smith 
1160edf189efSBarry Smith      To set options on the solvers for each block append -fieldsplit_ to all the PC
1161edf189efSBarry Smith         options database keys. For example, -fieldsplit_pc_type ilu -fieldsplit_pc_factor_levels 1
11620971522cSBarry Smith 
1163a8c7a070SBarry Smith      To set the options on the solvers separate for each block call PCFieldSplitGetSubKSP()
116469a612a9SBarry Smith          and set the options directly on the resulting KSP object
11650971522cSBarry Smith 
11660971522cSBarry Smith    Level: intermediate
11670971522cSBarry Smith 
116879416396SBarry Smith    Options Database Keys:
116981540f2fSBarry Smith +   -pc_fieldsplit_%d_fields <a,b,..> - indicates the fields to be used in the %d'th split
117081540f2fSBarry Smith .   -pc_fieldsplit_default - automatically add any fields to additional splits that have not
117181540f2fSBarry Smith                               been supplied explicitly by -pc_fieldsplit_%d_fields
117281540f2fSBarry Smith .   -pc_fieldsplit_block_size <bs> - size of block that defines fields (i.e. there are bs fields)
117381540f2fSBarry Smith .    -pc_fieldsplit_type <additive,multiplicative,schur,symmetric_multiplicative>
1174e69d4d44SBarry Smith .    -pc_fieldsplit_schur_precondition <true,false> default is true
117579416396SBarry Smith 
1176edf189efSBarry Smith -    Options prefix for inner solvers when using Schur complement preconditioner are -fieldsplit_0_ and -fieldsplit_1_
11773b224e63SBarry Smith      for all other solvers they are -fieldsplit_%d_ for the dth field, use -fieldsplit_ for all fields
11783b224e63SBarry Smith 
11793b224e63SBarry Smith 
1180d32f9abdSBarry Smith    Notes: use PCFieldSplitSetFields() to set fields defined by "strided" entries and PCFieldSplitSetIS()
1181d32f9abdSBarry Smith      to define a field by an arbitrary collection of entries.
1182d32f9abdSBarry Smith 
1183d32f9abdSBarry Smith       If no fields are set the default is used. The fields are defined by entries strided by bs,
1184d32f9abdSBarry Smith       beginning at 0 then 1, etc to bs-1. The block size can be set with PCFieldSplitSetBlockSize(),
1185d32f9abdSBarry Smith       if this is not called the block size defaults to the blocksize of the second matrix passed
1186d32f9abdSBarry Smith       to KSPSetOperators()/PCSetOperators().
1187d32f9abdSBarry Smith 
1188d32f9abdSBarry Smith       Currently for the multiplicative version, the updated residual needed for the next field
1189d32f9abdSBarry Smith      solve is computed via a matrix vector product over the entire array. An optimization would be
1190d32f9abdSBarry Smith      to update the residual only for the part of the right hand side associated with the next field
1191d32f9abdSBarry Smith      solve. (This would involve more MatGetSubMatrix() calls or some other mechanism to compute the
1192d32f9abdSBarry Smith      part of the matrix needed to just update part of the residual).
1193d32f9abdSBarry Smith 
1194e69d4d44SBarry Smith      For the Schur complement preconditioner if J = ( A B )
1195e69d4d44SBarry Smith                                                     ( C D )
1196e69d4d44SBarry Smith      the preconditioner is
1197e69d4d44SBarry Smith               (I   -B inv(A)) ( inv(A)   0    ) (I         0  )
1198e69d4d44SBarry Smith               (0    I       ) (   0    inv(S) ) (-C inv(A) I  )
1199edf189efSBarry Smith      where the action of inv(A) is applied using the KSP solver with prefix -fieldsplit_0_. The action of
1200e69d4d44SBarry Smith      inv(S) is computed using the KSP solver with prefix -schur_. For PCFieldSplitGetKSP() when field number is
1201edf189efSBarry Smith      0 it returns the KSP associated with -fieldsplit_0_ while field number 1 gives -fieldsplit_1_ KSP. By default
1202e69d4d44SBarry Smith      D is used to construct a preconditioner for S, use PCFieldSplitSchurPrecondition() to turn on or off this
1203e69d4d44SBarry Smith      option.
1204e69d4d44SBarry Smith 
1205edf189efSBarry Smith      If only one set of indices (one IS) is provided with PCFieldSplitSetIS() then the complement of that IS
1206edf189efSBarry Smith      is used automatically for a second block.
1207edf189efSBarry Smith 
1208a541d17aSBarry Smith    Concepts: physics based preconditioners, block preconditioners
12090971522cSBarry Smith 
1210a541d17aSBarry Smith .seealso:  PCCreate(), PCSetType(), PCType (for list of available types), PC, Block_Preconditioners
1211e69d4d44SBarry Smith            PCFieldSplitGetSubKSP(), PCFieldSplitSetFields(), PCFieldSplitSetType(), PCFieldSplitSetIS(), PCFieldSplitSchurPrecondition()
12120971522cSBarry Smith M*/
12130971522cSBarry Smith 
12140971522cSBarry Smith EXTERN_C_BEGIN
12150971522cSBarry Smith #undef __FUNCT__
12160971522cSBarry Smith #define __FUNCT__ "PCCreate_FieldSplit"
1217dba47a55SKris Buschelman PetscErrorCode PETSCKSP_DLLEXPORT PCCreate_FieldSplit(PC pc)
12180971522cSBarry Smith {
12190971522cSBarry Smith   PetscErrorCode ierr;
12200971522cSBarry Smith   PC_FieldSplit  *jac;
12210971522cSBarry Smith 
12220971522cSBarry Smith   PetscFunctionBegin;
122338f2d2fdSLisandro Dalcin   ierr = PetscNewLog(pc,PC_FieldSplit,&jac);CHKERRQ(ierr);
12240971522cSBarry Smith   jac->bs        = -1;
12250971522cSBarry Smith   jac->nsplits   = 0;
12263e197d65SBarry Smith   jac->type      = PC_COMPOSITE_MULTIPLICATIVE;
1227e6cab6aaSJed Brown   jac->schurpre  = PC_FIELDSPLIT_SCHUR_PRE_USER; /* Try user preconditioner first, fall back on diagonal */
122851f519a2SBarry Smith 
12290971522cSBarry Smith   pc->data     = (void*)jac;
12300971522cSBarry Smith 
12310971522cSBarry Smith   pc->ops->apply             = PCApply_FieldSplit;
1232421e10b8SBarry Smith   pc->ops->applytranspose    = PCApplyTranspose_FieldSplit;
12330971522cSBarry Smith   pc->ops->setup             = PCSetUp_FieldSplit;
12340971522cSBarry Smith   pc->ops->destroy           = PCDestroy_FieldSplit;
12350971522cSBarry Smith   pc->ops->setfromoptions    = PCSetFromOptions_FieldSplit;
12360971522cSBarry Smith   pc->ops->view              = PCView_FieldSplit;
12370971522cSBarry Smith   pc->ops->applyrichardson   = 0;
12380971522cSBarry Smith 
123969a612a9SBarry Smith   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitGetSubKSP_C","PCFieldSplitGetSubKSP_FieldSplit",
124069a612a9SBarry Smith                     PCFieldSplitGetSubKSP_FieldSplit);CHKERRQ(ierr);
12410971522cSBarry Smith   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetFields_C","PCFieldSplitSetFields_FieldSplit",
12420971522cSBarry Smith                     PCFieldSplitSetFields_FieldSplit);CHKERRQ(ierr);
1243704ba839SBarry Smith   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetIS_C","PCFieldSplitSetIS_FieldSplit",
1244704ba839SBarry Smith                     PCFieldSplitSetIS_FieldSplit);CHKERRQ(ierr);
124579416396SBarry Smith   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetType_C","PCFieldSplitSetType_FieldSplit",
124679416396SBarry Smith                     PCFieldSplitSetType_FieldSplit);CHKERRQ(ierr);
124751f519a2SBarry Smith   ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetBlockSize_C","PCFieldSplitSetBlockSize_FieldSplit",
124851f519a2SBarry Smith                     PCFieldSplitSetBlockSize_FieldSplit);CHKERRQ(ierr);
12490971522cSBarry Smith   PetscFunctionReturn(0);
12500971522cSBarry Smith }
12510971522cSBarry Smith EXTERN_C_END
12520971522cSBarry Smith 
12530971522cSBarry Smith 
1254a541d17aSBarry Smith /*MC
1255a541d17aSBarry Smith    Block_Preconditioners - PETSc provides support for a variety of "block preconditioners", this provides an
1256a541d17aSBarry Smith           overview of these methods.
1257a541d17aSBarry Smith 
1258a541d17aSBarry Smith       Consider the solution to ( A B ) (x_1)  =  (b_1)
1259a541d17aSBarry Smith                                ( C D ) (x_2)     (b_2)
1260a541d17aSBarry Smith 
1261a541d17aSBarry Smith       Important special cases, the Stokes equation: C = B' and D = 0  (A   B) (x_1) = (b_1)
1262a541d17aSBarry Smith                                                                        B'  0) (x_2)   (b_2)
1263a541d17aSBarry Smith 
1264a541d17aSBarry Smith       One of the goals of the PCFieldSplit preconditioner in PETSc is to provide a variety of preconditioners
1265a541d17aSBarry Smith       for this block system.
1266a541d17aSBarry Smith 
1267a541d17aSBarry Smith       Consider an additional matrix (Ap  Bp)
1268a541d17aSBarry Smith                                     (Cp  Dp) where some or all of the entries may be the same as
1269a541d17aSBarry Smith       in the original matrix (for example Ap == A).
1270a541d17aSBarry Smith 
1271a541d17aSBarry Smith       In the following, A^ denotes the approximate application of the inverse of A, possibly using Ap in the
1272a541d17aSBarry Smith       approximation. In PETSc this simply means one has called KSPSetOperators(ksp,A,Ap,...) or KSPSetOperators(ksp,Ap,Ap,...)
1273a541d17aSBarry Smith 
1274a541d17aSBarry Smith       Block Jacobi:   x_1 = A^ b_1
1275a541d17aSBarry Smith                       x_2 = D^ b_2
1276a541d17aSBarry Smith 
1277a541d17aSBarry Smith       Lower block Gauss-Seidel:   x_1 = A^ b_1
1278a541d17aSBarry Smith                             x_2 = D^ (b_2 - C x_1)       variant x_2 = D^ (b_2 - Cp x_1)
1279a541d17aSBarry Smith 
1280a541d17aSBarry 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)
1281a541d17aSBarry Smith           Interestingly this form is not actually a symmetric matrix, the symmetric version is
1282a541d17aSBarry Smith                               x_1 = A^(b_1 - B x_2)      variant x_1 = A^(b_1 - Bp x_2)
1283a541d17aSBarry Smith 
12840bc0a719SBarry Smith    Level: intermediate
12850bc0a719SBarry Smith 
1286a541d17aSBarry Smith .seealso:  PCCreate(), PCSetType(), PCType (for list of available types), PC, PCFIELDSPLIT
1287a541d17aSBarry Smith            PCFieldSplitGetSubKSP(), PCFieldSplitSetFields(), PCFieldSplitSetType(), PCFieldSplitSetIS(), PCFieldSplitSchurPrecondition()
1288a541d17aSBarry Smith M*/
1289