Пиомо оптимальное решение найдено, но число решений 0 (моделирование гидроэнергетики) - PullRequest
0 голосов
/ 30 апреля 2018

Я хочу смоделировать гидроэнергетику в Норвегии, принимая во внимание все каскадные зависимости (для почасового разрешения). Для начала я поставил задачу оптимизации в Pyomo для набора из трех заводов и трех водохранилищ на один день. На данный момент я хочу максимизировать прибыль за все часы, и все установки / резервуары рассчитываются следующим образом: цена электроэнергии [$ / МВтч] * мощность турбины [МВт] * 3600 [с = 1 ч] + объем [м3] * эквивалент энергии [МВтч / м3] * цена на электроэнергию [$ / МВтч]

Мои ограничения:

Часовая нагрузка = генерируемая мощность должна равняться нагрузке в каждый час

Водный баланс = уровни хранения обновляются должным образом на каждом временном шаге

Начальный и конечный уровни хранения = при 60% от максимального хранения начало и конец периода моделирования (это в ограничении водного баланса)

ВОПРОСЫ:

1) почему оператор print печатает 0.0 для cascade_inflow и discharged_flow: потому что он печатается во время создания модели, а не при ее решении?

2A) Условие завершения является оптимальным, и у меня есть значение для целевой функции, но число решений равно 0: я думаю, что проблема заключается в ограничении водный баланс , я опубликую результаты ниже на 6 часов. Нужно ли как-то устанавливать ограничения верхней и нижней границ для водного баланса ? edit : если я запускаю скрипт из командной строки с pyomo решить --solver = glpk script.py input.dat Я получаю отображаемое решение ..?!

2B) Функция ограничения воды не работает должным образом. Если я посмотрю на результаты, то скачок громкости от временного шага 1 к 2 неосуществим. Что там не так? Является ли способ добавления каскадных потоков некорректным, или переменная m.volume просто делает то, что хочет?

3) Может быть, лучше создать проблему сетевого потока? Примеры кодов для подобных проблем есть в Pyomo Gallery . Но я еще не уверен, как моделировать узлы как резервуары. (Скорее всего, я сделаю для этого новый пост, как только попробую реализовать скрипт).

4) (Это мой первый пост: что-то я сделал не так или в следующий раз лучше?)

Код (чтение параметров пропущено)

from pyomo.environ import *
from pyomo.opt import SolverFactory

opt = SolverFactory("glpk")

# Initiate model instance
m = AbstractModel()

# Define the variable power for each time step
m.turbine = Var(m.stage, m.res, initialize=0, bounds=turbine_bounds, within=NonNegativeReals)
# Define the variable volume for each time step
m.volume = Var(m.stage, m.res, initialize=volume_Init,  bounds=volume_bounds, within=NonNegativeReals)
# Define the variable spill flow for each time step
m.spilledFlow = Var(m.stage, m.res, initialize=0, bounds=spill_bounds, within=NonNegativeReals)


# Constrain total power generated over day
def hourly_load_rule(model, t):
    return model.P_load*model.hourly_demand[t] <= sum(model.turbine[t, res] for res in model.res) <= model.P_load*model.hourly_demand[t]
m.hourly_load = Constraint(m.stage, rule=hourly_load_rule)


# Water balance equation
def water_balance_rule(model, t, r):
    if t == model.T:  # final volume is same as initial volume at 60%
        return model.volume[t, r] == model.max_Vol[r]*0.6
    elif t > 1:
        cascade_inflow = 0
        for stor in model.res:
            # connectMat is a matrix that has a 1 where there is a connection and 0 where there is not
            cascade_inflow = cascade_inflow + model.connectMat[stor, r]*(model.turbine[t, stor]/model.slope[stor]+model.spilledFlow[t, stor])
            if model.connectMat[stor, r] == 1:
                print(stor, r, t, value(cascade_inflow))  # this always prints out 0.0 for cascade_inflow
         discharged_flow = model.turbine[t, r]/model.slope[r]  # model.turbine is in MW: divide by slope to get discharge flow [m3/s]
         print(value(discharged_flow))  # this always prints out 0.0
         return model.volume[t, r] == model.volume[t-1, r]+(cascade_inflow+model.inflow[t, r]-model.spilledFlow[t, r]-discharged_flow)*model.secPerTimeStep
    else:
        # start volume constrained to 60% of max volume
        return model.volume[t, r] == model.max_Vol[r]*0.6
