Actual source code: fieldsplit.c

  1: #define PETSCKSP_DLL

  3: /*

  5: */
 6:  #include private/pcimpl.h

  8: typedef struct _PC_FieldSplitLink *PC_FieldSplitLink;
  9: struct _PC_FieldSplitLink {
 10:   KSP               ksp;
 11:   Vec               x,y;
 12:   PetscInt          nfields;
 13:   PetscInt          *fields;
 14:   VecScatter        sctx;
 15:   PC_FieldSplitLink next;
 16: };

 18: typedef struct {
 19:   PCCompositeType   type;              /* additive or multiplicative */
 20:   PetscTruth        defaultsplit;
 21:   PetscInt          bs;
 22:   PetscInt          nsplits,*csize;
 23:   Vec               *x,*y,w1,w2;
 24:   Mat               *pmat;
 25:   IS                *is,*cis;
 26:   PC_FieldSplitLink head;
 27: } PC_FieldSplit;

 31: static PetscErrorCode PCView_FieldSplit(PC pc,PetscViewer viewer)
 32: {
 33:   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
 34:   PetscErrorCode    ierr;
 35:   PetscTruth        iascii;
 36:   PetscInt          i,j;
 37:   PC_FieldSplitLink ilink = jac->head;

 40:   PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&iascii);
 41:   if (iascii) {
 42:     PetscViewerASCIIPrintf(viewer,"  FieldSplit with %s composition: total splits = %D\n",PCCompositeTypes[jac->type],jac->nsplits);
 43:     PetscViewerASCIIPrintf(viewer,"  Solver info for each split is in the following KSP objects:\n");
 44:     PetscViewerASCIIPushTab(viewer);
 45:     for (i=0; i<jac->nsplits; i++) {
 46:       PetscViewerASCIIPrintf(viewer,"Split number %D Fields ",i);
 47:       PetscViewerASCIIUseTabs(viewer,PETSC_FALSE);
 48:       for (j=0; j<ilink->nfields; j++) {
 49:         if (j > 0) {
 50:           PetscViewerASCIIPrintf(viewer,",");
 51:         }
 52:         PetscViewerASCIIPrintf(viewer," %D",ilink->fields[j]);
 53:       }
 54:       PetscViewerASCIIPrintf(viewer,"\n");
 55:       PetscViewerASCIIUseTabs(viewer,PETSC_TRUE);
 56:       KSPView(ilink->ksp,viewer);
 57:       ilink = ilink->next;
 58:     }
 59:     PetscViewerASCIIPopTab(viewer);
 60:   } else {
 61:     SETERRQ1(PETSC_ERR_SUP,"Viewer type %s not supported for PCFieldSplit",((PetscObject)viewer)->type_name);
 62:   }
 63:   return(0);
 64: }

 68: static PetscErrorCode PCFieldSplitSetDefaults(PC pc)
 69: {
 70:   PC_FieldSplit     *jac  = (PC_FieldSplit*)pc->data;
 71:   PetscErrorCode    ierr;
 72:   PC_FieldSplitLink ilink = jac->head;
 73:   PetscInt          i;
 74:   PetscTruth        flg = PETSC_FALSE,*fields;

 77:   PetscOptionsGetTruth(pc->prefix,"-pc_fieldsplit_default",&flg,PETSC_NULL);
 78:   if (!ilink || flg) {
 79:     PetscInfo(pc,"Using default splitting of fields\n");
 80:     if (jac->bs <= 0) {
 81:       MatGetBlockSize(pc->pmat,&jac->bs);
 82:     }
 83:     PetscMalloc(jac->bs*sizeof(PetscTruth),&fields);
 84:     PetscMemzero(fields,jac->bs*sizeof(PetscTruth));
 85:     while (ilink) {
 86:       for (i=0; i<ilink->nfields; i++) {
 87:         fields[ilink->fields[i]] = PETSC_TRUE;
 88:       }
 89:       ilink = ilink->next;
 90:     }
 91:     jac->defaultsplit = PETSC_TRUE;
 92:     for (i=0; i<jac->bs; i++) {
 93:       if (!fields[i]) {
 94:         PCFieldSplitSetFields(pc,1,&i);
 95:       } else {
 96:         jac->defaultsplit = PETSC_FALSE;
 97:       }
 98:     }
 99:   }
100:   return(0);
101: }


