xref: /petsc/src/snes/tutorials/network/ex1.c (revision 327415f76d85372a4417cf1aaa14db707d4d6c04)
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) {
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));
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));
17663a3b9bcSJacob 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:
1850b121fc5SBarry Smith         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);
1862bf73ac6SHong Zhang         break;
1872bf73ac6SHong Zhang       case 1:
1880b121fc5SBarry Smith         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");
1892bf73ac6SHong Zhang         break;
1902bf73ac6SHong Zhang       case 2:
1910b121fc5SBarry Smith         PetscCheck(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;
19363a3b9bcSJacob Faibussowitsch       default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "k %" PetscInt_FMT " is wrong",k);
1942bf73ac6SHong Zhang       }
19563a3b9bcSJacob 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));
20063a3b9bcSJacob 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));
20463a3b9bcSJacob 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) {
20963a3b9bcSJacob 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 
324*327415f7SBarry Smith   PetscFunctionBeginUser;
3259566063dSJacob Faibussowitsch   PetscCall(PetscInitialize(&argc,&argv,"ex1options",help));
3269566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD,&rank));
3279566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(PETSC_COMM_WORLD,&size));
328c4762a1bSJed Brown 
329c4762a1bSJed Brown   /* (1) Read Data - Only rank 0 reads the data */
330c4762a1bSJed Brown   /*--------------------------------------------*/
3319566063dSJacob Faibussowitsch   PetscCall(PetscLogStageRegister("Read Data",&stage[0]));
3329566063dSJacob Faibussowitsch   PetscCall(PetscLogStagePush(stage[0]));
333c4762a1bSJed Brown 
3342bf73ac6SHong Zhang   for (i=0; i<Nsubnet; i++) {
335c4762a1bSJed Brown     numVertices[i] = 0;
336c4762a1bSJed Brown     numEdges[i]    = 0;
337c4762a1bSJed Brown   }
338c4762a1bSJed Brown 
3392bf73ac6SHong Zhang   /* All processes READ THE DATA FOR THE FIRST SUBNETWORK: Electric Power Grid */
3402bf73ac6SHong Zhang   /* Used for shared vertex, because currently the coupling info must be available in all processes!!! */
3419566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetString(NULL,NULL,"-pfdata",pfdata_file,PETSC_MAX_PATH_LEN-1,NULL));
3429566063dSJacob Faibussowitsch   PetscCall(PetscNew(&pfdata));
3439566063dSJacob Faibussowitsch   PetscCall(PFReadMatPowerData(pfdata,pfdata_file));
344dd400576SPatrick Sanan   if (rank == 0) {
34563a3b9bcSJacob 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));
3462bf73ac6SHong Zhang   }
347c4762a1bSJed Brown   Sbase = pfdata->sbase;
3482bf73ac6SHong Zhang   if (rank == 0) { /* proc[0] will create Electric Power Grid */
349c4762a1bSJed Brown     numEdges[0]    = pfdata->nbranch;
350c4762a1bSJed Brown     numVertices[0] = pfdata->nbus;
351c4762a1bSJed Brown 
3529566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(2*numEdges[0],&edgelist_power));
3539566063dSJacob Faibussowitsch     PetscCall(GetListofEdges_Power(pfdata,edgelist_power));
354c4762a1bSJed Brown   }
355c4762a1bSJed Brown   /* Broadcast power Sbase to all processors */
3569566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Bcast(&Sbase,1,MPIU_SCALAR,0,PETSC_COMM_WORLD));
357c4762a1bSJed Brown   appctx_power->Sbase     = Sbase;
358c4762a1bSJed Brown   appctx_power->jac_error = PETSC_FALSE;
359c4762a1bSJed Brown   /* If external option activated. Introduce error in jacobian */
3609566063dSJacob Faibussowitsch   PetscCall(PetscOptionsHasName(NULL,NULL, "-jac_error", &appctx_power->jac_error));
361c4762a1bSJed Brown 
3622bf73ac6SHong Zhang   /* All processes READ THE DATA FOR THE SECOND SUBNETWORK: Water */
3632bf73ac6SHong Zhang   /* Used for shared vertex, because currently the coupling info must be available in all processes!!! */
3649566063dSJacob Faibussowitsch   PetscCall(PetscNew(&waterdata));
3659566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetString(NULL,NULL,"-waterdata",waterdata_file,PETSC_MAX_PATH_LEN-1,NULL));
3669566063dSJacob Faibussowitsch   PetscCall(WaterReadData(waterdata,waterdata_file));
3672bf73ac6SHong Zhang   if (size == 1 || (size > 1 && rank == 1)) {
3689566063dSJacob Faibussowitsch     PetscCall(PetscCalloc1(2*waterdata->nedge,&edgelist_water));
3699566063dSJacob Faibussowitsch     PetscCall(GetListofEdges_Water(waterdata,edgelist_water));
370c4762a1bSJed Brown     numEdges[1]    = waterdata->nedge;
371c4762a1bSJed Brown     numVertices[1] = waterdata->nvertex;
372c4762a1bSJed Brown   }
3732bf73ac6SHong Zhang   PetscLogStagePop();
374c4762a1bSJed Brown 
3752bf73ac6SHong Zhang   /* (2) Create a network consist of two subnetworks */
3762bf73ac6SHong Zhang   /*-------------------------------------------------*/
3779566063dSJacob Faibussowitsch   PetscCall(PetscLogStageRegister("Net Setup",&stage[1]));
3789566063dSJacob Faibussowitsch   PetscCall(PetscLogStagePush(stage[1]));
379c4762a1bSJed Brown 
3809566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(NULL,NULL,"-viewDM",&viewDM,NULL));
3819566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(NULL,NULL,"-test",&test,NULL));
3829566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(NULL,NULL,"-distribute",&distribute,NULL));
383c4762a1bSJed Brown 
384c4762a1bSJed Brown   /* Create an empty network object */
3859566063dSJacob Faibussowitsch   PetscCall(DMNetworkCreate(PETSC_COMM_WORLD,&networkdm));
386c4762a1bSJed Brown 
387c4762a1bSJed Brown   /* Register the components in the network */
3889566063dSJacob Faibussowitsch   PetscCall(DMNetworkRegisterComponent(networkdm,"branchstruct",sizeof(struct _p_EDGE_Power),&appctx_power->compkey_branch));
3899566063dSJacob Faibussowitsch   PetscCall(DMNetworkRegisterComponent(networkdm,"busstruct",sizeof(struct _p_VERTEX_Power),&appctx_power->compkey_bus));
3909566063dSJacob Faibussowitsch   PetscCall(DMNetworkRegisterComponent(networkdm,"genstruct",sizeof(struct _p_GEN),&appctx_power->compkey_gen));
3919566063dSJacob Faibussowitsch   PetscCall(DMNetworkRegisterComponent(networkdm,"loadstruct",sizeof(struct _p_LOAD),&appctx_power->compkey_load));
392c4762a1bSJed Brown 
3939566063dSJacob Faibussowitsch   PetscCall(DMNetworkRegisterComponent(networkdm,"edge_water",sizeof(struct _p_EDGE_Water),&appctx_water->compkey_edge));
3949566063dSJacob Faibussowitsch   PetscCall(DMNetworkRegisterComponent(networkdm,"vertex_water",sizeof(struct _p_VERTEX_Water),&appctx_water->compkey_vtx));
3952bf73ac6SHong Zhang #if 0
3969566063dSJacob Faibussowitsch   PetscCall(PetscPrintf(PETSC_COMM_WORLD,"power->compkey_branch %d\n",appctx_power->compkey_branch));
3979566063dSJacob Faibussowitsch   PetscCall(PetscPrintf(PETSC_COMM_WORLD,"power->compkey_bus    %d\n",appctx_power->compkey_bus));
3989566063dSJacob Faibussowitsch   PetscCall(PetscPrintf(PETSC_COMM_WORLD,"power->compkey_gen    %d\n",appctx_power->compkey_gen));
3999566063dSJacob Faibussowitsch   PetscCall(PetscPrintf(PETSC_COMM_WORLD,"power->compkey_load   %d\n",appctx_power->compkey_load));
4009566063dSJacob Faibussowitsch   PetscCall(PetscPrintf(PETSC_COMM_WORLD,"water->compkey_edge   %d\n",appctx_water->compkey_edge));
4019566063dSJacob Faibussowitsch   PetscCall(PetscPrintf(PETSC_COMM_WORLD,"water->compkey_vtx    %d\n",appctx_water->compkey_vtx));
4022bf73ac6SHong Zhang #endif
40363a3b9bcSJacob 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]));
4049566063dSJacob Faibussowitsch   PetscCall(PetscSynchronizedFlush(PETSC_COMM_WORLD,PETSC_STDOUT));
405c4762a1bSJed Brown 
4069566063dSJacob Faibussowitsch   PetscCall(DMNetworkSetNumSubNetworks(networkdm,PETSC_DECIDE,Nsubnet));
4079566063dSJacob Faibussowitsch   PetscCall(DMNetworkAddSubnetwork(networkdm,"power",numEdges[0],edgelist_power,&power_netnum));
4089566063dSJacob Faibussowitsch   PetscCall(DMNetworkAddSubnetwork(networkdm,"water",numEdges[1],edgelist_water,&water_netnum));
409c4762a1bSJed Brown 
4102bf73ac6SHong Zhang   /* vertex subnet[0].4 shares with vertex subnet[1].0 */
4112bf73ac6SHong Zhang   power_svtx = 4; water_svtx = 0;
4129566063dSJacob Faibussowitsch   PetscCall(DMNetworkAddSharedVertices(networkdm,power_netnum,water_netnum,1,&power_svtx,&water_svtx));
413c4762a1bSJed Brown 
414c4762a1bSJed Brown   /* Set up the network layout */
4159566063dSJacob Faibussowitsch   PetscCall(DMNetworkLayoutSetUp(networkdm));
416c4762a1bSJed Brown 
417c4762a1bSJed Brown   /* ADD VARIABLES AND COMPONENTS FOR THE POWER SUBNETWORK */
4182bf73ac6SHong Zhang   /*-------------------------------------------------------*/
419c4762a1bSJed Brown   genj = 0; loadj = 0;
4209566063dSJacob Faibussowitsch   PetscCall(DMNetworkGetSubnetwork(networkdm,power_netnum,&nv,&ne,&vtx,&edges));
4212bf73ac6SHong Zhang 
422c4762a1bSJed Brown   for (i = 0; i < ne; i++) {
4239566063dSJacob Faibussowitsch     PetscCall(DMNetworkAddComponent(networkdm,edges[i],appctx_power->compkey_branch,&pfdata->branch[i],0));
424c4762a1bSJed Brown   }
425c4762a1bSJed Brown 
426c4762a1bSJed Brown   for (i = 0; i < nv; i++) {
4279566063dSJacob Faibussowitsch     PetscCall(DMNetworkIsSharedVertex(networkdm,vtx[i],&flg));
4282bf73ac6SHong Zhang     if (flg) continue;
4292bf73ac6SHong Zhang 
4309566063dSJacob Faibussowitsch     PetscCall(DMNetworkAddComponent(networkdm,vtx[i],appctx_power->compkey_bus,&pfdata->bus[i],2));
431c4762a1bSJed Brown     if (pfdata->bus[i].ngen) {
432c4762a1bSJed Brown       for (j = 0; j < pfdata->bus[i].ngen; j++) {
4339566063dSJacob Faibussowitsch         PetscCall(DMNetworkAddComponent(networkdm,vtx[i],appctx_power->compkey_gen,&pfdata->gen[genj++],0));
434c4762a1bSJed Brown       }
435c4762a1bSJed Brown     }
436c4762a1bSJed Brown     if (pfdata->bus[i].nload) {
437c4762a1bSJed Brown       for (j=0; j < pfdata->bus[i].nload; j++) {
4389566063dSJacob Faibussowitsch         PetscCall(DMNetworkAddComponent(networkdm,vtx[i],appctx_power->compkey_load,&pfdata->load[loadj++],0));
439c4762a1bSJed Brown       }
440c4762a1bSJed Brown     }
441c4762a1bSJed Brown   }
442c4762a1bSJed Brown 
443c4762a1bSJed Brown   /* ADD VARIABLES AND COMPONENTS FOR THE WATER SUBNETWORK */
4442bf73ac6SHong Zhang   /*-------------------------------------------------------*/
4459566063dSJacob Faibussowitsch   PetscCall(DMNetworkGetSubnetwork(networkdm,water_netnum,&nv,&ne,&vtx,&edges));
446c4762a1bSJed Brown   for (i = 0; i < ne; i++) {
4479566063dSJacob Faibussowitsch     PetscCall(DMNetworkAddComponent(networkdm,edges[i],appctx_water->compkey_edge,&waterdata->edge[i],0));
448c4762a1bSJed Brown   }
449c4762a1bSJed Brown 
450c4762a1bSJed Brown   for (i = 0; i < nv; i++) {
4519566063dSJacob Faibussowitsch     PetscCall(DMNetworkIsSharedVertex(networkdm,vtx[i],&flg));
4522bf73ac6SHong Zhang     if (flg) continue;
4532bf73ac6SHong Zhang 
4549566063dSJacob Faibussowitsch     PetscCall(DMNetworkAddComponent(networkdm,vtx[i],appctx_water->compkey_vtx,&waterdata->vertex[i],1));
455c4762a1bSJed Brown   }
4562bf73ac6SHong Zhang 
457eac198afSGetnet   /* 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 */
4582bf73ac6SHong Zhang   /*----------------------------------------------------------------------------------------------------------------------------*/
4599566063dSJacob Faibussowitsch   PetscCall(DMNetworkGetSharedVertices(networkdm,&nv,&vtx));
4602bf73ac6SHong Zhang   for (i = 0; i < nv; i++) {
4612bf73ac6SHong Zhang     /* power */
4629566063dSJacob Faibussowitsch     PetscCall(DMNetworkAddComponent(networkdm,vtx[i],appctx_power->compkey_bus,&pfdata->bus[4],2));
4632bf73ac6SHong Zhang     /* bus[4] is a load, add its component */
4649566063dSJacob Faibussowitsch     PetscCall(DMNetworkAddComponent(networkdm,vtx[i],appctx_power->compkey_load,&pfdata->load[0],0));
4652bf73ac6SHong Zhang 
4662bf73ac6SHong Zhang     /* water */
4679566063dSJacob Faibussowitsch     PetscCall(DMNetworkAddComponent(networkdm,vtx[i],appctx_water->compkey_vtx,&waterdata->vertex[0],1));
468c4762a1bSJed Brown   }
469c4762a1bSJed Brown 
470c4762a1bSJed Brown   /* Set up DM for use */
4719566063dSJacob Faibussowitsch   PetscCall(DMSetUp(networkdm));
472c4762a1bSJed Brown   if (viewDM) {
4739566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_WORLD,"\nAfter DMSetUp, DMView:\n"));
4749566063dSJacob Faibussowitsch     PetscCall(DMView(networkdm,PETSC_VIEWER_STDOUT_WORLD));
475c4762a1bSJed Brown   }
476c4762a1bSJed Brown 
477c4762a1bSJed Brown   /* Free user objects */
4789566063dSJacob Faibussowitsch   PetscCall(PetscFree(edgelist_power));
4799566063dSJacob Faibussowitsch   PetscCall(PetscFree(pfdata->bus));
4809566063dSJacob Faibussowitsch   PetscCall(PetscFree(pfdata->gen));
4819566063dSJacob Faibussowitsch   PetscCall(PetscFree(pfdata->branch));
4829566063dSJacob Faibussowitsch   PetscCall(PetscFree(pfdata->load));
4839566063dSJacob Faibussowitsch   PetscCall(PetscFree(pfdata));
4842bf73ac6SHong Zhang 
4859566063dSJacob Faibussowitsch   PetscCall(PetscFree(edgelist_water));
4869566063dSJacob Faibussowitsch   PetscCall(PetscFree(waterdata->vertex));
4879566063dSJacob Faibussowitsch   PetscCall(PetscFree(waterdata->edge));
4889566063dSJacob Faibussowitsch   PetscCall(PetscFree(waterdata));
489c4762a1bSJed Brown 
490d5c9c0c4SHong Zhang   /* Re-distribute networkdm to multiple processes for better job balance */
4912bf73ac6SHong Zhang   if (size >1 && distribute) {
4929566063dSJacob Faibussowitsch     PetscCall(DMNetworkDistribute(&networkdm,0));
493c4762a1bSJed Brown     if (viewDM) {
4949566063dSJacob Faibussowitsch       PetscCall(PetscPrintf(PETSC_COMM_WORLD,"\nAfter DMNetworkDistribute, DMView:\n"));
4959566063dSJacob Faibussowitsch       PetscCall(DMView(networkdm,PETSC_VIEWER_STDOUT_WORLD));
496c4762a1bSJed Brown     }
497d5c9c0c4SHong Zhang   }
498c4762a1bSJed Brown 
4992bf73ac6SHong Zhang   /* Test DMNetworkGetSubnetwork() and DMNetworkGetSubnetworkSharedVertices() */
500c4762a1bSJed Brown   if (test) {
5012bf73ac6SHong Zhang     PetscInt  v,gidx;
5029566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Barrier(PETSC_COMM_WORLD));
5032bf73ac6SHong Zhang     for (i=0; i<Nsubnet; i++) {
5049566063dSJacob Faibussowitsch       PetscCall(DMNetworkGetSubnetwork(networkdm,i,&nv,&ne,&vtx,&edges));
50563a3b9bcSJacob Faibussowitsch       PetscCall(PetscPrintf(PETSC_COMM_SELF,"[%d] After distribute, subnet[%" PetscInt_FMT "] ne %" PetscInt_FMT ", nv %" PetscInt_FMT "\n",rank,i,ne,nv));
5069566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Barrier(PETSC_COMM_WORLD));
507c4762a1bSJed Brown 
5082bf73ac6SHong Zhang       for (v=0; v<nv; v++) {
5099566063dSJacob Faibussowitsch         PetscCall(DMNetworkIsGhostVertex(networkdm,vtx[v],&ghost));
5109566063dSJacob Faibussowitsch         PetscCall(DMNetworkGetGlobalVertexIndex(networkdm,vtx[v],&gidx));
51163a3b9bcSJacob Faibussowitsch         PetscCall(PetscPrintf(PETSC_COMM_SELF,"[%d] subnet[%" PetscInt_FMT "] v %" PetscInt_FMT " %" PetscInt_FMT "; ghost %d\n",rank,i,vtx[v],gidx,ghost));
512c4762a1bSJed Brown       }
5139566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Barrier(PETSC_COMM_WORLD));
514c4762a1bSJed Brown     }
5159566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Barrier(PETSC_COMM_WORLD));
5162bf73ac6SHong Zhang 
5179566063dSJacob Faibussowitsch     PetscCall(DMNetworkGetSharedVertices(networkdm,&nv,&vtx));
51863a3b9bcSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_SELF,"[%d] After distribute, num of shared vertices nsv = %" PetscInt_FMT "\n",rank,nv));
5192bf73ac6SHong Zhang     for (v=0; v<nv; v++) {
5209566063dSJacob Faibussowitsch       PetscCall(DMNetworkGetGlobalVertexIndex(networkdm,vtx[v],&gidx));
52163a3b9bcSJacob Faibussowitsch       PetscCall(PetscPrintf(PETSC_COMM_SELF,"[%d] sv %" PetscInt_FMT ", gidx=%" PetscInt_FMT "\n",rank,vtx[v],gidx));
5222bf73ac6SHong Zhang     }
5239566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Barrier(PETSC_COMM_WORLD));
524c4762a1bSJed Brown   }
525c4762a1bSJed Brown 
5262bf73ac6SHong Zhang   /* Create solution vector X */
5279566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector(networkdm,&X));
5289566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(X,&F));
5299566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(networkdm,&user.localXold));
5302bf73ac6SHong Zhang   PetscLogStagePop();
531c4762a1bSJed Brown 
532c4762a1bSJed Brown   /* (3) Setup Solvers */
533c4762a1bSJed Brown   /*-------------------*/
5349566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(NULL,NULL,"-viewJ",&viewJ,NULL));
5359566063dSJacob Faibussowitsch   PetscCall(PetscOptionsGetBool(NULL,NULL,"-viewX",&viewX,NULL));
536c4762a1bSJed Brown 
5379566063dSJacob Faibussowitsch   PetscCall(PetscLogStageRegister("SNES Setup",&stage[2]));
5389566063dSJacob Faibussowitsch   PetscCall(PetscLogStagePush(stage[2]));
539c4762a1bSJed Brown 
5409566063dSJacob Faibussowitsch   PetscCall(SetInitialGuess(networkdm,X,&user));
541c4762a1bSJed Brown 
542c4762a1bSJed Brown   /* Create coupled snes */
543c4762a1bSJed Brown   /*-------------------- */
5449566063dSJacob Faibussowitsch   PetscCall(PetscPrintf(PETSC_COMM_WORLD,"SNES_coupled setup ......\n"));
5452bf73ac6SHong Zhang   user.subsnes_id = Nsubnet;
5469566063dSJacob Faibussowitsch   PetscCall(SNESCreate(PETSC_COMM_WORLD,&snes));
5479566063dSJacob Faibussowitsch   PetscCall(SNESSetDM(snes,networkdm));
5489566063dSJacob Faibussowitsch   PetscCall(SNESSetOptionsPrefix(snes,"coupled_"));
5499566063dSJacob Faibussowitsch   PetscCall(SNESSetFunction(snes,F,FormFunction,&user));
5509566063dSJacob Faibussowitsch   PetscCall(SNESMonitorSet(snes,UserMonitor,&user,NULL));
5519566063dSJacob Faibussowitsch   PetscCall(SNESSetFromOptions(snes));
552c4762a1bSJed Brown 
553c4762a1bSJed Brown   if (viewJ) {
554c4762a1bSJed Brown     /* View Jac structure */
5559566063dSJacob Faibussowitsch     PetscCall(SNESGetJacobian(snes,&Jac,NULL,NULL,NULL));
5569566063dSJacob Faibussowitsch     PetscCall(MatView(Jac,PETSC_VIEWER_DRAW_WORLD));
557c4762a1bSJed Brown   }
558c4762a1bSJed Brown 
559c4762a1bSJed Brown   if (viewX) {
5609566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_WORLD,"Solution:\n"));
5619566063dSJacob Faibussowitsch     PetscCall(VecView(X,PETSC_VIEWER_STDOUT_WORLD));
562c4762a1bSJed Brown   }
563c4762a1bSJed Brown 
564c4762a1bSJed Brown   if (viewJ) {
565c4762a1bSJed Brown     /* View assembled Jac */
5669566063dSJacob Faibussowitsch     PetscCall(MatView(Jac,PETSC_VIEWER_DRAW_WORLD));
567c4762a1bSJed Brown   }
568c4762a1bSJed Brown 
569c4762a1bSJed Brown   /* Create snes_power */
570c4762a1bSJed Brown   /*-------------------*/
5719566063dSJacob Faibussowitsch   PetscCall(PetscPrintf(PETSC_COMM_WORLD,"SNES_power setup ......\n"));
572c4762a1bSJed Brown 
573c4762a1bSJed Brown   user.subsnes_id = 0;
5749566063dSJacob Faibussowitsch   PetscCall(SNESCreate(PETSC_COMM_WORLD,&snes_power));
5759566063dSJacob Faibussowitsch   PetscCall(SNESSetDM(snes_power,networkdm));
5769566063dSJacob Faibussowitsch   PetscCall(SNESSetOptionsPrefix(snes_power,"power_"));
5779566063dSJacob Faibussowitsch   PetscCall(SNESSetFunction(snes_power,F,FormFunction,&user));
5789566063dSJacob Faibussowitsch   PetscCall(SNESMonitorSet(snes_power,UserMonitor,&user,NULL));
579c4762a1bSJed Brown 
580c4762a1bSJed Brown   /* Use user-provide Jacobian */
5819566063dSJacob Faibussowitsch   PetscCall(DMCreateMatrix(networkdm,&Jac));
5829566063dSJacob Faibussowitsch   PetscCall(SNESSetJacobian(snes_power,Jac,Jac,FormJacobian_subPower,&user));
5839566063dSJacob Faibussowitsch   PetscCall(SNESSetFromOptions(snes_power));
584c4762a1bSJed Brown 
585c4762a1bSJed Brown   if (viewX) {
5869566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_WORLD,"Power Solution:\n"));
5879566063dSJacob Faibussowitsch     PetscCall(VecView(X,PETSC_VIEWER_STDOUT_WORLD));
588c4762a1bSJed Brown   }
589c4762a1bSJed Brown   if (viewJ) {
5909566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_WORLD,"Power Jac:\n"));
5919566063dSJacob Faibussowitsch     PetscCall(SNESGetJacobian(snes_power,&Jac,NULL,NULL,NULL));
5929566063dSJacob Faibussowitsch     PetscCall(MatView(Jac,PETSC_VIEWER_DRAW_WORLD));
5939566063dSJacob Faibussowitsch     /* PetscCall(MatView(Jac,PETSC_VIEWER_STDOUT_WORLD)); */
594c4762a1bSJed Brown   }
595c4762a1bSJed Brown 
596c4762a1bSJed Brown   /* Create snes_water */
597c4762a1bSJed Brown   /*-------------------*/
5989566063dSJacob Faibussowitsch   PetscCall(PetscPrintf(PETSC_COMM_WORLD,"SNES_water setup......\n"));
599c4762a1bSJed Brown 
600c4762a1bSJed Brown   user.subsnes_id = 1;
6019566063dSJacob Faibussowitsch   PetscCall(SNESCreate(PETSC_COMM_WORLD,&snes_water));
6029566063dSJacob Faibussowitsch   PetscCall(SNESSetDM(snes_water,networkdm));
6039566063dSJacob Faibussowitsch   PetscCall(SNESSetOptionsPrefix(snes_water,"water_"));
6049566063dSJacob Faibussowitsch   PetscCall(SNESSetFunction(snes_water,F,FormFunction,&user));
6059566063dSJacob Faibussowitsch   PetscCall(SNESMonitorSet(snes_water,UserMonitor,&user,NULL));
6069566063dSJacob Faibussowitsch   PetscCall(SNESSetFromOptions(snes_water));
607c4762a1bSJed Brown 
608c4762a1bSJed Brown   if (viewX) {
6099566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_WORLD,"Water Solution:\n"));
6109566063dSJacob Faibussowitsch     PetscCall(VecView(X,PETSC_VIEWER_STDOUT_WORLD));
611c4762a1bSJed Brown   }
6129566063dSJacob Faibussowitsch   PetscCall(PetscLogStagePop());
613c4762a1bSJed Brown 
614c4762a1bSJed Brown   /* (4) Solve */
615c4762a1bSJed Brown   /*-----------*/
6169566063dSJacob Faibussowitsch   PetscCall(PetscLogStageRegister("SNES Solve",&stage[3]));
6179566063dSJacob Faibussowitsch   PetscCall(PetscLogStagePush(stage[3]));
618c4762a1bSJed Brown   user.it = 0;
619c4762a1bSJed Brown   reason  = SNES_DIVERGED_DTOL;
620c4762a1bSJed Brown   while (user.it < it_max && (PetscInt)reason<0) {
621c4762a1bSJed Brown #if 0
622c4762a1bSJed Brown     user.subsnes_id = 0;
6239566063dSJacob Faibussowitsch     PetscCall(SNESSolve(snes_power,NULL,X));
624c4762a1bSJed Brown 
625c4762a1bSJed Brown     user.subsnes_id = 1;
6269566063dSJacob Faibussowitsch     PetscCall(SNESSolve(snes_water,NULL,X));
627c4762a1bSJed Brown #endif
6282bf73ac6SHong Zhang     user.subsnes_id = Nsubnet;
6299566063dSJacob Faibussowitsch     PetscCall(SNESSolve(snes,NULL,X));
630c4762a1bSJed Brown 
6319566063dSJacob Faibussowitsch     PetscCall(SNESGetConvergedReason(snes,&reason));
632c4762a1bSJed Brown     user.it++;
633c4762a1bSJed Brown   }
63463a3b9bcSJacob Faibussowitsch   PetscCall(PetscPrintf(PETSC_COMM_WORLD,"Coupled_SNES converged in %" PetscInt_FMT " iterations\n",user.it));
635c4762a1bSJed Brown   if (viewX) {
6369566063dSJacob Faibussowitsch     PetscCall(PetscPrintf(PETSC_COMM_WORLD,"Final Solution:\n"));
6379566063dSJacob Faibussowitsch     PetscCall(VecView(X,PETSC_VIEWER_STDOUT_WORLD));
638c4762a1bSJed Brown   }
6399566063dSJacob Faibussowitsch   PetscCall(PetscLogStagePop());
640c4762a1bSJed Brown 
641c4762a1bSJed Brown   /* Free objects */
642c4762a1bSJed Brown   /* -------------*/
6439566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&X));
6449566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&F));
6459566063dSJacob Faibussowitsch   PetscCall(DMRestoreLocalVector(networkdm,&user.localXold));
646c4762a1bSJed Brown 
6479566063dSJacob Faibussowitsch   PetscCall(SNESDestroy(&snes));
6489566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&Jac));
6499566063dSJacob Faibussowitsch   PetscCall(SNESDestroy(&snes_power));
6509566063dSJacob Faibussowitsch   PetscCall(SNESDestroy(&snes_water));
651c4762a1bSJed Brown 
6529566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&networkdm));
6539566063dSJacob Faibussowitsch   PetscCall(PetscFinalize());
654b122ec5aSJacob Faibussowitsch   return 0;
655c4762a1bSJed Brown }
656c4762a1bSJed Brown 
657c4762a1bSJed Brown /*TEST
658c4762a1bSJed Brown 
659c4762a1bSJed Brown    build:
660dfd57a17SPierre Jolivet      requires: !complex double defined(PETSC_HAVE_ATTRIBUTEALIGNED)
661c4762a1bSJed Brown      depends: power/PFReadData.c power/pffunctions.c water/waterreaddata.c water/waterfunctions.c
662c4762a1bSJed Brown 
663c4762a1bSJed Brown    test:
6642bf73ac6SHong Zhang       args: -coupled_snes_converged_reason -options_left no -viewDM
665c4762a1bSJed Brown       localrunfiles: ex1options power/case9.m water/sample1.inp
666c4762a1bSJed Brown       output_file: output/ex1.out
667c4762a1bSJed Brown 
668c4762a1bSJed Brown    test:
669c4762a1bSJed Brown       suffix: 2
670c4762a1bSJed Brown       nsize: 3
6712bf73ac6SHong Zhang       args: -coupled_snes_converged_reason -options_left no -petscpartitioner_type parmetis
672c4762a1bSJed Brown       localrunfiles: ex1options power/case9.m water/sample1.inp
673d5c9c0c4SHong Zhang       output_file: output/ex1_2.out
6742bf73ac6SHong Zhang       requires: parmetis
6752bf73ac6SHong Zhang 
6762bf73ac6SHong Zhang #   test:
6772bf73ac6SHong Zhang #      suffix: 3
6782bf73ac6SHong Zhang #      nsize: 3
6792bf73ac6SHong Zhang #      args: -coupled_snes_converged_reason -options_left no -distribute false
6802bf73ac6SHong Zhang #      localrunfiles: ex1options power/case9.m water/sample1.inp
6812bf73ac6SHong Zhang #      output_file: output/ex1_2.out
682d5c9c0c4SHong Zhang 
683d5c9c0c4SHong Zhang    test:
6842bf73ac6SHong Zhang       suffix: 4
6852bf73ac6SHong Zhang       nsize: 4
6862bf73ac6SHong Zhang       args: -coupled_snes_converged_reason -options_left no -petscpartitioner_type simple -viewDM
687d5c9c0c4SHong Zhang       localrunfiles: ex1options power/case9.m water/sample1.inp
6882bf73ac6SHong Zhang       output_file: output/ex1_4.out
689c4762a1bSJed Brown 
690c4762a1bSJed Brown TEST*/
691