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