Convert usage.md to Literate.jl

m2m
Alinson S. Xavier 1 year ago
parent 007de88c3f
commit 8b78f38c25

1
.gitignore vendored

@ -36,3 +36,4 @@ instances/**/*.json
instances/_source instances/_source
local local
notebooks notebooks
docs/src/tutorials/usage.md

@ -4,6 +4,7 @@ Glob = "c27321d9-0574-5035-807b-f59d2c89b15c"
HiGHS = "87dc4568-4c63-4d18-b0c0-bb2238e4078b" HiGHS = "87dc4568-4c63-4d18-b0c0-bb2238e4078b"
JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" JSON = "682c06a0-de6a-54ab-a142-c8b1cf79cde6"
JuMP = "4076af6c-e467-56ae-b986-b466b2749572" JuMP = "4076af6c-e467-56ae-b986-b466b2749572"
Literate = "98b081ad-f1c9-55d3-8b20-4c87d4299306"
MPI = "da04e1cc-30fd-572f-bb4f-1f8673147195" MPI = "da04e1cc-30fd-572f-bb4f-1f8673147195"
Revise = "295af30f-e4ad-537b-8983-00126c2a3abe" Revise = "295af30f-e4ad-537b-8983-00126c2a3abe"
UnitCommitment = "64606440-39ea-11e9-0f29-3303a1d3d877" UnitCommitment = "64606440-39ea-11e9-0f29-3303a1d3d877"

