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