1 #include <private/snesimpl.h> 2 3 typedef struct _BlockDesc *BlockDesc; 4 struct _BlockDesc { 5 char *name; /* Block name */ 6 PetscInt nfields; /* If block is defined on a DA, the number of DA fields */ 7 PetscInt *fields; /* If block is defined on a DA, the list of DA fields */ 8 IS is; /* Index sets defining the block */ 9 VecScatter sctx; /* Scatter mapping global Vec to blockVec */ 10 SNES snes; /* Solver for this block */ 11 Vec x; 12 BlockDesc next, previous; 13 }; 14 15 typedef struct { 16 PetscBool issetup; /* Flag is true after the all ISs and operators have been defined */ 17 PetscBool defined; /* Flag is true after the blocks have been defined, to prevent more blocks from being added */ 18 PetscBool defaultblocks; /* Flag is true for a system with a set of 'k' scalar fields with the same layout (and bs = k) */ 19 PetscInt numBlocks; /* Number of blocks (can be fields, domains, etc.) */ 20 PetscInt bs; /* Block size for IS, Vec and Mat structures */ 21 PCCompositeType type; /* Solver combination method (additive, multiplicative, etc.) */ 22 BlockDesc blocks; /* Linked list of block descriptors */ 23 } SNES_Multiblock; 24 25 #undef __FUNCT__ 26 #define __FUNCT__ "SNESReset_Multiblock" 27 PetscErrorCode SNESReset_Multiblock(SNES snes) 28 { 29 SNES_Multiblock *mb = (SNES_Multiblock *) snes->data; 30 BlockDesc blocks = mb->blocks, next; 31 PetscErrorCode ierr; 32 33 PetscFunctionBegin; 34 while (blocks) { 35 ierr = SNESReset(blocks->snes);CHKERRQ(ierr); 36 //ierr = VecDestroy(&blocks->x);CHKERRQ(ierr); 37 //ierr = VecDestroy(&blocks->y);CHKERRQ(ierr); 38 ierr = VecScatterDestroy(&blocks->sctx);CHKERRQ(ierr); 39 ierr = ISDestroy(&blocks->is);CHKERRQ(ierr); 40 next = blocks->next; 41 blocks = next; 42 } 43 if (snes->work) {ierr = VecDestroyVecs(snes->nwork, &snes->work);CHKERRQ(ierr);} 44 PetscFunctionReturn(0); 45 } 46 47 /* 48 SNESDestroy_Multiblock - Destroys the private SNES_Multiblock context that was created with SNESCreate_Multiblock(). 49 50 Input Parameter: 51 . snes - the SNES context 52 53 Application Interface Routine: SNESDestroy() 54 */ 55 #undef __FUNCT__ 56 #define __FUNCT__ "SNESDestroy_Multiblock" 57 PetscErrorCode SNESDestroy_Multiblock(SNES snes) 58 { 59 SNES_Multiblock *mb = (SNES_Multiblock *) snes->data; 60 BlockDesc blocks = mb->blocks, next; 61 PetscErrorCode ierr; 62 63 PetscFunctionBegin; 64 ierr = SNESReset_Multiblock(snes);CHKERRQ(ierr); 65 while (blocks) { 66 next = blocks->next; 67 ierr = SNESDestroy(&blocks->snes);CHKERRQ(ierr); 68 ierr = PetscFree(blocks->name);CHKERRQ(ierr); 69 ierr = PetscFree(blocks->fields);CHKERRQ(ierr); 70 ierr = PetscFree(blocks);CHKERRQ(ierr); 71 blocks = next; 72 } 73 ierr = PetscFree(snes->data);CHKERRQ(ierr); 74 PetscFunctionReturn(0); 75 } 76 77 #undef __FUNCT__ 78 #define __FUNCT__ "SNESMultiblockSetFieldsRuntime_Private" 79 /* Precondition: blocksize is set to a meaningful value */ 80 static PetscErrorCode SNESMultiblockSetFieldsRuntime_Private(PC pc) 81 { 82 SNES_Multiblock *mb = (SNES_Multiblock *) snes->data; 83 PetscInt *ifields; 84 PetscInt i, nfields; 85 PetscBool flg = PETSC_TRUE; 86 char optionname[128], name[8]; 87 PetscErrorCode ierr; 88 89 PetscFunctionBegin; 90 ierr = PetscMalloc(mb->bs * sizeof(PetscInt), &ifields);CHKERRQ(ierr); 91 for(i = 0; ; ++i) { 92 ierr = PetscSNPrintf(name, sizeof name, "%D", i);CHKERRQ(ierr); 93 ierr = PetscSNPrintf(optionname, sizeof optionname, "-snes_multiblock_%D_fields", i);CHKERRQ(ierr); 94 nfields = mb->bs; 95 ierr = PetscOptionsGetIntArray(((PetscObject) snes)->prefix, optionname, ifields, &nfields, &flg);CHKERRQ(ierr); 96 if (!flg) break; 97 if (!nfields) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_USER, "Cannot list zero fields"); 98 ierr = SNESMultiblockSetFields(pc, name, nfields, ifields);CHKERRQ(ierr); 99 } 100 if (i > 0) { 101 /* Makes command-line setting of blocks take precedence over setting them in code. 102 Otherwise subsequent calls to SNESMultiblockSetIS() or SNESMultiblockSetFields() would 103 create new blocks, which would probably not be what the user wanted. */ 104 mb->defined = PETSC_TRUE; 105 } 106 ierr = PetscFree(ifields);CHKERRQ(ierr); 107 PetscFunctionReturn(0); 108 } 109 110 #undef __FUNCT__ 111 #define __FUNCT__ "SNESMultiblockSetDefaults" 112 static PetscErrorCode SNESMultiblockSetDefaults(SNES snes) 113 { 114 SNES_Multiblock *mb = (SNES_Multiblock *) snes->data; 115 BlockDesc blocks = mb->blocks; 116 PetscInt i; 117 PetscErrorCode ierr; 118 119 PetscFunctionBegin; 120 if (!blocks) { 121 if (snes->dm) { 122 PetscBool dmcomposite; 123 124 ierr = PetscTypeCompare((PetscObject) snes->dm, DMCOMPOSITE, &dmcomposite);CHKERRQ(ierr); 125 if (dmcomposite) { 126 PetscInt nDM; 127 IS *fields; 128 129 ierr = PetscInfo(pc,"Setting up physics based multiblock solver using the embedded DM\n");CHKERRQ(ierr); 130 ierr = DMCompositeGetNumberDM(snes->dm, &nDM);CHKERRQ(ierr); 131 ierr = DMCompositeGetGlobalISs(snes->dm, &fields);CHKERRQ(ierr); 132 for(i = 0; i < nDM; ++i) { 133 char name[8]; 134 135 ierr = PetscSNPrintf(name, sizeof name, "%D", i);CHKERRQ(ierr); 136 ierr = SNESMultiblockSetIS(snes, name, fields[i]);CHKERRQ(ierr); 137 ierr = ISDestroy(&fields[i]);CHKERRQ(ierr); 138 } 139 ierr = PetscFree(fields);CHKERRQ(ierr); 140 } 141 } else { 142 PetscBool flg = PETSC_FALSE; 143 PetscBool stokes = PETSC_FALSE; 144 145 if (mb->bs <= 0) { 146 if (snes->jac) { 147 ierr = MatGetBlockSize(snes->jac, &mb->bs);CHKERRQ(ierr); 148 } else { 149 mb->bs = 1; 150 } 151 } 152 153 ierr = PetscOptionsGetBool(((PetscObject) snes)->prefix, "-snes_multiblock_default", &flg, PETSC_NULL);CHKERRQ(ierr); 154 ierr = PetscOptionsGetBool(((PetscObject) snes)->prefix, "-snes_multiblock_detect_saddle_point", &stokes, PETSC_NULL);CHKERRQ(ierr); 155 if (stokes) { 156 IS zerodiags, rest; 157 PetscInt nmin, nmax; 158 159 ierr = MatGetOwnershipRange(snes->jac, &nmin, &nmax);CHKERRQ(ierr); 160 ierr = MatFindZeroDiagonals(snes->jac, &zerodiags);CHKERRQ(ierr); 161 ierr = ISComplement(zerodiags, nmin, nmax, &rest);CHKERRQ(ierr); 162 ierr = SNESMultiblockSetIS(snes, "0", rest);CHKERRQ(ierr); 163 ierr = SNESMultiblockSetIS(snes, "1", zerodiags);CHKERRQ(ierr); 164 ierr = ISDestroy(&zerodiags);CHKERRQ(ierr); 165 ierr = ISDestroy(&rest);CHKERRQ(ierr); 166 } else { 167 if (!flg) { 168 /* Allow user to set fields from command line, if bs was known at the time of SNESSetFromOptions_Multiblock() 169 then it is set there. This is not ideal because we should only have options set in XXSetFromOptions(). */ 170 ierr = SNESMultiblockSetFieldsRuntime_Private(pc);CHKERRQ(ierr); 171 if (mb->defined) {ierr = PetscInfo(snes, "Blocks defined using the options database\n");CHKERRQ(ierr);} 172 } 173 if (flg || !mb->defined) { 174 ierr = PetscInfo(snes, "Using default splitting of fields\n");CHKERRQ(ierr); 175 for(i = 0; i < mb->bs; ++i) { 176 char name[8]; 177 178 ierr = PetscSNPrintf(name, sizeof name, "%D", i);CHKERRQ(ierr); 179 ierr = SNESMultiblockSetFields(snes, name, 1, &i);CHKERRQ(ierr); 180 } 181 mb->defaultblocks = PETSC_TRUE; 182 } 183 } 184 } 185 } else if (mb->numBlocks == 1) { 186 if (blocks->is) { 187 IS is2; 188 PetscInt nmin, nmax; 189 190 ierr = MatGetOwnershipRange(snes->jac, &nmin, &nmax);CHKERRQ(ierr); 191 ierr = ISComplement(blocks->is, nmin, nmax, &is2);CHKERRQ(ierr); 192 ierr = SNESMultiblockSetIS(snes, "1", is2);CHKERRQ(ierr); 193 ierr = ISDestroy(&is2);CHKERRQ(ierr); 194 } else { 195 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Must provide at least two sets of fields to SNES multiblock"); 196 } 197 } 198 if (mb->numBlocks < 2) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unhandled case, must have at least two blocks"); 199 PetscFunctionReturn(0); 200 } 201 202 /* 203 SNESSetUp_Multiblock - Sets up the internal data structures for the later use 204 of the SNESMULTIBLOCK nonlinear solver. 205 206 Input Parameters: 207 + snes - the SNES context 208 - x - the solution vector 209 210 Application Interface Routine: SNESSetUp() 211 */ 212 #undef __FUNCT__ 213 #define __FUNCT__ "SNESSetUp_Multiblock" 214 PetscErrorCode SNESSetUp_Multiblock(SNES snes) 215 { 216 SNES_Multiblock *mb = (SNES_Multiblock *) snes->data; 217 BlockDesc blocks; 218 PetscInt i, numBlocks; 219 PetscErrorCode ierr; 220 221 PetscFunctionBegin; 222 /* ierr = SNESDefaultGetWork(snes, 1);CHKERRQ(ierr); */ 223 ierr = PCFieldSplitSetDefaults(snes);CHKERRQ(ierr); 224 numBlocks = mb->numBlocks; 225 blocks = jac->head; 226 227 /* Create ISs */ 228 if (!mb->issetup) { 229 PetscInt ccsize, rstart, rend, nslots, bs; 230 PetscBool sorted; 231 232 mb->issetup = PETSC_TRUE; 233 bs = mb->bs; 234 ierr = MatGetOwnershipRange(snes->jac, &rstart, &rend);CHKERRQ(ierr); 235 ierr = MatGetLocalSize(snes->jac, PETSC_NULL, &ccsize);CHKERRQ(ierr); 236 nslots = (rend - rstart)/bs; 237 for(i = 0; i < numBlocks; ++i) { 238 if (mb->defaultsplit) { 239 ierr = ISCreateStride(((PetscObject) snes)->comm, nslots, rstart+i, numBlocks, &blocks->is);CHKERRQ(ierr); 240 } else if (!blocks->is) { 241 if (blocks->nfields > 1) { 242 PetscInt *ii, j, k, nfields = blocks->nfields, *fields = blocks->fields; 243 244 ierr = PetscMalloc(nfields*nslots*sizeof(PetscInt), &ii);CHKERRQ(ierr); 245 for(j = 0; j < nslots; ++j) { 246 for(k = 0; k < nfields; ++k) { 247 ii[nfields*j + k] = rstart + bs*j + fields[k]; 248 } 249 } 250 ierr = ISCreateGeneral(((PetscObject) snes)->comm, nslots*nfields, ii, PETSC_OWN_POINTER, &blocks->is);CHKERRQ(ierr); 251 } else { 252 ierr = ISCreateStride(((PetscObject) snes)->comm, nslots, rstart+blocks->fields[0], bs, &blocks->is);CHKERRQ(ierr); 253 } 254 } 255 ierr = ISSorted(blocks->is, &sorted);CHKERRQ(ierr); 256 if (!sorted) {SETERRQ(PETSC_COMM_SELF, PETSC_ERR_USER, "Fields must be sorted when creating split");} 257 blocks = blocks->next; 258 } 259 } 260 261 #if 0 262 /* Create matrices */ 263 ilink = jac->head; 264 if (!jac->pmat) { 265 ierr = PetscMalloc(nsplit*sizeof(Mat),&jac->pmat);CHKERRQ(ierr); 266 for (i=0; i<nsplit; i++) { 267 ierr = MatGetSubMatrix(pc->pmat,ilink->is,ilink->is,MAT_INITIAL_MATRIX,&jac->pmat[i]);CHKERRQ(ierr); 268 ilink = ilink->next; 269 } 270 } else { 271 for (i=0; i<nsplit; i++) { 272 ierr = MatGetSubMatrix(pc->pmat,ilink->is,ilink->is,MAT_REUSE_MATRIX,&jac->pmat[i]);CHKERRQ(ierr); 273 ilink = ilink->next; 274 } 275 } 276 if (jac->realdiagonal) { 277 ilink = jac->head; 278 if (!jac->mat) { 279 ierr = PetscMalloc(nsplit*sizeof(Mat),&jac->mat);CHKERRQ(ierr); 280 for (i=0; i<nsplit; i++) { 281 ierr = MatGetSubMatrix(pc->mat,ilink->is,ilink->is,MAT_INITIAL_MATRIX,&jac->mat[i]);CHKERRQ(ierr); 282 ilink = ilink->next; 283 } 284 } else { 285 for (i=0; i<nsplit; i++) { 286 if (jac->mat[i]) {ierr = MatGetSubMatrix(pc->mat,ilink->is,ilink->is,MAT_REUSE_MATRIX,&jac->mat[i]);CHKERRQ(ierr);} 287 ilink = ilink->next; 288 } 289 } 290 } else { 291 jac->mat = jac->pmat; 292 } 293 #endif 294 295 #if 0 296 if (jac->type != PC_COMPOSITE_ADDITIVE && jac->type != PC_COMPOSITE_SCHUR) { 297 /* extract the rows of the matrix associated with each field: used for efficient computation of residual inside algorithm */ 298 ilink = jac->head; 299 if (!jac->Afield) { 300 ierr = PetscMalloc(nsplit*sizeof(Mat),&jac->Afield);CHKERRQ(ierr); 301 for (i=0; i<nsplit; i++) { 302 ierr = MatGetSubMatrix(pc->mat,ilink->is,PETSC_NULL,MAT_INITIAL_MATRIX,&jac->Afield[i]);CHKERRQ(ierr); 303 ilink = ilink->next; 304 } 305 } else { 306 for (i=0; i<nsplit; i++) { 307 ierr = MatGetSubMatrix(pc->mat,ilink->is,PETSC_NULL,MAT_REUSE_MATRIX,&jac->Afield[i]);CHKERRQ(ierr); 308 ilink = ilink->next; 309 } 310 } 311 } 312 #endif 313 314 if (jac->type == PC_COMPOSITE_SCHUR) { 315 #if 0 316 IS ccis; 317 PetscInt rstart,rend; 318 if (nsplit != 2) SETERRQ(((PetscObject)pc)->comm,PETSC_ERR_ARG_INCOMP,"To use Schur complement preconditioner you must have exactly 2 fields"); 319 320 /* When extracting off-diagonal submatrices, we take complements from this range */ 321 ierr = MatGetOwnershipRangeColumn(pc->mat,&rstart,&rend);CHKERRQ(ierr); 322 323 /* need to handle case when one is resetting up the preconditioner */ 324 if (jac->schur) { 325 ilink = jac->head; 326 ierr = ISComplement(ilink->is,rstart,rend,&ccis);CHKERRQ(ierr); 327 ierr = MatGetSubMatrix(pc->mat,ilink->is,ccis,MAT_REUSE_MATRIX,&jac->B);CHKERRQ(ierr); 328 ierr = ISDestroy(&ccis);CHKERRQ(ierr); 329 ilink = ilink->next; 330 ierr = ISComplement(ilink->is,rstart,rend,&ccis);CHKERRQ(ierr); 331 ierr = MatGetSubMatrix(pc->mat,ilink->is,ccis,MAT_REUSE_MATRIX,&jac->C);CHKERRQ(ierr); 332 ierr = ISDestroy(&ccis);CHKERRQ(ierr); 333 ierr = MatSchurComplementUpdate(jac->schur,jac->mat[0],jac->pmat[0],jac->B,jac->C,jac->pmat[1],pc->flag);CHKERRQ(ierr); 334 ierr = KSPSetOperators(jac->kspschur,jac->schur,FieldSplitSchurPre(jac),pc->flag);CHKERRQ(ierr); 335 336 } else { 337 KSP ksp; 338 char schurprefix[256]; 339 340 /* extract the A01 and A10 matrices */ 341 ilink = jac->head; 342 ierr = ISComplement(ilink->is,rstart,rend,&ccis);CHKERRQ(ierr); 343 ierr = MatGetSubMatrix(pc->mat,ilink->is,ccis,MAT_INITIAL_MATRIX,&jac->B);CHKERRQ(ierr); 344 ierr = ISDestroy(&ccis);CHKERRQ(ierr); 345 ilink = ilink->next; 346 ierr = ISComplement(ilink->is,rstart,rend,&ccis);CHKERRQ(ierr); 347 ierr = MatGetSubMatrix(pc->mat,ilink->is,ccis,MAT_INITIAL_MATRIX,&jac->C);CHKERRQ(ierr); 348 ierr = ISDestroy(&ccis);CHKERRQ(ierr); 349 /* Use mat[0] (diagonal block of the real matrix) preconditioned by pmat[0] */ 350 ierr = MatCreateSchurComplement(jac->mat[0],jac->pmat[0],jac->B,jac->C,jac->mat[1],&jac->schur);CHKERRQ(ierr); 351 /* set tabbing and options prefix of KSP inside the MatSchur */ 352 ierr = MatSchurComplementGetKSP(jac->schur,&ksp);CHKERRQ(ierr); 353 ierr = PetscObjectIncrementTabLevel((PetscObject)ksp,(PetscObject)pc,2);CHKERRQ(ierr); 354 ierr = PetscSNPrintf(schurprefix,sizeof schurprefix,"%sfieldsplit_%s_",((PetscObject)pc)->prefix?((PetscObject)pc)->prefix:"",jac->head->splitname);CHKERRQ(ierr); 355 ierr = KSPSetOptionsPrefix(ksp,schurprefix);CHKERRQ(ierr); 356 ierr = MatSetFromOptions(jac->schur);CHKERRQ(ierr); 357 358 ierr = KSPCreate(((PetscObject)pc)->comm,&jac->kspschur);CHKERRQ(ierr); 359 ierr = PetscLogObjectParent((PetscObject)pc,(PetscObject)jac->kspschur);CHKERRQ(ierr); 360 ierr = PetscObjectIncrementTabLevel((PetscObject)jac->kspschur,(PetscObject)pc,1);CHKERRQ(ierr); 361 ierr = KSPSetOperators(jac->kspschur,jac->schur,FieldSplitSchurPre(jac),DIFFERENT_NONZERO_PATTERN);CHKERRQ(ierr); 362 if (jac->schurpre == PC_FIELDSPLIT_SCHUR_PRE_SELF) { 363 PC pc; 364 ierr = KSPGetPC(jac->kspschur,&pc);CHKERRQ(ierr); 365 ierr = PCSetType(pc,PCNONE);CHKERRQ(ierr); 366 /* Note: This is bad if there exist preconditioners for MATSCHURCOMPLEMENT */ 367 } 368 ierr = PetscSNPrintf(schurprefix,sizeof schurprefix,"%sfieldsplit_%s_",((PetscObject)pc)->prefix?((PetscObject)pc)->prefix:"",ilink->splitname);CHKERRQ(ierr); 369 ierr = KSPSetOptionsPrefix(jac->kspschur,schurprefix);CHKERRQ(ierr); 370 /* really want setfromoptions called in PCSetFromOptions_FieldSplit(), but it is not ready yet */ 371 ierr = KSPSetFromOptions(jac->kspschur);CHKERRQ(ierr); 372 373 ierr = PetscMalloc2(2,Vec,&jac->x,2,Vec,&jac->y);CHKERRQ(ierr); 374 ierr = MatGetVecs(jac->pmat[0],&jac->x[0],&jac->y[0]);CHKERRQ(ierr); 375 ierr = MatGetVecs(jac->pmat[1],&jac->x[1],&jac->y[1]);CHKERRQ(ierr); 376 ilink = jac->head; 377 ilink->x = jac->x[0]; ilink->y = jac->y[0]; 378 ilink = ilink->next; 379 ilink->x = jac->x[1]; ilink->y = jac->y[1]; 380 } 381 #endif 382 } else { 383 /* Set up the individual SNESs */ 384 blocks = mb->blocks; 385 i = 0; 386 while (blocks) { 387 ierr = KSPSetOperators(blocks->snes, jac->mat[i], jac->pmat[i], flag);CHKERRQ(ierr); 388 ierr = VecDuplicate(blocks->snes->vec_sol, &blocks->snes->x);CHKERRQ(ierr); 389 /* really want setfromoptions called in SNESSetFromOptions_Multiblock(), but it is not ready yet */ 390 ierr = SNESSetFromOptions(blocks->snes);CHKERRQ(ierr); 391 ierr = SNESSetUp(blocks->snes);CHKERRQ(ierr); 392 blocks = blocks->next; 393 i++; 394 } 395 } 396 397 /* Compute scatter contexts needed by multiplicative versions and non-default splits */ 398 if (!mb->blocks->sctx) { 399 Vec xtmp; 400 401 blocks = mb->blocks; 402 ierr = MatGetVecs(pc->pmat, &xtmp, PETSC_NULL);CHKERRQ(ierr); 403 while(blocks) { 404 ierr = VecScatterCreate(xtmp, blocks->is, blocks->x, PETSC_NULL, &blocks->sctx);CHKERRQ(ierr); 405 blocks = blocks->next; 406 } 407 ierr = VecDestroy(&xtmp);CHKERRQ(ierr); 408 } 409 PetscFunctionReturn(0); 410 } 411 412 /* 413 SNESSetFromOptions_Multiblock - Sets various parameters for the SNESMULTIBLOCK method. 414 415 Input Parameter: 416 . snes - the SNES context 417 418 Application Interface Routine: SNESSetFromOptions() 419 */ 420 #undef __FUNCT__ 421 #define __FUNCT__ "SNESSetFromOptions_Multiblock" 422 static PetscErrorCode SNESSetFromOptions_Multiblock(SNES snes) 423 { 424 SNES_Multiblock *mb = (SNES_Multiblock *) snes->data; 425 PCCompositeType ctype; 426 PetscInt bs; 427 PetscBool flg; 428 PetscErrorCode ierr; 429 430 PetscFunctionBegin; 431 ierr = PetscOptionsHead("SNES Multiblock options");CHKERRQ(ierr); 432 ierr = PetscOptionsInt("-snes_multiblock_block_size", "Blocksize that defines number of fields", "PCFieldSplitSetBlockSize", mb->bs, &bs, &flg);CHKERRQ(ierr); 433 if (flg) {ierr = PCFieldSplitSetBlockSize(snes, bs);CHKERRQ(ierr);} 434 ierr = PetscOptionsEnum("-snes_multiblock_type", "Type of composition", "PCFieldSplitSetType", PCCompositeTypes, (PetscEnum) mb->type, (PetscEnum *) &ctype, &flg);CHKERRQ(ierr); 435 if (flg) { 436 ierr = PCFieldSplitSetType(pc,ctype);CHKERRQ(ierr); 437 } 438 /* Only setup fields once */ 439 if ((mb->bs > 0) && (mb->numBLocks == 0)) { 440 /* only allow user to set fields from command line if bs is already known, otherwise user can set them in SNESMultiblockSetDefaults() */ 441 ierr = PCFieldSplitSetRuntimeSplits_Private(pc);CHKERRQ(ierr); 442 if (mb->splitdefined) {ierr = PetscInfo(snes, "Splits defined using the options database\n");CHKERRQ(ierr);} 443 } 444 ierr = PetscOptionsTail();CHKERRQ(ierr); 445 PetscFunctionReturn(0); 446 } 447 448 /* 449 SNESView_Multiblock - Prints info from the SNESMULTIBLOCK data structure. 450 451 Input Parameters: 452 + SNES - the SNES context 453 - viewer - visualization context 454 455 Application Interface Routine: SNESView() 456 */ 457 #undef __FUNCT__ 458 #define __FUNCT__ "SNESView_Multiblock" 459 static PetscErrorCode SNESView_Multiblock(SNES snes, PetscViewer viewer) 460 { 461 SNES_Multiblock *mb = (SNES_Multiblock *) snes->data; 462 BlockDesc blocks = mb->blocks; 463 PetscBool iascii; 464 PetscErrorCode ierr; 465 466 PetscFunctionBegin; 467 ierr = PetscTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr); 468 if (iascii) { 469 ierr = PetscViewerASCIIPrintf(viewer," Multiblock with %s composition: total blocks = %D, blocksize = %D\n", PCCompositeTypes[mb->type], mb->numBlocks, mb->bs);CHKERRQ(ierr); 470 ierr = PetscViewerASCIIPrintf(viewer," Solver info for each split is in the following SNES objects:\n");CHKERRQ(ierr); 471 ierr = PetscViewerASCIIPushTab(viewer);CHKERRQ(ierr); 472 while (blocks) { 473 if (blocks->fields) { 474 PetscInt j; 475 476 ierr = PetscViewerASCIIPrintf(viewer, "Block %s Fields ", blocks->name);CHKERRQ(ierr); 477 ierr = PetscViewerASCIIUseTabs(viewer, PETSC_FALSE);CHKERRQ(ierr); 478 for(j = 0; j < blocks->nfields; ++j) { 479 if (j > 0) { 480 ierr = PetscViewerASCIIPrintf(viewer, ",");CHKERRQ(ierr); 481 } 482 ierr = PetscViewerASCIIPrintf(viewer, " %D", blocks->fields[j]);CHKERRQ(ierr); 483 } 484 ierr = PetscViewerASCIIPrintf(viewer, "\n");CHKERRQ(ierr); 485 ierr = PetscViewerASCIIUseTabs(viewer, PETSC_TRUE);CHKERRQ(ierr); 486 } else { 487 ierr = PetscViewerASCIIPrintf(viewer, "Block %s Defined by IS\n", blocks->names);CHKERRQ(ierr); 488 } 489 ierr = SNESView(blocks->snes, viewer);CHKERRQ(ierr); 490 blocks = blocks->next; 491 } 492 ierr = PetscViewerASCIIPopTab(viewer);CHKERRQ(ierr); 493 } else { 494 SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP, "Viewer type %s not supported for SNES Multiblock", ((PetscObject)viewer)->type_name); 495 } 496 PetscFunctionReturn(0); 497 } 498 499 /* 500 SNESSolve_Multiblock - Solves a nonlinear system with the Multiblock method. 501 502 Input Parameters: 503 . snes - the SNES context 504 505 Output Parameter: 506 . outits - number of iterations until termination 507 508 Application Interface Routine: SNESSolve() 509 */ 510 #undef __FUNCT__ 511 #define __FUNCT__ "SNESSolve_Multiblock" 512 PetscErrorCode SNESSolve_Multiblock(SNES snes) 513 { 514 SNES_Multiblock *mb = (SNES_Multiblock *) snes->data; 515 Vec X, Y, F; 516 PetscReal alpha = mb->alpha; 517 PetscReal fnorm; 518 PetscInt maxits, i; 519 PetscErrorCode ierr; 520 521 PetscFunctionBegin; 522 snes->reason = SNES_CONVERGED_ITERATING; 523 524 maxits = snes->max_its; /* maximum number of iterations */ 525 X = snes->vec_sol; /* X^n */ 526 Y = snes->vec_sol_update; /* \tilde X */ 527 F = snes->vec_func; /* residual vector */ 528 529 ierr = VecSetBlockSize(X, mb->bs);CHKERRQ(ierr); 530 ierr = VecSetBlockSize(Y, mb->bs);CHKERRQ(ierr); 531 ierr = VecSetBlockSize(F, mb->bs);CHKERRQ(ierr); 532 ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr); 533 snes->iter = 0; 534 snes->norm = 0.; 535 ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); 536 ierr = SNESComputeFunction(snes, X, F);CHKERRQ(ierr); 537 if (snes->domainerror) { 538 snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN; 539 PetscFunctionReturn(0); 540 } 541 ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr); /* fnorm <- ||F|| */ 542 if (PetscIsInfOrNanReal(fnorm)) {SETERRQ(PETSC_COMM_SELF, PETSC_ERR_FP, "Infinite or not-a-number generated in norm");} 543 ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr); 544 snes->norm = fnorm; 545 ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); 546 SNESLogConvHistory(snes,fnorm,0); 547 ierr = SNESMonitor(snes,0,fnorm);CHKERRQ(ierr); 548 549 /* set parameter for default relative tolerance convergence test */ 550 snes->ttol = fnorm*snes->rtol; 551 /* test convergence */ 552 ierr = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr); 553 if (snes->reason) PetscFunctionReturn(0); 554 555 for(i = 0; i < maxits; i++) { 556 PetscBool lsSuccess = PETSC_TRUE; 557 558 /* Call general purpose update function */ 559 if (snes->ops->update) { 560 ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr); 561 } 562 /* Compute X^{new} from subsolves */ 563 if (mb->type == PC_COMPOSITE_ADDITIVE) { 564 BlockDesc blocks = mb->blocks; 565 566 if (mb->defaultsplit) { 567 ierr = VecStrideGatherAll(x, mb->x, INSERT_VALUES);CHKERRQ(ierr); 568 while (blocks) { 569 ierr = SNESSolve(blocks->snes, PETSC_NULL, blocks->x);CHKERRQ(ierr); 570 blocks = blocks->next; 571 } 572 ierr = VecStrideScatterAll(mb->y, y, INSERT_VALUES);CHKERRQ(ierr); 573 } else { 574 while (blocks) { 575 ierr = VecScatterBegin(blocks->sctx, X, blocks->x, INSERT_VALUES, SCATTER_FORWARD);CHKERRQ(ierr); 576 ierr = VecScatterEnd(blocks->sctx, X, blocks->x, INSERT_VALUES, SCATTER_FORWARD);CHKERRQ(ierr); 577 ierr = SNESSolve(blocks->snes, PETSC_NULL, blocks->x);CHKERRQ(ierr); 578 ierr = VecScatterBegin(blocks->sctx, blocks->x, X, INSERT_VALUES, SCATTER_REVERSE);CHKERRQ(ierr); 579 ierr = VecScatterEnd(blocks->sctx, blocks->x, X, INSERT_VALUES, SCATTER_REVERSE);CHKERRQ(ierr); 580 blocks = blocks->next; 581 } 582 } 583 } else { 584 SETERRQ1(((PetscObject) snes)->comm, PETSC_ERR_SUP, "Unsupported or unknown composition", (int) mb->type); 585 } 586 CHKMEMQ; 587 /* Compute F(X^{new}) */ 588 ierr = SNESComputeFunction(snes, X, F);CHKERRQ(ierr); 589 ierr = VecNorm(F, NORM_2, &fnorm);CHKERRQ(ierr); 590 if (PetscIsInfOrNanReal(fnorm)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FP,"Infinite or not-a-number generated norm"); 591 592 if (snes->nfuncs >= snes->max_funcs) { 593 snes->reason = SNES_DIVERGED_FUNCTION_COUNT; 594 break; 595 } 596 if (snes->domainerror) { 597 snes->reason = SNES_DIVERGED_FUNCTION_DOMAIN; 598 PetscFunctionReturn(0); 599 } 600 /* Monitor convergence */ 601 ierr = PetscObjectTakeAccess(snes);CHKERRQ(ierr); 602 snes->iter = i+1; 603 snes->norm = fnorm; 604 ierr = PetscObjectGrantAccess(snes);CHKERRQ(ierr); 605 SNESLogConvHistory(snes,snes->norm,0); 606 ierr = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr); 607 /* Test for convergence */ 608 ierr = (*snes->ops->converged)(snes,snes->iter,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr); 609 if (snes->reason) break; 610 } 611 if (i == maxits) { 612 ierr = PetscInfo1(snes, "Maximum number of iterations has been reached: %D\n", maxits);CHKERRQ(ierr); 613 if (!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT; 614 } 615 PetscFunctionReturn(0); 616 } 617 618 EXTERN_C_BEGIN 619 #undef __FUNCT__ 620 #define __FUNCT__ "SNESMultiblockSetFields_Default" 621 PetscErrorCode SNESMultiblockSetFields_Default(SNES snes, const char name[], PetscInt n, const PetscInt fields[]) 622 { 623 SNES_Multiblock *mb = (SNES_Multiblock *) snes->data; 624 BlockDesc newblock, next = mb->blocks; 625 char prefix[128]; 626 PetscInt i; 627 PetscErrorCode ierr; 628 629 PetscFunctionBegin; 630 if (mb->defined) { 631 ierr = PetscInfo1(snes, "Ignoring new block \"%s\" because the blocks have already been defined\n", name);CHKERRQ(ierr); 632 PetscFunctionReturn(0); 633 } 634 for(i = 0; i < n; ++i) { 635 if (fields[i] >= mb->bs) {SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Field %D requested but only %D exist", fields[i], mb->bs);} 636 if (fields[i] < 0) {SETERRQ1(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Negative field %D requested", fields[i]);} 637 } 638 ierr = PetscNew(struct _BlockDesc, &newblock);CHKERRQ(ierr); 639 if (name) { 640 ierr = PetscStrallocpy(name, &newblock->name);CHKERRQ(ierr); 641 } else { 642 PetscInt len = floor(log10(mb->numBlocks))+1; 643 644 ierr = PetscMalloc((len+1)*sizeof(char), &newblock->name);CHKERRQ(ierr); 645 ierr = PetscSNPrintf(newblock->name, len, "%s", mb->numBlocks);CHKERRQ(ierr); 646 } 647 newblock->nfields = n; 648 ierr = PetscMalloc(n*sizeof(PetscInt), &newblock->fields);CHKERRQ(ierr); 649 ierr = PetscMemcpy(newblock->fields, fields, n*sizeof(PetscInt));CHKERRQ(ierr); 650 newblock->next = PETSC_NULL; 651 ierr = SNESCreate(((PetscObject) snes)->comm, &newblock->snes);CHKERRQ(ierr); 652 ierr = PetscObjectIncrementTabLevel((PetscObject) newblock->snes, (PetscObject) snes, 1);CHKERRQ(ierr); 653 ierr = SNESSetType(newblock->snes, SNESPICARD);CHKERRQ(ierr); 654 ierr = PetscLogObjectParent((PetscObject) snes, (PetscObject) newblock->snes);CHKERRQ(ierr); 655 ierr = PetscSNPrintf(prefix, sizeof prefix, "%smultiblock_%s_", ((PetscObject) snes)->prefix ? ((PetscObject) snes)->prefix : "", newblock->name);CHKERRQ(ierr); 656 ierr = SNESSetOptionsPrefix(newblock->snes, prefix);CHKERRQ(ierr); 657 658 if (!next) { 659 mb->blocks = newblock; 660 newblock->previous = PETSC_NULL; 661 } else { 662 while (next->next) { 663 next = next->next; 664 } 665 next->next = newblock; 666 newblock->previous = next; 667 } 668 mb->numBlocks++; 669 PetscFunctionReturn(0); 670 } 671 EXTERN_C_END 672 673 EXTERN_C_BEGIN 674 #undef __FUNCT__ 675 #define __FUNCT__ "SNESMultiblockSetIS_Default" 676 PetscErrorCode SNESMultiblockSetIS_Default(SNES snes, const char name[], IS is) 677 { 678 SNES_Multiblock *mb = (SNES_Multiblock *) snes->data; 679 BlockDesc newblock, next = mb->blocks; 680 char prefix[128]; 681 PetscErrorCode ierr; 682 683 PetscFunctionBegin; 684 if (mb->defined) { 685 ierr = PetscInfo1(snes, "Ignoring new block \"%s\" because the blocks have already been defined\n", name);CHKERRQ(ierr); 686 PetscFunctionReturn(0); 687 } 688 ierr = PetscNew(struct _BlockDesc, &newblock);CHKERRQ(ierr); 689 if (name) { 690 ierr = PetscStrallocpy(name, &newblock->name);CHKERRQ(ierr); 691 } else { 692 PetscInt len = floor(log10(mb->numBlocks))+1; 693 694 ierr = PetscMalloc((len+1)*sizeof(char), &newblock->name);CHKERRQ(ierr); 695 ierr = PetscSNPrintf(newblock->name, len, "%s", mb->numBlocks);CHKERRQ(ierr); 696 } 697 newblock->is = is; 698 ierr = PetscObjectReference((PetscObject) is);CHKERRQ(ierr); 699 newblock->next = PETSC_NULL; 700 ierr = SNESCreate(((PetscObject) snes)->comm, &newblock->snes);CHKERRQ(ierr); 701 ierr = PetscObjectIncrementTabLevel((PetscObject) newblock->snes, (PetscObject) snes, 1);CHKERRQ(ierr); 702 ierr = SNESSetType(newblock->snes, SNESPICARD);CHKERRQ(ierr); 703 ierr = PetscLogObjectParent((PetscObject) snes, (PetscObject) newblock->snes);CHKERRQ(ierr); 704 ierr = PetscSNPrintf(prefix, sizeof prefix, "%smultiblock_%s_", ((PetscObject) snes)->prefix ? ((PetscObject) snes)->prefix : "", newblock->name);CHKERRQ(ierr); 705 ierr = SNESSetOptionsPrefix(newblock->snes, prefix);CHKERRQ(ierr); 706 707 if (!next) { 708 mb->blocks = newblock; 709 newblock->previous = PETSC_NULL; 710 } else { 711 while (next->next) { 712 next = next->next; 713 } 714 next->next = newblock; 715 newblock->previous = next; 716 } 717 mb->numBlocks++; 718 PetscFunctionReturn(0); 719 } 720 EXTERN_C_END 721 722 EXTERN_C_BEGIN 723 #undef __FUNCT__ 724 #define __FUNCT__ "SNESMultiblockSetType_Default" 725 PetscErrorCode SNESMultiblockSetType_Default(SNES snes, PCCompositeType type) 726 { 727 SNES_Multiblock *mb = (SNES_Multiblock *) snes->data; 728 PetscErrorCode ierr; 729 730 PetscFunctionBegin; 731 mb->type = type; 732 if (type == PC_COMPOSITE_SCHUR) { 733 #if 1 734 SETERRQ(((PetscObject) snes)->comm, PETSC_ERR_SUP, "The Schur composite type is not yet supported"); 735 #else 736 snes->ops->solve = SNESApply_Multiblock_Schur; 737 snes->ops->view = SNESView_Multiblock_Schur; 738 ierr = PetscObjectComposeFunctionDynamic((PetscObject) snes, "SNESMultiblockGetSubSNES_C", "SNESMultiblockGetSubSNES_Schur", SNESMultiblockGetSubSNES_Schur);CHKERRQ(ierr); 739 ierr = PetscObjectComposeFunctionDynamic((PetscObject) snes, "SNESMultiblockSchurPrecondition_C", "SNESMultiblockSchurPrecondition_Default", SNESMultiblockSchurPrecondition_Default);CHKERRQ(ierr); 740 #endif 741 } else { 742 snes->ops->solve = SNESApply_Multiblock; 743 snes->ops->view = SNESView_Multiblock; 744 ierr = PetscObjectComposeFunctionDynamic((PetscObject) snes, "SNESMultiblockGetSubSNES_C", "SNESMultiblockGetSubSNES_Default", SNESMultiblockGetSubSNES_Default);CHKERRQ(ierr); 745 ierr = PetscObjectComposeFunctionDynamic((PetscObject) snes, "SNESMultiblockSchurPrecondition_C", "", 0);CHKERRQ(ierr); 746 } 747 PetscFunctionReturn(0); 748 } 749 EXTERN_C_END 750 751 EXTERN_C_BEGIN 752 #undef __FUNCT__ 753 #define __FUNCT__ "SNESMultiblockSetBlockSize_Default" 754 PetscErrorCode SNESMultiblockSetBlockSize_Default(SNES snes, PetscInt bs) 755 { 756 SNES_Multiblock *mb = (SNES_Multiblock *) snes->data; 757 758 PetscFunctionBegin; 759 if (bs < 1) {SETERRQ1(((PetscObject) snes)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Blocksize must be positive, you gave %D", bs);} 760 if (mb->bs > 0 && mb->bs != bs) {SETERRQ2(((PetscObject) snes)->comm, PETSC_ERR_ARG_WRONGSTATE, "Cannot change blocksize from %D to %D after it has been set", mb->bs, bs);} 761 mb->bs = bs; 762 PetscFunctionReturn(0); 763 } 764 EXTERN_C_END 765 766 EXTERN_C_BEGIN 767 #undef __FUNCT__ 768 #define __FUNCT__ "SNESMultiblockGetSubSNES_Default" 769 PetscErrorCode SNESMultiblockGetSubSNES_Default(SNES snes, PetscInt *n, SNES **subsnes) 770 { 771 SNES_Multiblock *mb = (SNES_Multiblock *) snes->data; 772 BlockDesc blocks = mb->blocks; 773 PetscInt cnt = 0; 774 PetscErrorCode ierr; 775 776 PetscFunctionBegin; 777 ierr = PetscMalloc(mb->numBlocks * sizeof(SNES), subsnes);CHKERRQ(ierr); 778 while (blocks) { 779 (*subsnes)[cnt++] = blocks->snes; 780 blocks = blocks->next; 781 } 782 if (cnt != mb->numBlocks) { 783 SETERRQ2(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Corrupt SNESMULTIBLOCK object: number of blocks in linked list %D does not match number in object %D", cnt, mb->numBlocks); 784 } 785 if (n) {*n = mb->numBlocks;} 786 PetscFunctionReturn(0); 787 } 788 EXTERN_C_END 789 790 #undef __FUNCT__ 791 #define __FUNCT__ "SNESMultiblockSetFields" 792 /*@ 793 SNESMultiblockSetFields - Sets the fields for one particular block in the solver 794 795 Logically Collective on SNES 796 797 Input Parameters: 798 + snes - the solver 799 . name - name of this block, if PETSC_NULL the number of the block is used 800 . n - the number of fields in this block 801 - fields - the fields in this block 802 803 Level: intermediate 804 805 Notes: Use SNESMultiblockSetIS() to set a completely general set of row indices as a block. 806 807 The SNESMultiblockSetFields() is for defining blocks as a group of strided indices, or fields. 808 For example, if the vector block size is three then one can define a block as field 0, or 809 1 or 2, or field 0,1 or 0,2 or 1,2 which means 810 0xx3xx6xx9xx12 ... x1xx4xx7xx ... xx2xx5xx8xx.. 01x34x67x... 0x1x3x5x7.. x12x45x78x.... 811 where the numbered entries indicate what is in the block. 812 813 This function is called once per block (it creates a new block each time). Solve options 814 for this block will be available under the prefix -multiblock_BLOCKNAME_. 815 816 .seealso: SNESMultiblockGetSubKSP(), SNESMULTIBLOCK, SNESMultiblockSetBlockSize(), SNESMultiblockSetIS() 817 @*/ 818 PetscErrorCode SNESMultiblockSetFields(SNES snes, const char name[], PetscInt n, const PetscInt *fields) 819 { 820 PetscErrorCode ierr; 821 822 PetscFunctionBegin; 823 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1); 824 PetscValidCharPointer(name, 2); 825 if (n < 1) SETERRQ2(((PetscObject) snes)->comm, PETSC_ERR_ARG_OUTOFRANGE, "Provided number of fields %D in split \"%s\" not positive", n, name); 826 PetscValidIntPointer(fields, 3); 827 ierr = PetscTryMethod(snes, "SNESMultiblockSetFields_C", (SNES, const char[], PetscInt, const PetscInt *), (snes, name, n, fields));CHKERRQ(ierr); 828 PetscFunctionReturn(0); 829 } 830 831 #undef __FUNCT__ 832 #define __FUNCT__ "SNESMultiblockSetIS" 833 /*@ 834 SNESMultiblockSetIS - Sets the global row indices for the block 835 836 Logically Collective on SNES 837 838 Input Parameters: 839 + snes - the solver context 840 . name - name of this block, if PETSC_NULL the number of the block is used 841 - is - the index set that defines the global row indices in this block 842 843 Notes: 844 Use SNESMultiblockSetFields(), for blocks defined by strides. 845 846 This function is called once per block (it creates a new block each time). Solve options 847 for this block will be available under the prefix -multiblock_BLOCKNAME_. 848 849 Level: intermediate 850 851 .seealso: SNESMultiblockGetSubKSP(), SNESMULTIBLOCK, SNESMultiblockSetBlockSize() 852 @*/ 853 PetscErrorCode SNESMultiblockSetIS(SNES snes, const char name[], IS is) 854 { 855 PetscErrorCode ierr; 856 857 PetscFunctionBegin; 858 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1); 859 PetscValidCharPointer(name, 2); 860 PetscValidHeaderSpecific(is, IS_CLASSID, 3); 861 ierr = PetscTryMethod(snes, "SNESMultiblockSetIS_C", (SNES, const char[], IS), (snes, name, is));CHKERRQ(ierr); 862 PetscFunctionReturn(0); 863 } 864 865 #undef __FUNCT__ 866 #define __FUNCT__ "SNESMultiblockSetType" 867 /*@ 868 SNESMultiblockSetType - Sets the type of block combination. 869 870 Collective on SNES 871 872 Input Parameters: 873 + snes - the solver context 874 - type - PC_COMPOSITE_ADDITIVE, PC_COMPOSITE_MULTIPLICATIVE (default), PC_COMPOSITE_SYMMETRIC_MULTIPLICATIVE 875 876 Options Database Key: 877 . -snes_multiblock_type <type: one of multiplicative, additive, symmetric_multiplicative> - Sets block combination type 878 879 Level: Developer 880 881 .keywords: SNES, set, type, composite preconditioner, additive, multiplicative 882 .seealso: PCCompositeSetType() 883 @*/ 884 PetscErrorCode SNESMultiblockSetType(SNES snes, PCCompositeType type) 885 { 886 PetscErrorCode ierr; 887 888 PetscFunctionBegin; 889 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1); 890 ierr = PetscTryMethod(snes, "SNESMultiblockSetType_C", (SNES, PCCompositeType), (snes, type));CHKERRQ(ierr); 891 PetscFunctionReturn(0); 892 } 893 894 #undef __FUNCT__ 895 #define __FUNCT__ "SNESMultiblockSetBlockSize" 896 /*@ 897 SNESMultiblockSetBlockSize - Sets the block size for structured mesh block division. If not set the matrix block size is used. 898 899 Logically Collective on SNES 900 901 Input Parameters: 902 + snes - the solver context 903 - bs - the block size 904 905 Level: intermediate 906 907 .seealso: SNESMultiblockGetSubKSP(), SNESMULTIBLOCK, SNESMultiblockSetFields() 908 @*/ 909 PetscErrorCode SNESMultiblockSetBlockSize(SNES snes, PetscInt bs) 910 { 911 PetscErrorCode ierr; 912 913 PetscFunctionBegin; 914 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1); 915 PetscValidLogicalCollectiveInt(snes, bs, 2); 916 ierr = PetscTryMethod(snes, "SNESMultiblockSetBlockSize_C", (SNES, PetscInt), (snes,bs));CHKERRQ(ierr); 917 PetscFunctionReturn(0); 918 } 919 920 #undef __FUNCT__ 921 #define __FUNCT__ "SNESMultiblockGetSubSNES" 922 /*@C 923 SNESMultiblockGetSubKSP - Gets the SNES contexts for all blocks 924 925 Collective on SNES 926 927 Input Parameter: 928 . snes - the solver context 929 930 Output Parameters: 931 + n - the number of blocks 932 - subsnes - the array of SNES contexts 933 934 Note: 935 After SNESMultiblockGetSubSNES() the array of SNESs MUST be freed by the user 936 (not each SNES, just the array that contains them). 937 938 You must call SNESSetUp() before calling SNESMultiblockGetSubSNES(). 939 940 Level: advanced 941 942 .seealso: SNESMULTIBLOCK 943 @*/ 944 PetscErrorCode SNESMultiblockGetSubSNES(SNES snes, PetscInt *n, SNES *subsnes[]) 945 { 946 PetscErrorCode ierr; 947 948 PetscFunctionBegin; 949 PetscValidHeaderSpecific(snes, SNES_CLASSID, 1); 950 if (n) PetscValidIntPointer(n, 2); 951 ierr = PetscUseMethod(snes, "SNESMultiblockGetSubKSP_C", (SNES, PetscInt*, KSP **), (snes, n, subsnes));CHKERRQ(ierr); 952 PetscFunctionReturn(0); 953 } 954 955 /*MC 956 SNESMULTIBLOCK - Multiblock nonlinear solver that can use overlapping or nonoverlapping blocks, organized 957 additively (Jacobi) or multiplicatively (Gauss-Seidel). 958 959 Level: beginner 960 961 .seealso: SNESCreate(), SNES, SNESSetType(), SNESLS, SNESTR, SNESPICARD 962 M*/ 963 EXTERN_C_BEGIN 964 #undef __FUNCT__ 965 #define __FUNCT__ "SNESCreate_Multiblock" 966 PetscErrorCode SNESCreate_Multiblock(SNES snes) 967 { 968 SNES_Multiblock *mb; 969 PetscErrorCode ierr; 970 971 PetscFunctionBegin; 972 snes->ops->destroy = SNESDestroy_Multiblock; 973 snes->ops->setup = SNESSetUp_Multiblock; 974 snes->ops->setfromoptions = SNESSetFromOptions_Multiblock; 975 snes->ops->view = SNESView_Multiblock; 976 snes->ops->solve = SNESSolve_Multiblock; 977 snes->ops->reset = SNESReset_Multiblock; 978 979 ierr = PetscNewLog(snes, SNES_Multiblock, &mb);CHKERRQ(ierr); 980 snes->data = (void*) mb; 981 mb->defined = PETSC_FALSE; 982 mb->numBlocks = 0; 983 mb->bs = -1; 984 mb->type = PC_COMPOSITE_MULTIPLICATIVE; 985 986 /* We attach functions so that they can be called on another PC without crashing the program */ 987 ierr = PetscObjectComposeFunctionDynamic((PetscObject) snes, "SNESMultiblockSetFields_C", "SNESMultiblockSetFields_Default", SNESMultiblockSetFields_Default);CHKERRQ(ierr); 988 ierr = PetscObjectComposeFunctionDynamic((PetscObject) snes, "SNESMultiblockSetIS_C", "SNESMultiblockSetIS_Default", SNESMultiblockSetIS_Default);CHKERRQ(ierr); 989 ierr = PetscObjectComposeFunctionDynamic((PetscObject) snes, "SNESMultiblockSetType_C", "SNESMultiblockSetType_Default", SNESMultiblockSetType_Default);CHKERRQ(ierr); 990 ierr = PetscObjectComposeFunctionDynamic((PetscObject) snes, "SNESMultiblockSetBlockSize_C", "SNESMultiblockSetBlockSize_Default", SNESMultiblockSetBlockSize_Default);CHKERRQ(ierr); 991 ierr = PetscObjectComposeFunctionDynamic((PetscObject) snes, "SNESMultiblockGetSubSNES_C", "SNESMultiblockGetSubSNES_Default", SNESMultiblockGetSubSNES_Default);CHKERRQ(ierr); 992 PetscFunctionReturn(0); 993 } 994 EXTERN_C_END 995