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