pythonoptimizationpyomoglpk

How to run this simple optimization program with Pyomo?


I am trying to run a 'simple' optimation programm without any constraints to get the programming running. After getting the program running I am planning on adding constraints and other input variables. However, I cannot seem to get the model to work. I have filterd the used dateframe down to just 2 days for computational feasability. The dataframe named df contains dates on a 15 minute interval (datetime) and two column with building load and PV generation, both floats(See attached figure). Example of df

I used the following code just to see if the optimzation problem works. Note that no constraints are added (Pgrid_max is commented out). Eventually I will add a data set with data on EV charging to optimize bi-directional EV charging.

start_date = '2023-06-01 00:00:00'
end_date = '2023-06-02 23:59:59'

# Pgrid_max = (df['Building load [kWh]'].max() + 24*18*0.25) * 1.5

model = ConcreteModel()

# Time intervals
T = df[start_date:end_date].index.tolist() # Create a list of the timesteps

# Sets
model.T = Set(initialize=T) # Time interval

# Parameters
model.Pbuilding = Param(model.T, initialize=df[start_date:end_date]['Building load [kWh]'].to_dict())
model.Ppv = Param(model.T, initialize=df[start_date:end_date]['PV load [kWh]'].to_dict())


# Variables
model.Pgrid = Var(model.T, domain=Reals)
# model.Pev = Var(model.T, domain=PositiveReals, bounds=(0, 24*0.25)) 


# Energy balance equation
def energy_balance(model, t):
    return model.Pgrid[t] == model.Pbuilding[t] - model.Ppv[t]

# Objective function
def objective_rule(model):
    return sum(model.Pgrid[t] for t in model.T)

model.obj = Objective(rule=objective_rule, sense=minimize)

# Solve the model (assuming you have a solver like glpk installed)
solver = SolverFactory('glpk')
solver.solve(model, tee=True)

# Extract results directly into a pandas DataFrame
results = pd.DataFrame(index=T)
results['Pgrid'] = [model.Pgrid[t].value for t in T]

for t in model.T:
    results['Pgrid'][t] = model.Pgrid[t].value

print(results)

When running this code I keep getting the message that the problem has no solution. How can this be the case sinde Pgrid can take any real value. Printing the results gives only "None" values. Anyone that knows what I am doing wrong?


