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