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