Basic example with renewable producer and battery
This tutorial goes over a creation of a simple Tulipa problem, with the following:
- 1 thermal generator, with 1 existing unit, and capacity for 500 KW;
- 1 solar generator, with 1 existing unit, capacity for 200 KW and an availability profile named "solar";
- 1 consumer, with peak demand of 500 KW, and a demand profile named "demand";
- 1 battery node;
- The profiles are stored in a CSV file.
using TulipaBuilderThe first step is to create a TulipaData object.
tulipa = TulipaData()TulipaData{String}(Meta graph based on a Graphs.SimpleGraphs.SimpleDiGraph{Int64} with vertex labels of type String, vertex metadata of type TulipaBuilder.TulipaAsset, edge metadata of type TulipaBuilder.TulipaFlow, graph metadata given by nothing, and default weight 1.0, false, Dict{Int64, Dict{Symbol, Any}}(), Dict{Tuple{String, Int64}, Dict{Symbol, Any}}())Then, we add each asset with their respective characteristics.
add_asset!(tulipa, "thermal", :producer, capacity = 500.0, initial_units = 1.0)
add_asset!(tulipa, "solar", :producer, capacity = 200.0, initial_units = 1.0)
add_asset!(tulipa, "demand", :consumer, peak_demand = 500.0)
add_asset!(tulipa, "battery", :storage)TulipaData{String}(Meta graph based on a Graphs.SimpleGraphs.SimpleDiGraph{Int64} with vertex labels of type String, vertex metadata of type TulipaBuilder.TulipaAsset, edge metadata of type TulipaBuilder.TulipaFlow, graph metadata given by nothing, and default weight 1.0, false, Dict{Int64, Dict{Symbol, Any}}(), Dict{Tuple{String, Int64}, Dict{Symbol, Any}}())Next, we need to define the flows between these assets, and the operational cost, if defined.
add_flow!(tulipa, "thermal", "demand", operational_cost = 0.05)
add_flow!(tulipa, "solar", "demand")
add_flow!(tulipa, "demand", "battery")
add_flow!(tulipa, "battery", "demand")TulipaData{String}(Meta graph based on a Graphs.SimpleGraphs.SimpleDiGraph{Int64} with vertex labels of type String, vertex metadata of type TulipaBuilder.TulipaAsset, edge metadata of type TulipaBuilder.TulipaFlow, graph metadata given by nothing, and default weight 1.0, false, Dict{Int64, Dict{Symbol, Any}}(), Dict{Tuple{String, Int64}, Dict{Symbol, Any}}())At this point, we can visualise the network using the internal graph. Note that this is optional, and you can just skip ahead.
# OPTIONAL: Plotting the graph
using Karnak
using Colors
using MetaGraphsNext
graph = tulipa.graph
assets = collect(labels(graph))
color_per_type = Dict(:producer => colorant"red", :consumer => colorant"green", :storage => colorant"blue")
function vertexfillcolors(vtx)
asset = assets[vtx]
asset_type = graph[asset].type
return color_per_type[asset_type]
end
@drawsvg begin
background("lightblue")
sethue("black")
drawgraph(
graph.graph,
edgegaps = 20,
vertexlabels = assets,
vertexfillcolors = vertexfillcolors,
vertexshapes = (vtx) -> box(O, 6.5 * length(assets[vtx]), 20, :fill),
vertexlabeltextcolors = colorant"white",
)
end 600 400Now, let's attach the profiles to the solar and demand assets. Notice that we need to pass the year in which these profiles are defined. In a single-year problem, the year doesn't matter, so any integer value could be used.
using CSV
using DataFrames
profiles_data = joinpath(@__DIR__, "..", "..", "..", "test", "tiny-profiles.csv")
df = DataFrame(CSV.File(profiles_data))
attach_profile!(tulipa, "solar", :availability, 2030, df[!, "availability-solar"])
attach_profile!(tulipa, "demand", :demand, 2030, df[!, "demand-demand"])
# Plotting the first week of the profiles
using Plots
plt = plot()
plot!(plt, df[1:168, "availability-solar"], c=:orange, lw=2, label="solar")
plot!(plt, df[1:168, "demand-demand"], c=:green, lw=2, label="demand")Now we can create the connection with the data of the Tulipa problem using the create_connection function.
using TulipaEnergyModel: TulipaEnergyModel as TEM
connection = create_connection(tulipa, TEM.schema)DuckDB.DB(":memory:")Notice that the profile names are automatically created from the attached data:
using DuckDB
DuckDB.query(connection, "FROM assets_profiles") |> DataFrame| Row | asset | commission_year | profile_name | profile_type |
|---|---|---|---|---|
| String | Int64 | String | String | |
| 1 | solar | 2030 | solar-availability-2030 | availability |
| 2 | demand | 2030 | demand-demand-2030 | demand |