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