xref: /petsc/src/snes/tutorials/network/ex1.c (revision 48a46eb9bd028bec07ec0f396b1a3abb43f14558)
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 
199371c9d4SSatish Balay PetscErrorCode UserMonitor(SNES snes, PetscInt its, PetscReal fnorm, void *appctx) {
20c4762a1bSJed Brown   UserCtx    *user = (UserCtx *)appctx;
21c4762a1bSJed Brown   Vec         X, localXold = user->localXold;
22c4762a1bSJed Brown   DM          networkdm;
23c4762a1bSJed Brown   PetscMPIInt rank;
24c4762a1bSJed Brown   MPI_Comm    comm;
25c4762a1bSJed Brown 
26c4762a1bSJed Brown   PetscFunctionBegin;
279566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)snes, &comm));
289566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
29c4762a1bSJed Brown #if 0
30dd400576SPatrick Sanan   if (rank == 0) {
31c4762a1bSJed Brown     PetscInt       subsnes_id = user->subsnes_id;
32c4762a1bSJed Brown     if (subsnes_id == 2) {
3363a3b9bcSJacob Faibussowitsch       PetscCall(PetscPrintf(PETSC_COMM_SELF," it %" PetscInt_FMT ", subsnes_id %" PetscInt_FMT ", fnorm %g\n",user->it,user->subsnes_id,(double)fnorm));
34c4762a1bSJed Brown     } else {
3563a3b9bcSJacob Faibussowitsch       PetscCall(PetscPrintf(PETSC_COMM_SELF,"       subsnes_id %" PetscInt_FMT ", fnorm %g\n",user->subsnes_id,(double)fnorm));
36c4762a1bSJed Brown     }
37c4762a1bSJed Brown   }
38c4762a1bSJed Brown #endif
399566063dSJacob Faibussowitsch   PetscCall(SNESGetSolution(snes, &X));
409566063dSJacob Faibussowitsch   PetscCall(SNESGetDM(snes, &networkdm));
419566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalBegin(networkdm, X, INSERT_VALUES, localXold));
429566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalEnd(networkdm, X, INSERT_VALUES, localXold));
43c4762a1bSJed Brown   PetscFunctionReturn(0);
44c4762a1bSJed Brown }
45c4762a1bSJed Brown 
469371c9d4SSatish Balay PetscErrorCode FormJacobian_subPower(SNES snes, Vec X, Mat J, Mat Jpre, void *appctx) {
47c4762a1bSJed Brown   DM              networkdm;
48c4762a1bSJed Brown   Vec             localX;
49c4762a1bSJed Brown   PetscInt        nv, ne, i, j, offset, nvar, row;
50c4762a1bSJed Brown   const PetscInt *vtx, *edges;
51c4762a1bSJed Brown   PetscBool       ghostvtex;
52c4762a1bSJed Brown   PetscScalar     one = 1.0;
53c4762a1bSJed Brown   PetscMPIInt     rank;
54c4762a1bSJed Brown   MPI_Comm        comm;
55c4762a1bSJed Brown 
56c4762a1bSJed Brown   PetscFunctionBegin;
579566063dSJacob Faibussowitsch   PetscCall(SNESGetDM(snes, &networkdm));
589566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(networkdm, &localX));
59c4762a1bSJed Brown 
609566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)networkdm, &comm));
619566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
62c4762a1bSJed Brown 
639566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalBegin(networkdm, X, INSERT_VALUES, localX));
649566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalEnd(networkdm, X, INSERT_VALUES, localX));
65c4762a1bSJed Brown 
669566063dSJacob Faibussowitsch   PetscCall(MatZeroEntries(J));
67c4762a1bSJed Brown 
68c4762a1bSJed Brown   /* Power subnetwork: copied from power/FormJacobian_Power() */
699566063dSJacob Faibussowitsch   PetscCall(DMNetworkGetSubnetwork(networkdm, 0, &nv, &ne, &vtx, &edges));
709566063dSJacob Faibussowitsch   PetscCall(FormJacobian_Power_private(networkdm, localX, J, nv, ne, vtx, edges, appctx));
71c4762a1bSJed Brown 
72c4762a1bSJed Brown   /* Water subnetwork: Identity */
739566063dSJacob Faibussowitsch   PetscCall(DMNetworkGetSubnetwork(networkdm, 1, &nv, &ne, &vtx, &edges));
74c4762a1bSJed Brown   for (i = 0; i < nv; i++) {
759566063dSJacob Faibussowitsch     PetscCall(DMNetworkIsGhostVertex(networkdm, vtx[i], &ghostvtex));
76c4762a1bSJed Brown     if (ghostvtex) continue;
77c4762a1bSJed Brown 
789566063dSJacob Faibussowitsch     PetscCall(DMNetworkGetGlobalVecOffset(networkdm, vtx[i], ALL_COMPONENTS, &offset));
799566063dSJacob Faibussowitsch     PetscCall(DMNetworkGetComponent(networkdm, vtx[i], ALL_COMPONENTS, NULL, NULL, &nvar));
80c4762a1bSJed Brown     for (j = 0; j < nvar; j++) {
81c4762a1bSJed Brown       row = offset + j;
829566063dSJacob Faibussowitsch       PetscCall(MatSetValues(J, 1, &row, 1, &row, &one, ADD_VALUES));
83c4762a1bSJed Brown     }
84c4762a1bSJed Brown   }
859566063dSJacob Faibussowitsch   PetscCall(MatAssemblyBegin(J, MAT_FINAL_ASSEMBLY));
869566063dSJacob Faibussowitsch   PetscCall(MatAssemblyEnd(J, MAT_FINAL_ASSEMBLY));
87c4762a1bSJed Brown 
889566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(networkdm, &localX));
89c4762a1bSJed Brown   PetscFunctionReturn(0);
90c4762a1bSJed Brown }
91c4762a1bSJed Brown 
92c4762a1bSJed Brown /* Dummy equation localF(X) = localX - localXold */
939371c9d4SSatish Balay PetscErrorCode FormFunction_Dummy(DM networkdm, Vec localX, Vec localF, PetscInt nv, PetscInt ne, const PetscInt *vtx, const PetscInt *edges, void *appctx) {
94c4762a1bSJed Brown   const PetscScalar *xarr, *xoldarr;
95c4762a1bSJed Brown   PetscScalar       *farr;
96c4762a1bSJed Brown   PetscInt           i, j, offset, nvar;
97c4762a1bSJed Brown   PetscBool          ghostvtex;
98c4762a1bSJed Brown   UserCtx           *user      = (UserCtx *)appctx;
99c4762a1bSJed Brown   Vec                localXold = user->localXold;
100c4762a1bSJed Brown 
101c4762a1bSJed Brown   PetscFunctionBegin;
1029566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(localX, &xarr));
1039566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(localXold, &xoldarr));
1049566063dSJacob Faibussowitsch   PetscCall(VecGetArray(localF, &farr));
105c4762a1bSJed Brown 
106c4762a1bSJed Brown   for (i = 0; i < nv; i++) {
1079566063dSJacob Faibussowitsch     PetscCall(DMNetworkIsGhostVertex(networkdm, vtx[i], &ghostvtex));
108c4762a1bSJed Brown     if (ghostvtex) continue;
109c4762a1bSJed Brown 
1109566063dSJacob Faibussowitsch     PetscCall(DMNetworkGetLocalVecOffset(networkdm, vtx[i], ALL_COMPONENTS, &offset));
1119566063dSJacob Faibussowitsch     PetscCall(DMNetworkGetComponent(networkdm, vtx[i], ALL_COMPONENTS, NULL, NULL, &nvar));
1129371c9d4SSatish Balay     for (j = 0; j < nvar; j++) { farr[offset + j] = xarr[offset + j] - xoldarr[offset + j]; }
113c4762a1bSJed Brown   }
114c4762a1bSJed Brown 
1159566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(localX, &xarr));
1169566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(localXold, &xoldarr));
1179566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(localF, &farr));
118c4762a1bSJed Brown   PetscFunctionReturn(0);
119c4762a1bSJed Brown }
120c4762a1bSJed Brown 
1219371c9d4SSatish Balay PetscErrorCode FormFunction(SNES snes, Vec X, Vec F, void *appctx) {
122c4762a1bSJed Brown   DM              networkdm;
123c4762a1bSJed Brown   Vec             localX, localF;
1242bf73ac6SHong Zhang   PetscInt        nv, ne, v;
125c4762a1bSJed Brown   const PetscInt *vtx, *edges;
126c4762a1bSJed Brown   PetscMPIInt     rank;
127c4762a1bSJed Brown   MPI_Comm        comm;
128c4762a1bSJed Brown   UserCtx        *user         = (UserCtx *)appctx;
129c4762a1bSJed Brown   UserCtx_Power   appctx_power = (*user).appctx_power;
1302bf73ac6SHong Zhang   AppCtx_Water    appctx_water = (*user).appctx_water;
131c4762a1bSJed Brown 
132c4762a1bSJed Brown   PetscFunctionBegin;
1339566063dSJacob Faibussowitsch   PetscCall(SNESGetDM(snes, &networkdm));
1349566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)networkdm, &comm));
1359566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
136c4762a1bSJed Brown 
1379566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(networkdm, &localX));
1389566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(networkdm, &localF));
1399566063dSJacob Faibussowitsch   PetscCall(VecSet(F, 0.0));
1409566063dSJacob Faibussowitsch   PetscCall(VecSet(localF, 0.0));
141c4762a1bSJed Brown 
1429566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalBegin(networkdm, X, INSERT_VALUES, localX));
1439566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalEnd(networkdm, X, INSERT_VALUES, localX));
144c4762a1bSJed Brown 
145c4762a1bSJed Brown   /* Form Function for power subnetwork */
1469566063dSJacob Faibussowitsch   PetscCall(DMNetworkGetSubnetwork(networkdm, 0, &nv, &ne, &vtx, &edges));
147c4762a1bSJed Brown   if (user->subsnes_id == 1) { /* snes_water only */
1489566063dSJacob Faibussowitsch     PetscCall(FormFunction_Dummy(networkdm, localX, localF, nv, ne, vtx, edges, user));
149c4762a1bSJed Brown   } else {
1509566063dSJacob Faibussowitsch     PetscCall(FormFunction_Power(networkdm, localX, localF, nv, ne, vtx, edges, &appctx_power));
151c4762a1bSJed Brown   }
152c4762a1bSJed Brown 
153c4762a1bSJed Brown   /* Form Function for water subnetwork */
1549566063dSJacob Faibussowitsch   PetscCall(DMNetworkGetSubnetwork(networkdm, 1, &nv, &ne, &vtx, &edges));
155c4762a1bSJed Brown   if (user->subsnes_id == 0) { /* snes_power only */
1569566063dSJacob Faibussowitsch     PetscCall(FormFunction_Dummy(networkdm, localX, localF, nv, ne, vtx, edges, user));
157c4762a1bSJed Brown   } else {
1589566063dSJacob Faibussowitsch     PetscCall(FormFunction_Water(networkdm, localX, localF, nv, ne, vtx, edges, NULL));
159c4762a1bSJed Brown   }
160c4762a1bSJed Brown 
1612bf73ac6SHong Zhang   /* Illustrate how to access the coupling vertex of the subnetworks without doing anything to F yet */
1629566063dSJacob Faibussowitsch   PetscCall(DMNetworkGetSharedVertices(networkdm, &nv, &vtx));
1632bf73ac6SHong Zhang   for (v = 0; v < nv; v++) {
1642bf73ac6SHong Zhang     PetscInt        key, ncomp, nvar, nconnedges, k, e, keye, goffset[3];
165c4762a1bSJed Brown     void           *component;
1662bf73ac6SHong Zhang     const PetscInt *connedges;
167c4762a1bSJed Brown 
1689566063dSJacob Faibussowitsch     PetscCall(DMNetworkGetComponent(networkdm, vtx[v], ALL_COMPONENTS, NULL, NULL, &nvar));
1699566063dSJacob Faibussowitsch     PetscCall(DMNetworkGetNumComponents(networkdm, vtx[v], &ncomp));
17063a3b9bcSJacob Faibussowitsch     /* printf("  [%d] coupling vertex[%" PetscInt_FMT "]: v %" PetscInt_FMT ", ncomp %" PetscInt_FMT "; nvar %" PetscInt_FMT "\n",rank,v,vtx[v], ncomp,nvar); */
171c4762a1bSJed Brown 
1722bf73ac6SHong Zhang     for (k = 0; k < ncomp; k++) {
1739566063dSJacob Faibussowitsch       PetscCall(DMNetworkGetComponent(networkdm, vtx[v], k, &key, &component, &nvar));
1749566063dSJacob Faibussowitsch       PetscCall(DMNetworkGetGlobalVecOffset(networkdm, vtx[v], k, &goffset[k]));
175c4762a1bSJed Brown 
1762bf73ac6SHong Zhang       /* Verify the coupling vertex is a powernet load vertex or a water vertex */
1772bf73ac6SHong Zhang       switch (k) {
1789371c9d4SSatish Balay       case 0: 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); break;
1799371c9d4SSatish Balay       case 1: 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"); break;
1809371c9d4SSatish Balay       case 2: PetscCheck(key == appctx_water.compkey_vtx && nvar == 1 && goffset[2] == goffset[1], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Not a water vertex"); break;
18163a3b9bcSJacob Faibussowitsch       default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "k %" PetscInt_FMT " is wrong", k);
1822bf73ac6SHong Zhang       }
18363a3b9bcSJacob Faibussowitsch       /* printf("  [%d] coupling vertex[%" PetscInt_FMT "]: key %" PetscInt_FMT "; nvar %" PetscInt_FMT ", goffset %" PetscInt_FMT "\n",rank,v,key,nvar,goffset[k]); */
1842bf73ac6SHong Zhang     }
185c4762a1bSJed Brown 
1862bf73ac6SHong Zhang     /* Get its supporting edges */
1879566063dSJacob Faibussowitsch     PetscCall(DMNetworkGetSupportingEdges(networkdm, vtx[v], &nconnedges, &connedges));
18863a3b9bcSJacob Faibussowitsch     /* printf("\n[%d] coupling vertex: nconnedges %" PetscInt_FMT "\n",rank,nconnedges); */
189c4762a1bSJed Brown     for (k = 0; k < nconnedges; k++) {
190c4762a1bSJed Brown       e = connedges[k];
1919566063dSJacob Faibussowitsch       PetscCall(DMNetworkGetNumComponents(networkdm, e, &ncomp));
19263a3b9bcSJacob Faibussowitsch       /* printf("\n  [%d] connected edge[%" PetscInt_FMT "]=%" PetscInt_FMT " has ncomp %" PetscInt_FMT "\n",rank,k,e,ncomp); */
1939566063dSJacob Faibussowitsch       PetscCall(DMNetworkGetComponent(networkdm, e, 0, &keye, &component, NULL));
1949371c9d4SSatish Balay       if (keye != appctx_water.compkey_edge) { PetscCheck(keye == appctx_power.compkey_branch, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Not a power branch"); }
195c4762a1bSJed Brown     }
196c4762a1bSJed Brown   }
197c4762a1bSJed Brown 
1989566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(networkdm, &localX));
199c4762a1bSJed Brown 
2009566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalBegin(networkdm, localF, ADD_VALUES, F));
2019566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalEnd(networkdm, localF, ADD_VALUES, F));
2029566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(networkdm, &localF));
2032bf73ac6SHong Zhang #if 0
204dd400576SPatrick Sanan   if (rank == 0) printf("F:\n");
2059566063dSJacob Faibussowitsch   PetscCall(VecView(F,PETSC_VIEWER_STDOUT_WORLD));
2062bf73ac6SHong Zhang #endif
207c4762a1bSJed Brown   PetscFunctionReturn(0);
208c4762a1bSJed Brown }
209c4762a1bSJed Brown 
2109371c9d4SSatish Balay PetscErrorCode SetInitialGuess(DM networkdm, Vec X, void *appctx) {
2112bf73ac6SHong Zhang   PetscInt        nv, ne, i, j, ncomp, offset, key;
212c4762a1bSJed Brown   const PetscInt *vtx, *edges;
213c4762a1bSJed Brown   UserCtx        *user         = (UserCtx *)appctx;
214c4762a1bSJed Brown   Vec             localX       = user->localXold;
215c4762a1bSJed Brown   UserCtx_Power   appctx_power = (*user).appctx_power;
2162bf73ac6SHong Zhang   AppCtx_Water    appctx_water = (*user).appctx_water;
2172bf73ac6SHong Zhang   PetscBool       ghost;
2182bf73ac6SHong Zhang   PetscScalar    *xarr;
2192bf73ac6SHong Zhang   VERTEX_Power    bus;
2202bf73ac6SHong Zhang   VERTEX_Water    vertex;
2212bf73ac6SHong Zhang   void           *component;
2222bf73ac6SHong Zhang   GEN             gen;
223c4762a1bSJed Brown 
224c4762a1bSJed Brown   PetscFunctionBegin;
2259566063dSJacob Faibussowitsch   PetscCall(VecSet(X, 0.0));
2269566063dSJacob Faibussowitsch   PetscCall(VecSet(localX, 0.0));
227c4762a1bSJed Brown 
228c4762a1bSJed Brown   /* Set initial guess for power subnetwork */
2299566063dSJacob Faibussowitsch   PetscCall(DMNetworkGetSubnetwork(networkdm, 0, &nv, &ne, &vtx, &edges));
2309566063dSJacob Faibussowitsch   PetscCall(SetInitialGuess_Power(networkdm, localX, nv, ne, vtx, edges, &appctx_power));
231c4762a1bSJed Brown 
232c4762a1bSJed Brown   /* Set initial guess for water subnetwork */
2339566063dSJacob Faibussowitsch   PetscCall(DMNetworkGetSubnetwork(networkdm, 1, &nv, &ne, &vtx, &edges));
2349566063dSJacob Faibussowitsch   PetscCall(SetInitialGuess_Water(networkdm, localX, nv, ne, vtx, edges, NULL));
235c4762a1bSJed Brown 
2362bf73ac6SHong Zhang   /* Set initial guess at the coupling vertex */
2379566063dSJacob Faibussowitsch   PetscCall(VecGetArray(localX, &xarr));
2389566063dSJacob Faibussowitsch   PetscCall(DMNetworkGetSharedVertices(networkdm, &nv, &vtx));
2392bf73ac6SHong Zhang   for (i = 0; i < nv; i++) {
2409566063dSJacob Faibussowitsch     PetscCall(DMNetworkIsGhostVertex(networkdm, vtx[i], &ghost));
2412bf73ac6SHong Zhang     if (ghost) continue;
2422bf73ac6SHong Zhang 
2439566063dSJacob Faibussowitsch     PetscCall(DMNetworkGetNumComponents(networkdm, vtx[i], &ncomp));
2442bf73ac6SHong Zhang     for (j = 0; j < ncomp; j++) {
2459566063dSJacob Faibussowitsch       PetscCall(DMNetworkGetLocalVecOffset(networkdm, vtx[i], j, &offset));
2469566063dSJacob Faibussowitsch       PetscCall(DMNetworkGetComponent(networkdm, vtx[i], j, &key, (void **)&component, NULL));
2472bf73ac6SHong Zhang       if (key == appctx_power.compkey_bus) {
2482bf73ac6SHong Zhang         bus              = (VERTEX_Power)(component);
2492bf73ac6SHong Zhang         xarr[offset]     = bus->va * PETSC_PI / 180.0;
2502bf73ac6SHong Zhang         xarr[offset + 1] = bus->vm;
2512bf73ac6SHong Zhang       } else if (key == appctx_power.compkey_gen) {
2522bf73ac6SHong Zhang         gen = (GEN)(component);
2532bf73ac6SHong Zhang         if (!gen->status) continue;
2542bf73ac6SHong Zhang         xarr[offset + 1] = gen->vs;
2552bf73ac6SHong Zhang       } else if (key == appctx_water.compkey_vtx) {
2562bf73ac6SHong Zhang         vertex = (VERTEX_Water)(component);
2572bf73ac6SHong Zhang         if (vertex->type == VERTEX_TYPE_JUNCTION) {
2582bf73ac6SHong Zhang           xarr[offset] = 100;
2592bf73ac6SHong Zhang         } else if (vertex->type == VERTEX_TYPE_RESERVOIR) {
2602bf73ac6SHong Zhang           xarr[offset] = vertex->res.head;
2612bf73ac6SHong Zhang         } else {
2622bf73ac6SHong Zhang           xarr[offset] = vertex->tank.initlvl + vertex->tank.elev;
263c4762a1bSJed Brown         }
2642bf73ac6SHong Zhang       }
2652bf73ac6SHong Zhang     }
2662bf73ac6SHong Zhang   }
2679566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(localX, &xarr));
268c4762a1bSJed Brown 
2699566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalBegin(networkdm, localX, ADD_VALUES, X));
2709566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalEnd(networkdm, localX, ADD_VALUES, X));
271c4762a1bSJed Brown   PetscFunctionReturn(0);
272c4762a1bSJed Brown }
273c4762a1bSJed Brown 
2749371c9d4SSatish Balay int main(int argc, char **argv) {
275c4762a1bSJed Brown   DM                  networkdm;
276c4762a1bSJed Brown   PetscLogStage       stage[4];
277d5c9c0c4SHong Zhang   PetscMPIInt         rank, size;
2782bf73ac6SHong Zhang   PetscInt            Nsubnet = 2, numVertices[2], numEdges[2], i, j, nv, ne, it_max = 10;
279c4762a1bSJed Brown   const PetscInt     *vtx, *edges;
280c4762a1bSJed Brown   Vec                 X, F;
281c4762a1bSJed Brown   SNES                snes, snes_power, snes_water;
282c4762a1bSJed Brown   Mat                 Jac;
2832bf73ac6SHong Zhang   PetscBool           ghost, viewJ = PETSC_FALSE, viewX = PETSC_FALSE, viewDM = PETSC_FALSE, test = PETSC_FALSE, distribute = PETSC_TRUE, flg;
284c4762a1bSJed Brown   UserCtx             user;
285c4762a1bSJed Brown   SNESConvergedReason reason;
286c4762a1bSJed Brown 
287c4762a1bSJed Brown   /* Power subnetwork */
288c4762a1bSJed Brown   UserCtx_Power *appctx_power                    = &user.appctx_power;
289c4762a1bSJed Brown   char           pfdata_file[PETSC_MAX_PATH_LEN] = "power/case9.m";
290c4762a1bSJed Brown   PFDATA        *pfdata                          = NULL;
2912bf73ac6SHong Zhang   PetscInt       genj, loadj, *edgelist_power = NULL, power_netnum;
292c4762a1bSJed Brown   PetscScalar    Sbase = 0.0;
293c4762a1bSJed Brown 
294c4762a1bSJed Brown   /* Water subnetwork */
295c4762a1bSJed Brown   AppCtx_Water *appctx_water                       = &user.appctx_water;
296c4762a1bSJed Brown   WATERDATA    *waterdata                          = NULL;
297c4762a1bSJed Brown   char          waterdata_file[PETSC_MAX_PATH_LEN] = "water/sample1.inp";
2982bf73ac6SHong Zhang   PetscInt     *edgelist_water                     = NULL, water_netnum;
299c4762a1bSJed Brown 
3002bf73ac6SHong Zhang   /* Shared vertices between subnetworks */
3012bf73ac6SHong Zhang   PetscInt power_svtx, water_svtx;
302c4762a1bSJed Brown 
303327415f7SBarry Smith   PetscFunctionBeginUser;
3049566063dSJacob Faibussowitsch   PetscCall(PetscInitialize(&argc, &argv, "ex1options", help));
3059566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD, &rank));
3069566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PETSC_COMM_WORLD, &size));
307c4762a1bSJed Brown 
308c4762a1bSJed Brown   /* (1) Read Data - Only rank 0 reads the data */
309c4762a1bSJed Brown   /*--------------------------------------------*/
3109566063dSJacob Faibussowitsch   PetscCall(PetscLogStageRegister("Read Data", &stage[0]));
3119566063dSJacob Faibussowitsch   PetscCall(PetscLogStagePush(stage[0]));
312c4762a1bSJed Brown 
3132bf73ac6SHong Zhang   for (i = 0; i < Nsubnet; i++) {
314c4762a1bSJed Brown     numVertices[i] = 0;
315c4762a1bSJed Brown     numEdges[i]    = 0;
316c4762a1bSJed Brown   }
317c4762a1bSJed Brown 
3182bf73ac6SHong Zhang   /* All processes READ THE DATA FOR THE FIRST SUBNETWORK: Electric Power Grid */
3192bf73ac6SHong Zhang   /* Used for shared vertex, because currently the coupling info must be available in all processes!!! */
3209566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetString(NULL, NULL, "-pfdata", pfdata_file, PETSC_MAX_PATH_LEN - 1, NULL));
3219566063dSJacob Faibussowitsch   PetscCall(PetscNew(&pfdata));
3229566063dSJacob Faibussowitsch   PetscCall(PFReadMatPowerData(pfdata, pfdata_file));
323*48a46eb9SPierre 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));
324c4762a1bSJed Brown   Sbase = pfdata->sbase;
3252bf73ac6SHong Zhang   if (rank == 0) { /* proc[0] will create Electric Power Grid */
326c4762a1bSJed Brown     numEdges[0]    = pfdata->nbranch;
327c4762a1bSJed Brown     numVertices[0] = pfdata->nbus;
328c4762a1bSJed Brown 
3299566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(2 * numEdges[0], &edgelist_power));
3309566063dSJacob Faibussowitsch     PetscCall(GetListofEdges_Power(pfdata, edgelist_power));
331c4762a1bSJed Brown   }
332c4762a1bSJed Brown   /* Broadcast power Sbase to all processors */
3339566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Bcast(&Sbase, 1, MPIU_SCALAR, 0, PETSC_COMM_WORLD));
334c4762a1bSJed Brown   appctx_power->Sbase     = Sbase;
335c4762a1bSJed Brown   appctx_power->jac_error = PETSC_FALSE;
336c4762a1bSJed Brown   /* If external option activated. Introduce error in jacobian */
3379566063dSJacob Faibussowitsch   PetscCall(PetscOptionsHasName(NULL, NULL, "-jac_error", &appctx_power->jac_error));
338c4762a1bSJed Brown 
3392bf73ac6SHong Zhang   /* All processes READ THE DATA FOR THE SECOND SUBNETWORK: Water */
3402bf73ac6SHong Zhang   /* Used for shared vertex, because currently the coupling info must be available in all processes!!! */
3419566063dSJacob Faibussowitsch   PetscCall(PetscNew(&waterdata));
3429566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetString(NULL, NULL, "-waterdata", waterdata_file, PETSC_MAX_PATH_LEN - 1, NULL));
3439566063dSJacob Faibussowitsch   PetscCall(WaterReadData(waterdata, waterdata_file));
3442bf73ac6SHong Zhang   if (size == 1 || (size > 1 && rank == 1)) {
3459566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(2 * waterdata->nedge, &edgelist_water));
3469566063dSJacob Faibussowitsch     PetscCall(GetListofEdges_Water(waterdata, edgelist_water));
347c4762a1bSJed Brown     numEdges[1]    = waterdata->nedge;
348c4762a1bSJed Brown     numVertices[1] = waterdata->nvertex;
349c4762a1bSJed Brown   }
3502bf73ac6SHong Zhang   PetscLogStagePop();
351c4762a1bSJed Brown 
3522bf73ac6SHong Zhang   /* (2) Create a network consist of two subnetworks */
3532bf73ac6SHong Zhang   /*-------------------------------------------------*/
3549566063dSJacob Faibussowitsch   PetscCall(PetscLogStageRegister("Net Setup", &stage[1]));
3559566063dSJacob Faibussowitsch   PetscCall(PetscLogStagePush(stage[1]));
356c4762a1bSJed Brown 
3579566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(NULL, NULL, "-viewDM", &viewDM, NULL));
3589566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(NULL, NULL, "-test", &test, NULL));
3599566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(NULL, NULL, "-distribute", &distribute, NULL));
360c4762a1bSJed Brown 
361c4762a1bSJed Brown   /* Create an empty network object */
3629566063dSJacob Faibussowitsch   PetscCall(DMNetworkCreate(PETSC_COMM_WORLD, &networkdm));
363c4762a1bSJed Brown 
364c4762a1bSJed Brown   /* Register the components in the network */
3659566063dSJacob Faibussowitsch   PetscCall(DMNetworkRegisterComponent(networkdm, "branchstruct", sizeof(struct _p_EDGE_Power), &appctx_power->compkey_branch));
3669566063dSJacob Faibussowitsch   PetscCall(DMNetworkRegisterComponent(networkdm, "busstruct", sizeof(struct _p_VERTEX_Power), &appctx_power->compkey_bus));
3679566063dSJacob Faibussowitsch   PetscCall(DMNetworkRegisterComponent(networkdm, "genstruct", sizeof(struct _p_GEN), &appctx_power->compkey_gen));
3689566063dSJacob Faibussowitsch   PetscCall(DMNetworkRegisterComponent(networkdm, "loadstruct", sizeof(struct _p_LOAD), &appctx_power->compkey_load));
369c4762a1bSJed Brown 
3709566063dSJacob Faibussowitsch   PetscCall(DMNetworkRegisterComponent(networkdm, "edge_water", sizeof(struct _p_EDGE_Water), &appctx_water->compkey_edge));
3719566063dSJacob Faibussowitsch   PetscCall(DMNetworkRegisterComponent(networkdm, "vertex_water", sizeof(struct _p_VERTEX_Water), &appctx_water->compkey_vtx));
3722bf73ac6SHong Zhang #if 0
3739566063dSJacob Faibussowitsch   PetscCall(PetscPrintf(PETSC_COMM_WORLD,"power->compkey_branch %d\n",appctx_power->compkey_branch));
3749566063dSJacob Faibussowitsch   PetscCall(PetscPrintf(PETSC_COMM_WORLD,"power->compkey_bus    %d\n",appctx_power->compkey_bus));
3759566063dSJacob Faibussowitsch   PetscCall(PetscPrintf(PETSC_COMM_WORLD,"power->compkey_gen    %d\n",appctx_power->compkey_gen));
3769566063dSJacob Faibussowitsch   PetscCall(PetscPrintf(PETSC_COMM_WORLD,"power->compkey_load   %d\n",appctx_power->compkey_load));
3779566063dSJacob Faibussowitsch   PetscCall(PetscPrintf(PETSC_COMM_WORLD,"water->compkey_edge   %d\n",appctx_water->compkey_edge));
3789566063dSJacob Faibussowitsch   PetscCall(PetscPrintf(PETSC_COMM_WORLD,"water->compkey_vtx    %d\n",appctx_water->compkey_vtx));
3792bf73ac6SHong Zhang #endif
38063a3b9bcSJacob 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]));
3819566063dSJacob Faibussowitsch   PetscCall(PetscSynchronizedFlush(PETSC_COMM_WORLD, PETSC_STDOUT));
382c4762a1bSJed Brown 
3839566063dSJacob Faibussowitsch   PetscCall(DMNetworkSetNumSubNetworks(networkdm, PETSC_DECIDE, Nsubnet));
3849566063dSJacob Faibussowitsch   PetscCall(DMNetworkAddSubnetwork(networkdm, "power", numEdges[0], edgelist_power, &power_netnum));
3859566063dSJacob Faibussowitsch   PetscCall(DMNetworkAddSubnetwork(networkdm, "water", numEdges[1], edgelist_water, &water_netnum));
386c4762a1bSJed Brown 
3872bf73ac6SHong Zhang   /* vertex subnet[0].4 shares with vertex subnet[1].0 */
3889371c9d4SSatish Balay   power_svtx = 4;
3899371c9d4SSatish Balay   water_svtx = 0;
3909566063dSJacob Faibussowitsch   PetscCall(DMNetworkAddSharedVertices(networkdm, power_netnum, water_netnum, 1, &power_svtx, &water_svtx));
391c4762a1bSJed Brown 
392c4762a1bSJed Brown   /* Set up the network layout */
3939566063dSJacob Faibussowitsch   PetscCall(DMNetworkLayoutSetUp(networkdm));
394c4762a1bSJed Brown 
395c4762a1bSJed Brown   /* ADD VARIABLES AND COMPONENTS FOR THE POWER SUBNETWORK */
3962bf73ac6SHong Zhang   /*-------------------------------------------------------*/
3979371c9d4SSatish Balay   genj  = 0;
3989371c9d4SSatish Balay   loadj = 0;
3999566063dSJacob Faibussowitsch   PetscCall(DMNetworkGetSubnetwork(networkdm, power_netnum, &nv, &ne, &vtx, &edges));
4002bf73ac6SHong Zhang 
401*48a46eb9SPierre Jolivet   for (i = 0; i < ne; i++) PetscCall(DMNetworkAddComponent(networkdm, edges[i], appctx_power->compkey_branch, &pfdata->branch[i], 0));
402c4762a1bSJed Brown 
403c4762a1bSJed Brown   for (i = 0; i < nv; i++) {
4049566063dSJacob Faibussowitsch     PetscCall(DMNetworkIsSharedVertex(networkdm, vtx[i], &flg));
4052bf73ac6SHong Zhang     if (flg) continue;
4062bf73ac6SHong Zhang 
4079566063dSJacob Faibussowitsch     PetscCall(DMNetworkAddComponent(networkdm, vtx[i], appctx_power->compkey_bus, &pfdata->bus[i], 2));
408c4762a1bSJed Brown     if (pfdata->bus[i].ngen) {
409*48a46eb9SPierre Jolivet       for (j = 0; j < pfdata->bus[i].ngen; j++) PetscCall(DMNetworkAddComponent(networkdm, vtx[i], appctx_power->compkey_gen, &pfdata->gen[genj++], 0));
410c4762a1bSJed Brown     }
411c4762a1bSJed Brown     if (pfdata->bus[i].nload) {
412*48a46eb9SPierre Jolivet       for (j = 0; j < pfdata->bus[i].nload; j++) PetscCall(DMNetworkAddComponent(networkdm, vtx[i], appctx_power->compkey_load, &pfdata->load[loadj++], 0));
413c4762a1bSJed Brown     }
414c4762a1bSJed Brown   }
415c4762a1bSJed Brown 
416c4762a1bSJed Brown   /* ADD VARIABLES AND COMPONENTS FOR THE WATER SUBNETWORK */
4172bf73ac6SHong Zhang   /*-------------------------------------------------------*/
4189566063dSJacob Faibussowitsch   PetscCall(DMNetworkGetSubnetwork(networkdm, water_netnum, &nv, &ne, &vtx, &edges));
419*48a46eb9SPierre Jolivet   for (i = 0; i < ne; i++) PetscCall(DMNetworkAddComponent(networkdm, edges[i], appctx_water->compkey_edge, &waterdata->edge[i], 0));
420c4762a1bSJed Brown 
421c4762a1bSJed Brown   for (i = 0; i < nv; i++) {
4229566063dSJacob Faibussowitsch     PetscCall(DMNetworkIsSharedVertex(networkdm, vtx[i], &flg));
4232bf73ac6SHong Zhang     if (flg) continue;
4242bf73ac6SHong Zhang 
4259566063dSJacob Faibussowitsch     PetscCall(DMNetworkAddComponent(networkdm, vtx[i], appctx_water->compkey_vtx, &waterdata->vertex[i], 1));
426c4762a1bSJed Brown   }
4272bf73ac6SHong Zhang 
428eac198afSGetnet   /* 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 */
4292bf73ac6SHong Zhang   /*----------------------------------------------------------------------------------------------------------------------------*/
4309566063dSJacob Faibussowitsch   PetscCall(DMNetworkGetSharedVertices(networkdm, &nv, &vtx));
4312bf73ac6SHong Zhang   for (i = 0; i < nv; i++) {
4322bf73ac6SHong Zhang     /* power */
4339566063dSJacob Faibussowitsch     PetscCall(DMNetworkAddComponent(networkdm, vtx[i], appctx_power->compkey_bus, &pfdata->bus[4], 2));
4342bf73ac6SHong Zhang     /* bus[4] is a load, add its component */
4359566063dSJacob Faibussowitsch     PetscCall(DMNetworkAddComponent(networkdm, vtx[i], appctx_power->compkey_load, &pfdata->load[0], 0));
4362bf73ac6SHong Zhang 
4372bf73ac6SHong Zhang     /* water */
4389566063dSJacob Faibussowitsch     PetscCall(DMNetworkAddComponent(networkdm, vtx[i], appctx_water->compkey_vtx, &waterdata->vertex[0], 1));
439c4762a1bSJed Brown   }
440c4762a1bSJed Brown 
441c4762a1bSJed Brown   /* Set up DM for use */
4429566063dSJacob Faibussowitsch   PetscCall(DMSetUp(networkdm));
443c4762a1bSJed Brown   if (viewDM) {
4449566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "\nAfter DMSetUp, DMView:\n"));
4459566063dSJacob Faibussowitsch     PetscCall(DMView(networkdm, PETSC_VIEWER_STDOUT_WORLD));
446c4762a1bSJed Brown   }
447c4762a1bSJed Brown 
448c4762a1bSJed Brown   /* Free user objects */
4499566063dSJacob Faibussowitsch   PetscCall(PetscFree(edgelist_power));
4509566063dSJacob Faibussowitsch   PetscCall(PetscFree(pfdata->bus));
4519566063dSJacob Faibussowitsch   PetscCall(PetscFree(pfdata->gen));
4529566063dSJacob Faibussowitsch   PetscCall(PetscFree(pfdata->branch));
4539566063dSJacob Faibussowitsch   PetscCall(PetscFree(pfdata->load));
4549566063dSJacob Faibussowitsch   PetscCall(PetscFree(pfdata));
4552bf73ac6SHong Zhang 
4569566063dSJacob Faibussowitsch   PetscCall(PetscFree(edgelist_water));
4579566063dSJacob Faibussowitsch   PetscCall(PetscFree(waterdata->vertex));
4589566063dSJacob Faibussowitsch   PetscCall(PetscFree(waterdata->edge));
4599566063dSJacob Faibussowitsch   PetscCall(PetscFree(waterdata));
460c4762a1bSJed Brown 
461d5c9c0c4SHong Zhang   /* Re-distribute networkdm to multiple processes for better job balance */
4622bf73ac6SHong Zhang   if (size > 1 && distribute) {
4639566063dSJacob Faibussowitsch     PetscCall(DMNetworkDistribute(&networkdm, 0));
464c4762a1bSJed Brown     if (viewDM) {
4659566063dSJacob Faibussowitsch       PetscCall(PetscPrintf(PETSC_COMM_WORLD, "\nAfter DMNetworkDistribute, DMView:\n"));
4669566063dSJacob Faibussowitsch       PetscCall(DMView(networkdm, PETSC_VIEWER_STDOUT_WORLD));
467c4762a1bSJed Brown     }
468d5c9c0c4SHong Zhang   }
469c4762a1bSJed Brown 
4702bf73ac6SHong Zhang   /* Test DMNetworkGetSubnetwork() and DMNetworkGetSubnetworkSharedVertices() */
471c4762a1bSJed Brown   if (test) {
4722bf73ac6SHong Zhang     PetscInt v, gidx;
4739566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Barrier(PETSC_COMM_WORLD));
4742bf73ac6SHong Zhang     for (i = 0; i < Nsubnet; i++) {
4759566063dSJacob Faibussowitsch       PetscCall(DMNetworkGetSubnetwork(networkdm, i, &nv, &ne, &vtx, &edges));
47663a3b9bcSJacob Faibussowitsch       PetscCall(PetscPrintf(PETSC_COMM_SELF, "[%d] After distribute, subnet[%" PetscInt_FMT "] ne %" PetscInt_FMT ", nv %" PetscInt_FMT "\n", rank, i, ne, nv));
4779566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Barrier(PETSC_COMM_WORLD));
478c4762a1bSJed Brown 
4792bf73ac6SHong Zhang       for (v = 0; v < nv; v++) {
4809566063dSJacob Faibussowitsch         PetscCall(DMNetworkIsGhostVertex(networkdm, vtx[v], &ghost));
4819566063dSJacob Faibussowitsch         PetscCall(DMNetworkGetGlobalVertexIndex(networkdm, vtx[v], &gidx));
48263a3b9bcSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF, "[%d] subnet[%" PetscInt_FMT "] v %" PetscInt_FMT " %" PetscInt_FMT "; ghost %d\n", rank, i, vtx[v], gidx, ghost));
483c4762a1bSJed Brown       }
4849566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Barrier(PETSC_COMM_WORLD));
485c4762a1bSJed Brown     }
4869566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Barrier(PETSC_COMM_WORLD));
4872bf73ac6SHong Zhang 
4889566063dSJacob Faibussowitsch     PetscCall(DMNetworkGetSharedVertices(networkdm, &nv, &vtx));
48963a3b9bcSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_SELF, "[%d] After distribute, num of shared vertices nsv = %" PetscInt_FMT "\n", rank, nv));
4902bf73ac6SHong Zhang     for (v = 0; v < nv; v++) {
4919566063dSJacob Faibussowitsch       PetscCall(DMNetworkGetGlobalVertexIndex(networkdm, vtx[v], &gidx));
49263a3b9bcSJacob Faibussowitsch       PetscCall(PetscPrintf(PETSC_COMM_SELF, "[%d] sv %" PetscInt_FMT ", gidx=%" PetscInt_FMT "\n", rank, vtx[v], gidx));
4932bf73ac6SHong Zhang     }
4949566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Barrier(PETSC_COMM_WORLD));
495c4762a1bSJed Brown   }
496c4762a1bSJed Brown 
4972bf73ac6SHong Zhang   /* Create solution vector X */
4989566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector(networkdm, &X));
4999566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(X, &F));
5009566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(networkdm, &user.localXold));
5012bf73ac6SHong Zhang   PetscLogStagePop();
502c4762a1bSJed Brown 
503c4762a1bSJed Brown   /* (3) Setup Solvers */
504c4762a1bSJed Brown   /*-------------------*/
5059566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(NULL, NULL, "-viewJ", &viewJ, NULL));
5069566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(NULL, NULL, "-viewX", &viewX, NULL));
507c4762a1bSJed Brown 
5089566063dSJacob Faibussowitsch   PetscCall(PetscLogStageRegister("SNES Setup", &stage[2]));
5099566063dSJacob Faibussowitsch   PetscCall(PetscLogStagePush(stage[2]));
510c4762a1bSJed Brown 
5119566063dSJacob Faibussowitsch   PetscCall(SetInitialGuess(networkdm, X, &user));
512c4762a1bSJed Brown 
513c4762a1bSJed Brown   /* Create coupled snes */
514c4762a1bSJed Brown   /*-------------------- */
5159566063dSJacob Faibussowitsch   PetscCall(PetscPrintf(PETSC_COMM_WORLD, "SNES_coupled setup ......\n"));
5162bf73ac6SHong Zhang   user.subsnes_id = Nsubnet;
5179566063dSJacob Faibussowitsch   PetscCall(SNESCreate(PETSC_COMM_WORLD, &snes));
5189566063dSJacob Faibussowitsch   PetscCall(SNESSetDM(snes, networkdm));
5199566063dSJacob Faibussowitsch   PetscCall(SNESSetOptionsPrefix(snes, "coupled_"));
5209566063dSJacob Faibussowitsch   PetscCall(SNESSetFunction(snes, F, FormFunction, &user));
5219566063dSJacob Faibussowitsch   PetscCall(SNESMonitorSet(snes, UserMonitor, &user, NULL));
5229566063dSJacob Faibussowitsch   PetscCall(SNESSetFromOptions(snes));
523c4762a1bSJed Brown 
524c4762a1bSJed Brown   if (viewJ) {
525c4762a1bSJed Brown     /* View Jac structure */
5269566063dSJacob Faibussowitsch     PetscCall(SNESGetJacobian(snes, &Jac, NULL, NULL, NULL));
5279566063dSJacob Faibussowitsch     PetscCall(MatView(Jac, PETSC_VIEWER_DRAW_WORLD));
528c4762a1bSJed Brown   }
529c4762a1bSJed Brown 
530c4762a1bSJed Brown   if (viewX) {
5319566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Solution:\n"));
5329566063dSJacob Faibussowitsch     PetscCall(VecView(X, PETSC_VIEWER_STDOUT_WORLD));
533c4762a1bSJed Brown   }
534c4762a1bSJed Brown 
535c4762a1bSJed Brown   if (viewJ) {
536c4762a1bSJed Brown     /* View assembled Jac */
5379566063dSJacob Faibussowitsch     PetscCall(MatView(Jac, PETSC_VIEWER_DRAW_WORLD));
538c4762a1bSJed Brown   }
539c4762a1bSJed Brown 
540c4762a1bSJed Brown   /* Create snes_power */
541c4762a1bSJed Brown   /*-------------------*/
5429566063dSJacob Faibussowitsch   PetscCall(PetscPrintf(PETSC_COMM_WORLD, "SNES_power setup ......\n"));
543c4762a1bSJed Brown 
544c4762a1bSJed Brown   user.subsnes_id = 0;
5459566063dSJacob Faibussowitsch   PetscCall(SNESCreate(PETSC_COMM_WORLD, &snes_power));
5469566063dSJacob Faibussowitsch   PetscCall(SNESSetDM(snes_power, networkdm));
5479566063dSJacob Faibussowitsch   PetscCall(SNESSetOptionsPrefix(snes_power, "power_"));
5489566063dSJacob Faibussowitsch   PetscCall(SNESSetFunction(snes_power, F, FormFunction, &user));
5499566063dSJacob Faibussowitsch   PetscCall(SNESMonitorSet(snes_power, UserMonitor, &user, NULL));
550c4762a1bSJed Brown 
551c4762a1bSJed Brown   /* Use user-provide Jacobian */
5529566063dSJacob Faibussowitsch   PetscCall(DMCreateMatrix(networkdm, &Jac));
5539566063dSJacob Faibussowitsch   PetscCall(SNESSetJacobian(snes_power, Jac, Jac, FormJacobian_subPower, &user));
5549566063dSJacob Faibussowitsch   PetscCall(SNESSetFromOptions(snes_power));
555c4762a1bSJed Brown 
556c4762a1bSJed Brown   if (viewX) {
5579566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Power Solution:\n"));
5589566063dSJacob Faibussowitsch     PetscCall(VecView(X, PETSC_VIEWER_STDOUT_WORLD));
559c4762a1bSJed Brown   }
560c4762a1bSJed Brown   if (viewJ) {
5619566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Power Jac:\n"));
5629566063dSJacob Faibussowitsch     PetscCall(SNESGetJacobian(snes_power, &Jac, NULL, NULL, NULL));
5639566063dSJacob Faibussowitsch     PetscCall(MatView(Jac, PETSC_VIEWER_DRAW_WORLD));
5649566063dSJacob Faibussowitsch     /* PetscCall(MatView(Jac,PETSC_VIEWER_STDOUT_WORLD)); */
565c4762a1bSJed Brown   }
566c4762a1bSJed Brown 
567c4762a1bSJed Brown   /* Create snes_water */
568c4762a1bSJed Brown   /*-------------------*/
5699566063dSJacob Faibussowitsch   PetscCall(PetscPrintf(PETSC_COMM_WORLD, "SNES_water setup......\n"));
570c4762a1bSJed Brown 
571c4762a1bSJed Brown   user.subsnes_id = 1;
5729566063dSJacob Faibussowitsch   PetscCall(SNESCreate(PETSC_COMM_WORLD, &snes_water));
5739566063dSJacob Faibussowitsch   PetscCall(SNESSetDM(snes_water, networkdm));
5749566063dSJacob Faibussowitsch   PetscCall(SNESSetOptionsPrefix(snes_water, "water_"));
5759566063dSJacob Faibussowitsch   PetscCall(SNESSetFunction(snes_water, F, FormFunction, &user));
5769566063dSJacob Faibussowitsch   PetscCall(SNESMonitorSet(snes_water, UserMonitor, &user, NULL));
5779566063dSJacob Faibussowitsch   PetscCall(SNESSetFromOptions(snes_water));
578c4762a1bSJed Brown 
579c4762a1bSJed Brown   if (viewX) {
5809566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Water Solution:\n"));
5819566063dSJacob Faibussowitsch     PetscCall(VecView(X, PETSC_VIEWER_STDOUT_WORLD));
582c4762a1bSJed Brown   }
5839566063dSJacob Faibussowitsch   PetscCall(PetscLogStagePop());
584c4762a1bSJed Brown 
585c4762a1bSJed Brown   /* (4) Solve */
586c4762a1bSJed Brown   /*-----------*/
5879566063dSJacob Faibussowitsch   PetscCall(PetscLogStageRegister("SNES Solve", &stage[3]));
5889566063dSJacob Faibussowitsch   PetscCall(PetscLogStagePush(stage[3]));
589c4762a1bSJed Brown   user.it = 0;
590c4762a1bSJed Brown   reason  = SNES_DIVERGED_DTOL;
591c4762a1bSJed Brown   while (user.it < it_max && (PetscInt)reason < 0) {
592c4762a1bSJed Brown #if 0
593c4762a1bSJed Brown     user.subsnes_id = 0;
5949566063dSJacob Faibussowitsch     PetscCall(SNESSolve(snes_power,NULL,X));
595c4762a1bSJed Brown 
596c4762a1bSJed Brown     user.subsnes_id = 1;
5979566063dSJacob Faibussowitsch     PetscCall(SNESSolve(snes_water,NULL,X));
598c4762a1bSJed Brown #endif
5992bf73ac6SHong Zhang     user.subsnes_id = Nsubnet;
6009566063dSJacob Faibussowitsch     PetscCall(SNESSolve(snes, NULL, X));
601c4762a1bSJed Brown 
6029566063dSJacob Faibussowitsch     PetscCall(SNESGetConvergedReason(snes, &reason));
603c4762a1bSJed Brown     user.it++;
604c4762a1bSJed Brown   }
60563a3b9bcSJacob Faibussowitsch   PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Coupled_SNES converged in %" PetscInt_FMT " iterations\n", user.it));
606c4762a1bSJed Brown   if (viewX) {
6079566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Final Solution:\n"));
6089566063dSJacob Faibussowitsch     PetscCall(VecView(X, PETSC_VIEWER_STDOUT_WORLD));
609c4762a1bSJed Brown   }
6109566063dSJacob Faibussowitsch   PetscCall(PetscLogStagePop());
611c4762a1bSJed Brown 
612c4762a1bSJed Brown   /* Free objects */
613c4762a1bSJed Brown   /* -------------*/
6149566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&X));
6159566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&F));
6169566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(networkdm, &user.localXold));
617c4762a1bSJed Brown 
6189566063dSJacob Faibussowitsch   PetscCall(SNESDestroy(&snes));
6199566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Jac));
6209566063dSJacob Faibussowitsch   PetscCall(SNESDestroy(&snes_power));
6219566063dSJacob Faibussowitsch   PetscCall(SNESDestroy(&snes_water));
622c4762a1bSJed Brown 
6239566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&networkdm));
6249566063dSJacob Faibussowitsch   PetscCall(PetscFinalize());
625b122ec5aSJacob Faibussowitsch   return 0;
626c4762a1bSJed Brown }
627c4762a1bSJed Brown 
628c4762a1bSJed Brown /*TEST
629c4762a1bSJed Brown 
630c4762a1bSJed Brown    build:
631dfd57a17SPierre Jolivet      requires: !complex double defined(PETSC_HAVE_ATTRIBUTEALIGNED)
632c4762a1bSJed Brown      depends: power/PFReadData.c power/pffunctions.c water/waterreaddata.c water/waterfunctions.c
633c4762a1bSJed Brown 
634c4762a1bSJed Brown    test:
6352bf73ac6SHong Zhang       args: -coupled_snes_converged_reason -options_left no -viewDM
636c4762a1bSJed Brown       localrunfiles: ex1options power/case9.m water/sample1.inp
637c4762a1bSJed Brown       output_file: output/ex1.out
638c4762a1bSJed Brown 
639c4762a1bSJed Brown    test:
640c4762a1bSJed Brown       suffix: 2
641c4762a1bSJed Brown       nsize: 3
6422bf73ac6SHong Zhang       args: -coupled_snes_converged_reason -options_left no -petscpartitioner_type parmetis
643c4762a1bSJed Brown       localrunfiles: ex1options power/case9.m water/sample1.inp
644d5c9c0c4SHong Zhang       output_file: output/ex1_2.out
6452bf73ac6SHong Zhang       requires: parmetis
6462bf73ac6SHong Zhang 
6472bf73ac6SHong Zhang #   test:
6482bf73ac6SHong Zhang #      suffix: 3
6492bf73ac6SHong Zhang #      nsize: 3
6502bf73ac6SHong Zhang #      args: -coupled_snes_converged_reason -options_left no -distribute false
6512bf73ac6SHong Zhang #      localrunfiles: ex1options power/case9.m water/sample1.inp
6522bf73ac6SHong Zhang #      output_file: output/ex1_2.out
653d5c9c0c4SHong Zhang 
654d5c9c0c4SHong Zhang    test:
6552bf73ac6SHong Zhang       suffix: 4
6562bf73ac6SHong Zhang       nsize: 4
6572bf73ac6SHong Zhang       args: -coupled_snes_converged_reason -options_left no -petscpartitioner_type simple -viewDM
658d5c9c0c4SHong Zhang       localrunfiles: ex1options power/case9.m water/sample1.inp
6592bf73ac6SHong Zhang       output_file: output/ex1_4.out
660c4762a1bSJed Brown 
661c4762a1bSJed Brown TEST*/
662