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