Actual source code: ex3opt.c

petsc-3.7.2 2016-06-05
Report Typos and Errors
  2: static char help[] = "Finds optimal parameter P_m for the generator system while maintaining generator stability.\n";


\begin{eqnarray}
\frac{d \theta}{dt} = \omega_b (\omega - \omega_s)
\frac{2 H}{\omega_s}\frac{d \omega}{dt} & = & P_m - P_max \sin(\theta) -D(\omega - \omega_s)\\
\end{eqnarray}

 13: /*
 14:   This code demonstrates how to solve a ODE-constrained optimization problem with TAO, TSEvent, TSAdjoint and TS.
 15:   The problem features discontinuities and a cost function in integral form.
 16:   The gradient is computed with the discrete adjoint of an implicit theta method, see ex3adj.c for details.
 17: */
 18: #include <petsctao.h>
 19: #include <petscts.h>

 21: typedef struct {
 22:   PetscScalar H,D,omega_b,omega_s,Pmax,Pmax_ini,Pm,E,V,X,u_s,c;
 23:   PetscInt    beta;
 24:   PetscReal   tf,tcl;
 25: } AppCtx;

 27: PetscErrorCode FormFunctionGradient(Tao,Vec,PetscReal*,Vec,void*);

 29: /* Event check */
 32: PetscErrorCode EventFunction(TS ts,PetscReal t,Vec X,PetscScalar *fvalue,void *ctx)
 33: {
 34:   AppCtx        *user=(AppCtx*)ctx;

 37:   /* Event for fault-on time */
 38:   fvalue[0] = t - user->tf;
 39:   /* Event for fault-off time */
 40:   fvalue[1] = t - user->tcl;

 42:   return(0);
 43: }

 47: PetscErrorCode PostEventFunction(TS ts,PetscInt nevents,PetscInt event_list[],PetscReal t,Vec X,PetscBool forwardsolve,void* ctx)
 48: {
 49:   AppCtx *user=(AppCtx*)ctx;


 53:   if (event_list[0] == 0) {
 54:     if (forwardsolve) user->Pmax = 0.0; /* Apply disturbance - this is done by setting Pmax = 0 */
 55:     else user->Pmax = user->Pmax_ini; /* Going backward, reversal of event */
 56:   } else if(event_list[0] == 1) {
 57:     if (forwardsolve) user->Pmax = user->Pmax_ini; /* Remove the fault  - this is done by setting Pmax = Pmax_ini */
 58:     else user->Pmax = 0.0; /* Going backward, reversal of event */
 59:   }
 60:   return(0);
 61: }

 65: /*
 66:      Defines the ODE passed to the ODE solver
 67: */
 68: static PetscErrorCode IFunction(TS ts,PetscReal t,Vec U,Vec Udot,Vec F,AppCtx *ctx)
 69: {
 70:   PetscErrorCode    ierr;
 71:   PetscScalar       *f,Pmax;
 72:   const PetscScalar *u,*udot;

 75:   /*  The next three lines allow us to access the entries of the vectors directly */
 76:   VecGetArrayRead(U,&u);
 77:   VecGetArrayRead(Udot,&udot);
 78:   VecGetArray(F,&f);
 79:   Pmax = ctx->Pmax;
 80:   f[0] = udot[0] - ctx->omega_b*(u[1] - ctx->omega_s);
 81:   f[1] = 2.0*ctx->H/ctx->omega_s*udot[1] +  Pmax*PetscSinScalar(u[0]) + ctx->D*(u[1] - ctx->omega_s)- ctx->Pm;

 83:   VecRestoreArrayRead(U,&u);
 84:   VecRestoreArrayRead(Udot,&udot);
 85:   VecRestoreArray(F,&f);
 86:   return(0);
 87: }

 91: /*
 92:      Defines the Jacobian of the ODE passed to the ODE solver. See TSSetIJacobian() for the meaning of a and the Jacobian.
 93: */
 94: static PetscErrorCode IJacobian(TS ts,PetscReal t,Vec U,Vec Udot,PetscReal a,Mat A,Mat B,AppCtx *ctx)
 95: {
 96:   PetscErrorCode    ierr;
 97:   PetscInt          rowcol[] = {0,1};
 98:   PetscScalar       J[2][2],Pmax;
 99:   const PetscScalar *u,*udot;

102:   VecGetArrayRead(U,&u);
103:   VecGetArrayRead(Udot,&udot);
104:   Pmax = ctx->Pmax;
105:   J[0][0] = a;                       J[0][1] = -ctx->omega_b;
106:   J[1][1] = 2.0*ctx->H/ctx->omega_s*a + ctx->D;   J[1][0] = Pmax*PetscCosScalar(u[0]);

108:   MatSetValues(B,2,rowcol,2,rowcol,&J[0][0],INSERT_VALUES);
109:   VecRestoreArrayRead(U,&u);
110:   VecRestoreArrayRead(Udot,&udot);

112:   MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY);
113:   MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY);
114:   if (A != B) {
115:     MatAssemblyBegin(B,MAT_FINAL_ASSEMBLY);
116:     MatAssemblyEnd(B,MAT_FINAL_ASSEMBLY);
117:   }
118:   return(0);
119: }

