import json
import gurobipy as gp
import pandas as pd
from gurobipy import GRB


data = pd.read_csv("data/data.csv")
price = data['price']
load = data['load']
pre_pv = data['pv']
wind = data['wind']
period = len(data)

DG_parameters = {
    'gen_1': {'a': 0.0034, 'b': 3, 'c': 30,
              'power_output_max': 150, 'power_output_min': 10,
              'ramping_up': 100, 'ramping_down': 100},

    'gen_2': {'a': 0.001, 'b': 10, 'c': 40,
              'power_output_max': 375, 'power_output_min': 50,
              'ramping_up': 100, 'ramping_down': 100},

    'gen_3': {'a': 0.001, 'b': 15, 'c': 70,
              'power_output_max': 500, 'power_output_min': 100,
              'ramping_up': 200, 'ramping_down': 200}
}


def get_dg_info(parameters):
    p_max = []
    p_min = []
    ramping_up = []
    ramping_down = []
    a_para = []
    b_para = []
    c_para = []
    for name, gen_info in parameters.items():
        p_max.append(gen_info['power_output_max'])
        p_min.append(gen_info['power_output_min'])
        ramping_up.append(gen_info['ramping_up'])
        ramping_down.append(gen_info['ramping_down'])
        a_para.append(gen_info['a'])
        b_para.append(gen_info['b'])
        c_para.append(gen_info['c'])
    return p_max, p_min, ramping_up, ramping_down, a_para, b_para, c_para


p_max, p_min, ramping_up, ramping_down, a_para, b_para, c_para = get_dg_info(parameters=DG_parameters)
NUM_GEN = len(DG_parameters.keys())
grid_exchange_ability = 100
sell_coefficient = 0.5
battery_capacity = 500
battery_efficiency = 0.9
initial_soc = 0.2
battery_degradation = 0.01
battery_holding = 0.1
battery_maxcharge = 100
solar_cofficient = 0.01
wind_cofficient = 0.01

m = gp.Model("UC")

# 设置系统变量
on_off = m.addVars(NUM_GEN, period, vtype=GRB.BINARY, name='on_off')
gen_output = m.addVars(NUM_GEN, period, vtype=GRB.CONTINUOUS, name='output')
# 设置充放电约束
soc = m.addVars(period, vtype=GRB.CONTINUOUS, lb=0.2, ub=0.8, name='SOC')
battery_energy_change = m.addVars(period, vtype=GRB.CONTINUOUS, lb=-battery_maxcharge, ub=battery_maxcharge, name='battery_action')
# 设置外部电网与能源系统交换约束
grid_energy_import = m.addVars(period, vtype=GRB.CONTINUOUS, lb=0, ub=grid_exchange_ability, name='import')
grid_energy_export = m.addVars(period, vtype=GRB.CONTINUOUS, lb=0, ub=grid_exchange_ability, name='export')
# 设置电压控制约束
pv_voltage = m.addVars(period, vtype=GRB.CONTINUOUS, lb=-1, ub=1, name='pv_voltage')

# 计算光伏发电量
pv = [pre_pv[t] * (1 + pv_voltage[t]) for t in range(period)]

# 1. 添加平衡约束
m.addConstrs(((sum(gen_output[g, t] for g in range(NUM_GEN)) + pv[t] + wind[t] + grid_energy_import[t] == load[t]
               + battery_energy_change[t] + grid_energy_export[t]) for t in range(period)), name='powerbalance')
# 2. 添加发电机最大/最小功率约束
m.addConstrs((gen_output[g, t] <= on_off[g, t] * p_max[g] for g in range(NUM_GEN) for t in range(period)),
             'gen_output_max')
m.addConstrs((gen_output[g, t] >= on_off[g, t] * p_min[g] for g in range(NUM_GEN) for t in range(period)),
             'gen_output_min')
# 3. 添加上升和下降约束
m.addConstrs((gen_output[g, t + 1] - gen_output[g, t] <= ramping_up[g] for g in range(NUM_GEN)
              for t in range(period - 1)), 'ramping_up')
m.addConstrs((gen_output[g, t] - gen_output[g, t + 1] <= ramping_down[g] for g in range(NUM_GEN)
              for t in range(period - 1)), 'ramping_down')
# 4. 添加电池容量约束
m.addConstr(battery_capacity * soc[0] == battery_capacity * initial_soc +
            (battery_energy_change[0] * battery_efficiency), name='soc0')
m.addConstrs((battery_capacity * soc[t] == battery_capacity * soc[t - 1] +
              (battery_energy_change[t] * battery_efficiency) for t in range(1, period)), name='soc update')
# 设置成本函数
cost_gen = gp.quicksum(
    (a_para[g] * gen_output[g, t] * gen_output[g, t] + b_para[g] * gen_output[g, t] + c_para[g] * on_off[g, t])
    for t in range(period) for g in range(NUM_GEN))
cost_battery = gp.quicksum(
    battery_energy_change[t] * battery_degradation + soc[t] * battery_holding for t in range(period))
cost_import = gp.quicksum(grid_energy_import[t] * price[t] for t in range(period))
cost_export = gp.quicksum(grid_energy_export[t] * price[t] * sell_coefficient for t in range(period))
cost_solar = gp.quicksum(pv[t] * solar_cofficient for t in range(period))
cost_wind = gp.quicksum(wind[t] * wind_cofficient for t in range(period))

m.setObjective((cost_gen + cost_battery + cost_import - cost_export + cost_solar + cost_wind), GRB.MINIMIZE)
m.optimize()

# 记录动作便于辅助决策
results = []
for t in range(period):
    action = [battery_energy_change[t].x / 100,
              (gen_output[0, t].x - (gen_output[0, t - 1].x if t > 0 else 0)) / 100,
              (gen_output[1, t].x - (gen_output[1, t - 1].x if t > 0 else 0)) / 100,
              (gen_output[2, t].x - (gen_output[2, t - 1].x if t > 0 else 0)) / 200,
              pv_voltage[t].x - (pv_voltage[t - 1].x if t > 0 else 0)]
    results.append(action)
with open('./results_9.3.json', 'w') as f:
    json.dump(results, f, indent=2)
