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