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