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