Search code examples
loopsvariablespyomo

How to store last value from a pyomo optimization loop and use it as initialisation for the next optimization loop?


UPDATE

Busy with an optimization on battery storage, I face an issue while trying to optimize the model based on loops of 36 hours, for example, running for a full year of data.
By doing this, I reinitialize the variable that matters at each step and therefore compromising the model. How to extract the last value of a variable and use it for the next iteration as first value ? Here is the problem in a simple way:

#creation of list to store last variable values:
df1=[]
df2=[]
df3=[]

# Loop  
for i in range (0,3)
        step = 36
        first_model_hour = step * i
        last_model_hour = (step * (i+1)) - 1
        
        model = ConcreteModel() 

        model.T = Set(doc='hour of year',initialize=df.index.tolist())
        model.A = Var(model.T, NonNegativeReals)
        model.B = Var(model.T, NonNegativeReals)
        model.C = Var(model.T, NonNegativeReals)

     def constraints_x(model,t)
           for t == 0
               return model.C == 100
           elif t == first_model_hour
               return model.C[t] == model.A[from previous loop] + model.B[from previous loop] + model.C[from previous loop]           
           else
               return model.C[t] == model.A[t-1]+model.B[t-1]+model.C[t-1]
       
       model.constraint = Constraint(model.T, rule=constraint_x)
        
       solver = SolverFactory('cbc')
       solver.solve(model)
       
       df1.append(model.S[last_model_hour])
       df2.append(model.B[last_model_hour])
       df3.append(model.C[last_model_hour])

Is it possible to retrieve the last value of variables from pyomo to use it a initialization for the next loop and hence not loosing the continuous state of charge of the battery over time ?


Solution

  • Here is a full model that implements what I think you want to do; which is to carry over a value from a previous iteration. This builds on the previous answer/example.

    # rolling time horizon
    
    import pyomo.environ as pyo
    
    periods = 3
    num_segments = 4
    
    starting_value = 2.0
    
    solver = pyo.SolverFactory('cbc')
    
    for period in range(periods):
        segments = list(range(period*num_segments, (period + 1) * num_segments))  # the time segments in this per
    
        model = pyo.ConcreteModel()
        model.S = pyo.Set(initialize=segments)
        model.X = pyo.Var(model.S, domain=pyo.NonNegativeReals)
    
        # assign the first value and fix it
        model.X[model.S.first()] = starting_value
        model.X[model.S.first()].fix()
    
        # dummy constraint to constrain each value to 1 greater than previous.
        def C1(model, s):
            if s == model.S.first():
                return pyo.Constraint.Skip
            return model.X[s] <= model.X[s-1] + 1
    
        model.C1 = pyo.Constraint(model.S, rule=C1)
    
        # obj:  maximize X
        model.obj = pyo.Objective(expr=pyo.summation(model.X), sense=pyo.maximize)
    
        # solve
        result = solver.solve(model)
        assert(result.Solver()['Termination condition'].value == 'optimal')  # a little insurance
        # print(result)
        # model.display()
    
        starting_value = pyo.value(model.X[model.S.last()]) + 1
    
        # rolling printout of results...
        print(f'From iteration {period}:')
        model.X.display()
    

    Yields:

    From iteration 0:
    X : Size=4, Index=S
        Key : Lower : Value : Upper : Fixed : Stale : Domain
          0 :     0 :   2.0 :  None :  True :  True : NonNegativeReals
          1 :     0 :   3.0 :  None : False : False : NonNegativeReals
          2 :     0 :   4.0 :  None : False : False : NonNegativeReals
          3 :     0 :   5.0 :  None : False : False : NonNegativeReals
    From iteration 1:
    X : Size=4, Index=S
        Key : Lower : Value : Upper : Fixed : Stale : Domain
          4 :     0 :   6.0 :  None :  True :  True : NonNegativeReals
          5 :     0 :   7.0 :  None : False : False : NonNegativeReals
          6 :     0 :   8.0 :  None : False : False : NonNegativeReals
          7 :     0 :   9.0 :  None : False : False : NonNegativeReals
    From iteration 2:
    X : Size=4, Index=S
        Key : Lower : Value : Upper : Fixed : Stale : Domain
          8 :     0 :  10.0 :  None :  True :  True : NonNegativeReals
          9 :     0 :  11.0 :  None : False : False : NonNegativeReals
         10 :     0 :  12.0 :  None : False : False : NonNegativeReals
         11 :     0 :  13.0 :  None : False : False : NonNegativeReals