106: static PetscErrorCode PCSetUp_FieldSplit(PC pc)
107: {
108:   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
109:   PetscErrorCode    ierr;
110:   PC_FieldSplitLink ilink;
111:   PetscInt          i,nsplit,ccsize;
112:   MatStructure      flag = pc->flag;

115:   PCFieldSplitSetDefaults(pc);
116:   nsplit = jac->nsplits;
117:   ilink  = jac->head;

119:   /* get the matrices for each split */
120:   if (!jac->is) {
121:     PetscInt rstart,rend,nslots,bs;

123:     MatGetBlockSize(pc->pmat,&bs);
124:     MatGetOwnershipRange(pc->pmat,&rstart,&rend);
125:     MatGetLocalSize(pc->pmat,PETSC_NULL,&ccsize);
126:     nslots = (rend - rstart)/bs;
127:     PetscMalloc(nsplit*sizeof(IS),&jac->is);
128:     PetscMalloc(nsplit*sizeof(IS),&jac->cis);
129:     PetscMalloc(nsplit*sizeof(PetscInt),&jac->csize);
130:     for (i=0; i<nsplit; i++) {
131:       if (jac->defaultsplit) {
132:         ISCreateStride(pc->comm,nslots,rstart+i,nsplit,&jac->is[i]);
133:         if (bs != nsplit) SETERRQ2(PETSC_ERR_PLIB,"With default-split the number of fields %D must equal the matrix block size %D",nsplit,bs);
134:         jac->csize[i] = ccsize/nsplit;
135:       } else {
136:         PetscInt   *ii,j,k,nfields = ilink->nfields,*fields = ilink->fields;
137:         PetscTruth sorted;
138:         PetscMalloc(ilink->nfields*nslots*sizeof(PetscInt),&ii);
139:         for (j=0; j<nslots; j++) {
140:           for (k=0; k<nfields; k++) {
141:             ii[nfields*j + k] = rstart + bs*j + fields[k];
142:           }
143:         }
144:         ISCreateGeneral(pc->comm,nslots*nfields,ii,&jac->is[i]);
145:         jac->csize[i] = (ccsize/bs)*ilink->nfields;
146:         ISSorted(jac->is[i],&sorted);
147:         if (!sorted) SETERRQ(PETSC_ERR_USER,"Fields must be sorted when creating split");
148:         PetscFree(ii);
149:         ilink = ilink->next;
150:       }
151:       ISAllGather(jac->is[i],&jac->cis[i]);
152:     }
153:   }
154: 
155:   if (!jac->pmat) {
156:     PetscMalloc(nsplit*sizeof(Mat),&jac->pmat);
157:     for (i=0; i<nsplit; i++) {
158:       MatGetSubMatrix(pc->pmat,jac->is[i],jac->cis[i],jac->csize[i],MAT_INITIAL_MATRIX,&jac->pmat[i]);
159:     }
160:   } else {
161:     for (i=0; i<nsplit; i++) {
162:       MatGetSubMatrix(pc->pmat,jac->is[i],jac->cis[i],jac->csize[i],MAT_REUSE_MATRIX,&jac->pmat[i]);
163:     }
164:   }

166:   /* set up the individual PCs */
167:   i    = 0;
168:   ilink = jac->head;
169:   while (ilink) {
170:     KSPSetOperators(ilink->ksp,jac->pmat[i],jac->pmat[i],flag);
171:     KSPSetFromOptions(ilink->ksp);
172:     KSPSetUp(ilink->ksp);
173:     i++;
174:     ilink = ilink->next;
175:   }
176: 
177:   /* create work vectors for each split */
178:   if (!jac->x) {
179:     Vec xtmp;
180:     PetscMalloc2(nsplit,Vec,&jac->x,nsplit,Vec,&jac->y);
181:     ilink = jac->head;
182:     for (i=0; i<nsplit; i++) {
183:       Vec *vl,*vr;

185:       KSPGetVecs(ilink->ksp,1,&vr,1,&vl);
186:       ilink->x  = *vr;
187:       ilink->y  = *vl;
188:       PetscFree(vr);
189:       PetscFree(vl);
190:       jac->x[i] = ilink->x;
191:       jac->y[i] = ilink->y;
192:       ilink     = ilink->next;
193:     }
194:     /* compute scatter contexts needed by multiplicative versions and non-default splits */
195: 
196:     ilink = jac->head;
197:     MatGetVecs(pc->pmat,&xtmp,PETSC_NULL);
198:     for (i=0; i<nsplit; i++) {
199:       VecScatterCreate(xtmp,jac->is[i],jac->x[i],PETSC_NULL,&ilink->sctx);
200:       ilink = ilink->next;
201:     }
202:     VecDestroy(xtmp);
203:   }
204:   return(0);
205: }

