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