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