1 #include <petsc/private/pcimpl.h> /*I "petscpc.h" I*/ 2 #include <petsc/private/kspimpl.h> /* This is needed to provide the appropriate PETSC_EXTERN for KSP_Solve_FS ....*/ 3 #include <petscdm.h> 4 5 const char *const PCFieldSplitSchurPreTypes[] = {"SELF","SELFP","A11","USER","FULL","PCFieldSplitSchurPreType","PC_FIELDSPLIT_SCHUR_PRE_",0}; 6 const char *const PCFieldSplitSchurFactTypes[] = {"DIAG","LOWER","UPPER","FULL","PCFieldSplitSchurFactType","PC_FIELDSPLIT_SCHUR_FACT_",0}; 7 8 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; 9 10 typedef struct _PC_FieldSplitLink *PC_FieldSplitLink; 11 struct _PC_FieldSplitLink { 12 KSP ksp; 13 Vec x,y,z; 14 char *splitname; 15 PetscInt nfields; 16 PetscInt *fields,*fields_col; 17 VecScatter sctx; 18 IS is,is_col; 19 PC_FieldSplitLink next,previous; 20 PetscLogEvent event; 21 }; 22 23 typedef struct { 24 PCCompositeType type; 25 PetscBool defaultsplit; /* Flag for a system with a set of 'k' scalar fields with the same layout (and bs = k) */ 26 PetscBool splitdefined; /* Flag is set after the splits have been defined, to prevent more splits from being added */ 27 PetscInt bs; /* Block size for IS and Mat structures */ 28 PetscInt nsplits; /* Number of field divisions defined */ 29 Vec *x,*y,w1,w2; 30 Mat *mat; /* The diagonal block for each split */ 31 Mat *pmat; /* The preconditioning diagonal block for each split */ 32 Mat *Afield; /* The rows of the matrix associated with each split */ 33 PetscBool issetup; 34 35 /* Only used when Schur complement preconditioning is used */ 36 Mat B; /* The (0,1) block */ 37 Mat C; /* The (1,0) block */ 38 Mat schur; /* The Schur complement S = A11 - A10 A00^{-1} A01, the KSP here, kspinner, is H_1 in [El08] */ 39 Mat schurp; /* Assembled approximation to S built by MatSchurComplement to be used as a preconditioning matrix when solving with S */ 40 Mat schur_user; /* User-provided preconditioning matrix for the Schur complement */ 41 PCFieldSplitSchurPreType schurpre; /* Determines which preconditioning matrix is used for the Schur complement */ 42 PCFieldSplitSchurFactType schurfactorization; 43 KSP kspschur; /* The solver for S */ 44 KSP kspupper; /* The solver for A in the upper diagonal part of the factorization (H_2 in [El08]) */ 45 PetscScalar schurscale; /* Scaling factor for the Schur complement solution with DIAG factorization */ 46 47 /* Only used when Golub-Kahan bidiagonalization preconditioning is used */ 48 Mat H; /* The modified matrix H = A00 + nu*A01*A01' */ 49 PetscReal gkbtol; /* Stopping tolerance for lower bound estimate */ 50 PetscInt gkbdelay; /* The delay window for the stopping criterion */ 51 PetscReal gkbnu; /* Parameter for augmented Lagrangian H = A + nu*A01*A01' */ 52 PetscInt gkbmaxit; /* Maximum number of iterations for outer loop */ 53 PetscBool gkbmonitor; /* Monitor for gkb iterations and the lower bound error */ 54 PetscViewer gkbviewer; /* Viewer context for gkbmonitor */ 55 Vec u,v,d,Hu; /* Work vectors for the GKB algorithm */ 56 PetscScalar *vecz; /* Contains intermediate values, eg for lower bound */ 57 58 PC_FieldSplitLink head; 59 PetscBool isrestrict; /* indicates PCFieldSplitRestrictIS() has been last called on this object, hack */ 60 PetscBool suboptionsset; /* Indicates that the KSPSetFromOptions() has been called on the sub-KSPs */ 61 PetscBool dm_splits; /* Whether to use DMCreateFieldDecomposition() whenever possible */ 62 PetscBool diag_use_amat; /* Whether to extract diagonal matrix blocks from Amat, rather than Pmat (weaker than -pc_use_amat) */ 63 PetscBool offdiag_use_amat; /* Whether to extract off-diagonal matrix blocks from Amat, rather than Pmat (weaker than -pc_use_amat) */ 64 PetscBool detect; /* Whether to form 2-way split by finding zero diagonal entries */ 65 } PC_FieldSplit; 66 67 /* 68 Notes: 69 there is no particular reason that pmat, x, and y are stored as arrays in PC_FieldSplit instead of 70 inside PC_FieldSplitLink, just historical. If you want to be able to add new fields after already using the 71 PC you could change this. 72 */ 73 74 /* This helper is so that setting a user-provided preconditioning matrix is orthogonal to choosing to use it. This way the 75 * application-provided FormJacobian can provide this matrix without interfering with the user's (command-line) choices. */ 76 static Mat FieldSplitSchurPre(PC_FieldSplit *jac) 77 { 78 switch (jac->schurpre) { 79 case PC_FIELDSPLIT_SCHUR_PRE_SELF: return jac->schur; 80 case PC_FIELDSPLIT_SCHUR_PRE_SELFP: return jac->schurp; 81 case PC_FIELDSPLIT_SCHUR_PRE_A11: return jac->pmat[1]; 82 case PC_FIELDSPLIT_SCHUR_PRE_FULL: /* We calculate this and store it in schur_user */ 83 case PC_FIELDSPLIT_SCHUR_PRE_USER: /* Use a user-provided matrix if it is given, otherwise diagonal block */ 84 default: 85 return jac->schur_user ? jac->schur_user : jac->pmat[1]; 86 } 87 } 88 89 90 #include <petscdraw.h> 91 static PetscErrorCode PCView_FieldSplit(PC pc,PetscViewer viewer) 92 { 93 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 94 PetscErrorCode ierr; 95 PetscBool iascii,isdraw; 96 PetscInt i,j; 97 PC_FieldSplitLink ilink = jac->head; 98 99 PetscFunctionBegin; 100 ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr); 101 ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERDRAW,&isdraw);CHKERRQ(ierr); 102 if (iascii) { 103 if (jac->bs > 0) { 104 ierr = PetscViewerASCIIPrintf(viewer," FieldSplit with %s composition: total splits = %D, blocksize = %D\n",PCCompositeTypes[jac->type],jac->nsplits,jac->bs);CHKERRQ(ierr); 105 } else { 106 ierr = PetscViewerASCIIPrintf(viewer," FieldSplit with %s composition: total splits = %D\n",PCCompositeTypes[jac->type],jac->nsplits);CHKERRQ(ierr); 107 } 108 if (pc->useAmat) { 109 ierr = PetscViewerASCIIPrintf(viewer," using Amat (not Pmat) as operator for blocks\n");CHKERRQ(ierr); 110 } 111 if (jac->diag_use_amat) { 112 ierr = PetscViewerASCIIPrintf(viewer," using Amat (not Pmat) as operator for diagonal blocks\n");CHKERRQ(ierr); 113 } 114 if (jac->offdiag_use_amat) { 115 ierr = PetscViewerASCIIPrintf(viewer," using Amat (not Pmat) as operator for off-diagonal blocks\n");CHKERRQ(ierr); 116 } 117 ierr = PetscViewerASCIIPrintf(viewer," Solver info for each split is in the following KSP objects:\n");CHKERRQ(ierr); 118 for (i=0; i<jac->nsplits; i++) { 119 if (ilink->fields) { 120 ierr = PetscViewerASCIIPrintf(viewer,"Split number %D Fields ",i);CHKERRQ(ierr); 121 ierr = PetscViewerASCIIUseTabs(viewer,PETSC_FALSE);CHKERRQ(ierr); 122 for (j=0; j<ilink->nfields; j++) { 123 if (j > 0) { 124 ierr = PetscViewerASCIIPrintf(viewer,",");CHKERRQ(ierr); 125 } 126 ierr = PetscViewerASCIIPrintf(viewer," %D",ilink->fields[j]);CHKERRQ(ierr); 127 } 128 ierr = PetscViewerASCIIPrintf(viewer,"\n");CHKERRQ(ierr); 129 ierr = PetscViewerASCIIUseTabs(viewer,PETSC_TRUE);CHKERRQ(ierr); 130 } else { 131 ierr = PetscViewerASCIIPrintf(viewer,"Split number %D Defined by IS\n",i);CHKERRQ(ierr); 132 } 133 ierr = KSPView(ilink->ksp,viewer);CHKERRQ(ierr); 134 ilink = ilink->next; 135 } 136 } 137 138 if (isdraw) { 139 PetscDraw draw; 140 PetscReal x,y,w,wd; 141 142 ierr = PetscViewerDrawGetDraw(viewer,0,&draw);CHKERRQ(ierr); 143 ierr = PetscDrawGetCurrentPoint(draw,&x,&y);CHKERRQ(ierr); 144 w = 2*PetscMin(1.0 - x,x); 145 wd = w/(jac->nsplits + 1); 146 x = x - wd*(jac->nsplits-1)/2.0; 147 for (i=0; i<jac->nsplits; i++) { 148 ierr = PetscDrawPushCurrentPoint(draw,x,y);CHKERRQ(ierr); 149 ierr = KSPView(ilink->ksp,viewer);CHKERRQ(ierr); 150 ierr = PetscDrawPopCurrentPoint(draw);CHKERRQ(ierr); 151 x += wd; 152 ilink = ilink->next; 153 } 154 } 155 PetscFunctionReturn(0); 156 } 157 158 static PetscErrorCode PCView_FieldSplit_Schur(PC pc,PetscViewer viewer) 159 { 160 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 161 PetscErrorCode ierr; 162 PetscBool iascii,isdraw; 163 PetscInt i,j; 164 PC_FieldSplitLink ilink = jac->head; 165 MatSchurComplementAinvType atype; 166 167 PetscFunctionBegin; 168 ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr); 169 ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERDRAW,&isdraw);CHKERRQ(ierr); 170 if (iascii) { 171 if (jac->bs > 0) { 172 ierr = PetscViewerASCIIPrintf(viewer," FieldSplit with Schur preconditioner, blocksize = %D, factorization %s\n",jac->bs,PCFieldSplitSchurFactTypes[jac->schurfactorization]);CHKERRQ(ierr); 173 } else { 174 ierr = PetscViewerASCIIPrintf(viewer," FieldSplit with Schur preconditioner, factorization %s\n",PCFieldSplitSchurFactTypes[jac->schurfactorization]);CHKERRQ(ierr); 175 } 176 if (pc->useAmat) { 177 ierr = PetscViewerASCIIPrintf(viewer," using Amat (not Pmat) as operator for blocks\n");CHKERRQ(ierr); 178 } 179 switch (jac->schurpre) { 180 case PC_FIELDSPLIT_SCHUR_PRE_SELF: 181 ierr = PetscViewerASCIIPrintf(viewer," Preconditioner for the Schur complement formed from S itself\n");CHKERRQ(ierr); 182 break; 183 case PC_FIELDSPLIT_SCHUR_PRE_SELFP: 184 ierr = MatSchurComplementGetAinvType(jac->schur,&atype);CHKERRQ(ierr); 185 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; 186 case PC_FIELDSPLIT_SCHUR_PRE_A11: 187 ierr = PetscViewerASCIIPrintf(viewer," Preconditioner for the Schur complement formed from A11\n");CHKERRQ(ierr); 188 break; 189 case PC_FIELDSPLIT_SCHUR_PRE_FULL: 190 ierr = PetscViewerASCIIPrintf(viewer," Preconditioner for the Schur complement formed from the exact Schur complement\n");CHKERRQ(ierr); 191 break; 192 case PC_FIELDSPLIT_SCHUR_PRE_USER: 193 if (jac->schur_user) { 194 ierr = PetscViewerASCIIPrintf(viewer," Preconditioner for the Schur complement formed from user provided matrix\n");CHKERRQ(ierr); 195 } else { 196 ierr = PetscViewerASCIIPrintf(viewer," Preconditioner for the Schur complement formed from A11\n");CHKERRQ(ierr); 197 } 198 break; 199 default: 200 SETERRQ1(PetscObjectComm((PetscObject)pc), PETSC_ERR_ARG_OUTOFRANGE, "Invalid Schur preconditioning type: %d", jac->schurpre); 201 } 202 ierr = PetscViewerASCIIPrintf(viewer," Split info:\n");CHKERRQ(ierr); 203 ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 204 for (i=0; i<jac->nsplits; i++) { 205 if (ilink->fields) { 206 ierr = PetscViewerASCIIPrintf(viewer,"Split number %D Fields ",i);CHKERRQ(ierr); 207 ierr = PetscViewerASCIIUseTabs(viewer,PETSC_FALSE);CHKERRQ(ierr); 208 for (j=0; j<ilink->nfields; j++) { 209 if (j > 0) { 210 ierr = PetscViewerASCIIPrintf(viewer,",");CHKERRQ(ierr); 211 } 212 ierr = PetscViewerASCIIPrintf(viewer," %D",ilink->fields[j]);CHKERRQ(ierr); 213 } 214 ierr = PetscViewerASCIIPrintf(viewer,"\n");CHKERRQ(ierr); 215 ierr = PetscViewerASCIIUseTabs(viewer,PETSC_TRUE);CHKERRQ(ierr); 216 } else { 217 ierr = PetscViewerASCIIPrintf(viewer,"Split number %D Defined by IS\n",i);CHKERRQ(ierr); 218 } 219 ilink = ilink->next; 220 } 221 ierr = PetscViewerASCIIPrintf(viewer,"KSP solver for A00 block\n");CHKERRQ(ierr); 222 ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 223 if (jac->head) { 224 ierr = KSPView(jac->head->ksp,viewer);CHKERRQ(ierr); 225 } else {ierr = PetscViewerASCIIPrintf(viewer," not yet available\n");CHKERRQ(ierr);} 226 ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 227 if (jac->head && jac->kspupper != jac->head->ksp) { 228 ierr = PetscViewerASCIIPrintf(viewer,"KSP solver for upper A00 in upper triangular factor \n");CHKERRQ(ierr); 229 ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 230 if (jac->kspupper) {ierr = KSPView(jac->kspupper,viewer);CHKERRQ(ierr);} 231 else {ierr = PetscViewerASCIIPrintf(viewer," not yet available\n");CHKERRQ(ierr);} 232 ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 233 } 234 ierr = PetscViewerASCIIPrintf(viewer,"KSP solver for S = A11 - A10 inv(A00) A01 \n");CHKERRQ(ierr); 235 ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 236 if (jac->kspschur) { 237 ierr = KSPView(jac->kspschur,viewer);CHKERRQ(ierr); 238 } else { 239 ierr = PetscViewerASCIIPrintf(viewer," not yet available\n");CHKERRQ(ierr); 240 } 241 ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 242 ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 243 } else if (isdraw && jac->head) { 244 PetscDraw draw; 245 PetscReal x,y,w,wd,h; 246 PetscInt cnt = 2; 247 char str[32]; 248 249 ierr = PetscViewerDrawGetDraw(viewer,0,&draw);CHKERRQ(ierr); 250 ierr = PetscDrawGetCurrentPoint(draw,&x,&y);CHKERRQ(ierr); 251 if (jac->kspupper != jac->head->ksp) cnt++; 252 w = 2*PetscMin(1.0 - x,x); 253 wd = w/(cnt + 1); 254 255 ierr = PetscSNPrintf(str,32,"Schur fact. %s",PCFieldSplitSchurFactTypes[jac->schurfactorization]);CHKERRQ(ierr); 256 ierr = PetscDrawStringBoxed(draw,x,y,PETSC_DRAW_RED,PETSC_DRAW_BLACK,str,NULL,&h);CHKERRQ(ierr); 257 y -= h; 258 if (jac->schurpre == PC_FIELDSPLIT_SCHUR_PRE_USER && !jac->schur_user) { 259 ierr = PetscSNPrintf(str,32,"Prec. for Schur from %s",PCFieldSplitSchurPreTypes[PC_FIELDSPLIT_SCHUR_PRE_A11]);CHKERRQ(ierr); 260 } else { 261 ierr = PetscSNPrintf(str,32,"Prec. for Schur from %s",PCFieldSplitSchurPreTypes[jac->schurpre]);CHKERRQ(ierr); 262 } 263 ierr = PetscDrawStringBoxed(draw,x+wd*(cnt-1)/2.0,y,PETSC_DRAW_RED,PETSC_DRAW_BLACK,str,NULL,&h);CHKERRQ(ierr); 264 y -= h; 265 x = x - wd*(cnt-1)/2.0; 266 267 ierr = PetscDrawPushCurrentPoint(draw,x,y);CHKERRQ(ierr); 268 ierr = KSPView(jac->head->ksp,viewer);CHKERRQ(ierr); 269 ierr = PetscDrawPopCurrentPoint(draw);CHKERRQ(ierr); 270 if (jac->kspupper != jac->head->ksp) { 271 x += wd; 272 ierr = PetscDrawPushCurrentPoint(draw,x,y);CHKERRQ(ierr); 273 ierr = KSPView(jac->kspupper,viewer);CHKERRQ(ierr); 274 ierr = PetscDrawPopCurrentPoint(draw);CHKERRQ(ierr); 275 } 276 x += wd; 277 ierr = PetscDrawPushCurrentPoint(draw,x,y);CHKERRQ(ierr); 278 ierr = KSPView(jac->kspschur,viewer);CHKERRQ(ierr); 279 ierr = PetscDrawPopCurrentPoint(draw);CHKERRQ(ierr); 280 } 281 PetscFunctionReturn(0); 282 } 283 284 static PetscErrorCode PCView_FieldSplit_GKB(PC pc,PetscViewer viewer) 285 { 286 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 287 PetscErrorCode ierr; 288 PetscBool iascii,isdraw; 289 PetscInt i,j; 290 PC_FieldSplitLink ilink = jac->head; 291 292 PetscFunctionBegin; 293 ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr); 294 ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERDRAW,&isdraw);CHKERRQ(ierr); 295 if (iascii) { 296 if (jac->bs > 0) { 297 ierr = PetscViewerASCIIPrintf(viewer," FieldSplit with %s composition: total splits = %D, blocksize = %D\n",PCCompositeTypes[jac->type],jac->nsplits,jac->bs);CHKERRQ(ierr); 298 } else { 299 ierr = PetscViewerASCIIPrintf(viewer," FieldSplit with %s composition: total splits = %D\n",PCCompositeTypes[jac->type],jac->nsplits);CHKERRQ(ierr); 300 } 301 if (pc->useAmat) { 302 ierr = PetscViewerASCIIPrintf(viewer," using Amat (not Pmat) as operator for blocks\n");CHKERRQ(ierr); 303 } 304 if (jac->diag_use_amat) { 305 ierr = PetscViewerASCIIPrintf(viewer," using Amat (not Pmat) as operator for diagonal blocks\n");CHKERRQ(ierr); 306 } 307 if (jac->offdiag_use_amat) { 308 ierr = PetscViewerASCIIPrintf(viewer," using Amat (not Pmat) as operator for off-diagonal blocks\n");CHKERRQ(ierr); 309 } 310 311 ierr = PetscViewerASCIIPrintf(viewer," Stopping tolerance=%.1e, delay in error estimate=%D, maximum iterations=%D\n",jac->gkbtol,jac->gkbdelay,jac->gkbmaxit);CHKERRQ(ierr); 312 ierr = PetscViewerASCIIPrintf(viewer," Solver info for H = A00 + nu*A01*A01' matrix:\n");CHKERRQ(ierr); 313 ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 314 315 if (ilink->fields) { 316 ierr = PetscViewerASCIIPrintf(viewer,"Split number %D Fields ",0);CHKERRQ(ierr); 317 ierr = PetscViewerASCIIUseTabs(viewer,PETSC_FALSE);CHKERRQ(ierr); 318 for (j=0; j<ilink->nfields; j++) { 319 if (j > 0) { 320 ierr = PetscViewerASCIIPrintf(viewer,",");CHKERRQ(ierr); 321 } 322 ierr = PetscViewerASCIIPrintf(viewer," %D",ilink->fields[j]);CHKERRQ(ierr); 323 } 324 ierr = PetscViewerASCIIPrintf(viewer,"\n");CHKERRQ(ierr); 325 ierr = PetscViewerASCIIUseTabs(viewer,PETSC_TRUE);CHKERRQ(ierr); 326 } else { 327 ierr = PetscViewerASCIIPrintf(viewer,"Split number %D Defined by IS\n",0);CHKERRQ(ierr); 328 } 329 ierr = KSPView(ilink->ksp,viewer);CHKERRQ(ierr); 330 331 ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 332 } 333 334 if (isdraw) { 335 PetscDraw draw; 336 PetscReal x,y,w,wd; 337 338 ierr = PetscViewerDrawGetDraw(viewer,0,&draw);CHKERRQ(ierr); 339 ierr = PetscDrawGetCurrentPoint(draw,&x,&y);CHKERRQ(ierr); 340 w = 2*PetscMin(1.0 - x,x); 341 wd = w/(jac->nsplits + 1); 342 x = x - wd*(jac->nsplits-1)/2.0; 343 for (i=0; i<jac->nsplits; i++) { 344 ierr = PetscDrawPushCurrentPoint(draw,x,y);CHKERRQ(ierr); 345 ierr = KSPView(ilink->ksp,viewer);CHKERRQ(ierr); 346 ierr = PetscDrawPopCurrentPoint(draw);CHKERRQ(ierr); 347 x += wd; 348 ilink = ilink->next; 349 } 350 } 351 PetscFunctionReturn(0); 352 } 353 354 355 /* Precondition: jac->bs is set to a meaningful value */ 356 static PetscErrorCode PCFieldSplitSetRuntimeSplits_Private(PC pc) 357 { 358 PetscErrorCode ierr; 359 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 360 PetscInt i,nfields,*ifields,nfields_col,*ifields_col; 361 PetscBool flg,flg_col; 362 char optionname[128],splitname[8],optionname_col[128]; 363 364 PetscFunctionBegin; 365 ierr = PetscMalloc1(jac->bs,&ifields);CHKERRQ(ierr); 366 ierr = PetscMalloc1(jac->bs,&ifields_col);CHKERRQ(ierr); 367 for (i=0,flg=PETSC_TRUE;; i++) { 368 ierr = PetscSNPrintf(splitname,sizeof(splitname),"%D",i);CHKERRQ(ierr); 369 ierr = PetscSNPrintf(optionname,sizeof(optionname),"-pc_fieldsplit_%D_fields",i);CHKERRQ(ierr); 370 ierr = PetscSNPrintf(optionname_col,sizeof(optionname_col),"-pc_fieldsplit_%D_fields_col",i);CHKERRQ(ierr); 371 nfields = jac->bs; 372 nfields_col = jac->bs; 373 ierr = PetscOptionsGetIntArray(((PetscObject)pc)->options,((PetscObject)pc)->prefix,optionname,ifields,&nfields,&flg);CHKERRQ(ierr); 374 ierr = PetscOptionsGetIntArray(((PetscObject)pc)->options,((PetscObject)pc)->prefix,optionname_col,ifields_col,&nfields_col,&flg_col);CHKERRQ(ierr); 375 if (!flg) break; 376 else if (flg && !flg_col) { 377 if (!nfields) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Cannot list zero fields"); 378 ierr = PCFieldSplitSetFields(pc,splitname,nfields,ifields,ifields);CHKERRQ(ierr); 379 } else { 380 if (!nfields || !nfields_col) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Cannot list zero fields"); 381 if (nfields != nfields_col) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Number of row and column fields must match"); 382 ierr = PCFieldSplitSetFields(pc,splitname,nfields,ifields,ifields_col);CHKERRQ(ierr); 383 } 384 } 385 if (i > 0) { 386 /* Makes command-line setting of splits take precedence over setting them in code. 387 Otherwise subsequent calls to PCFieldSplitSetIS() or PCFieldSplitSetFields() would 388 create new splits, which would probably not be what the user wanted. */ 389 jac->splitdefined = PETSC_TRUE; 390 } 391 ierr = PetscFree(ifields);CHKERRQ(ierr); 392 ierr = PetscFree(ifields_col);CHKERRQ(ierr); 393 PetscFunctionReturn(0); 394 } 395 396 static PetscErrorCode PCFieldSplitSetDefaults(PC pc) 397 { 398 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 399 PetscErrorCode ierr; 400 PC_FieldSplitLink ilink = jac->head; 401 PetscBool fieldsplit_default = PETSC_FALSE,coupling = PETSC_FALSE; 402 PetscInt i; 403 404 PetscFunctionBegin; 405 /* 406 Kinda messy, but at least this now uses DMCreateFieldDecomposition(). 407 Should probably be rewritten. 408 */ 409 if (!ilink) { 410 ierr = PetscOptionsGetBool(((PetscObject)pc)->options,((PetscObject)pc)->prefix,"-pc_fieldsplit_detect_coupling",&coupling,NULL);CHKERRQ(ierr); 411 if (pc->dm && jac->dm_splits && !jac->detect && !coupling) { 412 PetscInt numFields, f, i, j; 413 char **fieldNames; 414 IS *fields; 415 DM *dms; 416 DM subdm[128]; 417 PetscBool flg; 418 419 ierr = DMCreateFieldDecomposition(pc->dm, &numFields, &fieldNames, &fields, &dms);CHKERRQ(ierr); 420 /* Allow the user to prescribe the splits */ 421 for (i = 0, flg = PETSC_TRUE;; i++) { 422 PetscInt ifields[128]; 423 IS compField; 424 char optionname[128], splitname[8]; 425 PetscInt nfields = numFields; 426 427 ierr = PetscSNPrintf(optionname, sizeof(optionname), "-pc_fieldsplit_%D_fields", i);CHKERRQ(ierr); 428 ierr = PetscOptionsGetIntArray(((PetscObject)pc)->options,((PetscObject)pc)->prefix, optionname, ifields, &nfields, &flg);CHKERRQ(ierr); 429 if (!flg) break; 430 if (numFields > 128) SETERRQ1(PetscObjectComm((PetscObject)pc),PETSC_ERR_SUP,"Cannot currently support %d > 128 fields", numFields); 431 ierr = DMCreateSubDM(pc->dm, nfields, ifields, &compField, &subdm[i]);CHKERRQ(ierr); 432 if (nfields == 1) { 433 ierr = PCFieldSplitSetIS(pc, fieldNames[ifields[0]], compField);CHKERRQ(ierr); 434 } else { 435 ierr = PetscSNPrintf(splitname, sizeof(splitname), "%D", i);CHKERRQ(ierr); 436 ierr = PCFieldSplitSetIS(pc, splitname, compField);CHKERRQ(ierr); 437 } 438 ierr = ISDestroy(&compField);CHKERRQ(ierr); 439 for (j = 0; j < nfields; ++j) { 440 f = ifields[j]; 441 ierr = PetscFree(fieldNames[f]);CHKERRQ(ierr); 442 ierr = ISDestroy(&fields[f]);CHKERRQ(ierr); 443 } 444 } 445 if (i == 0) { 446 for (f = 0; f < numFields; ++f) { 447 ierr = PCFieldSplitSetIS(pc, fieldNames[f], fields[f]);CHKERRQ(ierr); 448 ierr = PetscFree(fieldNames[f]);CHKERRQ(ierr); 449 ierr = ISDestroy(&fields[f]);CHKERRQ(ierr); 450 } 451 } else { 452 for (j=0; j<numFields; j++) { 453 ierr = DMDestroy(dms+j);CHKERRQ(ierr); 454 } 455 ierr = PetscFree(dms);CHKERRQ(ierr); 456 ierr = PetscMalloc1(i, &dms);CHKERRQ(ierr); 457 for (j = 0; j < i; ++j) dms[j] = subdm[j]; 458 } 459 ierr = PetscFree(fieldNames);CHKERRQ(ierr); 460 ierr = PetscFree(fields);CHKERRQ(ierr); 461 if (dms) { 462 ierr = PetscInfo(pc, "Setting up physics based fieldsplit preconditioner using the embedded DM\n");CHKERRQ(ierr); 463 for (ilink = jac->head, i = 0; ilink; ilink = ilink->next, ++i) { 464 const char *prefix; 465 ierr = PetscObjectGetOptionsPrefix((PetscObject)(ilink->ksp),&prefix);CHKERRQ(ierr); 466 ierr = PetscObjectSetOptionsPrefix((PetscObject)(dms[i]), prefix);CHKERRQ(ierr); 467 ierr = KSPSetDM(ilink->ksp, dms[i]);CHKERRQ(ierr); 468 ierr = KSPSetDMActive(ilink->ksp, PETSC_FALSE);CHKERRQ(ierr); 469 { 470 PetscErrorCode (*func)(KSP,Mat,Mat,void*); 471 void *ctx; 472 473 ierr = DMKSPGetComputeOperators(pc->dm, &func, &ctx);CHKERRQ(ierr); 474 ierr = DMKSPSetComputeOperators(dms[i], func, ctx);CHKERRQ(ierr); 475 } 476 ierr = PetscObjectIncrementTabLevel((PetscObject)dms[i],(PetscObject)ilink->ksp,0);CHKERRQ(ierr); 477 ierr = DMDestroy(&dms[i]);CHKERRQ(ierr); 478 } 479 ierr = PetscFree(dms);CHKERRQ(ierr); 480 } 481 } else { 482 if (jac->bs <= 0) { 483 if (pc->pmat) { 484 ierr = MatGetBlockSize(pc->pmat,&jac->bs);CHKERRQ(ierr); 485 } else jac->bs = 1; 486 } 487 488 if (jac->detect) { 489 IS zerodiags,rest; 490 PetscInt nmin,nmax; 491 492 ierr = MatGetOwnershipRange(pc->mat,&nmin,&nmax);CHKERRQ(ierr); 493 ierr = MatFindZeroDiagonals(pc->mat,&zerodiags);CHKERRQ(ierr); 494 ierr = ISComplement(zerodiags,nmin,nmax,&rest);CHKERRQ(ierr); 495 ierr = PCFieldSplitSetIS(pc,"0",rest);CHKERRQ(ierr); 496 ierr = PCFieldSplitSetIS(pc,"1",zerodiags);CHKERRQ(ierr); 497 ierr = ISDestroy(&zerodiags);CHKERRQ(ierr); 498 ierr = ISDestroy(&rest);CHKERRQ(ierr); 499 } else if (coupling) { 500 IS coupling,rest; 501 PetscInt nmin,nmax; 502 503 ierr = MatGetOwnershipRange(pc->mat,&nmin,&nmax);CHKERRQ(ierr); 504 ierr = MatFindOffBlockDiagonalEntries(pc->mat,&coupling);CHKERRQ(ierr); 505 ierr = ISCreateStride(PetscObjectComm((PetscObject)pc->mat),nmax-nmin,nmin,1,&rest);CHKERRQ(ierr); 506 ierr = ISSetIdentity(rest);CHKERRQ(ierr); 507 ierr = PCFieldSplitSetIS(pc,"0",rest);CHKERRQ(ierr); 508 ierr = PCFieldSplitSetIS(pc,"1",coupling);CHKERRQ(ierr); 509 ierr = ISDestroy(&coupling);CHKERRQ(ierr); 510 ierr = ISDestroy(&rest);CHKERRQ(ierr); 511 } else { 512 ierr = PetscOptionsGetBool(((PetscObject)pc)->options,((PetscObject)pc)->prefix,"-pc_fieldsplit_default",&fieldsplit_default,NULL);CHKERRQ(ierr); 513 if (!fieldsplit_default) { 514 /* Allow user to set fields from command line, if bs was known at the time of PCSetFromOptions_FieldSplit() 515 then it is set there. This is not ideal because we should only have options set in XXSetFromOptions(). */ 516 ierr = PCFieldSplitSetRuntimeSplits_Private(pc);CHKERRQ(ierr); 517 if (jac->splitdefined) {ierr = PetscInfo(pc,"Splits defined using the options database\n");CHKERRQ(ierr);} 518 } 519 if ((fieldsplit_default || !jac->splitdefined) && !jac->isrestrict) { 520 Mat M = pc->pmat; 521 PetscBool isnest; 522 523 ierr = PetscInfo(pc,"Using default splitting of fields\n");CHKERRQ(ierr); 524 ierr = PetscObjectTypeCompare((PetscObject)pc->pmat,MATNEST,&isnest);CHKERRQ(ierr); 525 if (!isnest) { 526 M = pc->mat; 527 ierr = PetscObjectTypeCompare((PetscObject)pc->mat,MATNEST,&isnest);CHKERRQ(ierr); 528 } 529 if (isnest) { 530 IS *fields; 531 PetscInt nf; 532 533 ierr = MatNestGetSize(M,&nf,NULL);CHKERRQ(ierr); 534 ierr = PetscMalloc1(nf,&fields);CHKERRQ(ierr); 535 ierr = MatNestGetISs(M,fields,NULL);CHKERRQ(ierr); 536 for (i=0;i<nf;i++) { 537 ierr = PCFieldSplitSetIS(pc,NULL,fields[i]);CHKERRQ(ierr); 538 } 539 ierr = PetscFree(fields);CHKERRQ(ierr); 540 } else { 541 for (i=0; i<jac->bs; i++) { 542 char splitname[8]; 543 ierr = PetscSNPrintf(splitname,sizeof(splitname),"%D",i);CHKERRQ(ierr); 544 ierr = PCFieldSplitSetFields(pc,splitname,1,&i,&i);CHKERRQ(ierr); 545 } 546 jac->defaultsplit = PETSC_TRUE; 547 } 548 } 549 } 550 } 551 } else if (jac->nsplits == 1) { 552 if (ilink->is) { 553 IS is2; 554 PetscInt nmin,nmax; 555 556 ierr = MatGetOwnershipRange(pc->mat,&nmin,&nmax);CHKERRQ(ierr); 557 ierr = ISComplement(ilink->is,nmin,nmax,&is2);CHKERRQ(ierr); 558 ierr = PCFieldSplitSetIS(pc,"1",is2);CHKERRQ(ierr); 559 ierr = ISDestroy(&is2);CHKERRQ(ierr); 560 } else SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_SUP,"Must provide at least two sets of fields to PCFieldSplit()"); 561 } 562 563 if (jac->nsplits < 2) SETERRQ1(PetscObjectComm((PetscObject)pc),PETSC_ERR_PLIB,"Unhandled case, must have at least two fields, not %d", jac->nsplits); 564 PetscFunctionReturn(0); 565 } 566 567 static PetscErrorCode MatGolubKahanComputeExplicitOperator(Mat A,Mat B,Mat C,Mat *H,PetscReal gkbnu) 568 { 569 PetscErrorCode ierr; 570 Mat BT,T; 571 PetscReal nrmT,nrmB; 572 573 PetscFunctionBegin; 574 ierr = MatHermitianTranspose(C,MAT_INITIAL_MATRIX,&T);CHKERRQ(ierr); /* Test if augmented matrix is symmetric */ 575 ierr = MatAXPY(T,-1.0,B,DIFFERENT_NONZERO_PATTERN);CHKERRQ(ierr); 576 ierr = MatNorm(T,NORM_1,&nrmT);CHKERRQ(ierr); 577 ierr = MatNorm(B,NORM_1,&nrmB);CHKERRQ(ierr); 578 if (nrmB > 0) { 579 if (nrmT/nrmB >= PETSC_SMALL) { 580 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Matrix is not symmetric/hermitian, GKB is not applicable."); 581 } 582 } 583 /* Compute augmented Lagrangian matrix H = A00 + nu*A01*A01'. This corresponds to */ 584 /* setting N := 1/nu*I in [Ar13]. */ 585 ierr = MatHermitianTranspose(B,MAT_INITIAL_MATRIX,&BT);CHKERRQ(ierr); 586 ierr = MatMatMult(B,BT,MAT_INITIAL_MATRIX,PETSC_DEFAULT,H);CHKERRQ(ierr); /* H = A01*A01' */ 587 ierr = MatAYPX(*H,gkbnu,A,DIFFERENT_NONZERO_PATTERN);CHKERRQ(ierr); /* H = A00 + nu*A01*A01' */ 588 589 ierr = MatDestroy(&BT);CHKERRQ(ierr); 590 ierr = MatDestroy(&T);CHKERRQ(ierr); 591 PetscFunctionReturn(0); 592 } 593 594 PETSC_EXTERN PetscErrorCode PetscOptionsFindPairPrefix_Private(PetscOptions,const char pre[], const char name[],const char *value[],PetscBool *flg); 595 596 static PetscErrorCode PCSetUp_FieldSplit(PC pc) 597 { 598 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 599 PetscErrorCode ierr; 600 PC_FieldSplitLink ilink; 601 PetscInt i,nsplit; 602 PetscBool sorted, sorted_col; 603 604 PetscFunctionBegin; 605 pc->failedreason = PC_NOERROR; 606 ierr = PCFieldSplitSetDefaults(pc);CHKERRQ(ierr); 607 nsplit = jac->nsplits; 608 ilink = jac->head; 609 610 /* get the matrices for each split */ 611 if (!jac->issetup) { 612 PetscInt rstart,rend,nslots,bs; 613 614 jac->issetup = PETSC_TRUE; 615 616 /* This is done here instead of in PCFieldSplitSetFields() because may not have matrix at that point */ 617 if (jac->defaultsplit || !ilink->is) { 618 if (jac->bs <= 0) jac->bs = nsplit; 619 } 620 bs = jac->bs; 621 ierr = MatGetOwnershipRange(pc->pmat,&rstart,&rend);CHKERRQ(ierr); 622 nslots = (rend - rstart)/bs; 623 for (i=0; i<nsplit; i++) { 624 if (jac->defaultsplit) { 625 ierr = ISCreateStride(PetscObjectComm((PetscObject)pc),nslots,rstart+i,nsplit,&ilink->is);CHKERRQ(ierr); 626 ierr = ISDuplicate(ilink->is,&ilink->is_col);CHKERRQ(ierr); 627 } else if (!ilink->is) { 628 if (ilink->nfields > 1) { 629 PetscInt *ii,*jj,j,k,nfields = ilink->nfields,*fields = ilink->fields,*fields_col = ilink->fields_col; 630 ierr = PetscMalloc1(ilink->nfields*nslots,&ii);CHKERRQ(ierr); 631 ierr = PetscMalloc1(ilink->nfields*nslots,&jj);CHKERRQ(ierr); 632 for (j=0; j<nslots; j++) { 633 for (k=0; k<nfields; k++) { 634 ii[nfields*j + k] = rstart + bs*j + fields[k]; 635 jj[nfields*j + k] = rstart + bs*j + fields_col[k]; 636 } 637 } 638 ierr = ISCreateGeneral(PetscObjectComm((PetscObject)pc),nslots*nfields,ii,PETSC_OWN_POINTER,&ilink->is);CHKERRQ(ierr); 639 ierr = ISCreateGeneral(PetscObjectComm((PetscObject)pc),nslots*nfields,jj,PETSC_OWN_POINTER,&ilink->is_col);CHKERRQ(ierr); 640 ierr = ISSetBlockSize(ilink->is, nfields);CHKERRQ(ierr); 641 ierr = ISSetBlockSize(ilink->is_col, nfields);CHKERRQ(ierr); 642 } else { 643 ierr = ISCreateStride(PetscObjectComm((PetscObject)pc),nslots,rstart+ilink->fields[0],bs,&ilink->is);CHKERRQ(ierr); 644 ierr = ISCreateStride(PetscObjectComm((PetscObject)pc),nslots,rstart+ilink->fields_col[0],bs,&ilink->is_col);CHKERRQ(ierr); 645 } 646 } 647 ierr = ISSorted(ilink->is,&sorted);CHKERRQ(ierr); 648 if (ilink->is_col) { ierr = ISSorted(ilink->is_col,&sorted_col);CHKERRQ(ierr); } 649 if (!sorted || !sorted_col) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Fields must be sorted when creating split"); 650 ilink = ilink->next; 651 } 652 } 653 654 ilink = jac->head; 655 if (!jac->pmat) { 656 Vec xtmp; 657 658 ierr = MatCreateVecs(pc->pmat,&xtmp,NULL);CHKERRQ(ierr); 659 ierr = PetscMalloc1(nsplit,&jac->pmat);CHKERRQ(ierr); 660 ierr = PetscMalloc2(nsplit,&jac->x,nsplit,&jac->y);CHKERRQ(ierr); 661 for (i=0; i<nsplit; i++) { 662 MatNullSpace sp; 663 664 /* Check for preconditioning matrix attached to IS */ 665 ierr = PetscObjectQuery((PetscObject) ilink->is, "pmat", (PetscObject*) &jac->pmat[i]);CHKERRQ(ierr); 666 if (jac->pmat[i]) { 667 ierr = PetscObjectReference((PetscObject) jac->pmat[i]);CHKERRQ(ierr); 668 if (jac->type == PC_COMPOSITE_SCHUR) { 669 jac->schur_user = jac->pmat[i]; 670 671 ierr = PetscObjectReference((PetscObject) jac->schur_user);CHKERRQ(ierr); 672 } 673 } else { 674 const char *prefix; 675 ierr = MatCreateSubMatrix(pc->pmat,ilink->is,ilink->is_col,MAT_INITIAL_MATRIX,&jac->pmat[i]);CHKERRQ(ierr); 676 ierr = KSPGetOptionsPrefix(ilink->ksp,&prefix);CHKERRQ(ierr); 677 ierr = MatSetOptionsPrefix(jac->pmat[i],prefix);CHKERRQ(ierr); 678 ierr = MatViewFromOptions(jac->pmat[i],NULL,"-mat_view");CHKERRQ(ierr); 679 } 680 /* create work vectors for each split */ 681 ierr = MatCreateVecs(jac->pmat[i],&jac->x[i],&jac->y[i]);CHKERRQ(ierr); 682 ilink->x = jac->x[i]; ilink->y = jac->y[i]; ilink->z = NULL; 683 /* compute scatter contexts needed by multiplicative versions and non-default splits */ 684 ierr = VecScatterCreate(xtmp,ilink->is,jac->x[i],NULL,&ilink->sctx);CHKERRQ(ierr); 685 ierr = PetscObjectQuery((PetscObject) ilink->is, "nearnullspace", (PetscObject*) &sp);CHKERRQ(ierr); 686 if (sp) { 687 ierr = MatSetNearNullSpace(jac->pmat[i], sp);CHKERRQ(ierr); 688 } 689 ilink = ilink->next; 690 } 691 ierr = VecDestroy(&xtmp);CHKERRQ(ierr); 692 } else { 693 MatReuse scall; 694 if (pc->flag == DIFFERENT_NONZERO_PATTERN) { 695 for (i=0; i<nsplit; i++) { 696 ierr = MatDestroy(&jac->pmat[i]);CHKERRQ(ierr); 697 } 698 scall = MAT_INITIAL_MATRIX; 699 } else scall = MAT_REUSE_MATRIX; 700 701 for (i=0; i<nsplit; i++) { 702 Mat pmat; 703 704 /* Check for preconditioning matrix attached to IS */ 705 ierr = PetscObjectQuery((PetscObject) ilink->is, "pmat", (PetscObject*) &pmat);CHKERRQ(ierr); 706 if (!pmat) { 707 ierr = MatCreateSubMatrix(pc->pmat,ilink->is,ilink->is_col,scall,&jac->pmat[i]);CHKERRQ(ierr); 708 } 709 ilink = ilink->next; 710 } 711 } 712 if (jac->diag_use_amat) { 713 ilink = jac->head; 714 if (!jac->mat) { 715 ierr = PetscMalloc1(nsplit,&jac->mat);CHKERRQ(ierr); 716 for (i=0; i<nsplit; i++) { 717 ierr = MatCreateSubMatrix(pc->mat,ilink->is,ilink->is_col,MAT_INITIAL_MATRIX,&jac->mat[i]);CHKERRQ(ierr); 718 ilink = ilink->next; 719 } 720 } else { 721 MatReuse scall; 722 if (pc->flag == DIFFERENT_NONZERO_PATTERN) { 723 for (i=0; i<nsplit; i++) { 724 ierr = MatDestroy(&jac->mat[i]);CHKERRQ(ierr); 725 } 726 scall = MAT_INITIAL_MATRIX; 727 } else scall = MAT_REUSE_MATRIX; 728 729 for (i=0; i<nsplit; i++) { 730 if (jac->mat[i]) {ierr = MatCreateSubMatrix(pc->mat,ilink->is,ilink->is_col,scall,&jac->mat[i]);CHKERRQ(ierr);} 731 ilink = ilink->next; 732 } 733 } 734 } else { 735 jac->mat = jac->pmat; 736 } 737 738 /* Check for null space attached to IS */ 739 ilink = jac->head; 740 for (i=0; i<nsplit; i++) { 741 MatNullSpace sp; 742 743 ierr = PetscObjectQuery((PetscObject) ilink->is, "nullspace", (PetscObject*) &sp);CHKERRQ(ierr); 744 if (sp) { 745 ierr = MatSetNullSpace(jac->mat[i], sp);CHKERRQ(ierr); 746 } 747 ilink = ilink->next; 748 } 749 750 if (jac->type != PC_COMPOSITE_ADDITIVE && jac->type != PC_COMPOSITE_SCHUR && jac->type != PC_COMPOSITE_GKB) { 751 /* extract the rows of the matrix associated with each field: used for efficient computation of residual inside algorithm */ 752 /* FIXME: Can/should we reuse jac->mat whenever (jac->diag_use_amat) is true? */ 753 ilink = jac->head; 754 if (nsplit == 2 && jac->type == PC_COMPOSITE_MULTIPLICATIVE) { 755 /* 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 */ 756 if (!jac->Afield) { 757 ierr = PetscCalloc1(nsplit,&jac->Afield);CHKERRQ(ierr); 758 if (jac->offdiag_use_amat) { 759 ierr = MatCreateSubMatrix(pc->mat,ilink->next->is,ilink->is,MAT_INITIAL_MATRIX,&jac->Afield[1]);CHKERRQ(ierr); 760 } else { 761 ierr = MatCreateSubMatrix(pc->pmat,ilink->next->is,ilink->is,MAT_INITIAL_MATRIX,&jac->Afield[1]);CHKERRQ(ierr); 762 } 763 } else { 764 MatReuse scall; 765 if (pc->flag == DIFFERENT_NONZERO_PATTERN) { 766 for (i=0; i<nsplit; i++) { 767 ierr = MatDestroy(&jac->Afield[1]);CHKERRQ(ierr); 768 } 769 scall = MAT_INITIAL_MATRIX; 770 } else scall = MAT_REUSE_MATRIX; 771 772 if (jac->offdiag_use_amat) { 773 ierr = MatCreateSubMatrix(pc->mat,ilink->next->is,ilink->is,scall,&jac->Afield[1]);CHKERRQ(ierr); 774 } else { 775 ierr = MatCreateSubMatrix(pc->pmat,ilink->next->is,ilink->is,scall,&jac->Afield[1]);CHKERRQ(ierr); 776 } 777 } 778 } else { 779 if (!jac->Afield) { 780 ierr = PetscMalloc1(nsplit,&jac->Afield);CHKERRQ(ierr); 781 for (i=0; i<nsplit; i++) { 782 if (jac->offdiag_use_amat) { 783 ierr = MatCreateSubMatrix(pc->mat,ilink->is,NULL,MAT_INITIAL_MATRIX,&jac->Afield[i]);CHKERRQ(ierr); 784 } else { 785 ierr = MatCreateSubMatrix(pc->pmat,ilink->is,NULL,MAT_INITIAL_MATRIX,&jac->Afield[i]);CHKERRQ(ierr); 786 } 787 ilink = ilink->next; 788 } 789 } else { 790 MatReuse scall; 791 if (pc->flag == DIFFERENT_NONZERO_PATTERN) { 792 for (i=0; i<nsplit; i++) { 793 ierr = MatDestroy(&jac->Afield[i]);CHKERRQ(ierr); 794 } 795 scall = MAT_INITIAL_MATRIX; 796 } else scall = MAT_REUSE_MATRIX; 797 798 for (i=0; i<nsplit; i++) { 799 if (jac->offdiag_use_amat) { 800 ierr = MatCreateSubMatrix(pc->mat,ilink->is,NULL,scall,&jac->Afield[i]);CHKERRQ(ierr); 801 } else { 802 ierr = MatCreateSubMatrix(pc->pmat,ilink->is,NULL,scall,&jac->Afield[i]);CHKERRQ(ierr); 803 } 804 ilink = ilink->next; 805 } 806 } 807 } 808 } 809 810 if (jac->type == PC_COMPOSITE_SCHUR) { 811 IS ccis; 812 PetscBool isspd; 813 PetscInt rstart,rend; 814 char lscname[256]; 815 PetscObject LSC_L; 816 817 if (nsplit != 2) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_INCOMP,"To use Schur complement preconditioner you must have exactly 2 fields"); 818 819 /* If pc->mat is SPD, don't scale by -1 the Schur complement */ 820 if (jac->schurscale == (PetscScalar)-1.0) { 821 ierr = MatGetOption(pc->pmat,MAT_SPD,&isspd);CHKERRQ(ierr); 822 jac->schurscale = (isspd == PETSC_TRUE) ? 1.0 : -1.0; 823 } 824 825 /* When extracting off-diagonal submatrices, we take complements from this range */ 826 ierr = MatGetOwnershipRangeColumn(pc->mat,&rstart,&rend);CHKERRQ(ierr); 827 828 /* need to handle case when one is resetting up the preconditioner */ 829 if (jac->schur) { 830 KSP kspA = jac->head->ksp, kspInner = NULL, kspUpper = jac->kspupper; 831 832 ierr = MatSchurComplementGetKSP(jac->schur, &kspInner);CHKERRQ(ierr); 833 ilink = jac->head; 834 ierr = ISComplement(ilink->is_col,rstart,rend,&ccis);CHKERRQ(ierr); 835 if (jac->offdiag_use_amat) { 836 ierr = MatCreateSubMatrix(pc->mat,ilink->is,ccis,MAT_REUSE_MATRIX,&jac->B);CHKERRQ(ierr); 837 } else { 838 ierr = MatCreateSubMatrix(pc->pmat,ilink->is,ccis,MAT_REUSE_MATRIX,&jac->B);CHKERRQ(ierr); 839 } 840 ierr = ISDestroy(&ccis);CHKERRQ(ierr); 841 ilink = ilink->next; 842 ierr = ISComplement(ilink->is_col,rstart,rend,&ccis);CHKERRQ(ierr); 843 if (jac->offdiag_use_amat) { 844 ierr = MatCreateSubMatrix(pc->mat,ilink->is,ccis,MAT_REUSE_MATRIX,&jac->C);CHKERRQ(ierr); 845 } else { 846 ierr = MatCreateSubMatrix(pc->pmat,ilink->is,ccis,MAT_REUSE_MATRIX,&jac->C);CHKERRQ(ierr); 847 } 848 ierr = ISDestroy(&ccis);CHKERRQ(ierr); 849 ierr = MatSchurComplementUpdateSubMatrices(jac->schur,jac->mat[0],jac->pmat[0],jac->B,jac->C,jac->mat[1]);CHKERRQ(ierr); 850 if (jac->schurpre == PC_FIELDSPLIT_SCHUR_PRE_SELFP) { 851 ierr = MatDestroy(&jac->schurp);CHKERRQ(ierr); 852 ierr = MatSchurComplementGetPmat(jac->schur,MAT_INITIAL_MATRIX,&jac->schurp);CHKERRQ(ierr); 853 } 854 if (kspA != kspInner) { 855 ierr = KSPSetOperators(kspA,jac->mat[0],jac->pmat[0]);CHKERRQ(ierr); 856 } 857 if (kspUpper != kspA) { 858 ierr = KSPSetOperators(kspUpper,jac->mat[0],jac->pmat[0]);CHKERRQ(ierr); 859 } 860 ierr = KSPSetOperators(jac->kspschur,jac->schur,FieldSplitSchurPre(jac));CHKERRQ(ierr); 861 } else { 862 const char *Dprefix; 863 char schurprefix[256], schurmatprefix[256]; 864 char schurtestoption[256]; 865 MatNullSpace sp; 866 PetscBool flg; 867 KSP kspt; 868 869 /* extract the A01 and A10 matrices */ 870 ilink = jac->head; 871 ierr = ISComplement(ilink->is_col,rstart,rend,&ccis);CHKERRQ(ierr); 872 if (jac->offdiag_use_amat) { 873 ierr = MatCreateSubMatrix(pc->mat,ilink->is,ccis,MAT_INITIAL_MATRIX,&jac->B);CHKERRQ(ierr); 874 } else { 875 ierr = MatCreateSubMatrix(pc->pmat,ilink->is,ccis,MAT_INITIAL_MATRIX,&jac->B);CHKERRQ(ierr); 876 } 877 ierr = ISDestroy(&ccis);CHKERRQ(ierr); 878 ilink = ilink->next; 879 ierr = ISComplement(ilink->is_col,rstart,rend,&ccis);CHKERRQ(ierr); 880 if (jac->offdiag_use_amat) { 881 ierr = MatCreateSubMatrix(pc->mat,ilink->is,ccis,MAT_INITIAL_MATRIX,&jac->C);CHKERRQ(ierr); 882 } else { 883 ierr = MatCreateSubMatrix(pc->pmat,ilink->is,ccis,MAT_INITIAL_MATRIX,&jac->C);CHKERRQ(ierr); 884 } 885 ierr = ISDestroy(&ccis);CHKERRQ(ierr); 886 887 /* Use mat[0] (diagonal block of Amat) preconditioned by pmat[0] to define Schur complement */ 888 ierr = MatCreate(((PetscObject)jac->mat[0])->comm,&jac->schur);CHKERRQ(ierr); 889 ierr = MatSetType(jac->schur,MATSCHURCOMPLEMENT);CHKERRQ(ierr); 890 ierr = MatSchurComplementSetSubMatrices(jac->schur,jac->mat[0],jac->pmat[0],jac->B,jac->C,jac->mat[1]);CHKERRQ(ierr); 891 ierr = PetscSNPrintf(schurmatprefix, sizeof(schurmatprefix), "%sfieldsplit_%s_", ((PetscObject)pc)->prefix ? ((PetscObject)pc)->prefix : "", ilink->splitname);CHKERRQ(ierr); 892 ierr = MatSetOptionsPrefix(jac->schur,schurmatprefix);CHKERRQ(ierr); 893 ierr = MatSchurComplementGetKSP(jac->schur,&kspt);CHKERRQ(ierr); 894 ierr = KSPSetOptionsPrefix(kspt,schurmatprefix);CHKERRQ(ierr); 895 896 /* Note: this is not true in general */ 897 ierr = MatGetNullSpace(jac->mat[1], &sp);CHKERRQ(ierr); 898 if (sp) { 899 ierr = MatSetNullSpace(jac->schur, sp);CHKERRQ(ierr); 900 } 901 902 ierr = PetscSNPrintf(schurtestoption, sizeof(schurtestoption), "-fieldsplit_%s_inner_", ilink->splitname);CHKERRQ(ierr); 903 ierr = PetscOptionsFindPairPrefix_Private(((PetscObject)pc)->options,((PetscObject)pc)->prefix, schurtestoption, NULL, &flg);CHKERRQ(ierr); 904 if (flg) { 905 DM dmInner; 906 KSP kspInner; 907 PC pcInner; 908 909 ierr = MatSchurComplementGetKSP(jac->schur, &kspInner);CHKERRQ(ierr); 910 ierr = KSPReset(kspInner);CHKERRQ(ierr); 911 ierr = KSPSetOperators(kspInner,jac->mat[0],jac->pmat[0]);CHKERRQ(ierr); 912 ierr = PetscSNPrintf(schurprefix, sizeof(schurprefix), "%sfieldsplit_%s_inner_", ((PetscObject)pc)->prefix ? ((PetscObject)pc)->prefix : "", ilink->splitname);CHKERRQ(ierr); 913 /* Indent this deeper to emphasize the "inner" nature of this solver. */ 914 ierr = PetscObjectIncrementTabLevel((PetscObject)kspInner, (PetscObject) pc, 2);CHKERRQ(ierr); 915 ierr = PetscObjectIncrementTabLevel((PetscObject)kspInner->pc, (PetscObject) pc, 2);CHKERRQ(ierr); 916 ierr = KSPSetOptionsPrefix(kspInner, schurprefix);CHKERRQ(ierr); 917 918 /* Set DM for new solver */ 919 ierr = KSPGetDM(jac->head->ksp, &dmInner);CHKERRQ(ierr); 920 ierr = KSPSetDM(kspInner, dmInner);CHKERRQ(ierr); 921 ierr = KSPSetDMActive(kspInner, PETSC_FALSE);CHKERRQ(ierr); 922 923 /* Defaults to PCKSP as preconditioner */ 924 ierr = KSPGetPC(kspInner, &pcInner);CHKERRQ(ierr); 925 ierr = PCSetType(pcInner, PCKSP);CHKERRQ(ierr); 926 ierr = PCKSPSetKSP(pcInner, jac->head->ksp);CHKERRQ(ierr); 927 } else { 928 /* Use the outer solver for the inner solve, but revert the KSPPREONLY from PCFieldSplitSetFields_FieldSplit or 929 * PCFieldSplitSetIS_FieldSplit. We don't want KSPPREONLY because it makes the Schur complement inexact, 930 * preventing Schur complement reduction to be an accurate solve. Usually when an iterative solver is used for 931 * S = D - C A_inner^{-1} B, we expect S to be defined using an accurate definition of A_inner^{-1}, so we make 932 * GMRES the default. Note that it is also common to use PREONLY for S, in which case S may not be used 933 * directly, and the user is responsible for setting an inexact method for fieldsplit's A^{-1}. */ 934 ierr = KSPSetType(jac->head->ksp,KSPGMRES);CHKERRQ(ierr); 935 ierr = MatSchurComplementSetKSP(jac->schur,jac->head->ksp);CHKERRQ(ierr); 936 } 937 ierr = KSPSetOperators(jac->head->ksp,jac->mat[0],jac->pmat[0]);CHKERRQ(ierr); 938 ierr = KSPSetFromOptions(jac->head->ksp);CHKERRQ(ierr); 939 ierr = MatSetFromOptions(jac->schur);CHKERRQ(ierr); 940 941 ierr = PetscObjectTypeCompare((PetscObject)jac->schur, MATSCHURCOMPLEMENT, &flg);CHKERRQ(ierr); 942 if (flg) { /* Need to do this otherwise PCSetUp_KSP will overwrite the amat of jac->head->ksp */ 943 KSP kspInner; 944 PC pcInner; 945 946 ierr = MatSchurComplementGetKSP(jac->schur, &kspInner);CHKERRQ(ierr); 947 ierr = KSPGetPC(kspInner, &pcInner);CHKERRQ(ierr); 948 ierr = PetscObjectTypeCompare((PetscObject)pcInner, PCKSP, &flg);CHKERRQ(ierr); 949 if (flg) { 950 KSP ksp; 951 952 ierr = PCKSPGetKSP(pcInner, &ksp);CHKERRQ(ierr); 953 if (ksp == jac->head->ksp) { 954 ierr = PCSetUseAmat(pcInner, PETSC_TRUE);CHKERRQ(ierr); 955 } 956 } 957 } 958 ierr = PetscSNPrintf(schurtestoption, sizeof(schurtestoption), "-fieldsplit_%s_upper_", ilink->splitname);CHKERRQ(ierr); 959 ierr = PetscOptionsFindPairPrefix_Private(((PetscObject)pc)->options,((PetscObject)pc)->prefix, schurtestoption, NULL, &flg);CHKERRQ(ierr); 960 if (flg) { 961 DM dmInner; 962 963 ierr = PetscSNPrintf(schurprefix, sizeof(schurprefix), "%sfieldsplit_%s_upper_", ((PetscObject)pc)->prefix ? ((PetscObject)pc)->prefix : "", ilink->splitname);CHKERRQ(ierr); 964 ierr = KSPCreate(PetscObjectComm((PetscObject)pc), &jac->kspupper);CHKERRQ(ierr); 965 ierr = KSPSetErrorIfNotConverged(jac->kspupper,pc->erroriffailure);CHKERRQ(ierr); 966 ierr = KSPSetOptionsPrefix(jac->kspupper, schurprefix);CHKERRQ(ierr); 967 ierr = PetscObjectIncrementTabLevel((PetscObject)jac->kspupper, (PetscObject) pc, 1);CHKERRQ(ierr); 968 ierr = PetscObjectIncrementTabLevel((PetscObject)jac->kspupper->pc, (PetscObject) pc, 1);CHKERRQ(ierr); 969 ierr = KSPGetDM(jac->head->ksp, &dmInner);CHKERRQ(ierr); 970 ierr = KSPSetDM(jac->kspupper, dmInner);CHKERRQ(ierr); 971 ierr = KSPSetDMActive(jac->kspupper, PETSC_FALSE);CHKERRQ(ierr); 972 ierr = KSPSetFromOptions(jac->kspupper);CHKERRQ(ierr); 973 ierr = KSPSetOperators(jac->kspupper,jac->mat[0],jac->pmat[0]);CHKERRQ(ierr); 974 ierr = VecDuplicate(jac->head->x, &jac->head->z);CHKERRQ(ierr); 975 } else { 976 jac->kspupper = jac->head->ksp; 977 ierr = PetscObjectReference((PetscObject) jac->head->ksp);CHKERRQ(ierr); 978 } 979 980 if (jac->schurpre == PC_FIELDSPLIT_SCHUR_PRE_SELFP) { 981 ierr = MatSchurComplementGetPmat(jac->schur,MAT_INITIAL_MATRIX,&jac->schurp);CHKERRQ(ierr); 982 } 983 ierr = KSPCreate(PetscObjectComm((PetscObject)pc),&jac->kspschur);CHKERRQ(ierr); 984 ierr = KSPSetErrorIfNotConverged(jac->kspschur,pc->erroriffailure);CHKERRQ(ierr); 985 ierr = PetscLogObjectParent((PetscObject)pc,(PetscObject)jac->kspschur);CHKERRQ(ierr); 986 ierr = PetscObjectIncrementTabLevel((PetscObject)jac->kspschur,(PetscObject)pc,1);CHKERRQ(ierr); 987 if (jac->schurpre == PC_FIELDSPLIT_SCHUR_PRE_SELF) { 988 PC pcschur; 989 ierr = KSPGetPC(jac->kspschur,&pcschur);CHKERRQ(ierr); 990 ierr = PCSetType(pcschur,PCNONE);CHKERRQ(ierr); 991 /* Note: This is bad if there exist preconditioners for MATSCHURCOMPLEMENT */ 992 } else if (jac->schurpre == PC_FIELDSPLIT_SCHUR_PRE_FULL) { 993 ierr = MatSchurComplementComputeExplicitOperator(jac->schur, &jac->schur_user);CHKERRQ(ierr); 994 } 995 ierr = KSPSetOperators(jac->kspschur,jac->schur,FieldSplitSchurPre(jac));CHKERRQ(ierr); 996 ierr = KSPGetOptionsPrefix(jac->head->next->ksp, &Dprefix);CHKERRQ(ierr); 997 ierr = KSPSetOptionsPrefix(jac->kspschur, Dprefix);CHKERRQ(ierr); 998 /* propagate DM */ 999 { 1000 DM sdm; 1001 ierr = KSPGetDM(jac->head->next->ksp, &sdm);CHKERRQ(ierr); 1002 if (sdm) { 1003 ierr = KSPSetDM(jac->kspschur, sdm);CHKERRQ(ierr); 1004 ierr = KSPSetDMActive(jac->kspschur, PETSC_FALSE);CHKERRQ(ierr); 1005 } 1006 } 1007 /* really want setfromoptions called in PCSetFromOptions_FieldSplit(), but it is not ready yet */ 1008 /* need to call this every time, since the jac->kspschur is freshly created, otherwise its options never get set */ 1009 ierr = KSPSetFromOptions(jac->kspschur);CHKERRQ(ierr); 1010 } 1011 ierr = MatAssemblyBegin(jac->schur,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 1012 ierr = MatAssemblyEnd(jac->schur,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr); 1013 1014 /* HACK: special support to forward L and Lp matrices that might be used by PCLSC */ 1015 ierr = PetscSNPrintf(lscname,sizeof(lscname),"%s_LSC_L",ilink->splitname);CHKERRQ(ierr); 1016 ierr = PetscObjectQuery((PetscObject)pc->mat,lscname,(PetscObject*)&LSC_L);CHKERRQ(ierr); 1017 if (!LSC_L) {ierr = PetscObjectQuery((PetscObject)pc->pmat,lscname,(PetscObject*)&LSC_L);CHKERRQ(ierr);} 1018 if (LSC_L) {ierr = PetscObjectCompose((PetscObject)jac->schur,"LSC_L",(PetscObject)LSC_L);CHKERRQ(ierr);} 1019 ierr = PetscSNPrintf(lscname,sizeof(lscname),"%s_LSC_Lp",ilink->splitname);CHKERRQ(ierr); 1020 ierr = PetscObjectQuery((PetscObject)pc->pmat,lscname,(PetscObject*)&LSC_L);CHKERRQ(ierr); 1021 if (!LSC_L) {ierr = PetscObjectQuery((PetscObject)pc->mat,lscname,(PetscObject*)&LSC_L);CHKERRQ(ierr);} 1022 if (LSC_L) {ierr = PetscObjectCompose((PetscObject)jac->schur,"LSC_Lp",(PetscObject)LSC_L);CHKERRQ(ierr);} 1023 } else if (jac->type == PC_COMPOSITE_GKB) { 1024 IS ccis; 1025 PetscInt rstart,rend; 1026 1027 if (nsplit != 2) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_INCOMP,"To use GKB preconditioner you must have exactly 2 fields"); 1028 1029 ilink = jac->head; 1030 1031 /* When extracting off-diagonal submatrices, we take complements from this range */ 1032 ierr = MatGetOwnershipRangeColumn(pc->mat,&rstart,&rend);CHKERRQ(ierr); 1033 1034 ierr = ISComplement(ilink->is_col,rstart,rend,&ccis);CHKERRQ(ierr); 1035 if (jac->offdiag_use_amat) { 1036 ierr = MatCreateSubMatrix(pc->mat,ilink->is,ccis,MAT_INITIAL_MATRIX,&jac->B);CHKERRQ(ierr); 1037 } else { 1038 ierr = MatCreateSubMatrix(pc->pmat,ilink->is,ccis,MAT_INITIAL_MATRIX,&jac->B);CHKERRQ(ierr); 1039 } 1040 ierr = ISDestroy(&ccis);CHKERRQ(ierr); 1041 /* Create work vectors for GKB algorithm */ 1042 ierr = VecDuplicate(ilink->x,&jac->u);CHKERRQ(ierr); 1043 ierr = VecDuplicate(ilink->x,&jac->Hu);CHKERRQ(ierr); 1044 ierr = VecDuplicate(ilink->x,&jac->w2);CHKERRQ(ierr); 1045 ilink = ilink->next; 1046 ierr = ISComplement(ilink->is_col,rstart,rend,&ccis);CHKERRQ(ierr); 1047 if (jac->offdiag_use_amat) { 1048 ierr = MatCreateSubMatrix(pc->mat,ilink->is,ccis,MAT_INITIAL_MATRIX,&jac->C);CHKERRQ(ierr); 1049 } else { 1050 ierr = MatCreateSubMatrix(pc->pmat,ilink->is,ccis,MAT_INITIAL_MATRIX,&jac->C);CHKERRQ(ierr); 1051 } 1052 ierr = ISDestroy(&ccis);CHKERRQ(ierr); 1053 /* Create work vectors for GKB algorithm */ 1054 ierr = VecDuplicate(ilink->x,&jac->v);CHKERRQ(ierr); 1055 ierr = VecDuplicate(ilink->x,&jac->d);CHKERRQ(ierr); 1056 ierr = VecDuplicate(ilink->x,&jac->w1);CHKERRQ(ierr); 1057 ierr = MatGolubKahanComputeExplicitOperator(jac->mat[0],jac->B,jac->C,&jac->H,jac->gkbnu);CHKERRQ(ierr); 1058 ierr = PetscCalloc1(jac->gkbdelay,&jac->vecz);CHKERRQ(ierr); 1059 1060 ilink = jac->head; 1061 ierr = KSPSetOperators(ilink->ksp,jac->H,jac->H);CHKERRQ(ierr); 1062 if (!jac->suboptionsset) {ierr = KSPSetFromOptions(ilink->ksp);CHKERRQ(ierr);} 1063 /* Create gkb_monitor context */ 1064 if (jac->gkbmonitor) { 1065 PetscInt tablevel; 1066 ierr = PetscViewerCreate(PETSC_COMM_WORLD,&jac->gkbviewer);CHKERRQ(ierr); 1067 ierr = PetscViewerSetType(jac->gkbviewer,PETSCVIEWERASCII);CHKERRQ(ierr); 1068 ierr = PetscObjectGetTabLevel((PetscObject)ilink->ksp,&tablevel);CHKERRQ(ierr); 1069 ierr = PetscViewerASCIISetTab(jac->gkbviewer,tablevel);CHKERRQ(ierr); 1070 ierr = PetscObjectIncrementTabLevel((PetscObject)ilink->ksp,(PetscObject)ilink->ksp,1);CHKERRQ(ierr); 1071 } 1072 } else { 1073 /* set up the individual splits' PCs */ 1074 i = 0; 1075 ilink = jac->head; 1076 while (ilink) { 1077 ierr = KSPSetOperators(ilink->ksp,jac->mat[i],jac->pmat[i]);CHKERRQ(ierr); 1078 /* really want setfromoptions called in PCSetFromOptions_FieldSplit(), but it is not ready yet */ 1079 if (!jac->suboptionsset) {ierr = KSPSetFromOptions(ilink->ksp);CHKERRQ(ierr);} 1080 i++; 1081 ilink = ilink->next; 1082 } 1083 } 1084 1085 jac->suboptionsset = PETSC_TRUE; 1086 PetscFunctionReturn(0); 1087 } 1088 1089 #define FieldSplitSplitSolveAdd(ilink,xx,yy) \ 1090 (VecScatterBegin(ilink->sctx,xx,ilink->x,INSERT_VALUES,SCATTER_FORWARD) || \ 1091 VecScatterEnd(ilink->sctx,xx,ilink->x,INSERT_VALUES,SCATTER_FORWARD) || \ 1092 PetscLogEventBegin(ilink->event,ilink->ksp,ilink->x,ilink->y,NULL) ||\ 1093 KSPSolve(ilink->ksp,ilink->x,ilink->y) || \ 1094 KSPCheckSolve(ilink->ksp,pc,ilink->y) || \ 1095 PetscLogEventEnd(ilink->event,ilink->ksp,ilink->x,ilink->y,NULL) ||\ 1096 VecScatterBegin(ilink->sctx,ilink->y,yy,ADD_VALUES,SCATTER_REVERSE) || \ 1097 VecScatterEnd(ilink->sctx,ilink->y,yy,ADD_VALUES,SCATTER_REVERSE)) 1098 1099 static PetscErrorCode PCApply_FieldSplit_Schur(PC pc,Vec x,Vec y) 1100 { 1101 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 1102 PetscErrorCode ierr; 1103 PC_FieldSplitLink ilinkA = jac->head, ilinkD = ilinkA->next; 1104 KSP kspA = ilinkA->ksp, kspLower = kspA, kspUpper = jac->kspupper; 1105 1106 PetscFunctionBegin; 1107 switch (jac->schurfactorization) { 1108 case PC_FIELDSPLIT_SCHUR_FACT_DIAG: 1109 /* [A00 0; 0 -S], positive definite, suitable for MINRES */ 1110 ierr = VecScatterBegin(ilinkA->sctx,x,ilinkA->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 1111 ierr = VecScatterBegin(ilinkD->sctx,x,ilinkD->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 1112 ierr = VecScatterEnd(ilinkA->sctx,x,ilinkA->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 1113 ierr = PetscLogEventBegin(ilinkA->event,kspA,ilinkA->x,ilinkA->y,NULL);CHKERRQ(ierr); 1114 ierr = KSPSolve(kspA,ilinkA->x,ilinkA->y);CHKERRQ(ierr); 1115 ierr = KSPCheckSolve(kspA,pc,ilinkA->y);CHKERRQ(ierr); 1116 ierr = PetscLogEventEnd(ilinkA->event,kspA,ilinkA->x,ilinkA->y,NULL);CHKERRQ(ierr); 1117 ierr = VecScatterBegin(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 1118 ierr = VecScatterEnd(ilinkD->sctx,x,ilinkD->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 1119 ierr = PetscLogEventBegin(KSP_Solve_FS_S,jac->kspschur,ilinkD->x,ilinkD->y,NULL);CHKERRQ(ierr); 1120 ierr = KSPSolve(jac->kspschur,ilinkD->x,ilinkD->y);CHKERRQ(ierr); 1121 ierr = KSPCheckSolve(jac->kspschur,pc,ilinkD->y);CHKERRQ(ierr); 1122 ierr = PetscLogEventEnd(KSP_Solve_FS_S,jac->kspschur,ilinkD->x,ilinkD->y,NULL);CHKERRQ(ierr); 1123 ierr = VecScale(ilinkD->y,jac->schurscale);CHKERRQ(ierr); 1124 ierr = VecScatterEnd(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 1125 ierr = VecScatterBegin(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 1126 ierr = VecScatterEnd(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 1127 break; 1128 case PC_FIELDSPLIT_SCHUR_FACT_LOWER: 1129 /* [A00 0; A10 S], suitable for left preconditioning */ 1130 ierr = VecScatterBegin(ilinkA->sctx,x,ilinkA->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 1131 ierr = VecScatterEnd(ilinkA->sctx,x,ilinkA->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 1132 ierr = PetscLogEventBegin(ilinkA->event,kspA,ilinkA->x,ilinkA->y,NULL);CHKERRQ(ierr); 1133 ierr = KSPSolve(kspA,ilinkA->x,ilinkA->y);CHKERRQ(ierr); 1134 ierr = KSPCheckSolve(kspA,pc,ilinkA->y);CHKERRQ(ierr); 1135 ierr = PetscLogEventEnd(ilinkA->event,kspA,ilinkA->x,ilinkA->y,NULL);CHKERRQ(ierr); 1136 ierr = MatMult(jac->C,ilinkA->y,ilinkD->x);CHKERRQ(ierr); 1137 ierr = VecScale(ilinkD->x,-1.);CHKERRQ(ierr); 1138 ierr = VecScatterBegin(ilinkD->sctx,x,ilinkD->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 1139 ierr = VecScatterBegin(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 1140 ierr = VecScatterEnd(ilinkD->sctx,x,ilinkD->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 1141 ierr = PetscLogEventBegin(KSP_Solve_FS_S,jac->kspschur,ilinkD->x,ilinkD->y,NULL);CHKERRQ(ierr); 1142 ierr = KSPSolve(jac->kspschur,ilinkD->x,ilinkD->y);CHKERRQ(ierr); 1143 ierr = KSPCheckSolve(jac->kspschur,pc,ilinkD->y);CHKERRQ(ierr); 1144 ierr = PetscLogEventEnd(KSP_Solve_FS_S,jac->kspschur,ilinkD->x,ilinkD->y,NULL);CHKERRQ(ierr); 1145 ierr = VecScatterEnd(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 1146 ierr = VecScatterBegin(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 1147 ierr = VecScatterEnd(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 1148 break; 1149 case PC_FIELDSPLIT_SCHUR_FACT_UPPER: 1150 /* [A00 A01; 0 S], suitable for right preconditioning */ 1151 ierr = VecScatterBegin(ilinkD->sctx,x,ilinkD->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 1152 ierr = VecScatterEnd(ilinkD->sctx,x,ilinkD->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 1153 ierr = PetscLogEventBegin(KSP_Solve_FS_S,jac->kspschur,ilinkD->x,ilinkD->y,NULL);CHKERRQ(ierr); 1154 ierr = KSPSolve(jac->kspschur,ilinkD->x,ilinkD->y);CHKERRQ(ierr); 1155 ierr = KSPCheckSolve(jac->kspschur,pc,ilinkD->y);CHKERRQ(ierr); 1156 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); 1157 ierr = VecScale(ilinkA->x,-1.);CHKERRQ(ierr); 1158 ierr = VecScatterBegin(ilinkA->sctx,x,ilinkA->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 1159 ierr = VecScatterBegin(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 1160 ierr = VecScatterEnd(ilinkA->sctx,x,ilinkA->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 1161 ierr = PetscLogEventBegin(ilinkA->event,kspA,ilinkA->x,ilinkA->y,NULL);CHKERRQ(ierr); 1162 ierr = KSPSolve(kspA,ilinkA->x,ilinkA->y);CHKERRQ(ierr); 1163 ierr = KSPCheckSolve(kspA,pc,ilinkA->y);CHKERRQ(ierr); 1164 ierr = PetscLogEventEnd(ilinkA->event,kspA,ilinkA->x,ilinkA->y,NULL);CHKERRQ(ierr); 1165 ierr = VecScatterEnd(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 1166 ierr = VecScatterBegin(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 1167 ierr = VecScatterEnd(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 1168 break; 1169 case PC_FIELDSPLIT_SCHUR_FACT_FULL: 1170 /* [1 0; A10 A00^{-1} 1] [A00 0; 0 S] [1 A00^{-1}A01; 0 1] */ 1171 ierr = VecScatterBegin(ilinkA->sctx,x,ilinkA->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 1172 ierr = VecScatterEnd(ilinkA->sctx,x,ilinkA->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 1173 ierr = PetscLogEventBegin(KSP_Solve_FS_L,kspLower,ilinkA->x,ilinkA->y,NULL);CHKERRQ(ierr); 1174 ierr = KSPSolve(kspLower,ilinkA->x,ilinkA->y);CHKERRQ(ierr); 1175 ierr = KSPCheckSolve(kspLower,pc,ilinkA->y);CHKERRQ(ierr); 1176 ierr = PetscLogEventEnd(KSP_Solve_FS_L,kspLower,ilinkA->x,ilinkA->y,NULL);CHKERRQ(ierr); 1177 ierr = MatMult(jac->C,ilinkA->y,ilinkD->x);CHKERRQ(ierr); 1178 ierr = VecScale(ilinkD->x,-1.0);CHKERRQ(ierr); 1179 ierr = VecScatterBegin(ilinkD->sctx,x,ilinkD->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 1180 ierr = VecScatterEnd(ilinkD->sctx,x,ilinkD->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 1181 1182 ierr = PetscLogEventBegin(KSP_Solve_FS_S,jac->kspschur,ilinkD->x,ilinkD->y,NULL);CHKERRQ(ierr); 1183 ierr = KSPSolve(jac->kspschur,ilinkD->x,ilinkD->y);CHKERRQ(ierr); 1184 ierr = KSPCheckSolve(jac->kspschur,pc,ilinkD->y);CHKERRQ(ierr); 1185 ierr = PetscLogEventEnd(KSP_Solve_FS_S,jac->kspschur,ilinkD->x,ilinkD->y,NULL);CHKERRQ(ierr); 1186 ierr = VecScatterBegin(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 1187 1188 if (kspUpper == kspA) { 1189 ierr = MatMult(jac->B,ilinkD->y,ilinkA->y);CHKERRQ(ierr); 1190 ierr = VecAXPY(ilinkA->x,-1.0,ilinkA->y);CHKERRQ(ierr); 1191 ierr = PetscLogEventBegin(ilinkA->event,kspA,ilinkA->x,ilinkA->y,NULL);CHKERRQ(ierr); 1192 ierr = KSPSolve(kspA,ilinkA->x,ilinkA->y);CHKERRQ(ierr); 1193 ierr = KSPCheckSolve(kspA,pc,ilinkA->y);CHKERRQ(ierr); 1194 ierr = PetscLogEventEnd(ilinkA->event,kspA,ilinkA->x,ilinkA->y,NULL);CHKERRQ(ierr); 1195 } else { 1196 ierr = PetscLogEventBegin(ilinkA->event,kspA,ilinkA->x,ilinkA->y,NULL);CHKERRQ(ierr); 1197 ierr = KSPSolve(kspA,ilinkA->x,ilinkA->y);CHKERRQ(ierr); 1198 ierr = KSPCheckSolve(kspA,pc,ilinkA->y);CHKERRQ(ierr); 1199 ierr = MatMult(jac->B,ilinkD->y,ilinkA->x);CHKERRQ(ierr); 1200 ierr = PetscLogEventBegin(KSP_Solve_FS_U,kspUpper,ilinkA->x,ilinkA->z,NULL);CHKERRQ(ierr); 1201 ierr = KSPSolve(kspUpper,ilinkA->x,ilinkA->z);CHKERRQ(ierr); 1202 ierr = KSPCheckSolve(kspUpper,pc,ilinkA->z);CHKERRQ(ierr); 1203 ierr = PetscLogEventEnd(KSP_Solve_FS_U,kspUpper,ilinkA->x,ilinkA->z,NULL);CHKERRQ(ierr); 1204 ierr = VecAXPY(ilinkA->y,-1.0,ilinkA->z);CHKERRQ(ierr); 1205 } 1206 ierr = VecScatterEnd(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 1207 ierr = VecScatterBegin(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 1208 ierr = VecScatterEnd(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 1209 } 1210 PetscFunctionReturn(0); 1211 } 1212 1213 static PetscErrorCode PCApply_FieldSplit(PC pc,Vec x,Vec y) 1214 { 1215 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 1216 PetscErrorCode ierr; 1217 PC_FieldSplitLink ilink = jac->head; 1218 PetscInt cnt,bs; 1219 1220 PetscFunctionBegin; 1221 if (jac->type == PC_COMPOSITE_ADDITIVE) { 1222 if (jac->defaultsplit) { 1223 ierr = VecGetBlockSize(x,&bs);CHKERRQ(ierr); 1224 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); 1225 ierr = VecGetBlockSize(y,&bs);CHKERRQ(ierr); 1226 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); 1227 ierr = VecStrideGatherAll(x,jac->x,INSERT_VALUES);CHKERRQ(ierr); 1228 while (ilink) { 1229 ierr = PetscLogEventBegin(ilink->event,ilink->ksp,ilink->x,ilink->y,NULL);CHKERRQ(ierr); 1230 ierr = KSPSolve(ilink->ksp,ilink->x,ilink->y);CHKERRQ(ierr); 1231 ierr = KSPCheckSolve(ilink->ksp,pc,ilink->y);CHKERRQ(ierr); 1232 ierr = PetscLogEventEnd(ilink->event,ilink->ksp,ilink->x,ilink->y,NULL);CHKERRQ(ierr); 1233 ilink = ilink->next; 1234 } 1235 ierr = VecStrideScatterAll(jac->y,y,INSERT_VALUES);CHKERRQ(ierr); 1236 } else { 1237 ierr = VecSet(y,0.0);CHKERRQ(ierr); 1238 while (ilink) { 1239 ierr = FieldSplitSplitSolveAdd(ilink,x,y);CHKERRQ(ierr); 1240 ilink = ilink->next; 1241 } 1242 } 1243 } else if (jac->type == PC_COMPOSITE_MULTIPLICATIVE && jac->nsplits == 2) { 1244 ierr = VecSet(y,0.0);CHKERRQ(ierr); 1245 /* solve on first block for first block variables */ 1246 ierr = VecScatterBegin(ilink->sctx,x,ilink->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 1247 ierr = VecScatterEnd(ilink->sctx,x,ilink->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 1248 ierr = PetscLogEventBegin(ilink->event,ilink->ksp,ilink->x,ilink->y,NULL);CHKERRQ(ierr); 1249 ierr = KSPSolve(ilink->ksp,ilink->x,ilink->y);CHKERRQ(ierr); 1250 ierr = KSPCheckSolve(ilink->ksp,pc,ilink->y);CHKERRQ(ierr); 1251 ierr = PetscLogEventEnd(ilink->event,ilink->ksp,ilink->x,ilink->y,NULL);CHKERRQ(ierr); 1252 ierr = VecScatterBegin(ilink->sctx,ilink->y,y,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 1253 ierr = VecScatterEnd(ilink->sctx,ilink->y,y,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 1254 1255 /* compute the residual only onto second block variables using first block variables */ 1256 ierr = MatMult(jac->Afield[1],ilink->y,ilink->next->x);CHKERRQ(ierr); 1257 ilink = ilink->next; 1258 ierr = VecScale(ilink->x,-1.0);CHKERRQ(ierr); 1259 ierr = VecScatterBegin(ilink->sctx,x,ilink->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 1260 ierr = VecScatterEnd(ilink->sctx,x,ilink->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 1261 1262 /* solve on second block variables */ 1263 ierr = PetscLogEventBegin(ilink->event,ilink->ksp,ilink->x,ilink->y,NULL);CHKERRQ(ierr); 1264 ierr = KSPSolve(ilink->ksp,ilink->x,ilink->y);CHKERRQ(ierr); 1265 ierr = KSPCheckSolve(ilink->ksp,pc,ilink->y);CHKERRQ(ierr); 1266 ierr = PetscLogEventEnd(ilink->event,ilink->ksp,ilink->x,ilink->y,NULL);CHKERRQ(ierr); 1267 ierr = VecScatterBegin(ilink->sctx,ilink->y,y,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 1268 ierr = VecScatterEnd(ilink->sctx,ilink->y,y,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 1269 } else if (jac->type == PC_COMPOSITE_MULTIPLICATIVE || jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) { 1270 if (!jac->w1) { 1271 ierr = VecDuplicate(x,&jac->w1);CHKERRQ(ierr); 1272 ierr = VecDuplicate(x,&jac->w2);CHKERRQ(ierr); 1273 } 1274 ierr = VecSet(y,0.0);CHKERRQ(ierr); 1275 ierr = FieldSplitSplitSolveAdd(ilink,x,y);CHKERRQ(ierr); 1276 cnt = 1; 1277 while (ilink->next) { 1278 ilink = ilink->next; 1279 /* compute the residual only over the part of the vector needed */ 1280 ierr = MatMult(jac->Afield[cnt++],y,ilink->x);CHKERRQ(ierr); 1281 ierr = VecScale(ilink->x,-1.0);CHKERRQ(ierr); 1282 ierr = VecScatterBegin(ilink->sctx,x,ilink->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 1283 ierr = VecScatterEnd(ilink->sctx,x,ilink->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 1284 ierr = PetscLogEventBegin(ilink->event,ilink->ksp,ilink->x,ilink->y,NULL);CHKERRQ(ierr); 1285 ierr = KSPSolve(ilink->ksp,ilink->x,ilink->y);CHKERRQ(ierr); 1286 ierr = KSPCheckSolve(ilink->ksp,pc,ilink->y);CHKERRQ(ierr); 1287 ierr = PetscLogEventEnd(ilink->event,ilink->ksp,ilink->x,ilink->y,NULL);CHKERRQ(ierr); 1288 ierr = VecScatterBegin(ilink->sctx,ilink->y,y,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 1289 ierr = VecScatterEnd(ilink->sctx,ilink->y,y,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 1290 } 1291 if (jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) { 1292 cnt -= 2; 1293 while (ilink->previous) { 1294 ilink = ilink->previous; 1295 /* compute the residual only over the part of the vector needed */ 1296 ierr = MatMult(jac->Afield[cnt--],y,ilink->x);CHKERRQ(ierr); 1297 ierr = VecScale(ilink->x,-1.0);CHKERRQ(ierr); 1298 ierr = VecScatterBegin(ilink->sctx,x,ilink->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 1299 ierr = VecScatterEnd(ilink->sctx,x,ilink->x,ADD_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 1300 ierr = PetscLogEventBegin(ilink->event,ilink->ksp,ilink->x,ilink->y,NULL);CHKERRQ(ierr); 1301 ierr = KSPSolve(ilink->ksp,ilink->x,ilink->y);CHKERRQ(ierr); 1302 ierr = KSPCheckSolve(ilink->ksp,pc,ilink->y);CHKERRQ(ierr); 1303 ierr = PetscLogEventEnd(ilink->event,ilink->ksp,ilink->x,ilink->y,NULL);CHKERRQ(ierr); 1304 ierr = VecScatterBegin(ilink->sctx,ilink->y,y,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 1305 ierr = VecScatterEnd(ilink->sctx,ilink->y,y,ADD_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 1306 } 1307 } 1308 } else SETERRQ1(PetscObjectComm((PetscObject)pc),PETSC_ERR_SUP,"Unsupported or unknown composition",(int) jac->type); 1309 PetscFunctionReturn(0); 1310 } 1311 1312 1313 static PetscErrorCode PCApply_FieldSplit_GKB(PC pc,Vec x,Vec y) 1314 { 1315 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 1316 PetscErrorCode ierr; 1317 PC_FieldSplitLink ilinkA = jac->head,ilinkD = ilinkA->next; 1318 KSP ksp = ilinkA->ksp; 1319 Vec u,v,Hu,d,work1,work2; 1320 PetscScalar alpha,z,nrmz2,*vecz; 1321 PetscReal lowbnd,nu,beta; 1322 PetscInt j,iterGKB; 1323 1324 PetscFunctionBegin; 1325 ierr = VecScatterBegin(ilinkA->sctx,x,ilinkA->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 1326 ierr = VecScatterBegin(ilinkD->sctx,x,ilinkD->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 1327 ierr = VecScatterEnd(ilinkA->sctx,x,ilinkA->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 1328 ierr = VecScatterEnd(ilinkD->sctx,x,ilinkD->x,INSERT_VALUES,SCATTER_FORWARD);CHKERRQ(ierr); 1329 1330 u = jac->u; 1331 v = jac->v; 1332 Hu = jac->Hu; 1333 d = jac->d; 1334 work1 = jac->w1; 1335 work2 = jac->w2; 1336 vecz = jac->vecz; 1337 1338 /* Change RHS to comply with matrix regularization H = A + nu*B*B' */ 1339 /* Add q = q + nu*B*b */ 1340 if (jac->gkbnu) { 1341 nu = jac->gkbnu; 1342 ierr = VecScale(ilinkD->x,jac->gkbnu);CHKERRQ(ierr); 1343 ierr = MatMultAdd(jac->B,ilinkD->x,ilinkA->x,ilinkA->x);CHKERRQ(ierr); /* q = q + nu*B*b */ 1344 } else { 1345 /* Situation when no augmented Lagrangian is used. Then we set inner */ 1346 /* matrix N = I in [Ar13], and thus nu = 1. */ 1347 nu = 1; 1348 } 1349 1350 /* Transform rhs from [q,tilde{b}] to [0,b] */ 1351 ierr = PetscLogEventBegin(ilinkA->event,ksp,ilinkA->x,ilinkA->y,NULL);CHKERRQ(ierr); 1352 ierr = KSPSolve(ksp,ilinkA->x,ilinkA->y);CHKERRQ(ierr); 1353 ierr = KSPCheckSolve(ksp,pc,ilinkA->y);CHKERRQ(ierr); 1354 ierr = PetscLogEventEnd(ilinkA->event,ksp,ilinkA->x,ilinkA->y,NULL);CHKERRQ(ierr); 1355 ierr = MatMultHermitianTranspose(jac->B,ilinkA->y,work1);CHKERRQ(ierr); 1356 ierr = VecAXPBY(work1,1.0/nu,-1.0,ilinkD->x);CHKERRQ(ierr); /* c = b - B'*x */ 1357 1358 /* First step of algorithm */ 1359 ierr = VecNorm(work1,NORM_2,&beta);CHKERRQ(ierr); /* beta = sqrt(nu*c'*c)*/ 1360 KSPCheckDot(ksp,beta); 1361 beta = PetscSqrtScalar(nu)*beta; 1362 ierr = VecAXPBY(v,nu/beta,0.0,work1);CHKERRQ(ierr); /* v = nu/beta *c */ 1363 ierr = MatMult(jac->B,v,work2);CHKERRQ(ierr); /* u = H^{-1}*B*v */ 1364 ierr = PetscLogEventBegin(ilinkA->event,ksp,work2,u,NULL);CHKERRQ(ierr); 1365 ierr = KSPSolve(ksp,work2,u);CHKERRQ(ierr); 1366 ierr = KSPCheckSolve(ksp,pc,u);CHKERRQ(ierr); 1367 ierr = PetscLogEventEnd(ilinkA->event,ksp,work2,u,NULL);CHKERRQ(ierr); 1368 ierr = MatMult(jac->H,u,Hu);CHKERRQ(ierr); /* alpha = u'*H*u */ 1369 ierr = VecDot(Hu,u,&alpha);CHKERRQ(ierr); 1370 KSPCheckDot(ksp,alpha); 1371 if (PetscRealPart(alpha) <= 0.0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_NOT_CONVERGED,"GKB preconditioner diverged, H is not positive definite"); 1372 alpha = PetscSqrtScalar(PetscAbsScalar(alpha)); 1373 ierr = VecScale(u,1.0/alpha);CHKERRQ(ierr); 1374 ierr = VecAXPBY(d,1.0/alpha,0.0,v);CHKERRQ(ierr); /* v = nu/beta *c */ 1375 1376 z = beta/alpha; 1377 vecz[1] = z; 1378 1379 /* Computation of first iterate x(1) and p(1) */ 1380 ierr = VecAXPY(ilinkA->y,z,u);CHKERRQ(ierr); 1381 ierr = VecCopy(d,ilinkD->y);CHKERRQ(ierr); 1382 ierr = VecScale(ilinkD->y,-z);CHKERRQ(ierr); 1383 1384 iterGKB = 1; lowbnd = 2*jac->gkbtol; 1385 if (jac->gkbmonitor) { 1386 ierr = PetscViewerASCIIPrintf(jac->gkbviewer,"%3D GKB Lower bound estimate %14.12e\n",iterGKB,lowbnd);CHKERRQ(ierr); 1387 } 1388 1389 while (iterGKB < jac->gkbmaxit && lowbnd > jac->gkbtol) { 1390 iterGKB += 1; 1391 ierr = MatMultHermitianTranspose(jac->B,u,work1);CHKERRQ(ierr); /* v <- nu*(B'*u-alpha/nu*v) */ 1392 ierr = VecAXPBY(v,nu,-alpha,work1);CHKERRQ(ierr); 1393 ierr = VecNorm(v,NORM_2,&beta);CHKERRQ(ierr); /* beta = sqrt(nu)*v'*v */ 1394 beta = beta/PetscSqrtScalar(nu); 1395 ierr = VecScale(v,1.0/beta);CHKERRQ(ierr); 1396 ierr = MatMult(jac->B,v,work2);CHKERRQ(ierr); /* u <- H^{-1}*(B*v-beta*H*u) */ 1397 ierr = MatMult(jac->H,u,Hu);CHKERRQ(ierr); 1398 ierr = VecAXPY(work2,-beta,Hu);CHKERRQ(ierr); 1399 ierr = PetscLogEventBegin(ilinkA->event,ksp,work2,u,NULL);CHKERRQ(ierr); 1400 ierr = KSPSolve(ksp,work2,u);CHKERRQ(ierr); 1401 ierr = KSPCheckSolve(ksp,pc,u);CHKERRQ(ierr); 1402 ierr = PetscLogEventEnd(ilinkA->event,ksp,work2,u,NULL);CHKERRQ(ierr); 1403 ierr = MatMult(jac->H,u,Hu);CHKERRQ(ierr); /* alpha = u'*H*u */ 1404 ierr = VecDot(Hu,u,&alpha);CHKERRQ(ierr); 1405 KSPCheckDot(ksp,alpha); 1406 if (PetscRealPart(alpha) <= 0.0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_NOT_CONVERGED,"GKB preconditioner diverged, H is not positive definite"); 1407 alpha = PetscSqrtScalar(PetscAbsScalar(alpha)); 1408 ierr = VecScale(u,1.0/alpha);CHKERRQ(ierr); 1409 1410 z = -beta/alpha*z; /* z <- beta/alpha*z */ 1411 vecz[0] = z; 1412 1413 /* Computation of new iterate x(i+1) and p(i+1) */ 1414 ierr = VecAXPBY(d,1.0/alpha,-beta/alpha,v);CHKERRQ(ierr); /* d = (v-beta*d)/alpha */ 1415 ierr = VecAXPY(ilinkA->y,z,u);CHKERRQ(ierr); /* r = r + z*u */ 1416 ierr = VecAXPY(ilinkD->y,-z,d);CHKERRQ(ierr); /* p = p - z*d */ 1417 ierr = MatMult(jac->H,ilinkA->y,Hu);CHKERRQ(ierr); /* ||u||_H = u'*H*u */ 1418 ierr = VecDot(Hu,ilinkA->y,&nrmz2);CHKERRQ(ierr); 1419 1420 /* Compute Lower Bound estimate */ 1421 if (iterGKB > jac->gkbdelay) { 1422 lowbnd = 0.0; 1423 for (j=0; j<jac->gkbdelay; j++) { 1424 lowbnd += PetscAbsScalar(vecz[j]*vecz[j]); 1425 } 1426 lowbnd = PetscSqrtScalar(lowbnd/PetscAbsScalar(nrmz2)); 1427 } 1428 1429 for (j=0; j<jac->gkbdelay-1; j++) { 1430 vecz[jac->gkbdelay-j-1] = vecz[jac->gkbdelay-j-2]; 1431 } 1432 if (jac->gkbmonitor) { 1433 ierr = PetscViewerASCIIPrintf(jac->gkbviewer,"%3D GKB Lower bound estimate %14.12e\n",iterGKB,lowbnd);CHKERRQ(ierr); 1434 } 1435 } 1436 1437 ierr = VecScatterBegin(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 1438 ierr = VecScatterEnd(ilinkA->sctx,ilinkA->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 1439 ierr = VecScatterBegin(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 1440 ierr = VecScatterEnd(ilinkD->sctx,ilinkD->y,y,INSERT_VALUES,SCATTER_REVERSE);CHKERRQ(ierr); 1441 1442 PetscFunctionReturn(0); 1443 } 1444 1445 1446 #define FieldSplitSplitSolveAddTranspose(ilink,xx,yy) \ 1447 (VecScatterBegin(ilink->sctx,xx,ilink->y,INSERT_VALUES,SCATTER_FORWARD) || \ 1448 VecScatterEnd(ilink->sctx,xx,ilink->y,INSERT_VALUES,SCATTER_FORWARD) || \ 1449 PetscLogEventBegin(ilink->event,ilink->ksp,ilink->y,ilink->x,NULL) || \ 1450 KSPSolveTranspose(ilink->ksp,ilink->y,ilink->x) || \ 1451 KSPCheckSolve(ilink->ksp,pc,ilink->x) || \ 1452 PetscLogEventEnd(ilink->event,ilink->ksp,ilink->y,ilink->x,NULL) || \ 1453 VecScatterBegin(ilink->sctx,ilink->x,yy,ADD_VALUES,SCATTER_REVERSE) || \ 1454 VecScatterEnd(ilink->sctx,ilink->x,yy,ADD_VALUES,SCATTER_REVERSE)) 1455 1456 static PetscErrorCode PCApplyTranspose_FieldSplit(PC pc,Vec x,Vec y) 1457 { 1458 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 1459 PetscErrorCode ierr; 1460 PC_FieldSplitLink ilink = jac->head; 1461 PetscInt bs; 1462 1463 PetscFunctionBegin; 1464 if (jac->type == PC_COMPOSITE_ADDITIVE) { 1465 if (jac->defaultsplit) { 1466 ierr = VecGetBlockSize(x,&bs);CHKERRQ(ierr); 1467 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); 1468 ierr = VecGetBlockSize(y,&bs);CHKERRQ(ierr); 1469 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); 1470 ierr = VecStrideGatherAll(x,jac->x,INSERT_VALUES);CHKERRQ(ierr); 1471 while (ilink) { 1472 ierr = PetscLogEventBegin(ilink->event,ilink->ksp,ilink->x,ilink->y,NULL);CHKERRQ(ierr); 1473 ierr = KSPSolveTranspose(ilink->ksp,ilink->x,ilink->y);CHKERRQ(ierr); 1474 ierr = KSPCheckSolve(ilink->ksp,pc,ilink->y);CHKERRQ(ierr); 1475 ierr = PetscLogEventEnd(ilink->event,ilink->ksp,ilink->x,ilink->y,NULL);CHKERRQ(ierr); 1476 ilink = ilink->next; 1477 } 1478 ierr = VecStrideScatterAll(jac->y,y,INSERT_VALUES);CHKERRQ(ierr); 1479 } else { 1480 ierr = VecSet(y,0.0);CHKERRQ(ierr); 1481 while (ilink) { 1482 ierr = FieldSplitSplitSolveAddTranspose(ilink,x,y);CHKERRQ(ierr); 1483 ilink = ilink->next; 1484 } 1485 } 1486 } else { 1487 if (!jac->w1) { 1488 ierr = VecDuplicate(x,&jac->w1);CHKERRQ(ierr); 1489 ierr = VecDuplicate(x,&jac->w2);CHKERRQ(ierr); 1490 } 1491 ierr = VecSet(y,0.0);CHKERRQ(ierr); 1492 if (jac->type == PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE) { 1493 ierr = FieldSplitSplitSolveAddTranspose(ilink,x,y);CHKERRQ(ierr); 1494 while (ilink->next) { 1495 ilink = ilink->next; 1496 ierr = MatMultTranspose(pc->mat,y,jac->w1);CHKERRQ(ierr); 1497 ierr = VecWAXPY(jac->w2,-1.0,jac->w1,x);CHKERRQ(ierr); 1498 ierr = FieldSplitSplitSolveAddTranspose(ilink,jac->w2,y);CHKERRQ(ierr); 1499 } 1500 while (ilink->previous) { 1501 ilink = ilink->previous; 1502 ierr = MatMultTranspose(pc->mat,y,jac->w1);CHKERRQ(ierr); 1503 ierr = VecWAXPY(jac->w2,-1.0,jac->w1,x);CHKERRQ(ierr); 1504 ierr = FieldSplitSplitSolveAddTranspose(ilink,jac->w2,y);CHKERRQ(ierr); 1505 } 1506 } else { 1507 while (ilink->next) { /* get to last entry in linked list */ 1508 ilink = ilink->next; 1509 } 1510 ierr = FieldSplitSplitSolveAddTranspose(ilink,x,y);CHKERRQ(ierr); 1511 while (ilink->previous) { 1512 ilink = ilink->previous; 1513 ierr = MatMultTranspose(pc->mat,y,jac->w1);CHKERRQ(ierr); 1514 ierr = VecWAXPY(jac->w2,-1.0,jac->w1,x);CHKERRQ(ierr); 1515 ierr = FieldSplitSplitSolveAddTranspose(ilink,jac->w2,y);CHKERRQ(ierr); 1516 } 1517 } 1518 } 1519 PetscFunctionReturn(0); 1520 } 1521 1522 static PetscErrorCode PCReset_FieldSplit(PC pc) 1523 { 1524 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 1525 PetscErrorCode ierr; 1526 PC_FieldSplitLink ilink = jac->head,next; 1527 1528 PetscFunctionBegin; 1529 while (ilink) { 1530 ierr = KSPDestroy(&ilink->ksp);CHKERRQ(ierr); 1531 ierr = VecDestroy(&ilink->x);CHKERRQ(ierr); 1532 ierr = VecDestroy(&ilink->y);CHKERRQ(ierr); 1533 ierr = VecDestroy(&ilink->z);CHKERRQ(ierr); 1534 ierr = VecScatterDestroy(&ilink->sctx);CHKERRQ(ierr); 1535 ierr = ISDestroy(&ilink->is);CHKERRQ(ierr); 1536 ierr = ISDestroy(&ilink->is_col);CHKERRQ(ierr); 1537 ierr = PetscFree(ilink->splitname);CHKERRQ(ierr); 1538 ierr = PetscFree(ilink->fields);CHKERRQ(ierr); 1539 ierr = PetscFree(ilink->fields_col);CHKERRQ(ierr); 1540 next = ilink->next; 1541 ierr = PetscFree(ilink);CHKERRQ(ierr); 1542 ilink = next; 1543 } 1544 jac->head = NULL; 1545 ierr = PetscFree2(jac->x,jac->y);CHKERRQ(ierr); 1546 if (jac->mat && jac->mat != jac->pmat) { 1547 ierr = MatDestroyMatrices(jac->nsplits,&jac->mat);CHKERRQ(ierr); 1548 } else if (jac->mat) { 1549 jac->mat = NULL; 1550 } 1551 if (jac->pmat) {ierr = MatDestroyMatrices(jac->nsplits,&jac->pmat);CHKERRQ(ierr);} 1552 if (jac->Afield) {ierr = MatDestroyMatrices(jac->nsplits,&jac->Afield);CHKERRQ(ierr);} 1553 jac->nsplits = 0; 1554 ierr = VecDestroy(&jac->w1);CHKERRQ(ierr); 1555 ierr = VecDestroy(&jac->w2);CHKERRQ(ierr); 1556 ierr = MatDestroy(&jac->schur);CHKERRQ(ierr); 1557 ierr = MatDestroy(&jac->schurp);CHKERRQ(ierr); 1558 ierr = MatDestroy(&jac->schur_user);CHKERRQ(ierr); 1559 ierr = KSPDestroy(&jac->kspschur);CHKERRQ(ierr); 1560 ierr = KSPDestroy(&jac->kspupper);CHKERRQ(ierr); 1561 ierr = MatDestroy(&jac->B);CHKERRQ(ierr); 1562 ierr = MatDestroy(&jac->C);CHKERRQ(ierr); 1563 ierr = MatDestroy(&jac->H);CHKERRQ(ierr); 1564 ierr = VecDestroy(&jac->u);CHKERRQ(ierr); 1565 ierr = VecDestroy(&jac->v);CHKERRQ(ierr); 1566 ierr = VecDestroy(&jac->Hu);CHKERRQ(ierr); 1567 ierr = VecDestroy(&jac->d);CHKERRQ(ierr); 1568 ierr = PetscFree(jac->vecz);CHKERRQ(ierr); 1569 ierr = PetscViewerDestroy(&jac->gkbviewer);CHKERRQ(ierr); 1570 jac->isrestrict = PETSC_FALSE; 1571 PetscFunctionReturn(0); 1572 } 1573 1574 static PetscErrorCode PCDestroy_FieldSplit(PC pc) 1575 { 1576 PetscErrorCode ierr; 1577 1578 PetscFunctionBegin; 1579 ierr = PCReset_FieldSplit(pc);CHKERRQ(ierr); 1580 ierr = PetscFree(pc->data);CHKERRQ(ierr); 1581 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitSchurGetSubKSP_C",NULL);CHKERRQ(ierr); 1582 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitGetSubKSP_C",NULL);CHKERRQ(ierr); 1583 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitSetFields_C",NULL);CHKERRQ(ierr); 1584 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitSetIS_C",NULL);CHKERRQ(ierr); 1585 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitSetType_C",NULL);CHKERRQ(ierr); 1586 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitSetBlockSize_C",NULL);CHKERRQ(ierr); 1587 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitSetSchurPre_C",NULL);CHKERRQ(ierr); 1588 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitGetSchurPre_C",NULL);CHKERRQ(ierr); 1589 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitSetSchurFactType_C",NULL);CHKERRQ(ierr); 1590 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitRestrictIS_C",NULL);CHKERRQ(ierr); 1591 PetscFunctionReturn(0); 1592 } 1593 1594 static PetscErrorCode PCSetFromOptions_FieldSplit(PetscOptionItems *PetscOptionsObject,PC pc) 1595 { 1596 PetscErrorCode ierr; 1597 PetscInt bs; 1598 PetscBool flg; 1599 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 1600 PCCompositeType ctype; 1601 1602 PetscFunctionBegin; 1603 ierr = PetscOptionsHead(PetscOptionsObject,"FieldSplit options");CHKERRQ(ierr); 1604 ierr = PetscOptionsBool("-pc_fieldsplit_dm_splits","Whether to use DMCreateFieldDecomposition() for splits","PCFieldSplitSetDMSplits",jac->dm_splits,&jac->dm_splits,NULL);CHKERRQ(ierr); 1605 ierr = PetscOptionsInt("-pc_fieldsplit_block_size","Blocksize that defines number of fields","PCFieldSplitSetBlockSize",jac->bs,&bs,&flg);CHKERRQ(ierr); 1606 if (flg) { 1607 ierr = PCFieldSplitSetBlockSize(pc,bs);CHKERRQ(ierr); 1608 } 1609 jac->diag_use_amat = pc->useAmat; 1610 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); 1611 jac->offdiag_use_amat = pc->useAmat; 1612 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); 1613 ierr = PetscOptionsBool("-pc_fieldsplit_detect_saddle_point","Form 2-way split by detecting zero diagonal entries", "PCFieldSplitSetDetectSaddlePoint",jac->detect,&jac->detect,NULL);CHKERRQ(ierr); 1614 ierr = PCFieldSplitSetDetectSaddlePoint(pc,jac->detect);CHKERRQ(ierr); /* Sets split type and Schur PC type */ 1615 ierr = PetscOptionsEnum("-pc_fieldsplit_type","Type of composition","PCFieldSplitSetType",PCCompositeTypes,(PetscEnum)jac->type,(PetscEnum*)&ctype,&flg);CHKERRQ(ierr); 1616 if (flg) { 1617 ierr = PCFieldSplitSetType(pc,ctype);CHKERRQ(ierr); 1618 } 1619 /* Only setup fields once */ 1620 if ((jac->bs > 0) && (jac->nsplits == 0)) { 1621 /* only allow user to set fields from command line if bs is already known. 1622 otherwise user can set them in PCFieldSplitSetDefaults() */ 1623 ierr = PCFieldSplitSetRuntimeSplits_Private(pc);CHKERRQ(ierr); 1624 if (jac->splitdefined) {ierr = PetscInfo(pc,"Splits defined using the options database\n");CHKERRQ(ierr);} 1625 } 1626 if (jac->type == PC_COMPOSITE_SCHUR) { 1627 ierr = PetscOptionsGetEnum(((PetscObject)pc)->options,((PetscObject)pc)->prefix,"-pc_fieldsplit_schur_factorization_type",PCFieldSplitSchurFactTypes,(PetscEnum*)&jac->schurfactorization,&flg);CHKERRQ(ierr); 1628 if (flg) {ierr = PetscInfo(pc,"Deprecated use of -pc_fieldsplit_schur_factorization_type\n");CHKERRQ(ierr);} 1629 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); 1630 ierr = PetscOptionsEnum("-pc_fieldsplit_schur_precondition","How to build preconditioner for Schur complement","PCFieldSplitSetSchurPre",PCFieldSplitSchurPreTypes,(PetscEnum)jac->schurpre,(PetscEnum*)&jac->schurpre,NULL);CHKERRQ(ierr); 1631 ierr = PetscOptionsScalar("-pc_fieldsplit_schur_scale","Scale Schur complement","PCFieldSplitSetSchurScale",jac->schurscale,&jac->schurscale,NULL);CHKERRQ(ierr); 1632 } else if (jac->type == PC_COMPOSITE_GKB) { 1633 ierr = PetscOptionsReal("-pc_fieldsplit_gkb_tol","The tolerance for the lower bound stopping criterion","PCFieldSplitGKBTol",jac->gkbtol,&jac->gkbtol,NULL);CHKERRQ(ierr); 1634 ierr = PetscOptionsInt("-pc_fieldsplit_gkb_delay","The delay value for lower bound criterion","PCFieldSplitGKBDelay",jac->gkbdelay,&jac->gkbdelay,NULL);CHKERRQ(ierr); 1635 ierr = PetscOptionsReal("-pc_fieldsplit_gkb_nu","Parameter in augmented Lagrangian approach","PCFieldSplitGKBNu",jac->gkbnu,&jac->gkbnu,NULL);CHKERRQ(ierr); 1636 if (jac->gkbnu < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"nu cannot be less than 0: value %f",jac->gkbnu); 1637 ierr = PetscOptionsInt("-pc_fieldsplit_gkb_maxit","Maximum allowed number of iterations","PCFieldSplitGKBMaxit",jac->gkbmaxit,&jac->gkbmaxit,NULL);CHKERRQ(ierr); 1638 ierr = PetscOptionsBool("-pc_fieldsplit_gkb_monitor","Prints number of GKB iterations and error","PCFieldSplitGKB",jac->gkbmonitor,&jac->gkbmonitor,NULL);CHKERRQ(ierr); 1639 } 1640 ierr = PetscOptionsTail();CHKERRQ(ierr); 1641 PetscFunctionReturn(0); 1642 } 1643 1644 /*------------------------------------------------------------------------------------*/ 1645 1646 static PetscErrorCode PCFieldSplitSetFields_FieldSplit(PC pc,const char splitname[],PetscInt n,const PetscInt *fields,const PetscInt *fields_col) 1647 { 1648 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 1649 PetscErrorCode ierr; 1650 PC_FieldSplitLink ilink,next = jac->head; 1651 char prefix[128]; 1652 PetscInt i; 1653 1654 PetscFunctionBegin; 1655 if (jac->splitdefined) { 1656 ierr = PetscInfo1(pc,"Ignoring new split \"%s\" because the splits have already been defined\n",splitname);CHKERRQ(ierr); 1657 PetscFunctionReturn(0); 1658 } 1659 for (i=0; i<n; i++) { 1660 if (fields[i] >= jac->bs) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Field %D requested but only %D exist",fields[i],jac->bs); 1661 if (fields[i] < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Negative field %D requested",fields[i]); 1662 } 1663 ierr = PetscNew(&ilink);CHKERRQ(ierr); 1664 if (splitname) { 1665 ierr = PetscStrallocpy(splitname,&ilink->splitname);CHKERRQ(ierr); 1666 } else { 1667 ierr = PetscMalloc1(3,&ilink->splitname);CHKERRQ(ierr); 1668 ierr = PetscSNPrintf(ilink->splitname,2,"%s",jac->nsplits);CHKERRQ(ierr); 1669 } 1670 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 */ 1671 ierr = PetscMalloc1(n,&ilink->fields);CHKERRQ(ierr); 1672 ierr = PetscArraycpy(ilink->fields,fields,n);CHKERRQ(ierr); 1673 ierr = PetscMalloc1(n,&ilink->fields_col);CHKERRQ(ierr); 1674 ierr = PetscArraycpy(ilink->fields_col,fields_col,n);CHKERRQ(ierr); 1675 1676 ilink->nfields = n; 1677 ilink->next = NULL; 1678 ierr = KSPCreate(PetscObjectComm((PetscObject)pc),&ilink->ksp);CHKERRQ(ierr); 1679 ierr = KSPSetErrorIfNotConverged(ilink->ksp,pc->erroriffailure);CHKERRQ(ierr); 1680 ierr = PetscObjectIncrementTabLevel((PetscObject)ilink->ksp,(PetscObject)pc,1);CHKERRQ(ierr); 1681 ierr = KSPSetType(ilink->ksp,KSPPREONLY);CHKERRQ(ierr); 1682 ierr = PetscLogObjectParent((PetscObject)pc,(PetscObject)ilink->ksp);CHKERRQ(ierr); 1683 1684 ierr = PetscSNPrintf(prefix,sizeof(prefix),"%sfieldsplit_%s_",((PetscObject)pc)->prefix ? ((PetscObject)pc)->prefix : "",ilink->splitname);CHKERRQ(ierr); 1685 ierr = KSPSetOptionsPrefix(ilink->ksp,prefix);CHKERRQ(ierr); 1686 1687 if (!next) { 1688 jac->head = ilink; 1689 ilink->previous = NULL; 1690 } else { 1691 while (next->next) { 1692 next = next->next; 1693 } 1694 next->next = ilink; 1695 ilink->previous = next; 1696 } 1697 jac->nsplits++; 1698 PetscFunctionReturn(0); 1699 } 1700 1701 static PetscErrorCode PCFieldSplitSchurGetSubKSP_FieldSplit(PC pc,PetscInt *n,KSP **subksp) 1702 { 1703 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 1704 PetscErrorCode ierr; 1705 1706 PetscFunctionBegin; 1707 *subksp = NULL; 1708 if (n) *n = 0; 1709 if (jac->type == PC_COMPOSITE_SCHUR) { 1710 PetscInt nn; 1711 1712 if (!jac->schur) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must call KSPSetUp() or PCSetUp() before calling PCFieldSplitSchurGetSubKSP()"); 1713 if (jac->nsplits != 2) SETERRQ1(PetscObjectComm((PetscObject)pc),PETSC_ERR_PLIB,"Unexpected number of splits %D != 2",jac->nsplits); 1714 nn = jac->nsplits + (jac->kspupper != jac->head->ksp ? 1 : 0); 1715 ierr = PetscMalloc1(nn,subksp);CHKERRQ(ierr); 1716 (*subksp)[0] = jac->head->ksp; 1717 (*subksp)[1] = jac->kspschur; 1718 if (jac->kspupper != jac->head->ksp) (*subksp)[2] = jac->kspupper; 1719 if (n) *n = nn; 1720 } 1721 PetscFunctionReturn(0); 1722 } 1723 1724 static PetscErrorCode PCFieldSplitGetSubKSP_FieldSplit_Schur(PC pc,PetscInt *n,KSP **subksp) 1725 { 1726 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 1727 PetscErrorCode ierr; 1728 1729 PetscFunctionBegin; 1730 if (!jac->schur) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONGSTATE,"Must call KSPSetUp() or PCSetUp() before calling PCFieldSplitGetSubKSP()"); 1731 ierr = PetscMalloc1(jac->nsplits,subksp);CHKERRQ(ierr); 1732 ierr = MatSchurComplementGetKSP(jac->schur,*subksp);CHKERRQ(ierr); 1733 1734 (*subksp)[1] = jac->kspschur; 1735 if (n) *n = jac->nsplits; 1736 PetscFunctionReturn(0); 1737 } 1738 1739 static PetscErrorCode PCFieldSplitGetSubKSP_FieldSplit(PC pc,PetscInt *n,KSP **subksp) 1740 { 1741 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 1742 PetscErrorCode ierr; 1743 PetscInt cnt = 0; 1744 PC_FieldSplitLink ilink = jac->head; 1745 1746 PetscFunctionBegin; 1747 ierr = PetscMalloc1(jac->nsplits,subksp);CHKERRQ(ierr); 1748 while (ilink) { 1749 (*subksp)[cnt++] = ilink->ksp; 1750 ilink = ilink->next; 1751 } 1752 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); 1753 if (n) *n = jac->nsplits; 1754 PetscFunctionReturn(0); 1755 } 1756 1757 /*@C 1758 PCFieldSplitRestrictIS - Restricts the fieldsplit ISs to be within a given IS. 1759 1760 Input Parameters: 1761 + pc - the preconditioner context 1762 - is - the index set that defines the indices to which the fieldsplit is to be restricted 1763 1764 Level: advanced 1765 1766 @*/ 1767 PetscErrorCode PCFieldSplitRestrictIS(PC pc,IS isy) 1768 { 1769 PetscErrorCode ierr; 1770 1771 PetscFunctionBegin; 1772 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1773 PetscValidHeaderSpecific(isy,IS_CLASSID,2); 1774 ierr = PetscTryMethod(pc,"PCFieldSplitRestrictIS_C",(PC,IS),(pc,isy));CHKERRQ(ierr); 1775 PetscFunctionReturn(0); 1776 } 1777 1778 1779 static PetscErrorCode PCFieldSplitRestrictIS_FieldSplit(PC pc, IS isy) 1780 { 1781 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 1782 PetscErrorCode ierr; 1783 PC_FieldSplitLink ilink = jac->head, next; 1784 PetscInt localsize,size,sizez,i; 1785 const PetscInt *ind, *indz; 1786 PetscInt *indc, *indcz; 1787 PetscBool flg; 1788 1789 PetscFunctionBegin; 1790 ierr = ISGetLocalSize(isy,&localsize);CHKERRQ(ierr); 1791 ierr = MPI_Scan(&localsize,&size,1,MPIU_INT,MPI_SUM,PetscObjectComm((PetscObject)isy));CHKERRQ(ierr); 1792 size -= localsize; 1793 while(ilink) { 1794 IS isrl,isr; 1795 PC subpc; 1796 ierr = ISEmbed(ilink->is, isy, PETSC_TRUE, &isrl);CHKERRQ(ierr); 1797 ierr = ISGetLocalSize(isrl,&localsize);CHKERRQ(ierr); 1798 ierr = PetscMalloc1(localsize,&indc);CHKERRQ(ierr); 1799 ierr = ISGetIndices(isrl,&ind);CHKERRQ(ierr); 1800 ierr = PetscArraycpy(indc,ind,localsize);CHKERRQ(ierr); 1801 ierr = ISRestoreIndices(isrl,&ind);CHKERRQ(ierr); 1802 ierr = ISDestroy(&isrl);CHKERRQ(ierr); 1803 for (i=0; i<localsize; i++) *(indc+i) += size; 1804 ierr = ISCreateGeneral(PetscObjectComm((PetscObject)isy),localsize,indc,PETSC_OWN_POINTER,&isr);CHKERRQ(ierr); 1805 ierr = PetscObjectReference((PetscObject)isr);CHKERRQ(ierr); 1806 ierr = ISDestroy(&ilink->is);CHKERRQ(ierr); 1807 ilink->is = isr; 1808 ierr = PetscObjectReference((PetscObject)isr);CHKERRQ(ierr); 1809 ierr = ISDestroy(&ilink->is_col);CHKERRQ(ierr); 1810 ilink->is_col = isr; 1811 ierr = ISDestroy(&isr);CHKERRQ(ierr); 1812 ierr = KSPGetPC(ilink->ksp, &subpc);CHKERRQ(ierr); 1813 ierr = PetscObjectTypeCompare((PetscObject)subpc,PCFIELDSPLIT,&flg);CHKERRQ(ierr); 1814 if(flg) { 1815 IS iszl,isz; 1816 MPI_Comm comm; 1817 ierr = ISGetLocalSize(ilink->is,&localsize);CHKERRQ(ierr); 1818 comm = PetscObjectComm((PetscObject)ilink->is); 1819 ierr = ISEmbed(isy, ilink->is, PETSC_TRUE, &iszl);CHKERRQ(ierr); 1820 ierr = MPI_Scan(&localsize,&sizez,1,MPIU_INT,MPI_SUM,comm);CHKERRQ(ierr); 1821 sizez -= localsize; 1822 ierr = ISGetLocalSize(iszl,&localsize);CHKERRQ(ierr); 1823 ierr = PetscMalloc1(localsize,&indcz);CHKERRQ(ierr); 1824 ierr = ISGetIndices(iszl,&indz);CHKERRQ(ierr); 1825 ierr = PetscArraycpy(indcz,indz,localsize);CHKERRQ(ierr); 1826 ierr = ISRestoreIndices(iszl,&indz);CHKERRQ(ierr); 1827 ierr = ISDestroy(&iszl);CHKERRQ(ierr); 1828 for (i=0; i<localsize; i++) *(indcz+i) += sizez; 1829 ierr = ISCreateGeneral(comm,localsize,indcz,PETSC_OWN_POINTER,&isz);CHKERRQ(ierr); 1830 ierr = PCFieldSplitRestrictIS(subpc,isz);CHKERRQ(ierr); 1831 ierr = ISDestroy(&isz);CHKERRQ(ierr); 1832 } 1833 next = ilink->next; 1834 ilink = next; 1835 } 1836 jac->isrestrict = PETSC_TRUE; 1837 PetscFunctionReturn(0); 1838 } 1839 1840 static PetscErrorCode PCFieldSplitSetIS_FieldSplit(PC pc,const char splitname[],IS is) 1841 { 1842 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 1843 PetscErrorCode ierr; 1844 PC_FieldSplitLink ilink, next = jac->head; 1845 char prefix[128]; 1846 1847 PetscFunctionBegin; 1848 if (jac->splitdefined) { 1849 ierr = PetscInfo1(pc,"Ignoring new split \"%s\" because the splits have already been defined\n",splitname);CHKERRQ(ierr); 1850 PetscFunctionReturn(0); 1851 } 1852 ierr = PetscNew(&ilink);CHKERRQ(ierr); 1853 if (splitname) { 1854 ierr = PetscStrallocpy(splitname,&ilink->splitname);CHKERRQ(ierr); 1855 } else { 1856 ierr = PetscMalloc1(8,&ilink->splitname);CHKERRQ(ierr); 1857 ierr = PetscSNPrintf(ilink->splitname,7,"%D",jac->nsplits);CHKERRQ(ierr); 1858 } 1859 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 */ 1860 ierr = PetscObjectReference((PetscObject)is);CHKERRQ(ierr); 1861 ierr = ISDestroy(&ilink->is);CHKERRQ(ierr); 1862 ilink->is = is; 1863 ierr = PetscObjectReference((PetscObject)is);CHKERRQ(ierr); 1864 ierr = ISDestroy(&ilink->is_col);CHKERRQ(ierr); 1865 ilink->is_col = is; 1866 ilink->next = NULL; 1867 ierr = KSPCreate(PetscObjectComm((PetscObject)pc),&ilink->ksp);CHKERRQ(ierr); 1868 ierr = KSPSetErrorIfNotConverged(ilink->ksp,pc->erroriffailure);CHKERRQ(ierr); 1869 ierr = PetscObjectIncrementTabLevel((PetscObject)ilink->ksp,(PetscObject)pc,1);CHKERRQ(ierr); 1870 ierr = KSPSetType(ilink->ksp,KSPPREONLY);CHKERRQ(ierr); 1871 ierr = PetscLogObjectParent((PetscObject)pc,(PetscObject)ilink->ksp);CHKERRQ(ierr); 1872 1873 ierr = PetscSNPrintf(prefix,sizeof(prefix),"%sfieldsplit_%s_",((PetscObject)pc)->prefix ? ((PetscObject)pc)->prefix : "",ilink->splitname);CHKERRQ(ierr); 1874 ierr = KSPSetOptionsPrefix(ilink->ksp,prefix);CHKERRQ(ierr); 1875 1876 if (!next) { 1877 jac->head = ilink; 1878 ilink->previous = NULL; 1879 } else { 1880 while (next->next) { 1881 next = next->next; 1882 } 1883 next->next = ilink; 1884 ilink->previous = next; 1885 } 1886 jac->nsplits++; 1887 PetscFunctionReturn(0); 1888 } 1889 1890 /*@C 1891 PCFieldSplitSetFields - Sets the fields for one particular split in the field split preconditioner 1892 1893 Logically Collective on PC 1894 1895 Input Parameters: 1896 + pc - the preconditioner context 1897 . splitname - name of this split, if NULL the number of the split is used 1898 . n - the number of fields in this split 1899 - fields - the fields in this split 1900 1901 Level: intermediate 1902 1903 Notes: 1904 Use PCFieldSplitSetIS() to set a completely general set of indices as a field. 1905 1906 The PCFieldSplitSetFields() is for defining fields as strided blocks. For example, if the block 1907 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 1908 0xx3xx6xx9xx12 ... x1xx4xx7xx ... xx2xx5xx8xx.. 01x34x67x... 0x1x3x5x7.. x12x45x78x.... 1909 where the numbered entries indicate what is in the field. 1910 1911 This function is called once per split (it creates a new split each time). Solve options 1912 for this split will be available under the prefix -fieldsplit_SPLITNAME_. 1913 1914 Developer Note: This routine does not actually create the IS representing the split, that is delayed 1915 until PCSetUp_FieldSplit(), because information about the vector/matrix layouts may not be 1916 available when this routine is called. 1917 1918 .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetBlockSize(), PCFieldSplitSetIS() 1919 1920 @*/ 1921 PetscErrorCode PCFieldSplitSetFields(PC pc,const char splitname[],PetscInt n,const PetscInt *fields,const PetscInt *fields_col) 1922 { 1923 PetscErrorCode ierr; 1924 1925 PetscFunctionBegin; 1926 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1927 PetscValidCharPointer(splitname,2); 1928 if (n < 1) SETERRQ2(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_OUTOFRANGE,"Provided number of fields %D in split \"%s\" not positive",n,splitname); 1929 PetscValidIntPointer(fields,3); 1930 ierr = PetscTryMethod(pc,"PCFieldSplitSetFields_C",(PC,const char[],PetscInt,const PetscInt*,const PetscInt*),(pc,splitname,n,fields,fields_col));CHKERRQ(ierr); 1931 PetscFunctionReturn(0); 1932 } 1933 1934 /*@ 1935 PCFieldSplitSetDiagUseAmat - set flag indicating whether to extract diagonal blocks from Amat (rather than Pmat) 1936 1937 Logically Collective on PC 1938 1939 Input Parameters: 1940 + pc - the preconditioner object 1941 - flg - boolean flag indicating whether or not to use Amat to extract the diagonal blocks from 1942 1943 Options Database: 1944 . -pc_fieldsplit_diag_use_amat 1945 1946 Level: intermediate 1947 1948 .seealso: PCFieldSplitGetDiagUseAmat(), PCFieldSplitSetOffDiagUseAmat(), PCFIELDSPLIT 1949 1950 @*/ 1951 PetscErrorCode PCFieldSplitSetDiagUseAmat(PC pc,PetscBool flg) 1952 { 1953 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 1954 PetscBool isfs; 1955 PetscErrorCode ierr; 1956 1957 PetscFunctionBegin; 1958 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1959 ierr = PetscObjectTypeCompare((PetscObject)pc,PCFIELDSPLIT,&isfs);CHKERRQ(ierr); 1960 if (!isfs) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"PC not of type %s",PCFIELDSPLIT); 1961 jac->diag_use_amat = flg; 1962 PetscFunctionReturn(0); 1963 } 1964 1965 /*@ 1966 PCFieldSplitGetDiagUseAmat - get the flag indicating whether to extract diagonal blocks from Amat (rather than Pmat) 1967 1968 Logically Collective on PC 1969 1970 Input Parameters: 1971 . pc - the preconditioner object 1972 1973 Output Parameters: 1974 . flg - boolean flag indicating whether or not to use Amat to extract the diagonal blocks from 1975 1976 1977 Level: intermediate 1978 1979 .seealso: PCFieldSplitSetDiagUseAmat(), PCFieldSplitGetOffDiagUseAmat(), PCFIELDSPLIT 1980 1981 @*/ 1982 PetscErrorCode PCFieldSplitGetDiagUseAmat(PC pc,PetscBool *flg) 1983 { 1984 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 1985 PetscBool isfs; 1986 PetscErrorCode ierr; 1987 1988 PetscFunctionBegin; 1989 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 1990 PetscValidBoolPointer(flg,2); 1991 ierr = PetscObjectTypeCompare((PetscObject)pc,PCFIELDSPLIT,&isfs);CHKERRQ(ierr); 1992 if (!isfs) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"PC not of type %s",PCFIELDSPLIT); 1993 *flg = jac->diag_use_amat; 1994 PetscFunctionReturn(0); 1995 } 1996 1997 /*@ 1998 PCFieldSplitSetOffDiagUseAmat - set flag indicating whether to extract off-diagonal blocks from Amat (rather than Pmat) 1999 2000 Logically Collective on PC 2001 2002 Input Parameters: 2003 + pc - the preconditioner object 2004 - flg - boolean flag indicating whether or not to use Amat to extract the off-diagonal blocks from 2005 2006 Options Database: 2007 . -pc_fieldsplit_off_diag_use_amat 2008 2009 Level: intermediate 2010 2011 .seealso: PCFieldSplitGetOffDiagUseAmat(), PCFieldSplitSetDiagUseAmat(), PCFIELDSPLIT 2012 2013 @*/ 2014 PetscErrorCode PCFieldSplitSetOffDiagUseAmat(PC pc,PetscBool flg) 2015 { 2016 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 2017 PetscBool isfs; 2018 PetscErrorCode ierr; 2019 2020 PetscFunctionBegin; 2021 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 2022 ierr = PetscObjectTypeCompare((PetscObject)pc,PCFIELDSPLIT,&isfs);CHKERRQ(ierr); 2023 if (!isfs) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"PC not of type %s",PCFIELDSPLIT); 2024 jac->offdiag_use_amat = flg; 2025 PetscFunctionReturn(0); 2026 } 2027 2028 /*@ 2029 PCFieldSplitGetOffDiagUseAmat - get the flag indicating whether to extract off-diagonal blocks from Amat (rather than Pmat) 2030 2031 Logically Collective on PC 2032 2033 Input Parameters: 2034 . pc - the preconditioner object 2035 2036 Output Parameters: 2037 . flg - boolean flag indicating whether or not to use Amat to extract the off-diagonal blocks from 2038 2039 2040 Level: intermediate 2041 2042 .seealso: PCFieldSplitSetOffDiagUseAmat(), PCFieldSplitGetDiagUseAmat(), PCFIELDSPLIT 2043 2044 @*/ 2045 PetscErrorCode PCFieldSplitGetOffDiagUseAmat(PC pc,PetscBool *flg) 2046 { 2047 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 2048 PetscBool isfs; 2049 PetscErrorCode ierr; 2050 2051 PetscFunctionBegin; 2052 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 2053 PetscValidBoolPointer(flg,2); 2054 ierr = PetscObjectTypeCompare((PetscObject)pc,PCFIELDSPLIT,&isfs);CHKERRQ(ierr); 2055 if (!isfs) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"PC not of type %s",PCFIELDSPLIT); 2056 *flg = jac->offdiag_use_amat; 2057 PetscFunctionReturn(0); 2058 } 2059 2060 2061 2062 /*@C 2063 PCFieldSplitSetIS - Sets the exact elements for field 2064 2065 Logically Collective on PC 2066 2067 Input Parameters: 2068 + pc - the preconditioner context 2069 . splitname - name of this split, if NULL the number of the split is used 2070 - is - the index set that defines the vector elements in this field 2071 2072 2073 Notes: 2074 Use PCFieldSplitSetFields(), for fields defined by strided types. 2075 2076 This function is called once per split (it creates a new split each time). Solve options 2077 for this split will be available under the prefix -fieldsplit_SPLITNAME_. 2078 2079 Level: intermediate 2080 2081 .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetBlockSize() 2082 2083 @*/ 2084 PetscErrorCode PCFieldSplitSetIS(PC pc,const char splitname[],IS is) 2085 { 2086 PetscErrorCode ierr; 2087 2088 PetscFunctionBegin; 2089 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 2090 if (splitname) PetscValidCharPointer(splitname,2); 2091 PetscValidHeaderSpecific(is,IS_CLASSID,3); 2092 ierr = PetscTryMethod(pc,"PCFieldSplitSetIS_C",(PC,const char[],IS),(pc,splitname,is));CHKERRQ(ierr); 2093 PetscFunctionReturn(0); 2094 } 2095 2096 /*@C 2097 PCFieldSplitGetIS - Retrieves the elements for a field as an IS 2098 2099 Logically Collective on PC 2100 2101 Input Parameters: 2102 + pc - the preconditioner context 2103 - splitname - name of this split 2104 2105 Output Parameter: 2106 - is - the index set that defines the vector elements in this field, or NULL if the field is not found 2107 2108 Level: intermediate 2109 2110 .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetIS() 2111 2112 @*/ 2113 PetscErrorCode PCFieldSplitGetIS(PC pc,const char splitname[],IS *is) 2114 { 2115 PetscErrorCode ierr; 2116 2117 PetscFunctionBegin; 2118 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 2119 PetscValidCharPointer(splitname,2); 2120 PetscValidPointer(is,3); 2121 { 2122 PC_FieldSplit *jac = (PC_FieldSplit*) pc->data; 2123 PC_FieldSplitLink ilink = jac->head; 2124 PetscBool found; 2125 2126 *is = NULL; 2127 while (ilink) { 2128 ierr = PetscStrcmp(ilink->splitname, splitname, &found);CHKERRQ(ierr); 2129 if (found) { 2130 *is = ilink->is; 2131 break; 2132 } 2133 ilink = ilink->next; 2134 } 2135 } 2136 PetscFunctionReturn(0); 2137 } 2138 2139 /*@C 2140 PCFieldSplitGetISByIndex - Retrieves the elements for a given index field as an IS 2141 2142 Logically Collective on PC 2143 2144 Input Parameters: 2145 + pc - the preconditioner context 2146 - index - index of this split 2147 2148 Output Parameter: 2149 - is - the index set that defines the vector elements in this field 2150 2151 Level: intermediate 2152 2153 .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitGetIS(), PCFieldSplitSetIS() 2154 2155 @*/ 2156 PetscErrorCode PCFieldSplitGetISByIndex(PC pc,PetscInt index,IS *is) 2157 { 2158 PetscErrorCode ierr; 2159 2160 PetscFunctionBegin; 2161 if (index < 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Negative field %D requested",index); 2162 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 2163 PetscValidPointer(is,3); 2164 { 2165 PC_FieldSplit *jac = (PC_FieldSplit*) pc->data; 2166 PC_FieldSplitLink ilink = jac->head; 2167 PetscInt i = 0; 2168 if (index >= jac->nsplits) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Field %D requested but only %D exist",index,jac->nsplits); 2169 2170 while (i < index) { 2171 ilink = ilink->next; 2172 ++i; 2173 } 2174 ierr = PCFieldSplitGetIS(pc,ilink->splitname,is);CHKERRQ(ierr); 2175 } 2176 PetscFunctionReturn(0); 2177 } 2178 2179 /*@ 2180 PCFieldSplitSetBlockSize - Sets the block size for defining where fields start in the 2181 fieldsplit preconditioner. If not set the matrix block size is used. 2182 2183 Logically Collective on PC 2184 2185 Input Parameters: 2186 + pc - the preconditioner context 2187 - bs - the block size 2188 2189 Level: intermediate 2190 2191 .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetFields() 2192 2193 @*/ 2194 PetscErrorCode PCFieldSplitSetBlockSize(PC pc,PetscInt bs) 2195 { 2196 PetscErrorCode ierr; 2197 2198 PetscFunctionBegin; 2199 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 2200 PetscValidLogicalCollectiveInt(pc,bs,2); 2201 ierr = PetscTryMethod(pc,"PCFieldSplitSetBlockSize_C",(PC,PetscInt),(pc,bs));CHKERRQ(ierr); 2202 PetscFunctionReturn(0); 2203 } 2204 2205 /*@C 2206 PCFieldSplitGetSubKSP - Gets the KSP contexts for all splits 2207 2208 Collective on KSP 2209 2210 Input Parameter: 2211 . pc - the preconditioner context 2212 2213 Output Parameters: 2214 + n - the number of splits 2215 - subksp - the array of KSP contexts 2216 2217 Note: 2218 After PCFieldSplitGetSubKSP() the array of KSPs is to be freed by the user with PetscFree() 2219 (not the KSP just the array that contains them). 2220 2221 You must call PCSetUp() before calling PCFieldSplitGetSubKSP(). 2222 2223 If the fieldsplit is of type PC_COMPOSITE_SCHUR, it returns the KSP object used inside the 2224 Schur complement and the KSP object used to iterate over the Schur complement. 2225 To access all the KSP objects used in PC_COMPOSITE_SCHUR, use PCFieldSplitSchurGetSubKSP(). 2226 2227 If the fieldsplit is of type PC_COMPOSITE_GKB, it returns the KSP object used to solve the 2228 inner linear system defined by the matrix H in each loop. 2229 2230 Fortran Usage: You must pass in a KSP array that is large enough to contain all the local KSPs. 2231 You can call PCFieldSplitGetSubKSP(pc,n,PETSC_NULL_KSP,ierr) to determine how large the 2232 KSP array must be. 2233 2234 2235 Level: advanced 2236 2237 .seealso: PCFIELDSPLIT 2238 @*/ 2239 PetscErrorCode PCFieldSplitGetSubKSP(PC pc,PetscInt *n,KSP *subksp[]) 2240 { 2241 PetscErrorCode ierr; 2242 2243 PetscFunctionBegin; 2244 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 2245 if (n) PetscValidIntPointer(n,2); 2246 ierr = PetscUseMethod(pc,"PCFieldSplitGetSubKSP_C",(PC,PetscInt*,KSP **),(pc,n,subksp));CHKERRQ(ierr); 2247 PetscFunctionReturn(0); 2248 } 2249 2250 /*@C 2251 PCFieldSplitSchurGetSubKSP - Gets the KSP contexts used inside the Schur complement based PCFIELDSPLIT 2252 2253 Collective on KSP 2254 2255 Input Parameter: 2256 . pc - the preconditioner context 2257 2258 Output Parameters: 2259 + n - the number of splits 2260 - subksp - the array of KSP contexts 2261 2262 Note: 2263 After PCFieldSplitSchurGetSubKSP() the array of KSPs is to be freed by the user with PetscFree() 2264 (not the KSP just the array that contains them). 2265 2266 You must call PCSetUp() before calling PCFieldSplitSchurGetSubKSP(). 2267 2268 If the fieldsplit type is of type PC_COMPOSITE_SCHUR, it returns (in order) 2269 - the KSP used for the (1,1) block 2270 - the KSP used for the Schur complement (not the one used for the interior Schur solver) 2271 - the KSP used for the (1,1) block in the upper triangular factor (if different from that of the (1,1) block). 2272 2273 It returns a null array if the fieldsplit is not of type PC_COMPOSITE_SCHUR; in this case, you should use PCFieldSplitGetSubKSP(). 2274 2275 Fortran Usage: You must pass in a KSP array that is large enough to contain all the local KSPs. 2276 You can call PCFieldSplitSchurGetSubKSP(pc,n,PETSC_NULL_KSP,ierr) to determine how large the 2277 KSP array must be. 2278 2279 Level: advanced 2280 2281 .seealso: PCFIELDSPLIT 2282 @*/ 2283 PetscErrorCode PCFieldSplitSchurGetSubKSP(PC pc,PetscInt *n,KSP *subksp[]) 2284 { 2285 PetscErrorCode ierr; 2286 2287 PetscFunctionBegin; 2288 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 2289 if (n) PetscValidIntPointer(n,2); 2290 ierr = PetscUseMethod(pc,"PCFieldSplitSchurGetSubKSP_C",(PC,PetscInt*,KSP **),(pc,n,subksp));CHKERRQ(ierr); 2291 PetscFunctionReturn(0); 2292 } 2293 2294 /*@ 2295 PCFieldSplitSetSchurPre - Indicates from what operator the preconditioner is constructucted for the Schur complement. 2296 The default is the A11 matrix. 2297 2298 Collective on PC 2299 2300 Input Parameters: 2301 + pc - the preconditioner context 2302 . 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 2303 PC_FIELDSPLIT_SCHUR_PRE_SELFP, and PC_FIELDSPLIT_SCHUR_PRE_FULL 2304 - userpre - matrix to use for preconditioning, or NULL 2305 2306 Options Database: 2307 + -pc_fieldsplit_schur_precondition <self,selfp,user,a11,full> - default is a11. See notes for meaning of various arguments 2308 - -fieldsplit_1_pc_type <pctype> - the preconditioner algorithm that is used to construct the preconditioner from the operator 2309 2310 Notes: 2311 $ If ptype is 2312 $ a11 - the preconditioner for the Schur complement is generated from the block diagonal part of the preconditioner 2313 $ matrix associated with the Schur complement (i.e. A11), not the Schur complement matrix 2314 $ self - the preconditioner for the Schur complement is generated from the symbolic representation of the Schur complement matrix: 2315 $ The only preconditioner that currently works with this symbolic respresentation matrix object is the PCLSC 2316 $ preconditioner 2317 $ user - the preconditioner for the Schur complement is generated from the user provided matrix (pre argument 2318 $ to this function). 2319 $ selfp - the preconditioning for the Schur complement is generated from an explicitly-assembled approximation Sp = A11 - A10 inv(diag(A00)) A01 2320 $ This is only a good preconditioner when diag(A00) is a good preconditioner for A00. Optionally, A00 can be 2321 $ lumped before extracting the diagonal using the additional option -fieldsplit_1_mat_schur_complement_ainv_type lump 2322 $ full - the preconditioner for the Schur complement is generated from the exact Schur complement matrix representation computed internally by PCFIELDSPLIT (this is expensive) 2323 $ useful mostly as a test that the Schur complement approach can work for your problem 2324 2325 When solving a saddle point problem, where the A11 block is identically zero, using a11 as the ptype only makes sense 2326 with the additional option -fieldsplit_1_pc_type none. Usually for saddle point problems one would use a ptype of self and 2327 -fieldsplit_1_pc_type lsc which uses the least squares commutator to compute a preconditioner for the Schur complement. 2328 2329 Level: intermediate 2330 2331 .seealso: PCFieldSplitGetSchurPre(), PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetFields(), PCFieldSplitSchurPreType, 2332 MatSchurComplementSetAinvType(), PCLSC 2333 2334 @*/ 2335 PetscErrorCode PCFieldSplitSetSchurPre(PC pc,PCFieldSplitSchurPreType ptype,Mat pre) 2336 { 2337 PetscErrorCode ierr; 2338 2339 PetscFunctionBegin; 2340 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 2341 ierr = PetscTryMethod(pc,"PCFieldSplitSetSchurPre_C",(PC,PCFieldSplitSchurPreType,Mat),(pc,ptype,pre));CHKERRQ(ierr); 2342 PetscFunctionReturn(0); 2343 } 2344 2345 PetscErrorCode PCFieldSplitSchurPrecondition(PC pc,PCFieldSplitSchurPreType ptype,Mat pre) {return PCFieldSplitSetSchurPre(pc,ptype,pre);} /* Deprecated name */ 2346 2347 /*@ 2348 PCFieldSplitGetSchurPre - For Schur complement fieldsplit, determine how the Schur complement will be 2349 preconditioned. See PCFieldSplitSetSchurPre() for details. 2350 2351 Logically Collective on PC 2352 2353 Input Parameters: 2354 . pc - the preconditioner context 2355 2356 Output Parameters: 2357 + ptype - which matrix to use for preconditioning the Schur complement: PC_FIELDSPLIT_SCHUR_PRE_A11, PC_FIELDSPLIT_SCHUR_PRE_SELF, PC_FIELDSPLIT_PRE_USER 2358 - userpre - matrix to use for preconditioning (with PC_FIELDSPLIT_PRE_USER), or NULL 2359 2360 Level: intermediate 2361 2362 .seealso: PCFieldSplitSetSchurPre(), PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetFields(), PCFieldSplitSchurPreType, PCLSC 2363 2364 @*/ 2365 PetscErrorCode PCFieldSplitGetSchurPre(PC pc,PCFieldSplitSchurPreType *ptype,Mat *pre) 2366 { 2367 PetscErrorCode ierr; 2368 2369 PetscFunctionBegin; 2370 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 2371 ierr = PetscUseMethod(pc,"PCFieldSplitGetSchurPre_C",(PC,PCFieldSplitSchurPreType*,Mat*),(pc,ptype,pre));CHKERRQ(ierr); 2372 PetscFunctionReturn(0); 2373 } 2374 2375 /*@ 2376 PCFieldSplitSchurGetS - extract the MatSchurComplement object used by this PC in case it needs to be configured separately 2377 2378 Not collective 2379 2380 Input Parameter: 2381 . pc - the preconditioner context 2382 2383 Output Parameter: 2384 . S - the Schur complement matrix 2385 2386 Notes: 2387 This matrix should not be destroyed using MatDestroy(); rather, use PCFieldSplitSchurRestoreS(). 2388 2389 Level: advanced 2390 2391 .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSchurPreType, PCFieldSplitSetSchurPre(), MatSchurComplement, PCFieldSplitSchurRestoreS() 2392 2393 @*/ 2394 PetscErrorCode PCFieldSplitSchurGetS(PC pc,Mat *S) 2395 { 2396 PetscErrorCode ierr; 2397 const char* t; 2398 PetscBool isfs; 2399 PC_FieldSplit *jac; 2400 2401 PetscFunctionBegin; 2402 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 2403 ierr = PetscObjectGetType((PetscObject)pc,&t);CHKERRQ(ierr); 2404 ierr = PetscStrcmp(t,PCFIELDSPLIT,&isfs);CHKERRQ(ierr); 2405 if (!isfs) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Expected PC of type PCFIELDSPLIT, got %s instead",t); 2406 jac = (PC_FieldSplit*)pc->data; 2407 if (jac->type != PC_COMPOSITE_SCHUR) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Expected PCFIELDSPLIT of type SCHUR, got %D instead",jac->type); 2408 if (S) *S = jac->schur; 2409 PetscFunctionReturn(0); 2410 } 2411 2412 /*@ 2413 PCFieldSplitSchurRestoreS - restores the MatSchurComplement object used by this PC 2414 2415 Not collective 2416 2417 Input Parameters: 2418 + pc - the preconditioner context 2419 - S - the Schur complement matrix 2420 2421 Level: advanced 2422 2423 .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSchurPreType, PCFieldSplitSetSchurPre(), MatSchurComplement, PCFieldSplitSchurGetS() 2424 2425 @*/ 2426 PetscErrorCode PCFieldSplitSchurRestoreS(PC pc,Mat *S) 2427 { 2428 PetscErrorCode ierr; 2429 const char* t; 2430 PetscBool isfs; 2431 PC_FieldSplit *jac; 2432 2433 PetscFunctionBegin; 2434 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 2435 ierr = PetscObjectGetType((PetscObject)pc,&t);CHKERRQ(ierr); 2436 ierr = PetscStrcmp(t,PCFIELDSPLIT,&isfs);CHKERRQ(ierr); 2437 if (!isfs) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Expected PC of type PCFIELDSPLIT, got %s instead",t); 2438 jac = (PC_FieldSplit*)pc->data; 2439 if (jac->type != PC_COMPOSITE_SCHUR) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Expected PCFIELDSPLIT of type SCHUR, got %D instead",jac->type); 2440 if (!S || *S != jac->schur) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"MatSchurComplement restored is not the same as gotten"); 2441 PetscFunctionReturn(0); 2442 } 2443 2444 2445 static PetscErrorCode PCFieldSplitSetSchurPre_FieldSplit(PC pc,PCFieldSplitSchurPreType ptype,Mat pre) 2446 { 2447 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 2448 PetscErrorCode ierr; 2449 2450 PetscFunctionBegin; 2451 jac->schurpre = ptype; 2452 if (ptype == PC_FIELDSPLIT_SCHUR_PRE_USER && pre) { 2453 ierr = MatDestroy(&jac->schur_user);CHKERRQ(ierr); 2454 jac->schur_user = pre; 2455 ierr = PetscObjectReference((PetscObject)jac->schur_user);CHKERRQ(ierr); 2456 } 2457 PetscFunctionReturn(0); 2458 } 2459 2460 static PetscErrorCode PCFieldSplitGetSchurPre_FieldSplit(PC pc,PCFieldSplitSchurPreType *ptype,Mat *pre) 2461 { 2462 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 2463 2464 PetscFunctionBegin; 2465 *ptype = jac->schurpre; 2466 *pre = jac->schur_user; 2467 PetscFunctionReturn(0); 2468 } 2469 2470 /*@ 2471 PCFieldSplitSetSchurFactType - sets which blocks of the approximate block factorization to retain in the preconditioner 2472 2473 Collective on PC 2474 2475 Input Parameters: 2476 + pc - the preconditioner context 2477 - ftype - which blocks of factorization to retain, PC_FIELDSPLIT_SCHUR_FACT_FULL is default 2478 2479 Options Database: 2480 . -pc_fieldsplit_schur_fact_type <diag,lower,upper,full> default is full 2481 2482 2483 Level: intermediate 2484 2485 Notes: 2486 The FULL factorization is 2487 2488 $ (A B) = (1 0) (A 0) (1 Ainv*B) = L D U 2489 $ (C E) (C*Ainv 1) (0 S) (0 1 ) 2490 2491 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, 2492 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(). 2493 2494 $ If A and S are solved exactly 2495 $ *) FULL factorization is a direct solver. 2496 $ *) 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. 2497 $ *) 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. 2498 2499 If the iteration count is very low, consider using KSPFGMRES or KSPGCR which can use one less preconditioner 2500 application in this case. Note that the preconditioned operator may be highly non-normal, so such fast convergence may not be observed in practice. 2501 2502 For symmetric problems in which A is positive definite and S is negative definite, DIAG can be used with KSPMINRES. 2503 2504 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). 2505 2506 References: 2507 + 1. - Murphy, Golub, and Wathen, A note on preconditioning indefinite linear systems, SIAM J. Sci. Comput., 21 (2000). 2508 - 2. - Ipsen, A note on preconditioning nonsymmetric matrices, SIAM J. Sci. Comput., 23 (2001). 2509 2510 .seealso: PCFieldSplitGetSubKSP(), PCFIELDSPLIT, PCFieldSplitSetFields(), PCFieldSplitSchurPreType, PCFieldSplitSetSchurScale() 2511 @*/ 2512 PetscErrorCode PCFieldSplitSetSchurFactType(PC pc,PCFieldSplitSchurFactType ftype) 2513 { 2514 PetscErrorCode ierr; 2515 2516 PetscFunctionBegin; 2517 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 2518 ierr = PetscTryMethod(pc,"PCFieldSplitSetSchurFactType_C",(PC,PCFieldSplitSchurFactType),(pc,ftype));CHKERRQ(ierr); 2519 PetscFunctionReturn(0); 2520 } 2521 2522 static PetscErrorCode PCFieldSplitSetSchurFactType_FieldSplit(PC pc,PCFieldSplitSchurFactType ftype) 2523 { 2524 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 2525 2526 PetscFunctionBegin; 2527 jac->schurfactorization = ftype; 2528 PetscFunctionReturn(0); 2529 } 2530 2531 /*@ 2532 PCFieldSplitSetSchurScale - Controls the sign flip of S for PC_FIELDSPLIT_SCHUR_FACT_DIAG. 2533 2534 Collective on PC 2535 2536 Input Parameters: 2537 + pc - the preconditioner context 2538 - scale - scaling factor for the Schur complement 2539 2540 Options Database: 2541 . -pc_fieldsplit_schur_scale - default is -1.0 2542 2543 Level: intermediate 2544 2545 .seealso: PCFIELDSPLIT, PCFieldSplitSetFields(), PCFieldSplitSchurFactType, PCFieldSplitSetSchurScale() 2546 @*/ 2547 PetscErrorCode PCFieldSplitSetSchurScale(PC pc,PetscScalar scale) 2548 { 2549 PetscErrorCode ierr; 2550 2551 PetscFunctionBegin; 2552 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 2553 PetscValidLogicalCollectiveScalar(pc,scale,2); 2554 ierr = PetscTryMethod(pc,"PCFieldSplitSetSchurScale_C",(PC,PetscScalar),(pc,scale));CHKERRQ(ierr); 2555 PetscFunctionReturn(0); 2556 } 2557 2558 static PetscErrorCode PCFieldSplitSetSchurScale_FieldSplit(PC pc,PetscScalar scale) 2559 { 2560 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 2561 2562 PetscFunctionBegin; 2563 jac->schurscale = scale; 2564 PetscFunctionReturn(0); 2565 } 2566 2567 /*@C 2568 PCFieldSplitGetSchurBlocks - Gets all matrix blocks for the Schur complement 2569 2570 Collective on KSP 2571 2572 Input Parameter: 2573 . pc - the preconditioner context 2574 2575 Output Parameters: 2576 + A00 - the (0,0) block 2577 . A01 - the (0,1) block 2578 . A10 - the (1,0) block 2579 - A11 - the (1,1) block 2580 2581 Level: advanced 2582 2583 .seealso: PCFIELDSPLIT 2584 @*/ 2585 PetscErrorCode PCFieldSplitGetSchurBlocks(PC pc,Mat *A00,Mat *A01,Mat *A10, Mat *A11) 2586 { 2587 PC_FieldSplit *jac = (PC_FieldSplit*) pc->data; 2588 2589 PetscFunctionBegin; 2590 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 2591 if (jac->type != PC_COMPOSITE_SCHUR) SETERRQ(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_WRONG, "FieldSplit is not using a Schur complement approach."); 2592 if (A00) *A00 = jac->pmat[0]; 2593 if (A01) *A01 = jac->B; 2594 if (A10) *A10 = jac->C; 2595 if (A11) *A11 = jac->pmat[1]; 2596 PetscFunctionReturn(0); 2597 } 2598 2599 /*@ 2600 PCFieldSplitSetGKBTol - Sets the solver tolerance for the generalized Golub-Kahan bidiagonalization preconditioner. 2601 2602 Collective on PC 2603 2604 Notes: 2605 The generalized GKB algorithm uses a lower bound estimate of the error in energy norm as stopping criterion. 2606 It stops once the lower bound estimate undershoots the required solver tolerance. Although the actual error might be bigger than 2607 this estimate, the stopping criterion is satisfactory in practical cases [A13]. 2608 2609 [Ar13] Generalized Golub-Kahan bidiagonalization and stopping criteria, SIAM J. Matrix Anal. Appl., Vol. 34, No. 2, pp. 571-592, 2013. 2610 2611 Input Parameters: 2612 + pc - the preconditioner context 2613 - tolerance - the solver tolerance 2614 2615 Options Database: 2616 . -pc_fieldsplit_gkb_tol - default is 1e-5 2617 2618 Level: intermediate 2619 2620 .seealso: PCFIELDSPLIT, PCFieldSplitSetGKBDelay(), PCFieldSplitSetGKBNu(), PCFieldSplitSetGKBMaxit() 2621 @*/ 2622 PetscErrorCode PCFieldSplitSetGKBTol(PC pc,PetscReal tolerance) 2623 { 2624 PetscErrorCode ierr; 2625 2626 PetscFunctionBegin; 2627 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 2628 PetscValidLogicalCollectiveReal(pc,tolerance,2); 2629 ierr = PetscTryMethod(pc,"PCFieldSplitSetGKBTol_C",(PC,PetscReal),(pc,tolerance));CHKERRQ(ierr); 2630 PetscFunctionReturn(0); 2631 } 2632 2633 static PetscErrorCode PCFieldSplitSetGKBTol_FieldSplit(PC pc,PetscReal tolerance) 2634 { 2635 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 2636 2637 PetscFunctionBegin; 2638 jac->gkbtol = tolerance; 2639 PetscFunctionReturn(0); 2640 } 2641 2642 2643 /*@ 2644 PCFieldSplitSetGKBMaxit - Sets the maximum number of iterations for the generalized Golub-Kahan bidiagonalization 2645 preconditioner. 2646 2647 Collective on PC 2648 2649 Input Parameters: 2650 + pc - the preconditioner context 2651 - maxit - the maximum number of iterations 2652 2653 Options Database: 2654 . -pc_fieldsplit_gkb_maxit - default is 100 2655 2656 Level: intermediate 2657 2658 .seealso: PCFIELDSPLIT, PCFieldSplitSetGKBDelay(), PCFieldSplitSetGKBTol(), PCFieldSplitSetGKBNu() 2659 @*/ 2660 PetscErrorCode PCFieldSplitSetGKBMaxit(PC pc,PetscInt maxit) 2661 { 2662 PetscErrorCode ierr; 2663 2664 PetscFunctionBegin; 2665 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 2666 PetscValidLogicalCollectiveInt(pc,maxit,2); 2667 ierr = PetscTryMethod(pc,"PCFieldSplitSetGKBMaxit_C",(PC,PetscInt),(pc,maxit));CHKERRQ(ierr); 2668 PetscFunctionReturn(0); 2669 } 2670 2671 static PetscErrorCode PCFieldSplitSetGKBMaxit_FieldSplit(PC pc,PetscInt maxit) 2672 { 2673 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 2674 2675 PetscFunctionBegin; 2676 jac->gkbmaxit = maxit; 2677 PetscFunctionReturn(0); 2678 } 2679 2680 /*@ 2681 PCFieldSplitSetGKBDelay - Sets the delay in the lower bound error estimate in the generalized Golub-Kahan bidiagonalization 2682 preconditioner. 2683 2684 Collective on PC 2685 2686 Notes: 2687 The algorithm uses a lower bound estimate of the error in energy norm as stopping criterion. The lower bound of the error ||u-u^k||_H 2688 is expressed as a truncated sum. The error at iteration k can only be measured at iteration (k + delay), and thus the algorithm needs 2689 at least (delay + 1) iterations to stop. For more details on the generalized Golub-Kahan bidiagonalization method and its lower bound stopping criterion, please refer to 2690 2691 [Ar13] Generalized Golub-Kahan bidiagonalization and stopping criteria, SIAM J. Matrix Anal. Appl., Vol. 34, No. 2, pp. 571-592, 2013. 2692 2693 Input Parameters: 2694 + pc - the preconditioner context 2695 - delay - the delay window in the lower bound estimate 2696 2697 Options Database: 2698 . -pc_fieldsplit_gkb_delay - default is 5 2699 2700 Level: intermediate 2701 2702 .seealso: PCFIELDSPLIT, PCFieldSplitSetGKBNu(), PCFieldSplitSetGKBTol(), PCFieldSplitSetGKBMaxit() 2703 @*/ 2704 PetscErrorCode PCFieldSplitSetGKBDelay(PC pc,PetscInt delay) 2705 { 2706 PetscErrorCode ierr; 2707 2708 PetscFunctionBegin; 2709 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 2710 PetscValidLogicalCollectiveInt(pc,delay,2); 2711 ierr = PetscTryMethod(pc,"PCFieldSplitSetGKBDelay_C",(PC,PetscInt),(pc,delay));CHKERRQ(ierr); 2712 PetscFunctionReturn(0); 2713 } 2714 2715 static PetscErrorCode PCFieldSplitSetGKBDelay_FieldSplit(PC pc,PetscInt delay) 2716 { 2717 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 2718 2719 PetscFunctionBegin; 2720 jac->gkbdelay = delay; 2721 PetscFunctionReturn(0); 2722 } 2723 2724 /*@ 2725 PCFieldSplitSetGKBNu - Sets the scalar value nu >= 0 in the transformation H = A00 + nu*A01*A01' of the (1,1) block in the Golub-Kahan bidiagonalization preconditioner. 2726 2727 Collective on PC 2728 2729 Notes: 2730 This shift is in general done to obtain better convergence properties for the outer loop of the algorithm. This is often achieved by chosing nu sufficiently big. However, 2731 if nu is chosen too big, the matrix H might be badly conditioned and the solution of the linear system Hx = b in the inner loop gets difficult. It is therefore 2732 necessary to find a good balance in between the convergence of the inner and outer loop. 2733 2734 For nu = 0, no shift is done. In this case A00 has to be positive definite. The matrix N in [Ar13] is then chosen as identity. 2735 2736 [Ar13] Generalized Golub-Kahan bidiagonalization and stopping criteria, SIAM J. Matrix Anal. Appl., Vol. 34, No. 2, pp. 571-592, 2013. 2737 2738 Input Parameters: 2739 + pc - the preconditioner context 2740 - nu - the shift parameter 2741 2742 Options Database: 2743 . -pc_fieldsplit_gkb_nu - default is 1 2744 2745 Level: intermediate 2746 2747 .seealso: PCFIELDSPLIT, PCFieldSplitSetGKBDelay(), PCFieldSplitSetGKBTol(), PCFieldSplitSetGKBMaxit() 2748 @*/ 2749 PetscErrorCode PCFieldSplitSetGKBNu(PC pc,PetscReal nu) 2750 { 2751 PetscErrorCode ierr; 2752 2753 PetscFunctionBegin; 2754 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 2755 PetscValidLogicalCollectiveReal(pc,nu,2); 2756 ierr = PetscTryMethod(pc,"PCFieldSplitSetGKBNu_C",(PC,PetscReal),(pc,nu));CHKERRQ(ierr); 2757 PetscFunctionReturn(0); 2758 } 2759 2760 static PetscErrorCode PCFieldSplitSetGKBNu_FieldSplit(PC pc,PetscReal nu) 2761 { 2762 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 2763 2764 PetscFunctionBegin; 2765 jac->gkbnu = nu; 2766 PetscFunctionReturn(0); 2767 } 2768 2769 2770 static PetscErrorCode PCFieldSplitSetType_FieldSplit(PC pc,PCCompositeType type) 2771 { 2772 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 2773 PetscErrorCode ierr; 2774 2775 PetscFunctionBegin; 2776 jac->type = type; 2777 2778 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitGetSubKSP_C",0);CHKERRQ(ierr); 2779 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitSetSchurPre_C",0);CHKERRQ(ierr); 2780 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitGetSchurPre_C",0);CHKERRQ(ierr); 2781 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitSetSchurFactType_C",0);CHKERRQ(ierr); 2782 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitSetSchurScale_C",0);CHKERRQ(ierr); 2783 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitSetGKBTol_C",0);CHKERRQ(ierr); 2784 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitSetGKBMaxit_C",0);CHKERRQ(ierr); 2785 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitSetGKBNu_C",0);CHKERRQ(ierr); 2786 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitSetGKBDelay_C",0);CHKERRQ(ierr); 2787 2788 if (type == PC_COMPOSITE_SCHUR) { 2789 pc->ops->apply = PCApply_FieldSplit_Schur; 2790 pc->ops->view = PCView_FieldSplit_Schur; 2791 2792 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitGetSubKSP_C",PCFieldSplitGetSubKSP_FieldSplit_Schur);CHKERRQ(ierr); 2793 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitSetSchurPre_C",PCFieldSplitSetSchurPre_FieldSplit);CHKERRQ(ierr); 2794 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitGetSchurPre_C",PCFieldSplitGetSchurPre_FieldSplit);CHKERRQ(ierr); 2795 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitSetSchurFactType_C",PCFieldSplitSetSchurFactType_FieldSplit);CHKERRQ(ierr); 2796 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitSetSchurScale_C",PCFieldSplitSetSchurScale_FieldSplit);CHKERRQ(ierr); 2797 } else if (type == PC_COMPOSITE_GKB){ 2798 pc->ops->apply = PCApply_FieldSplit_GKB; 2799 pc->ops->view = PCView_FieldSplit_GKB; 2800 2801 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitGetSubKSP_C",PCFieldSplitGetSubKSP_FieldSplit);CHKERRQ(ierr); 2802 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitSetGKBTol_C",PCFieldSplitSetGKBTol_FieldSplit);CHKERRQ(ierr); 2803 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitSetGKBMaxit_C",PCFieldSplitSetGKBMaxit_FieldSplit);CHKERRQ(ierr); 2804 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitSetGKBNu_C",PCFieldSplitSetGKBNu_FieldSplit);CHKERRQ(ierr); 2805 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitSetGKBDelay_C",PCFieldSplitSetGKBDelay_FieldSplit);CHKERRQ(ierr); 2806 } else { 2807 pc->ops->apply = PCApply_FieldSplit; 2808 pc->ops->view = PCView_FieldSplit; 2809 2810 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitGetSubKSP_C",PCFieldSplitGetSubKSP_FieldSplit);CHKERRQ(ierr); 2811 } 2812 PetscFunctionReturn(0); 2813 } 2814 2815 static PetscErrorCode PCFieldSplitSetBlockSize_FieldSplit(PC pc,PetscInt bs) 2816 { 2817 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 2818 2819 PetscFunctionBegin; 2820 if (bs < 1) SETERRQ1(PetscObjectComm((PetscObject)pc),PETSC_ERR_ARG_OUTOFRANGE,"Blocksize must be positive, you gave %D",bs); 2821 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); 2822 jac->bs = bs; 2823 PetscFunctionReturn(0); 2824 } 2825 2826 /*@ 2827 PCFieldSplitSetType - Sets the type of fieldsplit preconditioner. 2828 2829 Collective on PC 2830 2831 Input Parameter: 2832 + pc - the preconditioner context 2833 - type - PC_COMPOSITE_ADDITIVE, PC_COMPOSITE_MULTIPLICATIVE (default), PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE, PC_COMPOSITE_SPECIAL, PC_COMPOSITE_SCHUR 2834 2835 Options Database Key: 2836 . -pc_fieldsplit_type <type: one of multiplicative, additive, symmetric_multiplicative, special, schur> - Sets fieldsplit preconditioner type 2837 2838 Level: Intermediate 2839 2840 .seealso: PCCompositeSetType() 2841 2842 @*/ 2843 PetscErrorCode PCFieldSplitSetType(PC pc,PCCompositeType type) 2844 { 2845 PetscErrorCode ierr; 2846 2847 PetscFunctionBegin; 2848 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 2849 ierr = PetscTryMethod(pc,"PCFieldSplitSetType_C",(PC,PCCompositeType),(pc,type));CHKERRQ(ierr); 2850 PetscFunctionReturn(0); 2851 } 2852 2853 /*@ 2854 PCFieldSplitGetType - Gets the type of fieldsplit preconditioner. 2855 2856 Not collective 2857 2858 Input Parameter: 2859 . pc - the preconditioner context 2860 2861 Output Parameter: 2862 . type - PC_COMPOSITE_ADDITIVE, PC_COMPOSITE_MULTIPLICATIVE (default), PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE, PC_COMPOSITE_SPECIAL, PC_COMPOSITE_SCHUR 2863 2864 Level: Intermediate 2865 2866 .seealso: PCCompositeSetType() 2867 @*/ 2868 PetscErrorCode PCFieldSplitGetType(PC pc, PCCompositeType *type) 2869 { 2870 PC_FieldSplit *jac = (PC_FieldSplit*) pc->data; 2871 2872 PetscFunctionBegin; 2873 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 2874 PetscValidIntPointer(type,2); 2875 *type = jac->type; 2876 PetscFunctionReturn(0); 2877 } 2878 2879 /*@ 2880 PCFieldSplitSetDMSplits - Flags whether DMCreateFieldDecomposition() should be used to define the splits, whenever possible. 2881 2882 Logically Collective 2883 2884 Input Parameters: 2885 + pc - the preconditioner context 2886 - flg - boolean indicating whether to use field splits defined by the DM 2887 2888 Options Database Key: 2889 . -pc_fieldsplit_dm_splits 2890 2891 Level: Intermediate 2892 2893 .seealso: PCFieldSplitGetDMSplits() 2894 2895 @*/ 2896 PetscErrorCode PCFieldSplitSetDMSplits(PC pc,PetscBool flg) 2897 { 2898 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 2899 PetscBool isfs; 2900 PetscErrorCode ierr; 2901 2902 PetscFunctionBegin; 2903 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 2904 PetscValidLogicalCollectiveBool(pc,flg,2); 2905 ierr = PetscObjectTypeCompare((PetscObject)pc,PCFIELDSPLIT,&isfs);CHKERRQ(ierr); 2906 if (isfs) { 2907 jac->dm_splits = flg; 2908 } 2909 PetscFunctionReturn(0); 2910 } 2911 2912 2913 /*@ 2914 PCFieldSplitGetDMSplits - Returns flag indicating whether DMCreateFieldDecomposition() should be used to define the splits, whenever possible. 2915 2916 Logically Collective 2917 2918 Input Parameter: 2919 . pc - the preconditioner context 2920 2921 Output Parameter: 2922 . flg - boolean indicating whether to use field splits defined by the DM 2923 2924 Level: Intermediate 2925 2926 .seealso: PCFieldSplitSetDMSplits() 2927 2928 @*/ 2929 PetscErrorCode PCFieldSplitGetDMSplits(PC pc,PetscBool* flg) 2930 { 2931 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 2932 PetscBool isfs; 2933 PetscErrorCode ierr; 2934 2935 PetscFunctionBegin; 2936 PetscValidHeaderSpecific(pc,PC_CLASSID,1); 2937 PetscValidBoolPointer(flg,2); 2938 ierr = PetscObjectTypeCompare((PetscObject)pc,PCFIELDSPLIT,&isfs);CHKERRQ(ierr); 2939 if (isfs) { 2940 if(flg) *flg = jac->dm_splits; 2941 } 2942 PetscFunctionReturn(0); 2943 } 2944 2945 /*@ 2946 PCFieldSplitGetDetectSaddlePoint - Returns flag indicating whether PCFieldSplit will attempt to automatically determine fields based on zero diagonal entries. 2947 2948 Logically Collective 2949 2950 Input Parameter: 2951 . pc - the preconditioner context 2952 2953 Output Parameter: 2954 . flg - boolean indicating whether to detect fields or not 2955 2956 Level: Intermediate 2957 2958 .seealso: PCFIELDSPLIT, PCFieldSplitSetDetectSaddlePoint() 2959 2960 @*/ 2961 PetscErrorCode PCFieldSplitGetDetectSaddlePoint(PC pc,PetscBool *flg) 2962 { 2963 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 2964 2965 PetscFunctionBegin; 2966 *flg = jac->detect; 2967 PetscFunctionReturn(0); 2968 } 2969 2970 /*@ 2971 PCFieldSplitSetDetectSaddlePoint - Sets flag indicating whether PCFieldSplit will attempt to automatically determine fields based on zero diagonal entries. 2972 2973 Logically Collective 2974 2975 Notes: 2976 Also sets the split type to PC_COMPOSITE_SCHUR (see PCFieldSplitSetType()) and the Schur preconditioner type to PC_FIELDSPLIT_SCHUR_PRE_SELF (see PCFieldSplitSetSchurPre()). 2977 2978 Input Parameter: 2979 . pc - the preconditioner context 2980 2981 Output Parameter: 2982 . flg - boolean indicating whether to detect fields or not 2983 2984 Options Database Key: 2985 . -pc_fieldsplit_detect_saddle_point 2986 2987 Level: Intermediate 2988 2989 .seealso: PCFIELDSPLIT, PCFieldSplitSetDetectSaddlePoint(), PCFieldSplitSetType(), PCFieldSplitSetSchurPre() 2990 2991 @*/ 2992 PetscErrorCode PCFieldSplitSetDetectSaddlePoint(PC pc,PetscBool flg) 2993 { 2994 PC_FieldSplit *jac = (PC_FieldSplit*)pc->data; 2995 PetscErrorCode ierr; 2996 2997 PetscFunctionBegin; 2998 jac->detect = flg; 2999 if (jac->detect) { 3000 ierr = PCFieldSplitSetType(pc,PC_COMPOSITE_SCHUR);CHKERRQ(ierr); 3001 ierr = PCFieldSplitSetSchurPre(pc,PC_FIELDSPLIT_SCHUR_PRE_SELF,NULL);CHKERRQ(ierr); 3002 } 3003 PetscFunctionReturn(0); 3004 } 3005 3006 /* -------------------------------------------------------------------------------------*/ 3007 /*MC 3008 PCFIELDSPLIT - Preconditioner created by combining separate preconditioners for individual 3009 fields or groups of fields. See the users manual section "Solving Block Matrices" for more details. 3010 3011 To set options on the solvers for each block append -fieldsplit_ to all the PC 3012 options database keys. For example, -fieldsplit_pc_type ilu -fieldsplit_pc_factor_levels 1 3013 3014 To set the options on the solvers separate for each block call PCFieldSplitGetSubKSP() 3015 and set the options directly on the resulting KSP object 3016 3017 Level: intermediate 3018 3019 Options Database Keys: 3020 + -pc_fieldsplit_%d_fields <a,b,..> - indicates the fields to be used in the %d'th split 3021 . -pc_fieldsplit_default - automatically add any fields to additional splits that have not 3022 been supplied explicitly by -pc_fieldsplit_%d_fields 3023 . -pc_fieldsplit_block_size <bs> - size of block that defines fields (i.e. there are bs fields) 3024 . -pc_fieldsplit_type <additive,multiplicative,symmetric_multiplicative,schur,gkb> - type of relaxation or factorization splitting 3025 . -pc_fieldsplit_schur_precondition <self,selfp,user,a11,full> - default is a11; see PCFieldSplitSetSchurPre() 3026 . -pc_fieldsplit_schur_fact_type <diag,lower,upper,full> - set factorization type when using -pc_fieldsplit_type schur 3027 - -pc_fieldsplit_detect_saddle_point - automatically finds rows with zero diagonal and uses Schur complement with no preconditioner as the solver 3028 3029 Options prefixes for inner solvers when using the Schur complement preconditioner are -fieldsplit_0_ and -fieldsplit_1_ . 3030 For all other solvers they are -fieldsplit_%d_ for the dth field; use -fieldsplit_ for all fields. 3031 The options prefix for the inner solver when using the Golub-Kahan biadiagonalization preconditioner is -fieldsplit_0_ 3032 3033 Notes: 3034 Use PCFieldSplitSetFields() to set fields defined by "strided" entries and PCFieldSplitSetIS() 3035 to define a field by an arbitrary collection of entries. 3036 3037 If no fields are set the default is used. The fields are defined by entries strided by bs, 3038 beginning at 0 then 1, etc to bs-1. The block size can be set with PCFieldSplitSetBlockSize(), 3039 if this is not called the block size defaults to the blocksize of the second matrix passed 3040 to KSPSetOperators()/PCSetOperators(). 3041 3042 $ For the Schur complement preconditioner if J = ( A00 A01 ) 3043 $ ( A10 A11 ) 3044 $ the preconditioner using full factorization is 3045 $ ( I -ksp(A00) A01 ) ( inv(A00) 0 ) ( I 0 ) 3046 $ ( 0 I ) ( 0 ksp(S) ) ( -A10 ksp(A00) I ) 3047 where the action of inv(A00) is applied using the KSP solver with prefix -fieldsplit_0_. S is the Schur complement 3048 $ S = A11 - A10 ksp(A00) A01 3049 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 3050 in providing the SECOND split or 1 if not give). For PCFieldSplitGetSubKSP() when field number is 0, 3051 it returns the KSP associated with -fieldsplit_0_ while field number 1 gives -fieldsplit_1_ KSP. By default 3052 A11 is used to construct a preconditioner for S, use PCFieldSplitSetSchurPre() for all the possible ways to construct the preconditioner for S. 3053 3054 The factorization type is set using -pc_fieldsplit_schur_fact_type <diag, lower, upper, full>. The full is shown above, 3055 diag gives 3056 $ ( inv(A00) 0 ) 3057 $ ( 0 -ksp(S) ) 3058 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 3059 can be turned off with PCFieldSplitSetSchurScale() or by command line -pc_fieldsplit_schur_scale 1.0. The lower factorization is the inverse of 3060 $ ( A00 0 ) 3061 $ ( A10 S ) 3062 where the inverses of A00 and S are applied using KSPs. The upper factorization is the inverse of 3063 $ ( A00 A01 ) 3064 $ ( 0 S ) 3065 where again the inverses of A00 and S are applied using KSPs. 3066 3067 If only one set of indices (one IS) is provided with PCFieldSplitSetIS() then the complement of that IS 3068 is used automatically for a second block. 3069 3070 The fieldsplit preconditioner cannot currently be used with the BAIJ or SBAIJ data formats if the blocksize is larger than 1. 3071 Generally it should be used with the AIJ format. 3072 3073 The forms of these preconditioners are closely related if not identical to forms derived as "Distributive Iterations", see, 3074 for example, page 294 in "Principles of Computational Fluid Dynamics" by Pieter Wesseling. Note that one can also use PCFIELDSPLIT 3075 inside a smoother resulting in "Distributive Smoothers". 3076 3077 There is a nice discussion of block preconditioners in 3078 3079 [El08] A taxonomy and comparison of parallel block multi-level preconditioners for the incompressible Navier-Stokes equations 3080 Howard Elman, V.E. Howle, John Shadid, Robert Shuttleworth, Ray Tuminaro, Journal of Computational Physics 227 (2008) 1790--1808 3081 http://chess.cs.umd.edu/~elman/papers/tax.pdf 3082 3083 The Constrained Pressure Preconditioner (CPR) can be implemented using PCCOMPOSITE with PCGALERKIN. CPR first solves an R A P subsystem, updates the 3084 residual on all variables (PCCompositeSetType(pc,PC_COMPOSITE_MULTIPLICATIVE)), and then applies a simple ILU like preconditioner on all the variables. 3085 3086 The generalized Golub-Kahan bidiagonalization preconditioner (gkb) can be applied to symmetric 2x2 block matrices of the shape 3087 $ ( A00 A01 ) 3088 $ ( A01' 0 ) 3089 with A00 positive semi-definite. The implementation follows [Ar13]. Therein, we choose N := 1/nu * I and the (1,1)-block of the matrix is modified to H = A00 + nu*A01*A01'. 3090 A linear system Hx = b has to be solved in each iteration of the GKB algorithm. This solver is chosen with the option prefix -fieldsplit_0_. 3091 3092 [Ar13] Generalized Golub-Kahan bidiagonalization and stopping criteria, SIAM J. Matrix Anal. Appl., Vol. 34, No. 2, pp. 571-592, 2013. 3093 3094 .seealso: PCCreate(), PCSetType(), PCType (for list of available types), PC, Block_Preconditioners, PCLSC, 3095 PCFieldSplitGetSubKSP(), PCFieldSplitSchurGetSubKSP(), PCFieldSplitSetFields(), PCFieldSplitSetType(), PCFieldSplitSetIS(), PCFieldSplitSetSchurPre(), 3096 MatSchurComplementSetAinvType(), PCFieldSplitSetSchurScale(), 3097 PCFieldSplitSetDetectSaddlePoint() 3098 M*/ 3099 3100 PETSC_EXTERN PetscErrorCode PCCreate_FieldSplit(PC pc) 3101 { 3102 PetscErrorCode ierr; 3103 PC_FieldSplit *jac; 3104 3105 PetscFunctionBegin; 3106 ierr = PetscNewLog(pc,&jac);CHKERRQ(ierr); 3107 3108 jac->bs = -1; 3109 jac->nsplits = 0; 3110 jac->type = PC_COMPOSITE_MULTIPLICATIVE; 3111 jac->schurpre = PC_FIELDSPLIT_SCHUR_PRE_USER; /* Try user preconditioner first, fall back on diagonal */ 3112 jac->schurfactorization = PC_FIELDSPLIT_SCHUR_FACT_FULL; 3113 jac->schurscale = -1.0; 3114 jac->dm_splits = PETSC_TRUE; 3115 jac->detect = PETSC_FALSE; 3116 jac->gkbtol = 1e-5; 3117 jac->gkbdelay = 5; 3118 jac->gkbnu = 1; 3119 jac->gkbmaxit = 100; 3120 jac->gkbmonitor = PETSC_FALSE; 3121 3122 pc->data = (void*)jac; 3123 3124 pc->ops->apply = PCApply_FieldSplit; 3125 pc->ops->applytranspose = PCApplyTranspose_FieldSplit; 3126 pc->ops->setup = PCSetUp_FieldSplit; 3127 pc->ops->reset = PCReset_FieldSplit; 3128 pc->ops->destroy = PCDestroy_FieldSplit; 3129 pc->ops->setfromoptions = PCSetFromOptions_FieldSplit; 3130 pc->ops->view = PCView_FieldSplit; 3131 pc->ops->applyrichardson = 0; 3132 3133 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitSchurGetSubKSP_C",PCFieldSplitSchurGetSubKSP_FieldSplit);CHKERRQ(ierr); 3134 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitGetSubKSP_C",PCFieldSplitGetSubKSP_FieldSplit);CHKERRQ(ierr); 3135 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitSetFields_C",PCFieldSplitSetFields_FieldSplit);CHKERRQ(ierr); 3136 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitSetIS_C",PCFieldSplitSetIS_FieldSplit);CHKERRQ(ierr); 3137 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitSetType_C",PCFieldSplitSetType_FieldSplit);CHKERRQ(ierr); 3138 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitSetBlockSize_C",PCFieldSplitSetBlockSize_FieldSplit);CHKERRQ(ierr); 3139 ierr = PetscObjectComposeFunction((PetscObject)pc,"PCFieldSplitRestrictIS_C",PCFieldSplitRestrictIS_FieldSplit);CHKERRQ(ierr); 3140 PetscFunctionReturn(0); 3141 } 3142