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