Files
2025-06-16 09:31:15 +02:00

261 lines
12 KiB
Python

import numpy as np
import pandas as pd
import plotly.graph_objects as go
from files.energy.input.DSM_optimizer.func.func import genetic_algorithm, stampa_result
###################################################################################################################################################
def ottimizzazione(immission_profile, consumption_profiles,num_intervals, day, create_plot = True, show_plot = True):
##### Trovare valori permessi immissione nei quali andare a inserire elettrodomestici:
# Trovare gli indici dei valori maggiori di zero
allowed_intervals = np.where(np.array(immission_profile) > 0)[0].tolist()
max_power_contract = 3
# Grid search parameters
n_devices = len(consumption_profiles)
# consumo totale:
#consumption_total = sum([sum(consumption_profile) for consumption_profile in consumption_profiles])
consumption_total = sum(map(np.sum, consumption_profiles))
# Define energy cost (e.g., cost per kWh)
# energy_cost_per_hour = [0.3]* num_intervals #- intervallo_funzionamento(35,60,96)*0.2 # Electricity price per kWh
energy_cost_per_hour = np.full(num_intervals, 0.3)
# Generation profile
# # Trova il valore massimo
# max_value = max(pv_profile)
# # Normalizza la lista
# normalized_profile = [x / max_value for x in pv_profile]
# # scalo in funzione della taglia:
# taglia_FV = max(2,1*(math.ceil(n_devices/4)))
# #taglia_FV = consumption_total/(sum(normalized_profile)*0.04*n_devices) # la taglia deve rendere il rapporto tra cosnumo singolo dispositivo e totale energia immessa = 0.6
# generation_profile = [x * taglia_FV for x in normalized_profile]
# Immission profile
# """ Questa parte è da modificare quando avremo la produzione fotovoltaica"""
# immission_profile = [
# max(0, generation_profile[i] - immission_profile[i])
# for i in range(num_intervals)
# ]
# Calcoliamo il rapporto tra il consumo e l'immissionee, per valutare percentuale possibili condivisione sul totale:
# immission_total = sum(immission_profile)
immission_total = np.sum(immission_profile)
perc_econd= min(consumption_total, immission_total)/immission_total # varia tra 0 e 1
perc_error = 0
perc_error_1 = 0
# Calcoliamo il rapporto tra il consumo e l'immissionee, per valutare percentuale possibili condivisione sul totale:
if perc_econd/n_devices < 0.04 and perc_econd < 0.65:
# Grid search parameters
population_size = min(50,max(10,n_devices*2))
generations = 20
mutation_rate = 0.05
elif perc_econd/n_devices < 0.06 and perc_econd < 0.55:
# Grid search parameters
population_size = min(50,n_devices*3)
generations = max(20,min(50,n_devices*2))
mutation_rate = 0.05
elif perc_econd/n_devices < 0.01 and perc_econd > 0.65:
# Grid search parameters
""""da mnodificare---->"""
population_size = 20
generations = 20
mutation_rate = 0.05
else:
# Grid search parameters
population_size = min(50,n_devices*3)
generations = max(20,min(50,n_devices*6))
mutation_rate = 0.05
# print(f"\nNUMBER DEVICE(S): {n_devices}")
#################### SOLUTIONS:####################
# Creazione del dizionario di input alla funzione.
params = {
"num_intervals": num_intervals,
"population_size": population_size,
"generations": generations,
"mutation_rate": mutation_rate,
"consumption_profiles": consumption_profiles,
"immission_profile": immission_profile,
"max_power_contract": max_power_contract,
"energy_cost_per_hour": energy_cost_per_hour,
"allowed_intervals": allowed_intervals
}
# vera e propria funzione di ottimizzazione:
best_solution = genetic_algorithm(**params)
param = [population_size, generations, mutation_rate]
# funzione per il plot
#################### PLOT:####################
# create the dataframe devices:
# Possiamo differenziarlo in funzione della tipologia di utenza e del nome del dispositivo: ad esempio user_n_single_washing_machine ecc..
# magari creo una funzione ad hoc per questo, vediamo dopo ?
##############
# Creazione delle colonne in modo compatto
u = 0
#columns = [f'user_{u}_{key}' for key, count in sched_dev.items() for _ in range(1, count + 1)]
columns = []
for count in range(int(n_devices/2)):
for key in ['washing_machine','dish_washer']:
columns.append(f'user_{u}_{key}')
u = u +1
# Creazione del DataFrame
df_plot = pd.DataFrame(data=np.transpose(best_solution[0]),
index=np.arange(num_intervals),
columns=columns)
# df_plot = pd.DataFrame(data=np.transpose(best_solution[0]),
# index=np.arange(num_intervals),
# columns=[f'user_{u=u+1}_{key}' for u in range(1, n_devices + 1) for key in sched_dev.keys()])
##############
# Crea il DataFrame immissione:
df = pd.DataFrame({
'immission_profile': immission_profile,
}, index=np.arange(num_intervals))
# Voglio calcolarmi l'energia totale condivisa. Con ritorno economico dato da incentivo totale:
# max(immissione[t], sum(prelievo utenze domestiche[t])*incentivo for
# Calcolare la somma degli elementi su ogni riga per il primo DataFrame
sum_df1_1 = df_plot.sum(axis=1)
# Sottrarre il valore corrispondente del secondo DataFrame
energy_shared_1 = np.minimum(sum_df1_1.values, df['immission_profile'].values)
# Creare un nuovo DataFrame con una colonna chiamata 'energy_shared'
#df_energy_shared_1 = pd.DataFrame({'energy_shared': energy_shared_1})
#print(f'Vector of energy sherred: {df_energy_shared}')
#total_energy_shared_1 = df_energy_shared_1['energy_shared'].sum()
total_energy_shared_1 = np.sum(energy_shared_1)
total_incentive_1 = total_energy_shared_1*0.11
total_energy_consumption_1 = np.sum(sum_df1_1)
total_energy_cost_1 = total_energy_consumption_1*0.3
#total_immission_energy_1 = df['immission_profile'].sum()
total_immission_energy_1 = np.sum(immission_profile)
perc_error_1 = total_energy_shared_1/min(total_immission_energy_1,total_energy_consumption_1)
if perc_error_1<=1:
e_cond_i = 0
e_cond_f = 0
e_cons_profile = np.zeros(96)
# Crea il DataFrame dispositivi in surplus:
df_user_over = pd.DataFrame({
},
index=np.arange(num_intervals))
# Ciclo
for column in df_plot.columns:
e_cons_profile += df_plot[column]
#e_cond_f = sum([min(immission_profile[t], e_cons_profile[t])for t in range(len(e_cons_profile))])
e_cond_f = np.sum(np.minimum(immission_profile, e_cons_profile))
if e_cond_f == e_cond_i:
df_user_over[column] = df_plot[column]
e_cons_profile -= df_plot[column]
#if e_cond_f < sum(e_cons_profile):
if e_cond_f < np.sum(e_cons_profile):
df_user_over[column] = df_plot[column]
e_cons_profile -= df_plot[column]
e_cond_f = e_cond_i
e_cond_i = e_cond_f
if not df_user_over.dropna().empty:
df_total_new =df_plot.drop(columns= df_user_over.columns)
df_total_new_sum = df_total_new.sum(axis=1)
# Trasformiamo per vettorializzare:
# Calcolo del nuovo profilo di immissione utilizzando Pandas
#immission_profile_series = pd.Series(immission_profile)
# Calcolo del nuovo profilo di immissione
#immission_profile_new = (immission_profile_series - df_total_new_sum).clip(lower=0).tolist()
immission_profile_new = np.clip(immission_profile - df_total_new_sum.values, 0, None)
##### Trovare valori permessi immissione nei quali andare a inserire elettrodomestici:
# Trovare valori permessi di immissione
allowed_intervals = np.where(np.array(immission_profile) > 0)[0].tolist()
# Trasposizione e filtraggio dei profili di consumo
consumption_profiles = [df_user_over.transpose().values[t][df_user_over.transpose().values[t] > 0] for t in range(len(df_user_over.columns))]
population_size = min(50,len(consumption_profiles)*20)
generations = min(50,len(consumption_profiles)*20)
params = {
"num_intervals": num_intervals,
"population_size": population_size,
"generations": generations,
"mutation_rate": mutation_rate,
"consumption_profiles": consumption_profiles,
"immission_profile": immission_profile_new,
"max_power_contract": max_power_contract,
"energy_cost_per_hour": energy_cost_per_hour,
"allowed_intervals": allowed_intervals
}
# second GA
best_solution_2 = genetic_algorithm(**params)
param = [population_size, generations, mutation_rate]
# create the dataframe devices:
df_user_opt_2 = pd.DataFrame(data=np.transpose(best_solution_2[0]),
index=np.arange(num_intervals),
columns= df_user_over.columns)
df_total_new = pd.concat([df_total_new, df_user_opt_2], axis=1)
sum_df1 = df_total_new.sum(axis=1)
# Sottrarre il valore corrispondente del secondo DataFrame
energy_shared = np.minimum(sum_df1.values, df['immission_profile'].values)
# Creare un nuovo DataFrame con una colonna chiamata 'energy_shared'
# df_energy_shared = pd.DataFrame({'energy_shared': energy_shared})
# total_energy_shared = df_energy_shared['energy_shared'].sum()
total_energy_shared = np.sum(energy_shared)
total_incentive = total_energy_shared*0.11
#total_energy_consumption = sum_df1.sum()
total_energy_consumption = np.sum(sum_df1)
total_energy_cost = total_energy_consumption*0.3
#total_immission_energy = df['immission_profile'].sum()
#total_immission_energy = total_immission_energy_1.copy()
perc_error = total_energy_shared/min(total_immission_energy_1,total_energy_consumption)
# teniamo solo quello con percentuale condivisione migliore, quindi:
if perc_error < perc_error_1:
#print("Return first")
if create_plot:
stampa_result(df_plot, immission_profile, num_intervals, day, show_plot)
#print_result(perc_econd,n_devices,total_energy_shared_1,total_incentive_1,total_energy_consumption_1,total_energy_cost_1,perc_error_1,*param)
#perc_condivisione_utilizzo = total_energy_shared_1/total_energy_consumption_1
return df_plot
else:
#print("Return second")
if create_plot:
stampa_result(df_total_new, immission_profile, num_intervals, day, show_plot)
#print_result(perc_econd,n_devices,total_energy_shared,total_incentive,total_energy_consumption,total_energy_cost,perc_error,*param)
#perc_condivisione_utilizzo = total_energy_shared/total_energy_consumption # type: ignore
return df_total_new