123: static PetscErrorCode RHSJacobianP(TS ts,PetscReal t,Vec X,Mat A,void *ctx0)
124: {
126:   PetscInt       row[] = {0,1},col[]={0};
127:   PetscScalar    J[2][1];

130:   J[0][0] = 0;
131:   J[1][0] = 1.;
132:   MatSetValues(A,2,row,1,col,&J[0][0],INSERT_VALUES);
133:   MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY);
134:   MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY);
135:   return(0);
136: }

140: static PetscErrorCode CostIntegrand(TS ts,PetscReal t,Vec U,Vec R,AppCtx *ctx)
141: {
142:   PetscErrorCode    ierr;
143:   PetscScalar       *r;
144:   const PetscScalar *u;

147:   VecGetArrayRead(U,&u);
148:   VecGetArray(R,&r);
149:   r[0] = ctx->c*PetscPowScalarInt(PetscMax(0., u[0]-ctx->u_s),ctx->beta);
150:   VecRestoreArray(R,&r);
151:   VecRestoreArrayRead(U,&u);
152:   return(0);
153: }

157: static PetscErrorCode DRDYFunction(TS ts,PetscReal t,Vec U,Vec *drdy,AppCtx *ctx)
158: {
159:   PetscErrorCode     ierr;
160:   PetscScalar        *ry;
161:   const PetscScalar  *u;

164:   VecGetArrayRead(U,&u);
165:   VecGetArray(drdy[0],&ry);
166:   ry[0] = ctx->c*ctx->beta*PetscPowScalarInt(PetscMax(0., u[0]-ctx->u_s),ctx->beta-1);
167:   VecRestoreArray(drdy[0],&ry);
168:   VecRestoreArrayRead(U,&u);
169:   return(0);
170: }

174: static PetscErrorCode DRDPFunction(TS ts,PetscReal t,Vec U,Vec *drdp,AppCtx *ctx)
175: {
177:   PetscScalar    *rp;

180:   VecGetArray(drdp[0],&rp);
181:   rp[0] = 0.;
182:   VecRestoreArray(drdp[0],&rp);
183:   return(0);
184: }

188: PetscErrorCode ComputeSensiP(Vec lambda,Vec mu,AppCtx *ctx)
189: {
190:   PetscErrorCode    ierr;
191:   PetscScalar       *y,sensip;
192:   const PetscScalar *x;

195:   VecGetArrayRead(lambda,&x);
196:   VecGetArray(mu,&y);
197:   sensip = 1./PetscSqrtScalar(1.-(ctx->Pm/ctx->Pmax)*(ctx->Pm/ctx->Pmax))/ctx->Pmax*x[0]+y[0];
198:   /* PetscPrintf(PETSC_COMM_WORLD,"\n sensitivity wrt parameter pm: %g \n",(double)sensip); */
199:   y[0] = sensip;
200:   VecRestoreArray(mu,&y);
201:   VecRestoreArrayRead(lambda,&x);
202:   return(0);
203: }

