Reputation: 502
I've built a pyomo concrete model and am trying to run it using a python script (Pyomo version 5.2 with python 3.7). When I try solving the model by running:
opt = SolverFactory('glpk')
results = opt.solve(model)
results.write()
then I get this error:
ValueError: ERROR: No objectives defined for input model; cannot write legal LP file
Interstingly I know the objective rule works. When I run Objective_rule(model)
I get a value back, and I can also manually change the model variables by assigning them different values, such as:
model.system_capacity = 1000
with the return value from the objective rule changing in response.
Any thoughts? I'm pretty new to pyomo and Algebraic Modeling Languages (AMLs) in general.
Here's my model, simplified:
# pyomo model for fitting historical solar generation profile to PVWatts simulation
# initialize input parameters
system_capacity_init = 1.0
lims = [0.2, 3.0]
system_capacity_bounds = (system_capacity_init * lims[0], system_capacity_init * lims[1])
# define and initialize integer parameters
# module type
module_type_dict = {0: 'Standard', 1: 'Premium', 2: 'ThinFilm'}
module_type_vals = list(module_type_dict.keys())
module_type_index_init = 0
# initialize pyomo concrete model
model = ConcreteModel()
# define continuous variables
model.system_capacity = Var(initialize=system_capacity_init,
bounds=system_capacity_bounds,
domain=PositiveReals)
# define integer variables
# module type
model.module_type_vals = Set(initialize=module_type_vals)
model.module_type = Var(initialize=module_type_vals[module_type_index_init],
within=model.module_type_vals)
# define objective function
def Objective_rule(model):
"""get hourly modeled solar roduction from PVWatts5 simulation tool using hourly historical solar insolation
defined in filename_solar comparing against hourly historical date in hourlysettlementdata"""
system_capacity = value(model.system_capacity)
module_type = value(model.module_type)
hourlypvwatts = sf.gethourlysolarproduction(filename_solar, folder,
system_capacity, module_type)
leastsquared = np.sum((hourlypvwatts[:8760] - hourlysettlementdata[:8760])**2)
return float(leastsquared)
# when passed function named as _rule then automatically assigns as rule, defaulte sense=minimize
model.Objective = Objective()
# examine model
model.pprint()
And here's the pprint / model declaration (again I cut out some variables so it is shorter...):
1 Set Declarations
module_type_vals : Dim=0, Dimen=1, Size=3, Domain=None, Ordered=False, Bounds=(0, 2)
[0, 1, 2]
2 Var Declarations
module_type : Size=1, Index=None
Key : Lower : Value : Upper : Fixed : Stale : Domain
None : 0 : 0 : 2 : False : False : module_type_vals
system_capacity : Size=1, Index=None
Key : Lower : Value : Upper : Fixed : Stale : Domain
None : 12.0 : 60.0 : 180.0 : False : False : PositiveReals
1 Objective Declarations
Objective : Size=0, Index=None, Active=True
Key : Active : Sense : Expression
12 Declarations: system_capacity dc_ac_ratio inv_eff losses tilt azimuth gcr module_type_vals module_type array_type_vals array_type Objective
Thanks for any help.
Upvotes: 0
Views: 903
Reputation: 2634
I was going to post this as a comment to @bethany-nicholson, but there is enough additional information to warrant an additional answer.
First, the answer about returning an expression instead of a computed value (i.e., rules generate expressions and are not callbacks) is spot-on and correct.
The remainder of this answer targets the use of "implicit rules". While older versions of Pyomo supported "implicit rules" (i.e., a component foo
automatically looking for and using a foo_rule()
if no rule was explicitly provided), that behavior was deprecated in Pyomo 4.0, and the developers threatened to remove it completely in Pyomo 5.0 (although as of 5.5 the functionality - with deprecation warning - is still there).
That said, it appears that implicit rules have never worked for Objective
components (the implicit rule functionality was built into the Block component, and relied on rules being stored as a _rule
attribute in the Component ... and Objective uses rule
instead of _rule
). This fragility is in part why support for implicit rules was deprecated.
If you are looking for a concise notation for specifying models, you might consider the component decorator notation:
@model.Objective()
def obj(m):
return # expression defining the objective
This creates an Objective component and attaches it to the model
object using the name obj
, assigning the obj()
function as the component's rule.
Upvotes: 1
Reputation: 2828
As mentioned in the comment, you didn't pass in the objective function rule when declaring your objective function. Your objective function declaration should be:
model.Objective = Objective(rule=Objective_rule)
The other issue I see is that your objective function rule doesn't look like it depends on any of the variables in the model and will be a fixed float value the way it is currently written. Remember that the objective function rule is not a call-back function that is evaluated multiple times by the solver. The objective function rule should return an algebraic expression involving Pyomo variables.
Upvotes: 1