GithubHelp home page GithubHelp logo

youngfaithful / capacityexpansion.jl Goto Github PK

View Code? Open in Web Editor NEW
23.0 5.0 4.0 187.15 MB

Capacity Expansion Problem Formulation for Julia

Home Page: https://youngfaithful.github.io/CapacityExpansion.jl/stable

License: MIT License

Julia 97.70% TeX 2.30%
capacity-expansion-planning energy energy-optimization-model julia jump clustering california germany

capacityexpansion.jl's Introduction

CapacityExpansion logo

Build Status DOI DOI

CapacityExpansion is a julia implementation of an input-data-scaling capacity expansion modeling framework.

The primary purpose of the package is providing an extensible, simple-to-use generation and transmission capacity expansion model that allows addressing a diverse set of research questions in the area of energy systems planning. The secondary purposes are:

  1. Providing a simple process to integrate (clustered) time-series input data, geographical input data, cost input data, and technology input data.
  2. Providing a model configuration, a modular model setup and model optimization.
  3. Providing an interface between the optimization result and further analysis.

Please refer to the documentation for details on how to use this software.

Model Information
Model class Capacity Expansion Problem
Model type Optimization, Linear optimization model input-data depending energy system
Carriers Electricity, Hydrogen,...
Technologies dispatchable and non-dispatchable Generation, Conversion, Storage (seasonal), Transmission
Decisions investment and dispatch
Objective Total system cost
Variables Cost, Capacities, Generation, Storage, Lost-Load, Lost-Emissions
Input Data Depending Provided Input Data
Regions California, USA (single and multi-node) and Germany, Europe (single and multi-node)
Geographic Resolution aggregated regions
Time resolution hourly
Network coverage transmission, DCOPF load flow

The package uses TimeSeriesClustering as a basis for its time-series aggregation.

Elias Kuepper @YoungFaithful and Holger Teichgraeber @holgerteichgraeber developed this package.

Installation

This package runs under julia v1.0 and higher. It depends on multiple packages, which are also listed in the Project.toml. The julia package manager automatically installs the packages:

  • JuMP.jl - for the modeling environment
  • CSV.jl - for handling of .csv-Files
  • DataFrames.jl - for handling of tables
  • StatsBase.jl - for handling of basic
  • JLD2 - for saving your result data
  • FileIO - for file accessing
  • TimeSeriesClustering.jl - for time-series data

Install CapacityExpansion using the package mode:

]
add CapacityExpansion

or using the Pkg.add function:

using Pkg
Pkg.add("CapacityExpansion")

A solver is required to run an optimization, as explained in section Solver. Install e.g. Clp using the package mode:

]
add Clp

or using the Pkg.add function:

using Pkg
Pkg.add("Clp")

Example Workflow

using CapacityExpansion
using Clp
optimizer=Clp.Optimizer # select optimizer

## LOAD DATA ##
# laod ts-data
ts_input_data = load_timeseries_data_provided("GER_1"; T=24, years=[2016])
# load cep-data
cep_data = load_cep_data_provided("GER_1")

## OPTIMIZATION ##
# run a simple
run_opt(ts_input_data,cep_data,optimizer)

Testing

The model is being tested against a capacity expansion model presented in the paper On representation of temporal variability in electricity capacity planning models by Merrick 2016. The model additionally tests itself against previously calculated data to detect new errors.

Links

Citing CapacityExpansion

If you find CapacityExpansion usefuel in your work, we kindly request that you cite the following paper

