PetscErrorCode DMSetUp_AKKT(DM dm) { DM_AKKT *kkt = (DM_AKKT*)(dm->data); PetscErrorCode ierr; PetscFunctionBegin; if(dm->setupcalled) PetscFunctionReturn(0); if(!kkt->Aff){ if(kkt->dm) { ierr = DMCreateMatrix(kkt->dm, MATAIJ, &kkt->Aff); CHKERRQ(ierr); } else SETERRQ(((PetscObject)dm)->comm, PETSC_ERR_ARG_WRONGSTATE, "Neither matrix nor DM set"); } if(!kkt->isf[0] && !kkt->isf[0]) { if(kkt->detect_saddle_point) { ierr = MatFindZeroDiagonals(kkt->Aff,&kkt->isf[1]);CHKERRQ(ierr); } else if(kkt->dm && kkt->dname) { DM ddm; PetscInt n; char **names; IS *iss; DM *dms; PetscInt i; ierr = DMCreateFieldDecompositionDM(kkt->dm, kkt->dname, &ddm); CHKERRQ(ierr); ierr = DMCreateFieldDecomposition(ddm, &n, &names, &iss, &dms); CHKERRQ(ierr); if(n < 1 || n > 2) SETERRQ2(((PetscObject)dm)->comm, PETSC_ERR_ARG_WRONG, "Number of parts in decomposition %s must be between 1 and 2. Got %D instead",kkt->dname, n); for(i = 0; i < n; ++i) { if(!iss[i] && dms[i]) { const char* label; if(i == 0) label = "primal"; else label = "dual"; SETERRQ1(((PetscObject)dm)->comm, PETSC_ERR_ARG_WRONG, "Decomposition defines %s subDM, but no embedding IS is given", label); } } ierr = DMAKKTSetFieldDecomposition(dm, n, (const char**)names, iss, dms); CHKERRQ(ierr); for(i = 0; i < n; ++i) { ierr = PetscFree(names[i]); CHKERRQ(ierr); ierr = ISDestroy(&(iss[i])); CHKERRQ(ierr); ierr = DMDestroy(&(dms[i])); CHKERRQ(ierr); } } } if(!kkt->isf[0] && !kkt->isf[1]) SETERRQ(((PetscObject)dm)->comm, PETSC_ERR_ARG_WRONGSTATE, "Decomposition ISs not set and could not be derived. "); if(!kkt->isf[0] || !kkt->isf[1]) { PetscInt lstart, lend; ierr = MatGetOwnershipRange(kkt->Aff, &lstart, &lend); CHKERRQ(ierr); if(!kkt->isf[0]) { ierr = ISComplement(kkt->isf[0], lstart, lend, kkt->isf+1); CHKERRQ(ierr); } else { ierr = ISComplement(kkt->isf[1], lstart, lend, kkt->isf+0); CHKERRQ(ierr); } } /* FIX: Should we allow a combination of empty kkt->dmf[0] and non-empty kkt->dmf[1]? */ if(!kkt->dmf[0]) { /* Construct a GAMG proxy to coarsen the primal block. */ Mat A0f0f; IS is00; PetscInt lstart, lend; const char* primal = {"all"}; ierr = DMCreate(((PetscObject)dm)->comm, kkt->dmf+0); CHKERRQ(ierr); ierr = DMSetType(kkt->dmf[0],DMAKKT); CHKERRQ(ierr); ierr = MatGetSubMatrix(kkt->Aff, kkt->isf[0], kkt->isf[0], MAT_INITIAL_MATRIX, &A0f0f); CHKERRQ(ierr); ierr = DMAKKTSetMatrix(kkt->dmf[0], A0f0f); CHKERRQ(ierr); ierr = MatGetOwnershipRange(A0f0f, &lstart, &lend); CHKERRQ(ierr); ierr = ISCreateStride(((PetscObject)A0f0f)->comm, lend-lstart, lstart, 1, &is00); CHKERRQ(ierr); ierr = DMAKKTSetFieldDecomposition(kkt->dmf[0], 1, &primal, &is00, PETSC_NULL); CHKERRQ(ierr); } dm->setupcalled = PETSC_TRUE; PetscFunctionReturn(0); }
static PetscErrorCode SNESMultiblockSetDefaults(SNES snes) { SNES_Multiblock *mb = (SNES_Multiblock *) snes->data; BlockDesc blocks = mb->blocks; PetscInt i; PetscErrorCode ierr; PetscFunctionBegin; if (!blocks) { if (snes->dm) { PetscBool dmcomposite; ierr = PetscObjectTypeCompare((PetscObject) snes->dm, DMCOMPOSITE, &dmcomposite);CHKERRQ(ierr); if (dmcomposite) { PetscInt nDM; IS *fields; ierr = PetscInfo(snes,"Setting up physics based multiblock solver using the embedded DM\n");CHKERRQ(ierr); ierr = DMCompositeGetNumberDM(snes->dm, &nDM);CHKERRQ(ierr); ierr = DMCompositeGetGlobalISs(snes->dm, &fields);CHKERRQ(ierr); for (i = 0; i < nDM; ++i) { char name[8]; ierr = PetscSNPrintf(name, sizeof(name), "%D", i);CHKERRQ(ierr); ierr = SNESMultiblockSetIS(snes, name, fields[i]);CHKERRQ(ierr); ierr = ISDestroy(&fields[i]);CHKERRQ(ierr); } ierr = PetscFree(fields);CHKERRQ(ierr); } } else { PetscBool flg = PETSC_FALSE; PetscBool stokes = PETSC_FALSE; if (mb->bs <= 0) { if (snes->jacobian_pre) { ierr = MatGetBlockSize(snes->jacobian_pre, &mb->bs);CHKERRQ(ierr); } else { mb->bs = 1; } } ierr = PetscOptionsGetBool(((PetscObject) snes)->prefix, "-snes_multiblock_default", &flg, PETSC_NULL);CHKERRQ(ierr); ierr = PetscOptionsGetBool(((PetscObject) snes)->prefix, "-snes_multiblock_detect_saddle_point", &stokes, PETSC_NULL);CHKERRQ(ierr); if (stokes) { IS zerodiags, rest; PetscInt nmin, nmax; ierr = MatGetOwnershipRange(snes->jacobian_pre, &nmin, &nmax);CHKERRQ(ierr); ierr = MatFindZeroDiagonals(snes->jacobian_pre, &zerodiags);CHKERRQ(ierr); ierr = ISComplement(zerodiags, nmin, nmax, &rest);CHKERRQ(ierr); ierr = SNESMultiblockSetIS(snes, "0", rest);CHKERRQ(ierr); ierr = SNESMultiblockSetIS(snes, "1", zerodiags);CHKERRQ(ierr); ierr = ISDestroy(&zerodiags);CHKERRQ(ierr); ierr = ISDestroy(&rest);CHKERRQ(ierr); } else { if (!flg) { /* Allow user to set fields from command line, if bs was known at the time of SNESSetFromOptions_Multiblock() then it is set there. This is not ideal because we should only have options set in XXSetFromOptions(). */ ierr = SNESMultiblockSetFieldsRuntime_Private(snes);CHKERRQ(ierr); if (mb->defined) {ierr = PetscInfo(snes, "Blocks defined using the options database\n");CHKERRQ(ierr);} } if (flg || !mb->defined) { ierr = PetscInfo(snes, "Using default splitting of fields\n");CHKERRQ(ierr); for (i = 0; i < mb->bs; ++i) { char name[8]; ierr = PetscSNPrintf(name, sizeof(name), "%D", i);CHKERRQ(ierr); ierr = SNESMultiblockSetFields(snes, name, 1, &i);CHKERRQ(ierr); } mb->defaultblocks = PETSC_TRUE; } } } } else if (mb->numBlocks == 1) { if (blocks->is) { IS is2; PetscInt nmin, nmax; ierr = MatGetOwnershipRange(snes->jacobian_pre, &nmin, &nmax);CHKERRQ(ierr); ierr = ISComplement(blocks->is, nmin, nmax, &is2);CHKERRQ(ierr); ierr = SNESMultiblockSetIS(snes, "1", is2);CHKERRQ(ierr); ierr = ISDestroy(&is2);CHKERRQ(ierr); } else { SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONGSTATE, "Must provide at least two sets of fields to SNES multiblock"); } } if (mb->numBlocks < 2) SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unhandled case, must have at least two blocks"); PetscFunctionReturn(0); }