xref: /petsc/src/ts/tutorials/power_grid/stability_9bus/ex9busoptfd.c (revision daa037dfd3c3bec8dc8659548d2b20b07c1dc6de)
1 static char help[] = "Using finite difference for the problem in ex9busopt.c \n\n";
2 
3 /*
4   Use finite difference approximations to solve the same optimization problem as in ex9busopt.c.
5  */
6 
7 #include <petsctao.h>
8 #include <petscts.h>
9 #include <petscdm.h>
10 #include <petscdmda.h>
11 #include <petscdmcomposite.h>
12 
13 PetscErrorCode FormFunction(Tao,Vec,PetscReal*,void*);
14 
15 #define freq 60
16 #define w_s (2*PETSC_PI*freq)
17 
18 /* Sizes and indices */
19 const PetscInt nbus    = 9; /* Number of network buses */
20 const PetscInt ngen    = 3; /* Number of generators */
21 const PetscInt nload   = 3; /* Number of loads */
22 const PetscInt gbus[3] = {0,1,2}; /* Buses at which generators are incident */
23 const PetscInt lbus[3] = {4,5,7}; /* Buses at which loads are incident */
24 
25 /* Generator real and reactive powers (found via loadflow) */
26 PetscScalar PG[3] = { 0.69,1.59,0.69};
27 /* PetscScalar PG[3] = {0.716786142395021,1.630000000000000,0.850000000000000};*/
28 const PetscScalar QG[3] = {0.270702180178785,0.066120127797275,-0.108402221791588};
29 /* Generator constants */
30 const PetscScalar H[3]    = {23.64,6.4,3.01};   /* Inertia constant */
31 const PetscScalar Rs[3]   = {0.0,0.0,0.0}; /* Stator Resistance */
32 const PetscScalar Xd[3]   = {0.146,0.8958,1.3125};  /* d-axis reactance */
33 const PetscScalar Xdp[3]  = {0.0608,0.1198,0.1813}; /* d-axis transient reactance */
34 const PetscScalar Xq[3]   = {0.4360,0.8645,1.2578}; /* q-axis reactance Xq(1) set to 0.4360, value given in text 0.0969 */
35 const PetscScalar Xqp[3]  = {0.0969,0.1969,0.25}; /* q-axis transient reactance */
36 const PetscScalar Td0p[3] = {8.96,6.0,5.89}; /* d-axis open circuit time constant */
37 const PetscScalar Tq0p[3] = {0.31,0.535,0.6}; /* q-axis open circuit time constant */
38 PetscScalar M[3]; /* M = 2*H/w_s */
39 PetscScalar D[3]; /* D = 0.1*M */
40 
41 PetscScalar TM[3]; /* Mechanical Torque */
42 /* Exciter system constants */
43 const PetscScalar KA[3] = {20.0,20.0,20.0};  /* Voltage regulartor gain constant */
44 const PetscScalar TA[3] = {0.2,0.2,0.2};     /* Voltage regulator time constant */
45 const PetscScalar KE[3] = {1.0,1.0,1.0};     /* Exciter gain constant */
46 const PetscScalar TE[3] = {0.314,0.314,0.314}; /* Exciter time constant */
47 const PetscScalar KF[3] = {0.063,0.063,0.063};  /* Feedback stabilizer gain constant */
48 const PetscScalar TF[3] = {0.35,0.35,0.35};    /* Feedback stabilizer time constant */
49 const PetscScalar k1[3] = {0.0039,0.0039,0.0039};
50 const PetscScalar k2[3] = {1.555,1.555,1.555};  /* k1 and k2 for calculating the saturation function SE = k1*exp(k2*Efd) */
51 
52 PetscScalar Vref[3];
53 /* Load constants
54   We use a composite load model that describes the load and reactive powers at each time instant as follows
55   P(t) = \sum\limits_{i=0}^ld_nsegsp \ld_alphap_i*P_D0(\frac{V_m(t)}{V_m0})^\ld_betap_i
56   Q(t) = \sum\limits_{i=0}^ld_nsegsq \ld_alphaq_i*Q_D0(\frac{V_m(t)}{V_m0})^\ld_betaq_i
57   where
58     ld_nsegsp,ld_nsegsq - Number of individual load models for real and reactive power loads
59     ld_alphap,ld_alphap - Percentage contribution (weights) or loads
60     P_D0                - Real power load
61     Q_D0                - Reactive power load
62     V_m(t)              - Voltage magnitude at time t
63     V_m0                - Voltage magnitude at t = 0
64     ld_betap, ld_betaq  - exponents describing the load model for real and reactive part
65 
66     Note: All loads have the same characteristic currently.
67 */
68 const PetscScalar PD0[3] = {1.25,0.9,1.0};
69 const PetscScalar QD0[3] = {0.5,0.3,0.35};
70 const PetscInt    ld_nsegsp[3] = {3,3,3};
71 const PetscScalar ld_alphap[3] = {1.0,0.0,0.0};
72 const PetscScalar ld_betap[3]  = {2.0,1.0,0.0};
73 const PetscInt    ld_nsegsq[3] = {3,3,3};
74 const PetscScalar ld_alphaq[3] = {1.0,0.0,0.0};
75 const PetscScalar ld_betaq[3]  = {2.0,1.0,0.0};
76 
77 typedef struct {
78   DM          dmgen, dmnet; /* DMs to manage generator and network subsystem */
79   DM          dmpgrid; /* Composite DM to manage the entire power grid */
80   Mat         Ybus; /* Network admittance matrix */
81   Vec         V0;  /* Initial voltage vector (Power flow solution) */
82   PetscReal   tfaulton,tfaultoff; /* Fault on and off times */
83   PetscInt    faultbus; /* Fault bus */
84   PetscScalar Rfault;
85   PetscReal   t0,tmax;
86   PetscInt    neqs_gen,neqs_net,neqs_pgrid;
87   Mat         Sol; /* Matrix to save solution at each time step */
88   PetscInt    stepnum;
89   PetscBool   alg_flg;
90   PetscReal   t;
91   IS          is_diff; /* indices for differential equations */
92   IS          is_alg; /* indices for algebraic equations */
93   PetscReal   freq_u,freq_l; /* upper and lower frequency limit */
94   PetscInt    pow; /* power coefficient used in the cost function */
95   Vec         vec_q;
96 } Userctx;
97 
98 /* Converts from machine frame (dq) to network (phase a real,imag) reference frame */
99 PetscErrorCode dq2ri(PetscScalar Fd,PetscScalar Fq,PetscScalar delta,PetscScalar *Fr, PetscScalar *Fi)
100 {
101   PetscFunctionBegin;
102   *Fr =  Fd*PetscSinScalar(delta) + Fq*PetscCosScalar(delta);
103   *Fi = -Fd*PetscCosScalar(delta) + Fq*PetscSinScalar(delta);
104   PetscFunctionReturn(0);
105 }
106 
107 /* Converts from network frame ([phase a real,imag) to machine (dq) reference frame */
108 PetscErrorCode ri2dq(PetscScalar Fr,PetscScalar Fi,PetscScalar delta,PetscScalar *Fd, PetscScalar *Fq)
109 {
110   PetscFunctionBegin;
111   *Fd =  Fr*PetscSinScalar(delta) - Fi*PetscCosScalar(delta);
112   *Fq =  Fr*PetscCosScalar(delta) + Fi*PetscSinScalar(delta);
113   PetscFunctionReturn(0);
114 }
115 
116 PetscErrorCode SetInitialGuess(Vec X,Userctx *user)
117 {
118   Vec            Xgen,Xnet;
119   PetscScalar    *xgen,*xnet;
120   PetscInt       i,idx=0;
121   PetscScalar    Vr,Vi,IGr,IGi,Vm,Vm2;
122   PetscScalar    Eqp,Edp,delta;
123   PetscScalar    Efd,RF,VR; /* Exciter variables */
124   PetscScalar    Id,Iq;  /* Generator dq axis currents */
125   PetscScalar    theta,Vd,Vq,SE;
126 
127   PetscFunctionBegin;
128   M[0] = 2*H[0]/w_s; M[1] = 2*H[1]/w_s; M[2] = 2*H[2]/w_s;
129   D[0] = 0.1*M[0]; D[1] = 0.1*M[1]; D[2] = 0.1*M[2];
130 
131   PetscCall(DMCompositeGetLocalVectors(user->dmpgrid,&Xgen,&Xnet));
132 
133   /* Network subsystem initialization */
134   PetscCall(VecCopy(user->V0,Xnet));
135 
136   /* Generator subsystem initialization */
137   PetscCall(VecGetArray(Xgen,&xgen));
138   PetscCall(VecGetArray(Xnet,&xnet));
139 
140   for (i=0; i < ngen; i++) {
141     Vr  = xnet[2*gbus[i]]; /* Real part of generator terminal voltage */
142     Vi  = xnet[2*gbus[i]+1]; /* Imaginary part of the generator terminal voltage */
143     Vm  = PetscSqrtScalar(Vr*Vr + Vi*Vi); Vm2 = Vm*Vm;
144     IGr = (Vr*PG[i] + Vi*QG[i])/Vm2;
145     IGi = (Vi*PG[i] - Vr*QG[i])/Vm2;
146 
147     delta = PetscAtan2Real(Vi+Xq[i]*IGr,Vr-Xq[i]*IGi); /* Machine angle */
148 
149     theta = PETSC_PI/2.0 - delta;
150 
151     Id = IGr*PetscCosScalar(theta) - IGi*PetscSinScalar(theta); /* d-axis stator current */
152     Iq = IGr*PetscSinScalar(theta) + IGi*PetscCosScalar(theta); /* q-axis stator current */
153 
154     Vd = Vr*PetscCosScalar(theta) - Vi*PetscSinScalar(theta);
155     Vq = Vr*PetscSinScalar(theta) + Vi*PetscCosScalar(theta);
156 
157     Edp = Vd + Rs[i]*Id - Xqp[i]*Iq; /* d-axis transient EMF */
158     Eqp = Vq + Rs[i]*Iq + Xdp[i]*Id; /* q-axis transient EMF */
159 
160     TM[i] = PG[i];
161 
162     /* The generator variables are ordered as [Eqp,Edp,delta,w,Id,Iq] */
163     xgen[idx]   = Eqp;
164     xgen[idx+1] = Edp;
165     xgen[idx+2] = delta;
166     xgen[idx+3] = w_s;
167 
168     idx = idx + 4;
169 
170     xgen[idx]   = Id;
171     xgen[idx+1] = Iq;
172 
173     idx = idx + 2;
174 
175     /* Exciter */
176     Efd = Eqp + (Xd[i] - Xdp[i])*Id;
177     SE  = k1[i]*PetscExpScalar(k2[i]*Efd);
178     VR  =  KE[i]*Efd + SE;
179     RF  =  KF[i]*Efd/TF[i];
180 
181     xgen[idx]   = Efd;
182     xgen[idx+1] = RF;
183     xgen[idx+2] = VR;
184 
185     Vref[i] = Vm + (VR/KA[i]);
186 
187     idx = idx + 3;
188   }
189 
190   PetscCall(VecRestoreArray(Xgen,&xgen));
191   PetscCall(VecRestoreArray(Xnet,&xnet));
192 
193   /* PetscCall(VecView(Xgen,0)); */
194   PetscCall(DMCompositeGather(user->dmpgrid,INSERT_VALUES,X,Xgen,Xnet));
195   PetscCall(DMCompositeRestoreLocalVectors(user->dmpgrid,&Xgen,&Xnet));
196   PetscFunctionReturn(0);
197 }
198 
199 /* Computes F = [-f(x,y);g(x,y)] */
200 PetscErrorCode ResidualFunction(SNES snes,Vec X, Vec F, Userctx *user)
201 {
202   Vec            Xgen,Xnet,Fgen,Fnet;
203   PetscScalar    *xgen,*xnet,*fgen,*fnet;
204   PetscInt       i,idx=0;
205   PetscScalar    Vr,Vi,Vm,Vm2;
206   PetscScalar    Eqp,Edp,delta,w; /* Generator variables */
207   PetscScalar    Efd,RF,VR; /* Exciter variables */
208   PetscScalar    Id,Iq;  /* Generator dq axis currents */
209   PetscScalar    Vd,Vq,SE;
210   PetscScalar    IGr,IGi,IDr,IDi;
211   PetscScalar    Zdq_inv[4],det;
212   PetscScalar    PD,QD,Vm0,*v0;
213   PetscInt       k;
214 
215   PetscFunctionBegin;
216   PetscCall(VecZeroEntries(F));
217   PetscCall(DMCompositeGetLocalVectors(user->dmpgrid,&Xgen,&Xnet));
218   PetscCall(DMCompositeGetLocalVectors(user->dmpgrid,&Fgen,&Fnet));
219   PetscCall(DMCompositeScatter(user->dmpgrid,X,Xgen,Xnet));
220   PetscCall(DMCompositeScatter(user->dmpgrid,F,Fgen,Fnet));
221 
222   /* Network current balance residual IG + Y*V + IL = 0. Only YV is added here.
223      The generator current injection, IG, and load current injection, ID are added later
224   */
225   /* Note that the values in Ybus are stored assuming the imaginary current balance
226      equation is ordered first followed by real current balance equation for each bus.
227      Thus imaginary current contribution goes in location 2*i, and
228      real current contribution in 2*i+1
229   */
230   PetscCall(MatMult(user->Ybus,Xnet,Fnet));
231 
232   PetscCall(VecGetArray(Xgen,&xgen));
233   PetscCall(VecGetArray(Xnet,&xnet));
234   PetscCall(VecGetArray(Fgen,&fgen));
235   PetscCall(VecGetArray(Fnet,&fnet));
236 
237   /* Generator subsystem */
238   for (i=0; i < ngen; i++) {
239     Eqp   = xgen[idx];
240     Edp   = xgen[idx+1];
241     delta = xgen[idx+2];
242     w     = xgen[idx+3];
243     Id    = xgen[idx+4];
244     Iq    = xgen[idx+5];
245     Efd   = xgen[idx+6];
246     RF    = xgen[idx+7];
247     VR    = xgen[idx+8];
248 
249     /* Generator differential equations */
250     fgen[idx]   = (Eqp + (Xd[i] - Xdp[i])*Id - Efd)/Td0p[i];
251     fgen[idx+1] = (Edp - (Xq[i] - Xqp[i])*Iq)/Tq0p[i];
252     fgen[idx+2] = -w + w_s;
253     fgen[idx+3] = (-TM[i] + Edp*Id + Eqp*Iq + (Xqp[i] - Xdp[i])*Id*Iq + D[i]*(w - w_s))/M[i];
254 
255     Vr = xnet[2*gbus[i]]; /* Real part of generator terminal voltage */
256     Vi = xnet[2*gbus[i]+1]; /* Imaginary part of the generator terminal voltage */
257 
258     PetscCall(ri2dq(Vr,Vi,delta,&Vd,&Vq));
259     /* Algebraic equations for stator currents */
260     det = Rs[i]*Rs[i] + Xdp[i]*Xqp[i];
261 
262     Zdq_inv[0] = Rs[i]/det;
263     Zdq_inv[1] = Xqp[i]/det;
264     Zdq_inv[2] = -Xdp[i]/det;
265     Zdq_inv[3] = Rs[i]/det;
266 
267     fgen[idx+4] = Zdq_inv[0]*(-Edp + Vd) + Zdq_inv[1]*(-Eqp + Vq) + Id;
268     fgen[idx+5] = Zdq_inv[2]*(-Edp + Vd) + Zdq_inv[3]*(-Eqp + Vq) + Iq;
269 
270     /* Add generator current injection to network */
271     PetscCall(dq2ri(Id,Iq,delta,&IGr,&IGi));
272 
273     fnet[2*gbus[i]]   -= IGi;
274     fnet[2*gbus[i]+1] -= IGr;
275 
276     Vm = PetscSqrtScalar(Vd*Vd + Vq*Vq);
277 
278     SE = k1[i]*PetscExpScalar(k2[i]*Efd);
279 
280     /* Exciter differential equations */
281     fgen[idx+6] = (KE[i]*Efd + SE - VR)/TE[i];
282     fgen[idx+7] = (RF - KF[i]*Efd/TF[i])/TF[i];
283     fgen[idx+8] = (VR - KA[i]*RF + KA[i]*KF[i]*Efd/TF[i] - KA[i]*(Vref[i] - Vm))/TA[i];
284 
285     idx = idx + 9;
286   }
287 
288   PetscCall(VecGetArray(user->V0,&v0));
289   for (i=0; i < nload; i++) {
290     Vr  = xnet[2*lbus[i]]; /* Real part of load bus voltage */
291     Vi  = xnet[2*lbus[i]+1]; /* Imaginary part of the load bus voltage */
292     Vm  = PetscSqrtScalar(Vr*Vr + Vi*Vi); Vm2 = Vm*Vm;
293     Vm0 = PetscSqrtScalar(v0[2*lbus[i]]*v0[2*lbus[i]] + v0[2*lbus[i]+1]*v0[2*lbus[i]+1]);
294     PD  = QD = 0.0;
295     for (k=0; k < ld_nsegsp[i]; k++) PD += ld_alphap[k]*PD0[i]*PetscPowScalar((Vm/Vm0),ld_betap[k]);
296     for (k=0; k < ld_nsegsq[i]; k++) QD += ld_alphaq[k]*QD0[i]*PetscPowScalar((Vm/Vm0),ld_betaq[k]);
297 
298     /* Load currents */
299     IDr = (PD*Vr + QD*Vi)/Vm2;
300     IDi = (-QD*Vr + PD*Vi)/Vm2;
301 
302     fnet[2*lbus[i]]   += IDi;
303     fnet[2*lbus[i]+1] += IDr;
304   }
305   PetscCall(VecRestoreArray(user->V0,&v0));
306 
307   PetscCall(VecRestoreArray(Xgen,&xgen));
308   PetscCall(VecRestoreArray(Xnet,&xnet));
309   PetscCall(VecRestoreArray(Fgen,&fgen));
310   PetscCall(VecRestoreArray(Fnet,&fnet));
311 
312   PetscCall(DMCompositeGather(user->dmpgrid,INSERT_VALUES,F,Fgen,Fnet));
313   PetscCall(DMCompositeRestoreLocalVectors(user->dmpgrid,&Xgen,&Xnet));
314   PetscCall(DMCompositeRestoreLocalVectors(user->dmpgrid,&Fgen,&Fnet));
315   PetscFunctionReturn(0);
316 }
317 
318 /* \dot{x} - f(x,y)
319      g(x,y) = 0
320  */
321 PetscErrorCode IFunction(TS ts,PetscReal t, Vec X, Vec Xdot, Vec F, Userctx *user)
322 {
323   SNES              snes;
324   PetscScalar       *f;
325   const PetscScalar *xdot;
326   PetscInt          i;
327 
328   PetscFunctionBegin;
329   user->t = t;
330 
331   PetscCall(TSGetSNES(ts,&snes));
332   PetscCall(ResidualFunction(snes,X,F,user));
333   PetscCall(VecGetArray(F,&f));
334   PetscCall(VecGetArrayRead(Xdot,&xdot));
335   for (i=0;i < ngen;i++) {
336     f[9*i]   += xdot[9*i];
337     f[9*i+1] += xdot[9*i+1];
338     f[9*i+2] += xdot[9*i+2];
339     f[9*i+3] += xdot[9*i+3];
340     f[9*i+6] += xdot[9*i+6];
341     f[9*i+7] += xdot[9*i+7];
342     f[9*i+8] += xdot[9*i+8];
343   }
344   PetscCall(VecRestoreArray(F,&f));
345   PetscCall(VecRestoreArrayRead(Xdot,&xdot));
346   PetscFunctionReturn(0);
347 }
348 
349 /* This function is used for solving the algebraic system only during fault on and
350    off times. It computes the entire F and then zeros out the part corresponding to
351    differential equations
352  F = [0;g(y)];
353 */
354 PetscErrorCode AlgFunction(SNES snes, Vec X, Vec F, void *ctx)
355 {
356   Userctx        *user=(Userctx*)ctx;
357   PetscScalar    *f;
358   PetscInt       i;
359 
360   PetscFunctionBegin;
361   PetscCall(ResidualFunction(snes,X,F,user));
362   PetscCall(VecGetArray(F,&f));
363   for (i=0; i < ngen; i++) {
364     f[9*i]   = 0;
365     f[9*i+1] = 0;
366     f[9*i+2] = 0;
367     f[9*i+3] = 0;
368     f[9*i+6] = 0;
369     f[9*i+7] = 0;
370     f[9*i+8] = 0;
371   }
372   PetscCall(VecRestoreArray(F,&f));
373   PetscFunctionReturn(0);
374 }
375 
376 PetscErrorCode PreallocateJacobian(Mat J, Userctx *user)
377 {
378   PetscInt       *d_nnz;
379   PetscInt       i,idx=0,start=0;
380   PetscInt       ncols;
381 
382   PetscFunctionBegin;
383   PetscCall(PetscMalloc1(user->neqs_pgrid,&d_nnz));
384   for (i=0; i<user->neqs_pgrid; i++) d_nnz[i] = 0;
385   /* Generator subsystem */
386   for (i=0; i < ngen; i++) {
387 
388     d_nnz[idx]   += 3;
389     d_nnz[idx+1] += 2;
390     d_nnz[idx+2] += 2;
391     d_nnz[idx+3] += 5;
392     d_nnz[idx+4] += 6;
393     d_nnz[idx+5] += 6;
394 
395     d_nnz[user->neqs_gen+2*gbus[i]]   += 3;
396     d_nnz[user->neqs_gen+2*gbus[i]+1] += 3;
397 
398     d_nnz[idx+6] += 2;
399     d_nnz[idx+7] += 2;
400     d_nnz[idx+8] += 5;
401 
402     idx = idx + 9;
403   }
404 
405   start = user->neqs_gen;
406 
407   for (i=0; i < nbus; i++) {
408     PetscCall(MatGetRow(user->Ybus,2*i,&ncols,NULL,NULL));
409     d_nnz[start+2*i]   += ncols;
410     d_nnz[start+2*i+1] += ncols;
411     PetscCall(MatRestoreRow(user->Ybus,2*i,&ncols,NULL,NULL));
412   }
413 
414   PetscCall(MatSeqAIJSetPreallocation(J,0,d_nnz));
415 
416   PetscCall(PetscFree(d_nnz));
417   PetscFunctionReturn(0);
418 }
419 
420 /*
421    J = [-df_dx, -df_dy
422         dg_dx, dg_dy]
423 */
424 PetscErrorCode ResidualJacobian(SNES snes,Vec X,Mat J,Mat B,void *ctx)
425 {
426   Userctx           *user=(Userctx*)ctx;
427   Vec               Xgen,Xnet;
428   PetscScalar       *xgen,*xnet;
429   PetscInt          i,idx=0;
430   PetscScalar       Vr,Vi,Vm,Vm2;
431   PetscScalar       Eqp,Edp,delta; /* Generator variables */
432   PetscScalar       Efd; /* Exciter variables */
433   PetscScalar       Id,Iq;  /* Generator dq axis currents */
434   PetscScalar       Vd,Vq;
435   PetscScalar       val[10];
436   PetscInt          row[2],col[10];
437   PetscInt          net_start=user->neqs_gen;
438   PetscScalar       Zdq_inv[4],det;
439   PetscScalar       dVd_dVr,dVd_dVi,dVq_dVr,dVq_dVi,dVd_ddelta,dVq_ddelta;
440   PetscScalar       dIGr_ddelta,dIGi_ddelta,dIGr_dId,dIGr_dIq,dIGi_dId,dIGi_dIq;
441   PetscScalar       dSE_dEfd;
442   PetscScalar       dVm_dVd,dVm_dVq,dVm_dVr,dVm_dVi;
443   PetscInt          ncols;
444   const PetscInt    *cols;
445   const PetscScalar *yvals;
446   PetscInt          k;
447   PetscScalar       PD,QD,Vm0,*v0,Vm4;
448   PetscScalar       dPD_dVr,dPD_dVi,dQD_dVr,dQD_dVi;
449   PetscScalar       dIDr_dVr,dIDr_dVi,dIDi_dVr,dIDi_dVi;
450 
451   PetscFunctionBegin;
452   PetscCall(MatZeroEntries(B));
453   PetscCall(DMCompositeGetLocalVectors(user->dmpgrid,&Xgen,&Xnet));
454   PetscCall(DMCompositeScatter(user->dmpgrid,X,Xgen,Xnet));
455 
456   PetscCall(VecGetArray(Xgen,&xgen));
457   PetscCall(VecGetArray(Xnet,&xnet));
458 
459   /* Generator subsystem */
460   for (i=0; i < ngen; i++) {
461     Eqp   = xgen[idx];
462     Edp   = xgen[idx+1];
463     delta = xgen[idx+2];
464     Id    = xgen[idx+4];
465     Iq    = xgen[idx+5];
466     Efd   = xgen[idx+6];
467 
468     /*    fgen[idx]   = (Eqp + (Xd[i] - Xdp[i])*Id - Efd)/Td0p[i]; */
469     row[0] = idx;
470     col[0] = idx;           col[1] = idx+4;          col[2] = idx+6;
471     val[0] = 1/ Td0p[i]; val[1] = (Xd[i] - Xdp[i])/ Td0p[i]; val[2] = -1/Td0p[i];
472 
473     PetscCall(MatSetValues(J,1,row,3,col,val,INSERT_VALUES));
474 
475     /*    fgen[idx+1] = (Edp - (Xq[i] - Xqp[i])*Iq)/Tq0p[i]; */
476     row[0] = idx + 1;
477     col[0] = idx + 1;       col[1] = idx+5;
478     val[0] = 1/Tq0p[i]; val[1] = -(Xq[i] - Xqp[i])/Tq0p[i];
479     PetscCall(MatSetValues(J,1,row,2,col,val,INSERT_VALUES));
480 
481     /*    fgen[idx+2] = - w + w_s; */
482     row[0] = idx + 2;
483     col[0] = idx + 2; col[1] = idx + 3;
484     val[0] = 0;       val[1] = -1;
485     PetscCall(MatSetValues(J,1,row,2,col,val,INSERT_VALUES));
486 
487     /*    fgen[idx+3] = (-TM[i] + Edp*Id + Eqp*Iq + (Xqp[i] - Xdp[i])*Id*Iq + D[i]*(w - w_s))/M[i]; */
488     row[0] = idx + 3;
489     col[0] = idx; col[1] = idx + 1; col[2] = idx + 3;       col[3] = idx + 4;                  col[4] = idx + 5;
490     val[0] = Iq/M[i];  val[1] = Id/M[i];      val[2] = D[i]/M[i]; val[3] = (Edp + (Xqp[i]-Xdp[i])*Iq)/M[i]; val[4] = (Eqp + (Xqp[i] - Xdp[i])*Id)/M[i];
491     PetscCall(MatSetValues(J,1,row,5,col,val,INSERT_VALUES));
492 
493     Vr   = xnet[2*gbus[i]]; /* Real part of generator terminal voltage */
494     Vi   = xnet[2*gbus[i]+1]; /* Imaginary part of the generator terminal voltage */
495     PetscCall(ri2dq(Vr,Vi,delta,&Vd,&Vq));
496 
497     det = Rs[i]*Rs[i] + Xdp[i]*Xqp[i];
498 
499     Zdq_inv[0] = Rs[i]/det;
500     Zdq_inv[1] = Xqp[i]/det;
501     Zdq_inv[2] = -Xdp[i]/det;
502     Zdq_inv[3] = Rs[i]/det;
503 
504     dVd_dVr    = PetscSinScalar(delta); dVd_dVi = -PetscCosScalar(delta);
505     dVq_dVr    = PetscCosScalar(delta); dVq_dVi = PetscSinScalar(delta);
506     dVd_ddelta = Vr*PetscCosScalar(delta) + Vi*PetscSinScalar(delta);
507     dVq_ddelta = -Vr*PetscSinScalar(delta) + Vi*PetscCosScalar(delta);
508 
509     /*    fgen[idx+4] = Zdq_inv[0]*(-Edp + Vd) + Zdq_inv[1]*(-Eqp + Vq) + Id; */
510     row[0] = idx+4;
511     col[0] = idx;         col[1] = idx+1;        col[2] = idx + 2;
512     val[0] = -Zdq_inv[1]; val[1] = -Zdq_inv[0];  val[2] = Zdq_inv[0]*dVd_ddelta + Zdq_inv[1]*dVq_ddelta;
513     col[3] = idx + 4; col[4] = net_start+2*gbus[i];                     col[5] = net_start + 2*gbus[i]+1;
514     val[3] = 1;       val[4] = Zdq_inv[0]*dVd_dVr + Zdq_inv[1]*dVq_dVr; val[5] = Zdq_inv[0]*dVd_dVi + Zdq_inv[1]*dVq_dVi;
515     PetscCall(MatSetValues(J,1,row,6,col,val,INSERT_VALUES));
516 
517     /*  fgen[idx+5] = Zdq_inv[2]*(-Edp + Vd) + Zdq_inv[3]*(-Eqp + Vq) + Iq; */
518     row[0] = idx+5;
519     col[0] = idx;         col[1] = idx+1;        col[2] = idx + 2;
520     val[0] = -Zdq_inv[3]; val[1] = -Zdq_inv[2];  val[2] = Zdq_inv[2]*dVd_ddelta + Zdq_inv[3]*dVq_ddelta;
521     col[3] = idx + 5; col[4] = net_start+2*gbus[i];                     col[5] = net_start + 2*gbus[i]+1;
522     val[3] = 1;       val[4] = Zdq_inv[2]*dVd_dVr + Zdq_inv[3]*dVq_dVr; val[5] = Zdq_inv[2]*dVd_dVi + Zdq_inv[3]*dVq_dVi;
523     PetscCall(MatSetValues(J,1,row,6,col,val,INSERT_VALUES));
524 
525     dIGr_ddelta = Id*PetscCosScalar(delta) - Iq*PetscSinScalar(delta);
526     dIGi_ddelta = Id*PetscSinScalar(delta) + Iq*PetscCosScalar(delta);
527     dIGr_dId    = PetscSinScalar(delta);  dIGr_dIq = PetscCosScalar(delta);
528     dIGi_dId    = -PetscCosScalar(delta); dIGi_dIq = PetscSinScalar(delta);
529 
530     /* fnet[2*gbus[i]]   -= IGi; */
531     row[0] = net_start + 2*gbus[i];
532     col[0] = idx+2;        col[1] = idx + 4;   col[2] = idx + 5;
533     val[0] = -dIGi_ddelta; val[1] = -dIGi_dId; val[2] = -dIGi_dIq;
534     PetscCall(MatSetValues(J,1,row,3,col,val,INSERT_VALUES));
535 
536     /* fnet[2*gbus[i]+1]   -= IGr; */
537     row[0] = net_start + 2*gbus[i]+1;
538     col[0] = idx+2;        col[1] = idx + 4;   col[2] = idx + 5;
539     val[0] = -dIGr_ddelta; val[1] = -dIGr_dId; val[2] = -dIGr_dIq;
540     PetscCall(MatSetValues(J,1,row,3,col,val,INSERT_VALUES));
541 
542     Vm = PetscSqrtScalar(Vd*Vd + Vq*Vq);
543 
544     /*    fgen[idx+6] = (KE[i]*Efd + SE - VR)/TE[i]; */
545     /*    SE  = k1[i]*PetscExpScalar(k2[i]*Efd); */
546 
547     dSE_dEfd = k1[i]*k2[i]*PetscExpScalar(k2[i]*Efd);
548 
549     row[0] = idx + 6;
550     col[0] = idx + 6;                     col[1] = idx + 8;
551     val[0] = (KE[i] + dSE_dEfd)/TE[i];  val[1] = -1/TE[i];
552     PetscCall(MatSetValues(J,1,row,2,col,val,INSERT_VALUES));
553 
554     /* Exciter differential equations */
555 
556     /*    fgen[idx+7] = (RF - KF[i]*Efd/TF[i])/TF[i]; */
557     row[0] = idx + 7;
558     col[0] = idx + 6;       col[1] = idx + 7;
559     val[0] = (-KF[i]/TF[i])/TF[i];  val[1] = 1/TF[i];
560     PetscCall(MatSetValues(J,1,row,2,col,val,INSERT_VALUES));
561 
562     /*    fgen[idx+8] = (VR - KA[i]*RF + KA[i]*KF[i]*Efd/TF[i] - KA[i]*(Vref[i] - Vm))/TA[i]; */
563     /* Vm = (Vd^2 + Vq^2)^0.5; */
564     dVm_dVd    = Vd/Vm; dVm_dVq = Vq/Vm;
565     dVm_dVr    = dVm_dVd*dVd_dVr + dVm_dVq*dVq_dVr;
566     dVm_dVi    = dVm_dVd*dVd_dVi + dVm_dVq*dVq_dVi;
567     row[0]     = idx + 8;
568     col[0]     = idx + 6;           col[1] = idx + 7; col[2] = idx + 8;
569     val[0]     = (KA[i]*KF[i]/TF[i])/TA[i]; val[1] = -KA[i]/TA[i];  val[2] = 1/TA[i];
570     col[3]     = net_start + 2*gbus[i]; col[4] = net_start + 2*gbus[i]+1;
571     val[3]     = KA[i]*dVm_dVr/TA[i];         val[4] = KA[i]*dVm_dVi/TA[i];
572     PetscCall(MatSetValues(J,1,row,5,col,val,INSERT_VALUES));
573     idx        = idx + 9;
574   }
575 
576   for (i=0; i<nbus; i++) {
577     PetscCall(MatGetRow(user->Ybus,2*i,&ncols,&cols,&yvals));
578     row[0] = net_start + 2*i;
579     for (k=0; k<ncols; k++) {
580       col[k] = net_start + cols[k];
581       val[k] = yvals[k];
582     }
583     PetscCall(MatSetValues(J,1,row,ncols,col,val,INSERT_VALUES));
584     PetscCall(MatRestoreRow(user->Ybus,2*i,&ncols,&cols,&yvals));
585 
586     PetscCall(MatGetRow(user->Ybus,2*i+1,&ncols,&cols,&yvals));
587     row[0] = net_start + 2*i+1;
588     for (k=0; k<ncols; k++) {
589       col[k] = net_start + cols[k];
590       val[k] = yvals[k];
591     }
592     PetscCall(MatSetValues(J,1,row,ncols,col,val,INSERT_VALUES));
593     PetscCall(MatRestoreRow(user->Ybus,2*i+1,&ncols,&cols,&yvals));
594   }
595 
596   PetscCall(MatAssemblyBegin(J,MAT_FLUSH_ASSEMBLY));
597   PetscCall(MatAssemblyEnd(J,MAT_FLUSH_ASSEMBLY));
598 
599   PetscCall(VecGetArray(user->V0,&v0));
600   for (i=0; i < nload; i++) {
601     Vr      = xnet[2*lbus[i]]; /* Real part of load bus voltage */
602     Vi      = xnet[2*lbus[i]+1]; /* Imaginary part of the load bus voltage */
603     Vm      = PetscSqrtScalar(Vr*Vr + Vi*Vi); Vm2 = Vm*Vm; Vm4 = Vm2*Vm2;
604     Vm0     = PetscSqrtScalar(v0[2*lbus[i]]*v0[2*lbus[i]] + v0[2*lbus[i]+1]*v0[2*lbus[i]+1]);
605     PD      = QD = 0.0;
606     dPD_dVr = dPD_dVi = dQD_dVr = dQD_dVi = 0.0;
607     for (k=0; k < ld_nsegsp[i]; k++) {
608       PD      += ld_alphap[k]*PD0[i]*PetscPowScalar((Vm/Vm0),ld_betap[k]);
609       dPD_dVr += ld_alphap[k]*ld_betap[k]*PD0[i]*PetscPowScalar((1/Vm0),ld_betap[k])*Vr*PetscPowScalar(Vm,(ld_betap[k]-2));
610       dPD_dVi += ld_alphap[k]*ld_betap[k]*PD0[i]*PetscPowScalar((1/Vm0),ld_betap[k])*Vi*PetscPowScalar(Vm,(ld_betap[k]-2));
611     }
612     for (k=0; k < ld_nsegsq[i]; k++) {
613       QD      += ld_alphaq[k]*QD0[i]*PetscPowScalar((Vm/Vm0),ld_betaq[k]);
614       dQD_dVr += ld_alphaq[k]*ld_betaq[k]*QD0[i]*PetscPowScalar((1/Vm0),ld_betaq[k])*Vr*PetscPowScalar(Vm,(ld_betaq[k]-2));
615       dQD_dVi += ld_alphaq[k]*ld_betaq[k]*QD0[i]*PetscPowScalar((1/Vm0),ld_betaq[k])*Vi*PetscPowScalar(Vm,(ld_betaq[k]-2));
616     }
617 
618     /*    IDr = (PD*Vr + QD*Vi)/Vm2; */
619     /*    IDi = (-QD*Vr + PD*Vi)/Vm2; */
620 
621     dIDr_dVr = (dPD_dVr*Vr + dQD_dVr*Vi + PD)/Vm2 - ((PD*Vr + QD*Vi)*2*Vr)/Vm4;
622     dIDr_dVi = (dPD_dVi*Vr + dQD_dVi*Vi + QD)/Vm2 - ((PD*Vr + QD*Vi)*2*Vi)/Vm4;
623 
624     dIDi_dVr = (-dQD_dVr*Vr + dPD_dVr*Vi - QD)/Vm2 - ((-QD*Vr + PD*Vi)*2*Vr)/Vm4;
625     dIDi_dVi = (-dQD_dVi*Vr + dPD_dVi*Vi + PD)/Vm2 - ((-QD*Vr + PD*Vi)*2*Vi)/Vm4;
626 
627     /*    fnet[2*lbus[i]]   += IDi; */
628     row[0] = net_start + 2*lbus[i];
629     col[0] = net_start + 2*lbus[i];  col[1] = net_start + 2*lbus[i]+1;
630     val[0] = dIDi_dVr;               val[1] = dIDi_dVi;
631     PetscCall(MatSetValues(J,1,row,2,col,val,ADD_VALUES));
632     /*    fnet[2*lbus[i]+1] += IDr; */
633     row[0] = net_start + 2*lbus[i]+1;
634     col[0] = net_start + 2*lbus[i];  col[1] = net_start + 2*lbus[i]+1;
635     val[0] = dIDr_dVr;               val[1] = dIDr_dVi;
636     PetscCall(MatSetValues(J,1,row,2,col,val,ADD_VALUES));
637   }
638   PetscCall(VecRestoreArray(user->V0,&v0));
639 
640   PetscCall(VecRestoreArray(Xgen,&xgen));
641   PetscCall(VecRestoreArray(Xnet,&xnet));
642 
643   PetscCall(DMCompositeRestoreLocalVectors(user->dmpgrid,&Xgen,&Xnet));
644 
645   PetscCall(MatAssemblyBegin(J,MAT_FINAL_ASSEMBLY));
646   PetscCall(MatAssemblyEnd(J,MAT_FINAL_ASSEMBLY));
647   PetscFunctionReturn(0);
648 }
649 
650 /*
651    J = [I, 0
652         dg_dx, dg_dy]
653 */
654 PetscErrorCode AlgJacobian(SNES snes,Vec X,Mat A,Mat B,void *ctx)
655 {
656   Userctx        *user=(Userctx*)ctx;
657 
658   PetscFunctionBegin;
659   PetscCall(ResidualJacobian(snes,X,A,B,ctx));
660   PetscCall(MatSetOption(A,MAT_KEEP_NONZERO_PATTERN,PETSC_TRUE));
661   PetscCall(MatZeroRowsIS(A,user->is_diff,1.0,NULL,NULL));
662   PetscFunctionReturn(0);
663 }
664 
665 /*
666    J = [a*I-df_dx, -df_dy
667         dg_dx, dg_dy]
668 */
669 
670 PetscErrorCode IJacobian(TS ts,PetscReal t,Vec X,Vec Xdot,PetscReal a,Mat A,Mat B,Userctx *user)
671 {
672   SNES           snes;
673   PetscScalar    atmp = (PetscScalar) a;
674   PetscInt       i,row;
675 
676   PetscFunctionBegin;
677   user->t = t;
678 
679   PetscCall(TSGetSNES(ts,&snes));
680   PetscCall(ResidualJacobian(snes,X,A,B,user));
681   for (i=0;i < ngen;i++) {
682     row = 9*i;
683     PetscCall(MatSetValues(A,1,&row,1,&row,&atmp,ADD_VALUES));
684     row  = 9*i+1;
685     PetscCall(MatSetValues(A,1,&row,1,&row,&atmp,ADD_VALUES));
686     row  = 9*i+2;
687     PetscCall(MatSetValues(A,1,&row,1,&row,&atmp,ADD_VALUES));
688     row  = 9*i+3;
689     PetscCall(MatSetValues(A,1,&row,1,&row,&atmp,ADD_VALUES));
690     row  = 9*i+6;
691     PetscCall(MatSetValues(A,1,&row,1,&row,&atmp,ADD_VALUES));
692     row  = 9*i+7;
693     PetscCall(MatSetValues(A,1,&row,1,&row,&atmp,ADD_VALUES));
694     row  = 9*i+8;
695     PetscCall(MatSetValues(A,1,&row,1,&row,&atmp,ADD_VALUES));
696   }
697   PetscCall(MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY));
698   PetscCall(MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY));
699   PetscFunctionReturn(0);
700 }
701 
702 static PetscErrorCode CostIntegrand(TS ts,PetscReal t,Vec U,Vec R,Userctx *user)
703 {
704   PetscScalar       *r;
705   const PetscScalar *u;
706   PetscInt          idx;
707   Vec               Xgen,Xnet;
708   PetscScalar       *xgen;
709   PetscInt          i;
710 
711   PetscFunctionBegin;
712   PetscCall(DMCompositeGetLocalVectors(user->dmpgrid,&Xgen,&Xnet));
713   PetscCall(DMCompositeScatter(user->dmpgrid,U,Xgen,Xnet));
714 
715   PetscCall(VecGetArray(Xgen,&xgen));
716 
717   PetscCall(VecGetArrayRead(U,&u));
718   PetscCall(VecGetArray(R,&r));
719   r[0] = 0.;
720 
721   idx = 0;
722   for (i=0;i<ngen;i++) {
723     r[0] += PetscPowScalarInt(PetscMax(0.,PetscMax(xgen[idx+3]/(2.*PETSC_PI)-user->freq_u,user->freq_l-xgen[idx+3]/(2.*PETSC_PI))),user->pow);
724     idx  += 9;
725   }
726   PetscCall(VecRestoreArray(R,&r));
727   PetscCall(VecRestoreArrayRead(U,&u));
728   PetscCall(DMCompositeRestoreLocalVectors(user->dmpgrid,&Xgen,&Xnet));
729   PetscFunctionReturn(0);
730 }
731 
732 static PetscErrorCode MonitorUpdateQ(TS ts,PetscInt stepnum,PetscReal time,Vec X,void *ctx0)
733 {
734   Vec            C,*Y;
735   PetscInt       Nr;
736   PetscReal      h,theta;
737   Userctx        *ctx=(Userctx*)ctx0;
738 
739   PetscFunctionBegin;
740   theta = 0.5;
741   PetscCall(TSGetStages(ts,&Nr,&Y));
742   PetscCall(TSGetTimeStep(ts,&h));
743   PetscCall(VecDuplicate(ctx->vec_q,&C));
744   /* compute integrals */
745   if (stepnum>0) {
746     PetscCall(CostIntegrand(ts,time,X,C,ctx));
747     PetscCall(VecAXPY(ctx->vec_q,h*theta,C));
748     PetscCall(CostIntegrand(ts,time+h*theta,Y[0],C,ctx));
749     PetscCall(VecAXPY(ctx->vec_q,h*(1-theta),C));
750   }
751   PetscCall(VecDestroy(&C));
752   PetscFunctionReturn(0);
753 }
754 
755 int main(int argc,char **argv)
756 {
757   Userctx            user;
758   Vec                p;
759   PetscScalar        *x_ptr;
760   PetscErrorCode     ierr;
761   PetscMPIInt        size;
762   PetscInt           i;
763   KSP                ksp;
764   PC                 pc;
765   PetscInt           *idx2;
766   Tao                tao;
767   Vec                lowerb,upperb;
768 
769   PetscFunctionBeginUser;
770   PetscCall(PetscInitialize(&argc,&argv,"petscoptions",help));
771   PetscCallMPI(MPI_Comm_size(PETSC_COMM_WORLD,&size));
772   PetscCheck(size == 1,PETSC_COMM_WORLD,PETSC_ERR_WRONG_MPI_SIZE,"Only for sequential runs");
773 
774   PetscCall(VecCreateSeq(PETSC_COMM_WORLD,1,&user.vec_q));
775 
776   user.neqs_gen   = 9*ngen; /* # eqs. for generator subsystem */
777   user.neqs_net   = 2*nbus; /* # eqs. for network subsystem   */
778   user.neqs_pgrid = user.neqs_gen + user.neqs_net;
779 
780   /* Create indices for differential and algebraic equations */
781   PetscCall(PetscMalloc1(7*ngen,&idx2));
782   for (i=0; i<ngen; i++) {
783     idx2[7*i]   = 9*i;   idx2[7*i+1] = 9*i+1; idx2[7*i+2] = 9*i+2; idx2[7*i+3] = 9*i+3;
784     idx2[7*i+4] = 9*i+6; idx2[7*i+5] = 9*i+7; idx2[7*i+6] = 9*i+8;
785   }
786   PetscCall(ISCreateGeneral(PETSC_COMM_WORLD,7*ngen,idx2,PETSC_COPY_VALUES,&user.is_diff));
787   PetscCall(ISComplement(user.is_diff,0,user.neqs_pgrid,&user.is_alg));
788   PetscCall(PetscFree(idx2));
789 
790   /* Set run time options */
791   ierr = PetscOptionsBegin(PETSC_COMM_WORLD,NULL,"Transient stability fault options","");PetscCall(ierr);
792   {
793     user.tfaulton  = 1.0;
794     user.tfaultoff = 1.2;
795     user.Rfault    = 0.0001;
796     user.faultbus  = 8;
797     PetscCall(PetscOptionsReal("-tfaulton","","",user.tfaulton,&user.tfaulton,NULL));
798     PetscCall(PetscOptionsReal("-tfaultoff","","",user.tfaultoff,&user.tfaultoff,NULL));
799     PetscCall(PetscOptionsInt("-faultbus","","",user.faultbus,&user.faultbus,NULL));
800     user.t0        = 0.0;
801     user.tmax      = 1.5;
802     PetscCall(PetscOptionsReal("-t0","","",user.t0,&user.t0,NULL));
803     PetscCall(PetscOptionsReal("-tmax","","",user.tmax,&user.tmax,NULL));
804     user.freq_u    = 61.0;
805     user.freq_l    = 59.0;
806     user.pow       = 2;
807     PetscCall(PetscOptionsReal("-frequ","","",user.freq_u,&user.freq_u,NULL));
808     PetscCall(PetscOptionsReal("-freql","","",user.freq_l,&user.freq_l,NULL));
809     PetscCall(PetscOptionsInt("-pow","","",user.pow,&user.pow,NULL));
810 
811   }
812   ierr = PetscOptionsEnd();PetscCall(ierr);
813 
814   /* Create DMs for generator and network subsystems */
815   PetscCall(DMDACreate1d(PETSC_COMM_WORLD,DM_BOUNDARY_NONE,user.neqs_gen,1,1,NULL,&user.dmgen));
816   PetscCall(DMSetOptionsPrefix(user.dmgen,"dmgen_"));
817   PetscCall(DMSetFromOptions(user.dmgen));
818   PetscCall(DMSetUp(user.dmgen));
819   PetscCall(DMDACreate1d(PETSC_COMM_WORLD,DM_BOUNDARY_NONE,user.neqs_net,1,1,NULL,&user.dmnet));
820   PetscCall(DMSetOptionsPrefix(user.dmnet,"dmnet_"));
821   PetscCall(DMSetFromOptions(user.dmnet));
822   PetscCall(DMSetUp(user.dmnet));
823   /* Create a composite DM packer and add the two DMs */
824   PetscCall(DMCompositeCreate(PETSC_COMM_WORLD,&user.dmpgrid));
825   PetscCall(DMSetOptionsPrefix(user.dmpgrid,"pgrid_"));
826   PetscCall(DMCompositeAddDM(user.dmpgrid,user.dmgen));
827   PetscCall(DMCompositeAddDM(user.dmpgrid,user.dmnet));
828 
829   /* Create TAO solver and set desired solution method */
830   PetscCall(TaoCreate(PETSC_COMM_WORLD,&tao));
831   PetscCall(TaoSetType(tao,TAOBLMVM));
832   /*
833      Optimization starts
834   */
835   /* Set initial solution guess */
836   PetscCall(VecCreateSeq(PETSC_COMM_WORLD,3,&p));
837   PetscCall(VecGetArray(p,&x_ptr));
838   x_ptr[0] = PG[0]; x_ptr[1] = PG[1]; x_ptr[2] = PG[2];
839   PetscCall(VecRestoreArray(p,&x_ptr));
840 
841   PetscCall(TaoSetSolution(tao,p));
842   /* Set routine for function and gradient evaluation */
843   PetscCall(TaoSetObjective(tao,FormFunction,(void *)&user));
844   PetscCall(TaoSetGradient(tao,NULL,TaoDefaultComputeGradient,(void *)&user));
845 
846   /* Set bounds for the optimization */
847   PetscCall(VecDuplicate(p,&lowerb));
848   PetscCall(VecDuplicate(p,&upperb));
849   PetscCall(VecGetArray(lowerb,&x_ptr));
850   x_ptr[0] = 0.5; x_ptr[1] = 0.5; x_ptr[2] = 0.5;
851   PetscCall(VecRestoreArray(lowerb,&x_ptr));
852   PetscCall(VecGetArray(upperb,&x_ptr));
853   x_ptr[0] = 2.0; x_ptr[1] = 2.0; x_ptr[2] = 2.0;
854   PetscCall(VecRestoreArray(upperb,&x_ptr));
855   PetscCall(TaoSetVariableBounds(tao,lowerb,upperb));
856 
857   /* Check for any TAO command line options */
858   PetscCall(TaoSetFromOptions(tao));
859   PetscCall(TaoGetKSP(tao,&ksp));
860   if (ksp) {
861     PetscCall(KSPGetPC(ksp,&pc));
862     PetscCall(PCSetType(pc,PCNONE));
863   }
864 
865   /* SOLVE THE APPLICATION */
866   PetscCall(TaoSolve(tao));
867 
868   PetscCall(VecView(p,PETSC_VIEWER_STDOUT_WORLD));
869   /* Free TAO data structures */
870   PetscCall(TaoDestroy(&tao));
871   PetscCall(VecDestroy(&user.vec_q));
872   PetscCall(VecDestroy(&lowerb));
873   PetscCall(VecDestroy(&upperb));
874   PetscCall(VecDestroy(&p));
875   PetscCall(DMDestroy(&user.dmgen));
876   PetscCall(DMDestroy(&user.dmnet));
877   PetscCall(DMDestroy(&user.dmpgrid));
878   PetscCall(ISDestroy(&user.is_diff));
879   PetscCall(ISDestroy(&user.is_alg));
880   PetscCall(PetscFinalize());
881   return 0;
882 }
883 
884 /* ------------------------------------------------------------------ */
885 /*
886    FormFunction - Evaluates the function and corresponding gradient.
887 
888    Input Parameters:
889    tao - the Tao context
890    X   - the input vector
891    ptr - optional user-defined context, as set by TaoSetObjectiveAndGradient()
892 
893    Output Parameters:
894    f   - the newly evaluated function
895 */
896 PetscErrorCode FormFunction(Tao tao,Vec P,PetscReal *f,void *ctx0)
897 {
898   TS             ts;
899   SNES           snes_alg;
900   Userctx        *ctx = (Userctx*)ctx0;
901   Vec            X;
902   Mat            J;
903   /* sensitivity context */
904   PetscScalar    *x_ptr;
905   PetscViewer    Xview,Ybusview;
906   Vec            F_alg;
907   Vec            Xdot;
908   PetscInt       row_loc,col_loc;
909   PetscScalar    val;
910 
911   PetscCall(VecGetArrayRead(P,(const PetscScalar**)&x_ptr));
912   PG[0] = x_ptr[0];
913   PG[1] = x_ptr[1];
914   PG[2] = x_ptr[2];
915   PetscCall(VecRestoreArrayRead(P,(const PetscScalar**)&x_ptr));
916 
917   ctx->stepnum = 0;
918 
919   PetscCall(VecZeroEntries(ctx->vec_q));
920 
921   /* Read initial voltage vector and Ybus */
922   PetscCall(PetscViewerBinaryOpen(PETSC_COMM_WORLD,"X.bin",FILE_MODE_READ,&Xview));
923   PetscCall(PetscViewerBinaryOpen(PETSC_COMM_WORLD,"Ybus.bin",FILE_MODE_READ,&Ybusview));
924 
925   PetscCall(VecCreate(PETSC_COMM_WORLD,&ctx->V0));
926   PetscCall(VecSetSizes(ctx->V0,PETSC_DECIDE,ctx->neqs_net));
927   PetscCall(VecLoad(ctx->V0,Xview));
928 
929   PetscCall(MatCreate(PETSC_COMM_WORLD,&ctx->Ybus));
930   PetscCall(MatSetSizes(ctx->Ybus,PETSC_DECIDE,PETSC_DECIDE,ctx->neqs_net,ctx->neqs_net));
931   PetscCall(MatSetType(ctx->Ybus,MATBAIJ));
932   /*  PetscCall(MatSetBlockSize(ctx->Ybus,2)); */
933   PetscCall(MatLoad(ctx->Ybus,Ybusview));
934 
935   PetscCall(PetscViewerDestroy(&Xview));
936   PetscCall(PetscViewerDestroy(&Ybusview));
937 
938   PetscCall(DMCreateGlobalVector(ctx->dmpgrid,&X));
939 
940   PetscCall(MatCreate(PETSC_COMM_WORLD,&J));
941   PetscCall(MatSetSizes(J,PETSC_DECIDE,PETSC_DECIDE,ctx->neqs_pgrid,ctx->neqs_pgrid));
942   PetscCall(MatSetFromOptions(J));
943   PetscCall(PreallocateJacobian(J,ctx));
944 
945   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
946      Create timestepping solver context
947      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
948   PetscCall(TSCreate(PETSC_COMM_WORLD,&ts));
949   PetscCall(TSSetProblemType(ts,TS_NONLINEAR));
950   PetscCall(TSSetType(ts,TSCN));
951   PetscCall(TSSetIFunction(ts,NULL,(TSIFunction) IFunction,ctx));
952   PetscCall(TSSetIJacobian(ts,J,J,(TSIJacobian)IJacobian,ctx));
953   PetscCall(TSSetApplicationContext(ts,ctx));
954 
955   PetscCall(TSMonitorSet(ts,MonitorUpdateQ,ctx,NULL));
956   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
957      Set initial conditions
958    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
959   PetscCall(SetInitialGuess(X,ctx));
960 
961   PetscCall(VecDuplicate(X,&F_alg));
962   PetscCall(SNESCreate(PETSC_COMM_WORLD,&snes_alg));
963   PetscCall(SNESSetFunction(snes_alg,F_alg,AlgFunction,ctx));
964   PetscCall(MatZeroEntries(J));
965   PetscCall(SNESSetJacobian(snes_alg,J,J,AlgJacobian,ctx));
966   PetscCall(SNESSetOptionsPrefix(snes_alg,"alg_"));
967   PetscCall(SNESSetFromOptions(snes_alg));
968   ctx->alg_flg = PETSC_TRUE;
969   /* Solve the algebraic equations */
970   PetscCall(SNESSolve(snes_alg,NULL,X));
971 
972   /* Just to set up the Jacobian structure */
973   PetscCall(VecDuplicate(X,&Xdot));
974   PetscCall(IJacobian(ts,0.0,X,Xdot,0.0,J,J,ctx));
975   PetscCall(VecDestroy(&Xdot));
976 
977   ctx->stepnum++;
978 
979   PetscCall(TSSetTimeStep(ts,0.01));
980   PetscCall(TSSetMaxTime(ts,ctx->tmax));
981   PetscCall(TSSetExactFinalTime(ts,TS_EXACTFINALTIME_MATCHSTEP));
982   PetscCall(TSSetFromOptions(ts));
983 
984   /* Prefault period */
985   ctx->alg_flg = PETSC_FALSE;
986   PetscCall(TSSetTime(ts,0.0));
987   PetscCall(TSSetMaxTime(ts,ctx->tfaulton));
988   PetscCall(TSSolve(ts,X));
989 
990   /* Create the nonlinear solver for solving the algebraic system */
991   /* Note that although the algebraic system needs to be solved only for
992      Idq and V, we reuse the entire system including xgen. The xgen
993      variables are held constant by setting their residuals to 0 and
994      putting a 1 on the Jacobian diagonal for xgen rows
995   */
996   PetscCall(MatZeroEntries(J));
997 
998   /* Apply disturbance - resistive fault at ctx->faultbus */
999   /* This is done by adding shunt conductance to the diagonal location
1000      in the Ybus matrix */
1001   row_loc = 2*ctx->faultbus; col_loc = 2*ctx->faultbus+1; /* Location for G */
1002   val     = 1/ctx->Rfault;
1003   PetscCall(MatSetValues(ctx->Ybus,1,&row_loc,1,&col_loc,&val,ADD_VALUES));
1004   row_loc = 2*ctx->faultbus+1; col_loc = 2*ctx->faultbus; /* Location for G */
1005   val     = 1/ctx->Rfault;
1006   PetscCall(MatSetValues(ctx->Ybus,1,&row_loc,1,&col_loc,&val,ADD_VALUES));
1007 
1008   PetscCall(MatAssemblyBegin(ctx->Ybus,MAT_FINAL_ASSEMBLY));
1009   PetscCall(MatAssemblyEnd(ctx->Ybus,MAT_FINAL_ASSEMBLY));
1010 
1011   ctx->alg_flg = PETSC_TRUE;
1012   /* Solve the algebraic equations */
1013   PetscCall(SNESSolve(snes_alg,NULL,X));
1014 
1015   ctx->stepnum++;
1016 
1017   /* Disturbance period */
1018   ctx->alg_flg = PETSC_FALSE;
1019   PetscCall(TSSetTime(ts,ctx->tfaulton));
1020   PetscCall(TSSetMaxTime(ts,ctx->tfaultoff));
1021   PetscCall(TSSolve(ts,X));
1022 
1023   /* Remove the fault */
1024   row_loc = 2*ctx->faultbus; col_loc = 2*ctx->faultbus+1;
1025   val     = -1/ctx->Rfault;
1026   PetscCall(MatSetValues(ctx->Ybus,1,&row_loc,1,&col_loc,&val,ADD_VALUES));
1027   row_loc = 2*ctx->faultbus+1; col_loc = 2*ctx->faultbus;
1028   val     = -1/ctx->Rfault;
1029   PetscCall(MatSetValues(ctx->Ybus,1,&row_loc,1,&col_loc,&val,ADD_VALUES));
1030 
1031   PetscCall(MatAssemblyBegin(ctx->Ybus,MAT_FINAL_ASSEMBLY));
1032   PetscCall(MatAssemblyEnd(ctx->Ybus,MAT_FINAL_ASSEMBLY));
1033 
1034   PetscCall(MatZeroEntries(J));
1035 
1036   ctx->alg_flg = PETSC_TRUE;
1037 
1038   /* Solve the algebraic equations */
1039   PetscCall(SNESSolve(snes_alg,NULL,X));
1040 
1041   ctx->stepnum++;
1042 
1043   /* Post-disturbance period */
1044   ctx->alg_flg = PETSC_TRUE;
1045   PetscCall(TSSetTime(ts,ctx->tfaultoff));
1046   PetscCall(TSSetMaxTime(ts,ctx->tmax));
1047   PetscCall(TSSolve(ts,X));
1048 
1049   PetscCall(VecGetArray(ctx->vec_q,&x_ptr));
1050   *f   = x_ptr[0];
1051   PetscCall(VecRestoreArray(ctx->vec_q,&x_ptr));
1052 
1053   PetscCall(MatDestroy(&ctx->Ybus));
1054   PetscCall(VecDestroy(&ctx->V0));
1055   PetscCall(SNESDestroy(&snes_alg));
1056   PetscCall(VecDestroy(&F_alg));
1057   PetscCall(MatDestroy(&J));
1058   PetscCall(VecDestroy(&X));
1059   PetscCall(TSDestroy(&ts));
1060 
1061   return 0;
1062 }
1063 
1064 /*TEST
1065 
1066   build:
1067       requires: double !complex !defined(USE_64BIT_INDICES)
1068 
1069    test:
1070       args: -viewer_binary_skip_info -tao_monitor -tao_gttol .2
1071       localrunfiles: petscoptions X.bin Ybus.bin
1072 
1073 TEST*/
1074