# port of # https://colab.research.google.com/drive/1PJgcJ4ly7x5GuZy344eJeYSODo8trbM4#scrollTo=39F2u-4hvwLU import numpy as np import pandas as pd import gradio as gr from types import SimpleNamespace import datetime # from simulation import * from data_processing import * from visualization import * from supplier import Supplier, precalculate_supplier from architecture import simulator, add_dummy_predictions from decider import Decider, RandomDecider from bess import BatteryParameters, BatteryModel #@title ### Downloading the data # !wget "https://static.renyi.hu/ai-shared/daniel/pq/PL_44527.19-21.csv.gz" # !wget "https://static.renyi.hu/ai-shared/daniel/pq/pq_terheles_2021_adatok.tsv" OLD_DATASET = False MINI = False if MINI: met_default_filename = 'PL_44527.2101.csv.gz' cons_default_filename = 'pq_terheles_202101_adatok.tsv' else: met_default_filename = 'PL_44527.19-21.csv.gz' cons_default_filename = 'pq_terheles_2021_adatok.tsv' met_2021_data, cons_2021_data = read_datasets(met_default_filename, cons_default_filename, old_dataset=OLD_DATASET) # TODO some gui to upload consumption data. # and maybe solar data? but we don't have a solar data -> production model built in. just scale and switch years from a dropdown? def recalculate(ui): np.random.seed(1) supplier = create_supplier(ui) solar_parameters = SolarParameters(solar_cell_num=ui.solar_cell_num, panel_power_at_NOCT=ui.solar_cell_nominal_capacity) met_data = met_2021_data cons_data = cons_2021_data changed_datasource = False if ui.meteorology_csv is not None: met_filename = ui.meteorology_csv.name changed_datasource = True else: met_filename = met_default_filename if ui.consumption_csv is not None: print("Hm, we should do something with this CSV.", ui.consumption_csv.name) cons_filename = ui.consumption_csv.name changed_datasource = True else: cons_filename = cons_default_filename if changed_datasource: met_data, cons_data = read_datasets(met_filename, cons_filename, old_dataset=OLD_DATASET) else: met_data, cons_data = met_2021_data, cons_2021_data add_production_field(met_data, solar_parameters) if OLD_DATASET: # i've obsoleted this, but it's not a 100% replacement, # it treats daylight savings changes differently. # new version drops repeated hour and interpolates skipped hour. all_data = interpolate_and_join(met_data, cons_data) else: all_data = join_consumption_meteorology( met_data, cons_data, target_freq="5min", ) time_interval_min = all_data.index.freq.n time_interval_h = time_interval_min / 60 battery_parameters = BatteryParameters( capacity_Ah = ui.bess_capacity_Ah, voltage_V = ui.bess_voltage_V, charge_kW = ui.bess_charge_kW, discharge_kW = ui.bess_discharge_kW ) battery_model = BatteryModel(battery_parameters, time_interval_h=time_interval_h) # for faster testing: DATASET_TRUNCATED_SIZE = None if DATASET_TRUNCATED_SIZE is not None: print("Truncating dataset to", DATASET_TRUNCATED_SIZE, "datapoints, that is", DATASET_TRUNCATED_SIZE * time_interval_h / 24, "days") all_data = all_data.iloc[:DATASET_TRUNCATED_SIZE] if ui.fixed_consumption_kW is not None: all_data['Consumption'] = ui.fixed_consumption_kW all_data_with_predictions = all_data.copy() add_dummy_predictions(all_data_with_predictions) precalculated_supplier = precalculate_supplier(supplier, all_data.index) # we delete the supplier to avoid accidentally calling it instead of precalculated_supplier supplier = None # param_1 is prob of choosing PASSIVE # param_2 is prob of choosing NETWORK_CHARGE # so this corresponds to constant DISCHARGE mode, where the priorities are: # 1. try solar 2. try bess 3. try network decider = RandomDecider(np.array([0.0, 0.0]), precalculated_supplier) all_data_with_predictions['Consumption_fees'] = precalculated_supplier.consumption_fees # [HUF / kWh] results, total_network_fee = simulator(battery_model, all_data_with_predictions, decider) print(f"{total_network_fee=}") return results # that's very error-prone, sorry. must be kept in sync with the gradio button click call, # the caller ui_refresh and recalculate(). def list_to_namespace( solar_cell_num, solar_cell_nominal_capacity, bess_capacity_Ah, bess_voltage_V, bess_charge_kW, bess_discharge_kW, fixed_consumption_kW, base_price_HUFpkWh, peak_price_HUFpkWh, consumption_csv, meteorology_csv ): return SimpleNamespace( solar_cell_num=solar_cell_num, solar_cell_nominal_capacity=solar_cell_nominal_capacity, bess_capacity_Ah=bess_capacity_Ah, bess_voltage_V=bess_voltage_V, bess_charge_kW=bess_charge_kW, bess_discharge_kW=bess_discharge_kW, # not passed to recalculate(ui): # fixed_consumption_checkbox=fixed_consumption_checkbox, fixed_consumption_kW=fixed_consumption_kW, base_price_HUFpkWh=base_price_HUFpkWh, peak_price_HUFpkWh=peak_price_HUFpkWh, # not passed to recalculate(ui): # week_a=week_a, week_b=week_b, consumption_csv=consumption_csv, meteorology_csv=meteorology_csv ) def create_supplier(ui): supplier = Supplier(price=ui.base_price_HUFpkWh) supplier.set_price_for_daily_interval_on_workdays(start=6, end=18, price=ui.peak_price_HUFpkWh) return supplier def ui_refresh( solar_cell_num, solar_cell_nominal_capacity, bess_capacity_Ah, bess_voltage_V, bess_charge_kW, bess_discharge_kW, fixed_consumption_checkbox, fixed_consumption_kW, base_price_HUFpkWh, peak_price_HUFpkWh, week_a, week_b, consumption_csv, meteorology_csv): if not fixed_consumption_checkbox: fixed_consumption_kW = None # None means use dataframe. ui = list_to_namespace( solar_cell_num, solar_cell_nominal_capacity, bess_capacity_Ah, bess_voltage_V, bess_charge_kW, bess_discharge_kW, fixed_consumption_kW, base_price_HUFpkWh, peak_price_HUFpkWh, consumption_csv, meteorology_csv ) results = recalculate(ui) # TODO this is a bit too vibey start_a = (week_a if isinstance(week_a, datetime.datetime) else datetime.datetime.fromisoformat(week_a)) end_a = start_a + datetime.timedelta(days=6) start_b = (week_b if isinstance(week_b, datetime.datetime) else datetime.datetime.fromisoformat(week_b)) end_b = start_b + datetime.timedelta(days=6) date_range_a = (start_a.strftime("%Y-%m-%d"), end_a.strftime("%Y-%m-%d")) date_range_b = (start_b.strftime("%Y-%m-%d"), end_b.strftime("%Y-%m-%d")) fig1 = plotly_visualize_simulation(results, date_range=date_range_a) fig2 = plotly_visualize_simulation(results, date_range=date_range_b) # (12, 3), the 3 indexed with (network, solar, bess): consumptions_in_mwh = monthly_analysis(results) fig_monthly = plotly_visualize_monthly(consumptions_in_mwh) network, solar, bess = consumptions_in_mwh.sum(axis=0) html = "
| Yearly consumption served by {column_name}: | {column:0.2f} MWh |
| Network energy usage charge: | {fee/1e6:.3f} million HUF |