207: #define FieldSplitSplitSolveAdd(ilink,xx,yy) \
208:     (VecScatterBegin(xx,ilink->x,INSERT_VALUES,SCATTER_FORWARD,ilink->sctx) || \
209:      VecScatterEnd(xx,ilink->x,INSERT_VALUES,SCATTER_FORWARD,ilink->sctx) || \
210:      KSPSolve(ilink->ksp,ilink->x,ilink->y) || \
211:      VecScatterBegin(ilink->y,yy,ADD_VALUES,SCATTER_REVERSE,ilink->sctx) || \
212:      VecScatterEnd(ilink->y,yy,ADD_VALUES,SCATTER_REVERSE,ilink->sctx))

216: static PetscErrorCode PCApply_FieldSplit(PC pc,Vec x,Vec y)
217: {
218:   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
219:   PetscErrorCode    ierr;
220:   PC_FieldSplitLink ilink = jac->head;
221:   PetscInt          bs;

224:   VecGetBlockSize(x,&bs);
225:   if (bs != jac->bs) {
226:     SETERRQ2(PETSC_ERR_ARG_SIZ,"Vector blocksize %D does not match Fieldsplit blocksize %D",bs,jac->bs);
227:   }
228:   if (jac->type == PC_COMPOSITE_ADDITIVE) {
229:     if (jac->defaultsplit) {
230:       VecStrideGatherAll(x,jac->x,INSERT_VALUES);
231:       while (ilink) {
232:         KSPSolve(ilink->ksp,ilink->x,ilink->y);
233:         ilink = ilink->next;
234:       }
235:       VecStrideScatterAll(jac->y,y,INSERT_VALUES);
236:     } else {
237:       PetscInt    i = 0;

239:       VecSet(y,0.0);
240:       while (ilink) {
241:         FieldSplitSplitSolveAdd(ilink,x,y);
242:         ilink = ilink->next;
243:         i++;
244:       }
245:     }
246:   } else {
247:     if (!jac->w1) {
248:       VecDuplicate(x,&jac->w1);
249:       VecDuplicate(x,&jac->w2);
250:     }
251:     VecSet(y,0.0);
252:     FieldSplitSplitSolveAdd(ilink,x,y);
253:     while (ilink->next) {
254:       ilink = ilink->next;
255:       MatMult(pc->pmat,y,jac->w1);
256:       VecWAXPY(jac->w2,-1.0,jac->w1,x);
257:       FieldSplitSplitSolveAdd(ilink,jac->w2,y);
258:     }
259:   }
260:   return(0);
261: }

265: static PetscErrorCode PCDestroy_FieldSplit(PC pc)
266: {
267:   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
268:   PetscErrorCode    ierr;
269:   PC_FieldSplitLink ilink = jac->head,next;

272:   while (ilink) {
273:     KSPDestroy(ilink->ksp);
274:     if (ilink->x) {VecDestroy(ilink->x);}
275:     if (ilink->y) {VecDestroy(ilink->y);}
276:     if (ilink->sctx) {VecScatterDestroy(ilink->sctx);}
277:     next = ilink->next;
278:     PetscFree2(ilink,ilink->fields);
279:     ilink = next;
280:   }
281:   PetscFree2(jac->x,jac->y);
282:   if (jac->pmat) {MatDestroyMatrices(jac->nsplits,&jac->pmat);}
283:   if (jac->is) {
284:     PetscInt i;
285:     for (i=0; i<jac->nsplits; i++) {ISDestroy(jac->is[i]);}
286:     PetscFree(jac->is);
287:   }
288:   if (jac->cis) {
289:     PetscInt i;
290:     for (i=0; i<jac->nsplits; i++) {ISDestroy(jac->cis[i]);}
291:     PetscFree(jac->cis);
292:   }
293:   if (jac->w1) {VecDestroy(jac->w1);}
294:   if (jac->w2) {VecDestroy(jac->w2);}
295:   PetscFree(jac->csize);
296:   PetscFree(jac);
297:   return(0);
298: }

