太阳能发电厂正在为三个水泵和其他电器供电,我想知道什么时候应该运行水泵以充分利用太阳能发电厂(因为它的产量每天都不是恒定的)。
我尝试在 Pyomo 上实现这样一个优化问题,但他为我提供了 0 个解决方案,而且似乎他只采用了我的三个约束中的一个,这很令人惊讶,因为它看起来并不是一个非常复杂的问题.
我的建模遵循以下规则:
• power_m_pyomo 包含太阳能电池板每月(以 m 为索引)和每小时 8 到 17 之间(以 Id 为索引)的平均发电量,
• base_demand 包含电器的电力需求,等于 8 点到 17 点之间每小时 90 kW,
• model.P 包含每小时应运行的水泵数量。所以它是一个小于或等于3的正整数。我只需要9个“水泵每天运行的等效小时”,这意味着model.P[i]的总和应该等于9。
目标函数是过剩功率(如果供电功率高于需求,则可能为负值)与供电功率之比的平均值。对于我的情况来说,这不是最佳选择,但我使用这个是因为它是线性的(我宁愿使用每年所需的精确超额功率的总和,但它需要使用 max 函数)。
我的代码是:
# Importation of the supplied power
df = pd.read_csv('test_power.csv', header=0, names=["Hour", "Power [kW]"])
power_supplied = df['Power [kW]'].tolist()
# Creation of the average monthly yield power
power_m = monthly_profile_creation(power_supplied)
# Conversion of the power supplied into something that can be used by Pyomo
power_m_pyomo = {}
for m in range(1,13):
for h in range(8, 18):
power_m_pyomo[(m,h)] = power_m[m][h]
# Creation of the model (now empty)
model = pyomo.ConcreteModel()
# Creation of index for the peak demand
model.M = pyomo.Set(initialize = range(1, 13))
model.Id = pyomo.Set(initialize = range(8, 18))
# Parameters
base_demand = list_to_dico([90]*10, 8)
model.base_demand = pyomo.Param(model.Id, initialize=base_demand)
model.power_supplied = pyomo.Param(model.M, model.Id, initialize=power_m_pyomo)
# Variables
model.P = pyomo.Var(model.Id, domain=pyomo.Integers)
# Objective function
def objective_func(model):
power_stored = 0
for m in model.M:
for i in model.Id:
power_stored_hourly = model.base_demand[i] + 24*model.P[i] - model.power_supplied[m,i]
power_stored += power_stored_hourly/model.power_supplied[m,i]
return power_stored/(len(model.M)*(len(model.Id)))
model.objective = pyomo.Objective(rule = objective_func, sense=pyomo.minimize)
# Constraints
def constraint_pump_1(model, i):
return model.P[i] <= 3
model.constraint_pump_1 = pyomo.Constraint(model.Id, rule=constraint_pump_1)
def constraint_pump_2(model):
return sum([model.P[i] for i in model.Id]) == 9
model.constraint_pump_2 = pyomo.Constraint(rule=constraint_pump_2)
def constraint_pump_3(model, i):
return model.P[i] >= 0
model.constraint_pump_3 = pyomo.Constraint(model.Id, rule=constraint_pump_3)
solver = pyomo.SolverFactory("cbc")
results = solver.solve(model, keepfiles=False, logfile="solve.log", tee=True)
print(results)
顺便说一句,当我打印我的模型时,它显示三个约束已被声明...
有人可以帮助我吗?
代码的其他部分(对于理解模型并不重要,但无论如何)是:
import pyomo.environ as pyomo
import pandas as pd
def monthly_profile_creation(power):
"""
Create the average monthly yield power of the system.
Parameters
----------
power : list of 8760 numbers
Contains the hourly yield power.
Return
------
power_m : dictionnary of 12 indices
Contains the average yield power of the system for each month.
"""
# power_d is a dictionnary indexed by the number of days, and containing
# the hourly yield power of the system.
power_d = {}
for d in range(365):
power_per_day = []
for h in range(24):
power_per_day.append(power[h+d*24])
power_d[d] = power_per_day
power_m = {}
months = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
actual_day = 0
for m in range(len(months)):
list_power_one_month = []
for d in range(months[m]):
list_power_one_month.append(power_d[actual_day])
actual_day += 1
power_m[m+1] = [sum(x)/months[m] for x in zip(*list_power_one_month)]
return power_m
def list_to_dico(input_list, starting_index):
"""
To convert a list into a dictionnary, indexed by integers from starting_index (for Pyomo).
Parameters
----------
input_list : list
The list that will be converted.
starting_index : int.
The starting value for indexes
Returns
-------
dico : dictionnary
Dictionnary indexed by integers from starting_index containing the list values.
"""
dico = {}
for i in range(len(input_list)):
dico[i+starting_index] = input_list[i]
return dico
你的模型看起来“不错”,如果没有更多关于什么不起作用的细节,很难给出好的建议。也就是说,可能还有一些需要改进的地方。
首先,作为一般建议,如果您的模型是一个独立的工作示例,那么您可能会在这个网站上获得更好的帮助,因此没有丢失 .csv 文件等。通常很容易创建一些小的虚假数据来正如我在下面所做的那样代表问题。
简化:在您的模型中,太阳能和“其他需求”是给定的,不需要成为模型的一部分。您需要担心的是如何管理
power_available
,如下所示。因此,在进行任何建模之前,只需进行计算即可。
您对泵运行的限制是正确的。
这里有一些关于良好目标的想法,也有一些不太好的想法......
max
函数,通过正实数变量和约束即可计算所需的总过剩功率。import pyomo.environ as pyo
hours = list(range(8, 18))
power_avail = [4.0, 4.0, 6.2, 5.8, 8.7, 7.8, 5.2, 4.1, 3.0, 6.2]
power_avail_dict = dict(zip(hours, power_avail))
# Creation of the model (now empty)
model = pyo.ConcreteModel()
# Creation of index for the peak demand
# model.M = pyo.Set(initialize = range(1, 13))
model.Id = pyo.Set(initialize = hours)
# Parameters
# base_demand = list_to_dico([90]*10, 8)
# model.base_demand = pyo.Param(model.Id, initialize=base_demand)
# model.power_supplied = pyo.Param(model.M, model.Id, initialize=power_m_pyo)
model.power_avail = pyo.Param(model.Id, initialize=power_avail_dict)
model.pump_power = pyo.Param(initialize=4.5, doc='power required by pump per hour')
# Variables
model.P = pyo.Var(model.Id, domain=pyo.Integers)
model.excess_power = pyo.Var(model.Id, domain=pyo.NonNegativeReals, doc='the extra power required in period i')
# Objective function
# minimize the total excess power reqd.
model.objective = pyo.Objective(expr= sum(model.excess_power[i] for i in model.Id))
# Constraints
def constraint_pump_1(model, i):
return model.P[i] <= 3
model.constraint_pump_1 = pyo.Constraint(model.Id, rule=constraint_pump_1)
def constraint_pump_2(model):
return sum([model.P[i] for i in model.Id]) == 9
model.constraint_pump_2 = pyo.Constraint(rule=constraint_pump_2)
def constraint_pump_3(model, i):
return model.P[i] >= 0
model.constraint_pump_3 = pyo.Constraint(model.Id, rule=constraint_pump_3)
def constraint_excess_power(model, i):
return model.excess_power[i] >= model.pump_power * model.P[i] - model.power_avail[i]
model.constraint_excess_power = pyo.Constraint(model.Id, rule=constraint_excess_power)
solver = pyo.SolverFactory("cbc")
results = solver.solve(model, keepfiles=False, logfile="solve.log", tee=True)
print(results)
model.P.display()
for idx in model.Id:
print(f'excess power reqd in period {idx}: {pyo.value(model.excess_power[idx]) :0.2f}')
Objective value: 1.20000000
Enumerated nodes: 0
Total iterations: 13
Time (CPU seconds): 0.00
Time (Wallclock seconds): 0.01
Total time (CPU seconds): 0.00 (Wallclock seconds): 0.01
Problem:
- Name: unknown
Lower bound: 1.2
Upper bound: 1.2
Number of objectives: 1
Number of constraints: 11
Number of variables: 20
Number of binary variables: 0
Number of integer variables: 10
Number of nonzeros: 10
Sense: minimize
Solver:
- Status: ok
User time: -1.0
System time: 0.0
Wallclock time: 0.01
Termination condition: optimal
Termination message: Model was solved to optimality (subject to tolerances), and an optimal solution is available.
Statistics:
Branch and bound:
Number of bounded subproblems: 0
Number of created subproblems: 0
Black box:
Number of iterations: 13
Error rc: 0
Time: 0.013698101043701172
Solution:
- number of solutions: 0
number of solutions displayed: 0
P : Size=10, Index=Id
Key : Lower : Value : Upper : Fixed : Stale : Domain
8 : None : -0.0 : None : False : False : Integers
9 : None : 1.0 : None : False : False : Integers
10 : None : 1.0 : None : False : False : Integers
11 : None : 1.0 : None : False : False : Integers
12 : None : 2.0 : None : False : False : Integers
13 : None : 1.0 : None : False : False : Integers
14 : None : 1.0 : None : False : False : Integers
15 : None : 1.0 : None : False : False : Integers
16 : None : -0.0 : None : False : False : Integers
17 : None : 1.0 : None : False : False : Integers
excess power reqd in period 8: 0.00
excess power reqd in period 9: 0.50
excess power reqd in period 10: 0.00
excess power reqd in period 11: 0.00
excess power reqd in period 12: 0.30
excess power reqd in period 13: 0.00
excess power reqd in period 14: 0.00
excess power reqd in period 15: 0.40
excess power reqd in period 16: 0.00
excess power reqd in period 17: 0.00
[Finished in 278ms]