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