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