xref: /petsc/src/ts/tutorials/ex20td.c (revision 4e8208cbcbc709572b8abe32f33c78b69c819375)
180f8ae99SSajid Ali static char help[] = "Performs adjoint sensitivity analysis for a van der Pol like \n\
280f8ae99SSajid Ali equation with time dependent parameters using two approaches :  \n\
380f8ae99SSajid Ali track  : track only local sensitivities at each adjoint step \n\
480f8ae99SSajid Ali          and accumulate them in a global array \n\
580f8ae99SSajid Ali global : track parameters at all timesteps together \n\
680f8ae99SSajid Ali Choose one of the two at runtime by -sa_method {track,global}. \n";
780f8ae99SSajid Ali 
880f8ae99SSajid Ali /*
980f8ae99SSajid Ali    Simple example to demonstrate TSAdjoint capabilities for time dependent params
1080f8ae99SSajid Ali    without integral cost terms using either a tracking or global method.
1180f8ae99SSajid Ali 
1280f8ae99SSajid Ali    Modify the Van Der Pol Eq to :
1380f8ae99SSajid Ali    [u1'] = [mu1(t)*u1]
1480f8ae99SSajid Ali    [u2'] = [mu2(t)*((1-u1^2)*u2-u1)]
1580f8ae99SSajid Ali    (with initial conditions & params independent)
1680f8ae99SSajid Ali 
17da81f932SPierre Jolivet    Define uref to be solution with initial conditions (2,-2/3), mu=(1,1e3)
1880f8ae99SSajid Ali    - u_ref : (1.5967,-1.02969)
1980f8ae99SSajid Ali 
2080f8ae99SSajid Ali    Define const function as cost = 2-norm(u - u_ref);
2180f8ae99SSajid Ali 
2280f8ae99SSajid Ali    Initialization for the adjoint TS :
2380f8ae99SSajid Ali    - dcost/dy|final_time = 2*(u-u_ref)|final_time
2480f8ae99SSajid Ali    - dcost/dp|final_time = 0
2580f8ae99SSajid Ali 
2680f8ae99SSajid Ali    The tracking method only tracks local sensitivity at each time step
2780f8ae99SSajid Ali    and accumulates these sensitivities in a global array. Since the structure
2880f8ae99SSajid Ali    of the equations being solved at each time step does not change, the jacobian
2980f8ae99SSajid Ali    wrt parameters is defined analogous to constant RHSJacobian for a liner
3080f8ae99SSajid Ali    TSSolve and the size of the jacP is independent of the number of time
3180f8ae99SSajid Ali    steps. Enable this mode of adjoint analysis by -sa_method track.
3280f8ae99SSajid Ali 
3380f8ae99SSajid Ali    The global method combines the parameters at all timesteps and tracks them
3480f8ae99SSajid Ali    together. Thus, the columns of the jacP matrix are filled dependent upon the
3580f8ae99SSajid Ali    time step. Also, the dimensions of the jacP matrix now depend upon the number
3680f8ae99SSajid Ali    of time steps. Enable this mode of adjoint analysis by -sa_method global.
3780f8ae99SSajid Ali 
3880f8ae99SSajid Ali    Since the equations here have parameters at predefined time steps, this
3980f8ae99SSajid Ali    example should be run with non adaptive time stepping solvers only. This
4080f8ae99SSajid Ali    can be ensured by -ts_adapt_type none (which is the default behavior only
4180f8ae99SSajid Ali    for certain TS solvers like TSCN. If using an explicit TS like TSRK,
4280f8ae99SSajid Ali    please be sure to add the aforementioned option to disable adaptive
4380f8ae99SSajid Ali    timestepping.)
4480f8ae99SSajid Ali */
4580f8ae99SSajid Ali 
4680f8ae99SSajid Ali /*
4780f8ae99SSajid Ali    Include "petscts.h" so that we can use TS solvers.  Note that this file
4880f8ae99SSajid Ali    automatically includes:
4980f8ae99SSajid Ali      petscsys.h    - base PETSc routines   petscvec.h  - vectors
5080f8ae99SSajid Ali      petscmat.h    - matrices
5180f8ae99SSajid Ali      petscis.h     - index sets            petscksp.h  - Krylov subspace methods
5280f8ae99SSajid Ali      petscviewer.h - viewers               petscpc.h   - preconditioners
5380f8ae99SSajid Ali      petscksp.h    - linear solvers        petscsnes.h - nonlinear solvers
5480f8ae99SSajid Ali */
5580f8ae99SSajid Ali #include <petscts.h>
5680f8ae99SSajid Ali 
5780f8ae99SSajid Ali extern PetscErrorCode RHSFunction(TS, PetscReal, Vec, Vec, void *);
5880f8ae99SSajid Ali extern PetscErrorCode RHSJacobian(TS, PetscReal, Vec, Mat, Mat, void *);
5980f8ae99SSajid Ali extern PetscErrorCode RHSJacobianP_track(TS, PetscReal, Vec, Mat, void *);
6080f8ae99SSajid Ali extern PetscErrorCode RHSJacobianP_global(TS, PetscReal, Vec, Mat, void *);
6180f8ae99SSajid Ali extern PetscErrorCode Monitor(TS, PetscInt, PetscReal, Vec, void *);
6280f8ae99SSajid Ali extern PetscErrorCode AdjointMonitor(TS, PetscInt, PetscReal, Vec, PetscInt, Vec *, Vec *, void *);
6380f8ae99SSajid Ali 
6480f8ae99SSajid Ali /*
6580f8ae99SSajid Ali    User-defined application context - contains data needed by the
6680f8ae99SSajid Ali    application-provided call-back routines.
6780f8ae99SSajid Ali */
6880f8ae99SSajid Ali 
6980f8ae99SSajid Ali typedef struct {
7080f8ae99SSajid Ali   /*------------- Forward solve data structures --------------*/
7180f8ae99SSajid Ali   PetscInt  max_steps;  /* number of steps to run ts for */
7280f8ae99SSajid Ali   PetscReal final_time; /* final time to integrate to*/
7380f8ae99SSajid Ali   PetscReal time_step;  /* ts integration time step */
7480f8ae99SSajid Ali   Vec       mu1;        /* time dependent params */
7580f8ae99SSajid Ali   Vec       mu2;        /* time dependent params */
7680f8ae99SSajid Ali   Vec       U;          /* solution vector */
7780f8ae99SSajid Ali   Mat       A;          /* Jacobian matrix */
7880f8ae99SSajid Ali 
7980f8ae99SSajid Ali   /*------------- Adjoint solve data structures --------------*/
8080f8ae99SSajid Ali   Mat Jacp;   /* JacobianP matrix */
8180f8ae99SSajid Ali   Vec lambda; /* adjoint variable */
8280f8ae99SSajid Ali   Vec mup;    /* adjoint variable */
8380f8ae99SSajid Ali 
8480f8ae99SSajid Ali   /*------------- Global accumation vecs for monitor based tracking --------------*/
8580f8ae99SSajid Ali   Vec      sens_mu1; /* global sensitivity accumulation */
8680f8ae99SSajid Ali   Vec      sens_mu2; /* global sensitivity accumulation */
8780f8ae99SSajid Ali   PetscInt adj_idx;  /* to keep track of adjoint solve index */
8880f8ae99SSajid Ali } AppCtx;
8980f8ae99SSajid Ali 
909371c9d4SSatish Balay typedef enum {
919371c9d4SSatish Balay   SA_TRACK,
929371c9d4SSatish Balay   SA_GLOBAL
939371c9d4SSatish Balay } SAMethod;
9480f8ae99SSajid Ali static const char *const SAMethods[] = {"TRACK", "GLOBAL", "SAMethod", "SA_", 0};
9580f8ae99SSajid Ali 
9680f8ae99SSajid Ali /* ----------------------- Explicit form of the ODE  -------------------- */
9780f8ae99SSajid Ali 
RHSFunction(TS ts,PetscReal t,Vec U,Vec F,PetscCtx ctx)98*2a8381b2SBarry Smith PetscErrorCode RHSFunction(TS ts, PetscReal t, Vec U, Vec F, PetscCtx ctx)
99d71ae5a4SJacob Faibussowitsch {
10080f8ae99SSajid Ali   AppCtx            *user = (AppCtx *)ctx;
10180f8ae99SSajid Ali   PetscScalar       *f;
10280f8ae99SSajid Ali   PetscInt           curr_step;
10380f8ae99SSajid Ali   const PetscScalar *u;
10480f8ae99SSajid Ali   const PetscScalar *mu1;
10580f8ae99SSajid Ali   const PetscScalar *mu2;
10680f8ae99SSajid Ali 
10780f8ae99SSajid Ali   PetscFunctionBeginUser;
1089566063dSJacob Faibussowitsch   PetscCall(TSGetStepNumber(ts, &curr_step));
1099566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(U, &u));
1109566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(user->mu1, &mu1));
1119566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(user->mu2, &mu2));
1129566063dSJacob Faibussowitsch   PetscCall(VecGetArray(F, &f));
11380f8ae99SSajid Ali   f[0] = mu1[curr_step] * u[1];
11480f8ae99SSajid Ali   f[1] = mu2[curr_step] * ((1. - u[0] * u[0]) * u[1] - u[0]);
1159566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(U, &u));
1169566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(user->mu1, &mu1));
1179566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(user->mu2, &mu2));
1189566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(F, &f));
1193ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
12080f8ae99SSajid Ali }
12180f8ae99SSajid Ali 
RHSJacobian(TS ts,PetscReal t,Vec U,Mat A,Mat B,PetscCtx ctx)122*2a8381b2SBarry Smith PetscErrorCode RHSJacobian(TS ts, PetscReal t, Vec U, Mat A, Mat B, PetscCtx ctx)
123d71ae5a4SJacob Faibussowitsch {
12480f8ae99SSajid Ali   AppCtx            *user     = (AppCtx *)ctx;
12580f8ae99SSajid Ali   PetscInt           rowcol[] = {0, 1};
12680f8ae99SSajid Ali   PetscScalar        J[2][2];
12780f8ae99SSajid Ali   PetscInt           curr_step;
12880f8ae99SSajid Ali   const PetscScalar *u;
12980f8ae99SSajid Ali   const PetscScalar *mu1;
13080f8ae99SSajid Ali   const PetscScalar *mu2;
13180f8ae99SSajid Ali 
13280f8ae99SSajid Ali   PetscFunctionBeginUser;
1339566063dSJacob Faibussowitsch   PetscCall(TSGetStepNumber(ts, &curr_step));
1349566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(user->mu1, &mu1));
1359566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(user->mu2, &mu2));
1369566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(U, &u));
13780f8ae99SSajid Ali   J[0][0] = 0;
13880f8ae99SSajid Ali   J[1][0] = -mu2[curr_step] * (2.0 * u[1] * u[0] + 1.);
13980f8ae99SSajid Ali   J[0][1] = mu1[curr_step];
14080f8ae99SSajid Ali   J[1][1] = mu2[curr_step] * (1.0 - u[0] * u[0]);
1419566063dSJacob Faibussowitsch   PetscCall(MatSetValues(A, 2, rowcol, 2, rowcol, &J[0][0], INSERT_VALUES));
1429566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
1439566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
1449566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(U, &u));
1459566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(user->mu1, &mu1));
1469566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(user->mu2, &mu2));
1473ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
14880f8ae99SSajid Ali }
14980f8ae99SSajid Ali 
15080f8ae99SSajid Ali /* ------------------ Jacobian wrt parameters for tracking method ------------------ */
15180f8ae99SSajid Ali 
RHSJacobianP_track(TS ts,PetscReal t,Vec U,Mat A,PetscCtx ctx)152*2a8381b2SBarry Smith PetscErrorCode RHSJacobianP_track(TS ts, PetscReal t, Vec U, Mat A, PetscCtx ctx)
153d71ae5a4SJacob Faibussowitsch {
15480f8ae99SSajid Ali   PetscInt           row[] = {0, 1}, col[] = {0, 1};
15580f8ae99SSajid Ali   PetscScalar        J[2][2];
15680f8ae99SSajid Ali   const PetscScalar *u;
15780f8ae99SSajid Ali 
15880f8ae99SSajid Ali   PetscFunctionBeginUser;
1599566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(U, &u));
16080f8ae99SSajid Ali   J[0][0] = u[1];
16180f8ae99SSajid Ali   J[1][0] = 0;
16280f8ae99SSajid Ali   J[0][1] = 0;
16380f8ae99SSajid Ali   J[1][1] = (1. - u[0] * u[0]) * u[1] - u[0];
1649566063dSJacob Faibussowitsch   PetscCall(MatSetValues(A, 2, row, 2, col, &J[0][0], INSERT_VALUES));
1659566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
1669566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
1679566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(U, &u));
1683ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
16980f8ae99SSajid Ali }
17080f8ae99SSajid Ali 
17180f8ae99SSajid Ali /* ------------------ Jacobian wrt parameters for global method ------------------ */
17280f8ae99SSajid Ali 
RHSJacobianP_global(TS ts,PetscReal t,Vec U,Mat A,PetscCtx ctx)173*2a8381b2SBarry Smith PetscErrorCode RHSJacobianP_global(TS ts, PetscReal t, Vec U, Mat A, PetscCtx ctx)
174d71ae5a4SJacob Faibussowitsch {
17580f8ae99SSajid Ali   PetscInt           row[] = {0, 1}, col[] = {0, 1};
17680f8ae99SSajid Ali   PetscScalar        J[2][2];
17780f8ae99SSajid Ali   const PetscScalar *u;
17880f8ae99SSajid Ali   PetscInt           curr_step;
17980f8ae99SSajid Ali 
18080f8ae99SSajid Ali   PetscFunctionBeginUser;
1819566063dSJacob Faibussowitsch   PetscCall(TSGetStepNumber(ts, &curr_step));
1829566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(U, &u));
18380f8ae99SSajid Ali   J[0][0] = u[1];
18480f8ae99SSajid Ali   J[1][0] = 0;
18580f8ae99SSajid Ali   J[0][1] = 0;
18680f8ae99SSajid Ali   J[1][1] = (1. - u[0] * u[0]) * u[1] - u[0];
1874ad8454bSPierre Jolivet   col[0]  = curr_step * 2;
1884ad8454bSPierre Jolivet   col[1]  = curr_step * 2 + 1;
1899566063dSJacob Faibussowitsch   PetscCall(MatSetValues(A, 2, row, 2, col, &J[0][0], INSERT_VALUES));
1909566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(A, MAT_FINAL_ASSEMBLY));
1919566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(A, MAT_FINAL_ASSEMBLY));
1929566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(U, &u));
1933ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
19480f8ae99SSajid Ali }
19580f8ae99SSajid Ali 
19680f8ae99SSajid Ali /* Dump solution to console if called */
Monitor(TS ts,PetscInt step,PetscReal t,Vec U,PetscCtx ctx)197*2a8381b2SBarry Smith PetscErrorCode Monitor(TS ts, PetscInt step, PetscReal t, Vec U, PetscCtx ctx)
198d71ae5a4SJacob Faibussowitsch {
19980f8ae99SSajid Ali   PetscFunctionBeginUser;
20063a3b9bcSJacob Faibussowitsch   PetscCall(PetscPrintf(PETSC_COMM_WORLD, "\n Solution at time %e is \n", (double)t));
2019566063dSJacob Faibussowitsch   PetscCall(VecView(U, PETSC_VIEWER_STDOUT_WORLD));
2023ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
20380f8ae99SSajid Ali }
20480f8ae99SSajid Ali 
20580f8ae99SSajid Ali /* Customized adjoint monitor to keep track of local
20680f8ae99SSajid Ali    sensitivities by storing them in a global sensitivity array.
20780f8ae99SSajid Ali    Note : This routine is only used for the tracking method. */
AdjointMonitor(TS ts,PetscInt steps,PetscReal time,Vec u,PetscInt numcost,Vec * lambda,Vec * mu,PetscCtx ctx)208*2a8381b2SBarry Smith PetscErrorCode AdjointMonitor(TS ts, PetscInt steps, PetscReal time, Vec u, PetscInt numcost, Vec *lambda, Vec *mu, PetscCtx ctx)
209d71ae5a4SJacob Faibussowitsch {
21080f8ae99SSajid Ali   AppCtx            *user = (AppCtx *)ctx;
21180f8ae99SSajid Ali   PetscInt           curr_step;
21280f8ae99SSajid Ali   PetscScalar       *sensmu1_glob;
21380f8ae99SSajid Ali   PetscScalar       *sensmu2_glob;
21480f8ae99SSajid Ali   const PetscScalar *sensmu_loc;
21580f8ae99SSajid Ali 
21680f8ae99SSajid Ali   PetscFunctionBeginUser;
2179566063dSJacob Faibussowitsch   PetscCall(TSGetStepNumber(ts, &curr_step));
21880f8ae99SSajid Ali   /* Note that we skip the first call to the monitor in the adjoint
21980f8ae99SSajid Ali      solve since the sensitivities are already set (during
22080f8ae99SSajid Ali      initialization of adjoint vectors).
22180f8ae99SSajid Ali      We also note that each indvidial TSAdjointSolve calls the monitor
22280f8ae99SSajid Ali      twice, once at the step it is integrating from and once at the step
22380f8ae99SSajid Ali      it integrates to. Only the second call is useful for transferring
22480f8ae99SSajid Ali      local sensitivities to the global array. */
22580f8ae99SSajid Ali   if (curr_step == user->adj_idx) {
2263ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
22780f8ae99SSajid Ali   } else {
2289566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(*mu, &sensmu_loc));
2299566063dSJacob Faibussowitsch     PetscCall(VecGetArray(user->sens_mu1, &sensmu1_glob));
2309566063dSJacob Faibussowitsch     PetscCall(VecGetArray(user->sens_mu2, &sensmu2_glob));
23180f8ae99SSajid Ali     sensmu1_glob[curr_step] = sensmu_loc[0];
23280f8ae99SSajid Ali     sensmu2_glob[curr_step] = sensmu_loc[1];
2339566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(user->sens_mu1, &sensmu1_glob));
2349566063dSJacob Faibussowitsch     PetscCall(VecRestoreArray(user->sens_mu2, &sensmu2_glob));
2359566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(*mu, &sensmu_loc));
2363ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
23780f8ae99SSajid Ali   }
23880f8ae99SSajid Ali }
23980f8ae99SSajid Ali 
main(int argc,char ** argv)240d71ae5a4SJacob Faibussowitsch int main(int argc, char **argv)
241d71ae5a4SJacob Faibussowitsch {
24280f8ae99SSajid Ali   TS           ts;
24380f8ae99SSajid Ali   AppCtx       user;
24480f8ae99SSajid Ali   PetscScalar *x_ptr, *y_ptr, *u_ptr;
24580f8ae99SSajid Ali   PetscMPIInt  size;
24680f8ae99SSajid Ali   PetscBool    monitor = PETSC_FALSE;
24780f8ae99SSajid Ali   SAMethod     sa      = SA_GLOBAL;
24880f8ae99SSajid Ali 
24980f8ae99SSajid Ali   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
25080f8ae99SSajid Ali      Initialize program
25180f8ae99SSajid Ali      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
252327415f7SBarry Smith   PetscFunctionBeginUser;
2539566063dSJacob Faibussowitsch   PetscCall(PetscInitialize(&argc, &argv, NULL, help));
2549566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PETSC_COMM_WORLD, &size));
2553c633725SBarry Smith   PetscCheck(size == 1, PETSC_COMM_WORLD, PETSC_ERR_WRONG_MPI_SIZE, "This is a uniprocessor example only!");
25680f8ae99SSajid Ali 
25780f8ae99SSajid Ali   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
25880f8ae99SSajid Ali      Set runtime options
25980f8ae99SSajid Ali      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2609371c9d4SSatish Balay   PetscOptionsBegin(PETSC_COMM_WORLD, NULL, "SA analysis options.", "");
2619371c9d4SSatish Balay   {
2629566063dSJacob Faibussowitsch     PetscCall(PetscOptionsGetBool(NULL, NULL, "-monitor", &monitor, NULL));
2639566063dSJacob Faibussowitsch     PetscCall(PetscOptionsEnum("-sa_method", "Sensitivity analysis method (track or global)", "", SAMethods, (PetscEnum)sa, (PetscEnum *)&sa, NULL));
26480f8ae99SSajid Ali   }
265d0609cedSBarry Smith   PetscOptionsEnd();
26680f8ae99SSajid Ali 
26780f8ae99SSajid Ali   user.final_time = 0.1;
26880f8ae99SSajid Ali   user.max_steps  = 5;
26980f8ae99SSajid Ali   user.time_step  = user.final_time / user.max_steps;
27080f8ae99SSajid Ali 
27180f8ae99SSajid Ali   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
27280f8ae99SSajid Ali      Create necessary matrix and vectors for forward solve.
27380f8ae99SSajid Ali      Create Jacp matrix for adjoint solve.
27480f8ae99SSajid Ali      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2759566063dSJacob Faibussowitsch   PetscCall(VecCreateSeq(PETSC_COMM_WORLD, user.max_steps, &user.mu1));
2769566063dSJacob Faibussowitsch   PetscCall(VecCreateSeq(PETSC_COMM_WORLD, user.max_steps, &user.mu2));
2779566063dSJacob Faibussowitsch   PetscCall(VecSet(user.mu1, 1.25));
2789566063dSJacob Faibussowitsch   PetscCall(VecSet(user.mu2, 1.0e2));
27980f8ae99SSajid Ali 
28080f8ae99SSajid Ali   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
28180f8ae99SSajid Ali       For tracking method : create the global sensitivity array to
28280f8ae99SSajid Ali       accumulate sensitivity with respect to parameters at each step.
28380f8ae99SSajid Ali      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
28480f8ae99SSajid Ali   if (sa == SA_TRACK) {
2859566063dSJacob Faibussowitsch     PetscCall(VecCreateSeq(PETSC_COMM_WORLD, user.max_steps, &user.sens_mu1));
2869566063dSJacob Faibussowitsch     PetscCall(VecCreateSeq(PETSC_COMM_WORLD, user.max_steps, &user.sens_mu2));
28780f8ae99SSajid Ali   }
28880f8ae99SSajid Ali 
2899566063dSJacob Faibussowitsch   PetscCall(MatCreate(PETSC_COMM_WORLD, &user.A));
2909566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(user.A, PETSC_DECIDE, PETSC_DECIDE, 2, 2));
2919566063dSJacob Faibussowitsch   PetscCall(MatSetFromOptions(user.A));
2929566063dSJacob Faibussowitsch   PetscCall(MatSetUp(user.A));
2939566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(user.A, &user.U, NULL));
29480f8ae99SSajid Ali 
29580f8ae99SSajid Ali   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
29680f8ae99SSajid Ali       Note that the dimensions of the Jacp matrix depend upon the
29780f8ae99SSajid Ali       sensitivity analysis method being used !
29880f8ae99SSajid Ali      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
2999566063dSJacob Faibussowitsch   PetscCall(MatCreate(PETSC_COMM_WORLD, &user.Jacp));
30048a46eb9SPierre Jolivet   if (sa == SA_TRACK) PetscCall(MatSetSizes(user.Jacp, PETSC_DECIDE, PETSC_DECIDE, 2, 2));
30148a46eb9SPierre Jolivet   if (sa == SA_GLOBAL) PetscCall(MatSetSizes(user.Jacp, PETSC_DECIDE, PETSC_DECIDE, 2, user.max_steps * 2));
3029566063dSJacob Faibussowitsch   PetscCall(MatSetFromOptions(user.Jacp));
3039566063dSJacob Faibussowitsch   PetscCall(MatSetUp(user.Jacp));
30480f8ae99SSajid Ali 
30580f8ae99SSajid Ali   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
30680f8ae99SSajid Ali      Create timestepping solver context
30780f8ae99SSajid Ali      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
3089566063dSJacob Faibussowitsch   PetscCall(TSCreate(PETSC_COMM_WORLD, &ts));
3099566063dSJacob Faibussowitsch   PetscCall(TSSetEquationType(ts, TS_EQ_ODE_EXPLICIT));
3109566063dSJacob Faibussowitsch   PetscCall(TSSetType(ts, TSCN));
31180f8ae99SSajid Ali 
3129566063dSJacob Faibussowitsch   PetscCall(TSSetRHSFunction(ts, NULL, RHSFunction, &user));
3139566063dSJacob Faibussowitsch   PetscCall(TSSetRHSJacobian(ts, user.A, user.A, RHSJacobian, &user));
31448a46eb9SPierre Jolivet   if (sa == SA_TRACK) PetscCall(TSSetRHSJacobianP(ts, user.Jacp, RHSJacobianP_track, &user));
31548a46eb9SPierre Jolivet   if (sa == SA_GLOBAL) PetscCall(TSSetRHSJacobianP(ts, user.Jacp, RHSJacobianP_global, &user));
31680f8ae99SSajid Ali 
3179566063dSJacob Faibussowitsch   PetscCall(TSSetExactFinalTime(ts, TS_EXACTFINALTIME_MATCHSTEP));
3189566063dSJacob Faibussowitsch   PetscCall(TSSetMaxTime(ts, user.final_time));
3199566063dSJacob Faibussowitsch   PetscCall(TSSetTimeStep(ts, user.final_time / user.max_steps));
32080f8ae99SSajid Ali 
32148a46eb9SPierre Jolivet   if (monitor) PetscCall(TSMonitorSet(ts, Monitor, &user, NULL));
32248a46eb9SPierre Jolivet   if (sa == SA_TRACK) PetscCall(TSAdjointMonitorSet(ts, AdjointMonitor, &user, NULL));
32380f8ae99SSajid Ali 
32480f8ae99SSajid Ali   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
32580f8ae99SSajid Ali      Set initial conditions
32680f8ae99SSajid Ali      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
3279566063dSJacob Faibussowitsch   PetscCall(VecGetArray(user.U, &x_ptr));
32880f8ae99SSajid Ali   x_ptr[0] = 2.0;
32980f8ae99SSajid Ali   x_ptr[1] = -2.0 / 3.0;
3309566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(user.U, &x_ptr));
33180f8ae99SSajid Ali 
33280f8ae99SSajid Ali   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
33380f8ae99SSajid Ali      Save trajectory of solution so that TSAdjointSolve() may be used
33480f8ae99SSajid Ali      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
3359566063dSJacob Faibussowitsch   PetscCall(TSSetSaveTrajectory(ts));
33680f8ae99SSajid Ali 
33780f8ae99SSajid Ali   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
33880f8ae99SSajid Ali      Set runtime options
33980f8ae99SSajid Ali      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
3409566063dSJacob Faibussowitsch   PetscCall(TSSetFromOptions(ts));
34180f8ae99SSajid Ali 
34280f8ae99SSajid Ali   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
34380f8ae99SSajid Ali      Execute forward model and print solution.
34480f8ae99SSajid Ali      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
3459566063dSJacob Faibussowitsch   PetscCall(TSSolve(ts, user.U));
3469566063dSJacob Faibussowitsch   PetscCall(PetscPrintf(PETSC_COMM_WORLD, "\n Solution of forward TS :\n"));
3479566063dSJacob Faibussowitsch   PetscCall(VecView(user.U, PETSC_VIEWER_STDOUT_WORLD));
3486aad120cSJose E. Roman   PetscCall(PetscPrintf(PETSC_COMM_WORLD, "\n Forward TS solve successful! Adjoint run begins!\n"));
34980f8ae99SSajid Ali 
35080f8ae99SSajid Ali   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
35180f8ae99SSajid Ali      Adjoint model starts here! Create adjoint vectors.
35280f8ae99SSajid Ali      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
3539566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(user.A, &user.lambda, NULL));
3549566063dSJacob Faibussowitsch   PetscCall(MatCreateVecs(user.Jacp, &user.mup, NULL));
35580f8ae99SSajid Ali 
35680f8ae99SSajid Ali   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
35780f8ae99SSajid Ali      Set initial conditions for the adjoint vector
35880f8ae99SSajid Ali      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
3599566063dSJacob Faibussowitsch   PetscCall(VecGetArray(user.U, &u_ptr));
3609566063dSJacob Faibussowitsch   PetscCall(VecGetArray(user.lambda, &y_ptr));
36180f8ae99SSajid Ali   y_ptr[0] = 2 * (u_ptr[0] - 1.5967);
36280f8ae99SSajid Ali   y_ptr[1] = 2 * (u_ptr[1] - -(1.02969));
3639566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(user.lambda, &y_ptr));
3649566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(user.U, &y_ptr));
3659566063dSJacob Faibussowitsch   PetscCall(VecSet(user.mup, 0));
36680f8ae99SSajid Ali 
36780f8ae99SSajid Ali   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
36880f8ae99SSajid Ali      Set number of cost functions.
36980f8ae99SSajid Ali      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
3709566063dSJacob Faibussowitsch   PetscCall(TSSetCostGradients(ts, 1, &user.lambda, &user.mup));
37180f8ae99SSajid Ali 
37280f8ae99SSajid Ali   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
37380f8ae99SSajid Ali      The adjoint vector mup has to be reset for each adjoint step when
37480f8ae99SSajid Ali      using the tracking method as we want to treat the parameters at each
37580f8ae99SSajid Ali      time step one at a time and prevent accumulation of the sensitivities
37680f8ae99SSajid Ali      from parameters at previous time steps.
37780f8ae99SSajid Ali      This is not necessary for the global method as each time dependent
37880f8ae99SSajid Ali      parameter is treated as an independent parameter.
37980f8ae99SSajid Ali    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
38080f8ae99SSajid Ali   if (sa == SA_TRACK) {
38180f8ae99SSajid Ali     for (user.adj_idx = user.max_steps; user.adj_idx > 0; user.adj_idx--) {
3829566063dSJacob Faibussowitsch       PetscCall(VecSet(user.mup, 0));
3839566063dSJacob Faibussowitsch       PetscCall(TSAdjointSetSteps(ts, 1));
3849566063dSJacob Faibussowitsch       PetscCall(TSAdjointSolve(ts));
38580f8ae99SSajid Ali     }
38680f8ae99SSajid Ali   }
38748a46eb9SPierre Jolivet   if (sa == SA_GLOBAL) PetscCall(TSAdjointSolve(ts));
38880f8ae99SSajid Ali 
38980f8ae99SSajid Ali   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
390d5b43468SJose E. Roman      Display adjoint sensitivities wrt parameters and initial conditions
39180f8ae99SSajid Ali      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
39280f8ae99SSajid Ali   if (sa == SA_TRACK) {
3939566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "\n sensitivity wrt  mu1: d[cost]/d[mu1]\n"));
3949566063dSJacob Faibussowitsch     PetscCall(VecView(user.sens_mu1, PETSC_VIEWER_STDOUT_WORLD));
3959566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "\n sensitivity wrt  mu2: d[cost]/d[mu2]\n"));
3969566063dSJacob Faibussowitsch     PetscCall(VecView(user.sens_mu2, PETSC_VIEWER_STDOUT_WORLD));
39780f8ae99SSajid Ali   }
39880f8ae99SSajid Ali 
39980f8ae99SSajid Ali   if (sa == SA_GLOBAL) {
400d0609cedSBarry Smith     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "\n sensitivity wrt  params: d[cost]/d[p], where p refers to \nthe interlaced vector made by combining mu1,mu2\n"));
4019566063dSJacob Faibussowitsch     PetscCall(VecView(user.mup, PETSC_VIEWER_STDOUT_WORLD));
40280f8ae99SSajid Ali   }
40380f8ae99SSajid Ali 
4049566063dSJacob Faibussowitsch   PetscCall(PetscPrintf(PETSC_COMM_WORLD, "\n sensitivity wrt initial conditions: d[cost]/d[u(t=0)]\n"));
4059566063dSJacob Faibussowitsch   PetscCall(VecView(user.lambda, PETSC_VIEWER_STDOUT_WORLD));
40680f8ae99SSajid Ali 
40780f8ae99SSajid Ali   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
40880f8ae99SSajid Ali      Free work space!
40980f8ae99SSajid Ali      All PETSc objects should be destroyed when they are no longer needed.
41080f8ae99SSajid Ali      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
4119566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&user.A));
4129566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&user.Jacp));
4139566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&user.U));
4149566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&user.lambda));
4159566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&user.mup));
4169566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&user.mu1));
4179566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&user.mu2));
41880f8ae99SSajid Ali   if (sa == SA_TRACK) {
4199566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&user.sens_mu1));
4209566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&user.sens_mu2));
42180f8ae99SSajid Ali   }
4229566063dSJacob Faibussowitsch   PetscCall(TSDestroy(&ts));
4239566063dSJacob Faibussowitsch   PetscCall(PetscFinalize());
4244ad8454bSPierre Jolivet   return 0;
42580f8ae99SSajid Ali }
42680f8ae99SSajid Ali 
42780f8ae99SSajid Ali /*TEST
42880f8ae99SSajid Ali 
42980f8ae99SSajid Ali   test:
43080f8ae99SSajid Ali     requires: !complex
43180f8ae99SSajid Ali     suffix : track
43280f8ae99SSajid Ali     args : -sa_method track
43380f8ae99SSajid Ali 
43480f8ae99SSajid Ali   test:
43580f8ae99SSajid Ali     requires: !complex
43680f8ae99SSajid Ali     suffix : global
43780f8ae99SSajid Ali     args : -sa_method global
43880f8ae99SSajid Ali 
43980f8ae99SSajid Ali TEST*/
440