1 2 static char help[] = "Power grid stability analysis of WECC 9 bus system.\n\ 3 This example is based on the 9-bus (node) example given in the book Power\n\ 4 Systems Dynamics and Stability (Chapter 7) by P. Sauer and M. A. Pai.\n\ 5 The power grid in this example consists of 9 buses (nodes), 3 generators,\n\ 6 3 loads, and 9 transmission lines. The network equations are written\n\ 7 in current balance form using rectangular coordinates.\n\n"; 8 9 /* 10 The equations for the stability analysis are described by the DAE 11 12 \dot{x} = f(x,y,t) 13 0 = g(x,y,t) 14 15 where the generators are described by differential equations, while the algebraic 16 constraints define the network equations. 17 18 The generators are modeled with a 4th order differential equation describing the electrical 19 and mechanical dynamics. Each generator also has an exciter system modeled by 3rd order 20 diff. eqns. describing the exciter, voltage regulator, and the feedback stabilizer 21 mechanism. 22 23 The network equations are described by nodal current balance equations. 24 I(x,y) - Y*V = 0 25 26 where: 27 I(x,y) is the current injected from generators and loads. 28 Y is the admittance matrix, and 29 V is the voltage vector 30 */ 31 32 /* 33 Include "petscts.h" so that we can use TS solvers. Note that this 34 file automatically includes: 35 petscsys.h - base PETSc routines petscvec.h - vectors 36 petscmat.h - matrices 37 petscis.h - index sets petscksp.h - Krylov subspace methods 38 petscviewer.h - viewers petscpc.h - preconditioners 39 petscksp.h - linear solvers 40 */ 41 42 #include <petscts.h> 43 #include <petscdm.h> 44 #include <petscdmda.h> 45 #include <petscdmcomposite.h> 46 47 #define freq 60 48 #define w_s (2*PETSC_PI*freq) 49 50 /* Sizes and indices */ 51 const PetscInt nbus = 9; /* Number of network buses */ 52 const PetscInt ngen = 3; /* Number of generators */ 53 const PetscInt nload = 3; /* Number of loads */ 54 const PetscInt gbus[3] = {0,1,2}; /* Buses at which generators are incident */ 55 const PetscInt lbus[3] = {4,5,7}; /* Buses at which loads are incident */ 56 57 /* Generator real and reactive powers (found via loadflow) */ 58 const PetscScalar PG[3] = {0.716786142395021,1.630000000000000,0.850000000000000}; 59 const PetscScalar QG[3] = {0.270702180178785,0.066120127797275,-0.108402221791588}; 60 /* Generator constants */ 61 const PetscScalar H[3] = {23.64,6.4,3.01}; /* Inertia constant */ 62 const PetscScalar Rs[3] = {0.0,0.0,0.0}; /* Stator Resistance */ 63 const PetscScalar Xd[3] = {0.146,0.8958,1.3125}; /* d-axis reactance */ 64 const PetscScalar Xdp[3] = {0.0608,0.1198,0.1813}; /* d-axis transient reactance */ 65 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 */ 66 const PetscScalar Xqp[3] = {0.0969,0.1969,0.25}; /* q-axis transient reactance */ 67 const PetscScalar Td0p[3] = {8.96,6.0,5.89}; /* d-axis open circuit time constant */ 68 const PetscScalar Tq0p[3] = {0.31,0.535,0.6}; /* q-axis open circuit time constant */ 69 PetscScalar M[3]; /* M = 2*H/w_s */ 70 PetscScalar D[3]; /* D = 0.1*M */ 71 72 PetscScalar TM[3]; /* Mechanical Torque */ 73 /* Exciter system constants */ 74 const PetscScalar KA[3] = {20.0,20.0,20.0}; /* Voltage regulartor gain constant */ 75 const PetscScalar TA[3] = {0.2,0.2,0.2}; /* Voltage regulator time constant */ 76 const PetscScalar KE[3] = {1.0,1.0,1.0}; /* Exciter gain constant */ 77 const PetscScalar TE[3] = {0.314,0.314,0.314}; /* Exciter time constant */ 78 const PetscScalar KF[3] = {0.063,0.063,0.063}; /* Feedback stabilizer gain constant */ 79 const PetscScalar TF[3] = {0.35,0.35,0.35}; /* Feedback stabilizer time constant */ 80 const PetscScalar k1[3] = {0.0039,0.0039,0.0039}; 81 const PetscScalar k2[3] = {1.555,1.555,1.555}; /* k1 and k2 for calculating the saturation function SE = k1*exp(k2*Efd) */ 82 const PetscScalar VRMIN[3] = {-4.0,-4.0,-4.0}; 83 const PetscScalar VRMAX[3] = {7.0,7.0,7.0}; 84 PetscInt VRatmin[3]; 85 PetscInt VRatmax[3]; 86 87 PetscScalar Vref[3]; 88 /* Load constants 89 We use a composite load model that describes the load and reactive powers at each time instant as follows 90 P(t) = \sum\limits_{i=0}^ld_nsegsp \ld_alphap_i*P_D0(\frac{V_m(t)}{V_m0})^\ld_betap_i 91 Q(t) = \sum\limits_{i=0}^ld_nsegsq \ld_alphaq_i*Q_D0(\frac{V_m(t)}{V_m0})^\ld_betaq_i 92 where 93 ld_nsegsp,ld_nsegsq - Number of individual load models for real and reactive power loads 94 ld_alphap,ld_alphap - Percentage contribution (weights) or loads 95 P_D0 - Real power load 96 Q_D0 - Reactive power load 97 V_m(t) - Voltage magnitude at time t 98 V_m0 - Voltage magnitude at t = 0 99 ld_betap, ld_betaq - exponents describing the load model for real and reactive part 100 101 Note: All loads have the same characteristic currently. 102 */ 103 const PetscScalar PD0[3] = {1.25,0.9,1.0}; 104 const PetscScalar QD0[3] = {0.5,0.3,0.35}; 105 const PetscInt ld_nsegsp[3] = {3,3,3}; 106 const PetscScalar ld_alphap[3] = {1.0,0.0,0.0}; 107 const PetscScalar ld_betap[3] = {2.0,1.0,0.0}; 108 const PetscInt ld_nsegsq[3] = {3,3,3}; 109 const PetscScalar ld_alphaq[3] = {1.0,0.0,0.0}; 110 const PetscScalar ld_betaq[3] = {2.0,1.0,0.0}; 111 112 typedef struct { 113 DM dmgen, dmnet; /* DMs to manage generator and network subsystem */ 114 DM dmpgrid; /* Composite DM to manage the entire power grid */ 115 Mat Ybus; /* Network admittance matrix */ 116 Vec V0; /* Initial voltage vector (Power flow solution) */ 117 PetscReal tfaulton,tfaultoff; /* Fault on and off times */ 118 PetscInt faultbus; /* Fault bus */ 119 PetscScalar Rfault; 120 PetscReal t0,tmax; 121 PetscInt neqs_gen,neqs_net,neqs_pgrid; 122 Mat Sol; /* Matrix to save solution at each time step */ 123 PetscInt stepnum; 124 PetscReal t; 125 SNES snes_alg; 126 IS is_diff; /* indices for differential equations */ 127 IS is_alg; /* indices for algebraic equations */ 128 PetscBool setisdiff; /* TS computes truncation error based only on the differential variables */ 129 PetscBool semiexplicit; /* If the flag is set then a semi-explicit method is used using TSRK */ 130 } Userctx; 131 132 /* 133 The first two events are for fault on and off, respectively. The following events are 134 to check the min/max limits on the state variable VR. A non windup limiter is used for 135 the VR limits. 136 */ 137 PetscErrorCode EventFunction(TS ts,PetscReal t,Vec X,PetscScalar *fvalue,void *ctx) 138 { 139 Userctx *user=(Userctx*)ctx; 140 Vec Xgen,Xnet; 141 PetscInt i,idx=0; 142 const PetscScalar *xgen,*xnet; 143 PetscScalar Efd,RF,VR,Vr,Vi,Vm; 144 145 PetscFunctionBegin; 146 147 CHKERRQ(DMCompositeGetLocalVectors(user->dmpgrid,&Xgen,&Xnet)); 148 CHKERRQ(DMCompositeScatter(user->dmpgrid,X,Xgen,Xnet)); 149 150 CHKERRQ(VecGetArrayRead(Xgen,&xgen)); 151 CHKERRQ(VecGetArrayRead(Xnet,&xnet)); 152 153 /* Event for fault-on time */ 154 fvalue[0] = t - user->tfaulton; 155 /* Event for fault-off time */ 156 fvalue[1] = t - user->tfaultoff; 157 158 for (i=0; i < ngen; i++) { 159 Efd = xgen[idx+6]; 160 RF = xgen[idx+7]; 161 VR = xgen[idx+8]; 162 163 Vr = xnet[2*gbus[i]]; /* Real part of generator terminal voltage */ 164 Vi = xnet[2*gbus[i]+1]; /* Imaginary part of the generator terminal voltage */ 165 Vm = PetscSqrtScalar(Vr*Vr + Vi*Vi); 166 167 if (!VRatmax[i]) { 168 fvalue[2+2*i] = VRMAX[i] - VR; 169 } else { 170 fvalue[2+2*i] = (VR - KA[i]*RF + KA[i]*KF[i]*Efd/TF[i] - KA[i]*(Vref[i] - Vm))/TA[i]; 171 } 172 if (!VRatmin[i]) { 173 fvalue[2+2*i+1] = VRMIN[i] - VR; 174 } else { 175 fvalue[2+2*i+1] = (VR - KA[i]*RF + KA[i]*KF[i]*Efd/TF[i] - KA[i]*(Vref[i] - Vm))/TA[i]; 176 } 177 idx = idx+9; 178 } 179 CHKERRQ(VecRestoreArrayRead(Xgen,&xgen)); 180 CHKERRQ(VecRestoreArrayRead(Xnet,&xnet)); 181 182 CHKERRQ(DMCompositeRestoreLocalVectors(user->dmpgrid,&Xgen,&Xnet)); 183 184 PetscFunctionReturn(0); 185 } 186 187 PetscErrorCode PostEventFunction(TS ts,PetscInt nevents,PetscInt event_list[],PetscReal t,Vec X,PetscBool forwardsolve,void* ctx) 188 { 189 Userctx *user=(Userctx*)ctx; 190 Vec Xgen,Xnet; 191 PetscScalar *xgen,*xnet; 192 PetscInt row_loc,col_loc; 193 PetscScalar val; 194 PetscInt i,idx=0,event_num; 195 PetscScalar fvalue; 196 PetscScalar Efd, RF, VR; 197 PetscScalar Vr,Vi,Vm; 198 199 PetscFunctionBegin; 200 201 CHKERRQ(DMCompositeGetLocalVectors(user->dmpgrid,&Xgen,&Xnet)); 202 CHKERRQ(DMCompositeScatter(user->dmpgrid,X,Xgen,Xnet)); 203 204 CHKERRQ(VecGetArray(Xgen,&xgen)); 205 CHKERRQ(VecGetArray(Xnet,&xnet)); 206 207 for (i=0; i < nevents; i++) { 208 if (event_list[i] == 0) { 209 /* Apply disturbance - resistive fault at user->faultbus */ 210 /* This is done by adding shunt conductance to the diagonal location 211 in the Ybus matrix */ 212 row_loc = 2*user->faultbus; col_loc = 2*user->faultbus+1; /* Location for G */ 213 val = 1/user->Rfault; 214 CHKERRQ(MatSetValues(user->Ybus,1,&row_loc,1,&col_loc,&val,ADD_VALUES)); 215 row_loc = 2*user->faultbus+1; col_loc = 2*user->faultbus; /* Location for G */ 216 val = 1/user->Rfault; 217 CHKERRQ(MatSetValues(user->Ybus,1,&row_loc,1,&col_loc,&val,ADD_VALUES)); 218 219 CHKERRQ(MatAssemblyBegin(user->Ybus,MAT_FINAL_ASSEMBLY)); 220 CHKERRQ(MatAssemblyEnd(user->Ybus,MAT_FINAL_ASSEMBLY)); 221 222 /* Solve the algebraic equations */ 223 CHKERRQ(SNESSolve(user->snes_alg,NULL,X)); 224 } else if (event_list[i] == 1) { 225 /* Remove the fault */ 226 row_loc = 2*user->faultbus; col_loc = 2*user->faultbus+1; 227 val = -1/user->Rfault; 228 CHKERRQ(MatSetValues(user->Ybus,1,&row_loc,1,&col_loc,&val,ADD_VALUES)); 229 row_loc = 2*user->faultbus+1; col_loc = 2*user->faultbus; 230 val = -1/user->Rfault; 231 CHKERRQ(MatSetValues(user->Ybus,1,&row_loc,1,&col_loc,&val,ADD_VALUES)); 232 233 CHKERRQ(MatAssemblyBegin(user->Ybus,MAT_FINAL_ASSEMBLY)); 234 CHKERRQ(MatAssemblyEnd(user->Ybus,MAT_FINAL_ASSEMBLY)); 235 236 /* Solve the algebraic equations */ 237 CHKERRQ(SNESSolve(user->snes_alg,NULL,X)); 238 239 /* Check the VR derivatives and reset flags if needed */ 240 for (i=0; i < ngen; i++) { 241 Efd = xgen[idx+6]; 242 RF = xgen[idx+7]; 243 VR = xgen[idx+8]; 244 245 Vr = xnet[2*gbus[i]]; /* Real part of generator terminal voltage */ 246 Vi = xnet[2*gbus[i]+1]; /* Imaginary part of the generator terminal voltage */ 247 Vm = PetscSqrtScalar(Vr*Vr + Vi*Vi); 248 249 if (VRatmax[i]) { 250 fvalue = (VR - KA[i]*RF + KA[i]*KF[i]*Efd/TF[i] - KA[i]*(Vref[i] - Vm))/TA[i]; 251 if (fvalue < 0) { 252 VRatmax[i] = 0; 253 CHKERRQ(PetscPrintf(PETSC_COMM_SELF,"VR[%d]: dVR_dt went negative on fault clearing at time %g\n",i,t)); 254 } 255 } 256 if (VRatmin[i]) { 257 fvalue = (VR - KA[i]*RF + KA[i]*KF[i]*Efd/TF[i] - KA[i]*(Vref[i] - Vm))/TA[i]; 258 259 if (fvalue > 0) { 260 VRatmin[i] = 0; 261 CHKERRQ(PetscPrintf(PETSC_COMM_SELF,"VR[%d]: dVR_dt went positive on fault clearing at time %g\n",i,t)); 262 } 263 } 264 idx = idx+9; 265 } 266 } else { 267 idx = (event_list[i]-2)/2; 268 event_num = (event_list[i]-2)%2; 269 if (event_num == 0) { /* Max VR */ 270 if (!VRatmax[idx]) { 271 VRatmax[idx] = 1; 272 CHKERRQ(PetscPrintf(PETSC_COMM_SELF,"VR[%d]: hit upper limit at time %g\n",idx,t)); 273 } 274 else { 275 VRatmax[idx] = 0; 276 CHKERRQ(PetscPrintf(PETSC_COMM_SELF,"VR[%d]: freeing variable as dVR_dt is negative at time %g\n",idx,t)); 277 } 278 } else { 279 if (!VRatmin[idx]) { 280 VRatmin[idx] = 1; 281 CHKERRQ(PetscPrintf(PETSC_COMM_SELF,"VR[%d]: hit lower limit at time %g\n",idx,t)); 282 } 283 else { 284 VRatmin[idx] = 0; 285 CHKERRQ(PetscPrintf(PETSC_COMM_SELF,"VR[%d]: freeing variable as dVR_dt is positive at time %g\n",idx,t)); 286 } 287 } 288 } 289 } 290 291 CHKERRQ(VecRestoreArray(Xgen,&xgen)); 292 CHKERRQ(VecRestoreArray(Xnet,&xnet)); 293 294 CHKERRQ(DMCompositeRestoreLocalVectors(user->dmpgrid,&Xgen,&Xnet)); 295 296 PetscFunctionReturn(0); 297 } 298 299 /* Converts from machine frame (dq) to network (phase a real,imag) reference frame */ 300 PetscErrorCode dq2ri(PetscScalar Fd,PetscScalar Fq,PetscScalar delta,PetscScalar *Fr, PetscScalar *Fi) 301 { 302 PetscFunctionBegin; 303 *Fr = Fd*PetscSinScalar(delta) + Fq*PetscCosScalar(delta); 304 *Fi = -Fd*PetscCosScalar(delta) + Fq*PetscSinScalar(delta); 305 PetscFunctionReturn(0); 306 } 307 308 /* Converts from network frame ([phase a real,imag) to machine (dq) reference frame */ 309 PetscErrorCode ri2dq(PetscScalar Fr,PetscScalar Fi,PetscScalar delta,PetscScalar *Fd, PetscScalar *Fq) 310 { 311 PetscFunctionBegin; 312 *Fd = Fr*PetscSinScalar(delta) - Fi*PetscCosScalar(delta); 313 *Fq = Fr*PetscCosScalar(delta) + Fi*PetscSinScalar(delta); 314 PetscFunctionReturn(0); 315 } 316 317 /* Saves the solution at each time to a matrix */ 318 PetscErrorCode SaveSolution(TS ts) 319 { 320 Userctx *user; 321 Vec X; 322 const PetscScalar *x; 323 PetscScalar *mat; 324 PetscInt idx; 325 PetscReal t; 326 327 PetscFunctionBegin; 328 CHKERRQ(TSGetApplicationContext(ts,&user)); 329 CHKERRQ(TSGetTime(ts,&t)); 330 CHKERRQ(TSGetSolution(ts,&X)); 331 idx = user->stepnum*(user->neqs_pgrid+1); 332 CHKERRQ(MatDenseGetArray(user->Sol,&mat)); 333 CHKERRQ(VecGetArrayRead(X,&x)); 334 mat[idx] = t; 335 CHKERRQ(PetscArraycpy(mat+idx+1,x,user->neqs_pgrid)); 336 CHKERRQ(MatDenseRestoreArray(user->Sol,&mat)); 337 CHKERRQ(VecRestoreArrayRead(X,&x)); 338 user->stepnum++; 339 PetscFunctionReturn(0); 340 } 341 342 PetscErrorCode SetInitialGuess(Vec X,Userctx *user) 343 { 344 Vec Xgen,Xnet; 345 PetscScalar *xgen; 346 const PetscScalar *xnet; 347 PetscInt i,idx=0; 348 PetscScalar Vr,Vi,IGr,IGi,Vm,Vm2; 349 PetscScalar Eqp,Edp,delta; 350 PetscScalar Efd,RF,VR; /* Exciter variables */ 351 PetscScalar Id,Iq; /* Generator dq axis currents */ 352 PetscScalar theta,Vd,Vq,SE; 353 354 PetscFunctionBegin; 355 M[0] = 2*H[0]/w_s; M[1] = 2*H[1]/w_s; M[2] = 2*H[2]/w_s; 356 D[0] = 0.1*M[0]; D[1] = 0.1*M[1]; D[2] = 0.1*M[2]; 357 358 CHKERRQ(DMCompositeGetLocalVectors(user->dmpgrid,&Xgen,&Xnet)); 359 360 /* Network subsystem initialization */ 361 CHKERRQ(VecCopy(user->V0,Xnet)); 362 363 /* Generator subsystem initialization */ 364 CHKERRQ(VecGetArrayWrite(Xgen,&xgen)); 365 CHKERRQ(VecGetArrayRead(Xnet,&xnet)); 366 367 for (i=0; i < ngen; i++) { 368 Vr = xnet[2*gbus[i]]; /* Real part of generator terminal voltage */ 369 Vi = xnet[2*gbus[i]+1]; /* Imaginary part of the generator terminal voltage */ 370 Vm = PetscSqrtScalar(Vr*Vr + Vi*Vi); Vm2 = Vm*Vm; 371 IGr = (Vr*PG[i] + Vi*QG[i])/Vm2; 372 IGi = (Vi*PG[i] - Vr*QG[i])/Vm2; 373 374 delta = PetscAtan2Real(Vi+Xq[i]*IGr,Vr-Xq[i]*IGi); /* Machine angle */ 375 376 theta = PETSC_PI/2.0 - delta; 377 378 Id = IGr*PetscCosScalar(theta) - IGi*PetscSinScalar(theta); /* d-axis stator current */ 379 Iq = IGr*PetscSinScalar(theta) + IGi*PetscCosScalar(theta); /* q-axis stator current */ 380 381 Vd = Vr*PetscCosScalar(theta) - Vi*PetscSinScalar(theta); 382 Vq = Vr*PetscSinScalar(theta) + Vi*PetscCosScalar(theta); 383 384 Edp = Vd + Rs[i]*Id - Xqp[i]*Iq; /* d-axis transient EMF */ 385 Eqp = Vq + Rs[i]*Iq + Xdp[i]*Id; /* q-axis transient EMF */ 386 387 TM[i] = PG[i]; 388 389 /* The generator variables are ordered as [Eqp,Edp,delta,w,Id,Iq] */ 390 xgen[idx] = Eqp; 391 xgen[idx+1] = Edp; 392 xgen[idx+2] = delta; 393 xgen[idx+3] = w_s; 394 395 idx = idx + 4; 396 397 xgen[idx] = Id; 398 xgen[idx+1] = Iq; 399 400 idx = idx + 2; 401 402 /* Exciter */ 403 Efd = Eqp + (Xd[i] - Xdp[i])*Id; 404 SE = k1[i]*PetscExpScalar(k2[i]*Efd); 405 VR = KE[i]*Efd + SE; 406 RF = KF[i]*Efd/TF[i]; 407 408 xgen[idx] = Efd; 409 xgen[idx+1] = RF; 410 xgen[idx+2] = VR; 411 412 Vref[i] = Vm + (VR/KA[i]); 413 414 VRatmin[i] = VRatmax[i] = 0; 415 416 idx = idx + 3; 417 } 418 CHKERRQ(VecRestoreArrayWrite(Xgen,&xgen)); 419 CHKERRQ(VecRestoreArrayRead(Xnet,&xnet)); 420 421 /* CHKERRQ(VecView(Xgen,0)); */ 422 CHKERRQ(DMCompositeGather(user->dmpgrid,INSERT_VALUES,X,Xgen,Xnet)); 423 CHKERRQ(DMCompositeRestoreLocalVectors(user->dmpgrid,&Xgen,&Xnet)); 424 PetscFunctionReturn(0); 425 } 426 427 /* Computes F = [f(x,y);g(x,y)] */ 428 PetscErrorCode ResidualFunction(Vec X, Vec F, Userctx *user) 429 { 430 Vec Xgen,Xnet,Fgen,Fnet; 431 const PetscScalar *xgen,*xnet; 432 PetscScalar *fgen,*fnet; 433 PetscInt i,idx=0; 434 PetscScalar Vr,Vi,Vm,Vm2; 435 PetscScalar Eqp,Edp,delta,w; /* Generator variables */ 436 PetscScalar Efd,RF,VR; /* Exciter variables */ 437 PetscScalar Id,Iq; /* Generator dq axis currents */ 438 PetscScalar Vd,Vq,SE; 439 PetscScalar IGr,IGi,IDr,IDi; 440 PetscScalar Zdq_inv[4],det; 441 PetscScalar PD,QD,Vm0,*v0; 442 PetscInt k; 443 444 PetscFunctionBegin; 445 CHKERRQ(VecZeroEntries(F)); 446 CHKERRQ(DMCompositeGetLocalVectors(user->dmpgrid,&Xgen,&Xnet)); 447 CHKERRQ(DMCompositeGetLocalVectors(user->dmpgrid,&Fgen,&Fnet)); 448 CHKERRQ(DMCompositeScatter(user->dmpgrid,X,Xgen,Xnet)); 449 CHKERRQ(DMCompositeScatter(user->dmpgrid,F,Fgen,Fnet)); 450 451 /* Network current balance residual IG + Y*V + IL = 0. Only YV is added here. 452 The generator current injection, IG, and load current injection, ID are added later 453 */ 454 /* Note that the values in Ybus are stored assuming the imaginary current balance 455 equation is ordered first followed by real current balance equation for each bus. 456 Thus imaginary current contribution goes in location 2*i, and 457 real current contribution in 2*i+1 458 */ 459 CHKERRQ(MatMult(user->Ybus,Xnet,Fnet)); 460 461 CHKERRQ(VecGetArrayRead(Xgen,&xgen)); 462 CHKERRQ(VecGetArrayRead(Xnet,&xnet)); 463 CHKERRQ(VecGetArrayWrite(Fgen,&fgen)); 464 CHKERRQ(VecGetArrayWrite(Fnet,&fnet)); 465 466 /* Generator subsystem */ 467 for (i=0; i < ngen; i++) { 468 Eqp = xgen[idx]; 469 Edp = xgen[idx+1]; 470 delta = xgen[idx+2]; 471 w = xgen[idx+3]; 472 Id = xgen[idx+4]; 473 Iq = xgen[idx+5]; 474 Efd = xgen[idx+6]; 475 RF = xgen[idx+7]; 476 VR = xgen[idx+8]; 477 478 /* Generator differential equations */ 479 fgen[idx] = (-Eqp - (Xd[i] - Xdp[i])*Id + Efd)/Td0p[i]; 480 fgen[idx+1] = (-Edp + (Xq[i] - Xqp[i])*Iq)/Tq0p[i]; 481 fgen[idx+2] = w - w_s; 482 fgen[idx+3] = (TM[i] - Edp*Id - Eqp*Iq - (Xqp[i] - Xdp[i])*Id*Iq - D[i]*(w - w_s))/M[i]; 483 484 Vr = xnet[2*gbus[i]]; /* Real part of generator terminal voltage */ 485 Vi = xnet[2*gbus[i]+1]; /* Imaginary part of the generator terminal voltage */ 486 487 CHKERRQ(ri2dq(Vr,Vi,delta,&Vd,&Vq)); 488 /* Algebraic equations for stator currents */ 489 det = Rs[i]*Rs[i] + Xdp[i]*Xqp[i]; 490 491 Zdq_inv[0] = Rs[i]/det; 492 Zdq_inv[1] = Xqp[i]/det; 493 Zdq_inv[2] = -Xdp[i]/det; 494 Zdq_inv[3] = Rs[i]/det; 495 496 fgen[idx+4] = Zdq_inv[0]*(-Edp + Vd) + Zdq_inv[1]*(-Eqp + Vq) + Id; 497 fgen[idx+5] = Zdq_inv[2]*(-Edp + Vd) + Zdq_inv[3]*(-Eqp + Vq) + Iq; 498 499 /* Add generator current injection to network */ 500 CHKERRQ(dq2ri(Id,Iq,delta,&IGr,&IGi)); 501 502 fnet[2*gbus[i]] -= IGi; 503 fnet[2*gbus[i]+1] -= IGr; 504 505 Vm = PetscSqrtScalar(Vd*Vd + Vq*Vq); 506 507 SE = k1[i]*PetscExpScalar(k2[i]*Efd); 508 509 /* Exciter differential equations */ 510 fgen[idx+6] = (-KE[i]*Efd - SE + VR)/TE[i]; 511 fgen[idx+7] = (-RF + KF[i]*Efd/TF[i])/TF[i]; 512 if (VRatmax[i]) fgen[idx+8] = VR - VRMAX[i]; 513 else if (VRatmin[i]) fgen[idx+8] = VRMIN[i] - VR; 514 else fgen[idx+8] = (-VR + KA[i]*RF - KA[i]*KF[i]*Efd/TF[i] + KA[i]*(Vref[i] - Vm))/TA[i]; 515 516 idx = idx + 9; 517 } 518 519 CHKERRQ(VecGetArray(user->V0,&v0)); 520 for (i=0; i < nload; i++) { 521 Vr = xnet[2*lbus[i]]; /* Real part of load bus voltage */ 522 Vi = xnet[2*lbus[i]+1]; /* Imaginary part of the load bus voltage */ 523 Vm = PetscSqrtScalar(Vr*Vr + Vi*Vi); Vm2 = Vm*Vm; 524 Vm0 = PetscSqrtScalar(v0[2*lbus[i]]*v0[2*lbus[i]] + v0[2*lbus[i]+1]*v0[2*lbus[i]+1]); 525 PD = QD = 0.0; 526 for (k=0; k < ld_nsegsp[i]; k++) PD += ld_alphap[k]*PD0[i]*PetscPowScalar((Vm/Vm0),ld_betap[k]); 527 for (k=0; k < ld_nsegsq[i]; k++) QD += ld_alphaq[k]*QD0[i]*PetscPowScalar((Vm/Vm0),ld_betaq[k]); 528 529 /* Load currents */ 530 IDr = (PD*Vr + QD*Vi)/Vm2; 531 IDi = (-QD*Vr + PD*Vi)/Vm2; 532 533 fnet[2*lbus[i]] += IDi; 534 fnet[2*lbus[i]+1] += IDr; 535 } 536 CHKERRQ(VecRestoreArray(user->V0,&v0)); 537 538 CHKERRQ(VecRestoreArrayRead(Xgen,&xgen)); 539 CHKERRQ(VecRestoreArrayRead(Xnet,&xnet)); 540 CHKERRQ(VecRestoreArrayWrite(Fgen,&fgen)); 541 CHKERRQ(VecRestoreArrayWrite(Fnet,&fnet)); 542 543 CHKERRQ(DMCompositeGather(user->dmpgrid,INSERT_VALUES,F,Fgen,Fnet)); 544 CHKERRQ(DMCompositeRestoreLocalVectors(user->dmpgrid,&Xgen,&Xnet)); 545 CHKERRQ(DMCompositeRestoreLocalVectors(user->dmpgrid,&Fgen,&Fnet)); 546 PetscFunctionReturn(0); 547 } 548 549 /* f(x,y) 550 g(x,y) 551 */ 552 PetscErrorCode RHSFunction(TS ts,PetscReal t, Vec X, Vec F, void *ctx) 553 { 554 Userctx *user=(Userctx*)ctx; 555 556 PetscFunctionBegin; 557 user->t = t; 558 CHKERRQ(ResidualFunction(X,F,user)); 559 PetscFunctionReturn(0); 560 } 561 562 /* f(x,y) - \dot{x} 563 g(x,y) = 0 564 */ 565 PetscErrorCode IFunction(TS ts,PetscReal t, Vec X, Vec Xdot, Vec F, void *ctx) 566 { 567 PetscScalar *f; 568 const PetscScalar *xdot; 569 PetscInt i; 570 571 PetscFunctionBegin; 572 CHKERRQ(RHSFunction(ts,t,X,F,ctx)); 573 CHKERRQ(VecScale(F,-1.0)); 574 CHKERRQ(VecGetArray(F,&f)); 575 CHKERRQ(VecGetArrayRead(Xdot,&xdot)); 576 for (i=0;i < ngen;i++) { 577 f[9*i] += xdot[9*i]; 578 f[9*i+1] += xdot[9*i+1]; 579 f[9*i+2] += xdot[9*i+2]; 580 f[9*i+3] += xdot[9*i+3]; 581 f[9*i+6] += xdot[9*i+6]; 582 f[9*i+7] += xdot[9*i+7]; 583 f[9*i+8] += xdot[9*i+8]; 584 } 585 CHKERRQ(VecRestoreArray(F,&f)); 586 CHKERRQ(VecRestoreArrayRead(Xdot,&xdot)); 587 PetscFunctionReturn(0); 588 } 589 590 /* This function is used for solving the algebraic system only during fault on and 591 off times. It computes the entire F and then zeros out the part corresponding to 592 differential equations 593 F = [0;g(y)]; 594 */ 595 PetscErrorCode AlgFunction(SNES snes, Vec X, Vec F, void *ctx) 596 { 597 Userctx *user=(Userctx*)ctx; 598 PetscScalar *f; 599 PetscInt i; 600 601 PetscFunctionBegin; 602 CHKERRQ(ResidualFunction(X,F,user)); 603 CHKERRQ(VecGetArray(F,&f)); 604 for (i=0; i < ngen; i++) { 605 f[9*i] = 0; 606 f[9*i+1] = 0; 607 f[9*i+2] = 0; 608 f[9*i+3] = 0; 609 f[9*i+6] = 0; 610 f[9*i+7] = 0; 611 f[9*i+8] = 0; 612 } 613 CHKERRQ(VecRestoreArray(F,&f)); 614 PetscFunctionReturn(0); 615 } 616 617 PetscErrorCode PostStage(TS ts, PetscReal t, PetscInt i, Vec *X) 618 { 619 Userctx *user; 620 621 PetscFunctionBegin; 622 CHKERRQ(TSGetApplicationContext(ts,&user)); 623 CHKERRQ(SNESSolve(user->snes_alg,NULL,X[i])); 624 PetscFunctionReturn(0); 625 } 626 627 PetscErrorCode PostEvaluate(TS ts) 628 { 629 Userctx *user; 630 Vec X; 631 632 PetscFunctionBegin; 633 CHKERRQ(TSGetApplicationContext(ts,&user)); 634 CHKERRQ(TSGetSolution(ts,&X)); 635 CHKERRQ(SNESSolve(user->snes_alg,NULL,X)); 636 PetscFunctionReturn(0); 637 } 638 639 PetscErrorCode PreallocateJacobian(Mat J, Userctx *user) 640 { 641 PetscInt *d_nnz; 642 PetscInt i,idx=0,start=0; 643 PetscInt ncols; 644 645 PetscFunctionBegin; 646 CHKERRQ(PetscMalloc1(user->neqs_pgrid,&d_nnz)); 647 for (i=0; i<user->neqs_pgrid; i++) d_nnz[i] = 0; 648 /* Generator subsystem */ 649 for (i=0; i < ngen; i++) { 650 651 d_nnz[idx] += 3; 652 d_nnz[idx+1] += 2; 653 d_nnz[idx+2] += 2; 654 d_nnz[idx+3] += 5; 655 d_nnz[idx+4] += 6; 656 d_nnz[idx+5] += 6; 657 658 d_nnz[user->neqs_gen+2*gbus[i]] += 3; 659 d_nnz[user->neqs_gen+2*gbus[i]+1] += 3; 660 661 d_nnz[idx+6] += 2; 662 d_nnz[idx+7] += 2; 663 d_nnz[idx+8] += 5; 664 665 idx = idx + 9; 666 } 667 start = user->neqs_gen; 668 669 for (i=0; i < nbus; i++) { 670 CHKERRQ(MatGetRow(user->Ybus,2*i,&ncols,NULL,NULL)); 671 d_nnz[start+2*i] += ncols; 672 d_nnz[start+2*i+1] += ncols; 673 CHKERRQ(MatRestoreRow(user->Ybus,2*i,&ncols,NULL,NULL)); 674 } 675 CHKERRQ(MatSeqAIJSetPreallocation(J,0,d_nnz)); 676 CHKERRQ(PetscFree(d_nnz)); 677 PetscFunctionReturn(0); 678 } 679 680 /* 681 J = [df_dx, df_dy 682 dg_dx, dg_dy] 683 */ 684 PetscErrorCode ResidualJacobian(Vec X,Mat J,Mat B,void *ctx) 685 { 686 Userctx *user = (Userctx*)ctx; 687 Vec Xgen,Xnet; 688 const PetscScalar *xgen,*xnet; 689 PetscInt i,idx=0; 690 PetscScalar Vr,Vi,Vm,Vm2; 691 PetscScalar Eqp,Edp,delta; /* Generator variables */ 692 PetscScalar Efd; 693 PetscScalar Id,Iq; /* Generator dq axis currents */ 694 PetscScalar Vd,Vq; 695 PetscScalar val[10]; 696 PetscInt row[2],col[10]; 697 PetscInt net_start = user->neqs_gen; 698 PetscScalar Zdq_inv[4],det; 699 PetscScalar dVd_dVr,dVd_dVi,dVq_dVr,dVq_dVi,dVd_ddelta,dVq_ddelta; 700 PetscScalar dIGr_ddelta,dIGi_ddelta,dIGr_dId,dIGr_dIq,dIGi_dId,dIGi_dIq; 701 PetscScalar dSE_dEfd; 702 PetscScalar dVm_dVd,dVm_dVq,dVm_dVr,dVm_dVi; 703 PetscInt ncols; 704 const PetscInt *cols; 705 const PetscScalar *yvals; 706 PetscInt k; 707 PetscScalar PD,QD,Vm0,Vm4; 708 const PetscScalar *v0; 709 PetscScalar dPD_dVr,dPD_dVi,dQD_dVr,dQD_dVi; 710 PetscScalar dIDr_dVr,dIDr_dVi,dIDi_dVr,dIDi_dVi; 711 712 PetscFunctionBegin; 713 CHKERRQ(MatZeroEntries(B)); 714 CHKERRQ(DMCompositeGetLocalVectors(user->dmpgrid,&Xgen,&Xnet)); 715 CHKERRQ(DMCompositeScatter(user->dmpgrid,X,Xgen,Xnet)); 716 717 CHKERRQ(VecGetArrayRead(Xgen,&xgen)); 718 CHKERRQ(VecGetArrayRead(Xnet,&xnet)); 719 720 /* Generator subsystem */ 721 for (i=0; i < ngen; i++) { 722 Eqp = xgen[idx]; 723 Edp = xgen[idx+1]; 724 delta = xgen[idx+2]; 725 Id = xgen[idx+4]; 726 Iq = xgen[idx+5]; 727 Efd = xgen[idx+6]; 728 729 /* fgen[idx] = (-Eqp - (Xd[i] - Xdp[i])*Id + Efd)/Td0p[i]; */ 730 row[0] = idx; 731 col[0] = idx; col[1] = idx+4; col[2] = idx+6; 732 val[0] = -1/ Td0p[i]; val[1] = -(Xd[i] - Xdp[i])/ Td0p[i]; val[2] = 1/Td0p[i]; 733 734 CHKERRQ(MatSetValues(J,1,row,3,col,val,INSERT_VALUES)); 735 736 /* fgen[idx+1] = (-Edp + (Xq[i] - Xqp[i])*Iq)/Tq0p[i]; */ 737 row[0] = idx + 1; 738 col[0] = idx + 1; col[1] = idx+5; 739 val[0] = -1/Tq0p[i]; val[1] = (Xq[i] - Xqp[i])/Tq0p[i]; 740 CHKERRQ(MatSetValues(J,1,row,2,col,val,INSERT_VALUES)); 741 742 /* fgen[idx+2] = w - w_s; */ 743 row[0] = idx + 2; 744 col[0] = idx + 2; col[1] = idx + 3; 745 val[0] = 0; val[1] = 1; 746 CHKERRQ(MatSetValues(J,1,row,2,col,val,INSERT_VALUES)); 747 748 /* fgen[idx+3] = (TM[i] - Edp*Id - Eqp*Iq - (Xqp[i] - Xdp[i])*Id*Iq - D[i]*(w - w_s))/M[i]; */ 749 row[0] = idx + 3; 750 col[0] = idx; col[1] = idx + 1; col[2] = idx + 3; col[3] = idx + 4; col[4] = idx + 5; 751 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]; 752 CHKERRQ(MatSetValues(J,1,row,5,col,val,INSERT_VALUES)); 753 754 Vr = xnet[2*gbus[i]]; /* Real part of generator terminal voltage */ 755 Vi = xnet[2*gbus[i]+1]; /* Imaginary part of the generator terminal voltage */ 756 CHKERRQ(ri2dq(Vr,Vi,delta,&Vd,&Vq)); 757 758 det = Rs[i]*Rs[i] + Xdp[i]*Xqp[i]; 759 760 Zdq_inv[0] = Rs[i]/det; 761 Zdq_inv[1] = Xqp[i]/det; 762 Zdq_inv[2] = -Xdp[i]/det; 763 Zdq_inv[3] = Rs[i]/det; 764 765 dVd_dVr = PetscSinScalar(delta); dVd_dVi = -PetscCosScalar(delta); 766 dVq_dVr = PetscCosScalar(delta); dVq_dVi = PetscSinScalar(delta); 767 dVd_ddelta = Vr*PetscCosScalar(delta) + Vi*PetscSinScalar(delta); 768 dVq_ddelta = -Vr*PetscSinScalar(delta) + Vi*PetscCosScalar(delta); 769 770 /* fgen[idx+4] = Zdq_inv[0]*(-Edp + Vd) + Zdq_inv[1]*(-Eqp + Vq) + Id; */ 771 row[0] = idx+4; 772 col[0] = idx; col[1] = idx+1; col[2] = idx + 2; 773 val[0] = -Zdq_inv[1]; val[1] = -Zdq_inv[0]; val[2] = Zdq_inv[0]*dVd_ddelta + Zdq_inv[1]*dVq_ddelta; 774 col[3] = idx + 4; col[4] = net_start+2*gbus[i]; col[5] = net_start + 2*gbus[i]+1; 775 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; 776 CHKERRQ(MatSetValues(J,1,row,6,col,val,INSERT_VALUES)); 777 778 /* fgen[idx+5] = Zdq_inv[2]*(-Edp + Vd) + Zdq_inv[3]*(-Eqp + Vq) + Iq; */ 779 row[0] = idx+5; 780 col[0] = idx; col[1] = idx+1; col[2] = idx + 2; 781 val[0] = -Zdq_inv[3]; val[1] = -Zdq_inv[2]; val[2] = Zdq_inv[2]*dVd_ddelta + Zdq_inv[3]*dVq_ddelta; 782 col[3] = idx + 5; col[4] = net_start+2*gbus[i]; col[5] = net_start + 2*gbus[i]+1; 783 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; 784 CHKERRQ(MatSetValues(J,1,row,6,col,val,INSERT_VALUES)); 785 786 dIGr_ddelta = Id*PetscCosScalar(delta) - Iq*PetscSinScalar(delta); 787 dIGi_ddelta = Id*PetscSinScalar(delta) + Iq*PetscCosScalar(delta); 788 dIGr_dId = PetscSinScalar(delta); dIGr_dIq = PetscCosScalar(delta); 789 dIGi_dId = -PetscCosScalar(delta); dIGi_dIq = PetscSinScalar(delta); 790 791 /* fnet[2*gbus[i]] -= IGi; */ 792 row[0] = net_start + 2*gbus[i]; 793 col[0] = idx+2; col[1] = idx + 4; col[2] = idx + 5; 794 val[0] = -dIGi_ddelta; val[1] = -dIGi_dId; val[2] = -dIGi_dIq; 795 CHKERRQ(MatSetValues(J,1,row,3,col,val,INSERT_VALUES)); 796 797 /* fnet[2*gbus[i]+1] -= IGr; */ 798 row[0] = net_start + 2*gbus[i]+1; 799 col[0] = idx+2; col[1] = idx + 4; col[2] = idx + 5; 800 val[0] = -dIGr_ddelta; val[1] = -dIGr_dId; val[2] = -dIGr_dIq; 801 CHKERRQ(MatSetValues(J,1,row,3,col,val,INSERT_VALUES)); 802 803 Vm = PetscSqrtScalar(Vd*Vd + Vq*Vq); 804 805 /* fgen[idx+6] = (-KE[i]*Efd - SE + VR)/TE[i]; */ 806 /* SE = k1[i]*PetscExpScalar(k2[i]*Efd); */ 807 808 dSE_dEfd = k1[i]*k2[i]*PetscExpScalar(k2[i]*Efd); 809 810 row[0] = idx + 6; 811 col[0] = idx + 6; col[1] = idx + 8; 812 val[0] = (-KE[i] - dSE_dEfd)/TE[i]; val[1] = 1/TE[i]; 813 CHKERRQ(MatSetValues(J,1,row,2,col,val,INSERT_VALUES)); 814 815 /* Exciter differential equations */ 816 817 /* fgen[idx+7] = (-RF + KF[i]*Efd/TF[i])/TF[i]; */ 818 row[0] = idx + 7; 819 col[0] = idx + 6; col[1] = idx + 7; 820 val[0] = (KF[i]/TF[i])/TF[i]; val[1] = -1/TF[i]; 821 CHKERRQ(MatSetValues(J,1,row,2,col,val,INSERT_VALUES)); 822 823 /* fgen[idx+8] = (-VR + KA[i]*RF - KA[i]*KF[i]*Efd/TF[i] + KA[i]*(Vref[i] - Vm))/TA[i]; */ 824 /* Vm = (Vd^2 + Vq^2)^0.5; */ 825 826 row[0] = idx + 8; 827 if (VRatmax[i]) { 828 col[0] = idx + 8; val[0] = 1.0; 829 CHKERRQ(MatSetValues(J,1,row,1,col,val,INSERT_VALUES)); 830 } else if (VRatmin[i]) { 831 col[0] = idx + 8; val[0] = -1.0; 832 CHKERRQ(MatSetValues(J,1,row,1,col,val,INSERT_VALUES)); 833 } else { 834 dVm_dVd = Vd/Vm; dVm_dVq = Vq/Vm; 835 dVm_dVr = dVm_dVd*dVd_dVr + dVm_dVq*dVq_dVr; 836 dVm_dVi = dVm_dVd*dVd_dVi + dVm_dVq*dVq_dVi; 837 row[0] = idx + 8; 838 col[0] = idx + 6; col[1] = idx + 7; col[2] = idx + 8; 839 val[0] = -(KA[i]*KF[i]/TF[i])/TA[i]; val[1] = KA[i]/TA[i]; val[2] = -1/TA[i]; 840 col[3] = net_start + 2*gbus[i]; col[4] = net_start + 2*gbus[i]+1; 841 val[3] = -KA[i]*dVm_dVr/TA[i]; val[4] = -KA[i]*dVm_dVi/TA[i]; 842 CHKERRQ(MatSetValues(J,1,row,5,col,val,INSERT_VALUES)); 843 } 844 idx = idx + 9; 845 } 846 847 for (i=0; i<nbus; i++) { 848 CHKERRQ(MatGetRow(user->Ybus,2*i,&ncols,&cols,&yvals)); 849 row[0] = net_start + 2*i; 850 for (k=0; k<ncols; k++) { 851 col[k] = net_start + cols[k]; 852 val[k] = yvals[k]; 853 } 854 CHKERRQ(MatSetValues(J,1,row,ncols,col,val,INSERT_VALUES)); 855 CHKERRQ(MatRestoreRow(user->Ybus,2*i,&ncols,&cols,&yvals)); 856 857 CHKERRQ(MatGetRow(user->Ybus,2*i+1,&ncols,&cols,&yvals)); 858 row[0] = net_start + 2*i+1; 859 for (k=0; k<ncols; k++) { 860 col[k] = net_start + cols[k]; 861 val[k] = yvals[k]; 862 } 863 CHKERRQ(MatSetValues(J,1,row,ncols,col,val,INSERT_VALUES)); 864 CHKERRQ(MatRestoreRow(user->Ybus,2*i+1,&ncols,&cols,&yvals)); 865 } 866 867 CHKERRQ(MatAssemblyBegin(J,MAT_FLUSH_ASSEMBLY)); 868 CHKERRQ(MatAssemblyEnd(J,MAT_FLUSH_ASSEMBLY)); 869 870 CHKERRQ(VecGetArrayRead(user->V0,&v0)); 871 for (i=0; i < nload; i++) { 872 Vr = xnet[2*lbus[i]]; /* Real part of load bus voltage */ 873 Vi = xnet[2*lbus[i]+1]; /* Imaginary part of the load bus voltage */ 874 Vm = PetscSqrtScalar(Vr*Vr + Vi*Vi); Vm2 = Vm*Vm; Vm4 = Vm2*Vm2; 875 Vm0 = PetscSqrtScalar(v0[2*lbus[i]]*v0[2*lbus[i]] + v0[2*lbus[i]+1]*v0[2*lbus[i]+1]); 876 PD = QD = 0.0; 877 dPD_dVr = dPD_dVi = dQD_dVr = dQD_dVi = 0.0; 878 for (k=0; k < ld_nsegsp[i]; k++) { 879 PD += ld_alphap[k]*PD0[i]*PetscPowScalar((Vm/Vm0),ld_betap[k]); 880 dPD_dVr += ld_alphap[k]*ld_betap[k]*PD0[i]*PetscPowScalar((1/Vm0),ld_betap[k])*Vr*PetscPowScalar(Vm,(ld_betap[k]-2)); 881 dPD_dVi += ld_alphap[k]*ld_betap[k]*PD0[i]*PetscPowScalar((1/Vm0),ld_betap[k])*Vi*PetscPowScalar(Vm,(ld_betap[k]-2)); 882 } 883 for (k=0; k < ld_nsegsq[i]; k++) { 884 QD += ld_alphaq[k]*QD0[i]*PetscPowScalar((Vm/Vm0),ld_betaq[k]); 885 dQD_dVr += ld_alphaq[k]*ld_betaq[k]*QD0[i]*PetscPowScalar((1/Vm0),ld_betaq[k])*Vr*PetscPowScalar(Vm,(ld_betaq[k]-2)); 886 dQD_dVi += ld_alphaq[k]*ld_betaq[k]*QD0[i]*PetscPowScalar((1/Vm0),ld_betaq[k])*Vi*PetscPowScalar(Vm,(ld_betaq[k]-2)); 887 } 888 889 /* IDr = (PD*Vr + QD*Vi)/Vm2; */ 890 /* IDi = (-QD*Vr + PD*Vi)/Vm2; */ 891 892 dIDr_dVr = (dPD_dVr*Vr + dQD_dVr*Vi + PD)/Vm2 - ((PD*Vr + QD*Vi)*2*Vr)/Vm4; 893 dIDr_dVi = (dPD_dVi*Vr + dQD_dVi*Vi + QD)/Vm2 - ((PD*Vr + QD*Vi)*2*Vi)/Vm4; 894 895 dIDi_dVr = (-dQD_dVr*Vr + dPD_dVr*Vi - QD)/Vm2 - ((-QD*Vr + PD*Vi)*2*Vr)/Vm4; 896 dIDi_dVi = (-dQD_dVi*Vr + dPD_dVi*Vi + PD)/Vm2 - ((-QD*Vr + PD*Vi)*2*Vi)/Vm4; 897 898 /* fnet[2*lbus[i]] += IDi; */ 899 row[0] = net_start + 2*lbus[i]; 900 col[0] = net_start + 2*lbus[i]; col[1] = net_start + 2*lbus[i]+1; 901 val[0] = dIDi_dVr; val[1] = dIDi_dVi; 902 CHKERRQ(MatSetValues(J,1,row,2,col,val,ADD_VALUES)); 903 /* fnet[2*lbus[i]+1] += IDr; */ 904 row[0] = net_start + 2*lbus[i]+1; 905 col[0] = net_start + 2*lbus[i]; col[1] = net_start + 2*lbus[i]+1; 906 val[0] = dIDr_dVr; val[1] = dIDr_dVi; 907 CHKERRQ(MatSetValues(J,1,row,2,col,val,ADD_VALUES)); 908 } 909 CHKERRQ(VecRestoreArrayRead(user->V0,&v0)); 910 911 CHKERRQ(VecRestoreArrayRead(Xgen,&xgen)); 912 CHKERRQ(VecRestoreArrayRead(Xnet,&xnet)); 913 914 CHKERRQ(DMCompositeRestoreLocalVectors(user->dmpgrid,&Xgen,&Xnet)); 915 916 CHKERRQ(MatAssemblyBegin(J,MAT_FINAL_ASSEMBLY)); 917 CHKERRQ(MatAssemblyEnd(J,MAT_FINAL_ASSEMBLY)); 918 PetscFunctionReturn(0); 919 } 920 921 /* 922 J = [I, 0 923 dg_dx, dg_dy] 924 */ 925 PetscErrorCode AlgJacobian(SNES snes,Vec X,Mat A,Mat B,void *ctx) 926 { 927 Userctx *user=(Userctx*)ctx; 928 929 PetscFunctionBegin; 930 CHKERRQ(ResidualJacobian(X,A,B,ctx)); 931 CHKERRQ(MatSetOption(A,MAT_KEEP_NONZERO_PATTERN,PETSC_TRUE)); 932 CHKERRQ(MatZeroRowsIS(A,user->is_diff,1.0,NULL,NULL)); 933 PetscFunctionReturn(0); 934 } 935 936 /* 937 J = [-df_dx, -df_dy 938 dg_dx, dg_dy] 939 */ 940 941 PetscErrorCode RHSJacobian(TS ts,PetscReal t,Vec X,Mat A,Mat B,void *ctx) 942 { 943 Userctx *user=(Userctx*)ctx; 944 945 PetscFunctionBegin; 946 user->t = t; 947 948 CHKERRQ(ResidualJacobian(X,A,B,user)); 949 950 PetscFunctionReturn(0); 951 } 952 953 /* 954 J = [df_dx-aI, df_dy 955 dg_dx, dg_dy] 956 */ 957 958 PetscErrorCode IJacobian(TS ts,PetscReal t,Vec X,Vec Xdot,PetscReal a,Mat A,Mat B,Userctx *user) 959 { 960 PetscScalar atmp = (PetscScalar) a; 961 PetscInt i,row; 962 963 PetscFunctionBegin; 964 user->t = t; 965 966 CHKERRQ(RHSJacobian(ts,t,X,A,B,user)); 967 CHKERRQ(MatScale(B,-1.0)); 968 for (i=0;i < ngen;i++) { 969 row = 9*i; 970 CHKERRQ(MatSetValues(A,1,&row,1,&row,&atmp,ADD_VALUES)); 971 row = 9*i+1; 972 CHKERRQ(MatSetValues(A,1,&row,1,&row,&atmp,ADD_VALUES)); 973 row = 9*i+2; 974 CHKERRQ(MatSetValues(A,1,&row,1,&row,&atmp,ADD_VALUES)); 975 row = 9*i+3; 976 CHKERRQ(MatSetValues(A,1,&row,1,&row,&atmp,ADD_VALUES)); 977 row = 9*i+6; 978 CHKERRQ(MatSetValues(A,1,&row,1,&row,&atmp,ADD_VALUES)); 979 row = 9*i+7; 980 CHKERRQ(MatSetValues(A,1,&row,1,&row,&atmp,ADD_VALUES)); 981 row = 9*i+8; 982 CHKERRQ(MatSetValues(A,1,&row,1,&row,&atmp,ADD_VALUES)); 983 } 984 CHKERRQ(MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY)); 985 CHKERRQ(MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY)); 986 PetscFunctionReturn(0); 987 } 988 989 int main(int argc,char **argv) 990 { 991 TS ts; 992 SNES snes_alg; 993 PetscErrorCode ierr; 994 PetscMPIInt size; 995 Userctx user; 996 PetscViewer Xview,Ybusview,viewer; 997 Vec X,F_alg; 998 Mat J,A; 999 PetscInt i,idx,*idx2; 1000 Vec Xdot; 1001 PetscScalar *x,*mat,*amat; 1002 const PetscScalar *rmat; 1003 Vec vatol; 1004 PetscInt *direction; 1005 PetscBool *terminate; 1006 const PetscInt *idx3; 1007 PetscScalar *vatoli; 1008 PetscInt k; 1009 1010 ierr = PetscInitialize(&argc,&argv,"petscoptions",help);if (ierr) return ierr; 1011 CHKERRMPI(MPI_Comm_size(PETSC_COMM_WORLD,&size)); 1012 PetscCheck(size == 1,PETSC_COMM_WORLD,PETSC_ERR_WRONG_MPI_SIZE,"Only for sequential runs"); 1013 1014 user.neqs_gen = 9*ngen; /* # eqs. for generator subsystem */ 1015 user.neqs_net = 2*nbus; /* # eqs. for network subsystem */ 1016 user.neqs_pgrid = user.neqs_gen + user.neqs_net; 1017 1018 /* Create indices for differential and algebraic equations */ 1019 1020 CHKERRQ(PetscMalloc1(7*ngen,&idx2)); 1021 for (i=0; i<ngen; i++) { 1022 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; 1023 idx2[7*i+4] = 9*i+6; idx2[7*i+5] = 9*i+7; idx2[7*i+6] = 9*i+8; 1024 } 1025 CHKERRQ(ISCreateGeneral(PETSC_COMM_WORLD,7*ngen,idx2,PETSC_COPY_VALUES,&user.is_diff)); 1026 CHKERRQ(ISComplement(user.is_diff,0,user.neqs_pgrid,&user.is_alg)); 1027 CHKERRQ(PetscFree(idx2)); 1028 1029 /* Read initial voltage vector and Ybus */ 1030 CHKERRQ(PetscViewerBinaryOpen(PETSC_COMM_WORLD,"X.bin",FILE_MODE_READ,&Xview)); 1031 CHKERRQ(PetscViewerBinaryOpen(PETSC_COMM_WORLD,"Ybus.bin",FILE_MODE_READ,&Ybusview)); 1032 1033 CHKERRQ(VecCreate(PETSC_COMM_WORLD,&user.V0)); 1034 CHKERRQ(VecSetSizes(user.V0,PETSC_DECIDE,user.neqs_net)); 1035 CHKERRQ(VecLoad(user.V0,Xview)); 1036 1037 CHKERRQ(MatCreate(PETSC_COMM_WORLD,&user.Ybus)); 1038 CHKERRQ(MatSetSizes(user.Ybus,PETSC_DECIDE,PETSC_DECIDE,user.neqs_net,user.neqs_net)); 1039 CHKERRQ(MatSetType(user.Ybus,MATBAIJ)); 1040 /* CHKERRQ(MatSetBlockSize(user.Ybus,2)); */ 1041 CHKERRQ(MatLoad(user.Ybus,Ybusview)); 1042 1043 /* Set run time options */ 1044 ierr = PetscOptionsBegin(PETSC_COMM_WORLD,NULL,"Transient stability fault options","");CHKERRQ(ierr); 1045 { 1046 user.tfaulton = 1.0; 1047 user.tfaultoff = 1.2; 1048 user.Rfault = 0.0001; 1049 user.setisdiff = PETSC_FALSE; 1050 user.semiexplicit = PETSC_FALSE; 1051 user.faultbus = 8; 1052 CHKERRQ(PetscOptionsReal("-tfaulton","","",user.tfaulton,&user.tfaulton,NULL)); 1053 CHKERRQ(PetscOptionsReal("-tfaultoff","","",user.tfaultoff,&user.tfaultoff,NULL)); 1054 CHKERRQ(PetscOptionsInt("-faultbus","","",user.faultbus,&user.faultbus,NULL)); 1055 user.t0 = 0.0; 1056 user.tmax = 5.0; 1057 CHKERRQ(PetscOptionsReal("-t0","","",user.t0,&user.t0,NULL)); 1058 CHKERRQ(PetscOptionsReal("-tmax","","",user.tmax,&user.tmax,NULL)); 1059 CHKERRQ(PetscOptionsBool("-setisdiff","","",user.setisdiff,&user.setisdiff,NULL)); 1060 CHKERRQ(PetscOptionsBool("-dae_semiexplicit","","",user.semiexplicit,&user.semiexplicit,NULL)); 1061 } 1062 ierr = PetscOptionsEnd();CHKERRQ(ierr); 1063 1064 CHKERRQ(PetscViewerDestroy(&Xview)); 1065 CHKERRQ(PetscViewerDestroy(&Ybusview)); 1066 1067 /* Create DMs for generator and network subsystems */ 1068 CHKERRQ(DMDACreate1d(PETSC_COMM_WORLD,DM_BOUNDARY_NONE,user.neqs_gen,1,1,NULL,&user.dmgen)); 1069 CHKERRQ(DMSetOptionsPrefix(user.dmgen,"dmgen_")); 1070 CHKERRQ(DMSetFromOptions(user.dmgen)); 1071 CHKERRQ(DMSetUp(user.dmgen)); 1072 CHKERRQ(DMDACreate1d(PETSC_COMM_WORLD,DM_BOUNDARY_NONE,user.neqs_net,1,1,NULL,&user.dmnet)); 1073 CHKERRQ(DMSetOptionsPrefix(user.dmnet,"dmnet_")); 1074 CHKERRQ(DMSetFromOptions(user.dmnet)); 1075 CHKERRQ(DMSetUp(user.dmnet)); 1076 /* Create a composite DM packer and add the two DMs */ 1077 CHKERRQ(DMCompositeCreate(PETSC_COMM_WORLD,&user.dmpgrid)); 1078 CHKERRQ(DMSetOptionsPrefix(user.dmpgrid,"pgrid_")); 1079 CHKERRQ(DMCompositeAddDM(user.dmpgrid,user.dmgen)); 1080 CHKERRQ(DMCompositeAddDM(user.dmpgrid,user.dmnet)); 1081 1082 CHKERRQ(DMCreateGlobalVector(user.dmpgrid,&X)); 1083 1084 CHKERRQ(MatCreate(PETSC_COMM_WORLD,&J)); 1085 CHKERRQ(MatSetSizes(J,PETSC_DECIDE,PETSC_DECIDE,user.neqs_pgrid,user.neqs_pgrid)); 1086 CHKERRQ(MatSetFromOptions(J)); 1087 CHKERRQ(PreallocateJacobian(J,&user)); 1088 1089 /* Create matrix to save solutions at each time step */ 1090 user.stepnum = 0; 1091 1092 CHKERRQ(MatCreateSeqDense(PETSC_COMM_SELF,user.neqs_pgrid+1,1002,NULL,&user.Sol)); 1093 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1094 Create timestepping solver context 1095 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 1096 CHKERRQ(TSCreate(PETSC_COMM_WORLD,&ts)); 1097 CHKERRQ(TSSetProblemType(ts,TS_NONLINEAR)); 1098 if (user.semiexplicit) { 1099 CHKERRQ(TSSetType(ts,TSRK)); 1100 CHKERRQ(TSSetRHSFunction(ts,NULL,RHSFunction,&user)); 1101 CHKERRQ(TSSetRHSJacobian(ts,J,J,RHSJacobian,&user)); 1102 } else { 1103 CHKERRQ(TSSetType(ts,TSCN)); 1104 CHKERRQ(TSSetEquationType(ts,TS_EQ_DAE_IMPLICIT_INDEX1)); 1105 CHKERRQ(TSSetIFunction(ts,NULL,(TSIFunction) IFunction,&user)); 1106 CHKERRQ(TSSetIJacobian(ts,J,J,(TSIJacobian)IJacobian,&user)); 1107 } 1108 CHKERRQ(TSSetApplicationContext(ts,&user)); 1109 1110 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1111 Set initial conditions 1112 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 1113 CHKERRQ(SetInitialGuess(X,&user)); 1114 /* Just to set up the Jacobian structure */ 1115 1116 CHKERRQ(VecDuplicate(X,&Xdot)); 1117 CHKERRQ(IJacobian(ts,0.0,X,Xdot,0.0,J,J,&user)); 1118 CHKERRQ(VecDestroy(&Xdot)); 1119 1120 /* Save initial solution */ 1121 1122 idx=user.stepnum*(user.neqs_pgrid+1); 1123 CHKERRQ(MatDenseGetArray(user.Sol,&mat)); 1124 CHKERRQ(VecGetArray(X,&x)); 1125 1126 mat[idx] = 0.0; 1127 1128 CHKERRQ(PetscArraycpy(mat+idx+1,x,user.neqs_pgrid)); 1129 CHKERRQ(MatDenseRestoreArray(user.Sol,&mat)); 1130 CHKERRQ(VecRestoreArray(X,&x)); 1131 user.stepnum++; 1132 1133 CHKERRQ(TSSetMaxTime(ts,user.tmax)); 1134 CHKERRQ(TSSetExactFinalTime(ts,TS_EXACTFINALTIME_MATCHSTEP)); 1135 CHKERRQ(TSSetTimeStep(ts,0.01)); 1136 CHKERRQ(TSSetFromOptions(ts)); 1137 CHKERRQ(TSSetPostStep(ts,SaveSolution)); 1138 CHKERRQ(TSSetSolution(ts,X)); 1139 1140 CHKERRQ(PetscMalloc1((2*ngen+2),&direction)); 1141 CHKERRQ(PetscMalloc1((2*ngen+2),&terminate)); 1142 direction[0] = direction[1] = 1; 1143 terminate[0] = terminate[1] = PETSC_FALSE; 1144 for (i=0; i < ngen;i++) { 1145 direction[2+2*i] = -1; direction[2+2*i+1] = 1; 1146 terminate[2+2*i] = terminate[2+2*i+1] = PETSC_FALSE; 1147 } 1148 1149 CHKERRQ(TSSetEventHandler(ts,2*ngen+2,direction,terminate,EventFunction,PostEventFunction,(void*)&user)); 1150 1151 if (user.semiexplicit) { 1152 /* Use a semi-explicit approach with the time-stepping done by an explicit method and the 1153 algrebraic part solved via PostStage and PostEvaluate callbacks 1154 */ 1155 CHKERRQ(TSSetType(ts,TSRK)); 1156 CHKERRQ(TSSetPostStage(ts,PostStage)); 1157 CHKERRQ(TSSetPostEvaluate(ts,PostEvaluate)); 1158 } 1159 1160 if (user.setisdiff) { 1161 /* Create vector of absolute tolerances and set the algebraic part to infinity */ 1162 CHKERRQ(VecDuplicate(X,&vatol)); 1163 CHKERRQ(VecSet(vatol,100000.0)); 1164 CHKERRQ(VecGetArray(vatol,&vatoli)); 1165 CHKERRQ(ISGetIndices(user.is_diff,&idx3)); 1166 for (k=0; k < 7*ngen; k++) vatoli[idx3[k]] = 1e-2; 1167 CHKERRQ(VecRestoreArray(vatol,&vatoli)); 1168 } 1169 1170 /* Create the nonlinear solver for solving the algebraic system */ 1171 /* Note that although the algebraic system needs to be solved only for 1172 Idq and V, we reuse the entire system including xgen. The xgen 1173 variables are held constant by setting their residuals to 0 and 1174 putting a 1 on the Jacobian diagonal for xgen rows 1175 */ 1176 1177 CHKERRQ(VecDuplicate(X,&F_alg)); 1178 CHKERRQ(SNESCreate(PETSC_COMM_WORLD,&snes_alg)); 1179 CHKERRQ(SNESSetFunction(snes_alg,F_alg,AlgFunction,&user)); 1180 CHKERRQ(SNESSetJacobian(snes_alg,J,J,AlgJacobian,&user)); 1181 CHKERRQ(SNESSetFromOptions(snes_alg)); 1182 1183 user.snes_alg=snes_alg; 1184 1185 /* Solve */ 1186 CHKERRQ(TSSolve(ts,X)); 1187 1188 CHKERRQ(MatAssemblyBegin(user.Sol,MAT_FINAL_ASSEMBLY)); 1189 CHKERRQ(MatAssemblyEnd(user.Sol,MAT_FINAL_ASSEMBLY)); 1190 1191 CHKERRQ(MatCreateSeqDense(PETSC_COMM_SELF,user.neqs_pgrid+1,user.stepnum,NULL,&A)); 1192 CHKERRQ(MatDenseGetArrayRead(user.Sol,&rmat)); 1193 CHKERRQ(MatDenseGetArray(A,&amat)); 1194 CHKERRQ(PetscArraycpy(amat,rmat,user.stepnum*(user.neqs_pgrid+1))); 1195 CHKERRQ(MatDenseRestoreArray(A,&amat)); 1196 CHKERRQ(MatDenseRestoreArrayRead(user.Sol,&rmat)); 1197 CHKERRQ(PetscViewerBinaryOpen(PETSC_COMM_SELF,"out.bin",FILE_MODE_WRITE,&viewer)); 1198 CHKERRQ(MatView(A,viewer)); 1199 CHKERRQ(PetscViewerDestroy(&viewer)); 1200 CHKERRQ(MatDestroy(&A)); 1201 1202 CHKERRQ(PetscFree(direction)); 1203 CHKERRQ(PetscFree(terminate)); 1204 CHKERRQ(SNESDestroy(&snes_alg)); 1205 CHKERRQ(VecDestroy(&F_alg)); 1206 CHKERRQ(MatDestroy(&J)); 1207 CHKERRQ(MatDestroy(&user.Ybus)); 1208 CHKERRQ(MatDestroy(&user.Sol)); 1209 CHKERRQ(VecDestroy(&X)); 1210 CHKERRQ(VecDestroy(&user.V0)); 1211 CHKERRQ(DMDestroy(&user.dmgen)); 1212 CHKERRQ(DMDestroy(&user.dmnet)); 1213 CHKERRQ(DMDestroy(&user.dmpgrid)); 1214 CHKERRQ(ISDestroy(&user.is_diff)); 1215 CHKERRQ(ISDestroy(&user.is_alg)); 1216 CHKERRQ(TSDestroy(&ts)); 1217 if (user.setisdiff) { 1218 CHKERRQ(VecDestroy(&vatol)); 1219 } 1220 ierr = PetscFinalize(); 1221 return ierr; 1222 } 1223 1224 /*TEST 1225 1226 build: 1227 requires: double !complex !defined(PETSC_USE_64BIT_INDICES) 1228 1229 test: 1230 suffix: implicit 1231 args: -ts_monitor -snes_monitor_short 1232 localrunfiles: petscoptions X.bin Ybus.bin 1233 1234 test: 1235 suffix: semiexplicit 1236 args: -ts_monitor -snes_monitor_short -dae_semiexplicit -ts_rk_type 2a 1237 localrunfiles: petscoptions X.bin Ybus.bin 1238 1239 test: 1240 suffix: steprestart 1241 # needs ARKIMEX methods with all implicit stages since the mass matrix is not the identity 1242 args: -ts_monitor -snes_monitor_short -ts_type arkimex -ts_arkimex_type prssp2 1243 localrunfiles: petscoptions X.bin Ybus.bin 1244 1245 TEST*/ 1246