模型目标包含非线性项(pyomo)

问题描述 投票:0回答:1

我正在尝试创建一个模型来最小化电解槽的 LCOH。价格有每小时的价值,应根据生产的数量来决定是否值得生产。所有其他值最初都是恒定的。这个想法是,投资成本和可变成本除以生产总量,从而使 LCOH 下降到一定的边际价格。 LCOH 的计算方法是投资成本加上可变成本除以产量。投资成本一开始就固定,剩下的由生产时间决定。 如果我尝试将固定成本包含在分子中并使用决策变量的总和来表示可变成本,我会得到一个错误,即我的函数不是线性的。我尝试了两种不同的方法来定义我的目标函数,但都不起作用。有人可以帮我解决这个问题吗?

import pandas as pd
from pyomo.environ import *

# prices with values in €/MWh
el_prices =[-5.17, -1.07, -1.47, -5.08, -4.49, -5.4, -5.02, -1.3, -1.44, -1.09, -1.07, -1.07, -0.79, -0.27, 0.85, 23.53, 36.54, 46.03, 55.57, 54.95, 49.23, 44.99, 45.96, 35.0, 57.91, 51.67, 52.93, 44.09, 50.08, 69.72, 105.08, 140.64, 145.98, 147.05, 145.61, 143.35, 144.38, 143.76, 148.2, 155.34, 162.89, 170.0, 174.74, 164.46, 153.0, 141.67, 134.91, 124.22, 130.01, 120.0]
    
investment_cost_ely = 1500  # Beispiel-Fixkosten in Euro/kw
power_ely = 1000  # Beispiel-Leistung des Elektrolyseurs in kW
conversion_factor = 0.6  # Beispiel-Wirkungsgrad des Elektrolyseurs
number_years = 20
interest_rate = 0.06


a = (((1+interest_rate)**number_years)*interest_rate)/(((1+interest_rate)**number_years)-1)
annualized_cost = investment_cost_ely * power_ely * a


  
m3 = ConcreteModel()

    
m3.betriebsstunden = Var(hours, domain=Binary)

   
def gestehungskosten_rule(model):
    return fixe_kosten + sum(m3.betriebsstunden[t] * power_ely * el_prices[t]) / sum(m3.betriebsstunden[t] * power_ely * conversion_factor for t in hours)    
m3.gestehungskosten = Objective(rule=gestehungskosten_rule, sense=minimize)

我收到此错误

ERROR: Rule failed when generating expression for Objective gestehungskosten
with index None: NameError: name 't' is not defined
ERROR: Constructing component 'gestehungskosten' from data=None failed:
        NameError: name 't' is not defined
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[7], line 10
      8 def gestehungskosten_rule(model):
      9     return fixe_kosten + sum(m3.betriebsstunden[t] * leistung * strompreise[t]) / sum(m3.betriebsstunden[t] * leistung * wirkungsgrad for t in hours)    
---> 10 m3.gestehungskosten = Objective(rule=gestehungskosten_rule, sense=minimize)
     12 m3.gestehungskosten.pprint()

File /opt/anaconda3/lib/python3.11/site-packages/pyomo/core/base/block.py:568, in _BlockData.__setattr__(self, name, val)
    563 if name not in self.__dict__:
    564     if isinstance(val, Component):
    565         #
    566         # Pyomo components are added with the add_component method.
    567         #
--> 568         self.add_component(name, val)
    569     else:
    570         #
    571         # Other Python objects are added with the standard __setattr__
    572         # method.
    573         #
    574         super(_BlockData, self).__setattr__(name, val)

File /opt/anaconda3/lib/python3.11/site-packages/pyomo/core/base/block.py:1126, in _BlockData.add_component(self, name, val)
   1118     logger.debug(
   1119         "Constructing %s '%s' on %s from data=%s",
   1120         val.__class__.__name__,
   (...)
   1123         str(data),
   1124     )
   1125 try:
-> 1126     val.construct(data)
   1127 except:
   1128     err = sys.exc_info()[1]

File /opt/anaconda3/lib/python3.11/site-packages/pyomo/core/base/objective.py:318, in Objective.construct(self, data)
    315 else:
    316     # Bypass the index validation and create the member directly
    317     for index in self.index_set():
