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