xref: /petsc/src/dm/impls/network/network.c (revision f86eb7e8e649d001a590796288a3a529ede879d1) !
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 
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 
1056     ierr = PetscSectionCreateGlobalSection(network->vertex.DofSection, network->vertex.sf, PETSC_FALSE, PETSC_FALSE, &network->vertex.GlobalDofSection);CHKERRQ(ierr);
1057     ierr = PetscSFGetSubSF(network->plex->sf, network->edge.mapping, &network->edge.sf);CHKERRQ(ierr);
1058     ierr = PetscSectionCreateGlobalSection(network->edge.DofSection, network->edge.sf, PETSC_FALSE, PETSC_FALSE, &network->edge.GlobalDofSection);CHKERRQ(ierr);
1059   } else {
1060     /* create structures for vertex */
1061     ierr = PetscSectionClone(network->vertex.DofSection,&network->vertex.GlobalDofSection);CHKERRQ(ierr);
1062     /* create structures for edge */
1063     ierr = PetscSectionClone(network->edge.DofSection,&network->edge.GlobalDofSection);CHKERRQ(ierr);
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   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   newDMnetwork->distributecalled = PETSC_TRUE;
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 
1367   dm->setupcalled = PETSC_TRUE;
1368   ierr = DMViewFromOptions(dm,NULL,"-dm_view");CHKERRQ(ierr);
1369   PetscFunctionReturn(0);
1370 }
1371 
1372 /*@
1373     DMNetworkHasJacobian - Sets global flag for using user's sub Jacobian matrices
1374                             -- replaced by DMNetworkSetOption(network,userjacobian,PETSC_TURE)?
1375 
1376     Collective
1377 
1378     Input Parameters:
1379 +   dm - The DMNetwork object
1380 .   eflg - turn the option on (PETSC_TRUE) or off (PETSC_FALSE) if user provides Jacobian for edges
1381 -   vflg - turn the option on (PETSC_TRUE) or off (PETSC_FALSE) if user provides Jacobian for vertices
1382 
1383     Level: intermediate
1384 
1385 @*/
1386 PetscErrorCode DMNetworkHasJacobian(DM dm,PetscBool eflg,PetscBool vflg)
1387 {
1388   DM_Network     *network=(DM_Network*)dm->data;
1389   PetscErrorCode ierr;
1390   PetscInt       nVertices = network->nVertices;
1391 
1392   PetscFunctionBegin;
1393   network->userEdgeJacobian   = eflg;
1394   network->userVertexJacobian = vflg;
1395 
1396   if (eflg && !network->Je) {
1397     ierr = PetscCalloc1(3*network->nEdges,&network->Je);CHKERRQ(ierr);
1398   }
1399 
1400   if (vflg && !network->Jv && nVertices) {
1401     PetscInt       i,*vptr,nedges,vStart=network->vStart;
1402     PetscInt       nedges_total;
1403     const PetscInt *edges;
1404 
1405     /* count nvertex_total */
1406     nedges_total = 0;
1407     ierr = PetscMalloc1(nVertices+1,&vptr);CHKERRQ(ierr);
1408 
1409     vptr[0] = 0;
1410     for (i=0; i<nVertices; i++) {
1411       ierr = DMNetworkGetSupportingEdges(dm,i+vStart,&nedges,&edges);CHKERRQ(ierr);
1412       nedges_total += nedges;
1413       vptr[i+1] = vptr[i] + 2*nedges + 1;
1414     }
1415 
1416     ierr = PetscCalloc1(2*nedges_total+nVertices,&network->Jv);CHKERRQ(ierr);
1417     network->Jvptr = vptr;
1418   }
1419   PetscFunctionReturn(0);
1420 }
1421 
1422 /*@
1423     DMNetworkEdgeSetMatrix - Sets user-provided Jacobian matrices for this edge to the network
1424 
1425     Not Collective
1426 
1427     Input Parameters:
1428 +   dm - The DMNetwork object
1429 .   p  - the edge point
1430 -   J - array (size = 3) of Jacobian submatrices for this edge point:
1431         J[0]: this edge
1432         J[1] and J[2]: connected vertices, obtained by calling DMNetworkGetConnectedVertices()
1433 
1434     Level: intermediate
1435 
1436 .seealso: DMNetworkVertexSetMatrix
1437 @*/
1438 PetscErrorCode DMNetworkEdgeSetMatrix(DM dm,PetscInt p,Mat J[])
1439 {
1440   DM_Network     *network=(DM_Network*)dm->data;
1441 
1442   PetscFunctionBegin;
1443   if (!network->Je) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ORDER,"Must call DMNetworkHasJacobian() collectively before calling DMNetworkEdgeSetMatrix");
1444 
1445   if (J) {
1446     network->Je[3*p]   = J[0];
1447     network->Je[3*p+1] = J[1];
1448     network->Je[3*p+2] = J[2];
1449   }
1450   PetscFunctionReturn(0);
1451 }
1452 
1453 /*@
1454     DMNetworkVertexSetMatrix - Sets user-provided Jacobian matrix for this vertex to the network
1455 
1456     Not Collective
1457 
1458     Input Parameters:
1459 +   dm - The DMNetwork object
1460 .   p  - the vertex point
1461 -   J - array of Jacobian (size = 2*(num of supporting edges) + 1) submatrices for this vertex point:
1462         J[0]:       this vertex
1463         J[1+2*i]:   i-th supporting edge
1464         J[1+2*i+1]: i-th connected vertex
1465 
1466     Level: intermediate
1467 
1468 .seealso: DMNetworkEdgeSetMatrix
1469 @*/
1470 PetscErrorCode DMNetworkVertexSetMatrix(DM dm,PetscInt p,Mat J[])
1471 {
1472   PetscErrorCode ierr;
1473   DM_Network     *network=(DM_Network*)dm->data;
1474   PetscInt       i,*vptr,nedges,vStart=network->vStart;
1475   const PetscInt *edges;
1476 
1477   PetscFunctionBegin;
1478   if (!network->Jv) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ORDER,"Must call DMNetworkHasJacobian() collectively before calling DMNetworkVertexSetMatrix");
1479 
1480   if (J) {
1481     vptr = network->Jvptr;
1482     network->Jv[vptr[p-vStart]] = J[0]; /* Set Jacobian for this vertex */
1483 
1484     /* Set Jacobian for each supporting edge and connected vertex */
1485     ierr = DMNetworkGetSupportingEdges(dm,p,&nedges,&edges);CHKERRQ(ierr);
1486     for (i=1; i<=2*nedges; i++) network->Jv[vptr[p-vStart]+i] = J[i];
1487   }
1488   PetscFunctionReturn(0);
1489 }
1490 
1491 PETSC_STATIC_INLINE PetscErrorCode MatSetPreallocationDenseblock_private(PetscInt nrows,PetscInt *rows,PetscInt ncols,PetscBool ghost,Vec vdnz,Vec vonz)
1492 {
1493   PetscErrorCode ierr;
1494   PetscInt       j;
1495   PetscScalar    val=(PetscScalar)ncols;
1496 
1497   PetscFunctionBegin;
1498   if (!ghost) {
1499     for (j=0; j<nrows; j++) {
1500       ierr = VecSetValues(vdnz,1,&rows[j],&val,ADD_VALUES);CHKERRQ(ierr);
1501     }
1502   } else {
1503     for (j=0; j<nrows; j++) {
1504       ierr = VecSetValues(vonz,1,&rows[j],&val,ADD_VALUES);CHKERRQ(ierr);
1505     }
1506   }
1507   PetscFunctionReturn(0);
1508 }
1509 
1510 PETSC_STATIC_INLINE PetscErrorCode MatSetPreallocationUserblock_private(Mat Ju,PetscInt nrows,PetscInt *rows,PetscInt ncols,PetscBool ghost,Vec vdnz,Vec vonz)
1511 {
1512   PetscErrorCode ierr;
1513   PetscInt       j,ncols_u;
1514   PetscScalar    val;
1515 
1516   PetscFunctionBegin;
1517   if (!ghost) {
1518     for (j=0; j<nrows; j++) {
1519       ierr = MatGetRow(Ju,j,&ncols_u,NULL,NULL);CHKERRQ(ierr);
1520       val = (PetscScalar)ncols_u;
1521       ierr = VecSetValues(vdnz,1,&rows[j],&val,ADD_VALUES);CHKERRQ(ierr);
1522       ierr = MatRestoreRow(Ju,j,&ncols_u,NULL,NULL);CHKERRQ(ierr);
1523     }
1524   } else {
1525     for (j=0; j<nrows; j++) {
1526       ierr = MatGetRow(Ju,j,&ncols_u,NULL,NULL);CHKERRQ(ierr);
1527       val = (PetscScalar)ncols_u;
1528       ierr = VecSetValues(vonz,1,&rows[j],&val,ADD_VALUES);CHKERRQ(ierr);
1529       ierr = MatRestoreRow(Ju,j,&ncols_u,NULL,NULL);CHKERRQ(ierr);
1530     }
1531   }
1532   PetscFunctionReturn(0);
1533 }
1534 
1535 PETSC_STATIC_INLINE PetscErrorCode MatSetPreallocationblock_private(Mat Ju,PetscInt nrows,PetscInt *rows,PetscInt ncols,PetscBool ghost,Vec vdnz,Vec vonz)
1536 {
1537   PetscErrorCode ierr;
1538 
1539   PetscFunctionBegin;
1540   if (Ju) {
1541     ierr = MatSetPreallocationUserblock_private(Ju,nrows,rows,ncols,ghost,vdnz,vonz);CHKERRQ(ierr);
1542   } else {
1543     ierr = MatSetPreallocationDenseblock_private(nrows,rows,ncols,ghost,vdnz,vonz);CHKERRQ(ierr);
1544   }
1545   PetscFunctionReturn(0);
1546 }
1547 
1548 PETSC_STATIC_INLINE PetscErrorCode MatSetDenseblock_private(PetscInt nrows,PetscInt *rows,PetscInt ncols,PetscInt cstart,Mat *J)
1549 {
1550   PetscErrorCode ierr;
1551   PetscInt       j,*cols;
1552   PetscScalar    *zeros;
1553 
1554   PetscFunctionBegin;
1555   ierr = PetscCalloc2(ncols,&cols,nrows*ncols,&zeros);CHKERRQ(ierr);
1556   for (j=0; j<ncols; j++) cols[j] = j+ cstart;
1557   ierr = MatSetValues(*J,nrows,rows,ncols,cols,zeros,INSERT_VALUES);CHKERRQ(ierr);
1558   ierr = PetscFree2(cols,zeros);CHKERRQ(ierr);
1559   PetscFunctionReturn(0);
1560 }
1561 
1562 PETSC_STATIC_INLINE PetscErrorCode MatSetUserblock_private(Mat Ju,PetscInt nrows,PetscInt *rows,PetscInt ncols,PetscInt cstart,Mat *J)
1563 {
1564   PetscErrorCode ierr;
1565   PetscInt       j,M,N,row,col,ncols_u;
1566   const PetscInt *cols;
1567   PetscScalar    zero=0.0;
1568 
1569   PetscFunctionBegin;
1570   ierr = MatGetSize(Ju,&M,&N);CHKERRQ(ierr);
1571   if (nrows != M || ncols != N) SETERRQ4(PetscObjectComm((PetscObject)Ju),PETSC_ERR_USER,"%D by %D must equal %D by %D",nrows,ncols,M,N);
1572 
1573   for (row=0; row<nrows; row++) {
1574     ierr = MatGetRow(Ju,row,&ncols_u,&cols,NULL);CHKERRQ(ierr);
1575     for (j=0; j<ncols_u; j++) {
1576       col = cols[j] + cstart;
1577       ierr = MatSetValues(*J,1,&rows[row],1,&col,&zero,INSERT_VALUES);CHKERRQ(ierr);
1578     }
1579     ierr = MatRestoreRow(Ju,row,&ncols_u,&cols,NULL);CHKERRQ(ierr);
1580   }
1581   PetscFunctionReturn(0);
1582 }
1583 
1584 PETSC_STATIC_INLINE PetscErrorCode MatSetblock_private(Mat Ju,PetscInt nrows,PetscInt *rows,PetscInt ncols,PetscInt cstart,Mat *J)
1585 {
1586   PetscErrorCode ierr;
1587 
1588   PetscFunctionBegin;
1589   if (Ju) {
1590     ierr = MatSetUserblock_private(Ju,nrows,rows,ncols,cstart,J);CHKERRQ(ierr);
1591   } else {
1592     ierr = MatSetDenseblock_private(nrows,rows,ncols,cstart,J);CHKERRQ(ierr);
1593   }
1594   PetscFunctionReturn(0);
1595 }
1596 
1597 /* 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.
1598 */
1599 PetscErrorCode CreateSubGlobalToLocalMapping_private(PetscSection globalsec, PetscSection localsec, ISLocalToGlobalMapping *ltog)
1600 {
1601   PetscErrorCode ierr;
1602   PetscInt       i,size,dof;
1603   PetscInt       *glob2loc;
1604 
1605   PetscFunctionBegin;
1606   ierr = PetscSectionGetStorageSize(localsec,&size);CHKERRQ(ierr);
1607   ierr = PetscMalloc1(size,&glob2loc);CHKERRQ(ierr);
1608 
1609   for (i = 0; i < size; i++) {
1610     ierr = PetscSectionGetOffset(globalsec,i,&dof);CHKERRQ(ierr);
1611     dof = (dof >= 0) ? dof : -(dof + 1);
1612     glob2loc[i] = dof;
1613   }
1614 
1615   ierr = ISLocalToGlobalMappingCreate(PETSC_COMM_WORLD,1,size,glob2loc,PETSC_OWN_POINTER,ltog);CHKERRQ(ierr);
1616 #if 0
1617   ierr = PetscIntView(size,glob2loc,PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
1618 #endif
1619   PetscFunctionReturn(0);
1620 }
1621 
1622 #include <petsc/private/matimpl.h>
1623 
1624 PetscErrorCode DMCreateMatrix_Network_Nest(DM dm,Mat *J)
1625 {
1626   PetscErrorCode ierr;
1627   DM_Network     *network = (DM_Network*)dm->data;
1628   PetscMPIInt    rank, size;
1629   PetscInt       eDof,vDof;
1630   Mat            j11,j12,j21,j22,bA[2][2];
1631   MPI_Comm       comm;
1632   ISLocalToGlobalMapping eISMap,vISMap;
1633 
1634   PetscFunctionBegin;
1635   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
1636   ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
1637   ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr);
1638 
1639   ierr = PetscSectionGetConstrainedStorageSize(network->edge.GlobalDofSection,&eDof);CHKERRQ(ierr);
1640   ierr = PetscSectionGetConstrainedStorageSize(network->vertex.GlobalDofSection,&vDof);CHKERRQ(ierr);
1641 
1642   ierr = MatCreate(comm, &j11);CHKERRQ(ierr);
1643   ierr = MatSetSizes(j11, eDof, eDof, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
1644   ierr = MatSetType(j11, MATMPIAIJ);CHKERRQ(ierr);
1645 
1646   ierr = MatCreate(comm, &j12);CHKERRQ(ierr);
1647   ierr = MatSetSizes(j12, eDof, vDof, PETSC_DETERMINE ,PETSC_DETERMINE);CHKERRQ(ierr);
1648   ierr = MatSetType(j12, MATMPIAIJ);CHKERRQ(ierr);
1649 
1650   ierr = MatCreate(comm, &j21);CHKERRQ(ierr);
1651   ierr = MatSetSizes(j21, vDof, eDof, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
1652   ierr = MatSetType(j21, MATMPIAIJ);CHKERRQ(ierr);
1653 
1654   ierr = MatCreate(comm, &j22);CHKERRQ(ierr);
1655   ierr = MatSetSizes(j22, vDof, vDof, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
1656   ierr = MatSetType(j22, MATMPIAIJ);CHKERRQ(ierr);
1657 
1658   bA[0][0] = j11;
1659   bA[0][1] = j12;
1660   bA[1][0] = j21;
1661   bA[1][1] = j22;
1662 
1663   ierr = CreateSubGlobalToLocalMapping_private(network->edge.GlobalDofSection,network->edge.DofSection,&eISMap);CHKERRQ(ierr);
1664   ierr = CreateSubGlobalToLocalMapping_private(network->vertex.GlobalDofSection,network->vertex.DofSection,&vISMap);CHKERRQ(ierr);
1665 
1666   ierr = MatSetLocalToGlobalMapping(j11,eISMap,eISMap);CHKERRQ(ierr);
1667   ierr = MatSetLocalToGlobalMapping(j12,eISMap,vISMap);CHKERRQ(ierr);
1668   ierr = MatSetLocalToGlobalMapping(j21,vISMap,eISMap);CHKERRQ(ierr);
1669   ierr = MatSetLocalToGlobalMapping(j22,vISMap,vISMap);CHKERRQ(ierr);
1670 
1671   ierr = MatSetUp(j11);CHKERRQ(ierr);
1672   ierr = MatSetUp(j12);CHKERRQ(ierr);
1673   ierr = MatSetUp(j21);CHKERRQ(ierr);
1674   ierr = MatSetUp(j22);CHKERRQ(ierr);
1675 
1676   ierr = MatCreateNest(comm,2,NULL,2,NULL,&bA[0][0],J);CHKERRQ(ierr);
1677   ierr = MatSetUp(*J);CHKERRQ(ierr);
1678   ierr = MatNestSetVecType(*J,VECNEST);CHKERRQ(ierr);
1679   ierr = MatDestroy(&j11);CHKERRQ(ierr);
1680   ierr = MatDestroy(&j12);CHKERRQ(ierr);
1681   ierr = MatDestroy(&j21);CHKERRQ(ierr);
1682   ierr = MatDestroy(&j22);CHKERRQ(ierr);
1683 
1684   ierr = MatAssemblyBegin(*J,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1685   ierr = MatAssemblyEnd(*J,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1686   ierr = MatSetOption(*J,MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_TRUE);CHKERRQ(ierr);
1687 
1688   /* Free structures */
1689   ierr = ISLocalToGlobalMappingDestroy(&eISMap);CHKERRQ(ierr);
1690   ierr = ISLocalToGlobalMappingDestroy(&vISMap);CHKERRQ(ierr);
1691   PetscFunctionReturn(0);
1692 }
1693 
1694 PetscErrorCode DMCreateMatrix_Network(DM dm,Mat *J)
1695 {
1696   PetscErrorCode ierr;
1697   DM_Network     *network = (DM_Network*)dm->data;
1698   PetscInt       eStart,eEnd,vStart,vEnd,rstart,nrows,*rows,localSize;
1699   PetscInt       cstart,ncols,j,e,v;
1700   PetscBool      ghost,ghost_vc,ghost2,isNest;
1701   Mat            Juser;
1702   PetscSection   sectionGlobal;
1703   PetscInt       nedges,*vptr=NULL,vc,*rows_v; /* suppress maybe-uninitialized warning */
1704   const PetscInt *edges,*cone;
1705   MPI_Comm       comm;
1706   MatType        mtype;
1707   Vec            vd_nz,vo_nz;
1708   PetscInt       *dnnz,*onnz;
1709   PetscScalar    *vdnz,*vonz;
1710 
1711   PetscFunctionBegin;
1712   mtype = dm->mattype;
1713   ierr = PetscStrcmp(mtype,MATNEST,&isNest);CHKERRQ(ierr);
1714   if (isNest) {
1715     ierr = DMCreateMatrix_Network_Nest(dm,J);CHKERRQ(ierr);
1716     PetscFunctionReturn(0);
1717   }
1718 
1719   if (!network->userEdgeJacobian && !network->userVertexJacobian) {
1720     /* user does not provide Jacobian blocks */
1721     ierr = DMCreateMatrix_Plex(network->plex,J);CHKERRQ(ierr);
1722     ierr = MatSetDM(*J,dm);CHKERRQ(ierr);
1723     PetscFunctionReturn(0);
1724   }
1725 
1726   ierr = MatCreate(PetscObjectComm((PetscObject)dm),J);CHKERRQ(ierr);
1727   ierr = DMGetGlobalSection(network->plex,&sectionGlobal);CHKERRQ(ierr);
1728   ierr = PetscSectionGetConstrainedStorageSize(sectionGlobal,&localSize);CHKERRQ(ierr);
1729   ierr = MatSetSizes(*J,localSize,localSize,PETSC_DETERMINE,PETSC_DETERMINE);CHKERRQ(ierr);
1730 
1731   ierr = MatSetType(*J,MATAIJ);CHKERRQ(ierr);
1732   ierr = MatSetFromOptions(*J);CHKERRQ(ierr);
1733 
1734   /* (1) Set matrix preallocation */
1735   /*------------------------------*/
1736   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
1737   ierr = VecCreate(comm,&vd_nz);CHKERRQ(ierr);
1738   ierr = VecSetSizes(vd_nz,localSize,PETSC_DECIDE);CHKERRQ(ierr);
1739   ierr = VecSetFromOptions(vd_nz);CHKERRQ(ierr);
1740   ierr = VecSet(vd_nz,0.0);CHKERRQ(ierr);
1741   ierr = VecDuplicate(vd_nz,&vo_nz);CHKERRQ(ierr);
1742 
1743   /* Set preallocation for edges */
1744   /*-----------------------------*/
1745   ierr = DMNetworkGetEdgeRange(dm,&eStart,&eEnd);CHKERRQ(ierr);
1746 
1747   ierr = PetscMalloc1(localSize,&rows);CHKERRQ(ierr);
1748   for (e=eStart; e<eEnd; e++) {
1749     /* Get row indices */
1750     ierr = DMNetworkGetVariableGlobalOffset(dm,e,&rstart);CHKERRQ(ierr);
1751     ierr = DMNetworkGetNumVariables(dm,e,&nrows);CHKERRQ(ierr);
1752     if (nrows) {
1753       for (j=0; j<nrows; j++) rows[j] = j + rstart;
1754 
1755       /* Set preallocation for conntected vertices */
1756       ierr = DMNetworkGetConnectedVertices(dm,e,&cone);CHKERRQ(ierr);
1757       for (v=0; v<2; v++) {
1758         ierr = DMNetworkGetNumVariables(dm,cone[v],&ncols);CHKERRQ(ierr);
1759 
1760         if (network->Je) {
1761           Juser = network->Je[3*e+1+v]; /* Jacobian(e,v) */
1762         } else Juser = NULL;
1763         ierr = DMNetworkIsGhostVertex(dm,cone[v],&ghost);CHKERRQ(ierr);
1764         ierr = MatSetPreallocationblock_private(Juser,nrows,rows,ncols,ghost,vd_nz,vo_nz);CHKERRQ(ierr);
1765       }
1766 
1767       /* Set preallocation for edge self */
1768       cstart = rstart;
1769       if (network->Je) {
1770         Juser = network->Je[3*e]; /* Jacobian(e,e) */
1771       } else Juser = NULL;
1772       ierr = MatSetPreallocationblock_private(Juser,nrows,rows,nrows,PETSC_FALSE,vd_nz,vo_nz);CHKERRQ(ierr);
1773     }
1774   }
1775 
1776   /* Set preallocation for vertices */
1777   /*--------------------------------*/
1778   ierr = DMNetworkGetVertexRange(dm,&vStart,&vEnd);CHKERRQ(ierr);
1779   if (vEnd - vStart) vptr = network->Jvptr;
1780 
1781   for (v=vStart; v<vEnd; v++) {
1782     /* Get row indices */
1783     ierr = DMNetworkGetVariableGlobalOffset(dm,v,&rstart);CHKERRQ(ierr);
1784     ierr = DMNetworkGetNumVariables(dm,v,&nrows);CHKERRQ(ierr);
1785     if (!nrows) continue;
1786 
1787     ierr = DMNetworkIsGhostVertex(dm,v,&ghost);CHKERRQ(ierr);
1788     if (ghost) {
1789       ierr = PetscMalloc1(nrows,&rows_v);CHKERRQ(ierr);
1790     } else {
1791       rows_v = rows;
1792     }
1793 
1794     for (j=0; j<nrows; j++) rows_v[j] = j + rstart;
1795 
1796     /* Get supporting edges and connected vertices */
1797     ierr = DMNetworkGetSupportingEdges(dm,v,&nedges,&edges);CHKERRQ(ierr);
1798 
1799     for (e=0; e<nedges; e++) {
1800       /* Supporting edges */
1801       ierr = DMNetworkGetVariableGlobalOffset(dm,edges[e],&cstart);CHKERRQ(ierr);
1802       ierr = DMNetworkGetNumVariables(dm,edges[e],&ncols);CHKERRQ(ierr);
1803 
1804       if (network->Jv) {
1805         Juser = network->Jv[vptr[v-vStart]+2*e+1]; /* Jacobian(v,e) */
1806       } else Juser = NULL;
1807       ierr = MatSetPreallocationblock_private(Juser,nrows,rows_v,ncols,ghost,vd_nz,vo_nz);CHKERRQ(ierr);
1808 
1809       /* Connected vertices */
1810       ierr = DMNetworkGetConnectedVertices(dm,edges[e],&cone);CHKERRQ(ierr);
1811       vc = (v == cone[0]) ? cone[1]:cone[0];
1812       ierr = DMNetworkIsGhostVertex(dm,vc,&ghost_vc);CHKERRQ(ierr);
1813 
1814       ierr = DMNetworkGetNumVariables(dm,vc,&ncols);CHKERRQ(ierr);
1815 
1816       if (network->Jv) {
1817         Juser = network->Jv[vptr[v-vStart]+2*e+2]; /* Jacobian(v,vc) */
1818       } else Juser = NULL;
1819       if (ghost_vc||ghost) {
1820         ghost2 = PETSC_TRUE;
1821       } else {
1822         ghost2 = PETSC_FALSE;
1823       }
1824       ierr = MatSetPreallocationblock_private(Juser,nrows,rows_v,ncols,ghost2,vd_nz,vo_nz);CHKERRQ(ierr);
1825     }
1826 
1827     /* Set preallocation for vertex self */
1828     ierr = DMNetworkIsGhostVertex(dm,v,&ghost);CHKERRQ(ierr);
1829     if (!ghost) {
1830       ierr = DMNetworkGetVariableGlobalOffset(dm,v,&cstart);CHKERRQ(ierr);
1831       if (network->Jv) {
1832         Juser = network->Jv[vptr[v-vStart]]; /* Jacobian(v,v) */
1833       } else Juser = NULL;
1834       ierr = MatSetPreallocationblock_private(Juser,nrows,rows_v,nrows,PETSC_FALSE,vd_nz,vo_nz);CHKERRQ(ierr);
1835     }
1836     if (ghost) {
1837       ierr = PetscFree(rows_v);CHKERRQ(ierr);
1838     }
1839   }
1840 
1841   ierr = VecAssemblyBegin(vd_nz);CHKERRQ(ierr);
1842   ierr = VecAssemblyBegin(vo_nz);CHKERRQ(ierr);
1843 
1844   ierr = PetscMalloc2(localSize,&dnnz,localSize,&onnz);CHKERRQ(ierr);
1845 
1846   ierr = VecAssemblyEnd(vd_nz);CHKERRQ(ierr);
1847   ierr = VecAssemblyEnd(vo_nz);CHKERRQ(ierr);
1848 
1849   ierr = VecGetArray(vd_nz,&vdnz);CHKERRQ(ierr);
1850   ierr = VecGetArray(vo_nz,&vonz);CHKERRQ(ierr);
1851   for (j=0; j<localSize; j++) {
1852     dnnz[j] = (PetscInt)PetscRealPart(vdnz[j]);
1853     onnz[j] = (PetscInt)PetscRealPart(vonz[j]);
1854   }
1855   ierr = VecRestoreArray(vd_nz,&vdnz);CHKERRQ(ierr);
1856   ierr = VecRestoreArray(vo_nz,&vonz);CHKERRQ(ierr);
1857   ierr = VecDestroy(&vd_nz);CHKERRQ(ierr);
1858   ierr = VecDestroy(&vo_nz);CHKERRQ(ierr);
1859 
1860   ierr = MatSeqAIJSetPreallocation(*J,0,dnnz);CHKERRQ(ierr);
1861   ierr = MatMPIAIJSetPreallocation(*J,0,dnnz,0,onnz);CHKERRQ(ierr);
1862   ierr = MatSetOption(*J,MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_TRUE);CHKERRQ(ierr);
1863 
1864   ierr = PetscFree2(dnnz,onnz);CHKERRQ(ierr);
1865 
1866   /* (2) Set matrix entries for edges */
1867   /*----------------------------------*/
1868   for (e=eStart; e<eEnd; e++) {
1869     /* Get row indices */
1870     ierr = DMNetworkGetVariableGlobalOffset(dm,e,&rstart);CHKERRQ(ierr);
1871     ierr = DMNetworkGetNumVariables(dm,e,&nrows);CHKERRQ(ierr);
1872     if (nrows) {
1873       for (j=0; j<nrows; j++) rows[j] = j + rstart;
1874 
1875       /* Set matrix entries for conntected vertices */
1876       ierr = DMNetworkGetConnectedVertices(dm,e,&cone);CHKERRQ(ierr);
1877       for (v=0; v<2; v++) {
1878         ierr = DMNetworkGetVariableGlobalOffset(dm,cone[v],&cstart);CHKERRQ(ierr);
1879         ierr = DMNetworkGetNumVariables(dm,cone[v],&ncols);CHKERRQ(ierr);
1880 
1881         if (network->Je) {
1882           Juser = network->Je[3*e+1+v]; /* Jacobian(e,v) */
1883         } else Juser = NULL;
1884         ierr = MatSetblock_private(Juser,nrows,rows,ncols,cstart,J);CHKERRQ(ierr);
1885       }
1886 
1887       /* Set matrix entries for edge self */
1888       cstart = rstart;
1889       if (network->Je) {
1890         Juser = network->Je[3*e]; /* Jacobian(e,e) */
1891       } else Juser = NULL;
1892       ierr = MatSetblock_private(Juser,nrows,rows,nrows,cstart,J);CHKERRQ(ierr);
1893     }
1894   }
1895 
1896   /* Set matrix entries for vertices */
1897   /*---------------------------------*/
1898   for (v=vStart; v<vEnd; v++) {
1899     /* Get row indices */
1900     ierr = DMNetworkGetVariableGlobalOffset(dm,v,&rstart);CHKERRQ(ierr);
1901     ierr = DMNetworkGetNumVariables(dm,v,&nrows);CHKERRQ(ierr);
1902     if (!nrows) continue;
1903 
1904     ierr = DMNetworkIsGhostVertex(dm,v,&ghost);CHKERRQ(ierr);
1905     if (ghost) {
1906       ierr = PetscMalloc1(nrows,&rows_v);CHKERRQ(ierr);
1907     } else {
1908       rows_v = rows;
1909     }
1910     for (j=0; j<nrows; j++) rows_v[j] = j + rstart;
1911 
1912     /* Get supporting edges and connected vertices */
1913     ierr = DMNetworkGetSupportingEdges(dm,v,&nedges,&edges);CHKERRQ(ierr);
1914 
1915     for (e=0; e<nedges; e++) {
1916       /* Supporting edges */
1917       ierr = DMNetworkGetVariableGlobalOffset(dm,edges[e],&cstart);CHKERRQ(ierr);
1918       ierr = DMNetworkGetNumVariables(dm,edges[e],&ncols);CHKERRQ(ierr);
1919 
1920       if (network->Jv) {
1921         Juser = network->Jv[vptr[v-vStart]+2*e+1]; /* Jacobian(v,e) */
1922       } else Juser = NULL;
1923       ierr = MatSetblock_private(Juser,nrows,rows_v,ncols,cstart,J);CHKERRQ(ierr);
1924 
1925       /* Connected vertices */
1926       ierr = DMNetworkGetConnectedVertices(dm,edges[e],&cone);CHKERRQ(ierr);
1927       vc = (v == cone[0]) ? cone[1]:cone[0];
1928 
1929       ierr = DMNetworkGetVariableGlobalOffset(dm,vc,&cstart);CHKERRQ(ierr);
1930       ierr = DMNetworkGetNumVariables(dm,vc,&ncols);CHKERRQ(ierr);
1931 
1932       if (network->Jv) {
1933         Juser = network->Jv[vptr[v-vStart]+2*e+2]; /* Jacobian(v,vc) */
1934       } else Juser = NULL;
1935       ierr = MatSetblock_private(Juser,nrows,rows_v,ncols,cstart,J);CHKERRQ(ierr);
1936     }
1937 
1938     /* Set matrix entries for vertex self */
1939     if (!ghost) {
1940       ierr = DMNetworkGetVariableGlobalOffset(dm,v,&cstart);CHKERRQ(ierr);
1941       if (network->Jv) {
1942         Juser = network->Jv[vptr[v-vStart]]; /* Jacobian(v,v) */
1943       } else Juser = NULL;
1944       ierr = MatSetblock_private(Juser,nrows,rows_v,nrows,cstart,J);CHKERRQ(ierr);
1945     }
1946     if (ghost) {
1947       ierr = PetscFree(rows_v);CHKERRQ(ierr);
1948     }
1949   }
1950   ierr = PetscFree(rows);CHKERRQ(ierr);
1951 
1952   ierr = MatAssemblyBegin(*J,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1953   ierr = MatAssemblyEnd(*J,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1954 
1955   ierr = MatSetDM(*J,dm);CHKERRQ(ierr);
1956   PetscFunctionReturn(0);
1957 }
1958 
1959 PetscErrorCode DMDestroy_Network(DM dm)
1960 {
1961   PetscErrorCode ierr;
1962   DM_Network     *network = (DM_Network*)dm->data;
1963   PetscInt       j;
1964 
1965   PetscFunctionBegin;
1966   if (--network->refct > 0) PetscFunctionReturn(0);
1967   if (network->Je) {
1968     ierr = PetscFree(network->Je);CHKERRQ(ierr);
1969   }
1970   if (network->Jv) {
1971     ierr = PetscFree(network->Jvptr);CHKERRQ(ierr);
1972     ierr = PetscFree(network->Jv);CHKERRQ(ierr);
1973   }
1974 
1975   ierr = ISLocalToGlobalMappingDestroy(&network->vertex.mapping);CHKERRQ(ierr);
1976   ierr = PetscSectionDestroy(&network->vertex.DofSection);CHKERRQ(ierr);
1977   ierr = PetscSectionDestroy(&network->vertex.GlobalDofSection);CHKERRQ(ierr);
1978   if (network->vltog) {
1979     ierr = PetscFree(network->vltog);CHKERRQ(ierr);
1980   }
1981   if (network->vertex.sf) {
1982     ierr = PetscSFDestroy(&network->vertex.sf);CHKERRQ(ierr);
1983   }
1984   /* edge */
1985   ierr = ISLocalToGlobalMappingDestroy(&network->edge.mapping);CHKERRQ(ierr);
1986   ierr = PetscSectionDestroy(&network->edge.DofSection);CHKERRQ(ierr);
1987   ierr = PetscSectionDestroy(&network->edge.GlobalDofSection);CHKERRQ(ierr);
1988   if (network->edge.sf) {
1989     ierr = PetscSFDestroy(&network->edge.sf);CHKERRQ(ierr);
1990   }
1991   ierr = DMDestroy(&network->plex);CHKERRQ(ierr);
1992   ierr = PetscSectionDestroy(&network->DataSection);CHKERRQ(ierr);
1993   ierr = PetscSectionDestroy(&network->DofSection);CHKERRQ(ierr);
1994 
1995   for(j=0; j<network->nsubnet; j++) {
1996     ierr = PetscFree(network->subnet[j].edges);CHKERRQ(ierr);
1997   }
1998   ierr = PetscFree(network->subnetvtx);CHKERRQ(ierr);
1999 
2000   ierr = PetscFree(network->subnet);CHKERRQ(ierr);
2001   ierr = PetscFree(network->componentdataarray);CHKERRQ(ierr);
2002   ierr = PetscFree2(network->header,network->cvalue);CHKERRQ(ierr);
2003   ierr = PetscFree(network);CHKERRQ(ierr);
2004   PetscFunctionReturn(0);
2005 }
2006 
2007 PetscErrorCode DMView_Network(DM dm,PetscViewer viewer)
2008 {
2009   PetscErrorCode ierr;
2010   DM_Network     *network = (DM_Network*)dm->data;
2011   PetscBool      iascii;
2012   PetscMPIInt    rank;
2013   PetscInt       p,nsubnet;
2014 
2015   PetscFunctionBegin;
2016   if (!dm->setupcalled) SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE,"Must call DMSetUp() first");
2017   ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm),&rank);CHKERRQ(ierr);
2018   PetscValidHeaderSpecific(dm,DM_CLASSID, 1);
2019   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2020   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii);CHKERRQ(ierr);
2021   if (iascii) {
2022     const PetscInt    *cone,*vtx,*edges;
2023     PetscInt          vfrom,vto,i,j,nv,ne;
2024 
2025     nsubnet = network->nsubnet - network->ncsubnet; /* num of subnetworks */
2026     ierr = PetscViewerASCIIPushSynchronized(viewer);CHKERRQ(ierr);
2027     ierr = PetscViewerASCIISynchronizedPrintf(viewer, "  [%d] nsubnet: %D; nsubnetCouple: %D; nEdges: %D; nVertices: %D\n",rank,nsubnet,network->ncsubnet,network->nEdges,network->nVertices);CHKERRQ(ierr);
2028 
2029     for (i=0; i<nsubnet; i++) {
2030       ierr = DMNetworkGetSubnetworkInfo(dm,i,&nv,&ne,&vtx,&edges);CHKERRQ(ierr);
2031       if (ne) {
2032         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "     Subnet %D: nEdges %D, nVertices %D\n",i,ne,nv);CHKERRQ(ierr);
2033         for (j=0; j<ne; j++) {
2034           p = edges[j];
2035           ierr = DMNetworkGetConnectedVertices(dm,p,&cone);CHKERRQ(ierr);
2036           ierr = DMNetworkGetGlobalVertexIndex(dm,cone[0],&vfrom);CHKERRQ(ierr);
2037           ierr = DMNetworkGetGlobalVertexIndex(dm,cone[1],&vto);CHKERRQ(ierr);
2038           ierr = DMNetworkGetGlobalEdgeIndex(dm,edges[j],&p);CHKERRQ(ierr);
2039           ierr = PetscViewerASCIISynchronizedPrintf(viewer, "       edge %D: %D----> %D\n",p,vfrom,vto);CHKERRQ(ierr);
2040         }
2041       }
2042     }
2043     /* Coupling subnets */
2044     nsubnet = network->nsubnet;
2045     for (; i<nsubnet; i++) {
2046       ierr = DMNetworkGetSubnetworkInfo(dm,i,&nv,&ne,&vtx,&edges);CHKERRQ(ierr);
2047       if (ne) {
2048         ierr = PetscViewerASCIISynchronizedPrintf(viewer, "     Subnet %D (couple): nEdges %D, nVertices %D\n",i,ne,nv);CHKERRQ(ierr);
2049         for (j=0; j<ne; j++) {
2050           p = edges[j];
2051           ierr = DMNetworkGetConnectedVertices(dm,p,&cone);CHKERRQ(ierr);
2052           ierr = DMNetworkGetGlobalVertexIndex(dm,cone[0],&vfrom);CHKERRQ(ierr);
2053           ierr = DMNetworkGetGlobalVertexIndex(dm,cone[1],&vto);CHKERRQ(ierr);
2054           ierr = PetscViewerASCIISynchronizedPrintf(viewer, "       edge %D: %D----> %D\n",p,vfrom,vto);CHKERRQ(ierr);
2055         }
2056       }
2057     }
2058     ierr = PetscViewerFlush(viewer);CHKERRQ(ierr);
2059     ierr = PetscViewerASCIIPopSynchronized(viewer);CHKERRQ(ierr);
2060   } else SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "Viewer type %s not yet supported for DMNetwork writing", ((PetscObject)viewer)->type_name);
2061   PetscFunctionReturn(0);
2062 }
2063 
2064 PetscErrorCode DMGlobalToLocalBegin_Network(DM dm, Vec g, InsertMode mode, Vec l)
2065 {
2066   PetscErrorCode ierr;
2067   DM_Network     *network = (DM_Network*)dm->data;
2068 
2069   PetscFunctionBegin;
2070   ierr = DMGlobalToLocalBegin(network->plex,g,mode,l);CHKERRQ(ierr);
2071   PetscFunctionReturn(0);
2072 }
2073 
2074 PetscErrorCode DMGlobalToLocalEnd_Network(DM dm, Vec g, InsertMode mode, Vec l)
2075 {
2076   PetscErrorCode ierr;
2077   DM_Network     *network = (DM_Network*)dm->data;
2078 
2079   PetscFunctionBegin;
2080   ierr = DMGlobalToLocalEnd(network->plex,g,mode,l);CHKERRQ(ierr);
2081   PetscFunctionReturn(0);
2082 }
2083 
2084 PetscErrorCode DMLocalToGlobalBegin_Network(DM dm, Vec l, InsertMode mode, Vec g)
2085 {
2086   PetscErrorCode ierr;
2087   DM_Network     *network = (DM_Network*)dm->data;
2088 
2089   PetscFunctionBegin;
2090   ierr = DMLocalToGlobalBegin(network->plex,l,mode,g);CHKERRQ(ierr);
2091   PetscFunctionReturn(0);
2092 }
2093 
2094 PetscErrorCode DMLocalToGlobalEnd_Network(DM dm, Vec l, InsertMode mode, Vec g)
2095 {
2096   PetscErrorCode ierr;
2097   DM_Network     *network = (DM_Network*)dm->data;
2098 
2099   PetscFunctionBegin;
2100   ierr = DMLocalToGlobalEnd(network->plex,l,mode,g);CHKERRQ(ierr);
2101   PetscFunctionReturn(0);
2102 }
2103 
2104 /*@
2105   DMNetworkSetVertexLocalToGlobalOrdering - Create and setup vertex local to globle map
2106 
2107   Not collective
2108 
2109   Input Parameters
2110 + dm - the dm object
2111 - vloc - local vertex ordering, start from 0
2112 
2113   Output Parameters
2114 +  vg  - global vertex ordering, start from 0
2115 
2116   Level: Advanced
2117 
2118 .seealso: DMNetworkSetVertexLocalToGlobalOrdering()
2119 @*/
2120 PetscErrorCode DMNetworkGetVertexLocalToGlobalOrdering(DM dm,PetscInt vloc,PetscInt *vg)
2121 {
2122   DM_Network  *network = (DM_Network*)dm->data;
2123   PetscInt    *vltog = network->vltog;
2124 
2125   PetscFunctionBegin;
2126   if (!vltog) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_WRONGSTATE,"Must call DMNetworkSetVertexLocalToGlobalOrdering() first");
2127   *vg = vltog[vloc];
2128   PetscFunctionReturn(0);
2129 }
2130 
2131 /*@
2132   DMNetworkSetVertexLocalToGlobalOrdering - Create and setup vertex local to globle map
2133 
2134   Collective
2135 
2136   Input Parameters:
2137 + dm - the dm object
2138 
2139   Level: Advanced
2140 
2141 .seealso: DMNetworkCreate()
2142 @*/
2143 PetscErrorCode DMNetworkSetVertexLocalToGlobalOrdering(DM dm)
2144 {
2145   PetscErrorCode    ierr;
2146   DM_Network        *network=(DM_Network*)dm->data;
2147   MPI_Comm          comm;
2148   PetscMPIInt       rank,size,*displs,*recvcounts;
2149   PetscBool         ghost;
2150   PetscInt          *vltog,nroots,nleaves,i,*vrange,k=0,kg=0;
2151   const PetscSFNode *iremote;
2152   PetscSF           vsf;
2153 
2154   PetscFunctionBegin;
2155   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
2156   ierr = MPI_Comm_size(comm, &size);CHKERRQ(ierr);
2157 
2158   if (size == 1) {
2159     nroots = network->vEnd - network->vStart;
2160     ierr = PetscMalloc1(nroots, &vltog);CHKERRQ(ierr);
2161     for (i=0; i<nroots; i++) vltog[i] = i;
2162     network->vltog = vltog;
2163     PetscFunctionReturn(0);
2164   }
2165 
2166   if (!network->distributecalled) SETERRQ(comm, PETSC_ERR_ARG_WRONGSTATE,"Must call DMNetworkDistribute() first");
2167   if (network->vltog) {
2168     ierr = PetscFree(network->vltog);CHKERRQ(ierr);
2169   }
2170 
2171   ierr = DMNetworkSetSubMap_private(network->vStart,network->vEnd,&network->vertex.mapping);CHKERRQ(ierr);
2172   ierr = PetscSFGetSubSF(network->plex->sf, network->vertex.mapping, &network->vertex.sf);CHKERRQ(ierr);
2173   vsf = network->vertex.sf;
2174 
2175   ierr = PetscMalloc3(size+1,&vrange,size+1,&displs,size,&recvcounts);CHKERRQ(ierr);
2176   ierr = PetscSFGetGraph(vsf,&nroots,&nleaves,NULL,&iremote);CHKERRQ(ierr);
2177 
2178   for (i=0; i<size; i++) { displs[i] = i; recvcounts[i] = 1;}
2179 
2180   i         = nroots - nleaves; /* local number of vertices, excluding ghosts */
2181   vrange[0] = 0;
2182   ierr = MPI_Allgatherv(&i,1,MPIU_INT,vrange+1,recvcounts,displs,MPIU_INT,comm);CHKERRQ(ierr);
2183   for (i=2; i<size+1; i++) {vrange[i] += vrange[i-1];}
2184 
2185   ierr = PetscMalloc1(nroots, &vltog);CHKERRQ(ierr);
2186   network->vltog = vltog;
2187 
2188   ierr = MPI_Comm_rank(comm, &rank);CHKERRQ(ierr);
2189   for (i=0; i<nroots; i++) {
2190     ierr = DMNetworkIsGhostVertex(dm,i+network->vStart,&ghost);CHKERRQ(ierr);
2191     if (!ghost) {
2192       vltog[i] = vrange[rank] + k; k++;
2193     } else {
2194       vltog[i] = vrange[iremote[kg].rank] + iremote[kg].index; kg++;
2195     }
2196   }
2197   ierr = PetscFree3(vrange,displs,recvcounts);CHKERRQ(ierr);
2198   PetscFunctionReturn(0);
2199 }
2200