Solution

  • You have a couple issues in your code.

    The most significant (and why you are probably getting zeros) is that you didn't construct the constraint. You need to call the function as a rule as shown in the code below.

    A couple other tips/ideas:

    On your model:

    Code:

    """
    Simple Power Grid Model
    """
    from pyomo.environ import *
    import pandas as pd
    
    ### DATA
    
    # take pandas out of the equation for simple model...
    load = { 0:  8.2,
             15: 9.5,
             30: 7.7,
             45: 4.3}
    
    pv = {   0:  4.2,
             15: 5.1,
             30: 6.0,
             45: 8.8}
    
    # start_date = '2023-06-01 00:00:00'
    # end_date = '2023-06-02 23:59:59'
    
    model = ConcreteModel()
    
    # Time intervals
    # T = df[start_date:end_date].index.tolist() # Create a list of the timesteps
    
    # Sets
    model.T = Set(initialize=load.keys()) # Time interval
    
    # Parameters
    model.Pbuilding = Param(model.T, initialize=load) # df[start_date:end_date]['Building load [kWh]'].to_dict())
    model.Ppv = Param(model.T, initialize=pv) # df[start_date:end_date]['PV load [kWh]'].to_dict())
    
    
    # Variables
    model.Pgrid = Var(model.T, domain=NonNegativeReals) # probably can't "push" back to grid...
    # model.Pev = Var(model.T, domain=PositiveReals, bounds=(0, 24*0.25))
    
    
    # Energy balance equation
    def energy_balance(model, t):
        # make this a GTE constraint:  must pull enough from grid to make up deficit, if there is one
        return model.Pgrid[t] >= model.Pbuilding[t] - model.Ppv[t]
    # you were MISSING the contraint construction call w/ a rule:
    model.balance = Constraint(model.T, rule=energy_balance)
    
    # Objective function
    def objective_rule(model):
        return sum(model.Pgrid[t] for t in model.T)
    model.obj = Objective(rule=objective_rule, sense=minimize)
    
    #  INSPECT THE MODEL!!!
    model.pprint()
    
    # Solve the model (assuming you have a solver like glpk installed)
    solver = SolverFactory('cbc')  # or glpk or ...
    results = solver.solve(model, tee=True)  # catch the results object
    
    #  Ensure that it was OPTIMAL or results are junk
    status = results.Solver()['Termination condition'].value
    assert status == 'optimal', f'error occurred, status: {status}.  Check model!'
    
    # Extract results directly into a pandas DataFrame
    results = pd.DataFrame(index=model.T)
    
    # providing the item pairs is "safer" as there is no risk of issues
    # with the order of the values pulled from the set model.T
    results['Pgrid'] = pd.Series({k:v.value for k, v in model.Pgrid.items()}) # [model.Pgrid[t].value for t in model.T]
    
    print(results)
    

    Output:

    1 Set Declarations
        T : Size=1, Index=None, Ordered=Insertion
            Key  : Dimen : Domain : Size : Members
            None :     1 :    Any :    4 : {0, 15, 30, 45}
    
    2 Param Declarations
        Pbuilding : Size=4, Index=T, Domain=Any, Default=None, Mutable=False
            Key : Value
              0 :   8.2
             15 :   9.5
             30 :   7.7
             45 :   4.3
        Ppv : Size=4, Index=T, Domain=Any, Default=None, Mutable=False
            Key : Value
              0 :   4.2
             15 :   5.1
             30 :   6.0
             45 :   8.8
    
    1 Var Declarations
        Pgrid : Size=4, Index=T
            Key : Lower : Value : Upper : Fixed : Stale : Domain
              0 :     0 :  None :  None : False :  True : NonNegativeReals
             15 :     0 :  None :  None : False :  True : NonNegativeReals
             30 :     0 :  None :  None : False :  True : NonNegativeReals
             45 :     0 :  None :  None : False :  True : NonNegativeReals
    
    1 Objective Declarations
        obj : Size=1, Index=None, Active=True
            Key  : Active : Sense    : Expression
            None :   True : minimize : Pgrid[0] + Pgrid[15] + Pgrid[30] + Pgrid[45]
    
    1 Constraint Declarations
        balance : Size=4, Index=T, Active=True
            Key : Lower              : Body      : Upper : Active
              0 :  3.999999999999999 :  Pgrid[0] :  +Inf :   True
             15 :                4.4 : Pgrid[15] :  +Inf :   True
             30 : 1.7000000000000002 : Pgrid[30] :  +Inf :   True
             45 : -4.500000000000001 : Pgrid[45] :  +Inf :   True
    
    6 Declarations: T Pbuilding Ppv Pgrid balance obj
    Welcome to the CBC MILP Solver 
    Version: 2.10.10 
    Build Date: Jul 24 2023 
    
    command line - /opt/homebrew/opt/cbc/bin/cbc -printingOptions all -import /var/folders/7l/f196n6c974x3yjx5s37t69dc0000gn/T/tmp28wkyeg0.pyomo.lp -stat=1 -solve -solu /var/folders/7l/f196n6c974x3yjx5s37t69dc0000gn/T/tmp28wkyeg0.pyomo.soln (default strategy 1)
    Option for printingOptions changed from normal to all
    Presolve 0 (-4) rows, 0 (-4) columns and 0 (-4) elements
    Statistics for presolved model
    
    
    Problem has 0 rows, 0 columns (0 with objective) and 0 elements
    Column breakdown:
    0 of type 0.0->inf, 0 of type 0.0->up, 0 of type lo->inf, 
    0 of type lo->up, 0 of type free, 0 of type fixed, 
    0 of type -inf->0.0, 0 of type -inf->up, 0 of type 0.0->1.0 
    Row breakdown:
    0 of type E 0.0, 0 of type E 1.0, 0 of type E -1.0, 
    0 of type E other, 0 of type G 0.0, 0 of type G 1.0, 
    0 of type G other, 0 of type L 0.0, 0 of type L 1.0, 
    0 of type L other, 0 of type Range 0.0->1.0, 0 of type Range other, 
    0 of type Free 
    Presolve 0 (-4) rows, 0 (-4) columns and 0 (-4) elements
    Empty problem - 0 rows, 0 columns and 0 elements
    Optimal - objective value 10.1
    After Postsolve, objective 10.1, infeasibilities - dual 0 (0), primal 0 (0)
    Optimal objective 10.1 - 0 iterations time 0.002, Presolve 0.00
    Total time (CPU seconds):       0.00   (Wallclock seconds):       0.00
    
        Pgrid
    0     4.0
    15    4.4
    30    1.7
    45    0.0
    
    Process finished with exit code 0