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