302: static PetscErrorCode PCSetFromOptions_FieldSplit(PC pc)
303: {
305:   PetscInt       i = 0,nfields,fields[12];
306:   PetscTruth     flg;
307:   char           optionname[128];
308:   PC_FieldSplit  *jac = (PC_FieldSplit*)pc->data;

311:   PetscOptionsHead("FieldSplit options");
312:   PetscOptionsEnum("-pc_fieldsplit_type","Type of composition","PCFieldSplitSetType",PCCompositeTypes,(PetscEnum)jac->type,(PetscEnum*)&jac->type,&flg);
313:   while (PETSC_TRUE) {
314:     sprintf(optionname,"-pc_fieldsplit_%d_fields",(int)i++);
315:     nfields = 12;
316:     PetscOptionsIntArray(optionname,"Fields in this split","PCFieldSplitSetFields",fields,&nfields,&flg);
317:     if (!flg) break;
318:     if (!nfields) SETERRQ(PETSC_ERR_USER,"Cannot list zero fields");
319:     PCFieldSplitSetFields(pc,nfields,fields);
320:   }
321:   PetscOptionsTail();
322:   return(0);
323: }

325: /*------------------------------------------------------------------------------------*/

330: PetscErrorCode  PCFieldSplitSetFields_FieldSplit(PC pc,PetscInt n,PetscInt *fields)
331: {
332:   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
333:   PetscErrorCode    ierr;
334:   PC_FieldSplitLink ilink,next = jac->head;
335:   char              prefix[128];

338:   if (n <= 0) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Negative number of fields requested");
339:   PetscMalloc2(1,struct _PC_FieldSplitLink,&ilink,n,PetscInt,&ilink->fields);
340:   PetscMemcpy(ilink->fields,fields,n*sizeof(PetscInt));
341:   ilink->nfields = n;
342:   ilink->next    = PETSC_NULL;
343:   KSPCreate(pc->comm,&ilink->ksp);
344:   KSPSetType(ilink->ksp,KSPPREONLY);

346:   if (pc->prefix) {
347:     sprintf(prefix,"%sfieldsplit_%d_",pc->prefix,(int)jac->nsplits);
348:   } else {
349:     sprintf(prefix,"fieldsplit_%d_",(int)jac->nsplits);
350:   }
351:   KSPSetOptionsPrefix(ilink->ksp,prefix);

353:   if (!next) {
354:     jac->head = ilink;
355:   } else {
356:     while (next->next) {
357:       next = next->next;
358:     }
359:     next->next = ilink;
360:   }
361:   jac->nsplits++;
362:   return(0);
363: }


370: PetscErrorCode  PCFieldSplitGetSubKSP_FieldSplit(PC pc,PetscInt *n,KSP **subksp)
371: {
372:   PC_FieldSplit     *jac = (PC_FieldSplit*)pc->data;
373:   PetscErrorCode    ierr;
374:   PetscInt          cnt = 0;
375:   PC_FieldSplitLink ilink = jac->head;

378:   PetscMalloc(jac->nsplits*sizeof(KSP*),subksp);
379:   while (ilink) {
380:     (*subksp)[cnt++] = ilink->ksp;
381:     ilink = ilink->next;
382:   }
383:   if (cnt != jac->nsplits) SETERRQ2(PETSC_ERR_PLIB,"Corrupt PCFIELDSPLIT object: number splits in linked list %D in object %D",cnt,jac->nsplits);
384:   *n = jac->nsplits;
385:   return(0);
386: }

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

394:     Collective on PC

396:     Input Parameters:
397: +   pc  - the preconditioner context
398: .   n - the number of fields in this split
399: .   fields - the fields in this split

401:     Level: intermediate

403: .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT

405: @*/
406: PetscErrorCode  PCFieldSplitSetFields(PC pc,PetscInt n, PetscInt *fields)
407: {
408:   PetscErrorCode ierr,(*f)(PC,PetscInt,PetscInt *);

412:   PetscObjectQueryFunction((PetscObject)pc,"PCFieldSplitSetFields_C",(void (**)(void))&f);
413:   if (f) {
414:     (*f)(pc,n,fields);
415:   }
416:   return(0);
417: }

