xref: /petsc/src/snes/tutorials/network/power/power2.c (revision 66af8762ec03dbef0e079729eb2a1734a35ed7ff)
1 static char help[] = "This example demonstrates the use of DMNetwork interface with subnetworks for solving a nonlinear electric power grid problem.\n\
2                       The available solver options are in the poweroptions file and the data files are in the datafiles directory.\n\
3                       The data file format used is from the MatPower package (http://www.pserc.cornell.edu//matpower/).\n\
4                       This example shows the use of subnetwork feature in DMNetwork. It creates duplicates of the same network which are treated as subnetworks.\n\
5                       Run this program: mpiexec -n <n> ./pf2\n\
6                       mpiexec -n <n> ./pf2 \n";
7 
8 #include "power.h"
9 #include <petscdmnetwork.h>
10 
11 PetscErrorCode FormFunction_Subnet(DM networkdm, Vec localX, Vec localF, PetscInt nv, PetscInt ne, const PetscInt *vtx, const PetscInt *edges, void *appctx)
12 {
13   UserCtx_Power     *User = (UserCtx_Power *)appctx;
14   PetscInt           e, v, vfrom, vto;
15   const PetscScalar *xarr;
16   PetscScalar       *farr;
17   PetscInt           offsetfrom, offsetto, offset;
18 
19   PetscFunctionBegin;
20   PetscCall(VecGetArrayRead(localX, &xarr));
21   PetscCall(VecGetArray(localF, &farr));
22 
23   for (v = 0; v < nv; v++) {
24     PetscInt     i, j, key;
25     PetscScalar  Vm;
26     PetscScalar  Sbase = User->Sbase;
27     VERTEX_Power bus   = NULL;
28     GEN          gen;
29     LOAD         load;
30     PetscBool    ghostvtex;
31     PetscInt     numComps;
32     void        *component;
33 
34     PetscCall(DMNetworkIsGhostVertex(networkdm, vtx[v], &ghostvtex));
35     PetscCall(DMNetworkGetNumComponents(networkdm, vtx[v], &numComps));
36     PetscCall(DMNetworkGetLocalVecOffset(networkdm, vtx[v], ALL_COMPONENTS, &offset));
37     for (j = 0; j < numComps; j++) {
38       PetscCall(DMNetworkGetComponent(networkdm, vtx[v], j, &key, &component, NULL));
39       if (key == 1) {
40         PetscInt        nconnedges;
41         const PetscInt *connedges;
42 
43         bus = (VERTEX_Power)(component);
44         /* Handle reference bus constrained dofs */
45         if (bus->ide == REF_BUS || bus->ide == ISOLATED_BUS) {
46           farr[offset]     = xarr[offset] - bus->va * PETSC_PI / 180.0;
47           farr[offset + 1] = xarr[offset + 1] - bus->vm;
48           break;
49         }
50 
51         if (!ghostvtex) {
52           Vm = xarr[offset + 1];
53 
54           /* Shunt injections */
55           farr[offset] += Vm * Vm * bus->gl / Sbase;
56           if (bus->ide != PV_BUS) farr[offset + 1] += -Vm * Vm * bus->bl / Sbase;
57         }
58 
59         PetscCall(DMNetworkGetSupportingEdges(networkdm, vtx[v], &nconnedges, &connedges));
60         for (i = 0; i < nconnedges; i++) {
61           EDGE_Power      branch;
62           PetscInt        keye;
63           PetscScalar     Gff, Bff, Gft, Bft, Gtf, Btf, Gtt, Btt;
64           const PetscInt *cone;
65           PetscScalar     Vmf, Vmt, thetaf, thetat, thetaft, thetatf;
66 
67           e = connedges[i];
68           PetscCall(DMNetworkGetComponent(networkdm, e, 0, &keye, (void **)&branch, NULL));
69           if (!branch->status) continue;
70           Gff = branch->yff[0];
71           Bff = branch->yff[1];
72           Gft = branch->yft[0];
73           Bft = branch->yft[1];
74           Gtf = branch->ytf[0];
75           Btf = branch->ytf[1];
76           Gtt = branch->ytt[0];
77           Btt = branch->ytt[1];
78 
79           PetscCall(DMNetworkGetConnectedVertices(networkdm, e, &cone));
80           vfrom = cone[0];
81           vto   = cone[1];
82 
83           PetscCall(DMNetworkGetLocalVecOffset(networkdm, vfrom, ALL_COMPONENTS, &offsetfrom));
84           PetscCall(DMNetworkGetLocalVecOffset(networkdm, vto, ALL_COMPONENTS, &offsetto));
85 
86           thetaf  = xarr[offsetfrom];
87           Vmf     = xarr[offsetfrom + 1];
88           thetat  = xarr[offsetto];
89           Vmt     = xarr[offsetto + 1];
90           thetaft = thetaf - thetat;
91           thetatf = thetat - thetaf;
92 
93           if (vfrom == vtx[v]) {
94             farr[offsetfrom] += Gff * Vmf * Vmf + Vmf * Vmt * (Gft * PetscCosScalar(thetaft) + Bft * PetscSinScalar(thetaft));
95             farr[offsetfrom + 1] += -Bff * Vmf * Vmf + Vmf * Vmt * (-Bft * PetscCosScalar(thetaft) + Gft * PetscSinScalar(thetaft));
96           } else {
97             farr[offsetto] += Gtt * Vmt * Vmt + Vmt * Vmf * (Gtf * PetscCosScalar(thetatf) + Btf * PetscSinScalar(thetatf));
98             farr[offsetto + 1] += -Btt * Vmt * Vmt + Vmt * Vmf * (-Btf * PetscCosScalar(thetatf) + Gtf * PetscSinScalar(thetatf));
99           }
100         }
101       } else if (key == 2) {
102         if (!ghostvtex) {
103           gen = (GEN)(component);
104           if (!gen->status) continue;
105           farr[offset] += -gen->pg / Sbase;
106           farr[offset + 1] += -gen->qg / Sbase;
107         }
108       } else if (key == 3) {
109         if (!ghostvtex) {
110           load = (LOAD)(component);
111           farr[offset] += load->pl / Sbase;
112           farr[offset + 1] += load->ql / Sbase;
113         }
114       }
115     }
116     if (bus && bus->ide == PV_BUS) farr[offset + 1] = xarr[offset + 1] - bus->vm;
117   }
118   PetscCall(VecRestoreArrayRead(localX, &xarr));
119   PetscCall(VecRestoreArray(localF, &farr));
120   PetscFunctionReturn(PETSC_SUCCESS);
121 }
122 
123 PetscErrorCode FormFunction(SNES snes, Vec X, Vec F, void *appctx)
124 {
125   DM              networkdm;
126   Vec             localX, localF;
127   PetscInt        nv, ne;
128   const PetscInt *vtx, *edges;
129 
130   PetscFunctionBegin;
131   PetscCall(SNESGetDM(snes, &networkdm));
132   PetscCall(DMGetLocalVector(networkdm, &localX));
133   PetscCall(DMGetLocalVector(networkdm, &localF));
134   PetscCall(VecSet(F, 0.0));
135 
136   PetscCall(DMGlobalToLocalBegin(networkdm, X, INSERT_VALUES, localX));
137   PetscCall(DMGlobalToLocalEnd(networkdm, X, INSERT_VALUES, localX));
138 
139   PetscCall(DMGlobalToLocalBegin(networkdm, F, INSERT_VALUES, localF));
140   PetscCall(DMGlobalToLocalEnd(networkdm, F, INSERT_VALUES, localF));
141 
142   /* Form Function for first subnetwork */
143   PetscCall(DMNetworkGetSubnetwork(networkdm, 0, &nv, &ne, &vtx, &edges));
144   PetscCall(FormFunction_Subnet(networkdm, localX, localF, nv, ne, vtx, edges, appctx));
145 
146   /* Form Function for second subnetwork */
147   PetscCall(DMNetworkGetSubnetwork(networkdm, 1, &nv, &ne, &vtx, &edges));
148   PetscCall(FormFunction_Subnet(networkdm, localX, localF, nv, ne, vtx, edges, appctx));
149 
150   PetscCall(DMRestoreLocalVector(networkdm, &localX));
151 
152   PetscCall(DMLocalToGlobalBegin(networkdm, localF, ADD_VALUES, F));
153   PetscCall(DMLocalToGlobalEnd(networkdm, localF, ADD_VALUES, F));
154   PetscCall(DMRestoreLocalVector(networkdm, &localF));
155   PetscFunctionReturn(PETSC_SUCCESS);
156 }
157 
158 PetscErrorCode FormJacobian_Subnet(DM networkdm, Vec localX, Mat J, Mat Jpre, PetscInt nv, PetscInt ne, const PetscInt *vtx, const PetscInt *edges, void *appctx)
159 {
160   UserCtx_Power     *User = (UserCtx_Power *)appctx;
161   PetscInt           e, v, vfrom, vto;
162   const PetscScalar *xarr;
163   PetscInt           offsetfrom, offsetto, goffsetfrom, goffsetto;
164   PetscInt           row[2], col[8];
165   PetscScalar        values[8];
166 
167   PetscFunctionBegin;
168   PetscCall(VecGetArrayRead(localX, &xarr));
169 
170   for (v = 0; v < nv; v++) {
171     PetscInt     i, j, key;
172     PetscInt     offset, goffset;
173     PetscScalar  Vm;
174     PetscScalar  Sbase = User->Sbase;
175     VERTEX_Power bus;
176     PetscBool    ghostvtex;
177     PetscInt     numComps;
178     void        *component;
179 
180     PetscCall(DMNetworkIsGhostVertex(networkdm, vtx[v], &ghostvtex));
181     PetscCall(DMNetworkGetNumComponents(networkdm, vtx[v], &numComps));
182     for (j = 0; j < numComps; j++) {
183       PetscCall(DMNetworkGetLocalVecOffset(networkdm, vtx[v], ALL_COMPONENTS, &offset));
184       PetscCall(DMNetworkGetGlobalVecOffset(networkdm, vtx[v], ALL_COMPONENTS, &goffset));
185       PetscCall(DMNetworkGetComponent(networkdm, vtx[v], j, &key, &component, NULL));
186       if (key == 1) {
187         PetscInt        nconnedges;
188         const PetscInt *connedges;
189 
190         bus = (VERTEX_Power)(component);
191         if (!ghostvtex) {
192           /* Handle reference bus constrained dofs */
193           if (bus->ide == REF_BUS || bus->ide == ISOLATED_BUS) {
194             row[0]    = goffset;
195             row[1]    = goffset + 1;
196             col[0]    = goffset;
197             col[1]    = goffset + 1;
198             col[2]    = goffset;
199             col[3]    = goffset + 1;
200             values[0] = 1.0;
201             values[1] = 0.0;
202             values[2] = 0.0;
203             values[3] = 1.0;
204             PetscCall(MatSetValues(J, 2, row, 2, col, values, ADD_VALUES));
205             break;
206           }
207 
208           Vm = xarr[offset + 1];
209 
210           /* Shunt injections */
211           row[0]    = goffset;
212           row[1]    = goffset + 1;
213           col[0]    = goffset;
214           col[1]    = goffset + 1;
215           values[0] = values[1] = values[2] = values[3] = 0.0;
216           if (bus->ide != PV_BUS) {
217             values[1] = 2.0 * Vm * bus->gl / Sbase;
218             values[3] = -2.0 * Vm * bus->bl / Sbase;
219           }
220           PetscCall(MatSetValues(J, 2, row, 2, col, values, ADD_VALUES));
221         }
222 
223         PetscCall(DMNetworkGetSupportingEdges(networkdm, vtx[v], &nconnedges, &connedges));
224         for (i = 0; i < nconnedges; i++) {
225           EDGE_Power      branch;
226           VERTEX_Power    busf, bust;
227           PetscInt        keyf, keyt;
228           PetscScalar     Gff, Bff, Gft, Bft, Gtf, Btf, Gtt, Btt;
229           const PetscInt *cone;
230           PetscScalar     Vmf, Vmt, thetaf, thetat, thetaft, thetatf;
231 
232           e = connedges[i];
233           PetscCall(DMNetworkGetComponent(networkdm, e, 0, &key, (void **)&branch, NULL));
234           if (!branch->status) continue;
235 
236           Gff = branch->yff[0];
237           Bff = branch->yff[1];
238           Gft = branch->yft[0];
239           Bft = branch->yft[1];
240           Gtf = branch->ytf[0];
241           Btf = branch->ytf[1];
242           Gtt = branch->ytt[0];
243           Btt = branch->ytt[1];
244 
245           PetscCall(DMNetworkGetConnectedVertices(networkdm, e, &cone));
246           vfrom = cone[0];
247           vto   = cone[1];
248 
249           PetscCall(DMNetworkGetLocalVecOffset(networkdm, vfrom, ALL_COMPONENTS, &offsetfrom));
250           PetscCall(DMNetworkGetLocalVecOffset(networkdm, vto, ALL_COMPONENTS, &offsetto));
251           PetscCall(DMNetworkGetGlobalVecOffset(networkdm, vfrom, ALL_COMPONENTS, &goffsetfrom));
252           PetscCall(DMNetworkGetGlobalVecOffset(networkdm, vto, ALL_COMPONENTS, &goffsetto));
253 
254           if (goffsetto < 0) goffsetto = -goffsetto - 1;
255 
256           thetaf  = xarr[offsetfrom];
257           Vmf     = xarr[offsetfrom + 1];
258           thetat  = xarr[offsetto];
259           Vmt     = xarr[offsetto + 1];
260           thetaft = thetaf - thetat;
261           thetatf = thetat - thetaf;
262 
263           PetscCall(DMNetworkGetComponent(networkdm, vfrom, 0, &keyf, (void **)&busf, NULL));
264           PetscCall(DMNetworkGetComponent(networkdm, vto, 0, &keyt, (void **)&bust, NULL));
265 
266           if (vfrom == vtx[v]) {
267             if (busf->ide != REF_BUS) {
268               /*    farr[offsetfrom]   += Gff*Vmf*Vmf + Vmf*Vmt*(Gft*PetscCosScalar(thetaft) + Bft*PetscSinScalar(thetaft));  */
269               row[0]    = goffsetfrom;
270               col[0]    = goffsetfrom;
271               col[1]    = goffsetfrom + 1;
272               col[2]    = goffsetto;
273               col[3]    = goffsetto + 1;
274               values[0] = Vmf * Vmt * (Gft * -PetscSinScalar(thetaft) + Bft * PetscCosScalar(thetaft));            /* df_dthetaf */
275               values[1] = 2.0 * Gff * Vmf + Vmt * (Gft * PetscCosScalar(thetaft) + Bft * PetscSinScalar(thetaft)); /* df_dVmf */
276               values[2] = Vmf * Vmt * (Gft * PetscSinScalar(thetaft) + Bft * -PetscCosScalar(thetaft));            /* df_dthetat */
277               values[3] = Vmf * (Gft * PetscCosScalar(thetaft) + Bft * PetscSinScalar(thetaft));                   /* df_dVmt */
278 
279               PetscCall(MatSetValues(J, 1, row, 4, col, values, ADD_VALUES));
280             }
281             if (busf->ide != PV_BUS && busf->ide != REF_BUS) {
282               row[0] = goffsetfrom + 1;
283               col[0] = goffsetfrom;
284               col[1] = goffsetfrom + 1;
285               col[2] = goffsetto;
286               col[3] = goffsetto + 1;
287               /*    farr[offsetfrom+1] += -Bff*Vmf*Vmf + Vmf*Vmt*(-Bft*PetscCosScalar(thetaft) + Gft*PetscSinScalar(thetaft)); */
288               values[0] = Vmf * Vmt * (Bft * PetscSinScalar(thetaft) + Gft * PetscCosScalar(thetaft));
289               values[1] = -2.0 * Bff * Vmf + Vmt * (-Bft * PetscCosScalar(thetaft) + Gft * PetscSinScalar(thetaft));
290               values[2] = Vmf * Vmt * (-Bft * PetscSinScalar(thetaft) + Gft * -PetscCosScalar(thetaft));
291               values[3] = Vmf * (-Bft * PetscCosScalar(thetaft) + Gft * PetscSinScalar(thetaft));
292 
293               PetscCall(MatSetValues(J, 1, row, 4, col, values, ADD_VALUES));
294             }
295           } else {
296             if (bust->ide != REF_BUS) {
297               row[0] = goffsetto;
298               col[0] = goffsetto;
299               col[1] = goffsetto + 1;
300               col[2] = goffsetfrom;
301               col[3] = goffsetfrom + 1;
302               /*    farr[offsetto]   += Gtt*Vmt*Vmt + Vmt*Vmf*(Gtf*PetscCosScalar(thetatf) + Btf*PetscSinScalar(thetatf)); */
303               values[0] = Vmt * Vmf * (Gtf * -PetscSinScalar(thetatf) + Btf * PetscCosScalar(thetaft));            /* df_dthetat */
304               values[1] = 2.0 * Gtt * Vmt + Vmf * (Gtf * PetscCosScalar(thetatf) + Btf * PetscSinScalar(thetatf)); /* df_dVmt */
305               values[2] = Vmt * Vmf * (Gtf * PetscSinScalar(thetatf) + Btf * -PetscCosScalar(thetatf));            /* df_dthetaf */
306               values[3] = Vmt * (Gtf * PetscCosScalar(thetatf) + Btf * PetscSinScalar(thetatf));                   /* df_dVmf */
307 
308               PetscCall(MatSetValues(J, 1, row, 4, col, values, ADD_VALUES));
309             }
310             if (bust->ide != PV_BUS && bust->ide != REF_BUS) {
311               row[0] = goffsetto + 1;
312               col[0] = goffsetto;
313               col[1] = goffsetto + 1;
314               col[2] = goffsetfrom;
315               col[3] = goffsetfrom + 1;
316               /*    farr[offsetto+1] += -Btt*Vmt*Vmt + Vmt*Vmf*(-Btf*PetscCosScalar(thetatf) + Gtf*PetscSinScalar(thetatf)); */
317               values[0] = Vmt * Vmf * (Btf * PetscSinScalar(thetatf) + Gtf * PetscCosScalar(thetatf));
318               values[1] = -2.0 * Btt * Vmt + Vmf * (-Btf * PetscCosScalar(thetatf) + Gtf * PetscSinScalar(thetatf));
319               values[2] = Vmt * Vmf * (-Btf * PetscSinScalar(thetatf) + Gtf * -PetscCosScalar(thetatf));
320               values[3] = Vmt * (-Btf * PetscCosScalar(thetatf) + Gtf * PetscSinScalar(thetatf));
321 
322               PetscCall(MatSetValues(J, 1, row, 4, col, values, ADD_VALUES));
323             }
324           }
325         }
326         if (!ghostvtex && bus->ide == PV_BUS) {
327           row[0]    = goffset + 1;
328           col[0]    = goffset + 1;
329           values[0] = 1.0;
330           PetscCall(MatSetValues(J, 1, row, 1, col, values, ADD_VALUES));
331         }
332       }
333     }
334   }
335   PetscCall(VecRestoreArrayRead(localX, &xarr));
336   PetscFunctionReturn(PETSC_SUCCESS);
337 }
338 
339 PetscErrorCode FormJacobian(SNES snes, Vec X, Mat J, Mat Jpre, void *appctx)
340 {
341   DM              networkdm;
342   Vec             localX;
343   PetscInt        ne, nv;
344   const PetscInt *vtx, *edges;
345 
346   PetscFunctionBegin;
347   PetscCall(MatZeroEntries(J));
348 
349   PetscCall(SNESGetDM(snes, &networkdm));
350   PetscCall(DMGetLocalVector(networkdm, &localX));
351 
352   PetscCall(DMGlobalToLocalBegin(networkdm, X, INSERT_VALUES, localX));
353   PetscCall(DMGlobalToLocalEnd(networkdm, X, INSERT_VALUES, localX));
354 
355   /* Form Jacobian for first subnetwork */
356   PetscCall(DMNetworkGetSubnetwork(networkdm, 0, &nv, &ne, &vtx, &edges));
357   PetscCall(FormJacobian_Subnet(networkdm, localX, J, Jpre, nv, ne, vtx, edges, appctx));
358 
359   /* Form Jacobian for second subnetwork */
360   PetscCall(DMNetworkGetSubnetwork(networkdm, 1, &nv, &ne, &vtx, &edges));
361   PetscCall(FormJacobian_Subnet(networkdm, localX, J, Jpre, nv, ne, vtx, edges, appctx));
362 
363   PetscCall(DMRestoreLocalVector(networkdm, &localX));
364 
365   PetscCall(MatAssemblyBegin(J, MAT_FINAL_ASSEMBLY));
366   PetscCall(MatAssemblyEnd(J, MAT_FINAL_ASSEMBLY));
367   PetscFunctionReturn(PETSC_SUCCESS);
368 }
369 
370 PetscErrorCode SetInitialValues_Subnet(DM networkdm, Vec localX, PetscInt nv, PetscInt ne, const PetscInt *vtx, const PetscInt *edges, void *appctx)
371 {
372   VERTEX_Power bus;
373   PetscInt     i;
374   GEN          gen;
375   PetscBool    ghostvtex;
376   PetscScalar *xarr;
377   PetscInt     key, numComps, j, offset;
378   void        *component;
379 
380   PetscFunctionBegin;
381   PetscCall(VecGetArray(localX, &xarr));
382   for (i = 0; i < nv; i++) {
383     PetscCall(DMNetworkIsGhostVertex(networkdm, vtx[i], &ghostvtex));
384     if (ghostvtex) continue;
385 
386     PetscCall(DMNetworkGetLocalVecOffset(networkdm, vtx[i], ALL_COMPONENTS, &offset));
387     PetscCall(DMNetworkGetNumComponents(networkdm, vtx[i], &numComps));
388     for (j = 0; j < numComps; j++) {
389       PetscCall(DMNetworkGetComponent(networkdm, vtx[i], j, &key, &component, NULL));
390       if (key == 1) {
391         bus              = (VERTEX_Power)(component);
392         xarr[offset]     = bus->va * PETSC_PI / 180.0;
393         xarr[offset + 1] = bus->vm;
394       } else if (key == 2) {
395         gen = (GEN)(component);
396         if (!gen->status) continue;
397         xarr[offset + 1] = gen->vs;
398         break;
399       }
400     }
401   }
402   PetscCall(VecRestoreArray(localX, &xarr));
403   PetscFunctionReturn(PETSC_SUCCESS);
404 }
405 
406 PetscErrorCode SetInitialValues(DM networkdm, Vec X, void *appctx)
407 {
408   PetscInt        nv, ne;
409   const PetscInt *vtx, *edges;
410   Vec             localX;
411 
412   PetscFunctionBegin;
413   PetscCall(DMGetLocalVector(networkdm, &localX));
414 
415   PetscCall(VecSet(X, 0.0));
416   PetscCall(DMGlobalToLocalBegin(networkdm, X, INSERT_VALUES, localX));
417   PetscCall(DMGlobalToLocalEnd(networkdm, X, INSERT_VALUES, localX));
418 
419   /* Set initial guess for first subnetwork */
420   PetscCall(DMNetworkGetSubnetwork(networkdm, 0, &nv, &ne, &vtx, &edges));
421   PetscCall(SetInitialValues_Subnet(networkdm, localX, nv, ne, vtx, edges, appctx));
422 
423   /* Set initial guess for second subnetwork */
424   PetscCall(DMNetworkGetSubnetwork(networkdm, 1, &nv, &ne, &vtx, &edges));
425   PetscCall(SetInitialValues_Subnet(networkdm, localX, nv, ne, vtx, edges, appctx));
426 
427   PetscCall(DMLocalToGlobalBegin(networkdm, localX, ADD_VALUES, X));
428   PetscCall(DMLocalToGlobalEnd(networkdm, localX, ADD_VALUES, X));
429   PetscCall(DMRestoreLocalVector(networkdm, &localX));
430   PetscFunctionReturn(PETSC_SUCCESS);
431 }
432 
433 int main(int argc, char **argv)
434 {
435   char            pfdata_file[PETSC_MAX_PATH_LEN] = "case9.m";
436   PFDATA         *pfdata1, *pfdata2;
437   PetscInt        numEdges1 = 0, numEdges2 = 0;
438   PetscInt       *edgelist1 = NULL, *edgelist2 = NULL, componentkey[4];
439   DM              networkdm;
440   UserCtx_Power   User;
441   PetscLogStage   stage1, stage2;
442   PetscMPIInt     rank;
443   PetscInt        nsubnet = 2, nv, ne, i, j, genj, loadj;
444   const PetscInt *vtx, *edges;
445   Vec             X, F;
446   Mat             J;
447   SNES            snes;
448 
449   PetscFunctionBeginUser;
450   PetscCall(PetscInitialize(&argc, &argv, "poweroptions", help));
451   PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD, &rank));
452   {
453     /* introduce the const crank so the clang static analyzer realizes that if it enters any of the if (crank) then it must have entered the first */
454     /* this is an experiment to see how the analyzer reacts */
455     const PetscMPIInt crank = rank;
456 
457     /* Create an empty network object */
458     PetscCall(DMNetworkCreate(PETSC_COMM_WORLD, &networkdm));
459 
460     /* Register the components in the network */
461     PetscCall(DMNetworkRegisterComponent(networkdm, "branchstruct", sizeof(struct _p_EDGE_Power), &componentkey[0]));
462     PetscCall(DMNetworkRegisterComponent(networkdm, "busstruct", sizeof(struct _p_VERTEX_Power), &componentkey[1]));
463     PetscCall(DMNetworkRegisterComponent(networkdm, "genstruct", sizeof(struct _p_GEN), &componentkey[2]));
464     PetscCall(DMNetworkRegisterComponent(networkdm, "loadstruct", sizeof(struct _p_LOAD), &componentkey[3]));
465 
466     PetscCall(PetscLogStageRegister("Read Data", &stage1));
467     PetscCall(PetscLogStagePush(stage1));
468     /* READ THE DATA */
469     if (!crank) {
470       /* Only rank 0 reads the data */
471       PetscCall(PetscOptionsGetString(NULL, NULL, "-pfdata", pfdata_file, sizeof(pfdata_file), NULL));
472       /* HERE WE CREATE COPIES OF THE SAME NETWORK THAT WILL BE TREATED AS SUBNETWORKS */
473 
474       /*    READ DATA FOR THE FIRST SUBNETWORK */
475       PetscCall(PetscNew(&pfdata1));
476       PetscCall(PFReadMatPowerData(pfdata1, pfdata_file));
477       User.Sbase = pfdata1->sbase;
478 
479       numEdges1 = pfdata1->nbranch;
480       PetscCall(PetscMalloc1(2 * numEdges1, &edgelist1));
481       PetscCall(GetListofEdges_Power(pfdata1, edgelist1));
482 
483       /*    READ DATA FOR THE SECOND SUBNETWORK */
484       PetscCall(PetscNew(&pfdata2));
485       PetscCall(PFReadMatPowerData(pfdata2, pfdata_file));
486       User.Sbase = pfdata2->sbase;
487 
488       numEdges2 = pfdata2->nbranch;
489       PetscCall(PetscMalloc1(2 * numEdges2, &edgelist2));
490       PetscCall(GetListofEdges_Power(pfdata2, edgelist2));
491     }
492 
493     PetscCall(PetscLogStagePop());
494     PetscCallMPI(MPI_Barrier(PETSC_COMM_WORLD));
495     PetscCall(PetscLogStageRegister("Create network", &stage2));
496     PetscCall(PetscLogStagePush(stage2));
497 
498     /* Set number of nodes/edges and edge connectivity */
499     PetscCall(DMNetworkSetNumSubNetworks(networkdm, PETSC_DECIDE, nsubnet));
500     PetscCall(DMNetworkAddSubnetwork(networkdm, "", numEdges1, edgelist1, NULL));
501     PetscCall(DMNetworkAddSubnetwork(networkdm, "", numEdges2, edgelist2, NULL));
502 
503     /* Set up the network layout */
504     PetscCall(DMNetworkLayoutSetUp(networkdm));
505 
506     /* Add network components only process 0 has any data to add*/
507     if (!crank) {
508       genj  = 0;
509       loadj = 0;
510 
511       /* ADD VARIABLES AND COMPONENTS FOR THE FIRST SUBNETWORK */
512       PetscCall(DMNetworkGetSubnetwork(networkdm, 0, &nv, &ne, &vtx, &edges));
513 
514       for (i = 0; i < ne; i++) PetscCall(DMNetworkAddComponent(networkdm, edges[i], componentkey[0], &pfdata1->branch[i], 0));
515 
516       for (i = 0; i < nv; i++) {
517         PetscCall(DMNetworkAddComponent(networkdm, vtx[i], componentkey[1], &pfdata1->bus[i], 2));
518         if (pfdata1->bus[i].ngen) {
519           for (j = 0; j < pfdata1->bus[i].ngen; j++) PetscCall(DMNetworkAddComponent(networkdm, vtx[i], componentkey[2], &pfdata1->gen[genj++], 0));
520         }
521         if (pfdata1->bus[i].nload) {
522           for (j = 0; j < pfdata1->bus[i].nload; j++) PetscCall(DMNetworkAddComponent(networkdm, vtx[i], componentkey[3], &pfdata1->load[loadj++], 0));
523         }
524       }
525 
526       genj  = 0;
527       loadj = 0;
528 
529       /* ADD VARIABLES AND COMPONENTS FOR THE SECOND SUBNETWORK */
530       PetscCall(DMNetworkGetSubnetwork(networkdm, 1, &nv, &ne, &vtx, &edges));
531 
532       for (i = 0; i < ne; i++) PetscCall(DMNetworkAddComponent(networkdm, edges[i], componentkey[0], &pfdata2->branch[i], 0));
533 
534       for (i = 0; i < nv; i++) {
535         PetscCall(DMNetworkAddComponent(networkdm, vtx[i], componentkey[1], &pfdata2->bus[i], 2));
536         if (pfdata2->bus[i].ngen) {
537           for (j = 0; j < pfdata2->bus[i].ngen; j++) PetscCall(DMNetworkAddComponent(networkdm, vtx[i], componentkey[2], &pfdata2->gen[genj++], 0));
538         }
539         if (pfdata2->bus[i].nload) {
540           for (j = 0; j < pfdata2->bus[i].nload; j++) PetscCall(DMNetworkAddComponent(networkdm, vtx[i], componentkey[3], &pfdata2->load[loadj++], 0));
541         }
542       }
543     }
544 
545     /* Set up DM for use */
546     PetscCall(DMSetUp(networkdm));
547 
548     if (!crank) {
549       PetscCall(PetscFree(edgelist1));
550       PetscCall(PetscFree(edgelist2));
551     }
552 
553     if (!crank) {
554       PetscCall(PetscFree(pfdata1->bus));
555       PetscCall(PetscFree(pfdata1->gen));
556       PetscCall(PetscFree(pfdata1->branch));
557       PetscCall(PetscFree(pfdata1->load));
558       PetscCall(PetscFree(pfdata1));
559 
560       PetscCall(PetscFree(pfdata2->bus));
561       PetscCall(PetscFree(pfdata2->gen));
562       PetscCall(PetscFree(pfdata2->branch));
563       PetscCall(PetscFree(pfdata2->load));
564       PetscCall(PetscFree(pfdata2));
565     }
566 
567     /* Distribute networkdm to multiple processes */
568     PetscCall(DMNetworkDistribute(&networkdm, 0));
569 
570     PetscCall(PetscLogStagePop());
571 
572     /* Broadcast Sbase to all processors */
573     PetscCallMPI(MPI_Bcast(&User.Sbase, 1, MPIU_SCALAR, 0, PETSC_COMM_WORLD));
574 
575     PetscCall(DMCreateGlobalVector(networkdm, &X));
576     PetscCall(VecDuplicate(X, &F));
577 
578     PetscCall(DMCreateMatrix(networkdm, &J));
579     PetscCall(MatSetOption(J, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_FALSE));
580 
581     PetscCall(SetInitialValues(networkdm, X, &User));
582 
583     /* HOOK UP SOLVER */
584     PetscCall(SNESCreate(PETSC_COMM_WORLD, &snes));
585     PetscCall(SNESSetDM(snes, networkdm));
586     PetscCall(SNESSetFunction(snes, F, FormFunction, &User));
587     PetscCall(SNESSetJacobian(snes, J, J, FormJacobian, &User));
588     PetscCall(SNESSetFromOptions(snes));
589 
590     PetscCall(SNESSolve(snes, NULL, X));
591     /* PetscCall(VecView(X,PETSC_VIEWER_STDOUT_WORLD)); */
592 
593     PetscCall(VecDestroy(&X));
594     PetscCall(VecDestroy(&F));
595     PetscCall(MatDestroy(&J));
596 
597     PetscCall(SNESDestroy(&snes));
598     PetscCall(DMDestroy(&networkdm));
599   }
600   PetscCall(PetscFinalize());
601   return 0;
602 }
603 
604 /*TEST
605 
606    build:
607      depends: PFReadData.c pffunctions.c
608      requires: !complex double defined(PETSC_HAVE_ATTRIBUTEALIGNED)
609 
610    test:
611      args: -snes_rtol 1.e-3
612      localrunfiles: poweroptions case9.m
613      output_file: output/power_1.out
614 
615    test:
616      suffix: 2
617      args: -snes_rtol 1.e-3 -petscpartitioner_type simple
618      nsize: 4
619      localrunfiles: poweroptions case9.m
620      output_file: output/power_1.out
621 
622 TEST*/
623