Optimising storage locations#

Functions to optimise hydrogen storage locations.

References#

h2ss.optimisation.ref_power_curve(v)[source]#

Power curve for the reference wind turbine.

Parameters#

vfloat

Wind speed [m s⁻¹]

Returns#

float

Wind turbine power output at a given wind speed from the power curve [MW]

Notes#

The NREL 15 MW reference wind turbine is used; see [1], Appendix D, p. 84, for the data used to generate the power curve.

h2ss.optimisation.weibull_probability_distribution(v, k, c)[source]#

Weibull probability distribution function.

Parameters#

vfloat

Wind speed [m s⁻¹]

kfloat

Shape (Weibull distribution parameter, k)

cfloat

Scale (Weibull distribution parameter, C) [m s⁻¹]

Returns#

float

Weibull probability distribution function [s m⁻¹]

Notes#

The Weibull probability distribution function, \(f(v)\) [s m⁻¹] is based on Eqn. (1) of [2], where \(k\) and \(C\) [m s⁻¹] are the shape and scale Weibull distribution parameters, respectively, and \(v\) is the wind speed.

\[f(v) = \frac{k}{C} \, \left( \frac{v}{C} \right)^{k - 1} \, \exp \left( -\left( \frac{v}{C} \right)^k \right)\]

See also [3], Eqn. (2).

h2ss.optimisation.weibull_distribution(weibull_wf_data)[source]#

Generate a power curve and Weibull distribution.

Parameters#

weibull_wf_datapandas.DataFrame

Dataframe of the Weibull distribution parameters for the wind farms

Returns#

pandas.DataFrame

Dataframe of the Weibull distribution for each wind farm for wind speeds of 0 to 30 m s⁻¹ at an interval of 0.01

h2ss.optimisation.weibull_power_curve(v, k, c)[source]#

Weibull probability distribution function multiplied by the power curve.

Parameters#

vfloat

Wind speed between cut-in and cut-out [m s⁻¹]

kfloat

Shape (Weibull distribution parameter, k)

cfloat

Scale (Weibull distribution parameter, C) [m s⁻¹]

Returns#

float

Weibull probability distribution multiplied by the power curve [MW s m⁻¹]

h2ss.optimisation.number_of_turbines(owf_cap, wt_power=15)[source]#

Number of reference wind turbines in the offshore wind farm.

Parameters#

owf_capfloat

Maximum nameplate capacity of the proposed offshore wind farm [MW]

wt_powerfloat

Rated power of the reference wind turbine [MW]

Returns#

int

Number of wind turbines in the offshore wind farm comprising of reference wind turbines

Notes#

The number of turbines, \(n\) of an offshore wind farm was determined using the floor division of the wind farm’s maximum nameplate capacity, \(P_{owf}\) [MW] by the reference wind turbine’s rated power, \(P_{rated}\) [MW].

\[n = \left\lfloor \frac{P_{owf}}{P_{rated}} \right\rfloor\]
h2ss.optimisation.annual_energy_production_function(n_turbines, k, c, w_loss=0.1, acdc_loss=0.982)[source]#

Annual energy production of the wind farm.

Parameters#

n_turbinesint

Number of wind turbines in wind farm

kfloat

Shape (Weibull distribution parameter)

cfloat

Scale (Weibull distribution parameter) [m s⁻¹]

w_lossfloat

Wake loss

acdc_lossfloat

AC-DC conversion losses

Returns#

tuple[float, float, float]

Annual energy production of wind farm [MWh], integral [MW], and absolute error [MW]

Notes#

The annual energy production, \(E_{annual}\) [MWh], is based on Eqn. (3) of [2], where \(n\) is the number of turbines in the wind farm, \(w\) is the wake loss, which is assumed to be a constant value of 0.1, \(v_i\) and \(v_o\) [m s⁻¹] are the cut-in and cut-out speeds of the wind turbine, respectively, \(P(v)\) [MW] is the wind turbine power output, \(f(v)\) [s m⁻¹] is the Weibull probability distribution function, and \(\varepsilon\) is the AC-DC conversion loss.

