Skip to content
Merged
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
6 changes: 3 additions & 3 deletions src/datastructures.jl
Original file line number Diff line number Diff line change
Expand Up @@ -498,14 +498,14 @@ function MultipleBuildingTypes(
# Filter demands based on buildings and time period. Also convert the format of demands from
# Dict{String, Vector{Dict}} to Dict{Resource, Vector{Float64}} and scale results to MW
for building ∈ buildings
temp = Dict{Any,Vector{Any}}(val => Any[] for val ∈ values(resources_map))
temp = Dict{Any,Vector{Any}}(val => Any[] for val ∈ keys(resources_map))

for v ∈ demands_orig_format[building]
date = DateTime(v["Datetime"], "yyyy-mm-dd HH:MM")
if time_start <= date && date <= time_end
for (res, res_val) ∈ v
if !(res ∈ ["Datetime", "Variable cost [€]", "Emissions [KgCO2]"])
push!(temp[resources_map[res]], res_val/1e6) # Scale power_outputs to MW
push!(temp[res], res_val/1e6) # Scale power_outputs to MW
end
end
end
Expand All @@ -520,7 +520,7 @@ function MultipleBuildingTypes(
# Sum the demands for all building types
for val ∈ values(demands)
for (res, demand) ∈ val
cap_vec[res] += demand
cap_vec[resources_map[res]] += demand
end
end

Expand Down
189 changes: 97 additions & 92 deletions test/test_CSPandPV.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,97 +3,102 @@ using JSON
using Dates

@testset "CSPandPV" begin
case, modeltype = simple_graph_csp_pv()

csp_and_pv_plant = get_node(case, "CSP and PV plant") # The MultipleBuildingTypes node
𝒫 = setdiff(get_products(case), [CO2])

# Run the model
m = EMB.run_model(case, modeltype, OPTIMIZER)

# Extraction of the time structure
𝒯 = get_time_struct(case)

# Run of the general tests
general_tests(m)

# Test that curtailment is correctly with respect to the profile.
@test sum(value.(m[:solar_curtailment][csp_and_pv_plant, t, Power]) > 0.0 for t ∈ 𝒯) ==
102

# Test constraints from EMB.constraints_capacity
@test sum(
value.(m[:solar_cap_use][csp_and_pv_plant, t, p]) ≤
EMB.capacity(csp_and_pv_plant, t, p) for t ∈ 𝒯, p ∈ 𝒫
) == length(𝒯) * length(𝒫)

@test sum(
value.(m[:solar_cap_use][csp_and_pv_plant, t, p]) +
value.(m[:solar_curtailment][csp_and_pv_plant, t, p]) ≈
EMRP.profile(csp_and_pv_plant, t, p) *
EMB.capacity(csp_and_pv_plant, t, p) for t ∈ 𝒯, p ∈ 𝒫
) == length(𝒯) * length(𝒫)

@test sum(
sum(value.(m[:solar_curtailment][csp_and_pv_plant, t, p]) for p ∈ 𝒫) ≈
value(m[:curtailment][csp_and_pv_plant, t]) for t ∈ 𝒯
) == length(𝒯)

# Test constraints frmo EMB.constraints_flow_out
@test sum(
value(m[:flow_out][csp_and_pv_plant, t, p]) ≈
value(m[:solar_cap_use][csp_and_pv_plant, t, p]) * outputs(csp_and_pv_plant, p) for
t ∈ 𝒯, p ∈ 𝒫
) == length(𝒯) * length(𝒫)

# Test constraints from EMB.constraints_opex_var
𝒯ᴵⁿᵛ = strategic_periods(𝒯)
@test sum(
value(m[:opex_var][csp_and_pv_plant, t_inv]) ≈
sum(
value(m[:solar_cap_use][csp_and_pv_plant, t, p]) *
EMB.opex_var(csp_and_pv_plant, t, p) *
scale_op_sp(t_inv, t) for t ∈ t_inv, p ∈ outputs(csp_and_pv_plant)
) for t_inv ∈ 𝒯ᴵⁿᵛ
) == length(𝒯ᴵⁿᵛ)

# Test constraints from EMB.constraints_opex_fixed
@test sum(
value(m[:opex_fixed][csp_and_pv_plant, t_inv]) ≈
sum(
EMB.opex_fixed(csp_and_pv_plant, t_inv, p) *
EMB.capacity(csp_and_pv_plant, first(t_inv), p) for
p ∈ outputs(csp_and_pv_plant)
) for t_inv ∈ 𝒯ᴵⁿᵛ
) == length(𝒯ᴵⁿᵛ)

# Test that the EMB function has_capacity is false for the CSPandPV node.
@test !EMB.has_capacity(csp_and_pv_plant)

# Test the utility functions
for p ∈ 𝒫
# Capacity
@test EMB.capacity(csp_and_pv_plant, p) isa TimeProfile
@test EMB.capacity(csp_and_pv_plant)[p] == EMB.capacity(csp_and_pv_plant, p)
@test EMB.capacity(csp_and_pv_plant, first(𝒯), p) ==
EMB.capacity(csp_and_pv_plant, p)[first(𝒯)]

# OPEX variable
@test EMB.opex_var(csp_and_pv_plant, p) isa TimeProfile
@test EMB.opex_var(csp_and_pv_plant)[p] == EMB.opex_var(csp_and_pv_plant, p)
@test EMB.opex_var(csp_and_pv_plant, first(𝒯), p) ==
EMB.opex_var(csp_and_pv_plant, p)[first(𝒯)]

# OPEX fixed
@test EMB.opex_fixed(csp_and_pv_plant, p) isa TimeProfile
@test EMB.opex_fixed(csp_and_pv_plant)[p] == EMB.opex_fixed(csp_and_pv_plant, p)
@test EMB.opex_fixed(csp_and_pv_plant, first(𝒯ᴵⁿᵛ), p) ==
EMB.opex_fixed(csp_and_pv_plant, p)[first(𝒯ᴵⁿᵛ)]

# Profile
@test EMRP.profile(csp_and_pv_plant, p) isa TimeProfile
@test EMRP.profile(csp_and_pv_plant)[p] == EMRP.profile(csp_and_pv_plant, p)
@test EMRP.profile(csp_and_pv_plant, first(𝒯), p) ==
EMRP.profile(csp_and_pv_plant, p)[first(𝒯)]
for _ ∈ 1:2 # Run the test two times to also test running from stored files (from first run)
case, modeltype = simple_graph_csp_pv()

csp_and_pv_plant = get_node(case, "CSP and PV plant") # The MultipleBuildingTypes node
𝒫 = setdiff(get_products(case), [CO2])

# Run the model
m = EMB.run_model(case, modeltype, OPTIMIZER)

# Extraction of the time structure
𝒯 = get_time_struct(case)

# Run of the general tests
general_tests(m)

# Test that curtailment is correctly with respect to the profile.
@test sum(
value.(m[:solar_curtailment][csp_and_pv_plant, t, Power]) > 0.0 for t ∈ 𝒯
) ==
102

# Test constraints from EMB.constraints_capacity
@test sum(
value.(m[:solar_cap_use][csp_and_pv_plant, t, p]) ≤
EMB.capacity(csp_and_pv_plant, t, p) for t ∈ 𝒯, p ∈ 𝒫
) == length(𝒯) * length(𝒫)

@test sum(
value.(m[:solar_cap_use][csp_and_pv_plant, t, p]) +
value.(m[:solar_curtailment][csp_and_pv_plant, t, p]) ≈
EMRP.profile(csp_and_pv_plant, t, p) *
EMB.capacity(csp_and_pv_plant, t, p) for t ∈ 𝒯, p ∈ 𝒫
) == length(𝒯) * length(𝒫)

@test sum(
sum(value.(m[:solar_curtailment][csp_and_pv_plant, t, p]) for p ∈ 𝒫) ≈
value(m[:curtailment][csp_and_pv_plant, t]) for t ∈ 𝒯
) == length(𝒯)

# Test constraints frmo EMB.constraints_flow_out
@test sum(
value(m[:flow_out][csp_and_pv_plant, t, p]) ≈
value(m[:solar_cap_use][csp_and_pv_plant, t, p]) * outputs(csp_and_pv_plant, p)
for
t ∈ 𝒯, p ∈ 𝒫
) == length(𝒯) * length(𝒫)

# Test constraints from EMB.constraints_opex_var
𝒯ᴵⁿᵛ = strategic_periods(𝒯)
@test sum(
value(m[:opex_var][csp_and_pv_plant, t_inv]) ≈
sum(
value(m[:solar_cap_use][csp_and_pv_plant, t, p]) *
EMB.opex_var(csp_and_pv_plant, t, p) *
scale_op_sp(t_inv, t) for t ∈ t_inv, p ∈ outputs(csp_and_pv_plant)
) for t_inv ∈ 𝒯ᴵⁿᵛ
) == length(𝒯ᴵⁿᵛ)

# Test constraints from EMB.constraints_opex_fixed
@test sum(
value(m[:opex_fixed][csp_and_pv_plant, t_inv]) ≈
sum(
EMB.opex_fixed(csp_and_pv_plant, t_inv, p) *
EMB.capacity(csp_and_pv_plant, first(t_inv), p) for
p ∈ outputs(csp_and_pv_plant)
) for t_inv ∈ 𝒯ᴵⁿᵛ
) == length(𝒯ᴵⁿᵛ)

# Test that the EMB function has_capacity is false for the CSPandPV node.
@test !EMB.has_capacity(csp_and_pv_plant)

# Test the utility functions
for p ∈ 𝒫
# Capacity
@test EMB.capacity(csp_and_pv_plant, p) isa TimeProfile
@test EMB.capacity(csp_and_pv_plant)[p] == EMB.capacity(csp_and_pv_plant, p)
@test EMB.capacity(csp_and_pv_plant, first(𝒯), p) ==
EMB.capacity(csp_and_pv_plant, p)[first(𝒯)]

# OPEX variable
@test EMB.opex_var(csp_and_pv_plant, p) isa TimeProfile
@test EMB.opex_var(csp_and_pv_plant)[p] == EMB.opex_var(csp_and_pv_plant, p)
@test EMB.opex_var(csp_and_pv_plant, first(𝒯), p) ==
EMB.opex_var(csp_and_pv_plant, p)[first(𝒯)]

# OPEX fixed
@test EMB.opex_fixed(csp_and_pv_plant, p) isa TimeProfile
@test EMB.opex_fixed(csp_and_pv_plant)[p] == EMB.opex_fixed(csp_and_pv_plant, p)
@test EMB.opex_fixed(csp_and_pv_plant, first(𝒯ᴵⁿᵛ), p) ==
EMB.opex_fixed(csp_and_pv_plant, p)[first(𝒯ᴵⁿᵛ)]

# Profile
@test EMRP.profile(csp_and_pv_plant, p) isa TimeProfile
@test EMRP.profile(csp_and_pv_plant)[p] == EMRP.profile(csp_and_pv_plant, p)
@test EMRP.profile(csp_and_pv_plant, first(𝒯), p) ==
EMRP.profile(csp_and_pv_plant, p)[first(𝒯)]
end
end
end
149 changes: 77 additions & 72 deletions test/test_buildings.jl
Original file line number Diff line number Diff line change
@@ -1,89 +1,94 @@
@testset "MultipleBuildingTypes" begin
case, modeltype = simple_graph_buildings()
for _ ∈ 1:2 # Run the test two times to also test running from stored files (from first run)
case, modeltype = simple_graph_buildings()

buildings = get_node(case, "Buildings") # The MultipleBuildingTypes node
products = get_products(case)
building_res = products[1:(end-1)] # All resources except CO2
CO2 = products[end] # The CO2 resource
buildings = get_node(case, "Buildings") # The MultipleBuildingTypes node
products = get_products(case)
building_res = products[1:(end-1)] # All resources except CO2
CO2 = products[end] # The CO2 resource

# Run the model
m = EMB.run_model(case, modeltype, OPTIMIZER)
# Run the model
m = EMB.run_model(case, modeltype, OPTIMIZER)

# Extraction of the time structure
𝒯 = get_time_struct(case)
# Extraction of the time structure
𝒯 = get_time_struct(case)

# Run of the general tests
general_tests(m)
# Run of the general tests
general_tests(m)

@test all(
value.(m[:buildings_surplus][buildings, t, p]) == 0.0 for t ∈ 𝒯, p ∈ building_res
)
@test all(
value.(m[:buildings_deficit][buildings, t, p]) == 0.0 for t ∈ 𝒯, p ∈ building_res
)
@test all(value.(m[:emissions_total][t, CO2]) > 0.001 for t ∈ 𝒯)
@test all(
value.(m[:buildings_surplus][buildings, t, p]) == 0.0 for
t ∈ 𝒯, p ∈ building_res
)
@test all(
value.(m[:buildings_deficit][buildings, t, p]) == 0.0 for
t ∈ 𝒯, p ∈ building_res
)
@test all(value.(m[:emissions_total][t, CO2]) > 0.001 for t ∈ 𝒯)

# Test that the EMB function has_capacity is false for the MultipleBuildingTypes node.
@test !EMB.has_capacity(buildings)
# Test that the EMB function has_capacity is false for the MultipleBuildingTypes node.
@test !EMB.has_capacity(buildings)

# Test constraints from EMB.constraints_capacity
@test all(
value.(m[:flow_in][buildings, t, p]) / inputs(buildings, p) +
value.(m[:buildings_deficit][buildings, t, p]) ==
EMB.capacity(buildings, t, p) + value.(m[:buildings_surplus][buildings, t, p])
for t ∈ 𝒯, p ∈ inputs(buildings)
)
# Test constraints from EMB.constraints_capacity
@test all(
value.(m[:flow_in][buildings, t, p]) / inputs(buildings, p) +
value.(m[:buildings_deficit][buildings, t, p]) ==
EMB.capacity(buildings, t, p) + value.(m[:buildings_surplus][buildings, t, p])
for t ∈ 𝒯, p ∈ inputs(buildings)
)

@test all(
sum(value.(m[:buildings_deficit][buildings, t, p]) for p ∈ inputs(buildings)) ==
value.(m[:sink_deficit][buildings, t])
for t ∈ 𝒯
)
@test all(
sum(value.(m[:buildings_deficit][buildings, t, p]) for p ∈ inputs(buildings)) ==
value.(m[:sink_deficit][buildings, t])
for t ∈ 𝒯
)

@test all(
sum(value.(m[:buildings_surplus][buildings, t, p]) for p ∈ inputs(buildings)) ==
value.(m[:sink_surplus][buildings, t])
for t ∈ 𝒯
)
@test all(
sum(value.(m[:buildings_surplus][buildings, t, p]) for p ∈ inputs(buildings)) ==
value.(m[:sink_surplus][buildings, t])
for t ∈ 𝒯
)

# Test constraints from EMB.constraints_opex_var
𝒯ᴵⁿᵛ = strategic_periods(𝒯)
@test all(
value.(m[:opex_var][buildings, t_inv]) ==
sum(
(
value.(m[:buildings_surplus][buildings, t, p]) *
EMB.surplus_penalty(buildings, t, p) +
value.(m[:buildings_deficit][buildings, t, p]) *
EMB.deficit_penalty(buildings, t, p)
) * scale_op_sp(t_inv, t) for t ∈ t_inv, p ∈ inputs(buildings)
# Test constraints from EMB.constraints_opex_var
𝒯ᴵⁿᵛ = strategic_periods(𝒯)
@test all(
value.(m[:opex_var][buildings, t_inv]) ==
sum(
(
value.(m[:buildings_surplus][buildings, t, p]) *
EMB.surplus_penalty(buildings, t, p) +
value.(m[:buildings_deficit][buildings, t, p]) *
EMB.deficit_penalty(buildings, t, p)
) * scale_op_sp(t_inv, t) for t ∈ t_inv, p ∈ inputs(buildings)
)
for t_inv ∈ 𝒯ᴵⁿᵛ
)
for t_inv ∈ 𝒯ᴵⁿᵛ
)

# Test the utility functions for MultipleBuildingTypes
for p ∈ building_res
# Capacity
@test EMB.capacity(buildings) isa Dict
@test EMB.capacity(buildings, p) isa TimeProfile
@test EMB.capacity(buildings)[p] == EMB.capacity(buildings, p)
@test EMB.capacity(buildings, first(𝒯), p) == EMB.capacity(buildings, p)[first(𝒯)]
# Test the utility functions for MultipleBuildingTypes
for p ∈ building_res
# Capacity
@test EMB.capacity(buildings) isa Dict
@test EMB.capacity(buildings, p) isa TimeProfile
@test EMB.capacity(buildings)[p] == EMB.capacity(buildings, p)
@test EMB.capacity(buildings, first(𝒯), p) ==
EMB.capacity(buildings, p)[first(𝒯)]

# Surplus penalty
@test EMB.surplus_penalty(buildings) isa Dict
@test EMB.surplus_penalty(buildings, p) isa TimeProfile
@test EMB.surplus_penalty(buildings)[p] == EMB.surplus_penalty(buildings, p)
@test EMB.surplus_penalty(buildings, first(𝒯), p) ==
EMB.surplus_penalty(buildings, p)[first(𝒯)]
# Surplus penalty
@test EMB.surplus_penalty(buildings) isa Dict
@test EMB.surplus_penalty(buildings, p) isa TimeProfile
@test EMB.surplus_penalty(buildings)[p] == EMB.surplus_penalty(buildings, p)
@test EMB.surplus_penalty(buildings, first(𝒯), p) ==
EMB.surplus_penalty(buildings, p)[first(𝒯)]

# Deficit penalty
@test EMB.deficit_penalty(buildings) isa Dict
@test EMB.deficit_penalty(buildings, p) isa TimeProfile
@test EMB.deficit_penalty(buildings)[p] == EMB.deficit_penalty(buildings, p)
@test EMB.deficit_penalty(buildings, first(𝒯), p) ==
EMB.deficit_penalty(buildings, p)[first(𝒯)]
end
# Deficit penalty
@test EMB.deficit_penalty(buildings) isa Dict
@test EMB.deficit_penalty(buildings, p) isa TimeProfile
@test EMB.deficit_penalty(buildings)[p] == EMB.deficit_penalty(buildings, p)
@test EMB.deficit_penalty(buildings, first(𝒯), p) ==
EMB.deficit_penalty(buildings, p)[first(𝒯)]
end

# Test has_capacity utility function
@test EMB.has_capacity(buildings) == false
# Test has_capacity utility function
@test EMB.has_capacity(buildings) == false
end
end
2 changes: 1 addition & 1 deletion test/utils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ function simple_graph_buildings(; cap_p = nothing,
penalty_deficit, # deficit penalty for the node in €/MWh;
data = [EmissionsEnergy()],
data_location = joinpath(pkgdir(EMLI), "test", "data", "buildings"),
overwrite_saved_data = true,
overwrite_saved_data = false,
)
else
buildings = MultipleBuildingTypes(
Expand Down