--> 318         ans = self._setitem_when_not_present(index, rule(block, index))
    319         if ans is not None:
    320             ans.set_sense(self._init_sense(block, index))

File /opt/anaconda3/lib/python3.11/site-packages/pyomo/core/base/initializer.py:438, in ScalarCallInitializer.__call__(self, parent, idx)
    437 def __call__(self, parent, idx):
--> 438     return self._fcn(parent)

Cell In[7], line 9, in gestehungskosten_rule(model)
      8 def gestehungskosten_rule(model):
----> 9     return fixe_kosten + sum(m3.betriebsstunden[t] * leistung * strompreise[t]) / sum(m3.betriebsstunden[t] * leistung * wirkungsgrad for t in hours)

NameError: name 't' is not defined

这是我的第二种方法

#define promo model second ry
m6 = ConcreteModel()

    # variables
fix_costs = 100000
m6.betriebsstunden = Var(hours, domain=Binary)

def gestehungskosten_rule(model):
    variable_costs = sum(m6.betriebsstunden[t] * power_ely * el_prices[t] for t in hours)
    quantity = sum(m6.betriebsstunden[t] * power_ely * conversion_factor for t in hours)
    return (fix_costs + variable_costs) / quantity
m6.gestehungskosten = Objective(rule=gestehungskosten_rule, sense=minimize)


    # solve problem
solver = SolverFactory('glpk')  # Anpassen des Solvers je nach Bedarf (glpk)
results = solver.solve(m6)

    # print result
print("Minimale Gestehungskosten:", m6.gestehungskosten())
print("Anzahl der Betriebsstunden:", sum(m6.betriebsstunden[t].value for t in hours))

print("Stunden mit Produktion:")
for t in hours:
    if m6.betriebsstunden[t].value == 1:
        print("Stunde:", t, "Strompreis:", el_prices[t])

这里出现这个错误

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[6], line 3
      1 # Solver konfigurieren und Problem lösen
      2 solver = SolverFactory('glpk')  # Anpassen des Solvers je nach Bedarf (glpk)
----> 3 results = solver.solve(m6)
      5 # Ergebnisse ausgeben
      6 print("Minimale Gestehungskosten:", m6.gestehungskosten())

File /opt/anaconda3/lib/python3.11/site-packages/pyomo/opt/base/solvers.py:598, in OptSolver.solve(self, *args, **kwds)
    594 try:
    595     # we're good to go.
    596     initial_time = time.time()
--> 598     self._presolve(*args, **kwds)
    600     presolve_completion_time = time.time()
    601     if self._report_timing:

File /opt/anaconda3/lib/python3.11/site-packages/pyomo/opt/solver/shellcmd.py:222, in SystemCallSolver._presolve(self, *args, **kwds)
    219 self._keepfiles = kwds.pop("keepfiles", False)
    220 self._define_signal_handlers = kwds.pop('use_signal_handling', None)
--> 222 OptSolver._presolve(self, *args, **kwds)
    224 #
    225 # Verify that the input problems exists
    226 #
    227 for filename in self._problem_files:

File /opt/anaconda3/lib/python3.11/site-packages/pyomo/opt/base/solvers.py:704, in OptSolver._presolve(self, *args, **kwds)
    701 if self._problem_format:
    702     write_start_time = time.time()
    703     (self._problem_files, self._problem_format, self._smap_id) = (
--> 704         self._convert_problem(
    705             args, self._problem_format, self._valid_problem_formats, **kwds
    706         )
    707     )
    708     total_time = time.time() - write_start_time
    709     if self._report_timing:

File /opt/anaconda3/lib/python3.11/site-packages/pyomo/opt/base/solvers.py:756, in OptSolver._convert_problem(self, args, problem_format, valid_problem_formats, **kwds)
    755 def _convert_problem(self, args, problem_format, valid_problem_formats, **kwds):
--> 756     return convert_problem(
    757         args, problem_format, valid_problem_formats, self.has_capability, **kwds
    758     )

File /opt/anaconda3/lib/python3.11/site-packages/pyomo/opt/base/convert.py:97, in convert_problem(args, target_problem_type, valid_problem_types, has_capability, **kwds)
     95                 tmpkw = kwds
     96                 tmpkw['capabilities'] = has_capability
