1 2 static char help[] = "Solves one dimensional Burger's equation compares with exact solution\n\n"; 3 4 /* 5 6 Not yet tested in parallel 7 8 */ 9 10 /* ------------------------------------------------------------------------ 11 12 This program uses the one-dimensional Burger's equation 13 u_t = mu*u_xx - u u_x, 14 on the domain 0 <= x <= 1, with periodic boundary conditions 15 16 The operators are discretized with the spectral element method 17 18 See the paper PDE-CONSTRAINED OPTIMIZATION WITH SPECTRAL ELEMENTS USING PETSC AND TAO 19 by OANA MARIN, EMIL CONSTANTINESCU, AND BARRY SMITH for details on the exact solution 20 used 21 22 See src/tao/unconstrained/tutorials/burgers_spectral.c 23 24 ------------------------------------------------------------------------- */ 25 26 #include <petscts.h> 27 #include <petscdt.h> 28 #include <petscdraw.h> 29 #include <petscdmda.h> 30 31 /* 32 User-defined application context - contains data needed by the 33 application-provided call-back routines. 34 */ 35 36 typedef struct { 37 PetscInt n; /* number of nodes */ 38 PetscReal *nodes; /* GLL nodes */ 39 PetscReal *weights; /* GLL weights */ 40 } PetscGLL; 41 42 typedef struct { 43 PetscInt N; /* grid points per elements*/ 44 PetscInt E; /* number of elements */ 45 PetscReal tol_L2, tol_max; /* error norms */ 46 PetscInt steps; /* number of timesteps */ 47 PetscReal Tend; /* endtime */ 48 PetscReal mu; /* viscosity */ 49 PetscReal L; /* total length of domain */ 50 PetscReal Le; 51 PetscReal Tadj; 52 } PetscParam; 53 54 typedef struct { 55 Vec grid; /* total grid */ 56 Vec curr_sol; 57 } PetscData; 58 59 typedef struct { 60 Vec grid; /* total grid */ 61 Vec mass; /* mass matrix for total integration */ 62 Mat stiff; /* stifness matrix */ 63 Mat keptstiff; 64 Mat grad; 65 PetscGLL gll; 66 } PetscSEMOperators; 67 68 typedef struct { 69 DM da; /* distributed array data structure */ 70 PetscSEMOperators SEMop; 71 PetscParam param; 72 PetscData dat; 73 TS ts; 74 PetscReal initial_dt; 75 } AppCtx; 76 77 /* 78 User-defined routines 79 */ 80 extern PetscErrorCode RHSMatrixLaplaciangllDM(TS, PetscReal, Vec, Mat, Mat, void *); 81 extern PetscErrorCode RHSMatrixAdvectiongllDM(TS, PetscReal, Vec, Mat, Mat, void *); 82 extern PetscErrorCode TrueSolution(TS, PetscReal, Vec, AppCtx *); 83 extern PetscErrorCode RHSFunction(TS, PetscReal, Vec, Vec, void *); 84 extern PetscErrorCode RHSJacobian(TS, PetscReal, Vec, Mat, Mat, void *); 85 86 int main(int argc, char **argv) 87 { 88 AppCtx appctx; /* user-defined application context */ 89 PetscInt i, xs, xm, ind, j, lenglob; 90 PetscReal x, *wrk_ptr1, *wrk_ptr2; 91 MatNullSpace nsp; 92 PetscMPIInt size; 93 94 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 95 Initialize program and set problem parameters 96 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 97 PetscFunctionBeginUser; 98 99 PetscFunctionBeginUser; 100 PetscCall(PetscInitialize(&argc, &argv, (char *)0, help)); 101 102 /*initialize parameters */ 103 appctx.param.N = 10; /* order of the spectral element */ 104 appctx.param.E = 10; /* number of elements */ 105 appctx.param.L = 4.0; /* length of the domain */ 106 appctx.param.mu = 0.01; /* diffusion coefficient */ 107 appctx.initial_dt = 5e-3; 108 appctx.param.steps = PETSC_MAX_INT; 109 appctx.param.Tend = 4; 110 111 PetscCall(PetscOptionsGetInt(NULL, NULL, "-N", &appctx.param.N, NULL)); 112 PetscCall(PetscOptionsGetInt(NULL, NULL, "-E", &appctx.param.E, NULL)); 113 PetscCall(PetscOptionsGetReal(NULL, NULL, "-Tend", &appctx.param.Tend, NULL)); 114 PetscCall(PetscOptionsGetReal(NULL, NULL, "-mu", &appctx.param.mu, NULL)); 115 appctx.param.Le = appctx.param.L / appctx.param.E; 116 117 PetscCallMPI(MPI_Comm_size(PETSC_COMM_WORLD, &size)); 118 PetscCheck((appctx.param.E % size) == 0, PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG, "Number of elements must be divisible by number of processes"); 119 120 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 121 Create GLL data structures 122 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 123 PetscCall(PetscMalloc2(appctx.param.N, &appctx.SEMop.gll.nodes, appctx.param.N, &appctx.SEMop.gll.weights)); 124 PetscCall(PetscDTGaussLobattoLegendreQuadrature(appctx.param.N, PETSCGAUSSLOBATTOLEGENDRE_VIA_LINEAR_ALGEBRA, appctx.SEMop.gll.nodes, appctx.SEMop.gll.weights)); 125 appctx.SEMop.gll.n = appctx.param.N; 126 lenglob = appctx.param.E * (appctx.param.N - 1); 127 128 /* 129 Create distributed array (DMDA) to manage parallel grid and vectors 130 and to set up the ghost point communication pattern. There are E*(Nl-1)+1 131 total grid values spread equally among all the processors, except first and last 132 */ 133 134 PetscCall(DMDACreate1d(PETSC_COMM_WORLD, DM_BOUNDARY_PERIODIC, lenglob, 1, 1, NULL, &appctx.da)); 135 PetscCall(DMSetFromOptions(appctx.da)); 136 PetscCall(DMSetUp(appctx.da)); 137 138 /* 139 Extract global and local vectors from DMDA; we use these to store the 140 approximate solution. Then duplicate these for remaining vectors that 141 have the same types. 142 */ 143 144 PetscCall(DMCreateGlobalVector(appctx.da, &appctx.dat.curr_sol)); 145 PetscCall(VecDuplicate(appctx.dat.curr_sol, &appctx.SEMop.grid)); 146 PetscCall(VecDuplicate(appctx.dat.curr_sol, &appctx.SEMop.mass)); 147 148 PetscCall(DMDAGetCorners(appctx.da, &xs, NULL, NULL, &xm, NULL, NULL)); 149 PetscCall(DMDAVecGetArray(appctx.da, appctx.SEMop.grid, &wrk_ptr1)); 150 PetscCall(DMDAVecGetArray(appctx.da, appctx.SEMop.mass, &wrk_ptr2)); 151 152 /* Compute function over the locally owned part of the grid */ 153 154 xs = xs / (appctx.param.N - 1); 155 xm = xm / (appctx.param.N - 1); 156 157 /* 158 Build total grid and mass over entire mesh (multi-elemental) 159 */ 160 161 for (i = xs; i < xs + xm; i++) { 162 for (j = 0; j < appctx.param.N - 1; j++) { 163 x = (appctx.param.Le / 2.0) * (appctx.SEMop.gll.nodes[j] + 1.0) + appctx.param.Le * i; 164 ind = i * (appctx.param.N - 1) + j; 165 wrk_ptr1[ind] = x; 166 wrk_ptr2[ind] = .5 * appctx.param.Le * appctx.SEMop.gll.weights[j]; 167 if (j == 0) wrk_ptr2[ind] += .5 * appctx.param.Le * appctx.SEMop.gll.weights[j]; 168 } 169 } 170 PetscCall(DMDAVecRestoreArray(appctx.da, appctx.SEMop.grid, &wrk_ptr1)); 171 PetscCall(DMDAVecRestoreArray(appctx.da, appctx.SEMop.mass, &wrk_ptr2)); 172 173 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 174 Create matrix data structure; set matrix evaluation routine. 175 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 176 PetscCall(DMSetMatrixPreallocateOnly(appctx.da, PETSC_TRUE)); 177 PetscCall(DMCreateMatrix(appctx.da, &appctx.SEMop.stiff)); 178 PetscCall(DMCreateMatrix(appctx.da, &appctx.SEMop.grad)); 179 /* 180 For linear problems with a time-dependent f(u,t) in the equation 181 u_t = f(u,t), the user provides the discretized right-hand-side 182 as a time-dependent matrix. 183 */ 184 PetscCall(RHSMatrixLaplaciangllDM(appctx.ts, 0.0, appctx.dat.curr_sol, appctx.SEMop.stiff, appctx.SEMop.stiff, &appctx)); 185 PetscCall(RHSMatrixAdvectiongllDM(appctx.ts, 0.0, appctx.dat.curr_sol, appctx.SEMop.grad, appctx.SEMop.grad, &appctx)); 186 /* 187 For linear problems with a time-dependent f(u,t) in the equation 188 u_t = f(u,t), the user provides the discretized right-hand-side 189 as a time-dependent matrix. 190 */ 191 192 PetscCall(MatDuplicate(appctx.SEMop.stiff, MAT_COPY_VALUES, &appctx.SEMop.keptstiff)); 193 194 /* attach the null space to the matrix, this probably is not needed but does no harm */ 195 PetscCall(MatNullSpaceCreate(PETSC_COMM_WORLD, PETSC_TRUE, 0, NULL, &nsp)); 196 PetscCall(MatSetNullSpace(appctx.SEMop.stiff, nsp)); 197 PetscCall(MatSetNullSpace(appctx.SEMop.keptstiff, nsp)); 198 PetscCall(MatNullSpaceTest(nsp, appctx.SEMop.stiff, NULL)); 199 PetscCall(MatNullSpaceDestroy(&nsp)); 200 /* attach the null space to the matrix, this probably is not needed but does no harm */ 201 PetscCall(MatNullSpaceCreate(PETSC_COMM_WORLD, PETSC_TRUE, 0, NULL, &nsp)); 202 PetscCall(MatSetNullSpace(appctx.SEMop.grad, nsp)); 203 PetscCall(MatNullSpaceTest(nsp, appctx.SEMop.grad, NULL)); 204 PetscCall(MatNullSpaceDestroy(&nsp)); 205 206 /* Create the TS solver that solves the ODE and its adjoint; set its options */ 207 PetscCall(TSCreate(PETSC_COMM_WORLD, &appctx.ts)); 208 PetscCall(TSSetProblemType(appctx.ts, TS_NONLINEAR)); 209 PetscCall(TSSetType(appctx.ts, TSRK)); 210 PetscCall(TSSetDM(appctx.ts, appctx.da)); 211 PetscCall(TSSetTime(appctx.ts, 0.0)); 212 PetscCall(TSSetTimeStep(appctx.ts, appctx.initial_dt)); 213 PetscCall(TSSetMaxSteps(appctx.ts, appctx.param.steps)); 214 PetscCall(TSSetMaxTime(appctx.ts, appctx.param.Tend)); 215 PetscCall(TSSetExactFinalTime(appctx.ts, TS_EXACTFINALTIME_MATCHSTEP)); 216 PetscCall(TSSetTolerances(appctx.ts, 1e-7, NULL, 1e-7, NULL)); 217 PetscCall(TSSetSaveTrajectory(appctx.ts)); 218 PetscCall(TSSetFromOptions(appctx.ts)); 219 PetscCall(TSSetRHSFunction(appctx.ts, NULL, RHSFunction, &appctx)); 220 PetscCall(TSSetRHSJacobian(appctx.ts, appctx.SEMop.stiff, appctx.SEMop.stiff, RHSJacobian, &appctx)); 221 222 /* Set Initial conditions for the problem */ 223 PetscCall(TrueSolution(appctx.ts, 0, appctx.dat.curr_sol, &appctx)); 224 225 PetscCall(TSSetSolutionFunction(appctx.ts, (PetscErrorCode(*)(TS, PetscReal, Vec, void *))TrueSolution, &appctx)); 226 PetscCall(TSSetTime(appctx.ts, 0.0)); 227 PetscCall(TSSetStepNumber(appctx.ts, 0)); 228 229 PetscCall(TSSolve(appctx.ts, appctx.dat.curr_sol)); 230 231 PetscCall(MatDestroy(&appctx.SEMop.stiff)); 232 PetscCall(MatDestroy(&appctx.SEMop.keptstiff)); 233 PetscCall(MatDestroy(&appctx.SEMop.grad)); 234 PetscCall(VecDestroy(&appctx.SEMop.grid)); 235 PetscCall(VecDestroy(&appctx.SEMop.mass)); 236 PetscCall(VecDestroy(&appctx.dat.curr_sol)); 237 PetscCall(PetscFree2(appctx.SEMop.gll.nodes, appctx.SEMop.gll.weights)); 238 PetscCall(DMDestroy(&appctx.da)); 239 PetscCall(TSDestroy(&appctx.ts)); 240 241 /* 242 Always call PetscFinalize() before exiting a program. This routine 243 - finalizes the PETSc libraries as well as MPI 244 - provides summary and diagnostic information if certain runtime 245 options are chosen (e.g., -log_view). 246 */ 247 PetscCall(PetscFinalize()); 248 return 0; 249 } 250 251 /* 252 TrueSolution() computes the true solution for the PDE 253 254 Input Parameter: 255 u - uninitialized solution vector (global) 256 appctx - user-defined application context 257 258 Output Parameter: 259 u - vector with solution at initial time (global) 260 */ 261 PetscErrorCode TrueSolution(TS ts, PetscReal t, Vec u, AppCtx *appctx) 262 { 263 PetscScalar *s; 264 const PetscScalar *xg; 265 PetscInt i, xs, xn; 266 267 PetscFunctionBeginUser; 268 PetscCall(DMDAVecGetArray(appctx->da, u, &s)); 269 PetscCall(DMDAVecGetArrayRead(appctx->da, appctx->SEMop.grid, (void *)&xg)); 270 PetscCall(DMDAGetCorners(appctx->da, &xs, NULL, NULL, &xn, NULL, NULL)); 271 for (i = xs; i < xs + xn; i++) { 272 s[i] = 2.0 * appctx->param.mu * PETSC_PI * PetscSinScalar(PETSC_PI * xg[i]) * PetscExpReal(-appctx->param.mu * PETSC_PI * PETSC_PI * t) / (2.0 + PetscCosScalar(PETSC_PI * xg[i]) * PetscExpReal(-appctx->param.mu * PETSC_PI * PETSC_PI * t)); 273 } 274 PetscCall(DMDAVecRestoreArray(appctx->da, u, &s)); 275 PetscCall(DMDAVecRestoreArrayRead(appctx->da, appctx->SEMop.grid, (void *)&xg)); 276 PetscFunctionReturn(PETSC_SUCCESS); 277 } 278 279 PetscErrorCode RHSFunction(TS ts, PetscReal t, Vec globalin, Vec globalout, void *ctx) 280 { 281 AppCtx *appctx = (AppCtx *)ctx; 282 283 PetscFunctionBeginUser; 284 PetscCall(MatMult(appctx->SEMop.grad, globalin, globalout)); /* grad u */ 285 PetscCall(VecPointwiseMult(globalout, globalin, globalout)); /* u grad u */ 286 PetscCall(VecScale(globalout, -1.0)); 287 PetscCall(MatMultAdd(appctx->SEMop.keptstiff, globalin, globalout, globalout)); 288 PetscFunctionReturn(PETSC_SUCCESS); 289 } 290 291 /* 292 293 K is the discretiziation of the Laplacian 294 G is the discretization of the gradient 295 296 Computes Jacobian of K u + diag(u) G u which is given by 297 K + diag(u)G + diag(Gu) 298 */ 299 PetscErrorCode RHSJacobian(TS ts, PetscReal t, Vec globalin, Mat A, Mat B, void *ctx) 300 { 301 AppCtx *appctx = (AppCtx *)ctx; 302 Vec Gglobalin; 303 304 PetscFunctionBeginUser; 305 /* A = diag(u) G */ 306 307 PetscCall(MatCopy(appctx->SEMop.grad, A, SAME_NONZERO_PATTERN)); 308 PetscCall(MatDiagonalScale(A, globalin, NULL)); 309 310 /* A = A + diag(Gu) */ 311 PetscCall(VecDuplicate(globalin, &Gglobalin)); 312 PetscCall(MatMult(appctx->SEMop.grad, globalin, Gglobalin)); 313 PetscCall(MatDiagonalSet(A, Gglobalin, ADD_VALUES)); 314 PetscCall(VecDestroy(&Gglobalin)); 315 316 /* A = K - A */ 317 PetscCall(MatScale(A, -1.0)); 318 PetscCall(MatAXPY(A, 0.0, appctx->SEMop.keptstiff, SAME_NONZERO_PATTERN)); 319 PetscFunctionReturn(PETSC_SUCCESS); 320 } 321 322 /* --------------------------------------------------------------------- */ 323 324 #include "petscblaslapack.h" 325 /* 326 Matrix free operation of 1d Laplacian and Grad for GLL spectral elements 327 */ 328 PetscErrorCode MatMult_Laplacian(Mat A, Vec x, Vec y) 329 { 330 AppCtx *appctx; 331 PetscReal **temp, vv; 332 PetscInt i, j, xs, xn; 333 Vec xlocal, ylocal; 334 const PetscScalar *xl; 335 PetscScalar *yl; 336 PetscBLASInt _One = 1, n; 337 PetscScalar _DOne = 1; 338 339 PetscFunctionBeginUser; 340 PetscCall(MatShellGetContext(A, &appctx)); 341 PetscCall(DMGetLocalVector(appctx->da, &xlocal)); 342 PetscCall(DMGlobalToLocalBegin(appctx->da, x, INSERT_VALUES, xlocal)); 343 PetscCall(DMGlobalToLocalEnd(appctx->da, x, INSERT_VALUES, xlocal)); 344 PetscCall(DMGetLocalVector(appctx->da, &ylocal)); 345 PetscCall(VecSet(ylocal, 0.0)); 346 PetscCall(PetscGaussLobattoLegendreElementLaplacianCreate(appctx->SEMop.gll.n, appctx->SEMop.gll.nodes, appctx->SEMop.gll.weights, &temp)); 347 for (i = 0; i < appctx->param.N; i++) { 348 vv = -appctx->param.mu * 2.0 / appctx->param.Le; 349 for (j = 0; j < appctx->param.N; j++) temp[i][j] = temp[i][j] * vv; 350 } 351 PetscCall(DMDAVecGetArrayRead(appctx->da, xlocal, (void *)&xl)); 352 PetscCall(DMDAVecGetArray(appctx->da, ylocal, &yl)); 353 PetscCall(DMDAGetCorners(appctx->da, &xs, NULL, NULL, &xn, NULL, NULL)); 354 PetscCall(PetscBLASIntCast(appctx->param.N, &n)); 355 for (j = xs; j < xs + xn; j += appctx->param.N - 1) PetscCallBLAS("BLASgemv", BLASgemv_("N", &n, &n, &_DOne, &temp[0][0], &n, &xl[j], &_One, &_DOne, &yl[j], &_One)); 356 PetscCall(DMDAVecRestoreArrayRead(appctx->da, xlocal, (void *)&xl)); 357 PetscCall(DMDAVecRestoreArray(appctx->da, ylocal, &yl)); 358 PetscCall(PetscGaussLobattoLegendreElementLaplacianDestroy(appctx->SEMop.gll.n, appctx->SEMop.gll.nodes, appctx->SEMop.gll.weights, &temp)); 359 PetscCall(VecSet(y, 0.0)); 360 PetscCall(DMLocalToGlobalBegin(appctx->da, ylocal, ADD_VALUES, y)); 361 PetscCall(DMLocalToGlobalEnd(appctx->da, ylocal, ADD_VALUES, y)); 362 PetscCall(DMRestoreLocalVector(appctx->da, &xlocal)); 363 PetscCall(DMRestoreLocalVector(appctx->da, &ylocal)); 364 PetscCall(VecPointwiseDivide(y, y, appctx->SEMop.mass)); 365 PetscFunctionReturn(PETSC_SUCCESS); 366 } 367 368 PetscErrorCode MatMult_Advection(Mat A, Vec x, Vec y) 369 { 370 AppCtx *appctx; 371 PetscReal **temp; 372 PetscInt j, xs, xn; 373 Vec xlocal, ylocal; 374 const PetscScalar *xl; 375 PetscScalar *yl; 376 PetscBLASInt _One = 1, n; 377 PetscScalar _DOne = 1; 378 379 PetscFunctionBeginUser; 380 PetscCall(MatShellGetContext(A, &appctx)); 381 PetscCall(DMGetLocalVector(appctx->da, &xlocal)); 382 PetscCall(DMGlobalToLocalBegin(appctx->da, x, INSERT_VALUES, xlocal)); 383 PetscCall(DMGlobalToLocalEnd(appctx->da, x, INSERT_VALUES, xlocal)); 384 PetscCall(DMGetLocalVector(appctx->da, &ylocal)); 385 PetscCall(VecSet(ylocal, 0.0)); 386 PetscCall(PetscGaussLobattoLegendreElementAdvectionCreate(appctx->SEMop.gll.n, appctx->SEMop.gll.nodes, appctx->SEMop.gll.weights, &temp)); 387 PetscCall(DMDAVecGetArrayRead(appctx->da, xlocal, (void *)&xl)); 388 PetscCall(DMDAVecGetArray(appctx->da, ylocal, &yl)); 389 PetscCall(DMDAGetCorners(appctx->da, &xs, NULL, NULL, &xn, NULL, NULL)); 390 PetscCall(PetscBLASIntCast(appctx->param.N, &n)); 391 for (j = xs; j < xs + xn; j += appctx->param.N - 1) PetscCallBLAS("BLASgemv", BLASgemv_("N", &n, &n, &_DOne, &temp[0][0], &n, &xl[j], &_One, &_DOne, &yl[j], &_One)); 392 PetscCall(DMDAVecRestoreArrayRead(appctx->da, xlocal, (void *)&xl)); 393 PetscCall(DMDAVecRestoreArray(appctx->da, ylocal, &yl)); 394 PetscCall(PetscGaussLobattoLegendreElementAdvectionDestroy(appctx->SEMop.gll.n, appctx->SEMop.gll.nodes, appctx->SEMop.gll.weights, &temp)); 395 PetscCall(VecSet(y, 0.0)); 396 PetscCall(DMLocalToGlobalBegin(appctx->da, ylocal, ADD_VALUES, y)); 397 PetscCall(DMLocalToGlobalEnd(appctx->da, ylocal, ADD_VALUES, y)); 398 PetscCall(DMRestoreLocalVector(appctx->da, &xlocal)); 399 PetscCall(DMRestoreLocalVector(appctx->da, &ylocal)); 400 PetscCall(VecPointwiseDivide(y, y, appctx->SEMop.mass)); 401 PetscCall(VecScale(y, -1.0)); 402 PetscFunctionReturn(PETSC_SUCCESS); 403 } 404 405 /* 406 RHSMatrixLaplacian - User-provided routine to compute the right-hand-side 407 matrix for the Laplacian operator 408 409 Input Parameters: 410 ts - the TS context 411 t - current time (ignored) 412 X - current solution (ignored) 413 dummy - optional user-defined context, as set by TSetRHSJacobian() 414 415 Output Parameters: 416 AA - Jacobian matrix 417 BB - optionally different matrix from which the preconditioner is built 418 str - flag indicating matrix structure 419 420 */ 421 PetscErrorCode RHSMatrixLaplaciangllDM(TS ts, PetscReal t, Vec X, Mat A, Mat BB, void *ctx) 422 { 423 PetscReal **temp; 424 PetscReal vv; 425 AppCtx *appctx = (AppCtx *)ctx; /* user-defined application context */ 426 PetscInt i, xs, xn, l, j; 427 PetscInt *rowsDM; 428 PetscBool flg = PETSC_FALSE; 429 430 PetscFunctionBeginUser; 431 PetscCall(PetscOptionsGetBool(NULL, NULL, "-gll_mf", &flg, NULL)); 432 433 if (!flg) { 434 /* 435 Creates the element stiffness matrix for the given gll 436 */ 437 PetscCall(PetscGaussLobattoLegendreElementLaplacianCreate(appctx->SEMop.gll.n, appctx->SEMop.gll.nodes, appctx->SEMop.gll.weights, &temp)); 438 /* workaround for clang analyzer warning: Division by zero */ 439 PetscCheck(appctx->param.N > 1, PETSC_COMM_WORLD, PETSC_ERR_ARG_WRONG, "Spectral element order should be > 1"); 440 441 /* scale by the size of the element */ 442 for (i = 0; i < appctx->param.N; i++) { 443 vv = -appctx->param.mu * 2.0 / appctx->param.Le; 444 for (j = 0; j < appctx->param.N; j++) temp[i][j] = temp[i][j] * vv; 445 } 446 447 PetscCall(MatSetOption(A, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_FALSE)); 448 PetscCall(DMDAGetCorners(appctx->da, &xs, NULL, NULL, &xn, NULL, NULL)); 449 450 xs = xs / (appctx->param.N - 1); 451 xn = xn / (appctx->param.N - 1); 452 453 PetscCall(PetscMalloc1(appctx->param.N, &rowsDM)); 454 /* 455 loop over local elements 456 */ 457 for (j = xs; j < xs + xn; j++) { 458 for (l = 0; l < appctx->param.N; l++) rowsDM[l] = 1 + (j - xs) * (appctx->param.N - 1) + l; 459 PetscCall(MatSetValuesLocal(A, appctx->param.N, rowsDM, appctx->param.N, rowsDM, &temp[0][0], ADD_VALUES)); 460 } 461 PetscCall(PetscFree(rowsDM)); 462 PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY)); 463 PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY)); 464 PetscCall(VecReciprocal(appctx->SEMop.mass)); 465 PetscCall(MatDiagonalScale(A, appctx->SEMop.mass, 0)); 466 PetscCall(VecReciprocal(appctx->SEMop.mass)); 467 468 PetscCall(PetscGaussLobattoLegendreElementLaplacianDestroy(appctx->SEMop.gll.n, appctx->SEMop.gll.nodes, appctx->SEMop.gll.weights, &temp)); 469 } else { 470 PetscCall(MatSetType(A, MATSHELL)); 471 PetscCall(MatSetUp(A)); 472 PetscCall(MatShellSetContext(A, appctx)); 473 PetscCall(MatShellSetOperation(A, MATOP_MULT, (void (*)(void))MatMult_Laplacian)); 474 } 475 PetscFunctionReturn(PETSC_SUCCESS); 476 } 477 478 /* 479 RHSMatrixAdvection - User-provided routine to compute the right-hand-side 480 matrix for the Advection (gradient) operator. 481 482 Input Parameters: 483 ts - the TS context 484 t - current time 485 global_in - global input vector 486 dummy - optional user-defined context, as set by TSetRHSJacobian() 487 488 Output Parameters: 489 AA - Jacobian matrix 490 BB - optionally different preconditioning matrix 491 str - flag indicating matrix structure 492 493 */ 494 PetscErrorCode RHSMatrixAdvectiongllDM(TS ts, PetscReal t, Vec X, Mat A, Mat BB, void *ctx) 495 { 496 PetscReal **temp; 497 AppCtx *appctx = (AppCtx *)ctx; /* user-defined application context */ 498 PetscInt xs, xn, l, j; 499 PetscInt *rowsDM; 500 PetscBool flg = PETSC_FALSE; 501 502 PetscFunctionBeginUser; 503 PetscCall(PetscOptionsGetBool(NULL, NULL, "-gll_mf", &flg, NULL)); 504 505 if (!flg) { 506 /* 507 Creates the advection matrix for the given gll 508 */ 509 PetscCall(PetscGaussLobattoLegendreElementAdvectionCreate(appctx->SEMop.gll.n, appctx->SEMop.gll.nodes, appctx->SEMop.gll.weights, &temp)); 510 PetscCall(MatSetOption(A, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_FALSE)); 511 PetscCall(DMDAGetCorners(appctx->da, &xs, NULL, NULL, &xn, NULL, NULL)); 512 xs = xs / (appctx->param.N - 1); 513 xn = xn / (appctx->param.N - 1); 514 515 PetscCall(PetscMalloc1(appctx->param.N, &rowsDM)); 516 for (j = xs; j < xs + xn; j++) { 517 for (l = 0; l < appctx->param.N; l++) rowsDM[l] = 1 + (j - xs) * (appctx->param.N - 1) + l; 518 PetscCall(MatSetValuesLocal(A, appctx->param.N, rowsDM, appctx->param.N, rowsDM, &temp[0][0], ADD_VALUES)); 519 } 520 PetscCall(PetscFree(rowsDM)); 521 PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY)); 522 PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY)); 523 524 PetscCall(VecReciprocal(appctx->SEMop.mass)); 525 PetscCall(MatDiagonalScale(A, appctx->SEMop.mass, 0)); 526 PetscCall(VecReciprocal(appctx->SEMop.mass)); 527 528 PetscCall(PetscGaussLobattoLegendreElementAdvectionDestroy(appctx->SEMop.gll.n, appctx->SEMop.gll.nodes, appctx->SEMop.gll.weights, &temp)); 529 } else { 530 PetscCall(MatSetType(A, MATSHELL)); 531 PetscCall(MatSetUp(A)); 532 PetscCall(MatShellSetContext(A, appctx)); 533 PetscCall(MatShellSetOperation(A, MATOP_MULT, (void (*)(void))MatMult_Advection)); 534 } 535 PetscFunctionReturn(PETSC_SUCCESS); 536 } 537 538 /*TEST 539 540 build: 541 requires: !complex 542 543 test: 544 suffix: 1 545 requires: !single 546 547 test: 548 suffix: 2 549 nsize: 5 550 requires: !single 551 552 test: 553 suffix: 3 554 requires: !single 555 args: -ts_view -ts_type beuler -gll_mf -pc_type none -ts_max_steps 5 -ts_monitor_error 556 557 test: 558 suffix: 4 559 requires: !single 560 args: -ts_view -ts_type beuler -pc_type none -ts_max_steps 5 -ts_monitor_error 561 562 TEST*/ 563