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