Skip to content

Commit

Permalink
Change Zoneinfo to pytz module
Browse files Browse the repository at this point in the history
  • Loading branch information
MAYANK12SHARMA committed Jan 22, 2025
1 parent 9baf32c commit 009009a
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 37 deletions.
89 changes: 60 additions & 29 deletions src/pvsite_forecast.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@

import plotly.graph_objects as go
import pytz
from zoneinfo import ZoneInfo

# Penalty Calculator
def calculate_penalty(df, region, asset_type, capacity_kw):
Expand All @@ -25,16 +24,24 @@ def calculate_penalty(df, region, asset_type, capacity_kw):
# Define penalty bands for combinations of region and asset type
penalty_bands = {
("Rajasthan", "solar"): [
(10, 15, 0.1), # Band (lowest bound of the band range, highest bound of the band range, penalty that particular band carries)
(15, None, 1.0), # Band (lowest bound of the band range, no highest bound of the band range, penalty that particular band carries)
(
10,
15,
0.1,
), # Band (lowest bound of the band range, highest bound of the band range, penalty that particular band carries)
(
15,
None,
1.0,
), # Band (lowest bound of the band range, no highest bound of the band range, penalty that particular band carries)
],
("Madhya Pradesh", "wind"): [
(10, 20, 0.25),
(10, 20, 0.25),
(20, 30, 0.5),
(30, None, 0.75),
],
("Gujarat", "solar"): [
(7, 15, 0.25),
(7, 15, 0.25),
(15, 23, 0.5),
(23, None, 0.75),
],
Expand Down Expand Up @@ -71,7 +78,7 @@ def calculate_penalty(df, region, asset_type, capacity_kw):
for lower, upper, rate in bands:
mask = (deviation_percentage >= lower) if lower is not None else True
if upper is not None:
mask &= (deviation_percentage < upper)
mask &= deviation_percentage < upper
penalty[mask] += abs(deviation[mask]) * rate

# Calculate total penalty
Expand All @@ -80,7 +87,6 @@ def calculate_penalty(df, region, asset_type, capacity_kw):
return penalty, total_penalty



# Internal Dashboard
def pvsite_forecast_page():
"""Main page for pvsite forecast"""
Expand All @@ -97,7 +103,9 @@ def pvsite_forecast_page():
site_uuids = [sites.site_uuid for sites in sites if sites.site_uuid is not None]

# streamlit toggle between site_uuid and client_site_name
query_method = st.sidebar.radio("Select site by", ("site_uuid", "client_site_name"))
query_method = st.sidebar.radio(
"Select site by", ("site_uuid", "client_site_name")
)

if query_method == "site_uuid":
site_selection_uuid = st.sidebar.selectbox(
Expand All @@ -111,15 +119,21 @@ def pvsite_forecast_page():
sorted([sites.client_site_name for sites in sites]),
)
site_selection_uuid = [
sites.site_uuid for sites in sites if sites.client_site_name == client_site_name
sites.site_uuid
for sites in sites
if sites.client_site_name == client_site_name
][0]

timezone_selected = st.sidebar.selectbox("Select timezone", ["UTC", "Asia/Calcutta"])
timezone_selected = ZoneInfo(timezone_selected)
timezone_selected = st.sidebar.selectbox(
"Select timezone", ["UTC", "Asia/Calcutta"]
)
timezone_selected = pytz.timezone(timezone_selected)

day_after_tomorrow = datetime.today() + timedelta(days=3)
starttime = st.sidebar.date_input(
"Start Date", min_value=datetime.today() - timedelta(days=365), max_value=datetime.today()
"Start Date",
min_value=datetime.today() - timedelta(days=365),
max_value=datetime.today(),
)
endtime = st.sidebar.date_input("End Date", day_after_tomorrow)

Expand All @@ -139,7 +153,6 @@ def pvsite_forecast_page():
asset_type = site.asset_type # Assume site object has an 'asset_type' attribute
capacity_kw = site.capacity_kw # Extract capacity dynamically


if forecast_type == "Latest":
created = pd.Timestamp.utcnow().ceil("15min")
created = created.astimezone(timezone.utc)
Expand All @@ -158,7 +171,9 @@ def pvsite_forecast_page():
created = None

if forecast_type == "Forecast_horizon":
forecast_horizon = st.sidebar.selectbox("Select Forecast Horizon", range(0, 2880, 15), 6)
forecast_horizon = st.sidebar.selectbox(
"Select Forecast Horizon", range(0, 2880, 15), 6
)
else:
forecast_horizon = None

Expand Down Expand Up @@ -206,16 +221,18 @@ def pvsite_forecast_page():
endtime = datetime.combine(endtime, time.min)

# change to the correct timezone
starttime = starttime.replace(tzinfo=timezone_selected)
endtime = endtime.replace(tzinfo=timezone_selected)
# starttime = starttime.replace(tzinfo=timezone_selected)
# endtime = endtime.replace(tzinfo=timezone_selected)
starttime = timezone_selected.localize(starttime)
endtime = timezone_selected.localize(endtime)

# change to utc
starttime = starttime.astimezone(ZoneInfo("UTC"))
endtime = endtime.astimezone(ZoneInfo("UTC"))
starttime = starttime.astimezone(pytz.utc)
endtime = endtime.astimezone(pytz.utc)

if created is not None:
created = created.replace(tzinfo=timezone_selected) # Add timezone information to created
created = created.astimezone(ZoneInfo("UTC"))
created = timezone_selected.localize(created)
created = created.astimezone(pytz.utc)

# great ml model names for this site

Expand All @@ -231,8 +248,10 @@ def pvsite_forecast_page():
)

