1 2 #include <petsc-private/pcimpl.h> /*I "petscpc.h" I*/ 3 #include <petscdmcomposite.h> 4 5 /* 6 There is a nice discussion of block preconditioners in 7 8 [El08] A taxonomy and comparison of parallel block multi-level preconditioners for the incompressible Navier–Stokes equations 9 Howard Elman, V.E. Howle, John Shadid, Robert Shuttleworth, Ray Tuminaro, Journal of Computational Physics 227 (2008) 1790--1808 10 http://chess.cs.umd.edu/~elman/papers/tax.pdf 11 */ 12 13 const char *const PCFieldSplitSchurPreTypes[] = {"SELF","A11","USER","PCFieldSplitSchurPreType","PC_FIELDSPLIT_SCHUR_PRE_",0}; 14 const char *const PCFieldSplitSchurFactTypes[] = {"DIAG","LOWER","UPPER","FULL","PCFieldSplitSchurFactType","PC_FIELDSPLIT_SCHUR_FACT_",0}; 15 16 typedef struct _PC_FieldSplitLink *PC_FieldSplitLink; 17 struct _PC_FieldSplitLink { 18 KSP ksp; 19 Vec x,y,z; 20 char *splitname; 21 PetscInt nfields; 22 PetscInt *fields,*fields_col; 23 VecScatter sctx; 24 IS is,is_col; 25 PC_FieldSplitLink next,previous; 26 }; 27 28 typedef struct { 29 PCCompositeType type; 30 PetscBool defaultsplit; /* Flag for a system with a set of 'k' scalar fields with the same layout (and bs = k) */ 31 PetscBool splitdefined; /* Flag is set after the splits have been defined, to prevent more splits from being added */ 32 PetscBool realdiagonal; /* Flag to use the diagonal blocks of mat preconditioned by pmat, instead of just pmat */ 33 PetscInt bs; /* Block size for IS and Mat structures */ 34 PetscInt nsplits; /* Number of field divisions defined */ 35 Vec *x,*y,w1,w2; 36 Mat *mat; /* The diagonal block for each split */ 37 Mat *pmat; /* The preconditioning diagonal block for each split */ 38 Mat *Afield; /* The rows of the matrix associated with each split */ 39 PetscBool issetup; 40 41 /* Only used when Schur complement preconditioning is used */ 42 Mat B; /* The (0,1) block */ 43 Mat C; /* The (1,0) block */ 44 Mat schur; /* The Schur complement S = A11 - A10 A00^{-1} A01, the KSP here, kspinner, is H_1 in [El08] */ 45 Mat schur_user; /* User-provided preconditioning matrix for the Schur complement */ 46 PCFieldSplitSchurPreType schurpre; /* Determines which preconditioning matrix is used for the Schur complement */ 47 PCFieldSplitSchurFactType schurfactorization; 48 KSP kspschur; /* The solver for S */ 49 KSP kspupper; /* The solver for A in the upper diagonal part of the factorization (H_2 in [El08]) */ 50 PC_FieldSplitLink head; 51 PetscBool reset; /* indicates PCReset() has been last called on this object, hack */ 52 PetscBool suboptionsset; /* Indicates that the KSPSetFromOptions() has been called on the sub-KSPs */ 53 } PC_FieldSplit; 54 55 /* 56 Notes: there is no particular reason that pmat, x, and y are stored as arrays in PC_FieldSplit instead of 57 inside PC_FieldSplitLink, just historical. If you want to be able to add new fields after already using the 58 PC you could change this. 59 */ 60 61 /* This helper is so that setting a user-provided preconditioning matrix is orthogonal to choosing to use it. This way the 62 * application-provided FormJacobian can provide this matrix without interfering with the user's (command-line) choices. */ 63 static Mat FieldSplitSchurPre(PC_FieldSplit *jac) 64 { 65 switch (jac->schurpre) { 66 case PC_FIELDSPLIT_SCHUR_PRE_SELF: return jac->schur; 67 case PC_FIELDSPLIT_SCHUR_PRE_A11: return jac->pmat[1]; 68 case PC_FIELDSPLIT_SCHUR_PRE_USER: /* Use a user-provided matrix if it is given, otherwise diagonal block */ 69 default: 70 return jac->schur_user ? jac->schur_user : jac->pmat[1]; 71 } 72 } 73 74 75 #undef __FUNCT__ 76 #define __FUNCT__ "PCView_FieldSplit" 77 static PetscErrorCode PCView_FieldSplit(PC pc,PetscViewer viewer) 78 { 79 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 80 PetscErrorCode ierr; 81 PetscBool iascii,isdraw; 82 PetscInt i,j; 83 PC_FieldSplitLink ilink = jac->head; 84 85 PetscFunctionBegin; 86 ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr); 87 ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERDRAW,&isdraw);CHKERRQ(ierr); 88 if (iascii) { 89 if (jac->bs > 0) { 90 ierr = PetscViewerASCIIPrintf(viewer," FieldSplit with %s composition: total splits = %D, blocksize = %D\n",PCCompositeTypes[jac->type],jac->nsplits,jac->bs);CHKERRQ(ierr); 91 } else { 92 ierr = PetscViewerASCIIPrintf(viewer," FieldSplit with %s composition: total splits = %D\n",PCCompositeTypes[jac->type],jac->nsplits);CHKERRQ(ierr); 93 } 94 if (jac->realdiagonal) { 95 ierr = PetscViewerASCIIPrintf(viewer," using actual matrix for blocks rather than preconditioner matrix\n");CHKERRQ(ierr); 96 } 97 ierr = PetscViewerASCIIPrintf(viewer," Solver info for each split is in the following KSP objects:\n");CHKERRQ(ierr); 98 ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 99 for (i=0; i<jac->nsplits; i++) { 100 if (ilink->fields) { 101 ierr = PetscViewerASCIIPrintf(viewer,"Split number %D Fields ",i);CHKERRQ(ierr); 102 ierr = PetscViewerASCIIUseTabs(viewer,PETSC_FALSE);CHKERRQ(ierr); 103 for (j=0; j<ilink->nfields; j++) { 104 if (j > 0) { 105 ierr = PetscViewerASCIIPrintf(viewer,",");CHKERRQ(ierr); 106 } 107 ierr = PetscViewerASCIIPrintf(viewer," %D",ilink->fields[j]);CHKERRQ(ierr); 108 } 109 ierr = PetscViewerASCIIPrintf(viewer,"\n");CHKERRQ(ierr); 110 ierr = PetscViewerASCIIUseTabs(viewer,PETSC_TRUE);CHKERRQ(ierr); 111 } else { 112 ierr = PetscViewerASCIIPrintf(viewer,"Split number %D Defined by IS\n",i);CHKERRQ(ierr); 113 } 114 ierr = KSPView(ilink->ksp,viewer);CHKERRQ(ierr); 115 ilink = ilink->next; 116 } 117 ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 118 } 119 120 if (isdraw) { 121 PetscDraw draw; 122 PetscReal x,y,w,wd; 123 124 ierr = PetscViewerDrawGetDraw(viewer,0,&draw);CHKERRQ(ierr); 125 ierr = PetscDrawGetCurrentPoint(draw,&x,&y);CHKERRQ(ierr); 126 w = 2*PetscMin(1.0 - x,x); 127 wd = w/(jac->nsplits + 1); 128 x = x - wd*(jac->nsplits-1)/2.0; 129 for (i=0; i<jac->nsplits; i++) { 130 ierr = PetscDrawPushCurrentPoint(draw,x,y);CHKERRQ(ierr); 131 ierr = KSPView(ilink->ksp,viewer);CHKERRQ(ierr); 132 ierr = PetscDrawPopCurrentPoint(draw);CHKERRQ(ierr); 133 x += wd; 134 ilink = ilink->next; 135 } 136 } 137 PetscFunctionReturn(0); 138 } 139 140 #undef __FUNCT__ 141 #define __FUNCT__ "PCView_FieldSplit_Schur" 142 static PetscErrorCode PCView_FieldSplit_Schur(PC pc,PetscViewer viewer) 143 { 144 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 145 PetscErrorCode ierr; 146 PetscBool iascii,isdraw; 147 PetscInt i,j; 148 PC_FieldSplitLink ilink = jac->head; 149 150 PetscFunctionBegin; 151 ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr); 152 ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERDRAW,&isdraw);CHKERRQ(ierr); 153 if (iascii) { 154 if (jac->bs > 0) { 155 ierr = PetscViewerASCIIPrintf(viewer," FieldSplit with Schur preconditioner, blocksize = %D, factorization %s\n",jac->bs,PCFieldSplitSchurFactTypes[jac->schurfactorization]);CHKERRQ(ierr); 156 } else { 157 ierr = PetscViewerASCIIPrintf(viewer," FieldSplit with Schur preconditioner, factorization %s\n",PCFieldSplitSchurFactTypes[jac->schurfactorization]);CHKERRQ(ierr); 158 } 159 if (jac->realdiagonal) { 160 ierr = PetscViewerASCIIPrintf(viewer," using actual matrix for blocks rather than preconditioner matrix\n");CHKERRQ(ierr); 161 } 162 switch (jac->schurpre) { 163 case PC_FIELDSPLIT_SCHUR_PRE_SELF: 164 ierr = PetscViewerASCIIPrintf(viewer," Preconditioner for the Schur complement formed from S itself\n");CHKERRQ(ierr);break; 165 case PC_FIELDSPLIT_SCHUR_PRE_A11: 166 ierr = PetscViewerASCIIPrintf(viewer," Preconditioner for the Schur complement formed from A11\n");CHKERRQ(ierr);break; 167 case PC_FIELDSPLIT_SCHUR_PRE_USER: 168 if (jac->schur_user) { 169 ierr = PetscViewerASCIIPrintf(viewer," Preconditioner for the Schur complement formed from user provided matrix\n");CHKERRQ(ierr); 170 } else { 171 ierr = PetscViewerASCIIPrintf(viewer," Preconditioner for the Schur complement formed from A11\n");CHKERRQ(ierr); 172 } 173 break; 174 default: 175 SETERRQ1(((PetscObject) pc)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Invalid Schur preconditioning type: %d", jac->schurpre); 176 } 177 ierr = PetscViewerASCIIPrintf(viewer," Split info:\n");CHKERRQ(ierr); 178 ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 179 for (i=0; i<jac->nsplits; i++) { 180 if (ilink->fields) { 181 ierr = PetscViewerASCIIPrintf(viewer,"Split number %D Fields ",i);CHKERRQ(ierr); 182 ierr = PetscViewerASCIIUseTabs(viewer,PETSC_FALSE);CHKERRQ(ierr); 183 for (j=0; j<ilink->nfields; j++) { 184 if (j > 0) { 185 ierr = PetscViewerASCIIPrintf(viewer,",");CHKERRQ(ierr); 186 } 187 ierr = PetscViewerASCIIPrintf(viewer," %D",ilink->fields[j]);CHKERRQ(ierr); 188 } 189 ierr = PetscViewerASCIIPrintf(viewer,"\n");CHKERRQ(ierr); 190 ierr = PetscViewerASCIIUseTabs(viewer,PETSC_TRUE);CHKERRQ(ierr); 191 } else { 192 ierr = PetscViewerASCIIPrintf(viewer,"Split number %D Defined by IS\n",i);CHKERRQ(ierr); 193 } 194 ilink = ilink->next; 195 } 196 ierr = PetscViewerASCIIPrintf(viewer,"KSP solver for A00 block \n");CHKERRQ(ierr); 197 ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 198 ierr = KSPView(jac->head->ksp,viewer);CHKERRQ(ierr); 199 ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 200 if (jac->kspupper != jac->head->ksp) { 201 ierr = PetscViewerASCIIPrintf(viewer,"KSP solver for upper A00 in upper triangular factor \n");CHKERRQ(ierr); 202 ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 203 ierr = KSPView(jac->kspupper,viewer);CHKERRQ(ierr); 204 ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 205 } 206 ierr = PetscViewerASCIIPrintf(viewer,"KSP solver for S = A11 - A10 inv(A00) A01 \n");CHKERRQ(ierr); 207 ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 208 if (jac->kspschur) { 209 ierr = KSPView(jac->kspschur,viewer);CHKERRQ(ierr); 210 } else { 211 ierr = PetscViewerASCIIPrintf(viewer," not yet available\n");CHKERRQ(ierr); 212 } 213 ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 214 ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 215 } else if (isdraw) { 216 PetscDraw draw; 217 PetscReal x,y,w,wd,h; 218 PetscInt cnt = 2; 219 char str[32]; 220 221 ierr = PetscViewerDrawGetDraw(viewer,0,&draw);CHKERRQ(ierr); 222 ierr = PetscDrawGetCurrentPoint(draw,&x,&y);CHKERRQ(ierr); 223 if (jac->kspupper != jac->head->ksp) cnt++; 224 w = 2*PetscMin(1.0 - x,x); 225 wd = w/(cnt + 1); 226 227 ierr = PetscSNPrintf(str,32,"Schur fact. %s",PCFieldSplitSchurFactTypes[jac->schurfactorization]);CHKERRQ(ierr); 228 ierr = PetscDrawBoxedString(draw,x,y,PETSC_DRAW_RED,PETSC_DRAW_BLACK,str,NULL,&h);CHKERRQ(ierr); 229 y -= h; 230 if (jac->schurpre == PC_FIELDSPLIT_SCHUR_PRE_USER && !jac->schur_user) { 231 ierr = PetscSNPrintf(str,32,"Prec. for Schur from %s",PCFieldSplitSchurPreTypes[PC_FIELDSPLIT_SCHUR_PRE_A11]);CHKERRQ(ierr); 232 } else { 233 ierr = PetscSNPrintf(str,32,"Prec. for Schur from %s",PCFieldSplitSchurPreTypes[jac->schurpre]);CHKERRQ(ierr); 234 } 235 ierr = PetscDrawBoxedString(draw,x+wd*(cnt-1)/2.0,y,PETSC_DRAW_RED,PETSC_DRAW_BLACK,str,NULL,&h);CHKERRQ(ierr); 236 y -= h; 237 x = x - wd*(cnt-1)/2.0; 238 239 ierr = PetscDrawPushCurrentPoint(draw,x,y);CHKERRQ(ierr); 240 ierr = KSPView(jac->head->ksp,viewer);CHKERRQ(ierr); 241 ierr = PetscDrawPopCurrentPoint(draw);CHKERRQ(ierr); 242 if (jac->kspupper != jac->head->ksp) { 243 x += wd; 244 ierr = PetscDrawPushCurrentPoint(draw,x,y);CHKERRQ(ierr); 245 ierr = KSPView(jac->kspupper,viewer);CHKERRQ(ierr); 246 ierr = PetscDrawPopCurrentPoint(draw);CHKERRQ(ierr); 247 } 248 x += wd; 249 ierr = PetscDrawPushCurrentPoint(draw,x,y);CHKERRQ(ierr); 250 ierr = KSPView(jac->kspschur,viewer);CHKERRQ(ierr); 251 ierr = PetscDrawPopCurrentPoint(draw);CHKERRQ(ierr); 252 } 253 PetscFunctionReturn(0); 254 } 255 256 #undef __FUNCT__ 257 #define __FUNCT__ "PCFieldSplitSetRuntimeSplits_Private" 258 /* Precondition: jac->bs is set to a meaningful value */ 259 static PetscErrorCode PCFieldSplitSetRuntimeSplits_Private(PC pc) 260 { 261 PetscErrorCode ierr; 262 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 263 PetscInt i,nfields,*ifields,nfields_col,*ifields_col; 264 PetscBool flg,flg_col; 265 char optionname[128],splitname[8],optionname_col[128]; 266 267 PetscFunctionBegin; 268 ierr = PetscMalloc(jac->bs*sizeof(PetscInt),&ifields);CHKERRQ(ierr); 269 ierr = PetscMalloc(jac->bs*sizeof(PetscInt),&ifields_col);CHKERRQ(ierr); 270 for (i=0,flg=PETSC_TRUE;; i++) { 271 ierr = PetscSNPrintf(splitname,sizeof(splitname),"%D",i);CHKERRQ(ierr); 272 ierr = PetscSNPrintf(optionname,sizeof(optionname),"-pc_fieldsplit_%D_fields",i);CHKERRQ(ierr); 273 ierr = PetscSNPrintf(optionname_col,sizeof(optionname_col),"-pc_fieldsplit_%D_fields_col",i);CHKERRQ(ierr); 274 nfields = jac->bs; 275 nfields_col = jac->bs; 276 ierr = PetscOptionsGetIntArray(((PetscObject)pc)->prefix,optionname,ifields,&nfields,&flg);CHKERRQ(ierr); 277 ierr = PetscOptionsGetIntArray(((PetscObject)pc)->prefix,optionname_col,ifields_col,&nfields_col,&flg_col);CHKERRQ(ierr); 278 if (!flg) break; 279 else if (flg && !flg_col) { 280 if (!nfields) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Cannot list zero fields"); 281 ierr = PCFieldSplitSetFields(pc,splitname,nfields,ifields,ifields);CHKERRQ(ierr); 282 } else { 283 if (!nfields || !nfields_col) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Cannot list zero fields"); 284 if (nfields != nfields_col) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Number of row and column fields must match"); 285 ierr = PCFieldSplitSetFields(pc,splitname,nfields,ifields,ifields_col);CHKERRQ(ierr); 286 } 287 } 288 if (i > 0) { 289 /* Makes command-line setting of splits take precedence over setting them in code. 290 Otherwise subsequent calls to PCFieldSplitSetIS() or PCFieldSplitSetFields() would 291 create new splits, which would probably not be what the user wanted. */ 292 jac->splitdefined = PETSC_TRUE; 293 } 294 ierr = PetscFree(ifields);CHKERRQ(ierr); 295 ierr = PetscFree(ifields_col);CHKERRQ(ierr); 296 PetscFunctionReturn(0); 297 } 298 299 #undef __FUNCT__ 300 #define __FUNCT__ "PCFieldSplitSetDefaults" 301 static PetscErrorCode PCFieldSplitSetDefaults(PC pc) 302 { 303 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 304 PetscErrorCode ierr; 305 PC_FieldSplitLink ilink = jac->head; 306 PetscBool fieldsplit_default = PETSC_FALSE,stokes = PETSC_FALSE; 307 PetscInt i; 308 309 PetscFunctionBegin; 310 /* 311 Kinda messy, but at least this now uses DMCreateFieldDecomposition() even with jac->reset. 312 Should probably be rewritten. 313 */ 314 if (!ilink || jac->reset) { 315 ierr = PetscOptionsGetBool(((PetscObject)pc)->prefix,"-pc_fieldsplit_detect_saddle_point",&stokes,NULL);CHKERRQ(ierr); 316 if (pc->dm && !stokes) { 317 PetscInt numFields, f, i, j; 318 char **fieldNames; 319 IS *fields; 320 DM *dms; 321 DM subdm[128]; 322 PetscBool flg; 323 324 ierr = DMCreateFieldDecomposition(pc->dm, &numFields, &fieldNames, &fields, &dms);CHKERRQ(ierr); 325 /* Allow the user to prescribe the splits */ 326 for (i = 0, flg = PETSC_TRUE;; i++) { 327 PetscInt ifields[128]; 328 IS compField; 329 char optionname[128], splitname[8]; 330 PetscInt nfields = numFields; 331 332 ierr = PetscSNPrintf(optionname, sizeof(optionname), "-pc_fieldsplit_%D_fields", i);CHKERRQ(ierr); 333 ierr = PetscOptionsGetIntArray(((PetscObject) pc)->prefix, optionname, ifields, &nfields, &flg);CHKERRQ(ierr); 334 if (!flg) break; 335 if (numFields > 128) SETERRQ1(((PetscObject) pc)->comm,PETSC_ERR_SUP,"Cannot currently support %d > 128 fields", numFields); 336 ierr = DMCreateSubDM(pc->dm, nfields, ifields, &compField, &subdm[i]);CHKERRQ(ierr); 337 if (nfields == 1) { 338 ierr = PCFieldSplitSetIS(pc, fieldNames[ifields[0]], compField);CHKERRQ(ierr); 339 /* ierr = PetscPrintf(((PetscObject) pc)->comm, "%s Field Indices:", fieldNames[ifields[0]]);CHKERRQ(ierr); 340 ierr = ISView(compField, NULL);CHKERRQ(ierr); */ 341 } else { 342 ierr = PetscSNPrintf(splitname, sizeof(splitname), "%D", i);CHKERRQ(ierr); 343 ierr = PCFieldSplitSetIS(pc, splitname, compField);CHKERRQ(ierr); 344 /* ierr = PetscPrintf(((PetscObject) pc)->comm, "%s Field Indices:", splitname);CHKERRQ(ierr); 345 ierr = ISView(compField, NULL);CHKERRQ(ierr); */ 346 } 347 ierr = ISDestroy(&compField);CHKERRQ(ierr); 348 for (j = 0; j < nfields; ++j) { 349 f = ifields[j]; 350 ierr = PetscFree(fieldNames[f]);CHKERRQ(ierr); 351 ierr = ISDestroy(&fields[f]);CHKERRQ(ierr); 352 } 353 } 354 if (i == 0) { 355 for (f = 0; f < numFields; ++f) { 356 ierr = PCFieldSplitSetIS(pc, fieldNames[f], fields[f]);CHKERRQ(ierr); 357 ierr = PetscFree(fieldNames[f]);CHKERRQ(ierr); 358 ierr = ISDestroy(&fields[f]);CHKERRQ(ierr); 359 } 360 } else { 361 for (j=0; j<numFields; j++) { 362 ierr = DMDestroy(dms+j);CHKERRQ(ierr); 363 } 364 ierr = PetscFree(dms);CHKERRQ(ierr); 365 ierr = PetscMalloc(i * sizeof(DM), &dms);CHKERRQ(ierr); 366 for (j = 0; j < i; ++j) dms[j] = subdm[j]; 367 } 368 ierr = PetscFree(fieldNames);CHKERRQ(ierr); 369 ierr = PetscFree(fields);CHKERRQ(ierr); 370 if (dms) { 371 ierr = PetscInfo(pc, "Setting up physics based fieldsplit preconditioner using the embedded DM\n");CHKERRQ(ierr); 372 for (ilink = jac->head, i = 0; ilink; ilink = ilink->next, ++i) { 373 const char *prefix; 374 ierr = PetscObjectGetOptionsPrefix((PetscObject)(ilink->ksp),&prefix);CHKERRQ(ierr); 375 ierr = PetscObjectSetOptionsPrefix((PetscObject)(dms[i]), prefix);CHKERRQ(ierr); 376 ierr = KSPSetDM(ilink->ksp, dms[i]);CHKERRQ(ierr); 377 ierr = KSPSetDMActive(ilink->ksp, PETSC_FALSE);CHKERRQ(ierr); 378 ierr = PetscObjectIncrementTabLevel((PetscObject)dms[i],(PetscObject)ilink->ksp,0);CHKERRQ(ierr); 379 ierr = DMDestroy(&dms[i]);CHKERRQ(ierr); 380 } 381 ierr = PetscFree(dms);CHKERRQ(ierr); 382 } 383 } else { 384 if (jac->bs <= 0) { 385 if (pc->pmat) { 386 ierr = MatGetBlockSize(pc->pmat,&jac->bs);CHKERRQ(ierr); 387 } else jac->bs = 1; 388 } 389 390 ierr = PetscOptionsGetBool(((PetscObject)pc)->prefix,"-pc_fieldsplit_default",&fieldsplit_default,NULL);CHKERRQ(ierr); 391 if (stokes) { 392 IS zerodiags,rest; 393 PetscInt nmin,nmax; 394 395 ierr = MatGetOwnershipRange(pc->mat,&nmin,&nmax);CHKERRQ(ierr); 396 ierr = MatFindZeroDiagonals(pc->mat,&zerodiags);CHKERRQ(ierr); 397 ierr = ISComplement(zerodiags,nmin,nmax,&rest);CHKERRQ(ierr); 398 if (jac->reset) { 399 jac->head->is = rest; 400 jac->head->next->is = zerodiags; 401 } else { 402 ierr = PCFieldSplitSetIS(pc,"0",rest);CHKERRQ(ierr); 403 ierr = PCFieldSplitSetIS(pc,"1",zerodiags);CHKERRQ(ierr); 404 } 405 ierr = ISDestroy(&zerodiags);CHKERRQ(ierr); 406 ierr = ISDestroy(&rest);CHKERRQ(ierr); 407 } else { 408 if (jac->reset) SETERRQ(((PetscObject)pc)->comm,PETSC_ERR_SUP,"Cases not yet handled when PCReset() was used"); 409 if (!fieldsplit_default) { 410 /* Allow user to set fields from command line, if bs was known at the time of PCSetFromOptions_FieldSplit() 411 then it is set there. This is not ideal because we should only have options set in XXSetFromOptions(). */ 412 ierr = PCFieldSplitSetRuntimeSplits_Private(pc);CHKERRQ(ierr); 413 if (jac->splitdefined) {ierr = PetscInfo(pc,"Splits defined using the options database\n");CHKERRQ(ierr);} 414 } 415 if (fieldsplit_default || !jac->splitdefined) { 416 ierr = PetscInfo(pc,"Using default splitting of fields\n");CHKERRQ(ierr); 417 for (i=0; i<jac->bs; i++) { 418 char splitname[8]; 419 ierr = PetscSNPrintf(splitname,sizeof(splitname),"%D",i);CHKERRQ(ierr); 420 ierr = PCFieldSplitSetFields(pc,splitname,1,&i,&i);CHKERRQ(ierr); 421 } 422 jac->defaultsplit = PETSC_TRUE; 423 } 424 } 425 } 426 } else if (jac->nsplits == 1) { 427 if (ilink->is) { 428 IS is2; 429 PetscInt nmin,nmax; 430 431 ierr = MatGetOwnershipRange(pc->mat,&nmin,&nmax);CHKERRQ(ierr); 432 ierr = ISComplement(ilink->is,nmin,nmax,&is2);CHKERRQ(ierr); 433 ierr = PCFieldSplitSetIS(pc,"1",is2);CHKERRQ(ierr); 434 ierr = ISDestroy(&is2);CHKERRQ(ierr); 435 } else SETERRQ(((PetscObject) pc)->comm,PETSC_ERR_SUP,"Must provide at least two sets of fields to PCFieldSplit()"); 436 } 437 438 439 if (jac->nsplits < 2) SETERRQ1(((PetscObject) pc)->comm,PETSC_ERR_PLIB,"Unhandled case, must have at least two fields, not %d", jac->nsplits); 440 PetscFunctionReturn(0); 441 } 442 443 PetscErrorCode PetscOptionsFindPairPrefix_Private(const char pre[], const char name[], char *value[], PetscBool *flg); 444 445 #undef __FUNCT__ 446 #define __FUNCT__ "PCSetUp_FieldSplit" 447 static PetscErrorCode PCSetUp_FieldSplit(PC pc) 448 { 449 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 450 PetscErrorCode ierr; 451 PC_FieldSplitLink ilink; 452 PetscInt i,nsplit; 453 MatStructure flag = pc->flag; 454 PetscBool sorted, sorted_col; 455 456 PetscFunctionBegin; 457 ierr = PCFieldSplitSetDefaults(pc);CHKERRQ(ierr); 458 nsplit = jac->nsplits; 459 ilink = jac->head; 460 461 /* get the matrices for each split */ 462 if (!jac->issetup) { 463 PetscInt rstart,rend,nslots,bs; 464 465 jac->issetup = PETSC_TRUE; 466 467 /* This is done here instead of in PCFieldSplitSetFields() because may not have matrix at that point */ 468 if (jac->defaultsplit || !ilink->is) { 469 if (jac->bs <= 0) jac->bs = nsplit; 470 } 471 bs = jac->bs; 472 ierr = MatGetOwnershipRange(pc->pmat,&rstart,&rend);CHKERRQ(ierr); 473 nslots = (rend - rstart)/bs; 474 for (i=0; i<nsplit; i++) { 475 if (jac->defaultsplit) { 476 ierr = ISCreateStride(((PetscObject)pc)->comm,nslots,rstart+i,nsplit,&ilink->is);CHKERRQ(ierr); 477 ierr = ISDuplicate(ilink->is,&ilink->is_col);CHKERRQ(ierr); 478 } else if (!ilink->is) { 479 if (ilink->nfields > 1) { 480 PetscInt *ii,*jj,j,k,nfields = ilink->nfields,*fields = ilink->fields,*fields_col = ilink->fields_col; 481 ierr = PetscMalloc(ilink->nfields*nslots*sizeof(PetscInt),&ii);CHKERRQ(ierr); 482 ierr = PetscMalloc(ilink->nfields*nslots*sizeof(PetscInt),&jj);CHKERRQ(ierr); 483 for (j=0; j<nslots; j++) { 484 for (k=0; k<nfields; k++) { 485 ii[nfields*j + k] = rstart + bs*j + fields[k]; 486 jj[nfields*j + k] = rstart + bs*j + fields_col[k]; 487 } 488 } 489 ierr = ISCreateGeneral(((PetscObject)pc)->comm,nslots*nfields,ii,PETSC_OWN_POINTER,&ilink->is);CHKERRQ(ierr); 490 ierr = ISCreateGeneral(((PetscObject)pc)->comm,nslots*nfields,jj,PETSC_OWN_POINTER,&ilink->is_col);CHKERRQ(ierr); 491 } else { 492 ierr = ISCreateStride(((PetscObject)pc)->comm,nslots,rstart+ilink->fields[0],bs,&ilink->is);CHKERRQ(ierr); 493 ierr = ISCreateStride(((PetscObject)pc)->comm,nslots,rstart+ilink->fields_col[0],bs,&ilink->is_col);CHKERRQ(ierr); 494 } 495 } 496 ierr = ISSorted(ilink->is,&sorted);CHKERRQ(ierr); 497 if (ilink->is_col) { ierr = ISSorted(ilink->is_col,&sorted_col);CHKERRQ(ierr); } 498 if (!sorted || !sorted_col) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Fields must be sorted when creating split"); 499 ilink = ilink->next; 500 } 501 } 502 503 ilink = jac->head; 504 if (!jac->pmat) { 505 Vec xtmp; 506 507 ierr = MatGetVecs(pc->pmat,&xtmp,NULL);CHKERRQ(ierr); 508 ierr = PetscMalloc(nsplit*sizeof(Mat),&jac->pmat);CHKERRQ(ierr); 509 ierr = PetscMalloc2(nsplit,Vec,&jac->x,nsplit,Vec,&jac->y);CHKERRQ(ierr); 510 for (i=0; i<nsplit; i++) { 511 MatNullSpace sp; 512 513 /* Check for preconditioning matrix attached to IS */ 514 ierr = PetscObjectQuery((PetscObject) ilink->is, "pmat", (PetscObject*) &jac->pmat[i]);CHKERRQ(ierr); 515 if (jac->pmat[i]) { 516 ierr = PetscObjectReference((PetscObject) jac->pmat[i]);CHKERRQ(ierr); 517 if (jac->type == PC_COMPOSITE_SCHUR) { 518 jac->schur_user = jac->pmat[i]; 519 520 ierr = PetscObjectReference((PetscObject) jac->schur_user);CHKERRQ(ierr); 521 } 522 } else { 523 ierr = MatGetSubMatrix(pc->pmat,ilink->is,ilink->is_col,MAT_INITIAL_MATRIX,&jac->pmat[i]);CHKERRQ(ierr); 524 } 525 /* create work vectors for each split */ 526 ierr = MatGetVecs(jac->pmat[i],&jac->x[i],&jac->y[i]);CHKERRQ(ierr); 527 ilink->x = jac->x[i]; ilink->y = jac->y[i]; ilink->z = NULL; 528 /* compute scatter contexts needed by multiplicative versions and non-default splits */ 529 ierr = VecScatterCreate(xtmp,ilink->is,jac->x[i],NULL,&ilink->sctx);CHKERRQ(ierr); 530 /* Check for null space attached to IS */ 531 ierr = PetscObjectQuery((PetscObject) ilink->is, "nullspace", (PetscObject*) &sp);CHKERRQ(ierr); 532 if (sp) { 533 ierr = MatSetNullSpace(jac->pmat[i], sp);CHKERRQ(ierr); 534 } 535 ierr = PetscObjectQuery((PetscObject) ilink->is, "nearnullspace", (PetscObject*) &sp);CHKERRQ(ierr); 536 if (sp) { 537 ierr = MatSetNearNullSpace(jac->pmat[i], sp);CHKERRQ(ierr); 538 } 539 ilink = ilink->next; 540 } 541 ierr = VecDestroy(&xtmp);CHKERRQ(ierr); 542 } else { 543 for (i=0; i<nsplit; i++) { 544 Mat pmat; 545 546 /* Check for preconditioning matrix attached to IS */ 547 ierr = PetscObjectQuery((PetscObject) ilink->is, "pmat", (PetscObject*) &pmat);CHKERRQ(ierr); 548 if (!pmat) { 549 ierr = MatGetSubMatrix(pc->pmat,ilink->is,ilink->is_col,MAT_REUSE_MATRIX,&jac->pmat[i]);CHKERRQ(ierr); 550 } 551 ilink = ilink->next; 552 } 553 } 554 if (jac->realdiagonal) { 555 ilink = jac->head; 556 if (!jac->mat) { 557 ierr = PetscMalloc(nsplit*sizeof(Mat),&jac->mat);CHKERRQ(ierr); 558 for (i=0; i<nsplit; i++) { 559 ierr = MatGetSubMatrix(pc->mat,ilink->is,ilink->is_col,MAT_INITIAL_MATRIX,&jac->mat[i]);CHKERRQ(ierr); 560 ilink = ilink->next; 561 } 562 } else { 563 for (i=0; i<nsplit; i++) { 564 if (jac->mat[i]) {ierr = MatGetSubMatrix(pc->mat,ilink->is,ilink->is_col,MAT_REUSE_MATRIX,&jac->mat[i]);CHKERRQ(ierr);} 565 ilink = ilink->next; 566 } 567 } 568 } else { 569 jac->mat = jac->pmat; 570 } 571 572 if (jac->type != PC_COMPOSITE_ADDITIVE && jac->type != PC_COMPOSITE_SCHUR) { 573 /* extract the rows of the matrix associated with each field: used for efficient computation of residual inside algorithm */ 574 ilink = jac->head; 575 if (!jac->Afield) { 576 ierr = PetscMalloc(nsplit*sizeof(Mat),&jac->Afield);CHKERRQ(ierr); 577 for (i=0; i<nsplit; i++) { 578 ierr = MatGetSubMatrix(pc->mat,ilink->is,NULL,MAT_INITIAL_MATRIX,&jac->Afield[i]);CHKERRQ(ierr); 579 ilink = ilink->next; 580 } 581 } else { 582 for (i=0; i<nsplit; i++) { 583 ierr = MatGetSubMatrix(pc->mat,ilink->is,NULL,MAT_REUSE_MATRIX,&jac->Afield[i]);CHKERRQ(ierr); 584 ilink = ilink->next; 585 } 586 } 587 } 588 589 if (jac->type == PC_COMPOSITE_SCHUR) { 590 IS ccis; 591 PetscInt rstart,rend; 592 char lscname[256]; 593 PetscObject LSC_L; 594 if (nsplit != 2) SETERRQ(((PetscObject)pc)->comm,PETSC_ERR_ARG_INCOMP,"To use Schur complement preconditioner you must have exactly 2 fields"); 595 596 /* When extracting off-diagonal submatrices, we take complements from this range */ 597 ierr = MatGetOwnershipRangeColumn(pc->mat,&rstart,&rend);CHKERRQ(ierr); 598 599 /* need to handle case when one is resetting up the preconditioner */ 600 if (jac->schur) { 601 KSP kspA = jac->head->ksp, kspInner = NULL, kspUpper = jac->kspupper; 602 603 ierr = MatSchurComplementGetKSP(jac->schur, &kspInner);CHKERRQ(ierr); 604 ilink = jac->head; 605 ierr = ISComplement(ilink->is_col,rstart,rend,&ccis);CHKERRQ(ierr); 606 ierr = MatGetSubMatrix(pc->mat,ilink->is,ccis,MAT_REUSE_MATRIX,&jac->B);CHKERRQ(ierr); 607 ierr = ISDestroy(&ccis);CHKERRQ(ierr); 608 ilink = ilink->next; 609 ierr = ISComplement(ilink->is_col,rstart,rend,&ccis);CHKERRQ(ierr); 610 ierr = MatGetSubMatrix(pc->mat,ilink->is,ccis,MAT_REUSE_MATRIX,&jac->C);CHKERRQ(ierr); 611 ierr = ISDestroy(&ccis);CHKERRQ(ierr); 612 ierr = MatSchurComplementUpdate(jac->schur,jac->mat[0],jac->pmat[0],jac->B,jac->C,jac->mat[1],pc->flag);CHKERRQ(ierr); 613 if (kspA != kspInner) { 614 ierr = KSPSetOperators(kspA,jac->mat[0],jac->pmat[0],pc->flag);CHKERRQ(ierr); 615 } 616 if (kspUpper != kspA) { 617 ierr = KSPSetOperators(kspUpper,jac->mat[0],jac->pmat[0],pc->flag);CHKERRQ(ierr); 618 } 619 ierr = KSPSetOperators(jac->kspschur,jac->schur,FieldSplitSchurPre(jac),pc->flag);CHKERRQ(ierr); 620 } else { 621 KSP ksp; 622 const char *Dprefix; 623 char schurprefix[256]; 624 char schurtestoption[256]; 625 MatNullSpace sp; 626 PetscBool flg; 627 628 /* extract the A01 and A10 matrices */ 629 ilink = jac->head; 630 ierr = ISComplement(ilink->is_col,rstart,rend,&ccis);CHKERRQ(ierr); 631 ierr = MatGetSubMatrix(pc->mat,ilink->is,ccis,MAT_INITIAL_MATRIX,&jac->B);CHKERRQ(ierr); 632 ierr = ISDestroy(&ccis);CHKERRQ(ierr); 633 ilink = ilink->next; 634 ierr = ISComplement(ilink->is_col,rstart,rend,&ccis);CHKERRQ(ierr); 635 ierr = MatGetSubMatrix(pc->mat,ilink->is,ccis,MAT_INITIAL_MATRIX,&jac->C);CHKERRQ(ierr); 636 ierr = ISDestroy(&ccis);CHKERRQ(ierr); 637 638 /* Use mat[0] (diagonal block of the real matrix) preconditioned by pmat[0] to define Schur complement */ 639 ierr = MatCreate(((PetscObject)jac->mat[0])->comm,&jac->schur);CHKERRQ(ierr); 640 ierr = MatSetType(jac->schur,MATSCHURCOMPLEMENT);CHKERRQ(ierr); 641 ierr = MatSchurComplementGetKSP(jac->schur, &ksp);CHKERRQ(ierr); 642 ierr = PetscSNPrintf(schurprefix, sizeof(schurprefix), "%sfieldsplit_%s_inner_", ((PetscObject)pc)->prefix ? ((PetscObject)pc)->prefix : "", ilink->splitname);CHKERRQ(ierr); 643 /* Indent this deeper to emphasize the "inner" nature of this solver. */ 644 ierr = PetscObjectIncrementTabLevel((PetscObject)ksp, (PetscObject) pc, 2);CHKERRQ(ierr); 645 ierr = KSPSetOptionsPrefix(ksp, schurprefix);CHKERRQ(ierr); 646 ierr = MatSchurComplementSet(jac->schur,jac->mat[0],jac->pmat[0],jac->B,jac->C,jac->mat[1]);CHKERRQ(ierr); 647 648 ierr = MatGetNullSpace(jac->pmat[1], &sp);CHKERRQ(ierr); 649 if (sp) { 650 ierr = MatSetNullSpace(jac->schur, sp);CHKERRQ(ierr); 651 } 652 653 ierr = PetscSNPrintf(schurtestoption, sizeof(schurtestoption), "-fieldsplit_%s_inner_", ilink->splitname);CHKERRQ(ierr); 654 ierr = PetscOptionsFindPairPrefix_Private(((PetscObject)pc)->prefix, schurtestoption, NULL, &flg);CHKERRQ(ierr); 655 if (flg) { 656 DM dmInner; 657 658 /* Set DM for new solver */ 659 ierr = KSPGetDM(jac->head->ksp, &dmInner);CHKERRQ(ierr); 660 ierr = KSPSetDM(ksp, dmInner);CHKERRQ(ierr); 661 ierr = KSPSetDMActive(ksp, PETSC_FALSE);CHKERRQ(ierr); 662 ierr = KSPSetOperators(jac->head->ksp,jac->mat[0],jac->pmat[0],flag);CHKERRQ(ierr); 663 ierr = KSPSetFromOptions(jac->head->ksp);CHKERRQ(ierr); 664 } else { 665 ierr = MatSchurComplementSetKSP(jac->schur, jac->head->ksp);CHKERRQ(ierr); 666 ierr = PetscObjectReference((PetscObject) jac->head->ksp);CHKERRQ(ierr); 667 } 668 ierr = MatSetFromOptions(jac->schur);CHKERRQ(ierr); 669 670 ierr = PetscSNPrintf(schurtestoption, sizeof(schurtestoption), "-fieldsplit_%s_upper_", ilink->splitname);CHKERRQ(ierr); 671 ierr = PetscOptionsFindPairPrefix_Private(((PetscObject)pc)->prefix, schurtestoption, NULL, &flg);CHKERRQ(ierr); 672 if (flg) { 673 DM dmInner; 674 675 ierr = PetscSNPrintf(schurprefix, sizeof(schurprefix), "%sfieldsplit_%s_upper_", ((PetscObject)pc)->prefix ? ((PetscObject)pc)->prefix : "", ilink->splitname);CHKERRQ(ierr); 676 ierr = KSPCreate(((PetscObject) pc)->comm, &jac->kspupper);CHKERRQ(ierr); 677 ierr = KSPSetOptionsPrefix(jac->kspupper, schurprefix);CHKERRQ(ierr); 678 ierr = KSPGetDM(jac->head->ksp, &dmInner);CHKERRQ(ierr); 679 ierr = KSPSetDM(jac->kspupper, dmInner);CHKERRQ(ierr); 680 ierr = KSPSetDMActive(jac->kspupper, PETSC_FALSE);CHKERRQ(ierr); 681 ierr = KSPSetFromOptions(jac->kspupper);CHKERRQ(ierr); 682 ierr = KSPSetOperators(jac->kspupper,jac->mat[0],jac->pmat[0],flag);CHKERRQ(ierr); 683 ierr = VecDuplicate(jac->head->x, &jac->head->z);CHKERRQ(ierr); 684 } else { 685 jac->kspupper = jac->head->ksp; 686 ierr = PetscObjectReference((PetscObject) jac->head->ksp);CHKERRQ(ierr); 687 } 688 689 ierr = KSPCreate(((PetscObject)pc)->comm,&jac->kspschur);CHKERRQ(ierr); 690 ierr = PetscLogObjectParent((PetscObject)pc,(PetscObject)jac->kspschur);CHKERRQ(ierr); 691 ierr = PetscObjectIncrementTabLevel((PetscObject)jac->kspschur,(PetscObject)pc,1);CHKERRQ(ierr); 692 ierr = KSPSetOperators(jac->kspschur,jac->schur,FieldSplitSchurPre(jac),DIFFERENT_NONZERO_PATTERN);CHKERRQ(ierr); 693 if (jac->schurpre == PC_FIELDSPLIT_SCHUR_PRE_SELF) { 694 PC pcschur; 695 ierr = KSPGetPC(jac->kspschur,&pcschur);CHKERRQ(ierr); 696 ierr = PCSetType(pcschur,PCNONE);CHKERRQ(ierr); 697 /* Note: This is bad if there exist preconditioners for MATSCHURCOMPLEMENT */ 698 } 699 ierr = KSPGetOptionsPrefix(jac->head->next->ksp, &Dprefix);CHKERRQ(ierr); 700 ierr = KSPSetOptionsPrefix(jac->kspschur, Dprefix);CHKERRQ(ierr); 701 /* really want setfromoptions called in PCSetFromOptions_FieldSplit(), but it is not ready yet */ 702 /* need to call this every time, since the jac->kspschur is freshly created, otherwise its options never get set */ 703 ierr = KSPSetFromOptions(jac->kspschur);CHKERRQ(ierr); 704 } 705 706 /* HACK: special support to forward L and Lp matrices that might be used by PCLSC */ 707 ierr = PetscSNPrintf(lscname,sizeof(lscname),"%s_LSC_L",ilink->splitname);CHKERRQ(ierr); 708 ierr = PetscObjectQuery((PetscObject)pc->mat,lscname,(PetscObject*)&LSC_L);CHKERRQ(ierr); 709 if (!LSC_L) {ierr = PetscObjectQuery((PetscObject)pc->pmat,lscname,(PetscObject*)&LSC_L);CHKERRQ(ierr);} 710 if (LSC_L) {ierr = PetscObjectCompose((PetscObject)jac->schur,"LSC_L",(PetscObject)LSC_L);CHKERRQ(ierr);} 711 ierr = PetscSNPrintf(lscname,sizeof(lscname),"%s_LSC_Lp",ilink->splitname);CHKERRQ(ierr); 712 ierr = PetscObjectQuery((PetscObject)pc->pmat,lscname,(PetscObject*)&LSC_L);CHKERRQ(ierr); 713 if (!LSC_L) {ierr = PetscObjectQuery((PetscObject)pc->mat,lscname,(PetscObject*)&LSC_L);CHKERRQ(ierr);} 714 if (LSC_L) {ierr = PetscObjectCompose((PetscObject)jac->schur,"LSC_Lp",(PetscObject)LSC_L);CHKERRQ(ierr);} 715 } else { 716 /* set up the individual splits' PCs */ 717 i = 0; 718 ilink = jac->head; 719 while (ilink) { 720 ierr = KSPSetOperators(ilink->ksp,jac->mat[i],jac->pmat[i],flag);CHKERRQ(ierr); 721 /* really want setfromoptions called in PCSetFromOptions_FieldSplit(), but it is not ready yet */ 722 if (!jac->suboptionsset) {ierr = KSPSetFromOptions(ilink->ksp);CHKERRQ(ierr);} 723 i++; 724 ilink = ilink->next; 725 } 726 } 727 728 jac->suboptionsset = PETSC_TRUE; 729 PetscFunctionReturn(0); 730 } 731 732 #define FieldSplitSplitSolveAdd(ilink,xx,yy) \ 733 (VecScatterBegin(ilink->sctx,xx,ilink->x,INSERT_VALUES,SCATTER_FORWARD) || \ 734 VecScatterEnd(ilink->sctx,xx,ilink->x,INSERT_VALUES,SCATTER_FORWARD) || \ 735 KSPSolve(ilink->ksp,ilink->x,ilink->y) || \ 736 VecScatterBegin(ilink->sctx,ilink->y,yy,ADD_VALUES,SCATTER_REVERSE) || \ 737 VecScatterEnd(ilink->sctx,ilink->y,yy,ADD_VALUES,SCATTER_REVERSE)) 738 739 #undef __FUNCT__ 740 #define __FUNCT__ "PCApply_FieldSplit_Schur" 741 static PetscErrorCode PCApply_FieldSplit_Schur(PC pc,Vec x,Vec y) 742 { 743 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 744 PetscErrorCode ierr; 745 PC_FieldSplitLink ilinkA = jac->head, ilinkD = ilinkA->next; 746 KSP kspA = ilinkA->ksp, kspLower = kspA, kspUpper = jac->kspupper; 747 748 PetscFunctionBegin; 749 switch (jac->schurfactorization) { 750 case PC_FIELDSPLIT_SCHUR_FACT_DIAG: 751 /* [A00 0; 0 -S], positive definite, suitable for MINRES */ 752 ierr = VecScatterBegin(ilinkA->sctx,x,ilinkA->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 753 ierr = VecScatterBegin(ilinkD->sctx,x,ilinkD->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 754 ierr = VecScatterEnd(ilinkA->sctx,x,ilinkA->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 755 ierr = KSPSolve(kspA,ilinkA->x,ilinkA->y);CHKERRQ(ierr); 756 ierr = VecScatterBegin(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 757 ierr = VecScatterEnd(ilinkD->sctx,x,ilinkD->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 758 ierr = KSPSolve(jac->kspschur,ilinkD->x,ilinkD->y);CHKERRQ(ierr); 759 ierr = VecScale(ilinkD->y,-1.);CHKERRQ(ierr); 760 ierr = VecScatterBegin(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 761 ierr = VecScatterEnd(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 762 ierr = VecScatterEnd(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 763 break; 764 case PC_FIELDSPLIT_SCHUR_FACT_LOWER: 765 /* [A00 0; A10 S], suitable for left preconditioning */ 766 ierr = VecScatterBegin(ilinkA->sctx,x,ilinkA->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 767 ierr = VecScatterEnd(ilinkA->sctx,x,ilinkA->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 768 ierr = KSPSolve(kspA,ilinkA->x,ilinkA->y);CHKERRQ(ierr); 769 ierr = MatMult(jac->C,ilinkA->y,ilinkD->x);CHKERRQ(ierr); 770 ierr = VecScale(ilinkD->x,-1.);CHKERRQ(ierr); 771 ierr = VecScatterBegin(ilinkD->sctx,x,ilinkD->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 772 ierr = VecScatterBegin(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 773 ierr = VecScatterEnd(ilinkD->sctx,x,ilinkD->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 774 ierr = KSPSolve(jac->kspschur,ilinkD->x,ilinkD->y);CHKERRQ(ierr); 775 ierr = VecScatterBegin(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 776 ierr = VecScatterEnd(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 777 ierr = VecScatterEnd(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 778 break; 779 case PC_FIELDSPLIT_SCHUR_FACT_UPPER: 780 /* [A00 A01; 0 S], suitable for right preconditioning */ 781 ierr = VecScatterBegin(ilinkD->sctx,x,ilinkD->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 782 ierr = VecScatterEnd(ilinkD->sctx,x,ilinkD->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 783 ierr = KSPSolve(jac->kspschur,ilinkD->x,ilinkD->y);CHKERRQ(ierr); 784 ierr = MatMult(jac->B,ilinkD->y,ilinkA->x);CHKERRQ(ierr); 785 ierr = VecScale(ilinkA->x,-1.);CHKERRQ(ierr); 786 ierr = VecScatterBegin(ilinkA->sctx,x,ilinkA->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 787 ierr = VecScatterBegin(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 788 ierr = VecScatterEnd(ilinkA->sctx,x,ilinkA->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 789 ierr = KSPSolve(kspA,ilinkA->x,ilinkA->y);CHKERRQ(ierr); 790 ierr = VecScatterBegin(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 791 ierr = VecScatterEnd(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 792 ierr = VecScatterEnd(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 793 break; 794 case PC_FIELDSPLIT_SCHUR_FACT_FULL: 795 /* [1 0; A10 A00^{-1} 1] [A00 0; 0 S] [1 A00^{-1}A01; 0 1], an exact solve if applied exactly, needs one extra solve with A */ 796 ierr = VecScatterBegin(ilinkA->sctx,x,ilinkA->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 797 ierr = VecScatterEnd(ilinkA->sctx,x,ilinkA->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 798 ierr = KSPSolve(kspLower,ilinkA->x,ilinkA->y);CHKERRQ(ierr); 799 ierr = MatMult(jac->C,ilinkA->y,ilinkD->x);CHKERRQ(ierr); 800 ierr = VecScale(ilinkD->x,-1.0);CHKERRQ(ierr); 801 ierr = VecScatterBegin(ilinkD->sctx,x,ilinkD->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 802 ierr = VecScatterEnd(ilinkD->sctx,x,ilinkD->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 803 804 ierr = KSPSolve(jac->kspschur,ilinkD->x,ilinkD->y);CHKERRQ(ierr); 805 ierr = VecScatterBegin(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 806 ierr = VecScatterEnd(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 807 808 if (kspUpper == kspA) { 809 ierr = MatMult(jac->B,ilinkD->y,ilinkA->y);CHKERRQ(ierr); 810 ierr = VecAXPY(ilinkA->x,-1.0,ilinkA->y);CHKERRQ(ierr); 811 ierr = KSPSolve(kspA,ilinkA->x,ilinkA->y);CHKERRQ(ierr); 812 } else { 813 ierr = KSPSolve(kspA,ilinkA->x,ilinkA->y);CHKERRQ(ierr); 814 ierr = MatMult(jac->B,ilinkD->y,ilinkA->x);CHKERRQ(ierr); 815 ierr = KSPSolve(kspUpper,ilinkA->x,ilinkA->z);CHKERRQ(ierr); 816 ierr = VecAXPY(ilinkA->y,-1.0,ilinkA->z);CHKERRQ(ierr); 817 } 818 ierr = VecScatterBegin(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 819 ierr = VecScatterEnd(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 820 } 821 PetscFunctionReturn(0); 822 } 823 824 #undef __FUNCT__ 825 #define __FUNCT__ "PCApply_FieldSplit" 826 static PetscErrorCode PCApply_FieldSplit(PC pc,Vec x,Vec y) 827 { 828 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 829 PetscErrorCode ierr; 830 PC_FieldSplitLink ilink = jac->head; 831 PetscInt cnt,bs; 832 833 PetscFunctionBegin; 834 if (jac->bs > 0) { 835 ierr = VecSetBlockSize(x,jac->bs);CHKERRQ(ierr); 836 ierr = VecSetBlockSize(y,jac->bs);CHKERRQ(ierr); 837 } 838 CHKMEMQ; 839 if (jac->type == PC_COMPOSITE_ADDITIVE) { 840 if (jac->defaultsplit) { 841 ierr = VecGetBlockSize(x,&bs);CHKERRQ(ierr); 842 if (jac->bs > 0 && bs != jac->bs) SETERRQ2(((PetscObject)pc)->comm,PETSC_ERR_ARG_WRONGSTATE,"Blocksize of x vector %D does not match fieldsplit blocksize %D",bs,jac->bs); 843 ierr = VecGetBlockSize(y,&bs);CHKERRQ(ierr); 844 if (jac->bs > 0 && bs != jac->bs) SETERRQ2(((PetscObject)pc)->comm,PETSC_ERR_ARG_WRONGSTATE,"Blocksize of y vector %D does not match fieldsplit blocksize %D",bs,jac->bs); 845 ierr = VecStrideGatherAll(x,jac->x,INSERT_VALUES);CHKERRQ(ierr); 846 while (ilink) { 847 ierr = KSPSolve(ilink->ksp,ilink->x,ilink->y);CHKERRQ(ierr); 848 ilink = ilink->next; 849 } 850 ierr = VecStrideScatterAll(jac->y,y,INSERT_VALUES);CHKERRQ(ierr); 851 } else { 852 ierr = VecSet(y,0.0);CHKERRQ(ierr); 853 while (ilink) { 854 ierr = FieldSplitSplitSolveAdd(ilink,x,y);CHKERRQ(ierr); 855 ilink = ilink->next; 856 } 857 } 858 } else if (jac->type == PC_COMPOSITE_MULTIPLICATIVE || jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) { 859 if (!jac->w1) { 860 ierr = VecDuplicate(x,&jac->w1);CHKERRQ(ierr); 861 ierr = VecDuplicate(x,&jac->w2);CHKERRQ(ierr); 862 } 863 ierr = VecSet(y,0.0);CHKERRQ(ierr); 864 ierr = FieldSplitSplitSolveAdd(ilink,x,y);CHKERRQ(ierr); 865 cnt = 1; 866 while (ilink->next) { 867 ilink = ilink->next; 868 /* compute the residual only over the part of the vector needed */ 869 ierr = MatMult(jac->Afield[cnt++],y,ilink->x);CHKERRQ(ierr); 870 ierr = VecScale(ilink->x,-1.0);CHKERRQ(ierr); 871 ierr = VecScatterBegin(ilink->sctx,x,ilink->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 872 ierr = VecScatterEnd(ilink->sctx,x,ilink->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 873 ierr = KSPSolve(ilink->ksp,ilink->x,ilink->y);CHKERRQ(ierr); 874 ierr = VecScatterBegin(ilink->sctx,ilink->y,y,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 875 ierr = VecScatterEnd(ilink->sctx,ilink->y,y,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 876 } 877 if (jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) { 878 cnt -= 2; 879 while (ilink->previous) { 880 ilink = ilink->previous; 881 /* compute the residual only over the part of the vector needed */ 882 ierr = MatMult(jac->Afield[cnt--],y,ilink->x);CHKERRQ(ierr); 883 ierr = VecScale(ilink->x,-1.0);CHKERRQ(ierr); 884 ierr = VecScatterBegin(ilink->sctx,x,ilink->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 885 ierr = VecScatterEnd(ilink->sctx,x,ilink->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 886 ierr = KSPSolve(ilink->ksp,ilink->x,ilink->y);CHKERRQ(ierr); 887 ierr = VecScatterBegin(ilink->sctx,ilink->y,y,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 888 ierr = VecScatterEnd(ilink->sctx,ilink->y,y,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 889 } 890 } 891 } else SETERRQ1(((PetscObject)pc)->comm,PETSC_ERR_SUP,"Unsupported or unknown composition",(int) jac->type); 892 CHKMEMQ; 893 PetscFunctionReturn(0); 894 } 895 896 #define FieldSplitSplitSolveAddTranspose(ilink,xx,yy) \ 897 (VecScatterBegin(ilink->sctx,xx,ilink->y,INSERT_VALUES,SCATTER_FORWARD) || \ 898 VecScatterEnd(ilink->sctx,xx,ilink->y,INSERT_VALUES,SCATTER_FORWARD) || \ 899 KSPSolveTranspose(ilink->ksp,ilink->y,ilink->x) || \ 900 VecScatterBegin(ilink->sctx,ilink->x,yy,ADD_VALUES,SCATTER_REVERSE) || \ 901 VecScatterEnd(ilink->sctx,ilink->x,yy,ADD_VALUES,SCATTER_REVERSE)) 902 903 #undef __FUNCT__ 904 #define __FUNCT__ "PCApplyTranspose_FieldSplit" 905 static PetscErrorCode PCApplyTranspose_FieldSplit(PC pc,Vec x,Vec y) 906 { 907 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 908 PetscErrorCode ierr; 909 PC_FieldSplitLink ilink = jac->head; 910 PetscInt bs; 911 912 PetscFunctionBegin; 913 CHKMEMQ; 914 if (jac->type == PC_COMPOSITE_ADDITIVE) { 915 if (jac->defaultsplit) { 916 ierr = VecGetBlockSize(x,&bs);CHKERRQ(ierr); 917 if (jac->bs > 0 && bs != jac->bs) SETERRQ2(((PetscObject)pc)->comm,PETSC_ERR_ARG_WRONGSTATE,"Blocksize of x vector %D does not match fieldsplit blocksize %D",bs,jac->bs); 918 ierr = VecGetBlockSize(y,&bs);CHKERRQ(ierr); 919 if (jac->bs > 0 && bs != jac->bs) SETERRQ2(((PetscObject)pc)->comm,PETSC_ERR_ARG_WRONGSTATE,"Blocksize of y vector %D does not match fieldsplit blocksize %D",bs,jac->bs); 920 ierr = VecStrideGatherAll(x,jac->x,INSERT_VALUES);CHKERRQ(ierr); 921 while (ilink) { 922 ierr = KSPSolveTranspose(ilink->ksp,ilink->x,ilink->y);CHKERRQ(ierr); 923 ilink = ilink->next; 924 } 925 ierr = VecStrideScatterAll(jac->y,y,INSERT_VALUES);CHKERRQ(ierr); 926 } else { 927 ierr = VecSet(y,0.0);CHKERRQ(ierr); 928 while (ilink) { 929 ierr = FieldSplitSplitSolveAddTranspose(ilink,x,y);CHKERRQ(ierr); 930 ilink = ilink->next; 931 } 932 } 933 } else { 934 if (!jac->w1) { 935 ierr = VecDuplicate(x,&jac->w1);CHKERRQ(ierr); 936 ierr = VecDuplicate(x,&jac->w2);CHKERRQ(ierr); 937 } 938 ierr = VecSet(y,0.0);CHKERRQ(ierr); 939 if (jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) { 940 ierr = FieldSplitSplitSolveAddTranspose(ilink,x,y);CHKERRQ(ierr); 941 while (ilink->next) { 942 ilink = ilink->next; 943 ierr = MatMultTranspose(pc->mat,y,jac->w1);CHKERRQ(ierr); 944 ierr = VecWAXPY(jac->w2,-1.0,jac->w1,x);CHKERRQ(ierr); 945 ierr = FieldSplitSplitSolveAddTranspose(ilink,jac->w2,y);CHKERRQ(ierr); 946 } 947 while (ilink->previous) { 948 ilink = ilink->previous; 949 ierr = MatMultTranspose(pc->mat,y,jac->w1);CHKERRQ(ierr); 950 ierr = VecWAXPY(jac->w2,-1.0,jac->w1,x);CHKERRQ(ierr); 951 ierr = FieldSplitSplitSolveAddTranspose(ilink,jac->w2,y);CHKERRQ(ierr); 952 } 953 } else { 954 while (ilink->next) { /* get to last entry in linked list */ 955 ilink = ilink->next; 956 } 957 ierr = FieldSplitSplitSolveAddTranspose(ilink,x,y);CHKERRQ(ierr); 958 while (ilink->previous) { 959 ilink = ilink->previous; 960 ierr = MatMultTranspose(pc->mat,y,jac->w1);CHKERRQ(ierr); 961 ierr = VecWAXPY(jac->w2,-1.0,jac->w1,x);CHKERRQ(ierr); 962 ierr = FieldSplitSplitSolveAddTranspose(ilink,jac->w2,y);CHKERRQ(ierr); 963 } 964 } 965 } 966 CHKMEMQ; 967 PetscFunctionReturn(0); 968 } 969 970 #undef __FUNCT__ 971 #define __FUNCT__ "PCReset_FieldSplit" 972 static PetscErrorCode PCReset_FieldSplit(PC pc) 973 { 974 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 975 PetscErrorCode ierr; 976 PC_FieldSplitLink ilink = jac->head,next; 977 978 PetscFunctionBegin; 979 while (ilink) { 980 ierr = KSPReset(ilink->ksp);CHKERRQ(ierr); 981 ierr = VecDestroy(&ilink->x);CHKERRQ(ierr); 982 ierr = VecDestroy(&ilink->y);CHKERRQ(ierr); 983 ierr = VecDestroy(&ilink->z);CHKERRQ(ierr); 984 ierr = VecScatterDestroy(&ilink->sctx);CHKERRQ(ierr); 985 ierr = ISDestroy(&ilink->is);CHKERRQ(ierr); 986 ierr = ISDestroy(&ilink->is_col);CHKERRQ(ierr); 987 next = ilink->next; 988 ilink = next; 989 } 990 ierr = PetscFree2(jac->x,jac->y);CHKERRQ(ierr); 991 if (jac->mat && jac->mat != jac->pmat) { 992 ierr = MatDestroyMatrices(jac->nsplits,&jac->mat);CHKERRQ(ierr); 993 } else if (jac->mat) { 994 jac->mat = NULL; 995 } 996 if (jac->pmat) {ierr = MatDestroyMatrices(jac->nsplits,&jac->pmat);CHKERRQ(ierr);} 997 if (jac->Afield) {ierr = MatDestroyMatrices(jac->nsplits,&jac->Afield);CHKERRQ(ierr);} 998 ierr = VecDestroy(&jac->w1);CHKERRQ(ierr); 999 ierr = VecDestroy(&jac->w2);CHKERRQ(ierr); 1000 ierr = MatDestroy(&jac->schur);CHKERRQ(ierr); 1001 ierr = MatDestroy(&jac->schur_user);CHKERRQ(ierr); 1002 ierr = KSPDestroy(&jac->kspschur);CHKERRQ(ierr); 1003 ierr = KSPDestroy(&jac->kspupper);CHKERRQ(ierr); 1004 ierr = MatDestroy(&jac->B);CHKERRQ(ierr); 1005 ierr = MatDestroy(&jac->C);CHKERRQ(ierr); 1006 jac->reset = PETSC_TRUE; 1007 PetscFunctionReturn(0); 1008 } 1009 1010 #undef __FUNCT__ 1011 #define __FUNCT__ "PCDestroy_FieldSplit" 1012 static PetscErrorCode PCDestroy_FieldSplit(PC pc) 1013 { 1014 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 1015 PetscErrorCode ierr; 1016 PC_FieldSplitLink ilink = jac->head,next; 1017 1018 PetscFunctionBegin; 1019 ierr = PCReset_FieldSplit(pc);CHKERRQ(ierr); 1020 while (ilink) { 1021 ierr = KSPDestroy(&ilink->ksp);CHKERRQ(ierr); 1022 next = ilink->next; 1023 ierr = PetscFree(ilink->splitname);CHKERRQ(ierr); 1024 ierr = PetscFree(ilink->fields);CHKERRQ(ierr); 1025 ierr = PetscFree(ilink->fields_col);CHKERRQ(ierr); 1026 ierr = PetscFree(ilink);CHKERRQ(ierr); 1027 ilink = next; 1028 } 1029 ierr = PetscFree2(jac->x,jac->y);CHKERRQ(ierr); 1030 ierr = PetscFree(pc->data);CHKERRQ(ierr); 1031 ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitGetSubKSP_C","",NULL);CHKERRQ(ierr); 1032 ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetFields_C","",NULL);CHKERRQ(ierr); 1033 ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetIS_C","",NULL);CHKERRQ(ierr); 1034 ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetType_C","",NULL);CHKERRQ(ierr); 1035 ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetBlockSize_C","",NULL);CHKERRQ(ierr); 1036 ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSchurPrecondition_C","",NULL);CHKERRQ(ierr); 1037 ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetSchurFactType_C","",NULL);CHKERRQ(ierr); 1038 PetscFunctionReturn(0); 1039 } 1040 1041 #undef __FUNCT__ 1042 #define __FUNCT__ "PCSetFromOptions_FieldSplit" 1043 static PetscErrorCode PCSetFromOptions_FieldSplit(PC pc) 1044 { 1045 PetscErrorCode ierr; 1046 PetscInt bs; 1047 PetscBool flg,stokes = PETSC_FALSE; 1048 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 1049 PCCompositeType ctype; 1050 1051 PetscFunctionBegin; 1052 ierr = PetscOptionsHead("FieldSplit options");CHKERRQ(ierr); 1053 ierr = PetscOptionsBool("-pc_fieldsplit_real_diagonal","Use diagonal blocks of the operator","PCFieldSplitSetRealDiagonal",jac->realdiagonal,&jac->realdiagonal,NULL);CHKERRQ(ierr); 1054 ierr = PetscOptionsInt("-pc_fieldsplit_block_size","Blocksize that defines number of fields","PCFieldSplitSetBlockSize",jac->bs,&bs,&flg);CHKERRQ(ierr); 1055 if (flg) { 1056 ierr = PCFieldSplitSetBlockSize(pc,bs);CHKERRQ(ierr); 1057 } 1058 1059 ierr = PetscOptionsGetBool(((PetscObject)pc)->prefix,"-pc_fieldsplit_detect_saddle_point",&stokes,NULL);CHKERRQ(ierr); 1060 if (stokes) { 1061 ierr = PCFieldSplitSetType(pc,PC_COMPOSITE_SCHUR);CHKERRQ(ierr); 1062 jac->schurpre = PC_FIELDSPLIT_SCHUR_PRE_SELF; 1063 } 1064 1065 ierr = PetscOptionsEnum("-pc_fieldsplit_type","Type of composition","PCFieldSplitSetType",PCCompositeTypes,(PetscEnum)jac->type,(PetscEnum*)&ctype,&flg);CHKERRQ(ierr); 1066 if (flg) { 1067 ierr = PCFieldSplitSetType(pc,ctype);CHKERRQ(ierr); 1068 } 1069 /* Only setup fields once */ 1070 if ((jac->bs > 0) && (jac->nsplits == 0)) { 1071 /* only allow user to set fields from command line if bs is already known. 1072 otherwise user can set them in PCFieldSplitSetDefaults() */ 1073 ierr = PCFieldSplitSetRuntimeSplits_Private(pc);CHKERRQ(ierr); 1074 if (jac->splitdefined) {ierr = PetscInfo(pc,"Splits defined using the options database\n");CHKERRQ(ierr);} 1075 } 1076 if (jac->type == PC_COMPOSITE_SCHUR) { 1077 ierr = PetscOptionsGetEnum(((PetscObject)pc)->prefix,"-pc_fieldsplit_schur_factorization_type",PCFieldSplitSchurFactTypes,(PetscEnum*)&jac->schurfactorization,&flg);CHKERRQ(ierr); 1078 if (flg) {ierr = PetscInfo(pc,"Deprecated use of -pc_fieldsplit_schur_factorization_type\n");CHKERRQ(ierr);} 1079 ierr = PetscOptionsEnum("-pc_fieldsplit_schur_fact_type","Which off-diagonal parts of the block factorization to use","PCFieldSplitSetSchurFactType",PCFieldSplitSchurFactTypes,(PetscEnum)jac->schurfactorization,(PetscEnum*)&jac->schurfactorization,NULL);CHKERRQ(ierr); 1080 ierr = PetscOptionsEnum("-pc_fieldsplit_schur_precondition","How to build preconditioner for Schur complement","PCFieldSplitSchurPrecondition",PCFieldSplitSchurPreTypes,(PetscEnum)jac->schurpre,(PetscEnum*)&jac->schurpre,NULL);CHKERRQ(ierr); 1081 } 1082 ierr = PetscOptionsTail();CHKERRQ(ierr); 1083 PetscFunctionReturn(0); 1084 } 1085 1086 /*------------------------------------------------------------------------------------*/ 1087 1088 EXTERN_C_BEGIN 1089 #undef __FUNCT__ 1090 #define __FUNCT__ "PCFieldSplitSetFields_FieldSplit" 1091 PetscErrorCode PCFieldSplitSetFields_FieldSplit(PC pc,const char splitname[],PetscInt n,const PetscInt *fields,const PetscInt *fields_col) 1092 { 1093 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 1094 PetscErrorCode ierr; 1095 PC_FieldSplitLink ilink,next = jac->head; 1096 char prefix[128]; 1097 PetscInt i; 1098 1099 PetscFunctionBegin; 1100 if (jac->splitdefined) { 1101 ierr = PetscInfo1(pc,"Ignoring new split \"%s\" because the splits have already been defined\n",splitname);CHKERRQ(ierr); 1102 PetscFunctionReturn(0); 1103 } 1104 for (i=0; i<n; i++) { 1105 if (fields[i] >= jac->bs) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Field %D requested but only %D exist",fields[i],jac->bs); 1106 if (fields[i] < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Negative field %D requested",fields[i]); 1107 } 1108 ierr = PetscNew(struct _PC_FieldSplitLink,&ilink);CHKERRQ(ierr); 1109 if (splitname) { 1110 ierr = PetscStrallocpy(splitname,&ilink->splitname);CHKERRQ(ierr); 1111 } else { 1112 ierr = PetscMalloc(3*sizeof(char),&ilink->splitname);CHKERRQ(ierr); 1113 ierr = PetscSNPrintf(ilink->splitname,2,"%s",jac->nsplits);CHKERRQ(ierr); 1114 } 1115 ierr = PetscMalloc(n*sizeof(PetscInt),&ilink->fields);CHKERRQ(ierr); 1116 ierr = PetscMemcpy(ilink->fields,fields,n*sizeof(PetscInt));CHKERRQ(ierr); 1117 ierr = PetscMalloc(n*sizeof(PetscInt),&ilink->fields_col);CHKERRQ(ierr); 1118 ierr = PetscMemcpy(ilink->fields_col,fields_col,n*sizeof(PetscInt));CHKERRQ(ierr); 1119 1120 ilink->nfields = n; 1121 ilink->next = NULL; 1122 ierr = KSPCreate(((PetscObject)pc)->comm,&ilink->ksp);CHKERRQ(ierr); 1123 ierr = PetscObjectIncrementTabLevel((PetscObject)ilink->ksp,(PetscObject)pc,1);CHKERRQ(ierr); 1124 ierr = KSPSetType(ilink->ksp,KSPPREONLY);CHKERRQ(ierr); 1125 ierr = PetscLogObjectParent((PetscObject)pc,(PetscObject)ilink->ksp);CHKERRQ(ierr); 1126 1127 ierr = PetscSNPrintf(prefix,sizeof(prefix),"%sfieldsplit_%s_",((PetscObject)pc)->prefix ? ((PetscObject)pc)->prefix : "",ilink->splitname);CHKERRQ(ierr); 1128 ierr = KSPSetOptionsPrefix(ilink->ksp,prefix);CHKERRQ(ierr); 1129 1130 if (!next) { 1131 jac->head = ilink; 1132 ilink->previous = NULL; 1133 } else { 1134 while (next->next) { 1135 next = next->next; 1136 } 1137 next->next = ilink; 1138 ilink->previous = next; 1139 } 1140 jac->nsplits++; 1141 PetscFunctionReturn(0); 1142 } 1143 EXTERN_C_END 1144 1145 EXTERN_C_BEGIN 1146 #undef __FUNCT__ 1147 #define __FUNCT__ "PCFieldSplitGetSubKSP_FieldSplit_Schur" 1148 PetscErrorCode PCFieldSplitGetSubKSP_FieldSplit_Schur(PC pc,PetscInt *n,KSP **subksp) 1149 { 1150 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 1151 PetscErrorCode ierr; 1152 1153 PetscFunctionBegin; 1154 ierr = PetscMalloc(jac->nsplits*sizeof(KSP),subksp);CHKERRQ(ierr); 1155 ierr = MatSchurComplementGetKSP(jac->schur,*subksp);CHKERRQ(ierr); 1156 1157 (*subksp)[1] = jac->kspschur; 1158 if (n) *n = jac->nsplits; 1159 PetscFunctionReturn(0); 1160 } 1161 EXTERN_C_END 1162 1163 EXTERN_C_BEGIN 1164 #undef __FUNCT__ 1165 #define __FUNCT__ "PCFieldSplitGetSubKSP_FieldSplit" 1166 PetscErrorCode PCFieldSplitGetSubKSP_FieldSplit(PC pc,PetscInt *n,KSP **subksp) 1167 { 1168 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 1169 PetscErrorCode ierr; 1170 PetscInt cnt = 0; 1171 PC_FieldSplitLink ilink = jac->head; 1172 1173 PetscFunctionBegin; 1174 ierr = PetscMalloc(jac->nsplits*sizeof(KSP),subksp);CHKERRQ(ierr); 1175 while (ilink) { 1176 (*subksp)[cnt++] = ilink->ksp; 1177 ilink = ilink->next; 1178 } 1179 if (cnt != jac->nsplits) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Corrupt PCFIELDSPLIT object: number of splits in linked list %D does not match number in object %D",cnt,jac->nsplits); 1180 if (n) *n = jac->nsplits; 1181 PetscFunctionReturn(0); 1182 } 1183 EXTERN_C_END 1184 1185 EXTERN_C_BEGIN 1186 #undef __FUNCT__ 1187 #define __FUNCT__ "PCFieldSplitSetIS_FieldSplit" 1188 PetscErrorCode PCFieldSplitSetIS_FieldSplit(PC pc,const char splitname[],IS is) 1189 { 1190 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 1191 PetscErrorCode ierr; 1192 PC_FieldSplitLink ilink, next = jac->head; 1193 char prefix[128]; 1194 1195 PetscFunctionBegin; 1196 if (jac->splitdefined) { 1197 ierr = PetscInfo1(pc,"Ignoring new split \"%s\" because the splits have already been defined\n",splitname);CHKERRQ(ierr); 1198 PetscFunctionReturn(0); 1199 } 1200 ierr = PetscNew(struct _PC_FieldSplitLink,&ilink);CHKERRQ(ierr); 1201 if (splitname) { 1202 ierr = PetscStrallocpy(splitname,&ilink->splitname);CHKERRQ(ierr); 1203 } else { 1204 ierr = PetscMalloc(8*sizeof(char),&ilink->splitname);CHKERRQ(ierr); 1205 ierr = PetscSNPrintf(ilink->splitname,7,"%D",jac->nsplits);CHKERRQ(ierr); 1206 } 1207 ierr = PetscObjectReference((PetscObject)is);CHKERRQ(ierr); 1208 ierr = ISDestroy(&ilink->is);CHKERRQ(ierr); 1209 ilink->is = is; 1210 ierr = PetscObjectReference((PetscObject)is);CHKERRQ(ierr); 1211 ierr = ISDestroy(&ilink->is_col);CHKERRQ(ierr); 1212 ilink->is_col = is; 1213 ilink->next = NULL; 1214 ierr = KSPCreate(((PetscObject)pc)->comm,&ilink->ksp);CHKERRQ(ierr); 1215 ierr = PetscObjectIncrementTabLevel((PetscObject)ilink->ksp,(PetscObject)pc,1);CHKERRQ(ierr); 1216 ierr = KSPSetType(ilink->ksp,KSPPREONLY);CHKERRQ(ierr); 1217 ierr = PetscLogObjectParent((PetscObject)pc,(PetscObject)ilink->ksp);CHKERRQ(ierr); 1218 1219 ierr = PetscSNPrintf(prefix,sizeof(prefix),"%sfieldsplit_%s_",((PetscObject)pc)->prefix ? ((PetscObject)pc)->prefix : "",ilink->splitname);CHKERRQ(ierr); 1220 ierr = KSPSetOptionsPrefix(ilink->ksp,prefix);CHKERRQ(ierr); 1221 1222 if (!next) { 1223 jac->head = ilink; 1224 ilink->previous = NULL; 1225 } else { 1226 while (next->next) { 1227 next = next->next; 1228 } 1229 next->next = ilink; 1230 ilink->previous = next; 1231 } 1232 jac->nsplits++; 1233 PetscFunctionReturn(0); 1234 } 1235 EXTERN_C_END 1236 1237 #undef __FUNCT__ 1238 #define __FUNCT__ "PCFieldSplitSetFields" 1239 /*@ 1240 PCFieldSplitSetFields - Sets the fields for one particular split in the field split preconditioner 1241 1242 Logically Collective on PC 1243 1244 Input Parameters: 1245 + pc - the preconditioner context 1246 . splitname - name of this split, if NULL the number of the split is used 1247 . n - the number of fields in this split 1248 - fields - the fields in this split 1249 1250 Level: intermediate 1251 1252 Notes: Use PCFieldSplitSetIS() to set a completely general set of indices as a field. 1253 1254 The PCFieldSplitSetFields() is for defining fields as strided blocks. For example, if the block 1255 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 1256 0xx3xx6xx9xx12 ... x1xx4xx7xx ... xx2xx5xx8xx.. 01x34x67x... 0x1x3x5x7.. x12x45x78x.... 1257 where the numbered entries indicate what is in the field. 1258 1259 This function is called once per split (it creates a new split each time). Solve options 1260 for this split will be available under the prefix -fieldsplit_SPLITNAME_. 1261 1262 Developer Note: This routine does not actually create the IS representing the split, that is delayed 1263 until PCSetUp_FieldSplit(), because information about the vector/matrix layouts may not be 1264 available when this routine is called. 1265 1266 .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetBlockSize(), PCFieldSplitSetIS() 1267 1268 @*/ 1269 PetscErrorCode PCFieldSplitSetFields(PC pc,const char splitname[],PetscInt n,const PetscInt *fields,const PetscInt *fields_col) 1270 { 1271 PetscErrorCode ierr; 1272 1273 PetscFunctionBegin; 1274 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1275 PetscValidCharPointer(splitname,2); 1276 if (n < 1) SETERRQ2(((PetscObject)pc)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Provided number of fields %D in split \"%s\" not positive",n,splitname); 1277 PetscValidIntPointer(fields,3); 1278 ierr = PetscTryMethod(pc,"PCFieldSplitSetFields_C",(PC,const char[],PetscInt,const PetscInt*,const PetscInt*),(pc,splitname,n,fields,fields_col));CHKERRQ(ierr); 1279 PetscFunctionReturn(0); 1280 } 1281 1282 #undef __FUNCT__ 1283 #define __FUNCT__ "PCFieldSplitSetIS" 1284 /*@ 1285 PCFieldSplitSetIS - Sets the exact elements for field 1286 1287 Logically Collective on PC 1288 1289 Input Parameters: 1290 + pc - the preconditioner context 1291 . splitname - name of this split, if NULL the number of the split is used 1292 - is - the index set that defines the vector elements in this field 1293 1294 1295 Notes: 1296 Use PCFieldSplitSetFields(), for fields defined by strided types. 1297 1298 This function is called once per split (it creates a new split each time). Solve options 1299 for this split will be available under the prefix -fieldsplit_SPLITNAME_. 1300 1301 Level: intermediate 1302 1303 .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetBlockSize() 1304 1305 @*/ 1306 PetscErrorCode PCFieldSplitSetIS(PC pc,const char splitname[],IS is) 1307 { 1308 PetscErrorCode ierr; 1309 1310 PetscFunctionBegin; 1311 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1312 if (splitname) PetscValidCharPointer(splitname,2); 1313 PetscValidHeaderSpecific(is,IS_CLASSID,3); 1314 ierr = PetscTryMethod(pc,"PCFieldSplitSetIS_C",(PC,const char[],IS),(pc,splitname,is));CHKERRQ(ierr); 1315 PetscFunctionReturn(0); 1316 } 1317 1318 #undef __FUNCT__ 1319 #define __FUNCT__ "PCFieldSplitGetIS" 1320 /*@ 1321 PCFieldSplitGetIS - Retrieves the elements for a field as an IS 1322 1323 Logically Collective on PC 1324 1325 Input Parameters: 1326 + pc - the preconditioner context 1327 - splitname - name of this split 1328 1329 Output Parameter: 1330 - is - the index set that defines the vector elements in this field, or NULL if the field is not found 1331 1332 Level: intermediate 1333 1334 .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetIS() 1335 1336 @*/ 1337 PetscErrorCode PCFieldSplitGetIS(PC pc,const char splitname[],IS *is) 1338 { 1339 PetscErrorCode ierr; 1340 1341 PetscFunctionBegin; 1342 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1343 PetscValidCharPointer(splitname,2); 1344 PetscValidPointer(is,3); 1345 { 1346 PC_FieldSplit *jac = (PC_FieldSplit*) pc->data; 1347 PC_FieldSplitLink ilink = jac->head; 1348 PetscBool found; 1349 1350 *is = NULL; 1351 while (ilink) { 1352 ierr = PetscStrcmp(ilink->splitname, splitname, &found);CHKERRQ(ierr); 1353 if (found) { 1354 *is = ilink->is; 1355 break; 1356 } 1357 ilink = ilink->next; 1358 } 1359 } 1360 PetscFunctionReturn(0); 1361 } 1362 1363 #undef __FUNCT__ 1364 #define __FUNCT__ "PCFieldSplitSetBlockSize" 1365 /*@ 1366 PCFieldSplitSetBlockSize - Sets the block size for defining where fields start in the 1367 fieldsplit preconditioner. If not set the matrix block size is used. 1368 1369 Logically Collective on PC 1370 1371 Input Parameters: 1372 + pc - the preconditioner context 1373 - bs - the block size 1374 1375 Level: intermediate 1376 1377 .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetFields() 1378 1379 @*/ 1380 PetscErrorCode PCFieldSplitSetBlockSize(PC pc,PetscInt bs) 1381 { 1382 PetscErrorCode ierr; 1383 1384 PetscFunctionBegin; 1385 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1386 PetscValidLogicalCollectiveInt(pc,bs,2); 1387 ierr = PetscTryMethod(pc,"PCFieldSplitSetBlockSize_C",(PC,PetscInt),(pc,bs));CHKERRQ(ierr); 1388 PetscFunctionReturn(0); 1389 } 1390 1391 #undef __FUNCT__ 1392 #define __FUNCT__ "PCFieldSplitGetSubKSP" 1393 /*@C 1394 PCFieldSplitGetSubKSP - Gets the KSP contexts for all splits 1395 1396 Collective on KSP 1397 1398 Input Parameter: 1399 . pc - the preconditioner context 1400 1401 Output Parameters: 1402 + n - the number of splits 1403 - pc - the array of KSP contexts 1404 1405 Note: 1406 After PCFieldSplitGetSubKSP() the array of KSPs IS to be freed by the user 1407 (not the KSP just the array that contains them). 1408 1409 You must call KSPSetUp() before calling PCFieldSplitGetSubKSP(). 1410 1411 Fortran Usage: You must pass in a KSP array that is large enough to contain all the local KSPs. 1412 You can call PCFieldSplitGetSubKSP(pc,n,NULL_OBJECT,ierr) to determine how large the 1413 KSP array must be. 1414 1415 1416 Level: advanced 1417 1418 .seealso: PCFIELDSPLIT 1419 @*/ 1420 PetscErrorCode PCFieldSplitGetSubKSP(PC pc,PetscInt *n,KSP *subksp[]) 1421 { 1422 PetscErrorCode ierr; 1423 1424 PetscFunctionBegin; 1425 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1426 if (n) PetscValidIntPointer(n,2); 1427 ierr = PetscUseMethod(pc,"PCFieldSplitGetSubKSP_C",(PC,PetscInt*,KSP **),(pc,n,subksp));CHKERRQ(ierr); 1428 PetscFunctionReturn(0); 1429 } 1430 1431 #undef __FUNCT__ 1432 #define __FUNCT__ "PCFieldSplitSchurPrecondition" 1433 /*@ 1434 PCFieldSplitSchurPrecondition - Indicates if the Schur complement is preconditioned by a preconditioner constructed by the 1435 A11 matrix. Otherwise no preconditioner is used. 1436 1437 Collective on PC 1438 1439 Input Parameters: 1440 + pc - the preconditioner context 1441 . ptype - which matrix to use for preconditioning the Schur complement, PC_FIELDSPLIT_SCHUR_PRE_A11 (diag) is default 1442 - userpre - matrix to use for preconditioning, or NULL 1443 1444 Options Database: 1445 . -pc_fieldsplit_schur_precondition <self,user,a11> default is a11 1446 1447 Notes: 1448 $ If ptype is 1449 $ user then the preconditioner for the Schur complement is generated by the provided matrix (pre argument 1450 $ to this function). 1451 $ a11 then the preconditioner for the Schur complement is generated by the block diagonal part of the original 1452 $ matrix associated with the Schur complement (i.e. A11) 1453 $ self the preconditioner for the Schur complement is generated from the Schur complement matrix itself: 1454 $ The only preconditioner that currently works directly with the Schur complement matrix object is the PCLSC 1455 $ preconditioner 1456 1457 When solving a saddle point problem, where the A11 block is identically zero, using a11 as the ptype only makes sense 1458 with the additional option -fieldsplit_1_pc_type none. Usually for saddle point problems one would use a ptype of self and 1459 -fieldsplit_1_pc_type lsc which uses the least squares commutator compute a preconditioner for the Schur complement. 1460 1461 Developer Notes: This is a terrible name, gives no good indication of what the function does and should also have Set in 1462 the name since it sets a proceedure to use. 1463 1464 Level: intermediate 1465 1466 .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetFields(), PCFieldSplitSchurPreType, PCLSC 1467 1468 @*/ 1469 PetscErrorCode PCFieldSplitSchurPrecondition(PC pc,PCFieldSplitSchurPreType ptype,Mat pre) 1470 { 1471 PetscErrorCode ierr; 1472 1473 PetscFunctionBegin; 1474 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1475 ierr = PetscTryMethod(pc,"PCFieldSplitSchurPrecondition_C",(PC,PCFieldSplitSchurPreType,Mat),(pc,ptype,pre));CHKERRQ(ierr); 1476 PetscFunctionReturn(0); 1477 } 1478 1479 EXTERN_C_BEGIN 1480 #undef __FUNCT__ 1481 #define __FUNCT__ "PCFieldSplitSchurPrecondition_FieldSplit" 1482 PetscErrorCode PCFieldSplitSchurPrecondition_FieldSplit(PC pc,PCFieldSplitSchurPreType ptype,Mat pre) 1483 { 1484 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 1485 PetscErrorCode ierr; 1486 1487 PetscFunctionBegin; 1488 jac->schurpre = ptype; 1489 if (pre) { 1490 ierr = MatDestroy(&jac->schur_user);CHKERRQ(ierr); 1491 jac->schur_user = pre; 1492 ierr = PetscObjectReference((PetscObject)jac->schur_user);CHKERRQ(ierr); 1493 } 1494 PetscFunctionReturn(0); 1495 } 1496 EXTERN_C_END 1497 1498 #undef __FUNCT__ 1499 #define __FUNCT__ "PCFieldSplitSetSchurFactType" 1500 /*@ 1501 PCFieldSplitSetSchurFactType - sets which blocks of the approximate block factorization to retain 1502 1503 Collective on PC 1504 1505 Input Parameters: 1506 + pc - the preconditioner context 1507 - ftype - which blocks of factorization to retain, PC_FIELDSPLIT_SCHUR_FACT_FULL is default 1508 1509 Options Database: 1510 . -pc_fieldsplit_schur_fact_type <diag,lower,upper,full> default is full 1511 1512 1513 Level: intermediate 1514 1515 Notes: 1516 The FULL factorization is 1517 1518 $ (A B) = (1 0) (A 0) (1 Ainv*B) 1519 $ (C D) (C*Ainv 1) (0 S) (0 1 ) 1520 1521 where S = D - C*Ainv*B. In practice, the full factorization is applied via block triangular solves with the grouping L*(D*U). UPPER uses D*U, LOWER uses L*D, 1522 and DIAG is the diagonal part with the sign of S flipped (because this makes the preconditioner positive definite for many formulations, thus allowing the use of KSPMINRES). 1523 1524 If applied exactly, FULL factorization is a direct solver. The preconditioned operator with LOWER or UPPER has all eigenvalues equal to 1 and minimal polynomial 1525 of degree 2, so KSPGMRES converges in 2 iterations. If the iteration count is very low, consider using KSPFGMRES or KSPGCR which can use one less preconditioner 1526 application in this case. Note that the preconditioned operator may be highly non-normal, so such fast convergence may not be observed in practice. With DIAG, 1527 the preconditioned operator has three distinct nonzero eigenvalues and minimal polynomial of degree at most 4, so KSPGMRES converges in at most 4 iterations. 1528 1529 For symmetric problems in which A is positive definite and S is negative definite, DIAG can be used with KSPMINRES. Note that a flexible method like KSPFGMRES 1530 or KSPGCR must be used if the fieldsplit preconditioner is nonlinear (e.g. a few iterations of a Krylov method is used inside a split). 1531 1532 References: 1533 Murphy, Golub, and Wathen, A note on preconditioning indefinite linear systems, SIAM J. Sci. Comput., 21 (2000) pp. 1969-1972. 1534 1535 Ipsen, A note on preconditioning nonsymmetric matrices, SIAM J. Sci. Comput., 23 (2001), pp. 1050-1051. 1536 1537 .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetFields(), PCFieldSplitSchurPreType 1538 @*/ 1539 PetscErrorCode PCFieldSplitSetSchurFactType(PC pc,PCFieldSplitSchurFactType ftype) 1540 { 1541 PetscErrorCode ierr; 1542 1543 PetscFunctionBegin; 1544 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1545 ierr = PetscTryMethod(pc,"PCFieldSplitSetSchurFactType_C",(PC,PCFieldSplitSchurFactType),(pc,ftype));CHKERRQ(ierr); 1546 PetscFunctionReturn(0); 1547 } 1548 1549 #undef __FUNCT__ 1550 #define __FUNCT__ "PCFieldSplitSetSchurFactType_FieldSplit" 1551 PETSC_EXTERN_C PetscErrorCode PCFieldSplitSetSchurFactType_FieldSplit(PC pc,PCFieldSplitSchurFactType ftype) 1552 { 1553 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 1554 1555 PetscFunctionBegin; 1556 jac->schurfactorization = ftype; 1557 PetscFunctionReturn(0); 1558 } 1559 1560 #undef __FUNCT__ 1561 #define __FUNCT__ "PCFieldSplitGetSchurBlocks" 1562 /*@C 1563 PCFieldSplitGetSchurBlocks - Gets all matrix blocks for the Schur complement 1564 1565 Collective on KSP 1566 1567 Input Parameter: 1568 . pc - the preconditioner context 1569 1570 Output Parameters: 1571 + A00 - the (0,0) block 1572 . A01 - the (0,1) block 1573 . A10 - the (1,0) block 1574 - A11 - the (1,1) block 1575 1576 Level: advanced 1577 1578 .seealso: PCFIELDSPLIT 1579 @*/ 1580 PetscErrorCode PCFieldSplitGetSchurBlocks(PC pc,Mat *A00,Mat *A01,Mat *A10, Mat *A11) 1581 { 1582 PC_FieldSplit *jac = (PC_FieldSplit*) pc->data; 1583 1584 PetscFunctionBegin; 1585 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1586 if (jac->type != PC_COMPOSITE_SCHUR) SETERRQ(((PetscObject)pc)->comm,PETSC_ERR_ARG_WRONG, "FieldSplit is not using a Schur complement approach."); 1587 if (A00) *A00 = jac->pmat[0]; 1588 if (A01) *A01 = jac->B; 1589 if (A10) *A10 = jac->C; 1590 if (A11) *A11 = jac->pmat[1]; 1591 PetscFunctionReturn(0); 1592 } 1593 1594 EXTERN_C_BEGIN 1595 #undef __FUNCT__ 1596 #define __FUNCT__ "PCFieldSplitSetType_FieldSplit" 1597 PetscErrorCode PCFieldSplitSetType_FieldSplit(PC pc,PCCompositeType type) 1598 { 1599 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 1600 PetscErrorCode ierr; 1601 1602 PetscFunctionBegin; 1603 jac->type = type; 1604 if (type == PC_COMPOSITE_SCHUR) { 1605 pc->ops->apply = PCApply_FieldSplit_Schur; 1606 pc->ops->view = PCView_FieldSplit_Schur; 1607 1608 ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitGetSubKSP_C","PCFieldSplitGetSubKSP_FieldSplit_Schur",PCFieldSplitGetSubKSP_FieldSplit_Schur);CHKERRQ(ierr); 1609 ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSchurPrecondition_C","PCFieldSplitSchurPrecondition_FieldSplit",PCFieldSplitSchurPrecondition_FieldSplit);CHKERRQ(ierr); 1610 ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetSchurFactType_C","PCFieldSplitSetSchurFactType_FieldSplit",PCFieldSplitSetSchurFactType_FieldSplit);CHKERRQ(ierr); 1611 1612 } else { 1613 pc->ops->apply = PCApply_FieldSplit; 1614 pc->ops->view = PCView_FieldSplit; 1615 1616 ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitGetSubKSP_C","PCFieldSplitGetSubKSP_FieldSplit",PCFieldSplitGetSubKSP_FieldSplit);CHKERRQ(ierr); 1617 ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSchurPrecondition_C","",0);CHKERRQ(ierr); 1618 ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetSchurFactType_C","",0);CHKERRQ(ierr); 1619 } 1620 PetscFunctionReturn(0); 1621 } 1622 EXTERN_C_END 1623 1624 EXTERN_C_BEGIN 1625 #undef __FUNCT__ 1626 #define __FUNCT__ "PCFieldSplitSetBlockSize_FieldSplit" 1627 PetscErrorCode PCFieldSplitSetBlockSize_FieldSplit(PC pc,PetscInt bs) 1628 { 1629 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 1630 1631 PetscFunctionBegin; 1632 if (bs < 1) SETERRQ1(((PetscObject)pc)->comm,PETSC_ERR_ARG_OUTOFRANGE,"Blocksize must be positive, you gave %D",bs); 1633 if (jac->bs > 0 && jac->bs != bs) SETERRQ2(((PetscObject)pc)->comm,PETSC_ERR_ARG_WRONGSTATE,"Cannot change fieldsplit blocksize from %D to %D after it has been set",jac->bs,bs); 1634 jac->bs = bs; 1635 PetscFunctionReturn(0); 1636 } 1637 EXTERN_C_END 1638 1639 #undef __FUNCT__ 1640 #define __FUNCT__ "PCFieldSplitSetType" 1641 /*@ 1642 PCFieldSplitSetType - Sets the type of fieldsplit preconditioner. 1643 1644 Collective on PC 1645 1646 Input Parameter: 1647 . pc - the preconditioner context 1648 . type - PC_COMPOSITE_ADDITIVE, PC_COMPOSITE_MULTIPLICATIVE (default), PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE, PC_COMPOSITE_SPECIAL, PC_COMPOSITE_SCHUR 1649 1650 Options Database Key: 1651 . -pc_fieldsplit_type <type: one of multiplicative, additive, symmetric_multiplicative, special, schur> - Sets fieldsplit preconditioner type 1652 1653 Level: Intermediate 1654 1655 .keywords: PC, set, type, composite preconditioner, additive, multiplicative 1656 1657 .seealso: PCCompositeSetType() 1658 1659 @*/ 1660 PetscErrorCode PCFieldSplitSetType(PC pc,PCCompositeType type) 1661 { 1662 PetscErrorCode ierr; 1663 1664 PetscFunctionBegin; 1665 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1666 ierr = PetscTryMethod(pc,"PCFieldSplitSetType_C",(PC,PCCompositeType),(pc,type));CHKERRQ(ierr); 1667 PetscFunctionReturn(0); 1668 } 1669 1670 #undef __FUNCT__ 1671 #define __FUNCT__ "PCFieldSplitGetType" 1672 /*@ 1673 PCFieldSplitGetType - Gets the type of fieldsplit preconditioner. 1674 1675 Not collective 1676 1677 Input Parameter: 1678 . pc - the preconditioner context 1679 1680 Output Parameter: 1681 . type - PC_COMPOSITE_ADDITIVE, PC_COMPOSITE_MULTIPLICATIVE (default), PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE, PC_COMPOSITE_SPECIAL, PC_COMPOSITE_SCHUR 1682 1683 Level: Intermediate 1684 1685 .keywords: PC, set, type, composite preconditioner, additive, multiplicative 1686 .seealso: PCCompositeSetType() 1687 @*/ 1688 PetscErrorCode PCFieldSplitGetType(PC pc, PCCompositeType *type) 1689 { 1690 PC_FieldSplit *jac = (PC_FieldSplit*) pc->data; 1691 1692 PetscFunctionBegin; 1693 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1694 PetscValidIntPointer(type,2); 1695 *type = jac->type; 1696 PetscFunctionReturn(0); 1697 } 1698 1699 /* -------------------------------------------------------------------------------------*/ 1700 /*MC 1701 PCFIELDSPLIT - Preconditioner created by combining separate preconditioners for individual 1702 fields or groups of fields. See the users manual section "Solving Block Matrices" for more details. 1703 1704 To set options on the solvers for each block append -fieldsplit_ to all the PC 1705 options database keys. For example, -fieldsplit_pc_type ilu -fieldsplit_pc_factor_levels 1 1706 1707 To set the options on the solvers separate for each block call PCFieldSplitGetSubKSP() 1708 and set the options directly on the resulting KSP object 1709 1710 Level: intermediate 1711 1712 Options Database Keys: 1713 + -pc_fieldsplit_%d_fields <a,b,..> - indicates the fields to be used in the %d'th split 1714 . -pc_fieldsplit_default - automatically add any fields to additional splits that have not 1715 been supplied explicitly by -pc_fieldsplit_%d_fields 1716 . -pc_fieldsplit_block_size <bs> - size of block that defines fields (i.e. there are bs fields) 1717 . -pc_fieldsplit_type <additive,multiplicative,symmetric_multiplicative,schur> - type of relaxation or factorization splitting 1718 . -pc_fieldsplit_schur_precondition <self,user,a11> - default is a11 1719 . -pc_fieldsplit_detect_saddle_point - automatically finds rows with zero or negative diagonal and uses Schur complement with no preconditioner as the solver 1720 1721 - Options prefix for inner solvers when using Schur complement preconditioner are -fieldsplit_0_ and -fieldsplit_1_ 1722 for all other solvers they are -fieldsplit_%d_ for the dth field, use -fieldsplit_ for all fields 1723 1724 Notes: 1725 Use PCFieldSplitSetFields() to set fields defined by "strided" entries and PCFieldSplitSetIS() 1726 to define a field by an arbitrary collection of entries. 1727 1728 If no fields are set the default is used. The fields are defined by entries strided by bs, 1729 beginning at 0 then 1, etc to bs-1. The block size can be set with PCFieldSplitSetBlockSize(), 1730 if this is not called the block size defaults to the blocksize of the second matrix passed 1731 to KSPSetOperators()/PCSetOperators(). 1732 1733 $ For the Schur complement preconditioner if J = ( A00 A01 ) 1734 $ ( A10 A11 ) 1735 $ the preconditioner using full factorization is 1736 $ ( I -A10 ksp(A00) ) ( inv(A00) 0 ) ( I 0 ) 1737 $ ( 0 I ) ( 0 ksp(S) ) ( -A10 ksp(A00) I ) 1738 where the action of inv(A00) is applied using the KSP solver with prefix -fieldsplit_0_. The action of 1739 ksp(S) is computed using the KSP solver with prefix -fieldsplit_splitname_ (where splitname was given 1740 in providing the SECOND split or 1 if not give). For PCFieldSplitGetKSP() when field number is 0, 1741 it returns the KSP associated with -fieldsplit_0_ while field number 1 gives -fieldsplit_1_ KSP. By default 1742 A11 is used to construct a preconditioner for S, use PCFieldSplitSchurPrecondition() to turn on or off this 1743 option. You can use the preconditioner PCLSC to precondition the Schur complement with -fieldsplit_1_pc_type lsc. The 1744 factorization type is set using -pc_fieldsplit_schur_fact_type <diag, lower, upper, full>. The full is shown above, 1745 diag gives 1746 $ ( inv(A00) 0 ) 1747 $ ( 0 -ksp(S) ) 1748 note that slightly counter intuitively there is a negative in front of the ksp(S) so that the preconditioner is positive definite. The lower factorization is the inverse of 1749 $ ( A00 0 ) 1750 $ ( A10 S ) 1751 where the inverses of A00 and S are applied using KSPs. The upper factorization is the inverse of 1752 $ ( A00 A01 ) 1753 $ ( 0 S ) 1754 where again the inverses of A00 and S are applied using KSPs. 1755 1756 If only one set of indices (one IS) is provided with PCFieldSplitSetIS() then the complement of that IS 1757 is used automatically for a second block. 1758 1759 The fieldsplit preconditioner cannot currently be used with the BAIJ or SBAIJ data formats if the blocksize is larger than 1. 1760 Generally it should be used with the AIJ format. 1761 1762 The forms of these preconditioners are closely related if not identical to forms derived as "Distributive Iterations", see, 1763 for example, page 294 in "Principles of Computational Fluid Dynamics" by Pieter Wesseling. Note that one can also use PCFIELDSPLIT 1764 inside a smoother resulting in "Distributive Smoothers". 1765 1766 Concepts: physics based preconditioners, block preconditioners 1767 1768 .seealso: PCCreate(), PCSetType(), PCType (for list of available types), PC, Block_Preconditioners, PCLSC, 1769 PCFieldSplitGetSubKSP(), PCFieldSplitSetFields(), PCFieldSplitSetType(), PCFieldSplitSetIS(), PCFieldSplitSchurPrecondition() 1770 M*/ 1771 1772 EXTERN_C_BEGIN 1773 #undef __FUNCT__ 1774 #define __FUNCT__ "PCCreate_FieldSplit" 1775 PetscErrorCode PCCreate_FieldSplit(PC pc) 1776 { 1777 PetscErrorCode ierr; 1778 PC_FieldSplit *jac; 1779 1780 PetscFunctionBegin; 1781 ierr = PetscNewLog(pc,PC_FieldSplit,&jac);CHKERRQ(ierr); 1782 1783 jac->bs = -1; 1784 jac->nsplits = 0; 1785 jac->type = PC_COMPOSITE_MULTIPLICATIVE; 1786 jac->schurpre = PC_FIELDSPLIT_SCHUR_PRE_USER; /* Try user preconditioner first, fall back on diagonal */ 1787 jac->schurfactorization = PC_FIELDSPLIT_SCHUR_FACT_FULL; 1788 1789 pc->data = (void*)jac; 1790 1791 pc->ops->apply = PCApply_FieldSplit; 1792 pc->ops->applytranspose = PCApplyTranspose_FieldSplit; 1793 pc->ops->setup = PCSetUp_FieldSplit; 1794 pc->ops->reset = PCReset_FieldSplit; 1795 pc->ops->destroy = PCDestroy_FieldSplit; 1796 pc->ops->setfromoptions = PCSetFromOptions_FieldSplit; 1797 pc->ops->view = PCView_FieldSplit; 1798 pc->ops->applyrichardson = 0; 1799 1800 ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitGetSubKSP_C","PCFieldSplitGetSubKSP_FieldSplit", 1801 PCFieldSplitGetSubKSP_FieldSplit);CHKERRQ(ierr); 1802 ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetFields_C","PCFieldSplitSetFields_FieldSplit", 1803 PCFieldSplitSetFields_FieldSplit);CHKERRQ(ierr); 1804 ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetIS_C","PCFieldSplitSetIS_FieldSplit", 1805 PCFieldSplitSetIS_FieldSplit);CHKERRQ(ierr); 1806 ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetType_C","PCFieldSplitSetType_FieldSplit", 1807 PCFieldSplitSetType_FieldSplit);CHKERRQ(ierr); 1808 ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetBlockSize_C","PCFieldSplitSetBlockSize_FieldSplit", 1809 PCFieldSplitSetBlockSize_FieldSplit);CHKERRQ(ierr); 1810 PetscFunctionReturn(0); 1811 } 1812 EXTERN_C_END 1813 1814 1815 1816