Actual source code: power2.c

  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";

  8: #include "power.h"
  9: #include <petscdmnetwork.h>

 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;

 19:   PetscFunctionBegin;
 20:   PetscCall(VecGetArrayRead(localX, &xarr));
 21:   PetscCall(VecGetArray(localF, &farr));

 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;

 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;

 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:         }

 51:         if (!ghostvtex) {
 52:           Vm = xarr[offset + 1];

 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:         }

 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;

 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];

 79:           PetscCall(DMNetworkGetConnectedVertices(networkdm, e, &cone));
 80:           vfrom = cone[0];
 81:           vto   = cone[1];

 83:           PetscCall(DMNetworkGetLocalVecOffset(networkdm, vfrom, ALL_COMPONENTS, &offsetfrom));
 84:           PetscCall(DMNetworkGetLocalVecOffset(networkdm, vto, ALL_COMPONENTS, &offsetto));

 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;

 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: }

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;

130:   PetscFunctionBegin;
131:   PetscCall(SNESGetDM(snes, &networkdm));
132:   PetscCall(DMGetLocalVector(networkdm, &localX));
133:   PetscCall(DMGetLocalVector(networkdm, &localF));
134:   PetscCall(VecSet(F, 0.0));

136:   PetscCall(DMGlobalToLocalBegin(networkdm, X, INSERT_VALUES, localX));
137:   PetscCall(DMGlobalToLocalEnd(networkdm, X, INSERT_VALUES, localX));

139:   PetscCall(DMGlobalToLocalBegin(networkdm, F, INSERT_VALUES, localF));
140:   PetscCall(DMGlobalToLocalEnd(networkdm, F, INSERT_VALUES, localF));

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));

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));

150:   PetscCall(DMRestoreLocalVector(networkdm, &localX));

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: }

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];

167:   PetscFunctionBegin;
168:   PetscCall(VecGetArrayRead(localX, &xarr));

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;

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;

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:           }

208:           Vm = xarr[offset + 1];

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:         }

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;

232:           e = connedges[i];
233:           PetscCall(DMNetworkGetComponent(networkdm, e, 0, &key, (void **)&branch, NULL));
234:           if (!branch->status) continue;

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];

245:           PetscCall(DMNetworkGetConnectedVertices(networkdm, e, &cone));
246:           vfrom = cone[0];
247:           vto   = cone[1];

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));

254:           if (goffsetto < 0) goffsetto = -goffsetto - 1;

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;

263:           PetscCall(DMNetworkGetComponent(networkdm, vfrom, 0, &keyf, (void **)&busf, NULL));
264:           PetscCall(DMNetworkGetComponent(networkdm, vto, 0, &keyt, (void **)&bust, NULL));

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 */

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));

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 */

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));

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: }

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;

346:   PetscFunctionBegin;
347:   PetscCall(MatZeroEntries(J));

349:   PetscCall(SNESGetDM(snes, &networkdm));
350:   PetscCall(DMGetLocalVector(networkdm, &localX));

352:   PetscCall(DMGlobalToLocalBegin(networkdm, X, INSERT_VALUES, localX));
353:   PetscCall(DMGlobalToLocalEnd(networkdm, X, INSERT_VALUES, localX));

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));

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));

363:   PetscCall(DMRestoreLocalVector(networkdm, &localX));

365:   PetscCall(MatAssemblyBegin(J, MAT_FINAL_ASSEMBLY));
366:   PetscCall(MatAssemblyEnd(J, MAT_FINAL_ASSEMBLY));
367:   PetscFunctionReturn(PETSC_SUCCESS);
368: }

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;

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;

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: }

406: PetscErrorCode SetInitialValues(DM networkdm, Vec X, void *appctx)
407: {
408:   PetscInt        nv, ne;
409:   const PetscInt *vtx, *edges;
410:   Vec             localX;

412:   PetscFunctionBegin;
413:   PetscCall(DMGetLocalVector(networkdm, &localX));

415:   PetscCall(VecSet(X, 0.0));
416:   PetscCall(DMGlobalToLocalBegin(networkdm, X, INSERT_VALUES, localX));
417:   PetscCall(DMGlobalToLocalEnd(networkdm, X, INSERT_VALUES, localX));

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));

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));

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: }

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;

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;

457:     /* Create an empty network object */
458:     PetscCall(DMNetworkCreate(PETSC_COMM_WORLD, &networkdm));

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]));

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 */

