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