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