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