Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

New techs/chemical energy carriers by @euronion #32

Closed
wants to merge 41 commits into from
Closed
Show file tree
Hide file tree
Changes from 40 commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
1f0c26a
Add desalination (SWRO) and clean water tank costs.
euronion Dec 15, 2020
1ea2a3e
Add inflation adjustment method and adjust desalination and clean wat…
euronion Dec 15, 2020
d855b64
Typo
euronion Dec 15, 2020
003fc7f
Unit consistency.
euronion Dec 15, 2020
481833d
Typo + unit consistency.
euronion Dec 15, 2020
cc327c9
Add industrial heat pump (HT heatpump) for medium process temperatures.
euronion Dec 17, 2020
830e784
Allow for manual input via csv file.
euronion Dec 18, 2020
a53d427
Add pipeline and compressors for CH4 (g), H2 (g).
euronion Jan 11, 2021
a0ab213
Update output .csv files for changed technology data.
euronion Jan 11, 2021
03d9dc6
House keeping: 'Investment' -> 'investment'.
euronion Jan 11, 2021
161a055
Housekeeping: 'Lifetime' -> 'lifetime'.
euronion Jan 11, 2021
8ecc7e3
Add H2 (l) shipping, liquefaction and evaporation.
euronion Jan 18, 2021
33e7fd8
Add shipping for CH4 (l), NH3 (l), LOHC and MeOH.
euronion Jan 19, 2021
3d44225
Add NH3 production: Haber-Bosch synthesis and air separation unit.
euronion Jan 22, 2021
1acbc43
Add LOHC liquid costs and correct currency year for Runge et al 2020.
euronion Jan 23, 2021
dc441a7
Add costs for LOHC (DBT) hydrogenation and dehydrogenation.
euronion Jan 23, 2021
63cbdcc
Convert unit of LOHC deyhdrogenation cost from MW_out to t_in .
euronion Jan 24, 2021
bc94d8c
Update compile_cost_assumptions.py
euronion Feb 3, 2021
4a009d6
Add methanolisation (Power to Methanol).
euronion Feb 3, 2021
b265b9f
Add costs for NH3 (l) and CO2 (l) storage tanks.
euronion Feb 8, 2021
69f75da
Add CO2 liquefaction, LNG tank storage and general liquid hydrocarbon…
euronion Feb 9, 2021
c7a3f9b
Add storage for DBT (LOHC) based on densities and compressed methane.
euronion Feb 10, 2021
574de1e
Update output files.
euronion Feb 10, 2021
09b802b
Housekeeping: 'Compressors' -> 'compressor'.
euronion Feb 10, 2021
c16785e
Correct unit for LOHC DBT storage (t instead of m^3).
euronion Feb 10, 2021
5c2e2fb
Update output files.
euronion Feb 10, 2021
9801680
Update deleted output files.
euronion Feb 10, 2021
cb91081
Fix FOM for LNG storage tank.
euronion Feb 10, 2021
bbfe718
Increase number of decimal places from 2 to 6.
euronion Feb 12, 2021
2863fff
Convert some entries to their relevant range in kWh rather than MWh.
euronion Feb 12, 2021
1110a20
Change units for LOHC (de-) hydrogenation to MW_H2.
euronion Feb 12, 2021
7d8e074
Specify H2 (l) costs per t rather than LHV MWh.
euronion Feb 15, 2021
8789f17
Add HVDC submarine costs.
euronion Mar 22, 2021
23bb3ad
Add methane and hydrogen gas submarine pipeline costs.
euronion Mar 23, 2021
ed654dc
Add Fischer-Tropsch synthesis and shiping costs.
euronion Mar 26, 2021
44e4ee7
Consistent naming of methane -> CH4 and unit consistency.
euronion Mar 26, 2021
a29c24e
Add costs for SMR (methane, methanol) and ammonia cracking.
euronion Apr 6, 2021
24cf417
Merge branch 'new-techs/chemical-energy-carriers' of https://github.c…
euronion Apr 6, 2021
62865af
Update of names, costs.
euronion May 1, 2021
6bf78e5
Merge remote-tracking branch 'upstream/master' into new-techs/chemica…
euronion May 2, 2021
738b115
Fix unit mismatch due to faulty manual_input.csv for CH4 evaporation/…
euronion Jul 5, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Snakefile
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ rule compile_cost_assumptions:
dea_storage = "inputs/technology_data_catalogue_for_energy_storage.xlsx",
dea_generation = "inputs/technology_data_for_el_and_dh_-_0009.xlsx",
dea_heating = "inputs/technologydatafor_heating_installations_marts_2018.xlsx",
dea_industrial = "inputs/technology_data_for_industrial_process_heat_0002.xlsx"
dea_industrial = "inputs/technology_data_for_industrial_process_heat_0002.xlsx",
manual_input = "inputs/manual_input.csv"
output:
expand("outputs/costs_{year}.csv", year = config["years"])
threads: 1
Expand Down
3 changes: 3 additions & 0 deletions config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,6 @@ h2_from_budischak : false
# remove grid connection costs from DEA for offwind because they are calculated
# seperately in pypsa-eur
offwind_no_gridcosts : true

