xref: /petsc/src/dm/impls/network/network.c (revision 5bc9b31f8b5bce8bec0959439fb2f3e131fe48a2)
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->nVertices >= 0 || network->NVertices >= 0) && (network->nVertices != nV || network->NVertices != 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->nVertices,network->NVertices);
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->nVertices = nV;
68   network->NVertices = 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->nVertices) {
130     ierr = PetscCalloc1(numCorners*network->nVertices,&vertexcoords);CHKERRQ(ierr);
131   }
132   ierr = DMPlexCreateFromCellList(PetscObjectComm((PetscObject)dm),dim,network->nEdges,network->nVertices,numCorners,PETSC_FALSE,network->edges,spacedim,vertexcoords,&network->plex);CHKERRQ(ierr);
133   if (network->nVertices) {
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   DMNetworkGetComponentKeyOffset - 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       DMNetworkGetComponentKeyOffset(dm,v,compnum,&key,&offset);
409       compdata = (UserCompDataType)(arr+offset);
410 
411   Level: intermediate
412 
413 .seealso: DMNetworkGetNumComponents, DMNetworkGetComponentDataArray,
414 @*/
415 PetscErrorCode DMNetworkGetComponentKeyOffset(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 vertex */
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: DMNetworkGetComponentKeyOffset, 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->nVertices = newDMnetwork->vEnd - newDMnetwork->vStart;
834   newDMnetwork->NVertices = oldDMnetwork->NVertices;
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   PetscFunctionReturn(0);
907 }
908 
909 /*@C
910   DMNetworkGetSupportingEdges - Return the supporting edges for this vertex point
911 
912   Not Collective
913 
914   Input Parameters:
915 + dm - The DMNetwork object
916 - p  - the vertex point
917 
918   Output Paramters:
919 + nedges - number of edges connected to this vertex point
920 - edges  - List of edge points
921 
922   Level: intermediate
923 
924   Fortran Notes:
925   Since it returns an array, this routine is only available in Fortran 90, and you must
926   include petsc.h90 in your code.
927 
928 .seealso: DMNetworkCreate, DMNetworkGetConnectedVertices
929 @*/
930 PetscErrorCode DMNetworkGetSupportingEdges(DM dm,PetscInt vertex,PetscInt *nedges,const PetscInt *edges[])
931 {
932   PetscErrorCode ierr;
933   DM_Network     *network = (DM_Network*)dm->data;
934 
935   PetscFunctionBegin;
936   ierr = DMPlexGetSupportSize(network->plex,vertex,nedges);CHKERRQ(ierr);
937   ierr = DMPlexGetSupport(network->plex,vertex,edges);CHKERRQ(ierr);
938   PetscFunctionReturn(0);
939 }
940 
941 /*@C
942   DMNetworkGetConnectedVertices - Return the connected vertices for this edge point
943 
944   Not Collective
945 
946   Input Parameters:
947 + dm - The DMNetwork object
948 - p  - the edge point
949 
950   Output Paramters:
951 . vertices  - vertices connected to this edge
952 
953   Level: intermediate
954 
955   Fortran Notes:
956   Since it returns an array, this routine is only available in Fortran 90, and you must
957   include petsc.h90 in your code.
958 
959 .seealso: DMNetworkCreate, DMNetworkGetSupportingEdges
960 @*/
961 PetscErrorCode DMNetworkGetConnectedVertices(DM dm,PetscInt edge,const PetscInt *vertices[])
962 {
963   PetscErrorCode ierr;
964   DM_Network     *network = (DM_Network*)dm->data;
965 
966   PetscFunctionBegin;
967   ierr = DMPlexGetCone(network->plex,edge,vertices);CHKERRQ(ierr);
968   PetscFunctionReturn(0);
969 }
970 
971 /*@
972   DMNetworkIsGhostVertex - Returns TRUE if the vertex is a ghost vertex
973 
974   Not Collective
975 
976   Input Parameters:
977 + dm - The DMNetwork object
978 . p  - the vertex point
979 
980   Output Parameter:
981 . isghost - TRUE if the vertex is a ghost point
982 
983   Level: intermediate
984 
985 .seealso: DMNetworkCreate, DMNetworkGetConnectedVertices, DMNetworkGetVertexRange
986 @*/
987 PetscErrorCode DMNetworkIsGhostVertex(DM dm,PetscInt p,PetscBool *isghost)
988 {
989   PetscErrorCode ierr;
990   DM_Network     *network = (DM_Network*)dm->data;
991   PetscInt       offsetg;
992   PetscSection   sectiong;
993 
994   PetscFunctionBegin;
995   *isghost = PETSC_FALSE;
996   ierr = DMGetDefaultGlobalSection(network->plex,&sectiong);CHKERRQ(ierr);
997   ierr = PetscSectionGetOffset(sectiong,p,&offsetg);CHKERRQ(ierr);
998   if (offsetg < 0) *isghost = PETSC_TRUE;
999   PetscFunctionReturn(0);
1000 }
1001 
1002 PetscErrorCode DMSetUp_Network(DM dm)
1003 {
1004   PetscErrorCode ierr;
1005   DM_Network     *network=(DM_Network*)dm->data;
1006 
1007   PetscFunctionBegin;
1008   ierr = DMNetworkComponentSetUp(dm);CHKERRQ(ierr);
1009   ierr = DMNetworkVariablesSetUp(dm);CHKERRQ(ierr);
1010 
1011   ierr = DMSetDefaultSection(network->plex,network->DofSection);CHKERRQ(ierr);
1012   ierr = DMGetDefaultGlobalSection(network->plex,&network->GlobalDofSection);CHKERRQ(ierr);
1013   PetscFunctionReturn(0);
1014 }
1015 
1016 /*@
1017     DMNetworkHasJacobian - Sets global flag for using user's sub Jacobian matrices
1018                             -- replaced by DMNetworkSetOption(network,userjacobian,PETSC_TURE)?
1019 
1020     Collective
1021 
1022     Input Parameters:
1023 +   dm - The DMNetwork object
1024 .   eflg - turn the option on (PETSC_TRUE) or off (PETSC_FALSE) if user provides Jacobian for edges
1025 -   vflg - turn the option on (PETSC_TRUE) or off (PETSC_FALSE) if user provides Jacobian for vertices
1026 
1027     Level: intermediate
1028 
1029 @*/
1030 PetscErrorCode DMNetworkHasJacobian(DM dm,PetscBool eflg,PetscBool vflg)
1031 {
1032   DM_Network     *network=(DM_Network*)dm->data;
1033 
1034   PetscFunctionBegin;
1035   network->userEdgeJacobian   = eflg;
1036   network->userVertexJacobian = vflg;
1037   PetscFunctionReturn(0);
1038 }
1039 
1040 /*@
1041     DMNetworkEdgeSetMatrix - Sets user-provided Jacobian matrices for this edge to the network
1042 
1043     Not Collective
1044 
1045     Input Parameters:
1046 +   dm - The DMNetwork object
1047 .   p  - the edge point
1048 -   J - array (size = 3) of Jacobian submatrices for this edge point:
1049         J[0]: this edge
1050         J[1] and J[2]: connected vertices, obtained by calling DMNetworkGetConnectedVertices()
1051 
1052     Level: intermediate
1053 
1054 .seealso: DMNetworkVertexSetMatrix
1055 @*/
1056 PetscErrorCode DMNetworkEdgeSetMatrix(DM dm,PetscInt p,Mat J[])
1057 {
1058   PetscErrorCode ierr;
1059   DM_Network     *network=(DM_Network*)dm->data;
1060 
1061   PetscFunctionBegin;
1062   if (!network->userEdgeJacobian) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ORDER,"Must call DMNetworkHasJacobian() collectively before calling DMNetworkEdgeSetMatrix");
1063   if (!network->Je) {
1064     ierr = PetscCalloc1(3*network->nEdges,&network->Je);CHKERRQ(ierr);
1065   }
1066   network->Je[3*p]   = J[0];
1067   network->Je[3*p+1] = J[1];
1068   network->Je[3*p+2] = J[2];
1069   PetscFunctionReturn(0);
1070 }
1071 
1072 /*@
1073     DMNetworkVertexSetMatrix - Sets user-provided Jacobian matrix for this vertex to the network
1074 
1075     Not Collective
1076 
1077     Input Parameters:
1078 +   dm - The DMNetwork object
1079 .   p  - the vertex point
1080 -   J - array of Jacobian (size = 2*(num of supporting edges) + 1) submatrices for this vertex point:
1081         J[0]:       this vertex
1082         J[1+2*i]:   i-th supporting edge
1083         J[1+2*i+1]: i-th connected vertex
1084 
1085     Level: intermediate
1086 
1087 .seealso: DMNetworkEdgeSetMatrix
1088 @*/
1089 PetscErrorCode DMNetworkVertexSetMatrix(DM dm,PetscInt p,Mat J[])
1090 {
1091   PetscErrorCode ierr;
1092   DM_Network     *network=(DM_Network*)dm->data;
1093   PetscInt       i,*vptr,nedges,vStart,vEnd;
1094   const PetscInt *edges;
1095 
1096   PetscFunctionBegin;
1097   if (!network->userVertexJacobian) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ORDER,"Must call DMNetworkHasJacobian() collectively before calling DMNetworkVertexSetMatrix");
1098 
1099   ierr = DMNetworkGetVertexRange(dm,&vStart,&vEnd);CHKERRQ(ierr);
1100 
1101   if (!network->Jv) {
1102     PetscInt nVertices = network->nVertices,nedges_total;
1103     /* count nvertex_total */
1104     nedges_total = 0;
1105     ierr = DMNetworkGetVertexRange(dm,&vStart,&vEnd);CHKERRQ(ierr);
1106     ierr = PetscMalloc1(nVertices+1,&vptr);CHKERRQ(ierr);
1107 
1108     vptr[0] = 0;
1109     for (i=0; i<nVertices; i++) {
1110       ierr = DMNetworkGetSupportingEdges(dm,i+vStart,&nedges,&edges);CHKERRQ(ierr);
1111       nedges_total += nedges;
1112       vptr[i+1] = vptr[i] + 2*nedges + 1;
1113     }
1114 
1115     ierr = PetscCalloc1(2*nedges_total+nVertices,&network->Jv);CHKERRQ(ierr);
1116     network->Jvptr = vptr;
1117   }
1118 
1119   vptr = network->Jvptr;
1120   network->Jv[vptr[p-vStart]] = J[0]; /* Set Jacobian for this vertex */
1121 
1122   /* Set Jacobian for each supporting edge and connected vertex */
1123   ierr = DMNetworkGetSupportingEdges(dm,p,&nedges,&edges);CHKERRQ(ierr);
1124   for (i=1; i<=2*nedges; i++) network->Jv[vptr[p-vStart]+i] = J[i];
1125   PetscFunctionReturn(0);
1126 }
1127 
1128 PETSC_STATIC_INLINE PetscErrorCode MatSetPreallocationDenseblock_private(PetscInt nrows,PetscInt *rows,PetscInt ncols,PetscBool ghost,Vec vdnz,Vec vonz)
1129 {
1130   PetscErrorCode ierr;
1131   PetscInt       j;
1132   PetscScalar    val=(PetscScalar)ncols;
1133 
1134   PetscFunctionBegin;
1135   if (!ghost) {
1136     for (j=0; j<nrows; j++) {
1137       ierr = VecSetValues(vdnz,1,&rows[j],&val,ADD_VALUES);CHKERRQ(ierr);
1138     }
1139   } else {
1140     for (j=0; j<nrows; j++) {
1141       ierr = VecSetValues(vonz,1,&rows[j],&val,ADD_VALUES);CHKERRQ(ierr);
1142     }
1143   }
1144   PetscFunctionReturn(0);
1145 }
1146 
1147 PETSC_STATIC_INLINE PetscErrorCode MatSetPreallocationUserblock_private(Mat Ju,PetscInt nrows,PetscInt *rows,PetscInt ncols,PetscBool ghost,Vec vdnz,Vec vonz)
1148 {
1149   PetscErrorCode ierr;
1150   PetscInt       j,ncols_u;
1151   PetscScalar    val;
1152 
1153   PetscFunctionBegin;
1154   if (!ghost) {
1155     for (j=0; j<nrows; j++) {
1156       ierr = MatGetRow(Ju,j,&ncols_u,NULL,NULL);CHKERRQ(ierr);
1157       val = (PetscScalar)ncols_u;
1158       ierr = VecSetValues(vdnz,1,&rows[j],&val,ADD_VALUES);CHKERRQ(ierr);
1159       ierr = MatRestoreRow(Ju,j,&ncols_u,NULL,NULL);CHKERRQ(ierr);
1160     }
1161   } else {
1162     for (j=0; j<nrows; j++) {
1163       ierr = MatGetRow(Ju,j,&ncols_u,NULL,NULL);CHKERRQ(ierr);
1164       val = (PetscScalar)ncols_u;
1165       ierr = VecSetValues(vonz,1,&rows[j],&val,ADD_VALUES);CHKERRQ(ierr);
1166       ierr = MatRestoreRow(Ju,j,&ncols_u,NULL,NULL);CHKERRQ(ierr);
1167     }
1168   }
1169   PetscFunctionReturn(0);
1170 }
1171 
1172 PETSC_STATIC_INLINE PetscErrorCode MatSetPreallocationblock_private(Mat Ju,PetscInt nrows,PetscInt *rows,PetscInt ncols,PetscBool ghost,Vec vdnz,Vec vonz)
1173 {
1174   PetscErrorCode ierr;
1175 
1176   PetscFunctionBegin;
1177   if (Ju) {
1178     ierr = MatSetPreallocationUserblock_private(Ju,nrows,rows,ncols,ghost,vdnz,vonz);CHKERRQ(ierr);
1179   } else {
1180     ierr = MatSetPreallocationDenseblock_private(nrows,rows,ncols,ghost,vdnz,vonz);CHKERRQ(ierr);
1181   }
1182   PetscFunctionReturn(0);
1183 }
1184 
1185 PETSC_STATIC_INLINE PetscErrorCode MatSetDenseblock_private(PetscInt nrows,PetscInt *rows,PetscInt ncols,PetscInt cstart,Mat *J)
1186 {
1187   PetscErrorCode ierr;
1188   PetscInt       j,*cols;
1189   PetscScalar    *zeros;
1190 
1191   PetscFunctionBegin;
1192   ierr = PetscCalloc2(ncols,&cols,nrows*ncols,&zeros);CHKERRQ(ierr);
1193   for (j=0; j<ncols; j++) cols[j] = j+ cstart;
1194   ierr = MatSetValues(*J,nrows,rows,ncols,cols,zeros,INSERT_VALUES);CHKERRQ(ierr);
1195   ierr = PetscFree2(cols,zeros);CHKERRQ(ierr);
1196   PetscFunctionReturn(0);
1197 }
1198 
1199 PETSC_STATIC_INLINE PetscErrorCode MatSetUserblock_private(Mat Ju,PetscInt nrows,PetscInt *rows,PetscInt ncols,PetscInt cstart,Mat *J)
1200 {
1201   PetscErrorCode ierr;
1202   PetscInt       j,M,N,row,col,ncols_u;
1203   const PetscInt *cols;
1204   PetscScalar    zero=0.0;
1205 
1206   PetscFunctionBegin;
1207   ierr = MatGetSize(Ju,&M,&N);CHKERRQ(ierr);
1208   if (nrows != M || ncols != N) SETERRQ4(PetscObjectComm((PetscObject)Ju),PETSC_ERR_USER,"%D by %D must equal %D by %D",nrows,ncols,M,N);
1209 
1210   for (row=0; row<nrows; row++) {
1211     ierr = MatGetRow(Ju,row,&ncols_u,&cols,NULL);CHKERRQ(ierr);
1212     for (j=0; j<ncols_u; j++) {
1213       col = cols[j] + cstart;
1214       ierr = MatSetValues(*J,1,&rows[row],1,&col,&zero,INSERT_VALUES);CHKERRQ(ierr);
1215     }
1216     ierr = MatRestoreRow(Ju,row,&ncols_u,&cols,NULL);CHKERRQ(ierr);
1217   }
1218   PetscFunctionReturn(0);
1219 }
1220 
1221 PETSC_STATIC_INLINE PetscErrorCode MatSetblock_private(Mat Ju,PetscInt nrows,PetscInt *rows,PetscInt ncols,PetscInt cstart,Mat *J)
1222 {
1223   PetscErrorCode ierr;
1224 
1225   PetscFunctionBegin;
1226   if (Ju) {
1227     ierr = MatSetUserblock_private(Ju,nrows,rows,ncols,cstart,J);CHKERRQ(ierr);
1228   } else {
1229     ierr = MatSetDenseblock_private(nrows,rows,ncols,cstart,J);CHKERRQ(ierr);
1230   }
1231   PetscFunctionReturn(0);
1232 }
1233 
1234 /* 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.
1235 */
1236 PetscErrorCode CreateSubGlobalToLocalMapping_private(PetscSection globalsec, PetscSection localsec, ISLocalToGlobalMapping *ltog)
1237 {
1238   PetscErrorCode ierr;
1239   PetscInt       i, size, dof;
1240   PetscInt       *glob2loc;
1241 
1242   PetscFunctionBegin;
1243   ierr = PetscSectionGetStorageSize(localsec,&size);CHKERRQ(ierr);
1244   ierr = PetscMalloc1(size,&glob2loc);CHKERRQ(ierr);
1245 
1246   for (i = 0; i < size; i++) {
1247     ierr = PetscSectionGetOffset(globalsec,i,&dof);CHKERRQ(ierr);
1248     dof = (dof >= 0) ? dof : -(dof + 1);
1249     glob2loc[i] = dof;
1250   }
1251 
1252   ierr = ISLocalToGlobalMappingCreate(PETSC_COMM_WORLD,1,size,glob2loc,PETSC_OWN_POINTER,ltog);CHKERRQ(ierr);
1253 #if 0
1254   ierr = PetscIntView(size,glob2loc,PETSC_VIEWER_STDOUT_WORLD);CHKERRQ(ierr);
1255 #endif
1256   PetscFunctionReturn(0);
1257 }
1258 
1259 #include <petsc/private/matimpl.h>
1260 PetscErrorCode DMCreateMatrix_Network(DM dm,Mat *J)
1261 {
1262   PetscErrorCode ierr;
1263   PetscMPIInt    rank, size;
1264   DM_Network     *network = (DM_Network*) dm->data;
1265   PetscInt       eStart,eEnd,vStart,vEnd,rstart,nrows,*rows,localSize;
1266   PetscInt       cstart,ncols,j,e,v;
1267   PetscBool      ghost,ghost_vc,ghost2,isNest;
1268   Mat            Juser;
1269   PetscSection   sectionGlobal;
1270   PetscInt       nedges,*vptr=NULL,vc,*rows_v; /* suppress maybe-uninitialized warning */
1271   const PetscInt *edges,*cone;
1272   MPI_Comm       comm;
1273   MatType        mtype;
1274   Vec            vd_nz,vo_nz;
1275   PetscInt       *dnnz,*onnz;
1276   PetscScalar    *vdnz,*vonz;
1277 
1278   PetscFunctionBegin;
1279   mtype = dm->mattype;
1280   ierr = PetscStrcmp(mtype, MATNEST, &isNest);CHKERRQ(ierr);
1281 
1282   if (isNest) {
1283     /* ierr = DMCreateMatrix_Network_Nest(); */
1284     PetscInt   eDof, vDof;
1285     Mat        j11, j12, j21, j22, bA[2][2];
1286     ISLocalToGlobalMapping eISMap, vISMap;
1287 
1288     ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
1289     ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
1290     ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr);
1291 
1292     ierr = PetscSectionGetConstrainedStorageSize(network->edge.GlobalDofSection,&eDof);CHKERRQ(ierr);
1293     ierr = PetscSectionGetConstrainedStorageSize(network->vertex.GlobalDofSection,&vDof);CHKERRQ(ierr);
1294 
1295     ierr = MatCreate(comm, &j11);CHKERRQ(ierr);
1296     ierr = MatSetSizes(j11, eDof, eDof, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
1297     ierr = MatSetType(j11, MATMPIAIJ);CHKERRQ(ierr);
1298 
1299     ierr = MatCreate(comm, &j12);CHKERRQ(ierr);
1300     ierr = MatSetSizes(j12, eDof, vDof, PETSC_DETERMINE ,PETSC_DETERMINE);CHKERRQ(ierr);
1301     ierr = MatSetType(j12, MATMPIAIJ);CHKERRQ(ierr);
1302 
1303     ierr = MatCreate(comm, &j21);CHKERRQ(ierr);
1304     ierr = MatSetSizes(j21, vDof, eDof, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
1305     ierr = MatSetType(j21, MATMPIAIJ);CHKERRQ(ierr);
1306 
1307     ierr = MatCreate(comm, &j22);CHKERRQ(ierr);
1308     ierr = MatSetSizes(j22, vDof, vDof, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
1309     ierr = MatSetType(j22, MATMPIAIJ);CHKERRQ(ierr);
1310 
1311     bA[0][0] = j11;
1312     bA[0][1] = j12;
1313     bA[1][0] = j21;
1314     bA[1][1] = j22;
1315 
1316     ierr = CreateSubGlobalToLocalMapping_private(network->edge.GlobalDofSection,network->edge.DofSection,&eISMap);CHKERRQ(ierr);
1317     ierr = CreateSubGlobalToLocalMapping_private(network->vertex.GlobalDofSection,network->vertex.DofSection,&vISMap);CHKERRQ(ierr);
1318 
1319     ierr = MatSetLocalToGlobalMapping(j11,eISMap,eISMap);CHKERRQ(ierr);
1320     ierr = MatSetLocalToGlobalMapping(j12,eISMap,vISMap);CHKERRQ(ierr);
1321     ierr = MatSetLocalToGlobalMapping(j21,vISMap,eISMap);CHKERRQ(ierr);
1322     ierr = MatSetLocalToGlobalMapping(j22,vISMap,vISMap);CHKERRQ(ierr);
1323 
1324     ierr = MatSetUp(j11);CHKERRQ(ierr);
1325     ierr = MatSetUp(j12);CHKERRQ(ierr);
1326     ierr = MatSetUp(j21);CHKERRQ(ierr);
1327     ierr = MatSetUp(j22);CHKERRQ(ierr);
1328 
1329     ierr = MatCreateNest(comm,2,NULL,2,NULL,&bA[0][0],J);CHKERRQ(ierr);
1330     ierr = MatSetUp(*J);CHKERRQ(ierr);
1331     ierr = MatNestSetVecType(*J,VECNEST);CHKERRQ(ierr);
1332     ierr = MatDestroy(&j11);CHKERRQ(ierr);
1333     ierr = MatDestroy(&j12);CHKERRQ(ierr);
1334     ierr = MatDestroy(&j21);CHKERRQ(ierr);
1335     ierr = MatDestroy(&j22);CHKERRQ(ierr);
1336 
1337     ierr = MatAssemblyBegin(*J,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1338     ierr = MatAssemblyEnd(*J,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1339 
1340     /* Free structures */
1341     ierr = ISLocalToGlobalMappingDestroy(&eISMap);CHKERRQ(ierr);
1342     ierr = ISLocalToGlobalMappingDestroy(&vISMap);CHKERRQ(ierr);
1343 
1344     PetscFunctionReturn(0);
1345   } else if (!network->userEdgeJacobian && !network->userVertexJacobian) {
1346     /* user does not provide Jacobian blocks */
1347     ierr = DMCreateMatrix(network->plex,J);CHKERRQ(ierr);
1348     ierr = MatSetDM(*J,dm);CHKERRQ(ierr);
1349     PetscFunctionReturn(0);
1350   }
1351 
1352   ierr = MatCreate(PetscObjectComm((PetscObject)dm),J);CHKERRQ(ierr);
1353   ierr = DMGetDefaultGlobalSection(network->plex,&sectionGlobal);CHKERRQ(ierr);
1354   ierr = PetscSectionGetConstrainedStorageSize(sectionGlobal,&localSize);CHKERRQ(ierr);
1355   ierr = MatSetSizes(*J,localSize,localSize,PETSC_DETERMINE,PETSC_DETERMINE);CHKERRQ(ierr);
1356 
1357   ierr = MatSetType(*J,MATAIJ);CHKERRQ(ierr);
1358   ierr = MatSetFromOptions(*J);CHKERRQ(ierr);
1359 
1360   /* (1) Set matrix preallocation */
1361   /*------------------------------*/
1362   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
1363   ierr = VecCreate(comm,&vd_nz);CHKERRQ(ierr);
1364   ierr = VecSetSizes(vd_nz,localSize,PETSC_DECIDE);CHKERRQ(ierr);
1365   ierr = VecSetFromOptions(vd_nz);CHKERRQ(ierr);
1366   ierr = VecSet(vd_nz,0.0);CHKERRQ(ierr);
1367   ierr = VecDuplicate(vd_nz,&vo_nz);CHKERRQ(ierr);
1368 
1369   /* Set preallocation for edges */
1370   /*-----------------------------*/
1371   ierr = DMNetworkGetEdgeRange(dm,&eStart,&eEnd);CHKERRQ(ierr);
1372 
1373   ierr = PetscMalloc1(localSize,&rows);CHKERRQ(ierr);
1374   for (e=eStart; e<eEnd; e++) {
1375     /* Get row indices */
1376     ierr = DMNetworkGetVariableGlobalOffset(dm,e,&rstart);CHKERRQ(ierr);
1377     ierr = DMNetworkGetNumVariables(dm,e,&nrows);CHKERRQ(ierr);
1378     if (nrows) {
1379       if (!network->Je) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NULL,"Uer must provide Je");
1380       for (j=0; j<nrows; j++) rows[j] = j + rstart;
1381 
1382       /* Set preallocation for conntected vertices */
1383       ierr = DMNetworkGetConnectedVertices(dm,e,&cone);CHKERRQ(ierr);
1384       for (v=0; v<2; v++) {
1385         ierr = DMNetworkGetNumVariables(dm,cone[v],&ncols);CHKERRQ(ierr);
1386 
1387         Juser = network->Je[3*e+1+v]; /* Jacobian(e,v) */
1388         ierr = DMNetworkIsGhostVertex(dm,cone[v],&ghost);CHKERRQ(ierr);
1389         ierr = MatSetPreallocationblock_private(Juser,nrows,rows,ncols,ghost,vd_nz,vo_nz);CHKERRQ(ierr);
1390       }
1391 
1392       /* Set preallocation for edge self */
1393       cstart = rstart;
1394       Juser = network->Je[3*e]; /* Jacobian(e,e) */
1395       ierr = MatSetPreallocationblock_private(Juser,nrows,rows,nrows,PETSC_FALSE,vd_nz,vo_nz);CHKERRQ(ierr);
1396     }
1397   }
1398 
1399   /* Set preallocation for vertices */
1400   /*--------------------------------*/
1401   ierr = DMNetworkGetVertexRange(dm,&vStart,&vEnd);CHKERRQ(ierr);
1402   if (vEnd - vStart) {
1403     if (!network->Jv) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NULL,"Uer must provide Jv");
1404     vptr = network->Jvptr;
1405     if (!vptr) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NULL,"Uer must provide vptr");
1406   }
1407 
1408   for (v=vStart; v<vEnd; v++) {
1409     /* Get row indices */
1410     ierr = DMNetworkGetVariableGlobalOffset(dm,v,&rstart);CHKERRQ(ierr);
1411     ierr = DMNetworkGetNumVariables(dm,v,&nrows);CHKERRQ(ierr);
1412     if (!nrows) continue;
1413 
1414     ierr = DMNetworkIsGhostVertex(dm,v,&ghost);CHKERRQ(ierr);
1415     if (ghost) {
1416       ierr = PetscMalloc1(nrows,&rows_v);CHKERRQ(ierr);
1417     } else {
1418       rows_v = rows;
1419     }
1420 
1421     for (j=0; j<nrows; j++) rows_v[j] = j + rstart;
1422 
1423     /* Get supporting edges and connected vertices */
1424     ierr = DMNetworkGetSupportingEdges(dm,v,&nedges,&edges);CHKERRQ(ierr);
1425 
1426     for (e=0; e<nedges; e++) {
1427       /* Supporting edges */
1428       ierr = DMNetworkGetVariableGlobalOffset(dm,edges[e],&cstart);CHKERRQ(ierr);
1429       ierr = DMNetworkGetNumVariables(dm,edges[e],&ncols);CHKERRQ(ierr);
1430 
1431       Juser = network->Jv[vptr[v-vStart]+2*e+1]; /* Jacobian(v,e) */
1432       ierr = MatSetPreallocationblock_private(Juser,nrows,rows_v,ncols,ghost,vd_nz,vo_nz);CHKERRQ(ierr);
1433 
1434       /* Connected vertices */
1435       ierr = DMNetworkGetConnectedVertices(dm,edges[e],&cone);CHKERRQ(ierr);
1436       vc = (v == cone[0]) ? cone[1]:cone[0];
1437       ierr = DMNetworkIsGhostVertex(dm,vc,&ghost_vc);CHKERRQ(ierr);
1438 
1439       ierr = DMNetworkGetNumVariables(dm,vc,&ncols);CHKERRQ(ierr);
1440 
1441       Juser = network->Jv[vptr[v-vStart]+2*e+2]; /* Jacobian(v,vc) */
1442       if (ghost_vc||ghost) {
1443         ghost2 = PETSC_TRUE;
1444       } else {
1445         ghost2 = PETSC_FALSE;
1446       }
1447       ierr = MatSetPreallocationblock_private(Juser,nrows,rows_v,ncols,ghost2,vd_nz,vo_nz);CHKERRQ(ierr);
1448     }
1449 
1450     /* Set preallocation for vertex self */
1451     ierr = DMNetworkIsGhostVertex(dm,v,&ghost);CHKERRQ(ierr);
1452     if (!ghost) {
1453       ierr = DMNetworkGetVariableGlobalOffset(dm,v,&cstart);CHKERRQ(ierr);
1454       Juser = network->Jv[vptr[v-vStart]]; /* Jacobian(v,v) */
1455       ierr = MatSetPreallocationblock_private(Juser,nrows,rows_v,nrows,PETSC_FALSE,vd_nz,vo_nz);CHKERRQ(ierr);
1456     }
1457     if (ghost) {
1458       ierr = PetscFree(rows_v);CHKERRQ(ierr);
1459     }
1460   }
1461 
1462   ierr = VecAssemblyBegin(vd_nz);CHKERRQ(ierr);
1463   ierr = VecAssemblyBegin(vo_nz);CHKERRQ(ierr);
1464 
1465   ierr = PetscMalloc2(localSize,&dnnz,localSize,&onnz);CHKERRQ(ierr);
1466 
1467   ierr = VecAssemblyEnd(vd_nz);CHKERRQ(ierr);
1468   ierr = VecAssemblyEnd(vo_nz);CHKERRQ(ierr);
1469 
1470   ierr = VecGetArray(vd_nz,&vdnz);CHKERRQ(ierr);
1471   ierr = VecGetArray(vo_nz,&vonz);CHKERRQ(ierr);
1472   for (j=0; j<localSize; j++) {
1473     dnnz[j] = (PetscInt)PetscRealPart(vdnz[j]);
1474     onnz[j] = (PetscInt)PetscRealPart(vonz[j]);
1475   }
1476   ierr = VecRestoreArray(vd_nz,&vdnz);CHKERRQ(ierr);
1477   ierr = VecRestoreArray(vo_nz,&vonz);CHKERRQ(ierr);
1478   ierr = VecDestroy(&vd_nz);CHKERRQ(ierr);
1479   ierr = VecDestroy(&vo_nz);CHKERRQ(ierr);
1480 
1481   ierr = MatSeqAIJSetPreallocation(*J,0,dnnz);CHKERRQ(ierr);
1482   ierr = MatMPIAIJSetPreallocation(*J,0,dnnz,0,onnz);CHKERRQ(ierr);
1483   ierr = MatSetOption(*J,MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_TRUE);CHKERRQ(ierr);
1484 
1485   ierr = PetscFree2(dnnz,onnz);CHKERRQ(ierr);
1486 
1487   /* (2) Set matrix entries for edges */
1488   /*----------------------------------*/
1489   for (e=eStart; e<eEnd; e++) {
1490     /* Get row indices */
1491     ierr = DMNetworkGetVariableGlobalOffset(dm,e,&rstart);CHKERRQ(ierr);
1492     ierr = DMNetworkGetNumVariables(dm,e,&nrows);CHKERRQ(ierr);
1493     if (nrows) {
1494       if (!network->Je) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NULL,"Uer must provide Je");
1495 
1496       for (j=0; j<nrows; j++) rows[j] = j + rstart;
1497 
1498       /* Set matrix entries for conntected vertices */
1499       ierr = DMNetworkGetConnectedVertices(dm,e,&cone);CHKERRQ(ierr);
1500       for (v=0; v<2; v++) {
1501         ierr = DMNetworkGetVariableGlobalOffset(dm,cone[v],&cstart);CHKERRQ(ierr);
1502         ierr = DMNetworkGetNumVariables(dm,cone[v],&ncols);CHKERRQ(ierr);
1503 
1504         Juser = network->Je[3*e+1+v]; /* Jacobian(e,v) */
1505         ierr = MatSetblock_private(Juser,nrows,rows,ncols,cstart,J);CHKERRQ(ierr);
1506       }
1507 
1508       /* Set matrix entries for edge self */
1509       cstart = rstart;
1510       Juser = network->Je[3*e]; /* Jacobian(e,e) */
1511       ierr = MatSetblock_private(Juser,nrows,rows,nrows,cstart,J);CHKERRQ(ierr);
1512     }
1513   }
1514 
1515   /* Set matrix entries for vertices */
1516   /*---------------------------------*/
1517   for (v=vStart; v<vEnd; v++) {
1518     /* Get row indices */
1519     ierr = DMNetworkGetVariableGlobalOffset(dm,v,&rstart);CHKERRQ(ierr);
1520     ierr = DMNetworkGetNumVariables(dm,v,&nrows);CHKERRQ(ierr);
1521     if (!nrows) continue;
1522 
1523     ierr = DMNetworkIsGhostVertex(dm,v,&ghost);CHKERRQ(ierr);
1524     if (ghost) {
1525       ierr = PetscMalloc1(nrows,&rows_v);CHKERRQ(ierr);
1526     } else {
1527       rows_v = rows;
1528     }
1529     for (j=0; j<nrows; j++) rows_v[j] = j + rstart;
1530 
1531     /* Get supporting edges and connected vertices */
1532     ierr = DMNetworkGetSupportingEdges(dm,v,&nedges,&edges);CHKERRQ(ierr);
1533 
1534     for (e=0; e<nedges; e++) {
1535       /* Supporting edges */
1536       ierr = DMNetworkGetVariableGlobalOffset(dm,edges[e],&cstart);CHKERRQ(ierr);
1537       ierr = DMNetworkGetNumVariables(dm,edges[e],&ncols);CHKERRQ(ierr);
1538 
1539       Juser = network->Jv[vptr[v-vStart]+2*e+1]; /* Jacobian(v,e) */
1540       ierr = MatSetblock_private(Juser,nrows,rows_v,ncols,cstart,J);CHKERRQ(ierr);
1541 
1542       /* Connected vertices */
1543       ierr = DMNetworkGetConnectedVertices(dm,edges[e],&cone);CHKERRQ(ierr);
1544       vc = (v == cone[0]) ? cone[1]:cone[0];
1545 
1546       ierr = DMNetworkGetVariableGlobalOffset(dm,vc,&cstart);CHKERRQ(ierr);
1547       ierr = DMNetworkGetNumVariables(dm,vc,&ncols);CHKERRQ(ierr);
1548 
1549       Juser = network->Jv[vptr[v-vStart]+2*e+2]; /* Jacobian(v,vc) */
1550       ierr = MatSetblock_private(Juser,nrows,rows_v,ncols,cstart,J);CHKERRQ(ierr);
1551     }
1552 
1553     /* Set matrix entries for vertex self */
1554     if (!ghost) {
1555       ierr = DMNetworkGetVariableGlobalOffset(dm,v,&cstart);CHKERRQ(ierr);
1556       Juser = network->Jv[vptr[v-vStart]]; /* Jacobian(v,v) */
1557       ierr = MatSetblock_private(Juser,nrows,rows_v,nrows,cstart,J);CHKERRQ(ierr);
1558     }
1559     if (ghost) {
1560       ierr = PetscFree(rows_v);CHKERRQ(ierr);
1561     }
1562   }
1563   ierr = PetscFree(rows);CHKERRQ(ierr);
1564 
1565   ierr = MatAssemblyBegin(*J,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1566   ierr = MatAssemblyEnd(*J,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1567 
1568   ierr = MatSetDM(*J,dm);CHKERRQ(ierr);
1569   PetscFunctionReturn(0);
1570 }
1571 
1572 PetscErrorCode DMDestroy_Network(DM dm)
1573 {
1574   PetscErrorCode ierr;
1575   DM_Network     *network = (DM_Network*) dm->data;
1576 
1577   PetscFunctionBegin;
1578   if (--network->refct > 0) PetscFunctionReturn(0);
1579   if (network->Je) {
1580     ierr = PetscFree(network->Je);CHKERRQ(ierr);
1581   }
1582   if (network->Jv) {
1583     ierr = PetscFree(network->Jvptr);CHKERRQ(ierr);
1584     ierr = PetscFree(network->Jv);CHKERRQ(ierr);
1585   }
1586 
1587   ierr = ISLocalToGlobalMappingDestroy(&network->vertex.mapping);CHKERRQ(ierr);
1588   ierr = PetscSectionDestroy(&network->vertex.DofSection);CHKERRQ(ierr);
1589   ierr = PetscSectionDestroy(&network->vertex.GlobalDofSection);CHKERRQ(ierr);
1590   if (network->vertex.sf) {
1591     ierr = PetscSFDestroy(&network->vertex.sf);CHKERRQ(ierr);
1592   }
1593   /* edge */
1594   ierr = ISLocalToGlobalMappingDestroy(&network->edge.mapping);CHKERRQ(ierr);
1595   ierr = PetscSectionDestroy(&network->edge.DofSection);CHKERRQ(ierr);
1596   ierr = PetscSectionDestroy(&network->edge.GlobalDofSection);CHKERRQ(ierr);
1597   if (network->edge.sf) {
1598     ierr = PetscSFDestroy(&network->edge.sf);CHKERRQ(ierr);
1599   }
1600   ierr = DMDestroy(&network->plex);CHKERRQ(ierr);
1601   network->edges = NULL;
1602   ierr = PetscSectionDestroy(&network->DataSection);CHKERRQ(ierr);
1603   ierr = PetscSectionDestroy(&network->DofSection);CHKERRQ(ierr);
1604 
1605   ierr = PetscFree(network->componentdataarray);CHKERRQ(ierr);
1606   ierr = PetscFree(network->cvalue);CHKERRQ(ierr);
1607   ierr = PetscFree(network->header);CHKERRQ(ierr);
1608   ierr = PetscFree(network);CHKERRQ(ierr);
1609   PetscFunctionReturn(0);
1610 }
1611 
1612 PetscErrorCode DMView_Network(DM dm, PetscViewer viewer)
1613 {
1614   PetscErrorCode ierr;
1615   DM_Network     *network = (DM_Network*) dm->data;
1616 
1617   PetscFunctionBegin;
1618   ierr = DMView(network->plex,viewer);CHKERRQ(ierr);
1619   PetscFunctionReturn(0);
1620 }
1621 
1622 PetscErrorCode DMGlobalToLocalBegin_Network(DM dm, Vec g, InsertMode mode, Vec l)
1623 {
1624   PetscErrorCode ierr;
1625   DM_Network     *network = (DM_Network*) dm->data;
1626 
1627   PetscFunctionBegin;
1628   ierr = DMGlobalToLocalBegin(network->plex,g,mode,l);CHKERRQ(ierr);
1629   PetscFunctionReturn(0);
1630 }
1631 
1632 PetscErrorCode DMGlobalToLocalEnd_Network(DM dm, Vec g, InsertMode mode, Vec l)
1633 {
1634   PetscErrorCode ierr;
1635   DM_Network     *network = (DM_Network*) dm->data;
1636 
1637   PetscFunctionBegin;
1638   ierr = DMGlobalToLocalEnd(network->plex,g,mode,l);CHKERRQ(ierr);
1639   PetscFunctionReturn(0);
1640 }
1641 
1642 PetscErrorCode DMLocalToGlobalBegin_Network(DM dm, Vec l, InsertMode mode, Vec g)
1643 {
1644   PetscErrorCode ierr;
1645   DM_Network     *network = (DM_Network*) dm->data;
1646 
1647   PetscFunctionBegin;
1648   ierr = DMLocalToGlobalBegin(network->plex,l,mode,g);CHKERRQ(ierr);
1649   PetscFunctionReturn(0);
1650 }
1651 
1652 PetscErrorCode DMLocalToGlobalEnd_Network(DM dm, Vec l, InsertMode mode, Vec g)
1653 {
1654   PetscErrorCode ierr;
1655   DM_Network     *network = (DM_Network*) dm->data;
1656 
1657   PetscFunctionBegin;
1658   ierr = DMLocalToGlobalEnd(network->plex,l,mode,g);CHKERRQ(ierr);
1659   PetscFunctionReturn(0);
1660 }
1661