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