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