diff --git a/docs/make.jl b/docs/make.jl index 536d7ca..b400249 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -9,7 +9,7 @@ makedocs(sitename="CapacityExpansion.jl", "Quickstart" => "quickstart.md", "Workflow" => "workflow.md", "Data" => ["preparing_clust_data.md", "preparing_opt_cep_data.md", "csv_structure.md", "README_GER_18.md", "README_GER_1.md", "README_CA_14.md", "README_CA_1.md", "README_TX_1.md"], - "Optimization" => ["opt_cep.md","opt_cep_examples.md"], + "Optimization" => ["opt_cep.md","results_opt.md", "opt_cep_examples.md"], ], format = Documenter.HTML(assets = [ "assets/clust_for_opt_text.svg", diff --git a/docs/src/README_CA_14.md b/docs/src/README_CA_14.md index 12083dc..a063028 100644 --- a/docs/src/README_CA_14.md +++ b/docs/src/README_CA_14.md @@ -1,5 +1,5 @@ # CA-14 -California (modeling CAISO) 14-node model, no existing capacity (currently not published) +California (modeling CAISO) 10-node model, no existing capacity (currently not published) ![Plot](assets/CA_14.svg) ## Time Series - `el_demand`: http://www.caiso.com/planning/Pages/ReliabilityRequirements/Default.aspx#Historical diff --git a/docs/src/assets/workflow.svg b/docs/src/assets/workflow.svg index a3d2c57..a3f109c 100644 --- a/docs/src/assets/workflow.svg +++ b/docs/src/assets/workflow.svg @@ -202,19 +202,19 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="0.92546231" - inkscape:cx="270.18722" - inkscape:cy="263.44901" + inkscape:zoom="1.6235842" + inkscape:cx="174.69367" + inkscape:cy="253.82562" inkscape:document-units="mm" - inkscape:current-layer="layer4" + inkscape:current-layer="g4874" showgrid="true" inkscape:snap-intersection-paths="true" fit-margin-top="1" fit-margin-left="1" fit-margin-right="1" fit-margin-bottom="1" - inkscape:window-width="1920" - inkscape:window-height="1055" + inkscape:window-width="1680" + inkscape:window-height="1025" inkscape:window-x="0" inkscape:window-y="0" inkscape:window-maximized="1" @@ -233,7 +233,7 @@ image/svg+xml - + @@ -377,7 +377,7 @@ style="fill:#000000;stroke:none;stroke-width:0.10000001" y="-0.15688452" x="44.0895" - sodipodi:role="line">run_clust().best_results + sodipodi:role="line">run_clust().clust_data diff --git a/docs/src/opt_cep.md b/docs/src/opt_cep.md index 1bbe28f..40b4e05 100644 --- a/docs/src/opt_cep.md +++ b/docs/src/opt_cep.md @@ -14,9 +14,14 @@ The model is designed to minimize social costs by minimizing the following objec min \sum_{account,tech}COST_{account,'EUR/USD',tech} + \sum LL \cdot cost_{LL} + LE \cdot cos_{LE} ``` -## Variables and Sets +## Sets The models scalability is relying on the usage of sets. The elements of the sets are extracted from the input data and scale the different variables. An overview of the sets is provided in the table. Depending on the models configuration the necessary sets are initialized. +The sets are setup as a dictionary and organized as `set[tech_name][tech_group]=[elements...]`, where: +- `tech_name` is the name of the dimension like e.g. `tech`, or `node` +- `tech_group` is the name of a group of elements within each dimension like e.g. `["all", "generation"]`. The group `'all'` always contains all elements of the dimension +- `[elements...]` is the Array with the different elements like `["pv", "wind", "gas"]` + | name | description | |------------------|-----------------------------------------------------------------------| | lines | transmission lines connecting the nodes | @@ -26,7 +31,6 @@ The models scalability is relying on the usage of sets. The elements of the sets | impact | impact categories like EUR or USD, CO 2 − eq., ... | | account | fixed costs for installation and yearly expenses, variable costs | | infrastruct | infrastructure status being either new or existing | -| sector | energy sector like electricity | | time K | numeration of the representative periods | | time T period | numeration of the time intervals within a period | | time T point | numeration of the time points within a period | @@ -34,22 +38,26 @@ The models scalability is relying on the usage of sets. The elements of the sets | time I point | numeration of the time points of the full input data periods | | dir transmission | direction of the flow uniform with or opposite to the lines direction | - - +## Variables +The variables can have different types: +- `cv`: cost variable - information of the costs +- `dv`: design variable - information of the energy system design +- `ov`: operation variable - information of the energy system operation +- `sv`: slack variable - information of unmet demands or exceeded emission limits An overview of the variables used in the CEP is provided in the table: -| name | dimensions | unit | description | -|-----------|----------------------------|-------------------------|--------------------------------------------------------------------------------------| -| COST | [account,impact,tech] | EUR/USD, LCA-categories | Costs | -| CAP | [tech,infrastruct,node] | MW | Capacity | -| GEN | [sector,tech,t,k,node] | MW | Generation | -| SLACK | [sector,t,k,node] | MW | Power gap, not provided by installed CAP | -| LL | [sector] | MWh | LoastLoad Generation gap, not provided by installed CAP | -| LE | [impact] | LCA-categories | LoastEmission Amount of emissions that installed CAP crosses the Emission constraint | -| INTRASTOR | [sector, tech,t,k,node] | MWh | Storage level within a period | -| INTERSTOR | [sector,tech,i,node] | MWh | Storage level between periods of the full time series | -| FLOW | [sector,dir,tech,t,k,line] | MW | Flow over transmission line | -| TRANS | [tech,infrastruct,lines] | MW | maximum capacity of transmission lines | +| name | type | dimensions | unit | description | +|---------|--|----------------------------|-------------------------|--------------------------------------------------------------------------------------| +| COST | `cv` | [account,impact,tech] | EUR/USD, LCA-categories | Costs | +| CAP | `dv` | [tech,infrastruct,node] | MW | Capacity | +| GEN | `ov` | [tech,carrier,t,k,node] | MW | Generation | +| SLACK | `sv` | [carrier,t,k,node] | MW | Power gap, not provided by installed CAP | +| LL | `sv` | [carrier] | MWh | LoastLoad Generation gap, not provided by installed CAP | +| LE | `sv` | [impact] | LCA-categories | LoastEmission Amount of emissions that installed CAP crosses the Emission constraint | +| INTRASTOR | `ov` | [tech,carrier,t,k,node] | MWh | Storage level within a period | +| INTERSTOR | `ov` | [tech,carrier,i,node] | MWh | Storage level between periods of the full time series | +| FLOW | `ov` | [tech,carrier,dir,t,k,line] | MW | Flow over transmission line | +| TRANS | `ov` | [tech,infrastruct,lines] | MW | maximum capacity of transmission lines | ## Running the Capacity Expansion Problem @@ -76,11 +84,17 @@ They can be applied in the following way: ```@docs run_opt ``` +## Transmission +A CapacityExpansion model can be run with or without the technology transmission. +!!! note + If the technology `transmission` is not modeled (`transmission=false`), the transmission between nodes is not restricted, which is equivalent to a copperplate assumption. +!!! note + 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. ## Solver The package provides no `optimizer` and a solver has to be added separately. For the linear optimization problem suggestions are: - `Clp` as an open source solver -- `Gurobi` as a proprietary solver with free academic licenses +- `Gurobi` as a proprietary solver with free academic licenses. Gurobi is faster than Clp and we prefer it in the academic setting. - `CPLEX` as an alternative proprietary solver Install the corresponding julia-package for the solver and call its `optimizer` like e.g.: @@ -91,6 +105,15 @@ using Clp optimizer=Clp.Optimizer ``` +## Solver Configuration +Depending on the Solver different solver configurations are possible. The information is always provided as `Dict{Symbol,Any}`. The keys of the dictionary are the parameters and the values of the dictionary are the values passed to the solver. + +For example the `Gurobi` solver can be configured to have no OutputFlag and run on two threads (per julia thread) the following way: +```julia +optimizer_config=Dict{Symbol,Any}(:OutputFlag => 0, :Threads => 2) +``` +Further information on possible keys for Gurobi can be found at [Gurobi parameter description](https://www.gurobi.com/documentation/8.1/refman/parameter_descriptions.html). + ## Scaling The package features the scaling of variables and equations. Scaling variables, which are used in the numerical model, to `0.01 ≤ x ≤ 100` and scaling equations to `3⋅x = 1` instead of `3000⋅x = 1000` improves the shape of the optimization space and significantly reduces the computational time used to solve the numerical model. @@ -117,26 +140,3 @@ scale_result = run_opt(ts_clust_data,cep_data,optimizer;scale=scale) - Include the new variable in the problem formulation in the `src/optim_problems/opt_cep`-file. Reformulate the equations by dividing them by the scaling parameter of the first variable, which is `scale[:COST]` in the following example: ` scale[:COST]⋅COST = 10⋅scale[:CAP]⋅CAP + 100` `⇔ COST = 10⋅(scale[:CAP]/scale[:COST])⋅CAP + 100/scale[:COST]` - -## Opt Result - A closer look -```@docs -OptResult -``` -!!! note - The model tracks how it is setup and which equations are used. This can help you to understand the models exact configuration without looking up the source code. - -The information of the model setup can be checked out the following way: -```@setup 3 -using CapacityExpansion -using Clp -optimizer=Clp.Optimizer -state="GER_1" -years=[2016] -ts_input_data = load_timeseries_data_provided(state;T=24, years=years) -cep_data = load_cep_data_provided(state) -ts_clust_data = run_clust(ts_input_data;method="kmeans",representation="centroid",n_init=10,n_clust=5).best_results -``` -```@example 3 -result = run_opt(ts_clust_data,cep_data,optimizer;descriptor="Model Name") -println.(result.opt_info["model"]) -``` diff --git a/docs/src/opt_cep_examples.md b/docs/src/opt_cep_examples.md index ffc8f15..735b689 100644 --- a/docs/src/opt_cep_examples.md +++ b/docs/src/opt_cep_examples.md @@ -38,13 +38,6 @@ design_variables=get_cep_design_variables(design_result) # Use the design variable results for the operational (dispatch problem) run operation_result = run_opt(ts_input_data,cep_data,design_result.opt_config,design_variables,optimizer;lost_load_cost=Dict{String,Number}("electricity"=>1e6), lost_emission_cost=Dict{String,Number}("CO2"=>700)) ``` -## Get Functions -The get functions allow an easy access to the information included in the result. -```@docs -get_cep_variable_set -get_cep_slack_variables -get_cep_design_variables -``` ## Plotting Capacities ```julia co2_result = run_opt(ts_clust_data,cep_data,optimizer;descriptor="co2",limit_emission=Dict{String,Number}("CO2/electricity"=>500)) #hide diff --git a/docs/src/results_opt.md b/docs/src/results_opt.md new file mode 100644 index 0000000..66627ce --- /dev/null +++ b/docs/src/results_opt.md @@ -0,0 +1,39 @@ +#Result +Here, we describe the optimization result. + +## Types +The optimization results are provided in an `OptResult` struct: +```@docs +OptResult +``` +## Equations +!!! note + The model tracks how it is setup and which equations are used. This can help you to understand the models exact configuration without looking up the source code. + +The information of the model setup can be checked out the following way: +```@setup 3 +using CapacityExpansion +using Clp +optimizer=Clp.Optimizer +state="GER_1" +years=[2016] +ts_input_data = load_timeseries_data_provided(state;T=24, years=years) +cep_data = load_cep_data_provided(state) +ts_clust_data = run_clust(ts_input_data;method="kmeans",representation="centroid",n_init=10,n_clust=5).best_results +``` +```@example 3 +result = run_opt(ts_clust_data,cep_data,optimizer;descriptor="Model Name") +println.(result.opt_info["model"]) +``` +## Variables in Result +All variables are provided as dense `OptVariable` structs and can be indexed: +```@docs +OptVariable +``` +The variables can be of different type as explained in [Variables](@ref). The different groups of variables can be extracted from the `OptResult` based on the `variable_type`: +```@docs +get_cep_variables +get_cep_slack_variables +get_cep_design_variables +``` +The extraction of design variables is e.g. necessary for a [Second stage operational validation step](@ref), which validates the energy system design on a different time series. diff --git a/src/CapacityExpansion.jl b/src/CapacityExpansion.jl index 592ea5c..6262809 100644 --- a/src/CapacityExpansion.jl +++ b/src/CapacityExpansion.jl @@ -27,11 +27,9 @@ module CapacityExpansion load_cep_data, load_cep_data_provided, load_timeseries_data_provided, - get_cep_variable_value, - get_cep_variable_set, + get_cep_variables, get_cep_slack_variables, - get_cep_design_variables, - get_total_demand + get_cep_design_variables include(joinpath("utils","datastructs.jl")) include(joinpath("utils","optvariable.jl")) diff --git a/src/optim_problems/run_opt.jl b/src/optim_problems/run_opt.jl index a24193b..b465a9c 100644 --- a/src/optim_problems/run_opt.jl +++ b/src/optim_problems/run_opt.jl @@ -103,7 +103,7 @@ function run_opt(ts_data::ClustData, fixed_design_variables::Dict{String,Any}, optimizer::DataType; lost_load_cost::Dict{String,Number}=Dict{String,Number}(), - lost_emission_cost::Dict{String,Number}=Dict{String,Number}(),) + lost_emission_cost::Dict{String,Number}=Dict{String,Number}()) # Add the fixed_design_variables and new setting for slack costs to the existing config set_opt_config_cep!(opt_config;fixed_design_variables=fixed_design_variables, lost_load_cost=lost_load_cost, lost_emission_cost=lost_emission_cost) diff --git a/src/utils/datastructs.jl b/src/utils/datastructs.jl index 8d79826..f6a1c23 100644 --- a/src/utils/datastructs.jl +++ b/src/utils/datastructs.jl @@ -3,9 +3,10 @@ abstract type OptData <: InputData end """ OptModelCEP --model::JuMP.Model --info::Array{String} --set::Dict{String,Array} +The essential elements of a CapacityExpansionProblem are organized as a `OptModelCEP` struct: +- `model`::JuMP.Model - contains the actual JuMP-Model +- `info`::Array{String} - contains the information about the model setup in form of multiple lines of equations +- `set`::Dict{String,Array} - contains the sets used by the model """ struct OptModelCEP model::JuMP.Model @@ -14,11 +15,19 @@ struct OptModelCEP end """ - OptVariable --`data::Array` - includes the optimization variable output in form of an array --`axes_names::Array{String,1}`` - includes the names of the different axes and is equivalent to the sets in the optimization formulation --`axes::Tuple` - includes the values of the different axes of the optimization variables --`type::String` - defines the type of the variable being cv - cost variable - dv -design variable - ov - operating variable - sv - slack variable + OptVariable{T,N,Ax,L<:NTuple{N,Dict}} <: AbstractArray{T,N}{ + data::Array{T,N}, + axes::Ax, + lookup::L, + axes_names::Array{String,1}} + type::String +OptVariable is a structure that allows to have a multi-dimensional `data`-Array that can be indexed using keys. An examplary lookup can be done the following way: `optvar['key1','key2']=value`. +The value can be of any type like e.g. `Float64`. +The OptVariable is used both for data input and output. +- `data::Array` - includes the optimization variable output in form of an array +- `axes_names::Array{String,1}`` - includes the names of the different axes and is equivalent to the sets in the optimization formulation +- `axes::Tuple` - includes the values of the different axes of the optimization variables +- `type::String` - defines the type of the variable being cv - cost variable - dv -design variable - ov - operating variable - sv - slack variable """ struct OptVariable{T,N,Ax,L<:NTuple{N,Dict}} <: AbstractArray{T,N} data::Array{T,N} @@ -29,10 +38,16 @@ struct OptVariable{T,N,Ax,L<:NTuple{N,Dict}} <: AbstractArray{T,N} end """ - OptResult{status::Symbol,objective::Float64,variables::Dict{String,Any},sets::Dict{String,Array},opt_config::Dict{String,Any},opt_info::Dict{String,Any}} + OptResult{status::Symbol, + objective::Float64, + variables::Dict{String,Any}, + sets::Dict{String,Array}, + opt_config::Dict{String,Any}, + opt_info::Dict{String,Any}} +The result of an optimized model is organized as an `OptResult` struct: - `status`: Symbol about the solution status of the model in normal cases `:OPTIMAL` - `objective`: Value of the objective function -- `variables`: Dictionary with each OptVariable as an entry +- `variables`: Dictionary with each variables in form of `OptVariable` structs as entries. For details on indexing the `OptVariables` see the `OptVariable` documentation - `sets`: Dictionary with each set as an entry - `opt_config`: The configuration of the model setup - for more detail see tye `run_opt` documentation that sets the `opt_config` up - `opt_info`: Holds information about the model. E.g. `opt_info["model"]` contains the exact equations used in the model. @@ -47,13 +62,17 @@ struct OptResult end """ - OptDataCEP{region::String, costs::OptVariable, techs::OptVariable, nodes::OptVariable, lines::OptVariabl} <: OptData + OptDataCEP{region::String, + costs::OptVariable, + techs::OptVariable, + nodes::OptVariable, + lines::OptVariabl} <: OptData +All not timeseries depending data for the CapacityExpansionProblem is stored in an `OptDataCEP` struct. `OptVariable` structs are used to index an element of e.g. `.costs['pv','germany',2016,'var','EUR']=value`. Depending on the field the value has another type like `Number`, `OptDataCEPLine`,... - `region::String`: name of state or region data belongs to -- `costs::OptVariable`: costs[tech,node,year,account,impact] - Number -- `techs::OptVariable`: techs[tech] - OptDataCEPTech -- `nodes::OptVariable`: nodes[tech, node] - OptDataCEPNode -- `lines::OptVarible`: lines[tech, line] - OptDataCEPLine -instead of USD you can also use your favorite currency like EUR +- `costs::OptVariable`: costs[tech,node,year,account,impact] - `Number` +- `techs::OptVariable`: techs[tech] - `OptDataCEPTech` +- `nodes::OptVariable`: nodes[tech, node] - `OptDataCEPNode` +- `lines::OptVarible`: lines[tech, line] - `OptDataCEPLine` """ struct OptDataCEP <: OptData region::String @@ -83,7 +102,11 @@ Base.show(io::IO, ll::LatLon) = print(io, "LatLon(lat=$(ll.lat)°, lon=$(ll.lon) Base.isapprox(ll1::LatLon, ll2::LatLon; atol = 1e-6, kwargs...) = isapprox(ll1.lat, ll2.lat; atol = 180*atol/6.371e6, kwargs...) & isapprox(ll1.lon, ll2.lon; atol = 180*atol/6.371e6, kwargs...) # atol in metres (1μm) """ - OptDataCEPNode{name::String,value::Number,lat::Number,lon::Number} <: OptData + OptDataCEPNode{name::String, + value::Number, + lat::Number, + lon::Number} <: OptData +The information about the nodes in stored in an `OptDataCEPNode` struct: - `name` - `power_ex` existing capacity [MW or MWh (tech_e)] - `power_lim` capacity limit [MW or MWh (tech_e)] @@ -99,8 +122,17 @@ struct OptDataCEPNode <: OptData end """ - OptDataCEPLine{name::String,node_start::String,node_end::String,reactance::Number,resistance::Number,power::Number,circuits::Int,voltage::Number,length::Number} <: OptData -- `name` + OptDataCEPLine{name::String, + node_start::String, + node_end::String, + reactance::Number, + resistance::Number, + power::Number, + circuits::Int, + voltage::Number, + length::Number} <: OptData +The information of the single lines is stored in an `OptDataCEPLine` struct: +- `name`: Name of the line - `node_start` Node where line starts - `node_end` Node where line ends - `reactance` @@ -127,16 +159,29 @@ struct OptDataCEPLine <: OptData end """ - OptDataCEPTech{name::String,categ::String,sector::String,eff::Number,time_series::String,lifetime::Number,financial_lifetime::Number,discount_rate::Number, annuityfactor::Number} <: OptData -- `name` -- `categ`: the category of this technology (is it storage, transmission or generation) -- `sector`: sector of the technology (electricity or heat) -- `eff`: efficiency of this technologies conversion [-] -- `time_series`: time_series name for availability -- `lifetime`: product lifetime [a] + OptDataCEPTech{name::String + tech_group::Array{String,1} + unit::String + structure::String + plant_lifetime::Number + financial_lifetime::Number + discount_rate::Number + annuityfactor::Number + input::Dict + output::Dict + constraints::Dict} <: OptData +The information of the single tech is stored in an `OptDataCEPTech` struct: +- `name`: A detailed name of the technology +- `tech_group`: technology-groups that the technology belongs to. Groups can be: `all`, `demand`, `generation`, `dispatchable_generation`, `non_dispatchable_generation`, `storage`, `conversion`, `transmission` +- `plant_lifetime`: the lifetime of this technologies plant [a] - `financial_lifetime`: financial time to break even [a] +- `annuityfactor`: the annuityfactor is calculated based on the discount_rate and the plant_lifetime - `discount_rate`: discount rate for technology [a] -- `annuityfactor`: annuity factor, important for cap-costs [-] +- `structure`: `node` or `line` depending on the structure of the technology +- `unit`: the unit that the capacity of the technology scales with. It can be `power`[MW] or `energy`[MWh] +- `input`: the input can be a `carrier` like e.g. electricity `"carrier" => electricity, a `timeseries` like e.g. `"timeseries"=> demand_electricity`, or a `fuel` like e.g. `fuel: gas` +- `constraints`: a dictionary with information like an `efficiency` like e.g. `"efficiency"=> 0.53` or `cap_eq` (e.g. discharge capacity is same as charge capacity) `"cap_eq" => "bat_in"` +returns `techs::OptVariable` techs[tech] - OptDataCEPTech """ struct OptDataCEPTech <: OptData name::String @@ -153,21 +198,10 @@ struct OptDataCEPTech <: OptData end """ - is_in(k::Symbol,table::DataFrame,alt_value::Any) -is Symbol `k` in `table`? Lookup value if true, return `alt_value` if false -""" -function is_in(k::Symbol,table::DataFrame,alt_value::Any) - if k in names(table) - return table[k][1] - else - @warn "$k not provided in $(repr(table))" - return alt_value - end -end - - -""" - Scenario{descriptor::String,clust_res::AbstractClustResult,opt_res::OptResult} + Scenario{descriptor::String, + clust_res::AbstractClustResult, + opt_res::OptResult} +A scenario is organized in a `Scenario` struct: -`descriptor::String` -`clust_res::AbstractClustResult` -`opt_res::OptResult` diff --git a/src/utils/optvariable.jl b/src/utils/optvariable.jl index d48f752..ddb71a3 100644 --- a/src/utils/optvariable.jl +++ b/src/utils/optvariable.jl @@ -92,16 +92,16 @@ match `size(data)` in the corresponding dimensions. # Example ```jldoctest -julia> array = OptVariable([1 2; 3 4], [:a, :b], 2:3) -2-dimensional OptVariable{Int,2,...} with index sets: - Dimension 1, Symbol[:a, :b] - Dimension 2, 2:3 -And data, a 2×2 Array{Int,2}: +julia> cap = OptVariable([1 2; 3 4],["pv", "wind"], 1:2; axes_names=["tech","time"],type="dv") +2-dimensional OptVariable{Int64,2,...} of type dv with index sets: + Dimension 1 - tech, ["pv", "wind"] + Dimension 2 - time, 1:2 +And data, a 2×2 Array{Int64,2}: 1 2 3 4 -julia> array[:b, 3] -4 +julia> cap["pv", 2] +2 ``` """ function OptVariable(data::Array{T,N}, axs...;axes_names::Array=repeat([""],N), type="") where {T,N} @@ -117,29 +117,29 @@ given axes. # Example ```jldoctest -julia> array = OptVariable{Float}(undef, [:a, :b], 1:2); +julia> cap = OptVariable{Float64}(undef,["pv", "wind"], 1:2; axes_names=["tech","time"],type="dv"); -julia> fill!(array, 1.0) -2-dimensional OptVariable{Float64,2,...} with index sets: - Dimension 1, Symbol[:a, :b] - Dimension 2, 1:2 +julia> fill!(cap, 1.0) +2-dimensional OptVariable{Float64,2,...} of type dv with index sets: + Dimension 1 - tech, ["pv", "wind"] + Dimension 2 - time, 1:2 And data, a 2×2 Array{Float64,2}: 1.0 1.0 1.0 1.0 -julia> array[:a, 2] = 5.0 +julia> cap["wind", 2] = 5.0 5.0 -julia> array[:a, 2] +julia> cap["wind", 2] 5.0 -julia> array -2-dimensional OptVariable{Float64,2,...} with index sets: - Dimension 1, Symbol[:a, :b] - Dimension 2, 1:2 +julia> cap +2-dimensional OptVariable{Float64,2,...} of type dv with index sets: + Dimension 1 - tech, ["pv", "wind"] + Dimension 2 - time, 1:2 And data, a 2×2 Array{Float64,2}: - 1.0 5.0 1.0 1.0 + 1.0 5.0 ``` """ function OptVariable{T}(::UndefInitializer, axs...; axes_names::Array{String,1}=repeat([""],length(axs)), type="") where T diff --git a/src/utils/utils.jl b/src/utils/utils.jl index e384f82..716b798 100644 --- a/src/utils/utils.jl +++ b/src/utils/utils.jl @@ -1,39 +1,3 @@ -""" - find_val_in_df(df::DataFrame,column_of_reference::Symbol,reference::String,value_to_return::Symbol) -Take DataFrame(df) Look in Column (column_of_reference) for the reference value (reference) and return in same row the value in column (value_to_return) -""" -function find_val_in_df(df::DataFrame, - column_of_reference::Symbol, - reference::String, - value_to_return::Symbol - ) - @warn "find_val_in_df deprecated" - return df[findfirst(df[column_of_reference].==reference),value_to_return] -end - -""" - find_val_in_df(df::DataFrame,column_of_reference::Symbol,reference::String,value_to_return::String) -Take DataFrame(df) Look in Column (column_of_reference) for the reference value (reference) and return corresponding value in column (value_to_return) -""" -function find_val_in_df(df::DataFrame, - column_of_reference::Symbol, - reference::String, - value_to_return::String - ) - @warn "find_val_in_df deprecated" - return find_val_in_df(df,column_of_reference,reference,Symbol(value_to_return)) -end - -#Use getindex to return all rows of the DataFrame fulfilling that in column `col` value `val` is found -function Base.getindex(df::DataFrame, col_and_val::Tuple{Symbol,Any}) - return df[findall(df[col_and_val[1]].==col_and_val[2]), :] -end - -#Use getindex to return all rows of the DataFrame fulfilling that in column `col` value `val` is found and the column `colon_ind` -function Base.getindex(df::DataFrame, col_and_val::Tuple{Symbol,Any}, colon_ind::Symbol) - return df[findall(df[col_and_val[1]].==col_and_val[2]), colon_ind] -end - """ check_column(df::DataFrame, names_array::Array{Symbol,1}) check if the columns provided in `names_array` exist in the DataFrame `df` @@ -46,78 +10,14 @@ function check_column(df::DataFrame, names_array::Array{Symbol,1}) end end -""" - map_set_in_df(df::DataFrame,column_of_reference::Symbol,reference::String,set_to_return::Symbol) - Take DataFrame(`df`) Look in Column (`column_of_reference`) for all cases that match the reference value (`reference`) and return the corresponding sets in Column (`set_to_return`) -""" -function map_set_in_df(df::DataFrame, - column_of_reference::Symbol, - reference::String, - set_to_return::Symbol - ) - @warn "mat_set_in_df deprecated" - return df[df[column_of_reference].==reference,set_to_return] -end - -""" - getindex(variable::OptVariable,index_set::Array) -Get the variable data from the specific Scenario by indicating the `var_name` e.g. "COST" and the `index_set` like `[:;"EUR";"pv"]` -""" -function get_cep_variable_value(variable::OptVariable, - index_set::Array - ) - @warn "get_cep_variable_value deprecated" - index_num=[] - for i in 1:length(index_set) - if index_set[i]==Colon() - push!(index_num,Colon()) - elseif typeof(index_set[i])==Int || typeof(index_set[i])==UnitRange{Int} - push!(index_num,index_set[i]) - else - new_index_num=findfirst(variable.axes[i].==index_set[i]) - if new_index_num==[] - throw(@error("$(index_set[i]) not in indexset #$i of Variable $var_name")) - else - push!(index_num,new_index_num) - end - end - end - return getindex(variable.data,Tuple(index_num)...) -end - -""" - get_cep_variable_value(scenario::Scenario,var_name::String,index_set::Array) -Get the variable data from the specific Scenario by indicating the `var_name` e.g. "COST" and the `index_set` like `[:;"EUR";"pv"]` -""" -function get_cep_variable_value(scenario::Scenario, - var_name::String, - index_set::Array - ) - @warn "get_cep_variable_value deprecated" - return get_cep_variable_value(scenario.opt_res.variables[var_name], index_set) -end - -""" - get_cep_variable_set(variable::OptVariable,num_index_set::Int) -Get the variable set from the specific variable and the `num_index_set` like 1 -""" -function get_cep_variable_set(variable::OptVariable, - num_index_set::Int - ) - @warn "get_cep_variable_set deprecated" - return variable.axes[num_index_set] +#Use getindex to return all rows of the DataFrame fulfilling that in column `col` value `val` is found +function Base.getindex(df::DataFrame, col_and_val::Tuple{Symbol,Any}) + return df[findall(df[!,col_and_val[1]].==col_and_val[2]), :] end -""" - get_cep_variable_set(scenario::Scenario,var_name::String,num_index_set::Int) -Get the variable set from the specific Scenario by indicating the `var_name` e.g. "COST" and the `num_index_set` like 1 -""" -function get_cep_variable_set(scenario::Scenario, - var_name::String, - num_index_set::Int - ) - @warn "get_cep_variable_set deprecated" - return get_cep_variable_set(scenario.opt_res.variables[var_name], num_index_set) +#Use getindex to return all rows of the DataFrame fulfilling that in column `col` value `val` is found and the column `colon_ind` +function Base.getindex(df::DataFrame, col_and_val::Tuple{Symbol,Any}, colon_ind::Symbol) + return df[findall(df[!,col_and_val[1]].==col_and_val[2]), colon_ind] end """ @@ -140,7 +40,8 @@ end """ get_cep_variables(opt_result::OptResult, variable_type::String) -Returns all variables which types match the String of `variable_type` +The variables can be of different type. The different groups of variables can be extracted from the `OptResult` based on the `variable_type`: +Returns all variables which types match the String `variable_type` """ function get_cep_variables(opt_result::OptResult, variable_type::String) variables=Dict{String,Any}() @@ -174,7 +75,7 @@ Returning Dictionary with the variables as entries function set_opt_config_cep(opt_data::OptDataCEP ;kwargs...) # Create new Dictionary and set possible unique tech_groups to false to later check wrong setting - config=Dict{String,Any}("demand"=>false, "transmission"=>false, "storage"=>false, "conversion"=>false, "generation"=>false, "non_dispatchable_generation"=>false, "dispatchable_generation"=>false) + config=Dict{String,Any}("demand"=>false, "transmission"=>false, "storage"=>false, "conversion"=>false, "non_dispatchable_generation"=>false, "dispatchable_generation"=>false) # Check the existence of the tech_group (like generation or storage - see techs.yml) and write it into Dictionary for tech_group in unique(vcat(getfield.(opt_data.techs[:], :tech_group)...)) config[tech_group]=true