xref: /petsc/src/snes/tutorials/network/ex1.c (revision 5039956b1551adaf5f1762cf3911e24e7c2801d8)
15f25b224SDuncan Campbell static char help[] = "This example demonstrates the use of DMNetwork with subnetworks for solving a coupled nonlinear \n\
2c4762a1bSJed Brown                       electric power grid and water pipe problem.\n\
3c4762a1bSJed Brown                       The available solver options are in the ex1options file \n\
4c4762a1bSJed Brown                       and the data files are in the datafiles of subdirectories.\n\
5c4762a1bSJed Brown                       Run this program: mpiexec -n <n> ./ex1 \n\\n";
65f25b224SDuncan Campbell /*
75f25b224SDuncan Campbell   Example:
85f25b224SDuncan Campbell     mpiexec -n 3 ./ex1 -petscpartitioner_type parmetis -dmnetwork_view draw -dmnetwork_view_distributed draw -dmnetwork_view_rank_range 0,1,2
9*5039956bSHong Zhang     mpiexec -n 3 ./ex1 -petscpartitioner_type simple -dmnetwork_view_distributed draw -dmnetwork_view_zoomin_vertices 0 -dmnetwork_view_zoomin_vertices_padding 2 -dmnetwork_view_rank_range 0
107cd471e7SHong Zhang     mpiexec -n <n> ./ex1 -monitorIteration -monitorColor -power_snes_max_it 0 -water_snes_max_it 0 -coupled_snes_max_it 10 -draw_pause 5.0
115f25b224SDuncan Campbell */
125f25b224SDuncan Campbell 
13c4762a1bSJed Brown #include "power/power.h"
14c4762a1bSJed Brown #include "water/water.h"
15c4762a1bSJed Brown 
16c4762a1bSJed Brown typedef struct {
17c4762a1bSJed Brown   UserCtx_Power appctx_power;
18c4762a1bSJed Brown   AppCtx_Water  appctx_water;
19c4762a1bSJed Brown   PetscInt      subsnes_id; /* snes solver id */
20c4762a1bSJed Brown   PetscInt      it;         /* iteration number */
21c4762a1bSJed Brown   Vec           localXold;  /* store previous solution, used by FormFunction_Dummy() */
227cd471e7SHong Zhang   PetscBool     monitorColor;
23c4762a1bSJed Brown } UserCtx;
24c4762a1bSJed Brown 
257cd471e7SHong Zhang /*
267cd471e7SHong Zhang   UserMonitor -- called at the end of every SNES iteration via option `-monitorIteration' or `-monitorColor'
277cd471e7SHong Zhang */
28d71ae5a4SJacob Faibussowitsch PetscErrorCode UserMonitor(SNES snes, PetscInt its, PetscReal fnorm, void *appctx)
29d71ae5a4SJacob Faibussowitsch {
30c4762a1bSJed Brown   UserCtx    *user = (UserCtx *)appctx;
31c4762a1bSJed Brown   PetscMPIInt rank;
32c4762a1bSJed Brown   MPI_Comm    comm;
337cd471e7SHong Zhang   PetscInt    it;
34c4762a1bSJed Brown 
35c4762a1bSJed Brown   PetscFunctionBegin;
369566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)snes, &comm));
379566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
387cd471e7SHong Zhang 
397cd471e7SHong Zhang   PetscCall(SNESGetIterationNumber(snes, &it));
40dd400576SPatrick Sanan   if (rank == 0) {
417cd471e7SHong Zhang     PetscCall(SNESGetIterationNumber(snes, &it));
427cd471e7SHong Zhang     if (user->subsnes_id == 0 || user->subsnes_id == 1) {
437cd471e7SHong Zhang       PetscCall(PetscPrintf(PETSC_COMM_SELF, " subsnes_id %" PetscInt_FMT ", it %" PetscInt_FMT ", fnorm %g\n", user->subsnes_id, it, (double)fnorm));
44c4762a1bSJed Brown     } else {
457cd471e7SHong Zhang       PetscCall(PetscPrintf(PETSC_COMM_SELF, "   coupled_snes_it %" PetscInt_FMT ", total_snes_it %" PetscInt_FMT ", fnorm %g\n", it, user->it, (double)fnorm));
46c4762a1bSJed Brown     }
47c4762a1bSJed Brown   }
487cd471e7SHong Zhang 
497cd471e7SHong Zhang   if (user->monitorColor) {
507cd471e7SHong Zhang     DM           networkdm, dmcoords;
517cd471e7SHong Zhang     Vec          F;
527cd471e7SHong Zhang     PetscInt     v, vStart, vEnd, offset, gidx, rstart;
537cd471e7SHong Zhang     PetscReal   *color;
547cd471e7SHong Zhang     PetscScalar *farr;
557cd471e7SHong Zhang     PetscBool    ghost;
567cd471e7SHong Zhang 
579566063dSJacob Faibussowitsch     PetscCall(SNESGetDM(snes, &networkdm));
587cd471e7SHong Zhang     PetscCall(DMGetCoordinateDM(networkdm, &dmcoords));
597cd471e7SHong Zhang 
607cd471e7SHong Zhang     PetscCall(SNESGetFunction(snes, &F, NULL, NULL));
617cd471e7SHong Zhang     PetscCall(VecGetOwnershipRange(F, &rstart, NULL));
627cd471e7SHong Zhang 
637cd471e7SHong Zhang     PetscCall(VecGetArray(F, &farr));
647cd471e7SHong Zhang     PetscCall(DMNetworkGetVertexRange(dmcoords, &vStart, &vEnd));
657cd471e7SHong Zhang 
667cd471e7SHong Zhang     PetscCall(PetscPrintf(MPI_COMM_WORLD, "\nColorPrint:\n"));
677cd471e7SHong Zhang     for (v = vStart; v < vEnd; v++) {
687cd471e7SHong Zhang       PetscCall(DMNetworkIsGhostVertex(networkdm, v, &ghost));
697cd471e7SHong Zhang       PetscCall(DMNetworkGetComponent(dmcoords, v, 0, NULL, (void **)&color, NULL));
707cd471e7SHong Zhang       PetscCall(DMNetworkGetGlobalVertexIndex(networkdm, v, &gidx));
717cd471e7SHong Zhang       if (!ghost) {
727cd471e7SHong Zhang         PetscCall(DMNetworkGetGlobalVecOffset(networkdm, v, 0, &offset));
737cd471e7SHong Zhang         *color = (PetscRealPart(farr[offset - rstart]));
747cd471e7SHong Zhang       }
757cd471e7SHong Zhang       PetscCall(PetscSynchronizedPrintf(MPI_COMM_WORLD, "[%d] v %" PetscInt_FMT ": color[%" PetscInt_FMT "] = %g\n", rank, gidx, offset - rstart, *color));
767cd471e7SHong Zhang     }
777cd471e7SHong Zhang     PetscCall(PetscSynchronizedFlush(MPI_COMM_WORLD, NULL));
787cd471e7SHong Zhang     PetscCall(VecRestoreArray(F, &farr));
797cd471e7SHong Zhang 
807cd471e7SHong Zhang     PetscCall(PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD, PETSC_VIEWER_ASCII_CSV));
817cd471e7SHong Zhang     PetscCall(DMView(networkdm, PETSC_VIEWER_DRAW_WORLD));
827cd471e7SHong Zhang     PetscCall(PetscViewerPopFormat(PETSC_VIEWER_STDOUT_WORLD));
837cd471e7SHong Zhang   }
843ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
85c4762a1bSJed Brown }
86c4762a1bSJed Brown 
87d71ae5a4SJacob Faibussowitsch PetscErrorCode FormJacobian_subPower(SNES snes, Vec X, Mat J, Mat Jpre, void *appctx)
88d71ae5a4SJacob Faibussowitsch {
89c4762a1bSJed Brown   DM              networkdm;
90c4762a1bSJed Brown   Vec             localX;
91c4762a1bSJed Brown   PetscInt        nv, ne, i, j, offset, nvar, row;
92c4762a1bSJed Brown   const PetscInt *vtx, *edges;
93c4762a1bSJed Brown   PetscBool       ghostvtex;
94c4762a1bSJed Brown   PetscScalar     one = 1.0;
95c4762a1bSJed Brown   PetscMPIInt     rank;
96c4762a1bSJed Brown   MPI_Comm        comm;
97c4762a1bSJed Brown 
98c4762a1bSJed Brown   PetscFunctionBegin;
999566063dSJacob Faibussowitsch   PetscCall(SNESGetDM(snes, &networkdm));
1009566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(networkdm, &localX));
101c4762a1bSJed Brown 
1029566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)networkdm, &comm));
1039566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
104c4762a1bSJed Brown 
1059566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalBegin(networkdm, X, INSERT_VALUES, localX));
1069566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalEnd(networkdm, X, INSERT_VALUES, localX));
107c4762a1bSJed Brown 
1089566063dSJacob Faibussowitsch   PetscCall(MatZeroEntries(J));
109c4762a1bSJed Brown 
110c4762a1bSJed Brown   /* Power subnetwork: copied from power/FormJacobian_Power() */
1119566063dSJacob Faibussowitsch   PetscCall(DMNetworkGetSubnetwork(networkdm, 0, &nv, &ne, &vtx, &edges));
1129566063dSJacob Faibussowitsch   PetscCall(FormJacobian_Power_private(networkdm, localX, J, nv, ne, vtx, edges, appctx));
113c4762a1bSJed Brown 
114c4762a1bSJed Brown   /* Water subnetwork: Identity */
1159566063dSJacob Faibussowitsch   PetscCall(DMNetworkGetSubnetwork(networkdm, 1, &nv, &ne, &vtx, &edges));
116c4762a1bSJed Brown   for (i = 0; i < nv; i++) {
1179566063dSJacob Faibussowitsch     PetscCall(DMNetworkIsGhostVertex(networkdm, vtx[i], &ghostvtex));
118c4762a1bSJed Brown     if (ghostvtex) continue;
119c4762a1bSJed Brown 
1209566063dSJacob Faibussowitsch     PetscCall(DMNetworkGetGlobalVecOffset(networkdm, vtx[i], ALL_COMPONENTS, &offset));
1219566063dSJacob Faibussowitsch     PetscCall(DMNetworkGetComponent(networkdm, vtx[i], ALL_COMPONENTS, NULL, NULL, &nvar));
122c4762a1bSJed Brown     for (j = 0; j < nvar; j++) {
123c4762a1bSJed Brown       row = offset + j;
1249566063dSJacob Faibussowitsch       PetscCall(MatSetValues(J, 1, &row, 1, &row, &one, ADD_VALUES));
125c4762a1bSJed Brown     }
126c4762a1bSJed Brown   }
1279566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(J, MAT_FINAL_ASSEMBLY));
1289566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(J, MAT_FINAL_ASSEMBLY));
129c4762a1bSJed Brown 
1309566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(networkdm, &localX));
1313ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
132c4762a1bSJed Brown }
133c4762a1bSJed Brown 
134c4762a1bSJed Brown /* Dummy equation localF(X) = localX - localXold */
135d71ae5a4SJacob Faibussowitsch PetscErrorCode FormFunction_Dummy(DM networkdm, Vec localX, Vec localF, PetscInt nv, PetscInt ne, const PetscInt *vtx, const PetscInt *edges, void *appctx)
136d71ae5a4SJacob Faibussowitsch {
137c4762a1bSJed Brown   const PetscScalar *xarr, *xoldarr;
138c4762a1bSJed Brown   PetscScalar       *farr;
139c4762a1bSJed Brown   PetscInt           i, j, offset, nvar;
140c4762a1bSJed Brown   PetscBool          ghostvtex;
141c4762a1bSJed Brown   UserCtx           *user      = (UserCtx *)appctx;
142c4762a1bSJed Brown   Vec                localXold = user->localXold;
143c4762a1bSJed Brown 
144c4762a1bSJed Brown   PetscFunctionBegin;
1459566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(localX, &xarr));
1469566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(localXold, &xoldarr));
1479566063dSJacob Faibussowitsch   PetscCall(VecGetArray(localF, &farr));
148c4762a1bSJed Brown 
149c4762a1bSJed Brown   for (i = 0; i < nv; i++) {
1509566063dSJacob Faibussowitsch     PetscCall(DMNetworkIsGhostVertex(networkdm, vtx[i], &ghostvtex));
151c4762a1bSJed Brown     if (ghostvtex) continue;
152c4762a1bSJed Brown 
1539566063dSJacob Faibussowitsch     PetscCall(DMNetworkGetLocalVecOffset(networkdm, vtx[i], ALL_COMPONENTS, &offset));
1549566063dSJacob Faibussowitsch     PetscCall(DMNetworkGetComponent(networkdm, vtx[i], ALL_COMPONENTS, NULL, NULL, &nvar));
155ad540459SPierre Jolivet     for (j = 0; j < nvar; j++) farr[offset + j] = xarr[offset + j] - xoldarr[offset + j];
156c4762a1bSJed Brown   }
157c4762a1bSJed Brown 
1589566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(localX, &xarr));
1599566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(localXold, &xoldarr));
1609566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(localF, &farr));
1613ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
162c4762a1bSJed Brown }
163c4762a1bSJed Brown 
164d71ae5a4SJacob Faibussowitsch PetscErrorCode FormFunction(SNES snes, Vec X, Vec F, void *appctx)
165d71ae5a4SJacob Faibussowitsch {
166c4762a1bSJed Brown   DM              networkdm;
167c4762a1bSJed Brown   Vec             localX, localF;
1682bf73ac6SHong Zhang   PetscInt        nv, ne, v;
169c4762a1bSJed Brown   const PetscInt *vtx, *edges;
170c4762a1bSJed Brown   PetscMPIInt     rank;
171c4762a1bSJed Brown   MPI_Comm        comm;
172c4762a1bSJed Brown   UserCtx        *user         = (UserCtx *)appctx;
173c4762a1bSJed Brown   UserCtx_Power   appctx_power = (*user).appctx_power;
1742bf73ac6SHong Zhang   AppCtx_Water    appctx_water = (*user).appctx_water;
175c4762a1bSJed Brown 
176c4762a1bSJed Brown   PetscFunctionBegin;
1779566063dSJacob Faibussowitsch   PetscCall(SNESGetDM(snes, &networkdm));
1789566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)networkdm, &comm));
1799566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
180c4762a1bSJed Brown 
1819566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(networkdm, &localX));
1829566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(networkdm, &localF));
1839566063dSJacob Faibussowitsch   PetscCall(VecSet(F, 0.0));
1849566063dSJacob Faibussowitsch   PetscCall(VecSet(localF, 0.0));
185c4762a1bSJed Brown 
1869566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalBegin(networkdm, X, INSERT_VALUES, localX));
1879566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalEnd(networkdm, X, INSERT_VALUES, localX));
188c4762a1bSJed Brown 
189c4762a1bSJed Brown   /* Form Function for power subnetwork */
1909566063dSJacob Faibussowitsch   PetscCall(DMNetworkGetSubnetwork(networkdm, 0, &nv, &ne, &vtx, &edges));
191c4762a1bSJed Brown   if (user->subsnes_id == 1) { /* snes_water only */
1929566063dSJacob Faibussowitsch     PetscCall(FormFunction_Dummy(networkdm, localX, localF, nv, ne, vtx, edges, user));
193c4762a1bSJed Brown   } else {
1949566063dSJacob Faibussowitsch     PetscCall(FormFunction_Power(networkdm, localX, localF, nv, ne, vtx, edges, &appctx_power));
195c4762a1bSJed Brown   }
196c4762a1bSJed Brown 
197c4762a1bSJed Brown   /* Form Function for water subnetwork */
1989566063dSJacob Faibussowitsch   PetscCall(DMNetworkGetSubnetwork(networkdm, 1, &nv, &ne, &vtx, &edges));
199c4762a1bSJed Brown   if (user->subsnes_id == 0) { /* snes_power only */
2009566063dSJacob Faibussowitsch     PetscCall(FormFunction_Dummy(networkdm, localX, localF, nv, ne, vtx, edges, user));
201c4762a1bSJed Brown   } else {
2029566063dSJacob Faibussowitsch     PetscCall(FormFunction_Water(networkdm, localX, localF, nv, ne, vtx, edges, NULL));
203c4762a1bSJed Brown   }
204c4762a1bSJed Brown 
2052bf73ac6SHong Zhang   /* Illustrate how to access the coupling vertex of the subnetworks without doing anything to F yet */
2069566063dSJacob Faibussowitsch   PetscCall(DMNetworkGetSharedVertices(networkdm, &nv, &vtx));
2072bf73ac6SHong Zhang   for (v = 0; v < nv; v++) {
2082bf73ac6SHong Zhang     PetscInt        key, ncomp, nvar, nconnedges, k, e, keye, goffset[3];
209c4762a1bSJed Brown     void           *component;
2102bf73ac6SHong Zhang     const PetscInt *connedges;
211c4762a1bSJed Brown 
2129566063dSJacob Faibussowitsch     PetscCall(DMNetworkGetComponent(networkdm, vtx[v], ALL_COMPONENTS, NULL, NULL, &nvar));
2139566063dSJacob Faibussowitsch     PetscCall(DMNetworkGetNumComponents(networkdm, vtx[v], &ncomp));
21463a3b9bcSJacob Faibussowitsch     /* printf("  [%d] coupling vertex[%" PetscInt_FMT "]: v %" PetscInt_FMT ", ncomp %" PetscInt_FMT "; nvar %" PetscInt_FMT "\n",rank,v,vtx[v], ncomp,nvar); */
215c4762a1bSJed Brown 
2162bf73ac6SHong Zhang     for (k = 0; k < ncomp; k++) {
2179566063dSJacob Faibussowitsch       PetscCall(DMNetworkGetComponent(networkdm, vtx[v], k, &key, &component, &nvar));
2189566063dSJacob Faibussowitsch       PetscCall(DMNetworkGetGlobalVecOffset(networkdm, vtx[v], k, &goffset[k]));
219c4762a1bSJed Brown 
2202bf73ac6SHong Zhang       /* Verify the coupling vertex is a powernet load vertex or a water vertex */
2212bf73ac6SHong Zhang       switch (k) {
222d71ae5a4SJacob Faibussowitsch       case 0:
223d71ae5a4SJacob Faibussowitsch         PetscCheck(key == appctx_power.compkey_bus && nvar == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "key %" PetscInt_FMT " not a power bus vertex or nvar %" PetscInt_FMT " != 2", key, nvar);
224d71ae5a4SJacob Faibussowitsch         break;
225d71ae5a4SJacob Faibussowitsch       case 1:
226d71ae5a4SJacob Faibussowitsch         PetscCheck(key == appctx_power.compkey_load && nvar == 0 && goffset[1] == goffset[0] + 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Not a power load vertex");
227d71ae5a4SJacob Faibussowitsch         break;
228d71ae5a4SJacob Faibussowitsch       case 2:
229d71ae5a4SJacob Faibussowitsch         PetscCheck(key == appctx_water.compkey_vtx && nvar == 1 && goffset[2] == goffset[1], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Not a water vertex");
230d71ae5a4SJacob Faibussowitsch         break;
231d71ae5a4SJacob Faibussowitsch       default:
232d71ae5a4SJacob Faibussowitsch         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "k %" PetscInt_FMT " is wrong", k);
2332bf73ac6SHong Zhang       }
23463a3b9bcSJacob Faibussowitsch       /* printf("  [%d] coupling vertex[%" PetscInt_FMT "]: key %" PetscInt_FMT "; nvar %" PetscInt_FMT ", goffset %" PetscInt_FMT "\n",rank,v,key,nvar,goffset[k]); */
2352bf73ac6SHong Zhang     }
236c4762a1bSJed Brown 
2372bf73ac6SHong Zhang     /* Get its supporting edges */
2389566063dSJacob Faibussowitsch     PetscCall(DMNetworkGetSupportingEdges(networkdm, vtx[v], &nconnedges, &connedges));
23963a3b9bcSJacob Faibussowitsch     /* printf("\n[%d] coupling vertex: nconnedges %" PetscInt_FMT "\n",rank,nconnedges); */
240c4762a1bSJed Brown     for (k = 0; k < nconnedges; k++) {
241c4762a1bSJed Brown       e = connedges[k];
2429566063dSJacob Faibussowitsch       PetscCall(DMNetworkGetNumComponents(networkdm, e, &ncomp));
24363a3b9bcSJacob Faibussowitsch       /* printf("\n  [%d] connected edge[%" PetscInt_FMT "]=%" PetscInt_FMT " has ncomp %" PetscInt_FMT "\n",rank,k,e,ncomp); */
2449566063dSJacob Faibussowitsch       PetscCall(DMNetworkGetComponent(networkdm, e, 0, &keye, &component, NULL));
245ad540459SPierre Jolivet       if (keye != appctx_water.compkey_edge) PetscCheck(keye == appctx_power.compkey_branch, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Not a power branch");
246c4762a1bSJed Brown     }
247c4762a1bSJed Brown   }
248c4762a1bSJed Brown 
2499566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(networkdm, &localX));
250c4762a1bSJed Brown 
2519566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalBegin(networkdm, localF, ADD_VALUES, F));
2529566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalEnd(networkdm, localF, ADD_VALUES, F));
2539566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(networkdm, &localF));
2542bf73ac6SHong Zhang #if 0
255dd400576SPatrick Sanan   if (rank == 0) printf("F:\n");
2569566063dSJacob Faibussowitsch   PetscCall(VecView(F,PETSC_VIEWER_STDOUT_WORLD));
2572bf73ac6SHong Zhang #endif
2583ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
259c4762a1bSJed Brown }
260c4762a1bSJed Brown 
261d71ae5a4SJacob Faibussowitsch PetscErrorCode SetInitialGuess(DM networkdm, Vec X, void *appctx)
262d71ae5a4SJacob Faibussowitsch {
2632bf73ac6SHong Zhang   PetscInt        nv, ne, i, j, ncomp, offset, key;
264c4762a1bSJed Brown   const PetscInt *vtx, *edges;
265c4762a1bSJed Brown   UserCtx        *user         = (UserCtx *)appctx;
266c4762a1bSJed Brown   Vec             localX       = user->localXold;
267c4762a1bSJed Brown   UserCtx_Power   appctx_power = (*user).appctx_power;
2682bf73ac6SHong Zhang   AppCtx_Water    appctx_water = (*user).appctx_water;
2692bf73ac6SHong Zhang   PetscBool       ghost;
2702bf73ac6SHong Zhang   PetscScalar    *xarr;
2712bf73ac6SHong Zhang   VERTEX_Power    bus;
2722bf73ac6SHong Zhang   VERTEX_Water    vertex;
2732bf73ac6SHong Zhang   void           *component;
2742bf73ac6SHong Zhang   GEN             gen;
275c4762a1bSJed Brown 
276c4762a1bSJed Brown   PetscFunctionBegin;
2779566063dSJacob Faibussowitsch   PetscCall(VecSet(X, 0.0));
2789566063dSJacob Faibussowitsch   PetscCall(VecSet(localX, 0.0));
279c4762a1bSJed Brown 
280c4762a1bSJed Brown   /* Set initial guess for power subnetwork */
2819566063dSJacob Faibussowitsch   PetscCall(DMNetworkGetSubnetwork(networkdm, 0, &nv, &ne, &vtx, &edges));
2829566063dSJacob Faibussowitsch   PetscCall(SetInitialGuess_Power(networkdm, localX, nv, ne, vtx, edges, &appctx_power));
283c4762a1bSJed Brown 
284c4762a1bSJed Brown   /* Set initial guess for water subnetwork */
2859566063dSJacob Faibussowitsch   PetscCall(DMNetworkGetSubnetwork(networkdm, 1, &nv, &ne, &vtx, &edges));
2869566063dSJacob Faibussowitsch   PetscCall(SetInitialGuess_Water(networkdm, localX, nv, ne, vtx, edges, NULL));
287c4762a1bSJed Brown 
2882bf73ac6SHong Zhang   /* Set initial guess at the coupling vertex */
2899566063dSJacob Faibussowitsch   PetscCall(VecGetArray(localX, &xarr));
2909566063dSJacob Faibussowitsch   PetscCall(DMNetworkGetSharedVertices(networkdm, &nv, &vtx));
2912bf73ac6SHong Zhang   for (i = 0; i < nv; i++) {
2929566063dSJacob Faibussowitsch     PetscCall(DMNetworkIsGhostVertex(networkdm, vtx[i], &ghost));
2932bf73ac6SHong Zhang     if (ghost) continue;
2942bf73ac6SHong Zhang 
2959566063dSJacob Faibussowitsch     PetscCall(DMNetworkGetNumComponents(networkdm, vtx[i], &ncomp));
2962bf73ac6SHong Zhang     for (j = 0; j < ncomp; j++) {
2979566063dSJacob Faibussowitsch       PetscCall(DMNetworkGetLocalVecOffset(networkdm, vtx[i], j, &offset));
2989566063dSJacob Faibussowitsch       PetscCall(DMNetworkGetComponent(networkdm, vtx[i], j, &key, (void **)&component, NULL));
2992bf73ac6SHong Zhang       if (key == appctx_power.compkey_bus) {
3002bf73ac6SHong Zhang         bus              = (VERTEX_Power)(component);
3012bf73ac6SHong Zhang         xarr[offset]     = bus->va * PETSC_PI / 180.0;
3022bf73ac6SHong Zhang         xarr[offset + 1] = bus->vm;
3032bf73ac6SHong Zhang       } else if (key == appctx_power.compkey_gen) {
3042bf73ac6SHong Zhang         gen = (GEN)(component);
3052bf73ac6SHong Zhang         if (!gen->status) continue;
3062bf73ac6SHong Zhang         xarr[offset + 1] = gen->vs;
3072bf73ac6SHong Zhang       } else if (key == appctx_water.compkey_vtx) {
3082bf73ac6SHong Zhang         vertex = (VERTEX_Water)(component);
3092bf73ac6SHong Zhang         if (vertex->type == VERTEX_TYPE_JUNCTION) {
3102bf73ac6SHong Zhang           xarr[offset] = 100;
3112bf73ac6SHong Zhang         } else if (vertex->type == VERTEX_TYPE_RESERVOIR) {
3122bf73ac6SHong Zhang           xarr[offset] = vertex->res.head;
3132bf73ac6SHong Zhang         } else {
3142bf73ac6SHong Zhang           xarr[offset] = vertex->tank.initlvl + vertex->tank.elev;
315c4762a1bSJed Brown         }
3162bf73ac6SHong Zhang       }
3172bf73ac6SHong Zhang     }
3182bf73ac6SHong Zhang   }
3199566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(localX, &xarr));
320c4762a1bSJed Brown 
3219566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalBegin(networkdm, localX, ADD_VALUES, X));
3229566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalEnd(networkdm, localX, ADD_VALUES, X));
3233ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
324c4762a1bSJed Brown }
325c4762a1bSJed Brown 
326cc13d412SHong Zhang /* Set coordinates */
3277cd471e7SHong Zhang static PetscErrorCode CoordinateVecSetUp(DM dmcoords, Vec coords)
328cc13d412SHong Zhang {
329cc13d412SHong Zhang   PetscInt        i, gidx, offset, v, nv, Nsubnet;
330cc13d412SHong Zhang   const PetscInt *vtx;
331cc13d412SHong Zhang   PetscScalar    *carray;
3327cd471e7SHong Zhang   PetscReal      *color;
333cc13d412SHong Zhang 
334cc13d412SHong Zhang   PetscFunctionBeginUser;
335cc13d412SHong Zhang   PetscCall(VecGetArrayWrite(coords, &carray));
3367cd471e7SHong Zhang   PetscCall(DMNetworkGetNumSubNetworks(dmcoords, NULL, &Nsubnet));
337cc13d412SHong Zhang   for (i = 0; i < Nsubnet; i++) {
3387cd471e7SHong Zhang     PetscCall(DMNetworkGetSubnetwork(dmcoords, i, &nv, NULL, &vtx, NULL));
339cc13d412SHong Zhang     for (v = 0; v < nv; v++) {
3407cd471e7SHong Zhang       PetscCall(DMNetworkGetGlobalVertexIndex(dmcoords, vtx[v], &gidx));
3417cd471e7SHong Zhang       PetscCall(DMNetworkGetLocalVecOffset(dmcoords, vtx[v], 0, &offset));
3427cd471e7SHong Zhang       PetscCall(DMNetworkGetComponent(dmcoords, vtx[v], 0, NULL, (void **)&color, NULL));
3437cd471e7SHong Zhang       *color = 0.0;
344cc13d412SHong Zhang       switch (gidx) {
345cc13d412SHong Zhang       case 0:
346cc13d412SHong Zhang         carray[offset]     = -1.0;
347cc13d412SHong Zhang         carray[offset + 1] = -1.0;
348cc13d412SHong Zhang         break;
349cc13d412SHong Zhang       case 1:
350cc13d412SHong Zhang         carray[offset]     = -2.0;
351cc13d412SHong Zhang         carray[offset + 1] = 2.0;
352cc13d412SHong Zhang         break;
353cc13d412SHong Zhang       case 2:
354cc13d412SHong Zhang         carray[offset]     = 0.0;
355cc13d412SHong Zhang         carray[offset + 1] = 2.0;
356cc13d412SHong Zhang         break;
357cc13d412SHong Zhang       case 3:
358cc13d412SHong Zhang         carray[offset]     = -1.0;
359cc13d412SHong Zhang         carray[offset + 1] = 0.0;
360cc13d412SHong Zhang         break;
361cc13d412SHong Zhang       case 4:
362cc13d412SHong Zhang         carray[offset]     = 0.0;
363cc13d412SHong Zhang         carray[offset + 1] = 0.0;
364cc13d412SHong Zhang         break;
365cc13d412SHong Zhang       case 5:
366cc13d412SHong Zhang         carray[offset]     = 0.0;
367cc13d412SHong Zhang         carray[offset + 1] = 1.0;
368cc13d412SHong Zhang         break;
369cc13d412SHong Zhang       case 6:
370cc13d412SHong Zhang         carray[offset]     = -1.0;
371cc13d412SHong Zhang         carray[offset + 1] = 1.0;
372cc13d412SHong Zhang         break;
373cc13d412SHong Zhang       case 7:
374cc13d412SHong Zhang         carray[offset]     = -2.0;
375cc13d412SHong Zhang         carray[offset + 1] = 1.0;
376cc13d412SHong Zhang         break;
377cc13d412SHong Zhang       case 8:
378cc13d412SHong Zhang         carray[offset]     = -2.0;
379cc13d412SHong Zhang         carray[offset + 1] = 0.0;
380cc13d412SHong Zhang         break;
381cc13d412SHong Zhang       case 9:
382cc13d412SHong Zhang         carray[offset]     = 1.0;
383cc13d412SHong Zhang         carray[offset + 1] = 0.0;
384cc13d412SHong Zhang         break;
385cc13d412SHong Zhang       case 10:
386cc13d412SHong Zhang         carray[offset]     = 1.0;
387cc13d412SHong Zhang         carray[offset + 1] = -1.0;
388cc13d412SHong Zhang         break;
389cc13d412SHong Zhang       case 11:
390cc13d412SHong Zhang         carray[offset]     = 2.0;
391cc13d412SHong Zhang         carray[offset + 1] = -1.0;
392cc13d412SHong Zhang         break;
393cc13d412SHong Zhang       case 12:
394cc13d412SHong Zhang         carray[offset]     = 2.0;
395cc13d412SHong Zhang         carray[offset + 1] = 0.0;
396cc13d412SHong Zhang         break;
397cc13d412SHong Zhang       case 13:
398cc13d412SHong Zhang         carray[offset]     = 0.0;
399cc13d412SHong Zhang         carray[offset + 1] = -1.0;
400cc13d412SHong Zhang         break;
401cc13d412SHong Zhang       case 14:
402cc13d412SHong Zhang         carray[offset]     = 2.0;
403cc13d412SHong Zhang         carray[offset + 1] = 1.0;
404cc13d412SHong Zhang         break;
405cc13d412SHong Zhang       default:
406cc13d412SHong Zhang         PetscCheck(gidx < 15 && gidx > -1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "gidx %" PetscInt_FMT "must between 0 and 14", gidx);
407cc13d412SHong Zhang       }
408cc13d412SHong Zhang     }
409cc13d412SHong Zhang   }
410cc13d412SHong Zhang   PetscCall(VecRestoreArrayWrite(coords, &carray));
411cc13d412SHong Zhang   PetscFunctionReturn(PETSC_SUCCESS);
412cc13d412SHong Zhang }
413cc13d412SHong Zhang 
414cc13d412SHong Zhang static PetscErrorCode CoordinatePrint(DM dm)
415cc13d412SHong Zhang {
4167cd471e7SHong Zhang   DM                 dmcoords;
417cc13d412SHong Zhang   PetscInt           cdim, v, off, vglobal, vStart, vEnd;
418cc13d412SHong Zhang   const PetscScalar *carray;
419cc13d412SHong Zhang   Vec                coords;
420cc13d412SHong Zhang   MPI_Comm           comm;
421cc13d412SHong Zhang   PetscMPIInt        rank;
422cc13d412SHong Zhang 
423cc13d412SHong Zhang   PetscFunctionBegin;
4247cd471e7SHong Zhang   /* get info from dm */
4257cd471e7SHong Zhang   PetscCall(DMGetCoordinateDim(dm, &cdim));
426cc13d412SHong Zhang   PetscCall(DMGetCoordinatesLocal(dm, &coords));
427cc13d412SHong Zhang 
4287cd471e7SHong Zhang   PetscCall(DMGetCoordinateDM(dm, &dmcoords));
4297cd471e7SHong Zhang   PetscCall(PetscObjectGetComm((PetscObject)dmcoords, &comm));
4307cd471e7SHong Zhang   PetscCallMPI(MPI_Comm_rank(comm, &rank));
431cc13d412SHong Zhang 
4327cd471e7SHong Zhang   /* print coordinates from dmcoords */
433cc13d412SHong Zhang   PetscCall(PetscPrintf(MPI_COMM_WORLD, "\nCoordinatePrint, cdim %" PetscInt_FMT ":\n", cdim));
4347cd471e7SHong Zhang   PetscCall(PetscSynchronizedPrintf(MPI_COMM_WORLD, "[%d]\n", rank));
4357cd471e7SHong Zhang 
4367cd471e7SHong Zhang   PetscCall(DMNetworkGetVertexRange(dmcoords, &vStart, &vEnd));
4377cd471e7SHong Zhang   PetscCall(VecGetArrayRead(coords, &carray));
438cc13d412SHong Zhang   for (v = vStart; v < vEnd; v++) {
4397cd471e7SHong Zhang     PetscCall(DMNetworkGetLocalVecOffset(dmcoords, v, 0, &off));
4407cd471e7SHong Zhang     PetscCall(DMNetworkGetGlobalVertexIndex(dmcoords, v, &vglobal));
441cc13d412SHong Zhang     switch (cdim) {
442cc13d412SHong Zhang     case 2:
443cc13d412SHong Zhang       PetscCall(PetscSynchronizedPrintf(MPI_COMM_WORLD, "Vertex: %" PetscInt_FMT ", x =  %f y = %f \n", vglobal, (double)PetscRealPart(carray[off]), (double)PetscRealPart(carray[off + 1])));
444cc13d412SHong Zhang       break;
445cc13d412SHong Zhang     default:
446cc13d412SHong Zhang       PetscCheck(cdim == 2, MPI_COMM_WORLD, PETSC_ERR_SUP, "Only supports Network embedding dimension of 2, not supplied  %" PetscInt_FMT, cdim);
447cc13d412SHong Zhang       break;
448cc13d412SHong Zhang     }
449cc13d412SHong Zhang   }
450cc13d412SHong Zhang   PetscCall(PetscSynchronizedFlush(MPI_COMM_WORLD, NULL));
451cc13d412SHong Zhang   PetscCall(VecRestoreArrayRead(coords, &carray));
452cc13d412SHong Zhang   PetscFunctionReturn(PETSC_SUCCESS);
453cc13d412SHong Zhang }
454cc13d412SHong Zhang 
455d71ae5a4SJacob Faibussowitsch int main(int argc, char **argv)
456d71ae5a4SJacob Faibussowitsch {
4577cd471e7SHong Zhang   DM                  networkdm, dmcoords;
458d5c9c0c4SHong Zhang   PetscMPIInt         rank, size;
4592bf73ac6SHong Zhang   PetscInt            Nsubnet = 2, numVertices[2], numEdges[2], i, j, nv, ne, it_max = 10;
460cc13d412SHong Zhang   PetscInt            vStart, vEnd, compkey;
461c4762a1bSJed Brown   const PetscInt     *vtx, *edges;
4627cd471e7SHong Zhang   PetscReal          *color;
463cc13d412SHong Zhang   Vec                 X, F, coords;
464c4762a1bSJed Brown   SNES                snes, snes_power, snes_water;
465c4762a1bSJed Brown   Mat                 Jac;
4667cd471e7SHong Zhang   PetscBool           ghost, viewJ = PETSC_FALSE, viewX = PETSC_FALSE, test = PETSC_FALSE, distribute = PETSC_TRUE, flg, printCoord = PETSC_FALSE, viewCSV = PETSC_FALSE, monitorIt = PETSC_FALSE;
467c4762a1bSJed Brown   UserCtx             user;
468c4762a1bSJed Brown   SNESConvergedReason reason;
4694279555eSSatish Balay #if defined(PETSC_USE_LOG)
4704279555eSSatish Balay   PetscLogStage stage[4];
4714279555eSSatish Balay #endif
472c4762a1bSJed Brown 
473c4762a1bSJed Brown   /* Power subnetwork */
474c4762a1bSJed Brown   UserCtx_Power *appctx_power                    = &user.appctx_power;
475c4762a1bSJed Brown   char           pfdata_file[PETSC_MAX_PATH_LEN] = "power/case9.m";
476c4762a1bSJed Brown   PFDATA        *pfdata                          = NULL;
4772bf73ac6SHong Zhang   PetscInt       genj, loadj, *edgelist_power = NULL, power_netnum;
478c4762a1bSJed Brown   PetscScalar    Sbase = 0.0;
479c4762a1bSJed Brown 
480c4762a1bSJed Brown   /* Water subnetwork */
481c4762a1bSJed Brown   AppCtx_Water *appctx_water                       = &user.appctx_water;
482c4762a1bSJed Brown   WATERDATA    *waterdata                          = NULL;
483c4762a1bSJed Brown   char          waterdata_file[PETSC_MAX_PATH_LEN] = "water/sample1.inp";
4842bf73ac6SHong Zhang   PetscInt     *edgelist_water                     = NULL, water_netnum;
485c4762a1bSJed Brown 
4862bf73ac6SHong Zhang   /* Shared vertices between subnetworks */
4872bf73ac6SHong Zhang   PetscInt power_svtx, water_svtx;
488c4762a1bSJed Brown 
489327415f7SBarry Smith   PetscFunctionBeginUser;
4909566063dSJacob Faibussowitsch   PetscCall(PetscInitialize(&argc, &argv, "ex1options", help));
4919566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD, &rank));
4929566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PETSC_COMM_WORLD, &size));
493c4762a1bSJed Brown 
494c4762a1bSJed Brown   /* (1) Read Data - Only rank 0 reads the data */
4959566063dSJacob Faibussowitsch   PetscCall(PetscLogStageRegister("Read Data", &stage[0]));
4969566063dSJacob Faibussowitsch   PetscCall(PetscLogStagePush(stage[0]));
497c4762a1bSJed Brown 
4982bf73ac6SHong Zhang   for (i = 0; i < Nsubnet; i++) {
499c4762a1bSJed Brown     numVertices[i] = 0;
500c4762a1bSJed Brown     numEdges[i]    = 0;
501c4762a1bSJed Brown   }
502c4762a1bSJed Brown 
5032bf73ac6SHong Zhang   /* All processes READ THE DATA FOR THE FIRST SUBNETWORK: Electric Power Grid */
5042bf73ac6SHong Zhang   /* Used for shared vertex, because currently the coupling info must be available in all processes!!! */
5059566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetString(NULL, NULL, "-pfdata", pfdata_file, PETSC_MAX_PATH_LEN - 1, NULL));
5069566063dSJacob Faibussowitsch   PetscCall(PetscNew(&pfdata));
5079566063dSJacob Faibussowitsch   PetscCall(PFReadMatPowerData(pfdata, pfdata_file));
50848a46eb9SPierre Jolivet   if (rank == 0) PetscCall(PetscPrintf(PETSC_COMM_SELF, "Power network: nb = %" PetscInt_FMT ", ngen = %" PetscInt_FMT ", nload = %" PetscInt_FMT ", nbranch = %" PetscInt_FMT "\n", pfdata->nbus, pfdata->ngen, pfdata->nload, pfdata->nbranch));
509c4762a1bSJed Brown   Sbase = pfdata->sbase;
5102bf73ac6SHong Zhang   if (rank == 0) { /* proc[0] will create Electric Power Grid */
511c4762a1bSJed Brown     numEdges[0]    = pfdata->nbranch;
512c4762a1bSJed Brown     numVertices[0] = pfdata->nbus;
513c4762a1bSJed Brown 
5149566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(2 * numEdges[0], &edgelist_power));
5159566063dSJacob Faibussowitsch     PetscCall(GetListofEdges_Power(pfdata, edgelist_power));
516c4762a1bSJed Brown   }
517c4762a1bSJed Brown   /* Broadcast power Sbase to all processors */
5189566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Bcast(&Sbase, 1, MPIU_SCALAR, 0, PETSC_COMM_WORLD));
519c4762a1bSJed Brown   appctx_power->Sbase     = Sbase;
520c4762a1bSJed Brown   appctx_power->jac_error = PETSC_FALSE;
521c4762a1bSJed Brown   /* If external option activated. Introduce error in jacobian */
5229566063dSJacob Faibussowitsch   PetscCall(PetscOptionsHasName(NULL, NULL, "-jac_error", &appctx_power->jac_error));
523c4762a1bSJed Brown 
5242bf73ac6SHong Zhang   /* All processes READ THE DATA FOR THE SECOND SUBNETWORK: Water */
5252bf73ac6SHong Zhang   /* Used for shared vertex, because currently the coupling info must be available in all processes!!! */
5269566063dSJacob Faibussowitsch   PetscCall(PetscNew(&waterdata));
5279566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetString(NULL, NULL, "-waterdata", waterdata_file, PETSC_MAX_PATH_LEN - 1, NULL));
5289566063dSJacob Faibussowitsch   PetscCall(WaterReadData(waterdata, waterdata_file));
5292bf73ac6SHong Zhang   if (size == 1 || (size > 1 && rank == 1)) {
5309566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(2 * waterdata->nedge, &edgelist_water));
5319566063dSJacob Faibussowitsch     PetscCall(GetListofEdges_Water(waterdata, edgelist_water));
532c4762a1bSJed Brown     numEdges[1]    = waterdata->nedge;
533c4762a1bSJed Brown     numVertices[1] = waterdata->nvertex;
534c4762a1bSJed Brown   }
5353ba16761SJacob Faibussowitsch   PetscCall(PetscLogStagePop());
536c4762a1bSJed Brown 
5372bf73ac6SHong Zhang   /* (2) Create a network consist of two subnetworks */
5389566063dSJacob Faibussowitsch   PetscCall(PetscLogStageRegister("Net Setup", &stage[1]));
5399566063dSJacob Faibussowitsch   PetscCall(PetscLogStagePush(stage[1]));
540c4762a1bSJed Brown 
541cc13d412SHong Zhang   PetscCall(PetscOptionsGetBool(NULL, NULL, "-viewCSV", &viewCSV, NULL));
542cc13d412SHong Zhang   PetscCall(PetscOptionsGetBool(NULL, NULL, "-printCoord", &printCoord, NULL));
5439566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(NULL, NULL, "-test", &test, NULL));
5449566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(NULL, NULL, "-distribute", &distribute, NULL));
545c4762a1bSJed Brown 
546c4762a1bSJed Brown   /* Create an empty network object */
5479566063dSJacob Faibussowitsch   PetscCall(DMNetworkCreate(PETSC_COMM_WORLD, &networkdm));
548c4762a1bSJed Brown 
549c4762a1bSJed Brown   /* Register the components in the network */
5509566063dSJacob Faibussowitsch   PetscCall(DMNetworkRegisterComponent(networkdm, "branchstruct", sizeof(struct _p_EDGE_Power), &appctx_power->compkey_branch));
5519566063dSJacob Faibussowitsch   PetscCall(DMNetworkRegisterComponent(networkdm, "busstruct", sizeof(struct _p_VERTEX_Power), &appctx_power->compkey_bus));
5529566063dSJacob Faibussowitsch   PetscCall(DMNetworkRegisterComponent(networkdm, "genstruct", sizeof(struct _p_GEN), &appctx_power->compkey_gen));
5539566063dSJacob Faibussowitsch   PetscCall(DMNetworkRegisterComponent(networkdm, "loadstruct", sizeof(struct _p_LOAD), &appctx_power->compkey_load));
554c4762a1bSJed Brown 
5559566063dSJacob Faibussowitsch   PetscCall(DMNetworkRegisterComponent(networkdm, "edge_water", sizeof(struct _p_EDGE_Water), &appctx_water->compkey_edge));
5569566063dSJacob Faibussowitsch   PetscCall(DMNetworkRegisterComponent(networkdm, "vertex_water", sizeof(struct _p_VERTEX_Water), &appctx_water->compkey_vtx));
557cc13d412SHong Zhang 
55863a3b9bcSJacob Faibussowitsch   PetscCall(PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[%d] Total local nvertices %" PetscInt_FMT " + %" PetscInt_FMT " = %" PetscInt_FMT ", nedges %" PetscInt_FMT " + %" PetscInt_FMT " = %" PetscInt_FMT "\n", rank, numVertices[0], numVertices[1], numVertices[0] + numVertices[1], numEdges[0], numEdges[1], numEdges[0] + numEdges[1]));
5599566063dSJacob Faibussowitsch   PetscCall(PetscSynchronizedFlush(PETSC_COMM_WORLD, PETSC_STDOUT));
560c4762a1bSJed Brown 
5619566063dSJacob Faibussowitsch   PetscCall(DMNetworkSetNumSubNetworks(networkdm, PETSC_DECIDE, Nsubnet));
5629566063dSJacob Faibussowitsch   PetscCall(DMNetworkAddSubnetwork(networkdm, "power", numEdges[0], edgelist_power, &power_netnum));
5639566063dSJacob Faibussowitsch   PetscCall(DMNetworkAddSubnetwork(networkdm, "water", numEdges[1], edgelist_water, &water_netnum));
564c4762a1bSJed Brown 
5652bf73ac6SHong Zhang   /* vertex subnet[0].4 shares with vertex subnet[1].0 */
5669371c9d4SSatish Balay   power_svtx = 4;
5679371c9d4SSatish Balay   water_svtx = 0;
5689566063dSJacob Faibussowitsch   PetscCall(DMNetworkAddSharedVertices(networkdm, power_netnum, water_netnum, 1, &power_svtx, &water_svtx));
569c4762a1bSJed Brown 
570c4762a1bSJed Brown   /* Set up the network layout */
5719566063dSJacob Faibussowitsch   PetscCall(DMNetworkLayoutSetUp(networkdm));
572c4762a1bSJed Brown 
573c4762a1bSJed Brown   /* ADD VARIABLES AND COMPONENTS FOR THE POWER SUBNETWORK */
5749371c9d4SSatish Balay   genj  = 0;
5759371c9d4SSatish Balay   loadj = 0;
5769566063dSJacob Faibussowitsch   PetscCall(DMNetworkGetSubnetwork(networkdm, power_netnum, &nv, &ne, &vtx, &edges));
5772bf73ac6SHong Zhang 
57848a46eb9SPierre Jolivet   for (i = 0; i < ne; i++) PetscCall(DMNetworkAddComponent(networkdm, edges[i], appctx_power->compkey_branch, &pfdata->branch[i], 0));
579c4762a1bSJed Brown 
580c4762a1bSJed Brown   for (i = 0; i < nv; i++) {
5819566063dSJacob Faibussowitsch     PetscCall(DMNetworkIsSharedVertex(networkdm, vtx[i], &flg));
5822bf73ac6SHong Zhang     if (flg) continue;
5832bf73ac6SHong Zhang 
5849566063dSJacob Faibussowitsch     PetscCall(DMNetworkAddComponent(networkdm, vtx[i], appctx_power->compkey_bus, &pfdata->bus[i], 2));
585c4762a1bSJed Brown     if (pfdata->bus[i].ngen) {
58648a46eb9SPierre Jolivet       for (j = 0; j < pfdata->bus[i].ngen; j++) PetscCall(DMNetworkAddComponent(networkdm, vtx[i], appctx_power->compkey_gen, &pfdata->gen[genj++], 0));
587c4762a1bSJed Brown     }
588c4762a1bSJed Brown     if (pfdata->bus[i].nload) {
58948a46eb9SPierre Jolivet       for (j = 0; j < pfdata->bus[i].nload; j++) PetscCall(DMNetworkAddComponent(networkdm, vtx[i], appctx_power->compkey_load, &pfdata->load[loadj++], 0));
590c4762a1bSJed Brown     }
591c4762a1bSJed Brown   }
592c4762a1bSJed Brown 
593c4762a1bSJed Brown   /* ADD VARIABLES AND COMPONENTS FOR THE WATER SUBNETWORK */
5949566063dSJacob Faibussowitsch   PetscCall(DMNetworkGetSubnetwork(networkdm, water_netnum, &nv, &ne, &vtx, &edges));
59548a46eb9SPierre Jolivet   for (i = 0; i < ne; i++) PetscCall(DMNetworkAddComponent(networkdm, edges[i], appctx_water->compkey_edge, &waterdata->edge[i], 0));
596c4762a1bSJed Brown 
597c4762a1bSJed Brown   for (i = 0; i < nv; i++) {
5989566063dSJacob Faibussowitsch     PetscCall(DMNetworkIsSharedVertex(networkdm, vtx[i], &flg));
5992bf73ac6SHong Zhang     if (flg) continue;
6002bf73ac6SHong Zhang 
6019566063dSJacob Faibussowitsch     PetscCall(DMNetworkAddComponent(networkdm, vtx[i], appctx_water->compkey_vtx, &waterdata->vertex[i], 1));
602c4762a1bSJed Brown   }
6032bf73ac6SHong Zhang 
604eac198afSGetnet   /* 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 */
6059566063dSJacob Faibussowitsch   PetscCall(DMNetworkGetSharedVertices(networkdm, &nv, &vtx));
6062bf73ac6SHong Zhang   for (i = 0; i < nv; i++) {
6072bf73ac6SHong Zhang     /* power */
6089566063dSJacob Faibussowitsch     PetscCall(DMNetworkAddComponent(networkdm, vtx[i], appctx_power->compkey_bus, &pfdata->bus[4], 2));
6092bf73ac6SHong Zhang     /* bus[4] is a load, add its component */
6109566063dSJacob Faibussowitsch     PetscCall(DMNetworkAddComponent(networkdm, vtx[i], appctx_power->compkey_load, &pfdata->load[0], 0));
6112bf73ac6SHong Zhang 
6122bf73ac6SHong Zhang     /* water */
6139566063dSJacob Faibussowitsch     PetscCall(DMNetworkAddComponent(networkdm, vtx[i], appctx_water->compkey_vtx, &waterdata->vertex[0], 1));
614c4762a1bSJed Brown   }
615c4762a1bSJed Brown 
616cc13d412SHong Zhang   /* Set coordinates for visualization */
617cc13d412SHong Zhang   PetscCall(DMSetCoordinateDim(networkdm, 2));
6187cd471e7SHong Zhang   PetscCall(DMGetCoordinateDM(networkdm, &dmcoords));
6197cd471e7SHong Zhang   PetscCall(DMNetworkGetVertexRange(dmcoords, &vStart, &vEnd));
620cc13d412SHong Zhang 
6217cd471e7SHong Zhang   PetscCall(PetscCalloc1(vEnd - vStart, &color));
6227cd471e7SHong Zhang   PetscCall(DMNetworkRegisterComponent(dmcoords, "coordinate&color", sizeof(PetscReal), &compkey));
6237cd471e7SHong Zhang   for (i = vStart; i < vEnd; i++) PetscCall(DMNetworkAddComponent(dmcoords, i, compkey, &color[i - vStart], 2));
6247cd471e7SHong Zhang   PetscCall(DMNetworkFinalizeComponents(dmcoords));
6257cd471e7SHong Zhang 
6267cd471e7SHong Zhang   PetscCall(DMCreateLocalVector(dmcoords, &coords));
627cc13d412SHong Zhang   PetscCall(DMSetCoordinatesLocal(networkdm, coords)); /* set/get coords to/from networkdm */
6287cd471e7SHong Zhang   PetscCall(CoordinateVecSetUp(dmcoords, coords));
629cc13d412SHong Zhang   if (printCoord) PetscCall(CoordinatePrint(networkdm));
630cc13d412SHong Zhang 
631c4762a1bSJed Brown   /* Set up DM for use */
6329566063dSJacob Faibussowitsch   PetscCall(DMSetUp(networkdm));
633c4762a1bSJed Brown 
634c4762a1bSJed Brown   /* Free user objects */
6359566063dSJacob Faibussowitsch   PetscCall(PetscFree(edgelist_power));
6369566063dSJacob Faibussowitsch   PetscCall(PetscFree(pfdata->bus));
6379566063dSJacob Faibussowitsch   PetscCall(PetscFree(pfdata->gen));
6389566063dSJacob Faibussowitsch   PetscCall(PetscFree(pfdata->branch));
6399566063dSJacob Faibussowitsch   PetscCall(PetscFree(pfdata->load));
6409566063dSJacob Faibussowitsch   PetscCall(PetscFree(pfdata));
6412bf73ac6SHong Zhang 
6429566063dSJacob Faibussowitsch   PetscCall(PetscFree(edgelist_water));
6439566063dSJacob Faibussowitsch   PetscCall(PetscFree(waterdata->vertex));
6449566063dSJacob Faibussowitsch   PetscCall(PetscFree(waterdata->edge));
6459566063dSJacob Faibussowitsch   PetscCall(PetscFree(waterdata));
646c4762a1bSJed Brown 
647d5c9c0c4SHong Zhang   /* Re-distribute networkdm to multiple processes for better job balance */
648cc13d412SHong Zhang   if (distribute) {
6499566063dSJacob Faibussowitsch     PetscCall(DMNetworkDistribute(&networkdm, 0));
650cc13d412SHong Zhang 
651cc13d412SHong Zhang     if (printCoord) PetscCall(CoordinatePrint(networkdm));
652cc13d412SHong Zhang     if (viewCSV) { /* CSV View of network with coordinates */
653cc13d412SHong Zhang       PetscCall(PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD, PETSC_VIEWER_ASCII_CSV));
6549566063dSJacob Faibussowitsch       PetscCall(DMView(networkdm, PETSC_VIEWER_STDOUT_WORLD));
655cc13d412SHong Zhang       PetscCall(PetscViewerPopFormat(PETSC_VIEWER_STDOUT_WORLD));
656c4762a1bSJed Brown     }
657d5c9c0c4SHong Zhang   }
658cc13d412SHong Zhang   PetscCall(VecDestroy(&coords));
659c4762a1bSJed Brown 
6602bf73ac6SHong Zhang   /* Test DMNetworkGetSubnetwork() and DMNetworkGetSubnetworkSharedVertices() */
661c4762a1bSJed Brown   if (test) {
6622bf73ac6SHong Zhang     PetscInt v, gidx;
6639566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Barrier(PETSC_COMM_WORLD));
6642bf73ac6SHong Zhang     for (i = 0; i < Nsubnet; i++) {
6659566063dSJacob Faibussowitsch       PetscCall(DMNetworkGetSubnetwork(networkdm, i, &nv, &ne, &vtx, &edges));
66663a3b9bcSJacob Faibussowitsch       PetscCall(PetscPrintf(PETSC_COMM_SELF, "[%d] After distribute, subnet[%" PetscInt_FMT "] ne %" PetscInt_FMT ", nv %" PetscInt_FMT "\n", rank, i, ne, nv));
6679566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Barrier(PETSC_COMM_WORLD));
668c4762a1bSJed Brown 
6692bf73ac6SHong Zhang       for (v = 0; v < nv; v++) {
6709566063dSJacob Faibussowitsch         PetscCall(DMNetworkIsGhostVertex(networkdm, vtx[v], &ghost));
6719566063dSJacob Faibussowitsch         PetscCall(DMNetworkGetGlobalVertexIndex(networkdm, vtx[v], &gidx));
67263a3b9bcSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "[%d] subnet[%" PetscInt_FMT "] v %" PetscInt_FMT " %" PetscInt_FMT "; ghost %d\n", rank, i, vtx[v], gidx, ghost));
673c4762a1bSJed Brown       }
6749566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Barrier(PETSC_COMM_WORLD));
675c4762a1bSJed Brown     }
6769566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Barrier(PETSC_COMM_WORLD));
6772bf73ac6SHong Zhang 
6789566063dSJacob Faibussowitsch     PetscCall(DMNetworkGetSharedVertices(networkdm, &nv, &vtx));
67963a3b9bcSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_SELF, "[%d] After distribute, num of shared vertices nsv = %" PetscInt_FMT "\n", rank, nv));
6802bf73ac6SHong Zhang     for (v = 0; v < nv; v++) {
6819566063dSJacob Faibussowitsch       PetscCall(DMNetworkGetGlobalVertexIndex(networkdm, vtx[v], &gidx));
68263a3b9bcSJacob Faibussowitsch       PetscCall(PetscPrintf(PETSC_COMM_SELF, "[%d] sv %" PetscInt_FMT ", gidx=%" PetscInt_FMT "\n", rank, vtx[v], gidx));
6832bf73ac6SHong Zhang     }
6849566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Barrier(PETSC_COMM_WORLD));
685c4762a1bSJed Brown   }
686c4762a1bSJed Brown 
6872bf73ac6SHong Zhang   /* Create solution vector X */
6889566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector(networkdm, &X));
6899566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(X, &F));
6909566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(networkdm, &user.localXold));
6913ba16761SJacob Faibussowitsch   PetscCall(PetscLogStagePop());
692c4762a1bSJed Brown 
693c4762a1bSJed Brown   /* (3) Setup Solvers */
6949566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(NULL, NULL, "-viewJ", &viewJ, NULL));
6959566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(NULL, NULL, "-viewX", &viewX, NULL));
696c4762a1bSJed Brown 
6979566063dSJacob Faibussowitsch   PetscCall(PetscLogStageRegister("SNES Setup", &stage[2]));
6989566063dSJacob Faibussowitsch   PetscCall(PetscLogStagePush(stage[2]));
699c4762a1bSJed Brown 
7009566063dSJacob Faibussowitsch   PetscCall(SetInitialGuess(networkdm, X, &user));
701c4762a1bSJed Brown 
702c4762a1bSJed Brown   /* Create coupled snes */
7039566063dSJacob Faibussowitsch   PetscCall(PetscPrintf(PETSC_COMM_WORLD, "SNES_coupled setup ......\n"));
7042bf73ac6SHong Zhang   user.subsnes_id = Nsubnet;
7059566063dSJacob Faibussowitsch   PetscCall(SNESCreate(PETSC_COMM_WORLD, &snes));
7069566063dSJacob Faibussowitsch   PetscCall(SNESSetDM(snes, networkdm));
7079566063dSJacob Faibussowitsch   PetscCall(SNESSetOptionsPrefix(snes, "coupled_"));
7089566063dSJacob Faibussowitsch   PetscCall(SNESSetFunction(snes, F, FormFunction, &user));
7097cd471e7SHong Zhang   /* set maxit=1 which can be changed via option '-coupled_snes_max_it <>', see ex1options */
7107cd471e7SHong Zhang   PetscCall(SNESSetTolerances(snes, PETSC_DEFAULT, PETSC_DEFAULT, PETSC_DEFAULT, 1, PETSC_DEFAULT));
7119566063dSJacob Faibussowitsch   PetscCall(SNESSetFromOptions(snes));
712c4762a1bSJed Brown 
713c4762a1bSJed Brown   if (viewJ) {
714c4762a1bSJed Brown     /* View Jac structure */
7159566063dSJacob Faibussowitsch     PetscCall(SNESGetJacobian(snes, &Jac, NULL, NULL, NULL));
7169566063dSJacob Faibussowitsch     PetscCall(MatView(Jac, PETSC_VIEWER_DRAW_WORLD));
717c4762a1bSJed Brown   }
718c4762a1bSJed Brown 
719c4762a1bSJed Brown   if (viewX) {
7209566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Solution:\n"));
7219566063dSJacob Faibussowitsch     PetscCall(VecView(X, PETSC_VIEWER_STDOUT_WORLD));
722c4762a1bSJed Brown   }
723c4762a1bSJed Brown 
724c4762a1bSJed Brown   if (viewJ) {
725c4762a1bSJed Brown     /* View assembled Jac */
7269566063dSJacob Faibussowitsch     PetscCall(MatView(Jac, PETSC_VIEWER_DRAW_WORLD));
727c4762a1bSJed Brown   }
728c4762a1bSJed Brown 
729c4762a1bSJed Brown   /* Create snes_power */
7309566063dSJacob Faibussowitsch   PetscCall(PetscPrintf(PETSC_COMM_WORLD, "SNES_power setup ......\n"));
731c4762a1bSJed Brown   user.subsnes_id = 0;
7329566063dSJacob Faibussowitsch   PetscCall(SNESCreate(PETSC_COMM_WORLD, &snes_power));
7339566063dSJacob Faibussowitsch   PetscCall(SNESSetDM(snes_power, networkdm));
7349566063dSJacob Faibussowitsch   PetscCall(SNESSetOptionsPrefix(snes_power, "power_"));
7359566063dSJacob Faibussowitsch   PetscCall(SNESSetFunction(snes_power, F, FormFunction, &user));
7367cd471e7SHong Zhang   /* set maxit=1 which can be changed via option '-power_snes_max_it <>', see ex1options */
7377cd471e7SHong Zhang   PetscCall(SNESSetTolerances(snes_power, PETSC_DEFAULT, PETSC_DEFAULT, PETSC_DEFAULT, 1, PETSC_DEFAULT));
738c4762a1bSJed Brown 
739c4762a1bSJed Brown   /* Use user-provide Jacobian */
7409566063dSJacob Faibussowitsch   PetscCall(DMCreateMatrix(networkdm, &Jac));
7419566063dSJacob Faibussowitsch   PetscCall(SNESSetJacobian(snes_power, Jac, Jac, FormJacobian_subPower, &user));
7429566063dSJacob Faibussowitsch   PetscCall(SNESSetFromOptions(snes_power));
743c4762a1bSJed Brown 
744c4762a1bSJed Brown   if (viewX) {
7459566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Power Solution:\n"));
7469566063dSJacob Faibussowitsch     PetscCall(VecView(X, PETSC_VIEWER_STDOUT_WORLD));
747c4762a1bSJed Brown   }
748c4762a1bSJed Brown   if (viewJ) {
7499566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Power Jac:\n"));
7509566063dSJacob Faibussowitsch     PetscCall(SNESGetJacobian(snes_power, &Jac, NULL, NULL, NULL));
7519566063dSJacob Faibussowitsch     PetscCall(MatView(Jac, PETSC_VIEWER_DRAW_WORLD));
752c4762a1bSJed Brown   }
753c4762a1bSJed Brown 
754c4762a1bSJed Brown   /* Create snes_water */
7559566063dSJacob Faibussowitsch   PetscCall(PetscPrintf(PETSC_COMM_WORLD, "SNES_water setup......\n"));
756c4762a1bSJed Brown 
757c4762a1bSJed Brown   user.subsnes_id = 1;
7589566063dSJacob Faibussowitsch   PetscCall(SNESCreate(PETSC_COMM_WORLD, &snes_water));
7599566063dSJacob Faibussowitsch   PetscCall(SNESSetDM(snes_water, networkdm));
7609566063dSJacob Faibussowitsch   PetscCall(SNESSetOptionsPrefix(snes_water, "water_"));
7619566063dSJacob Faibussowitsch   PetscCall(SNESSetFunction(snes_water, F, FormFunction, &user));
7627cd471e7SHong Zhang   /* set maxit=1 which can be changed via option '-water_snes_max_it <>', see ex1options */
7637cd471e7SHong Zhang   PetscCall(SNESSetTolerances(snes_water, PETSC_DEFAULT, PETSC_DEFAULT, PETSC_DEFAULT, 1, PETSC_DEFAULT));
7649566063dSJacob Faibussowitsch   PetscCall(SNESSetFromOptions(snes_water));
765c4762a1bSJed Brown 
766c4762a1bSJed Brown   if (viewX) {
7679566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Water Solution:\n"));
7689566063dSJacob Faibussowitsch     PetscCall(VecView(X, PETSC_VIEWER_STDOUT_WORLD));
769c4762a1bSJed Brown   }
7707cd471e7SHong Zhang 
7717cd471e7SHong Zhang   /* Monitor snes, snes_power and snes_water iterations */
7727cd471e7SHong Zhang   PetscCall(PetscOptionsGetBool(NULL, NULL, "-monitorIteration", &monitorIt, NULL));
7737cd471e7SHong Zhang   user.monitorColor = PETSC_FALSE;
7747cd471e7SHong Zhang   PetscCall(PetscOptionsGetBool(NULL, NULL, "-monitorColor", &user.monitorColor, NULL));
7757cd471e7SHong Zhang   if (user.monitorColor) monitorIt = PETSC_TRUE; /* require installation of pandas and matplotlib */
7767cd471e7SHong Zhang   if (monitorIt) {
7777cd471e7SHong Zhang     PetscCall(SNESMonitorSet(snes_power, UserMonitor, &user, NULL));
7787cd471e7SHong Zhang     PetscCall(SNESMonitorSet(snes_water, UserMonitor, &user, NULL));
7797cd471e7SHong Zhang     PetscCall(SNESMonitorSet(snes, UserMonitor, &user, NULL));
7807cd471e7SHong Zhang   }
7819566063dSJacob Faibussowitsch   PetscCall(PetscLogStagePop());
782c4762a1bSJed Brown 
7837cd471e7SHong Zhang   /* (4) Solve: we must update user.localXold after each call of SNESSolve().
7847cd471e7SHong Zhang          See "PETSc DMNetwork: A Library for Scalable Network PDE-Based Multiphysics Simulations",
7857cd471e7SHong Zhang          https://dl.acm.org/doi/10.1145/3344587
7867cd471e7SHong Zhang   */
7879566063dSJacob Faibussowitsch   PetscCall(PetscLogStageRegister("SNES Solve", &stage[3]));
7889566063dSJacob Faibussowitsch   PetscCall(PetscLogStagePush(stage[3]));
7897cd471e7SHong Zhang   user.it = 0; /* total_snes_it */
790c4762a1bSJed Brown   reason  = SNES_DIVERGED_DTOL;
791c4762a1bSJed Brown   while (user.it < it_max && (PetscInt)reason < 0) {
792c4762a1bSJed Brown     user.subsnes_id = 0;
7939566063dSJacob Faibussowitsch     PetscCall(SNESSolve(snes_power, NULL, X));
7947cd471e7SHong Zhang     PetscCall(DMGlobalToLocalBegin(networkdm, X, INSERT_VALUES, user.localXold));
7957cd471e7SHong Zhang     PetscCall(DMGlobalToLocalEnd(networkdm, X, INSERT_VALUES, user.localXold));
796c4762a1bSJed Brown 
797c4762a1bSJed Brown     user.subsnes_id = 1;
7989566063dSJacob Faibussowitsch     PetscCall(SNESSolve(snes_water, NULL, X));
7997cd471e7SHong Zhang     PetscCall(DMGlobalToLocalBegin(networkdm, X, INSERT_VALUES, user.localXold));
8007cd471e7SHong Zhang     PetscCall(DMGlobalToLocalEnd(networkdm, X, INSERT_VALUES, user.localXold));
8017cd471e7SHong Zhang 
8022bf73ac6SHong Zhang     user.subsnes_id = Nsubnet;
8039566063dSJacob Faibussowitsch     PetscCall(SNESSolve(snes, NULL, X));
8047cd471e7SHong Zhang     PetscCall(DMGlobalToLocalBegin(networkdm, X, INSERT_VALUES, user.localXold));
8057cd471e7SHong Zhang     PetscCall(DMGlobalToLocalEnd(networkdm, X, INSERT_VALUES, user.localXold));
806c4762a1bSJed Brown 
8079566063dSJacob Faibussowitsch     PetscCall(SNESGetConvergedReason(snes, &reason));
808c4762a1bSJed Brown     user.it++;
809c4762a1bSJed Brown   }
81063a3b9bcSJacob Faibussowitsch   PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Coupled_SNES converged in %" PetscInt_FMT " iterations\n", user.it));
811c4762a1bSJed Brown   if (viewX) {
8129566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Final Solution:\n"));
8139566063dSJacob Faibussowitsch     PetscCall(VecView(X, PETSC_VIEWER_STDOUT_WORLD));
814c4762a1bSJed Brown   }
8159566063dSJacob Faibussowitsch   PetscCall(PetscLogStagePop());
816c4762a1bSJed Brown 
817c4762a1bSJed Brown   /* Free objects */
818c4762a1bSJed Brown   /* -------------*/
8197cd471e7SHong Zhang   PetscCall(PetscFree(color));
8209566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&X));
8219566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&F));
8229566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(networkdm, &user.localXold));
823c4762a1bSJed Brown 
8249566063dSJacob Faibussowitsch   PetscCall(SNESDestroy(&snes));
8259566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Jac));
8269566063dSJacob Faibussowitsch   PetscCall(SNESDestroy(&snes_power));
8279566063dSJacob Faibussowitsch   PetscCall(SNESDestroy(&snes_water));
828c4762a1bSJed Brown 
8299566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&networkdm));
8309566063dSJacob Faibussowitsch   PetscCall(PetscFinalize());
831b122ec5aSJacob Faibussowitsch   return 0;
832c4762a1bSJed Brown }
833c4762a1bSJed Brown 
834c4762a1bSJed Brown /*TEST
835c4762a1bSJed Brown 
836c4762a1bSJed Brown    build:
837dfd57a17SPierre Jolivet      requires: !complex double defined(PETSC_HAVE_ATTRIBUTEALIGNED)
838c4762a1bSJed Brown      depends: power/PFReadData.c power/pffunctions.c water/waterreaddata.c water/waterfunctions.c
839c4762a1bSJed Brown 
840c4762a1bSJed Brown    test:
8417cd471e7SHong Zhang       args: -options_left no -dmnetwork_view -fp_trap 0
842c4762a1bSJed Brown       localrunfiles: ex1options power/case9.m water/sample1.inp
843c4762a1bSJed Brown       output_file: output/ex1.out
844c4762a1bSJed Brown 
845c4762a1bSJed Brown    test:
846c4762a1bSJed Brown       suffix: 2
847c4762a1bSJed Brown       nsize: 3
8487cd471e7SHong Zhang       args: -options_left no -petscpartitioner_type parmetis -fp_trap 0
849c4762a1bSJed Brown       localrunfiles: ex1options power/case9.m water/sample1.inp
850d5c9c0c4SHong Zhang       output_file: output/ex1_2.out
8512bf73ac6SHong Zhang       requires: parmetis
8522bf73ac6SHong Zhang 
853cc13d412SHong Zhang    test:
854cc13d412SHong Zhang       suffix: 3
855cc13d412SHong Zhang       nsize: 3
8567cd471e7SHong Zhang       args: -options_left no -distribute false -fp_trap 0
857cc13d412SHong Zhang       localrunfiles: ex1options power/case9.m water/sample1.inp
858cc13d412SHong Zhang       output_file: output/ex1_2.out
859d5c9c0c4SHong Zhang 
860d5c9c0c4SHong Zhang    test:
8612bf73ac6SHong Zhang       suffix: 4
8622bf73ac6SHong Zhang       nsize: 4
8637cd471e7SHong Zhang       args: -options_left no -petscpartitioner_type simple -dmnetwork_view -dmnetwork_view_distributed -fp_trap 0
864d5c9c0c4SHong Zhang       localrunfiles: ex1options power/case9.m water/sample1.inp
8652bf73ac6SHong Zhang       output_file: output/ex1_4.out
866c4762a1bSJed Brown 
867cc13d412SHong Zhang    test:
868cc13d412SHong Zhang       suffix: 5
8697cd471e7SHong Zhang       args: -options_left no -viewCSV -fp_trap 0
870cc13d412SHong Zhang       localrunfiles: ex1options power/case9.m water/sample1.inp
871cc13d412SHong Zhang       output_file: output/ex1_5.out
872cc13d412SHong Zhang 
873cc13d412SHong Zhang    test:
874cc13d412SHong Zhang       suffix: 6
875cc13d412SHong Zhang       nsize: 3
8767cd471e7SHong Zhang       args: -options_left no -petscpartitioner_type parmetis -dmnetwork_view_distributed draw:null -fp_trap 0
877cc13d412SHong Zhang       localrunfiles: ex1options power/case9.m water/sample1.inp
878cc13d412SHong Zhang       output_file: output/ex1_2.out
879cc13d412SHong Zhang       requires: parmetis
880cc13d412SHong Zhang 
881c4762a1bSJed Brown TEST*/
882