Skip to content

Commit

Permalink
Merge pull request #8 from lanl-ansi/v0.2-dev
Browse files Browse the repository at this point in the history
UPD: Updates for new versions of InfrastructureModels, PowerModelsDistribution, and WaterModels
  • Loading branch information
tasseff authored Sep 3, 2021
2 parents c793092 + 8605961 commit 61c1e37
Show file tree
Hide file tree
Showing 30 changed files with 889 additions and 507 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
PowerWaterModels.jl Change Log
=======================
### v0.2.0
- Updates for WaterModels v0.8.
- Updates for PowerModelsDistribution v0.11.
- Updates for InfrastructureModels v0.6.

### v0.1.0
- Updates for WaterModels v0.6.0.
Expand Down
12 changes: 8 additions & 4 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
name = "PowerWaterModels"
uuid = "7f4f7f52-2f44-4c87-b9ed-462dc784f1b2"
authors = ["Byron Tasseff"]
authors = ["Byron Tasseff", "Russell Bent", "Carleton Coffrin"]
repo = "https://github.com/lanl-ansi/PowerWaterModels.jl"
version = "0.1.0"
version = "0.2.0"

[deps]
InfrastructureModels = "2030c09a-7f63-5d83-885d-db604e0e9cc0"
PowerModels = "c36e90e8-916a-50a6-bd94-075b64ef4655"
PowerModelsDistribution = "d7431456-977f-11e9-2de3-97ff7677985e"
WaterModels = "7c60b362-08f4-5b14-8680-cd67a3e18348"

[compat]
PowerModelsDistribution = "~0.9"
WaterModels = "~0.6"
InfrastructureModels = "~0.6"
PowerModels = "~0.18"
PowerModelsDistribution = "~0.11"
WaterModels = "~0.8"
julia = "^1"

[extras]
Expand Down
21 changes: 9 additions & 12 deletions docs/src/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ CurrentModule = PowerWaterModels
```

## Overview
PowerWaterModels.jl is a Julia/JuMP package for the joint optimization of steady state power and water distribution networks.
PowerWaterModels.jl is a Julia/JuMP package for the joint optimization of steady-state power and water distribution networks.
It is designed to enable the computational evaluation of historical and emerging power-water network optimization formulations and algorithms using a common platform.
The code is engineered to decouple [Problem Specifications](@ref) (e.g., power-water flow, optimal power-water flow) from [Network Formulations](@ref) (e.g., mixed-integer linear, mixed-integer nonlinear).
This decoupling enables the definition of a variety of optimization formulations and their comparison on common problem specifications.
Expand Down Expand Up @@ -44,25 +44,22 @@ using JuMP, Juniper, Ipopt, Cbc
using PowerWaterModels

# Set up the optimization solvers.
ipopt = JuMP.optimizer_with_attributes(Ipopt.Optimizer, "print_level"=>0, "sb"=>"yes")
cbc = JuMP.optimizer_with_attributes(Cbc.Optimizer, "logLevel"=>0)
ipopt = JuMP.optimizer_with_attributes(Ipopt.Optimizer, "print_level" => 0, "sb" => "yes")
cbc = JuMP.optimizer_with_attributes(Cbc.Optimizer, "logLevel" => 0)
juniper = JuMP.optimizer_with_attributes(
Juniper.Optimizer, "nl_solver"=>ipopt, "mip_solver"=>cbc,
"branch_strategy" => :MostInfeasible, "time_limit" => 60.0)
Juniper.Optimizer, "nl_solver" => ipopt, "mip_solver" => cbc,
"time_limit" => 60.0)

# Specify paths to the power, water, and power-water linking files.
p_file = "examples/data/opendss/IEEE13_CDPSM.dss" # Power network.
w_file = "examples/data/epanet/cohen-short.inp" # Water network.
pw_file = "examples/data/json/zamzam.json" # Power-water linking.

# Specify the power and water formulation types separately.
p_type, w_type = LinDist3FlowPowerModel, PWLRDWaterModel

# Specify the number of breakpoints used in the linearized water formulation.
wm_ext = Dict{Symbol,Any}(:pipe_breakpoints=>2, :pump_breakpoints=>3)
pwm_type = PowerWaterModel{LinDist3FlowPowerModel, CRDWaterModel}

# Solve the joint optimal power-water flow problem and store the result.
result = run_opwf(p_file, w_file, pw_file, p_type, w_type, juniper; wm_ext=wm_ext)
result = run_opwf(p_file, w_file, pw_file, pwm_type, juniper)
```

