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