207: int main(int argc,char **argv)
208: {
209:   Vec                p;
210:   PetscScalar        *x_ptr;
211:   PetscErrorCode     ierr;
212:   PetscMPIInt        size;
213:   AppCtx             ctx;
214:   Tao                tao;
215:   KSP                ksp;
216:   PC                 pc;
217:   Vec                lowerb,upperb;

219:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
220:      Initialize program
221:      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
222:   PetscInitialize(&argc,&argv,NULL,help);
224:   MPI_Comm_size(PETSC_COMM_WORLD,&size);
225:   if (size != 1) SETERRQ(PETSC_COMM_SELF,1,"This is a uniprocessor example only!");

227:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
228:     Set runtime options
229:     - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
230:   PetscOptionsBegin(PETSC_COMM_WORLD,NULL,"Swing equation options","");
231:   {
232:     ctx.beta    = 2;
233:     ctx.c       = 10000.0;
234:     ctx.u_s     = 1.0;
235:     ctx.omega_s = 1.0;
236:     ctx.omega_b = 120.0*PETSC_PI;
237:     ctx.H       = 5.0;
238:     PetscOptionsScalar("-Inertia","","",ctx.H,&ctx.H,NULL);
239:     ctx.D       = 5.0;
240:     PetscOptionsScalar("-D","","",ctx.D,&ctx.D,NULL);
241:     ctx.E       = 1.1378;
242:     ctx.V       = 1.0;
243:     ctx.X       = 0.545;
244:     ctx.Pmax    = ctx.E*ctx.V/ctx.X;;
245:     ctx.Pmax_ini = ctx.Pmax;
246:     PetscOptionsScalar("-Pmax","","",ctx.Pmax,&ctx.Pmax,NULL);
247:     ctx.Pm      = 1.06161;
248:     PetscOptionsScalar("-Pm","","",ctx.Pm,&ctx.Pm,NULL);
249:     ctx.tf      = 0.1;
250:     ctx.tcl     = 0.2;
251:     PetscOptionsReal("-tf","Time to start fault","",ctx.tf,&ctx.tf,NULL);
252:     PetscOptionsReal("-tcl","Time to end fault","",ctx.tcl,&ctx.tcl,NULL);

254:   }
255:   PetscOptionsEnd();

257:   /* Create TAO solver and set desired solution method */
258:   TaoCreate(PETSC_COMM_WORLD,&tao);
259:   TaoSetType(tao,TAOBLMVM);

261:   /*
262:      Optimization starts
263:   */
264:   /* Set initial solution guess */
265:   VecCreateSeq(PETSC_COMM_WORLD,1,&p);
266:   VecGetArray(p,&x_ptr);
267:   x_ptr[0] = ctx.Pm;
268:   VecRestoreArray(p,&x_ptr);

270:   TaoSetInitialVector(tao,p);
271:   /* Set routine for function and gradient evaluation */
272:   TaoSetObjectiveAndGradientRoutine(tao,FormFunctionGradient,(void *)&ctx);

274:   /* Set bounds for the optimization */
275:   VecDuplicate(p,&lowerb);
276:   VecDuplicate(p,&upperb);
277:   VecGetArray(lowerb,&x_ptr);
278:   x_ptr[0] = 0.;
279:   VecRestoreArray(lowerb,&x_ptr);
280:   VecGetArray(upperb,&x_ptr);
281:   x_ptr[0] = 1.1;
282:   VecRestoreArray(upperb,&x_ptr);
283:   TaoSetVariableBounds(tao,lowerb,upperb);

285:   /* Check for any TAO command line options */
286:   TaoSetFromOptions(tao);
287:   TaoGetKSP(tao,&ksp);
288:   if (ksp) {
289:     KSPGetPC(ksp,&pc);
290:     PCSetType(pc,PCNONE);
291:   }

293:   TaoSetTolerances(tao,1e-12,1e-12,1e-12);
294:   /* SOLVE THE APPLICATION */
295:   TaoSolve(tao);

297:   VecView(p,PETSC_VIEWER_STDOUT_WORLD);
298:   VecDestroy(&p);
299:   VecDestroy(&lowerb);
300:   VecDestroy(&upperb);
301:   TaoDestroy(&tao);
302:   PetscFinalize();
303:   return 0;
304: }

