diff --git a/config.default.yaml b/config.default.yaml index d23cc033..dfce8794 100644 --- a/config.default.yaml +++ b/config.default.yaml @@ -30,6 +30,7 @@ scenario: # B for biomass supply, I for industry, shipping and aviation # solar+c0.5 reduces the capital cost of solar to 50\% of reference value # solar+p3 multiplies the available installable potential by factor 3 + # co2 stored+e2 multiplies the potential of CO2 sequestration by a factor 2 # dist{n} includes distribution grids with investment cost of n times cost in data/costs.csv # for myopic/perfect foresight cb states the carbon budget in GtCO2 (cumulative # emissions throughout the transition path in the timeframe determined by the @@ -71,7 +72,8 @@ electricity: # regulate what components with which carriers are kept from PyPSA-Eur; # some technologies are removed because they are implemented differently -# or have different year-dependent costs in PyPSA-Eur-Sec +# (e.g. battery or H2 storage) or have different year-dependent costs +# in PyPSA-Eur-Sec pypsa_eur: Bus: - AC @@ -179,6 +181,7 @@ sector: transport_fuel_cell_efficiency: 0.5 transport_internal_combustion_efficiency: 0.3 shipping_average_efficiency: 0.4 #For conversion of fuel oil to propulsion in 2011 + shipping_hydrogen_liquefaction: true # whether to consider liquefaction costs for shipping H2 demands shipping_hydrogen_share: # 1 means all hydrogen FC 2020: 0 2025: 0 diff --git a/doc/installation.rst b/doc/installation.rst index 3ab3d328..cbd4c948 100644 --- a/doc/installation.rst +++ b/doc/installation.rst @@ -89,10 +89,8 @@ The data licences and sources are given in the following table. Set up the default configuration ================================ -First make your own copy of the ``config.yaml``. For overnight -scenarios, use ``config.default.yaml``. For a pathway optimization -with myopic foresight (which is still experimental), use -``config.myopic.yaml``. For example: +First make your own copy of the ``config.yaml`` based on + ``config.default.yaml``. For example: .. code:: bash diff --git a/doc/release_notes.rst b/doc/release_notes.rst index 455bb01a..15419438 100644 --- a/doc/release_notes.rst +++ b/doc/release_notes.rst @@ -60,8 +60,12 @@ Future release These are included in the environment specifications of PyPSA-Eur. * Consistent use of ``__main__`` block and further unspecific code cleaning. * Distinguish costs for home battery storage and inverter from utility-scale battery costs. +* Added option for hydrogen liquefaction costs for hydrogen demand in shipping. + This introduces a new ``H2 liquid`` bus at each location. + It is activated via ``sector: shipping_hydrogen_liquefaction: true``. * The share of shipping transformed into hydrogen fuel cell can be now defined for different years in the ``config.yaml`` file. The carbon emission from the remaining share is treated as a negative load on the atmospheric carbon dioxide bus, just like aviation and land transport emissions. * The transformation of the Steel and Aluminium production can be now defined for different years in the ``config.yaml`` file. +* Include the option to alter the maximum energy capacity of a store via the ``carrier+factor`` in the ``{sector_opts}`` wildcard. This can be useful for sensitivity analyses. Example: ``co2 stored+e2`` multiplies the ``e_nom_max`` by factor 2. In this example, ``e_nom_max`` represents the CO2 sequestration potential in Europe. PyPSA-Eur-Sec 0.5.0 (21st May 2021) =================================== diff --git a/graphics/multisector_figure.pdf b/graphics/multisector_figure.pdf index e49994d7..35bbaf1d 100644 Binary files a/graphics/multisector_figure.pdf and b/graphics/multisector_figure.pdf differ diff --git a/graphics/multisector_figure.png b/graphics/multisector_figure.png index e5c17c73..415e7e6d 100644 Binary files a/graphics/multisector_figure.png and b/graphics/multisector_figure.png differ diff --git a/graphics/multisector_figure.svg b/graphics/multisector_figure.svg index 65fcad07..ece433df 100644 --- a/graphics/multisector_figure.svg +++ b/graphics/multisector_figure.svg @@ -15,7 +15,7 @@ id="svg7114" version="1.1" inkscape:version="0.92.4 (5da689c313, 2019-01-14)" - sodipodi:docname="20200223_multisector_figure.svg"> + sodipodi:docname="multisector_figure.svg"> + + + image/svg+xml - + @@ -1630,14 +1645,6 @@ inkscape:groupmode="layer" id="layer1" transform="translate(-27.752361,-374.2016)"> -       - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Wind & Solar PV - - - - Hydroelectricity - - - - Biogas - - - - Fossil gas - - - - Other biomass - - - - Atmosphere - - - - Fossil oil - - - - Electricity - - - - Hydrogen - - - - Methane - - - - Carbon Dioxide - - - - Liquid hydrocarbons - - - - - Electric devices - - - - - Resistive heaters - - - - Heat pumps - - - - - Gas boilers - - - - - CHP - - - - Electric - - - - Fuel cell - - - - - Internalcombustion - - - - - Industry - - Heating Transport - - - - S O U R C E S G R I D S & S T O R A G E D E M A N D Electrolysis Fuel cell Methanation Steam reforming Direct air capture Carbon capture Fischer-Tropsch     - + +     + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Wind & Solar PV + + + + Hydroelectricity + + + + Biogas + + + + Fossil gas + + + + Other biomass + + + + Atmosphere + + + + Fossil oil + + + + Electricity + + + + Hydrogen + + + + Methane + + + + Carbon Dioxide + + + + Liquid hydrocarbons + + + + + Electric devices + + + + + Resistive heaters + + + + Heat pumps + + + + + Gas boilers + + + + + CHP + + + + Electric + + + + Fuel cell + + + + + Internalcombustion + + + + + Industry + + Heating Transport + + + + S O U R C E S G R I D S & S T O R A G E D E M A N D Electrolysis Fuel cell Methanation Steam reforming Direct air capture Carbon capture Fischer-Tropsch   - + x="30.698057" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:0%;font-family:Calibri;-inkscape-font-specification:Calibri;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + xml:space="preserve">  + + + diff --git a/scripts/build_industrial_production_per_country_tomorrow.py b/scripts/build_industrial_production_per_country_tomorrow.py index 9257368b..ba69e0a6 100644 --- a/scripts/build_industrial_production_per_country_tomorrow.py +++ b/scripts/build_industrial_production_per_country_tomorrow.py @@ -27,7 +27,7 @@ if __name__ == '__main__': dri = dri_fraction * fraction_persistent_primary * production["Integrated steelworks"] production.insert(2, "DRI + Electric arc", dri) - not_dri = (1 - dri_fraction) * fraction_persistent_primary + not_dri = (1 - dri_fraction) production["Integrated steelworks"] = not_dri * fraction_persistent_primary * production["Integrated steelworks"] production["Electric arc"] = total_steel - production["DRI + Electric arc"] - production["Integrated steelworks"] diff --git a/scripts/prepare_sector_network.py b/scripts/prepare_sector_network.py index 54f1bab9..66dbfc71 100644 --- a/scripts/prepare_sector_network.py +++ b/scripts/prepare_sector_network.py @@ -906,7 +906,7 @@ def add_storage(n, costs): ) # hydrogen stored overground (where not already underground) - h2_capital_cost = costs.at["hydrogen storage tank", "fixed"] + h2_capital_cost = costs.at["hydrogen storage tank incl. compressor", "fixed"] nodes_overground = cavern_nodes.index.symmetric_difference(nodes) n.madd("Store", @@ -941,9 +941,9 @@ def add_storage(n, costs): p_min_pu=-1, p_nom_extendable=True, length=h2_links.length.values, - capital_cost=costs.at['H2 pipeline', 'fixed'] * h2_links.length.values, + capital_cost=costs.at['H2 (g) pipeline', 'fixed'] * h2_links.length.values, carrier="H2 pipeline", - lifetime=costs.at['H2 pipeline', 'lifetime'] + lifetime=costs.at['H2 (g) pipeline', 'lifetime'] ) n.add("Carrier", "battery") @@ -997,7 +997,7 @@ def add_storage(n, costs): carrier="Sabatier", efficiency=costs.at["methanation", "efficiency"], efficiency2=-costs.at["methanation", "efficiency"] * costs.at['gas', 'CO2 intensity'], - capital_cost=costs.at["methanation", "fixed"], + capital_cost=costs.at["methanation", "fixed"] * costs.at["methanation", "efficiency"], # costs given per kW_gas lifetime=costs.at['methanation', 'lifetime'] ) @@ -1751,6 +1751,30 @@ def add_industry(n, costs): p_set=industrial_demand.loc[nodes, "hydrogen"] / 8760 ) + if options["shipping_hydrogen_liquefaction"]: + + n.madd("Bus", + nodes, + suffix=" H2 liquid", + carrier="H2 liquid", + location=nodes + ) + + n.madd("Link", + nodes + " H2 liquefaction", + bus0=nodes + " H2", + bus1=nodes + " H2 liquid", + carrier="H2 liquefaction", + efficiency=costs.at["H2 liquefaction", 'efficiency'], + capital_cost=costs.at["H2 liquefaction", 'fixed'], + p_nom_extendable=True, + lifetime=costs.at['H2 liquefaction', 'lifetime'] + ) + + shipping_bus = nodes + " H2 liquid" + else: + shipping_bus = nodes + " H2" + all_navigation = ["total international navigation", "total domestic navigation"] efficiency = options['shipping_average_efficiency'] / costs.at["fuel cell", "efficiency"] shipping_hydrogen_share = get(options['shipping_hydrogen_share'], investment_year) @@ -1759,7 +1783,7 @@ def add_industry(n, costs): n.madd("Load", nodes, suffix=" H2 for shipping", - bus=nodes + " H2", + bus=shipping_bus, carrier="H2 for shipping", p_set=p_set ) @@ -1769,7 +1793,7 @@ def add_industry(n, costs): shipping_oil_share = 1 - shipping_hydrogen_share p_set = shipping_oil_share * nodal_energy_totals.loc[nodes, all_navigation].sum(axis=1) * 1e6 / 8760. - + n.madd("Load", nodes, suffix=" shipping oil", @@ -1986,14 +2010,19 @@ def maybe_adjust_costs_and_potentials(n, opts): suptechs = map(lambda c: c.split("-", 2)[0], carrier_list) if oo[0].startswith(tuple(suptechs)): carrier = oo[0] - attr_lookup = {"p": "p_nom_max", "c": "capital_cost"} + attr_lookup = {"p": "p_nom_max", "e": "e_nom_max", "c": "capital_cost"} attr = attr_lookup[oo[1][0]] factor = float(oo[1][1:]) #beware if factor is 0 and p_nom_max is np.inf, 0*np.inf is nan if carrier == "AC": # lines do not have carrier n.lines[attr] *= factor else: - comps = {"Generator", "Link", "StorageUnit"} if attr == 'p_nom_max' else {"Generator", "Link", "StorageUnit", "Store"} + if attr == 'p_nom_max': + comps = {"Generator", "Link", "StorageUnit"} + elif attr == 'e_nom_max': + comps = {"Store"} + else: + comps = {"Generator", "Link", "StorageUnit", "Store"} for c in n.iterate_components(comps): if carrier=='solar': sel = c.df.carrier.str.contains(carrier) & ~c.df.carrier.str.contains("solar rooftop") diff --git a/scripts/solve_network.py b/scripts/solve_network.py index 8c0313f1..a46acc30 100644 --- a/scripts/solve_network.py +++ b/scripts/solve_network.py @@ -151,7 +151,6 @@ def add_chp_constraints(n): def extra_functionality(n, snapshots): - add_chp_constraints(n) add_battery_constraints(n)