我正在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