1 static char help[] = "This example demonstrates the use of DMNetwork interface with subnetworks for solving a coupled nonlinear \n\ 2 electric power grid and water pipe problem.\n\ 3 The available solver options are in the ex1options file \n\ 4 and the data files are in the datafiles of subdirectories.\n\ 5 This example shows the use of subnetwork feature in DMNetwork. \n\ 6 Run this program: mpiexec -n <n> ./ex1 \n\\n"; 7 8 #include "power/power.h" 9 #include "water/water.h" 10 11 typedef struct { 12 UserCtx_Power appctx_power; 13 AppCtx_Water appctx_water; 14 PetscInt subsnes_id; /* snes solver id */ 15 PetscInt it; /* iteration number */ 16 Vec localXold; /* store previous solution, used by FormFunction_Dummy() */ 17 } UserCtx; 18 19 PetscErrorCode UserMonitor(SNES snes, PetscInt its, PetscReal fnorm, void *appctx) 20 { 21 UserCtx *user = (UserCtx *)appctx; 22 Vec X, localXold = user->localXold; 23 DM networkdm; 24 PetscMPIInt rank; 25 MPI_Comm comm; 26 27 PetscFunctionBegin; 28 PetscCall(PetscObjectGetComm((PetscObject)snes, &comm)); 29 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 30 #if 0 31 if (rank == 0) { 32 PetscInt subsnes_id = user->subsnes_id; 33 if (subsnes_id == 2) { 34 PetscCall(PetscPrintf(PETSC_COMM_SELF," it %" PetscInt_FMT ", subsnes_id %" PetscInt_FMT ", fnorm %g\n",user->it,user->subsnes_id,(double)fnorm)); 35 } else { 36 PetscCall(PetscPrintf(PETSC_COMM_SELF," subsnes_id %" PetscInt_FMT ", fnorm %g\n",user->subsnes_id,(double)fnorm)); 37 } 38 } 39 #endif 40 PetscCall(SNESGetSolution(snes, &X)); 41 PetscCall(SNESGetDM(snes, &networkdm)); 42 PetscCall(DMGlobalToLocalBegin(networkdm, X, INSERT_VALUES, localXold)); 43 PetscCall(DMGlobalToLocalEnd(networkdm, X, INSERT_VALUES, localXold)); 44 PetscFunctionReturn(PETSC_SUCCESS); 45 } 46 47 PetscErrorCode FormJacobian_subPower(SNES snes, Vec X, Mat J, Mat Jpre, void *appctx) 48 { 49 DM networkdm; 50 Vec localX; 51 PetscInt nv, ne, i, j, offset, nvar, row; 52 const PetscInt *vtx, *edges; 53 PetscBool ghostvtex; 54 PetscScalar one = 1.0; 55 PetscMPIInt rank; 56 MPI_Comm comm; 57 58 PetscFunctionBegin; 59 PetscCall(SNESGetDM(snes, &networkdm)); 60 PetscCall(DMGetLocalVector(networkdm, &localX)); 61 62 PetscCall(PetscObjectGetComm((PetscObject)networkdm, &comm)); 63 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 64 65 PetscCall(DMGlobalToLocalBegin(networkdm, X, INSERT_VALUES, localX)); 66 PetscCall(DMGlobalToLocalEnd(networkdm, X, INSERT_VALUES, localX)); 67 68 PetscCall(MatZeroEntries(J)); 69 70 /* Power subnetwork: copied from power/FormJacobian_Power() */ 71 PetscCall(DMNetworkGetSubnetwork(networkdm, 0, &nv, &ne, &vtx, &edges)); 72 PetscCall(FormJacobian_Power_private(networkdm, localX, J, nv, ne, vtx, edges, appctx)); 73 74 /* Water subnetwork: Identity */ 75 PetscCall(DMNetworkGetSubnetwork(networkdm, 1, &nv, &ne, &vtx, &edges)); 76 for (i = 0; i < nv; i++) { 77 PetscCall(DMNetworkIsGhostVertex(networkdm, vtx[i], &ghostvtex)); 78 if (ghostvtex) continue; 79 80 PetscCall(DMNetworkGetGlobalVecOffset(networkdm, vtx[i], ALL_COMPONENTS, &offset)); 81 PetscCall(DMNetworkGetComponent(networkdm, vtx[i], ALL_COMPONENTS, NULL, NULL, &nvar)); 82 for (j = 0; j < nvar; j++) { 83 row = offset + j; 84 PetscCall(MatSetValues(J, 1, &row, 1, &row, &one, ADD_VALUES)); 85 } 86 } 87 PetscCall(MatAssemblyBegin(J, MAT_FINAL_ASSEMBLY)); 88 PetscCall(MatAssemblyEnd(J, MAT_FINAL_ASSEMBLY)); 89 90 PetscCall(DMRestoreLocalVector(networkdm, &localX)); 91 PetscFunctionReturn(PETSC_SUCCESS); 92 } 93 94 /* Dummy equation localF(X) = localX - localXold */ 95 PetscErrorCode FormFunction_Dummy(DM networkdm, Vec localX, Vec localF, PetscInt nv, PetscInt ne, const PetscInt *vtx, const PetscInt *edges, void *appctx) 96 { 97 const PetscScalar *xarr, *xoldarr; 98 PetscScalar *farr; 99 PetscInt i, j, offset, nvar; 100 PetscBool ghostvtex; 101 UserCtx *user = (UserCtx *)appctx; 102 Vec localXold = user->localXold; 103 104 PetscFunctionBegin; 105 PetscCall(VecGetArrayRead(localX, &xarr)); 106 PetscCall(VecGetArrayRead(localXold, &xoldarr)); 107 PetscCall(VecGetArray(localF, &farr)); 108 109 for (i = 0; i < nv; i++) { 110 PetscCall(DMNetworkIsGhostVertex(networkdm, vtx[i], &ghostvtex)); 111 if (ghostvtex) continue; 112 113 PetscCall(DMNetworkGetLocalVecOffset(networkdm, vtx[i], ALL_COMPONENTS, &offset)); 114 PetscCall(DMNetworkGetComponent(networkdm, vtx[i], ALL_COMPONENTS, NULL, NULL, &nvar)); 115 for (j = 0; j < nvar; j++) farr[offset + j] = xarr[offset + j] - xoldarr[offset + j]; 116 } 117 118 PetscCall(VecRestoreArrayRead(localX, &xarr)); 119 PetscCall(VecRestoreArrayRead(localXold, &xoldarr)); 120 PetscCall(VecRestoreArray(localF, &farr)); 121 PetscFunctionReturn(PETSC_SUCCESS); 122 } 123 124 PetscErrorCode FormFunction(SNES snes, Vec X, Vec F, void *appctx) 125 { 126 DM networkdm; 127 Vec localX, localF; 128 PetscInt nv, ne, v; 129 const PetscInt *vtx, *edges; 130 PetscMPIInt rank; 131 MPI_Comm comm; 132 UserCtx *user = (UserCtx *)appctx; 133 UserCtx_Power appctx_power = (*user).appctx_power; 134 AppCtx_Water appctx_water = (*user).appctx_water; 135 136 PetscFunctionBegin; 137 PetscCall(SNESGetDM(snes, &networkdm)); 138 PetscCall(PetscObjectGetComm((PetscObject)networkdm, &comm)); 139 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 140 141 PetscCall(DMGetLocalVector(networkdm, &localX)); 142 PetscCall(DMGetLocalVector(networkdm, &localF)); 143 PetscCall(VecSet(F, 0.0)); 144 PetscCall(VecSet(localF, 0.0)); 145 146 PetscCall(DMGlobalToLocalBegin(networkdm, X, INSERT_VALUES, localX)); 147 PetscCall(DMGlobalToLocalEnd(networkdm, X, INSERT_VALUES, localX)); 148 149 /* Form Function for power subnetwork */ 150 PetscCall(DMNetworkGetSubnetwork(networkdm, 0, &nv, &ne, &vtx, &edges)); 151 if (user->subsnes_id == 1) { /* snes_water only */ 152 PetscCall(FormFunction_Dummy(networkdm, localX, localF, nv, ne, vtx, edges, user)); 153 } else { 154 PetscCall(FormFunction_Power(networkdm, localX, localF, nv, ne, vtx, edges, &appctx_power)); 155 } 156 157 /* Form Function for water subnetwork */ 158 PetscCall(DMNetworkGetSubnetwork(networkdm, 1, &nv, &ne, &vtx, &edges)); 159 if (user->subsnes_id == 0) { /* snes_power only */ 160 PetscCall(FormFunction_Dummy(networkdm, localX, localF, nv, ne, vtx, edges, user)); 161 } else { 162 PetscCall(FormFunction_Water(networkdm, localX, localF, nv, ne, vtx, edges, NULL)); 163 } 164 165 /* Illustrate how to access the coupling vertex of the subnetworks without doing anything to F yet */ 166 PetscCall(DMNetworkGetSharedVertices(networkdm, &nv, &vtx)); 167 for (v = 0; v < nv; v++) { 168 PetscInt key, ncomp, nvar, nconnedges, k, e, keye, goffset[3]; 169 void *component; 170 const PetscInt *connedges; 171 172 PetscCall(DMNetworkGetComponent(networkdm, vtx[v], ALL_COMPONENTS, NULL, NULL, &nvar)); 173 PetscCall(DMNetworkGetNumComponents(networkdm, vtx[v], &ncomp)); 174 /* printf(" [%d] coupling vertex[%" PetscInt_FMT "]: v %" PetscInt_FMT ", ncomp %" PetscInt_FMT "; nvar %" PetscInt_FMT "\n",rank,v,vtx[v], ncomp,nvar); */ 175 176 for (k = 0; k < ncomp; k++) { 177 PetscCall(DMNetworkGetComponent(networkdm, vtx[v], k, &key, &component, &nvar)); 178 PetscCall(DMNetworkGetGlobalVecOffset(networkdm, vtx[v], k, &goffset[k])); 179 180 /* Verify the coupling vertex is a powernet load vertex or a water vertex */ 181 switch (k) { 182 case 0: 183 PetscCheck(key == appctx_power.compkey_bus && nvar == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "key %" PetscInt_FMT " not a power bus vertex or nvar %" PetscInt_FMT " != 2", key, nvar); 184 break; 185 case 1: 186 PetscCheck(key == appctx_power.compkey_load && nvar == 0 && goffset[1] == goffset[0] + 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Not a power load vertex"); 187 break; 188 case 2: 189 PetscCheck(key == appctx_water.compkey_vtx && nvar == 1 && goffset[2] == goffset[1], PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Not a water vertex"); 190 break; 191 default: 192 SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "k %" PetscInt_FMT " is wrong", k); 193 } 194 /* printf(" [%d] coupling vertex[%" PetscInt_FMT "]: key %" PetscInt_FMT "; nvar %" PetscInt_FMT ", goffset %" PetscInt_FMT "\n",rank,v,key,nvar,goffset[k]); */ 195 } 196 197 /* Get its supporting edges */ 198 PetscCall(DMNetworkGetSupportingEdges(networkdm, vtx[v], &nconnedges, &connedges)); 199 /* printf("\n[%d] coupling vertex: nconnedges %" PetscInt_FMT "\n",rank,nconnedges); */ 200 for (k = 0; k < nconnedges; k++) { 201 e = connedges[k]; 202 PetscCall(DMNetworkGetNumComponents(networkdm, e, &ncomp)); 203 /* printf("\n [%d] connected edge[%" PetscInt_FMT "]=%" PetscInt_FMT " has ncomp %" PetscInt_FMT "\n",rank,k,e,ncomp); */ 204 PetscCall(DMNetworkGetComponent(networkdm, e, 0, &keye, &component, NULL)); 205 if (keye != appctx_water.compkey_edge) PetscCheck(keye == appctx_power.compkey_branch, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Not a power branch"); 206 } 207 } 208 209 PetscCall(DMRestoreLocalVector(networkdm, &localX)); 210 211 PetscCall(DMLocalToGlobalBegin(networkdm, localF, ADD_VALUES, F)); 212 PetscCall(DMLocalToGlobalEnd(networkdm, localF, ADD_VALUES, F)); 213 PetscCall(DMRestoreLocalVector(networkdm, &localF)); 214 #if 0 215 if (rank == 0) printf("F:\n"); 216 PetscCall(VecView(F,PETSC_VIEWER_STDOUT_WORLD)); 217 #endif 218 PetscFunctionReturn(PETSC_SUCCESS); 219 } 220 221 PetscErrorCode SetInitialGuess(DM networkdm, Vec X, void *appctx) 222 { 223 PetscInt nv, ne, i, j, ncomp, offset, key; 224 const PetscInt *vtx, *edges; 225 UserCtx *user = (UserCtx *)appctx; 226 Vec localX = user->localXold; 227 UserCtx_Power appctx_power = (*user).appctx_power; 228 AppCtx_Water appctx_water = (*user).appctx_water; 229 PetscBool ghost; 230 PetscScalar *xarr; 231 VERTEX_Power bus; 232 VERTEX_Water vertex; 233 void *component; 234 GEN gen; 235 236 PetscFunctionBegin; 237 PetscCall(VecSet(X, 0.0)); 238 PetscCall(VecSet(localX, 0.0)); 239 240 /* Set initial guess for power subnetwork */ 241 PetscCall(DMNetworkGetSubnetwork(networkdm, 0, &nv, &ne, &vtx, &edges)); 242 PetscCall(SetInitialGuess_Power(networkdm, localX, nv, ne, vtx, edges, &appctx_power)); 243 244 /* Set initial guess for water subnetwork */ 245 PetscCall(DMNetworkGetSubnetwork(networkdm, 1, &nv, &ne, &vtx, &edges)); 246 PetscCall(SetInitialGuess_Water(networkdm, localX, nv, ne, vtx, edges, NULL)); 247 248 /* Set initial guess at the coupling vertex */ 249 PetscCall(VecGetArray(localX, &xarr)); 250 PetscCall(DMNetworkGetSharedVertices(networkdm, &nv, &vtx)); 251 for (i = 0; i < nv; i++) { 252 PetscCall(DMNetworkIsGhostVertex(networkdm, vtx[i], &ghost)); 253 if (ghost) continue; 254 255 PetscCall(DMNetworkGetNumComponents(networkdm, vtx[i], &ncomp)); 256 for (j = 0; j < ncomp; j++) { 257 PetscCall(DMNetworkGetLocalVecOffset(networkdm, vtx[i], j, &offset)); 258 PetscCall(DMNetworkGetComponent(networkdm, vtx[i], j, &key, (void **)&component, NULL)); 259 if (key == appctx_power.compkey_bus) { 260 bus = (VERTEX_Power)(component); 261 xarr[offset] = bus->va * PETSC_PI / 180.0; 262 xarr[offset + 1] = bus->vm; 263 } else if (key == appctx_power.compkey_gen) { 264 gen = (GEN)(component); 265 if (!gen->status) continue; 266 xarr[offset + 1] = gen->vs; 267 } else if (key == appctx_water.compkey_vtx) { 268 vertex = (VERTEX_Water)(component); 269 if (vertex->type == VERTEX_TYPE_JUNCTION) { 270 xarr[offset] = 100; 271 } else if (vertex->type == VERTEX_TYPE_RESERVOIR) { 272 xarr[offset] = vertex->res.head; 273 } else { 274 xarr[offset] = vertex->tank.initlvl + vertex->tank.elev; 275 } 276 } 277 } 278 } 279 PetscCall(VecRestoreArray(localX, &xarr)); 280 281 PetscCall(DMLocalToGlobalBegin(networkdm, localX, ADD_VALUES, X)); 282 PetscCall(DMLocalToGlobalEnd(networkdm, localX, ADD_VALUES, X)); 283 PetscFunctionReturn(PETSC_SUCCESS); 284 } 285 286 /* Set coordinates */ 287 static PetscErrorCode CoordinateVecSetUp(DM dm, Vec coords) 288 { 289 DM dmclone; 290 PetscInt i, gidx, offset, v, nv, Nsubnet; 291 const PetscInt *vtx; 292 PetscScalar *carray; 293 294 PetscFunctionBeginUser; 295 PetscCall(DMGetCoordinateDM(dm, &dmclone)); 296 PetscCall(VecGetArrayWrite(coords, &carray)); 297 PetscCall(DMNetworkGetNumSubNetworks(dm, NULL, &Nsubnet)); 298 for (i = 0; i < Nsubnet; i++) { 299 PetscCall(DMNetworkGetSubnetwork(dm, i, &nv, NULL, &vtx, NULL)); 300 for (v = 0; v < nv; v++) { 301 PetscCall(DMNetworkGetGlobalVertexIndex(dm, vtx[v], &gidx)); 302 PetscCall(DMNetworkGetLocalVecOffset(dmclone, vtx[v], 0, &offset)); 303 switch (gidx) { 304 case 0: 305 carray[offset] = -1.0; 306 carray[offset + 1] = -1.0; 307 break; 308 case 1: 309 carray[offset] = -2.0; 310 carray[offset + 1] = 2.0; 311 break; 312 case 2: 313 carray[offset] = 0.0; 314 carray[offset + 1] = 2.0; 315 break; 316 case 3: 317 carray[offset] = -1.0; 318 carray[offset + 1] = 0.0; 319 break; 320 case 4: 321 carray[offset] = 0.0; 322 carray[offset + 1] = 0.0; 323 break; 324 case 5: 325 carray[offset] = 0.0; 326 carray[offset + 1] = 1.0; 327 break; 328 case 6: 329 carray[offset] = -1.0; 330 carray[offset + 1] = 1.0; 331 break; 332 case 7: 333 carray[offset] = -2.0; 334 carray[offset + 1] = 1.0; 335 break; 336 case 8: 337 carray[offset] = -2.0; 338 carray[offset + 1] = 0.0; 339 break; 340 case 9: 341 carray[offset] = 1.0; 342 carray[offset + 1] = 0.0; 343 break; 344 case 10: 345 carray[offset] = 1.0; 346 carray[offset + 1] = -1.0; 347 break; 348 case 11: 349 carray[offset] = 2.0; 350 carray[offset + 1] = -1.0; 351 break; 352 case 12: 353 carray[offset] = 2.0; 354 carray[offset + 1] = 0.0; 355 break; 356 case 13: 357 carray[offset] = 0.0; 358 carray[offset + 1] = -1.0; 359 break; 360 case 14: 361 carray[offset] = 2.0; 362 carray[offset + 1] = 1.0; 363 break; 364 default: 365 PetscCheck(gidx < 15 && gidx > -1, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "gidx %" PetscInt_FMT "must between 0 and 14", gidx); 366 } 367 } 368 } 369 PetscCall(VecRestoreArrayWrite(coords, &carray)); 370 PetscFunctionReturn(PETSC_SUCCESS); 371 } 372 373 static PetscErrorCode CoordinatePrint(DM dm) 374 { 375 DM dmclone; 376 PetscInt cdim, v, off, vglobal, vStart, vEnd; 377 const PetscScalar *carray; 378 Vec coords; 379 MPI_Comm comm; 380 PetscMPIInt rank; 381 382 PetscFunctionBegin; 383 PetscCall(PetscObjectGetComm((PetscObject)dm, &comm)); 384 PetscCallMPI(MPI_Comm_rank(comm, &rank)); 385 386 PetscCall(DMGetCoordinateDM(dm, &dmclone)); 387 PetscCall(DMNetworkGetVertexRange(dm, &vStart, &vEnd)); 388 PetscCall(DMGetCoordinatesLocal(dm, &coords)); 389 390 PetscCall(DMGetCoordinateDim(dm, &cdim)); 391 PetscCall(VecGetArrayRead(coords, &carray)); 392 393 PetscCall(PetscPrintf(MPI_COMM_WORLD, "\nCoordinatePrint, cdim %" PetscInt_FMT ":\n", cdim)); 394 PetscCall(PetscSynchronizedPrintf(MPI_COMM_WORLD, "[%i]\n", rank)); 395 for (v = vStart; v < vEnd; v++) { 396 PetscCall(DMNetworkGetLocalVecOffset(dmclone, v, 0, &off)); 397 PetscCall(DMNetworkGetGlobalVertexIndex(dmclone, v, &vglobal)); 398 switch (cdim) { 399 case 2: 400 PetscCall(PetscSynchronizedPrintf(MPI_COMM_WORLD, "Vertex: %" PetscInt_FMT ", x = %f y = %f \n", vglobal, (double)PetscRealPart(carray[off]), (double)PetscRealPart(carray[off + 1]))); 401 break; 402 default: 403 PetscCheck(cdim == 2, MPI_COMM_WORLD, PETSC_ERR_SUP, "Only supports Network embedding dimension of 2, not supplied %" PetscInt_FMT, cdim); 404 break; 405 } 406 } 407 PetscCall(PetscSynchronizedFlush(MPI_COMM_WORLD, NULL)); 408 PetscCall(VecRestoreArrayRead(coords, &carray)); 409 PetscFunctionReturn(PETSC_SUCCESS); 410 } 411 412 int main(int argc, char **argv) 413 { 414 DM networkdm, dmclone; 415 PetscMPIInt rank, size; 416 PetscInt Nsubnet = 2, numVertices[2], numEdges[2], i, j, nv, ne, it_max = 10; 417 PetscInt vStart, vEnd, compkey; 418 const PetscInt *vtx, *edges; 419 Vec X, F, coords; 420 SNES snes, snes_power, snes_water; 421 Mat Jac; 422 PetscBool ghost, viewJ = PETSC_FALSE, viewX = PETSC_FALSE, test = PETSC_FALSE, distribute = PETSC_TRUE, flg, printCoord = PETSC_FALSE, viewCSV = PETSC_FALSE; 423 UserCtx user; 424 SNESConvergedReason reason; 425 #if defined(PETSC_USE_LOG) 426 PetscLogStage stage[4]; 427 #endif 428 429 /* Power subnetwork */ 430 UserCtx_Power *appctx_power = &user.appctx_power; 431 char pfdata_file[PETSC_MAX_PATH_LEN] = "power/case9.m"; 432 PFDATA *pfdata = NULL; 433 PetscInt genj, loadj, *edgelist_power = NULL, power_netnum; 434 PetscScalar Sbase = 0.0; 435 436 /* Water subnetwork */ 437 AppCtx_Water *appctx_water = &user.appctx_water; 438 WATERDATA *waterdata = NULL; 439 char waterdata_file[PETSC_MAX_PATH_LEN] = "water/sample1.inp"; 440 PetscInt *edgelist_water = NULL, water_netnum; 441 442 /* Shared vertices between subnetworks */ 443 PetscInt power_svtx, water_svtx; 444 445 PetscFunctionBeginUser; 446 PetscCall(PetscInitialize(&argc, &argv, "ex1options", help)); 447 PetscCallMPI(MPI_Comm_rank(PETSC_COMM_WORLD, &rank)); 448 PetscCallMPI(MPI_Comm_size(PETSC_COMM_WORLD, &size)); 449 450 /* (1) Read Data - Only rank 0 reads the data */ 451 PetscCall(PetscLogStageRegister("Read Data", &stage[0])); 452 PetscCall(PetscLogStagePush(stage[0])); 453 454 for (i = 0; i < Nsubnet; i++) { 455 numVertices[i] = 0; 456 numEdges[i] = 0; 457 } 458 459 /* All processes READ THE DATA FOR THE FIRST SUBNETWORK: Electric Power Grid */ 460 /* Used for shared vertex, because currently the coupling info must be available in all processes!!! */ 461 PetscCall(PetscOptionsGetString(NULL, NULL, "-pfdata", pfdata_file, PETSC_MAX_PATH_LEN - 1, NULL)); 462 PetscCall(PetscNew(&pfdata)); 463 PetscCall(PFReadMatPowerData(pfdata, pfdata_file)); 464 if (rank == 0) PetscCall(PetscPrintf(PETSC_COMM_SELF, "Power network: nb = %" PetscInt_FMT ", ngen = %" PetscInt_FMT ", nload = %" PetscInt_FMT ", nbranch = %" PetscInt_FMT "\n", pfdata->nbus, pfdata->ngen, pfdata->nload, pfdata->nbranch)); 465 Sbase = pfdata->sbase; 466 if (rank == 0) { /* proc[0] will create Electric Power Grid */ 467 numEdges[0] = pfdata->nbranch; 468 numVertices[0] = pfdata->nbus; 469 470 PetscCall(PetscMalloc1(2 * numEdges[0], &edgelist_power)); 471 PetscCall(GetListofEdges_Power(pfdata, edgelist_power)); 472 } 473 /* Broadcast power Sbase to all processors */ 474 PetscCallMPI(MPI_Bcast(&Sbase, 1, MPIU_SCALAR, 0, PETSC_COMM_WORLD)); 475 appctx_power->Sbase = Sbase; 476 appctx_power->jac_error = PETSC_FALSE; 477 /* If external option activated. Introduce error in jacobian */ 478 PetscCall(PetscOptionsHasName(NULL, NULL, "-jac_error", &appctx_power->jac_error)); 479 480 /* All processes READ THE DATA FOR THE SECOND SUBNETWORK: Water */ 481 /* Used for shared vertex, because currently the coupling info must be available in all processes!!! */ 482 PetscCall(PetscNew(&waterdata)); 483 PetscCall(PetscOptionsGetString(NULL, NULL, "-waterdata", waterdata_file, PETSC_MAX_PATH_LEN - 1, NULL)); 484 PetscCall(WaterReadData(waterdata, waterdata_file)); 485 if (size == 1 || (size > 1 && rank == 1)) { 486 PetscCall(PetscCalloc1(2 * waterdata->nedge, &edgelist_water)); 487 PetscCall(GetListofEdges_Water(waterdata, edgelist_water)); 488 numEdges[1] = waterdata->nedge; 489 numVertices[1] = waterdata->nvertex; 490 } 491 PetscCall(PetscLogStagePop()); 492 493 /* (2) Create a network consist of two subnetworks */ 494 PetscCall(PetscLogStageRegister("Net Setup", &stage[1])); 495 PetscCall(PetscLogStagePush(stage[1])); 496 497 PetscCall(PetscOptionsGetBool(NULL, NULL, "-viewCSV", &viewCSV, NULL)); 498 PetscCall(PetscOptionsGetBool(NULL, NULL, "-printCoord", &printCoord, NULL)); 499 PetscCall(PetscOptionsGetBool(NULL, NULL, "-test", &test, NULL)); 500 PetscCall(PetscOptionsGetBool(NULL, NULL, "-distribute", &distribute, NULL)); 501 502 /* Create an empty network object */ 503 PetscCall(DMNetworkCreate(PETSC_COMM_WORLD, &networkdm)); 504 505 /* Register the components in the network */ 506 PetscCall(DMNetworkRegisterComponent(networkdm, "branchstruct", sizeof(struct _p_EDGE_Power), &appctx_power->compkey_branch)); 507 PetscCall(DMNetworkRegisterComponent(networkdm, "busstruct", sizeof(struct _p_VERTEX_Power), &appctx_power->compkey_bus)); 508 PetscCall(DMNetworkRegisterComponent(networkdm, "genstruct", sizeof(struct _p_GEN), &appctx_power->compkey_gen)); 509 PetscCall(DMNetworkRegisterComponent(networkdm, "loadstruct", sizeof(struct _p_LOAD), &appctx_power->compkey_load)); 510 511 PetscCall(DMNetworkRegisterComponent(networkdm, "edge_water", sizeof(struct _p_EDGE_Water), &appctx_water->compkey_edge)); 512 PetscCall(DMNetworkRegisterComponent(networkdm, "vertex_water", sizeof(struct _p_VERTEX_Water), &appctx_water->compkey_vtx)); 513 514 PetscCall(PetscSynchronizedPrintf(PETSC_COMM_WORLD, "[%d] Total local nvertices %" PetscInt_FMT " + %" PetscInt_FMT " = %" PetscInt_FMT ", nedges %" PetscInt_FMT " + %" PetscInt_FMT " = %" PetscInt_FMT "\n", rank, numVertices[0], numVertices[1], numVertices[0] + numVertices[1], numEdges[0], numEdges[1], numEdges[0] + numEdges[1])); 515 PetscCall(PetscSynchronizedFlush(PETSC_COMM_WORLD, PETSC_STDOUT)); 516 517 PetscCall(DMNetworkSetNumSubNetworks(networkdm, PETSC_DECIDE, Nsubnet)); 518 PetscCall(DMNetworkAddSubnetwork(networkdm, "power", numEdges[0], edgelist_power, &power_netnum)); 519 PetscCall(DMNetworkAddSubnetwork(networkdm, "water", numEdges[1], edgelist_water, &water_netnum)); 520 521 /* vertex subnet[0].4 shares with vertex subnet[1].0 */ 522 power_svtx = 4; 523 water_svtx = 0; 524 PetscCall(DMNetworkAddSharedVertices(networkdm, power_netnum, water_netnum, 1, &power_svtx, &water_svtx)); 525 526 /* Set up the network layout */ 527 PetscCall(DMNetworkLayoutSetUp(networkdm)); 528 529 /* ADD VARIABLES AND COMPONENTS FOR THE POWER SUBNETWORK */ 530 genj = 0; 531 loadj = 0; 532 PetscCall(DMNetworkGetSubnetwork(networkdm, power_netnum, &nv, &ne, &vtx, &edges)); 533 534 for (i = 0; i < ne; i++) PetscCall(DMNetworkAddComponent(networkdm, edges[i], appctx_power->compkey_branch, &pfdata->branch[i], 0)); 535 536 for (i = 0; i < nv; i++) { 537 PetscCall(DMNetworkIsSharedVertex(networkdm, vtx[i], &flg)); 538 if (flg) continue; 539 540 PetscCall(DMNetworkAddComponent(networkdm, vtx[i], appctx_power->compkey_bus, &pfdata->bus[i], 2)); 541 if (pfdata->bus[i].ngen) { 542 for (j = 0; j < pfdata->bus[i].ngen; j++) PetscCall(DMNetworkAddComponent(networkdm, vtx[i], appctx_power->compkey_gen, &pfdata->gen[genj++], 0)); 543 } 544 if (pfdata->bus[i].nload) { 545 for (j = 0; j < pfdata->bus[i].nload; j++) PetscCall(DMNetworkAddComponent(networkdm, vtx[i], appctx_power->compkey_load, &pfdata->load[loadj++], 0)); 546 } 547 } 548 549 /* ADD VARIABLES AND COMPONENTS FOR THE WATER SUBNETWORK */ 550 PetscCall(DMNetworkGetSubnetwork(networkdm, water_netnum, &nv, &ne, &vtx, &edges)); 551 for (i = 0; i < ne; i++) PetscCall(DMNetworkAddComponent(networkdm, edges[i], appctx_water->compkey_edge, &waterdata->edge[i], 0)); 552 553 for (i = 0; i < nv; i++) { 554 PetscCall(DMNetworkIsSharedVertex(networkdm, vtx[i], &flg)); 555 if (flg) continue; 556 557 PetscCall(DMNetworkAddComponent(networkdm, vtx[i], appctx_water->compkey_vtx, &waterdata->vertex[i], 1)); 558 } 559 560 /* ADD VARIABLES AND COMPONENTS AT THE SHARED VERTEX: net[0].4 coupls with net[1].0 -- owning and all ghost ranks of the vertex do this */ 561 PetscCall(DMNetworkGetSharedVertices(networkdm, &nv, &vtx)); 562 for (i = 0; i < nv; i++) { 563 /* power */ 564 PetscCall(DMNetworkAddComponent(networkdm, vtx[i], appctx_power->compkey_bus, &pfdata->bus[4], 2)); 565 /* bus[4] is a load, add its component */ 566 PetscCall(DMNetworkAddComponent(networkdm, vtx[i], appctx_power->compkey_load, &pfdata->load[0], 0)); 567 568 /* water */ 569 PetscCall(DMNetworkAddComponent(networkdm, vtx[i], appctx_water->compkey_vtx, &waterdata->vertex[0], 1)); 570 } 571 572 /* Set coordinates for visualization */ 573 PetscCall(DMSetCoordinateDim(networkdm, 2)); 574 PetscCall(DMGetCoordinateDM(networkdm, &dmclone)); 575 PetscCall(DMNetworkGetVertexRange(dmclone, &vStart, &vEnd)); 576 PetscCall(DMNetworkRegisterComponent(dmclone, "coordinates", 0, &compkey)); 577 for (i = vStart; i < vEnd; i++) PetscCall(DMNetworkAddComponent(dmclone, i, compkey, NULL, 2)); 578 PetscCall(DMNetworkFinalizeComponents(dmclone)); 579 580 PetscCall(DMCreateLocalVector(dmclone, &coords)); 581 PetscCall(DMSetCoordinatesLocal(networkdm, coords)); /* set/get coords to/from networkdm */ 582 PetscCall(CoordinateVecSetUp(networkdm, coords)); 583 if (printCoord) PetscCall(CoordinatePrint(networkdm)); 584 585 /* Set up DM for use */ 586 PetscCall(DMSetUp(networkdm)); 587 588 /* Free user objects */ 589 PetscCall(PetscFree(edgelist_power)); 590 PetscCall(PetscFree(pfdata->bus)); 591 PetscCall(PetscFree(pfdata->gen)); 592 PetscCall(PetscFree(pfdata->branch)); 593 PetscCall(PetscFree(pfdata->load)); 594 PetscCall(PetscFree(pfdata)); 595 596 PetscCall(PetscFree(edgelist_water)); 597 PetscCall(PetscFree(waterdata->vertex)); 598 PetscCall(PetscFree(waterdata->edge)); 599 PetscCall(PetscFree(waterdata)); 600 601 /* Re-distribute networkdm to multiple processes for better job balance */ 602 if (distribute) { 603 PetscCall(DMNetworkDistribute(&networkdm, 0)); 604 605 if (printCoord) PetscCall(CoordinatePrint(networkdm)); 606 if (viewCSV) { /* CSV View of network with coordinates */ 607 PetscCall(PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD, PETSC_VIEWER_ASCII_CSV)); 608 PetscCall(DMView(networkdm, PETSC_VIEWER_STDOUT_WORLD)); 609 PetscCall(PetscViewerPopFormat(PETSC_VIEWER_STDOUT_WORLD)); 610 } 611 } 612 PetscCall(VecDestroy(&coords)); 613 614 /* Test DMNetworkGetSubnetwork() and DMNetworkGetSubnetworkSharedVertices() */ 615 if (test) { 616 PetscInt v, gidx; 617 PetscCallMPI(MPI_Barrier(PETSC_COMM_WORLD)); 618 for (i = 0; i < Nsubnet; i++) { 619 PetscCall(DMNetworkGetSubnetwork(networkdm, i, &nv, &ne, &vtx, &edges)); 620 PetscCall(PetscPrintf(PETSC_COMM_SELF, "[%d] After distribute, subnet[%" PetscInt_FMT "] ne %" PetscInt_FMT ", nv %" PetscInt_FMT "\n", rank, i, ne, nv)); 621 PetscCallMPI(MPI_Barrier(PETSC_COMM_WORLD)); 622 623 for (v = 0; v < nv; v++) { 624 PetscCall(DMNetworkIsGhostVertex(networkdm, vtx[v], &ghost)); 625 PetscCall(DMNetworkGetGlobalVertexIndex(networkdm, vtx[v], &gidx)); 626 PetscCall(PetscPrintf(PETSC_COMM_SELF, "[%d] subnet[%" PetscInt_FMT "] v %" PetscInt_FMT " %" PetscInt_FMT "; ghost %d\n", rank, i, vtx[v], gidx, ghost)); 627 } 628 PetscCallMPI(MPI_Barrier(PETSC_COMM_WORLD)); 629 } 630 PetscCallMPI(MPI_Barrier(PETSC_COMM_WORLD)); 631 632 PetscCall(DMNetworkGetSharedVertices(networkdm, &nv, &vtx)); 633 PetscCall(PetscPrintf(PETSC_COMM_SELF, "[%d] After distribute, num of shared vertices nsv = %" PetscInt_FMT "\n", rank, nv)); 634 for (v = 0; v < nv; v++) { 635 PetscCall(DMNetworkGetGlobalVertexIndex(networkdm, vtx[v], &gidx)); 636 PetscCall(PetscPrintf(PETSC_COMM_SELF, "[%d] sv %" PetscInt_FMT ", gidx=%" PetscInt_FMT "\n", rank, vtx[v], gidx)); 637 } 638 PetscCallMPI(MPI_Barrier(PETSC_COMM_WORLD)); 639 } 640 641 /* Create solution vector X */ 642 PetscCall(DMCreateGlobalVector(networkdm, &X)); 643 PetscCall(VecDuplicate(X, &F)); 644 PetscCall(DMGetLocalVector(networkdm, &user.localXold)); 645 PetscCall(PetscLogStagePop()); 646 647 /* (3) Setup Solvers */ 648 PetscCall(PetscOptionsGetBool(NULL, NULL, "-viewJ", &viewJ, NULL)); 649 PetscCall(PetscOptionsGetBool(NULL, NULL, "-viewX", &viewX, NULL)); 650 651 PetscCall(PetscLogStageRegister("SNES Setup", &stage[2])); 652 PetscCall(PetscLogStagePush(stage[2])); 653 654 PetscCall(SetInitialGuess(networkdm, X, &user)); 655 656 /* Create coupled snes */ 657 PetscCall(PetscPrintf(PETSC_COMM_WORLD, "SNES_coupled setup ......\n")); 658 user.subsnes_id = Nsubnet; 659 PetscCall(SNESCreate(PETSC_COMM_WORLD, &snes)); 660 PetscCall(SNESSetDM(snes, networkdm)); 661 PetscCall(SNESSetOptionsPrefix(snes, "coupled_")); 662 PetscCall(SNESSetFunction(snes, F, FormFunction, &user)); 663 PetscCall(SNESMonitorSet(snes, UserMonitor, &user, NULL)); 664 PetscCall(SNESSetFromOptions(snes)); 665 666 if (viewJ) { 667 /* View Jac structure */ 668 PetscCall(SNESGetJacobian(snes, &Jac, NULL, NULL, NULL)); 669 PetscCall(MatView(Jac, PETSC_VIEWER_DRAW_WORLD)); 670 } 671 672 if (viewX) { 673 PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Solution:\n")); 674 PetscCall(VecView(X, PETSC_VIEWER_STDOUT_WORLD)); 675 } 676 677 if (viewJ) { 678 /* View assembled Jac */ 679 PetscCall(MatView(Jac, PETSC_VIEWER_DRAW_WORLD)); 680 } 681 682 /* Create snes_power */ 683 PetscCall(PetscPrintf(PETSC_COMM_WORLD, "SNES_power setup ......\n")); 684 685 user.subsnes_id = 0; 686 PetscCall(SNESCreate(PETSC_COMM_WORLD, &snes_power)); 687 PetscCall(SNESSetDM(snes_power, networkdm)); 688 PetscCall(SNESSetOptionsPrefix(snes_power, "power_")); 689 PetscCall(SNESSetFunction(snes_power, F, FormFunction, &user)); 690 PetscCall(SNESMonitorSet(snes_power, UserMonitor, &user, NULL)); 691 692 /* Use user-provide Jacobian */ 693 PetscCall(DMCreateMatrix(networkdm, &Jac)); 694 PetscCall(SNESSetJacobian(snes_power, Jac, Jac, FormJacobian_subPower, &user)); 695 PetscCall(SNESSetFromOptions(snes_power)); 696 697 if (viewX) { 698 PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Power Solution:\n")); 699 PetscCall(VecView(X, PETSC_VIEWER_STDOUT_WORLD)); 700 } 701 if (viewJ) { 702 PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Power Jac:\n")); 703 PetscCall(SNESGetJacobian(snes_power, &Jac, NULL, NULL, NULL)); 704 PetscCall(MatView(Jac, PETSC_VIEWER_DRAW_WORLD)); 705 /* PetscCall(MatView(Jac,PETSC_VIEWER_STDOUT_WORLD)); */ 706 } 707 708 /* Create snes_water */ 709 PetscCall(PetscPrintf(PETSC_COMM_WORLD, "SNES_water setup......\n")); 710 711 user.subsnes_id = 1; 712 PetscCall(SNESCreate(PETSC_COMM_WORLD, &snes_water)); 713 PetscCall(SNESSetDM(snes_water, networkdm)); 714 PetscCall(SNESSetOptionsPrefix(snes_water, "water_")); 715 PetscCall(SNESSetFunction(snes_water, F, FormFunction, &user)); 716 PetscCall(SNESMonitorSet(snes_water, UserMonitor, &user, NULL)); 717 PetscCall(SNESSetFromOptions(snes_water)); 718 719 if (viewX) { 720 PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Water Solution:\n")); 721 PetscCall(VecView(X, PETSC_VIEWER_STDOUT_WORLD)); 722 } 723 PetscCall(PetscLogStagePop()); 724 725 /* (4) Solve */ 726 PetscCall(PetscLogStageRegister("SNES Solve", &stage[3])); 727 PetscCall(PetscLogStagePush(stage[3])); 728 user.it = 0; 729 reason = SNES_DIVERGED_DTOL; 730 while (user.it < it_max && (PetscInt)reason < 0) { 731 #if 0 732 user.subsnes_id = 0; 733 PetscCall(SNESSolve(snes_power,NULL,X)); 734 735 user.subsnes_id = 1; 736 PetscCall(SNESSolve(snes_water,NULL,X)); 737 #endif 738 user.subsnes_id = Nsubnet; 739 PetscCall(SNESSolve(snes, NULL, X)); 740 741 PetscCall(SNESGetConvergedReason(snes, &reason)); 742 user.it++; 743 } 744 PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Coupled_SNES converged in %" PetscInt_FMT " iterations\n", user.it)); 745 if (viewX) { 746 PetscCall(PetscPrintf(PETSC_COMM_WORLD, "Final Solution:\n")); 747 PetscCall(VecView(X, PETSC_VIEWER_STDOUT_WORLD)); 748 } 749 PetscCall(PetscLogStagePop()); 750 751 /* Free objects */ 752 /* -------------*/ 753 PetscCall(VecDestroy(&X)); 754 PetscCall(VecDestroy(&F)); 755 PetscCall(DMRestoreLocalVector(networkdm, &user.localXold)); 756 757 PetscCall(SNESDestroy(&snes)); 758 PetscCall(MatDestroy(&Jac)); 759 PetscCall(SNESDestroy(&snes_power)); 760 PetscCall(SNESDestroy(&snes_water)); 761 762 PetscCall(DMDestroy(&networkdm)); 763 PetscCall(PetscFinalize()); 764 return 0; 765 } 766 767 /*TEST 768 769 build: 770 requires: !complex double defined(PETSC_HAVE_ATTRIBUTEALIGNED) 771 depends: power/PFReadData.c power/pffunctions.c water/waterreaddata.c water/waterfunctions.c 772 773 test: 774 args: -coupled_snes_converged_reason -options_left no -dmnetwork_view 775 localrunfiles: ex1options power/case9.m water/sample1.inp 776 output_file: output/ex1.out 777 778 test: 779 suffix: 2 780 nsize: 3 781 args: -coupled_snes_converged_reason -options_left no -petscpartitioner_type parmetis 782 localrunfiles: ex1options power/case9.m water/sample1.inp 783 output_file: output/ex1_2.out 784 requires: parmetis 785 786 test: 787 suffix: 3 788 nsize: 3 789 args: -coupled_snes_converged_reason -options_left no -distribute false 790 localrunfiles: ex1options power/case9.m water/sample1.inp 791 output_file: output/ex1_2.out 792 793 test: 794 suffix: 4 795 nsize: 4 796 args: -coupled_snes_converged_reason -options_left no -petscpartitioner_type simple -dmnetwork_view -dmnetwork_view_distributed 797 localrunfiles: ex1options power/case9.m water/sample1.inp 798 output_file: output/ex1_4.out 799 800 test: 801 suffix: 5 802 args: -coupled_snes_converged_reason -options_left no -viewCSV 803 localrunfiles: ex1options power/case9.m water/sample1.inp 804 output_file: output/ex1_5.out 805 806 test: 807 suffix: 6 808 nsize: 3 809 args: -coupled_snes_converged_reason -options_left no -petscpartitioner_type parmetis -dmnetwork_view_distributed draw:null 810 localrunfiles: ex1options power/case9.m water/sample1.inp 811 output_file: output/ex1_2.out 812 requires: parmetis 813 814 TEST*/ 815