xref: /petsc/src/snes/tutorials/network/power/power.c (revision 6dd63270497ad23dcf16ae500a87ff2b2a0b7474)
1 static char help[] = "This example demonstrates the use of DMNetwork interface for solving a nonlinear electric power grid problem.\n\
2                       The available solver options are in the poweroptions file and the data files are in the datafiles directory.\n\
3                       See 'Evaluation of overlapping restricted additive schwarz preconditioning for parallel solution \n\
4                           of very large power flow problems' https://dl.acm.org/citation.cfm?id=2536784).\n\
5                       The data file format used is from the MatPower package (http://www.pserc.cornell.edu//matpower/).\n\
6                       Run this program: mpiexec -n <n> ./pf\n\
7                       mpiexec -n <n> ./pfc \n";
8 
9 #include "power.h"
10 #include <petscdmnetwork.h>
11 
12 PetscErrorCode FormFunction(SNES snes, Vec X, Vec F, void *appctx)
13 {
14   DM              networkdm;
15   UserCtx_Power  *User = (UserCtx_Power *)appctx;
16   Vec             localX, localF;
17   PetscInt        nv, ne;
18   const PetscInt *vtx, *edges;
19 
20   PetscFunctionBegin;
21   PetscCall(SNESGetDM(snes, &networkdm));
22   PetscCall(DMGetLocalVector(networkdm, &localX));
23   PetscCall(DMGetLocalVector(networkdm, &localF));
24   PetscCall(VecSet(F, 0.0));
25   PetscCall(VecSet(localF, 0.0));
26 
27   PetscCall(DMGlobalToLocalBegin(networkdm, X, INSERT_VALUES, localX));
28   PetscCall(DMGlobalToLocalEnd(networkdm, X, INSERT_VALUES, localX));
29 
30   PetscCall(DMNetworkGetSubnetwork(networkdm, 0, &nv, &ne, &vtx, &edges));
31   PetscCall(FormFunction_Power(networkdm, localX, localF, nv, ne, vtx, edges, User));
32 
33   PetscCall(DMRestoreLocalVector(networkdm, &localX));
34 
35   PetscCall(DMLocalToGlobalBegin(networkdm, localF, ADD_VALUES, F));
36   PetscCall(DMLocalToGlobalEnd(networkdm, localF, ADD_VALUES, F));
37   PetscCall(DMRestoreLocalVector(networkdm, &localF));
38   PetscFunctionReturn(PETSC_SUCCESS);
39 }
40 
41 PetscErrorCode SetInitialValues(DM networkdm, Vec X, void *appctx)
42 {
43   PetscInt        vStart, vEnd, nv, ne;
44   const PetscInt *vtx, *edges;
45   Vec             localX;
46   UserCtx_Power  *user_power = (UserCtx_Power *)appctx;
47 
48   PetscFunctionBegin;
49   PetscCall(DMNetworkGetVertexRange(networkdm, &vStart, &vEnd));
50 
51   PetscCall(DMGetLocalVector(networkdm, &localX));
52 
53   PetscCall(VecSet(X, 0.0));
54   PetscCall(DMGlobalToLocalBegin(networkdm, X, INSERT_VALUES, localX));
55   PetscCall(DMGlobalToLocalEnd(networkdm, X, INSERT_VALUES, localX));
56 
57   PetscCall(DMNetworkGetSubnetwork(networkdm, 0, &nv, &ne, &vtx, &edges));
58   PetscCall(SetInitialGuess_Power(networkdm, localX, nv, ne, vtx, edges, user_power));
59 
60   PetscCall(DMLocalToGlobalBegin(networkdm, localX, ADD_VALUES, X));
61   PetscCall(DMLocalToGlobalEnd(networkdm, localX, ADD_VALUES, X));
62   PetscCall(DMRestoreLocalVector(networkdm, &localX));
63   PetscFunctionReturn(PETSC_SUCCESS);
64 }
65 
66 int main(int argc, char **argv)
67 {
68   char          pfdata_file[PETSC_MAX_PATH_LEN] = "case9.m";
69   PFDATA       *pfdata;
70   PetscInt      numEdges = 0;
71   PetscInt     *edges    = NULL;
72   PetscInt      i;
73   DM            networkdm;
74   UserCtx_Power User;
75   PetscLogStage stage1, stage2;
76   PetscMPIInt   rank;
77   PetscInt      eStart, eEnd, vStart, vEnd, j;
78   PetscInt      genj, loadj;
79   Vec           X, F;
80   Mat           J;
81   SNES          snes;
82 
83   PetscFunctionBeginUser;
84   PetscCall(PetscInitialize(&argc, &argv, "poweroptions", help));
85   PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD, &rank));
86   {
87     /* introduce the const crank so the clang static analyzer realizes that if it enters any of the if (crank) then it must have entered the first */
88     /* this is an experiment to see how the analyzer reacts */
89     const PetscMPIInt crank = rank;
90 
91     /* Create an empty network object */
92     PetscCall(DMNetworkCreate(PETSC_COMM_WORLD, &networkdm));
93     /* Register the components in the network */
94     PetscCall(DMNetworkRegisterComponent(networkdm, "branchstruct", sizeof(struct _p_EDGE_Power), &User.compkey_branch));
95     PetscCall(DMNetworkRegisterComponent(networkdm, "busstruct", sizeof(struct _p_VERTEX_Power), &User.compkey_bus));
96     PetscCall(DMNetworkRegisterComponent(networkdm, "genstruct", sizeof(struct _p_GEN), &User.compkey_gen));
97     PetscCall(DMNetworkRegisterComponent(networkdm, "loadstruct", sizeof(struct _p_LOAD), &User.compkey_load));
98 
99     PetscCall(PetscLogStageRegister("Read Data", &stage1));
100     PetscCall(PetscLogStagePush(stage1));
101     /* READ THE DATA */
102     if (!crank) {
103       /*    READ DATA */
104       /* Only rank 0 reads the data */
105       PetscCall(PetscOptionsGetString(NULL, NULL, "-pfdata", pfdata_file, sizeof(pfdata_file), NULL));
106       PetscCall(PetscNew(&pfdata));
107       PetscCall(PFReadMatPowerData(pfdata, pfdata_file));
108       User.Sbase = pfdata->sbase;
109 
110       numEdges = pfdata->nbranch;
111       PetscCall(PetscMalloc1(2 * numEdges, &edges));
112       PetscCall(GetListofEdges_Power(pfdata, edges));
113     }
114 
115     /* If external option activated. Introduce error in jacobian */
116     PetscCall(PetscOptionsHasName(NULL, NULL, "-jac_error", &User.jac_error));
117 
118     PetscCall(PetscLogStagePop());
119     PetscCallMPI(MPI_Barrier(PETSC_COMM_WORLD));
120     PetscCall(PetscLogStageRegister("Create network", &stage2));
121     PetscCall(PetscLogStagePush(stage2));
122     /* Set number of nodes/edges */
123     PetscCall(DMNetworkSetNumSubNetworks(networkdm, PETSC_DECIDE, 1));
124     PetscCall(DMNetworkAddSubnetwork(networkdm, "", numEdges, edges, NULL));
125 
126     /* Set up the network layout */
127     PetscCall(DMNetworkLayoutSetUp(networkdm));
128 
129     if (!crank) PetscCall(PetscFree(edges));
130 
131     /* Add network components only process 0 has any data to add */
132     if (!crank) {
133       genj  = 0;
134       loadj = 0;
135       PetscCall(DMNetworkGetEdgeRange(networkdm, &eStart, &eEnd));
136       for (i = eStart; i < eEnd; i++) PetscCall(DMNetworkAddComponent(networkdm, i, User.compkey_branch, &pfdata->branch[i - eStart], 0));
137       PetscCall(DMNetworkGetVertexRange(networkdm, &vStart, &vEnd));
138       for (i = vStart; i < vEnd; i++) {
139         PetscCall(DMNetworkAddComponent(networkdm, i, User.compkey_bus, &pfdata->bus[i - vStart], 2));
140         if (pfdata->bus[i - vStart].ngen) {
141           for (j = 0; j < pfdata->bus[i - vStart].ngen; j++) PetscCall(DMNetworkAddComponent(networkdm, i, User.compkey_gen, &pfdata->gen[genj++], 0));
142         }
143         if (pfdata->bus[i - vStart].nload) {
144           for (j = 0; j < pfdata->bus[i - vStart].nload; j++) PetscCall(DMNetworkAddComponent(networkdm, i, User.compkey_load, &pfdata->load[loadj++], 0));
145         }
146       }
147     }
148 
149     /* Set up DM for use */
150     PetscCall(DMSetUp(networkdm));
151 
152     if (!crank) {
153       PetscCall(PetscFree(pfdata->bus));
154       PetscCall(PetscFree(pfdata->gen));
155       PetscCall(PetscFree(pfdata->branch));
156       PetscCall(PetscFree(pfdata->load));
157       PetscCall(PetscFree(pfdata));
158     }
159 
160     /* Distribute networkdm to multiple processes */
161     PetscCall(DMNetworkDistribute(&networkdm, 0));
162 
163     PetscCall(PetscLogStagePop());
164     PetscCall(DMNetworkGetEdgeRange(networkdm, &eStart, &eEnd));
165     PetscCall(DMNetworkGetVertexRange(networkdm, &vStart, &vEnd));
166 
167 #if 0
168     EDGE_Power     edge;
169     PetscInt       key,kk,numComponents;
170     VERTEX_Power   bus;
171     GEN            gen;
172     LOAD           load;
173 
174     for (i = eStart; i < eEnd; i++) {
175       PetscCall(DMNetworkGetComponent(networkdm,i,0,&key,(void**)&edge));
176       PetscCall(DMNetworkGetNumComponents(networkdm,i,&numComponents));
177       PetscCall(PetscPrintf(PETSC_COMM_SELF,"Rank %d ncomps = %d Line %d ---- %d\n",crank,numComponents,edge->internal_i,edge->internal_j));
178     }
179 
180     for (i = vStart; i < vEnd; i++) {
181       PetscCall(DMNetworkGetNumComponents(networkdm,i,&numComponents));
182       for (kk=0; kk < numComponents; kk++) {
183         PetscCall(DMNetworkGetComponent(networkdm,i,kk,&key,&component));
184         if (key == 1) {
185           bus = (VERTEX_Power)component;
186           PetscCall(PetscPrintf(PETSC_COMM_SELF,"Rank %d ncomps = %d Bus %d\n",crank,numComponents,bus->internal_i));
187         } else if (key == 2) {
188           gen = (GEN)component;
189           PetscCall(PetscPrintf(PETSC_COMM_SELF,"Rank %d Gen pg = %f qg = %f\n",crank,(double)gen->pg,(double)gen->qg));
190         } else if (key == 3) {
191           load = (LOAD)component;
192           PetscCall(PetscPrintf(PETSC_COMM_SELF,"Rank %d Load pl = %f ql = %f\n",crank,(double)load->pl,(double)load->ql));
193         }
194       }
195     }
196 #endif
197     /* Broadcast Sbase to all processors */
198     PetscCallMPI(MPI_Bcast(&User.Sbase, 1, MPIU_SCALAR, 0, PETSC_COMM_WORLD));
199 
200     PetscCall(DMCreateGlobalVector(networkdm, &X));
201     PetscCall(VecDuplicate(X, &F));
202 
203     PetscCall(DMCreateMatrix(networkdm, &J));
204     PetscCall(MatSetOption(J, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_FALSE));
205 
206     PetscCall(SetInitialValues(networkdm, X, &User));
207 
208     /* HOOK UP SOLVER */
209     PetscCall(SNESCreate(PETSC_COMM_WORLD, &snes));
210     PetscCall(SNESSetDM(snes, networkdm));
211     PetscCall(SNESSetFunction(snes, F, FormFunction, &User));
212     PetscCall(SNESSetJacobian(snes, J, J, FormJacobian_Power, &User));
213     PetscCall(SNESSetFromOptions(snes));
214 
215     PetscCall(SNESSolve(snes, NULL, X));
216     /* PetscCall(VecView(X,PETSC_VIEWER_STDOUT_WORLD)); */
217 
218     PetscCall(VecDestroy(&X));
219     PetscCall(VecDestroy(&F));
220     PetscCall(MatDestroy(&J));
221 
222     PetscCall(SNESDestroy(&snes));
223     PetscCall(DMDestroy(&networkdm));
224   }
225   PetscCall(PetscFinalize());
226   return 0;
227 }
228 
229 /*TEST
230 
231    build:
232      depends: PFReadData.c pffunctions.c
233      requires: !complex double defined(PETSC_HAVE_ATTRIBUTEALIGNED)
234 
235    test:
236      args: -snes_rtol 1.e-3
237      localrunfiles: poweroptions case9.m
238      output_file: output/power_1.out
239 
240    test:
241      suffix: 2
242      args: -snes_rtol 1.e-3 -petscpartitioner_type simple
243      nsize: 4
244      localrunfiles: poweroptions case9.m
245      output_file: output/power_1.out
246 
247 TEST*/
248