Hello,
I am trying to model a nonlinear optimization problem involving binary variables and continuous variables. Specifically, I cannot understand why a binary variable “z_sys_to_HP(s)” makes the model unusable.
My model tries to minimize the Levelized Cost of Heating (LCOH) of a system. One part is the solar collectors, which provide a production and the other part is a heat pump (HP), with which a certain temperature level is to be reached.
The model works as long as lines 143 to 150 do not contain the binary variable “z_sys_to_HP(s)”. I have highlighted this in the code with “PROBLEM- START” and “PROBLEM - END”.
I would be very grateful if someone could tell me why the model cannot be solved if I include the variable “z_sys_to_HP(s)”.
Best regards
Fynn
using JuMP, XLSX, Ipopt, Juniper
ipopt = optimizer_with_attributes(Ipopt.Optimizer, "tol" => 1e-6, "print_level" => 4, "max_iter" => 20000)
optimizer = optimizer_with_attributes(Juniper.Optimizer, "nl_solver" => ipopt, "mip_gap" => 0.05, "time_limit" => 86400) #Maximal 5% Optimalitätslücke, #Zeitlimit von 24 Stunden
model = Model(optimizer)
# 0. Pfad zur Excel-Datei und Excel-Datei einlesen
daten = XLSX.readxlsx("SOURCE")
# Kollektoren
Werte_Flachkollektoren = daten["Tabelle_Daten"]["B2:B11"]
EDATA_Coll_FK_values = [Werte_Flachkollektoren[i][1] for i in 1:length(Werte_Flachkollektoren)] #Flachkollektoren - EDATA [kWh / m^2]
# Energienachfrage
Werte_Energienachfrage = daten["Tabelle_Daten"]["E2:E11"]
Energienachfrage_values = [Werte_Energienachfrage[i][1] for i in 1:length(Werte_Energienachfrage)] #Energienachfrage - EDATA [MWh]
# Temperatur-Nachfrage
Werte_Temperatur_Nachfrage = daten["Tabelle_Daten"]["F2:F11"] #Temperaturen des Vorlaufs des Bedarfs in °C
Temp_Bedarf_values = [Werte_Temperatur_Nachfrage[i][1] for i in 1:length(Werte_Temperatur_Nachfrage)] #Temperaturen des Vorlaufs des Bedarfs in °C - T_H (s)
# Strompreis
Werte_Strompreis = daten["Tabelle_Daten"]["G2:G11"] #Strompreise in €/MWh zu jeder Stunde (entnommen Agorameter, 2023)
Strompreis_values = [Werte_Strompreis[i][1] for i in 1:length(Werte_Strompreis)] #Strompreise in €/MWh zu jeder Stunde
println("Anzahl der eingelesenen Werte (Flachkollektoren): ", length(EDATA_Coll_FK_values))
println("Anzahl der eingelesenen Werte (Energienachfrage): ", length(Energienachfrage_values))
println("Anzahl der eingelesenen Werte (Temperaturbedarf): ", length(Temp_Bedarf_values))
println("Anzahl der eingelesenen Werte (Strompreis): ", length(Strompreis_values))
# 1. Mengen definieren
S = 1:10 # Stunden
# 2. Parameter definieren
#Diskontierungsfaktor
diskont = 1.05 # r=0,5
#Kollektoren
n_opt_FK = 0.838
a1_FK = 2.46
a2_FK = 0.00971
T_M_FK = 75 #°C
T_u_peak = 15.4 #°C
#Wärmepumpe
E_elektr_max = 4 #MWh (Abhängig von der Nennleistung der HP - Annahme: 2 MW Leistung_Peak)
# 3. Variablen definieren
# Nachfrage
@variable(model, E_Demand >= 0)
# System
@variable(model, Ertrag_System >= 0)
@variable(model, z_Netz[s in S], Bin)
@variable(model, SD >= 0)
# Zusatz
@variable(model, OperationWartung_Zusatz >= 0)
@variable(model, Ertrag_Zusatz >= 0)
@variable(model, Ertrag_Zusatz_zum_Bedarf[s in S] >= 0)
# Kollektoren
@variable(model, I_Coll >= 0)
@variable(model, A_Coll >= 0)
@variable(model, I_spez_Coll >= 0)
@variable(model, P_Coll_peak >= 0)
@variable(model, Wirkungsgrad_Coll_non_conc >= 0)
@variable(model, OperationWartung_Kollektor >= 0)
@variable(model, Ertrag_Coll[s in S] >= 0)
@variable(model, Ertrag_Coll_zur_HP[s in S] >= 0)
@variable(model, Ertrag_Coll_zum_Netz[s in S] >= 0)
# Wärmepumpe
@variable(model, E_sys_zur_HP[s in S] >= 0)
@variable(model, z_Coll_zur_HP[s in S], Bin)
@variable(model, Temp_HP_Quelle[s in S] >= 0)
@variable(model, COP_HP[s in S] >= 0) #COP of HP
@variable(model, E_elektr[s in S] >= 0) #Elektrische Energie
@variable(model, E_HP_zum_Bedarf[s in S] >= 0) #Energie, die von der HP zur Deckung des Bedarfs eingesetzt wird
@variable(model, Price_HP[s in S]) #Preis, den die HP aufgrund der elektr. Energie verursacht
@variable(model, I_HP >= 0) #Investitionssume der HP
@variable(model, OperationWartung_HP)
@variable(model, z_sys_zur_HP[s in S], Bin)
# 4. Zielfunktionsvariable(n) definieren
@variable(model, LCOH >= 0)
@variable(model, LCOH_System >= 0)
# 5. Nebenbedingungen aufstellen
# Kollektor
@constraint(model, A_Coll * I_spez_Coll == I_Coll)
@constraint(model, (504.25 * A_Coll^(-0.077)) == I_spez_Coll)
@constraint(model, P_Coll_peak <= 10)
@constraint(model, P_Coll_peak >= 5)
@constraint(model, 9.066375 * (10^(-4)) * Wirkungsgrad_Coll_non_conc * A_Coll == P_Coll_peak)
@constraint(model, (n_opt_FK - ((a1_FK*(T_M_FK-T_u_peak) + a2_FK * ((T_M_FK-T_u_peak)^2)) / 906.6375)) == Wirkungsgrad_Coll_non_conc)
for s in S
@constraint(model, Ertrag_Coll[s] == (EDATA_Coll_FK_values[s] * A_Coll) * (1 / 1000))
end
@constraint(model, OperationWartung_Kollektor == 0.0075 * I_Coll)
for s in S
@constraint(model, Temp_Bedarf_values[s] <= 90 + 80*(1-z_Netz[s]))
end
for s in S
@constraint(model, Temp_Bedarf_values[s] >= 90 - 80*z_Netz[s]) #FEHLERPOTENTIAL 1????
end
for s in S
@constraint(model, Ertrag_Coll[s] == Ertrag_Coll_zur_HP[s] + Ertrag_Coll_zum_Netz[s])
end
for s in S
@constraint(model, Ertrag_Coll_zum_Netz[s] <= 100000 * z_Netz[s])
end
# Wärmepumpe
for s in S
@constraint(model, E_sys_zur_HP[s] == Ertrag_Coll_zur_HP[s])
end
for s in S
@constraint(model, Ertrag_Coll_zur_HP[s] <= 10000*z_Coll_zur_HP[s])
end
for s in S
@constraint(model, Ertrag_Coll_zur_HP[s] >= z_Coll_zur_HP[s])
end
for s in S
@constraint(model, Temp_HP_Quelle[s] == (90+273.15))
end
for s in S
@constraint(model, COP_HP[s] == (0.5 * ((Temp_Bedarf_values[s]+273.15)/((Temp_Bedarf_values[s]+273.15)-Temp_HP_Quelle[s])))*z_Coll_zur_HP[s])
end
# PROBLEM - START!!!!
for s in S
@constraint(model, z_sys_zur_HP[s] == z_Coll_zur_HP[s])
end
for s in S
@constraint(model, E_elektr[s] <= E_elektr_max * z_sys_zur_HP[s])
end
for s in S
@constraint(model, E_elektr[s] >= z_sys_zur_HP[s])
end
# PROBLEM - END!!!!
for s in S
@constraint(model, E_elektr[s] * COP_HP[s] == E_HP_zum_Bedarf[s])
end
for s in S
@constraint(model, Price_HP[s] == E_elektr[s] * Strompreis_values[s])
end
@constraint(model, Ertrag_System == sum(E_HP_zum_Bedarf[s] for s in S) + sum(Ertrag_Coll_zum_Netz[s] for s in S))
@constraint(model, I_HP == E_elektr_max * (5881.1*(E_elektr_max^(-0.779)))) #MUSS NOCH ANGEPASST WERDEN -> BISHER NUR BEISPIELHAFT!!!!!!
@constraint(model, OperationWartung_HP == 0.01*I_HP + sum(Price_HP[s] for s in S)) #Annahme: 1% der Investitionskosten jedes Jahr
# Weitere Bedingungen
for s in S
@constraint(model, Ertrag_Zusatz_zum_Bedarf[s] == Energienachfrage_values[s] - (E_HP_zum_Bedarf[s] + Ertrag_Coll_zum_Netz[s]))
end
@constraint(model, Ertrag_Zusatz == sum(Ertrag_Zusatz_zum_Bedarf[s] for s in S))
@constraint(model, OperationWartung_Zusatz == 100000*Ertrag_Zusatz)
@constraint(model, E_Demand == sum(Energienachfrage_values[s] for s in S))
@constraint(model, SD == Ertrag_System / E_Demand)
# LCOH Zwischenausdrücke
# Diskontierte Betriebs- & Wartungskosten
@expression(model, diskontierte_wartungskosten, (OperationWartung_Kollektor + OperationWartung_HP + OperationWartung_Zusatz) / diskont)
# Diskontierte Erträge
@expression(model, diskontierte_erträge, (Ertrag_Zusatz + Ertrag_System) / diskont)
# LCOH_System Zwischenausdrücke
# Diskontierte Betriebs- & Wartungskosten (System)
@expression(model, diskontierte_wartungskosten_system, (OperationWartung_Kollektor + OperationWartung_HP) / diskont)
# Diskontierte Erträge
@expression(model, diskontierte_erträge_system, (Ertrag_System) / diskont)
# LCOH Definieren
@constraint(model, LCOH == (I_Coll + I_HP + diskontierte_wartungskosten) / (diskontierte_erträge))
# LCOH_System Definieren
@constraint(model, LCOH_System == (I_Coll + I_HP + diskontierte_wartungskosten_system) / (diskontierte_erträge_system))
# 6. Ziel definieren
@objective(model, Min, LCOH)
# 7. Modell lösen
optimize!(model)
# 8. Stauts ausgeben
status = termination_status(model)
println("Status: ", status)