xref: /petsc/src/snes/tutorials/network/ex1.c (revision 5f25b2246b55a8c64bf69fee40a0d75b9b096a54)
1*5f25b224SDuncan 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";
6c4762a1bSJed Brown 
7*5f25b224SDuncan Campbell /*
8*5f25b224SDuncan Campbell   Example:
9*5f25b224SDuncan Campbell     mpiexec -n 3 ./ex1 -petscpartitioner_type parmetis -dmnetwork_view draw -dmnetwork_view_distributed draw -dmnetwork_view_rank_range 0,1,2
10*5f25b224SDuncan Campbell */
11*5f25b224SDuncan 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() */
21c4762a1bSJed Brown } UserCtx;
22c4762a1bSJed Brown 
23d71ae5a4SJacob Faibussowitsch PetscErrorCode UserMonitor(SNES snes, PetscInt its, PetscReal fnorm, void *appctx)
24d71ae5a4SJacob Faibussowitsch {
25c4762a1bSJed Brown   UserCtx    *user = (UserCtx *)appctx;
26c4762a1bSJed Brown   Vec         X, localXold = user->localXold;
27c4762a1bSJed Brown   DM          networkdm;
28c4762a1bSJed Brown   PetscMPIInt rank;
29c4762a1bSJed Brown   MPI_Comm    comm;
30c4762a1bSJed Brown 
31c4762a1bSJed Brown   PetscFunctionBegin;
329566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)snes, &comm));
339566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
34c4762a1bSJed Brown #if 0
35dd400576SPatrick Sanan   if (rank == 0) {
36c4762a1bSJed Brown     PetscInt       subsnes_id = user->subsnes_id;
37c4762a1bSJed Brown     if (subsnes_id == 2) {
3863a3b9bcSJacob Faibussowitsch       PetscCall(PetscPrintf(PETSC_COMM_SELF," it %" PetscInt_FMT ", subsnes_id %" PetscInt_FMT ", fnorm %g\n",user->it,user->subsnes_id,(double)fnorm));
39c4762a1bSJed Brown     } else {
4063a3b9bcSJacob Faibussowitsch       PetscCall(PetscPrintf(PETSC_COMM_SELF,"       subsnes_id %" PetscInt_FMT ", fnorm %g\n",user->subsnes_id,(double)fnorm));
41c4762a1bSJed Brown     }
42c4762a1bSJed Brown   }
43c4762a1bSJed Brown #endif
449566063dSJacob Faibussowitsch   PetscCall(SNESGetSolution(snes, &X));
459566063dSJacob Faibussowitsch   PetscCall(SNESGetDM(snes, &networkdm));
469566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalBegin(networkdm, X, INSERT_VALUES, localXold));
479566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalEnd(networkdm, X, INSERT_VALUES, localXold));
483ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
49c4762a1bSJed Brown }
50c4762a1bSJed Brown 
51d71ae5a4SJacob Faibussowitsch PetscErrorCode FormJacobian_subPower(SNES snes, Vec X, Mat J, Mat Jpre, void *appctx)
52d71ae5a4SJacob Faibussowitsch {
53c4762a1bSJed Brown   DM              networkdm;
54c4762a1bSJed Brown   Vec             localX;
55c4762a1bSJed Brown   PetscInt        nv, ne, i, j, offset, nvar, row;
56c4762a1bSJed Brown   const PetscInt *vtx, *edges;
57c4762a1bSJed Brown   PetscBool       ghostvtex;
58c4762a1bSJed Brown   PetscScalar     one = 1.0;
59c4762a1bSJed Brown   PetscMPIInt     rank;
60c4762a1bSJed Brown   MPI_Comm        comm;
61c4762a1bSJed Brown 
62c4762a1bSJed Brown   PetscFunctionBegin;
639566063dSJacob Faibussowitsch   PetscCall(SNESGetDM(snes, &networkdm));
649566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(networkdm, &localX));
65c4762a1bSJed Brown 
669566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)networkdm, &comm));
679566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
68c4762a1bSJed Brown 
699566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalBegin(networkdm, X, INSERT_VALUES, localX));
709566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalEnd(networkdm, X, INSERT_VALUES, localX));
71c4762a1bSJed Brown 
729566063dSJacob Faibussowitsch   PetscCall(MatZeroEntries(J));
73c4762a1bSJed Brown 
74c4762a1bSJed Brown   /* Power subnetwork: copied from power/FormJacobian_Power() */
759566063dSJacob Faibussowitsch   PetscCall(DMNetworkGetSubnetwork(networkdm, 0, &nv, &ne, &vtx, &edges));
769566063dSJacob Faibussowitsch   PetscCall(FormJacobian_Power_private(networkdm, localX, J, nv, ne, vtx, edges, appctx));
77c4762a1bSJed Brown 
78c4762a1bSJed Brown   /* Water subnetwork: Identity */
799566063dSJacob Faibussowitsch   PetscCall(DMNetworkGetSubnetwork(networkdm, 1, &nv, &ne, &vtx, &edges));
80c4762a1bSJed Brown   for (i = 0; i < nv; i++) {
819566063dSJacob Faibussowitsch     PetscCall(DMNetworkIsGhostVertex(networkdm, vtx[i], &ghostvtex));
82c4762a1bSJed Brown     if (ghostvtex) continue;
83c4762a1bSJed Brown 
849566063dSJacob Faibussowitsch     PetscCall(DMNetworkGetGlobalVecOffset(networkdm, vtx[i], ALL_COMPONENTS, &offset));
859566063dSJacob Faibussowitsch     PetscCall(DMNetworkGetComponent(networkdm, vtx[i], ALL_COMPONENTS, NULL, NULL, &nvar));
86c4762a1bSJed Brown     for (j = 0; j < nvar; j++) {
87c4762a1bSJed Brown       row = offset + j;
889566063dSJacob Faibussowitsch       PetscCall(MatSetValues(J, 1, &row, 1, &row, &one, ADD_VALUES));
89c4762a1bSJed Brown     }
90c4762a1bSJed Brown   }
919566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(J, MAT_FINAL_ASSEMBLY));
929566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(J, MAT_FINAL_ASSEMBLY));
93c4762a1bSJed Brown 
949566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(networkdm, &localX));
953ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
96c4762a1bSJed Brown }
97c4762a1bSJed Brown 
98c4762a1bSJed Brown /* Dummy equation localF(X) = localX - localXold */
99d71ae5a4SJacob Faibussowitsch PetscErrorCode FormFunction_Dummy(DM networkdm, Vec localX, Vec localF, PetscInt nv, PetscInt ne, const PetscInt *vtx, const PetscInt *edges, void *appctx)
100d71ae5a4SJacob Faibussowitsch {
101c4762a1bSJed Brown   const PetscScalar *xarr, *xoldarr;
102c4762a1bSJed Brown   PetscScalar       *farr;
103c4762a1bSJed Brown   PetscInt           i, j, offset, nvar;
104c4762a1bSJed Brown   PetscBool          ghostvtex;
105c4762a1bSJed Brown   UserCtx           *user      = (UserCtx *)appctx;
106c4762a1bSJed Brown   Vec                localXold = user->localXold;
107c4762a1bSJed Brown 
108c4762a1bSJed Brown   PetscFunctionBegin;
1099566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(localX, &xarr));
1109566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(localXold, &xoldarr));
1119566063dSJacob Faibussowitsch   PetscCall(VecGetArray(localF, &farr));
112c4762a1bSJed Brown 
113c4762a1bSJed Brown   for (i = 0; i < nv; i++) {
1149566063dSJacob Faibussowitsch     PetscCall(DMNetworkIsGhostVertex(networkdm, vtx[i], &ghostvtex));
115c4762a1bSJed Brown     if (ghostvtex) continue;
116c4762a1bSJed Brown 
1179566063dSJacob Faibussowitsch     PetscCall(DMNetworkGetLocalVecOffset(networkdm, vtx[i], ALL_COMPONENTS, &offset));
1189566063dSJacob Faibussowitsch     PetscCall(DMNetworkGetComponent(networkdm, vtx[i], ALL_COMPONENTS, NULL, NULL, &nvar));
119ad540459SPierre Jolivet     for (j = 0; j < nvar; j++) farr[offset + j] = xarr[offset + j] - xoldarr[offset + j];
120c4762a1bSJed Brown   }
121c4762a1bSJed Brown 
1229566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(localX, &xarr));
1239566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(localXold, &xoldarr));
1249566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(localF, &farr));
1253ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
126c4762a1bSJed Brown }
127c4762a1bSJed Brown 
128d71ae5a4SJacob Faibussowitsch PetscErrorCode FormFunction(SNES snes, Vec X, Vec F, void *appctx)
129d71ae5a4SJacob Faibussowitsch {
130c4762a1bSJed Brown   DM              networkdm;
131c4762a1bSJed Brown   Vec             localX, localF;
1322bf73ac6SHong Zhang   PetscInt        nv, ne, v;
133c4762a1bSJed Brown   const PetscInt *vtx, *edges;
134c4762a1bSJed Brown   PetscMPIInt     rank;
135c4762a1bSJed Brown   MPI_Comm        comm;
136c4762a1bSJed Brown   UserCtx        *user         = (UserCtx *)appctx;
137c4762a1bSJed Brown   UserCtx_Power   appctx_power = (*user).appctx_power;
1382bf73ac6SHong Zhang   AppCtx_Water    appctx_water = (*user).appctx_water;
139c4762a1bSJed Brown 
140c4762a1bSJed Brown   PetscFunctionBegin;
1419566063dSJacob Faibussowitsch   PetscCall(SNESGetDM(snes, &networkdm));
1429566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)networkdm, &comm));
1439566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
144c4762a1bSJed Brown 
1459566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(networkdm, &localX));
1469566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(networkdm, &localF));
1479566063dSJacob Faibussowitsch   PetscCall(VecSet(F, 0.0));
1489566063dSJacob Faibussowitsch   PetscCall(VecSet(localF, 0.0));
149c4762a1bSJed Brown 
1509566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalBegin(networkdm, X, INSERT_VALUES, localX));
1519566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalEnd(networkdm, X, INSERT_VALUES, localX));
152c4762a1bSJed Brown 
153c4762a1bSJed Brown   /* Form Function for power subnetwork */
1549566063dSJacob Faibussowitsch   PetscCall(DMNetworkGetSubnetwork(networkdm, 0, &nv, &ne, &vtx, &edges));
155c4762a1bSJed Brown   if (user->subsnes_id == 1) { /* snes_water only */
1569566063dSJacob Faibussowitsch     PetscCall(FormFunction_Dummy(networkdm, localX, localF, nv, ne, vtx, edges, user));
157c4762a1bSJed Brown   } else {
1589566063dSJacob Faibussowitsch     PetscCall(FormFunction_Power(networkdm, localX, localF, nv, ne, vtx, edges, &appctx_power));
159c4762a1bSJed Brown   }
160c4762a1bSJed Brown 
161c4762a1bSJed Brown   /* Form Function for water subnetwork */
1629566063dSJacob Faibussowitsch   PetscCall(DMNetworkGetSubnetwork(networkdm, 1, &nv, &ne, &vtx, &edges));
163c4762a1bSJed Brown   if (user->subsnes_id == 0) { /* snes_power only */
1649566063dSJacob Faibussowitsch     PetscCall(FormFunction_Dummy(networkdm, localX, localF, nv, ne, vtx, edges, user));
165c4762a1bSJed Brown   } else {
1669566063dSJacob Faibussowitsch     PetscCall(FormFunction_Water(networkdm, localX, localF, nv, ne, vtx, edges, NULL));
167c4762a1bSJed Brown   }
168c4762a1bSJed Brown 
1692bf73ac6SHong Zhang   /* Illustrate how to access the coupling vertex of the subnetworks without doing anything to F yet */
1709566063dSJacob Faibussowitsch   PetscCall(DMNetworkGetSharedVertices(networkdm, &nv, &vtx));
1712bf73ac6SHong Zhang   for (v = 0; v < nv; v++) {
1722bf73ac6SHong Zhang     PetscInt        key, ncomp, nvar, nconnedges, k, e, keye, goffset[3];
173c4762a1bSJed Brown     void           *component;
1742bf73ac6SHong Zhang     const PetscInt *connedges;
175c4762a1bSJed Brown 
1769566063dSJacob Faibussowitsch     PetscCall(DMNetworkGetComponent(networkdm, vtx[v], ALL_COMPONENTS, NULL, NULL, &nvar));
1779566063dSJacob Faibussowitsch     PetscCall(DMNetworkGetNumComponents(networkdm, vtx[v], &ncomp));
17863a3b9bcSJacob Faibussowitsch     /* printf("  [%d] coupling vertex[%" PetscInt_FMT "]: v %" PetscInt_FMT ", ncomp %" PetscInt_FMT "; nvar %" PetscInt_FMT "\n",rank,v,vtx[v], ncomp,nvar); */
179c4762a1bSJed Brown 
1802bf73ac6SHong Zhang     for (k = 0; k < ncomp; k++) {
1819566063dSJacob Faibussowitsch       PetscCall(DMNetworkGetComponent(networkdm, vtx[v], k, &key, &component, &nvar));
1829566063dSJacob Faibussowitsch       PetscCall(DMNetworkGetGlobalVecOffset(networkdm, vtx[v], k, &goffset[k]));
183c4762a1bSJed Brown 
1842bf73ac6SHong Zhang       /* Verify the coupling vertex is a powernet load vertex or a water vertex */
1852bf73ac6SHong Zhang       switch (k) {
186d71ae5a4SJacob Faibussowitsch       case 0:
187d71ae5a4SJacob 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);
188d71ae5a4SJacob Faibussowitsch         break;
189d71ae5a4SJacob Faibussowitsch       case 1:
190d71ae5a4SJacob 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");
191d71ae5a4SJacob Faibussowitsch         break;
192d71ae5a4SJacob Faibussowitsch       case 2:
193d71ae5a4SJacob Faibussowitsch         PetscCheck(key == appctx_water.compkey_vtx && nvar == 1 && goffset[2] == goffset[1], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Not a water vertex");
194d71ae5a4SJacob Faibussowitsch         break;
195d71ae5a4SJacob Faibussowitsch       default:
196d71ae5a4SJacob Faibussowitsch         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "k %" PetscInt_FMT " is wrong", k);
1972bf73ac6SHong Zhang       }
19863a3b9bcSJacob Faibussowitsch       /* printf("  [%d] coupling vertex[%" PetscInt_FMT "]: key %" PetscInt_FMT "; nvar %" PetscInt_FMT ", goffset %" PetscInt_FMT "\n",rank,v,key,nvar,goffset[k]); */
1992bf73ac6SHong Zhang     }
200c4762a1bSJed Brown 
2012bf73ac6SHong Zhang     /* Get its supporting edges */
2029566063dSJacob Faibussowitsch     PetscCall(DMNetworkGetSupportingEdges(networkdm, vtx[v], &nconnedges, &connedges));
20363a3b9bcSJacob Faibussowitsch     /* printf("\n[%d] coupling vertex: nconnedges %" PetscInt_FMT "\n",rank,nconnedges); */
204c4762a1bSJed Brown     for (k = 0; k < nconnedges; k++) {
205c4762a1bSJed Brown       e = connedges[k];
2069566063dSJacob Faibussowitsch       PetscCall(DMNetworkGetNumComponents(networkdm, e, &ncomp));
20763a3b9bcSJacob Faibussowitsch       /* printf("\n  [%d] connected edge[%" PetscInt_FMT "]=%" PetscInt_FMT " has ncomp %" PetscInt_FMT "\n",rank,k,e,ncomp); */
2089566063dSJacob Faibussowitsch       PetscCall(DMNetworkGetComponent(networkdm, e, 0, &keye, &component, NULL));
209ad540459SPierre Jolivet       if (keye != appctx_water.compkey_edge) PetscCheck(keye == appctx_power.compkey_branch, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Not a power branch");
210c4762a1bSJed Brown     }
211c4762a1bSJed Brown   }
212c4762a1bSJed Brown 
2139566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(networkdm, &localX));
214c4762a1bSJed Brown 
2159566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalBegin(networkdm, localF, ADD_VALUES, F));
2169566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalEnd(networkdm, localF, ADD_VALUES, F));
2179566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(networkdm, &localF));
2182bf73ac6SHong Zhang #if 0
219dd400576SPatrick Sanan   if (rank == 0) printf("F:\n");
2209566063dSJacob Faibussowitsch   PetscCall(VecView(F,PETSC_VIEWER_STDOUT_WORLD));
2212bf73ac6SHong Zhang #endif
2223ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
223c4762a1bSJed Brown }
224c4762a1bSJed Brown 
225d71ae5a4SJacob Faibussowitsch PetscErrorCode SetInitialGuess(DM networkdm, Vec X, void *appctx)
226d71ae5a4SJacob Faibussowitsch {
2272bf73ac6SHong Zhang   PetscInt        nv, ne, i, j, ncomp, offset, key;
228c4762a1bSJed Brown   const PetscInt *vtx, *edges;
229c4762a1bSJed Brown   UserCtx        *user         = (UserCtx *)appctx;
230c4762a1bSJed Brown   Vec             localX       = user->localXold;
231c4762a1bSJed Brown   UserCtx_Power   appctx_power = (*user).appctx_power;
2322bf73ac6SHong Zhang   AppCtx_Water    appctx_water = (*user).appctx_water;
2332bf73ac6SHong Zhang   PetscBool       ghost;
2342bf73ac6SHong Zhang   PetscScalar    *xarr;
2352bf73ac6SHong Zhang   VERTEX_Power    bus;
2362bf73ac6SHong Zhang   VERTEX_Water    vertex;
2372bf73ac6SHong Zhang   void           *component;
2382bf73ac6SHong Zhang   GEN             gen;
239c4762a1bSJed Brown 
240c4762a1bSJed Brown   PetscFunctionBegin;
2419566063dSJacob Faibussowitsch   PetscCall(VecSet(X, 0.0));
2429566063dSJacob Faibussowitsch   PetscCall(VecSet(localX, 0.0));
243c4762a1bSJed Brown 
244c4762a1bSJed Brown   /* Set initial guess for power subnetwork */
2459566063dSJacob Faibussowitsch   PetscCall(DMNetworkGetSubnetwork(networkdm, 0, &nv, &ne, &vtx, &edges));
2469566063dSJacob Faibussowitsch   PetscCall(SetInitialGuess_Power(networkdm, localX, nv, ne, vtx, edges, &appctx_power));
247c4762a1bSJed Brown 
248c4762a1bSJed Brown   /* Set initial guess for water subnetwork */
2499566063dSJacob Faibussowitsch   PetscCall(DMNetworkGetSubnetwork(networkdm, 1, &nv, &ne, &vtx, &edges));
2509566063dSJacob Faibussowitsch   PetscCall(SetInitialGuess_Water(networkdm, localX, nv, ne, vtx, edges, NULL));
251c4762a1bSJed Brown 
2522bf73ac6SHong Zhang   /* Set initial guess at the coupling vertex */
2539566063dSJacob Faibussowitsch   PetscCall(VecGetArray(localX, &xarr));
2549566063dSJacob Faibussowitsch   PetscCall(DMNetworkGetSharedVertices(networkdm, &nv, &vtx));
2552bf73ac6SHong Zhang   for (i = 0; i < nv; i++) {
2569566063dSJacob Faibussowitsch     PetscCall(DMNetworkIsGhostVertex(networkdm, vtx[i], &ghost));
2572bf73ac6SHong Zhang     if (ghost) continue;
2582bf73ac6SHong Zhang 
2599566063dSJacob Faibussowitsch     PetscCall(DMNetworkGetNumComponents(networkdm, vtx[i], &ncomp));
2602bf73ac6SHong Zhang     for (j = 0; j < ncomp; j++) {
2619566063dSJacob Faibussowitsch       PetscCall(DMNetworkGetLocalVecOffset(networkdm, vtx[i], j, &offset));
2629566063dSJacob Faibussowitsch       PetscCall(DMNetworkGetComponent(networkdm, vtx[i], j, &key, (void **)&component, NULL));
2632bf73ac6SHong Zhang       if (key == appctx_power.compkey_bus) {
2642bf73ac6SHong Zhang         bus              = (VERTEX_Power)(component);
2652bf73ac6SHong Zhang         xarr[offset]     = bus->va * PETSC_PI / 180.0;
2662bf73ac6SHong Zhang         xarr[offset + 1] = bus->vm;
2672bf73ac6SHong Zhang       } else if (key == appctx_power.compkey_gen) {
2682bf73ac6SHong Zhang         gen = (GEN)(component);
2692bf73ac6SHong Zhang         if (!gen->status) continue;
2702bf73ac6SHong Zhang         xarr[offset + 1] = gen->vs;
2712bf73ac6SHong Zhang       } else if (key == appctx_water.compkey_vtx) {
2722bf73ac6SHong Zhang         vertex = (VERTEX_Water)(component);
2732bf73ac6SHong Zhang         if (vertex->type == VERTEX_TYPE_JUNCTION) {
2742bf73ac6SHong Zhang           xarr[offset] = 100;
2752bf73ac6SHong Zhang         } else if (vertex->type == VERTEX_TYPE_RESERVOIR) {
2762bf73ac6SHong Zhang           xarr[offset] = vertex->res.head;
2772bf73ac6SHong Zhang         } else {
2782bf73ac6SHong Zhang           xarr[offset] = vertex->tank.initlvl + vertex->tank.elev;
279c4762a1bSJed Brown         }
2802bf73ac6SHong Zhang       }
2812bf73ac6SHong Zhang     }
2822bf73ac6SHong Zhang   }
2839566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(localX, &xarr));
284c4762a1bSJed Brown 
2859566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalBegin(networkdm, localX, ADD_VALUES, X));
2869566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalEnd(networkdm, localX, ADD_VALUES, X));
2873ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
288c4762a1bSJed Brown }
289c4762a1bSJed Brown 
290cc13d412SHong Zhang /* Set coordinates */
291cc13d412SHong Zhang static PetscErrorCode CoordinateVecSetUp(DM dm, Vec coords)
292cc13d412SHong Zhang {
293cc13d412SHong Zhang   DM              dmclone;
294cc13d412SHong Zhang   PetscInt        i, gidx, offset, v, nv, Nsubnet;
295cc13d412SHong Zhang   const PetscInt *vtx;
296cc13d412SHong Zhang   PetscScalar    *carray;
297cc13d412SHong Zhang 
298cc13d412SHong Zhang   PetscFunctionBeginUser;
299cc13d412SHong Zhang   PetscCall(DMGetCoordinateDM(dm, &dmclone));
300cc13d412SHong Zhang   PetscCall(VecGetArrayWrite(coords, &carray));
301cc13d412SHong Zhang   PetscCall(DMNetworkGetNumSubNetworks(dm, NULL, &Nsubnet));
302cc13d412SHong Zhang   for (i = 0; i < Nsubnet; i++) {
303cc13d412SHong Zhang     PetscCall(DMNetworkGetSubnetwork(dm, i, &nv, NULL, &vtx, NULL));
304cc13d412SHong Zhang     for (v = 0; v < nv; v++) {
305cc13d412SHong Zhang       PetscCall(DMNetworkGetGlobalVertexIndex(dm, vtx[v], &gidx));
306cc13d412SHong Zhang       PetscCall(DMNetworkGetLocalVecOffset(dmclone, vtx[v], 0, &offset));
307cc13d412SHong Zhang       switch (gidx) {
308cc13d412SHong Zhang       case 0:
309cc13d412SHong Zhang         carray[offset]     = -1.0;
310cc13d412SHong Zhang         carray[offset + 1] = -1.0;
311cc13d412SHong Zhang         break;
312cc13d412SHong Zhang       case 1:
313cc13d412SHong Zhang         carray[offset]     = -2.0;
314cc13d412SHong Zhang         carray[offset + 1] = 2.0;
315cc13d412SHong Zhang         break;
316cc13d412SHong Zhang       case 2:
317cc13d412SHong Zhang         carray[offset]     = 0.0;
318cc13d412SHong Zhang         carray[offset + 1] = 2.0;
319cc13d412SHong Zhang         break;
320cc13d412SHong Zhang       case 3:
321cc13d412SHong Zhang         carray[offset]     = -1.0;
322cc13d412SHong Zhang         carray[offset + 1] = 0.0;
323cc13d412SHong Zhang         break;
324cc13d412SHong Zhang       case 4:
325cc13d412SHong Zhang         carray[offset]     = 0.0;
326cc13d412SHong Zhang         carray[offset + 1] = 0.0;
327cc13d412SHong Zhang         break;
328cc13d412SHong Zhang       case 5:
329cc13d412SHong Zhang         carray[offset]     = 0.0;
330cc13d412SHong Zhang         carray[offset + 1] = 1.0;
331cc13d412SHong Zhang         break;
332cc13d412SHong Zhang       case 6:
333cc13d412SHong Zhang         carray[offset]     = -1.0;
334cc13d412SHong Zhang         carray[offset + 1] = 1.0;
335cc13d412SHong Zhang         break;
336cc13d412SHong Zhang       case 7:
337cc13d412SHong Zhang         carray[offset]     = -2.0;
338cc13d412SHong Zhang         carray[offset + 1] = 1.0;
339cc13d412SHong Zhang         break;
340cc13d412SHong Zhang       case 8:
341cc13d412SHong Zhang         carray[offset]     = -2.0;
342cc13d412SHong Zhang         carray[offset + 1] = 0.0;
343cc13d412SHong Zhang         break;
344cc13d412SHong Zhang       case 9:
345cc13d412SHong Zhang         carray[offset]     = 1.0;
346cc13d412SHong Zhang         carray[offset + 1] = 0.0;
347cc13d412SHong Zhang         break;
348cc13d412SHong Zhang       case 10:
349cc13d412SHong Zhang         carray[offset]     = 1.0;
350cc13d412SHong Zhang         carray[offset + 1] = -1.0;
351cc13d412SHong Zhang         break;
352cc13d412SHong Zhang       case 11:
353cc13d412SHong Zhang         carray[offset]     = 2.0;
354cc13d412SHong Zhang         carray[offset + 1] = -1.0;
355cc13d412SHong Zhang         break;
356cc13d412SHong Zhang       case 12:
357cc13d412SHong Zhang         carray[offset]     = 2.0;
358cc13d412SHong Zhang         carray[offset + 1] = 0.0;
359cc13d412SHong Zhang         break;
360cc13d412SHong Zhang       case 13:
361cc13d412SHong Zhang         carray[offset]     = 0.0;
362cc13d412SHong Zhang         carray[offset + 1] = -1.0;
363cc13d412SHong Zhang         break;
364cc13d412SHong Zhang       case 14:
365cc13d412SHong Zhang         carray[offset]     = 2.0;
366cc13d412SHong Zhang         carray[offset + 1] = 1.0;
367cc13d412SHong Zhang         break;
368cc13d412SHong Zhang       default:
369cc13d412SHong Zhang         PetscCheck(gidx < 15 && gidx > -1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "gidx %" PetscInt_FMT "must between 0 and 14", gidx);
370cc13d412SHong Zhang       }
371cc13d412SHong Zhang     }
372cc13d412SHong Zhang   }
373cc13d412SHong Zhang   PetscCall(VecRestoreArrayWrite(coords, &carray));
374cc13d412SHong Zhang   PetscFunctionReturn(PETSC_SUCCESS);
375cc13d412SHong Zhang }
376cc13d412SHong Zhang 
377cc13d412SHong Zhang static PetscErrorCode CoordinatePrint(DM dm)
378cc13d412SHong Zhang {
379cc13d412SHong Zhang   DM                 dmclone;
380cc13d412SHong Zhang   PetscInt           cdim, v, off, vglobal, vStart, vEnd;
381cc13d412SHong Zhang   const PetscScalar *carray;
382cc13d412SHong Zhang   Vec                coords;
383cc13d412SHong Zhang   MPI_Comm           comm;
384cc13d412SHong Zhang   PetscMPIInt        rank;
385cc13d412SHong Zhang 
386cc13d412SHong Zhang   PetscFunctionBegin;
387cc13d412SHong Zhang   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
388cc13d412SHong Zhang   PetscCallMPI(MPI_Comm_rank(comm, &rank));
389cc13d412SHong Zhang 
390cc13d412SHong Zhang   PetscCall(DMGetCoordinateDM(dm, &dmclone));
391cc13d412SHong Zhang   PetscCall(DMNetworkGetVertexRange(dm, &vStart, &vEnd));
392cc13d412SHong Zhang   PetscCall(DMGetCoordinatesLocal(dm, &coords));
393cc13d412SHong Zhang 
394cc13d412SHong Zhang   PetscCall(DMGetCoordinateDim(dm, &cdim));
395cc13d412SHong Zhang   PetscCall(VecGetArrayRead(coords, &carray));
396cc13d412SHong Zhang 
397cc13d412SHong Zhang   PetscCall(PetscPrintf(MPI_COMM_WORLD, "\nCoordinatePrint, cdim %" PetscInt_FMT ":\n", cdim));
398cc13d412SHong Zhang   PetscCall(PetscSynchronizedPrintf(MPI_COMM_WORLD, "[%i]\n", rank));
399cc13d412SHong Zhang   for (v = vStart; v < vEnd; v++) {
400cc13d412SHong Zhang     PetscCall(DMNetworkGetLocalVecOffset(dmclone, v, 0, &off));
401cc13d412SHong Zhang     PetscCall(DMNetworkGetGlobalVertexIndex(dmclone, v, &vglobal));
402cc13d412SHong Zhang     switch (cdim) {
403cc13d412SHong Zhang     case 2:
404cc13d412SHong Zhang       PetscCall(PetscSynchronizedPrintf(MPI_COMM_WORLD, "Vertex: %" PetscInt_FMT ", x =  %f y = %f \n", vglobal, (double)PetscRealPart(carray[off]), (double)PetscRealPart(carray[off + 1])));
405cc13d412SHong Zhang       break;
406cc13d412SHong Zhang     default:
407cc13d412SHong Zhang       PetscCheck(cdim == 2, MPI_COMM_WORLD, PETSC_ERR_SUP, "Only supports Network embedding dimension of 2, not supplied  %" PetscInt_FMT, cdim);
408cc13d412SHong Zhang       break;
409cc13d412SHong Zhang     }
410cc13d412SHong Zhang   }
411cc13d412SHong Zhang   PetscCall(PetscSynchronizedFlush(MPI_COMM_WORLD, NULL));
412cc13d412SHong Zhang   PetscCall(VecRestoreArrayRead(coords, &carray));
413cc13d412SHong Zhang   PetscFunctionReturn(PETSC_SUCCESS);
414cc13d412SHong Zhang }
415cc13d412SHong Zhang 
416d71ae5a4SJacob Faibussowitsch int main(int argc, char **argv)
417d71ae5a4SJacob Faibussowitsch {
418cc13d412SHong Zhang   DM                  networkdm, dmclone;
419d5c9c0c4SHong Zhang   PetscMPIInt         rank, size;
4202bf73ac6SHong Zhang   PetscInt            Nsubnet = 2, numVertices[2], numEdges[2], i, j, nv, ne, it_max = 10;
421cc13d412SHong Zhang   PetscInt            vStart, vEnd, compkey;
422c4762a1bSJed Brown   const PetscInt     *vtx, *edges;
423cc13d412SHong Zhang   Vec                 X, F, coords;
424c4762a1bSJed Brown   SNES                snes, snes_power, snes_water;
425c4762a1bSJed Brown   Mat                 Jac;
426cc13d412SHong Zhang   PetscBool           ghost, viewJ = PETSC_FALSE, viewX = PETSC_FALSE, test = PETSC_FALSE, distribute = PETSC_TRUE, flg, printCoord = PETSC_FALSE, viewCSV = PETSC_FALSE;
427c4762a1bSJed Brown   UserCtx             user;
428c4762a1bSJed Brown   SNESConvergedReason reason;
4294279555eSSatish Balay #if defined(PETSC_USE_LOG)
4304279555eSSatish Balay   PetscLogStage stage[4];
4314279555eSSatish Balay #endif
432c4762a1bSJed Brown 
433c4762a1bSJed Brown   /* Power subnetwork */
434c4762a1bSJed Brown   UserCtx_Power *appctx_power                    = &user.appctx_power;
435c4762a1bSJed Brown   char           pfdata_file[PETSC_MAX_PATH_LEN] = "power/case9.m";
436c4762a1bSJed Brown   PFDATA        *pfdata                          = NULL;
4372bf73ac6SHong Zhang   PetscInt       genj, loadj, *edgelist_power = NULL, power_netnum;
438c4762a1bSJed Brown   PetscScalar    Sbase = 0.0;
439c4762a1bSJed Brown 
440c4762a1bSJed Brown   /* Water subnetwork */
441c4762a1bSJed Brown   AppCtx_Water *appctx_water                       = &user.appctx_water;
442c4762a1bSJed Brown   WATERDATA    *waterdata                          = NULL;
443c4762a1bSJed Brown   char          waterdata_file[PETSC_MAX_PATH_LEN] = "water/sample1.inp";
4442bf73ac6SHong Zhang   PetscInt     *edgelist_water                     = NULL, water_netnum;
445c4762a1bSJed Brown 
4462bf73ac6SHong Zhang   /* Shared vertices between subnetworks */
4472bf73ac6SHong Zhang   PetscInt power_svtx, water_svtx;
448c4762a1bSJed Brown 
449327415f7SBarry Smith   PetscFunctionBeginUser;
4509566063dSJacob Faibussowitsch   PetscCall(PetscInitialize(&argc, &argv, "ex1options", help));
4519566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD, &rank));
4529566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PETSC_COMM_WORLD, &size));
453c4762a1bSJed Brown 
454c4762a1bSJed Brown   /* (1) Read Data - Only rank 0 reads the data */
4559566063dSJacob Faibussowitsch   PetscCall(PetscLogStageRegister("Read Data", &stage[0]));
4569566063dSJacob Faibussowitsch   PetscCall(PetscLogStagePush(stage[0]));
457c4762a1bSJed Brown 
4582bf73ac6SHong Zhang   for (i = 0; i < Nsubnet; i++) {
459c4762a1bSJed Brown     numVertices[i] = 0;
460c4762a1bSJed Brown     numEdges[i]    = 0;
461c4762a1bSJed Brown   }
462c4762a1bSJed Brown 
4632bf73ac6SHong Zhang   /* All processes READ THE DATA FOR THE FIRST SUBNETWORK: Electric Power Grid */
4642bf73ac6SHong Zhang   /* Used for shared vertex, because currently the coupling info must be available in all processes!!! */
4659566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetString(NULL, NULL, "-pfdata", pfdata_file, PETSC_MAX_PATH_LEN - 1, NULL));
4669566063dSJacob Faibussowitsch   PetscCall(PetscNew(&pfdata));
4679566063dSJacob Faibussowitsch   PetscCall(PFReadMatPowerData(pfdata, pfdata_file));
46848a46eb9SPierre 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));
469c4762a1bSJed Brown   Sbase = pfdata->sbase;
4702bf73ac6SHong Zhang   if (rank == 0) { /* proc[0] will create Electric Power Grid */
471c4762a1bSJed Brown     numEdges[0]    = pfdata->nbranch;
472c4762a1bSJed Brown     numVertices[0] = pfdata->nbus;
473c4762a1bSJed Brown 
4749566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(2 * numEdges[0], &edgelist_power));
4759566063dSJacob Faibussowitsch     PetscCall(GetListofEdges_Power(pfdata, edgelist_power));
476c4762a1bSJed Brown   }
477c4762a1bSJed Brown   /* Broadcast power Sbase to all processors */
4789566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Bcast(&Sbase, 1, MPIU_SCALAR, 0, PETSC_COMM_WORLD));
479c4762a1bSJed Brown   appctx_power->Sbase     = Sbase;
480c4762a1bSJed Brown   appctx_power->jac_error = PETSC_FALSE;
481c4762a1bSJed Brown   /* If external option activated. Introduce error in jacobian */
4829566063dSJacob Faibussowitsch   PetscCall(PetscOptionsHasName(NULL, NULL, "-jac_error", &appctx_power->jac_error));
483c4762a1bSJed Brown 
4842bf73ac6SHong Zhang   /* All processes READ THE DATA FOR THE SECOND SUBNETWORK: Water */
4852bf73ac6SHong Zhang   /* Used for shared vertex, because currently the coupling info must be available in all processes!!! */
4869566063dSJacob Faibussowitsch   PetscCall(PetscNew(&waterdata));
4879566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetString(NULL, NULL, "-waterdata", waterdata_file, PETSC_MAX_PATH_LEN - 1, NULL));
4889566063dSJacob Faibussowitsch   PetscCall(WaterReadData(waterdata, waterdata_file));
4892bf73ac6SHong Zhang   if (size == 1 || (size > 1 && rank == 1)) {
4909566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(2 * waterdata->nedge, &edgelist_water));
4919566063dSJacob Faibussowitsch     PetscCall(GetListofEdges_Water(waterdata, edgelist_water));
492c4762a1bSJed Brown     numEdges[1]    = waterdata->nedge;
493c4762a1bSJed Brown     numVertices[1] = waterdata->nvertex;
494c4762a1bSJed Brown   }
4953ba16761SJacob Faibussowitsch   PetscCall(PetscLogStagePop());
496c4762a1bSJed Brown 
4972bf73ac6SHong Zhang   /* (2) Create a network consist of two subnetworks */
4989566063dSJacob Faibussowitsch   PetscCall(PetscLogStageRegister("Net Setup", &stage[1]));
4999566063dSJacob Faibussowitsch   PetscCall(PetscLogStagePush(stage[1]));
500c4762a1bSJed Brown 
501cc13d412SHong Zhang   PetscCall(PetscOptionsGetBool(NULL, NULL, "-viewCSV", &viewCSV, NULL));
502cc13d412SHong Zhang   PetscCall(PetscOptionsGetBool(NULL, NULL, "-printCoord", &printCoord, NULL));
5039566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(NULL, NULL, "-test", &test, NULL));
5049566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(NULL, NULL, "-distribute", &distribute, NULL));
505c4762a1bSJed Brown 
506c4762a1bSJed Brown   /* Create an empty network object */
5079566063dSJacob Faibussowitsch   PetscCall(DMNetworkCreate(PETSC_COMM_WORLD, &networkdm));
508c4762a1bSJed Brown 
509c4762a1bSJed Brown   /* Register the components in the network */
5109566063dSJacob Faibussowitsch   PetscCall(DMNetworkRegisterComponent(networkdm, "branchstruct", sizeof(struct _p_EDGE_Power), &appctx_power->compkey_branch));
5119566063dSJacob Faibussowitsch   PetscCall(DMNetworkRegisterComponent(networkdm, "busstruct", sizeof(struct _p_VERTEX_Power), &appctx_power->compkey_bus));
5129566063dSJacob Faibussowitsch   PetscCall(DMNetworkRegisterComponent(networkdm, "genstruct", sizeof(struct _p_GEN), &appctx_power->compkey_gen));
5139566063dSJacob Faibussowitsch   PetscCall(DMNetworkRegisterComponent(networkdm, "loadstruct", sizeof(struct _p_LOAD), &appctx_power->compkey_load));
514c4762a1bSJed Brown 
5159566063dSJacob Faibussowitsch   PetscCall(DMNetworkRegisterComponent(networkdm, "edge_water", sizeof(struct _p_EDGE_Water), &appctx_water->compkey_edge));
5169566063dSJacob Faibussowitsch   PetscCall(DMNetworkRegisterComponent(networkdm, "vertex_water", sizeof(struct _p_VERTEX_Water), &appctx_water->compkey_vtx));
517cc13d412SHong Zhang 
51863a3b9bcSJacob 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]));
5199566063dSJacob Faibussowitsch   PetscCall(PetscSynchronizedFlush(PETSC_COMM_WORLD, PETSC_STDOUT));
520c4762a1bSJed Brown 
5219566063dSJacob Faibussowitsch   PetscCall(DMNetworkSetNumSubNetworks(networkdm, PETSC_DECIDE, Nsubnet));
5229566063dSJacob Faibussowitsch   PetscCall(DMNetworkAddSubnetwork(networkdm, "power", numEdges[0], edgelist_power, &power_netnum));
5239566063dSJacob Faibussowitsch   PetscCall(DMNetworkAddSubnetwork(networkdm, "water", numEdges[1], edgelist_water, &water_netnum));
524c4762a1bSJed Brown 
5252bf73ac6SHong Zhang   /* vertex subnet[0].4 shares with vertex subnet[1].0 */
5269371c9d4SSatish Balay   power_svtx = 4;
5279371c9d4SSatish Balay   water_svtx = 0;
5289566063dSJacob Faibussowitsch   PetscCall(DMNetworkAddSharedVertices(networkdm, power_netnum, water_netnum, 1, &power_svtx, &water_svtx));
529c4762a1bSJed Brown 
530c4762a1bSJed Brown   /* Set up the network layout */
5319566063dSJacob Faibussowitsch   PetscCall(DMNetworkLayoutSetUp(networkdm));
532c4762a1bSJed Brown 
533c4762a1bSJed Brown   /* ADD VARIABLES AND COMPONENTS FOR THE POWER SUBNETWORK */
5349371c9d4SSatish Balay   genj  = 0;
5359371c9d4SSatish Balay   loadj = 0;
5369566063dSJacob Faibussowitsch   PetscCall(DMNetworkGetSubnetwork(networkdm, power_netnum, &nv, &ne, &vtx, &edges));
5372bf73ac6SHong Zhang 
53848a46eb9SPierre Jolivet   for (i = 0; i < ne; i++) PetscCall(DMNetworkAddComponent(networkdm, edges[i], appctx_power->compkey_branch, &pfdata->branch[i], 0));
539c4762a1bSJed Brown 
540c4762a1bSJed Brown   for (i = 0; i < nv; i++) {
5419566063dSJacob Faibussowitsch     PetscCall(DMNetworkIsSharedVertex(networkdm, vtx[i], &flg));
5422bf73ac6SHong Zhang     if (flg) continue;
5432bf73ac6SHong Zhang 
5449566063dSJacob Faibussowitsch     PetscCall(DMNetworkAddComponent(networkdm, vtx[i], appctx_power->compkey_bus, &pfdata->bus[i], 2));
545c4762a1bSJed Brown     if (pfdata->bus[i].ngen) {
54648a46eb9SPierre Jolivet       for (j = 0; j < pfdata->bus[i].ngen; j++) PetscCall(DMNetworkAddComponent(networkdm, vtx[i], appctx_power->compkey_gen, &pfdata->gen[genj++], 0));
547c4762a1bSJed Brown     }
548c4762a1bSJed Brown     if (pfdata->bus[i].nload) {
54948a46eb9SPierre Jolivet       for (j = 0; j < pfdata->bus[i].nload; j++) PetscCall(DMNetworkAddComponent(networkdm, vtx[i], appctx_power->compkey_load, &pfdata->load[loadj++], 0));
550c4762a1bSJed Brown     }
551c4762a1bSJed Brown   }
552c4762a1bSJed Brown 
553c4762a1bSJed Brown   /* ADD VARIABLES AND COMPONENTS FOR THE WATER SUBNETWORK */
5549566063dSJacob Faibussowitsch   PetscCall(DMNetworkGetSubnetwork(networkdm, water_netnum, &nv, &ne, &vtx, &edges));
55548a46eb9SPierre Jolivet   for (i = 0; i < ne; i++) PetscCall(DMNetworkAddComponent(networkdm, edges[i], appctx_water->compkey_edge, &waterdata->edge[i], 0));
556c4762a1bSJed Brown 
557c4762a1bSJed Brown   for (i = 0; i < nv; i++) {
5589566063dSJacob Faibussowitsch     PetscCall(DMNetworkIsSharedVertex(networkdm, vtx[i], &flg));
5592bf73ac6SHong Zhang     if (flg) continue;
5602bf73ac6SHong Zhang 
5619566063dSJacob Faibussowitsch     PetscCall(DMNetworkAddComponent(networkdm, vtx[i], appctx_water->compkey_vtx, &waterdata->vertex[i], 1));
562c4762a1bSJed Brown   }
5632bf73ac6SHong Zhang 
564eac198afSGetnet   /* 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 */
5659566063dSJacob Faibussowitsch   PetscCall(DMNetworkGetSharedVertices(networkdm, &nv, &vtx));
5662bf73ac6SHong Zhang   for (i = 0; i < nv; i++) {
5672bf73ac6SHong Zhang     /* power */
5689566063dSJacob Faibussowitsch     PetscCall(DMNetworkAddComponent(networkdm, vtx[i], appctx_power->compkey_bus, &pfdata->bus[4], 2));
5692bf73ac6SHong Zhang     /* bus[4] is a load, add its component */
5709566063dSJacob Faibussowitsch     PetscCall(DMNetworkAddComponent(networkdm, vtx[i], appctx_power->compkey_load, &pfdata->load[0], 0));
5712bf73ac6SHong Zhang 
5722bf73ac6SHong Zhang     /* water */
5739566063dSJacob Faibussowitsch     PetscCall(DMNetworkAddComponent(networkdm, vtx[i], appctx_water->compkey_vtx, &waterdata->vertex[0], 1));
574c4762a1bSJed Brown   }
575c4762a1bSJed Brown 
576cc13d412SHong Zhang   /* Set coordinates for visualization */
577cc13d412SHong Zhang   PetscCall(DMSetCoordinateDim(networkdm, 2));
578cc13d412SHong Zhang   PetscCall(DMGetCoordinateDM(networkdm, &dmclone));
579cc13d412SHong Zhang   PetscCall(DMNetworkGetVertexRange(dmclone, &vStart, &vEnd));
580cc13d412SHong Zhang   PetscCall(DMNetworkRegisterComponent(dmclone, "coordinates", 0, &compkey));
581aa624791SPierre Jolivet   for (i = vStart; i < vEnd; i++) PetscCall(DMNetworkAddComponent(dmclone, i, compkey, NULL, 2));
582cc13d412SHong Zhang   PetscCall(DMNetworkFinalizeComponents(dmclone));
583cc13d412SHong Zhang 
584cc13d412SHong Zhang   PetscCall(DMCreateLocalVector(dmclone, &coords));
585cc13d412SHong Zhang   PetscCall(DMSetCoordinatesLocal(networkdm, coords)); /* set/get coords to/from networkdm */
586cc13d412SHong Zhang   PetscCall(CoordinateVecSetUp(networkdm, coords));
587cc13d412SHong Zhang   if (printCoord) PetscCall(CoordinatePrint(networkdm));
588cc13d412SHong Zhang 
589c4762a1bSJed Brown   /* Set up DM for use */
590*5f25b224SDuncan Campbell   PetscCall(DMSetFromOptions(networkdm));
5919566063dSJacob Faibussowitsch   PetscCall(DMSetUp(networkdm));
592c4762a1bSJed Brown 
593c4762a1bSJed Brown   /* Free user objects */
5949566063dSJacob Faibussowitsch   PetscCall(PetscFree(edgelist_power));
5959566063dSJacob Faibussowitsch   PetscCall(PetscFree(pfdata->bus));
5969566063dSJacob Faibussowitsch   PetscCall(PetscFree(pfdata->gen));
5979566063dSJacob Faibussowitsch   PetscCall(PetscFree(pfdata->branch));
5989566063dSJacob Faibussowitsch   PetscCall(PetscFree(pfdata->load));
5999566063dSJacob Faibussowitsch   PetscCall(PetscFree(pfdata));
6002bf73ac6SHong Zhang 
6019566063dSJacob Faibussowitsch   PetscCall(PetscFree(edgelist_water));
6029566063dSJacob Faibussowitsch   PetscCall(PetscFree(waterdata->vertex));
6039566063dSJacob Faibussowitsch   PetscCall(PetscFree(waterdata->edge));
6049566063dSJacob Faibussowitsch   PetscCall(PetscFree(waterdata));
605c4762a1bSJed Brown 
606d5c9c0c4SHong Zhang   /* Re-distribute networkdm to multiple processes for better job balance */
607cc13d412SHong Zhang   if (distribute) {
6089566063dSJacob Faibussowitsch     PetscCall(DMNetworkDistribute(&networkdm, 0));
609cc13d412SHong Zhang 
610cc13d412SHong Zhang     if (printCoord) PetscCall(CoordinatePrint(networkdm));
611cc13d412SHong Zhang     if (viewCSV) { /* CSV View of network with coordinates */
612cc13d412SHong Zhang       PetscCall(PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD, PETSC_VIEWER_ASCII_CSV));
6139566063dSJacob Faibussowitsch       PetscCall(DMView(networkdm, PETSC_VIEWER_STDOUT_WORLD));
614cc13d412SHong Zhang       PetscCall(PetscViewerPopFormat(PETSC_VIEWER_STDOUT_WORLD));
615c4762a1bSJed Brown     }
616d5c9c0c4SHong Zhang   }
617cc13d412SHong Zhang   PetscCall(VecDestroy(&coords));
618c4762a1bSJed Brown 
6192bf73ac6SHong Zhang   /* Test DMNetworkGetSubnetwork() and DMNetworkGetSubnetworkSharedVertices() */
620c4762a1bSJed Brown   if (test) {
6212bf73ac6SHong Zhang     PetscInt v, gidx;
6229566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Barrier(PETSC_COMM_WORLD));
6232bf73ac6SHong Zhang     for (i = 0; i < Nsubnet; i++) {
6249566063dSJacob Faibussowitsch       PetscCall(DMNetworkGetSubnetwork(networkdm, i, &nv, &ne, &vtx, &edges));
62563a3b9bcSJacob Faibussowitsch       PetscCall(PetscPrintf(PETSC_COMM_SELF, "[%d] After distribute, subnet[%" PetscInt_FMT "] ne %" PetscInt_FMT ", nv %" PetscInt_FMT "\n", rank, i, ne, nv));
6269566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Barrier(PETSC_COMM_WORLD));
627c4762a1bSJed Brown 
6282bf73ac6SHong Zhang       for (v = 0; v < nv; v++) {
6299566063dSJacob Faibussowitsch         PetscCall(DMNetworkIsGhostVertex(networkdm, vtx[v], &ghost));
6309566063dSJacob Faibussowitsch         PetscCall(DMNetworkGetGlobalVertexIndex(networkdm, vtx[v], &gidx));
63163a3b9bcSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "[%d] subnet[%" PetscInt_FMT "] v %" PetscInt_FMT " %" PetscInt_FMT "; ghost %d\n", rank, i, vtx[v], gidx, ghost));
632c4762a1bSJed Brown       }
6339566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Barrier(PETSC_COMM_WORLD));
634c4762a1bSJed Brown     }
6359566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Barrier(PETSC_COMM_WORLD));
6362bf73ac6SHong Zhang 
6379566063dSJacob Faibussowitsch     PetscCall(DMNetworkGetSharedVertices(networkdm, &nv, &vtx));
63863a3b9bcSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_SELF, "[%d] After distribute, num of shared vertices nsv = %" PetscInt_FMT "\n", rank, nv));
6392bf73ac6SHong Zhang     for (v = 0; v < nv; v++) {
6409566063dSJacob Faibussowitsch       PetscCall(DMNetworkGetGlobalVertexIndex(networkdm, vtx[v], &gidx));
64163a3b9bcSJacob Faibussowitsch       PetscCall(PetscPrintf(PETSC_COMM_SELF, "[%d] sv %" PetscInt_FMT ", gidx=%" PetscInt_FMT "\n", rank, vtx[v], gidx));
6422bf73ac6SHong Zhang     }
6439566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Barrier(PETSC_COMM_WORLD));
644c4762a1bSJed Brown   }
645c4762a1bSJed Brown 
6462bf73ac6SHong Zhang   /* Create solution vector X */
6479566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector(networkdm, &X));
6489566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(X, &F));
6499566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(networkdm, &user.localXold));
6503ba16761SJacob Faibussowitsch   PetscCall(PetscLogStagePop());
651c4762a1bSJed Brown 
652c4762a1bSJed Brown   /* (3) Setup Solvers */
6539566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(NULL, NULL, "-viewJ", &viewJ, NULL));
6549566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(NULL, NULL, "-viewX", &viewX, NULL));
655c4762a1bSJed Brown 
6569566063dSJacob Faibussowitsch   PetscCall(PetscLogStageRegister("SNES Setup", &stage[2]));
6579566063dSJacob Faibussowitsch   PetscCall(PetscLogStagePush(stage[2]));
658c4762a1bSJed Brown 
6599566063dSJacob Faibussowitsch   PetscCall(SetInitialGuess(networkdm, X, &user));
660c4762a1bSJed Brown 
661c4762a1bSJed Brown   /* Create coupled snes */
6629566063dSJacob Faibussowitsch   PetscCall(PetscPrintf(PETSC_COMM_WORLD, "SNES_coupled setup ......\n"));
6632bf73ac6SHong Zhang   user.subsnes_id = Nsubnet;
6649566063dSJacob Faibussowitsch   PetscCall(SNESCreate(PETSC_COMM_WORLD, &snes));
6659566063dSJacob Faibussowitsch   PetscCall(SNESSetDM(snes, networkdm));
6669566063dSJacob Faibussowitsch   PetscCall(SNESSetOptionsPrefix(snes, "coupled_"));
6679566063dSJacob Faibussowitsch   PetscCall(SNESSetFunction(snes, F, FormFunction, &user));
6689566063dSJacob Faibussowitsch   PetscCall(SNESMonitorSet(snes, UserMonitor, &user, NULL));
6699566063dSJacob Faibussowitsch   PetscCall(SNESSetFromOptions(snes));
670c4762a1bSJed Brown 
671c4762a1bSJed Brown   if (viewJ) {
672c4762a1bSJed Brown     /* View Jac structure */
6739566063dSJacob Faibussowitsch     PetscCall(SNESGetJacobian(snes, &Jac, NULL, NULL, NULL));
6749566063dSJacob Faibussowitsch     PetscCall(MatView(Jac, PETSC_VIEWER_DRAW_WORLD));
675c4762a1bSJed Brown   }
676c4762a1bSJed Brown 
677c4762a1bSJed Brown   if (viewX) {
6789566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Solution:\n"));
6799566063dSJacob Faibussowitsch     PetscCall(VecView(X, PETSC_VIEWER_STDOUT_WORLD));
680c4762a1bSJed Brown   }
681c4762a1bSJed Brown 
682c4762a1bSJed Brown   if (viewJ) {
683c4762a1bSJed Brown     /* View assembled Jac */
6849566063dSJacob Faibussowitsch     PetscCall(MatView(Jac, PETSC_VIEWER_DRAW_WORLD));
685c4762a1bSJed Brown   }
686c4762a1bSJed Brown 
687c4762a1bSJed Brown   /* Create snes_power */
6889566063dSJacob Faibussowitsch   PetscCall(PetscPrintf(PETSC_COMM_WORLD, "SNES_power setup ......\n"));
689c4762a1bSJed Brown 
690c4762a1bSJed Brown   user.subsnes_id = 0;
6919566063dSJacob Faibussowitsch   PetscCall(SNESCreate(PETSC_COMM_WORLD, &snes_power));
6929566063dSJacob Faibussowitsch   PetscCall(SNESSetDM(snes_power, networkdm));
6939566063dSJacob Faibussowitsch   PetscCall(SNESSetOptionsPrefix(snes_power, "power_"));
6949566063dSJacob Faibussowitsch   PetscCall(SNESSetFunction(snes_power, F, FormFunction, &user));
6959566063dSJacob Faibussowitsch   PetscCall(SNESMonitorSet(snes_power, UserMonitor, &user, NULL));
696c4762a1bSJed Brown 
697c4762a1bSJed Brown   /* Use user-provide Jacobian */
6989566063dSJacob Faibussowitsch   PetscCall(DMCreateMatrix(networkdm, &Jac));
6999566063dSJacob Faibussowitsch   PetscCall(SNESSetJacobian(snes_power, Jac, Jac, FormJacobian_subPower, &user));
7009566063dSJacob Faibussowitsch   PetscCall(SNESSetFromOptions(snes_power));
701c4762a1bSJed Brown 
702c4762a1bSJed Brown   if (viewX) {
7039566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Power Solution:\n"));
7049566063dSJacob Faibussowitsch     PetscCall(VecView(X, PETSC_VIEWER_STDOUT_WORLD));
705c4762a1bSJed Brown   }
706c4762a1bSJed Brown   if (viewJ) {
7079566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Power Jac:\n"));
7089566063dSJacob Faibussowitsch     PetscCall(SNESGetJacobian(snes_power, &Jac, NULL, NULL, NULL));
7099566063dSJacob Faibussowitsch     PetscCall(MatView(Jac, PETSC_VIEWER_DRAW_WORLD));
7109566063dSJacob Faibussowitsch     /* PetscCall(MatView(Jac,PETSC_VIEWER_STDOUT_WORLD)); */
711c4762a1bSJed Brown   }
712c4762a1bSJed Brown 
713c4762a1bSJed Brown   /* Create snes_water */
7149566063dSJacob Faibussowitsch   PetscCall(PetscPrintf(PETSC_COMM_WORLD, "SNES_water setup......\n"));
715c4762a1bSJed Brown 
716c4762a1bSJed Brown   user.subsnes_id = 1;
7179566063dSJacob Faibussowitsch   PetscCall(SNESCreate(PETSC_COMM_WORLD, &snes_water));
7189566063dSJacob Faibussowitsch   PetscCall(SNESSetDM(snes_water, networkdm));
7199566063dSJacob Faibussowitsch   PetscCall(SNESSetOptionsPrefix(snes_water, "water_"));
7209566063dSJacob Faibussowitsch   PetscCall(SNESSetFunction(snes_water, F, FormFunction, &user));
7219566063dSJacob Faibussowitsch   PetscCall(SNESMonitorSet(snes_water, UserMonitor, &user, NULL));
7229566063dSJacob Faibussowitsch   PetscCall(SNESSetFromOptions(snes_water));
723c4762a1bSJed Brown 
724c4762a1bSJed Brown   if (viewX) {
7259566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Water Solution:\n"));
7269566063dSJacob Faibussowitsch     PetscCall(VecView(X, PETSC_VIEWER_STDOUT_WORLD));
727c4762a1bSJed Brown   }
7289566063dSJacob Faibussowitsch   PetscCall(PetscLogStagePop());
729c4762a1bSJed Brown 
730c4762a1bSJed Brown   /* (4) Solve */
7319566063dSJacob Faibussowitsch   PetscCall(PetscLogStageRegister("SNES Solve", &stage[3]));
7329566063dSJacob Faibussowitsch   PetscCall(PetscLogStagePush(stage[3]));
733c4762a1bSJed Brown   user.it = 0;
734c4762a1bSJed Brown   reason  = SNES_DIVERGED_DTOL;
735c4762a1bSJed Brown   while (user.it < it_max && (PetscInt)reason < 0) {
736c4762a1bSJed Brown #if 0
737c4762a1bSJed Brown     user.subsnes_id = 0;
7389566063dSJacob Faibussowitsch     PetscCall(SNESSolve(snes_power,NULL,X));
739c4762a1bSJed Brown 
740c4762a1bSJed Brown     user.subsnes_id = 1;
7419566063dSJacob Faibussowitsch     PetscCall(SNESSolve(snes_water,NULL,X));
742c4762a1bSJed Brown #endif
7432bf73ac6SHong Zhang     user.subsnes_id = Nsubnet;
7449566063dSJacob Faibussowitsch     PetscCall(SNESSolve(snes, NULL, X));
745c4762a1bSJed Brown 
7469566063dSJacob Faibussowitsch     PetscCall(SNESGetConvergedReason(snes, &reason));
747c4762a1bSJed Brown     user.it++;
748c4762a1bSJed Brown   }
74963a3b9bcSJacob Faibussowitsch   PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Coupled_SNES converged in %" PetscInt_FMT " iterations\n", user.it));
750c4762a1bSJed Brown   if (viewX) {
7519566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Final Solution:\n"));
7529566063dSJacob Faibussowitsch     PetscCall(VecView(X, PETSC_VIEWER_STDOUT_WORLD));
753c4762a1bSJed Brown   }
7549566063dSJacob Faibussowitsch   PetscCall(PetscLogStagePop());
755c4762a1bSJed Brown 
756c4762a1bSJed Brown   /* Free objects */
757c4762a1bSJed Brown   /* -------------*/
7589566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&X));
7599566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&F));
7609566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(networkdm, &user.localXold));
761c4762a1bSJed Brown 
7629566063dSJacob Faibussowitsch   PetscCall(SNESDestroy(&snes));
7639566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Jac));
7649566063dSJacob Faibussowitsch   PetscCall(SNESDestroy(&snes_power));
7659566063dSJacob Faibussowitsch   PetscCall(SNESDestroy(&snes_water));
766c4762a1bSJed Brown 
7679566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&networkdm));
7689566063dSJacob Faibussowitsch   PetscCall(PetscFinalize());
769b122ec5aSJacob Faibussowitsch   return 0;
770c4762a1bSJed Brown }
771c4762a1bSJed Brown 
772c4762a1bSJed Brown /*TEST
773c4762a1bSJed Brown 
774c4762a1bSJed Brown    build:
775dfd57a17SPierre Jolivet      requires: !complex double defined(PETSC_HAVE_ATTRIBUTEALIGNED)
776c4762a1bSJed Brown      depends: power/PFReadData.c power/pffunctions.c water/waterreaddata.c water/waterfunctions.c
777c4762a1bSJed Brown 
778c4762a1bSJed Brown    test:
779cc13d412SHong Zhang       args: -coupled_snes_converged_reason -options_left no -dmnetwork_view
780c4762a1bSJed Brown       localrunfiles: ex1options power/case9.m water/sample1.inp
781c4762a1bSJed Brown       output_file: output/ex1.out
782c4762a1bSJed Brown 
783c4762a1bSJed Brown    test:
784c4762a1bSJed Brown       suffix: 2
785c4762a1bSJed Brown       nsize: 3
7862bf73ac6SHong Zhang       args: -coupled_snes_converged_reason -options_left no -petscpartitioner_type parmetis
787c4762a1bSJed Brown       localrunfiles: ex1options power/case9.m water/sample1.inp
788d5c9c0c4SHong Zhang       output_file: output/ex1_2.out
7892bf73ac6SHong Zhang       requires: parmetis
7902bf73ac6SHong Zhang 
791cc13d412SHong Zhang    test:
792cc13d412SHong Zhang       suffix: 3
793cc13d412SHong Zhang       nsize: 3
794cc13d412SHong Zhang       args: -coupled_snes_converged_reason -options_left no -distribute false
795cc13d412SHong Zhang       localrunfiles: ex1options power/case9.m water/sample1.inp
796cc13d412SHong Zhang       output_file: output/ex1_2.out
797d5c9c0c4SHong Zhang 
798d5c9c0c4SHong Zhang    test:
7992bf73ac6SHong Zhang       suffix: 4
8002bf73ac6SHong Zhang       nsize: 4
801cc13d412SHong Zhang       args: -coupled_snes_converged_reason -options_left no -petscpartitioner_type simple -dmnetwork_view -dmnetwork_view_distributed
802d5c9c0c4SHong Zhang       localrunfiles: ex1options power/case9.m water/sample1.inp
8032bf73ac6SHong Zhang       output_file: output/ex1_4.out
804c4762a1bSJed Brown 
805cc13d412SHong Zhang    test:
806cc13d412SHong Zhang       suffix: 5
807cc13d412SHong Zhang       args: -coupled_snes_converged_reason -options_left no -viewCSV
808cc13d412SHong Zhang       localrunfiles: ex1options power/case9.m water/sample1.inp
809cc13d412SHong Zhang       output_file: output/ex1_5.out
810cc13d412SHong Zhang 
811cc13d412SHong Zhang    test:
812cc13d412SHong Zhang       suffix: 6
813cc13d412SHong Zhang       nsize: 3
814cc13d412SHong Zhang       args: -coupled_snes_converged_reason -options_left no -petscpartitioner_type parmetis -dmnetwork_view_distributed draw:null
815cc13d412SHong Zhang       localrunfiles: ex1options power/case9.m water/sample1.inp
816cc13d412SHong Zhang       output_file: output/ex1_2.out
817cc13d412SHong Zhang       requires: parmetis
818cc13d412SHong Zhang 
819c4762a1bSJed Brown TEST*/
820