xref: /petsc/src/ts/tutorials/ex27.c (revision 0e03b746557e2551025fde0294144c0532d12f68)
1 static char help[] = "Time-Dependent Reactive Flow example in 2D with Darcy Flow";
2 
3 /*T
4    Concepts: Solving a multicomponent time-dependent reactive flow system
5    Concepts: DMDA with timestepping
6    Processors: n
7 T*/
8 
9 /*
10 
11 This example solves the elementary chemical reaction:
12 
13 SP_A + 2SP_B = SP_C
14 
15 Subject to predetermined flow modeled as though it were in a porous media.
16 This flow is modeled as advection and diffusion of the three species as
17 
18 v = porosity*saturation*grad(q)
19 
20 and the time-dependent equation solved for each species as
21 advection + diffusion + reaction:
22 
23 v dot grad SP_i + dSP_i / dt + dispersivity*div*grad(SP_i) + R(SP_i) = 0
24 
25 The following options are available:
26 
27 -length_x - The length of the domain in the direction of the flow
28 -length_y - The length of the domain in the direction orthogonal to the flow
29 
30 -gradq_inflow - The inflow speed as if the saturation and porosity were 1.
31 -saturation - The saturation of the porous medium.
32 -porosity - The porosity of the medium.
33 -dispersivity - The dispersivity of the flow.
34 -rate_constant - The rate constant for the chemical reaction
35 -stoich - The stoichiometry matrix for the reaction
36 -sp_inflow - The species concentrations at the inflow
37 -sp_0 - The species concentrations at time 0
38 
39  */
40 
41 #include <petscdm.h>
42 #include <petscdmda.h>
43 #include <petscsnes.h>
44 #include <petscts.h>
45 
46 #define N_SPECIES 3
47 #define N_REACTIONS 1
48 #define DIM 2
49 
50 #define stoich(i, j)  ctx->stoichiometry[N_SPECIES*i + j]
51 
52 typedef struct {
53   PetscScalar sp[N_SPECIES];
54 } Field;
55 
56 
57 typedef struct {
58 
59   Field     x_inflow;
60   Field     x_0;
61   PetscReal stoichiometry[N_SPECIES*N_REACTIONS];
62   PetscReal porosity;
63   PetscReal dispersivity;
64   PetscReal saturation;
65   PetscReal rate_constant[N_REACTIONS];
66   PetscReal gradq_inflow;
67   PetscReal length[DIM];
68 } AppCtx;
69 
70 extern PetscErrorCode FormInitialGuess(DM da,AppCtx *ctx,Vec X);
71 extern PetscErrorCode FormIFunctionLocal(DMDALocalInfo*,PetscReal,Field**,Field**,Field**,AppCtx*);
72 extern PetscErrorCode FormIFunction(TS,PetscReal,Vec,Vec,Vec,void*);
73 extern PetscErrorCode ReactingFlowPostCheck(SNESLineSearch,Vec,Vec,Vec,PetscBool*,PetscBool*,void*);
74 
75 
76 PetscErrorCode SetFromOptions(AppCtx * ctx)
77 {
78   PetscErrorCode ierr;
79   PetscInt       i,j;
80 
81   PetscFunctionBeginUser;
82   ctx->dispersivity     = 0.5;
83   ctx->porosity         = 0.25;
84   ctx->saturation       = 1.0;
85   ctx->gradq_inflow     = 1.0;
86   ctx->rate_constant[0] = 0.5;
87 
88   ctx->length[0] = 100.0;
89   ctx->length[1] = 100.0;
90 
91   ctx->x_0.sp[0] = 0.0;
92   ctx->x_0.sp[1] = 0.0;
93   ctx->x_0.sp[2] = 0.0;
94 
95   ctx->x_inflow.sp[0] = 0.05;
96   ctx->x_inflow.sp[1] = 0.05;
97   ctx->x_inflow.sp[2] = 0.0;
98 
99   for (i = 0; i < N_REACTIONS; i++) {
100     for (j = 0; j < N_SPECIES; j++) stoich(i, j) = 0.;
101   }
102 
103   /* set up a pretty easy example */
104   stoich(0, 0) = -1.;
105   stoich(0, 1) = -2.;
106   stoich(0, 2) = 1.;
107 
108   PetscInt as = N_SPECIES;
109   ierr = PetscOptionsGetReal(NULL,NULL,"-length_x",&ctx->length[0],NULL);CHKERRQ(ierr);
110   ierr = PetscOptionsGetReal(NULL,NULL,"-length_y",&ctx->length[1],NULL);CHKERRQ(ierr);
111   ierr = PetscOptionsGetReal(NULL,NULL,"-porosity",&ctx->porosity,NULL);CHKERRQ(ierr);
112   ierr = PetscOptionsGetReal(NULL,NULL,"-saturation",&ctx->saturation,NULL);CHKERRQ(ierr);
113   ierr = PetscOptionsGetReal(NULL,NULL,"-dispersivity",&ctx->dispersivity,NULL);CHKERRQ(ierr);
114   ierr = PetscOptionsGetReal(NULL,NULL,"-gradq_inflow",&ctx->gradq_inflow,NULL);CHKERRQ(ierr);
115   ierr = PetscOptionsGetReal(NULL,NULL,"-rate_constant",&ctx->rate_constant[0],NULL);CHKERRQ(ierr);
116   ierr = PetscOptionsGetRealArray(NULL,NULL,"-sp_inflow",ctx->x_inflow.sp,&as,NULL);CHKERRQ(ierr);
117   ierr = PetscOptionsGetRealArray(NULL,NULL,"-sp_0",ctx->x_0.sp,&as,NULL);CHKERRQ(ierr);
118   as   = N_SPECIES;
119   ierr = PetscOptionsGetRealArray(NULL,NULL,"-stoich",ctx->stoichiometry,&as,NULL);CHKERRQ(ierr);
120   PetscFunctionReturn(0);
121 }
122 
123 int main(int argc,char **argv)
124 {
125   TS             ts;
126   SNES           snes;
127   SNESLineSearch linesearch;
128   Vec            x;
129   AppCtx         ctx;
130   PetscErrorCode ierr;
131   DM             da;
132 
133   ierr = PetscInitialize(&argc,&argv,(char*)0,help);if (ierr) return ierr;
134   ierr = SetFromOptions(&ctx);CHKERRQ(ierr);
135   ierr = TSCreate(PETSC_COMM_WORLD, &ts);CHKERRQ(ierr);
136   ierr = TSSetType(ts,TSCN);CHKERRQ(ierr);
137   ierr = TSSetProblemType(ts,TS_NONLINEAR);CHKERRQ(ierr);
138   ierr = TSSetIFunction(ts, NULL, FormIFunction, &ctx);CHKERRQ(ierr);
139   ierr = DMDACreate2d(PETSC_COMM_WORLD, DM_BOUNDARY_NONE, DM_BOUNDARY_NONE,DMDA_STENCIL_STAR,-4,-4,PETSC_DECIDE,PETSC_DECIDE,N_SPECIES,1,NULL,NULL,&da);CHKERRQ(ierr);
140   ierr = DMSetFromOptions(da);CHKERRQ(ierr);
141   ierr = DMSetUp(da);CHKERRQ(ierr);
142   ierr = DMDASetUniformCoordinates(da, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0);CHKERRQ(ierr);
143   ierr = DMDASetFieldName(da,0,"species A");CHKERRQ(ierr);
144   ierr = DMDASetFieldName(da,1,"species B");CHKERRQ(ierr);
145   ierr = DMDASetFieldName(da,2,"species C");CHKERRQ(ierr);
146   ierr = DMSetApplicationContext(da,&ctx);CHKERRQ(ierr);
147   ierr = DMCreateGlobalVector(da,&x);CHKERRQ(ierr);
148   ierr = FormInitialGuess(da, &ctx, x);CHKERRQ(ierr);
149 
150   ierr = TSSetDM(ts, da);CHKERRQ(ierr);
151   ierr = TSSetMaxTime(ts,1000.0);CHKERRQ(ierr);
152   ierr = TSSetExactFinalTime(ts,TS_EXACTFINALTIME_STEPOVER);CHKERRQ(ierr);
153   ierr = TSSetTimeStep(ts,1.0);CHKERRQ(ierr);
154   ierr = TSSetSolution(ts,x);CHKERRQ(ierr);
155   ierr = TSSetFromOptions(ts);CHKERRQ(ierr);
156 
157   ierr = TSGetSNES(ts,&snes);CHKERRQ(ierr);
158   ierr = SNESGetLineSearch(snes,&linesearch);CHKERRQ(ierr);
159   ierr = SNESLineSearchSetPostCheck(linesearch, ReactingFlowPostCheck, (void*)&ctx);CHKERRQ(ierr);
160   ierr = SNESSetFromOptions(snes);CHKERRQ(ierr);
161   ierr = TSSolve(ts,x);CHKERRQ(ierr);
162 
163   ierr = VecDestroy(&x);CHKERRQ(ierr);
164   ierr = TSDestroy(&ts);CHKERRQ(ierr);
165   ierr = DMDestroy(&da);CHKERRQ(ierr);
166   ierr = PetscFinalize();
167   PetscFunctionReturn(0);
168 }
169 
170 /* ------------------------------------------------------------------- */
171 
172 PetscErrorCode FormInitialGuess(DM da,AppCtx *ctx,Vec X)
173 {
174   PetscInt       i,j,l,Mx,My,xs,ys,xm,ym;
175   PetscErrorCode ierr;
176   Field          **x;
177 
178   PetscFunctionBeginUser;
179   ierr = DMDAGetInfo(da,PETSC_IGNORE,&Mx,&My,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,
180                      PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE);
181 
182   ierr = DMDAVecGetArray(da,X,&x);CHKERRQ(ierr);
183   ierr = DMDAGetCorners(da,&xs,&ys,NULL,&xm,&ym,NULL);CHKERRQ(ierr);
184 
185   for (j=ys; j<ys+ym; j++) {
186     for (i=xs; i<xs+xm; i++) {
187       for (l = 0; l < N_SPECIES; l++) {
188         if (i == 0) {
189           if (l == 0)      x[j][i].sp[l] = (ctx->x_inflow.sp[l]*((PetscScalar)j) / (My - 1));
190           else if (l == 1) x[j][i].sp[l] = (ctx->x_inflow.sp[l]*(1. - ((PetscScalar)j) / (My - 1)));
191           else             x[j][i].sp[l] = ctx->x_0.sp[l];
192         }
193       }
194     }
195   }
196   ierr = DMDAVecRestoreArray(da,X,&x);CHKERRQ(ierr);
197   PetscFunctionReturn(0);
198 
199 }
200 
201 PetscErrorCode FormIFunctionLocal(DMDALocalInfo *info,PetscScalar ptime,Field **x,Field **xt,Field **f,AppCtx *ctx)
202 {
203   PetscErrorCode ierr;
204   PetscInt       i,j,l,m;
205   PetscReal      hx,hy,dhx,dhy,hxdhy,hydhx,scale;
206   PetscScalar    u,uxx,uyy;
207   PetscScalar    vx, vy,sxp,syp,sxm,sym,avx,vxp,vxm,avy,vyp,vym,f_advect;
208   PetscScalar    rate;
209 
210   PetscFunctionBeginUser;
211   hx = ctx->length[0]/((PetscReal)(info->mx-1));
212   hy = ctx->length[1]/((PetscReal)(info->my-1));
213 
214   dhx   =     1. / hx;
215   dhy   =     1. / hy;
216   hxdhy =  hx/hy;
217   hydhx =  hy/hx;
218   scale =   hx*hy;
219 
220   for (j=info->ys; j<info->ys+info->ym; j++) {
221     for (i=info->xs; i<info->xs+info->xm; i++) {
222       vx  = ctx->gradq_inflow*ctx->porosity*ctx->saturation;
223       vy  = 0.0*dhy;
224       avx = PetscAbsScalar(vx);
225       vxp = .5*(vx+avx); vxm = .5*(vx-avx);
226       avy = PetscAbsScalar(vy);
227       vyp = .5*(vy+avy); vym = .5*(vy-avy);
228       /* chemical reactions */
229       for (l = 0; l < N_SPECIES; l++) {
230         /* determine the velocites as the gradients of the pressure */
231         if (i == 0) {
232           sxp = (x[j][i+1].sp[l] - x[j][i].sp[l])*dhx;
233           sxm = sxp;
234         } else if (i == info->mx - 1) {
235           sxp = (x[j][i].sp[l] - x[j][i-1].sp[l])*dhx;
236           sxm = sxp;
237         } else {
238           sxm = (x[j][i+1].sp[l] - x[j][i].sp[l])*dhx;
239           sxp = (x[j][i].sp[l] - x[j][i-1].sp[l])*dhx;
240         }
241         if (j == 0) {
242           syp = (x[j+1][i].sp[l] - x[j][i].sp[l])*dhy;
243           sym = syp;
244         } else if (j == info->my - 1) {
245           syp = (x[j][i].sp[l] - x[j-1][i].sp[l])*dhy;
246           sym = syp;
247         } else {
248           sym = (x[j+1][i].sp[l] - x[j][i].sp[l])*dhy;
249           syp = (x[j][i].sp[l] - x[j-1][i].sp[l])*dhy;
250         } /* 4 flops per species*point */
251 
252         if (i == 0) {
253           if (l == 0)      f[j][i].sp[l] = (x[j][i].sp[l] - ctx->x_inflow.sp[l]*((PetscScalar)j) / (info->my - 1));
254           else if (l == 1) f[j][i].sp[l] = (x[j][i].sp[l] - ctx->x_inflow.sp[l]*(1. - ((PetscScalar)j) / (info->my - 1)));
255           else             f[j][i].sp[l] = x[j][i].sp[l];
256 
257         } else {
258           f[j][i].sp[l] = xt[j][i].sp[l]*scale;
259           u       = x[j][i].sp[l];
260           if (j == 0) uyy = u - x[j+1][i].sp[l];
261           else if (j == info->my - 1) uyy = u - x[j-1][i].sp[l];
262           else                        uyy = (2.0*u - x[j-1][i].sp[l] - x[j+1][i].sp[l])*hxdhy;
263 
264           if (i != info->mx - 1) uxx = (2.0*u - x[j][i-1].sp[l] - x[j][i+1].sp[l])*hydhx;
265           else                   uxx = u - x[j][i-1].sp[l];
266           /* 10 flops per species*point */
267 
268           f_advect       = 0.;
269           f_advect      += scale*(vxp*sxp + vxm*sxm);
270           f_advect      += scale*(vyp*syp + vym*sym);
271           f[j][i].sp[l] += f_advect + ctx->dispersivity*(uxx + uyy);
272           /* 14 flops per species*point */
273         }
274       }
275       /* reaction */
276       if (i != 0) {
277         for (m = 0; m < N_REACTIONS; m++) {
278           rate = ctx->rate_constant[m];
279           for (l = 0; l < N_SPECIES; l++) {
280             if (stoich(m, l) < 0) {
281               /* assume an elementary reaction */
282               rate *= PetscPowScalar(x[j][i].sp[l], PetscAbsScalar(stoich(m, l)));
283               /* ~10 flops per reaction per species per point */
284             }
285           }
286           for (l = 0; l < N_SPECIES; l++) {
287               f[j][i].sp[l] += -scale*stoich(m, l)*rate;  /* Reaction term */
288               /* 3 flops per reaction per species per point */
289           }
290         }
291       }
292     }
293   }
294   ierr = PetscLogFlops((N_SPECIES*(28 + 13*N_REACTIONS))*info->ym*info->xm);CHKERRQ(ierr);
295   PetscFunctionReturn(0);
296 }
297 
298 
299 PetscErrorCode ReactingFlowPostCheck(SNESLineSearch linesearch, Vec X, Vec Y, Vec W, PetscBool *changed_y, PetscBool *changed_w, void *vctx)
300 {
301   PetscInt       i,j,l,Mx,My,xs,ys,xm,ym;
302   PetscErrorCode ierr;
303   Field          **x;
304   SNES           snes;
305   DM             da;
306   PetscScalar    min;
307 
308   PetscFunctionBeginUser;
309    *changed_w = PETSC_FALSE;
310   ierr = VecMin(X,NULL,&min);CHKERRQ(ierr);
311   if (min >= 0.) PetscFunctionReturn(0);
312 
313   *changed_w = PETSC_TRUE;
314   ierr = SNESLineSearchGetSNES(linesearch, &snes);CHKERRQ(ierr);
315   ierr = SNESGetDM(snes,&da);CHKERRQ(ierr);
316   ierr = DMDAGetInfo(da,PETSC_IGNORE,&Mx,&My,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,
317                      PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE);
318   ierr = DMDAVecGetArray(da,W,&x);CHKERRQ(ierr);
319   ierr = DMDAGetCorners(da,&xs,&ys,NULL,&xm,&ym,NULL);CHKERRQ(ierr);
320   for (j=ys; j<ys+ym; j++) {
321     for (i=xs; i<xs+xm; i++) {
322       for (l = 0; l < N_SPECIES; l++) {
323         if (x[j][i].sp[l] < 0.) x[j][i].sp[l] = 0.;
324       }
325     }
326   }
327   ierr = DMDAVecRestoreArray(da,W,&x);CHKERRQ(ierr);
328   PetscFunctionReturn(0);
329 }
330 
331 
332 PetscErrorCode FormIFunction(TS ts,PetscReal ptime,Vec X,Vec Xdot,Vec F,void *user)
333 {
334   DMDALocalInfo  info;
335   Field          **u,**udot,**fu;
336   PetscErrorCode ierr;
337   Vec            localX;
338   DM             da;
339 
340   PetscFunctionBeginUser;
341   ierr = TSGetDM(ts,(DM*)&da);CHKERRQ(ierr);
342   ierr = DMGetLocalVector(da,&localX);CHKERRQ(ierr);
343   ierr = DMGlobalToLocalBegin(da,X,INSERT_VALUES,localX);CHKERRQ(ierr);
344   ierr = DMGlobalToLocalEnd(da,X,INSERT_VALUES,localX);CHKERRQ(ierr);
345   ierr = DMDAGetLocalInfo(da,&info);CHKERRQ(ierr);
346   ierr = DMDAVecGetArrayRead(da,localX,&u);CHKERRQ(ierr);
347   ierr = DMDAVecGetArrayRead(da,Xdot,&udot);CHKERRQ(ierr);
348   ierr = DMDAVecGetArray(da,F,&fu);CHKERRQ(ierr);
349   ierr = FormIFunctionLocal(&info,ptime,u,udot,fu,(AppCtx*)user);CHKERRQ(ierr);
350   ierr = DMDAVecRestoreArrayRead(da,localX,&u);CHKERRQ(ierr);
351   ierr = DMDAVecRestoreArrayRead(da,Xdot,&udot);CHKERRQ(ierr);
352   ierr = DMDAVecRestoreArray(da,F,&fu);CHKERRQ(ierr);
353   ierr = DMRestoreLocalVector(da,&localX);CHKERRQ(ierr);
354   PetscFunctionReturn(0);
355 }
356