1 #define PETSCDM_DLL 2 #include <petsc/private/dmnetworkimpl.h> /*I "petscdmnetwork.h" I*/ 3 #include <petsc/private/vecimpl.h> 4 5 static PetscErrorCode DMSetFromOptions_Network(DM dm, PetscOptionItems PetscOptionsObject) 6 { 7 PetscFunctionBegin; 8 PetscOptionsHeadBegin(PetscOptionsObject, "DMNetwork Options"); 9 PetscOptionsHeadEnd(); 10 PetscFunctionReturn(PETSC_SUCCESS); 11 } 12 13 /* External function declarations here */ 14 extern PetscErrorCode DMCreateMatrix_Network(DM, Mat *); 15 extern PetscErrorCode DMDestroy_Network(DM); 16 extern PetscErrorCode DMView_Network(DM, PetscViewer); 17 extern PetscErrorCode DMGlobalToLocalBegin_Network(DM, Vec, InsertMode, Vec); 18 extern PetscErrorCode DMGlobalToLocalEnd_Network(DM, Vec, InsertMode, Vec); 19 extern PetscErrorCode DMLocalToGlobalBegin_Network(DM, Vec, InsertMode, Vec); 20 extern PetscErrorCode DMLocalToGlobalEnd_Network(DM, Vec, InsertMode, Vec); 21 extern PetscErrorCode DMSetUp_Network(DM); 22 extern PetscErrorCode DMClone_Network(DM, DM *); 23 24 static PetscErrorCode VecArrayPrint_private(PetscViewer viewer, PetscInt n, const PetscScalar *xv) 25 { 26 PetscInt i; 27 28 PetscFunctionBegin; 29 for (i = 0; i < n; i++) { 30 #if defined(PETSC_USE_COMPLEX) 31 if (PetscImaginaryPart(xv[i]) > 0.0) { 32 PetscCall(PetscViewerASCIIPrintf(viewer, " %g + %g i\n", (double)PetscRealPart(xv[i]), (double)PetscImaginaryPart(xv[i]))); 33 } else if (PetscImaginaryPart(xv[i]) < 0.0) { 34 PetscCall(PetscViewerASCIIPrintf(viewer, " %g - %g i\n", (double)PetscRealPart(xv[i]), -(double)PetscImaginaryPart(xv[i]))); 35 } else PetscCall(PetscViewerASCIIPrintf(viewer, " %g\n", (double)PetscRealPart(xv[i]))); 36 #else 37 PetscCall(PetscViewerASCIIPrintf(viewer, " %g\n", (double)xv[i])); 38 #endif 39 } 40 PetscFunctionReturn(PETSC_SUCCESS); 41 } 42 43 static PetscErrorCode VecView_Network_Seq(DM networkdm, Vec X, PetscViewer viewer) 44 { 45 PetscInt e, v, Start, End, offset, nvar, id; 46 const PetscScalar *xv; 47 48 PetscFunctionBegin; 49 PetscCall(VecGetArrayRead(X, &xv)); 50 51 /* iterate over edges */ 52 PetscCall(DMNetworkGetEdgeRange(networkdm, &Start, &End)); 53 for (e = Start; e < End; e++) { 54 PetscCall(DMNetworkGetComponent(networkdm, e, ALL_COMPONENTS, NULL, NULL, &nvar)); 55 if (!nvar) continue; 56 57 PetscCall(DMNetworkGetLocalVecOffset(networkdm, e, ALL_COMPONENTS, &offset)); 58 PetscCall(DMNetworkGetGlobalEdgeIndex(networkdm, e, &id)); 59 60 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge %" PetscInt_FMT ":\n", id)); 61 PetscCall(VecArrayPrint_private(viewer, nvar, xv + offset)); 62 } 63 64 /* iterate over vertices */ 65 PetscCall(DMNetworkGetVertexRange(networkdm, &Start, &End)); 66 for (v = Start; v < End; v++) { 67 PetscCall(DMNetworkGetComponent(networkdm, v, ALL_COMPONENTS, NULL, NULL, &nvar)); 68 if (!nvar) continue; 69 70 PetscCall(DMNetworkGetLocalVecOffset(networkdm, v, ALL_COMPONENTS, &offset)); 71 PetscCall(DMNetworkGetGlobalVertexIndex(networkdm, v, &id)); 72 73 PetscCall(PetscViewerASCIIPrintf(viewer, " Vertex %" PetscInt_FMT ":\n", id)); 74 PetscCall(VecArrayPrint_private(viewer, nvar, xv + offset)); 75 } 76 PetscCall(PetscViewerFlush(viewer)); 77 PetscCall(VecRestoreArrayRead(X, &xv)); 78 PetscFunctionReturn(PETSC_SUCCESS); 79 } 80 81 static PetscErrorCode VecView_Network_MPI(DM networkdm, Vec X, PetscViewer viewer) 82 { 83 PetscInt i, e, v, eStart, eEnd, vStart, vEnd, offset, nvar, len_loc, k; 84 const PetscScalar *xv; 85 MPI_Comm comm; 86 PetscMPIInt size, rank, tag = ((PetscObject)viewer)->tag, len; 87 Vec localX; 88 PetscBool ghostvtex; 89 PetscScalar *values; 90 PetscInt ne, nv, id; 91 MPI_Status status; 92 93 PetscFunctionBegin; 94 PetscCall(PetscObjectGetComm((PetscObject)networkdm, &comm)); 95 PetscCallMPI(MPI_Comm_size(comm, &size)); 96 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 97 98 PetscCall(DMGetLocalVector(networkdm, &localX)); 99 PetscCall(DMGlobalToLocalBegin(networkdm, X, INSERT_VALUES, localX)); 100 PetscCall(DMGlobalToLocalEnd(networkdm, X, INSERT_VALUES, localX)); 101 PetscCall(VecGetArrayRead(localX, &xv)); 102 103 PetscCall(VecGetLocalSize(localX, &len_loc)); 104 105 PetscCall(DMNetworkGetEdgeRange(networkdm, &eStart, &eEnd)); 106 PetscCall(DMNetworkGetVertexRange(networkdm, &vStart, &vEnd)); 107 len_loc += 2 * (1 + eEnd - eStart + vEnd - vStart); 108 109 /* values = [nedges, nvertices; id, nvar, xedge; ...; id, nvars, xvertex;...], to be sent to proc[0] */ 110 PetscCallMPI(MPIU_Allreduce(MPI_IN_PLACE, &len_loc, 1, MPIU_INT, MPI_MAX, comm)); 111 PetscCall(PetscMPIIntCast(len_loc, &len)); 112 PetscCall(PetscCalloc1(len, &values)); 113 114 if (rank == 0) PetscCall(PetscViewerASCIIPrintf(viewer, "Process [%d]\n", rank)); 115 116 /* iterate over edges */ 117 k = 2; 118 for (e = eStart; e < eEnd; e++) { 119 PetscCall(DMNetworkGetComponent(networkdm, e, ALL_COMPONENTS, NULL, NULL, &nvar)); 120 if (!nvar) continue; 121 122 PetscCall(DMNetworkGetLocalVecOffset(networkdm, e, ALL_COMPONENTS, &offset)); 123 PetscCall(DMNetworkGetGlobalEdgeIndex(networkdm, e, &id)); 124 125 if (rank == 0) { /* print its own entries */ 126 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge %" PetscInt_FMT ":\n", id)); 127 PetscCall(VecArrayPrint_private(viewer, nvar, xv + offset)); 128 } else { 129 values[0] += 1; /* number of edges */ 130 values[k++] = id; 131 values[k++] = nvar; 132 for (i = offset; i < offset + nvar; i++) values[k++] = xv[i]; 133 } 134 } 135 136 /* iterate over vertices */ 137 for (v = vStart; v < vEnd; v++) { 138 PetscCall(DMNetworkIsGhostVertex(networkdm, v, &ghostvtex)); 139 if (ghostvtex) continue; 140 PetscCall(DMNetworkGetComponent(networkdm, v, ALL_COMPONENTS, NULL, NULL, &nvar)); 141 if (!nvar) continue; 142 143 PetscCall(DMNetworkGetLocalVecOffset(networkdm, v, ALL_COMPONENTS, &offset)); 144 PetscCall(DMNetworkGetGlobalVertexIndex(networkdm, v, &id)); 145 146 if (rank == 0) { 147 PetscCall(PetscViewerASCIIPrintf(viewer, " Vertex %" PetscInt_FMT ":\n", id)); 148 PetscCall(VecArrayPrint_private(viewer, nvar, xv + offset)); 149 } else { 150 values[1] += 1; /* number of vertices */ 151 values[k++] = id; 152 values[k++] = nvar; 153 for (i = offset; i < offset + nvar; i++) values[k++] = xv[i]; 154 } 155 } 156 157 if (rank == 0) { 158 /* proc[0] receives and prints messages */ 159 for (PetscMPIInt j = 1; j < size; j++) { 160 PetscCall(PetscViewerASCIIPrintf(viewer, "Process [%d]\n", j)); 161 162 PetscCallMPI(MPI_Recv(values, len, MPIU_SCALAR, j, tag, comm, &status)); 163 164 ne = (PetscInt)PetscAbsScalar(values[0]); 165 nv = (PetscInt)PetscAbsScalar(values[1]); 166 167 /* print received edges */ 168 k = 2; 169 for (i = 0; i < ne; i++) { 170 id = (PetscInt)PetscAbsScalar(values[k++]); 171 nvar = (PetscInt)PetscAbsScalar(values[k++]); 172 PetscCall(PetscViewerASCIIPrintf(viewer, " Edge %" PetscInt_FMT ":\n", id)); 173 PetscCall(VecArrayPrint_private(viewer, nvar, values + k)); 174 k += nvar; 175 } 176 177 /* print received vertices */ 178 for (i = 0; i < nv; i++) { 179 id = (PetscInt)PetscAbsScalar(values[k++]); 180 nvar = (PetscInt)PetscAbsScalar(values[k++]); 181 PetscCall(PetscViewerASCIIPrintf(viewer, " Vertex %" PetscInt_FMT ":\n", id)); 182 PetscCall(VecArrayPrint_private(viewer, nvar, values + k)); 183 k += nvar; 184 } 185 } 186 } else { 187 /* sends values to proc[0] */ 188 PetscCallMPI(MPIU_Send((void *)values, k, MPIU_SCALAR, 0, tag, comm)); 189 } 190 191 PetscCall(PetscFree(values)); 192 PetscCall(VecRestoreArrayRead(localX, &xv)); 193 PetscCall(DMRestoreLocalVector(networkdm, &localX)); 194 PetscFunctionReturn(PETSC_SUCCESS); 195 } 196 197 PETSC_SINGLE_LIBRARY_INTERN PetscErrorCode VecView_MPI(Vec, PetscViewer); 198 199 static PetscErrorCode VecView_Network(Vec v, PetscViewer viewer) 200 { 201 DM dm; 202 PetscBool isseq; 203 PetscBool iascii; 204 205 PetscFunctionBegin; 206 PetscCall(VecGetDM(v, &dm)); 207 PetscCheck(dm, PetscObjectComm((PetscObject)v), PETSC_ERR_ARG_WRONG, "Vector not generated from a DM"); 208 PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii)); 209 PetscCall(PetscObjectTypeCompare((PetscObject)v, VECSEQ, &isseq)); 210 211 /* Use VecView_Network if the viewer is ASCII; use VecView_Seq/MPI for other viewer formats */ 212 if (iascii) { 213 if (isseq) PetscCall(VecView_Network_Seq(dm, v, viewer)); 214 else PetscCall(VecView_Network_MPI(dm, v, viewer)); 215 } else { 216 if (isseq) PetscCall(VecView_Seq(v, viewer)); 217 else PetscCall(VecView_MPI(v, viewer)); 218 } 219 PetscFunctionReturn(PETSC_SUCCESS); 220 } 221 222 static PetscErrorCode DMCreateGlobalVector_Network(DM dm, Vec *vec) 223 { 224 DM_Network *network = (DM_Network *)dm->data; 225 226 PetscFunctionBegin; 227 PetscCall(DMCreateGlobalVector(network->plex, vec)); 228 PetscCall(VecSetOperation(*vec, VECOP_VIEW, (void (*)(void))VecView_Network)); 229 PetscCall(VecSetDM(*vec, dm)); 230 PetscFunctionReturn(PETSC_SUCCESS); 231 } 232 233 static PetscErrorCode DMCreateLocalVector_Network(DM dm, Vec *vec) 234 { 235 DM_Network *network = (DM_Network *)dm->data; 236 237 PetscFunctionBegin; 238 PetscCall(DMCreateLocalVector(network->plex, vec)); 239 PetscCall(VecSetDM(*vec, dm)); 240 PetscFunctionReturn(PETSC_SUCCESS); 241 } 242 243 PetscErrorCode DMNetworkInitializeToDefault_NonShared(DM dm) 244 { 245 DM_Network *network = (DM_Network *)dm->data; 246 247 PetscFunctionBegin; 248 network->Je = NULL; 249 network->Jv = NULL; 250 network->Jvptr = NULL; 251 network->userEdgeJacobian = PETSC_FALSE; 252 network->userVertexJacobian = PETSC_FALSE; 253 254 network->vertex.DofSection = NULL; 255 network->vertex.GlobalDofSection = NULL; 256 network->vertex.mapping = NULL; 257 network->vertex.sf = NULL; 258 259 network->edge.DofSection = NULL; 260 network->edge.GlobalDofSection = NULL; 261 network->edge.mapping = NULL; 262 network->edge.sf = NULL; 263 264 network->DataSection = NULL; 265 network->DofSection = NULL; 266 network->GlobalDofSection = NULL; 267 network->componentsetup = PETSC_FALSE; 268 269 network->plex = NULL; 270 271 network->component = NULL; 272 network->ncomponent = 0; 273 274 network->header = NULL; 275 network->cvalue = NULL; 276 network->componentdataarray = NULL; 277 278 network->max_comps_registered = DMNETWORK_MAX_COMP_REGISTERED_DEFAULT; /* return to default */ 279 PetscFunctionReturn(PETSC_SUCCESS); 280 } 281 /* Default values for the parameters in DMNetwork */ 282 PetscErrorCode DMNetworkInitializeToDefault(DM dm) 283 { 284 DM_Network *network = (DM_Network *)dm->data; 285 DMNetworkCloneShared cloneshared = network->cloneshared; 286 287 PetscFunctionBegin; 288 PetscCall(DMNetworkInitializeToDefault_NonShared(dm)); 289 /* Default values for shared data */ 290 cloneshared->refct = 1; 291 cloneshared->NVertices = 0; 292 cloneshared->NEdges = 0; 293 cloneshared->nVertices = 0; 294 cloneshared->nEdges = 0; 295 cloneshared->nsubnet = 0; 296 cloneshared->pStart = -1; 297 cloneshared->pEnd = -1; 298 cloneshared->vStart = -1; 299 cloneshared->vEnd = -1; 300 cloneshared->eStart = -1; 301 cloneshared->eEnd = -1; 302 cloneshared->vltog = NULL; 303 cloneshared->distributecalled = PETSC_FALSE; 304 305 cloneshared->subnet = NULL; 306 cloneshared->subnetvtx = NULL; 307 cloneshared->subnetedge = NULL; 308 cloneshared->svtx = NULL; 309 cloneshared->nsvtx = 0; 310 cloneshared->Nsvtx = 0; 311 cloneshared->svertices = NULL; 312 cloneshared->sedgelist = NULL; 313 cloneshared->svtable = NULL; 314 PetscFunctionReturn(PETSC_SUCCESS); 315 } 316 317 static PetscErrorCode DMInitialize_Network(DM dm) 318 { 319 PetscFunctionBegin; 320 PetscCall(DMSetDimension(dm, 1)); 321 dm->ops->view = DMView_Network; 322 dm->ops->setfromoptions = DMSetFromOptions_Network; 323 dm->ops->clone = DMClone_Network; 324 dm->ops->setup = DMSetUp_Network; 325 dm->ops->createglobalvector = DMCreateGlobalVector_Network; 326 dm->ops->createlocalvector = DMCreateLocalVector_Network; 327 dm->ops->getlocaltoglobalmapping = NULL; 328 dm->ops->createfieldis = NULL; 329 dm->ops->createcoordinatedm = DMCreateCoordinateDM_Network; 330 dm->ops->getcoloring = NULL; 331 dm->ops->creatematrix = DMCreateMatrix_Network; 332 dm->ops->createinterpolation = NULL; 333 dm->ops->createinjection = NULL; 334 dm->ops->refine = NULL; 335 dm->ops->coarsen = NULL; 336 dm->ops->refinehierarchy = NULL; 337 dm->ops->coarsenhierarchy = NULL; 338 dm->ops->globaltolocalbegin = DMGlobalToLocalBegin_Network; 339 dm->ops->globaltolocalend = DMGlobalToLocalEnd_Network; 340 dm->ops->localtoglobalbegin = DMLocalToGlobalBegin_Network; 341 dm->ops->localtoglobalend = DMLocalToGlobalEnd_Network; 342 dm->ops->destroy = DMDestroy_Network; 343 dm->ops->createsubdm = NULL; 344 dm->ops->locatepoints = NULL; 345 PetscFunctionReturn(PETSC_SUCCESS); 346 } 347 /* 348 copies over the subnetid and index portions of the DMNetworkComponentHeader from original dm to the newdm 349 */ 350 static PetscErrorCode DMNetworkCopyHeaderTopological(DM dm, DM newdm) 351 { 352 DM_Network *network = (DM_Network *)dm->data, *newnetwork = (DM_Network *)newdm->data; 353 PetscInt p, i, np, index, subnetid; 354 355 PetscFunctionBegin; 356 np = network->cloneshared->pEnd - network->cloneshared->pStart; 357 PetscCall(PetscCalloc2(np, &newnetwork->header, np, &newnetwork->cvalue)); 358 for (i = 0; i < np; i++) { 359 p = i + network->cloneshared->pStart; 360 PetscCall(DMNetworkGetSubnetID(dm, p, &subnetid)); 361 PetscCall(DMNetworkGetIndex(dm, p, &index)); 362 newnetwork->header[i].index = index; 363 newnetwork->header[i].subnetid = subnetid; 364 newnetwork->header[i].size = NULL; 365 newnetwork->header[i].key = NULL; 366 newnetwork->header[i].offset = NULL; 367 newnetwork->header[i].nvar = NULL; 368 newnetwork->header[i].offsetvarrel = NULL; 369 newnetwork->header[i].ndata = 0; 370 newnetwork->header[i].maxcomps = DMNETWORK_MAX_COMP_AT_POINT_DEFAULT; 371 newnetwork->header[i].hsize = sizeof(struct _p_DMNetworkComponentHeader) / sizeof(sizeof(DMNetworkComponentGenericDataType)); 372 } 373 PetscFunctionReturn(PETSC_SUCCESS); 374 } 375 376 PetscErrorCode DMClone_Network(DM dm, DM *newdm) 377 { 378 DM_Network *network = (DM_Network *)dm->data, *newnetwork = NULL; 379 380 PetscFunctionBegin; 381 network->cloneshared->refct++; 382 PetscCall(PetscNew(&newnetwork)); 383 (*newdm)->data = newnetwork; 384 PetscCall(DMNetworkInitializeToDefault_NonShared(*newdm)); 385 newnetwork->cloneshared = network->cloneshared; /* Share all data that can be cloneshared */ 386 387 PetscCheck(network->plex, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_NULL, "Must call DMNetworkLayoutSetUp() first"); 388 PetscCall(DMClone(network->plex, &newnetwork->plex)); 389 PetscCall(DMNetworkCopyHeaderTopological(dm, *newdm)); 390 PetscCall(DMNetworkInitializeNonTopological(*newdm)); /* initialize all non-topological data to the state after DMNetworkLayoutSetUp as been called */ 391 PetscCall(PetscObjectChangeTypeName((PetscObject)*newdm, DMNETWORK)); 392 PetscCall(DMInitialize_Network(*newdm)); 393 PetscFunctionReturn(PETSC_SUCCESS); 394 } 395 396 /* Developer Note: Be aware that the plex inside of the network does not have a coordinate plex. 397 */ 398 PetscErrorCode DMCreateCoordinateDM_Network(DM dm, DM *cdm) 399 { 400 DM_Network *newnetwork = NULL; 401 PetscInt Nf; 402 const char *prefix; 403 404 PetscFunctionBegin; 405 PetscCall(DMClone(dm, cdm)); 406 newnetwork = (DM_Network *)(*cdm)->data; 407 PetscCall(DMGetNumFields(newnetwork->plex, &Nf)); 408 PetscCall(DMSetNumFields(*cdm, Nf)); /* consistency with the coordinate plex */ 409 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix)); 410 PetscCall(PetscObjectSetOptionsPrefix((PetscObject)*cdm, prefix)); 411 PetscCall(PetscObjectAppendOptionsPrefix((PetscObject)*cdm, "cdm_")); 412 PetscFunctionReturn(PETSC_SUCCESS); 413 } 414 415 /*MC 416 DMNETWORK = "network" - A DM object that encapsulates an unstructured network. The implementation is based on the DM object 417 DMPlex that manages unstructured grids. Distributed networks use a non-overlapping partitioning of 418 the edges. In the local representation, Vecs contain all unknowns in the interior and shared boundary. 419 This is specified by a PetscSection object. Ownership in the global representation is determined by 420 ownership of the underlying DMPlex points. This is specified by another PetscSection object. 421 422 Level: intermediate 423 424 .seealso: `DMType`, `DMNetworkCreate()`, `DMCreate()`, `DMSetType()` 425 M*/ 426 427 PETSC_EXTERN PetscErrorCode DMCreate_Network(DM dm) 428 { 429 DM_Network *network; 430 431 PetscFunctionBegin; 432 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 433 PetscCall(PetscNew(&network)); 434 PetscCall(PetscNew(&network->cloneshared)); 435 dm->data = network; 436 437 PetscCall(DMNetworkInitializeToDefault(dm)); 438 PetscCall(DMInitialize_Network(dm)); 439 PetscFunctionReturn(PETSC_SUCCESS); 440 } 441 442 /*@ 443 DMNetworkCreate - Creates a DMNetwork object, which encapsulates an unstructured network. 444 445 Collective 446 447 Input Parameter: 448 . comm - The communicator for the DMNetwork object 449 450 Output Parameter: 451 . network - The DMNetwork object 452 453 Level: beginner 454 455 .seealso: `DMCreate()` 456 @*/ 457 PetscErrorCode DMNetworkCreate(MPI_Comm comm, DM *network) 458 { 459 PetscFunctionBegin; 460 PetscAssertPointer(network, 2); 461 PetscCall(DMCreate(comm, network)); 462 PetscCall(DMSetType(*network, DMNETWORK)); 463 PetscFunctionReturn(PETSC_SUCCESS); 464 } 465