static char help[] = "Demonstrates adjoint sensitivity analysis for Reaction-Diffusion Equations.\n"; /* See ex5.c for details on the equation. This code demonestrates the TSAdjoint/TAO interface to solve an inverse initial value problem built on a system of time-dependent partial differential equations. In this problem, the initial value for the PDE is unknown, but the output (the final solution of the PDE) is known. We want to determine the initial value that can produce the given output. We formulate the problem as a nonlinear optimization problem that minimizes the discrepency between the simulated result and given reference solution, calculate the gradient of the objective function with the discrete adjoint solver, and solve the optimization problem with TAO. Runtime options: -forwardonly - run only the forward simulation -implicitform - provide IFunction and IJacobian to TS, if not set, RHSFunction and RHSJacobian will be used */ #include "reaction_diffusion.h" #include #include #include /* User-defined routines */ extern PetscErrorCode FormFunctionAndGradient(Tao,Vec,PetscReal*,Vec,void*); /* Set terminal condition for the adjoint variable */ PetscErrorCode InitializeLambda(DM da,Vec lambda,Vec U,AppCtx *appctx) { char filename[PETSC_MAX_PATH_LEN]=""; PetscViewer viewer; Vec Uob; PetscErrorCode ierr; PetscFunctionBegin; ierr = VecDuplicate(U,&Uob);CHKERRQ(ierr); ierr = PetscSNPrintf(filename,sizeof filename,"ex5opt.ob");CHKERRQ(ierr); ierr = PetscViewerBinaryOpen(PETSC_COMM_WORLD,filename,FILE_MODE_READ,&viewer);CHKERRQ(ierr); ierr = VecLoad(Uob,viewer);CHKERRQ(ierr); ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr); ierr = VecAYPX(Uob,-1.,U);CHKERRQ(ierr); ierr = VecScale(Uob,2.0);CHKERRQ(ierr); ierr = VecAXPY(lambda,1.,Uob);CHKERRQ(ierr); ierr = VecDestroy(&Uob);CHKERRQ(ierr); PetscFunctionReturn(0); } /* Set up a viewer that dumps data into a binary file */ PetscErrorCode OutputBIN(DM da, const char *filename, PetscViewer *viewer) { PetscErrorCode ierr; PetscFunctionBegin; ierr = PetscViewerCreate(PetscObjectComm((PetscObject)da),viewer);CHKERRQ(ierr); ierr = PetscViewerSetType(*viewer,PETSCVIEWERBINARY);CHKERRQ(ierr); ierr = PetscViewerFileSetMode(*viewer,FILE_MODE_WRITE);CHKERRQ(ierr); ierr = PetscViewerFileSetName(*viewer,filename);CHKERRQ(ierr); PetscFunctionReturn(0); } /* Generate a reference solution and save it to a binary file */ PetscErrorCode GenerateOBs(TS ts,Vec U,AppCtx *appctx) { char filename[PETSC_MAX_PATH_LEN] = ""; PetscViewer viewer; DM da; PetscErrorCode ierr; PetscFunctionBegin; ierr = TSGetDM(ts,&da);CHKERRQ(ierr); ierr = TSSolve(ts,U);CHKERRQ(ierr); ierr = PetscSNPrintf(filename,sizeof filename,"ex5opt.ob");CHKERRQ(ierr); ierr = OutputBIN(da,filename,&viewer);CHKERRQ(ierr); ierr = VecView(U,viewer);CHKERRQ(ierr); ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr); PetscFunctionReturn(0); } PetscErrorCode InitialConditions(DM da,Vec U) { PetscErrorCode ierr; PetscInt i,j,xs,ys,xm,ym,Mx,My; Field **u; PetscReal hx,hy,x,y; PetscFunctionBegin; 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); hx = 2.5/(PetscReal)Mx; hy = 2.5/(PetscReal)My; ierr = DMDAVecGetArray(da,U,&u);CHKERRQ(ierr); /* Get local grid boundaries */ ierr = DMDAGetCorners(da,&xs,&ys,NULL,&xm,&ym,NULL);CHKERRQ(ierr); /* Compute function over the locally owned part of the grid */ for (j=ys; jts,0.0);CHKERRQ(ierr); ierr = TSGetTimeStep(appctx->ts,×tep);CHKERRQ(ierr); if (timestep<0) { ierr = TSSetTimeStep(appctx->ts,-timestep);CHKERRQ(ierr); } ierr = TSSetStepNumber(appctx->ts,0);CHKERRQ(ierr); ierr = TSSetFromOptions(appctx->ts);CHKERRQ(ierr); ierr = VecDuplicate(P,&SDiff);CHKERRQ(ierr); ierr = VecCopy(P,appctx->U);CHKERRQ(ierr); ierr = TSGetDM(appctx->ts,&da);CHKERRQ(ierr); *f = 0; ierr = TSSolve(appctx->ts,appctx->U);CHKERRQ(ierr); ierr = PetscSNPrintf(filename,sizeof filename,"ex5opt.ob");CHKERRQ(ierr); ierr = PetscViewerBinaryOpen(PETSC_COMM_WORLD,filename,FILE_MODE_READ,&viewer);CHKERRQ(ierr); ierr = VecLoad(SDiff,viewer);CHKERRQ(ierr); ierr = PetscViewerDestroy(&viewer);CHKERRQ(ierr); ierr = VecAYPX(SDiff,-1.,appctx->U);CHKERRQ(ierr); ierr = VecDot(SDiff,SDiff,&soberr);CHKERRQ(ierr); *f += soberr; ierr = TSGetCostGradients(appctx->ts,NULL,&lambda,NULL);CHKERRQ(ierr); ierr = VecSet(lambda[0],0.0);CHKERRQ(ierr); ierr = InitializeLambda(da,lambda[0],appctx->U,appctx);CHKERRQ(ierr); ierr = TSAdjointSolve(appctx->ts);CHKERRQ(ierr); ierr = VecCopy(lambda[0],G);CHKERRQ(ierr); ierr = VecDestroy(&SDiff);CHKERRQ(ierr); PetscFunctionReturn(0); } /*TEST build: depends: reaction_diffusion.c requires: !complex !single test: args: -ts_max_steps 5 -ts_type rk -ts_rk_type 3 -ts_trajectory_type memory -tao_monitor -tao_view -tao_gatol 1e-6 output_file: output/ex5opt_ic_1.out TEST*/