After solving the problem, results can then be analyzed, e.g.,
Expand All @@ -72,8 +69,8 @@ After solving the problem, results can then be analyzed, e.g.,
result["objective"]

# Generator 1's real power generation at the first time step.
result["solution"]["nw"]["1"]["gen"]["1"]["pg"]
result["solution"]["it"]["pmd"]["nw"]["1"]["gen"]["1"]["pg"]

# Pump 2's head gain at the third time step.
result["solution"]["nw"]["3"]["pump"]["2"]["g"]
result["solution"]["it"]["wm"]["nw"]["3"]["pump"]["2"]["g"]
```
59 changes: 25 additions & 34 deletions docs/src/quickguide.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,27 +44,35 @@ After installation of the required solvers, an example optimal power-water flow
```julia
using JuMP, Juniper, Ipopt, Cbc
using PowerWaterModels
const WM = PowerWaterModels.WaterModels

# Set up the optimization solvers.
ipopt = JuMP.optimizer_with_attributes(Ipopt.Optimizer, "print_level"=>0, "sb"=>"yes")
cbc = JuMP.optimizer_with_attributes(Cbc.Optimizer, "logLevel"=>0)
ipopt = JuMP.optimizer_with_attributes(Ipopt.Optimizer, "print_level" => 0, "sb" => "yes")
cbc = JuMP.optimizer_with_attributes(Cbc.Optimizer, "logLevel" => 0)
juniper = JuMP.optimizer_with_attributes(
Juniper.Optimizer, "nl_solver"=>ipopt, "mip_solver"=>cbc,
Juniper.Optimizer, "nl_solver" => ipopt, "mip_solver" => cbc,
"branch_strategy" => :MostInfeasible, "time_limit" => 60.0)

# Specify paths to the power, water, and power-water linking files.
p_file = "examples/data/opendss/IEEE13_CDPSM.dss" # Power network.
w_file = "examples/data/epanet/cohen-short.inp" # Water network.
pw_file = "examples/data/json/zamzam.json" # Power-water linking.

# Specify the power and water formulation types separately.
p_type, w_type = LinDist3FlowPowerModel, PWLRDWaterModel
# Parse the input files as a multi-infrastructure data object.
data = parse_files(p_file, w_file, pw_file)

# Perform OBBT on water network to improve variable bounds.
WM.solve_obbt_owf!(data, ipopt; use_relaxed_network = false,
model_type = WM.CRDWaterModel, max_iter = 3)

# Specify the number of breakpoints used in the linearized water formulation.
wm_ext = Dict{Symbol,Any}(:pipe_breakpoints=>2, :pump_breakpoints=>3)
# Use WaterModels to set the partitioning of flows in the water network.
WM.set_flow_partitions_num!(data, 5)

# Specify the power and water formulation types separately.
pwm_type = PowerWaterModel{LinDist3FlowPowerModel, PWLRDWaterModel}

# Solve the joint optimal power-water flow problem and store the result.
result = run_opwf(p_file, w_file, pw_file, p_type, w_type, juniper; wm_ext=wm_ext)
result = run_opwf(data, pwm_type, juniper)
```

### (Optional) Solving the Problem with Gurobi
Expand All @@ -75,8 +83,8 @@ The problem considered above can then be solved using Gurobi (instead of Juniper
import Gurobi

# Solve the joint optimal power-water flow problem and store its result.
gurobi = JuMP.optimizer_with_attributes(Gurobi.Optimizer, "NonConvex"=>2)
result_grb = run_opwf(p_file, w_file, pw_file, p_type, w_type, gurobi; wm_ext=wm_ext)
gurobi = JuMP.optimizer_with_attributes(Gurobi.Optimizer, "NonConvex" => 2)
result_grb = run_opwf(data, pwm_type, gurobi)
```

First, note that Gurobi solves the problem much more quickly than Juniper.
Expand All @@ -91,7 +99,7 @@ The objective value obtained via Gurobi is _smaller_ than the one obtained via J
The `run` commands in PowerWaterModels return detailed results data in the form of a Julia `Dict`.
This dictionary can be saved for further processing as follows:
```julia
result = run_opwf(p_file, w_file, pw_file, p_type, w_type, juniper; wm_ext=wm_ext)
result = run_opwf(data, pwm_type, juniper)
```

