1 static char help[] = "Solves a time-dependent nonlinear PDE. Uses implicit\n\ 2 timestepping. Runtime options include:\n\ 3 -M <xg>, where <xg> = number of grid points\n\ 4 -debug : Activate debugging printouts\n\ 5 -nox : Deactivate x-window graphics\n\n"; 6 7 /* ------------------------------------------------------------------------ 8 9 This program solves the PDE 10 11 u * u_xx 12 u_t = --------- 13 2*(t+1)^2 14 15 on the domain 0 <= x <= 1, with boundary conditions 16 u(t,0) = t + 1, u(t,1) = 2*t + 2, 17 and initial condition 18 u(0,x) = 1 + x*x. 19 20 The exact solution is: 21 u(t,x) = (1 + x*x) * (1 + t) 22 23 Note that since the solution is linear in time and quadratic in x, 24 the finite difference scheme actually computes the "exact" solution. 25 26 We use by default the backward Euler method. 27 28 ------------------------------------------------------------------------- */ 29 30 /* 31 Include "petscts.h" to use the PETSc timestepping routines. Note that 32 this file automatically includes "petscsys.h" and other lower-level 33 PETSc include files. 34 35 Include the "petscdmda.h" to allow us to use the distributed array data 36 structures to manage the parallel grid. 37 */ 38 #include <petscts.h> 39 #include <petscdm.h> 40 #include <petscdmda.h> 41 #include <petscdraw.h> 42 43 /* 44 User-defined application context - contains data needed by the 45 application-provided callback routines. 46 */ 47 typedef struct { 48 MPI_Comm comm; /* communicator */ 49 DM da; /* distributed array data structure */ 50 Vec localwork; /* local ghosted work vector */ 51 Vec u_local; /* local ghosted approximate solution vector */ 52 Vec solution; /* global exact solution vector */ 53 PetscInt m; /* total number of grid points */ 54 PetscReal h; /* mesh width: h = 1/(m-1) */ 55 PetscBool debug; /* flag (1 indicates activation of debugging printouts) */ 56 } AppCtx; 57 58 /* 59 User-defined routines, provided below. 60 */ 61 extern PetscErrorCode InitialConditions(Vec, AppCtx *); 62 extern PetscErrorCode RHSFunction(TS, PetscReal, Vec, Vec, void *); 63 extern PetscErrorCode RHSJacobian(TS, PetscReal, Vec, Mat, Mat, void *); 64 extern PetscErrorCode Monitor(TS, PetscInt, PetscReal, Vec, void *); 65 extern PetscErrorCode ExactSolution(PetscReal, Vec, AppCtx *); 66 67 int main(int argc, char **argv) 68 { 69 AppCtx appctx; /* user-defined application context */ 70 TS ts; /* timestepping context */ 71 Mat A; /* Jacobian matrix data structure */ 72 Vec u; /* approximate solution vector */ 73 PetscInt time_steps_max = 100; /* default max timesteps */ 74 PetscReal dt; 75 PetscReal time_total_max = 100.0; /* default max total time */ 76 PetscBool mymonitor = PETSC_FALSE; 77 PetscReal bounds[] = {1.0, 3.3}; 78 79 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 80 Initialize program and set problem parameters 81 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 82 83 PetscFunctionBeginUser; 84 PetscCall(PetscInitialize(&argc, &argv, (char *)0, help)); 85 PetscCall(PetscViewerDrawSetBounds(PETSC_VIEWER_DRAW_(PETSC_COMM_WORLD), 1, bounds)); 86 87 appctx.comm = PETSC_COMM_WORLD; 88 appctx.m = 60; 89 90 PetscCall(PetscOptionsGetInt(NULL, NULL, "-M", &appctx.m, NULL)); 91 PetscCall(PetscOptionsHasName(NULL, NULL, "-debug", &appctx.debug)); 92 PetscCall(PetscOptionsHasName(NULL, NULL, "-mymonitor", &mymonitor)); 93 94 appctx.h = 1.0 / (appctx.m - 1.0); 95 96 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 97 Create vector data structures 98 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 99 100 /* 101 Create distributed array (DMDA) to manage parallel grid and vectors 102 and to set up the ghost point communication pattern. There are M 103 total grid values spread equally among all the processors. 104 */ 105 PetscCall(DMDACreate1d(PETSC_COMM_WORLD, DM_BOUNDARY_NONE, appctx.m, 1, 1, NULL, &appctx.da)); 106 PetscCall(DMSetFromOptions(appctx.da)); 107 PetscCall(DMSetUp(appctx.da)); 108 109 /* 110 Extract global and local vectors from DMDA; we use these to store the 111 approximate solution. Then duplicate these for remaining vectors that 112 have the same types. 113 */ 114 PetscCall(DMCreateGlobalVector(appctx.da, &u)); 115 PetscCall(DMCreateLocalVector(appctx.da, &appctx.u_local)); 116 117 /* 118 Create local work vector for use in evaluating right-hand-side function; 119 create global work vector for storing exact solution. 120 */ 121 PetscCall(VecDuplicate(appctx.u_local, &appctx.localwork)); 122 PetscCall(VecDuplicate(u, &appctx.solution)); 123 124 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 125 Create timestepping solver context; set callback routine for 126 right-hand-side function evaluation. 127 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 128 129 PetscCall(TSCreate(PETSC_COMM_WORLD, &ts)); 130 PetscCall(TSSetProblemType(ts, TS_NONLINEAR)); 131 PetscCall(TSSetRHSFunction(ts, NULL, RHSFunction, &appctx)); 132 133 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 134 Set optional user-defined monitoring routine 135 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 136 137 if (mymonitor) PetscCall(TSMonitorSet(ts, Monitor, &appctx, NULL)); 138 139 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 140 For nonlinear problems, the user can provide a Jacobian evaluation 141 routine (or use a finite differencing approximation). 142 143 Create matrix data structure; set Jacobian evaluation routine. 144 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 145 146 PetscCall(MatCreate(PETSC_COMM_WORLD, &A)); 147 PetscCall(MatSetSizes(A, PETSC_DECIDE, PETSC_DECIDE, appctx.m, appctx.m)); 148 PetscCall(MatSetFromOptions(A)); 149 PetscCall(MatSetUp(A)); 150 PetscCall(TSSetRHSJacobian(ts, A, A, RHSJacobian, &appctx)); 151 152 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 153 Set solution vector and initial timestep 154 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 155 156 dt = appctx.h / 2.0; 157 PetscCall(TSSetTimeStep(ts, dt)); 158 159 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 160 Customize timestepping solver: 161 - Set the solution method to be the Backward Euler method. 162 - Set timestepping duration info 163 Then set runtime options, which can override these defaults. 164 For example, 165 -ts_max_steps <maxsteps> -ts_max_time <maxtime> 166 to override the defaults set by TSSetMaxSteps()/TSSetMaxTime(). 167 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 168 169 PetscCall(TSSetType(ts, TSBEULER)); 170 PetscCall(TSSetMaxSteps(ts, time_steps_max)); 171 PetscCall(TSSetMaxTime(ts, time_total_max)); 172 PetscCall(TSSetExactFinalTime(ts, TS_EXACTFINALTIME_STEPOVER)); 173 PetscCall(TSSetFromOptions(ts)); 174 175 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 176 Solve the problem 177 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 178 179 /* 180 Evaluate initial conditions 181 */ 182 PetscCall(InitialConditions(u, &appctx)); 183 184 /* 185 Run the timestepping solver 186 */ 187 PetscCall(TSSolve(ts, u)); 188 189 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 190 Free work space. All PETSc objects should be destroyed when they 191 are no longer needed. 192 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 193 194 PetscCall(TSDestroy(&ts)); 195 PetscCall(VecDestroy(&u)); 196 PetscCall(MatDestroy(&A)); 197 PetscCall(DMDestroy(&appctx.da)); 198 PetscCall(VecDestroy(&appctx.localwork)); 199 PetscCall(VecDestroy(&appctx.solution)); 200 PetscCall(VecDestroy(&appctx.u_local)); 201 202 /* 203 Always call PetscFinalize() before exiting a program. This routine 204 - finalizes the PETSc libraries as well as MPI 205 - provides summary and diagnostic information if certain runtime 206 options are chosen (e.g., -log_view). 207 */ 208 PetscCall(PetscFinalize()); 209 return 0; 210 } 211 /* --------------------------------------------------------------------- */ 212 /* 213 InitialConditions - Computes the solution at the initial time. 214 215 Input Parameters: 216 u - uninitialized solution vector (global) 217 appctx - user-defined application context 218 219 Output Parameter: 220 u - vector with solution at initial time (global) 221 */ 222 PetscErrorCode InitialConditions(Vec u, AppCtx *appctx) 223 { 224 PetscScalar *u_localptr, h = appctx->h, x; 225 PetscInt i, mybase, myend; 226 227 PetscFunctionBeginUser; 228 /* 229 Determine starting point of each processor's range of 230 grid values. 231 */ 232 PetscCall(VecGetOwnershipRange(u, &mybase, &myend)); 233 234 /* 235 Get a pointer to vector data. 236 - For default PETSc vectors, VecGetArray() returns a pointer to 237 the data array. Otherwise, the routine is implementation dependent. 238 - You MUST call VecRestoreArray() when you no longer need access to 239 the array. 240 - Note that the Fortran interface to VecGetArray() differs from the 241 C version. See the users manual for details. 242 */ 243 PetscCall(VecGetArray(u, &u_localptr)); 244 245 /* 246 We initialize the solution array by simply writing the solution 247 directly into the array locations. Alternatively, we could use 248 VecSetValues() or VecSetValuesLocal(). 249 */ 250 for (i = mybase; i < myend; i++) { 251 x = h * (PetscReal)i; /* current location in global grid */ 252 u_localptr[i - mybase] = 1.0 + x * x; 253 } 254 255 /* 256 Restore vector 257 */ 258 PetscCall(VecRestoreArray(u, &u_localptr)); 259 260 /* 261 Print debugging information if desired 262 */ 263 if (appctx->debug) { 264 PetscCall(PetscPrintf(appctx->comm, "initial guess vector\n")); 265 PetscCall(VecView(u, PETSC_VIEWER_STDOUT_WORLD)); 266 } 267 268 PetscFunctionReturn(PETSC_SUCCESS); 269 } 270 /* --------------------------------------------------------------------- */ 271 /* 272 ExactSolution - Computes the exact solution at a given time. 273 274 Input Parameters: 275 t - current time 276 solution - vector in which exact solution will be computed 277 appctx - user-defined application context 278 279 Output Parameter: 280 solution - vector with the newly computed exact solution 281 */ 282 PetscErrorCode ExactSolution(PetscReal t, Vec solution, AppCtx *appctx) 283 { 284 PetscScalar *s_localptr, h = appctx->h, x; 285 PetscInt i, mybase, myend; 286 287 PetscFunctionBeginUser; 288 /* 289 Determine starting and ending points of each processor's 290 range of grid values 291 */ 292 PetscCall(VecGetOwnershipRange(solution, &mybase, &myend)); 293 294 /* 295 Get a pointer to vector data. 296 */ 297 PetscCall(VecGetArray(solution, &s_localptr)); 298 299 /* 300 Simply write the solution directly into the array locations. 301 Alternatively, we could use VecSetValues() or VecSetValuesLocal(). 302 */ 303 for (i = mybase; i < myend; i++) { 304 x = h * (PetscReal)i; 305 s_localptr[i - mybase] = (t + 1.0) * (1.0 + x * x); 306 } 307 308 /* 309 Restore vector 310 */ 311 PetscCall(VecRestoreArray(solution, &s_localptr)); 312 PetscFunctionReturn(PETSC_SUCCESS); 313 } 314 /* --------------------------------------------------------------------- */ 315 /* 316 Monitor - User-provided routine to monitor the solution computed at 317 each timestep. This example plots the solution and computes the 318 error in two different norms. 319 320 Input Parameters: 321 ts - the timestep context 322 step - the count of the current step (with 0 meaning the 323 initial condition) 324 time - the current time 325 u - the solution at this timestep 326 ctx - the user-provided context for this monitoring routine. 327 In this case we use the application context which contains 328 information about the problem size, workspace and the exact 329 solution. 330 */ 331 PetscErrorCode Monitor(TS ts, PetscInt step, PetscReal time, Vec u, void *ctx) 332 { 333 AppCtx *appctx = (AppCtx *)ctx; /* user-defined application context */ 334 PetscReal en2, en2s, enmax; 335 PetscDraw draw; 336 337 PetscFunctionBeginUser; 338 /* 339 We use the default X Windows viewer 340 PETSC_VIEWER_DRAW_(appctx->comm) 341 that is associated with the current communicator. This saves 342 the effort of calling PetscViewerDrawOpen() to create the window. 343 Note that if we wished to plot several items in separate windows we 344 would create each viewer with PetscViewerDrawOpen() and store them in 345 the application context, appctx. 346 347 PetscReal buffering makes graphics look better. 348 */ 349 PetscCall(PetscViewerDrawGetDraw(PETSC_VIEWER_DRAW_(appctx->comm), 0, &draw)); 350 PetscCall(PetscDrawSetDoubleBuffer(draw)); 351 PetscCall(VecView(u, PETSC_VIEWER_DRAW_(appctx->comm))); 352 353 /* 354 Compute the exact solution at this timestep 355 */ 356 PetscCall(ExactSolution(time, appctx->solution, appctx)); 357 358 /* 359 Print debugging information if desired 360 */ 361 if (appctx->debug) { 362 PetscCall(PetscPrintf(appctx->comm, "Computed solution vector\n")); 363 PetscCall(VecView(u, PETSC_VIEWER_STDOUT_WORLD)); 364 PetscCall(PetscPrintf(appctx->comm, "Exact solution vector\n")); 365 PetscCall(VecView(appctx->solution, PETSC_VIEWER_STDOUT_WORLD)); 366 } 367 368 /* 369 Compute the 2-norm and max-norm of the error 370 */ 371 PetscCall(VecAXPY(appctx->solution, -1.0, u)); 372 PetscCall(VecNorm(appctx->solution, NORM_2, &en2)); 373 en2s = PetscSqrtReal(appctx->h) * en2; /* scale the 2-norm by the grid spacing */ 374 PetscCall(VecNorm(appctx->solution, NORM_MAX, &enmax)); 375 376 /* 377 PetscPrintf() causes only the first processor in this 378 communicator to print the timestep information. 379 */ 380 PetscCall(PetscPrintf(appctx->comm, "Timestep %" PetscInt_FMT ": time = %g 2-norm error = %g max norm error = %g\n", step, (double)time, (double)en2s, (double)enmax)); 381 382 /* 383 Print debugging information if desired 384 */ 385 if (appctx->debug) { 386 PetscCall(PetscPrintf(appctx->comm, "Error vector\n")); 387 PetscCall(VecView(appctx->solution, PETSC_VIEWER_STDOUT_WORLD)); 388 } 389 PetscFunctionReturn(PETSC_SUCCESS); 390 } 391 /* --------------------------------------------------------------------- */ 392 /* 393 RHSFunction - User-provided routine that evalues the right-hand-side 394 function of the ODE. This routine is set in the main program by 395 calling TSSetRHSFunction(). We compute: 396 global_out = F(global_in) 397 398 Input Parameters: 399 ts - timesteping context 400 t - current time 401 global_in - vector containing the current iterate 402 ctx - (optional) user-provided context for function evaluation. 403 In this case we use the appctx defined above. 404 405 Output Parameter: 406 global_out - vector containing the newly evaluated function 407 */ 408 PetscErrorCode RHSFunction(TS ts, PetscReal t, Vec global_in, Vec global_out, void *ctx) 409 { 410 AppCtx *appctx = (AppCtx *)ctx; /* user-defined application context */ 411 DM da = appctx->da; /* distributed array */ 412 Vec local_in = appctx->u_local; /* local ghosted input vector */ 413 Vec localwork = appctx->localwork; /* local ghosted work vector */ 414 PetscInt i, localsize; 415 PetscMPIInt rank, size; 416 PetscScalar *copyptr, sc; 417 const PetscScalar *localptr; 418 419 PetscFunctionBeginUser; 420 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 421 Get ready for local function computations 422 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 423 /* 424 Scatter ghost points to local vector, using the 2-step process 425 DMGlobalToLocalBegin(), DMGlobalToLocalEnd(). 426 By placing code between these two statements, computations can be 427 done while messages are in transition. 428 */ 429 PetscCall(DMGlobalToLocalBegin(da, global_in, INSERT_VALUES, local_in)); 430 PetscCall(DMGlobalToLocalEnd(da, global_in, INSERT_VALUES, local_in)); 431 432 /* 433 Access directly the values in our local INPUT work array 434 */ 435 PetscCall(VecGetArrayRead(local_in, &localptr)); 436 437 /* 438 Access directly the values in our local OUTPUT work array 439 */ 440 PetscCall(VecGetArray(localwork, ©ptr)); 441 442 sc = 1.0 / (appctx->h * appctx->h * 2.0 * (1.0 + t) * (1.0 + t)); 443 444 /* 445 Evaluate our function on the nodes owned by this processor 446 */ 447 PetscCall(VecGetLocalSize(local_in, &localsize)); 448 449 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 450 Compute entries for the locally owned part 451 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 452 453 /* 454 Handle boundary conditions: This is done by using the boundary condition 455 u(t,boundary) = g(t,boundary) 456 for some function g. Now take the derivative with respect to t to obtain 457 u_{t}(t,boundary) = g_{t}(t,boundary) 458 459 In our case, u(t,0) = t + 1, so that u_{t}(t,0) = 1 460 and u(t,1) = 2t+ 2, so that u_{t}(t,1) = 2 461 */ 462 PetscCallMPI(MPI_Comm_rank(appctx->comm, &rank)); 463 PetscCallMPI(MPI_Comm_size(appctx->comm, &size)); 464 if (rank == 0) copyptr[0] = 1.0; 465 if (rank == size - 1) copyptr[localsize - 1] = 2.0; 466 467 /* 468 Handle the interior nodes where the PDE is replace by finite 469 difference operators. 470 */ 471 for (i = 1; i < localsize - 1; i++) copyptr[i] = localptr[i] * sc * (localptr[i + 1] + localptr[i - 1] - 2.0 * localptr[i]); 472 473 /* 474 Restore vectors 475 */ 476 PetscCall(VecRestoreArrayRead(local_in, &localptr)); 477 PetscCall(VecRestoreArray(localwork, ©ptr)); 478 479 /* 480 Insert values from the local OUTPUT vector into the global 481 output vector 482 */ 483 PetscCall(DMLocalToGlobalBegin(da, localwork, INSERT_VALUES, global_out)); 484 PetscCall(DMLocalToGlobalEnd(da, localwork, INSERT_VALUES, global_out)); 485 486 /* Print debugging information if desired */ 487 if (appctx->debug) { 488 PetscCall(PetscPrintf(appctx->comm, "RHS function vector\n")); 489 PetscCall(VecView(global_out, PETSC_VIEWER_STDOUT_WORLD)); 490 } 491 492 PetscFunctionReturn(PETSC_SUCCESS); 493 } 494 /* --------------------------------------------------------------------- */ 495 /* 496 RHSJacobian - User-provided routine to compute the Jacobian of 497 the nonlinear right-hand-side function of the ODE. 498 499 Input Parameters: 500 ts - the TS context 501 t - current time 502 global_in - global input vector 503 dummy - optional user-defined context, as set by TSetRHSJacobian() 504 505 Output Parameters: 506 AA - Jacobian matrix 507 BB - optionally different preconditioning matrix 508 str - flag indicating matrix structure 509 510 Notes: 511 RHSJacobian computes entries for the locally owned part of the Jacobian. 512 - Currently, all PETSc parallel matrix formats are partitioned by 513 contiguous chunks of rows across the processors. 514 - Each processor needs to insert only elements that it owns 515 locally (but any non-local elements will be sent to the 516 appropriate processor during matrix assembly). 517 - Always specify global row and columns of matrix entries when 518 using MatSetValues(). 519 - Here, we set all entries for a particular row at once. 520 - Note that MatSetValues() uses 0-based row and column numbers 521 in Fortran as well as in C. 522 */ 523 PetscErrorCode RHSJacobian(TS ts, PetscReal t, Vec global_in, Mat AA, Mat BB, void *ctx) 524 { 525 AppCtx *appctx = (AppCtx *)ctx; /* user-defined application context */ 526 Vec local_in = appctx->u_local; /* local ghosted input vector */ 527 DM da = appctx->da; /* distributed array */ 528 PetscScalar v[3], sc; 529 const PetscScalar *localptr; 530 PetscInt i, mstart, mend, mstarts, mends, idx[3], is; 531 532 PetscFunctionBeginUser; 533 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 534 Get ready for local Jacobian computations 535 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 536 /* 537 Scatter ghost points to local vector, using the 2-step process 538 DMGlobalToLocalBegin(), DMGlobalToLocalEnd(). 539 By placing code between these two statements, computations can be 540 done while messages are in transition. 541 */ 542 PetscCall(DMGlobalToLocalBegin(da, global_in, INSERT_VALUES, local_in)); 543 PetscCall(DMGlobalToLocalEnd(da, global_in, INSERT_VALUES, local_in)); 544 545 /* 546 Get pointer to vector data 547 */ 548 PetscCall(VecGetArrayRead(local_in, &localptr)); 549 550 /* 551 Get starting and ending locally owned rows of the matrix 552 */ 553 PetscCall(MatGetOwnershipRange(BB, &mstarts, &mends)); 554 mstart = mstarts; 555 mend = mends; 556 557 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 558 Compute entries for the locally owned part of the Jacobian. 559 - Currently, all PETSc parallel matrix formats are partitioned by 560 contiguous chunks of rows across the processors. 561 - Each processor needs to insert only elements that it owns 562 locally (but any non-local elements will be sent to the 563 appropriate processor during matrix assembly). 564 - Here, we set all entries for a particular row at once. 565 - We can set matrix entries either using either 566 MatSetValuesLocal() or MatSetValues(). 567 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 568 569 /* 570 Set matrix rows corresponding to boundary data 571 */ 572 if (mstart == 0) { 573 v[0] = 0.0; 574 PetscCall(MatSetValues(BB, 1, &mstart, 1, &mstart, v, INSERT_VALUES)); 575 mstart++; 576 } 577 if (mend == appctx->m) { 578 mend--; 579 v[0] = 0.0; 580 PetscCall(MatSetValues(BB, 1, &mend, 1, &mend, v, INSERT_VALUES)); 581 } 582 583 /* 584 Set matrix rows corresponding to interior data. We construct the 585 matrix one row at a time. 586 */ 587 sc = 1.0 / (appctx->h * appctx->h * 2.0 * (1.0 + t) * (1.0 + t)); 588 for (i = mstart; i < mend; i++) { 589 idx[0] = i - 1; 590 idx[1] = i; 591 idx[2] = i + 1; 592 is = i - mstart + 1; 593 v[0] = sc * localptr[is]; 594 v[1] = sc * (localptr[is + 1] + localptr[is - 1] - 4.0 * localptr[is]); 595 v[2] = sc * localptr[is]; 596 PetscCall(MatSetValues(BB, 1, &i, 3, idx, v, INSERT_VALUES)); 597 } 598 599 /* 600 Restore vector 601 */ 602 PetscCall(VecRestoreArrayRead(local_in, &localptr)); 603 604 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 605 Complete the matrix assembly process and set some options 606 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 607 /* 608 Assemble matrix, using the 2-step process: 609 MatAssemblyBegin(), MatAssemblyEnd() 610 Computations can be done while messages are in transition 611 by placing code between these two statements. 612 */ 613 PetscCall(MatAssemblyBegin(BB, MAT_FINAL_ASSEMBLY)); 614 PetscCall(MatAssemblyEnd(BB, MAT_FINAL_ASSEMBLY)); 615 if (BB != AA) { 616 PetscCall(MatAssemblyBegin(AA, MAT_FINAL_ASSEMBLY)); 617 PetscCall(MatAssemblyEnd(AA, MAT_FINAL_ASSEMBLY)); 618 } 619 620 /* 621 Set and option to indicate that we will never add a new nonzero location 622 to the matrix. If we do, it will generate an error. 623 */ 624 PetscCall(MatSetOption(BB, MAT_NEW_NONZERO_LOCATION_ERR, PETSC_TRUE)); 625 626 PetscFunctionReturn(PETSC_SUCCESS); 627 } 628 629 /*TEST 630 631 test: 632 args: -nox -ts_dt 10 -mymonitor 633 nsize: 2 634 requires: !single 635 636 test: 637 suffix: tut_1 638 nsize: 1 639 args: -ts_max_steps 10 -ts_monitor 640 641 test: 642 suffix: tut_2 643 nsize: 4 644 args: -ts_max_steps 10 -ts_monitor -snes_monitor -ksp_monitor 645 646 test: 647 suffix: tut_3 648 nsize: 4 649 args: -ts_max_steps 10 -ts_monitor -M 128 650 651 TEST*/ 652