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