xref: /petsc/src/ts/tutorials/advection-diffusion-reaction/ex5adj_mf.c (revision 60f0b76ed2293387b137bb632a681b21c2f7fb7d)
1*60f0b76eSHong Zhang static char help[] = "Demonstrates adjoint sensitivity analysis for Reaction-Diffusion Equations.\n";
2*60f0b76eSHong Zhang 
3*60f0b76eSHong Zhang /*
4*60f0b76eSHong Zhang   See ex5.c for details on the equation.
5*60f0b76eSHong Zhang   This code demonestrates the TSAdjoint interface to a system of time-dependent partial differential equations.
6*60f0b76eSHong Zhang   It computes the sensitivity of a component in the final solution, which locates in the center of the 2D domain, w.r.t. the initial conditions.
7*60f0b76eSHong Zhang   The user does not need to provide any additional functions. The required functions in the original simulation are reused in the adjoint run.
8*60f0b76eSHong Zhang 
9*60f0b76eSHong Zhang   Runtime options:
10*60f0b76eSHong Zhang     -forwardonly  - run the forward simulation without adjoint
11*60f0b76eSHong Zhang     -implicitform - provide IFunction and IJacobian to TS, if not set, RHSFunction and RHSJacobian will be used
12*60f0b76eSHong Zhang     -aijpc        - set the preconditioner matrix to be aij (the Jacobian matrix can be of a different type such as ELL)
13*60f0b76eSHong Zhang */
14*60f0b76eSHong Zhang 
15*60f0b76eSHong Zhang #include "reaction_diffusion.h"
16*60f0b76eSHong Zhang #include <petscdm.h>
17*60f0b76eSHong Zhang #include <petscdmda.h>
18*60f0b76eSHong Zhang 
19*60f0b76eSHong Zhang /* Matrix free support */
20*60f0b76eSHong Zhang typedef struct {
21*60f0b76eSHong Zhang   PetscReal time;
22*60f0b76eSHong Zhang   Vec       U;
23*60f0b76eSHong Zhang   Vec       Udot;
24*60f0b76eSHong Zhang   PetscReal shift;
25*60f0b76eSHong Zhang   AppCtx*   appctx;
26*60f0b76eSHong Zhang   TS        ts;
27*60f0b76eSHong Zhang } MCtx;
28*60f0b76eSHong Zhang 
29*60f0b76eSHong Zhang /*
30*60f0b76eSHong Zhang    User-defined routines
31*60f0b76eSHong Zhang */
32*60f0b76eSHong Zhang PetscErrorCode InitialConditions(DM,Vec);
33*60f0b76eSHong Zhang PetscErrorCode RHSJacobianShell(TS,PetscReal,Vec,Mat,Mat,void*);
34*60f0b76eSHong Zhang PetscErrorCode IJacobianShell(TS,PetscReal,Vec,Vec,PetscReal,Mat,Mat,void*);
35*60f0b76eSHong Zhang 
36*60f0b76eSHong Zhang PetscErrorCode InitializeLambda(DM da,Vec lambda,PetscReal x,PetscReal y)
37*60f0b76eSHong Zhang {
38*60f0b76eSHong Zhang    PetscInt i,j,Mx,My,xs,ys,xm,ym;
39*60f0b76eSHong Zhang    PetscErrorCode ierr;
40*60f0b76eSHong Zhang    Field **l;
41*60f0b76eSHong Zhang    PetscFunctionBegin;
42*60f0b76eSHong Zhang 
43*60f0b76eSHong Zhang    ierr = DMDAGetInfo(da,PETSC_IGNORE,&Mx,&My,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE);CHKERRQ(ierr);
44*60f0b76eSHong Zhang    /* locate the global i index for x and j index for y */
45*60f0b76eSHong Zhang    i = (PetscInt)(x*(Mx-1));
46*60f0b76eSHong Zhang    j = (PetscInt)(y*(My-1));
47*60f0b76eSHong Zhang    ierr = DMDAGetCorners(da,&xs,&ys,NULL,&xm,&ym,NULL);CHKERRQ(ierr);
48*60f0b76eSHong Zhang 
49*60f0b76eSHong Zhang    if (xs <= i && i < xs+xm && ys <= j && j < ys+ym) {
50*60f0b76eSHong Zhang      /* the i,j vertex is on this process */
51*60f0b76eSHong Zhang      ierr = DMDAVecGetArray(da,lambda,&l);CHKERRQ(ierr);
52*60f0b76eSHong Zhang      l[j][i].u = 1.0;
53*60f0b76eSHong Zhang      l[j][i].v = 1.0;
54*60f0b76eSHong Zhang      ierr = DMDAVecRestoreArray(da,lambda,&l);CHKERRQ(ierr);
55*60f0b76eSHong Zhang    }
56*60f0b76eSHong Zhang    PetscFunctionReturn(0);
57*60f0b76eSHong Zhang }
58*60f0b76eSHong Zhang 
59*60f0b76eSHong Zhang static PetscErrorCode MyRHSMatMultTranspose(Mat A_shell,Vec X,Vec Y)
60*60f0b76eSHong Zhang {
61*60f0b76eSHong Zhang   MCtx           *mctx;
62*60f0b76eSHong Zhang   AppCtx         *appctx;
63*60f0b76eSHong Zhang   DM             da;
64*60f0b76eSHong Zhang   PetscInt       i,j,Mx,My,xs,ys,xm,ym;
65*60f0b76eSHong Zhang   PetscReal      hx,hy,sx,sy;
66*60f0b76eSHong Zhang   PetscScalar    uc,uxx,uyy,vc,vxx,vyy,ucb,vcb;
67*60f0b76eSHong Zhang   Field          **u,**x,**y;
68*60f0b76eSHong Zhang   Vec            localX;
69*60f0b76eSHong Zhang   PetscErrorCode ierr;
70*60f0b76eSHong Zhang 
71*60f0b76eSHong Zhang   PetscFunctionBeginUser;
72*60f0b76eSHong Zhang   ierr = MatShellGetContext(A_shell,&mctx);CHKERRQ(ierr);
73*60f0b76eSHong Zhang   appctx = mctx->appctx;
74*60f0b76eSHong Zhang   ierr = TSGetDM(mctx->ts,&da);CHKERRQ(ierr);
75*60f0b76eSHong Zhang   ierr = DMGetLocalVector(da,&localX);CHKERRQ(ierr);
76*60f0b76eSHong Zhang   ierr = DMDAGetInfo(da,PETSC_IGNORE,&Mx,&My,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE);CHKERRQ(ierr);
77*60f0b76eSHong Zhang   hx = 2.50/(PetscReal)Mx; sx = 1.0/(hx*hx);
78*60f0b76eSHong Zhang   hy = 2.50/(PetscReal)My; sy = 1.0/(hy*hy);
79*60f0b76eSHong Zhang 
80*60f0b76eSHong Zhang   /* Scatter ghost points to local vector,using the 2-step process
81*60f0b76eSHong Zhang      DMGlobalToLocalBegin(),DMGlobalToLocalEnd().
82*60f0b76eSHong Zhang      By placing code between these two statements, computations can be
83*60f0b76eSHong Zhang      done while messages are in transition. */
84*60f0b76eSHong Zhang   ierr = DMGlobalToLocalBegin(da,X,INSERT_VALUES,localX);CHKERRQ(ierr);
85*60f0b76eSHong Zhang   ierr = DMGlobalToLocalEnd(da,X,INSERT_VALUES,localX);CHKERRQ(ierr);
86*60f0b76eSHong Zhang 
87*60f0b76eSHong Zhang   /* Get pointers to vector data */
88*60f0b76eSHong Zhang   ierr = DMDAVecGetArrayRead(da,localX,&x);CHKERRQ(ierr);
89*60f0b76eSHong Zhang   ierr = DMDAVecGetArrayRead(da,mctx->U,&u);CHKERRQ(ierr);
90*60f0b76eSHong Zhang   ierr = DMDAVecGetArray(da,Y,&y);CHKERRQ(ierr);
91*60f0b76eSHong Zhang 
92*60f0b76eSHong Zhang   /* Get local grid boundaries */
93*60f0b76eSHong Zhang   ierr = DMDAGetCorners(da,&xs,&ys,NULL,&xm,&ym,NULL);CHKERRQ(ierr);
94*60f0b76eSHong Zhang 
95*60f0b76eSHong Zhang   /* Compute function over the locally owned part of the grid */
96*60f0b76eSHong Zhang   for (j=ys; j<ys+ym; j++) {
97*60f0b76eSHong Zhang     for (i=xs; i<xs+xm; i++) {
98*60f0b76eSHong Zhang       uc        = u[j][i].u;
99*60f0b76eSHong Zhang       ucb       = x[j][i].u;
100*60f0b76eSHong Zhang       uxx       = (-2.0*ucb + x[j][i-1].u + x[j][i+1].u)*sx;
101*60f0b76eSHong Zhang       uyy       = (-2.0*ucb + x[j-1][i].u + x[j+1][i].u)*sy;
102*60f0b76eSHong Zhang       vc        = u[j][i].v;
103*60f0b76eSHong Zhang       vcb       = x[j][i].v;
104*60f0b76eSHong Zhang       vxx       = (-2.0*vcb + x[j][i-1].v + x[j][i+1].v)*sx;
105*60f0b76eSHong Zhang       vyy       = (-2.0*vcb + x[j-1][i].v + x[j+1][i].v)*sy;
106*60f0b76eSHong Zhang       y[j][i].u = appctx->D1*(uxx + uyy) - ucb*(vc*vc+appctx->gamma) + vc*vc*vcb;
107*60f0b76eSHong Zhang       y[j][i].v = appctx->D2*(vxx + vyy) - 2.0*uc*vc*ucb + (2.0*uc*vc-appctx->gamma - appctx->kappa)*vcb;
108*60f0b76eSHong Zhang     }
109*60f0b76eSHong Zhang   }
110*60f0b76eSHong Zhang   ierr = DMDAVecRestoreArrayRead(da,localX,&x);CHKERRQ(ierr);
111*60f0b76eSHong Zhang   ierr = DMDAVecRestoreArrayRead(da,mctx->U,&u);CHKERRQ(ierr);
112*60f0b76eSHong Zhang   ierr = DMDAVecRestoreArray(da,Y,&y);CHKERRQ(ierr);
113*60f0b76eSHong Zhang   ierr = DMRestoreLocalVector(da,&localX);CHKERRQ(ierr);
114*60f0b76eSHong Zhang   PetscFunctionReturn(0);
115*60f0b76eSHong Zhang }
116*60f0b76eSHong Zhang 
117*60f0b76eSHong Zhang static PetscErrorCode MyIMatMultTranspose(Mat A_shell,Vec X,Vec Y)
118*60f0b76eSHong Zhang {
119*60f0b76eSHong Zhang   MCtx           *mctx;
120*60f0b76eSHong Zhang   AppCtx         *appctx;
121*60f0b76eSHong Zhang   DM             da;
122*60f0b76eSHong Zhang   PetscInt       i,j,Mx,My,xs,ys,xm,ym;
123*60f0b76eSHong Zhang   PetscReal      hx,hy,sx,sy;
124*60f0b76eSHong Zhang   PetscScalar    uc,uxx,uyy,vc,vxx,vyy,ucb,vcb;
125*60f0b76eSHong Zhang   Field          **u,**x,**y;
126*60f0b76eSHong Zhang   Vec            localX;
127*60f0b76eSHong Zhang   PetscErrorCode ierr;
128*60f0b76eSHong Zhang 
129*60f0b76eSHong Zhang   PetscFunctionBeginUser;
130*60f0b76eSHong Zhang   ierr = MatShellGetContext(A_shell,&mctx);CHKERRQ(ierr);
131*60f0b76eSHong Zhang   appctx = mctx->appctx;
132*60f0b76eSHong Zhang   ierr = TSGetDM(mctx->ts,&da);CHKERRQ(ierr);
133*60f0b76eSHong Zhang   ierr = DMGetLocalVector(da,&localX);CHKERRQ(ierr);
134*60f0b76eSHong Zhang   ierr = DMDAGetInfo(da,PETSC_IGNORE,&Mx,&My,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE);CHKERRQ(ierr);
135*60f0b76eSHong Zhang   hx = 2.50/(PetscReal)Mx; sx = 1.0/(hx*hx);
136*60f0b76eSHong Zhang   hy = 2.50/(PetscReal)My; sy = 1.0/(hy*hy);
137*60f0b76eSHong Zhang 
138*60f0b76eSHong Zhang   /* Scatter ghost points to local vector,using the 2-step process
139*60f0b76eSHong Zhang      DMGlobalToLocalBegin(),DMGlobalToLocalEnd().
140*60f0b76eSHong Zhang      By placing code between these two statements, computations can be
141*60f0b76eSHong Zhang      done while messages are in transition. */
142*60f0b76eSHong Zhang   ierr = DMGlobalToLocalBegin(da,X,INSERT_VALUES,localX);CHKERRQ(ierr);
143*60f0b76eSHong Zhang   ierr = DMGlobalToLocalEnd(da,X,INSERT_VALUES,localX);CHKERRQ(ierr);
144*60f0b76eSHong Zhang 
145*60f0b76eSHong Zhang   /* Get pointers to vector data */
146*60f0b76eSHong Zhang   ierr = DMDAVecGetArrayRead(da,localX,&x);CHKERRQ(ierr);
147*60f0b76eSHong Zhang   ierr = DMDAVecGetArrayRead(da,mctx->U,&u);CHKERRQ(ierr);
148*60f0b76eSHong Zhang   ierr = DMDAVecGetArray(da,Y,&y);CHKERRQ(ierr);
149*60f0b76eSHong Zhang 
150*60f0b76eSHong Zhang   /* Get local grid boundaries */
151*60f0b76eSHong Zhang   ierr = DMDAGetCorners(da,&xs,&ys,NULL,&xm,&ym,NULL);CHKERRQ(ierr);
152*60f0b76eSHong Zhang 
153*60f0b76eSHong Zhang   /* Compute function over the locally owned part of the grid */
154*60f0b76eSHong Zhang   for (j=ys; j<ys+ym; j++) {
155*60f0b76eSHong Zhang     for (i=xs; i<xs+xm; i++) {
156*60f0b76eSHong Zhang       uc        = u[j][i].u;
157*60f0b76eSHong Zhang       ucb       = x[j][i].u;
158*60f0b76eSHong Zhang       uxx       = (-2.0*ucb + x[j][i-1].u + x[j][i+1].u)*sx;
159*60f0b76eSHong Zhang       uyy       = (-2.0*ucb + x[j-1][i].u + x[j+1][i].u)*sy;
160*60f0b76eSHong Zhang       vc        = u[j][i].v;
161*60f0b76eSHong Zhang       vcb       = x[j][i].v;
162*60f0b76eSHong Zhang       vxx       = (-2.0*vcb + x[j][i-1].v + x[j][i+1].v)*sx;
163*60f0b76eSHong Zhang       vyy       = (-2.0*vcb + x[j-1][i].v + x[j+1][i].v)*sy;
164*60f0b76eSHong Zhang       y[j][i].u = appctx->D1*(uxx + uyy) - ucb*(vc*vc+appctx->gamma) + vc*vc*vcb;
165*60f0b76eSHong Zhang       y[j][i].v = appctx->D2*(vxx + vyy) - 2.0*uc*vc*ucb + (2.0*uc*vc-appctx->gamma - appctx->kappa)*vcb;
166*60f0b76eSHong Zhang       y[j][i].u = mctx->shift*ucb - y[j][i].u;
167*60f0b76eSHong Zhang       y[j][i].v = mctx->shift*vcb - y[j][i].v;
168*60f0b76eSHong Zhang     }
169*60f0b76eSHong Zhang   }
170*60f0b76eSHong Zhang   ierr = DMDAVecRestoreArrayRead(da,localX,&x);CHKERRQ(ierr);
171*60f0b76eSHong Zhang   ierr = DMDAVecRestoreArrayRead(da,mctx->U,&u);CHKERRQ(ierr);
172*60f0b76eSHong Zhang   ierr = DMDAVecRestoreArray(da,Y,&y);CHKERRQ(ierr);
173*60f0b76eSHong Zhang   ierr = DMRestoreLocalVector(da,&localX);CHKERRQ(ierr);
174*60f0b76eSHong Zhang   PetscFunctionReturn(0);
175*60f0b76eSHong Zhang }
176*60f0b76eSHong Zhang 
177*60f0b76eSHong Zhang static PetscErrorCode MyIMatMult(Mat A_shell,Vec X,Vec Y)
178*60f0b76eSHong Zhang {
179*60f0b76eSHong Zhang   MCtx           *mctx;
180*60f0b76eSHong Zhang   AppCtx         *appctx;
181*60f0b76eSHong Zhang   DM             da;
182*60f0b76eSHong Zhang   PetscInt       i,j,Mx,My,xs,ys,xm,ym;
183*60f0b76eSHong Zhang   PetscReal      hx,hy,sx,sy;
184*60f0b76eSHong Zhang   PetscScalar    uc,uxx,uyy,vc,vxx,vyy,ucb,vcb;
185*60f0b76eSHong Zhang   Field          **u,**x,**y;
186*60f0b76eSHong Zhang   Vec            localX;
187*60f0b76eSHong Zhang   PetscErrorCode ierr;
188*60f0b76eSHong Zhang 
189*60f0b76eSHong Zhang   PetscFunctionBeginUser;
190*60f0b76eSHong Zhang   ierr = MatShellGetContext(A_shell,&mctx);CHKERRQ(ierr);
191*60f0b76eSHong Zhang   appctx = mctx->appctx;
192*60f0b76eSHong Zhang   ierr = TSGetDM(mctx->ts,&da);CHKERRQ(ierr);
193*60f0b76eSHong Zhang   ierr = DMGetLocalVector(da,&localX);CHKERRQ(ierr);
194*60f0b76eSHong Zhang   ierr = DMDAGetInfo(da,PETSC_IGNORE,&Mx,&My,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE);CHKERRQ(ierr);
195*60f0b76eSHong Zhang   hx = 2.50/(PetscReal)Mx; sx = 1.0/(hx*hx);
196*60f0b76eSHong Zhang   hy = 2.50/(PetscReal)My; sy = 1.0/(hy*hy);
197*60f0b76eSHong Zhang 
198*60f0b76eSHong Zhang   /* Scatter ghost points to local vector,using the 2-step process
199*60f0b76eSHong Zhang      DMGlobalToLocalBegin(),DMGlobalToLocalEnd().
200*60f0b76eSHong Zhang      By placing code between these two statements, computations can be
201*60f0b76eSHong Zhang      done while messages are in transition. */
202*60f0b76eSHong Zhang   ierr = DMGlobalToLocalBegin(da,X,INSERT_VALUES,localX);CHKERRQ(ierr);
203*60f0b76eSHong Zhang   ierr = DMGlobalToLocalEnd(da,X,INSERT_VALUES,localX);CHKERRQ(ierr);
204*60f0b76eSHong Zhang 
205*60f0b76eSHong Zhang   /* Get pointers to vector data */
206*60f0b76eSHong Zhang   ierr = DMDAVecGetArrayRead(da,localX,&x);CHKERRQ(ierr);
207*60f0b76eSHong Zhang   ierr = DMDAVecGetArrayRead(da,mctx->U,&u);CHKERRQ(ierr);
208*60f0b76eSHong Zhang   ierr = DMDAVecGetArray(da,Y,&y);CHKERRQ(ierr);
209*60f0b76eSHong Zhang 
210*60f0b76eSHong Zhang   /* Get local grid boundaries */
211*60f0b76eSHong Zhang   ierr = DMDAGetCorners(da,&xs,&ys,NULL,&xm,&ym,NULL);CHKERRQ(ierr);
212*60f0b76eSHong Zhang 
213*60f0b76eSHong Zhang   /* Compute function over the locally owned part of the grid */
214*60f0b76eSHong Zhang   for (j=ys; j<ys+ym; j++) {
215*60f0b76eSHong Zhang     for (i=xs; i<xs+xm; i++) {
216*60f0b76eSHong Zhang       uc        = u[j][i].u;
217*60f0b76eSHong Zhang       ucb       = x[j][i].u;
218*60f0b76eSHong Zhang       uxx       = (-2.0*ucb + x[j][i-1].u + x[j][i+1].u)*sx;
219*60f0b76eSHong Zhang       uyy       = (-2.0*ucb + x[j-1][i].u + x[j+1][i].u)*sy;
220*60f0b76eSHong Zhang       vc        = u[j][i].v;
221*60f0b76eSHong Zhang       vcb       = x[j][i].v;
222*60f0b76eSHong Zhang       vxx       = (-2.0*vcb + x[j][i-1].v + x[j][i+1].v)*sx;
223*60f0b76eSHong Zhang       vyy       = (-2.0*vcb + x[j-1][i].v + x[j+1][i].v)*sy;
224*60f0b76eSHong Zhang       y[j][i].u = appctx->D1*(uxx + uyy) - (vc*vc+appctx->gamma)*ucb - 2.0*uc*vc*vcb;
225*60f0b76eSHong Zhang       y[j][i].v = appctx->D2*(vxx + vyy) + vc*vc*ucb + (2.0*uc*vc-appctx->gamma-appctx->kappa)*vcb;
226*60f0b76eSHong Zhang       y[j][i].u = mctx->shift*ucb - y[j][i].u;
227*60f0b76eSHong Zhang       y[j][i].v = mctx->shift*vcb - y[j][i].v;
228*60f0b76eSHong Zhang     }
229*60f0b76eSHong Zhang   }
230*60f0b76eSHong Zhang   ierr = DMDAVecRestoreArrayRead(da,localX,&x);CHKERRQ(ierr);
231*60f0b76eSHong Zhang   ierr = DMDAVecRestoreArrayRead(da,mctx->U,&u);CHKERRQ(ierr);
232*60f0b76eSHong Zhang   ierr = DMDAVecRestoreArray(da,Y,&y);CHKERRQ(ierr);
233*60f0b76eSHong Zhang   ierr = DMRestoreLocalVector(da,&localX);CHKERRQ(ierr);
234*60f0b76eSHong Zhang   PetscFunctionReturn(0);
235*60f0b76eSHong Zhang }
236*60f0b76eSHong Zhang 
237*60f0b76eSHong Zhang int main(int argc,char **argv)
238*60f0b76eSHong Zhang {
239*60f0b76eSHong Zhang   TS             ts;                  /* ODE integrator */
240*60f0b76eSHong Zhang   Vec            x;                   /* solution */
241*60f0b76eSHong Zhang   PetscErrorCode ierr;
242*60f0b76eSHong Zhang   DM             da;
243*60f0b76eSHong Zhang   AppCtx         appctx;
244*60f0b76eSHong Zhang   MCtx           mctx;
245*60f0b76eSHong Zhang   Vec            lambda[1];
246*60f0b76eSHong Zhang   PetscBool      forwardonly=PETSC_FALSE,implicitform=PETSC_TRUE,mf = PETSC_FALSE;
247*60f0b76eSHong Zhang   PetscLogDouble v1,v2;
248*60f0b76eSHong Zhang #if defined(PETSC_USE_LOG)
249*60f0b76eSHong Zhang   PetscLogStage  stage;
250*60f0b76eSHong Zhang #endif
251*60f0b76eSHong Zhang 
252*60f0b76eSHong Zhang   ierr = PetscInitialize(&argc,&argv,(char*)0,help);if (ierr) return ierr;
253*60f0b76eSHong Zhang   ierr = PetscOptionsGetBool(NULL,NULL,"-forwardonly",&forwardonly,NULL);CHKERRQ(ierr);
254*60f0b76eSHong Zhang   ierr = PetscOptionsGetBool(NULL,NULL,"-implicitform",&implicitform,NULL);CHKERRQ(ierr);
255*60f0b76eSHong Zhang   appctx.aijpc = PETSC_FALSE;
256*60f0b76eSHong Zhang   ierr = PetscOptionsGetBool(NULL,NULL,"-aijpc",&appctx.aijpc,NULL);CHKERRQ(ierr);
257*60f0b76eSHong Zhang   ierr = PetscOptionsGetBool(NULL,NULL,"-mf",&mf,NULL);CHKERRQ(ierr);
258*60f0b76eSHong Zhang 
259*60f0b76eSHong Zhang   appctx.D1    = 8.0e-5;
260*60f0b76eSHong Zhang   appctx.D2    = 4.0e-5;
261*60f0b76eSHong Zhang   appctx.gamma = .024;
262*60f0b76eSHong Zhang   appctx.kappa = .06;
263*60f0b76eSHong Zhang 
264*60f0b76eSHong Zhang   PetscLogStageRegister("MyAdjoint", &stage);
265*60f0b76eSHong Zhang   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
266*60f0b76eSHong Zhang      Create distributed array (DMDA) to manage parallel grid and vectors
267*60f0b76eSHong Zhang   - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
268*60f0b76eSHong Zhang   ierr = DMDACreate2d(PETSC_COMM_WORLD,DM_BOUNDARY_PERIODIC,DM_BOUNDARY_PERIODIC,DMDA_STENCIL_STAR,64,64,PETSC_DECIDE,PETSC_DECIDE,2,1,NULL,NULL,&da);CHKERRQ(ierr);
269*60f0b76eSHong Zhang   ierr = DMSetFromOptions(da);CHKERRQ(ierr);
270*60f0b76eSHong Zhang   ierr = DMSetUp(da);CHKERRQ(ierr);
271*60f0b76eSHong Zhang   ierr = DMDASetFieldName(da,0,"u");CHKERRQ(ierr);
272*60f0b76eSHong Zhang   ierr = DMDASetFieldName(da,1,"v");CHKERRQ(ierr);
273*60f0b76eSHong Zhang 
274*60f0b76eSHong Zhang   /*  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
275*60f0b76eSHong Zhang      Extract global vectors from DMDA; then duplicate for remaining
276*60f0b76eSHong Zhang      vectors that are the same types
277*60f0b76eSHong Zhang    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
278*60f0b76eSHong Zhang   ierr = DMCreateGlobalVector(da,&x);CHKERRQ(ierr);
279*60f0b76eSHong Zhang 
280*60f0b76eSHong Zhang   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
281*60f0b76eSHong Zhang      Create timestepping solver context
282*60f0b76eSHong Zhang      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
283*60f0b76eSHong Zhang   ierr = TSCreate(PETSC_COMM_WORLD,&ts);CHKERRQ(ierr);
284*60f0b76eSHong Zhang   ierr = TSSetDM(ts,da);CHKERRQ(ierr);
285*60f0b76eSHong Zhang   ierr = TSSetProblemType(ts,TS_NONLINEAR);CHKERRQ(ierr);
286*60f0b76eSHong Zhang   ierr = TSSetEquationType(ts,TS_EQ_ODE_EXPLICIT);CHKERRQ(ierr); /* less Jacobian evaluations when adjoint BEuler is used, otherwise no effect */
287*60f0b76eSHong Zhang   if (!implicitform) {
288*60f0b76eSHong Zhang     ierr = TSSetType(ts,TSRK);CHKERRQ(ierr);
289*60f0b76eSHong Zhang     ierr = TSSetRHSFunction(ts,NULL,RHSFunction,&appctx);CHKERRQ(ierr);
290*60f0b76eSHong Zhang     ierr = TSSetRHSJacobian(ts,NULL,NULL,RHSJacobian,&appctx);CHKERRQ(ierr);
291*60f0b76eSHong Zhang   } else {
292*60f0b76eSHong Zhang     ierr = TSSetType(ts,TSCN);CHKERRQ(ierr);
293*60f0b76eSHong Zhang     ierr = TSSetIFunction(ts,NULL,IFunction,&appctx);CHKERRQ(ierr);
294*60f0b76eSHong Zhang     if (appctx.aijpc) {
295*60f0b76eSHong Zhang       Mat                    A,B;
296*60f0b76eSHong Zhang 
297*60f0b76eSHong Zhang       ierr = DMSetMatType(da,MATSELL);CHKERRQ(ierr);
298*60f0b76eSHong Zhang       ierr = DMCreateMatrix(da,&A);CHKERRQ(ierr);
299*60f0b76eSHong Zhang       ierr = MatConvert(A,MATAIJ,MAT_INITIAL_MATRIX,&B);CHKERRQ(ierr);
300*60f0b76eSHong Zhang       /* FIXME do we need to change viewer to display matrix in natural ordering as DMCreateMatrix_DA does? */
301*60f0b76eSHong Zhang       ierr = TSSetIJacobian(ts,A,B,IJacobian,&appctx);CHKERRQ(ierr);
302*60f0b76eSHong Zhang       ierr = MatDestroy(&A);CHKERRQ(ierr);
303*60f0b76eSHong Zhang       ierr = MatDestroy(&B);CHKERRQ(ierr);
304*60f0b76eSHong Zhang     } else {
305*60f0b76eSHong Zhang       ierr = TSSetIJacobian(ts,NULL,NULL,IJacobian,&appctx);CHKERRQ(ierr);
306*60f0b76eSHong Zhang     }
307*60f0b76eSHong Zhang   }
308*60f0b76eSHong Zhang 
309*60f0b76eSHong Zhang   if (mf) {
310*60f0b76eSHong Zhang     PetscInt xm,ym,Mx,My,dof;
311*60f0b76eSHong Zhang     mctx.ts = ts;
312*60f0b76eSHong Zhang     mctx.appctx = &appctx;
313*60f0b76eSHong Zhang     ierr = VecDuplicate(x,&mctx.U);CHKERRQ(ierr);
314*60f0b76eSHong Zhang     /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
315*60f0b76eSHong Zhang       Create matrix free context
316*60f0b76eSHong Zhang       - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
317*60f0b76eSHong Zhang     ierr = DMDAGetInfo(da,PETSC_IGNORE,&Mx,&My,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,&dof,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE);CHKERRQ(ierr);
318*60f0b76eSHong Zhang     ierr = DMDAGetCorners(da,NULL,NULL,NULL,&xm,&ym,NULL);CHKERRQ(ierr);
319*60f0b76eSHong Zhang     ierr = MatCreateShell(PETSC_COMM_WORLD,dof*xm*ym,PETSC_DETERMINE,dof*Mx*My,dof*Mx*My,&mctx,&appctx.A);CHKERRQ(ierr);
320*60f0b76eSHong Zhang     ierr = MatShellSetOperation(appctx.A,MATOP_MULT_TRANSPOSE,(void (*)(void))MyRHSMatMultTranspose);CHKERRQ(ierr);
321*60f0b76eSHong Zhang     if (!implicitform) { /* for explicit methods only */
322*60f0b76eSHong Zhang       ierr = TSSetRHSJacobian(ts,appctx.A,appctx.A,RHSJacobianShell,&appctx);CHKERRQ(ierr);
323*60f0b76eSHong Zhang     } else {
324*60f0b76eSHong Zhang       /* ierr = VecDuplicate(appctx.U,&mctx.Udot);CHKERRQ(ierr); */
325*60f0b76eSHong Zhang       ierr = MatShellSetOperation(appctx.A,MATOP_MULT,(void (*)(void))MyIMatMult);CHKERRQ(ierr);
326*60f0b76eSHong Zhang       ierr = MatShellSetOperation(appctx.A,MATOP_MULT_TRANSPOSE,(void (*)(void))MyIMatMultTranspose);CHKERRQ(ierr);
327*60f0b76eSHong Zhang       ierr = TSSetIJacobian(ts,appctx.A,appctx.A,IJacobianShell,&appctx);CHKERRQ(ierr);
328*60f0b76eSHong Zhang     }
329*60f0b76eSHong Zhang   }
330*60f0b76eSHong Zhang 
331*60f0b76eSHong Zhang   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
332*60f0b76eSHong Zhang      Set initial conditions
333*60f0b76eSHong Zhang    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
334*60f0b76eSHong Zhang   ierr = InitialConditions(da,x);CHKERRQ(ierr);
335*60f0b76eSHong Zhang   ierr = TSSetSolution(ts,x);CHKERRQ(ierr);
336*60f0b76eSHong Zhang 
337*60f0b76eSHong Zhang   /*
338*60f0b76eSHong Zhang     Have the TS save its trajectory so that TSAdjointSolve() may be used
339*60f0b76eSHong Zhang   */
340*60f0b76eSHong Zhang   if (!forwardonly) { ierr = TSSetSaveTrajectory(ts);CHKERRQ(ierr); }
341*60f0b76eSHong Zhang 
342*60f0b76eSHong Zhang   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
343*60f0b76eSHong Zhang      Set solver options
344*60f0b76eSHong Zhang    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
345*60f0b76eSHong Zhang   ierr = TSSetMaxTime(ts,200.0);CHKERRQ(ierr);
346*60f0b76eSHong Zhang   ierr = TSSetTimeStep(ts,0.5);CHKERRQ(ierr);
347*60f0b76eSHong Zhang   ierr = TSSetExactFinalTime(ts,TS_EXACTFINALTIME_MATCHSTEP);CHKERRQ(ierr);
348*60f0b76eSHong Zhang   ierr = TSSetFromOptions(ts);CHKERRQ(ierr);
349*60f0b76eSHong Zhang 
350*60f0b76eSHong Zhang   ierr = PetscTime(&v1);CHKERRQ(ierr);
351*60f0b76eSHong Zhang   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
352*60f0b76eSHong Zhang      Solve ODE system
353*60f0b76eSHong Zhang      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
354*60f0b76eSHong Zhang   ierr = TSSolve(ts,x);CHKERRQ(ierr);
355*60f0b76eSHong Zhang   if (!forwardonly) {
356*60f0b76eSHong Zhang     /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
357*60f0b76eSHong Zhang        Start the Adjoint model
358*60f0b76eSHong Zhang        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
359*60f0b76eSHong Zhang     ierr = VecDuplicate(x,&lambda[0]);CHKERRQ(ierr);
360*60f0b76eSHong Zhang     /*   Reset initial conditions for the adjoint integration */
361*60f0b76eSHong Zhang     ierr = InitializeLambda(da,lambda[0],0.5,0.5);CHKERRQ(ierr);
362*60f0b76eSHong Zhang     ierr = TSSetCostGradients(ts,1,lambda,NULL);CHKERRQ(ierr);
363*60f0b76eSHong Zhang     PetscLogStagePush(stage);
364*60f0b76eSHong Zhang     ierr = TSAdjointSolve(ts);CHKERRQ(ierr);
365*60f0b76eSHong Zhang     PetscLogStagePop();
366*60f0b76eSHong Zhang     ierr = VecDestroy(&lambda[0]);CHKERRQ(ierr);
367*60f0b76eSHong Zhang   }
368*60f0b76eSHong Zhang   ierr = PetscTime(&v2);CHKERRQ(ierr);
369*60f0b76eSHong Zhang   ierr = PetscPrintf(PETSC_COMM_WORLD," %.3lf ",v2-v1);
370*60f0b76eSHong Zhang 
371*60f0b76eSHong Zhang   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
372*60f0b76eSHong Zhang      Free work space.  All PETSc objects should be destroyed when they
373*60f0b76eSHong Zhang      are no longer needed.
374*60f0b76eSHong Zhang    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
375*60f0b76eSHong Zhang   ierr = VecDestroy(&x);CHKERRQ(ierr);
376*60f0b76eSHong Zhang   ierr = TSDestroy(&ts);CHKERRQ(ierr);
377*60f0b76eSHong Zhang   ierr = DMDestroy(&da);CHKERRQ(ierr);
378*60f0b76eSHong Zhang   if (mf) {
379*60f0b76eSHong Zhang     ierr = VecDestroy(&mctx.U);CHKERRQ(ierr);
380*60f0b76eSHong Zhang     /* ierr = VecDestroy(&mctx.Udot);CHKERRQ(ierr);*/
381*60f0b76eSHong Zhang     ierr = MatDestroy(&appctx.A);CHKERRQ(ierr);
382*60f0b76eSHong Zhang   }
383*60f0b76eSHong Zhang   ierr = PetscFinalize();
384*60f0b76eSHong Zhang   return ierr;
385*60f0b76eSHong Zhang }
386*60f0b76eSHong Zhang 
387*60f0b76eSHong Zhang /* ------------------------------------------------------------------- */
388*60f0b76eSHong Zhang PetscErrorCode RHSJacobianShell(TS ts,PetscReal t,Vec U,Mat A,Mat BB,void *ctx)
389*60f0b76eSHong Zhang {
390*60f0b76eSHong Zhang   MCtx           *mctx;
391*60f0b76eSHong Zhang   PetscErrorCode ierr;
392*60f0b76eSHong Zhang 
393*60f0b76eSHong Zhang   PetscFunctionBegin;
394*60f0b76eSHong Zhang   ierr = MatShellGetContext(A,&mctx);CHKERRQ(ierr);
395*60f0b76eSHong Zhang   ierr = VecCopy(U,mctx->U);CHKERRQ(ierr);
396*60f0b76eSHong Zhang   PetscFunctionReturn(0);
397*60f0b76eSHong Zhang }
398*60f0b76eSHong Zhang 
399*60f0b76eSHong Zhang PetscErrorCode IJacobianShell(TS ts,PetscReal t,Vec U,Vec Udot,PetscReal a,Mat A,Mat BB,void *ctx)
400*60f0b76eSHong Zhang {
401*60f0b76eSHong Zhang   MCtx           *mctx;
402*60f0b76eSHong Zhang   PetscErrorCode ierr;
403*60f0b76eSHong Zhang 
404*60f0b76eSHong Zhang   PetscFunctionBegin;
405*60f0b76eSHong Zhang   ierr = MatShellGetContext(A,&mctx);CHKERRQ(ierr);
406*60f0b76eSHong Zhang   ierr = VecCopy(U,mctx->U);CHKERRQ(ierr);
407*60f0b76eSHong Zhang   /* ierr = VecCopy(Udot,mctx->Udot);CHKERRQ(ierr); */
408*60f0b76eSHong Zhang   mctx->shift = a;
409*60f0b76eSHong Zhang   PetscFunctionReturn(0);
410*60f0b76eSHong Zhang }
411*60f0b76eSHong Zhang 
412*60f0b76eSHong Zhang /* ------------------------------------------------------------------- */
413*60f0b76eSHong Zhang PetscErrorCode InitialConditions(DM da,Vec U)
414*60f0b76eSHong Zhang {
415*60f0b76eSHong Zhang   PetscErrorCode ierr;
416*60f0b76eSHong Zhang   PetscInt       i,j,xs,ys,xm,ym,Mx,My;
417*60f0b76eSHong Zhang   Field          **u;
418*60f0b76eSHong Zhang   PetscReal      hx,hy,x,y;
419*60f0b76eSHong Zhang 
420*60f0b76eSHong Zhang   PetscFunctionBegin;
421*60f0b76eSHong Zhang   ierr = DMDAGetInfo(da,PETSC_IGNORE,&Mx,&My,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE,PETSC_IGNORE);CHKERRQ(ierr);
422*60f0b76eSHong Zhang 
423*60f0b76eSHong Zhang   hx = 2.5/(PetscReal)Mx;
424*60f0b76eSHong Zhang   hy = 2.5/(PetscReal)My;
425*60f0b76eSHong Zhang 
426*60f0b76eSHong Zhang   /*
427*60f0b76eSHong Zhang      Get pointers to vector data
428*60f0b76eSHong Zhang   */
429*60f0b76eSHong Zhang   ierr = DMDAVecGetArray(da,U,&u);CHKERRQ(ierr);
430*60f0b76eSHong Zhang 
431*60f0b76eSHong Zhang   /*
432*60f0b76eSHong Zhang      Get local grid boundaries
433*60f0b76eSHong Zhang   */
434*60f0b76eSHong Zhang   ierr = DMDAGetCorners(da,&xs,&ys,NULL,&xm,&ym,NULL);CHKERRQ(ierr);
435*60f0b76eSHong Zhang 
436*60f0b76eSHong Zhang   /*
437*60f0b76eSHong Zhang      Compute function over the locally owned part of the grid
438*60f0b76eSHong Zhang   */
439*60f0b76eSHong Zhang   for (j=ys; j<ys+ym; j++) {
440*60f0b76eSHong Zhang     y = j*hy;
441*60f0b76eSHong Zhang     for (i=xs; i<xs+xm; i++) {
442*60f0b76eSHong Zhang       x = i*hx;
443*60f0b76eSHong Zhang       if ((1.0 <= x) && (x <= 1.5) && (1.0 <= y) && (y <= 1.5)) u[j][i].v = .25*PetscPowReal(PetscSinReal(4.0*PETSC_PI*x),2.0)*PetscPowReal(PetscSinReal(4.0*PETSC_PI*y),2.0);
444*60f0b76eSHong Zhang       else u[j][i].v = 0.0;
445*60f0b76eSHong Zhang 
446*60f0b76eSHong Zhang       u[j][i].u = 1.0 - 2.0*u[j][i].v;
447*60f0b76eSHong Zhang     }
448*60f0b76eSHong Zhang   }
449*60f0b76eSHong Zhang 
450*60f0b76eSHong Zhang   /*
451*60f0b76eSHong Zhang      Restore vectors
452*60f0b76eSHong Zhang   */
453*60f0b76eSHong Zhang   ierr = DMDAVecRestoreArray(da,U,&u);CHKERRQ(ierr);
454*60f0b76eSHong Zhang   PetscFunctionReturn(0);
455*60f0b76eSHong Zhang }
456*60f0b76eSHong Zhang 
457*60f0b76eSHong Zhang /*TEST
458*60f0b76eSHong Zhang 
459*60f0b76eSHong Zhang    build:
460*60f0b76eSHong Zhang       depends: reaction_diffusion.c
461*60f0b76eSHong Zhang       requires: !complex !single
462*60f0b76eSHong Zhang 
463*60f0b76eSHong Zhang    test:
464*60f0b76eSHong Zhang       requires: cams
465*60f0b76eSHong Zhang       args: -mf -ts_max_steps 10 -ts_monitor -ts_adjoint_monitor -ts_trajectory_type memory -ts_trajectory_solution_only 0 -ts_trajectory_max_units_ram 6
466*60f0b76eSHong Zhang TEST*/
467