421: /*@C
422:    PCFieldSplitGetSubKSP - Gets the KSP contexts for all splits
423:    
424:    Collective on KSP

426:    Input Parameter:
427: .  pc - the preconditioner context

429:    Output Parameters:
430: +  n - the number of split
431: -  pc - the array of KSP contexts

433:    Note:  
434:    After PCFieldSplitGetSubKSP() the array of KSPs IS to be freed

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

438:    Level: advanced

440: .seealso: PCFIELDSPLIT
441: @*/
442: PetscErrorCode  PCFieldSplitGetSubKSP(PC pc,PetscInt *n,KSP *subksp[])
443: {
444:   PetscErrorCode ierr,(*f)(PC,PetscInt*,KSP **);

449:   PetscObjectQueryFunction((PetscObject)pc,"PCFieldSplitGetSubKSP_C",(void (**)(void))&f);
450:   if (f) {
451:     (*f)(pc,n,subksp);
452:   } else {
453:     SETERRQ(PETSC_ERR_ARG_WRONG,"Cannot get subksp for this type of PC");
454:   }
455:   return(0);
456: }

461: PetscErrorCode  PCFieldSplitSetType_FieldSplit(PC pc,PCCompositeType type)
462: {
463:   PC_FieldSplit  *jac = (PC_FieldSplit*)pc->data;

466:   jac->type = type;
467:   return(0);
468: }

473: /*@C
474:    PCFieldSplitSetType - Sets the type of fieldsplit preconditioner.
475:    
476:    Collective on PC

478:    Input Parameter:
479: .  pc - the preconditioner context
480: .  type - PC_COMPOSITE_ADDITIVE (default), PC_COMPOSITE_MULTIPLICATIVE

482:    Options Database Key:
483: .  -pc_fieldsplit_type <type: one of multiplicative, additive, special> - Sets fieldsplit preconditioner type

485:    Level: Developer

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

489: .seealso: PCCompositeSetType()

491: @*/
492: PetscErrorCode  PCFieldSplitSetType(PC pc,PCCompositeType type)
493: {
494:   PetscErrorCode ierr,(*f)(PC,PCCompositeType);

498:   PetscObjectQueryFunction((PetscObject)pc,"PCFieldSplitSetType_C",(void (**)(void))&f);
499:   if (f) {
500:     (*f)(pc,type);
501:   }
502:   return(0);
503: }

505: /* -------------------------------------------------------------------------------------*/
506: /*MC
507:    PCFIELDSPLIT - Preconditioner created by combining separate preconditioners for individual
508:                   fields or groups of fields


511:      To set options on the solvers for each block append -sub_ to all the PC
512:         options database keys. For example, -sub_pc_type ilu -sub_pc_factor_levels 1
513:         
514:      To set the options on the solvers separate for each block call PCFieldSplitGetSubKSP()
515:          and set the options directly on the resulting KSP object

517:    Level: intermediate

519:    Options Database Keys:
520: +   -pc_splitfield_%d_fields <a,b,..> - indicates the fields to be used in the %d'th split
521: .   -pc_splitfield_default - automatically add any fields to additional splits that have not
522:                               been supplied explicitly by -pc_splitfield_%d_fields
523: -   -pc_splitfield_type <additive,multiplicative>

525:    Concepts: physics based preconditioners

527: .seealso:  PCCreate(), PCSetType(), PCType (for list of available types), PC,
528:            PCFieldSplitGetSubKSP(), PCFieldSplitSetFields(),PCFieldSplitSetType()
529: M*/

534: PetscErrorCode  PCCreate_FieldSplit(PC pc)
535: {
537:   PC_FieldSplit  *jac;

540:   PetscNew(PC_FieldSplit,&jac);
541:   PetscLogObjectMemory(pc,sizeof(PC_FieldSplit));
542:   jac->bs      = -1;
543:   jac->nsplits = 0;
544:   jac->type    = PC_COMPOSITE_ADDITIVE;
545:   pc->data     = (void*)jac;

547:   pc->ops->apply             = PCApply_FieldSplit;
548:   pc->ops->setup             = PCSetUp_FieldSplit;
549:   pc->ops->destroy           = PCDestroy_FieldSplit;
550:   pc->ops->setfromoptions    = PCSetFromOptions_FieldSplit;
551:   pc->ops->view              = PCView_FieldSplit;
552:   pc->ops->applyrichardson   = 0;

554:   PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitGetSubKSP_C","PCFieldSplitGetSubKSP_FieldSplit",
555:                     PCFieldSplitGetSubKSP_FieldSplit);
556:   PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetFields_C","PCFieldSplitSetFields_FieldSplit",
557:                     PCFieldSplitSetFields_FieldSplit);
558:   PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetType_C","PCFieldSplitSetType_FieldSplit",
559:                     PCFieldSplitSetType_FieldSplit);
560:   return(0);
561: }