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