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