xref: /petsc/src/snes/tutorials/network/ex1.c (revision 63a3b9bc7a1f24f247904ccba9383635fe6abade)
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 
19c4762a1bSJed Brown PetscErrorCode UserMonitor(SNES snes,PetscInt its,PetscReal fnorm ,void *appctx)
20c4762a1bSJed Brown {
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) {
34*63a3b9bcSJacob 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 {
36*63a3b9bcSJacob 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));
44c4762a1bSJed Brown   PetscFunctionReturn(0);
45c4762a1bSJed Brown }
46c4762a1bSJed Brown 
47c4762a1bSJed Brown PetscErrorCode FormJacobian_subPower(SNES snes,Vec X, Mat J,Mat Jpre,void *appctx)
48c4762a1bSJed Brown {
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));
91c4762a1bSJed Brown   PetscFunctionReturn(0);
92c4762a1bSJed Brown }
93c4762a1bSJed Brown 
94c4762a1bSJed Brown /* Dummy equation localF(X) = localX - localXold */
95c4762a1bSJed Brown PetscErrorCode FormFunction_Dummy(DM networkdm,Vec localX, Vec localF,PetscInt nv,PetscInt ne,const PetscInt* vtx,const PetscInt* edges,void* appctx)
96c4762a1bSJed Brown {
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));
115c4762a1bSJed Brown     for (j=0; j<nvar; j++) {
116c4762a1bSJed Brown       farr[offset+j] = xarr[offset+j] - xoldarr[offset+j];
117c4762a1bSJed Brown     }
118c4762a1bSJed Brown   }
119c4762a1bSJed Brown 
1209566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(localX,&xarr));
1219566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(localXold,&xoldarr));
1229566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(localF,&farr));
123c4762a1bSJed Brown   PetscFunctionReturn(0);
124c4762a1bSJed Brown }
125c4762a1bSJed Brown 
126c4762a1bSJed Brown PetscErrorCode FormFunction(SNES snes,Vec X,Vec F,void *appctx)
127c4762a1bSJed Brown {
128c4762a1bSJed Brown   DM             networkdm;
129c4762a1bSJed Brown   Vec            localX,localF;
1302bf73ac6SHong Zhang   PetscInt       nv,ne,v;
131c4762a1bSJed Brown   const PetscInt *vtx,*edges;
132c4762a1bSJed Brown   PetscMPIInt    rank;
133c4762a1bSJed Brown   MPI_Comm       comm;
134c4762a1bSJed Brown   UserCtx        *user = (UserCtx*)appctx;
135c4762a1bSJed Brown   UserCtx_Power  appctx_power = (*user).appctx_power;
1362bf73ac6SHong Zhang   AppCtx_Water   appctx_water = (*user).appctx_water;
137c4762a1bSJed Brown 
138c4762a1bSJed Brown   PetscFunctionBegin;
1399566063dSJacob Faibussowitsch   PetscCall(SNESGetDM(snes,&networkdm));
1409566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)networkdm,&comm));
1419566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm,&rank));
142c4762a1bSJed Brown 
1439566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(networkdm,&localX));
1449566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(networkdm,&localF));
1459566063dSJacob Faibussowitsch   PetscCall(VecSet(F,0.0));
1469566063dSJacob Faibussowitsch   PetscCall(VecSet(localF,0.0));
147c4762a1bSJed Brown 
1489566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalBegin(networkdm,X,INSERT_VALUES,localX));
1499566063dSJacob Faibussowitsch   PetscCall(DMGlobalToLocalEnd(networkdm,X,INSERT_VALUES,localX));
150c4762a1bSJed Brown 
151c4762a1bSJed Brown   /* Form Function for power subnetwork */
1529566063dSJacob Faibussowitsch   PetscCall(DMNetworkGetSubnetwork(networkdm,0,&nv,&ne,&vtx,&edges));
153c4762a1bSJed Brown   if (user->subsnes_id == 1) { /* snes_water only */
1549566063dSJacob Faibussowitsch     PetscCall(FormFunction_Dummy(networkdm,localX,localF,nv,ne,vtx,edges,user));
155c4762a1bSJed Brown   } else {
1569566063dSJacob Faibussowitsch     PetscCall(FormFunction_Power(networkdm,localX,localF,nv,ne,vtx,edges,&appctx_power));
157c4762a1bSJed Brown   }
158c4762a1bSJed Brown 
159c4762a1bSJed Brown   /* Form Function for water subnetwork */
1609566063dSJacob Faibussowitsch   PetscCall(DMNetworkGetSubnetwork(networkdm,1,&nv,&ne,&vtx,&edges));
161c4762a1bSJed Brown   if (user->subsnes_id == 0) { /* snes_power only */
1629566063dSJacob Faibussowitsch     PetscCall(FormFunction_Dummy(networkdm,localX,localF,nv,ne,vtx,edges,user));
163c4762a1bSJed Brown   } else {
1649566063dSJacob Faibussowitsch     PetscCall(FormFunction_Water(networkdm,localX,localF,nv,ne,vtx,edges,NULL));
165c4762a1bSJed Brown   }
166c4762a1bSJed Brown 
1672bf73ac6SHong Zhang   /* Illustrate how to access the coupling vertex of the subnetworks without doing anything to F yet */
1689566063dSJacob Faibussowitsch   PetscCall(DMNetworkGetSharedVertices(networkdm,&nv,&vtx));
1692bf73ac6SHong Zhang   for (v=0; v<nv; v++) {
1702bf73ac6SHong Zhang     PetscInt       key,ncomp,nvar,nconnedges,k,e,keye,goffset[3];
171c4762a1bSJed Brown     void*          component;
1722bf73ac6SHong Zhang     const PetscInt *connedges;
173c4762a1bSJed Brown 
1749566063dSJacob Faibussowitsch     PetscCall(DMNetworkGetComponent(networkdm,vtx[v],ALL_COMPONENTS,NULL,NULL,&nvar));
1759566063dSJacob Faibussowitsch     PetscCall(DMNetworkGetNumComponents(networkdm,vtx[v],&ncomp));
176*63a3b9bcSJacob Faibussowitsch     /* printf("  [%d] coupling vertex[%" PetscInt_FMT "]: v %" PetscInt_FMT ", ncomp %" PetscInt_FMT "; nvar %" PetscInt_FMT "\n",rank,v,vtx[v], ncomp,nvar); */
177c4762a1bSJed Brown 
1782bf73ac6SHong Zhang     for (k=0; k<ncomp; k++) {
1799566063dSJacob Faibussowitsch       PetscCall(DMNetworkGetComponent(networkdm,vtx[v],k,&key,&component,&nvar));
1809566063dSJacob Faibussowitsch       PetscCall(DMNetworkGetGlobalVecOffset(networkdm,vtx[v],k,&goffset[k]));
181c4762a1bSJed Brown 
1822bf73ac6SHong Zhang       /* Verify the coupling vertex is a powernet load vertex or a water vertex */
1832bf73ac6SHong Zhang       switch (k) {
1842bf73ac6SHong Zhang       case 0:
185*63a3b9bcSJacob Faibussowitsch         PetscCheckFalse(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);
1862bf73ac6SHong Zhang         break;
1872bf73ac6SHong Zhang       case 1:
1882c71b3e2SJacob Faibussowitsch         PetscCheckFalse(key != appctx_power.compkey_load || nvar != 0 || goffset[1] != goffset[0]+2,PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Not a power load vertex");
1892bf73ac6SHong Zhang         break;
1902bf73ac6SHong Zhang       case 2:
1912c71b3e2SJacob Faibussowitsch         PetscCheckFalse(key != appctx_water.compkey_vtx || nvar != 1 || goffset[2] != goffset[1],PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Not a water vertex");
1922bf73ac6SHong Zhang         break;
193*63a3b9bcSJacob Faibussowitsch       default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "k %" PetscInt_FMT " is wrong",k);
1942bf73ac6SHong Zhang       }
195*63a3b9bcSJacob Faibussowitsch       /* printf("  [%d] coupling vertex[%" PetscInt_FMT "]: key %" PetscInt_FMT "; nvar %" PetscInt_FMT ", goffset %" PetscInt_FMT "\n",rank,v,key,nvar,goffset[k]); */
1962bf73ac6SHong Zhang     }
197c4762a1bSJed Brown 
1982bf73ac6SHong Zhang     /* Get its supporting edges */
1999566063dSJacob Faibussowitsch     PetscCall(DMNetworkGetSupportingEdges(networkdm,vtx[v],&nconnedges,&connedges));
200*63a3b9bcSJacob Faibussowitsch     /* printf("\n[%d] coupling vertex: nconnedges %" PetscInt_FMT "\n",rank,nconnedges); */
201c4762a1bSJed Brown     for (k=0; k<nconnedges; k++) {
202c4762a1bSJed Brown       e = connedges[k];
2039566063dSJacob Faibussowitsch       PetscCall(DMNetworkGetNumComponents(networkdm,e,&ncomp));
204*63a3b9bcSJacob Faibussowitsch       /* printf("\n  [%d] connected edge[%" PetscInt_FMT "]=%" PetscInt_FMT " has ncomp %" PetscInt_FMT "\n",rank,k,e,ncomp); */
2059566063dSJacob Faibussowitsch       PetscCall(DMNetworkGetComponent(networkdm,e,0,&keye,&component,NULL));
206c4762a1bSJed Brown       if (keye == appctx_water.compkey_edge) { /* water_compkey_edge */
207c4762a1bSJed Brown         EDGE_Water        edge=(EDGE_Water)component;
208c4762a1bSJed Brown         if (edge->type == EDGE_TYPE_PUMP) {
209*63a3b9bcSJacob Faibussowitsch           /* printf("  connected edge[%" PetscInt_FMT "]=%" PetscInt_FMT " has keye=%" PetscInt_FMT ", is appctx_water.compkey_edge with EDGE_TYPE_PUMP\n",k,e,keye); */
210c4762a1bSJed Brown         }
2112bf73ac6SHong Zhang       } else { /* ower->compkey_branch */
21208401ef6SPierre Jolivet         PetscCheck(keye == appctx_power.compkey_branch,PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Not a power branch");
213c4762a1bSJed Brown       }
214c4762a1bSJed Brown     }
215c4762a1bSJed Brown   }
216c4762a1bSJed Brown 
2179566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(networkdm,&localX));
218c4762a1bSJed Brown 
2199566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalBegin(networkdm,localF,ADD_VALUES,F));
2209566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalEnd(networkdm,localF,ADD_VALUES,F));
2219566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(networkdm,&localF));
2222bf73ac6SHong Zhang #if 0
223dd400576SPatrick Sanan   if (rank == 0) printf("F:\n");
2249566063dSJacob Faibussowitsch   PetscCall(VecView(F,PETSC_VIEWER_STDOUT_WORLD));
2252bf73ac6SHong Zhang #endif
226c4762a1bSJed Brown   PetscFunctionReturn(0);
227c4762a1bSJed Brown }
228c4762a1bSJed Brown 
229c4762a1bSJed Brown PetscErrorCode SetInitialGuess(DM networkdm,Vec X,void* appctx)
230c4762a1bSJed Brown {
2312bf73ac6SHong Zhang   PetscInt       nv,ne,i,j,ncomp,offset,key;
232c4762a1bSJed Brown   const PetscInt *vtx,*edges;
233c4762a1bSJed Brown   UserCtx        *user = (UserCtx*)appctx;
234c4762a1bSJed Brown   Vec            localX = user->localXold;
235c4762a1bSJed Brown   UserCtx_Power  appctx_power = (*user).appctx_power;
2362bf73ac6SHong Zhang   AppCtx_Water   appctx_water = (*user).appctx_water;
2372bf73ac6SHong Zhang   PetscBool      ghost;
2382bf73ac6SHong Zhang   PetscScalar    *xarr;
2392bf73ac6SHong Zhang   VERTEX_Power   bus;
2402bf73ac6SHong Zhang   VERTEX_Water   vertex;
2412bf73ac6SHong Zhang   void*          component;
2422bf73ac6SHong Zhang   GEN            gen;
243c4762a1bSJed Brown 
244c4762a1bSJed Brown   PetscFunctionBegin;
2459566063dSJacob Faibussowitsch   PetscCall(VecSet(X,0.0));
2469566063dSJacob Faibussowitsch   PetscCall(VecSet(localX,0.0));
247c4762a1bSJed Brown 
248c4762a1bSJed Brown   /* Set initial guess for power subnetwork */
2499566063dSJacob Faibussowitsch   PetscCall(DMNetworkGetSubnetwork(networkdm,0,&nv,&ne,&vtx,&edges));
2509566063dSJacob Faibussowitsch   PetscCall(SetInitialGuess_Power(networkdm,localX,nv,ne,vtx,edges,&appctx_power));
251c4762a1bSJed Brown 
252c4762a1bSJed Brown   /* Set initial guess for water subnetwork */
2539566063dSJacob Faibussowitsch   PetscCall(DMNetworkGetSubnetwork(networkdm,1,&nv,&ne,&vtx,&edges));
2549566063dSJacob Faibussowitsch   PetscCall(SetInitialGuess_Water(networkdm,localX,nv,ne,vtx,edges,NULL));
255c4762a1bSJed Brown 
2562bf73ac6SHong Zhang   /* Set initial guess at the coupling vertex */
2579566063dSJacob Faibussowitsch   PetscCall(VecGetArray(localX,&xarr));
2589566063dSJacob Faibussowitsch   PetscCall(DMNetworkGetSharedVertices(networkdm,&nv,&vtx));
2592bf73ac6SHong Zhang   for (i=0; i<nv; i++) {
2609566063dSJacob Faibussowitsch     PetscCall(DMNetworkIsGhostVertex(networkdm,vtx[i],&ghost));
2612bf73ac6SHong Zhang     if (ghost) continue;
2622bf73ac6SHong Zhang 
2639566063dSJacob Faibussowitsch     PetscCall(DMNetworkGetNumComponents(networkdm,vtx[i],&ncomp));
2642bf73ac6SHong Zhang     for (j=0; j<ncomp; j++) {
2659566063dSJacob Faibussowitsch       PetscCall(DMNetworkGetLocalVecOffset(networkdm,vtx[i],j,&offset));
2669566063dSJacob Faibussowitsch       PetscCall(DMNetworkGetComponent(networkdm,vtx[i],j,&key,(void**)&component,NULL));
2672bf73ac6SHong Zhang       if (key == appctx_power.compkey_bus) {
2682bf73ac6SHong Zhang         bus = (VERTEX_Power)(component);
2692bf73ac6SHong Zhang         xarr[offset]   = bus->va*PETSC_PI/180.0;
2702bf73ac6SHong Zhang         xarr[offset+1] = bus->vm;
2712bf73ac6SHong Zhang       } else if (key == appctx_power.compkey_gen) {
2722bf73ac6SHong Zhang         gen = (GEN)(component);
2732bf73ac6SHong Zhang         if (!gen->status) continue;
2742bf73ac6SHong Zhang         xarr[offset+1] = gen->vs;
2752bf73ac6SHong Zhang       } else if (key == appctx_water.compkey_vtx) {
2762bf73ac6SHong Zhang         vertex = (VERTEX_Water)(component);
2772bf73ac6SHong Zhang         if (vertex->type == VERTEX_TYPE_JUNCTION) {
2782bf73ac6SHong Zhang           xarr[offset] = 100;
2792bf73ac6SHong Zhang         } else if (vertex->type == VERTEX_TYPE_RESERVOIR) {
2802bf73ac6SHong Zhang           xarr[offset] = vertex->res.head;
2812bf73ac6SHong Zhang         } else {
2822bf73ac6SHong Zhang           xarr[offset] = vertex->tank.initlvl + vertex->tank.elev;
283c4762a1bSJed Brown         }
2842bf73ac6SHong Zhang       }
2852bf73ac6SHong Zhang     }
2862bf73ac6SHong Zhang   }
2879566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(localX,&xarr));
288c4762a1bSJed Brown 
2899566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalBegin(networkdm,localX,ADD_VALUES,X));
2909566063dSJacob Faibussowitsch   PetscCall(DMLocalToGlobalEnd(networkdm,localX,ADD_VALUES,X));
291c4762a1bSJed Brown   PetscFunctionReturn(0);
292c4762a1bSJed Brown }
293c4762a1bSJed Brown 
294c4762a1bSJed Brown int main(int argc,char **argv)
295c4762a1bSJed Brown {
296c4762a1bSJed Brown   DM               networkdm;
297c4762a1bSJed Brown   PetscLogStage    stage[4];
298d5c9c0c4SHong Zhang   PetscMPIInt      rank,size;
2992bf73ac6SHong Zhang   PetscInt         Nsubnet=2,numVertices[2],numEdges[2],i,j,nv,ne,it_max=10;
300c4762a1bSJed Brown   const PetscInt   *vtx,*edges;
301c4762a1bSJed Brown   Vec              X,F;
302c4762a1bSJed Brown   SNES             snes,snes_power,snes_water;
303c4762a1bSJed Brown   Mat              Jac;
3042bf73ac6SHong Zhang   PetscBool        ghost,viewJ=PETSC_FALSE,viewX=PETSC_FALSE,viewDM=PETSC_FALSE,test=PETSC_FALSE,distribute=PETSC_TRUE,flg;
305c4762a1bSJed Brown   UserCtx          user;
306c4762a1bSJed Brown   SNESConvergedReason reason;
307c4762a1bSJed Brown 
308c4762a1bSJed Brown   /* Power subnetwork */
309c4762a1bSJed Brown   UserCtx_Power       *appctx_power  = &user.appctx_power;
310c4762a1bSJed Brown   char                pfdata_file[PETSC_MAX_PATH_LEN] = "power/case9.m";
311c4762a1bSJed Brown   PFDATA              *pfdata = NULL;
3122bf73ac6SHong Zhang   PetscInt            genj,loadj,*edgelist_power = NULL,power_netnum;
313c4762a1bSJed Brown   PetscScalar         Sbase = 0.0;
314c4762a1bSJed Brown 
315c4762a1bSJed Brown   /* Water subnetwork */
316c4762a1bSJed Brown   AppCtx_Water        *appctx_water = &user.appctx_water;
317c4762a1bSJed Brown   WATERDATA           *waterdata = NULL;
318c4762a1bSJed Brown   char                waterdata_file[PETSC_MAX_PATH_LEN] = "water/sample1.inp";
3192bf73ac6SHong Zhang   PetscInt            *edgelist_water = NULL,water_netnum;
320c4762a1bSJed Brown 
3212bf73ac6SHong Zhang   /* Shared vertices between subnetworks */
3222bf73ac6SHong Zhang   PetscInt           power_svtx,water_svtx;
323c4762a1bSJed Brown 
3249566063dSJacob Faibussowitsch   PetscCall(PetscInitialize(&argc,&argv,"ex1options",help));
3259566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD,&rank));
3269566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PETSC_COMM_WORLD,&size));
327c4762a1bSJed Brown 
328c4762a1bSJed Brown   /* (1) Read Data - Only rank 0 reads the data */
329c4762a1bSJed Brown   /*--------------------------------------------*/
3309566063dSJacob Faibussowitsch   PetscCall(PetscLogStageRegister("Read Data",&stage[0]));
3319566063dSJacob Faibussowitsch   PetscCall(PetscLogStagePush(stage[0]));
332c4762a1bSJed Brown 
3332bf73ac6SHong Zhang   for (i=0; i<Nsubnet; i++) {
334c4762a1bSJed Brown     numVertices[i] = 0;
335c4762a1bSJed Brown     numEdges[i]    = 0;
336c4762a1bSJed Brown   }
337c4762a1bSJed Brown 
3382bf73ac6SHong Zhang   /* All processes READ THE DATA FOR THE FIRST SUBNETWORK: Electric Power Grid */
3392bf73ac6SHong Zhang   /* Used for shared vertex, because currently the coupling info must be available in all processes!!! */
3409566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetString(NULL,NULL,"-pfdata",pfdata_file,PETSC_MAX_PATH_LEN-1,NULL));
3419566063dSJacob Faibussowitsch   PetscCall(PetscNew(&pfdata));
3429566063dSJacob Faibussowitsch   PetscCall(PFReadMatPowerData(pfdata,pfdata_file));
343dd400576SPatrick Sanan   if (rank == 0) {
344*63a3b9bcSJacob Faibussowitsch     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));
3452bf73ac6SHong Zhang   }
346c4762a1bSJed Brown   Sbase = pfdata->sbase;
3472bf73ac6SHong Zhang   if (rank == 0) { /* proc[0] will create Electric Power Grid */
348c4762a1bSJed Brown     numEdges[0]    = pfdata->nbranch;
349c4762a1bSJed Brown     numVertices[0] = pfdata->nbus;
350c4762a1bSJed Brown 
3519566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(2*numEdges[0],&edgelist_power));
3529566063dSJacob Faibussowitsch     PetscCall(GetListofEdges_Power(pfdata,edgelist_power));
353c4762a1bSJed Brown   }
354c4762a1bSJed Brown   /* Broadcast power Sbase to all processors */
3559566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Bcast(&Sbase,1,MPIU_SCALAR,0,PETSC_COMM_WORLD));
356c4762a1bSJed Brown   appctx_power->Sbase     = Sbase;
357c4762a1bSJed Brown   appctx_power->jac_error = PETSC_FALSE;
358c4762a1bSJed Brown   /* If external option activated. Introduce error in jacobian */
3599566063dSJacob Faibussowitsch   PetscCall(PetscOptionsHasName(NULL,NULL, "-jac_error", &appctx_power->jac_error));
360c4762a1bSJed Brown 
3612bf73ac6SHong Zhang   /* All processes READ THE DATA FOR THE SECOND SUBNETWORK: Water */
3622bf73ac6SHong Zhang   /* Used for shared vertex, because currently the coupling info must be available in all processes!!! */
3639566063dSJacob Faibussowitsch   PetscCall(PetscNew(&waterdata));
3649566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetString(NULL,NULL,"-waterdata",waterdata_file,PETSC_MAX_PATH_LEN-1,NULL));
3659566063dSJacob Faibussowitsch   PetscCall(WaterReadData(waterdata,waterdata_file));
3662bf73ac6SHong Zhang   if (size == 1 || (size > 1 && rank == 1)) {
3679566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(2*waterdata->nedge,&edgelist_water));
3689566063dSJacob Faibussowitsch     PetscCall(GetListofEdges_Water(waterdata,edgelist_water));
369c4762a1bSJed Brown     numEdges[1]    = waterdata->nedge;
370c4762a1bSJed Brown     numVertices[1] = waterdata->nvertex;
371c4762a1bSJed Brown   }
3722bf73ac6SHong Zhang   PetscLogStagePop();
373c4762a1bSJed Brown 
3742bf73ac6SHong Zhang   /* (2) Create a network consist of two subnetworks */
3752bf73ac6SHong Zhang   /*-------------------------------------------------*/
3769566063dSJacob Faibussowitsch   PetscCall(PetscLogStageRegister("Net Setup",&stage[1]));
3779566063dSJacob Faibussowitsch   PetscCall(PetscLogStagePush(stage[1]));
378c4762a1bSJed Brown 
3799566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(NULL,NULL,"-viewDM",&viewDM,NULL));
3809566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(NULL,NULL,"-test",&test,NULL));
3819566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(NULL,NULL,"-distribute",&distribute,NULL));
382c4762a1bSJed Brown 
383c4762a1bSJed Brown   /* Create an empty network object */
3849566063dSJacob Faibussowitsch   PetscCall(DMNetworkCreate(PETSC_COMM_WORLD,&networkdm));
385c4762a1bSJed Brown 
386c4762a1bSJed Brown   /* Register the components in the network */
3879566063dSJacob Faibussowitsch   PetscCall(DMNetworkRegisterComponent(networkdm,"branchstruct",sizeof(struct _p_EDGE_Power),&appctx_power->compkey_branch));
3889566063dSJacob Faibussowitsch   PetscCall(DMNetworkRegisterComponent(networkdm,"busstruct",sizeof(struct _p_VERTEX_Power),&appctx_power->compkey_bus));
3899566063dSJacob Faibussowitsch   PetscCall(DMNetworkRegisterComponent(networkdm,"genstruct",sizeof(struct _p_GEN),&appctx_power->compkey_gen));
3909566063dSJacob Faibussowitsch   PetscCall(DMNetworkRegisterComponent(networkdm,"loadstruct",sizeof(struct _p_LOAD),&appctx_power->compkey_load));
391c4762a1bSJed Brown 
3929566063dSJacob Faibussowitsch   PetscCall(DMNetworkRegisterComponent(networkdm,"edge_water",sizeof(struct _p_EDGE_Water),&appctx_water->compkey_edge));
3939566063dSJacob Faibussowitsch   PetscCall(DMNetworkRegisterComponent(networkdm,"vertex_water",sizeof(struct _p_VERTEX_Water),&appctx_water->compkey_vtx));
3942bf73ac6SHong Zhang #if 0
3959566063dSJacob Faibussowitsch   PetscCall(PetscPrintf(PETSC_COMM_WORLD,"power->compkey_branch %d\n",appctx_power->compkey_branch));
3969566063dSJacob Faibussowitsch   PetscCall(PetscPrintf(PETSC_COMM_WORLD,"power->compkey_bus    %d\n",appctx_power->compkey_bus));
3979566063dSJacob Faibussowitsch   PetscCall(PetscPrintf(PETSC_COMM_WORLD,"power->compkey_gen    %d\n",appctx_power->compkey_gen));
3989566063dSJacob Faibussowitsch   PetscCall(PetscPrintf(PETSC_COMM_WORLD,"power->compkey_load   %d\n",appctx_power->compkey_load));
3999566063dSJacob Faibussowitsch   PetscCall(PetscPrintf(PETSC_COMM_WORLD,"water->compkey_edge   %d\n",appctx_water->compkey_edge));
4009566063dSJacob Faibussowitsch   PetscCall(PetscPrintf(PETSC_COMM_WORLD,"water->compkey_vtx    %d\n",appctx_water->compkey_vtx));
4012bf73ac6SHong Zhang #endif
402*63a3b9bcSJacob 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]));
4039566063dSJacob Faibussowitsch   PetscCall(PetscSynchronizedFlush(PETSC_COMM_WORLD,PETSC_STDOUT));
404c4762a1bSJed Brown 
4059566063dSJacob Faibussowitsch   PetscCall(DMNetworkSetNumSubNetworks(networkdm,PETSC_DECIDE,Nsubnet));
4069566063dSJacob Faibussowitsch   PetscCall(DMNetworkAddSubnetwork(networkdm,"power",numEdges[0],edgelist_power,&power_netnum));
4079566063dSJacob Faibussowitsch   PetscCall(DMNetworkAddSubnetwork(networkdm,"water",numEdges[1],edgelist_water,&water_netnum));
408c4762a1bSJed Brown 
4092bf73ac6SHong Zhang   /* vertex subnet[0].4 shares with vertex subnet[1].0 */
4102bf73ac6SHong Zhang   power_svtx = 4; water_svtx = 0;
4119566063dSJacob Faibussowitsch   PetscCall(DMNetworkAddSharedVertices(networkdm,power_netnum,water_netnum,1,&power_svtx,&water_svtx));
412c4762a1bSJed Brown 
413c4762a1bSJed Brown   /* Set up the network layout */
4149566063dSJacob Faibussowitsch   PetscCall(DMNetworkLayoutSetUp(networkdm));
415c4762a1bSJed Brown 
416c4762a1bSJed Brown   /* ADD VARIABLES AND COMPONENTS FOR THE POWER SUBNETWORK */
4172bf73ac6SHong Zhang   /*-------------------------------------------------------*/
418c4762a1bSJed Brown   genj = 0; loadj = 0;
4199566063dSJacob Faibussowitsch   PetscCall(DMNetworkGetSubnetwork(networkdm,power_netnum,&nv,&ne,&vtx,&edges));
4202bf73ac6SHong Zhang 
421c4762a1bSJed Brown   for (i = 0; i < ne; i++) {
4229566063dSJacob Faibussowitsch     PetscCall(DMNetworkAddComponent(networkdm,edges[i],appctx_power->compkey_branch,&pfdata->branch[i],0));
423c4762a1bSJed Brown   }
424c4762a1bSJed Brown 
425c4762a1bSJed Brown   for (i = 0; i < nv; i++) {
4269566063dSJacob Faibussowitsch     PetscCall(DMNetworkIsSharedVertex(networkdm,vtx[i],&flg));
4272bf73ac6SHong Zhang     if (flg) continue;
4282bf73ac6SHong Zhang 
4299566063dSJacob Faibussowitsch     PetscCall(DMNetworkAddComponent(networkdm,vtx[i],appctx_power->compkey_bus,&pfdata->bus[i],2));
430c4762a1bSJed Brown     if (pfdata->bus[i].ngen) {
431c4762a1bSJed Brown       for (j = 0; j < pfdata->bus[i].ngen; j++) {
4329566063dSJacob Faibussowitsch         PetscCall(DMNetworkAddComponent(networkdm,vtx[i],appctx_power->compkey_gen,&pfdata->gen[genj++],0));
433c4762a1bSJed Brown       }
434c4762a1bSJed Brown     }
435c4762a1bSJed Brown     if (pfdata->bus[i].nload) {
436c4762a1bSJed Brown       for (j=0; j < pfdata->bus[i].nload; j++) {
4379566063dSJacob Faibussowitsch         PetscCall(DMNetworkAddComponent(networkdm,vtx[i],appctx_power->compkey_load,&pfdata->load[loadj++],0));
438c4762a1bSJed Brown       }
439c4762a1bSJed Brown     }
440c4762a1bSJed Brown   }
441c4762a1bSJed Brown 
442c4762a1bSJed Brown   /* ADD VARIABLES AND COMPONENTS FOR THE WATER SUBNETWORK */
4432bf73ac6SHong Zhang   /*-------------------------------------------------------*/
4449566063dSJacob Faibussowitsch   PetscCall(DMNetworkGetSubnetwork(networkdm,water_netnum,&nv,&ne,&vtx,&edges));
445c4762a1bSJed Brown   for (i = 0; i < ne; i++) {
4469566063dSJacob Faibussowitsch     PetscCall(DMNetworkAddComponent(networkdm,edges[i],appctx_water->compkey_edge,&waterdata->edge[i],0));
447c4762a1bSJed Brown   }
448c4762a1bSJed Brown 
449c4762a1bSJed Brown   for (i = 0; i < nv; i++) {
4509566063dSJacob Faibussowitsch     PetscCall(DMNetworkIsSharedVertex(networkdm,vtx[i],&flg));
4512bf73ac6SHong Zhang     if (flg) continue;
4522bf73ac6SHong Zhang 
4539566063dSJacob Faibussowitsch     PetscCall(DMNetworkAddComponent(networkdm,vtx[i],appctx_water->compkey_vtx,&waterdata->vertex[i],1));
454c4762a1bSJed Brown   }
4552bf73ac6SHong Zhang 
456eac198afSGetnet   /* 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 */
4572bf73ac6SHong Zhang   /*----------------------------------------------------------------------------------------------------------------------------*/
4589566063dSJacob Faibussowitsch   PetscCall(DMNetworkGetSharedVertices(networkdm,&nv,&vtx));
4592bf73ac6SHong Zhang   for (i = 0; i < nv; i++) {
4602bf73ac6SHong Zhang     /* power */
4619566063dSJacob Faibussowitsch     PetscCall(DMNetworkAddComponent(networkdm,vtx[i],appctx_power->compkey_bus,&pfdata->bus[4],2));
4622bf73ac6SHong Zhang     /* bus[4] is a load, add its component */
4639566063dSJacob Faibussowitsch     PetscCall(DMNetworkAddComponent(networkdm,vtx[i],appctx_power->compkey_load,&pfdata->load[0],0));
4642bf73ac6SHong Zhang 
4652bf73ac6SHong Zhang     /* water */
4669566063dSJacob Faibussowitsch     PetscCall(DMNetworkAddComponent(networkdm,vtx[i],appctx_water->compkey_vtx,&waterdata->vertex[0],1));
467c4762a1bSJed Brown   }
468c4762a1bSJed Brown 
469c4762a1bSJed Brown   /* Set up DM for use */
4709566063dSJacob Faibussowitsch   PetscCall(DMSetUp(networkdm));
471c4762a1bSJed Brown   if (viewDM) {
4729566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_WORLD,"\nAfter DMSetUp, DMView:\n"));
4739566063dSJacob Faibussowitsch     PetscCall(DMView(networkdm,PETSC_VIEWER_STDOUT_WORLD));
474c4762a1bSJed Brown   }
475c4762a1bSJed Brown 
476c4762a1bSJed Brown   /* Free user objects */
4779566063dSJacob Faibussowitsch   PetscCall(PetscFree(edgelist_power));
4789566063dSJacob Faibussowitsch   PetscCall(PetscFree(pfdata->bus));
4799566063dSJacob Faibussowitsch   PetscCall(PetscFree(pfdata->gen));
4809566063dSJacob Faibussowitsch   PetscCall(PetscFree(pfdata->branch));
4819566063dSJacob Faibussowitsch   PetscCall(PetscFree(pfdata->load));
4829566063dSJacob Faibussowitsch   PetscCall(PetscFree(pfdata));
4832bf73ac6SHong Zhang 
4849566063dSJacob Faibussowitsch   PetscCall(PetscFree(edgelist_water));
4859566063dSJacob Faibussowitsch   PetscCall(PetscFree(waterdata->vertex));
4869566063dSJacob Faibussowitsch   PetscCall(PetscFree(waterdata->edge));
4879566063dSJacob Faibussowitsch   PetscCall(PetscFree(waterdata));
488c4762a1bSJed Brown 
489d5c9c0c4SHong Zhang   /* Re-distribute networkdm to multiple processes for better job balance */
4902bf73ac6SHong Zhang   if (size >1 && distribute) {
4919566063dSJacob Faibussowitsch     PetscCall(DMNetworkDistribute(&networkdm,0));
492c4762a1bSJed Brown     if (viewDM) {
4939566063dSJacob Faibussowitsch       PetscCall(PetscPrintf(PETSC_COMM_WORLD,"\nAfter DMNetworkDistribute, DMView:\n"));
4949566063dSJacob Faibussowitsch       PetscCall(DMView(networkdm,PETSC_VIEWER_STDOUT_WORLD));
495c4762a1bSJed Brown     }
496d5c9c0c4SHong Zhang   }
497c4762a1bSJed Brown 
4982bf73ac6SHong Zhang   /* Test DMNetworkGetSubnetwork() and DMNetworkGetSubnetworkSharedVertices() */
499c4762a1bSJed Brown   if (test) {
5002bf73ac6SHong Zhang     PetscInt  v,gidx;
5019566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Barrier(PETSC_COMM_WORLD));
5022bf73ac6SHong Zhang     for (i=0; i<Nsubnet; i++) {
5039566063dSJacob Faibussowitsch       PetscCall(DMNetworkGetSubnetwork(networkdm,i,&nv,&ne,&vtx,&edges));
504*63a3b9bcSJacob Faibussowitsch       PetscCall(PetscPrintf(PETSC_COMM_SELF,"[%d] After distribute, subnet[%" PetscInt_FMT "] ne %" PetscInt_FMT ", nv %" PetscInt_FMT "\n",rank,i,ne,nv));
5059566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Barrier(PETSC_COMM_WORLD));
506c4762a1bSJed Brown 
5072bf73ac6SHong Zhang       for (v=0; v<nv; v++) {
5089566063dSJacob Faibussowitsch         PetscCall(DMNetworkIsGhostVertex(networkdm,vtx[v],&ghost));
5099566063dSJacob Faibussowitsch         PetscCall(DMNetworkGetGlobalVertexIndex(networkdm,vtx[v],&gidx));
510*63a3b9bcSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF,"[%d] subnet[%" PetscInt_FMT "] v %" PetscInt_FMT " %" PetscInt_FMT "; ghost %d\n",rank,i,vtx[v],gidx,ghost));
511c4762a1bSJed Brown       }
5129566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Barrier(PETSC_COMM_WORLD));
513c4762a1bSJed Brown     }
5149566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Barrier(PETSC_COMM_WORLD));
5152bf73ac6SHong Zhang 
5169566063dSJacob Faibussowitsch     PetscCall(DMNetworkGetSharedVertices(networkdm,&nv,&vtx));
517*63a3b9bcSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_SELF,"[%d] After distribute, num of shared vertices nsv = %" PetscInt_FMT "\n",rank,nv));
5182bf73ac6SHong Zhang     for (v=0; v<nv; v++) {
5199566063dSJacob Faibussowitsch       PetscCall(DMNetworkGetGlobalVertexIndex(networkdm,vtx[v],&gidx));
520*63a3b9bcSJacob Faibussowitsch       PetscCall(PetscPrintf(PETSC_COMM_SELF,"[%d] sv %" PetscInt_FMT ", gidx=%" PetscInt_FMT "\n",rank,vtx[v],gidx));
5212bf73ac6SHong Zhang     }
5229566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Barrier(PETSC_COMM_WORLD));
523c4762a1bSJed Brown   }
524c4762a1bSJed Brown 
5252bf73ac6SHong Zhang   /* Create solution vector X */
5269566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector(networkdm,&X));
5279566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(X,&F));
5289566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(networkdm,&user.localXold));
5292bf73ac6SHong Zhang   PetscLogStagePop();
530c4762a1bSJed Brown 
531c4762a1bSJed Brown   /* (3) Setup Solvers */
532c4762a1bSJed Brown   /*-------------------*/
5339566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(NULL,NULL,"-viewJ",&viewJ,NULL));
5349566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(NULL,NULL,"-viewX",&viewX,NULL));
535c4762a1bSJed Brown 
5369566063dSJacob Faibussowitsch   PetscCall(PetscLogStageRegister("SNES Setup",&stage[2]));
5379566063dSJacob Faibussowitsch   PetscCall(PetscLogStagePush(stage[2]));
538c4762a1bSJed Brown 
5399566063dSJacob Faibussowitsch   PetscCall(SetInitialGuess(networkdm,X,&user));
540c4762a1bSJed Brown 
541c4762a1bSJed Brown   /* Create coupled snes */
542c4762a1bSJed Brown   /*-------------------- */
5439566063dSJacob Faibussowitsch   PetscCall(PetscPrintf(PETSC_COMM_WORLD,"SNES_coupled setup ......\n"));
5442bf73ac6SHong Zhang   user.subsnes_id = Nsubnet;
5459566063dSJacob Faibussowitsch   PetscCall(SNESCreate(PETSC_COMM_WORLD,&snes));
5469566063dSJacob Faibussowitsch   PetscCall(SNESSetDM(snes,networkdm));
5479566063dSJacob Faibussowitsch   PetscCall(SNESSetOptionsPrefix(snes,"coupled_"));
5489566063dSJacob Faibussowitsch   PetscCall(SNESSetFunction(snes,F,FormFunction,&user));
5499566063dSJacob Faibussowitsch   PetscCall(SNESMonitorSet(snes,UserMonitor,&user,NULL));
5509566063dSJacob Faibussowitsch   PetscCall(SNESSetFromOptions(snes));
551c4762a1bSJed Brown 
552c4762a1bSJed Brown   if (viewJ) {
553c4762a1bSJed Brown     /* View Jac structure */
5549566063dSJacob Faibussowitsch     PetscCall(SNESGetJacobian(snes,&Jac,NULL,NULL,NULL));
5559566063dSJacob Faibussowitsch     PetscCall(MatView(Jac,PETSC_VIEWER_DRAW_WORLD));
556c4762a1bSJed Brown   }
557c4762a1bSJed Brown 
558c4762a1bSJed Brown   if (viewX) {
5599566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_WORLD,"Solution:\n"));
5609566063dSJacob Faibussowitsch     PetscCall(VecView(X,PETSC_VIEWER_STDOUT_WORLD));
561c4762a1bSJed Brown   }
562c4762a1bSJed Brown 
563c4762a1bSJed Brown   if (viewJ) {
564c4762a1bSJed Brown     /* View assembled Jac */
5659566063dSJacob Faibussowitsch     PetscCall(MatView(Jac,PETSC_VIEWER_DRAW_WORLD));
566c4762a1bSJed Brown   }
567c4762a1bSJed Brown 
568c4762a1bSJed Brown   /* Create snes_power */
569c4762a1bSJed Brown   /*-------------------*/
5709566063dSJacob Faibussowitsch   PetscCall(PetscPrintf(PETSC_COMM_WORLD,"SNES_power setup ......\n"));
571c4762a1bSJed Brown 
572c4762a1bSJed Brown   user.subsnes_id = 0;
5739566063dSJacob Faibussowitsch   PetscCall(SNESCreate(PETSC_COMM_WORLD,&snes_power));
5749566063dSJacob Faibussowitsch   PetscCall(SNESSetDM(snes_power,networkdm));
5759566063dSJacob Faibussowitsch   PetscCall(SNESSetOptionsPrefix(snes_power,"power_"));
5769566063dSJacob Faibussowitsch   PetscCall(SNESSetFunction(snes_power,F,FormFunction,&user));
5779566063dSJacob Faibussowitsch   PetscCall(SNESMonitorSet(snes_power,UserMonitor,&user,NULL));
578c4762a1bSJed Brown 
579c4762a1bSJed Brown   /* Use user-provide Jacobian */
5809566063dSJacob Faibussowitsch   PetscCall(DMCreateMatrix(networkdm,&Jac));
5819566063dSJacob Faibussowitsch   PetscCall(SNESSetJacobian(snes_power,Jac,Jac,FormJacobian_subPower,&user));
5829566063dSJacob Faibussowitsch   PetscCall(SNESSetFromOptions(snes_power));
583c4762a1bSJed Brown 
584c4762a1bSJed Brown   if (viewX) {
5859566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_WORLD,"Power Solution:\n"));
5869566063dSJacob Faibussowitsch     PetscCall(VecView(X,PETSC_VIEWER_STDOUT_WORLD));
587c4762a1bSJed Brown   }
588c4762a1bSJed Brown   if (viewJ) {
5899566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_WORLD,"Power Jac:\n"));
5909566063dSJacob Faibussowitsch     PetscCall(SNESGetJacobian(snes_power,&Jac,NULL,NULL,NULL));
5919566063dSJacob Faibussowitsch     PetscCall(MatView(Jac,PETSC_VIEWER_DRAW_WORLD));
5929566063dSJacob Faibussowitsch     /* PetscCall(MatView(Jac,PETSC_VIEWER_STDOUT_WORLD)); */
593c4762a1bSJed Brown   }
594c4762a1bSJed Brown 
595c4762a1bSJed Brown   /* Create snes_water */
596c4762a1bSJed Brown   /*-------------------*/
5979566063dSJacob Faibussowitsch   PetscCall(PetscPrintf(PETSC_COMM_WORLD,"SNES_water setup......\n"));
598c4762a1bSJed Brown 
599c4762a1bSJed Brown   user.subsnes_id = 1;
6009566063dSJacob Faibussowitsch   PetscCall(SNESCreate(PETSC_COMM_WORLD,&snes_water));
6019566063dSJacob Faibussowitsch   PetscCall(SNESSetDM(snes_water,networkdm));
6029566063dSJacob Faibussowitsch   PetscCall(SNESSetOptionsPrefix(snes_water,"water_"));
6039566063dSJacob Faibussowitsch   PetscCall(SNESSetFunction(snes_water,F,FormFunction,&user));
6049566063dSJacob Faibussowitsch   PetscCall(SNESMonitorSet(snes_water,UserMonitor,&user,NULL));
6059566063dSJacob Faibussowitsch   PetscCall(SNESSetFromOptions(snes_water));
606c4762a1bSJed Brown 
607c4762a1bSJed Brown   if (viewX) {
6089566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_WORLD,"Water Solution:\n"));
6099566063dSJacob Faibussowitsch     PetscCall(VecView(X,PETSC_VIEWER_STDOUT_WORLD));
610c4762a1bSJed Brown   }
6119566063dSJacob Faibussowitsch   PetscCall(PetscLogStagePop());
612c4762a1bSJed Brown 
613c4762a1bSJed Brown   /* (4) Solve */
614c4762a1bSJed Brown   /*-----------*/
6159566063dSJacob Faibussowitsch   PetscCall(PetscLogStageRegister("SNES Solve",&stage[3]));
6169566063dSJacob Faibussowitsch   PetscCall(PetscLogStagePush(stage[3]));
617c4762a1bSJed Brown   user.it = 0;
618c4762a1bSJed Brown   reason  = SNES_DIVERGED_DTOL;
619c4762a1bSJed Brown   while (user.it < it_max && (PetscInt)reason<0) {
620c4762a1bSJed Brown #if 0
621c4762a1bSJed Brown     user.subsnes_id = 0;
6229566063dSJacob Faibussowitsch     PetscCall(SNESSolve(snes_power,NULL,X));
623c4762a1bSJed Brown 
624c4762a1bSJed Brown     user.subsnes_id = 1;
6259566063dSJacob Faibussowitsch     PetscCall(SNESSolve(snes_water,NULL,X));
626c4762a1bSJed Brown #endif
6272bf73ac6SHong Zhang     user.subsnes_id = Nsubnet;
6289566063dSJacob Faibussowitsch     PetscCall(SNESSolve(snes,NULL,X));
629c4762a1bSJed Brown 
6309566063dSJacob Faibussowitsch     PetscCall(SNESGetConvergedReason(snes,&reason));
631c4762a1bSJed Brown     user.it++;
632c4762a1bSJed Brown   }
633*63a3b9bcSJacob Faibussowitsch   PetscCall(PetscPrintf(PETSC_COMM_WORLD,"Coupled_SNES converged in %" PetscInt_FMT " iterations\n",user.it));
634c4762a1bSJed Brown   if (viewX) {
6359566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_WORLD,"Final Solution:\n"));
6369566063dSJacob Faibussowitsch     PetscCall(VecView(X,PETSC_VIEWER_STDOUT_WORLD));
637c4762a1bSJed Brown   }
6389566063dSJacob Faibussowitsch   PetscCall(PetscLogStagePop());
639c4762a1bSJed Brown 
640c4762a1bSJed Brown   /* Free objects */
641c4762a1bSJed Brown   /* -------------*/
6429566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&X));
6439566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&F));
6449566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(networkdm,&user.localXold));
645c4762a1bSJed Brown 
6469566063dSJacob Faibussowitsch   PetscCall(SNESDestroy(&snes));
6479566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Jac));
6489566063dSJacob Faibussowitsch   PetscCall(SNESDestroy(&snes_power));
6499566063dSJacob Faibussowitsch   PetscCall(SNESDestroy(&snes_water));
650c4762a1bSJed Brown 
6519566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&networkdm));
6529566063dSJacob Faibussowitsch   PetscCall(PetscFinalize());
653b122ec5aSJacob Faibussowitsch   return 0;
654c4762a1bSJed Brown }
655c4762a1bSJed Brown 
656c4762a1bSJed Brown /*TEST
657c4762a1bSJed Brown 
658c4762a1bSJed Brown    build:
659dfd57a17SPierre Jolivet      requires: !complex double defined(PETSC_HAVE_ATTRIBUTEALIGNED)
660c4762a1bSJed Brown      depends: power/PFReadData.c power/pffunctions.c water/waterreaddata.c water/waterfunctions.c
661c4762a1bSJed Brown 
662c4762a1bSJed Brown    test:
6632bf73ac6SHong Zhang       args: -coupled_snes_converged_reason -options_left no -viewDM
664c4762a1bSJed Brown       localrunfiles: ex1options power/case9.m water/sample1.inp
665c4762a1bSJed Brown       output_file: output/ex1.out
666c4762a1bSJed Brown 
667c4762a1bSJed Brown    test:
668c4762a1bSJed Brown       suffix: 2
669c4762a1bSJed Brown       nsize: 3
6702bf73ac6SHong Zhang       args: -coupled_snes_converged_reason -options_left no -petscpartitioner_type parmetis
671c4762a1bSJed Brown       localrunfiles: ex1options power/case9.m water/sample1.inp
672d5c9c0c4SHong Zhang       output_file: output/ex1_2.out
6732bf73ac6SHong Zhang       requires: parmetis
6742bf73ac6SHong Zhang 
6752bf73ac6SHong Zhang #   test:
6762bf73ac6SHong Zhang #      suffix: 3
6772bf73ac6SHong Zhang #      nsize: 3
6782bf73ac6SHong Zhang #      args: -coupled_snes_converged_reason -options_left no -distribute false
6792bf73ac6SHong Zhang #      localrunfiles: ex1options power/case9.m water/sample1.inp
6802bf73ac6SHong Zhang #      output_file: output/ex1_2.out
681d5c9c0c4SHong Zhang 
682d5c9c0c4SHong Zhang    test:
6832bf73ac6SHong Zhang       suffix: 4
6842bf73ac6SHong Zhang       nsize: 4
6852bf73ac6SHong Zhang       args: -coupled_snes_converged_reason -options_left no -petscpartitioner_type simple -viewDM
686d5c9c0c4SHong Zhang       localrunfiles: ex1options power/case9.m water/sample1.inp
6872bf73ac6SHong Zhang       output_file: output/ex1_4.out
688c4762a1bSJed Brown 
689c4762a1bSJed Brown TEST*/
690