m.water_balance = Constraint(m.stage, m.res, rule=water_balance_rule)


# Revenue = Objective function (sum over all hours and all plants/reservoirs)
def revenue_rule(model):
    return sum(sum(model.el_price[i]*model.turbine[i, j]*model.secPerTimeStep+model.volume[i, j]*model.energy_stored[j]*model.el_price[i] for i in model.stage) for j in model.res)
m.obj = Objective(rule=revenue_rule, sense=maximize)

instance = m.create("three_input_stack.dat")

results = opt.solve(instance)

instance.display()

results.write()

Результаты

0.0
(1, 2, 2, 0.0)
0.0
(2, 3, 2, 0.0)
0.0
0.0
(1, 2, 3, 0.0)
0.0
(2, 3, 3, 0.0)
0.0
0.0
(1, 2, 4, 0.0)
0.0
(2, 3, 4, 0.0)
0.0
0.0
(1, 2, 5, 0.0)
0.0
(2, 3, 5, 0.0)
0.0
Model unknown

  Variables:
    turbine : Size=18, Index=turbine_index
        Key    : Lower : Value          : Upper : Fixed : Stale : Domain
        (1, 1) :     0 :           3.31 :  3.31 : False : False : NonNegativeReals
        (1, 2) :     0 :           3.71 :   5.9 : False : False : NonNegativeReals
        (1, 3) :     0 :            0.0 :   9.0 : False : False : NonNegativeReals
        (2, 1) :     0 :            0.8 :  3.31 : False : False : NonNegativeReals
        (2, 2) :     0 :            5.9 :   5.9 : False : False : NonNegativeReals
        (2, 3) :     0 :            0.0 :   9.0 : False : False : NonNegativeReals
        (3, 1) :     0 :            0.0 :  3.31 : False : False : NonNegativeReals
        (3, 2) :     0 : 0.242202133966 :   5.9 : False : False : NonNegativeReals
        (3, 3) :     0 :  6.31779786603 :   9.0 : False : False : NonNegativeReals
        (4, 1) :     0 :            0.0 :  3.31 : False : False : NonNegativeReals
        (4, 2) :     0 :            0.0 :   5.9 : False : False : NonNegativeReals
        (4, 3) :     0 :            6.5 :   9.0 : False : False : NonNegativeReals
        (5, 1) :     0 :            0.0 :  3.31 : False : False : NonNegativeReals
        (5, 2) :     0 :         1.9665 :   5.9 : False : False : NonNegativeReals
        (5, 3) :     0 :         4.6535 :   9.0 : False : False : NonNegativeReals
        (6, 1) :     0 :           3.31 :  3.31 : False : False : NonNegativeReals
        (6, 2) :     0 :           3.83 :   5.9 : False : False : NonNegativeReals
        (6, 3) :     0 :            0.0 :   9.0 : False : False : NonNegativeReals
    volume : Size=18, Index=volume_index
        Key    : Lower : Value         : Upper      : Fixed : Stale : Domain
        (1, 1) :   0.0 :    39600000.0 : 66000000.0 : False : False : NonNegativeReals
        (1, 2) :   0.0 :    10020000.0 : 16700000.0 : False : False : NonNegativeReals
        (1, 3) :   0.0 :     1260000.0 :  2100000.0 : False : False : NonNegativeReals
        (2, 1) :   0.0 : 32149783.0468 : 66000000.0 : False : False : NonNegativeReals
        (2, 2) :   0.0 : 16684216.9532 : 16700000.0 : False : False : NonNegativeReals
        (2, 3) :   0.0 :     2100000.0 :  2100000.0 : False : False : NonNegativeReals
        (3, 1) :   0.0 : 32167783.0468 : 66000000.0 : False : False : NonNegativeReals
        (3, 2) :   0.0 :    16700000.0 : 16700000.0 : False : False : NonNegativeReals
        (3, 3) :   0.0 :     2100000.0 :  2100000.0 : False : False : NonNegativeReals
        (4, 1) :   0.0 : 32185783.0468 : 66000000.0 : False : False : NonNegativeReals
        (4, 2) :   0.0 :    16700000.0 : 16700000.0 : False : False : NonNegativeReals
        (4, 3) :   0.0 :     2100000.0 :  2100000.0 : False : False : NonNegativeReals
        (5, 1) :   0.0 : 32203783.0468 : 66000000.0 : False : False : NonNegativeReals
        (5, 2) :   0.0 :    16700000.0 : 16700000.0 : False : False : NonNegativeReals
        (5, 3) :   0.0 :     2100000.0 :  2100000.0 : False : False : NonNegativeReals
        (6, 1) :   0.0 :    39600000.0 : 66000000.0 : False : False : NonNegativeReals
        (6, 2) :   0.0 :    10020000.0 : 16700000.0 : False : False : NonNegativeReals
        (6, 3) :   0.0 :     1260000.0 :  2100000.0 : False : False : NonNegativeReals
    spilledFlow : Size=18, Index=spilledFlow_index
        Key    : Lower : Value         : Upper   : Fixed : Stale : Domain
        (1, 1) :   0.0 :             0 : 10000.0 : False :  True : NonNegativeReals
        (1, 2) :   0.0 :             0 : 10000.0 : False :  True : NonNegativeReals
        (1, 3) :   0.0 :             0 : 10000.0 : False :  True : NonNegativeReals
        (2, 1) :   0.0 : 2069.67087236 : 10000.0 : False : False : NonNegativeReals
        (2, 2) :   0.0 : 213.332062039 : 10000.0 : False : False : NonNegativeReals
        (2, 3) :   0.0 :           0.0 : 10000.0 : False : False : NonNegativeReals
        (3, 1) :   0.0 :           0.0 : 10000.0 : False : False : NonNegativeReals
        (3, 2) :   0.0 :           0.0 : 10000.0 : False : False : NonNegativeReals
        (3, 3) :   0.0 :           0.0 : 10000.0 : False : False : NonNegativeReals
        (4, 1) :   0.0 :           0.0 : 10000.0 : False : False : NonNegativeReals
        (4, 2) :   0.0 :           5.0 : 10000.0 : False : False : NonNegativeReals
        (4, 3) :   0.0 : 4.22222222222 : 10000.0 : False : False : NonNegativeReals
        (5, 1) :   0.0 :           0.0 : 10000.0 : False : False : NonNegativeReals
        (5, 2) :   0.0 :           0.0 : 10000.0 : False : False : NonNegativeReals
        (5, 3) :   0.0 : 5.86355555556 : 10000.0 : False : False : NonNegativeReals
        (6, 1) :   0.0 :             0 : 10000.0 : False :  True : NonNegativeReals
        (6, 2) :   0.0 :             0 : 10000.0 : False :  True : NonNegativeReals
        (6, 3) :   0.0 :             0 : 10000.0 : False :  True : NonNegativeReals

  Objectives:
    obj : Size=1, Index=None, Active=True
        Key  : Active : Value
        None :   True : 39250323.6272

  Constraints:
    hourly_load : Size=6
        Key : Lower : Body : Upper
          1 :  7.02 : 7.02 :  7.02
          2 :   6.7 :  6.7 :   6.7
          3 :  6.56 : 6.56 :  6.56
          4 :   6.5 :  6.5 :   6.5
          5 :  6.62 : 6.62 :  6.62
          6 :  7.14 : 7.14 :  7.14
    water_balance : Size=18
         Key    : Lower      : Body               : Upper
         (1, 1) : 39600000.0 :         39600000.0 : 39600000.0
         (1, 2) : 10020000.0 :         10020000.0 : 10020000.0
         (1, 3) :  1260000.0 :          1260000.0 :  1260000.0
         (2, 1) :        0.0 :  2.14204192162e-08 :        0.0
         (2, 2) :        0.0 : -2.23517417908e-08 :        0.0
         (2, 3) :        0.0 : -5.82076609135e-10 :        0.0
         (3, 1) :        0.0 :                0.0 :        0.0
         (3, 2) :        0.0 :  1.55250745593e-08 :        0.0
         (3, 3) :        0.0 : -7.13669123797e-09 :        0.0
         (4, 1) :        0.0 :                0.0 :        0.0
         (4, 2) :        0.0 : -7.35411731512e-11 :        0.0
         (4, 3) :        0.0 : -6.39488462184e-12 :        0.0
         (5, 1) :        0.0 :                0.0 :        0.0
         (5, 2) :        0.0 : -5.49960077478e-10 :        0.0
         (5, 3) :        0.0 : -1.79056769412e-10 :        0.0
         (6, 1) : 39600000.0 :         39600000.0 : 39600000.0
         (6, 2) : 10020000.0 :         10020000.0 : 10020000.0
         (6, 3) :  1260000.0 :          1260000.0 :  1260000.0
