Fully Parameterized Working Example (Detailed)

In contrast to the mwe, the fpwe differs (among other things) by utilizing a fixed timeseries to model a solar panel’s output.

Initial code to do the comparison

>>> # change spellings_logging_level to debug to declutter output
>>> import tessif.frused.configurations as configurations
>>> configurations.spellings_logging_level = 'debug'
>>> # Import hardcoded tessif energy system using the example hub:
>>> import tessif.examples.data.tsf.py_hard as tsf_examples
>>> # Choose the underlying energy system
>>> tsf_es = tsf_examples.create_fpwe()
>>> # write it to disk, so the comparatier can read it out
>>> import os
>>> from tessif.frused.paths import write_dir
>>> #
>>> output_msg = tsf_es.to_hdf5(
...     directory=os.path.join(write_dir, 'tsf'),
...     filename='es_to_compare.hdf5',
... )
>>> # let the comparatier do the auto comparison:
>>> import tessif.analyze, tessif.parse
>>> import functools  # nopep8
>>> from tessif.frused.hooks.tsf import reparameterize_components  # nopep8
>>> comparatier = tessif.analyze.Comparatier(
...     path=os.path.join(write_dir, 'tsf', 'es_to_compare.hdf5'),
...     parser=tessif.parse.hdf5,
...     models=('oemof', 'pypsa', 'fine', 'calliope'),
...     hooks={
...         'calliope': functools.partial(
...            reparameterize_components,
...            components={
...                'Battery': {
...                     'initial_soc': 9,
...                 },
...             }
...         )
...     },
...     scaling=True,
... )

Code accessing the results

Following section provides examples on how to use the Comparatier interface to access the auto generated comparison results

Analyzed Subjects

Following sections show how to access the analyzed energy systems and models

Models

>>> # show the models compared:
>>> for model in sorted(comparatier.models):
...     print(model)
cllp
fine
omf
ppsa

Energy System Objects

>>> # access the model based energy system objects
>>> # (type(es) printed here for doctesting)
>>> #
>>> for model, es in comparatier.energy_systems.items():
...     print(f'{model}: {type(es)}')
cllp: <class 'calliope.core.model.Model'>
fine: <class 'FINE.energySystemModel.EnergySystemModel'>
omf: <class 'oemof.solph.network.energy_system.EnergySystem'>
ppsa: <class 'pypsa.components.Network'>

Optimization Results

Following demonstrate how to access the numerical simulation results

Singular Model Results

>>> # access the model based post processing results
>>> for model, resultier in comparatier.optimization_results.items():
...     print(model)
...     print(79*'-')
...     print(resultier.node_load['Powerline'])
...     print(79*'-')
cllp
-------------------------------------------------------------------------------
Powerline            Battery  Generator  Solar Panel  Battery  Demand
1990-07-13 00:00:00     -0.0       -0.0        -12.0      1.0    11.0
1990-07-13 01:00:00     -8.0       -0.0         -3.0      0.0    11.0
1990-07-13 02:00:00     -0.9       -3.1         -7.0      0.0    11.0
-------------------------------------------------------------------------------
fine
-------------------------------------------------------------------------------
Powerline            Battery  Generator  Solar Panel  Battery  Demand
1990-07-13 00:00:00     -0.0       -0.0        -12.0      1.0    11.0
1990-07-13 01:00:00     -0.9       -7.1         -3.0      0.0    11.0
1990-07-13 02:00:00     -0.0       -4.0         -7.0      0.0    11.0
-------------------------------------------------------------------------------
omf
-------------------------------------------------------------------------------
Powerline            Battery  Generator  Solar Panel  Battery  Demand
1990-07-13 00:00:00     -0.0       -0.0        -12.0      1.0    11.0
1990-07-13 01:00:00     -8.0       -0.0         -3.0      0.0    11.0
1990-07-13 02:00:00     -0.9       -3.1         -7.0      0.0    11.0
-------------------------------------------------------------------------------
ppsa
-------------------------------------------------------------------------------
Powerline            Battery  Generator  Solar Panel  Battery  Demand
1990-07-13 00:00:00     -0.0       -0.0        -12.0      1.0    11.0
1990-07-13 01:00:00     -8.0       -0.0         -3.0      0.0    11.0
1990-07-13 02:00:00     -0.9       -3.1         -7.0      0.0    11.0
-------------------------------------------------------------------------------

Comparative Model Results

Following sections show how to utilize to built-in ComparativeResultier to access results conveniently among models.

