1 /* 2 3 */ 4 #include "src/ksp/pc/pcimpl.h" /*I "petscpc.h" I*/ 5 6 typedef struct _PC_FieldSplitLink *PC_FieldSplitLink; 7 struct _PC_FieldSplitLink { 8 KSP ksp; 9 Vec x,y; 10 PetscInt nfields; 11 PetscInt *fields; 12 VecScatter sctx; 13 PC_FieldSplitLink next; 14 }; 15 16 typedef struct { 17 PCCompositeType type; /* additive or multiplicative */ 18 PetscTruth defaultsplit; 19 PetscInt bs; 20 PetscInt nsplits; 21 Vec *x,*y,w1,w2; 22 Mat *pmat; 23 IS *is; 24 PC_FieldSplitLink head; 25 } PC_FieldSplit; 26 27 #undef __FUNCT__ 28 #define __FUNCT__ "PCView_FieldSplit" 29 static PetscErrorCode PCView_FieldSplit(PC pc,PetscViewer viewer) 30 { 31 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 32 PetscErrorCode ierr; 33 PetscTruth iascii; 34 PetscInt i,j; 35 PC_FieldSplitLink link = jac->head; 36 const char *types[] = {"additive","multiplicative"}; 37 38 PetscFunctionBegin; 39 ierr = PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&iascii);CHKERRQ(ierr); 40 if (iascii) { 41 ierr = PetscViewerASCIIPrintf(viewer," FieldSplit with %s composition: total splits = %D",types[jac->type],jac->nsplits);CHKERRQ(ierr); 42 ierr = PetscViewerASCIIPrintf(viewer," Solver info for each split is in the following KSP objects:\n");CHKERRQ(ierr); 43 ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 44 for (i=0; i<jac->nsplits; i++) { 45 ierr = PetscViewerASCIIPrintf(viewer,"Split number %D Fields ",i);CHKERRQ(ierr); 46 ierr = PetscViewerASCIIUseTabs(viewer,PETSC_FALSE);CHKERRQ(ierr); 47 for (j=0; j<link->nfields; j++) { 48 if (j > 0) { 49 ierr = PetscViewerASCIIPrintf(viewer,",");CHKERRQ(ierr); 50 } 51 ierr = PetscViewerASCIIPrintf(viewer," %D",link->fields[j]);CHKERRQ(ierr); 52 } 53 ierr = PetscViewerASCIIPrintf(viewer,"\n");CHKERRQ(ierr); 54 ierr = PetscViewerASCIIUseTabs(viewer,PETSC_TRUE);CHKERRQ(ierr); 55 ierr = KSPView(link->ksp,viewer);CHKERRQ(ierr); 56 link = link->next; 57 } 58 ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 59 } else { 60 SETERRQ1(PETSC_ERR_SUP,"Viewer type %s not supported for PCFieldSplit",((PetscObject)viewer)->type_name); 61 } 62 PetscFunctionReturn(0); 63 } 64 65 #undef __FUNCT__ 66 #define __FUNCT__ "PCFieldSplitSetDefaults" 67 static PetscErrorCode PCFieldSplitSetDefaults(PC pc) 68 { 69 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 70 PetscErrorCode ierr; 71 PC_FieldSplitLink link = jac->head; 72 PetscInt i; 73 PetscTruth flg = PETSC_FALSE,*fields; 74 75 PetscFunctionBegin; 76 ierr = PetscOptionsGetLogical(pc->prefix,"-pc_fieldsplit_default",&flg,PETSC_NULL);CHKERRQ(ierr); 77 if (!link || flg) { 78 ierr = PetscLogInfo(pc,"PCFieldSplitSetDefaults: Using default splitting of fields");CHKERRQ(ierr); 79 if (jac->bs <= 0) { 80 ierr = MatGetBlockSize(pc->pmat,&jac->bs);CHKERRQ(ierr); 81 } 82 ierr = PetscMalloc(jac->bs*sizeof(PetscTruth),&fields);CHKERRQ(ierr); 83 ierr = PetscMemzero(fields,jac->bs*sizeof(PetscTruth));CHKERRQ(ierr); 84 while (link) { 85 for (i=0; i<link->nfields; i++) { 86 fields[link->fields[i]] = PETSC_TRUE; 87 } 88 link = link->next; 89 } 90 jac->defaultsplit = PETSC_TRUE; 91 for (i=0; i<jac->bs; i++) { 92 if (!fields[i]) { 93 ierr = PCFieldSplitSetFields(pc,1,&i);CHKERRQ(ierr); 94 } else { 95 jac->defaultsplit = PETSC_FALSE; 96 } 97 } 98 } 99 PetscFunctionReturn(0); 100 } 101 102 103 #undef __FUNCT__ 104 #define __FUNCT__ "PCSetUp_FieldSplit" 105 static PetscErrorCode PCSetUp_FieldSplit(PC pc) 106 { 107 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 108 PetscErrorCode ierr; 109 PC_FieldSplitLink link; 110 PetscInt i,nsplit; 111 MatStructure flag = pc->flag; 112 113 PetscFunctionBegin; 114 ierr = PCFieldSplitSetDefaults(pc);CHKERRQ(ierr); 115 nsplit = jac->nsplits; 116 link = jac->head; 117 118 /* get the matrices for each split */ 119 if (!jac->is) { 120 PetscInt rstart,rend,nslots,bs; 121 122 ierr = MatGetBlockSize(pc->pmat,&bs);CHKERRQ(ierr); 123 ierr = MatGetOwnershipRange(pc->pmat,&rstart,&rend);CHKERRQ(ierr); 124 nslots = (rend - rstart)/bs; 125 ierr = PetscMalloc(nsplit*sizeof(IS),&jac->is);CHKERRQ(ierr); 126 for (i=0; i<nsplit; i++) { 127 if (jac->defaultsplit) { 128 ierr = ISCreateStride(pc->comm,nslots,rstart+i,nsplit,&jac->is[i]);CHKERRQ(ierr); 129 } else { 130 PetscInt *ii,j,k,nfields = link->nfields,*fields = link->fields; 131 PetscTruth sorted; 132 ierr = PetscMalloc(link->nfields*nslots*sizeof(PetscInt),&ii);CHKERRQ(ierr); 133 for (j=0; j<nslots; j++) { 134 for (k=0; k<nfields; k++) { 135 ii[nfields*j + k] = rstart + bs*j + fields[k]; 136 } 137 } 138 ierr = ISCreateGeneral(pc->comm,nslots*nfields,ii,&jac->is[i]);CHKERRQ(ierr); 139 ierr = ISSorted(jac->is[i],&sorted);CHKERRQ(ierr); 140 if (!sorted) SETERRQ(PETSC_ERR_USER,"Fields must be sorted when creating split"); 141 ierr = PetscFree(ii);CHKERRQ(ierr); 142 link = link->next; 143 } 144 } 145 } 146 147 if (!jac->pmat) { 148 ierr = MatGetSubMatrices(pc->pmat,nsplit,jac->is,jac->is,MAT_INITIAL_MATRIX,&jac->pmat);CHKERRQ(ierr); 149 } else { 150 ierr = MatGetSubMatrices(pc->pmat,nsplit,jac->is,jac->is,MAT_REUSE_MATRIX,&jac->pmat);CHKERRQ(ierr); 151 } 152 153 /* set up the individual PCs */ 154 i = 0; 155 link = jac->head; 156 while (link) { 157 ierr = KSPSetOperators(link->ksp,jac->pmat[i],jac->pmat[i],flag);CHKERRQ(ierr); 158 ierr = KSPSetFromOptions(link->ksp);CHKERRQ(ierr); 159 ierr = KSPSetUp(link->ksp);CHKERRQ(ierr); 160 i++; 161 link = link->next; 162 } 163 164 /* create work vectors for each split */ 165 if (!jac->x) { 166 Vec xtmp; 167 ierr = PetscMalloc2(nsplit,Vec,&jac->x,nsplit,Vec,&jac->y);CHKERRQ(ierr); 168 link = jac->head; 169 for (i=0; i<nsplit; i++) { 170 Mat A; 171 ierr = KSPGetOperators(link->ksp,PETSC_NULL,&A,PETSC_NULL);CHKERRQ(ierr); 172 ierr = MatGetVecs(A,&link->x,&link->y);CHKERRQ(ierr); 173 jac->x[i] = link->x; 174 jac->y[i] = link->y; 175 link = link->next; 176 } 177 /* compute scatter contexts needed by multiplicative versions and non-default splits */ 178 179 link = jac->head; 180 ierr = MatGetVecs(pc->pmat,&xtmp,PETSC_NULL);CHKERRQ(ierr); 181 for (i=0; i<nsplit; i++) { 182 ierr = VecScatterCreate(xtmp,jac->is[i],jac->x[i],PETSC_NULL,&link->sctx);CHKERRQ(ierr); 183 link = link->next; 184 } 185 ierr = VecDestroy(xtmp);CHKERRQ(ierr); 186 } 187 PetscFunctionReturn(0); 188 } 189 190 #define FieldSplitSplitSolveAdd(link,xx,yy) \ 191 (VecScatterBegin(xx,link->x,INSERT_VALUES,SCATTER_FORWARD,link->sctx) || \ 192 VecScatterEnd(xx,link->x,INSERT_VALUES,SCATTER_FORWARD,link->sctx) || \ 193 KSPSolve(link->ksp,link->x,link->y) || \ 194 VecScatterBegin(link->y,yy,ADD_VALUES,SCATTER_REVERSE,link->sctx) || \ 195 VecScatterEnd(link->y,yy,ADD_VALUES,SCATTER_REVERSE,link->sctx)) 196 197 #undef __FUNCT__ 198 #define __FUNCT__ "PCApply_FieldSplit" 199 static PetscErrorCode PCApply_FieldSplit(PC pc,Vec x,Vec y) 200 { 201 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 202 PetscErrorCode ierr; 203 PC_FieldSplitLink link = jac->head; 204 PetscScalar zero = 0.0,mone = -1.0; 205 206 PetscFunctionBegin; 207 if (jac->type == PC_COMPOSITE_ADDITIVE) { 208 if (jac->defaultsplit) { 209 ierr = VecStrideGatherAll(x,jac->x,INSERT_VALUES);CHKERRQ(ierr); 210 while (link) { 211 ierr = KSPSolve(link->ksp,link->x,link->y);CHKERRQ(ierr); 212 link = link->next; 213 } 214 ierr = VecStrideScatterAll(jac->y,y,INSERT_VALUES);CHKERRQ(ierr); 215 } else { 216 PetscInt i = 0; 217 218 ierr = VecSet(&zero,y);CHKERRQ(ierr); 219 while (link) { 220 ierr = FieldSplitSplitSolveAdd(link,x,y);CHKERRQ(ierr); 221 link = link->next; 222 i++; 223 } 224 } 225 } else { 226 if (!jac->w1) { 227 ierr = VecDuplicate(x,&jac->w1);CHKERRQ(ierr); 228 ierr = VecDuplicate(x,&jac->w2);CHKERRQ(ierr); 229 } 230 ierr = VecSet(&zero,y);CHKERRQ(ierr); 231 ierr = FieldSplitSplitSolveAdd(link,x,y);CHKERRQ(ierr); 232 while (link->next) { 233 link = link->next; 234 ierr = MatMult(pc->pmat,y,jac->w1);CHKERRQ(ierr); 235 ierr = VecWAXPY(&mone,jac->w1,x,jac->w2);CHKERRQ(ierr); 236 ierr = FieldSplitSplitSolveAdd(link,jac->w2,y);CHKERRQ(ierr); 237 } 238 } 239 PetscFunctionReturn(0); 240 } 241 242 #undef __FUNCT__ 243 #define __FUNCT__ "PCDestroy_FieldSplit" 244 static PetscErrorCode PCDestroy_FieldSplit(PC pc) 245 { 246 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 247 PetscErrorCode ierr; 248 PC_FieldSplitLink link = jac->head,next; 249 250 PetscFunctionBegin; 251 while (link) { 252 ierr = KSPDestroy(link->ksp);CHKERRQ(ierr); 253 if (link->x) {ierr = VecDestroy(link->x);CHKERRQ(ierr);} 254 if (link->y) {ierr = VecDestroy(link->y);CHKERRQ(ierr);} 255 if (link->sctx) {ierr = VecScatterDestroy(link->sctx);CHKERRQ(ierr);} 256 next = link->next; 257 ierr = PetscFree2(link,link->fields);CHKERRQ(ierr); 258 link = next; 259 } 260 if (jac->x) {ierr = PetscFree2(jac->x,jac->y);CHKERRQ(ierr);} 261 if (jac->pmat) {ierr = MatDestroyMatrices(jac->nsplits,&jac->pmat);CHKERRQ(ierr);} 262 if (jac->is) { 263 PetscInt i; 264 for (i=0; i<jac->nsplits; i++) {ierr = ISDestroy(jac->is[i]);CHKERRQ(ierr);} 265 ierr = PetscFree(jac->is);CHKERRQ(ierr); 266 } 267 if (jac->w1) {ierr = VecDestroy(jac->w1);CHKERRQ(ierr);} 268 if (jac->w2) {ierr = VecDestroy(jac->w2);CHKERRQ(ierr);} 269 ierr = PetscFree(jac);CHKERRQ(ierr); 270 PetscFunctionReturn(0); 271 } 272 273 #undef __FUNCT__ 274 #define __FUNCT__ "PCSetFromOptions_FieldSplit" 275 static PetscErrorCode PCSetFromOptions_FieldSplit(PC pc) 276 /* This does not call KSPSetFromOptions() on the subksp's, see PCSetFromOptionsBJacobi/ASM() */ 277 { 278 PetscErrorCode ierr; 279 PetscInt i = 0,nfields,fields[12],indx; 280 PetscTruth flg; 281 char optionname[128]; 282 const char *types[] = {"additive","multiplicative"}; 283 284 PetscFunctionBegin; 285 ierr = PetscOptionsHead("FieldSplit options");CHKERRQ(ierr); 286 ierr = PetscOptionsEList("-pc_fieldsplit_type","Type of composition","PCFieldSplitSetType",types,2,types[0],&indx,&flg);CHKERRQ(ierr); 287 if (flg) { 288 ierr = PCFieldSplitSetType(pc,(PCCompositeType)indx);CHKERRQ(ierr); 289 } 290 while (PETSC_TRUE) { 291 sprintf(optionname,"-pc_fieldsplit_%d_fields",(int)i++); 292 nfields = 12; 293 ierr = PetscOptionsIntArray(optionname,"Fields in this split","PCFieldSplitSetFields",fields,&nfields,&flg);CHKERRQ(ierr); 294 if (!flg) break; 295 if (!nfields) SETERRQ(PETSC_ERR_USER,"Cannot list zero fields"); 296 ierr = PCFieldSplitSetFields(pc,nfields,fields);CHKERRQ(ierr); 297 } 298 ierr = PetscOptionsTail();CHKERRQ(ierr); 299 PetscFunctionReturn(0); 300 } 301 302 /*------------------------------------------------------------------------------------*/ 303 304 EXTERN_C_BEGIN 305 #undef __FUNCT__ 306 #define __FUNCT__ "PCFieldSplitSetFields_FieldSplit" 307 PetscErrorCode PCFieldSplitSetFields_FieldSplit(PC pc,PetscInt n,PetscInt *fields) 308 { 309 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 310 PetscErrorCode ierr; 311 PC_FieldSplitLink link,next = jac->head; 312 char prefix[128]; 313 314 PetscFunctionBegin; 315 if (n <= 0) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Negative number of fields requested"); 316 ierr = PetscMalloc2(1,struct _PC_FieldSplitLink,&link,n,PetscInt,&link->fields);CHKERRQ(ierr); 317 ierr = PetscMemcpy(link->fields,fields,n*sizeof(PetscInt));CHKERRQ(ierr); 318 link->nfields = n; 319 link->next = PETSC_NULL; 320 ierr = KSPCreate(pc->comm,&link->ksp);CHKERRQ(ierr); 321 ierr = KSPSetType(link->ksp,KSPPREONLY);CHKERRQ(ierr); 322 323 if (pc->prefix) { 324 sprintf(prefix,"%sfieldsplit_%d_",pc->prefix,(int)jac->nsplits); 325 } else { 326 sprintf(prefix,"fieldsplit_%d_",(int)jac->nsplits); 327 } 328 ierr = KSPSetOptionsPrefix(link->ksp,prefix);CHKERRQ(ierr); 329 330 if (!next) { 331 jac->head = link; 332 } else { 333 while (next->next) { 334 next = next->next; 335 } 336 next->next = link; 337 } 338 jac->nsplits++; 339 PetscFunctionReturn(0); 340 } 341 EXTERN_C_END 342 343 344 EXTERN_C_BEGIN 345 #undef __FUNCT__ 346 #define __FUNCT__ "PCFieldSplitGetSubKSP_FieldSplit" 347 PetscErrorCode PCFieldSplitGetSubKSP_FieldSplit(PC pc,PetscInt *n,KSP **subksp) 348 { 349 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 350 PetscErrorCode ierr; 351 PetscInt cnt = 0; 352 PC_FieldSplitLink link = jac->head; 353 354 PetscFunctionBegin; 355 ierr = PetscMalloc(jac->nsplits*sizeof(KSP*),subksp);CHKERRQ(ierr); 356 while (link) { 357 (*subksp)[cnt++] = link->ksp; 358 link = link->next; 359 } 360 if (cnt != jac->nsplits) SETERRQ2(PETSC_ERR_PLIB,"Corrupt PCFIELDSPLIT object: number splits in linked list %D in object %D",cnt,jac->nsplits); 361 *n = jac->nsplits; 362 PetscFunctionReturn(0); 363 } 364 EXTERN_C_END 365 366 #undef __FUNCT__ 367 #define __FUNCT__ "PCFieldSplitSetFields" 368 /*@ 369 PCFieldSplitSetFields - Sets the fields for one particular split in the field split preconditioner 370 371 Collective on PC 372 373 Input Parameters: 374 + pc - the preconditioner context 375 . n - the number of fields in this split 376 . fields - the fields in this split 377 378 Level: intermediate 379 380 .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT 381 382 @*/ 383 PetscErrorCode PCFieldSplitSetFields(PC pc,PetscInt n, PetscInt *fields) 384 { 385 PetscErrorCode ierr,(*f)(PC,PetscInt,PetscInt *); 386 387 PetscFunctionBegin; 388 PetscValidHeaderSpecific(pc,PC_COOKIE,1); 389 ierr = PetscObjectQueryFunction((PetscObject)pc,"PCFieldSplitSetFields_C",(void (**)(void))&f);CHKERRQ(ierr); 390 if (f) { 391 ierr = (*f)(pc,n,fields);CHKERRQ(ierr); 392 } 393 PetscFunctionReturn(0); 394 } 395 396 #undef __FUNCT__ 397 #define __FUNCT__ "PCFieldSplitGetSubKSP" 398 /*@C 399 PCFieldSplitGetSubKSP - Gets the KSP contexts for all splits 400 401 Collective on KSP 402 403 Input Parameter: 404 . pc - the preconditioner context 405 406 Output Parameters: 407 + n - the number of split 408 - pc - the array of KSP contexts 409 410 Note: 411 After PCFieldSplitGetSubKSP() the array of KSPs IS to be freed 412 413 You must call KSPSetUp() before calling PCFieldSplitGetSubKSP(). 414 415 Level: advanced 416 417 .seealso: PCFIELDSPLIT 418 @*/ 419 PetscErrorCode PCFieldSplitGetSubKSP(PC pc,PetscInt *n,KSP *subksp[]) 420 { 421 PetscErrorCode ierr,(*f)(PC,PetscInt*,KSP **); 422 423 PetscFunctionBegin; 424 PetscValidHeaderSpecific(pc,PC_COOKIE,1); 425 PetscValidIntPointer(n,2); 426 ierr = PetscObjectQueryFunction((PetscObject)pc,"PCFieldSplitGetSubKSP_C",(void (**)(void))&f);CHKERRQ(ierr); 427 if (f) { 428 ierr = (*f)(pc,n,subksp);CHKERRQ(ierr); 429 } else { 430 SETERRQ(PETSC_ERR_ARG_WRONG,"Cannot get subksp for this type of PC"); 431 } 432 PetscFunctionReturn(0); 433 } 434 435 EXTERN_C_BEGIN 436 #undef __FUNCT__ 437 #define __FUNCT__ "PCFieldSplitSetType_FieldSplit" 438 PetscErrorCode PCFieldSplitSetType_FieldSplit(PC pc,PCCompositeType type) 439 { 440 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 441 442 PetscFunctionBegin; 443 jac->type = type; 444 PetscFunctionReturn(0); 445 } 446 EXTERN_C_END 447 448 #undef __FUNCT__ 449 #define __FUNCT__ "PCFieldSplitSetType" 450 /*@C 451 PCFieldSplitSetType - Sets the type of fieldsplit preconditioner. 452 453 Collective on PC 454 455 Input Parameter: 456 . pc - the preconditioner context 457 . type - PC_COMPOSITE_ADDITIVE (default), PC_COMPOSITE_MULTIPLICATIVE 458 459 Options Database Key: 460 . -pc_fieldsplit_type <type: one of multiplicative, additive, special> - Sets fieldsplit preconditioner type 461 462 Level: Developer 463 464 .keywords: PC, set, type, composite preconditioner, additive, multiplicative 465 466 .seealso: PCCompositeSetType() 467 468 @*/ 469 PetscErrorCode PCFieldSplitSetType(PC pc,PCCompositeType type) 470 { 471 PetscErrorCode ierr,(*f)(PC,PCCompositeType); 472 473 PetscFunctionBegin; 474 PetscValidHeaderSpecific(pc,PC_COOKIE,1); 475 ierr = PetscObjectQueryFunction((PetscObject)pc,"PCFieldSplitSetType_C",(void (**)(void))&f);CHKERRQ(ierr); 476 if (f) { 477 ierr = (*f)(pc,type);CHKERRQ(ierr); 478 } 479 PetscFunctionReturn(0); 480 } 481 482 /* -------------------------------------------------------------------------------------*/ 483 /*MC 484 PCFieldSplit - Preconditioner created by combining seperate preconditioners for individual 485 fields or groups of fields 486 487 488 To set options on the solvers for each block append -sub_ to all the PC 489 options database keys. For example, -sub_pc_type ilu -sub_pc_ilu_levels 1 490 491 To set the options on the solvers seperate for each block call PCFieldSplitGetSubKSP() 492 and set the options directly on the resulting KSP object 493 494 Level: intermediate 495 496 Options Database Keys: 497 + -pc_splitfield_%d_fields <a,b,..> - indicates the fields to be used in the %d'th split 498 . -pc_splitfield_default - automatically add any fields to additional splits that have not 499 been supplied explicitly by -pc_splitfield_%d_fields 500 - -pc_splitfield_type <additive,multiplicative> 501 502 Concepts: physics based preconditioners 503 504 .seealso: PCCreate(), PCSetType(), PCType (for list of available types), PC, 505 PCFieldSplitGetSubKSP(), PCFieldSplitSetFields() 506 M*/ 507 508 EXTERN_C_BEGIN 509 #undef __FUNCT__ 510 #define __FUNCT__ "PCCreate_FieldSplit" 511 PetscErrorCode PCCreate_FieldSplit(PC pc) 512 { 513 PetscErrorCode ierr; 514 PC_FieldSplit *jac; 515 516 PetscFunctionBegin; 517 ierr = PetscNew(PC_FieldSplit,&jac);CHKERRQ(ierr); 518 PetscLogObjectMemory(pc,sizeof(PC_FieldSplit)); 519 ierr = PetscMemzero(jac,sizeof(PC_FieldSplit));CHKERRQ(ierr); 520 jac->bs = -1; 521 jac->nsplits = 0; 522 jac->type = PC_COMPOSITE_ADDITIVE; 523 pc->data = (void*)jac; 524 525 pc->ops->apply = PCApply_FieldSplit; 526 pc->ops->setup = PCSetUp_FieldSplit; 527 pc->ops->destroy = PCDestroy_FieldSplit; 528 pc->ops->setfromoptions = PCSetFromOptions_FieldSplit; 529 pc->ops->view = PCView_FieldSplit; 530 pc->ops->applyrichardson = 0; 531 532 ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitGetSubKSP_C","PCFieldSplitGetSubKSP_FieldSplit", 533 PCFieldSplitGetSubKSP_FieldSplit);CHKERRQ(ierr); 534 ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetFields_C","PCFieldSplitSetFields_FieldSplit", 535 PCFieldSplitSetFields_FieldSplit);CHKERRQ(ierr); 536 ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetType_C","PCFieldSplitSetType_FieldSplit", 537 PCFieldSplitSetType_FieldSplit);CHKERRQ(ierr); 538 PetscFunctionReturn(0); 539 } 540 EXTERN_C_END 541 542 543