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