\[E_{annual} = 365 \times 24 \times n \, \left( 1 - w \right) \, \varepsilon \, \int\limits_{v_i}^{v_o} P(v) \, f(v) \,\mathrm{d}v\]

In the function’s implementation, both the limit and absolute error tolerance for the integration have been increased.

h2ss.optimisation.annual_energy_production(weibull_wf_data)[source]#

Annual energy production of the wind farms.

Parameters#

weibull_wf_datapandas.DataFrame

Dataframe of the Weibull distribution parameters for the wind farms

Returns#

pandas.DataFrame

Dataframe with the annual energy production for each wind farm

h2ss.optimisation.annual_hydrogen_production(aep, eta_conv=0.7, e_pcl=0.003053)[source]#

Annual hydrogen production from the wind farm’s energy generation.

Parameters#

aepfloat

Annual energy production of wind farm [MWh]

eta_convfloat

Conversion efficiency of the electrolyser

e_pclfloat

Electricity consumed by other parts of the hydrogen plant [MWh kg⁻¹]

Returns#

float

Annual hydrogen production [kg]

Notes#

Eqn. (4) of [2], Eqn. (9) of [4], and [6]. The value for the electricity consumed by other parts of the hydrogen plant is from Table 3 of [4] for proton exchange membrane (PEM) electrolysers predicted for the year 2030. This includes energy for water purification, hydrogen compression, and losses. The electrolyser conversion efficiency is based on [6]. See [5] for the heating values.

\[m_{annual} = \dfrac{E_{annual}}{\dfrac{LHV}{3,600 \, \eta} + E_{plant}}\]

where \(m_{annual}\) is the annual hydrogen production [kg], \(E_{annual}\) is the annual energy production of the wind farm [MWh], \(LHV\) is the lower heating value of hydrogen [MJ kg⁻¹], \(\eta\) is the conversion efficiency of the electrolyser, and \(E_{plant}\) is the electricity consumed by other parts of the hydrogen plant [MWh kg⁻¹].

h2ss.optimisation.transmission_distance(cavern_df, wf_data, injection_point_coords=(-6, -12, 53, 21))[source]#

Calculate the transmission distance to the injection point.

Parameters#

cavern_dfgeopandas.GeoDataFrame

Dataframe of potential caverns

wf_datageopandas.GeoDataFrame

Geodataframe of the offshore wind farm data

injection_point_coordstuple[float, float, float, float]

Injection point coordinates (lon-deg, lon-min, lat-deg, lat-min)

Returns#

tuple[geopandas.GeoDataFrame, geopandas.GeoSeries]

The cavern dataframe and injection point

Notes#

A hacky workaround was used to prevent “DeprecationWarning: Conversion of an array with ndim > 0 to a scalar is deprecated, and will error in future. Ensure you extract a single element from your array before performing this operation. (Deprecated NumPy 1.25.)” during the transformation of the injection point from a single-row series, i.e. assigning a duplicate row and dropping it after reprojecting.

h2ss.optimisation.electrolyser_capacity(n_turbines, wt_power=15, cap_ratio=0.83)[source]#

Calculate the electrolyser capacity for an offshore wind farm.

Parameters#

n_turbinesint

Number of wind turbines in wind farm

wt_powerfloat

Rated power of the reference wind turbine [MW]

cap_ratiofloat

Ratio of electrolyser capacity to the wind farm capacity

Returns#

int

Electrolyser capacity [MW]

Notes#

In the offshore electrolyser concept of [6], the electricity from an offshore wind farm “is supplied to the electrolyser by medium voltage alternating current (AC) cable. The electrolyser requires direct current (DC) electricity input so this concept includes an AC-DC converter. The hydrogen obtained is compressed and delivered onshore by hydrogen pipelines”.

