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