1 2 #include <petsc-private/pcimpl.h> /*I "petscpc.h" I*/ 3 #include <petscdm.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 PetscBool dm_splits; /* Whether to use DMCreateFieldDecomposition() whenever possible */ 54 } PC_FieldSplit; 55 56 /* 57 Notes: there is no particular reason that pmat, x, and y are stored as arrays in PC_FieldSplit instead of 58 inside PC_FieldSplitLink, just historical. If you want to be able to add new fields after already using the 59 PC you could change this. 60 */ 61 62 /* This helper is so that setting a user-provided preconditioning matrix is orthogonal to choosing to use it. This way the 63 * application-provided FormJacobian can provide this matrix without interfering with the user's (command-line) choices. */ 64 static Mat FieldSplitSchurPre(PC_FieldSplit *jac) 65 { 66 switch (jac->schurpre) { 67 case PC_FIELDSPLIT_SCHUR_PRE_SELF: return jac->schur; 68 case PC_FIELDSPLIT_SCHUR_PRE_A11: return jac->pmat[1]; 69 case PC_FIELDSPLIT_SCHUR_PRE_USER: /* Use a user-provided matrix if it is given, otherwise diagonal block */ 70 default: 71 return jac->schur_user ? jac->schur_user : jac->pmat[1]; 72 } 73 } 74 75 76 #include <petscdraw.h> 77 #undef __FUNCT__ 78 #define __FUNCT__ "PCView_FieldSplit" 79 static PetscErrorCode PCView_FieldSplit(PC pc,PetscViewer viewer) 80 { 81 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 82 PetscErrorCode ierr; 83 PetscBool iascii,isdraw; 84 PetscInt i,j; 85 PC_FieldSplitLink ilink = jac->head; 86 87 PetscFunctionBegin; 88 ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr); 89 ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERDRAW,&isdraw);CHKERRQ(ierr); 90 if (iascii) { 91 if (jac->bs > 0) { 92 ierr = PetscViewerASCIIPrintf(viewer," FieldSplit with %s composition: total splits = %D, blocksize = %D\n",PCCompositeTypes[jac->type],jac->nsplits,jac->bs);CHKERRQ(ierr); 93 } else { 94 ierr = PetscViewerASCIIPrintf(viewer," FieldSplit with %s composition: total splits = %D\n",PCCompositeTypes[jac->type],jac->nsplits);CHKERRQ(ierr); 95 } 96 if (jac->realdiagonal) { 97 ierr = PetscViewerASCIIPrintf(viewer," using actual matrix for blocks rather than preconditioner matrix\n");CHKERRQ(ierr); 98 } 99 ierr = PetscViewerASCIIPrintf(viewer," Solver info for each split is in the following KSP objects:\n");CHKERRQ(ierr); 100 ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 101 for (i=0; i<jac->nsplits; i++) { 102 if (ilink->fields) { 103 ierr = PetscViewerASCIIPrintf(viewer,"Split number %D Fields ",i);CHKERRQ(ierr); 104 ierr = PetscViewerASCIIUseTabs(viewer,PETSC_FALSE);CHKERRQ(ierr); 105 for (j=0; j<ilink->nfields; j++) { 106 if (j > 0) { 107 ierr = PetscViewerASCIIPrintf(viewer,",");CHKERRQ(ierr); 108 } 109 ierr = PetscViewerASCIIPrintf(viewer," %D",ilink->fields[j]);CHKERRQ(ierr); 110 } 111 ierr = PetscViewerASCIIPrintf(viewer,"\n");CHKERRQ(ierr); 112 ierr = PetscViewerASCIIUseTabs(viewer,PETSC_TRUE);CHKERRQ(ierr); 113 } else { 114 ierr = PetscViewerASCIIPrintf(viewer,"Split number %D Defined by IS\n",i);CHKERRQ(ierr); 115 } 116 ierr = KSPView(ilink->ksp,viewer);CHKERRQ(ierr); 117 ilink = ilink->next; 118 } 119 ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 120 } 121 122 if (isdraw) { 123 PetscDraw draw; 124 PetscReal x,y,w,wd; 125 126 ierr = PetscViewerDrawGetDraw(viewer,0,&draw);CHKERRQ(ierr); 127 ierr = PetscDrawGetCurrentPoint(draw,&x,&y);CHKERRQ(ierr); 128 w = 2*PetscMin(1.0 - x,x); 129 wd = w/(jac->nsplits + 1); 130 x = x - wd*(jac->nsplits-1)/2.0; 131 for (i=0; i<jac->nsplits; i++) { 132 ierr = PetscDrawPushCurrentPoint(draw,x,y);CHKERRQ(ierr); 133 ierr = KSPView(ilink->ksp,viewer);CHKERRQ(ierr); 134 ierr = PetscDrawPopCurrentPoint(draw);CHKERRQ(ierr); 135 x += wd; 136 ilink = ilink->next; 137 } 138 } 139 PetscFunctionReturn(0); 140 } 141 142 #undef __FUNCT__ 143 #define __FUNCT__ "PCView_FieldSplit_Schur" 144 static PetscErrorCode PCView_FieldSplit_Schur(PC pc,PetscViewer viewer) 145 { 146 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 147 PetscErrorCode ierr; 148 PetscBool iascii,isdraw; 149 PetscInt i,j; 150 PC_FieldSplitLink ilink = jac->head; 151 152 PetscFunctionBegin; 153 ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr); 154 ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERDRAW,&isdraw);CHKERRQ(ierr); 155 if (iascii) { 156 if (jac->bs > 0) { 157 ierr = PetscViewerASCIIPrintf(viewer," FieldSplit with Schur preconditioner, blocksize = %D, factorization %s\n",jac->bs,PCFieldSplitSchurFactTypes[jac->schurfactorization]);CHKERRQ(ierr); 158 } else { 159 ierr = PetscViewerASCIIPrintf(viewer," FieldSplit with Schur preconditioner, factorization %s\n",PCFieldSplitSchurFactTypes[jac->schurfactorization]);CHKERRQ(ierr); 160 } 161 if (jac->realdiagonal) { 162 ierr = PetscViewerASCIIPrintf(viewer," using actual matrix for blocks rather than preconditioner matrix\n");CHKERRQ(ierr); 163 } 164 switch (jac->schurpre) { 165 case PC_FIELDSPLIT_SCHUR_PRE_SELF: 166 ierr = PetscViewerASCIIPrintf(viewer," Preconditioner for the Schur complement formed from S itself\n");CHKERRQ(ierr);break; 167 case PC_FIELDSPLIT_SCHUR_PRE_A11: 168 ierr = PetscViewerASCIIPrintf(viewer," Preconditioner for the Schur complement formed from A11\n");CHKERRQ(ierr);break; 169 case PC_FIELDSPLIT_SCHUR_PRE_USER: 170 if (jac->schur_user) { 171 ierr = PetscViewerASCIIPrintf(viewer," Preconditioner for the Schur complement formed from user provided matrix\n");CHKERRQ(ierr); 172 } else { 173 ierr = PetscViewerASCIIPrintf(viewer," Preconditioner for the Schur complement formed from A11\n");CHKERRQ(ierr); 174 } 175 break; 176 default: 177 SETERRQ1(PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Invalid Schur preconditioning type: %d", jac->schurpre); 178 } 179 ierr = PetscViewerASCIIPrintf(viewer," Split info:\n");CHKERRQ(ierr); 180 ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 181 for (i=0; i<jac->nsplits; i++) { 182 if (ilink->fields) { 183 ierr = PetscViewerASCIIPrintf(viewer,"Split number %D Fields ",i);CHKERRQ(ierr); 184 ierr = PetscViewerASCIIUseTabs(viewer,PETSC_FALSE);CHKERRQ(ierr); 185 for (j=0; j<ilink->nfields; j++) { 186 if (j > 0) { 187 ierr = PetscViewerASCIIPrintf(viewer,",");CHKERRQ(ierr); 188 } 189 ierr = PetscViewerASCIIPrintf(viewer," %D",ilink->fields[j]);CHKERRQ(ierr); 190 } 191 ierr = PetscViewerASCIIPrintf(viewer,"\n");CHKERRQ(ierr); 192 ierr = PetscViewerASCIIUseTabs(viewer,PETSC_TRUE);CHKERRQ(ierr); 193 } else { 194 ierr = PetscViewerASCIIPrintf(viewer,"Split number %D Defined by IS\n",i);CHKERRQ(ierr); 195 } 196 ilink = ilink->next; 197 } 198 ierr = PetscViewerASCIIPrintf(viewer,"KSP solver for A00 block \n");CHKERRQ(ierr); 199 ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 200 ierr = KSPView(jac->head->ksp,viewer);CHKERRQ(ierr); 201 ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 202 if (jac->kspupper != jac->head->ksp) { 203 ierr = PetscViewerASCIIPrintf(viewer,"KSP solver for upper A00 in upper triangular factor \n");CHKERRQ(ierr); 204 ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 205 ierr = KSPView(jac->kspupper,viewer);CHKERRQ(ierr); 206 ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 207 } 208 ierr = PetscViewerASCIIPrintf(viewer,"KSP solver for S = A11 - A10 inv(A00) A01 \n");CHKERRQ(ierr); 209 ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 210 if (jac->kspschur) { 211 ierr = KSPView(jac->kspschur,viewer);CHKERRQ(ierr); 212 } else { 213 ierr = PetscViewerASCIIPrintf(viewer," not yet available\n");CHKERRQ(ierr); 214 } 215 ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 216 ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 217 } else if (isdraw) { 218 PetscDraw draw; 219 PetscReal x,y,w,wd,h; 220 PetscInt cnt = 2; 221 char str[32]; 222 223 ierr = PetscViewerDrawGetDraw(viewer,0,&draw);CHKERRQ(ierr); 224 ierr = PetscDrawGetCurrentPoint(draw,&x,&y);CHKERRQ(ierr); 225 if (jac->kspupper != jac->head->ksp) cnt++; 226 w = 2*PetscMin(1.0 - x,x); 227 wd = w/(cnt + 1); 228 229 ierr = PetscSNPrintf(str,32,"Schur fact. %s",PCFieldSplitSchurFactTypes[jac->schurfactorization]);CHKERRQ(ierr); 230 ierr = PetscDrawBoxedString(draw,x,y,PETSC_DRAW_RED,PETSC_DRAW_BLACK,str,NULL,&h);CHKERRQ(ierr); 231 y -= h; 232 if (jac->schurpre == PC_FIELDSPLIT_SCHUR_PRE_USER && !jac->schur_user) { 233 ierr = PetscSNPrintf(str,32,"Prec. for Schur from %s",PCFieldSplitSchurPreTypes[PC_FIELDSPLIT_SCHUR_PRE_A11]);CHKERRQ(ierr); 234 } else { 235 ierr = PetscSNPrintf(str,32,"Prec. for Schur from %s",PCFieldSplitSchurPreTypes[jac->schurpre]);CHKERRQ(ierr); 236 } 237 ierr = PetscDrawBoxedString(draw,x+wd*(cnt-1)/2.0,y,PETSC_DRAW_RED,PETSC_DRAW_BLACK,str,NULL,&h);CHKERRQ(ierr); 238 y -= h; 239 x = x - wd*(cnt-1)/2.0; 240 241 ierr = PetscDrawPushCurrentPoint(draw,x,y);CHKERRQ(ierr); 242 ierr = KSPView(jac->head->ksp,viewer);CHKERRQ(ierr); 243 ierr = PetscDrawPopCurrentPoint(draw);CHKERRQ(ierr); 244 if (jac->kspupper != jac->head->ksp) { 245 x += wd; 246 ierr = PetscDrawPushCurrentPoint(draw,x,y);CHKERRQ(ierr); 247 ierr = KSPView(jac->kspupper,viewer);CHKERRQ(ierr); 248 ierr = PetscDrawPopCurrentPoint(draw);CHKERRQ(ierr); 249 } 250 x += wd; 251 ierr = PetscDrawPushCurrentPoint(draw,x,y);CHKERRQ(ierr); 252 ierr = KSPView(jac->kspschur,viewer);CHKERRQ(ierr); 253 ierr = PetscDrawPopCurrentPoint(draw);CHKERRQ(ierr); 254 } 255 PetscFunctionReturn(0); 256 } 257 258 #undef __FUNCT__ 259 #define __FUNCT__ "PCFieldSplitSetRuntimeSplits_Private" 260 /* Precondition: jac->bs is set to a meaningful value */ 261 static PetscErrorCode PCFieldSplitSetRuntimeSplits_Private(PC pc) 262 { 263 PetscErrorCode ierr; 264 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 265 PetscInt i,nfields,*ifields,nfields_col,*ifields_col; 266 PetscBool flg,flg_col; 267 char optionname[128],splitname[8],optionname_col[128]; 268 269 PetscFunctionBegin; 270 ierr = PetscMalloc(jac->bs*sizeof(PetscInt),&ifields);CHKERRQ(ierr); 271 ierr = PetscMalloc(jac->bs*sizeof(PetscInt),&ifields_col);CHKERRQ(ierr); 272 for (i=0,flg=PETSC_TRUE;; i++) { 273 ierr = PetscSNPrintf(splitname,sizeof(splitname),"%D",i);CHKERRQ(ierr); 274 ierr = PetscSNPrintf(optionname,sizeof(optionname),"-pc_fieldsplit_%D_fields",i);CHKERRQ(ierr); 275 ierr = PetscSNPrintf(optionname_col,sizeof(optionname_col),"-pc_fieldsplit_%D_fields_col",i);CHKERRQ(ierr); 276 nfields = jac->bs; 277 nfields_col = jac->bs; 278 ierr = PetscOptionsGetIntArray(((PetscObject)pc)->prefix,optionname,ifields,&nfields,&flg);CHKERRQ(ierr); 279 ierr = PetscOptionsGetIntArray(((PetscObject)pc)->prefix,optionname_col,ifields_col,&nfields_col,&flg_col);CHKERRQ(ierr); 280 if (!flg) break; 281 else if (flg && !flg_col) { 282 if (!nfields) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Cannot list zero fields"); 283 ierr = PCFieldSplitSetFields(pc,splitname,nfields,ifields,ifields);CHKERRQ(ierr); 284 } else { 285 if (!nfields || !nfields_col) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Cannot list zero fields"); 286 if (nfields != nfields_col) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Number of row and column fields must match"); 287 ierr = PCFieldSplitSetFields(pc,splitname,nfields,ifields,ifields_col);CHKERRQ(ierr); 288 } 289 } 290 if (i > 0) { 291 /* Makes command-line setting of splits take precedence over setting them in code. 292 Otherwise subsequent calls to PCFieldSplitSetIS() or PCFieldSplitSetFields() would 293 create new splits, which would probably not be what the user wanted. */ 294 jac->splitdefined = PETSC_TRUE; 295 } 296 ierr = PetscFree(ifields);CHKERRQ(ierr); 297 ierr = PetscFree(ifields_col);CHKERRQ(ierr); 298 PetscFunctionReturn(0); 299 } 300 301 #undef __FUNCT__ 302 #define __FUNCT__ "PCFieldSplitSetDefaults" 303 static PetscErrorCode PCFieldSplitSetDefaults(PC pc) 304 { 305 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 306 PetscErrorCode ierr; 307 PC_FieldSplitLink ilink = jac->head; 308 PetscBool fieldsplit_default = PETSC_FALSE,stokes = PETSC_FALSE; 309 PetscInt i; 310 311 PetscFunctionBegin; 312 /* 313 Kinda messy, but at least this now uses DMCreateFieldDecomposition() even with jac->reset. 314 Should probably be rewritten. 315 */ 316 if (!ilink || jac->reset) { 317 ierr = PetscOptionsGetBool(((PetscObject)pc)->prefix,"-pc_fieldsplit_detect_saddle_point",&stokes,NULL);CHKERRQ(ierr); 318 if (pc->dm && jac->dm_splits && !stokes) { 319 PetscInt numFields, f, i, j; 320 char **fieldNames; 321 IS *fields; 322 DM *dms; 323 DM subdm[128]; 324 PetscBool flg; 325 326 ierr = DMCreateFieldDecomposition(pc->dm, &numFields, &fieldNames, &fields, &dms);CHKERRQ(ierr); 327 /* Allow the user to prescribe the splits */ 328 for (i = 0, flg = PETSC_TRUE;; i++) { 329 PetscInt ifields[128]; 330 IS compField; 331 char optionname[128], splitname[8]; 332 PetscInt nfields = numFields; 333 334 ierr = PetscSNPrintf(optionname, sizeof(optionname), "-pc_fieldsplit_%D_fields", i);CHKERRQ(ierr); 335 ierr = PetscOptionsGetIntArray(((PetscObject) pc)->prefix, optionname, ifields, &nfields, &flg);CHKERRQ(ierr); 336 if (!flg) break; 337 if (numFields > 128) SETERRQ1(PetscObjectComm((PetscObject)pc),PETSC_ERR_SUP,"Cannot currently support %d > 128 fields", numFields); 338 ierr = DMCreateSubDM(pc->dm, nfields, ifields, &compField, &subdm[i]);CHKERRQ(ierr); 339 if (nfields == 1) { 340 ierr = PCFieldSplitSetIS(pc, fieldNames[ifields[0]], compField);CHKERRQ(ierr); 341 /* ierr = PetscPrintf(PetscObjectComm((PetscObject)pc), "%s Field Indices:", fieldNames[ifields[0]]);CHKERRQ(ierr); 342 ierr = ISView(compField, NULL);CHKERRQ(ierr); */ 343 } else { 344 ierr = PetscSNPrintf(splitname, sizeof(splitname), "%D", i);CHKERRQ(ierr); 345 ierr = PCFieldSplitSetIS(pc, splitname, compField);CHKERRQ(ierr); 346 /* ierr = PetscPrintf(PetscObjectComm((PetscObject)pc), "%s Field Indices:", splitname);CHKERRQ(ierr); 347 ierr = ISView(compField, NULL);CHKERRQ(ierr); */ 348 } 349 ierr = ISDestroy(&compField);CHKERRQ(ierr); 350 for (j = 0; j < nfields; ++j) { 351 f = ifields[j]; 352 ierr = PetscFree(fieldNames[f]);CHKERRQ(ierr); 353 ierr = ISDestroy(&fields[f]);CHKERRQ(ierr); 354 } 355 } 356 if (i == 0) { 357 for (f = 0; f < numFields; ++f) { 358 ierr = PCFieldSplitSetIS(pc, fieldNames[f], fields[f]);CHKERRQ(ierr); 359 ierr = PetscFree(fieldNames[f]);CHKERRQ(ierr); 360 ierr = ISDestroy(&fields[f]);CHKERRQ(ierr); 361 } 362 } else { 363 for (j=0; j<numFields; j++) { 364 ierr = DMDestroy(dms+j);CHKERRQ(ierr); 365 } 366 ierr = PetscFree(dms);CHKERRQ(ierr); 367 ierr = PetscMalloc(i * sizeof(DM), &dms);CHKERRQ(ierr); 368 for (j = 0; j < i; ++j) dms[j] = subdm[j]; 369 } 370 ierr = PetscFree(fieldNames);CHKERRQ(ierr); 371 ierr = PetscFree(fields);CHKERRQ(ierr); 372 if (dms) { 373 ierr = PetscInfo(pc, "Setting up physics based fieldsplit preconditioner using the embedded DM\n");CHKERRQ(ierr); 374 for (ilink = jac->head, i = 0; ilink; ilink = ilink->next, ++i) { 375 const char *prefix; 376 ierr = PetscObjectGetOptionsPrefix((PetscObject)(ilink->ksp),&prefix);CHKERRQ(ierr); 377 ierr = PetscObjectSetOptionsPrefix((PetscObject)(dms[i]), prefix);CHKERRQ(ierr); 378 ierr = KSPSetDM(ilink->ksp, dms[i]);CHKERRQ(ierr); 379 ierr = KSPSetDMActive(ilink->ksp, PETSC_FALSE);CHKERRQ(ierr); 380 ierr = PetscObjectIncrementTabLevel((PetscObject)dms[i],(PetscObject)ilink->ksp,0);CHKERRQ(ierr); 381 ierr = DMDestroy(&dms[i]);CHKERRQ(ierr); 382 } 383 ierr = PetscFree(dms);CHKERRQ(ierr); 384 } 385 } else { 386 if (jac->bs <= 0) { 387 if (pc->pmat) { 388 ierr = MatGetBlockSize(pc->pmat,&jac->bs);CHKERRQ(ierr); 389 } else jac->bs = 1; 390 } 391 392 if (stokes) { 393 IS zerodiags,rest; 394 PetscInt nmin,nmax; 395 396 ierr = MatGetOwnershipRange(pc->mat,&nmin,&nmax);CHKERRQ(ierr); 397 ierr = MatFindZeroDiagonals(pc->mat,&zerodiags);CHKERRQ(ierr); 398 ierr = ISComplement(zerodiags,nmin,nmax,&rest);CHKERRQ(ierr); 399 if (jac->reset) { 400 jac->head->is = rest; 401 jac->head->next->is = zerodiags; 402 } else { 403 ierr = PCFieldSplitSetIS(pc,"0",rest);CHKERRQ(ierr); 404 ierr = PCFieldSplitSetIS(pc,"1",zerodiags);CHKERRQ(ierr); 405 } 406 ierr = ISDestroy(&zerodiags);CHKERRQ(ierr); 407 ierr = ISDestroy(&rest);CHKERRQ(ierr); 408 } else { 409 if (jac->reset) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_SUP,"Cases not yet handled when PCReset() was used"); 410 ierr = PetscOptionsGetBool(((PetscObject)pc)->prefix,"-pc_fieldsplit_default",&fieldsplit_default,NULL);CHKERRQ(ierr); 411 if (!fieldsplit_default) { 412 /* Allow user to set fields from command line, if bs was known at the time of PCSetFromOptions_FieldSplit() 413 then it is set there. This is not ideal because we should only have options set in XXSetFromOptions(). */ 414 ierr = PCFieldSplitSetRuntimeSplits_Private(pc);CHKERRQ(ierr); 415 if (jac->splitdefined) {ierr = PetscInfo(pc,"Splits defined using the options database\n");CHKERRQ(ierr);} 416 } 417 if (fieldsplit_default || !jac->splitdefined) { 418 ierr = PetscInfo(pc,"Using default splitting of fields\n");CHKERRQ(ierr); 419 for (i=0; i<jac->bs; i++) { 420 char splitname[8]; 421 ierr = PetscSNPrintf(splitname,sizeof(splitname),"%D",i);CHKERRQ(ierr); 422 ierr = PCFieldSplitSetFields(pc,splitname,1,&i,&i);CHKERRQ(ierr); 423 } 424 jac->defaultsplit = PETSC_TRUE; 425 } 426 } 427 } 428 } else if (jac->nsplits == 1) { 429 if (ilink->is) { 430 IS is2; 431 PetscInt nmin,nmax; 432 433 ierr = MatGetOwnershipRange(pc->mat,&nmin,&nmax);CHKERRQ(ierr); 434 ierr = ISComplement(ilink->is,nmin,nmax,&is2);CHKERRQ(ierr); 435 ierr = PCFieldSplitSetIS(pc,"1",is2);CHKERRQ(ierr); 436 ierr = ISDestroy(&is2);CHKERRQ(ierr); 437 } else SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_SUP,"Must provide at least two sets of fields to PCFieldSplit()"); 438 } 439 440 441 if (jac->nsplits < 2) SETERRQ1(PetscObjectComm((PetscObject)pc),PETSC_ERR_PLIB,"Unhandled case, must have at least two fields, not %d", jac->nsplits); 442 PetscFunctionReturn(0); 443 } 444 445 PetscErrorCode PetscOptionsFindPairPrefix_Private(const char pre[], const char name[], char *value[], PetscBool *flg); 446 447 #undef __FUNCT__ 448 #define __FUNCT__ "PCSetUp_FieldSplit" 449 static PetscErrorCode PCSetUp_FieldSplit(PC pc) 450 { 451 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 452 PetscErrorCode ierr; 453 PC_FieldSplitLink ilink; 454 PetscInt i,nsplit; 455 MatStructure flag = pc->flag; 456 PetscBool sorted, sorted_col; 457 458 PetscFunctionBegin; 459 ierr = PCFieldSplitSetDefaults(pc);CHKERRQ(ierr); 460 nsplit = jac->nsplits; 461 ilink = jac->head; 462 463 /* get the matrices for each split */ 464 if (!jac->issetup) { 465 PetscInt rstart,rend,nslots,bs; 466 467 jac->issetup = PETSC_TRUE; 468 469 /* This is done here instead of in PCFieldSplitSetFields() because may not have matrix at that point */ 470 if (jac->defaultsplit || !ilink->is) { 471 if (jac->bs <= 0) jac->bs = nsplit; 472 } 473 bs = jac->bs; 474 ierr = MatGetOwnershipRange(pc->pmat,&rstart,&rend);CHKERRQ(ierr); 475 nslots = (rend - rstart)/bs; 476 for (i=0; i<nsplit; i++) { 477 if (jac->defaultsplit) { 478 ierr = ISCreateStride(PetscObjectComm((PetscObject)pc),nslots,rstart+i,nsplit,&ilink->is);CHKERRQ(ierr); 479 ierr = ISDuplicate(ilink->is,&ilink->is_col);CHKERRQ(ierr); 480 } else if (!ilink->is) { 481 if (ilink->nfields > 1) { 482 PetscInt *ii,*jj,j,k,nfields = ilink->nfields,*fields = ilink->fields,*fields_col = ilink->fields_col; 483 ierr = PetscMalloc(ilink->nfields*nslots*sizeof(PetscInt),&ii);CHKERRQ(ierr); 484 ierr = PetscMalloc(ilink->nfields*nslots*sizeof(PetscInt),&jj);CHKERRQ(ierr); 485 for (j=0; j<nslots; j++) { 486 for (k=0; k<nfields; k++) { 487 ii[nfields*j + k] = rstart + bs*j + fields[k]; 488 jj[nfields*j + k] = rstart + bs*j + fields_col[k]; 489 } 490 } 491 ierr = ISCreateGeneral(PetscObjectComm((PetscObject)pc),nslots*nfields,ii,PETSC_OWN_POINTER,&ilink->is);CHKERRQ(ierr); 492 ierr = ISCreateGeneral(PetscObjectComm((PetscObject)pc),nslots*nfields,jj,PETSC_OWN_POINTER,&ilink->is_col);CHKERRQ(ierr); 493 } else { 494 ierr = ISCreateStride(PetscObjectComm((PetscObject)pc),nslots,rstart+ilink->fields[0],bs,&ilink->is);CHKERRQ(ierr); 495 ierr = ISCreateStride(PetscObjectComm((PetscObject)pc),nslots,rstart+ilink->fields_col[0],bs,&ilink->is_col);CHKERRQ(ierr); 496 } 497 } 498 ierr = ISSorted(ilink->is,&sorted);CHKERRQ(ierr); 499 if (ilink->is_col) { ierr = ISSorted(ilink->is_col,&sorted_col);CHKERRQ(ierr); } 500 if (!sorted || !sorted_col) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Fields must be sorted when creating split"); 501 ilink = ilink->next; 502 } 503 } 504 505 ilink = jac->head; 506 if (!jac->pmat) { 507 Vec xtmp; 508 509 ierr = MatGetVecs(pc->pmat,&xtmp,NULL);CHKERRQ(ierr); 510 ierr = PetscMalloc(nsplit*sizeof(Mat),&jac->pmat);CHKERRQ(ierr); 511 ierr = PetscMalloc2(nsplit,Vec,&jac->x,nsplit,Vec,&jac->y);CHKERRQ(ierr); 512 for (i=0; i<nsplit; i++) { 513 MatNullSpace sp; 514 515 /* Check for preconditioning matrix attached to IS */ 516 ierr = PetscObjectQuery((PetscObject) ilink->is, "pmat", (PetscObject*) &jac->pmat[i]);CHKERRQ(ierr); 517 if (jac->pmat[i]) { 518 ierr = PetscObjectReference((PetscObject) jac->pmat[i]);CHKERRQ(ierr); 519 if (jac->type == PC_COMPOSITE_SCHUR) { 520 jac->schur_user = jac->pmat[i]; 521 522 ierr = PetscObjectReference((PetscObject) jac->schur_user);CHKERRQ(ierr); 523 } 524 } else { 525 ierr = MatGetSubMatrix(pc->pmat,ilink->is,ilink->is_col,MAT_INITIAL_MATRIX,&jac->pmat[i]);CHKERRQ(ierr); 526 } 527 /* create work vectors for each split */ 528 ierr = MatGetVecs(jac->pmat[i],&jac->x[i],&jac->y[i]);CHKERRQ(ierr); 529 ilink->x = jac->x[i]; ilink->y = jac->y[i]; ilink->z = NULL; 530 /* compute scatter contexts needed by multiplicative versions and non-default splits */ 531 ierr = VecScatterCreate(xtmp,ilink->is,jac->x[i],NULL,&ilink->sctx);CHKERRQ(ierr); 532 /* Check for null space attached to IS */ 533 ierr = PetscObjectQuery((PetscObject) ilink->is, "nullspace", (PetscObject*) &sp);CHKERRQ(ierr); 534 if (sp) { 535 ierr = MatSetNullSpace(jac->pmat[i], sp);CHKERRQ(ierr); 536 } 537 ierr = PetscObjectQuery((PetscObject) ilink->is, "nearnullspace", (PetscObject*) &sp);CHKERRQ(ierr); 538 if (sp) { 539 ierr = MatSetNearNullSpace(jac->pmat[i], sp);CHKERRQ(ierr); 540 } 541 ilink = ilink->next; 542 } 543 ierr = VecDestroy(&xtmp);CHKERRQ(ierr); 544 } else { 545 for (i=0; i<nsplit; i++) { 546 Mat pmat; 547 548 /* Check for preconditioning matrix attached to IS */ 549 ierr = PetscObjectQuery((PetscObject) ilink->is, "pmat", (PetscObject*) &pmat);CHKERRQ(ierr); 550 if (!pmat) { 551 ierr = MatGetSubMatrix(pc->pmat,ilink->is,ilink->is_col,MAT_REUSE_MATRIX,&jac->pmat[i]);CHKERRQ(ierr); 552 } 553 ilink = ilink->next; 554 } 555 } 556 if (jac->realdiagonal) { 557 ilink = jac->head; 558 if (!jac->mat) { 559 ierr = PetscMalloc(nsplit*sizeof(Mat),&jac->mat);CHKERRQ(ierr); 560 for (i=0; i<nsplit; i++) { 561 ierr = MatGetSubMatrix(pc->mat,ilink->is,ilink->is_col,MAT_INITIAL_MATRIX,&jac->mat[i]);CHKERRQ(ierr); 562 ilink = ilink->next; 563 } 564 } else { 565 for (i=0; i<nsplit; i++) { 566 if (jac->mat[i]) {ierr = MatGetSubMatrix(pc->mat,ilink->is,ilink->is_col,MAT_REUSE_MATRIX,&jac->mat[i]);CHKERRQ(ierr);} 567 ilink = ilink->next; 568 } 569 } 570 } else { 571 jac->mat = jac->pmat; 572 } 573 574 if (jac->type != PC_COMPOSITE_ADDITIVE && jac->type != PC_COMPOSITE_SCHUR) { 575 /* extract the rows of the matrix associated with each field: used for efficient computation of residual inside algorithm */ 576 ilink = jac->head; 577 if (!jac->Afield) { 578 ierr = PetscMalloc(nsplit*sizeof(Mat),&jac->Afield);CHKERRQ(ierr); 579 for (i=0; i<nsplit; i++) { 580 ierr = MatGetSubMatrix(pc->mat,ilink->is,NULL,MAT_INITIAL_MATRIX,&jac->Afield[i]);CHKERRQ(ierr); 581 ilink = ilink->next; 582 } 583 } else { 584 for (i=0; i<nsplit; i++) { 585 ierr = MatGetSubMatrix(pc->mat,ilink->is,NULL,MAT_REUSE_MATRIX,&jac->Afield[i]);CHKERRQ(ierr); 586 ilink = ilink->next; 587 } 588 } 589 } 590 591 if (jac->type == PC_COMPOSITE_SCHUR) { 592 IS ccis; 593 PetscInt rstart,rend; 594 char lscname[256]; 595 PetscObject LSC_L; 596 597 if (nsplit != 2) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_INCOMP,"To use Schur complement preconditioner you must have exactly 2 fields"); 598 599 /* When extracting off-diagonal submatrices, we take complements from this range */ 600 ierr = MatGetOwnershipRangeColumn(pc->mat,&rstart,&rend);CHKERRQ(ierr); 601 602 /* need to handle case when one is resetting up the preconditioner */ 603 if (jac->schur) { 604 KSP kspA = jac->head->ksp, kspInner = NULL, kspUpper = jac->kspupper; 605 606 ierr = MatSchurComplementGetKSP(jac->schur, &kspInner);CHKERRQ(ierr); 607 ilink = jac->head; 608 ierr = ISComplement(ilink->is_col,rstart,rend,&ccis);CHKERRQ(ierr); 609 ierr = MatGetSubMatrix(pc->mat,ilink->is,ccis,MAT_REUSE_MATRIX,&jac->B);CHKERRQ(ierr); 610 ierr = ISDestroy(&ccis);CHKERRQ(ierr); 611 ilink = ilink->next; 612 ierr = ISComplement(ilink->is_col,rstart,rend,&ccis);CHKERRQ(ierr); 613 ierr = MatGetSubMatrix(pc->mat,ilink->is,ccis,MAT_REUSE_MATRIX,&jac->C);CHKERRQ(ierr); 614 ierr = ISDestroy(&ccis);CHKERRQ(ierr); 615 ierr = MatSchurComplementUpdate(jac->schur,jac->mat[0],jac->pmat[0],jac->B,jac->C,jac->mat[1],pc->flag);CHKERRQ(ierr); 616 if (kspA != kspInner) { 617 ierr = KSPSetOperators(kspA,jac->mat[0],jac->pmat[0],pc->flag);CHKERRQ(ierr); 618 } 619 if (kspUpper != kspA) { 620 ierr = KSPSetOperators(kspUpper,jac->mat[0],jac->pmat[0],pc->flag);CHKERRQ(ierr); 621 } 622 ierr = KSPSetOperators(jac->kspschur,jac->schur,FieldSplitSchurPre(jac),pc->flag);CHKERRQ(ierr); 623 } else { 624 KSP ksp; 625 const char *Dprefix; 626 char schurprefix[256]; 627 char schurtestoption[256]; 628 MatNullSpace sp; 629 PetscBool flg; 630 631 /* extract the A01 and A10 matrices */ 632 ilink = jac->head; 633 ierr = ISComplement(ilink->is_col,rstart,rend,&ccis);CHKERRQ(ierr); 634 ierr = MatGetSubMatrix(pc->mat,ilink->is,ccis,MAT_INITIAL_MATRIX,&jac->B);CHKERRQ(ierr); 635 ierr = ISDestroy(&ccis);CHKERRQ(ierr); 636 ilink = ilink->next; 637 ierr = ISComplement(ilink->is_col,rstart,rend,&ccis);CHKERRQ(ierr); 638 ierr = MatGetSubMatrix(pc->mat,ilink->is,ccis,MAT_INITIAL_MATRIX,&jac->C);CHKERRQ(ierr); 639 ierr = ISDestroy(&ccis);CHKERRQ(ierr); 640 641 /* Use mat[0] (diagonal block of the real matrix) preconditioned by pmat[0] to define Schur complement */ 642 ierr = MatCreate(((PetscObject)jac->mat[0])->comm,&jac->schur);CHKERRQ(ierr); 643 ierr = MatSetType(jac->schur,MATSCHURCOMPLEMENT);CHKERRQ(ierr); 644 ierr = MatSchurComplementGetKSP(jac->schur, &ksp);CHKERRQ(ierr); 645 ierr = PetscSNPrintf(schurprefix, sizeof(schurprefix), "%sfieldsplit_%s_inner_", ((PetscObject)pc)->prefix ? ((PetscObject)pc)->prefix : "", ilink->splitname);CHKERRQ(ierr); 646 /* Indent this deeper to emphasize the "inner" nature of this solver. */ 647 ierr = PetscObjectIncrementTabLevel((PetscObject)ksp, (PetscObject) pc, 2);CHKERRQ(ierr); 648 ierr = KSPSetOptionsPrefix(ksp, schurprefix);CHKERRQ(ierr); 649 ierr = MatSchurComplementSet(jac->schur,jac->mat[0],jac->pmat[0],jac->B,jac->C,jac->mat[1]);CHKERRQ(ierr); 650 651 ierr = MatGetNullSpace(jac->pmat[1], &sp);CHKERRQ(ierr); 652 if (sp) { 653 ierr = MatSetNullSpace(jac->schur, sp);CHKERRQ(ierr); 654 } 655 656 ierr = PetscSNPrintf(schurtestoption, sizeof(schurtestoption), "-fieldsplit_%s_inner_", ilink->splitname);CHKERRQ(ierr); 657 ierr = PetscOptionsFindPairPrefix_Private(((PetscObject)pc)->prefix, schurtestoption, NULL, &flg);CHKERRQ(ierr); 658 if (flg) { 659 DM dmInner; 660 661 /* Set DM for new solver */ 662 ierr = KSPGetDM(jac->head->ksp, &dmInner);CHKERRQ(ierr); 663 ierr = KSPSetDM(ksp, dmInner);CHKERRQ(ierr); 664 ierr = KSPSetDMActive(ksp, PETSC_FALSE);CHKERRQ(ierr); 665 ierr = KSPSetOperators(jac->head->ksp,jac->mat[0],jac->pmat[0],flag);CHKERRQ(ierr); 666 ierr = KSPSetFromOptions(jac->head->ksp);CHKERRQ(ierr); 667 } else { 668 ierr = MatSchurComplementSetKSP(jac->schur, jac->head->ksp);CHKERRQ(ierr); 669 ierr = PetscObjectReference((PetscObject) jac->head->ksp);CHKERRQ(ierr); 670 } 671 ierr = MatSetFromOptions(jac->schur);CHKERRQ(ierr); 672 673 ierr = PetscSNPrintf(schurtestoption, sizeof(schurtestoption), "-fieldsplit_%s_upper_", ilink->splitname);CHKERRQ(ierr); 674 ierr = PetscOptionsFindPairPrefix_Private(((PetscObject)pc)->prefix, schurtestoption, NULL, &flg);CHKERRQ(ierr); 675 if (flg) { 676 DM dmInner; 677 678 ierr = PetscSNPrintf(schurprefix, sizeof(schurprefix), "%sfieldsplit_%s_upper_", ((PetscObject)pc)->prefix ? ((PetscObject)pc)->prefix : "", ilink->splitname);CHKERRQ(ierr); 679 ierr = KSPCreate(PetscObjectComm((PetscObject)pc), &jac->kspupper);CHKERRQ(ierr); 680 ierr = KSPSetOptionsPrefix(jac->kspupper, schurprefix);CHKERRQ(ierr); 681 ierr = KSPGetDM(jac->head->ksp, &dmInner);CHKERRQ(ierr); 682 ierr = KSPSetDM(jac->kspupper, dmInner);CHKERRQ(ierr); 683 ierr = KSPSetDMActive(jac->kspupper, PETSC_FALSE);CHKERRQ(ierr); 684 ierr = KSPSetFromOptions(jac->kspupper);CHKERRQ(ierr); 685 ierr = KSPSetOperators(jac->kspupper,jac->mat[0],jac->pmat[0],flag);CHKERRQ(ierr); 686 ierr = VecDuplicate(jac->head->x, &jac->head->z);CHKERRQ(ierr); 687 } else { 688 jac->kspupper = jac->head->ksp; 689 ierr = PetscObjectReference((PetscObject) jac->head->ksp);CHKERRQ(ierr); 690 } 691 692 ierr = KSPCreate(PetscObjectComm((PetscObject)pc),&jac->kspschur);CHKERRQ(ierr); 693 ierr = PetscLogObjectParent((PetscObject)pc,(PetscObject)jac->kspschur);CHKERRQ(ierr); 694 ierr = PetscObjectIncrementTabLevel((PetscObject)jac->kspschur,(PetscObject)pc,1);CHKERRQ(ierr); 695 ierr = KSPSetOperators(jac->kspschur,jac->schur,FieldSplitSchurPre(jac),DIFFERENT_NONZERO_PATTERN);CHKERRQ(ierr); 696 if (jac->schurpre == PC_FIELDSPLIT_SCHUR_PRE_SELF) { 697 PC pcschur; 698 ierr = KSPGetPC(jac->kspschur,&pcschur);CHKERRQ(ierr); 699 ierr = PCSetType(pcschur,PCNONE);CHKERRQ(ierr); 700 /* Note: This is bad if there exist preconditioners for MATSCHURCOMPLEMENT */ 701 } 702 ierr = KSPGetOptionsPrefix(jac->head->next->ksp, &Dprefix);CHKERRQ(ierr); 703 ierr = KSPSetOptionsPrefix(jac->kspschur, Dprefix);CHKERRQ(ierr); 704 /* really want setfromoptions called in PCSetFromOptions_FieldSplit(), but it is not ready yet */ 705 /* need to call this every time, since the jac->kspschur is freshly created, otherwise its options never get set */ 706 ierr = KSPSetFromOptions(jac->kspschur);CHKERRQ(ierr); 707 } 708 709 /* HACK: special support to forward L and Lp matrices that might be used by PCLSC */ 710 ierr = PetscSNPrintf(lscname,sizeof(lscname),"%s_LSC_L",ilink->splitname);CHKERRQ(ierr); 711 ierr = PetscObjectQuery((PetscObject)pc->mat,lscname,(PetscObject*)&LSC_L);CHKERRQ(ierr); 712 if (!LSC_L) {ierr = PetscObjectQuery((PetscObject)pc->pmat,lscname,(PetscObject*)&LSC_L);CHKERRQ(ierr);} 713 if (LSC_L) {ierr = PetscObjectCompose((PetscObject)jac->schur,"LSC_L",(PetscObject)LSC_L);CHKERRQ(ierr);} 714 ierr = PetscSNPrintf(lscname,sizeof(lscname),"%s_LSC_Lp",ilink->splitname);CHKERRQ(ierr); 715 ierr = PetscObjectQuery((PetscObject)pc->pmat,lscname,(PetscObject*)&LSC_L);CHKERRQ(ierr); 716 if (!LSC_L) {ierr = PetscObjectQuery((PetscObject)pc->mat,lscname,(PetscObject*)&LSC_L);CHKERRQ(ierr);} 717 if (LSC_L) {ierr = PetscObjectCompose((PetscObject)jac->schur,"LSC_Lp",(PetscObject)LSC_L);CHKERRQ(ierr);} 718 } else { 719 /* set up the individual splits' PCs */ 720 i = 0; 721 ilink = jac->head; 722 while (ilink) { 723 ierr = KSPSetOperators(ilink->ksp,jac->mat[i],jac->pmat[i],flag);CHKERRQ(ierr); 724 /* really want setfromoptions called in PCSetFromOptions_FieldSplit(), but it is not ready yet */ 725 if (!jac->suboptionsset) {ierr = KSPSetFromOptions(ilink->ksp);CHKERRQ(ierr);} 726 i++; 727 ilink = ilink->next; 728 } 729 } 730 731 jac->suboptionsset = PETSC_TRUE; 732 PetscFunctionReturn(0); 733 } 734 735 #define FieldSplitSplitSolveAdd(ilink,xx,yy) \ 736 (VecScatterBegin(ilink->sctx,xx,ilink->x,INSERT_VALUES,SCATTER_FORWARD) || \ 737 VecScatterEnd(ilink->sctx,xx,ilink->x,INSERT_VALUES,SCATTER_FORWARD) || \ 738 KSPSolve(ilink->ksp,ilink->x,ilink->y) || \ 739 VecScatterBegin(ilink->sctx,ilink->y,yy,ADD_VALUES,SCATTER_REVERSE) || \ 740 VecScatterEnd(ilink->sctx,ilink->y,yy,ADD_VALUES,SCATTER_REVERSE)) 741 742 #undef __FUNCT__ 743 #define __FUNCT__ "PCApply_FieldSplit_Schur" 744 static PetscErrorCode PCApply_FieldSplit_Schur(PC pc,Vec x,Vec y) 745 { 746 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 747 PetscErrorCode ierr; 748 PC_FieldSplitLink ilinkA = jac->head, ilinkD = ilinkA->next; 749 KSP kspA = ilinkA->ksp, kspLower = kspA, kspUpper = jac->kspupper; 750 751 PetscFunctionBegin; 752 switch (jac->schurfactorization) { 753 case PC_FIELDSPLIT_SCHUR_FACT_DIAG: 754 /* [A00 0; 0 -S], positive definite, suitable for MINRES */ 755 ierr = VecScatterBegin(ilinkA->sctx,x,ilinkA->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 756 ierr = VecScatterBegin(ilinkD->sctx,x,ilinkD->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 757 ierr = VecScatterEnd(ilinkA->sctx,x,ilinkA->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 758 ierr = KSPSolve(kspA,ilinkA->x,ilinkA->y);CHKERRQ(ierr); 759 ierr = VecScatterBegin(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 760 ierr = VecScatterEnd(ilinkD->sctx,x,ilinkD->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 761 ierr = KSPSolve(jac->kspschur,ilinkD->x,ilinkD->y);CHKERRQ(ierr); 762 ierr = VecScale(ilinkD->y,-1.);CHKERRQ(ierr); 763 ierr = VecScatterBegin(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 764 ierr = VecScatterEnd(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 765 ierr = VecScatterEnd(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 766 break; 767 case PC_FIELDSPLIT_SCHUR_FACT_LOWER: 768 /* [A00 0; A10 S], suitable for left preconditioning */ 769 ierr = VecScatterBegin(ilinkA->sctx,x,ilinkA->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 770 ierr = VecScatterEnd(ilinkA->sctx,x,ilinkA->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 771 ierr = KSPSolve(kspA,ilinkA->x,ilinkA->y);CHKERRQ(ierr); 772 ierr = MatMult(jac->C,ilinkA->y,ilinkD->x);CHKERRQ(ierr); 773 ierr = VecScale(ilinkD->x,-1.);CHKERRQ(ierr); 774 ierr = VecScatterBegin(ilinkD->sctx,x,ilinkD->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 775 ierr = VecScatterBegin(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 776 ierr = VecScatterEnd(ilinkD->sctx,x,ilinkD->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 777 ierr = KSPSolve(jac->kspschur,ilinkD->x,ilinkD->y);CHKERRQ(ierr); 778 ierr = VecScatterBegin(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 779 ierr = VecScatterEnd(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 780 ierr = VecScatterEnd(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 781 break; 782 case PC_FIELDSPLIT_SCHUR_FACT_UPPER: 783 /* [A00 A01; 0 S], suitable for right preconditioning */ 784 ierr = VecScatterBegin(ilinkD->sctx,x,ilinkD->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 785 ierr = VecScatterEnd(ilinkD->sctx,x,ilinkD->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 786 ierr = KSPSolve(jac->kspschur,ilinkD->x,ilinkD->y);CHKERRQ(ierr); 787 ierr = MatMult(jac->B,ilinkD->y,ilinkA->x);CHKERRQ(ierr); 788 ierr = VecScale(ilinkA->x,-1.);CHKERRQ(ierr); 789 ierr = VecScatterBegin(ilinkA->sctx,x,ilinkA->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 790 ierr = VecScatterBegin(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 791 ierr = VecScatterEnd(ilinkA->sctx,x,ilinkA->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 792 ierr = KSPSolve(kspA,ilinkA->x,ilinkA->y);CHKERRQ(ierr); 793 ierr = VecScatterBegin(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 794 ierr = VecScatterEnd(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 795 ierr = VecScatterEnd(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 796 break; 797 case PC_FIELDSPLIT_SCHUR_FACT_FULL: 798 /* [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 */ 799 ierr = VecScatterBegin(ilinkA->sctx,x,ilinkA->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 800 ierr = VecScatterEnd(ilinkA->sctx,x,ilinkA->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 801 ierr = KSPSolve(kspLower,ilinkA->x,ilinkA->y);CHKERRQ(ierr); 802 ierr = MatMult(jac->C,ilinkA->y,ilinkD->x);CHKERRQ(ierr); 803 ierr = VecScale(ilinkD->x,-1.0);CHKERRQ(ierr); 804 ierr = VecScatterBegin(ilinkD->sctx,x,ilinkD->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 805 ierr = VecScatterEnd(ilinkD->sctx,x,ilinkD->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 806 807 ierr = KSPSolve(jac->kspschur,ilinkD->x,ilinkD->y);CHKERRQ(ierr); 808 ierr = VecScatterBegin(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 809 ierr = VecScatterEnd(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 810 811 if (kspUpper == kspA) { 812 ierr = MatMult(jac->B,ilinkD->y,ilinkA->y);CHKERRQ(ierr); 813 ierr = VecAXPY(ilinkA->x,-1.0,ilinkA->y);CHKERRQ(ierr); 814 ierr = KSPSolve(kspA,ilinkA->x,ilinkA->y);CHKERRQ(ierr); 815 } else { 816 ierr = KSPSolve(kspA,ilinkA->x,ilinkA->y);CHKERRQ(ierr); 817 ierr = MatMult(jac->B,ilinkD->y,ilinkA->x);CHKERRQ(ierr); 818 ierr = KSPSolve(kspUpper,ilinkA->x,ilinkA->z);CHKERRQ(ierr); 819 ierr = VecAXPY(ilinkA->y,-1.0,ilinkA->z);CHKERRQ(ierr); 820 } 821 ierr = VecScatterBegin(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 822 ierr = VecScatterEnd(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 823 } 824 PetscFunctionReturn(0); 825 } 826 827 #undef __FUNCT__ 828 #define __FUNCT__ "PCApply_FieldSplit" 829 static PetscErrorCode PCApply_FieldSplit(PC pc,Vec x,Vec y) 830 { 831 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 832 PetscErrorCode ierr; 833 PC_FieldSplitLink ilink = jac->head; 834 PetscInt cnt,bs; 835 836 PetscFunctionBegin; 837 CHKMEMQ; 838 if (jac->type == PC_COMPOSITE_ADDITIVE) { 839 if (jac->defaultsplit) { 840 ierr = VecGetBlockSize(x,&bs);CHKERRQ(ierr); 841 if (jac->bs > 0 && bs != jac->bs) SETERRQ2(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Blocksize of x vector %D does not match fieldsplit blocksize %D",bs,jac->bs); 842 ierr = VecGetBlockSize(y,&bs);CHKERRQ(ierr); 843 if (jac->bs > 0 && bs != jac->bs) SETERRQ2(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Blocksize of y vector %D does not match fieldsplit blocksize %D",bs,jac->bs); 844 ierr = VecStrideGatherAll(x,jac->x,INSERT_VALUES);CHKERRQ(ierr); 845 while (ilink) { 846 ierr = KSPSolve(ilink->ksp,ilink->x,ilink->y);CHKERRQ(ierr); 847 ilink = ilink->next; 848 } 849 ierr = VecStrideScatterAll(jac->y,y,INSERT_VALUES);CHKERRQ(ierr); 850 } else { 851 ierr = VecSet(y,0.0);CHKERRQ(ierr); 852 while (ilink) { 853 ierr = FieldSplitSplitSolveAdd(ilink,x,y);CHKERRQ(ierr); 854 ilink = ilink->next; 855 } 856 } 857 } else if (jac->type == PC_COMPOSITE_MULTIPLICATIVE || jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) { 858 if (!jac->w1) { 859 ierr = VecDuplicate(x,&jac->w1);CHKERRQ(ierr); 860 ierr = VecDuplicate(x,&jac->w2);CHKERRQ(ierr); 861 } 862 ierr = VecSet(y,0.0);CHKERRQ(ierr); 863 ierr = FieldSplitSplitSolveAdd(ilink,x,y);CHKERRQ(ierr); 864 cnt = 1; 865 while (ilink->next) { 866 ilink = ilink->next; 867 /* compute the residual only over the part of the vector needed */ 868 ierr = MatMult(jac->Afield[cnt++],y,ilink->x);CHKERRQ(ierr); 869 ierr = VecScale(ilink->x,-1.0);CHKERRQ(ierr); 870 ierr = VecScatterBegin(ilink->sctx,x,ilink->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 871 ierr = VecScatterEnd(ilink->sctx,x,ilink->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 872 ierr = KSPSolve(ilink->ksp,ilink->x,ilink->y);CHKERRQ(ierr); 873 ierr = VecScatterBegin(ilink->sctx,ilink->y,y,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 874 ierr = VecScatterEnd(ilink->sctx,ilink->y,y,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 875 } 876 if (jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) { 877 cnt -= 2; 878 while (ilink->previous) { 879 ilink = ilink->previous; 880 /* compute the residual only over the part of the vector needed */ 881 ierr = MatMult(jac->Afield[cnt--],y,ilink->x);CHKERRQ(ierr); 882 ierr = VecScale(ilink->x,-1.0);CHKERRQ(ierr); 883 ierr = VecScatterBegin(ilink->sctx,x,ilink->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 884 ierr = VecScatterEnd(ilink->sctx,x,ilink->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 885 ierr = KSPSolve(ilink->ksp,ilink->x,ilink->y);CHKERRQ(ierr); 886 ierr = VecScatterBegin(ilink->sctx,ilink->y,y,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 887 ierr = VecScatterEnd(ilink->sctx,ilink->y,y,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 888 } 889 } 890 } else SETERRQ1(PetscObjectComm((PetscObject)pc),PETSC_ERR_SUP,"Unsupported or unknown composition",(int) jac->type); 891 CHKMEMQ; 892 PetscFunctionReturn(0); 893 } 894 895 #define FieldSplitSplitSolveAddTranspose(ilink,xx,yy) \ 896 (VecScatterBegin(ilink->sctx,xx,ilink->y,INSERT_VALUES,SCATTER_FORWARD) || \ 897 VecScatterEnd(ilink->sctx,xx,ilink->y,INSERT_VALUES,SCATTER_FORWARD) || \ 898 KSPSolveTranspose(ilink->ksp,ilink->y,ilink->x) || \ 899 VecScatterBegin(ilink->sctx,ilink->x,yy,ADD_VALUES,SCATTER_REVERSE) || \ 900 VecScatterEnd(ilink->sctx,ilink->x,yy,ADD_VALUES,SCATTER_REVERSE)) 901 902 #undef __FUNCT__ 903 #define __FUNCT__ "PCApplyTranspose_FieldSplit" 904 static PetscErrorCode PCApplyTranspose_FieldSplit(PC pc,Vec x,Vec y) 905 { 906 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 907 PetscErrorCode ierr; 908 PC_FieldSplitLink ilink = jac->head; 909 PetscInt bs; 910 911 PetscFunctionBegin; 912 CHKMEMQ; 913 if (jac->type == PC_COMPOSITE_ADDITIVE) { 914 if (jac->defaultsplit) { 915 ierr = VecGetBlockSize(x,&bs);CHKERRQ(ierr); 916 if (jac->bs > 0 && bs != jac->bs) SETERRQ2(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Blocksize of x vector %D does not match fieldsplit blocksize %D",bs,jac->bs); 917 ierr = VecGetBlockSize(y,&bs);CHKERRQ(ierr); 918 if (jac->bs > 0 && bs != jac->bs) SETERRQ2(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Blocksize of y vector %D does not match fieldsplit blocksize %D",bs,jac->bs); 919 ierr = VecStrideGatherAll(x,jac->x,INSERT_VALUES);CHKERRQ(ierr); 920 while (ilink) { 921 ierr = KSPSolveTranspose(ilink->ksp,ilink->x,ilink->y);CHKERRQ(ierr); 922 ilink = ilink->next; 923 } 924 ierr = VecStrideScatterAll(jac->y,y,INSERT_VALUES);CHKERRQ(ierr); 925 } else { 926 ierr = VecSet(y,0.0);CHKERRQ(ierr); 927 while (ilink) { 928 ierr = FieldSplitSplitSolveAddTranspose(ilink,x,y);CHKERRQ(ierr); 929 ilink = ilink->next; 930 } 931 } 932 } else { 933 if (!jac->w1) { 934 ierr = VecDuplicate(x,&jac->w1);CHKERRQ(ierr); 935 ierr = VecDuplicate(x,&jac->w2);CHKERRQ(ierr); 936 } 937 ierr = VecSet(y,0.0);CHKERRQ(ierr); 938 if (jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) { 939 ierr = FieldSplitSplitSolveAddTranspose(ilink,x,y);CHKERRQ(ierr); 940 while (ilink->next) { 941 ilink = ilink->next; 942 ierr = MatMultTranspose(pc->mat,y,jac->w1);CHKERRQ(ierr); 943 ierr = VecWAXPY(jac->w2,-1.0,jac->w1,x);CHKERRQ(ierr); 944 ierr = FieldSplitSplitSolveAddTranspose(ilink,jac->w2,y);CHKERRQ(ierr); 945 } 946 while (ilink->previous) { 947 ilink = ilink->previous; 948 ierr = MatMultTranspose(pc->mat,y,jac->w1);CHKERRQ(ierr); 949 ierr = VecWAXPY(jac->w2,-1.0,jac->w1,x);CHKERRQ(ierr); 950 ierr = FieldSplitSplitSolveAddTranspose(ilink,jac->w2,y);CHKERRQ(ierr); 951 } 952 } else { 953 while (ilink->next) { /* get to last entry in linked list */ 954 ilink = ilink->next; 955 } 956 ierr = FieldSplitSplitSolveAddTranspose(ilink,x,y);CHKERRQ(ierr); 957 while (ilink->previous) { 958 ilink = ilink->previous; 959 ierr = MatMultTranspose(pc->mat,y,jac->w1);CHKERRQ(ierr); 960 ierr = VecWAXPY(jac->w2,-1.0,jac->w1,x);CHKERRQ(ierr); 961 ierr = FieldSplitSplitSolveAddTranspose(ilink,jac->w2,y);CHKERRQ(ierr); 962 } 963 } 964 } 965 CHKMEMQ; 966 PetscFunctionReturn(0); 967 } 968 969 #undef __FUNCT__ 970 #define __FUNCT__ "PCReset_FieldSplit" 971 static PetscErrorCode PCReset_FieldSplit(PC pc) 972 { 973 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 974 PetscErrorCode ierr; 975 PC_FieldSplitLink ilink = jac->head,next; 976 977 PetscFunctionBegin; 978 while (ilink) { 979 ierr = KSPReset(ilink->ksp);CHKERRQ(ierr); 980 ierr = VecDestroy(&ilink->x);CHKERRQ(ierr); 981 ierr = VecDestroy(&ilink->y);CHKERRQ(ierr); 982 ierr = VecDestroy(&ilink->z);CHKERRQ(ierr); 983 ierr = VecScatterDestroy(&ilink->sctx);CHKERRQ(ierr); 984 ierr = ISDestroy(&ilink->is);CHKERRQ(ierr); 985 ierr = ISDestroy(&ilink->is_col);CHKERRQ(ierr); 986 next = ilink->next; 987 ilink = next; 988 } 989 ierr = PetscFree2(jac->x,jac->y);CHKERRQ(ierr); 990 if (jac->mat && jac->mat != jac->pmat) { 991 ierr = MatDestroyMatrices(jac->nsplits,&jac->mat);CHKERRQ(ierr); 992 } else if (jac->mat) { 993 jac->mat = NULL; 994 } 995 if (jac->pmat) {ierr = MatDestroyMatrices(jac->nsplits,&jac->pmat);CHKERRQ(ierr);} 996 if (jac->Afield) {ierr = MatDestroyMatrices(jac->nsplits,&jac->Afield);CHKERRQ(ierr);} 997 ierr = VecDestroy(&jac->w1);CHKERRQ(ierr); 998 ierr = VecDestroy(&jac->w2);CHKERRQ(ierr); 999 ierr = MatDestroy(&jac->schur);CHKERRQ(ierr); 1000 ierr = MatDestroy(&jac->schur_user);CHKERRQ(ierr); 1001 ierr = KSPDestroy(&jac->kspschur);CHKERRQ(ierr); 1002 ierr = KSPDestroy(&jac->kspupper);CHKERRQ(ierr); 1003 ierr = MatDestroy(&jac->B);CHKERRQ(ierr); 1004 ierr = MatDestroy(&jac->C);CHKERRQ(ierr); 1005 jac->reset = PETSC_TRUE; 1006 PetscFunctionReturn(0); 1007 } 1008 1009 #undef __FUNCT__ 1010 #define __FUNCT__ "PCDestroy_FieldSplit" 1011 static PetscErrorCode PCDestroy_FieldSplit(PC pc) 1012 { 1013 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 1014 PetscErrorCode ierr; 1015 PC_FieldSplitLink ilink = jac->head,next; 1016 1017 PetscFunctionBegin; 1018 ierr = PCReset_FieldSplit(pc);CHKERRQ(ierr); 1019 while (ilink) { 1020 ierr = KSPDestroy(&ilink->ksp);CHKERRQ(ierr); 1021 next = ilink->next; 1022 ierr = PetscFree(ilink->splitname);CHKERRQ(ierr); 1023 ierr = PetscFree(ilink->fields);CHKERRQ(ierr); 1024 ierr = PetscFree(ilink->fields_col);CHKERRQ(ierr); 1025 ierr = PetscFree(ilink);CHKERRQ(ierr); 1026 ilink = next; 1027 } 1028 ierr = PetscFree2(jac->x,jac->y);CHKERRQ(ierr); 1029 ierr = PetscFree(pc->data);CHKERRQ(ierr); 1030 ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitGetSubKSP_C","",NULL);CHKERRQ(ierr); 1031 ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetFields_C","",NULL);CHKERRQ(ierr); 1032 ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetIS_C","",NULL);CHKERRQ(ierr); 1033 ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetType_C","",NULL);CHKERRQ(ierr); 1034 ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetBlockSize_C","",NULL);CHKERRQ(ierr); 1035 ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSchurPrecondition_C","",NULL);CHKERRQ(ierr); 1036 ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetSchurFactType_C","",NULL);CHKERRQ(ierr); 1037 PetscFunctionReturn(0); 1038 } 1039 1040 #undef __FUNCT__ 1041 #define __FUNCT__ "PCSetFromOptions_FieldSplit" 1042 static PetscErrorCode PCSetFromOptions_FieldSplit(PC pc) 1043 { 1044 PetscErrorCode ierr; 1045 PetscInt bs; 1046 PetscBool flg,stokes = PETSC_FALSE; 1047 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 1048 PCCompositeType ctype; 1049 1050 PetscFunctionBegin; 1051 ierr = PetscOptionsHead("FieldSplit options");CHKERRQ(ierr); 1052 ierr = PetscOptionsBool("-pc_fieldsplit_real_diagonal","Use diagonal blocks of the operator","PCFieldSplitSetRealDiagonal",jac->realdiagonal,&jac->realdiagonal,NULL);CHKERRQ(ierr); 1053 ierr = PetscOptionsBool("-pc_fieldsplit_dm_splits","Whether to use DMCreateFieldDecomposition() for splits","PCFieldSplitSetDMSplits",jac->dm_splits,&jac->dm_splits,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(PetscObjectComm((PetscObject)pc),&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(PetscObjectComm((PetscObject)pc),&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(PetscObjectComm((PetscObject)pc),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(PetscObjectComm((PetscObject)pc),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(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_OUTOFRANGE,"Blocksize must be positive, you gave %D",bs); 1633 if (jac->bs > 0 && jac->bs != bs) SETERRQ2(PetscObjectComm((PetscObject)pc),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 #undef __FUNCT__ 1700 #define __FUNCT__ "PCFieldSplitSetDMSplits" 1701 /*@ 1702 PCFieldSplitSetDMSplits - Flags whether DMCreateFieldDecomposition() should be used to define the splits, whenever possible. 1703 1704 Logically Collective 1705 1706 Input Parameters: 1707 + pc - the preconditioner context 1708 - flg - boolean indicating whether to use field splits defined by the DM 1709 1710 Options Database Key: 1711 . -pc_fieldsplit_dm_splits 1712 1713 Level: Intermediate 1714 1715 .keywords: PC, DM, composite preconditioner, additive, multiplicative 1716 1717 .seealso: PCFieldSplitGetDMSplits() 1718 1719 @*/ 1720 PetscErrorCode PCFieldSplitSetDMSplits(PC pc,PetscBool flg) 1721 { 1722 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 1723 PetscBool isfs; 1724 PetscErrorCode ierr; 1725 1726 PetscFunctionBegin; 1727 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1728 PetscValidLogicalCollectiveBool(pc,flg,2); 1729 ierr = PetscObjectTypeCompare((PetscObject)pc,PCFIELDSPLIT,&isfs);CHKERRQ(ierr); 1730 if (isfs) { 1731 jac->dm_splits = flg; 1732 } 1733 PetscFunctionReturn(0); 1734 } 1735 1736 1737 #undef __FUNCT__ 1738 #define __FUNCT__ "PCFieldSplitGetDMSplits" 1739 /*@ 1740 PCFieldSplitGetDMSplits - Returns flag indicating whether DMCreateFieldDecomposition() should be used to define the splits, whenever possible. 1741 1742 Logically Collective 1743 1744 Input Parameter: 1745 . pc - the preconditioner context 1746 1747 Output Parameter: 1748 . flg - boolean indicating whether to use field splits defined by the DM 1749 1750 Level: Intermediate 1751 1752 .keywords: PC, DM, composite preconditioner, additive, multiplicative 1753 1754 .seealso: PCFieldSplitSetDMSplits() 1755 1756 @*/ 1757 PetscErrorCode PCFieldSplitGetDMSplits(PC pc,PetscBool* flg) 1758 { 1759 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 1760 PetscBool isfs; 1761 PetscErrorCode ierr; 1762 1763 PetscFunctionBegin; 1764 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1765 PetscValidPointer(flg,2); 1766 ierr = PetscObjectTypeCompare((PetscObject)pc,PCFIELDSPLIT,&isfs);CHKERRQ(ierr); 1767 if (isfs) { 1768 if(flg) *flg = jac->dm_splits; 1769 } 1770 PetscFunctionReturn(0); 1771 } 1772 1773 /* -------------------------------------------------------------------------------------*/ 1774 /*MC 1775 PCFIELDSPLIT - Preconditioner created by combining separate preconditioners for individual 1776 fields or groups of fields. See the users manual section "Solving Block Matrices" for more details. 1777 1778 To set options on the solvers for each block append -fieldsplit_ to all the PC 1779 options database keys. For example, -fieldsplit_pc_type ilu -fieldsplit_pc_factor_levels 1 1780 1781 To set the options on the solvers separate for each block call PCFieldSplitGetSubKSP() 1782 and set the options directly on the resulting KSP object 1783 1784 Level: intermediate 1785 1786 Options Database Keys: 1787 + -pc_fieldsplit_%d_fields <a,b,..> - indicates the fields to be used in the %d'th split 1788 . -pc_fieldsplit_default - automatically add any fields to additional splits that have not 1789 been supplied explicitly by -pc_fieldsplit_%d_fields 1790 . -pc_fieldsplit_block_size <bs> - size of block that defines fields (i.e. there are bs fields) 1791 . -pc_fieldsplit_type <additive,multiplicative,symmetric_multiplicative,schur> - type of relaxation or factorization splitting 1792 . -pc_fieldsplit_schur_precondition <self,user,a11> - default is a11 1793 . -pc_fieldsplit_detect_saddle_point - automatically finds rows with zero or negative diagonal and uses Schur complement with no preconditioner as the solver 1794 1795 - Options prefix for inner solvers when using Schur complement preconditioner are -fieldsplit_0_ and -fieldsplit_1_ 1796 for all other solvers they are -fieldsplit_%d_ for the dth field, use -fieldsplit_ for all fields 1797 1798 Notes: 1799 Use PCFieldSplitSetFields() to set fields defined by "strided" entries and PCFieldSplitSetIS() 1800 to define a field by an arbitrary collection of entries. 1801 1802 If no fields are set the default is used. The fields are defined by entries strided by bs, 1803 beginning at 0 then 1, etc to bs-1. The block size can be set with PCFieldSplitSetBlockSize(), 1804 if this is not called the block size defaults to the blocksize of the second matrix passed 1805 to KSPSetOperators()/PCSetOperators(). 1806 1807 $ For the Schur complement preconditioner if J = ( A00 A01 ) 1808 $ ( A10 A11 ) 1809 $ the preconditioner using full factorization is 1810 $ ( I -A10 ksp(A00) ) ( inv(A00) 0 ) ( I 0 ) 1811 $ ( 0 I ) ( 0 ksp(S) ) ( -A10 ksp(A00) I ) 1812 where the action of inv(A00) is applied using the KSP solver with prefix -fieldsplit_0_. The action of 1813 ksp(S) is computed using the KSP solver with prefix -fieldsplit_splitname_ (where splitname was given 1814 in providing the SECOND split or 1 if not give). For PCFieldSplitGetKSP() when field number is 0, 1815 it returns the KSP associated with -fieldsplit_0_ while field number 1 gives -fieldsplit_1_ KSP. By default 1816 A11 is used to construct a preconditioner for S, use PCFieldSplitSchurPrecondition() to turn on or off this 1817 option. You can use the preconditioner PCLSC to precondition the Schur complement with -fieldsplit_1_pc_type lsc. The 1818 factorization type is set using -pc_fieldsplit_schur_fact_type <diag, lower, upper, full>. The full is shown above, 1819 diag gives 1820 $ ( inv(A00) 0 ) 1821 $ ( 0 -ksp(S) ) 1822 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 1823 $ ( A00 0 ) 1824 $ ( A10 S ) 1825 where the inverses of A00 and S are applied using KSPs. The upper factorization is the inverse of 1826 $ ( A00 A01 ) 1827 $ ( 0 S ) 1828 where again the inverses of A00 and S are applied using KSPs. 1829 1830 If only one set of indices (one IS) is provided with PCFieldSplitSetIS() then the complement of that IS 1831 is used automatically for a second block. 1832 1833 The fieldsplit preconditioner cannot currently be used with the BAIJ or SBAIJ data formats if the blocksize is larger than 1. 1834 Generally it should be used with the AIJ format. 1835 1836 The forms of these preconditioners are closely related if not identical to forms derived as "Distributive Iterations", see, 1837 for example, page 294 in "Principles of Computational Fluid Dynamics" by Pieter Wesseling. Note that one can also use PCFIELDSPLIT 1838 inside a smoother resulting in "Distributive Smoothers". 1839 1840 Concepts: physics based preconditioners, block preconditioners 1841 1842 .seealso: PCCreate(), PCSetType(), PCType (for list of available types), PC, Block_Preconditioners, PCLSC, 1843 PCFieldSplitGetSubKSP(), PCFieldSplitSetFields(), PCFieldSplitSetType(), PCFieldSplitSetIS(), PCFieldSplitSchurPrecondition() 1844 M*/ 1845 1846 EXTERN_C_BEGIN 1847 #undef __FUNCT__ 1848 #define __FUNCT__ "PCCreate_FieldSplit" 1849 PetscErrorCode PCCreate_FieldSplit(PC pc) 1850 { 1851 PetscErrorCode ierr; 1852 PC_FieldSplit *jac; 1853 1854 PetscFunctionBegin; 1855 ierr = PetscNewLog(pc,PC_FieldSplit,&jac);CHKERRQ(ierr); 1856 1857 jac->bs = -1; 1858 jac->nsplits = 0; 1859 jac->type = PC_COMPOSITE_MULTIPLICATIVE; 1860 jac->schurpre = PC_FIELDSPLIT_SCHUR_PRE_USER; /* Try user preconditioner first, fall back on diagonal */ 1861 jac->schurfactorization = PC_FIELDSPLIT_SCHUR_FACT_FULL; 1862 jac->dm_splits = PETSC_FALSE; 1863 1864 pc->data = (void*)jac; 1865 1866 pc->ops->apply = PCApply_FieldSplit; 1867 pc->ops->applytranspose = PCApplyTranspose_FieldSplit; 1868 pc->ops->setup = PCSetUp_FieldSplit; 1869 pc->ops->reset = PCReset_FieldSplit; 1870 pc->ops->destroy = PCDestroy_FieldSplit; 1871 pc->ops->setfromoptions = PCSetFromOptions_FieldSplit; 1872 pc->ops->view = PCView_FieldSplit; 1873 pc->ops->applyrichardson = 0; 1874 1875 ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitGetSubKSP_C","PCFieldSplitGetSubKSP_FieldSplit", 1876 PCFieldSplitGetSubKSP_FieldSplit);CHKERRQ(ierr); 1877 ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetFields_C","PCFieldSplitSetFields_FieldSplit", 1878 PCFieldSplitSetFields_FieldSplit);CHKERRQ(ierr); 1879 ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetIS_C","PCFieldSplitSetIS_FieldSplit", 1880 PCFieldSplitSetIS_FieldSplit);CHKERRQ(ierr); 1881 ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetType_C","PCFieldSplitSetType_FieldSplit", 1882 PCFieldSplitSetType_FieldSplit);CHKERRQ(ierr); 1883 ierr = PetscObjectComposeFunctionDynamic((PetscObject)pc,"PCFieldSplitSetBlockSize_C","PCFieldSplitSetBlockSize_FieldSplit", 1884 PCFieldSplitSetBlockSize_FieldSplit);CHKERRQ(ierr); 1885 PetscFunctionReturn(0); 1886 } 1887 EXTERN_C_END 1888 1889 1890 1891