Pyomo,如何使用来自两个不同Set()的两个决策变量创建约束?

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

Pyomo, how to make a constraint with two decision variables from two different Set()

问题

我有一个抽象的Pyomo优化问题,其中有两个决策变量,它们分别定义在两个单独的Set()中。

它们分别命名为model.BATTERYmodel.HYDROGEN

我想创建的约束是这样的,即这两个决策变量的和不超过一个名为FR的特定数值。约束如下:

  1. def LimitPshFlex_rule(model,i):
  2. return (sum(model.BatteryPsh[i] for i in model.BATTERY) + sum(model.HydrogenPsh[i] for i in model.HYDROGEN)) <= FR

当我调用函数以激活约束时,我需要输入涉及的Set()和规则的名称。代码如下:

  1. model.LimitPshFlex = Constraint(model.HYDROGEN, model.BATTERY, rule=LimitPshFlex_rule)

问题出在Pyomo不识别这种方法,因为它只接受一个Set()作为输入。以下是我得到的错误:

  1. TypeError: LimitPshFlex_rule() takes 2 positional arguments but 3 were given

如果我将它们定义为两个单独的约束,虽然也可以,但如果我能将它们合并为一个约束,可以节省一些后续编码工作。我想知道是否有人知道如何解决这个问题。

英文:

I have an Abstract Pyomo optimization problem where I have two decision variables that are defined in two separate Set().

These are named model.BATTERY and model.HYDROGEN.

The constraint that I want to create is such that the sum of the two decision variables does not exceed a certain amount named FR. The constraint looks like this:

  1. def LimitPshFlex_rule(model,i):
  2. return (sum(model.BatteryPsh[i] for i in model.BATTERY) + sum(model.HydrogenPsh[i] for i in model.HYDROGEN)) &lt;= FR

When I call the function so that the constraint can be activated I need to input the Set() involved and the name of the rule. It looks like this:

  1. model.LimitPshFlex = Constraint(model.HYDROGEN, model.BATTERY, rule=LimitPshFlex_rule)

The problem with this approach is that Pyomo does not recognize it as it accepts only one Set() as input. Here is the error that I get.

  1. TypeError: LimitPshFlex_rule() takes 2 positional arguments but 3 were given

