xref: /petsc/src/snes/tutorials/network/ex1.c (revision 7cd471e73bbf44b514919ff6364b3d49ed4f6988)
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*7cd471e7SHong 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
105f25b224SDuncan Campbell */
115f25b224SDuncan Campbell 
12c4762a1bSJed Brown #include "power/power.h"
13c4762a1bSJed Brown #include "water/water.h"
14c4762a1bSJed Brown 
15c4762a1bSJed Brown typedef struct {
16c4762a1bSJed Brown   UserCtx_Power appctx_power;
17c4762a1bSJed Brown   AppCtx_Water  appctx_water;
18c4762a1bSJed Brown   PetscInt      subsnes_id; /* snes solver id */
19c4762a1bSJed Brown   PetscInt      it;         /* iteration number */
20c4762a1bSJed Brown   Vec           localXold;  /* store previous solution, used by FormFunction_Dummy() */
21*7cd471e7SHong Zhang   PetscBool     monitorColor;
22c4762a1bSJed Brown } UserCtx;
23c4762a1bSJed Brown 
24*7cd471e7SHong Zhang /*
25*7cd471e7SHong Zhang   UserMonitor -- called at the end of every SNES iteration via option `-monitorIteration' or `-monitorColor'
26*7cd471e7SHong Zhang */
27d71ae5a4SJacob Faibussowitsch PetscErrorCode UserMonitor(SNES snes, PetscInt its, PetscReal fnorm, void *appctx)
28d71ae5a4SJacob Faibussowitsch {
29c4762a1bSJed Brown   UserCtx    *user = (UserCtx *)appctx;
30c4762a1bSJed Brown   PetscMPIInt rank;
31c4762a1bSJed Brown   MPI_Comm    comm;
32*7cd471e7SHong Zhang   PetscInt    it;
33c4762a1bSJed Brown 
34c4762a1bSJed Brown   PetscFunctionBegin;
359566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)snes, &comm));
369566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
37*7cd471e7SHong Zhang 
38*7cd471e7SHong Zhang   PetscCall(SNESGetIterationNumber(snes, &it));
39dd400576SPatrick Sanan   if (rank == 0) {
40*7cd471e7SHong Zhang     PetscCall(SNESGetIterationNumber(snes, &it));
41*7cd471e7SHong Zhang     if (user->subsnes_id == 0 || user->subsnes_id == 1) {
42*7cd471e7SHong Zhang       PetscCall(PetscPrintf(PETSC_COMM_SELF, " subsnes_id %" PetscInt_FMT ", it %" PetscInt_FMT ", fnorm %g\n", user->subsnes_id, it, (double)fnorm));
43c4762a1bSJed Brown     } else {
44*7cd471e7SHong Zhang       PetscCall(PetscPrintf(PETSC_COMM_SELF, "   coupled_snes_it %" PetscInt_FMT ", total_snes_it %" PetscInt_FMT ", fnorm %g\n", it, user->it, (double)fnorm));
45c4762a1bSJed Brown     }
46c4762a1bSJed Brown   }
47*7cd471e7SHong Zhang 
48*7cd471e7SHong Zhang   if (user->monitorColor) {
49*7cd471e7SHong Zhang     DM           networkdm, dmcoords;
50*7cd471e7SHong Zhang     Vec          F;
51*7cd471e7SHong Zhang     PetscInt     v, vStart, vEnd, offset, gidx, rstart;
52*7cd471e7SHong Zhang     PetscReal   *color;
53*7cd471e7SHong Zhang     PetscScalar *farr;
54*7cd471e7SHong Zhang     PetscBool    ghost;
55*7cd471e7SHong Zhang 
569566063dSJacob Faibussowitsch     PetscCall(SNESGetDM(snes, &networkdm));
57*7cd471e7SHong Zhang     PetscCall(DMGetCoordinateDM(networkdm, &dmcoords));
58*7cd471e7SHong Zhang 
59*7cd471e7SHong Zhang     PetscCall(SNESGetFunction(snes, &F, NULL, NULL));
60*7cd471e7SHong Zhang     PetscCall(VecGetOwnershipRange(F, &rstart, NULL));
61*7cd471e7SHong Zhang 
62*7cd471e7SHong Zhang     PetscCall(VecGetArray(F, &farr));
63*7cd471e7SHong Zhang     PetscCall(DMNetworkGetVertexRange(dmcoords, &vStart, &vEnd));
64*7cd471e7SHong Zhang 
65*7cd471e7SHong Zhang     PetscCall(PetscPrintf(MPI_COMM_WORLD, "\nColorPrint:\n"));
66*7cd471e7SHong Zhang     for (v = vStart; v < vEnd; v++) {
67*7cd471e7SHong Zhang       PetscCall(DMNetworkIsGhostVertex(networkdm, v, &ghost));
68*7cd471e7SHong Zhang       PetscCall(DMNetworkGetComponent(dmcoords, v, 0, NULL, (void **)&color, NULL));
69*7cd471e7SHong Zhang       PetscCall(DMNetworkGetGlobalVertexIndex(networkdm, v, &gidx));
70*7cd471e7SHong Zhang       if (!ghost) {
71*7cd471e7SHong Zhang         PetscCall(DMNetworkGetGlobalVecOffset(networkdm, v, 0, &offset));
72*7cd471e7SHong Zhang         *color = (PetscRealPart(farr[offset - rstart]));
73*7cd471e7SHong Zhang       }
74*7cd471e7SHong Zhang       PetscCall(PetscSynchronizedPrintf(MPI_COMM_WORLD, "[%d] v %" PetscInt_FMT ": color[%" PetscInt_FMT "] = %g\n", rank, gidx, offset - rstart, *color));
75*7cd471e7SHong Zhang     }
76*7cd471e7SHong Zhang     PetscCall(PetscSynchronizedFlush(MPI_COMM_WORLD, NULL));
77*7cd471e7SHong Zhang     PetscCall(VecRestoreArray(F, &farr));
78*7cd471e7SHong Zhang 
79*7cd471e7SHong Zhang     PetscCall(PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD, PETSC_VIEWER_ASCII_CSV));
80*7cd471e7SHong Zhang     PetscCall(DMView(networkdm, PETSC_VIEWER_DRAW_WORLD));
81*7cd471e7SHong Zhang     PetscCall(PetscViewerPopFormat(PETSC_VIEWER_STDOUT_WORLD));
82*7cd471e7SHong Zhang   }
833ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
84c4762a1bSJed Brown }
85c4762a1bSJed Brown 
86d71ae5a4SJacob Faibussowitsch PetscErrorCode FormJacobian_subPower(SNES snes, Vec X, Mat J, Mat Jpre, void *appctx)
87d71ae5a4SJacob Faibussowitsch {
88c4762a1bSJed Brown   DM              networkdm;
89c4762a1bSJed Brown   Vec             localX;
90c4762a1bSJed Brown   PetscInt        nv, ne, i, j, offset, nvar, row;
91c4762a1bSJed Brown   const PetscInt *vtx, *edges;
92c4762a1bSJed Brown   PetscBool       ghostvtex;
93c4762a1bSJed Brown   PetscScalar     one = 1.0;
94c4762a1bSJed Brown   PetscMPIInt     rank;
95c4762a1bSJed Brown   MPI_Comm        comm;
96c4762a1bSJed Brown 
97c4762a1bSJed Brown   PetscFunctionBegin;
989566063dSJacob Faibussowitsch   PetscCall(SNESGetDM(snes, &networkdm));
999566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(networkdm, &localX));
100c4762a1bSJed Brown 
1019566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)networkdm, &comm));
1029566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
103c4762a1bSJed Brown 
1049566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalBegin(networkdm, X, INSERT_VALUES, localX));
1059566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalEnd(networkdm, X, INSERT_VALUES, localX));
106c4762a1bSJed Brown 
1079566063dSJacob Faibussowitsch   PetscCall(MatZeroEntries(J));
108c4762a1bSJed Brown 
109c4762a1bSJed Brown   /* Power subnetwork: copied from power/FormJacobian_Power() */
1109566063dSJacob Faibussowitsch   PetscCall(DMNetworkGetSubnetwork(networkdm, 0, &nv, &ne, &vtx, &edges));
1119566063dSJacob Faibussowitsch   PetscCall(FormJacobian_Power_private(networkdm, localX, J, nv, ne, vtx, edges, appctx));
112c4762a1bSJed Brown 
113c4762a1bSJed Brown   /* Water subnetwork: Identity */
1149566063dSJacob Faibussowitsch   PetscCall(DMNetworkGetSubnetwork(networkdm, 1, &nv, &ne, &vtx, &edges));
115c4762a1bSJed Brown   for (i = 0; i < nv; i++) {
1169566063dSJacob Faibussowitsch     PetscCall(DMNetworkIsGhostVertex(networkdm, vtx[i], &ghostvtex));
117c4762a1bSJed Brown     if (ghostvtex) continue;
118c4762a1bSJed Brown 
1199566063dSJacob Faibussowitsch     PetscCall(DMNetworkGetGlobalVecOffset(networkdm, vtx[i], ALL_COMPONENTS, &offset));
1209566063dSJacob Faibussowitsch     PetscCall(DMNetworkGetComponent(networkdm, vtx[i], ALL_COMPONENTS, NULL, NULL, &nvar));
121c4762a1bSJed Brown     for (j = 0; j < nvar; j++) {
122c4762a1bSJed Brown       row = offset + j;
1239566063dSJacob Faibussowitsch       PetscCall(MatSetValues(J, 1, &row, 1, &row, &one, ADD_VALUES));
124c4762a1bSJed Brown     }
125c4762a1bSJed Brown   }
1269566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(J, MAT_FINAL_ASSEMBLY));
1279566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(J, MAT_FINAL_ASSEMBLY));
128c4762a1bSJed Brown 
1299566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(networkdm, &localX));
1303ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
131c4762a1bSJed Brown }
132c4762a1bSJed Brown 
133c4762a1bSJed Brown /* Dummy equation localF(X) = localX - localXold */
134d71ae5a4SJacob Faibussowitsch PetscErrorCode FormFunction_Dummy(DM networkdm, Vec localX, Vec localF, PetscInt nv, PetscInt ne, const PetscInt *vtx, const PetscInt *edges, void *appctx)
135d71ae5a4SJacob Faibussowitsch {
136c4762a1bSJed Brown   const PetscScalar *xarr, *xoldarr;
137c4762a1bSJed Brown   PetscScalar       *farr;
138c4762a1bSJed Brown   PetscInt           i, j, offset, nvar;
139c4762a1bSJed Brown   PetscBool          ghostvtex;
140c4762a1bSJed Brown   UserCtx           *user      = (UserCtx *)appctx;
141c4762a1bSJed Brown   Vec                localXold = user->localXold;
142c4762a1bSJed Brown 
143c4762a1bSJed Brown   PetscFunctionBegin;
1449566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(localX, &xarr));
1459566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(localXold, &xoldarr));
1469566063dSJacob Faibussowitsch   PetscCall(VecGetArray(localF, &farr));
147c4762a1bSJed Brown 
148c4762a1bSJed Brown   for (i = 0; i < nv; i++) {
1499566063dSJacob Faibussowitsch     PetscCall(DMNetworkIsGhostVertex(networkdm, vtx[i], &ghostvtex));
150c4762a1bSJed Brown     if (ghostvtex) continue;
151c4762a1bSJed Brown 
1529566063dSJacob Faibussowitsch     PetscCall(DMNetworkGetLocalVecOffset(networkdm, vtx[i], ALL_COMPONENTS, &offset));
1539566063dSJacob Faibussowitsch     PetscCall(DMNetworkGetComponent(networkdm, vtx[i], ALL_COMPONENTS, NULL, NULL, &nvar));
154ad540459SPierre Jolivet     for (j = 0; j < nvar; j++) farr[offset + j] = xarr[offset + j] - xoldarr[offset + j];
155c4762a1bSJed Brown   }
156c4762a1bSJed Brown 
1579566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(localX, &xarr));
1589566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(localXold, &xoldarr));
1599566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(localF, &farr));
1603ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
161c4762a1bSJed Brown }
162c4762a1bSJed Brown 
163d71ae5a4SJacob Faibussowitsch PetscErrorCode FormFunction(SNES snes, Vec X, Vec F, void *appctx)
164d71ae5a4SJacob Faibussowitsch {
165c4762a1bSJed Brown   DM              networkdm;
166c4762a1bSJed Brown   Vec             localX, localF;
1672bf73ac6SHong Zhang   PetscInt        nv, ne, v;
168c4762a1bSJed Brown   const PetscInt *vtx, *edges;
169c4762a1bSJed Brown   PetscMPIInt     rank;
170c4762a1bSJed Brown   MPI_Comm        comm;
171c4762a1bSJed Brown   UserCtx        *user         = (UserCtx *)appctx;
172c4762a1bSJed Brown   UserCtx_Power   appctx_power = (*user).appctx_power;
1732bf73ac6SHong Zhang   AppCtx_Water    appctx_water = (*user).appctx_water;
174c4762a1bSJed Brown 
175c4762a1bSJed Brown   PetscFunctionBegin;
1769566063dSJacob Faibussowitsch   PetscCall(SNESGetDM(snes, &networkdm));
1779566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)networkdm, &comm));
1789566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
179c4762a1bSJed Brown 
1809566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(networkdm, &localX));
1819566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(networkdm, &localF));
1829566063dSJacob Faibussowitsch   PetscCall(VecSet(F, 0.0));
1839566063dSJacob Faibussowitsch   PetscCall(VecSet(localF, 0.0));
184c4762a1bSJed Brown 
1859566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalBegin(networkdm, X, INSERT_VALUES, localX));
1869566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalEnd(networkdm, X, INSERT_VALUES, localX));
187c4762a1bSJed Brown 
188c4762a1bSJed Brown   /* Form Function for power subnetwork */
1899566063dSJacob Faibussowitsch   PetscCall(DMNetworkGetSubnetwork(networkdm, 0, &nv, &ne, &vtx, &edges));
190c4762a1bSJed Brown   if (user->subsnes_id == 1) { /* snes_water only */
1919566063dSJacob Faibussowitsch     PetscCall(FormFunction_Dummy(networkdm, localX, localF, nv, ne, vtx, edges, user));
192c4762a1bSJed Brown   } else {
1939566063dSJacob Faibussowitsch     PetscCall(FormFunction_Power(networkdm, localX, localF, nv, ne, vtx, edges, &appctx_power));
194c4762a1bSJed Brown   }
195c4762a1bSJed Brown 
196c4762a1bSJed Brown   /* Form Function for water subnetwork */
1979566063dSJacob Faibussowitsch   PetscCall(DMNetworkGetSubnetwork(networkdm, 1, &nv, &ne, &vtx, &edges));
198c4762a1bSJed Brown   if (user->subsnes_id == 0) { /* snes_power only */
1999566063dSJacob Faibussowitsch     PetscCall(FormFunction_Dummy(networkdm, localX, localF, nv, ne, vtx, edges, user));
200c4762a1bSJed Brown   } else {
2019566063dSJacob Faibussowitsch     PetscCall(FormFunction_Water(networkdm, localX, localF, nv, ne, vtx, edges, NULL));
202c4762a1bSJed Brown   }
203c4762a1bSJed Brown 
2042bf73ac6SHong Zhang   /* Illustrate how to access the coupling vertex of the subnetworks without doing anything to F yet */
2059566063dSJacob Faibussowitsch   PetscCall(DMNetworkGetSharedVertices(networkdm, &nv, &vtx));
2062bf73ac6SHong Zhang   for (v = 0; v < nv; v++) {
2072bf73ac6SHong Zhang     PetscInt        key, ncomp, nvar, nconnedges, k, e, keye, goffset[3];
208c4762a1bSJed Brown     void           *component;
2092bf73ac6SHong Zhang     const PetscInt *connedges;
210c4762a1bSJed Brown 
2119566063dSJacob Faibussowitsch     PetscCall(DMNetworkGetComponent(networkdm, vtx[v], ALL_COMPONENTS, NULL, NULL, &nvar));
2129566063dSJacob Faibussowitsch     PetscCall(DMNetworkGetNumComponents(networkdm, vtx[v], &ncomp));
21363a3b9bcSJacob Faibussowitsch     /* printf("  [%d] coupling vertex[%" PetscInt_FMT "]: v %" PetscInt_FMT ", ncomp %" PetscInt_FMT "; nvar %" PetscInt_FMT "\n",rank,v,vtx[v], ncomp,nvar); */
214c4762a1bSJed Brown 
2152bf73ac6SHong Zhang     for (k = 0; k < ncomp; k++) {
2169566063dSJacob Faibussowitsch       PetscCall(DMNetworkGetComponent(networkdm, vtx[v], k, &key, &component, &nvar));
2179566063dSJacob Faibussowitsch       PetscCall(DMNetworkGetGlobalVecOffset(networkdm, vtx[v], k, &goffset[k]));
218c4762a1bSJed Brown 
2192bf73ac6SHong Zhang       /* Verify the coupling vertex is a powernet load vertex or a water vertex */
2202bf73ac6SHong Zhang       switch (k) {
221d71ae5a4SJacob Faibussowitsch       case 0:
222d71ae5a4SJacob 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);
223d71ae5a4SJacob Faibussowitsch         break;
224d71ae5a4SJacob Faibussowitsch       case 1:
225d71ae5a4SJacob 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");
226d71ae5a4SJacob Faibussowitsch         break;
227d71ae5a4SJacob Faibussowitsch       case 2:
228d71ae5a4SJacob Faibussowitsch         PetscCheck(key == appctx_water.compkey_vtx && nvar == 1 && goffset[2] == goffset[1], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Not a water vertex");
229d71ae5a4SJacob Faibussowitsch         break;
230d71ae5a4SJacob Faibussowitsch       default:
231d71ae5a4SJacob Faibussowitsch         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "k %" PetscInt_FMT " is wrong", k);
2322bf73ac6SHong Zhang       }
23363a3b9bcSJacob Faibussowitsch       /* printf("  [%d] coupling vertex[%" PetscInt_FMT "]: key %" PetscInt_FMT "; nvar %" PetscInt_FMT ", goffset %" PetscInt_FMT "\n",rank,v,key,nvar,goffset[k]); */
2342bf73ac6SHong Zhang     }
235c4762a1bSJed Brown 
2362bf73ac6SHong Zhang     /* Get its supporting edges */
2379566063dSJacob Faibussowitsch     PetscCall(DMNetworkGetSupportingEdges(networkdm, vtx[v], &nconnedges, &connedges));
23863a3b9bcSJacob Faibussowitsch     /* printf("\n[%d] coupling vertex: nconnedges %" PetscInt_FMT "\n",rank,nconnedges); */
239c4762a1bSJed Brown     for (k = 0; k < nconnedges; k++) {
240c4762a1bSJed Brown       e = connedges[k];
2419566063dSJacob Faibussowitsch       PetscCall(DMNetworkGetNumComponents(networkdm, e, &ncomp));
24263a3b9bcSJacob Faibussowitsch       /* printf("\n  [%d] connected edge[%" PetscInt_FMT "]=%" PetscInt_FMT " has ncomp %" PetscInt_FMT "\n",rank,k,e,ncomp); */
2439566063dSJacob Faibussowitsch       PetscCall(DMNetworkGetComponent(networkdm, e, 0, &keye, &component, NULL));
244ad540459SPierre Jolivet       if (keye != appctx_water.compkey_edge) PetscCheck(keye == appctx_power.compkey_branch, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Not a power branch");
245c4762a1bSJed Brown     }
246c4762a1bSJed Brown   }
247c4762a1bSJed Brown 
2489566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(networkdm, &localX));
249c4762a1bSJed Brown 
2509566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalBegin(networkdm, localF, ADD_VALUES, F));
2519566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalEnd(networkdm, localF, ADD_VALUES, F));
2529566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(networkdm, &localF));
2532bf73ac6SHong Zhang #if 0
254dd400576SPatrick Sanan   if (rank == 0) printf("F:\n");
2559566063dSJacob Faibussowitsch   PetscCall(VecView(F,PETSC_VIEWER_STDOUT_WORLD));
2562bf73ac6SHong Zhang #endif
2573ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
258c4762a1bSJed Brown }
259c4762a1bSJed Brown 
260d71ae5a4SJacob Faibussowitsch PetscErrorCode SetInitialGuess(DM networkdm, Vec X, void *appctx)
261d71ae5a4SJacob Faibussowitsch {
2622bf73ac6SHong Zhang   PetscInt        nv, ne, i, j, ncomp, offset, key;
263c4762a1bSJed Brown   const PetscInt *vtx, *edges;
264c4762a1bSJed Brown   UserCtx        *user         = (UserCtx *)appctx;
265c4762a1bSJed Brown   Vec             localX       = user->localXold;
266c4762a1bSJed Brown   UserCtx_Power   appctx_power = (*user).appctx_power;
2672bf73ac6SHong Zhang   AppCtx_Water    appctx_water = (*user).appctx_water;
2682bf73ac6SHong Zhang   PetscBool       ghost;
2692bf73ac6SHong Zhang   PetscScalar    *xarr;
2702bf73ac6SHong Zhang   VERTEX_Power    bus;
2712bf73ac6SHong Zhang   VERTEX_Water    vertex;
2722bf73ac6SHong Zhang   void           *component;
2732bf73ac6SHong Zhang   GEN             gen;
274c4762a1bSJed Brown 
275c4762a1bSJed Brown   PetscFunctionBegin;
2769566063dSJacob Faibussowitsch   PetscCall(VecSet(X, 0.0));
2779566063dSJacob Faibussowitsch   PetscCall(VecSet(localX, 0.0));
278c4762a1bSJed Brown 
279c4762a1bSJed Brown   /* Set initial guess for power subnetwork */
2809566063dSJacob Faibussowitsch   PetscCall(DMNetworkGetSubnetwork(networkdm, 0, &nv, &ne, &vtx, &edges));
2819566063dSJacob Faibussowitsch   PetscCall(SetInitialGuess_Power(networkdm, localX, nv, ne, vtx, edges, &appctx_power));
282c4762a1bSJed Brown 
283c4762a1bSJed Brown   /* Set initial guess for water subnetwork */
2849566063dSJacob Faibussowitsch   PetscCall(DMNetworkGetSubnetwork(networkdm, 1, &nv, &ne, &vtx, &edges));
2859566063dSJacob Faibussowitsch   PetscCall(SetInitialGuess_Water(networkdm, localX, nv, ne, vtx, edges, NULL));
286c4762a1bSJed Brown 
2872bf73ac6SHong Zhang   /* Set initial guess at the coupling vertex */
2889566063dSJacob Faibussowitsch   PetscCall(VecGetArray(localX, &xarr));
2899566063dSJacob Faibussowitsch   PetscCall(DMNetworkGetSharedVertices(networkdm, &nv, &vtx));
2902bf73ac6SHong Zhang   for (i = 0; i < nv; i++) {
2919566063dSJacob Faibussowitsch     PetscCall(DMNetworkIsGhostVertex(networkdm, vtx[i], &ghost));
2922bf73ac6SHong Zhang     if (ghost) continue;
2932bf73ac6SHong Zhang 
2949566063dSJacob Faibussowitsch     PetscCall(DMNetworkGetNumComponents(networkdm, vtx[i], &ncomp));
2952bf73ac6SHong Zhang     for (j = 0; j < ncomp; j++) {
2969566063dSJacob Faibussowitsch       PetscCall(DMNetworkGetLocalVecOffset(networkdm, vtx[i], j, &offset));
2979566063dSJacob Faibussowitsch       PetscCall(DMNetworkGetComponent(networkdm, vtx[i], j, &key, (void **)&component, NULL));
2982bf73ac6SHong Zhang       if (key == appctx_power.compkey_bus) {
2992bf73ac6SHong Zhang         bus              = (VERTEX_Power)(component);
3002bf73ac6SHong Zhang         xarr[offset]     = bus->va * PETSC_PI / 180.0;
3012bf73ac6SHong Zhang         xarr[offset + 1] = bus->vm;
3022bf73ac6SHong Zhang       } else if (key == appctx_power.compkey_gen) {
3032bf73ac6SHong Zhang         gen = (GEN)(component);
3042bf73ac6SHong Zhang         if (!gen->status) continue;
3052bf73ac6SHong Zhang         xarr[offset + 1] = gen->vs;
3062bf73ac6SHong Zhang       } else if (key == appctx_water.compkey_vtx) {
3072bf73ac6SHong Zhang         vertex = (VERTEX_Water)(component);
3082bf73ac6SHong Zhang         if (vertex->type == VERTEX_TYPE_JUNCTION) {
3092bf73ac6SHong Zhang           xarr[offset] = 100;
3102bf73ac6SHong Zhang         } else if (vertex->type == VERTEX_TYPE_RESERVOIR) {
3112bf73ac6SHong Zhang           xarr[offset] = vertex->res.head;
3122bf73ac6SHong Zhang         } else {
3132bf73ac6SHong Zhang           xarr[offset] = vertex->tank.initlvl + vertex->tank.elev;
314c4762a1bSJed Brown         }
3152bf73ac6SHong Zhang       }
3162bf73ac6SHong Zhang     }
3172bf73ac6SHong Zhang   }
3189566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(localX, &xarr));
319c4762a1bSJed Brown 
3209566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalBegin(networkdm, localX, ADD_VALUES, X));
3219566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalEnd(networkdm, localX, ADD_VALUES, X));
3223ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
323c4762a1bSJed Brown }
324c4762a1bSJed Brown 
325cc13d412SHong Zhang /* Set coordinates */
326*7cd471e7SHong Zhang static PetscErrorCode CoordinateVecSetUp(DM dmcoords, Vec coords)
327cc13d412SHong Zhang {
328cc13d412SHong Zhang   PetscInt        i, gidx, offset, v, nv, Nsubnet;
329cc13d412SHong Zhang   const PetscInt *vtx;
330cc13d412SHong Zhang   PetscScalar    *carray;
331*7cd471e7SHong Zhang   PetscReal      *color;
332cc13d412SHong Zhang 
333cc13d412SHong Zhang   PetscFunctionBeginUser;
334cc13d412SHong Zhang   PetscCall(VecGetArrayWrite(coords, &carray));
335*7cd471e7SHong Zhang   PetscCall(DMNetworkGetNumSubNetworks(dmcoords, NULL, &Nsubnet));
336cc13d412SHong Zhang   for (i = 0; i < Nsubnet; i++) {
337*7cd471e7SHong Zhang     PetscCall(DMNetworkGetSubnetwork(dmcoords, i, &nv, NULL, &vtx, NULL));
338cc13d412SHong Zhang     for (v = 0; v < nv; v++) {
339*7cd471e7SHong Zhang       PetscCall(DMNetworkGetGlobalVertexIndex(dmcoords, vtx[v], &gidx));
340*7cd471e7SHong Zhang       PetscCall(DMNetworkGetLocalVecOffset(dmcoords, vtx[v], 0, &offset));
341*7cd471e7SHong Zhang       PetscCall(DMNetworkGetComponent(dmcoords, vtx[v], 0, NULL, (void **)&color, NULL));
342*7cd471e7SHong Zhang       *color = 0.0;
343cc13d412SHong Zhang       switch (gidx) {
344cc13d412SHong Zhang       case 0:
345cc13d412SHong Zhang         carray[offset]     = -1.0;
346cc13d412SHong Zhang         carray[offset + 1] = -1.0;
347cc13d412SHong Zhang         break;
348cc13d412SHong Zhang       case 1:
349cc13d412SHong Zhang         carray[offset]     = -2.0;
350cc13d412SHong Zhang         carray[offset + 1] = 2.0;
351cc13d412SHong Zhang         break;
352cc13d412SHong Zhang       case 2:
353cc13d412SHong Zhang         carray[offset]     = 0.0;
354cc13d412SHong Zhang         carray[offset + 1] = 2.0;
355cc13d412SHong Zhang         break;
356cc13d412SHong Zhang       case 3:
357cc13d412SHong Zhang         carray[offset]     = -1.0;
358cc13d412SHong Zhang         carray[offset + 1] = 0.0;
359cc13d412SHong Zhang         break;
360cc13d412SHong Zhang       case 4:
361cc13d412SHong Zhang         carray[offset]     = 0.0;
362cc13d412SHong Zhang         carray[offset + 1] = 0.0;
363cc13d412SHong Zhang         break;
364cc13d412SHong Zhang       case 5:
365cc13d412SHong Zhang         carray[offset]     = 0.0;
366cc13d412SHong Zhang         carray[offset + 1] = 1.0;
367cc13d412SHong Zhang         break;
368cc13d412SHong Zhang       case 6:
369cc13d412SHong Zhang         carray[offset]     = -1.0;
370cc13d412SHong Zhang         carray[offset + 1] = 1.0;
371cc13d412SHong Zhang         break;
372cc13d412SHong Zhang       case 7:
373cc13d412SHong Zhang         carray[offset]     = -2.0;
374cc13d412SHong Zhang         carray[offset + 1] = 1.0;
375cc13d412SHong Zhang         break;
376cc13d412SHong Zhang       case 8:
377cc13d412SHong Zhang         carray[offset]     = -2.0;
378cc13d412SHong Zhang         carray[offset + 1] = 0.0;
379cc13d412SHong Zhang         break;
380cc13d412SHong Zhang       case 9:
381cc13d412SHong Zhang         carray[offset]     = 1.0;
382cc13d412SHong Zhang         carray[offset + 1] = 0.0;
383cc13d412SHong Zhang         break;
384cc13d412SHong Zhang       case 10:
385cc13d412SHong Zhang         carray[offset]     = 1.0;
386cc13d412SHong Zhang         carray[offset + 1] = -1.0;
387cc13d412SHong Zhang         break;
388cc13d412SHong Zhang       case 11:
389cc13d412SHong Zhang         carray[offset]     = 2.0;
390cc13d412SHong Zhang         carray[offset + 1] = -1.0;
391cc13d412SHong Zhang         break;
392cc13d412SHong Zhang       case 12:
393cc13d412SHong Zhang         carray[offset]     = 2.0;
394cc13d412SHong Zhang         carray[offset + 1] = 0.0;
395cc13d412SHong Zhang         break;
396cc13d412SHong Zhang       case 13:
397cc13d412SHong Zhang         carray[offset]     = 0.0;
398cc13d412SHong Zhang         carray[offset + 1] = -1.0;
399cc13d412SHong Zhang         break;
400cc13d412SHong Zhang       case 14:
401cc13d412SHong Zhang         carray[offset]     = 2.0;
402cc13d412SHong Zhang         carray[offset + 1] = 1.0;
403cc13d412SHong Zhang         break;
404cc13d412SHong Zhang       default:
405cc13d412SHong Zhang         PetscCheck(gidx < 15 && gidx > -1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "gidx %" PetscInt_FMT "must between 0 and 14", gidx);
406cc13d412SHong Zhang       }
407cc13d412SHong Zhang     }
408cc13d412SHong Zhang   }
409cc13d412SHong Zhang   PetscCall(VecRestoreArrayWrite(coords, &carray));
410cc13d412SHong Zhang   PetscFunctionReturn(PETSC_SUCCESS);
411cc13d412SHong Zhang }
412cc13d412SHong Zhang 
413cc13d412SHong Zhang static PetscErrorCode CoordinatePrint(DM dm)
414cc13d412SHong Zhang {
415*7cd471e7SHong Zhang   DM                 dmcoords;
416cc13d412SHong Zhang   PetscInt           cdim, v, off, vglobal, vStart, vEnd;
417cc13d412SHong Zhang   const PetscScalar *carray;
418cc13d412SHong Zhang   Vec                coords;
419cc13d412SHong Zhang   MPI_Comm           comm;
420cc13d412SHong Zhang   PetscMPIInt        rank;
421cc13d412SHong Zhang 
422cc13d412SHong Zhang   PetscFunctionBegin;
423*7cd471e7SHong Zhang   /* get info from dm */
424*7cd471e7SHong Zhang   PetscCall(DMGetCoordinateDim(dm, &cdim));
425cc13d412SHong Zhang   PetscCall(DMGetCoordinatesLocal(dm, &coords));
426cc13d412SHong Zhang 
427*7cd471e7SHong Zhang   PetscCall(DMGetCoordinateDM(dm, &dmcoords));
428*7cd471e7SHong Zhang   PetscCall(PetscObjectGetComm((PetscObject)dmcoords, &comm));
429*7cd471e7SHong Zhang   PetscCallMPI(MPI_Comm_rank(comm, &rank));
430cc13d412SHong Zhang 
431*7cd471e7SHong Zhang   /* print coordinates from dmcoords */
432cc13d412SHong Zhang   PetscCall(PetscPrintf(MPI_COMM_WORLD, "\nCoordinatePrint, cdim %" PetscInt_FMT ":\n", cdim));
433*7cd471e7SHong Zhang   PetscCall(PetscSynchronizedPrintf(MPI_COMM_WORLD, "[%d]\n", rank));
434*7cd471e7SHong Zhang 
435*7cd471e7SHong Zhang   PetscCall(DMNetworkGetVertexRange(dmcoords, &vStart, &vEnd));
436*7cd471e7SHong Zhang   PetscCall(VecGetArrayRead(coords, &carray));
437cc13d412SHong Zhang   for (v = vStart; v < vEnd; v++) {
438*7cd471e7SHong Zhang     PetscCall(DMNetworkGetLocalVecOffset(dmcoords, v, 0, &off));
439*7cd471e7SHong Zhang     PetscCall(DMNetworkGetGlobalVertexIndex(dmcoords, v, &vglobal));
440cc13d412SHong Zhang     switch (cdim) {
441cc13d412SHong Zhang     case 2:
442cc13d412SHong Zhang       PetscCall(PetscSynchronizedPrintf(MPI_COMM_WORLD, "Vertex: %" PetscInt_FMT ", x =  %f y = %f \n", vglobal, (double)PetscRealPart(carray[off]), (double)PetscRealPart(carray[off + 1])));
443cc13d412SHong Zhang       break;
444cc13d412SHong Zhang     default:
445cc13d412SHong Zhang       PetscCheck(cdim == 2, MPI_COMM_WORLD, PETSC_ERR_SUP, "Only supports Network embedding dimension of 2, not supplied  %" PetscInt_FMT, cdim);
446cc13d412SHong Zhang       break;
447cc13d412SHong Zhang     }
448cc13d412SHong Zhang   }
449cc13d412SHong Zhang   PetscCall(PetscSynchronizedFlush(MPI_COMM_WORLD, NULL));
450cc13d412SHong Zhang   PetscCall(VecRestoreArrayRead(coords, &carray));
451cc13d412SHong Zhang   PetscFunctionReturn(PETSC_SUCCESS);
452cc13d412SHong Zhang }
453cc13d412SHong Zhang 
454d71ae5a4SJacob Faibussowitsch int main(int argc, char **argv)
455d71ae5a4SJacob Faibussowitsch {
456*7cd471e7SHong Zhang   DM                  networkdm, dmcoords;
457d5c9c0c4SHong Zhang   PetscMPIInt         rank, size;
4582bf73ac6SHong Zhang   PetscInt            Nsubnet = 2, numVertices[2], numEdges[2], i, j, nv, ne, it_max = 10;
459cc13d412SHong Zhang   PetscInt            vStart, vEnd, compkey;
460c4762a1bSJed Brown   const PetscInt     *vtx, *edges;
461*7cd471e7SHong Zhang   PetscReal          *color;
462cc13d412SHong Zhang   Vec                 X, F, coords;
463c4762a1bSJed Brown   SNES                snes, snes_power, snes_water;
464c4762a1bSJed Brown   Mat                 Jac;
465*7cd471e7SHong 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;
466c4762a1bSJed Brown   UserCtx             user;
467c4762a1bSJed Brown   SNESConvergedReason reason;
4684279555eSSatish Balay #if defined(PETSC_USE_LOG)
4694279555eSSatish Balay   PetscLogStage stage[4];
4704279555eSSatish Balay #endif
471c4762a1bSJed Brown 
472c4762a1bSJed Brown   /* Power subnetwork */
473c4762a1bSJed Brown   UserCtx_Power *appctx_power                    = &user.appctx_power;
474c4762a1bSJed Brown   char           pfdata_file[PETSC_MAX_PATH_LEN] = "power/case9.m";
475c4762a1bSJed Brown   PFDATA        *pfdata                          = NULL;
4762bf73ac6SHong Zhang   PetscInt       genj, loadj, *edgelist_power = NULL, power_netnum;
477c4762a1bSJed Brown   PetscScalar    Sbase = 0.0;
478c4762a1bSJed Brown 
479c4762a1bSJed Brown   /* Water subnetwork */
480c4762a1bSJed Brown   AppCtx_Water *appctx_water                       = &user.appctx_water;
481c4762a1bSJed Brown   WATERDATA    *waterdata                          = NULL;
482c4762a1bSJed Brown   char          waterdata_file[PETSC_MAX_PATH_LEN] = "water/sample1.inp";
4832bf73ac6SHong Zhang   PetscInt     *edgelist_water                     = NULL, water_netnum;
484c4762a1bSJed Brown 
4852bf73ac6SHong Zhang   /* Shared vertices between subnetworks */
4862bf73ac6SHong Zhang   PetscInt power_svtx, water_svtx;
487c4762a1bSJed Brown 
488327415f7SBarry Smith   PetscFunctionBeginUser;
4899566063dSJacob Faibussowitsch   PetscCall(PetscInitialize(&argc, &argv, "ex1options", help));
4909566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD, &rank));
4919566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PETSC_COMM_WORLD, &size));
492c4762a1bSJed Brown 
493c4762a1bSJed Brown   /* (1) Read Data - Only rank 0 reads the data */
4949566063dSJacob Faibussowitsch   PetscCall(PetscLogStageRegister("Read Data", &stage[0]));
4959566063dSJacob Faibussowitsch   PetscCall(PetscLogStagePush(stage[0]));
496c4762a1bSJed Brown 
4972bf73ac6SHong Zhang   for (i = 0; i < Nsubnet; i++) {
498c4762a1bSJed Brown     numVertices[i] = 0;
499c4762a1bSJed Brown     numEdges[i]    = 0;
500c4762a1bSJed Brown   }
501c4762a1bSJed Brown 
5022bf73ac6SHong Zhang   /* All processes READ THE DATA FOR THE FIRST SUBNETWORK: Electric Power Grid */
5032bf73ac6SHong Zhang   /* Used for shared vertex, because currently the coupling info must be available in all processes!!! */
5049566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetString(NULL, NULL, "-pfdata", pfdata_file, PETSC_MAX_PATH_LEN - 1, NULL));
5059566063dSJacob Faibussowitsch   PetscCall(PetscNew(&pfdata));
5069566063dSJacob Faibussowitsch   PetscCall(PFReadMatPowerData(pfdata, pfdata_file));
50748a46eb9SPierre 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));
508c4762a1bSJed Brown   Sbase = pfdata->sbase;
5092bf73ac6SHong Zhang   if (rank == 0) { /* proc[0] will create Electric Power Grid */
510c4762a1bSJed Brown     numEdges[0]    = pfdata->nbranch;
511c4762a1bSJed Brown     numVertices[0] = pfdata->nbus;
512c4762a1bSJed Brown 
5139566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(2 * numEdges[0], &edgelist_power));
5149566063dSJacob Faibussowitsch     PetscCall(GetListofEdges_Power(pfdata, edgelist_power));
515c4762a1bSJed Brown   }
516c4762a1bSJed Brown   /* Broadcast power Sbase to all processors */
5179566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Bcast(&Sbase, 1, MPIU_SCALAR, 0, PETSC_COMM_WORLD));
518c4762a1bSJed Brown   appctx_power->Sbase     = Sbase;
519c4762a1bSJed Brown   appctx_power->jac_error = PETSC_FALSE;
520c4762a1bSJed Brown   /* If external option activated. Introduce error in jacobian */
5219566063dSJacob Faibussowitsch   PetscCall(PetscOptionsHasName(NULL, NULL, "-jac_error", &appctx_power->jac_error));
522c4762a1bSJed Brown 
5232bf73ac6SHong Zhang   /* All processes READ THE DATA FOR THE SECOND SUBNETWORK: Water */
5242bf73ac6SHong Zhang   /* Used for shared vertex, because currently the coupling info must be available in all processes!!! */
5259566063dSJacob Faibussowitsch   PetscCall(PetscNew(&waterdata));
5269566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetString(NULL, NULL, "-waterdata", waterdata_file, PETSC_MAX_PATH_LEN - 1, NULL));
5279566063dSJacob Faibussowitsch   PetscCall(WaterReadData(waterdata, waterdata_file));
5282bf73ac6SHong Zhang   if (size == 1 || (size > 1 && rank == 1)) {
5299566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(2 * waterdata->nedge, &edgelist_water));
5309566063dSJacob Faibussowitsch     PetscCall(GetListofEdges_Water(waterdata, edgelist_water));
531c4762a1bSJed Brown     numEdges[1]    = waterdata->nedge;
532c4762a1bSJed Brown     numVertices[1] = waterdata->nvertex;
533c4762a1bSJed Brown   }
5343ba16761SJacob Faibussowitsch   PetscCall(PetscLogStagePop());
535c4762a1bSJed Brown 
5362bf73ac6SHong Zhang   /* (2) Create a network consist of two subnetworks */
5379566063dSJacob Faibussowitsch   PetscCall(PetscLogStageRegister("Net Setup", &stage[1]));
5389566063dSJacob Faibussowitsch   PetscCall(PetscLogStagePush(stage[1]));
539c4762a1bSJed Brown 
540cc13d412SHong Zhang   PetscCall(PetscOptionsGetBool(NULL, NULL, "-viewCSV", &viewCSV, NULL));
541cc13d412SHong Zhang   PetscCall(PetscOptionsGetBool(NULL, NULL, "-printCoord", &printCoord, NULL));
5429566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(NULL, NULL, "-test", &test, NULL));
5439566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(NULL, NULL, "-distribute", &distribute, NULL));
544c4762a1bSJed Brown 
545c4762a1bSJed Brown   /* Create an empty network object */
5469566063dSJacob Faibussowitsch   PetscCall(DMNetworkCreate(PETSC_COMM_WORLD, &networkdm));
547c4762a1bSJed Brown 
548c4762a1bSJed Brown   /* Register the components in the network */
5499566063dSJacob Faibussowitsch   PetscCall(DMNetworkRegisterComponent(networkdm, "branchstruct", sizeof(struct _p_EDGE_Power), &appctx_power->compkey_branch));
5509566063dSJacob Faibussowitsch   PetscCall(DMNetworkRegisterComponent(networkdm, "busstruct", sizeof(struct _p_VERTEX_Power), &appctx_power->compkey_bus));
5519566063dSJacob Faibussowitsch   PetscCall(DMNetworkRegisterComponent(networkdm, "genstruct", sizeof(struct _p_GEN), &appctx_power->compkey_gen));
5529566063dSJacob Faibussowitsch   PetscCall(DMNetworkRegisterComponent(networkdm, "loadstruct", sizeof(struct _p_LOAD), &appctx_power->compkey_load));
553c4762a1bSJed Brown 
5549566063dSJacob Faibussowitsch   PetscCall(DMNetworkRegisterComponent(networkdm, "edge_water", sizeof(struct _p_EDGE_Water), &appctx_water->compkey_edge));
5559566063dSJacob Faibussowitsch   PetscCall(DMNetworkRegisterComponent(networkdm, "vertex_water", sizeof(struct _p_VERTEX_Water), &appctx_water->compkey_vtx));
556cc13d412SHong Zhang 
55763a3b9bcSJacob 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]));
5589566063dSJacob Faibussowitsch   PetscCall(PetscSynchronizedFlush(PETSC_COMM_WORLD, PETSC_STDOUT));
559c4762a1bSJed Brown 
5609566063dSJacob Faibussowitsch   PetscCall(DMNetworkSetNumSubNetworks(networkdm, PETSC_DECIDE, Nsubnet));
5619566063dSJacob Faibussowitsch   PetscCall(DMNetworkAddSubnetwork(networkdm, "power", numEdges[0], edgelist_power, &power_netnum));
5629566063dSJacob Faibussowitsch   PetscCall(DMNetworkAddSubnetwork(networkdm, "water", numEdges[1], edgelist_water, &water_netnum));
563c4762a1bSJed Brown 
5642bf73ac6SHong Zhang   /* vertex subnet[0].4 shares with vertex subnet[1].0 */
5659371c9d4SSatish Balay   power_svtx = 4;
5669371c9d4SSatish Balay   water_svtx = 0;
5679566063dSJacob Faibussowitsch   PetscCall(DMNetworkAddSharedVertices(networkdm, power_netnum, water_netnum, 1, &power_svtx, &water_svtx));
568c4762a1bSJed Brown 
569c4762a1bSJed Brown   /* Set up the network layout */
5709566063dSJacob Faibussowitsch   PetscCall(DMNetworkLayoutSetUp(networkdm));
571c4762a1bSJed Brown 
572c4762a1bSJed Brown   /* ADD VARIABLES AND COMPONENTS FOR THE POWER SUBNETWORK */
5739371c9d4SSatish Balay   genj  = 0;
5749371c9d4SSatish Balay   loadj = 0;
5759566063dSJacob Faibussowitsch   PetscCall(DMNetworkGetSubnetwork(networkdm, power_netnum, &nv, &ne, &vtx, &edges));
5762bf73ac6SHong Zhang 
57748a46eb9SPierre Jolivet   for (i = 0; i < ne; i++) PetscCall(DMNetworkAddComponent(networkdm, edges[i], appctx_power->compkey_branch, &pfdata->branch[i], 0));
578c4762a1bSJed Brown 
579c4762a1bSJed Brown   for (i = 0; i < nv; i++) {
5809566063dSJacob Faibussowitsch     PetscCall(DMNetworkIsSharedVertex(networkdm, vtx[i], &flg));
5812bf73ac6SHong Zhang     if (flg) continue;
5822bf73ac6SHong Zhang 
5839566063dSJacob Faibussowitsch     PetscCall(DMNetworkAddComponent(networkdm, vtx[i], appctx_power->compkey_bus, &pfdata->bus[i], 2));
584c4762a1bSJed Brown     if (pfdata->bus[i].ngen) {
58548a46eb9SPierre Jolivet       for (j = 0; j < pfdata->bus[i].ngen; j++) PetscCall(DMNetworkAddComponent(networkdm, vtx[i], appctx_power->compkey_gen, &pfdata->gen[genj++], 0));
586c4762a1bSJed Brown     }
587c4762a1bSJed Brown     if (pfdata->bus[i].nload) {
58848a46eb9SPierre Jolivet       for (j = 0; j < pfdata->bus[i].nload; j++) PetscCall(DMNetworkAddComponent(networkdm, vtx[i], appctx_power->compkey_load, &pfdata->load[loadj++], 0));
589c4762a1bSJed Brown     }
590c4762a1bSJed Brown   }
591c4762a1bSJed Brown 
592c4762a1bSJed Brown   /* ADD VARIABLES AND COMPONENTS FOR THE WATER SUBNETWORK */
5939566063dSJacob Faibussowitsch   PetscCall(DMNetworkGetSubnetwork(networkdm, water_netnum, &nv, &ne, &vtx, &edges));
59448a46eb9SPierre Jolivet   for (i = 0; i < ne; i++) PetscCall(DMNetworkAddComponent(networkdm, edges[i], appctx_water->compkey_edge, &waterdata->edge[i], 0));
595c4762a1bSJed Brown 
596c4762a1bSJed Brown   for (i = 0; i < nv; i++) {
5979566063dSJacob Faibussowitsch     PetscCall(DMNetworkIsSharedVertex(networkdm, vtx[i], &flg));
5982bf73ac6SHong Zhang     if (flg) continue;
5992bf73ac6SHong Zhang 
6009566063dSJacob Faibussowitsch     PetscCall(DMNetworkAddComponent(networkdm, vtx[i], appctx_water->compkey_vtx, &waterdata->vertex[i], 1));
601c4762a1bSJed Brown   }
6022bf73ac6SHong Zhang 
603eac198afSGetnet   /* 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 */
6049566063dSJacob Faibussowitsch   PetscCall(DMNetworkGetSharedVertices(networkdm, &nv, &vtx));
6052bf73ac6SHong Zhang   for (i = 0; i < nv; i++) {
6062bf73ac6SHong Zhang     /* power */
6079566063dSJacob Faibussowitsch     PetscCall(DMNetworkAddComponent(networkdm, vtx[i], appctx_power->compkey_bus, &pfdata->bus[4], 2));
6082bf73ac6SHong Zhang     /* bus[4] is a load, add its component */
6099566063dSJacob Faibussowitsch     PetscCall(DMNetworkAddComponent(networkdm, vtx[i], appctx_power->compkey_load, &pfdata->load[0], 0));
6102bf73ac6SHong Zhang 
6112bf73ac6SHong Zhang     /* water */
6129566063dSJacob Faibussowitsch     PetscCall(DMNetworkAddComponent(networkdm, vtx[i], appctx_water->compkey_vtx, &waterdata->vertex[0], 1));
613c4762a1bSJed Brown   }
614c4762a1bSJed Brown 
615cc13d412SHong Zhang   /* Set coordinates for visualization */
616cc13d412SHong Zhang   PetscCall(DMSetCoordinateDim(networkdm, 2));
617*7cd471e7SHong Zhang   PetscCall(DMGetCoordinateDM(networkdm, &dmcoords));
618*7cd471e7SHong Zhang   PetscCall(DMNetworkGetVertexRange(dmcoords, &vStart, &vEnd));
619cc13d412SHong Zhang 
620*7cd471e7SHong Zhang   PetscCall(PetscCalloc1(vEnd - vStart, &color));
621*7cd471e7SHong Zhang   PetscCall(DMNetworkRegisterComponent(dmcoords, "coordinate&color", sizeof(PetscReal), &compkey));
622*7cd471e7SHong Zhang   for (i = vStart; i < vEnd; i++) PetscCall(DMNetworkAddComponent(dmcoords, i, compkey, &color[i - vStart], 2));
623*7cd471e7SHong Zhang   PetscCall(DMNetworkFinalizeComponents(dmcoords));
624*7cd471e7SHong Zhang 
625*7cd471e7SHong Zhang   PetscCall(DMCreateLocalVector(dmcoords, &coords));
626cc13d412SHong Zhang   PetscCall(DMSetCoordinatesLocal(networkdm, coords)); /* set/get coords to/from networkdm */
627*7cd471e7SHong Zhang   PetscCall(CoordinateVecSetUp(dmcoords, coords));
628cc13d412SHong Zhang   if (printCoord) PetscCall(CoordinatePrint(networkdm));
629cc13d412SHong Zhang 
630c4762a1bSJed Brown   /* Set up DM for use */
6319566063dSJacob Faibussowitsch   PetscCall(DMSetUp(networkdm));
632c4762a1bSJed Brown 
633c4762a1bSJed Brown   /* Free user objects */
6349566063dSJacob Faibussowitsch   PetscCall(PetscFree(edgelist_power));
6359566063dSJacob Faibussowitsch   PetscCall(PetscFree(pfdata->bus));
6369566063dSJacob Faibussowitsch   PetscCall(PetscFree(pfdata->gen));
6379566063dSJacob Faibussowitsch   PetscCall(PetscFree(pfdata->branch));
6389566063dSJacob Faibussowitsch   PetscCall(PetscFree(pfdata->load));
6399566063dSJacob Faibussowitsch   PetscCall(PetscFree(pfdata));
6402bf73ac6SHong Zhang 
6419566063dSJacob Faibussowitsch   PetscCall(PetscFree(edgelist_water));
6429566063dSJacob Faibussowitsch   PetscCall(PetscFree(waterdata->vertex));
6439566063dSJacob Faibussowitsch   PetscCall(PetscFree(waterdata->edge));
6449566063dSJacob Faibussowitsch   PetscCall(PetscFree(waterdata));
645c4762a1bSJed Brown 
646d5c9c0c4SHong Zhang   /* Re-distribute networkdm to multiple processes for better job balance */
647cc13d412SHong Zhang   if (distribute) {
6489566063dSJacob Faibussowitsch     PetscCall(DMNetworkDistribute(&networkdm, 0));
649cc13d412SHong Zhang 
650cc13d412SHong Zhang     if (printCoord) PetscCall(CoordinatePrint(networkdm));
651cc13d412SHong Zhang     if (viewCSV) { /* CSV View of network with coordinates */
652cc13d412SHong Zhang       PetscCall(PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD, PETSC_VIEWER_ASCII_CSV));
6539566063dSJacob Faibussowitsch       PetscCall(DMView(networkdm, PETSC_VIEWER_STDOUT_WORLD));
654cc13d412SHong Zhang       PetscCall(PetscViewerPopFormat(PETSC_VIEWER_STDOUT_WORLD));
655c4762a1bSJed Brown     }
656d5c9c0c4SHong Zhang   }
657cc13d412SHong Zhang   PetscCall(VecDestroy(&coords));
658c4762a1bSJed Brown 
6592bf73ac6SHong Zhang   /* Test DMNetworkGetSubnetwork() and DMNetworkGetSubnetworkSharedVertices() */
660c4762a1bSJed Brown   if (test) {
6612bf73ac6SHong Zhang     PetscInt v, gidx;
6629566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Barrier(PETSC_COMM_WORLD));
6632bf73ac6SHong Zhang     for (i = 0; i < Nsubnet; i++) {
6649566063dSJacob Faibussowitsch       PetscCall(DMNetworkGetSubnetwork(networkdm, i, &nv, &ne, &vtx, &edges));
66563a3b9bcSJacob Faibussowitsch       PetscCall(PetscPrintf(PETSC_COMM_SELF, "[%d] After distribute, subnet[%" PetscInt_FMT "] ne %" PetscInt_FMT ", nv %" PetscInt_FMT "\n", rank, i, ne, nv));
6669566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Barrier(PETSC_COMM_WORLD));
667c4762a1bSJed Brown 
6682bf73ac6SHong Zhang       for (v = 0; v < nv; v++) {
6699566063dSJacob Faibussowitsch         PetscCall(DMNetworkIsGhostVertex(networkdm, vtx[v], &ghost));
6709566063dSJacob Faibussowitsch         PetscCall(DMNetworkGetGlobalVertexIndex(networkdm, vtx[v], &gidx));
67163a3b9bcSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "[%d] subnet[%" PetscInt_FMT "] v %" PetscInt_FMT " %" PetscInt_FMT "; ghost %d\n", rank, i, vtx[v], gidx, ghost));
672c4762a1bSJed Brown       }
6739566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Barrier(PETSC_COMM_WORLD));
674c4762a1bSJed Brown     }
6759566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Barrier(PETSC_COMM_WORLD));
6762bf73ac6SHong Zhang 
6779566063dSJacob Faibussowitsch     PetscCall(DMNetworkGetSharedVertices(networkdm, &nv, &vtx));
67863a3b9bcSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_SELF, "[%d] After distribute, num of shared vertices nsv = %" PetscInt_FMT "\n", rank, nv));
6792bf73ac6SHong Zhang     for (v = 0; v < nv; v++) {
6809566063dSJacob Faibussowitsch       PetscCall(DMNetworkGetGlobalVertexIndex(networkdm, vtx[v], &gidx));
68163a3b9bcSJacob Faibussowitsch       PetscCall(PetscPrintf(PETSC_COMM_SELF, "[%d] sv %" PetscInt_FMT ", gidx=%" PetscInt_FMT "\n", rank, vtx[v], gidx));
6822bf73ac6SHong Zhang     }
6839566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Barrier(PETSC_COMM_WORLD));
684c4762a1bSJed Brown   }
685c4762a1bSJed Brown 
6862bf73ac6SHong Zhang   /* Create solution vector X */
6879566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector(networkdm, &X));
6889566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(X, &F));
6899566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(networkdm, &user.localXold));
6903ba16761SJacob Faibussowitsch   PetscCall(PetscLogStagePop());
691c4762a1bSJed Brown 
692c4762a1bSJed Brown   /* (3) Setup Solvers */
6939566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(NULL, NULL, "-viewJ", &viewJ, NULL));
6949566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(NULL, NULL, "-viewX", &viewX, NULL));
695c4762a1bSJed Brown 
6969566063dSJacob Faibussowitsch   PetscCall(PetscLogStageRegister("SNES Setup", &stage[2]));
6979566063dSJacob Faibussowitsch   PetscCall(PetscLogStagePush(stage[2]));
698c4762a1bSJed Brown 
6999566063dSJacob Faibussowitsch   PetscCall(SetInitialGuess(networkdm, X, &user));
700c4762a1bSJed Brown 
701c4762a1bSJed Brown   /* Create coupled snes */
7029566063dSJacob Faibussowitsch   PetscCall(PetscPrintf(PETSC_COMM_WORLD, "SNES_coupled setup ......\n"));
7032bf73ac6SHong Zhang   user.subsnes_id = Nsubnet;
7049566063dSJacob Faibussowitsch   PetscCall(SNESCreate(PETSC_COMM_WORLD, &snes));
7059566063dSJacob Faibussowitsch   PetscCall(SNESSetDM(snes, networkdm));
7069566063dSJacob Faibussowitsch   PetscCall(SNESSetOptionsPrefix(snes, "coupled_"));
7079566063dSJacob Faibussowitsch   PetscCall(SNESSetFunction(snes, F, FormFunction, &user));
708*7cd471e7SHong Zhang   /* set maxit=1 which can be changed via option '-coupled_snes_max_it <>', see ex1options */
709*7cd471e7SHong Zhang   PetscCall(SNESSetTolerances(snes, PETSC_DEFAULT, PETSC_DEFAULT, PETSC_DEFAULT, 1, PETSC_DEFAULT));
7109566063dSJacob Faibussowitsch   PetscCall(SNESSetFromOptions(snes));
711c4762a1bSJed Brown 
712c4762a1bSJed Brown   if (viewJ) {
713c4762a1bSJed Brown     /* View Jac structure */
7149566063dSJacob Faibussowitsch     PetscCall(SNESGetJacobian(snes, &Jac, NULL, NULL, NULL));
7159566063dSJacob Faibussowitsch     PetscCall(MatView(Jac, PETSC_VIEWER_DRAW_WORLD));
716c4762a1bSJed Brown   }
717c4762a1bSJed Brown 
718c4762a1bSJed Brown   if (viewX) {
7199566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Solution:\n"));
7209566063dSJacob Faibussowitsch     PetscCall(VecView(X, PETSC_VIEWER_STDOUT_WORLD));
721c4762a1bSJed Brown   }
722c4762a1bSJed Brown 
723c4762a1bSJed Brown   if (viewJ) {
724c4762a1bSJed Brown     /* View assembled Jac */
7259566063dSJacob Faibussowitsch     PetscCall(MatView(Jac, PETSC_VIEWER_DRAW_WORLD));
726c4762a1bSJed Brown   }
727c4762a1bSJed Brown 
728c4762a1bSJed Brown   /* Create snes_power */
7299566063dSJacob Faibussowitsch   PetscCall(PetscPrintf(PETSC_COMM_WORLD, "SNES_power setup ......\n"));
730c4762a1bSJed Brown   user.subsnes_id = 0;
7319566063dSJacob Faibussowitsch   PetscCall(SNESCreate(PETSC_COMM_WORLD, &snes_power));
7329566063dSJacob Faibussowitsch   PetscCall(SNESSetDM(snes_power, networkdm));
7339566063dSJacob Faibussowitsch   PetscCall(SNESSetOptionsPrefix(snes_power, "power_"));
7349566063dSJacob Faibussowitsch   PetscCall(SNESSetFunction(snes_power, F, FormFunction, &user));
735*7cd471e7SHong Zhang   /* set maxit=1 which can be changed via option '-power_snes_max_it <>', see ex1options */
736*7cd471e7SHong Zhang   PetscCall(SNESSetTolerances(snes_power, PETSC_DEFAULT, PETSC_DEFAULT, PETSC_DEFAULT, 1, PETSC_DEFAULT));
737c4762a1bSJed Brown 
738c4762a1bSJed Brown   /* Use user-provide Jacobian */
7399566063dSJacob Faibussowitsch   PetscCall(DMCreateMatrix(networkdm, &Jac));
7409566063dSJacob Faibussowitsch   PetscCall(SNESSetJacobian(snes_power, Jac, Jac, FormJacobian_subPower, &user));
7419566063dSJacob Faibussowitsch   PetscCall(SNESSetFromOptions(snes_power));
742c4762a1bSJed Brown 
743c4762a1bSJed Brown   if (viewX) {
7449566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Power Solution:\n"));
7459566063dSJacob Faibussowitsch     PetscCall(VecView(X, PETSC_VIEWER_STDOUT_WORLD));
746c4762a1bSJed Brown   }
747c4762a1bSJed Brown   if (viewJ) {
7489566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Power Jac:\n"));
7499566063dSJacob Faibussowitsch     PetscCall(SNESGetJacobian(snes_power, &Jac, NULL, NULL, NULL));
7509566063dSJacob Faibussowitsch     PetscCall(MatView(Jac, PETSC_VIEWER_DRAW_WORLD));
751c4762a1bSJed Brown   }
752c4762a1bSJed Brown 
753c4762a1bSJed Brown   /* Create snes_water */
7549566063dSJacob Faibussowitsch   PetscCall(PetscPrintf(PETSC_COMM_WORLD, "SNES_water setup......\n"));
755c4762a1bSJed Brown 
756c4762a1bSJed Brown   user.subsnes_id = 1;
7579566063dSJacob Faibussowitsch   PetscCall(SNESCreate(PETSC_COMM_WORLD, &snes_water));
7589566063dSJacob Faibussowitsch   PetscCall(SNESSetDM(snes_water, networkdm));
7599566063dSJacob Faibussowitsch   PetscCall(SNESSetOptionsPrefix(snes_water, "water_"));
7609566063dSJacob Faibussowitsch   PetscCall(SNESSetFunction(snes_water, F, FormFunction, &user));
761*7cd471e7SHong Zhang   /* set maxit=1 which can be changed via option '-water_snes_max_it <>', see ex1options */
762*7cd471e7SHong Zhang   PetscCall(SNESSetTolerances(snes_water, PETSC_DEFAULT, PETSC_DEFAULT, PETSC_DEFAULT, 1, PETSC_DEFAULT));
7639566063dSJacob Faibussowitsch   PetscCall(SNESSetFromOptions(snes_water));
764c4762a1bSJed Brown 
765c4762a1bSJed Brown   if (viewX) {
7669566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Water Solution:\n"));
7679566063dSJacob Faibussowitsch     PetscCall(VecView(X, PETSC_VIEWER_STDOUT_WORLD));
768c4762a1bSJed Brown   }
769*7cd471e7SHong Zhang 
770*7cd471e7SHong Zhang   /* Monitor snes, snes_power and snes_water iterations */
771*7cd471e7SHong Zhang   PetscCall(PetscOptionsGetBool(NULL, NULL, "-monitorIteration", &monitorIt, NULL));
772*7cd471e7SHong Zhang   user.monitorColor = PETSC_FALSE;
773*7cd471e7SHong Zhang   PetscCall(PetscOptionsGetBool(NULL, NULL, "-monitorColor", &user.monitorColor, NULL));
774*7cd471e7SHong Zhang   if (user.monitorColor) monitorIt = PETSC_TRUE; /* require installation of pandas and matplotlib */
775*7cd471e7SHong Zhang   if (monitorIt) {
776*7cd471e7SHong Zhang     PetscCall(SNESMonitorSet(snes_power, UserMonitor, &user, NULL));
777*7cd471e7SHong Zhang     PetscCall(SNESMonitorSet(snes_water, UserMonitor, &user, NULL));
778*7cd471e7SHong Zhang     PetscCall(SNESMonitorSet(snes, UserMonitor, &user, NULL));
779*7cd471e7SHong Zhang   }
7809566063dSJacob Faibussowitsch   PetscCall(PetscLogStagePop());
781c4762a1bSJed Brown 
782*7cd471e7SHong Zhang   /* (4) Solve: we must update user.localXold after each call of SNESSolve().
783*7cd471e7SHong Zhang          See "PETSc DMNetwork: A Library for Scalable Network PDE-Based Multiphysics Simulations",
784*7cd471e7SHong Zhang          https://dl.acm.org/doi/10.1145/3344587
785*7cd471e7SHong Zhang   */
7869566063dSJacob Faibussowitsch   PetscCall(PetscLogStageRegister("SNES Solve", &stage[3]));
7879566063dSJacob Faibussowitsch   PetscCall(PetscLogStagePush(stage[3]));
788*7cd471e7SHong Zhang   user.it = 0; /* total_snes_it */
789c4762a1bSJed Brown   reason  = SNES_DIVERGED_DTOL;
790c4762a1bSJed Brown   while (user.it < it_max && (PetscInt)reason < 0) {
791c4762a1bSJed Brown     user.subsnes_id = 0;
7929566063dSJacob Faibussowitsch     PetscCall(SNESSolve(snes_power, NULL, X));
793*7cd471e7SHong Zhang     PetscCall(DMGlobalToLocalBegin(networkdm, X, INSERT_VALUES, user.localXold));
794*7cd471e7SHong Zhang     PetscCall(DMGlobalToLocalEnd(networkdm, X, INSERT_VALUES, user.localXold));
795c4762a1bSJed Brown 
796c4762a1bSJed Brown     user.subsnes_id = 1;
7979566063dSJacob Faibussowitsch     PetscCall(SNESSolve(snes_water, NULL, X));
798*7cd471e7SHong Zhang     PetscCall(DMGlobalToLocalBegin(networkdm, X, INSERT_VALUES, user.localXold));
799*7cd471e7SHong Zhang     PetscCall(DMGlobalToLocalEnd(networkdm, X, INSERT_VALUES, user.localXold));
800*7cd471e7SHong Zhang 
8012bf73ac6SHong Zhang     user.subsnes_id = Nsubnet;
8029566063dSJacob Faibussowitsch     PetscCall(SNESSolve(snes, NULL, X));
803*7cd471e7SHong Zhang     PetscCall(DMGlobalToLocalBegin(networkdm, X, INSERT_VALUES, user.localXold));
804*7cd471e7SHong Zhang     PetscCall(DMGlobalToLocalEnd(networkdm, X, INSERT_VALUES, user.localXold));
805c4762a1bSJed Brown 
8069566063dSJacob Faibussowitsch     PetscCall(SNESGetConvergedReason(snes, &reason));
807c4762a1bSJed Brown     user.it++;
808c4762a1bSJed Brown   }
80963a3b9bcSJacob Faibussowitsch   PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Coupled_SNES converged in %" PetscInt_FMT " iterations\n", user.it));
810c4762a1bSJed Brown   if (viewX) {
8119566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Final Solution:\n"));
8129566063dSJacob Faibussowitsch     PetscCall(VecView(X, PETSC_VIEWER_STDOUT_WORLD));
813c4762a1bSJed Brown   }
8149566063dSJacob Faibussowitsch   PetscCall(PetscLogStagePop());
815c4762a1bSJed Brown 
816c4762a1bSJed Brown   /* Free objects */
817c4762a1bSJed Brown   /* -------------*/
818*7cd471e7SHong Zhang   PetscCall(PetscFree(color));
8199566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&X));
8209566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&F));
8219566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(networkdm, &user.localXold));
822c4762a1bSJed Brown 
8239566063dSJacob Faibussowitsch   PetscCall(SNESDestroy(&snes));
8249566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Jac));
8259566063dSJacob Faibussowitsch   PetscCall(SNESDestroy(&snes_power));
8269566063dSJacob Faibussowitsch   PetscCall(SNESDestroy(&snes_water));
827c4762a1bSJed Brown 
8289566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&networkdm));
8299566063dSJacob Faibussowitsch   PetscCall(PetscFinalize());
830b122ec5aSJacob Faibussowitsch   return 0;
831c4762a1bSJed Brown }
832c4762a1bSJed Brown 
833c4762a1bSJed Brown /*TEST
834c4762a1bSJed Brown 
835c4762a1bSJed Brown    build:
836dfd57a17SPierre Jolivet      requires: !complex double defined(PETSC_HAVE_ATTRIBUTEALIGNED)
837c4762a1bSJed Brown      depends: power/PFReadData.c power/pffunctions.c water/waterreaddata.c water/waterfunctions.c
838c4762a1bSJed Brown 
839c4762a1bSJed Brown    test:
840*7cd471e7SHong Zhang       args: -options_left no -dmnetwork_view -fp_trap 0
841c4762a1bSJed Brown       localrunfiles: ex1options power/case9.m water/sample1.inp
842c4762a1bSJed Brown       output_file: output/ex1.out
843c4762a1bSJed Brown 
844c4762a1bSJed Brown    test:
845c4762a1bSJed Brown       suffix: 2
846c4762a1bSJed Brown       nsize: 3
847*7cd471e7SHong Zhang       args: -options_left no -petscpartitioner_type parmetis -fp_trap 0
848c4762a1bSJed Brown       localrunfiles: ex1options power/case9.m water/sample1.inp
849d5c9c0c4SHong Zhang       output_file: output/ex1_2.out
8502bf73ac6SHong Zhang       requires: parmetis
8512bf73ac6SHong Zhang 
852cc13d412SHong Zhang    test:
853cc13d412SHong Zhang       suffix: 3
854cc13d412SHong Zhang       nsize: 3
855*7cd471e7SHong Zhang       args: -options_left no -distribute false -fp_trap 0
856cc13d412SHong Zhang       localrunfiles: ex1options power/case9.m water/sample1.inp
857cc13d412SHong Zhang       output_file: output/ex1_2.out
858d5c9c0c4SHong Zhang 
859d5c9c0c4SHong Zhang    test:
8602bf73ac6SHong Zhang       suffix: 4
8612bf73ac6SHong Zhang       nsize: 4
862*7cd471e7SHong Zhang       args: -options_left no -petscpartitioner_type simple -dmnetwork_view -dmnetwork_view_distributed -fp_trap 0
863d5c9c0c4SHong Zhang       localrunfiles: ex1options power/case9.m water/sample1.inp
8642bf73ac6SHong Zhang       output_file: output/ex1_4.out
865c4762a1bSJed Brown 
866cc13d412SHong Zhang    test:
867cc13d412SHong Zhang       suffix: 5
868*7cd471e7SHong Zhang       args: -options_left no -viewCSV -fp_trap 0
869cc13d412SHong Zhang       localrunfiles: ex1options power/case9.m water/sample1.inp
870cc13d412SHong Zhang       output_file: output/ex1_5.out
871cc13d412SHong Zhang 
872cc13d412SHong Zhang    test:
873cc13d412SHong Zhang       suffix: 6
874cc13d412SHong Zhang       nsize: 3
875*7cd471e7SHong Zhang       args: -options_left no -petscpartitioner_type parmetis -dmnetwork_view_distributed draw:null -fp_trap 0
876cc13d412SHong Zhang       localrunfiles: ex1options power/case9.m water/sample1.inp
877cc13d412SHong Zhang       output_file: output/ex1_2.out
878cc13d412SHong Zhang       requires: parmetis
879cc13d412SHong Zhang 
880c4762a1bSJed Brown TEST*/
881