@article{Kuepper2020,
  doi = {10.21105/joss.02034},
  url = {https://doi.org/10.21105/joss.02034},
  year = {2020},
  publisher = {The Open Journal},
  volume = {5},
  number = {52},
  pages = {2034},
  author = {Lucas Elias Kuepper and Holger Teichgraeber and Adam R. Brandt},
  title = {CapacityExpansion: A capacity expansion modeling framework in Julia},
  journal = {Journal of Open Source Software}
}

capacityexpansion.jl's People

Contributors

ali-ramadhan avatar holgerteichgraeber avatar youngfaithful avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

capacityexpansion.jl's Issues

Typo in README?

The README states

The main purpose of the package is providing an extensible, simple-to-use generation and transmission capacity extension model

Did you mean a capacity expansion model?

Sorry I'm not familiar with these models but wasn't sure if it was a typo as the package name is CapacityExpansion.jl. Maybe they are synonymous in which case please feel free to close this issue.

X-Ref: openjournals/joss-reviews#2034

Transmission: existing + no new transmission

@YoungFaithful
I would like to run a capacity expansion model with existing transmission, but not allow any newly build transmission. The documentation suggests the following (thanks for putting that in there!):

Include transmission=true and infrastructure = Dict{String,Array}("existing"=>[...,"transmission"], "limit"=>[...,"transmission"]) to model existing transmission and limit the total transmission TRANS to the values defined in the lines.csv file. If no new transmission should be setup, use the same values for existing transmission and the limit.

However, the following code seems to build new transmission beyond what is defined in lines.csv as power_ex:

region = "CA_14"
ts_input_data = load_timeseries_data_provided(region)
cep_data = load_cep_data_provided(region)
optimizer=Clp.Optimizer
ts_clust_result = run_clust(ts_input_data; method="kmeans", representation="centroid", n_init=5, n_clust=5)
ts_clust_data = ts_clust_result.clust_data
test_result = run_opt(ts_clust_data,cep_data,optimizer;descriptor="Test",transmission = true,infrastructure = Dict{String,Array}("existing"=>["demand","transmission"], "limit"=>["transmission"]),  limit_emission=Dict{String,Number}("CO2/electricity"=>1000));
test_result.variables["TRANS"]

Two questions:

  1. What am I missing when setting up the problem?
  2. I see that CA14 data does not have exisiting transmission defined (all 0). Do we have that data somewhere? Would love to play with that.

CA 14 data

When I am running the optimization with CA 14 data, I am getting the following error:

ERROR: LoadError: KeyError: key "solar-MX" not found

I see that TS/solar.csv does not have a column MX. Is there another file that should be used for CA14?

Remove explicit list of dependencies in README?

A list of dependencies in the README might give beginners to Julia the impression that they must install these dependencies themselves as virtually every Julia package does not list dependencies in the README. They are always handled automatically.

Perhaps a more useful way of listing dependencies is to point out that they are listed in the Project.toml file, which is automatically updated every time the dependencies change while the README must be edited manually.

X-Ref: openjournals/joss-reviews#2034

Upgrade DataFrames Version to 1.5.0

Currently, the "CapacityExpansion" repository is using an older version of the DataFrames library. I propose upgrading it to the latest stable release, version 1.5.0, to take advantage of the newest features and bug fixes.

Upgrading DataFrames to version 1.5.0 offers several benefits, including improved performance, enhanced compatibility with other libraries, and additional functionalities. This update will ensure that the project remains up-to-date with the latest developments in the DataFrames ecosystem.

Thank you for your attention to this matter

lost_emission_cost - documentation

@YoungFaithful:
In the documentation, is this a typo? should be greater than 1e6. In my previous modeling, I have this value at 700.

https://youngfaithful.github.io/CapacityExpansion.jl/dev/opt_cep/#Running-the-Capacity-Expansion-Problem-1

lost_emission_cost: Dictionary with numbers indicating the emission price/kg-emission (should be greater than 1e6), give Inf for no LE (Lost Emissions - a variable for emissions that will exceed the limit in order to provide the demand with the installed capacities)

JuMP v0.20

There is a JuMP version 0.20. I am getting compatibility errors when updating packages because it seems fixed to 0.19 by CapacityExpansion. Can we make it 0.19 and upwards?

Travis documentation builds failing

This is the error I'm seeing from https://travis-ci.com/github/YoungFaithful/CapacityExpansion.jl/jobs/346302482

$ julia --project=docs/ docs/make.jl
ERROR: LoadError: Unrecognised asset class unknown for `assets/clust_for_opt_text.svg`
Stacktrace:
 [1] error(::String) at ./error.jl:33
 [2] Documenter.Writers.HTMLWriter.HTMLAsset(::Symbol, ::String, ::Bool) at /home/travis/.julia/packages/Documenter/PLD7m/src/Writers/HTMLWriter.jl:81
 [3] #3 at /home/travis/.julia/packages/Documenter/PLD7m/src/Writers/HTMLWriter.jl:348 [inlined]
 [4] iterate at ./generator.jl:47 [inlined]
 [5] _collect(::Array{String,1}, ::Base.Generator{Array{String,1},getfield(Documenter.Writers.HTMLWriter, Symbol("##3#5"))}, ::Base.EltypeUnknown, ::Base.HasShape{1}) at ./array.jl:632
 [6] map at ./array.jl:561 [inlined]
 [7] #HTML#2 at /home/travis/.julia/packages/Documenter/PLD7m/src/Writers/HTMLWriter.jl:346 [inlined]
 [8] (::getfield(Core, Symbol("#kw#Type")))(::NamedTuple{(:assets,),Tuple{Array{String,1}}}, ::Type{Documenter.Writers.HTMLWriter.HTML}) at ./none:0
 [9] top-level scope at none:0
 [10] include at ./boot.jl:317 [inlined]
 [11] include_relative(::Module, ::String) at ./loading.jl:1044
 [12] include(::Module, ::String) at ./sysimg.jl:29
 [13] exec_options(::Base.JLOptions) at ./client.jl:266
 [14] _start() at ./client.jl:425

in expression starting at /home/travis/build/YoungFaithful/CapacityExpansion.jl/docs/make.jl:5

X-Ref: openjournals/joss-reviews#2034

Storage="simple", but no hydrogen

@YoungFaithful If I want to run a CEP for CA14, what is the simplest way to only run it with a battery, and not consider hydrogen storage. Can I delete the hydrogen entries from techs.yml, or what is the best way to accomplish this?

Storage: storage_type + conversion

What is the reason that the conversion parameter is exposed to the user? It seems to me that this is true if we model storage, and false if we don't model storage. In that case, I think it would be beneficial to not expose the parameter to the user, and just have it assigned somewhere under the hood.

Or am I missing some case where we want to actually play with the conversion parameter when running the optimization model?

get_cep_slack_variables error

region = "CA_14"
ts_input_data = load_timeseries_data_provided(region)
cep_data = load_cep_data_provided(region)
optimizer=Clp.Optimizer
ts_clust_result = run_clust(ts_input_data; method="kmeans", representation="centroid", n_init=5, n_clust=5)
ts_clust_data = ts_clust_result.clust_data
test_result = run_opt(ts_clust_data,cep_data,optimizer;descriptor="Test",transmission = true,infrastructure = Dict{String,Array}("existing"=>["demand","transmission"], "limit"=>["transmission"]),  limit_emission=Dict{String,Number}("CO2/electricity"=>1000));
test_result.variables["TRANS"]
get_cep_slack_variables(test_result)
type OptResult has no field descriptor

Stacktrace:
 [1] getproperty(::Any, ::Symbol) at ./sysimg.jl:18
 [2] macro expansion at ./logging.jl:319 [inlined]
 [3] get_cep_variables(::OptResult, ::String) at /home/holger/.julia/dev/CapacityExpansion/src/utils/utils.jl:54
 [4] get_cep_slack_variables(::OptResult) at /home/holger/.julia/dev/CapacityExpansion/src/utils/utils.jl:38
 [5] top-level scope at In[13]:1

This seems to be an error in get_cep_variables() in utils.jl, potentially here:

 if isempty(variables)
     throw(@error("$variable_type-Variable not provided in $(opt_result.descriptor)"))

Any thoughts on what happened? / was there a change in the most recent dev branch that we have to accomodate here?

Documentation/example enhancements

As I am trying to use CapacityExpansion, I'll make some notes here of things where better examples/documentation would help:

  • OptVariable, and how to use get_cep_variables() / get_cep_slack_variables() . It is not intuitively clear how to get the values from the fields. Also, what is SLACK? I assume it is just LL for every hour?
  • should sv["LL"].data and sv["LE"].data be floats instead of array{float}?
  • explain that they can be indexed, e.g. : sv["SLACK"]["el",1,1,"germany"] (this is currently not in the documentation of OptVariable)
  • add an example with co2_limit. Mention default in the documentatoin.
  • Explain the operations optimization function (that if you pass it config, it automatically takes some arguments. list which ones. In my use case, I got an error when I redefined co2_limit. That should happen and is great. Should just be documented.)
  • Mention that Gurobi is much faster than Clp and should be preferred if in an academic setting
  • show an example of how to configure gurobi in docs (e.g. outputflag=0)
  • run_opt documentation: for each option, state the default
  • transmission in run_opt(): Does this include transmission as variables? How do I set fixed transmission infrastructure (existing), but without transmission as a variable?
  • in run_opt(): if transmission=true, does that mean I allow transmission as a variable? and if transmission=false, I do not allow transmission as a variable? Does false mean that no energy exchange between different nodes can happen?

Setting initial battery storage level to 50%

@YoungFaithful
I'm trying to fix every day at an initial storage level of 50%. This is for the case of simple storage.

I am looking at the function below in opt.jl.

  • Limit the storage of the energy part of the battery to its installed power : Is this limiting the energy part of the battery to its installed power, or to its installed energy capacity (I would hope the latter)?
  • Is this the battery energy capacity: sum(cep.model[:CAP][tech, infrastruct, node] for infrastruct=set["infrastruct"]["all"])*scale[:CAP]/scale[:INTRASTOR] ? Why the sum over infrastruct, what are examples where it is summed over multiple infrastructs?
  • I'm thinking of replacing the right hand side of the third constraint by sum(cep.model[:CAP][tech, infrastruct, node] for infrastruct=set["infrastruct"]["all"])*scale[:CAP]/scale[:INTRASTOR] / 0.5. Anything I should be aware of with scaling?
function setup_opt_simplestorage!(cep::OptModelCEP,
                            ts_data::ClustData,
                            opt_data::OptDataCEP,
                            scale::Dict{Symbol,Int})
    ## DATA ##
    set=cep.set
    #`techs::OptVariable`: techs[tech][tech_group] - OptDataCEPTech
    techs = opt_data.techs

    ## INTRASTORAGE ##
    # Limit the storage of the energy part of the battery to its installed power
    push!(cep.info,"INTRASTOR[carrier,tech, t, k, node] ≤ Σ_{infrastruct} CAP[tech,infrastruct,node] ∀ node, tech_storage, t, k")
    @constraint(cep.model, [node=set["nodes"]["all"], tech=set["tech"]["storage"], t=set["time_T_period"]["all"], k=set["time_K"]["all"]], cep.model[:INTRASTOR][tech, techs[tech].input["carrier"], t,k,node]<=sum(cep.model[:CAP][tech, infrastruct, node] for infrastruct=set["infrastruct"]["all"])*scale[:CAP]/scale[:INTRASTOR])
    # Set storage level at beginning and end of day equal
    push!(cep.info,"INTRASTOR[carrier,tech, '0', k, node] = INTRASTOR[carrier,tech, 't[end]', k, node] ∀ node, tech_storage, k")
    @constraint(cep.model, [node=set["nodes"]["all"], tech=set["tech"]["storage"], k=set["time_K"]["all"]], cep.model[:INTRASTOR][tech, techs[tech].input["carrier"], 0, k, node]== cep.model[:INTRASTOR][tech,techs[tech].input["carrier"],set["time_T_point"]["all"][end],k,node])
    # Set the storage level at the beginning of each representative day to the same
    push!(cep.info,"INTRASTOR[carrier,tech, '0', k, node] = INTRASTOR[carrier,tech, '0', k, node] ∀ node, tech_storage, k")
    @constraint(cep.model, [node=set["nodes"]["all"], tech=set["tech"]["storage"], k=set["time_K"]["all"]], cep.model[:INTRASTOR][tech, techs[tech].input["carrier"], 0, k, node]== cep.model[:INTRASTOR][tech, techs[tech].input["carrier"], 0, 1, node])
    return cep
end

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.