Skip to content

Release #8

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Nov 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 10 additions & 6 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,18 @@ jobs:
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.12.5' # Specify Python version (e.g., '3.9')
python-version: '3.11.9' # Specify Python version (e.g., '3.9')

# Install dependencies (you can specify requirements.txt or pyproject.toml)
# Install Poetry
- name: Install Poetry
run: |
curl -sSL https://install.python-poetry.org | python3 -
export PATH="$HOME/.local/bin:$PATH"

# Install dependencies using Poetry
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install pytest pandas numpy entsoe-py redis tensorflow scikit-learn sphinx
pip install .
poetry install

# Run pytest to execute tests
- name: Generate .config file inside the test folder
Expand All @@ -40,4 +44,4 @@ jobs:
echo "enable_energy_caching=false" >> .codegreencore.config
- name: Run tests
run: |
pytest
poetry run pytest
6 changes: 3 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,6 @@ tests/data1

# temp, will remove later
codegreen_core/models/files
codegreen_core/utilities/log.py

.vscode
Dockerfile
.vscode
poetry.lock
1 change: 1 addition & 0 deletions codegreen_core/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
from .utilities.config import Config

Config.load_config()
3 changes: 2 additions & 1 deletion codegreen_core/data/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
from .main import *
__all__ = ['energy']

__all__ = ["energy"]
347 changes: 227 additions & 120 deletions codegreen_core/data/entsoe.py

Large diffs are not rendered by default.

110 changes: 60 additions & 50 deletions codegreen_core/data/main.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import pandas as pd
from datetime import datetime

from ..utilities.message import Message,CodegreenDataError
from ..utilities import metadata as meta
from ..utilities.message import Message, CodegreenDataError
from ..utilities import metadata as meta
from . import entsoe as et

def energy(country,start_time,end_time,type="generation",interval60=True)-> pd.DataFrame:
"""

def energy(country, start_time, end_time, type="generation", interval60=True) -> dict:
"""
Returns hourly time series of energy production mix for a specified country and time range.

This method fetches the energy data for the specified country between the specified duration.
Expand All @@ -15,56 +16,65 @@ def energy(country,start_time,end_time,type="generation",interval60=True)-> pd.D

For example, if the source is ENTSOE, the data contains:

========================== ========== ================================================================
Column type Description
========================== ========== ================================================================
startTimeUTC datetime Start date in UTC (60 min interval)
Biomass float64
Fossil Hard coal float64
Geothermal float64
....more energy sources float64
**renewableTotal** float64 The total based on all renewable sources
renewableTotalWS float64 The total production using only Wind and Solar energy sources
nonRenewableTotal float64
total float64 Total using all energy sources
percentRenewable int64
percentRenewableWS int64 Percentage of energy produced using only wind and solar energy
Wind_per int64 Percentages of individual energy sources
Solar_per int64
Nuclear_per int64
Hydroelectricity_per int64
Geothermal_per int64
Natural Gas_per int64
Petroleum_per int64
Coal_per int64
Biomass_per int64
========================== ========== ================================================================
========================== ========== ================================================================
Column type Description
========================== ========== ================================================================
startTimeUTC datetime Start date in UTC (60 min interval)
Biomass float64
Fossil Hard coal float64
Geothermal float64
....more energy sources float64
**renewableTotal** float64 The total based on all renewable sources
renewableTotalWS float64 The total production using only Wind and Solar energy sources
nonRenewableTotal float64
total float64 Total using all energy sources
percentRenewable int64
percentRenewableWS int64 Percentage of energy produced using only wind and solar energy
Wind_per int64 Percentages of individual energy sources
Solar_per int64
Nuclear_per int64
Hydroelectricity_per int64
Geothermal_per int64
Natural Gas_per int64
Petroleum_per int64
Coal_per int64
Biomass_per int64
========================== ========== ================================================================

Note : fields marked bold are calculated based on the data fetched.

