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