Using fully with Python
ecodynelec offers the possibility to being fully used via Python.
This tutorial shows the different steps and possibilities, relying
solely on operations doable within a python script or notebook. As the
configuration of ecodynelec pipeline execution may benefit from more
visual interaction, an alternative is suggested in the “Using with a
spreadsheet-based
configuraion”
tutorial.
Initialization
To download and install ecodynelec to being used as a python
package, the user is referred to either the getting started
tutorial.
Configuration
The configuration of ecodynelec is handled by the parameter
module.
from ecodynelec.parameter import Parameter # Import the class to manipulate parameters
Python is an object oriented language. Thus a specific configuration can
be built and stored in a Parameter object that will be called
my_config in this tutorial. The next cell only initializes the
configuration object with the default parameters.
my_config = Parameter() # Initialize a configuration object
Before modifying the configuration, let’s have a look at this default setting
print(my_config)
ctry --> ['AT', 'CH', 'CZ', 'DE', 'FR', 'IT']
target --> CH
start --> 2017-02-01 00:00:00
end --> 2017-02-01 23:00:00
freq --> H
timezone --> UTC
cst_imports --> False
net_exchanges --> False
network_losses --> False
sg_imports --> False
residual_local --> False
residual_global --> False
data_cleaning --> True
Filepath to generation --> None
Filepath to exchanges --> None
Filepath to savedir --> None
Filepath to ui_vector --> None
Filepath to mapping --> None
Filepath to neighbours --> None
Filepath to gap --> None
Filepath to swissGrid --> None
Filepath to networkLosses --> None
Server for useServer --> False
Server for host --> sftp-transparency.entsoe.eu
Server for port --> 22
Server for username --> None
Server for password -->
Server for removeUnused --> False
Server for _remoteGenerationDir --> /TP_export/AggregatedGenerationPerType_16.1.B_C/
Server for _remoteExchangesDir --> /TP_export/PhysicalFlows_12.1.G/
The configuration is composed of 3 parts. The detail about the meaning
of each is developed in the input data
section.
Essentially: * the first block contains the elements to configure the
execution itself. These elements are directly available and modifiable
with the syntax my_config.element. * the second block deals with
all paths to information files, directory containing information, or
where to write and save information before, during and after the
computation. It is accessible with the syntax my_config.path.element
* the third block deals with information related to the ENTSO-E server,
as electricity data from the ENTSO-E server is at the center of
ecodynelec. More on this topic is covered on the next paragraph and
on the dedicated downloading
tutorial.
The next cell partly modifies the execution configuration. * First the
starting date is modified. Note that objects of the Parameter class
will verify if this element is a date, and will raise an error if the
format is not recognized. * Then we modify the size of time step
(frequency) for the computation. Possibilities are specified in the
input data
section.
* Third in this example, the auto-completing feature is turned off.
## Change the starting date
my_config.start = '2017-02-01 00:00'
## Change the time step
my_config.freq = "15min"
## Change the coutry list
my_config.ctry = ['AT','CH','DE','FR','IT']
## Turn off the auto-complete
my_config.data_cleaning = False
The next cell partly modifies file path configuration. Here we modify the location of directories containing data downloaded from the ENTSO-E database.
# Indicate where to find generation data
my_config.path.generation = "./test_data/generations/"
# Indicate where to find exchange data
my_config.path.exchanges = "./test_data/exchanges/"
Note that, for the generation, exchanges and savedir paths,
the specified directory will be created if it does not already exist.
For every other file path element, a default file is used if nothing
is specified, and an error is returned if the information passed does
not correspond to any existing file on your local machine.
Downloading Entso-E data
The downloading
tutorial
covers the specificities about how to download the ENTSO-E data or
include the download as part of the ecodynelec pipeline execution.
This feature is not triggered per default and ecodynelec is
expecting to find already downloaded ENTSO-E files.
Execution
ecodynelec is build out of a myriad of modules that can be used
relatively independently, under the condition that inputs data is shaped
the correct way. Fortunately, the entire pipeline starting from a set of
parameters and computing down to the calculation of impact metrics.
The usage of this entire pipeline is demonstrated below. This pipeline
allows to save results into files (c.f. paragraph on
configuration).
However results are also always returned for further in-script use.
These results are stored in the impacts variable for later
paragraphs in this tutorial.
from ecodynelec.pipelines import execute
impacts = execute(config=my_config, is_verbose=True)
Load auxiliary datasets...
Load generation data...
Generation data.
Data loading: 0.03 sec..
Memory usage table: 0.18 MB
Autocomplete... 5/5)...
=========================
Missing data identified: 8 (0.22%)
AT CH DE FR IT
Biomass - - - - -
Fossil Gas - - - - -
Fossil Hard coal - - - - -
Fossil Oil - - - - -
Geothermal - - - - -
Hydro Pumped Storage - - - 8 -
Hydro Run-of-river and poundage - - - - -
Hydro Water Reservoir - - - - -
Other - - - - -
Other renewable - - - - -
Solar - - - - -
Waste - - - - -
Wind Onshore - - - - -
Nuclear - - - - -
Fossil Brown coal/Lignite - - - - -
Fossil Coal-derived gas - - - - -
Wind Offshore - - - - -
=========================
Extraction raw generation: 0.13 sec.
Extraction time: 0.16 sec.
4/4 - Resample exchanges to 15min steps...
Get and reduce importation data...
Cross-border flow data.
Data loading: 0.02 sec..
Memory usage table: 0.04 MB
Autocomplete... ...
=========================
Missing data identified: 1152 (71.38%)
AT CH DE FR IT
CH - - - - -
CZ - - - - -
DE - - - - -
HU 96 - - - -
IT - - - - -
SI 96 - - - 96
AT - - - - -
FR - - - - -
DK - - 96 - -
NL - - 96 - -
PL - - 96 - -
SE - - 96 - -
BE - - - 96 -
ES - - - 96 -
GB - - - 96 -
GR - - - - 96
MT - - - - 96
=========================
Extraction raw import: 0.10 sec.
Extraction time: 0.12 sec.
Resample exchanges to 15min steps...
Gather generation and importation...
Import of data: 0.3 sec
Importing information...
Tracking origin of electricity...
compute for day 1/1
Electricity tracking: 1.2 sec.
Compute the electricity impacts...
Global...
Carbon intensity...
Human carcinogenic toxicity...
Fine particulate matter formation...
Land use...
Impact computation: 0.0 sec.
Adapt timezone: UTC >> UTC
done.
Outcome and Visualization
The outcome is stored in files and returned for further in-script use.
In the previous section, results were stored in the impacts
variable. The current section highlights the content returned and shows
some basic possibilities for data visualization.
import numpy as np
import pandas as pd
Description of the outcome
The impacts variable contains a collection of tables. This
collection is a dict with one Global key, and one other key per
impact category:
print(impacts.keys())
dict_keys(['Global', 'Carbon intensity', 'Human carcinogenic toxicity', 'Fine particulate matter formation', 'Land use'])
The Global table is the sum across all technologies for each
index, as it is shown for the first few time steps:
display(impacts['Global'].head())
| Carbon intensity | Human carcinogenic toxicity | Fine particulate matter formation | Land use | |
|---|---|---|---|---|
| 2017-02-01 00:00:00 | 0.460800 | 0.030586 | 0.000353 | 0.007269 |
| 2017-02-01 00:15:00 | 0.460092 | 0.030610 | 0.000353 | 0.007258 |
| 2017-02-01 00:30:00 | 0.460153 | 0.030682 | 0.000353 | 0.007247 |
| 2017-02-01 00:45:00 | 0.457920 | 0.030642 | 0.000348 | 0.007215 |
| 2017-02-01 01:00:00 | 0.458639 | 0.030747 | 0.000349 | 0.007192 |
The other tables are, for each impact category, the breakdown into all possible sources:
for i in impacts: # Iterate for all impact categories
if i=='Global': continue; # Skip the Global, already visualized above.
print(f"#############\nimpacts for {i}:")
display( impacts[i].head(3).T ) # Transpose table for readability
#############
impacts for Carbon intensity:
| 2017-02-01 00:00:00 | 2017-02-01 00:15:00 | 2017-02-01 00:30:00 | |
|---|---|---|---|
| Carbon intensity_source | |||
| Mix_Other | 0.006686 | 0.006624 | 0.006525 |
| Biomass_AT | 0.000330 | 0.000325 | 0.000317 |
| Fossil_Brown_coal/Lignite_AT | 0.000000 | 0.000000 | 0.000000 |
| Fossil_Coal-derived_gas_AT | 0.000000 | 0.000000 | 0.000000 |
| Fossil_Gas_AT | 0.018306 | 0.017540 | 0.017000 |
| ... | ... | ... | ... |
| Other_renewable_IT | 0.000000 | 0.000000 | 0.000000 |
| Solar_IT | 0.000000 | 0.000000 | 0.000000 |
| Waste_IT | 0.000000 | 0.000000 | 0.000000 |
| Wind_Offshore_IT | 0.000000 | 0.000000 | 0.000000 |
| Wind_Onshore_IT | 0.000000 | 0.000000 | 0.000000 |
101 rows × 3 columns
#############
impacts for Human carcinogenic toxicity:
| 2017-02-01 00:00:00 | 2017-02-01 00:15:00 | 2017-02-01 00:30:00 | |
|---|---|---|---|
| Human carcinogenic toxicity_source | |||
| Mix_Other | 0.000446 | 0.000442 | 0.000435 |
| Biomass_AT | 0.000023 | 0.000022 | 0.000022 |
| Fossil_Brown_coal/Lignite_AT | 0.000000 | 0.000000 | 0.000000 |
| Fossil_Coal-derived_gas_AT | 0.000000 | 0.000000 | 0.000000 |
| Fossil_Gas_AT | 0.000132 | 0.000126 | 0.000122 |
| ... | ... | ... | ... |
| Other_renewable_IT | 0.000000 | 0.000000 | 0.000000 |
| Solar_IT | 0.000000 | 0.000000 | 0.000000 |
| Waste_IT | 0.000000 | 0.000000 | 0.000000 |
| Wind_Offshore_IT | 0.000000 | 0.000000 | 0.000000 |
| Wind_Onshore_IT | 0.000000 | 0.000000 | 0.000000 |
101 rows × 3 columns
#############
impacts for Fine particulate matter formation:
| 2017-02-01 00:00:00 | 2017-02-01 00:15:00 | 2017-02-01 00:30:00 | |
|---|---|---|---|
| Fine particulate matter formation_source | |||
| Mix_Other | 0.000010 | 0.000010 | 0.000010 |
| Biomass_AT | 0.000001 | 0.000001 | 0.000001 |
| Fossil_Brown_coal/Lignite_AT | 0.000000 | 0.000000 | 0.000000 |
| Fossil_Coal-derived_gas_AT | 0.000000 | 0.000000 | 0.000000 |
| Fossil_Gas_AT | 0.000006 | 0.000006 | 0.000005 |
| ... | ... | ... | ... |
| Other_renewable_IT | 0.000000 | 0.000000 | 0.000000 |
| Solar_IT | 0.000000 | 0.000000 | 0.000000 |
| Waste_IT | 0.000000 | 0.000000 | 0.000000 |
| Wind_Offshore_IT | 0.000000 | 0.000000 | 0.000000 |
| Wind_Onshore_IT | 0.000000 | 0.000000 | 0.000000 |
101 rows × 3 columns
#############
impacts for Land use:
| 2017-02-01 00:00:00 | 2017-02-01 00:15:00 | 2017-02-01 00:30:00 | |
|---|---|---|---|
| Land use_source | |||
| Mix_Other | 0.000192 | 0.000191 | 0.000188 |
| Biomass_AT | 0.001014 | 0.000997 | 0.000974 |
| Fossil_Brown_coal/Lignite_AT | 0.000000 | 0.000000 | 0.000000 |
| Fossil_Coal-derived_gas_AT | 0.000000 | 0.000000 | 0.000000 |
| Fossil_Gas_AT | 0.000068 | 0.000065 | 0.000063 |
| ... | ... | ... | ... |
| Other_renewable_IT | 0.000000 | 0.000000 | 0.000000 |
| Solar_IT | 0.000000 | 0.000000 | 0.000000 |
| Waste_IT | 0.000000 | 0.000000 | 0.000000 |
| Wind_Offshore_IT | 0.000000 | 0.000000 | 0.000000 |
| Wind_Onshore_IT | 0.000000 | 0.000000 | 0.000000 |
101 rows × 3 columns
Group per country
The following piece of code suggests a basic visualization of the Carbon intensity category, grouping the results per country of origin of the tracked electricity.
def compute_per_country(results):
"""Function to group results per country"""
countries = np.unique([c.split("_")[-1] for c in results.columns]) # List of countries
per_country = []
for c in countries:
cols = [k for k in results.columns if k[-3:]==f"_{c}"]
per_country.append(pd.Series(results.loc[:,cols].sum(axis=1), name=c))
return pd.concat(per_country,axis=1)
gwp_per_country = compute_per_country(impacts['Carbon intensity']) # Group Carbon intensity index impacts per country
gwp_per_country.plot.area(figsize=(12,4), legend='reverse', color=['r','w','y','b','c','k'],
title="Some visualization of the Carbon intensity aggregated per country"); # Build the graph
Group per production type
The following piece of code suggests a basic visualization of the Carbon intensity category, grouping the results per technology of origin of the tracked electricity.
def compute_per_type(results):
"""Function to group datasets per type of unit, regardless of the country of origin"""
unit_list = np.unique([k[:-3] if k[-3]=="_" else k for k in results.columns]) # List the different production units
per_unit = []
for u in unit_list:
cols = [k for k in results.columns if k[:-3]==u] # collect the useful columns
per_unit.append(pd.Series(results.loc[:,cols].sum(axis=1), name=u)) # aggregate
return pd.concat(per_unit,axis=1)
es13_per_type = compute_per_type(impacts['Carbon intensity']) # Group Carbon intensity index impacts per country
es13_per_type.plot.area(figsize=(12,8), legend='reverse',
title="Some visualization of the Carbon intensity index aggregated per source"); # Build the graph