Search code examples
constraintspyomoscalar

Constraint issue with pyomo involving a scalar


working on an economic optimization problem with pyomo, I would like to add a constraint to prevent the product of the commodity quantity and its price to go below zero (<0), avoiding a negative revenue. It appears that all the data are in a dataframe and I can't setup a constraint like:

def positive_revenue(model, t)
    return model.P * model.C >=0
model.positive_rev = Constraint(model.T, rule=positive_revenue)

The system returns the error that the price is a scalar and it cannot process it. Indeed the price is set as such in the model:

model.T = Set(doc='quarter of year', initialize=df.quarter.tolist(), ordered=True)



model.P = Param(initialize=df.price.tolist(), doc='Price for each quarter')

##while the commodity is:
model.C = Var(model.T, domain=NonNegativeReals)

I just would like to apply that for each timestep (quarter of hour here) that:

price(t) * model.C(t) >=0

Can someone help me to spot the issue ? Thanks

Here are more information:

df dataframe:

df                   time_stamp  price Status  imbalance  
quarter                                                                                                                                  
0       2021-01-01 00:00:00  64.84  Final         16          
1       2021-01-01 00:15:00  13.96  Final         38          
2       2021-01-01 00:30:00  12.40  Final         46  

index = quarter from 0 till 35049, so it is ok

Here is the df.info()
#   Column          Non-Null Count  Dtype         
---  ------          --------------  -----         
 0   time_stamp      35040 non-null  datetime64[ns]
 1   price           35040 non-null  float64       
 2   Status          35040 non-null  object        
 3   imbalance       35040 non-null  int64  

   

I modified the to_list() > to_dict() in model.T but still facing the same issue:

KeyError: "Cannot treat the scalar component 'P' as an indexed component" at the time model.T is defined in the model parameter, set and variables.

Here is the constraint where the system issues the error:

def revenue_positive(model,t):
        for t in model.T:
            return (model.C[t] * model.P[t]) >= 0
    
    model.positive_revenue = Constraint(model.T,rule=revenue_positive)

Can't figure it out...any idea ? UPDATE Model works after dropping an unfortunate 'quarter' column somewhere...after I renamed the index as quarter. It runs but i still get negative revenues, so the constraints seems not working at present, here is how it is written:

def revenue_positive(model,t): for t in model.T: return (model.C[t] * model.P[t]) >= 0

model.positive_revenue = Constraint(model.T,rule=revenue_positive)

What am I missing here ? Thanks for help, just beginning


Solution

  • Welcome to the site.

    The problem you appear to be having is that you are not building your model parameter model.P as an indexed component. I believe you likely want it to be indexed by your set model.T.

    When you make indexed params in pyomo you need to initialize it with some key:value pairing, like a python dictionary. You can make that from your data frame by re-indexing your data frame so that the quarter labels are the index values.

    Caution: The construction you have for model.T and this assume there are no duplicates in the quarter names.

    If you have duplicates (or get a warning) then you'll need to do something else. If the quarter labels are unique you can do this:

    import pandas as pd
    import pyomo.environ as pyo
    df = pd.DataFrame({'qtr':['Q5', 'Q6', 'Q7'], 'price':[12.80, 11.50, 8.12]})
    df.set_index('qtr', inplace=True)
    print(df)
    
    m = pyo.ConcreteModel()
    m.T = pyo.Set(initialize=df.index.to_list())
    m.price = pyo.Param(m.T, initialize=df['price'].to_dict())
    
    m.pprint()
    

    which should get you:

         price
    qtr       
    Q5   12.80
    Q6   11.50
    Q7    8.12
    
    1 Set Declarations
        T : Size=1, Index=None, Ordered=Insertion
            Key  : Dimen : Domain : Size : Members
            None :     1 :    Any :    3 : {'Q5', 'Q6', 'Q7'}
    
    1 Param Declarations
        price : Size=3, Index=T, Domain=Any, Default=None, Mutable=False
            Key : Value
             Q5 :  12.8
             Q6 :  11.5
             Q7 :  8.12
    
    2 Declarations: T price
    

    edit for clarity...

    NOTE:

    The first argument when you create a pyomo parameter is the indexing set. If this is not provided, pyomo assumes that it is a scalar. You are missing the set as shown in my example and highlighted with arrow here: :)

                         |
                         |
                         |
                         V
    m.price = pyo.Param(m.T, initialize=df['price'].to_dict())
    

    Also note, you will need to initialize model.P with a dictionary as I have in the example, not a list.