1 #define PETSCKSP_DLL 2 3 /* 4 5 */ 6 #include "private/pcimpl.h" /*I "petscpc.h" I*/ 7 8 const char *PCFieldSplitSchurPreTypes[] = {"self","diag","user","PCFieldSplitSchurPreType","PC_FIELDSPLIT_SCHUR_PRE_",0}; 9 10 typedef struct _PC_FieldSplitLink *PC_FieldSplitLink; 11 struct _PC_FieldSplitLink { 12 KSP ksp; 13 Vec x,y; 14 PetscInt nfields; 15 PetscInt *fields; 16 VecScatter sctx; 17 IS is; 18 PC_FieldSplitLink next,previous; 19 }; 20 21 typedef struct { 22 PCCompositeType type; 23 PetscTruth defaultsplit; /* Flag for a system with a set of 'k' scalar fields with the same layout (and bs = k) */ 24 PetscTruth realdiagonal; /* Flag to use the diagonal blocks of mat preconditioned by pmat, instead of just pmat */ 25 PetscInt bs; /* Block size for IS and Mat structures */ 26 PetscInt nsplits; /* Number of field divisions defined */ 27 Vec *x,*y,w1,w2; 28 Mat *mat; /* The diagonal block for each split */ 29 Mat *pmat; /* The preconditioning diagonal block for each split */ 30 Mat *Afield; /* The rows of the matrix associated with each split */ 31 PetscTruth issetup; 32 /* Only used when Schur complement preconditioning is used */ 33 Mat B; /* The (0,1) block */ 34 Mat C; /* The (1,0) block */ 35 Mat schur; /* The Schur complement S = D - C A^{-1} B */ 36 Mat schur_user; /* User-provided preconditioning matrix for the Schur complement */ 37 PCFieldSplitSchurPreType schurpre; /* Determines which preconditioning matrix is used for the Schur complement */ 38 KSP kspschur; /* The solver for S */ 39 PC_FieldSplitLink head; 40 } PC_FieldSplit; 41 42 /* 43 Notes: there is no particular reason that pmat, x, and y are stored as arrays in PC_FieldSplit instead of 44 inside PC_FieldSplitLink, just historical. If you want to be able to add new fields after already using the 45 PC you could change this. 46 */ 47 48 /* This helper is so that setting a user-provided preconditioning matrix is orthogonal to choosing to use it. This way the 49 * application-provided FormJacobian can provide this matrix without interfering with the user's (command-line) choices. */ 50 static Mat FieldSplitSchurPre(PC_FieldSplit *jac) 51 { 52 switch (jac->schurpre) { 53 case PC_FIELDSPLIT_SCHUR_PRE_SELF: return jac->schur; 54 case PC_FIELDSPLIT_SCHUR_PRE_DIAG: return jac->pmat[1]; 55 case PC_FIELDSPLIT_SCHUR_PRE_USER: /* Use a user-provided matrix if it is given, otherwise diagonal block */ 56 default: 57 return jac->schur_user ? jac->schur_user : jac->pmat[1]; 58 } 59 } 60 61 62 #undef __FUNCT__ 63 #define __FUNCT__ "PCView_FieldSplit" 64 static PetscErrorCode PCView_FieldSplit(PC pc,PetscViewer viewer) 65 { 66 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 67 PetscErrorCode ierr; 68 PetscTruth iascii; 69 PetscInt i,j; 70 PC_FieldSplitLink ilink = jac->head; 71 72 PetscFunctionBegin; 73 ierr = PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&iascii);CHKERRQ(ierr); 74 if (iascii) { 75 ierr = PetscViewerASCIIPrintf(viewer," FieldSplit with %s composition: total splits = %D, blocksize = %D\n",PCCompositeTypes[jac->type],jac->nsplits,jac->bs);CHKERRQ(ierr); 76 ierr = PetscViewerASCIIPrintf(viewer," Solver info for each split is in the following KSP objects:\n");CHKERRQ(ierr); 77 ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 78 for (i=0; i<jac->nsplits; i++) { 79 if (ilink->fields) { 80 ierr = PetscViewerASCIIPrintf(viewer,"Split number %D Fields ",i);CHKERRQ(ierr); 81 ierr = PetscViewerASCIIUseTabs(viewer,PETSC_FALSE);CHKERRQ(ierr); 82 for (j=0; j<ilink->nfields; j++) { 83 if (j > 0) { 84 ierr = PetscViewerASCIIPrintf(viewer,",");CHKERRQ(ierr); 85 } 86 ierr = PetscViewerASCIIPrintf(viewer," %D",ilink->fields[j]);CHKERRQ(ierr); 87 } 88 ierr = PetscViewerASCIIPrintf(viewer,"\n");CHKERRQ(ierr); 89 ierr = PetscViewerASCIIUseTabs(viewer,PETSC_TRUE);CHKERRQ(ierr); 90 } else { 91 ierr = PetscViewerASCIIPrintf(viewer,"Split number %D Defined by IS\n",i);CHKERRQ(ierr); 92 } 93 ierr = KSPView(ilink->ksp,viewer);CHKERRQ(ierr); 94 ilink = ilink->next; 95 } 96 ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 97 } else { 98 SETERRQ1(PETSC_ERR_SUP,"Viewer type %s not supported for PCFieldSplit",((PetscObject)viewer)->type_name); 99 } 100 PetscFunctionReturn(0); 101 } 102 103 #undef __FUNCT__ 104 #define __FUNCT__ "PCView_FieldSplit_Schur" 105 static PetscErrorCode PCView_FieldSplit_Schur(PC pc,PetscViewer viewer) 106 { 107 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 108 PetscErrorCode ierr; 109 PetscTruth iascii; 110 PetscInt i,j; 111 PC_FieldSplitLink ilink = jac->head; 112 KSP ksp; 113 114 PetscFunctionBegin; 115 ierr = PetscTypeCompare((PetscObject)viewer,PETSC_VIEWER_ASCII,&iascii);CHKERRQ(ierr); 116 if (iascii) { 117 ierr = PetscViewerASCIIPrintf(viewer," FieldSplit with Schur preconditioner, blocksize = %D\n",jac->bs);CHKERRQ(ierr); 118 ierr = PetscViewerASCIIPrintf(viewer," Split info:\n");CHKERRQ(ierr); 119 ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 120 for (i=0; i<jac->nsplits; i++) { 121 if (ilink->fields) { 122 ierr = PetscViewerASCIIPrintf(viewer,"Split number %D Fields ",i);CHKERRQ(ierr); 123 ierr = PetscViewerASCIIUseTabs(viewer,PETSC_FALSE);CHKERRQ(ierr); 124 for (j=0; j<ilink->nfields; j++) { 125 if (j > 0) { 126 ierr = PetscViewerASCIIPrintf(viewer,",");CHKERRQ(ierr); 127 } 128 ierr = PetscViewerASCIIPrintf(viewer," %D",ilink->fields[j]);CHKERRQ(ierr); 129 } 130 ierr = PetscViewerASCIIPrintf(viewer,"\n");CHKERRQ(ierr); 131 ierr = PetscViewerASCIIUseTabs(viewer,PETSC_TRUE);CHKERRQ(ierr); 132 } else { 133 ierr = PetscViewerASCIIPrintf(viewer,"Split number %D Defined by IS\n",i);CHKERRQ(ierr); 134 } 135 ilink = ilink->next; 136 } 137 ierr = PetscViewerASCIIPrintf(viewer,"KSP solver for A block \n");CHKERRQ(ierr); 138 ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 139 if (jac->schur) { 140 ierr = MatSchurComplementGetKSP(jac->schur,&ksp);CHKERRQ(ierr); 141 ierr = KSPView(ksp,viewer);CHKERRQ(ierr); 142 } else { 143 ierr = PetscViewerASCIIPrintf(viewer," not yet available\n");CHKERRQ(ierr); 144 } 145 ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 146 ierr = PetscViewerASCIIPrintf(viewer,"KSP solver for S = D - C inv(A) B \n");CHKERRQ(ierr); 147 ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 148 if (jac->kspschur) { 149 ierr = KSPView(jac->kspschur,viewer);CHKERRQ(ierr); 150 } else { 151 ierr = PetscViewerASCIIPrintf(viewer," not yet available\n");CHKERRQ(ierr); 152 } 153 ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 154 ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 155 } else { 156 SETERRQ1(PETSC_ERR_SUP,"Viewer type %s not supported for PCFieldSplit",((PetscObject)viewer)->type_name); 157 } 158 PetscFunctionReturn(0); 159 } 160 161 #undef __FUNCT__ 162 #define __FUNCT__ "PCFieldSplitSetDefaults" 163 static PetscErrorCode PCFieldSplitSetDefaults(PC pc) 164 { 165 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 166 PetscErrorCode ierr; 167 PC_FieldSplitLink ilink = jac->head; 168 PetscInt i = 0,*ifields,nfields; 169 PetscTruth flg = PETSC_FALSE,*fields,flg2; 170 char optionname[128]; 171 172 PetscFunctionBegin; 173 if (!ilink) { 174 175 if (jac->bs <= 0) { 176 if (pc->pmat) { 177 ierr = MatGetBlockSize(pc->pmat,&jac->bs);CHKERRQ(ierr); 178 } else { 179 jac->bs = 1; 180 } 181 } 182 183 ierr = PetscOptionsGetTruth(((PetscObject)pc)->prefix,"-pc_fieldsplit_default",&flg,PETSC_NULL);CHKERRQ(ierr); 184 if (!flg) { 185 /* Allow user to set fields from command line, if bs was known at the time of PCSetFromOptions_FieldSplit() 186 then it is set there. This is not ideal because we should only have options set in XXSetFromOptions(). */ 187 flg = PETSC_TRUE; /* switched off automatically if user sets fields manually here */ 188 ierr = PetscMalloc(jac->bs*sizeof(PetscInt),&ifields);CHKERRQ(ierr); 189 while (PETSC_TRUE) { 190 sprintf(optionname,"-pc_fieldsplit_%d_fields",(int)i++); 191 nfields = jac->bs; 192 ierr = PetscOptionsGetIntArray(((PetscObject)pc)->prefix,optionname,ifields,&nfields,&flg2);CHKERRQ(ierr); 193 if (!flg2) break; 194 if (!nfields) SETERRQ(PETSC_ERR_USER,"Cannot list zero fields"); 195 flg = PETSC_FALSE; 196 ierr = PCFieldSplitSetFields(pc,nfields,ifields);CHKERRQ(ierr); 197 } 198 ierr = PetscFree(ifields);CHKERRQ(ierr); 199 } 200 201 if (flg) { 202 ierr = PetscInfo(pc,"Using default splitting of fields\n");CHKERRQ(ierr); 203 ierr = PetscMalloc(jac->bs*sizeof(PetscTruth),&fields);CHKERRQ(ierr); 204 ierr = PetscMemzero(fields,jac->bs*sizeof(PetscTruth));CHKERRQ(ierr); 205 while (ilink) { 206 for (i=0; i<ilink->nfields; i++) { 207 fields[ilink->fields[i]] = PETSC_TRUE; 208 } 209 ilink = ilink->next; 210 } 211 jac->defaultsplit = PETSC_TRUE; 212 for (i=0; i<jac->bs; i++) { 213 if (!fields[i]) { 214 ierr = PCFieldSplitSetFields(pc,1,&i);CHKERRQ(ierr); 215 } else { 216 jac->defaultsplit = PETSC_FALSE; 217 } 218 } 219 ierr = PetscFree(fields);CHKERRQ(ierr); 220 } 221 } else if (jac->nsplits == 1) { 222 if (ilink->is) { 223 IS is2; 224 PetscInt nmin,nmax; 225 226 ierr = MatGetOwnershipRange(pc->mat,&nmin,&nmax);CHKERRQ(ierr); 227 ierr = ISComplement(ilink->is,nmin,nmax,&is2);CHKERRQ(ierr); 228 ierr = PCFieldSplitSetIS(pc,is2);CHKERRQ(ierr); 229 ierr = ISDestroy(is2);CHKERRQ(ierr); 230 } else { 231 SETERRQ(PETSC_ERR_SUP,"Must provide at least two sets of fields to PCFieldSplit()"); 232 } 233 } 234 if (jac->nsplits < 2) { 235 SETERRQ(PETSC_ERR_PLIB,"Unhandled case, must have at least two fields"); 236 } 237 PetscFunctionReturn(0); 238 } 239 240 241 #undef __FUNCT__ 242 #define __FUNCT__ "PCSetUp_FieldSplit" 243 static PetscErrorCode PCSetUp_FieldSplit(PC pc) 244 { 245 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 246 PetscErrorCode ierr; 247 PC_FieldSplitLink ilink; 248 PetscInt i,nsplit,ccsize; 249 MatStructure flag = pc->flag; 250 PetscTruth sorted; 251 252 PetscFunctionBegin; 253 ierr = PCFieldSplitSetDefaults(pc);CHKERRQ(ierr); 254 nsplit = jac->nsplits; 255 ilink = jac->head; 256 257 /* get the matrices for each split */ 258 if (!jac->issetup) { 259 PetscInt rstart,rend,nslots,bs; 260 261 jac->issetup = PETSC_TRUE; 262 263 /* This is done here instead of in PCFieldSplitSetFields() because may not have matrix at that point */ 264 bs = jac->bs; 265 ierr = MatGetOwnershipRange(pc->pmat,&rstart,&rend);CHKERRQ(ierr); 266 ierr = MatGetLocalSize(pc->pmat,PETSC_NULL,&ccsize);CHKERRQ(ierr); 267 nslots = (rend - rstart)/bs; 268 for (i=0; i<nsplit; i++) { 269 if (jac->defaultsplit) { 270 ierr = ISCreateStride(((PetscObject)pc)->comm,nslots,rstart+i,nsplit,&ilink->is);CHKERRQ(ierr); 271 } else if (!ilink->is) { 272 if (ilink->nfields > 1) { 273 PetscInt *ii,j,k,nfields = ilink->nfields,*fields = ilink->fields; 274 ierr = PetscMalloc(ilink->nfields*nslots*sizeof(PetscInt),&ii);CHKERRQ(ierr); 275 for (j=0; j<nslots; j++) { 276 for (k=0; k<nfields; k++) { 277 ii[nfields*j + k] = rstart + bs*j + fields[k]; 278 } 279 } 280 ierr = ISCreateGeneral(((PetscObject)pc)->comm,nslots*nfields,ii,&ilink->is);CHKERRQ(ierr); 281 ierr = PetscFree(ii);CHKERRQ(ierr); 282 } else { 283 ierr = ISCreateStride(((PetscObject)pc)->comm,nslots,rstart+ilink->fields[0],bs,&ilink->is);CHKERRQ(ierr); 284 } 285 } 286 ierr = ISSorted(ilink->is,&sorted);CHKERRQ(ierr); 287 if (!sorted) SETERRQ(PETSC_ERR_USER,"Fields must be sorted when creating split"); 288 ilink = ilink->next; 289 } 290 } 291 292 ilink = jac->head; 293 if (!jac->pmat) { 294 ierr = PetscMalloc(nsplit*sizeof(Mat),&jac->pmat);CHKERRQ(ierr); 295 for (i=0; i<nsplit; i++) { 296 ierr = MatGetSubMatrix(pc->pmat,ilink->is,ilink->is,MAT_INITIAL_MATRIX,&jac->pmat[i]);CHKERRQ(ierr); 297 ilink = ilink->next; 298 } 299 } else { 300 for (i=0; i<nsplit; i++) { 301 ierr = MatGetSubMatrix(pc->pmat,ilink->is,ilink->is,MAT_REUSE_MATRIX,&jac->pmat[i]);CHKERRQ(ierr); 302 ilink = ilink->next; 303 } 304 } 305 if (jac->realdiagonal) { 306 ilink = jac->head; 307 if (!jac->mat) { 308 ierr = PetscMalloc(nsplit*sizeof(Mat),&jac->mat);CHKERRQ(ierr); 309 for (i=0; i<nsplit; i++) { 310 ierr = MatGetSubMatrix(pc->mat,ilink->is,ilink->is,MAT_INITIAL_MATRIX,&jac->mat[i]);CHKERRQ(ierr); 311 ilink = ilink->next; 312 } 313 } else { 314 for (i=0; i<nsplit; i++) { 315 ierr = MatGetSubMatrix(pc->mat,ilink->is,ilink->is,MAT_REUSE_MATRIX,&jac->mat[i]);CHKERRQ(ierr); 316 ilink = ilink->next; 317 } 318 } 319 } else { 320 jac->mat = jac->pmat; 321 } 322 323 if (jac->type != PC_COMPOSITE_ADDITIVE && jac->type != PC_COMPOSITE_SCHUR) { 324 /* extract the rows of the matrix associated with each field: used for efficient computation of residual inside algorithm */ 325 ilink = jac->head; 326 if (!jac->Afield) { 327 ierr = PetscMalloc(nsplit*sizeof(Mat),&jac->Afield);CHKERRQ(ierr); 328 for (i=0; i<nsplit; i++) { 329 ierr = MatGetSubMatrix(pc->mat,ilink->is,PETSC_NULL,MAT_INITIAL_MATRIX,&jac->Afield[i]);CHKERRQ(ierr); 330 ilink = ilink->next; 331 } 332 } else { 333 for (i=0; i<nsplit; i++) { 334 ierr = MatGetSubMatrix(pc->mat,ilink->is,PETSC_NULL,MAT_REUSE_MATRIX,&jac->Afield[i]);CHKERRQ(ierr); 335 ilink = ilink->next; 336 } 337 } 338 } 339 340 if (jac->type == PC_COMPOSITE_SCHUR) { 341 IS ccis; 342 PetscInt rstart,rend; 343 if (nsplit != 2) SETERRQ(PETSC_ERR_ARG_INCOMP,"To use Schur complement preconditioner you must have exactly 2 fields"); 344 345 /* When extracting off-diagonal submatrices, we take complements from this range */ 346 ierr = MatGetOwnershipRangeColumn(pc->mat,&rstart,&rend);CHKERRQ(ierr); 347 348 /* need to handle case when one is resetting up the preconditioner */ 349 if (jac->schur) { 350 ilink = jac->head; 351 ierr = ISComplement(ilink->is,rstart,rend,&ccis);CHKERRQ(ierr); 352 ierr = MatGetSubMatrix(pc->mat,ilink->is,ccis,MAT_REUSE_MATRIX,&jac->B);CHKERRQ(ierr); 353 ierr = ISDestroy(ccis);CHKERRQ(ierr); 354 ilink = ilink->next; 355 ierr = ISComplement(ilink->is,rstart,rend,&ccis);CHKERRQ(ierr); 356 ierr = MatGetSubMatrix(pc->mat,ilink->is,ccis,MAT_REUSE_MATRIX,&jac->C);CHKERRQ(ierr); 357 ierr = ISDestroy(ccis);CHKERRQ(ierr); 358 ierr = MatSchurComplementUpdate(jac->schur,jac->mat[0],jac->pmat[0],jac->B,jac->C,jac->pmat[1],pc->flag);CHKERRQ(ierr); 359 ierr = KSPSetOperators(jac->kspschur,jac->schur,FieldSplitSchurPre(jac),pc->flag);CHKERRQ(ierr); 360 361 } else { 362 KSP ksp; 363 364 /* extract the B and C matrices */ 365 ilink = jac->head; 366 ierr = ISComplement(ilink->is,rstart,rend,&ccis);CHKERRQ(ierr); 367 ierr = MatGetSubMatrix(pc->mat,ilink->is,ccis,MAT_INITIAL_MATRIX,&jac->B);CHKERRQ(ierr); 368 ierr = ISDestroy(ccis);CHKERRQ(ierr); 369 ilink = ilink->next; 370 ierr = ISComplement(ilink->is,rstart,rend,&ccis);CHKERRQ(ierr); 371 ierr = MatGetSubMatrix(pc->mat,ilink->is,ccis,MAT_INITIAL_MATRIX,&jac->C);CHKERRQ(ierr); 372 ierr = ISDestroy(ccis);CHKERRQ(ierr); 373 /* Better would be to use 'mat[0]' (diagonal block of the real matrix) preconditioned by pmat[0] */ 374 ierr = MatCreateSchurComplement(jac->mat[0],jac->pmat[0],jac->B,jac->C,jac->mat[1],&jac->schur);CHKERRQ(ierr); 375 ierr = MatSchurComplementGetKSP(jac->schur,&ksp);CHKERRQ(ierr); 376 ierr = PetscObjectIncrementTabLevel((PetscObject)ksp,(PetscObject)pc,2);CHKERRQ(ierr); 377 ierr = MatSetFromOptions(jac->schur);CHKERRQ(ierr); 378 379 ierr = KSPCreate(((PetscObject)pc)->comm,&jac->kspschur);CHKERRQ(ierr); 380 ierr = PetscObjectIncrementTabLevel((PetscObject)jac->kspschur,(PetscObject)pc,1);CHKERRQ(ierr); 381 ierr = KSPSetOperators(jac->kspschur,jac->schur,FieldSplitSchurPre(jac),DIFFERENT_NONZERO_PATTERN);CHKERRQ(ierr); 382 if (jac->schurpre == PC_FIELDSPLIT_SCHUR_PRE_SELF) { 383 PC pc; 384 ierr = KSPGetPC(jac->kspschur,&pc);CHKERRQ(ierr); 385 ierr = PCSetType(pc,PCNONE);CHKERRQ(ierr); 386 /* Note: This is bad if there exist preconditioners for MATSCHURCOMPLEMENT */ 387 } 388 ierr = KSPSetOptionsPrefix(jac->kspschur,((PetscObject)pc)->prefix);CHKERRQ(ierr); 389 ierr = KSPAppendOptionsPrefix(jac->kspschur,"fieldsplit_1_");CHKERRQ(ierr); 390 /* really want setfromoptions called in PCSetFromOptions_FieldSplit(), but it is not ready yet */ 391 ierr = KSPSetFromOptions(jac->kspschur);CHKERRQ(ierr); 392 393 ierr = PetscMalloc2(2,Vec,&jac->x,2,Vec,&jac->y);CHKERRQ(ierr); 394 ierr = MatGetVecs(jac->pmat[0],&jac->x[0],&jac->y[0]);CHKERRQ(ierr); 395 ierr = MatGetVecs(jac->pmat[1],&jac->x[1],&jac->y[1]);CHKERRQ(ierr); 396 ilink = jac->head; 397 ilink->x = jac->x[0]; ilink->y = jac->y[0]; 398 ilink = ilink->next; 399 ilink->x = jac->x[1]; ilink->y = jac->y[1]; 400 } 401 } else { 402 /* set up the individual PCs */ 403 i = 0; 404 ilink = jac->head; 405 while (ilink) { 406 ierr = KSPSetOperators(ilink->ksp,jac->mat[i],jac->pmat[i],flag);CHKERRQ(ierr); 407 /* really want setfromoptions called in PCSetFromOptions_FieldSplit(), but it is not ready yet */ 408 ierr = KSPSetFromOptions(ilink->ksp);CHKERRQ(ierr); 409 ierr = KSPSetUp(ilink->ksp);CHKERRQ(ierr); 410 i++; 411 ilink = ilink->next; 412 } 413 414 /* create work vectors for each split */ 415 if (!jac->x) { 416 ierr = PetscMalloc2(nsplit,Vec,&jac->x,nsplit,Vec,&jac->y);CHKERRQ(ierr); 417 ilink = jac->head; 418 for (i=0; i<nsplit; i++) { 419 Vec *vl,*vr; 420 421 ierr = KSPGetVecs(ilink->ksp,1,&vr,1,&vl);CHKERRQ(ierr); 422 ilink->x = *vr; 423 ilink->y = *vl; 424 ierr = PetscFree(vr);CHKERRQ(ierr); 425 ierr = PetscFree(vl);CHKERRQ(ierr); 426 jac->x[i] = ilink->x; 427 jac->y[i] = ilink->y; 428 ilink = ilink->next; 429 } 430 } 431 } 432 433 434 if (!jac->head->sctx) { 435 Vec xtmp; 436 437 /* compute scatter contexts needed by multiplicative versions and non-default splits */ 438 439 ilink = jac->head; 440 ierr = MatGetVecs(pc->pmat,&xtmp,PETSC_NULL);CHKERRQ(ierr); 441 for (i=0; i<nsplit; i++) { 442 ierr = VecScatterCreate(xtmp,ilink->is,jac->x[i],PETSC_NULL,&ilink->sctx);CHKERRQ(ierr); 443 ilink = ilink->next; 444 } 445 ierr = VecDestroy(xtmp);CHKERRQ(ierr); 446 } 447 PetscFunctionReturn(0); 448 } 449 450 #define FieldSplitSplitSolveAdd(ilink,xx,yy) \ 451 (VecScatterBegin(ilink->sctx,xx,ilink->x,INSERT_VALUES,SCATTER_FORWARD) || \ 452 VecScatterEnd(ilink->sctx,xx,ilink->x,INSERT_VALUES,SCATTER_FORWARD) || \ 453 KSPSolve(ilink->ksp,ilink->x,ilink->y) || \ 454 VecScatterBegin(ilink->sctx,ilink->y,yy,ADD_VALUES,SCATTER_REVERSE) || \ 455 VecScatterEnd(ilink->sctx,ilink->y,yy,ADD_VALUES,SCATTER_REVERSE)) 456 457 #undef __FUNCT__ 458 #define __FUNCT__ "PCApply_FieldSplit_Schur" 459 static PetscErrorCode PCApply_FieldSplit_Schur(PC pc,Vec x,Vec y) 460 { 461 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 462 PetscErrorCode ierr; 463 KSP ksp; 464 PC_FieldSplitLink ilinkA = jac->head, ilinkD = ilinkA->next; 465 466 PetscFunctionBegin; 467 ierr = MatSchurComplementGetKSP(jac->schur,&ksp);CHKERRQ(ierr); 468 469 ierr = VecScatterBegin(ilinkA->sctx,x,ilinkA->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 470 ierr = VecScatterEnd(ilinkA->sctx,x,ilinkA->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 471 ierr = KSPSolve(ksp,ilinkA->x,ilinkA->y);CHKERRQ(ierr); 472 ierr = MatMult(jac->C,ilinkA->y,ilinkD->x);CHKERRQ(ierr); 473 ierr = VecScale(ilinkD->x,-1.0);CHKERRQ(ierr); 474 ierr = VecScatterBegin(ilinkD->sctx,x,ilinkD->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 475 ierr = VecScatterEnd(ilinkD->sctx,x,ilinkD->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 476 477 ierr = KSPSolve(jac->kspschur,ilinkD->x,ilinkD->y);CHKERRQ(ierr); 478 ierr = VecScatterBegin(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 479 ierr = VecScatterEnd(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 480 481 ierr = MatMult(jac->B,ilinkD->y,ilinkA->y);CHKERRQ(ierr); 482 ierr = VecAXPY(ilinkA->x,-1.0,ilinkA->y);CHKERRQ(ierr); 483 ierr = KSPSolve(ksp,ilinkA->x,ilinkA->y);CHKERRQ(ierr); 484 ierr = VecScatterBegin(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 485 ierr = VecScatterEnd(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 486 487 PetscFunctionReturn(0); 488 } 489 490 #undef __FUNCT__ 491 #define __FUNCT__ "PCApply_FieldSplit" 492 static PetscErrorCode PCApply_FieldSplit(PC pc,Vec x,Vec y) 493 { 494 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 495 PetscErrorCode ierr; 496 PC_FieldSplitLink ilink = jac->head; 497 PetscInt cnt; 498 499 PetscFunctionBegin; 500 CHKMEMQ; 501 ierr = VecSetBlockSize(x,jac->bs);CHKERRQ(ierr); 502 ierr = VecSetBlockSize(y,jac->bs);CHKERRQ(ierr); 503 504 if (jac->type == PC_COMPOSITE_ADDITIVE) { 505 if (jac->defaultsplit) { 506 ierr = VecStrideGatherAll(x,jac->x,INSERT_VALUES);CHKERRQ(ierr); 507 while (ilink) { 508 ierr = KSPSolve(ilink->ksp,ilink->x,ilink->y);CHKERRQ(ierr); 509 ilink = ilink->next; 510 } 511 ierr = VecStrideScatterAll(jac->y,y,INSERT_VALUES);CHKERRQ(ierr); 512 } else { 513 ierr = VecSet(y,0.0);CHKERRQ(ierr); 514 while (ilink) { 515 ierr = FieldSplitSplitSolveAdd(ilink,x,y);CHKERRQ(ierr); 516 ilink = ilink->next; 517 } 518 } 519 } else if (jac->type == PC_COMPOSITE_MULTIPLICATIVE || jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) { 520 if (!jac->w1) { 521 ierr = VecDuplicate(x,&jac->w1);CHKERRQ(ierr); 522 ierr = VecDuplicate(x,&jac->w2);CHKERRQ(ierr); 523 } 524 ierr = VecSet(y,0.0);CHKERRQ(ierr); 525 ierr = FieldSplitSplitSolveAdd(ilink,x,y);CHKERRQ(ierr); 526 cnt = 1; 527 while (ilink->next) { 528 ilink = ilink->next; 529 /* compute the residual only over the part of the vector needed */ 530 ierr = MatMult(jac->Afield[cnt++],y,ilink->x);CHKERRQ(ierr); 531 ierr = VecScale(ilink->x,-1.0);CHKERRQ(ierr); 532 ierr = VecScatterBegin(ilink->sctx,x,ilink->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 533 ierr = VecScatterEnd(ilink->sctx,x,ilink->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 534 ierr = KSPSolve(ilink->ksp,ilink->x,ilink->y);CHKERRQ(ierr); 535 ierr = VecScatterBegin(ilink->sctx,ilink->y,y,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 536 ierr = VecScatterEnd(ilink->sctx,ilink->y,y,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 537 } 538 if (jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) { 539 cnt -= 2; 540 while (ilink->previous) { 541 ilink = ilink->previous; 542 /* compute the residual only over the part of the vector needed */ 543 ierr = MatMult(jac->Afield[cnt--],y,ilink->x);CHKERRQ(ierr); 544 ierr = VecScale(ilink->x,-1.0);CHKERRQ(ierr); 545 ierr = VecScatterBegin(ilink->sctx,x,ilink->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 546 ierr = VecScatterEnd(ilink->sctx,x,ilink->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 547 ierr = KSPSolve(ilink->ksp,ilink->x,ilink->y);CHKERRQ(ierr); 548 ierr = VecScatterBegin(ilink->sctx,ilink->y,y,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 549 ierr = VecScatterEnd(ilink->sctx,ilink->y,y,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 550 } 551 } 552 } else SETERRQ1(PETSC_ERR_SUP,"Unsupported or unknown composition",(int) jac->type); 553 CHKMEMQ; 554 PetscFunctionReturn(0); 555 } 556 557 #define FieldSplitSplitSolveAddTranspose(ilink,xx,yy) \ 558 (VecScatterBegin(ilink->sctx,xx,ilink->y,INSERT_VALUES,SCATTER_FORWARD) || \ 559 VecScatterEnd(ilink->sctx,xx,ilink->y,INSERT_VALUES,SCATTER_FORWARD) || \ 560 KSPSolveTranspose(ilink->ksp,ilink->y,ilink->x) || \ 561 VecScatterBegin(ilink->sctx,ilink->x,yy,ADD_VALUES,SCATTER_REVERSE) || \ 562 VecScatterEnd(ilink->sctx,ilink->x,yy,ADD_VALUES,SCATTER_REVERSE)) 563 564 #undef __FUNCT__ 565 #define __FUNCT__ "PCApply_FieldSplit" 566 static PetscErrorCode PCApplyTranspose_FieldSplit(PC pc,Vec x,Vec y) 567 { 568 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 569 PetscErrorCode ierr; 570 PC_FieldSplitLink ilink = jac->head; 571 572 PetscFunctionBegin; 573 CHKMEMQ; 574 ierr = VecSetBlockSize(x,jac->bs);CHKERRQ(ierr); 575 ierr = VecSetBlockSize(y,jac->bs);CHKERRQ(ierr); 576 577 if (jac->type == PC_COMPOSITE_ADDITIVE) { 578 if (jac->defaultsplit) { 579 ierr = VecStrideGatherAll(x,jac->x,INSERT_VALUES);CHKERRQ(ierr); 580 while (ilink) { 581 ierr = KSPSolveTranspose(ilink->ksp,ilink->x,ilink->y);CHKERRQ(ierr); 582 ilink = ilink->next; 583 } 584 ierr = VecStrideScatterAll(jac->y,y,INSERT_VALUES);CHKERRQ(ierr); 585 } else { 586 ierr = VecSet(y,0.0);CHKERRQ(ierr); 587 while (ilink) { 588 ierr = FieldSplitSplitSolveAddTranspose(ilink,x,y);CHKERRQ(ierr); 589 ilink = ilink->next; 590 } 591 } 592 } else { 593 if (!jac->w1) { 594 ierr = VecDuplicate(x,&jac->w1);CHKERRQ(ierr); 595 ierr = VecDuplicate(x,&jac->w2);CHKERRQ(ierr); 596 } 597 ierr = VecSet(y,0.0);CHKERRQ(ierr); 598 if (jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) { 599 ierr = FieldSplitSplitSolveAddTranspose(ilink,x,y);CHKERRQ(ierr); 600 while (ilink->next) { 601 ilink = ilink->next; 602 ierr = MatMultTranspose(pc->mat,y,jac->w1);CHKERRQ(ierr); 603 ierr = VecWAXPY(jac->w2,-1.0,jac->w1,x);CHKERRQ(ierr); 604 ierr = FieldSplitSplitSolveAddTranspose(ilink,jac->w2,y);CHKERRQ(ierr); 605 } 606 while (ilink->previous) { 607 ilink = ilink->previous; 608 ierr = MatMultTranspose(pc->mat,y,jac->w1);CHKERRQ(ierr); 609 ierr = VecWAXPY(jac->w2,-1.0,jac->w1,x);CHKERRQ(ierr); 610 ierr = FieldSplitSplitSolveAddTranspose(ilink,jac->w2,y);CHKERRQ(ierr); 611 } 612 } else { 613 while (ilink->next) { /* get to last entry in linked list */ 614 ilink = ilink->next; 615 } 616 ierr = FieldSplitSplitSolveAddTranspose(ilink,x,y);CHKERRQ(ierr); 617 while (ilink->previous) { 618 ilink = ilink->previous; 619 ierr = MatMultTranspose(pc->mat,y,jac->w1);CHKERRQ(ierr); 620 ierr = VecWAXPY(jac->w2,-1.0,jac->w1,x);CHKERRQ(ierr); 621 ierr = FieldSplitSplitSolveAddTranspose(ilink,jac->w2,y);CHKERRQ(ierr); 622 } 623 } 624 } 625 CHKMEMQ; 626 PetscFunctionReturn(0); 627 } 628 629 #undef __FUNCT__ 630 #define __FUNCT__ "PCDestroy_FieldSplit" 631 static PetscErrorCode PCDestroy_FieldSplit(PC pc) 632 { 633 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 634 PetscErrorCode ierr; 635 PC_FieldSplitLink ilink = jac->head,next; 636 637 PetscFunctionBegin; 638 while (ilink) { 639 ierr = KSPDestroy(ilink->ksp);CHKERRQ(ierr); 640 if (ilink->x) {ierr = VecDestroy(ilink->x);CHKERRQ(ierr);} 641 if (ilink->y) {ierr = VecDestroy(ilink->y);CHKERRQ(ierr);} 642 if (ilink->sctx) {ierr = VecScatterDestroy(ilink->sctx);CHKERRQ(ierr);} 643 if (ilink->is) {ierr = ISDestroy(ilink->is);CHKERRQ(ierr);} 644 next = ilink->next; 645 ierr = PetscFree(ilink->fields);CHKERRQ(ierr); 646 ierr = PetscFree(ilink);CHKERRQ(ierr); 647 ilink = next; 648 } 649 ierr = PetscFree2(jac->x,jac->y);CHKERRQ(ierr); 650 if (jac->mat && jac->mat != jac->pmat) {ierr = MatDestroyMatrices(jac->nsplits,&jac->mat);CHKERRQ(ierr);} 651 if (jac->pmat) {ierr = MatDestroyMatrices(jac->nsplits,&jac->pmat);CHKERRQ(ierr);} 652 if (jac->Afield) {ierr = MatDestroyMatrices(jac->nsplits,&jac->Afield);CHKERRQ(ierr);} 653 if (jac->w1) {ierr = VecDestroy(jac->w1);CHKERRQ(ierr);} 654 if (jac->w2) {ierr = VecDestroy(jac->w2);CHKERRQ(ierr);} 655 if (jac->schur) {ierr = MatDestroy(jac->schur);CHKERRQ(ierr);} 656 if (jac->schur_user) {ierr = MatDestroy(jac->schur_user);CHKERRQ(ierr);} 657 if (jac->kspschur) {ierr = KSPDestroy(jac->kspschur);CHKERRQ(ierr);} 658 if (jac->B) {ierr = MatDestroy(jac->B);CHKERRQ(ierr);} 659 if (jac->C) {ierr = MatDestroy(jac->C);CHKERRQ(ierr);} 660 ierr = PetscFree(jac);CHKERRQ(ierr); 661 PetscFunctionReturn(0); 662 } 663 664 #undef __FUNCT__ 665 #define __FUNCT__ "PCSetFromOptions_FieldSplit" 666 static PetscErrorCode PCSetFromOptions_FieldSplit(PC pc) 667 { 668 PetscErrorCode ierr; 669 PetscInt i = 0,nfields,*fields,bs; 670 PetscTruth flg; 671 char optionname[128]; 672 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 673 PCCompositeType ctype; 674 675 PetscFunctionBegin; 676 ierr = PetscOptionsHead("FieldSplit options");CHKERRQ(ierr); 677 ierr = PetscOptionsTruth("-pc_fieldsplit_real_diagonal","Use diagonal blocks of the operator","PCFieldSplitSetRealDiagonal",jac->realdiagonal,&jac->realdiagonal,PETSC_NULL);CHKERRQ(ierr); 678 ierr = PetscOptionsInt("-pc_fieldsplit_block_size","Blocksize that defines number of fields","PCFieldSplitSetBlockSize",jac->bs,&bs,&flg);CHKERRQ(ierr); 679 if (flg) { 680 ierr = PCFieldSplitSetBlockSize(pc,bs);CHKERRQ(ierr); 681 } 682 683 ierr = PetscOptionsEnum("-pc_fieldsplit_type","Type of composition","PCFieldSplitSetType",PCCompositeTypes,(PetscEnum)jac->type,(PetscEnum*)&ctype,&flg);CHKERRQ(ierr); 684 if (flg) { 685 ierr = PCFieldSplitSetType(pc,ctype);CHKERRQ(ierr); 686 } 687 688 /* Only setup fields once */ 689 if ((jac->bs > 0) && (jac->nsplits == 0)) { 690 /* only allow user to set fields from command line if bs is already known. 691 otherwise user can set them in PCFieldSplitSetDefaults() */ 692 ierr = PetscMalloc(jac->bs*sizeof(PetscInt),&fields);CHKERRQ(ierr); 693 while (PETSC_TRUE) { 694 sprintf(optionname,"-pc_fieldsplit_%d_fields",(int)i++); 695 nfields = jac->bs; 696 ierr = PetscOptionsIntArray(optionname,"Fields in this split","PCFieldSplitSetFields",fields,&nfields,&flg);CHKERRQ(ierr); 697 if (!flg) break; 698 if (!nfields) SETERRQ(PETSC_ERR_USER,"Cannot list zero fields"); 699 ierr = PCFieldSplitSetFields(pc,nfields,fields);CHKERRQ(ierr); 700 } 701 ierr = PetscFree(fields);CHKERRQ(ierr); 702 } 703 ierr = PetscOptionsEnum("-pc_fieldsplit_schur_precondition","How to build preconditioner for Schur complement","PCFieldSplitSchurPrecondition",PCFieldSplitSchurPreTypes,(PetscEnum)jac->schurpre,(PetscEnum*)&jac->schurpre,PETSC_NULL);CHKERRQ(ierr); 704 ierr = PetscOptionsTail();CHKERRQ(ierr); 705 PetscFunctionReturn(0); 706 } 707 708 /*------------------------------------------------------------------------------------*/ 709 710 EXTERN_C_BEGIN 711 #undef __FUNCT__ 712 #define __FUNCT__ "PCFieldSplitSetFields_FieldSplit" 713 PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitSetFields_FieldSplit(PC pc,PetscInt n,PetscInt *fields) 714 { 715 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 716 PetscErrorCode ierr; 717 PC_FieldSplitLink ilink,next = jac->head; 718 char prefix[128]; 719 PetscInt i; 720 721 PetscFunctionBegin; 722 if (n <= 0) SETERRQ(PETSC_ERR_ARG_OUTOFRANGE,"Negative number of fields requested"); 723 for (i=0; i<n; i++) { 724 if (fields[i] >= jac->bs) SETERRQ2(PETSC_ERR_ARG_OUTOFRANGE,"Field %D requested but only %D exist",fields[i],jac->bs); 725 if (fields[i] < 0) SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"Negative field %D requested",fields[i]); 726 } 727 ierr = PetscNew(struct _PC_FieldSplitLink,&ilink);CHKERRQ(ierr); 728 ierr = PetscMalloc(n*sizeof(PetscInt),&ilink->fields);CHKERRQ(ierr); 729 ierr = PetscMemcpy(ilink->fields,fields,n*sizeof(PetscInt));CHKERRQ(ierr); 730 ilink->nfields = n; 731 ilink->next = PETSC_NULL; 732 ierr = KSPCreate(((PetscObject)pc)->comm,&ilink->ksp);CHKERRQ(ierr); 733 ierr = PetscObjectIncrementTabLevel((PetscObject)ilink->ksp,(PetscObject)pc,1);CHKERRQ(ierr); 734 ierr = KSPSetType(ilink->ksp,KSPPREONLY);CHKERRQ(ierr); 735 736 if (((PetscObject)pc)->prefix) { 737 sprintf(prefix,"%sfieldsplit_%d_",((PetscObject)pc)->prefix,(int)jac->nsplits); 738 } else { 739 sprintf(prefix,"fieldsplit_%d_",(int)jac->nsplits); 740 } 741 ierr = KSPSetOptionsPrefix(ilink->ksp,prefix);CHKERRQ(ierr); 742 743 if (!next) { 744 jac->head = ilink; 745 ilink->previous = PETSC_NULL; 746 } else { 747 while (next->next) { 748 next = next->next; 749 } 750 next->next = ilink; 751 ilink->previous = next; 752 } 753 jac->nsplits++; 754 PetscFunctionReturn(0); 755 } 756 EXTERN_C_END 757 758 EXTERN_C_BEGIN 759 #undef __FUNCT__ 760 #define __FUNCT__ "PCFieldSplitGetSubKSP_FieldSplit_Schur" 761 PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitGetSubKSP_FieldSplit_Schur(PC pc,PetscInt *n,KSP **subksp) 762 { 763 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 764 PetscErrorCode ierr; 765 766 PetscFunctionBegin; 767 ierr = PetscMalloc(jac->nsplits*sizeof(KSP),subksp);CHKERRQ(ierr); 768 ierr = MatSchurComplementGetKSP(jac->schur,*subksp);CHKERRQ(ierr); 769 (*subksp)[1] = jac->kspschur; 770 *n = jac->nsplits; 771 PetscFunctionReturn(0); 772 } 773 EXTERN_C_END 774 775 EXTERN_C_BEGIN 776 #undef __FUNCT__ 777 #define __FUNCT__ "PCFieldSplitGetSubKSP_FieldSplit" 778 PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitGetSubKSP_FieldSplit(PC pc,PetscInt *n,KSP **subksp) 779 { 780 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 781 PetscErrorCode ierr; 782 PetscInt cnt = 0; 783 PC_FieldSplitLink ilink = jac->head; 784 785 PetscFunctionBegin; 786 ierr = PetscMalloc(jac->nsplits*sizeof(KSP*),subksp);CHKERRQ(ierr); 787 while (ilink) { 788 (*subksp)[cnt++] = ilink->ksp; 789 ilink = ilink->next; 790 } 791 if (cnt != jac->nsplits) SETERRQ2(PETSC_ERR_PLIB,"Corrupt PCFIELDSPLIT object: number splits in linked list %D in object %D",cnt,jac->nsplits); 792 *n = jac->nsplits; 793 PetscFunctionReturn(0); 794 } 795 EXTERN_C_END 796 797 EXTERN_C_BEGIN 798 #undef __FUNCT__ 799 #define __FUNCT__ "PCFieldSplitSetIS_FieldSplit" 800 PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitSetIS_FieldSplit(PC pc,IS is) 801 { 802 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 803 PetscErrorCode ierr; 804 PC_FieldSplitLink ilink, next = jac->head; 805 char prefix[128]; 806 807 PetscFunctionBegin; 808 ierr = PetscNew(struct _PC_FieldSplitLink,&ilink);CHKERRQ(ierr); 809 ilink->is = is; 810 ierr = PetscObjectReference((PetscObject)is);CHKERRQ(ierr); 811 ilink->next = PETSC_NULL; 812 ierr = KSPCreate(((PetscObject)pc)->comm,&ilink->ksp);CHKERRQ(ierr); 813 ierr = PetscObjectIncrementTabLevel((PetscObject)ilink->ksp,(PetscObject)pc,1);CHKERRQ(ierr); 814 ierr = KSPSetType(ilink->ksp,KSPPREONLY);CHKERRQ(ierr); 815 816 if (((PetscObject)pc)->prefix) { 817 sprintf(prefix,"%sfieldsplit_%d_",((PetscObject)pc)->prefix,(int)jac->nsplits); 818 } else { 819 sprintf(prefix,"fieldsplit_%d_",(int)jac->nsplits); 820 } 821 ierr = KSPSetOptionsPrefix(ilink->ksp,prefix);CHKERRQ(ierr); 822 823 if (!next) { 824 jac->head = ilink; 825 ilink->previous = PETSC_NULL; 826 } else { 827 while (next->next) { 828 next = next->next; 829 } 830 next->next = ilink; 831 ilink->previous = next; 832 } 833 jac->nsplits++; 834 835 PetscFunctionReturn(0); 836 } 837 EXTERN_C_END 838 839 #undef __FUNCT__ 840 #define __FUNCT__ "PCFieldSplitSetFields" 841 /*@ 842 PCFieldSplitSetFields - Sets the fields for one particular split in the field split preconditioner 843 844 Collective on PC 845 846 Input Parameters: 847 + pc - the preconditioner context 848 . n - the number of fields in this split 849 . fields - the fields in this split 850 851 Level: intermediate 852 853 Notes: Use PCFieldSplitSetIS() to set a completely general set of indices as a field. 854 855 The PCFieldSplitSetFields() is for defining fields as a strided blocks. For example, if the block 856 size is three then one can define a field as 0, or 1 or 2 or 0,1 or 0,2 or 1,2 which mean 857 0xx3xx6xx9xx12 ... x1xx4xx7xx ... xx2xx5xx8xx.. 01x34x67x... 0x1x3x5x7.. x12x45x78x.... 858 where the numbered entries indicate what is in the field. 859 860 .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetBlockSize(), PCFieldSplitSetIS() 861 862 @*/ 863 PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitSetFields(PC pc,PetscInt n, PetscInt *fields) 864 { 865 PetscErrorCode ierr,(*f)(PC,PetscInt,PetscInt *); 866 867 PetscFunctionBegin; 868 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 869 ierr = PetscObjectQueryFunction((PetscObject)pc,"PCFieldSplitSetFields_C",(void (**)(void))&f);CHKERRQ(ierr); 870 if (f) { 871 ierr = (*f)(pc,n,fields);CHKERRQ(ierr); 872 } 873 PetscFunctionReturn(0); 874 } 875 876 #undef __FUNCT__ 877 #define __FUNCT__ "PCFieldSplitSetIS" 878 /*@ 879 PCFieldSplitSetIS - Sets the exact elements for field 880 881 Collective on PC 882 883 Input Parameters: 884 + pc - the preconditioner context 885 . is - the index set that defines the vector elements in this field 886 887 888 Notes: Use PCFieldSplitSetFields(), for fields defined by strided types. 889 890 Level: intermediate 891 892 .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetBlockSize() 893 894 @*/ 895 PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitSetIS(PC pc,IS is) 896 { 897 PetscErrorCode ierr,(*f)(PC,IS); 898 899 PetscFunctionBegin; 900 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 901 PetscValidHeaderSpecific(is,IS_CLASSID,1); 902 ierr = PetscObjectQueryFunction((PetscObject)pc,"PCFieldSplitSetIS_C",(void (**)(void))&f);CHKERRQ(ierr); 903 if (f) { 904 ierr = (*f)(pc,is);CHKERRQ(ierr); 905 } 906 PetscFunctionReturn(0); 907 } 908 909 #undef __FUNCT__ 910 #define __FUNCT__ "PCFieldSplitSetBlockSize" 911 /*@ 912 PCFieldSplitSetBlockSize - Sets the block size for defining where fields start in the 913 fieldsplit preconditioner. If not set the matrix block size is used. 914 915 Collective on PC 916 917 Input Parameters: 918 + pc - the preconditioner context 919 - bs - the block size 920 921 Level: intermediate 922 923 .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetFields() 924 925 @*/ 926 PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitSetBlockSize(PC pc,PetscInt bs) 927 { 928 PetscErrorCode ierr,(*f)(PC,PetscInt); 929 930 PetscFunctionBegin; 931 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 932 ierr = PetscObjectQueryFunction((PetscObject)pc,"PCFieldSplitSetBlockSize_C",(void (**)(void))&f);CHKERRQ(ierr); 933 if (f) { 934 ierr = (*f)(pc,bs);CHKERRQ(ierr); 935 } 936 PetscFunctionReturn(0); 937 } 938 939 #undef __FUNCT__ 940 #define __FUNCT__ "PCFieldSplitGetSubKSP" 941 /*@C 942 PCFieldSplitGetSubKSP - Gets the KSP contexts for all splits 943 944 Collective on KSP 945 946 Input Parameter: 947 . pc - the preconditioner context 948 949 Output Parameters: 950 + n - the number of split 951 - pc - the array of KSP contexts 952 953 Note: 954 After PCFieldSplitGetSubKSP() the array of KSPs IS to be freed by the user 955 (not the KSP just the array that contains them). 956 957 You must call KSPSetUp() before calling PCFieldSplitGetSubKSP(). 958 959 Level: advanced 960 961 .seealso: PCFIELDSPLIT 962 @*/ 963 PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitGetSubKSP(PC pc,PetscInt *n,KSP *subksp[]) 964 { 965 PetscErrorCode ierr,(*f)(PC,PetscInt*,KSP **); 966 967 PetscFunctionBegin; 968 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 969 PetscValidIntPointer(n,2); 970 ierr = PetscObjectQueryFunction((PetscObject)pc,"PCFieldSplitGetSubKSP_C",(void (**)(void))&f);CHKERRQ(ierr); 971 if (f) { 972 ierr = (*f)(pc,n,subksp);CHKERRQ(ierr); 973 } else { 974 SETERRQ(PETSC_ERR_ARG_WRONG,"Cannot get subksp for this type of PC"); 975 } 976 PetscFunctionReturn(0); 977 } 978 979 #undef __FUNCT__ 980 #define __FUNCT__ "PCFieldSplitSchurPrecondition" 981 /*@ 982 PCFieldSplitSchurPrecondition - Indicates if the Schur complement is preconditioned by a preconditioner constructed by the 983 D matrix. Otherwise no preconditioner is used. 984 985 Collective on PC 986 987 Input Parameters: 988 + pc - the preconditioner context 989 . ptype - which matrix to use for preconditioning the Schur complement 990 - userpre - matrix to use for preconditioning, or PETSC_NULL 991 992 Notes: 993 The default is to use the block on the diagonal of the preconditioning matrix. This is D, in the (1,1) position. 994 There are currently no preconditioners that work directly with the Schur complement so setting 995 PC_FIELDSPLIT_SCHUR_PRE_SELF is observationally equivalent to -fieldsplit_1_pc_type none. 996 997 Options Database: 998 . -pc_fieldsplit_schur_precondition <self,user,diag> default is diag 999 1000 Level: intermediate 1001 1002 .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetFields(), PCFieldSplitSchurPreType 1003 1004 @*/ 1005 PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitSchurPrecondition(PC pc,PCFieldSplitSchurPreType ptype,Mat pre) 1006 { 1007 PetscErrorCode ierr,(*f)(PC,PCFieldSplitSchurPreType,Mat); 1008 1009 PetscFunctionBegin; 1010 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1011 ierr = PetscObjectQueryFunction((PetscObject)pc,"PCFieldSplitSchurPrecondition_C",(void (**)(void))&f);CHKERRQ(ierr); 1012 if (f) { 1013 ierr = (*f)(pc,ptype,pre);CHKERRQ(ierr); 1014 } 1015 PetscFunctionReturn(0); 1016 } 1017 1018 EXTERN_C_BEGIN 1019 #undef __FUNCT__ 1020 #define __FUNCT__ "PCFieldSplitSchurPrecondition_FieldSplit" 1021 PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitSchurPrecondition_FieldSplit(PC pc,PCFieldSplitSchurPreType ptype,Mat pre) 1022 { 1023 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 1024 PetscErrorCode ierr; 1025 1026 PetscFunctionBegin; 1027 jac->schurpre = ptype; 1028 if (pre) { 1029 if (jac->schur_user) {ierr = MatDestroy(jac->schur_user);CHKERRQ(ierr);} 1030 jac->schur_user = pre; 1031 ierr = PetscObjectReference((PetscObject)jac->schur_user);CHKERRQ(ierr); 1032 } 1033 PetscFunctionReturn(0); 1034 } 1035 EXTERN_C_END 1036 1037 #undef __FUNCT__ 1038 #define __FUNCT__ "PCFieldSplitGetSchurBlocks" 1039 /*@C 1040 PCFieldSplitGetSchurBlocks - Gets the all matrix blocks for the Schur complement 1041 1042 Collective on KSP 1043 1044 Input Parameter: 1045 . pc - the preconditioner context 1046 1047 Output Parameters: 1048 + A - the (0,0) block 1049 . B - the (0,1) block 1050 . C - the (1,0) block 1051 - D - the (1,1) block 1052 1053 Level: advanced 1054 1055 .seealso: PCFIELDSPLIT 1056 @*/ 1057 PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitGetSchurBlocks(PC pc,Mat *A,Mat *B,Mat *C, Mat *D) 1058 { 1059 PC_FieldSplit *jac = (PC_FieldSplit *) pc->data; 1060 1061 PetscFunctionBegin; 1062 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1063 if (jac->type != PC_COMPOSITE_SCHUR) {SETERRQ(PETSC_ERR_ARG_WRONG, "FieldSplit is not using a Schur complement approach.");} 1064 if (A) *A = jac->pmat[0]; 1065 if (B) *B = jac->B; 1066 if (C) *C = jac->C; 1067 if (D) *D = jac->pmat[1]; 1068 PetscFunctionReturn(0); 1069 } 1070 1071 EXTERN_C_BEGIN 1072 #undef __FUNCT__ 1073 #define __FUNCT__ "PCFieldSplitSetType_FieldSplit" 1074 PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitSetType_FieldSplit(PC pc,PCCompositeType type) 1075 { 1076 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 1077 PetscErrorCode ierr; 1078 1079 PetscFunctionBegin; 1080 jac->type = type; 1081 if (type == PC_COMPOSITE_SCHUR) { 1082 pc->ops->apply = PCApply_FieldSplit_Schur; 1083 pc->ops->view = PCView_FieldSplit_Schur; 1084 ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitGetSubKSP_C","PCFieldSplitGetSubKSP_FieldSplit_Schur",PCFieldSplitGetSubKSP_FieldSplit_Schur);CHKERRQ(ierr); 1085 ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSchurPrecondition_C","PCFieldSplitSchurPrecondition_FieldSplit",PCFieldSplitSchurPrecondition_FieldSplit);CHKERRQ(ierr); 1086 1087 } else { 1088 pc->ops->apply = PCApply_FieldSplit; 1089 pc->ops->view = PCView_FieldSplit; 1090 ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitGetSubKSP_C","PCFieldSplitGetSubKSP_FieldSplit",PCFieldSplitGetSubKSP_FieldSplit);CHKERRQ(ierr); 1091 ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSchurPrecondition_C","",0);CHKERRQ(ierr); 1092 } 1093 PetscFunctionReturn(0); 1094 } 1095 EXTERN_C_END 1096 1097 EXTERN_C_BEGIN 1098 #undef __FUNCT__ 1099 #define __FUNCT__ "PCFieldSplitSetBlockSize_FieldSplit" 1100 PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitSetBlockSize_FieldSplit(PC pc,PetscInt bs) 1101 { 1102 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 1103 1104 PetscFunctionBegin; 1105 if (bs < 1) SETERRQ1(PETSC_ERR_ARG_OUTOFRANGE,"Blocksize must be positive, you gave %D",bs); 1106 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); 1107 jac->bs = bs; 1108 PetscFunctionReturn(0); 1109 } 1110 EXTERN_C_END 1111 1112 #undef __FUNCT__ 1113 #define __FUNCT__ "PCFieldSplitSetType" 1114 /*@ 1115 PCFieldSplitSetType - Sets the type of fieldsplit preconditioner. 1116 1117 Collective on PC 1118 1119 Input Parameter: 1120 . pc - the preconditioner context 1121 . type - PC_COMPOSITE_ADDITIVE, PC_COMPOSITE_MULTIPLICATIVE (default), PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE, PC_COMPOSITE_SPECIAL, PC_COMPOSITE_SCHUR 1122 1123 Options Database Key: 1124 . -pc_fieldsplit_type <type: one of multiplicative, additive, symmetric_multiplicative, special, schur> - Sets fieldsplit preconditioner type 1125 1126 Level: Developer 1127 1128 .keywords: PC, set, type, composite preconditioner, additive, multiplicative 1129 1130 .seealso: PCCompositeSetType() 1131 1132 @*/ 1133 PetscErrorCode PETSCKSP_DLLEXPORT PCFieldSplitSetType(PC pc,PCCompositeType type) 1134 { 1135 PetscErrorCode ierr,(*f)(PC,PCCompositeType); 1136 1137 PetscFunctionBegin; 1138 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1139 ierr = PetscObjectQueryFunction((PetscObject)pc,"PCFieldSplitSetType_C",(void (**)(void))&f);CHKERRQ(ierr); 1140 if (f) { 1141 ierr = (*f)(pc,type);CHKERRQ(ierr); 1142 } 1143 PetscFunctionReturn(0); 1144 } 1145 1146 /* -------------------------------------------------------------------------------------*/ 1147 /*MC 1148 PCFIELDSPLIT - Preconditioner created by combining separate preconditioners for individual 1149 fields or groups of fields 1150 1151 1152 To set options on the solvers for each block append -fieldsplit_ to all the PC 1153 options database keys. For example, -fieldsplit_pc_type ilu -fieldsplit_pc_factor_levels 1 1154 1155 To set the options on the solvers separate for each block call PCFieldSplitGetSubKSP() 1156 and set the options directly on the resulting KSP object 1157 1158 Level: intermediate 1159 1160 Options Database Keys: 1161 + -pc_fieldsplit_%d_fields <a,b,..> - indicates the fields to be used in the %d'th split 1162 . -pc_fieldsplit_default - automatically add any fields to additional splits that have not 1163 been supplied explicitly by -pc_fieldsplit_%d_fields 1164 . -pc_fieldsplit_block_size <bs> - size of block that defines fields (i.e. there are bs fields) 1165 . -pc_fieldsplit_type <additive,multiplicative,schur,symmetric_multiplicative> 1166 . -pc_fieldsplit_schur_precondition <true,false> default is true 1167 1168 - Options prefix for inner solvers when using Schur complement preconditioner are -fieldsplit_0_ and -fieldsplit_1_ 1169 for all other solvers they are -fieldsplit_%d_ for the dth field, use -fieldsplit_ for all fields 1170 1171 1172 Notes: use PCFieldSplitSetFields() to set fields defined by "strided" entries and PCFieldSplitSetIS() 1173 to define a field by an arbitrary collection of entries. 1174 1175 If no fields are set the default is used. The fields are defined by entries strided by bs, 1176 beginning at 0 then 1, etc to bs-1. The block size can be set with PCFieldSplitSetBlockSize(), 1177 if this is not called the block size defaults to the blocksize of the second matrix passed 1178 to KSPSetOperators()/PCSetOperators(). 1179 1180 Currently for the multiplicative version, the updated residual needed for the next field 1181 solve is computed via a matrix vector product over the entire array. An optimization would be 1182 to update the residual only for the part of the right hand side associated with the next field 1183 solve. (This would involve more MatGetSubMatrix() calls or some other mechanism to compute the 1184 part of the matrix needed to just update part of the residual). 1185 1186 For the Schur complement preconditioner if J = ( A B ) 1187 ( C D ) 1188 the preconditioner is 1189 (I -B inv(A)) ( inv(A) 0 ) (I 0 ) 1190 (0 I ) ( 0 inv(S) ) (-C inv(A) I ) 1191 where the action of inv(A) is applied using the KSP solver with prefix -fieldsplit_0_. The action of 1192 inv(S) is computed using the KSP solver with prefix -schur_. For PCFieldSplitGetKSP() when field number is 1193 0 it returns the KSP associated with -fieldsplit_0_ while field number 1 gives -fieldsplit_1_ KSP. By default 1194 D is used to construct a preconditioner for S, use PCFieldSplitSchurPrecondition() to turn on or off this 1195 option. 1196 1197 If only one set of indices (one IS) is provided with PCFieldSplitSetIS() then the complement of that IS 1198 is used automatically for a second block. 1199 1200 Concepts: physics based preconditioners, block preconditioners 1201 1202 .seealso: PCCreate(), PCSetType(), PCType (for list of available types), PC, Block_Preconditioners 1203 PCFieldSplitGetSubKSP(), PCFieldSplitSetFields(), PCFieldSplitSetType(), PCFieldSplitSetIS(), PCFieldSplitSchurPrecondition() 1204 M*/ 1205 1206 EXTERN_C_BEGIN 1207 #undef __FUNCT__ 1208 #define __FUNCT__ "PCCreate_FieldSplit" 1209 PetscErrorCode PETSCKSP_DLLEXPORT PCCreate_FieldSplit(PC pc) 1210 { 1211 PetscErrorCode ierr; 1212 PC_FieldSplit *jac; 1213 1214 PetscFunctionBegin; 1215 ierr = PetscNewLog(pc,PC_FieldSplit,&jac);CHKERRQ(ierr); 1216 jac->bs = -1; 1217 jac->nsplits = 0; 1218 jac->type = PC_COMPOSITE_MULTIPLICATIVE; 1219 jac->schurpre = PC_FIELDSPLIT_SCHUR_PRE_USER; /* Try user preconditioner first, fall back on diagonal */ 1220 1221 pc->data = (void*)jac; 1222 1223 pc->ops->apply = PCApply_FieldSplit; 1224 pc->ops->applytranspose = PCApplyTranspose_FieldSplit; 1225 pc->ops->setup = PCSetUp_FieldSplit; 1226 pc->ops->destroy = PCDestroy_FieldSplit; 1227 pc->ops->setfromoptions = PCSetFromOptions_FieldSplit; 1228 pc->ops->view = PCView_FieldSplit; 1229 pc->ops->applyrichardson = 0; 1230 1231 ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitGetSubKSP_C","PCFieldSplitGetSubKSP_FieldSplit", 1232 PCFieldSplitGetSubKSP_FieldSplit);CHKERRQ(ierr); 1233 ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetFields_C","PCFieldSplitSetFields_FieldSplit", 1234 PCFieldSplitSetFields_FieldSplit);CHKERRQ(ierr); 1235 ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetIS_C","PCFieldSplitSetIS_FieldSplit", 1236 PCFieldSplitSetIS_FieldSplit);CHKERRQ(ierr); 1237 ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetType_C","PCFieldSplitSetType_FieldSplit", 1238 PCFieldSplitSetType_FieldSplit);CHKERRQ(ierr); 1239 ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetBlockSize_C","PCFieldSplitSetBlockSize_FieldSplit", 1240 PCFieldSplitSetBlockSize_FieldSplit);CHKERRQ(ierr); 1241 PetscFunctionReturn(0); 1242 } 1243 EXTERN_C_END 1244 1245 1246 /*MC 1247 Block_Preconditioners - PETSc provides support for a variety of "block preconditioners", this provides an 1248 overview of these methods. 1249 1250 Consider the solution to ( A B ) (x_1) = (b_1) 1251 ( C D ) (x_2) (b_2) 1252 1253 Important special cases, the Stokes equation: C = B' and D = 0 (A B) (x_1) = (b_1) 1254 B' 0) (x_2) (b_2) 1255 1256 One of the goals of the PCFieldSplit preconditioner in PETSc is to provide a variety of preconditioners 1257 for this block system. 1258 1259 Consider an additional matrix (Ap Bp) 1260 (Cp Dp) where some or all of the entries may be the same as 1261 in the original matrix (for example Ap == A). 1262 1263 In the following, A^ denotes the approximate application of the inverse of A, possibly using Ap in the 1264 approximation. In PETSc this simply means one has called KSPSetOperators(ksp,A,Ap,...) or KSPSetOperators(ksp,Ap,Ap,...) 1265 1266 Block Jacobi: x_1 = A^ b_1 1267 x_2 = D^ b_2 1268 1269 Lower block Gauss-Seidel: x_1 = A^ b_1 1270 x_2 = D^ (b_2 - C x_1) variant x_2 = D^ (b_2 - Cp x_1) 1271 1272 Symmetric Gauss-Seidel: x_1 = x_1 + A^(b_1 - A x_1 - B x_2) variant x_1 = x_1 + A^(b_1 - Ap x_1 - Bp x_2) 1273 Interestingly this form is not actually a symmetric matrix, the symmetric version is 1274 x_1 = A^(b_1 - B x_2) variant x_1 = A^(b_1 - Bp x_2) 1275 1276 Level: intermediate 1277 1278 .seealso: PCCreate(), PCSetType(), PCType (for list of available types), PC, PCFIELDSPLIT 1279 PCFieldSplitGetSubKSP(), PCFieldSplitSetFields(), PCFieldSplitSetType(), PCFieldSplitSetIS(), PCFieldSplitSchurPrecondition() 1280 M*/ 1281