1 static char help[] = "Trajectory sensitivity of a hybrid system with state-dependent switchings.\n"; 2 3 /* 4 The dynamics is described by the ODE 5 u_t = A_i u 6 7 where A_1 = [ 1 -100 8 10 1 ], 9 A_2 = [ 1 10 10 -100 1 ]. 11 The index i changes from 1 to 2 when u[1]=2.75u[0] and from 2 to 1 when u[1]=0.36u[0]. 12 Initially u=[0 1]^T and i=1. 13 14 References: 15 + * - H. Zhang, S. Abhyankar, E. Constantinescu, M. Mihai, Discrete Adjoint Sensitivity Analysis of Hybrid Dynamical Systems With Switching, IEEE Transactions on Circuits and Systems I: Regular Papers, 64(5), May 2017 16 - * - I. A. Hiskens, M.A. Pai, Trajectory Sensitivity Analysis of Hybrid Systems, IEEE Transactions on Circuits and Systems, Vol 47, No 2, February 2000 17 */ 18 19 #include <petscts.h> 20 21 typedef struct { 22 PetscScalar lambda1; 23 PetscScalar lambda2; 24 PetscInt mode; /* mode flag*/ 25 PetscReal print_time; 26 } AppCtx; 27 28 PetscErrorCode MyMonitor(TS ts,PetscInt stepnum,PetscReal time,Vec U,void *ctx) 29 { 30 AppCtx *actx=(AppCtx*)ctx; 31 Mat sp; 32 PetscScalar *u; 33 PetscInt nump; 34 FILE *f; 35 36 PetscFunctionBegin; 37 if (time >= actx->print_time) { 38 actx->print_time += 1./256.; 39 PetscCall(TSForwardGetSensitivities(ts,&nump,&sp)); 40 PetscCall(MatDenseGetColumn(sp,2,&u)); 41 f = fopen("fwd_sp.out", "a"); 42 PetscCall(PetscFPrintf(PETSC_COMM_WORLD,f,"%20.15lf %20.15lf %20.15lf\n",time,u[0],u[1])); 43 PetscCall(MatDenseRestoreColumn(sp,&u)); 44 fclose(f); 45 } 46 PetscFunctionReturn(0); 47 } 48 49 PetscErrorCode EventFunction(TS ts,PetscReal t,Vec U,PetscScalar *fvalue,void *ctx) 50 { 51 AppCtx *actx=(AppCtx*)ctx; 52 const PetscScalar *u; 53 54 PetscFunctionBegin; 55 PetscCall(VecGetArrayRead(U,&u)); 56 if (actx->mode == 1) { 57 fvalue[0] = u[1]-actx->lambda1*u[0]; 58 }else if (actx->mode == 2) { 59 fvalue[0] = u[1]-actx->lambda2*u[0]; 60 } 61 PetscCall(VecRestoreArrayRead(U,&u)); 62 PetscFunctionReturn(0); 63 } 64 65 PetscErrorCode ShiftGradients(TS ts,Vec U,AppCtx *actx) 66 { 67 Mat sp; 68 PetscScalar *x; 69 PetscScalar *u; 70 PetscScalar tmp[2],A1[2][2],A2[2],denorm; 71 PetscInt nump; 72 73 PetscFunctionBegin; 74 PetscCall(TSForwardGetSensitivities(ts,&nump,&sp)); 75 PetscCall(VecGetArray(U,&u)); 76 77 if (actx->mode==1) { 78 denorm = -actx->lambda1*(u[0]-100.*u[1])+1.*(10.*u[0]+u[1]); 79 A1[0][0] = 110.*u[1]*(-actx->lambda1)/denorm+1.; 80 A1[1][0] = -110.*u[0]*(-actx->lambda1)/denorm; 81 A1[0][1] = 110.*u[1]*1./denorm; 82 A1[1][1] = -110.*u[0]*1./denorm+1.; 83 84 A2[0] = 110.*u[1]*(-u[0])/denorm; 85 A2[1] = -110.*u[0]*(-u[0])/denorm; 86 }else { 87 denorm = -actx->lambda2*(u[0]+10.*u[1])+1.*(-100.*u[0]+u[1]); 88 A1[0][0] = 110.*u[1]*(actx->lambda2)/denorm+1; 89 A1[1][0] = -110.*u[0]*(actx->lambda2)/denorm; 90 A1[0][1] = -110.*u[1]*1./denorm; 91 A1[1][1] = 110.*u[0]*1./denorm+1.; 92 93 A2[0] = 0; 94 A2[1] = 0; 95 } 96 97 PetscCall(VecRestoreArray(U,&u)); 98 99 PetscCall(MatDenseGetColumn(sp,0,&x)); 100 tmp[0] = A1[0][0]*x[0]+A1[0][1]*x[1]; 101 tmp[1] = A1[1][0]*x[0]+A1[1][1]*x[1]; 102 x[0] = tmp[0]; 103 x[1] = tmp[1]; 104 PetscCall(MatDenseRestoreColumn(sp,&x)); 105 106 PetscCall(MatDenseGetColumn(sp,1,&x)); 107 tmp[0] = A1[0][0]*x[0]+A1[0][1]*x[1]; 108 tmp[1] = A1[1][0]*x[0]+A1[1][1]*x[1]; 109 x[0] = tmp[0]; 110 x[1] = tmp[1]; 111 PetscCall(MatDenseRestoreColumn(sp,&x)); 112 113 PetscCall(MatDenseGetColumn(sp,2,&x)); 114 tmp[0] = A1[0][0]*x[0]+A1[0][1]*x[1]; 115 tmp[1] = A1[1][0]*x[0]+A1[1][1]*x[1]; 116 x[0] = tmp[0]+A2[0]; 117 x[1] = tmp[1]+A2[1]; 118 PetscCall(MatDenseRestoreColumn(sp,&x)); 119 120 PetscFunctionReturn(0); 121 } 122 123 PetscErrorCode PostEventFunction(TS ts,PetscInt nevents,PetscInt event_list[],PetscReal t,Vec U,PetscBool forwardsolve,void* ctx) 124 { 125 AppCtx *actx=(AppCtx*)ctx; 126 127 PetscFunctionBegin; 128 /* PetscCall(VecView(U,PETSC_VIEWER_STDOUT_WORLD)); */ 129 PetscCall(ShiftGradients(ts,U,actx)); 130 if (actx->mode == 1) { 131 actx->mode = 2; 132 /* PetscCall(PetscPrintf(PETSC_COMM_SELF,"Change from mode 1 to 2 at t = %f \n",(double)t)); */ 133 } else if (actx->mode == 2) { 134 actx->mode = 1; 135 /* PetscCall(PetscPrintf(PETSC_COMM_SELF,"Change from mode 2 to 1 at t = %f \n",(double)t)); */ 136 } 137 PetscFunctionReturn(0); 138 } 139 140 /* 141 Defines the ODE passed to the ODE solver 142 */ 143 static PetscErrorCode IFunction(TS ts,PetscReal t,Vec U,Vec Udot,Vec F,void *ctx) 144 { 145 AppCtx *actx=(AppCtx*)ctx; 146 PetscScalar *f; 147 const PetscScalar *u,*udot; 148 149 PetscFunctionBegin; 150 /* The next three lines allow us to access the entries of the vectors directly */ 151 PetscCall(VecGetArrayRead(U,&u)); 152 PetscCall(VecGetArrayRead(Udot,&udot)); 153 PetscCall(VecGetArray(F,&f)); 154 155 if (actx->mode == 1) { 156 f[0] = udot[0]-u[0]+100*u[1]; 157 f[1] = udot[1]-10*u[0]-u[1]; 158 } else if (actx->mode == 2) { 159 f[0] = udot[0]-u[0]-10*u[1]; 160 f[1] = udot[1]+100*u[0]-u[1]; 161 } 162 163 PetscCall(VecRestoreArrayRead(U,&u)); 164 PetscCall(VecRestoreArrayRead(Udot,&udot)); 165 PetscCall(VecRestoreArray(F,&f)); 166 PetscFunctionReturn(0); 167 } 168 169 /* 170 Defines the Jacobian of the ODE passed to the ODE solver. See TSSetIJacobian() for the meaning of a and the Jacobian. 171 */ 172 static PetscErrorCode IJacobian(TS ts,PetscReal t,Vec U,Vec Udot,PetscReal a,Mat A,Mat B,void *ctx) 173 { 174 AppCtx *actx=(AppCtx*)ctx; 175 PetscInt rowcol[] = {0,1}; 176 PetscScalar J[2][2]; 177 const PetscScalar *u,*udot; 178 179 PetscFunctionBegin; 180 PetscCall(VecGetArrayRead(U,&u)); 181 PetscCall(VecGetArrayRead(Udot,&udot)); 182 183 if (actx->mode == 1) { 184 J[0][0] = a-1; J[0][1] = 100; 185 J[1][0] = -10; J[1][1] = a-1; 186 } else if (actx->mode == 2) { 187 J[0][0] = a-1; J[0][1] = -10; 188 J[1][0] = 100; J[1][1] = a-1; 189 } 190 PetscCall(MatSetValues(B,2,rowcol,2,rowcol,&J[0][0],INSERT_VALUES)); 191 192 PetscCall(VecRestoreArrayRead(U,&u)); 193 PetscCall(VecRestoreArrayRead(Udot,&udot)); 194 195 PetscCall(MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY)); 196 PetscCall(MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY)); 197 if (A != B) { 198 PetscCall(MatAssemblyBegin(B,MAT_FINAL_ASSEMBLY)); 199 PetscCall(MatAssemblyEnd(B,MAT_FINAL_ASSEMBLY)); 200 } 201 PetscFunctionReturn(0); 202 } 203 204 /* Matrix JacobianP is constant so that it only needs to be evaluated once */ 205 static PetscErrorCode RHSJacobianP(TS ts,PetscReal t,Vec X,Mat Ap,void *ctx) 206 { 207 PetscFunctionBeginUser; 208 PetscFunctionReturn(0); 209 } 210 211 int main(int argc,char **argv) 212 { 213 TS ts; /* ODE integrator */ 214 Vec U; /* solution will be stored here */ 215 Mat A; /* Jacobian matrix */ 216 Mat Ap; /* Jacobian dfdp */ 217 PetscErrorCode ierr; 218 PetscMPIInt size; 219 PetscInt n = 2; 220 PetscScalar *u; 221 AppCtx app; 222 PetscInt direction[1]; 223 PetscBool terminate[1]; 224 Mat sp; 225 PetscReal tend; 226 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 227 Initialize program 228 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 229 PetscCall(PetscInitialize(&argc,&argv,(char*)0,help)); 230 PetscCallMPI(MPI_Comm_size(PETSC_COMM_WORLD,&size)); 231 PetscCheck(size == 1,PETSC_COMM_WORLD,PETSC_ERR_WRONG_MPI_SIZE,"Only for sequential runs"); 232 app.mode = 1; 233 app.lambda1 = 2.75; 234 app.lambda2 = 0.36; 235 app.print_time = 1./256.; 236 tend = 0.125; 237 ierr = PetscOptionsBegin(PETSC_COMM_WORLD,NULL,"ex1fwd options","");PetscCall(ierr); 238 { 239 PetscCall(PetscOptionsReal("-lambda1","","",app.lambda1,&app.lambda1,NULL)); 240 PetscCall(PetscOptionsReal("-lambda2","","",app.lambda2,&app.lambda2,NULL)); 241 PetscCall(PetscOptionsReal("-tend","","",tend,&tend,NULL)); 242 } 243 ierr = PetscOptionsEnd();PetscCall(ierr); 244 245 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 246 Create necessary matrix and vectors 247 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 248 PetscCall(MatCreate(PETSC_COMM_WORLD,&A)); 249 PetscCall(MatSetSizes(A,n,n,PETSC_DETERMINE,PETSC_DETERMINE)); 250 PetscCall(MatSetType(A,MATDENSE)); 251 PetscCall(MatSetFromOptions(A)); 252 PetscCall(MatSetUp(A)); 253 254 PetscCall(MatCreateVecs(A,&U,NULL)); 255 256 PetscCall(MatCreate(PETSC_COMM_WORLD,&Ap)); 257 PetscCall(MatSetSizes(Ap,n,3,PETSC_DETERMINE,PETSC_DETERMINE)); 258 PetscCall(MatSetType(Ap,MATDENSE)); 259 PetscCall(MatSetFromOptions(Ap)); 260 PetscCall(MatSetUp(Ap)); 261 PetscCall(MatZeroEntries(Ap)); 262 263 PetscCall(MatCreateDense(PETSC_COMM_WORLD,PETSC_DECIDE,PETSC_DECIDE,n,3,NULL,&sp)); 264 PetscCall(MatZeroEntries(sp)); 265 PetscCall(MatShift(sp,1.0)); 266 267 PetscCall(VecGetArray(U,&u)); 268 u[0] = 0; 269 u[1] = 1; 270 PetscCall(VecRestoreArray(U,&u)); 271 272 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 273 Create timestepping solver context 274 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 275 PetscCall(TSCreate(PETSC_COMM_WORLD,&ts)); 276 PetscCall(TSSetProblemType(ts,TS_NONLINEAR)); 277 PetscCall(TSSetType(ts,TSCN)); 278 PetscCall(TSSetIFunction(ts,NULL,(TSIFunction)IFunction,&app)); 279 PetscCall(TSSetIJacobian(ts,A,A,(TSIJacobian)IJacobian,&app)); 280 281 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 282 Set initial conditions 283 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 284 PetscCall(TSSetSolution(ts,U)); 285 286 PetscCall(TSForwardSetSensitivities(ts,3,sp)); 287 /* Set RHS JacobianP */ 288 PetscCall(TSSetRHSJacobianP(ts,Ap,RHSJacobianP,&app)); 289 290 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 291 Set solver options 292 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 293 PetscCall(TSSetMaxTime(ts,tend)); 294 PetscCall(TSSetExactFinalTime(ts,TS_EXACTFINALTIME_MATCHSTEP)); 295 PetscCall(TSSetTimeStep(ts,1./256.)); 296 PetscCall(TSMonitorSet(ts,MyMonitor,&app,PETSC_NULL)); 297 PetscCall(TSSetFromOptions(ts)); 298 299 /* Set directions and terminate flags for the two events */ 300 direction[0] = 0; 301 terminate[0] = PETSC_FALSE; 302 PetscCall(TSSetEventHandler(ts,1,direction,terminate,EventFunction,PostEventFunction,(void*)&app)); 303 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 304 Run timestepping solver 305 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 306 PetscCall(TSSolve(ts,U)); 307 308 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 309 Free work space. All PETSc objects should be destroyed when they are no longer needed. 310 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 311 PetscCall(MatDestroy(&A)); 312 PetscCall(VecDestroy(&U)); 313 PetscCall(TSDestroy(&ts)); 314 315 PetscCall(MatDestroy(&Ap)); 316 PetscCall(MatDestroy(&sp)); 317 PetscCall(PetscFinalize()); 318 return(ierr); 319 } 320 321 /*TEST 322 323 build: 324 requires: !complex 325 326 test: 327 args: -ts_monitor 328 329 TEST*/ 330