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