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