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