pq / v2 /app.py
Daniel Varga
left-right pane
07d9d06
# 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 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 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"
met_2021_data, cons_2021_data = read_datasets()
# TODO move out everything that should not be recalculated.
# TODO actually use uiParameters. (base_price and peak_price were just to mock up the Accordion gui.)
# TODO ui_refresh spawns its own Supplier, which is just dumb.
def recalculate(**uiParameters):
fixed_consumption = uiParameters['fixed_consumption']
del uiParameters['fixed_consumption']
parameters = SolarParameters()
for k, v in uiParameters.items():
setattr(parameters, k, v)
np.random.seed(1)
supplier = Supplier(price=100) # Ft/kWh
# nine-to-five increased price.
supplier.set_price_for_daily_interval(9, 17, 150)
# midnight-to-three decreased price, to test network charge.
supplier.set_price_for_daily_interval(0, 3, 20)
# peak_demand dimension is kWh, but it's interpreted as the full consumption
# during a 15 minute timestep.
supplier.set_demand_charge(peak_demand=2.5, surcharge_per_kwh=500) # kWh in a 15 minutes interval, Ft/kWh
solar_parameters = SolarParameters()
add_production_field(met_2021_data, solar_parameters)
all_data = interpolate_and_join(met_2021_data, cons_2021_data)
time_interval_min = all_data.index.freq.n
time_interval_h = time_interval_min / 60
# 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 fixed_consumption:
all_data['Consumption'] = 10
print("Working with", solar_parameters.solar_cell_num, "solar cells, that's a maximum production of", all_data['Production'].max(), "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
all_data_with_predictions['Consumption_fees'] = precalculated_supplier.consumption_fees # [HUF / kWh]
battery_model = BatteryModel(capacity_Ah=600, time_interval_h=time_interval_h)
# param_1 is prob of choosing PASSIVE
# param_2 is prob of choosing NETWORK_CHARGE
decider = RandomDecider(np.array([0.0, 0.0]), precalculated_supplier)
results, total_network_fee = simulator(battery_model, all_data_with_predictions, decider)
print(f"{total_network_fee=}")
return results
def ui_refresh(solar_cell_num, bess_nominal_capacity, fixed_consumption, base_price, peak_price):
results = recalculate(solar_cell_num=solar_cell_num, bess_nominal_capacity=bess_nominal_capacity, fixed_consumption=fixed_consumption)
fig1 = plotly_visualize_simulation(results, date_range=("2021-02-01", "2021-02-07"))
fig2 = plotly_visualize_simulation(results, date_range=("2021-08-02", "2021-08-08"))
# (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}:&nbsp;&nbsp;&nbsp;</td><td>{column:0.2f} MWh</td></tr>\n"
supplier = Supplier(price=70) # HUF/kWh
supplier.set_price_for_daily_interval_on_workdays(start=6, end=22, price=100)
# not realistic, just for testing the effect
# supplier.set_demand_charge(peak_demand=100, surcharge_per_kw=1000)
fee = supplier.fee(results["consumption_from_network"])
html += f"<tr><td>{fee/1e6:.3f} million HUF billed by energy supplier</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_slider = gr.Slider(0, 2000, 114, label="Solar cell number")
bess_slider = gr.Slider(0, 2000, 330, label="BESS nominal capacity in [Ah]")
fixed_consumption = gr.Checkbox(value=False, label="Use fixed consumption (10 kW)")
with gr.Accordion("Advanced Pricing Settings", open=False):
base_price = gr.Number(value=0.1, label="Base energy price [€/kWh]")
peak_price = gr.Number(value=0.3, label="Peak energy price [€/kWh]")
run_btn = gr.Button("Run Simulation")
# RIGHT: Output display
with gr.Column(scale=2): # wider column
html_out = gr.HTML()
plot1 = gr.Plot()
plot2 = gr.Plot()
plot3 = gr.Plot()
run_btn.click(
ui_refresh,
inputs=[solar_slider, bess_slider, fixed_consumption, base_price, peak_price],
outputs=[html_out, plot1, plot2, plot3],
)
ui.launch()