From 6929d811bb807ed327a821287681a841c77b1470 Mon Sep 17 00:00:00 2001 From: shubh Date: Sun, 2 Mar 2025 13:34:44 +0100 Subject: [PATCH 1/3] new info method, fixed docs --- codegreen_core/data/__init__.py | 2 +- codegreen_core/data/main.py | 144 ++++++++++++++++++++------------ 2 files changed, 90 insertions(+), 56 deletions(-) diff --git a/codegreen_core/data/__init__.py b/codegreen_core/data/__init__.py index 8dc6ff4..23d14ff 100644 --- a/codegreen_core/data/__init__.py +++ b/codegreen_core/data/__init__.py @@ -1,3 +1,3 @@ from .main import * -__all__ = ["energy"] +__all__ = ["energy","info"] diff --git a/codegreen_core/data/main.py b/codegreen_core/data/main.py index edd5d64..611d380 100644 --- a/codegreen_core/data/main.py +++ b/codegreen_core/data/main.py @@ -10,54 +10,75 @@ def energy(country, start_time, end_time, type="generation") -> 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. - It checks if a valid energy data source is available. If not, None is returned. Otherwise, the - energy data is returned as a pandas DataFrame. The structure of data depends on the energy source. - - For example, if the source is ENTSOE, the data contains: - - ========================== ========== ================================================================ - Column type Description - ========================== ========== ================================================================ - startTimeUTC object Start date in UTC (format YYYYMMDDhhmm) - startTime datetime Start time in local timezone - 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 'generation' or 'forecast'. Defaults to 'generation'. - :param boolean interval60: To fix the time interval of data to 60 minutes. True by default. Only applicable for generation data - - :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 + Returns an hourly time series of the energy production mix for a specified country and time range, + if a valid energy data source is available. + + The data is returned as a pandas DataFrame along with additional metadata. + The columns vary depending on the data source. For example, if the source is ENTSOE, + the data includes fields such as "Biomass", "Geothermal", "Hydro Pumped Storage", + "Hydro Run-of-river and Poundage", "Hydro Water Reservoir", etc. + + However, some fields remain consistent across data sources: + + ========================= ========== ================================================================ + Column Type Description + ========================= ========== ================================================================ + startTimeUTC object Start time in UTC (format: YYYYMMDDhhmm) + startTime datetime Start time in local timezone + renewableTotal float64 The total production from all renewable sources + renewableTotalWS float64 Total production using only Wind and Solar energy sources + nonRenewableTotal float64 Total production from non-renewable sources + total float64 Total energy production from all sources + percentRenewable int64 Percentage of total energy from renewable sources + percentRenewableWS int64 Percentage of energy from Wind and Solar only + Wind_per int64 Percentage contribution from Wind energy + Solar_per int64 Percentage contribution from Solar energy + Nuclear_per int64 Percentage contribution from Nuclear energy + Hydroelectricity_per int64 Percentage contribution from Hydroelectricity + Geothermal_per int64 Percentage contribution from Geothermal energy + Natural Gas_per int64 Percentage contribution from Natural Gas + Petroleum_per int64 Percentage contribution from Petroleum + Coal_per int64 Percentage contribution from Coal + Biomass_per int64 Percentage contribution from Biomass + ========================= ========== ================================================================ + + :param str country: + The 2-letter country code (e.g., "DE" for Germany, "FR" for France, etc.). + :param datetime start_time: + The start date for data retrieval (rounded to the nearest hour). + :param datetime end_time: + The end date for data retrieval (rounded to the nearest hour). + :param str type: + The type of data to retrieve; either 'generation' or 'forecast'. Defaults to 'generation'. + + :return: A dictionary containing the following keys: + + - **error** (*str*): An error message, empty if no errors occurred. + - **data_available** (*bool*): Indicates whether data was successfully retrieved. + - **data** (*pandas.DataFrame*): The retrieved energy data if available; an empty DataFrame otherwise. + - **time_interval** (*int*): The time interval of the DataFrame (constant value: ``60``). + - **source** (*str*): Specifies the origin of the retrieved data. Defaults to ``'public_data'``, indicating it was fetched from an external source. If the offline storage feature is enabled, this value may change if the data is available locally. + :rtype: dict + + **Example Usage:** + + Get generation data for Germany + + .. code-block:: python + + from datetime import datetime + from codegreen_core.data import energy + result = energy(country="DE", start_time=datetime(2025, 1, 1), end_time=datetime(2025, 1, 2), type="generation") + + Get forecast data for Norway + + .. code-block:: python + + from datetime import datetime + from codegreen_core.data import energy + result = energy(country="NO", start_time=datetime(2025, 1, 1), end_time=datetime(2025, 1, 2), type="forecast") + """ if not isinstance(country, str): raise ValueError("Invalid country") @@ -75,14 +96,6 @@ def energy(country, start_time, end_time, type="generation") -> dict: e_source = meta.get_country_energy_source(country) if e_source == "ENTSOE": if type == "generation": - """ - let local_found= false - see if caching is enabled, if yes, first check in the cache - if not, - check if offline data is enabled - if yes, check is data is available locally - if no, go online - """ offline_data = off.get_offline_data(country,start_time,end_time) if offline_data["available"] is True and offline_data["partial"] is False and offline_data["data"] is not None: # todo fix this if partial get remaining data and merge instead of fetching the complete data @@ -99,3 +112,24 @@ def energy(country, start_time, end_time, type="generation") -> dict: else: raise CodegreenDataError(Message.NO_ENERGY_SOURCE) return None + +def info()-> list: + """ + Returns a list of countries (in two-letter codes) and energy sources for which data can be fetched using the package. + + :return: A list of dictionary containing: + + - name of the country + - `energy_source` : the publicly available energy data source + - `carbon_intensity_method` : the methodology used to calculate carbon intensity + - `code` : the 2 letter country code + + :rtype: list + """ + data = meta.get_country_metadata() + data_list = [] + for key , value in data.items(): + c = value + c["code"] = key + data_list.append(c) + return data_list \ No newline at end of file From d6c2ae5d38b35511df91b7d52fa44058331e1e35 Mon Sep 17 00:00:00 2001 From: shubh Date: Sun, 2 Mar 2025 14:36:49 +0100 Subject: [PATCH 2/3] doc for data api done --- codegreen_core/data/__init__.py | 4 +- codegreen_core/data/offline.py | 47 ++++++++++++++-------- codegreen_core/tools/loadshift_time.py | 25 ++++++++++++ docs/_static/modules.png | Bin 11329 -> 0 bytes docs/api.rst | 52 +------------------------ docs/conf.py | 4 ++ docs/methodology.rst | 2 +- 7 files changed, 65 insertions(+), 69 deletions(-) delete mode 100644 docs/_static/modules.png diff --git a/codegreen_core/data/__init__.py b/codegreen_core/data/__init__.py index 23d14ff..5670f91 100644 --- a/codegreen_core/data/__init__.py +++ b/codegreen_core/data/__init__.py @@ -1,3 +1,5 @@ from .main import * +from .offline import * +# from . import main -__all__ = ["energy","info"] +__all__ = ["info","energy","sync_offline_data",'get_offline_data'] \ No newline at end of file diff --git a/codegreen_core/data/offline.py b/codegreen_core/data/offline.py index e512a40..b280636 100644 --- a/codegreen_core/data/offline.py +++ b/codegreen_core/data/offline.py @@ -243,16 +243,27 @@ def _get_offline_cache_data(country,start,end): return False,None -def get_offline_data(country,start,end,sync_first=False): +def get_offline_data(country,start,end,sync_first=False)->dict: """ - This method returns locally stored energy data. - Data is stored in 2 sources : one. Redis cache and second : csv files. - Redis cache contains data only for the last 72 hours from when it was last synced - Offline data files can contain data for longer durations. - Both these options can be configured in the config file - returns {available:True/False, data:dataframe} - Note that this method assumes that syncing of the sources is being handled separately + This method returns locally stored energy data. + + Data is stored in two sources: + + 1. **Redis cache**: Contains data for a limited number of hours from the last sync. + 2. **CSV files**: Contain data for longer durations. + + Both storage options can be configured in the configuration file. + + **Note**: Unless you specify the ``sync_first`` flag, the method assumes that syncing of the data sources is handled separately. If ``sync_first`` is set to ``True`` and data files are not initialized in advance, the method may take longer to complete + + :return: A dictionary with the following keys: + - **available** (*bool*): Indicates if the data is available. + - **data** (*pandas.DataFrame*): The energy data, if available. Otherwise, an empty DataFrame. + + :rtype: dict + """ + output = {"available":False,"data":None, "partial":False,"source":""} offline = Config.get("enable_offline_energy_generation") cache = Config.get("enable_energy_caching") @@ -264,7 +275,7 @@ def get_offline_data(country,start,end,sync_first=False): if cache : # first look in the cache if(sync_first): - print("will first sync the cache to get the latest data") + #print("will first sync the cache to get the latest data") _sync_offline_cache(country) partial,data = _get_offline_cache_data(country,start,end) if data is not None and partial is False: @@ -278,23 +289,28 @@ def get_offline_data(country,start,end,sync_first=False): if offline: # first look if data files are available, if yes, return data if(sync_first): - print("will first sync the offline files to get the latest data") + #print("will first sync the offline files to get the latest data") _sync_offline_file(country) partial,data = _get_offline_file_data(country,start,end) output["partial"] = partial output["data"] = data output["available"] = True output["source"] = "offline_file" - print("just got the data from offline file") + #print("just got the data from offline file") return output def sync_offline_data(file=False,cache=False): """ - This method syncs offline data for offline sources enabled in the cache. - Data is synced for all available countries - You need to run this before getting offline data. you can even setup a CRON job to call this method on regular intervals + This method syncs offline data for offline sources enabled in the configuration file. The data is synced for all available countries. + + You need to run this method before retrieving offline data. It is also possible to set up a CRON job to call this method at regular intervals to keep data synchronized. + + The sync operation can take some time, depending on the data size and the selected sync options (file, cache, or both). + + :param bool file: If ``True``, sync data in offline files. Defaults to ``False``. + :param bool cache: If ``True``, sync data in the cache. Defaults to ``False``. """ c_keys = meta.get_country_metadata() if Config.get("enable_offline_energy_generation") == True and file == True: @@ -302,13 +318,10 @@ def sync_offline_data(file=False,cache=False): try: _sync_offline_file(key) except Exception as e: - # print(e) log_stuff("Error in syncing offline file for "+key+". Message"+ str(e)) if Config.get("enable_energy_caching") == True and cache == True : for key in c_keys: try: _sync_offline_cache(key) except Exception as e: - # print(e) log_stuff("Error in syncing offline file for "+key+". Message: "+ str(e)) - diff --git a/codegreen_core/tools/loadshift_time.py b/codegreen_core/tools/loadshift_time.py index 7d7fb8e..e8aae72 100644 --- a/codegreen_core/tools/loadshift_time.py +++ b/codegreen_core/tools/loadshift_time.py @@ -70,6 +70,31 @@ def predict_now( :type criteria: str :return: Tuple[timestamp, message, average_percent_renewable] :rtype: tuple + + **Example usage**: + + .. code-block:: python + + from datetime import datetime,timedelta + from codegreen_core.tools.loadshift_time import predict_now + + country_code = "DK" + est_runtime_hour = 10 + est_runtime_min = 0 + now = datetime.now() + hard_finish_date = now + timedelta(days=1) + criteria = "percent_renewable" + per_renewable = 50 + + time = predict_now(country_code, + est_runtime_hour, + est_runtime_min, + hard_finish_date, + criteria, + per_renewable) + # (1728640800.0, , 76.9090909090909) + + """ if criteria == "percent_renewable": try: diff --git a/docs/_static/modules.png b/docs/_static/modules.png deleted file mode 100644 index ea57e673fc9cbfd67ee48fb7880b09ab70baccc0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11329 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 diff --git a/docs/api.rst b/docs/api.rst index 7b672f0..b736c41 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -1,57 +1,9 @@ codegreen_core API =================== - -Package Organization ---------------------- - -.. image:: _static/modules.png - :alt: modules - :width: 400px - :align: center - - -The package is divided into two main sub packages: `data`` and `tools`. (There is also an additional module, `utilities`, which provides helper methods that support other modules.) - -The `data` sub package contains methods for fetching energy production data. This package relies on external data sources to retrieve this information, which is then processed to make it usable by other components of the package. For more details and a complete API , see the data module documentation. - -The `tools` sub package provides a variety of tools, including: - -- Carbon intensity calculator -- Carbon emission calculator -- Optimal time-shifting predictor -- Optimal location-shifting predictor - - -Example : Calculating optimal time for a computational task -------------------------------------------------------------- -Assuming all the above steps are done, you can now calculate the optimal starting time for a computations. - -.. code-block:: python - - from datetime import datetime,timedelta - from codegreen_core.tools.loadshift_time import predict_now - - country_code = "DK" - est_runtime_hour = 10 - est_runtime_min = 0 - now = datetime.now() - hard_finish_date = now + timedelta(days=1) - criteria = "percent_renewable" - per_renewable = 50 - - time = predict_now(country_code, - est_runtime_hour, - est_runtime_min, - hard_finish_date, - criteria, - per_renewable) - # (1728640800.0, , 76.9090909090909) - - - The core package contains 2 main module : -- `data` : To fetch energy data for a country + +- `data` : To fetch energy data for a country. - `tools` : To calculate various quantities like Optimal computation time, carbon intensity etc. diff --git a/docs/conf.py b/docs/conf.py index 3af2104..d10c0ee 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -47,5 +47,9 @@ html_theme = "alabaster" html_static_path = ["_static"] +html_theme_options = { + "github_user": "codegreen-framework", + "github_repo": "codegreen-core" +} # import codegreen_core diff --git a/docs/methodology.rst b/docs/methodology.rst index fc06d5a..cdb7414 100644 --- a/docs/methodology.rst +++ b/docs/methodology.rst @@ -6,7 +6,7 @@ Here we describe how we calcualte stuff ``tools`` Module -================= +------------------ This subpackage provides tools and methods for tasks like calculating the carbon intensity of energy production and calculating the emissions produced due to a computation. From dff3aec88930471c70cc4b81d62b6c68a72567b5 Mon Sep 17 00:00:00 2001 From: shubh Date: Mon, 10 Mar 2025 16:38:25 +0100 Subject: [PATCH 3/3] new pkg --- .github/workflows/workflow.yml | 6 +++--- codegreen_core/data/entsoe.py | 34 ++++++++++++++++++++++++++++++++++ codegreen_core/data/main.py | 8 +++++--- pyproject.toml | 2 +- 4 files changed, 43 insertions(+), 7 deletions(-) diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index 2b39f94..2255de0 100644 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -1,4 +1,4 @@ -name: Publish Python 🐍 distribution 📦 to PyPI +name: Publish to PyPI on: push: @@ -7,7 +7,7 @@ on: jobs: build: - name: Build distribution 📦 + name: Build distribution runs-on: ubuntu-latest steps: @@ -30,7 +30,7 @@ jobs: path: dist/ publish-to-pypi: - name: Publish Python 🐍 distribution 📦 to PyPI + name: Publish to PyPI needs: - build runs-on: ubuntu-latest diff --git a/codegreen_core/data/entsoe.py b/codegreen_core/data/entsoe.py index 54a0b78..20474c3 100644 --- a/codegreen_core/data/entsoe.py +++ b/codegreen_core/data/entsoe.py @@ -47,6 +47,8 @@ "Biomass": ["Biomass"], } + + # helper methods @@ -287,6 +289,7 @@ def get_actual_production_percentage(country, start, end, interval60=False) -> d - `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 + - `columns` : a dict with column description :rtype: dict """ try: @@ -371,6 +374,7 @@ def get_actual_production_percentage(country, start, end, interval60=False) -> d "data": _format_energy_data(table), "data_available": True, "time_interval": duration, + "columns":gen_cols_from_data(table) } except Exception as e: # print(e) @@ -380,8 +384,38 @@ def get_actual_production_percentage(country, start, end, interval60=False) -> d "data_available": False, "error": e, "time_interval": 0, + "columns":None } +def gen_cols_from_data(df): + """generates list of columns for the given energy generation dataframe""" + allAddkeys = [ + "Wind", + "Solar", + "Nuclear", + "Hydroelectricity", + "Geothermal", + "Natural Gas", + "Petroleum", + "Coal", + "Biomass", + ] + + allCols = df.columns.tolist() + # find out which columns are present in the data out of all the possible columns in both the categories + renPresent = list(set(allCols).intersection(renewableSources)) + nonRenPresent = list(set(allCols).intersection(nonRenewableSources)) + + cols = { + "renewable" : renPresent, + "nonRenewable": nonRenPresent, + "percentage":[] + } + for ky in allAddkeys: + fieldName = ky + "_per" + cols["percentage"].append(fieldName) + return cols + def get_forecast_percent_renewable( country: str, start: datetime, end: datetime diff --git a/codegreen_core/data/main.py b/codegreen_core/data/main.py index 611d380..2caa0d6 100644 --- a/codegreen_core/data/main.py +++ b/codegreen_core/data/main.py @@ -58,6 +58,7 @@ def energy(country, start_time, end_time, type="generation") -> dict: - **data** (*pandas.DataFrame*): The retrieved energy data if available; an empty DataFrame otherwise. - **time_interval** (*int*): The time interval of the DataFrame (constant value: ``60``). - **source** (*str*): Specifies the origin of the retrieved data. Defaults to ``'public_data'``, indicating it was fetched from an external source. If the offline storage feature is enabled, this value may change if the data is available locally. + - **columns** : a dict of columns for renewable and non renewable energy sources in the data :rtype: dict @@ -99,15 +100,16 @@ def energy(country, start_time, end_time, type="generation") -> dict: offline_data = off.get_offline_data(country,start_time,end_time) if offline_data["available"] is True and offline_data["partial"] is False and offline_data["data"] is not None: # todo fix this if partial get remaining data and merge instead of fetching the complete data - return {"data":offline_data["data"],"data_available":True,"error":"None","time_interval":60,"source":offline_data["source"]} + return {"data":offline_data["data"],"data_available":True,"error":"None","time_interval":60,"source":offline_data["source"],"columns":et.gen_cols_from_data(offline_data["data"])} else: energy_data = et.get_actual_production_percentage(country, start_time, end_time, interval60=True) - energy_data["data"] = energy_data["data"] + #energy_data["data"] = energy_data["data"] energy_data["source"] = "public_data" + #energy_data["columns"] = return energy_data elif type == "forecast": energy_data = et.get_forecast_percent_renewable(country, start_time, end_time) - energy_data["data"] = energy_data["data"] + # energy_data["data"] = energy_data["data"] return energy_data else: raise CodegreenDataError(Message.NO_ENERGY_SOURCE) diff --git a/pyproject.toml b/pyproject.toml index af2f4db..0d35fb5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "codegreen_core" -version = "0.0.4" +version = "0.0.5" description = "This package helps you become aware of the carbon footprint of your computation" authors = ["Anne Hartebrodt ","Shubh Vardhan Jain "] readme = "README.md"