Date: 2026-03-31T05:46:27+00:00

Actual source code: ex64.c

      1: static char help[] = "Biot consolidation model discretized with finite elements,\n\
      2: using a parallel unstructured mesh (DMPLEX) to represent the domain.\n\
      3: We follow https://arxiv.org/pdf/1507.03199.\n\n\n";

      5: #include <petscdmplex.h>
      6: #include <petscsnes.h>
      7: #include <petscds.h>

      9: typedef struct {
     10:   PetscScalar mu;
     11:   PetscScalar lam;
     12:   PetscScalar alpha;
     13:   PetscScalar kappa;
     14: } Parameter;

     16: static void u_1(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[])
     17: {
     18:   const PetscReal mu = PetscRealPart(constants[0]);

     20:   for (PetscInt c = 0; c < dim; ++c) {
     21:     for (PetscInt d = 0; d < dim; ++d) f[c * dim + d] = mu * (u_x[c * dim + d] + u_x[d * dim + c]);
     22:     f[c * dim + c] -= u[uOff[1]];
     23:   }
     24: }

     26: /* Jfunction_testtrial */
     27: static void Ju_1_u1p0(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar J[])
     28: {
     29:   for (PetscInt d = 0; d < dim; ++d) J[d * dim + d] = -1.0;
     30: }

     32: static void Ju_1_u1u1(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar J[])
     33: {
     34:   const PetscReal mu = PetscRealPart(constants[0]);
     35:   const PetscInt  Nc = uOff[1] - uOff[0];

     37:   for (PetscInt c = 0; c < Nc; ++c) {
     38:     for (PetscInt d = 0; d < dim; ++d) {
     39:       J[((c * Nc + c) * dim + d) * dim + d] += mu;
     40:       J[((c * Nc + d) * dim + d) * dim + c] += mu;
     41:     }
     42:   }
     43: }

     45: static void p_0(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[])
     46: {
     47:   const PetscReal lam   = PetscRealPart(constants[1]);
     48:   const PetscReal alpha = PetscRealPart(constants[2]);

     50:   f[0] = (-u[uOff[1]] + alpha * u[uOff[2]]) / lam;
     51:   for (PetscInt d = 0; d < dim; ++d) f[0] -= u_x[d * dim + d];
     52: }

     54: static void Jp_0_p0u1(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar J[])
     55: {
     56:   for (PetscInt d = 0; d < dim; ++d) J[d * dim + d] = -1.0;
     57: }

     59: static void Jp_0_p0p0(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar J[])
     60: {
     61:   const PetscReal lam = PetscRealPart(constants[1]);

     63:   J[0] = -1.0 / lam;
     64: }

     66: static void pJp_0_p0p0(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar J[])
     67: {
     68:   const PetscReal mu = PetscRealPart(constants[0]);

     70:   J[0] = 1.0 / mu;
     71: }

     73: static void Jp_0_p0w0(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar J[])
     74: {
     75:   const PetscReal lam   = PetscRealPart(constants[1]);
     76:   const PetscReal alpha = PetscRealPart(constants[2]);

     78:   J[0] = alpha / lam;
     79: }

     81: static void w_0(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[])
     82: {
     83:   const PetscReal lam   = PetscRealPart(constants[1]);
     84:   const PetscReal alpha = PetscRealPart(constants[2]);

     86:   f[0] = alpha / lam * (-2 * alpha * u[uOff[2]] + u[uOff[1]]);
     87: }

     89: static void Jw_0_w0p0(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar J[])
     90: {
     91:   const PetscReal lam   = PetscRealPart(constants[1]);
     92:   const PetscReal alpha = PetscRealPart(constants[2]);

     94:   J[0] = alpha / lam;
     95: }

     97: static void Jw_0_w0w0(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar J[])
     98: {
     99:   const PetscReal lam   = PetscRealPart(constants[1]);
    100:   const PetscReal alpha = PetscRealPart(constants[2]);

    102:   J[0] = -2 * PetscSqr(alpha) / lam;
    103: }

    105: static void pJw_0_w0w0(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar J[])
    106: {
    107:   const PetscReal lam   = PetscRealPart(constants[1]);
    108:   const PetscReal alpha = PetscRealPart(constants[2]);

    110:   J[0] = 2 * PetscSqr(alpha) / lam;
    111: }

    113: static void w_1(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f[])
    114: {
    115:   const PetscReal kappa = PetscRealPart(constants[3]);
    116:   for (PetscInt d = 0; d < dim; ++d) f[d] = -kappa * u_x[uOff_x[2] + d];
    117: }

    119: static void Jw_1_w1w1(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar J[])
    120: {
    121:   const PetscReal kappa = PetscRealPart(constants[3]);

    123:   for (PetscInt d = 0; d < dim; ++d) J[d * dim + d] = -kappa;
    124: }

    126: static void pJw_1_w1w1(PetscInt dim, PetscInt Nf, PetscInt NfAux, const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar J[])
    127: {
    128:   const PetscReal kappa = PetscRealPart(constants[3]);

    130:   for (PetscInt d = 0; d < dim; ++d) J[d * dim + d] = kappa;
    131: }

    133: typedef struct {
    134:   PetscScalar E;
    135:   PetscScalar nu;
    136:   PetscScalar alpha;
    137:   PetscScalar kappa;
    138: } AppCtx;

    140: static PetscErrorCode ProcessOptions(MPI_Comm comm, AppCtx *user)
    141: {
    142:   PetscFunctionBeginUser;
    143:   user->E     = 1.0;
    144:   user->nu    = 0.3;
    145:   user->alpha = 0.5;
    146:   user->kappa = 1.0;
    147:   PetscOptionsBegin(comm, "", "Biot Problem Options", "DMPLEX");
    148:   PetscCall(PetscOptionsScalar("-E", "Young modulus", NULL, user->E, &user->E, NULL));
    149:   PetscCall(PetscOptionsScalar("-nu", "Poisson ratio", NULL, user->nu, &user->nu, NULL));
    150:   PetscCall(PetscOptionsScalar("-alpha", "Alpha", NULL, user->alpha, &user->alpha, NULL));
    151:   PetscCall(PetscOptionsScalar("-kappa", "kappa", NULL, user->kappa, &user->kappa, NULL));
    152:   PetscOptionsEnd();
    153:   PetscFunctionReturn(PETSC_SUCCESS);
    154: }

    156: static PetscErrorCode CreateMesh(MPI_Comm comm, AppCtx *user, DM *dm)
    157: {
    158:   PetscFunctionBeginUser;
    159:   PetscCall(DMCreate(comm, dm));
    160:   PetscCall(DMSetType(*dm, DMPLEX));
    161:   PetscCall(DMSetFromOptions(*dm));
    162:   PetscCall(DMViewFromOptions(*dm, NULL, "-dm_view"));
    163:   PetscFunctionReturn(PETSC_SUCCESS);
    164: }

    166: static PetscErrorCode SetupEqn(DM dm, AppCtx *user)
    167: {
    168:   PetscDS        ds;
    169:   DMLabel        label;
    170:   const PetscInt id = 1;
    171:   PetscScalar    constants[4];

    173:   PetscFunctionBeginUser;
    174:   PetscCall(DMGetDS(dm, &ds));
    175:   PetscCall(PetscDSSetResidual(ds, 0, NULL, u_1));
    176:   PetscCall(PetscDSSetResidual(ds, 1, p_0, NULL));
    177:   PetscCall(PetscDSSetResidual(ds, 2, w_0, w_1));
    178:   PetscCall(PetscDSSetJacobian(ds, 0, 0, NULL, NULL, NULL, Ju_1_u1u1));
    179:   PetscCall(PetscDSSetJacobian(ds, 0, 1, NULL, NULL, Ju_1_u1p0, NULL));
    180:   PetscCall(PetscDSSetJacobian(ds, 1, 0, NULL, Jp_0_p0u1, NULL, NULL));
    181:   PetscCall(PetscDSSetJacobian(ds, 1, 1, Jp_0_p0p0, NULL, NULL, NULL));
    182:   PetscCall(PetscDSSetJacobian(ds, 1, 2, Jp_0_p0w0, NULL, NULL, NULL));
    183:   PetscCall(PetscDSSetJacobian(ds, 2, 1, Jw_0_w0p0, NULL, NULL, NULL));
    184:   PetscCall(PetscDSSetJacobian(ds, 2, 2, Jw_0_w0w0, NULL, NULL, Jw_1_w1w1));
    185:   PetscCall(PetscDSSetJacobianPreconditioner(ds, 0, 0, NULL, NULL, NULL, Ju_1_u1u1));
    186:   PetscCall(PetscDSSetJacobianPreconditioner(ds, 0, 1, NULL, NULL, Ju_1_u1p0, NULL));
    187:   PetscCall(PetscDSSetJacobianPreconditioner(ds, 1, 0, NULL, Jp_0_p0u1, NULL, NULL));
    188:   PetscCall(PetscDSSetJacobianPreconditioner(ds, 1, 1, pJp_0_p0p0, NULL, NULL, NULL));
    189:   PetscCall(PetscDSSetJacobianPreconditioner(ds, 2, 2, pJw_0_w0w0, NULL, NULL, pJw_1_w1w1));

    191:   PetscCall(DMGetLabel(dm, "marker", &label));
    192:   PetscCall(DMAddBoundary(dm, DM_BC_ESSENTIAL, "wall-d", label, 1, &id, 0, 0, NULL, NULL, NULL, NULL, NULL));
    193:   PetscCall(DMAddBoundary(dm, DM_BC_ESSENTIAL, "wall-p", label, 1, &id, 2, 0, NULL, NULL, NULL, NULL, NULL));

    195:   constants[0] = user->E / (2.0 * (1.0 + user->nu));
    196:   constants[1] = user->nu * user->E / ((1.0 + user->nu) * (1.0 - 2.0 * user->nu));
    197:   constants[2] = user->alpha;
    198:   constants[3] = user->kappa;
    199:   PetscCall(PetscDSSetConstants(ds, 4, constants));

    201:   PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "E = %g, nu = %g\n", (double)PetscRealPart(user->E), (double)PetscRealPart(user->nu)));
    202:   PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "mu = %g, lambda = %g\n", (double)PetscRealPart(constants[0]), (double)PetscRealPart(constants[1])));
    203:   PetscCall(PetscPrintf(PetscObjectComm((PetscObject)dm), "alpha = %g, kappa = %g\n", (double)PetscRealPart(constants[2]), (double)PetscRealPart(constants[3])));
    204:   PetscFunctionReturn(PETSC_SUCCESS);
    205: }

    207: static PetscErrorCode SetupProblem(DM dm, PetscErrorCode (*setupEqn)(DM, AppCtx *), AppCtx *user)
    208: {
    209:   DM              cdm = dm;
    210:   PetscQuadrature q   = NULL;
    211:   PetscBool       simplex;
    212:   PetscInt        dim, Nf = 3, f, Nc[3];
    213:   const char     *name[3]   = {"displacement", "totalpressure", "pressure"};
    214:   const char     *prefix[3] = {"displacement_", "totalpressure_", "pressure_"};

    216:   PetscFunctionBegin;
    217:   PetscCall(DMGetDimension(dm, &dim));
    218:   PetscCall(DMPlexIsSimplex(dm, &simplex));
    219:   Nc[0] = dim;
    220:   Nc[1] = 1;
    221:   Nc[2] = 1;
    222:   for (f = 0; f < Nf; ++f) {
    223:     PetscFE fe;

    225:     PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, Nc[f], simplex, prefix[f], -1, &fe));
    226:     PetscCall(PetscObjectSetName((PetscObject)fe, name[f]));
    227:     if (!q) PetscCall(PetscFEGetQuadrature(fe, &q));
    228:     PetscCall(PetscFESetQuadrature(fe, q));
    229:     PetscCall(DMSetField(dm, f, NULL, (PetscObject)fe));
    230:     PetscCall(PetscFEDestroy(&fe));
    231:   }
    232:   PetscCall(DMCreateDS(dm));
    233:   PetscCall((*setupEqn)(dm, user));
    234:   while (cdm) {
    235:     PetscCall(DMCopyDisc(dm, cdm));
    236:     PetscCall(DMGetCoarseDM(cdm, &cdm));
    237:   }
    238:   PetscFunctionReturn(PETSC_SUCCESS);
    239: }

    241: int main(int argc, char **argv)
    242: {
    243:   SNES   snes;
    244:   DM     dm;
    245:   Vec    u;
    246:   AppCtx user;

    248:   PetscFunctionBeginUser;
    249:   PetscCall(PetscInitialize(&argc, &argv, NULL, help));
    250:   PetscCall(ProcessOptions(PETSC_COMM_WORLD, &user));
    251:   PetscCall(CreateMesh(PETSC_COMM_WORLD, &user, &dm));
    252:   PetscCall(SetupProblem(dm, SetupEqn, &user));
    253:   PetscCall(DMPlexCreateClosureIndex(dm, NULL));
    254:   PetscCall(DMPlexSetSNESLocalFEM(dm, PETSC_FALSE, &user));
    255:   PetscCall(DMSetApplicationContext(dm, &user));

    257:   PetscCall(SNESCreate(PetscObjectComm((PetscObject)dm), &snes));
    258:   PetscCall(SNESSetDM(snes, dm));
    259:   PetscCall(SNESSetType(snes, SNESKSPONLY));
    260:   PetscCall(SNESSetFromOptions(snes));

    262:   /* Solve with random rhs */
    263:   PetscCall(DMCreateGlobalVector(dm, &u));
    264:   PetscCall(VecSetRandom(u, NULL));
    265:   PetscCall(SNESSolve(snes, NULL, u));

    267:   PetscCall(VecDestroy(&u));
    268:   PetscCall(SNESDestroy(&snes));
    269:   PetscCall(DMDestroy(&dm));
    270:   PetscCall(PetscFinalize());
    271:   return 0;
    272: }

    274: /*TEST

    276:   test:
    277:     suffix: 2d_p2_p1_p2
    278:     args: -displacement_petscspace_degree 2 -totalpressure_petscspace_degree 1 -pressure_petscspace_degree 2 \
    279:           -dm_plex_box_faces 5,5 -dm_plex_separate_marker -dm_plex_simplex 0 \
    280:           -snes_error_if_not_converged -ksp_error_if_not_converged \
    281:           -ksp_type minres -pc_type fieldsplit -pc_fieldsplit_type additive -fieldsplit_totalpressure_pc_type jacobi -fieldsplit_displacement_pc_type gamg -fieldsplit_pressure_pc_type gamg

    283:   test:
    284:     nsize: 4
    285:     suffix: 2d_p2_p1_p2_fetidp
    286:     args: -displacement_petscspace_degree 2 -totalpressure_petscspace_degree 1 -pressure_petscspace_degree 2 \
    287:           -petscpartitioner_type simple -dm_mat_type is -dm_plex_box_faces 3,3 -dm_refine 2 -dm_plex_separate_marker -dm_plex_simplex 0 \
    288:           -snes_error_if_not_converged -ksp_error_if_not_converged \
    289:           -ksp_type fetidp -ksp_fetidp_saddlepoint -ksp_fetidp_pressure_field 1,2 -ksp_fetidp_pressure_schur -fetidp_ksp_type cg -fetidp_ksp_norm_type natural \
    290:           -fetidp_fieldsplit_lag_ksp_type preonly \
    291:           -fetidp_bddc_pc_bddc_detect_disconnected -fetidp_bddc_pc_bddc_corner_selection -fetidp_bddc_pc_bddc_symmetric -fetidp_bddc_pc_bddc_coarse_redundant_pc_type cholesky \
    292:           -fetidp_pc_discrete_harmonic 1 -fetidp_harmonic_pc_type cholesky \
    293:           -fetidp_fieldsplit_p_pc_type bddc -fetidp_fieldsplit_p_ksp_type preonly

    295: TEST*/