xref: /petsc/src/dm/impls/network/network.c (revision 6a5217c03994f2d95bb2e6dbd8bed42381aeb015)
1 #include <petsc/private/dmnetworkimpl.h>  /*I  "petscdmnetwork.h"  I*/
2 
3 /*
4   Creates the component header and value objects for a network point
5 */
6 static PetscErrorCode SetUpNetworkHeaderComponentValue(DM dm,DMNetworkComponentHeader header,DMNetworkComponentValue cvalue)
7 {
8   PetscFunctionBegin;
9   /* Allocate arrays for component information */
10   PetscCall(PetscCalloc5(header->maxcomps,&header->size,header->maxcomps,&header->key,header->maxcomps,&header->offset,header->maxcomps,&header->nvar,header->maxcomps,&header->offsetvarrel));
11   PetscCall(PetscCalloc1(header->maxcomps,&cvalue->data));
12 
13   /* The size of the header is the size of struct _p_DMNetworkComponentHeader. Since the struct contains PetscInt pointers we cannot use sizeof(struct). So, we need to explicitly calculate the size.
14    If the data header struct changes then this header size calculation needs to be updated. */
15   header->hsize = sizeof(struct _p_DMNetworkComponentHeader) + 5*header->maxcomps*sizeof(PetscInt);
16   header->hsize /= sizeof(DMNetworkComponentGenericDataType);
17   PetscFunctionReturn(0);
18 }
19 
20 /*@
21   DMNetworkGetPlex - Gets the Plex DM associated with this network DM
22 
23   Not collective
24 
25   Input Parameters:
26 . dm - the dm object
27 
28   Output Parameters:
29 . plexdm - the plex dm object
30 
31   Level: Advanced
32 
33 .seealso: DMNetworkCreate()
34 @*/
35 PetscErrorCode DMNetworkGetPlex(DM dm,DM *plexdm)
36 {
37   DM_Network *network = (DM_Network*)dm->data;
38 
39   PetscFunctionBegin;
40   *plexdm = network->plex;
41   PetscFunctionReturn(0);
42 }
43 
44 /*@
45   DMNetworkGetNumSubNetworks - Gets the the number of subnetworks
46 
47   Not collective
48 
49   Input Parameter:
50 . dm - the dm object
51 
52   Output Parameters:
53 + nsubnet - local number of subnetworks
54 - Nsubnet - global number of subnetworks
55 
56   Level: beginner
57 
58 .seealso: DMNetworkCreate(), DMNetworkSetNumSubNetworks()
59 @*/
60 PetscErrorCode DMNetworkGetNumSubNetworks(DM dm,PetscInt *nsubnet,PetscInt *Nsubnet)
61 {
62   DM_Network *network = (DM_Network*)dm->data;
63 
64   PetscFunctionBegin;
65   if (nsubnet) *nsubnet = network->nsubnet;
66   if (Nsubnet) *Nsubnet = network->Nsubnet;
67   PetscFunctionReturn(0);
68 }
69 
70 /*@
71   DMNetworkSetNumSubNetworks - Sets the number of subnetworks
72 
73   Collective on dm
74 
75   Input Parameters:
76 + dm - the dm object
77 . nsubnet - local number of subnetworks
78 - Nsubnet - global number of subnetworks
79 
80    Level: beginner
81 
82 .seealso: DMNetworkCreate(), DMNetworkGetNumSubNetworks()
83 @*/
84 PetscErrorCode DMNetworkSetNumSubNetworks(DM dm,PetscInt nsubnet,PetscInt Nsubnet)
85 {
86   DM_Network     *network = (DM_Network*)dm->data;
87 
88   PetscFunctionBegin;
89   PetscCheck(network->Nsubnet == 0,PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_INCOMP,"Network sizes alread set, cannot resize the network");
90 
91   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
92   PetscValidLogicalCollectiveInt(dm,nsubnet,2);
93   PetscValidLogicalCollectiveInt(dm,Nsubnet,3);
94 
95   if (Nsubnet == PETSC_DECIDE) {
96     PetscCheck(nsubnet >= 0,PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Number of local subnetworks %" PetscInt_FMT " cannot be less than 0",nsubnet);
97     PetscCall(MPIU_Allreduce(&nsubnet,&Nsubnet,1,MPIU_INT,MPI_SUM,PetscObjectComm((PetscObject)dm)));
98   }
99   PetscCheck(Nsubnet >= 1,PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_INCOMP,"Number of global subnetworks %" PetscInt_FMT " cannot be less than 1",Nsubnet);
100 
101   network->Nsubnet  = Nsubnet;
102   network->nsubnet  = 0;       /* initia value; will be determind by DMNetworkAddSubnetwork() */
103   PetscCall(PetscCalloc1(Nsubnet,&network->subnet));
104 
105   /* num of shared vertices */
106   network->nsvtx = 0;
107   network->Nsvtx = 0;
108   PetscFunctionReturn(0);
109 }
110 
111 /*@
112   DMNetworkAddSubnetwork - Add a subnetwork
113 
114   Collective on dm
115 
116   Input Parameters:
117 + dm - the dm object
118 . name - name of the subnetwork
119 . ne - number of local edges of this subnetwork
120 - edgelist - list of edges for this subnetwork, this is a one dimensional array with pairs of entries being the two vertices (in global numbering of the vertices) of each edge,
121 $            [first vertex of first edge, second vertex of first edge, first vertex of second edge, second vertex of second edge, etc]
122 
123   Output Parameters:
124 . netnum - global index of the subnetwork
125 
126   Notes:
127   There is no copy involved in this operation, only the pointer is referenced. The edgelist should
128   not be destroyed before the call to DMNetworkLayoutSetUp()
129 
130   A network can comprise of a single subnetwork OR multiple subnetworks. For a single subnetwork, the subnetwork can be read either in serial or parallel. For a multiple subnetworks,
131   each subnetwork topology needs to be set on a unique rank and the communicator size needs to be at least equal to the number of subnetworks.
132 
133   Level: beginner
134 
135   Example usage:
136   Consider the following networks:
137   1) A sigle subnetwork:
138 .vb
139  network 0:
140  rank[0]:
141    v0 --> v2; v1 --> v2
142  rank[1]:
143    v3 --> v5; v4 --> v5
144 .ve
145 
146  The resulting input
147  network 0:
148  rank[0]:
149    ne = 2
150    edgelist = [0 2 | 1 2]
151  rank[1]:
152    ne = 2
153    edgelist = [3 5 | 4 5]
154 
155   2) Two subnetworks:
156 .vb
157  subnetwork 0:
158  rank[0]:
159    v0 --> v2; v2 --> v1; v1 --> v3;
160  subnetwork 1:
161  rank[1]:
162    v0 --> v3; v3 --> v2; v2 --> v1;
163 .ve
164 
165  The resulting input
166  subnetwork 0:
167  rank[0]:
168    ne = 3
169    edgelist = [0 2 | 2 1 | 1 3]
170  rank[1]:
171    ne = 0
172    edgelist = NULL
173 
174  subnetwork 1:
175  rank[0]:
176    ne = 0
177    edgelist = NULL
178  rank[1]:
179    edgelist = [0 3 | 3 2 | 2 1]
180 
181 .seealso: DMNetworkCreate(), DMNetworkSetNumSubnetworks()
182 @*/
183 PetscErrorCode DMNetworkAddSubnetwork(DM dm,const char* name,PetscInt ne,PetscInt edgelist[],PetscInt *netnum)
184 {
185   DM_Network     *network = (DM_Network*)dm->data;
186   PetscInt       i,Nedge,j,Nvtx,nvtx,nvtx_min=-1,nvtx_max=0;
187   PetscBT        table;
188 
189   PetscFunctionBegin;
190   for (i=0; i<ne; i++) {
191     PetscCheck(edgelist[2*i] != edgelist[2*i+1],PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Edge %" PetscInt_FMT " has the same vertex %" PetscInt_FMT " at each endpoint",i,edgelist[2*i]);
192   }
193 
194   i = 0;
195   if (ne) nvtx_min = nvtx_max = edgelist[0];
196   for (j=0; j<ne; j++) {
197     nvtx_min = PetscMin(nvtx_min, edgelist[i]);
198     nvtx_max = PetscMax(nvtx_max, edgelist[i]);
199     i++;
200     nvtx_min = PetscMin(nvtx_min, edgelist[i]);
201     nvtx_max = PetscMax(nvtx_max, edgelist[i]);
202     i++;
203   }
204   Nvtx = nvtx_max - nvtx_min + 1; /* approximated total local nvtx for this subnet */
205 
206   /* Get exact local nvtx for this subnet: counting local values between nvtx_min and nvtx_max */
207   PetscCall(PetscBTCreate(Nvtx,&table));
208   PetscCall(PetscBTMemzero(Nvtx,table));
209   i = 0;
210   for (j=0; j<ne; j++) {
211     PetscCall(PetscBTSet(table,edgelist[i++]-nvtx_min));
212     PetscCall(PetscBTSet(table,edgelist[i++]-nvtx_min));
213   }
214   nvtx = 0;
215   for (j=0; j<Nvtx; j++) {
216     if (PetscBTLookup(table,j)) nvtx++;
217   }
218 
219   /* Get global total Nvtx = max(edgelist[])+1 for this subnet */
220   PetscCall(MPIU_Allreduce(&nvtx_max,&Nvtx,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm)));
221   Nvtx++;
222   PetscCall(PetscBTDestroy(&table));
223 
224   /* Get global total Nedge for this subnet */
225   PetscCall(MPIU_Allreduce(&ne,&Nedge,1,MPIU_INT,MPI_SUM,PetscObjectComm((PetscObject)dm)));
226 
227   i = network->nsubnet;
228   if (name) {
229     PetscCall(PetscStrcpy(network->subnet[i].name,name));
230   }
231   network->subnet[i].nvtx     = nvtx; /* include ghost vertices */
232   network->subnet[i].nedge    = ne;
233   network->subnet[i].edgelist = edgelist;
234   network->subnet[i].Nvtx     = Nvtx;
235   network->subnet[i].Nedge    = Nedge;
236 
237   /* ----------------------------------------------------------
238    p=v or e;
239    subnet[0].pStart   = 0
240    subnet[i+1].pStart = subnet[i].pEnd = subnet[i].pStart + (nE[i] or NV[i])
241    ----------------------------------------------------------------------- */
242   /* GLOBAL subnet[].vStart and vEnd, used by DMNetworkLayoutSetUp() */
243   network->subnet[i].vStart = network->NVertices;
244   network->subnet[i].vEnd   = network->subnet[i].vStart + network->subnet[i].Nvtx; /* global vEnd of subnet[i] */
245 
246   network->nVertices += nvtx; /* include ghost vertices */
247   network->NVertices += network->subnet[i].Nvtx;
248 
249   /* LOCAL subnet[].eStart and eEnd, used by DMNetworkLayoutSetUp() */
250   network->subnet[i].eStart = network->nEdges;
251   network->subnet[i].eEnd   = network->subnet[i].eStart + ne;
252   network->nEdges += ne;
253   network->NEdges += network->subnet[i].Nedge;
254 
255   PetscCall(PetscStrcpy(network->subnet[i].name,name));
256   if (netnum) *netnum = network->nsubnet;
257   network->nsubnet++;
258   PetscFunctionReturn(0);
259 }
260 
261 /*@C
262   DMNetworkSharedVertexGetInfo - Get info of a shared vertex struct, see petsc/private/dmnetworkimpl.h
263 
264   Not collective
265 
266   Input Parameters:
267 + dm - the DM object
268 - v - vertex point
269 
270   Output Parameters:
271 + gidx - global number of this shared vertex in the internal dmplex
272 . n - number of subnetworks that share this vertex
273 - sv - array of size n: sv[2*i,2*i+1]=(net[i], idx[i]), i=0,...,n-1
274 
275   Level: intermediate
276 
277 .seealso: DMNetworkGetSharedVertices()
278 @*/
279 PetscErrorCode DMNetworkSharedVertexGetInfo(DM dm,PetscInt v,PetscInt *gidx,PetscInt *n,const PetscInt **sv)
280 {
281   DM_Network     *network = (DM_Network*)dm->data;
282   SVtx           *svtx = network->svtx;
283   PetscInt       i,gidx_tmp;
284 
285   PetscFunctionBegin;
286   PetscCall(DMNetworkGetGlobalVertexIndex(dm,v,&gidx_tmp));
287   PetscCall(PetscTableFind(network->svtable,gidx_tmp+1,&i));
288   PetscCheck(i > 0,PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"input vertex is not a shared vertex");
289 
290   i--;
291   if (gidx) *gidx = gidx_tmp;
292   if (n)    *n    = svtx[i].n;
293   if (sv)   *sv   = svtx[i].sv;
294   PetscFunctionReturn(0);
295 }
296 
297 /*
298   VtxGetInfo - Get info of an input vertex=(net,idx)
299 
300   Input Parameters:
301 + Nsvtx - global num of shared vertices
302 . svtx - array of shared vertices (global)
303 - (net,idx) - subnet number and local index for a vertex
304 
305   Output Parameters:
306 + gidx - global index of (net,idx)
307 . svtype - see petsc/private/dmnetworkimpl.h
308 - svtx_idx - ordering in the svtx array
309 */
310 static inline PetscErrorCode VtxGetInfo(PetscInt Nsvtx,SVtx *svtx,PetscInt net,PetscInt idx,PetscInt *gidx,SVtxType *svtype,PetscInt *svtx_idx)
311 {
312   PetscInt i,j,*svto,g_idx;
313   SVtxType vtype;
314 
315   PetscFunctionBegin;
316   if (!Nsvtx) PetscFunctionReturn(0);
317 
318   g_idx = -1;
319   vtype = SVNONE;
320 
321   for (i=0; i<Nsvtx; i++) {
322     if (net == svtx[i].sv[0] && idx == svtx[i].sv[1]) {
323       g_idx = svtx[i].gidx;
324       vtype = SVFROM;
325     } else { /* loop over svtx[i].n */
326       for (j=1; j<svtx[i].n; j++) {
327         svto = svtx[i].sv + 2*j;
328         if (net == svto[0] && idx == svto[1]) {
329           /* input vertex net.idx is a shared to_vertex, output its global index and its svtype */
330           g_idx = svtx[i].gidx; /* output gidx for to_vertex */
331           vtype = SVTO;
332         }
333       }
334     }
335     if (vtype != SVNONE) break;
336   }
337   if (gidx)     *gidx     = g_idx;
338   if (svtype)   *svtype   = vtype;
339   if (svtx_idx) *svtx_idx = i;
340   PetscFunctionReturn(0);
341 }
342 
343 /*
344   TableAddSVtx - Add a new shared vertice from sedgelist[k] to a ctable svta
345 
346   Input:  network, sedgelist, k, svta
347   Output: svta, tdata, ta2sv
348 */
349 static inline PetscErrorCode TableAddSVtx(DM_Network *network,PetscInt *sedgelist,PetscInt k,PetscTable svta,PetscInt* tdata,PetscInt *ta2sv)
350 {
351   PetscInt       net,idx,gidx;
352 
353   PetscFunctionBegin;
354   net = sedgelist[k];
355   idx = sedgelist[k+1];
356   gidx = network->subnet[net].vStart + idx;
357   PetscCall(PetscTableAdd(svta,gidx+1,*tdata+1,INSERT_VALUES));
358 
359   ta2sv[*tdata] = k; /* maps tdata to index of sedgelist */
360   (*tdata)++;
361   PetscFunctionReturn(0);
362 }
363 
364 /*
365   SharedVtxCreate - Create an array of global shared vertices. See SVtx and SVtxType in dmnetworkimpl.h
366 
367   Input:  dm, Nsedgelist, sedgelist
368 
369   Note: Output svtx is organized as
370         sv(net[0],idx[0]) --> sv(net[1],idx[1])
371                           --> sv(net[1],idx[1])
372                           ...
373                           --> sv(net[n-1],idx[n-1])
374         and net[0] < net[1] < ... < net[n-1]
375         where sv[0] has SVFROM type, sv[i], i>0, has SVTO type.
376  */
377 static PetscErrorCode SharedVtxCreate(DM dm,PetscInt Nsedgelist,PetscInt *sedgelist)
378 {
379   SVtx               *svtx = NULL;
380   PetscInt           *sv,k,j,nsv,*tdata,**ta2sv;
381   PetscTable         *svtas;
382   PetscInt           gidx,net,idx,i,nta,ita,idx_from,idx_to,n;
383   DM_Network         *network = (DM_Network*)dm->data;
384   PetscTablePosition ppos;
385 
386   PetscFunctionBegin;
387   /* (1) Crete an array of ctables svtas to map (net,idx) -> gidx; a svtas[] for a shared/merged vertex */
388   PetscCall(PetscCalloc3(Nsedgelist,&svtas,Nsedgelist,&tdata,2*Nsedgelist,&ta2sv));
389 
390   k   = 0;   /* sedgelist vertex counter j = 4*k */
391   nta = 0;   /* num of svta tables created */
392 
393   /* for j=0 */
394   PetscCall(PetscTableCreate(2*Nsedgelist,network->NVertices+1,&svtas[nta]));
395   PetscCall(PetscMalloc1(2*Nsedgelist,&ta2sv[nta]));
396 
397   PetscCall(TableAddSVtx(network,sedgelist,k,svtas[nta],&tdata[nta],ta2sv[nta]));
398   PetscCall(TableAddSVtx(network,sedgelist,k+2,svtas[nta],&tdata[nta],ta2sv[nta]));
399   nta++; k += 4;
400 
401   for (j = 1; j < Nsedgelist; j++) { /* j: sedgelist counter */
402     for (ita = 0; ita < nta; ita++) {
403       /* vfrom */
404       net = sedgelist[k]; idx = sedgelist[k+1];
405       gidx = network->subnet[net].vStart + idx; /* global index of the vertex net.idx before merging shared vertices */
406       PetscCall(PetscTableFind(svtas[ita],gidx+1,&idx_from));
407 
408       /* vto */
409       net = sedgelist[k+2]; idx = sedgelist[k+3];
410       gidx = network->subnet[net].vStart + idx;
411       PetscCall(PetscTableFind(svtas[ita],gidx+1,&idx_to));
412 
413       if (idx_from || idx_to) { /* vfrom or vto is on table svtas[ita] */
414         idx_from--; idx_to--;
415         if (idx_from < 0) { /* vto is on svtas[ita] */
416           PetscCall(TableAddSVtx(network,sedgelist,k,svtas[ita],&tdata[ita],ta2sv[ita]));
417           break;
418         } else if (idx_to < 0) {
419           PetscCall(TableAddSVtx(network,sedgelist,k+2,svtas[ita],&tdata[ita],ta2sv[ita]));
420           break;
421         }
422       }
423     }
424 
425     if (ita == nta) {
426       PetscCall(PetscTableCreate(2*Nsedgelist,network->NVertices+1,&svtas[nta]));
427       PetscCall(PetscMalloc1(2*Nsedgelist, &ta2sv[nta]));
428 
429       PetscCall(TableAddSVtx(network,sedgelist,k,svtas[nta],&tdata[nta],ta2sv[nta]));
430       PetscCall(TableAddSVtx(network,sedgelist,k+2,svtas[nta],&tdata[nta],ta2sv[nta]));
431       nta++;
432     }
433     k += 4;
434   }
435 
436   /* (2) Create svtable for querry shared vertices using gidx */
437   PetscCall(PetscTableCreate(nta,network->NVertices+1,&network->svtable));
438 
439   /* (3) Construct svtx from svtas
440      svtx: array of SVtx: sv[0]=(net[0],idx[0]) to vertices sv[k], k=1,...,n-1;
441      net[k], k=0, ...,n-1, are in ascending order */
442   PetscCall(PetscMalloc1(nta,&svtx));
443   for (nsv = 0; nsv < nta; nsv++) {
444     /* for a single svtx, put shared vertices in ascending order of gidx */
445     PetscCall(PetscTableGetCount(svtas[nsv],&n));
446     PetscCall(PetscCalloc1(2*n,&sv));
447     svtx[nsv].sv   = sv;
448     svtx[nsv].n    = n;
449     svtx[nsv].gidx = network->NVertices; /* initialization */
450 
451     PetscCall(PetscTableGetHeadPosition(svtas[nsv],&ppos));
452     for (k=0; k<n; k++) { /* gidx is sorted in ascending order */
453       PetscCall(PetscTableGetNext(svtas[nsv],&ppos,&gidx,&i));
454       gidx--; i--;
455 
456       if (svtx[nsv].gidx > gidx) svtx[nsv].gidx = gidx; /*svtx[nsv].gidx = min(gidx) */
457 
458       j = ta2sv[nsv][i]; /* maps i to index of sedgelist */
459       sv[2*k]   = sedgelist[j];   /* subnet number */
460       sv[2*k+1] = sedgelist[j+1]; /* index on the subnet */
461     }
462 
463     /* Setup svtable for querry shared vertices */
464     PetscCall(PetscTableAdd(network->svtable,svtx[nsv].gidx+1,nsv+1,INSERT_VALUES));
465   }
466 
467   for (j=0; j<nta; j++) {
468     PetscCall(PetscTableDestroy(&svtas[j]));
469     PetscCall(PetscFree(ta2sv[j]));
470   }
471   PetscCall(PetscFree3(svtas,tdata,ta2sv));
472 
473   network->Nsvtx = nta;
474   network->svtx  = svtx;
475   PetscFunctionReturn(0);
476 }
477 
478 /*
479   GetEdgelist_Coupling - Get an integrated edgelist for dmplex from user-provided subnet[].edgelist when subnets are coupled by shared vertices
480 
481   Input Parameters:
482 . dm - the dmnetwork object
483 
484    Output Parameters:
485 +  edges - the integrated edgelist for dmplex
486 -  nmerged_ptr - num of vertices being merged
487 */
488 static PetscErrorCode GetEdgelist_Coupling(DM dm,PetscInt *edges,PetscInt *nmerged_ptr)
489 {
490   MPI_Comm       comm;
491   PetscMPIInt    size,rank,*recvcounts=NULL,*displs=NULL;
492   DM_Network     *network = (DM_Network*)dm->data;
493   PetscInt       i,j,ctr,np;
494   PetscInt       *vidxlTog,Nsv,Nsubnet=network->Nsubnet;
495   PetscInt       *sedgelist=network->sedgelist;
496   PetscInt       net,idx,gidx,nmerged,*vrange,gidx_from,net_from,sv_idx;
497   SVtxType       svtype = SVNONE;
498   SVtx           *svtx;
499 
500   PetscFunctionBegin;
501   PetscCall(PetscObjectGetComm((PetscObject)dm,&comm));
502   PetscCallMPI(MPI_Comm_rank(comm,&rank));
503   PetscCallMPI(MPI_Comm_size(comm,&size));
504 
505   /* (1) Create global svtx[] from sedgelist */
506   /* --------------------------------------- */
507   PetscCall(SharedVtxCreate(dm,network->Nsvtx,sedgelist));
508   Nsv  = network->Nsvtx;
509   svtx = network->svtx;
510 
511   /* (2) Merge shared vto vertices to their vfrom vertex with same global vetex index (gidx) */
512   /* --------------------------------------------------------------------------------------- */
513   /* (2.1) compute vrage[rank]: global index of 1st local vertex in proc[rank] */
514   PetscCall(PetscMalloc4(size+1,&vrange,size,&displs,size,&recvcounts,network->nVertices,&vidxlTog));
515   for (i=0; i<size; i++) {displs[i] = i; recvcounts[i] = 1;}
516 
517   vrange[0] = 0;
518   PetscCallMPI(MPI_Allgatherv(&network->nVertices,1,MPIU_INT,vrange+1,recvcounts,displs,MPIU_INT,comm));
519   for (i=2; i<size+1; i++) vrange[i] += vrange[i-1];
520 
521   /* (2.2) Create vidxlTog: maps UN-MERGED local vertex index i to global index gidx (plex, excluding ghost vertices) */
522   i = 0; gidx = 0;
523   nmerged        = 0; /* local num of merged vertices */
524   network->nsvtx = 0; /* local num of SVtx structs, including ghosts */
525   for (net=0; net<Nsubnet; net++) {
526     for (idx=0; idx<network->subnet[net].Nvtx; idx++) { /* Note: global subnet[net].Nvtx */
527       PetscCall(VtxGetInfo(Nsv,svtx,net,idx,&gidx_from,&svtype,&sv_idx));
528       if (svtype == SVTO) {
529         if (network->subnet[net].nvtx) {/* this proc owns sv_to */
530           net_from = svtx[sv_idx].sv[0]; /* subnet number of its shared vertex */
531           if (network->subnet[net_from].nvtx == 0) {
532             /* this proc does not own v_from, thus a ghost local vertex */
533             network->nsvtx++;
534           }
535           vidxlTog[i++] = gidx_from; /* gidx before merging! Bug??? */
536           nmerged++; /* a shared vertex -- merged */
537         }
538       } else {
539         if (svtype == SVFROM && network->subnet[net].nvtx) {
540           /* this proc owns this v_from, a new local shared vertex */
541           network->nsvtx++;
542         }
543         if (network->subnet[net].nvtx) vidxlTog[i++] = gidx;
544         gidx++;
545       }
546     }
547   }
548 #if defined(PETSC_USE_DEBUG)
549   PetscCheck(i == network->nVertices,PETSC_COMM_SELF,PETSC_ERR_ARG_NULL,"%" PetscInt_FMT " != %" PetscInt_FMT " nVertices",i,network->nVertices);
550 #endif
551 
552   /* (2.3) Shared vertices in the subnetworks are merged, update global NVertices: np = sum(local nmerged) */
553   PetscCallMPI(MPI_Allreduce(&nmerged,&np,1,MPIU_INT,MPI_SUM,comm));
554   network->NVertices -= np;
555 
556   ctr = 0;
557   for (net=0; net<Nsubnet; net++) {
558     for (j = 0; j < network->subnet[net].nedge; j++) {
559       /* vfrom: */
560       i = network->subnet[net].edgelist[2*j] + (network->subnet[net].vStart - vrange[rank]);
561       edges[2*ctr] = vidxlTog[i];
562 
563       /* vto */
564       i = network->subnet[net].edgelist[2*j+1] + (network->subnet[net].vStart - vrange[rank]);
565       edges[2*ctr+1] = vidxlTog[i];
566       ctr++;
567     }
568   }
569   PetscCall(PetscFree4(vrange,displs,recvcounts,vidxlTog));
570   PetscCall(PetscFree(sedgelist)); /* created in DMNetworkAddSharedVertices() */
571 
572   *nmerged_ptr = nmerged;
573   PetscFunctionReturn(0);
574 }
575 
576 /*@
577   DMNetworkLayoutSetUp - Sets up the bare layout (graph) for the network
578 
579   Not Collective
580 
581   Input Parameters:
582 . dm - the dmnetwork object
583 
584   Notes:
585   This routine should be called after the network sizes and edgelists have been provided. It creates
586   the bare layout of the network and sets up the network to begin insertion of components.
587 
588   All the components should be registered before calling this routine.
589 
590   Level: beginner
591 
592 .seealso: DMNetworkSetNumSubNetworks(), DMNetworkAddSubnetwork()
593 @*/
594 PetscErrorCode DMNetworkLayoutSetUp(DM dm)
595 {
596   DM_Network     *network = (DM_Network*)dm->data;
597   PetscInt       i,j,ctr,Nsubnet=network->Nsubnet,*eowners,np,*edges,*subnetvtx,*subnetedge,e,v,vfrom,vto,net;
598   const PetscInt *cone;
599   MPI_Comm       comm;
600   PetscMPIInt    size,rank;
601   PetscSection   sectiong;
602   PetscInt       nmerged=0;
603 
604   PetscFunctionBegin;
605   PetscCheck(network->nsubnet == Nsubnet,PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Must call DMNetworkAddSubnetwork() %" PetscInt_FMT " times",Nsubnet);
606 
607   /* This implementation requires user input each subnet by a single processor when Nsubnet>1, thus subnet[net].nvtx=subnet[net].Nvtx when net>0 */
608   for (net=1; net<Nsubnet; net++) {
609     if (network->subnet[net].nvtx) PetscCheck(network->subnet[net].nvtx == network->subnet[net].Nvtx,PETSC_COMM_SELF,PETSC_ERR_SUP,"subnetwork %" PetscInt_FMT " local num of vertices %" PetscInt_FMT " != %" PetscInt_FMT " global num",net,network->subnet[net].nvtx,network->subnet[net].Nvtx);
610   }
611 
612   PetscCall(PetscObjectGetComm((PetscObject)dm,&comm));
613   PetscCallMPI(MPI_Comm_rank(comm,&rank));
614   PetscCallMPI(MPI_Comm_size(comm,&size));
615 
616   /* Create LOCAL edgelist in global vertex ordering for the network by concatenating local input edgelists of the subnetworks */
617   PetscCall(PetscCalloc2(2*network->nEdges,&edges,size+1,&eowners));
618 
619   if (network->Nsvtx) { /* subnetworks are coupled via shared vertices */
620     PetscCall(GetEdgelist_Coupling(dm,edges,&nmerged));
621   } else { /* subnetworks are not coupled */
622     /* Create a 0-size svtable for querry shared vertices */
623     PetscCall(PetscTableCreate(0,network->NVertices+1,&network->svtable));
624     ctr = 0;
625     for (i=0; i < Nsubnet; i++) {
626       for (j = 0; j < network->subnet[i].nedge; j++) {
627         edges[2*ctr]   = network->subnet[i].vStart + network->subnet[i].edgelist[2*j];
628         edges[2*ctr+1] = network->subnet[i].vStart + network->subnet[i].edgelist[2*j+1];
629         ctr++;
630       }
631     }
632   }
633 
634   /* Create network->plex; One dimensional network, numCorners=2 */
635   PetscCall(DMCreate(comm,&network->plex));
636   PetscCall(DMSetType(network->plex,DMPLEX));
637   PetscCall(DMSetDimension(network->plex,1));
638 
639   if (size == 1) {
640     PetscCall(DMPlexBuildFromCellList(network->plex,network->nEdges,PETSC_DECIDE,2,edges));
641   } else {
642     PetscCall(DMPlexBuildFromCellListParallel(network->plex,network->nEdges,PETSC_DECIDE,PETSC_DECIDE,2,edges,NULL, NULL));
643   }
644 
645   PetscCall(DMPlexGetChart(network->plex,&network->pStart,&network->pEnd));
646   PetscCall(DMPlexGetHeightStratum(network->plex,0,&network->eStart,&network->eEnd));
647   PetscCall(DMPlexGetHeightStratum(network->plex,1,&network->vStart,&network->vEnd));
648 
649   PetscCall(PetscSectionCreate(comm,&network->DataSection));
650   PetscCall(PetscSectionCreate(comm,&network->DofSection));
651   PetscCall(PetscSectionSetChart(network->DataSection,network->pStart,network->pEnd));
652   PetscCall(PetscSectionSetChart(network->DofSection,network->pStart,network->pEnd));
653 
654   np = network->pEnd - network->pStart;
655   PetscCall(PetscCalloc2(np,&network->header,np,&network->cvalue));
656   for (i=0; i < np; i++) {
657     network->header[i].maxcomps = 1;
658     PetscCall(SetUpNetworkHeaderComponentValue(dm,&network->header[i],&network->cvalue[i]));
659   }
660 
661   /* Create edge and vertex arrays for the subnetworks
662      This implementation assumes that DMNetwork reads
663      (1) a single subnetwork in parallel; or
664      (2) n subnetworks using n processors, one subnetwork/processor.
665   */
666   PetscCall(PetscCalloc2(network->nEdges,&subnetedge,network->nVertices+network->nsvtx,&subnetvtx)); /* Maps local edge/vertex to local subnetwork's edge/vertex */
667   network->subnetedge = subnetedge;
668   network->subnetvtx  = subnetvtx;
669   for (j=0; j < Nsubnet; j++) {
670     network->subnet[j].edges = subnetedge;
671     subnetedge              += network->subnet[j].nedge;
672 
673     network->subnet[j].vertices = subnetvtx;
674     subnetvtx                  += network->subnet[j].nvtx;
675   }
676   network->svertices = subnetvtx;
677 
678   /* Get edge ownership */
679   np = network->eEnd - network->eStart;
680   PetscCallMPI(MPI_Allgather(&np,1,MPIU_INT,eowners+1,1,MPIU_INT,comm));
681   eowners[0] = 0;
682   for (i=2; i<=size; i++) eowners[i] += eowners[i-1];
683 
684   /* Setup local edge and vertex arrays for subnetworks */
685   e = 0;
686   for (i=0; i < Nsubnet; i++) {
687     ctr = 0;
688     for (j = 0; j < network->subnet[i].nedge; j++) {
689       /* edge e */
690       network->header[e].index    = e + eowners[rank];   /* Global edge index */
691       network->header[e].subnetid = i;
692       network->subnet[i].edges[j] = e;
693 
694       network->header[e].ndata           = 0;
695       network->header[e].offset[0]       = 0;
696       network->header[e].offsetvarrel[0] = 0;
697       PetscCall(PetscSectionAddDof(network->DataSection,e,network->header[e].hsize));
698 
699       /* connected vertices */
700       PetscCall(DMPlexGetCone(network->plex,e,&cone));
701 
702       /* vertex cone[0] */
703       v = cone[0];
704       network->header[v].index     = edges[2*e];  /* Global vertex index */
705       network->header[v].subnetid  = i;           /* Subnetwork id */
706       if (Nsubnet == 1) {
707         network->subnet[i].vertices[v - network->vStart] = v; /* user's subnet[].idx = petsc's v */
708       } else {
709         vfrom = network->subnet[i].edgelist[2*ctr];     /* =subnet[i].idx, Global index! */
710         network->subnet[i].vertices[vfrom] = v; /* user's subnet[].dix = petsc's v */
711       }
712 
713       /* vertex cone[1] */
714       v = cone[1];
715       network->header[v].index    = edges[2*e+1];   /* Global vertex index */
716       network->header[v].subnetid = i;              /* Subnetwork id */
717       if (Nsubnet == 1) {
718         network->subnet[i].vertices[v - network->vStart] = v; /* user's subnet[].idx = petsc's v */
719       } else {
720         vto = network->subnet[i].edgelist[2*ctr+1];     /* =subnet[i].idx, Global index! */
721         network->subnet[i].vertices[vto] = v; /* user's subnet[].dix = petsc's v */
722       }
723 
724       e++; ctr++;
725     }
726   }
727   PetscCall(PetscFree2(edges,eowners));
728 
729   /* Set local vertex array for the subnetworks */
730   j = 0;
731   for (v = network->vStart; v < network->vEnd; v++) {
732     network->header[v].ndata           = 0;
733     network->header[v].offset[0]       = 0;
734     network->header[v].offsetvarrel[0] = 0;
735     PetscCall(PetscSectionAddDof(network->DataSection,v,network->header[e].hsize));
736 
737     /* local shared vertex */
738     PetscCall(PetscTableFind(network->svtable,network->header[v].index+1,&i));
739     if (i) network->svertices[j++] = v;
740   }
741 
742   /* Create a global section to be used by DMNetworkIsGhostVertex() which is a non-collective routine */
743   /* see snes_tutorials_network-ex1_4 */
744   PetscCall(DMGetGlobalSection(network->plex,&sectiong));
745   PetscFunctionReturn(0);
746 }
747 
748 /*@C
749   DMNetworkGetSubnetwork - Returns the information about a requested subnetwork
750 
751   Not collective
752 
753   Input Parameters:
754 + dm - the DM object
755 - netnum - the global index of the subnetwork
756 
757   Output Parameters:
758 + nv - number of vertices (local)
759 . ne - number of edges (local)
760 . vtx - local vertices of the subnetwork
761 - edge - local edges of the subnetwork
762 
763   Notes:
764     Cannot call this routine before DMNetworkLayoutSetup()
765 
766     The local vertices returned on each rank are determined by DMNetwork. The user does not have any control over what vertices are local.
767 
768   Level: intermediate
769 
770 .seealso: DMNetworkCreate(), DMNetworkAddSubnetwork(), DMNetworkLayoutSetUp()
771 @*/
772 PetscErrorCode DMNetworkGetSubnetwork(DM dm,PetscInt netnum,PetscInt *nv,PetscInt *ne,const PetscInt **vtx,const PetscInt **edge)
773 {
774   DM_Network *network = (DM_Network*)dm->data;
775 
776   PetscFunctionBegin;
777   PetscCheck(netnum < network->Nsubnet,PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Subnet index %" PetscInt_FMT " exceeds the num of subnets %" PetscInt_FMT "",netnum,network->Nsubnet);
778   if (nv) *nv     = network->subnet[netnum].nvtx;
779   if (ne) *ne     = network->subnet[netnum].nedge;
780   if (vtx) *vtx   = network->subnet[netnum].vertices;
781   if (edge) *edge = network->subnet[netnum].edges;
782   PetscFunctionReturn(0);
783 }
784 
785 /*@
786   DMNetworkAddSharedVertices - Add shared vertices that connect two given subnetworks
787 
788   Collective on dm
789 
790   Input Parameters:
791 + dm - the dm object
792 . anetnum - first subnetwork global numbering returned by DMNetworkAddSubnetwork()
793 . bnetnum - second subnetwork global numbering returned by DMNetworkAddSubnetwork()
794 . nsvtx - number of vertices that are shared by the two subnetworks
795 . asvtx - vertex index in the first subnetwork
796 - bsvtx - vertex index in the second subnetwork
797 
798   Level: beginner
799 
800 .seealso: DMNetworkCreate(), DMNetworkAddSubnetwork(), DMNetworkGetSharedVertices()
801 @*/
802 PetscErrorCode DMNetworkAddSharedVertices(DM dm,PetscInt anetnum,PetscInt bnetnum,PetscInt nsvtx,PetscInt asvtx[],PetscInt bsvtx[])
803 {
804   DM_Network     *network = (DM_Network*)dm->data;
805   PetscInt       i,nsubnet = network->Nsubnet,*sedgelist,Nsvtx=network->Nsvtx;
806 
807   PetscFunctionBegin;
808   PetscCheck(anetnum != bnetnum,PetscObjectComm((PetscObject)dm),PETSC_ERR_USER,"Subnetworks must have different netnum");
809   PetscCheck(anetnum >= 0 && bnetnum >= 0,PetscObjectComm((PetscObject)dm),PETSC_ERR_USER,"netnum cannot be negative");
810   if (!Nsvtx) {
811     /* allocate network->sedgelist to hold at most 2*nsubnet pairs of shared vertices */
812     PetscCall(PetscMalloc1(2*4*nsubnet,&network->sedgelist));
813   }
814 
815   sedgelist = network->sedgelist;
816   for (i=0; i<nsvtx; i++) {
817     sedgelist[4*Nsvtx]   = anetnum; sedgelist[4*Nsvtx+1] = asvtx[i];
818     sedgelist[4*Nsvtx+2] = bnetnum; sedgelist[4*Nsvtx+3] = bsvtx[i];
819     Nsvtx++;
820   }
821   PetscCheck(Nsvtx <= 2*nsubnet,PETSC_COMM_SELF,PETSC_ERR_SUP,"allocate more space for coupling edgelist");
822   network->Nsvtx = Nsvtx;
823   PetscFunctionReturn(0);
824 }
825 
826 /*@C
827   DMNetworkGetSharedVertices - Returns the info for the shared vertices
828 
829   Not collective
830 
831   Input Parameter:
832 . dm - the DM object
833 
834   Output Parameters:
835 + nsv - number of local shared vertices
836 - svtx - local shared vertices
837 
838   Notes:
839   Cannot call this routine before DMNetworkLayoutSetup()
840 
841   Level: intermediate
842 
843 .seealso: DMNetworkGetSubnetwork(), DMNetworkLayoutSetUp(), DMNetworkAddSharedVertices()
844 @*/
845 PetscErrorCode DMNetworkGetSharedVertices(DM dm,PetscInt *nsv,const PetscInt **svtx)
846 {
847   DM_Network *net = (DM_Network*)dm->data;
848 
849   PetscFunctionBegin;
850   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
851   if (nsv)  *nsv  = net->nsvtx;
852   if (svtx) *svtx = net->svertices;
853   PetscFunctionReturn(0);
854 }
855 
856 /*@C
857   DMNetworkRegisterComponent - Registers the network component
858 
859   Logically collective on dm
860 
861   Input Parameters:
862 + dm - the network object
863 . name - the component name
864 - size - the storage size in bytes for this component data
865 
866    Output Parameters:
867 .  key - an integer key that defines the component
868 
869    Notes
870    This routine should be called by all processors before calling DMNetworkLayoutSetup().
871 
872    Level: beginner
873 
874 .seealso: DMNetworkCreate(), DMNetworkLayoutSetUp()
875 @*/
876 PetscErrorCode DMNetworkRegisterComponent(DM dm,const char *name,size_t size,PetscInt *key)
877 {
878   DM_Network            *network = (DM_Network*) dm->data;
879   DMNetworkComponent    *component=NULL,*newcomponent=NULL;
880   PetscBool             flg=PETSC_FALSE;
881   PetscInt              i;
882 
883   PetscFunctionBegin;
884   if (!network->component) {
885     PetscCall(PetscCalloc1(network->max_comps_registered,&network->component));
886   }
887 
888   for (i=0; i < network->ncomponent; i++) {
889     PetscCall(PetscStrcmp(network->component[i].name,name,&flg));
890     if (flg) {
891       *key = i;
892       PetscFunctionReturn(0);
893     }
894   }
895 
896   if (network->ncomponent == network->max_comps_registered) {
897     /* Reached max allowed so resize component */
898     network->max_comps_registered += 2;
899     PetscCall(PetscCalloc1(network->max_comps_registered,&newcomponent));
900     /* Copy over the previous component info */
901     for (i=0; i < network->ncomponent; i++) {
902       PetscCall(PetscStrcpy(newcomponent[i].name,network->component[i].name));
903       newcomponent[i].size = network->component[i].size;
904     }
905     /* Free old one */
906     PetscCall(PetscFree(network->component));
907     /* Update pointer */
908     network->component = newcomponent;
909   }
910 
911   component = &network->component[network->ncomponent];
912 
913   PetscCall(PetscStrcpy(component->name,name));
914   component->size = size/sizeof(DMNetworkComponentGenericDataType);
915   *key = network->ncomponent;
916   network->ncomponent++;
917   PetscFunctionReturn(0);
918 }
919 
920 /*@
921   DMNetworkGetVertexRange - Get the bounds [start, end) for the local vertices
922 
923   Not Collective
924 
925   Input Parameter:
926 . dm - the DMNetwork object
927 
928   Output Parameters:
929 + vStart - the first vertex point
930 - vEnd - one beyond the last vertex point
931 
932   Level: beginner
933 
934 .seealso: DMNetworkGetEdgeRange()
935 @*/
936 PetscErrorCode DMNetworkGetVertexRange(DM dm,PetscInt *vStart,PetscInt *vEnd)
937 {
938   DM_Network *network = (DM_Network*)dm->data;
939 
940   PetscFunctionBegin;
941   if (vStart) *vStart = network->vStart;
942   if (vEnd) *vEnd = network->vEnd;
943   PetscFunctionReturn(0);
944 }
945 
946 /*@
947   DMNetworkGetEdgeRange - Get the bounds [start, end) for the local edges
948 
949   Not Collective
950 
951   Input Parameter:
952 . dm - the DMNetwork object
953 
954   Output Parameters:
955 + eStart - The first edge point
956 - eEnd - One beyond the last edge point
957 
958   Level: beginner
959 
960 .seealso: DMNetworkGetVertexRange()
961 @*/
962 PetscErrorCode DMNetworkGetEdgeRange(DM dm,PetscInt *eStart,PetscInt *eEnd)
963 {
964   DM_Network *network = (DM_Network*)dm->data;
965 
966   PetscFunctionBegin;
967   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
968   if (eStart) *eStart = network->eStart;
969   if (eEnd)   *eEnd   = network->eEnd;
970   PetscFunctionReturn(0);
971 }
972 
973 static PetscErrorCode DMNetworkGetIndex(DM dm,PetscInt p,PetscInt *index)
974 {
975   DM_Network *network = (DM_Network*)dm->data;
976 
977   PetscFunctionBegin;
978   if (network->header) {
979     *index = network->header[p].index;
980   } else {
981     PetscInt                 offsetp;
982     DMNetworkComponentHeader header;
983 
984     PetscCall(PetscSectionGetOffset(network->DataSection,p,&offsetp));
985     header = (DMNetworkComponentHeader)(network->componentdataarray+offsetp);
986     *index = header->index;
987   }
988   PetscFunctionReturn(0);
989 }
990 
991 /*@
992   DMNetworkGetGlobalEdgeIndex - Get the global numbering for the edge on the network
993 
994   Not Collective
995 
996   Input Parameters:
997 + dm - DMNetwork object
998 - p - edge point
999 
1000   Output Parameters:
1001 . index - the global numbering for the edge
1002 
1003   Level: intermediate
1004 
1005 .seealso: DMNetworkGetGlobalVertexIndex()
1006 @*/
1007 PetscErrorCode DMNetworkGetGlobalEdgeIndex(DM dm,PetscInt p,PetscInt *index)
1008 {
1009   PetscFunctionBegin;
1010   PetscCall(DMNetworkGetIndex(dm,p,index));
1011   PetscFunctionReturn(0);
1012 }
1013 
1014 /*@
1015   DMNetworkGetGlobalVertexIndex - Get the global numbering for the vertex on the network
1016 
1017   Not Collective
1018 
1019   Input Parameters:
1020 + dm - DMNetwork object
1021 - p  - vertex point
1022 
1023   Output Parameters:
1024 . index - the global numbering for the vertex
1025 
1026   Level: intermediate
1027 
1028 .seealso: DMNetworkGetGlobalEdgeIndex(), DMNetworkGetLocalVertexIndex()
1029 @*/
1030 PetscErrorCode DMNetworkGetGlobalVertexIndex(DM dm,PetscInt p,PetscInt *index)
1031 {
1032   PetscFunctionBegin;
1033   PetscCall(DMNetworkGetIndex(dm,p,index));
1034   PetscFunctionReturn(0);
1035 }
1036 
1037 /*@
1038   DMNetworkGetNumComponents - Get the number of components at a vertex/edge
1039 
1040   Not Collective
1041 
1042   Input Parameters:
1043 + dm - the DMNetwork object
1044 - p - vertex/edge point
1045 
1046   Output Parameters:
1047 . numcomponents - Number of components at the vertex/edge
1048 
1049   Level: beginner
1050 
1051 .seealso: DMNetworkRegisterComponent(), DMNetworkAddComponent()
1052 @*/
1053 PetscErrorCode DMNetworkGetNumComponents(DM dm,PetscInt p,PetscInt *numcomponents)
1054 {
1055   PetscInt       offset;
1056   DM_Network     *network = (DM_Network*)dm->data;
1057 
1058   PetscFunctionBegin;
1059   PetscCall(PetscSectionGetOffset(network->DataSection,p,&offset));
1060   *numcomponents = ((DMNetworkComponentHeader)(network->componentdataarray+offset))->ndata;
1061   PetscFunctionReturn(0);
1062 }
1063 
1064 /*@
1065   DMNetworkGetLocalVecOffset - Get the offset for accessing the variables associated with a component at the given vertex/edge from the local vector
1066 
1067   Not Collective
1068 
1069   Input Parameters:
1070 + dm - the DMNetwork object
1071 . p - the edge or vertex point
1072 - compnum - component number; use ALL_COMPONENTS if no specific component is requested
1073 
1074   Output Parameters:
1075 . offset - the local offset
1076 
1077   Notes:
1078     These offsets can be passed to MatSetValuesLocal() for matrices obtained with DMCreateMatrix().
1079 
1080     For vectors obtained with DMCreateLocalVector() the offsets can be used with VecSetValues().
1081 
1082     For vectors obtained with DMCreateLocalVector() and the array obtained with VecGetArray(vec,&array) you can access or set
1083     the vector values with array[offset].
1084 
1085     For vectors obtained with DMCreateGlobalVector() the offsets can be used with VecSetValuesLocal().
1086 
1087   Level: intermediate
1088 
1089 .seealso: DMGetLocalVector(), DMNetworkGetComponent(), DMNetworkGetGlobalVecOffset(), DMCreateGlobalVector(), VecGetArray(), VecSetValuesLocal(), MatSetValuesLocal()
1090 @*/
1091 PetscErrorCode DMNetworkGetLocalVecOffset(DM dm,PetscInt p,PetscInt compnum,PetscInt *offset)
1092 {
1093   DM_Network     *network = (DM_Network*)dm->data;
1094   PetscInt       offsetp,offsetd;
1095   DMNetworkComponentHeader header;
1096 
1097   PetscFunctionBegin;
1098   PetscCall(PetscSectionGetOffset(network->plex->localSection,p,&offsetp));
1099   if (compnum == ALL_COMPONENTS) {
1100     *offset = offsetp;
1101     PetscFunctionReturn(0);
1102   }
1103 
1104   PetscCall(PetscSectionGetOffset(network->DataSection,p,&offsetd));
1105   header = (DMNetworkComponentHeader)(network->componentdataarray+offsetd);
1106   *offset = offsetp + header->offsetvarrel[compnum];
1107   PetscFunctionReturn(0);
1108 }
1109 
1110 /*@
1111   DMNetworkGetGlobalVecOffset - Get the global offset for accessing the variables associated with a component for the given vertex/edge from the global vector
1112 
1113   Not Collective
1114 
1115   Input Parameters:
1116 + dm - the DMNetwork object
1117 . p - the edge or vertex point
1118 - compnum - component number; use ALL_COMPONENTS if no specific component is requested
1119 
1120   Output Parameters:
1121 . offsetg - the global offset
1122 
1123   Notes:
1124     These offsets can be passed to MatSetValues() for matrices obtained with DMCreateMatrix().
1125 
1126     For vectors obtained with DMCreateGlobalVector() the offsets can be used with VecSetValues().
1127 
1128     For vectors obtained with DMCreateGlobalVector() and the array obtained with VecGetArray(vec,&array) you can access or set
1129     the vector values with array[offset - rstart] where restart is obtained with VecGetOwnershipRange(v,&rstart,NULL);
1130 
1131   Level: intermediate
1132 
1133 .seealso: DMNetworkGetLocalVecOffset(), DMGetGlobalVector(), DMNetworkGetComponent(), DMCreateGlobalVector(), VecGetArray(), VecSetValues(), MatSetValues()
1134 @*/
1135 PetscErrorCode DMNetworkGetGlobalVecOffset(DM dm,PetscInt p,PetscInt compnum,PetscInt *offsetg)
1136 {
1137   DM_Network               *network = (DM_Network*)dm->data;
1138   PetscInt                 offsetp,offsetd;
1139   DMNetworkComponentHeader header;
1140 
1141   PetscFunctionBegin;
1142   PetscCall(PetscSectionGetOffset(network->plex->globalSection,p,&offsetp));
1143   if (offsetp < 0) offsetp = -(offsetp + 1); /* Convert to actual global offset for ghost vertex */
1144 
1145   if (compnum == ALL_COMPONENTS) {
1146     *offsetg = offsetp;
1147     PetscFunctionReturn(0);
1148   }
1149   PetscCall(PetscSectionGetOffset(network->DataSection,p,&offsetd));
1150   header = (DMNetworkComponentHeader)(network->componentdataarray+offsetd);
1151   *offsetg = offsetp + header->offsetvarrel[compnum];
1152   PetscFunctionReturn(0);
1153 }
1154 
1155 /*@
1156   DMNetworkGetEdgeOffset - Get the offset for accessing the variables associated with the given edge from the local subvector
1157 
1158   Not Collective
1159 
1160   Input Parameters:
1161 + dm - the DMNetwork object
1162 - p - the edge point
1163 
1164   Output Parameters:
1165 . offset - the offset
1166 
1167   Level: intermediate
1168 
1169 .seealso: DMNetworkGetLocalVecOffset(), DMGetLocalVector()
1170 @*/
1171 PetscErrorCode DMNetworkGetEdgeOffset(DM dm,PetscInt p,PetscInt *offset)
1172 {
1173   DM_Network     *network = (DM_Network*)dm->data;
1174 
1175   PetscFunctionBegin;
1176   PetscCall(PetscSectionGetOffset(network->edge.DofSection,p,offset));
1177   PetscFunctionReturn(0);
1178 }
1179 
1180 /*@
1181   DMNetworkGetVertexOffset - Get the offset for accessing the variables associated with the given vertex from the local subvector
1182 
1183   Not Collective
1184 
1185   Input Parameters:
1186 + dm - the DMNetwork object
1187 - p - the vertex point
1188 
1189   Output Parameters:
1190 . offset - the offset
1191 
1192   Level: intermediate
1193 
1194 .seealso: DMNetworkGetEdgeOffset(), DMGetLocalVector()
1195 @*/
1196 PetscErrorCode DMNetworkGetVertexOffset(DM dm,PetscInt p,PetscInt *offset)
1197 {
1198   DM_Network     *network = (DM_Network*)dm->data;
1199 
1200   PetscFunctionBegin;
1201   p -= network->vStart;
1202   PetscCall(PetscSectionGetOffset(network->vertex.DofSection,p,offset));
1203   PetscFunctionReturn(0);
1204 }
1205 
1206 /*@
1207   DMNetworkAddComponent - Adds a network component and number of variables at the given point (vertex/edge)
1208 
1209   Collective on dm
1210 
1211   Input Parameters:
1212 + dm - the DMNetwork
1213 . p - the vertex/edge point. These points are local indices provided by DMNetworkGetSubnetwork()
1214 . componentkey - component key returned while registering the component with DMNetworkRegisterComponent()
1215 . compvalue - pointer to the data structure for the component, or NULL if the component does not require data
1216 - nvar - number of variables for the component at the vertex/edge point, zero if the component does not introduce any degrees of freedom at the point
1217 
1218   Notes:
1219     The owning rank and any other ranks that have this point as a ghost location must call this routine to add a component and number of variables in the same order at the given point.
1220 
1221     DMNetworkLayoutSetUp() must be called before this routine.
1222 
1223   Developer Notes:
1224      The requirement that all the ranks with access to a vertex (as owner or as ghost) add all the components comes from a limitation of the underlying implementation based on DMPLEX.
1225   Level: beginner
1226 
1227 .seealso: DMNetworkGetComponent(), DMNetworkGetSubnetwork(), DMNetworkIsGhostVertex(), DMNetworkLayoutSetUp()
1228 @*/
1229 PetscErrorCode DMNetworkAddComponent(DM dm,PetscInt p,PetscInt componentkey,void* compvalue,PetscInt nvar)
1230 {
1231   DM_Network               *network = (DM_Network*)dm->data;
1232   DMNetworkComponent       *component = &network->component[componentkey];
1233   DMNetworkComponentHeader header;
1234   DMNetworkComponentValue  cvalue;
1235   PetscInt                 compnum;
1236   PetscInt                 *compsize,*compkey,*compoffset,*compnvar,*compoffsetvarrel;
1237   void*                    *compdata;
1238 
1239   PetscFunctionBegin;
1240   PetscCheck(componentkey >= 0,PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"componentkey %" PetscInt_FMT " cannot be negative. Input a component key returned while registering the component with DMNetworkRegisterComponent()",componentkey);
1241 
1242   /* The owning rank and all ghost ranks add nvar */
1243   PetscCall(PetscSectionAddDof(network->DofSection,p,nvar));
1244 
1245   /* The owning rank and all ghost ranks add a component, including compvalue=NULL */
1246   header = &network->header[p];
1247   cvalue = &network->cvalue[p];
1248   if (header->ndata == header->maxcomps) {
1249     PetscInt additional_size;
1250 
1251     /* Reached limit so resize header component arrays */
1252     header->maxcomps += 2;
1253 
1254     /* Allocate arrays for component information and value */
1255     PetscCall(PetscCalloc5(header->maxcomps,&compsize,header->maxcomps,&compkey,header->maxcomps,&compoffset,header->maxcomps,&compnvar,header->maxcomps,&compoffsetvarrel));
1256     PetscCall(PetscMalloc1(header->maxcomps,&compdata));
1257 
1258     /* Recalculate header size */
1259     header->hsize = sizeof(struct _p_DMNetworkComponentHeader) + 5*header->maxcomps*sizeof(PetscInt);
1260 
1261     header->hsize /= sizeof(DMNetworkComponentGenericDataType);
1262 
1263     /* Copy over component info */
1264     PetscCall(PetscMemcpy(compsize,header->size,header->ndata*sizeof(PetscInt)));
1265     PetscCall(PetscMemcpy(compkey,header->key,header->ndata*sizeof(PetscInt)));
1266     PetscCall(PetscMemcpy(compoffset,header->offset,header->ndata*sizeof(PetscInt)));
1267     PetscCall(PetscMemcpy(compnvar,header->nvar,header->ndata*sizeof(PetscInt)));
1268     PetscCall(PetscMemcpy(compoffsetvarrel,header->offsetvarrel,header->ndata*sizeof(PetscInt)));
1269 
1270     /* Copy over component data pointers */
1271     PetscCall(PetscMemcpy(compdata,cvalue->data,header->ndata*sizeof(void*)));
1272 
1273     /* Free old arrays */
1274     PetscCall(PetscFree5(header->size,header->key,header->offset,header->nvar,header->offsetvarrel));
1275     PetscCall(PetscFree(cvalue->data));
1276 
1277     /* Update pointers */
1278     header->size         = compsize;
1279     header->key          = compkey;
1280     header->offset       = compoffset;
1281     header->nvar         = compnvar;
1282     header->offsetvarrel = compoffsetvarrel;
1283 
1284     cvalue->data = compdata;
1285 
1286     /* Update DataSection Dofs */
1287     /* The dofs for datasection point p equals sizeof the header (i.e. header->hsize) + sizes of the components added at point p. With the resizing of the header, we need to update the dofs for point p. Hence, we add the extra size added for the header */
1288     additional_size = (5*(header->maxcomps - header->ndata)*sizeof(PetscInt))/sizeof(DMNetworkComponentGenericDataType);
1289     PetscCall(PetscSectionAddDof(network->DataSection,p,additional_size));
1290   }
1291   header = &network->header[p];
1292   cvalue = &network->cvalue[p];
1293 
1294   compnum = header->ndata;
1295 
1296   header->size[compnum] = component->size;
1297   PetscCall(PetscSectionAddDof(network->DataSection,p,component->size));
1298   header->key[compnum] = componentkey;
1299   if (compnum != 0) header->offset[compnum] = header->offset[compnum-1] + header->size[compnum-1];
1300   cvalue->data[compnum] = (void*)compvalue;
1301 
1302   /* variables */
1303   header->nvar[compnum] += nvar;
1304   if (compnum != 0) header->offsetvarrel[compnum] = header->offsetvarrel[compnum-1] + header->nvar[compnum-1];
1305 
1306   header->ndata++;
1307   PetscFunctionReturn(0);
1308 }
1309 
1310 /*@
1311   DMNetworkGetComponent - Gets the component key, the component data, and the number of variables at a given network point
1312 
1313   Not Collective
1314 
1315   Input Parameters:
1316 + dm - the DMNetwork object
1317 . p - vertex/edge point
1318 - compnum - component number; use ALL_COMPONENTS if sum up all the components
1319 
1320   Output Parameters:
1321 + compkey - the key obtained when registering the component (use NULL if not required)
1322 . component - the component data (use NULL if not required)
1323 - nvar  - number of variables (use NULL if not required)
1324 
1325   Level: beginner
1326 
1327 .seealso: DMNetworkAddComponent(), DMNetworkGetNumComponents()
1328 @*/
1329 PetscErrorCode DMNetworkGetComponent(DM dm,PetscInt p,PetscInt compnum,PetscInt *compkey,void **component,PetscInt *nvar)
1330 {
1331   DM_Network     *network = (DM_Network*)dm->data;
1332   PetscInt       offset = 0;
1333   DMNetworkComponentHeader header;
1334 
1335   PetscFunctionBegin;
1336   if (compnum == ALL_COMPONENTS) {
1337     PetscCall(PetscSectionGetDof(network->DofSection,p,nvar));
1338     PetscFunctionReturn(0);
1339   }
1340 
1341   PetscCall(PetscSectionGetOffset(network->DataSection,p,&offset));
1342   header = (DMNetworkComponentHeader)(network->componentdataarray+offset);
1343 
1344   if (compnum >= 0) {
1345     if (compkey) *compkey = header->key[compnum];
1346     if (component) {
1347       offset += header->hsize+header->offset[compnum];
1348       *component = network->componentdataarray+offset;
1349     }
1350   }
1351 
1352   if (nvar) *nvar = header->nvar[compnum];
1353 
1354   PetscFunctionReturn(0);
1355 }
1356 
1357 /*
1358  Sets up the array that holds the data for all components and its associated section.
1359  It copies the data for all components in a contiguous array called componentdataarray. The component data is stored pointwise with an additional header (metadata) stored for each point. The header has metadata information such as number of components at each point, number of variables for each component, offsets for the components data, etc.
1360 */
1361 PetscErrorCode DMNetworkComponentSetUp(DM dm)
1362 {
1363   DM_Network               *network = (DM_Network*)dm->data;
1364   PetscInt                 arr_size,p,offset,offsetp,ncomp,i,*headerarr;
1365   DMNetworkComponentHeader header;
1366   DMNetworkComponentValue  cvalue;
1367   DMNetworkComponentHeader headerinfo;
1368   DMNetworkComponentGenericDataType *componentdataarray;
1369 
1370   PetscFunctionBegin;
1371   PetscCall(PetscSectionSetUp(network->DataSection));
1372   PetscCall(PetscSectionGetStorageSize(network->DataSection,&arr_size));
1373   /* arr_size+1 fixes pipeline test of opensolaris-misc for src/dm/tests/ex10.c -- Do not know why */
1374   PetscCall(PetscCalloc1(arr_size+1,&network->componentdataarray));
1375 
1376   componentdataarray = network->componentdataarray;
1377   for (p = network->pStart; p < network->pEnd; p++) {
1378     PetscCall(PetscSectionGetOffset(network->DataSection,p,&offsetp));
1379     /* Copy header */
1380     header = &network->header[p];
1381     headerinfo = (DMNetworkComponentHeader)(componentdataarray+offsetp);
1382     PetscCall(PetscMemcpy(headerinfo,header,sizeof(struct _p_DMNetworkComponentHeader)));
1383     headerarr = (PetscInt*)(headerinfo+1);
1384     PetscCall(PetscMemcpy(headerarr,header->size,header->maxcomps*sizeof(PetscInt)));
1385     headerarr += header->maxcomps;
1386     PetscCall(PetscMemcpy(headerarr,header->key,header->maxcomps*sizeof(PetscInt)));
1387     headerarr += header->maxcomps;
1388     PetscCall(PetscMemcpy(headerarr,header->offset,header->maxcomps*sizeof(PetscInt)));
1389     headerarr += header->maxcomps;
1390     PetscCall(PetscMemcpy(headerarr,header->nvar,header->maxcomps*sizeof(PetscInt)));
1391     headerarr += header->maxcomps;
1392     PetscCall(PetscMemcpy(headerarr,header->offsetvarrel,header->maxcomps*sizeof(PetscInt)));
1393 
1394     /* Copy data */
1395     cvalue = &network->cvalue[p];
1396     ncomp  = header->ndata;
1397 
1398     for (i = 0; i < ncomp; i++) {
1399       offset = offsetp + header->hsize + header->offset[i];
1400       PetscCall(PetscMemcpy(componentdataarray+offset,cvalue->data[i],header->size[i]*sizeof(DMNetworkComponentGenericDataType)));
1401     }
1402   }
1403   PetscFunctionReturn(0);
1404 }
1405 
1406 /* Sets up the section for dofs. This routine is called during DMSetUp() */
1407 static PetscErrorCode DMNetworkVariablesSetUp(DM dm)
1408 {
1409   DM_Network     *network = (DM_Network*)dm->data;
1410 
1411   PetscFunctionBegin;
1412   PetscCall(PetscSectionSetUp(network->DofSection));
1413   PetscFunctionReturn(0);
1414 }
1415 
1416 /* Get a subsection from a range of points */
1417 static PetscErrorCode DMNetworkGetSubSection_private(PetscSection main,PetscInt pstart,PetscInt pend,PetscSection *subsection)
1418 {
1419   PetscInt       i, nvar;
1420 
1421   PetscFunctionBegin;
1422   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)main), subsection));
1423   PetscCall(PetscSectionSetChart(*subsection, 0, pend - pstart));
1424   for (i = pstart; i < pend; i++) {
1425     PetscCall(PetscSectionGetDof(main,i,&nvar));
1426     PetscCall(PetscSectionSetDof(*subsection, i - pstart, nvar));
1427   }
1428 
1429   PetscCall(PetscSectionSetUp(*subsection));
1430   PetscFunctionReturn(0);
1431 }
1432 
1433 /* Create a submap of points with a GlobalToLocal structure */
1434 static PetscErrorCode DMNetworkSetSubMap_private(PetscInt pstart, PetscInt pend, ISLocalToGlobalMapping *map)
1435 {
1436   PetscInt       i, *subpoints;
1437 
1438   PetscFunctionBegin;
1439   /* Create index sets to map from "points" to "subpoints" */
1440   PetscCall(PetscMalloc1(pend - pstart, &subpoints));
1441   for (i = pstart; i < pend; i++) {
1442     subpoints[i - pstart] = i;
1443   }
1444   PetscCall(ISLocalToGlobalMappingCreate(PETSC_COMM_WORLD,1,pend-pstart,subpoints,PETSC_COPY_VALUES,map));
1445   PetscCall(PetscFree(subpoints));
1446   PetscFunctionReturn(0);
1447 }
1448 
1449 /*@
1450   DMNetworkAssembleGraphStructures - Assembles vertex and edge data structures. Must be called after DMNetworkDistribute
1451 
1452   Collective on dm
1453 
1454   Input Parameters:
1455 . dm - the DMNetworkObject
1456 
1457   Note: the routine will create alternative orderings for the vertices and edges. Assume global network points are:
1458 
1459   points = [0 1 2 3 4 5 6]
1460 
1461   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]).
1462 
1463   With this new ordering a local PetscSection, global PetscSection and PetscSF will be created specific to the subset.
1464 
1465   Level: intermediate
1466 
1467 @*/
1468 PetscErrorCode DMNetworkAssembleGraphStructures(DM dm)
1469 {
1470   MPI_Comm       comm;
1471   PetscMPIInt    size;
1472   DM_Network     *network = (DM_Network*)dm->data;
1473 
1474   PetscFunctionBegin;
1475   PetscCall(PetscObjectGetComm((PetscObject)dm,&comm));
1476   PetscCallMPI(MPI_Comm_size(comm, &size));
1477 
1478   /* Create maps for vertices and edges */
1479   PetscCall(DMNetworkSetSubMap_private(network->vStart,network->vEnd,&network->vertex.mapping));
1480   PetscCall(DMNetworkSetSubMap_private(network->eStart,network->eEnd,&network->edge.mapping));
1481 
1482   /* Create local sub-sections */
1483   PetscCall(DMNetworkGetSubSection_private(network->DofSection,network->vStart,network->vEnd,&network->vertex.DofSection));
1484   PetscCall(DMNetworkGetSubSection_private(network->DofSection,network->eStart,network->eEnd,&network->edge.DofSection));
1485 
1486   if (size > 1) {
1487     PetscCall(PetscSFGetSubSF(network->plex->sf, network->vertex.mapping, &network->vertex.sf));
1488 
1489     PetscCall(PetscSectionCreateGlobalSection(network->vertex.DofSection, network->vertex.sf, PETSC_FALSE, PETSC_FALSE, &network->vertex.GlobalDofSection));
1490     PetscCall(PetscSFGetSubSF(network->plex->sf, network->edge.mapping, &network->edge.sf));
1491     PetscCall(PetscSectionCreateGlobalSection(network->edge.DofSection, network->edge.sf, PETSC_FALSE, PETSC_FALSE, &network->edge.GlobalDofSection));
1492   } else {
1493     /* create structures for vertex */
1494     PetscCall(PetscSectionClone(network->vertex.DofSection,&network->vertex.GlobalDofSection));
1495     /* create structures for edge */
1496     PetscCall(PetscSectionClone(network->edge.DofSection,&network->edge.GlobalDofSection));
1497   }
1498 
1499   /* Add viewers */
1500   PetscCall(PetscObjectSetName((PetscObject)network->edge.GlobalDofSection,"Global edge dof section"));
1501   PetscCall(PetscObjectSetName((PetscObject)network->vertex.GlobalDofSection,"Global vertex dof section"));
1502   PetscCall(PetscSectionViewFromOptions(network->edge.GlobalDofSection, NULL, "-edge_global_section_view"));
1503   PetscCall(PetscSectionViewFromOptions(network->vertex.GlobalDofSection, NULL, "-vertex_global_section_view"));
1504   PetscFunctionReturn(0);
1505 }
1506 
1507 /*
1508    Setup a lookup btable for the input v's owning subnetworks
1509    - add all owing subnetworks that connect to this v to the btable
1510      vertex_subnetid = supportingedge_subnetid
1511 */
1512 static inline PetscErrorCode SetSubnetIdLookupBT(DM dm,PetscInt v,PetscInt Nsubnet,PetscBT btable)
1513 {
1514   PetscInt       e,nedges,offset;
1515   const PetscInt *edges;
1516   DM_Network     *newDMnetwork = (DM_Network*)dm->data;
1517   DMNetworkComponentHeader header;
1518 
1519   PetscFunctionBegin;
1520   PetscCall(PetscBTMemzero(Nsubnet,btable));
1521   PetscCall(DMNetworkGetSupportingEdges(dm,v,&nedges,&edges));
1522   for (e=0; e<nedges; e++) {
1523     PetscCall(PetscSectionGetOffset(newDMnetwork->DataSection,edges[e],&offset));
1524     header = (DMNetworkComponentHeader)(newDMnetwork->componentdataarray+offset);
1525     PetscCall(PetscBTSet(btable,header->subnetid));
1526   }
1527   PetscFunctionReturn(0);
1528 }
1529 
1530 /*@
1531   DMNetworkDistribute - Distributes the network and moves associated component data
1532 
1533   Collective
1534 
1535   Input Parameters:
1536 + DM - the DMNetwork object
1537 - overlap - the overlap of partitions, 0 is the default
1538 
1539   Options Database Key:
1540 + -dmnetwork_view - Calls DMView() at the conclusion of DMSetUp()
1541 - -dmnetwork_view_distributed - Calls DMView() at the conclusion of DMNetworkDistribute()
1542 
1543   Notes:
1544   Distributes the network with <overlap>-overlapping partitioning of the edges.
1545 
1546   Level: intermediate
1547 
1548 .seealso: DMNetworkCreate()
1549 @*/
1550 PetscErrorCode DMNetworkDistribute(DM *dm,PetscInt overlap)
1551 {
1552   MPI_Comm       comm;
1553   PetscMPIInt    size;
1554   DM_Network     *oldDMnetwork = (DM_Network*)((*dm)->data);
1555   DM_Network     *newDMnetwork;
1556   PetscSF        pointsf=NULL;
1557   DM             newDM;
1558   PetscInt       j,e,v,offset,*subnetvtx,*subnetedge,Nsubnet,gidx,svtx_idx,nv;
1559   PetscInt       net,*sv;
1560   PetscBT        btable;
1561   PetscPartitioner         part;
1562   DMNetworkComponentHeader header;
1563 
1564   PetscFunctionBegin;
1565   PetscValidPointer(dm,1);
1566   PetscValidHeaderSpecific(*dm,DM_CLASSID,1);
1567   PetscCall(PetscObjectGetComm((PetscObject)*dm,&comm));
1568   PetscCallMPI(MPI_Comm_size(comm, &size));
1569   if (size == 1) PetscFunctionReturn(0);
1570 
1571   PetscCheck(!overlap,PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"overlap %" PetscInt_FMT " != 0 is not supported yet",overlap);
1572 
1573   /* This routine moves the component data to the appropriate processors. It makes use of the DataSection and the componentdataarray to move the component data to appropriate processors and returns a new DataSection and new componentdataarray. */
1574   PetscCall(DMNetworkCreate(PetscObjectComm((PetscObject)*dm),&newDM));
1575   newDMnetwork = (DM_Network*)newDM->data;
1576   newDMnetwork->max_comps_registered = oldDMnetwork->max_comps_registered;
1577   PetscCall(PetscMalloc1(newDMnetwork->max_comps_registered,&newDMnetwork->component));
1578 
1579   /* Enable runtime options for petscpartitioner */
1580   PetscCall(DMPlexGetPartitioner(oldDMnetwork->plex,&part));
1581   PetscCall(PetscPartitionerSetFromOptions(part));
1582 
1583   /* Distribute plex dm */
1584   PetscCall(DMPlexDistribute(oldDMnetwork->plex,overlap,&pointsf,&newDMnetwork->plex));
1585 
1586   /* Distribute dof section */
1587   PetscCall(PetscSectionCreate(comm,&newDMnetwork->DofSection));
1588   PetscCall(PetscSFDistributeSection(pointsf,oldDMnetwork->DofSection,NULL,newDMnetwork->DofSection));
1589 
1590   /* Distribute data and associated section */
1591   PetscCall(PetscSectionCreate(comm,&newDMnetwork->DataSection));
1592   PetscCall(DMPlexDistributeData(newDMnetwork->plex,pointsf,oldDMnetwork->DataSection,MPIU_INT,(void*)oldDMnetwork->componentdataarray,newDMnetwork->DataSection,(void**)&newDMnetwork->componentdataarray));
1593 
1594   PetscCall(PetscSectionGetChart(newDMnetwork->DataSection,&newDMnetwork->pStart,&newDMnetwork->pEnd));
1595   PetscCall(DMPlexGetHeightStratum(newDMnetwork->plex,0, &newDMnetwork->eStart,&newDMnetwork->eEnd));
1596   PetscCall(DMPlexGetHeightStratum(newDMnetwork->plex,1,&newDMnetwork->vStart,&newDMnetwork->vEnd));
1597   newDMnetwork->nEdges    = newDMnetwork->eEnd - newDMnetwork->eStart;
1598   newDMnetwork->nVertices = newDMnetwork->vEnd - newDMnetwork->vStart;
1599   newDMnetwork->NVertices = oldDMnetwork->NVertices;
1600   newDMnetwork->NEdges    = oldDMnetwork->NEdges;
1601   newDMnetwork->svtable   = oldDMnetwork->svtable; /* global table! */
1602   oldDMnetwork->svtable   = NULL;
1603 
1604   /* Set Dof section as the section for dm */
1605   PetscCall(DMSetLocalSection(newDMnetwork->plex,newDMnetwork->DofSection));
1606   PetscCall(DMGetGlobalSection(newDMnetwork->plex,&newDMnetwork->GlobalDofSection));
1607 
1608   /* Setup subnetwork info in the newDM */
1609   newDMnetwork->Nsubnet = oldDMnetwork->Nsubnet;
1610   newDMnetwork->Nsvtx   = oldDMnetwork->Nsvtx;
1611   oldDMnetwork->Nsvtx   = 0;
1612   newDMnetwork->svtx    = oldDMnetwork->svtx; /* global vertices! */
1613   oldDMnetwork->svtx    = NULL;
1614   PetscCall(PetscCalloc1(newDMnetwork->Nsubnet,&newDMnetwork->subnet));
1615 
1616   /* Copy over the global number of vertices and edges in each subnetwork.
1617      Note: these are calculated in DMNetworkLayoutSetUp()
1618   */
1619   Nsubnet = newDMnetwork->Nsubnet;
1620   for (j = 0; j < Nsubnet; j++) {
1621     newDMnetwork->subnet[j].Nvtx  = oldDMnetwork->subnet[j].Nvtx;
1622     newDMnetwork->subnet[j].Nedge = oldDMnetwork->subnet[j].Nedge;
1623   }
1624 
1625   /* Count local nedges for subnetworks */
1626   for (e = newDMnetwork->eStart; e < newDMnetwork->eEnd; e++) {
1627     PetscCall(PetscSectionGetOffset(newDMnetwork->DataSection,e,&offset));
1628     header = (DMNetworkComponentHeader)(newDMnetwork->componentdataarray+offset);
1629 
1630     /* Update pointers */
1631     header->size          = (PetscInt*)(header + 1);
1632     header->key           = header->size   + header->maxcomps;
1633     header->offset        = header->key    + header->maxcomps;
1634     header->nvar          = header->offset + header->maxcomps;
1635     header->offsetvarrel  = header->nvar   + header->maxcomps;
1636 
1637     newDMnetwork->subnet[header->subnetid].nedge++;
1638   }
1639 
1640   /* Setup a btable to keep track subnetworks owned by this process at a shared vertex */
1641   if (newDMnetwork->Nsvtx) {
1642     PetscCall(PetscBTCreate(Nsubnet,&btable));
1643   }
1644 
1645   /* Count local nvtx for subnetworks */
1646   for (v = newDMnetwork->vStart; v < newDMnetwork->vEnd; v++) {
1647     PetscCall(PetscSectionGetOffset(newDMnetwork->DataSection,v,&offset));
1648     header = (DMNetworkComponentHeader)(newDMnetwork->componentdataarray+offset);
1649 
1650     /* Update pointers */
1651     header->size          = (PetscInt*)(header + 1);
1652     header->key           = header->size   + header->maxcomps;
1653     header->offset        = header->key    + header->maxcomps;
1654     header->nvar          = header->offset + header->maxcomps;
1655     header->offsetvarrel  = header->nvar   + header->maxcomps;
1656 
1657     /* shared vertices: use gidx=header->index to check if v is a shared vertex */
1658     gidx = header->index;
1659     PetscCall(PetscTableFind(newDMnetwork->svtable,gidx+1,&svtx_idx));
1660     svtx_idx--;
1661 
1662     if (svtx_idx < 0) { /* not a shared vertex */
1663       newDMnetwork->subnet[header->subnetid].nvtx++;
1664     } else { /* a shared vertex belongs to more than one subnetworks, it is being counted by multiple subnets */
1665       /* Setup a lookup btable for this v's owning subnetworks */
1666       PetscCall(SetSubnetIdLookupBT(newDM,v,Nsubnet,btable));
1667 
1668       for (j=0; j<newDMnetwork->svtx[svtx_idx].n; j++) {
1669         sv  = newDMnetwork->svtx[svtx_idx].sv + 2*j;
1670         net = sv[0];
1671         if (PetscBTLookup(btable,net)) newDMnetwork->subnet[net].nvtx++; /* sv is on net owned by this proces */
1672       }
1673     }
1674   }
1675 
1676   /* Get total local nvtx for subnetworks */
1677   nv = 0;
1678   for (j=0; j<Nsubnet; j++) nv += newDMnetwork->subnet[j].nvtx;
1679   nv += newDMnetwork->Nsvtx;
1680 
1681   /* Now create the vertices and edge arrays for the subnetworks */
1682   PetscCall(PetscCalloc2(newDMnetwork->nEdges,&subnetedge,nv,&subnetvtx)); /* Maps local vertex to local subnetwork's vertex */
1683   newDMnetwork->subnetedge = subnetedge;
1684   newDMnetwork->subnetvtx  = subnetvtx;
1685   for (j=0; j < newDMnetwork->Nsubnet; j++) {
1686     newDMnetwork->subnet[j].edges = subnetedge;
1687     subnetedge                   += newDMnetwork->subnet[j].nedge;
1688 
1689     newDMnetwork->subnet[j].vertices = subnetvtx;
1690     subnetvtx                       += newDMnetwork->subnet[j].nvtx;
1691 
1692     /* Temporarily setting nvtx and nedge to 0 so we can use them as counters in the below for loop. These get updated when the vertices and edges are added. */
1693     newDMnetwork->subnet[j].nvtx = newDMnetwork->subnet[j].nedge = 0;
1694   }
1695   newDMnetwork->svertices = subnetvtx;
1696 
1697   /* Set the edges and vertices in each subnetwork */
1698   for (e = newDMnetwork->eStart; e < newDMnetwork->eEnd; e++) {
1699     PetscCall(PetscSectionGetOffset(newDMnetwork->DataSection,e,&offset));
1700     header = (DMNetworkComponentHeader)(newDMnetwork->componentdataarray+offset);
1701     newDMnetwork->subnet[header->subnetid].edges[newDMnetwork->subnet[header->subnetid].nedge++] = e;
1702   }
1703 
1704   nv = 0;
1705   for (v = newDMnetwork->vStart; v < newDMnetwork->vEnd; v++) {
1706     PetscCall(PetscSectionGetOffset(newDMnetwork->DataSection,v,&offset));
1707     header = (DMNetworkComponentHeader)(newDMnetwork->componentdataarray+offset);
1708 
1709     /* coupling vertices: use gidx = header->index to check if v is a coupling vertex */
1710     PetscCall(PetscTableFind(newDMnetwork->svtable,header->index+1,&svtx_idx));
1711     svtx_idx--;
1712     if (svtx_idx < 0) {
1713       newDMnetwork->subnet[header->subnetid].vertices[newDMnetwork->subnet[header->subnetid].nvtx++] = v;
1714     } else { /* a shared vertex */
1715       newDMnetwork->svertices[nv++] = v;
1716 
1717       /* Setup a lookup btable for this v's owning subnetworks */
1718       PetscCall(SetSubnetIdLookupBT(newDM,v,Nsubnet,btable));
1719 
1720       for (j=0; j<newDMnetwork->svtx[svtx_idx].n; j++) {
1721         sv  = newDMnetwork->svtx[svtx_idx].sv + 2*j;
1722         net = sv[0];
1723         if (PetscBTLookup(btable,net))
1724           newDMnetwork->subnet[net].vertices[newDMnetwork->subnet[net].nvtx++] = v;
1725       }
1726     }
1727   }
1728   newDMnetwork->nsvtx = nv;   /* num of local shared vertices */
1729 
1730   newDM->setupcalled = (*dm)->setupcalled;
1731   newDMnetwork->distributecalled = PETSC_TRUE;
1732 
1733   /* Free spaces */
1734   PetscCall(PetscSFDestroy(&pointsf));
1735   PetscCall(DMDestroy(dm));
1736   if (newDMnetwork->Nsvtx) {
1737     PetscCall(PetscBTDestroy(&btable));
1738   }
1739 
1740   /* View distributed dmnetwork */
1741   PetscCall(DMViewFromOptions(newDM,NULL,"-dmnetwork_view_distributed"));
1742 
1743   *dm  = newDM;
1744   PetscFunctionReturn(0);
1745 }
1746 
1747 /*@C
1748   PetscSFGetSubSF - Returns an SF for a specific subset of points. Leaves are re-numbered to reflect the new ordering
1749 
1750  Collective
1751 
1752   Input Parameters:
1753 + mainSF - the original SF structure
1754 - map - a ISLocalToGlobal mapping that contains the subset of points
1755 
1756   Output Parameter:
1757 . subSF - a subset of the mainSF for the desired subset.
1758 
1759   Level: intermediate
1760 @*/
1761 PetscErrorCode PetscSFGetSubSF(PetscSF mainsf,ISLocalToGlobalMapping map,PetscSF *subSF)
1762 {
1763   PetscInt              nroots, nleaves, *ilocal_sub;
1764   PetscInt              i, *ilocal_map, nroots_sub, nleaves_sub = 0;
1765   PetscInt              *local_points, *remote_points;
1766   PetscSFNode           *iremote_sub;
1767   const PetscInt        *ilocal;
1768   const PetscSFNode     *iremote;
1769 
1770   PetscFunctionBegin;
1771   PetscCall(PetscSFGetGraph(mainsf,&nroots,&nleaves,&ilocal,&iremote));
1772 
1773   /* Look for leaves that pertain to the subset of points. Get the local ordering */
1774   PetscCall(PetscMalloc1(nleaves,&ilocal_map));
1775   PetscCall(ISGlobalToLocalMappingApply(map,IS_GTOLM_MASK,nleaves,ilocal,NULL,ilocal_map));
1776   for (i = 0; i < nleaves; i++) {
1777     if (ilocal_map[i] != -1) nleaves_sub += 1;
1778   }
1779   /* Re-number ilocal with subset numbering. Need information from roots */
1780   PetscCall(PetscMalloc2(nroots,&local_points,nroots,&remote_points));
1781   for (i = 0; i < nroots; i++) local_points[i] = i;
1782   PetscCall(ISGlobalToLocalMappingApply(map,IS_GTOLM_MASK,nroots,local_points,NULL,local_points));
1783   PetscCall(PetscSFBcastBegin(mainsf, MPIU_INT, local_points, remote_points,MPI_REPLACE));
1784   PetscCall(PetscSFBcastEnd(mainsf, MPIU_INT, local_points, remote_points,MPI_REPLACE));
1785   /* Fill up graph using local (that is, local to the subset) numbering. */
1786   PetscCall(PetscMalloc1(nleaves_sub,&ilocal_sub));
1787   PetscCall(PetscMalloc1(nleaves_sub,&iremote_sub));
1788   nleaves_sub = 0;
1789   for (i = 0; i < nleaves; i++) {
1790     if (ilocal_map[i] != -1) {
1791       ilocal_sub[nleaves_sub] = ilocal_map[i];
1792       iremote_sub[nleaves_sub].rank = iremote[i].rank;
1793       iremote_sub[nleaves_sub].index = remote_points[ilocal[i]];
1794       nleaves_sub += 1;
1795     }
1796   }
1797   PetscCall(PetscFree2(local_points,remote_points));
1798   PetscCall(ISLocalToGlobalMappingGetSize(map,&nroots_sub));
1799 
1800   /* Create new subSF */
1801   PetscCall(PetscSFCreate(PETSC_COMM_WORLD,subSF));
1802   PetscCall(PetscSFSetFromOptions(*subSF));
1803   PetscCall(PetscSFSetGraph(*subSF,nroots_sub,nleaves_sub,ilocal_sub,PETSC_OWN_POINTER,iremote_sub,PETSC_COPY_VALUES));
1804   PetscCall(PetscFree(ilocal_map));
1805   PetscCall(PetscFree(iremote_sub));
1806   PetscFunctionReturn(0);
1807 }
1808 
1809 /*@C
1810   DMNetworkGetSupportingEdges - Return the supporting edges for this vertex point
1811 
1812   Not Collective
1813 
1814   Input Parameters:
1815 + dm - the DMNetwork object
1816 - p  - the vertex point
1817 
1818   Output Parameters:
1819 + nedges - number of edges connected to this vertex point
1820 - edges  - list of edge points
1821 
1822   Level: beginner
1823 
1824   Fortran Notes:
1825   Since it returns an array, this routine is only available in Fortran 90, and you must
1826   include petsc.h90 in your code.
1827 
1828 .seealso: DMNetworkCreate(), DMNetworkGetConnectedVertices()
1829 @*/
1830 PetscErrorCode DMNetworkGetSupportingEdges(DM dm,PetscInt vertex,PetscInt *nedges,const PetscInt *edges[])
1831 {
1832   DM_Network     *network = (DM_Network*)dm->data;
1833 
1834   PetscFunctionBegin;
1835   PetscCall(DMPlexGetSupportSize(network->plex,vertex,nedges));
1836   if (edges) PetscCall(DMPlexGetSupport(network->plex,vertex,edges));
1837   PetscFunctionReturn(0);
1838 }
1839 
1840 /*@C
1841   DMNetworkGetConnectedVertices - Return the connected vertices for this edge point
1842 
1843   Not Collective
1844 
1845   Input Parameters:
1846 + dm - the DMNetwork object
1847 - p - the edge point
1848 
1849   Output Parameters:
1850 . vertices - vertices connected to this edge
1851 
1852   Level: beginner
1853 
1854   Fortran Notes:
1855   Since it returns an array, this routine is only available in Fortran 90, and you must
1856   include petsc.h90 in your code.
1857 
1858 .seealso: DMNetworkCreate(), DMNetworkGetSupportingEdges()
1859 @*/
1860 PetscErrorCode DMNetworkGetConnectedVertices(DM dm,PetscInt edge,const PetscInt *vertices[])
1861 {
1862   DM_Network     *network = (DM_Network*)dm->data;
1863 
1864   PetscFunctionBegin;
1865   PetscCall(DMPlexGetCone(network->plex,edge,vertices));
1866   PetscFunctionReturn(0);
1867 }
1868 
1869 /*@
1870   DMNetworkIsSharedVertex - Returns TRUE if the vertex is shared by subnetworks
1871 
1872   Not Collective
1873 
1874   Input Parameters:
1875 + dm - the DMNetwork object
1876 - p - the vertex point
1877 
1878   Output Parameter:
1879 . flag - TRUE if the vertex is shared by subnetworks
1880 
1881   Level: beginner
1882 
1883 .seealso: DMNetworkAddSharedVertices(), DMNetworkIsGhostVertex()
1884 @*/
1885 PetscErrorCode DMNetworkIsSharedVertex(DM dm,PetscInt p,PetscBool *flag)
1886 {
1887   PetscInt       i;
1888 
1889   PetscFunctionBegin;
1890   *flag = PETSC_FALSE;
1891 
1892   if (dm->setupcalled) { /* DMNetworkGetGlobalVertexIndex() requires DMSetUp() be called */
1893     DM_Network     *network = (DM_Network*)dm->data;
1894     PetscInt       gidx;
1895     PetscCall(DMNetworkGetGlobalVertexIndex(dm,p,&gidx));
1896     PetscCall(PetscTableFind(network->svtable,gidx+1,&i));
1897     if (i) *flag = PETSC_TRUE;
1898   } else { /* would be removed? */
1899     PetscInt       nv;
1900     const PetscInt *vtx;
1901     PetscCall(DMNetworkGetSharedVertices(dm,&nv,&vtx));
1902     for (i=0; i<nv; i++) {
1903       if (p == vtx[i]) {
1904         *flag = PETSC_TRUE;
1905         break;
1906       }
1907     }
1908   }
1909   PetscFunctionReturn(0);
1910 }
1911 
1912 /*@
1913   DMNetworkIsGhostVertex - Returns TRUE if the vertex is a ghost vertex
1914 
1915   Not Collective
1916 
1917   Input Parameters:
1918 + dm - the DMNetwork object
1919 - p - the vertex point
1920 
1921   Output Parameter:
1922 . isghost - TRUE if the vertex is a ghost point
1923 
1924   Level: beginner
1925 
1926 .seealso: DMNetworkGetConnectedVertices(), DMNetworkGetVertexRange(), DMNetworkIsSharedVertex()
1927 @*/
1928 PetscErrorCode DMNetworkIsGhostVertex(DM dm,PetscInt p,PetscBool *isghost)
1929 {
1930   DM_Network     *network = (DM_Network*)dm->data;
1931   PetscInt       offsetg;
1932   PetscSection   sectiong;
1933 
1934   PetscFunctionBegin;
1935   *isghost = PETSC_FALSE;
1936   PetscCall(DMGetGlobalSection(network->plex,&sectiong));
1937   PetscCall(PetscSectionGetOffset(sectiong,p,&offsetg));
1938   if (offsetg < 0) *isghost = PETSC_TRUE;
1939   PetscFunctionReturn(0);
1940 }
1941 
1942 PetscErrorCode DMSetUp_Network(DM dm)
1943 {
1944   DM_Network     *network=(DM_Network*)dm->data;
1945 
1946   PetscFunctionBegin;
1947   PetscCall(DMNetworkComponentSetUp(dm));
1948   PetscCall(DMNetworkVariablesSetUp(dm));
1949 
1950   PetscCall(DMSetLocalSection(network->plex,network->DofSection));
1951   PetscCall(DMGetGlobalSection(network->plex,&network->GlobalDofSection));
1952 
1953   dm->setupcalled = PETSC_TRUE;
1954 
1955   /* View dmnetwork */
1956   PetscCall(DMViewFromOptions(dm,NULL,"-dmnetwork_view"));
1957   PetscFunctionReturn(0);
1958 }
1959 
1960 /*@
1961   DMNetworkHasJacobian - Sets global flag for using user's sub Jacobian matrices
1962       -- replaced by DMNetworkSetOption(network,userjacobian,PETSC_TURE)?
1963 
1964   Collective
1965 
1966   Input Parameters:
1967 + dm - the DMNetwork object
1968 . eflg - turn the option on (PETSC_TRUE) or off (PETSC_FALSE) if user provides Jacobian for edges
1969 - vflg - turn the option on (PETSC_TRUE) or off (PETSC_FALSE) if user provides Jacobian for vertices
1970 
1971  Level: intermediate
1972 
1973 @*/
1974 PetscErrorCode DMNetworkHasJacobian(DM dm,PetscBool eflg,PetscBool vflg)
1975 {
1976   DM_Network     *network=(DM_Network*)dm->data;
1977   PetscInt       nVertices = network->nVertices;
1978 
1979   PetscFunctionBegin;
1980   network->userEdgeJacobian   = eflg;
1981   network->userVertexJacobian = vflg;
1982 
1983   if (eflg && !network->Je) {
1984     PetscCall(PetscCalloc1(3*network->nEdges,&network->Je));
1985   }
1986 
1987   if (vflg && !network->Jv && nVertices) {
1988     PetscInt       i,*vptr,nedges,vStart=network->vStart;
1989     PetscInt       nedges_total;
1990     const PetscInt *edges;
1991 
1992     /* count nvertex_total */
1993     nedges_total = 0;
1994     PetscCall(PetscMalloc1(nVertices+1,&vptr));
1995 
1996     vptr[0] = 0;
1997     for (i=0; i<nVertices; i++) {
1998       PetscCall(DMNetworkGetSupportingEdges(dm,i+vStart,&nedges,&edges));
1999       nedges_total += nedges;
2000       vptr[i+1] = vptr[i] + 2*nedges + 1;
2001     }
2002 
2003     PetscCall(PetscCalloc1(2*nedges_total+nVertices,&network->Jv));
2004     network->Jvptr = vptr;
2005   }
2006   PetscFunctionReturn(0);
2007 }
2008 
2009 /*@
2010   DMNetworkEdgeSetMatrix - Sets user-provided Jacobian matrices for this edge to the network
2011 
2012   Not Collective
2013 
2014   Input Parameters:
2015 + dm - the DMNetwork object
2016 . p - the edge point
2017 - J - array (size = 3) of Jacobian submatrices for this edge point:
2018         J[0]: this edge
2019         J[1] and J[2]: connected vertices, obtained by calling DMNetworkGetConnectedVertices()
2020 
2021   Level: advanced
2022 
2023 .seealso: DMNetworkVertexSetMatrix()
2024 @*/
2025 PetscErrorCode DMNetworkEdgeSetMatrix(DM dm,PetscInt p,Mat J[])
2026 {
2027   DM_Network *network=(DM_Network*)dm->data;
2028 
2029   PetscFunctionBegin;
2030   PetscCheck(network->Je,PetscObjectComm((PetscObject)dm),PETSC_ERR_ORDER,"Must call DMNetworkHasJacobian() collectively before calling DMNetworkEdgeSetMatrix");
2031 
2032   if (J) {
2033     network->Je[3*p]   = J[0];
2034     network->Je[3*p+1] = J[1];
2035     network->Je[3*p+2] = J[2];
2036   }
2037   PetscFunctionReturn(0);
2038 }
2039 
2040 /*@
2041   DMNetworkVertexSetMatrix - Sets user-provided Jacobian matrix for this vertex to the network
2042 
2043   Not Collective
2044 
2045   Input Parameters:
2046 + dm - The DMNetwork object
2047 . p - the vertex point
2048 - J - array of Jacobian (size = 2*(num of supporting edges) + 1) submatrices for this vertex point:
2049         J[0]:       this vertex
2050         J[1+2*i]:   i-th supporting edge
2051         J[1+2*i+1]: i-th connected vertex
2052 
2053   Level: advanced
2054 
2055 .seealso: DMNetworkEdgeSetMatrix()
2056 @*/
2057 PetscErrorCode DMNetworkVertexSetMatrix(DM dm,PetscInt p,Mat J[])
2058 {
2059   DM_Network     *network=(DM_Network*)dm->data;
2060   PetscInt       i,*vptr,nedges,vStart=network->vStart;
2061   const PetscInt *edges;
2062 
2063   PetscFunctionBegin;
2064   PetscCheck(network->Jv,PetscObjectComm((PetscObject)dm),PETSC_ERR_ORDER,"Must call DMNetworkHasJacobian() collectively before calling DMNetworkVertexSetMatrix");
2065 
2066   if (J) {
2067     vptr = network->Jvptr;
2068     network->Jv[vptr[p-vStart]] = J[0]; /* Set Jacobian for this vertex */
2069 
2070     /* Set Jacobian for each supporting edge and connected vertex */
2071     PetscCall(DMNetworkGetSupportingEdges(dm,p,&nedges,&edges));
2072     for (i=1; i<=2*nedges; i++) network->Jv[vptr[p-vStart]+i] = J[i];
2073   }
2074   PetscFunctionReturn(0);
2075 }
2076 
2077 static inline PetscErrorCode MatSetPreallocationDenseblock_private(PetscInt nrows,PetscInt *rows,PetscInt ncols,PetscBool ghost,Vec vdnz,Vec vonz)
2078 {
2079   PetscInt       j;
2080   PetscScalar    val=(PetscScalar)ncols;
2081 
2082   PetscFunctionBegin;
2083   if (!ghost) {
2084     for (j=0; j<nrows; j++) {
2085       PetscCall(VecSetValues(vdnz,1,&rows[j],&val,ADD_VALUES));
2086     }
2087   } else {
2088     for (j=0; j<nrows; j++) {
2089       PetscCall(VecSetValues(vonz,1,&rows[j],&val,ADD_VALUES));
2090     }
2091   }
2092   PetscFunctionReturn(0);
2093 }
2094 
2095 static inline PetscErrorCode MatSetPreallocationUserblock_private(Mat Ju,PetscInt nrows,PetscInt *rows,PetscInt ncols,PetscBool ghost,Vec vdnz,Vec vonz)
2096 {
2097   PetscInt       j,ncols_u;
2098   PetscScalar    val;
2099 
2100   PetscFunctionBegin;
2101   if (!ghost) {
2102     for (j=0; j<nrows; j++) {
2103       PetscCall(MatGetRow(Ju,j,&ncols_u,NULL,NULL));
2104       val = (PetscScalar)ncols_u;
2105       PetscCall(VecSetValues(vdnz,1,&rows[j],&val,ADD_VALUES));
2106       PetscCall(MatRestoreRow(Ju,j,&ncols_u,NULL,NULL));
2107     }
2108   } else {
2109     for (j=0; j<nrows; j++) {
2110       PetscCall(MatGetRow(Ju,j,&ncols_u,NULL,NULL));
2111       val = (PetscScalar)ncols_u;
2112       PetscCall(VecSetValues(vonz,1,&rows[j],&val,ADD_VALUES));
2113       PetscCall(MatRestoreRow(Ju,j,&ncols_u,NULL,NULL));
2114     }
2115   }
2116   PetscFunctionReturn(0);
2117 }
2118 
2119 static inline PetscErrorCode MatSetPreallocationblock_private(Mat Ju,PetscInt nrows,PetscInt *rows,PetscInt ncols,PetscBool ghost,Vec vdnz,Vec vonz)
2120 {
2121   PetscFunctionBegin;
2122   if (Ju) {
2123     PetscCall(MatSetPreallocationUserblock_private(Ju,nrows,rows,ncols,ghost,vdnz,vonz));
2124   } else {
2125     PetscCall(MatSetPreallocationDenseblock_private(nrows,rows,ncols,ghost,vdnz,vonz));
2126   }
2127   PetscFunctionReturn(0);
2128 }
2129 
2130 static inline PetscErrorCode MatSetDenseblock_private(PetscInt nrows,PetscInt *rows,PetscInt ncols,PetscInt cstart,Mat *J)
2131 {
2132   PetscInt       j,*cols;
2133   PetscScalar    *zeros;
2134 
2135   PetscFunctionBegin;
2136   PetscCall(PetscCalloc2(ncols,&cols,nrows*ncols,&zeros));
2137   for (j=0; j<ncols; j++) cols[j] = j+ cstart;
2138   PetscCall(MatSetValues(*J,nrows,rows,ncols,cols,zeros,INSERT_VALUES));
2139   PetscCall(PetscFree2(cols,zeros));
2140   PetscFunctionReturn(0);
2141 }
2142 
2143 static inline PetscErrorCode MatSetUserblock_private(Mat Ju,PetscInt nrows,PetscInt *rows,PetscInt ncols,PetscInt cstart,Mat *J)
2144 {
2145   PetscInt       j,M,N,row,col,ncols_u;
2146   const PetscInt *cols;
2147   PetscScalar    zero=0.0;
2148 
2149   PetscFunctionBegin;
2150   PetscCall(MatGetSize(Ju,&M,&N));
2151   PetscCheck(nrows == M && ncols == N,PetscObjectComm((PetscObject)Ju),PETSC_ERR_USER,"%" PetscInt_FMT " by %" PetscInt_FMT " must equal %" PetscInt_FMT " by %" PetscInt_FMT "",nrows,ncols,M,N);
2152 
2153   for (row=0; row<nrows; row++) {
2154     PetscCall(MatGetRow(Ju,row,&ncols_u,&cols,NULL));
2155     for (j=0; j<ncols_u; j++) {
2156       col = cols[j] + cstart;
2157       PetscCall(MatSetValues(*J,1,&rows[row],1,&col,&zero,INSERT_VALUES));
2158     }
2159     PetscCall(MatRestoreRow(Ju,row,&ncols_u,&cols,NULL));
2160   }
2161   PetscFunctionReturn(0);
2162 }
2163 
2164 static inline PetscErrorCode MatSetblock_private(Mat Ju,PetscInt nrows,PetscInt *rows,PetscInt ncols,PetscInt cstart,Mat *J)
2165 {
2166   PetscFunctionBegin;
2167   if (Ju) {
2168     PetscCall(MatSetUserblock_private(Ju,nrows,rows,ncols,cstart,J));
2169   } else {
2170     PetscCall(MatSetDenseblock_private(nrows,rows,ncols,cstart,J));
2171   }
2172   PetscFunctionReturn(0);
2173 }
2174 
2175 /* 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.
2176 */
2177 PetscErrorCode CreateSubGlobalToLocalMapping_private(PetscSection globalsec, PetscSection localsec, ISLocalToGlobalMapping *ltog)
2178 {
2179   PetscInt       i,size,dof;
2180   PetscInt       *glob2loc;
2181 
2182   PetscFunctionBegin;
2183   PetscCall(PetscSectionGetStorageSize(localsec,&size));
2184   PetscCall(PetscMalloc1(size,&glob2loc));
2185 
2186   for (i = 0; i < size; i++) {
2187     PetscCall(PetscSectionGetOffset(globalsec,i,&dof));
2188     dof = (dof >= 0) ? dof : -(dof + 1);
2189     glob2loc[i] = dof;
2190   }
2191 
2192   PetscCall(ISLocalToGlobalMappingCreate(PETSC_COMM_WORLD,1,size,glob2loc,PETSC_OWN_POINTER,ltog));
2193 #if 0
2194   PetscCall(PetscIntView(size,glob2loc,PETSC_VIEWER_STDOUT_WORLD));
2195 #endif
2196   PetscFunctionReturn(0);
2197 }
2198 
2199 #include <petsc/private/matimpl.h>
2200 
2201 PetscErrorCode DMCreateMatrix_Network_Nest(DM dm,Mat *J)
2202 {
2203   DM_Network     *network = (DM_Network*)dm->data;
2204   PetscInt       eDof,vDof;
2205   Mat            j11,j12,j21,j22,bA[2][2];
2206   MPI_Comm       comm;
2207   ISLocalToGlobalMapping eISMap,vISMap;
2208 
2209   PetscFunctionBegin;
2210   PetscCall(PetscObjectGetComm((PetscObject)dm,&comm));
2211 
2212   PetscCall(PetscSectionGetConstrainedStorageSize(network->edge.GlobalDofSection,&eDof));
2213   PetscCall(PetscSectionGetConstrainedStorageSize(network->vertex.GlobalDofSection,&vDof));
2214 
2215   PetscCall(MatCreate(comm, &j11));
2216   PetscCall(MatSetSizes(j11, eDof, eDof, PETSC_DETERMINE, PETSC_DETERMINE));
2217   PetscCall(MatSetType(j11, MATMPIAIJ));
2218 
2219   PetscCall(MatCreate(comm, &j12));
2220   PetscCall(MatSetSizes(j12, eDof, vDof, PETSC_DETERMINE ,PETSC_DETERMINE));
2221   PetscCall(MatSetType(j12, MATMPIAIJ));
2222 
2223   PetscCall(MatCreate(comm, &j21));
2224   PetscCall(MatSetSizes(j21, vDof, eDof, PETSC_DETERMINE, PETSC_DETERMINE));
2225   PetscCall(MatSetType(j21, MATMPIAIJ));
2226 
2227   PetscCall(MatCreate(comm, &j22));
2228   PetscCall(MatSetSizes(j22, vDof, vDof, PETSC_DETERMINE, PETSC_DETERMINE));
2229   PetscCall(MatSetType(j22, MATMPIAIJ));
2230 
2231   bA[0][0] = j11;
2232   bA[0][1] = j12;
2233   bA[1][0] = j21;
2234   bA[1][1] = j22;
2235 
2236   PetscCall(CreateSubGlobalToLocalMapping_private(network->edge.GlobalDofSection,network->edge.DofSection,&eISMap));
2237   PetscCall(CreateSubGlobalToLocalMapping_private(network->vertex.GlobalDofSection,network->vertex.DofSection,&vISMap));
2238 
2239   PetscCall(MatSetLocalToGlobalMapping(j11,eISMap,eISMap));
2240   PetscCall(MatSetLocalToGlobalMapping(j12,eISMap,vISMap));
2241   PetscCall(MatSetLocalToGlobalMapping(j21,vISMap,eISMap));
2242   PetscCall(MatSetLocalToGlobalMapping(j22,vISMap,vISMap));
2243 
2244   PetscCall(MatSetUp(j11));
2245   PetscCall(MatSetUp(j12));
2246   PetscCall(MatSetUp(j21));
2247   PetscCall(MatSetUp(j22));
2248 
2249   PetscCall(MatCreateNest(comm,2,NULL,2,NULL,&bA[0][0],J));
2250   PetscCall(MatSetUp(*J));
2251   PetscCall(MatNestSetVecType(*J,VECNEST));
2252   PetscCall(MatDestroy(&j11));
2253   PetscCall(MatDestroy(&j12));
2254   PetscCall(MatDestroy(&j21));
2255   PetscCall(MatDestroy(&j22));
2256 
2257   PetscCall(MatAssemblyBegin(*J,MAT_FINAL_ASSEMBLY));
2258   PetscCall(MatAssemblyEnd(*J,MAT_FINAL_ASSEMBLY));
2259   PetscCall(MatSetOption(*J,MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_TRUE));
2260 
2261   /* Free structures */
2262   PetscCall(ISLocalToGlobalMappingDestroy(&eISMap));
2263   PetscCall(ISLocalToGlobalMappingDestroy(&vISMap));
2264   PetscFunctionReturn(0);
2265 }
2266 
2267 PetscErrorCode DMCreateMatrix_Network(DM dm,Mat *J)
2268 {
2269   DM_Network     *network = (DM_Network*)dm->data;
2270   PetscInt       eStart,eEnd,vStart,vEnd,rstart,nrows,*rows,localSize;
2271   PetscInt       cstart,ncols,j,e,v;
2272   PetscBool      ghost,ghost_vc,ghost2,isNest;
2273   Mat            Juser;
2274   PetscSection   sectionGlobal;
2275   PetscInt       nedges,*vptr=NULL,vc,*rows_v; /* suppress maybe-uninitialized warning */
2276   const PetscInt *edges,*cone;
2277   MPI_Comm       comm;
2278   MatType        mtype;
2279   Vec            vd_nz,vo_nz;
2280   PetscInt       *dnnz,*onnz;
2281   PetscScalar    *vdnz,*vonz;
2282 
2283   PetscFunctionBegin;
2284   mtype = dm->mattype;
2285   PetscCall(PetscStrcmp(mtype,MATNEST,&isNest));
2286   if (isNest) {
2287     PetscCall(DMCreateMatrix_Network_Nest(dm,J));
2288     PetscCall(MatSetDM(*J,dm));
2289     PetscFunctionReturn(0);
2290   }
2291 
2292   if (!network->userEdgeJacobian && !network->userVertexJacobian) {
2293     /* user does not provide Jacobian blocks */
2294     PetscCall(DMCreateMatrix_Plex(network->plex,J));
2295     PetscCall(MatSetDM(*J,dm));
2296     PetscFunctionReturn(0);
2297   }
2298 
2299   PetscCall(MatCreate(PetscObjectComm((PetscObject)dm),J));
2300   PetscCall(DMGetGlobalSection(network->plex,&sectionGlobal));
2301   PetscCall(PetscSectionGetConstrainedStorageSize(sectionGlobal,&localSize));
2302   PetscCall(MatSetSizes(*J,localSize,localSize,PETSC_DETERMINE,PETSC_DETERMINE));
2303 
2304   PetscCall(MatSetType(*J,MATAIJ));
2305   PetscCall(MatSetFromOptions(*J));
2306 
2307   /* (1) Set matrix preallocation */
2308   /*------------------------------*/
2309   PetscCall(PetscObjectGetComm((PetscObject)dm,&comm));
2310   PetscCall(VecCreate(comm,&vd_nz));
2311   PetscCall(VecSetSizes(vd_nz,localSize,PETSC_DECIDE));
2312   PetscCall(VecSetFromOptions(vd_nz));
2313   PetscCall(VecSet(vd_nz,0.0));
2314   PetscCall(VecDuplicate(vd_nz,&vo_nz));
2315 
2316   /* Set preallocation for edges */
2317   /*-----------------------------*/
2318   PetscCall(DMNetworkGetEdgeRange(dm,&eStart,&eEnd));
2319 
2320   PetscCall(PetscMalloc1(localSize,&rows));
2321   for (e=eStart; e<eEnd; e++) {
2322     /* Get row indices */
2323     PetscCall(DMNetworkGetGlobalVecOffset(dm,e,ALL_COMPONENTS,&rstart));
2324     PetscCall(PetscSectionGetDof(network->DofSection,e,&nrows));
2325     if (nrows) {
2326       for (j=0; j<nrows; j++) rows[j] = j + rstart;
2327 
2328       /* Set preallocation for connected vertices */
2329       PetscCall(DMNetworkGetConnectedVertices(dm,e,&cone));
2330       for (v=0; v<2; v++) {
2331         PetscCall(PetscSectionGetDof(network->DofSection,cone[v],&ncols));
2332 
2333         if (network->Je) {
2334           Juser = network->Je[3*e+1+v]; /* Jacobian(e,v) */
2335         } else Juser = NULL;
2336         PetscCall(DMNetworkIsGhostVertex(dm,cone[v],&ghost));
2337         PetscCall(MatSetPreallocationblock_private(Juser,nrows,rows,ncols,ghost,vd_nz,vo_nz));
2338       }
2339 
2340       /* Set preallocation for edge self */
2341       cstart = rstart;
2342       if (network->Je) {
2343         Juser = network->Je[3*e]; /* Jacobian(e,e) */
2344       } else Juser = NULL;
2345       PetscCall(MatSetPreallocationblock_private(Juser,nrows,rows,nrows,PETSC_FALSE,vd_nz,vo_nz));
2346     }
2347   }
2348 
2349   /* Set preallocation for vertices */
2350   /*--------------------------------*/
2351   PetscCall(DMNetworkGetVertexRange(dm,&vStart,&vEnd));
2352   if (vEnd - vStart) vptr = network->Jvptr;
2353 
2354   for (v=vStart; v<vEnd; v++) {
2355     /* Get row indices */
2356     PetscCall(DMNetworkGetGlobalVecOffset(dm,v,ALL_COMPONENTS,&rstart));
2357     PetscCall(PetscSectionGetDof(network->DofSection,v,&nrows));
2358     if (!nrows) continue;
2359 
2360     PetscCall(DMNetworkIsGhostVertex(dm,v,&ghost));
2361     if (ghost) {
2362       PetscCall(PetscMalloc1(nrows,&rows_v));
2363     } else {
2364       rows_v = rows;
2365     }
2366 
2367     for (j=0; j<nrows; j++) rows_v[j] = j + rstart;
2368 
2369     /* Get supporting edges and connected vertices */
2370     PetscCall(DMNetworkGetSupportingEdges(dm,v,&nedges,&edges));
2371 
2372     for (e=0; e<nedges; e++) {
2373       /* Supporting edges */
2374       PetscCall(DMNetworkGetGlobalVecOffset(dm,edges[e],ALL_COMPONENTS,&cstart));
2375       PetscCall(PetscSectionGetDof(network->DofSection,edges[e],&ncols));
2376 
2377       if (network->Jv) {
2378         Juser = network->Jv[vptr[v-vStart]+2*e+1]; /* Jacobian(v,e) */
2379       } else Juser = NULL;
2380       PetscCall(MatSetPreallocationblock_private(Juser,nrows,rows_v,ncols,ghost,vd_nz,vo_nz));
2381 
2382       /* Connected vertices */
2383       PetscCall(DMNetworkGetConnectedVertices(dm,edges[e],&cone));
2384       vc = (v == cone[0]) ? cone[1]:cone[0];
2385       PetscCall(DMNetworkIsGhostVertex(dm,vc,&ghost_vc));
2386 
2387       PetscCall(PetscSectionGetDof(network->DofSection,vc,&ncols));
2388 
2389       if (network->Jv) {
2390         Juser = network->Jv[vptr[v-vStart]+2*e+2]; /* Jacobian(v,vc) */
2391       } else Juser = NULL;
2392       if (ghost_vc||ghost) {
2393         ghost2 = PETSC_TRUE;
2394       } else {
2395         ghost2 = PETSC_FALSE;
2396       }
2397       PetscCall(MatSetPreallocationblock_private(Juser,nrows,rows_v,ncols,ghost2,vd_nz,vo_nz));
2398     }
2399 
2400     /* Set preallocation for vertex self */
2401     PetscCall(DMNetworkIsGhostVertex(dm,v,&ghost));
2402     if (!ghost) {
2403       PetscCall(DMNetworkGetGlobalVecOffset(dm,v,ALL_COMPONENTS,&cstart));
2404       if (network->Jv) {
2405         Juser = network->Jv[vptr[v-vStart]]; /* Jacobian(v,v) */
2406       } else Juser = NULL;
2407       PetscCall(MatSetPreallocationblock_private(Juser,nrows,rows_v,nrows,PETSC_FALSE,vd_nz,vo_nz));
2408     }
2409     if (ghost) {
2410       PetscCall(PetscFree(rows_v));
2411     }
2412   }
2413 
2414   PetscCall(VecAssemblyBegin(vd_nz));
2415   PetscCall(VecAssemblyBegin(vo_nz));
2416 
2417   PetscCall(PetscMalloc2(localSize,&dnnz,localSize,&onnz));
2418 
2419   PetscCall(VecAssemblyEnd(vd_nz));
2420   PetscCall(VecAssemblyEnd(vo_nz));
2421 
2422   PetscCall(VecGetArray(vd_nz,&vdnz));
2423   PetscCall(VecGetArray(vo_nz,&vonz));
2424   for (j=0; j<localSize; j++) {
2425     dnnz[j] = (PetscInt)PetscRealPart(vdnz[j]);
2426     onnz[j] = (PetscInt)PetscRealPart(vonz[j]);
2427   }
2428   PetscCall(VecRestoreArray(vd_nz,&vdnz));
2429   PetscCall(VecRestoreArray(vo_nz,&vonz));
2430   PetscCall(VecDestroy(&vd_nz));
2431   PetscCall(VecDestroy(&vo_nz));
2432 
2433   PetscCall(MatSeqAIJSetPreallocation(*J,0,dnnz));
2434   PetscCall(MatMPIAIJSetPreallocation(*J,0,dnnz,0,onnz));
2435   PetscCall(MatSetOption(*J,MAT_NEW_NONZERO_ALLOCATION_ERR,PETSC_TRUE));
2436 
2437   PetscCall(PetscFree2(dnnz,onnz));
2438 
2439   /* (2) Set matrix entries for edges */
2440   /*----------------------------------*/
2441   for (e=eStart; e<eEnd; e++) {
2442     /* Get row indices */
2443     PetscCall(DMNetworkGetGlobalVecOffset(dm,e,ALL_COMPONENTS,&rstart));
2444     PetscCall(PetscSectionGetDof(network->DofSection,e,&nrows));
2445     if (nrows) {
2446       for (j=0; j<nrows; j++) rows[j] = j + rstart;
2447 
2448       /* Set matrix entries for connected vertices */
2449       PetscCall(DMNetworkGetConnectedVertices(dm,e,&cone));
2450       for (v=0; v<2; v++) {
2451         PetscCall(DMNetworkGetGlobalVecOffset(dm,cone[v],ALL_COMPONENTS,&cstart));
2452         PetscCall(PetscSectionGetDof(network->DofSection,cone[v],&ncols));
2453 
2454         if (network->Je) {
2455           Juser = network->Je[3*e+1+v]; /* Jacobian(e,v) */
2456         } else Juser = NULL;
2457         PetscCall(MatSetblock_private(Juser,nrows,rows,ncols,cstart,J));
2458       }
2459 
2460       /* Set matrix entries for edge self */
2461       cstart = rstart;
2462       if (network->Je) {
2463         Juser = network->Je[3*e]; /* Jacobian(e,e) */
2464       } else Juser = NULL;
2465       PetscCall(MatSetblock_private(Juser,nrows,rows,nrows,cstart,J));
2466     }
2467   }
2468 
2469   /* Set matrix entries for vertices */
2470   /*---------------------------------*/
2471   for (v=vStart; v<vEnd; v++) {
2472     /* Get row indices */
2473     PetscCall(DMNetworkGetGlobalVecOffset(dm,v,ALL_COMPONENTS,&rstart));
2474     PetscCall(PetscSectionGetDof(network->DofSection,v,&nrows));
2475     if (!nrows) continue;
2476 
2477     PetscCall(DMNetworkIsGhostVertex(dm,v,&ghost));
2478     if (ghost) {
2479       PetscCall(PetscMalloc1(nrows,&rows_v));
2480     } else {
2481       rows_v = rows;
2482     }
2483     for (j=0; j<nrows; j++) rows_v[j] = j + rstart;
2484 
2485     /* Get supporting edges and connected vertices */
2486     PetscCall(DMNetworkGetSupportingEdges(dm,v,&nedges,&edges));
2487 
2488     for (e=0; e<nedges; e++) {
2489       /* Supporting edges */
2490       PetscCall(DMNetworkGetGlobalVecOffset(dm,edges[e],ALL_COMPONENTS,&cstart));
2491       PetscCall(PetscSectionGetDof(network->DofSection,edges[e],&ncols));
2492 
2493       if (network->Jv) {
2494         Juser = network->Jv[vptr[v-vStart]+2*e+1]; /* Jacobian(v,e) */
2495       } else Juser = NULL;
2496       PetscCall(MatSetblock_private(Juser,nrows,rows_v,ncols,cstart,J));
2497 
2498       /* Connected vertices */
2499       PetscCall(DMNetworkGetConnectedVertices(dm,edges[e],&cone));
2500       vc = (v == cone[0]) ? cone[1]:cone[0];
2501 
2502       PetscCall(DMNetworkGetGlobalVecOffset(dm,vc,ALL_COMPONENTS,&cstart));
2503       PetscCall(PetscSectionGetDof(network->DofSection,vc,&ncols));
2504 
2505       if (network->Jv) {
2506         Juser = network->Jv[vptr[v-vStart]+2*e+2]; /* Jacobian(v,vc) */
2507       } else Juser = NULL;
2508       PetscCall(MatSetblock_private(Juser,nrows,rows_v,ncols,cstart,J));
2509     }
2510 
2511     /* Set matrix entries for vertex self */
2512     if (!ghost) {
2513       PetscCall(DMNetworkGetGlobalVecOffset(dm,v,ALL_COMPONENTS,&cstart));
2514       if (network->Jv) {
2515         Juser = network->Jv[vptr[v-vStart]]; /* Jacobian(v,v) */
2516       } else Juser = NULL;
2517       PetscCall(MatSetblock_private(Juser,nrows,rows_v,nrows,cstart,J));
2518     }
2519     if (ghost) {
2520       PetscCall(PetscFree(rows_v));
2521     }
2522   }
2523   PetscCall(PetscFree(rows));
2524 
2525   PetscCall(MatAssemblyBegin(*J,MAT_FINAL_ASSEMBLY));
2526   PetscCall(MatAssemblyEnd(*J,MAT_FINAL_ASSEMBLY));
2527 
2528   PetscCall(MatSetDM(*J,dm));
2529   PetscFunctionReturn(0);
2530 }
2531 
2532 PetscErrorCode DMDestroy_Network(DM dm)
2533 {
2534   DM_Network     *network = (DM_Network*)dm->data;
2535   PetscInt       j,np;
2536 
2537   PetscFunctionBegin;
2538   if (--network->refct > 0) PetscFunctionReturn(0);
2539   PetscCall(PetscFree(network->Je));
2540   if (network->Jv) {
2541     PetscCall(PetscFree(network->Jvptr));
2542     PetscCall(PetscFree(network->Jv));
2543   }
2544 
2545   PetscCall(ISLocalToGlobalMappingDestroy(&network->vertex.mapping));
2546   PetscCall(PetscSectionDestroy(&network->vertex.DofSection));
2547   PetscCall(PetscSectionDestroy(&network->vertex.GlobalDofSection));
2548   PetscCall(PetscFree(network->vltog));
2549   PetscCall(PetscSFDestroy(&network->vertex.sf));
2550   /* edge */
2551   PetscCall(ISLocalToGlobalMappingDestroy(&network->edge.mapping));
2552   PetscCall(PetscSectionDestroy(&network->edge.DofSection));
2553   PetscCall(PetscSectionDestroy(&network->edge.GlobalDofSection));
2554   PetscCall(PetscSFDestroy(&network->edge.sf));
2555   PetscCall(DMDestroy(&network->plex));
2556   PetscCall(PetscSectionDestroy(&network->DataSection));
2557   PetscCall(PetscSectionDestroy(&network->DofSection));
2558 
2559   for (j=0; j<network->Nsvtx; j++) PetscCall(PetscFree(network->svtx[j].sv));
2560   PetscCall(PetscFree(network->svtx));
2561   PetscCall(PetscFree2(network->subnetedge,network->subnetvtx));
2562 
2563   PetscCall(PetscTableDestroy(&network->svtable));
2564   PetscCall(PetscFree(network->subnet));
2565   PetscCall(PetscFree(network->component));
2566   PetscCall(PetscFree(network->componentdataarray));
2567 
2568   if (network->header) {
2569     np = network->pEnd - network->pStart;
2570     for (j=0; j < np; j++) {
2571       PetscCall(PetscFree5(network->header[j].size,network->header[j].key,network->header[j].offset,network->header[j].nvar,network->header[j].offsetvarrel));
2572       PetscCall(PetscFree(network->cvalue[j].data));
2573     }
2574     PetscCall(PetscFree2(network->header,network->cvalue));
2575   }
2576   PetscCall(PetscFree(network));
2577   PetscFunctionReturn(0);
2578 }
2579 
2580 PetscErrorCode DMView_Network(DM dm,PetscViewer viewer)
2581 {
2582   PetscBool      iascii;
2583   PetscMPIInt    rank;
2584 
2585   PetscFunctionBegin;
2586   PetscValidHeaderSpecific(dm,DM_CLASSID, 1);
2587   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
2588   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm),&rank));
2589   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&iascii));
2590   if (iascii) {
2591     const PetscInt *cone,*vtx,*edges;
2592     PetscInt       vfrom,vto,i,j,nv,ne,nsv,p,nsubnet;
2593     DM_Network     *network = (DM_Network*)dm->data;
2594 
2595     nsubnet = network->Nsubnet; /* num of subnetworks */
2596     if (rank == 0) {
2597       PetscCall(PetscPrintf(PETSC_COMM_SELF,"  NSubnets: %" PetscInt_FMT "; NEdges: %" PetscInt_FMT "; NVertices: %" PetscInt_FMT "; NSharedVertices: %" PetscInt_FMT ".\n",nsubnet,network->NEdges,network->NVertices,network->Nsvtx));
2598     }
2599 
2600     PetscCall(DMNetworkGetSharedVertices(dm,&nsv,NULL));
2601     PetscCall(PetscViewerASCIIPushSynchronized(viewer));
2602     PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "  [%d] nEdges: %" PetscInt_FMT "; nVertices: %" PetscInt_FMT "; nSharedVertices: %" PetscInt_FMT "\n",rank,network->nEdges,network->nVertices,nsv));
2603 
2604     for (i=0; i<nsubnet; i++) {
2605       PetscCall(DMNetworkGetSubnetwork(dm,i,&nv,&ne,&vtx,&edges));
2606       if (ne) {
2607         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "     Subnet %" PetscInt_FMT ": nEdges %" PetscInt_FMT ", nVertices(include shared vertices) %" PetscInt_FMT "\n",i,ne,nv));
2608         for (j=0; j<ne; j++) {
2609           p = edges[j];
2610           PetscCall(DMNetworkGetConnectedVertices(dm,p,&cone));
2611           PetscCall(DMNetworkGetGlobalVertexIndex(dm,cone[0],&vfrom));
2612           PetscCall(DMNetworkGetGlobalVertexIndex(dm,cone[1],&vto));
2613           PetscCall(DMNetworkGetGlobalEdgeIndex(dm,edges[j],&p));
2614           PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "       edge %" PetscInt_FMT ": %" PetscInt_FMT " ----> %" PetscInt_FMT "\n",p,vfrom,vto));
2615         }
2616       }
2617     }
2618 
2619     /* Shared vertices */
2620     PetscCall(DMNetworkGetSharedVertices(dm,NULL,&vtx));
2621     if (nsv) {
2622       PetscInt       gidx;
2623       PetscBool      ghost;
2624       const PetscInt *sv=NULL;
2625 
2626       PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "     SharedVertices:\n"));
2627       for (i=0; i<nsv; i++) {
2628         PetscCall(DMNetworkIsGhostVertex(dm,vtx[i],&ghost));
2629         if (ghost) continue;
2630 
2631         PetscCall(DMNetworkSharedVertexGetInfo(dm,vtx[i],&gidx,&nv,&sv));
2632         PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "       svtx %" PetscInt_FMT ": global index %" PetscInt_FMT ", subnet[%" PetscInt_FMT "].%" PetscInt_FMT " ---->\n",i,gidx,sv[0],sv[1]));
2633         for (j=1; j<nv; j++) {
2634           PetscCall(PetscViewerASCIISynchronizedPrintf(viewer, "                                           ----> subnet[%" PetscInt_FMT "].%" PetscInt_FMT "\n",sv[2*j],sv[2*j+1]));
2635         }
2636       }
2637     }
2638     PetscCall(PetscViewerFlush(viewer));
2639     PetscCall(PetscViewerASCIIPopSynchronized(viewer));
2640   } else PetscCheck(iascii,PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Viewer type %s not yet supported for DMNetwork writing",((PetscObject)viewer)->type_name);
2641   PetscFunctionReturn(0);
2642 }
2643 
2644 PetscErrorCode DMGlobalToLocalBegin_Network(DM dm, Vec g, InsertMode mode, Vec l)
2645 {
2646   DM_Network     *network = (DM_Network*)dm->data;
2647 
2648   PetscFunctionBegin;
2649   PetscCall(DMGlobalToLocalBegin(network->plex,g,mode,l));
2650   PetscFunctionReturn(0);
2651 }
2652 
2653 PetscErrorCode DMGlobalToLocalEnd_Network(DM dm, Vec g, InsertMode mode, Vec l)
2654 {
2655   DM_Network     *network = (DM_Network*)dm->data;
2656 
2657   PetscFunctionBegin;
2658   PetscCall(DMGlobalToLocalEnd(network->plex,g,mode,l));
2659   PetscFunctionReturn(0);
2660 }
2661 
2662 PetscErrorCode DMLocalToGlobalBegin_Network(DM dm, Vec l, InsertMode mode, Vec g)
2663 {
2664   DM_Network     *network = (DM_Network*)dm->data;
2665 
2666   PetscFunctionBegin;
2667   PetscCall(DMLocalToGlobalBegin(network->plex,l,mode,g));
2668   PetscFunctionReturn(0);
2669 }
2670 
2671 PetscErrorCode DMLocalToGlobalEnd_Network(DM dm, Vec l, InsertMode mode, Vec g)
2672 {
2673   DM_Network     *network = (DM_Network*)dm->data;
2674 
2675   PetscFunctionBegin;
2676   PetscCall(DMLocalToGlobalEnd(network->plex,l,mode,g));
2677   PetscFunctionReturn(0);
2678 }
2679 
2680 /*@
2681   DMNetworkGetVertexLocalToGlobalOrdering - Get vertex global index
2682 
2683   Not collective
2684 
2685   Input Parameters:
2686 + dm - the dm object
2687 - vloc - local vertex ordering, start from 0
2688 
2689   Output Parameters:
2690 .  vg  - global vertex ordering, start from 0
2691 
2692   Level: advanced
2693 
2694 .seealso: DMNetworkSetVertexLocalToGlobalOrdering()
2695 @*/
2696 PetscErrorCode DMNetworkGetVertexLocalToGlobalOrdering(DM dm,PetscInt vloc,PetscInt *vg)
2697 {
2698   DM_Network  *network = (DM_Network*)dm->data;
2699   PetscInt    *vltog = network->vltog;
2700 
2701   PetscFunctionBegin;
2702   PetscCheck(vltog,PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_WRONGSTATE,"Must call DMNetworkSetVertexLocalToGlobalOrdering() first");
2703   *vg = vltog[vloc];
2704   PetscFunctionReturn(0);
2705 }
2706 
2707 /*@
2708   DMNetworkSetVertexLocalToGlobalOrdering - Create and setup vertex local to global map
2709 
2710   Collective
2711 
2712   Input Parameters:
2713 . dm - the dm object
2714 
2715   Level: advanced
2716 
2717 .seealso: DMNetworkGetGlobalVertexIndex()
2718 @*/
2719 PetscErrorCode DMNetworkSetVertexLocalToGlobalOrdering(DM dm)
2720 {
2721   DM_Network        *network=(DM_Network*)dm->data;
2722   MPI_Comm          comm;
2723   PetscMPIInt       rank,size,*displs=NULL,*recvcounts=NULL,remoterank;
2724   PetscBool         ghost;
2725   PetscInt          *vltog,nroots,nleaves,i,*vrange,k,N,lidx;
2726   const PetscSFNode *iremote;
2727   PetscSF           vsf;
2728   Vec               Vleaves,Vleaves_seq;
2729   VecScatter        ctx;
2730   PetscScalar       *varr,val;
2731   const PetscScalar *varr_read;
2732 
2733   PetscFunctionBegin;
2734   PetscCall(PetscObjectGetComm((PetscObject)dm,&comm));
2735   PetscCallMPI(MPI_Comm_size(comm,&size));
2736   PetscCallMPI(MPI_Comm_rank(comm,&rank));
2737 
2738   if (size == 1) {
2739     nroots = network->vEnd - network->vStart;
2740     PetscCall(PetscMalloc1(nroots, &vltog));
2741     for (i=0; i<nroots; i++) vltog[i] = i;
2742     network->vltog = vltog;
2743     PetscFunctionReturn(0);
2744   }
2745 
2746   PetscCheck(network->distributecalled,comm, PETSC_ERR_ARG_WRONGSTATE,"Must call DMNetworkDistribute() first");
2747   if (network->vltog) {
2748     PetscCall(PetscFree(network->vltog));
2749   }
2750 
2751   PetscCall(DMNetworkSetSubMap_private(network->vStart,network->vEnd,&network->vertex.mapping));
2752   PetscCall(PetscSFGetSubSF(network->plex->sf, network->vertex.mapping, &network->vertex.sf));
2753   vsf = network->vertex.sf;
2754 
2755   PetscCall(PetscMalloc3(size+1,&vrange,size,&displs,size,&recvcounts));
2756   PetscCall(PetscSFGetGraph(vsf,&nroots,&nleaves,NULL,&iremote));
2757 
2758   for (i=0; i<size; i++) { displs[i] = i; recvcounts[i] = 1;}
2759 
2760   i         = nroots - nleaves; /* local number of vertices, excluding ghosts */
2761   vrange[0] = 0;
2762   PetscCallMPI(MPI_Allgatherv(&i,1,MPIU_INT,vrange+1,recvcounts,displs,MPIU_INT,comm));
2763   for (i=2; i<size+1; i++) {vrange[i] += vrange[i-1];}
2764 
2765   PetscCall(PetscMalloc1(nroots, &vltog));
2766   network->vltog = vltog;
2767 
2768   /* Set vltog for non-ghost vertices */
2769   k = 0;
2770   for (i=0; i<nroots; i++) {
2771     PetscCall(DMNetworkIsGhostVertex(dm,i+network->vStart,&ghost));
2772     if (ghost) continue;
2773     vltog[i] = vrange[rank] + k++;
2774   }
2775   PetscCall(PetscFree3(vrange,displs,recvcounts));
2776 
2777   /* Set vltog for ghost vertices */
2778   /* (a) create parallel Vleaves and sequential Vleaves_seq to convert local iremote[*].index to global index */
2779   PetscCall(VecCreate(comm,&Vleaves));
2780   PetscCall(VecSetSizes(Vleaves,2*nleaves,PETSC_DETERMINE));
2781   PetscCall(VecSetFromOptions(Vleaves));
2782   PetscCall(VecGetArray(Vleaves,&varr));
2783   for (i=0; i<nleaves; i++) {
2784     varr[2*i]   = (PetscScalar)(iremote[i].rank);  /* rank of remote process */
2785     varr[2*i+1] = (PetscScalar)(iremote[i].index); /* local index in remote process */
2786   }
2787   PetscCall(VecRestoreArray(Vleaves,&varr));
2788 
2789   /* (b) scatter local info to remote processes via VecScatter() */
2790   PetscCall(VecScatterCreateToAll(Vleaves,&ctx,&Vleaves_seq));
2791   PetscCall(VecScatterBegin(ctx,Vleaves,Vleaves_seq,INSERT_VALUES,SCATTER_FORWARD));
2792   PetscCall(VecScatterEnd(ctx,Vleaves,Vleaves_seq,INSERT_VALUES,SCATTER_FORWARD));
2793 
2794   /* (c) convert local indices to global indices in parallel vector Vleaves */
2795   PetscCall(VecGetSize(Vleaves_seq,&N));
2796   PetscCall(VecGetArrayRead(Vleaves_seq,&varr_read));
2797   for (i=0; i<N; i+=2) {
2798     remoterank = (PetscMPIInt)PetscRealPart(varr_read[i]);
2799     if (remoterank == rank) {
2800       k = i+1; /* row number */
2801       lidx = (PetscInt)PetscRealPart(varr_read[i+1]);
2802       val  = (PetscScalar)vltog[lidx]; /* global index for non-ghost vertex computed above */
2803       PetscCall(VecSetValues(Vleaves,1,&k,&val,INSERT_VALUES));
2804     }
2805   }
2806   PetscCall(VecRestoreArrayRead(Vleaves_seq,&varr_read));
2807   PetscCall(VecAssemblyBegin(Vleaves));
2808   PetscCall(VecAssemblyEnd(Vleaves));
2809 
2810   /* (d) Set vltog for ghost vertices by copying local values of Vleaves */
2811   PetscCall(VecGetArrayRead(Vleaves,&varr_read));
2812   k = 0;
2813   for (i=0; i<nroots; i++) {
2814     PetscCall(DMNetworkIsGhostVertex(dm,i+network->vStart,&ghost));
2815     if (!ghost) continue;
2816     vltog[i] = (PetscInt)PetscRealPart(varr_read[2*k+1]); k++;
2817   }
2818   PetscCall(VecRestoreArrayRead(Vleaves,&varr_read));
2819 
2820   PetscCall(VecDestroy(&Vleaves));
2821   PetscCall(VecDestroy(&Vleaves_seq));
2822   PetscCall(VecScatterDestroy(&ctx));
2823   PetscFunctionReturn(0);
2824 }
2825 
2826 static inline PetscErrorCode DMISAddSize_private(DM_Network *network,PetscInt p,PetscInt numkeys,PetscInt keys[],PetscInt blocksize[],PetscInt nselectedvar[],PetscInt *nidx)
2827 {
2828   PetscInt                 i,j,ncomps,nvar,key,offset=0;
2829   DMNetworkComponentHeader header;
2830 
2831   PetscFunctionBegin;
2832   PetscCall(PetscSectionGetOffset(network->DataSection,p,&offset));
2833   ncomps = ((DMNetworkComponentHeader)(network->componentdataarray+offset))->ndata;
2834   header = (DMNetworkComponentHeader)(network->componentdataarray+offset);
2835 
2836   for (i=0; i<ncomps; i++) {
2837     key  = header->key[i];
2838     nvar = header->nvar[i];
2839     for (j=0; j<numkeys; j++) {
2840       if (key == keys[j]) {
2841         if (!blocksize || blocksize[j] == -1) {
2842           *nidx += nvar;
2843         } else {
2844           *nidx += nselectedvar[j]*nvar/blocksize[j];
2845         }
2846       }
2847     }
2848   }
2849   PetscFunctionReturn(0);
2850 }
2851 
2852 static inline PetscErrorCode DMISComputeIdx_private(DM dm,PetscInt p,PetscInt numkeys,PetscInt keys[],PetscInt blocksize[],PetscInt nselectedvar[],PetscInt *selectedvar[],PetscInt *ii,PetscInt *idx)
2853 {
2854   PetscInt                 i,j,ncomps,nvar,key,offsetg,k,k1,offset=0;
2855   DM_Network               *network = (DM_Network*)dm->data;
2856   DMNetworkComponentHeader header;
2857 
2858   PetscFunctionBegin;
2859   PetscCall(PetscSectionGetOffset(network->DataSection,p,&offset));
2860   ncomps = ((DMNetworkComponentHeader)(network->componentdataarray+offset))->ndata;
2861   header = (DMNetworkComponentHeader)(network->componentdataarray+offset);
2862 
2863   for (i=0; i<ncomps; i++) {
2864     key  = header->key[i];
2865     nvar = header->nvar[i];
2866     for (j=0; j<numkeys; j++) {
2867       if (key != keys[j]) continue;
2868 
2869       PetscCall(DMNetworkGetGlobalVecOffset(dm,p,i,&offsetg));
2870       if (!blocksize || blocksize[j] == -1) {
2871         for (k=0; k<nvar; k++) idx[(*ii)++] = offsetg + k;
2872       } else {
2873         for (k=0; k<nvar; k+=blocksize[j]) {
2874           for (k1=0; k1<nselectedvar[j]; k1++) idx[(*ii)++] = offsetg + k + selectedvar[j][k1];
2875         }
2876       }
2877     }
2878   }
2879   PetscFunctionReturn(0);
2880 }
2881 
2882 /*@
2883   DMNetworkCreateIS - Create an index set object from the global vector of the network
2884 
2885   Collective
2886 
2887   Input Parameters:
2888 + dm - DMNetwork object
2889 . numkeys - number of keys
2890 . keys - array of keys that define the components of the variables you wish to extract
2891 . blocksize - block size of the variables associated to the component
2892 . nselectedvar - number of variables in each block to select
2893 - selectedvar - the offset into the block of each variable in each block to select
2894 
2895   Output Parameters:
2896 . is - the index set
2897 
2898   Level: Advanced
2899 
2900   Notes:
2901     Use blocksize[i] of -1 to indicate select all the variables of the i-th component, for which nselectvar[i] and selectedvar[i] are ignored. Use NULL, NULL, NULL to indicate for all selected components one wishes to obtain all the values of that component. For example, DMNetworkCreateIS(dm,1,&key,NULL,NULL,NULL,&is) will return an is that extracts all the variables for the 0-th component.
2902 
2903 .seealso: DMNetworkCreate(), ISCreateGeneral(), DMNetworkCreateLocalIS()
2904 @*/
2905 PetscErrorCode DMNetworkCreateIS(DM dm,PetscInt numkeys,PetscInt keys[],PetscInt blocksize[],PetscInt nselectedvar[],PetscInt *selectedvar[],IS *is)
2906 {
2907   MPI_Comm       comm;
2908   DM_Network     *network = (DM_Network*)dm->data;
2909   PetscInt       i,p,estart,eend,vstart,vend,nidx,*idx;
2910   PetscBool      ghost;
2911 
2912   PetscFunctionBegin;
2913   PetscCall(PetscObjectGetComm((PetscObject)dm,&comm));
2914 
2915   /* Check input parameters */
2916   for (i=0; i<numkeys; i++) {
2917     if (!blocksize || blocksize[i] == -1) continue;
2918     PetscCheck(nselectedvar[i] <= blocksize[i],PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"number of selectedvariables %" PetscInt_FMT " cannot be larger than blocksize %" PetscInt_FMT "",nselectedvar[i],blocksize[i]);
2919   }
2920 
2921   PetscCall(DMNetworkGetEdgeRange(dm,&estart,&eend));
2922   PetscCall(DMNetworkGetVertexRange(dm,&vstart,&vend));
2923 
2924   /* Get local number of idx */
2925   nidx = 0;
2926   for (p=estart; p<eend; p++) {
2927     PetscCall(DMISAddSize_private(network,p,numkeys,keys,blocksize,nselectedvar,&nidx));
2928   }
2929   for (p=vstart; p<vend; p++) {
2930     PetscCall(DMNetworkIsGhostVertex(dm,p,&ghost));
2931     if (ghost) continue;
2932     PetscCall(DMISAddSize_private(network,p,numkeys,keys,blocksize,nselectedvar,&nidx));
2933   }
2934 
2935   /* Compute idx */
2936   PetscCall(PetscMalloc1(nidx,&idx));
2937   i = 0;
2938   for (p=estart; p<eend; p++) {
2939     PetscCall(DMISComputeIdx_private(dm,p,numkeys,keys,blocksize,nselectedvar,selectedvar,&i,idx));
2940   }
2941   for (p=vstart; p<vend; p++) {
2942     PetscCall(DMNetworkIsGhostVertex(dm,p,&ghost));
2943     if (ghost) continue;
2944     PetscCall(DMISComputeIdx_private(dm,p,numkeys,keys,blocksize,nselectedvar,selectedvar,&i,idx));
2945   }
2946 
2947   /* Create is */
2948   PetscCall(ISCreateGeneral(comm,nidx,idx,PETSC_COPY_VALUES,is));
2949   PetscCall(PetscFree(idx));
2950   PetscFunctionReturn(0);
2951 }
2952 
2953 static inline PetscErrorCode DMISComputeLocalIdx_private(DM dm,PetscInt p,PetscInt numkeys,PetscInt keys[],PetscInt blocksize[],PetscInt nselectedvar[],PetscInt *selectedvar[],PetscInt *ii,PetscInt *idx)
2954 {
2955   PetscInt                 i,j,ncomps,nvar,key,offsetl,k,k1,offset=0;
2956   DM_Network               *network = (DM_Network*)dm->data;
2957   DMNetworkComponentHeader header;
2958 
2959   PetscFunctionBegin;
2960   PetscCall(PetscSectionGetOffset(network->DataSection,p,&offset));
2961   ncomps = ((DMNetworkComponentHeader)(network->componentdataarray+offset))->ndata;
2962   header = (DMNetworkComponentHeader)(network->componentdataarray+offset);
2963 
2964   for (i=0; i<ncomps; i++) {
2965     key  = header->key[i];
2966     nvar = header->nvar[i];
2967     for (j=0; j<numkeys; j++) {
2968       if (key != keys[j]) continue;
2969 
2970       PetscCall(DMNetworkGetLocalVecOffset(dm,p,i,&offsetl));
2971       if (!blocksize || blocksize[j] == -1) {
2972         for (k=0; k<nvar; k++) idx[(*ii)++] = offsetl + k;
2973       } else {
2974         for (k=0; k<nvar; k+=blocksize[j]) {
2975           for (k1=0; k1<nselectedvar[j]; k1++) idx[(*ii)++] = offsetl + k + selectedvar[j][k1];
2976         }
2977       }
2978     }
2979   }
2980   PetscFunctionReturn(0);
2981 }
2982 
2983 /*@
2984   DMNetworkCreateLocalIS - Create an index set object from the local vector of the network
2985 
2986   Not collective
2987 
2988   Input Parameters:
2989 + dm - DMNetwork object
2990 . numkeys - number of keys
2991 . keys - array of keys that define the components of the variables you wish to extract
2992 . blocksize - block size of the variables associated to the component
2993 . nselectedvar - number of variables in each block to select
2994 - selectedvar - the offset into the block of each variable in each block to select
2995 
2996   Output Parameters:
2997 . is - the index set
2998 
2999   Level: Advanced
3000 
3001   Notes:
3002     Use blocksize[i] of -1 to indicate select all the variables of the i-th component, for which nselectvar[i] and selectedvar[i] are ignored. Use NULL, NULL, NULL to indicate for all selected components one wishes to obtain all the values of that component. For example, DMNetworkCreateLocalIS(dm,1,&key,NULL,NULL,NULL,&is) will return an is that extracts all the variables for the 0-th component.
3003 
3004 .seealso: DMNetworkCreate(), DMNetworkCreateIS, ISCreateGeneral()
3005 @*/
3006 PetscErrorCode DMNetworkCreateLocalIS(DM dm,PetscInt numkeys,PetscInt keys[],PetscInt blocksize[],PetscInt nselectedvar[],PetscInt *selectedvar[],IS *is)
3007 {
3008   DM_Network     *network = (DM_Network*)dm->data;
3009   PetscInt       i,p,pstart,pend,nidx,*idx;
3010 
3011   PetscFunctionBegin;
3012   /* Check input parameters */
3013   for (i=0; i<numkeys; i++) {
3014     if (!blocksize || blocksize[i] == -1) continue;
3015     PetscCheck(nselectedvar[i] <= blocksize[i],PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"number of selectedvariables %" PetscInt_FMT " cannot be larger than blocksize %" PetscInt_FMT "",nselectedvar[i],blocksize[i]);
3016   }
3017 
3018   pstart = network->pStart;
3019   pend   = network->pEnd;
3020 
3021   /* Get local number of idx */
3022   nidx = 0;
3023   for (p=pstart; p<pend; p++) {
3024     PetscCall(DMISAddSize_private(network,p,numkeys,keys,blocksize,nselectedvar,&nidx));
3025   }
3026 
3027   /* Compute local idx */
3028   PetscCall(PetscMalloc1(nidx,&idx));
3029   i = 0;
3030   for (p=pstart; p<pend; p++) {
3031     PetscCall(DMISComputeLocalIdx_private(dm,p,numkeys,keys,blocksize,nselectedvar,selectedvar,&i,idx));
3032   }
3033 
3034   /* Create is */
3035   PetscCall(ISCreateGeneral(PETSC_COMM_SELF,nidx,idx,PETSC_COPY_VALUES,is));
3036   PetscCall(PetscFree(idx));
3037   PetscFunctionReturn(0);
3038 }
3039