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