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