Installed Capacity Results
>>> print(comparatier.comparative_results.capacities['Battery'])
cllp    10.0
fine     1.0
omf     10.0
ppsa    10.0
Name: Battery, dtype: float64
Original Capacity Results
>>> print(comparatier.comparative_results.original_capacities['Battery'])
cllp    10.0
fine     0.0
omf     10.0
ppsa    10.0
Name: Battery, dtype: float64
Capacity Expansion Costs
>>> print(comparatier.comparative_results.original_capacities['Solar Panel'])
cllp    20.0
fine    12.0
omf     20.0
ppsa    20.0
Name: Solar Panel, dtype: float64
Flow Cost Results
>>> print(comparatier.comparative_results.costs[('Generator', 'Powerline')])
cllp    10.000000
fine    10.000000
omf     10.000000
ppsa    33.809524
Name: (Generator, Powerline), dtype: float64
Characteristic Value Results
>>> print(comparatier.comparative_results.cvs['Generator'])
cllp    0.068889
fine    0.180000
omf     0.068889
ppsa    0.068889
Name: Generator, dtype: float64
Flow Emission Results
>>> print(comparatier.comparative_results.emissions[('Generator', 'Powerline')])
cllp    10.000000
fine    10.000000
omf     10.000000
ppsa    17.142857
Name: (Generator, Powerline), dtype: float64
Load Results
>>> print(comparatier.comparative_results.loads['Powerline'])
                       cllp                                         fine                                          omf                                         ppsa
Powerline           Battery Generator Solar Panel Battery Demand Battery Generator Solar Panel Battery Demand Battery Generator Solar Panel Battery Demand Battery Generator Solar Panel Battery Demand
1990-07-13 00:00:00    -0.0      -0.0       -12.0     1.0   11.0    -0.0      -0.0       -12.0     1.0   11.0    -0.0      -0.0       -12.0     1.0   11.0    -0.0      -0.0       -12.0     1.0   11.0
1990-07-13 01:00:00    -8.0      -0.0        -3.0     0.0   11.0    -0.9      -7.1        -3.0     0.0   11.0    -8.0      -0.0        -3.0     0.0   11.0    -8.0      -0.0        -3.0     0.0   11.0
1990-07-13 02:00:00    -0.9      -3.1        -7.0     0.0   11.0    -0.0      -4.0        -7.0     0.0   11.0    -0.9      -3.1        -7.0     0.0   11.0    -0.9      -3.1        -7.0     0.0   11.0
All Load Results
>>> print(comparatier.comparative_results.all_loads['omf'])
                      Battery Gas Station Generator  Pipeline Powerline        Solar Panel
                    Powerline    Pipeline Powerline Generator   Battery Demand   Powerline
1990-07-13 00:00:00       0.0    0.000000       0.0  0.000000       1.0   11.0        12.0
1990-07-13 01:00:00       8.0    0.000000       0.0  0.000000       0.0   11.0         3.0
1990-07-13 02:00:00       0.9    7.380952       3.1  7.380952       0.0   11.0         7.0
>>> print(comparatier.comparative_results.all_loads['ppsa'])
                      Battery Generator Powerline        Solar Panel
                    Powerline Powerline   Battery Demand   Powerline
1990-07-13 00:00:00       0.0       0.0       1.0   11.0        12.0
1990-07-13 01:00:00       8.0       0.0       0.0   11.0         3.0
1990-07-13 02:00:00       0.9       3.1       0.0   11.0         7.0
>>> print(comparatier.comparative_results.all_loads['fine'])
                      Battery Gas Station Generator   Pipeline Powerline        Solar Panel
                    Powerline    Pipeline Powerline  Generator   Battery Demand   Powerline
1990-07-13 00:00:00       0.0    0.000000       0.0   0.000000       1.0   11.0        12.0
1990-07-13 01:00:00       0.9   16.904762       7.1  16.904762       0.0   11.0         3.0
1990-07-13 02:00:00       0.0    9.523810       4.0   9.523810       0.0   11.0         7.0
>>> print(comparatier.comparative_results.all_loads['cllp'])
                      Battery Gas Station Generator  Pipeline Powerline        Solar Panel
                    Powerline    Pipeline Powerline Generator   Battery Demand   Powerline
1990-07-13 00:00:00       0.0    0.000000       0.0  0.000000       1.0   11.0        12.0
1990-07-13 01:00:00       8.0    0.000000       0.0  0.000000       0.0   11.0         3.0
1990-07-13 02:00:00       0.9    7.380952       3.1  7.380952       0.0   11.0         7.0

