xref: /petsc/src/dm/impls/network/network.c (revision 95c0884e6f7665b705eebf88174e89dc920c2fc0)
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   PetscInt       nVertices = network->nVertices;
1279 
1280   PetscFunctionBegin;
1281   network->userEdgeJacobian   = eflg;
1282   network->userVertexJacobian = vflg;
1283 
1284   if (eflg && !network->Je) {
1285     ierr = PetscCalloc1(3*network->nEdges,&network->Je);CHKERRQ(ierr);
1286   }
1287 
1288   if (vflg && !network->Jv && nVertices) {
1289     PetscInt       i,*vptr,nedges,vStart=network->vStart;
1290     PetscInt       nedges_total;
1291     const PetscInt *edges;
1292 
1293     /* count nvertex_total */
1294     nedges_total = 0;
1295     ierr = PetscMalloc1(nVertices+1,&vptr);CHKERRQ(ierr);
1296 
1297     vptr[0] = 0;
1298     for (i=0; i<nVertices; i++) {
1299       ierr = DMNetworkGetSupportingEdges(dm,i+vStart,&nedges,&edges);CHKERRQ(ierr);
1300       nedges_total += nedges;
1301       vptr[i+1] = vptr[i] + 2*nedges + 1;
1302     }
1303 
1304     ierr = PetscCalloc1(2*nedges_total+nVertices,&network->Jv);CHKERRQ(ierr);
1305     network->Jvptr = vptr;
1306   }
1307   PetscFunctionReturn(0);
1308 }
1309 
1310 /*@
1311     DMNetworkEdgeSetMatrix - Sets user-provided Jacobian matrices for this edge to the network
1312 
1313     Not Collective
1314 
1315     Input Parameters:
1316 +   dm - The DMNetwork object
1317 .   p  - the edge point
1318 -   J - array (size = 3) of Jacobian submatrices for this edge point:
1319         J[0]: this edge
1320         J[1] and J[2]: connected vertices, obtained by calling DMNetworkGetConnectedVertices()
1321 
1322     Level: intermediate
1323 
1324 .seealso: DMNetworkVertexSetMatrix
1325 @*/
1326 PetscErrorCode DMNetworkEdgeSetMatrix(DM dm,PetscInt p,Mat J[])
1327 {
1328   DM_Network     *network=(DM_Network*)dm->data;
1329 
1330   PetscFunctionBegin;
1331   if (!network->Je) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ORDER,"Must call DMNetworkHasJacobian() collectively before calling DMNetworkEdgeSetMatrix");
1332 
1333   if (J) {
1334     network->Je[3*p]   = J[0];
1335     network->Je[3*p+1] = J[1];
1336     network->Je[3*p+2] = J[2];
1337   }
1338   PetscFunctionReturn(0);
1339 }
1340 
1341 /*@
1342     DMNetworkVertexSetMatrix - Sets user-provided Jacobian matrix for this vertex to the network
1343 
1344     Not Collective
1345 
1346     Input Parameters:
1347 +   dm - The DMNetwork object
1348 .   p  - the vertex point
1349 -   J - array of Jacobian (size = 2*(num of supporting edges) + 1) submatrices for this vertex point:
1350         J[0]:       this vertex
1351         J[1+2*i]:   i-th supporting edge
1352         J[1+2*i+1]: i-th connected vertex
1353 
1354     Level: intermediate
1355 
1356 .seealso: DMNetworkEdgeSetMatrix
1357 @*/
1358 PetscErrorCode DMNetworkVertexSetMatrix(DM dm,PetscInt p,Mat J[])
1359 {
1360   PetscErrorCode ierr;
1361   DM_Network     *network=(DM_Network*)dm->data;
1362   PetscInt       i,*vptr,nedges,vStart=network->vStart;
1363   const PetscInt *edges;
1364 
1365   PetscFunctionBegin;
1366   if (!network->Jv) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ORDER,"Must call DMNetworkHasJacobian() collectively before calling DMNetworkVertexSetMatrix");
1367 
1368   if (J) {
1369     vptr = network->Jvptr;
1370     network->Jv[vptr[p-vStart]] = J[0]; /* Set Jacobian for this vertex */
1371 
1372     /* Set Jacobian for each supporting edge and connected vertex */
1373     ierr = DMNetworkGetSupportingEdges(dm,p,&nedges,&edges);CHKERRQ(ierr);
1374     for (i=1; i<=2*nedges; i++) network->Jv[vptr[p-vStart]+i] = J[i];
1375   }
1376   PetscFunctionReturn(0);
1377 }
1378 
1379 PETSC_STATIC_INLINE PetscErrorCode MatSetPreallocationDenseblock_private(PetscInt nrows,PetscInt *rows,PetscInt ncols,PetscBool ghost,Vec vdnz,Vec vonz)
1380 {
1381   PetscErrorCode ierr;
1382   PetscInt       j;
1383   PetscScalar    val=(PetscScalar)ncols;
1384 
1385   PetscFunctionBegin;
1386   if (!ghost) {
1387     for (j=0; j<nrows; j++) {
1388       ierr = VecSetValues(vdnz,1,&rows[j],&val,ADD_VALUES);CHKERRQ(ierr);
1389     }
1390   } else {
1391     for (j=0; j<nrows; j++) {
1392       ierr = VecSetValues(vonz,1,&rows[j],&val,ADD_VALUES);CHKERRQ(ierr);
1393     }
1394   }
1395   PetscFunctionReturn(0);
1396 }
1397 
1398 PETSC_STATIC_INLINE PetscErrorCode MatSetPreallocationUserblock_private(Mat Ju,PetscInt nrows,PetscInt *rows,PetscInt ncols,PetscBool ghost,Vec vdnz,Vec vonz)
1399 {
1400   PetscErrorCode ierr;
1401   PetscInt       j,ncols_u;
1402   PetscScalar    val;
1403 
1404   PetscFunctionBegin;
1405   if (!ghost) {
1406     for (j=0; j<nrows; j++) {
1407       ierr = MatGetRow(Ju,j,&ncols_u,NULL,NULL);CHKERRQ(ierr);
1408       val = (PetscScalar)ncols_u;
1409       ierr = VecSetValues(vdnz,1,&rows[j],&val,ADD_VALUES);CHKERRQ(ierr);
1410       ierr = MatRestoreRow(Ju,j,&ncols_u,NULL,NULL);CHKERRQ(ierr);
1411     }
1412   } else {
1413     for (j=0; j<nrows; j++) {
1414       ierr = MatGetRow(Ju,j,&ncols_u,NULL,NULL);CHKERRQ(ierr);
1415       val = (PetscScalar)ncols_u;
1416       ierr = VecSetValues(vonz,1,&rows[j],&val,ADD_VALUES);CHKERRQ(ierr);
1417       ierr = MatRestoreRow(Ju,j,&ncols_u,NULL,NULL);CHKERRQ(ierr);
1418     }
1419   }
1420   PetscFunctionReturn(0);
1421 }
1422 
1423 PETSC_STATIC_INLINE PetscErrorCode MatSetPreallocationblock_private(Mat Ju,PetscInt nrows,PetscInt *rows,PetscInt ncols,PetscBool ghost,Vec vdnz,Vec vonz)
1424 {
1425   PetscErrorCode ierr;
1426 
1427   PetscFunctionBegin;
1428   if (Ju) {
1429     ierr = MatSetPreallocationUserblock_private(Ju,nrows,rows,ncols,ghost,vdnz,vonz);CHKERRQ(ierr);
1430   } else {
1431     ierr = MatSetPreallocationDenseblock_private(nrows,rows,ncols,ghost,vdnz,vonz);CHKERRQ(ierr);
1432   }
1433   PetscFunctionReturn(0);
1434 }
1435 
1436 PETSC_STATIC_INLINE PetscErrorCode MatSetDenseblock_private(PetscInt nrows,PetscInt *rows,PetscInt ncols,PetscInt cstart,Mat *J)
1437 {
1438   PetscErrorCode ierr;
1439   PetscInt       j,*cols;
1440   PetscScalar    *zeros;
1441 
1442   PetscFunctionBegin;
1443   ierr = PetscCalloc2(ncols,&cols,nrows*ncols,&zeros);CHKERRQ(ierr);
1444   for (j=0; j<ncols; j++) cols[j] = j+ cstart;
1445   ierr = MatSetValues(*J,nrows,rows,ncols,cols,zeros,INSERT_VALUES);CHKERRQ(ierr);
1446   ierr = PetscFree2(cols,zeros);CHKERRQ(ierr);
1447   PetscFunctionReturn(0);
1448 }
1449 
1450 PETSC_STATIC_INLINE PetscErrorCode MatSetUserblock_private(Mat Ju,PetscInt nrows,PetscInt *rows,PetscInt ncols,PetscInt cstart,Mat *J)
1451 {
1452   PetscErrorCode ierr;
1453   PetscInt       j,M,N,row,col,ncols_u;
1454   const PetscInt *cols;
1455   PetscScalar    zero=0.0;
1456 
1457   PetscFunctionBegin;
1458   ierr = MatGetSize(Ju,&M,&N);CHKERRQ(ierr);
1459   if (nrows != M || ncols != N) SETERRQ4(PetscObjectComm((PetscObject)Ju),PETSC_ERR_USER,"%D by %D must equal %D by %D",nrows,ncols,M,N);
1460 
1461   for (row=0; row<nrows; row++) {
1462     ierr = MatGetRow(Ju,row,&ncols_u,&cols,NULL);CHKERRQ(ierr);
1463     for (j=0; j<ncols_u; j++) {
1464       col = cols[j] + cstart;
1465       ierr = MatSetValues(*J,1,&rows[row],1,&col,&zero,INSERT_VALUES);CHKERRQ(ierr);
1466     }
1467     ierr = MatRestoreRow(Ju,row,&ncols_u,&cols,NULL);CHKERRQ(ierr);
1468   }
1469   PetscFunctionReturn(0);
1470 }
1471 
1472 PETSC_STATIC_INLINE PetscErrorCode MatSetblock_private(Mat Ju,PetscInt nrows,PetscInt *rows,PetscInt ncols,PetscInt cstart,Mat *J)
1473 {
1474   PetscErrorCode ierr;
1475 
1476   PetscFunctionBegin;
1477   if (Ju) {
1478     ierr = MatSetUserblock_private(Ju,nrows,rows,ncols,cstart,J);CHKERRQ(ierr);
1479   } else {
1480     ierr = MatSetDenseblock_private(nrows,rows,ncols,cstart,J);CHKERRQ(ierr);
1481   }
1482   PetscFunctionReturn(0);
1483 }
1484 
1485 /* 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.
1486 */
1487 PetscErrorCode CreateSubGlobalToLocalMapping_private(PetscSection globalsec, PetscSection localsec, ISLocalToGlobalMapping *ltog)
1488 {
1489   PetscErrorCode ierr;
1490   PetscInt       i, size, dof;
1491   PetscInt       *glob2loc;
1492 
1493   PetscFunctionBegin;
1494   ierr = PetscSectionGetStorageSize(localsec,&size);CHKERRQ(ierr);
1495   ierr = PetscMalloc1(size,&glob2loc);CHKERRQ(ierr);
1496 
1497   for (i = 0; i < size; i++) {
1498     ierr = PetscSectionGetOffset(globalsec,i,&dof);CHKERRQ(ierr);
1499     dof = (dof >= 0) ? dof : -(dof + 1);
1500     glob2loc[i] = dof;
1501   }
1502 
1503   ierr = ISLocalToGlobalMappingCreate(PETSC_COMM_WORLD,1,size,glob2loc,PETSC_OWN_POINTER,ltog);CHKERRQ(ierr);
1504 #if 0
1505   ierr = PetscIntView(size,glob2loc,PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
1506 #endif
1507   PetscFunctionReturn(0);
1508 }
1509 
1510 #include <petsc/private/matimpl.h>
1511 PetscErrorCode DMCreateMatrix_Network(DM dm,Mat *J)
1512 {
1513   PetscErrorCode ierr;
1514   PetscMPIInt    rank, size;
1515   DM_Network     *network = (DM_Network*)dm->data;
1516   PetscInt       eStart,eEnd,vStart,vEnd,rstart,nrows,*rows,localSize;
1517   PetscInt       cstart,ncols,j,e,v;
1518   PetscBool      ghost,ghost_vc,ghost2,isNest;
1519   Mat            Juser;
1520   PetscSection   sectionGlobal;
1521   PetscInt       nedges,*vptr=NULL,vc,*rows_v; /* suppress maybe-uninitialized warning */
1522   const PetscInt *edges,*cone;
1523   MPI_Comm       comm;
1524   MatType        mtype;
1525   Vec            vd_nz,vo_nz;
1526   PetscInt       *dnnz,*onnz;
1527   PetscScalar    *vdnz,*vonz;
1528 
1529   PetscFunctionBegin;
1530   mtype = dm->mattype;
1531   ierr = PetscStrcmp(mtype, MATNEST, &isNest);CHKERRQ(ierr);
1532 
1533   if (isNest) {
1534     /* ierr = DMCreateMatrix_Network_Nest(); */
1535     PetscInt   eDof, vDof;
1536     Mat        j11, j12, j21, j22, bA[2][2];
1537     ISLocalToGlobalMapping eISMap, vISMap;
1538 
1539     ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
1540     ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
1541     ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr);
1542 
1543     ierr = PetscSectionGetConstrainedStorageSize(network->edge.GlobalDofSection,&eDof);CHKERRQ(ierr);
1544     ierr = PetscSectionGetConstrainedStorageSize(network->vertex.GlobalDofSection,&vDof);CHKERRQ(ierr);
1545 
1546     ierr = MatCreate(comm, &j11);CHKERRQ(ierr);
1547     ierr = MatSetSizes(j11, eDof, eDof, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
1548     ierr = MatSetType(j11, MATMPIAIJ);CHKERRQ(ierr);
1549 
1550     ierr = MatCreate(comm, &j12);CHKERRQ(ierr);
1551     ierr = MatSetSizes(j12, eDof, vDof, PETSC_DETERMINE ,PETSC_DETERMINE);CHKERRQ(ierr);
1552     ierr = MatSetType(j12, MATMPIAIJ);CHKERRQ(ierr);
1553 
1554     ierr = MatCreate(comm, &j21);CHKERRQ(ierr);
1555     ierr = MatSetSizes(j21, vDof, eDof, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
1556     ierr = MatSetType(j21, MATMPIAIJ);CHKERRQ(ierr);
1557 
1558     ierr = MatCreate(comm, &j22);CHKERRQ(ierr);
1559     ierr = MatSetSizes(j22, vDof, vDof, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
1560     ierr = MatSetType(j22, MATMPIAIJ);CHKERRQ(ierr);
1561 
1562     bA[0][0] = j11;
1563     bA[0][1] = j12;
1564     bA[1][0] = j21;
1565     bA[1][1] = j22;
1566 
1567     ierr = CreateSubGlobalToLocalMapping_private(network->edge.GlobalDofSection,network->edge.DofSection,&eISMap);CHKERRQ(ierr);
1568     ierr = CreateSubGlobalToLocalMapping_private(network->vertex.GlobalDofSection,network->vertex.DofSection,&vISMap);CHKERRQ(ierr);
1569 
1570     ierr = MatSetLocalToGlobalMapping(j11,eISMap,eISMap);CHKERRQ(ierr);
1571     ierr = MatSetLocalToGlobalMapping(j12,eISMap,vISMap);CHKERRQ(ierr);
1572     ierr = MatSetLocalToGlobalMapping(j21,vISMap,eISMap);CHKERRQ(ierr);
1573     ierr = MatSetLocalToGlobalMapping(j22,vISMap,vISMap);CHKERRQ(ierr);
1574 
1575     ierr = MatSetUp(j11);CHKERRQ(ierr);
1576     ierr = MatSetUp(j12);CHKERRQ(ierr);
1577     ierr = MatSetUp(j21);CHKERRQ(ierr);
1578     ierr = MatSetUp(j22);CHKERRQ(ierr);
1579 
1580     ierr = MatCreateNest(comm,2,NULL,2,NULL,&bA[0][0],J);CHKERRQ(ierr);
1581     ierr = MatSetUp(*J);CHKERRQ(ierr);
1582     ierr = MatNestSetVecType(*J,VECNEST);CHKERRQ(ierr);
1583     ierr = MatDestroy(&j11);CHKERRQ(ierr);
1584     ierr = MatDestroy(&j12);CHKERRQ(ierr);
1585     ierr = MatDestroy(&j21);CHKERRQ(ierr);
1586     ierr = MatDestroy(&j22);CHKERRQ(ierr);
1587 
1588     ierr = MatAssemblyBegin(*J,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1589     ierr = MatAssemblyEnd(*J,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1590 
1591     /* Free structures */
1592     ierr = ISLocalToGlobalMappingDestroy(&eISMap);CHKERRQ(ierr);
1593     ierr = ISLocalToGlobalMappingDestroy(&vISMap);CHKERRQ(ierr);
1594 
1595     PetscFunctionReturn(0);
1596   } else if (!network->userEdgeJacobian && !network->userVertexJacobian) {
1597     /* user does not provide Jacobian blocks */
1598     ierr = DMCreateMatrix(network->plex,J);CHKERRQ(ierr);
1599     ierr = MatSetDM(*J,dm);CHKERRQ(ierr);
1600     PetscFunctionReturn(0);
1601   }
1602 
1603   ierr = MatCreate(PetscObjectComm((PetscObject)dm),J);CHKERRQ(ierr);
1604   ierr = DMGetDefaultGlobalSection(network->plex,&sectionGlobal);CHKERRQ(ierr);
1605   ierr = PetscSectionGetConstrainedStorageSize(sectionGlobal,&localSize);CHKERRQ(ierr);
1606   ierr = MatSetSizes(*J,localSize,localSize,PETSC_DETERMINE,PETSC_DETERMINE);CHKERRQ(ierr);
1607 
1608   ierr = MatSetType(*J,MATAIJ);CHKERRQ(ierr);
1609   ierr = MatSetFromOptions(*J);CHKERRQ(ierr);
1610 
1611   /* (1) Set matrix preallocation */
1612   /*------------------------------*/
1613   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
1614   ierr = VecCreate(comm,&vd_nz);CHKERRQ(ierr);
1615   ierr = VecSetSizes(vd_nz,localSize,PETSC_DECIDE);CHKERRQ(ierr);
1616   ierr = VecSetFromOptions(vd_nz);CHKERRQ(ierr);
1617   ierr = VecSet(vd_nz,0.0);CHKERRQ(ierr);
1618   ierr = VecDuplicate(vd_nz,&vo_nz);CHKERRQ(ierr);
1619 
1620   /* Set preallocation for edges */
1621   /*-----------------------------*/
1622   ierr = DMNetworkGetEdgeRange(dm,&eStart,&eEnd);CHKERRQ(ierr);
1623 
1624   ierr = PetscMalloc1(localSize,&rows);CHKERRQ(ierr);
1625   for (e=eStart; e<eEnd; e++) {
1626     /* Get row indices */
1627     ierr = DMNetworkGetVariableGlobalOffset(dm,e,&rstart);CHKERRQ(ierr);
1628     ierr = DMNetworkGetNumVariables(dm,e,&nrows);CHKERRQ(ierr);
1629     if (nrows) {
1630       for (j=0; j<nrows; j++) rows[j] = j + rstart;
1631 
1632       /* Set preallocation for conntected vertices */
1633       ierr = DMNetworkGetConnectedVertices(dm,e,&cone);CHKERRQ(ierr);
1634       for (v=0; v<2; v++) {
1635         ierr = DMNetworkGetNumVariables(dm,cone[v],&ncols);CHKERRQ(ierr);
1636 
1637         if (network->Je) {
1638           Juser = network->Je[3*e+1+v]; /* Jacobian(e,v) */
1639         } else Juser = NULL;
1640         ierr = DMNetworkIsGhostVertex(dm,cone[v],&ghost);CHKERRQ(ierr);
1641         ierr = MatSetPreallocationblock_private(Juser,nrows,rows,ncols,ghost,vd_nz,vo_nz);CHKERRQ(ierr);
1642       }
1643 
1644       /* Set preallocation for edge self */
1645       cstart = rstart;
1646       if (network->Je) {
1647         Juser = network->Je[3*e]; /* Jacobian(e,e) */
1648       } else Juser = NULL;
1649       ierr = MatSetPreallocationblock_private(Juser,nrows,rows,nrows,PETSC_FALSE,vd_nz,vo_nz);CHKERRQ(ierr);
1650     }
1651   }
1652 
1653   /* Set preallocation for vertices */
1654   /*--------------------------------*/
1655   ierr = DMNetworkGetVertexRange(dm,&vStart,&vEnd);CHKERRQ(ierr);
1656   if (vEnd - vStart) vptr = network->Jvptr;
1657 
1658   for (v=vStart; v<vEnd; v++) {
1659     /* Get row indices */
1660     ierr = DMNetworkGetVariableGlobalOffset(dm,v,&rstart);CHKERRQ(ierr);
1661     ierr = DMNetworkGetNumVariables(dm,v,&nrows);CHKERRQ(ierr);
1662     if (!nrows) continue;
1663 
1664     ierr = DMNetworkIsGhostVertex(dm,v,&ghost);CHKERRQ(ierr);
1665     if (ghost) {
1666       ierr = PetscMalloc1(nrows,&rows_v);CHKERRQ(ierr);
1667     } else {
1668       rows_v = rows;
1669     }
1670 
1671     for (j=0; j<nrows; j++) rows_v[j] = j + rstart;
1672 
1673     /* Get supporting edges and connected vertices */
1674     ierr = DMNetworkGetSupportingEdges(dm,v,&nedges,&edges);CHKERRQ(ierr);
1675 
1676     for (e=0; e<nedges; e++) {
1677       /* Supporting edges */
1678       ierr = DMNetworkGetVariableGlobalOffset(dm,edges[e],&cstart);CHKERRQ(ierr);
1679       ierr = DMNetworkGetNumVariables(dm,edges[e],&ncols);CHKERRQ(ierr);
1680 
1681       if (network->Jv) {
1682         Juser = network->Jv[vptr[v-vStart]+2*e+1]; /* Jacobian(v,e) */
1683       } else Juser = NULL;
1684       ierr = MatSetPreallocationblock_private(Juser,nrows,rows_v,ncols,ghost,vd_nz,vo_nz);CHKERRQ(ierr);
1685 
1686       /* Connected vertices */
1687       ierr = DMNetworkGetConnectedVertices(dm,edges[e],&cone);CHKERRQ(ierr);
1688       vc = (v == cone[0]) ? cone[1]:cone[0];
1689       ierr = DMNetworkIsGhostVertex(dm,vc,&ghost_vc);CHKERRQ(ierr);
1690 
1691       ierr = DMNetworkGetNumVariables(dm,vc,&ncols);CHKERRQ(ierr);
1692 
1693       if (network->Jv) {
1694         Juser = network->Jv[vptr[v-vStart]+2*e+2]; /* Jacobian(v,vc) */
1695       } else Juser = NULL;
1696       if (ghost_vc||ghost) {
1697         ghost2 = PETSC_TRUE;
1698       } else {
1699         ghost2 = PETSC_FALSE;
1700       }
1701       ierr = MatSetPreallocationblock_private(Juser,nrows,rows_v,ncols,ghost2,vd_nz,vo_nz);CHKERRQ(ierr);
1702     }
1703 
1704     /* Set preallocation for vertex self */
1705     ierr = DMNetworkIsGhostVertex(dm,v,&ghost);CHKERRQ(ierr);
1706     if (!ghost) {
1707       ierr = DMNetworkGetVariableGlobalOffset(dm,v,&cstart);CHKERRQ(ierr);
1708       if (network->Jv) {
1709         Juser = network->Jv[vptr[v-vStart]]; /* Jacobian(v,v) */
1710       } else Juser = NULL;
1711       ierr = MatSetPreallocationblock_private(Juser,nrows,rows_v,nrows,PETSC_FALSE,vd_nz,vo_nz);CHKERRQ(ierr);
1712     }
1713     if (ghost) {
1714       ierr = PetscFree(rows_v);CHKERRQ(ierr);
1715     }
1716   }
1717 
1718   ierr = VecAssemblyBegin(vd_nz);CHKERRQ(ierr);
1719   ierr = VecAssemblyBegin(vo_nz);CHKERRQ(ierr);
1720 
1721   ierr = PetscMalloc2(localSize,&dnnz,localSize,&onnz);CHKERRQ(ierr);
1722 
1723   ierr = VecAssemblyEnd(vd_nz);CHKERRQ(ierr);
1724   ierr = VecAssemblyEnd(vo_nz);CHKERRQ(ierr);
1725 
1726   ierr = VecGetArray(vd_nz,&vdnz);CHKERRQ(ierr);
1727   ierr = VecGetArray(vo_nz,&vonz);CHKERRQ(ierr);
1728   for (j=0; j<localSize; j++) {
1729     dnnz[j] = (PetscInt)PetscRealPart(vdnz[j]);
1730     onnz[j] = (PetscInt)PetscRealPart(vonz[j]);
1731   }
1732   ierr = VecRestoreArray(vd_nz,&vdnz);CHKERRQ(ierr);
1733   ierr = VecRestoreArray(vo_nz,&vonz);CHKERRQ(ierr);
1734   ierr = VecDestroy(&vd_nz);CHKERRQ(ierr);
1735   ierr = VecDestroy(&vo_nz);CHKERRQ(ierr);
1736 
1737   ierr = MatSeqAIJSetPreallocation(*J,0,dnnz);CHKERRQ(ierr);
1738   ierr = MatMPIAIJSetPreallocation(*J,0,dnnz,0,onnz);CHKERRQ(ierr);
1739   ierr = MatSetOption(*J,MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_TRUE);CHKERRQ(ierr);
1740 
1741   ierr = PetscFree2(dnnz,onnz);CHKERRQ(ierr);
1742 
1743   /* (2) Set matrix entries for edges */
1744   /*----------------------------------*/
1745   for (e=eStart; e<eEnd; e++) {
1746     /* Get row indices */
1747     ierr = DMNetworkGetVariableGlobalOffset(dm,e,&rstart);CHKERRQ(ierr);
1748     ierr = DMNetworkGetNumVariables(dm,e,&nrows);CHKERRQ(ierr);
1749     if (nrows) {
1750       for (j=0; j<nrows; j++) rows[j] = j + rstart;
1751 
1752       /* Set matrix entries for conntected vertices */
1753       ierr = DMNetworkGetConnectedVertices(dm,e,&cone);CHKERRQ(ierr);
1754       for (v=0; v<2; v++) {
1755         ierr = DMNetworkGetVariableGlobalOffset(dm,cone[v],&cstart);CHKERRQ(ierr);
1756         ierr = DMNetworkGetNumVariables(dm,cone[v],&ncols);CHKERRQ(ierr);
1757 
1758         if (network->Je) {
1759           Juser = network->Je[3*e+1+v]; /* Jacobian(e,v) */
1760         } else Juser = NULL;
1761         ierr = MatSetblock_private(Juser,nrows,rows,ncols,cstart,J);CHKERRQ(ierr);
1762       }
1763 
1764       /* Set matrix entries for edge self */
1765       cstart = rstart;
1766       if (network->Je) {
1767         Juser = network->Je[3*e]; /* Jacobian(e,e) */
1768       } else Juser = NULL;
1769       ierr = MatSetblock_private(Juser,nrows,rows,nrows,cstart,J);CHKERRQ(ierr);
1770     }
1771   }
1772 
1773   /* Set matrix entries for vertices */
1774   /*---------------------------------*/
1775   for (v=vStart; v<vEnd; v++) {
1776     /* Get row indices */
1777     ierr = DMNetworkGetVariableGlobalOffset(dm,v,&rstart);CHKERRQ(ierr);
1778     ierr = DMNetworkGetNumVariables(dm,v,&nrows);CHKERRQ(ierr);
1779     if (!nrows) continue;
1780 
1781     ierr = DMNetworkIsGhostVertex(dm,v,&ghost);CHKERRQ(ierr);
1782     if (ghost) {
1783       ierr = PetscMalloc1(nrows,&rows_v);CHKERRQ(ierr);
1784     } else {
1785       rows_v = rows;
1786     }
1787     for (j=0; j<nrows; j++) rows_v[j] = j + rstart;
1788 
1789     /* Get supporting edges and connected vertices */
1790     ierr = DMNetworkGetSupportingEdges(dm,v,&nedges,&edges);CHKERRQ(ierr);
1791 
1792     for (e=0; e<nedges; e++) {
1793       /* Supporting edges */
1794       ierr = DMNetworkGetVariableGlobalOffset(dm,edges[e],&cstart);CHKERRQ(ierr);
1795       ierr = DMNetworkGetNumVariables(dm,edges[e],&ncols);CHKERRQ(ierr);
1796 
1797       if (network->Jv) {
1798         Juser = network->Jv[vptr[v-vStart]+2*e+1]; /* Jacobian(v,e) */
1799       } else Juser = NULL;
1800       ierr = MatSetblock_private(Juser,nrows,rows_v,ncols,cstart,J);CHKERRQ(ierr);
1801 
1802       /* Connected vertices */
1803       ierr = DMNetworkGetConnectedVertices(dm,edges[e],&cone);CHKERRQ(ierr);
1804       vc = (v == cone[0]) ? cone[1]:cone[0];
1805 
1806       ierr = DMNetworkGetVariableGlobalOffset(dm,vc,&cstart);CHKERRQ(ierr);
1807       ierr = DMNetworkGetNumVariables(dm,vc,&ncols);CHKERRQ(ierr);
1808 
1809       if (network->Jv) {
1810         Juser = network->Jv[vptr[v-vStart]+2*e+2]; /* Jacobian(v,vc) */
1811       } else Juser = NULL;
1812       ierr = MatSetblock_private(Juser,nrows,rows_v,ncols,cstart,J);CHKERRQ(ierr);
1813     }
1814 
1815     /* Set matrix entries for vertex self */
1816     if (!ghost) {
1817       ierr = DMNetworkGetVariableGlobalOffset(dm,v,&cstart);CHKERRQ(ierr);
1818       if (network->Jv) {
1819         Juser = network->Jv[vptr[v-vStart]]; /* Jacobian(v,v) */
1820       } else Juser = NULL;
1821       ierr = MatSetblock_private(Juser,nrows,rows_v,nrows,cstart,J);CHKERRQ(ierr);
1822     }
1823     if (ghost) {
1824       ierr = PetscFree(rows_v);CHKERRQ(ierr);
1825     }
1826   }
1827   ierr = PetscFree(rows);CHKERRQ(ierr);
1828 
1829   ierr = MatAssemblyBegin(*J,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1830   ierr = MatAssemblyEnd(*J,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1831 
1832   ierr = MatSetDM(*J,dm);CHKERRQ(ierr);
1833   PetscFunctionReturn(0);
1834 }
1835 
1836 PetscErrorCode DMDestroy_Network(DM dm)
1837 {
1838   PetscErrorCode ierr;
1839   DM_Network     *network = (DM_Network*)dm->data;
1840   PetscInt       j;
1841 
1842   PetscFunctionBegin;
1843   if (--network->refct > 0) PetscFunctionReturn(0);
1844   if (network->Je) {
1845     ierr = PetscFree(network->Je);CHKERRQ(ierr);
1846   }
1847   if (network->Jv) {
1848     ierr = PetscFree(network->Jvptr);CHKERRQ(ierr);
1849     ierr = PetscFree(network->Jv);CHKERRQ(ierr);
1850   }
1851 
1852   ierr = ISLocalToGlobalMappingDestroy(&network->vertex.mapping);CHKERRQ(ierr);
1853   ierr = PetscSectionDestroy(&network->vertex.DofSection);CHKERRQ(ierr);
1854   ierr = PetscSectionDestroy(&network->vertex.GlobalDofSection);CHKERRQ(ierr);
1855   if (network->vertex.sf) {
1856     ierr = PetscSFDestroy(&network->vertex.sf);CHKERRQ(ierr);
1857   }
1858   /* edge */
1859   ierr = ISLocalToGlobalMappingDestroy(&network->edge.mapping);CHKERRQ(ierr);
1860   ierr = PetscSectionDestroy(&network->edge.DofSection);CHKERRQ(ierr);
1861   ierr = PetscSectionDestroy(&network->edge.GlobalDofSection);CHKERRQ(ierr);
1862   if (network->edge.sf) {
1863     ierr = PetscSFDestroy(&network->edge.sf);CHKERRQ(ierr);
1864   }
1865   ierr = DMDestroy(&network->plex);CHKERRQ(ierr);
1866   network->edges = NULL;
1867   ierr = PetscSectionDestroy(&network->DataSection);CHKERRQ(ierr);
1868   ierr = PetscSectionDestroy(&network->DofSection);CHKERRQ(ierr);
1869 
1870   for(j=0; j < network->nsubnet; j++) {
1871     ierr = PetscFree(network->subnet[j].edges);CHKERRQ(ierr);
1872     ierr = PetscFree(network->subnet[j].vertices);CHKERRQ(ierr);
1873   }
1874   ierr = PetscFree(network->subnet);CHKERRQ(ierr);
1875   ierr = PetscFree(network->componentdataarray);CHKERRQ(ierr);
1876   ierr = PetscFree(network->cvalue);CHKERRQ(ierr);
1877   ierr = PetscFree(network->header);CHKERRQ(ierr);
1878   ierr = PetscFree(network);CHKERRQ(ierr);
1879   PetscFunctionReturn(0);
1880 }
1881 
1882 PetscErrorCode DMView_Network(DM dm,PetscViewer viewer)
1883 {
1884   PetscErrorCode ierr;
1885   DM_Network     *network = (DM_Network*)dm->data;
1886 
1887   PetscFunctionBegin;
1888   ierr = DMView(network->plex,viewer);CHKERRQ(ierr);
1889   PetscFunctionReturn(0);
1890 }
1891 
1892 PetscErrorCode DMGlobalToLocalBegin_Network(DM dm, Vec g, InsertMode mode, Vec l)
1893 {
1894   PetscErrorCode ierr;
1895   DM_Network     *network = (DM_Network*)dm->data;
1896 
1897   PetscFunctionBegin;
1898   ierr = DMGlobalToLocalBegin(network->plex,g,mode,l);CHKERRQ(ierr);
1899   PetscFunctionReturn(0);
1900 }
1901 
1902 PetscErrorCode DMGlobalToLocalEnd_Network(DM dm, Vec g, InsertMode mode, Vec l)
1903 {
1904   PetscErrorCode ierr;
1905   DM_Network     *network = (DM_Network*)dm->data;
1906 
1907   PetscFunctionBegin;
1908   ierr = DMGlobalToLocalEnd(network->plex,g,mode,l);CHKERRQ(ierr);
1909   PetscFunctionReturn(0);
1910 }
1911 
1912 PetscErrorCode DMLocalToGlobalBegin_Network(DM dm, Vec l, InsertMode mode, Vec g)
1913 {
1914   PetscErrorCode ierr;
1915   DM_Network     *network = (DM_Network*)dm->data;
1916 
1917   PetscFunctionBegin;
1918   ierr = DMLocalToGlobalBegin(network->plex,l,mode,g);CHKERRQ(ierr);
1919   PetscFunctionReturn(0);
1920 }
1921 
1922 PetscErrorCode DMLocalToGlobalEnd_Network(DM dm, Vec l, InsertMode mode, Vec g)
1923 {
1924   PetscErrorCode ierr;
1925   DM_Network     *network = (DM_Network*)dm->data;
1926 
1927   PetscFunctionBegin;
1928   ierr = DMLocalToGlobalEnd(network->plex,l,mode,g);CHKERRQ(ierr);
1929   PetscFunctionReturn(0);
1930 }
1931