1 2 3 #include <petsc/private/pcimpl.h> /*I "petscpc.h" I*/ 4 #include <petsc/private/kspimpl.h> /* This is needed to provide the appropriate PETSC_EXTERN for KSP_Solve_FS ....*/ 5 #include <petscdm.h> 6 7 const char *const PCFieldSplitSchurPreTypes[] = {"SELF","SELFP","A11","USER","FULL","PCFieldSplitSchurPreType","PC_FIELDSPLIT_SCHUR_PRE_",0}; 8 const char *const PCFieldSplitSchurFactTypes[] = {"DIAG","LOWER","UPPER","FULL","PCFieldSplitSchurFactType","PC_FIELDSPLIT_SCHUR_FACT_",0}; 9 10 PetscLogEvent KSP_Solve_FS_0,KSP_Solve_FS_1,KSP_Solve_FS_S,KSP_Solve_FS_U,KSP_Solve_FS_L,KSP_Solve_FS_2,KSP_Solve_FS_3,KSP_Solve_FS_4; 11 12 typedef struct _PC_FieldSplitLink *PC_FieldSplitLink; 13 struct _PC_FieldSplitLink { 14 KSP ksp; 15 Vec x,y,z; 16 char *splitname; 17 PetscInt nfields; 18 PetscInt *fields,*fields_col; 19 VecScatter sctx; 20 IS is,is_col; 21 PC_FieldSplitLink next,previous; 22 PetscLogEvent event; 23 }; 24 25 typedef struct { 26 PCCompositeType type; 27 PetscBool defaultsplit; /* Flag for a system with a set of 'k' scalar fields with the same layout (and bs = k) */ 28 PetscBool splitdefined; /* Flag is set after the splits have been defined, to prevent more splits from being added */ 29 PetscInt bs; /* Block size for IS and Mat structures */ 30 PetscInt nsplits; /* Number of field divisions defined */ 31 Vec *x,*y,w1,w2; 32 Mat *mat; /* The diagonal block for each split */ 33 Mat *pmat; /* The preconditioning diagonal block for each split */ 34 Mat *Afield; /* The rows of the matrix associated with each split */ 35 PetscBool issetup; 36 37 /* Only used when Schur complement preconditioning is used */ 38 Mat B; /* The (0,1) block */ 39 Mat C; /* The (1,0) block */ 40 Mat schur; /* The Schur complement S = A11 - A10 A00^{-1} A01, the KSP here, kspinner, is H_1 in [El08] */ 41 Mat schurp; /* Assembled approximation to S built by MatSchurComplement to be used as a preconditioning matrix when solving with S */ 42 Mat schur_user; /* User-provided preconditioning matrix for the Schur complement */ 43 PCFieldSplitSchurPreType schurpre; /* Determines which preconditioning matrix is used for the Schur complement */ 44 PCFieldSplitSchurFactType schurfactorization; 45 KSP kspschur; /* The solver for S */ 46 KSP kspupper; /* The solver for A in the upper diagonal part of the factorization (H_2 in [El08]) */ 47 PetscScalar schurscale; /* Scaling factor for the Schur complement solution with DIAG factorization */ 48 49 PC_FieldSplitLink head; 50 PetscBool isrestrict; /* indicates PCFieldSplitRestrictIS() has been last called on this object, hack */ 51 PetscBool suboptionsset; /* Indicates that the KSPSetFromOptions() has been called on the sub-KSPs */ 52 PetscBool dm_splits; /* Whether to use DMCreateFieldDecomposition() whenever possible */ 53 PetscBool diag_use_amat; /* Whether to extract diagonal matrix blocks from Amat, rather than Pmat (weaker than -pc_use_amat) */ 54 PetscBool offdiag_use_amat; /* Whether to extract off-diagonal matrix blocks from Amat, rather than Pmat (weaker than -pc_use_amat) */ 55 } PC_FieldSplit; 56 57 /* 58 Notes: there is no particular reason that pmat, x, and y are stored as arrays in PC_FieldSplit instead of 59 inside PC_FieldSplitLink, just historical. If you want to be able to add new fields after already using the 60 PC you could change this. 61 */ 62 63 /* This helper is so that setting a user-provided preconditioning matrix is orthogonal to choosing to use it. This way the 64 * application-provided FormJacobian can provide this matrix without interfering with the user's (command-line) choices. */ 65 static Mat FieldSplitSchurPre(PC_FieldSplit *jac) 66 { 67 switch (jac->schurpre) { 68 case PC_FIELDSPLIT_SCHUR_PRE_SELF: return jac->schur; 69 case PC_FIELDSPLIT_SCHUR_PRE_SELFP: return jac->schurp; 70 case PC_FIELDSPLIT_SCHUR_PRE_A11: return jac->pmat[1]; 71 case PC_FIELDSPLIT_SCHUR_PRE_FULL: /* We calculate this and store it in schur_user */ 72 case PC_FIELDSPLIT_SCHUR_PRE_USER: /* Use a user-provided matrix if it is given, otherwise diagonal block */ 73 default: 74 return jac->schur_user ? jac->schur_user : jac->pmat[1]; 75 } 76 } 77 78 79 #include <petscdraw.h> 80 static PetscErrorCode PCView_FieldSplit(PC pc,PetscViewer viewer) 81 { 82 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 83 PetscErrorCode ierr; 84 PetscBool iascii,isdraw; 85 PetscInt i,j; 86 PC_FieldSplitLink ilink = jac->head; 87 88 PetscFunctionBegin; 89 ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr); 90 ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERDRAW,&isdraw);CHKERRQ(ierr); 91 if (iascii) { 92 if (jac->bs > 0) { 93 ierr = PetscViewerASCIIPrintf(viewer," FieldSplit with %s composition: total splits = %D, blocksize = %D\n",PCCompositeTypes[jac->type],jac->nsplits,jac->bs);CHKERRQ(ierr); 94 } else { 95 ierr = PetscViewerASCIIPrintf(viewer," FieldSplit with %s composition: total splits = %D\n",PCCompositeTypes[jac->type],jac->nsplits);CHKERRQ(ierr); 96 } 97 if (pc->useAmat) { 98 ierr = PetscViewerASCIIPrintf(viewer," using Amat (not Pmat) as operator for blocks\n");CHKERRQ(ierr); 99 } 100 if (jac->diag_use_amat) { 101 ierr = PetscViewerASCIIPrintf(viewer," using Amat (not Pmat) as operator for diagonal blocks\n");CHKERRQ(ierr); 102 } 103 if (jac->offdiag_use_amat) { 104 ierr = PetscViewerASCIIPrintf(viewer," using Amat (not Pmat) as operator for off-diagonal blocks\n");CHKERRQ(ierr); 105 } 106 ierr = PetscViewerASCIIPrintf(viewer," Solver info for each split is in the following KSP objects:\n");CHKERRQ(ierr); 107 ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 108 for (i=0; i<jac->nsplits; i++) { 109 if (ilink->fields) { 110 ierr = PetscViewerASCIIPrintf(viewer,"Split number %D Fields ",i);CHKERRQ(ierr); 111 ierr = PetscViewerASCIIUseTabs(viewer,PETSC_FALSE);CHKERRQ(ierr); 112 for (j=0; j<ilink->nfields; j++) { 113 if (j > 0) { 114 ierr = PetscViewerASCIIPrintf(viewer,",");CHKERRQ(ierr); 115 } 116 ierr = PetscViewerASCIIPrintf(viewer," %D",ilink->fields[j]);CHKERRQ(ierr); 117 } 118 ierr = PetscViewerASCIIPrintf(viewer,"\n");CHKERRQ(ierr); 119 ierr = PetscViewerASCIIUseTabs(viewer,PETSC_TRUE);CHKERRQ(ierr); 120 } else { 121 ierr = PetscViewerASCIIPrintf(viewer,"Split number %D Defined by IS\n",i);CHKERRQ(ierr); 122 } 123 ierr = KSPView(ilink->ksp,viewer);CHKERRQ(ierr); 124 ilink = ilink->next; 125 } 126 ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 127 } 128 129 if (isdraw) { 130 PetscDraw draw; 131 PetscReal x,y,w,wd; 132 133 ierr = PetscViewerDrawGetDraw(viewer,0,&draw);CHKERRQ(ierr); 134 ierr = PetscDrawGetCurrentPoint(draw,&x,&y);CHKERRQ(ierr); 135 w = 2*PetscMin(1.0 - x,x); 136 wd = w/(jac->nsplits + 1); 137 x = x - wd*(jac->nsplits-1)/2.0; 138 for (i=0; i<jac->nsplits; i++) { 139 ierr = PetscDrawPushCurrentPoint(draw,x,y);CHKERRQ(ierr); 140 ierr = KSPView(ilink->ksp,viewer);CHKERRQ(ierr); 141 ierr = PetscDrawPopCurrentPoint(draw);CHKERRQ(ierr); 142 x += wd; 143 ilink = ilink->next; 144 } 145 } 146 PetscFunctionReturn(0); 147 } 148 149 static PetscErrorCode PCView_FieldSplit_Schur(PC pc,PetscViewer viewer) 150 { 151 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 152 PetscErrorCode ierr; 153 PetscBool iascii,isdraw; 154 PetscInt i,j; 155 PC_FieldSplitLink ilink = jac->head; 156 MatSchurComplementAinvType atype; 157 158 PetscFunctionBegin; 159 ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr); 160 ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERDRAW,&isdraw);CHKERRQ(ierr); 161 if (iascii) { 162 if (jac->bs > 0) { 163 ierr = PetscViewerASCIIPrintf(viewer," FieldSplit with Schur preconditioner, blocksize = %D, factorization %s\n",jac->bs,PCFieldSplitSchurFactTypes[jac->schurfactorization]);CHKERRQ(ierr); 164 } else { 165 ierr = PetscViewerASCIIPrintf(viewer," FieldSplit with Schur preconditioner, factorization %s\n",PCFieldSplitSchurFactTypes[jac->schurfactorization]);CHKERRQ(ierr); 166 } 167 if (pc->useAmat) { 168 ierr = PetscViewerASCIIPrintf(viewer," using Amat (not Pmat) as operator for blocks\n");CHKERRQ(ierr); 169 } 170 switch (jac->schurpre) { 171 case PC_FIELDSPLIT_SCHUR_PRE_SELF: 172 ierr = PetscViewerASCIIPrintf(viewer," Preconditioner for the Schur complement formed from S itself\n");CHKERRQ(ierr); 173 break; 174 case PC_FIELDSPLIT_SCHUR_PRE_SELFP: 175 ierr = MatSchurComplementGetAinvType(jac->schur,&atype);CHKERRQ(ierr); 176 ierr = PetscViewerASCIIPrintf(viewer," Preconditioner for the Schur complement formed from Sp, an assembled approximation to S, which uses A00's %sdiagonal's inverse\n",atype == MAT_SCHUR_COMPLEMENT_AINV_DIAG ? "" : (atype == MAT_SCHUR_COMPLEMENT_AINV_BLOCK_DIAG ? "block " : "lumped "));CHKERRQ(ierr);break; 177 case PC_FIELDSPLIT_SCHUR_PRE_A11: 178 ierr = PetscViewerASCIIPrintf(viewer," Preconditioner for the Schur complement formed from A11\n");CHKERRQ(ierr); 179 break; 180 case PC_FIELDSPLIT_SCHUR_PRE_FULL: 181 ierr = PetscViewerASCIIPrintf(viewer," Preconditioner for the Schur complement formed from the exact Schur complement\n");CHKERRQ(ierr); 182 break; 183 case PC_FIELDSPLIT_SCHUR_PRE_USER: 184 if (jac->schur_user) { 185 ierr = PetscViewerASCIIPrintf(viewer," Preconditioner for the Schur complement formed from user provided matrix\n");CHKERRQ(ierr); 186 } else { 187 ierr = PetscViewerASCIIPrintf(viewer," Preconditioner for the Schur complement formed from A11\n");CHKERRQ(ierr); 188 } 189 break; 190 default: 191 SETERRQ1(PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Invalid Schur preconditioning type: %d", jac->schurpre); 192 } 193 ierr = PetscViewerASCIIPrintf(viewer," Split info:\n");CHKERRQ(ierr); 194 ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 195 for (i=0; i<jac->nsplits; i++) { 196 if (ilink->fields) { 197 ierr = PetscViewerASCIIPrintf(viewer,"Split number %D Fields ",i);CHKERRQ(ierr); 198 ierr = PetscViewerASCIIUseTabs(viewer,PETSC_FALSE);CHKERRQ(ierr); 199 for (j=0; j<ilink->nfields; j++) { 200 if (j > 0) { 201 ierr = PetscViewerASCIIPrintf(viewer,",");CHKERRQ(ierr); 202 } 203 ierr = PetscViewerASCIIPrintf(viewer," %D",ilink->fields[j]);CHKERRQ(ierr); 204 } 205 ierr = PetscViewerASCIIPrintf(viewer,"\n");CHKERRQ(ierr); 206 ierr = PetscViewerASCIIUseTabs(viewer,PETSC_TRUE);CHKERRQ(ierr); 207 } else { 208 ierr = PetscViewerASCIIPrintf(viewer,"Split number %D Defined by IS\n",i);CHKERRQ(ierr); 209 } 210 ilink = ilink->next; 211 } 212 ierr = PetscViewerASCIIPrintf(viewer,"KSP solver for A00 block\n");CHKERRQ(ierr); 213 ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 214 if (jac->head) { 215 ierr = KSPView(jac->head->ksp,viewer);CHKERRQ(ierr); 216 } else {ierr = PetscViewerASCIIPrintf(viewer," not yet available\n");CHKERRQ(ierr);} 217 ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 218 if (jac->head && jac->kspupper != jac->head->ksp) { 219 ierr = PetscViewerASCIIPrintf(viewer,"KSP solver for upper A00 in upper triangular factor \n");CHKERRQ(ierr); 220 ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 221 if (jac->kspupper) {ierr = KSPView(jac->kspupper,viewer);CHKERRQ(ierr);} 222 else {ierr = PetscViewerASCIIPrintf(viewer," not yet available\n");CHKERRQ(ierr);} 223 ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 224 } 225 ierr = PetscViewerASCIIPrintf(viewer,"KSP solver for S = A11 - A10 inv(A00) A01 \n");CHKERRQ(ierr); 226 ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 227 if (jac->kspschur) { 228 ierr = KSPView(jac->kspschur,viewer);CHKERRQ(ierr); 229 } else { 230 ierr = PetscViewerASCIIPrintf(viewer," not yet available\n");CHKERRQ(ierr); 231 } 232 ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 233 ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 234 } else if (isdraw && jac->head) { 235 PetscDraw draw; 236 PetscReal x,y,w,wd,h; 237 PetscInt cnt = 2; 238 char str[32]; 239 240 ierr = PetscViewerDrawGetDraw(viewer,0,&draw);CHKERRQ(ierr); 241 ierr = PetscDrawGetCurrentPoint(draw,&x,&y);CHKERRQ(ierr); 242 if (jac->kspupper != jac->head->ksp) cnt++; 243 w = 2*PetscMin(1.0 - x,x); 244 wd = w/(cnt + 1); 245 246 ierr = PetscSNPrintf(str,32,"Schur fact. %s",PCFieldSplitSchurFactTypes[jac->schurfactorization]);CHKERRQ(ierr); 247 ierr = PetscDrawStringBoxed(draw,x,y,PETSC_DRAW_RED,PETSC_DRAW_BLACK,str,NULL,&h);CHKERRQ(ierr); 248 y -= h; 249 if (jac->schurpre == PC_FIELDSPLIT_SCHUR_PRE_USER && !jac->schur_user) { 250 ierr = PetscSNPrintf(str,32,"Prec. for Schur from %s",PCFieldSplitSchurPreTypes[PC_FIELDSPLIT_SCHUR_PRE_A11]);CHKERRQ(ierr); 251 } else { 252 ierr = PetscSNPrintf(str,32,"Prec. for Schur from %s",PCFieldSplitSchurPreTypes[jac->schurpre]);CHKERRQ(ierr); 253 } 254 ierr = PetscDrawStringBoxed(draw,x+wd*(cnt-1)/2.0,y,PETSC_DRAW_RED,PETSC_DRAW_BLACK,str,NULL,&h);CHKERRQ(ierr); 255 y -= h; 256 x = x - wd*(cnt-1)/2.0; 257 258 ierr = PetscDrawPushCurrentPoint(draw,x,y);CHKERRQ(ierr); 259 ierr = KSPView(jac->head->ksp,viewer);CHKERRQ(ierr); 260 ierr = PetscDrawPopCurrentPoint(draw);CHKERRQ(ierr); 261 if (jac->kspupper != jac->head->ksp) { 262 x += wd; 263 ierr = PetscDrawPushCurrentPoint(draw,x,y);CHKERRQ(ierr); 264 ierr = KSPView(jac->kspupper,viewer);CHKERRQ(ierr); 265 ierr = PetscDrawPopCurrentPoint(draw);CHKERRQ(ierr); 266 } 267 x += wd; 268 ierr = PetscDrawPushCurrentPoint(draw,x,y);CHKERRQ(ierr); 269 ierr = KSPView(jac->kspschur,viewer);CHKERRQ(ierr); 270 ierr = PetscDrawPopCurrentPoint(draw);CHKERRQ(ierr); 271 } 272 PetscFunctionReturn(0); 273 } 274 275 /* Precondition: jac->bs is set to a meaningful value */ 276 static PetscErrorCode PCFieldSplitSetRuntimeSplits_Private(PC pc) 277 { 278 PetscErrorCode ierr; 279 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 280 PetscInt i,nfields,*ifields,nfields_col,*ifields_col; 281 PetscBool flg,flg_col; 282 char optionname[128],splitname[8],optionname_col[128]; 283 284 PetscFunctionBegin; 285 ierr = PetscMalloc1(jac->bs,&ifields);CHKERRQ(ierr); 286 ierr = PetscMalloc1(jac->bs,&ifields_col);CHKERRQ(ierr); 287 for (i=0,flg=PETSC_TRUE;; i++) { 288 ierr = PetscSNPrintf(splitname,sizeof(splitname),"%D",i);CHKERRQ(ierr); 289 ierr = PetscSNPrintf(optionname,sizeof(optionname),"-pc_fieldsplit_%D_fields",i);CHKERRQ(ierr); 290 ierr = PetscSNPrintf(optionname_col,sizeof(optionname_col),"-pc_fieldsplit_%D_fields_col",i);CHKERRQ(ierr); 291 nfields = jac->bs; 292 nfields_col = jac->bs; 293 ierr = PetscOptionsGetIntArray(((PetscObject)pc)->options,((PetscObject)pc)->prefix,optionname,ifields,&nfields,&flg);CHKERRQ(ierr); 294 ierr = PetscOptionsGetIntArray(((PetscObject)pc)->options,((PetscObject)pc)->prefix,optionname_col,ifields_col,&nfields_col,&flg_col);CHKERRQ(ierr); 295 if (!flg) break; 296 else if (flg && !flg_col) { 297 if (!nfields) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Cannot list zero fields"); 298 ierr = PCFieldSplitSetFields(pc,splitname,nfields,ifields,ifields);CHKERRQ(ierr); 299 } else { 300 if (!nfields || !nfields_col) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Cannot list zero fields"); 301 if (nfields != nfields_col) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Number of row and column fields must match"); 302 ierr = PCFieldSplitSetFields(pc,splitname,nfields,ifields,ifields_col);CHKERRQ(ierr); 303 } 304 } 305 if (i > 0) { 306 /* Makes command-line setting of splits take precedence over setting them in code. 307 Otherwise subsequent calls to PCFieldSplitSetIS() or PCFieldSplitSetFields() would 308 create new splits, which would probably not be what the user wanted. */ 309 jac->splitdefined = PETSC_TRUE; 310 } 311 ierr = PetscFree(ifields);CHKERRQ(ierr); 312 ierr = PetscFree(ifields_col);CHKERRQ(ierr); 313 PetscFunctionReturn(0); 314 } 315 316 static PetscErrorCode PCFieldSplitSetDefaults(PC pc) 317 { 318 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 319 PetscErrorCode ierr; 320 PC_FieldSplitLink ilink = jac->head; 321 PetscBool fieldsplit_default = PETSC_FALSE,stokes = PETSC_FALSE,coupling = PETSC_FALSE; 322 PetscInt i; 323 324 PetscFunctionBegin; 325 /* 326 Kinda messy, but at least this now uses DMCreateFieldDecomposition(). 327 Should probably be rewritten. 328 */ 329 if (!ilink) { 330 ierr = PetscOptionsGetBool(((PetscObject)pc)->options,((PetscObject)pc)->prefix,"-pc_fieldsplit_detect_saddle_point",&stokes,NULL);CHKERRQ(ierr); 331 ierr = PetscOptionsGetBool(((PetscObject)pc)->options,((PetscObject)pc)->prefix,"-pc_fieldsplit_detect_coupling",&coupling,NULL);CHKERRQ(ierr); 332 if (pc->dm && jac->dm_splits && !stokes && !coupling) { 333 PetscInt numFields, f, i, j; 334 char **fieldNames; 335 IS *fields; 336 DM *dms; 337 DM subdm[128]; 338 PetscBool flg; 339 340 ierr = DMCreateFieldDecomposition(pc->dm, &numFields, &fieldNames, &fields, &dms);CHKERRQ(ierr); 341 /* Allow the user to prescribe the splits */ 342 for (i = 0, flg = PETSC_TRUE;; i++) { 343 PetscInt ifields[128]; 344 IS compField; 345 char optionname[128], splitname[8]; 346 PetscInt nfields = numFields; 347 348 ierr = PetscSNPrintf(optionname, sizeof(optionname), "-pc_fieldsplit_%D_fields", i);CHKERRQ(ierr); 349 ierr = PetscOptionsGetIntArray(((PetscObject)pc)->options,((PetscObject)pc)->prefix, optionname, ifields, &nfields, &flg);CHKERRQ(ierr); 350 if (!flg) break; 351 if (numFields > 128) SETERRQ1(PetscObjectComm((PetscObject)pc),PETSC_ERR_SUP,"Cannot currently support %d > 128 fields", numFields); 352 ierr = DMCreateSubDM(pc->dm, nfields, ifields, &compField, &subdm[i]);CHKERRQ(ierr); 353 if (nfields == 1) { 354 ierr = PCFieldSplitSetIS(pc, fieldNames[ifields[0]], compField);CHKERRQ(ierr); 355 } else { 356 ierr = PetscSNPrintf(splitname, sizeof(splitname), "%D", i);CHKERRQ(ierr); 357 ierr = PCFieldSplitSetIS(pc, splitname, compField);CHKERRQ(ierr); 358 } 359 ierr = ISDestroy(&compField);CHKERRQ(ierr); 360 for (j = 0; j < nfields; ++j) { 361 f = ifields[j]; 362 ierr = PetscFree(fieldNames[f]);CHKERRQ(ierr); 363 ierr = ISDestroy(&fields[f]);CHKERRQ(ierr); 364 } 365 } 366 if (i == 0) { 367 for (f = 0; f < numFields; ++f) { 368 ierr = PCFieldSplitSetIS(pc, fieldNames[f], fields[f]);CHKERRQ(ierr); 369 ierr = PetscFree(fieldNames[f]);CHKERRQ(ierr); 370 ierr = ISDestroy(&fields[f]);CHKERRQ(ierr); 371 } 372 } else { 373 for (j=0; j<numFields; j++) { 374 ierr = DMDestroy(dms+j);CHKERRQ(ierr); 375 } 376 ierr = PetscFree(dms);CHKERRQ(ierr); 377 ierr = PetscMalloc1(i, &dms);CHKERRQ(ierr); 378 for (j = 0; j < i; ++j) dms[j] = subdm[j]; 379 } 380 ierr = PetscFree(fieldNames);CHKERRQ(ierr); 381 ierr = PetscFree(fields);CHKERRQ(ierr); 382 if (dms) { 383 ierr = PetscInfo(pc, "Setting up physics based fieldsplit preconditioner using the embedded DM\n");CHKERRQ(ierr); 384 for (ilink = jac->head, i = 0; ilink; ilink = ilink->next, ++i) { 385 const char *prefix; 386 ierr = PetscObjectGetOptionsPrefix((PetscObject)(ilink->ksp),&prefix);CHKERRQ(ierr); 387 ierr = PetscObjectSetOptionsPrefix((PetscObject)(dms[i]), prefix);CHKERRQ(ierr); 388 ierr = KSPSetDM(ilink->ksp, dms[i]);CHKERRQ(ierr); 389 ierr = KSPSetDMActive(ilink->ksp, PETSC_FALSE);CHKERRQ(ierr); 390 ierr = PetscObjectIncrementTabLevel((PetscObject)dms[i],(PetscObject)ilink->ksp,0);CHKERRQ(ierr); 391 ierr = DMDestroy(&dms[i]);CHKERRQ(ierr); 392 } 393 ierr = PetscFree(dms);CHKERRQ(ierr); 394 } 395 } else { 396 if (jac->bs <= 0) { 397 if (pc->pmat) { 398 ierr = MatGetBlockSize(pc->pmat,&jac->bs);CHKERRQ(ierr); 399 } else jac->bs = 1; 400 } 401 402 if (stokes) { 403 IS zerodiags,rest; 404 PetscInt nmin,nmax; 405 406 ierr = MatGetOwnershipRange(pc->mat,&nmin,&nmax);CHKERRQ(ierr); 407 ierr = MatFindZeroDiagonals(pc->mat,&zerodiags);CHKERRQ(ierr); 408 ierr = ISComplement(zerodiags,nmin,nmax,&rest);CHKERRQ(ierr); 409 ierr = PCFieldSplitSetIS(pc,"0",rest);CHKERRQ(ierr); 410 ierr = PCFieldSplitSetIS(pc,"1",zerodiags);CHKERRQ(ierr); 411 ierr = ISDestroy(&zerodiags);CHKERRQ(ierr); 412 ierr = ISDestroy(&rest);CHKERRQ(ierr); 413 } else if (coupling) { 414 IS coupling,rest; 415 PetscInt nmin,nmax; 416 417 ierr = MatGetOwnershipRange(pc->mat,&nmin,&nmax);CHKERRQ(ierr); 418 ierr = MatFindOffBlockDiagonalEntries(pc->mat,&coupling);CHKERRQ(ierr); 419 ierr = ISCreateStride(PetscObjectComm((PetscObject)pc->mat),nmax-nmin,nmin,1,&rest);CHKERRQ(ierr); 420 ierr = ISSetIdentity(rest);CHKERRQ(ierr); 421 ierr = PCFieldSplitSetIS(pc,"0",rest);CHKERRQ(ierr); 422 ierr = PCFieldSplitSetIS(pc,"1",coupling);CHKERRQ(ierr); 423 ierr = ISDestroy(&coupling);CHKERRQ(ierr); 424 ierr = ISDestroy(&rest);CHKERRQ(ierr); 425 } else { 426 ierr = PetscOptionsGetBool(((PetscObject)pc)->options,((PetscObject)pc)->prefix,"-pc_fieldsplit_default",&fieldsplit_default,NULL);CHKERRQ(ierr); 427 if (!fieldsplit_default) { 428 /* Allow user to set fields from command line, if bs was known at the time of PCSetFromOptions_FieldSplit() 429 then it is set there. This is not ideal because we should only have options set in XXSetFromOptions(). */ 430 ierr = PCFieldSplitSetRuntimeSplits_Private(pc);CHKERRQ(ierr); 431 if (jac->splitdefined) {ierr = PetscInfo(pc,"Splits defined using the options database\n");CHKERRQ(ierr);} 432 } 433 if ((fieldsplit_default || !jac->splitdefined) && !jac->isrestrict) { 434 ierr = PetscInfo(pc,"Using default splitting of fields\n");CHKERRQ(ierr); 435 for (i=0; i<jac->bs; i++) { 436 char splitname[8]; 437 ierr = PetscSNPrintf(splitname,sizeof(splitname),"%D",i);CHKERRQ(ierr); 438 ierr = PCFieldSplitSetFields(pc,splitname,1,&i,&i);CHKERRQ(ierr); 439 } 440 jac->defaultsplit = PETSC_TRUE; 441 } 442 } 443 } 444 } else if (jac->nsplits == 1) { 445 if (ilink->is) { 446 IS is2; 447 PetscInt nmin,nmax; 448 449 ierr = MatGetOwnershipRange(pc->mat,&nmin,&nmax);CHKERRQ(ierr); 450 ierr = ISComplement(ilink->is,nmin,nmax,&is2);CHKERRQ(ierr); 451 ierr = PCFieldSplitSetIS(pc,"1",is2);CHKERRQ(ierr); 452 ierr = ISDestroy(&is2);CHKERRQ(ierr); 453 } else SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_SUP,"Must provide at least two sets of fields to PCFieldSplit()"); 454 } 455 456 if (jac->nsplits < 2) SETERRQ1(PetscObjectComm((PetscObject)pc),PETSC_ERR_PLIB,"Unhandled case, must have at least two fields, not %d", jac->nsplits); 457 PetscFunctionReturn(0); 458 } 459 460 PETSC_EXTERN PetscErrorCode PetscOptionsFindPairPrefix_Private(PetscOptions,const char pre[], const char name[], char *value[], PetscBool *flg); 461 462 static PetscErrorCode PCSetUp_FieldSplit(PC pc) 463 { 464 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 465 PetscErrorCode ierr; 466 PC_FieldSplitLink ilink; 467 PetscInt i,nsplit; 468 PetscBool sorted, sorted_col; 469 470 PetscFunctionBegin; 471 ierr = PCFieldSplitSetDefaults(pc);CHKERRQ(ierr); 472 nsplit = jac->nsplits; 473 ilink = jac->head; 474 475 /* get the matrices for each split */ 476 if (!jac->issetup) { 477 PetscInt rstart,rend,nslots,bs; 478 479 jac->issetup = PETSC_TRUE; 480 481 /* This is done here instead of in PCFieldSplitSetFields() because may not have matrix at that point */ 482 if (jac->defaultsplit || !ilink->is) { 483 if (jac->bs <= 0) jac->bs = nsplit; 484 } 485 bs = jac->bs; 486 ierr = MatGetOwnershipRange(pc->pmat,&rstart,&rend);CHKERRQ(ierr); 487 nslots = (rend - rstart)/bs; 488 for (i=0; i<nsplit; i++) { 489 if (jac->defaultsplit) { 490 ierr = ISCreateStride(PetscObjectComm((PetscObject)pc),nslots,rstart+i,nsplit,&ilink->is);CHKERRQ(ierr); 491 ierr = ISDuplicate(ilink->is,&ilink->is_col);CHKERRQ(ierr); 492 } else if (!ilink->is) { 493 if (ilink->nfields > 1) { 494 PetscInt *ii,*jj,j,k,nfields = ilink->nfields,*fields = ilink->fields,*fields_col = ilink->fields_col; 495 ierr = PetscMalloc1(ilink->nfields*nslots,&ii);CHKERRQ(ierr); 496 ierr = PetscMalloc1(ilink->nfields*nslots,&jj);CHKERRQ(ierr); 497 for (j=0; j<nslots; j++) { 498 for (k=0; k<nfields; k++) { 499 ii[nfields*j + k] = rstart + bs*j + fields[k]; 500 jj[nfields*j + k] = rstart + bs*j + fields_col[k]; 501 } 502 } 503 ierr = ISCreateGeneral(PetscObjectComm((PetscObject)pc),nslots*nfields,ii,PETSC_OWN_POINTER,&ilink->is);CHKERRQ(ierr); 504 ierr = ISCreateGeneral(PetscObjectComm((PetscObject)pc),nslots*nfields,jj,PETSC_OWN_POINTER,&ilink->is_col);CHKERRQ(ierr); 505 ierr = ISSetBlockSize(ilink->is, nfields);CHKERRQ(ierr); 506 ierr = ISSetBlockSize(ilink->is_col, nfields);CHKERRQ(ierr); 507 } else { 508 ierr = ISCreateStride(PetscObjectComm((PetscObject)pc),nslots,rstart+ilink->fields[0],bs,&ilink->is);CHKERRQ(ierr); 509 ierr = ISCreateStride(PetscObjectComm((PetscObject)pc),nslots,rstart+ilink->fields_col[0],bs,&ilink->is_col);CHKERRQ(ierr); 510 } 511 } 512 ierr = ISSorted(ilink->is,&sorted);CHKERRQ(ierr); 513 if (ilink->is_col) { ierr = ISSorted(ilink->is_col,&sorted_col);CHKERRQ(ierr); } 514 if (!sorted || !sorted_col) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Fields must be sorted when creating split"); 515 ilink = ilink->next; 516 } 517 } 518 519 ilink = jac->head; 520 if (!jac->pmat) { 521 Vec xtmp; 522 523 ierr = MatCreateVecs(pc->pmat,&xtmp,NULL);CHKERRQ(ierr); 524 ierr = PetscMalloc1(nsplit,&jac->pmat);CHKERRQ(ierr); 525 ierr = PetscMalloc2(nsplit,&jac->x,nsplit,&jac->y);CHKERRQ(ierr); 526 for (i=0; i<nsplit; i++) { 527 MatNullSpace sp; 528 529 /* Check for preconditioning matrix attached to IS */ 530 ierr = PetscObjectQuery((PetscObject) ilink->is, "pmat", (PetscObject*) &jac->pmat[i]);CHKERRQ(ierr); 531 if (jac->pmat[i]) { 532 ierr = PetscObjectReference((PetscObject) jac->pmat[i]);CHKERRQ(ierr); 533 if (jac->type == PC_COMPOSITE_SCHUR) { 534 jac->schur_user = jac->pmat[i]; 535 536 ierr = PetscObjectReference((PetscObject) jac->schur_user);CHKERRQ(ierr); 537 } 538 } else { 539 const char *prefix; 540 ierr = MatCreateSubMatrix(pc->pmat,ilink->is,ilink->is_col,MAT_INITIAL_MATRIX,&jac->pmat[i]);CHKERRQ(ierr); 541 ierr = KSPGetOptionsPrefix(ilink->ksp,&prefix);CHKERRQ(ierr); 542 ierr = MatSetOptionsPrefix(jac->pmat[i],prefix);CHKERRQ(ierr); 543 ierr = MatViewFromOptions(jac->pmat[i],NULL,"-mat_view");CHKERRQ(ierr); 544 } 545 /* create work vectors for each split */ 546 ierr = MatCreateVecs(jac->pmat[i],&jac->x[i],&jac->y[i]);CHKERRQ(ierr); 547 ilink->x = jac->x[i]; ilink->y = jac->y[i]; ilink->z = NULL; 548 /* compute scatter contexts needed by multiplicative versions and non-default splits */ 549 ierr = VecScatterCreate(xtmp,ilink->is,jac->x[i],NULL,&ilink->sctx);CHKERRQ(ierr); 550 ierr = PetscObjectQuery((PetscObject) ilink->is, "nearnullspace", (PetscObject*) &sp);CHKERRQ(ierr); 551 if (sp) { 552 ierr = MatSetNearNullSpace(jac->pmat[i], sp);CHKERRQ(ierr); 553 } 554 ilink = ilink->next; 555 } 556 ierr = VecDestroy(&xtmp);CHKERRQ(ierr); 557 } else { 558 for (i=0; i<nsplit; i++) { 559 Mat pmat; 560 561 /* Check for preconditioning matrix attached to IS */ 562 ierr = PetscObjectQuery((PetscObject) ilink->is, "pmat", (PetscObject*) &pmat);CHKERRQ(ierr); 563 if (!pmat) { 564 ierr = MatCreateSubMatrix(pc->pmat,ilink->is,ilink->is_col,MAT_REUSE_MATRIX,&jac->pmat[i]);CHKERRQ(ierr); 565 } 566 ilink = ilink->next; 567 } 568 } 569 if (jac->diag_use_amat) { 570 ilink = jac->head; 571 if (!jac->mat) { 572 ierr = PetscMalloc1(nsplit,&jac->mat);CHKERRQ(ierr); 573 for (i=0; i<nsplit; i++) { 574 ierr = MatCreateSubMatrix(pc->mat,ilink->is,ilink->is_col,MAT_INITIAL_MATRIX,&jac->mat[i]);CHKERRQ(ierr); 575 ilink = ilink->next; 576 } 577 } else { 578 for (i=0; i<nsplit; i++) { 579 if (jac->mat[i]) {ierr = MatCreateSubMatrix(pc->mat,ilink->is,ilink->is_col,MAT_REUSE_MATRIX,&jac->mat[i]);CHKERRQ(ierr);} 580 ilink = ilink->next; 581 } 582 } 583 } else { 584 jac->mat = jac->pmat; 585 } 586 587 /* Check for null space attached to IS */ 588 ilink = jac->head; 589 for (i=0; i<nsplit; i++) { 590 MatNullSpace sp; 591 592 ierr = PetscObjectQuery((PetscObject) ilink->is, "nullspace", (PetscObject*) &sp);CHKERRQ(ierr); 593 if (sp) { 594 ierr = MatSetNullSpace(jac->mat[i], sp);CHKERRQ(ierr); 595 } 596 ilink = ilink->next; 597 } 598 599 if (jac->type != PC_COMPOSITE_ADDITIVE && jac->type != PC_COMPOSITE_SCHUR) { 600 /* extract the rows of the matrix associated with each field: used for efficient computation of residual inside algorithm */ 601 /* FIXME: Can/should we reuse jac->mat whenever (jac->diag_use_amat) is true? */ 602 ilink = jac->head; 603 if (nsplit == 2 && jac->type == PC_COMPOSITE_MULTIPLICATIVE) { 604 /* special case need where Afield[0] is not needed and only certain columns of Afield[1] are needed since update is only on those rows of the solution */ 605 if (!jac->Afield) { 606 ierr = PetscCalloc1(nsplit,&jac->Afield);CHKERRQ(ierr); 607 if (jac->offdiag_use_amat) { 608 ierr = MatCreateSubMatrix(pc->mat,ilink->next->is,ilink->is,MAT_INITIAL_MATRIX,&jac->Afield[1]);CHKERRQ(ierr); 609 } else { 610 ierr = MatCreateSubMatrix(pc->pmat,ilink->next->is,ilink->is,MAT_INITIAL_MATRIX,&jac->Afield[1]);CHKERRQ(ierr); 611 } 612 } else { 613 if (jac->offdiag_use_amat) { 614 ierr = MatCreateSubMatrix(pc->mat,ilink->next->is,ilink->is,MAT_REUSE_MATRIX,&jac->Afield[1]);CHKERRQ(ierr); 615 } else { 616 ierr = MatCreateSubMatrix(pc->pmat,ilink->next->is,ilink->is,MAT_REUSE_MATRIX,&jac->Afield[1]);CHKERRQ(ierr); 617 } 618 } 619 } else { 620 if (!jac->Afield) { 621 ierr = PetscMalloc1(nsplit,&jac->Afield);CHKERRQ(ierr); 622 for (i=0; i<nsplit; i++) { 623 if (jac->offdiag_use_amat) { 624 ierr = MatCreateSubMatrix(pc->mat,ilink->is,NULL,MAT_INITIAL_MATRIX,&jac->Afield[i]);CHKERRQ(ierr); 625 } else { 626 ierr = MatCreateSubMatrix(pc->pmat,ilink->is,NULL,MAT_INITIAL_MATRIX,&jac->Afield[i]);CHKERRQ(ierr); 627 } 628 ilink = ilink->next; 629 } 630 } else { 631 for (i=0; i<nsplit; i++) { 632 if (jac->offdiag_use_amat) { 633 ierr = MatCreateSubMatrix(pc->mat,ilink->is,NULL,MAT_REUSE_MATRIX,&jac->Afield[i]);CHKERRQ(ierr); 634 } else { 635 ierr = MatCreateSubMatrix(pc->pmat,ilink->is,NULL,MAT_REUSE_MATRIX,&jac->Afield[i]);CHKERRQ(ierr); 636 } 637 ilink = ilink->next; 638 } 639 } 640 } 641 } 642 643 if (jac->type == PC_COMPOSITE_SCHUR) { 644 IS ccis; 645 PetscBool isspd; 646 PetscInt rstart,rend; 647 char lscname[256]; 648 PetscObject LSC_L; 649 650 if (nsplit != 2) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_INCOMP,"To use Schur complement preconditioner you must have exactly 2 fields"); 651 652 /* If pc->mat is SPD, don't scale by -1 the Schur complement */ 653 if (jac->schurscale == (PetscScalar)-1.0) { 654 ierr = MatGetOption(pc->pmat,MAT_SPD,&isspd);CHKERRQ(ierr); 655 jac->schurscale = (isspd == PETSC_TRUE) ? 1.0 : -1.0; 656 } 657 658 /* When extracting off-diagonal submatrices, we take complements from this range */ 659 ierr = MatGetOwnershipRangeColumn(pc->mat,&rstart,&rend);CHKERRQ(ierr); 660 661 /* need to handle case when one is resetting up the preconditioner */ 662 if (jac->schur) { 663 KSP kspA = jac->head->ksp, kspInner = NULL, kspUpper = jac->kspupper; 664 665 ierr = MatSchurComplementGetKSP(jac->schur, &kspInner);CHKERRQ(ierr); 666 ilink = jac->head; 667 ierr = ISComplement(ilink->is_col,rstart,rend,&ccis);CHKERRQ(ierr); 668 if (jac->offdiag_use_amat) { 669 ierr = MatCreateSubMatrix(pc->mat,ilink->is,ccis,MAT_REUSE_MATRIX,&jac->B);CHKERRQ(ierr); 670 } else { 671 ierr = MatCreateSubMatrix(pc->pmat,ilink->is,ccis,MAT_REUSE_MATRIX,&jac->B);CHKERRQ(ierr); 672 } 673 ierr = ISDestroy(&ccis);CHKERRQ(ierr); 674 ilink = ilink->next; 675 ierr = ISComplement(ilink->is_col,rstart,rend,&ccis);CHKERRQ(ierr); 676 if (jac->offdiag_use_amat) { 677 ierr = MatCreateSubMatrix(pc->mat,ilink->is,ccis,MAT_REUSE_MATRIX,&jac->C);CHKERRQ(ierr); 678 } else { 679 ierr = MatCreateSubMatrix(pc->pmat,ilink->is,ccis,MAT_REUSE_MATRIX,&jac->C);CHKERRQ(ierr); 680 } 681 ierr = ISDestroy(&ccis);CHKERRQ(ierr); 682 ierr = MatSchurComplementUpdateSubMatrices(jac->schur,jac->mat[0],jac->pmat[0],jac->B,jac->C,jac->mat[1]);CHKERRQ(ierr); 683 if (jac->schurpre == PC_FIELDSPLIT_SCHUR_PRE_SELFP) { 684 ierr = MatDestroy(&jac->schurp);CHKERRQ(ierr); 685 ierr = MatSchurComplementGetPmat(jac->schur,MAT_INITIAL_MATRIX,&jac->schurp);CHKERRQ(ierr); 686 } 687 if (kspA != kspInner) { 688 ierr = KSPSetOperators(kspA,jac->mat[0],jac->pmat[0]);CHKERRQ(ierr); 689 } 690 if (kspUpper != kspA) { 691 ierr = KSPSetOperators(kspUpper,jac->mat[0],jac->pmat[0]);CHKERRQ(ierr); 692 } 693 ierr = KSPSetOperators(jac->kspschur,jac->schur,FieldSplitSchurPre(jac));CHKERRQ(ierr); 694 } else { 695 const char *Dprefix; 696 char schurprefix[256], schurmatprefix[256]; 697 char schurtestoption[256]; 698 MatNullSpace sp; 699 PetscBool flg; 700 701 /* extract the A01 and A10 matrices */ 702 ilink = jac->head; 703 ierr = ISComplement(ilink->is_col,rstart,rend,&ccis);CHKERRQ(ierr); 704 if (jac->offdiag_use_amat) { 705 ierr = MatCreateSubMatrix(pc->mat,ilink->is,ccis,MAT_INITIAL_MATRIX,&jac->B);CHKERRQ(ierr); 706 } else { 707 ierr = MatCreateSubMatrix(pc->pmat,ilink->is,ccis,MAT_INITIAL_MATRIX,&jac->B);CHKERRQ(ierr); 708 } 709 ierr = ISDestroy(&ccis);CHKERRQ(ierr); 710 ilink = ilink->next; 711 ierr = ISComplement(ilink->is_col,rstart,rend,&ccis);CHKERRQ(ierr); 712 if (jac->offdiag_use_amat) { 713 ierr = MatCreateSubMatrix(pc->mat,ilink->is,ccis,MAT_INITIAL_MATRIX,&jac->C);CHKERRQ(ierr); 714 } else { 715 ierr = MatCreateSubMatrix(pc->pmat,ilink->is,ccis,MAT_INITIAL_MATRIX,&jac->C);CHKERRQ(ierr); 716 } 717 ierr = ISDestroy(&ccis);CHKERRQ(ierr); 718 719 /* Use mat[0] (diagonal block of Amat) preconditioned by pmat[0] to define Schur complement */ 720 ierr = MatCreate(((PetscObject)jac->mat[0])->comm,&jac->schur);CHKERRQ(ierr); 721 ierr = MatSetType(jac->schur,MATSCHURCOMPLEMENT);CHKERRQ(ierr); 722 ierr = MatSchurComplementSetSubMatrices(jac->schur,jac->mat[0],jac->pmat[0],jac->B,jac->C,jac->mat[1]);CHKERRQ(ierr); 723 ierr = PetscSNPrintf(schurmatprefix, sizeof(schurmatprefix), "%sfieldsplit_%s_", ((PetscObject)pc)->prefix ? ((PetscObject)pc)->prefix : "", ilink->splitname);CHKERRQ(ierr); 724 /* Note that the inner KSP is NOT going to inherit this prefix, and if it did, it would be reset just below. Is that what we want? */ 725 ierr = MatSetOptionsPrefix(jac->schur,schurmatprefix);CHKERRQ(ierr); 726 ierr = MatSetFromOptions(jac->schur);CHKERRQ(ierr); 727 ierr = MatGetNullSpace(jac->mat[1], &sp);CHKERRQ(ierr); 728 if (sp) { 729 ierr = MatSetNullSpace(jac->schur, sp);CHKERRQ(ierr); 730 } 731 732 ierr = PetscSNPrintf(schurtestoption, sizeof(schurtestoption), "-fieldsplit_%s_inner_", ilink->splitname);CHKERRQ(ierr); 733 ierr = PetscOptionsFindPairPrefix_Private(((PetscObject)pc)->options,((PetscObject)pc)->prefix, schurtestoption, NULL, &flg);CHKERRQ(ierr); 734 if (flg) { 735 DM dmInner; 736 KSP kspInner; 737 738 ierr = MatSchurComplementGetKSP(jac->schur, &kspInner);CHKERRQ(ierr); 739 ierr = PetscSNPrintf(schurprefix, sizeof(schurprefix), "%sfieldsplit_%s_inner_", ((PetscObject)pc)->prefix ? ((PetscObject)pc)->prefix : "", ilink->splitname);CHKERRQ(ierr); 740 /* Indent this deeper to emphasize the "inner" nature of this solver. */ 741 ierr = PetscObjectIncrementTabLevel((PetscObject)kspInner, (PetscObject) pc, 2);CHKERRQ(ierr); 742 ierr = KSPSetOptionsPrefix(kspInner, schurprefix);CHKERRQ(ierr); 743 744 /* Set DM for new solver */ 745 ierr = KSPGetDM(jac->head->ksp, &dmInner);CHKERRQ(ierr); 746 ierr = KSPSetDM(kspInner, dmInner);CHKERRQ(ierr); 747 ierr = KSPSetDMActive(kspInner, PETSC_FALSE);CHKERRQ(ierr); 748 } else { 749 /* Use the outer solver for the inner solve, but revert the KSPPREONLY from PCFieldSplitSetFields_FieldSplit or 750 * PCFieldSplitSetIS_FieldSplit. We don't want KSPPREONLY because it makes the Schur complement inexact, 751 * preventing Schur complement reduction to be an accurate solve. Usually when an iterative solver is used for 752 * S = D - C A_inner^{-1} B, we expect S to be defined using an accurate definition of A_inner^{-1}, so we make 753 * GMRES the default. Note that it is also common to use PREONLY for S, in which case S may not be used 754 * directly, and the user is responsible for setting an inexact method for fieldsplit's A^{-1}. */ 755 ierr = KSPSetType(jac->head->ksp,KSPGMRES);CHKERRQ(ierr); 756 ierr = MatSchurComplementSetKSP(jac->schur,jac->head->ksp);CHKERRQ(ierr); 757 } 758 ierr = KSPSetOperators(jac->head->ksp,jac->mat[0],jac->pmat[0]);CHKERRQ(ierr); 759 ierr = KSPSetFromOptions(jac->head->ksp);CHKERRQ(ierr); 760 ierr = MatSetFromOptions(jac->schur);CHKERRQ(ierr); 761 762 ierr = PetscSNPrintf(schurtestoption, sizeof(schurtestoption), "-fieldsplit_%s_upper_", ilink->splitname);CHKERRQ(ierr); 763 ierr = PetscOptionsFindPairPrefix_Private(((PetscObject)pc)->options,((PetscObject)pc)->prefix, schurtestoption, NULL, &flg);CHKERRQ(ierr); 764 if (flg) { 765 DM dmInner; 766 767 ierr = PetscSNPrintf(schurprefix, sizeof(schurprefix), "%sfieldsplit_%s_upper_", ((PetscObject)pc)->prefix ? ((PetscObject)pc)->prefix : "", ilink->splitname);CHKERRQ(ierr); 768 ierr = KSPCreate(PetscObjectComm((PetscObject)pc), &jac->kspupper);CHKERRQ(ierr); 769 ierr = KSPSetErrorIfNotConverged(jac->kspupper,pc->erroriffailure);CHKERRQ(ierr); 770 ierr = KSPSetOptionsPrefix(jac->kspupper, schurprefix);CHKERRQ(ierr); 771 ierr = KSPGetDM(jac->head->ksp, &dmInner);CHKERRQ(ierr); 772 ierr = KSPSetDM(jac->kspupper, dmInner);CHKERRQ(ierr); 773 ierr = KSPSetDMActive(jac->kspupper, PETSC_FALSE);CHKERRQ(ierr); 774 ierr = KSPSetFromOptions(jac->kspupper);CHKERRQ(ierr); 775 ierr = KSPSetOperators(jac->kspupper,jac->mat[0],jac->pmat[0]);CHKERRQ(ierr); 776 ierr = VecDuplicate(jac->head->x, &jac->head->z);CHKERRQ(ierr); 777 } else { 778 jac->kspupper = jac->head->ksp; 779 ierr = PetscObjectReference((PetscObject) jac->head->ksp);CHKERRQ(ierr); 780 } 781 782 if (jac->schurpre == PC_FIELDSPLIT_SCHUR_PRE_SELFP) { 783 ierr = MatSchurComplementGetPmat(jac->schur,MAT_INITIAL_MATRIX,&jac->schurp);CHKERRQ(ierr); 784 } 785 ierr = KSPCreate(PetscObjectComm((PetscObject)pc),&jac->kspschur);CHKERRQ(ierr); 786 ierr = KSPSetErrorIfNotConverged(jac->kspschur,pc->erroriffailure);CHKERRQ(ierr); 787 ierr = PetscLogObjectParent((PetscObject)pc,(PetscObject)jac->kspschur);CHKERRQ(ierr); 788 ierr = PetscObjectIncrementTabLevel((PetscObject)jac->kspschur,(PetscObject)pc,1);CHKERRQ(ierr); 789 if (jac->schurpre == PC_FIELDSPLIT_SCHUR_PRE_SELF) { 790 PC pcschur; 791 ierr = KSPGetPC(jac->kspschur,&pcschur);CHKERRQ(ierr); 792 ierr = PCSetType(pcschur,PCNONE);CHKERRQ(ierr); 793 /* Note: This is bad if there exist preconditioners for MATSCHURCOMPLEMENT */ 794 } else if (jac->schurpre == PC_FIELDSPLIT_SCHUR_PRE_FULL) { 795 ierr = MatSchurComplementComputeExplicitOperator(jac->schur, &jac->schur_user);CHKERRQ(ierr); 796 } 797 ierr = KSPSetOperators(jac->kspschur,jac->schur,FieldSplitSchurPre(jac));CHKERRQ(ierr); 798 ierr = KSPGetOptionsPrefix(jac->head->next->ksp, &Dprefix);CHKERRQ(ierr); 799 ierr = KSPSetOptionsPrefix(jac->kspschur, Dprefix);CHKERRQ(ierr); 800 /* propagate DM */ 801 { 802 DM sdm; 803 ierr = KSPGetDM(jac->head->next->ksp, &sdm);CHKERRQ(ierr); 804 if (sdm) { 805 ierr = KSPSetDM(jac->kspschur, sdm);CHKERRQ(ierr); 806 ierr = KSPSetDMActive(jac->kspschur, PETSC_FALSE);CHKERRQ(ierr); 807 } 808 } 809 /* really want setfromoptions called in PCSetFromOptions_FieldSplit(), but it is not ready yet */ 810 /* need to call this every time, since the jac->kspschur is freshly created, otherwise its options never get set */ 811 ierr = KSPSetFromOptions(jac->kspschur);CHKERRQ(ierr); 812 } 813 814 /* HACK: special support to forward L and Lp matrices that might be used by PCLSC */ 815 ierr = PetscSNPrintf(lscname,sizeof(lscname),"%s_LSC_L",ilink->splitname);CHKERRQ(ierr); 816 ierr = PetscObjectQuery((PetscObject)pc->mat,lscname,(PetscObject*)&LSC_L);CHKERRQ(ierr); 817 if (!LSC_L) {ierr = PetscObjectQuery((PetscObject)pc->pmat,lscname,(PetscObject*)&LSC_L);CHKERRQ(ierr);} 818 if (LSC_L) {ierr = PetscObjectCompose((PetscObject)jac->schur,"LSC_L",(PetscObject)LSC_L);CHKERRQ(ierr);} 819 ierr = PetscSNPrintf(lscname,sizeof(lscname),"%s_LSC_Lp",ilink->splitname);CHKERRQ(ierr); 820 ierr = PetscObjectQuery((PetscObject)pc->pmat,lscname,(PetscObject*)&LSC_L);CHKERRQ(ierr); 821 if (!LSC_L) {ierr = PetscObjectQuery((PetscObject)pc->mat,lscname,(PetscObject*)&LSC_L);CHKERRQ(ierr);} 822 if (LSC_L) {ierr = PetscObjectCompose((PetscObject)jac->schur,"LSC_Lp",(PetscObject)LSC_L);CHKERRQ(ierr);} 823 } else { 824 /* set up the individual splits' PCs */ 825 i = 0; 826 ilink = jac->head; 827 while (ilink) { 828 ierr = KSPSetOperators(ilink->ksp,jac->mat[i],jac->pmat[i]);CHKERRQ(ierr); 829 /* really want setfromoptions called in PCSetFromOptions_FieldSplit(), but it is not ready yet */ 830 if (!jac->suboptionsset) {ierr = KSPSetFromOptions(ilink->ksp);CHKERRQ(ierr);} 831 i++; 832 ilink = ilink->next; 833 } 834 } 835 836 jac->suboptionsset = PETSC_TRUE; 837 PetscFunctionReturn(0); 838 } 839 840 #define FieldSplitSplitSolveAdd(ilink,xx,yy) \ 841 (VecScatterBegin(ilink->sctx,xx,ilink->x,INSERT_VALUES,SCATTER_FORWARD) || \ 842 VecScatterEnd(ilink->sctx,xx,ilink->x,INSERT_VALUES,SCATTER_FORWARD) || \ 843 PetscLogEventBegin(ilink->event,ilink->ksp,ilink->x,ilink->y,NULL) ||\ 844 KSPSolve(ilink->ksp,ilink->x,ilink->y) || \ 845 PetscLogEventEnd(ilink->event,ilink->ksp,ilink->x,ilink->y,NULL) ||\ 846 VecScatterBegin(ilink->sctx,ilink->y,yy,ADD_VALUES,SCATTER_REVERSE) || \ 847 VecScatterEnd(ilink->sctx,ilink->y,yy,ADD_VALUES,SCATTER_REVERSE)) 848 849 static PetscErrorCode PCApply_FieldSplit_Schur(PC pc,Vec x,Vec y) 850 { 851 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 852 PetscErrorCode ierr; 853 PC_FieldSplitLink ilinkA = jac->head, ilinkD = ilinkA->next; 854 KSP kspA = ilinkA->ksp, kspLower = kspA, kspUpper = jac->kspupper; 855 856 PetscFunctionBegin; 857 switch (jac->schurfactorization) { 858 case PC_FIELDSPLIT_SCHUR_FACT_DIAG: 859 /* [A00 0; 0 -S], positive definite, suitable for MINRES */ 860 ierr = VecScatterBegin(ilinkA->sctx,x,ilinkA->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 861 ierr = VecScatterBegin(ilinkD->sctx,x,ilinkD->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 862 ierr = VecScatterEnd(ilinkA->sctx,x,ilinkA->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 863 ierr = PetscLogEventBegin(ilinkA->event,kspA,ilinkA->x,ilinkA->y,NULL);CHKERRQ(ierr); 864 ierr = KSPSolve(kspA,ilinkA->x,ilinkA->y);CHKERRQ(ierr); 865 ierr = PetscLogEventEnd(ilinkA->event,kspA,ilinkA->x,ilinkA->y,NULL);CHKERRQ(ierr); 866 ierr = VecScatterBegin(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 867 ierr = VecScatterEnd(ilinkD->sctx,x,ilinkD->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 868 ierr = PetscLogEventBegin(KSP_Solve_FS_S,jac->kspschur,ilinkD->x,ilinkD->y,NULL);CHKERRQ(ierr); 869 ierr = KSPSolve(jac->kspschur,ilinkD->x,ilinkD->y);CHKERRQ(ierr); 870 ierr = PetscLogEventEnd(KSP_Solve_FS_S,jac->kspschur,ilinkD->x,ilinkD->y,NULL);CHKERRQ(ierr); 871 ierr = VecScale(ilinkD->y,jac->schurscale);CHKERRQ(ierr); 872 ierr = VecScatterBegin(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 873 ierr = VecScatterEnd(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 874 ierr = VecScatterEnd(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 875 break; 876 case PC_FIELDSPLIT_SCHUR_FACT_LOWER: 877 /* [A00 0; A10 S], suitable for left preconditioning */ 878 ierr = VecScatterBegin(ilinkA->sctx,x,ilinkA->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 879 ierr = VecScatterEnd(ilinkA->sctx,x,ilinkA->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 880 ierr = PetscLogEventBegin(ilinkA->event,kspA,ilinkA->x,ilinkA->y,NULL);CHKERRQ(ierr); 881 ierr = KSPSolve(kspA,ilinkA->x,ilinkA->y);CHKERRQ(ierr); 882 ierr = PetscLogEventEnd(ilinkA->event,kspA,ilinkA->x,ilinkA->y,NULL);CHKERRQ(ierr); 883 ierr = MatMult(jac->C,ilinkA->y,ilinkD->x);CHKERRQ(ierr); 884 ierr = VecScale(ilinkD->x,-1.);CHKERRQ(ierr); 885 ierr = VecScatterBegin(ilinkD->sctx,x,ilinkD->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 886 ierr = VecScatterBegin(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 887 ierr = VecScatterEnd(ilinkD->sctx,x,ilinkD->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 888 ierr = PetscLogEventBegin(KSP_Solve_FS_S,jac->kspschur,ilinkD->x,ilinkD->y,NULL);CHKERRQ(ierr); 889 ierr = KSPSolve(jac->kspschur,ilinkD->x,ilinkD->y);CHKERRQ(ierr); 890 ierr = PetscLogEventEnd(KSP_Solve_FS_S,jac->kspschur,ilinkD->x,ilinkD->y,NULL);CHKERRQ(ierr); 891 ierr = VecScatterBegin(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 892 ierr = VecScatterEnd(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 893 ierr = VecScatterEnd(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 894 break; 895 case PC_FIELDSPLIT_SCHUR_FACT_UPPER: 896 /* [A00 A01; 0 S], suitable for right preconditioning */ 897 ierr = VecScatterBegin(ilinkD->sctx,x,ilinkD->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 898 ierr = VecScatterEnd(ilinkD->sctx,x,ilinkD->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 899 ierr = PetscLogEventBegin(KSP_Solve_FS_S,jac->kspschur,ilinkD->x,ilinkD->y,NULL);CHKERRQ(ierr); 900 ierr = KSPSolve(jac->kspschur,ilinkD->x,ilinkD->y);CHKERRQ(ierr); 901 ierr = PetscLogEventEnd(KSP_Solve_FS_S,jac->kspschur,ilinkD->x,ilinkD->y,NULL);CHKERRQ(ierr); ierr = MatMult(jac->B,ilinkD->y,ilinkA->x);CHKERRQ(ierr); 902 ierr = VecScale(ilinkA->x,-1.);CHKERRQ(ierr); 903 ierr = VecScatterBegin(ilinkA->sctx,x,ilinkA->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 904 ierr = VecScatterBegin(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 905 ierr = VecScatterEnd(ilinkA->sctx,x,ilinkA->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 906 ierr = PetscLogEventBegin(ilinkA->event,kspA,ilinkA->x,ilinkA->y,NULL);CHKERRQ(ierr); 907 ierr = KSPSolve(kspA,ilinkA->x,ilinkA->y);CHKERRQ(ierr); 908 ierr = PetscLogEventEnd(ilinkA->event,kspA,ilinkA->x,ilinkA->y,NULL);CHKERRQ(ierr); 909 ierr = VecScatterBegin(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 910 ierr = VecScatterEnd(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 911 ierr = VecScatterEnd(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 912 break; 913 case PC_FIELDSPLIT_SCHUR_FACT_FULL: 914 /* [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 */ 915 ierr = VecScatterBegin(ilinkA->sctx,x,ilinkA->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 916 ierr = VecScatterEnd(ilinkA->sctx,x,ilinkA->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 917 ierr = PetscLogEventBegin(KSP_Solve_FS_L,kspLower,ilinkA->x,ilinkA->y,NULL);CHKERRQ(ierr); 918 ierr = KSPSolve(kspLower,ilinkA->x,ilinkA->y);CHKERRQ(ierr); 919 ierr = PetscLogEventEnd(KSP_Solve_FS_L,kspLower,ilinkA->x,ilinkA->y,NULL);CHKERRQ(ierr); 920 ierr = MatMult(jac->C,ilinkA->y,ilinkD->x);CHKERRQ(ierr); 921 ierr = VecScale(ilinkD->x,-1.0);CHKERRQ(ierr); 922 ierr = VecScatterBegin(ilinkD->sctx,x,ilinkD->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 923 ierr = VecScatterEnd(ilinkD->sctx,x,ilinkD->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 924 925 ierr = PetscLogEventBegin(KSP_Solve_FS_S,jac->kspschur,ilinkD->x,ilinkD->y,NULL);CHKERRQ(ierr); 926 ierr = KSPSolve(jac->kspschur,ilinkD->x,ilinkD->y);CHKERRQ(ierr); 927 ierr = PetscLogEventEnd(KSP_Solve_FS_S,jac->kspschur,ilinkD->x,ilinkD->y,NULL);CHKERRQ(ierr); 928 ierr = VecScatterBegin(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 929 ierr = VecScatterEnd(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 930 931 if (kspUpper == kspA) { 932 ierr = MatMult(jac->B,ilinkD->y,ilinkA->y);CHKERRQ(ierr); 933 ierr = VecAXPY(ilinkA->x,-1.0,ilinkA->y);CHKERRQ(ierr); 934 ierr = PetscLogEventBegin(ilinkA->event,kspA,ilinkA->x,ilinkA->y,NULL);CHKERRQ(ierr); 935 ierr = KSPSolve(kspA,ilinkA->x,ilinkA->y);CHKERRQ(ierr); 936 ierr = PetscLogEventEnd(ilinkA->event,kspA,ilinkA->x,ilinkA->y,NULL);CHKERRQ(ierr); 937 } else { 938 ierr = PetscLogEventBegin(ilinkA->event,kspA,ilinkA->x,ilinkA->y,NULL);CHKERRQ(ierr); 939 ierr = KSPSolve(kspA,ilinkA->x,ilinkA->y);CHKERRQ(ierr); 940 ierr = PetscLogEventEnd(ilinkA->event,kspA,ilinkA->x,ilinkA->y,NULL);CHKERRQ(ierr); 941 ierr = MatMult(jac->B,ilinkD->y,ilinkA->x);CHKERRQ(ierr); 942 ierr = PetscLogEventBegin(KSP_Solve_FS_U,kspUpper,ilinkA->x,ilinkA->z,NULL);CHKERRQ(ierr); 943 ierr = KSPSolve(kspUpper,ilinkA->x,ilinkA->z);CHKERRQ(ierr); 944 ierr = PetscLogEventEnd(KSP_Solve_FS_U,kspUpper,ilinkA->x,ilinkA->z,NULL);CHKERRQ(ierr); 945 ierr = VecAXPY(ilinkA->y,-1.0,ilinkA->z);CHKERRQ(ierr); 946 } 947 ierr = VecScatterBegin(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 948 ierr = VecScatterEnd(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 949 } 950 PetscFunctionReturn(0); 951 } 952 953 static PetscErrorCode PCApply_FieldSplit(PC pc,Vec x,Vec y) 954 { 955 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 956 PetscErrorCode ierr; 957 PC_FieldSplitLink ilink = jac->head; 958 PetscInt cnt,bs; 959 KSPConvergedReason reason; 960 961 PetscFunctionBegin; 962 if (jac->type == PC_COMPOSITE_ADDITIVE) { 963 if (jac->defaultsplit) { 964 ierr = VecGetBlockSize(x,&bs);CHKERRQ(ierr); 965 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); 966 ierr = VecGetBlockSize(y,&bs);CHKERRQ(ierr); 967 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); 968 ierr = VecStrideGatherAll(x,jac->x,INSERT_VALUES);CHKERRQ(ierr); 969 while (ilink) { 970 ierr = PetscLogEventBegin(ilink->event,ilink->ksp,ilink->x,ilink->y,NULL);CHKERRQ(ierr); 971 ierr = KSPSolve(ilink->ksp,ilink->x,ilink->y);CHKERRQ(ierr); 972 ierr = PetscLogEventEnd(ilink->event,ilink->ksp,ilink->x,ilink->y,NULL);CHKERRQ(ierr); 973 ierr = KSPGetConvergedReason(ilink->ksp,&reason);CHKERRQ(ierr); 974 if (reason == KSP_DIVERGED_PCSETUP_FAILED) { 975 pc->failedreason = PC_SUBPC_ERROR; 976 } 977 ilink = ilink->next; 978 } 979 ierr = VecStrideScatterAll(jac->y,y,INSERT_VALUES);CHKERRQ(ierr); 980 } else { 981 ierr = VecSet(y,0.0);CHKERRQ(ierr); 982 while (ilink) { 983 ierr = FieldSplitSplitSolveAdd(ilink,x,y);CHKERRQ(ierr); 984 ierr = KSPGetConvergedReason(ilink->ksp,&reason);CHKERRQ(ierr); 985 if (reason == KSP_DIVERGED_PCSETUP_FAILED) { 986 pc->failedreason = PC_SUBPC_ERROR; 987 } 988 ilink = ilink->next; 989 } 990 } 991 } else if (jac->type == PC_COMPOSITE_MULTIPLICATIVE && jac->nsplits == 2) { 992 ierr = VecSet(y,0.0);CHKERRQ(ierr); 993 /* solve on first block for first block variables */ 994 ierr = VecScatterBegin(ilink->sctx,x,ilink->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 995 ierr = VecScatterEnd(ilink->sctx,x,ilink->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 996 ierr = PetscLogEventBegin(ilink->event,ilink->ksp,ilink->x,ilink->y,NULL);CHKERRQ(ierr); 997 ierr = KSPSolve(ilink->ksp,ilink->x,ilink->y);CHKERRQ(ierr); 998 ierr = PetscLogEventEnd(ilink->event,ilink->ksp,ilink->x,ilink->y,NULL);CHKERRQ(ierr); 999 ierr = KSPGetConvergedReason(ilink->ksp,&reason);CHKERRQ(ierr); 1000 if (reason == KSP_DIVERGED_PCSETUP_FAILED) { 1001 pc->failedreason = PC_SUBPC_ERROR; 1002 } 1003 ierr = VecScatterBegin(ilink->sctx,ilink->y,y,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 1004 ierr = VecScatterEnd(ilink->sctx,ilink->y,y,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 1005 1006 /* compute the residual only onto second block variables using first block variables */ 1007 ierr = MatMult(jac->Afield[1],ilink->y,ilink->next->x);CHKERRQ(ierr); 1008 ilink = ilink->next; 1009 ierr = VecScale(ilink->x,-1.0);CHKERRQ(ierr); 1010 ierr = VecScatterBegin(ilink->sctx,x,ilink->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 1011 ierr = VecScatterEnd(ilink->sctx,x,ilink->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 1012 1013 /* solve on second block variables */ 1014 ierr = PetscLogEventBegin(ilink->event,ilink->ksp,ilink->x,ilink->y,NULL);CHKERRQ(ierr); 1015 ierr = KSPSolve(ilink->ksp,ilink->x,ilink->y);CHKERRQ(ierr); 1016 ierr = PetscLogEventEnd(ilink->event,ilink->ksp,ilink->x,ilink->y,NULL);CHKERRQ(ierr); 1017 ierr = KSPGetConvergedReason(ilink->ksp,&reason);CHKERRQ(ierr); 1018 if (reason == KSP_DIVERGED_PCSETUP_FAILED) { 1019 pc->failedreason = PC_SUBPC_ERROR; 1020 } 1021 ierr = VecScatterBegin(ilink->sctx,ilink->y,y,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 1022 ierr = VecScatterEnd(ilink->sctx,ilink->y,y,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 1023 } else if (jac->type == PC_COMPOSITE_MULTIPLICATIVE || jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) { 1024 if (!jac->w1) { 1025 ierr = VecDuplicate(x,&jac->w1);CHKERRQ(ierr); 1026 ierr = VecDuplicate(x,&jac->w2);CHKERRQ(ierr); 1027 } 1028 ierr = VecSet(y,0.0);CHKERRQ(ierr); 1029 ierr = FieldSplitSplitSolveAdd(ilink,x,y);CHKERRQ(ierr); 1030 ierr = KSPGetConvergedReason(ilink->ksp,&reason);CHKERRQ(ierr); 1031 if (reason == KSP_DIVERGED_PCSETUP_FAILED) { 1032 pc->failedreason = PC_SUBPC_ERROR; 1033 } 1034 cnt = 1; 1035 while (ilink->next) { 1036 ilink = ilink->next; 1037 /* compute the residual only over the part of the vector needed */ 1038 ierr = MatMult(jac->Afield[cnt++],y,ilink->x);CHKERRQ(ierr); 1039 ierr = VecScale(ilink->x,-1.0);CHKERRQ(ierr); 1040 ierr = VecScatterBegin(ilink->sctx,x,ilink->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 1041 ierr = VecScatterEnd(ilink->sctx,x,ilink->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 1042 ierr = PetscLogEventBegin(ilink->event,ilink->ksp,ilink->x,ilink->y,NULL);CHKERRQ(ierr); 1043 ierr = KSPSolve(ilink->ksp,ilink->x,ilink->y);CHKERRQ(ierr); 1044 ierr = PetscLogEventEnd(ilink->event,ilink->ksp,ilink->x,ilink->y,NULL);CHKERRQ(ierr); 1045 ierr = KSPGetConvergedReason(ilink->ksp,&reason);CHKERRQ(ierr); 1046 if (reason == KSP_DIVERGED_PCSETUP_FAILED) { 1047 pc->failedreason = PC_SUBPC_ERROR; 1048 } 1049 ierr = VecScatterBegin(ilink->sctx,ilink->y,y,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 1050 ierr = VecScatterEnd(ilink->sctx,ilink->y,y,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 1051 } 1052 if (jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) { 1053 cnt -= 2; 1054 while (ilink->previous) { 1055 ilink = ilink->previous; 1056 /* compute the residual only over the part of the vector needed */ 1057 ierr = MatMult(jac->Afield[cnt--],y,ilink->x);CHKERRQ(ierr); 1058 ierr = VecScale(ilink->x,-1.0);CHKERRQ(ierr); 1059 ierr = VecScatterBegin(ilink->sctx,x,ilink->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 1060 ierr = VecScatterEnd(ilink->sctx,x,ilink->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 1061 ierr = PetscLogEventBegin(ilink->event,ilink->ksp,ilink->x,ilink->y,NULL);CHKERRQ(ierr); 1062 ierr = KSPSolve(ilink->ksp,ilink->x,ilink->y);CHKERRQ(ierr); 1063 ierr = PetscLogEventEnd(ilink->event,ilink->ksp,ilink->x,ilink->y,NULL);CHKERRQ(ierr); 1064 ierr = KSPGetConvergedReason(ilink->ksp,&reason);CHKERRQ(ierr); 1065 if (reason == KSP_DIVERGED_PCSETUP_FAILED) { 1066 pc->failedreason = PC_SUBPC_ERROR; 1067 } 1068 ierr = VecScatterBegin(ilink->sctx,ilink->y,y,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 1069 ierr = VecScatterEnd(ilink->sctx,ilink->y,y,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 1070 } 1071 } 1072 } else SETERRQ1(PetscObjectComm((PetscObject)pc),PETSC_ERR_SUP,"Unsupported or unknown composition",(int) jac->type); 1073 PetscFunctionReturn(0); 1074 } 1075 1076 #define FieldSplitSplitSolveAddTranspose(ilink,xx,yy) \ 1077 (VecScatterBegin(ilink->sctx,xx,ilink->y,INSERT_VALUES,SCATTER_FORWARD) || \ 1078 VecScatterEnd(ilink->sctx,xx,ilink->y,INSERT_VALUES,SCATTER_FORWARD) || \ 1079 PetscLogEventBegin(ilink->event,ilink->ksp,ilink->y,ilink->x,NULL) || \ 1080 KSPSolveTranspose(ilink->ksp,ilink->y,ilink->x) || \ 1081 PetscLogEventBegin(ilink->event,ilink->ksp,ilink->y,ilink->x,NULL) || \ 1082 VecScatterBegin(ilink->sctx,ilink->x,yy,ADD_VALUES,SCATTER_REVERSE) || \ 1083 VecScatterEnd(ilink->sctx,ilink->x,yy,ADD_VALUES,SCATTER_REVERSE)) 1084 1085 static PetscErrorCode PCApplyTranspose_FieldSplit(PC pc,Vec x,Vec y) 1086 { 1087 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 1088 PetscErrorCode ierr; 1089 PC_FieldSplitLink ilink = jac->head; 1090 PetscInt bs; 1091 KSPConvergedReason reason; 1092 1093 PetscFunctionBegin; 1094 if (jac->type == PC_COMPOSITE_ADDITIVE) { 1095 if (jac->defaultsplit) { 1096 ierr = VecGetBlockSize(x,&bs);CHKERRQ(ierr); 1097 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); 1098 ierr = VecGetBlockSize(y,&bs);CHKERRQ(ierr); 1099 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); 1100 ierr = VecStrideGatherAll(x,jac->x,INSERT_VALUES);CHKERRQ(ierr); 1101 while (ilink) { 1102 ierr = PetscLogEventBegin(ilink->event,ilink->ksp,ilink->x,ilink->y,NULL);CHKERRQ(ierr); 1103 ierr = KSPSolveTranspose(ilink->ksp,ilink->x,ilink->y);CHKERRQ(ierr); 1104 ierr = PetscLogEventEnd(ilink->event,ilink->ksp,ilink->x,ilink->y,NULL);CHKERRQ(ierr); 1105 ierr = KSPGetConvergedReason(ilink->ksp,&reason);CHKERRQ(ierr); 1106 if (reason == KSP_DIVERGED_PCSETUP_FAILED) { 1107 pc->failedreason = PC_SUBPC_ERROR; 1108 } 1109 ilink = ilink->next; 1110 } 1111 ierr = VecStrideScatterAll(jac->y,y,INSERT_VALUES);CHKERRQ(ierr); 1112 } else { 1113 ierr = VecSet(y,0.0);CHKERRQ(ierr); 1114 while (ilink) { 1115 ierr = FieldSplitSplitSolveAddTranspose(ilink,x,y);CHKERRQ(ierr); 1116 ierr = KSPGetConvergedReason(ilink->ksp,&reason);CHKERRQ(ierr); 1117 if (reason == KSP_DIVERGED_PCSETUP_FAILED) { 1118 pc->failedreason = PC_SUBPC_ERROR; 1119 } 1120 ilink = ilink->next; 1121 } 1122 } 1123 } else { 1124 if (!jac->w1) { 1125 ierr = VecDuplicate(x,&jac->w1);CHKERRQ(ierr); 1126 ierr = VecDuplicate(x,&jac->w2);CHKERRQ(ierr); 1127 } 1128 ierr = VecSet(y,0.0);CHKERRQ(ierr); 1129 if (jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) { 1130 ierr = FieldSplitSplitSolveAddTranspose(ilink,x,y);CHKERRQ(ierr); 1131 ierr = KSPGetConvergedReason(ilink->ksp,&reason);CHKERRQ(ierr); 1132 if (reason == KSP_DIVERGED_PCSETUP_FAILED) { 1133 pc->failedreason = PC_SUBPC_ERROR; 1134 } 1135 while (ilink->next) { 1136 ilink = ilink->next; 1137 ierr = MatMultTranspose(pc->mat,y,jac->w1);CHKERRQ(ierr); 1138 ierr = VecWAXPY(jac->w2,-1.0,jac->w1,x);CHKERRQ(ierr); 1139 ierr = FieldSplitSplitSolveAddTranspose(ilink,jac->w2,y);CHKERRQ(ierr); 1140 } 1141 while (ilink->previous) { 1142 ilink = ilink->previous; 1143 ierr = MatMultTranspose(pc->mat,y,jac->w1);CHKERRQ(ierr); 1144 ierr = VecWAXPY(jac->w2,-1.0,jac->w1,x);CHKERRQ(ierr); 1145 ierr = FieldSplitSplitSolveAddTranspose(ilink,jac->w2,y);CHKERRQ(ierr); 1146 } 1147 } else { 1148 while (ilink->next) { /* get to last entry in linked list */ 1149 ilink = ilink->next; 1150 } 1151 ierr = FieldSplitSplitSolveAddTranspose(ilink,x,y);CHKERRQ(ierr); 1152 ierr = KSPGetConvergedReason(ilink->ksp,&reason);CHKERRQ(ierr); 1153 if (reason == KSP_DIVERGED_PCSETUP_FAILED) { 1154 pc->failedreason = PC_SUBPC_ERROR; 1155 } 1156 while (ilink->previous) { 1157 ilink = ilink->previous; 1158 ierr = MatMultTranspose(pc->mat,y,jac->w1);CHKERRQ(ierr); 1159 ierr = VecWAXPY(jac->w2,-1.0,jac->w1,x);CHKERRQ(ierr); 1160 ierr = FieldSplitSplitSolveAddTranspose(ilink,jac->w2,y);CHKERRQ(ierr); 1161 } 1162 } 1163 } 1164 PetscFunctionReturn(0); 1165 } 1166 1167 static PetscErrorCode PCReset_FieldSplit(PC pc) 1168 { 1169 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 1170 PetscErrorCode ierr; 1171 PC_FieldSplitLink ilink = jac->head,next; 1172 1173 PetscFunctionBegin; 1174 while (ilink) { 1175 ierr = KSPDestroy(&ilink->ksp);CHKERRQ(ierr); 1176 ierr = VecDestroy(&ilink->x);CHKERRQ(ierr); 1177 ierr = VecDestroy(&ilink->y);CHKERRQ(ierr); 1178 ierr = VecDestroy(&ilink->z);CHKERRQ(ierr); 1179 ierr = VecScatterDestroy(&ilink->sctx);CHKERRQ(ierr); 1180 ierr = ISDestroy(&ilink->is);CHKERRQ(ierr); 1181 ierr = ISDestroy(&ilink->is_col);CHKERRQ(ierr); 1182 ierr = PetscFree(ilink->splitname);CHKERRQ(ierr); 1183 ierr = PetscFree(ilink->fields);CHKERRQ(ierr); 1184 ierr = PetscFree(ilink->fields_col);CHKERRQ(ierr); 1185 next = ilink->next; 1186 ierr = PetscFree(ilink);CHKERRQ(ierr); 1187 ilink = next; 1188 } 1189 jac->head = NULL; 1190 ierr = PetscFree2(jac->x,jac->y);CHKERRQ(ierr); 1191 if (jac->mat && jac->mat != jac->pmat) { 1192 ierr = MatDestroyMatrices(jac->nsplits,&jac->mat);CHKERRQ(ierr); 1193 } else if (jac->mat) { 1194 jac->mat = NULL; 1195 } 1196 if (jac->pmat) {ierr = MatDestroyMatrices(jac->nsplits,&jac->pmat);CHKERRQ(ierr);} 1197 if (jac->Afield) {ierr = MatDestroyMatrices(jac->nsplits,&jac->Afield);CHKERRQ(ierr);} 1198 jac->nsplits = 0; 1199 ierr = VecDestroy(&jac->w1);CHKERRQ(ierr); 1200 ierr = VecDestroy(&jac->w2);CHKERRQ(ierr); 1201 ierr = MatDestroy(&jac->schur);CHKERRQ(ierr); 1202 ierr = MatDestroy(&jac->schurp);CHKERRQ(ierr); 1203 ierr = MatDestroy(&jac->schur_user);CHKERRQ(ierr); 1204 ierr = KSPDestroy(&jac->kspschur);CHKERRQ(ierr); 1205 ierr = KSPDestroy(&jac->kspupper);CHKERRQ(ierr); 1206 ierr = MatDestroy(&jac->B);CHKERRQ(ierr); 1207 ierr = MatDestroy(&jac->C);CHKERRQ(ierr); 1208 jac->isrestrict = PETSC_FALSE; 1209 PetscFunctionReturn(0); 1210 } 1211 1212 static PetscErrorCode PCDestroy_FieldSplit(PC pc) 1213 { 1214 PetscErrorCode ierr; 1215 1216 PetscFunctionBegin; 1217 ierr = PCReset_FieldSplit(pc);CHKERRQ(ierr); 1218 ierr = PetscFree(pc->data);CHKERRQ(ierr); 1219 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitGetSubKSP_C",NULL);CHKERRQ(ierr); 1220 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitSetFields_C",NULL);CHKERRQ(ierr); 1221 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitSetIS_C",NULL);CHKERRQ(ierr); 1222 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitSetType_C",NULL);CHKERRQ(ierr); 1223 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitSetBlockSize_C",NULL);CHKERRQ(ierr); 1224 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitSetSchurPre_C",NULL);CHKERRQ(ierr); 1225 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitGetSchurPre_C",NULL);CHKERRQ(ierr); 1226 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitSetSchurFactType_C",NULL);CHKERRQ(ierr); 1227 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitRestrictIS_C",NULL);CHKERRQ(ierr); 1228 PetscFunctionReturn(0); 1229 } 1230 1231 static PetscErrorCode PCSetFromOptions_FieldSplit(PetscOptionItems *PetscOptionsObject,PC pc) 1232 { 1233 PetscErrorCode ierr; 1234 PetscInt bs; 1235 PetscBool flg,stokes = PETSC_FALSE; 1236 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 1237 PCCompositeType ctype; 1238 1239 PetscFunctionBegin; 1240 ierr = PetscOptionsHead(PetscOptionsObject,"FieldSplit options");CHKERRQ(ierr); 1241 ierr = PetscOptionsBool("-pc_fieldsplit_dm_splits","Whether to use DMCreateFieldDecomposition() for splits","PCFieldSplitSetDMSplits",jac->dm_splits,&jac->dm_splits,NULL);CHKERRQ(ierr); 1242 ierr = PetscOptionsInt("-pc_fieldsplit_block_size","Blocksize that defines number of fields","PCFieldSplitSetBlockSize",jac->bs,&bs,&flg);CHKERRQ(ierr); 1243 if (flg) { 1244 ierr = PCFieldSplitSetBlockSize(pc,bs);CHKERRQ(ierr); 1245 } 1246 jac->diag_use_amat = pc->useAmat; 1247 ierr = PetscOptionsBool("-pc_fieldsplit_diag_use_amat","Use Amat (not Pmat) to extract diagonal fieldsplit blocks", "PCFieldSplitSetDiagUseAmat",jac->diag_use_amat,&jac->diag_use_amat,NULL);CHKERRQ(ierr); 1248 jac->offdiag_use_amat = pc->useAmat; 1249 ierr = PetscOptionsBool("-pc_fieldsplit_off_diag_use_amat","Use Amat (not Pmat) to extract off-diagonal fieldsplit blocks", "PCFieldSplitSetOffDiagUseAmat",jac->offdiag_use_amat,&jac->offdiag_use_amat,NULL);CHKERRQ(ierr); 1250 /* FIXME: No programmatic equivalent to the following. */ 1251 ierr = PetscOptionsGetBool(((PetscObject)pc)->options,((PetscObject)pc)->prefix,"-pc_fieldsplit_detect_saddle_point",&stokes,NULL);CHKERRQ(ierr); 1252 if (stokes) { 1253 ierr = PCFieldSplitSetType(pc,PC_COMPOSITE_SCHUR);CHKERRQ(ierr); 1254 jac->schurpre = PC_FIELDSPLIT_SCHUR_PRE_SELF; 1255 } 1256 1257 ierr = PetscOptionsEnum("-pc_fieldsplit_type","Type of composition","PCFieldSplitSetType",PCCompositeTypes,(PetscEnum)jac->type,(PetscEnum*)&ctype,&flg);CHKERRQ(ierr); 1258 if (flg) { 1259 ierr = PCFieldSplitSetType(pc,ctype);CHKERRQ(ierr); 1260 } 1261 /* Only setup fields once */ 1262 if ((jac->bs > 0) && (jac->nsplits == 0)) { 1263 /* only allow user to set fields from command line if bs is already known. 1264 otherwise user can set them in PCFieldSplitSetDefaults() */ 1265 ierr = PCFieldSplitSetRuntimeSplits_Private(pc);CHKERRQ(ierr); 1266 if (jac->splitdefined) {ierr = PetscInfo(pc,"Splits defined using the options database\n");CHKERRQ(ierr);} 1267 } 1268 if (jac->type == PC_COMPOSITE_SCHUR) { 1269 ierr = PetscOptionsGetEnum(((PetscObject)pc)->options,((PetscObject)pc)->prefix,"-pc_fieldsplit_schur_factorization_type",PCFieldSplitSchurFactTypes,(PetscEnum*)&jac->schurfactorization,&flg);CHKERRQ(ierr); 1270 if (flg) {ierr = PetscInfo(pc,"Deprecated use of -pc_fieldsplit_schur_factorization_type\n");CHKERRQ(ierr);} 1271 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); 1272 ierr = PetscOptionsEnum("-pc_fieldsplit_schur_precondition","How to build preconditioner for Schur complement","PCFieldSplitSetSchurPre",PCFieldSplitSchurPreTypes,(PetscEnum)jac->schurpre,(PetscEnum*)&jac->schurpre,NULL);CHKERRQ(ierr); 1273 ierr = PetscOptionsScalar("-pc_fieldsplit_schur_scale","Scale Schur complement","PCFieldSplitSetSchurScale",jac->schurscale,&jac->schurscale,NULL);CHKERRQ(ierr); 1274 } 1275 ierr = PetscOptionsTail();CHKERRQ(ierr); 1276 PetscFunctionReturn(0); 1277 } 1278 1279 /*------------------------------------------------------------------------------------*/ 1280 1281 static PetscErrorCode PCFieldSplitSetFields_FieldSplit(PC pc,const char splitname[],PetscInt n,const PetscInt *fields,const PetscInt *fields_col) 1282 { 1283 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 1284 PetscErrorCode ierr; 1285 PC_FieldSplitLink ilink,next = jac->head; 1286 char prefix[128]; 1287 PetscInt i; 1288 1289 PetscFunctionBegin; 1290 if (jac->splitdefined) { 1291 ierr = PetscInfo1(pc,"Ignoring new split \"%s\" because the splits have already been defined\n",splitname);CHKERRQ(ierr); 1292 PetscFunctionReturn(0); 1293 } 1294 for (i=0; i<n; i++) { 1295 if (fields[i] >= jac->bs) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Field %D requested but only %D exist",fields[i],jac->bs); 1296 if (fields[i] < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Negative field %D requested",fields[i]); 1297 } 1298 ierr = PetscNew(&ilink);CHKERRQ(ierr); 1299 if (splitname) { 1300 ierr = PetscStrallocpy(splitname,&ilink->splitname);CHKERRQ(ierr); 1301 } else { 1302 ierr = PetscMalloc1(3,&ilink->splitname);CHKERRQ(ierr); 1303 ierr = PetscSNPrintf(ilink->splitname,2,"%s",jac->nsplits);CHKERRQ(ierr); 1304 } 1305 ilink->event = jac->nsplits < 5 ? KSP_Solve_FS_0 + jac->nsplits : KSP_Solve_FS_0 + 4; /* Any split great than 4 gets logged in the 4th split */ 1306 ierr = PetscMalloc1(n,&ilink->fields);CHKERRQ(ierr); 1307 ierr = PetscMemcpy(ilink->fields,fields,n*sizeof(PetscInt));CHKERRQ(ierr); 1308 ierr = PetscMalloc1(n,&ilink->fields_col);CHKERRQ(ierr); 1309 ierr = PetscMemcpy(ilink->fields_col,fields_col,n*sizeof(PetscInt));CHKERRQ(ierr); 1310 1311 ilink->nfields = n; 1312 ilink->next = NULL; 1313 ierr = KSPCreate(PetscObjectComm((PetscObject)pc),&ilink->ksp);CHKERRQ(ierr); 1314 ierr = KSPSetErrorIfNotConverged(ilink->ksp,pc->erroriffailure);CHKERRQ(ierr); 1315 ierr = PetscObjectIncrementTabLevel((PetscObject)ilink->ksp,(PetscObject)pc,1);CHKERRQ(ierr); 1316 ierr = KSPSetType(ilink->ksp,KSPPREONLY);CHKERRQ(ierr); 1317 ierr = PetscLogObjectParent((PetscObject)pc,(PetscObject)ilink->ksp);CHKERRQ(ierr); 1318 1319 ierr = PetscSNPrintf(prefix,sizeof(prefix),"%sfieldsplit_%s_",((PetscObject)pc)->prefix ? ((PetscObject)pc)->prefix : "",ilink->splitname);CHKERRQ(ierr); 1320 ierr = KSPSetOptionsPrefix(ilink->ksp,prefix);CHKERRQ(ierr); 1321 1322 if (!next) { 1323 jac->head = ilink; 1324 ilink->previous = NULL; 1325 } else { 1326 while (next->next) { 1327 next = next->next; 1328 } 1329 next->next = ilink; 1330 ilink->previous = next; 1331 } 1332 jac->nsplits++; 1333 PetscFunctionReturn(0); 1334 } 1335 1336 static PetscErrorCode PCFieldSplitGetSubKSP_FieldSplit_Schur(PC pc,PetscInt *n,KSP **subksp) 1337 { 1338 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 1339 PetscErrorCode ierr; 1340 1341 PetscFunctionBegin; 1342 if (!jac->schur) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must call KSPSetUp() or PCSetUp() before calling PCFieldSplitGetSubKSP()"); 1343 ierr = PetscMalloc1(jac->nsplits,subksp);CHKERRQ(ierr); 1344 ierr = MatSchurComplementGetKSP(jac->schur,*subksp);CHKERRQ(ierr); 1345 1346 (*subksp)[1] = jac->kspschur; 1347 if (n) *n = jac->nsplits; 1348 PetscFunctionReturn(0); 1349 } 1350 1351 static PetscErrorCode PCFieldSplitGetSubKSP_FieldSplit(PC pc,PetscInt *n,KSP **subksp) 1352 { 1353 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 1354 PetscErrorCode ierr; 1355 PetscInt cnt = 0; 1356 PC_FieldSplitLink ilink = jac->head; 1357 1358 PetscFunctionBegin; 1359 ierr = PetscMalloc1(jac->nsplits,subksp);CHKERRQ(ierr); 1360 while (ilink) { 1361 (*subksp)[cnt++] = ilink->ksp; 1362 ilink = ilink->next; 1363 } 1364 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); 1365 if (n) *n = jac->nsplits; 1366 PetscFunctionReturn(0); 1367 } 1368 1369 /*@C 1370 PCFieldSplitRestrictIS - Restricts the fieldsplit ISs to be within a given IS. 1371 1372 Input Parameters: 1373 + pc - the preconditioner context 1374 + is - the index set that defines the indices to which the fieldsplit is to be restricted 1375 1376 Level: advanced 1377 1378 @*/ 1379 PetscErrorCode PCFieldSplitRestrictIS(PC pc,IS isy) 1380 { 1381 PetscErrorCode ierr; 1382 1383 PetscFunctionBegin; 1384 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1385 PetscValidHeaderSpecific(isy,IS_CLASSID,2); 1386 ierr = PetscTryMethod(pc,"PCFieldSplitRestrictIS_C",(PC,IS),(pc,isy));CHKERRQ(ierr); 1387 PetscFunctionReturn(0); 1388 } 1389 1390 1391 static PetscErrorCode PCFieldSplitRestrictIS_FieldSplit(PC pc, IS isy) 1392 { 1393 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 1394 PetscErrorCode ierr; 1395 PC_FieldSplitLink ilink = jac->head, next; 1396 PetscInt localsize,size,sizez,i; 1397 const PetscInt *ind, *indz; 1398 PetscInt *indc, *indcz; 1399 PetscBool flg; 1400 1401 PetscFunctionBegin; 1402 ierr = ISGetLocalSize(isy,&localsize);CHKERRQ(ierr); 1403 ierr = MPI_Scan(&localsize,&size,1,MPIU_INT,MPI_SUM,PetscObjectComm((PetscObject)isy));CHKERRQ(ierr); 1404 size -= localsize; 1405 while(ilink) { 1406 IS isrl,isr; 1407 PC subpc; 1408 ierr = ISEmbed(ilink->is, isy, PETSC_TRUE, &isrl);CHKERRQ(ierr); 1409 ierr = ISGetLocalSize(isrl,&localsize);CHKERRQ(ierr); 1410 ierr = PetscMalloc1(localsize,&indc);CHKERRQ(ierr); 1411 ierr = ISGetIndices(isrl,&ind);CHKERRQ(ierr); 1412 ierr = PetscMemcpy(indc,ind,localsize*sizeof(PetscInt));CHKERRQ(ierr); 1413 ierr = ISRestoreIndices(isrl,&ind);CHKERRQ(ierr); 1414 ierr = ISDestroy(&isrl);CHKERRQ(ierr); 1415 for (i=0; i<localsize; i++) *(indc+i) += size; 1416 ierr = ISCreateGeneral(PetscObjectComm((PetscObject)isy),localsize,indc,PETSC_OWN_POINTER,&isr);CHKERRQ(ierr); 1417 ierr = PetscObjectReference((PetscObject)isr);CHKERRQ(ierr); 1418 ierr = ISDestroy(&ilink->is);CHKERRQ(ierr); 1419 ilink->is = isr; 1420 ierr = PetscObjectReference((PetscObject)isr);CHKERRQ(ierr); 1421 ierr = ISDestroy(&ilink->is_col);CHKERRQ(ierr); 1422 ilink->is_col = isr; 1423 ierr = ISDestroy(&isr);CHKERRQ(ierr); 1424 ierr = KSPGetPC(ilink->ksp, &subpc);CHKERRQ(ierr); 1425 ierr = PetscObjectTypeCompare((PetscObject)subpc,PCFIELDSPLIT,&flg);CHKERRQ(ierr); 1426 if(flg) { 1427 IS iszl,isz; 1428 MPI_Comm comm; 1429 ierr = ISGetLocalSize(ilink->is,&localsize);CHKERRQ(ierr); 1430 comm = PetscObjectComm((PetscObject)ilink->is); 1431 ierr = ISEmbed(isy, ilink->is, PETSC_TRUE, &iszl);CHKERRQ(ierr); 1432 ierr = MPI_Scan(&localsize,&sizez,1,MPIU_INT,MPI_SUM,comm);CHKERRQ(ierr); 1433 sizez -= localsize; 1434 ierr = ISGetLocalSize(iszl,&localsize);CHKERRQ(ierr); 1435 ierr = PetscMalloc1(localsize,&indcz);CHKERRQ(ierr); 1436 ierr = ISGetIndices(iszl,&indz);CHKERRQ(ierr); 1437 ierr = PetscMemcpy(indcz,indz,localsize*sizeof(PetscInt));CHKERRQ(ierr); 1438 ierr = ISRestoreIndices(iszl,&indz);CHKERRQ(ierr); 1439 ierr = ISDestroy(&iszl);CHKERRQ(ierr); 1440 for (i=0; i<localsize; i++) *(indcz+i) += sizez; 1441 ierr = ISCreateGeneral(comm,localsize,indcz,PETSC_OWN_POINTER,&isz);CHKERRQ(ierr); 1442 ierr = PCFieldSplitRestrictIS(subpc,isz);CHKERRQ(ierr); 1443 ierr = ISDestroy(&isz);CHKERRQ(ierr); 1444 } 1445 next = ilink->next; 1446 ilink = next; 1447 } 1448 jac->isrestrict = PETSC_TRUE; 1449 PetscFunctionReturn(0); 1450 } 1451 1452 static PetscErrorCode PCFieldSplitSetIS_FieldSplit(PC pc,const char splitname[],IS is) 1453 { 1454 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 1455 PetscErrorCode ierr; 1456 PC_FieldSplitLink ilink, next = jac->head; 1457 char prefix[128]; 1458 1459 PetscFunctionBegin; 1460 if (jac->splitdefined) { 1461 ierr = PetscInfo1(pc,"Ignoring new split \"%s\" because the splits have already been defined\n",splitname);CHKERRQ(ierr); 1462 PetscFunctionReturn(0); 1463 } 1464 ierr = PetscNew(&ilink);CHKERRQ(ierr); 1465 if (splitname) { 1466 ierr = PetscStrallocpy(splitname,&ilink->splitname);CHKERRQ(ierr); 1467 } else { 1468 ierr = PetscMalloc1(8,&ilink->splitname);CHKERRQ(ierr); 1469 ierr = PetscSNPrintf(ilink->splitname,7,"%D",jac->nsplits);CHKERRQ(ierr); 1470 } 1471 ilink->event = jac->nsplits < 5 ? KSP_Solve_FS_0 + jac->nsplits : KSP_Solve_FS_0 + 4; /* Any split great than 4 gets logged in the 4th split */ 1472 ierr = PetscObjectReference((PetscObject)is);CHKERRQ(ierr); 1473 ierr = ISDestroy(&ilink->is);CHKERRQ(ierr); 1474 ilink->is = is; 1475 ierr = PetscObjectReference((PetscObject)is);CHKERRQ(ierr); 1476 ierr = ISDestroy(&ilink->is_col);CHKERRQ(ierr); 1477 ilink->is_col = is; 1478 ilink->next = NULL; 1479 ierr = KSPCreate(PetscObjectComm((PetscObject)pc),&ilink->ksp);CHKERRQ(ierr); 1480 ierr = KSPSetErrorIfNotConverged(ilink->ksp,pc->erroriffailure);CHKERRQ(ierr); 1481 ierr = PetscObjectIncrementTabLevel((PetscObject)ilink->ksp,(PetscObject)pc,1);CHKERRQ(ierr); 1482 ierr = KSPSetType(ilink->ksp,KSPPREONLY);CHKERRQ(ierr); 1483 ierr = PetscLogObjectParent((PetscObject)pc,(PetscObject)ilink->ksp);CHKERRQ(ierr); 1484 1485 ierr = PetscSNPrintf(prefix,sizeof(prefix),"%sfieldsplit_%s_",((PetscObject)pc)->prefix ? ((PetscObject)pc)->prefix : "",ilink->splitname);CHKERRQ(ierr); 1486 ierr = KSPSetOptionsPrefix(ilink->ksp,prefix);CHKERRQ(ierr); 1487 1488 if (!next) { 1489 jac->head = ilink; 1490 ilink->previous = NULL; 1491 } else { 1492 while (next->next) { 1493 next = next->next; 1494 } 1495 next->next = ilink; 1496 ilink->previous = next; 1497 } 1498 jac->nsplits++; 1499 PetscFunctionReturn(0); 1500 } 1501 1502 /*@C 1503 PCFieldSplitSetFields - Sets the fields for one particular split in the field split preconditioner 1504 1505 Logically Collective on PC 1506 1507 Input Parameters: 1508 + pc - the preconditioner context 1509 . splitname - name of this split, if NULL the number of the split is used 1510 . n - the number of fields in this split 1511 - fields - the fields in this split 1512 1513 Level: intermediate 1514 1515 Notes: Use PCFieldSplitSetIS() to set a completely general set of indices as a field. 1516 1517 The PCFieldSplitSetFields() is for defining fields as strided blocks. For example, if the block 1518 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 1519 0xx3xx6xx9xx12 ... x1xx4xx7xx ... xx2xx5xx8xx.. 01x34x67x... 0x1x3x5x7.. x12x45x78x.... 1520 where the numbered entries indicate what is in the field. 1521 1522 This function is called once per split (it creates a new split each time). Solve options 1523 for this split will be available under the prefix -fieldsplit_SPLITNAME_. 1524 1525 Developer Note: This routine does not actually create the IS representing the split, that is delayed 1526 until PCSetUp_FieldSplit(), because information about the vector/matrix layouts may not be 1527 available when this routine is called. 1528 1529 .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetBlockSize(), PCFieldSplitSetIS() 1530 1531 @*/ 1532 PetscErrorCode PCFieldSplitSetFields(PC pc,const char splitname[],PetscInt n,const PetscInt *fields,const PetscInt *fields_col) 1533 { 1534 PetscErrorCode ierr; 1535 1536 PetscFunctionBegin; 1537 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1538 PetscValidCharPointer(splitname,2); 1539 if (n < 1) SETERRQ2(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_OUTOFRANGE,"Provided number of fields %D in split \"%s\" not positive",n,splitname); 1540 PetscValidIntPointer(fields,3); 1541 ierr = PetscTryMethod(pc,"PCFieldSplitSetFields_C",(PC,const char[],PetscInt,const PetscInt*,const PetscInt*),(pc,splitname,n,fields,fields_col));CHKERRQ(ierr); 1542 PetscFunctionReturn(0); 1543 } 1544 1545 /*@ 1546 PCFieldSplitSetDiagUseAmat - set flag indicating whether to extract diagonal blocks from Amat (rather than Pmat) 1547 1548 Logically Collective on PC 1549 1550 Input Parameters: 1551 + pc - the preconditioner object 1552 - flg - boolean flag indicating whether or not to use Amat to extract the diagonal blocks from 1553 1554 Options Database: 1555 . -pc_fieldsplit_diag_use_amat 1556 1557 Level: intermediate 1558 1559 .seealso: PCFieldSplitGetDiagUseAmat(), PCFieldSplitSetOffDiagUseAmat(), PCFIELDSPLIT 1560 1561 @*/ 1562 PetscErrorCode PCFieldSplitSetDiagUseAmat(PC pc,PetscBool flg) 1563 { 1564 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 1565 PetscBool isfs; 1566 PetscErrorCode ierr; 1567 1568 PetscFunctionBegin; 1569 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1570 ierr = PetscObjectTypeCompare((PetscObject)pc,PCFIELDSPLIT,&isfs);CHKERRQ(ierr); 1571 if (!isfs) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"PC not of type %s",PCFIELDSPLIT); 1572 jac->diag_use_amat = flg; 1573 PetscFunctionReturn(0); 1574 } 1575 1576 /*@ 1577 PCFieldSplitGetDiagUseAmat - get the flag indicating whether to extract diagonal blocks from Amat (rather than Pmat) 1578 1579 Logically Collective on PC 1580 1581 Input Parameters: 1582 . pc - the preconditioner object 1583 1584 Output Parameters: 1585 . flg - boolean flag indicating whether or not to use Amat to extract the diagonal blocks from 1586 1587 1588 Level: intermediate 1589 1590 .seealso: PCFieldSplitSetDiagUseAmat(), PCFieldSplitGetOffDiagUseAmat(), PCFIELDSPLIT 1591 1592 @*/ 1593 PetscErrorCode PCFieldSplitGetDiagUseAmat(PC pc,PetscBool *flg) 1594 { 1595 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 1596 PetscBool isfs; 1597 PetscErrorCode ierr; 1598 1599 PetscFunctionBegin; 1600 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1601 PetscValidPointer(flg,2); 1602 ierr = PetscObjectTypeCompare((PetscObject)pc,PCFIELDSPLIT,&isfs);CHKERRQ(ierr); 1603 if (!isfs) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"PC not of type %s",PCFIELDSPLIT); 1604 *flg = jac->diag_use_amat; 1605 PetscFunctionReturn(0); 1606 } 1607 1608 /*@ 1609 PCFieldSplitSetOffDiagUseAmat - set flag indicating whether to extract off-diagonal blocks from Amat (rather than Pmat) 1610 1611 Logically Collective on PC 1612 1613 Input Parameters: 1614 + pc - the preconditioner object 1615 - flg - boolean flag indicating whether or not to use Amat to extract the off-diagonal blocks from 1616 1617 Options Database: 1618 . -pc_fieldsplit_off_diag_use_amat 1619 1620 Level: intermediate 1621 1622 .seealso: PCFieldSplitGetOffDiagUseAmat(), PCFieldSplitSetDiagUseAmat(), PCFIELDSPLIT 1623 1624 @*/ 1625 PetscErrorCode PCFieldSplitSetOffDiagUseAmat(PC pc,PetscBool flg) 1626 { 1627 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 1628 PetscBool isfs; 1629 PetscErrorCode ierr; 1630 1631 PetscFunctionBegin; 1632 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1633 ierr = PetscObjectTypeCompare((PetscObject)pc,PCFIELDSPLIT,&isfs);CHKERRQ(ierr); 1634 if (!isfs) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"PC not of type %s",PCFIELDSPLIT); 1635 jac->offdiag_use_amat = flg; 1636 PetscFunctionReturn(0); 1637 } 1638 1639 /*@ 1640 PCFieldSplitGetOffDiagUseAmat - get the flag indicating whether to extract off-diagonal blocks from Amat (rather than Pmat) 1641 1642 Logically Collective on PC 1643 1644 Input Parameters: 1645 . pc - the preconditioner object 1646 1647 Output Parameters: 1648 . flg - boolean flag indicating whether or not to use Amat to extract the off-diagonal blocks from 1649 1650 1651 Level: intermediate 1652 1653 .seealso: PCFieldSplitSetOffDiagUseAmat(), PCFieldSplitGetDiagUseAmat(), PCFIELDSPLIT 1654 1655 @*/ 1656 PetscErrorCode PCFieldSplitGetOffDiagUseAmat(PC pc,PetscBool *flg) 1657 { 1658 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 1659 PetscBool isfs; 1660 PetscErrorCode ierr; 1661 1662 PetscFunctionBegin; 1663 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1664 PetscValidPointer(flg,2); 1665 ierr = PetscObjectTypeCompare((PetscObject)pc,PCFIELDSPLIT,&isfs);CHKERRQ(ierr); 1666 if (!isfs) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"PC not of type %s",PCFIELDSPLIT); 1667 *flg = jac->offdiag_use_amat; 1668 PetscFunctionReturn(0); 1669 } 1670 1671 1672 1673 /*@C 1674 PCFieldSplitSetIS - Sets the exact elements for field 1675 1676 Logically Collective on PC 1677 1678 Input Parameters: 1679 + pc - the preconditioner context 1680 . splitname - name of this split, if NULL the number of the split is used 1681 - is - the index set that defines the vector elements in this field 1682 1683 1684 Notes: 1685 Use PCFieldSplitSetFields(), for fields defined by strided types. 1686 1687 This function is called once per split (it creates a new split each time). Solve options 1688 for this split will be available under the prefix -fieldsplit_SPLITNAME_. 1689 1690 Level: intermediate 1691 1692 .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetBlockSize() 1693 1694 @*/ 1695 PetscErrorCode PCFieldSplitSetIS(PC pc,const char splitname[],IS is) 1696 { 1697 PetscErrorCode ierr; 1698 1699 PetscFunctionBegin; 1700 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1701 if (splitname) PetscValidCharPointer(splitname,2); 1702 PetscValidHeaderSpecific(is,IS_CLASSID,3); 1703 ierr = PetscTryMethod(pc,"PCFieldSplitSetIS_C",(PC,const char[],IS),(pc,splitname,is));CHKERRQ(ierr); 1704 PetscFunctionReturn(0); 1705 } 1706 1707 /*@C 1708 PCFieldSplitGetIS - Retrieves the elements for a field as an IS 1709 1710 Logically Collective on PC 1711 1712 Input Parameters: 1713 + pc - the preconditioner context 1714 - splitname - name of this split 1715 1716 Output Parameter: 1717 - is - the index set that defines the vector elements in this field, or NULL if the field is not found 1718 1719 Level: intermediate 1720 1721 .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetIS() 1722 1723 @*/ 1724 PetscErrorCode PCFieldSplitGetIS(PC pc,const char splitname[],IS *is) 1725 { 1726 PetscErrorCode ierr; 1727 1728 PetscFunctionBegin; 1729 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1730 PetscValidCharPointer(splitname,2); 1731 PetscValidPointer(is,3); 1732 { 1733 PC_FieldSplit *jac = (PC_FieldSplit*) pc->data; 1734 PC_FieldSplitLink ilink = jac->head; 1735 PetscBool found; 1736 1737 *is = NULL; 1738 while (ilink) { 1739 ierr = PetscStrcmp(ilink->splitname, splitname, &found);CHKERRQ(ierr); 1740 if (found) { 1741 *is = ilink->is; 1742 break; 1743 } 1744 ilink = ilink->next; 1745 } 1746 } 1747 PetscFunctionReturn(0); 1748 } 1749 1750 /*@ 1751 PCFieldSplitSetBlockSize - Sets the block size for defining where fields start in the 1752 fieldsplit preconditioner. If not set the matrix block size is used. 1753 1754 Logically Collective on PC 1755 1756 Input Parameters: 1757 + pc - the preconditioner context 1758 - bs - the block size 1759 1760 Level: intermediate 1761 1762 .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetFields() 1763 1764 @*/ 1765 PetscErrorCode PCFieldSplitSetBlockSize(PC pc,PetscInt bs) 1766 { 1767 PetscErrorCode ierr; 1768 1769 PetscFunctionBegin; 1770 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1771 PetscValidLogicalCollectiveInt(pc,bs,2); 1772 ierr = PetscTryMethod(pc,"PCFieldSplitSetBlockSize_C",(PC,PetscInt),(pc,bs));CHKERRQ(ierr); 1773 PetscFunctionReturn(0); 1774 } 1775 1776 /*@C 1777 PCFieldSplitGetSubKSP - Gets the KSP contexts for all splits 1778 1779 Collective on KSP 1780 1781 Input Parameter: 1782 . pc - the preconditioner context 1783 1784 Output Parameters: 1785 + n - the number of splits 1786 - subksp - the array of KSP contexts 1787 1788 Note: 1789 After PCFieldSplitGetSubKSP() the array of KSPs is to be freed by the user with PetscFree() 1790 (not the KSP just the array that contains them). 1791 1792 You must call KSPSetUp() before calling PCFieldSplitGetSubKSP(). 1793 1794 Fortran Usage: You must pass in a KSP array that is large enough to contain all the local KSPs. 1795 You can call PCFieldSplitGetSubKSP(pc,n,PETSC_NULL_KSP,ierr) to determine how large the 1796 KSP array must be. 1797 1798 1799 Level: advanced 1800 1801 .seealso: PCFIELDSPLIT 1802 @*/ 1803 PetscErrorCode PCFieldSplitGetSubKSP(PC pc,PetscInt *n,KSP *subksp[]) 1804 { 1805 PetscErrorCode ierr; 1806 1807 PetscFunctionBegin; 1808 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1809 if (n) PetscValidIntPointer(n,2); 1810 ierr = PetscUseMethod(pc,"PCFieldSplitGetSubKSP_C",(PC,PetscInt*,KSP **),(pc,n,subksp));CHKERRQ(ierr); 1811 PetscFunctionReturn(0); 1812 } 1813 1814 /*@ 1815 PCFieldSplitSetSchurPre - Indicates what operator is used to construct the preconditioner for the Schur complement. 1816 A11 matrix. Otherwise no preconditioner is used. 1817 1818 Collective on PC 1819 1820 Input Parameters: 1821 + pc - the preconditioner context 1822 . ptype - which matrix to use for preconditioning the Schur complement: PC_FIELDSPLIT_SCHUR_PRE_A11 (default), PC_FIELDSPLIT_SCHUR_PRE_SELF, PC_FIELDSPLIT_SCHUR_PRE_USER 1823 PC_FIELDSPLIT_SCHUR_PRE_SELFP, and PC_FIELDSPLIT_SCHUR_PRE_FULL 1824 - userpre - matrix to use for preconditioning, or NULL 1825 1826 Options Database: 1827 . -pc_fieldsplit_schur_precondition <self,selfp,user,a11,full> - default is a11. See notes for meaning of various arguments 1828 1829 Notes: 1830 $ If ptype is 1831 $ a11 then the preconditioner for the Schur complement is generated from the block diagonal part of the preconditioner 1832 $ matrix associated with the Schur complement (i.e. A11), not the Schur complement matrix 1833 $ self the preconditioner for the Schur complement is generated from the symbolic representation of the Schur complement matrix: 1834 $ The only preconditioner that currently works with this symbolic respresentation matrix object is the PCLSC 1835 $ preconditioner 1836 $ user then the preconditioner for the Schur complement is generated from the user provided matrix (pre argument 1837 $ to this function). 1838 $ selfp then the preconditioning for the Schur complement is generated from an explicitly-assembled approximation Sp = A11 - A10 inv(diag(A00)) A01 1839 $ This is only a good preconditioner when diag(A00) is a good preconditioner for A00. Optionally, A00 can be 1840 $ lumped before extracting the diagonal using the additional option -fieldsplit_1_mat_schur_complement_ainv_type lump 1841 $ full then the preconditioner for the Schur complement is generated from the exact Schur complement matrix representation computed internally by PFIELDSPLIT (this is expensive) 1842 $ useful mostly as a test that the Schur complement approach can work for your problem 1843 1844 When solving a saddle point problem, where the A11 block is identically zero, using a11 as the ptype only makes sense 1845 with the additional option -fieldsplit_1_pc_type none. Usually for saddle point problems one would use a ptype of self and 1846 -fieldsplit_1_pc_type lsc which uses the least squares commutator to compute a preconditioner for the Schur complement. 1847 1848 Level: intermediate 1849 1850 .seealso: PCFieldSplitGetSchurPre(), PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetFields(), PCFieldSplitSchurPreType, 1851 MatSchurComplementSetAinvType(), PCLSC 1852 1853 @*/ 1854 PetscErrorCode PCFieldSplitSetSchurPre(PC pc,PCFieldSplitSchurPreType ptype,Mat pre) 1855 { 1856 PetscErrorCode ierr; 1857 1858 PetscFunctionBegin; 1859 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1860 ierr = PetscTryMethod(pc,"PCFieldSplitSetSchurPre_C",(PC,PCFieldSplitSchurPreType,Mat),(pc,ptype,pre));CHKERRQ(ierr); 1861 PetscFunctionReturn(0); 1862 } 1863 PetscErrorCode PCFieldSplitSchurPrecondition(PC pc,PCFieldSplitSchurPreType ptype,Mat pre) {return PCFieldSplitSetSchurPre(pc,ptype,pre);} /* Deprecated name */ 1864 1865 /*@ 1866 PCFieldSplitGetSchurPre - For Schur complement fieldsplit, determine how the Schur complement will be 1867 preconditioned. See PCFieldSplitSetSchurPre() for details. 1868 1869 Logically Collective on PC 1870 1871 Input Parameters: 1872 . pc - the preconditioner context 1873 1874 Output Parameters: 1875 + ptype - which matrix to use for preconditioning the Schur complement: PC_FIELDSPLIT_SCHUR_PRE_A11, PC_FIELDSPLIT_SCHUR_PRE_SELF, PC_FIELDSPLIT_PRE_USER 1876 - userpre - matrix to use for preconditioning (with PC_FIELDSPLIT_PRE_USER), or NULL 1877 1878 Level: intermediate 1879 1880 .seealso: PCFieldSplitSetSchurPre(), PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetFields(), PCFieldSplitSchurPreType, PCLSC 1881 1882 @*/ 1883 PetscErrorCode PCFieldSplitGetSchurPre(PC pc,PCFieldSplitSchurPreType *ptype,Mat *pre) 1884 { 1885 PetscErrorCode ierr; 1886 1887 PetscFunctionBegin; 1888 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1889 ierr = PetscUseMethod(pc,"PCFieldSplitGetSchurPre_C",(PC,PCFieldSplitSchurPreType*,Mat*),(pc,ptype,pre));CHKERRQ(ierr); 1890 PetscFunctionReturn(0); 1891 } 1892 1893 /*@ 1894 PCFieldSplitSchurGetS - extract the MatSchurComplement object used by this PC in case it needs to be configured separately 1895 1896 Not collective 1897 1898 Input Parameter: 1899 . pc - the preconditioner context 1900 1901 Output Parameter: 1902 . S - the Schur complement matrix 1903 1904 Notes: 1905 This matrix should not be destroyed using MatDestroy(); rather, use PCFieldSplitSchurRestoreS(). 1906 1907 Level: advanced 1908 1909 .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSchurPreType, PCFieldSplitSetSchurPre(), MatSchurComplement, PCFieldSplitSchurRestoreS() 1910 1911 @*/ 1912 PetscErrorCode PCFieldSplitSchurGetS(PC pc,Mat *S) 1913 { 1914 PetscErrorCode ierr; 1915 const char* t; 1916 PetscBool isfs; 1917 PC_FieldSplit *jac; 1918 1919 PetscFunctionBegin; 1920 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1921 ierr = PetscObjectGetType((PetscObject)pc,&t);CHKERRQ(ierr); 1922 ierr = PetscStrcmp(t,PCFIELDSPLIT,&isfs);CHKERRQ(ierr); 1923 if (!isfs) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Expected PC of type PCFIELDSPLIT, got %s instead",t); 1924 jac = (PC_FieldSplit*)pc->data; 1925 if (jac->type != PC_COMPOSITE_SCHUR) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Expected PCFIELDSPLIT of type SCHUR, got %D instead",jac->type); 1926 if (S) *S = jac->schur; 1927 PetscFunctionReturn(0); 1928 } 1929 1930 /*@ 1931 PCFieldSplitSchurRestoreS - restores the MatSchurComplement object used by this PC 1932 1933 Not collective 1934 1935 Input Parameters: 1936 + pc - the preconditioner context 1937 . S - the Schur complement matrix 1938 1939 Level: advanced 1940 1941 .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSchurPreType, PCFieldSplitSetSchurPre(), MatSchurComplement, PCFieldSplitSchurGetS() 1942 1943 @*/ 1944 PetscErrorCode PCFieldSplitSchurRestoreS(PC pc,Mat *S) 1945 { 1946 PetscErrorCode ierr; 1947 const char* t; 1948 PetscBool isfs; 1949 PC_FieldSplit *jac; 1950 1951 PetscFunctionBegin; 1952 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1953 ierr = PetscObjectGetType((PetscObject)pc,&t);CHKERRQ(ierr); 1954 ierr = PetscStrcmp(t,PCFIELDSPLIT,&isfs);CHKERRQ(ierr); 1955 if (!isfs) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Expected PC of type PCFIELDSPLIT, got %s instead",t); 1956 jac = (PC_FieldSplit*)pc->data; 1957 if (jac->type != PC_COMPOSITE_SCHUR) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Expected PCFIELDSPLIT of type SCHUR, got %D instead",jac->type); 1958 if (!S || *S != jac->schur) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"MatSchurComplement restored is not the same as gotten"); 1959 PetscFunctionReturn(0); 1960 } 1961 1962 1963 static PetscErrorCode PCFieldSplitSetSchurPre_FieldSplit(PC pc,PCFieldSplitSchurPreType ptype,Mat pre) 1964 { 1965 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 1966 PetscErrorCode ierr; 1967 1968 PetscFunctionBegin; 1969 jac->schurpre = ptype; 1970 if (ptype == PC_FIELDSPLIT_SCHUR_PRE_USER && pre) { 1971 ierr = MatDestroy(&jac->schur_user);CHKERRQ(ierr); 1972 jac->schur_user = pre; 1973 ierr = PetscObjectReference((PetscObject)jac->schur_user);CHKERRQ(ierr); 1974 } 1975 PetscFunctionReturn(0); 1976 } 1977 1978 static PetscErrorCode PCFieldSplitGetSchurPre_FieldSplit(PC pc,PCFieldSplitSchurPreType *ptype,Mat *pre) 1979 { 1980 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 1981 1982 PetscFunctionBegin; 1983 *ptype = jac->schurpre; 1984 *pre = jac->schur_user; 1985 PetscFunctionReturn(0); 1986 } 1987 1988 /*@ 1989 PCFieldSplitSetSchurFactType - sets which blocks of the approximate block factorization to retain in the preconditioner 1990 1991 Collective on PC 1992 1993 Input Parameters: 1994 + pc - the preconditioner context 1995 - ftype - which blocks of factorization to retain, PC_FIELDSPLIT_SCHUR_FACT_FULL is default 1996 1997 Options Database: 1998 . -pc_fieldsplit_schur_fact_type <diag,lower,upper,full> default is full 1999 2000 2001 Level: intermediate 2002 2003 Notes: 2004 The FULL factorization is 2005 2006 $ (A B) = (1 0) (A 0) (1 Ainv*B) = L D U 2007 $ (C E) (C*Ainv 1) (0 S) (0 1 ) 2008 2009 where S = E - 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, 2010 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). Sign flipping of S can be turned off with PCFieldSplitSetSchurScale(). 2011 2012 $ If A and S are solved exactly 2013 $ *) FULL factorization is a direct solver. 2014 $ *) The preconditioned operator with LOWER or UPPER has all eigenvalues equal to 1 and minimal polynomial of degree 2, so KSPGMRES converges in 2 iterations. 2015 $ *) With DIAG, the preconditioned operator has three distinct nonzero eigenvalues and minimal polynomial of degree at most 4, so KSPGMRES converges in at most 4 iterations. 2016 2017 If the iteration count is very low, consider using KSPFGMRES or KSPGCR which can use one less preconditioner 2018 application in this case. Note that the preconditioned operator may be highly non-normal, so such fast convergence may not be observed in practice. 2019 2020 For symmetric problems in which A is positive definite and S is negative definite, DIAG can be used with KSPMINRES. 2021 2022 Note that a flexible method like KSPFGMRES or KSPGCR must be used if the fieldsplit preconditioner is nonlinear (e.g. a few iterations of a Krylov method is used to solve with A or S). 2023 2024 References: 2025 + 1. - Murphy, Golub, and Wathen, A note on preconditioning indefinite linear systems, SIAM J. Sci. Comput., 21 (2000). 2026 - 2. - Ipsen, A note on preconditioning nonsymmetric matrices, SIAM J. Sci. Comput., 23 (2001). 2027 2028 .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetFields(), PCFieldSplitSchurPreType, PCFieldSplitSetSchurScale() 2029 @*/ 2030 PetscErrorCode PCFieldSplitSetSchurFactType(PC pc,PCFieldSplitSchurFactType ftype) 2031 { 2032 PetscErrorCode ierr; 2033 2034 PetscFunctionBegin; 2035 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 2036 ierr = PetscTryMethod(pc,"PCFieldSplitSetSchurFactType_C",(PC,PCFieldSplitSchurFactType),(pc,ftype));CHKERRQ(ierr); 2037 PetscFunctionReturn(0); 2038 } 2039 2040 static PetscErrorCode PCFieldSplitSetSchurFactType_FieldSplit(PC pc,PCFieldSplitSchurFactType ftype) 2041 { 2042 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 2043 2044 PetscFunctionBegin; 2045 jac->schurfactorization = ftype; 2046 PetscFunctionReturn(0); 2047 } 2048 2049 /*@ 2050 PCFieldSplitSetSchurScale - Controls the sign flip of S for PC_FIELDSPLIT_SCHUR_FACT_DIAG. 2051 2052 Collective on PC 2053 2054 Input Parameters: 2055 + pc - the preconditioner context 2056 - scale - scaling factor for the Schur complement 2057 2058 Options Database: 2059 . -pc_fieldsplit_schur_scale - default is -1.0 2060 2061 Level: intermediate 2062 2063 .seealso: PCFIELDSPLIT, PCFieldSplitSetFields(), PCFieldSplitSchurFactType, PCFieldSplitSetSchurScale() 2064 @*/ 2065 PetscErrorCode PCFieldSplitSetSchurScale(PC pc,PetscScalar scale) 2066 { 2067 PetscErrorCode ierr; 2068 2069 PetscFunctionBegin; 2070 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 2071 PetscValidLogicalCollectiveScalar(pc,scale,2); 2072 ierr = PetscTryMethod(pc,"PCFieldSplitSetSchurScale_C",(PC,PetscScalar),(pc,scale));CHKERRQ(ierr); 2073 PetscFunctionReturn(0); 2074 } 2075 2076 static PetscErrorCode PCFieldSplitSetSchurScale_FieldSplit(PC pc,PetscScalar scale) 2077 { 2078 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 2079 2080 PetscFunctionBegin; 2081 jac->schurscale = scale; 2082 PetscFunctionReturn(0); 2083 } 2084 2085 /*@C 2086 PCFieldSplitGetSchurBlocks - Gets all matrix blocks for the Schur complement 2087 2088 Collective on KSP 2089 2090 Input Parameter: 2091 . pc - the preconditioner context 2092 2093 Output Parameters: 2094 + A00 - the (0,0) block 2095 . A01 - the (0,1) block 2096 . A10 - the (1,0) block 2097 - A11 - the (1,1) block 2098 2099 Level: advanced 2100 2101 .seealso: PCFIELDSPLIT 2102 @*/ 2103 PetscErrorCode PCFieldSplitGetSchurBlocks(PC pc,Mat *A00,Mat *A01,Mat *A10, Mat *A11) 2104 { 2105 PC_FieldSplit *jac = (PC_FieldSplit*) pc->data; 2106 2107 PetscFunctionBegin; 2108 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 2109 if (jac->type != PC_COMPOSITE_SCHUR) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONG, "FieldSplit is not using a Schur complement approach."); 2110 if (A00) *A00 = jac->pmat[0]; 2111 if (A01) *A01 = jac->B; 2112 if (A10) *A10 = jac->C; 2113 if (A11) *A11 = jac->pmat[1]; 2114 PetscFunctionReturn(0); 2115 } 2116 2117 static PetscErrorCode PCFieldSplitSetType_FieldSplit(PC pc,PCCompositeType type) 2118 { 2119 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 2120 PetscErrorCode ierr; 2121 2122 PetscFunctionBegin; 2123 jac->type = type; 2124 if (type == PC_COMPOSITE_SCHUR) { 2125 pc->ops->apply = PCApply_FieldSplit_Schur; 2126 pc->ops->view = PCView_FieldSplit_Schur; 2127 2128 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitGetSubKSP_C",PCFieldSplitGetSubKSP_FieldSplit_Schur);CHKERRQ(ierr); 2129 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitSetSchurPre_C",PCFieldSplitSetSchurPre_FieldSplit);CHKERRQ(ierr); 2130 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitGetSchurPre_C",PCFieldSplitGetSchurPre_FieldSplit);CHKERRQ(ierr); 2131 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitSetSchurFactType_C",PCFieldSplitSetSchurFactType_FieldSplit);CHKERRQ(ierr); 2132 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitSetSchurScale_C",PCFieldSplitSetSchurScale_FieldSplit);CHKERRQ(ierr); 2133 2134 } else { 2135 pc->ops->apply = PCApply_FieldSplit; 2136 pc->ops->view = PCView_FieldSplit; 2137 2138 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitGetSubKSP_C",PCFieldSplitGetSubKSP_FieldSplit);CHKERRQ(ierr); 2139 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitSetSchurPre_C",0);CHKERRQ(ierr); 2140 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitGetSchurPre_C",0);CHKERRQ(ierr); 2141 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitSetSchurFactType_C",0);CHKERRQ(ierr); 2142 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitSetSchurScale_C",0);CHKERRQ(ierr); 2143 } 2144 PetscFunctionReturn(0); 2145 } 2146 2147 static PetscErrorCode PCFieldSplitSetBlockSize_FieldSplit(PC pc,PetscInt bs) 2148 { 2149 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 2150 2151 PetscFunctionBegin; 2152 if (bs < 1) SETERRQ1(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_OUTOFRANGE,"Blocksize must be positive, you gave %D",bs); 2153 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); 2154 jac->bs = bs; 2155 PetscFunctionReturn(0); 2156 } 2157 2158 /*@ 2159 PCFieldSplitSetType - Sets the type of fieldsplit preconditioner. 2160 2161 Collective on PC 2162 2163 Input Parameter: 2164 . pc - the preconditioner context 2165 . type - PC_COMPOSITE_ADDITIVE, PC_COMPOSITE_MULTIPLICATIVE (default), PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE, PC_COMPOSITE_SPECIAL, PC_COMPOSITE_SCHUR 2166 2167 Options Database Key: 2168 . -pc_fieldsplit_type <type: one of multiplicative, additive, symmetric_multiplicative, special, schur> - Sets fieldsplit preconditioner type 2169 2170 Level: Intermediate 2171 2172 .keywords: PC, set, type, composite preconditioner, additive, multiplicative 2173 2174 .seealso: PCCompositeSetType() 2175 2176 @*/ 2177 PetscErrorCode PCFieldSplitSetType(PC pc,PCCompositeType type) 2178 { 2179 PetscErrorCode ierr; 2180 2181 PetscFunctionBegin; 2182 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 2183 ierr = PetscTryMethod(pc,"PCFieldSplitSetType_C",(PC,PCCompositeType),(pc,type));CHKERRQ(ierr); 2184 PetscFunctionReturn(0); 2185 } 2186 2187 /*@ 2188 PCFieldSplitGetType - Gets the type of fieldsplit preconditioner. 2189 2190 Not collective 2191 2192 Input Parameter: 2193 . pc - the preconditioner context 2194 2195 Output Parameter: 2196 . type - PC_COMPOSITE_ADDITIVE, PC_COMPOSITE_MULTIPLICATIVE (default), PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE, PC_COMPOSITE_SPECIAL, PC_COMPOSITE_SCHUR 2197 2198 Level: Intermediate 2199 2200 .keywords: PC, set, type, composite preconditioner, additive, multiplicative 2201 .seealso: PCCompositeSetType() 2202 @*/ 2203 PetscErrorCode PCFieldSplitGetType(PC pc, PCCompositeType *type) 2204 { 2205 PC_FieldSplit *jac = (PC_FieldSplit*) pc->data; 2206 2207 PetscFunctionBegin; 2208 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 2209 PetscValidIntPointer(type,2); 2210 *type = jac->type; 2211 PetscFunctionReturn(0); 2212 } 2213 2214 /*@ 2215 PCFieldSplitSetDMSplits - Flags whether DMCreateFieldDecomposition() should be used to define the splits, whenever possible. 2216 2217 Logically Collective 2218 2219 Input Parameters: 2220 + pc - the preconditioner context 2221 - flg - boolean indicating whether to use field splits defined by the DM 2222 2223 Options Database Key: 2224 . -pc_fieldsplit_dm_splits 2225 2226 Level: Intermediate 2227 2228 .keywords: PC, DM, composite preconditioner, additive, multiplicative 2229 2230 .seealso: PCFieldSplitGetDMSplits() 2231 2232 @*/ 2233 PetscErrorCode PCFieldSplitSetDMSplits(PC pc,PetscBool flg) 2234 { 2235 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 2236 PetscBool isfs; 2237 PetscErrorCode ierr; 2238 2239 PetscFunctionBegin; 2240 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 2241 PetscValidLogicalCollectiveBool(pc,flg,2); 2242 ierr = PetscObjectTypeCompare((PetscObject)pc,PCFIELDSPLIT,&isfs);CHKERRQ(ierr); 2243 if (isfs) { 2244 jac->dm_splits = flg; 2245 } 2246 PetscFunctionReturn(0); 2247 } 2248 2249 2250 /*@ 2251 PCFieldSplitGetDMSplits - Returns flag indicating whether DMCreateFieldDecomposition() should be used to define the splits, whenever possible. 2252 2253 Logically Collective 2254 2255 Input Parameter: 2256 . pc - the preconditioner context 2257 2258 Output Parameter: 2259 . flg - boolean indicating whether to use field splits defined by the DM 2260 2261 Level: Intermediate 2262 2263 .keywords: PC, DM, composite preconditioner, additive, multiplicative 2264 2265 .seealso: PCFieldSplitSetDMSplits() 2266 2267 @*/ 2268 PetscErrorCode PCFieldSplitGetDMSplits(PC pc,PetscBool* flg) 2269 { 2270 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 2271 PetscBool isfs; 2272 PetscErrorCode ierr; 2273 2274 PetscFunctionBegin; 2275 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 2276 PetscValidPointer(flg,2); 2277 ierr = PetscObjectTypeCompare((PetscObject)pc,PCFIELDSPLIT,&isfs);CHKERRQ(ierr); 2278 if (isfs) { 2279 if(flg) *flg = jac->dm_splits; 2280 } 2281 PetscFunctionReturn(0); 2282 } 2283 2284 /* -------------------------------------------------------------------------------------*/ 2285 /*MC 2286 PCFIELDSPLIT - Preconditioner created by combining separate preconditioners for individual 2287 fields or groups of fields. See the users manual section "Solving Block Matrices" for more details. 2288 2289 To set options on the solvers for each block append -fieldsplit_ to all the PC 2290 options database keys. For example, -fieldsplit_pc_type ilu -fieldsplit_pc_factor_levels 1 2291 2292 To set the options on the solvers separate for each block call PCFieldSplitGetSubKSP() 2293 and set the options directly on the resulting KSP object 2294 2295 Level: intermediate 2296 2297 Options Database Keys: 2298 + -pc_fieldsplit_%d_fields <a,b,..> - indicates the fields to be used in the %d'th split 2299 . -pc_fieldsplit_default - automatically add any fields to additional splits that have not 2300 been supplied explicitly by -pc_fieldsplit_%d_fields 2301 . -pc_fieldsplit_block_size <bs> - size of block that defines fields (i.e. there are bs fields) 2302 . -pc_fieldsplit_type <additive,multiplicative,symmetric_multiplicative,schur> - type of relaxation or factorization splitting 2303 . -pc_fieldsplit_schur_precondition <self,selfp,user,a11,full> - default is a11; see PCFieldSplitSetSchurPre() 2304 . -pc_fieldsplit_detect_saddle_point - automatically finds rows with zero or negative diagonal and uses Schur complement with no preconditioner as the solver 2305 2306 - Options prefix for inner solvers when using Schur complement preconditioner are -fieldsplit_0_ and -fieldsplit_1_ 2307 for all other solvers they are -fieldsplit_%d_ for the dth field, use -fieldsplit_ for all fields 2308 2309 Notes: 2310 Use PCFieldSplitSetFields() to set fields defined by "strided" entries and PCFieldSplitSetIS() 2311 to define a field by an arbitrary collection of entries. 2312 2313 If no fields are set the default is used. The fields are defined by entries strided by bs, 2314 beginning at 0 then 1, etc to bs-1. The block size can be set with PCFieldSplitSetBlockSize(), 2315 if this is not called the block size defaults to the blocksize of the second matrix passed 2316 to KSPSetOperators()/PCSetOperators(). 2317 2318 $ For the Schur complement preconditioner if J = ( A00 A01 ) 2319 $ ( A10 A11 ) 2320 $ the preconditioner using full factorization is 2321 $ ( I -ksp(A00) A01 ) ( inv(A00) 0 ) ( I 0 ) 2322 $ ( 0 I ) ( 0 ksp(S) ) ( -A10 ksp(A00) I ) 2323 where the action of inv(A00) is applied using the KSP solver with prefix -fieldsplit_0_. S is the Schur complement 2324 $ S = A11 - A10 ksp(A00) A01 2325 which is usually dense and not stored explicitly. The action of ksp(S) is computed using the KSP solver with prefix -fieldsplit_splitname_ (where splitname was given 2326 in providing the SECOND split or 1 if not give). For PCFieldSplitGetKSP() when field number is 0, 2327 it returns the KSP associated with -fieldsplit_0_ while field number 1 gives -fieldsplit_1_ KSP. By default 2328 A11 is used to construct a preconditioner for S, use PCFieldSplitSetSchurPre() for all the possible ways to construct the preconditioner for S. 2329 2330 The factorization type is set using -pc_fieldsplit_schur_fact_type <diag, lower, upper, full>. The full is shown above, 2331 diag gives 2332 $ ( inv(A00) 0 ) 2333 $ ( 0 -ksp(S) ) 2334 note that slightly counter intuitively there is a negative in front of the ksp(S) so that the preconditioner is positive definite. For SPD matrices J, the sign flip 2335 can be turned off with PCFieldSplitSetSchurScale() or by command line -pc_fieldsplit_schur_scale 1.0. The lower factorization is the inverse of 2336 $ ( A00 0 ) 2337 $ ( A10 S ) 2338 where the inverses of A00 and S are applied using KSPs. The upper factorization is the inverse of 2339 $ ( A00 A01 ) 2340 $ ( 0 S ) 2341 where again the inverses of A00 and S are applied using KSPs. 2342 2343 If only one set of indices (one IS) is provided with PCFieldSplitSetIS() then the complement of that IS 2344 is used automatically for a second block. 2345 2346 The fieldsplit preconditioner cannot currently be used with the BAIJ or SBAIJ data formats if the blocksize is larger than 1. 2347 Generally it should be used with the AIJ format. 2348 2349 The forms of these preconditioners are closely related if not identical to forms derived as "Distributive Iterations", see, 2350 for example, page 294 in "Principles of Computational Fluid Dynamics" by Pieter Wesseling. Note that one can also use PCFIELDSPLIT 2351 inside a smoother resulting in "Distributive Smoothers". 2352 2353 Concepts: physics based preconditioners, block preconditioners 2354 2355 There is a nice discussion of block preconditioners in 2356 2357 [El08] A taxonomy and comparison of parallel block multi-level preconditioners for the incompressible Navier-Stokes equations 2358 Howard Elman, V.E. Howle, John Shadid, Robert Shuttleworth, Ray Tuminaro, Journal of Computational Physics 227 (2008) 1790--1808 2359 http://chess.cs.umd.edu/~elman/papers/tax.pdf 2360 2361 The Constrained Pressure Preconditioner (CPR) can be implemented using PCCOMPOSITE with PCGALERKIN. CPR first solves an R A P subsystem, updates the 2362 residual on all variables (PCCompositeSetType(pc,PC_COMPOSITE_MULTIPLICATIVE)), and then applies a simple ILU like preconditioner on all the variables. 2363 2364 .seealso: PCCreate(), PCSetType(), PCType (for list of available types), PC, Block_Preconditioners, PCLSC, 2365 PCFieldSplitGetSubKSP(), PCFieldSplitSetFields(), PCFieldSplitSetType(), PCFieldSplitSetIS(), PCFieldSplitSetSchurPre(), 2366 MatSchurComplementSetAinvType(), PCFieldSplitSetSchurScale() 2367 M*/ 2368 2369 PETSC_EXTERN PetscErrorCode PCCreate_FieldSplit(PC pc) 2370 { 2371 PetscErrorCode ierr; 2372 PC_FieldSplit *jac; 2373 2374 PetscFunctionBegin; 2375 ierr = PetscNewLog(pc,&jac);CHKERRQ(ierr); 2376 2377 jac->bs = -1; 2378 jac->nsplits = 0; 2379 jac->type = PC_COMPOSITE_MULTIPLICATIVE; 2380 jac->schurpre = PC_FIELDSPLIT_SCHUR_PRE_USER; /* Try user preconditioner first, fall back on diagonal */ 2381 jac->schurfactorization = PC_FIELDSPLIT_SCHUR_FACT_FULL; 2382 jac->schurscale = -1.0; 2383 jac->dm_splits = PETSC_TRUE; 2384 2385 pc->data = (void*)jac; 2386 2387 pc->ops->apply = PCApply_FieldSplit; 2388 pc->ops->applytranspose = PCApplyTranspose_FieldSplit; 2389 pc->ops->setup = PCSetUp_FieldSplit; 2390 pc->ops->reset = PCReset_FieldSplit; 2391 pc->ops->destroy = PCDestroy_FieldSplit; 2392 pc->ops->setfromoptions = PCSetFromOptions_FieldSplit; 2393 pc->ops->view = PCView_FieldSplit; 2394 pc->ops->applyrichardson = 0; 2395 2396 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitGetSubKSP_C",PCFieldSplitGetSubKSP_FieldSplit);CHKERRQ(ierr); 2397 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitSetFields_C",PCFieldSplitSetFields_FieldSplit);CHKERRQ(ierr); 2398 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitSetIS_C",PCFieldSplitSetIS_FieldSplit);CHKERRQ(ierr); 2399 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitSetType_C",PCFieldSplitSetType_FieldSplit);CHKERRQ(ierr); 2400 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitSetBlockSize_C",PCFieldSplitSetBlockSize_FieldSplit);CHKERRQ(ierr); 2401 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitRestrictIS_C",PCFieldSplitRestrictIS_FieldSplit);CHKERRQ(ierr); 2402 PetscFunctionReturn(0); 2403 } 2404 2405 2406 2407