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