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