diff --git a/benchmark/EU/assets-base-periods-partitions.csv b/benchmark/EU/assets-timeframe-partitions.csv similarity index 100% rename from benchmark/EU/assets-base-periods-partitions.csv rename to benchmark/EU/assets-timeframe-partitions.csv diff --git a/benchmark/EU/assets-base-periods-profiles.csv b/benchmark/EU/assets-timeframe-profiles.csv similarity index 100% rename from benchmark/EU/assets-base-periods-profiles.csv rename to benchmark/EU/assets-timeframe-profiles.csv diff --git a/benchmark/EU/flows-base-periods-partitions.csv b/benchmark/EU/flows-timeframe-partitions.csv similarity index 100% rename from benchmark/EU/flows-base-periods-partitions.csv rename to benchmark/EU/flows-timeframe-partitions.csv diff --git a/benchmark/EU/flows-base-periods-profiles.csv b/benchmark/EU/flows-timeframe-profiles.csv similarity index 100% rename from benchmark/EU/flows-base-periods-profiles.csv rename to benchmark/EU/flows-timeframe-profiles.csv diff --git a/benchmark/EU/profiles-rep-periods-availability.csv b/benchmark/EU/profiles-rep-periods-availability.csv index 263cbc05..2a64e2f6 100644 --- a/benchmark/EU/profiles-rep-periods-availability.csv +++ b/benchmark/EU/profiles-rep-periods-availability.csv @@ -1,5 +1,5 @@ ,,,p.u. -profile_name,rep_period,time_step,value +profile_name,rep_period,timestep,value NL_Wind_Onshore,1,1,0.007717831 NL_Wind_Onshore,1,2,0.006234769 NL_Wind_Onshore,1,3,0.007409822 diff --git a/benchmark/EU/profiles-rep-periods-demand.csv b/benchmark/EU/profiles-rep-periods-demand.csv index b666b0b8..df257b42 100644 --- a/benchmark/EU/profiles-rep-periods-demand.csv +++ b/benchmark/EU/profiles-rep-periods-demand.csv @@ -1,5 +1,5 @@ ,,,p.u. -profile_name,rep_period,time_step,value +profile_name,rep_period,timestep,value NL_E_Demand,1,1,0.68144623 NL_E_Demand,1,2,0.666893812 NL_E_Demand,1,3,0.656786995 diff --git a/benchmark/EU/profiles-rep-periods-inflows.csv b/benchmark/EU/profiles-rep-periods-inflows.csv index 90d609c4..2a399a43 100644 --- a/benchmark/EU/profiles-rep-periods-inflows.csv +++ b/benchmark/EU/profiles-rep-periods-inflows.csv @@ -1,5 +1,5 @@ ,,,p.u. -profile_name,rep_period,time_step,value +profile_name,rep_period,timestep,value BE_Hydro,1,1,0.4007930950734051 BE_Hydro,1,2,0.4007930950734051 BE_Hydro,1,3,0.4007930950734051 diff --git a/benchmark/EU/rep-periods-data.csv b/benchmark/EU/rep-periods-data.csv index 2faf1275..9da88c55 100644 --- a/benchmark/EU/rep-periods-data.csv +++ b/benchmark/EU/rep-periods-data.csv @@ -1,3 +1,3 @@ ,hours,,hours -id,weight,num_time_steps,resolution +id,weight,num_timesteps,resolution 1,1,8760,1.0 diff --git a/benchmark/profiling.jl b/benchmark/profiling.jl index 131c9707..ed1d1e7e 100644 --- a/benchmark/profiling.jl +++ b/benchmark/profiling.jl @@ -36,7 +36,7 @@ end #%% -@time graph, representative_periods, base_periods = +@time graph, representative_periods, timeframe = create_graph_and_representative_periods_from_csv_folder(input_dir); @benchmark create_graph_and_representative_periods_from_csv_folder($input_dir) # @profview create_graph_and_representative_periods_from_csv_folder(input_dir); @@ -50,17 +50,17 @@ end #%% @time dataframes = - construct_dataframes(graph, representative_periods, constraints_partitions, base_periods) + construct_dataframes(graph, representative_periods, constraints_partitions, timeframe) @benchmark construct_dataframes( $graph, $representative_periods, $constraints_partitions, - $base_periods, + $timeframe, ) -# @profview construct_dataframes($graph, $representative_periods, $constraints_partitions, $base_periods) +# @profview construct_dataframes($graph, $representative_periods, $constraints_partitions, $timeframe) #%% -@time model = create_model(graph, representative_periods, dataframes, base_periods); -@benchmark create_model($graph, $representative_periods, $dataframes, $base_periods) -# @profview create_model(graph, representative_periods, dataframes, base_periods); +@time model = create_model(graph, representative_periods, dataframes, timeframe); +@benchmark create_model($graph, $representative_periods, $dataframes, $timeframe) +# @profview create_model(graph, representative_periods, dataframes, timeframe); diff --git a/docs/src/how-to-use.md b/docs/src/how-to-use.md index 55695f50..2e6ed564 100644 --- a/docs/src/how-to-use.md +++ b/docs/src/how-to-use.md @@ -68,15 +68,15 @@ The `Missing` data meaning depends on the parameter, for instance: - `investment_limit`: There is no investment limit. -#### `assets-base-periods-profiles.csv` and `assets-rep-periods-profiles.csv` +#### `assets-timeframe-profiles.csv` and `assets-rep-periods-profiles.csv` -These files contain the reference to profiles for each asset at each base period step, or at each representative period. +These files contain the reference to profiles for each asset at each period, or at each representative period. #### `flows-rep-periods-profiles.csv` Similar to their `asset` counterpart. -#### `profiles-base-periods-.csv` and `profiles-rep-periods-.csv` +#### `profiles-timeframe-.csv` and `profiles-rep-periods-.csv` For each `type` defined in either `assets-*-periods-profiles` or `flows-rep-periods-profiles`, one of these files must exist. They store the profile data as indexed by a profile name. @@ -106,9 +106,9 @@ The table below shows various results for different formats for a representative Similar to `assets-rep-periods-partitions.csv`, but for flows. -#### `assets-base-periods-partitions.csv` +#### `assets-timeframe-partitions.csv` -Similar to their `rep-periods` counterpart, but for the base periods. +Similar to their `rep-periods` counterpart, but for the timeframe. #### `rep-periods-data.csv` @@ -147,7 +147,7 @@ It hides the complexity behind the energy problem, making the usage more friendl - `graph`: The [Graph](@ref) object that defines the geometry of the energy problem. - `representative_periods`: A vector of [Representative Periods](@ref representative-periods). - `constraints_partitions`: Dictionaries that connect pairs of asset and representative periods to [time partitions (vectors of time blocks)](@ref Partition). -- `base_periods`: The number of periods of the `representative_periods`. +- `timeframe`: The number of periods of the `representative_periods`. - `dataframes`: The data frames used to linearize the variables and constraints. These are used internally in the model only. - `model`: A JuMP.Model object representing the optimization model. - `solved`: A boolean indicating whether the `model` has been solved or not. @@ -161,7 +161,7 @@ It hides the complexity behind the energy problem, making the usage more friendl The `EnergyProblem` can also be constructed using the minimal constructor below. -- `EnergyProblem(graph, representative_periods, base_periods)`: Constructs a new `EnergyProblem` object with the given graph, representative periods, and base periods. The `constraints_partitions` field is computed from the `representative_periods`, and the other fields are initialized with default values. +- `EnergyProblem(graph, representative_periods, timeframe)`: Constructs a new `EnergyProblem` object with the given graph, representative periods, and timeframe. The `constraints_partitions` field is computed from the `representative_periods`, and the other fields are initialized with default values. See the [basic example tutorial](@ref basic-example) to see how these can be used. @@ -227,9 +227,9 @@ The solution object is a NamedTuple with the following fields: - `objective_value`: A Float64 with the objective value at the solution. - `assets_investment[a]`: The investment for each asset, indexed on the investable asset `a`. - `flows_investment[u, v]`: The investment for each flow, indexed on the investable flow `(u, v)`. -- `flow[(u, v), rp, time_block]`: The flow value for a given flow `(u, v)` at a given representative period `rp`, and time block `time_block`. The list of time blocks is defined by `graph[(u, v)].partitions[rp]`. -- `storage_level_intra_rp[a, rp, time_block]`: The storage level for the storage asset `a` within (intra) a representative period `rp` and a time block `time_block`. The list of time blocks is defined by `constraints_partitions`, which was used to create the model. -- `storage_level_inter_rp[a, bp]`: The storage level for the storage asset `a` between (inter) representative periods in the base periods `bp`. +- `flow[(u, v), rp, timesteps_block]`: The flow value for a given flow `(u, v)` at a given representative period `rp`, and time block `timesteps_block`. The list of time blocks is defined by `graph[(u, v)].partitions[rp]`. +- `storage_level_intra_rp[a, rp, timesteps_block]`: The storage level for the storage asset `a` within (intra) a representative period `rp` and a time block `timesteps_block`. The list of time blocks is defined by `constraints_partitions`, which was used to create the model. +- `storage_level_inter_rp[a, pb]`: The storage level for the storage asset `a` between (inter) representative periods in the periods block `pb`. For tips on manipulating the solution, check the [tutorial](@ref solution-tutorial). diff --git a/docs/src/tutorial.md b/docs/src/tutorial.md index cc062d2f..53596e22 100644 --- a/docs/src/tutorial.md +++ b/docs/src/tutorial.md @@ -84,7 +84,7 @@ using TulipaEnergyModel input_dir = "../../test/inputs/Tiny" # hide # input_dir should be the path to Tiny -graph, representative_periods, base_periods = create_graph_and_representative_periods_from_csv_folder(input_dir) +graph, representative_periods, timeframe = create_graph_and_representative_periods_from_csv_folder(input_dir) ``` To create the model we also need a time partition for the constraints. @@ -99,13 +99,13 @@ The `constraints_partitions` has two dictionaries with the keys `:lowest_resolut Finally, we also need dataframes that store the linearized indexes of the variables. ```@example manual -dataframes = construct_dataframes(graph, representative_periods, constraints_partitions, base_periods) +dataframes = construct_dataframes(graph, representative_periods, constraints_partitions, timeframe) ``` Now we can compute the model. ```@example manual -model = create_model(graph, representative_periods, dataframes, base_periods) +model = create_model(graph, representative_periods, dataframes, timeframe) ``` Finally, we can compute the solution. @@ -343,7 +343,7 @@ df = filter( energy_problem.dataframes[:flows], view = true, ) -[energy_problem.graph[u, v].flow[(rp, row.time_block)] for row in eachrow(df)] +[energy_problem.graph[u, v].flow[(rp, row.timesteps_block)] for row in eachrow(df)] ``` To create a vector with the all values of `storage_level_intra_rp` for a given `a` and `rp`, one can run @@ -356,7 +356,7 @@ df = filter( energy_problem.dataframes[:lowest_storage_level_intra_rp], view = true, ) -[energy_problem.graph[a].storage_level_intra_rp[(rp, row.time_block)] for row in eachrow(df)] +[energy_problem.graph[a].storage_level_intra_rp[(rp, row.timesteps_block)] for row in eachrow(df)] ``` To create a vector with the all values of `storage_level_inter_rp` for a given `a`, one can run @@ -368,7 +368,7 @@ df = filter( energy_problem.dataframes[:storage_level_inter_rp], view = true, ) -[energy_problem.graph[a].storage_level_inter_rp[row.base_period_block] for row in eachrow(df)] +[energy_problem.graph[a].storage_level_inter_rp[row.periods_block] for row in eachrow(df)] ``` ### The solution inside the dataframes object diff --git a/src/create-model.jl b/src/create-model.jl index cc6f1591..40357f8f 100644 --- a/src/create-model.jl +++ b/src/create-model.jl @@ -5,13 +5,13 @@ export create_model!, create_model, construct_dataframes graph, representative_periods, constraints_partitions, - base_periods, + timeframe, ) Computes the data frames used to linearize the variables and constraints. These are used internally in the model only. """ -function construct_dataframes(graph, representative_periods, constraints_partitions, base_periods) +function construct_dataframes(graph, representative_periods, constraints_partitions, timeframe) A = MetaGraphsNext.labels(graph) |> collect F = MetaGraphsNext.edge_labels(graph) |> collect RP = 1:length(representative_periods) @@ -27,9 +27,9 @@ function construct_dataframes(graph, representative_periods, constraints_partiti from = u, to = v, rp = rp, - time_block = time_block, + timesteps_block = timesteps_block, efficiency = graph[u, v].efficiency, - ) for time_block ∈ graph[u, v].rep_periods_partitions[rp] + ) for timesteps_block ∈ graph[u, v].rep_periods_partitions[rp] ) for (u, v) ∈ F, rp ∈ RP ) |> Iterators.flatten, ) @@ -41,7 +41,7 @@ function construct_dataframes(graph, representative_periods, constraints_partiti dataframes[key] = DataFrame(; asset = Symbol[], rp = Int[], - time_block = UnitRange{Int}[], + timesteps_block = UnitRange{Int}[], index = Int[], ) continue @@ -50,8 +50,10 @@ function construct_dataframes(graph, representative_periods, constraints_partiti # This construction should ensure the ordering of the time blocks for groups of (a, rp) df = DataFrame( ( - ((asset = a, rp = rp, time_block = time_block) for time_block ∈ partition) for - ((a, rp), partition) in partitions + ( + (asset = a, rp = rp, timesteps_block = timesteps_block) for + timesteps_block ∈ partition + ) for ((a, rp), partition) in partitions ) |> Iterators.flatten, ) df.index = 1:size(df, 1) @@ -63,14 +65,14 @@ function construct_dataframes(graph, representative_periods, constraints_partiti dataframes[:storage_level_inter_rp] = DataFrame( ( ( - (asset = a, base_period_block = time_block) for - time_block in graph[a].base_periods_partitions + (asset = a, periods_block = periods_block) for + periods_block in graph[a].timeframe_partitions ) for a in A ) |> Iterators.flatten, ) if size(dataframes[:storage_level_inter_rp], 1) == 0 dataframes[:storage_level_inter_rp] = - DataFrame(; asset = Symbol[], base_period_block = UnitRange{Int}[]) + DataFrame(; asset = Symbol[], periods_block = PeriodsBlock[]) end dataframes[:storage_level_inter_rp].index = 1:size(dataframes[:storage_level_inter_rp], 1) @@ -136,7 +138,7 @@ function add_expression_terms_intra_rp_constraints!( # Store the corresponding flow in the workspace for row in eachrow(grouped_flows[(rp, asset)]) asset = row[case.asset_match] - for t ∈ row.time_block + for t ∈ row.timesteps_block # Set the efficiency to 1 for inflows and outflows of hub and consumer assets, and outflows for producer assets # And when you want the highest resolution (which is asset type-agnostic) efficiency_coefficient = @@ -159,7 +161,7 @@ function add_expression_terms_intra_rp_constraints!( end # Sum the corresponding flows from the workspace for row in eachrow(sub_df) - row[case.col_name] = agg(@view workspace[row.time_block]) + row[case.col_name] = agg(@view workspace[row.timesteps_block]) end end end @@ -192,7 +194,7 @@ function add_expression_terms_inter_rp_constraints!( # Incoming, outgoing flows, and profile aggregation for row_inter in eachrow(df_inter) - sub_df_map = filter(row -> row.period in row_inter.base_period_block, df_map) + sub_df_map = filter(row -> row.period in row_inter.periods_block, df_map) for row_map in eachrow(sub_df_map) sub_df_flows = @@ -208,7 +210,7 @@ function add_expression_terms_inter_rp_constraints!( sum, graph[row_inter.asset].rep_periods_profiles, (:inflows, row_map.rep_period), - representative_periods[row_map.rep_period].time_steps, + representative_periods[row_map.rep_period].timesteps, 0.0, ) * graph[row_inter.asset].storage_inflows * @@ -218,21 +220,21 @@ function add_expression_terms_inter_rp_constraints!( end """ - profile_aggregation(agg, profiles, key, time_block, default_value) + profile_aggregation(agg, profiles, key, block, default_value) -Aggregates the `profiles[key]` over the `time_block` using the `agg` function. +Aggregates the `profiles[key]` over the `block` using the `agg` function. If the profile does not exist, uses `default_value` instead of **each** profile value. `profiles` should be a dictionary of profiles, for instance `graph[a].profiles` or `graph[u, v].profiles`. If `profiles[key]` exists, then this function computes the aggregation of `profiles[key]` -over the range `time_block` using the aggregator `agg`, i.e., `agg(profiles[key][time_block])`. +over the range `block` using the aggregator `agg`, i.e., `agg(profiles[key][block])`. If `profiles[key]` does not exist, then this substitutes it by a vector of `default_value`s. """ -function profile_aggregation(agg, profiles, key, time_block, default_value) +function profile_aggregation(agg, profiles, key, block, default_value) if haskey(profiles, key) - return agg(profiles[key][time_block]) + return agg(profiles[key][block]) else - return agg(Iterators.repeated(default_value, length(time_block))) + return agg(Iterators.repeated(default_value, length(block))) end end @@ -245,16 +247,11 @@ function create_model!(energy_problem; kwargs...) graph = energy_problem.graph representative_periods = energy_problem.representative_periods constraints_partitions = energy_problem.constraints_partitions - base_periods = energy_problem.base_periods + timeframe = energy_problem.timeframe energy_problem.dataframes = - construct_dataframes(graph, representative_periods, constraints_partitions, base_periods) - energy_problem.model = create_model( - graph, - representative_periods, - energy_problem.dataframes, - base_periods; - kwargs..., - ) + construct_dataframes(graph, representative_periods, constraints_partitions, timeframe) + energy_problem.model = + create_model(graph, representative_periods, energy_problem.dataframes, timeframe; kwargs...) energy_problem.termination_status = JuMP.OPTIMIZE_NOT_CALLED energy_problem.solved = false energy_problem.objective_value = NaN @@ -262,23 +259,17 @@ function create_model!(energy_problem; kwargs...) end """ - model = create_model(graph, representative_periods, dataframes, base_periods; write_lp_file = false) + model = create_model(graph, representative_periods, dataframes, timeframe; write_lp_file = false) -Create the energy model given the `graph`, `representative_periods`, dictionary of `dataframes` (created by [`construct_dataframes`](@ref)), and base_periods. +Create the energy model given the `graph`, `representative_periods`, dictionary of `dataframes` (created by [`construct_dataframes`](@ref)), and timeframe. """ -function create_model( - graph, - representative_periods, - dataframes, - base_periods; - write_lp_file = false, -) +function create_model(graph, representative_periods, dataframes, timeframe; write_lp_file = false) ## Helper functions # Computes the duration of the `block` and multiply by the resolution of the # representative period `rp`. - function duration(time_block, rp) - return length(time_block) * representative_periods[rp].resolution + function duration(timesteps_block, rp) + return length(timesteps_block) * representative_periods[rp].resolution end ## Sets unpacking @@ -300,7 +291,7 @@ function create_model( Fi = filter_flows(:investable, true) # Maximum time step - Tmax = maximum(last(rp.time_steps) for rp in representative_periods) + Tmax = maximum(last(rp.timesteps) for rp in representative_periods) expression_workspace = Vector{JuMP.AffExpr}(undef, Tmax) # Unpacking dataframes @@ -320,7 +311,7 @@ function create_model( df_flows.flow = [ @variable( model, - base_name = "flow[($(row.from), $(row.to)), $(row.rp), $(row.time_block)]" + base_name = "flow[($(row.from), $(row.to)), $(row.rp), $(row.timesteps_block)]" ) for row in eachrow(df_flows) ] @variable(model, 0 ≤ assets_investment[Ai]) #number of installed asset units [N] @@ -330,7 +321,7 @@ function create_model( @variable( model, lower_bound = 0.0, - base_name = "storage_level_intra_rp[$(row.asset),$(row.rp),$(row.time_block)]" + base_name = "storage_level_intra_rp[$(row.asset),$(row.rp),$(row.timesteps_block)]" ) for row in eachrow(dataframes[:lowest_storage_level_intra_rp]) ] storage_level_inter_rp = @@ -338,7 +329,7 @@ function create_model( @variable( model, lower_bound = 0.0, - base_name = "storage_level_inter_rp[$(row.asset),$(row.base_period_block)]" + base_name = "storage_level_inter_rp[$(row.asset),$(row.periods_block)]" ) for row in eachrow(dataframes[:storage_level_inter_rp]) ] ### Integer Investment Variables @@ -410,7 +401,7 @@ function create_model( add_expression_terms_inter_rp_constraints!( dataframes[:storage_level_inter_rp], df_flows, - base_periods.rp_mapping_df, + timeframe.map_periods_to_rp, graph, representative_periods, ) @@ -469,7 +460,7 @@ function create_model( model, sum( representative_periods[row.rp].weight * - duration(row.time_block, row.rp) * + duration(row.timesteps_block, row.rp) * graph[row.from, row.to].variable_cost * row.flow for row in eachrow(df_flows) ) @@ -490,10 +481,10 @@ function create_model( Statistics.mean, graph[row.asset].rep_periods_profiles, (:demand, row.rp), - row.time_block, + row.timesteps_block, 1.0, ) * graph[row.asset].peak_demand, - base_name = "consumer_balance[$(row.asset),$(row.rp),$(row.time_block)]" + base_name = "consumer_balance[$(row.asset),$(row.rp),$(row.timesteps_block)]" ) for row in eachrow(df) ] @@ -523,12 +514,12 @@ function create_model( sum, graph[a].rep_periods_profiles, (:inflows, rp), - row.time_block, + row.timesteps_block, 0.0, ) * graph[a].storage_inflows + incoming_flow_lowest_storage_resolution_intra_rp[row.index] - outgoing_flow_lowest_storage_resolution_intra_rp[row.index], - base_name = "storage_intra_rp_balance[$a,$rp,$(row.time_block)]" + base_name = "storage_intra_rp_balance[$a,$rp,$(row.timesteps_block)]" ) for (k, row) ∈ enumerate(eachrow(sub_df)) ] end @@ -557,7 +548,7 @@ function create_model( row.inflows_profile_aggregation + incoming_flow_storage_inter_rp_balance[row.index] - outgoing_flow_storage_inter_rp_balance[row.index], - base_name = "storage_inter_rp_balance[$a,$(row.base_period_block)]" + base_name = "storage_inter_rp_balance[$a,$(row.periods_block)]" ) for (k, row) ∈ enumerate(eachrow(sub_df)) ] end @@ -569,7 +560,7 @@ function create_model( model, incoming_flow_highest_in_out_resolution[row.index] == outgoing_flow_highest_in_out_resolution[row.index], - base_name = "hub_balance[$(row.asset),$(row.rp),$(row.time_block)]" + base_name = "hub_balance[$(row.asset),$(row.rp),$(row.timesteps_block)]" ) for row in eachrow(df) ] @@ -580,7 +571,7 @@ function create_model( model, incoming_flow_lowest_resolution[row.index] == outgoing_flow_lowest_resolution[row.index], - base_name = "conversion_balance[$(row.asset),$(row.rp),$(row.time_block)]" + base_name = "conversion_balance[$(row.asset),$(row.rp),$(row.timesteps_block)]" ) for row in eachrow(df) ] @@ -593,7 +584,7 @@ function create_model( Statistics.mean, graph[row.asset].rep_periods_profiles, (:availability, row.rp), - row.time_block, + row.timesteps_block, 1.0, ) * ( graph[row.asset].initial_capacity + @@ -607,7 +598,7 @@ function create_model( Statistics.mean, graph[row.asset].rep_periods_profiles, (:availability, row.rp), - row.time_block, + row.timesteps_block, 1.0, ) * graph[row.asset].initial_capacity ) @@ -623,7 +614,7 @@ function create_model( Statistics.mean, graph[row.asset].rep_periods_profiles, (:availability, row.rp), - row.time_block, + row.timesteps_block, 1.0, ) * ( graph[row.asset].initial_capacity + @@ -637,7 +628,7 @@ function create_model( Statistics.mean, graph[row.asset].rep_periods_profiles, (:availability, row.rp), - row.time_block, + row.timesteps_block, 1.0, ) * graph[row.asset].initial_capacity ) @@ -651,7 +642,7 @@ function create_model( model, outgoing_flow_highest_out_resolution[row.index] ≤ assets_profile_times_capacity_out[row.index], - base_name = "max_output_flows_limit[$(row.asset),$(row.rp),$(row.time_block)]" + base_name = "max_output_flows_limit[$(row.asset),$(row.rp),$(row.timesteps_block)]" ) for row in eachrow(dataframes[:highest_out]) if outgoing_flow_highest_out_resolution[row.index] != 0 ] @@ -662,7 +653,7 @@ function create_model( model, incoming_flow_highest_in_resolution[row.index] ≤ assets_profile_times_capacity_in[row.index], - base_name = "max_input_flows_limit[$(row.asset),$(row.rp),$(row.time_block)]" + base_name = "max_input_flows_limit[$(row.asset),$(row.rp),$(row.timesteps_block)]" ) for row in eachrow(dataframes[:highest_in]) if incoming_flow_highest_in_resolution[row.index] != 0 ] @@ -683,7 +674,7 @@ function create_model( Statistics.mean, graph[row.from, row.to].rep_periods_profiles, (:availability, row.rp), - row.time_block, + row.timesteps_block, 1.0, ) * ( graph[row.from, row.to].initial_export_capacity + @@ -697,7 +688,7 @@ function create_model( Statistics.mean, graph[row.from, row.to].rep_periods_profiles, (:availability, row.rp), - row.time_block, + row.timesteps_block, 1.0, ) * graph[row.from, row.to].initial_export_capacity ) @@ -712,7 +703,7 @@ function create_model( Statistics.mean, graph[row.from, row.to].rep_periods_profiles, (:availability, row.rp), - row.time_block, + row.timesteps_block, 1.0, ) * ( graph[row.from, row.to].initial_import_capacity + @@ -726,7 +717,7 @@ function create_model( Statistics.mean, graph[row.from, row.to].rep_periods_profiles, (:availability, row.rp), - row.time_block, + row.timesteps_block, 1.0, ) * graph[row.from, row.to].initial_import_capacity ) @@ -739,7 +730,7 @@ function create_model( @constraint( model, flow[row.index] ≤ upper_bound_transport_flow[row.index], - base_name = "max_transport_flow_limit[($(row.from),$(row.to)),$(row.rp),$(row.time_block)]" + base_name = "max_transport_flow_limit[($(row.from),$(row.to)),$(row.rp),$(row.timesteps_block)]" ) for row in eachrow(df) ] @@ -747,7 +738,7 @@ function create_model( @constraint( model, flow[row.index] ≥ -lower_bound_transport_flow[row.index], - base_name = "min_transport_flow_limit[($(row.from),$(row.to)),$(row.rp),$(row.time_block)]" + base_name = "min_transport_flow_limit[($(row.from),$(row.to)),$(row.rp),$(row.timesteps_block)]" ) for row in eachrow(df) ] @@ -761,13 +752,13 @@ function create_model( Statistics.mean, graph[row.asset].rep_periods_profiles, ("max-storage-level", row.rp), - row.time_block, + row.timesteps_block, 1.0, ) * ( graph[row.asset].initial_storage_capacity + (row.asset ∈ Ai ? energy_limit[row.asset] : 0.0) ), - base_name = "max_storage_level_intra_rp_limit[$(row.asset),$(row.rp),$(row.time_block)]" + base_name = "max_storage_level_intra_rp_limit[$(row.asset),$(row.rp),$(row.timesteps_block)]" ) for row ∈ eachrow(dataframes[:lowest_storage_level_intra_rp]) ] @@ -780,13 +771,13 @@ function create_model( Statistics.mean, graph[row.asset].rep_periods_profiles, (:min_storage_level, row.rp), - row.time_block, + row.timesteps_block, 0.0, ) * ( graph[row.asset].initial_storage_capacity + (row.asset ∈ Ai ? energy_limit[row.asset] : 0.0) ), - base_name = "min_storage_level_intra_rp_limit[$(row.asset),$(row.rp),$(row.time_block)]" + base_name = "min_storage_level_intra_rp_limit[$(row.asset),$(row.rp),$(row.timesteps_block)]" ) for row ∈ eachrow(dataframes[:lowest_storage_level_intra_rp]) ] @@ -808,15 +799,15 @@ function create_model( storage_level_inter_rp[row.index] ≤ profile_aggregation( Statistics.mean, - graph[row.asset].base_periods_profiles, + graph[row.asset].timeframe_profiles, :max_storage_level, - row.base_period_block, + row.periods_block, 1.0, ) * ( graph[row.asset].initial_storage_capacity + (row.asset ∈ Ai ? energy_limit[row.asset] : 0.0) ), - base_name = "max_storage_level_inter_rp_limit[$(row.asset),$(row.base_period_block)]" + base_name = "max_storage_level_inter_rp_limit[$(row.asset),$(row.periods_block)]" ) for row ∈ eachrow(dataframes[:storage_level_inter_rp]) ] @@ -827,15 +818,15 @@ function create_model( storage_level_inter_rp[row.index] ≥ profile_aggregation( Statistics.mean, - graph[row.asset].base_periods_profiles, + graph[row.asset].timeframe_profiles, :min_storage_level, - row.base_period_block, + row.periods_block, 0.0, ) * ( graph[row.asset].initial_storage_capacity + (row.asset ∈ Ai ? energy_limit[row.asset] : 0.0) ), - base_name = "min_storage_level_inter_rp_limit[$(row.asset),$(row.base_period_block)]" + base_name = "min_storage_level_inter_rp_limit[$(row.asset),$(row.periods_block)]" ) for row ∈ eachrow(dataframes[:storage_level_inter_rp]) ] diff --git a/src/input-schemas.jl b/src/input-schemas.jl index 872684cd..56629417 100644 --- a/src/input-schemas.jl +++ b/src/input-schemas.jl @@ -28,8 +28,8 @@ const schemas = ( :profile_name => Symbol, # Name of profile, used to determine data inside the dataframe ), - # Schema for the assets-base-periods-partitions.csv file. - base_periods_partition = OrderedDict( + # Schema for the assets-timeframe-partitions.csv file. + timeframe_partition = OrderedDict( :asset => Symbol, :specification => Symbol, :partition => String, @@ -79,11 +79,11 @@ const schemas = ( :partition => String, ), ), - base_periods = ( - # Schema for the profiles-base-periods-.csv file. + timeframe = ( + # Schema for the profiles-timeframe-.csv file. profiles_data = OrderedDict( :profile_name => Symbol, # Asset ID - :base_period => Int, # Base period ID + :period => Int, # Period :value => Float64, # p.u. (per unit) ), ), @@ -92,7 +92,7 @@ const schemas = ( rep_periods = ( data = OrderedDict( :id => Int, # Representative period ID - :num_time_steps => Int, # Numer of time steps + :num_timesteps => Int, # Numer of time steps :resolution => Float64, # Duration of each time steps (hours) ), @@ -107,22 +107,22 @@ const schemas = ( profiles_data = OrderedDict( :profile_name => Symbol, # Asset ID :rep_period => Int, # Representative period ID - :time_step => Int, # Time step ID + :timestep => Int, # Time step ID :value => Float64, # p.u. (per unit) ), ), ) const schema_per_file = OrderedDict( - "assets-base-periods-partitions.csv" => schemas.assets.base_periods_partition, + "assets-timeframe-partitions.csv" => schemas.assets.timeframe_partition, "assets-data.csv" => schemas.assets.data, - "assets-base-periods-profiles.csv" => schemas.assets.profiles_reference, + "assets-timeframe-profiles.csv" => schemas.assets.profiles_reference, "assets-rep-periods-profiles.csv" => schemas.assets.profiles_reference, "assets-rep-periods-partitions.csv" => schemas.assets.rep_periods_partition, "flows-data.csv" => schemas.flows.data, "flows-rep-periods-profiles.csv" => schemas.flows.profiles_reference, "flows-rep-periods-partitions.csv" => schemas.flows.rep_periods_partition, - "profiles-base-periods-.csv" => schemas.base_periods.profiles_data, + "profiles-timeframe-.csv" => schemas.timeframe.profiles_data, "profiles-rep-periods-.csv" => schemas.rep_periods.profiles_data, "rep-periods-data.csv" => schemas.rep_periods.data, "rep-periods-mapping.csv" => schemas.rep_periods.mapping, diff --git a/src/io.jl b/src/io.jl index 1b8f09a0..0f4e3109 100644 --- a/src/io.jl +++ b/src/io.jl @@ -14,28 +14,28 @@ the `EnergyProblem` structure. Set strict = true to error if assets are missing from partition data. """ function create_energy_problem_from_csv_folder(input_folder::AbstractString; strict = false) - graph, representative_periods, base_periods = + graph, representative_periods, timeframe = create_graph_and_representative_periods_from_csv_folder(input_folder; strict = strict) - return EnergyProblem(graph, representative_periods, base_periods) + return EnergyProblem(graph, representative_periods, timeframe) end """ - graph, representative_periods, base_periods = create_graph_and_representative_periods_from_csv_folder(input_folder; strict = false) + graph, representative_periods, timeframe = create_graph_and_representative_periods_from_csv_folder(input_folder; strict = false) Returns the `graph` structure that holds all data, and the `representative_periods` array. Set strict = true to error if assets are missing from partition data. The following files are expected to exist in the input folder: - - `assets-base-periods-partitions.csv`: Following the schema `schemas.assets.base_periods_partition`. + - `assets-timeframe-partitions.csv`: Following the schema `schemas.assets.timeframe_partition`. - `assets-data.csv`: Following the schema `schemas.assets.data`. - - `assets-base-periods-profiles.csv`: Following the schema `schemas.assets.profiles_reference`. + - `assets-timeframe-profiles.csv`: Following the schema `schemas.assets.profiles_reference`. - `assets-rep-periods-profiles.csv`: Following the schema `schemas.assets.profiles_reference`. - `assets-rep-periods-partitions.csv`: Following the schema `schemas.assets.rep_periods_partition`. - `flows-data.csv`: Following the schema `schemas.flows.data`. - `flows-rep-periods-profiles.csv`: Following the schema `schemas.flows.profiles_reference`. - `flows-rep-periods-partitions.csv`: Following the schema `schemas.flows.rep_periods_partition`. - - `profiles-base-periods-.csv`: Following the schema `schemas.base_periods.profiles_data`. + - `profiles-timeframe-.csv`: Following the schema `schemas.timeframe.profiles_data`. - `profiles-rep-periods-.csv`: Following the schema `schemas.rep_periods.profiles_data`. - `rep-periods-data.csv`: Following the schema `schemas.rep_periods.data`. - `rep-periods-mapping.csv`: Following the schema `schemas.rep_periods.mapping`. @@ -52,8 +52,8 @@ The returned structures are: - `representative_periods`: An array of [`TulipaEnergyModel.RepresentativePeriod`](@ref) ordered by their IDs. - - `base_periods`: Information of - [`TulipaEnergyModel.BasePeriod`](@ref). + - `timeframe`: Information of + [`TulipaEnergyModel.Timeframe`](@ref). """ function create_graph_and_representative_periods_from_csv_folder( input_folder::AbstractString; @@ -65,17 +65,16 @@ function create_graph_and_representative_periods_from_csv_folder( rp_mapping_df = read_csv_with_implicit_schema(input_folder, "rep-periods-mapping.csv") assets_profiles_df = Dict( - profile_type => read_csv_with_implicit_schema( - input_folder, - "assets-$profile_type-periods-profiles.csv", - ) for profile_type in [:base, :rep] + profile_type => + read_csv_with_implicit_schema(input_folder, "assets-$profile_type-profiles.csv") for + profile_type in ["timeframe", "rep-periods"] ) flows_profiles_df = read_csv_with_implicit_schema(input_folder, "flows-rep-periods-profiles.csv") assets_partitions_df = Dict( - :base => - read_csv_with_implicit_schema(input_folder, "assets-base-periods-partitions.csv"), - :rep => + "timeframe" => + read_csv_with_implicit_schema(input_folder, "assets-timeframe-partitions.csv"), + "rep-periods" => read_csv_with_implicit_schema(input_folder, "assets-rep-periods-partitions.csv"), ) flows_partitions_df = @@ -84,19 +83,20 @@ function create_graph_and_representative_periods_from_csv_folder( profiles_dfs = Dict( period_type => Dict( begin - regex = "profiles-$(period_type)-periods-(.*).csv" + regex = "profiles-$(period_type)-(.*).csv" # Sanitized key: Spaces and dashes convert to underscore key = Symbol(replace(match(Regex(regex), filename)[1], r"[ -]" => "_")) value = read_csv_with_implicit_schema(input_folder, filename) key => value end for filename in readdir(input_folder) if - startswith("profiles-$period_type-periods-")(filename) - ) for period_type in [:rep, :base] + startswith("profiles-$period_type-")(filename) + ) for period_type in ["rep-periods", "timeframe"] ) # Error if partition data is missing assets (if strict) if strict - missing_assets = setdiff(assets_data_df[!, :name], assets_partitions_df[:rep][!, :asset]) + missing_assets = + setdiff(assets_data_df[!, :name], assets_partitions_df["rep-periods"][!, :asset]) if length(missing_assets) > 0 msg = "Error: Partition data missing for these assets: \n" for a in missing_assets @@ -121,11 +121,11 @@ function create_graph_and_representative_periods_from_csv_folder( end representative_periods = [ - RepresentativePeriod(weights[row.id], row.num_time_steps, row.resolution) for + RepresentativePeriod(weights[row.id], row.num_timesteps, row.resolution) for row in eachrow(rep_period_df) ] - base_periods = BasePeriod(maximum(rp_mapping_df.period), rp_mapping_df) + timeframe = Timeframe(maximum(rp_mapping_df.period), rp_mapping_df) asset_data = [ row.name => GraphAssetData( @@ -176,7 +176,7 @@ function create_graph_and_representative_periods_from_csv_folder( for a in MetaGraphsNext.labels(graph) compute_assets_partitions!( graph[a].rep_periods_partitions, - assets_partitions_df[:rep], + assets_partitions_df["rep-periods"], a, representative_periods, ) @@ -192,34 +192,34 @@ function create_graph_and_representative_periods_from_csv_folder( ) end - # For base periods, only the assets where is_seasonal is true are selected + # For timeframe, only the assets where is_seasonal is true are selected for row in eachrow(assets_data_df) if row.is_seasonal # Search for this row in the assets_partitions_df and error if it is not found found = false - for partition_row in eachrow(assets_partitions_df[:base]) + for partition_row in eachrow(assets_partitions_df["timeframe"]) if row.name == partition_row.asset - graph[row.name].base_periods_partitions = _parse_rp_partition( + graph[row.name].timeframe_partitions = _parse_rp_partition( Val(partition_row.specification), partition_row.partition, - 1:base_periods.num_base_periods, + 1:timeframe.num_periods, ) found = true break end end if !found - graph[row.name].base_periods_partitions = - _parse_rp_partition(Val(:uniform), "1", 1:base_periods.num_base_periods) + graph[row.name].timeframe_partitions = + _parse_rp_partition(Val(:uniform), "1", 1:timeframe.num_periods) end end end - for asset_profile_row in eachrow(assets_profiles_df[:rep]) # row = asset, profile_type, profile_name + for asset_profile_row in eachrow(assets_profiles_df["rep-periods"]) # row = asset, profile_type, profile_name gp = DataFrames.groupby( # 3. group by RP filter( row -> row.profile_name == asset_profile_row.profile_name, # 2. Filter profile_name - profiles_dfs[:rep][asset_profile_row.profile_type], # 1. Get the profile of given type + profiles_dfs["rep-periods"][asset_profile_row.profile_type], # 1. Get the profile of given type ), :rep_period, ) @@ -235,7 +235,7 @@ function create_graph_and_representative_periods_from_csv_folder( gp = DataFrames.groupby( filter( row -> row.profile_name == flow_profile_row.profile_name, - profiles_dfs[:rep][flow_profile_row.profile_type], + profiles_dfs["rep-periods"][flow_profile_row.profile_type], ), :rep_period, ) @@ -247,16 +247,15 @@ function create_graph_and_representative_periods_from_csv_folder( end end - for asset_profile_row in eachrow(assets_profiles_df[:base]) # row = asset, profile_type, profile_name + for asset_profile_row in eachrow(assets_profiles_df["timeframe"]) # row = asset, profile_type, profile_name df = filter( row -> row.profile_name == asset_profile_row.profile_name, # 2. Filter profile_name - profiles_dfs[:base][asset_profile_row.profile_type], # 1. Get the profile of given type + profiles_dfs["timeframe"][asset_profile_row.profile_type], # 1. Get the profile of given type ) - graph[asset_profile_row.asset].base_periods_profiles[asset_profile_row.profile_type] = - df.value + graph[asset_profile_row.asset].timeframe_profiles[asset_profile_row.profile_type] = df.value end - return graph, representative_periods, base_periods + return graph, representative_periods, timeframe end """ @@ -285,8 +284,8 @@ function read_csv_with_implicit_schema(dir, filename; csvargs...) schema = if haskey(schema_per_file, filename) schema_per_file[filename] else - if startswith("profiles-base-periods")(filename) - schema_per_file["profiles-base-periods-.csv"] + if startswith("profiles-timeframe")(filename) + schema_per_file["profiles-timeframe-.csv"] elseif startswith("profiles-rep-periods")(filename) schema_per_file["profiles-rep-periods-.csv"] else @@ -325,10 +324,10 @@ The following files are created: capacity value. Only investable assets are included. - `flows-investment.csv`: Similar to `assets-investment.csv`, but for flows. - `flows.csv`: The value of each flow, per `(from, to)` flow, `rp` representative period - and `time_step`. Since the flow is in power, the value at a time step is equal to the value + and `timestep`. Since the flow is in power, the value at a time step is equal to the value at the corresponding time block, i.e., if flow[1:3] = 30, then flow[1] = flow[2] = flow[3] = 30. - `storage-level.csv`: The value of each storage level, per `asset`, `rp` representative period, - and `time_step`. Since the storage level is in energy, the value at a time step is a + and `timestep`. Since the storage level is in energy, the value at a time step is a proportional fraction of the value at the corresponding time block, i.e., if level[1:3] = 30, then level[1] = level[2] = level[3] = 10. """ @@ -366,26 +365,27 @@ function save_solution_to_file(output_folder, graph, dataframes, solution) In both cases below, we select the relevant columns from the existing dataframes, then, we append the solution column. After that, we transform and flatten, by rows, the time block values into a long version. - I.e., if a row shows `time_block = 3:5` and `value = 30`, then we transform into - three rows with values `time_step = [3, 4, 5]` and `value` equal to 30 / 3 for storage, + I.e., if a row shows `timesteps_block = 3:5` and `value = 30`, then we transform into + three rows with values `timestep = [3, 4, 5]` and `value` equal to 30 / 3 for storage, or 30 for flows. =# output_file = joinpath(output_folder, "flows.csv") - output_table = DataFrames.select(dataframes[:flows], :from, :to, :rp, :time_block => :time_step) + output_table = + DataFrames.select(dataframes[:flows], :from, :to, :rp, :timesteps_block => :timestep) output_table.value = solution.flow output_table = DataFrames.flatten( DataFrames.transform( output_table, - [:time_step, :value] => + [:timestep, :value] => DataFrames.ByRow( - (time_block, value) -> begin # transform each row using these two columns - n = length(time_block) - (time_block, Iterators.repeated(value, n)) # e.g., (3:5, [30, 30, 30]) + (timesteps_block, value) -> begin # transform each row using these two columns + n = length(timesteps_block) + (timesteps_block, Iterators.repeated(value, n)) # e.g., (3:5, [30, 30, 30]) end, - ) => [:time_step, :value], + ) => [:timestep, :value], ), - [:time_step, :value], # flatten, e.g., [(3, 30), (4, 30), (5, 30)] + [:timestep, :value], # flatten, e.g., [(3, 30), (4, 30), (5, 30)] ) output_table |> CSV.write(output_file) @@ -394,43 +394,38 @@ function save_solution_to_file(output_folder, graph, dataframes, solution) dataframes[:lowest_storage_level_intra_rp], :asset, :rp, - :time_block => :time_step, + :timesteps_block => :timestep, ) output_table.value = solution.storage_level_intra_rp output_table = DataFrames.flatten( DataFrames.transform( output_table, - [:time_step, :value] => + [:timestep, :value] => DataFrames.ByRow( - (time_block, value) -> begin - n = length(time_block) - (time_block, Iterators.repeated(value, n)) + (timesteps_block, value) -> begin + n = length(timesteps_block) + (timesteps_block, Iterators.repeated(value, n)) end, - ) => [:time_step, :value], + ) => [:timestep, :value], ), - [:time_step, :value], + [:timestep, :value], ) output_table |> CSV.write(output_file) output_file = joinpath(output_folder, "storage-level-inter-rp.csv") - output_table = DataFrames.select( - dataframes[:storage_level_inter_rp], - :asset, - :base_period_block => :time_step, - ) + output_table = + DataFrames.select(dataframes[:storage_level_inter_rp], :asset, :periods_block => :period) output_table.value = solution.storage_level_inter_rp output_table = DataFrames.flatten( DataFrames.transform( output_table, - [:time_step, :value] => - DataFrames.ByRow( - (base_period_block, value) -> begin - n = length(base_period_block) - (base_period_block, Iterators.repeated(value, n)) - end, - ) => [:time_step, :value], + [:period, :value] => + DataFrames.ByRow((period, value) -> begin + n = length(period) + (period, Iterators.repeated(value, n)) + end) => [:period, :value], ), - [:time_step, :value], + [:period, :value], ) output_table |> CSV.write(output_file) @@ -438,27 +433,27 @@ function save_solution_to_file(output_folder, graph, dataframes, solution) end """ - _parse_rp_partition(Val(specification), time_step_string, rp_time_steps) + _parse_rp_partition(Val(specification), timestep_string, rp_timesteps) -Parses the time_step_string according to the specification. -The representative period time steps (`rp_time_steps`) might not be used in the computation, +Parses the timestep_string according to the specification. +The representative period time steps (`rp_timesteps`) might not be used in the computation, but it will be used for validation. -The specification defines what is expected from the `time_step_string`: +The specification defines what is expected from the `timestep_string`: - - `:uniform`: The `time_step_string` should be a single number indicating the duration of + - `:uniform`: The `timestep_string` should be a single number indicating the duration of each block. Examples: "3", "4", "1". - - `:explicit`: The `time_step_string` should be a semicolon-separated list of integers. + - `:explicit`: The `timestep_string` should be a semicolon-separated list of integers. Each integer is a duration of a block. Examples: "3;3;3;3", "4;4;4", "1;1;1;1;1;1;1;1;1;1;1;1", and "3;3;4;2". - - `:math`: The `time_step_string` should be an expression of the form `NxD+NxD…`, where `D` + - `:math`: The `timestep_string` should be an expression of the form `NxD+NxD…`, where `D` is the duration of the block and `N` is the number of blocks. Examples: "4x3", "3x4", "12x1", and "2x3+1x4+1x2". The generated blocks will be ranges (`a:b`). The first block starts at `1`, and the last -block ends at `length(rp_time_steps)`. +block ends at `length(rp_timesteps)`. -The following table summarizes the formats for a `rp_time_steps = 1:12`: +The following table summarizes the formats for a `rp_timesteps = 1:12`: | Output | :uniform | :explicit | :math | |:--------------------- |:-------- |:----------------------- |:----------- | @@ -509,30 +504,30 @@ TulipaEnergyModel._parse_rp_partition(Val(:math), "2x3+1x4+1x2", 1:12) """ function _parse_rp_partition end -function _parse_rp_partition(::Val{:uniform}, time_step_string, rp_time_steps) - duration = parse(Int, time_step_string) - partition = [i:i+duration-1 for i ∈ 1:duration:length(rp_time_steps)] - @assert partition[end][end] == length(rp_time_steps) +function _parse_rp_partition(::Val{:uniform}, timestep_string, rp_timesteps) + duration = parse(Int, timestep_string) + partition = [i:i+duration-1 for i ∈ 1:duration:length(rp_timesteps)] + @assert partition[end][end] == length(rp_timesteps) return partition end -function _parse_rp_partition(::Val{:explicit}, time_step_string, rp_time_steps) +function _parse_rp_partition(::Val{:explicit}, timestep_string, rp_timesteps) partition = UnitRange{Int}[] block_begin = 1 - block_lengths = parse.(Int, split(time_step_string, ";")) + block_lengths = parse.(Int, split(timestep_string, ";")) for block_length in block_lengths block_end = block_begin + block_length - 1 push!(partition, block_begin:block_end) block_begin = block_end + 1 end - @assert block_begin - 1 == length(rp_time_steps) + @assert block_begin - 1 == length(rp_timesteps) return partition end -function _parse_rp_partition(::Val{:math}, time_step_string, rp_time_steps) +function _parse_rp_partition(::Val{:math}, timestep_string, rp_timesteps) partition = UnitRange{Int}[] block_begin = 1 - block_instruction = split(time_step_string, "+") + block_instruction = split(timestep_string, "+") for R in block_instruction num, len = parse.(Int, split(R, "x")) for _ ∈ 1:num @@ -541,7 +536,7 @@ function _parse_rp_partition(::Val{:math}, time_step_string, rp_time_steps) push!(partition, block) end end - @assert block_begin - 1 == length(rp_time_steps) + @assert block_begin - 1 == length(rp_timesteps) return partition end @@ -549,13 +544,13 @@ end compute_assets_partitions!(partitions, df, a, representative_periods) Parses the time blocks in the DataFrame `df` for the asset `a` and every -representative period in the `time_steps_per_rp` dictionary, modifying the +representative period in the `timesteps_per_rp` dictionary, modifying the input `partitions`. `partitions` must be a dictionary indexed by the representative periods, possibly empty. -`time_steps_per_rp` must be a dictionary indexed by `rp` and its values are the +`timesteps_per_rp` must be a dictionary indexed by `rp` and its values are the time steps of that `rp`. To obtain the partitions, the columns `specification` and `partition` from `df` @@ -566,11 +561,11 @@ function compute_assets_partitions!(partitions, df, a, representative_periods) # Look for index in df that matches this asset and rp j = findfirst((df.asset .== a) .& (df.rep_period .== rp_id)) partitions[rp_id] = if j === nothing - N = length(rp.time_steps) + N = length(rp.timesteps) # If there is no time block specification, use default of 1 [k:k for k ∈ 1:N] else - _parse_rp_partition(Val(df[j, :specification]), df[j, :partition], rp.time_steps) + _parse_rp_partition(Val(df[j, :specification]), df[j, :partition], rp.timesteps) end end end @@ -579,13 +574,13 @@ end compute_flows_partitions!(partitions, df, u, v, representative_periods) Parses the time blocks in the DataFrame `df` for the flow `(u, v)` and every -representative period in the `time_steps_per_rp` dictionary, modifying the +representative period in the `timesteps_per_rp` dictionary, modifying the input `partitions`. `partitions` must be a dictionary indexed by the representative periods, possibly empty. -`time_steps_per_rp` must be a dictionary indexed by `rp` and its values are the +`timesteps_per_rp` must be a dictionary indexed by `rp` and its values are the time steps of that `rp`. To obtain the partitions, the columns `specification` and `partition` from `df` @@ -596,11 +591,11 @@ function compute_flows_partitions!(partitions, df, u, v, representative_periods) # Look for index in df that matches this asset and rp j = findfirst((df.from_asset .== u) .& (df.to_asset .== v) .& (df.rep_period .== rp_id)) partitions[rp_id] = if j === nothing - N = length(rp.time_steps) + N = length(rp.timesteps) # If there is no time block specification, use default of 1 [k:k for k ∈ 1:N] else - _parse_rp_partition(Val(df[j, :specification]), df[j, :partition], rp.time_steps) + _parse_rp_partition(Val(df[j, :specification]), df[j, :partition], rp.timesteps) end end end diff --git a/src/solve-model.jl b/src/solve-model.jl index 7daba81c..ee47b1ea 100644 --- a/src/solve-model.jl +++ b/src/solve-model.jl @@ -39,13 +39,13 @@ function solve_model!( end for row in eachrow(energy_problem.dataframes[:lowest_storage_level_intra_rp]) - a, rp, time_block, value = row.asset, row.rp, row.time_block, row.solution - graph[a].storage_level_intra_rp[(rp, time_block)] = value + a, rp, timesteps_block, value = row.asset, row.rp, row.timesteps_block, row.solution + graph[a].storage_level_intra_rp[(rp, timesteps_block)] = value end for row in eachrow(energy_problem.dataframes[:storage_level_inter_rp]) - a, bp, value = row.asset, row.base_period_block, row.solution - graph[a].storage_level_inter_rp[bp] = value + a, pb, value = row.asset, row.periods_block, row.solution + graph[a].storage_level_inter_rp[pb] = value end for (u, v) in MetaGraphsNext.edge_labels(graph) @@ -60,8 +60,9 @@ function solve_model!( end for row in eachrow(energy_problem.dataframes[:flows]) - u, v, rp, time_block, value = row.from, row.to, row.rp, row.time_block, row.solution - graph[u, v].flow[(rp, time_block)] = value + u, v, rp, timesteps_block, value = + row.from, row.to, row.rp, row.timesteps_block, row.solution + graph[u, v].flow[(rp, timesteps_block)] = value end return energy_problem.solution @@ -117,26 +118,26 @@ The `solution` object is a NamedTuple with the following fields: ``` [solution.flows_investment[(u, v)] for (u, v) in edge_labels(graph) if graph[u, v].investable] ``` - - `flow[(u, v), rp, time_block]`: The flow value for a given flow `(u, v)` at a given representative period - `rp`, and time block `time_block`. The list of time blocks is defined by `graph[(u, v)].partitions[rp]`. + - `flow[(u, v), rp, timesteps_block]`: The flow value for a given flow `(u, v)` at a given representative period + `rp`, and time block `timesteps_block`. The list of time blocks is defined by `graph[(u, v)].partitions[rp]`. To create a vector with all values of `flow` for a given `(u, v)` and `rp`, one can run ``` - [solution.flow[(u, v), rp, time_block] for time_block in graph[u, v].partitions[rp]] + [solution.flow[(u, v), rp, timesteps_block] for timesteps_block in graph[u, v].partitions[rp]] ``` - - `storage_level_intra_rp[a, rp, time_block]`: The storage level for the storage asset `a` for a representative period `rp` - and a time block `time_block`. The list of time blocks is defined by `constraints_partitions`, which was used + - `storage_level_intra_rp[a, rp, timesteps_block]`: The storage level for the storage asset `a` for a representative period `rp` + and a time block `timesteps_block`. The list of time blocks is defined by `constraints_partitions`, which was used to create the model. To create a vector with the all values of `storage_level_intra_rp` for a given `a` and `rp`, one can run ``` - [solution.storage_level_intra_rp[a, rp, time_block] for time_block in constraints_partitions[:lowest_resolution][(a, rp)]] + [solution.storage_level_intra_rp[a, rp, timesteps_block] for timesteps_block in constraints_partitions[:lowest_resolution][(a, rp)]] ``` -- `storage_level_inter_rp[a, bp]`: The storage level for the storage asset `a` for a base period `bp`. +- `storage_level_inter_rp[a, pb]`: The storage level for the storage asset `a` for a periods block `pb`. To create a vector with the all values of `storage_level_inter_rp` for a given `a`, one can run ``` - [solution.storage_level_inter_rp[a, bp] for bp in 1:base_periods] + [solution.storage_level_inter_rp[a, bp] for bp in graph[a].timeframe_partitions[a]] ``` ## Examples diff --git a/src/structures.jl b/src/structures.jl index 3c9d2559..1273bda3 100644 --- a/src/structures.jl +++ b/src/structures.jl @@ -1,13 +1,15 @@ -export GraphAssetData, GraphFlowData, EnergyProblem, RepresentativePeriod, BasePeriod, TimeBlock +export GraphAssetData, + GraphFlowData, EnergyProblem, RepresentativePeriod, PeriodsBlock, TimestepsBlock, Timeframe -const TimeBlock = UnitRange{Int} +const TimestepsBlock = UnitRange{Int} +const PeriodsBlock = UnitRange{Int} """ -Structure to hold the data of the base periods. +Structure to hold the data of the timeframe. """ -struct BasePeriod - num_base_periods::Int64 - rp_mapping_df::DataFrame +struct Timeframe + num_periods::Int64 + map_periods_to_rp::DataFrame end """ @@ -16,12 +18,12 @@ Structure to hold the data of one representative period. struct RepresentativePeriod mapping::Union{Nothing,Dict{Int,Float64}} # which periods in the full problem formulation does this RP stand for weight::Float64 - time_steps::TimeBlock + timesteps::TimestepsBlock resolution::Float64 - function RepresentativePeriod(mapping, num_time_steps, resolution) + function RepresentativePeriod(mapping, num_timesteps, resolution) weight = sum(values(mapping)) - return new(mapping, weight, 1:num_time_steps, resolution) + return new(mapping, weight, 1:num_timesteps, resolution) end end @@ -42,14 +44,14 @@ mutable struct GraphAssetData initial_storage_capacity::Float64 initial_storage_level::Union{Missing,Float64} energy_to_power_ratio::Float64 - base_periods_profiles::Dict{Symbol,Vector{Float64}} + timeframe_profiles::Dict{Symbol,Vector{Float64}} rep_periods_profiles::Dict{Tuple{Symbol,Int},Vector{Float64}} - base_periods_partitions::Vector{TimeBlock} - rep_periods_partitions::Dict{Int,Vector{TimeBlock}} + timeframe_partitions::Vector{PeriodsBlock} + rep_periods_partitions::Dict{Int,Vector{TimestepsBlock}} # Solution investment::Float64 - storage_level_intra_rp::Dict{Tuple{Int,TimeBlock},Float64} - storage_level_inter_rp::Dict{TimeBlock,Float64} + storage_level_intra_rp::Dict{Tuple{Int,TimestepsBlock},Float64} + storage_level_inter_rp::Dict{PeriodsBlock,Float64} # You don't need profiles to create the struct, so initiate it empty function GraphAssetData( @@ -67,10 +69,10 @@ mutable struct GraphAssetData initial_storage_level, energy_to_power_ratio, ) - base_periods_profiles = Dict{Symbol,Vector{Float64}}() + timeframe_profiles = Dict{Symbol,Vector{Float64}}() rep_periods_profiles = Dict{Tuple{Symbol,Int},Vector{Float64}}() - base_periods_partitions = TimeBlock[] - rep_periods_partitions = Dict{Int,Vector{TimeBlock}}() + timeframe_partitions = PeriodsBlock[] + rep_periods_partitions = Dict{Int,Vector{TimestepsBlock}}() return new( type, investable, @@ -85,13 +87,13 @@ mutable struct GraphAssetData initial_storage_capacity, initial_storage_level, energy_to_power_ratio, - base_periods_profiles, + timeframe_profiles, rep_periods_profiles, - base_periods_partitions, + timeframe_partitions, rep_periods_partitions, -1, - Dict{Tuple{Int,TimeBlock},Float64}(), - Dict{TimeBlock,Float64}(), + Dict{Tuple{Int,TimestepsBlock},Float64}(), + Dict{TimestepsBlock,Float64}(), ) end end @@ -112,12 +114,12 @@ mutable struct GraphFlowData initial_export_capacity::Float64 initial_import_capacity::Float64 efficiency::Float64 - base_periods_profiles::Dict{Symbol,Vector{Float64}} + timeframe_profiles::Dict{Symbol,Vector{Float64}} rep_periods_profiles::Dict{Tuple{Symbol,Int},Vector{Float64}} - base_periods_partitions::Vector{TimeBlock} - rep_periods_partitions::Dict{Int,Vector{TimeBlock}} + timeframe_partitions::Vector{PeriodsBlock} + rep_periods_partitions::Dict{Int,Vector{TimestepsBlock}} # Solution - flow::Dict{Tuple{Int,TimeBlock},Float64} + flow::Dict{Tuple{Int,TimestepsBlock},Float64} investment::Float64 end @@ -150,9 +152,9 @@ function GraphFlowData( efficiency, Dict{Symbol,Vector{Float64}}(), Dict{Tuple{Symbol,Int},Vector{Float64}}(), - TimeBlock[], - Dict{Int,Vector{TimeBlock}}(), - Dict{Tuple{Int,TimeBlock},Float64}(), + PeriodsBlock[], + Dict{Int,Vector{TimestepsBlock}}(), + Dict{Tuple{Int,TimestepsBlock},Float64}(), -1, ) end @@ -175,7 +177,7 @@ It hides the complexity behind the energy problem, making the usage more friendl - `graph`: The [Graph](@ref) object that defines the geometry of the energy problem. - `representative_periods`: A vector of [Representative Periods](@ref representative-periods). - `constraints_partitions`: Dictionaries that connect pairs of asset and representative periods to [time partitions (vectors of time blocks)](@ref Partition) -- `base_periods`: The number of periods of the `representative_periods`. +- `timeframe`: The number of periods of the `representative_periods`. - `dataframes`: The data frames used to linearize the variables and constraints. These are used internally in the model only. - `model`: A JuMP.Model object representing the optimization model. - `solved`: A boolean indicating whether the `model` has been solved or not. @@ -187,7 +189,7 @@ It hides the complexity behind the energy problem, making the usage more friendl # Constructor -- `EnergyProblem(graph, representative_periods, base_periods)`: Constructs a new `EnergyProblem` object with the given graph, representative periods, and base periods. The `constraints_partitions` field is computed from the `representative_periods`, and the other fields are initialized with default values. +- `EnergyProblem(graph, representative_periods, timeframe)`: Constructs a new `EnergyProblem` object with the given graph, representative periods, and timeframe. The `constraints_partitions` field is computed from the `representative_periods`, and the other fields are initialized with default values. See the [basic example tutorial](@ref basic-example) to see how these can be used. """ @@ -203,8 +205,8 @@ mutable struct EnergyProblem Nothing, # Default edge weight } representative_periods::Vector{RepresentativePeriod} - constraints_partitions::Dict{Symbol,Dict{Tuple{Symbol,Int},Vector{TimeBlock}}} - base_periods::BasePeriod + constraints_partitions::Dict{Symbol,Dict{Tuple{Symbol,Int},Vector{TimestepsBlock}}} + timeframe::Timeframe dataframes::Dict{Symbol,DataFrame} model::Union{JuMP.Model,Nothing} solution::Union{Solution,Nothing} @@ -216,19 +218,19 @@ mutable struct EnergyProblem time_solve_model::Float64 """ - EnergyProblem(graph, representative_periods, base_periods) + EnergyProblem(graph, representative_periods, timeframe) - Constructs a new EnergyProblem object with the given graph, representative periods, and base periods. The `constraints_partitions` field is computed from the `representative_periods`, + Constructs a new EnergyProblem object with the given graph, representative periods, and timeframe. The `constraints_partitions` field is computed from the `representative_periods`, and the other fields and nothing or set to default values. """ - function EnergyProblem(graph, representative_periods, base_periods) + function EnergyProblem(graph, representative_periods, timeframe) constraints_partitions = compute_constraints_partitions(graph, representative_periods) return new( graph, representative_periods, constraints_partitions, - base_periods, + timeframe, Dict(), nothing, nothing, diff --git a/src/time-resolution.jl b/src/time-resolution.jl index c64957c2..5fb2e322 100644 --- a/src/time-resolution.jl +++ b/src/time-resolution.jl @@ -14,7 +14,7 @@ For each asset and representative period, it calls the `compute_rp_partition` fu to compute the partition based on the strategy. """ function compute_constraints_partitions(graph, representative_periods) - constraints_partitions = Dict{Symbol,Dict{Tuple{Symbol,Int},Vector{TimeBlock}}}() + constraints_partitions = Dict{Symbol,Dict{Tuple{Symbol,Int},Vector{TimestepsBlock}}}() _inflows(a, rp) = [graph[u, a].rep_periods_partitions[rp] for u in MetaGraphsNext.inneighbor_labels(graph, a)] @@ -67,7 +67,7 @@ function compute_constraints_partitions(graph, representative_periods) if length(P) > 0 compute_rp_partition(partitions(a, rp), strategy) else - Vector{TimeBlock}[] + Vector{TimestepsBlock}[] end end for a in MetaGraphsNext.labels(graph), rp = 1:num_rep_periods if asset_filter(a) ) @@ -206,8 +206,8 @@ function compute_rp_partition( block_end = block_start for partition in partitions # For this partition, find the first block that ends after block_start - for time_block in partition - tentative_end = time_block[end] + for timesteps_block in partition + tentative_end = timesteps_block[end] if tentative_end ≥ block_start if tentative_end > block_end # Better block block_end = tentative_end diff --git a/test/inputs/Norse/assets-base-periods-partitions.csv b/test/inputs/Norse/assets-timeframe-partitions.csv similarity index 100% rename from test/inputs/Norse/assets-base-periods-partitions.csv rename to test/inputs/Norse/assets-timeframe-partitions.csv diff --git a/test/inputs/Norse/assets-base-periods-profiles.csv b/test/inputs/Norse/assets-timeframe-profiles.csv similarity index 100% rename from test/inputs/Norse/assets-base-periods-profiles.csv rename to test/inputs/Norse/assets-timeframe-profiles.csv diff --git a/test/inputs/Norse/profiles-rep-periods-availability.csv b/test/inputs/Norse/profiles-rep-periods-availability.csv index 14a9150f..e4424e38 100644 --- a/test/inputs/Norse/profiles-rep-periods-availability.csv +++ b/test/inputs/Norse/profiles-rep-periods-availability.csv @@ -1,5 +1,5 @@ ,,,p.u. -profile_name,rep_period,time_step,value +profile_name,rep_period,timestep,value Asgard_Solar,1,1,0.0 Asgard_Solar,1,2,0.0 Asgard_Solar,1,3,0.0 diff --git a/test/inputs/Norse/profiles-rep-periods-demand.csv b/test/inputs/Norse/profiles-rep-periods-demand.csv index 832bb3d5..f2c45414 100644 --- a/test/inputs/Norse/profiles-rep-periods-demand.csv +++ b/test/inputs/Norse/profiles-rep-periods-demand.csv @@ -1,5 +1,5 @@ ,,,p.u. -profile_name,rep_period,time_step,value +profile_name,rep_period,timestep,value Asgard_E_demand,1,1,0.516087278 Asgard_E_demand,1,2,0.491576652 Asgard_E_demand,1,3,0.465411058 diff --git a/test/inputs/Norse/profiles-rep-periods-inflows.csv b/test/inputs/Norse/profiles-rep-periods-inflows.csv index 9b01c5af..7f1fa37f 100644 --- a/test/inputs/Norse/profiles-rep-periods-inflows.csv +++ b/test/inputs/Norse/profiles-rep-periods-inflows.csv @@ -1,5 +1,5 @@ ,,,p.u. -profile_name,rep_period,time_step,value +profile_name,rep_period,timestep,value Midgard_Hydro,1,1,0.0001 Midgard_Hydro,1,2,0.0001 Midgard_Hydro,1,3,0.0001 diff --git a/test/inputs/Norse/profiles-base-periods-max-storage-level.csv b/test/inputs/Norse/profiles-timeframe-max-storage-level.csv similarity index 99% rename from test/inputs/Norse/profiles-base-periods-max-storage-level.csv rename to test/inputs/Norse/profiles-timeframe-max-storage-level.csv index ba5fa406..b2f10aaa 100644 --- a/test/inputs/Norse/profiles-base-periods-max-storage-level.csv +++ b/test/inputs/Norse/profiles-timeframe-max-storage-level.csv @@ -1,5 +1,5 @@ ,,p.u. -profile_name,base_period,value +profile_name,period,value Midgard_Hydro,1,0.95 Midgard_Hydro,2,0.95 Midgard_Hydro,3,0.95 diff --git a/test/inputs/Norse/profiles-base-periods-min-storage-level.csv b/test/inputs/Norse/profiles-timeframe-min-storage-level.csv similarity index 99% rename from test/inputs/Norse/profiles-base-periods-min-storage-level.csv rename to test/inputs/Norse/profiles-timeframe-min-storage-level.csv index de46510d..2d80180a 100644 --- a/test/inputs/Norse/profiles-base-periods-min-storage-level.csv +++ b/test/inputs/Norse/profiles-timeframe-min-storage-level.csv @@ -1,5 +1,5 @@ ,,p.u. -profile_name,base_period,value +profile_name,period,value Midgard_Hydro,1,0.40 Midgard_Hydro,2,0.40 Midgard_Hydro,3,0.40 diff --git a/test/inputs/Norse/rep-periods-data.csv b/test/inputs/Norse/rep-periods-data.csv index ebb6e12b..f27004e1 100644 --- a/test/inputs/Norse/rep-periods-data.csv +++ b/test/inputs/Norse/rep-periods-data.csv @@ -1,4 +1,4 @@ ,,hours -id,num_time_steps,resolution +id,num_timesteps,resolution 1,168,1.0 2,24,1.0 diff --git a/test/inputs/Tiny/assets-base-periods-partitions.csv b/test/inputs/Tiny/assets-timeframe-partitions.csv similarity index 100% rename from test/inputs/Tiny/assets-base-periods-partitions.csv rename to test/inputs/Tiny/assets-timeframe-partitions.csv diff --git a/test/inputs/Tiny/assets-base-periods-profiles.csv b/test/inputs/Tiny/assets-timeframe-profiles.csv similarity index 100% rename from test/inputs/Tiny/assets-base-periods-profiles.csv rename to test/inputs/Tiny/assets-timeframe-profiles.csv diff --git a/test/inputs/Tiny/flows-base-periods-partitions.csv b/test/inputs/Tiny/flows-timeframe-partitions.csv similarity index 100% rename from test/inputs/Tiny/flows-base-periods-partitions.csv rename to test/inputs/Tiny/flows-timeframe-partitions.csv diff --git a/test/inputs/Tiny/flows-base-periods-profiles.csv b/test/inputs/Tiny/flows-timeframe-profiles.csv similarity index 100% rename from test/inputs/Tiny/flows-base-periods-profiles.csv rename to test/inputs/Tiny/flows-timeframe-profiles.csv diff --git a/test/inputs/Tiny/profiles-rep-periods-availability.csv b/test/inputs/Tiny/profiles-rep-periods-availability.csv index f4c501ba..b89fcec7 100644 --- a/test/inputs/Tiny/profiles-rep-periods-availability.csv +++ b/test/inputs/Tiny/profiles-rep-periods-availability.csv @@ -1,5 +1,5 @@ ,,,p.u. -profile_name,rep_period,time_step,value +profile_name,rep_period,timestep,value wind,1,1,0.11 wind,1,2,0.11 wind,1,3,0.11 diff --git a/test/inputs/Tiny/profiles-rep-periods-demand.csv b/test/inputs/Tiny/profiles-rep-periods-demand.csv index 19aadfac..502300db 100644 --- a/test/inputs/Tiny/profiles-rep-periods-demand.csv +++ b/test/inputs/Tiny/profiles-rep-periods-demand.csv @@ -1,5 +1,5 @@ ,,,p.u. -profile_name,rep_period,time_step,value +profile_name,rep_period,timestep,value demand,1,1,0.852017937 demand,1,2,0.780269058 demand,1,3,0.730044843 diff --git a/test/inputs/Tiny/rep-periods-data.csv b/test/inputs/Tiny/rep-periods-data.csv index 867bfdd0..5b784cd1 100644 --- a/test/inputs/Tiny/rep-periods-data.csv +++ b/test/inputs/Tiny/rep-periods-data.csv @@ -1,5 +1,5 @@ ,,hours -id,num_time_steps,resolution +id,num_timesteps,resolution 1,24,1.0 2,24,1.0 3,24,1.0 diff --git a/test/inputs/Variable Resolution/assets-base-periods-partitions.csv b/test/inputs/Variable Resolution/assets-timeframe-partitions.csv similarity index 100% rename from test/inputs/Variable Resolution/assets-base-periods-partitions.csv rename to test/inputs/Variable Resolution/assets-timeframe-partitions.csv diff --git a/test/inputs/Variable Resolution/assets-base-periods-profiles.csv b/test/inputs/Variable Resolution/assets-timeframe-profiles.csv similarity index 100% rename from test/inputs/Variable Resolution/assets-base-periods-profiles.csv rename to test/inputs/Variable Resolution/assets-timeframe-profiles.csv diff --git a/test/inputs/Variable Resolution/flows-base-periods-partitions.csv b/test/inputs/Variable Resolution/flows-timeframe-partitions.csv similarity index 100% rename from test/inputs/Variable Resolution/flows-base-periods-partitions.csv rename to test/inputs/Variable Resolution/flows-timeframe-partitions.csv diff --git a/test/inputs/Variable Resolution/flows-base-periods-profiles.csv b/test/inputs/Variable Resolution/flows-timeframe-profiles.csv similarity index 100% rename from test/inputs/Variable Resolution/flows-base-periods-profiles.csv rename to test/inputs/Variable Resolution/flows-timeframe-profiles.csv diff --git a/test/inputs/Variable Resolution/profiles-rep-periods-availability.csv b/test/inputs/Variable Resolution/profiles-rep-periods-availability.csv index 121e21f0..4bd33561 100644 --- a/test/inputs/Variable Resolution/profiles-rep-periods-availability.csv +++ b/test/inputs/Variable Resolution/profiles-rep-periods-availability.csv @@ -1,5 +1,5 @@ ,,,p.u. -profile_name,rep_period,time_step,value +profile_name,rep_period,timestep,value wind,1,1,0.11 wind,1,2,0.11 wind,1,3,0.11 diff --git a/test/inputs/Variable Resolution/profiles-rep-periods-demand.csv b/test/inputs/Variable Resolution/profiles-rep-periods-demand.csv index 7c395d62..f24e43db 100644 --- a/test/inputs/Variable Resolution/profiles-rep-periods-demand.csv +++ b/test/inputs/Variable Resolution/profiles-rep-periods-demand.csv @@ -1,5 +1,5 @@ ,,,p.u. -profile_name,rep_period,time_step,value +profile_name,rep_period,timestep,value demand,1,1,0.85 demand,1,2,0.85 demand,1,3,0.85 diff --git a/test/inputs/Variable Resolution/rep-periods-data.csv b/test/inputs/Variable Resolution/rep-periods-data.csv index ffbcd0d8..b8c7556d 100644 --- a/test/inputs/Variable Resolution/rep-periods-data.csv +++ b/test/inputs/Variable Resolution/rep-periods-data.csv @@ -1,3 +1,3 @@ ,,hours -id,num_time_steps,resolution +id,num_timesteps,resolution 1,6,1.0 diff --git a/test/test-io.jl b/test/test-io.jl index d03aa089..5e5e3944 100644 --- a/test/test-io.jl +++ b/test/test-io.jl @@ -42,8 +42,7 @@ end @testset "Graph structure" begin @testset "Graph structure is correct" begin dir = joinpath(INPUT_FOLDER, "Tiny") - graph, representative_periods, base_periods = - create_graph_and_representative_periods_from_csv_folder(dir) + graph, _, _ = create_graph_and_representative_periods_from_csv_folder(dir) @test Graphs.nv(graph) == 6 @test Graphs.ne(graph) == 5 @@ -133,7 +132,7 @@ end cp(joinpath(root, file), joinpath(dir, file)) end end - filename = joinpath(dir, "assets-base-periods-partitions.csv") + filename = joinpath(dir, "assets-timeframe-partitions.csv") lines = readlines(filename) open(filename, "w") do io for line in lines[1:end-1] @@ -142,6 +141,6 @@ end end missing_asset = Symbol(split(lines[end], ",")[1]) # The asset the was not included - graph, rps, bps = create_graph_and_representative_periods_from_csv_folder(dir) - @test graph[missing_asset].base_periods_partitions == [i:i for i = 1:bps.num_base_periods] + graph, rps, tf = create_graph_and_representative_periods_from_csv_folder(dir) + @test graph[missing_asset].timeframe_partitions == [i:i for i = 1:tf.num_periods] end