I can also define them as two separate constraints but it saves me some coding later on if I manage to put them into one constraint so I wanted to check if anyone knows how to solve it.
Here is my full code below to give you a better perspective.

  1. ## CREATING MODEL, SET AND PARAM
  2. model = AbstractModel()
  3. # Creating sets for each decision variable
  4. model.BATTERY = Set()
  5. model.HYDROGEN = Set()
  6. # Creating the different variables that will be used for the constraints
  7. model.BatteryMinPower = Param(model.BATTERY)
  8. model.BatteryMaxPower = Param(model.BATTERY)
  9. model.BatteryCapacity = Param(model.BATTERY)
  10. model.BatterySoC = Param(model.BATTERY)
  11. model.BatteryPrated = Param(model.BATTERY)
  12. model.HydrogenMinPower = Param(model.HYDROGEN)
  13. model.HydrogenMaxPower = Param(model.HYDROGEN)
  14. model.HydrogenCapacity = Param(model.HYDROGEN)
  15. model.HydrogenSoC = Param(model.HYDROGEN)
  16. model.HydrogenPrated = Param(model.HYDROGEN)
  17. # model.BatteryMinPower = Param(model.BATTERY, initialize=data[&#39;MinPower1&#39;])
  18. # model.BatteryMaxPower = Param(model.BATTERY, initialize=data[&#39;MaxPower1&#39;])
  19. # model.BatteryCapacity = Param(model.BATTERY, initialize=data[&#39;Capacity1&#39;])
  20. # model.BatterySoC = Param(model.BATTERY, initialize=data[&#39;SoC1&#39;])
  21. # model.BatteryPrated = Param(model.BATTERY, initialize=data[&#39;P_rated2&#39;])
  22. # model.HydrogenMinPower = Param(initialize=data[&#39;MinPower2&#39;])
  23. # model.HydrogenMaxPower = Param(initialize=data[&#39;MaxPower2&#39;])
  24. # model.HydrogenCapacity = Param(initialize=data[&#39;Capacity2&#39;])
  25. # model.HydrogenSoC = Param(initialize=data[&#39;SoC2&#39;])
  26. # model.HydrogenDisPrated = Param(initialize=data[&#39;P_rated2&#39;])
  27. # Creating dataframes that will be used for the optimization:
  28. PshFlex = pd.DataFrame(index=EMS.index) # Amount of power provided at each PTU
  29. SoC = pd.DataFrame(index=EMS.index) # The SoC of the different assets
  30. SoC_change = pd.DataFrame(index=EMS.index) # The change in SoC of each assets
  31. P_rated_EMS = pd.DataFrame(index=EMS.index) # How much the asset is already in use during the request of power
  32. AGR_E_prog = pd.DataFrame(index=EMS.index) # The energy program proposed by the AGR.
  33. # Assigning the values of the EMS to the respective variables.
  34. # Note: Soc used for defining the parameters of the optimization and SoC_change for saving the optimization results.
  35. SoC[&#39;battery_soc&#39;] = EMS[&#39;battery_soc_actual&#39;]
  36. SoC[&#39;H2_soc&#39;] = EMS[&#39;hydrogen_soc_actual&#39;]
  37. SoC_change[&#39;battery_soc_new&#39;] = SoC[&#39;battery_soc&#39;] #This colums will be the altered SoC after the bidding has been done.
  38. SoC_change[&#39;H2_soc_new&#39;] = SoC[&#39;H2_soc&#39;] #This colums will be the altered SoC after the bidding has been done.
  39. P_rated_EMS[&#39;Battery_Prated&#39;] = -EMS[&#39;battery_actual&#39;]
  40. P_rated_EMS[&#39;H2_disPrated&#39;] = -EMS[&#39;hydrogen_actual&#39;]
  41. # These are just starting value to initaliaze the model but will be changed later.
  42. PshFlex[&#39;batt_power&#39;] = 0 # power used for flex bid
  43. PshFlex[&#39;H2_power&#39;] = 0 # power used for flex bid
  44. FR = 0 # request of power.
  45. # # Setting up the paramaters. A dictionary type of strucuture is used
  46. # # so that the values can be continuously updated:
  47. data = {None: { #Somehow the Set will not properly create if I don&#39;t insert this None. I do not know the reason why :(
  48. &#39;BATTERY&#39;: {None: [1]},
  49. &#39;HYDROGEN&#39;: {None: [1]},
  50. &#39;BatteryMaxPower&#39;: {1: 4},
  51. &#39;BatteryMinPower&#39;: {1: 4},
  52. &#39;BatteryCapacity&#39;: {1: 15.4},
  53. &#39;BatterySoC&#39;: {1: SoC.iloc[0,0]},
  54. &#39;BatteryPrated&#39;: {1: P_rated_EMS.iloc[0,0]},
  55. &#39;HydrogenMinPower&#39;: {1: 0},
  56. &#39;HydrogenMaxPower&#39;: {1: 2.3},
  57. &#39;HydrogenCapacity&#39;: {1: 1998},
  58. &#39;HydrogenSoC&#39;: {1: SoC.iloc[0,1]},
  59. &#39;HydrogenPrated&#39;: {1: P_rated_EMS.iloc[0,1]}
  60. } }
  61. # # Decision variable
  62. model.BatteryPsh = Var(model.BATTERY, within=Reals, initialize=0)
  63. model.HydrogenPsh = Var(model.HYDROGEN, within=Reals, initialize=0)
  64. # Objective Function
  65. def objective_rule(model): # For a flexibility request (FR) the power (Psh) of the assets is used to match it.
  66. return FR - (sum(model.BatteryPsh[i] for i in model.BATTERY) + sum(model.HydrogenPsh[j] for j in model.HYDROGEN))
  67. # Constraints
  68. def MaxPowerRated_rule_BATT(model,i): # Max rated power limit
  69. return model.BatteryPsh[i] &lt;= model.BatteryMaxPower[i]
  70. def MinPowerRated_rule_BATT(model,i): # Min rated power limit
  71. return model.BatteryMinPower[i] &lt;= model.BatteryPsh[i]
  72. def MaxCapacityLimits_rule_BATT(model,i): # Checks that the power flex is within the limits of the storage (discharge limit).
  73. return model.BatteryPsh[i] &lt;= model.BatteryCapacity[i]*model.BatterySoC[i]**4
  74. def MaxPowerAvailable_rule_BATT(model,i): # Checks how much power the asset is already using at that moment.
  75. return model.BatteryPsh[i] &lt;= model.BatteryMaxPower[i] - model.BatteryPrated[i]
  76. def MinPowerRated_rule_HYDRO(model,i): # Min rated power limit
  77. return model.HydrogenMinPower[i] &lt;= model.HydrogenPsh[i]
  78. def MaxPowerRated_rule_HYDRO(model, i): # Max rated power limit
  79. return model.HydrogenPsh[i] &lt;= model.HydrogenMaxPower[i]
  80. def MaxCapacityLimits_rule_HYDRO(model, i): # Checks that the power flex is within the limits of the storage (discharge limit).
  81. return model.HydrogenPsh[i] &lt;= model.HydrogenCapacity[i]*model.HydrogenSoC[i]*4
  82. def MaxPowerAvailable_rule_HYDRO(model, i): # Checks how much power the asset is already using at that moment.
  83. return model.HydrogenPsh[i] &lt;= model.HydrogenMaxPower[i] - model.HydrogenPrated[i]
  84. def LimitPshFlex_rule(model,i): # Makes sure that the optimization does not provide more power than what the FR needs. (minimization wil try to reduce it as much as possible)
  85. return (sum(model.BatteryPsh[i] for i in model.BATTERY) + sum(model.HydrogenPsh[i] for i in model.HYDROGEN)) &lt;= FR
  86. # def LimitPshFlex_rule_HYDRO(model,i): # Makes sure that the optimization does not provide more power than what the FR needs. (minimization wil try to reduce it as much as possible)
  87. # return sum(model.HydrogenPsh[i] for i in model.HYDROGEN) &lt;= FR
  88. # def LimitPshFlex_rule_BATT(model,i): # Makes sure that the optimization does not provide more power than what the FR needs. (minimization wil try to reduce it as much as possible)
  89. # return sum(model.BatteryPsh[i] for i in model.BATTERY) &lt;= FR
  90. # Activating the constraints
  91. model.MaxPowerRated_BATT = Constraint(model.BATTERY, rule=MaxPowerRated_rule_BATT)
  92. model.MinPowerRated_BATT = Constraint(model.BATTERY, rule=MinPowerRated_rule_BATT)
  93. model.MaxCapacityLimits_BATT = Constraint(model.BATTERY, rule=MaxCapacityLimits_rule_BATT)
  94. model.MaxPowerAvailable_BATT = Constraint(model.BATTERY, rule=MaxPowerAvailable_rule_BATT)
  95. model.MaxPowerRated_HYDRO = Constraint(model.HYDROGEN, rule=MaxPowerRated_rule_HYDRO)
  96. model.MinPowerRated_HYDRO = Constraint(model.HYDROGEN, rule=MinPowerRated_rule_HYDRO)
  97. model.MaxCapacityLimits_HYDRO = Constraint(model.HYDROGEN, rule=MaxCapacityLimits_rule_HYDRO)
  98. model.MaxPowerAvailable_HYDRO = Constraint(model.HYDROGEN, rule=MaxPowerAvailable_rule_HYDRO)
  99. # model.LimitPshFlex_BATT = Constraint(model.BATTERY, rule=LimitPshFlex_rule_BATT)
  100. # model.LimitPshFlex_HYDRO = Constraint(model.HYDROGEN, rule=LimitPshFlex_rule_HYDRO)
  101. model.LimitPshFlex = Constraint(model.HYDROGEN, model.BATTERY, rule=LimitPshFlex_rule)
  102. model.PowerProvided = Objective(rule=objective_rule, sense=minimize)
  103. instance = model.create_instance(data)
  104. # For loop for each PTU is created. Within the for loop the model is run through the optimization and
  105. # the assets change of state is updated for the following PTU. (i.e. battery discharged = SoC decreases)
  106. for t in range(0,len(EMS.index)-1):
  107. # The values of the SoC and rated power are updated as the for loop iterates.
  108. data = {None: { #Somehow the Set() will not create propery if I don&#39;t insert this None. I do not know the reason why :(
  109. &#39;BATTERY&#39;: {None: [1]},
  110. &#39;HYDROGEN&#39;: {None: [1]},
  111. &#39;BatteryMaxPower&#39;: {1: 4},
  112. &#39;BatteryMinPower&#39;: {1: 0},
  113. &#39;BatteryCapacity&#39;: {1: 15.4},
  114. &#39;BatterySoC&#39;: {1: SoC.iloc[t,0]},
  115. &#39;BatteryPrated&#39;: {1: P_rated_EMS.iloc[t,0]},
  116. &#39;HydrogenMinPower&#39;: {1: 0},
  117. &#39;HydrogenMaxPower&#39;: {1: 2.3},
  118. &#39;HydrogenCapacity&#39;: {1: 1998},
  119. &#39;HydrogenSoC&#39;: {1: SoC.iloc[t,1]},
  120. &#39;HydrogenPrated&#39;: {1: P_rated_EMS.iloc[t,1]}
  121. } }
  122. # The flexibility requests changes at every iteration.
  123. FR = FR_PTU.loc[t,&#39;Flex_Request&#39;]
  124. # Obejective goal is set
  125. model.PowerProvided = Objective(rule=objective_rule, sense=minimize)
  126. # The model is created with the updated data
  127. instance = model.create_instance(data)
  128. # Checks that the battery asset is available for usage (not charging). The H2 can work also during charging because it is formed of a compressor and fuel cell.
  129. if (P_rated_EMS.iloc[t,0] &lt; 0): #or (SoC_change.iloc[t,0] &lt; 0.2): # If assets is being charged or low in charge then disable decision variable.
  130. instance.BatteryPsh[1].fix(0)
  131. elif (P_rated_EMS.iloc[t,0] &gt; 0):
  132. instance.BatteryPsh[1].unfix()
  133. # if SoC_change.iloc[t,0] &lt; 0.2: # If battery SoC is lower than 0.2 disable decision variable
  134. # instance.Psh[1].fix(0)
  135. # elif SoC_change.iloc[t,0] &gt; 0.2:
  136. # instance.Psh[1].unfix()
  137. # # The optimization is runned and solved.
  138. opt = SolverFactory(&#39;glpk&#39;)
  139. opt.solve(instance)
  140. print(&#39;\n \n working... \n \n &#39;)
  141. for i in range(0,2):
  142. if i == 0:
  143. PshFlex.iloc[t,i] = instance.BatteryPsh[1].value
  144. if i == 1:
  145. PshFlex.iloc[t,i] = instance.HydrogenPsh[1].value

答案1

得分: 1

不应在制定该约束时传递索引。

当您使用规则函数组合制定约束时,它只是一种机制,用于使约束对传递的索引的“每个”值类似。在这种情况下,只有一个求和约束是需要的,因此您不需要传递索引,只需访问表达式中的正确集合。

此外,如果只是需要单一约束,您可以直接制定单一表达式并基于该表达式制定约束,而无需使用函数。无论哪种方式。如您所见,C1C2 是等效约束。

英文:

You shouldn't be passing an index in at all in making that constraint.

Realize when you are using the rule-function combination to make constraints, it is just a mechanism to make a similar constraint "for each" value of the index(es) that you pass in. In this case, there is only one summation constraint desired, so you don't need to pass in an index, just access the correct sets within the expression.

Also, if it is just a single constraint desired, you can just hammer out the single expression and make the constraint from that rather than having a function do it for you. Either way. As you can see below, C1 and C2 are equivalent constraints.

Code:

  1. import pyomo.environ as pyo
  2. m = pyo.ConcreteModel()
  3. m.B = pyo.Set(initialize=[&#39;b1&#39;, &#39;b2&#39;], doc=&#39;set of batteries&#39;)
  4. m.H = pyo.Set(initialize=[&#39;h1&#39;, &#39;h2&#39;, &#39;h3&#39;], doc=&#39;set of hydrogen cells&#39;)
  5. m.batt_use = pyo.Var(m.B)
  6. m.h_use = pyo.Var(m.H)
  7. def total_use(m):
  8. return sum(m.batt_use[b] for b in m.B) + sum(m.h_use[h] for h in m.H) &lt;= 50
  9. m.C1 = pyo.Constraint(rule=total_use)
  10. m.C2 = pyo.Constraint(expr=sum(m.batt_use[b] for b in m.B) + sum(m.h_use[h] for h in m.H) &lt;= 50)
  11. m.pprint()

Output:

  1. 2 Set Declarations
  2. B : set of batteries
  3. Size=1, Index=None, Ordered=Insertion
  4. Key : Dimen : Domain : Size : Members
  5. None : 1 : Any : 2 : {&#39;b1&#39;, &#39;b2&#39;}
  6. H : set of hydrogen cells
  7. Size=1, Index=None, Ordered=Insertion
  8. Key : Dimen : Domain : Size : Members
  9. None : 1 : Any : 3 : {&#39;h1&#39;, &#39;h2&#39;, &#39;h3&#39;}
  10. 2 Var Declarations
  11. batt_use : Size=2, Index=B
  12. Key : Lower : Value : Upper : Fixed : Stale : Domain
  13. b1 : None : None : None : False : True : Reals
  14. b2 : None : None : None : False : True : Reals
  15. h_use : Size=3, Index=H
  16. Key : Lower : Value : Upper : Fixed : Stale : Domain
  17. h1 : None : None : None : False : True : Reals
  18. h2 : None : None : None : False : True : Reals
  19. h3 : None : None : None : False : True : Reals
  20. 2 Constraint Declarations
  21. C1 : Size=1, Index=None, Active=True
  22. Key : Lower : Body : Upper : Active
  23. None : -Inf : batt_use[b1] + batt_use[b2] + h_use[h1] + h_use[h2] + h_use[h3] : 50.0 : True
  24. C2 : Size=1, Index=None, Active=True
  25. Key : Lower : Body : Upper : Active
  26. None : -Inf : batt_use[b1] + batt_use[b2] + h_use[h1] + h_use[h2] + h_use[h3] : 50.0 : True
  27. 6 Declarations: B H batt_use h_use C1 C2

huangapple
  • 本文由 发表于 2023年5月6日 19:47:42
  • 转载请务必保留本文链接:https://go.coder-hub.com/76188698.html
匿名

发表评论

匿名网友

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

确定