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: }