Date: 2025-03-28T21:11:09+00:00

Actual source code: power.c

      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";

      9: #include "power.h"
     10: #include <petscdmnetwork.h>

     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;

     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));

     27:   PetscCall(DMGlobalToLocalBegin(networkdm, X, INSERT_VALUES, localX));
     28:   PetscCall(DMGlobalToLocalEnd(networkdm, X, INSERT_VALUES, localX));

     30:   PetscCall(DMNetworkGetSubnetwork(networkdm, 0, &nv, &ne, &vtx, &edges));
     31:   PetscCall(FormFunction_Power(networkdm, localX, localF, nv, ne, vtx, edges, User));

     33:   PetscCall(DMRestoreLocalVector(networkdm, &localX));

     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: }

     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;

     48:   PetscFunctionBegin;
     49:   PetscCall(DMNetworkGetVertexRange(networkdm, &vStart, &vEnd));

     51:   PetscCall(DMGetLocalVector(networkdm, &localX));

     53:   PetscCall(VecSet(X, 0.0));
     54:   PetscCall(DMGlobalToLocalBegin(networkdm, X, INSERT_VALUES, localX));
     55:   PetscCall(DMGlobalToLocalEnd(networkdm, X, INSERT_VALUES, localX));

     57:   PetscCall(DMNetworkGetSubnetwork(networkdm, 0, &nv, &ne, &vtx, &edges));
     58:   PetscCall(SetInitialGuess_Power(networkdm, localX, nv, ne, vtx, edges, user_power));

     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: }

     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;

     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;

     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));

     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;

    110:       numEdges = pfdata->nbranch;
    111:       PetscCall(PetscMalloc1(2 * numEdges, &edges));
    112:       PetscCall(GetListofEdges_Power(pfdata, edges));
    113:     }

    115:     /* If external option activated. Introduce error in jacobian */
    116:     PetscCall(PetscOptionsHasName(NULL, NULL, "-jac_error", &User.jac_error));

    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));

    126:     /* Set up the network layout */
    127:     PetscCall(DMNetworkLayoutSetUp(networkdm));

    129:     if (!crank) PetscCall(PetscFree(edges));

    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:     }

    149:     /* Set up DM for use */
    150:     PetscCall(DMSetUp(networkdm));

    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:     }

    160:     /* Distribute networkdm to multiple processes */
    161:     PetscCall(DMNetworkDistribute(&networkdm, 0));

    163:     PetscCall(PetscLogStagePop());
    164:     PetscCall(DMNetworkGetEdgeRange(networkdm, &eStart, &eEnd));
    165:     PetscCall(DMNetworkGetVertexRange(networkdm, &vStart, &vEnd));

    167: #if 0
    168:     EDGE_Power     edge;
    169:     PetscInt       key,kk,numComponents;
    170:     VERTEX_Power   bus;
    171:     GEN            gen;
    172:     LOAD           load;

    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:     }

    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));

    200:     PetscCall(DMCreateGlobalVector(networkdm, &X));
    201:     PetscCall(VecDuplicate(X, &F));

    203:     PetscCall(DMCreateMatrix(networkdm, &J));
    204:     PetscCall(MatSetOption(J, MAT_NEW_NONZERO_ALLOCATION_ERR, PETSC_FALSE));

    206:     PetscCall(SetInitialValues(networkdm, X, &User));

    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));

    215:     PetscCall(SNESSolve(snes, NULL, X));
    216:     /* PetscCall(VecView(X,PETSC_VIEWER_STDOUT_WORLD)); */

    218:     PetscCall(VecDestroy(&X));
    219:     PetscCall(VecDestroy(&F));
    220:     PetscCall(MatDestroy(&J));

    222:     PetscCall(SNESDestroy(&snes));
    223:     PetscCall(DMDestroy(&networkdm));
    224:   }
    225:   PetscCall(PetscFinalize());
    226:   return 0;
    227: }

    229: /*TEST

    231:    build:
    232:      depends: PFReadData.c pffunctions.c
    233:      requires: !complex double defined(PETSC_HAVE_ATTRIBUTEALIGNED)

    235:    test:
    236:      args: -snes_rtol 1.e-3
    237:      localrunfiles: poweroptions case9.m
    238:      output_file: output/power_1.out

    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

    247: TEST*/