184 lines
7.2 KiB
Python
184 lines
7.2 KiB
Python
|
import json
|
||
|
import os
|
||
|
import time
|
||
|
import numpy as np
|
||
|
import pandas as pd
|
||
|
import torch
|
||
|
from concurrent.futures import ThreadPoolExecutor
|
||
|
from deap import base, creator, tools, algorithms
|
||
|
|
||
|
|
||
|
def fitness_torch(individuals, price, load, temperature, irradiance, wind_speed, prev_soc, prev_Pg1, prev_Pg2, prev_Pg3,
|
||
|
device):
|
||
|
individuals_torch = torch.tensor(individuals, device=device)
|
||
|
num = individuals_torch.shape[0]
|
||
|
Ac, Ag1, Ag2, Ag3, Av = [individuals_torch[:, i * period:(i + 1) * period] for i in range(5)]
|
||
|
# soc = torch.zeros((num, period), device=device)
|
||
|
# Pg1, Pg2, Pg3 = [torch.zeros((num, period), device=device) for _ in range(3)]
|
||
|
# Cb, Cg1, Cg2, Cg3, Cs, Cw, Rs, Cp, Pe, Ps, Ee, Es = [torch.zeros((num, period), device=device) for _ in range(12)]
|
||
|
|
||
|
soc = torch.clamp(prev_soc + 0.2 * Ac * 0.9, 0.2, 0.8)
|
||
|
Pg1 = torch.clamp(prev_Pg1 + 100 * Ag1, min=0, max=150)
|
||
|
Pg2 = torch.clamp(prev_Pg2 + 100 * Ag2, min=0, max=375)
|
||
|
Pg3 = torch.clamp(prev_Pg3 + 200 * Ag3, min=0, max=500)
|
||
|
Pso = torch.clamp((0.2 * irradiance + 0.05 * temperature - 9.25) * (1 + Av), min=0)
|
||
|
Pw = torch.where(
|
||
|
(wind_speed >= 3) & (wind_speed < 8),
|
||
|
wind_speed ** 3 * 172.2625 / 1000,
|
||
|
torch.where(
|
||
|
(wind_speed >= 8) & (wind_speed < 12),
|
||
|
64 * 172.2625 / 125,
|
||
|
torch.zeros_like(wind_speed)
|
||
|
)
|
||
|
)
|
||
|
P = Ac + Pg1 + Pg2 + Pg3 + Pso + Pw
|
||
|
|
||
|
Ee = torch.where(P >= load, P - load, torch.zeros_like(P))
|
||
|
Es = torch.where(P < load, load - P, torch.zeros_like(P))
|
||
|
|
||
|
Cb = 0.01 * Ac + 0.1 * soc
|
||
|
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 * price * Ee
|
||
|
Cp = price * Es
|
||
|
Pe = torch.where(Ee > 100, (Ee - 100) * 50, torch.zeros_like(Ee))
|
||
|
Ps = torch.where(Es > 100, (Es - 100) * 50, torch.zeros_like(Es))
|
||
|
|
||
|
total_cost = torch.sum(Cb + Cg1 + Cg2 + Cg3 + Cs + Cw + Pe + Ps - Rs + Cp, dim=1)
|
||
|
reward = -total_cost / 1000
|
||
|
|
||
|
return reward.cpu().numpy(), soc.cpu().numpy(), Pg1.cpu().numpy(), Pg2.cpu().numpy(), Pg3.cpu().numpy()
|
||
|
|
||
|
|
||
|
def save_decision_values(best_ind, period, index):
|
||
|
decisions = {
|
||
|
'Ac': best_ind[0],
|
||
|
'Ag1': best_ind[1],
|
||
|
'Ag2': best_ind[2],
|
||
|
'Ag3': best_ind[3],
|
||
|
'Av': best_ind[4]
|
||
|
}
|
||
|
with open(f'decision_values_{period}_index_{index}.json', 'w') as f:
|
||
|
json.dump(decisions, f)
|
||
|
|
||
|
|
||
|
def save_progress(population, period):
|
||
|
population_data = [ind.tolist() for ind in population]
|
||
|
with open(f'population_{period}.json', 'w') as f:
|
||
|
json.dump({'period': period, 'population': population_data}, f)
|
||
|
|
||
|
|
||
|
def load_progress():
|
||
|
if os.path.exists('population_gen_499.json'):
|
||
|
with open('population_gen_499.json', 'r') as f:
|
||
|
data = json.load(f)
|
||
|
return data['population'], data['period']
|
||
|
return None, 0
|
||
|
|
||
|
|
||
|
def check_bounds(func):
|
||
|
def wrapper(*args, **kwargs):
|
||
|
offspring = func(*args, **kwargs)
|
||
|
if offspring[0] is None or offspring[1] is None:
|
||
|
print("Error: One of the offspring is None", offspring)
|
||
|
raise ValueError("Offspring cannot be None.")
|
||
|
for child in offspring:
|
||
|
for i in range(len(child)):
|
||
|
if child[i] < -1:
|
||
|
child[i] = -1
|
||
|
elif child[i] > 1:
|
||
|
child[i] = 1
|
||
|
return offspring
|
||
|
return wrapper
|
||
|
|
||
|
|
||
|
def main():
|
||
|
period = 8760
|
||
|
NGEN = 500
|
||
|
CXPB, MUTPB = 0.7, 0.2
|
||
|
batch_size = 500
|
||
|
|
||
|
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
|
||
|
|
||
|
data = pd.read_csv('./data.csv')
|
||
|
price, load, temperature, irradiance, wind_speed = [data[col].values for col in
|
||
|
['price', 'load', 'temperature', 'irradiance', 'wind_speed']]
|
||
|
|
||
|
creator.create("FitnessMin", base.Fitness, weights=(-1.0,))
|
||
|
creator.create("Individual", list, fitness=creator.FitnessMin)
|
||
|
|
||
|
toolbox = base.Toolbox()
|
||
|
toolbox.register("attr_float", np.random.uniform, -1, 1)
|
||
|
toolbox.register("individual", tools.initRepeat, creator.Individual, toolbox.attr_float, 5)
|
||
|
toolbox.register("population", tools.initRepeat, list, toolbox.individual)
|
||
|
|
||
|
toolbox.register("mate", check_bounds(tools.cxBlend), alpha=0.5)
|
||
|
toolbox.register("mutate", check_bounds(tools.mutGaussian), mu=0, sigma=0.1, indpb=0.2)
|
||
|
toolbox.register("select", tools.selTournament, tournsize=3)
|
||
|
toolbox.register("evaluate", fitness_torch)
|
||
|
|
||
|
population = load_progress()
|
||
|
if population is None:
|
||
|
population = toolbox.population(n=NGEN)
|
||
|
print("Initial population:", len(population), "and first individual:", population[0])
|
||
|
|
||
|
prev_soc = torch.tensor([0.4] * NGEN, device=device)
|
||
|
prev_Pg1 = torch.zeros(NGEN, device=device)
|
||
|
prev_Pg2 = torch.zeros(NGEN, device=device)
|
||
|
prev_Pg3 = torch.zeros(NGEN, device=device)
|
||
|
|
||
|
for index in range(period):
|
||
|
for gen in range(NGEN):
|
||
|
start_time = time.time()
|
||
|
|
||
|
offspring = algorithms.varAnd(population, toolbox, cxpb=CXPB, mutpb=MUTPB)
|
||
|
num_individuals = len(offspring)
|
||
|
|
||
|
with ThreadPoolExecutor() as executor:
|
||
|
futures = []
|
||
|
for i in range(0, num_individuals, batch_size):
|
||
|
batch = offspring[i:i + batch_size]
|
||
|
individuals = [ind[:] for ind in batch]
|
||
|
futures.append(
|
||
|
executor.submit(toolbox.evaluate, individuals, price[index], load[index], temperature[index],
|
||
|
irradiance[index], wind_speed[index], prev_soc, prev_Pg1, prev_Pg2, prev_Pg3,
|
||
|
device)
|
||
|
)
|
||
|
|
||
|
for future in futures:
|
||
|
fitnesses, socs, Pg1s, Pg2s, Pg3s = zip(*future.result())
|
||
|
for ind, fitness in zip(offspring, fitnesses):
|
||
|
ind.fitness.values = (fitness,)
|
||
|
|
||
|
prev_soc[:len(socs)] = torch.tensor(socs, device=device)
|
||
|
prev_Pg1[:len(Pg1s)] = torch.tensor(Pg1s, device=device)
|
||
|
prev_Pg2[:len(Pg2s)] = torch.tensor(Pg2s, device=device)
|
||
|
prev_Pg3[:len(Pg3s)] = torch.tensor(Pg3s, device=device)
|
||
|
|
||
|
population = toolbox.select(offspring, k=len(population))
|
||
|
print("Population after selection:", population[:5])
|
||
|
end_time = time.time()
|
||
|
print(f"第 {index + 1}小时完成花费 {end_time - start_time:.2f} 秒")
|
||
|
|
||
|
best_ind = tools.selBest(population, 1)[0]
|
||
|
print('最佳个体:', best_ind)
|
||
|
print('适应度:', best_ind.fitness.values)
|
||
|
save_decision_values(best_ind, period, index)
|
||
|
save_progress(population, period)
|
||
|
|
||
|
prev_soc.fill_(0.4)
|
||
|
prev_Pg1.fill_(0)
|
||
|
prev_Pg2.fill_(0)
|
||
|
prev_Pg3.fill_(0)
|
||
|
prev_soc[:len(best_ind)] = torch.tensor(best_ind[:period], device=device)
|
||
|
prev_Pg1[:len(best_ind)] = torch.tensor(best_ind[period:2 * period], device=device)
|
||
|
prev_Pg2[:len(best_ind)] = torch.tensor(best_ind[2 * period:3 * period], device=device)
|
||
|
prev_Pg3[:len(best_ind)] = torch.tensor(best_ind[3 * period:4 * period], device=device)
|
||
|
|
||
|
|
||
|
if __name__ == "__main__":
|
||
|
main()
|