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