:param str country: The 2 alphabet country code.
:param datetime start_time: The start date for data retrieval. A Datetime object. Note that this date will be rounded to the nearest hour.
:param datetime end_time: The end date for data retrieval. A datetime object. This date is also rounded to the nearest hour.
:param str type: The type of data to retrieve; either 'historical' or 'forecasted'. Defaults to 'historical'.
:return: A DataFrame containing the hourly energy production mix.
:rtype: pd.DataFrame
:param str type: The type of data to retrieve; either 'generation' or 'forecast'. Defaults to 'generation'.
:return: A dictionary containing:
- `error`: A string with an error message, empty if no errors.
- `data_available`: A boolean indicating if data was successfully retrieved.
- `data`: A pandas DataFrame containing the energy data if available, empty DataFrame if not.
- `time_interval` : the time interval of the DataFrame
:rtype: dict
"""
if not isinstance(country, str):
raise ValueError("Invalid country")
if not isinstance(start_time,datetime):
raise ValueError("Invalid start date")
if not isinstance(end_time, datetime):
raise ValueError("Invalid end date")
if type not in ['generation', 'forecast']:
raise ValueError(Message.INVALID_ENERGY_TYPE)
# check start<end and both are not same

e_source = meta.get_country_energy_source(country)
if e_source=="ENTSOE" :
if type == "generation":
return et.get_actual_production_percentage(country,start_time,end_time,interval60)
elif type == "forecast":
return et.get_forecast_percent_renewable(country,start_time,end_time)
else:
raise CodegreenDataError(Message.NO_ENERGY_SOURCE)
return None
if not isinstance(country, str):
raise ValueError("Invalid country")
if not isinstance(start_time, datetime):
raise ValueError("Invalid start date")
if not isinstance(end_time, datetime):
raise ValueError("Invalid end date")
if type not in ["generation", "forecast"]:
raise ValueError(Message.INVALID_ENERGY_TYPE)
# check start<end and both are not same

if start_time > end_time:
raise ValueError("Invalid time.End time should be greater than start time")

e_source = meta.get_country_energy_source(country)
if e_source == "ENTSOE":
if type == "generation":
return et.get_actual_production_percentage(
country, start_time, end_time, interval60
)
elif type == "forecast":
return et.get_forecast_percent_renewable(country, start_time, end_time)
else:
raise CodegreenDataError(Message.NO_ENERGY_SOURCE)
return None
77 changes: 46 additions & 31 deletions codegreen_core/models/predict.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,50 +11,60 @@

# Path to the models directory
models_dir = Path(__file__).parent / "files"



def predicted_energy(country):
# do the forecast from now , same return format as data.energy
return {"data": None}


# Function to load a specific model by name
def load_prediction_model(country,version=None):
def _load_prediction_model(country, version=None):
"""Load a model by name"""
model_details = get_prediction_model_details(country,version)
model_details = get_prediction_model_details(country, version)
model_path = models_dir / model_details["name"]
print(model_path)
if not model_path.exists():
raise FileNotFoundError(f"Model does not exist.")

return load_model(model_path,compile=False)

return load_model(model_path, compile=False)

def run(country,input,model_version=None):

def _run(country, input, model_version=None):
"""Returns the prediction values"""

seq_length = len(input)
date = input[['startTimeUTC']].copy()
date = input[["startTimeUTC"]].copy()
# Convert 'startTimeUTC' column to datetime
date['startTimeUTC'] = pd.to_datetime(date['startTimeUTC'])
date["startTimeUTC"] = pd.to_datetime(date["startTimeUTC"])
# Get the last date value
last_date = date.iloc[-1]['startTimeUTC']
last_date = date.iloc[-1]["startTimeUTC"]
# Calculate the next hour
next_hour = last_date + timedelta(hours=1)
# Create a range of 48 hours starting from the next hour
next_48_hours = pd.date_range(next_hour, periods=48, freq='h')
next_48_hours = pd.date_range(next_hour, periods=48, freq="h")
# Create a DataFrame with the next 48 hours
next_48_hours_df = pd.DataFrame(
{'startTimeUTC': next_48_hours.strftime('%Y%m%d%H%M')})

model_details = get_prediction_model_details(country,model_version)

lstm = load_prediction_model(country,model_version) #load_model(model_path,compile=False)
{"startTimeUTC": next_48_hours.strftime("%Y%m%d%H%M")}
)

model_details = get_prediction_model_details(country, model_version)

lstm = load_prediction_model(
country, model_version
) # load_model(model_path,compile=False)

scaler = StandardScaler()
percent_renewable = input['percentRenewable']
percent_renewable = input["percentRenewable"]
forecast_values_total = []
prev_values_total = percent_renewable.values.flatten()
for _ in range(48):
scaled_prev_values_total = scaler.fit_transform(
prev_values_total.reshape(-1, 1))
x_pred_total = scaled_prev_values_total[-(
seq_length-1):].reshape(1, (seq_length-1), 1)
prev_values_total.reshape(-1, 1)
)
x_pred_total = scaled_prev_values_total[-(seq_length - 1) :].reshape(
1, (seq_length - 1), 1
)
# Make the prediction using the loaded model
predicted_value_total = lstm.predict(x_pred_total, verbose=0)
# Inverse transform the predicted value
Expand All @@ -64,24 +74,29 @@ def run(country,input,model_version=None):
prev_values_total = prev_values_total[1:]
# Create a DataFrame
forecast_df = pd.DataFrame(
{'startTimeUTC': next_48_hours_df['startTimeUTC'], 'percentRenewableForecast': forecast_values_total})
forecast_df["percentRenewableForecast"] = forecast_df["percentRenewableForecast"].round(
).astype(int)
forecast_df['percentRenewableForecast'] = forecast_df['percentRenewableForecast'].apply(
lambda x: 0 if x <= 0 else x)

{
"startTimeUTC": next_48_hours_df["startTimeUTC"],
"percentRenewableForecast": forecast_values_total,
}
)
forecast_df["percentRenewableForecast"] = (
forecast_df["percentRenewableForecast"].round().astype(int)
)
forecast_df["percentRenewableForecast"] = forecast_df[
"percentRenewableForecast"
].apply(lambda x: 0 if x <= 0 else x)

input_percentage = input["percentRenewable"].tolist()
input_start = input.iloc[0]["startTimeUTC"]
input_end = input.iloc[-1]["startTimeUTC"]
input_end = input.iloc[-1]["startTimeUTC"]

return {
"input": {
"country": country,
"model": model_details["name"],
"percentRenewable": input_percentage,
"start": input_start,
"end": input_end
"end": input_end,
},
"output": forecast_df
"output": forecast_df,
}

2 changes: 1 addition & 1 deletion codegreen_core/models/train.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
# the code for model training comes here # todo later
# the code for model training comes here # todo later
Loading
Loading