if len(ml_models) == 0:

class Models:
name = None

ml_models = [Models()]

ys = {}
Expand All @@ -257,7 +276,7 @@ class Models:
y = [i.forecast_power_kw for i in forecast]

# convert to timezone
x = [i.replace(tzinfo=ZoneInfo("UTC")) for i in x]
x = [i.replace(tzinfo=pytz.utc) for i in x]
x = [i.astimezone(timezone_selected) for i in x]

ys[model.name] = y
Expand All @@ -273,12 +292,16 @@ class Models:
)

yy = [
generation.generation_power_kw for generation in generations if generation is not None
generation.generation_power_kw
for generation in generations
if generation is not None
]
xx = [
generation.start_utc for generation in generations if generation is not None
]
xx = [generation.start_utc for generation in generations if generation is not None]

# convert to timezone
xx = [i.replace(tzinfo=ZoneInfo("UTC")) for i in xx]
xx = [i.replace(tzinfo=pytz.utc) for i in xx]
xx = [i.astimezone(timezone_selected) for i in xx]

df_forecast = []
Expand All @@ -304,7 +327,9 @@ class Models:
df_generation = df_generation.resample(resample).mean()

# merge together
df_all = df_forecast.merge(df_generation, left_index=True, right_index=True, how="outer")
df_all = df_forecast.merge(
df_generation, left_index=True, right_index=True, how="outer"
)

# select variables
xx = df_all.index
Expand All @@ -313,7 +338,9 @@ class Models:
fig = go.Figure(
layout=go.Layout(
title=go.layout.Title(text="Latest Forecast for Selected Site"),
xaxis=go.layout.XAxis(title=go.layout.xaxis.Title(text=f"Time [{timezone_selected}]")),
xaxis=go.layout.XAxis(
title=go.layout.xaxis.Title(text=f"Time [{timezone_selected}]")
),
yaxis=go.layout.YAxis(title=go.layout.yaxis.Title(text="KW")),
legend=go.layout.Legend(title=go.layout.legend.Title(text="Chart Legend")),
)
Expand Down Expand Up @@ -366,7 +393,9 @@ def convert_df(df: pd.DataFrame):

# MAE and NMAE Calculator
mae_kw = (df["generation_power_kw"] - df[forecast_column]).abs().mean()
mae_mw = (df["generation_power_kw"] - df[forecast_column]).abs().mean() / 1000
mae_mw = (
df["generation_power_kw"] - df[forecast_column]
).abs().mean() / 1000
me_kw = (df["generation_power_kw"] - df[forecast_column]).mean()
mean_generation = df["generation_power_kw"].mean()
nmae = mae_kw / mean_generation * 100
Expand All @@ -389,10 +418,12 @@ def convert_df(df: pd.DataFrame):
"capacity": capacity,
"pearson_corr": pearson_corr,
}

if country == "india":
df["forecast_power_kw"] = df[forecast_column]
penalties, total_penalty = calculate_penalty(df, str(region), str(asset_type), capacity_kw)
penalties, total_penalty = calculate_penalty(
df, str(region), str(asset_type), capacity_kw
)
one_metric_data["total_penalty [INR]"] = total_penalty

metrics.append(one_metric_data)
Expand Down
16 changes: 8 additions & 8 deletions src/utils.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import streamlit as st
import json
import json
import requests
from datetime import datetime
from zoneinfo import ZoneInfo # Replacing pytz with zoneinfo
import pytz


def load_css(css_file):
"""Load CSS from a file."""
Expand All @@ -13,7 +14,6 @@ def load_css(css_file):
st.error(f"CSS file not found: {css_file}")



def parse_timestamp(status):
"""Parse the timestamp from the status object and return local time"""
timestamp = str(status.created_utc)
Expand All @@ -22,17 +22,17 @@ def parse_timestamp(status):
parsed_time = datetime.fromisoformat(timestamp)
except ValueError as e:
raise ValueError(f"Invalid timestamp format: {e}")

if parsed_time.tzinfo is not None:
utc_time = parsed_time.astimezone(ZoneInfo("UTC"))
utc_time = parsed_time.astimezone(pytz.utc)
else:
# If no timezone is specified, assume it's UTC
utc_time = parsed_time.replace(tzinfo=ZoneInfo("UTC"))
utc_time = parsed_time.replace(tzinfo=pytz.utc)

# Convert to specific timezone (Asia/Kolkata)
local_timezone = ZoneInfo("Asia/Kolkata")
local_timezone = pytz.timezone("Asia/Kolkata")
local_time = parsed_time.astimezone(local_timezone)

return local_time


Expand Down

0 comments on commit 009009a

Please sign in to comment.