The “energy from the offshore wind farm is only subjected to wake losses and a small amount of electricity loss in the site network and the AC-DC converter before being supplied to the electrolyser. The hydrogen obtained will then be transported to onshore infrastructure by pipeline. The losses incurred by pipeline transmission are very low” [6].

The electrolyser capacity, \(P_{electrolyser}\) [MW] is rounded down to an integer and is the product of the number of reference wind turbines of the offshore wind farm, \(n\), the rated power of the reference wind turbine, \(P_{rated}\), and the ratio of the electrolyser capacity to the offshore wind farm capacity, \(F_{electrolyser}\).

\[P_{electrolyser} = \left\lfloor n \, P_{rated} \, F_{electrolyser} \right\rfloor\]
h2ss.optimisation.hydrogen_pipeline_density(pressure, temperature)[source]#

Calculate the density of hydrogen in the pipelines.

Parameters#

pressurefloat

Pressure of hydrogen in the pipeline [Pa]

temperaturefloat

Temperature of hydrogen in the pipeline [°C]

Returns#

float

Pipeline hydrogen density [kg m⁻³]

Notes#

According to [8], the envisaged future hydrogen pipeline system is assumed to be operated at pressure levels up to 10 MPa. They used an average operating pressure of 6.5 MPa for transmission pipelines and calculated the density using the average soil temperature, which was assumed to be the operating temperature of the hydrogen [8].

h2ss.optimisation.capex_pipeline(e_cap, p_rate=0.0055, pressure=10000000.0, temperature=10, u=15)[source]#

Capital expenditure (CAPEX) for the pipeline.

Parameters#

e_capfloat

Electrolyser capacity [MW]

p_ratefloat

Electrolyser production rate [kg s⁻¹ MW⁻¹]

pressurefloat

Pressure of hydrogen in the pipeline [Pa]

temperaturefloat

Temperature of hydrogen in the pipeline [°C]

ufloat

Average fluid velocity [m s⁻¹]

Returns#

float

CAPEX of the pipeline per km of pipeline [€ km⁻¹]

Notes#

See Eqn. (18) of [2] and Section 3.1 of [7], from which the following text has been taken.

The estimation of offshore pipeline costs is based on the onshore pipeline calculations of [8], multiplied by a factor of two to reflect the estimated cost scaling of onshore to expected offshore costs, as suggested by [9].

In the reference case, the resulting capital expenditure for transmission pipelines and associated recompression stations was represented by a second order polynomial function.

The electrolyser production rate was based on the Siemens - Silyzer 300 [10].

Because the electrolyser plant is assumed to be operating at full capacity at all times, the CAPEX was calculated considering a 75% utilisation rate, i.e. the pipeline capacity is 33% oversized [11].

\[CAPEX = 2,000 \, \left( 16,000 \, \frac{P_{electrolyser} \times EPR}{\rho_{H_2} \, v_{H_2} \, \pi} + 1,197.2 \, \sqrt{\frac{P_{electrolyser} \times EPR}{\rho_{H_2} \, v_{H_2} \, \pi}} + 329 \right)\]

where \(CAPEX\) is the CAPEX of the pipeline per km of pipeline [€ km⁻¹], \(P_{electrolyser}\) is the electrolyser capacity [MW], \(EPR\) is the electrolyser production rate [kg s⁻¹ MW⁻¹], \(\rho_{H_2}\) is the density of hydrogen [kg m⁻³], and \(v_{H_2}\) is the average fluid velocity [m s⁻¹].

h2ss.optimisation.lcot_pipeline_function(capex, d_transmission, ahp, opex_ratio=0.02, discount_rate=0.08, lifetime=30)[source]#

Levelised cost of transmission (LCOT) of hydrogen in pipelines.

Parameters#

capexfloat

Capital expenditure (CAPEX) of the pipeline [€ km⁻¹]

d_transmissionfloat

Pipeline transmission distance [km]

ahpfloat

