import numpy as np
import pandas as pd
import json
from scipy.optimize import minimize
from pyswarm import pso

# 读取数据
file_path = './data.csv'
data = pd.read_csv(file_path)

# 初始化状态
initial_soc = 0.4  # 电池初始荷电状态
initial_sg1 = 0
initial_sg2 = 0
initial_sg3 = 0
battery_capacity = 500 * initial_soc

# 参数设置
battery_efficiency = 0.9
battery_degradation = 0.01
battery_holding = 0.1
solar_cofficient = 0.01
volatage_change_percent = 0.1
wind_cofficient = 0.01

# 发电机参数
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}
}

NUM_GEN = len(DG_parameters.keys())
period = 100  # 处理前 100 个数据


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)


# 目标函数
def objective(x, period_batch, start, initial_states):
    total_cost = 0
    soc, sg1, sg2, sg3 = initial_states
    for t in range(period_batch):
        Ac, Ag1, Ag2, Ag3, Av = x[t * 5:(t + 1) * 5]
        Pc = max(0.2, min(0.8, soc + 0.2 * Ac * 0.9))
        Pg1 = max(0, min(150, 100 * Ag1 + sg1))
        Pg2 = max(0, min(375, 100 * Ag2 + sg2))
        Pg3 = max(0, min(500, 200 * Ag3 + sg3))
        Pso = max(0, (0.2 * data['irradiance'][start + t] + 0.05 * data['temperature'][start + t] - 9.25) * (1 + Av))

        if 3 <= data['wind_speed'][start + t] < 8:
            Pw = data['wind_speed'][start + t] ** 3 * 172.2625 / 1000
        elif 8 <= data['wind_speed'][start + t] < 12:
            Pw = 64 * 172.2625 / 125
        else:
            Pw = 0

        P = Pc + Pg1 + Pg2 + Pg3 + Pso + Pw

        if P >= data['load'][start + t]:
            Ee = P - data['load'][start + t]
            Es = 0
        else:
            Es = data['load'][start + t] - P
            Ee = 0

        Cb = 0.01 * battery_capacity + 0.1 * Pc
        Cg1 = 0.0034 * Pg1 ** 2 + 3 * Pg1 + 30
        Cg2 = 0.001 * Pg2 ** 2 + 10 * Pg2 + 40
        Cg3 = 0.001 * Pg3 ** 2 + 15 * Pg3 + 70
        Cs = 0.01 * Pso
        Cw = 0.01 * Pw
        Rs = 0.5 * data['price'][start + t] * Ee
        Cp = data['price'][start + t] * Es
        Pe = (Ee - 100) * 50 if Ee > 100 else 0
        Ps = (Es - 100) * 50 if Es > 100 else 0

        total_cost += (Cb + Cg1 + Cg2 + Cg3 + Cs + Cw + Pe + Ps - Rs + Cp) / 1000

        soc = Pc
        sg1 = Pg1
        sg2 = Pg2
        sg3 = Pg3

    return total_cost


# 约束条件
def constraint(x, period_batch, start, initial_states):
    constraints = []
    soc, sg1, sg2, sg3 = initial_states
    for t in range(period_batch):
        Ac, Ag1, Ag2, Ag3, Av = x[t * 5:(t + 1) * 5]
        Pc = max(0.2, min(0.8, soc + 0.2 * Ac * 0.9))
        Pg1 = max(10, min(150, 100 * Ag1 + sg1))
        Pg2 = max(50, min(375, 100 * Ag2 + sg2))
        Pg3 = max(100, min(500, 200 * Ag3 + sg3))
        Pso = max(0, (0.2 * data['irradiance'][start + t] + 0.05 * data['temperature'][start + t] - 9.25) * (1 + Av))

        if 3 <= data['wind_speed'][start + t] < 8:
            Pw = data['wind_speed'][start + t] ** 3 * 172.2625 / 1000
        elif 8 <= data['wind_speed'][start + t] < 12:
            Pw = 64 * 172.2625 / 125
        else:
            Pw = 0

        P = Pc + Pg1 + Pg2 + Pg3 + Pso + Pw

        # 保证变化后的值不小于最小值
        constraints.append(Pc - 0.2)
        constraints.append(Pg1 - 10)
        constraints.append(Pg2 - 50)
        constraints.append(Pg3 - 100)

        constraints.append(P - data['load'][start + t])
        soc = Pc
        sg1 = Pg1
        sg2 = Pg2
        sg3 = Pg3
    return constraints


actions = []
batch_size = 10  # 每次处理 10 个数据
total_batches = 10  # 总共处理 100 个数据
start = 0

for batch_num in range(total_batches):
    end = min(start + batch_size, period)
    period_batch = end - start

    # 初始化初始状态
    initial_states = (initial_soc, initial_sg1, initial_sg2, initial_sg3)

    # # 使用随机初始化更接近实际情况
    # x0 = np.random.uniform(0, 1, period_batch * 5)
    # bounds = [(-1, 1)] * (period_batch * 5)
    # cons = {'type': 'ineq', 'fun': lambda x: constraint(x, period_batch, start, initial_states)}
    # result = minimize(lambda x: objective(x, period_batch, start, initial_states), x0, method='SLSQP', bounds=bounds,
    #                   constraints=cons)
    #
    # actions.extend(result.x.reshape((period_batch, 5)).tolist())

    # 使用粒子群优化算法
    lb = [-1] * (period_batch * 5)
    ub = [1] * (period_batch * 5)
    xopt, fopt = pso(lambda x: objective(x, period_batch, start, initial_states), lb, ub,
                     ieqcons=[lambda x: constraint(x, period_batch, start, initial_states)], maxiter=100, swarmsize=50)

    actions.extend(xopt.reshape((period_batch, 5)).tolist())

    # 更新初始状态为当前批次最后一个状态
    last_action = actions[-1]
    initial_soc = max(0.2, min(0.8, initial_soc + 0.2 * last_action[0] * 0.9))
    initial_sg1 = max(10, min(150, 100 * last_action[1] + initial_sg1))
    initial_sg2 = max(50, min(375, 100 * last_action[2] + initial_sg2))
    initial_sg3 = max(100, min(500, 200 * last_action[3] + initial_sg3))

    start += batch_size

actions_json_path = './actions_batch_p.json'
try:
    with open(actions_json_path, 'w') as f:
        json.dump(actions, f)
    print(f"文件保存成功：{actions_json_path}")
except Exception as e:
    print(f"文件保存失败：{e}")