@ -1,6 +1,22 @@
using Documenter, UnitCommitment, JuMP using Documenter
using UnitCommitment
using JuMP
using Literate
function make() function make()
literate_sources = [
"src/tutorials/usage.jl"
]
for src in literate_sources
Literate.markdown(
src,
dirname(src);
documenter = true,
credit = false,
)
end
return makedocs( return makedocs(
sitename = "UnitCommitment.jl", sitename = "UnitCommitment.jl",
pages = [ pages = [

@ -0,0 +1,188 @@
# # Getting started
# ## Installing the package
# UnitCommitment.jl was tested and developed with [Julia 1.10](https://julialang.org/). To install Julia, please follow the [installation guide on the official Julia website](https://julialang.org/downloads/). To install UnitCommitment.jl, run the Julia interpreter, type `]` to open the package manager, then type:
# ```text
# pkg> add UnitCommitment@0.4
# ```
# To solve the optimization models, a mixed-integer linear programming (MILP) solver is also required. Please see the [JuMP installation guide](https://jump.dev/JuMP.jl/stable/installation/) for more instructions on installing a solver. Typical open-source choices are [HiGHS](https://github.com/jump-dev/HiGHS.jl), [Cbc](https://github.com/JuliaOpt/Cbc.jl) and [GLPK](https://github.com/JuliaOpt/GLPK.jl). In the instructions below, HiGHS will be used, but any other MILP solver listed in JuMP installation guide should also be compatible.
# ## Solving a benchmark instance
# In this section, we illustrate how to use the package by solving one of the provided benchmark instances. The first step is to import `UnitCommitment` and HiGHS, our MILP solver.
using HiGHS
using UnitCommitment
# Next, we use the function `read_benchmark` to read one of the provided benchmark instances. UnitCommitment.jl contains a large number of deterministic benchmark instances collected from the literature and converted into a common data format. See [Instances](../guides/instances.md) for more details.
instance = UnitCommitment.read_benchmark("matpower/case14/2017-01-01");
# Now that we have the instance loaded in memory, we build the JuMP optimization model using `UnitCommitment.build_model`:
model = UnitCommitment.build_model(
instance=instance,
optimizer=HiGHS.Optimizer,
);
# Next, we run the optimization process, with `UnitCommitment.optimize!`:
UnitCommitment.optimize!(model)
# Finally, we export the optimal solution to a JSON file:
solution = UnitCommitment.solution(model)
UnitCommitment.write("solution.json", solution)
# ## Solving a custom deterministic instance
# In the previous example, we solved an instance provided by the package. To solve your own custom instances, the first step is to create an input file describing your generators, loads and transmission network in JSON format. See [Data Format](../guides/format.md) for a complete description of the data format UC.jl expects. To keep this tutorial self-contained, we will create the input JSON file using Julia, but this step can also be done with a simple text editor.
# First, we define the contents of the file:
json_contents = """
{
"Parameters": {
"Version": "0.4",
"Time horizon (h)": 4
},
"Buses": {
"b1": {
"Load (MW)": [100, 150, 200, 250]
}
},
"Generators": {
"g1": {
"Bus": "b1",
"Type": "Thermal",
"Production cost curve (MW)": [0, 200],
"Production cost curve (\$)": [0, 1000],
"Initial status (h)": -24,
"Initial power (MW)": 0
},
"g2": {
"Bus": "b1",
"Type": "Thermal",
"Production cost curve (MW)": [0, 300],
"Production cost curve (\$)": [0, 3000],
"Initial status (h)": -24,
"Initial power (MW)": 0
}
}
}
""";
# Next, we write it to `example.json`.
open("example.json", "w") do file
write(file, json_contents)
end;
# Now that we have the input file, we can proceed as before, but using `UnitCommitment.read` instead of `UnitCommitment.read_benchmark`:
instance = UnitCommitment.read("example.json");
model = UnitCommitment.build_model(
instance=instance,
optimizer=HiGHS.Optimizer,
);
UnitCommitment.optimize!(model)
# ## Solving a custom stochastic instance
# In addition to deterministic test cases, UnitCommitment.jl can also solve two-stage stochastic instances of the problem. In this section, we demonstrate the most simple form, which builds a single extensive form model containing information for all scenarios. See [Decomposition](../tutorials/decomposition.md) for details on using a scenario decomposition approach with Progressive Hedging.
# First, we need to create one JSON input file for each scenario. Parameters that are allowed to change across scenarios are marked as "uncertain" in the [JSON data format](../guides/format.md) page. It is also possible to specify the name and weight of each scenario, as shown below.
json_contents_s1 = """
{
"Parameters": {
"Version": "0.4",
"Time horizon (h)": 4,
"Scenario name": "s1",
"Scenario weight": 3.0
},
"Buses": {
"b1": {
"Load (MW)": [100, 150, 200, 250]
}
},
"Generators": {
"g1": {
"Bus": "b1",
"Type": "Thermal",
"Production cost curve (MW)": [0, 200],
"Production cost curve (\$)": [0, 1000],
"Initial status (h)": -24,
"Initial power (MW)": 0
},
"g2": {
"Bus": "b1",
"Type": "Thermal",
"Production cost curve (MW)": [0, 300],
"Production cost curve (\$)": [0, 3000],
"Initial status (h)": -24,
"Initial power (MW)": 0
}
}
}
"""
open("example_s1.json", "w") do file
write(file, json_contents_s1)
end;
json_contents_s2 = """
{
"Parameters": {
"Version": "0.4",
"Time horizon (h)": 4,
"Scenario name": "s1",
"Scenario weight": 1.0
},
"Buses": {
"b1": {
"Load (MW)": [200, 300, 400, 500]
}
},
"Generators": {
"g1": {
"Bus": "b1",
"Type": "Thermal",
"Production cost curve (MW)": [0, 200],
"Production cost curve (\$)": [0, 1000],
"Initial status (h)": -24,
"Initial power (MW)": 0
},
"g2": {
"Bus": "b1",
"Type": "Thermal",
"Production cost curve (MW)": [0, 300],
"Production cost curve (\$)": [0, 3000],
"Initial status (h)": -24,
"Initial power (MW)": 0
}
}
}
""";
open("example_s2.json", "w") do file
write(file, json_contents_s2)
end;
# Now that we have our two scenario files, we can read them using `UnitCommitment.read`:
instance = UnitCommitment.read(["example_s1.json", "example_s2.json"])
# If we have a large number of scenario files, the [Glob](https://github.com/vtjnash/Glob.jl) package can also be used to avoid having to enumerate them individually:
using Glob
instance = UnitCommitment.read(glob("example_s*.json"))
# Finally, we build the model and optmize as before:
model = UnitCommitment.build_model(
instance=instance,
optimizer=HiGHS.Optimizer,
);
UnitCommitment.optimize!(model)

@ -1,119 +0,0 @@
# Getting started
## Installation
UnitCommitment.jl was tested and developed with [Julia 1.9](https://julialang.org/). To install Julia, please follow the [installation guide on the official Julia website](https://julialang.org/downloads/). To install UnitCommitment.jl, run the Julia interpreter, type `]` to open the package manager, then type:
```text
pkg> add UnitCommitment@0.4
```
To solve the optimization models, a mixed-integer linear programming (MILP) solver is also required. Please see the [JuMP installation guide](https://jump.dev/JuMP.jl/stable/installation/) for more instructions on installing a solver. Typical open-source choices are [HiGHS](https://github.com/jump-dev/HiGHS.jl), [Cbc](https://github.com/JuliaOpt/Cbc.jl) and [GLPK](https://github.com/JuliaOpt/GLPK.jl). In the instructions below, HiGHS will be used, but any other MILP solver listed in JuMP installation guide should also be compatible.
## Solving user-provided instances
The first step to use UC.jl is to construct JSON files that describe each scenario of your deterministic or stochastic unit commitment instance. See [Data Format](../guides/format.md) for a complete description of the data format UC.jl expects. The next steps, as shown below, are to: (1) read the scenario files; (2) build the optimization model; (3) run the optimization; and (4) extract the optimal solution.
```julia
using HiGHS
using JuMP
using UnitCommitment
# 1. Read instance
instance = UnitCommitment.read(["example/s1.json", "example/s2.json"])
# 2. Construct optimization model
model = UnitCommitment.build_model(
instance=instance,
optimizer=HiGHS.Optimizer,
)
# 3. Solve model
UnitCommitment.optimize!(model)
# 4. Write solution to a file
solution = UnitCommitment.solution(model)
UnitCommitment.write("example/out.json", solution)
```
To read multiple files from a given folder, the [Glob](https://github.com/vtjnash/Glob.jl) package can be used:
```jldoctest usage1; output = false
using Glob
using UnitCommitment
instance = UnitCommitment.read(glob("s*.json", "example/"))
# output
UnitCommitmentInstance(2 scenarios, 6 thermal units, 0 profiled units, 14 buses, 20 lines, 19 contingencies, 1 price sensitive loads, 4 time steps)
```
To solve deterministic instances, a single scenario file may be provided.
```jldoctest usage1; output = false
instance = UnitCommitment.read("example/s1.json")
# output
UnitCommitmentInstance(1 scenarios, 6 thermal units, 0 profiled units, 14 buses, 20 lines, 19 contingencies, 1 price sensitive loads, 4 time steps)
```
## Solving benchmark instances
UnitCommitment.jl contains a large number of deterministic benchmark instances collected from the literature and converted into a common data format. To solve one of these instances individually, instead of constructing your own, the function `read_benchmark` can be used, as shown below. See [Instances](../guides/instances.md) for the complete list of available instances.
```jldoctest usage1; output = false
instance = UnitCommitment.read_benchmark("matpower/case3375wp/2017-02-01")
# output
UnitCommitmentInstance(1 scenarios, 590 thermal units, 0 profiled units, 3374 buses, 4161 lines, 3245 contingencies, 0 price sensitive loads, 36 time steps)
```
## Generating initial conditions
When creating random unit commitment instances for benchmark purposes, it is often hard to compute, in advance, sensible initial conditions for all thermal generators. Setting initial conditions naively (for example, making all generators initially off and producing no power) can easily cause the instance to become infeasible due to excessive ramping. Initial conditions can also make it hard to modify existing instances. For example, increasing the system load without carefully modifying the initial conditions may make the problem infeasible or unrealistically challenging to solve.
To help with this issue, UC.jl provides a utility function which can generate feasible initial conditions by solving a single-period optimization problem, as shown below:
```julia
using HiGHS
using UnitCommitment
# Read original instance
instance = UnitCommitment.read("example/s1.json")
# Generate initial conditions (in-place)
UnitCommitment.generate_initial_conditions!(instance, HiGHS.Optimizer)
# Construct and solve optimization model
model = UnitCommitment.build_model(
instance=instance,
optimizer=HiGHS.Optimizer,
)
UnitCommitment.optimize!(model)
```
!!! warning
The function `generate_initial_conditions!` may return different initial conditions after each call, even if the same instance and the same optimizer is provided. The particular algorithm may also change in a future version of UC.jl. For these reasons, it is recommended that you generate initial conditions exactly once for each instance and store them for later use.
## Verifying solutions
When developing new formulations, it is very easy to introduce subtle errors in the model that result in incorrect solutions. To help avoiding this, UC.jl includes a utility function that verifies if a given solution is feasible, and, if not, prints all the validation errors it found. The implementation of this function is completely independent from the implementation of the optimization model, and therefore can be used to validate it.
```jldoctest; output = false
using JSON
using UnitCommitment
# Read instance
instance = UnitCommitment.read("example/s1.json")
# Read solution (potentially produced by other packages)
solution = JSON.parsefile("example/out.json")
# Validate solution and print validation errors
UnitCommitment.validate(instance, solution)
# output
true
```

@ -0,0 +1,76 @@
# ## Generating initial conditions
# When creating random unit commitment instances for benchmark purposes, it is often hard to compute, in advance, sensible initial conditions for all thermal generators. Setting initial conditions naively (for example, making all generators initially off and producing no power) can easily cause the instance to become infeasible due to excessive ramping. Initial conditions can also make it hard to modify existing instances. For example, increasing the system load without carefully modifying the initial conditions may make the problem infeasible or unrealistically challenging to solve.
# To help with this issue, UC.jl provides a utility function which can generate feasible initial conditions by solving a single-period optimization problem. To illustrate its usage, we first generate a JSON file without initial conditions:
json_contents = """
{
"Parameters": {
"Version": "0.4",
"Time horizon (h)": 4
},
"Buses": {
"b1": {
"Load (MW)": [100, 150, 200, 250]
}
},
"Generators": {
"g1": {
"Bus": "b1",
"Type": "Thermal",
"Production cost curve (MW)": [0, 200],
"Production cost curve (\$)": [0, 1000]
},
"g2": {
"Bus": "b1",
"Type": "Thermal",
"Production cost curve (MW)": [0, 300],
"Production cost curve (\$)": [0, 3000]
}
}
}
""";
open("example_initial.json", "w") do file
write(file, json_contents)
end;
# Next, we read the instance and generate the initial conditions (in-place):
instance = UnitCommitment.read("example_initial.json")
UnitCommitment.generate_initial_conditions!(instance, HiGHS.Optimizer)
# Finally, we optimize the resulting problem:
model = UnitCommitment.build_model(
instance=instance,
optimizer=HiGHS.Optimizer,
)
UnitCommitment.optimize!(model)
# !!! warning
# The function `generate_initial_conditions!` may return different initial conditions after each call, even if the same instance and the same optimizer is provided. The particular algorithm may also change in a future version of UC.jl. For these reasons, it is recommended that you generate initial conditions exactly once for each instance and store them for later use.
# ## 6. Verifying solutions
# When developing new formulations, it is very easy to introduce subtle errors in the model that result in incorrect solutions. To help avoiding this, UC.jl includes a utility function that verifies if a given solution is feasible, and, if not, prints all the validation errors it found. The implementation of this function is completely independent from the implementation of the optimization model, and therefore can be used to validate it.
# ```jldoctest; output = false
# using JSON
# using UnitCommitment
# # Read instance
# instance = UnitCommitment.read("example/s1.json")
# # Read solution (potentially produced by other packages)
# solution = JSON.parsefile("example/out.json")
# # Validate solution and print validation errors
# UnitCommitment.validate(instance, solution)
# # output
# true
# ```
Loading…
Cancel
Save