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