1 static char help[] = "Heat Equation in 2d and 3d with finite elements.\n\ 2 We solve the heat equation in a rectangular\n\ 3 domain, using a parallel unstructured mesh (DMPLEX) to discretize it.\n\ 4 Contributed by: Julian Andrej <juan@tf.uni-kiel.de>\n\n\n"; 5 6 #include <petscdmplex.h> 7 #include <petscds.h> 8 #include <petscts.h> 9 10 /* 11 Heat equation: 12 13 du/dt - \Delta u + f = 0 14 */ 15 16 typedef enum { 17 SOL_QUADRATIC_LINEAR, 18 SOL_QUADRATIC_TRIG, 19 SOL_TRIG_LINEAR, 20 SOL_TRIG_TRIG, 21 NUM_SOLUTION_TYPES 22 } SolutionType; 23 const char *solutionTypes[NUM_SOLUTION_TYPES + 1] = {"quadratic_linear", "quadratic_trig", "trig_linear", "trig_trig", "unknown"}; 24 25 typedef struct { 26 SolutionType solType; /* Type of exact solution */ 27 /* Solver setup */ 28 PetscBool expTS; /* Flag for explicit timestepping */ 29 PetscBool lumped; /* Lump the mass matrix */ 30 PetscInt remesh_every; /* Remesh every number of steps */ 31 DM remesh_dm; /* New DM after remeshing */ 32 } AppCtx; 33 34 /* 35 Exact 2D solution: 36 u = 2t + x^2 + y^2 37 u_t = 2 38 \Delta u = 2 + 2 = 4 39 f = 2 40 F(u) = 2 - (2 + 2) + 2 = 0 41 42 Exact 3D solution: 43 u = 3t + x^2 + y^2 + z^2 44 F(u) = 3 - (2 + 2 + 2) + 3 = 0 45 */ 46 static PetscErrorCode mms_quad_lin(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, PetscCtx ctx) 47 { 48 PetscInt d; 49 50 *u = dim * time; 51 for (d = 0; d < dim; ++d) *u += x[d] * x[d]; 52 return PETSC_SUCCESS; 53 } 54 55 static PetscErrorCode mms_quad_lin_t(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, PetscCtx ctx) 56 { 57 *u = dim; 58 return PETSC_SUCCESS; 59 } 60 61 static void f0_quad_lin_exp(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 f0[]) 62 { 63 f0[0] = -(PetscScalar)dim; 64 } 65 static void f0_quad_lin(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 f0[]) 66 { 67 PetscScalar exp[1] = {0.}; 68 f0_quad_lin_exp(dim, Nf, NfAux, uOff, uOff_x, u, u_t, u_x, aOff, aOff_x, a, a_t, a_x, t, x, numConstants, constants, exp); 69 f0[0] = u_t[0] - exp[0]; 70 } 71 72 /* 73 Exact 2D solution: 74 u = 2*cos(t) + x^2 + y^2 75 F(u) = -2*sint(t) - (2 + 2) + 2*sin(t) + 4 = 0 76 77 Exact 3D solution: 78 u = 3*cos(t) + x^2 + y^2 + z^2 79 F(u) = -3*sin(t) - (2 + 2 + 2) + 3*sin(t) + 6 = 0 80 */ 81 static PetscErrorCode mms_quad_trig(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, PetscCtx ctx) 82 { 83 PetscInt d; 84 85 *u = dim * PetscCosReal(time); 86 for (d = 0; d < dim; ++d) *u += x[d] * x[d]; 87 return PETSC_SUCCESS; 88 } 89 90 static PetscErrorCode mms_quad_trig_t(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, PetscCtx ctx) 91 { 92 *u = -dim * PetscSinReal(time); 93 return PETSC_SUCCESS; 94 } 95 96 static void f0_quad_trig_exp(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 f0[]) 97 { 98 f0[0] = -dim * (PetscSinReal(t) + 2.0); 99 } 100 static void f0_quad_trig(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 f0[]) 101 { 102 PetscScalar exp[1] = {0.}; 103 f0_quad_trig_exp(dim, Nf, NfAux, uOff, uOff_x, u, u_t, u_x, aOff, aOff_x, a, a_t, a_x, t, x, numConstants, constants, exp); 104 f0[0] = u_t[0] - exp[0]; 105 } 106 107 /* 108 Exact 2D solution: 109 u = 2\pi^2 t + cos(\pi x) + cos(\pi y) 110 F(u) = 2\pi^2 - \pi^2 (cos(\pi x) + cos(\pi y)) + \pi^2 (cos(\pi x) + cos(\pi y)) - 2\pi^2 = 0 111 112 Exact 3D solution: 113 u = 3\pi^2 t + cos(\pi x) + cos(\pi y) + cos(\pi z) 114 F(u) = 3\pi^2 - \pi^2 (cos(\pi x) + cos(\pi y) + cos(\pi z)) + \pi^2 (cos(\pi x) + cos(\pi y) + cos(\pi z)) - 3\pi^2 = 0 115 */ 116 static PetscErrorCode mms_trig_lin(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, PetscCtx ctx) 117 { 118 PetscInt d; 119 120 *u = dim * PetscSqr(PETSC_PI) * time; 121 for (d = 0; d < dim; ++d) *u += PetscCosReal(PETSC_PI * x[d]); 122 return PETSC_SUCCESS; 123 } 124 125 static PetscErrorCode mms_trig_lin_t(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, PetscCtx ctx) 126 { 127 *u = dim * PetscSqr(PETSC_PI); 128 return PETSC_SUCCESS; 129 } 130 131 static void f0_trig_lin(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 f0[]) 132 { 133 PetscInt d; 134 f0[0] = u_t[0]; 135 for (d = 0; d < dim; ++d) f0[0] += PetscSqr(PETSC_PI) * (PetscCosReal(PETSC_PI * x[d]) - 1.0); 136 } 137 138 /* 139 Exact 2D solution: 140 u = pi^2 cos(t) + cos(\pi x) + cos(\pi y) 141 u_t = -pi^2 sin(t) 142 \Delta u = -\pi^2 (cos(\pi x) + cos(\pi y)) 143 f = pi^2 sin(t) - \pi^2 (cos(\pi x) + cos(\pi y)) 144 F(u) = -\pi^2 sin(t) + \pi^2 (cos(\pi x) + cos(\pi y)) - \pi^2 (cos(\pi x) + cos(\pi y)) + \pi^2 sin(t) = 0 145 146 Exact 3D solution: 147 u = pi^2 cos(t) + cos(\pi x) + cos(\pi y) + cos(\pi z) 148 u_t = -pi^2 sin(t) 149 \Delta u = -\pi^2 (cos(\pi x) + cos(\pi y) + cos(\pi z)) 150 f = pi^2 sin(t) - \pi^2 (cos(\pi x) + cos(\pi y) + cos(\pi z)) 151 F(u) = -\pi^2 sin(t) + \pi^2 (cos(\pi x) + cos(\pi y) + cos(\pi z)) - \pi^2 (cos(\pi x) + cos(\pi y) + cos(\pi z)) + \pi^2 sin(t) = 0 152 */ 153 static PetscErrorCode mms_trig_trig(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, PetscCtx ctx) 154 { 155 PetscInt d; 156 157 *u = PetscSqr(PETSC_PI) * PetscCosReal(time); 158 for (d = 0; d < dim; ++d) *u += PetscCosReal(PETSC_PI * x[d]); 159 return PETSC_SUCCESS; 160 } 161 162 static PetscErrorCode mms_trig_trig_t(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, PetscCtx ctx) 163 { 164 *u = -PetscSqr(PETSC_PI) * PetscSinReal(time); 165 return PETSC_SUCCESS; 166 } 167 168 static void f0_trig_trig_exp(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 f0[]) 169 { 170 PetscInt d; 171 f0[0] -= PetscSqr(PETSC_PI) * PetscSinReal(t); 172 for (d = 0; d < dim; ++d) f0[0] += PetscSqr(PETSC_PI) * PetscCosReal(PETSC_PI * x[d]); 173 } 174 static void f0_trig_trig(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 f0[]) 175 { 176 PetscScalar exp[1] = {0.}; 177 f0_trig_trig_exp(dim, Nf, NfAux, uOff, uOff_x, u, u_t, u_x, aOff, aOff_x, a, a_t, a_x, t, x, numConstants, constants, exp); 178 f0[0] = u_t[0] - exp[0]; 179 } 180 181 static void f1_temp_exp(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 f1[]) 182 { 183 for (PetscInt d = 0; d < dim; ++d) f1[d] = -u_x[d]; 184 } 185 static void f1_temp(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 f1[]) 186 { 187 for (PetscInt d = 0; d < dim; ++d) f1[d] = u_x[d]; 188 } 189 190 static void g3_temp(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 g3[]) 191 { 192 for (PetscInt d = 0; d < dim; ++d) g3[d * dim + d] = 1.0; 193 } 194 195 static void g0_temp(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 g0[]) 196 { 197 g0[0] = u_tShift * 1.0; 198 } 199 200 static PetscErrorCode ProcessOptions(MPI_Comm comm, AppCtx *options) 201 { 202 PetscInt sol; 203 204 PetscFunctionBeginUser; 205 options->solType = SOL_QUADRATIC_LINEAR; 206 options->expTS = PETSC_FALSE; 207 options->lumped = PETSC_TRUE; 208 options->remesh_every = 0; 209 210 PetscOptionsBegin(comm, "", "Heat Equation Options", "DMPLEX"); 211 sol = options->solType; 212 PetscCall(PetscOptionsEList("-sol_type", "Type of exact solution", "ex45.c", solutionTypes, NUM_SOLUTION_TYPES, solutionTypes[options->solType], &sol, NULL)); 213 options->solType = (SolutionType)sol; 214 PetscCall(PetscOptionsBool("-explicit", "Use explicit timestepping", "ex45.c", options->expTS, &options->expTS, NULL)); 215 PetscCall(PetscOptionsBool("-lumped", "Lump the mass matrix", "ex45.c", options->lumped, &options->lumped, NULL)); 216 PetscCall(PetscOptionsInt("-remesh_every", "Remesh every number of steps", "ex45.c", options->remesh_every, &options->remesh_every, NULL)); 217 PetscOptionsEnd(); 218 PetscFunctionReturn(PETSC_SUCCESS); 219 } 220 221 static PetscErrorCode CreateMesh(MPI_Comm comm, DM *dm, AppCtx *ctx) 222 { 223 PetscFunctionBeginUser; 224 PetscCall(DMCreate(comm, dm)); 225 PetscCall(DMSetType(*dm, DMPLEX)); 226 PetscCall(DMSetFromOptions(*dm)); 227 { 228 char convType[256]; 229 PetscBool flg; 230 PetscOptionsBegin(comm, "", "Mesh conversion options", "DMPLEX"); 231 PetscCall(PetscOptionsFList("-dm_plex_convert_type", "Convert DMPlex to another format", __FILE__, DMList, DMPLEX, convType, 256, &flg)); 232 PetscOptionsEnd(); 233 if (flg) { 234 DM dmConv; 235 PetscCall(DMConvert(*dm, convType, &dmConv)); 236 if (dmConv) { 237 PetscCall(DMDestroy(dm)); 238 *dm = dmConv; 239 PetscCall(DMSetFromOptions(*dm)); 240 PetscCall(DMSetUp(*dm)); 241 } 242 } 243 } 244 PetscCall(DMViewFromOptions(*dm, NULL, "-dm_view")); 245 PetscFunctionReturn(PETSC_SUCCESS); 246 } 247 248 static PetscErrorCode SetupProblem(DM dm, AppCtx *ctx) 249 { 250 PetscDS ds; 251 DMLabel label; 252 const PetscInt id = 1; 253 254 PetscFunctionBeginUser; 255 PetscCall(DMGetLabel(dm, "marker", &label)); 256 PetscCall(DMGetDS(dm, &ds)); 257 PetscCall(PetscDSSetJacobian(ds, 0, 0, g0_temp, NULL, NULL, g3_temp)); 258 switch (ctx->solType) { 259 case SOL_QUADRATIC_LINEAR: 260 PetscCall(PetscDSSetResidual(ds, 0, f0_quad_lin, f1_temp)); 261 PetscCall(PetscDSSetRHSResidual(ds, 0, f0_quad_lin_exp, f1_temp_exp)); 262 PetscCall(PetscDSSetExactSolution(ds, 0, mms_quad_lin, ctx)); 263 PetscCall(PetscDSSetExactSolutionTimeDerivative(ds, 0, mms_quad_lin_t, ctx)); 264 PetscCall(DMAddBoundary(dm, DM_BC_ESSENTIAL, "wall", label, 1, &id, 0, 0, NULL, (PetscVoidFn *)mms_quad_lin, (PetscVoidFn *)mms_quad_lin_t, ctx, NULL)); 265 break; 266 case SOL_QUADRATIC_TRIG: 267 PetscCall(PetscDSSetResidual(ds, 0, f0_quad_trig, f1_temp)); 268 PetscCall(PetscDSSetRHSResidual(ds, 0, f0_quad_trig_exp, f1_temp_exp)); 269 PetscCall(PetscDSSetExactSolution(ds, 0, mms_quad_trig, ctx)); 270 PetscCall(PetscDSSetExactSolutionTimeDerivative(ds, 0, mms_quad_trig_t, ctx)); 271 PetscCall(DMAddBoundary(dm, DM_BC_ESSENTIAL, "wall", label, 1, &id, 0, 0, NULL, (PetscVoidFn *)mms_quad_trig, (PetscVoidFn *)mms_quad_trig_t, ctx, NULL)); 272 break; 273 case SOL_TRIG_LINEAR: 274 PetscCall(PetscDSSetResidual(ds, 0, f0_trig_lin, f1_temp)); 275 PetscCall(PetscDSSetExactSolution(ds, 0, mms_trig_lin, ctx)); 276 PetscCall(PetscDSSetExactSolutionTimeDerivative(ds, 0, mms_trig_lin_t, ctx)); 277 PetscCall(DMAddBoundary(dm, DM_BC_ESSENTIAL, "wall", label, 1, &id, 0, 0, NULL, (PetscVoidFn *)mms_trig_lin, (PetscVoidFn *)mms_trig_lin_t, ctx, NULL)); 278 break; 279 case SOL_TRIG_TRIG: 280 PetscCall(PetscDSSetResidual(ds, 0, f0_trig_trig, f1_temp)); 281 PetscCall(PetscDSSetRHSResidual(ds, 0, f0_trig_trig_exp, f1_temp_exp)); 282 PetscCall(PetscDSSetExactSolution(ds, 0, mms_trig_trig, ctx)); 283 PetscCall(PetscDSSetExactSolutionTimeDerivative(ds, 0, mms_trig_trig_t, ctx)); 284 break; 285 default: 286 SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Invalid solution type: %s (%d)", solutionTypes[PetscMin(ctx->solType, NUM_SOLUTION_TYPES)], ctx->solType); 287 } 288 PetscFunctionReturn(PETSC_SUCCESS); 289 } 290 291 static PetscErrorCode SetupDiscretization(DM dm, AppCtx *ctx) 292 { 293 DM plex, cdm = dm; 294 PetscFE fe; 295 PetscBool simplex; 296 PetscInt dim; 297 298 PetscFunctionBeginUser; 299 PetscCall(DMGetDimension(dm, &dim)); 300 PetscCall(DMConvert(dm, DMPLEX, &plex)); 301 PetscCall(DMPlexIsSimplex(plex, &simplex)); 302 PetscCall(DMDestroy(&plex)); 303 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, 1, simplex, "temp_", -1, &fe)); 304 PetscCall(PetscObjectSetName((PetscObject)fe, "temperature")); 305 /* Set discretization and boundary conditions for each mesh */ 306 PetscCall(DMSetField(dm, 0, NULL, (PetscObject)fe)); 307 PetscCall(DMCreateDS(dm)); 308 if (ctx->expTS) { 309 PetscDS ds; 310 311 PetscCall(DMGetDS(dm, &ds)); 312 PetscCall(PetscDSSetImplicit(ds, 0, PETSC_FALSE)); 313 } 314 PetscCall(SetupProblem(dm, ctx)); 315 while (cdm) { 316 PetscCall(DMCopyDisc(dm, cdm)); 317 PetscCall(DMGetCoarseDM(cdm, &cdm)); 318 } 319 PetscCall(PetscFEDestroy(&fe)); 320 PetscFunctionReturn(PETSC_SUCCESS); 321 } 322 323 #include <petsc/private/dmpleximpl.h> 324 static PetscErrorCode Remesh(DM dm, Vec U, DM *newdm) 325 { 326 PetscFunctionBeginUser; 327 PetscCall(DMViewFromOptions(dm, NULL, "-remesh_dmin_view")); 328 *newdm = NULL; 329 330 PetscInt dim; 331 DM plex; 332 PetscBool simplex; 333 PetscCall(DMGetDimension(dm, &dim)); 334 PetscCall(DMConvert(dm, DMPLEX, &plex)); 335 PetscCall(DMPlexIsSimplex(plex, &simplex)); 336 PetscCall(DMDestroy(&plex)); 337 338 DM dmGrad; 339 PetscFE fe; 340 PetscCall(DMClone(dm, &dmGrad)); 341 PetscCall(PetscFECreateDefault(PETSC_COMM_SELF, dim, dim, simplex, "grad_", -1, &fe)); 342 PetscCall(DMSetField(dmGrad, 0, NULL, (PetscObject)fe)); 343 PetscCall(PetscFEDestroy(&fe)); 344 PetscCall(DMCreateDS(dmGrad)); 345 346 Vec locU, locG; 347 PetscCall(DMGetLocalVector(dm, &locU)); 348 PetscCall(DMGetLocalVector(dmGrad, &locG)); 349 PetscCall(DMGlobalToLocal(dm, U, INSERT_VALUES, locU)); 350 PetscCall(VecViewFromOptions(locU, NULL, "-remesh_input_view")); 351 PetscCall(DMPlexComputeGradientClementInterpolant(dm, locU, locG)); 352 PetscCall(VecViewFromOptions(locG, NULL, "-remesh_grad_view")); 353 354 const PetscScalar *g; 355 PetscScalar *u; 356 PetscInt n; 357 PetscCall(VecGetLocalSize(locU, &n)); 358 PetscCall(VecGetArrayWrite(locU, &u)); 359 PetscCall(VecGetArrayRead(locG, &g)); 360 for (PetscInt i = 0; i < n; i++) { 361 PetscReal norm = 0.0; 362 for (PetscInt d = 0; d < dim; d++) norm += PetscSqr(PetscRealPart(g[dim * i + d])); 363 u[i] = PetscSqrtReal(norm); 364 } 365 PetscCall(VecRestoreArrayRead(locG, &g)); 366 PetscCall(VecRestoreArrayWrite(locU, &u)); 367 368 DM dmM; 369 Vec metric; 370 PetscCall(DMClone(dm, &dmM)); 371 PetscCall(DMPlexMetricCreateIsotropic(dmM, 0, locU, &metric)); 372 PetscCall(DMDestroy(&dmM)); 373 PetscCall(DMRestoreLocalVector(dm, &locU)); 374 PetscCall(DMRestoreLocalVector(dmGrad, &locG)); 375 PetscCall(DMDestroy(&dmGrad)); 376 377 // TODO remove? 378 PetscScalar scale = 10.0; 379 PetscCall(PetscOptionsGetScalar(NULL, NULL, "-metric_scale", &scale, NULL)); 380 PetscCall(VecScale(metric, scale)); 381 PetscCall(VecViewFromOptions(metric, NULL, "-metric_view")); 382 383 DMLabel label = NULL; 384 PetscCall(DMGetLabel(dm, "marker", &label)); 385 PetscCall(DMAdaptMetric(dm, metric, label, NULL, newdm)); 386 PetscCall(VecDestroy(&metric)); 387 388 PetscCall(DMViewFromOptions(*newdm, NULL, "-remesh_dmout_view")); 389 390 AppCtx *ctx; 391 PetscCall(DMGetApplicationContext(dm, &ctx)); 392 PetscCall(DMSetApplicationContext(*newdm, ctx)); 393 PetscCall(SetupDiscretization(*newdm, ctx)); 394 395 // TODO 396 ((DM_Plex *)(*newdm)->data)->useHashLocation = ((DM_Plex *)dm->data)->useHashLocation; 397 PetscFunctionReturn(PETSC_SUCCESS); 398 } 399 400 static PetscErrorCode SetInitialConditions(TS ts, Vec u) 401 { 402 DM dm; 403 PetscReal t; 404 405 PetscFunctionBeginUser; 406 PetscCall(TSGetDM(ts, &dm)); 407 PetscCall(TSGetTime(ts, &t)); 408 PetscCall(DMComputeExactSolution(dm, t, u, NULL)); 409 PetscCall(VecSetOptionsPrefix(u, NULL)); 410 PetscFunctionReturn(PETSC_SUCCESS); 411 } 412 413 static PetscErrorCode TransferSetUp(TS ts, PetscInt step, PetscReal time, Vec U, PetscBool *remesh, void *tctx) 414 { 415 AppCtx *ctx = (AppCtx *)tctx; 416 417 PetscFunctionBeginUser; 418 *remesh = PETSC_FALSE; 419 if (ctx->remesh_every > 0 && step && step % ctx->remesh_every == 0) { 420 DM dm; 421 422 *remesh = PETSC_TRUE; 423 PetscCall(TSGetDM(ts, &dm)); 424 PetscCall(Remesh(dm, U, &ctx->remesh_dm)); 425 } 426 PetscFunctionReturn(PETSC_SUCCESS); 427 } 428 429 static PetscErrorCode TransferVecs(TS ts, PetscInt nv, Vec vin[], Vec vout[], void *tctx) 430 { 431 AppCtx *ctx = (AppCtx *)tctx; 432 DM dm; 433 Mat Interp; 434 435 PetscFunctionBeginUser; 436 PetscCall(TSGetDM(ts, &dm)); 437 PetscCall(DMCreateInterpolation(dm, ctx->remesh_dm, &Interp, NULL)); 438 for (PetscInt i = 0; i < nv; i++) { 439 PetscCall(DMCreateGlobalVector(ctx->remesh_dm, &vout[i])); 440 PetscCall(MatMult(Interp, vin[i], vout[i])); 441 } 442 PetscCall(MatDestroy(&Interp)); 443 PetscCall(TSSetDM(ts, ctx->remesh_dm)); 444 PetscCall(DMDestroy(&ctx->remesh_dm)); 445 PetscFunctionReturn(PETSC_SUCCESS); 446 } 447 448 int main(int argc, char **argv) 449 { 450 DM dm; 451 TS ts; 452 Vec u; 453 AppCtx ctx; 454 455 PetscFunctionBeginUser; 456 PetscCall(PetscInitialize(&argc, &argv, NULL, help)); 457 PetscCall(ProcessOptions(PETSC_COMM_WORLD, &ctx)); 458 PetscCall(CreateMesh(PETSC_COMM_WORLD, &dm, &ctx)); 459 PetscCall(DMSetApplicationContext(dm, &ctx)); 460 PetscCall(SetupDiscretization(dm, &ctx)); 461 462 PetscCall(TSCreate(PETSC_COMM_WORLD, &ts)); 463 PetscCall(TSSetDM(ts, dm)); 464 PetscCall(DMTSSetBoundaryLocal(dm, DMPlexTSComputeBoundary, &ctx)); 465 if (ctx.expTS) { 466 PetscCall(DMTSSetRHSFunctionLocal(dm, DMPlexTSComputeRHSFunctionFEM, &ctx)); 467 if (ctx.lumped) PetscCall(DMTSCreateRHSMassMatrixLumped(dm)); 468 else PetscCall(DMTSCreateRHSMassMatrix(dm)); 469 } else { 470 PetscCall(DMTSSetIFunctionLocal(dm, DMPlexTSComputeIFunctionFEM, &ctx)); 471 PetscCall(DMTSSetIJacobianLocal(dm, DMPlexTSComputeIJacobianFEM, &ctx)); 472 } 473 PetscCall(TSSetMaxTime(ts, 1.0)); 474 PetscCall(TSSetExactFinalTime(ts, TS_EXACTFINALTIME_MATCHSTEP)); 475 PetscCall(TSSetFromOptions(ts)); 476 PetscCall(TSSetComputeInitialCondition(ts, SetInitialConditions)); 477 PetscCall(TSSetResize(ts, PETSC_FALSE, TransferSetUp, TransferVecs, &ctx)); 478 479 PetscCall(DMCreateGlobalVector(dm, &u)); 480 PetscCall(DMTSCheckFromOptions(ts, u)); 481 PetscCall(SetInitialConditions(ts, u)); 482 PetscCall(PetscObjectSetName((PetscObject)u, "temperature")); 483 484 PetscCall(TSSetSolution(ts, u)); 485 PetscCall(VecViewFromOptions(u, NULL, "-u0_view")); 486 PetscCall(VecDestroy(&u)); 487 PetscCall(TSSolve(ts, NULL)); 488 489 PetscCall(TSGetSolution(ts, &u)); 490 PetscCall(VecViewFromOptions(u, NULL, "-uf_view")); 491 PetscCall(DMTSCheckFromOptions(ts, u)); 492 if (ctx.expTS) PetscCall(DMTSDestroyRHSMassMatrix(dm)); 493 494 PetscCall(TSDestroy(&ts)); 495 PetscCall(DMDestroy(&dm)); 496 PetscCall(PetscFinalize()); 497 return 0; 498 } 499 500 /*TEST 501 502 test: 503 suffix: 2d_p1 504 requires: triangle 505 args: -sol_type quadratic_linear -dm_refine 1 -temp_petscspace_degree 1 -dmts_check .0001 \ 506 -ts_type beuler -ts_max_steps 5 -ts_time_step 0.1 -snes_error_if_not_converged -pc_type lu 507 test: 508 suffix: 2d_p1_exp 509 requires: triangle 510 args: -sol_type quadratic_linear -dm_refine 1 -temp_petscspace_degree 1 -explicit \ 511 -ts_type euler -ts_max_steps 4 -ts_time_step 1e-3 -ts_monitor_error 512 test: 513 # -dm_refine 2 -convest_num_refine 3 get L_2 convergence rate: [1.9] 514 suffix: 2d_p1_sconv 515 requires: triangle 516 args: -sol_type quadratic_linear -temp_petscspace_degree 1 -ts_convergence_estimate -ts_convergence_temporal 0 -convest_num_refine 1 \ 517 -ts_type beuler -ts_max_steps 1 -ts_time_step 0.00001 -snes_error_if_not_converged -pc_type lu 518 test: 519 # -dm_refine 2 -convest_num_refine 3 get L_2 convergence rate: [2.1] 520 suffix: 2d_p1_sconv_2 521 requires: triangle 522 args: -sol_type trig_trig -temp_petscspace_degree 1 -ts_convergence_estimate -ts_convergence_temporal 0 -convest_num_refine 1 \ 523 -ts_type beuler -ts_max_steps 1 -ts_time_step 1e-6 -snes_error_if_not_converged -pc_type lu 524 test: 525 # -dm_refine 4 -convest_num_refine 3 get L_2 convergence rate: [1.2] 526 suffix: 2d_p1_tconv 527 requires: triangle 528 args: -sol_type quadratic_trig -temp_petscspace_degree 1 -ts_convergence_estimate -convest_num_refine 1 \ 529 -ts_type beuler -ts_max_steps 4 -ts_time_step 0.1 -snes_error_if_not_converged -pc_type lu 530 test: 531 # -dm_refine 6 -convest_num_refine 3 get L_2 convergence rate: [1.0] 532 suffix: 2d_p1_tconv_2 533 requires: triangle 534 args: -sol_type trig_trig -temp_petscspace_degree 1 -ts_convergence_estimate -convest_num_refine 1 \ 535 -ts_type beuler -ts_max_steps 4 -ts_time_step 0.1 -snes_error_if_not_converged -pc_type lu 536 test: 537 # The L_2 convergence rate cannot be seen since stability of the explicit integrator requires that is be more accurate than the grid 538 suffix: 2d_p1_exp_tconv_2 539 requires: triangle 540 args: -sol_type trig_trig -temp_petscspace_degree 1 -explicit -ts_convergence_estimate -convest_num_refine 1 \ 541 -ts_type euler -ts_max_steps 4 -ts_time_step 1e-4 -lumped 0 -mass_pc_type lu 542 test: 543 # The L_2 convergence rate cannot be seen since stability of the explicit integrator requires that is be more accurate than the grid 544 suffix: 2d_p1_exp_tconv_2_lump 545 requires: triangle 546 args: -sol_type trig_trig -temp_petscspace_degree 1 -explicit -ts_convergence_estimate -convest_num_refine 1 \ 547 -ts_type euler -ts_max_steps 4 -ts_time_step 1e-4 548 test: 549 suffix: 2d_p2 550 requires: triangle 551 args: -sol_type quadratic_linear -dm_refine 0 -temp_petscspace_degree 2 -dmts_check .0001 \ 552 -ts_type beuler -ts_max_steps 5 -ts_time_step 0.1 -snes_error_if_not_converged -pc_type lu 553 test: 554 # -dm_refine 2 -convest_num_refine 3 get L_2 convergence rate: [2.9] 555 suffix: 2d_p2_sconv 556 requires: triangle 557 args: -sol_type trig_linear -temp_petscspace_degree 2 -ts_convergence_estimate -ts_convergence_temporal 0 -convest_num_refine 1 \ 558 -ts_type beuler -ts_max_steps 1 -ts_time_step 0.00000001 -snes_error_if_not_converged -pc_type lu 559 test: 560 # -dm_refine 2 -convest_num_refine 3 get L_2 convergence rate: [3.1] 561 suffix: 2d_p2_sconv_2 562 requires: triangle 563 args: -sol_type trig_trig -temp_petscspace_degree 2 -ts_convergence_estimate -ts_convergence_temporal 0 -convest_num_refine 1 \ 564 -ts_type beuler -ts_max_steps 1 -ts_time_step 0.00000001 -snes_error_if_not_converged -pc_type lu 565 test: 566 # -dm_refine 3 -convest_num_refine 3 get L_2 convergence rate: [1.0] 567 suffix: 2d_p2_tconv 568 requires: triangle 569 args: -sol_type quadratic_trig -temp_petscspace_degree 2 -ts_convergence_estimate -convest_num_refine 1 \ 570 -ts_type beuler -ts_max_steps 4 -ts_time_step 0.1 -snes_error_if_not_converged -pc_type lu 571 test: 572 # -dm_refine 3 -convest_num_refine 3 get L_2 convergence rate: [1.0] 573 suffix: 2d_p2_tconv_2 574 requires: triangle 575 args: -sol_type trig_trig -temp_petscspace_degree 2 -ts_convergence_estimate -convest_num_refine 1 \ 576 -ts_type beuler -ts_max_steps 4 -ts_time_step 0.1 -snes_error_if_not_converged -pc_type lu 577 test: 578 suffix: 2d_q1 579 args: -sol_type quadratic_linear -dm_plex_simplex 0 -dm_refine 1 -temp_petscspace_degree 1 -dmts_check .0001 \ 580 -ts_type beuler -ts_max_steps 5 -ts_time_step 0.1 -snes_error_if_not_converged -pc_type lu 581 test: 582 # -dm_refine 2 -convest_num_refine 3 get L_2 convergence rate: [1.9] 583 suffix: 2d_q1_sconv 584 args: -sol_type quadratic_linear -dm_plex_simplex 0 -temp_petscspace_degree 1 -ts_convergence_estimate -ts_convergence_temporal 0 -convest_num_refine 1 \ 585 -ts_type beuler -ts_max_steps 1 -ts_time_step 0.00001 -snes_error_if_not_converged -pc_type lu 586 test: 587 # -dm_refine 4 -convest_num_refine 3 get L_2 convergence rate: [1.2] 588 suffix: 2d_q1_tconv 589 args: -sol_type quadratic_trig -dm_plex_simplex 0 -temp_petscspace_degree 1 -ts_convergence_estimate -convest_num_refine 1 \ 590 -ts_type beuler -ts_max_steps 4 -ts_time_step 0.1 -snes_error_if_not_converged -pc_type lu 591 test: 592 suffix: 2d_q2 593 args: -sol_type quadratic_linear -dm_plex_simplex 0 -dm_refine 0 -temp_petscspace_degree 2 -dmts_check .0001 \ 594 -ts_type beuler -ts_max_steps 5 -ts_time_step 0.1 -snes_error_if_not_converged -pc_type lu 595 test: 596 # -dm_refine 2 -convest_num_refine 3 get L_2 convergence rate: [2.9] 597 suffix: 2d_q2_sconv 598 args: -sol_type trig_linear -dm_plex_simplex 0 -temp_petscspace_degree 2 -ts_convergence_estimate -ts_convergence_temporal 0 -convest_num_refine 1 \ 599 -ts_type beuler -ts_max_steps 1 -ts_time_step 0.00000001 -snes_error_if_not_converged -pc_type lu 600 test: 601 # -dm_refine 3 -convest_num_refine 3 get L_2 convergence rate: [1.0] 602 suffix: 2d_q2_tconv 603 args: -sol_type quadratic_trig -dm_plex_simplex 0 -temp_petscspace_degree 2 -ts_convergence_estimate -convest_num_refine 1 \ 604 -ts_type beuler -ts_max_steps 4 -ts_time_step 0.1 -snes_error_if_not_converged -pc_type lu 605 606 test: 607 suffix: 3d_p1 608 requires: ctetgen 609 args: -sol_type quadratic_linear -dm_refine 1 -temp_petscspace_degree 1 -dmts_check .0001 \ 610 -ts_type beuler -ts_max_steps 5 -ts_time_step 0.1 -snes_error_if_not_converged -pc_type lu 611 test: 612 # -dm_refine 2 -convest_num_refine 3 get L_2 convergence rate: [1.9] 613 suffix: 3d_p1_sconv 614 requires: ctetgen 615 args: -sol_type quadratic_linear -temp_petscspace_degree 1 -ts_convergence_estimate -ts_convergence_temporal 0 -convest_num_refine 1 \ 616 -ts_type beuler -ts_max_steps 1 -ts_time_step 0.00001 -snes_error_if_not_converged -pc_type lu 617 test: 618 # -dm_refine 4 -convest_num_refine 3 get L_2 convergence rate: [1.2] 619 suffix: 3d_p1_tconv 620 requires: ctetgen 621 args: -sol_type quadratic_trig -temp_petscspace_degree 1 -ts_convergence_estimate -convest_num_refine 1 \ 622 -ts_type beuler -ts_max_steps 4 -ts_time_step 0.1 -snes_error_if_not_converged -pc_type lu 623 test: 624 suffix: 3d_p2 625 requires: ctetgen 626 args: -sol_type quadratic_linear -dm_refine 0 -temp_petscspace_degree 2 -dmts_check .0001 \ 627 -ts_type beuler -ts_max_steps 5 -ts_time_step 0.1 -snes_error_if_not_converged -pc_type lu 628 test: 629 # -dm_refine 2 -convest_num_refine 3 get L_2 convergence rate: [2.9] 630 suffix: 3d_p2_sconv 631 requires: ctetgen 632 args: -sol_type trig_linear -temp_petscspace_degree 2 -ts_convergence_estimate -ts_convergence_temporal 0 -convest_num_refine 1 \ 633 -ts_type beuler -ts_max_steps 1 -ts_time_step 0.00000001 -snes_error_if_not_converged -pc_type lu 634 test: 635 # -dm_refine 3 -convest_num_refine 3 get L_2 convergence rate: [1.0] 636 suffix: 3d_p2_tconv 637 requires: ctetgen 638 args: -sol_type quadratic_trig -temp_petscspace_degree 2 -ts_convergence_estimate -convest_num_refine 1 \ 639 -ts_type beuler -ts_max_steps 4 -ts_time_step 0.1 -snes_error_if_not_converged -pc_type lu 640 test: 641 suffix: 3d_q1 642 args: -sol_type quadratic_linear -dm_plex_simplex 0 -dm_refine 1 -temp_petscspace_degree 1 -dmts_check .0001 \ 643 -ts_type beuler -ts_max_steps 5 -ts_time_step 0.1 -snes_error_if_not_converged -pc_type lu 644 test: 645 # -dm_refine 2 -convest_num_refine 3 get L_2 convergence rate: [1.9] 646 suffix: 3d_q1_sconv 647 args: -sol_type quadratic_linear -dm_plex_simplex 0 -temp_petscspace_degree 1 -ts_convergence_estimate -ts_convergence_temporal 0 -convest_num_refine 1 \ 648 -ts_type beuler -ts_max_steps 1 -ts_time_step 0.00001 -snes_error_if_not_converged -pc_type lu 649 test: 650 # -dm_refine 4 -convest_num_refine 3 get L_2 convergence rate: [1.2] 651 suffix: 3d_q1_tconv 652 args: -sol_type quadratic_trig -dm_plex_simplex 0 -temp_petscspace_degree 1 -ts_convergence_estimate -convest_num_refine 1 \ 653 -ts_type beuler -ts_max_steps 4 -ts_time_step 0.1 -snes_error_if_not_converged -pc_type lu 654 test: 655 suffix: 3d_q2 656 args: -sol_type quadratic_linear -dm_plex_simplex 0 -dm_refine 0 -temp_petscspace_degree 2 -dmts_check .0001 \ 657 -ts_type beuler -ts_max_steps 5 -ts_time_step 0.1 -snes_error_if_not_converged -pc_type lu 658 test: 659 # -dm_refine 2 -convest_num_refine 3 get L_2 convergence rate: [2.9] 660 suffix: 3d_q2_sconv 661 args: -sol_type trig_linear -dm_plex_simplex 0 -temp_petscspace_degree 2 -ts_convergence_estimate -ts_convergence_temporal 0 -convest_num_refine 1 \ 662 -ts_type beuler -ts_max_steps 1 -ts_time_step 0.00000001 -snes_error_if_not_converged -pc_type lu 663 test: 664 # -dm_refine 3 -convest_num_refine 3 get L_2 convergence rate: [1.0] 665 suffix: 3d_q2_tconv 666 args: -sol_type quadratic_trig -dm_plex_simplex 0 -temp_petscspace_degree 2 -ts_convergence_estimate -convest_num_refine 1 \ 667 -ts_type beuler -ts_max_steps 4 -ts_time_step 0.1 -snes_error_if_not_converged -pc_type lu 668 669 test: 670 # For a nice picture, -bd_dm_refine 2 -dm_refine 1 -dm_view hdf5:${PETSC_DIR}/sol.h5 -ts_monitor_solution hdf5:${PETSC_DIR}/sol.h5::append 671 suffix: egads_sphere 672 requires: egads ctetgen datafilespath 673 args: -sol_type quadratic_linear \ 674 -dm_plex_boundary_filename ${DATAFILESPATH}/meshes/cad/sphere_example.egadslite -dm_plex_boundary_label marker \ 675 -temp_petscspace_degree 2 -dmts_check .0001 \ 676 -ts_type beuler -ts_max_steps 5 -ts_time_step 0.1 -snes_error_if_not_converged -pc_type lu 677 678 test: 679 suffix: remesh 680 requires: triangle mmg 681 args: -sol_type quadratic_trig -dm_refine 2 -temp_petscspace_degree 1 -ts_type beuler -ts_time_step 0.01 -snes_error_if_not_converged -pc_type lu -grad_petscspace_degree 1 -dm_adaptor mmg -dm_plex_hash_location -remesh_every 5 682 output_file: output/empty.out 683 684 TEST*/ 685