Spaces:
Sleeping
Sleeping
| # 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 = "<table>\n" | |
| for column, column_name in zip((network, solar, bess), ("Network", "Solar directly", "Solar via BESS")): | |
| html += f"<tr><td>Yearly consumption served by {column_name}: </td><td>{column:0.2f} MWh</td></tr>\n" | |
| supplier = create_supplier(ui) | |
| fee = supplier.fee(results["consumption_from_network"]) | |
| html += f"<tr><td>Network energy usage charge:</td><td>{fee/1e6:.3f} million HUF</td></tr>\n" | |
| html += "</table>" | |
| return (html, fig_monthly, fig1, fig2) | |
| with gr.Blocks() as ui: | |
| with gr.Row(): | |
| # LEFT: Input controls | |
| with gr.Column(scale=1): # narrower column | |
| solar_cell_num = gr.Slider(0, 3000, 1140, label="Number of installed solar cells") | |
| solar_cell_nominal_capacity = gr.Slider(0, 1000, 280, label="Solar cell nominal capacity at NOCT [W]") | |
| bess_capacity_Ah = gr.Slider(0, 2000, 330, label="BESS nominal capacity [Ah]") | |
| fixed_consumption_checkbox = gr.Checkbox(value=False, label="Use fixed consumption") | |
| fixed_consumption_kW = gr.Slider(0, 100, 10, label="Amount of fixed consumption [kW]") | |
| with gr.Accordion("Extra BESS settings", open=False): | |
| bess_voltage_V = gr.Number(value=600, label="BESS voltage [V]") | |
| bess_charge_kW = gr.Number(value=50, label="BESS charge [kW]") | |
| bess_discharge_kW = gr.Number(value=60, label="BESS discharge [kW]") | |
| with gr.Accordion("Pricing settings", open=False): | |
| peak_price_HUFpkWh = gr.Number(value=60, label="Peak energy price [HUF/kWh]") | |
| base_price_HUFpkWh = gr.Number(value=60, label="Base energy price [HUF/kWh]") | |
| with gr.Accordion("Custom consumption/meteorology data", open=False): | |
| consumption_csv = gr.File(label="Upload consumption CSV", file_types=[".csv", ".gz", ".tsv"]) | |
| meteorology_csv = gr.File(label="Upload meteorology CSV", file_types=[".csv", ".gz", ".tsv"]) | |
| run_btn = gr.Button("Run Simulation") | |
| week_a_default = "2021-02-01" ; week_b_default = "2021-08-02" | |
| # week_b_default = datetime.date(2021, 2, 1) ; week_b_default = datetime.date(2021, 8, 2) | |
| # RIGHT: Output display | |
| with gr.Column(scale=2): # wider column | |
| html_out = gr.HTML() | |
| plot1 = gr.Plot(label="Monthly energy use") | |
| # date selector + Plot 2 | |
| week_a = gr.DateTime( | |
| value=week_a_default, include_time=False, label="Start date for Week A", type="string" | |
| ) | |
| plot2 = gr.Plot(label="Week A") | |
| # date selector + Plot 3 | |
| week_b = gr.DateTime( | |
| value=week_b_default, include_time=False, label="Start date for Week B", type="string" | |
| ) | |
| plot3 = gr.Plot(label="Week B") | |
| inputs = [ | |
| 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 | |
| ] | |
| run_btn.click( | |
| ui_refresh, | |
| inputs=inputs, | |
| # [solar_cell_num_slider, bess_slider, fixed_consumption_slider, base_price, peak_price], | |
| outputs=[html_out, plot1, plot2, plot3], | |
| ) | |
| ui.launch() | |