calliope-project / calliope

A multi-scale energy systems modelling framework
https://www.callio.pe
Apache License 2.0
286 stars 93 forks source link

Obtaining duals from linear optimization model #283

Closed CROdominik closed 7 months ago

CROdominik commented 4 years ago

Problem description

Obtaining duals is useful in linear optimization problems in order to know e.g. the marginal generation price in a specific timestep. Gurobi has the attribute 'Pi' for this purpose and Pyomo has a pyo.Suffix attribute. Right now, Calliope itself cannot print out duals. Knowing marginal prices at specific timesteps is also very useful for coupling Calliope with different models, and linking of different models is becoming more and more important topic in the energy modelling. The problem is that when I tried to interact with Pyomo, I couldn't obtained the duals as it threw an error.

Steps to reproduce the problem

Any Calliope model:

model=calliope.Model(r'C:\Users\dodo\Google_Drive\2_postdoc\Krk_paper\KrkCalliope\model.yaml') #loading a model
model.dual = pyo.Suffix(direction=pyo.Suffix.IMPORT) #this I use to interact with Pyomo to show that I want duals
model.run(force_rerun=True)

And then I want to print the duals with the following:

print ("Duals")
for c in model.component_objects(pyo.Constraint, active=True):
    print ("   Constraint",c)
    for index in c:
        print ("      ", index, model.dual[c[index]])

I get the following error:

"AttributeError: 'Model' object has no attribute 'component_objects"

Alternatively, when I try to print out a specific dual variables via:

print ("Dual for Ele=", model.dual[model.AxbConstraint['Electrical demand']])

I get the error:

"'Model' object has no attribute 'AxbConstraint'"

Calliope version

Version 0.6.4

brynpickering commented 4 years ago

This should do the trick:

import pyomo.core as pyo
import calliope

model = calliope.Model(...)
model.run(build_only=True)
model._backend_model.dual = pyo.Suffix(direction=pyo.Suffix.IMPORT)

model2 = model.backend.rerun()

then:

print ("Duals")
for c in model._backend_model.component_objects(pyo.Constraint, active=True):
    print ("   Constraint",c)
    for index in c:
        print ("      ", index, model._backend_model.dual[c[index]])
sjpfenninger commented 4 years ago

Doing this in a cleaner way should be considered in discussing #293

sjpfenninger commented 7 months ago

Available in v0.7 of #540