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