For more info on why the ppsa dataframe has less columns than the omf dataframe, please refer to tessif.transform.es2es.ppsa.compute_unneeded_supply_chains() and to the emission objective example comparison.

All Capacities
>>> print(comparatier.comparative_results.all_capacities)
              cllp   fine    omf  ppsa
Battery       10.0    1.0   10.0  10.0
Demand        11.0   11.0   11.0  11.0
Gas Station  100.0  100.0  100.0   NaN
Generator     15.0   21.0   15.0  15.0
Solar Panel   20.0   12.0   20.0  20.0
All Original Capacities
>>> print(comparatier.comparative_results.all_original_capacities)
              cllp   fine    omf  ppsa
Battery       10.0    0.0   10.0  10.0
Demand        11.0   11.0   11.0  11.0
Gas Station  100.0  100.0  100.0   NaN
Generator     15.0   21.0   15.0  15.0
Solar Panel   20.0   12.0   20.0  20.0
Pipeline       NaN    0.0    NaN   NaN
Powerline      NaN    0.0    NaN   NaN
All Net Energy Flows
>>> print(comparatier.comparative_results.all_net_energy_flows)
                        cllp   fine    omf  ppsa
Battery     Powerline   8.90   0.90   8.90   8.9
Gas Station Pipeline    7.38  26.43   7.38   NaN
Generator   Powerline   3.10  11.10   3.10   3.1
Pipeline    Generator   7.38  26.43   7.38   NaN
Powerline   Battery     1.00   1.00   1.00   1.0
            Demand     33.00  33.00  33.00  33.0
Solar Panel Powerline  22.00  22.00  22.00  22.0
All Costs Incurred
>>> print(comparatier.comparative_results.all_costs_incurred)
                       cllp   fine   omf        ppsa
Battery     Powerline   0.0    0.0   0.0    0.000000
Gas Station Pipeline   73.8  264.3  73.8         NaN
Generator   Powerline  31.0  111.0  31.0  104.809524
Pipeline    Generator   0.0    0.0   0.0         NaN
Powerline   Battery     0.0    0.0   0.0    0.000000
            Demand      0.0    0.0   0.0    0.000000
Solar Panel Powerline   0.0    0.0   0.0    0.000000
All Emissions Caused
>>> print(comparatier.comparative_results.all_emissions_caused)
                        cllp    fine    omf       ppsa
Battery     Powerline   0.00    0.00   0.00   0.000000
Gas Station Pipeline   22.14   79.29  22.14        NaN
Generator   Powerline  31.00  111.00  31.00  53.142857
Pipeline    Generator   0.00    0.00   0.00        NaN
Powerline   Battery     0.00    0.00   0.00   0.000000
            Demand      0.00    0.00   0.00   0.000000
Solar Panel Powerline   0.00    0.00   0.00   0.000000
All States of Charges
>>> print(comparatier.comparative_results.all_socs)
                       cllp    fine     omf    ppsa
                    Battery Battery Battery Battery
1990-07-13 00:00:00    10.0     0.0    10.0    10.0
1990-07-13 01:00:00     1.0     1.0     1.0     1.0
1990-07-13 02:00:00     0.0     0.0     0.0     0.0
Net Energy Flow Results
>>> print(comparatier.comparative_results.net_energy_flows[('Solar Panel', 'Powerline')])
cllp    22.0
fine    22.0
omf     22.0
ppsa    22.0
Name: (Solar Panel, Powerline), dtype: float64
State of Charge Results
>>> print(comparatier.comparative_results.socs['Battery'])
Battery              cllp  fine   omf  ppsa
1990-07-13 00:00:00  10.0   0.0  10.0  10.0
1990-07-13 01:00:00   1.0   1.0   1.0   1.0
1990-07-13 02:00:00   0.0   0.0   0.0   0.0
Edge Weight Results
>>> print(comparatier.comparative_results.weights[('Generator', 'Powerline')])
cllp    1.0
fine    1.0
omf     1.0
ppsa    1.0
Name: (Generator, Powerline), dtype: float64

Computational Results

Following sections demonstrate how to access the auto generated computational results.

Memory Usage Results in Bytes

Not doctested, since results vary slightly between runs:

import pprint

# Access the model based memory usage results:
for model, memory_results in comparatier.memory_usage_results.items():
    print(model)
    print(79*'-')
    pprint.pprint(memory_results)
    print(79*'-')

cllp
-------------------------------------------------------------------------------
{'parsing': 83185,
 'post_processing': 161250,
 'reading': 220657,
 'result': 1801156,
 'simulation': 576657,
 'transformation': 759407}
