1 #define PETSCKSP_DLL 2 3 /* 4 This file defines a "solve the problem redundantly on each subgroup of processor" preconditioner. 5 */ 6 #include "private/pcimpl.h" /*I "petscpc.h" I*/ 7 #include "petscksp.h" 8 9 typedef struct { 10 KSP ksp; 11 PC pc; /* actual preconditioner used on each processor */ 12 Vec xsub,ysub; /* vectors of a subcommunicator to hold parallel vectors of pc->comm */ 13 Vec xdup,ydup; /* parallel vector that congregates xsub or ysub facilitating vector scattering */ 14 Mat pmats; /* matrix and optional preconditioner matrix belong to a subcommunicator */ 15 VecScatter scatterin,scatterout; /* scatter used to move all values to each processor group (subcommunicator) */ 16 PetscTruth useparallelmat; 17 PetscSubcomm psubcomm; 18 PetscInt nsubcomm; /* num of data structure PetscSubcomm */ 19 } PC_Redundant; 20 21 #undef __FUNCT__ 22 #define __FUNCT__ "PCView_Redundant" 23 static PetscErrorCode PCView_Redundant(PC pc,PetscViewer viewer) 24 { 25 PC_Redundant *red = (PC_Redundant*)pc->data; 26 PetscErrorCode ierr; 27 PetscMPIInt rank; 28 PetscTruth iascii,isstring; 29 PetscViewer sviewer,subviewer; 30 PetscInt color = red->psubcomm->color; 31 32 PetscFunctionBegin; 33 ierr = MPI_Comm_rank(pc->comm,&rank);CHKERRQ(ierr); 34 ierr = PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&iascii);CHKERRQ(ierr); 35 ierr = PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_STRING,&isstring);CHKERRQ(ierr); 36 if (iascii) { 37 ierr = PetscViewerASCIIPrintf(viewer," Redundant preconditioner: First (color=0) of %D PCs follows\n",red->nsubcomm);CHKERRQ(ierr); 38 ierr = PetscViewerGetSubcomm(viewer,red->pc->comm,&subviewer);CHKERRQ(ierr); 39 if (!color) { /* only view first redundant pc */ 40 ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 41 ierr = KSPView(red->ksp,subviewer);CHKERRQ(ierr); 42 ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 43 } 44 ierr = PetscViewerRestoreSubcomm(viewer,red->pc->comm,&subviewer);CHKERRQ(ierr); 45 } else if (isstring) { /* not test it yet! */ 46 ierr = PetscViewerStringSPrintf(viewer," Redundant solver preconditioner");CHKERRQ(ierr); 47 ierr = PetscViewerGetSingleton(viewer,&sviewer);CHKERRQ(ierr); 48 if (!rank) { 49 ierr = KSPView(red->ksp,sviewer);CHKERRQ(ierr); 50 } 51 ierr = PetscViewerRestoreSingleton(viewer,&sviewer);CHKERRQ(ierr); 52 } else { 53 SETERRQ1(PETSC_ERR_SUP,"Viewer type %s not supported for PC redundant",((PetscObject)viewer)->type_name); 54 } 55 PetscFunctionReturn(0); 56 } 57 58 #include "include/private/matimpl.h" /*I "petscmat.h" I*/ 59 #undef __FUNCT__ 60 #define __FUNCT__ "PCSetUp_Redundant" 61 static PetscErrorCode PCSetUp_Redundant(PC pc) 62 { 63 PC_Redundant *red = (PC_Redundant*)pc->data; 64 PetscErrorCode ierr; 65 PetscInt mstart,mend,mlocal,m,mlocal_sub,rstart_sub,rend_sub,mloc_sub; 66 PetscMPIInt size; 67 MatReuse reuse = MAT_INITIAL_MATRIX; 68 MatStructure str = DIFFERENT_NONZERO_PATTERN; 69 MPI_Comm comm = pc->comm,subcomm; 70 Vec vec; 71 PetscMPIInt subsize,subrank; 72 const char *prefix; 73 74 PetscFunctionBegin; 75 ierr = MatGetVecs(pc->pmat,&vec,0);CHKERRQ(ierr); 76 ierr = VecGetSize(vec,&m);CHKERRQ(ierr); 77 78 if (!pc->setupcalled) { 79 ierr = PetscSubcommCreate(comm,red->nsubcomm,&red->psubcomm);CHKERRQ(ierr); 80 ierr = PetscLogObjectMemory(pc,sizeof(PetscSubcomm));CHKERRQ(ierr); 81 82 /* create a new PC that processors in each subcomm have copy of */ 83 subcomm = red->psubcomm->comm; 84 KSP subksp; 85 PC subpc; 86 ierr = KSPCreate(subcomm,&subksp);CHKERRQ(ierr); 87 ierr = PetscLogObjectParent(pc,subksp);CHKERRQ(ierr); 88 ierr = KSPSetType(subksp,KSPPREONLY);CHKERRQ(ierr); 89 ierr = KSPGetPC(subksp,&subpc);CHKERRQ(ierr); 90 ierr = PCSetType(subpc,PCLU);CHKERRQ(ierr); 91 ierr = PCGetOptionsPrefix(pc,&prefix);CHKERRQ(ierr); 92 ierr = KSPSetOptionsPrefix(subksp,prefix);CHKERRQ(ierr); 93 ierr = KSPAppendOptionsPrefix(subksp,"redundant_");CHKERRQ(ierr); 94 ierr = PCSetOptionsPrefix(subpc,prefix);CHKERRQ(ierr); 95 ierr = PCAppendOptionsPrefix(subpc,"redundant_ksp_");CHKERRQ(ierr); 96 red->ksp = subksp; 97 red->pc = subpc; 98 99 /* create working vectors xsub/ysub and xdup/ydup */ 100 ierr = VecGetLocalSize(vec,&mlocal);CHKERRQ(ierr); 101 ierr = VecGetOwnershipRange(vec,&mstart,&mend);CHKERRQ(ierr); 102 103 /* get local size of xsub/ysub */ 104 ierr = MPI_Comm_size(subcomm,&subsize);CHKERRQ(ierr); 105 ierr = MPI_Comm_rank(subcomm,&subrank);CHKERRQ(ierr); 106 rstart_sub = pc->pmat->rmap.range[red->psubcomm->n*subrank]; /* rstart in xsub/ysub */ 107 if (subrank+1 < subsize){ 108 rend_sub = pc->pmat->rmap.range[red->psubcomm->n*(subrank+1)]; 109 } else { 110 rend_sub = m; 111 } 112 mloc_sub = rend_sub - rstart_sub; 113 ierr = VecCreateMPI(subcomm,mloc_sub,PETSC_DECIDE,&red->ysub);CHKERRQ(ierr); 114 /* create xsub with empty local arrays, because xdup's arrays will be placed into it */ 115 ierr = VecCreateMPIWithArray(subcomm,mloc_sub,PETSC_DECIDE,PETSC_NULL,&red->xsub);CHKERRQ(ierr); 116 117 /* create xdup and ydup. ydup has empty local arrays because ysub's arrays will be place into it. 118 Note: we use communicator dupcomm, not pc->comm! */ 119 ierr = VecCreateMPI(red->psubcomm->dupparent,mloc_sub,PETSC_DECIDE,&red->xdup);CHKERRQ(ierr); 120 ierr = VecCreateMPIWithArray(red->psubcomm->dupparent,mloc_sub,PETSC_DECIDE,PETSC_NULL,&red->ydup);CHKERRQ(ierr); 121 122 /* create vec scatters */ 123 if (!red->scatterin){ 124 IS is1,is2; 125 PetscInt *idx1,*idx2,i,j,k; 126 127 ierr = PetscMalloc(2*red->psubcomm->n*mlocal*sizeof(PetscInt),&idx1);CHKERRQ(ierr); 128 idx2 = idx1 + red->psubcomm->n*mlocal; 129 j = 0; 130 for (k=0; k<red->psubcomm->n; k++){ 131 for (i=mstart; i<mend; i++){ 132 idx1[j] = i; 133 idx2[j++] = i + m*k; 134 } 135 } 136 ierr = ISCreateGeneral(comm,red->psubcomm->n*mlocal,idx1,&is1);CHKERRQ(ierr); 137 ierr = ISCreateGeneral(comm,red->psubcomm->n*mlocal,idx2,&is2);CHKERRQ(ierr); 138 ierr = VecScatterCreate(vec,is1,red->xdup,is2,&red->scatterin);CHKERRQ(ierr); 139 ierr = ISDestroy(is1);CHKERRQ(ierr); 140 ierr = ISDestroy(is2);CHKERRQ(ierr); 141 142 ierr = ISCreateStride(comm,mlocal,mstart+ red->psubcomm->color*m,1,&is1);CHKERRQ(ierr); 143 ierr = ISCreateStride(comm,mlocal,mstart,1,&is2);CHKERRQ(ierr); 144 ierr = VecScatterCreate(red->xdup,is1,vec,is2,&red->scatterout);CHKERRQ(ierr); 145 ierr = ISDestroy(is1);CHKERRQ(ierr); 146 ierr = ISDestroy(is2);CHKERRQ(ierr); 147 ierr = PetscFree(idx1);CHKERRQ(ierr); 148 } 149 } 150 ierr = VecDestroy(vec);CHKERRQ(ierr); 151 152 /* if pmatrix set by user is sequential then we do not need to gather the parallel matrix */ 153 ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr); 154 if (size == 1) { 155 red->useparallelmat = PETSC_FALSE; 156 } 157 158 if (red->useparallelmat) { 159 if (pc->setupcalled == 1 && pc->flag == DIFFERENT_NONZERO_PATTERN) { 160 /* destroy old matrices */ 161 if (red->pmats) { 162 ierr = MatDestroy(red->pmats);CHKERRQ(ierr); 163 } 164 } else if (pc->setupcalled == 1) { 165 reuse = MAT_REUSE_MATRIX; 166 str = SAME_NONZERO_PATTERN; 167 } 168 169 /* grab the parallel matrix and put it into processors of a subcomminicator */ 170 /*--------------------------------------------------------------------------*/ 171 ierr = VecGetLocalSize(red->ysub,&mlocal_sub);CHKERRQ(ierr); 172 ierr = MatGetRedundantMatrix(pc->pmat,red->psubcomm->n,red->psubcomm->comm,mlocal_sub,reuse,&red->pmats);CHKERRQ(ierr); 173 174 /* tell PC of the subcommunicator its operators */ 175 ierr = PCSetOperators(red->pc,red->pmats,red->pmats,str);CHKERRQ(ierr); 176 } else { 177 ierr = PCSetOperators(red->pc,pc->mat,pc->pmat,pc->flag);CHKERRQ(ierr); 178 } 179 if (pc->setfromoptionscalled){ 180 ierr = KSPSetFromOptions(red->ksp);CHKERRQ(ierr); 181 } 182 ierr = KSPSetUp(red->ksp);CHKERRQ(ierr); 183 PetscFunctionReturn(0); 184 } 185 186 #undef __FUNCT__ 187 #define __FUNCT__ "PCApply_Redundant" 188 static PetscErrorCode PCApply_Redundant(PC pc,Vec x,Vec y) 189 { 190 PC_Redundant *red = (PC_Redundant*)pc->data; 191 PetscErrorCode ierr; 192 PetscScalar *array; 193 194 PetscFunctionBegin; 195 /* scatter x to xdup */ 196 ierr = VecScatterBegin(x,red->xdup,INSERT_VALUES,SCATTER_FORWARD,red->scatterin);CHKERRQ(ierr); 197 ierr = VecScatterEnd(x,red->xdup,INSERT_VALUES,SCATTER_FORWARD,red->scatterin);CHKERRQ(ierr); 198 199 /* place xdup's local array into xsub */ 200 ierr = VecGetArray(red->xdup,&array);CHKERRQ(ierr); 201 ierr = VecPlaceArray(red->xsub,(const PetscScalar*)array);CHKERRQ(ierr); 202 203 /* apply preconditioner on each processor */ 204 ierr = PCApply(red->pc,red->xsub,red->ysub);CHKERRQ(ierr); 205 ierr = VecResetArray(red->xsub);CHKERRQ(ierr); 206 ierr = VecRestoreArray(red->xdup,&array);CHKERRQ(ierr); 207 208 /* place ysub's local array into ydup */ 209 ierr = VecGetArray(red->ysub,&array);CHKERRQ(ierr); 210 ierr = VecPlaceArray(red->ydup,(const PetscScalar*)array);CHKERRQ(ierr); 211 212 /* scatter ydup to y */ 213 ierr = VecScatterBegin(red->ydup,y,INSERT_VALUES,SCATTER_FORWARD,red->scatterout);CHKERRQ(ierr); 214 ierr = VecScatterEnd(red->ydup,y,INSERT_VALUES,SCATTER_FORWARD,red->scatterout);CHKERRQ(ierr); 215 ierr = VecResetArray(red->ydup);CHKERRQ(ierr); 216 ierr = VecRestoreArray(red->ysub,&array);CHKERRQ(ierr); 217 PetscFunctionReturn(0); 218 } 219 220 #undef __FUNCT__ 221 #define __FUNCT__ "PCDestroy_Redundant" 222 static PetscErrorCode PCDestroy_Redundant(PC pc) 223 { 224 PC_Redundant *red = (PC_Redundant*)pc->data; 225 PetscErrorCode ierr; 226 227 PetscFunctionBegin; 228 if (red->scatterin) {ierr = VecScatterDestroy(red->scatterin);CHKERRQ(ierr);} 229 if (red->scatterout) {ierr = VecScatterDestroy(red->scatterout);CHKERRQ(ierr);} 230 if (red->ysub) {ierr = VecDestroy(red->ysub);CHKERRQ(ierr);} 231 if (red->xsub) {ierr = VecDestroy(red->xsub);CHKERRQ(ierr);} 232 if (red->xdup) {ierr = VecDestroy(red->xdup);CHKERRQ(ierr);} 233 if (red->ydup) {ierr = VecDestroy(red->ydup);CHKERRQ(ierr);} 234 if (red->pmats) { 235 ierr = MatDestroy(red->pmats);CHKERRQ(ierr); 236 } 237 if (red->psubcomm) {ierr = PetscSubcommDestroy(red->psubcomm);CHKERRQ(ierr);} 238 if (red->ksp) {ierr = KSPDestroy(red->ksp);CHKERRQ(ierr);} 239 ierr = PetscFree(red);CHKERRQ(ierr); 240 PetscFunctionReturn(0); 241 } 242 243 #undef __FUNCT__ 244 #define __FUNCT__ "PCSetFromOptions_Redundant" 245 static PetscErrorCode PCSetFromOptions_Redundant(PC pc) 246 { 247 PetscErrorCode ierr; 248 PC_Redundant *red = (PC_Redundant*)pc->data; 249 250 PetscFunctionBegin; 251 ierr = PetscOptionsHead("Redundant options");CHKERRQ(ierr); 252 ierr = PetscOptionsInt("-pc_redundant_number","Number of redundant pc","PCRedundantSetNumber",red->nsubcomm,&red->nsubcomm,0);CHKERRQ(ierr); 253 ierr = PetscOptionsTail();CHKERRQ(ierr); 254 PetscFunctionReturn(0); 255 } 256 257 EXTERN_C_BEGIN 258 #undef __FUNCT__ 259 #define __FUNCT__ "PCRedundantSetNumber_Redundant" 260 PetscErrorCode PETSCKSP_DLLEXPORT PCRedundantSetNumber_Redundant(PC pc,PetscInt nreds) 261 { 262 PC_Redundant *red = (PC_Redundant*)pc->data; 263 264 PetscFunctionBegin; 265 red->nsubcomm = nreds; 266 PetscFunctionReturn(0); 267 } 268 EXTERN_C_END 269 270 #undef __FUNCT__ 271 #define __FUNCT__ "PCRedundantSetNumber" 272 /*@ 273 PCRedundantSetNumber - Sets the number of redundant preconditioner contexts. 274 275 Collective on PC 276 277 Input Parameters: 278 + pc - the preconditioner context 279 - nredundant - number of redundant preconditioner contexts; for example if you are using 64 MPI processes and 280 use an nredundant of 4 there will be 4 parallel solves each on 16 = 64/4 processes. 281 282 Level: advanced 283 284 .keywords: PC, redundant solve 285 @*/ 286 PetscErrorCode PETSCKSP_DLLEXPORT PCRedundantSetNumber(PC pc,PetscInt nredundant) 287 { 288 PetscErrorCode ierr,(*f)(PC,PetscInt); 289 290 PetscFunctionBegin; 291 PetscValidHeaderSpecific(pc,PC_COOKIE,1); 292 if (nredundant <= 0) SETERRQ1(PETSC_ERR_ARG_WRONG, "num of redundant pc %D must be positive",nredundant); 293 ierr = PetscObjectQueryFunction((PetscObject)pc,"PCRedundantSetNumber_C",(void (**)(void))&f);CHKERRQ(ierr); 294 if (f) { 295 ierr = (*f)(pc,nredundant);CHKERRQ(ierr); 296 } 297 PetscFunctionReturn(0); 298 } 299 300 EXTERN_C_BEGIN 301 #undef __FUNCT__ 302 #define __FUNCT__ "PCRedundantSetScatter_Redundant" 303 PetscErrorCode PETSCKSP_DLLEXPORT PCRedundantSetScatter_Redundant(PC pc,VecScatter in,VecScatter out) 304 { 305 PC_Redundant *red = (PC_Redundant*)pc->data; 306 PetscErrorCode ierr; 307 308 PetscFunctionBegin; 309 ierr = PetscObjectReference((PetscObject)in);CHKERRQ(ierr); 310 if (red->scatterin) { ierr = VecScatterDestroy(red->scatterin);CHKERRQ(ierr); } 311 red->scatterin = in; 312 ierr = PetscObjectReference((PetscObject)out);CHKERRQ(ierr); 313 if (red->scatterout) { ierr = VecScatterDestroy(red->scatterout);CHKERRQ(ierr); } 314 red->scatterout = out; 315 PetscFunctionReturn(0); 316 } 317 EXTERN_C_END 318 319 #undef __FUNCT__ 320 #define __FUNCT__ "PCRedundantSetScatter" 321 /*@ 322 PCRedundantSetScatter - Sets the scatter used to copy values into the 323 redundant local solve and the scatter to move them back into the global 324 vector. 325 326 Collective on PC 327 328 Input Parameters: 329 + pc - the preconditioner context 330 . in - the scatter to move the values in 331 - out - the scatter to move them out 332 333 Level: advanced 334 335 .keywords: PC, redundant solve 336 @*/ 337 PetscErrorCode PETSCKSP_DLLEXPORT PCRedundantSetScatter(PC pc,VecScatter in,VecScatter out) 338 { 339 PetscErrorCode ierr,(*f)(PC,VecScatter,VecScatter); 340 341 PetscFunctionBegin; 342 PetscValidHeaderSpecific(pc,PC_COOKIE,1); 343 PetscValidHeaderSpecific(in,VEC_SCATTER_COOKIE,2); 344 PetscValidHeaderSpecific(out,VEC_SCATTER_COOKIE,3); 345 ierr = PetscObjectQueryFunction((PetscObject)pc,"PCRedundantSetScatter_C",(void (**)(void))&f);CHKERRQ(ierr); 346 if (f) { 347 ierr = (*f)(pc,in,out);CHKERRQ(ierr); 348 } 349 PetscFunctionReturn(0); 350 } 351 352 EXTERN_C_BEGIN 353 #undef __FUNCT__ 354 #define __FUNCT__ "PCRedundantGetPC_Redundant" 355 PetscErrorCode PETSCKSP_DLLEXPORT PCRedundantGetPC_Redundant(PC pc,PC *innerpc) 356 { 357 PC_Redundant *red = (PC_Redundant*)pc->data; 358 359 PetscFunctionBegin; 360 *innerpc = red->pc; 361 PetscFunctionReturn(0); 362 } 363 EXTERN_C_END 364 365 #undef __FUNCT__ 366 #define __FUNCT__ "PCRedundantGetPC" 367 /*@ 368 PCRedundantGetPC - Gets the sequential PC created by the redundant PC. 369 370 Not Collective 371 372 Input Parameter: 373 . pc - the preconditioner context 374 375 Output Parameter: 376 . innerpc - the sequential PC 377 378 Level: advanced 379 380 .keywords: PC, redundant solve 381 @*/ 382 PetscErrorCode PETSCKSP_DLLEXPORT PCRedundantGetPC(PC pc,PC *innerpc) 383 { 384 PetscErrorCode ierr,(*f)(PC,PC*); 385 386 PetscFunctionBegin; 387 PetscValidHeaderSpecific(pc,PC_COOKIE,1); 388 PetscValidPointer(innerpc,2); 389 ierr = PetscObjectQueryFunction((PetscObject)pc,"PCRedundantGetPC_C",(void (**)(void))&f);CHKERRQ(ierr); 390 if (f) { 391 ierr = (*f)(pc,innerpc);CHKERRQ(ierr); 392 } 393 PetscFunctionReturn(0); 394 } 395 396 EXTERN_C_BEGIN 397 #undef __FUNCT__ 398 #define __FUNCT__ "PCRedundantGetOperators_Redundant" 399 PetscErrorCode PETSCKSP_DLLEXPORT PCRedundantGetOperators_Redundant(PC pc,Mat *mat,Mat *pmat) 400 { 401 PC_Redundant *red = (PC_Redundant*)pc->data; 402 403 PetscFunctionBegin; 404 if (mat) *mat = red->pmats; 405 if (pmat) *pmat = red->pmats; 406 PetscFunctionReturn(0); 407 } 408 EXTERN_C_END 409 410 #undef __FUNCT__ 411 #define __FUNCT__ "PCRedundantGetOperators" 412 /*@ 413 PCRedundantGetOperators - gets the sequential matrix and preconditioner matrix 414 415 Not Collective 416 417 Input Parameter: 418 . pc - the preconditioner context 419 420 Output Parameters: 421 + mat - the matrix 422 - pmat - the (possibly different) preconditioner matrix 423 424 Level: advanced 425 426 .keywords: PC, redundant solve 427 @*/ 428 PetscErrorCode PETSCKSP_DLLEXPORT PCRedundantGetOperators(PC pc,Mat *mat,Mat *pmat) 429 { 430 PetscErrorCode ierr,(*f)(PC,Mat*,Mat*); 431 432 PetscFunctionBegin; 433 PetscValidHeaderSpecific(pc,PC_COOKIE,1); 434 if (mat) PetscValidPointer(mat,2); 435 if (pmat) PetscValidPointer(pmat,3); 436 ierr = PetscObjectQueryFunction((PetscObject)pc,"PCRedundantGetOperators_C",(void (**)(void))&f);CHKERRQ(ierr); 437 if (f) { 438 ierr = (*f)(pc,mat,pmat);CHKERRQ(ierr); 439 } 440 PetscFunctionReturn(0); 441 } 442 443 /* -------------------------------------------------------------------------------------*/ 444 /*MC 445 PCREDUNDANT - Runs a preconditioner for the entire problem on subgroups of processors 446 447 Options for the redundant preconditioners can be set with -redundant_pc_xxx 448 449 Options Database: 450 . -pc_redundant_number <n> - number of redundant solves, for example if you are using 64 MPI processes and 451 use an n of 4 there will be 4 parallel solves each on 16 = 64/4 processes. 452 453 Level: intermediate 454 455 .seealso: PCCreate(), PCSetType(), PCType (for list of available types), PCRedundantSetScatter(), 456 PCRedundantGetPC(), PCRedundantGetOperators(), PCRedundantSetNumber() 457 M*/ 458 459 EXTERN_C_BEGIN 460 #undef __FUNCT__ 461 #define __FUNCT__ "PCCreate_Redundant" 462 PetscErrorCode PETSCKSP_DLLEXPORT PCCreate_Redundant(PC pc) 463 { 464 PetscErrorCode ierr; 465 PC_Redundant *red; 466 PetscMPIInt size; 467 468 PetscFunctionBegin; 469 ierr = PetscNew(PC_Redundant,&red);CHKERRQ(ierr); 470 ierr = PetscLogObjectMemory(pc,sizeof(PC_Redundant));CHKERRQ(ierr); 471 ierr = MPI_Comm_size(pc->comm,&size);CHKERRQ(ierr); 472 red->nsubcomm = size; 473 red->useparallelmat = PETSC_TRUE; 474 pc->data = (void*)red; 475 476 pc->ops->apply = PCApply_Redundant; 477 pc->ops->applytranspose = 0; 478 pc->ops->setup = PCSetUp_Redundant; 479 pc->ops->destroy = PCDestroy_Redundant; 480 pc->ops->setfromoptions = PCSetFromOptions_Redundant; 481 pc->ops->view = PCView_Redundant; 482 ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCRedundantSetScatter_C","PCRedundantSetScatter_Redundant", 483 PCRedundantSetScatter_Redundant);CHKERRQ(ierr); 484 ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCRedundantSetNumber_C","PCRedundantSetNumber_Redundant", 485 PCRedundantSetNumber_Redundant);CHKERRQ(ierr); 486 ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCRedundantGetPC_C","PCRedundantGetPC_Redundant", 487 PCRedundantGetPC_Redundant);CHKERRQ(ierr); 488 ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCRedundantGetOperators_C","PCRedundantGetOperators_Redundant", 489 PCRedundantGetOperators_Redundant);CHKERRQ(ierr); 490 PetscFunctionReturn(0); 491 } 492 EXTERN_C_END 493