Как установить ограничение в зависимости от предыдущего заданного индекса

Я пишу модель оптимизации энергопотребления с помощью Pyomo. В этой модели у меня есть ограничение, которое обновляет уровень заряда накопителя энергии на каждом временном шаге, используя уровень заряда на предыдущем временном шаге (упрощенное уравнение):

Storage_level[t] = Storage_level[t-1] + Charge [t] - Discharge [t]

И есть дополнительное ограничение на начальный период:

Storage_level[1] = 0

Когда я запускаю задачу, я не получаю никакого полезного результата, а в окне вывода просто отображаются границы ограничений, например:

ev_soc_max : Size=24
    Key : Lower : Body : Upper
      1 :  None : None :   0.0
      2 :  None : None :   0.0
      3 :  None : None :   0.0
      4 :  None : None :   0.0
      5 :  None : None :   0.0
      ...

и я также получаю эту ошибку для некоторых переменных:

ERROR: evaluating object as numeric value: p_bat_ch[1]
        (object: <class 'pyomo.core.base.var._GeneralVarData'>)
    No value for uninitialized NumericValue object p_bat_ch[1]

Подозреваю, что проблема связана с определением ограничений хранилища.

Вот как я закодировал это в Pyomo (я пришел к этому результату, объединив разные примеры, которые я нашел здесь и там в Интернете):

def bat_soc_ini_rule(model, t):
    if t == 1:
        return model.e_bat_t[t] == 0.
    else:
        return Constraint.Skip
model.bat_soc_ini = Constraint(model.T, rule = bat_soc_ini_rule)

def bat_soc_rule(model, t):
    if t >= 2:
        return model.e_bat_t[t] == model.eta_bat_cal * model.e_bat_t[t-1] + model.eta_bat_ch * model.p_bat_ch[t] - model.eta_bat_dis**-1 * model.p_bat_dis[t]
    else:
        return Constraint.Skip
model.bat_soc = Constraint(model.T, rule = bat_soc_rule)

Я также должен заявить, что я объявил набор model.T с помощью model.T = RangeSet(24), а переменные объявлены следующим образом: model.e_bat_t = Var(model.T, within = NonNegativeReals)

И последнее: я использую GLPK в качестве решателя.

Мои вопросы:

  1. Как мне объявить ограничение, которое вызывает предыдущий член набора? Правильно ли я делаю?

  2. Как мне установить ограничение только для части набора (например, для ограничения инициализации)?

  3. Правильно ли я считаю, что ошибка возникает из-за неправильного определения этого ограничения? Если нет, знаете ли вы, откуда могла взяться проблема?


person johnwolf1987    schedule 18.02.2019    source источник
comment
Я не вижу проблем с тем, как вы объявили свои ограничения. Чтобы отладить вашу модель, я бы рекомендовал использовать функцию model.pprint() для распечатки модели и вручную проверить, соответствуют ли выражения ограничений ожидаемым вами. Вы также должны добавить параметр tee=True к вашему вызову solve, чтобы отобразить выходные данные решателя и проверить наличие там каких-либо проблем.   -  person Bethany Nicholson    schedule 18.02.2019
comment
Спасибо за совет. Мне было интересно, что происходит с решателем, и я не знал, как получить информацию из решателя. Это не решило проблему, но дало мне еще несколько инструментов, которые помогут мне найти решение.   -  person johnwolf1987    schedule 19.02.2019
comment
И я забыл упомянуть, что это помогло мне определить, что решатель действительно работает, но дает в качестве вывода: ПРОБЛЕМА НЕ ИМЕЕТ ОСНОВНОГО ВОЗМОЖНОГО РЕШЕНИЯ.   -  person johnwolf1987    schedule 19.02.2019


Ответы (1)


Что ж, я работаю с urbs atm, и из него исходит следующий код.

Это правило ограничения, которое вы ищете storage[t] = storage[t-1] + in - out

# storage content in timestep [t] == storage content[t-1] * (1-discharge)
# + newly stored energy * input efficiency
# - retrieved energy / output efficiency
def def_storage_state_rule(m, t, sit, sto, com):
    return (m.e_sto_con[t, sit, sto, com] ==
            m.e_sto_con[t-1, sit, sto, com] *
            (1 - m.storage_dict['discharge'][(sit, sto, com)]) ** m.dt.value +
            m.e_sto_in[t, sit, sto, com] *
            m.storage_dict['eff-in'][(sit, sto, com)] -
            m.e_sto_out[t, sit, sto, com] /
            m.storage_dict['eff-out'][(sit, sto, com)])

А для установки значения инициализации у них есть что-то вроде следующего:

# initialization of storage content in first timestep t[1]
# forced minimun  storage content in final timestep t[len(m.t)]
# content[t=1] == storage capacity * fraction <= content[t=final]
def res_initial_and_final_storage_state_rule(m, t, sit, sto, com):
    if t == m.t[1]:  # first timestep (Pyomo uses 1-based indexing)
        return (m.e_sto_con[t, sit, sto, com] ==
                m.cap_sto_c[sit, sto, com] *
                m.storage_dict['init'][(sit, sto, com)])
    elif t == m.t[len(m.t)]:  # last timestep
        return (m.e_sto_con[t, sit, sto, com] >=
                m.cap_sto_c[sit, sto, com] *
                m.storage_dict['init'][(sit, sto, com)])
    else:
        return pyomo.Constraint.Skip

Надеюсь, этот пример вам поможет. Вы можете использовать его, изменить или адаптировать в своем коде -

person oakca    schedule 05.03.2019
comment
Спасибо, что поделились своим кодом. На самом деле, я отказался от использования Pyomo и вместо этого начал использовать PuLP, который я считаю более удобным и простым в использовании для проблем с MILP. После перехода на PuLP выяснилось, что то, как были установлены мои ограничения для хранилища, делало проблему невыполнимой. Теперь моя модель работает нормально в PuLP, но я еще не нашел времени, чтобы вернуться и исправить модель в Pyomo, чтобы посмотреть, решает ли она ее. Если я дойду до него, я дам вам знать. - person johnwolf1987; 09.03.2019
comment
Вы уверены, что t-1 в m.e_sto_con[t-1, sit, sto, com] работает? Я все еще получаю сообщение об ошибке, в котором говорится, что он может только объединять str. - person PM0087; 07.06.2021