Main POSTED tutorial for python¶
Prerequisits¶
Dependencies¶
First, we import some general-purpose libraries. The python-side of posted
depends on pandas
for working with dataframes. Here we also use plotly
and itables
for plotting and inspecting data, but posted
does not depend on those and other tools could be used instead. The package igraph
is an optional dependency used for representing the interlinkages in value chains. The package matplotlib
is only used for plotting igraphs, which is again optional.
import pandas as pd
import plotly
pd.options.plotting.backend = "plotly"
# for process chains only
import igraph as ig
import matplotlib.pyplot as plt
Importing POSTED¶
The posted
package has to be installed in the python environment. If it is not installed yet, you can easily install it from the GitHub source code using pip
.
try:
import posted
except ImportError:
! pip install git+https://github.com:PhilippVerpoort/posted.git@develop
Import specific functions and classes from POSTED that will be used later.
from posted.tedf import TEDF
from posted.noslag import DataSet
from posted.units import Q, U
from posted.team import CalcVariable, LCOX, FSCP, ProcessChain, annuity_factor
Use some basic plotly and pandas functions for plotting and output analysis
NOSLAG¶
Electrolysis CAPEX¶
Let's compare CAPEX data for electrolysis in years 2020–2050 for Alkaline and PEM across different sources (Danish Energy Agency, Breyer, Fraunhofer, IRENA) for different electrolyser plant sizes.
# select data from TEDFs
df_elh2 = DataSet('Tech|Electrolysis').select(
period=[2020, 2030, 2040, 2050],
subtech=['AEL', 'PEM'],
override={'Tech|Electrolysis|Output Capacity|Hydrogen': 'kW;LHV'},
source=['DEARF23', 'Vartiainen22', 'Holst21', 'IRENA22'],
size=['1 MW', '5 MW', '100 MW'],
extrapolate_period=False
).query(f"variable=='Tech|Electrolysis|CAPEX'")
# display a few examples
display(df_elh2.sample(15).sort_index())
# sort data and plot
df_elh2.assign(size_sort=lambda df: df['size'].str.split(' ', n=1, expand=True).iloc[:, 0].astype(int)) \
.sort_values(by=['size_sort', 'period']) \
.plot.line(x='period', y='value', color='source', facet_col='size', facet_row='subtech')
subtech | size | source | variable | reference_variable | region | period | unit | value | |
---|---|---|---|---|---|---|---|---|---|
0 | AEL | 1 MW | DEARF23 | Tech|Electrolysis|CAPEX | Tech|Electrolysis|Output Capacity|Hydrogen | World | 2020 | USD_2005/kW | 1121.0 |
1 | AEL | 1 MW | DEARF23 | Tech|Electrolysis|CAPEX | Tech|Electrolysis|Output Capacity|Hydrogen | World | 2030 | USD_2005/kW | 833.4 |
37 | AEL | 100 MW | DEARF23 | Tech|Electrolysis|CAPEX | Tech|Electrolysis|Output Capacity|Hydrogen | World | 2020 | USD_2005/kW | 972.3 |
38 | AEL | 100 MW | DEARF23 | Tech|Electrolysis|CAPEX | Tech|Electrolysis|Output Capacity|Hydrogen | World | 2030 | USD_2005/kW | 658.0 |
53 | AEL | 100 MW | Holst21 | Tech|Electrolysis|CAPEX | Tech|Electrolysis|Output Capacity|Hydrogen | World | 2020 | USD_2005/kW | 955.4 |
54 | AEL | 100 MW | Holst21 | Tech|Electrolysis|CAPEX | Tech|Electrolysis|Output Capacity|Hydrogen | World | 2030 | USD_2005/kW | 604.0 |
64 | AEL | 100 MW | IRENA22 | Tech|Electrolysis|CAPEX | Tech|Electrolysis|Output Capacity|Hydrogen | World | 2050 | USD_2005/kW | 236.2 |
73 | AEL | 100 MW | Vartiainen22 | Tech|Electrolysis|CAPEX | Tech|Electrolysis|Output Capacity|Hydrogen | World | 2030 | USD_2005/kW | 340.9 |
74 | AEL | 100 MW | Vartiainen22 | Tech|Electrolysis|CAPEX | Tech|Electrolysis|Output Capacity|Hydrogen | World | 2040 | USD_2005/kW | 190.7 |
96 | AEL | 5 MW | Holst21 | Tech|Electrolysis|CAPEX | Tech|Electrolysis|Output Capacity|Hydrogen | World | 2020 | USD_2005/kW | 1367.0 |
107 | AEL | 5 MW | IRENA22 | Tech|Electrolysis|CAPEX | Tech|Electrolysis|Output Capacity|Hydrogen | World | 2050 | USD_2005/kW | 236.2 |
119 | PEM | 1 MW | DEARF23 | Tech|Electrolysis|CAPEX | Tech|Electrolysis|Output Capacity|Hydrogen | World | 2020 | USD_2005/kW | 1586.0 |
121 | PEM | 1 MW | DEARF23 | Tech|Electrolysis|CAPEX | Tech|Electrolysis|Output Capacity|Hydrogen | World | 2040 | USD_2005/kW | 658.0 |
150 | PEM | 100 MW | DEARF23 | Tech|Electrolysis|CAPEX | Tech|Electrolysis|Output Capacity|Hydrogen | World | 2020 | USD_2005/kW | 1586.0 |
167 | PEM | 100 MW | Holst21 | Tech|Electrolysis|CAPEX | Tech|Electrolysis|Output Capacity|Hydrogen | World | 2030 | USD_2005/kW | 684.4 |
Based on those many sources and cases (size and subtechnology), we can now aggregate the data for further use.
DataSet('Tech|Electrolysis').aggregate(
period=[2020, 2030, 2040, 2050],
subtech=['AEL', 'PEM'],
override={'Tech|Electrolysis|Output Capacity|Hydrogen': 'kW;LHV'},
source=['DEARF23', 'Vartiainen22', 'Holst21', 'IRENA22'],
size=['1 MW', '5 MW', '100 MW'],
agg=['subtech', 'size', 'source'],
extrapolate_period=False,
).team.varsplit('Tech|Electrolysis|*variable') \
.query(f"variable.isin({['CAPEX', 'Output Capacity|Hydrogen']})")
variable | region | period | unit | value | |
---|---|---|---|---|---|
0 | CAPEX | World | 2020 | USD_2005 | 1046.0 |
1 | CAPEX | World | 2030 | USD_2005 | 737.4 |
2 | CAPEX | World | 2040 | USD_2005 | 586.1 |
3 | CAPEX | World | 2050 | USD_2005 | 499.3 |
12 | Output Capacity|Hydrogen | World | 2020 | kW | 1.0 |
13 | Output Capacity|Hydrogen | World | 2030 | kW | 1.0 |
14 | Output Capacity|Hydrogen | World | 2040 | kW | 1.0 |
15 | Output Capacity|Hydrogen | World | 2050 | kW | 1.0 |
Energy demand of green vs. blue hydrogen production¶
Next, let's compare the energy demand of methane reforming (for blue hydrogen) and different types of electrolysis (for green hydrogen).
pd.concat([
DataSet('Tech|Methane Reforming').aggregate(period=2030, source='Lewis22'),
DataSet('Tech|Electrolysis').aggregate(period=2030, agg=['source', 'size']),
]) \
.reset_index(drop=True) \
.team.varsplit('Tech|?tech|Input|?fuel') \
.assign(tech=lambda df: df.apply(lambda row: f"{row['tech']}<br>({row['subtech']})" if pd.isnull(row['capture_rate']) else f"{row['tech']}<br>({row['subtech']}, {row['capture_rate']} CR)", axis=1)) \
.plot.bar(x='tech', y='value', color='fuel') \
.update_layout(
xaxis_title='Technologies',
yaxis_title='Energy demand ( MWh<sub>LHV</sub> / MWh<sub>LHV</sub> H<sub>2</sub> )',
legend_title='Energy carriers',
)
({row['subtech']})" if pd.isnull(row['capture_rate']) else f"{row['tech']}
({row['subtech']}, {row['capture_rate']} CR)", axis=1)) \ .plot.bar(x='tech', y='value', color='fuel') \ .update_layout( xaxis_title='Technologies', yaxis_title='Energy demand ( MWhLHV / MWhLHV H2 )', legend_title='Energy carriers', )
Energy demand of iron direct reduction¶
Next, let's compare the energy demand of iron direct reduction (production of low-carbon crude iron) across sources.
DataSet('Tech|Iron Direct Reduction') \
.aggregate(period=2030, mode='h2', agg=[]) \
.team.varsplit('Tech|Iron Direct Reduction|Input|?fuel') \
.query(f"fuel != 'Iron Ore'") \
.team.varcombine('{fuel} ({component})') \
.plot.bar(x='source', y='value', color='variable') \
.update_layout(
xaxis_title='Sources',
yaxis_title='Energy demand ( MWh<sub>LHV</sub> / t<sub>DRI</sub> )',
legend_title='Energy carriers'
)
We can also compare the energy demand for operation with hydrogen or with fossil gas for only one source.
DataSet('Tech|Iron Direct Reduction') \
.select(period=2030, source='Jacobasch21') \
.team.varsplit('Tech|Iron Direct Reduction|Input|?fuel') \
.query(f"fuel.isin({['Electricity', 'Fossil Gas', 'Hydrogen']})") \
.plot.bar(x='mode', y='value', color='fuel') \
.update_layout(
xaxis_title='Mode of operation',
yaxis_title='Energy demand ( MWh<sub>LHV</sub> / t<sub>DRI</sub> )',
legend_title='Energy carriers'
)
Energy demand of Haber-Bosch synthesis¶
Finally, let's compare the energy demand of Haber-Bosch synthesis between an integrated SMR plant and a plant running on green hydrogen.
pd.concat([
DataSet('Tech|Haber-Bosch with ASU').aggregate(period=2024, agg='component'),
DataSet('Tech|Haber-Bosch with Reforming').aggregate(period=2024, agg='component')
]) \
.reset_index(drop=True) \
.team.varsplit('Tech|?tech|*variable') \
.query(f"variable.str.startswith('Input|')") \
.plot.bar(x='source', y='value', color='variable') \
.update_layout(
xaxis_title='Sources',
yaxis_title='Energy demand ( MWh<sub>LHV</sub> / t<sub>NH<sub>3</sub></sub> )',
legend_title='Energy carriers'
)
TEAM¶
CalcVariable¶
New variables can be calculated manually via the CalcVariable
class. The next example demonstrates this for calculating the levelised cost of hydrogen.
assumptions = pd.DataFrame.from_records([
{'elec_price_case': f"Case {i}", 'variable': 'Price|Electricity', 'unit': 'EUR_2020/MWh', 'value': 30 + (i-1)*25}
for i in range(1, 4)
] + [
{'variable': 'Tech|Electrolysis|OCF', 'value': 50, 'unit': 'pct'},
{'variable': 'Annuity Factor', 'value': annuity_factor(Q('5 pct'), Q('18 a')).m, 'unit': '1/a'},
])
display(assumptions)
elec_price_case | variable | unit | value | |
---|---|---|---|---|
0 | Case 1 | Price|Electricity | EUR_2020/MWh | 30.000000 |
1 | Case 2 | Price|Electricity | EUR_2020/MWh | 55.000000 |
2 | Case 3 | Price|Electricity | EUR_2020/MWh | 80.000000 |
3 | NaN | Tech|Electrolysis|OCF | pct | 50.000000 |
4 | NaN | Annuity Factor | 1/a | 0.085546 |
df_calc = pd.concat([
DataSet('Tech|Electrolysis').aggregate(period=[2030, 2040, 2050], subtech=['AEL', 'PEM'], agg=['size', 'source']),
assumptions,
]).team.perform(CalcVariable(**{
'LCOX|Green Hydrogen|Capital Cost': lambda x: (x['Annuity Factor'] * x['Tech|Electrolysis|CAPEX'] / x['Tech|Electrolysis|Output Capacity|Hydrogen'] / x['Tech|Electrolysis|OCF']),
'LCOX|Green Hydrogen|OM Cost Fixed': lambda x: x['Tech|Electrolysis|OPEX Fixed'] / x['Tech|Electrolysis|Output Capacity|Hydrogen'] / x['Tech|Electrolysis|OCF'],
'LCOX|Green Hydrogen|Input Cost|Electricity': lambda x: x['Price|Electricity'] * x['Tech|Electrolysis|Input|Electricity'] / x['Tech|Electrolysis|Output|Hydrogen'],
}), only_new=True) \
.team.unit_convert(to='EUR_2020/MWh')
display(df_calc.sample(15).sort_index())
subtech | region | period | elec_price_case | variable | value | unit | |
---|---|---|---|---|---|---|---|
1 | AEL | World | 2030.0 | Case 2 | LCOX|Green Hydrogen|Capital Cost | 12.824046 | EUR_2020/MWh |
10 | PEM | World | 2030.0 | Case 2 | LCOX|Green Hydrogen|Capital Cost | 19.839159 | EUR_2020/MWh |
12 | PEM | World | 2040.0 | Case 1 | LCOX|Green Hydrogen|Capital Cost | 17.258175 | EUR_2020/MWh |
13 | PEM | World | 2040.0 | Case 2 | LCOX|Green Hydrogen|Capital Cost | 17.258175 | EUR_2020/MWh |
19 | AEL | World | 2030.0 | Case 2 | LCOX|Green Hydrogen|OM Cost Fixed | 5.247678 | EUR_2020/MWh |
21 | AEL | World | 2040.0 | Case 1 | LCOX|Green Hydrogen|OM Cost Fixed | 4.887642 | EUR_2020/MWh |
22 | AEL | World | 2040.0 | Case 2 | LCOX|Green Hydrogen|OM Cost Fixed | 4.887642 | EUR_2020/MWh |
25 | AEL | World | 2050.0 | Case 2 | LCOX|Green Hydrogen|OM Cost Fixed | 4.670413 | EUR_2020/MWh |
31 | PEM | World | 2040.0 | Case 2 | LCOX|Green Hydrogen|OM Cost Fixed | 5.901375 | EUR_2020/MWh |
37 | AEL | World | 2030.0 | Case 2 | LCOX|Green Hydrogen|Input Cost|Electricity | 82.170000 | EUR_2020/MWh |
39 | AEL | World | 2040.0 | Case 1 | LCOX|Green Hydrogen|Input Cost|Electricity | 43.830000 | EUR_2020/MWh |
43 | AEL | World | 2050.0 | Case 2 | LCOX|Green Hydrogen|Input Cost|Electricity | 78.760000 | EUR_2020/MWh |
45 | PEM | World | 2030.0 | Case 1 | LCOX|Green Hydrogen|Input Cost|Electricity | 45.690000 | EUR_2020/MWh |
50 | PEM | World | 2040.0 | Case 3 | LCOX|Green Hydrogen|Input Cost|Electricity | 120.560000 | EUR_2020/MWh |
52 | PEM | World | 2050.0 | Case 2 | LCOX|Green Hydrogen|Input Cost|Electricity | 81.950000 | EUR_2020/MWh |
df_calc.team.varsplit('LCOX|Green Hydrogen|?component') \
.sort_values(by=['elec_price_case', 'value']) \
.plot.bar(x='period', y='value', color='component', facet_col='elec_price_case', facet_row='subtech')
Pivot¶
POSTED uses the pivot
dataframe method to bring the data into a usable format.
pd.concat([
DataSet('Tech|Electrolysis').aggregate(period=[2030, 2040, 2050], subtech=['AEL', 'PEM'], agg=['size', 'source']),
assumptions,
]).team.pivot_wide().pint.dequantify()
variable | Tech|Electrolysis|CAPEX | Tech|Electrolysis|Input|Electricity | Tech|Electrolysis|Input|Water | Tech|Electrolysis|OPEX Fixed | Tech|Electrolysis|Output Capacity|Hydrogen | Tech|Electrolysis|Output|Hydrogen | Tech|Electrolysis|Total Input Capacity|Electricity | Tech|Electrolysis|Total Output Capacity|Hydrogen | Price|Electricity | Tech|Electrolysis|OCF | Annuity Factor | |||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
unit | USD_2005 | MWh | t | USD_2005/a | MWh/a | MWh | MWh/a | MWh/a | EUR_2020/MWh | pct | 1/a | |||
subtech | region | period | elec_price_case | |||||||||||
AEL | World | 2030.0 | Case 1 | 74.53 | 1.494 | 0.2848 | 2.609 | 1.0 | 1.0 | 309500.0 | 3179000.0 | 30.0 | 50.0 | 0.085546 |
Case 2 | 74.53 | 1.494 | 0.2848 | 2.609 | 1.0 | 1.0 | 309500.0 | 3179000.0 | 55.0 | 50.0 | 0.085546 | |||
Case 3 | 74.53 | 1.494 | 0.2848 | 2.609 | 1.0 | 1.0 | 309500.0 | 3179000.0 | 80.0 | 50.0 | 0.085546 | |||
2040.0 | Case 1 | 59.19 | 1.461 | 0.2848 | 2.430 | 1.0 | 1.0 | 309500.0 | 3179000.0 | 30.0 | 50.0 | 0.085546 | ||
Case 2 | 59.19 | 1.461 | 0.2848 | 2.430 | 1.0 | 1.0 | 309500.0 | 3179000.0 | 55.0 | 50.0 | 0.085546 | |||
Case 3 | 59.19 | 1.461 | 0.2848 | 2.430 | 1.0 | 1.0 | 309500.0 | 3179000.0 | 80.0 | 50.0 | 0.085546 | |||
2050.0 | Case 1 | 47.46 | 1.432 | 0.2848 | 2.322 | 1.0 | 1.0 | 309500.0 | 3179000.0 | 30.0 | 50.0 | 0.085546 | ||
Case 2 | 47.46 | 1.432 | 0.2848 | 2.322 | 1.0 | 1.0 | 309500.0 | 3179000.0 | 55.0 | 50.0 | 0.085546 | |||
Case 3 | 47.46 | 1.432 | 0.2848 | 2.322 | 1.0 | 1.0 | 309500.0 | 3179000.0 | 80.0 | 50.0 | 0.085546 | |||
PEM | World | 2030.0 | Case 1 | 115.30 | 1.523 | 0.2850 | 3.621 | 1.0 | 1.0 | 309500.0 | 3179000.0 | 30.0 | 50.0 | 0.085546 |
Case 2 | 115.30 | 1.523 | 0.2850 | 3.621 | 1.0 | 1.0 | 309500.0 | 3179000.0 | 55.0 | 50.0 | 0.085546 | |||
Case 3 | 115.30 | 1.523 | 0.2850 | 3.621 | 1.0 | 1.0 | 309500.0 | 3179000.0 | 80.0 | 50.0 | 0.085546 | |||
2040.0 | Case 1 | 100.30 | 1.507 | 0.2850 | 2.934 | 1.0 | 1.0 | 309500.0 | 3179000.0 | 30.0 | 50.0 | 0.085546 | ||
Case 2 | 100.30 | 1.507 | 0.2850 | 2.934 | 1.0 | 1.0 | 309500.0 | 3179000.0 | 55.0 | 50.0 | 0.085546 | |||
Case 3 | 100.30 | 1.507 | 0.2850 | 2.934 | 1.0 | 1.0 | 309500.0 | 3179000.0 | 80.0 | 50.0 | 0.085546 | |||
2050.0 | Case 1 | 96.00 | 1.490 | 0.2850 | 2.737 | 1.0 | 1.0 | 309500.0 | 3179000.0 | 30.0 | 50.0 | 0.085546 | ||
Case 2 | 96.00 | 1.490 | 0.2850 | 2.737 | 1.0 | 1.0 | 309500.0 | 3179000.0 | 55.0 | 50.0 | 0.085546 | |||
Case 3 | 96.00 | 1.490 | 0.2850 | 2.737 | 1.0 | 1.0 | 309500.0 | 3179000.0 | 80.0 | 50.0 | 0.085546 |
LCOX of blue and green hydrogen¶
POSTED also contains predefined methods for calculating LCOX. Here we apply it to blue and green hydrogen.
df_lcox_bluegreen = pd.concat([
pd.DataFrame.from_records([
{'elec_price_case': f"Case {i}", 'variable': 'Price|Electricity', 'unit': 'EUR_2020/MWh', 'value': 30 + (i-1)*25}
for i in range(1, 4)
]),
pd.DataFrame.from_records([
{'ng_price_case': 'High' if i-1 else 'Low', 'variable': 'Price|Fossil Gas', 'unit': 'EUR_2020/MWh', 'value': 40 if i-1 else 20}
for i in range(1, 3)
]),
DataSet('Tech|Electrolysis').aggregate(period=2030, subtech=['AEL', 'PEM'], agg=['size', 'subtech', 'source']),
DataSet('Tech|Methane Reforming').aggregate(period=2030, capture_rate=['55.70%', '94.50%'])
.team.varsplit('Tech|Methane Reforming|*comp')
.team.varcombine('{variable} {subtech} ({capture_rate})|{comp}')
]) \
.team.perform(
LCOX('Output|Hydrogen', 'Electrolysis', name='Green Hydrogen', interest_rate=0.1, book_lifetime=18),
LCOX('Output|Hydrogen', 'Methane Reforming SMR (55.70%)', name='Blue Hydrogen (Low CR)', interest_rate=0.1, book_lifetime=18),
LCOX('Output|Hydrogen', 'Methane Reforming ATR (94.50%)', name='Blue Hydrogen (High CR)', interest_rate=0.1, book_lifetime=18),
only_new=True,
) \
.team.unit_convert(to='EUR_2022/MWh')
display(df_lcox_bluegreen)
/home/philippv/Documents/4-projects/10-posted/01-vcs/posted/python/posted/team.py:582: UserWarning: The following inputs/outputs are not used in LCOX, because they are neither the reference nor is an associated price given: Input|Water
elec_price_case | ng_price_case | region | period | variable | value | unit | |
---|---|---|---|---|---|---|---|
0 | Case 1 | High | World | 2030.0 | LCOX|Green Hydrogen|Capital | 11.746556 | EUR_2022/MWh |
1 | Case 1 | Low | World | 2030.0 | LCOX|Green Hydrogen|Capital | 11.746556 | EUR_2022/MWh |
2 | Case 2 | High | World | 2030.0 | LCOX|Green Hydrogen|Capital | 11.746556 | EUR_2022/MWh |
3 | Case 2 | Low | World | 2030.0 | LCOX|Green Hydrogen|Capital | 11.746556 | EUR_2022/MWh |
4 | Case 3 | High | World | 2030.0 | LCOX|Green Hydrogen|Capital | 11.746556 | EUR_2022/MWh |
... | ... | ... | ... | ... | ... | ... | ... |
73 | Case 1 | Low | World | 2030.0 | LCOX|Blue Hydrogen (High CR)|Input Cost|Fossil... | 30.112121 | EUR_2022/MWh |
74 | Case 2 | High | World | 2030.0 | LCOX|Blue Hydrogen (High CR)|Input Cost|Fossil... | 60.224242 | EUR_2022/MWh |
75 | Case 2 | Low | World | 2030.0 | LCOX|Blue Hydrogen (High CR)|Input Cost|Fossil... | 30.112121 | EUR_2022/MWh |
76 | Case 3 | High | World | 2030.0 | LCOX|Blue Hydrogen (High CR)|Input Cost|Fossil... | 60.224242 | EUR_2022/MWh |
77 | Case 3 | Low | World | 2030.0 | LCOX|Blue Hydrogen (High CR)|Input Cost|Fossil... | 30.112121 | EUR_2022/MWh |
78 rows × 7 columns
df_lcox_bluegreen.team.varsplit('LCOX|?fuel|*comp') \
.plot.bar(x='fuel', y='value', color='comp', facet_col='elec_price_case', facet_row='ng_price_case')
LCOX of methanol¶
Let's calculate the levelised cost of green methanol (from electrolytic hydrogen). First we can do this simply based on a hydrogen price (i.e. without accounting for electrolysis).
df_lcox_meoh = pd.concat([
DataSet('Tech|Methanol Synthesis').aggregate(period=[2030, 2050]),
pd.DataFrame.from_records([
{'period': 2030, 'variable': 'Price|Hydrogen', 'unit': 'EUR_2022/MWh', 'value': 120},
{'period': 2050, 'variable': 'Price|Hydrogen', 'unit': 'EUR_2022/MWh', 'value': 80},
{'period': 2030, 'variable': 'Price|Captured CO2', 'unit': 'EUR_2022/t', 'value': 150},
{'period': 2050, 'variable': 'Price|Captured CO2', 'unit': 'EUR_2022/t', 'value': 100},
]),
]) \
.team.perform(LCOX(
'Output|Methanol', 'Methanol Synthesis', name='Green Methanol',
interest_rate=0.1, book_lifetime=10.0), only_new=True,
) \
.team.unit_convert('EUR_2022/MWh')
display(df_lcox_meoh)
/home/philippv/Documents/4-projects/10-posted/01-vcs/posted/python/posted/noslag.py:368: UserWarning: Unknown variable, so dropping rows: 36 Emissions|CO2 37 Emissions|CO2 Name: variable, dtype: object
/home/philippv/Documents/4-projects/10-posted/01-vcs/posted/python/posted/team.py:582: UserWarning: The following inputs/outputs are not used in LCOX, because they are neither the reference nor is an associated price given: Output|Heat
region | period | variable | value | unit | |
---|---|---|---|---|---|
0 | World | 2030 | LCOX|Green Methanol|Capital | 10.583450 | EUR_2022/MWh |
1 | World | 2050 | LCOX|Green Methanol|Capital | 9.831386 | EUR_2022/MWh |
2 | World | 2030 | LCOX|Green Methanol|OM Fixed | 3.231184 | EUR_2022/MWh |
3 | World | 2050 | LCOX|Green Methanol|OM Fixed | 2.984565 | EUR_2022/MWh |
4 | World | 2030 | LCOX|Green Methanol|OM Variable | 3.385836 | EUR_2022/MWh |
5 | World | 2050 | LCOX|Green Methanol|OM Variable | 3.385836 | EUR_2022/MWh |
6 | World | 2030 | LCOX|Green Methanol|Input Cost|Captured CO2 | 38.355000 | EUR_2022/MWh |
7 | World | 2050 | LCOX|Green Methanol|Input Cost|Captured CO2 | 25.570000 | EUR_2022/MWh |
8 | World | 2030 | LCOX|Green Methanol|Input Cost|Hydrogen | 140.760000 | EUR_2022/MWh |
9 | World | 2050 | LCOX|Green Methanol|Input Cost|Hydrogen | 93.840000 | EUR_2022/MWh |
df_lcox_meoh.team.varsplit('LCOX|Green Methanol|*component') \
.plot.bar(x='period', y='value', color='component')
Next, we can calculate the LCOX of green methanol for a the value chain consisting of electrolysis, low-temperature direct air capture, and methanol synthesis. The heat for the direct air capture will be provided by an industrial heat pump.
pc_green_meoh = ProcessChain(
'Green Methanol',
{'Methanol Synthesis': {'Methanol': Q('1 MWh')}},
'Heatpump for DAC -> Heat => Direct Air Capture -> Captured CO2 => Methanol Synthesis;Electrolysis -> Hydrogen => Methanol Synthesis -> Methanol',
)
g, lay = pc_green_meoh.igraph()
fig, ax = plt.subplots()
ax.set_title(pc_green_meoh.name)
ig.plot(g, target=ax, layout=lay, vertex_label=[n.replace(' ', '\n') for n in g.vs['name']], edge_label=[n.replace(' ', '\n') for n in g.es['name']], vertex_label_size=8, edge_label_size=6)
<igraph.drawing.matplotlib.graph.GraphArtist at 0x77a690c46a40>
df_lcox_meoh_pc = pd.concat([
DataSet('Tech|Electrolysis').aggregate(period=[2030, 2050], subtech=['AEL', 'PEM'], size=['1 MW', '100 MW'], agg=['subtech', 'size', 'source']),
DataSet('Tech|Direct Air Capture').aggregate(period=[2030, 2050], subtech='LT-DAC'),
DataSet('Tech|Heatpump for DAC').aggregate(period=[2030, 2050]),
DataSet('Tech|Methanol Synthesis').aggregate(period=[2030, 2050]),
pd.DataFrame.from_records([
{'period': 2030, 'variable': 'Price|Electricity', 'unit': 'EUR_2022/MWh', 'value': 50},
{'period': 2050, 'variable': 'Price|Electricity', 'unit': 'EUR_2022/MWh', 'value': 30},
]),
]) \
.team.perform(pc_green_meoh) \
.team.perform(LCOX(
'Methanol Synthesis|Output|Methanol', process_chain='Green Methanol',
interest_rate=0.1, book_lifetime=10.0,
), only_new=True) \
.team.unit_convert('EUR_2022/MWh')
display(df_lcox_meoh_pc)
/home/philippv/Documents/4-projects/10-posted/01-vcs/posted/python/posted/noslag.py:368: UserWarning: Unknown variable, so dropping rows: 36 Emissions|CO2 37 Emissions|CO2 Name: variable, dtype: object
/home/philippv/Documents/4-projects/10-posted/01-vcs/posted/.venv/lib/python3.10/site-packages/pandas/core/dtypes/cast.py:1601: UnitStrippedWarning: The unit of the quantity is stripped when downcasting to ndarray. /home/philippv/Documents/4-projects/10-posted/01-vcs/posted/python/posted/team.py:582: UserWarning: The following inputs/outputs are not used in LCOX, because they are neither the reference nor is an associated price given: Input|Heat, Output|Captured CO2 /home/philippv/Documents/4-projects/10-posted/01-vcs/posted/python/posted/team.py:582: UserWarning: The following inputs/outputs are not used in LCOX, because they are neither the reference nor is an associated price given: Input|Water, Output|Hydrogen /home/philippv/Documents/4-projects/10-posted/01-vcs/posted/python/posted/team.py:582: UserWarning: The following inputs/outputs are not used in LCOX, because they are neither the reference nor is an associated price given: Output|Heat /home/philippv/Documents/4-projects/10-posted/01-vcs/posted/python/posted/team.py:582: UserWarning: The following inputs/outputs are not used in LCOX, because they are neither the reference nor is an associated price given: Input|Captured CO2, Input|Hydrogen, Output|Heat, Output|Methanol
region | period | variable | value | unit | |
---|---|---|---|---|---|
0 | World | 2030 | LCOX|Green Methanol|Direct Air Capture|OM Fixed | 6.333591 | EUR_2022/MWh |
1 | World | 2050 | LCOX|Green Methanol|Direct Air Capture|OM Fixed | 5.237687 | EUR_2022/MWh |
2 | World | 2030 | LCOX|Green Methanol|Direct Air Capture|OM Vari... | 11.528534 | EUR_2022/MWh |
3 | World | 2050 | LCOX|Green Methanol|Direct Air Capture|OM Vari... | 11.528534 | EUR_2022/MWh |
4 | World | 2030 | LCOX|Green Methanol|Direct Air Capture|Input C... | 13.206905 | EUR_2022/MWh |
5 | World | 2050 | LCOX|Green Methanol|Direct Air Capture|Input C... | 7.924143 | EUR_2022/MWh |
6 | World | 2030 | LCOX|Green Methanol|Electrolysis|Capital | 16.639994 | EUR_2022/MWh |
7 | World | 2050 | LCOX|Green Methanol|Electrolysis|Capital | 10.030329 | EUR_2022/MWh |
8 | World | 2030 | LCOX|Green Methanol|Electrolysis|OM Fixed | 4.045965 | EUR_2022/MWh |
9 | World | 2050 | LCOX|Green Methanol|Electrolysis|OM Fixed | 3.059801 | EUR_2022/MWh |
10 | World | 2030 | LCOX|Green Methanol|Electrolysis|Input Cost|El... | 87.623100 | EUR_2022/MWh |
11 | World | 2050 | LCOX|Green Methanol|Electrolysis|Input Cost|El... | 50.603220 | EUR_2022/MWh |
12 | World | 2030 | LCOX|Green Methanol|Heatpump for DAC|Capital | 8.246405 | EUR_2022/MWh |
13 | World | 2050 | LCOX|Green Methanol|Heatpump for DAC|Capital | 7.408040 | EUR_2022/MWh |
14 | World | 2030 | LCOX|Green Methanol|Heatpump for DAC|OM Fixed | 1.013412 | EUR_2022/MWh |
15 | World | 2050 | LCOX|Green Methanol|Heatpump for DAC|OM Fixed | 0.910103 | EUR_2022/MWh |
16 | World | 2030 | LCOX|Green Methanol|Heatpump for DAC|OM Variable | 1.279063 | EUR_2022/MWh |
17 | World | 2050 | LCOX|Green Methanol|Heatpump for DAC|OM Variable | 1.203866 | EUR_2022/MWh |
18 | World | 2030 | LCOX|Green Methanol|Heatpump for DAC|Input Cos... | 0.009858 | EUR_2022/MWh |
19 | World | 2050 | LCOX|Green Methanol|Heatpump for DAC|Input Cos... | 0.005494 | EUR_2022/MWh |
20 | World | 2030 | LCOX|Green Methanol|Methanol Synthesis|Capital | 10.583450 | EUR_2022/MWh |
21 | World | 2050 | LCOX|Green Methanol|Methanol Synthesis|Capital | 9.831386 | EUR_2022/MWh |
22 | World | 2030 | LCOX|Green Methanol|Methanol Synthesis|OM Fixed | 3.231184 | EUR_2022/MWh |
23 | World | 2050 | LCOX|Green Methanol|Methanol Synthesis|OM Fixed | 2.984565 | EUR_2022/MWh |
24 | World | 2030 | LCOX|Green Methanol|Methanol Synthesis|OM Vari... | 3.385836 | EUR_2022/MWh |
25 | World | 2050 | LCOX|Green Methanol|Methanol Synthesis|OM Vari... | 3.385836 | EUR_2022/MWh |
df_lcox_meoh_pc.team.varsplit('LCOX|Green Methanol|?process|*component') \
.plot.bar(x='period', y='value', color='component', hover_data='process')
LCOX of green ethylene (from green methanol)¶
pc_green_ethylene = ProcessChain(
'Green Ethylene',
{'Electric Arc Furnace': {'Ethylene': Q('1t')}},
'Electrolysis -> Hydrogen => Methanol Synthesis; Heatpump for DAC -> Heat => Direct Air Capture -> Captured CO2 => Methanol Synthesis -> Methanol => Methanol to Olefines -> Ethylene',
)
g, lay = pc_green_ethylene.igraph()
fig, ax = plt.subplots()
ax.set_title(pc_green_ethylene.name)
ig.plot(g, target=ax, layout=lay, vertex_label=[n.replace(' ', '\n') for n in g.vs['name']], edge_label=[n.replace(' ', '\n') for n in g.es['name']], vertex_label_size=8, edge_label_size=6)
<igraph.drawing.matplotlib.graph.GraphArtist at 0x77a69275c910>
LCOX of green steel¶
pc_green_steel = ProcessChain(
'Green Steel (H2-DR)',
{'Steel Hot Rolling': {'Steel Hot-rolled Coil': Q('1t')}},
'Electrolysis -> Hydrogen => Iron Direct Reduction -> Directly Reduced Iron => Electric Arc Furnace -> Steel Liquid => Steel Casting -> Steel Slab => Steel Hot Rolling -> Steel Hot-rolled Coil',
)
g, lay = pc_green_steel.igraph()
fig, ax = plt.subplots()
ax.set_title(pc_green_steel.name)
ig.plot(g, target=ax, layout=lay, vertex_label=[n.replace(' ', '\n') for n in g.vs['name']], edge_label=[n.replace(' ', '\n') for n in g.es['name']], vertex_label_size=8, edge_label_size=6)
<igraph.drawing.matplotlib.graph.GraphArtist at 0x77a6927b2ec0>
df_lcox_green_steel = pd.concat([
DataSet('Tech|Electrolysis').aggregate(period=2030, subtech=['AEL', 'PEM'], size=['1 MW', '100 MW'], agg=['subtech', 'size', 'source'], override={'Tech|ELH2|Output Capacity|Hydrogen': 'kW;LHV'}),
DataSet('Tech|Iron Direct Reduction').aggregate(period=2030, mode='h2'),
DataSet('Tech|Electric Arc Furnace').aggregate(period=2030, mode='Primary'),
DataSet('Tech|Steel Casting').aggregate(period=2030),
DataSet('Tech|Steel Hot Rolling').aggregate(period=2030),
pd.DataFrame({'price_case': range(30, 60, 10), 'variable': 'Price|Electricity', 'unit': 'EUR_2020/MWh', 'value': range(30, 60, 10)}),
]) \
.team.perform(pc_green_steel) \
.team.perform(LCOX(
'Steel Hot Rolling|Output|Steel Hot-rolled Coil', process_chain='Green Steel (H2-DR)',
interest_rate=0.1, book_lifetime=10.0,
), only_new=True) \
.team.unit_convert('EUR_2022/t')
display(df_lcox_green_steel)
/home/philippv/Documents/4-projects/10-posted/01-vcs/posted/python/posted/noslag.py:651: HarmoniseMappingFailure: No OCF value matching a OPEX Fixed Specific value found. period reheating component region \ 73 2030 w/ reheating Labour World variable \ 73 Tech|Electric Arc Furnace|OPEX Fixed Specific reference_variable source value 73 Tech|Electric Arc Furnace|Output|Steel Liquid Vogl18 62.628147 /home/philippv/Documents/4-projects/10-posted/01-vcs/posted/python/posted/noslag.py:651: HarmoniseMappingFailure: No OCF value matching a OPEX Fixed Specific value found. period reheating component region \ 74 2030 w/o reheating Labour World variable \ 74 Tech|Electric Arc Furnace|OPEX Fixed Specific reference_variable source value 74 Tech|Electric Arc Furnace|Output|Steel Liquid Vogl18 62.628147
/home/philippv/Documents/4-projects/10-posted/01-vcs/posted/.venv/lib/python3.10/site-packages/pandas/core/dtypes/cast.py:1601: UnitStrippedWarning: The unit of the quantity is stripped when downcasting to ndarray. /home/philippv/Documents/4-projects/10-posted/01-vcs/posted/python/posted/team.py:582: UserWarning: The following inputs/outputs are not used in LCOX, because they are neither the reference nor is an associated price given: Input|Alloys, Input|Coal, Input|Directly Reduced Iron, Input|Fossil Gas, Input|Graphite Electrode, Input|Heat, Input|Lime, Input|Nitrogen, Input|Oxygen, Input|Steel Scrap, Output|Steel Liquid /home/philippv/Documents/4-projects/10-posted/01-vcs/posted/python/posted/team.py:582: UserWarning: The following inputs/outputs are not used in LCOX, because they are neither the reference nor is an associated price given: Input|Water, Output|Hydrogen /home/philippv/Documents/4-projects/10-posted/01-vcs/posted/python/posted/team.py:582: UserWarning: The following inputs/outputs are not used in LCOX, because they are neither the reference nor is an associated price given: Input|Fossil Gas, Input|Heat, Input|Hydrogen, Input|Iron Ore, Output|Directly Reduced Iron /home/philippv/Documents/4-projects/10-posted/01-vcs/posted/python/posted/team.py:582: UserWarning: The following inputs/outputs are not used in LCOX, because they are neither the reference nor is an associated price given: Input|Heat, Input|Steel Liquid, Output|Steel Slab /home/philippv/Documents/4-projects/10-posted/01-vcs/posted/python/posted/team.py:582: UserWarning: The following inputs/outputs are not used in LCOX, because they are neither the reference nor is an associated price given: Input|Heat, Input|Steel Slab, Output|Steel Hot-rolled Coil
region | period | reheating | price_case | variable | value | unit | |
---|---|---|---|---|---|---|---|
0 | World | 2030.0 | w/ reheating | 30.0 | LCOX|Green Steel (H2-DR)|Electric Arc Furnace|... | 51.314770 | EUR_2022/t |
1 | World | 2030.0 | w/ reheating | 40.0 | LCOX|Green Steel (H2-DR)|Electric Arc Furnace|... | 51.314770 | EUR_2022/t |
2 | World | 2030.0 | w/ reheating | 50.0 | LCOX|Green Steel (H2-DR)|Electric Arc Furnace|... | 51.314770 | EUR_2022/t |
3 | World | 2030.0 | w/o reheating | 30.0 | LCOX|Green Steel (H2-DR)|Electric Arc Furnace|... | 51.314770 | EUR_2022/t |
4 | World | 2030.0 | w/o reheating | 40.0 | LCOX|Green Steel (H2-DR)|Electric Arc Furnace|... | 51.314770 | EUR_2022/t |
... | ... | ... | ... | ... | ... | ... | ... |
79 | World | 2030.0 | w/ reheating | 40.0 | LCOX|Green Steel (H2-DR)|Steel Hot Rolling|Inp... | 4.101336 | EUR_2022/t |
80 | World | 2030.0 | w/ reheating | 50.0 | LCOX|Green Steel (H2-DR)|Steel Hot Rolling|Inp... | 5.126670 | EUR_2022/t |
81 | World | 2030.0 | w/o reheating | 30.0 | LCOX|Green Steel (H2-DR)|Steel Hot Rolling|Inp... | 3.076002 | EUR_2022/t |
82 | World | 2030.0 | w/o reheating | 40.0 | LCOX|Green Steel (H2-DR)|Steel Hot Rolling|Inp... | 4.101336 | EUR_2022/t |
83 | World | 2030.0 | w/o reheating | 50.0 | LCOX|Green Steel (H2-DR)|Steel Hot Rolling|Inp... | 5.126670 | EUR_2022/t |
84 rows × 7 columns
df_lcox_green_steel.team.varsplit('LCOX|Green Steel (H2-DR)|?process|*component') \
.plot.bar(x='price_case', y='value', color='component', hover_data='process', facet_col='reheating')
LCOX of cement w/ and w/o CC¶
df_lcox_cement = pd.concat([
DataSet('Tech|Cement Production').aggregate(period=2030),
pd.DataFrame.from_records([
{'variable': 'Price|Electricity', 'unit': 'EUR_2022/MWh', 'value': 50},
{'variable': 'Price|Coal', 'unit': 'EUR_2022/GJ', 'value': 3},
{'variable': 'Price|Oxygen', 'unit': 'EUR_2022/t', 'value': 30},
{'variable': 'Price|Captured CO2', 'unit': 'EUR_2022/t', 'value': -30},
]),
]) \
.team.perform(LCOX(
'Output|Cement', 'Cement Production',
interest_rate=0.1, book_lifetime=10.0,
), only_new=True) \
.team.unit_convert('EUR_2022/t')
display(df_lcox_cement)
/home/philippv/Documents/4-projects/10-posted/01-vcs/posted/python/posted/noslag.py:368: UserWarning: Unknown variable, so dropping rows: 37 Emissions|CO2 38 Emissions|CO2 39 Emissions|CO2 40 Emissions|CO2 41 Emissions|CO2 42 Emissions|CO2 43 Emissions|CO2 44 Emissions|CO2 Name: variable, dtype: object
subtech | region | period | variable | value | unit | |
---|---|---|---|---|---|---|
0 | Integrated CaL (w/ CC) | World | 2030.0 | LCOX|Cement Production|Capital | 65.362053 | EUR_2022/t |
1 | Standard (w/o CC) | World | 2030.0 | LCOX|Cement Production|Capital | 31.433808 | EUR_2022/t |
2 | Tail-end CaL 20% IL (w/ CC) | World | 2030.0 | LCOX|Cement Production|Capital | 67.076978 | EUR_2022/t |
3 | Tail-end CaL 50% IL (w/ CC) | World | 2030.0 | LCOX|Cement Production|Capital | 62.653250 | EUR_2022/t |
4 | Integrated CaL (w/ CC) | World | 2030.0 | LCOX|Cement Production|OM Variable | 34.077011 | EUR_2022/t |
5 | Standard (w/o CC) | World | 2030.0 | LCOX|Cement Production|OM Variable | 22.564951 | EUR_2022/t |
6 | Tail-end CaL 20% IL (w/ CC) | World | 2030.0 | LCOX|Cement Production|OM Variable | 34.306596 | EUR_2022/t |
7 | Tail-end CaL 50% IL (w/ CC) | World | 2030.0 | LCOX|Cement Production|OM Variable | 33.125872 | EUR_2022/t |
8 | Integrated CaL (w/ CC) | World | 2030.0 | LCOX|Cement Production|Input Cost|Coal | 11.998800 | EUR_2022/t |
9 | Standard (w/o CC) | World | 2030.0 | LCOX|Cement Production|Input Cost|Coal | 7.147440 | EUR_2022/t |
10 | Tail-end CaL 20% IL (w/ CC) | World | 2030.0 | LCOX|Cement Production|Input Cost|Coal | 19.234800 | EUR_2022/t |
11 | Tail-end CaL 50% IL (w/ CC) | World | 2030.0 | LCOX|Cement Production|Input Cost|Coal | 15.660000 | EUR_2022/t |
12 | Integrated CaL (w/ CC) | World | 2030.0 | LCOX|Cement Production|Input Cost|Electricity | 6.395000 | EUR_2022/t |
13 | Standard (w/o CC) | World | 2030.0 | LCOX|Cement Production|Input Cost|Electricity | 4.838000 | EUR_2022/t |
14 | Tail-end CaL 20% IL (w/ CC) | World | 2030.0 | LCOX|Cement Production|Input Cost|Electricity | NaN | EUR_2022/t |
15 | Tail-end CaL 50% IL (w/ CC) | World | 2030.0 | LCOX|Cement Production|Input Cost|Electricity | 2.121500 | EUR_2022/t |
16 | Integrated CaL (w/ CC) | World | 2030.0 | LCOX|Cement Production|Input Cost|Oxygen | 8.382000 | EUR_2022/t |
17 | Standard (w/o CC) | World | 2030.0 | LCOX|Cement Production|Input Cost|Oxygen | 11.250000 | EUR_2022/t |
18 | Tail-end CaL 20% IL (w/ CC) | World | 2030.0 | LCOX|Cement Production|Input Cost|Oxygen | 11.250000 | EUR_2022/t |
19 | Tail-end CaL 50% IL (w/ CC) | World | 2030.0 | LCOX|Cement Production|Input Cost|Oxygen | 9.705000 | EUR_2022/t |
20 | Integrated CaL (w/ CC) | World | 2030.0 | LCOX|Cement Production|Output Revenue|Captured... | 21.996000 | EUR_2022/t |
21 | Standard (w/o CC) | World | 2030.0 | LCOX|Cement Production|Output Revenue|Captured... | 0.000000 | EUR_2022/t |
22 | Tail-end CaL 20% IL (w/ CC) | World | 2030.0 | LCOX|Cement Production|Output Revenue|Captured... | 27.720000 | EUR_2022/t |
23 | Tail-end CaL 50% IL (w/ CC) | World | 2030.0 | LCOX|Cement Production|Output Revenue|Captured... | 25.488000 | EUR_2022/t |
24 | Integrated CaL (w/ CC) | World | 2030.0 | LCOX|Cement Production|Output Revenue|Electricity | NaN | EUR_2022/t |
25 | Standard (w/o CC) | World | 2030.0 | LCOX|Cement Production|Output Revenue|Electricity | NaN | EUR_2022/t |
26 | Tail-end CaL 20% IL (w/ CC) | World | 2030.0 | LCOX|Cement Production|Output Revenue|Electricity | -4.055000 | EUR_2022/t |
27 | Tail-end CaL 50% IL (w/ CC) | World | 2030.0 | LCOX|Cement Production|Output Revenue|Electricity | NaN | EUR_2022/t |
We first sort the dataframe by total LCOX for each subtech.
df_lcox_cement.team.varsplit('?variable|?process|*component') \
.groupby('subtech') \
.apply(lambda df: df.assign(order=df['value'].sum()), include_groups=False) \
.sort_values(by='order') \
.reset_index() \
.plot.bar(x='subtech', y='value', color='component', hover_data='process')