Annual hydrogen production [kg]

opex_ratiofloat

Ratio of the operational expenditure (OPEX) to the CAPEX

discount_ratefloat

Discount rate

lifetimeint

Lifetime of the pipeline [year]

Returns#

float

LCOT of hydrogen in the pipeline [€ kg⁻¹]

Notes#

The OPEX is calculated as a percentage of the CAPEX. See the introduction of Section 3, Eqn. (1) and (2), and Section 3.5, Eqn. (22) of [7]; see Tables 2 and 3 for the assumptions and constants used.

\[LCOT = \frac{\mathrm{total\ lifecycle\ costs\ of\ all\ components}} {\mathrm{lifetime\ hydrogen\ transported}}\]
\[OPEX = CAPEX \times F_{OPEX}\]
\[LCOT = \frac{\left( CAPEX + \displaystyle\sum_{l=0}^{L} \frac{OPEX}{{(1 + DR)}^l} \right) \, d} {\displaystyle\sum_{l=0}^{L} \frac{AHP}{{(1 + DR)}^l}}\]

where \(LCOT\) is the LCOT of hydrogen in pipelines [€ kg⁻¹], \(CAPEX\) is the CAPEX of the pipeline per km of pipeline [€ km⁻¹], \(d\) is the pipeline transmission distance [km], \(OPEX\) is the OPEX of the pipeline [€ km⁻¹], \(DR\) is the discount rate, \(AHP\) is the annual hydrogen production [kg], \(L\) is the lifetime of the pipeline [year], and \(F_{OPEX}\) is the ratio of the OPEX to the CAPEX.

h2ss.optimisation.lcot_pipeline(weibull_wf_data, cavern_df)[source]#

Calculate the pipeline levelised cost of transmission.

Parameters#

cavern_dfgeopandas.GeoDataFrame

Dataframe of potential caverns

weibull_wf_datapandas.DataFrame

Dataframe of the Weibull distribution parameters for the wind farms

Returns#

pandas.DataFrame

Dataframe of potential caverns

h2ss.optimisation.rotor_area(diameter=248)[source]#

Wind turbine rotor swept area.

Parameters#

diameterfloat

Wind turbine rotor diameter [m]

Returns#

float

Wind turbine rotor swept area [m²]

Notes#

\[A = \frac{\pi \, D^2}{4}\]

where \(A\) is the wind turbine rotor swept area [m²] and \(D\) is the rotor diameter [m].

h2ss.optimisation.power_wind_resource(v, rho=1.225, diameter=248)[source]#

Total wind resource power passing through a wind turbine’s rotor.

Parameters#

vfloat

Wind speed [m s⁻¹]

rhofloat

Air density [kg m⁻³]

diameterfloat

Wind turbine rotor diameter [m]

Returns#

float

Power contained in the wind resource [MW]

Notes#

\[P_{wind} = \frac{\rho_{air} \, A \, v^3}{2 \times 10^6}\]

where \(P_{wind}\) is the power contained in the wind resource [MW], \(\rho_{air}\) is the air density [kg m⁻³], \(A\) is the rotor swept area [m²], and \(v\) is the wind speed [m s⁻¹].

h2ss.optimisation.power_coefficient(v)[source]#

Power coefficient of the reference wind turbine.

Parameters#

vfloat

Wind speed [m s⁻¹]

Returns#

float

Power coefficient

Notes#

This is specific to the power curve of the NREL 15 MW reference wind turbine [1].

\[C_p = \frac{P}{P_{wind}} = \frac{P \times 2 \times 10^6} {\rho_{air} \, A \, v^3}\]

where \(P\) is the wind turbine power output [MW], \(P_{wind}\) is the power contained in the wind resource [MW], \(\rho_{air}\) is the air density [kg m⁻³], \(A\) is the rotor swept area [m²], \(v\) is the wind speed [m s⁻¹], and \(C_p\) is the power coefficient of the wind turbine.