1 2 static char help[] = "Solves the van der Pol equation.\n\ 3 Input parameters include:\n"; 4 5 /* ------------------------------------------------------------------------ 6 7 Notes: 8 This code demonstrates how to solve a DAE-constrained optimization problem with TAO, TSAdjoint and TS. 9 The nonlinear problem is written in a DAE equivalent form. 10 The objective is to minimize the difference between observation and model prediction by finding an optimal value for parameter \mu. 11 The gradient is computed with the discrete adjoint of an implicit theta method, see ex20adj.c for details. 12 ------------------------------------------------------------------------- */ 13 #include <petsctao.h> 14 #include <petscts.h> 15 16 typedef struct _n_User *User; 17 struct _n_User { 18 TS ts; 19 PetscReal mu; 20 PetscReal next_output; 21 22 /* Sensitivity analysis support */ 23 PetscReal ftime; 24 Mat A; /* Jacobian matrix */ 25 Mat Jacp; /* JacobianP matrix */ 26 Mat H; /* Hessian matrix for optimization */ 27 Vec U,Lambda[1],Mup[1]; /* adjoint variables */ 28 Vec Lambda2[1],Mup2[1]; /* second-order adjoint variables */ 29 Vec Ihp1[1]; /* working space for Hessian evaluations */ 30 Vec Ihp2[1]; /* working space for Hessian evaluations */ 31 Vec Ihp3[1]; /* working space for Hessian evaluations */ 32 Vec Ihp4[1]; /* working space for Hessian evaluations */ 33 Vec Dir; /* direction vector */ 34 PetscReal ob[2]; /* observation used by the cost function */ 35 PetscBool implicitform; /* implicit ODE? */ 36 }; 37 38 PetscErrorCode FormFunctionGradient(Tao,Vec,PetscReal*,Vec,void*); 39 PetscErrorCode FormHessian(Tao,Vec,Mat,Mat,void*); 40 PetscErrorCode Adjoint2(Vec,PetscScalar[],User); 41 42 /* ----------------------- Explicit form of the ODE -------------------- */ 43 44 static PetscErrorCode RHSFunction(TS ts,PetscReal t,Vec U,Vec F,void *ctx) 45 { 46 User user = (User)ctx; 47 PetscScalar *f; 48 const PetscScalar *u; 49 50 PetscFunctionBeginUser; 51 PetscCall(VecGetArrayRead(U,&u)); 52 PetscCall(VecGetArray(F,&f)); 53 f[0] = u[1]; 54 f[1] = user->mu*((1.-u[0]*u[0])*u[1]-u[0]); 55 PetscCall(VecRestoreArrayRead(U,&u)); 56 PetscCall(VecRestoreArray(F,&f)); 57 PetscFunctionReturn(0); 58 } 59 60 static PetscErrorCode RHSJacobian(TS ts,PetscReal t,Vec U,Mat A,Mat B,void *ctx) 61 { 62 User user = (User)ctx; 63 PetscReal mu = user->mu; 64 PetscInt rowcol[] = {0,1}; 65 PetscScalar J[2][2]; 66 const PetscScalar *u; 67 68 PetscFunctionBeginUser; 69 PetscCall(VecGetArrayRead(U,&u)); 70 71 J[0][0] = 0; 72 J[1][0] = -mu*(2.0*u[1]*u[0]+1.); 73 J[0][1] = 1.0; 74 J[1][1] = mu*(1.0-u[0]*u[0]); 75 PetscCall(MatSetValues(A,2,rowcol,2,rowcol,&J[0][0],INSERT_VALUES)); 76 PetscCall(MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY)); 77 PetscCall(MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY)); 78 if (B && A != B) { 79 PetscCall(MatAssemblyBegin(B,MAT_FINAL_ASSEMBLY)); 80 PetscCall(MatAssemblyEnd(B,MAT_FINAL_ASSEMBLY)); 81 } 82 83 PetscCall(VecRestoreArrayRead(U,&u)); 84 PetscFunctionReturn(0); 85 } 86 87 static PetscErrorCode RHSHessianProductUU(TS ts,PetscReal t,Vec U,Vec *Vl,Vec Vr,Vec *VHV,void *ctx) 88 { 89 const PetscScalar *vl,*vr,*u; 90 PetscScalar *vhv; 91 PetscScalar dJdU[2][2][2]={{{0}}}; 92 PetscInt i,j,k; 93 User user = (User)ctx; 94 95 PetscFunctionBeginUser; 96 PetscCall(VecGetArrayRead(U,&u)); 97 PetscCall(VecGetArrayRead(Vl[0],&vl)); 98 PetscCall(VecGetArrayRead(Vr,&vr)); 99 PetscCall(VecGetArray(VHV[0],&vhv)); 100 101 dJdU[1][0][0] = -2.*user->mu*u[1]; 102 dJdU[1][1][0] = -2.*user->mu*u[0]; 103 dJdU[1][0][1] = -2.*user->mu*u[0]; 104 for (j=0; j<2; j++) { 105 vhv[j] = 0; 106 for (k=0; k<2; k++) 107 for (i=0; i<2; i++) 108 vhv[j] += vl[i]*dJdU[i][j][k]*vr[k]; 109 } 110 111 PetscCall(VecRestoreArrayRead(U,&u)); 112 PetscCall(VecRestoreArrayRead(Vl[0],&vl)); 113 PetscCall(VecRestoreArrayRead(Vr,&vr)); 114 PetscCall(VecRestoreArray(VHV[0],&vhv)); 115 PetscFunctionReturn(0); 116 } 117 118 static PetscErrorCode RHSHessianProductUP(TS ts,PetscReal t,Vec U,Vec *Vl,Vec Vr,Vec *VHV,void *ctx) 119 { 120 const PetscScalar *vl,*vr,*u; 121 PetscScalar *vhv; 122 PetscScalar dJdP[2][2][1]={{{0}}}; 123 PetscInt i,j,k; 124 125 PetscFunctionBeginUser; 126 PetscCall(VecGetArrayRead(U,&u)); 127 PetscCall(VecGetArrayRead(Vl[0],&vl)); 128 PetscCall(VecGetArrayRead(Vr,&vr)); 129 PetscCall(VecGetArray(VHV[0],&vhv)); 130 131 dJdP[1][0][0] = -(1.+2.*u[0]*u[1]); 132 dJdP[1][1][0] = 1.-u[0]*u[0]; 133 for (j=0; j<2; j++) { 134 vhv[j] = 0; 135 for (k=0; k<1; k++) 136 for (i=0; i<2; i++) 137 vhv[j] += vl[i]*dJdP[i][j][k]*vr[k]; 138 } 139 140 PetscCall(VecRestoreArrayRead(U,&u)); 141 PetscCall(VecRestoreArrayRead(Vl[0],&vl)); 142 PetscCall(VecRestoreArrayRead(Vr,&vr)); 143 PetscCall(VecRestoreArray(VHV[0],&vhv)); 144 PetscFunctionReturn(0); 145 } 146 147 static PetscErrorCode RHSHessianProductPU(TS ts,PetscReal t,Vec U,Vec *Vl,Vec Vr,Vec *VHV,void *ctx) 148 { 149 const PetscScalar *vl,*vr,*u; 150 PetscScalar *vhv; 151 PetscScalar dJdU[2][1][2]={{{0}}}; 152 PetscInt i,j,k; 153 154 PetscFunctionBeginUser; 155 PetscCall(VecGetArrayRead(U,&u)); 156 PetscCall(VecGetArrayRead(Vl[0],&vl)); 157 PetscCall(VecGetArrayRead(Vr,&vr)); 158 PetscCall(VecGetArray(VHV[0],&vhv)); 159 160 dJdU[1][0][0] = -1.-2.*u[1]*u[0]; 161 dJdU[1][0][1] = 1.-u[0]*u[0]; 162 for (j=0; j<1; j++) { 163 vhv[j] = 0; 164 for (k=0; k<2; k++) 165 for (i=0; i<2; i++) 166 vhv[j] += vl[i]*dJdU[i][j][k]*vr[k]; 167 } 168 169 PetscCall(VecRestoreArrayRead(U,&u)); 170 PetscCall(VecRestoreArrayRead(Vl[0],&vl)); 171 PetscCall(VecRestoreArrayRead(Vr,&vr)); 172 PetscCall(VecRestoreArray(VHV[0],&vhv)); 173 PetscFunctionReturn(0); 174 } 175 176 static PetscErrorCode RHSHessianProductPP(TS ts,PetscReal t,Vec U,Vec *Vl,Vec Vr,Vec *VHV,void *ctx) 177 { 178 PetscFunctionBeginUser; 179 PetscFunctionReturn(0); 180 } 181 182 /* ----------------------- Implicit form of the ODE -------------------- */ 183 184 static PetscErrorCode IFunction(TS ts,PetscReal t,Vec U,Vec Udot,Vec F,void *ctx) 185 { 186 User user = (User)ctx; 187 PetscScalar *f; 188 const PetscScalar *u,*udot; 189 190 PetscFunctionBeginUser; 191 PetscCall(VecGetArrayRead(U,&u)); 192 PetscCall(VecGetArrayRead(Udot,&udot)); 193 PetscCall(VecGetArray(F,&f)); 194 195 f[0] = udot[0] - u[1]; 196 f[1] = udot[1] - user->mu*((1.0-u[0]*u[0])*u[1] - u[0]) ; 197 198 PetscCall(VecRestoreArrayRead(U,&u)); 199 PetscCall(VecRestoreArrayRead(Udot,&udot)); 200 PetscCall(VecRestoreArray(F,&f)); 201 PetscFunctionReturn(0); 202 } 203 204 static PetscErrorCode IJacobian(TS ts,PetscReal t,Vec U,Vec Udot,PetscReal a,Mat A,Mat B,void *ctx) 205 { 206 User user = (User)ctx; 207 PetscInt rowcol[] = {0,1}; 208 PetscScalar J[2][2]; 209 const PetscScalar *u; 210 211 PetscFunctionBeginUser; 212 PetscCall(VecGetArrayRead(U,&u)); 213 214 J[0][0] = a; J[0][1] = -1.0; 215 J[1][0] = user->mu*(1.0 + 2.0*u[0]*u[1]); J[1][1] = a - user->mu*(1.0-u[0]*u[0]); 216 PetscCall(MatSetValues(B,2,rowcol,2,rowcol,&J[0][0],INSERT_VALUES)); 217 PetscCall(VecRestoreArrayRead(U,&u)); 218 PetscCall(MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY)); 219 PetscCall(MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY)); 220 if (A != B) { 221 PetscCall(MatAssemblyBegin(B,MAT_FINAL_ASSEMBLY)); 222 PetscCall(MatAssemblyEnd(B,MAT_FINAL_ASSEMBLY)); 223 } 224 225 PetscCall(VecRestoreArrayRead(U,&u)); 226 PetscFunctionReturn(0); 227 } 228 229 static PetscErrorCode RHSJacobianP(TS ts,PetscReal t,Vec U,Mat A,void *ctx) 230 { 231 PetscInt row[] = {0,1},col[]={0}; 232 PetscScalar J[2][1]; 233 const PetscScalar *u; 234 235 PetscFunctionBeginUser; 236 PetscCall(VecGetArrayRead(U,&u)); 237 238 J[0][0] = 0; 239 J[1][0] = (1.-u[0]*u[0])*u[1]-u[0]; 240 PetscCall(MatSetValues(A,2,row,1,col,&J[0][0],INSERT_VALUES)); 241 PetscCall(VecRestoreArrayRead(U,&u)); 242 PetscCall(MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY)); 243 PetscCall(MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY)); 244 245 PetscCall(VecRestoreArrayRead(U,&u)); 246 PetscFunctionReturn(0); 247 } 248 249 static PetscErrorCode IHessianProductUU(TS ts,PetscReal t,Vec U,Vec *Vl,Vec Vr,Vec *VHV,void *ctx) 250 { 251 const PetscScalar *vl,*vr,*u; 252 PetscScalar *vhv; 253 PetscScalar dJdU[2][2][2]={{{0}}}; 254 PetscInt i,j,k; 255 User user = (User)ctx; 256 257 PetscFunctionBeginUser; 258 PetscCall(VecGetArrayRead(U,&u)); 259 PetscCall(VecGetArrayRead(Vl[0],&vl)); 260 PetscCall(VecGetArrayRead(Vr,&vr)); 261 PetscCall(VecGetArray(VHV[0],&vhv)); 262 263 dJdU[1][0][0] = 2.*user->mu*u[1]; 264 dJdU[1][1][0] = 2.*user->mu*u[0]; 265 dJdU[1][0][1] = 2.*user->mu*u[0]; 266 for (j=0; j<2; j++) { 267 vhv[j] = 0; 268 for (k=0; k<2; k++) 269 for (i=0; i<2; i++) 270 vhv[j] += vl[i]*dJdU[i][j][k]*vr[k]; 271 } 272 273 PetscCall(VecRestoreArrayRead(U,&u)); 274 PetscCall(VecRestoreArrayRead(Vl[0],&vl)); 275 PetscCall(VecRestoreArrayRead(Vr,&vr)); 276 PetscCall(VecRestoreArray(VHV[0],&vhv)); 277 PetscFunctionReturn(0); 278 } 279 280 static PetscErrorCode IHessianProductUP(TS ts,PetscReal t,Vec U,Vec *Vl,Vec Vr,Vec *VHV,void *ctx) 281 { 282 const PetscScalar *vl,*vr,*u; 283 PetscScalar *vhv; 284 PetscScalar dJdP[2][2][1]={{{0}}}; 285 PetscInt i,j,k; 286 287 PetscFunctionBeginUser; 288 PetscCall(VecGetArrayRead(U,&u)); 289 PetscCall(VecGetArrayRead(Vl[0],&vl)); 290 PetscCall(VecGetArrayRead(Vr,&vr)); 291 PetscCall(VecGetArray(VHV[0],&vhv)); 292 293 dJdP[1][0][0] = 1.+2.*u[0]*u[1]; 294 dJdP[1][1][0] = u[0]*u[0]-1.; 295 for (j=0; j<2; j++) { 296 vhv[j] = 0; 297 for (k=0; k<1; k++) 298 for (i=0; i<2; i++) 299 vhv[j] += vl[i]*dJdP[i][j][k]*vr[k]; 300 } 301 302 PetscCall(VecRestoreArrayRead(U,&u)); 303 PetscCall(VecRestoreArrayRead(Vl[0],&vl)); 304 PetscCall(VecRestoreArrayRead(Vr,&vr)); 305 PetscCall(VecRestoreArray(VHV[0],&vhv)); 306 PetscFunctionReturn(0); 307 } 308 309 static PetscErrorCode IHessianProductPU(TS ts,PetscReal t,Vec U,Vec *Vl,Vec Vr,Vec *VHV,void *ctx) 310 { 311 const PetscScalar *vl,*vr,*u; 312 PetscScalar *vhv; 313 PetscScalar dJdU[2][1][2]={{{0}}}; 314 PetscInt i,j,k; 315 316 PetscFunctionBeginUser; 317 PetscCall(VecGetArrayRead(U,&u)); 318 PetscCall(VecGetArrayRead(Vl[0],&vl)); 319 PetscCall(VecGetArrayRead(Vr,&vr)); 320 PetscCall(VecGetArray(VHV[0],&vhv)); 321 322 dJdU[1][0][0] = 1.+2.*u[1]*u[0]; 323 dJdU[1][0][1] = u[0]*u[0]-1.; 324 for (j=0; j<1; j++) { 325 vhv[j] = 0; 326 for (k=0; k<2; k++) 327 for (i=0; i<2; i++) 328 vhv[j] += vl[i]*dJdU[i][j][k]*vr[k]; 329 } 330 331 PetscCall(VecRestoreArrayRead(U,&u)); 332 PetscCall(VecRestoreArrayRead(Vl[0],&vl)); 333 PetscCall(VecRestoreArrayRead(Vr,&vr)); 334 PetscCall(VecRestoreArray(VHV[0],&vhv)); 335 PetscFunctionReturn(0); 336 } 337 338 static PetscErrorCode IHessianProductPP(TS ts,PetscReal t,Vec U,Vec *Vl,Vec Vr,Vec *VHV,void *ctx) 339 { 340 PetscFunctionBeginUser; 341 PetscFunctionReturn(0); 342 } 343 344 /* Monitor timesteps and use interpolation to output at integer multiples of 0.1 */ 345 static PetscErrorCode Monitor(TS ts,PetscInt step,PetscReal t,Vec X,void *ctx) 346 { 347 PetscErrorCode ierr; 348 const PetscScalar *x; 349 PetscReal tfinal, dt; 350 User user = (User)ctx; 351 Vec interpolatedX; 352 353 PetscFunctionBeginUser; 354 PetscCall(TSGetTimeStep(ts,&dt)); 355 PetscCall(TSGetMaxTime(ts,&tfinal)); 356 357 while (user->next_output <= t && user->next_output <= tfinal) { 358 PetscCall(VecDuplicate(X,&interpolatedX)); 359 PetscCall(TSInterpolate(ts,user->next_output,interpolatedX)); 360 PetscCall(VecGetArrayRead(interpolatedX,&x)); 361 ierr = PetscPrintf(PETSC_COMM_WORLD,"[%g] %D TS %g (dt = %g) X %g %g\n", 362 (double)user->next_output,step,(double)t,(double)dt,(double)PetscRealPart(x[0]), 363 (double)PetscRealPart(x[1]));PetscCall(ierr); 364 PetscCall(VecRestoreArrayRead(interpolatedX,&x)); 365 PetscCall(VecDestroy(&interpolatedX)); 366 user->next_output += PetscRealConstant(0.1); 367 } 368 PetscFunctionReturn(0); 369 } 370 371 int main(int argc,char **argv) 372 { 373 Vec P; 374 PetscBool monitor = PETSC_FALSE; 375 PetscScalar *x_ptr; 376 const PetscScalar *y_ptr; 377 PetscMPIInt size; 378 struct _n_User user; 379 Tao tao; 380 KSP ksp; 381 PC pc; 382 383 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 384 Initialize program 385 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 386 PetscCall(PetscInitialize(&argc,&argv,NULL,help)); 387 PetscCallMPI(MPI_Comm_size(PETSC_COMM_WORLD,&size)); 388 PetscCheck(size == 1,PETSC_COMM_WORLD,PETSC_ERR_WRONG_MPI_SIZE,"This is a uniprocessor example only!"); 389 390 /* Create TAO solver and set desired solution method */ 391 PetscCall(TaoCreate(PETSC_COMM_WORLD,&tao)); 392 PetscCall(TaoSetType(tao,TAOBQNLS)); 393 394 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 395 Set runtime options 396 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 397 user.next_output = 0.0; 398 user.mu = PetscRealConstant(1.0e3); 399 user.ftime = PetscRealConstant(0.5); 400 user.implicitform = PETSC_TRUE; 401 402 PetscCall(PetscOptionsGetBool(NULL,NULL,"-monitor",&monitor,NULL)); 403 PetscCall(PetscOptionsGetReal(NULL,NULL,"-mu",&user.mu,NULL)); 404 PetscCall(PetscOptionsGetBool(NULL,NULL,"-implicitform",&user.implicitform,NULL)); 405 406 /* Create necessary matrix and vectors, solve same ODE on every process */ 407 PetscCall(MatCreate(PETSC_COMM_WORLD,&user.A)); 408 PetscCall(MatSetSizes(user.A,PETSC_DECIDE,PETSC_DECIDE,2,2)); 409 PetscCall(MatSetFromOptions(user.A)); 410 PetscCall(MatSetUp(user.A)); 411 PetscCall(MatCreateVecs(user.A,&user.U,NULL)); 412 PetscCall(MatCreateVecs(user.A,&user.Lambda[0],NULL)); 413 PetscCall(MatCreateVecs(user.A,&user.Lambda2[0],NULL)); 414 PetscCall(MatCreateVecs(user.A,&user.Ihp1[0],NULL)); 415 PetscCall(MatCreateVecs(user.A,&user.Ihp2[0],NULL)); 416 417 PetscCall(MatCreate(PETSC_COMM_WORLD,&user.Jacp)); 418 PetscCall(MatSetSizes(user.Jacp,PETSC_DECIDE,PETSC_DECIDE,2,1)); 419 PetscCall(MatSetFromOptions(user.Jacp)); 420 PetscCall(MatSetUp(user.Jacp)); 421 PetscCall(MatCreateVecs(user.Jacp,&user.Dir,NULL)); 422 PetscCall(MatCreateVecs(user.Jacp,&user.Mup[0],NULL)); 423 PetscCall(MatCreateVecs(user.Jacp,&user.Mup2[0],NULL)); 424 PetscCall(MatCreateVecs(user.Jacp,&user.Ihp3[0],NULL)); 425 PetscCall(MatCreateVecs(user.Jacp,&user.Ihp4[0],NULL)); 426 427 /* Create timestepping solver context */ 428 PetscCall(TSCreate(PETSC_COMM_WORLD,&user.ts)); 429 PetscCall(TSSetEquationType(user.ts,TS_EQ_ODE_EXPLICIT)); /* less Jacobian evaluations when adjoint BEuler is used, otherwise no effect */ 430 if (user.implicitform) { 431 PetscCall(TSSetIFunction(user.ts,NULL,IFunction,&user)); 432 PetscCall(TSSetIJacobian(user.ts,user.A,user.A,IJacobian,&user)); 433 PetscCall(TSSetType(user.ts,TSCN)); 434 } else { 435 PetscCall(TSSetRHSFunction(user.ts,NULL,RHSFunction,&user)); 436 PetscCall(TSSetRHSJacobian(user.ts,user.A,user.A,RHSJacobian,&user)); 437 PetscCall(TSSetType(user.ts,TSRK)); 438 } 439 PetscCall(TSSetRHSJacobianP(user.ts,user.Jacp,RHSJacobianP,&user)); 440 PetscCall(TSSetMaxTime(user.ts,user.ftime)); 441 PetscCall(TSSetExactFinalTime(user.ts,TS_EXACTFINALTIME_MATCHSTEP)); 442 443 if (monitor) { 444 PetscCall(TSMonitorSet(user.ts,Monitor,&user,NULL)); 445 } 446 447 /* Set ODE initial conditions */ 448 PetscCall(VecGetArray(user.U,&x_ptr)); 449 x_ptr[0] = 2.0; 450 x_ptr[1] = -2.0/3.0 + 10.0/(81.0*user.mu) - 292.0/(2187.0*user.mu*user.mu); 451 PetscCall(VecRestoreArray(user.U,&x_ptr)); 452 PetscCall(TSSetTimeStep(user.ts,PetscRealConstant(0.001))); 453 454 /* Set runtime options */ 455 PetscCall(TSSetFromOptions(user.ts)); 456 457 PetscCall(TSSolve(user.ts,user.U)); 458 PetscCall(VecGetArrayRead(user.U,&y_ptr)); 459 user.ob[0] = y_ptr[0]; 460 user.ob[1] = y_ptr[1]; 461 PetscCall(VecRestoreArrayRead(user.U,&y_ptr)); 462 463 /* Save trajectory of solution so that TSAdjointSolve() may be used. 464 Skip checkpointing for the first TSSolve since no adjoint run follows it. 465 */ 466 PetscCall(TSSetSaveTrajectory(user.ts)); 467 468 /* Optimization starts */ 469 PetscCall(MatCreate(PETSC_COMM_WORLD,&user.H)); 470 PetscCall(MatSetSizes(user.H,PETSC_DECIDE,PETSC_DECIDE,1,1)); 471 PetscCall(MatSetUp(user.H)); /* Hessian should be symmetric. Do we need to do MatSetOption(user.H,MAT_SYMMETRIC,PETSC_TRUE) ? */ 472 473 /* Set initial solution guess */ 474 PetscCall(MatCreateVecs(user.Jacp,&P,NULL)); 475 PetscCall(VecGetArray(P,&x_ptr)); 476 x_ptr[0] = PetscRealConstant(1.2); 477 PetscCall(VecRestoreArray(P,&x_ptr)); 478 PetscCall(TaoSetSolution(tao,P)); 479 480 /* Set routine for function and gradient evaluation */ 481 PetscCall(TaoSetObjectiveAndGradient(tao,NULL,FormFunctionGradient,(void *)&user)); 482 PetscCall(TaoSetHessian(tao,user.H,user.H,FormHessian,(void *)&user)); 483 484 /* Check for any TAO command line options */ 485 PetscCall(TaoGetKSP(tao,&ksp)); 486 if (ksp) { 487 PetscCall(KSPGetPC(ksp,&pc)); 488 PetscCall(PCSetType(pc,PCNONE)); 489 } 490 PetscCall(TaoSetFromOptions(tao)); 491 492 PetscCall(TaoSolve(tao)); 493 494 PetscCall(VecView(P,PETSC_VIEWER_STDOUT_WORLD)); 495 /* Free TAO data structures */ 496 PetscCall(TaoDestroy(&tao)); 497 498 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 499 Free work space. All PETSc objects should be destroyed when they 500 are no longer needed. 501 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 502 PetscCall(MatDestroy(&user.H)); 503 PetscCall(MatDestroy(&user.A)); 504 PetscCall(VecDestroy(&user.U)); 505 PetscCall(MatDestroy(&user.Jacp)); 506 PetscCall(VecDestroy(&user.Lambda[0])); 507 PetscCall(VecDestroy(&user.Mup[0])); 508 PetscCall(VecDestroy(&user.Lambda2[0])); 509 PetscCall(VecDestroy(&user.Mup2[0])); 510 PetscCall(VecDestroy(&user.Ihp1[0])); 511 PetscCall(VecDestroy(&user.Ihp2[0])); 512 PetscCall(VecDestroy(&user.Ihp3[0])); 513 PetscCall(VecDestroy(&user.Ihp4[0])); 514 PetscCall(VecDestroy(&user.Dir)); 515 PetscCall(TSDestroy(&user.ts)); 516 PetscCall(VecDestroy(&P)); 517 PetscCall(PetscFinalize()); 518 return 0; 519 } 520 521 /* ------------------------------------------------------------------ */ 522 /* 523 FormFunctionGradient - Evaluates the function and corresponding gradient. 524 525 Input Parameters: 526 tao - the Tao context 527 X - the input vector 528 ptr - optional user-defined context, as set by TaoSetObjectiveAndGradient() 529 530 Output Parameters: 531 f - the newly evaluated function 532 G - the newly evaluated gradient 533 */ 534 PetscErrorCode FormFunctionGradient(Tao tao,Vec P,PetscReal *f,Vec G,void *ctx) 535 { 536 User user_ptr = (User)ctx; 537 TS ts = user_ptr->ts; 538 PetscScalar *x_ptr,*g; 539 const PetscScalar *y_ptr; 540 541 PetscFunctionBeginUser; 542 PetscCall(VecGetArrayRead(P,&y_ptr)); 543 user_ptr->mu = y_ptr[0]; 544 PetscCall(VecRestoreArrayRead(P,&y_ptr)); 545 546 PetscCall(TSSetTime(ts,0.0)); 547 PetscCall(TSSetStepNumber(ts,0)); 548 PetscCall(TSSetTimeStep(ts,PetscRealConstant(0.001))); /* can be overwritten by command line options */ 549 PetscCall(TSSetFromOptions(ts)); 550 PetscCall(VecGetArray(user_ptr->U,&x_ptr)); 551 x_ptr[0] = 2.0; 552 x_ptr[1] = -2.0/3.0 + 10.0/(81.0*user_ptr->mu) - 292.0/(2187.0*user_ptr->mu*user_ptr->mu); 553 PetscCall(VecRestoreArray(user_ptr->U,&x_ptr)); 554 555 PetscCall(TSSolve(ts,user_ptr->U)); 556 557 PetscCall(VecGetArrayRead(user_ptr->U,&y_ptr)); 558 *f = (y_ptr[0]-user_ptr->ob[0])*(y_ptr[0]-user_ptr->ob[0])+(y_ptr[1]-user_ptr->ob[1])*(y_ptr[1]-user_ptr->ob[1]); 559 560 /* Reset initial conditions for the adjoint integration */ 561 PetscCall(VecGetArray(user_ptr->Lambda[0],&x_ptr)); 562 x_ptr[0] = 2.*(y_ptr[0]-user_ptr->ob[0]); 563 x_ptr[1] = 2.*(y_ptr[1]-user_ptr->ob[1]); 564 PetscCall(VecRestoreArrayRead(user_ptr->U,&y_ptr)); 565 PetscCall(VecRestoreArray(user_ptr->Lambda[0],&x_ptr)); 566 567 PetscCall(VecGetArray(user_ptr->Mup[0],&x_ptr)); 568 x_ptr[0] = 0.0; 569 PetscCall(VecRestoreArray(user_ptr->Mup[0],&x_ptr)); 570 PetscCall(TSSetCostGradients(ts,1,user_ptr->Lambda,user_ptr->Mup)); 571 572 PetscCall(TSAdjointSolve(ts)); 573 574 PetscCall(VecGetArray(user_ptr->Mup[0],&x_ptr)); 575 PetscCall(VecGetArrayRead(user_ptr->Lambda[0],&y_ptr)); 576 PetscCall(VecGetArray(G,&g)); 577 g[0] = y_ptr[1]*(-10.0/(81.0*user_ptr->mu*user_ptr->mu)+2.0*292.0/(2187.0*user_ptr->mu*user_ptr->mu*user_ptr->mu))+x_ptr[0]; 578 PetscCall(VecRestoreArray(user_ptr->Mup[0],&x_ptr)); 579 PetscCall(VecRestoreArrayRead(user_ptr->Lambda[0],&y_ptr)); 580 PetscCall(VecRestoreArray(G,&g)); 581 PetscFunctionReturn(0); 582 } 583 584 PetscErrorCode FormHessian(Tao tao,Vec P,Mat H,Mat Hpre,void *ctx) 585 { 586 User user_ptr = (User)ctx; 587 PetscScalar harr[1]; 588 const PetscInt rows[1] = {0}; 589 PetscInt col = 0; 590 591 PetscFunctionBeginUser; 592 PetscCall(Adjoint2(P,harr,user_ptr)); 593 PetscCall(MatSetValues(H,1,rows,1,&col,harr,INSERT_VALUES)); 594 595 PetscCall(MatAssemblyBegin(H,MAT_FINAL_ASSEMBLY)); 596 PetscCall(MatAssemblyEnd(H,MAT_FINAL_ASSEMBLY)); 597 if (H != Hpre) { 598 PetscCall(MatAssemblyBegin(Hpre,MAT_FINAL_ASSEMBLY)); 599 PetscCall(MatAssemblyEnd(Hpre,MAT_FINAL_ASSEMBLY)); 600 } 601 PetscFunctionReturn(0); 602 } 603 604 PetscErrorCode Adjoint2(Vec P,PetscScalar arr[],User ctx) 605 { 606 TS ts = ctx->ts; 607 const PetscScalar *z_ptr; 608 PetscScalar *x_ptr,*y_ptr,dzdp,dzdp2; 609 Mat tlmsen; 610 611 PetscFunctionBeginUser; 612 /* Reset TSAdjoint so that AdjointSetUp will be called again */ 613 PetscCall(TSAdjointReset(ts)); 614 615 /* The directional vector should be 1 since it is one-dimensional */ 616 PetscCall(VecGetArray(ctx->Dir,&x_ptr)); 617 x_ptr[0] = 1.; 618 PetscCall(VecRestoreArray(ctx->Dir,&x_ptr)); 619 620 PetscCall(VecGetArrayRead(P,&z_ptr)); 621 ctx->mu = z_ptr[0]; 622 PetscCall(VecRestoreArrayRead(P,&z_ptr)); 623 624 dzdp = -10.0/(81.0*ctx->mu*ctx->mu) + 2.0*292.0/(2187.0*ctx->mu*ctx->mu*ctx->mu); 625 dzdp2 = 2.*10.0/(81.0*ctx->mu*ctx->mu*ctx->mu) - 3.0*2.0*292.0/(2187.0*ctx->mu*ctx->mu*ctx->mu*ctx->mu); 626 627 PetscCall(TSSetTime(ts,0.0)); 628 PetscCall(TSSetStepNumber(ts,0)); 629 PetscCall(TSSetTimeStep(ts,PetscRealConstant(0.001))); /* can be overwritten by command line options */ 630 PetscCall(TSSetFromOptions(ts)); 631 PetscCall(TSSetCostHessianProducts(ts,1,ctx->Lambda2,ctx->Mup2,ctx->Dir)); 632 633 PetscCall(MatZeroEntries(ctx->Jacp)); 634 PetscCall(MatSetValue(ctx->Jacp,1,0,dzdp,INSERT_VALUES)); 635 PetscCall(MatAssemblyBegin(ctx->Jacp,MAT_FINAL_ASSEMBLY)); 636 PetscCall(MatAssemblyEnd(ctx->Jacp,MAT_FINAL_ASSEMBLY)); 637 638 PetscCall(TSAdjointSetForward(ts,ctx->Jacp)); 639 PetscCall(VecGetArray(ctx->U,&y_ptr)); 640 y_ptr[0] = 2.0; 641 y_ptr[1] = -2.0/3.0 + 10.0/(81.0*ctx->mu) - 292.0/(2187.0*ctx->mu*ctx->mu); 642 PetscCall(VecRestoreArray(ctx->U,&y_ptr)); 643 PetscCall(TSSolve(ts,ctx->U)); 644 645 /* Set terminal conditions for first- and second-order adjonts */ 646 PetscCall(VecGetArrayRead(ctx->U,&z_ptr)); 647 PetscCall(VecGetArray(ctx->Lambda[0],&y_ptr)); 648 y_ptr[0] = 2.*(z_ptr[0]-ctx->ob[0]); 649 y_ptr[1] = 2.*(z_ptr[1]-ctx->ob[1]); 650 PetscCall(VecRestoreArray(ctx->Lambda[0],&y_ptr)); 651 PetscCall(VecRestoreArrayRead(ctx->U,&z_ptr)); 652 PetscCall(VecGetArray(ctx->Mup[0],&y_ptr)); 653 y_ptr[0] = 0.0; 654 PetscCall(VecRestoreArray(ctx->Mup[0],&y_ptr)); 655 PetscCall(TSForwardGetSensitivities(ts,NULL,&tlmsen)); 656 PetscCall(MatDenseGetColumn(tlmsen,0,&x_ptr)); 657 PetscCall(VecGetArray(ctx->Lambda2[0],&y_ptr)); 658 y_ptr[0] = 2.*x_ptr[0]; 659 y_ptr[1] = 2.*x_ptr[1]; 660 PetscCall(VecRestoreArray(ctx->Lambda2[0],&y_ptr)); 661 PetscCall(VecGetArray(ctx->Mup2[0],&y_ptr)); 662 y_ptr[0] = 0.0; 663 PetscCall(VecRestoreArray(ctx->Mup2[0],&y_ptr)); 664 PetscCall(MatDenseRestoreColumn(tlmsen,&x_ptr)); 665 PetscCall(TSSetCostGradients(ts,1,ctx->Lambda,ctx->Mup)); 666 if (ctx->implicitform) { 667 PetscCall(TSSetIHessianProduct(ts,ctx->Ihp1,IHessianProductUU,ctx->Ihp2,IHessianProductUP,ctx->Ihp3,IHessianProductPU,ctx->Ihp4,IHessianProductPP,ctx)); 668 } else { 669 PetscCall(TSSetRHSHessianProduct(ts,ctx->Ihp1,RHSHessianProductUU,ctx->Ihp2,RHSHessianProductUP,ctx->Ihp3,RHSHessianProductPU,ctx->Ihp4,RHSHessianProductPP,ctx)); 670 } 671 PetscCall(TSAdjointSolve(ts)); 672 673 PetscCall(VecGetArray(ctx->Lambda[0],&x_ptr)); 674 PetscCall(VecGetArray(ctx->Lambda2[0],&y_ptr)); 675 PetscCall(VecGetArrayRead(ctx->Mup2[0],&z_ptr)); 676 677 arr[0] = x_ptr[1]*dzdp2 + y_ptr[1]*dzdp2 + z_ptr[0]; 678 679 PetscCall(VecRestoreArray(ctx->Lambda2[0],&x_ptr)); 680 PetscCall(VecRestoreArray(ctx->Lambda2[0],&y_ptr)); 681 PetscCall(VecRestoreArrayRead(ctx->Mup2[0],&z_ptr)); 682 683 /* Disable second-order adjoint mode */ 684 PetscCall(TSAdjointReset(ts)); 685 PetscCall(TSAdjointResetForward(ts)); 686 PetscFunctionReturn(0); 687 } 688 689 /*TEST 690 build: 691 requires: !complex !single 692 test: 693 args: -implicitform 0 -ts_type rk -ts_adapt_type none -mu 10 -ts_dt 0.1 -viewer_binary_skip_info -tao_monitor -tao_view 694 output_file: output/ex20opt_p_1.out 695 696 test: 697 suffix: 2 698 args: -implicitform 0 -ts_type rk -ts_adapt_type none -mu 10 -ts_dt 0.01 -viewer_binary_skip_info -tao_monitor -tao_type bntr -tao_bnk_pc_type none 699 output_file: output/ex20opt_p_2.out 700 701 test: 702 suffix: 3 703 args: -ts_type cn -ts_adapt_type none -mu 100 -ts_dt 0.01 -viewer_binary_skip_info -tao_monitor -tao_view 704 output_file: output/ex20opt_p_3.out 705 706 test: 707 suffix: 4 708 args: -ts_type cn -ts_adapt_type none -mu 100 -ts_dt 0.01 -viewer_binary_skip_info -tao_monitor -tao_type bntr -tao_bnk_pc_type none 709 output_file: output/ex20opt_p_4.out 710 711 TEST*/ 712