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