xref: /petsc/src/snes/tutorials/network/ex1.c (revision aa62479103f8b3908dd743e7087487f9af829268)
1c4762a1bSJed Brown static char help[] = "This example demonstrates the use of DMNetwork interface 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                       This example shows the use of subnetwork feature in DMNetwork. \n\
6c4762a1bSJed Brown                       Run this program: mpiexec -n <n> ./ex1 \n\\n";
7c4762a1bSJed Brown 
8c4762a1bSJed Brown #include "power/power.h"
9c4762a1bSJed Brown #include "water/water.h"
10c4762a1bSJed Brown 
11c4762a1bSJed Brown typedef struct {
12c4762a1bSJed Brown   UserCtx_Power appctx_power;
13c4762a1bSJed Brown   AppCtx_Water  appctx_water;
14c4762a1bSJed Brown   PetscInt      subsnes_id; /* snes solver id */
15c4762a1bSJed Brown   PetscInt      it;         /* iteration number */
16c4762a1bSJed Brown   Vec           localXold;  /* store previous solution, used by FormFunction_Dummy() */
17c4762a1bSJed Brown } UserCtx;
18c4762a1bSJed Brown 
19d71ae5a4SJacob Faibussowitsch PetscErrorCode UserMonitor(SNES snes, PetscInt its, PetscReal fnorm, void *appctx)
20d71ae5a4SJacob Faibussowitsch {
21c4762a1bSJed Brown   UserCtx    *user = (UserCtx *)appctx;
22c4762a1bSJed Brown   Vec         X, localXold = user->localXold;
23c4762a1bSJed Brown   DM          networkdm;
24c4762a1bSJed Brown   PetscMPIInt rank;
25c4762a1bSJed Brown   MPI_Comm    comm;
26c4762a1bSJed Brown 
27c4762a1bSJed Brown   PetscFunctionBegin;
289566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)snes, &comm));
299566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
30c4762a1bSJed Brown #if 0
31dd400576SPatrick Sanan   if (rank == 0) {
32c4762a1bSJed Brown     PetscInt       subsnes_id = user->subsnes_id;
33c4762a1bSJed Brown     if (subsnes_id == 2) {
3463a3b9bcSJacob Faibussowitsch       PetscCall(PetscPrintf(PETSC_COMM_SELF," it %" PetscInt_FMT ", subsnes_id %" PetscInt_FMT ", fnorm %g\n",user->it,user->subsnes_id,(double)fnorm));
35c4762a1bSJed Brown     } else {
3663a3b9bcSJacob Faibussowitsch       PetscCall(PetscPrintf(PETSC_COMM_SELF,"       subsnes_id %" PetscInt_FMT ", fnorm %g\n",user->subsnes_id,(double)fnorm));
37c4762a1bSJed Brown     }
38c4762a1bSJed Brown   }
39c4762a1bSJed Brown #endif
409566063dSJacob Faibussowitsch   PetscCall(SNESGetSolution(snes, &X));
419566063dSJacob Faibussowitsch   PetscCall(SNESGetDM(snes, &networkdm));
429566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalBegin(networkdm, X, INSERT_VALUES, localXold));
439566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalEnd(networkdm, X, INSERT_VALUES, localXold));
443ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
45c4762a1bSJed Brown }
46c4762a1bSJed Brown 
47d71ae5a4SJacob Faibussowitsch PetscErrorCode FormJacobian_subPower(SNES snes, Vec X, Mat J, Mat Jpre, void *appctx)
48d71ae5a4SJacob Faibussowitsch {
49c4762a1bSJed Brown   DM              networkdm;
50c4762a1bSJed Brown   Vec             localX;
51c4762a1bSJed Brown   PetscInt        nv, ne, i, j, offset, nvar, row;
52c4762a1bSJed Brown   const PetscInt *vtx, *edges;
53c4762a1bSJed Brown   PetscBool       ghostvtex;
54c4762a1bSJed Brown   PetscScalar     one = 1.0;
55c4762a1bSJed Brown   PetscMPIInt     rank;
56c4762a1bSJed Brown   MPI_Comm        comm;
57c4762a1bSJed Brown 
58c4762a1bSJed Brown   PetscFunctionBegin;
599566063dSJacob Faibussowitsch   PetscCall(SNESGetDM(snes, &networkdm));
609566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(networkdm, &localX));
61c4762a1bSJed Brown 
629566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)networkdm, &comm));
639566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
64c4762a1bSJed Brown 
659566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalBegin(networkdm, X, INSERT_VALUES, localX));
669566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalEnd(networkdm, X, INSERT_VALUES, localX));
67c4762a1bSJed Brown 
689566063dSJacob Faibussowitsch   PetscCall(MatZeroEntries(J));
69c4762a1bSJed Brown 
70c4762a1bSJed Brown   /* Power subnetwork: copied from power/FormJacobian_Power() */
719566063dSJacob Faibussowitsch   PetscCall(DMNetworkGetSubnetwork(networkdm, 0, &nv, &ne, &vtx, &edges));
729566063dSJacob Faibussowitsch   PetscCall(FormJacobian_Power_private(networkdm, localX, J, nv, ne, vtx, edges, appctx));
73c4762a1bSJed Brown 
74c4762a1bSJed Brown   /* Water subnetwork: Identity */
759566063dSJacob Faibussowitsch   PetscCall(DMNetworkGetSubnetwork(networkdm, 1, &nv, &ne, &vtx, &edges));
76c4762a1bSJed Brown   for (i = 0; i < nv; i++) {
779566063dSJacob Faibussowitsch     PetscCall(DMNetworkIsGhostVertex(networkdm, vtx[i], &ghostvtex));
78c4762a1bSJed Brown     if (ghostvtex) continue;
79c4762a1bSJed Brown 
809566063dSJacob Faibussowitsch     PetscCall(DMNetworkGetGlobalVecOffset(networkdm, vtx[i], ALL_COMPONENTS, &offset));
819566063dSJacob Faibussowitsch     PetscCall(DMNetworkGetComponent(networkdm, vtx[i], ALL_COMPONENTS, NULL, NULL, &nvar));
82c4762a1bSJed Brown     for (j = 0; j < nvar; j++) {
83c4762a1bSJed Brown       row = offset + j;
849566063dSJacob Faibussowitsch       PetscCall(MatSetValues(J, 1, &row, 1, &row, &one, ADD_VALUES));
85c4762a1bSJed Brown     }
86c4762a1bSJed Brown   }
879566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(J, MAT_FINAL_ASSEMBLY));
889566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(J, MAT_FINAL_ASSEMBLY));
89c4762a1bSJed Brown 
909566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(networkdm, &localX));
913ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
92c4762a1bSJed Brown }
93c4762a1bSJed Brown 
94c4762a1bSJed Brown /* Dummy equation localF(X) = localX - localXold */
95d71ae5a4SJacob Faibussowitsch PetscErrorCode FormFunction_Dummy(DM networkdm, Vec localX, Vec localF, PetscInt nv, PetscInt ne, const PetscInt *vtx, const PetscInt *edges, void *appctx)
96d71ae5a4SJacob Faibussowitsch {
97c4762a1bSJed Brown   const PetscScalar *xarr, *xoldarr;
98c4762a1bSJed Brown   PetscScalar       *farr;
99c4762a1bSJed Brown   PetscInt           i, j, offset, nvar;
100c4762a1bSJed Brown   PetscBool          ghostvtex;
101c4762a1bSJed Brown   UserCtx           *user      = (UserCtx *)appctx;
102c4762a1bSJed Brown   Vec                localXold = user->localXold;
103c4762a1bSJed Brown 
104c4762a1bSJed Brown   PetscFunctionBegin;
1059566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(localX, &xarr));
1069566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(localXold, &xoldarr));
1079566063dSJacob Faibussowitsch   PetscCall(VecGetArray(localF, &farr));
108c4762a1bSJed Brown 
109c4762a1bSJed Brown   for (i = 0; i < nv; i++) {
1109566063dSJacob Faibussowitsch     PetscCall(DMNetworkIsGhostVertex(networkdm, vtx[i], &ghostvtex));
111c4762a1bSJed Brown     if (ghostvtex) continue;
112c4762a1bSJed Brown 
1139566063dSJacob Faibussowitsch     PetscCall(DMNetworkGetLocalVecOffset(networkdm, vtx[i], ALL_COMPONENTS, &offset));
1149566063dSJacob Faibussowitsch     PetscCall(DMNetworkGetComponent(networkdm, vtx[i], ALL_COMPONENTS, NULL, NULL, &nvar));
115ad540459SPierre Jolivet     for (j = 0; j < nvar; j++) farr[offset + j] = xarr[offset + j] - xoldarr[offset + j];
116c4762a1bSJed Brown   }
117c4762a1bSJed Brown 
1189566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(localX, &xarr));
1199566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(localXold, &xoldarr));
1209566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(localF, &farr));
1213ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
122c4762a1bSJed Brown }
123c4762a1bSJed Brown 
124d71ae5a4SJacob Faibussowitsch PetscErrorCode FormFunction(SNES snes, Vec X, Vec F, void *appctx)
125d71ae5a4SJacob Faibussowitsch {
126c4762a1bSJed Brown   DM              networkdm;
127c4762a1bSJed Brown   Vec             localX, localF;
1282bf73ac6SHong Zhang   PetscInt        nv, ne, v;
129c4762a1bSJed Brown   const PetscInt *vtx, *edges;
130c4762a1bSJed Brown   PetscMPIInt     rank;
131c4762a1bSJed Brown   MPI_Comm        comm;
132c4762a1bSJed Brown   UserCtx        *user         = (UserCtx *)appctx;
133c4762a1bSJed Brown   UserCtx_Power   appctx_power = (*user).appctx_power;
1342bf73ac6SHong Zhang   AppCtx_Water    appctx_water = (*user).appctx_water;
135c4762a1bSJed Brown 
136c4762a1bSJed Brown   PetscFunctionBegin;
1379566063dSJacob Faibussowitsch   PetscCall(SNESGetDM(snes, &networkdm));
1389566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)networkdm, &comm));
1399566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
140c4762a1bSJed Brown 
1419566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(networkdm, &localX));
1429566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(networkdm, &localF));
1439566063dSJacob Faibussowitsch   PetscCall(VecSet(F, 0.0));
1449566063dSJacob Faibussowitsch   PetscCall(VecSet(localF, 0.0));
145c4762a1bSJed Brown 
1469566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalBegin(networkdm, X, INSERT_VALUES, localX));
1479566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalEnd(networkdm, X, INSERT_VALUES, localX));
148c4762a1bSJed Brown 
149c4762a1bSJed Brown   /* Form Function for power subnetwork */
1509566063dSJacob Faibussowitsch   PetscCall(DMNetworkGetSubnetwork(networkdm, 0, &nv, &ne, &vtx, &edges));
151c4762a1bSJed Brown   if (user->subsnes_id == 1) { /* snes_water only */
1529566063dSJacob Faibussowitsch     PetscCall(FormFunction_Dummy(networkdm, localX, localF, nv, ne, vtx, edges, user));
153c4762a1bSJed Brown   } else {
1549566063dSJacob Faibussowitsch     PetscCall(FormFunction_Power(networkdm, localX, localF, nv, ne, vtx, edges, &appctx_power));
155c4762a1bSJed Brown   }
156c4762a1bSJed Brown 
157c4762a1bSJed Brown   /* Form Function for water subnetwork */
1589566063dSJacob Faibussowitsch   PetscCall(DMNetworkGetSubnetwork(networkdm, 1, &nv, &ne, &vtx, &edges));
159c4762a1bSJed Brown   if (user->subsnes_id == 0) { /* snes_power only */
1609566063dSJacob Faibussowitsch     PetscCall(FormFunction_Dummy(networkdm, localX, localF, nv, ne, vtx, edges, user));
161c4762a1bSJed Brown   } else {
1629566063dSJacob Faibussowitsch     PetscCall(FormFunction_Water(networkdm, localX, localF, nv, ne, vtx, edges, NULL));
163c4762a1bSJed Brown   }
164c4762a1bSJed Brown 
1652bf73ac6SHong Zhang   /* Illustrate how to access the coupling vertex of the subnetworks without doing anything to F yet */
1669566063dSJacob Faibussowitsch   PetscCall(DMNetworkGetSharedVertices(networkdm, &nv, &vtx));
1672bf73ac6SHong Zhang   for (v = 0; v < nv; v++) {
1682bf73ac6SHong Zhang     PetscInt        key, ncomp, nvar, nconnedges, k, e, keye, goffset[3];
169c4762a1bSJed Brown     void           *component;
1702bf73ac6SHong Zhang     const PetscInt *connedges;
171c4762a1bSJed Brown 
1729566063dSJacob Faibussowitsch     PetscCall(DMNetworkGetComponent(networkdm, vtx[v], ALL_COMPONENTS, NULL, NULL, &nvar));
1739566063dSJacob Faibussowitsch     PetscCall(DMNetworkGetNumComponents(networkdm, vtx[v], &ncomp));
17463a3b9bcSJacob Faibussowitsch     /* printf("  [%d] coupling vertex[%" PetscInt_FMT "]: v %" PetscInt_FMT ", ncomp %" PetscInt_FMT "; nvar %" PetscInt_FMT "\n",rank,v,vtx[v], ncomp,nvar); */
175c4762a1bSJed Brown 
1762bf73ac6SHong Zhang     for (k = 0; k < ncomp; k++) {
1779566063dSJacob Faibussowitsch       PetscCall(DMNetworkGetComponent(networkdm, vtx[v], k, &key, &component, &nvar));
1789566063dSJacob Faibussowitsch       PetscCall(DMNetworkGetGlobalVecOffset(networkdm, vtx[v], k, &goffset[k]));
179c4762a1bSJed Brown 
1802bf73ac6SHong Zhang       /* Verify the coupling vertex is a powernet load vertex or a water vertex */
1812bf73ac6SHong Zhang       switch (k) {
182d71ae5a4SJacob Faibussowitsch       case 0:
183d71ae5a4SJacob 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);
184d71ae5a4SJacob Faibussowitsch         break;
185d71ae5a4SJacob Faibussowitsch       case 1:
186d71ae5a4SJacob 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");
187d71ae5a4SJacob Faibussowitsch         break;
188d71ae5a4SJacob Faibussowitsch       case 2:
189d71ae5a4SJacob Faibussowitsch         PetscCheck(key == appctx_water.compkey_vtx && nvar == 1 && goffset[2] == goffset[1], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Not a water vertex");
190d71ae5a4SJacob Faibussowitsch         break;
191d71ae5a4SJacob Faibussowitsch       default:
192d71ae5a4SJacob Faibussowitsch         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "k %" PetscInt_FMT " is wrong", k);
1932bf73ac6SHong Zhang       }
19463a3b9bcSJacob Faibussowitsch       /* printf("  [%d] coupling vertex[%" PetscInt_FMT "]: key %" PetscInt_FMT "; nvar %" PetscInt_FMT ", goffset %" PetscInt_FMT "\n",rank,v,key,nvar,goffset[k]); */
1952bf73ac6SHong Zhang     }
196c4762a1bSJed Brown 
1972bf73ac6SHong Zhang     /* Get its supporting edges */
1989566063dSJacob Faibussowitsch     PetscCall(DMNetworkGetSupportingEdges(networkdm, vtx[v], &nconnedges, &connedges));
19963a3b9bcSJacob Faibussowitsch     /* printf("\n[%d] coupling vertex: nconnedges %" PetscInt_FMT "\n",rank,nconnedges); */
200c4762a1bSJed Brown     for (k = 0; k < nconnedges; k++) {
201c4762a1bSJed Brown       e = connedges[k];
2029566063dSJacob Faibussowitsch       PetscCall(DMNetworkGetNumComponents(networkdm, e, &ncomp));
20363a3b9bcSJacob Faibussowitsch       /* printf("\n  [%d] connected edge[%" PetscInt_FMT "]=%" PetscInt_FMT " has ncomp %" PetscInt_FMT "\n",rank,k,e,ncomp); */
2049566063dSJacob Faibussowitsch       PetscCall(DMNetworkGetComponent(networkdm, e, 0, &keye, &component, NULL));
205ad540459SPierre Jolivet       if (keye != appctx_water.compkey_edge) PetscCheck(keye == appctx_power.compkey_branch, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Not a power branch");
206c4762a1bSJed Brown     }
207c4762a1bSJed Brown   }
208c4762a1bSJed Brown 
2099566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(networkdm, &localX));
210c4762a1bSJed Brown 
2119566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalBegin(networkdm, localF, ADD_VALUES, F));
2129566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalEnd(networkdm, localF, ADD_VALUES, F));
2139566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(networkdm, &localF));
2142bf73ac6SHong Zhang #if 0
215dd400576SPatrick Sanan   if (rank == 0) printf("F:\n");
2169566063dSJacob Faibussowitsch   PetscCall(VecView(F,PETSC_VIEWER_STDOUT_WORLD));
2172bf73ac6SHong Zhang #endif
2183ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
219c4762a1bSJed Brown }
220c4762a1bSJed Brown 
221d71ae5a4SJacob Faibussowitsch PetscErrorCode SetInitialGuess(DM networkdm, Vec X, void *appctx)
222d71ae5a4SJacob Faibussowitsch {
2232bf73ac6SHong Zhang   PetscInt        nv, ne, i, j, ncomp, offset, key;
224c4762a1bSJed Brown   const PetscInt *vtx, *edges;
225c4762a1bSJed Brown   UserCtx        *user         = (UserCtx *)appctx;
226c4762a1bSJed Brown   Vec             localX       = user->localXold;
227c4762a1bSJed Brown   UserCtx_Power   appctx_power = (*user).appctx_power;
2282bf73ac6SHong Zhang   AppCtx_Water    appctx_water = (*user).appctx_water;
2292bf73ac6SHong Zhang   PetscBool       ghost;
2302bf73ac6SHong Zhang   PetscScalar    *xarr;
2312bf73ac6SHong Zhang   VERTEX_Power    bus;
2322bf73ac6SHong Zhang   VERTEX_Water    vertex;
2332bf73ac6SHong Zhang   void           *component;
2342bf73ac6SHong Zhang   GEN             gen;
235c4762a1bSJed Brown 
236c4762a1bSJed Brown   PetscFunctionBegin;
2379566063dSJacob Faibussowitsch   PetscCall(VecSet(X, 0.0));
2389566063dSJacob Faibussowitsch   PetscCall(VecSet(localX, 0.0));
239c4762a1bSJed Brown 
240c4762a1bSJed Brown   /* Set initial guess for power subnetwork */
2419566063dSJacob Faibussowitsch   PetscCall(DMNetworkGetSubnetwork(networkdm, 0, &nv, &ne, &vtx, &edges));
2429566063dSJacob Faibussowitsch   PetscCall(SetInitialGuess_Power(networkdm, localX, nv, ne, vtx, edges, &appctx_power));
243c4762a1bSJed Brown 
244c4762a1bSJed Brown   /* Set initial guess for water subnetwork */
2459566063dSJacob Faibussowitsch   PetscCall(DMNetworkGetSubnetwork(networkdm, 1, &nv, &ne, &vtx, &edges));
2469566063dSJacob Faibussowitsch   PetscCall(SetInitialGuess_Water(networkdm, localX, nv, ne, vtx, edges, NULL));
247c4762a1bSJed Brown 
2482bf73ac6SHong Zhang   /* Set initial guess at the coupling vertex */
2499566063dSJacob Faibussowitsch   PetscCall(VecGetArray(localX, &xarr));
2509566063dSJacob Faibussowitsch   PetscCall(DMNetworkGetSharedVertices(networkdm, &nv, &vtx));
2512bf73ac6SHong Zhang   for (i = 0; i < nv; i++) {
2529566063dSJacob Faibussowitsch     PetscCall(DMNetworkIsGhostVertex(networkdm, vtx[i], &ghost));
2532bf73ac6SHong Zhang     if (ghost) continue;
2542bf73ac6SHong Zhang 
2559566063dSJacob Faibussowitsch     PetscCall(DMNetworkGetNumComponents(networkdm, vtx[i], &ncomp));
2562bf73ac6SHong Zhang     for (j = 0; j < ncomp; j++) {
2579566063dSJacob Faibussowitsch       PetscCall(DMNetworkGetLocalVecOffset(networkdm, vtx[i], j, &offset));
2589566063dSJacob Faibussowitsch       PetscCall(DMNetworkGetComponent(networkdm, vtx[i], j, &key, (void **)&component, NULL));
2592bf73ac6SHong Zhang       if (key == appctx_power.compkey_bus) {
2602bf73ac6SHong Zhang         bus              = (VERTEX_Power)(component);
2612bf73ac6SHong Zhang         xarr[offset]     = bus->va * PETSC_PI / 180.0;
2622bf73ac6SHong Zhang         xarr[offset + 1] = bus->vm;
2632bf73ac6SHong Zhang       } else if (key == appctx_power.compkey_gen) {
2642bf73ac6SHong Zhang         gen = (GEN)(component);
2652bf73ac6SHong Zhang         if (!gen->status) continue;
2662bf73ac6SHong Zhang         xarr[offset + 1] = gen->vs;
2672bf73ac6SHong Zhang       } else if (key == appctx_water.compkey_vtx) {
2682bf73ac6SHong Zhang         vertex = (VERTEX_Water)(component);
2692bf73ac6SHong Zhang         if (vertex->type == VERTEX_TYPE_JUNCTION) {
2702bf73ac6SHong Zhang           xarr[offset] = 100;
2712bf73ac6SHong Zhang         } else if (vertex->type == VERTEX_TYPE_RESERVOIR) {
2722bf73ac6SHong Zhang           xarr[offset] = vertex->res.head;
2732bf73ac6SHong Zhang         } else {
2742bf73ac6SHong Zhang           xarr[offset] = vertex->tank.initlvl + vertex->tank.elev;
275c4762a1bSJed Brown         }
2762bf73ac6SHong Zhang       }
2772bf73ac6SHong Zhang     }
2782bf73ac6SHong Zhang   }
2799566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(localX, &xarr));
280c4762a1bSJed Brown 
2819566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalBegin(networkdm, localX, ADD_VALUES, X));
2829566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalEnd(networkdm, localX, ADD_VALUES, X));
2833ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
284c4762a1bSJed Brown }
285c4762a1bSJed Brown 
286cc13d412SHong Zhang /* Set coordinates */
287cc13d412SHong Zhang static PetscErrorCode CoordinateVecSetUp(DM dm, Vec coords)
288cc13d412SHong Zhang {
289cc13d412SHong Zhang   DM              dmclone;
290cc13d412SHong Zhang   PetscInt        i, gidx, offset, v, nv, Nsubnet;
291cc13d412SHong Zhang   const PetscInt *vtx;
292cc13d412SHong Zhang   PetscScalar    *carray;
293cc13d412SHong Zhang 
294cc13d412SHong Zhang   PetscFunctionBeginUser;
295cc13d412SHong Zhang   PetscCall(DMGetCoordinateDM(dm, &dmclone));
296cc13d412SHong Zhang   PetscCall(VecGetArrayWrite(coords, &carray));
297cc13d412SHong Zhang   PetscCall(DMNetworkGetNumSubNetworks(dm, NULL, &Nsubnet));
298cc13d412SHong Zhang   for (i = 0; i < Nsubnet; i++) {
299cc13d412SHong Zhang     PetscCall(DMNetworkGetSubnetwork(dm, i, &nv, NULL, &vtx, NULL));
300cc13d412SHong Zhang     for (v = 0; v < nv; v++) {
301cc13d412SHong Zhang       PetscCall(DMNetworkGetGlobalVertexIndex(dm, vtx[v], &gidx));
302cc13d412SHong Zhang       PetscCall(DMNetworkGetLocalVecOffset(dmclone, vtx[v], 0, &offset));
303cc13d412SHong Zhang       switch (gidx) {
304cc13d412SHong Zhang       case 0:
305cc13d412SHong Zhang         carray[offset]     = -1.0;
306cc13d412SHong Zhang         carray[offset + 1] = -1.0;
307cc13d412SHong Zhang         break;
308cc13d412SHong Zhang       case 1:
309cc13d412SHong Zhang         carray[offset]     = -2.0;
310cc13d412SHong Zhang         carray[offset + 1] = 2.0;
311cc13d412SHong Zhang         break;
312cc13d412SHong Zhang       case 2:
313cc13d412SHong Zhang         carray[offset]     = 0.0;
314cc13d412SHong Zhang         carray[offset + 1] = 2.0;
315cc13d412SHong Zhang         break;
316cc13d412SHong Zhang       case 3:
317cc13d412SHong Zhang         carray[offset]     = -1.0;
318cc13d412SHong Zhang         carray[offset + 1] = 0.0;
319cc13d412SHong Zhang         break;
320cc13d412SHong Zhang       case 4:
321cc13d412SHong Zhang         carray[offset]     = 0.0;
322cc13d412SHong Zhang         carray[offset + 1] = 0.0;
323cc13d412SHong Zhang         break;
324cc13d412SHong Zhang       case 5:
325cc13d412SHong Zhang         carray[offset]     = 0.0;
326cc13d412SHong Zhang         carray[offset + 1] = 1.0;
327cc13d412SHong Zhang         break;
328cc13d412SHong Zhang       case 6:
329cc13d412SHong Zhang         carray[offset]     = -1.0;
330cc13d412SHong Zhang         carray[offset + 1] = 1.0;
331cc13d412SHong Zhang         break;
332cc13d412SHong Zhang       case 7:
333cc13d412SHong Zhang         carray[offset]     = -2.0;
334cc13d412SHong Zhang         carray[offset + 1] = 1.0;
335cc13d412SHong Zhang         break;
336cc13d412SHong Zhang       case 8:
337cc13d412SHong Zhang         carray[offset]     = -2.0;
338cc13d412SHong Zhang         carray[offset + 1] = 0.0;
339cc13d412SHong Zhang         break;
340cc13d412SHong Zhang       case 9:
341cc13d412SHong Zhang         carray[offset]     = 1.0;
342cc13d412SHong Zhang         carray[offset + 1] = 0.0;
343cc13d412SHong Zhang         break;
344cc13d412SHong Zhang       case 10:
345cc13d412SHong Zhang         carray[offset]     = 1.0;
346cc13d412SHong Zhang         carray[offset + 1] = -1.0;
347cc13d412SHong Zhang         break;
348cc13d412SHong Zhang       case 11:
349cc13d412SHong Zhang         carray[offset]     = 2.0;
350cc13d412SHong Zhang         carray[offset + 1] = -1.0;
351cc13d412SHong Zhang         break;
352cc13d412SHong Zhang       case 12:
353cc13d412SHong Zhang         carray[offset]     = 2.0;
354cc13d412SHong Zhang         carray[offset + 1] = 0.0;
355cc13d412SHong Zhang         break;
356cc13d412SHong Zhang       case 13:
357cc13d412SHong Zhang         carray[offset]     = 0.0;
358cc13d412SHong Zhang         carray[offset + 1] = -1.0;
359cc13d412SHong Zhang         break;
360cc13d412SHong Zhang       case 14:
361cc13d412SHong Zhang         carray[offset]     = 2.0;
362cc13d412SHong Zhang         carray[offset + 1] = 1.0;
363cc13d412SHong Zhang         break;
364cc13d412SHong Zhang       default:
365cc13d412SHong Zhang         PetscCheck(gidx < 15 && gidx > -1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "gidx %" PetscInt_FMT "must between 0 and 14", gidx);
366cc13d412SHong Zhang       }
367cc13d412SHong Zhang     }
368cc13d412SHong Zhang   }
369cc13d412SHong Zhang   PetscCall(VecRestoreArrayWrite(coords, &carray));
370cc13d412SHong Zhang   PetscFunctionReturn(PETSC_SUCCESS);
371cc13d412SHong Zhang }
372cc13d412SHong Zhang 
373cc13d412SHong Zhang static PetscErrorCode CoordinatePrint(DM dm)
374cc13d412SHong Zhang {
375cc13d412SHong Zhang   DM                 dmclone;
376cc13d412SHong Zhang   PetscInt           cdim, v, off, vglobal, vStart, vEnd;
377cc13d412SHong Zhang   const PetscScalar *carray;
378cc13d412SHong Zhang   Vec                coords;
379cc13d412SHong Zhang   MPI_Comm           comm;
380cc13d412SHong Zhang   PetscMPIInt        rank;
381cc13d412SHong Zhang 
382cc13d412SHong Zhang   PetscFunctionBegin;
383cc13d412SHong Zhang   PetscCall(PetscObjectGetComm((PetscObject)dm, &comm));
384cc13d412SHong Zhang   PetscCallMPI(MPI_Comm_rank(comm, &rank));
385cc13d412SHong Zhang 
386cc13d412SHong Zhang   PetscCall(DMGetCoordinateDM(dm, &dmclone));
387cc13d412SHong Zhang   PetscCall(DMNetworkGetVertexRange(dm, &vStart, &vEnd));
388cc13d412SHong Zhang   PetscCall(DMGetCoordinatesLocal(dm, &coords));
389cc13d412SHong Zhang 
390cc13d412SHong Zhang   PetscCall(DMGetCoordinateDim(dm, &cdim));
391cc13d412SHong Zhang   PetscCall(VecGetArrayRead(coords, &carray));
392cc13d412SHong Zhang 
393cc13d412SHong Zhang   PetscCall(PetscPrintf(MPI_COMM_WORLD, "\nCoordinatePrint, cdim %" PetscInt_FMT ":\n", cdim));
394cc13d412SHong Zhang   PetscCall(PetscSynchronizedPrintf(MPI_COMM_WORLD, "[%i]\n", rank));
395cc13d412SHong Zhang   for (v = vStart; v < vEnd; v++) {
396cc13d412SHong Zhang     PetscCall(DMNetworkGetLocalVecOffset(dmclone, v, 0, &off));
397cc13d412SHong Zhang     PetscCall(DMNetworkGetGlobalVertexIndex(dmclone, v, &vglobal));
398cc13d412SHong Zhang     switch (cdim) {
399cc13d412SHong Zhang     case 2:
400cc13d412SHong Zhang       PetscCall(PetscSynchronizedPrintf(MPI_COMM_WORLD, "Vertex: %" PetscInt_FMT ", x =  %f y = %f \n", vglobal, (double)PetscRealPart(carray[off]), (double)PetscRealPart(carray[off + 1])));
401cc13d412SHong Zhang       break;
402cc13d412SHong Zhang     default:
403cc13d412SHong Zhang       PetscCheck(cdim == 2, MPI_COMM_WORLD, PETSC_ERR_SUP, "Only supports Network embedding dimension of 2, not supplied  %" PetscInt_FMT, cdim);
404cc13d412SHong Zhang       break;
405cc13d412SHong Zhang     }
406cc13d412SHong Zhang   }
407cc13d412SHong Zhang   PetscCall(PetscSynchronizedFlush(MPI_COMM_WORLD, NULL));
408cc13d412SHong Zhang   PetscCall(VecRestoreArrayRead(coords, &carray));
409cc13d412SHong Zhang   PetscFunctionReturn(PETSC_SUCCESS);
410cc13d412SHong Zhang }
411cc13d412SHong Zhang 
412d71ae5a4SJacob Faibussowitsch int main(int argc, char **argv)
413d71ae5a4SJacob Faibussowitsch {
414cc13d412SHong Zhang   DM                  networkdm, dmclone;
415c4762a1bSJed Brown   PetscLogStage       stage[4];
416d5c9c0c4SHong Zhang   PetscMPIInt         rank, size;
4172bf73ac6SHong Zhang   PetscInt            Nsubnet = 2, numVertices[2], numEdges[2], i, j, nv, ne, it_max = 10;
418cc13d412SHong Zhang   PetscInt            vStart, vEnd, compkey;
419c4762a1bSJed Brown   const PetscInt     *vtx, *edges;
420cc13d412SHong Zhang   Vec                 X, F, coords;
421c4762a1bSJed Brown   SNES                snes, snes_power, snes_water;
422c4762a1bSJed Brown   Mat                 Jac;
423cc13d412SHong Zhang   PetscBool           ghost, viewJ = PETSC_FALSE, viewX = PETSC_FALSE, test = PETSC_FALSE, distribute = PETSC_TRUE, flg, printCoord = PETSC_FALSE, viewCSV = PETSC_FALSE;
424c4762a1bSJed Brown   UserCtx             user;
425c4762a1bSJed Brown   SNESConvergedReason reason;
426c4762a1bSJed Brown 
427c4762a1bSJed Brown   /* Power subnetwork */
428c4762a1bSJed Brown   UserCtx_Power *appctx_power                    = &user.appctx_power;
429c4762a1bSJed Brown   char           pfdata_file[PETSC_MAX_PATH_LEN] = "power/case9.m";
430c4762a1bSJed Brown   PFDATA        *pfdata                          = NULL;
4312bf73ac6SHong Zhang   PetscInt       genj, loadj, *edgelist_power = NULL, power_netnum;
432c4762a1bSJed Brown   PetscScalar    Sbase = 0.0;
433c4762a1bSJed Brown 
434c4762a1bSJed Brown   /* Water subnetwork */
435c4762a1bSJed Brown   AppCtx_Water *appctx_water                       = &user.appctx_water;
436c4762a1bSJed Brown   WATERDATA    *waterdata                          = NULL;
437c4762a1bSJed Brown   char          waterdata_file[PETSC_MAX_PATH_LEN] = "water/sample1.inp";
4382bf73ac6SHong Zhang   PetscInt     *edgelist_water                     = NULL, water_netnum;
439c4762a1bSJed Brown 
4402bf73ac6SHong Zhang   /* Shared vertices between subnetworks */
4412bf73ac6SHong Zhang   PetscInt power_svtx, water_svtx;
442c4762a1bSJed Brown 
443327415f7SBarry Smith   PetscFunctionBeginUser;
4449566063dSJacob Faibussowitsch   PetscCall(PetscInitialize(&argc, &argv, "ex1options", help));
4459566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD, &rank));
4469566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PETSC_COMM_WORLD, &size));
447c4762a1bSJed Brown 
448c4762a1bSJed Brown   /* (1) Read Data - Only rank 0 reads the data */
4499566063dSJacob Faibussowitsch   PetscCall(PetscLogStageRegister("Read Data", &stage[0]));
4509566063dSJacob Faibussowitsch   PetscCall(PetscLogStagePush(stage[0]));
451c4762a1bSJed Brown 
4522bf73ac6SHong Zhang   for (i = 0; i < Nsubnet; i++) {
453c4762a1bSJed Brown     numVertices[i] = 0;
454c4762a1bSJed Brown     numEdges[i]    = 0;
455c4762a1bSJed Brown   }
456c4762a1bSJed Brown 
4572bf73ac6SHong Zhang   /* All processes READ THE DATA FOR THE FIRST SUBNETWORK: Electric Power Grid */
4582bf73ac6SHong Zhang   /* Used for shared vertex, because currently the coupling info must be available in all processes!!! */
4599566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetString(NULL, NULL, "-pfdata", pfdata_file, PETSC_MAX_PATH_LEN - 1, NULL));
4609566063dSJacob Faibussowitsch   PetscCall(PetscNew(&pfdata));
4619566063dSJacob Faibussowitsch   PetscCall(PFReadMatPowerData(pfdata, pfdata_file));
46248a46eb9SPierre 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));
463c4762a1bSJed Brown   Sbase = pfdata->sbase;
4642bf73ac6SHong Zhang   if (rank == 0) { /* proc[0] will create Electric Power Grid */
465c4762a1bSJed Brown     numEdges[0]    = pfdata->nbranch;
466c4762a1bSJed Brown     numVertices[0] = pfdata->nbus;
467c4762a1bSJed Brown 
4689566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(2 * numEdges[0], &edgelist_power));
4699566063dSJacob Faibussowitsch     PetscCall(GetListofEdges_Power(pfdata, edgelist_power));
470c4762a1bSJed Brown   }
471c4762a1bSJed Brown   /* Broadcast power Sbase to all processors */
4729566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Bcast(&Sbase, 1, MPIU_SCALAR, 0, PETSC_COMM_WORLD));
473c4762a1bSJed Brown   appctx_power->Sbase     = Sbase;
474c4762a1bSJed Brown   appctx_power->jac_error = PETSC_FALSE;
475c4762a1bSJed Brown   /* If external option activated. Introduce error in jacobian */
4769566063dSJacob Faibussowitsch   PetscCall(PetscOptionsHasName(NULL, NULL, "-jac_error", &appctx_power->jac_error));
477c4762a1bSJed Brown 
4782bf73ac6SHong Zhang   /* All processes READ THE DATA FOR THE SECOND SUBNETWORK: Water */
4792bf73ac6SHong Zhang   /* Used for shared vertex, because currently the coupling info must be available in all processes!!! */
4809566063dSJacob Faibussowitsch   PetscCall(PetscNew(&waterdata));
4819566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetString(NULL, NULL, "-waterdata", waterdata_file, PETSC_MAX_PATH_LEN - 1, NULL));
4829566063dSJacob Faibussowitsch   PetscCall(WaterReadData(waterdata, waterdata_file));
4832bf73ac6SHong Zhang   if (size == 1 || (size > 1 && rank == 1)) {
4849566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(2 * waterdata->nedge, &edgelist_water));
4859566063dSJacob Faibussowitsch     PetscCall(GetListofEdges_Water(waterdata, edgelist_water));
486c4762a1bSJed Brown     numEdges[1]    = waterdata->nedge;
487c4762a1bSJed Brown     numVertices[1] = waterdata->nvertex;
488c4762a1bSJed Brown   }
4893ba16761SJacob Faibussowitsch   PetscCall(PetscLogStagePop());
490c4762a1bSJed Brown 
4912bf73ac6SHong Zhang   /* (2) Create a network consist of two subnetworks */
4929566063dSJacob Faibussowitsch   PetscCall(PetscLogStageRegister("Net Setup", &stage[1]));
4939566063dSJacob Faibussowitsch   PetscCall(PetscLogStagePush(stage[1]));
494c4762a1bSJed Brown 
495cc13d412SHong Zhang   PetscCall(PetscOptionsGetBool(NULL, NULL, "-viewCSV", &viewCSV, NULL));
496cc13d412SHong Zhang   PetscCall(PetscOptionsGetBool(NULL, NULL, "-printCoord", &printCoord, NULL));
4979566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(NULL, NULL, "-test", &test, NULL));
4989566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(NULL, NULL, "-distribute", &distribute, NULL));
499c4762a1bSJed Brown 
500c4762a1bSJed Brown   /* Create an empty network object */
5019566063dSJacob Faibussowitsch   PetscCall(DMNetworkCreate(PETSC_COMM_WORLD, &networkdm));
502c4762a1bSJed Brown 
503c4762a1bSJed Brown   /* Register the components in the network */
5049566063dSJacob Faibussowitsch   PetscCall(DMNetworkRegisterComponent(networkdm, "branchstruct", sizeof(struct _p_EDGE_Power), &appctx_power->compkey_branch));
5059566063dSJacob Faibussowitsch   PetscCall(DMNetworkRegisterComponent(networkdm, "busstruct", sizeof(struct _p_VERTEX_Power), &appctx_power->compkey_bus));
5069566063dSJacob Faibussowitsch   PetscCall(DMNetworkRegisterComponent(networkdm, "genstruct", sizeof(struct _p_GEN), &appctx_power->compkey_gen));
5079566063dSJacob Faibussowitsch   PetscCall(DMNetworkRegisterComponent(networkdm, "loadstruct", sizeof(struct _p_LOAD), &appctx_power->compkey_load));
508c4762a1bSJed Brown 
5099566063dSJacob Faibussowitsch   PetscCall(DMNetworkRegisterComponent(networkdm, "edge_water", sizeof(struct _p_EDGE_Water), &appctx_water->compkey_edge));
5109566063dSJacob Faibussowitsch   PetscCall(DMNetworkRegisterComponent(networkdm, "vertex_water", sizeof(struct _p_VERTEX_Water), &appctx_water->compkey_vtx));
511cc13d412SHong Zhang 
51263a3b9bcSJacob 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]));
5139566063dSJacob Faibussowitsch   PetscCall(PetscSynchronizedFlush(PETSC_COMM_WORLD, PETSC_STDOUT));
514c4762a1bSJed Brown 
5159566063dSJacob Faibussowitsch   PetscCall(DMNetworkSetNumSubNetworks(networkdm, PETSC_DECIDE, Nsubnet));
5169566063dSJacob Faibussowitsch   PetscCall(DMNetworkAddSubnetwork(networkdm, "power", numEdges[0], edgelist_power, &power_netnum));
5179566063dSJacob Faibussowitsch   PetscCall(DMNetworkAddSubnetwork(networkdm, "water", numEdges[1], edgelist_water, &water_netnum));
518c4762a1bSJed Brown 
5192bf73ac6SHong Zhang   /* vertex subnet[0].4 shares with vertex subnet[1].0 */
5209371c9d4SSatish Balay   power_svtx = 4;
5219371c9d4SSatish Balay   water_svtx = 0;
5229566063dSJacob Faibussowitsch   PetscCall(DMNetworkAddSharedVertices(networkdm, power_netnum, water_netnum, 1, &power_svtx, &water_svtx));
523c4762a1bSJed Brown 
524c4762a1bSJed Brown   /* Set up the network layout */
5259566063dSJacob Faibussowitsch   PetscCall(DMNetworkLayoutSetUp(networkdm));
526c4762a1bSJed Brown 
527c4762a1bSJed Brown   /* ADD VARIABLES AND COMPONENTS FOR THE POWER SUBNETWORK */
5289371c9d4SSatish Balay   genj  = 0;
5299371c9d4SSatish Balay   loadj = 0;
5309566063dSJacob Faibussowitsch   PetscCall(DMNetworkGetSubnetwork(networkdm, power_netnum, &nv, &ne, &vtx, &edges));
5312bf73ac6SHong Zhang 
53248a46eb9SPierre Jolivet   for (i = 0; i < ne; i++) PetscCall(DMNetworkAddComponent(networkdm, edges[i], appctx_power->compkey_branch, &pfdata->branch[i], 0));
533c4762a1bSJed Brown 
534c4762a1bSJed Brown   for (i = 0; i < nv; i++) {
5359566063dSJacob Faibussowitsch     PetscCall(DMNetworkIsSharedVertex(networkdm, vtx[i], &flg));
5362bf73ac6SHong Zhang     if (flg) continue;
5372bf73ac6SHong Zhang 
5389566063dSJacob Faibussowitsch     PetscCall(DMNetworkAddComponent(networkdm, vtx[i], appctx_power->compkey_bus, &pfdata->bus[i], 2));
539c4762a1bSJed Brown     if (pfdata->bus[i].ngen) {
54048a46eb9SPierre Jolivet       for (j = 0; j < pfdata->bus[i].ngen; j++) PetscCall(DMNetworkAddComponent(networkdm, vtx[i], appctx_power->compkey_gen, &pfdata->gen[genj++], 0));
541c4762a1bSJed Brown     }
542c4762a1bSJed Brown     if (pfdata->bus[i].nload) {
54348a46eb9SPierre Jolivet       for (j = 0; j < pfdata->bus[i].nload; j++) PetscCall(DMNetworkAddComponent(networkdm, vtx[i], appctx_power->compkey_load, &pfdata->load[loadj++], 0));
544c4762a1bSJed Brown     }
545c4762a1bSJed Brown   }
546c4762a1bSJed Brown 
547c4762a1bSJed Brown   /* ADD VARIABLES AND COMPONENTS FOR THE WATER SUBNETWORK */
5489566063dSJacob Faibussowitsch   PetscCall(DMNetworkGetSubnetwork(networkdm, water_netnum, &nv, &ne, &vtx, &edges));
54948a46eb9SPierre Jolivet   for (i = 0; i < ne; i++) PetscCall(DMNetworkAddComponent(networkdm, edges[i], appctx_water->compkey_edge, &waterdata->edge[i], 0));
550c4762a1bSJed Brown 
551c4762a1bSJed Brown   for (i = 0; i < nv; i++) {
5529566063dSJacob Faibussowitsch     PetscCall(DMNetworkIsSharedVertex(networkdm, vtx[i], &flg));
5532bf73ac6SHong Zhang     if (flg) continue;
5542bf73ac6SHong Zhang 
5559566063dSJacob Faibussowitsch     PetscCall(DMNetworkAddComponent(networkdm, vtx[i], appctx_water->compkey_vtx, &waterdata->vertex[i], 1));
556c4762a1bSJed Brown   }
5572bf73ac6SHong Zhang 
558eac198afSGetnet   /* 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 */
5599566063dSJacob Faibussowitsch   PetscCall(DMNetworkGetSharedVertices(networkdm, &nv, &vtx));
5602bf73ac6SHong Zhang   for (i = 0; i < nv; i++) {
5612bf73ac6SHong Zhang     /* power */
5629566063dSJacob Faibussowitsch     PetscCall(DMNetworkAddComponent(networkdm, vtx[i], appctx_power->compkey_bus, &pfdata->bus[4], 2));
5632bf73ac6SHong Zhang     /* bus[4] is a load, add its component */
5649566063dSJacob Faibussowitsch     PetscCall(DMNetworkAddComponent(networkdm, vtx[i], appctx_power->compkey_load, &pfdata->load[0], 0));
5652bf73ac6SHong Zhang 
5662bf73ac6SHong Zhang     /* water */
5679566063dSJacob Faibussowitsch     PetscCall(DMNetworkAddComponent(networkdm, vtx[i], appctx_water->compkey_vtx, &waterdata->vertex[0], 1));
568c4762a1bSJed Brown   }
569c4762a1bSJed Brown 
570cc13d412SHong Zhang   /* Set coordinates for visualization */
571cc13d412SHong Zhang   PetscCall(DMSetCoordinateDim(networkdm, 2));
572cc13d412SHong Zhang   PetscCall(DMGetCoordinateDM(networkdm, &dmclone));
573cc13d412SHong Zhang   PetscCall(DMNetworkGetVertexRange(dmclone, &vStart, &vEnd));
574cc13d412SHong Zhang   PetscCall(DMNetworkRegisterComponent(dmclone, "coordinates", 0, &compkey));
575*aa624791SPierre Jolivet   for (i = vStart; i < vEnd; i++) PetscCall(DMNetworkAddComponent(dmclone, i, compkey, NULL, 2));
576cc13d412SHong Zhang   PetscCall(DMNetworkFinalizeComponents(dmclone));
577cc13d412SHong Zhang 
578cc13d412SHong Zhang   PetscCall(DMCreateLocalVector(dmclone, &coords));
579cc13d412SHong Zhang   PetscCall(DMSetCoordinatesLocal(networkdm, coords)); /* set/get coords to/from networkdm */
580cc13d412SHong Zhang   PetscCall(CoordinateVecSetUp(networkdm, coords));
581cc13d412SHong Zhang   if (printCoord) PetscCall(CoordinatePrint(networkdm));
582cc13d412SHong Zhang 
583c4762a1bSJed Brown   /* Set up DM for use */
5849566063dSJacob Faibussowitsch   PetscCall(DMSetUp(networkdm));
585c4762a1bSJed Brown 
586c4762a1bSJed Brown   /* Free user objects */
5879566063dSJacob Faibussowitsch   PetscCall(PetscFree(edgelist_power));
5889566063dSJacob Faibussowitsch   PetscCall(PetscFree(pfdata->bus));
5899566063dSJacob Faibussowitsch   PetscCall(PetscFree(pfdata->gen));
5909566063dSJacob Faibussowitsch   PetscCall(PetscFree(pfdata->branch));
5919566063dSJacob Faibussowitsch   PetscCall(PetscFree(pfdata->load));
5929566063dSJacob Faibussowitsch   PetscCall(PetscFree(pfdata));
5932bf73ac6SHong Zhang 
5949566063dSJacob Faibussowitsch   PetscCall(PetscFree(edgelist_water));
5959566063dSJacob Faibussowitsch   PetscCall(PetscFree(waterdata->vertex));
5969566063dSJacob Faibussowitsch   PetscCall(PetscFree(waterdata->edge));
5979566063dSJacob Faibussowitsch   PetscCall(PetscFree(waterdata));
598c4762a1bSJed Brown 
599d5c9c0c4SHong Zhang   /* Re-distribute networkdm to multiple processes for better job balance */
600cc13d412SHong Zhang   if (distribute) {
6019566063dSJacob Faibussowitsch     PetscCall(DMNetworkDistribute(&networkdm, 0));
602cc13d412SHong Zhang 
603cc13d412SHong Zhang     if (printCoord) PetscCall(CoordinatePrint(networkdm));
604cc13d412SHong Zhang     if (viewCSV) { /* CSV View of network with coordinates */
605cc13d412SHong Zhang       PetscCall(PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD, PETSC_VIEWER_ASCII_CSV));
6069566063dSJacob Faibussowitsch       PetscCall(DMView(networkdm, PETSC_VIEWER_STDOUT_WORLD));
607cc13d412SHong Zhang       PetscCall(PetscViewerPopFormat(PETSC_VIEWER_STDOUT_WORLD));
608c4762a1bSJed Brown     }
609d5c9c0c4SHong Zhang   }
610cc13d412SHong Zhang   PetscCall(VecDestroy(&coords));
611c4762a1bSJed Brown 
6122bf73ac6SHong Zhang   /* Test DMNetworkGetSubnetwork() and DMNetworkGetSubnetworkSharedVertices() */
613c4762a1bSJed Brown   if (test) {
6142bf73ac6SHong Zhang     PetscInt v, gidx;
6159566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Barrier(PETSC_COMM_WORLD));
6162bf73ac6SHong Zhang     for (i = 0; i < Nsubnet; i++) {
6179566063dSJacob Faibussowitsch       PetscCall(DMNetworkGetSubnetwork(networkdm, i, &nv, &ne, &vtx, &edges));
61863a3b9bcSJacob Faibussowitsch       PetscCall(PetscPrintf(PETSC_COMM_SELF, "[%d] After distribute, subnet[%" PetscInt_FMT "] ne %" PetscInt_FMT ", nv %" PetscInt_FMT "\n", rank, i, ne, nv));
6199566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Barrier(PETSC_COMM_WORLD));
620c4762a1bSJed Brown 
6212bf73ac6SHong Zhang       for (v = 0; v < nv; v++) {
6229566063dSJacob Faibussowitsch         PetscCall(DMNetworkIsGhostVertex(networkdm, vtx[v], &ghost));
6239566063dSJacob Faibussowitsch         PetscCall(DMNetworkGetGlobalVertexIndex(networkdm, vtx[v], &gidx));
62463a3b9bcSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "[%d] subnet[%" PetscInt_FMT "] v %" PetscInt_FMT " %" PetscInt_FMT "; ghost %d\n", rank, i, vtx[v], gidx, ghost));
625c4762a1bSJed Brown       }
6269566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Barrier(PETSC_COMM_WORLD));
627c4762a1bSJed Brown     }
6289566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Barrier(PETSC_COMM_WORLD));
6292bf73ac6SHong Zhang 
6309566063dSJacob Faibussowitsch     PetscCall(DMNetworkGetSharedVertices(networkdm, &nv, &vtx));
63163a3b9bcSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_SELF, "[%d] After distribute, num of shared vertices nsv = %" PetscInt_FMT "\n", rank, nv));
6322bf73ac6SHong Zhang     for (v = 0; v < nv; v++) {
6339566063dSJacob Faibussowitsch       PetscCall(DMNetworkGetGlobalVertexIndex(networkdm, vtx[v], &gidx));
63463a3b9bcSJacob Faibussowitsch       PetscCall(PetscPrintf(PETSC_COMM_SELF, "[%d] sv %" PetscInt_FMT ", gidx=%" PetscInt_FMT "\n", rank, vtx[v], gidx));
6352bf73ac6SHong Zhang     }
6369566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Barrier(PETSC_COMM_WORLD));
637c4762a1bSJed Brown   }
638c4762a1bSJed Brown 
6392bf73ac6SHong Zhang   /* Create solution vector X */
6409566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector(networkdm, &X));
6419566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(X, &F));
6429566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(networkdm, &user.localXold));
6433ba16761SJacob Faibussowitsch   PetscCall(PetscLogStagePop());
644c4762a1bSJed Brown 
645c4762a1bSJed Brown   /* (3) Setup Solvers */
6469566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(NULL, NULL, "-viewJ", &viewJ, NULL));
6479566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(NULL, NULL, "-viewX", &viewX, NULL));
648c4762a1bSJed Brown 
6499566063dSJacob Faibussowitsch   PetscCall(PetscLogStageRegister("SNES Setup", &stage[2]));
6509566063dSJacob Faibussowitsch   PetscCall(PetscLogStagePush(stage[2]));
651c4762a1bSJed Brown 
6529566063dSJacob Faibussowitsch   PetscCall(SetInitialGuess(networkdm, X, &user));
653c4762a1bSJed Brown 
654c4762a1bSJed Brown   /* Create coupled snes */
6559566063dSJacob Faibussowitsch   PetscCall(PetscPrintf(PETSC_COMM_WORLD, "SNES_coupled setup ......\n"));
6562bf73ac6SHong Zhang   user.subsnes_id = Nsubnet;
6579566063dSJacob Faibussowitsch   PetscCall(SNESCreate(PETSC_COMM_WORLD, &snes));
6589566063dSJacob Faibussowitsch   PetscCall(SNESSetDM(snes, networkdm));
6599566063dSJacob Faibussowitsch   PetscCall(SNESSetOptionsPrefix(snes, "coupled_"));
6609566063dSJacob Faibussowitsch   PetscCall(SNESSetFunction(snes, F, FormFunction, &user));
6619566063dSJacob Faibussowitsch   PetscCall(SNESMonitorSet(snes, UserMonitor, &user, NULL));
6629566063dSJacob Faibussowitsch   PetscCall(SNESSetFromOptions(snes));
663c4762a1bSJed Brown 
664c4762a1bSJed Brown   if (viewJ) {
665c4762a1bSJed Brown     /* View Jac structure */
6669566063dSJacob Faibussowitsch     PetscCall(SNESGetJacobian(snes, &Jac, NULL, NULL, NULL));
6679566063dSJacob Faibussowitsch     PetscCall(MatView(Jac, PETSC_VIEWER_DRAW_WORLD));
668c4762a1bSJed Brown   }
669c4762a1bSJed Brown 
670c4762a1bSJed Brown   if (viewX) {
6719566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Solution:\n"));
6729566063dSJacob Faibussowitsch     PetscCall(VecView(X, PETSC_VIEWER_STDOUT_WORLD));
673c4762a1bSJed Brown   }
674c4762a1bSJed Brown 
675c4762a1bSJed Brown   if (viewJ) {
676c4762a1bSJed Brown     /* View assembled Jac */
6779566063dSJacob Faibussowitsch     PetscCall(MatView(Jac, PETSC_VIEWER_DRAW_WORLD));
678c4762a1bSJed Brown   }
679c4762a1bSJed Brown 
680c4762a1bSJed Brown   /* Create snes_power */
6819566063dSJacob Faibussowitsch   PetscCall(PetscPrintf(PETSC_COMM_WORLD, "SNES_power setup ......\n"));
682c4762a1bSJed Brown 
683c4762a1bSJed Brown   user.subsnes_id = 0;
6849566063dSJacob Faibussowitsch   PetscCall(SNESCreate(PETSC_COMM_WORLD, &snes_power));
6859566063dSJacob Faibussowitsch   PetscCall(SNESSetDM(snes_power, networkdm));
6869566063dSJacob Faibussowitsch   PetscCall(SNESSetOptionsPrefix(snes_power, "power_"));
6879566063dSJacob Faibussowitsch   PetscCall(SNESSetFunction(snes_power, F, FormFunction, &user));
6889566063dSJacob Faibussowitsch   PetscCall(SNESMonitorSet(snes_power, UserMonitor, &user, NULL));
689c4762a1bSJed Brown 
690c4762a1bSJed Brown   /* Use user-provide Jacobian */
6919566063dSJacob Faibussowitsch   PetscCall(DMCreateMatrix(networkdm, &Jac));
6929566063dSJacob Faibussowitsch   PetscCall(SNESSetJacobian(snes_power, Jac, Jac, FormJacobian_subPower, &user));
6939566063dSJacob Faibussowitsch   PetscCall(SNESSetFromOptions(snes_power));
694c4762a1bSJed Brown 
695c4762a1bSJed Brown   if (viewX) {
6969566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Power Solution:\n"));
6979566063dSJacob Faibussowitsch     PetscCall(VecView(X, PETSC_VIEWER_STDOUT_WORLD));
698c4762a1bSJed Brown   }
699c4762a1bSJed Brown   if (viewJ) {
7009566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Power Jac:\n"));
7019566063dSJacob Faibussowitsch     PetscCall(SNESGetJacobian(snes_power, &Jac, NULL, NULL, NULL));
7029566063dSJacob Faibussowitsch     PetscCall(MatView(Jac, PETSC_VIEWER_DRAW_WORLD));
7039566063dSJacob Faibussowitsch     /* PetscCall(MatView(Jac,PETSC_VIEWER_STDOUT_WORLD)); */
704c4762a1bSJed Brown   }
705c4762a1bSJed Brown 
706c4762a1bSJed Brown   /* Create snes_water */
7079566063dSJacob Faibussowitsch   PetscCall(PetscPrintf(PETSC_COMM_WORLD, "SNES_water setup......\n"));
708c4762a1bSJed Brown 
709c4762a1bSJed Brown   user.subsnes_id = 1;
7109566063dSJacob Faibussowitsch   PetscCall(SNESCreate(PETSC_COMM_WORLD, &snes_water));
7119566063dSJacob Faibussowitsch   PetscCall(SNESSetDM(snes_water, networkdm));
7129566063dSJacob Faibussowitsch   PetscCall(SNESSetOptionsPrefix(snes_water, "water_"));
7139566063dSJacob Faibussowitsch   PetscCall(SNESSetFunction(snes_water, F, FormFunction, &user));
7149566063dSJacob Faibussowitsch   PetscCall(SNESMonitorSet(snes_water, UserMonitor, &user, NULL));
7159566063dSJacob Faibussowitsch   PetscCall(SNESSetFromOptions(snes_water));
716c4762a1bSJed Brown 
717c4762a1bSJed Brown   if (viewX) {
7189566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Water Solution:\n"));
7199566063dSJacob Faibussowitsch     PetscCall(VecView(X, PETSC_VIEWER_STDOUT_WORLD));
720c4762a1bSJed Brown   }
7219566063dSJacob Faibussowitsch   PetscCall(PetscLogStagePop());
722c4762a1bSJed Brown 
723c4762a1bSJed Brown   /* (4) Solve */
7249566063dSJacob Faibussowitsch   PetscCall(PetscLogStageRegister("SNES Solve", &stage[3]));
7259566063dSJacob Faibussowitsch   PetscCall(PetscLogStagePush(stage[3]));
726c4762a1bSJed Brown   user.it = 0;
727c4762a1bSJed Brown   reason  = SNES_DIVERGED_DTOL;
728c4762a1bSJed Brown   while (user.it < it_max && (PetscInt)reason < 0) {
729c4762a1bSJed Brown #if 0
730c4762a1bSJed Brown     user.subsnes_id = 0;
7319566063dSJacob Faibussowitsch     PetscCall(SNESSolve(snes_power,NULL,X));
732c4762a1bSJed Brown 
733c4762a1bSJed Brown     user.subsnes_id = 1;
7349566063dSJacob Faibussowitsch     PetscCall(SNESSolve(snes_water,NULL,X));
735c4762a1bSJed Brown #endif
7362bf73ac6SHong Zhang     user.subsnes_id = Nsubnet;
7379566063dSJacob Faibussowitsch     PetscCall(SNESSolve(snes, NULL, X));
738c4762a1bSJed Brown 
7399566063dSJacob Faibussowitsch     PetscCall(SNESGetConvergedReason(snes, &reason));
740c4762a1bSJed Brown     user.it++;
741c4762a1bSJed Brown   }
74263a3b9bcSJacob Faibussowitsch   PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Coupled_SNES converged in %" PetscInt_FMT " iterations\n", user.it));
743c4762a1bSJed Brown   if (viewX) {
7449566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Final Solution:\n"));
7459566063dSJacob Faibussowitsch     PetscCall(VecView(X, PETSC_VIEWER_STDOUT_WORLD));
746c4762a1bSJed Brown   }
7479566063dSJacob Faibussowitsch   PetscCall(PetscLogStagePop());
748c4762a1bSJed Brown 
749c4762a1bSJed Brown   /* Free objects */
750c4762a1bSJed Brown   /* -------------*/
7519566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&X));
7529566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&F));
7539566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(networkdm, &user.localXold));
754c4762a1bSJed Brown 
7559566063dSJacob Faibussowitsch   PetscCall(SNESDestroy(&snes));
7569566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Jac));
7579566063dSJacob Faibussowitsch   PetscCall(SNESDestroy(&snes_power));
7589566063dSJacob Faibussowitsch   PetscCall(SNESDestroy(&snes_water));
759c4762a1bSJed Brown 
7609566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&networkdm));
7619566063dSJacob Faibussowitsch   PetscCall(PetscFinalize());
762b122ec5aSJacob Faibussowitsch   return 0;
763c4762a1bSJed Brown }
764c4762a1bSJed Brown 
765c4762a1bSJed Brown /*TEST
766c4762a1bSJed Brown 
767c4762a1bSJed Brown    build:
768dfd57a17SPierre Jolivet      requires: !complex double defined(PETSC_HAVE_ATTRIBUTEALIGNED)
769c4762a1bSJed Brown      depends: power/PFReadData.c power/pffunctions.c water/waterreaddata.c water/waterfunctions.c
770c4762a1bSJed Brown 
771c4762a1bSJed Brown    test:
772cc13d412SHong Zhang       args: -coupled_snes_converged_reason -options_left no -dmnetwork_view
773c4762a1bSJed Brown       localrunfiles: ex1options power/case9.m water/sample1.inp
774c4762a1bSJed Brown       output_file: output/ex1.out
775c4762a1bSJed Brown 
776c4762a1bSJed Brown    test:
777c4762a1bSJed Brown       suffix: 2
778c4762a1bSJed Brown       nsize: 3
7792bf73ac6SHong Zhang       args: -coupled_snes_converged_reason -options_left no -petscpartitioner_type parmetis
780c4762a1bSJed Brown       localrunfiles: ex1options power/case9.m water/sample1.inp
781d5c9c0c4SHong Zhang       output_file: output/ex1_2.out
7822bf73ac6SHong Zhang       requires: parmetis
7832bf73ac6SHong Zhang 
784cc13d412SHong Zhang    test:
785cc13d412SHong Zhang       suffix: 3
786cc13d412SHong Zhang       nsize: 3
787cc13d412SHong Zhang       args: -coupled_snes_converged_reason -options_left no -distribute false
788cc13d412SHong Zhang       localrunfiles: ex1options power/case9.m water/sample1.inp
789cc13d412SHong Zhang       output_file: output/ex1_2.out
790d5c9c0c4SHong Zhang 
791d5c9c0c4SHong Zhang    test:
7922bf73ac6SHong Zhang       suffix: 4
7932bf73ac6SHong Zhang       nsize: 4
794cc13d412SHong Zhang       args: -coupled_snes_converged_reason -options_left no -petscpartitioner_type simple -dmnetwork_view -dmnetwork_view_distributed
795d5c9c0c4SHong Zhang       localrunfiles: ex1options power/case9.m water/sample1.inp
7962bf73ac6SHong Zhang       output_file: output/ex1_4.out
797c4762a1bSJed Brown 
798cc13d412SHong Zhang    test:
799cc13d412SHong Zhang       suffix: 5
800cc13d412SHong Zhang       args: -coupled_snes_converged_reason -options_left no -viewCSV
801cc13d412SHong Zhang       localrunfiles: ex1options power/case9.m water/sample1.inp
802cc13d412SHong Zhang       output_file: output/ex1_5.out
803cc13d412SHong Zhang 
804cc13d412SHong Zhang    test:
805cc13d412SHong Zhang       suffix: 6
806cc13d412SHong Zhang       nsize: 3
807cc13d412SHong Zhang       args: -coupled_snes_converged_reason -options_left no -petscpartitioner_type parmetis -dmnetwork_view_distributed draw:null
808cc13d412SHong Zhang       localrunfiles: ex1options power/case9.m water/sample1.inp
809cc13d412SHong Zhang       output_file: output/ex1_2.out
810cc13d412SHong Zhang       requires: parmetis
811cc13d412SHong Zhang 
812c4762a1bSJed Brown TEST*/
813