如何在Pyomo约束中实现条件求和



我正在Pyomo写一个模型,以县为单位(model.SourceCounty(优化约100种不同生物质类型(model.Biomass=玉米、小麦、木屑等(的生物质生产。我试图写的一个约束条件是,我的模型中的生物质产量等于我已经从另一个模型中获得的产量值。然而,另一个模型没有我的Pyomo模型所具有的粒度。在更一般的生物量分组中(model.SimpBiomass=草本生物量,木质生物量(,它仅具有区域(而非县(基础上的生物量生产值(model.Zone(。

在我的约束中,我试图做的是在要求该和等于另一个模型的输出之前,对区域和更一般的生物量分组的生物量生产决策变量(model.x(进行求和,以便我的模型产生一致的结果。然而,我学到的是,我目前编写代码的方式(如下(不起作用,因为Pyomo只调用约束一次,而此时决策变量的值尚未求解。因此,带有if语句的for循环只返回值0。

from pyomo.environ import *
# initialize model -- can rewrite as Concrete Model if that's better for what I'm trying to do
model = AbstractModel()
# initialize indices, including some manually
model.SourceCounty = Set() # county
model.Biomass = Set() # biomass type in my model
model.Year = Set(initialize=[2022, 2024, 2026, 2028, 2030, 2032, 2035, 2040])  # year
model.SimpBiomass = Set(initialize=['herbaceous biomass', 'waste biomass', 'woody biomass'])  # type of feedstock resource - simplified (from separate model)
model.Zone = Set(initialize=['midwest','southeast'])  # zones from separate model
# Create data import structure
data = DataPortal()
# Load indices that require data frame
data.load(filename='fips.csv', set=model.SourceCounty)
data.load(filename='Resources.csv', set=model.Biomass)
# initialize parameters
model.EERF = Param(model.SimpBiomass, model.Zone, model.Year)  # biomass production from the other model that I'm trying to match in my model
model.QIJ = Param(model.SourceCounty)  # mapping of county FIPS code from my model to zones from other model
model.AC = Param(model.Biomass)  # mapping of specific resource type from my model into less specific from other model (values are those in SimpBiomass)
# load in parameters
data.load(filename="county_to_zone.csv", param=model.QIJ)
data.load(filename="BT16_to_zone_Resource.csv", param=model.AC)
# create decision variables (known as Var in Pyomo)
model.x = Var(model.Biomass, model.SourceCounty, model.Year, domain=PositiveReals)  # feedstock production indexed by feedstock, source county, year
# I leave out the objective function for brevity
# Constraint in question
def feedstock_prod_rule(model, c, q, t):
expr2 = 0 # initialize summing variable

# for each biomass type (a) in my model, check if it belongs to a biomass category (c) from the other model

for a in model.Biomass:
if model.AC[a] == c:
# for each county (i) in my model, check if it belongs to a zone (q) from the other model
for i in model.SourceCounty:
if model.QIJ[i] == q:
# if it belongs to q and c from other model, add to expr2
expr2 += model.x[a, i, t]

# Sum of all biomass production from my model within zone q and biomass type c (expr2 at end of looping) should equal the output of the other model (EERF).
return expr2 == model.EERF[c, q, t]

# Add as constraint
model.feedstock_prod = Constraint(model.SimpBiomass, model.Zone, model.Year, rule=feedstock_prod_rule)

我需要帮助找出一种不同的方式来编写这个约束,这样它就不依赖于建立一个依赖于我的决策变量model.x的值的表达式,而这个值还没有解决。有没有一种方法可以在return行中有一行代码来完成同样的事情?

我不完全确定你是否正确诊断了这个问题,如果没有一些数据文件片段,很难重新创建。(这也是不必要的,因为即使它是可重新创建的,也有更好的方法。:(

通常,不能将条件语句嵌入到依赖于变量值的约束中是正确的,当约束被编码到模型中时,变量值是未知的。然而,您使用的条件是基于固定的参数,因此应该是可以的。但是,您将参数与集合中的进行比较,这是……即使有效,也是一个糟糕的计划。。。从来没有尝试过。它的结构问题是,你使用的是1:1配对,而不是标记一组组东西,这会导致条件语句。你有一个类似的结构:

beans : food
lettuce : food
paper : trash

在那里,你会更乐意与下面这样的团队合作,并避免";如果";语句:

food: { beans, lettuce }
trash: { paper }

所以这是可以做到的,你可以把它加载到一个抽象模型中。但是,我不认为您可以从.csv文件中执行此操作,因为我不认为有一种方法可以在.csv中表达indexed sets。您可以在.yaml.json中轻松完成。请参阅pyomo-dox了解更多示例。您甚至可以混合您的数据源,这样您就可以保留其他csv,,只要它们是一致的,所以您需要注意这一点。这是一个工作的例子,我认为这将清理你的模型一堆。特别注意末尾约束中的索引和分组(:

import pyomo.environ as pe
m = pe.AbstractModel()
# SETS
m.Group_names = pe.Set()
m.Items = pe.Set()
m.Groupings = pe.Set(m.Group_names, within=m.Items)
# PARAMS
m.Cost = pe.Param(m.Group_names)
# VARS
m.X = pe.Var(m.Items)
# Constraint "for each Group"
def C1(m, g_name):
return sum(m.X[i] for i in m.Groupings[g_name]) <= 10
m.C1 = pe.Constraint(m.Group_names, rule=C1)
# load data from sources
data = pe.DataPortal()
data.load(filename='cost.csv', param=m.Cost)
data.load(filename='data.yaml')
data.load(filename='items.csv', set=m.Items)
instance = m.create_instance(data)
instance.pprint()

yaml文件(其他文件未显示,它们很简单(:

Group_names: ['Waste', 'Food', 'Critters']
Groupings:
'Waste': ['Trash', 'Coal']
'Food': ['Salad', 'Compost', 'Fish']
'Critters': ['Snails', 'Worms']

结果模型:

3 Set Declarations
Group_names : Size=1, Index=None, Ordered=Insertion
Key  : Dimen : Domain : Size : Members
None :     1 :    Any :    3 : {'Waste', 'Food', 'Critters'}
Groupings : Size=3, Index=Group_names, Ordered=Insertion
Key      : Dimen : Domain : Size : Members
Critters :     1 :  Items :    2 : {'Snails', 'Worms'}
Food :     1 :  Items :    3 : {'Salad', 'Compost', 'Fish'}
Waste :     1 :  Items :    2 : {'Trash', 'Coal'}
Items : Size=1, Index=None, Ordered=Insertion
Key  : Dimen : Domain : Size : Members
None :     1 :    Any :    7 : {'Trash', 'Snails', 'Worms', 'Coal', 'Salad', 'Compost', 'Fish'}
1 Param Declarations
Cost : Size=2, Index=Group_names, Domain=Any, Default=None, Mutable=False
Key   : Value
Food :   8.9
Waste :   4.2
1 Var Declarations
X : Size=7, Index=Items
Key     : Lower : Value : Upper : Fixed : Stale : Domain
Coal :  None :  None :  None : False :  True :  Reals
Compost :  None :  None :  None : False :  True :  Reals
Fish :  None :  None :  None : False :  True :  Reals
Salad :  None :  None :  None : False :  True :  Reals
Snails :  None :  None :  None : False :  True :  Reals
Trash :  None :  None :  None : False :  True :  Reals
Worms :  None :  None :  None : False :  True :  Reals
1 Constraint Declarations
C1 : Size=3, Index=Group_names, Active=True
Key      : Lower : Body                            : Upper : Active
Critters :  -Inf :            X[Snails] + X[Worms] :  10.0 :   True
Food :  -Inf : X[Salad] + X[Compost] + X[Fish] :  10.0 :   True
Waste :  -Inf :              X[Trash] + X[Coal] :  10.0 :   True

最新更新