Date: 2022-03-04T17:39:18+00:00

Actual source code: ex1.c

      1: static char help[] = "This example demonstrates the use of DMNetwork interface for solving a simple electric circuit. \n\
      2:                       The example can be found in p.150 of 'Strang, Gilbert. Computational Science and Engineering. Wellesley, MA'.\n\n";

      4: /* T
      5:   Concepts: DMNetwork
      6:   Concepts: KSP
      7: */

      9: #include <petscdmnetwork.h>
     10: #include <petscksp.h>

     12: /* The topology looks like:

     14:             (0)
     15:             /|\
     16:            / | \
     17:           /  |  \
     18:          R   R   V
     19:         /    |b3  \
     20:     b0 /    (3)    \ b1
     21:       /    /   \    R
     22:      /   R       R   \
     23:     /  /           \  \
     24:    / / b4        b5  \ \
     25:   //                   \\
     26: (1)--------- R -------- (2)
     27:              b2

     29:   Nodes:          (0), ... (3)
     30:   Branches:       b0, ... b5
     31:   Resistances:    R
     32:   Voltage source: V

     34:   Additionally, there is a current source from (1) to (0).
     35: */

     37: /*
     38:   Structures containing physical data of circuit.
     39:   Note that no topology is defined
     40: */

     42: typedef struct {
     43:   PetscInt    id;  /* node id */
     44:   PetscScalar inj; /* current injection (A) */
     45:   PetscBool   gr;  /* boundary node */
     46: } Node;

     48: typedef struct {
     49:   PetscInt    id;  /* branch id */
     50:   PetscScalar r;   /* resistance (ohms) */
     51:   PetscScalar bat; /* battery (V) */
     52: } Branch;

     54: /*
     55:   read_data: this routine fills data structures with problem data.
     56:   This can be substituted by an external parser.
     57: */

     59: PetscErrorCode read_data(PetscInt *pnnode,PetscInt *pnbranch,Node **pnode,Branch **pbranch,PetscInt **pedgelist)
     60: {
     61:   PetscErrorCode    ierr;
     62:   PetscInt          nnode, nbranch, i;
     63:   Branch            *branch;
     64:   Node              *node;
     65:   PetscInt          *edgelist;

     68:   nnode   = 4;
     69:   nbranch = 6;

     71:   PetscCalloc2(nnode,&node,nbranch,&branch);

     73:   for (i = 0; i < nnode; i++) {
     74:     node[i].id  = i;
     75:     node[i].inj = 0;
     76:     node[i].gr = PETSC_FALSE;
     77:   }

     79:   for (i = 0; i < nbranch; i++) {
     80:     branch[i].id  = i;
     81:     branch[i].r   = 1.0;
     82:     branch[i].bat = 0;
     83:   }

     85:   /*
     86:     Branch 1 contains a voltage source of 12.0 V
     87:     From node 0 to 1 there exists a current source of 4.0 A
     88:     Node 3 is grounded, hence the voltage is 0.
     89:   */
     90:   branch[1].bat = 12.0;
     91:   node[0].inj   = -4.0;
     92:   node[1].inj   =  4.0;
     93:   node[3].gr    =  PETSC_TRUE;

     95:   /*
     96:     edgelist is an array of len = 2*nbranch that defines the
     97:     topology of the network. For branch i we have:
     98:       edgelist[2*i]     = from node
     99:       edgelist[2*i + 1] = to node.
    100:   */
    101:   PetscCalloc1(2*nbranch, &edgelist);

    103:   for (i = 0; i < nbranch; i++) {
    104:     switch (i) {
    105:       case 0:
    106:         edgelist[2*i]     = 0;
    107:         edgelist[2*i + 1] = 1;
    108:         break;
    109:       case 1:
    110:         edgelist[2*i]     = 0;
    111:         edgelist[2*i + 1] = 2;
    112:         break;
    113:       case 2:
    114:         edgelist[2*i]     = 1;
    115:         edgelist[2*i + 1] = 2;
    116:         break;
    117:       case 3:
    118:         edgelist[2*i]     = 0;
    119:         edgelist[2*i + 1] = 3;
    120:         break;
    121:       case 4:
    122:         edgelist[2*i]     = 1;
    123:         edgelist[2*i + 1] = 3;
    124:         break;
    125:       case 5:
    126:         edgelist[2*i]     = 2;
    127:         edgelist[2*i + 1] = 3;
    128:         break;
    129:       default:
    130:         break;
    131:     }
    132:   }

    134:   /* assign pointers */
    135:   *pnnode    = nnode;
    136:   *pnbranch  = nbranch;
    137:   *pedgelist = edgelist;
    138:   *pbranch   = branch;
    139:   *pnode     = node;
    140:   return(0);
    141: }

    143: PetscErrorCode FormOperator(DM dmnetwork,Mat A,Vec b)
    144: {
    145:   PetscErrorCode    ierr;
    146:   Branch            *branch;
    147:   Node              *node;
    148:   PetscInt          e,v,vStart,vEnd,eStart, eEnd;
    149:   PetscInt          lofst,lofst_to,lofst_fr,row[2],col[6];
    150:   PetscBool         ghost;
    151:   const PetscInt    *cone;
    152:   PetscScalar       *barr,val[6];

    155:   MatZeroEntries(A);

    157:   VecSet(b,0.0);
    158:   VecGetArray(b,&barr);

    160:   /*
    161:     We define the current i as an "edge characteristic" and the voltage v as a "vertex characteristic".
    162:     We iterate the list of edges and vertices, query the associated voltages and currents
    163:     and use them to write the Kirchoff equations:

    165:     Branch equations: i/r + v_to - v_from     = v_source (battery)
    166:     Node equations:   sum(i_to) - sum(i_from) = i_source
    167:    */
    168:   DMNetworkGetEdgeRange(dmnetwork,&eStart,&eEnd);
    169:   for (e = 0; e < eEnd; e++) {
    170:     DMNetworkGetComponent(dmnetwork,e,0,NULL,(void**)&branch,NULL);
    171:     DMNetworkGetLocalVecOffset(dmnetwork,e,ALL_COMPONENTS,&lofst);

    173:     DMNetworkGetConnectedVertices(dmnetwork,e,&cone);
    174:     DMNetworkGetLocalVecOffset(dmnetwork,cone[0],ALL_COMPONENTS,&lofst_fr);
    175:     DMNetworkGetLocalVecOffset(dmnetwork,cone[1],ALL_COMPONENTS,&lofst_to);

    177:     /* set rhs b for Branch equation */
    178:     barr[lofst] = branch->bat;

    180:     /* set Branch equation */
    181:     row[0] = lofst;
    182:     col[0] = lofst;     val[0] =  1./branch->r;
    183:     col[1] = lofst_to;  val[1] =  1;
    184:     col[2] = lofst_fr;  val[2] = -1;
    185:     MatSetValuesLocal(A,1,row,3,col,val,ADD_VALUES);

    187:     /* set Node equation */
    188:     DMNetworkGetComponent(dmnetwork,cone[0],0,NULL,(void**)&node,NULL);

    190:     /* from node */
    191:     if (!node->gr) { /* not a boundary node */
    192:       row[0] = lofst_fr;
    193:       col[0] = lofst;   val[0] = -1;
    194:       MatSetValuesLocal(A,1,row,1,col,val,ADD_VALUES);
    195:     }

    197:     /* to node */
    198:     DMNetworkGetComponent(dmnetwork,cone[1],0,NULL,(void**)&node,NULL);

    200:     if (!node->gr) { /* not a boundary node */
    201:       row[0] = lofst_to;
    202:       col[0] = lofst;   val[0] = 1;
    203:       MatSetValuesLocal(A,1,row,1,col,val,ADD_VALUES);
    204:     }
    205:   }

    207:   /* set rhs b for Node equation */
    208:   DMNetworkGetVertexRange(dmnetwork,&vStart,&vEnd);
    209:   for (v = vStart; v < vEnd; v++) {
    210:     DMNetworkIsGhostVertex(dmnetwork,v,&ghost);
    211:     if (!ghost) {
    212:       DMNetworkGetComponent(dmnetwork,v,0,NULL,(void**)&node,NULL);
    213:       DMNetworkGetLocalVecOffset(dmnetwork,v,ALL_COMPONENTS,&lofst);

    215:       if (node->gr) { /* a boundary node */
    216:         row[0] = lofst;
    217:         col[0] = lofst;   val[0] = 1;
    218:         MatSetValuesLocal(A,1,row,1,col,val,ADD_VALUES);
    219:       } else {       /* not a boundary node */
    220:         barr[lofst] += node->inj;
    221:       }
    222:     }
    223:   }

    225:   VecRestoreArray(b,&barr);

    227:   MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY);
    228:   MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY);
    229:   return(0);
    230: }

    232: int main(int argc,char ** argv)
    233: {
    234:   PetscErrorCode    ierr;
    235:   PetscInt          i, nnode = 0, nbranch = 0, eStart, eEnd, vStart, vEnd;
    236:   PetscMPIInt       size, rank;
    237:   DM                dmnetwork;
    238:   Vec               x, b;
    239:   Mat               A;
    240:   KSP               ksp;
    241:   PetscInt          *edgelist = NULL;
    242:   PetscInt          componentkey[2];
    243:   Node              *node;
    244:   Branch            *branch;
    245:   PetscInt          nE[1];

    247:   PetscInitialize(&argc,&argv,(char*)0,help);if (ierr) return ierr;
    248:   MPI_Comm_rank(PETSC_COMM_WORLD,&rank);
    249:   MPI_Comm_size(PETSC_COMM_WORLD,&size);

    251:   /* "Read" data only for processor 0 */
    252:   if (rank == 0) {
    253:     read_data(&nnode, &nbranch, &node, &branch, &edgelist);
    254:   }

    256:   DMNetworkCreate(PETSC_COMM_WORLD,&dmnetwork);
    257:   DMNetworkRegisterComponent(dmnetwork,"nstr",sizeof(Node),&componentkey[0]);
    258:   DMNetworkRegisterComponent(dmnetwork,"bsrt",sizeof(Branch),&componentkey[1]);

    260:   /* Set local number of nodes/edges, add edge connectivity */
    261:   nE[0] = nbranch;
    262:   DMNetworkSetNumSubNetworks(dmnetwork,PETSC_DECIDE,1);
    263:   DMNetworkAddSubnetwork(dmnetwork,"",nE[0],edgelist,NULL);

    265:   /* Set up the network layout */
    266:   DMNetworkLayoutSetUp(dmnetwork);

    268:   /* Add network components (physical parameters of nodes and branches) and num of variables */
    269:   if (rank == 0) {
    270:     DMNetworkGetEdgeRange(dmnetwork,&eStart,&eEnd);
    271:     for (i = eStart; i < eEnd; i++) {
    272:       DMNetworkAddComponent(dmnetwork,i,componentkey[1],&branch[i-eStart],1);
    273:     }

    275:     DMNetworkGetVertexRange(dmnetwork,&vStart,&vEnd);
    276:     for (i = vStart; i < vEnd; i++) {
    277:       DMNetworkAddComponent(dmnetwork,i,componentkey[0],&node[i-vStart],1);
    278:     }
    279:   }

    281:   /* Network partitioning and distribution of data */
    282:   DMSetUp(dmnetwork);
    283:   DMNetworkDistribute(&dmnetwork,0);

    285:   /* We do not use these data structures anymore since they have been copied to dmnetwork */
    286:   if (rank == 0) {
    287:     PetscFree(edgelist);
    288:     PetscFree2(node,branch);
    289:   }

    291:   /* Create vectors and matrix */
    292:   DMCreateGlobalVector(dmnetwork,&x);
    293:   VecDuplicate(x,&b);
    294:   DMCreateMatrix(dmnetwork,&A);

    296:   /* Assembly system of equations */
    297:   FormOperator(dmnetwork,A,b);

    299:   /* Solve linear system: A x = b */
    300:   KSPCreate(PETSC_COMM_WORLD, &ksp);
    301:   KSPSetOperators(ksp, A, A);
    302:   KSPSetFromOptions(ksp);
    303:   KSPSolve(ksp, b, x);
    304:   VecView(x, PETSC_VIEWER_STDOUT_WORLD);

    306:   /* Free work space */
    307:   VecDestroy(&x);
    308:   VecDestroy(&b);
    309:   MatDestroy(&A);
    310:   KSPDestroy(&ksp);
    311:   DMDestroy(&dmnetwork);
    312:   PetscFinalize();
    313:   return ierr;
    314: }

    316: /*TEST

    318:    build:
    319:       requires: !complex double defined(PETSC_HAVE_ATTRIBUTEALIGNED)

    321:    test:
    322:       args: -ksp_monitor_short

    324:    test:
    325:       suffix: 2
    326:       nsize: 2
    327:       args: -petscpartitioner_type simple -ksp_converged_reason

    329: TEST*/