Actual source code: ex1.c
petsc-3.8.4 2018-03-24
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,int **pedgelist)
60: {
61: PetscErrorCode ierr;
62: PetscInt nnode, nbranch, i;
63: Branch *branch;
64: Node *node;
65: int *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,compoffset,row[2],col[6];
150: PetscBool ghost;
151: const PetscInt *cone;
152: PetscScalar *barr,val[6];
153: DMNetworkComponentGenericDataType *arr;
156: MatZeroEntries(A);
158: VecSet(b,0.0);
159: VecGetArray(b,&barr);
161: /*
162: The component data array stores the information which we had in the
163: node and branch data structures. We access the correct element through
164: a variable offset that the DMNetwork provides.
165: */
166: DMNetworkGetComponentDataArray(dmnetwork,&arr);
168: /*
169: We define the current i as an "edge characteristic" and the voltage v as a "vertex characteristic".
170: We iterate the list of edges and vertices, query the associated voltages and currents
171: and use them to write the Kirchoff equations:
173: Branch equations: i/r + v_to - v_from = v_source (battery)
174: Node equations: sum(i_to) - sum(i_from) = i_source
175: */
176: DMNetworkGetEdgeRange(dmnetwork,&eStart,&eEnd);
177: for (e = 0; e < eEnd; e++) {
178: DMNetworkGetComponentKeyOffset(dmnetwork,e,0,NULL,&compoffset);
179: DMNetworkGetVariableOffset(dmnetwork,e,&lofst);
181: DMNetworkGetConnectedVertices(dmnetwork,e,&cone);
182: DMNetworkGetVariableOffset(dmnetwork,cone[0],&lofst_fr);
183: DMNetworkGetVariableOffset(dmnetwork,cone[1],&lofst_to);
185: branch = (Branch*)(arr + compoffset);
187: /* set rhs b for Branch equation */
188: barr[lofst] = branch->bat;
190: /* set Branch equation */
191: row[0] = lofst;
192: col[0] = lofst; val[0] = 1./branch->r;
193: col[1] = lofst_to; val[1] = 1;
194: col[2] = lofst_fr; val[2] = -1;
195: MatSetValuesLocal(A,1,row,3,col,val,ADD_VALUES);
197: /* set Node equation */
198: DMNetworkGetComponentKeyOffset(dmnetwork,cone[0],0,NULL,&compoffset);
199: node = (Node*)(arr + compoffset);
201: /* from node */
202: if (!node->gr) { /* not a boundary node */
203: row[0] = lofst_fr;
204: col[0] = lofst; val[0] = -1;
205: MatSetValuesLocal(A,1,row,1,col,val,ADD_VALUES);
206: }
208: /* to node */
209: DMNetworkGetComponentKeyOffset(dmnetwork,cone[1],0,NULL,&compoffset);
210: node = (Node*)(arr + compoffset);
212: if (!node->gr) { /* not a boundary node */
213: row[0] = lofst_to;
214: col[0] = lofst; val[0] = 1;
215: MatSetValuesLocal(A,1,row,1,col,val,ADD_VALUES);
216: }
217: }
219: /* set rhs b for Node equation */
220: DMNetworkGetVertexRange(dmnetwork,&vStart,&vEnd);
221: for (v = vStart; v < vEnd; v++) {
222: DMNetworkIsGhostVertex(dmnetwork,v,&ghost);
223: if (!ghost) {
224: DMNetworkGetComponentKeyOffset(dmnetwork,v,0,NULL,&compoffset);
225: DMNetworkGetVariableOffset(dmnetwork,v,&lofst);
226: node = (Node*)(arr + compoffset);
228: if (node->gr) { /* a boundary node */
229: row[0] = lofst;
230: col[0] = lofst; val[0] = 1;
231: MatSetValuesLocal(A,1,row,1,col,val,ADD_VALUES);
232: } else { /* not a boundary node */
233: barr[lofst] += node->inj;
234: }
235: }
236: }
238: VecRestoreArray(b,&barr);
240: MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY);
241: MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY);
242: return(0);
243: }
245: int main(int argc,char ** argv)
246: {
247: PetscErrorCode ierr;
248: PetscInt i, nnode = 0, nbranch = 0, eStart, eEnd, vStart, vEnd;
249: PetscMPIInt size, rank;
250: DM dmnetwork;
251: Vec x, b;
252: Mat A;
253: KSP ksp;
254: int *edgelist = NULL;
255: PetscInt componentkey[2];
256: Node *node;
257: Branch *branch;
259: PetscInitialize(&argc,&argv,(char*)0,help);if (ierr) return ierr;
260: MPI_Comm_rank(PETSC_COMM_WORLD,&rank);
261: MPI_Comm_size(PETSC_COMM_WORLD,&size);
263: /* "Read" data only for processor 0 */
264: if (!rank) {
265: read_data(&nnode, &nbranch, &node, &branch, &edgelist);
266: }
268: DMNetworkCreate(PETSC_COMM_WORLD,&dmnetwork);
269: DMNetworkRegisterComponent(dmnetwork,"nstr",sizeof(Node),&componentkey[0]);
270: DMNetworkRegisterComponent(dmnetwork,"bsrt",sizeof(Branch),&componentkey[1]);
272: /* Set local number of nodes/edges */
273: DMNetworkSetSizes(dmnetwork,nnode,nbranch,PETSC_DETERMINE,PETSC_DETERMINE);
274: /* Add edge connectivity */
275: DMNetworkSetEdgeList(dmnetwork,edgelist);
276: /* Set up the network layout */
277: DMNetworkLayoutSetUp(dmnetwork);
279: /* Add network components: physical parameters of nodes and branches*/
280: if (!rank) {
281: DMNetworkGetEdgeRange(dmnetwork,&eStart,&eEnd);
282: for (i = eStart; i < eEnd; i++) {
283: DMNetworkAddComponent(dmnetwork,i,componentkey[1],&branch[i-eStart]);
284: /* Add number of variables */
285: DMNetworkAddNumVariables(dmnetwork,i,1);
286: }
288: DMNetworkGetVertexRange(dmnetwork,&vStart,&vEnd);
289: for (i = vStart; i < vEnd; i++) {
290: DMNetworkAddComponent(dmnetwork,i,componentkey[0],&node[i-vStart]);
291: /* Add number of variables */
292: DMNetworkAddNumVariables(dmnetwork,i,1);
293: }
294: }
296: /* Network partitioning and distribution of data */
297: DMSetUp(dmnetwork);
298: DMNetworkDistribute(&dmnetwork,0);
300: /* We do not use these data structures anymore since they have been copied to dmnetwork */
301: if (!rank) {
302: PetscFree(edgelist);
303: PetscFree2(node,branch);
304: }
306: /* Create vectors and matrix */
307: DMCreateGlobalVector(dmnetwork,&x);
308: VecDuplicate(x,&b);
309: DMCreateMatrix(dmnetwork,&A);
311: /* Assembly system of equations */
312: FormOperator(dmnetwork,A,b);
314: /* Solve linear system: A x = b */
315: KSPCreate(PETSC_COMM_WORLD, &ksp);
316: KSPSetOperators(ksp, A, A);
317: KSPSetFromOptions(ksp);
318: KSPSolve(ksp, b, x);
319: VecView(x, PETSC_VIEWER_STDOUT_WORLD);
321: /* Free work space */
322: VecDestroy(&x);
323: VecDestroy(&b);
324: MatDestroy(&A);
325: KSPDestroy(&ksp);
326: DMDestroy(&dmnetwork);
327: PetscFinalize();
328: return ierr;
329: }