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