xref: /petsc/src/ts/tutorials/ex23fwdadj.c (revision 5f80ce2ab25dff0f4601e710601cbbcecf323266)
182ad9101SHong Zhang static char help[] = "A toy example for testing forward and adjoint sensitivity analysis of an implicit ODE with a paramerized mass matrice.\n";
282ad9101SHong Zhang 
382ad9101SHong Zhang /*
482ad9101SHong Zhang   This example solves the simple ODE
582ad9101SHong Zhang     c x' = b x, x(0) = a,
682ad9101SHong Zhang   whose analytical solution is x(T)=a*exp(b/c*T), and calculates the derivative of x(T) w.r.t. c (by default) or w.r.t. b (can be enabled with command line option -der 2).
782ad9101SHong Zhang 
882ad9101SHong Zhang */
982ad9101SHong Zhang 
1082ad9101SHong Zhang #include <petscts.h>
1182ad9101SHong Zhang 
1282ad9101SHong Zhang typedef struct _n_User *User;
1382ad9101SHong Zhang struct _n_User {
1482ad9101SHong Zhang   PetscReal a;
1582ad9101SHong Zhang   PetscReal b;
1682ad9101SHong Zhang   PetscReal c;
1782ad9101SHong Zhang   /* Sensitivity analysis support */
1882ad9101SHong Zhang   PetscInt  steps;
1982ad9101SHong Zhang   PetscReal ftime;
2082ad9101SHong Zhang   Mat       Jac;                    /* Jacobian matrix */
2182ad9101SHong Zhang   Mat       Jacp;                   /* JacobianP matrix */
2282ad9101SHong Zhang   Vec       x;
2382ad9101SHong Zhang   Mat       sp;                     /* forward sensitivity variables */
2482ad9101SHong Zhang   Vec       lambda[1];              /* adjoint sensitivity variables */
2582ad9101SHong Zhang   Vec       mup[1];                 /* adjoint sensitivity variables */
2682ad9101SHong Zhang   PetscInt  der;
2782ad9101SHong Zhang };
2882ad9101SHong Zhang 
2982ad9101SHong Zhang static PetscErrorCode IFunction(TS ts,PetscReal t,Vec X,Vec Xdot,Vec F,void *ctx)
3082ad9101SHong Zhang {
3182ad9101SHong Zhang   User              user = (User)ctx;
3282ad9101SHong Zhang   const PetscScalar *x,*xdot;
3382ad9101SHong Zhang   PetscScalar       *f;
3482ad9101SHong Zhang 
3582ad9101SHong Zhang   PetscFunctionBeginUser;
36*5f80ce2aSJacob Faibussowitsch   CHKERRQ(VecGetArrayRead(X,&x));
37*5f80ce2aSJacob Faibussowitsch   CHKERRQ(VecGetArrayRead(Xdot,&xdot));
38*5f80ce2aSJacob Faibussowitsch   CHKERRQ(VecGetArrayWrite(F,&f));
3982ad9101SHong Zhang   f[0] = user->c*xdot[0] - user->b*x[0];
40*5f80ce2aSJacob Faibussowitsch   CHKERRQ(VecRestoreArrayRead(X,&x));
41*5f80ce2aSJacob Faibussowitsch   CHKERRQ(VecRestoreArrayRead(Xdot,&xdot));
42*5f80ce2aSJacob Faibussowitsch   CHKERRQ(VecRestoreArrayWrite(F,&f));
4382ad9101SHong Zhang   PetscFunctionReturn(0);
4482ad9101SHong Zhang }
4582ad9101SHong Zhang 
4682ad9101SHong Zhang static PetscErrorCode IJacobian(TS ts,PetscReal t,Vec X,Vec Xdot,PetscReal a,Mat A,Mat B,void *ctx)
4782ad9101SHong Zhang {
4882ad9101SHong Zhang   User              user     = (User)ctx;
4982ad9101SHong Zhang   PetscInt          rowcol[] = {0};
5082ad9101SHong Zhang   PetscScalar       J[1][1];
5182ad9101SHong Zhang   const PetscScalar *x;
5282ad9101SHong Zhang 
5382ad9101SHong Zhang   PetscFunctionBeginUser;
54*5f80ce2aSJacob Faibussowitsch   CHKERRQ(VecGetArrayRead(X,&x));
5582ad9101SHong Zhang   J[0][0] = user->c*a - user->b*1.0;
56*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatSetValues(B,1,rowcol,1,rowcol,&J[0][0],INSERT_VALUES));
57*5f80ce2aSJacob Faibussowitsch   CHKERRQ(VecRestoreArrayRead(X,&x));
5882ad9101SHong Zhang 
59*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY));
60*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY));
6182ad9101SHong Zhang   if (A != B) {
62*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatAssemblyBegin(B,MAT_FINAL_ASSEMBLY));
63*5f80ce2aSJacob Faibussowitsch     CHKERRQ(MatAssemblyEnd(B,MAT_FINAL_ASSEMBLY));
6482ad9101SHong Zhang   }
6582ad9101SHong Zhang   PetscFunctionReturn(0);
6682ad9101SHong Zhang }
6782ad9101SHong Zhang 
6882ad9101SHong Zhang static PetscErrorCode IJacobianP(TS ts,PetscReal t,Vec X,Vec Xdot,PetscReal shift,Mat A,void *ctx)
6982ad9101SHong Zhang {
7082ad9101SHong Zhang   User              user = (User)ctx;
7182ad9101SHong Zhang   PetscInt          row[] = {0},col[]={0};
7282ad9101SHong Zhang   PetscScalar       J[1][1];
7382ad9101SHong Zhang   const PetscScalar *x,*xdot;
7482ad9101SHong Zhang   PetscReal         dt;
7582ad9101SHong Zhang 
7682ad9101SHong Zhang   PetscFunctionBeginUser;
77*5f80ce2aSJacob Faibussowitsch   CHKERRQ(VecGetArrayRead(X,&x));
78*5f80ce2aSJacob Faibussowitsch   CHKERRQ(VecGetArrayRead(Xdot,&xdot));
79*5f80ce2aSJacob Faibussowitsch   CHKERRQ(TSGetTimeStep(ts,&dt));
8082ad9101SHong Zhang   if (user->der == 1) J[0][0] = xdot[0];
8182ad9101SHong Zhang   if (user->der == 2) J[0][0] = -x[0];
82*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatSetValues(A,1,row,1,col,&J[0][0],INSERT_VALUES));
83*5f80ce2aSJacob Faibussowitsch   CHKERRQ(VecRestoreArrayRead(X,&x));
8482ad9101SHong Zhang 
85*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY));
86*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY));
8782ad9101SHong Zhang   PetscFunctionReturn(0);
8882ad9101SHong Zhang }
8982ad9101SHong Zhang 
9082ad9101SHong Zhang int main(int argc,char **argv)
9182ad9101SHong Zhang {
9282ad9101SHong Zhang   TS             ts;
9382ad9101SHong Zhang   PetscScalar    *x_ptr;
9482ad9101SHong Zhang   PetscMPIInt    size;
9582ad9101SHong Zhang   struct _n_User user;
9682ad9101SHong Zhang   PetscInt       rows,cols;
9782ad9101SHong Zhang   PetscErrorCode ierr;
9882ad9101SHong Zhang 
9982ad9101SHong Zhang   ierr = PetscInitialize(&argc,&argv,NULL,help);if (ierr) return ierr;
10082ad9101SHong Zhang 
101*5f80ce2aSJacob Faibussowitsch   CHKERRMPI(MPI_Comm_size(PETSC_COMM_WORLD,&size));
1023c633725SBarry Smith   PetscCheck(size == 1,PETSC_COMM_WORLD,PETSC_ERR_WRONG_MPI_SIZE,"This is a uniprocessor example only!");
10382ad9101SHong Zhang 
10482ad9101SHong Zhang   user.a           = 2.0;
10582ad9101SHong Zhang   user.b           = 4.0;
10682ad9101SHong Zhang   user.c           = 3.0;
10782ad9101SHong Zhang   user.steps       = 0;
10882ad9101SHong Zhang   user.ftime       = 1.0;
10982ad9101SHong Zhang   user.der         = 1;
110*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscOptionsGetInt(NULL,NULL,"-der",&user.der,NULL));
11182ad9101SHong Zhang 
11282ad9101SHong Zhang   rows = 1;
11382ad9101SHong Zhang   cols = 1;
114*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatCreate(PETSC_COMM_WORLD,&user.Jac));
115*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatSetSizes(user.Jac,PETSC_DECIDE,PETSC_DECIDE,1,1));
116*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatSetFromOptions(user.Jac));
117*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatSetUp(user.Jac));
118*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatCreateVecs(user.Jac,&user.x,NULL));
11982ad9101SHong Zhang 
120*5f80ce2aSJacob Faibussowitsch   CHKERRQ(TSCreate(PETSC_COMM_WORLD,&ts));
121*5f80ce2aSJacob Faibussowitsch   CHKERRQ(TSSetType(ts,TSBEULER));
122*5f80ce2aSJacob Faibussowitsch   CHKERRQ(TSSetIFunction(ts,NULL,IFunction,&user));
123*5f80ce2aSJacob Faibussowitsch   CHKERRQ(TSSetIJacobian(ts,user.Jac,user.Jac,IJacobian,&user));
124*5f80ce2aSJacob Faibussowitsch   CHKERRQ(TSSetExactFinalTime(ts,TS_EXACTFINALTIME_MATCHSTEP));
125*5f80ce2aSJacob Faibussowitsch   CHKERRQ(TSSetMaxTime(ts,user.ftime));
12682ad9101SHong Zhang 
127*5f80ce2aSJacob Faibussowitsch   CHKERRQ(VecGetArrayWrite(user.x,&x_ptr));
12882ad9101SHong Zhang   x_ptr[0] = user.a;
129*5f80ce2aSJacob Faibussowitsch   CHKERRQ(VecRestoreArrayWrite(user.x,&x_ptr));
130*5f80ce2aSJacob Faibussowitsch   CHKERRQ(TSSetTimeStep(ts,0.001));
13182ad9101SHong Zhang 
13282ad9101SHong Zhang   /* Set up forward sensitivity */
133*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatCreate(PETSC_COMM_WORLD,&user.Jacp));
134*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatSetSizes(user.Jacp,PETSC_DECIDE,PETSC_DECIDE,rows,cols));
135*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatSetFromOptions(user.Jacp));
136*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatSetUp(user.Jacp));
137*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatCreateDense(PETSC_COMM_WORLD,PETSC_DECIDE,PETSC_DECIDE,rows,cols,NULL,&user.sp));
138*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatZeroEntries(user.sp));
139*5f80ce2aSJacob Faibussowitsch   CHKERRQ(TSForwardSetSensitivities(ts,cols,user.sp));
140*5f80ce2aSJacob Faibussowitsch   CHKERRQ(TSSetIJacobianP(ts,user.Jacp,IJacobianP,&user));
14182ad9101SHong Zhang 
142*5f80ce2aSJacob Faibussowitsch   CHKERRQ(TSSetSaveTrajectory(ts));
143*5f80ce2aSJacob Faibussowitsch   CHKERRQ(TSSetFromOptions(ts));
14482ad9101SHong Zhang 
145*5f80ce2aSJacob Faibussowitsch   CHKERRQ(TSSolve(ts,user.x));
146*5f80ce2aSJacob Faibussowitsch   CHKERRQ(TSGetSolveTime(ts,&user.ftime));
147*5f80ce2aSJacob Faibussowitsch   CHKERRQ(TSGetStepNumber(ts,&user.steps));
148*5f80ce2aSJacob Faibussowitsch   CHKERRQ(VecGetArray(user.x,&x_ptr));
149*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscPrintf(PETSC_COMM_WORLD,"\n ode solution %g\n",(double)PetscRealPart(x_ptr[0])));
150*5f80ce2aSJacob Faibussowitsch   CHKERRQ(VecRestoreArray(user.x,&x_ptr));
151*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscPrintf(PETSC_COMM_WORLD,"\n analytical solution %g\n",(double)user.a*PetscExpReal(user.b/user.c*user.ftime)));
15282ad9101SHong Zhang 
15382ad9101SHong Zhang   if (user.der == 1) {
154*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscPrintf(PETSC_COMM_WORLD,"\n analytical derivative w.r.t. c %g\n",(double)-user.a*user.ftime*user.b/(user.c*user.c)*PetscExpReal(user.b/user.c*user.ftime)));
15582ad9101SHong Zhang   }
15682ad9101SHong Zhang   if (user.der == 2) {
157*5f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscPrintf(PETSC_COMM_WORLD,"\n analytical derivative w.r.t. b %g\n",user.a*user.ftime/user.c*PetscExpReal(user.b/user.c*user.ftime)));
15882ad9101SHong Zhang   }
159*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscPrintf(PETSC_COMM_WORLD,"\n forward sensitivity:\n"));
160*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatView(user.sp,PETSC_VIEWER_STDOUT_WORLD));
16182ad9101SHong Zhang 
162*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatCreateVecs(user.Jac,&user.lambda[0],NULL));
16382ad9101SHong Zhang   /* Set initial conditions for the adjoint integration */
164*5f80ce2aSJacob Faibussowitsch   CHKERRQ(VecGetArrayWrite(user.lambda[0],&x_ptr));
16582ad9101SHong Zhang   x_ptr[0] = 1.0;
166*5f80ce2aSJacob Faibussowitsch   CHKERRQ(VecRestoreArrayWrite(user.lambda[0],&x_ptr));
167*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatCreateVecs(user.Jacp,&user.mup[0],NULL));
168*5f80ce2aSJacob Faibussowitsch   CHKERRQ(VecGetArrayWrite(user.mup[0],&x_ptr));
16982ad9101SHong Zhang   x_ptr[0] = 0.0;
170*5f80ce2aSJacob Faibussowitsch   CHKERRQ(VecRestoreArrayWrite(user.mup[0],&x_ptr));
17182ad9101SHong Zhang 
172*5f80ce2aSJacob Faibussowitsch   CHKERRQ(TSSetCostGradients(ts,1,user.lambda,user.mup));
173*5f80ce2aSJacob Faibussowitsch   CHKERRQ(TSAdjointSolve(ts));
17482ad9101SHong Zhang 
175*5f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscPrintf(PETSC_COMM_WORLD,"\n adjoint sensitivity:\n"));
176*5f80ce2aSJacob Faibussowitsch   CHKERRQ(VecView(user.mup[0],PETSC_VIEWER_STDOUT_WORLD));
17782ad9101SHong Zhang 
178*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatDestroy(&user.Jac));
179*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatDestroy(&user.sp));
180*5f80ce2aSJacob Faibussowitsch   CHKERRQ(MatDestroy(&user.Jacp));
181*5f80ce2aSJacob Faibussowitsch   CHKERRQ(VecDestroy(&user.x));
182*5f80ce2aSJacob Faibussowitsch   CHKERRQ(VecDestroy(&user.lambda[0]));
183*5f80ce2aSJacob Faibussowitsch   CHKERRQ(VecDestroy(&user.mup[0]));
184*5f80ce2aSJacob Faibussowitsch   CHKERRQ(TSDestroy(&ts));
18582ad9101SHong Zhang 
18682ad9101SHong Zhang   ierr = PetscFinalize();
18782ad9101SHong Zhang   return(ierr);
18882ad9101SHong Zhang }
18982ad9101SHong Zhang 
19082ad9101SHong Zhang /*TEST
19182ad9101SHong Zhang 
19282ad9101SHong Zhang     test:
19382ad9101SHong Zhang       args: -ts_type beuler
19482ad9101SHong Zhang 
19582ad9101SHong Zhang     test:
19682ad9101SHong Zhang       suffix: 2
19782ad9101SHong Zhang       args: -ts_type cn
19882ad9101SHong Zhang       output_file: output/ex23fwdadj_1.out
19982ad9101SHong Zhang 
20082ad9101SHong Zhang TEST*/
201