xref: /petsc/src/snes/tutorials/network/ex1.c (revision 9566063d113dddea24716c546802770db7481bc0)
1 static char help[] = "This example demonstrates the use of DMNetwork interface with subnetworks for solving a coupled nonlinear \n\
2                       electric power grid and water pipe problem.\n\
3                       The available solver options are in the ex1options file \n\
4                       and the data files are in the datafiles of subdirectories.\n\
5                       This example shows the use of subnetwork feature in DMNetwork. \n\
6                       Run this program: mpiexec -n <n> ./ex1 \n\\n";
7 
8 /* T
9    Concepts: DMNetwork
10    Concepts: PETSc SNES solver
11 */
12 
13 #include "power/power.h"
14 #include "water/water.h"
15 
16 typedef struct{
17   UserCtx_Power appctx_power;
18   AppCtx_Water  appctx_water;
19   PetscInt      subsnes_id; /* snes solver id */
20   PetscInt      it;         /* iteration number */
21   Vec           localXold;  /* store previous solution, used by FormFunction_Dummy() */
22 } UserCtx;
23 
24 PetscErrorCode UserMonitor(SNES snes,PetscInt its,PetscReal fnorm ,void *appctx)
25 {
26   UserCtx        *user = (UserCtx*)appctx;
27   Vec            X,localXold = user->localXold;
28   DM             networkdm;
29   PetscMPIInt    rank;
30   MPI_Comm       comm;
31 
32   PetscFunctionBegin;
33   PetscCall(PetscObjectGetComm((PetscObject)snes,&comm));
34   PetscCallMPI(MPI_Comm_rank(comm,&rank));
35 #if 0
36   if (rank == 0) {
37     PetscInt       subsnes_id = user->subsnes_id;
38     if (subsnes_id == 2) {
39       PetscCall(PetscPrintf(PETSC_COMM_SELF," it %D, subsnes_id %D, fnorm %g\n",user->it,user->subsnes_id,(double)fnorm));
40     } else {
41       PetscCall(PetscPrintf(PETSC_COMM_SELF,"       subsnes_id %D, fnorm %g\n",user->subsnes_id,(double)fnorm));
42     }
43   }
44 #endif
45   PetscCall(SNESGetSolution(snes,&X));
46   PetscCall(SNESGetDM(snes,&networkdm));
47   PetscCall(DMGlobalToLocalBegin(networkdm,X,INSERT_VALUES,localXold));
48   PetscCall(DMGlobalToLocalEnd(networkdm,X,INSERT_VALUES,localXold));
49   PetscFunctionReturn(0);
50 }
51 
52 PetscErrorCode FormJacobian_subPower(SNES snes,Vec X, Mat J,Mat Jpre,void *appctx)
53 {
54   DM             networkdm;
55   Vec            localX;
56   PetscInt       nv,ne,i,j,offset,nvar,row;
57   const PetscInt *vtx,*edges;
58   PetscBool      ghostvtex;
59   PetscScalar    one = 1.0;
60   PetscMPIInt    rank;
61   MPI_Comm       comm;
62 
63   PetscFunctionBegin;
64   PetscCall(SNESGetDM(snes,&networkdm));
65   PetscCall(DMGetLocalVector(networkdm,&localX));
66 
67   PetscCall(PetscObjectGetComm((PetscObject)networkdm,&comm));
68   PetscCallMPI(MPI_Comm_rank(comm,&rank));
69 
70   PetscCall(DMGlobalToLocalBegin(networkdm,X,INSERT_VALUES,localX));
71   PetscCall(DMGlobalToLocalEnd(networkdm,X,INSERT_VALUES,localX));
72 
73   PetscCall(MatZeroEntries(J));
74 
75   /* Power subnetwork: copied from power/FormJacobian_Power() */
76   PetscCall(DMNetworkGetSubnetwork(networkdm,0,&nv,&ne,&vtx,&edges));
77   PetscCall(FormJacobian_Power_private(networkdm,localX,J,nv,ne,vtx,edges,appctx));
78 
79   /* Water subnetwork: Identity */
80   PetscCall(DMNetworkGetSubnetwork(networkdm,1,&nv,&ne,&vtx,&edges));
81   for (i=0; i<nv; i++) {
82     PetscCall(DMNetworkIsGhostVertex(networkdm,vtx[i],&ghostvtex));
83     if (ghostvtex) continue;
84 
85     PetscCall(DMNetworkGetGlobalVecOffset(networkdm,vtx[i],ALL_COMPONENTS,&offset));
86     PetscCall(DMNetworkGetComponent(networkdm,vtx[i],ALL_COMPONENTS,NULL,NULL,&nvar));
87     for (j=0; j<nvar; j++) {
88       row = offset + j;
89       PetscCall(MatSetValues(J,1,&row,1,&row,&one,ADD_VALUES));
90     }
91   }
92   PetscCall(MatAssemblyBegin(J,MAT_FINAL_ASSEMBLY));
93   PetscCall(MatAssemblyEnd(J,MAT_FINAL_ASSEMBLY));
94 
95   PetscCall(DMRestoreLocalVector(networkdm,&localX));
96   PetscFunctionReturn(0);
97 }
98 
99 /* Dummy equation localF(X) = localX - localXold */
100 PetscErrorCode FormFunction_Dummy(DM networkdm,Vec localX, Vec localF,PetscInt nv,PetscInt ne,const PetscInt* vtx,const PetscInt* edges,void* appctx)
101 {
102   const PetscScalar *xarr,*xoldarr;
103   PetscScalar       *farr;
104   PetscInt          i,j,offset,nvar;
105   PetscBool         ghostvtex;
106   UserCtx           *user = (UserCtx*)appctx;
107   Vec               localXold = user->localXold;
108 
109   PetscFunctionBegin;
110   PetscCall(VecGetArrayRead(localX,&xarr));
111   PetscCall(VecGetArrayRead(localXold,&xoldarr));
112   PetscCall(VecGetArray(localF,&farr));
113 
114   for (i=0; i<nv; i++) {
115     PetscCall(DMNetworkIsGhostVertex(networkdm,vtx[i],&ghostvtex));
116     if (ghostvtex) continue;
117 
118     PetscCall(DMNetworkGetLocalVecOffset(networkdm,vtx[i],ALL_COMPONENTS,&offset));
119     PetscCall(DMNetworkGetComponent(networkdm,vtx[i],ALL_COMPONENTS,NULL,NULL,&nvar));
120     for (j=0; j<nvar; j++) {
121       farr[offset+j] = xarr[offset+j] - xoldarr[offset+j];
122     }
123   }
124 
125   PetscCall(VecRestoreArrayRead(localX,&xarr));
126   PetscCall(VecRestoreArrayRead(localXold,&xoldarr));
127   PetscCall(VecRestoreArray(localF,&farr));
128   PetscFunctionReturn(0);
129 }
130 
131 PetscErrorCode FormFunction(SNES snes,Vec X,Vec F,void *appctx)
132 {
133   DM             networkdm;
134   Vec            localX,localF;
135   PetscInt       nv,ne,v;
136   const PetscInt *vtx,*edges;
137   PetscMPIInt    rank;
138   MPI_Comm       comm;
139   UserCtx        *user = (UserCtx*)appctx;
140   UserCtx_Power  appctx_power = (*user).appctx_power;
141   AppCtx_Water   appctx_water = (*user).appctx_water;
142 
143   PetscFunctionBegin;
144   PetscCall(SNESGetDM(snes,&networkdm));
145   PetscCall(PetscObjectGetComm((PetscObject)networkdm,&comm));
146   PetscCallMPI(MPI_Comm_rank(comm,&rank));
147 
148   PetscCall(DMGetLocalVector(networkdm,&localX));
149   PetscCall(DMGetLocalVector(networkdm,&localF));
150   PetscCall(VecSet(F,0.0));
151   PetscCall(VecSet(localF,0.0));
152 
153   PetscCall(DMGlobalToLocalBegin(networkdm,X,INSERT_VALUES,localX));
154   PetscCall(DMGlobalToLocalEnd(networkdm,X,INSERT_VALUES,localX));
155 
156   /* Form Function for power subnetwork */
157   PetscCall(DMNetworkGetSubnetwork(networkdm,0,&nv,&ne,&vtx,&edges));
158   if (user->subsnes_id == 1) { /* snes_water only */
159     PetscCall(FormFunction_Dummy(networkdm,localX,localF,nv,ne,vtx,edges,user));
160   } else {
161     PetscCall(FormFunction_Power(networkdm,localX,localF,nv,ne,vtx,edges,&appctx_power));
162   }
163 
164   /* Form Function for water subnetwork */
165   PetscCall(DMNetworkGetSubnetwork(networkdm,1,&nv,&ne,&vtx,&edges));
166   if (user->subsnes_id == 0) { /* snes_power only */
167     PetscCall(FormFunction_Dummy(networkdm,localX,localF,nv,ne,vtx,edges,user));
168   } else {
169     PetscCall(FormFunction_Water(networkdm,localX,localF,nv,ne,vtx,edges,NULL));
170   }
171 
172   /* Illustrate how to access the coupling vertex of the subnetworks without doing anything to F yet */
173   PetscCall(DMNetworkGetSharedVertices(networkdm,&nv,&vtx));
174   for (v=0; v<nv; v++) {
175     PetscInt       key,ncomp,nvar,nconnedges,k,e,keye,goffset[3];
176     void*          component;
177     const PetscInt *connedges;
178 
179     PetscCall(DMNetworkGetComponent(networkdm,vtx[v],ALL_COMPONENTS,NULL,NULL,&nvar));
180     PetscCall(DMNetworkGetNumComponents(networkdm,vtx[v],&ncomp));
181     /* printf("  [%d] coupling vertex[%D]: v %D, ncomp %D; nvar %D\n",rank,v,vtx[v], ncomp,nvar); */
182 
183     for (k=0; k<ncomp; k++) {
184       PetscCall(DMNetworkGetComponent(networkdm,vtx[v],k,&key,&component,&nvar));
185       PetscCall(DMNetworkGetGlobalVecOffset(networkdm,vtx[v],k,&goffset[k]));
186 
187       /* Verify the coupling vertex is a powernet load vertex or a water vertex */
188       switch (k) {
189       case 0:
190         PetscCheckFalse(key != appctx_power.compkey_bus || nvar != 2,PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"key %D not a power bus vertex or nvar %D != 2",key,nvar);
191         break;
192       case 1:
193         PetscCheckFalse(key != appctx_power.compkey_load || nvar != 0 || goffset[1] != goffset[0]+2,PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Not a power load vertex");
194         break;
195       case 2:
196         PetscCheckFalse(key != appctx_water.compkey_vtx || nvar != 1 || goffset[2] != goffset[1],PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Not a water vertex");
197         break;
198       default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "k %D is wrong",k);
199       }
200       /* printf("  [%d] coupling vertex[%D]: key %D; nvar %D, goffset %D\n",rank,v,key,nvar,goffset[k]); */
201     }
202 
203     /* Get its supporting edges */
204     PetscCall(DMNetworkGetSupportingEdges(networkdm,vtx[v],&nconnedges,&connedges));
205     /* printf("\n[%d] coupling vertex: nconnedges %D\n",rank,nconnedges);PetscCall(ierr); */
206     for (k=0; k<nconnedges; k++) {
207       e = connedges[k];
208       PetscCall(DMNetworkGetNumComponents(networkdm,e,&ncomp));
209       /* printf("\n  [%d] connected edge[%D]=%D has ncomp %D\n",rank,k,e,ncomp); */
210       PetscCall(DMNetworkGetComponent(networkdm,e,0,&keye,&component,NULL));
211       if (keye == appctx_water.compkey_edge) { /* water_compkey_edge */
212         EDGE_Water        edge=(EDGE_Water)component;
213         if (edge->type == EDGE_TYPE_PUMP) {
214           /* printf("  connected edge[%D]=%D has keye=%D, is appctx_water.compkey_edge with EDGE_TYPE_PUMP\n",k,e,keye); */
215         }
216       } else { /* ower->compkey_branch */
217         PetscCheckFalse(keye != appctx_power.compkey_branch,PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Not a power branch");
218       }
219     }
220   }
221 
222   PetscCall(DMRestoreLocalVector(networkdm,&localX));
223 
224   PetscCall(DMLocalToGlobalBegin(networkdm,localF,ADD_VALUES,F));
225   PetscCall(DMLocalToGlobalEnd(networkdm,localF,ADD_VALUES,F));
226   PetscCall(DMRestoreLocalVector(networkdm,&localF));
227 #if 0
228   if (rank == 0) printf("F:\n");
229   PetscCall(VecView(F,PETSC_VIEWER_STDOUT_WORLD));
230 #endif
231   PetscFunctionReturn(0);
232 }
233 
234 PetscErrorCode SetInitialGuess(DM networkdm,Vec X,void* appctx)
235 {
236   PetscInt       nv,ne,i,j,ncomp,offset,key;
237   const PetscInt *vtx,*edges;
238   UserCtx        *user = (UserCtx*)appctx;
239   Vec            localX = user->localXold;
240   UserCtx_Power  appctx_power = (*user).appctx_power;
241   AppCtx_Water   appctx_water = (*user).appctx_water;
242   PetscBool      ghost;
243   PetscScalar    *xarr;
244   VERTEX_Power   bus;
245   VERTEX_Water   vertex;
246   void*          component;
247   GEN            gen;
248 
249   PetscFunctionBegin;
250   PetscCall(VecSet(X,0.0));
251   PetscCall(VecSet(localX,0.0));
252 
253   /* Set initial guess for power subnetwork */
254   PetscCall(DMNetworkGetSubnetwork(networkdm,0,&nv,&ne,&vtx,&edges));
255   PetscCall(SetInitialGuess_Power(networkdm,localX,nv,ne,vtx,edges,&appctx_power));
256 
257   /* Set initial guess for water subnetwork */
258   PetscCall(DMNetworkGetSubnetwork(networkdm,1,&nv,&ne,&vtx,&edges));
259   PetscCall(SetInitialGuess_Water(networkdm,localX,nv,ne,vtx,edges,NULL));
260 
261   /* Set initial guess at the coupling vertex */
262   PetscCall(VecGetArray(localX,&xarr));
263   PetscCall(DMNetworkGetSharedVertices(networkdm,&nv,&vtx));
264   for (i=0; i<nv; i++) {
265     PetscCall(DMNetworkIsGhostVertex(networkdm,vtx[i],&ghost));
266     if (ghost) continue;
267 
268     PetscCall(DMNetworkGetNumComponents(networkdm,vtx[i],&ncomp));
269     for (j=0; j<ncomp; j++) {
270       PetscCall(DMNetworkGetLocalVecOffset(networkdm,vtx[i],j,&offset));
271       PetscCall(DMNetworkGetComponent(networkdm,vtx[i],j,&key,(void**)&component,NULL));
272       if (key == appctx_power.compkey_bus) {
273         bus = (VERTEX_Power)(component);
274         xarr[offset]   = bus->va*PETSC_PI/180.0;
275         xarr[offset+1] = bus->vm;
276       } else if (key == appctx_power.compkey_gen) {
277         gen = (GEN)(component);
278         if (!gen->status) continue;
279         xarr[offset+1] = gen->vs;
280       } else if (key == appctx_water.compkey_vtx) {
281         vertex = (VERTEX_Water)(component);
282         if (vertex->type == VERTEX_TYPE_JUNCTION) {
283           xarr[offset] = 100;
284         } else if (vertex->type == VERTEX_TYPE_RESERVOIR) {
285           xarr[offset] = vertex->res.head;
286         } else {
287           xarr[offset] = vertex->tank.initlvl + vertex->tank.elev;
288         }
289       }
290     }
291   }
292   PetscCall(VecRestoreArray(localX,&xarr));
293 
294   PetscCall(DMLocalToGlobalBegin(networkdm,localX,ADD_VALUES,X));
295   PetscCall(DMLocalToGlobalEnd(networkdm,localX,ADD_VALUES,X));
296   PetscFunctionReturn(0);
297 }
298 
299 int main(int argc,char **argv)
300 {
301   DM               networkdm;
302   PetscLogStage    stage[4];
303   PetscMPIInt      rank,size;
304   PetscInt         Nsubnet=2,numVertices[2],numEdges[2],i,j,nv,ne,it_max=10;
305   const PetscInt   *vtx,*edges;
306   Vec              X,F;
307   SNES             snes,snes_power,snes_water;
308   Mat              Jac;
309   PetscBool        ghost,viewJ=PETSC_FALSE,viewX=PETSC_FALSE,viewDM=PETSC_FALSE,test=PETSC_FALSE,distribute=PETSC_TRUE,flg;
310   UserCtx          user;
311   SNESConvergedReason reason;
312 
313   /* Power subnetwork */
314   UserCtx_Power       *appctx_power  = &user.appctx_power;
315   char                pfdata_file[PETSC_MAX_PATH_LEN] = "power/case9.m";
316   PFDATA              *pfdata = NULL;
317   PetscInt            genj,loadj,*edgelist_power = NULL,power_netnum;
318   PetscScalar         Sbase = 0.0;
319 
320   /* Water subnetwork */
321   AppCtx_Water        *appctx_water = &user.appctx_water;
322   WATERDATA           *waterdata = NULL;
323   char                waterdata_file[PETSC_MAX_PATH_LEN] = "water/sample1.inp";
324   PetscInt            *edgelist_water = NULL,water_netnum;
325 
326   /* Shared vertices between subnetworks */
327   PetscInt           power_svtx,water_svtx;
328 
329   PetscCall(PetscInitialize(&argc,&argv,"ex1options",help));
330   PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD,&rank));
331   PetscCallMPI(MPI_Comm_size(PETSC_COMM_WORLD,&size));
332 
333   /* (1) Read Data - Only rank 0 reads the data */
334   /*--------------------------------------------*/
335   PetscCall(PetscLogStageRegister("Read Data",&stage[0]));
336   PetscCall(PetscLogStagePush(stage[0]));
337 
338   for (i=0; i<Nsubnet; i++) {
339     numVertices[i] = 0;
340     numEdges[i]    = 0;
341   }
342 
343   /* All processes READ THE DATA FOR THE FIRST SUBNETWORK: Electric Power Grid */
344   /* Used for shared vertex, because currently the coupling info must be available in all processes!!! */
345   PetscCall(PetscOptionsGetString(NULL,NULL,"-pfdata",pfdata_file,PETSC_MAX_PATH_LEN-1,NULL));
346   PetscCall(PetscNew(&pfdata));
347   PetscCall(PFReadMatPowerData(pfdata,pfdata_file));
348   if (rank == 0) {
349     PetscCall(PetscPrintf(PETSC_COMM_SELF,"Power network: nb = %D, ngen = %D, nload = %D, nbranch = %D\n",pfdata->nbus,pfdata->ngen,pfdata->nload,pfdata->nbranch));
350   }
351   Sbase = pfdata->sbase;
352   if (rank == 0) { /* proc[0] will create Electric Power Grid */
353     numEdges[0]    = pfdata->nbranch;
354     numVertices[0] = pfdata->nbus;
355 
356     PetscCall(PetscMalloc1(2*numEdges[0],&edgelist_power));
357     PetscCall(GetListofEdges_Power(pfdata,edgelist_power));
358   }
359   /* Broadcast power Sbase to all processors */
360   PetscCallMPI(MPI_Bcast(&Sbase,1,MPIU_SCALAR,0,PETSC_COMM_WORLD));
361   appctx_power->Sbase     = Sbase;
362   appctx_power->jac_error = PETSC_FALSE;
363   /* If external option activated. Introduce error in jacobian */
364   PetscCall(PetscOptionsHasName(NULL,NULL, "-jac_error", &appctx_power->jac_error));
365 
366   /* All processes READ THE DATA FOR THE SECOND SUBNETWORK: Water */
367   /* Used for shared vertex, because currently the coupling info must be available in all processes!!! */
368   PetscCall(PetscNew(&waterdata));
369   PetscCall(PetscOptionsGetString(NULL,NULL,"-waterdata",waterdata_file,PETSC_MAX_PATH_LEN-1,NULL));
370   PetscCall(WaterReadData(waterdata,waterdata_file));
371   if (size == 1 || (size > 1 && rank == 1)) {
372     PetscCall(PetscCalloc1(2*waterdata->nedge,&edgelist_water));
373     PetscCall(GetListofEdges_Water(waterdata,edgelist_water));
374     numEdges[1]    = waterdata->nedge;
375     numVertices[1] = waterdata->nvertex;
376   }
377   PetscLogStagePop();
378 
379   /* (2) Create a network consist of two subnetworks */
380   /*-------------------------------------------------*/
381   PetscCall(PetscLogStageRegister("Net Setup",&stage[1]));
382   PetscCall(PetscLogStagePush(stage[1]));
383 
384   PetscCall(PetscOptionsGetBool(NULL,NULL,"-viewDM",&viewDM,NULL));
385   PetscCall(PetscOptionsGetBool(NULL,NULL,"-test",&test,NULL));
386   PetscCall(PetscOptionsGetBool(NULL,NULL,"-distribute",&distribute,NULL));
387 
388   /* Create an empty network object */
389   PetscCall(DMNetworkCreate(PETSC_COMM_WORLD,&networkdm));
390 
391   /* Register the components in the network */
392   PetscCall(DMNetworkRegisterComponent(networkdm,"branchstruct",sizeof(struct _p_EDGE_Power),&appctx_power->compkey_branch));
393   PetscCall(DMNetworkRegisterComponent(networkdm,"busstruct",sizeof(struct _p_VERTEX_Power),&appctx_power->compkey_bus));
394   PetscCall(DMNetworkRegisterComponent(networkdm,"genstruct",sizeof(struct _p_GEN),&appctx_power->compkey_gen));
395   PetscCall(DMNetworkRegisterComponent(networkdm,"loadstruct",sizeof(struct _p_LOAD),&appctx_power->compkey_load));
396 
397   PetscCall(DMNetworkRegisterComponent(networkdm,"edge_water",sizeof(struct _p_EDGE_Water),&appctx_water->compkey_edge));
398   PetscCall(DMNetworkRegisterComponent(networkdm,"vertex_water",sizeof(struct _p_VERTEX_Water),&appctx_water->compkey_vtx));
399 #if 0
400   PetscCall(PetscPrintf(PETSC_COMM_WORLD,"power->compkey_branch %d\n",appctx_power->compkey_branch));
401   PetscCall(PetscPrintf(PETSC_COMM_WORLD,"power->compkey_bus    %d\n",appctx_power->compkey_bus));
402   PetscCall(PetscPrintf(PETSC_COMM_WORLD,"power->compkey_gen    %d\n",appctx_power->compkey_gen));
403   PetscCall(PetscPrintf(PETSC_COMM_WORLD,"power->compkey_load   %d\n",appctx_power->compkey_load));
404   PetscCall(PetscPrintf(PETSC_COMM_WORLD,"water->compkey_edge   %d\n",appctx_water->compkey_edge));
405   PetscCall(PetscPrintf(PETSC_COMM_WORLD,"water->compkey_vtx    %d\n",appctx_water->compkey_vtx));
406 #endif
407   PetscCall(PetscSynchronizedPrintf(PETSC_COMM_WORLD,"[%d] Total local nvertices %D + %D = %D, nedges %D + %D = %D\n",rank,numVertices[0],numVertices[1],numVertices[0]+numVertices[1],numEdges[0],numEdges[1],numEdges[0]+numEdges[1]));
408   PetscCall(PetscSynchronizedFlush(PETSC_COMM_WORLD,PETSC_STDOUT));
409 
410   PetscCall(DMNetworkSetNumSubNetworks(networkdm,PETSC_DECIDE,Nsubnet));
411   PetscCall(DMNetworkAddSubnetwork(networkdm,"power",numEdges[0],edgelist_power,&power_netnum));
412   PetscCall(DMNetworkAddSubnetwork(networkdm,"water",numEdges[1],edgelist_water,&water_netnum));
413 
414   /* vertex subnet[0].4 shares with vertex subnet[1].0 */
415   power_svtx = 4; water_svtx = 0;
416   PetscCall(DMNetworkAddSharedVertices(networkdm,power_netnum,water_netnum,1,&power_svtx,&water_svtx));
417 
418   /* Set up the network layout */
419   PetscCall(DMNetworkLayoutSetUp(networkdm));
420 
421   /* ADD VARIABLES AND COMPONENTS FOR THE POWER SUBNETWORK */
422   /*-------------------------------------------------------*/
423   genj = 0; loadj = 0;
424   PetscCall(DMNetworkGetSubnetwork(networkdm,power_netnum,&nv,&ne,&vtx,&edges));
425 
426   for (i = 0; i < ne; i++) {
427     PetscCall(DMNetworkAddComponent(networkdm,edges[i],appctx_power->compkey_branch,&pfdata->branch[i],0));
428   }
429 
430   for (i = 0; i < nv; i++) {
431     PetscCall(DMNetworkIsSharedVertex(networkdm,vtx[i],&flg));
432     if (flg) continue;
433 
434     PetscCall(DMNetworkAddComponent(networkdm,vtx[i],appctx_power->compkey_bus,&pfdata->bus[i],2));
435     if (pfdata->bus[i].ngen) {
436       for (j = 0; j < pfdata->bus[i].ngen; j++) {
437         PetscCall(DMNetworkAddComponent(networkdm,vtx[i],appctx_power->compkey_gen,&pfdata->gen[genj++],0));
438       }
439     }
440     if (pfdata->bus[i].nload) {
441       for (j=0; j < pfdata->bus[i].nload; j++) {
442         PetscCall(DMNetworkAddComponent(networkdm,vtx[i],appctx_power->compkey_load,&pfdata->load[loadj++],0));
443       }
444     }
445   }
446 
447   /* ADD VARIABLES AND COMPONENTS FOR THE WATER SUBNETWORK */
448   /*-------------------------------------------------------*/
449   PetscCall(DMNetworkGetSubnetwork(networkdm,water_netnum,&nv,&ne,&vtx,&edges));
450   for (i = 0; i < ne; i++) {
451     PetscCall(DMNetworkAddComponent(networkdm,edges[i],appctx_water->compkey_edge,&waterdata->edge[i],0));
452   }
453 
454   for (i = 0; i < nv; i++) {
455     PetscCall(DMNetworkIsSharedVertex(networkdm,vtx[i],&flg));
456     if (flg) continue;
457 
458     PetscCall(DMNetworkAddComponent(networkdm,vtx[i],appctx_water->compkey_vtx,&waterdata->vertex[i],1));
459   }
460 
461   /* ADD VARIABLES AND COMPONENTS AT THE SHARED VERTEX: net[0].4 coupls with net[1].0 -- owning and all ghost ranks of the vertex do this */
462   /*----------------------------------------------------------------------------------------------------------------------------*/
463   PetscCall(DMNetworkGetSharedVertices(networkdm,&nv,&vtx));
464   for (i = 0; i < nv; i++) {
465     /* power */
466     PetscCall(DMNetworkAddComponent(networkdm,vtx[i],appctx_power->compkey_bus,&pfdata->bus[4],2));
467     /* bus[4] is a load, add its component */
468     PetscCall(DMNetworkAddComponent(networkdm,vtx[i],appctx_power->compkey_load,&pfdata->load[0],0));
469 
470     /* water */
471     PetscCall(DMNetworkAddComponent(networkdm,vtx[i],appctx_water->compkey_vtx,&waterdata->vertex[0],1));
472   }
473 
474   /* Set up DM for use */
475   PetscCall(DMSetUp(networkdm));
476   if (viewDM) {
477     PetscCall(PetscPrintf(PETSC_COMM_WORLD,"\nAfter DMSetUp, DMView:\n"));
478     PetscCall(DMView(networkdm,PETSC_VIEWER_STDOUT_WORLD));
479   }
480 
481   /* Free user objects */
482   PetscCall(PetscFree(edgelist_power));
483   PetscCall(PetscFree(pfdata->bus));
484   PetscCall(PetscFree(pfdata->gen));
485   PetscCall(PetscFree(pfdata->branch));
486   PetscCall(PetscFree(pfdata->load));
487   PetscCall(PetscFree(pfdata));
488 
489   PetscCall(PetscFree(edgelist_water));
490   PetscCall(PetscFree(waterdata->vertex));
491   PetscCall(PetscFree(waterdata->edge));
492   PetscCall(PetscFree(waterdata));
493 
494   /* Re-distribute networkdm to multiple processes for better job balance */
495   if (size >1 && distribute) {
496     PetscCall(DMNetworkDistribute(&networkdm,0));
497     if (viewDM) {
498       PetscCall(PetscPrintf(PETSC_COMM_WORLD,"\nAfter DMNetworkDistribute, DMView:\n"));
499       PetscCall(DMView(networkdm,PETSC_VIEWER_STDOUT_WORLD));
500     }
501   }
502 
503   /* Test DMNetworkGetSubnetwork() and DMNetworkGetSubnetworkSharedVertices() */
504   if (test) {
505     PetscInt  v,gidx;
506     PetscCallMPI(MPI_Barrier(PETSC_COMM_WORLD));
507     for (i=0; i<Nsubnet; i++) {
508       PetscCall(DMNetworkGetSubnetwork(networkdm,i,&nv,&ne,&vtx,&edges));
509       PetscCall(PetscPrintf(PETSC_COMM_SELF,"[%d] After distribute, subnet[%d] ne %d, nv %d\n",rank,i,ne,nv));
510       PetscCallMPI(MPI_Barrier(PETSC_COMM_WORLD));
511 
512       for (v=0; v<nv; v++) {
513         PetscCall(DMNetworkIsGhostVertex(networkdm,vtx[v],&ghost));
514         PetscCall(DMNetworkGetGlobalVertexIndex(networkdm,vtx[v],&gidx));
515         PetscCall(PetscPrintf(PETSC_COMM_SELF,"[%d] subnet[%d] v %d %d; ghost %d\n",rank,i,vtx[v],gidx,ghost));
516       }
517       PetscCallMPI(MPI_Barrier(PETSC_COMM_WORLD));
518     }
519     PetscCallMPI(MPI_Barrier(PETSC_COMM_WORLD));
520 
521     PetscCall(DMNetworkGetSharedVertices(networkdm,&nv,&vtx));
522     PetscCall(PetscPrintf(PETSC_COMM_SELF,"[%d] After distribute, num of shared vertices nsv = %d\n",rank,nv));
523     for (v=0; v<nv; v++) {
524       PetscCall(DMNetworkGetGlobalVertexIndex(networkdm,vtx[v],&gidx));
525       PetscCall(PetscPrintf(PETSC_COMM_SELF,"[%d] sv %d, gidx=%d\n",rank,vtx[v],gidx));
526     }
527     PetscCallMPI(MPI_Barrier(PETSC_COMM_WORLD));
528   }
529 
530   /* Create solution vector X */
531   PetscCall(DMCreateGlobalVector(networkdm,&X));
532   PetscCall(VecDuplicate(X,&F));
533   PetscCall(DMGetLocalVector(networkdm,&user.localXold));
534   PetscLogStagePop();
535 
536   /* (3) Setup Solvers */
537   /*-------------------*/
538   PetscCall(PetscOptionsGetBool(NULL,NULL,"-viewJ",&viewJ,NULL));
539   PetscCall(PetscOptionsGetBool(NULL,NULL,"-viewX",&viewX,NULL));
540 
541   PetscCall(PetscLogStageRegister("SNES Setup",&stage[2]));
542   PetscCall(PetscLogStagePush(stage[2]));
543 
544   PetscCall(SetInitialGuess(networkdm,X,&user));
545 
546   /* Create coupled snes */
547   /*-------------------- */
548   PetscCall(PetscPrintf(PETSC_COMM_WORLD,"SNES_coupled setup ......\n"));
549   user.subsnes_id = Nsubnet;
550   PetscCall(SNESCreate(PETSC_COMM_WORLD,&snes));
551   PetscCall(SNESSetDM(snes,networkdm));
552   PetscCall(SNESSetOptionsPrefix(snes,"coupled_"));
553   PetscCall(SNESSetFunction(snes,F,FormFunction,&user));
554   PetscCall(SNESMonitorSet(snes,UserMonitor,&user,NULL));
555   PetscCall(SNESSetFromOptions(snes));
556 
557   if (viewJ) {
558     /* View Jac structure */
559     PetscCall(SNESGetJacobian(snes,&Jac,NULL,NULL,NULL));
560     PetscCall(MatView(Jac,PETSC_VIEWER_DRAW_WORLD));
561   }
562 
563   if (viewX) {
564     PetscCall(PetscPrintf(PETSC_COMM_WORLD,"Solution:\n"));
565     PetscCall(VecView(X,PETSC_VIEWER_STDOUT_WORLD));
566   }
567 
568   if (viewJ) {
569     /* View assembled Jac */
570     PetscCall(MatView(Jac,PETSC_VIEWER_DRAW_WORLD));
571   }
572 
573   /* Create snes_power */
574   /*-------------------*/
575   PetscCall(PetscPrintf(PETSC_COMM_WORLD,"SNES_power setup ......\n"));
576 
577   user.subsnes_id = 0;
578   PetscCall(SNESCreate(PETSC_COMM_WORLD,&snes_power));
579   PetscCall(SNESSetDM(snes_power,networkdm));
580   PetscCall(SNESSetOptionsPrefix(snes_power,"power_"));
581   PetscCall(SNESSetFunction(snes_power,F,FormFunction,&user));
582   PetscCall(SNESMonitorSet(snes_power,UserMonitor,&user,NULL));
583 
584   /* Use user-provide Jacobian */
585   PetscCall(DMCreateMatrix(networkdm,&Jac));
586   PetscCall(SNESSetJacobian(snes_power,Jac,Jac,FormJacobian_subPower,&user));
587   PetscCall(SNESSetFromOptions(snes_power));
588 
589   if (viewX) {
590     PetscCall(PetscPrintf(PETSC_COMM_WORLD,"Power Solution:\n"));
591     PetscCall(VecView(X,PETSC_VIEWER_STDOUT_WORLD));
592   }
593   if (viewJ) {
594     PetscCall(PetscPrintf(PETSC_COMM_WORLD,"Power Jac:\n"));
595     PetscCall(SNESGetJacobian(snes_power,&Jac,NULL,NULL,NULL));
596     PetscCall(MatView(Jac,PETSC_VIEWER_DRAW_WORLD));
597     /* PetscCall(MatView(Jac,PETSC_VIEWER_STDOUT_WORLD)); */
598   }
599 
600   /* Create snes_water */
601   /*-------------------*/
602   PetscCall(PetscPrintf(PETSC_COMM_WORLD,"SNES_water setup......\n"));
603 
604   user.subsnes_id = 1;
605   PetscCall(SNESCreate(PETSC_COMM_WORLD,&snes_water));
606   PetscCall(SNESSetDM(snes_water,networkdm));
607   PetscCall(SNESSetOptionsPrefix(snes_water,"water_"));
608   PetscCall(SNESSetFunction(snes_water,F,FormFunction,&user));
609   PetscCall(SNESMonitorSet(snes_water,UserMonitor,&user,NULL));
610   PetscCall(SNESSetFromOptions(snes_water));
611 
612   if (viewX) {
613     PetscCall(PetscPrintf(PETSC_COMM_WORLD,"Water Solution:\n"));
614     PetscCall(VecView(X,PETSC_VIEWER_STDOUT_WORLD));
615   }
616   PetscCall(PetscLogStagePop());
617 
618   /* (4) Solve */
619   /*-----------*/
620   PetscCall(PetscLogStageRegister("SNES Solve",&stage[3]));
621   PetscCall(PetscLogStagePush(stage[3]));
622   user.it = 0;
623   reason  = SNES_DIVERGED_DTOL;
624   while (user.it < it_max && (PetscInt)reason<0) {
625 #if 0
626     user.subsnes_id = 0;
627     PetscCall(SNESSolve(snes_power,NULL,X));
628 
629     user.subsnes_id = 1;
630     PetscCall(SNESSolve(snes_water,NULL,X));
631 #endif
632     user.subsnes_id = Nsubnet;
633     PetscCall(SNESSolve(snes,NULL,X));
634 
635     PetscCall(SNESGetConvergedReason(snes,&reason));
636     user.it++;
637   }
638   PetscCall(PetscPrintf(PETSC_COMM_WORLD,"Coupled_SNES converged in %D iterations\n",user.it));
639   if (viewX) {
640     PetscCall(PetscPrintf(PETSC_COMM_WORLD,"Final Solution:\n"));
641     PetscCall(VecView(X,PETSC_VIEWER_STDOUT_WORLD));
642   }
643   PetscCall(PetscLogStagePop());
644 
645   /* Free objects */
646   /* -------------*/
647   PetscCall(VecDestroy(&X));
648   PetscCall(VecDestroy(&F));
649   PetscCall(DMRestoreLocalVector(networkdm,&user.localXold));
650 
651   PetscCall(SNESDestroy(&snes));
652   PetscCall(MatDestroy(&Jac));
653   PetscCall(SNESDestroy(&snes_power));
654   PetscCall(SNESDestroy(&snes_water));
655 
656   PetscCall(DMDestroy(&networkdm));
657   PetscCall(PetscFinalize());
658   return 0;
659 }
660 
661 /*TEST
662 
663    build:
664      requires: !complex double defined(PETSC_HAVE_ATTRIBUTEALIGNED)
665      depends: power/PFReadData.c power/pffunctions.c water/waterreaddata.c water/waterfunctions.c
666 
667    test:
668       args: -coupled_snes_converged_reason -options_left no -viewDM
669       localrunfiles: ex1options power/case9.m water/sample1.inp
670       output_file: output/ex1.out
671 
672    test:
673       suffix: 2
674       nsize: 3
675       args: -coupled_snes_converged_reason -options_left no -petscpartitioner_type parmetis
676       localrunfiles: ex1options power/case9.m water/sample1.inp
677       output_file: output/ex1_2.out
678       requires: parmetis
679 
680 #   test:
681 #      suffix: 3
682 #      nsize: 3
683 #      args: -coupled_snes_converged_reason -options_left no -distribute false
684 #      localrunfiles: ex1options power/case9.m water/sample1.inp
685 #      output_file: output/ex1_2.out
686 
687    test:
688       suffix: 4
689       nsize: 4
690       args: -coupled_snes_converged_reason -options_left no -petscpartitioner_type simple -viewDM
691       localrunfiles: ex1options power/case9.m water/sample1.inp
692       output_file: output/ex1_4.out
693 
694 TEST*/
695