xref: /petsc/src/dm/impls/network/network.c (revision e91eccc2778f456fc991f5a9b142a3a67738bfd5)
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 PetscErrorCode DMCreateMatrix_Network(DM dm,Mat *J)
1260 {
1261   PetscErrorCode ierr;
1262   PetscMPIInt    rank, size;
1263   DM_Network     *network = (DM_Network*) dm->data;
1264   PetscInt       eStart,eEnd,vStart,vEnd,rstart,nrows,*rows,localSize;
1265   PetscInt       cstart,ncols,j,e,v;
1266   PetscBool      ghost,ghost_vc,ghost2,isNest;
1267   Mat            Juser;
1268   PetscSection   sectionGlobal;
1269   PetscInt       nedges,*vptr=NULL,vc,*rows_v; /* suppress maybe-uninitialized warning */
1270   const PetscInt *edges,*cone;
1271   MPI_Comm       comm;
1272   MatType        mtype;
1273   Vec            vd_nz,vo_nz;
1274   PetscInt       *dnnz,*onnz;
1275   PetscScalar    *vdnz,*vonz;
1276 
1277   PetscFunctionBegin;
1278   mtype = dm->mattype;
1279   ierr = PetscStrcmp(mtype, MATNEST, &isNest);CHKERRQ(ierr);
1280 
1281   if (isNest) {
1282     /* ierr = DMCreateMatrix_Network_Nest(); */
1283     PetscInt   eDof, vDof;
1284     Mat        j11, j12, j21, j22, bA[2][2];
1285     ISLocalToGlobalMapping eISMap, vISMap;
1286 
1287     ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
1288     ierr = MPI_Comm_rank(comm,&rank);CHKERRQ(ierr);
1289     ierr = MPI_Comm_size(comm,&size);CHKERRQ(ierr);
1290 
1291     ierr = PetscSectionGetConstrainedStorageSize(network->edge.GlobalDofSection,&eDof);CHKERRQ(ierr);
1292     ierr = PetscSectionGetConstrainedStorageSize(network->vertex.GlobalDofSection,&vDof);CHKERRQ(ierr);
1293 
1294     ierr = MatCreate(PETSC_COMM_WORLD, &j11);CHKERRQ(ierr);
1295     ierr = MatSetSizes(j11, eDof, eDof, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
1296     ierr = MatSetType(j11, MATMPIAIJ);CHKERRQ(ierr);
1297 
1298     ierr = MatCreate(PETSC_COMM_WORLD, &j12);CHKERRQ(ierr);
1299     ierr = MatSetSizes(j12, eDof, vDof, PETSC_DETERMINE ,PETSC_DETERMINE);CHKERRQ(ierr);
1300     ierr = MatSetType(j12, MATMPIAIJ);CHKERRQ(ierr);
1301 
1302     ierr = MatCreate(PETSC_COMM_WORLD, &j21);CHKERRQ(ierr);
1303     ierr = MatSetSizes(j21, vDof, eDof, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
1304     ierr = MatSetType(j21, MATMPIAIJ);CHKERRQ(ierr);
1305 
1306     ierr = MatCreate(PETSC_COMM_WORLD, &j22);CHKERRQ(ierr);
1307     ierr = MatSetSizes(j22, vDof, vDof, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
1308     ierr = MatSetType(j22, MATMPIAIJ);CHKERRQ(ierr);
1309 
1310     bA[0][0] = j11;
1311     bA[0][1] = j12;
1312     bA[1][0] = j21;
1313     bA[1][1] = j22;
1314 
1315     ierr = CreateSubGlobalToLocalMapping_private(network->edge.GlobalDofSection,network->edge.DofSection,&eISMap);CHKERRQ(ierr);
1316     ierr = CreateSubGlobalToLocalMapping_private(network->vertex.GlobalDofSection,network->vertex.DofSection,&vISMap);CHKERRQ(ierr);
1317 
1318     ierr = MatSetLocalToGlobalMapping(j11,eISMap,eISMap);CHKERRQ(ierr);
1319     ierr = MatSetLocalToGlobalMapping(j12,eISMap,vISMap);CHKERRQ(ierr);
1320     ierr = MatSetLocalToGlobalMapping(j21,vISMap,eISMap);CHKERRQ(ierr);
1321     ierr = MatSetLocalToGlobalMapping(j22,vISMap,vISMap);CHKERRQ(ierr);
1322 
1323     ierr = MatSetUp(j11);CHKERRQ(ierr);
1324     ierr = MatSetUp(j12);CHKERRQ(ierr);
1325     ierr = MatSetUp(j21);CHKERRQ(ierr);
1326     ierr = MatSetUp(j22);CHKERRQ(ierr);
1327 
1328     ierr = MatCreateNest(PETSC_COMM_WORLD,2,NULL,2,NULL,&bA[0][0],J);CHKERRQ(ierr);
1329     ierr = MatSetUp(*J);CHKERRQ(ierr);
1330     ierr = MatNestSetVecType(*J,VECNEST);CHKERRQ(ierr);
1331     ierr = MatDestroy(&j11);CHKERRQ(ierr);
1332     ierr = MatDestroy(&j12);CHKERRQ(ierr);
1333     ierr = MatDestroy(&j21);CHKERRQ(ierr);
1334     ierr = MatDestroy(&j22);CHKERRQ(ierr);
1335 
1336     ierr = MatAssemblyBegin(*J,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1337     ierr = MatAssemblyEnd(*J,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1338 
1339     /* Free structures */
1340     ierr = ISLocalToGlobalMappingDestroy(&eISMap);CHKERRQ(ierr);
1341     ierr = ISLocalToGlobalMappingDestroy(&vISMap);CHKERRQ(ierr);
1342 
1343     PetscFunctionReturn(0);
1344   } else if (!network->userEdgeJacobian && !network->userVertexJacobian) {
1345     /* user does not provide Jacobian blocks */
1346     ierr = DMCreateMatrix(network->plex,J);CHKERRQ(ierr);
1347     ierr = MatSetDM(*J,dm);CHKERRQ(ierr);
1348     PetscFunctionReturn(0);
1349   }
1350 
1351   ierr = MatCreate(PetscObjectComm((PetscObject)dm),J);CHKERRQ(ierr);
1352   ierr = DMGetDefaultGlobalSection(network->plex,&sectionGlobal);CHKERRQ(ierr);
1353   ierr = PetscSectionGetConstrainedStorageSize(sectionGlobal,&localSize);CHKERRQ(ierr);
1354   ierr = MatSetSizes(*J,localSize,localSize,PETSC_DETERMINE,PETSC_DETERMINE);CHKERRQ(ierr);
1355 
1356   ierr = MatSetType(*J,MATAIJ);CHKERRQ(ierr);
1357   ierr = MatSetFromOptions(*J);CHKERRQ(ierr);
1358 
1359   /* (1) Set matrix preallocation */
1360   /*------------------------------*/
1361   ierr = PetscObjectGetComm((PetscObject)dm,&comm);CHKERRQ(ierr);
1362   ierr = VecCreate(comm,&vd_nz);CHKERRQ(ierr);
1363   ierr = VecSetSizes(vd_nz,localSize,PETSC_DECIDE);CHKERRQ(ierr);
1364   ierr = VecSetFromOptions(vd_nz);CHKERRQ(ierr);
1365   ierr = VecSet(vd_nz,0.0);CHKERRQ(ierr);
1366   ierr = VecDuplicate(vd_nz,&vo_nz);CHKERRQ(ierr);
1367 
1368   /* Set preallocation for edges */
1369   /*-----------------------------*/
1370   ierr = DMNetworkGetEdgeRange(dm,&eStart,&eEnd);CHKERRQ(ierr);
1371 
1372   ierr = PetscMalloc1(localSize,&rows);CHKERRQ(ierr);
1373   for (e=eStart; e<eEnd; e++) {
1374     /* Get row indices */
1375     ierr = DMNetworkGetVariableGlobalOffset(dm,e,&rstart);CHKERRQ(ierr);
1376     ierr = DMNetworkGetNumVariables(dm,e,&nrows);CHKERRQ(ierr);
1377     if (nrows) {
1378       if (!network->Je) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NULL,"Uer must provide Je");
1379       for (j=0; j<nrows; j++) rows[j] = j + rstart;
1380 
1381       /* Set preallocation for conntected vertices */
1382       ierr = DMNetworkGetConnectedVertices(dm,e,&cone);CHKERRQ(ierr);
1383       for (v=0; v<2; v++) {
1384         ierr = DMNetworkGetNumVariables(dm,cone[v],&ncols);CHKERRQ(ierr);
1385 
1386         Juser = network->Je[3*e+1+v]; /* Jacobian(e,v) */
1387         ierr = DMNetworkIsGhostVertex(dm,cone[v],&ghost);CHKERRQ(ierr);
1388         ierr = MatSetPreallocationblock_private(Juser,nrows,rows,ncols,ghost,vd_nz,vo_nz);CHKERRQ(ierr);
1389       }
1390 
1391       /* Set preallocation for edge self */
1392       cstart = rstart;
1393       Juser = network->Je[3*e]; /* Jacobian(e,e) */
1394       ierr = MatSetPreallocationblock_private(Juser,nrows,rows,nrows,PETSC_FALSE,vd_nz,vo_nz);CHKERRQ(ierr);
1395     }
1396   }
1397 
1398   /* Set preallocation for vertices */
1399   /*--------------------------------*/
1400   ierr = DMNetworkGetVertexRange(dm,&vStart,&vEnd);CHKERRQ(ierr);
1401   if (vEnd - vStart) {
1402     if (!network->Jv) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NULL,"Uer must provide Jv");
1403     vptr = network->Jvptr;
1404     if (!vptr) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NULL,"Uer must provide vptr");
1405   }
1406 
1407   for (v=vStart; v<vEnd; v++) {
1408     /* Get row indices */
1409     ierr = DMNetworkGetVariableGlobalOffset(dm,v,&rstart);CHKERRQ(ierr);
1410     ierr = DMNetworkGetNumVariables(dm,v,&nrows);CHKERRQ(ierr);
1411     if (!nrows) continue;
1412 
1413     ierr = DMNetworkIsGhostVertex(dm,v,&ghost);CHKERRQ(ierr);
1414     if (ghost) {
1415       ierr = PetscMalloc1(nrows,&rows_v);CHKERRQ(ierr);
1416     } else {
1417       rows_v = rows;
1418     }
1419 
1420     for (j=0; j<nrows; j++) rows_v[j] = j + rstart;
1421 
1422     /* Get supporting edges and connected vertices */
1423     ierr = DMNetworkGetSupportingEdges(dm,v,&nedges,&edges);CHKERRQ(ierr);
1424 
1425     for (e=0; e<nedges; e++) {
1426       /* Supporting edges */
1427       ierr = DMNetworkGetVariableGlobalOffset(dm,edges[e],&cstart);CHKERRQ(ierr);
1428       ierr = DMNetworkGetNumVariables(dm,edges[e],&ncols);CHKERRQ(ierr);
1429 
1430       Juser = network->Jv[vptr[v-vStart]+2*e+1]; /* Jacobian(v,e) */
1431       ierr = MatSetPreallocationblock_private(Juser,nrows,rows_v,ncols,ghost,vd_nz,vo_nz);CHKERRQ(ierr);
1432 
1433       /* Connected vertices */
1434       ierr = DMNetworkGetConnectedVertices(dm,edges[e],&cone);CHKERRQ(ierr);
1435       vc = (v == cone[0]) ? cone[1]:cone[0];
1436       ierr = DMNetworkIsGhostVertex(dm,vc,&ghost_vc);CHKERRQ(ierr);
1437 
1438       ierr = DMNetworkGetNumVariables(dm,vc,&ncols);CHKERRQ(ierr);
1439 
1440       Juser = network->Jv[vptr[v-vStart]+2*e+2]; /* Jacobian(v,vc) */
1441       if (ghost_vc||ghost) {
1442         ghost2 = PETSC_TRUE;
1443       } else {
1444         ghost2 = PETSC_FALSE;
1445       }
1446       ierr = MatSetPreallocationblock_private(Juser,nrows,rows_v,ncols,ghost2,vd_nz,vo_nz);CHKERRQ(ierr);
1447     }
1448 
1449     /* Set preallocation for vertex self */
1450     ierr = DMNetworkIsGhostVertex(dm,v,&ghost);CHKERRQ(ierr);
1451     if (!ghost) {
1452       ierr = DMNetworkGetVariableGlobalOffset(dm,v,&cstart);CHKERRQ(ierr);
1453       Juser = network->Jv[vptr[v-vStart]]; /* Jacobian(v,v) */
1454       ierr = MatSetPreallocationblock_private(Juser,nrows,rows_v,nrows,PETSC_FALSE,vd_nz,vo_nz);CHKERRQ(ierr);
1455     }
1456     if (ghost) {
1457       ierr = PetscFree(rows_v);CHKERRQ(ierr);
1458     }
1459   }
1460 
1461   ierr = VecAssemblyBegin(vd_nz);CHKERRQ(ierr);
1462   ierr = VecAssemblyBegin(vo_nz);CHKERRQ(ierr);
1463 
1464   ierr = PetscMalloc2(localSize,&dnnz,localSize,&onnz);CHKERRQ(ierr);
1465 
1466   ierr = VecAssemblyEnd(vd_nz);CHKERRQ(ierr);
1467   ierr = VecAssemblyEnd(vo_nz);CHKERRQ(ierr);
1468 
1469   ierr = VecGetArray(vd_nz,&vdnz);CHKERRQ(ierr);
1470   ierr = VecGetArray(vo_nz,&vonz);CHKERRQ(ierr);
1471   for (j=0; j<localSize; j++) {
1472     dnnz[j] = (PetscInt)PetscRealPart(vdnz[j]);
1473     onnz[j] = (PetscInt)PetscRealPart(vonz[j]);
1474   }
1475   ierr = VecRestoreArray(vd_nz,&vdnz);CHKERRQ(ierr);
1476   ierr = VecRestoreArray(vo_nz,&vonz);CHKERRQ(ierr);
1477   ierr = VecDestroy(&vd_nz);CHKERRQ(ierr);
1478   ierr = VecDestroy(&vo_nz);CHKERRQ(ierr);
1479 
1480   ierr = MatSeqAIJSetPreallocation(*J,0,dnnz);CHKERRQ(ierr);
1481   ierr = MatMPIAIJSetPreallocation(*J,0,dnnz,0,onnz);CHKERRQ(ierr);
1482   ierr = MatSetOption(*J,MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_TRUE);CHKERRQ(ierr);
1483 
1484   ierr = PetscFree2(dnnz,onnz);CHKERRQ(ierr);
1485 
1486   /* (2) Set matrix entries for edges */
1487   /*----------------------------------*/
1488   for (e=eStart; e<eEnd; e++) {
1489     /* Get row indices */
1490     ierr = DMNetworkGetVariableGlobalOffset(dm,e,&rstart);CHKERRQ(ierr);
1491     ierr = DMNetworkGetNumVariables(dm,e,&nrows);CHKERRQ(ierr);
1492     if (nrows) {
1493       if (!network->Je) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_NULL,"Uer must provide Je");
1494 
1495       for (j=0; j<nrows; j++) rows[j] = j + rstart;
1496 
1497       /* Set matrix entries for conntected vertices */
1498       ierr = DMNetworkGetConnectedVertices(dm,e,&cone);CHKERRQ(ierr);
1499       for (v=0; v<2; v++) {
1500         ierr = DMNetworkGetVariableGlobalOffset(dm,cone[v],&cstart);CHKERRQ(ierr);
1501         ierr = DMNetworkGetNumVariables(dm,cone[v],&ncols);CHKERRQ(ierr);
1502 
1503         Juser = network->Je[3*e+1+v]; /* Jacobian(e,v) */
1504         ierr = MatSetblock_private(Juser,nrows,rows,ncols,cstart,J);CHKERRQ(ierr);
1505       }
1506 
1507       /* Set matrix entries for edge self */
1508       cstart = rstart;
1509       Juser = network->Je[3*e]; /* Jacobian(e,e) */
1510       ierr = MatSetblock_private(Juser,nrows,rows,nrows,cstart,J);CHKERRQ(ierr);
1511     }
1512   }
1513 
1514   /* Set matrix entries for vertices */
1515   /*---------------------------------*/
1516   for (v=vStart; v<vEnd; v++) {
1517     /* Get row indices */
1518     ierr = DMNetworkGetVariableGlobalOffset(dm,v,&rstart);CHKERRQ(ierr);
1519     ierr = DMNetworkGetNumVariables(dm,v,&nrows);CHKERRQ(ierr);
1520     if (!nrows) continue;
1521 
1522     ierr = DMNetworkIsGhostVertex(dm,v,&ghost);CHKERRQ(ierr);
1523     if (ghost) {
1524       ierr = PetscMalloc1(nrows,&rows_v);CHKERRQ(ierr);
1525     } else {
1526       rows_v = rows;
1527     }
1528     for (j=0; j<nrows; j++) rows_v[j] = j + rstart;
1529 
1530     /* Get supporting edges and connected vertices */
1531     ierr = DMNetworkGetSupportingEdges(dm,v,&nedges,&edges);CHKERRQ(ierr);
1532 
1533     for (e=0; e<nedges; e++) {
1534       /* Supporting edges */
1535       ierr = DMNetworkGetVariableGlobalOffset(dm,edges[e],&cstart);CHKERRQ(ierr);
1536       ierr = DMNetworkGetNumVariables(dm,edges[e],&ncols);CHKERRQ(ierr);
1537 
1538       Juser = network->Jv[vptr[v-vStart]+2*e+1]; /* Jacobian(v,e) */
1539       ierr = MatSetblock_private(Juser,nrows,rows_v,ncols,cstart,J);CHKERRQ(ierr);
1540 
1541       /* Connected vertices */
1542       ierr = DMNetworkGetConnectedVertices(dm,edges[e],&cone);CHKERRQ(ierr);
1543       vc = (v == cone[0]) ? cone[1]:cone[0];
1544 
1545       ierr = DMNetworkGetVariableGlobalOffset(dm,vc,&cstart);CHKERRQ(ierr);
1546       ierr = DMNetworkGetNumVariables(dm,vc,&ncols);CHKERRQ(ierr);
1547 
1548       Juser = network->Jv[vptr[v-vStart]+2*e+2]; /* Jacobian(v,vc) */
1549       ierr = MatSetblock_private(Juser,nrows,rows_v,ncols,cstart,J);CHKERRQ(ierr);
1550     }
1551 
1552     /* Set matrix entries for vertex self */
1553     if (!ghost) {
1554       ierr = DMNetworkGetVariableGlobalOffset(dm,v,&cstart);CHKERRQ(ierr);
1555       Juser = network->Jv[vptr[v-vStart]]; /* Jacobian(v,v) */
1556       ierr = MatSetblock_private(Juser,nrows,rows_v,nrows,cstart,J);CHKERRQ(ierr);
1557     }
1558     if (ghost) {
1559       ierr = PetscFree(rows_v);CHKERRQ(ierr);
1560     }
1561   }
1562   ierr = PetscFree(rows);CHKERRQ(ierr);
1563 
1564   ierr = MatAssemblyBegin(*J,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1565   ierr = MatAssemblyEnd(*J,MAT_FINAL_ASSEMBLY);CHKERRQ(ierr);
1566 
1567   ierr = MatSetDM(*J,dm);CHKERRQ(ierr);
1568   PetscFunctionReturn(0);
1569 }
1570 
1571 PetscErrorCode DMDestroy_Network(DM dm)
1572 {
1573   PetscErrorCode ierr;
1574   DM_Network     *network = (DM_Network*) dm->data;
1575 
1576   PetscFunctionBegin;
1577   if (--network->refct > 0) PetscFunctionReturn(0);
1578   if (network->Je) {
1579     ierr = PetscFree(network->Je);CHKERRQ(ierr);
1580   }
1581   if (network->Jv) {
1582     ierr = PetscFree(network->Jvptr);CHKERRQ(ierr);
1583     ierr = PetscFree(network->Jv);CHKERRQ(ierr);
1584   }
1585 
1586   ierr = ISLocalToGlobalMappingDestroy(&network->vertex.mapping);CHKERRQ(ierr);
1587   ierr = PetscSectionDestroy(&network->vertex.DofSection);CHKERRQ(ierr);
1588   ierr = PetscSectionDestroy(&network->vertex.GlobalDofSection);CHKERRQ(ierr);
1589   if (network->vertex.sf) {
1590     ierr = PetscSFDestroy(&network->vertex.sf);CHKERRQ(ierr);
1591   }
1592   /* edge */
1593   ierr = ISLocalToGlobalMappingDestroy(&network->edge.mapping);CHKERRQ(ierr);
1594   ierr = PetscSectionDestroy(&network->edge.DofSection);CHKERRQ(ierr);
1595   ierr = PetscSectionDestroy(&network->edge.GlobalDofSection);CHKERRQ(ierr);
1596   if (network->edge.sf) {
1597     ierr = PetscSFDestroy(&network->edge.sf);CHKERRQ(ierr);
1598   }
1599   ierr = DMDestroy(&network->plex);CHKERRQ(ierr);
1600   network->edges = NULL;
1601   ierr = PetscSectionDestroy(&network->DataSection);CHKERRQ(ierr);
1602   ierr = PetscSectionDestroy(&network->DofSection);CHKERRQ(ierr);
1603 
1604   ierr = PetscFree(network->componentdataarray);CHKERRQ(ierr);
1605   ierr = PetscFree(network->cvalue);CHKERRQ(ierr);
1606   ierr = PetscFree(network->header);CHKERRQ(ierr);
1607   ierr = PetscFree(network);CHKERRQ(ierr);
1608   PetscFunctionReturn(0);
1609 }
1610 
1611 PetscErrorCode DMView_Network(DM dm, PetscViewer viewer)
1612 {
1613   PetscErrorCode ierr;
1614   DM_Network     *network = (DM_Network*) dm->data;
1615 
1616   PetscFunctionBegin;
1617   ierr = DMView(network->plex,viewer);CHKERRQ(ierr);
1618   PetscFunctionReturn(0);
1619 }
1620 
1621 PetscErrorCode DMGlobalToLocalBegin_Network(DM dm, Vec g, InsertMode mode, Vec l)
1622 {
1623   PetscErrorCode ierr;
1624   DM_Network     *network = (DM_Network*) dm->data;
1625 
1626   PetscFunctionBegin;
1627   ierr = DMGlobalToLocalBegin(network->plex,g,mode,l);CHKERRQ(ierr);
1628   PetscFunctionReturn(0);
1629 }
1630 
1631 PetscErrorCode DMGlobalToLocalEnd_Network(DM dm, Vec g, InsertMode mode, Vec l)
1632 {
1633   PetscErrorCode ierr;
1634   DM_Network     *network = (DM_Network*) dm->data;
1635 
1636   PetscFunctionBegin;
1637   ierr = DMGlobalToLocalEnd(network->plex,g,mode,l);CHKERRQ(ierr);
1638   PetscFunctionReturn(0);
1639 }
1640 
1641 PetscErrorCode DMLocalToGlobalBegin_Network(DM dm, Vec l, InsertMode mode, Vec g)
1642 {
1643   PetscErrorCode ierr;
1644   DM_Network     *network = (DM_Network*) dm->data;
1645 
1646   PetscFunctionBegin;
1647   ierr = DMLocalToGlobalBegin(network->plex,l,mode,g);CHKERRQ(ierr);
1648   PetscFunctionReturn(0);
1649 }
1650 
1651 PetscErrorCode DMLocalToGlobalEnd_Network(DM dm, Vec l, InsertMode mode, Vec g)
1652 {
1653   PetscErrorCode ierr;
1654   DM_Network     *network = (DM_Network*) dm->data;
1655 
1656   PetscFunctionBegin;
1657   ierr = DMLocalToGlobalEnd(network->plex,l,mode,g);CHKERRQ(ierr);
1658   PetscFunctionReturn(0);
1659 }
1660