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