1 static char help[] = "Second Order TVD Finite Volume Example.\n"; 2 /*F 3 4 We use a second order TVD finite volume method to evolve a system of PDEs. Our simple upwinded residual evaluation loops 5 over all mesh faces and uses a Riemann solver to produce the flux given the face geometry and cell values, 6 \begin{equation} 7 f_i = \mathrm{riemann}(\mathrm{phys}, p_\mathrm{centroid}, \hat n, x^L, x^R) 8 \end{equation} 9 and then update the cell values given the cell volume. 10 \begin{eqnarray} 11 f^L_i &-=& \frac{f_i}{vol^L} \\ 12 f^R_i &+=& \frac{f_i}{vol^R} 13 \end{eqnarray} 14 15 As an example, we can consider the shallow water wave equation, 16 \begin{eqnarray} 17 h_t + \nabla\cdot \left( uh \right) &=& 0 \\ 18 (uh)_t + \nabla\cdot \left( u\otimes uh + \frac{g h^2}{2} I \right) &=& 0 19 \end{eqnarray} 20 where $h$ is wave height, $u$ is wave velocity, and $g$ is the acceleration due to gravity. 21 22 A representative Riemann solver for the shallow water equations is given in the PhysicsRiemann_SW() function, 23 \begin{eqnarray} 24 f^{L,R}_h &=& uh^{L,R} \cdot \hat n \\ 25 f^{L,R}_{uh} &=& \frac{f^{L,R}_h}{h^{L,R}} uh^{L,R} + g (h^{L,R})^2 \hat n \\ 26 c^{L,R} &=& \sqrt{g h^{L,R}} \\ 27 s &=& \max\left( \left|\frac{uh^L \cdot \hat n}{h^L}\right| + c^L, \left|\frac{uh^R \cdot \hat n}{h^R}\right| + c^R \right) \\ 28 f_i &=& \frac{A_\mathrm{face}}{2} \left( f^L_i + f^R_i + s \left( x^L_i - x^R_i \right) \right) 29 \end{eqnarray} 30 where $c$ is the local gravity wave speed and $f_i$ is a Rusanov flux. 31 32 The more sophisticated residual evaluation in RHSFunctionLocal_LS() uses a least-squares fit to a quadratic polynomial 33 over a neighborhood of the given element. 34 35 The mesh is read in from an ExodusII file, usually generated by Cubit. 36 37 The example also shows how to handle AMR in a time-dependent TS solver. 38 F*/ 39 #include <petscdmplex.h> 40 #include <petscdmforest.h> 41 #include <petscds.h> 42 #include <petscts.h> 43 44 #include "ex11.h" 45 46 static PetscFunctionList PhysicsList, PhysicsRiemannList_SW, PhysicsRiemannList_Euler; 47 48 /* 'User' implements a discretization of a continuous model. */ 49 typedef struct _n_User *User; 50 typedef PetscErrorCode (*SolutionFunction)(Model, PetscReal, const PetscReal *, PetscScalar *, void *); 51 typedef PetscErrorCode (*SetUpBCFunction)(DM, PetscDS, Physics); 52 typedef PetscErrorCode (*FunctionalFunction)(Model, PetscReal, const PetscReal *, const PetscScalar *, PetscReal *, void *); 53 typedef PetscErrorCode (*SetupFields)(Physics, PetscSection); 54 static PetscErrorCode ModelSolutionSetDefault(Model, SolutionFunction, void *); 55 static PetscErrorCode ModelFunctionalRegister(Model, const char *, PetscInt *, FunctionalFunction, void *); 56 static PetscErrorCode OutputVTK(DM, const char *, PetscViewer *); 57 58 typedef struct _n_FunctionalLink *FunctionalLink; 59 struct _n_FunctionalLink { 60 char *name; 61 FunctionalFunction func; 62 void *ctx; 63 PetscInt offset; 64 FunctionalLink next; 65 }; 66 67 struct _n_Model { 68 MPI_Comm comm; /* Does not do collective communication, but some error conditions can be collective */ 69 Physics physics; 70 FunctionalLink functionalRegistry; 71 PetscInt maxComputed; 72 PetscInt numMonitored; 73 FunctionalLink *functionalMonitored; 74 PetscInt numCall; 75 FunctionalLink *functionalCall; 76 SolutionFunction solution; 77 SetUpBCFunction setupbc; 78 void *solutionctx; 79 PetscReal maxspeed; /* estimate of global maximum speed (for CFL calculation) */ 80 PetscReal bounds[2 * DIM]; 81 PetscErrorCode (*errorIndicator)(PetscInt, PetscReal, PetscInt, const PetscScalar[], const PetscScalar[], PetscReal *, void *); 82 void *errorCtx; 83 PetscErrorCode (*setupCEED)(DM, Physics); 84 }; 85 86 struct _n_User { 87 PetscInt vtkInterval; /* For monitor */ 88 char outputBasename[PETSC_MAX_PATH_LEN]; /* Basename for output files */ 89 PetscInt monitorStepOffset; 90 Model model; 91 PetscBool vtkmon; 92 }; 93 94 #ifdef PETSC_HAVE_LIBCEED 95 // Free a plain data context that was allocated using PETSc; returning libCEED error codes 96 static int FreeContextPetsc(void *data) 97 { 98 if (PetscFree(data)) return CeedError(NULL, CEED_ERROR_ACCESS, "PetscFree failed"); 99 return CEED_ERROR_SUCCESS; 100 } 101 #endif 102 103 /******************* Advect ********************/ 104 typedef enum { 105 ADVECT_SOL_TILTED, 106 ADVECT_SOL_BUMP, 107 ADVECT_SOL_BUMP_CAVITY 108 } AdvectSolType; 109 static const char *const AdvectSolTypes[] = {"TILTED", "BUMP", "BUMP_CAVITY", "AdvectSolType", "ADVECT_SOL_", 0}; 110 typedef enum { 111 ADVECT_SOL_BUMP_CONE, 112 ADVECT_SOL_BUMP_COS 113 } AdvectSolBumpType; 114 static const char *const AdvectSolBumpTypes[] = {"CONE", "COS", "AdvectSolBumpType", "ADVECT_SOL_BUMP_", 0}; 115 116 typedef struct { 117 PetscReal wind[DIM]; 118 } Physics_Advect_Tilted; 119 typedef struct { 120 PetscReal center[DIM]; 121 PetscReal radius; 122 AdvectSolBumpType type; 123 } Physics_Advect_Bump; 124 125 typedef struct { 126 PetscReal inflowState; 127 AdvectSolType soltype; 128 union 129 { 130 Physics_Advect_Tilted tilted; 131 Physics_Advect_Bump bump; 132 } sol; 133 struct { 134 PetscInt Solution; 135 PetscInt Error; 136 } functional; 137 } Physics_Advect; 138 139 static const struct FieldDescription PhysicsFields_Advect[] = { 140 {"U", 1}, 141 {NULL, 0} 142 }; 143 144 static PetscErrorCode PhysicsBoundary_Advect_Inflow(PetscReal time, const PetscReal *c, const PetscReal *n, const PetscScalar *xI, PetscScalar *xG, PetscCtx ctx) 145 { 146 Physics phys = (Physics)ctx; 147 Physics_Advect *advect = (Physics_Advect *)phys->data; 148 149 PetscFunctionBeginUser; 150 xG[0] = advect->inflowState; 151 PetscFunctionReturn(PETSC_SUCCESS); 152 } 153 154 static PetscErrorCode PhysicsBoundary_Advect_Outflow(PetscReal time, const PetscReal *c, const PetscReal *n, const PetscScalar *xI, PetscScalar *xG, PetscCtx ctx) 155 { 156 PetscFunctionBeginUser; 157 xG[0] = xI[0]; 158 PetscFunctionReturn(PETSC_SUCCESS); 159 } 160 161 static void PhysicsRiemann_Advect(PetscInt dim, PetscInt Nf, const PetscReal *qp, const PetscReal *n, const PetscScalar *xL, const PetscScalar *xR, PetscInt numConstants, const PetscScalar constants[], PetscScalar *flux, Physics phys) 162 { 163 Physics_Advect *advect = (Physics_Advect *)phys->data; 164 PetscReal wind[DIM], wn; 165 166 switch (advect->soltype) { 167 case ADVECT_SOL_TILTED: { 168 Physics_Advect_Tilted *tilted = &advect->sol.tilted; 169 wind[0] = tilted->wind[0]; 170 wind[1] = tilted->wind[1]; 171 } break; 172 case ADVECT_SOL_BUMP: 173 wind[0] = -qp[1]; 174 wind[1] = qp[0]; 175 break; 176 case ADVECT_SOL_BUMP_CAVITY: { 177 PetscInt i; 178 PetscReal comp2[3] = {0., 0., 0.}, rad2; 179 180 rad2 = 0.; 181 for (i = 0; i < dim; i++) { 182 comp2[i] = qp[i] * qp[i]; 183 rad2 += comp2[i]; 184 } 185 186 wind[0] = -qp[1]; 187 wind[1] = qp[0]; 188 if (rad2 > 1.) { 189 PetscInt maxI = 0; 190 PetscReal maxComp2 = comp2[0]; 191 192 for (i = 1; i < dim; i++) { 193 if (comp2[i] > maxComp2) { 194 maxI = i; 195 maxComp2 = comp2[i]; 196 } 197 } 198 wind[maxI] = 0.; 199 } 200 } break; 201 default: { 202 PetscInt i; 203 for (i = 0; i < DIM; ++i) wind[i] = 0.0; 204 } 205 /* default: SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"No support for solution type %s",AdvectSolBumpTypes[advect->soltype]); */ 206 } 207 wn = Dot2Real(wind, n); 208 flux[0] = (wn > 0 ? xL[0] : xR[0]) * wn; 209 } 210 211 static PetscErrorCode PhysicsSolution_Advect(Model mod, PetscReal time, const PetscReal *x, PetscScalar *u, PetscCtx ctx) 212 { 213 Physics phys = (Physics)ctx; 214 Physics_Advect *advect = (Physics_Advect *)phys->data; 215 216 PetscFunctionBeginUser; 217 switch (advect->soltype) { 218 case ADVECT_SOL_TILTED: { 219 PetscReal x0[DIM]; 220 Physics_Advect_Tilted *tilted = &advect->sol.tilted; 221 Waxpy2Real(-time, tilted->wind, x, x0); 222 if (x0[1] > 0) u[0] = 1. * x[0] + 3. * x[1]; 223 else u[0] = advect->inflowState; 224 } break; 225 case ADVECT_SOL_BUMP_CAVITY: 226 case ADVECT_SOL_BUMP: { 227 Physics_Advect_Bump *bump = &advect->sol.bump; 228 PetscReal x0[DIM], v[DIM], r, cost, sint; 229 cost = PetscCosReal(time); 230 sint = PetscSinReal(time); 231 x0[0] = cost * x[0] + sint * x[1]; 232 x0[1] = -sint * x[0] + cost * x[1]; 233 Waxpy2Real(-1, bump->center, x0, v); 234 r = Norm2Real(v); 235 switch (bump->type) { 236 case ADVECT_SOL_BUMP_CONE: 237 u[0] = PetscMax(1 - r / bump->radius, 0); 238 break; 239 case ADVECT_SOL_BUMP_COS: 240 u[0] = 0.5 + 0.5 * PetscCosReal(PetscMin(r / bump->radius, 1) * PETSC_PI); 241 break; 242 } 243 } break; 244 default: 245 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Unknown solution type"); 246 } 247 PetscFunctionReturn(PETSC_SUCCESS); 248 } 249 250 static PetscErrorCode PhysicsFunctional_Advect(Model mod, PetscReal time, const PetscReal *x, const PetscScalar *y, PetscReal *f, PetscCtx ctx) 251 { 252 Physics phys = (Physics)ctx; 253 Physics_Advect *advect = (Physics_Advect *)phys->data; 254 PetscScalar yexact[1] = {0.0}; 255 256 PetscFunctionBeginUser; 257 PetscCall(PhysicsSolution_Advect(mod, time, x, yexact, phys)); 258 f[advect->functional.Solution] = PetscRealPart(y[0]); 259 f[advect->functional.Error] = PetscAbsScalar(y[0] - yexact[0]); 260 PetscFunctionReturn(PETSC_SUCCESS); 261 } 262 263 static PetscErrorCode SetUpBC_Advect(DM dm, PetscDS prob, Physics phys) 264 { 265 const PetscInt inflowids[] = {100, 200, 300}, outflowids[] = {101}; 266 DMLabel label; 267 268 PetscFunctionBeginUser; 269 /* Register "canned" boundary conditions and defaults for where to apply. */ 270 PetscCall(DMGetLabel(dm, "Face Sets", &label)); 271 PetscCall(PetscDSAddBoundary(prob, DM_BC_NATURAL_RIEMANN, "inflow", label, PETSC_STATIC_ARRAY_LENGTH(inflowids), inflowids, 0, 0, NULL, (PetscVoidFn *)PhysicsBoundary_Advect_Inflow, NULL, phys, NULL)); 272 PetscCall(PetscDSAddBoundary(prob, DM_BC_NATURAL_RIEMANN, "outflow", label, PETSC_STATIC_ARRAY_LENGTH(outflowids), outflowids, 0, 0, NULL, (PetscVoidFn *)PhysicsBoundary_Advect_Outflow, NULL, phys, NULL)); 273 PetscFunctionReturn(PETSC_SUCCESS); 274 } 275 276 static PetscErrorCode PhysicsCreate_Advect(Model mod, Physics phys, PetscOptionItems PetscOptionsObject) 277 { 278 Physics_Advect *advect; 279 280 PetscFunctionBeginUser; 281 phys->field_desc = PhysicsFields_Advect; 282 phys->riemann = (PetscRiemannFn *)(PetscVoidFn *)PhysicsRiemann_Advect; 283 PetscCall(PetscNew(&advect)); 284 phys->data = advect; 285 mod->setupbc = SetUpBC_Advect; 286 287 PetscOptionsHeadBegin(PetscOptionsObject, "Advect options"); 288 { 289 PetscInt two = 2, dof = 1; 290 advect->soltype = ADVECT_SOL_TILTED; 291 PetscCall(PetscOptionsEnum("-advect_sol_type", "solution type", "", AdvectSolTypes, (PetscEnum)advect->soltype, (PetscEnum *)&advect->soltype, NULL)); 292 switch (advect->soltype) { 293 case ADVECT_SOL_TILTED: { 294 Physics_Advect_Tilted *tilted = &advect->sol.tilted; 295 two = 2; 296 tilted->wind[0] = 0.0; 297 tilted->wind[1] = 1.0; 298 PetscCall(PetscOptionsRealArray("-advect_tilted_wind", "background wind vx,vy", "", tilted->wind, &two, NULL)); 299 advect->inflowState = -2.0; 300 PetscCall(PetscOptionsRealArray("-advect_tilted_inflow", "Inflow state", "", &advect->inflowState, &dof, NULL)); 301 phys->maxspeed = Norm2Real(tilted->wind); 302 } break; 303 case ADVECT_SOL_BUMP_CAVITY: 304 case ADVECT_SOL_BUMP: { 305 Physics_Advect_Bump *bump = &advect->sol.bump; 306 two = 2; 307 bump->center[0] = 2.; 308 bump->center[1] = 0.; 309 PetscCall(PetscOptionsRealArray("-advect_bump_center", "location of center of bump x,y", "", bump->center, &two, NULL)); 310 bump->radius = 0.9; 311 PetscCall(PetscOptionsReal("-advect_bump_radius", "radius of bump", "", bump->radius, &bump->radius, NULL)); 312 bump->type = ADVECT_SOL_BUMP_CONE; 313 PetscCall(PetscOptionsEnum("-advect_bump_type", "type of bump", "", AdvectSolBumpTypes, (PetscEnum)bump->type, (PetscEnum *)&bump->type, NULL)); 314 phys->maxspeed = 3.; /* radius of mesh, kludge */ 315 } break; 316 } 317 } 318 PetscOptionsHeadEnd(); 319 /* Initial/transient solution with default boundary conditions */ 320 PetscCall(ModelSolutionSetDefault(mod, PhysicsSolution_Advect, phys)); 321 /* Register "canned" functionals */ 322 PetscCall(ModelFunctionalRegister(mod, "Solution", &advect->functional.Solution, PhysicsFunctional_Advect, phys)); 323 PetscCall(ModelFunctionalRegister(mod, "Error", &advect->functional.Error, PhysicsFunctional_Advect, phys)); 324 PetscFunctionReturn(PETSC_SUCCESS); 325 } 326 327 /******************* Shallow Water ********************/ 328 static const struct FieldDescription PhysicsFields_SW[] = { 329 {"Height", 1 }, 330 {"Momentum", DIM}, 331 {NULL, 0 } 332 }; 333 334 static PetscErrorCode PhysicsBoundary_SW_Wall(PetscReal time, const PetscReal *c, const PetscReal *n, const PetscScalar *xI, PetscScalar *xG, PetscCtx ctx) 335 { 336 PetscFunctionBeginUser; 337 xG[0] = xI[0]; 338 xG[1] = -xI[1]; 339 xG[2] = -xI[2]; 340 PetscFunctionReturn(PETSC_SUCCESS); 341 } 342 343 static PetscErrorCode PhysicsSolution_SW(Model mod, PetscReal time, const PetscReal *x, PetscScalar *u, PetscCtx ctx) 344 { 345 PetscReal dx[2], r, sigma; 346 347 PetscFunctionBeginUser; 348 PetscCheck(time == 0.0, mod->comm, PETSC_ERR_SUP, "No solution known for time %g", (double)time); 349 dx[0] = x[0] - 1.5; 350 dx[1] = x[1] - 1.0; 351 r = Norm2Real(dx); 352 sigma = 0.5; 353 u[0] = 1 + 2 * PetscExpReal(-PetscSqr(r) / (2 * PetscSqr(sigma))); 354 u[1] = 0.0; 355 u[2] = 0.0; 356 PetscFunctionReturn(PETSC_SUCCESS); 357 } 358 359 static PetscErrorCode PhysicsFunctional_SW(Model mod, PetscReal time, const PetscReal *coord, const PetscScalar *xx, PetscReal *f, PetscCtx ctx) 360 { 361 Physics phys = (Physics)ctx; 362 Physics_SW *sw = (Physics_SW *)phys->data; 363 const SWNode *x = (const SWNode *)xx; 364 PetscReal u[2]; 365 PetscReal h; 366 367 PetscFunctionBeginUser; 368 h = x->h; 369 Scale2Real(1. / x->h, x->uh, u); 370 f[sw->functional.Height] = h; 371 f[sw->functional.Speed] = Norm2Real(u) + PetscSqrtReal(sw->gravity * h); 372 f[sw->functional.Energy] = 0.5 * (Dot2Real(x->uh, u) + sw->gravity * PetscSqr(h)); 373 PetscFunctionReturn(PETSC_SUCCESS); 374 } 375 376 static PetscErrorCode SetUpBC_SW(DM dm, PetscDS prob, Physics phys) 377 { 378 const PetscInt wallids[] = {100, 101, 200, 300}; 379 DMLabel label; 380 381 PetscFunctionBeginUser; 382 PetscCall(DMGetLabel(dm, "Face Sets", &label)); 383 PetscCall(PetscDSAddBoundary(prob, DM_BC_NATURAL_RIEMANN, "wall", label, PETSC_STATIC_ARRAY_LENGTH(wallids), wallids, 0, 0, NULL, (PetscVoidFn *)PhysicsBoundary_SW_Wall, NULL, phys, NULL)); 384 PetscFunctionReturn(PETSC_SUCCESS); 385 } 386 387 #ifdef PETSC_HAVE_LIBCEED 388 static PetscErrorCode CreateQFunctionContext_SW(Physics phys, Ceed ceed, CeedQFunctionContext *qfCtx) 389 { 390 Physics_SW *in = (Physics_SW *)phys->data; 391 Physics_SW *sw; 392 393 PetscFunctionBeginUser; 394 PetscCall(PetscCalloc1(1, &sw)); 395 396 sw->gravity = in->gravity; 397 398 PetscCallCEED(CeedQFunctionContextCreate(ceed, qfCtx)); 399 PetscCallCEED(CeedQFunctionContextSetData(*qfCtx, CEED_MEM_HOST, CEED_USE_POINTER, sizeof(*sw), sw)); 400 PetscCallCEED(CeedQFunctionContextSetDataDestroy(*qfCtx, CEED_MEM_HOST, FreeContextPetsc)); 401 PetscCallCEED(CeedQFunctionContextRegisterDouble(*qfCtx, "gravity", offsetof(Physics_SW, gravity), 1, "Acceleration due to gravity")); 402 PetscFunctionReturn(PETSC_SUCCESS); 403 } 404 #endif 405 406 static PetscErrorCode SetupCEED_SW(DM dm, Physics physics) 407 { 408 #ifdef PETSC_HAVE_LIBCEED 409 Ceed ceed; 410 CeedQFunctionContext qfCtx; 411 #endif 412 413 PetscFunctionBegin; 414 #ifdef PETSC_HAVE_LIBCEED 415 PetscCall(DMGetCeed(dm, &ceed)); 416 PetscCall(CreateQFunctionContext_SW(physics, ceed, &qfCtx)); 417 PetscCall(DMCeedCreateFVM(dm, PETSC_TRUE, PhysicsRiemann_SW_Rusanov_CEED, PhysicsRiemann_SW_Rusanov_CEED_loc, qfCtx)); 418 PetscCallCEED(CeedQFunctionContextDestroy(&qfCtx)); 419 #endif 420 PetscFunctionReturn(PETSC_SUCCESS); 421 } 422 423 static PetscErrorCode PhysicsCreate_SW(Model mod, Physics phys, PetscOptionItems PetscOptionsObject) 424 { 425 Physics_SW *sw; 426 char sw_riemann[64] = "rusanov"; 427 428 PetscFunctionBeginUser; 429 phys->field_desc = PhysicsFields_SW; 430 PetscCall(PetscNew(&sw)); 431 phys->data = sw; 432 mod->setupbc = SetUpBC_SW; 433 mod->setupCEED = SetupCEED_SW; 434 435 PetscCall(PetscFunctionListAdd(&PhysicsRiemannList_SW, "rusanov", PhysicsRiemann_SW_Rusanov)); 436 PetscCall(PetscFunctionListAdd(&PhysicsRiemannList_SW, "hll", PhysicsRiemann_SW_HLL)); 437 #ifdef PETSC_HAVE_LIBCEED 438 PetscCall(PetscFunctionListAdd(&PhysicsRiemannList_SW, "rusanov_ceed", PhysicsRiemann_SW_Rusanov_CEED)); 439 #endif 440 441 PetscOptionsHeadBegin(PetscOptionsObject, "SW options"); 442 { 443 void (*PhysicsRiemann_SW)(PetscInt, PetscInt, const PetscReal *, const PetscReal *, const PetscScalar *, const PetscScalar *, PetscInt, const PetscScalar, PetscScalar *, Physics); 444 sw->gravity = 1.0; 445 PetscCall(PetscOptionsReal("-sw_gravity", "Gravitational constant", "", sw->gravity, &sw->gravity, NULL)); 446 PetscCall(PetscOptionsFList("-sw_riemann", "Riemann solver", "", PhysicsRiemannList_SW, sw_riemann, sw_riemann, sizeof sw_riemann, NULL)); 447 PetscCall(PetscFunctionListFind(PhysicsRiemannList_SW, sw_riemann, &PhysicsRiemann_SW)); 448 phys->riemann = (PetscRiemannFn *)(PetscVoidFn *)PhysicsRiemann_SW; 449 } 450 PetscOptionsHeadEnd(); 451 phys->maxspeed = PetscSqrtReal(2.0 * sw->gravity); /* Mach 1 for depth of 2 */ 452 453 PetscCall(ModelSolutionSetDefault(mod, PhysicsSolution_SW, phys)); 454 PetscCall(ModelFunctionalRegister(mod, "Height", &sw->functional.Height, PhysicsFunctional_SW, phys)); 455 PetscCall(ModelFunctionalRegister(mod, "Speed", &sw->functional.Speed, PhysicsFunctional_SW, phys)); 456 PetscCall(ModelFunctionalRegister(mod, "Energy", &sw->functional.Energy, PhysicsFunctional_SW, phys)); 457 PetscFunctionReturn(PETSC_SUCCESS); 458 } 459 460 /******************* Euler Density Shock (EULER_IV_SHOCK,EULER_SS_SHOCK) ********************/ 461 /* An initial-value and self-similar solutions of the compressible Euler equations */ 462 /* Ravi Samtaney and D. I. Pullin */ 463 /* Phys. Fluids 8, 2650 (1996); http://dx.doi.org/10.1063/1.869050 */ 464 static const struct FieldDescription PhysicsFields_Euler[] = { 465 {"Density", 1 }, 466 {"Momentum", DIM}, 467 {"Energy", 1 }, 468 {NULL, 0 } 469 }; 470 471 /* initial condition */ 472 int initLinearWave(EulerNode *ux, const PetscReal gamma, const PetscReal coord[], const PetscReal Lx); 473 static PetscErrorCode PhysicsSolution_Euler(Model mod, PetscReal time, const PetscReal *x, PetscScalar *u, PetscCtx ctx) 474 { 475 PetscInt i; 476 Physics phys = (Physics)ctx; 477 Physics_Euler *eu = (Physics_Euler *)phys->data; 478 EulerNode *uu = (EulerNode *)u; 479 PetscReal p0, gamma, c = 0.; 480 481 PetscFunctionBeginUser; 482 PetscCheck(time == 0.0, mod->comm, PETSC_ERR_SUP, "No solution known for time %g", (double)time); 483 484 for (i = 0; i < DIM; i++) uu->ru[i] = 0.0; /* zero out initial velocity */ 485 /* set E and rho */ 486 gamma = eu->gamma; 487 488 if (eu->type == EULER_IV_SHOCK || eu->type == EULER_SS_SHOCK) { 489 /******************* Euler Density Shock ********************/ 490 /* On initial-value and self-similar solutions of the compressible Euler equations */ 491 /* Ravi Samtaney and D. I. Pullin */ 492 /* Phys. Fluids 8, 2650 (1996); http://dx.doi.org/10.1063/1.869050 */ 493 /* initial conditions 1: left of shock, 0: left of discontinuity 2: right of discontinuity, */ 494 p0 = 1.; 495 if (x[0] < 0.0 + x[1] * eu->itana) { 496 if (x[0] < mod->bounds[0] * 0.5) { /* left of shock (1) */ 497 PetscReal amach, rho, press, gas1, p1; 498 amach = eu->amach; 499 rho = 1.; 500 press = p0; 501 p1 = press * (1.0 + 2.0 * gamma / (gamma + 1.0) * (amach * amach - 1.0)); 502 gas1 = (gamma - 1.0) / (gamma + 1.0); 503 uu->r = rho * (p1 / press + gas1) / (gas1 * p1 / press + 1.0); 504 uu->ru[0] = ((uu->r - rho) * PetscSqrtReal(gamma * press / rho) * amach); 505 uu->E = p1 / (gamma - 1.0) + .5 / uu->r * uu->ru[0] * uu->ru[0]; 506 } else { /* left of discontinuity (0) */ 507 uu->r = 1.; /* rho = 1 */ 508 uu->E = p0 / (gamma - 1.0); 509 } 510 } else { /* right of discontinuity (2) */ 511 uu->r = eu->rhoR; 512 uu->E = p0 / (gamma - 1.0); 513 } 514 } else if (eu->type == EULER_SHOCK_TUBE) { 515 /* For (x<x0) set (rho,u,p)=(8,0,10) and for (x>x0) set (rho,u,p)=(1,0,1). Choose x0 to the midpoint of the domain in the x-direction. */ 516 if (x[0] < 0.0) { 517 uu->r = 8.; 518 uu->E = 10. / (gamma - 1.); 519 } else { 520 uu->r = 1.; 521 uu->E = 1. / (gamma - 1.); 522 } 523 } else if (eu->type == EULER_LINEAR_WAVE) { 524 initLinearWave(uu, gamma, x, mod->bounds[1] - mod->bounds[0]); 525 } else SETERRQ(mod->comm, PETSC_ERR_SUP, "Unknown type %d", eu->type); 526 527 /* set phys->maxspeed: (mod->maxspeed = phys->maxspeed) in main; */ 528 PetscCall(SpeedOfSound_PG(gamma, uu, &c)); 529 c = (uu->ru[0] / uu->r) + c; 530 if (c > phys->maxspeed) phys->maxspeed = c; 531 PetscFunctionReturn(PETSC_SUCCESS); 532 } 533 534 /* PetscReal* => EulerNode* conversion */ 535 static PetscErrorCode PhysicsBoundary_Euler_Wall(PetscReal time, const PetscReal *c, const PetscReal *n, const PetscScalar *a_xI, PetscScalar *a_xG, PetscCtx ctx) 536 { 537 PetscInt i; 538 const EulerNode *xI = (const EulerNode *)a_xI; 539 EulerNode *xG = (EulerNode *)a_xG; 540 Physics phys = (Physics)ctx; 541 Physics_Euler *eu = (Physics_Euler *)phys->data; 542 543 PetscFunctionBeginUser; 544 xG->r = xI->r; /* ghost cell density - same */ 545 xG->E = xI->E; /* ghost cell energy - same */ 546 if (n[1] != 0.) { /* top and bottom */ 547 xG->ru[0] = xI->ru[0]; /* copy tang to wall */ 548 xG->ru[1] = -xI->ru[1]; /* reflect perp to t/b wall */ 549 } else { /* sides */ 550 for (i = 0; i < DIM; i++) xG->ru[i] = xI->ru[i]; /* copy */ 551 } 552 if (eu->type == EULER_LINEAR_WAVE) { /* debug */ 553 #if 0 554 PetscPrintf(PETSC_COMM_WORLD,"%s coord=%g,%g\n",PETSC_FUNCTION_NAME,(double)c[0],(double)c[1]); 555 #endif 556 } 557 PetscFunctionReturn(PETSC_SUCCESS); 558 } 559 560 static PetscErrorCode PhysicsFunctional_Euler(Model mod, PetscReal time, const PetscReal *coord, const PetscScalar *xx, PetscReal *f, PetscCtx ctx) 561 { 562 Physics phys = (Physics)ctx; 563 Physics_Euler *eu = (Physics_Euler *)phys->data; 564 const EulerNode *x = (const EulerNode *)xx; 565 PetscReal p; 566 567 PetscFunctionBeginUser; 568 f[eu->monitor.Density] = x->r; 569 f[eu->monitor.Momentum] = NormDIM(x->ru); 570 f[eu->monitor.Energy] = x->E; 571 f[eu->monitor.Speed] = NormDIM(x->ru) / x->r; 572 PetscCall(Pressure_PG(eu->gamma, x, &p)); 573 f[eu->monitor.Pressure] = p; 574 PetscFunctionReturn(PETSC_SUCCESS); 575 } 576 577 static PetscErrorCode SetUpBC_Euler(DM dm, PetscDS prob, Physics phys) 578 { 579 Physics_Euler *eu = (Physics_Euler *)phys->data; 580 DMLabel label; 581 582 PetscFunctionBeginUser; 583 PetscCall(DMGetLabel(dm, "Face Sets", &label)); 584 if (eu->type == EULER_LINEAR_WAVE) { 585 const PetscInt wallids[] = {100, 101}; 586 PetscCall(PetscDSAddBoundary(prob, DM_BC_NATURAL_RIEMANN, "wall", label, PETSC_STATIC_ARRAY_LENGTH(wallids), wallids, 0, 0, NULL, (PetscVoidFn *)PhysicsBoundary_Euler_Wall, NULL, phys, NULL)); 587 } else { 588 const PetscInt wallids[] = {100, 101, 200, 300}; 589 PetscCall(PetscDSAddBoundary(prob, DM_BC_NATURAL_RIEMANN, "wall", label, PETSC_STATIC_ARRAY_LENGTH(wallids), wallids, 0, 0, NULL, (PetscVoidFn *)PhysicsBoundary_Euler_Wall, NULL, phys, NULL)); 590 } 591 PetscFunctionReturn(PETSC_SUCCESS); 592 } 593 594 #ifdef PETSC_HAVE_LIBCEED 595 static PetscErrorCode CreateQFunctionContext_Euler(Physics phys, Ceed ceed, CeedQFunctionContext *qfCtx) 596 { 597 Physics_Euler *in = (Physics_Euler *)phys->data; 598 Physics_Euler *eu; 599 600 PetscFunctionBeginUser; 601 PetscCall(PetscCalloc1(1, &eu)); 602 603 eu->gamma = in->gamma; 604 605 PetscCallCEED(CeedQFunctionContextCreate(ceed, qfCtx)); 606 PetscCallCEED(CeedQFunctionContextSetData(*qfCtx, CEED_MEM_HOST, CEED_USE_POINTER, sizeof(*eu), eu)); 607 PetscCallCEED(CeedQFunctionContextSetDataDestroy(*qfCtx, CEED_MEM_HOST, FreeContextPetsc)); 608 PetscCallCEED(CeedQFunctionContextRegisterDouble(*qfCtx, "gamma", offsetof(Physics_Euler, gamma), 1, "Heat capacity ratio")); 609 PetscFunctionReturn(PETSC_SUCCESS); 610 } 611 #endif 612 613 static PetscErrorCode SetupCEED_Euler(DM dm, Physics physics) 614 { 615 #ifdef PETSC_HAVE_LIBCEED 616 Ceed ceed; 617 CeedQFunctionContext qfCtx; 618 #endif 619 620 PetscFunctionBegin; 621 #ifdef PETSC_HAVE_LIBCEED 622 PetscCall(DMGetCeed(dm, &ceed)); 623 PetscCall(CreateQFunctionContext_Euler(physics, ceed, &qfCtx)); 624 PetscCall(DMCeedCreateFVM(dm, PETSC_TRUE, PhysicsRiemann_Euler_Godunov_CEED, PhysicsRiemann_Euler_Godunov_CEED_loc, qfCtx)); 625 PetscCallCEED(CeedQFunctionContextDestroy(&qfCtx)); 626 #endif 627 PetscFunctionReturn(PETSC_SUCCESS); 628 } 629 630 static PetscErrorCode PhysicsCreate_Euler(Model mod, Physics phys, PetscOptionItems PetscOptionsObject) 631 { 632 Physics_Euler *eu; 633 634 PetscFunctionBeginUser; 635 phys->field_desc = PhysicsFields_Euler; 636 phys->riemann = (PetscRiemannFn *)(PetscVoidFn *)PhysicsRiemann_Euler_Godunov; 637 PetscCall(PetscNew(&eu)); 638 phys->data = eu; 639 mod->setupbc = SetUpBC_Euler; 640 mod->setupCEED = SetupCEED_Euler; 641 642 PetscCall(PetscFunctionListAdd(&PhysicsRiemannList_Euler, "godunov", PhysicsRiemann_Euler_Godunov)); 643 #ifdef PETSC_HAVE_LIBCEED 644 PetscCall(PetscFunctionListAdd(&PhysicsRiemannList_Euler, "godunov_ceed", PhysicsRiemann_Euler_Godunov_CEED)); 645 #endif 646 647 PetscOptionsHeadBegin(PetscOptionsObject, "Euler options"); 648 { 649 void (*PhysicsRiemann_Euler)(PetscInt, PetscInt, const PetscReal *, const PetscReal *, const PetscScalar *, const PetscScalar *, PetscInt, const PetscScalar, PetscScalar *, Physics); 650 PetscReal alpha; 651 char type[64] = "linear_wave"; 652 char eu_riemann[64] = "godunov"; 653 PetscBool is; 654 eu->gamma = 1.4; 655 eu->amach = 2.02; 656 eu->rhoR = 3.0; 657 eu->itana = 0.57735026918963; /* angle of Euler self similar (SS) shock */ 658 PetscCall(PetscOptionsFList("-eu_riemann", "Riemann solver", "", PhysicsRiemannList_Euler, eu_riemann, eu_riemann, sizeof eu_riemann, NULL)); 659 PetscCall(PetscFunctionListFind(PhysicsRiemannList_Euler, eu_riemann, &PhysicsRiemann_Euler)); 660 phys->riemann = (PetscRiemannFn *)(PetscVoidFn *)PhysicsRiemann_Euler; 661 PetscCall(PetscOptionsReal("-eu_gamma", "Heat capacity ratio", "", eu->gamma, &eu->gamma, NULL)); 662 PetscCall(PetscOptionsReal("-eu_amach", "Shock speed (Mach)", "", eu->amach, &eu->amach, NULL)); 663 PetscCall(PetscOptionsReal("-eu_rho2", "Density right of discontinuity", "", eu->rhoR, &eu->rhoR, NULL)); 664 alpha = 60.; 665 PetscCall(PetscOptionsRangeReal("-eu_alpha", "Angle of discontinuity", "", alpha, &alpha, NULL, 0.0, 90.0)); 666 eu->itana = 1. / PetscTanReal(alpha * PETSC_PI / 180.0); 667 PetscCall(PetscOptionsString("-eu_type", "Type of Euler test", "", type, type, sizeof(type), NULL)); 668 PetscCall(PetscStrcmp(type, "linear_wave", &is)); 669 if (is) { 670 /* Remember this should be periodic */ 671 eu->type = EULER_LINEAR_WAVE; 672 PetscCall(PetscPrintf(PETSC_COMM_WORLD, "%s set Euler type: %s\n", PETSC_FUNCTION_NAME, "linear_wave")); 673 } else { 674 PetscCheck(DIM == 2, PETSC_COMM_WORLD, PETSC_ERR_SUP, "DIM must be 2 unless linear wave test %s", type); 675 PetscCall(PetscStrcmp(type, "iv_shock", &is)); 676 if (is) { 677 eu->type = EULER_IV_SHOCK; 678 PetscCall(PetscPrintf(PETSC_COMM_WORLD, "%s set Euler type: %s\n", PETSC_FUNCTION_NAME, "iv_shock")); 679 } else { 680 PetscCall(PetscStrcmp(type, "ss_shock", &is)); 681 if (is) { 682 eu->type = EULER_SS_SHOCK; 683 PetscCall(PetscPrintf(PETSC_COMM_WORLD, "%s set Euler type: %s\n", PETSC_FUNCTION_NAME, "ss_shock")); 684 } else { 685 PetscCall(PetscStrcmp(type, "shock_tube", &is)); 686 PetscCheck(is, PETSC_COMM_WORLD, PETSC_ERR_SUP, "Unknown Euler type %s", type); 687 eu->type = EULER_SHOCK_TUBE; 688 PetscCall(PetscPrintf(PETSC_COMM_WORLD, "%s set Euler type: %s\n", PETSC_FUNCTION_NAME, "shock_tube")); 689 } 690 } 691 } 692 } 693 PetscOptionsHeadEnd(); 694 phys->maxspeed = 0.; /* will get set in solution */ 695 PetscCall(ModelSolutionSetDefault(mod, PhysicsSolution_Euler, phys)); 696 PetscCall(ModelFunctionalRegister(mod, "Speed", &eu->monitor.Speed, PhysicsFunctional_Euler, phys)); 697 PetscCall(ModelFunctionalRegister(mod, "Energy", &eu->monitor.Energy, PhysicsFunctional_Euler, phys)); 698 PetscCall(ModelFunctionalRegister(mod, "Density", &eu->monitor.Density, PhysicsFunctional_Euler, phys)); 699 PetscCall(ModelFunctionalRegister(mod, "Momentum", &eu->monitor.Momentum, PhysicsFunctional_Euler, phys)); 700 PetscCall(ModelFunctionalRegister(mod, "Pressure", &eu->monitor.Pressure, PhysicsFunctional_Euler, phys)); 701 PetscFunctionReturn(PETSC_SUCCESS); 702 } 703 704 static PetscErrorCode ErrorIndicator_Simple(PetscInt dim, PetscReal volume, PetscInt numComps, const PetscScalar u[], const PetscScalar grad[], PetscReal *error, PetscCtx ctx) 705 { 706 PetscReal err = 0.; 707 PetscInt i, j; 708 709 PetscFunctionBeginUser; 710 for (i = 0; i < numComps; i++) { 711 for (j = 0; j < dim; j++) err += PetscSqr(PetscRealPart(grad[i * dim + j])); 712 } 713 *error = volume * err; 714 PetscFunctionReturn(PETSC_SUCCESS); 715 } 716 717 PetscErrorCode CreatePartitionVec(DM dm, DM *dmCell, Vec *partition) 718 { 719 PetscSF sfPoint; 720 PetscSection coordSection; 721 Vec coordinates; 722 PetscSection sectionCell; 723 PetscScalar *part; 724 PetscInt cStart, cEnd, c; 725 PetscMPIInt rank; 726 727 PetscFunctionBeginUser; 728 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 729 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 730 PetscCall(DMClone(dm, dmCell)); 731 PetscCall(DMGetPointSF(dm, &sfPoint)); 732 PetscCall(DMSetPointSF(*dmCell, sfPoint)); 733 PetscCall(DMSetCoordinateSection(*dmCell, PETSC_DETERMINE, coordSection)); 734 PetscCall(DMSetCoordinatesLocal(*dmCell, coordinates)); 735 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank)); 736 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ionCell)); 737 PetscCall(DMPlexGetHeightStratum(*dmCell, 0, &cStart, &cEnd)); 738 PetscCall(PetscSectionSetChart(sectionCell, cStart, cEnd)); 739 for (c = cStart; c < cEnd; ++c) PetscCall(PetscSectionSetDof(sectionCell, c, 1)); 740 PetscCall(PetscSectionSetUp(sectionCell)); 741 PetscCall(DMSetLocalSection(*dmCell, sectionCell)); 742 PetscCall(PetscSectionDestroy(§ionCell)); 743 PetscCall(DMCreateLocalVector(*dmCell, partition)); 744 PetscCall(PetscObjectSetName((PetscObject)*partition, "partition")); 745 PetscCall(VecGetArray(*partition, &part)); 746 for (c = cStart; c < cEnd; ++c) { 747 PetscScalar *p; 748 749 PetscCall(DMPlexPointLocalRef(*dmCell, c, part, &p)); 750 p[0] = rank; 751 } 752 PetscCall(VecRestoreArray(*partition, &part)); 753 PetscFunctionReturn(PETSC_SUCCESS); 754 } 755 756 PetscErrorCode CreateMassMatrix(DM dm, Vec *massMatrix, User user) 757 { 758 DM plex, dmMass, dmFace, dmCell, dmCoord; 759 PetscSection coordSection; 760 Vec coordinates, facegeom, cellgeom; 761 PetscSection sectionMass; 762 PetscScalar *m; 763 const PetscScalar *fgeom, *cgeom, *coords; 764 PetscInt vStart, vEnd, v; 765 766 PetscFunctionBeginUser; 767 PetscCall(DMConvert(dm, DMPLEX, &plex)); 768 PetscCall(DMGetCoordinateSection(dm, &coordSection)); 769 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 770 PetscCall(DMClone(dm, &dmMass)); 771 PetscCall(DMSetCoordinateSection(dmMass, PETSC_DETERMINE, coordSection)); 772 PetscCall(DMSetCoordinatesLocal(dmMass, coordinates)); 773 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), §ionMass)); 774 PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd)); 775 PetscCall(PetscSectionSetChart(sectionMass, vStart, vEnd)); 776 for (v = vStart; v < vEnd; ++v) { 777 PetscInt numFaces; 778 779 PetscCall(DMPlexGetSupportSize(dmMass, v, &numFaces)); 780 PetscCall(PetscSectionSetDof(sectionMass, v, numFaces * numFaces)); 781 } 782 PetscCall(PetscSectionSetUp(sectionMass)); 783 PetscCall(DMSetLocalSection(dmMass, sectionMass)); 784 PetscCall(PetscSectionDestroy(§ionMass)); 785 PetscCall(DMGetLocalVector(dmMass, massMatrix)); 786 PetscCall(VecGetArray(*massMatrix, &m)); 787 PetscCall(DMPlexGetGeometryFVM(plex, &facegeom, &cellgeom, NULL)); 788 PetscCall(VecGetDM(facegeom, &dmFace)); 789 PetscCall(VecGetArrayRead(facegeom, &fgeom)); 790 PetscCall(VecGetDM(cellgeom, &dmCell)); 791 PetscCall(VecGetArrayRead(cellgeom, &cgeom)); 792 PetscCall(DMGetCoordinateDM(dm, &dmCoord)); 793 PetscCall(VecGetArrayRead(coordinates, &coords)); 794 for (v = vStart; v < vEnd; ++v) { 795 const PetscInt *faces; 796 PetscFVFaceGeom *fgA, *fgB, *cg; 797 PetscScalar *vertex; 798 PetscInt numFaces, sides[2], f, g; 799 800 PetscCall(DMPlexPointLocalRead(dmCoord, v, coords, &vertex)); 801 PetscCall(DMPlexGetSupportSize(dmMass, v, &numFaces)); 802 PetscCall(DMPlexGetSupport(dmMass, v, &faces)); 803 for (f = 0; f < numFaces; ++f) { 804 sides[0] = faces[f]; 805 PetscCall(DMPlexPointLocalRead(dmFace, faces[f], fgeom, &fgA)); 806 for (g = 0; g < numFaces; ++g) { 807 const PetscInt *cells = NULL; 808 PetscReal area = 0.0; 809 PetscInt numCells; 810 811 sides[1] = faces[g]; 812 PetscCall(DMPlexPointLocalRead(dmFace, faces[g], fgeom, &fgB)); 813 PetscCall(DMPlexGetJoin(dmMass, 2, sides, &numCells, &cells)); 814 PetscCheck(numCells == 1, PETSC_COMM_SELF, PETSC_ERR_LIB, "Invalid join for faces"); 815 PetscCall(DMPlexPointLocalRead(dmCell, cells[0], cgeom, &cg)); 816 area += PetscAbsScalar((vertex[0] - cg->centroid[0]) * (fgA->centroid[1] - cg->centroid[1]) - (vertex[1] - cg->centroid[1]) * (fgA->centroid[0] - cg->centroid[0])); 817 area += PetscAbsScalar((vertex[0] - cg->centroid[0]) * (fgB->centroid[1] - cg->centroid[1]) - (vertex[1] - cg->centroid[1]) * (fgB->centroid[0] - cg->centroid[0])); 818 m[f * numFaces + g] = Dot2Real(fgA->normal, fgB->normal) * area * 0.5; 819 PetscCall(DMPlexRestoreJoin(dmMass, 2, sides, &numCells, &cells)); 820 } 821 } 822 } 823 PetscCall(VecRestoreArrayRead(facegeom, &fgeom)); 824 PetscCall(VecRestoreArrayRead(cellgeom, &cgeom)); 825 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 826 PetscCall(VecRestoreArray(*massMatrix, &m)); 827 PetscCall(DMDestroy(&dmMass)); 828 PetscCall(DMDestroy(&plex)); 829 PetscFunctionReturn(PETSC_SUCCESS); 830 } 831 832 /* Behavior will be different for multi-physics or when using non-default boundary conditions */ 833 static PetscErrorCode ModelSolutionSetDefault(Model mod, SolutionFunction func, PetscCtx ctx) 834 { 835 PetscFunctionBeginUser; 836 mod->solution = func; 837 mod->solutionctx = ctx; 838 PetscFunctionReturn(PETSC_SUCCESS); 839 } 840 841 static PetscErrorCode ModelFunctionalRegister(Model mod, const char *name, PetscInt *offset, FunctionalFunction func, PetscCtx ctx) 842 { 843 FunctionalLink link, *ptr; 844 PetscInt lastoffset = -1; 845 846 PetscFunctionBeginUser; 847 for (ptr = &mod->functionalRegistry; *ptr; ptr = &(*ptr)->next) lastoffset = (*ptr)->offset; 848 PetscCall(PetscNew(&link)); 849 PetscCall(PetscStrallocpy(name, &link->name)); 850 link->offset = lastoffset + 1; 851 link->func = func; 852 link->ctx = ctx; 853 link->next = NULL; 854 *ptr = link; 855 *offset = link->offset; 856 PetscFunctionReturn(PETSC_SUCCESS); 857 } 858 859 static PetscErrorCode ModelFunctionalSetFromOptions(Model mod, PetscOptionItems PetscOptionsObject) 860 { 861 PetscInt i, j; 862 FunctionalLink link; 863 char *names[256]; 864 865 PetscFunctionBeginUser; 866 mod->numMonitored = PETSC_STATIC_ARRAY_LENGTH(names); 867 PetscCall(PetscOptionsStringArray("-monitor", "list of functionals to monitor", "", names, &mod->numMonitored, NULL)); 868 /* Create list of functionals that will be computed somehow */ 869 PetscCall(PetscMalloc1(mod->numMonitored, &mod->functionalMonitored)); 870 /* Create index of calls that we will have to make to compute these functionals (over-allocation in general). */ 871 PetscCall(PetscMalloc1(mod->numMonitored, &mod->functionalCall)); 872 mod->numCall = 0; 873 for (i = 0; i < mod->numMonitored; i++) { 874 for (link = mod->functionalRegistry; link; link = link->next) { 875 PetscBool match; 876 PetscCall(PetscStrcasecmp(names[i], link->name, &match)); 877 if (match) break; 878 } 879 PetscCheck(link, mod->comm, PETSC_ERR_USER, "No known functional '%s'", names[i]); 880 mod->functionalMonitored[i] = link; 881 for (j = 0; j < i; j++) { 882 if (mod->functionalCall[j]->func == link->func && mod->functionalCall[j]->ctx == link->ctx) goto next_name; 883 } 884 mod->functionalCall[mod->numCall++] = link; /* Just points to the first link using the result. There may be more results. */ 885 next_name: 886 PetscCall(PetscFree(names[i])); 887 } 888 889 /* Find out the maximum index of any functional computed by a function we will be calling (even if we are not using it) */ 890 mod->maxComputed = -1; 891 for (link = mod->functionalRegistry; link; link = link->next) { 892 for (i = 0; i < mod->numCall; i++) { 893 FunctionalLink call = mod->functionalCall[i]; 894 if (link->func == call->func && link->ctx == call->ctx) mod->maxComputed = PetscMax(mod->maxComputed, link->offset); 895 } 896 } 897 PetscFunctionReturn(PETSC_SUCCESS); 898 } 899 900 static PetscErrorCode FunctionalLinkDestroy(FunctionalLink *link) 901 { 902 FunctionalLink l, next; 903 904 PetscFunctionBeginUser; 905 if (!link) PetscFunctionReturn(PETSC_SUCCESS); 906 l = *link; 907 *link = NULL; 908 for (; l; l = next) { 909 next = l->next; 910 PetscCall(PetscFree(l->name)); 911 PetscCall(PetscFree(l)); 912 } 913 PetscFunctionReturn(PETSC_SUCCESS); 914 } 915 916 /* put the solution callback into a functional callback */ 917 static PetscErrorCode SolutionFunctional(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar *u, void *modctx) 918 { 919 Model mod; 920 921 PetscFunctionBeginUser; 922 mod = (Model)modctx; 923 PetscCall((*mod->solution)(mod, time, x, u, mod->solutionctx)); 924 PetscFunctionReturn(PETSC_SUCCESS); 925 } 926 927 PetscErrorCode SetInitialCondition(DM dm, Vec X, User user) 928 { 929 PetscErrorCode (*func[1])(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar *u, PetscCtx ctx); 930 PetscCtx ctx[1]; 931 Model mod = user->model; 932 933 PetscFunctionBeginUser; 934 func[0] = SolutionFunctional; 935 ctx[0] = (void *)mod; 936 PetscCall(DMProjectFunction(dm, 0.0, func, ctx, INSERT_ALL_VALUES, X)); 937 PetscFunctionReturn(PETSC_SUCCESS); 938 } 939 940 static PetscErrorCode OutputVTK(DM dm, const char *filename, PetscViewer *viewer) 941 { 942 PetscFunctionBeginUser; 943 PetscCall(PetscViewerCreate(PetscObjectComm((PetscObject)dm), viewer)); 944 PetscCall(PetscViewerSetType(*viewer, PETSCVIEWERVTK)); 945 PetscCall(PetscViewerFileSetName(*viewer, filename)); 946 PetscFunctionReturn(PETSC_SUCCESS); 947 } 948 949 static PetscErrorCode MonitorVTK(TS ts, PetscInt stepnum, PetscReal time, Vec X, PetscCtx ctx) 950 { 951 User user = (User)ctx; 952 DM dm, plex; 953 PetscViewer viewer; 954 char filename[PETSC_MAX_PATH_LEN], *ftable = NULL; 955 PetscReal xnorm; 956 PetscBool rollback; 957 958 PetscFunctionBeginUser; 959 PetscCall(TSGetStepRollBack(ts, &rollback)); 960 if (rollback) PetscFunctionReturn(PETSC_SUCCESS); 961 PetscCall(PetscObjectSetName((PetscObject)X, "u")); 962 PetscCall(VecGetDM(X, &dm)); 963 PetscCall(VecNorm(X, NORM_INFINITY, &xnorm)); 964 965 if (stepnum >= 0) stepnum += user->monitorStepOffset; 966 if (stepnum >= 0) { /* No summary for final time */ 967 Model mod = user->model; 968 Vec cellgeom; 969 PetscInt c, cStart, cEnd, fcount, i; 970 size_t ftableused, ftablealloc; 971 const PetscScalar *cgeom, *x; 972 DM dmCell; 973 DMLabel vtkLabel; 974 PetscReal *fmin, *fmax, *fintegral, *ftmp; 975 976 PetscCall(DMConvert(dm, DMPLEX, &plex)); 977 PetscCall(DMPlexGetGeometryFVM(plex, NULL, &cellgeom, NULL)); 978 fcount = mod->maxComputed + 1; 979 PetscCall(PetscMalloc4(fcount, &fmin, fcount, &fmax, fcount, &fintegral, fcount, &ftmp)); 980 for (i = 0; i < fcount; i++) { 981 fmin[i] = PETSC_MAX_REAL; 982 fmax[i] = PETSC_MIN_REAL; 983 fintegral[i] = 0; 984 } 985 PetscCall(VecGetDM(cellgeom, &dmCell)); 986 PetscCall(DMPlexGetSimplexOrBoxCells(dmCell, 0, &cStart, &cEnd)); 987 PetscCall(VecGetArrayRead(cellgeom, &cgeom)); 988 PetscCall(VecGetArrayRead(X, &x)); 989 PetscCall(DMGetLabel(dm, "vtk", &vtkLabel)); 990 for (c = cStart; c < cEnd; ++c) { 991 PetscFVCellGeom *cg; 992 const PetscScalar *cx = NULL; 993 PetscInt vtkVal = 0; 994 995 /* not that these two routines as currently implemented work for any dm with a 996 * localSection/globalSection */ 997 PetscCall(DMPlexPointLocalRead(dmCell, c, cgeom, &cg)); 998 PetscCall(DMPlexPointGlobalRead(dm, c, x, &cx)); 999 if (vtkLabel) PetscCall(DMLabelGetValue(vtkLabel, c, &vtkVal)); 1000 if (!vtkVal || !cx) continue; /* ghost, or not a global cell */ 1001 for (i = 0; i < mod->numCall; i++) { 1002 FunctionalLink flink = mod->functionalCall[i]; 1003 PetscCall((*flink->func)(mod, time, cg->centroid, cx, ftmp, flink->ctx)); 1004 } 1005 for (i = 0; i < fcount; i++) { 1006 fmin[i] = PetscMin(fmin[i], ftmp[i]); 1007 fmax[i] = PetscMax(fmax[i], ftmp[i]); 1008 fintegral[i] += cg->volume * ftmp[i]; 1009 } 1010 } 1011 PetscCall(VecRestoreArrayRead(cellgeom, &cgeom)); 1012 PetscCall(VecRestoreArrayRead(X, &x)); 1013 PetscCall(DMDestroy(&plex)); 1014 PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, fmin, (PetscMPIInt)fcount, MPIU_REAL, MPIU_MIN, PetscObjectComm((PetscObject)ts))); 1015 PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, fmax, (PetscMPIInt)fcount, MPIU_REAL, MPIU_MAX, PetscObjectComm((PetscObject)ts))); 1016 PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, fintegral, (PetscMPIInt)fcount, MPIU_REAL, MPIU_SUM, PetscObjectComm((PetscObject)ts))); 1017 1018 ftablealloc = fcount * 100; 1019 ftableused = 0; 1020 PetscCall(PetscMalloc1(ftablealloc, &ftable)); 1021 for (i = 0; i < mod->numMonitored; i++) { 1022 size_t countused; 1023 char buffer[256], *p; 1024 FunctionalLink flink = mod->functionalMonitored[i]; 1025 PetscInt id = flink->offset; 1026 if (i % 3) { 1027 PetscCall(PetscArraycpy(buffer, " ", 2)); 1028 p = buffer + 2; 1029 } else if (i) { 1030 char newline[] = "\n"; 1031 PetscCall(PetscMemcpy(buffer, newline, sizeof(newline) - 1)); 1032 p = buffer + sizeof(newline) - 1; 1033 } else { 1034 p = buffer; 1035 } 1036 PetscCall(PetscSNPrintfCount(p, sizeof buffer - (p - buffer), "%12s [%10.7g,%10.7g] int %10.7g", &countused, flink->name, (double)fmin[id], (double)fmax[id], (double)fintegral[id])); 1037 countused--; 1038 countused += p - buffer; 1039 if (countused > ftablealloc - ftableused - 1) { /* reallocate */ 1040 char *ftablenew; 1041 ftablealloc = 2 * ftablealloc + countused; 1042 PetscCall(PetscMalloc(ftablealloc, &ftablenew)); 1043 PetscCall(PetscArraycpy(ftablenew, ftable, ftableused)); 1044 PetscCall(PetscFree(ftable)); 1045 ftable = ftablenew; 1046 } 1047 PetscCall(PetscArraycpy(ftable + ftableused, buffer, countused)); 1048 ftableused += countused; 1049 ftable[ftableused] = 0; 1050 } 1051 PetscCall(PetscFree4(fmin, fmax, fintegral, ftmp)); 1052 1053 PetscCall(PetscPrintf(PetscObjectComm((PetscObject)ts), "% 3" PetscInt_FMT " time %8.4g |x| %8.4g %s\n", stepnum, (double)time, (double)xnorm, ftable ? ftable : "")); 1054 PetscCall(PetscFree(ftable)); 1055 } 1056 if (user->vtkInterval < 1) PetscFunctionReturn(PETSC_SUCCESS); 1057 if ((stepnum == -1) ^ (stepnum % user->vtkInterval == 0)) { 1058 if (stepnum == -1) { /* Final time is not multiple of normal time interval, write it anyway */ 1059 PetscCall(TSGetStepNumber(ts, &stepnum)); 1060 } 1061 PetscCall(PetscSNPrintf(filename, sizeof filename, "%s-%03" PetscInt_FMT ".vtu", user->outputBasename, stepnum)); 1062 PetscCall(OutputVTK(dm, filename, &viewer)); 1063 PetscCall(VecView(X, viewer)); 1064 PetscCall(PetscViewerDestroy(&viewer)); 1065 } 1066 PetscFunctionReturn(PETSC_SUCCESS); 1067 } 1068 1069 static PetscErrorCode initializeTS(DM dm, User user, TS *ts) 1070 { 1071 #ifdef PETSC_HAVE_LIBCEED 1072 PetscBool useCeed; 1073 #endif 1074 1075 PetscFunctionBeginUser; 1076 PetscCall(TSCreate(PetscObjectComm((PetscObject)dm), ts)); 1077 PetscCall(TSSetType(*ts, TSSSP)); 1078 PetscCall(TSSetDM(*ts, dm)); 1079 if (user->vtkmon) PetscCall(TSMonitorSet(*ts, MonitorVTK, user, NULL)); 1080 PetscCall(DMTSSetBoundaryLocal(dm, DMPlexTSComputeBoundary, user)); 1081 #ifdef PETSC_HAVE_LIBCEED 1082 PetscCall(DMPlexGetUseCeed(dm, &useCeed)); 1083 if (useCeed) PetscCall(DMTSSetRHSFunctionLocal(dm, DMPlexTSComputeRHSFunctionFVMCEED, user)); 1084 else 1085 #endif 1086 PetscCall(DMTSSetRHSFunctionLocal(dm, DMPlexTSComputeRHSFunctionFVM, user)); 1087 PetscCall(TSSetMaxTime(*ts, 2.0)); 1088 PetscCall(TSSetExactFinalTime(*ts, TS_EXACTFINALTIME_STEPOVER)); 1089 PetscFunctionReturn(PETSC_SUCCESS); 1090 } 1091 1092 typedef struct { 1093 PetscFV fvm; 1094 VecTagger refineTag; 1095 VecTagger coarsenTag; 1096 DM adaptedDM; 1097 User user; 1098 PetscReal cfl; 1099 PetscLimiter limiter; 1100 PetscLimiter noneLimiter; 1101 } TransferCtx; 1102 1103 static PetscErrorCode adaptToleranceFVMSetUp(TS ts, PetscInt nstep, PetscReal time, Vec sol, PetscBool *resize, PetscCtx ctx) 1104 { 1105 TransferCtx *tctx = (TransferCtx *)ctx; 1106 PetscFV fvm = tctx->fvm; 1107 VecTagger refineTag = tctx->refineTag; 1108 VecTagger coarsenTag = tctx->coarsenTag; 1109 User user = tctx->user; 1110 DM dm, gradDM, plex, cellDM, adaptedDM = NULL; 1111 Vec cellGeom, faceGeom; 1112 PetscBool computeGradient; 1113 Vec grad, locGrad, locX, errVec; 1114 PetscInt cStart, cEnd, c, dim, nRefine, nCoarsen; 1115 PetscReal minMaxInd[2] = {PETSC_MAX_REAL, PETSC_MIN_REAL}, minMaxIndGlobal[2]; 1116 PetscScalar *errArray; 1117 const PetscScalar *pointVals; 1118 const PetscScalar *pointGrads; 1119 const PetscScalar *pointGeom; 1120 DMLabel adaptLabel = NULL; 1121 IS refineIS, coarsenIS; 1122 1123 PetscFunctionBeginUser; 1124 *resize = PETSC_FALSE; 1125 PetscCall(VecGetDM(sol, &dm)); 1126 PetscCall(DMGetDimension(dm, &dim)); 1127 PetscCall(PetscFVSetLimiter(fvm, tctx->noneLimiter)); 1128 PetscCall(PetscFVGetComputeGradients(fvm, &computeGradient)); 1129 PetscCall(PetscFVSetComputeGradients(fvm, PETSC_TRUE)); 1130 PetscCall(DMConvert(dm, DMPLEX, &plex)); 1131 PetscCall(DMPlexGetDataFVM(plex, fvm, &cellGeom, &faceGeom, &gradDM)); 1132 PetscCall(DMCreateLocalVector(plex, &locX)); 1133 PetscCall(DMPlexInsertBoundaryValues(plex, PETSC_TRUE, locX, 0.0, faceGeom, cellGeom, NULL)); 1134 PetscCall(DMGlobalToLocalBegin(plex, sol, INSERT_VALUES, locX)); 1135 PetscCall(DMGlobalToLocalEnd(plex, sol, INSERT_VALUES, locX)); 1136 PetscCall(DMCreateGlobalVector(gradDM, &grad)); 1137 PetscCall(DMPlexReconstructGradientsFVM(plex, locX, grad)); 1138 PetscCall(DMCreateLocalVector(gradDM, &locGrad)); 1139 PetscCall(DMGlobalToLocalBegin(gradDM, grad, INSERT_VALUES, locGrad)); 1140 PetscCall(DMGlobalToLocalEnd(gradDM, grad, INSERT_VALUES, locGrad)); 1141 PetscCall(VecDestroy(&grad)); 1142 PetscCall(DMPlexGetSimplexOrBoxCells(plex, 0, &cStart, &cEnd)); 1143 PetscCall(VecGetArrayRead(locGrad, &pointGrads)); 1144 PetscCall(VecGetArrayRead(cellGeom, &pointGeom)); 1145 PetscCall(VecGetArrayRead(locX, &pointVals)); 1146 PetscCall(VecGetDM(cellGeom, &cellDM)); 1147 PetscCall(DMLabelCreate(PETSC_COMM_SELF, "adapt", &adaptLabel)); 1148 PetscCall(VecCreateFromOptions(PetscObjectComm((PetscObject)plex), NULL, 1, cEnd - cStart, PETSC_DETERMINE, &errVec)); 1149 PetscCall(VecSetUp(errVec)); 1150 PetscCall(VecGetArray(errVec, &errArray)); 1151 for (c = cStart; c < cEnd; c++) { 1152 PetscReal errInd = 0.; 1153 PetscScalar *pointGrad; 1154 PetscScalar *pointVal; 1155 PetscFVCellGeom *cg; 1156 1157 PetscCall(DMPlexPointLocalRead(gradDM, c, pointGrads, &pointGrad)); 1158 PetscCall(DMPlexPointLocalRead(cellDM, c, pointGeom, &cg)); 1159 PetscCall(DMPlexPointLocalRead(plex, c, pointVals, &pointVal)); 1160 1161 PetscCall((*user->model->errorIndicator)(dim, cg->volume, user->model->physics->dof, pointVal, pointGrad, &errInd, user->model->errorCtx)); 1162 errArray[c - cStart] = errInd; 1163 minMaxInd[0] = PetscMin(minMaxInd[0], errInd); 1164 minMaxInd[1] = PetscMax(minMaxInd[1], errInd); 1165 } 1166 PetscCall(VecRestoreArray(errVec, &errArray)); 1167 PetscCall(VecRestoreArrayRead(locX, &pointVals)); 1168 PetscCall(VecRestoreArrayRead(cellGeom, &pointGeom)); 1169 PetscCall(VecRestoreArrayRead(locGrad, &pointGrads)); 1170 PetscCall(VecDestroy(&locGrad)); 1171 PetscCall(VecDestroy(&locX)); 1172 PetscCall(DMDestroy(&plex)); 1173 1174 PetscCall(VecTaggerComputeIS(refineTag, errVec, &refineIS, NULL)); 1175 PetscCall(VecTaggerComputeIS(coarsenTag, errVec, &coarsenIS, NULL)); 1176 PetscCall(ISGetSize(refineIS, &nRefine)); 1177 PetscCall(ISGetSize(coarsenIS, &nCoarsen)); 1178 if (nRefine) PetscCall(DMLabelSetStratumIS(adaptLabel, DM_ADAPT_REFINE, refineIS)); 1179 if (nCoarsen) PetscCall(DMLabelSetStratumIS(adaptLabel, DM_ADAPT_COARSEN, coarsenIS)); 1180 PetscCall(ISDestroy(&coarsenIS)); 1181 PetscCall(ISDestroy(&refineIS)); 1182 PetscCall(VecDestroy(&errVec)); 1183 1184 PetscCall(PetscFVSetComputeGradients(fvm, computeGradient)); 1185 PetscCall(PetscFVSetLimiter(fvm, tctx->limiter)); 1186 minMaxInd[1] = -minMaxInd[1]; 1187 PetscCallMPI(MPIU_Allreduce(minMaxInd, minMaxIndGlobal, 2, MPIU_REAL, MPI_MIN, PetscObjectComm((PetscObject)dm))); 1188 PetscCall(PetscInfo(ts, "error indicator range (%E, %E)\n", (double)minMaxIndGlobal[0], (double)(-minMaxIndGlobal[1]))); 1189 if (nRefine || nCoarsen) { /* at least one cell is over the refinement threshold */ 1190 PetscCall(DMAdaptLabel(dm, adaptLabel, &adaptedDM)); 1191 } 1192 PetscCall(DMLabelDestroy(&adaptLabel)); 1193 if (adaptedDM) { 1194 tctx->adaptedDM = adaptedDM; 1195 PetscCall(PetscInfo(ts, "Step %" PetscInt_FMT " adapted mesh, marking %" PetscInt_FMT " cells for refinement, and %" PetscInt_FMT " cells for coarsening\n", nstep, nRefine, nCoarsen)); 1196 *resize = PETSC_TRUE; 1197 } else { 1198 PetscCall(PetscInfo(ts, "Step %" PetscInt_FMT " no adaptation\n", nstep)); 1199 } 1200 PetscFunctionReturn(PETSC_SUCCESS); 1201 } 1202 1203 static PetscErrorCode Transfer(TS ts, PetscInt nv, Vec vecsin[], Vec vecsout[], PetscCtx ctx) 1204 { 1205 TransferCtx *tctx = (TransferCtx *)ctx; 1206 DM dm; 1207 PetscReal time; 1208 1209 PetscFunctionBeginUser; 1210 PetscCall(TSGetDM(ts, &dm)); 1211 PetscCall(TSGetTime(ts, &time)); 1212 PetscCheck(tctx->adaptedDM, PetscObjectComm((PetscObject)ts), PETSC_ERR_ARG_WRONGSTATE, "Missing adaptedDM"); 1213 for (PetscInt i = 0; i < nv; i++) { 1214 PetscCall(DMCreateGlobalVector(tctx->adaptedDM, &vecsout[i])); 1215 PetscCall(DMForestTransferVec(dm, vecsin[i], tctx->adaptedDM, vecsout[i], PETSC_TRUE, time)); 1216 } 1217 PetscCall(DMForestSetAdaptivityForest(tctx->adaptedDM, NULL)); /* clear internal references to the previous dm */ 1218 1219 Model mod = tctx->user->model; 1220 Physics phys = mod->physics; 1221 PetscReal minRadius; 1222 1223 PetscCall(DMPlexGetGeometryFVM(tctx->adaptedDM, NULL, NULL, &minRadius)); 1224 PetscCallMPI(MPIU_Allreduce(&phys->maxspeed, &mod->maxspeed, 1, MPIU_REAL, MPIU_MAX, PetscObjectComm((PetscObject)ts))); 1225 PetscCheck(mod->maxspeed > 0, PetscObjectComm((PetscObject)ts), PETSC_ERR_ARG_WRONGSTATE, "Physics did not set maxspeed"); 1226 1227 PetscReal dt = tctx->cfl * minRadius / mod->maxspeed; 1228 PetscCall(TSSetTimeStep(ts, dt)); 1229 1230 PetscCall(TSSetDM(ts, tctx->adaptedDM)); 1231 PetscCall(DMDestroy(&tctx->adaptedDM)); 1232 PetscFunctionReturn(PETSC_SUCCESS); 1233 } 1234 1235 int main(int argc, char **argv) 1236 { 1237 MPI_Comm comm; 1238 PetscDS prob; 1239 PetscFV fvm; 1240 PetscLimiter limiter = NULL, noneLimiter = NULL; 1241 User user; 1242 Model mod; 1243 Physics phys; 1244 DM dm, plex; 1245 PetscReal ftime, cfl, dt, minRadius; 1246 PetscInt dim, nsteps; 1247 TS ts; 1248 TSConvergedReason reason; 1249 Vec X; 1250 PetscViewer viewer; 1251 PetscBool vtkCellGeom, useAMR; 1252 PetscInt adaptInterval; 1253 char physname[256] = "advect"; 1254 VecTagger refineTag = NULL, coarsenTag = NULL; 1255 TransferCtx tctx; 1256 1257 PetscFunctionBeginUser; 1258 PetscCall(PetscInitialize(&argc, &argv, NULL, help)); 1259 comm = PETSC_COMM_WORLD; 1260 1261 PetscCall(PetscNew(&user)); 1262 PetscCall(PetscNew(&user->model)); 1263 PetscCall(PetscNew(&user->model->physics)); 1264 mod = user->model; 1265 phys = mod->physics; 1266 mod->comm = comm; 1267 useAMR = PETSC_FALSE; 1268 adaptInterval = 1; 1269 1270 /* Register physical models to be available on the command line */ 1271 PetscCall(PetscFunctionListAdd(&PhysicsList, "advect", PhysicsCreate_Advect)); 1272 PetscCall(PetscFunctionListAdd(&PhysicsList, "sw", PhysicsCreate_SW)); 1273 PetscCall(PetscFunctionListAdd(&PhysicsList, "euler", PhysicsCreate_Euler)); 1274 1275 PetscOptionsBegin(comm, NULL, "Unstructured Finite Volume Mesh Options", ""); 1276 { 1277 cfl = 0.9 * 4; /* default SSPRKS2 with s=5 stages is stable for CFL number s-1 */ 1278 PetscCall(PetscOptionsReal("-ufv_cfl", "CFL number per step", "", cfl, &cfl, NULL)); 1279 user->vtkInterval = 1; 1280 PetscCall(PetscOptionsInt("-ufv_vtk_interval", "VTK output interval (0 to disable)", "", user->vtkInterval, &user->vtkInterval, NULL)); 1281 user->vtkmon = PETSC_TRUE; 1282 PetscCall(PetscOptionsBool("-ufv_vtk_monitor", "Use VTKMonitor routine", "", user->vtkmon, &user->vtkmon, NULL)); 1283 vtkCellGeom = PETSC_FALSE; 1284 PetscCall(PetscStrncpy(user->outputBasename, "ex11", sizeof(user->outputBasename))); 1285 PetscCall(PetscOptionsString("-ufv_vtk_basename", "VTK output basename", "", user->outputBasename, user->outputBasename, sizeof(user->outputBasename), NULL)); 1286 PetscCall(PetscOptionsBool("-ufv_vtk_cellgeom", "Write cell geometry (for debugging)", "", vtkCellGeom, &vtkCellGeom, NULL)); 1287 PetscCall(PetscOptionsBool("-ufv_use_amr", "use local adaptive mesh refinement", "", useAMR, &useAMR, NULL)); 1288 PetscCall(PetscOptionsInt("-ufv_adapt_interval", "time steps between AMR", "", adaptInterval, &adaptInterval, NULL)); 1289 } 1290 PetscOptionsEnd(); 1291 1292 if (useAMR) { 1293 VecTaggerBox refineBox, coarsenBox; 1294 1295 refineBox.min = refineBox.max = PETSC_MAX_REAL; 1296 coarsenBox.min = coarsenBox.max = PETSC_MIN_REAL; 1297 1298 PetscCall(VecTaggerCreate(comm, &refineTag)); 1299 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)refineTag, "refine_")); 1300 PetscCall(VecTaggerSetType(refineTag, VECTAGGERABSOLUTE)); 1301 PetscCall(VecTaggerAbsoluteSetBox(refineTag, &refineBox)); 1302 PetscCall(VecTaggerSetFromOptions(refineTag)); 1303 PetscCall(VecTaggerSetUp(refineTag)); 1304 PetscCall(PetscObjectViewFromOptions((PetscObject)refineTag, NULL, "-tag_view")); 1305 1306 PetscCall(VecTaggerCreate(comm, &coarsenTag)); 1307 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)coarsenTag, "coarsen_")); 1308 PetscCall(VecTaggerSetType(coarsenTag, VECTAGGERABSOLUTE)); 1309 PetscCall(VecTaggerAbsoluteSetBox(coarsenTag, &coarsenBox)); 1310 PetscCall(VecTaggerSetFromOptions(coarsenTag)); 1311 PetscCall(VecTaggerSetUp(coarsenTag)); 1312 PetscCall(PetscObjectViewFromOptions((PetscObject)coarsenTag, NULL, "-tag_view")); 1313 } 1314 1315 PetscOptionsBegin(comm, NULL, "Unstructured Finite Volume Physics Options", ""); 1316 { 1317 PetscErrorCode (*physcreate)(Model, Physics, PetscOptionItems); 1318 PetscCall(PetscOptionsFList("-physics", "Physics module to solve", "", PhysicsList, physname, physname, sizeof physname, NULL)); 1319 PetscCall(PetscFunctionListFind(PhysicsList, physname, &physcreate)); 1320 PetscCall(PetscMemzero(phys, sizeof(struct _n_Physics))); 1321 PetscCall((*physcreate)(mod, phys, PetscOptionsObject)); 1322 /* Count number of fields and dofs */ 1323 for (phys->nfields = 0, phys->dof = 0; phys->field_desc[phys->nfields].name; phys->nfields++) phys->dof += phys->field_desc[phys->nfields].dof; 1324 PetscCheck(phys->dof > 0, comm, PETSC_ERR_ARG_WRONGSTATE, "Physics '%s' did not set dof", physname); 1325 PetscCall(ModelFunctionalSetFromOptions(mod, PetscOptionsObject)); 1326 } 1327 PetscOptionsEnd(); 1328 1329 /* Create mesh */ 1330 { 1331 PetscInt i; 1332 1333 PetscCall(DMCreate(comm, &dm)); 1334 PetscCall(DMSetType(dm, DMPLEX)); 1335 PetscCall(DMSetFromOptions(dm)); 1336 for (i = 0; i < DIM; i++) { 1337 mod->bounds[2 * i] = 0.; 1338 mod->bounds[2 * i + 1] = 1.; 1339 } 1340 dim = DIM; 1341 { /* a null name means just do a hex box */ 1342 PetscInt cells[3] = {1, 1, 1}, n = 3; 1343 PetscBool flg2, skew = PETSC_FALSE; 1344 PetscInt nret2 = 2 * DIM; 1345 PetscOptionsBegin(comm, NULL, "Rectangular mesh options", ""); 1346 PetscCall(PetscOptionsRealArray("-grid_bounds", "bounds of the mesh in each direction (i.e., x_min,x_max,y_min,y_max", "", mod->bounds, &nret2, &flg2)); 1347 PetscCall(PetscOptionsBool("-grid_skew_60", "Skew grid for 60 degree shock mesh", "", skew, &skew, NULL)); 1348 PetscCall(PetscOptionsIntArray("-dm_plex_box_faces", "Number of faces along each dimension", "", cells, &n, NULL)); 1349 PetscOptionsEnd(); 1350 /* TODO Rewrite this with Mark, and remove grid_bounds at that time */ 1351 if (flg2) { 1352 PetscInt dimEmbed, i; 1353 PetscInt nCoords; 1354 PetscScalar *coords; 1355 Vec coordinates; 1356 1357 PetscCall(DMGetCoordinatesLocal(dm, &coordinates)); 1358 PetscCall(DMGetCoordinateDim(dm, &dimEmbed)); 1359 PetscCall(VecGetLocalSize(coordinates, &nCoords)); 1360 PetscCheck(!(nCoords % dimEmbed), PETSC_COMM_SELF, PETSC_ERR_ARG_SIZ, "Coordinate vector the wrong size"); 1361 PetscCall(VecGetArray(coordinates, &coords)); 1362 for (i = 0; i < nCoords; i += dimEmbed) { 1363 PetscInt j; 1364 1365 PetscScalar *coord = &coords[i]; 1366 for (j = 0; j < dimEmbed; j++) { 1367 coord[j] = mod->bounds[2 * j] + coord[j] * (mod->bounds[2 * j + 1] - mod->bounds[2 * j]); 1368 if (dim == 2 && cells[1] == 1 && j == 0 && skew) { 1369 if (cells[0] == 2 && i == 8) { 1370 coord[j] = .57735026918963; /* hack to get 60 deg skewed mesh */ 1371 } else if (cells[0] == 3) { 1372 if (i == 2 || i == 10) coord[j] = mod->bounds[1] / 4.; 1373 else if (i == 4) coord[j] = mod->bounds[1] / 2.; 1374 else if (i == 12) coord[j] = 1.57735026918963 * mod->bounds[1] / 2.; 1375 } 1376 } 1377 } 1378 } 1379 PetscCall(VecRestoreArray(coordinates, &coords)); 1380 PetscCall(DMSetCoordinatesLocal(dm, coordinates)); 1381 } 1382 } 1383 } 1384 PetscCall(DMViewFromOptions(dm, NULL, "-orig_dm_view")); 1385 PetscCall(DMGetDimension(dm, &dim)); 1386 1387 /* set up BCs, functions, tags */ 1388 PetscCall(DMCreateLabel(dm, "Face Sets")); 1389 mod->errorIndicator = ErrorIndicator_Simple; 1390 1391 { 1392 DM gdm; 1393 1394 PetscCall(DMPlexConstructGhostCells(dm, NULL, NULL, &gdm)); 1395 PetscCall(DMDestroy(&dm)); 1396 dm = gdm; 1397 PetscCall(DMViewFromOptions(dm, NULL, "-dm_view")); 1398 } 1399 1400 PetscCall(PetscFVCreate(comm, &fvm)); 1401 PetscCall(PetscFVSetFromOptions(fvm)); 1402 PetscCall(PetscFVSetNumComponents(fvm, phys->dof)); 1403 PetscCall(PetscFVSetSpatialDimension(fvm, dim)); 1404 PetscCall(PetscObjectSetName((PetscObject)fvm, "")); 1405 { 1406 PetscInt f, dof; 1407 for (f = 0, dof = 0; f < phys->nfields; f++) { 1408 PetscInt newDof = phys->field_desc[f].dof; 1409 1410 if (newDof == 1) { 1411 PetscCall(PetscFVSetComponentName(fvm, dof, phys->field_desc[f].name)); 1412 } else { 1413 PetscInt j; 1414 1415 for (j = 0; j < newDof; j++) { 1416 char compName[256] = "Unknown"; 1417 1418 PetscCall(PetscSNPrintf(compName, sizeof(compName), "%s_%" PetscInt_FMT, phys->field_desc[f].name, j)); 1419 PetscCall(PetscFVSetComponentName(fvm, dof + j, compName)); 1420 } 1421 } 1422 dof += newDof; 1423 } 1424 } 1425 /* FV is now structured with one field having all physics as components */ 1426 PetscCall(DMAddField(dm, NULL, (PetscObject)fvm)); 1427 PetscCall(DMCreateDS(dm)); 1428 PetscCall(DMGetDS(dm, &prob)); 1429 PetscCall(PetscDSSetRiemannSolver(prob, 0, user->model->physics->riemann)); 1430 PetscCall(PetscDSSetContext(prob, 0, user->model->physics)); 1431 PetscCall((*mod->setupbc)(dm, prob, phys)); 1432 PetscCall(PetscDSSetFromOptions(prob)); 1433 { 1434 char convType[256]; 1435 PetscBool flg; 1436 1437 PetscOptionsBegin(comm, "", "Mesh conversion options", "DMPLEX"); 1438 PetscCall(PetscOptionsFList("-dm_type", "Convert DMPlex to another format", "ex12", DMList, DMPLEX, convType, 256, &flg)); 1439 PetscOptionsEnd(); 1440 if (flg) { 1441 DM dmConv; 1442 1443 PetscCall(DMConvert(dm, convType, &dmConv)); 1444 if (dmConv) { 1445 PetscCall(DMViewFromOptions(dmConv, NULL, "-dm_conv_view")); 1446 PetscCall(DMDestroy(&dm)); 1447 dm = dmConv; 1448 PetscCall(DMSetFromOptions(dm)); 1449 } 1450 } 1451 } 1452 #ifdef PETSC_HAVE_LIBCEED 1453 { 1454 PetscBool useCeed; 1455 PetscCall(DMPlexGetUseCeed(dm, &useCeed)); 1456 if (useCeed) PetscCall((*user->model->setupCEED)(dm, user->model->physics)); 1457 } 1458 #endif 1459 1460 PetscCall(initializeTS(dm, user, &ts)); 1461 1462 PetscCall(DMCreateGlobalVector(dm, &X)); 1463 PetscCall(PetscObjectSetName((PetscObject)X, "solution")); 1464 PetscCall(SetInitialCondition(dm, X, user)); 1465 if (useAMR) { 1466 PetscInt adaptIter; 1467 1468 /* use no limiting when reconstructing gradients for adaptivity */ 1469 PetscCall(PetscFVGetLimiter(fvm, &limiter)); 1470 PetscCall(PetscObjectReference((PetscObject)limiter)); 1471 PetscCall(PetscLimiterCreate(PetscObjectComm((PetscObject)fvm), &noneLimiter)); 1472 PetscCall(PetscLimiterSetType(noneLimiter, PETSCLIMITERNONE)); 1473 1474 /* Refinement context */ 1475 tctx.fvm = fvm; 1476 tctx.refineTag = refineTag; 1477 tctx.coarsenTag = coarsenTag; 1478 tctx.adaptedDM = NULL; 1479 tctx.user = user; 1480 tctx.noneLimiter = noneLimiter; 1481 tctx.limiter = limiter; 1482 tctx.cfl = cfl; 1483 1484 /* Do some initial refinement steps */ 1485 for (adaptIter = 0;; ++adaptIter) { 1486 PetscLogDouble bytes; 1487 PetscBool resize; 1488 1489 PetscCall(PetscMemoryGetCurrentUsage(&bytes)); 1490 PetscCall(PetscInfo(ts, "refinement loop %" PetscInt_FMT ": memory used %g\n", adaptIter, bytes)); 1491 PetscCall(DMViewFromOptions(dm, NULL, "-initial_dm_view")); 1492 PetscCall(VecViewFromOptions(X, NULL, "-initial_vec_view")); 1493 1494 PetscCall(adaptToleranceFVMSetUp(ts, -1, 0.0, X, &resize, &tctx)); 1495 if (!resize) break; 1496 PetscCall(DMDestroy(&dm)); 1497 PetscCall(VecDestroy(&X)); 1498 dm = tctx.adaptedDM; 1499 tctx.adaptedDM = NULL; 1500 PetscCall(TSSetDM(ts, dm)); 1501 PetscCall(DMCreateGlobalVector(dm, &X)); 1502 PetscCall(PetscObjectSetName((PetscObject)X, "solution")); 1503 PetscCall(SetInitialCondition(dm, X, user)); 1504 } 1505 } 1506 1507 PetscCall(DMConvert(dm, DMPLEX, &plex)); 1508 if (vtkCellGeom) { 1509 DM dmCell; 1510 Vec cellgeom, partition; 1511 1512 PetscCall(DMPlexGetGeometryFVM(plex, NULL, &cellgeom, NULL)); 1513 PetscCall(OutputVTK(dm, "ex11-cellgeom.vtk", &viewer)); 1514 PetscCall(VecView(cellgeom, viewer)); 1515 PetscCall(PetscViewerDestroy(&viewer)); 1516 PetscCall(CreatePartitionVec(dm, &dmCell, &partition)); 1517 PetscCall(OutputVTK(dmCell, "ex11-partition.vtk", &viewer)); 1518 PetscCall(VecView(partition, viewer)); 1519 PetscCall(PetscViewerDestroy(&viewer)); 1520 PetscCall(VecDestroy(&partition)); 1521 PetscCall(DMDestroy(&dmCell)); 1522 } 1523 /* collect max maxspeed from all processes -- todo */ 1524 PetscCall(DMPlexGetGeometryFVM(plex, NULL, NULL, &minRadius)); 1525 PetscCall(DMDestroy(&plex)); 1526 PetscCallMPI(MPIU_Allreduce(&phys->maxspeed, &mod->maxspeed, 1, MPIU_REAL, MPIU_MAX, PetscObjectComm((PetscObject)ts))); 1527 PetscCheck(mod->maxspeed > 0, comm, PETSC_ERR_ARG_WRONGSTATE, "Physics '%s' did not set maxspeed", physname); 1528 dt = cfl * minRadius / mod->maxspeed; 1529 PetscCall(TSSetTimeStep(ts, dt)); 1530 PetscCall(TSSetFromOptions(ts)); 1531 1532 /* When using adaptive mesh refinement 1533 specify callbacks to refine the solution 1534 and interpolate data from old to new mesh 1535 When mesh adaption is requested, the step will be rolled back 1536 */ 1537 if (useAMR) PetscCall(TSSetResize(ts, PETSC_TRUE, adaptToleranceFVMSetUp, Transfer, &tctx)); 1538 PetscCall(TSSetSolution(ts, X)); 1539 PetscCall(VecDestroy(&X)); 1540 PetscCall(TSSolve(ts, NULL)); 1541 PetscCall(TSGetSolveTime(ts, &ftime)); 1542 PetscCall(TSGetStepNumber(ts, &nsteps)); 1543 PetscCall(TSGetConvergedReason(ts, &reason)); 1544 PetscCall(PetscPrintf(PETSC_COMM_WORLD, "%s at time %g after %" PetscInt_FMT " steps\n", TSConvergedReasons[reason], (double)ftime, nsteps)); 1545 PetscCall(TSDestroy(&ts)); 1546 1547 PetscCall(VecTaggerDestroy(&refineTag)); 1548 PetscCall(VecTaggerDestroy(&coarsenTag)); 1549 PetscCall(PetscFunctionListDestroy(&PhysicsList)); 1550 PetscCall(PetscFunctionListDestroy(&PhysicsRiemannList_SW)); 1551 PetscCall(PetscFunctionListDestroy(&PhysicsRiemannList_Euler)); 1552 PetscCall(FunctionalLinkDestroy(&user->model->functionalRegistry)); 1553 PetscCall(PetscFree(user->model->functionalMonitored)); 1554 PetscCall(PetscFree(user->model->functionalCall)); 1555 PetscCall(PetscFree(user->model->physics->data)); 1556 PetscCall(PetscFree(user->model->physics)); 1557 PetscCall(PetscFree(user->model)); 1558 PetscCall(PetscFree(user)); 1559 PetscCall(PetscLimiterDestroy(&limiter)); 1560 PetscCall(PetscLimiterDestroy(&noneLimiter)); 1561 PetscCall(PetscFVDestroy(&fvm)); 1562 PetscCall(DMDestroy(&dm)); 1563 PetscCall(PetscFinalize()); 1564 return 0; 1565 } 1566 1567 /* Subroutine to set up the initial conditions for the */ 1568 /* Shock Interface interaction or linear wave (Ravi Samtaney,Mark Adams). */ 1569 /* ----------------------------------------------------------------------- */ 1570 int projecteqstate(PetscReal wc[], const PetscReal ueq[], PetscReal lv[][3]) 1571 { 1572 int j, k; 1573 /* Wc=matmul(lv,Ueq) 3 vars */ 1574 for (k = 0; k < 3; ++k) { 1575 wc[k] = 0.; 1576 for (j = 0; j < 3; ++j) wc[k] += lv[k][j] * ueq[j]; 1577 } 1578 return 0; 1579 } 1580 /* ----------------------------------------------------------------------- */ 1581 int projecttoprim(PetscReal v[], const PetscReal wc[], PetscReal rv[][3]) 1582 { 1583 int k, j; 1584 /* V=matmul(rv,WC) 3 vars */ 1585 for (k = 0; k < 3; ++k) { 1586 v[k] = 0.; 1587 for (j = 0; j < 3; ++j) v[k] += rv[k][j] * wc[j]; 1588 } 1589 return 0; 1590 } 1591 /* ---------------------------------------------------------------------- */ 1592 int eigenvectors(PetscReal rv[][3], PetscReal lv[][3], const PetscReal ueq[], PetscReal gamma) 1593 { 1594 int j, k; 1595 PetscReal rho, csnd, p0; 1596 /* PetscScalar u; */ 1597 1598 for (k = 0; k < 3; ++k) 1599 for (j = 0; j < 3; ++j) { 1600 lv[k][j] = 0.; 1601 rv[k][j] = 0.; 1602 } 1603 rho = ueq[0]; 1604 /* u = ueq[1]; */ 1605 p0 = ueq[2]; 1606 csnd = PetscSqrtReal(gamma * p0 / rho); 1607 lv[0][1] = rho * .5; 1608 lv[0][2] = -.5 / csnd; 1609 lv[1][0] = csnd; 1610 lv[1][2] = -1. / csnd; 1611 lv[2][1] = rho * .5; 1612 lv[2][2] = .5 / csnd; 1613 rv[0][0] = -1. / csnd; 1614 rv[1][0] = 1. / rho; 1615 rv[2][0] = -csnd; 1616 rv[0][1] = 1. / csnd; 1617 rv[0][2] = 1. / csnd; 1618 rv[1][2] = 1. / rho; 1619 rv[2][2] = csnd; 1620 return 0; 1621 } 1622 1623 int initLinearWave(EulerNode *ux, const PetscReal gamma, const PetscReal coord[], const PetscReal Lx) 1624 { 1625 PetscReal p0, u0, wcp[3], wc[3]; 1626 PetscReal lv[3][3]; 1627 PetscReal vp[3]; 1628 PetscReal rv[3][3]; 1629 PetscReal eps, ueq[3], rho0, twopi; 1630 1631 /* Function Body */ 1632 twopi = 2. * PETSC_PI; 1633 eps = 1e-4; /* perturbation */ 1634 rho0 = 1e3; /* density of water */ 1635 p0 = 101325.; /* init pressure of 1 atm (?) */ 1636 u0 = 0.; 1637 ueq[0] = rho0; 1638 ueq[1] = u0; 1639 ueq[2] = p0; 1640 /* Project initial state to characteristic variables */ 1641 eigenvectors(rv, lv, ueq, gamma); 1642 projecteqstate(wc, ueq, lv); 1643 wcp[0] = wc[0]; 1644 wcp[1] = wc[1]; 1645 wcp[2] = wc[2] + eps * PetscCosReal(coord[0] * 2. * twopi / Lx); 1646 projecttoprim(vp, wcp, rv); 1647 ux->r = vp[0]; /* density */ 1648 ux->ru[0] = vp[0] * vp[1]; /* x momentum */ 1649 ux->ru[1] = 0.; 1650 /* E = rho * e + rho * v^2/2 = p/(gam-1) + rho*v^2/2 */ 1651 ux->E = vp[2] / (gamma - 1.) + 0.5 * vp[0] * vp[1] * vp[1]; 1652 return 0; 1653 } 1654 1655 /*TEST 1656 1657 testset: 1658 args: -dm_plex_adj_cone -dm_plex_adj_closure 0 1659 1660 test: 1661 suffix: adv_2d_tri_0 1662 requires: triangle 1663 TODO: how did this ever get in main when there is no support for this 1664 args: -ufv_vtk_interval 0 -simplex -dm_refine 3 -dm_plex_faces 1,1 -dm_plex_separate_marker -bc_inflow 1,2,4 -bc_outflow 3 1665 1666 test: 1667 suffix: adv_2d_tri_1 1668 requires: triangle 1669 TODO: how did this ever get in main when there is no support for this 1670 args: -ufv_vtk_interval 0 -simplex -dm_refine 5 -dm_plex_faces 1,1 -dm_plex_separate_marker -grid_bounds -0.5,0.5,-0.5,0.5 -bc_inflow 1,2,4 -bc_outflow 3 -advect_sol_type bump -advect_bump_center 0.25,0 -advect_bump_radius 0.1 1671 1672 test: 1673 suffix: tut_1 1674 requires: exodusii 1675 nsize: 1 1676 args: -dm_plex_filename ${wPETSC_DIR}/share/petsc/datafiles/meshes/sevenside.exo - 1677 1678 test: 1679 suffix: tut_2 1680 requires: exodusii 1681 nsize: 1 1682 args: -dm_plex_filename ${wPETSC_DIR}/share/petsc/datafiles/meshes/sevenside.exo -ts_type rosw 1683 1684 test: 1685 suffix: tut_3 1686 requires: exodusii 1687 nsize: 4 1688 args: -dm_distribute_overlap 1 -dm_plex_filename ${wPETSC_DIR}/share/petsc/datafiles/meshes/annulus-20.exo -monitor Error -advect_sol_type bump -petscfv_type leastsquares -petsclimiter_type sin 1689 1690 test: 1691 suffix: tut_4 1692 requires: exodusii !single 1693 nsize: 4 1694 args: -dm_distribute_overlap 1 -dm_plex_filename ${wPETSC_DIR}/share/petsc/datafiles/meshes/annulus-20.exo -physics sw -monitor Height,Energy -petscfv_type leastsquares -petsclimiter_type minmod 1695 1696 testset: 1697 args: -dm_plex_adj_cone -dm_plex_adj_closure 0 -dm_plex_simplex 0 -dm_plex_box_faces 1,1,1 1698 1699 # 2D Advection 0-10 1700 test: 1701 suffix: 0 1702 requires: exodusii 1703 args: -ufv_vtk_interval 0 -dm_plex_filename ${wPETSC_DIR}/share/petsc/datafiles/meshes/sevenside.exo 1704 1705 test: 1706 suffix: 1 1707 requires: exodusii 1708 args: -ufv_vtk_interval 0 -dm_plex_filename ${wPETSC_DIR}/share/petsc/datafiles/meshes/sevenside-quad-15.exo 1709 1710 test: 1711 suffix: 2 1712 requires: exodusii 1713 nsize: 2 1714 args: -dm_distribute_overlap 1 -ufv_vtk_interval 0 -dm_plex_filename ${wPETSC_DIR}/share/petsc/datafiles/meshes/sevenside.exo 1715 1716 test: 1717 suffix: 3 1718 requires: exodusii 1719 nsize: 2 1720 args: -dm_distribute_overlap 1 -ufv_vtk_interval 0 -dm_plex_filename ${wPETSC_DIR}/share/petsc/datafiles/meshes/sevenside-quad-15.exo 1721 1722 test: 1723 suffix: 4 1724 requires: exodusii 1725 nsize: 4 1726 args: -dm_distribute_overlap 1 -ufv_vtk_interval 0 -dm_plex_filename ${wPETSC_DIR}/share/petsc/datafiles/meshes/sevenside-quad.exo -petscpartitioner_type simple 1727 1728 test: 1729 suffix: 5 1730 requires: exodusii 1731 args: -ufv_vtk_interval 0 -dm_plex_filename ${wPETSC_DIR}/share/petsc/datafiles/meshes/sevenside.exo -ts_type rosw -ts_adapt_reject_safety 1 1732 1733 test: 1734 suffix: 7 1735 requires: exodusii 1736 args: -ufv_vtk_interval 0 -dm_plex_filename ${wPETSC_DIR}/share/petsc/datafiles/meshes/sevenside-quad-15.exo -dm_refine 1 1737 1738 test: 1739 suffix: 8 1740 requires: exodusii 1741 nsize: 2 1742 args: -dm_distribute_overlap 1 -ufv_vtk_interval 0 -dm_plex_filename ${wPETSC_DIR}/share/petsc/datafiles/meshes/sevenside-quad-15.exo -dm_refine 1 1743 1744 test: 1745 suffix: 9 1746 requires: exodusii 1747 nsize: 8 1748 args: -dm_distribute_overlap 1 -ufv_vtk_interval 0 -dm_plex_filename ${wPETSC_DIR}/share/petsc/datafiles/meshes/sevenside-quad-15.exo -dm_refine 1 1749 1750 test: 1751 suffix: 10 1752 requires: exodusii 1753 args: -ufv_vtk_interval 0 -dm_plex_filename ${wPETSC_DIR}/share/petsc/datafiles/meshes/sevenside-quad.exo 1754 1755 # 2D Shallow water 1756 testset: 1757 args: -physics sw -ufv_vtk_interval 0 -dm_plex_adj_cone -dm_plex_adj_closure 0 1758 1759 test: 1760 suffix: sw_0 1761 requires: exodusii 1762 args: -bc_wall 100,101 -ufv_cfl 5 -petscfv_type leastsquares -petsclimiter_type sin \ 1763 -dm_plex_filename ${wPETSC_DIR}/share/petsc/datafiles/meshes/annulus-20.exo \ 1764 -ts_max_time 1 -ts_ssp_type rks2 -ts_ssp_nstages 10 \ 1765 -monitor height,energy 1766 1767 test: 1768 suffix: sw_ceed 1769 requires: exodusii libceed 1770 args: -sw_riemann rusanov_ceed -bc_wall 100,101 -ufv_cfl 5 -petsclimiter_type sin \ 1771 -dm_plex_filename ${wPETSC_DIR}/share/petsc/datafiles/meshes/annulus-20.exo -dm_plex_use_ceed \ 1772 -ts_max_time 1 -ts_ssp_type rks2 -ts_ssp_nstages 10 \ 1773 -monitor height,energy 1774 1775 test: 1776 suffix: sw_ceed_small 1777 requires: exodusii libceed 1778 args: -sw_riemann rusanov_ceed -bc_wall 1,3 -ufv_cfl 5 -petsclimiter_type sin -dm_plex_use_ceed \ 1779 -dm_plex_shape annulus -dm_plex_simplex 0 -dm_plex_box_lower 0,1 -dm_plex_box_upper 6.28,3 -dm_plex_box_faces 8,2 \ 1780 -ts_max_time 1 -ts_ssp_type rks2 -ts_ssp_nstages 10 \ 1781 -monitor height,energy 1782 1783 test: 1784 suffix: sw_1 1785 nsize: 2 1786 args: -bc_wall 1,3 -ufv_cfl 5 -petsclimiter_type sin \ 1787 -dm_plex_shape annulus -dm_plex_simplex 0 -dm_plex_box_faces 24,12 -dm_plex_box_lower 0,1 -dm_plex_box_upper 1,3 -dm_distribute_overlap 1 \ 1788 -ts_max_time 1 -ts_ssp_type rks2 -ts_ssp_nstages 10 \ 1789 -monitor height,energy 1790 1791 test: 1792 suffix: sw_hll 1793 args: -sw_riemann hll -bc_wall 1,2,3,4 -ufv_cfl 3 -petscfv_type leastsquares -petsclimiter_type sin \ 1794 -grid_bounds 0,5,0,5 -dm_plex_simplex 0 -dm_plex_box_faces 25,25 \ 1795 -ts_max_steps 5 -ts_ssp_type rks2 -ts_ssp_nstages 10 \ 1796 -monitor height,energy 1797 1798 # 2D Euler 1799 testset: 1800 args: -physics euler -eu_type linear_wave -eu_gamma 1.4 -dm_plex_adj_cone -dm_plex_adj_closure 0 \ 1801 -ufv_vtk_interval 0 -ufv_vtk_basename ${wPETSC_DIR}/ex11 -monitor density,energy 1802 1803 test: 1804 suffix: euler_0 1805 requires: exodusii !complex !single 1806 args: -eu_riemann godunov -bc_wall 100,101 -ufv_cfl 5 -petsclimiter_type sin \ 1807 -dm_plex_filename ${wPETSC_DIR}/share/petsc/datafiles/meshes/annulus-20.exo \ 1808 -ts_max_time 1 -ts_ssp_type rks2 -ts_ssp_nstages 10 1809 1810 test: 1811 suffix: euler_ceed 1812 requires: exodusii libceed 1813 args: -eu_riemann godunov_ceed -bc_wall 100,101 -ufv_cfl 5 -petsclimiter_type sin \ 1814 -dm_plex_filename ${wPETSC_DIR}/share/petsc/datafiles/meshes/annulus-20.exo -dm_plex_use_ceed \ 1815 -ts_max_time 1 -ts_ssp_type rks2 -ts_ssp_nstages 10 1816 1817 testset: 1818 args: -dm_plex_adj_cone -dm_plex_adj_closure 0 -dm_plex_simplex 0 -dm_plex_box_faces 1,1,1 1819 1820 # 2D Advection: p4est 1821 test: 1822 suffix: p4est_advec_2d 1823 requires: p4est 1824 args: -ufv_vtk_interval 0 -dm_type p4est -dm_forest_minimum_refinement 1 -dm_forest_initial_refinement 2 -dm_p4est_refine_pattern hash -dm_forest_maximum_refinement 5 1825 1826 # Advection in a box 1827 test: 1828 suffix: adv_2d_quad_0 1829 args: -ufv_vtk_interval 0 -dm_refine 3 -dm_plex_separate_marker -bc_inflow 1,2,4 -bc_outflow 3 1830 1831 test: 1832 suffix: adv_2d_quad_1 1833 args: -ufv_vtk_interval 0 -dm_refine 3 -dm_plex_separate_marker -grid_bounds -0.5,0.5,-0.5,0.5 -bc_inflow 1,2,4 -bc_outflow 3 -advect_sol_type bump -advect_bump_center 0.25,0 -advect_bump_radius 0.1 1834 timeoutfactor: 3 1835 1836 test: 1837 suffix: adv_2d_quad_p4est_0 1838 requires: p4est 1839 args: -ufv_vtk_interval 0 -dm_refine 5 -dm_type p4est -dm_plex_separate_marker -bc_inflow 1,2,4 -bc_outflow 3 1840 1841 test: 1842 suffix: adv_2d_quad_p4est_1 1843 requires: p4est 1844 args: -ufv_vtk_interval 0 -dm_refine 5 -dm_type p4est -dm_plex_separate_marker -grid_bounds -0.5,0.5,-0.5,0.5 -bc_inflow 1,2,4 -bc_outflow 3 -advect_sol_type bump -advect_bump_center 0.25,0 -advect_bump_radius 0.1 1845 timeoutfactor: 3 1846 1847 test: # broken for quad precision 1848 suffix: adv_2d_quad_p4est_adapt_0 1849 requires: p4est !__float128 1850 args: -ufv_vtk_interval 0 -dm_refine 3 -dm_type p4est -dm_plex_separate_marker -grid_bounds -0.5,0.5,-0.5,0.5 -bc_inflow 1,2,4 -bc_outflow 3 -advect_sol_type bump -advect_bump_center 0.25,0 -advect_bump_radius 0.1 -ufv_use_amr -refine_vec_tagger_box 0.005,inf -coarsen_vec_tagger_box 0,1.e-5 -petscfv_type leastsquares -ts_max_time 0.01 1851 timeoutfactor: 3 1852 1853 test: 1854 suffix: adv_0 1855 requires: exodusii 1856 args: -ufv_vtk_interval 0 -dm_plex_filename ${wPETSC_DIR}/share/petsc/datafiles/meshes/blockcylinder-50.exo -bc_inflow 100,101,200 -bc_outflow 201 1857 1858 # Run with -dm_forest_maximum_refinement 6 -ts_max_time 0.5 instead to get the full movie 1859 test: 1860 suffix: shock_0 1861 requires: p4est !single !complex 1862 args: -dm_plex_box_faces 2,1 -grid_bounds -1,1.,0.,1 -grid_skew_60 \ 1863 -dm_type p4est -dm_forest_partition_overlap 1 -dm_forest_maximum_refinement 2 -dm_forest_minimum_refinement 2 -dm_forest_initial_refinement 2 \ 1864 -ufv_use_amr -refine_vec_tagger_box 0.5,inf -coarsen_vec_tagger_box 0,1.e-2 -refine_tag_view -coarsen_tag_view \ 1865 -bc_wall 1,2,3,4 -physics euler -eu_type iv_shock -ufv_cfl 10 -eu_alpha 60. -eu_gamma 1.4 -eu_amach 2.02 -eu_rho2 3. \ 1866 -petscfv_type leastsquares -petsclimiter_type minmod -petscfv_compute_gradients 0 \ 1867 -ts_max_steps 3 -ts_ssp_type rks2 -ts_ssp_nstages 10 \ 1868 -ufv_vtk_basename ${wPETSC_DIR}/ex11 -ufv_vtk_interval 0 -monitor density,energy 1869 1870 # Test GLVis visualization of PetscFV fields 1871 test: 1872 suffix: glvis_adv_2d_tri 1873 args: -ufv_vtk_interval 0 -ufv_vtk_monitor 0 \ 1874 -dm_plex_filename ${wPETSC_DIR}/share/petsc/datafiles/meshes/square_periodic.msh -dm_plex_gmsh_periodic 0 \ 1875 -ts_monitor_solution glvis: -ts_max_steps 0 1876 1877 test: 1878 suffix: glvis_adv_2d_quad 1879 args: -ufv_vtk_interval 0 -ufv_vtk_monitor 0 -bc_inflow 1,2,4 -bc_outflow 3 \ 1880 -dm_refine 5 -dm_plex_separate_marker \ 1881 -ts_monitor_solution glvis: -ts_max_steps 0 1882 1883 # Test CGNS file writing for PetscFV fields 1884 test: 1885 suffix: cgns_adv_2d_tri 1886 requires: cgns 1887 args: -ufv_vtk_interval 0 -ufv_vtk_monitor 0 \ 1888 -dm_plex_filename ${wPETSC_DIR}/share/petsc/datafiles/meshes/square_periodic.msh -dm_plex_gmsh_periodic 0 \ 1889 -ts_monitor_solution cgns:sol.cgns -ts_max_steps 0 1890 1891 test: 1892 suffix: cgns_adv_2d_quad 1893 requires: cgns 1894 args: -ufv_vtk_interval 0 -ufv_vtk_monitor 0 -bc_inflow 1,2,4 -bc_outflow 3 \ 1895 -dm_refine 5 -dm_plex_separate_marker \ 1896 -ts_monitor_solution cgns:sol.cgns -ts_max_steps 0 1897 1898 # Test CGNS file writing, cgns_batch_size, ts_run_steps, ts_monitor_skip_initial 1899 test: 1900 suffix: cgns_adv_2d_tri_monitor 1901 requires: cgns 1902 args: -ufv_vtk_interval 0 -ufv_vtk_monitor 0 \ 1903 -dm_plex_filename ${wPETSC_DIR}/share/petsc/datafiles/meshes/square_periodic.msh -dm_plex_gmsh_periodic 0 \ 1904 -ts_monitor_solution cgns:sol-%d.cgns -ts_run_steps 4 -ts_monitor_solution_interval 2 \ 1905 -viewer_cgns_batch_size 1 -ts_monitor_solution_skip_initial 1906 1907 # Test VTK file writing for PetscFV fields with -ts_monitor_solution_vtk 1908 test: 1909 suffix: vtk_adv_2d_tri 1910 args: -ufv_vtk_interval 0 -ufv_vtk_monitor 0 \ 1911 -dm_plex_filename ${wPETSC_DIR}/share/petsc/datafiles/meshes/square_periodic.msh -dm_plex_gmsh_periodic 0 \ 1912 -ts_monitor_solution_vtk 'bar-%03d.vtu' -ts_monitor_solution_vtk_interval 2 -ts_max_steps 5 1913 1914 TEST*/ 1915