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