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