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