For example, the algorithm's runtime and final objective value can be accessed with
Expand All @@ -103,38 +111,21 @@ result["objective"] # Final objective value (in units of the objective).
The `"solution"` field contains detailed information about the solution produced by the `run` method.
For example, the following can be used to inspect the temporal variation in the volume of tank 1 in the water distribution network:
```
tank_1_volume = Dict(nw=>data["tank"]["10"]["V"] for (nw, data) in result["solution"]["nw"])
tank_1_volume = Dict(nw=>data["tank"]["10"]["V"] for (nw, data) in result["solution"]["it"]["wm"]["nw"])
```

For more information about PowerWaterModels result data, see the [PowerWaterModels Result Data Format](@ref) section.

## Modifying Network Data
The following example demonstrates one way to perform PowerWaterModels solves while modifying network data.
```julia
p_data, w_data, pw_data = parse_files(p_file, w_file, pw_file)

for (nw, network) in w_data["nw"]
network["demand"]["3"]["flow_nominal"] *= 0.1
network["demand"]["4"]["flow_nominal"] *= 0.1
network["demand"]["5"]["flow_nominal"] *= 0.1
for (nw, network) in data["it"]["wm"]["nw"]
network["demand"]["3"]["flow_nominal"] *= 0.90
network["demand"]["4"]["flow_nominal"] *= 0.90
network["demand"]["5"]["flow_nominal"] *= 0.90
end

result_mod = run_opwf(p_data, w_data, pw_data, p_type, w_type, juniper; wm_ext=wm_ext)
result_mod = run_opwf(data, pwm_type, juniper)
```
Note that the smaller demands in the modified problem result in an overall smaller objective value.
For additional details about the network data, see the [PowerWaterModels Network Data Format](@ref) section.

## Alternate Methods for Building and Solving Models
The following example demonstrates how to break a `run_opwf` call into separate model building and solving steps.
This allows inspection of the JuMP model created by PowerWaterModels for the problem.
```julia
# Instantiate the joint power-water models.
pm, wm = instantiate_model(p_data, w_data, pw_data, p_type, w_type, build_opwf; wm_ext=wm_ext)

# Print the (shared) JuMP model.
print(pm.model)

# Create separate power and water result dictionaries.
power_result = PowerWaterModels._IM.optimize_model!(pm, optimizer=juniper)
water_result = PowerWaterModels._IM.build_result(wm, power_result["solve_time"])
```
51 changes: 35 additions & 16 deletions examples/data/json/zamzam.json
Original file line number Diff line number Diff line change
@@ -1,22 +1,41 @@
{
"power_water_links": [
{
"load_source_id": "Load.634a",
"pump_source_id": "1"
"it": {
"dep": {
"pump_load": {
"1": {
"pump": {
"source_id": "1"
},
"load": {
"source_id": "Load.634a"
},
"status": 1
},
"2": {
"pump": {
"source_id": "2"
},
"load": {
"source_id": "Load.645"
},
"status": 1
},
"3": {
"pump": {
"source_id": "5"
},
"load": {
"source_id": "Load.611"
},
"status": 1
}
}
},
{
"load_source_id": "Load.645",
"pump_source_id": "2"
"pmd": {
"source_type": "opendss"
},
{
"load_source_id": "Load.611",
"pump_source_id": "5"
"wm": {
"source_type": "epanet"
}
],
"power_metadata": {
"source_type": "opendss"
},
"water_metadata": {
"source_type": "epanet"
}
}
15 changes: 12 additions & 3 deletions src/PowerWaterModels.jl
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
module PowerWaterModels
import InfrastructureModels
import InfrastructureModels: optimize_model!, @im_fields, ismultinetwork, nw_id_default
import PowerModels
import PowerModelsDistribution
import WaterModels

# Initialize shortened package names for convenience.
const _PM = PowerModels
const _PMD = PowerModelsDistribution
const _WM = WaterModels

const _IM = _PMD._IM # InfrastructureModels
const _PM = _PMD._PM # PowerModels
const _IM = InfrastructureModels
const _MOI = _IM._MOI # MathOptInterface

# Borrow dependencies from other packages.
Expand Down Expand Up @@ -37,13 +39,20 @@ module PowerWaterModels
Memento.config!(Memento.getlogger("PowerWaterModels"), level)
end

const _pwm_global_keys = union(_PMD._pmd_global_keys, _WM._wm_global_keys)

include("io/json.jl")
include("io/common.jl")

include("core/base.jl")
include("core/constants.jl")
include("core/data.jl")
include("core/helpers.jl")
include("core/constraint.jl")
include("core/objective.jl")
include("core/types.jl")

include("prob/linking.jl")
include("prob/pwf.jl")
include("prob/opwf.jl")

Expand Down
Loading

0 comments on commit 61c1e37

Please sign in to comment.