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