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