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