Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/create-model.jl
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ function create_model(
model,
variables,
expressions,
profiles,
model_parameters,
)

Expand Down
3 changes: 2 additions & 1 deletion src/input-schemas.json
Original file line number Diff line number Diff line change
Expand Up @@ -686,7 +686,8 @@
"profile_type": {
"constraints": {
"oneOf": [
"availability"
"availability",
"commodity_price"
]
},
"description": "Type of profile, used to determine DuckDB table with source profile",
Expand Down
39 changes: 32 additions & 7 deletions src/objective.jl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
function add_objective!(connection, model, variables, expressions, model_parameters)
function add_objective!(connection, model, variables, expressions, profiles, model_parameters)
assets_investment = variables[:assets_investment]
assets_investment_energy = variables[:assets_investment_energy]
flows_investment = variables[:flows_investment]
Expand Down Expand Up @@ -230,9 +230,15 @@ function add_objective!(connection, model, variables, expressions, model_paramet
obj.weight_for_operation_discounts
* rp_weight.weight_sum
* rp_res.resolution
* (var.time_block_end - var.time_block_start + 1)
* obj.total_variable_cost
AS cost,
AS cost_coefficient,
var.time_block_start,
var.time_block_end,
var.year,
var.rep_period,
obj.commodity_price,
obj.efficiency,
obj.operational_cost,
commodity_price_profiles.profile_name,
FROM var_flow AS var
LEFT JOIN t_objective_flows as obj
ON var.from_asset = obj.from_asset
Expand All @@ -246,6 +252,11 @@ function add_objective!(connection, model, variables, expressions, model_paramet
AND var.rep_period = rp_res.rep_period
LEFT JOIN asset
ON asset.asset = var.from_asset
LEFT JOIN flows_profiles AS commodity_price_profiles
ON commodity_price_profiles.from_asset = var.from_asset
AND commodity_price_profiles.to_asset = var.to_asset
AND commodity_price_profiles.year = var.year
AND commodity_price_profiles.profile_type = 'commodity_price' -- TODO: inconsistent year naming to assets_profiles
WHERE asset.investment_method != 'semi-compact'
",
)
Expand All @@ -255,7 +266,23 @@ function add_objective!(connection, model, variables, expressions, model_paramet
# i.e., we only consider the costs of the flows that are not in semi-compact method
var_flow = variables[:flow].container

flows_operational_cost = @expression(model, sum(row.cost * var_flow[row.id] for row in indices))
flows_operational_cost = @expression(
model,
sum(
row.cost_coefficient *
(
row.commodity_price * _profile_aggregate( # commodity_price aggregation
profiles.rep_period,
(row.profile_name, row.year, row.rep_period),
row.time_block_start:row.time_block_end,
sum,
1.0,
) / row.efficiency +
row.operational_cost * (row.time_block_end - row.time_block_start + 1)
) *
var_flow[row.id] for row in indices
)
)

indices = DuckDB.query(
connection,
Expand Down Expand Up @@ -529,8 +556,6 @@ function _create_objective_auxiliary_table(connection, constants)
asset_commission.efficiency,
flow_milestone.operational_cost,
-- computed
(asset_milestone.commodity_price / asset_commission.efficiency) AS fuel_cost,
(fuel_cost + flow_milestone.operational_cost) AS total_variable_cost,
CASE
-- the below closed-form equation does not accept 0 in the denominator when flow.discount_rate = 0
WHEN flow.discount_rate = 0
Expand Down
54 changes: 54 additions & 0 deletions test/test-objective-profiles.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
@testitem "Commodity price is used correctly" setup = [CommonSetup] tags = [:case_study, :slow] begin
dir = joinpath(INPUT_FOLDER, "MIMO")
connection = DBInterface.connect(DuckDB.DB)
_read_csv_folder(connection, dir)

TulipaEnergyModel.populate_with_defaults!(connection)

# Copied over from test-case-studies.jl
energy_problem = TulipaEnergyModel.run_scenario(connection; show_log = false)
@test energy_problem.objective_value ≈ 89360.638146 atol = 1e-5

# Changing commodity_price to make sure it makes a difference
DuckDB.query(
connection,
"""
UPDATE asset_milestone
SET commodity_price = 10.0
WHERE asset = 'biomass'
""",
)
energy_problem = TulipaEnergyModel.run_scenario(connection; show_log = false)
@test energy_problem.objective_value ≈ 89971.40505 atol = 1e-5

# Testing commodity_price profile
# We duplicate the biomass_profile replacing the value
DuckDB.query(
connection,
"""
WITH cte_one_profile AS (
SELECT
profiles_rep_periods.* EXCLUDE (profile_name, value)
FROM profiles_rep_periods
WHERE profile_name = 'biomass_profile'
)
INSERT INTO profiles_rep_periods BY NAME
SELECT
'commodity_price' AS profile_name,
0.1 AS value,
cte_one_profile.*,
FROM cte_one_profile
""",
)
# Now we assign it to a flow
DuckDB.query(
connection,
"""
INSERT INTO flows_profiles (from_asset, to_asset, year, profile_type, profile_name)
VALUES ('biomass', 'power_plant', 2030, 'commodity_price', 'commodity_price');
""",
)

energy_problem = TulipaEnergyModel.run_scenario(connection; show_log = false)
@test energy_problem.objective_value ≈ 89421.71484 atol = 1e-5
end
Loading