# ==========================================================
# = Solver Results                                         =
# ==========================================================
# ----------------------------------------------------------
#   Problem Information
# ----------------------------------------------------------
Problem: 
- Name: unknown
  Lower bound: 39250323.6272
  Upper bound: 39250323.6272
  Number of objectives: 1
  Number of constraints: 25
  Number of variables: 49
  Number of nonzeros: 89
  Sense: maximize
# ----------------------------------------------------------
#   Solver Information
# ----------------------------------------------------------
Solver: 
- Status: ok
  Termination condition: optimal
  Statistics: 
    Branch and bound: 
      Number of bounded subproblems: 0
      Number of created subproblems: 0
  Error rc: 0
  Time: 0.0750000476837
# ----------------------------------------------------------
#   Solution Information
# ----------------------------------------------------------
Solution: 
- number of solutions: 0
  number of solutions displayed: 0

Входной файл

param secPerTimeStep:=3600;
param T:=6;
param numReservoirs:=3;
param connectMat:=
1   1   0
1   2   1
1   3   0
2   1   0
2   2   0
2   3   1
3   1   0
3   2   0
3   3   0;
param el_price:=
1   242.16
2   242.09
3   239.3
4   231.52
5   224.25
6   219.77;
param inflow:=
1   1   5
2   1   5
3   1   5
4   1   5
5   1   5
6   1   5
1   2   5
2   2   5
3   2   5
4   2   5
5   2   5
6   2   5
1   3   5
2   3   5
3   3   5
4   3   5
5   3   5
6   3   5;
param min_Vol:=
1   0.0
2   0.0
3   0.0;
param max_Vol:=
1   66000000.0
2   16700000.0
3   2100000.0;
param min_Turb_gen:=
1   0
2   0
3   0;
param max_Turb_gen:=
1   3.31
2   5.9
3   9.0;
param min_spill:=
1   0.0
2   0.0
3   0.0;
param max_spill:=
1   10000.0
2   10000.0
3   10000.0;
param min_discharge:=
1   0.0
2   0.0
3   0.0;
param max_discharge:=
1   20.0
2   15.0
3   8.0;
param slope:=
1   0.1655
2   0.3933
3   1.125;
param energy_stored:=
1   0.000046
2   0.000109
3   0.00031;
param hourly_demand:=
1   0.0351
2   0.0335
3   0.0328
4   0.0325
5   0.0331
6   0.0357;
param P_load:=200;

1 Ответ

0 голосов
/ 01 мая 2018

1) Нули всегда печатаются, потому что m.tubine инициализируется равным 0. Во время построения модели (то есть, когда выполняются операторы печати) выражения оцениваются в 0.

2A) Результат автоматически загружается обратно в модель после вызова решателя, поэтому команда instance.display() печатает результаты. Объект results используется только, если вы хотите отложить загрузку решений (это опция, которую вы можете установить при вызове решателя).

2B) Не уверен. Вы всегда можете выполнить команду instance.water_balance.pprint(), чтобы подтвердить, что выражения ограничений соответствуют вашим ожиданиям.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...