1 static char help[] = "Particle Basis Landau Example using nonlinear solve + Implicit Midpoint-like time stepping."; 2 3 /* TODO 4 5 1) SNES is sensitive to epsilon (but not to h). Should we do continuation in it? 6 7 2) Put this timestepper in library, maybe by changing DG 8 9 3) Add monitor to visualize distributions 10 11 */ 12 13 /* References 14 [1] https://arxiv.org/abs/1910.03080v2 15 */ 16 17 #include <petscdmplex.h> 18 #include <petscdmswarm.h> 19 #include <petscts.h> 20 #include <petscviewer.h> 21 #include <petscmath.h> 22 23 typedef struct { 24 /* Velocity space grid and functions */ 25 PetscInt N; /* The number of partices per spatial cell */ 26 PetscReal L; /* Velocity space is [-L, L]^d */ 27 PetscReal h; /* Spacing for grid 2L / N^{1/d} */ 28 PetscReal epsilon; /* gaussian regularization parameter */ 29 PetscReal momentTol; /* Tolerance for checking moment conservation */ 30 } AppCtx; 31 32 static PetscErrorCode ProcessOptions(MPI_Comm comm, AppCtx *options) 33 { 34 PetscErrorCode ierr; 35 36 PetscFunctionBeginUser; 37 options->N = 1; 38 options->momentTol = 100.0*PETSC_MACHINE_EPSILON; 39 options->L = 1.0; 40 options->h = -1.0; 41 options->epsilon = -1.0; 42 43 ierr = PetscOptionsBegin(comm, "", "Collision Options", "DMPLEX");CHKERRQ(ierr); 44 CHKERRQ(PetscOptionsInt("-N", "Number of particles per spatial cell", "ex27.c", options->N, &options->N, NULL)); 45 CHKERRQ(PetscOptionsReal("-L", "Velocity-space extent", "ex27.c", options->L, &options->L, NULL)); 46 CHKERRQ(PetscOptionsReal("-h", "Velocity-space resolution", "ex27.c", options->h, &options->h, NULL)); 47 CHKERRQ(PetscOptionsReal("-epsilon", "Mollifier regularization parameter", "ex27.c", options->epsilon, &options->epsilon, NULL)); 48 ierr = PetscOptionsEnd();CHKERRQ(ierr); 49 PetscFunctionReturn(0); 50 } 51 52 static PetscErrorCode CreateMesh(MPI_Comm comm, DM *dm, AppCtx *user) 53 { 54 PetscFunctionBeginUser; 55 CHKERRQ(DMCreate(comm, dm)); 56 CHKERRQ(DMSetType(*dm, DMPLEX)); 57 CHKERRQ(DMSetFromOptions(*dm)); 58 CHKERRQ(DMViewFromOptions(*dm, NULL, "-dm_view")); 59 PetscFunctionReturn(0); 60 } 61 62 static PetscErrorCode SetInitialCoordinates(DM sw) 63 { 64 AppCtx *user; 65 PetscRandom rnd, rndv; 66 DM dm; 67 DMPolytopeType ct; 68 PetscBool simplex; 69 PetscReal *centroid, *coords, *velocity, *xi0, *v0, *J, *invJ, detJ, *vals; 70 PetscInt dim, d, cStart, cEnd, c, Np, p; 71 72 PetscFunctionBeginUser; 73 /* Randomization for coordinates */ 74 CHKERRQ(PetscRandomCreate(PetscObjectComm((PetscObject) sw), &rnd)); 75 CHKERRQ(PetscRandomSetInterval(rnd, -1.0, 1.0)); 76 CHKERRQ(PetscRandomSetFromOptions(rnd)); 77 CHKERRQ(PetscRandomCreate(PetscObjectComm((PetscObject) sw), &rndv)); 78 CHKERRQ(PetscRandomSetInterval(rndv, -1., 1.)); 79 CHKERRQ(PetscRandomSetFromOptions(rndv)); 80 CHKERRQ(DMGetApplicationContext(sw, &user)); 81 Np = user->N; 82 CHKERRQ(DMGetDimension(sw, &dim)); 83 CHKERRQ(DMSwarmGetCellDM(sw, &dm)); 84 CHKERRQ(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 85 CHKERRQ(DMPlexGetCellType(dm, cStart, &ct)); 86 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE; 87 CHKERRQ(PetscMalloc5(dim, ¢roid, dim, &xi0, dim, &v0, dim*dim, &J, dim*dim, &invJ)); 88 for (d = 0; d < dim; ++d) xi0[d] = -1.0; 89 CHKERRQ(DMSwarmGetField(sw, DMSwarmPICField_coor, NULL, NULL, (void **) &coords)); 90 CHKERRQ(DMSwarmGetField(sw, "velocity", NULL, NULL, (void **) &velocity)); 91 CHKERRQ(DMSwarmGetField(sw, "w_q", NULL, NULL, (void **) &vals)); 92 for (c = cStart; c < cEnd; ++c) { 93 if (Np == 1) { 94 CHKERRQ(DMPlexComputeCellGeometryFVM(dm, c, NULL, centroid, NULL)); 95 for (d = 0; d < dim; ++d) { 96 coords[c*dim+d] = centroid[d]; 97 } 98 vals[c] = 1.0; 99 } else { 100 CHKERRQ(DMPlexComputeCellGeometryFEM(dm, c, NULL, v0, J, invJ, &detJ)); /* affine */ 101 for (p = 0; p < Np; ++p) { 102 const PetscInt n = c*Np + p; 103 PetscReal sum = 0.0, refcoords[3]; 104 105 for (d = 0; d < dim; ++d) { 106 CHKERRQ(PetscRandomGetValueReal(rnd, &refcoords[d])); 107 sum += refcoords[d]; 108 } 109 if (simplex && sum > 0.0) for (d = 0; d < dim; ++d) refcoords[d] -= PetscSqrtReal(dim)*sum; 110 vals[n] = 1.0; 111 CHKERRQ(DMPlexReferenceToCoordinates(dm, c, 1, refcoords, &coords[n*dim])); 112 } 113 } 114 } 115 /* Random velocity IC */ 116 for (c = cStart; c < cEnd; ++c) { 117 for (p = 0; p < Np; ++p) { 118 for (d = 0; d < dim; ++d) { 119 PetscReal v_val; 120 121 CHKERRQ(PetscRandomGetValueReal(rndv, &v_val)); 122 velocity[p*dim+d] = v_val; 123 } 124 } 125 } 126 CHKERRQ(DMSwarmRestoreField(sw, DMSwarmPICField_coor, NULL, NULL, (void **) &coords)); 127 CHKERRQ(DMSwarmRestoreField(sw, "velocity", NULL, NULL, (void **) &velocity)); 128 CHKERRQ(DMSwarmRestoreField(sw, "w_q", NULL, NULL, (void **) &vals)); 129 CHKERRQ(PetscFree5(centroid, xi0, v0, J, invJ)); 130 CHKERRQ(PetscRandomDestroy(&rnd)); 131 CHKERRQ(PetscRandomDestroy(&rndv)); 132 PetscFunctionReturn(0); 133 } 134 135 /* Get velocities from swarm and place in solution vector */ 136 static PetscErrorCode SetInitialConditions(DM dmSw, Vec u) 137 { 138 DM dm; 139 AppCtx *user; 140 PetscReal *velocity; 141 PetscScalar *initialConditions; 142 PetscInt dim, d, cStart, cEnd, c, Np, p, n; 143 144 PetscFunctionBeginUser; 145 CHKERRQ(VecGetLocalSize(u, &n)); 146 CHKERRQ(DMGetApplicationContext(dmSw, &user)); 147 Np = user->N; 148 CHKERRQ(DMSwarmGetCellDM(dmSw, &dm)); 149 CHKERRQ(DMGetDimension(dm, &dim)); 150 CHKERRQ(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 151 CHKERRQ(DMSwarmGetField(dmSw, "velocity", NULL, NULL, (void **) &velocity)); 152 CHKERRQ(VecGetArray(u, &initialConditions)); 153 for (c = cStart; c < cEnd; ++c) { 154 for (p = 0; p < Np; ++p) { 155 const PetscInt n = c*Np + p; 156 for (d = 0; d < dim; d++) { 157 initialConditions[n*dim+d] = velocity[n*dim+d]; 158 } 159 } 160 } 161 CHKERRQ(VecRestoreArray(u, &initialConditions)); 162 CHKERRQ(DMSwarmRestoreField(dmSw, "velocity", NULL, NULL, (void **) &velocity)); 163 PetscFunctionReturn(0); 164 } 165 166 static PetscErrorCode CreateParticles(DM dm, DM *sw, AppCtx *user) 167 { 168 PetscInt *cellid; 169 PetscInt dim, cStart, cEnd, c, Np = user->N, p; 170 PetscBool view = PETSC_FALSE; 171 172 PetscFunctionBeginUser; 173 CHKERRQ(DMGetDimension(dm, &dim)); 174 CHKERRQ(DMCreate(PetscObjectComm((PetscObject) dm), sw)); 175 CHKERRQ(DMSetType(*sw, DMSWARM)); 176 CHKERRQ(DMSetDimension(*sw, dim)); 177 /* h = 2L/n and N = n^d */ 178 if (user->h < 0.) user->h = 2.*user->L / PetscPowReal(user->N, 1./dim); 179 /* From Section 4 in [1], \epsilon = 0.64 h^.98 */ 180 if (user->epsilon < 0.) user->epsilon = 0.64*pow(user->h, 1.98); 181 CHKERRQ(PetscOptionsGetBool(NULL, NULL, "-param_view", &view, NULL)); 182 if (view) { 183 CHKERRQ(PetscPrintf(PETSC_COMM_SELF, "N: %D L: %g h: %g eps: %g\n", user->N, user->L, user->h, user->epsilon)); 184 } 185 CHKERRQ(DMSwarmSetType(*sw, DMSWARM_PIC)); 186 CHKERRQ(DMSwarmSetCellDM(*sw, dm)); 187 CHKERRQ(DMSwarmRegisterPetscDatatypeField(*sw, "velocity", dim, PETSC_REAL)); 188 CHKERRQ(DMSwarmRegisterPetscDatatypeField(*sw, "w_q", 1, PETSC_SCALAR)); 189 CHKERRQ(DMSwarmFinalizeFieldRegister(*sw)); 190 CHKERRQ(DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd)); 191 CHKERRQ(DMSwarmSetLocalSizes(*sw, (cEnd - cStart) * Np, 0)); 192 CHKERRQ(DMSetFromOptions(*sw)); 193 CHKERRQ(DMSwarmGetField(*sw, DMSwarmPICField_cellid, NULL, NULL, (void **) &cellid)); 194 for (c = cStart; c < cEnd; ++c) { 195 for (p = 0; p < Np; ++p) { 196 const PetscInt n = c*Np + p; 197 cellid[n] = c; 198 } 199 } 200 CHKERRQ(DMSwarmRestoreField(*sw, DMSwarmPICField_cellid, NULL, NULL, (void **) &cellid)); 201 CHKERRQ(PetscObjectSetName((PetscObject) *sw, "Particles")); 202 CHKERRQ(DMViewFromOptions(*sw, NULL, "-sw_view")); 203 PetscFunctionReturn(0); 204 } 205 206 /* Internal dmplex function, same as found in dmpleximpl.h */ 207 static void DMPlex_WaxpyD_Internal(PetscInt dim, PetscReal a, const PetscReal *x, const PetscReal *y, PetscReal *w) 208 { 209 PetscInt d; 210 211 for (d = 0; d < dim; ++d) w[d] = a*x[d] + y[d]; 212 } 213 214 /* Internal dmplex function, same as found in dmpleximpl.h */ 215 static PetscReal DMPlex_DotD_Internal(PetscInt dim, const PetscScalar *x, const PetscReal *y) 216 { 217 PetscReal sum = 0.0; 218 PetscInt d; 219 220 for (d = 0; d < dim; ++d) sum += PetscRealPart(x[d])*y[d]; 221 return sum; 222 } 223 224 /* Internal dmplex function, same as found in dmpleximpl.h */ 225 static void DMPlex_MultAdd2DReal_Internal(const PetscReal A[], PetscInt ldx, const PetscScalar x[], PetscScalar y[]) 226 { 227 PetscScalar z[2]; 228 z[0] = x[0]; z[1] = x[ldx]; 229 y[0] += A[0]*z[0] + A[1]*z[1]; 230 y[ldx] += A[2]*z[0] + A[3]*z[1]; 231 (void)PetscLogFlops(6.0); 232 } 233 234 /* Internal dmplex function, same as found in dmpleximpl.h to avoid private includes. */ 235 static void DMPlex_MultAdd3DReal_Internal(const PetscReal A[], PetscInt ldx, const PetscScalar x[], PetscScalar y[]) 236 { 237 PetscScalar z[3]; 238 z[0] = x[0]; z[1] = x[ldx]; z[2] = x[ldx*2]; 239 y[0] += A[0]*z[0] + A[1]*z[1] + A[2]*z[2]; 240 y[ldx] += A[3]*z[0] + A[4]*z[1] + A[5]*z[2]; 241 y[ldx*2] += A[6]*z[0] + A[7]*z[1] + A[8]*z[2]; 242 (void)PetscLogFlops(15.0); 243 } 244 245 /* 246 Gaussian - The Gaussian function G(x) 247 248 Input Parameters: 249 + dim - The number of dimensions, or size of x 250 . mu - The mean, or center 251 . sigma - The standard deviation, or width 252 - x - The evaluation point of the function 253 254 Output Parameter: 255 . ret - The value G(x) 256 */ 257 static PetscReal Gaussian(PetscInt dim, const PetscReal mu[], PetscReal sigma, const PetscReal x[]) 258 { 259 PetscReal arg = 0.0; 260 PetscInt d; 261 262 for (d = 0; d < dim; ++d) arg += PetscSqr(x[d] - mu[d]); 263 return PetscPowReal(2.0*PETSC_PI*sigma, -dim/2.0) * PetscExpReal(-arg/(2.0*sigma)); 264 } 265 266 /* 267 ComputeGradS - Compute grad_v dS_eps/df 268 269 Input Parameters: 270 + dim - The dimension 271 . Np - The number of particles 272 . vp - The velocity v_p of the particle at which we evaluate 273 . velocity - The velocity field for all particles 274 . epsilon - The regularization strength 275 276 Output Parameter: 277 . integral - The output grad_v dS_eps/df (v_p) 278 279 Note: 280 This comes from (3.6) in [1], and we are computing 281 $ \nabla_v S_p = \grad \psi_\epsilon(v_p - v) log \sum_q \psi_\epsilon(v - v_q) 282 which is discretized by using a one-point quadrature in each box l at its center v^c_l 283 $ \sum_l h^d \nabla\psi_\epsilon(v_p - v^c_l) \log\left( \sum_q w_q \psi_\epsilon(v^c_l - v_q) \right) 284 where h^d is the volume of each box. 285 */ 286 static PetscErrorCode ComputeGradS(PetscInt dim, PetscInt Np, const PetscReal vp[], const PetscReal velocity[], PetscReal integral[], AppCtx *ctx) 287 { 288 PetscReal vc_l[3], L = ctx->L, h = ctx->h, epsilon = ctx->epsilon, init = 0.5*h - L; 289 PetscInt nx = roundf(2.*L / h); 290 PetscInt ny = dim > 1 ? nx : 1; 291 PetscInt nz = dim > 2 ? nx : 1; 292 PetscInt i, j, k, d, q, dbg = 0; 293 294 PetscFunctionBeginHot; 295 for (d = 0; d < dim; ++d) integral[d] = 0.0; 296 for (k = 0, vc_l[2] = init; k < nz; ++k, vc_l[2] += h) { 297 for (j = 0, vc_l[1] = init; j < ny; ++j, vc_l[1] += h) { 298 for (i = 0, vc_l[0] = init; i < nx; ++i, vc_l[0] += h) { 299 PetscReal sum = 0.0; 300 301 if (dbg) CHKERRQ(PetscPrintf(PETSC_COMM_SELF, "(%D %D) vc_l: %g %g\n", i, j, vc_l[0], vc_l[1])); 302 /* \log \sum_k \psi(v - v_k) */ 303 for (q = 0; q < Np; ++q) sum += Gaussian(dim, &velocity[q*dim], epsilon, vc_l); 304 sum = PetscLogReal(sum); 305 for (d = 0; d < dim; ++d) integral[d] += (-1./(epsilon))*PetscAbsReal(vp[d] - vc_l[d])*(Gaussian(dim, vp, epsilon, vc_l)) * sum; 306 } 307 } 308 } 309 PetscFunctionReturn(0); 310 } 311 312 /* Q = 1/|xi| (I - xi xi^T / |xi|^2), xi = vp - vq */ 313 static PetscErrorCode QCompute(PetscInt dim, const PetscReal vp[], const PetscReal vq[], PetscReal Q[]) 314 { 315 PetscReal xi[3], xi2, xi3, mag; 316 PetscInt d, e; 317 318 PetscFunctionBeginHot; 319 DMPlex_WaxpyD_Internal(dim, -1.0, vq, vp, xi); 320 xi2 = DMPlex_DotD_Internal(dim, xi, xi); 321 mag = PetscSqrtReal(xi2); 322 xi3 = xi2 * mag; 323 for (d = 0; d < dim; ++d) { 324 for (e = 0; e < dim; ++e) { 325 Q[d*dim+e] = -xi[d]*xi[e] / xi3; 326 } 327 Q[d*dim+d] += 1. / mag; 328 } 329 PetscFunctionReturn(0); 330 } 331 332 static PetscErrorCode RHSFunctionParticles(TS ts, PetscReal t, Vec U, Vec R, void *ctx) 333 { 334 AppCtx *user = (AppCtx *) ctx; 335 PetscInt dbg = 0; 336 DM sw; /* Particles */ 337 Vec sol; /* Solution vector at current time */ 338 const PetscScalar *u; /* input solution vector */ 339 PetscScalar *r; 340 PetscReal *velocity; 341 PetscInt dim, Np, p, q; 342 343 PetscFunctionBeginUser; 344 CHKERRQ(VecZeroEntries(R)); 345 CHKERRQ(TSGetDM(ts, &sw)); 346 CHKERRQ(DMGetDimension(sw, &dim)); 347 CHKERRQ(VecGetLocalSize(U, &Np)); 348 CHKERRQ(TSGetSolution(ts, &sol)); 349 CHKERRQ(VecGetArray(sol, &velocity)); 350 CHKERRQ(VecGetArray(R, &r)); 351 CHKERRQ(VecGetArrayRead(U, &u)); 352 Np /= dim; 353 if (dbg) CHKERRQ(PetscPrintf(PETSC_COMM_WORLD, "Part ppr x y\n")); 354 for (p = 0; p < Np; ++p) { 355 PetscReal gradS_p[3] = {0., 0., 0.}; 356 357 CHKERRQ(ComputeGradS(dim, Np, &velocity[p*dim], velocity, gradS_p, user)); 358 for (q = 0; q < Np; ++q) { 359 PetscReal gradS_q[3] = {0., 0., 0.}, GammaS[3] = {0., 0., 0.}, Q[9]; 360 361 if (q == p) continue; 362 CHKERRQ(ComputeGradS(dim, Np, &velocity[q*dim], velocity, gradS_q, user)); 363 DMPlex_WaxpyD_Internal(dim, -1.0, gradS_q, gradS_p, GammaS); 364 CHKERRQ(QCompute(dim, &u[p*dim], &u[q*dim], Q)); 365 switch (dim) { 366 case 2: DMPlex_MultAdd2DReal_Internal(Q, 1, GammaS, &r[p*dim]);break; 367 case 3: DMPlex_MultAdd3DReal_Internal(Q, 1, GammaS, &r[p*dim]);break; 368 default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Do not support dimension %D", dim); 369 } 370 } 371 if (dbg) CHKERRQ(PetscPrintf(PETSC_COMM_WORLD, "Final %4D %10.8lf %10.8lf\n", p, r[p*dim+0], r[p*dim+1])); 372 } 373 CHKERRQ(VecRestoreArrayRead(U, &u)); 374 CHKERRQ(VecRestoreArray(R, &r)); 375 CHKERRQ(VecRestoreArray(sol, &velocity)); 376 CHKERRQ(VecViewFromOptions(R, NULL, "-residual_view")); 377 PetscFunctionReturn(0); 378 } 379 380 /* 381 TS Post Step Function. Copy the solution back into the swarm for migration. We may also need to reform 382 the solution vector in cases of particle migration, but we forgo that here since there is no velocity space grid 383 to migrate between. 384 */ 385 static PetscErrorCode UpdateSwarm(TS ts) 386 { 387 PetscInt idx, n; 388 const PetscScalar *u; 389 PetscScalar *velocity; 390 DM sw; 391 Vec sol; 392 393 PetscFunctionBeginUser; 394 CHKERRQ(TSGetDM(ts, &sw)); 395 CHKERRQ(DMSwarmGetField(sw, "velocity", NULL, NULL, (void **) &velocity)); 396 CHKERRQ(TSGetSolution(ts, &sol)); 397 CHKERRQ(VecGetArrayRead(sol, &u)); 398 CHKERRQ(VecGetLocalSize(sol, &n)); 399 for (idx = 0; idx < n; ++idx) velocity[idx] = u[idx]; 400 CHKERRQ(VecRestoreArrayRead(sol, &u)); 401 CHKERRQ(DMSwarmRestoreField(sw, "velocity", NULL, NULL, (void **) &velocity)); 402 PetscFunctionReturn(0); 403 } 404 405 static PetscErrorCode InitializeSolve(TS ts, Vec u) 406 { 407 DM dm; 408 AppCtx *user; 409 410 PetscFunctionBeginUser; 411 CHKERRQ(TSGetDM(ts, &dm)); 412 CHKERRQ(DMGetApplicationContext(dm, &user)); 413 CHKERRQ(SetInitialCoordinates(dm)); 414 CHKERRQ(SetInitialConditions(dm, u)); 415 PetscFunctionReturn(0); 416 } 417 418 int main(int argc,char **argv) 419 { 420 TS ts; /* nonlinear solver */ 421 DM dm, sw; /* Velocity space mesh and Particle Swarm */ 422 Vec u, v; /* problem vector */ 423 MPI_Comm comm; 424 AppCtx user; 425 PetscErrorCode ierr; 426 427 ierr = PetscInitialize(&argc, &argv, NULL, help);if (ierr) return ierr; 428 comm = PETSC_COMM_WORLD; 429 CHKERRQ(ProcessOptions(comm, &user)); 430 /* Initialize objects and set initial conditions */ 431 CHKERRQ(CreateMesh(comm, &dm, &user)); 432 CHKERRQ(CreateParticles(dm, &sw, &user)); 433 CHKERRQ(DMSetApplicationContext(sw, &user)); 434 CHKERRQ(DMSwarmVectorDefineField(sw, "velocity")); 435 CHKERRQ(TSCreate(comm, &ts)); 436 CHKERRQ(TSSetDM(ts, sw)); 437 CHKERRQ(TSSetMaxTime(ts, 10.0)); 438 CHKERRQ(TSSetTimeStep(ts, 0.1)); 439 CHKERRQ(TSSetMaxSteps(ts, 1)); 440 CHKERRQ(TSSetExactFinalTime(ts, TS_EXACTFINALTIME_MATCHSTEP)); 441 CHKERRQ(TSSetRHSFunction(ts, NULL, RHSFunctionParticles, &user)); 442 CHKERRQ(TSSetFromOptions(ts)); 443 CHKERRQ(TSSetComputeInitialCondition(ts, InitializeSolve)); 444 CHKERRQ(DMSwarmCreateGlobalVectorFromField(sw, "velocity", &v)); 445 CHKERRQ(VecDuplicate(v, &u)); 446 CHKERRQ(DMSwarmDestroyGlobalVectorFromField(sw, "velocity", &v)); 447 CHKERRQ(TSComputeInitialCondition(ts, u)); 448 CHKERRQ(TSSetPostStep(ts, UpdateSwarm)); 449 CHKERRQ(TSSolve(ts, u)); 450 CHKERRQ(VecDestroy(&u)); 451 CHKERRQ(TSDestroy(&ts)); 452 CHKERRQ(DMDestroy(&sw)); 453 CHKERRQ(DMDestroy(&dm)); 454 ierr = PetscFinalize(); 455 return ierr; 456 } 457 458 /*TEST 459 build: 460 requires: triangle !single !complex 461 test: 462 suffix: midpoint 463 args: -N 3 -dm_plex_dim 2 -dm_plex_simplex 0 -dm_plex_box_faces 1,1 -dm_plex_box_lower -1,-1 -dm_plex_box_upper 1,1 -dm_view \ 464 -ts_type theta -ts_theta_theta 0.5 -ts_dmswarm_monitor_moments -ts_monitor_frequency 1 -snes_fd 465 TEST*/ 466