xref: /petsc/src/ts/tutorials/ex35.cxx (revision a2fddd78f770fa4fc19a8af67e65be331f27d92b)
1 static const char help[] = "Time-dependent Brusselator reaction-diffusion PDE in 1d. Demonstrates IMEX methods and uses MOAB.\n";
2 /*
3    u_t - alpha u_xx = A + u^2 v - (B+1) u
4    v_t - alpha v_xx = B u - u^2 v
5    0 < x < 1;
6    A = 1, B = 3, alpha = 1/50
7 
8    Initial conditions:
9    u(x,0) = 1 + sin(2 pi x)
10    v(x,0) = 3
11 
12    Boundary conditions:
13    u(0,t) = u(1,t) = 1
14    v(0,t) = v(1,t) = 3
15 */
16 
17 // PETSc includes:
18 #include <petscts.h>
19 #include <petscdmmoab.h>
20 
21 typedef struct {
22   PetscScalar u,v;
23 } Field;
24 
25 struct pUserCtx {
26   PetscReal A,B;        /* Reaction coefficients */
27   PetscReal alpha;      /* Diffusion coefficient */
28   Field leftbc;         /* Dirichlet boundary conditions at left boundary */
29   Field rightbc;        /* Dirichlet boundary conditions at right boundary */
30   PetscInt  n,npts;       /* Number of mesh points */
31   PetscInt  ntsteps;    /* Number of time steps */
32   PetscInt nvars;       /* Number of variables in the equation system */
33   PetscBool io;
34 };
35 typedef pUserCtx* UserCtx;
36 
37 PetscErrorCode Initialize_AppContext(UserCtx *puser)
38 {
39   UserCtx           user;
40   PetscErrorCode    ierr;
41 
42   PetscFunctionBegin;
43   ierr = PetscNew(&user);CHKERRQ(ierr);
44 
45   ierr = PetscOptionsBegin(PETSC_COMM_WORLD,NULL,"Advection-reaction options","ex35.cxx");
46   {
47     user->nvars  = 2;
48     user->A      = 1;
49     user->B      = 3;
50     user->alpha  = 0.02;
51     user->leftbc.u  = 1;
52     user->rightbc.u = 1;
53     user->leftbc.v  = 3;
54     user->rightbc.v = 3;
55     user->n      = 10;
56     user->ntsteps = 10000;
57     user->io = PETSC_FALSE;
58     ierr = PetscOptionsReal("-A","Reaction rate","ex35.cxx",user->A,&user->A,NULL);CHKERRQ(ierr);
59     ierr = PetscOptionsReal("-B","Reaction rate","ex35.cxx",user->B,&user->B,NULL);CHKERRQ(ierr);
60     ierr = PetscOptionsReal("-alpha","Diffusion coefficient","ex35.cxx",user->alpha,&user->alpha,NULL);CHKERRQ(ierr);
61     ierr = PetscOptionsScalar("-uleft","Dirichlet boundary condition","ex35.cxx",user->leftbc.u,&user->leftbc.u,NULL);CHKERRQ(ierr);
62     ierr = PetscOptionsScalar("-uright","Dirichlet boundary condition","ex35.cxx",user->rightbc.u,&user->rightbc.u,NULL);CHKERRQ(ierr);
63     ierr = PetscOptionsScalar("-vleft","Dirichlet boundary condition","ex35.cxx",user->leftbc.v,&user->leftbc.v,NULL);CHKERRQ(ierr);
64     ierr = PetscOptionsScalar("-vright","Dirichlet boundary condition","ex35.cxx",user->rightbc.v,&user->rightbc.v,NULL);CHKERRQ(ierr);
65     ierr = PetscOptionsInt("-n","Number of 1-D elements","ex35.cxx",user->n,&user->n,NULL);CHKERRQ(ierr);
66     ierr = PetscOptionsInt("-ndt","Number of time steps","ex35.cxx",user->ntsteps,&user->ntsteps,NULL);CHKERRQ(ierr);
67     ierr = PetscOptionsBool("-io","Write the mesh and solution output to a file.","ex35.cxx",user->io,&user->io,NULL);CHKERRQ(ierr);
68     user->npts   = user->n+1;
69   }
70   ierr = PetscOptionsEnd();CHKERRQ(ierr);
71 
72   *puser = user;
73   PetscFunctionReturn(0);
74 }
75 
76 PetscErrorCode Destroy_AppContext(UserCtx *user)
77 {
78   PetscErrorCode ierr;
79 
80   PetscFunctionBegin;
81   ierr = PetscFree(*user);CHKERRQ(ierr);
82   PetscFunctionReturn(0);
83 }
84 
85 static PetscErrorCode FormInitialSolution(TS,Vec,void*);
86 static PetscErrorCode FormRHSFunction(TS,PetscReal,Vec,Vec,void*);
87 static PetscErrorCode FormIFunction(TS,PetscReal,Vec,Vec,Vec,void*);
88 static PetscErrorCode FormIJacobian(TS,PetscReal,Vec,Vec,PetscReal,Mat,Mat,void*);
89 
90 /****************
91  *              *
92  *     MAIN     *
93  *              *
94  ****************/
95 int main(int argc,char **argv)
96 {
97   TS                ts;         /* nonlinear solver */
98   Vec               X;          /* solution, residual vectors */
99   Mat               J;          /* Jacobian matrix */
100   PetscInt          steps,mx;
101   PetscErrorCode    ierr;
102   PetscReal         hx,dt,ftime;
103   UserCtx           user;       /* user-defined work context */
104   TSConvergedReason reason;
105 
106   DM                dm;
107   const char        *fields[2] = {"U","V"};
108 
109   ierr = PetscInitialize(&argc,&argv,(char *)0,help);if (ierr) return ierr;
110 
111   /* Initialize the user context struct */
112   ierr = Initialize_AppContext(&user);CHKERRQ(ierr);
113 
114   /* Fill in the user defined work context: */
115   ierr = DMMoabCreateBoxMesh(PETSC_COMM_WORLD, 1, PETSC_FALSE, NULL, user->n, 1, &dm);CHKERRQ(ierr);
116   ierr = DMMoabSetFieldNames(dm, user->nvars, fields);CHKERRQ(ierr);
117   ierr = DMMoabSetBlockSize(dm, user->nvars);CHKERRQ(ierr);
118   ierr = DMSetFromOptions(dm);CHKERRQ(ierr);
119 
120   /* SetUp the data structures for DMMOAB */
121   ierr = DMSetUp(dm);CHKERRQ(ierr);
122 
123   /*  Create timestepping solver context */
124   ierr = TSCreate(PETSC_COMM_WORLD,&ts);CHKERRQ(ierr);
125   ierr = TSSetDM(ts, dm);CHKERRQ(ierr);
126   ierr = TSSetType(ts,TSARKIMEX);CHKERRQ(ierr);
127   ierr = TSSetEquationType(ts,TS_EQ_DAE_IMPLICIT_INDEX1);CHKERRQ(ierr);
128   ierr = DMSetMatType(dm,MATBAIJ);CHKERRQ(ierr);
129   ierr = DMCreateMatrix(dm,&J);CHKERRQ(ierr);
130 
131   ierr = TSSetRHSFunction(ts,NULL,FormRHSFunction,user);CHKERRQ(ierr);
132   ierr = TSSetIFunction(ts,NULL,FormIFunction,user);CHKERRQ(ierr);
133   ierr = TSSetIJacobian(ts,J,J,FormIJacobian,user);CHKERRQ(ierr);
134 
135   ftime = 10.0;
136   ierr = TSSetMaxSteps(ts,user->ntsteps);CHKERRQ(ierr);
137   ierr = TSSetMaxTime(ts,ftime);CHKERRQ(ierr);
138   ierr = TSSetExactFinalTime(ts,TS_EXACTFINALTIME_STEPOVER);CHKERRQ(ierr);
139 
140   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
141      Create the solution vector and set the initial conditions
142    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
143   ierr = DMCreateGlobalVector(dm, &X);CHKERRQ(ierr);
144 
145   ierr = FormInitialSolution(ts,X,user);CHKERRQ(ierr);
146   ierr = TSSetSolution(ts,X);CHKERRQ(ierr);
147   ierr = VecGetSize(X,&mx);CHKERRQ(ierr);
148   hx = 1.0/(PetscReal)(mx/2-1);
149   dt = 0.4 * PetscSqr(hx) / user->alpha; /* Diffusive stability limit */
150   ierr = TSSetTimeStep(ts,dt);CHKERRQ(ierr);
151 
152   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
153      Set runtime options
154    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
155   ierr = TSSetFromOptions(ts);CHKERRQ(ierr);
156 
157   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
158      Solve nonlinear system
159      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
160   ierr = TSSolve(ts,X);CHKERRQ(ierr);
161   ierr = TSGetSolveTime(ts,&ftime);CHKERRQ(ierr);
162   ierr = TSGetStepNumber(ts,&steps);CHKERRQ(ierr);
163   ierr = TSGetConvergedReason(ts,&reason);CHKERRQ(ierr);
164   ierr = PetscPrintf(PETSC_COMM_WORLD,"%s at time %g after %D steps\n",TSConvergedReasons[reason],ftime,steps);CHKERRQ(ierr);
165 
166   if (user->io) {
167     /* Print the numerical solution to screen and then dump to file */
168     ierr = VecView(X,PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
169 
170     /* Write out the solution along with the mesh */
171     ierr = DMMoabSetGlobalFieldVector(dm, X);CHKERRQ(ierr);
172 #ifdef MOAB_HAVE_HDF5
173     ierr = DMMoabOutput(dm, "ex35.h5m", "");CHKERRQ(ierr);
174 #else
175     /* MOAB does not support true parallel writers that aren't HDF5 based
176        And so if you are using VTK as the output format in parallel,
177        the data could be jumbled due to the order in which the processors
178        write out their parts of the mesh and solution tags
179     */
180     ierr = DMMoabOutput(dm, "ex35.vtk", "");CHKERRQ(ierr);
181 #endif
182   }
183 
184   /* Free work space.
185      Free all PETSc related resources: */
186   ierr = MatDestroy(&J);CHKERRQ(ierr);
187   ierr = VecDestroy(&X);CHKERRQ(ierr);
188   ierr = TSDestroy(&ts);CHKERRQ(ierr);
189   ierr = DMDestroy(&dm);CHKERRQ(ierr);
190 
191   /* Free all MOAB related resources: */
192   ierr = Destroy_AppContext(&user);CHKERRQ(ierr);
193   ierr = PetscFinalize();
194   return ierr;
195 }
196 
197 /*
198   IJacobian - Compute IJacobian = dF/dU + a dF/dUdot
199 */
200 PetscErrorCode FormIJacobian(TS ts,PetscReal t,Vec X,Vec Xdot,PetscReal a,Mat J,Mat Jpre,void *ptr)
201 {
202   UserCtx             user = (UserCtx)ptr;
203   PetscErrorCode      ierr;
204   PetscInt            dof;
205   PetscReal           hx;
206   DM                  dm;
207   const moab::Range   *vlocal;
208   PetscBool           vonboundary;
209 
210   PetscFunctionBegin;
211   ierr = TSGetDM(ts, &dm);CHKERRQ(ierr);
212 
213   /* get the essential MOAB mesh related quantities needed for FEM assembly */
214   ierr = DMMoabGetLocalVertices(dm, &vlocal, NULL);CHKERRQ(ierr);
215 
216   /* compute local element sizes - structured grid */
217   hx = 1.0/user->n;
218 
219   /* Compute function over the locally owned part of the grid
220      Assemble the operator by looping over edges and computing
221      contribution for each vertex dof                         */
222   for (moab::Range::iterator iter = vlocal->begin(); iter != vlocal->end(); iter++) {
223     const moab::EntityHandle vhandle = *iter;
224 
225     ierr = DMMoabGetDofsBlocked(dm, 1, &vhandle, &dof);CHKERRQ(ierr);
226 
227     /* check if vertex is on the boundary */
228     ierr = DMMoabIsEntityOnBoundary(dm,vhandle,&vonboundary);CHKERRQ(ierr);
229 
230     if (vonboundary) {
231       const PetscScalar bcvals[2][2] = {{hx,0},{0,hx}};
232       ierr = MatSetValuesBlocked(Jpre,1,&dof,1,&dof,&bcvals[0][0],INSERT_VALUES);CHKERRQ(ierr);
233     }
234     else {
235       const PetscInt    row           = dof,col[] = {dof-1,dof,dof+1};
236       const PetscScalar dxxL          = -user->alpha/hx,dxx0 = 2.*user->alpha/hx,dxxR = -user->alpha/hx;
237       const PetscScalar vals[2][3][2] = {{{dxxL,0},{a *hx+dxx0,0},{dxxR,0}},
238                                          {{0,dxxL},{0,a*hx+dxx0},{0,dxxR}}};
239       ierr = MatSetValuesBlocked(Jpre,1,&row,3,col,&vals[0][0][0],INSERT_VALUES);CHKERRQ(ierr);
240     }
241   }
242 
243   ierr = MatAssemblyBegin(Jpre,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
244   ierr = MatAssemblyEnd(Jpre,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
245   if (J != Jpre) {
246     ierr = MatAssemblyBegin(J,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
247     ierr = MatAssemblyEnd(J,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
248   }
249   PetscFunctionReturn(0);
250 }
251 
252 static PetscErrorCode FormRHSFunction(TS ts,PetscReal t,Vec X,Vec F,void *ptr)
253 {
254   UserCtx           user = (UserCtx)ptr;
255   DM                dm;
256   PetscReal         hx;
257   const Field       *x;
258   Field             *f;
259   PetscInt          dof;
260   const moab::Range *ownedvtx;
261   PetscErrorCode    ierr;
262 
263   PetscFunctionBegin;
264   hx = 1.0/user->n;
265   ierr = TSGetDM(ts,&dm);CHKERRQ(ierr);
266 
267   /* Get pointers to vector data */
268   ierr = VecSet(F,0.0);CHKERRQ(ierr);
269 
270   ierr = DMMoabVecGetArrayRead(dm, X, &x);CHKERRQ(ierr);
271   ierr = DMMoabVecGetArray(dm, F, &f);CHKERRQ(ierr);
272 
273   ierr = DMMoabGetLocalVertices(dm, &ownedvtx, NULL);CHKERRQ(ierr);
274 
275   /* Compute function over the locally owned part of the grid */
276   for (moab::Range::iterator iter = ownedvtx->begin(); iter != ownedvtx->end(); iter++) {
277     const moab::EntityHandle vhandle = *iter;
278     ierr = DMMoabGetDofsBlockedLocal(dm, 1, &vhandle, &dof);CHKERRQ(ierr);
279 
280     PetscScalar u = x[dof].u,v = x[dof].v;
281     f[dof].u = hx*(user->A + u*u*v - (user->B+1)*u);
282     f[dof].v = hx*(user->B*u - u*u*v);
283   }
284 
285   /* Restore vectors */
286   ierr = DMMoabVecRestoreArrayRead(dm, X, &x);CHKERRQ(ierr);
287   ierr = DMMoabVecRestoreArray(dm, F, &f);CHKERRQ(ierr);
288   PetscFunctionReturn(0);
289 }
290 
291 static PetscErrorCode FormIFunction(TS ts,PetscReal t,Vec X,Vec Xdot,Vec F,void *ctx)
292 {
293   UserCtx         user = (UserCtx)ctx;
294   DM              dm;
295   Field           *x,*xdot,*f;
296   PetscReal       hx;
297   Vec             Xloc;
298   PetscErrorCode  ierr;
299   PetscInt        i,bcindx;
300   PetscBool       elem_on_boundary;
301   const moab::Range   *vlocal;
302 
303   PetscFunctionBegin;
304   hx = 1.0/user->n;
305   ierr = TSGetDM(ts, &dm);CHKERRQ(ierr);
306 
307   /* get the essential MOAB mesh related quantities needed for FEM assembly */
308   ierr = DMMoabGetLocalVertices(dm, &vlocal, NULL);CHKERRQ(ierr);
309 
310   /* reset the residual vector */
311   ierr = VecSet(F,0.0);CHKERRQ(ierr);
312 
313   ierr = DMGetLocalVector(dm,&Xloc);CHKERRQ(ierr);
314   ierr = DMGlobalToLocalBegin(dm,X,INSERT_VALUES,Xloc);CHKERRQ(ierr);
315   ierr = DMGlobalToLocalEnd(dm,X,INSERT_VALUES,Xloc);CHKERRQ(ierr);
316 
317   /* get the local representation of the arrays from Vectors */
318   ierr = DMMoabVecGetArrayRead(dm, Xloc, &x);CHKERRQ(ierr);
319   ierr = DMMoabVecGetArrayRead(dm, Xdot, &xdot);CHKERRQ(ierr);
320   ierr = DMMoabVecGetArray(dm, F, &f);CHKERRQ(ierr);
321 
322   /* loop over local elements */
323   for (moab::Range::iterator iter = vlocal->begin(); iter != vlocal->end(); iter++) {
324     const moab::EntityHandle vhandle = *iter;
325 
326     ierr = DMMoabGetDofsBlockedLocal(dm,1,&vhandle,&i);CHKERRQ(ierr);
327 
328     /* check if vertex is on the boundary */
329     ierr = DMMoabIsEntityOnBoundary(dm,vhandle,&elem_on_boundary);CHKERRQ(ierr);
330 
331     if (elem_on_boundary) {
332       ierr = DMMoabGetDofsBlocked(dm, 1, &vhandle, &bcindx);CHKERRQ(ierr);
333       if (bcindx == 0) {  /* Apply left BC */
334         f[i].u = hx * (x[i].u - user->leftbc.u);
335         f[i].v = hx * (x[i].v - user->leftbc.v);
336       } else {       /* Apply right BC */
337         f[i].u = hx * (x[i].u - user->rightbc.u);
338         f[i].v = hx * (x[i].v - user->rightbc.v);
339       }
340     }
341     else {
342       f[i].u = hx * xdot[i].u - user->alpha * (x[i-1].u - 2.*x[i].u + x[i+1].u) / hx;
343       f[i].v = hx * xdot[i].v - user->alpha * (x[i-1].v - 2.*x[i].v + x[i+1].v) / hx;
344     }
345   }
346 
347   /* Restore data */
348   ierr = DMMoabVecRestoreArrayRead(dm, Xloc, &x);CHKERRQ(ierr);
349   ierr = DMMoabVecRestoreArrayRead(dm, Xdot, &xdot);CHKERRQ(ierr);
350   ierr = DMMoabVecRestoreArray(dm, F, &f);CHKERRQ(ierr);
351   ierr = DMRestoreLocalVector(dm, &Xloc);CHKERRQ(ierr);
352   PetscFunctionReturn(0);
353 }
354 
355 PetscErrorCode FormInitialSolution(TS ts,Vec X,void *ctx)
356 {
357   UserCtx           user = (UserCtx)ctx;
358   PetscReal         vpos[3];
359   DM                dm;
360   Field             *x;
361   PetscErrorCode    ierr;
362   const moab::Range *vowned;
363   PetscInt          dof;
364   moab::Range::iterator iter;
365 
366   PetscFunctionBegin;
367   ierr = TSGetDM(ts, &dm);CHKERRQ(ierr);
368 
369   /* get the essential MOAB mesh related quantities needed for FEM assembly */
370   ierr = DMMoabGetLocalVertices(dm, &vowned, NULL);CHKERRQ(ierr);
371 
372   ierr = VecSet(X, 0.0);CHKERRQ(ierr);
373 
374   /* Get pointers to vector data */
375   ierr = DMMoabVecGetArray(dm, X, &x);CHKERRQ(ierr);
376 
377   /* Compute function over the locally owned part of the grid */
378   for (moab::Range::iterator iter = vowned->begin(); iter != vowned->end(); iter++) {
379     const moab::EntityHandle vhandle = *iter;
380     ierr = DMMoabGetDofsBlockedLocal(dm, 1, &vhandle, &dof);CHKERRQ(ierr);
381 
382     /* compute the mid-point of the element and use a 1-point lumped quadrature */
383     ierr = DMMoabGetVertexCoordinates(dm,1,&vhandle,vpos);CHKERRQ(ierr);
384 
385     PetscReal xi = vpos[0];
386     x[dof].u = user->leftbc.u*(1.-xi) + user->rightbc.u*xi + PetscSinReal(2.*PETSC_PI*xi);
387     x[dof].v = user->leftbc.v*(1.-xi) + user->rightbc.v*xi;
388   }
389 
390   /* Restore vectors */
391   ierr = DMMoabVecRestoreArray(dm, X, &x);CHKERRQ(ierr);
392   PetscFunctionReturn(0);
393 }
394 
395 /*TEST
396 
397     build:
398       requires: moab
399 
400     test:
401       args: -n 20 -ts_type rosw -ts_rosw_type 2p -ts_dt 5e-2 -ts_adapt_type none
402 
403     test:
404       suffix: 2
405       nsize: 2
406       args: -n 50 -ts_type glee -ts_adapt_type none -ts_dt 0.1 -io
407       TODO:
408 
409 TEST*/
410