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