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