desalination:
salinity: 35 # in PSU (Practical Salinity Unit) = kg/m^3
170 changes: 170 additions & 0 deletions inputs/manual_input.csv

Large diffs are not rendered by default.

324 changes: 227 additions & 97 deletions outputs/costs_2020.csv

Large diffs are not rendered by default.

348 changes: 239 additions & 109 deletions outputs/costs_2025.csv

Large diffs are not rendered by default.

328 changes: 229 additions & 99 deletions outputs/costs_2030.csv

Large diffs are not rendered by default.

356 changes: 243 additions & 113 deletions outputs/costs_2035.csv

Large diffs are not rendered by default.

330 changes: 230 additions & 100 deletions outputs/costs_2040.csv

Large diffs are not rendered by default.

350 changes: 240 additions & 110 deletions outputs/costs_2045.csv

Large diffs are not rendered by default.

324 changes: 227 additions & 97 deletions outputs/costs_2050.csv

Large diffs are not rendered by default.

129 changes: 119 additions & 10 deletions scripts/compile_cost_assumptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@
"co2" :'Entwicklung der spezifischen Kohlendioxid-Emissionen des deutschen Strommix in den Jahren 1990 - 2018',
# gas pipeline costs
"ISE": "WEGE ZU EINEM KLIMANEUTRALEN ENERGIESYSEM, Anhang zur Studie, Fraunhofer-Institut für Solare Energiesysteme ISE, Freiburg",
# Water desalination costs
"Caldera2016": "Caldera et al 2016: Local cost of seawater RO desalination based on solar PV and windenergy: A global estimate. (https://doi.org/10.1016/j.desal.2016.02.004)",
"Caldera2017": "Caldera et al 2017: Learning Curve for Seawater Reverse Osmosis Desalination Plants: Capital Cost Trend of the Past, Present, and Future (https://doi.org/10.1002/2017WR021402)",
# home battery storage and inverter investment costs
"EWG": "Global Energy System based on 100% Renewable Energy, Energywatchgroup/LTU University, 2019"
}
Expand Down Expand Up @@ -77,10 +80,11 @@
# 'decentral water tank storage': '142 Small scale hot water tank',
'fuel cell': '12 LT-PEMFC CHP',
'hydrogen storage underground': '151c Hydrogen Storage - Caverns',
'hydrogen storage tank': '151a Hydrogen Storage - Tanks',
'hydrogen storage tank incl. compressor': '151a Hydrogen Storage - Tanks',
'micro CHP': '219 LT-PEMFC mCHP - natural gas',
'biogas upgrading': '82 Biogas, upgrading',
'battery': '180 Lithium Ion Battery',
'industrial heat pump medium temperature':'302.a High temp. hp Up to 125 C',
'electrolysis': '86 AEC 100MW', #'88 Alkaline Electrolyser',
'direct air capture' : '403.a Direct air capture',
'biomass CHP capture' : '401.a Post comb - small CHP',
Expand Down Expand Up @@ -121,14 +125,15 @@
'central water tank storage': 'J:K',
'fuel cell': 'I:J',
'hydrogen storage underground': 'J:K',
'hydrogen storage tank': 'J:K',
'hydrogen storage tank incl. compressor': 'J:K',
'micro CHP': 'I:J',
'biogas upgrading': 'I:J',
'electrolysis': 'I:J',
'battery': 'L,N',
'direct air capture': 'I:J',
'cement capture': 'I:J',
'biomass CHP capture': 'I:J',
'industrial heat pump medium temperature':'H:I',
}


Expand Down Expand Up @@ -178,6 +183,8 @@ def get_data_DEA(tech, data_in, expectation=None):
usecols = f"B:J,{uncrtnty_lookup[tech]}"
elif tech in ['direct air capture', 'cement capture', 'biomass CHP capture']:
usecols = f"A:F,{uncrtnty_lookup[tech]}"
elif tech in ['industrial heat pump medium temperature']:
usecols = f"A:E,{uncrtnty_lookup[tech]}"
else:
usecols = f"B:G,{uncrtnty_lookup[tech]}"