-------------------------------------------------------------------------------
fine
-------------------------------------------------------------------------------
{'parsing': 92885,
 'post_processing': 172822,
 'reading': 216152,
 'result': 1441275,
 'simulation': 641177,
 'transformation': 318239}
-------------------------------------------------------------------------------
omf
-------------------------------------------------------------------------------
{'parsing': 90895,
 'post_processing': 116713,
 'reading': 223382,
 'result': 691305,
 'simulation': 235735,
 'transformation': 24580}
-------------------------------------------------------------------------------
ppsa
-------------------------------------------------------------------------------
{'parsing': 95061,
 'post_processing': 93522,
 'reading': 218610,
 'result': 1533652,
 'simulation': 409450,
 'transformation': 717009}

Time Usage Results in Seconds

Not doctested, since results vary slightly between runs:

import pprint

# Access the model based time usage results:
for model, timing_results in comparatier.timing_results.items():
    print(model)
    print(79*'-')
    pprint.pprint(timing_results)
    print(79*'-')

cllp
-------------------------------------------------------------------------------
{'parsing': 0.2704,
 'post_processing': 0.1708,
 'reading': 0.1224,
 'result': 1.061,
 'simulation': 0.4329,
 'transformation': 0.0652}
-------------------------------------------------------------------------------
fine
-------------------------------------------------------------------------------
{'parsing': 0.2704,
 'post_processing': 0.1708,
 'reading': 0.1224,
 'result': 1.061,
 'simulation': 0.4329,
 'transformation': 0.0652}
-------------------------------------------------------------------------------
omf
-------------------------------------------------------------------------------
{'parsing': 0.2651,
 'post_processing': 0.1722,
 'reading': 0.1158,
 'result': 0.653,
 'simulation': 0.0982,
 'transformation': 0.0016}
-------------------------------------------------------------------------------
ppsa
-------------------------------------------------------------------------------
{'parsing': 0.2663,
 'post_processing': 0.0829,
 'reading': 0.1166,
 'result': 1.121,
 'simulation': 0.2428,
 'transformation': 0.4119}
-------------------------------------------------------------------------------

Scalability Results

Not doctested, since results vary slightly between runs:

import pprint

# Access the model based scalability results:
# time in seconds, memory in MB:
for model, scalability_results in comparatier.scalability_results.items():
    print(model)
    print(79*'-')
    for result_type, results in scalability_results._asdict().items():
        print(result_type)
        pprint.pprint(results)
    print(79*'-')

cllp
-------------------------------------------------------------------------------
memory
                                            1                                              2
2  (227.4, 98.7, 798.7, 728.2, 205.0, 2058.0)  (301.9, 156.8, 1167.6, 1891.1, 300.9, 3818.2)
time
                                1                               2
2  (0.1, 0.2, 1.0, 0.5, 1.2, 3.1)  (0.2, 0.3, 1.3, 0.6, 3.2, 5.7)
-------------------------------------------------------------------------------
fine
-------------------------------------------------------------------------------
memory
                                            1                                            2
2  (223.6, 93.6, 260.9, 510.3, 171.1, 1259.4)  (309.3, 157.2, 546.9, 610.2, 339.3, 1962.9)
time
                                1                               2
2  (0.1, 0.2, 0.1, 0.4, 0.3, 1.1)  (0.2, 0.3, 0.1, 0.5, 0.7, 1.8)
-------------------------------------------------------------------------------
omf
-------------------------------------------------------------------------------
memory
                                          1                                           2
2  (227.3, 99.0, 30.7, 201.3, 131.5, 689.8)  (320.0, 155.3, 92.3, 358.1, 272.6, 1198.3)
time
                                1                               2
2  (0.1, 0.2, 0.0, 0.1, 0.2, 0.7)  (0.2, 0.3, 0.0, 0.2, 0.5, 1.2)
-------------------------------------------------------------------------------
ppsa
-------------------------------------------------------------------------------
memory
                                            1                                            2
2  (229.2, 96.3, 457.3, 396.3, 114.0, 1293.3)  (303.7, 156.4, 479.0, 436.5, 241.5, 1617.2)
time
                                1                               2
2  (0.1, 0.2, 0.5, 0.3, 0.1, 1.2)  (0.2, 0.3, 0.5, 0.3, 0.3, 1.7)
-------------------------------------------------------------------------------

Graphical Results

Following 2 sections show the available graphical representation of the scalability results.

2-Dimensional
3-Dimensional

The below charts were created using tessif.analyze.Comparatier.N = 4 and tessif.analyze.Comparatier.T = 4. Which is not shown in the code above:

