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