1 static char help[] = "Time-dependent reactive low Mach Flow in 2d and 3d channels with finite elements.\n\ 2 We solve the reactive low Mach flow problem in a rectangular domain\n\ 3 using a parallel unstructured mesh (DMPLEX) to discretize the flow\n\ 4 and particles (DWSWARM) to discretize the chemical species.\n\n\n"; 5 6 /*F 7 This low Mach flow is time-dependent isoviscous Navier-Stokes flow. We discretize using the 8 finite element method on an unstructured mesh. The weak form equations are 9 10 \begin{align*} 11 < q, \nabla\cdot u > = 0 12 <v, du/dt> + <v, u \cdot \nabla u> + < \nabla v, \nu (\nabla u + {\nabla u}^T) > - < \nabla\cdot v, p > - < v, f > = 0 13 < w, u \cdot \nabla T > + < \nabla w, \alpha \nabla T > - < w, Q > = 0 14 \end{align*} 15 16 where $\nu$ is the kinematic viscosity and $\alpha$ is thermal diffusivity. 17 18 For visualization, use 19 20 -dm_view hdf5:$PWD/sol.h5 -sol_vec_view hdf5:$PWD/sol.h5::append -exact_vec_view hdf5:$PWD/sol.h5::append 21 22 The particles can be visualized using 23 24 -part_dm_view draw -part_dm_view_swarm_radius 0.03 25 26 F*/ 27 28 #include <petscdmplex.h> 29 #include <petscdmswarm.h> 30 #include <petscts.h> 31 #include <petscds.h> 32 #include <petscbag.h> 33 34 typedef enum {SOL_TRIG_TRIG, NUM_SOL_TYPES} SolType; 35 const char *solTypes[NUM_SOL_TYPES+1] = {"trig_trig", "unknown"}; 36 37 typedef enum {PART_LAYOUT_CELL, PART_LAYOUT_BOX, NUM_PART_LAYOUT_TYPES} PartLayoutType; 38 const char *partLayoutTypes[NUM_PART_LAYOUT_TYPES+1] = {"cell", "box", "unknown"}; 39 40 typedef struct { 41 PetscReal nu; /* Kinematic viscosity */ 42 PetscReal alpha; /* Thermal diffusivity */ 43 PetscReal T_in; /* Inlet temperature*/ 44 PetscReal omega; /* Rotation speed in MMS benchmark */ 45 } Parameter; 46 47 typedef struct { 48 /* Problem definition */ 49 PetscBag bag; /* Holds problem parameters */ 50 SolType solType; /* MMS solution type */ 51 PartLayoutType partLayout; /* Type of particle distribution */ 52 PetscInt Npc; /* The initial number of particles per cell */ 53 PetscReal partLower[3]; /* Lower left corner of particle box */ 54 PetscReal partUpper[3]; /* Upper right corner of particle box */ 55 PetscInt Npb; /* The initial number of particles per box dimension */ 56 } AppCtx; 57 58 typedef struct { 59 PetscReal ti; /* The time for ui, at the beginning of the advection solve */ 60 PetscReal tf; /* The time for uf, at the end of the advection solve */ 61 Vec ui; /* The PDE solution field at ti */ 62 Vec uf; /* The PDE solution field at tf */ 63 Vec x0; /* The initial particle positions at t = 0 */ 64 PetscErrorCode (*exact)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *); 65 AppCtx *ctx; /* Context for exact solution */ 66 } AdvCtx; 67 68 static PetscErrorCode zero(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx) 69 { 70 PetscInt d; 71 for (d = 0; d < Nc; ++d) u[d] = 0.0; 72 return 0; 73 } 74 75 static PetscErrorCode constant(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nc, PetscScalar *u, void *ctx) 76 { 77 PetscInt d; 78 for (d = 0; d < Nc; ++d) u[d] = 1.0; 79 return 0; 80 } 81 82 /* 83 CASE: trigonometric-trigonometric 84 In 2D we use exact solution: 85 86 x = r0 cos(w t + theta0) r0 = sqrt(x0^2 + y0^2) 87 y = r0 sin(w t + theta0) theta0 = arctan(y0/x0) 88 u = -w r0 sin(theta0) = -w y 89 v = w r0 cos(theta0) = w x 90 p = x + y - 1 91 T = t + x + y 92 f = <1, 1> 93 Q = 1 + w (x - y)/r 94 95 so that 96 97 \nabla \cdot u = 0 + 0 = 0 98 99 f = du/dt + u \cdot \nabla u - \nu \Delta u + \nabla p 100 = <0, 0> + u_i d_i u_j - \nu 0 + <1, 1> 101 = <1, 1> + w^2 <-y, x> . <<0, 1>, <-1, 0>> 102 = <1, 1> + w^2 <-x, -y> 103 = <1, 1> - w^2 <x, y> 104 105 Q = dT/dt + u \cdot \nabla T - \alpha \Delta T 106 = 1 + <u, v> . <1, 1> - \alpha 0 107 = 1 + u + v 108 */ 109 static PetscErrorCode trig_trig_x(PetscInt dim, PetscReal time, const PetscReal X[], PetscInt Nf, PetscScalar *x, void *ctx) 110 { 111 const PetscReal x0 = X[0]; 112 const PetscReal y0 = X[1]; 113 const PetscReal R0 = PetscSqrtReal(x0*x0 + y0*y0); 114 const PetscReal theta0 = PetscAtan2Real(y0, x0); 115 Parameter *p = (Parameter *) ctx; 116 117 x[0] = R0*PetscCosReal(p->omega*time + theta0); 118 x[1] = R0*PetscSinReal(p->omega*time + theta0); 119 return 0; 120 } 121 static PetscErrorCode trig_trig_u(PetscInt dim, PetscReal time, const PetscReal X[], PetscInt Nf, PetscScalar *u, void *ctx) 122 { 123 Parameter *p = (Parameter *) ctx; 124 125 u[0] = -p->omega*X[1]; 126 u[1] = p->omega*X[0]; 127 return 0; 128 } 129 static PetscErrorCode trig_trig_u_t(PetscInt dim, PetscReal time, const PetscReal X[], PetscInt Nf, PetscScalar *u, void *ctx) 130 { 131 u[0] = 0.0; 132 u[1] = 0.0; 133 return 0; 134 } 135 136 static PetscErrorCode trig_trig_p(PetscInt dim, PetscReal time, const PetscReal X[], PetscInt Nf, PetscScalar *p, void *ctx) 137 { 138 p[0] = X[0] + X[1] - 1.0; 139 return 0; 140 } 141 142 static PetscErrorCode trig_trig_T(PetscInt dim, PetscReal time, const PetscReal X[], PetscInt Nf, PetscScalar *T, void *ctx) 143 { 144 T[0] = time + X[0] + X[1]; 145 return 0; 146 } 147 static PetscErrorCode trig_trig_T_t(PetscInt dim, PetscReal time, const PetscReal X[], PetscInt Nf, PetscScalar *T, void *ctx) 148 { 149 T[0] = 1.0; 150 return 0; 151 } 152 153 static void f0_trig_trig_v(PetscInt dim, PetscInt Nf, PetscInt NfAux, 154 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], 155 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], 156 PetscReal t, const PetscReal X[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[]) 157 { 158 const PetscReal omega = PetscRealPart(constants[3]); 159 PetscInt Nc = dim; 160 PetscInt c, d; 161 162 for (d = 0; d < dim; ++d) f0[d] = u_t[uOff[0]+d]; 163 164 for (c = 0; c < Nc; ++c) { 165 for (d = 0; d < dim; ++d) f0[c] += u[d]*u_x[c*dim+d]; 166 } 167 f0[0] -= 1.0 - omega*omega*X[0]; 168 f0[1] -= 1.0 - omega*omega*X[1]; 169 } 170 171 static void f0_trig_trig_w(PetscInt dim, PetscInt Nf, PetscInt NfAux, 172 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], 173 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], 174 PetscReal t, const PetscReal X[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[]) 175 { 176 const PetscReal omega = PetscRealPart(constants[3]); 177 PetscInt d; 178 179 for (d = 0, f0[0] = 0; d < dim; ++d) f0[0] += u[uOff[0]+d]*u_x[uOff_x[2]+d]; 180 f0[0] += u_t[uOff[2]] - (1.0 + omega*(X[0] - X[1])); 181 } 182 183 static void f0_q(PetscInt dim, PetscInt Nf, PetscInt NfAux, 184 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], 185 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], 186 PetscReal t, const PetscReal X[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f0[]) 187 { 188 PetscInt d; 189 for (d = 0, f0[0] = 0.0; d < dim; ++d) f0[0] += u_x[d*dim+d]; 190 } 191 192 /*f1_v = \nu[grad(u) + grad(u)^T] - pI */ 193 static void f1_v(PetscInt dim, PetscInt Nf, PetscInt NfAux, 194 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], 195 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], 196 PetscReal t, const PetscReal X[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f1[]) 197 { 198 const PetscReal nu = PetscRealPart(constants[0]); 199 const PetscInt Nc = dim; 200 PetscInt c, d; 201 202 for (c = 0; c < Nc; ++c) { 203 for (d = 0; d < dim; ++d) { 204 f1[c*dim+d] = nu*(u_x[c*dim+d] + u_x[d*dim+c]); 205 } 206 f1[c*dim+c] -= u[uOff[1]]; 207 } 208 } 209 210 static void f1_w(PetscInt dim, PetscInt Nf, PetscInt NfAux, 211 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], 212 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], 213 PetscReal t, const PetscReal X[], PetscInt numConstants, const PetscScalar constants[], PetscScalar f1[]) 214 { 215 const PetscReal alpha = PetscRealPart(constants[1]); 216 PetscInt d; 217 for (d = 0; d < dim; ++d) f1[d] = alpha*u_x[uOff_x[2]+d]; 218 } 219 220 /*Jacobians*/ 221 static void g1_qu(PetscInt dim, PetscInt Nf, PetscInt NfAux, 222 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], 223 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], 224 PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g1[]) 225 { 226 PetscInt d; 227 for (d = 0; d < dim; ++d) g1[d*dim+d] = 1.0; 228 } 229 230 static void g0_vu(PetscInt dim, PetscInt Nf, PetscInt NfAux, 231 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], 232 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], 233 PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]) 234 { 235 PetscInt c, d; 236 const PetscInt Nc = dim; 237 238 for (d = 0; d < dim; ++d) g0[d*dim+d] = u_tShift; 239 240 for (c = 0; c < Nc; ++c) { 241 for (d = 0; d < dim; ++d) { 242 g0[c*Nc+d] += u_x[c*Nc+d]; 243 } 244 } 245 } 246 247 static void g1_vu(PetscInt dim, PetscInt Nf, PetscInt NfAux, 248 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], 249 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], 250 PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g1[]) 251 { 252 PetscInt NcI = dim; 253 PetscInt NcJ = dim; 254 PetscInt c, d, e; 255 256 for (c = 0; c < NcI; ++c) { 257 for (d = 0; d < NcJ; ++d) { 258 for (e = 0; e < dim; ++e) { 259 if (c == d) { 260 g1[(c*NcJ+d)*dim+e] += u[e]; 261 } 262 } 263 } 264 } 265 } 266 267 268 static void g2_vp(PetscInt dim, PetscInt Nf, PetscInt NfAux, 269 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], 270 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], 271 PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g2[]) 272 { 273 PetscInt d; 274 for (d = 0; d < dim; ++d) g2[d*dim+d] = -1.0; 275 } 276 277 static void g3_vu(PetscInt dim, PetscInt Nf, PetscInt NfAux, 278 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], 279 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], 280 PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g3[]) 281 { 282 const PetscReal nu = PetscRealPart(constants[0]); 283 const PetscInt Nc = dim; 284 PetscInt c, d; 285 286 for (c = 0; c < Nc; ++c) { 287 for (d = 0; d < dim; ++d) { 288 g3[((c*Nc+c)*dim+d)*dim+d] += nu; // gradU 289 g3[((c*Nc+d)*dim+d)*dim+c] += nu; // gradU transpose 290 } 291 } 292 } 293 294 static void g0_wT(PetscInt dim, PetscInt Nf, PetscInt NfAux, 295 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], 296 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], 297 PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]) 298 { 299 PetscInt d; 300 for (d = 0; d < dim; ++d) g0[d] = u_tShift; 301 } 302 303 static void g0_wu(PetscInt dim, PetscInt Nf, PetscInt NfAux, 304 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], 305 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], 306 PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g0[]) 307 { 308 PetscInt d; 309 for (d = 0; d < dim; ++d) g0[d] = u_x[uOff_x[2]+d]; 310 } 311 312 static void g1_wT(PetscInt dim, PetscInt Nf, PetscInt NfAux, 313 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], 314 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], 315 PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g1[]) 316 { 317 PetscInt d; 318 for (d = 0; d < dim; ++d) g1[d] = u[uOff[0]+d]; 319 } 320 321 static void g3_wT(PetscInt dim, PetscInt Nf, PetscInt NfAux, 322 const PetscInt uOff[], const PetscInt uOff_x[], const PetscScalar u[], const PetscScalar u_t[], const PetscScalar u_x[], 323 const PetscInt aOff[], const PetscInt aOff_x[], const PetscScalar a[], const PetscScalar a_t[], const PetscScalar a_x[], 324 PetscReal t, PetscReal u_tShift, const PetscReal x[], PetscInt numConstants, const PetscScalar constants[], PetscScalar g3[]) 325 { 326 const PetscReal alpha = PetscRealPart(constants[1]); 327 PetscInt d; 328 329 for (d = 0; d < dim; ++d) g3[d*dim+d] = alpha; 330 } 331 332 static PetscErrorCode ProcessOptions(MPI_Comm comm, AppCtx *options) 333 { 334 PetscInt sol, pl, n; 335 PetscErrorCode ierr; 336 337 PetscFunctionBeginUser; 338 options->solType = SOL_TRIG_TRIG; 339 options->partLayout = PART_LAYOUT_CELL; 340 options->Npc = 1; 341 options->Npb = 1; 342 343 options->partLower[0] = options->partLower[1] = options->partLower[2] = 0.; 344 options->partUpper[0] = options->partUpper[1] = options->partUpper[2] = 1.; 345 ierr = PetscOptionsBegin(comm, "", "Low Mach flow Problem Options", "DMPLEX");CHKERRQ(ierr); 346 sol = options->solType; 347 ierr = PetscOptionsEList("-sol_type", "The solution type", "ex77.c", solTypes, NUM_SOL_TYPES, solTypes[options->solType], &sol, NULL);CHKERRQ(ierr); 348 options->solType = (SolType) sol; 349 pl = options->partLayout; 350 ierr = PetscOptionsEList("-part_layout_type", "The particle layout type", "ex77.c", partLayoutTypes, NUM_PART_LAYOUT_TYPES, partLayoutTypes[options->partLayout], &pl, NULL);CHKERRQ(ierr); 351 options->partLayout = (PartLayoutType) pl; 352 ierr = PetscOptionsInt("-Npc", "The initial number of particles per cell", "ex77.c", options->Npc, &options->Npc, NULL);CHKERRQ(ierr); 353 n = 3; 354 ierr = PetscOptionsRealArray("-part_lower", "The lower left corner of the particle box", "ex77.c", options->partLower, &n, NULL);CHKERRQ(ierr); 355 n = 3; 356 ierr = PetscOptionsRealArray("-part_upper", "The upper right corner of the particle box", "ex77.c", options->partUpper, &n, NULL);CHKERRQ(ierr); 357 ierr = PetscOptionsInt("-Npb", "The initial number of particles per box dimension", "ex77.c", options->Npb, &options->Npb, NULL);CHKERRQ(ierr); 358 ierr = PetscOptionsEnd(); 359 PetscFunctionReturn(0); 360 } 361 362 static PetscErrorCode SetupParameters(AppCtx *user) 363 { 364 PetscBag bag; 365 Parameter *p; 366 PetscErrorCode ierr; 367 368 PetscFunctionBeginUser; 369 /* setup PETSc parameter bag */ 370 ierr = PetscBagGetData(user->bag, (void **) &p);CHKERRQ(ierr); 371 ierr = PetscBagSetName(user->bag, "par", "Low Mach flow parameters");CHKERRQ(ierr); 372 bag = user->bag; 373 ierr = PetscBagRegisterReal(bag, &p->nu, 1.0, "nu", "Kinematic viscosity");CHKERRQ(ierr); 374 ierr = PetscBagRegisterReal(bag, &p->alpha, 1.0, "alpha", "Thermal diffusivity");CHKERRQ(ierr); 375 ierr = PetscBagRegisterReal(bag, &p->T_in, 1.0, "T_in", "Inlet temperature");CHKERRQ(ierr); 376 ierr = PetscBagRegisterReal(bag, &p->omega, 1.0, "omega", "Rotation speed in MMS benchmark");CHKERRQ(ierr); 377 PetscFunctionReturn(0); 378 } 379 380 static PetscErrorCode CreateMesh(MPI_Comm comm, AppCtx *user, DM *dm) 381 { 382 PetscErrorCode ierr; 383 384 PetscFunctionBeginUser; 385 ierr = DMCreate(comm, dm);CHKERRQ(ierr); 386 ierr = DMSetType(*dm, DMPLEX);CHKERRQ(ierr); 387 ierr = DMSetFromOptions(*dm);CHKERRQ(ierr); 388 ierr = DMViewFromOptions(*dm, NULL, "-dm_view");CHKERRQ(ierr); 389 PetscFunctionReturn(0); 390 } 391 392 static PetscErrorCode SetupProblem(DM dm, AppCtx *user) 393 { 394 PetscErrorCode (*exactFuncs[3])(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar *u, void *ctx); 395 PetscErrorCode (*exactFuncs_t[3])(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar *u, void *ctx); 396 PetscDS prob; 397 DMLabel label; 398 Parameter *ctx; 399 PetscInt id; 400 PetscErrorCode ierr; 401 402 PetscFunctionBeginUser; 403 ierr = DMGetLabel(dm, "marker", &label);CHKERRQ(ierr); 404 ierr = DMGetDS(dm, &prob);CHKERRQ(ierr); 405 switch(user->solType){ 406 case SOL_TRIG_TRIG: 407 ierr = PetscDSSetResidual(prob, 0, f0_trig_trig_v, f1_v);CHKERRQ(ierr); 408 ierr = PetscDSSetResidual(prob, 2, f0_trig_trig_w, f1_w);CHKERRQ(ierr); 409 410 exactFuncs[0] = trig_trig_u; 411 exactFuncs[1] = trig_trig_p; 412 exactFuncs[2] = trig_trig_T; 413 exactFuncs_t[0] = trig_trig_u_t; 414 exactFuncs_t[1] = NULL; 415 exactFuncs_t[2] = trig_trig_T_t; 416 break; 417 default: SETERRQ2(PetscObjectComm((PetscObject) prob), PETSC_ERR_ARG_WRONG, "Unsupported solution type: %s (%D)", solTypes[PetscMin(user->solType, NUM_SOL_TYPES)], user->solType); 418 } 419 420 ierr = PetscDSSetResidual(prob, 1, f0_q, NULL);CHKERRQ(ierr); 421 422 ierr = PetscDSSetJacobian(prob, 0, 0, g0_vu, g1_vu, NULL, g3_vu);CHKERRQ(ierr); 423 ierr = PetscDSSetJacobian(prob, 0, 1, NULL, NULL, g2_vp, NULL);CHKERRQ(ierr); 424 ierr = PetscDSSetJacobian(prob, 1, 0, NULL, g1_qu, NULL, NULL);CHKERRQ(ierr); 425 ierr = PetscDSSetJacobian(prob, 2, 0, g0_wu, NULL, NULL, NULL);CHKERRQ(ierr); 426 ierr = PetscDSSetJacobian(prob, 2, 2, g0_wT, g1_wT, NULL, g3_wT);CHKERRQ(ierr); 427 /* Setup constants */ 428 { 429 Parameter *param; 430 PetscScalar constants[4]; 431 432 ierr = PetscBagGetData(user->bag, (void **) ¶m);CHKERRQ(ierr); 433 434 constants[0] = param->nu; 435 constants[1] = param->alpha; 436 constants[2] = param->T_in; 437 constants[3] = param->omega; 438 ierr = PetscDSSetConstants(prob, 4, constants);CHKERRQ(ierr); 439 } 440 /* Setup Boundary Conditions */ 441 ierr = PetscBagGetData(user->bag, (void **) &ctx);CHKERRQ(ierr); 442 id = 3; 443 ierr = PetscDSAddBoundary(prob, DM_BC_ESSENTIAL, "top wall velocity", label, 1, &id, 0, 0, NULL, (void (*)(void)) exactFuncs[0], (void (*)(void)) exactFuncs_t[0], ctx, NULL);CHKERRQ(ierr); 444 id = 1; 445 ierr = PetscDSAddBoundary(prob, DM_BC_ESSENTIAL, "bottom wall velocity", label, 1, &id, 0, 0, NULL, (void (*)(void)) exactFuncs[0], (void (*)(void)) exactFuncs_t[0], ctx, NULL);CHKERRQ(ierr); 446 id = 2; 447 ierr = PetscDSAddBoundary(prob, DM_BC_ESSENTIAL, "right wall velocity", label, 1, &id, 0, 0, NULL, (void (*)(void)) exactFuncs[0], (void (*)(void)) exactFuncs_t[0], ctx, NULL);CHKERRQ(ierr); 448 id = 4; 449 ierr = PetscDSAddBoundary(prob, DM_BC_ESSENTIAL, "left wall velocity", label, 1, &id, 0, 0, NULL, (void (*)(void)) exactFuncs[0], (void (*)(void)) exactFuncs_t[0], ctx, NULL);CHKERRQ(ierr); 450 id = 3; 451 ierr = PetscDSAddBoundary(prob, DM_BC_ESSENTIAL, "top wall temp", label, 1, &id, 2, 0, NULL, (void (*)(void)) exactFuncs[2], (void (*)(void)) exactFuncs_t[2], ctx, NULL);CHKERRQ(ierr); 452 id = 1; 453 ierr = PetscDSAddBoundary(prob, DM_BC_ESSENTIAL, "bottom wall temp", label, 1, &id, 2, 0, NULL, (void (*)(void)) exactFuncs[2], (void (*)(void)) exactFuncs_t[2], ctx, NULL);CHKERRQ(ierr); 454 id = 2; 455 ierr = PetscDSAddBoundary(prob, DM_BC_ESSENTIAL, "right wall temp", label, 1, &id, 2, 0, NULL, (void (*)(void)) exactFuncs[2], (void (*)(void)) exactFuncs_t[2], ctx, NULL);CHKERRQ(ierr); 456 id = 4; 457 ierr = PetscDSAddBoundary(prob, DM_BC_ESSENTIAL, "left wall temp", label, 1, &id, 2, 0, NULL, (void (*)(void)) exactFuncs[2], (void (*)(void)) exactFuncs_t[2], ctx, NULL);CHKERRQ(ierr); 458 459 /*setup exact solution.*/ 460 ierr = PetscDSSetExactSolution(prob, 0, exactFuncs[0], ctx);CHKERRQ(ierr); 461 ierr = PetscDSSetExactSolution(prob, 1, exactFuncs[1], ctx);CHKERRQ(ierr); 462 ierr = PetscDSSetExactSolution(prob, 2, exactFuncs[2], ctx);CHKERRQ(ierr); 463 ierr = PetscDSSetExactSolutionTimeDerivative(prob, 0, exactFuncs_t[0], ctx);CHKERRQ(ierr); 464 ierr = PetscDSSetExactSolutionTimeDerivative(prob, 1, exactFuncs_t[1], ctx);CHKERRQ(ierr); 465 ierr = PetscDSSetExactSolutionTimeDerivative(prob, 2, exactFuncs_t[2], ctx);CHKERRQ(ierr); 466 PetscFunctionReturn(0); 467 } 468 469 /* x_t = v 470 471 Note that here we use the velocity field at t_{n+1} to advect the particles from 472 t_n to t_{n+1}. If we use both of these fields, we could use Crank-Nicholson or 473 the method of characteristics. 474 */ 475 static PetscErrorCode FreeStreaming(TS ts, PetscReal t, Vec X, Vec F, void *ctx) 476 { 477 AdvCtx *adv = (AdvCtx *) ctx; 478 Vec u = adv->ui; 479 DM sdm, dm, vdm; 480 Vec vel, locvel, pvel; 481 IS vis; 482 DMInterpolationInfo ictx; 483 const PetscScalar *coords, *v; 484 PetscScalar *f; 485 PetscInt vf[1] = {0}; 486 PetscInt dim, Np; 487 PetscErrorCode ierr; 488 489 PetscFunctionBeginUser; 490 ierr = TSGetDM(ts, &sdm);CHKERRQ(ierr); 491 ierr = DMSwarmGetCellDM(sdm, &dm);CHKERRQ(ierr); 492 ierr = DMGetGlobalVector(sdm, &pvel);CHKERRQ(ierr); 493 ierr = DMSwarmGetLocalSize(sdm, &Np);CHKERRQ(ierr); 494 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 495 /* Get local velocity */ 496 ierr = DMCreateSubDM(dm, 1, vf, &vis, &vdm);CHKERRQ(ierr); 497 ierr = VecGetSubVector(u, vis, &vel);CHKERRQ(ierr); 498 ierr = DMGetLocalVector(vdm, &locvel);CHKERRQ(ierr); 499 ierr = DMPlexInsertBoundaryValues(vdm, PETSC_TRUE, locvel, adv->ti, NULL, NULL, NULL);CHKERRQ(ierr); 500 ierr = DMGlobalToLocalBegin(vdm, vel, INSERT_VALUES, locvel);CHKERRQ(ierr); 501 ierr = DMGlobalToLocalEnd(vdm, vel, INSERT_VALUES, locvel);CHKERRQ(ierr); 502 ierr = VecRestoreSubVector(u, vis, &vel);CHKERRQ(ierr); 503 ierr = ISDestroy(&vis);CHKERRQ(ierr); 504 /* Interpolate velocity */ 505 ierr = DMInterpolationCreate(PETSC_COMM_SELF, &ictx);CHKERRQ(ierr); 506 ierr = DMInterpolationSetDim(ictx, dim);CHKERRQ(ierr); 507 ierr = DMInterpolationSetDof(ictx, dim);CHKERRQ(ierr); 508 ierr = VecGetArrayRead(X, &coords);CHKERRQ(ierr); 509 ierr = DMInterpolationAddPoints(ictx, Np, (PetscReal *) coords);CHKERRQ(ierr); 510 ierr = VecRestoreArrayRead(X, &coords);CHKERRQ(ierr); 511 /* Particles that lie outside the domain should be dropped, 512 whereas particles that move to another partition should trigger a migration */ 513 ierr = DMInterpolationSetUp(ictx, vdm, PETSC_FALSE, PETSC_TRUE);CHKERRQ(ierr); 514 ierr = VecSet(pvel, 0.);CHKERRQ(ierr); 515 ierr = DMInterpolationEvaluate(ictx, vdm, locvel, pvel);CHKERRQ(ierr); 516 ierr = DMInterpolationDestroy(&ictx);CHKERRQ(ierr); 517 ierr = DMRestoreLocalVector(vdm, &locvel);CHKERRQ(ierr); 518 ierr = DMDestroy(&vdm);CHKERRQ(ierr); 519 520 ierr = VecGetArray(F, &f);CHKERRQ(ierr); 521 ierr = VecGetArrayRead(pvel, &v);CHKERRQ(ierr); 522 ierr = PetscArraycpy(f, v, Np*dim);CHKERRQ(ierr); 523 ierr = VecRestoreArrayRead(pvel, &v);CHKERRQ(ierr); 524 ierr = VecRestoreArray(F, &f);CHKERRQ(ierr); 525 ierr = DMRestoreGlobalVector(sdm, &pvel);CHKERRQ(ierr); 526 PetscFunctionReturn(0); 527 } 528 529 static PetscErrorCode SetInitialParticleConditions(TS ts, Vec u) 530 { 531 AppCtx *user; 532 void *ctx; 533 DM dm; 534 PetscScalar *coords; 535 PetscReal x[3], dx[3]; 536 PetscInt n[3]; 537 PetscInt Np, dim, d, i, j, k; 538 PetscErrorCode ierr; 539 540 PetscFunctionBegin; 541 ierr = TSGetApplicationContext(ts, &ctx);CHKERRQ(ierr); 542 user = ((AdvCtx *) ctx)->ctx; 543 ierr = TSGetDM(ts, &dm);CHKERRQ(ierr); 544 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 545 switch (user->partLayout) { 546 case PART_LAYOUT_CELL: 547 ierr = DMSwarmSetPointCoordinatesRandom(dm, user->Npc);CHKERRQ(ierr); 548 break; 549 case PART_LAYOUT_BOX: 550 Np = 1; 551 for (d = 0; d < dim; ++d) { 552 n[d] = user->Npb; 553 dx[d] = (user->partUpper[d] - user->partLower[d])/PetscMax(1, n[d] - 1); 554 Np *= n[d]; 555 } 556 ierr = VecGetArray(u, &coords);CHKERRQ(ierr); 557 switch (dim) { 558 case 2: 559 x[0] = user->partLower[0]; 560 for (i = 0; i < n[0]; ++i, x[0] += dx[0]) { 561 x[1] = user->partLower[1]; 562 for (j = 0; j < n[1]; ++j, x[1] += dx[1]) { 563 const PetscInt p = j*n[0] + i; 564 for (d = 0; d < dim; ++d) coords[p*dim + d] = x[d]; 565 } 566 } 567 break; 568 case 3: 569 x[0] = user->partLower[0]; 570 for (i = 0; i < n[0]; ++i, x[0] += dx[0]) { 571 x[1] = user->partLower[1]; 572 for (j = 0; j < n[1]; ++j, x[1] += dx[1]) { 573 x[2] = user->partLower[2]; 574 for (k = 0; k < n[2]; ++k, x[2] += dx[2]) { 575 const PetscInt p = (k*n[1] + j)*n[0] + i; 576 for (d = 0; d < dim; ++d) coords[p*dim + d] = x[d]; 577 } 578 } 579 } 580 break; 581 default: SETERRQ1(PetscObjectComm((PetscObject) ts), PETSC_ERR_SUP, "Do not support particle layout in dimension %D", dim); 582 } 583 ierr = VecRestoreArray(u, &coords);CHKERRQ(ierr); 584 break; 585 default: SETERRQ1(PetscObjectComm((PetscObject) ts), PETSC_ERR_ARG_WRONG, "Invalid particle layout type %s", partLayoutTypes[PetscMin(user->partLayout, NUM_PART_LAYOUT_TYPES)]); 586 } 587 PetscFunctionReturn(0); 588 } 589 590 static PetscErrorCode SetupDiscretization(DM dm, DM sdm, AppCtx *user) 591 { 592 DM cdm = dm; 593 PetscFE fe[3]; 594 Parameter *param; 595 PetscInt *cellid, n[3]; 596 PetscReal x[3], dx[3]; 597 PetscScalar *coords; 598 DMPolytopeType ct; 599 PetscInt dim, d, cStart, cEnd, c, Np, p, i, j, k; 600 PetscBool simplex; 601 MPI_Comm comm; 602 PetscErrorCode ierr; 603 604 PetscFunctionBeginUser; 605 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 606 ierr = DMPlexGetHeightStratum(dm, 0, &cStart, &cEnd);CHKERRQ(ierr); 607 ierr = DMPlexGetCellType(dm, cStart, &ct);CHKERRQ(ierr); 608 simplex = DMPolytopeTypeGetNumVertices(ct) == DMPolytopeTypeGetDim(ct)+1 ? PETSC_TRUE : PETSC_FALSE; 609 /* Create finite element */ 610 ierr = PetscObjectGetComm((PetscObject) dm, &comm);CHKERRQ(ierr); 611 ierr = PetscFECreateDefault(comm, dim, dim, simplex, "vel_", PETSC_DEFAULT, &fe[0]);CHKERRQ(ierr); 612 ierr = PetscObjectSetName((PetscObject) fe[0], "velocity");CHKERRQ(ierr); 613 614 ierr = PetscFECreateDefault(comm, dim, 1, simplex, "pres_", PETSC_DEFAULT, &fe[1]);CHKERRQ(ierr); 615 ierr = PetscFECopyQuadrature(fe[0], fe[1]);CHKERRQ(ierr); 616 ierr = PetscObjectSetName((PetscObject) fe[1], "pressure");CHKERRQ(ierr); 617 618 ierr = PetscFECreateDefault(comm, dim, 1, simplex, "temp_", PETSC_DEFAULT, &fe[2]);CHKERRQ(ierr); 619 ierr = PetscFECopyQuadrature(fe[0], fe[2]);CHKERRQ(ierr); 620 ierr = PetscObjectSetName((PetscObject) fe[2], "temperature");CHKERRQ(ierr); 621 622 /* Set discretization and boundary conditions for each mesh */ 623 ierr = DMSetField(dm, 0, NULL, (PetscObject) fe[0]);CHKERRQ(ierr); 624 ierr = DMSetField(dm, 1, NULL, (PetscObject) fe[1]);CHKERRQ(ierr); 625 ierr = DMSetField(dm, 2, NULL, (PetscObject) fe[2]);CHKERRQ(ierr); 626 ierr = DMCreateDS(dm);CHKERRQ(ierr); 627 ierr = SetupProblem(dm, user);CHKERRQ(ierr); 628 ierr = PetscBagGetData(user->bag, (void **) ¶m);CHKERRQ(ierr); 629 while (cdm) { 630 ierr = DMCopyDisc(dm, cdm);CHKERRQ(ierr); 631 ierr = DMGetCoarseDM(cdm, &cdm);CHKERRQ(ierr); 632 } 633 ierr = PetscFEDestroy(&fe[0]);CHKERRQ(ierr); 634 ierr = PetscFEDestroy(&fe[1]);CHKERRQ(ierr); 635 ierr = PetscFEDestroy(&fe[2]);CHKERRQ(ierr); 636 637 { 638 PetscObject pressure; 639 MatNullSpace nullspacePres; 640 641 ierr = DMGetField(dm, 1, NULL, &pressure);CHKERRQ(ierr); 642 ierr = MatNullSpaceCreate(PetscObjectComm(pressure), PETSC_TRUE, 0, NULL, &nullspacePres);CHKERRQ(ierr); 643 ierr = PetscObjectCompose(pressure, "nullspace", (PetscObject) nullspacePres);CHKERRQ(ierr); 644 ierr = MatNullSpaceDestroy(&nullspacePres);CHKERRQ(ierr); 645 } 646 647 /* Setup particle information */ 648 ierr = DMSwarmSetType(sdm, DMSWARM_PIC);CHKERRQ(ierr); 649 ierr = DMSwarmRegisterPetscDatatypeField(sdm, "mass", 1, PETSC_REAL);CHKERRQ(ierr); 650 ierr = DMSwarmFinalizeFieldRegister(sdm);CHKERRQ(ierr); 651 switch (user->partLayout) { 652 case PART_LAYOUT_CELL: 653 ierr = DMSwarmSetLocalSizes(sdm, (cEnd - cStart) * user->Npc, 0);CHKERRQ(ierr); 654 ierr = DMSetFromOptions(sdm);CHKERRQ(ierr); 655 ierr = DMSwarmGetField(sdm, DMSwarmPICField_cellid, NULL, NULL, (void **) &cellid);CHKERRQ(ierr); 656 for (c = cStart; c < cEnd; ++c) { 657 for (p = 0; p < user->Npc; ++p) { 658 const PetscInt n = c*user->Npc + p; 659 660 cellid[n] = c; 661 } 662 } 663 ierr = DMSwarmRestoreField(sdm, DMSwarmPICField_cellid, NULL, NULL, (void **) &cellid);CHKERRQ(ierr); 664 ierr = DMSwarmSetPointCoordinatesRandom(sdm, user->Npc);CHKERRQ(ierr); 665 break; 666 case PART_LAYOUT_BOX: 667 Np = 1; 668 for (d = 0; d < dim; ++d) { 669 n[d] = user->Npb; 670 dx[d] = (user->partUpper[d] - user->partLower[d])/PetscMax(1, n[d] - 1); 671 Np *= n[d]; 672 } 673 ierr = DMSwarmSetLocalSizes(sdm, Np, 0);CHKERRQ(ierr); 674 ierr = DMSetFromOptions(sdm);CHKERRQ(ierr); 675 ierr = DMSwarmGetField(sdm, DMSwarmPICField_coor, NULL, NULL, (void **) &coords);CHKERRQ(ierr); 676 switch (dim) { 677 case 2: 678 x[0] = user->partLower[0]; 679 for (i = 0; i < n[0]; ++i, x[0] += dx[0]) { 680 x[1] = user->partLower[1]; 681 for (j = 0; j < n[1]; ++j, x[1] += dx[1]) { 682 const PetscInt p = j*n[0] + i; 683 for (d = 0; d < dim; ++d) coords[p*dim + d] = x[d]; 684 } 685 } 686 break; 687 case 3: 688 x[0] = user->partLower[0]; 689 for (i = 0; i < n[0]; ++i, x[0] += dx[0]) { 690 x[1] = user->partLower[1]; 691 for (j = 0; j < n[1]; ++j, x[1] += dx[1]) { 692 x[2] = user->partLower[2]; 693 for (k = 0; k < n[2]; ++k, x[2] += dx[2]) { 694 const PetscInt p = (k*n[1] + j)*n[0] + i; 695 for (d = 0; d < dim; ++d) coords[p*dim + d] = x[d]; 696 } 697 } 698 } 699 break; 700 default: SETERRQ1(comm, PETSC_ERR_SUP, "Do not support particle layout in dimension %D", dim); 701 } 702 ierr = DMSwarmRestoreField(sdm, DMSwarmPICField_coor, NULL, NULL, (void **) &coords);CHKERRQ(ierr); 703 ierr = DMSwarmGetField(sdm, DMSwarmPICField_cellid, NULL, NULL, (void **) &cellid);CHKERRQ(ierr); 704 for (p = 0; p < Np; ++p) cellid[p] = 0; 705 ierr = DMSwarmRestoreField(sdm, DMSwarmPICField_cellid, NULL, NULL, (void **) &cellid);CHKERRQ(ierr); 706 ierr = DMSwarmMigrate(sdm, PETSC_TRUE);CHKERRQ(ierr); 707 break; 708 default: SETERRQ1(comm, PETSC_ERR_ARG_WRONG, "Invalid particle layout type %s", partLayoutTypes[PetscMin(user->partLayout, NUM_PART_LAYOUT_TYPES)]); 709 } 710 ierr = PetscObjectSetName((PetscObject) sdm, "Particles");CHKERRQ(ierr); 711 ierr = DMViewFromOptions(sdm, NULL, "-dm_view");CHKERRQ(ierr); 712 PetscFunctionReturn(0); 713 } 714 715 static PetscErrorCode CreatePressureNullSpace(DM dm, PetscInt ofield, PetscInt nfield, MatNullSpace *nullSpace) 716 { 717 Vec vec; 718 PetscErrorCode (*funcs[3])(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *) = {zero, zero, zero}; 719 PetscErrorCode ierr; 720 721 PetscFunctionBeginUser; 722 if (ofield != 1) SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_ARG_WRONG, "Nullspace must be for pressure field at index 1, not %D", ofield); 723 funcs[nfield] = constant; 724 ierr = DMCreateGlobalVector(dm, &vec);CHKERRQ(ierr); 725 ierr = DMProjectFunction(dm, 0.0, funcs, NULL, INSERT_ALL_VALUES, vec);CHKERRQ(ierr); 726 ierr = VecNormalize(vec, NULL);CHKERRQ(ierr); 727 ierr = PetscObjectSetName((PetscObject) vec, "Pressure Null Space");CHKERRQ(ierr); 728 ierr = VecViewFromOptions(vec, NULL, "-pressure_nullspace_view");CHKERRQ(ierr); 729 ierr = MatNullSpaceCreate(PetscObjectComm((PetscObject) dm), PETSC_FALSE, 1, &vec, nullSpace);CHKERRQ(ierr); 730 ierr = VecDestroy(&vec);CHKERRQ(ierr); 731 PetscFunctionReturn(0); 732 } 733 734 static PetscErrorCode RemoveDiscretePressureNullspace_Private(TS ts, Vec u) 735 { 736 DM dm; 737 MatNullSpace nullsp; 738 PetscErrorCode ierr; 739 740 PetscFunctionBegin; 741 ierr = TSGetDM(ts, &dm);CHKERRQ(ierr); 742 ierr = CreatePressureNullSpace(dm, 1, 1, &nullsp);CHKERRQ(ierr); 743 ierr = MatNullSpaceRemove(nullsp, u);CHKERRQ(ierr); 744 ierr = MatNullSpaceDestroy(&nullsp);CHKERRQ(ierr); 745 PetscFunctionReturn(0); 746 } 747 748 /* Make the discrete pressure discretely divergence free */ 749 static PetscErrorCode RemoveDiscretePressureNullspace(TS ts) 750 { 751 Vec u; 752 PetscErrorCode ierr; 753 754 PetscFunctionBegin; 755 ierr = TSGetSolution(ts, &u);CHKERRQ(ierr); 756 ierr = RemoveDiscretePressureNullspace_Private(ts, u);CHKERRQ(ierr); 757 PetscFunctionReturn(0); 758 } 759 760 static PetscErrorCode SetInitialConditions(TS ts, Vec u) 761 { 762 DM dm; 763 PetscReal t; 764 PetscErrorCode ierr; 765 766 PetscFunctionBegin; 767 ierr = TSGetDM(ts, &dm);CHKERRQ(ierr); 768 ierr = TSGetTime(ts, &t);CHKERRQ(ierr); 769 ierr = DMComputeExactSolution(dm, t, u, NULL);CHKERRQ(ierr); 770 ierr = RemoveDiscretePressureNullspace_Private(ts, u);CHKERRQ(ierr); 771 PetscFunctionReturn(0); 772 } 773 774 static PetscErrorCode MonitorError(TS ts, PetscInt step, PetscReal crtime, Vec u, void *ctx) 775 { 776 PetscErrorCode (*exactFuncs[3])(PetscInt dim, PetscReal time, const PetscReal x[], PetscInt Nf, PetscScalar *u, void *ctx); 777 void *ctxs[3]; 778 DM dm; 779 PetscDS ds; 780 Vec v; 781 PetscReal ferrors[3]; 782 PetscInt tl, l, f; 783 PetscErrorCode ierr; 784 785 PetscFunctionBeginUser; 786 ierr = TSGetDM(ts, &dm);CHKERRQ(ierr); 787 ierr = DMGetDS(dm, &ds);CHKERRQ(ierr); 788 789 for (f = 0; f < 3; ++f) {ierr = PetscDSGetExactSolution(ds, f, &exactFuncs[f], &ctxs[f]);CHKERRQ(ierr);} 790 ierr = DMComputeL2FieldDiff(dm, crtime, exactFuncs, ctxs, u, ferrors);CHKERRQ(ierr); 791 ierr = PetscObjectGetTabLevel((PetscObject) ts, &tl);CHKERRQ(ierr); 792 for (l = 0; l < tl; ++l) {ierr = PetscPrintf(PETSC_COMM_WORLD, "\t");CHKERRQ(ierr);} 793 ierr = PetscPrintf(PETSC_COMM_WORLD, "Timestep: %04d time = %-8.4g \t L_2 Error: [%2.3g, %2.3g, %2.3g]\n", (int) step, (double) crtime, (double) ferrors[0], (double) ferrors[1], (double) ferrors[2]);CHKERRQ(ierr); 794 795 ierr = DMGetGlobalVector(dm, &u);CHKERRQ(ierr); 796 ierr = PetscObjectSetName((PetscObject) u, "Numerical Solution");CHKERRQ(ierr); 797 ierr = VecViewFromOptions(u, NULL, "-sol_vec_view");CHKERRQ(ierr); 798 ierr = DMRestoreGlobalVector(dm, &u);CHKERRQ(ierr); 799 800 ierr = DMGetGlobalVector(dm, &v);CHKERRQ(ierr); 801 ierr = DMProjectFunction(dm, 0.0, exactFuncs, ctxs, INSERT_ALL_VALUES, v);CHKERRQ(ierr); 802 ierr = PetscObjectSetName((PetscObject) v, "Exact Solution");CHKERRQ(ierr); 803 ierr = VecViewFromOptions(v, NULL, "-exact_vec_view");CHKERRQ(ierr); 804 ierr = DMRestoreGlobalVector(dm, &v);CHKERRQ(ierr); 805 806 PetscFunctionReturn(0); 807 } 808 809 /* Note that adv->x0 will not be correct after migration */ 810 static PetscErrorCode ComputeParticleError(TS ts, Vec u, Vec e) 811 { 812 AdvCtx *adv; 813 DM sdm; 814 Parameter *param; 815 const PetscScalar *xp0, *xp; 816 PetscScalar *ep; 817 PetscReal time; 818 PetscInt dim, Np, p; 819 MPI_Comm comm; 820 PetscErrorCode ierr; 821 822 PetscFunctionBeginUser; 823 ierr = TSGetTime(ts, &time);CHKERRQ(ierr); 824 ierr = TSGetApplicationContext(ts, (void **) &adv);CHKERRQ(ierr); 825 ierr = PetscBagGetData(adv->ctx->bag, (void **) ¶m);CHKERRQ(ierr); 826 ierr = PetscObjectGetComm((PetscObject) ts, &comm);CHKERRQ(ierr); 827 ierr = TSGetDM(ts, &sdm);CHKERRQ(ierr); 828 ierr = DMGetDimension(sdm, &dim);CHKERRQ(ierr); 829 ierr = DMSwarmGetLocalSize(sdm, &Np);CHKERRQ(ierr); 830 ierr = VecGetArrayRead(adv->x0, &xp0);CHKERRQ(ierr); 831 ierr = VecGetArrayRead(u, &xp);CHKERRQ(ierr); 832 ierr = VecGetArrayWrite(e, &ep);CHKERRQ(ierr); 833 for (p = 0; p < Np; ++p) { 834 PetscScalar x[3]; 835 PetscReal x0[3]; 836 PetscInt d; 837 838 for (d = 0; d < dim; ++d) x0[d] = PetscRealPart(xp0[p*dim+d]); 839 ierr = adv->exact(dim, time, x0, 1, x, param);CHKERRQ(ierr); 840 for (d = 0; d < dim; ++d) ep[p*dim+d] += x[d] - xp[p*dim+d]; 841 } 842 ierr = VecRestoreArrayRead(adv->x0, &xp0);CHKERRQ(ierr); 843 ierr = VecRestoreArrayRead(u, &xp);CHKERRQ(ierr); 844 ierr = VecRestoreArrayWrite(e, &ep);CHKERRQ(ierr); 845 PetscFunctionReturn(0); 846 } 847 848 static PetscErrorCode MonitorParticleError(TS ts, PetscInt step, PetscReal time, Vec u, void *ctx) 849 { 850 AdvCtx *adv = (AdvCtx *) ctx; 851 DM sdm; 852 Parameter *param; 853 const PetscScalar *xp0, *xp; 854 PetscReal error = 0.0; 855 PetscInt dim, tl, l, Np, p; 856 MPI_Comm comm; 857 PetscErrorCode ierr; 858 859 PetscFunctionBeginUser; 860 ierr = PetscBagGetData(adv->ctx->bag, (void **) ¶m);CHKERRQ(ierr); 861 ierr = PetscObjectGetComm((PetscObject) ts, &comm);CHKERRQ(ierr); 862 ierr = TSGetDM(ts, &sdm);CHKERRQ(ierr); 863 ierr = DMGetDimension(sdm, &dim);CHKERRQ(ierr); 864 ierr = DMSwarmGetLocalSize(sdm, &Np);CHKERRQ(ierr); 865 ierr = VecGetArrayRead(adv->x0, &xp0);CHKERRQ(ierr); 866 ierr = VecGetArrayRead(u, &xp);CHKERRQ(ierr); 867 for (p = 0; p < Np; ++p) { 868 PetscScalar x[3]; 869 PetscReal x0[3]; 870 PetscReal perror = 0.0; 871 PetscInt d; 872 873 for (d = 0; d < dim; ++d) x0[d] = PetscRealPart(xp0[p*dim+d]); 874 ierr = adv->exact(dim, time, x0, 1, x, param);CHKERRQ(ierr); 875 for (d = 0; d < dim; ++d) perror += PetscSqr(PetscRealPart(x[d] - xp[p*dim+d])); 876 error += perror; 877 } 878 ierr = VecRestoreArrayRead(adv->x0, &xp0);CHKERRQ(ierr); 879 ierr = VecRestoreArrayRead(u, &xp);CHKERRQ(ierr); 880 ierr = PetscObjectGetTabLevel((PetscObject) ts, &tl);CHKERRQ(ierr); 881 for (l = 0; l < tl; ++l) {ierr = PetscPrintf(PETSC_COMM_WORLD, "\t");CHKERRQ(ierr);} 882 ierr = PetscPrintf(comm, "Timestep: %04d time = %-8.4g \t L_2 Particle Error: [%2.3g]\n", (int) step, (double) time, (double) error);CHKERRQ(ierr); 883 PetscFunctionReturn(0); 884 } 885 886 static PetscErrorCode AdvectParticles(TS ts) 887 { 888 TS sts; 889 DM sdm; 890 Vec coordinates; 891 AdvCtx *adv; 892 PetscReal time; 893 PetscBool lreset, reset; 894 PetscInt dim, n, N, newn, newN; 895 PetscErrorCode ierr; 896 897 PetscFunctionBeginUser; 898 ierr = PetscObjectQuery((PetscObject) ts, "_SwarmTS", (PetscObject *) &sts);CHKERRQ(ierr); 899 ierr = TSGetDM(sts, &sdm);CHKERRQ(ierr); 900 ierr = TSGetRHSFunction(sts, NULL, NULL, (void **) &adv);CHKERRQ(ierr); 901 ierr = DMGetDimension(sdm, &dim);CHKERRQ(ierr); 902 ierr = DMSwarmGetSize(sdm, &N);CHKERRQ(ierr); 903 ierr = DMSwarmGetLocalSize(sdm, &n);CHKERRQ(ierr); 904 ierr = DMSwarmCreateGlobalVectorFromField(sdm, DMSwarmPICField_coor, &coordinates);CHKERRQ(ierr); 905 ierr = TSGetTime(ts, &time);CHKERRQ(ierr); 906 ierr = TSSetMaxTime(sts, time);CHKERRQ(ierr); 907 adv->tf = time; 908 ierr = TSSolve(sts, coordinates);CHKERRQ(ierr); 909 ierr = DMSwarmDestroyGlobalVectorFromField(sdm, DMSwarmPICField_coor, &coordinates);CHKERRQ(ierr); 910 ierr = VecCopy(adv->uf, adv->ui);CHKERRQ(ierr); 911 adv->ti = adv->tf; 912 913 ierr = DMSwarmMigrate(sdm, PETSC_TRUE);CHKERRQ(ierr); 914 ierr = DMSwarmGetSize(sdm, &newN);CHKERRQ(ierr); 915 ierr = DMSwarmGetLocalSize(sdm, &newn);CHKERRQ(ierr); 916 lreset = (n != newn || N != newN) ? PETSC_TRUE : PETSC_FALSE; 917 ierr = MPI_Allreduce(&lreset, &reset, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject) sts));CHKERRMPI(ierr); 918 if (reset) { 919 ierr = TSReset(sts);CHKERRQ(ierr); 920 ierr = DMSwarmVectorDefineField(sdm, DMSwarmPICField_coor);CHKERRQ(ierr); 921 } 922 ierr = DMViewFromOptions(sdm, NULL, "-dm_view");CHKERRQ(ierr); 923 PetscFunctionReturn(0); 924 } 925 926 int main(int argc, char **argv) 927 { 928 DM dm, sdm; 929 TS ts, sts; 930 Vec u, xtmp; 931 AppCtx user; 932 AdvCtx adv; 933 PetscReal t; 934 PetscInt dim; 935 PetscErrorCode ierr; 936 937 ierr = PetscInitialize(&argc, &argv, NULL,help);if (ierr) return ierr; 938 ierr = ProcessOptions(PETSC_COMM_WORLD, &user);CHKERRQ(ierr); 939 ierr = PetscBagCreate(PETSC_COMM_WORLD, sizeof(Parameter), &user.bag);CHKERRQ(ierr); 940 ierr = SetupParameters(&user);CHKERRQ(ierr); 941 ierr = TSCreate(PETSC_COMM_WORLD, &ts);CHKERRQ(ierr); 942 ierr = CreateMesh(PETSC_COMM_WORLD, &user, &dm);CHKERRQ(ierr); 943 ierr = TSSetDM(ts, dm);CHKERRQ(ierr); 944 ierr = DMSetApplicationContext(dm, &user);CHKERRQ(ierr); 945 /* Discretize chemical species */ 946 ierr = DMCreate(PETSC_COMM_WORLD, &sdm);CHKERRQ(ierr); 947 ierr = PetscObjectSetOptionsPrefix((PetscObject) sdm, "part_");CHKERRQ(ierr); 948 ierr = DMSetType(sdm, DMSWARM);CHKERRQ(ierr); 949 ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr); 950 ierr = DMSetDimension(sdm, dim);CHKERRQ(ierr); 951 ierr = DMSwarmSetCellDM(sdm, dm);CHKERRQ(ierr); 952 /* Setup problem */ 953 ierr = SetupDiscretization(dm, sdm, &user);CHKERRQ(ierr); 954 ierr = DMPlexCreateClosureIndex(dm, NULL);CHKERRQ(ierr); 955 956 ierr = DMCreateGlobalVector(dm, &u);CHKERRQ(ierr); 957 ierr = DMSetNullSpaceConstructor(dm, 1, CreatePressureNullSpace);CHKERRQ(ierr); 958 959 ierr = DMTSSetBoundaryLocal(dm, DMPlexTSComputeBoundary, &user);CHKERRQ(ierr); 960 ierr = DMTSSetIFunctionLocal(dm, DMPlexTSComputeIFunctionFEM, &user);CHKERRQ(ierr); 961 ierr = DMTSSetIJacobianLocal(dm, DMPlexTSComputeIJacobianFEM, &user);CHKERRQ(ierr); 962 ierr = TSSetExactFinalTime(ts, TS_EXACTFINALTIME_MATCHSTEP);CHKERRQ(ierr); 963 ierr = TSSetPreStep(ts, RemoveDiscretePressureNullspace);CHKERRQ(ierr); 964 ierr = TSMonitorSet(ts, MonitorError, &user, NULL);CHKERRQ(ierr);CHKERRQ(ierr); 965 ierr = TSSetFromOptions(ts);CHKERRQ(ierr); 966 967 ierr = TSSetComputeInitialCondition(ts, SetInitialConditions);CHKERRQ(ierr); /* Must come after SetFromOptions() */ 968 ierr = SetInitialConditions(ts, u);CHKERRQ(ierr); 969 ierr = TSGetTime(ts, &t);CHKERRQ(ierr); 970 ierr = DMSetOutputSequenceNumber(dm, 0, t);CHKERRQ(ierr); 971 ierr = DMTSCheckFromOptions(ts, u);CHKERRQ(ierr); 972 973 /* Setup particle position integrator */ 974 ierr = TSCreate(PETSC_COMM_WORLD, &sts);CHKERRQ(ierr); 975 ierr = PetscObjectSetOptionsPrefix((PetscObject) sts, "part_");CHKERRQ(ierr); 976 ierr = PetscObjectIncrementTabLevel((PetscObject) sts, (PetscObject) ts, 1);CHKERRQ(ierr); 977 ierr = TSSetDM(sts, sdm);CHKERRQ(ierr); 978 ierr = TSSetProblemType(sts, TS_NONLINEAR);CHKERRQ(ierr); 979 ierr = TSSetExactFinalTime(sts, TS_EXACTFINALTIME_MATCHSTEP);CHKERRQ(ierr); 980 ierr = TSMonitorSet(sts, MonitorParticleError, &adv, NULL);CHKERRQ(ierr);CHKERRQ(ierr); 981 ierr = TSSetFromOptions(sts);CHKERRQ(ierr); 982 ierr = TSSetApplicationContext(sts, &adv);CHKERRQ(ierr); 983 ierr = TSSetComputeExactError(sts, ComputeParticleError);CHKERRQ(ierr); 984 ierr = TSSetComputeInitialCondition(sts, SetInitialParticleConditions);CHKERRQ(ierr); 985 adv.ti = t; 986 adv.uf = u; 987 ierr = VecDuplicate(adv.uf, &adv.ui); 988 ierr = VecCopy(u, adv.ui);CHKERRQ(ierr); 989 ierr = TSSetRHSFunction(sts, NULL, FreeStreaming, &adv);CHKERRQ(ierr); 990 ierr = TSSetPostStep(ts, AdvectParticles);CHKERRQ(ierr); 991 ierr = PetscObjectCompose((PetscObject) ts, "_SwarmTS", (PetscObject) sts);CHKERRQ(ierr); 992 ierr = DMSwarmVectorDefineField(sdm, DMSwarmPICField_coor);CHKERRQ(ierr); 993 ierr = DMCreateGlobalVector(sdm, &adv.x0);CHKERRQ(ierr); 994 ierr = DMSwarmCreateGlobalVectorFromField(sdm, DMSwarmPICField_coor, &xtmp);CHKERRQ(ierr); 995 ierr = VecCopy(xtmp, adv.x0);CHKERRQ(ierr); 996 ierr = DMSwarmDestroyGlobalVectorFromField(sdm, DMSwarmPICField_coor, &xtmp);CHKERRQ(ierr); 997 switch(user.solType){ 998 case SOL_TRIG_TRIG: adv.exact = trig_trig_x;break; 999 default: SETERRQ2(PetscObjectComm((PetscObject) sdm), PETSC_ERR_ARG_WRONG, "Unsupported solution type: %s (%D)", solTypes[PetscMin(user.solType, NUM_SOL_TYPES)], user.solType); 1000 } 1001 adv.ctx = &user; 1002 1003 ierr = TSSolve(ts, u);CHKERRQ(ierr); 1004 ierr = DMTSCheckFromOptions(ts, u);CHKERRQ(ierr); 1005 ierr = PetscObjectSetName((PetscObject) u, "Numerical Solution");CHKERRQ(ierr); 1006 1007 ierr = VecDestroy(&u);CHKERRQ(ierr); 1008 ierr = VecDestroy(&adv.x0);CHKERRQ(ierr); 1009 ierr = VecDestroy(&adv.ui);CHKERRQ(ierr); 1010 ierr = DMDestroy(&dm);CHKERRQ(ierr); 1011 ierr = DMDestroy(&sdm);CHKERRQ(ierr); 1012 ierr = TSDestroy(&ts);CHKERRQ(ierr); 1013 ierr = TSDestroy(&sts);CHKERRQ(ierr); 1014 ierr = PetscBagDestroy(&user.bag);CHKERRQ(ierr); 1015 ierr = PetscFinalize(); 1016 return ierr; 1017 } 1018 1019 /*TEST 1020 1021 # Swarm does not work with complex 1022 test: 1023 suffix: 2d_tri_p2_p1_p1_tconvp 1024 requires: triangle !single !complex 1025 args: -dm_plex_separate_marker -sol_type trig_trig -dm_refine 2 \ 1026 -vel_petscspace_degree 2 -pres_petscspace_degree 1 -temp_petscspace_degree 1 \ 1027 -dmts_check .001 -ts_max_steps 4 -ts_dt 0.1 -ts_monitor_cancel \ 1028 -ksp_type fgmres -ksp_gmres_restart 10 -ksp_rtol 1.0e-9 -ksp_error_if_not_converged \ 1029 -pc_type fieldsplit -pc_fieldsplit_0_fields 0,2 -pc_fieldsplit_1_fields 1 -pc_fieldsplit_type schur -pc_fieldsplit_schur_factorization_type full \ 1030 -fieldsplit_0_pc_type lu \ 1031 -fieldsplit_pressure_ksp_rtol 1e-10 -fieldsplit_pressure_pc_type jacobi \ 1032 -omega 0.5 -part_layout_type box -part_lower 0.25,0.25 -part_upper 0.75,0.75 -Npb 5 \ 1033 -part_ts_max_steps 2 -part_ts_dt 0.05 -part_ts_convergence_estimate -convest_num_refine 1 -part_ts_monitor_cancel 1034 test: 1035 suffix: 2d_tri_p2_p1_p1_exit 1036 requires: triangle !single !complex 1037 args: -dm_plex_separate_marker -sol_type trig_trig -dm_refine 1 \ 1038 -vel_petscspace_degree 2 -pres_petscspace_degree 1 -temp_petscspace_degree 1 \ 1039 -dmts_check .001 -ts_max_steps 10 -ts_dt 0.1 \ 1040 -ksp_type fgmres -ksp_gmres_restart 10 -ksp_rtol 1.0e-9 -ksp_error_if_not_converged \ 1041 -pc_type fieldsplit -pc_fieldsplit_0_fields 0,2 -pc_fieldsplit_1_fields 1 -pc_fieldsplit_type schur -pc_fieldsplit_schur_factorization_type full \ 1042 -fieldsplit_0_pc_type lu \ 1043 -fieldsplit_pressure_ksp_rtol 1e-10 -fieldsplit_pressure_pc_type jacobi \ 1044 -omega 0.5 -part_layout_type box -part_lower 0.25,0.25 -part_upper 0.75,0.75 -Npb 5 \ 1045 -part_ts_max_steps 20 -part_ts_dt 0.05 1046 1047 TEST*/ 1048