>>> scalability_3d_charts = comparatier.scalability_charts_3D
>>> #
>>> # show the oemof memory results as an example:
>>> # commented out for doctesting:
>>> # scalability_3d_charts['ppsa'].memory.show()
Image showing the 3d pypsa memory results
>>> # show the pypsa timing results as an example:
>>> # commented out for doctesting:
>>> # scalability_3d_charts['ppsa'].time.show()
Image showing the 3d pypsa timing results

Integrated Global Results (IGR)

Following section demonstrate how to access the integrated global results of the models compared.

>>> # show the integrated global results of the fpwe:
>>> comparatier.integrated_global_results.drop(
...     ['time (s)', 'memory (MB)'], axis='index')
                  cllp   fine    omf   ppsa
emissions (sim)   53.0  190.0   53.0   53.0
costs (sim)      105.0  375.0  105.0  105.0
opex (ppcd)      105.0  375.0  105.0  105.0
capex (ppcd)       0.0    0.0    0.0    0.0

Memory and timing results are dropped because they vary slightly between runs. The original results look something like:

comparatier.integrated_global_results

                  cllp   fine    omf   ppsa
emissions (sim)   53.0  190.0   53.0   53.0
costs (sim)      105.0  375.0  105.0  105.0
opex (ppcd)      105.0  375.0  105.0  105.0
capex (ppcd)       0.0    0.0    0.0    0.0
time (s)           1.1    1.0    0.6    1.1
memory (MB)        1.5    1.3    0.6    1.4

Graphical Representation

>>> # show the IGR of the fpwe as bar chart
>>> # commented out for better doctesting
>>> # comparatier.draw_global_results_chart().show()
Image showing the integrated global results of the fpwe

Integrated Component Results (ICR)

Following section demonstrate how to access the integrated component results of the models compared.

>>> # access the model based integrated component results (ICR)
>>> # (type(graph) printed here for doctesting)
>>> #
>>> for model, graph in comparatier.ICR_graphs.items():
...     print(f'{model}: {type(graph)}')
cllp: <class 'tessif.transform.nxgrph.Graph'>
fine: <class 'tessif.transform.nxgrph.Graph'>
omf: <class 'tessif.transform.nxgrph.Graph'>
ppsa: <class 'tessif.transform.nxgrph.Graph'>

Graphical Representation

>>> # show the fpwe ICR of the compared models:
>>> # commented out for better doctesting
>>> # comparatier.ICR_graph_charts()['omf'].show()
Image showing the integrated component results of the oemof fpwe
>>> # comparatier.ICR_graph_charts()['ppsa'].show()
Image showing the integrated component results of the oemof fpwe

Difference Analyzation Results (DAR)

Following sections give an example on how to access the difference analyzation results of certain energy flows when comparing the model results.

>>> # show the difference analyzation results of the fpwe:
>>> load_diffs = comparatier.calculate_load_differences(
...     component='Generator',
...     flow='Powerline',
...     threshold=0.1,
... )
>>> print(load_diffs)
                     average  cllp  fine   omf  ppsa
1990-07-13 00:00:00     0.00  0.00   0.0  0.00  0.00
1990-07-13 01:00:00     1.78  0.00   7.1  0.00  0.00
1990-07-13 02:00:00     3.32  3.32   4.0  3.32  3.32

Graphical Representation

>>> # show the fpwe DAR of the flow from component 'Generator' to 'Powerline':
>>> # commented out for better doctesting
>>> chart = comparatier.draw_load_differences_chart(
...     component='Generator',
...     flow='Powerline',
...     threshold=0.1,
... )
>>> # chart.show()
Image showing the difference analysis results of the fpwe

Statistical Analyzation Results

Following sections give an example on how to access the statistical analyzation results of certain energy flows when comparing the model results.

>>> # show the difference analyzation results of the fpwe:
>>> statistical_diffs = comparatier.calculate_statistical_load_differences(
...     component='Generator',
...     flow='Powerline',
... )
>>> print(statistical_diffs.round(2))
       cllp  fine   omf  ppsa
NRMSE  0.61  1.82  0.61  0.61
NMAE   0.39  1.18  0.39  0.39
NMBE  -0.39  1.18 -0.39 -0.39

Graphical Representation

>>> # show the fpwe DAR of the flow from component 'Generator' to 'Powerline':
>>> # commented out for better doctesting
>>> chart = comparatier.draw_statistical_load_differences_chart(
...     component='Generator',
...     flow='Powerline',
... )
>>> # chart.show()
Image showing the statistical analysis results of the fpwe