Expand All @@ -203,7 +210,7 @@ def get_data_DEA(tech, data_in, expectation=None):
uncertainty_columns = ["2050-optimist", "2050-pessimist"]
if uncrtnty_lookup[tech]:
# hydrogen storage sheets have reverse order of lower/upper estimates
if tech in ["hydrogen storage tank", "hydrogen storage cavern"]:
if tech in ["hydrogen storage tank incl. compressor", "hydrogen storage cavern"]:
uncertainty_columns.reverse()
excel.rename(columns={excel.columns[-2]: uncertainty_columns[0],
excel.columns[-1]: uncertainty_columns[1]
Expand Down Expand Up @@ -268,6 +275,10 @@ def get_data_DEA(tech, data_in, expectation=None):
if (tech == "offwind") and snakemake.config['offwind_no_gridcosts']:
df.loc['Nominal investment (MEUR/MW)'] -= excel.loc[' - of which grid connection']

# Exlucde indirect costs for centralised system with additional piping.
if tech.startswith('industrial heat pump'):
df = df.drop('Indirect investments cost (MEUR per MW)')

df_final = pd.DataFrame(index=df.index, columns=years)

# [RTD-interpolation-example]
Expand All @@ -282,6 +293,54 @@ def get_data_DEA(tech, data_in, expectation=None):

return df_final

def add_desalinsation_data(costs):
"""
add technology data for sea water desalination (SWRO) and water storage.
"""

# Interpolate cost based on historic costs/cost projection to fitting year
cs = [2070,1917,1603,1282,1025] # in USD/(m^3/d)
ys = [2015,2022,2030,2040,2050]
c = np.interp(year, ys, cs)
c *= 24 # in USD/(m^3/h)
c /= 1.17 # in EUR/(m^3/h)

tech = "seawater desalination"
costs.loc[(tech, 'investment'), 'value'] = c
costs.loc[(tech, 'investment'), 'unit'] = "EUR/(m^3-H2O/h)"
costs.loc[(tech, 'investment'), 'source'] = source_dict['Caldera2017'] + ", Table 4."

costs.loc[(tech, 'FOM'), 'value'] = 4.
costs.loc[(tech, 'FOM'), 'unit'] = "%/year"
costs.loc[(tech, 'FOM'), 'source'] = source_dict['Caldera2016'] + ", Table 1."

costs.loc[(tech, 'lifetime'), 'value'] = 30
costs.loc[(tech, 'lifetime'), 'unit'] = "years"
costs.loc[(tech, 'lifetime'), 'source'] = source_dict['Caldera2016'] + ", Table 1."

salinity = snakemake.config['desalination']['salinity']
costs.loc[(tech, 'electricity-input'), 'value'] = (0.0003*salinity**2+0.0018*salinity+2.6043)
costs.loc[(tech, 'electricity-input'), 'unit'] = "kWh/m^3-H2O"
costs.loc[(tech, 'electricity-input'), 'source'] = source_dict['Caldera2016'] + ", Fig. 4."

tech = "clean water tank storage"
costs.loc[(tech, 'investment'), 'value'] = 65
costs.loc[(tech, 'investment'), 'unit'] = "EUR/m^3-H2O"
costs.loc[(tech, 'investment'), 'source'] = source_dict['Caldera2016'] + ", Table 1."

costs.loc[(tech, 'FOM'), 'value'] = 2
costs.loc[(tech, 'FOM'), 'unit'] = "%/year"
costs.loc[(tech, 'FOM'), 'source'] = source_dict['Caldera2016'] + ", Table 1."

costs.loc[(tech, 'lifetime'), 'value'] = 30
costs.loc[(tech, 'lifetime'), 'unit'] = "years"
costs.loc[(tech, 'lifetime'), 'source'] = source_dict['Caldera2016'] + ", Table 1."

costs = adjust_for_inflation(costs, ['seawater desalination'], 2015)
costs = adjust_for_inflation(costs, ['clean water tank storage'], 2013)

return costs

def add_conventional_data(costs):
""""
add technology data for conventional carriers from Lazards, DIW and BP
Expand Down Expand Up @@ -473,14 +532,30 @@ def get_data_from_DEA(data_in, expectation=None):
"""
d_by_tech = {}

for tech in sheet_names.keys():
print(tech + ' in PyPSA corresponds to ' + sheet_names[tech] +
' in DEA database.')
for tech, dea_tech in sheet_names.items():
print(f'{tech} in PyPSA corresponds to {dea_tech} in DEA database.')
df = get_data_DEA(tech, data_in, expectation).fillna(0)
d_by_tech[tech] = df

return d_by_tech

def adjust_for_inflation(costs, techs, ref_year):
"""
adjust the investment costs for the specified techs for inflation.

techs: str or list
One or more techs in costs index for which the inflation adjustment is done.
ref_year: int
Reference year for which the costs are provided and based on which the inflation adjustment is done.
costs: pd.Dataframe
Dataframe containing the costs data with multiindex on technology and one index key 'investment'.
"""

inflation = (1 + snakemake.config['rate_inflation'])**(ref_year - snakemake.config['eur_year'])
costs.loc[(techs, 'investment'), 'value'] /= inflation

return costs


def clean_up_units(tech_data):
"""
Expand Down Expand Up @@ -651,12 +726,12 @@ def set_round_trip_efficiency(tech_data):
"""

# hydrogen storage
to_drop = [("hydrogen storage tank", ' - Charge efficiency')]
to_drop.append(("hydrogen storage tank", ' - Discharge efficiency'))
to_drop = [("hydrogen storage tank incl. compressor", ' - Charge efficiency')]
to_drop.append(("hydrogen storage tank incl. compressor", ' - Discharge efficiency'))
to_drop.append(("hydrogen storage underground", ' - Charge efficiency'))
to_drop.append(("hydrogen storage underground", ' - Discharge efficiency'))
tech_data.loc[("hydrogen storage underground", "Round trip efficiency"), years] *= 100
tech_data.loc[("hydrogen storage tank", "Round trip efficiency"), years] *= 100
tech_data.loc[("hydrogen storage tank incl. compressor", "Round trip efficiency"), years] *= 100



Expand Down Expand Up @@ -983,6 +1058,36 @@ def rename_pypsa_old(costs_pypsa):

return costs_pypsa

def add_manual_input(data):

df = pd.read_csv(snakemake.input['manual_input'], quotechar='"',sep=',', keep_default_na=False)

# Inflation adjustment for investment and VOM
mask = df[df['parameter'].isin(['investment','VOM'])].index
df.loc[mask, 'value'] /= (1+snakemake.config['rate_inflation'])**(df.loc[mask, 'currency_year']-snakemake.config['eur_year'])

l = []
for tech in df['technology'].unique():
c0 = df[df['technology'] == tech]
for param in c0['parameter'].unique():

c = df.query('technology == @tech and parameter == @param')

s = pd.Series(index=snakemake.config['years'],
data=np.interp(snakemake.config['years'], c['year'], c['value']),
name=param)
s['parameter'] = param
s['technology'] = tech
for col in ['unit','source','further_description']:
s[col] = "; and\n".join(c[col].unique().astype(str))

l.append(s)

new_df = pd.DataFrame(l).set_index(['technology','parameter'])
data = data.combine_first(new_df)

return data


def rename_ISE(costs_ISE):
"""
Expand Down Expand Up @@ -1156,6 +1261,7 @@ def get_factor(df, cols, utility_col):
# add costs for gas pipelines
data = pd.concat([data, costs_ISE.loc[["Gasnetz"]]], sort=True)

data = add_manual_input(data)
# add costs for home batteries
data = add_home_battery_costs(data)
# %% (3) ------ add additional sources and save cost as csv ------------------
Expand All @@ -1173,6 +1279,9 @@ def get_factor(df, cols, utility_col):
# add solar data from other source than DEA
if any([snakemake.config['solar_utility_from_vartiaien'], snakemake.config['solar_rooftop_from_etip']]):
costs = add_solar_from_other(costs)

# add desalination and clean water tank storage
costs = add_desalinsation_data(costs)

# add electrolyzer and fuel cell efficiency from other source than DEA
if snakemake.config['h2_from_budischak']:
Expand Down Expand Up @@ -1214,5 +1323,5 @@ def get_factor(df, cols, utility_col):
costs_tot = unify_diw(costs_tot)
costs_tot.drop("fixed", level=1, inplace=True)
costs_tot.sort_index(inplace=True)
costs_tot = round(costs_tot, ndigits=2)
costs_tot = round(costs_tot, ndigits=6)
costs_tot.to_csv([v for v in snakemake.output if str(year) in v][0])