使用外部函数/计算的值定义Pyomo约束

huangapple go评论227阅读模式
英文:

Defining a Pyomo Constraint using values from external functions/calculations

问题

我想使用Pyomo来解决一个优化问题,其中以价格最优的方式确定电动汽车的充电曲线,同时满足各种约束条件。其中之一的约束条件应该是它们连接的电网中的线路负载不会超过限制。为了建模和模拟电网,我使用pandapower。

所以我将要创建优化充电曲线的时间步骤定义为pyo.Set,价格曲线定义为pyo.Param,两辆电动汽车的充电曲线分别定义为pyo.Var,即决策变量。

目标函数被映射为pyo.Objective,并被写成最小化两辆电动汽车的充电成本之和。

为了避免完全不充电,我已经定义了下面的最小示例的约束条件,规定必须充电一定数量的能量。

到目前为止,代码运行正常,两辆电动汽车以价格优化的方式充电。迄今为止的代码示例如下:

import pandapower as pp
import pandas as pd
import pyomo.environ as pyo

# ...(你的其余代码)

model.energy_constraint_load_1 = pyo.Constraint(rule=pyomo_constraint_energy_load1)
model.energy_constraint_load_2 = pyo.Constraint(rule=pyomo_constraint_energy_load2)

然后,我想要将电网的约束条件也实现为pyo.constraint,但是我在这里遇到了各种问题:

  1. 如果我直接访问Pyomo变量,就像在先前的约束定义中一样,我会得到错误消息,即“禁用了Pyomo数值值到浮点数的隐式转换”。建议使用Pyomo函数value()作为解决方法。
def pyomo_constraint_pandapower_net(m, ts):
    net.load.loc[0, "p_mw"] = m.load1_power_kw[ts] / 1000
    net.load.loc[1, "p_mw"] = m.load2_power_kw[ts] / 1000
    pp.runpp(net)
    return 0, net.res_line.loading_percent.max(), 20

model.pandapower_constraint = pyo.Constraint(model.time_steps, rule=pyomo_constraint_pandapower_net)
  1. 但是,无论我以哪种方式使用此函数,约束条件都没有正确计算。如果我使用.value标记
def pyomo_constraint_pandapower_net(m, ts):
    net.load.loc[0, "p_mw"] = m.load1_power_kw[ts].value / 1000
    net.load.loc[1, "p_mw"] = m.load2_power_kw[ts].value / 1000
    print(net.load.loc[0, "p_mw"])
    print(net.load.loc[1, "p_mw"])
    pp.runpp(net)
    return 0, net.res_line.loading_percent.max(), 20

model.pandapower_constraint = pyo.Constraint(model.time_steps, rule=pyomo_constraint_pandapower_net)
  1. 或者如果我使用函数pyo.value
def pyomo_constraint_pandapower_net(m, ts):
    net.load.loc[0, "p_mw"] = pyo.value(m.load1_power_kw[ts]) / 1000
    net.load.loc[1, "p_mw"] = pyo.value(m.load2_power_kw[ts]) / 1000
    print(net.load.loc[0, "p_mw"])
    print(net.load.loc[1, "p_mw"])
    pp.runpp(net)
    return 0, net.res_line.loading_percent.max(), 20

model.pandapower_constraint = pyo.Constraint(model.time_steps, rule=pyomo_constraint_pandapower_net)

