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