font setting for dashboard
This commit is contained in:
parent
7590aa6b58
commit
35dd46e799
34
.streamlit/config.toml
Normal file
34
.streamlit/config.toml
Normal file
@ -0,0 +1,34 @@
|
||||
[server]
|
||||
enableStaticServing = true
|
||||
|
||||
[[theme.fontFaces]]
|
||||
family = "Exo2"
|
||||
url = "app/static/EXO2-VARIABLEFONT_WGHT.TTF"
|
||||
style = "normal"
|
||||
weight = 400
|
||||
|
||||
|
||||
[[theme.fontFaces]]
|
||||
family = "Exo2"
|
||||
url = "app/static/EXO2-BOLD.TTF"
|
||||
style = "bold"
|
||||
weight = 700
|
||||
|
||||
[[theme.fontFaces]]
|
||||
family = "Exo2"
|
||||
url = "app/static/EXO2-ITALIC.TTF"
|
||||
style = "italic"
|
||||
weight = 400
|
||||
|
||||
[[theme.fontFaces]]
|
||||
family = "Exo2"
|
||||
url = "app/static/EXO2-BOLDITALIC.TTF"
|
||||
style = "bold italic"
|
||||
weight = 7
|
||||
|
||||
[theme]
|
||||
base="dark"
|
||||
primaryColor="#fcd913"
|
||||
font="Exo2"
|
||||
codeFont="Exo2"
|
||||
|
||||
33
dashboard.py
Normal file
33
dashboard.py
Normal file
@ -0,0 +1,33 @@
|
||||
# dashboard.py
|
||||
import streamlit as st
|
||||
import matplotlib.pyplot as plt
|
||||
from main import start_sim, stop_sim, reset_sim, bess_soc_since_start
|
||||
|
||||
# Header
|
||||
st.logo("https://rooftop.my/logo.svg", size="large")
|
||||
st.title("MEOS Control Dashboard")
|
||||
st.subheader("Mobile Energy Operations Simulation (MEOS)")
|
||||
st.text("Run MEOS Simulation and Monitor MBESS Status")
|
||||
|
||||
# some instructions
|
||||
|
||||
# --- SESSION STATE SETUP ---
|
||||
if "running" not in st.session_state:
|
||||
st.session_state.running = False
|
||||
if "plot_area" not in st.session_state:
|
||||
st.session_state.plot_area = st.empty()
|
||||
|
||||
# --- CONTROL BUTTONS ---
|
||||
col1, col2, col3 = st.columns(3)
|
||||
with col1:
|
||||
if st.button("Start", use_container_width=True):
|
||||
start_sim()
|
||||
st.session_state.running = True
|
||||
with col2:
|
||||
if st.button("Stop", use_container_width=True):
|
||||
stop_sim()
|
||||
st.session_state.running = False
|
||||
with col3:
|
||||
if st.button("Reset", use_container_width=True):
|
||||
reset_sim()
|
||||
st.session_state.running = False
|
||||
184
main.py
184
main.py
@ -13,6 +13,8 @@ import matplotlib.pyplot as pl
|
||||
import pandas as pd
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
|
||||
import threading ### <<< CONTROL ADDED >>>
|
||||
import time ### <<< CONTROL ADDED >>>
|
||||
|
||||
# read config file
|
||||
c = yaml.safe_load(open("YAMLs/config.yml"))
|
||||
@ -21,105 +23,125 @@ c = yaml.safe_load(open("YAMLs/config.yml"))
|
||||
bess_data = yaml.safe_load(open(c["paths"]["bess"]))
|
||||
|
||||
## simulation time setup
|
||||
# get current time
|
||||
c["sim_start_time"] = get_start_time()
|
||||
# get time step in minutes, then convert to seconds
|
||||
dt = c["sim_time"]["time_step_minutes"] * 60
|
||||
# compute end time based on duration in days
|
||||
duration = c["sim_time"]["duration_days"] * 24 * 60 * 60
|
||||
c["sim_end_time"] = c["sim_start_time"] + duration
|
||||
timestamps = np.arange(c["sim_start_time"], c["sim_end_time"] + 1, dt)
|
||||
|
||||
# batch process hours in seconds
|
||||
c["sim_time"]["batch_process_seconds"] = c["sim_time"]["batch_process_hours"] * 60 * 60
|
||||
|
||||
# load site info
|
||||
c["site_info"] = yaml.safe_load(open(c["paths"]["site_info"]))
|
||||
|
||||
### <<< CONTROL ADDED >>> Initialize simulation state globals
|
||||
sim_i = 0
|
||||
running = False
|
||||
is_running_in_async = False
|
||||
sim_lock = threading.Lock()
|
||||
|
||||
def generate_and_cache_profiles(c, dt):
|
||||
"""Generates load profiles for all sites and caches them."""
|
||||
return get_load_profiles(
|
||||
|
||||
# initialise BESS
|
||||
def _init_state():
|
||||
global bess_data, bess_soc_since_start, bess_soc_for_cycle, cumulative_load_profiles
|
||||
bd = initialise_SoC(bess_data.copy())
|
||||
bd = initial_site_assignment(c, bd)
|
||||
bess_data = bd
|
||||
|
||||
bess_soc_since_start = pd.DataFrame(
|
||||
columns=[unit["name"] for unit in bess_data["units"]]
|
||||
)
|
||||
init_df = pd.DataFrame(columns=["Timestamp", "SoC"])
|
||||
bess_soc_for_cycle = {unit["name"]: init_df for unit in bess_data["units"]}
|
||||
|
||||
cumulative_load_profiles = get_load_profiles(
|
||||
c, dt, c["sim_start_time"], c["sim_time"]["batch_process_seconds"]
|
||||
)
|
||||
|
||||
|
||||
# initialise BESS
|
||||
bess_data = initialise_SoC(bess_data)
|
||||
bess_data = initial_site_assignment(c, bess_data)
|
||||
# bess SoC dataframe
|
||||
bess_soc_since_start = pd.DataFrame(
|
||||
columns=[unit["name"] for unit in bess_data["units"]]
|
||||
)
|
||||
# bess SoC dictionary, meant to track SoC progress over each cycle.
|
||||
# resets after each charging cycle. This is for predicting swap times.
|
||||
init_df = pd.DataFrame(columns=["Timestamp", "SoC"])
|
||||
bess_soc_for_cycle = {unit["name"]: init_df for unit in bess_data["units"]}
|
||||
# do initial setup
|
||||
_init_state()
|
||||
|
||||
# get initial load profiles
|
||||
cumulative_load_profiles = get_load_profiles(
|
||||
c, dt, c["sim_start_time"], c["sim_time"]["batch_process_seconds"]
|
||||
)
|
||||
|
||||
# async function is running
|
||||
is_running_in_async = False
|
||||
def simulation_loop():
|
||||
"""Runs the loop, stepping through timestamps until stopped or finished."""
|
||||
global sim_i, running, is_running_in_async, cumulative_load_profiles, bess_data
|
||||
with ThreadPoolExecutor() as executor:
|
||||
while True:
|
||||
with sim_lock:
|
||||
if not running or sim_i >= len(timestamps):
|
||||
break
|
||||
|
||||
# loop through
|
||||
with ThreadPoolExecutor() as executor:
|
||||
for i in range(0, len(timestamps)):
|
||||
# start generating load profiles 200 seconds before data required
|
||||
if len(cumulative_load_profiles) <= len(timestamps):
|
||||
if is_running_in_async is False:
|
||||
# generate load profiles
|
||||
future = executor.submit(generate_and_cache_profiles, c, dt)
|
||||
is_running_in_async = True
|
||||
else:
|
||||
is_running_in_async = False
|
||||
i = sim_i
|
||||
sim_i += 1
|
||||
|
||||
# check if any BESS units are below threshold (buffer as defined in config)
|
||||
|
||||
# discharge BESS for each site
|
||||
for site in c["site_info"]["sites"]:
|
||||
site_name = site["name"]
|
||||
discharge_power = cumulative_load_profiles[site_name].iloc[i]
|
||||
bess_data = discharge_bess(bess_data, site_name, dt, discharge_power)
|
||||
temp_soc = [unit["SoC"] for unit in bess_data["units"]]
|
||||
|
||||
# append SoC to dataframe
|
||||
bess_soc_since_start = pd.concat(
|
||||
[
|
||||
bess_soc_since_start,
|
||||
pd.DataFrame(
|
||||
[temp_soc],
|
||||
columns=bess_soc_since_start.columns,
|
||||
index=[timestamps[i]],
|
||||
),
|
||||
],
|
||||
axis=0,
|
||||
)
|
||||
|
||||
# update cycle SoC
|
||||
# this is for predicting swap times
|
||||
bess_soc_for_cycle = update_cycle_SoC(bess_data, bess_soc_for_cycle, timestamps)
|
||||
|
||||
# predict swap times
|
||||
swap_times = predict_swap_time(bess_soc_for_cycle)
|
||||
|
||||
# add to cumulative load profiles
|
||||
# check if future exists and is done
|
||||
if is_running_in_async:
|
||||
if future.done():
|
||||
load_profiles = future.result()
|
||||
cumulative_load_profiles = pd.concat(
|
||||
[
|
||||
cumulative_load_profiles,
|
||||
load_profiles,
|
||||
],
|
||||
axis=0,
|
||||
)
|
||||
print(len(cumulative_load_profiles), "load profiles generated")
|
||||
# pre-fetch next batch if needed
|
||||
if len(cumulative_load_profiles) <= len(timestamps):
|
||||
if not is_running_in_async:
|
||||
future = executor.submit(
|
||||
get_load_profiles,
|
||||
c,
|
||||
dt,
|
||||
c["sim_start_time"],
|
||||
c["sim_time"]["batch_process_seconds"],
|
||||
)
|
||||
is_running_in_async = True
|
||||
else:
|
||||
is_running_in_async = False
|
||||
|
||||
pl.plot(cumulative_load_profiles)
|
||||
pl.show()
|
||||
pl.plot(bess_soc_since_start)
|
||||
# discharge BESS for each site
|
||||
for site in c["site_info"]["sites"]:
|
||||
name = site["name"]
|
||||
p = cumulative_load_profiles[name].iloc[i]
|
||||
bess_data = discharge_bess(bess_data, name, dt, p)
|
||||
|
||||
# record SoC
|
||||
temp_soc = [u["SoC"] for u in bess_data["units"]]
|
||||
bess_soc_since_start.loc[timestamps[i]] = temp_soc
|
||||
|
||||
# update cycle SoC and predict swaps
|
||||
bess_soc_for_cycle = update_cycle_SoC(
|
||||
bess_data, bess_soc_for_cycle, timestamps
|
||||
)
|
||||
swap_times = predict_swap_time(bess_soc_for_cycle)
|
||||
|
||||
# integrate newly fetched profiles
|
||||
if is_running_in_async and future.done():
|
||||
load_profiles = future.result()
|
||||
cumulative_load_profiles = pd.concat(
|
||||
[cumulative_load_profiles, load_profiles], axis=0
|
||||
)
|
||||
print(len(cumulative_load_profiles), "profiles generated")
|
||||
is_running_in_async = False
|
||||
|
||||
# small sleep to allow dashboard to refresh / release GIL
|
||||
time.sleep(0.01)
|
||||
|
||||
# once loop ends, you can plot or notify completion here
|
||||
pl.plot(cumulative_load_profiles)
|
||||
pl.show()
|
||||
pl.plot(bess_soc_since_start)
|
||||
pl.show()
|
||||
|
||||
|
||||
### <<< CONTROL ADDED >>> Control functions
|
||||
def start_sim():
|
||||
"""Starts the simulation in a background thread."""
|
||||
global running, sim_thread
|
||||
if not running:
|
||||
running = True
|
||||
sim_thread = threading.Thread(target=simulation_loop, daemon=True)
|
||||
sim_thread.start()
|
||||
|
||||
|
||||
def stop_sim():
|
||||
"""Stops the simulation loop."""
|
||||
global running
|
||||
running = False
|
||||
|
||||
|
||||
def reset_sim():
|
||||
"""Stops and re-initializes the simulation state."""
|
||||
global running, sim_i
|
||||
running = False
|
||||
sim_i = 0
|
||||
_init_state()
|
||||
|
||||
BIN
static/EXO2-BLACK.TTF
Normal file
BIN
static/EXO2-BLACK.TTF
Normal file
Binary file not shown.
BIN
static/EXO2-BLACKITALIC.TTF
Normal file
BIN
static/EXO2-BLACKITALIC.TTF
Normal file
Binary file not shown.
BIN
static/EXO2-BOLD.TTF
Normal file
BIN
static/EXO2-BOLD.TTF
Normal file
Binary file not shown.
BIN
static/EXO2-BOLDITALIC.TTF
Normal file
BIN
static/EXO2-BOLDITALIC.TTF
Normal file
Binary file not shown.
BIN
static/EXO2-EXTRABOLD.TTF
Normal file
BIN
static/EXO2-EXTRABOLD.TTF
Normal file
Binary file not shown.
BIN
static/EXO2-EXTRABOLDITALIC.TTF
Normal file
BIN
static/EXO2-EXTRABOLDITALIC.TTF
Normal file
Binary file not shown.
BIN
static/EXO2-EXTRALIGHT.TTF
Normal file
BIN
static/EXO2-EXTRALIGHT.TTF
Normal file
Binary file not shown.
BIN
static/EXO2-EXTRALIGHTITALIC.TTF
Normal file
BIN
static/EXO2-EXTRALIGHTITALIC.TTF
Normal file
Binary file not shown.
BIN
static/EXO2-LIGHT.TTF
Normal file
BIN
static/EXO2-LIGHT.TTF
Normal file
Binary file not shown.
BIN
static/EXO2-LIGHTITALIC.TTF
Normal file
BIN
static/EXO2-LIGHTITALIC.TTF
Normal file
Binary file not shown.
BIN
static/EXO2-MEDIUM.TTF
Normal file
BIN
static/EXO2-MEDIUM.TTF
Normal file
Binary file not shown.
BIN
static/EXO2-MEDIUMITALIC.TTF
Normal file
BIN
static/EXO2-MEDIUMITALIC.TTF
Normal file
Binary file not shown.
BIN
static/EXO2-SEMIBOLD.TTF
Normal file
BIN
static/EXO2-SEMIBOLD.TTF
Normal file
Binary file not shown.
BIN
static/EXO2-SEMIBOLDITALIC.TTF
Normal file
BIN
static/EXO2-SEMIBOLDITALIC.TTF
Normal file
Binary file not shown.
BIN
static/EXO2-THIN.TTF
Normal file
BIN
static/EXO2-THIN.TTF
Normal file
Binary file not shown.
BIN
static/EXO2-THINITALIC.TTF
Normal file
BIN
static/EXO2-THINITALIC.TTF
Normal file
Binary file not shown.
BIN
static/EXO2-VARIABLEFONT_WGHT.TTF
Normal file
BIN
static/EXO2-VARIABLEFONT_WGHT.TTF
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user