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