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