306: /* ------------------------------------------------------------------ */
309: /*
310:    FormFunctionGradient - Evaluates the function and corresponding gradient.

312:    Input Parameters:
313:    tao - the Tao context
314:    X   - the input vector
315:    ptr - optional user-defined context, as set by TaoSetObjectiveAndGradientRoutine()

317:    Output Parameters:
318:    f   - the newly evaluated function
319:    G   - the newly evaluated gradient
320: */
321: PetscErrorCode FormFunctionGradient(Tao tao,Vec P,PetscReal *f,Vec G,void *ctx0)
322: {
323:   AppCtx         *ctx = (AppCtx*)ctx0;
324:   TS             ts;
325:   Vec            U;             /* solution will be stored here */
326:   Mat            A;             /* Jacobian matrix */
327:   Mat            Jacp;          /* Jacobian matrix */
329:   PetscInt       n = 2;
330:   PetscReal      ftime;
331:   PetscInt       steps;
332:   PetscScalar    *u;
333:   PetscScalar    *x_ptr,*y_ptr;
334:   Vec            lambda[1],q,mu[1];
335:   PetscInt       direction[2];
336:   PetscBool      terminate[2];

338:   VecGetArray(P,&x_ptr);
339:   ctx->Pm = x_ptr[0];
340:   VecRestoreArray(P,&x_ptr);

342:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
343:     Create necessary matrix and vectors
344:     - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
345:   MatCreate(PETSC_COMM_WORLD,&A);
346:   MatSetSizes(A,n,n,PETSC_DETERMINE,PETSC_DETERMINE);
347:   MatSetType(A,MATDENSE);
348:   MatSetFromOptions(A);
349:   MatSetUp(A);

351:   MatCreateVecs(A,&U,NULL);

353:   MatCreate(PETSC_COMM_WORLD,&Jacp);
354:   MatSetSizes(Jacp,PETSC_DECIDE,PETSC_DECIDE,2,1);
355:   MatSetFromOptions(Jacp);
356:   MatSetUp(Jacp);

358:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
359:      Create timestepping solver context
360:      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
361:   TSCreate(PETSC_COMM_WORLD,&ts);
362:   TSSetProblemType(ts,TS_NONLINEAR);
363:   TSSetType(ts,TSCN);
364:   TSSetIFunction(ts,NULL,(TSIFunction) IFunction,ctx);
365:   TSSetIJacobian(ts,A,A,(TSIJacobian)IJacobian,ctx);
366:   TSSetExactFinalTime(ts,TS_EXACTFINALTIME_MATCHSTEP);

368:   TSSetCostIntegrand(ts,1,(PetscErrorCode (*)(TS,PetscReal,Vec,Vec,void*))CostIntegrand,
369:                                         (PetscErrorCode (*)(TS,PetscReal,Vec,Vec*,void*))DRDYFunction,
370:                                         (PetscErrorCode (*)(TS,PetscReal,Vec,Vec*,void*))DRDPFunction,PETSC_TRUE,ctx);

372:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
373:      Set initial conditions
374:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
375:   VecGetArray(U,&u);
376:   u[0] = PetscAsinScalar(ctx->Pm/ctx->Pmax);
377:   u[1] = 1.0;
378:   VecRestoreArray(U,&u);
379:   TSSetSolution(ts,U);

381:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
382:     Save trajectory of solution so that TSAdjointSolve() may be used
383:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
384:   TSSetSaveTrajectory(ts);

386:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
387:      Set solver options
388:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
389:   TSSetDuration(ts,PETSC_DEFAULT,1.0);
390:   TSSetExactFinalTime(ts,TS_EXACTFINALTIME_STEPOVER);
391:   TSSetInitialTimeStep(ts,0.0,.01);
392:   TSSetFromOptions(ts);

394:   direction[0] = direction[1] = 1;
395:   terminate[0] = terminate[1] = PETSC_FALSE;

397:   TSSetEventHandler(ts,2,direction,terminate,EventFunction,PostEventFunction,(void*)ctx);

399:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
400:      Solve nonlinear system
401:      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
402:   TSSolve(ts,U);

404:   TSGetSolveTime(ts,&ftime);
405:   TSGetTimeStepNumber(ts,&steps);
406:   /* VecView(U,PETSC_VIEWER_STDOUT_WORLD); */

408:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
409:      Adjoint model starts here
410:      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
411:   MatCreateVecs(A,&lambda[0],NULL);
412:   /*   Set initial conditions for the adjoint integration */
413:   VecGetArray(lambda[0],&y_ptr);
414:   y_ptr[0] = 0.0; y_ptr[1] = 0.0;
415:   VecRestoreArray(lambda[0],&y_ptr);

417:   MatCreateVecs(Jacp,&mu[0],NULL);
418:   VecGetArray(mu[0],&x_ptr);
419:   x_ptr[0] = -1.0;
420:   VecRestoreArray(mu[0],&x_ptr);
421:   TSSetCostGradients(ts,1,lambda,mu);

423:   /*   Set RHS JacobianP */
424:   TSAdjointSetRHSJacobian(ts,Jacp,RHSJacobianP,ctx);

426:   TSAdjointSolve(ts);
427:   TSGetCostIntegral(ts,&q);
428:   /* VecView(q,PETSC_VIEWER_STDOUT_WORLD); */
429:   ComputeSensiP(lambda[0],mu[0],ctx);
430:   VecCopy(mu[0],G);

432:   TSGetCostIntegral(ts,&q);
433:   VecGetArray(q,&x_ptr);
434:   *f   = -ctx->Pm + x_ptr[0];
435:   VecRestoreArray(q,&x_ptr);

437:   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
438:      Free work space.  All PETSc objects should be destroyed when they are no longer needed.
439:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
440:   MatDestroy(&A);
441:   MatDestroy(&Jacp);
442:   VecDestroy(&U);
443:   VecDestroy(&lambda[0]);
444:   VecDestroy(&mu[0]);
445:   TSDestroy(&ts);

447:   return 0;
448: }