1 #define PETSCKSP_DLL 2 3 /* 4 5 */ 6 #include "private/pcimpl.h" /*I "petscpc.h" I*/ 7 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 IS is,cis; 16 PetscInt csize; 17 PC_FieldSplitLink next,previous; 18 }; 19 20 typedef struct { 21 PCCompositeType type; /* additive or multiplicative */ 22 PetscTruth defaultsplit; 23 PetscInt bs; 24 PetscInt nsplits; 25 Vec *x,*y,w1,w2; 26 Mat *pmat; 27 PetscTruth issetup; 28 PC_FieldSplitLink head; 29 } PC_FieldSplit; 30 31 /* 32 Notes: there is no particular reason that pmat, x, and y are stored as arrays in PC_FieldSplit instead of 33 inside PC_FieldSplitLink, just historical. If you want to be able to add new fields after already using the 34 PC you could change this. 35 */ 36 #undef __FUNCT__ 37 #define __FUNCT__ "PCView_FieldSplit" 38 static PetscErrorCode PCView_FieldSplit(PC pc,PetscViewer viewer) 39 { 40 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 41 PetscErrorCode ierr; 42 PetscTruth iascii; 43 PetscInt i,j; 44 PC_FieldSplitLink ilink = jac->head; 45 46 PetscFunctionBegin; 47 ierr = PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&iascii);CHKERRQ(ierr); 48 if (iascii) { 49 ierr = PetscViewerASCIIPrintf(viewer," FieldSplit with %s composition: total splits = %D, blocksize = %D\n",PCCompositeTypes[jac->type],jac->nsplits,jac->bs);CHKERRQ(ierr); 50 ierr = PetscViewerASCIIPrintf(viewer," Solver info for each split is in the following KSP objects:\n");CHKERRQ(ierr); 51 ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 52 for (i=0; i<jac->nsplits; i++) { 53 ierr = PetscViewerASCIIPrintf(viewer,"Split number %D Fields ",i);CHKERRQ(ierr); 54 ierr = PetscViewerASCIIUseTabs(viewer,PETSC_FALSE);CHKERRQ(ierr); 55 for (j=0; j<ilink->nfields; j++) { 56 if (j > 0) { 57 ierr = PetscViewerASCIIPrintf(viewer,",");CHKERRQ(ierr); 58 } 59 ierr = PetscViewerASCIIPrintf(viewer," %D",ilink->fields[j]);CHKERRQ(ierr); 60 } 61 ierr = PetscViewerASCIIPrintf(viewer,"\n");CHKERRQ(ierr); 62 ierr = PetscViewerASCIIUseTabs(viewer,PETSC_TRUE);CHKERRQ(ierr); 63 ierr = KSPView(ilink->ksp,viewer);CHKERRQ(ierr); 64 ilink = ilink->next; 65 } 66 ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 67 } else { 68 SETERRQ1(PETSC_ERR_SUP,"Viewer type %s not supported for PCFieldSplit",((PetscObject)viewer)->type_name); 69 } 70 PetscFunctionReturn(0); 71 } 72 73 #undef __FUNCT__ 74 #define __FUNCT__ "PCFieldSplitSetDefaults" 75 static PetscErrorCode PCFieldSplitSetDefaults(PC pc) 76 { 77 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 78 PetscErrorCode ierr; 79 PC_FieldSplitLink ilink = jac->head; 80 PetscInt i; 81 PetscTruth flg = PETSC_FALSE,*fields; 82 83 PetscFunctionBegin; 84 ierr = PetscOptionsGetTruth(((PetscObject)pc)->prefix,"-pc_fieldsplit_default",&flg,PETSC_NULL);CHKERRQ(ierr); 85 if (!ilink || flg) { 86 ierr = PetscInfo(pc,"Using default splitting of fields\n");CHKERRQ(ierr); 87 if (jac->bs <= 0) { 88 if (pc->pmat) { 89 ierr = MatGetBlockSize(pc->pmat,&jac->bs);CHKERRQ(ierr); 90 } else { 91 jac->bs = 1; 92 } 93 } 94 ierr = PetscMalloc(jac->bs*sizeof(PetscTruth),&fields);CHKERRQ(ierr); 95 ierr = PetscMemzero(fields,jac->bs*sizeof(PetscTruth));CHKERRQ(ierr); 96 while (ilink) { 97 for (i=0; i<ilink->nfields; i++) { 98 fields[ilink->fields[i]] = PETSC_TRUE; 99 } 100 ilink = ilink->next; 101 } 102 jac->defaultsplit = PETSC_TRUE; 103 for (i=0; i<jac->bs; i++) { 104 if (!fields[i]) { 105 ierr = PCFieldSplitSetFields(pc,1,&i);CHKERRQ(ierr); 106 } else { 107 jac->defaultsplit = PETSC_FALSE; 108 } 109 } 110 } 111 PetscFunctionReturn(0); 112 } 113 114 115 #undef __FUNCT__ 116 #define __FUNCT__ "PCSetUp_FieldSplit" 117 static PetscErrorCode PCSetUp_FieldSplit(PC pc) 118 { 119 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 120 PetscErrorCode ierr; 121 PC_FieldSplitLink ilink; 122 PetscInt i,nsplit,ccsize; 123 MatStructure flag = pc->flag; 124 PetscTruth sorted; 125 126 PetscFunctionBegin; 127 ierr = PCFieldSplitSetDefaults(pc);CHKERRQ(ierr); 128 nsplit = jac->nsplits; 129 ilink = jac->head; 130 131 /* get the matrices for each split */ 132 if (!jac->issetup) { 133 PetscInt rstart,rend,nslots,bs; 134 135 jac->issetup = PETSC_TRUE; 136 137 /* This is done here instead of in PCFieldSplitSetFields() because may not have matrix at that point */ 138 bs = jac->bs; 139 ierr = MatGetOwnershipRange(pc->pmat,&rstart,&rend);CHKERRQ(ierr); 140 ierr = MatGetLocalSize(pc->pmat,PETSC_NULL,&ccsize);CHKERRQ(ierr); 141 nslots = (rend - rstart)/bs; 142 for (i=0; i<nsplit; i++) { 143 if (jac->defaultsplit) { 144 ierr = ISCreateStride(((PetscObject)pc)->comm,nslots,rstart+i,nsplit,&ilink->is);CHKERRQ(ierr); 145 ilink->csize = ccsize/nsplit; 146 } else if (!ilink->is) { 147 if (ilink->nfields > 1) { 148 PetscInt *ii,j,k,nfields = ilink->nfields,*fields = ilink->fields; 149 ierr = PetscMalloc(ilink->nfields*nslots*sizeof(PetscInt),&ii);CHKERRQ(ierr); 150 for (j=0; j<nslots; j++) { 151 for (k=0; k<nfields; k++) { 152 ii[nfields*j + k] = rstart + bs*j + fields[k]; 153 } 154 } 155 ierr = ISCreateGeneral(((PetscObject)pc)->comm,nslots*nfields,ii,&ilink->is);CHKERRQ(ierr); 156 ierr = PetscFree(ii);CHKERRQ(ierr); 157 } else { 158 ierr = ISCreateStride(((PetscObject)pc)->comm,nslots,rstart+ilink->fields[0],bs,&ilink->is);CHKERRQ(ierr); 159 } 160 ilink->csize = (ccsize/bs)*ilink->nfields; 161 ierr = ISSorted(ilink->is,&sorted);CHKERRQ(ierr); 162 if (!sorted) SETERRQ(PETSC_ERR_USER,"Fields must be sorted when creating split"); 163 } 164 ierr = ISAllGather(ilink->is,&ilink->cis);CHKERRQ(ierr); 165 ilink = ilink->next; 166 } 167 } 168 169 ilink = jac->head; 170 if (!jac->pmat) { 171 ierr = PetscMalloc(nsplit*sizeof(Mat),&jac->pmat);CHKERRQ(ierr); 172 for (i=0; i<nsplit; i++) { 173 ierr = MatGetSubMatrix(pc->pmat,ilink->is,ilink->cis,ilink->csize,MAT_INITIAL_MATRIX,&jac->pmat[i]);CHKERRQ(ierr); 174 ilink = ilink->next; 175 } 176 } else { 177 for (i=0; i<nsplit; i++) { 178 ierr = MatGetSubMatrix(pc->pmat,ilink->is,ilink->cis,ilink->csize,MAT_REUSE_MATRIX,&jac->pmat[i]);CHKERRQ(ierr); 179 ilink = ilink->next; 180 } 181 } 182 183 /* set up the individual PCs */ 184 i = 0; 185 ilink = jac->head; 186 while (ilink) { 187 ierr = KSPSetOperators(ilink->ksp,jac->pmat[i],jac->pmat[i],flag);CHKERRQ(ierr); 188 ierr = KSPSetFromOptions(ilink->ksp);CHKERRQ(ierr); 189 ierr = KSPSetUp(ilink->ksp);CHKERRQ(ierr); 190 i++; 191 ilink = ilink->next; 192 } 193 194 /* create work vectors for each split */ 195 if (!jac->x) { 196 Vec xtmp; 197 ierr = PetscMalloc2(nsplit,Vec,&jac->x,nsplit,Vec,&jac->y);CHKERRQ(ierr); 198 ilink = jac->head; 199 for (i=0; i<nsplit; i++) { 200 Vec *vl,*vr; 201 202 ierr = KSPGetVecs(ilink->ksp,1,&vr,1,&vl);CHKERRQ(ierr); 203 ilink->x = *vr; 204 ilink->y = *vl; 205 ierr = PetscFree(vr);CHKERRQ(ierr); 206 ierr = PetscFree(vl);CHKERRQ(ierr); 207 jac->x[i] = ilink->x; 208 jac->y[i] = ilink->y; 209 ilink = ilink->next; 210 } 211 /* compute scatter contexts needed by multiplicative versions and non-default splits */ 212 213 ilink = jac->head; 214 ierr = MatGetVecs(pc->pmat,&xtmp,PETSC_NULL);CHKERRQ(ierr); 215 for (i=0; i<nsplit; i++) { 216 ierr = VecScatterCreate(xtmp,ilink->is,jac->x[i],PETSC_NULL,&ilink->sctx);CHKERRQ(ierr); 217 ilink = ilink->next; 218 } 219 ierr = VecDestroy(xtmp);CHKERRQ(ierr); 220 } 221 PetscFunctionReturn(0); 222 } 223 224 #define FieldSplitSplitSolveAdd(ilink,xx,yy) \ 225 (VecScatterBegin(ilink->sctx,xx,ilink->x,INSERT_VALUES,SCATTER_FORWARD) || \ 226 VecScatterEnd(ilink->sctx,xx,ilink->x,INSERT_VALUES,SCATTER_FORWARD) || \ 227 KSPSolve(ilink->ksp,ilink->x,ilink->y) || \ 228 VecScatterBegin(ilink->sctx,ilink->y,yy,ADD_VALUES,SCATTER_REVERSE) || \ 229 VecScatterEnd(ilink->sctx,ilink->y,yy,ADD_VALUES,SCATTER_REVERSE)) 230 231 #undef __FUNCT__ 232 #define __FUNCT__ "PCApply_FieldSplit" 233 static PetscErrorCode PCApply_FieldSplit(PC pc,Vec x,Vec y) 234 { 235 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 236 PetscErrorCode ierr; 237 PC_FieldSplitLink ilink = jac->head; 238 PetscInt bs; 239 240 PetscFunctionBegin; 241 CHKMEMQ; 242 ierr = VecGetBlockSize(x,&bs);CHKERRQ(ierr); 243 ierr = VecSetBlockSize(x,jac->bs);CHKERRQ(ierr); 244 ierr = VecSetBlockSize(y,jac->bs);CHKERRQ(ierr); 245 246 if (jac->type == PC_COMPOSITE_ADDITIVE) { 247 if (jac->defaultsplit) { 248 ierr = VecStrideGatherAll(x,jac->x,INSERT_VALUES);CHKERRQ(ierr); 249 while (ilink) { 250 ierr = KSPSolve(ilink->ksp,ilink->x,ilink->y);CHKERRQ(ierr); 251 ilink = ilink->next; 252 } 253 ierr = VecStrideScatterAll(jac->y,y,INSERT_VALUES);CHKERRQ(ierr); 254 } else { 255 ierr = VecSet(y,0.0);CHKERRQ(ierr); 256 while (ilink) { 257 ierr = FieldSplitSplitSolveAdd(ilink,x,y);CHKERRQ(ierr); 258 ilink = ilink->next; 259 } 260 } 261 } else if (jac->type == PC_COMPOSITE_MULTIPLICATIVE || jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) { 262 if (!jac->w1) { 263 ierr = VecDuplicate(x,&jac->w1);CHKERRQ(ierr); 264 ierr = VecDuplicate(x,&jac->w2);CHKERRQ(ierr); 265 } 266 ierr = VecSet(y,0.0);CHKERRQ(ierr); 267 ierr = FieldSplitSplitSolveAdd(ilink,x,y);CHKERRQ(ierr); 268 while (ilink->next) { 269 ilink = ilink->next; 270 ierr = MatMult(pc->pmat,y,jac->w1);CHKERRQ(ierr); 271 ierr = VecWAXPY(jac->w2,-1.0,jac->w1,x);CHKERRQ(ierr); 272 ierr = FieldSplitSplitSolveAdd(ilink,jac->w2,y);CHKERRQ(ierr); 273 } 274 if (jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) { 275 while (ilink->previous) { 276 ilink = ilink->previous; 277 ierr = MatMult(pc->pmat,y,jac->w1);CHKERRQ(ierr); 278 ierr = VecWAXPY(jac->w2,-1.0,jac->w1,x);CHKERRQ(ierr); 279 ierr = FieldSplitSplitSolveAdd(ilink,jac->w2,y);CHKERRQ(ierr); 280 } 281 } 282 } else SETERRQ1(PETSC_ERR_SUP,"Unsupported or unknown composition",(int) jac->type); 283 CHKMEMQ; 284 PetscFunctionReturn(0); 285 } 286 287 #define FieldSplitSplitSolveAddTranspose(ilink,xx,yy) \ 288 (VecScatterBegin(ilink->sctx,xx,ilink->y,INSERT_VALUES,SCATTER_FORWARD) || \ 289 VecScatterEnd(ilink->sctx,xx,ilink->y,INSERT_VALUES,SCATTER_FORWARD) || \ 290 KSPSolveTranspose(ilink->ksp,ilink->y,ilink->x) || \ 291 VecScatterBegin(ilink->sctx,ilink->x,yy,ADD_VALUES,SCATTER_REVERSE) || \ 292 VecScatterEnd(ilink->sctx,ilink->x,yy,ADD_VALUES,SCATTER_REVERSE)) 293 294 #undef __FUNCT__ 295 #define __FUNCT__ "PCApply_FieldSplit" 296 static PetscErrorCode PCApplyTranspose_FieldSplit(PC pc,Vec x,Vec y) 297 { 298 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 299 PetscErrorCode ierr; 300 PC_FieldSplitLink ilink = jac->head; 301 PetscInt bs; 302 303 PetscFunctionBegin; 304 CHKMEMQ; 305 ierr = VecGetBlockSize(x,&bs);CHKERRQ(ierr); 306 ierr = VecSetBlockSize(x,jac->bs);CHKERRQ(ierr); 307 ierr = VecSetBlockSize(y,jac->bs);CHKERRQ(ierr); 308 309 if (jac->type == PC_COMPOSITE_ADDITIVE) { 310 if (jac->defaultsplit) { 311 ierr = VecStrideGatherAll(x,jac->x,INSERT_VALUES);CHKERRQ(ierr); 312 while (ilink) { 313 ierr = KSPSolveTranspose(ilink->ksp,ilink->x,ilink->y);CHKERRQ(ierr); 314 ilink = ilink->next; 315 } 316 ierr = VecStrideScatterAll(jac->y,y,INSERT_VALUES);CHKERRQ(ierr); 317 } else { 318 ierr = VecSet(y,0.0);CHKERRQ(ierr); 319 while (ilink) { 320 ierr = FieldSplitSplitSolveAddTranspose(ilink,x,y);CHKERRQ(ierr); 321 ilink = ilink->next; 322 } 323 } 324 } else { 325 if (!jac->w1) { 326 ierr = VecDuplicate(x,&jac->w1);CHKERRQ(ierr); 327 ierr = VecDuplicate(x,&jac->w2);CHKERRQ(ierr); 328 } 329 ierr = VecSet(y,0.0);CHKERRQ(ierr); 330 if (jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) { 331 ierr = FieldSplitSplitSolveAddTranspose(ilink,x,y);CHKERRQ(ierr); 332 while (ilink->next) { 333 ilink = ilink->next; 334 ierr = MatMultTranspose(pc->pmat,y,jac->w1);CHKERRQ(ierr); 335 ierr = VecWAXPY(jac->w2,-1.0,jac->w1,x);CHKERRQ(ierr); 336 ierr = FieldSplitSplitSolveAddTranspose(ilink,jac->w2,y);CHKERRQ(ierr); 337 } 338 while (ilink->previous) { 339 ilink = ilink->previous; 340 ierr = MatMultTranspose(pc->pmat,y,jac->w1);CHKERRQ(ierr); 341 ierr = VecWAXPY(jac->w2,-1.0,jac->w1,x);CHKERRQ(ierr); 342 ierr = FieldSplitSplitSolveAddTranspose(ilink,jac->w2,y);CHKERRQ(ierr); 343 } 344 } else { 345 while (ilink->next) { /* get to last entry in linked list */ 346 ilink = ilink->next; 347 } 348 ierr = FieldSplitSplitSolveAddTranspose(ilink,x,y);CHKERRQ(ierr); 349 while (ilink->previous) { 350 ilink = ilink->previous; 351 ierr = MatMultTranspose(pc->pmat,y,jac->w1);CHKERRQ(ierr); 352 ierr = VecWAXPY(jac->w2,-1.0,jac->w1,x);CHKERRQ(ierr); 353 ierr = FieldSplitSplitSolveAddTranspose(ilink,jac->w2,y);CHKERRQ(ierr); 354 } 355 } 356 } 357 CHKMEMQ; 358 PetscFunctionReturn(0); 359 } 360 361 #undef __FUNCT__ 362 #define __FUNCT__ "PCDestroy_FieldSplit" 363 static PetscErrorCode PCDestroy_FieldSplit(PC pc) 364 { 365 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 366 PetscErrorCode ierr; 367 PC_FieldSplitLink ilink = jac->head,next; 368 369 PetscFunctionBegin; 370 while (ilink) { 371 ierr = KSPDestroy(ilink->ksp);CHKERRQ(ierr); 372 if (ilink->x) {ierr = VecDestroy(ilink->x);CHKERRQ(ierr);} 373 if (ilink->y) {ierr = VecDestroy(ilink->y);CHKERRQ(ierr);} 374 if (ilink->sctx) {ierr = VecScatterDestroy(ilink->sctx);CHKERRQ(ierr);} 375 if (ilink->is) {ierr = ISDestroy(ilink->is);CHKERRQ(ierr);} 376 if (ilink->cis) {ierr = ISDestroy(ilink->cis);CHKERRQ(ierr);} 377 next = ilink->next; 378 ierr = PetscFree(ilink->fields);CHKERRQ(ierr); 379 ierr = PetscFree(ilink);CHKERRQ(ierr); 380 ilink = next; 381 } 382 ierr = PetscFree2(jac->x,jac->y);CHKERRQ(ierr); 383 if (jac->pmat) {ierr = MatDestroyMatrices(jac->nsplits,&jac->pmat);CHKERRQ(ierr);} 384 if (jac->w1) {ierr = VecDestroy(jac->w1);CHKERRQ(ierr);} 385 if (jac->w2) {ierr = VecDestroy(jac->w2);CHKERRQ(ierr);} 386 ierr = PetscFree(jac);CHKERRQ(ierr); 387 PetscFunctionReturn(0); 388 } 389 390 #undef __FUNCT__ 391 #define __FUNCT__ "PCSetFromOptions_FieldSplit" 392 static PetscErrorCode PCSetFromOptions_FieldSplit(PC pc) 393 { 394 PetscErrorCode ierr; 395 PetscInt i = 0,nfields,*fields,bs; 396 PetscTruth flg; 397 char optionname[128]; 398 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 399 400 PetscFunctionBegin; 401 ierr = PetscOptionsHead("FieldSplit options");CHKERRQ(ierr); 402 ierr = PetscOptionsInt("-pc_fieldsplit_block_size","Blocksize that defines number of fields","PCFieldSplitSetBlockSize",jac->bs,&bs,&flg);CHKERRQ(ierr); 403 if (flg) { 404 ierr = PCFieldSplitSetBlockSize(pc,bs);CHKERRQ(ierr); 405 } 406 if (jac->bs <= 0) { 407 408 ierr = PCFieldSplitSetBlockSize(pc,1);CHKERRQ(ierr); 409 } 410 ierr = PetscOptionsEnum("-pc_fieldsplit_type","Type of composition","PCFieldSplitSetType",PCCompositeTypes,(PetscEnum)jac->type,(PetscEnum*)&jac->type,&flg);CHKERRQ(ierr); 411 ierr = PetscMalloc(jac->bs*sizeof(PetscInt),&fields);CHKERRQ(ierr); 412 while (PETSC_TRUE) { 413 sprintf(optionname,"-pc_fieldsplit_%d_fields",(int)i++); 414 nfields = jac->bs; 415 ierr = PetscOptionsIntArray(optionname,"Fields in this split","PCFieldSplitSetFields",fields,&nfields,&flg);CHKERRQ(ierr); 416 if (!flg) break; 417 if (!nfields) SETERRQ(PETSC_ERR_USER,"Cannot list zero fields"); 418 ierr = PCFieldSplitSetFields(pc,nfields,fields);CHKERRQ(ierr); 419 } 420 ierr = PetscFree(fields);CHKERRQ(ierr); 421 ierr = PetscOptionsTail();CHKERRQ(ierr); 422 PetscFunctionReturn(0); 423 } 424 425 /*------------------------------------------------------------------------------------*/ 426 427 EXTERN_C_BEGIN 428 #undef __FUNCT__ 429 #define __FUNCT__ "PCFieldSplitSetFields_FieldSplit" 430 PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitSetFields_FieldSplit(PC pc,PetscInt n,PetscInt *fields) 431 { 432 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 433 PetscErrorCode ierr; 434 PC_FieldSplitLink ilink,next = jac->head; 435 char prefix[128]; 436 PetscInt i; 437 438 PetscFunctionBegin; 439 if (n <= 0) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Negative number of fields requested"); 440 for (i=0; i<n; i++) { 441 if (fields[i] >= jac->bs) SETERRQ2(PETSC_ERR_ARG_OUTOFRANGE,"Field %D requested but only %D exist",fields[i],jac->bs); 442 if (fields[i] < 0) SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"Negative field %D requested",fields[i]); 443 } 444 ierr = PetscNew(struct _PC_FieldSplitLink,&ilink);CHKERRQ(ierr); 445 ierr = PetscMalloc(n*sizeof(PetscInt),&ilink->fields);CHKERRQ(ierr); 446 ierr = PetscMemcpy(ilink->fields,fields,n*sizeof(PetscInt));CHKERRQ(ierr); 447 ilink->nfields = n; 448 ilink->next = PETSC_NULL; 449 ierr = KSPCreate(((PetscObject)pc)->comm,&ilink->ksp);CHKERRQ(ierr); 450 ierr = KSPSetType(ilink->ksp,KSPPREONLY);CHKERRQ(ierr); 451 452 if (((PetscObject)pc)->prefix) { 453 sprintf(prefix,"%sfieldsplit_%d_",((PetscObject)pc)->prefix,(int)jac->nsplits); 454 } else { 455 sprintf(prefix,"fieldsplit_%d_",(int)jac->nsplits); 456 } 457 ierr = KSPSetOptionsPrefix(ilink->ksp,prefix);CHKERRQ(ierr); 458 459 if (!next) { 460 jac->head = ilink; 461 ilink->previous = PETSC_NULL; 462 } else { 463 while (next->next) { 464 next = next->next; 465 } 466 next->next = ilink; 467 ilink->previous = next; 468 } 469 jac->nsplits++; 470 PetscFunctionReturn(0); 471 } 472 EXTERN_C_END 473 474 475 EXTERN_C_BEGIN 476 #undef __FUNCT__ 477 #define __FUNCT__ "PCFieldSplitGetSubKSP_FieldSplit" 478 PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitGetSubKSP_FieldSplit(PC pc,PetscInt *n,KSP **subksp) 479 { 480 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 481 PetscErrorCode ierr; 482 PetscInt cnt = 0; 483 PC_FieldSplitLink ilink = jac->head; 484 485 PetscFunctionBegin; 486 ierr = PetscMalloc(jac->nsplits*sizeof(KSP*),subksp);CHKERRQ(ierr); 487 while (ilink) { 488 (*subksp)[cnt++] = ilink->ksp; 489 ilink = ilink->next; 490 } 491 if (cnt != jac->nsplits) SETERRQ2(PETSC_ERR_PLIB,"Corrupt PCFIELDSPLIT object: number splits in linked list %D in object %D",cnt,jac->nsplits); 492 *n = jac->nsplits; 493 PetscFunctionReturn(0); 494 } 495 EXTERN_C_END 496 497 EXTERN_C_BEGIN 498 #undef __FUNCT__ 499 #define __FUNCT__ "PCFieldSplitSetIS_FieldSplit" 500 PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitSetIS_FieldSplit(PC pc,IS is) 501 { 502 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 503 PetscErrorCode ierr; 504 PC_FieldSplitLink ilink, next = jac->head; 505 char prefix[128]; 506 507 PetscFunctionBegin; 508 ierr = PetscNew(struct _PC_FieldSplitLink,&ilink);CHKERRQ(ierr); 509 ilink->next = PETSC_NULL; 510 ierr = KSPCreate(((PetscObject)pc)->comm,&ilink->ksp);CHKERRQ(ierr); 511 ierr = KSPSetType(ilink->ksp,KSPPREONLY);CHKERRQ(ierr); 512 513 if (((PetscObject)pc)->prefix) { 514 sprintf(prefix,"%sfieldsplit_%d_",((PetscObject)pc)->prefix,(int)jac->nsplits); 515 } else { 516 sprintf(prefix,"fieldsplit_%d_",(int)jac->nsplits); 517 } 518 ierr = KSPSetOptionsPrefix(ilink->ksp,prefix);CHKERRQ(ierr); 519 520 if (!next) { 521 jac->head = ilink; 522 ilink->previous = PETSC_NULL; 523 } else { 524 while (next->next) { 525 next = next->next; 526 } 527 next->next = ilink; 528 ilink->previous = next; 529 } 530 jac->nsplits++; 531 532 PetscFunctionReturn(0); 533 } 534 EXTERN_C_END 535 536 #undef __FUNCT__ 537 #define __FUNCT__ "PCFieldSplitSetFields" 538 /*@ 539 PCFieldSplitSetFields - Sets the fields for one particular split in the field split preconditioner 540 541 Collective on PC 542 543 Input Parameters: 544 + pc - the preconditioner context 545 . n - the number of fields in this split 546 . fields - the fields in this split 547 548 Level: intermediate 549 550 .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetBlockSize() 551 552 @*/ 553 PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitSetFields(PC pc,PetscInt n, PetscInt *fields) 554 { 555 PetscErrorCode ierr,(*f)(PC,PetscInt,PetscInt *); 556 557 PetscFunctionBegin; 558 PetscValidHeaderSpecific(pc,PC_COOKIE,1); 559 ierr = PetscObjectQueryFunction((PetscObject)pc,"PCFieldSplitSetFields_C",(void (**)(void))&f);CHKERRQ(ierr); 560 if (f) { 561 ierr = (*f)(pc,n,fields);CHKERRQ(ierr); 562 } 563 PetscFunctionReturn(0); 564 } 565 566 #undef __FUNCT__ 567 #define __FUNCT__ "PCFieldSplitSetIS" 568 /*@ 569 PCFieldSplitSetIS - Sets the exact elements for field 570 571 Collective on PC 572 573 Input Parameters: 574 + pc - the preconditioner context 575 . is - the index set that defines the vector elements in this field 576 577 Level: intermediate 578 579 .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetBlockSize() 580 581 @*/ 582 PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitSetIS(PC pc,IS is) 583 { 584 PetscErrorCode ierr,(*f)(PC,IS); 585 586 PetscFunctionBegin; 587 PetscValidHeaderSpecific(pc,PC_COOKIE,1); 588 PetscValidHeaderSpecific(is,IS_COOKIE,1); 589 ierr = PetscObjectQueryFunction((PetscObject)pc,"PCFieldSplitSetIS_C",(void (**)(void))&f);CHKERRQ(ierr); 590 if (f) { 591 ierr = (*f)(pc,is);CHKERRQ(ierr); 592 } 593 PetscFunctionReturn(0); 594 } 595 596 #undef __FUNCT__ 597 #define __FUNCT__ "PCFieldSplitSetBlockSize" 598 /*@ 599 PCFieldSplitSetBlockSize - Sets the block size for defining where fields start in the 600 fieldsplit preconditioner. If not set the matrix block size is used. 601 602 Collective on PC 603 604 Input Parameters: 605 + pc - the preconditioner context 606 - bs - the block size 607 608 Level: intermediate 609 610 .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetFields() 611 612 @*/ 613 PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitSetBlockSize(PC pc,PetscInt bs) 614 { 615 PetscErrorCode ierr,(*f)(PC,PetscInt); 616 617 PetscFunctionBegin; 618 PetscValidHeaderSpecific(pc,PC_COOKIE,1); 619 ierr = PetscObjectQueryFunction((PetscObject)pc,"PCFieldSplitSetBlockSize_C",(void (**)(void))&f);CHKERRQ(ierr); 620 if (f) { 621 ierr = (*f)(pc,bs);CHKERRQ(ierr); 622 } 623 PetscFunctionReturn(0); 624 } 625 626 #undef __FUNCT__ 627 #define __FUNCT__ "PCFieldSplitGetSubKSP" 628 /*@C 629 PCFieldSplitGetSubKSP - Gets the KSP contexts for all splits 630 631 Collective on KSP 632 633 Input Parameter: 634 . pc - the preconditioner context 635 636 Output Parameters: 637 + n - the number of split 638 - pc - the array of KSP contexts 639 640 Note: 641 After PCFieldSplitGetSubKSP() the array of KSPs IS to be freed 642 643 You must call KSPSetUp() before calling PCFieldSplitGetSubKSP(). 644 645 Level: advanced 646 647 .seealso: PCFIELDSPLIT 648 @*/ 649 PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitGetSubKSP(PC pc,PetscInt *n,KSP *subksp[]) 650 { 651 PetscErrorCode ierr,(*f)(PC,PetscInt*,KSP **); 652 653 PetscFunctionBegin; 654 PetscValidHeaderSpecific(pc,PC_COOKIE,1); 655 PetscValidIntPointer(n,2); 656 ierr = PetscObjectQueryFunction((PetscObject)pc,"PCFieldSplitGetSubKSP_C",(void (**)(void))&f);CHKERRQ(ierr); 657 if (f) { 658 ierr = (*f)(pc,n,subksp);CHKERRQ(ierr); 659 } else { 660 SETERRQ(PETSC_ERR_ARG_WRONG,"Cannot get subksp for this type of PC"); 661 } 662 PetscFunctionReturn(0); 663 } 664 665 EXTERN_C_BEGIN 666 #undef __FUNCT__ 667 #define __FUNCT__ "PCFieldSplitSetType_FieldSplit" 668 PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitSetType_FieldSplit(PC pc,PCCompositeType type) 669 { 670 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 671 672 PetscFunctionBegin; 673 jac->type = type; 674 PetscFunctionReturn(0); 675 } 676 EXTERN_C_END 677 678 EXTERN_C_BEGIN 679 #undef __FUNCT__ 680 #define __FUNCT__ "PCFieldSplitSetBlockSize_FieldSplit" 681 PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitSetBlockSize_FieldSplit(PC pc,PetscInt bs) 682 { 683 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 684 685 PetscFunctionBegin; 686 if (bs < 1) SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"Blocksize must be positive, you gave %D",bs); 687 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); 688 jac->bs = bs; 689 PetscFunctionReturn(0); 690 } 691 EXTERN_C_END 692 693 #undef __FUNCT__ 694 #define __FUNCT__ "PCFieldSplitSetType" 695 /*@ 696 PCFieldSplitSetType - Sets the type of fieldsplit preconditioner. 697 698 Collective on PC 699 700 Input Parameter: 701 . pc - the preconditioner context 702 . type - PC_COMPOSITE_ADDITIVE (default), PC_COMPOSITE_MULTIPLICATIVE, PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE 703 704 Options Database Key: 705 . -pc_fieldsplit_type <type: one of multiplicative, additive, symmetric_multiplicative, special> - Sets fieldsplit preconditioner type 706 707 Level: Developer 708 709 .keywords: PC, set, type, composite preconditioner, additive, multiplicative 710 711 .seealso: PCCompositeSetType() 712 713 @*/ 714 PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitSetType(PC pc,PCCompositeType type) 715 { 716 PetscErrorCode ierr,(*f)(PC,PCCompositeType); 717 718 PetscFunctionBegin; 719 PetscValidHeaderSpecific(pc,PC_COOKIE,1); 720 ierr = PetscObjectQueryFunction((PetscObject)pc,"PCFieldSplitSetType_C",(void (**)(void))&f);CHKERRQ(ierr); 721 if (f) { 722 ierr = (*f)(pc,type);CHKERRQ(ierr); 723 } 724 PetscFunctionReturn(0); 725 } 726 727 /* -------------------------------------------------------------------------------------*/ 728 /*MC 729 PCFIELDSPLIT - Preconditioner created by combining separate preconditioners for individual 730 fields or groups of fields 731 732 733 To set options on the solvers for each block append -sub_ to all the PC 734 options database keys. For example, -sub_pc_type ilu -sub_pc_factor_levels 1 735 736 To set the options on the solvers separate for each block call PCFieldSplitGetSubKSP() 737 and set the options directly on the resulting KSP object 738 739 Level: intermediate 740 741 Options Database Keys: 742 + -pc_splitfield_%d_fields <a,b,..> - indicates the fields to be used in the %d'th split 743 . -pc_splitfield_default - automatically add any fields to additional splits that have not 744 been supplied explicitly by -pc_splitfield_%d_fields 745 . -pc_splitfield_block_size <bs> - size of block that defines fields (i.e. there are bs fields) 746 - -pc_splitfield_type <additive,multiplicative> 747 748 Concepts: physics based preconditioners 749 750 .seealso: PCCreate(), PCSetType(), PCType (for list of available types), PC, 751 PCFieldSplitGetSubKSP(), PCFieldSplitSetFields(),PCFieldSplitSetType() 752 M*/ 753 754 EXTERN_C_BEGIN 755 #undef __FUNCT__ 756 #define __FUNCT__ "PCCreate_FieldSplit" 757 PetscErrorCode PETSCKSP_DLLEXPORT PCCreate_FieldSplit(PC pc) 758 { 759 PetscErrorCode ierr; 760 PC_FieldSplit *jac; 761 762 PetscFunctionBegin; 763 ierr = PetscNewLog(pc,PC_FieldSplit,&jac);CHKERRQ(ierr); 764 jac->bs = -1; 765 jac->nsplits = 0; 766 jac->type = PC_COMPOSITE_ADDITIVE; 767 768 pc->data = (void*)jac; 769 770 pc->ops->apply = PCApply_FieldSplit; 771 pc->ops->applytranspose = PCApplyTranspose_FieldSplit; 772 pc->ops->setup = PCSetUp_FieldSplit; 773 pc->ops->destroy = PCDestroy_FieldSplit; 774 pc->ops->setfromoptions = PCSetFromOptions_FieldSplit; 775 pc->ops->view = PCView_FieldSplit; 776 pc->ops->applyrichardson = 0; 777 778 ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitGetSubKSP_C","PCFieldSplitGetSubKSP_FieldSplit", 779 PCFieldSplitGetSubKSP_FieldSplit);CHKERRQ(ierr); 780 ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetFields_C","PCFieldSplitSetFields_FieldSplit", 781 PCFieldSplitSetFields_FieldSplit);CHKERRQ(ierr); 782 ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetIS_C","PCFieldSplitSetIS_FieldSplit", 783 PCFieldSplitSetIS_FieldSplit);CHKERRQ(ierr); 784 ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetType_C","PCFieldSplitSetType_FieldSplit", 785 PCFieldSplitSetType_FieldSplit);CHKERRQ(ierr); 786 ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetBlockSize_C","PCFieldSplitSetBlockSize_FieldSplit", 787 PCFieldSplitSetBlockSize_FieldSplit);CHKERRQ(ierr); 788 PetscFunctionReturn(0); 789 } 790 EXTERN_C_END 791 792 793