xref: /petsc/src/dm/impls/network/network.c (revision b9c6e19d9dc64277a806394b87c516adb6f1d372)
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 
1178   PetscFunctionBegin;
1179   network->userEdgeJacobian   = eflg;
1180   network->userVertexJacobian = vflg;
1181   PetscFunctionReturn(0);
1182 }
1183 
1184 /*@
1185     DMNetworkEdgeSetMatrix - Sets user-provided Jacobian matrices for this edge to the network
1186 
1187     Not Collective
1188 
1189     Input Parameters:
1190 +   dm - The DMNetwork object
1191 .   p  - the edge point
1192 -   J - array (size = 3) of Jacobian submatrices for this edge point:
1193         J[0]: this edge
1194         J[1] and J[2]: connected vertices, obtained by calling DMNetworkGetConnectedVertices()
1195 
1196     Level: intermediate
1197 
1198 .seealso: DMNetworkVertexSetMatrix
1199 @*/
1200 PetscErrorCode DMNetworkEdgeSetMatrix(DM dm,PetscInt p,Mat J[])
1201 {
1202   PetscErrorCode ierr;
1203   DM_Network     *network=(DM_Network*)dm->data;
1204 
1205   PetscFunctionBegin;
1206   if (!network->userEdgeJacobian) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ORDER,"Must call DMNetworkHasJacobian() collectively before calling DMNetworkEdgeSetMatrix");
1207   if (!network->Je) {
1208     ierr = PetscCalloc1(3*network->nEdges,&network->Je);CHKERRQ(ierr);
1209   }
1210   network->Je[3*p]   = J[0];
1211   network->Je[3*p+1] = J[1];
1212   network->Je[3*p+2] = J[2];
1213   PetscFunctionReturn(0);
1214 }
1215 
1216 /*@
1217     DMNetworkVertexSetMatrix - Sets user-provided Jacobian matrix for this vertex to the network
1218 
1219     Not Collective
1220 
1221     Input Parameters:
1222 +   dm - The DMNetwork object
1223 .   p  - the vertex point
1224 -   J - array of Jacobian (size = 2*(num of supporting edges) + 1) submatrices for this vertex point:
1225         J[0]:       this vertex
1226         J[1+2*i]:   i-th supporting edge
1227         J[1+2*i+1]: i-th connected vertex
1228 
1229     Level: intermediate
1230 
1231 .seealso: DMNetworkEdgeSetMatrix
1232 @*/
1233 PetscErrorCode DMNetworkVertexSetMatrix(DM dm,PetscInt p,Mat J[])
1234 {
1235   PetscErrorCode ierr;
1236   DM_Network     *network=(DM_Network*)dm->data;
1237   PetscInt       i,*vptr,nedges,vStart,vEnd;
1238   const PetscInt *edges;
1239 
1240   PetscFunctionBegin;
1241   if (!network->userVertexJacobian) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ORDER,"Must call DMNetworkHasJacobian() collectively before calling DMNetworkVertexSetMatrix");
1242 
1243   ierr = DMNetworkGetVertexRange(dm,&vStart,&vEnd);CHKERRQ(ierr);
1244 
1245   if (!network->Jv) {
1246     PetscInt nVertices = network->nVertices,nedges_total;
1247     /* count nvertex_total */
1248     nedges_total = 0;
1249     ierr = DMNetworkGetVertexRange(dm,&vStart,&vEnd);CHKERRQ(ierr);
1250     ierr = PetscMalloc1(nVertices+1,&vptr);CHKERRQ(ierr);
1251 
1252     vptr[0] = 0;
1253     for (i=0; i<nVertices; i++) {
1254       ierr = DMNetworkGetSupportingEdges(dm,i+vStart,&nedges,&edges);CHKERRQ(ierr);
1255       nedges_total += nedges;
1256       vptr[i+1] = vptr[i] + 2*nedges + 1;
1257     }
1258 
1259     ierr = PetscCalloc1(2*nedges_total+nVertices,&network->Jv);CHKERRQ(ierr);
1260     network->Jvptr = vptr;
1261   }
1262 
1263   vptr = network->Jvptr;
1264   network->Jv[vptr[p-vStart]] = J[0]; /* Set Jacobian for this vertex */
1265 
1266   /* Set Jacobian for each supporting edge and connected vertex */
1267   ierr = DMNetworkGetSupportingEdges(dm,p,&nedges,&edges);CHKERRQ(ierr);
1268   for (i=1; i<=2*nedges; i++) network->Jv[vptr[p-vStart]+i] = J[i];
1269   PetscFunctionReturn(0);
1270 }
1271 
1272 PETSC_STATIC_INLINE PetscErrorCode MatSetPreallocationDenseblock_private(PetscInt nrows,PetscInt *rows,PetscInt ncols,PetscBool ghost,Vec vdnz,Vec vonz)
1273 {
1274   PetscErrorCode ierr;
1275   PetscInt       j;
1276   PetscScalar    val=(PetscScalar)ncols;
1277 
1278   PetscFunctionBegin;
1279   if (!ghost) {
1280     for (j=0; j<nrows; j++) {
1281       ierr = VecSetValues(vdnz,1,&rows[j],&val,ADD_VALUES);CHKERRQ(ierr);
1282     }
1283   } else {
1284     for (j=0; j<nrows; j++) {
1285       ierr = VecSetValues(vonz,1,&rows[j],&val,ADD_VALUES);CHKERRQ(ierr);
1286     }
1287   }
1288   PetscFunctionReturn(0);
1289 }
1290 
1291 PETSC_STATIC_INLINE PetscErrorCode MatSetPreallocationUserblock_private(Mat Ju,PetscInt nrows,PetscInt *rows,PetscInt ncols,PetscBool ghost,Vec vdnz,Vec vonz)
1292 {
1293   PetscErrorCode ierr;
1294   PetscInt       j,ncols_u;
1295   PetscScalar    val;
1296 
1297   PetscFunctionBegin;
1298   if (!ghost) {
1299     for (j=0; j<nrows; j++) {
1300       ierr = MatGetRow(Ju,j,&ncols_u,NULL,NULL);CHKERRQ(ierr);
1301       val = (PetscScalar)ncols_u;
1302       ierr = VecSetValues(vdnz,1,&rows[j],&val,ADD_VALUES);CHKERRQ(ierr);
1303       ierr = MatRestoreRow(Ju,j,&ncols_u,NULL,NULL);CHKERRQ(ierr);
1304     }
1305   } else {
1306     for (j=0; j<nrows; j++) {
1307       ierr = MatGetRow(Ju,j,&ncols_u,NULL,NULL);CHKERRQ(ierr);
1308       val = (PetscScalar)ncols_u;
1309       ierr = VecSetValues(vonz,1,&rows[j],&val,ADD_VALUES);CHKERRQ(ierr);
1310       ierr = MatRestoreRow(Ju,j,&ncols_u,NULL,NULL);CHKERRQ(ierr);
1311     }
1312   }
1313   PetscFunctionReturn(0);
1314 }
1315 
1316 PETSC_STATIC_INLINE PetscErrorCode MatSetPreallocationblock_private(Mat Ju,PetscInt nrows,PetscInt *rows,PetscInt ncols,PetscBool ghost,Vec vdnz,Vec vonz)
1317 {
1318   PetscErrorCode ierr;
1319 
1320   PetscFunctionBegin;
1321   if (Ju) {
1322     ierr = MatSetPreallocationUserblock_private(Ju,nrows,rows,ncols,ghost,vdnz,vonz);CHKERRQ(ierr);
1323   } else {
1324     ierr = MatSetPreallocationDenseblock_private(nrows,rows,ncols,ghost,vdnz,vonz);CHKERRQ(ierr);
1325   }
1326   PetscFunctionReturn(0);
1327 }
1328 
1329 PETSC_STATIC_INLINE PetscErrorCode MatSetDenseblock_private(PetscInt nrows,PetscInt *rows,PetscInt ncols,PetscInt cstart,Mat *J)
1330 {
1331   PetscErrorCode ierr;
1332   PetscInt       j,*cols;
1333   PetscScalar    *zeros;
1334 
1335   PetscFunctionBegin;
1336   ierr = PetscCalloc2(ncols,&cols,nrows*ncols,&zeros);CHKERRQ(ierr);
1337   for (j=0; j<ncols; j++) cols[j] = j+ cstart;
1338   ierr = MatSetValues(*J,nrows,rows,ncols,cols,zeros,INSERT_VALUES);CHKERRQ(ierr);
1339   ierr = PetscFree2(cols,zeros);CHKERRQ(ierr);
1340   PetscFunctionReturn(0);
1341 }
1342 
1343 PETSC_STATIC_INLINE PetscErrorCode MatSetUserblock_private(Mat Ju,PetscInt nrows,PetscInt *rows,PetscInt ncols,PetscInt cstart,Mat *J)
1344 {
1345   PetscErrorCode ierr;
1346   PetscInt       j,M,N,row,col,ncols_u;
1347   const PetscInt *cols;
1348   PetscScalar    zero=0.0;
1349 
1350   PetscFunctionBegin;
1351   ierr = MatGetSize(Ju,&M,&N);CHKERRQ(ierr);
1352   if (nrows != M || ncols != N) SETERRQ4(PetscObjectComm((PetscObject)Ju),PETSC_ERR_USER,"%D by %D must equal %D by %D",nrows,ncols,M,N);
1353 
1354   for (row=0; row<nrows; row++) {
1355     ierr = MatGetRow(Ju,row,&ncols_u,&cols,NULL);CHKERRQ(ierr);
1356     for (j=0; j<ncols_u; j++) {
1357       col = cols[j] + cstart;
1358       ierr = MatSetValues(*J,1,&rows[row],1,&col,&zero,INSERT_VALUES);CHKERRQ(ierr);
1359     }
1360     ierr = MatRestoreRow(Ju,row,&ncols_u,&cols,NULL);CHKERRQ(ierr);
1361   }
1362   PetscFunctionReturn(0);
1363 }
1364 
1365 PETSC_STATIC_INLINE PetscErrorCode MatSetblock_private(Mat Ju,PetscInt nrows,PetscInt *rows,PetscInt ncols,PetscInt cstart,Mat *J)
1366 {
1367   PetscErrorCode ierr;
1368 
1369   PetscFunctionBegin;
1370   if (Ju) {
1371     ierr = MatSetUserblock_private(Ju,nrows,rows,ncols,cstart,J);CHKERRQ(ierr);
1372   } else {
1373     ierr = MatSetDenseblock_private(nrows,rows,ncols,cstart,J);CHKERRQ(ierr);
1374   }
1375   PetscFunctionReturn(0);
1376 }
1377 
1378 /* 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.
1379 */
1380 PetscErrorCode CreateSubGlobalToLocalMapping_private(PetscSection globalsec, PetscSection localsec, ISLocalToGlobalMapping *ltog)
1381 {
1382   PetscErrorCode ierr;
1383   PetscInt       i, size, dof;
1384   PetscInt       *glob2loc;
1385 
1386   PetscFunctionBegin;
1387   ierr = PetscSectionGetStorageSize(localsec,&size);CHKERRQ(ierr);
1388   ierr = PetscMalloc1(size,&glob2loc);CHKERRQ(ierr);
1389 
1390   for (i = 0; i < size; i++) {
1391     ierr = PetscSectionGetOffset(globalsec,i,&dof);CHKERRQ(ierr);
1392     dof = (dof >= 0) ? dof : -(dof + 1);
1393     glob2loc[i] = dof;
1394   }
1395 
1396   ierr = ISLocalToGlobalMappingCreate(PETSC_COMM_WORLD,1,size,glob2loc,PETSC_OWN_POINTER,ltog);CHKERRQ(ierr);
1397 #if 0
1398   ierr = PetscIntView(size,glob2loc,PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
1399 #endif
1400   PetscFunctionReturn(0);
1401 }
1402 
1403 #include <petsc/private/matimpl.h>
1404 PetscErrorCode DMCreateMatrix_Network(DM dm,Mat *J)
1405 {
1406   PetscErrorCode ierr;
1407   PetscMPIInt    rank, size;
1408   DM_Network     *network = (DM_Network*) dm->data;
1409   PetscInt       eStart,eEnd,vStart,vEnd,rstart,nrows,*rows,localSize;
1410   PetscInt       cstart,ncols,j,e,v;
1411   PetscBool      ghost,ghost_vc,ghost2,isNest;
1412   Mat            Juser;
1413   PetscSection   sectionGlobal;
1414   PetscInt       nedges,*vptr=NULL,vc,*rows_v; /* suppress maybe-uninitialized warning */
1415   const PetscInt *edges,*cone;
1416   MPI_Comm       comm;
1417   MatType        mtype;
1418   Vec            vd_nz,vo_nz;
1419   PetscInt       *dnnz,*onnz;
1420   PetscScalar    *vdnz,*vonz;
1421 
1422   PetscFunctionBegin;
1423   mtype = dm->mattype;
1424   ierr = PetscStrcmp(mtype, MATNEST, &isNest);CHKERRQ(ierr);
1425 
1426   if (isNest) {
1427     /* ierr = DMCreateMatrix_Network_Nest(); */
1428     PetscInt   eDof, vDof;
1429     Mat        j11, j12, j21, j22, bA[2][2];
1430     ISLocalToGlobalMapping eISMap, vISMap;
1431 
1432     ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
1433     ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
1434     ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr);
1435 
1436     ierr = PetscSectionGetConstrainedStorageSize(network->edge.GlobalDofSection,&eDof);CHKERRQ(ierr);
1437     ierr = PetscSectionGetConstrainedStorageSize(network->vertex.GlobalDofSection,&vDof);CHKERRQ(ierr);
1438 
1439     ierr = MatCreate(comm, &j11);CHKERRQ(ierr);
1440     ierr = MatSetSizes(j11, eDof, eDof, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
1441     ierr = MatSetType(j11, MATMPIAIJ);CHKERRQ(ierr);
1442 
1443     ierr = MatCreate(comm, &j12);CHKERRQ(ierr);
1444     ierr = MatSetSizes(j12, eDof, vDof, PETSC_DETERMINE ,PETSC_DETERMINE);CHKERRQ(ierr);
1445     ierr = MatSetType(j12, MATMPIAIJ);CHKERRQ(ierr);
1446 
1447     ierr = MatCreate(comm, &j21);CHKERRQ(ierr);
1448     ierr = MatSetSizes(j21, vDof, eDof, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
1449     ierr = MatSetType(j21, MATMPIAIJ);CHKERRQ(ierr);
1450 
1451     ierr = MatCreate(comm, &j22);CHKERRQ(ierr);
1452     ierr = MatSetSizes(j22, vDof, vDof, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
1453     ierr = MatSetType(j22, MATMPIAIJ);CHKERRQ(ierr);
1454 
1455     bA[0][0] = j11;
1456     bA[0][1] = j12;
1457     bA[1][0] = j21;
1458     bA[1][1] = j22;
1459 
1460     ierr = CreateSubGlobalToLocalMapping_private(network->edge.GlobalDofSection,network->edge.DofSection,&eISMap);CHKERRQ(ierr);
1461     ierr = CreateSubGlobalToLocalMapping_private(network->vertex.GlobalDofSection,network->vertex.DofSection,&vISMap);CHKERRQ(ierr);
1462 
1463     ierr = MatSetLocalToGlobalMapping(j11,eISMap,eISMap);CHKERRQ(ierr);
1464     ierr = MatSetLocalToGlobalMapping(j12,eISMap,vISMap);CHKERRQ(ierr);
1465     ierr = MatSetLocalToGlobalMapping(j21,vISMap,eISMap);CHKERRQ(ierr);
1466     ierr = MatSetLocalToGlobalMapping(j22,vISMap,vISMap);CHKERRQ(ierr);
1467 
1468     ierr = MatSetUp(j11);CHKERRQ(ierr);
1469     ierr = MatSetUp(j12);CHKERRQ(ierr);
1470     ierr = MatSetUp(j21);CHKERRQ(ierr);
1471     ierr = MatSetUp(j22);CHKERRQ(ierr);
1472 
1473     ierr = MatCreateNest(comm,2,NULL,2,NULL,&bA[0][0],J);CHKERRQ(ierr);
1474     ierr = MatSetUp(*J);CHKERRQ(ierr);
1475     ierr = MatNestSetVecType(*J,VECNEST);CHKERRQ(ierr);
1476     ierr = MatDestroy(&j11);CHKERRQ(ierr);
1477     ierr = MatDestroy(&j12);CHKERRQ(ierr);
1478     ierr = MatDestroy(&j21);CHKERRQ(ierr);
1479     ierr = MatDestroy(&j22);CHKERRQ(ierr);
1480 
1481     ierr = MatAssemblyBegin(*J,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1482     ierr = MatAssemblyEnd(*J,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1483 
1484     /* Free structures */
1485     ierr = ISLocalToGlobalMappingDestroy(&eISMap);CHKERRQ(ierr);
1486     ierr = ISLocalToGlobalMappingDestroy(&vISMap);CHKERRQ(ierr);
1487 
1488     PetscFunctionReturn(0);
1489   } else if (!network->userEdgeJacobian && !network->userVertexJacobian) {
1490     /* user does not provide Jacobian blocks */
1491     ierr = DMCreateMatrix(network->plex,J);CHKERRQ(ierr);
1492     ierr = MatSetDM(*J,dm);CHKERRQ(ierr);
1493     PetscFunctionReturn(0);
1494   }
1495 
1496   ierr = MatCreate(PetscObjectComm((PetscObject)dm),J);CHKERRQ(ierr);
1497   ierr = DMGetDefaultGlobalSection(network->plex,&sectionGlobal);CHKERRQ(ierr);
1498   ierr = PetscSectionGetConstrainedStorageSize(sectionGlobal,&localSize);CHKERRQ(ierr);
1499   ierr = MatSetSizes(*J,localSize,localSize,PETSC_DETERMINE,PETSC_DETERMINE);CHKERRQ(ierr);
1500 
1501   ierr = MatSetType(*J,MATAIJ);CHKERRQ(ierr);
1502   ierr = MatSetFromOptions(*J);CHKERRQ(ierr);
1503 
1504   /* (1) Set matrix preallocation */
1505   /*------------------------------*/
1506   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
1507   ierr = VecCreate(comm,&vd_nz);CHKERRQ(ierr);
1508   ierr = VecSetSizes(vd_nz,localSize,PETSC_DECIDE);CHKERRQ(ierr);
1509   ierr = VecSetFromOptions(vd_nz);CHKERRQ(ierr);
1510   ierr = VecSet(vd_nz,0.0);CHKERRQ(ierr);
1511   ierr = VecDuplicate(vd_nz,&vo_nz);CHKERRQ(ierr);
1512 
1513   /* Set preallocation for edges */
1514   /*-----------------------------*/
1515   ierr = DMNetworkGetEdgeRange(dm,&eStart,&eEnd);CHKERRQ(ierr);
1516 
1517   ierr = PetscMalloc1(localSize,&rows);CHKERRQ(ierr);
1518   for (e=eStart; e<eEnd; e++) {
1519     /* Get row indices */
1520     ierr = DMNetworkGetVariableGlobalOffset(dm,e,&rstart);CHKERRQ(ierr);
1521     ierr = DMNetworkGetNumVariables(dm,e,&nrows);CHKERRQ(ierr);
1522     if (nrows) {
1523       if (!network->Je) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NULL,"Uer must provide Je");
1524       for (j=0; j<nrows; j++) rows[j] = j + rstart;
1525 
1526       /* Set preallocation for conntected vertices */
1527       ierr = DMNetworkGetConnectedVertices(dm,e,&cone);CHKERRQ(ierr);
1528       for (v=0; v<2; v++) {
1529         ierr = DMNetworkGetNumVariables(dm,cone[v],&ncols);CHKERRQ(ierr);
1530 
1531         Juser = network->Je[3*e+1+v]; /* Jacobian(e,v) */
1532         ierr = DMNetworkIsGhostVertex(dm,cone[v],&ghost);CHKERRQ(ierr);
1533         ierr = MatSetPreallocationblock_private(Juser,nrows,rows,ncols,ghost,vd_nz,vo_nz);CHKERRQ(ierr);
1534       }
1535 
1536       /* Set preallocation for edge self */
1537       cstart = rstart;
1538       Juser = network->Je[3*e]; /* Jacobian(e,e) */
1539       ierr = MatSetPreallocationblock_private(Juser,nrows,rows,nrows,PETSC_FALSE,vd_nz,vo_nz);CHKERRQ(ierr);
1540     }
1541   }
1542 
1543   /* Set preallocation for vertices */
1544   /*--------------------------------*/
1545   ierr = DMNetworkGetVertexRange(dm,&vStart,&vEnd);CHKERRQ(ierr);
1546   if (vEnd - vStart) {
1547     if (!network->Jv) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NULL,"Uer must provide Jv");
1548     vptr = network->Jvptr;
1549     if (!vptr) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NULL,"Uer must provide vptr");
1550   }
1551 
1552   for (v=vStart; v<vEnd; v++) {
1553     /* Get row indices */
1554     ierr = DMNetworkGetVariableGlobalOffset(dm,v,&rstart);CHKERRQ(ierr);
1555     ierr = DMNetworkGetNumVariables(dm,v,&nrows);CHKERRQ(ierr);
1556     if (!nrows) continue;
1557 
1558     ierr = DMNetworkIsGhostVertex(dm,v,&ghost);CHKERRQ(ierr);
1559     if (ghost) {
1560       ierr = PetscMalloc1(nrows,&rows_v);CHKERRQ(ierr);
1561     } else {
1562       rows_v = rows;
1563     }
1564 
1565     for (j=0; j<nrows; j++) rows_v[j] = j + rstart;
1566 
1567     /* Get supporting edges and connected vertices */
1568     ierr = DMNetworkGetSupportingEdges(dm,v,&nedges,&edges);CHKERRQ(ierr);
1569 
1570     for (e=0; e<nedges; e++) {
1571       /* Supporting edges */
1572       ierr = DMNetworkGetVariableGlobalOffset(dm,edges[e],&cstart);CHKERRQ(ierr);
1573       ierr = DMNetworkGetNumVariables(dm,edges[e],&ncols);CHKERRQ(ierr);
1574 
1575       Juser = network->Jv[vptr[v-vStart]+2*e+1]; /* Jacobian(v,e) */
1576       ierr = MatSetPreallocationblock_private(Juser,nrows,rows_v,ncols,ghost,vd_nz,vo_nz);CHKERRQ(ierr);
1577 
1578       /* Connected vertices */
1579       ierr = DMNetworkGetConnectedVertices(dm,edges[e],&cone);CHKERRQ(ierr);
1580       vc = (v == cone[0]) ? cone[1]:cone[0];
1581       ierr = DMNetworkIsGhostVertex(dm,vc,&ghost_vc);CHKERRQ(ierr);
1582 
1583       ierr = DMNetworkGetNumVariables(dm,vc,&ncols);CHKERRQ(ierr);
1584 
1585       Juser = network->Jv[vptr[v-vStart]+2*e+2]; /* Jacobian(v,vc) */
1586       if (ghost_vc||ghost) {
1587         ghost2 = PETSC_TRUE;
1588       } else {
1589         ghost2 = PETSC_FALSE;
1590       }
1591       ierr = MatSetPreallocationblock_private(Juser,nrows,rows_v,ncols,ghost2,vd_nz,vo_nz);CHKERRQ(ierr);
1592     }
1593 
1594     /* Set preallocation for vertex self */
1595     ierr = DMNetworkIsGhostVertex(dm,v,&ghost);CHKERRQ(ierr);
1596     if (!ghost) {
1597       ierr = DMNetworkGetVariableGlobalOffset(dm,v,&cstart);CHKERRQ(ierr);
1598       Juser = network->Jv[vptr[v-vStart]]; /* Jacobian(v,v) */
1599       ierr = MatSetPreallocationblock_private(Juser,nrows,rows_v,nrows,PETSC_FALSE,vd_nz,vo_nz);CHKERRQ(ierr);
1600     }
1601     if (ghost) {
1602       ierr = PetscFree(rows_v);CHKERRQ(ierr);
1603     }
1604   }
1605 
1606   ierr = VecAssemblyBegin(vd_nz);CHKERRQ(ierr);
1607   ierr = VecAssemblyBegin(vo_nz);CHKERRQ(ierr);
1608 
1609   ierr = PetscMalloc2(localSize,&dnnz,localSize,&onnz);CHKERRQ(ierr);
1610 
1611   ierr = VecAssemblyEnd(vd_nz);CHKERRQ(ierr);
1612   ierr = VecAssemblyEnd(vo_nz);CHKERRQ(ierr);
1613 
1614   ierr = VecGetArray(vd_nz,&vdnz);CHKERRQ(ierr);
1615   ierr = VecGetArray(vo_nz,&vonz);CHKERRQ(ierr);
1616   for (j=0; j<localSize; j++) {
1617     dnnz[j] = (PetscInt)PetscRealPart(vdnz[j]);
1618     onnz[j] = (PetscInt)PetscRealPart(vonz[j]);
1619   }
1620   ierr = VecRestoreArray(vd_nz,&vdnz);CHKERRQ(ierr);
1621   ierr = VecRestoreArray(vo_nz,&vonz);CHKERRQ(ierr);
1622   ierr = VecDestroy(&vd_nz);CHKERRQ(ierr);
1623   ierr = VecDestroy(&vo_nz);CHKERRQ(ierr);
1624 
1625   ierr = MatSeqAIJSetPreallocation(*J,0,dnnz);CHKERRQ(ierr);
1626   ierr = MatMPIAIJSetPreallocation(*J,0,dnnz,0,onnz);CHKERRQ(ierr);
1627   ierr = MatSetOption(*J,MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_TRUE);CHKERRQ(ierr);
1628 
1629   ierr = PetscFree2(dnnz,onnz);CHKERRQ(ierr);
1630 
1631   /* (2) Set matrix entries for edges */
1632   /*----------------------------------*/
1633   for (e=eStart; e<eEnd; e++) {
1634     /* Get row indices */
1635     ierr = DMNetworkGetVariableGlobalOffset(dm,e,&rstart);CHKERRQ(ierr);
1636     ierr = DMNetworkGetNumVariables(dm,e,&nrows);CHKERRQ(ierr);
1637     if (nrows) {
1638       if (!network->Je) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NULL,"Uer must provide Je");
1639 
1640       for (j=0; j<nrows; j++) rows[j] = j + rstart;
1641 
1642       /* Set matrix entries for conntected vertices */
1643       ierr = DMNetworkGetConnectedVertices(dm,e,&cone);CHKERRQ(ierr);
1644       for (v=0; v<2; v++) {
1645         ierr = DMNetworkGetVariableGlobalOffset(dm,cone[v],&cstart);CHKERRQ(ierr);
1646         ierr = DMNetworkGetNumVariables(dm,cone[v],&ncols);CHKERRQ(ierr);
1647 
1648         Juser = network->Je[3*e+1+v]; /* Jacobian(e,v) */
1649         ierr = MatSetblock_private(Juser,nrows,rows,ncols,cstart,J);CHKERRQ(ierr);
1650       }
1651 
1652       /* Set matrix entries for edge self */
1653       cstart = rstart;
1654       Juser = network->Je[3*e]; /* Jacobian(e,e) */
1655       ierr = MatSetblock_private(Juser,nrows,rows,nrows,cstart,J);CHKERRQ(ierr);
1656     }
1657   }
1658 
1659   /* Set matrix entries for vertices */
1660   /*---------------------------------*/
1661   for (v=vStart; v<vEnd; v++) {
1662     /* Get row indices */
1663     ierr = DMNetworkGetVariableGlobalOffset(dm,v,&rstart);CHKERRQ(ierr);
1664     ierr = DMNetworkGetNumVariables(dm,v,&nrows);CHKERRQ(ierr);
1665     if (!nrows) continue;
1666 
1667     ierr = DMNetworkIsGhostVertex(dm,v,&ghost);CHKERRQ(ierr);
1668     if (ghost) {
1669       ierr = PetscMalloc1(nrows,&rows_v);CHKERRQ(ierr);
1670     } else {
1671       rows_v = rows;
1672     }
1673     for (j=0; j<nrows; j++) rows_v[j] = j + rstart;
1674 
1675     /* Get supporting edges and connected vertices */
1676     ierr = DMNetworkGetSupportingEdges(dm,v,&nedges,&edges);CHKERRQ(ierr);
1677 
1678     for (e=0; e<nedges; e++) {
1679       /* Supporting edges */
1680       ierr = DMNetworkGetVariableGlobalOffset(dm,edges[e],&cstart);CHKERRQ(ierr);
1681       ierr = DMNetworkGetNumVariables(dm,edges[e],&ncols);CHKERRQ(ierr);
1682 
1683       Juser = network->Jv[vptr[v-vStart]+2*e+1]; /* Jacobian(v,e) */
1684       ierr = MatSetblock_private(Juser,nrows,rows_v,ncols,cstart,J);CHKERRQ(ierr);
1685 
1686       /* Connected vertices */
1687       ierr = DMNetworkGetConnectedVertices(dm,edges[e],&cone);CHKERRQ(ierr);
1688       vc = (v == cone[0]) ? cone[1]:cone[0];
1689 
1690       ierr = DMNetworkGetVariableGlobalOffset(dm,vc,&cstart);CHKERRQ(ierr);
1691       ierr = DMNetworkGetNumVariables(dm,vc,&ncols);CHKERRQ(ierr);
1692 
1693       Juser = network->Jv[vptr[v-vStart]+2*e+2]; /* Jacobian(v,vc) */
1694       ierr = MatSetblock_private(Juser,nrows,rows_v,ncols,cstart,J);CHKERRQ(ierr);
1695     }
1696 
1697     /* Set matrix entries for vertex self */
1698     if (!ghost) {
1699       ierr = DMNetworkGetVariableGlobalOffset(dm,v,&cstart);CHKERRQ(ierr);
1700       Juser = network->Jv[vptr[v-vStart]]; /* Jacobian(v,v) */
1701       ierr = MatSetblock_private(Juser,nrows,rows_v,nrows,cstart,J);CHKERRQ(ierr);
1702     }
1703     if (ghost) {
1704       ierr = PetscFree(rows_v);CHKERRQ(ierr);
1705     }
1706   }
1707   ierr = PetscFree(rows);CHKERRQ(ierr);
1708 
1709   ierr = MatAssemblyBegin(*J,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1710   ierr = MatAssemblyEnd(*J,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1711 
1712   ierr = MatSetDM(*J,dm);CHKERRQ(ierr);
1713   PetscFunctionReturn(0);
1714 }
1715 
1716 PetscErrorCode DMDestroy_Network(DM dm)
1717 {
1718   PetscErrorCode ierr;
1719   DM_Network     *network = (DM_Network*) dm->data;
1720   PetscInt       j;
1721 
1722   PetscFunctionBegin;
1723   if (--network->refct > 0) PetscFunctionReturn(0);
1724   if (network->Je) {
1725     ierr = PetscFree(network->Je);CHKERRQ(ierr);
1726   }
1727   if (network->Jv) {
1728     ierr = PetscFree(network->Jvptr);CHKERRQ(ierr);
1729     ierr = PetscFree(network->Jv);CHKERRQ(ierr);
1730   }
1731 
1732   ierr = ISLocalToGlobalMappingDestroy(&network->vertex.mapping);CHKERRQ(ierr);
1733   ierr = PetscSectionDestroy(&network->vertex.DofSection);CHKERRQ(ierr);
1734   ierr = PetscSectionDestroy(&network->vertex.GlobalDofSection);CHKERRQ(ierr);
1735   if (network->vertex.sf) {
1736     ierr = PetscSFDestroy(&network->vertex.sf);CHKERRQ(ierr);
1737   }
1738   /* edge */
1739   ierr = ISLocalToGlobalMappingDestroy(&network->edge.mapping);CHKERRQ(ierr);
1740   ierr = PetscSectionDestroy(&network->edge.DofSection);CHKERRQ(ierr);
1741   ierr = PetscSectionDestroy(&network->edge.GlobalDofSection);CHKERRQ(ierr);
1742   if (network->edge.sf) {
1743     ierr = PetscSFDestroy(&network->edge.sf);CHKERRQ(ierr);
1744   }
1745   ierr = DMDestroy(&network->plex);CHKERRQ(ierr);
1746   network->edges = NULL;
1747   ierr = PetscSectionDestroy(&network->DataSection);CHKERRQ(ierr);
1748   ierr = PetscSectionDestroy(&network->DofSection);CHKERRQ(ierr);
1749 
1750   for(j=0; j < network->nsubnet; j++) {
1751     ierr = PetscFree(network->subnet[j].edges);CHKERRQ(ierr);
1752     ierr = PetscFree(network->subnet[j].vertices);CHKERRQ(ierr);
1753   }
1754   ierr = PetscFree(network->subnet);CHKERRQ(ierr);
1755   ierr = PetscFree(network->componentdataarray);CHKERRQ(ierr);
1756   ierr = PetscFree(network->cvalue);CHKERRQ(ierr);
1757   ierr = PetscFree(network->header);CHKERRQ(ierr);
1758   ierr = PetscFree(network);CHKERRQ(ierr);
1759   PetscFunctionReturn(0);
1760 }
1761 
1762 PetscErrorCode DMView_Network(DM dm, PetscViewer viewer)
1763 {
1764   PetscErrorCode ierr;
1765   DM_Network     *network = (DM_Network*) dm->data;
1766 
1767   PetscFunctionBegin;
1768   ierr = DMView(network->plex,viewer);CHKERRQ(ierr);
1769   PetscFunctionReturn(0);
1770 }
1771 
1772 PetscErrorCode DMGlobalToLocalBegin_Network(DM dm, Vec g, InsertMode mode, Vec l)
1773 {
1774   PetscErrorCode ierr;
1775   DM_Network     *network = (DM_Network*) dm->data;
1776 
1777   PetscFunctionBegin;
1778   ierr = DMGlobalToLocalBegin(network->plex,g,mode,l);CHKERRQ(ierr);
1779   PetscFunctionReturn(0);
1780 }
1781 
1782 PetscErrorCode DMGlobalToLocalEnd_Network(DM dm, Vec g, InsertMode mode, Vec l)
1783 {
1784   PetscErrorCode ierr;
1785   DM_Network     *network = (DM_Network*) dm->data;
1786 
1787   PetscFunctionBegin;
1788   ierr = DMGlobalToLocalEnd(network->plex,g,mode,l);CHKERRQ(ierr);
1789   PetscFunctionReturn(0);
1790 }
1791 
1792 PetscErrorCode DMLocalToGlobalBegin_Network(DM dm, Vec l, InsertMode mode, Vec g)
1793 {
1794   PetscErrorCode ierr;
1795   DM_Network     *network = (DM_Network*) dm->data;
1796 
1797   PetscFunctionBegin;
1798   ierr = DMLocalToGlobalBegin(network->plex,l,mode,g);CHKERRQ(ierr);
1799   PetscFunctionReturn(0);
1800 }
1801 
1802 PetscErrorCode DMLocalToGlobalEnd_Network(DM dm, Vec l, InsertMode mode, Vec g)
1803 {
1804   PetscErrorCode ierr;
1805   DM_Network     *network = (DM_Network*) dm->data;
1806 
1807   PetscFunctionBegin;
1808   ierr = DMLocalToGlobalEnd(network->plex,l,mode,g);CHKERRQ(ierr);
1809   PetscFunctionReturn(0);
1810 }
1811