xref: /petsc/src/dm/impls/network/network.c (revision 6500d4ab0b72a0e67bc93fd604cf502bd6a384b1)
1 #include <petsc/private/dmnetworkimpl.h>  /*I  "petscdmnetwork.h"  I*/
2 #include <petscdmplex.h>
3 #include <petscsf.h>
4 
5 /*@
6   DMNetworkGetPlex - Gets the Plex DM associated with this network DM
7 
8   Not collective
9 
10   Input Parameters:
11 + netdm - the dm object
12 - plexmdm - the plex dm object
13 
14   Level: Advanced
15 
16 .seealso: DMNetworkCreate()
17 @*/
18 PetscErrorCode DMNetworkGetPlex(DM netdm, DM *plexdm)
19 {
20   DM_Network     *network = (DM_Network*) netdm->data;
21 
22   PetscFunctionBegin;
23   *plexdm = network->plex;
24   PetscFunctionReturn(0);
25 }
26 
27 /*@
28   DMNetworkSetSizes - Sets the number of subnetworks,local and global vertices and edges for each subnetwork.
29 
30   Collective on DM
31 
32   Input Parameters:
33 + dm - the dm object
34 . Nsubnet - number of subnetworks
35 . nV - number of local vertices for each subnetwork
36 . nE - number of local edges for each subnetwork
37 . NV - number of global vertices (or PETSC_DETERMINE) for each subnetwork
38 - NE - number of global edges (or PETSC_DETERMINE) for each subnetwork
39 
40    Notes
41    If one processor calls this with NV (NE) of PETSC_DECIDE then all processors must, otherwise the prgram will hang.
42 
43    You cannot change the sizes once they have been set
44 
45    Level: intermediate
46 
47 .seealso: DMNetworkCreate()
48 @*/
49 PetscErrorCode DMNetworkSetSizes(DM dm, PetscInt Nsubnet, PetscInt nV[], PetscInt nE[], PetscInt NV[], PetscInt NE[])
50 {
51   PetscErrorCode ierr;
52   DM_Network     *network = (DM_Network*) dm->data;
53   PetscInt       a[2],b[2],i;
54 
55   PetscFunctionBegin;
56   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
57   if (Nsubnet <= 0) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Number of subnetworks %D cannot be less than 1",Nsubnet);
58 
59   if(Nsubnet > 0) PetscValidLogicalCollectiveInt(dm,Nsubnet,2);
60   if(network->nsubnet != 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Network sizes alread set, cannot resize the network");
61 
62   network->nsubnet = Nsubnet;
63   ierr = PetscCalloc1(Nsubnet,&network->subnet);CHKERRQ(ierr);
64   for(i=0; i < network->nsubnet; i++) {
65     if (NV[i] > 0) PetscValidLogicalCollectiveInt(dm,NV[i],5);
66     if (NE[i] > 0) PetscValidLogicalCollectiveInt(dm,NE[i],6);
67     if (NV[i] > 0 && nV[i] > NV[i]) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Subnetwork %D: Local vertex size %D cannot be larger than global vertex size %D",i,nV[i],NV[i]);
68     if (NE[i] > 0 && nE[i] > NE[i]) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Subnetwork %D: Local edge size %D cannot be larger than global edge size %D",i,nE[i],NE[i]);
69     a[0] = nV[i]; a[1] = nE[i];
70     ierr = MPIU_Allreduce(a,b,2,MPIU_INT,MPI_SUM,PetscObjectComm((PetscObject)dm));CHKERRQ(ierr);
71     network->subnet[i].Nvtx = b[0]; network->subnet[i].Nedge = b[1];
72 
73     network->subnet[i].id = i;
74 
75     network->subnet[i].nvtx = nV[i];
76     network->subnet[i].vStart = network->nVertices;
77     network->subnet[i].vEnd   = network->subnet[i].vStart + network->subnet[i].Nvtx;
78     network->nVertices += network->subnet[i].nvtx;
79     network->NVertices += network->subnet[i].Nvtx;
80 
81     network->subnet[i].nedge = nE[i];
82     network->subnet[i].eStart = network->nEdges;
83     network->subnet[i].eEnd = network->subnet[i].eStart + network->subnet[i].Nedge;
84     network->nEdges += network->subnet[i].nedge;
85     network->NEdges += network->subnet[i].Nedge;
86   }
87   PetscFunctionReturn(0);
88 }
89 
90 /*@
91   DMNetworkSetEdgeList - Sets the list of local edges (vertex connectivity) for the network
92 
93   Logically collective on DM
94 
95   Input Parameters:
96 . edges - list of edges for each subnetwork
97 
98   Notes:
99   There is no copy involved in this operation, only the pointer is referenced. The edgelist should
100   not be destroyed before the call to DMNetworkLayoutSetUp
101 
102   Level: intermediate
103 
104 .seealso: DMNetworkCreate, DMNetworkSetSizes
105 @*/
106 PetscErrorCode DMNetworkSetEdgeList(DM dm, int *edgelist[])
107 {
108   DM_Network *network = (DM_Network*) dm->data;
109   PetscInt   i;
110 
111   PetscFunctionBegin;
112   for(i=0; i < network->nsubnet; i++) {
113     network->subnet[i].edgelist = edgelist[i];
114   }
115   PetscFunctionReturn(0);
116 }
117 
118 /*@
119   DMNetworkLayoutSetUp - Sets up the bare layout (graph) for the network
120 
121   Collective on DM
122 
123   Input Parameters
124 . DM - the dmnetwork object
125 
126   Notes:
127   This routine should be called after the network sizes and edgelists have been provided. It creates
128   the bare layout of the network and sets up the network to begin insertion of components.
129 
130   All the components should be registered before calling this routine.
131 
132   Level: intermediate
133 
134 .seealso: DMNetworkSetSizes, DMNetworkSetEdgeList
135 @*/
136 PetscErrorCode DMNetworkLayoutSetUp(DM dm)
137 {
138   PetscErrorCode ierr;
139   DM_Network     *network = (DM_Network*) dm->data;
140   PetscInt       dim = 1; /* One dimensional network */
141   PetscInt       numCorners=2;
142   PetscInt       spacedim=2;
143   double         *vertexcoords=NULL;
144   PetscInt       i,j;
145   PetscInt       ndata;
146   PetscInt       ctr=0;
147 
148   PetscFunctionBegin;
149   if (network->nVertices) {
150     ierr = PetscCalloc1(numCorners*network->nVertices,&vertexcoords);CHKERRQ(ierr);
151   }
152 
153   /* Create the edgelist for the network by concatenating edgelists of the subnetworks */
154   ierr = PetscCalloc1(2*network->nEdges,&network->edges);CHKERRQ(ierr);
155   for(i=0; i < network->nsubnet; i++) {
156     for(j = 0; j < network->subnet[i].nedge; j++) {
157       network->edges[2*ctr] = network->subnet[i].vStart + network->subnet[i].edgelist[2*j];
158       network->edges[2*ctr+1] = network->subnet[i].vStart + network->subnet[i].edgelist[2*j+1];
159       ctr++;
160     }
161   }
162 
163 #if 1
164   for(i=0; i < network->nEdges; i++) {
165     ierr = PetscPrintf(PETSC_COMM_SELF,"[%D %D]",network->edges[2*i],network->edges[2*i+1]);CHKERRQ(ierr);
166   }
167 #endif
168 
169   ierr = DMPlexCreateFromCellList(PetscObjectComm((PetscObject)dm),dim,network->nEdges,network->nVertices,numCorners,PETSC_FALSE,network->edges,spacedim,vertexcoords,&network->plex);CHKERRQ(ierr);
170   if (network->nVertices) {
171     ierr = PetscFree(vertexcoords);CHKERRQ(ierr);
172   }
173   ierr = PetscFree(network->edges);CHKERRQ(ierr);
174 
175   ierr = DMPlexGetChart(network->plex,&network->pStart,&network->pEnd);CHKERRQ(ierr);
176   ierr = DMPlexGetHeightStratum(network->plex,0,&network->eStart,&network->eEnd);CHKERRQ(ierr);
177   ierr = DMPlexGetHeightStratum(network->plex,1,&network->vStart,&network->vEnd);CHKERRQ(ierr);
178 
179   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm),&network->DataSection);CHKERRQ(ierr);
180   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm),&network->DofSection);CHKERRQ(ierr);
181   ierr = PetscSectionSetChart(network->DataSection,network->pStart,network->pEnd);CHKERRQ(ierr);
182   ierr = PetscSectionSetChart(network->DofSection,network->pStart,network->pEnd);CHKERRQ(ierr);
183 
184   /* Create vertices and edges array for the subnetworks */
185   for(j=0; j < network->nsubnet; j++) {
186     ierr = PetscCalloc1(network->subnet[j].nedge,&network->subnet[j].edges);CHKERRQ(ierr);
187     ierr = PetscCalloc1(network->subnet[j].nvtx,&network->subnet[j].vertices);CHKERRQ(ierr);
188     /* Temporarily setting nvtx and nedge to 0 so we can use them as counters in the below for loop.
189        These get updated when the vertices and edges are added. */
190     network->subnet[j].nvtx = network->subnet[j].nedge = 0;
191   }
192 
193   network->dataheadersize = sizeof(struct _p_DMNetworkComponentHeader)/sizeof(DMNetworkComponentGenericDataType);
194   ierr = PetscCalloc1(network->pEnd-network->pStart,&network->header);CHKERRQ(ierr);
195   for(i=network->eStart; i < network->eEnd; i++) {
196     network->header[i].index = i;   /* Global edge number */
197     for(j=0; j < network->nsubnet; j++) {
198       if((network->subnet[j].eStart <= i) && (i < network->subnet[j].eEnd)) {
199 	network->header[i].subnetid = j; /* Subnetwork id */
200 	network->subnet[j].edges[network->subnet[j].nedge++] = i;
201 	break;
202       }
203     }
204     network->header[i].ndata = 0;
205     ndata = network->header[i].ndata;
206     ierr = PetscSectionAddDof(network->DataSection,i,network->dataheadersize);CHKERRQ(ierr);
207     network->header[i].offset[ndata] = 0;
208   }
209 
210   for(i=network->vStart; i < network->vEnd; i++) {
211     network->header[i].index = i - network->vStart;
212     for(j=0; j < network->nsubnet; j++) {
213       if((network->subnet[j].vStart <= i-network->vStart) && (i-network->vStart < network->subnet[j].vEnd)) {
214 	network->header[i].subnetid = j;
215 	network->subnet[j].vertices[network->subnet[j].nvtx++] = i;
216 	break;
217       }
218     }
219     network->header[i].ndata = 0;
220     ndata = network->header[i].ndata;
221     ierr = PetscSectionAddDof(network->DataSection,i,network->dataheadersize);CHKERRQ(ierr);
222     network->header[i].offset[ndata] = 0;
223   }
224 
225   ierr = PetscMalloc1(network->pEnd-network->pStart,&network->cvalue);CHKERRQ(ierr);
226   PetscFunctionReturn(0);
227 }
228 
229 
230 PetscErrorCode DMNetworkLayoutSetUpCoupled(DM dm)
231 {
232   PetscErrorCode ierr;
233   DM_Network     *network = (DM_Network*) dm->data;
234   PetscInt       dim = 1; /* One dimensional network */
235   PetscInt       numCorners=2;
236   PetscInt       spacedim=2;
237   double         *vertexcoords=NULL;
238   PetscInt       i,j;
239   PetscInt       ndata;
240   PetscInt       ctr=0;
241 
242   PetscFunctionBegin;
243   printf("DMNetworkLayoutSetUpCoupled...\n");
244   if (network->nVertices) {
245     ierr = PetscCalloc1(numCorners*network->nVertices,&vertexcoords);CHKERRQ(ierr);
246   }
247 
248   /* Create the edgelist for the network by concatenating edgelists of the subnetworks */
249   ierr = PetscCalloc1(2*network->nEdges,&network->edges);CHKERRQ(ierr);
250   for (i=0; i < network->nsubnet-1; i++) {
251     for (j = 0; j < network->subnet[i].nedge; j++) {
252       network->edges[2*ctr] = network->subnet[i].vStart + network->subnet[i].edgelist[2*j];
253       network->edges[2*ctr+1] = network->subnet[i].vStart + network->subnet[i].edgelist[2*j+1];
254       ctr++;
255     }
256   }
257   i = network->nsubnet-1; /* coupling subnet */
258   PetscInt *edgelist_couple = network->subnet[i].edgelist,k,netid,vid;
259   k = 0;
260   for (j = 0; j < network->subnet[i].nedge; j++) {
261     netid = edgelist_couple[k]; vid = edgelist_couple[k+1];
262     network->edges[2*ctr] = network->subnet[netid].vStart + vid; k += 2;
263 
264     netid = edgelist_couple[k]; vid = edgelist_couple[k+1];
265     network->edges[2*ctr+1] = network->subnet[netid].vStart + vi; k+=2;
266     ctr++;
267   }
268 
269 #if 1
270   for(i=0; i < network->nEdges; i++) {
271     ierr = PetscPrintf(PETSC_COMM_SELF,"[%D %D]",network->edges[2*i],network->edges[2*i+1]);CHKERRQ(ierr);
272     printf("\n");
273   }
274 #endif
275 
276   ierr = DMPlexCreateFromCellList(PetscObjectComm((PetscObject)dm),dim,network->nEdges,network->nVertices,numCorners,PETSC_FALSE,network->edges,spacedim,vertexcoords,&network->plex);CHKERRQ(ierr);
277   if (network->nVertices) {
278     ierr = PetscFree(vertexcoords);CHKERRQ(ierr);
279   }
280   ierr = PetscFree(network->edges);CHKERRQ(ierr);
281 
282   ierr = DMPlexGetChart(network->plex,&network->pStart,&network->pEnd);CHKERRQ(ierr);
283   ierr = DMPlexGetHeightStratum(network->plex,0,&network->eStart,&network->eEnd);CHKERRQ(ierr);
284   ierr = DMPlexGetHeightStratum(network->plex,1,&network->vStart,&network->vEnd);CHKERRQ(ierr);
285 
286   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm),&network->DataSection);CHKERRQ(ierr);
287   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dm),&network->DofSection);CHKERRQ(ierr);
288   ierr = PetscSectionSetChart(network->DataSection,network->pStart,network->pEnd);CHKERRQ(ierr);
289   ierr = PetscSectionSetChart(network->DofSection,network->pStart,network->pEnd);CHKERRQ(ierr);
290 
291   /* Create vertices and edges array for the subnetworks */
292   for(j=0; j < network->nsubnet; j++) {
293     ierr = PetscCalloc1(network->subnet[j].nedge,&network->subnet[j].edges);CHKERRQ(ierr);
294     ierr = PetscCalloc1(network->subnet[j].nvtx,&network->subnet[j].vertices);CHKERRQ(ierr);
295     /* Temporarily setting nvtx and nedge to 0 so we can use them as counters in the below for loop.
296        These get updated when the vertices and edges are added. */
297     network->subnet[j].nvtx = network->subnet[j].nedge = 0;
298   }
299 
300   network->dataheadersize = sizeof(struct _p_DMNetworkComponentHeader)/sizeof(DMNetworkComponentGenericDataType);
301   ierr = PetscCalloc1(network->pEnd-network->pStart,&network->header);CHKERRQ(ierr);
302   for(i=network->eStart; i < network->eEnd; i++) {
303     network->header[i].index = i;   /* Global edge number */
304     for(j=0; j < network->nsubnet; j++) {
305       if((network->subnet[j].eStart <= i) && (i < network->subnet[j].eEnd)) {
306 	network->header[i].subnetid = j; /* Subnetwork id */
307 	network->subnet[j].edges[network->subnet[j].nedge++] = i;
308 	break;
309       }
310     }
311     network->header[i].ndata = 0;
312     ndata = network->header[i].ndata;
313     ierr = PetscSectionAddDof(network->DataSection,i,network->dataheadersize);CHKERRQ(ierr);
314     network->header[i].offset[ndata] = 0;
315   }
316 
317   for(i=network->vStart; i < network->vEnd; i++) {
318     network->header[i].index = i - network->vStart;
319     for(j=0; j < network->nsubnet; j++) {
320       if((network->subnet[j].vStart <= i-network->vStart) && (i-network->vStart < network->subnet[j].vEnd)) {
321 	network->header[i].subnetid = j;
322 	network->subnet[j].vertices[network->subnet[j].nvtx++] = i;
323 	break;
324       }
325     }
326     network->header[i].ndata = 0;
327     ndata = network->header[i].ndata;
328     ierr = PetscSectionAddDof(network->DataSection,i,network->dataheadersize);CHKERRQ(ierr);
329     network->header[i].offset[ndata] = 0;
330   }
331 
332   ierr = PetscMalloc1(network->pEnd-network->pStart,&network->cvalue);CHKERRQ(ierr);
333   PetscFunctionReturn(0);
334 }
335 
336 /*@C
337   DMNetworkGetSubnetworkInfo - Returns the info for the subnetwork
338 
339   Input Parameters
340 + dm   - the number object
341 - id   - the ID (integer) of the subnetwork
342 
343   Output Parameters
344 + nv    - number of vertices (local)
345 . ne    - number of edges (local)
346 . vtx   - local vertices for this subnetwork
347 . edge  - local edges for this subnetwork
348 
349   Notes:
350   Cannot call this routine before DMNetworkLayoutSetup()
351 
352 .seealso: DMNetworkLayoutSetUp, DMNetworkCreate
353 @*/
354 PetscErrorCode DMNetworkGetSubnetworkInfo(DM netdm,PetscInt id,PetscInt *nv, PetscInt *ne,const PetscInt **vtx, const PetscInt **edge)
355 {
356   DM_Network     *network = (DM_Network*) netdm->data;
357 
358   PetscFunctionBegin;
359   *nv = network->subnet[id].nvtx;
360   *ne = network->subnet[id].nedge;
361   *vtx = network->subnet[id].vertices;
362   *edge = network->subnet[id].edges;
363   PetscFunctionReturn(0);
364 }
365 
366 /*@C
367   DMNetworkRegisterComponent - Registers the network component
368 
369   Logically collective on DM
370 
371   Input Parameters
372 + dm   - the network object
373 . name - the component name
374 - size - the storage size in bytes for this component data
375 
376    Output Parameters
377 .   key - an integer key that defines the component
378 
379    Notes
380    This routine should be called by all processors before calling DMNetworkLayoutSetup().
381 
382    Level: intermediate
383 
384 .seealso: DMNetworkLayoutSetUp, DMNetworkCreate
385 @*/
386 PetscErrorCode DMNetworkRegisterComponent(DM dm,const char *name,PetscInt size,PetscInt *key)
387 {
388   PetscErrorCode        ierr;
389   DM_Network            *network = (DM_Network*) dm->data;
390   DMNetworkComponent    *component=&network->component[network->ncomponent];
391   PetscBool             flg=PETSC_FALSE;
392   PetscInt              i;
393 
394   PetscFunctionBegin;
395 
396   for (i=0; i < network->ncomponent; i++) {
397     ierr = PetscStrcmp(component->name,name,&flg);CHKERRQ(ierr);
398     if (flg) {
399       *key = i;
400       PetscFunctionReturn(0);
401     }
402   }
403   if(network->ncomponent == MAX_COMPONENTS) {
404     SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_OUTOFRANGE,"Number of components registered exceeds the max %D",MAX_COMPONENTS);
405   }
406 
407   ierr = PetscStrcpy(component->name,name);CHKERRQ(ierr);
408   component->size = size/sizeof(DMNetworkComponentGenericDataType);
409   *key = network->ncomponent;
410   network->ncomponent++;
411   PetscFunctionReturn(0);
412 }
413 
414 /*@
415   DMNetworkGetVertexRange - Get the bounds [start, end) for the vertices.
416 
417   Not Collective
418 
419   Input Parameters:
420 + dm - The DMNetwork object
421 
422   Output Paramters:
423 + vStart - The first vertex point
424 - vEnd   - One beyond the last vertex point
425 
426   Level: intermediate
427 
428 .seealso: DMNetworkGetEdgeRange
429 @*/
430 PetscErrorCode DMNetworkGetVertexRange(DM dm,PetscInt *vStart,PetscInt *vEnd)
431 {
432   DM_Network     *network = (DM_Network*)dm->data;
433 
434   PetscFunctionBegin;
435   if (vStart) *vStart = network->vStart;
436   if (vEnd) *vEnd = network->vEnd;
437   PetscFunctionReturn(0);
438 }
439 
440 /*@
441   DMNetworkGetEdgeRange - Get the bounds [start, end) for the edges.
442 
443   Not Collective
444 
445   Input Parameters:
446 + dm - The DMNetwork object
447 
448   Output Paramters:
449 + eStart - The first edge point
450 - eEnd   - One beyond the last edge point
451 
452   Level: intermediate
453 
454 .seealso: DMNetworkGetVertexRange
455 @*/
456 PetscErrorCode DMNetworkGetEdgeRange(DM dm,PetscInt *eStart,PetscInt *eEnd)
457 {
458   DM_Network     *network = (DM_Network*)dm->data;
459 
460   PetscFunctionBegin;
461   if (eStart) *eStart = network->eStart;
462   if (eEnd) *eEnd = network->eEnd;
463   PetscFunctionReturn(0);
464 }
465 
466 /*@
467   DMNetworkGetGlobalEdgeIndex - Get the user global numbering for the edge.
468 
469   Not Collective
470 
471   Input Parameters:
472 + dm - DMNetwork object
473 - p  - edge point
474 
475   Output Paramters:
476 . index - user global numbering for the edge
477 
478   Level: intermediate
479 
480 .seealso: DMNetworkGetGlobalVertexIndex
481 @*/
482 PetscErrorCode DMNetworkGetGlobalEdgeIndex(DM dm,PetscInt p,PetscInt *index)
483 {
484   PetscErrorCode    ierr;
485   DM_Network        *network = (DM_Network*)dm->data;
486   PetscInt          offsetp;
487   DMNetworkComponentHeader header;
488 
489   PetscFunctionBegin;
490   ierr = PetscSectionGetOffset(network->DataSection,p,&offsetp);CHKERRQ(ierr);
491   header = (DMNetworkComponentHeader)(network->componentdataarray+offsetp);
492   *index = header->index;
493   PetscFunctionReturn(0);
494 }
495 
496 /*@
497   DMNetworkGetGlobalVertexIndex - Get the user global numbering for the vertex.
498 
499   Not Collective
500 
501   Input Parameters:
502 + dm - DMNetwork object
503 - p  - vertex point
504 
505   Output Paramters:
506 . index - user global numbering for the vertex
507 
508   Level: intermediate
509 
510 .seealso: DMNetworkGetGlobalEdgeIndex
511 @*/
512 PetscErrorCode DMNetworkGetGlobalVertexIndex(DM dm,PetscInt p,PetscInt *index)
513 {
514   PetscErrorCode    ierr;
515   DM_Network        *network = (DM_Network*)dm->data;
516   PetscInt          offsetp;
517   DMNetworkComponentHeader header;
518 
519   PetscFunctionBegin;
520   ierr = PetscSectionGetOffset(network->DataSection,p,&offsetp);CHKERRQ(ierr);
521   header = (DMNetworkComponentHeader)(network->componentdataarray+offsetp);
522   *index = header->index;
523   PetscFunctionReturn(0);
524 }
525 
526 /*
527   DMNetworkGetComponentKeyOffset - Gets the type along with the offset for indexing the
528                                     component value from the component data array
529 
530   Not Collective
531 
532   Input Parameters:
533 + dm      - The DMNetwork object
534 . p       - vertex/edge point
535 - compnum - component number
536 
537   Output Parameters:
538 + compkey - the key obtained when registering the component
539 - offset  - offset into the component data array associated with the vertex/edge point
540 
541   Notes:
542   Typical usage:
543 
544   DMNetworkGetComponentDataArray(dm, &arr);
545   DMNetworkGetVertex/EdgeRange(dm,&Start,&End);
546   Loop over vertices or edges
547     DMNetworkGetNumComponents(dm,v,&numcomps);
548     Loop over numcomps
549       DMNetworkGetComponentKeyOffset(dm,v,compnum,&key,&offset);
550       compdata = (UserCompDataType)(arr+offset);
551 
552   Level: intermediate
553 
554 .seealso: DMNetworkGetNumComponents, DMNetworkGetComponentDataArray,
555 */
556 PetscErrorCode DMNetworkGetComponentKeyOffset(DM dm,PetscInt p, PetscInt compnum, PetscInt *compkey, PetscInt *offset)
557 {
558   PetscErrorCode           ierr;
559   PetscInt                 offsetp;
560   DMNetworkComponentHeader header;
561   DM_Network               *network = (DM_Network*)dm->data;
562 
563   PetscFunctionBegin;
564   ierr = PetscSectionGetOffset(network->DataSection,p,&offsetp);CHKERRQ(ierr);
565   header = (DMNetworkComponentHeader)(network->componentdataarray+offsetp);
566   if (compkey) *compkey = header->key[compnum];
567   if (offset) *offset  = offsetp+network->dataheadersize+header->offset[compnum];
568   PetscFunctionReturn(0);
569 }
570 
571 /*@
572   DMNetworkGetComponent - Returns the network component and its key
573 
574   Not Collective
575 
576   Input Parameters
577 + dm - DMNetwork object
578 . p  - edge or vertex point
579 - compnum - component number
580 
581   Output Parameters:
582 + compkey - the key set for this computing during registration
583 - component - the component data
584 
585   Notes:
586   Typical usage:
587 
588   DMNetworkGetVertex/EdgeRange(dm,&Start,&End);
589   Loop over vertices or edges
590     DMNetworkGetNumComponents(dm,v,&numcomps);
591     Loop over numcomps
592       DMNetworkGetComponent(dm,v,compnum,&key,&component);
593 
594   Level: intermediate
595 
596 .seealso: DMNetworkGetNumComponents, DMNetworkGetVariableOffset
597 @*/
598 PetscErrorCode DMNetworkGetComponent(DM dm, PetscInt p, PetscInt compnum, PetscInt *key, void **component)
599 {
600   PetscErrorCode ierr;
601   DM_Network     *network = (DM_Network*)dm->data;
602   PetscInt       offsetd;
603 
604   PetscFunctionBegin;
605 
606   ierr = DMNetworkGetComponentKeyOffset(dm,p,compnum,key,&offsetd);CHKERRQ(ierr);
607   *component = network->componentdataarray+offsetd;
608 
609   PetscFunctionReturn(0);
610 }
611 
612 /*@
613   DMNetworkAddComponent - Adds a network component at the given point (vertex/edge)
614 
615   Not Collective
616 
617   Input Parameters:
618 + dm           - The DMNetwork object
619 . p            - vertex/edge point
620 . componentkey - component key returned while registering the component
621 - compvalue    - pointer to the data structure for the component
622 
623   Level: intermediate
624 
625 .seealso: DMNetworkGetVertexRange, DMNetworkGetEdgeRange, DMNetworkRegisterComponent
626 @*/
627 PetscErrorCode DMNetworkAddComponent(DM dm, PetscInt p,PetscInt componentkey,void* compvalue)
628 {
629   DM_Network               *network = (DM_Network*)dm->data;
630   DMNetworkComponent       *component = &network->component[componentkey];
631   DMNetworkComponentHeader header = &network->header[p];
632   DMNetworkComponentValue  cvalue = &network->cvalue[p];
633   PetscErrorCode           ierr;
634 
635   PetscFunctionBegin;
636   if (header->ndata == MAX_DATA_AT_POINT) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_OUTOFRANGE,"Number of components at a point exceeds the max %D",MAX_DATA_AT_POINT);
637 
638   header->size[header->ndata] = component->size;
639   ierr = PetscSectionAddDof(network->DataSection,p,component->size);CHKERRQ(ierr);
640   header->key[header->ndata] = componentkey;
641   if (header->ndata != 0) header->offset[header->ndata] = header->offset[header->ndata-1] + header->size[header->ndata-1];
642 
643   cvalue->data[header->ndata] = (void*)compvalue;
644   header->ndata++;
645   PetscFunctionReturn(0);
646 }
647 
648 /*@
649   DMNetworkGetNumComponents - Get the number of components at a vertex/edge
650 
651   Not Collective
652 
653   Input Parameters:
654 + dm - The DMNetwork object
655 . p  - vertex/edge point
656 
657   Output Parameters:
658 . numcomponents - Number of components at the vertex/edge
659 
660   Level: intermediate
661 
662 .seealso: DMNetworkRegisterComponent, DMNetworkAddComponent
663 @*/
664 PetscErrorCode DMNetworkGetNumComponents(DM dm,PetscInt p,PetscInt *numcomponents)
665 {
666   PetscErrorCode ierr;
667   PetscInt       offset;
668   DM_Network     *network = (DM_Network*)dm->data;
669 
670   PetscFunctionBegin;
671   ierr = PetscSectionGetOffset(network->DataSection,p,&offset);CHKERRQ(ierr);
672   *numcomponents = ((DMNetworkComponentHeader)(network->componentdataarray+offset))->ndata;
673   PetscFunctionReturn(0);
674 }
675 
676 /*@
677   DMNetworkGetVariableOffset - Get the offset for accessing the variable associated with the given vertex/edge from the local vector.
678 
679   Not Collective
680 
681   Input Parameters:
682 + dm     - The DMNetwork object
683 - p      - the edge/vertex point
684 
685   Output Parameters:
686 . offset - the offset
687 
688   Level: intermediate
689 
690 .seealso: DMNetworkGetVariableGlobalOffset, DMGetLocalVector
691 @*/
692 PetscErrorCode DMNetworkGetVariableOffset(DM dm,PetscInt p,PetscInt *offset)
693 {
694   PetscErrorCode ierr;
695   DM_Network     *network = (DM_Network*)dm->data;
696 
697   PetscFunctionBegin;
698   ierr = PetscSectionGetOffset(network->plex->defaultSection,p,offset);CHKERRQ(ierr);
699   PetscFunctionReturn(0);
700 }
701 
702 /*@
703   DMNetworkGetVariableGlobalOffset - Get the global offset for the variable associated with the given vertex/edge from the global vector.
704 
705   Not Collective
706 
707   Input Parameters:
708 + dm      - The DMNetwork object
709 - p       - the edge/vertex point
710 
711   Output Parameters:
712 . offsetg - the offset
713 
714   Level: intermediate
715 
716 .seealso: DMNetworkGetVariableOffset, DMGetLocalVector
717 @*/
718 PetscErrorCode DMNetworkGetVariableGlobalOffset(DM dm,PetscInt p,PetscInt *offsetg)
719 {
720   PetscErrorCode ierr;
721   DM_Network     *network = (DM_Network*)dm->data;
722 
723   PetscFunctionBegin;
724   ierr = PetscSectionGetOffset(network->plex->defaultGlobalSection,p,offsetg);CHKERRQ(ierr);
725   if (*offsetg < 0) *offsetg = -(*offsetg + 1); /* Convert to actual global offset for ghost vertex */
726   PetscFunctionReturn(0);
727 }
728 
729 /*@
730   DMNetworkGetEdgeOffset - Get the offset for accessing the variable associated with the given edge from the local subvector.
731 
732   Not Collective
733 
734   Input Parameters:
735 + dm     - The DMNetwork object
736 - p      - the edge point
737 
738   Output Parameters:
739 . offset - the offset
740 
741   Level: intermediate
742 
743 .seealso: DMNetworkGetVariableGlobalOffset, DMGetLocalVector
744 @*/
745 PetscErrorCode DMNetworkGetEdgeOffset(DM dm,PetscInt p,PetscInt *offset)
746 {
747   PetscErrorCode ierr;
748   DM_Network     *network = (DM_Network*)dm->data;
749 
750   PetscFunctionBegin;
751 
752   ierr = PetscSectionGetOffset(network->edge.DofSection,p,offset);CHKERRQ(ierr);
753   PetscFunctionReturn(0);
754 }
755 
756 /*@
757   DMNetworkGetVertexOffset - Get the offset for accessing the variable associated with the given vertex from the local subvector.
758 
759   Not Collective
760 
761   Input Parameters:
762 + dm     - The DMNetwork object
763 - p      - the vertex point
764 
765   Output Parameters:
766 . offset - the offset
767 
768   Level: intermediate
769 
770 .seealso: DMNetworkGetVariableGlobalOffset, DMGetLocalVector
771 @*/
772 PetscErrorCode DMNetworkGetVertexOffset(DM dm,PetscInt p,PetscInt *offset)
773 {
774   PetscErrorCode ierr;
775   DM_Network     *network = (DM_Network*)dm->data;
776 
777   PetscFunctionBegin;
778 
779   p -= network->vStart;
780 
781   ierr = PetscSectionGetOffset(network->vertex.DofSection,p,offset);CHKERRQ(ierr);
782   PetscFunctionReturn(0);
783 }
784 /*@
785   DMNetworkAddNumVariables - Add number of variables associated with a given point.
786 
787   Not Collective
788 
789   Input Parameters:
790 + dm   - The DMNetworkObject
791 . p    - the vertex/edge point
792 - nvar - number of additional variables
793 
794   Level: intermediate
795 
796 .seealso: DMNetworkSetNumVariables
797 @*/
798 PetscErrorCode DMNetworkAddNumVariables(DM dm,PetscInt p,PetscInt nvar)
799 {
800   PetscErrorCode ierr;
801   DM_Network     *network = (DM_Network*)dm->data;
802 
803   PetscFunctionBegin;
804   ierr = PetscSectionAddDof(network->DofSection,p,nvar);CHKERRQ(ierr);
805   PetscFunctionReturn(0);
806 }
807 
808 /*@
809   DMNetworkGetNumVariables - Gets number of variables for a vertex/edge point.
810 
811   Not Collective
812 
813   Input Parameters:
814 + dm   - The DMNetworkObject
815 - p    - the vertex/edge point
816 
817   Output Parameters:
818 . nvar - number of variables
819 
820   Level: intermediate
821 
822 .seealso: DMNetworkAddNumVariables, DMNetworkSddNumVariables
823 @*/
824 PetscErrorCode DMNetworkGetNumVariables(DM dm,PetscInt p,PetscInt *nvar)
825 {
826   PetscErrorCode ierr;
827   DM_Network     *network = (DM_Network*)dm->data;
828 
829   PetscFunctionBegin;
830   ierr = PetscSectionGetDof(network->DofSection,p,nvar);CHKERRQ(ierr);
831   PetscFunctionReturn(0);
832 }
833 
834 /*@
835   DMNetworkSetNumVariables - Sets number of variables for a vertex/edge point.
836 
837   Not Collective
838 
839   Input Parameters:
840 + dm   - The DMNetworkObject
841 . p    - the vertex/edge point
842 - nvar - number of variables
843 
844   Level: intermediate
845 
846 .seealso: DMNetworkAddNumVariables
847 @*/
848 PetscErrorCode DMNetworkSetNumVariables(DM dm,PetscInt p,PetscInt nvar)
849 {
850   PetscErrorCode ierr;
851   DM_Network     *network = (DM_Network*)dm->data;
852 
853   PetscFunctionBegin;
854   ierr = PetscSectionSetDof(network->DofSection,p,nvar);CHKERRQ(ierr);
855   PetscFunctionReturn(0);
856 }
857 
858 /* Sets up the array that holds the data for all components and its associated section. This
859    function is called during DMSetUp() */
860 PetscErrorCode DMNetworkComponentSetUp(DM dm)
861 {
862   PetscErrorCode              ierr;
863   DM_Network     *network = (DM_Network*)dm->data;
864   PetscInt                    arr_size;
865   PetscInt                    p,offset,offsetp;
866   DMNetworkComponentHeader header;
867   DMNetworkComponentValue  cvalue;
868   DMNetworkComponentGenericDataType      *componentdataarray;
869   PetscInt ncomp, i;
870 
871   PetscFunctionBegin;
872   ierr = PetscSectionSetUp(network->DataSection);CHKERRQ(ierr);
873   ierr = PetscSectionGetStorageSize(network->DataSection,&arr_size);CHKERRQ(ierr);
874   ierr = PetscMalloc1(arr_size,&network->componentdataarray);CHKERRQ(ierr);
875   componentdataarray = network->componentdataarray;
876   for (p = network->pStart; p < network->pEnd; p++) {
877     ierr = PetscSectionGetOffset(network->DataSection,p,&offsetp);CHKERRQ(ierr);
878     /* Copy header */
879     header = &network->header[p];
880     ierr = PetscMemcpy(componentdataarray+offsetp,header,network->dataheadersize*sizeof(DMNetworkComponentGenericDataType));CHKERRQ(ierr);
881     /* Copy data */
882     cvalue = &network->cvalue[p];
883     ncomp = header->ndata;
884     for (i = 0; i < ncomp; i++) {
885       offset = offsetp + network->dataheadersize + header->offset[i];
886       ierr = PetscMemcpy(componentdataarray+offset,cvalue->data[i],header->size[i]*sizeof(DMNetworkComponentGenericDataType));CHKERRQ(ierr);
887     }
888   }
889   PetscFunctionReturn(0);
890 }
891 
892 /* Sets up the section for dofs. This routine is called during DMSetUp() */
893 PetscErrorCode DMNetworkVariablesSetUp(DM dm)
894 {
895   PetscErrorCode ierr;
896   DM_Network     *network = (DM_Network*)dm->data;
897 
898   PetscFunctionBegin;
899   ierr = PetscSectionSetUp(network->DofSection);CHKERRQ(ierr);
900   PetscFunctionReturn(0);
901 }
902 
903 /*@C
904   DMNetworkGetComponentDataArray - Returns the component data array
905 
906   Not Collective
907 
908   Input Parameters:
909 . dm - The DMNetwork Object
910 
911   Output Parameters:
912 . componentdataarray - array that holds data for all components
913 
914   Level: intermediate
915 
916 .seealso: DMNetworkGetComponentKeyOffset, DMNetworkGetNumComponents
917 @*/
918 PetscErrorCode DMNetworkGetComponentDataArray(DM dm,DMNetworkComponentGenericDataType **componentdataarray)
919 {
920   DM_Network     *network = (DM_Network*)dm->data;
921 
922   PetscFunctionBegin;
923   *componentdataarray = network->componentdataarray;
924   PetscFunctionReturn(0);
925 }
926 
927 /* Get a subsection from a range of points */
928 PetscErrorCode DMNetworkGetSubSection_private(PetscSection master, PetscInt pstart, PetscInt pend,PetscSection *subsection)
929 {
930   PetscErrorCode ierr;
931   PetscInt       i, nvar;
932 
933   PetscFunctionBegin;
934   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)master), subsection);CHKERRQ(ierr);
935   ierr = PetscSectionSetChart(*subsection, 0, pend - pstart);CHKERRQ(ierr);
936   for (i = pstart; i < pend; i++) {
937     ierr = PetscSectionGetDof(master,i,&nvar);CHKERRQ(ierr);
938     ierr = PetscSectionSetDof(*subsection, i - pstart, nvar);CHKERRQ(ierr);
939   }
940 
941   ierr = PetscSectionSetUp(*subsection);CHKERRQ(ierr);
942   PetscFunctionReturn(0);
943 }
944 
945 /* Create a submap of points with a GlobalToLocal structure */
946 PetscErrorCode DMNetworkSetSubMap_private(PetscInt pstart, PetscInt pend, ISLocalToGlobalMapping *map)
947 {
948   PetscErrorCode ierr;
949   PetscInt       i, *subpoints;
950 
951   PetscFunctionBegin;
952   /* Create index sets to map from "points" to "subpoints" */
953   ierr = PetscMalloc1(pend - pstart, &subpoints);CHKERRQ(ierr);
954   for (i = pstart; i < pend; i++) {
955     subpoints[i - pstart] = i;
956   }
957   ierr = ISLocalToGlobalMappingCreate(PETSC_COMM_WORLD,1,pend-pstart,subpoints,PETSC_COPY_VALUES,map);CHKERRQ(ierr);
958   ierr = PetscFree(subpoints);CHKERRQ(ierr);
959   PetscFunctionReturn(0);
960 }
961 
962 /*@
963   DMNetworkAssembleGraphStructures - Assembles vertex and edge data structures. Must be called after DMNetworkDistribute.
964 
965   Collective
966 
967   Input Parameters:
968 . dm   - The DMNetworkObject
969 
970   Note: the routine will create alternative orderings for the vertices and edges. Assume global network points are:
971 
972   points = [0 1 2 3 4 5 6]
973 
974   where edges = [0, 3] and vertices = [4, 6]. The new orderings will be specific to the subset (i.e vertices = [0, 2]).
975 
976   With this new ordering a local PetscSection, global PetscSection and PetscSF will be created specific to the subset.
977 
978   Level: intermediate
979 
980 @*/
981 PetscErrorCode DMNetworkAssembleGraphStructures(DM dm)
982 {
983   PetscErrorCode ierr;
984   MPI_Comm       comm;
985   PetscMPIInt    rank, size;
986   DM_Network     *network = (DM_Network*)dm->data;
987 
988   PetscFunctionBegin;
989   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
990   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
991   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
992 
993   /* Create maps for vertices and edges */
994   ierr = DMNetworkSetSubMap_private(network->vStart,network->vEnd,&network->vertex.mapping);CHKERRQ(ierr);
995   ierr = DMNetworkSetSubMap_private(network->eStart,network->eEnd,&network->edge.mapping);CHKERRQ(ierr);
996 
997   /* Create local sub-sections */
998   ierr = DMNetworkGetSubSection_private(network->DofSection,network->vStart,network->vEnd,&network->vertex.DofSection);CHKERRQ(ierr);
999   ierr = DMNetworkGetSubSection_private(network->DofSection,network->eStart,network->eEnd,&network->edge.DofSection);CHKERRQ(ierr);
1000 
1001   if (size > 1) {
1002     ierr = PetscSFGetSubSF(network->plex->sf, network->vertex.mapping, &network->vertex.sf);CHKERRQ(ierr);
1003     ierr = PetscSectionCreateGlobalSection(network->vertex.DofSection, network->vertex.sf, PETSC_FALSE, PETSC_FALSE, &network->vertex.GlobalDofSection);CHKERRQ(ierr);
1004   ierr = PetscSFGetSubSF(network->plex->sf, network->edge.mapping, &network->edge.sf);CHKERRQ(ierr);
1005   ierr = PetscSectionCreateGlobalSection(network->edge.DofSection, network->edge.sf, PETSC_FALSE, PETSC_FALSE, &network->edge.GlobalDofSection);CHKERRQ(ierr);
1006   } else {
1007   /* create structures for vertex */
1008   ierr = PetscSectionClone(network->vertex.DofSection,&network->vertex.GlobalDofSection);CHKERRQ(ierr);
1009   /* create structures for edge */
1010   ierr = PetscSectionClone(network->edge.DofSection,&network->edge.GlobalDofSection);CHKERRQ(ierr);
1011   }
1012 
1013 
1014   /* Add viewers */
1015   ierr = PetscObjectSetName((PetscObject)network->edge.GlobalDofSection,"Global edge dof section");CHKERRQ(ierr);
1016   ierr = PetscObjectSetName((PetscObject)network->vertex.GlobalDofSection,"Global vertex dof section");CHKERRQ(ierr);
1017   ierr = PetscSectionViewFromOptions(network->edge.GlobalDofSection, NULL, "-edge_global_section_view");CHKERRQ(ierr);
1018   ierr = PetscSectionViewFromOptions(network->vertex.GlobalDofSection, NULL, "-vertex_global_section_view");CHKERRQ(ierr);
1019 
1020   PetscFunctionReturn(0);
1021 }
1022 
1023 /*@
1024   DMNetworkDistribute - Distributes the network and moves associated component data.
1025 
1026   Collective
1027 
1028   Input Parameter:
1029 + DM - the DMNetwork object
1030 - overlap - The overlap of partitions, 0 is the default
1031 
1032   Notes:
1033   Distributes the network with <overlap>-overlapping partitioning of the edges.
1034 
1035   Level: intermediate
1036 
1037 .seealso: DMNetworkCreate
1038 @*/
1039 PetscErrorCode DMNetworkDistribute(DM *dm,PetscInt overlap)
1040 {
1041   MPI_Comm       comm;
1042   PetscErrorCode ierr;
1043   PetscMPIInt    size;
1044   DM_Network     *oldDMnetwork = (DM_Network*)((*dm)->data);
1045   DM_Network     *newDMnetwork;
1046   PetscSF        pointsf;
1047   DM             newDM;
1048   PetscPartitioner part;
1049   PetscInt         j,e,v,offset;
1050   DMNetworkComponentHeader header;
1051 
1052   PetscFunctionBegin;
1053 
1054   ierr = PetscObjectGetComm((PetscObject)*dm,&comm);CHKERRQ(ierr);
1055   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
1056   if (size == 1) PetscFunctionReturn(0);
1057 
1058   ierr = DMNetworkCreate(PetscObjectComm((PetscObject)*dm),&newDM);CHKERRQ(ierr);
1059   newDMnetwork = (DM_Network*)newDM->data;
1060   newDMnetwork->dataheadersize = sizeof(struct _p_DMNetworkComponentHeader)/sizeof(DMNetworkComponentGenericDataType);
1061 
1062   /* Enable runtime options for petscpartitioner */
1063   ierr = DMPlexGetPartitioner(oldDMnetwork->plex,&part);CHKERRQ(ierr);
1064   ierr = PetscPartitionerSetFromOptions(part);CHKERRQ(ierr);
1065 
1066   /* Distribute plex dm and dof section */
1067   ierr = DMPlexDistribute(oldDMnetwork->plex,overlap,&pointsf,&newDMnetwork->plex);CHKERRQ(ierr);
1068 
1069   /* Distribute dof section */
1070   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)*dm),&newDMnetwork->DofSection);CHKERRQ(ierr);
1071   ierr = PetscSFDistributeSection(pointsf,oldDMnetwork->DofSection,NULL,newDMnetwork->DofSection);CHKERRQ(ierr);
1072   ierr = PetscSectionCreate(PetscObjectComm((PetscObject)*dm),&newDMnetwork->DataSection);CHKERRQ(ierr);
1073 
1074   /* Distribute data and associated section */
1075   ierr = DMPlexDistributeData(newDMnetwork->plex,pointsf,oldDMnetwork->DataSection,MPIU_INT,(void*)oldDMnetwork->componentdataarray,newDMnetwork->DataSection,(void**)&newDMnetwork->componentdataarray);CHKERRQ(ierr);
1076 
1077   ierr = PetscSectionGetChart(newDMnetwork->DataSection,&newDMnetwork->pStart,&newDMnetwork->pEnd);CHKERRQ(ierr);
1078   ierr = DMPlexGetHeightStratum(newDMnetwork->plex,0, &newDMnetwork->eStart,&newDMnetwork->eEnd);CHKERRQ(ierr);
1079   ierr = DMPlexGetHeightStratum(newDMnetwork->plex,1,&newDMnetwork->vStart,&newDMnetwork->vEnd);CHKERRQ(ierr);
1080   newDMnetwork->nEdges = newDMnetwork->eEnd - newDMnetwork->eStart;
1081   newDMnetwork->nVertices = newDMnetwork->vEnd - newDMnetwork->vStart;
1082   newDMnetwork->NVertices = oldDMnetwork->NVertices;
1083   newDMnetwork->NEdges = oldDMnetwork->NEdges;
1084 
1085   /* Set Dof section as the default section for dm */
1086   ierr = DMSetDefaultSection(newDMnetwork->plex,newDMnetwork->DofSection);CHKERRQ(ierr);
1087   ierr = DMGetDefaultGlobalSection(newDMnetwork->plex,&newDMnetwork->GlobalDofSection);CHKERRQ(ierr);
1088 
1089   /* Set up subnetwork info in the newDM */
1090   newDMnetwork->nsubnet = oldDMnetwork->nsubnet;
1091   ierr = PetscCalloc1(newDMnetwork->nsubnet,&newDMnetwork->subnet);CHKERRQ(ierr);
1092   /* Copy over the global number of vertices and edges in each subnetwork. Note that these are already
1093      calculated in DMNetworkLayoutSetUp()
1094   */
1095   for(j=0; j < newDMnetwork->nsubnet; j++) {
1096     newDMnetwork->subnet[j].Nvtx = oldDMnetwork->subnet[j].Nvtx;
1097     newDMnetwork->subnet[j].Nedge = oldDMnetwork->subnet[j].Nedge;
1098   }
1099 
1100   for(e = newDMnetwork->eStart; e < newDMnetwork->eEnd; e++ ) {
1101     ierr = PetscSectionGetOffset(newDMnetwork->DataSection,e,&offset);CHKERRQ(ierr);
1102     header = (DMNetworkComponentHeader)(newDMnetwork->componentdataarray+offset);CHKERRQ(ierr);
1103     newDMnetwork->subnet[header->subnetid].nedge++;
1104   }
1105 
1106   for(v = newDMnetwork->vStart; v < newDMnetwork->vEnd; v++ ) {
1107     ierr = PetscSectionGetOffset(newDMnetwork->DataSection,v,&offset);CHKERRQ(ierr);
1108     header = (DMNetworkComponentHeader)(newDMnetwork->componentdataarray+offset);CHKERRQ(ierr);
1109     newDMnetwork->subnet[header->subnetid].nvtx++;
1110   }
1111 
1112   /* Now create the vertices and edge arrays for the subnetworks */
1113   for(j=0; j < newDMnetwork->nsubnet; j++) {
1114     ierr = PetscCalloc1(newDMnetwork->subnet[j].nedge,&newDMnetwork->subnet[j].edges);CHKERRQ(ierr);
1115     ierr = PetscCalloc1(newDMnetwork->subnet[j].nvtx,&newDMnetwork->subnet[j].vertices);CHKERRQ(ierr);
1116     /* Temporarily setting nvtx and nedge to 0 so we can use them as counters in the below for loop.
1117        These get updated when the vertices and edges are added. */
1118     newDMnetwork->subnet[j].nvtx = newDMnetwork->subnet[j].nedge = 0;
1119   }
1120 
1121   /* Set the vertices and edges in each subnetwork */
1122   for(e = newDMnetwork->eStart; e < newDMnetwork->eEnd; e++ ) {
1123     ierr = PetscSectionGetOffset(newDMnetwork->DataSection,e,&offset);CHKERRQ(ierr);
1124     header = (DMNetworkComponentHeader)(newDMnetwork->componentdataarray+offset);CHKERRQ(ierr);
1125     newDMnetwork->subnet[header->subnetid].edges[newDMnetwork->subnet[header->subnetid].nedge++]  = e;
1126   }
1127 
1128   for(v = newDMnetwork->vStart; v < newDMnetwork->vEnd; v++ ) {
1129     ierr = PetscSectionGetOffset(newDMnetwork->DataSection,v,&offset);CHKERRQ(ierr);
1130     header = (DMNetworkComponentHeader)(newDMnetwork->componentdataarray+offset);CHKERRQ(ierr);
1131     newDMnetwork->subnet[header->subnetid].vertices[newDMnetwork->subnet[header->subnetid].nvtx++]  = v;
1132   }
1133 
1134   /* Destroy point SF */
1135   ierr = PetscSFDestroy(&pointsf);CHKERRQ(ierr);
1136 
1137   ierr = DMDestroy(dm);CHKERRQ(ierr);
1138   *dm  = newDM;
1139   PetscFunctionReturn(0);
1140 }
1141 
1142 /*@C
1143   PetscSFGetSubSF - Returns an SF for a specific subset of points. Leaves are re-numbered to reflect the new ordering.
1144 
1145   Input Parameters:
1146 + masterSF - the original SF structure
1147 - map      - a ISLocalToGlobal mapping that contains the subset of points
1148 
1149   Output Parameters:
1150 . subSF    - a subset of the masterSF for the desired subset.
1151 */
1152 
1153 PetscErrorCode PetscSFGetSubSF(PetscSF mastersf, ISLocalToGlobalMapping map, PetscSF *subSF) {
1154 
1155   PetscErrorCode        ierr;
1156   PetscInt              nroots, nleaves, *ilocal_sub;
1157   PetscInt              i, *ilocal_map, nroots_sub, nleaves_sub = 0;
1158   PetscInt              *local_points, *remote_points;
1159   PetscSFNode           *iremote_sub;
1160   const PetscInt        *ilocal;
1161   const PetscSFNode     *iremote;
1162 
1163   PetscFunctionBegin;
1164   ierr = PetscSFGetGraph(mastersf,&nroots,&nleaves,&ilocal,&iremote);CHKERRQ(ierr);
1165 
1166   /* Look for leaves that pertain to the subset of points. Get the local ordering */
1167   ierr = PetscMalloc1(nleaves,&ilocal_map);CHKERRQ(ierr);
1168   ierr = ISGlobalToLocalMappingApply(map,IS_GTOLM_MASK,nleaves,ilocal,NULL,ilocal_map);CHKERRQ(ierr);
1169   for (i = 0; i < nleaves; i++) {
1170     if (ilocal_map[i] != -1) nleaves_sub += 1;
1171   }
1172   /* Re-number ilocal with subset numbering. Need information from roots */
1173   ierr = PetscMalloc2(nroots,&local_points,nroots,&remote_points);CHKERRQ(ierr);
1174   for (i = 0; i < nroots; i++) local_points[i] = i;
1175   ierr = ISGlobalToLocalMappingApply(map,IS_GTOLM_MASK,nroots,local_points,NULL,local_points);CHKERRQ(ierr);
1176   ierr = PetscSFBcastBegin(mastersf, MPIU_INT, local_points, remote_points);CHKERRQ(ierr);
1177   ierr = PetscSFBcastEnd(mastersf, MPIU_INT, local_points, remote_points);CHKERRQ(ierr);
1178   /* Fill up graph using local (that is, local to the subset) numbering. */
1179   ierr = PetscMalloc1(nleaves_sub,&ilocal_sub);CHKERRQ(ierr);
1180   ierr = PetscMalloc1(nleaves_sub,&iremote_sub);CHKERRQ(ierr);
1181   nleaves_sub = 0;
1182   for (i = 0; i < nleaves; i++) {
1183     if (ilocal_map[i] != -1) {
1184       ilocal_sub[nleaves_sub] = ilocal_map[i];
1185       iremote_sub[nleaves_sub].rank = iremote[i].rank;
1186       iremote_sub[nleaves_sub].index = remote_points[ilocal[i]];
1187       nleaves_sub += 1;
1188     }
1189   }
1190   ierr = PetscFree2(local_points,remote_points);CHKERRQ(ierr);
1191   ierr = ISLocalToGlobalMappingGetSize(map,&nroots_sub);CHKERRQ(ierr);
1192 
1193   /* Create new subSF */
1194   ierr = PetscSFCreate(PETSC_COMM_WORLD,subSF);CHKERRQ(ierr);
1195   ierr = PetscSFSetFromOptions(*subSF);CHKERRQ(ierr);
1196   ierr = PetscSFSetGraph(*subSF,nroots_sub,nleaves_sub,ilocal_sub,PETSC_OWN_POINTER,iremote_sub,PETSC_COPY_VALUES);CHKERRQ(ierr);
1197   ierr = PetscFree(ilocal_map);CHKERRQ(ierr);
1198   ierr = PetscFree(iremote_sub);CHKERRQ(ierr);
1199   PetscFunctionReturn(0);
1200 }
1201 
1202 /*@C
1203   DMNetworkGetSupportingEdges - Return the supporting edges for this vertex point
1204 
1205   Not Collective
1206 
1207   Input Parameters:
1208 + dm - The DMNetwork object
1209 - p  - the vertex point
1210 
1211   Output Paramters:
1212 + nedges - number of edges connected to this vertex point
1213 - edges  - List of edge points
1214 
1215   Level: intermediate
1216 
1217   Fortran Notes:
1218   Since it returns an array, this routine is only available in Fortran 90, and you must
1219   include petsc.h90 in your code.
1220 
1221 .seealso: DMNetworkCreate, DMNetworkGetConnectedVertices
1222 @*/
1223 PetscErrorCode DMNetworkGetSupportingEdges(DM dm,PetscInt vertex,PetscInt *nedges,const PetscInt *edges[])
1224 {
1225   PetscErrorCode ierr;
1226   DM_Network     *network = (DM_Network*)dm->data;
1227 
1228   PetscFunctionBegin;
1229   ierr = DMPlexGetSupportSize(network->plex,vertex,nedges);CHKERRQ(ierr);
1230   ierr = DMPlexGetSupport(network->plex,vertex,edges);CHKERRQ(ierr);
1231   PetscFunctionReturn(0);
1232 }
1233 
1234 /*@C
1235   DMNetworkGetConnectedVertices - Return the connected vertices for this edge point
1236 
1237   Not Collective
1238 
1239   Input Parameters:
1240 + dm - The DMNetwork object
1241 - p  - the edge point
1242 
1243   Output Paramters:
1244 . vertices  - vertices connected to this edge
1245 
1246   Level: intermediate
1247 
1248   Fortran Notes:
1249   Since it returns an array, this routine is only available in Fortran 90, and you must
1250   include petsc.h90 in your code.
1251 
1252 .seealso: DMNetworkCreate, DMNetworkGetSupportingEdges
1253 @*/
1254 PetscErrorCode DMNetworkGetConnectedVertices(DM dm,PetscInt edge,const PetscInt *vertices[])
1255 {
1256   PetscErrorCode ierr;
1257   DM_Network     *network = (DM_Network*)dm->data;
1258 
1259   PetscFunctionBegin;
1260   ierr = DMPlexGetCone(network->plex,edge,vertices);CHKERRQ(ierr);
1261   PetscFunctionReturn(0);
1262 }
1263 
1264 /*@
1265   DMNetworkIsGhostVertex - Returns TRUE if the vertex is a ghost vertex
1266 
1267   Not Collective
1268 
1269   Input Parameters:
1270 + dm - The DMNetwork object
1271 . p  - the vertex point
1272 
1273   Output Parameter:
1274 . isghost - TRUE if the vertex is a ghost point
1275 
1276   Level: intermediate
1277 
1278 .seealso: DMNetworkCreate, DMNetworkGetConnectedVertices, DMNetworkGetVertexRange
1279 @*/
1280 PetscErrorCode DMNetworkIsGhostVertex(DM dm,PetscInt p,PetscBool *isghost)
1281 {
1282   PetscErrorCode ierr;
1283   DM_Network     *network = (DM_Network*)dm->data;
1284   PetscInt       offsetg;
1285   PetscSection   sectiong;
1286 
1287   PetscFunctionBegin;
1288   *isghost = PETSC_FALSE;
1289   ierr = DMGetDefaultGlobalSection(network->plex,&sectiong);CHKERRQ(ierr);
1290   ierr = PetscSectionGetOffset(sectiong,p,&offsetg);CHKERRQ(ierr);
1291   if (offsetg < 0) *isghost = PETSC_TRUE;
1292   PetscFunctionReturn(0);
1293 }
1294 
1295 PetscErrorCode DMSetUp_Network(DM dm)
1296 {
1297   PetscErrorCode ierr;
1298   DM_Network     *network=(DM_Network*)dm->data;
1299 
1300   PetscFunctionBegin;
1301   ierr = DMNetworkComponentSetUp(dm);CHKERRQ(ierr);
1302   ierr = DMNetworkVariablesSetUp(dm);CHKERRQ(ierr);
1303 
1304   ierr = DMSetDefaultSection(network->plex,network->DofSection);CHKERRQ(ierr);
1305   ierr = DMGetDefaultGlobalSection(network->plex,&network->GlobalDofSection);CHKERRQ(ierr);
1306   PetscFunctionReturn(0);
1307 }
1308 
1309 /*@
1310     DMNetworkHasJacobian - Sets global flag for using user's sub Jacobian matrices
1311                             -- replaced by DMNetworkSetOption(network,userjacobian,PETSC_TURE)?
1312 
1313     Collective
1314 
1315     Input Parameters:
1316 +   dm - The DMNetwork object
1317 .   eflg - turn the option on (PETSC_TRUE) or off (PETSC_FALSE) if user provides Jacobian for edges
1318 -   vflg - turn the option on (PETSC_TRUE) or off (PETSC_FALSE) if user provides Jacobian for vertices
1319 
1320     Level: intermediate
1321 
1322 @*/
1323 PetscErrorCode DMNetworkHasJacobian(DM dm,PetscBool eflg,PetscBool vflg)
1324 {
1325   DM_Network     *network=(DM_Network*)dm->data;
1326   PetscErrorCode ierr;
1327 
1328   PetscFunctionBegin;
1329   network->userEdgeJacobian   = eflg;
1330   network->userVertexJacobian = vflg;
1331 
1332   if (eflg && !network->Je) {
1333     ierr = PetscCalloc1(3*network->nEdges,&network->Je);CHKERRQ(ierr);
1334   }
1335 
1336   if (vflg && !network->Jv) {
1337     PetscInt       i,*vptr,nedges,vStart=network->vStart;
1338     PetscInt       nVertices = network->nVertices,nedges_total;
1339     const PetscInt *edges;
1340 
1341     /* count nvertex_total */
1342     nedges_total = 0;
1343     ierr = PetscMalloc1(nVertices+1,&vptr);CHKERRQ(ierr);
1344 
1345     vptr[0] = 0;
1346     for (i=0; i<nVertices; i++) {
1347       ierr = DMNetworkGetSupportingEdges(dm,i+vStart,&nedges,&edges);CHKERRQ(ierr);
1348       nedges_total += nedges;
1349       vptr[i+1] = vptr[i] + 2*nedges + 1;
1350     }
1351 
1352     ierr = PetscCalloc1(2*nedges_total+nVertices,&network->Jv);CHKERRQ(ierr);
1353     network->Jvptr = vptr;
1354   }
1355   PetscFunctionReturn(0);
1356 }
1357 
1358 /*@
1359     DMNetworkEdgeSetMatrix - Sets user-provided Jacobian matrices for this edge to the network
1360 
1361     Not Collective
1362 
1363     Input Parameters:
1364 +   dm - The DMNetwork object
1365 .   p  - the edge point
1366 -   J - array (size = 3) of Jacobian submatrices for this edge point:
1367         J[0]: this edge
1368         J[1] and J[2]: connected vertices, obtained by calling DMNetworkGetConnectedVertices()
1369 
1370     Level: intermediate
1371 
1372 .seealso: DMNetworkVertexSetMatrix
1373 @*/
1374 PetscErrorCode DMNetworkEdgeSetMatrix(DM dm,PetscInt p,Mat J[])
1375 {
1376   DM_Network     *network=(DM_Network*)dm->data;
1377 
1378   PetscFunctionBegin;
1379   if (!network->Je) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ORDER,"Must call DMNetworkHasJacobian() collectively before calling DMNetworkEdgeSetMatrix");
1380 
1381   if (J) {
1382     network->Je[3*p]   = J[0];
1383     network->Je[3*p+1] = J[1];
1384     network->Je[3*p+2] = J[2];
1385   }
1386   PetscFunctionReturn(0);
1387 }
1388 
1389 /*@
1390     DMNetworkVertexSetMatrix - Sets user-provided Jacobian matrix for this vertex to the network
1391 
1392     Not Collective
1393 
1394     Input Parameters:
1395 +   dm - The DMNetwork object
1396 .   p  - the vertex point
1397 -   J - array of Jacobian (size = 2*(num of supporting edges) + 1) submatrices for this vertex point:
1398         J[0]:       this vertex
1399         J[1+2*i]:   i-th supporting edge
1400         J[1+2*i+1]: i-th connected vertex
1401 
1402     Level: intermediate
1403 
1404 .seealso: DMNetworkEdgeSetMatrix
1405 @*/
1406 PetscErrorCode DMNetworkVertexSetMatrix(DM dm,PetscInt p,Mat J[])
1407 {
1408   PetscErrorCode ierr;
1409   DM_Network     *network=(DM_Network*)dm->data;
1410   PetscInt       i,*vptr,nedges,vStart=network->vStart;
1411   const PetscInt *edges;
1412 
1413   PetscFunctionBegin;
1414   if (!network->Jv) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ORDER,"Must call DMNetworkHasJacobian() collectively before calling DMNetworkVertexSetMatrix");
1415 
1416   if (J) {
1417     vptr = network->Jvptr;
1418     network->Jv[vptr[p-vStart]] = J[0]; /* Set Jacobian for this vertex */
1419 
1420     /* Set Jacobian for each supporting edge and connected vertex */
1421     ierr = DMNetworkGetSupportingEdges(dm,p,&nedges,&edges);CHKERRQ(ierr);
1422     for (i=1; i<=2*nedges; i++) network->Jv[vptr[p-vStart]+i] = J[i];
1423   }
1424   PetscFunctionReturn(0);
1425 }
1426 
1427 PETSC_STATIC_INLINE PetscErrorCode MatSetPreallocationDenseblock_private(PetscInt nrows,PetscInt *rows,PetscInt ncols,PetscBool ghost,Vec vdnz,Vec vonz)
1428 {
1429   PetscErrorCode ierr;
1430   PetscInt       j;
1431   PetscScalar    val=(PetscScalar)ncols;
1432 
1433   PetscFunctionBegin;
1434   if (!ghost) {
1435     for (j=0; j<nrows; j++) {
1436       ierr = VecSetValues(vdnz,1,&rows[j],&val,ADD_VALUES);CHKERRQ(ierr);
1437     }
1438   } else {
1439     for (j=0; j<nrows; j++) {
1440       ierr = VecSetValues(vonz,1,&rows[j],&val,ADD_VALUES);CHKERRQ(ierr);
1441     }
1442   }
1443   PetscFunctionReturn(0);
1444 }
1445 
1446 PETSC_STATIC_INLINE PetscErrorCode MatSetPreallocationUserblock_private(Mat Ju,PetscInt nrows,PetscInt *rows,PetscInt ncols,PetscBool ghost,Vec vdnz,Vec vonz)
1447 {
1448   PetscErrorCode ierr;
1449   PetscInt       j,ncols_u;
1450   PetscScalar    val;
1451 
1452   PetscFunctionBegin;
1453   if (!ghost) {
1454     for (j=0; j<nrows; j++) {
1455       ierr = MatGetRow(Ju,j,&ncols_u,NULL,NULL);CHKERRQ(ierr);
1456       val = (PetscScalar)ncols_u;
1457       ierr = VecSetValues(vdnz,1,&rows[j],&val,ADD_VALUES);CHKERRQ(ierr);
1458       ierr = MatRestoreRow(Ju,j,&ncols_u,NULL,NULL);CHKERRQ(ierr);
1459     }
1460   } else {
1461     for (j=0; j<nrows; j++) {
1462       ierr = MatGetRow(Ju,j,&ncols_u,NULL,NULL);CHKERRQ(ierr);
1463       val = (PetscScalar)ncols_u;
1464       ierr = VecSetValues(vonz,1,&rows[j],&val,ADD_VALUES);CHKERRQ(ierr);
1465       ierr = MatRestoreRow(Ju,j,&ncols_u,NULL,NULL);CHKERRQ(ierr);
1466     }
1467   }
1468   PetscFunctionReturn(0);
1469 }
1470 
1471 PETSC_STATIC_INLINE PetscErrorCode MatSetPreallocationblock_private(Mat Ju,PetscInt nrows,PetscInt *rows,PetscInt ncols,PetscBool ghost,Vec vdnz,Vec vonz)
1472 {
1473   PetscErrorCode ierr;
1474 
1475   PetscFunctionBegin;
1476   if (Ju) {
1477     ierr = MatSetPreallocationUserblock_private(Ju,nrows,rows,ncols,ghost,vdnz,vonz);CHKERRQ(ierr);
1478   } else {
1479     ierr = MatSetPreallocationDenseblock_private(nrows,rows,ncols,ghost,vdnz,vonz);CHKERRQ(ierr);
1480   }
1481   PetscFunctionReturn(0);
1482 }
1483 
1484 PETSC_STATIC_INLINE PetscErrorCode MatSetDenseblock_private(PetscInt nrows,PetscInt *rows,PetscInt ncols,PetscInt cstart,Mat *J)
1485 {
1486   PetscErrorCode ierr;
1487   PetscInt       j,*cols;
1488   PetscScalar    *zeros;
1489 
1490   PetscFunctionBegin;
1491   ierr = PetscCalloc2(ncols,&cols,nrows*ncols,&zeros);CHKERRQ(ierr);
1492   for (j=0; j<ncols; j++) cols[j] = j+ cstart;
1493   ierr = MatSetValues(*J,nrows,rows,ncols,cols,zeros,INSERT_VALUES);CHKERRQ(ierr);
1494   ierr = PetscFree2(cols,zeros);CHKERRQ(ierr);
1495   PetscFunctionReturn(0);
1496 }
1497 
1498 PETSC_STATIC_INLINE PetscErrorCode MatSetUserblock_private(Mat Ju,PetscInt nrows,PetscInt *rows,PetscInt ncols,PetscInt cstart,Mat *J)
1499 {
1500   PetscErrorCode ierr;
1501   PetscInt       j,M,N,row,col,ncols_u;
1502   const PetscInt *cols;
1503   PetscScalar    zero=0.0;
1504 
1505   PetscFunctionBegin;
1506   ierr = MatGetSize(Ju,&M,&N);CHKERRQ(ierr);
1507   if (nrows != M || ncols != N) SETERRQ4(PetscObjectComm((PetscObject)Ju),PETSC_ERR_USER,"%D by %D must equal %D by %D",nrows,ncols,M,N);
1508 
1509   for (row=0; row<nrows; row++) {
1510     ierr = MatGetRow(Ju,row,&ncols_u,&cols,NULL);CHKERRQ(ierr);
1511     for (j=0; j<ncols_u; j++) {
1512       col = cols[j] + cstart;
1513       ierr = MatSetValues(*J,1,&rows[row],1,&col,&zero,INSERT_VALUES);CHKERRQ(ierr);
1514     }
1515     ierr = MatRestoreRow(Ju,row,&ncols_u,&cols,NULL);CHKERRQ(ierr);
1516   }
1517   PetscFunctionReturn(0);
1518 }
1519 
1520 PETSC_STATIC_INLINE PetscErrorCode MatSetblock_private(Mat Ju,PetscInt nrows,PetscInt *rows,PetscInt ncols,PetscInt cstart,Mat *J)
1521 {
1522   PetscErrorCode ierr;
1523 
1524   PetscFunctionBegin;
1525   if (Ju) {
1526     ierr = MatSetUserblock_private(Ju,nrows,rows,ncols,cstart,J);CHKERRQ(ierr);
1527   } else {
1528     ierr = MatSetDenseblock_private(nrows,rows,ncols,cstart,J);CHKERRQ(ierr);
1529   }
1530   PetscFunctionReturn(0);
1531 }
1532 
1533 /* Creates a GlobalToLocal mapping with a Local and Global section. This is akin to the routine DMGetLocalToGlobalMapping but without the need of providing a dm.
1534 */
1535 PetscErrorCode CreateSubGlobalToLocalMapping_private(PetscSection globalsec, PetscSection localsec, ISLocalToGlobalMapping *ltog)
1536 {
1537   PetscErrorCode ierr;
1538   PetscInt       i, size, dof;
1539   PetscInt       *glob2loc;
1540 
1541   PetscFunctionBegin;
1542   ierr = PetscSectionGetStorageSize(localsec,&size);CHKERRQ(ierr);
1543   ierr = PetscMalloc1(size,&glob2loc);CHKERRQ(ierr);
1544 
1545   for (i = 0; i < size; i++) {
1546     ierr = PetscSectionGetOffset(globalsec,i,&dof);CHKERRQ(ierr);
1547     dof = (dof >= 0) ? dof : -(dof + 1);
1548     glob2loc[i] = dof;
1549   }
1550 
1551   ierr = ISLocalToGlobalMappingCreate(PETSC_COMM_WORLD,1,size,glob2loc,PETSC_OWN_POINTER,ltog);CHKERRQ(ierr);
1552 #if 0
1553   ierr = PetscIntView(size,glob2loc,PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
1554 #endif
1555   PetscFunctionReturn(0);
1556 }
1557 
1558 #include <petsc/private/matimpl.h>
1559 PetscErrorCode DMCreateMatrix_Network(DM dm,Mat *J)
1560 {
1561   PetscErrorCode ierr;
1562   PetscMPIInt    rank, size;
1563   DM_Network     *network = (DM_Network*) dm->data;
1564   PetscInt       eStart,eEnd,vStart,vEnd,rstart,nrows,*rows,localSize;
1565   PetscInt       cstart,ncols,j,e,v;
1566   PetscBool      ghost,ghost_vc,ghost2,isNest;
1567   Mat            Juser;
1568   PetscSection   sectionGlobal;
1569   PetscInt       nedges,*vptr=NULL,vc,*rows_v; /* suppress maybe-uninitialized warning */
1570   const PetscInt *edges,*cone;
1571   MPI_Comm       comm;
1572   MatType        mtype;
1573   Vec            vd_nz,vo_nz;
1574   PetscInt       *dnnz,*onnz;
1575   PetscScalar    *vdnz,*vonz;
1576 
1577   PetscFunctionBegin;
1578   mtype = dm->mattype;
1579   ierr = PetscStrcmp(mtype, MATNEST, &isNest);CHKERRQ(ierr);
1580 
1581   if (isNest) {
1582     /* ierr = DMCreateMatrix_Network_Nest(); */
1583     PetscInt   eDof, vDof;
1584     Mat        j11, j12, j21, j22, bA[2][2];
1585     ISLocalToGlobalMapping eISMap, vISMap;
1586 
1587     ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
1588     ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
1589     ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr);
1590 
1591     ierr = PetscSectionGetConstrainedStorageSize(network->edge.GlobalDofSection,&eDof);CHKERRQ(ierr);
1592     ierr = PetscSectionGetConstrainedStorageSize(network->vertex.GlobalDofSection,&vDof);CHKERRQ(ierr);
1593 
1594     ierr = MatCreate(comm, &j11);CHKERRQ(ierr);
1595     ierr = MatSetSizes(j11, eDof, eDof, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
1596     ierr = MatSetType(j11, MATMPIAIJ);CHKERRQ(ierr);
1597 
1598     ierr = MatCreate(comm, &j12);CHKERRQ(ierr);
1599     ierr = MatSetSizes(j12, eDof, vDof, PETSC_DETERMINE ,PETSC_DETERMINE);CHKERRQ(ierr);
1600     ierr = MatSetType(j12, MATMPIAIJ);CHKERRQ(ierr);
1601 
1602     ierr = MatCreate(comm, &j21);CHKERRQ(ierr);
1603     ierr = MatSetSizes(j21, vDof, eDof, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
1604     ierr = MatSetType(j21, MATMPIAIJ);CHKERRQ(ierr);
1605 
1606     ierr = MatCreate(comm, &j22);CHKERRQ(ierr);
1607     ierr = MatSetSizes(j22, vDof, vDof, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
1608     ierr = MatSetType(j22, MATMPIAIJ);CHKERRQ(ierr);
1609 
1610     bA[0][0] = j11;
1611     bA[0][1] = j12;
1612     bA[1][0] = j21;
1613     bA[1][1] = j22;
1614 
1615     ierr = CreateSubGlobalToLocalMapping_private(network->edge.GlobalDofSection,network->edge.DofSection,&eISMap);CHKERRQ(ierr);
1616     ierr = CreateSubGlobalToLocalMapping_private(network->vertex.GlobalDofSection,network->vertex.DofSection,&vISMap);CHKERRQ(ierr);
1617 
1618     ierr = MatSetLocalToGlobalMapping(j11,eISMap,eISMap);CHKERRQ(ierr);
1619     ierr = MatSetLocalToGlobalMapping(j12,eISMap,vISMap);CHKERRQ(ierr);
1620     ierr = MatSetLocalToGlobalMapping(j21,vISMap,eISMap);CHKERRQ(ierr);
1621     ierr = MatSetLocalToGlobalMapping(j22,vISMap,vISMap);CHKERRQ(ierr);
1622 
1623     ierr = MatSetUp(j11);CHKERRQ(ierr);
1624     ierr = MatSetUp(j12);CHKERRQ(ierr);
1625     ierr = MatSetUp(j21);CHKERRQ(ierr);
1626     ierr = MatSetUp(j22);CHKERRQ(ierr);
1627 
1628     ierr = MatCreateNest(comm,2,NULL,2,NULL,&bA[0][0],J);CHKERRQ(ierr);
1629     ierr = MatSetUp(*J);CHKERRQ(ierr);
1630     ierr = MatNestSetVecType(*J,VECNEST);CHKERRQ(ierr);
1631     ierr = MatDestroy(&j11);CHKERRQ(ierr);
1632     ierr = MatDestroy(&j12);CHKERRQ(ierr);
1633     ierr = MatDestroy(&j21);CHKERRQ(ierr);
1634     ierr = MatDestroy(&j22);CHKERRQ(ierr);
1635 
1636     ierr = MatAssemblyBegin(*J,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1637     ierr = MatAssemblyEnd(*J,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1638 
1639     /* Free structures */
1640     ierr = ISLocalToGlobalMappingDestroy(&eISMap);CHKERRQ(ierr);
1641     ierr = ISLocalToGlobalMappingDestroy(&vISMap);CHKERRQ(ierr);
1642 
1643     PetscFunctionReturn(0);
1644   } else if (!network->userEdgeJacobian && !network->userVertexJacobian) {
1645     /* user does not provide Jacobian blocks */
1646     ierr = DMCreateMatrix(network->plex,J);CHKERRQ(ierr);
1647     ierr = MatSetDM(*J,dm);CHKERRQ(ierr);
1648     PetscFunctionReturn(0);
1649   }
1650 
1651   ierr = MatCreate(PetscObjectComm((PetscObject)dm),J);CHKERRQ(ierr);
1652   ierr = DMGetDefaultGlobalSection(network->plex,&sectionGlobal);CHKERRQ(ierr);
1653   ierr = PetscSectionGetConstrainedStorageSize(sectionGlobal,&localSize);CHKERRQ(ierr);
1654   ierr = MatSetSizes(*J,localSize,localSize,PETSC_DETERMINE,PETSC_DETERMINE);CHKERRQ(ierr);
1655 
1656   ierr = MatSetType(*J,MATAIJ);CHKERRQ(ierr);
1657   ierr = MatSetFromOptions(*J);CHKERRQ(ierr);
1658 
1659   /* (1) Set matrix preallocation */
1660   /*------------------------------*/
1661   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
1662   ierr = VecCreate(comm,&vd_nz);CHKERRQ(ierr);
1663   ierr = VecSetSizes(vd_nz,localSize,PETSC_DECIDE);CHKERRQ(ierr);
1664   ierr = VecSetFromOptions(vd_nz);CHKERRQ(ierr);
1665   ierr = VecSet(vd_nz,0.0);CHKERRQ(ierr);
1666   ierr = VecDuplicate(vd_nz,&vo_nz);CHKERRQ(ierr);
1667 
1668   /* Set preallocation for edges */
1669   /*-----------------------------*/
1670   ierr = DMNetworkGetEdgeRange(dm,&eStart,&eEnd);CHKERRQ(ierr);
1671 
1672   ierr = PetscMalloc1(localSize,&rows);CHKERRQ(ierr);
1673   for (e=eStart; e<eEnd; e++) {
1674     /* Get row indices */
1675     ierr = DMNetworkGetVariableGlobalOffset(dm,e,&rstart);CHKERRQ(ierr);
1676     ierr = DMNetworkGetNumVariables(dm,e,&nrows);CHKERRQ(ierr);
1677     if (nrows) {
1678       for (j=0; j<nrows; j++) rows[j] = j + rstart;
1679 
1680       /* Set preallocation for conntected vertices */
1681       ierr = DMNetworkGetConnectedVertices(dm,e,&cone);CHKERRQ(ierr);
1682       for (v=0; v<2; v++) {
1683         ierr = DMNetworkGetNumVariables(dm,cone[v],&ncols);CHKERRQ(ierr);
1684 
1685         if (network->Je) {
1686           Juser = network->Je[3*e+1+v]; /* Jacobian(e,v) */
1687         } else Juser = NULL;
1688         ierr = DMNetworkIsGhostVertex(dm,cone[v],&ghost);CHKERRQ(ierr);
1689         ierr = MatSetPreallocationblock_private(Juser,nrows,rows,ncols,ghost,vd_nz,vo_nz);CHKERRQ(ierr);
1690       }
1691 
1692       /* Set preallocation for edge self */
1693       cstart = rstart;
1694       if (network->Je) {
1695         Juser = network->Je[3*e]; /* Jacobian(e,e) */
1696       } else Juser = NULL;
1697       ierr = MatSetPreallocationblock_private(Juser,nrows,rows,nrows,PETSC_FALSE,vd_nz,vo_nz);CHKERRQ(ierr);
1698     }
1699   }
1700 
1701   /* Set preallocation for vertices */
1702   /*--------------------------------*/
1703   ierr = DMNetworkGetVertexRange(dm,&vStart,&vEnd);CHKERRQ(ierr);
1704   if (vEnd - vStart) vptr = network->Jvptr;
1705 
1706   for (v=vStart; v<vEnd; v++) {
1707     /* Get row indices */
1708     ierr = DMNetworkGetVariableGlobalOffset(dm,v,&rstart);CHKERRQ(ierr);
1709     ierr = DMNetworkGetNumVariables(dm,v,&nrows);CHKERRQ(ierr);
1710     if (!nrows) continue;
1711 
1712     ierr = DMNetworkIsGhostVertex(dm,v,&ghost);CHKERRQ(ierr);
1713     if (ghost) {
1714       ierr = PetscMalloc1(nrows,&rows_v);CHKERRQ(ierr);
1715     } else {
1716       rows_v = rows;
1717     }
1718 
1719     for (j=0; j<nrows; j++) rows_v[j] = j + rstart;
1720 
1721     /* Get supporting edges and connected vertices */
1722     ierr = DMNetworkGetSupportingEdges(dm,v,&nedges,&edges);CHKERRQ(ierr);
1723 
1724     for (e=0; e<nedges; e++) {
1725       /* Supporting edges */
1726       ierr = DMNetworkGetVariableGlobalOffset(dm,edges[e],&cstart);CHKERRQ(ierr);
1727       ierr = DMNetworkGetNumVariables(dm,edges[e],&ncols);CHKERRQ(ierr);
1728 
1729       if (network->Jv) {
1730         Juser = network->Jv[vptr[v-vStart]+2*e+1]; /* Jacobian(v,e) */
1731       } else Juser = NULL;
1732       ierr = MatSetPreallocationblock_private(Juser,nrows,rows_v,ncols,ghost,vd_nz,vo_nz);CHKERRQ(ierr);
1733 
1734       /* Connected vertices */
1735       ierr = DMNetworkGetConnectedVertices(dm,edges[e],&cone);CHKERRQ(ierr);
1736       vc = (v == cone[0]) ? cone[1]:cone[0];
1737       ierr = DMNetworkIsGhostVertex(dm,vc,&ghost_vc);CHKERRQ(ierr);
1738 
1739       ierr = DMNetworkGetNumVariables(dm,vc,&ncols);CHKERRQ(ierr);
1740 
1741       if (network->Jv) {
1742         Juser = network->Jv[vptr[v-vStart]+2*e+2]; /* Jacobian(v,vc) */
1743       } else Juser = NULL;
1744       if (ghost_vc||ghost) {
1745         ghost2 = PETSC_TRUE;
1746       } else {
1747         ghost2 = PETSC_FALSE;
1748       }
1749       ierr = MatSetPreallocationblock_private(Juser,nrows,rows_v,ncols,ghost2,vd_nz,vo_nz);CHKERRQ(ierr);
1750     }
1751 
1752     /* Set preallocation for vertex self */
1753     ierr = DMNetworkIsGhostVertex(dm,v,&ghost);CHKERRQ(ierr);
1754     if (!ghost) {
1755       ierr = DMNetworkGetVariableGlobalOffset(dm,v,&cstart);CHKERRQ(ierr);
1756       if (network->Jv) {
1757         Juser = network->Jv[vptr[v-vStart]]; /* Jacobian(v,v) */
1758       } else Juser = NULL;
1759       ierr = MatSetPreallocationblock_private(Juser,nrows,rows_v,nrows,PETSC_FALSE,vd_nz,vo_nz);CHKERRQ(ierr);
1760     }
1761     if (ghost) {
1762       ierr = PetscFree(rows_v);CHKERRQ(ierr);
1763     }
1764   }
1765 
1766   ierr = VecAssemblyBegin(vd_nz);CHKERRQ(ierr);
1767   ierr = VecAssemblyBegin(vo_nz);CHKERRQ(ierr);
1768 
1769   ierr = PetscMalloc2(localSize,&dnnz,localSize,&onnz);CHKERRQ(ierr);
1770 
1771   ierr = VecAssemblyEnd(vd_nz);CHKERRQ(ierr);
1772   ierr = VecAssemblyEnd(vo_nz);CHKERRQ(ierr);
1773 
1774   ierr = VecGetArray(vd_nz,&vdnz);CHKERRQ(ierr);
1775   ierr = VecGetArray(vo_nz,&vonz);CHKERRQ(ierr);
1776   for (j=0; j<localSize; j++) {
1777     dnnz[j] = (PetscInt)PetscRealPart(vdnz[j]);
1778     onnz[j] = (PetscInt)PetscRealPart(vonz[j]);
1779   }
1780   ierr = VecRestoreArray(vd_nz,&vdnz);CHKERRQ(ierr);
1781   ierr = VecRestoreArray(vo_nz,&vonz);CHKERRQ(ierr);
1782   ierr = VecDestroy(&vd_nz);CHKERRQ(ierr);
1783   ierr = VecDestroy(&vo_nz);CHKERRQ(ierr);
1784 
1785   ierr = MatSeqAIJSetPreallocation(*J,0,dnnz);CHKERRQ(ierr);
1786   ierr = MatMPIAIJSetPreallocation(*J,0,dnnz,0,onnz);CHKERRQ(ierr);
1787   ierr = MatSetOption(*J,MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_TRUE);CHKERRQ(ierr);
1788 
1789   ierr = PetscFree2(dnnz,onnz);CHKERRQ(ierr);
1790 
1791   /* (2) Set matrix entries for edges */
1792   /*----------------------------------*/
1793   for (e=eStart; e<eEnd; e++) {
1794     /* Get row indices */
1795     ierr = DMNetworkGetVariableGlobalOffset(dm,e,&rstart);CHKERRQ(ierr);
1796     ierr = DMNetworkGetNumVariables(dm,e,&nrows);CHKERRQ(ierr);
1797     if (nrows) {
1798       for (j=0; j<nrows; j++) rows[j] = j + rstart;
1799 
1800       /* Set matrix entries for conntected vertices */
1801       ierr = DMNetworkGetConnectedVertices(dm,e,&cone);CHKERRQ(ierr);
1802       for (v=0; v<2; v++) {
1803         ierr = DMNetworkGetVariableGlobalOffset(dm,cone[v],&cstart);CHKERRQ(ierr);
1804         ierr = DMNetworkGetNumVariables(dm,cone[v],&ncols);CHKERRQ(ierr);
1805 
1806         if (network->Je) {
1807           Juser = network->Je[3*e+1+v]; /* Jacobian(e,v) */
1808         } else Juser = NULL;
1809         ierr = MatSetblock_private(Juser,nrows,rows,ncols,cstart,J);CHKERRQ(ierr);
1810       }
1811 
1812       /* Set matrix entries for edge self */
1813       cstart = rstart;
1814       if (network->Je) {
1815         Juser = network->Je[3*e]; /* Jacobian(e,e) */
1816       } else Juser = NULL;
1817       ierr = MatSetblock_private(Juser,nrows,rows,nrows,cstart,J);CHKERRQ(ierr);
1818     }
1819   }
1820 
1821   /* Set matrix entries for vertices */
1822   /*---------------------------------*/
1823   for (v=vStart; v<vEnd; v++) {
1824     /* Get row indices */
1825     ierr = DMNetworkGetVariableGlobalOffset(dm,v,&rstart);CHKERRQ(ierr);
1826     ierr = DMNetworkGetNumVariables(dm,v,&nrows);CHKERRQ(ierr);
1827     if (!nrows) continue;
1828 
1829     ierr = DMNetworkIsGhostVertex(dm,v,&ghost);CHKERRQ(ierr);
1830     if (ghost) {
1831       ierr = PetscMalloc1(nrows,&rows_v);CHKERRQ(ierr);
1832     } else {
1833       rows_v = rows;
1834     }
1835     for (j=0; j<nrows; j++) rows_v[j] = j + rstart;
1836 
1837     /* Get supporting edges and connected vertices */
1838     ierr = DMNetworkGetSupportingEdges(dm,v,&nedges,&edges);CHKERRQ(ierr);
1839 
1840     for (e=0; e<nedges; e++) {
1841       /* Supporting edges */
1842       ierr = DMNetworkGetVariableGlobalOffset(dm,edges[e],&cstart);CHKERRQ(ierr);
1843       ierr = DMNetworkGetNumVariables(dm,edges[e],&ncols);CHKERRQ(ierr);
1844 
1845       if (network->Jv) {
1846         Juser = network->Jv[vptr[v-vStart]+2*e+1]; /* Jacobian(v,e) */
1847       } else Juser = NULL;
1848       ierr = MatSetblock_private(Juser,nrows,rows_v,ncols,cstart,J);CHKERRQ(ierr);
1849 
1850       /* Connected vertices */
1851       ierr = DMNetworkGetConnectedVertices(dm,edges[e],&cone);CHKERRQ(ierr);
1852       vc = (v == cone[0]) ? cone[1]:cone[0];
1853 
1854       ierr = DMNetworkGetVariableGlobalOffset(dm,vc,&cstart);CHKERRQ(ierr);
1855       ierr = DMNetworkGetNumVariables(dm,vc,&ncols);CHKERRQ(ierr);
1856 
1857       if (network->Jv) {
1858         Juser = network->Jv[vptr[v-vStart]+2*e+2]; /* Jacobian(v,vc) */
1859       } else Juser = NULL;
1860       ierr = MatSetblock_private(Juser,nrows,rows_v,ncols,cstart,J);CHKERRQ(ierr);
1861     }
1862 
1863     /* Set matrix entries for vertex self */
1864     if (!ghost) {
1865       ierr = DMNetworkGetVariableGlobalOffset(dm,v,&cstart);CHKERRQ(ierr);
1866       if (network->Jv) {
1867         Juser = network->Jv[vptr[v-vStart]]; /* Jacobian(v,v) */
1868       } else Juser = NULL;
1869       ierr = MatSetblock_private(Juser,nrows,rows_v,nrows,cstart,J);CHKERRQ(ierr);
1870     }
1871     if (ghost) {
1872       ierr = PetscFree(rows_v);CHKERRQ(ierr);
1873     }
1874   }
1875   ierr = PetscFree(rows);CHKERRQ(ierr);
1876 
1877   ierr = MatAssemblyBegin(*J,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1878   ierr = MatAssemblyEnd(*J,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1879 
1880   ierr = MatSetDM(*J,dm);CHKERRQ(ierr);
1881   PetscFunctionReturn(0);
1882 }
1883 
1884 PetscErrorCode DMDestroy_Network(DM dm)
1885 {
1886   PetscErrorCode ierr;
1887   DM_Network     *network = (DM_Network*) dm->data;
1888   PetscInt       j;
1889 
1890   PetscFunctionBegin;
1891   if (--network->refct > 0) PetscFunctionReturn(0);
1892   if (network->Je) {
1893     ierr = PetscFree(network->Je);CHKERRQ(ierr);
1894   }
1895   if (network->Jv) {
1896     ierr = PetscFree(network->Jvptr);CHKERRQ(ierr);
1897     ierr = PetscFree(network->Jv);CHKERRQ(ierr);
1898   }
1899 
1900   ierr = ISLocalToGlobalMappingDestroy(&network->vertex.mapping);CHKERRQ(ierr);
1901   ierr = PetscSectionDestroy(&network->vertex.DofSection);CHKERRQ(ierr);
1902   ierr = PetscSectionDestroy(&network->vertex.GlobalDofSection);CHKERRQ(ierr);
1903   if (network->vertex.sf) {
1904     ierr = PetscSFDestroy(&network->vertex.sf);CHKERRQ(ierr);
1905   }
1906   /* edge */
1907   ierr = ISLocalToGlobalMappingDestroy(&network->edge.mapping);CHKERRQ(ierr);
1908   ierr = PetscSectionDestroy(&network->edge.DofSection);CHKERRQ(ierr);
1909   ierr = PetscSectionDestroy(&network->edge.GlobalDofSection);CHKERRQ(ierr);
1910   if (network->edge.sf) {
1911     ierr = PetscSFDestroy(&network->edge.sf);CHKERRQ(ierr);
1912   }
1913   ierr = DMDestroy(&network->plex);CHKERRQ(ierr);
1914   network->edges = NULL;
1915   ierr = PetscSectionDestroy(&network->DataSection);CHKERRQ(ierr);
1916   ierr = PetscSectionDestroy(&network->DofSection);CHKERRQ(ierr);
1917 
1918   for(j=0; j < network->nsubnet; j++) {
1919     ierr = PetscFree(network->subnet[j].edges);CHKERRQ(ierr);
1920     ierr = PetscFree(network->subnet[j].vertices);CHKERRQ(ierr);
1921   }
1922   ierr = PetscFree(network->subnet);CHKERRQ(ierr);
1923   ierr = PetscFree(network->componentdataarray);CHKERRQ(ierr);
1924   ierr = PetscFree(network->cvalue);CHKERRQ(ierr);
1925   ierr = PetscFree(network->header);CHKERRQ(ierr);
1926   ierr = PetscFree(network);CHKERRQ(ierr);
1927   PetscFunctionReturn(0);
1928 }
1929 
1930 PetscErrorCode DMView_Network(DM dm, PetscViewer viewer)
1931 {
1932   PetscErrorCode ierr;
1933   DM_Network     *network = (DM_Network*) dm->data;
1934 
1935   PetscFunctionBegin;
1936   ierr = DMView(network->plex,viewer);CHKERRQ(ierr);
1937   PetscFunctionReturn(0);
1938 }
1939 
1940 PetscErrorCode DMGlobalToLocalBegin_Network(DM dm, Vec g, InsertMode mode, Vec l)
1941 {
1942   PetscErrorCode ierr;
1943   DM_Network     *network = (DM_Network*) dm->data;
1944 
1945   PetscFunctionBegin;
1946   ierr = DMGlobalToLocalBegin(network->plex,g,mode,l);CHKERRQ(ierr);
1947   PetscFunctionReturn(0);
1948 }
1949 
1950 PetscErrorCode DMGlobalToLocalEnd_Network(DM dm, Vec g, InsertMode mode, Vec l)
1951 {
1952   PetscErrorCode ierr;
1953   DM_Network     *network = (DM_Network*) dm->data;
1954 
1955   PetscFunctionBegin;
1956   ierr = DMGlobalToLocalEnd(network->plex,g,mode,l);CHKERRQ(ierr);
1957   PetscFunctionReturn(0);
1958 }
1959 
1960 PetscErrorCode DMLocalToGlobalBegin_Network(DM dm, Vec l, InsertMode mode, Vec g)
1961 {
1962   PetscErrorCode ierr;
1963   DM_Network     *network = (DM_Network*) dm->data;
1964 
1965   PetscFunctionBegin;
1966   ierr = DMLocalToGlobalBegin(network->plex,l,mode,g);CHKERRQ(ierr);
1967   PetscFunctionReturn(0);
1968 }
1969 
1970 PetscErrorCode DMLocalToGlobalEnd_Network(DM dm, Vec l, InsertMode mode, Vec g)
1971 {
1972   PetscErrorCode ierr;
1973   DM_Network     *network = (DM_Network*) dm->data;
1974 
1975   PetscFunctionBegin;
1976   ierr = DMLocalToGlobalEnd(network->plex,l,mode,g);CHKERRQ(ierr);
1977   PetscFunctionReturn(0);
1978 }
1979