474:       /*    READ DATA FOR THE FIRST SUBNETWORK */
475:       PetscCall(PetscNew(&pfdata1));
476:       PetscCall(PFReadMatPowerData(pfdata1, pfdata_file));
477:       User.Sbase = pfdata1->sbase;

479:       numEdges1 = pfdata1->nbranch;
480:       PetscCall(PetscMalloc1(2 * numEdges1, &edgelist1));
481:       PetscCall(GetListofEdges_Power(pfdata1, edgelist1));

483:       /*    READ DATA FOR THE SECOND SUBNETWORK */
484:       PetscCall(PetscNew(&pfdata2));
485:       PetscCall(PFReadMatPowerData(pfdata2, pfdata_file));
486:       User.Sbase = pfdata2->sbase;

488:       numEdges2 = pfdata2->nbranch;
489:       PetscCall(PetscMalloc1(2 * numEdges2, &edgelist2));
490:       PetscCall(GetListofEdges_Power(pfdata2, edgelist2));
491:     }

493:     PetscCall(PetscLogStagePop());
494:     PetscCallMPI(MPI_Barrier(PETSC_COMM_WORLD));
495:     PetscCall(PetscLogStageRegister("Create network", &stage2));
496:     PetscCall(PetscLogStagePush(stage2));

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));

503:     /* Set up the network layout */
504:     PetscCall(DMNetworkLayoutSetUp(networkdm));

506:     /* Add network components only process 0 has any data to add*/
507:     if (!crank) {
508:       genj  = 0;
509:       loadj = 0;

511:       /* ADD VARIABLES AND COMPONENTS FOR THE FIRST SUBNETWORK */
512:       PetscCall(DMNetworkGetSubnetwork(networkdm, 0, &nv, &ne, &vtx, &edges));

514:       for (i = 0; i < ne; i++) PetscCall(DMNetworkAddComponent(networkdm, edges[i], componentkey[0], &pfdata1->branch[i], 0));

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:       }

526:       genj  = 0;
527:       loadj = 0;

529:       /* ADD VARIABLES AND COMPONENTS FOR THE SECOND SUBNETWORK */
530:       PetscCall(DMNetworkGetSubnetwork(networkdm, 1, &nv, &ne, &vtx, &edges));

532:       for (i = 0; i < ne; i++) PetscCall(DMNetworkAddComponent(networkdm, edges[i], componentkey[0], &pfdata2->branch[i], 0));

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:     }

545:     /* Set up DM for use */
546:     PetscCall(DMSetUp(networkdm));

548:     if (!crank) {
549:       PetscCall(PetscFree(edgelist1));
550:       PetscCall(PetscFree(edgelist2));
551:     }

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));

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:     }

567:     /* Distribute networkdm to multiple processes */
568:     PetscCall(DMNetworkDistribute(&networkdm, 0));

570:     PetscCall(PetscLogStagePop());

572:     /* Broadcast Sbase to all processors */
573:     PetscCallMPI(MPI_Bcast(&User.Sbase, 1, MPIU_SCALAR, 0, PETSC_COMM_WORLD));

575:     PetscCall(DMCreateGlobalVector(networkdm, &X));
576:     PetscCall(VecDuplicate(X, &F));

578:     PetscCall(DMCreateMatrix(networkdm, &J));
579:     PetscCall(MatSetOption(J, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_FALSE));

581:     PetscCall(SetInitialValues(networkdm, X, &User));

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));

590:     PetscCall(SNESSolve(snes, NULL, X));
591:     /* PetscCall(VecView(X,PETSC_VIEWER_STDOUT_WORLD)); */

593:     PetscCall(VecDestroy(&X));
594:     PetscCall(VecDestroy(&F));
595:     PetscCall(MatDestroy(&J));

597:     PetscCall(SNESDestroy(&snes));
598:     PetscCall(DMDestroy(&networkdm));
599:   }
600:   PetscCall(PetscFinalize());
601:   return 0;
602: }

604: /*TEST

606:    build:
607:      depends: PFReadData.c pffunctions.c
608:      requires: !complex double defined(PETSC_HAVE_ATTRIBUTEALIGNED)

610:    test:
611:      args: -snes_rtol 1.e-3
612:      localrunfiles: poweroptions case9.m
613:      output_file: output/power_1.out

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

622: TEST*/