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