在这两种情况下,都未为pandapower中的负载分配任何值 - 打印输出在每种情况下都返回值0.0。
此外,正如在此问题/答案(https://stackoverflow.com/questions/73732311/using-external-functions-within-pyomo-constraints)中所述,在Pyomo约束中定义表达式时不应取变量的值。在我的最小示例中,我没有定义表达式,只定义了约束,但我已经尝试使用表达式,并收到了相同的错误消息。

我可以通过这种方式解决优化问题,但约束条件计算不正确,因此对我帮助不大。

results = pyo.SolverFactory("glpk").solve(model)

model.load1_power_kw.display()
model.load2_power_kw.display()
model.pandapower_constraint.display()
model.objective.display()

print(f"\nOptimal solution: {results.solver.termination_condition == pyo.TerminationCondition.optimal}")

因此,再次总结我的问题或问题:
如何在外部函数中使用pyo.Var的值或将其传递给像pandapower这样的外部工具,以使用决策变量计算值,然后可以在Pyomo约束中重新检查这些值?
谢谢你的帮助,祝一切顺利!

英文:

I want to solve an optimization problem using Pyomo in which the charging profile of electric vehicles is determined in a price-optimal manner while satisfying various constraints. One of these constraints should be that the line loading in the power grid where they are connected does not increase above a limit. For the modeling and simulation of the power grid I use pandapower.

So I define the time steps for which I want to create the optimized charging profiles as a pyo.Set, the price profile as a pyo.Param, and the charging profiles of the two electric vehicles each as a pyo.Var, that is, as the decision variables.

The objective function is mapped as pyo.Objective and is written to minimize the summed charging costs of both electric vehicles.

To avoid not charging at all, I have defined constraints for the minimal example below, which specify a certain minimum amount of energy that must be charged.

Up to this point the code works, the two electric vehicles charge exactly the certain amount of energy in a price-optimized way. The code so far is shown here as a minimal example:

import pandapower as pp
import pandas as pd
import pyomo.environ as pyo


net = pp.create_empty_network()
pp.create_buses(net, nr_buses=3, vn_kv=0.4)
pp.create_ext_grid(net, bus=0)
pp.create_lines(net, from_buses=[0, 1], to_buses=[1, 2], length_km=0.05, std_type="NAYY 4x50 SE")
pp.create_loads(net, buses=[1, 2], p_mw=0.011)
pp.runpp(net)


model = pyo.ConcreteModel()
model.time_steps = pyo.Set(initialize=(0, 1, 2, 3))
model.price = pyo.Param(model.time_steps, initialize=pd.Series([0.40, 0.30, 0.35, 0.45]))
model.load1_power_kw = pyo.Var(model.time_steps, within=pyo.NonNegativeReals, bounds=[0, 11], initialize=0.0)
model.load2_power_kw = pyo.Var(model.time_steps, within=pyo.NonNegativeReals, bounds=[0, 11], initialize=0.0)


def objective(m):
    costs = 0
    for ts in m.time_steps:
        cost_load1 = m.load1_power_kw[ts] * m.price[ts]
        cost_load2 = m.load2_power_kw[ts] * m.price[ts]
        costs = costs + cost_load1 + cost_load2
    return costs


model.objective = pyo.Objective(expr=objective, sense=pyo.minimize)


def pyomo_constraint_energy_load1(m):
    energy = 0
    for ts in m.time_steps:
        energy = energy + m.load1_power_kw[ts] * 0.25
    return energy >= 4


def pyomo_constraint_energy_load2(m):
    energy = 0
    for ts in m.time_steps:
        energy = energy + m.load2_power_kw[ts] * 0.25
    return energy >= 6


model.energy_constraint_load_1 = pyo.Constraint(rule=pyomo_constraint_energy_load1)
model.energy_constraint_load_2 = pyo.Constraint(rule=pyomo_constraint_energy_load2)

I then wanted to implement the already mentioned constraint of the power grid as a pyo.constraint as well, but I run into various problems here:

  1. If I access the Pyomo variables directly as in the previous constraint definitions, I get the error message that an 'implicit conversion of Pyomo numeric value to float is disabled'. The Pyomo function value() is suggested as a solution.
def pyomo_constraint_pandapower_net(m, ts):
    net.load.loc[0, "p_mw"] = m.load1_power_kw[ts] / 1000
    net.load.loc[1, "p_mw"] = m.load2_power_kw[ts] / 1000
    pp.runpp(net)
    return 0, net.res_line.loading_percent.max(), 20

model.pandapower_constraint = pyo.Constraint(model.time_steps, rule=pyomo_constraint_pandapower_net)
  1. However, when I use this function (no matter in which way), the constraint is not calculated correctly. If I use the .value notation

def pyomo_constraint_pandapower_net(m, ts):
    net.load.loc[0, "p_mw"] = m.load1_power_kw[ts].value / 1000
    net.load.loc[1, "p_mw"] = m.load2_power_kw[ts].value / 1000
    print(net.load.loc[0, "p_mw"])
    print(net.load.loc[1, "p_mw"])
    pp.runpp(net)
    return 0, net.res_line.loading_percent.max(), 20

model.pandapower_constraint = pyo.Constraint(model.time_steps, rule=pyomo_constraint_pandapower_net)
  1. or if I use the function pyo.value
def pyomo_constraint_pandapower_net(m, ts):
    net.load.loc[0, "p_mw"] = pyo.value(m.load1_power_kw[ts]) / 1000
    net.load.loc[1, "p_mw"] = pyo.value(m.load2_power_kw[ts]) / 1000
    print(net.load.loc[0, "p_mw"])
    print(net.load.loc[1, "p_mw"])
    pp.runpp(net)
    return 0, net.res_line.loading_percent.max(), 20

model.pandapower_constraint = pyo.Constraint(model.time_steps, rule=pyomo_constraint_pandapower_net)

In both cases, no value is assigned to the loads in pandapower - the print outputs return the value 0.0 in each case.
Also, as described in this question/answer (https://stackoverflow.com/questions/73732311/using-external-functions-within-pyomo-constraints), you should not take values of variables when defining expressions in Pyomo. I don't define an expression in my minimal example, but only a constraint, but I have already tried it with expressions and got the same error messages.

I can solve the optimization problem this way, but the constraint is calculated incorrectly, so this solution is of little help to me.

results = pyo.SolverFactory("glpk").solve(model)

model.load1_power_kw.display()
model.load2_power_kw.display()
model.pandapower_constraint.display()
model.objective.display()

print(f"\nOptimal solution: {results.solver.termination_condition == pyo.TerminationCondition.optimal}")

So to summarize my problem or question again:
How can I use values from pyo.Var in an external function or pass them to an external tool like pandapower to calculate values there with the decision variables, which I can check again in a Pyomo constraint afterwards?

Thanks already for your help and best regards!

答案1

得分: 1

抱歉,我认为你在这里做不了你想要做的事情。我认为对于求解构造的工作方式存在基本误解。

我不熟悉你尝试使用pandapower的语法,但看起来你试图使用模型变量的值来计算约束。这是不可能的。模型约束的值在模型构建时是未知的,这是pyomo的全部工作。问题被传递给一个求解器,它进行魔术操作,但不涉及外部连接。

所以,你有几种选择... 你可以在一定的逻辑范围内捕获一些值并创建一个查找表,或者创建一个线性或分段线性约束。或者你可以切换到可以处理任意复杂函数并放弃一些良好求解器性能的框架。

英文:

Unfortunately, I don't think you can do what you are looking to do here. I think there is a fundamental misunderstanding of how the solving construct works.

I'm not familiar with the syntax for what you are trying to do with pandapower, but it appears you are trying to use the value of a model variable to compute a constraint. This isn't possible. The value of the model constraints are unknown when the model is constructed, which is all pyomo's job is. The problem is handed off to a solver which does its magic, but does not entertain external connections.

So, you have a couple choices.... You could capture a bunch of values within some logical range and make a look-up table, or linear, or piece-wise linear line for a constraint. Or you could switch frameworks to something that chews on arbitrarily complicated functions and give up some of the performance of a good solver.

huangapple
  • 本文由 发表于 2023年8月10日 20:49:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/76875889.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定