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