---> 97                 problem_files, symbol_map = converter.apply(*tmp, **tmpkw)
     98                 return problem_files, ptype, symbol_map
    100 msg = 'No conversion possible.  Source problem type: %s.  Valid target types: %s'

File /opt/anaconda3/lib/python3.11/site-packages/pyomo/solvers/plugins/converter/model.py:78, in PyomoMIPConverter.apply(self, *args, **kwds)
     70         symbol_map_id = instance.write(
     71             problem_filename,
     72             format=ProblemFormat.cpxlp,
   (...)
     75             **io_options
     76         )
     77     else:
---> 78         (problem_filename, symbol_map_id) = instance.write(
     79             filename=problem_filename,
     80             format=ProblemFormat.cpxlp,
     81             solver_capability=capabilities,
     82             io_options=io_options,
     83         )
     84     return (problem_filename,), symbol_map_id
     85 else:
     86     #
     87     # I'm simply exposing a fatal issue with
   (...)
     90     # arguments that can be sent to the writer?
     91     #

File /opt/anaconda3/lib/python3.11/site-packages/pyomo/core/base/block.py:1937, in _BlockData.write(self, filename, format, solver_capability, io_options, int_marker)
   1934     def solver_capability(x):
   1935         return True
-> 1937 (filename, smap) = problem_writer(self, filename, solver_capability, io_options)
   1938 smap_id = id(smap)
   1939 if not hasattr(self, 'solutions'):
   1940     # This is a bit of a hack.  The write() method was moved
   1941     # here from PyomoModel to support the solution of arbitrary
   (...)
   1946     # dependency (we only need it here because we store the
   1947     # SymbolMap returned by the writer in the solutions).

File /opt/anaconda3/lib/python3.11/site-packages/pyomo/repn/plugins/lp_writer.py:208, in LPWriter.__call__(self, model, filename, solver_capability, io_options)
    205     io_options['allow_quadratic_constraint'] = qc
    207 with open(filename, 'w', newline='') as FILE:
--> 208     info = self.write(model, FILE, **io_options)
    209 return filename, info.symbol_map

File /opt/anaconda3/lib/python3.11/site-packages/pyomo/repn/plugins/lp_writer.py:241, in LPWriter.write(self, model, ostream, **options)
    237 # Pause the GC, as the walker that generates the compiled LP
    238 # representation generates (and disposes of) a large number of
    239 # small objects.
    240 with PauseGC():
--> 241     return _LPWriter_impl(ostream, config).write(model)

File /opt/anaconda3/lib/python3.11/site-packages/pyomo/repn/plugins/lp_writer.py:378, in _LPWriter_impl.write(self, model)
    376 repn = objective_visitor.walk_expression(obj.expr)
    377 if repn.nonlinear is not None:
--> 378     raise ValueError(
    379         f"Model objective ({obj.name}) contains nonlinear terms that "
    380         "cannot be written to LP format"
    381     )
    382 if repn.constant or not (repn.linear or getattr(repn, 'quadratic', None)):
    383     # Older versions of CPLEX (including 12.6) and all versions
    384     # of GLPK (through 5.0) do not support constants in the
   (...)
    390     # objective, this will ensure we at least write out
    391     # 0*ONE_VAR_CONSTANT.
    392     repn.linear[id(ONE_VAR_CONSTANT)] = repn.constant

ValueError: Model objective (gestehungskosten) contains nonlinear terms that cannot be written to LP format

感谢您的帮助

python pyomo
1个回答
0
投票

如果你面临非线性约束,你可以尝试的是使用另一个Python包:docplex,并且该API允许非线性约束和目标,因为这依赖于约束编程

小示例位于 https://github.com/AlexFleischerParis/zoodocplex/blob/master/zoononlinear.py

from docplex.cp.model import CpoModel

mdl = CpoModel(name='buses')
nbbus40 = mdl.integer_var(0,1000,name='nbBus40')
nbbus30 = mdl.integer_var(0,1000,name='nbBus30')
mdl.add(nbbus40*40 + nbbus30*30 >= 300)

#non linear objective
mdl.minimize(mdl.exponent(nbbus40)*500 + mdl.exponent(nbbus30)*400)

msol=mdl.solve()

print(msol[nbbus40]," buses 40 seats")
print(msol[nbbus30]," buses 30 seats") 
© www.soinside.com 2019 - 2024. All rights reserved.