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