Skip to content

wind

Modules:

Functions:

build_ws_correction_function

build_ws_correction_function(type, data_dict)

type: str type of correction function data_dict: dict, str dictionary or json file containing the data needed to build the correction function

Source code in reskit/wind/core/windspeed_correction.py
def build_ws_correction_function(type, data_dict):
    """
    type: str
        type of correction function
    data_dict: dict, str
        dictionary or json file containing the data needed to
        build the correction function
    """
    if isinstance(data_dict, str):
        assert os.path.isfile(data_dict), f"data_dict is a str but not an existing file: {data_dict}"
        assert os.path.splitext(data_dict)[-1] in [
            ".yaml",
            ".yml",
        ], f"data_dict must be a yaml file if given as str path."
        with open(data_dict, "r") as f:
            data_dict = yaml.load(f, Loader=yaml.FullLoader)
    if type == "polynomial":
        # convert tuple to dict first if needed
        if isinstance(data_dict, (list, tuple)):
            # assume that the polynomial factors a_i*x^^i are sorted (a_n, ..., a_2, a_1, a_0)
            data_dict = {i: v for i, v in enumerate(list(data_dict)[::-1])}
        assert isinstance(data_dict, dict), f"data_dict must be a dict if not given as a tuple of polynomial factors."
        assert all([x % 1 == 0 for x in data_dict.keys()]), (
            f"All data_dict keys must be integers i with values a_i, for all required polynomial factors a_i*x^^i."
        )

        def correction_function(x):
            _func = 0
            for deg, fac in data_dict.items():
                _func = _func + fac * x ** int(deg)
            return _func

        return correction_function
    elif type == "ws_bins":
        assert "ws_bins" in data_dict.keys(), "data_dict must contain key 'ws_bins' with a dict of ws bins and factors."
        if not all(isinstance(ws_bin, Interval) for ws_bin in data_dict["ws_bins"].keys()):
            ws_bins_dict = {}
            for range_str, factor in data_dict["ws_bins"].copy().items():
                left, right = range_str.split("-")
                left = float(left)
                right = float(right) if right != "inf" else np.inf
                ws_bins_dict[Interval(left, right, closed="right")] = factor
            data_dict["ws_bins"] = ws_bins_dict

        # check if all keys are of instance Interval
        assert all(isinstance(ws_bin, Interval) for ws_bin in data_dict["ws_bins"].keys())
        ws_bins_correction = data_dict["ws_bins"]

        def correction_function(x):
            # x is numpy array. modify x based on ws_bins
            corrected_x = x.copy()
            for ws_bin, factor in ws_bins_correction.items():
                mask = (x >= ws_bin.left) & (x < ws_bin.right)
                corrected_x[mask] = x[mask] * (1 - factor)
            return corrected_x

        return correction_function

    elif type == "ws_double_bins":
        if not all(isinstance(ws_bin, Interval) for ws_bin in data_dict.keys()):
            # convert keys to pd.Interval
            def convert_interval(interval):
                left, right = interval.split("-")
                left = float(left)
                right = float(right) if right != "inf" else np.inf
                return Interval(left, right, closed="right")

            ws_bins_correction = {}
            for mean_ws_bin, mean_ws_bin_dict in data_dict.items():
                mean_ws_bin_interval = convert_interval(mean_ws_bin)
                _mean_ws_bin_dict = {}
                for range_str, factor in mean_ws_bin_dict.copy().items():
                    _mean_ws_bin_dict[convert_interval(range_str)] = factor
                ws_bins_correction[mean_ws_bin_interval] = _mean_ws_bin_dict

        def correction_function(x):
            mean_ws = x.mean(axis=0)

            corrected_x = x.copy()
            for mean_ws_bin, mean_ws_bin_dict in ws_bins_correction.items():
                mask_mean_ws = (mean_ws >= mean_ws_bin.left) & (mean_ws < mean_ws_bin.right)
                for ws_bin, factor in mean_ws_bin_dict.items():
                    mask_hourly_ws = (x >= ws_bin.left) & (x < ws_bin.right)
                    corrected_x[mask_mean_ws & mask_hourly_ws] = x[mask_mean_ws & mask_hourly_ws] * (1 - factor)
            return corrected_x

        return correction_function

    else:
        raise ValueError(f"Invalid ws_correction_func type: {type}. Select from: 'polynomial', 'ws_bins'.")

offshore_wind_era5

offshore_wind_era5(**kwargs)

Simulates offshore wind generation using NASA's ERA5 database [1].

Sources

[1] European Centre for Medium-Range Weather Forecasts. (2019). ERA5 dataset. https://www.ecmwf.int/en/forecasts/datasets/reanalysis-datasets/era5.

Source code in reskit/wind/workflows/workflows.py
def offshore_wind_era5(**kwargs):
    """
    Simulates offshore wind generation using NASA's ERA5 database [1].

    Sources
    -------
    [1] European Centre for Medium-Range Weather Forecasts. (2019). ERA5 dataset. https://www.ecmwf.int/en/forecasts/datasets/reanalysis-datasets/era5.

    """
    # this is the commit hash with the latest workflow status
    commit_hash = "379645675cb1b2559ffa8d73c84be0dd0daef55e"
    raise rk_util.RESKitDeprecationError(commit_hash)

offshore_wind_merra_caglayan2019

offshore_wind_merra_caglayan2019(
    placements,
    merra_path,
    output_netcdf_path=None,
    output_variables=None,
    max_batch_size=25000,
)

Simulates offshore wind generation using NASA's MERRA2 database [1].

Parameters:

  • placements

    (pandas Dataframe) –

    A Dataframe object with the parameters needed by the simulation.

  • merra_path

    (str) –

    Path to the MERRA2 data.

  • output_netcdf_path

    (str, default: None ) –

    Path to a directory to put the output files, by default None

  • output_variables

    (str, default: None ) –

    Restrict the output variables to these variables, by default None

  • max_batch_size

    The maximum number of locations to be simulated simultaneously, else multiple batches will be simulated iteratively. Helps limiting RAM requirements but may affect runtime. By default 25 000. Roughly 7GB RAM per 10k locations.

Returns:

  • Dataset

    A xarray dataset including all the output variables you defined as your output variables.

Sources

[1] National Aeronautics and Space Administration. (2019). Modern-Era Retrospective analysis for Research and Applications, Version 2. NASA Goddard Earth Sciences (GES) Data and Information Services Center (DISC). https://disc.gsfc.nasa.gov/datasets?keywords=%22MERRA-2%22&page=1&source=Models%2FAnalyses MERRA-2

Source code in reskit/wind/workflows/workflows.py
def offshore_wind_merra_caglayan2019(
    placements,
    merra_path,
    output_netcdf_path=None,
    output_variables=None,
    max_batch_size=25000,
):
    """
    Simulates offshore wind generation using NASA's MERRA2 database [1].

    Parameters
    ----------
    placements : pandas Dataframe
        A Dataframe object with the parameters needed by the simulation.
    merra_path : str
        Path to the MERRA2 data.
    output_netcdf_path : str, optional
        Path to a directory to put the output files, by default None
    output_variables : str, optional
        Restrict the output variables to these variables, by default None
    max_batch_size: int
        The maximum number of locations to be simulated simultaneously, else multiple batches will be simulated
        iteratively. Helps limiting RAM requirements but may affect runtime. By default 25 000. Roughly 7GB RAM per 10k locations.

    Returns
    -------
    xarray.Dataset
        A xarray dataset including all the output variables you defined as your output variables.

    Sources
    -------
    [1] National Aeronautics and Space Administration. (2019). Modern-Era Retrospective analysis for Research and Applications, Version 2. NASA Goddard Earth Sciences (GES) Data and Information Services Center (DISC). https://disc.gsfc.nasa.gov/datasets?keywords=%22MERRA-2%22&page=1&source=Models%2FAnalyses MERRA-2

    """
    wf = WindWorkflowManager(placements)

    wf.read(
        variables=[
            "elevated_wind_speed",
        ],
        source_type="MERRA",
        source=merra_path,
        set_time_index=True,
        verbose=False,
    )

    wf.set_roughness(0.0002)

    wf.logarithmic_projection_of_wind_speeds_to_hub_height()

    wf.convolute_power_curves(
        scaling=0.04,  # TODO: Check values with Dil
        base=0.5,  # TODO: Check values with Dil
    )

    wf.simulate(max_batch_size=max_batch_size)

    wf.apply_loss_factor(
        loss=lambda x: rk_util.low_generation_loss(x, base=0.1, sharpness=3.5)  # TODO: Check values with Dil
    )

    return wf.to_xarray(output_netcdf_path=output_netcdf_path, output_variables=output_variables)

onshore_wind_era5

onshore_wind_era5(**kwargs)

Simulates onshore wind generation using ECMWF's ERA5 database [1].

Sources

[1] European Centre for Medium-Range Weather Forecasts. (2019). ERA5 dataset. https://www.ecmwf.int/en/forecasts/datasets/reanalysis-datasets/era5

Source code in reskit/wind/workflows/workflows.py
def onshore_wind_era5(**kwargs):
    """
    Simulates onshore wind generation using ECMWF's ERA5 database [1].

    Sources
    -------
    [1] European Centre for Medium-Range Weather Forecasts. (2019). ERA5 dataset. https://www.ecmwf.int/en/forecasts/datasets/reanalysis-datasets/era5
    """
    # this is the commit hash with the latest workflow status
    commit_hash = "379645675cb1b2559ffa8d73c84be0dd0daef55e"
    raise rk_util.RESKitDeprecationError(commit_hash)

onshore_wind_era5_pure_2023

onshore_wind_era5_pure_2023(**kwargs)

Simulates onshore wind generation using pure ECMWF's ERA5 database [1] without further disaggregation or correction besides height projection and power curve convolution.

Sources

[1] European Centre for Medium-Range Weather Forecasts. (2019). ERA5 dataset. https://www.ecmwf.int/en/forecasts/datasets/reanalysis-datasets/era5

Source code in reskit/wind/workflows/workflows.py
def onshore_wind_era5_pure_2023(**kwargs):
    """
    Simulates onshore wind generation using pure ECMWF's ERA5 database [1]
    without further disaggregation or correction besides height projection
    and power curve convolution.

    Sources
    -------
    [1] European Centre for Medium-Range Weather Forecasts. (2019). ERA5 dataset. https://www.ecmwf.int/en/forecasts/datasets/reanalysis-datasets/era5
    """
    # this is the commit hash with the latest workflow status
    commit_hash = "379645675cb1b2559ffa8d73c84be0dd0daef55e"
    raise rk_util.RESKitDeprecationError(commit_hash)

onshore_wind_iconlam_2023

onshore_wind_iconlam_2023(
    placements,
    icon_lam_path,
    esa_cci_path,
    output_netcdf_path=None,
    output_variables=None,
    max_batch_size=25000,
)

Simulates onshore wind generation using high-resolution dynamically downscaled dataset ICON-LAM over southern Africa. This workflow was used in the publicaiton [1].

Parameters:

  • placements

    (pandas Dataframe) –

    A Dataframe object with the parameters needed by the simulation.

  • icon_lam_path

    (str) –

    Path to the specified weather data. May contain '' and ' spacers, in that case, a zoom level value is expected and the correct tiles will be assigned for every loation individually.

  • esa_cci_path

    (str) –

    Path to the ESA CCI raster file [2].

  • output_netcdf_path

    (str, default: None ) –

    Path to a directory to put the output files, by default None

  • output_variables

    (str, default: None ) –

    Restrict the output variables to these variables, by default None

  • max_batch_size

    The maximum number of locations to be simulated simultaneously, else multiple batches will be simulated iteratively. Helps limiting RAM requirements but may affect runtime. By default 20 000.

Returns:

  • Dataset

    A xarray dataset including all the output variables.

Sources

[1] Chen, S., Goergen, K., Hendricks Franssen, H. J., Winkler, C., Poll, S., Houssoukri Zounogo Wahabou, Y., ... & Heinrichs, H. (2024). Higher onshore wind energy potentials revealed by kilometer‐scale atmospheric modeling. Geophysical Research Letters, 51(19), e2024GL110122. https://doi.org/10.1029/2024GL110122 [2] ESA. Land Cover CCI Product User Guide Version 2. Tech. Rep. (2017). Available at: maps.elie.ucl.ac.be/CCI/viewer/download/ESACCI-LC-Ph2-PUGv2_2.0.pdf

Source code in reskit/wind/workflows/workflows.py
def onshore_wind_iconlam_2023(
    placements,
    icon_lam_path,
    esa_cci_path,
    output_netcdf_path=None,
    output_variables=None,
    max_batch_size=25000,
):
    """
    Simulates onshore wind generation using high-resolution dynamically downscaled dataset ICON-LAM over southern Africa.
    This workflow was used in the publicaiton [1].

    Parameters
    ----------
    placements : pandas Dataframe
        A Dataframe object with the parameters needed by the simulation.
    icon_lam_path : str
        Path to the specified weather data.
        May contain '<X-TILE>' and <Y-TILE>' spacers, in that case,
        a zoom level value is expected and the correct tiles will be assigned for every
        loation individually.
    esa_cci_path : str
        Path to the ESA CCI raster file [2].
    output_netcdf_path : str, optional
        Path to a directory to put the output files, by default None
    output_variables : str, optional
        Restrict the output variables to these variables, by default None
    max_batch_size: int
        The maximum number of locations to be simulated simultaneously, else multiple batches will be simulated
        iteratively. Helps limiting RAM requirements but may affect runtime. By default 20 000.


    Returns
    -------
    xarray.Dataset
        A xarray dataset including all the output variables.

    Sources
    -------
    [1] Chen, S., Goergen, K., Hendricks Franssen, H. J., Winkler, C., Poll, S., Houssoukri Zounogo Wahabou, Y., ... & Heinrichs, H. (2024). Higher onshore wind energy potentials revealed by kilometer‐scale atmospheric modeling. Geophysical Research Letters, 51(19), e2024GL110122. https://doi.org/10.1029/2024GL110122
    [2] ESA. Land Cover CCI Product User Guide Version 2. Tech. Rep. (2017). Available at: maps.elie.ucl.ac.be/CCI/viewer/download/ESACCI-LC-Ph2-PUGv2_2.0.pdf
    """
    wf = WindWorkflowManager(placements)

    # read data through wind workflow
    # WindWorkflowManager=rk.wind.WindWorkflowManager
    # wf = WindWorkflowManager(placements)
    # read the variables
    wf.read(
        variables=[
            "elevated_wind_speed",  # by default is a 100m!!
            "surface_pressure",
            "surface_air_temperature",
            "boundary_layer_height",
        ],
        source_type="ICON-LAM",
        source=icon_lam_path,
        set_time_index=True,
        spatial_interpolation_mode="near",
        verbose=False,
    )

    # derive roughness value from land cover type
    wf.estimate_roughness_from_land_cover(path=esa_cci_path, source_type="cci")

    # consider boundary layer height on wind speed value, assume wind speed is all the same in the height
    # that is larger than the height of the boundary layer and is equal to wind speed at the boundary layer height.
    wf.logarithmic_projection_of_wind_speeds_to_hub_height(
        consider_boundary_layer_height=False
    )  # you can change it to True

    # Apply density correction
    wf.apply_air_density_correction_to_wind_speeds()

    # Power curve convolution
    # Ryberg, 2019, Energy: scaling factor of 0.06 and base value of 0.1, by default
    wf.convolute_power_curves(scaling=0.01, base=0.00)

    # simulate wind power
    wf.simulate(max_batch_size=max_batch_size)

    return wf.to_xarray(output_netcdf_path=output_netcdf_path, output_variables=output_variables)

onshore_wind_merra_ryberg2019_europe

onshore_wind_merra_ryberg2019_europe(
    placements,
    merra_path,
    gwa_50m_path,
    clc2012_path,
    output_netcdf_path=None,
    output_variables=None,
    max_batch_size=25000,
)

Simulates onshore wind generation in Europe using NASA's MERRA2 database [1].

Parameters:

  • placements

    (pandas Dataframe) –

    A Dataframe object with the parameters needed by the simulation.

  • merra_path

    (str) –

    Path to the MERRA2 data.

  • gwa_50m_path

    (str) –

    Path to the Global Wind Atlas at 50m [2] rater file.

  • clc2012_path

    (str) –

    Path to the CLC 2012 raster file [3].

  • output_netcdf_path

    (str, default: None ) –

    Path to a directory to put the output files, by default None

  • output_variables

    (str, default: None ) –

    Restrict the output variables to these variables, by default None

  • max_batch_size

    The maximum number of locations to be simulated simultaneously, else multiple batches will be simulated iteratively. Helps limiting RAM requirements but may affect runtime. By default 25 000. Roughly 7GB RAM per 10k locations.

Returns:

  • Dataset

    A xarray dataset including all the output variables you defined as your output variables.

Sources

[1] NASA (National Aeronautics and Space Administration). (2019). Modern-Era Retrospective analysis for Research and Applications, Version 2. NASA Goddard Earth Sciences (GES) Data and Information Services Center (DISC). https://disc.gsfc.nasa.gov/datasets?keywords=%22MERRA-2%22&page=1&source=Models%2FAnalyses MERRA-2 [2] DTU Wind Energy. (2019). Global Wind Atlas. https://globalwindatlas.info/ [3] Copernicus (European Union’s Earth Observation Programme). (2012). Corine Land Cover 2012. Copernicus. https://land.copernicus.eu/pan-european/corine-land-cover/clc-2012

Source code in reskit/wind/workflows/workflows.py
def onshore_wind_merra_ryberg2019_europe(
    placements,
    merra_path,
    gwa_50m_path,
    clc2012_path,
    output_netcdf_path=None,
    output_variables=None,
    max_batch_size=25000,
):
    # TODO: Add range limitation over Europe by checking placements
    """
    Simulates onshore wind generation in Europe using NASA's MERRA2 database [1].

    Parameters
    ----------
    placements : pandas Dataframe
        A Dataframe object with the parameters needed by the simulation.
    merra_path : str
        Path to the MERRA2 data.
    gwa_50m_path : str
        Path to the Global Wind Atlas at 50m [2] rater file.
    clc2012_path : str
        Path to the CLC 2012 raster file [3].
    output_netcdf_path : str, optional
        Path to a directory to put the output files, by default None
    output_variables : str, optional
        Restrict the output variables to these variables, by default None
    max_batch_size: int
        The maximum number of locations to be simulated simultaneously, else multiple batches will be simulated
        iteratively. Helps limiting RAM requirements but may affect runtime. By default 25 000. Roughly 7GB RAM per 10k locations.

    Returns
    -------
    xarray.Dataset
        A xarray dataset including all the output variables you defined as your output variables.

    Sources
    -------
    [1] NASA (National Aeronautics and Space Administration). (2019). Modern-Era Retrospective analysis for Research and Applications, Version 2. NASA Goddard Earth Sciences (GES) Data and Information Services Center (DISC). https://disc.gsfc.nasa.gov/datasets?keywords=%22MERRA-2%22&page=1&source=Models%2FAnalyses MERRA-2
    [2] DTU Wind Energy. (2019). Global Wind Atlas. https://globalwindatlas.info/
    [3] Copernicus (European Union’s Earth Observation Programme). (2012). Corine Land Cover 2012. Copernicus. https://land.copernicus.eu/pan-european/corine-land-cover/clc-2012

    """
    wf = WindWorkflowManager(placements)

    wf.read(
        variables=[
            "elevated_wind_speed",
            "surface_pressure",
            "surface_air_temperature",
        ],
        source_type="MERRA",
        source=merra_path,
        set_time_index=True,
        verbose=False,
    )

    wf.adjust_variable_to_long_run_average(
        variable="elevated_wind_speed",
        source_long_run_average=rk_weather.MerraSource.LONG_RUN_AVERAGE_WINDSPEED,
        real_long_run_average=gwa_50m_path,
    )

    wf.estimate_roughness_from_land_cover(path=clc2012_path, source_type="clc")

    wf.logarithmic_projection_of_wind_speeds_to_hub_height()

    wf.apply_air_density_correction_to_wind_speeds()

    wf.convolute_power_curves(scaling=0.06, base=0.1)

    wf.simulate(max_batch_size=max_batch_size)

    wf.apply_loss_factor(loss=lambda x: rk_util.low_generation_loss(x, base=0.0, sharpness=5.0))

    return wf.to_xarray(output_netcdf_path=output_netcdf_path, output_variables=output_variables)

wind_config

A generic configuration workflow for wind simulations that allows flexible calibration of all arguments used in the workflow. NOTE: Only for calibration/validation purposes!

Parameters:

  • placements

    (pandas Dataframe) –

    A Dataframe object with the parameters needed by the simulation.

  • weather_path

    (str) –

    Path to the temporally resolved weather data, e.g. ERA-5 or MERRA-2 etc.

  • weather_lra_ws_path

    (str) –

    The path to a raster with the corresponding long-run-average windspeeds of the actual weather data (will be corrected to the real lra if given, else weather_lra_path has no effect)

  • enable_lra_adjustment

    (bool) –

    If True, enables the long-run-average adjustment using the provided lra information. Note: If False, all lra related parameters have no effect.

  • real_lra_ws_path

    ((str, float)) –

    Either a float/int (1.0 means no scaling) or a path to a raster with real long-run-average wind speeds, e.g. the Global Wind Atlas at the same height as the weather data.

  • real_lra_ws_scaling

    (float) –

    Accounts for unit differences, set to 1.0 if both weather data and real_lra_ws are in the same unit.

  • real_lra_ws_spatial_interpolation

    (str) –

    The spatial interpolation how the real lra ws shall be extracted, e.g. 'near', 'average', 'linear_spline', 'cubic_spline'

  • real_lra_ws_nodata_fallback

    (str) –

    If no GWA available, use for simulation: (1) float value for a multiple of the 'weather_lra_ws_path' value (ERA5 raw), i.e. 1.0 means weather_lra_ws_path value (2) np.nan for nan output (3) a callable function to be applied to the weather_lra_ws_path (ERA-5) value in the format: nodata_fallback(locs, weather_lra_ws_path_value) (4) a filepath to a raster file containing the fallback values

  • height_scaling_method

    (tuple) –

    The method to project the windspeeds from the default height (here 100m in ERA-5/GWA3) to hub height (possibly affected by the planetary boundary layer height). First tuple entry (str) describes the general approach (e.g. logarithmic scaling or based on long-run-average windspeeds). No height scaling will be applied when None. Options are: ("lra", [vertical method]) : Calculation based on the long-run average wind speeds (e.g. GWA) of the 2 nearest available height levels. [vertical method] (str) describes the form of interpolation. By default "linear". ("log", [landcover]) : Logarithmic height scaling based on surface roughness defined via a mapping of the land cover category. [landcover] (str) defines the landcover data used for roughness mapping. All landcover types accepted as land_cover_type in logarithmic_profile.roughness_from_land_cover_classification() are allowed, by default "cci" (ESA CCI raster).

  • height_scaling_data

    ((str, dict)) –

    The data required for the selected height_scaling_method (see above). The expected data formats are, depending on height_scaling_method: ("log", [landcover]) : str Path to the respective "landcover" raster file. ("lra", [vertical method]) : {int : str} Dict with heights as keys and paths to the LRA-windspeeds at the respective heights as values. Must contain at least one higher and one lower height than the reference height of real_lra_ws_path.

  • ws_correction_func

    An executable function that takes a numpy array as single input argument and returns an adapted windspeed. If 1.0 is passed, no windspeed correction will be applied. Can also be passed as tuple or list of length 2 with data_type (e.g. 'linear' or 'ws_bins') and data dict (dict or path to yaml) with parameters.

  • cf_correction_factor

    ((float, str)) –

    The factor by which the output capacity factors will be corrected indirectly (via corresponding adaptation of the windspeeds). Can be str formatted path to a raster with spatially resolved correction factors, set to 1.0 to not apply any correction.

  • wake_curve

    (str) –

    string value to describe the wake reduction method. None will cause no reduction, by default "dena_mean". Choose from (see more information here under wind_efficiency_curve_name[1]): "dena_mean", "knorr_mean", "dena_extreme1", "dena_extreme2", "knorr_extreme1", "knorr_extreme2", "knorr_extreme3". Alternatively, the 'wake_curve' str can also be provided per each location in a 'wake_curve' column of the placements dataframe, 'wake_curve' argument must then be None.

  • availability_factor

    (float) –

    This factor accounts for all downtimes and applies an average reduction to the output curve, assuming a statistical deviation of the downtime occurrences and a large enough turbine fleet. Suggested availability is 0.98 including technical availability of turbine and connector as well as outages for ecological reasons (e.g. bat protection). This does not include wake effects (see above) or curtailment/outage for economical reasons or transmission grid congestion.

  • consider_boundary_layer_height

    (bool) –

    If True, boundary layer height will be considered.

  • allow_height_extrapolation

    (bool) –

    Takes effect only if a height scaling method based on interpolation is chosen, will then allow or forbid extrapolation beyond the min/max provided height range.

  • power_curve_scaling

    (float) –

    The scaling factor to smoothen the power curve, for details see: convolute_power_curves()

  • power_curve_base

    (float) –

    The base factor to smoothen the power curve, for details see: convolute_power_curves()

  • convolute_power_curves_args

    (dict, default: {} ) –

    Further convolute_power_curve() arguments, for details see: convolute_power_curves(). By default {}.

  • loss_factor_args

    (dict, default: {} ) –

    Arguments that are passed to reskit.utils.low_generation_loss() besides the capacity factor. If empty dict ({}), no loss will be applied. For details see: reskit.utils.loss_factors.low_generation_loss() By default {}.

  • output_variables

    (str, default: None ) –

    Restrict the output variables to these variables, by default None

  • max_batch_size

    The maximum number of locations to be simulated simultaneously, else multiple batches will be simulated iteratively. Helps limiting RAM requirements but may affect runtime. By default 25 000. Roughly 7GB RAM per 10k locations.

  • output_netcdf_path

    (str, default: None ) –

    Path to a directory to put the output files, by default None

Returns:

  • Dataset

    A xarray dataset including all the output variables you defined as your output variables.

Source code in reskit/wind/workflows/workflows.py
def wind_config(
    placements,
    weather_path,
    weather_source_type,
    weather_lra_ws_path,
    enable_lra_adjustment,
    real_lra_ws_path,
    real_lra_ws_scaling,
    real_lra_ws_spatial_interpolation,
    real_lra_ws_nodata_fallback,
    height_scaling_method,
    height_scaling_data,
    ws_correction_func,
    cf_correction_factor,
    wake_curve,
    availability_factor,
    consider_boundary_layer_height,
    allow_height_extrapolation,
    power_curve_scaling,
    power_curve_base,
    convolute_power_curves_args={},
    loss_factor_args={},
    output_variables=None,
    max_batch_size=25000,
    output_netcdf_path=None,
    elevated_wind_speed=None,
):
    """
    A generic configuration workflow for wind simulations that allows
    flexible calibration of all arguments used in the workflow.
    NOTE: Only for calibration/validation purposes!

    Parameters
    ----------
    placements : pandas Dataframe
        A Dataframe object with the parameters needed by the simulation.
    weather_path : str
        Path to the temporally resolved weather data, e.g. ERA-5 or MERRA-2 etc.
    weather_lra_ws_path : str
        The path to a raster with the corresponding long-run-average
        windspeeds of the actual weather data (will be corrected to the
        real lra if given, else weather_lra_path has no effect)
    enable_lra_adjustment : bool
        If True, enables the long-run-average adjustment
        using the provided lra information.
        Note: If False, all lra related parameters have no effect.
    real_lra_ws_path : str, float
        Either a float/int (1.0 means no scaling) or a path to a raster
        with real long-run-average wind speeds, e.g. the Global Wind Atlas
        at the same height as the weather data.
    real_lra_ws_scaling : float
        Accounts for unit differences, set to 1.0 if both weather data and
        real_lra_ws are in the same unit.
    real_lra_ws_spatial_interpolation : str
        The spatial interpolation how the real lra ws shall be extracted,
        e.g. 'near', 'average', 'linear_spline', 'cubic_spline'
    real_lra_ws_nodata_fallback : str, optional
        If no GWA available, use for simulation:
        (1) float value for a multiple of the 'weather_lra_ws_path' value
            (ERA5 raw), i.e. 1.0 means weather_lra_ws_path value
        (2) np.nan for nan output
        (3) a callable function to be applied to the weather_lra_ws_path
            (ERA-5) value in the format:
            nodata_fallback(locs, weather_lra_ws_path_value)
        (4) a filepath to a raster file containing the fallback values
    height_scaling_method : tuple
        The method to project the windspeeds from the default height (here
        100m in ERA-5/GWA3) to hub height (possibly affected by the planetary
        boundary layer height). First tuple entry (str) describes the general
        approach (e.g. logarithmic scaling or based on long-run-average
        windspeeds). No height scaling will be applied when None. Options are:
        ("lra", [vertical method]) : Calculation based on the long-run average
            wind speeds (e.g. GWA) of the 2 nearest available height levels.
            [vertical method] (str) describes the form of interpolation. By
            default "linear".
        ("log", [landcover]) : Logarithmic height scaling based on surface
            roughness defined via a mapping of the land cover category.
            [landcover] (str) defines the landcover data used for roughness
            mapping. All landcover types accepted as land_cover_type in
            logarithmic_profile.roughness_from_land_cover_classification() are
            allowed, by default "cci" (ESA CCI raster).
    height_scaling_data : str, dict
        The data required for the selected height_scaling_method (see above).
        The expected data formats are, depending on height_scaling_method:
        ("log", [landcover]) : str
            Path to the respective "landcover" raster file.
        ("lra", [vertical method]) : {int : str}
            Dict with heights as keys and paths to the LRA-windspeeds at the
            respective heights as values. Must contain at least one higher and
            one lower height than the reference height of real_lra_ws_path.
    ws_correction_func :float, callable, tuple, list
        An executable function that takes a numpy array as single input
        argument and returns an adapted windspeed. If 1.0 is passed, no
        windspeed correction will be applied. Can also be passed as tuple
        or list of length 2 with data_type (e.g. 'linear' or 'ws_bins')
        and data dict (dict or path to yaml) with parameters.
    cf_correction_factor : float, str
        The factor by which the output capacity factors will be corrected
        indirectly (via corresponding adaptation of the windspeeds). Can
        be str formatted path to a raster with spatially resolved correction
        factors, set to 1.0 to not apply any correction.
    wake_curve : str, optional
        string value to describe the wake reduction method. None will
        cause no reduction, by default "dena_mean". Choose from (see more
        information here under wind_efficiency_curve_name[1]): "dena_mean",
        "knorr_mean", "dena_extreme1", "dena_extreme2", "knorr_extreme1",
        "knorr_extreme2", "knorr_extreme3". Alternatively, the
        'wake_curve' str can also be provided per each location in a
        'wake_curve' column of the placements dataframe, 'wake_curve'
        argument must then be None.
    availability_factor : float, optional
        This factor accounts for all downtimes and applies an average reduction to the output curve,
        assuming a statistical deviation of the downtime occurrences and a large enough turbine fleet.
        Suggested availability is 0.98 including technical availability of turbine and connector
        as well as outages for ecological reasons (e.g. bat protection). This does not include wake effects
        (see above) or curtailment/outage for economical reasons or transmission grid congestion.
    consider_boundary_layer_height : bool
        If True, boundary layer height will be considered.
    allow_height_extrapolation : bool
        Takes effect only if a height scaling method based on interpolation is
        chosen, will then allow or forbid extrapolation beyond the min/max
        provided height range.
    power_curve_scaling : float
        The scaling factor to smoothen the power curve, for details see:
        convolute_power_curves()
    power_curve_base : float
        The base factor to smoothen the power curve, for details see:
        convolute_power_curves()
    convolute_power_curves_args : dict, optional
        Further convolute_power_curve() arguments, for details see:
        convolute_power_curves(). By default {}.
    loss_factor_args : dict, optional
        Arguments that are passed to reskit.utils.low_generation_loss()
        besides the capacity factor. If empty dict ({}), no loss will be
        applied. For details see: reskit.utils.loss_factors.low_generation_loss()
        By default {}.
    output_variables : str, optional
        Restrict the output variables to these variables, by default None
    max_batch_size: int
        The maximum number of locations to be simulated simultaneously, else multiple batches will be simulated
        iteratively. Helps limiting RAM requirements but may affect runtime. By default 25 000. Roughly 7GB RAM per 10k locations.
    output_netcdf_path : str, optional
        Path to a directory to put the output files, by default None

    Returns
    -------
    xarray.Dataset
        A xarray dataset including all the output variables you defined as your output variables.
    """
    if isinstance(ws_correction_func, (int, float)):
        import copy

        factor = copy.copy(ws_correction_func)

        def _dummy_corr(x):
            return factor * x

        ws_correction_func = _dummy_corr
    elif isinstance(ws_correction_func, (tuple, list)):
        assert len(ws_correction_func) == 2
        assert isinstance(ws_correction_func[0], str)
        assert isinstance(ws_correction_func[1], (dict, str, list, tuple))

        # generate the actual ws corr func
        ws_correction_func = build_ws_correction_function(
            type=ws_correction_func[0],
            data_dict=ws_correction_func[1],
        )
    assert callable(ws_correction_func), (
        f"ws_correction_func must be an executable with a single argument that can be passed as np.array (if not 1)."
    )
    assert isinstance(enable_lra_adjustment, bool), "enable_lra_adjustment must be boolean."

    wf = WindWorkflowManager(placements)

    wf.read(
        variables=[
            "elevated_wind_speed",
            "surface_pressure",
            "surface_air_temperature",
            "boundary_layer_height",
        ],
        source_type=weather_source_type,
        source=weather_path,
        set_time_index=True,
        verbose=False,
    )

    if enable_lra_adjustment:
        wf.adjust_variable_to_long_run_average(
            variable="elevated_wind_speed",
            source_long_run_average=weather_lra_ws_path,
            real_long_run_average=real_lra_ws_path,
            nodata_fallback=real_lra_ws_nodata_fallback,
            spatial_interpolation=real_lra_ws_spatial_interpolation,
            real_lra_scaling=real_lra_ws_scaling,
        )

    if height_scaling_method is not None:
        if isinstance(height_scaling_method, list):
            # convert to tuple
            height_scaling_method = tuple(height_scaling_method)
        wf.project_windspeeds_to_hub_height(
            height_scaling_method=height_scaling_method,
            height_scaling_data=height_scaling_data,
            consider_boundary_layer_height=consider_boundary_layer_height,
            allow_extrapolation=allow_height_extrapolation,
        )

    # correct wind speeds
    wf.sim_data["elevated_wind_speed"] = ws_correction_func(wf.sim_data["elevated_wind_speed"])

    wf.apply_air_density_correction_to_wind_speeds()

    # do wake reduction if applicable
    wf.apply_wake_correction_of_wind_speeds(wake_curve=wake_curve)

    if elevated_wind_speed is not None:
        print("Using provided elevated_wind_speed")
        wf.sim_data["elevated_wind_speed"] = elevated_wind_speed

    # gaussian convolution of the power curve to account for statistical events in wind speed
    wf.convolute_power_curves(
        scaling=power_curve_scaling,
        base=power_curve_base,
        **convolute_power_curves_args,
    )

    # do simulation
    wf.simulate(cf_correction_factor=cf_correction_factor, max_batch_size=max_batch_size)

    if loss_factor_args != {}:
        wf.apply_loss_factor(loss=lambda x: rk_util.low_generation_loss(x, **loss_factor_args))

    # apply availability factor
    wf.apply_availability_factor(availability_factor=availability_factor)

    return wf.to_xarray(output_netcdf_path=output_netcdf_path, output_variables=output_variables)

wind_era5_2023

wind_era5_2023(**kwargs)

Simulates onshore and offshore (200km from shoreline) wind generation using ECMWF's ERA5 database [1].

Sources

[1] European Centre for Medium-Range Weather Forecasts. (2019). ERA5 dataset. https://www.ecmwf.int/en/forecasts/datasets/reanalysis-datasets/era5

Source code in reskit/wind/workflows/workflows.py
def wind_era5_2023(**kwargs):
    """
    Simulates onshore and offshore (200km from shoreline) wind generation using ECMWF's ERA5 database [1].

    Sources
    -------
    [1] European Centre for Medium-Range Weather Forecasts. (2019). ERA5 dataset. https://www.ecmwf.int/en/forecasts/datasets/reanalysis-datasets/era5
    """
    # this is the commit hash with the latest workflow status
    commit_hash = "379645675cb1b2559ffa8d73c84be0dd0daef55e"
    raise rk_util.RESKitDeprecationError(commit_hash)

wind_era5_PenaSanchezDunkelWinklerEtAl2025

wind_era5_PenaSanchezDunkelWinklerEtAl2025(
    placements,
    era5_path,
    gwa_100m_path,
    height_scaling_data,
    height_scaling_method=("lra", "linear"),
    gwa_nodata_fallback=1.0,
    output_netcdf_path=None,
    cf_correction=True,
    output_variables=None,
    max_batch_size=15000,
    time_slice=None,
    **simulate_kwargs,
)

Simulates wind turbine locations onshore and offshore using ECMWF's ERA5 database [1], with an optional correction loop to ensure that generated capacity factors for historic wind fleets meet reported generation/capacity based on Renewables Market Report [2] by the International Energy Agency (IEA).

Please cite the following publication when using the workflow [3]: Peña-Sánchez, Dunkel, Winkler et al. (2025): Towards high resolution, validated and open global wind power assessments. https://doi.org/10.48550/arXiv.2501.07937

Parameters:

  • placements

    (pandas Dataframe) –

    A Dataframe object with the parameters needed by the simulation.

  • era5_path

    (str) –

    Path to the ERA5 data.

  • gwa_100m_path

    (str) –

    Path to the Global Wind Atlas v4 (GWA4) at 100m [4] raster file.

  • height_scaling_data

    (dict | str) –

    The data required for the height_scaling_method. If height_scaling_method[0] (below) is "lra" (e.g. ("lra", "linear"), see default), a dict with integer heights as keys and str paths to the Global Wind Atlas windspeeds [4] at the respective heights as values is expected. Must contain at least one higher and one lower height than 100 [m] then. If height_scaling_method[0] (below) is "log", then a str filepath to the defined landcover raster is expected.

  • height_scaling_method

    (tuple | list | None, default: ('lra', 'linear') ) –

    The method to project the windspeeds from the default height (here 100m in ERA-5/GWA4) to hub height (possibly affected by the planetary boundary layer height). First tuple/list entry (str) describes the general approach (e.g. logarithmic scaling or based on long-run-average windspeed interpolation). Options are: ("lra", [vertical method]) : Calculation based on the long-run average wind speeds (e.g. GWA) of the 2 nearest available height levels. [vertical method] (str) describes the form of interpolation, e.g. "linear". ("lra", "linear") was used for publication [3]. ("log", [landcover]) : Logarithmic height scaling based on surface roughness defined via a mapping of the land cover category. [landcover] (str) defines the landcover data used for roughness mapping. All landcover types accepted as land_cover_type in logarithmic_profile.roughness_from_land_cover_classification() are allowed.. None : No height scaling will be applied when None. By default ("lra", "linear").

  • gwa_nodata_fallback

    (str, default: 1.0 ) –

    If no GWA data is available, use for simulation: (1) float value for a multiple of the respective ERA-5 value (ERA5 raw), i.e. 1.0 means fall back on unscaled ERA-5 value (2) np.nan for nan output (3) a callable function to be applied to the ERA-5 value in the format: nodata_fallback(locs, ERA5_value) (4) a filepath to a raster file containing the fallback values

  • output_netcdf_path

    (str, default: None ) –

    Path to a directory to put the output files, by default None

  • cf_correction

    (bool, default: True ) –

    If False, the capacity factors will be calculated based on a calibrated physical model only, else an additional correction step will be added to ensure that historic capacity factors based on [2] are met if historic wind fleets are simulated. By default True.

  • output_variables

    (str, default: None ) –

    Restrict the output variables to these variables, by default None

  • max_batch_size

    The maximum number of locations to be simulated simultaneously, else multiple batches will be simulated iteratively. Helps limiting RAM requirements but may affect runtime. Should be adapted to individual computation system (roughly 7GB RAM per 10k locations), by default 25 000.

  • time_slice

    (slice, default: None ) –

    Limit the time span loaded from the ERA5 source. Only supported for Zarr-backed ERA5 sources, where it is strongly recommended to avoid loading whole multi-year cloud stores. Raises for netCDF4-backed ERA5 sources; support for those is planned.

  • simulate_kwargs

    (optional, default: {} ) –

    Will be passed on to simulate().

Returns:

  • Dataset

    A xarray dataset including all the output variables you defined as your output variables.

Sources

[1] European Centre for Medium-Range Weather Forecasts. (2019). ERA5 dataset. https://www.ecmwf.int/en/forecasts/datasets/reanalysis-datasets/era5 [2] International Energy Agency. (2023). Renewables Market Report. https://www.iea.org/reports/renewables-2023 [3] Peña-Sánchez, Dunkel, Winkler et al. (2025): Towards high resolution, validated and open global wind power assessments. https://doi.org/10.48550/arXiv.2501.07937 [4] DTU Wind Energy. (2025). Global Wind Atlas v4. https://globalwindatlas.info/

Source code in reskit/wind/workflows/workflows.py
def wind_era5_PenaSanchezDunkelWinklerEtAl2025(
    placements,
    era5_path,
    gwa_100m_path,
    height_scaling_data,
    height_scaling_method=("lra", "linear"),
    gwa_nodata_fallback=1.0,
    output_netcdf_path=None,
    cf_correction=True,
    output_variables=None,
    max_batch_size=15000,
    time_slice=None,
    **simulate_kwargs,
):
    """
    Simulates wind turbine locations onshore and offshore using ECMWF's
    ERA5 database [1], with an optional correction loop to ensure that
    generated capacity factors for historic wind fleets meet reported
    generation/capacity based on Renewables Market Report [2] by the
    International Energy Agency (IEA).

    Please cite the following publication when using the workflow [3]:
    Peña-Sánchez, Dunkel, Winkler et al. (2025): Towards high resolution,
    validated and open global wind power assessments.
    https://doi.org/10.48550/arXiv.2501.07937

    Parameters
    ----------
    placements : pandas Dataframe
        A Dataframe object with the parameters needed by the simulation.
    era5_path : str
        Path to the ERA5 data.
    gwa_100m_path : str
        Path to the Global Wind Atlas v4 (GWA4) at 100m [4] raster file.
    height_scaling_data : dict | str
        The data required for the height_scaling_method. If height_scaling_method[0]
        (below) is "lra" (e.g. ("lra", "linear"), see default), a dict with integer
        heights as keys and str paths to the Global Wind Atlas windspeeds [4] at the
        respective heights as values is expected. Must contain at least one higher
        and one lower height than 100 [m] then. If height_scaling_method[0] (below)
        is "log", then a str filepath to the defined landcover raster is expected.
    height_scaling_method : tuple | list | None, optional
        The method to project the windspeeds from the default height (here
        100m in ERA-5/GWA4) to hub height (possibly affected by the planetary
        boundary layer height). First tuple/list entry (str) describes the
        general approach (e.g. logarithmic scaling or based on long-run-average
        windspeed interpolation). Options are:
        ("lra", [vertical method]) : Calculation based on the long-run average
            wind speeds (e.g. GWA) of the 2 nearest available height levels.
            [vertical method] (str) describes the form of interpolation, e.g.
            "linear". ("lra", "linear") was used for publication [3].
        ("log", [landcover]) : Logarithmic height scaling based on surface
            roughness defined via a mapping of the land cover category.
            [landcover] (str) defines the landcover data used for roughness
            mapping. All landcover types accepted as land_cover_type in
            logarithmic_profile.roughness_from_land_cover_classification() are
            allowed..
        None : No height scaling will be applied when None.
        By default ("lra", "linear").
    gwa_nodata_fallback : str, optional
        If no GWA data is available, use for simulation:
        (1) float value for a multiple of the respective ERA-5 value
            (ERA5 raw), i.e. 1.0 means fall back on unscaled ERA-5 value
        (2) np.nan for nan output
        (3) a callable function to be applied to the ERA-5 value in the format:
            nodata_fallback(locs, ERA5_value)
        (4) a filepath to a raster file containing the fallback values
    output_netcdf_path : str, optional
        Path to a directory to put the output files, by default None
    cf_correction : bool, optional
        If False, the capacity factors will be calculated based on a
        calibrated physical model only, else an additional correction
        step will be added to ensure that historic capacity factors based
        on [2] are met if historic wind fleets are simulated. By default
        True.
    output_variables : str, optional
        Restrict the output variables to these variables, by default None
    max_batch_size: int
        The maximum number of locations to be simulated simultaneously,
        else multiple batches will be simulated iteratively. Helps
        limiting RAM requirements but may affect runtime. Should be
        adapted to individual computation system (roughly 7GB RAM per
        10k locations), by default 25 000.
    time_slice : slice, optional
        Limit the time span loaded from the ERA5 source. Only supported for
        Zarr-backed ERA5 sources, where it is strongly recommended to avoid
        loading whole multi-year cloud stores. Raises for netCDF4-backed ERA5
        sources; support for those is planned.
    simulate_kwargs : optional
        Will be passed on to simulate().

    Returns
    -------
    xarray.Dataset
        A xarray dataset including all the output variables you defined as your output variables.

    Sources
    -------
    [1] European Centre for Medium-Range Weather Forecasts. (2019). ERA5 dataset. https://www.ecmwf.int/en/forecasts/datasets/reanalysis-datasets/era5
    [2] International Energy Agency. (2023). Renewables Market Report. https://www.iea.org/reports/renewables-2023
    [3] Peña-Sánchez, Dunkel, Winkler et al. (2025): Towards high resolution, validated and open global wind power assessments. https://doi.org/10.48550/arXiv.2501.07937
    [4] DTU Wind Energy. (2025). Global Wind Atlas v4. https://globalwindatlas.info/
    """
    # default data used as per [3]
    ws_correction_func = (
        "ws_bins",
        os.path.join(DATAFOLDER, f"ws_correction_factors_PSDW2025.yaml"),
    )
    cf_correction_factor = os.path.join(DATAFOLDER, f"cf_correction_factors_PSDW2025.tif")
    wake_curve = "dena_mean"
    availability_factor = 0.98
    era5_lra_path = rk_weather.Era5Source.LONG_RUN_AVERAGE_WINDSPEED_2008TO2017

    # initialize wf manager instance
    wf = WindWorkflowManager(placements)

    # read data
    wf.read(
        variables=[
            "elevated_wind_speed",
            "surface_pressure",
            "surface_air_temperature",
            "boundary_layer_height",
        ],
        source_type="ERA5",
        source=era5_path,
        time_slice=time_slice,
        set_time_index=True,
        verbose=False,
    )

    # adjust hourly wind speeds based on ERA-5 LRA and GWA
    wf.adjust_variable_to_long_run_average(
        variable="elevated_wind_speed",
        source_long_run_average=era5_lra_path,
        real_long_run_average=gwa_100m_path,
        nodata_fallback=gwa_nodata_fallback,
        spatial_interpolation="average",
    )

    # project the windspeeds to the respective hub heights
    wf.project_windspeeds_to_hub_height(
        height_scaling_method=height_scaling_method,
        height_scaling_data=height_scaling_data,
        consider_boundary_layer_height=True,
    )

    # generate the actual ws corr func and correct wind speeds
    ws_correction_func = build_ws_correction_function(
        type=ws_correction_func[0],
        data_dict=ws_correction_func[1],
    )
    wf.sim_data["elevated_wind_speed"] = ws_correction_func(wf.sim_data["elevated_wind_speed"])

    # apply air density correction
    wf.apply_air_density_correction_to_wind_speeds()
    # do wake reduction
    wf.apply_wake_correction_of_wind_speeds(wake_curve=wake_curve)
    # gaussian convolution of the power curve to account for statistical events in wind speed
    wf.convolute_power_curves(
        scaling=0.01,  # standard deviation of gaussian equals scaling*v + base
        base=0.00,  # values are derived from validation with real wind turbine data
    )

    # do simulation
    if not cf_correction:
        # set cf correction factor to 1.0, i.e. do not correct
        cf_correction_factor = 1.0
    wf.simulate(
        cf_correction_factor=cf_correction_factor,
        max_batch_size=max_batch_size,
        **simulate_kwargs,
    )

    # apply availability factor
    wf.apply_availability_factor(availability_factor=availability_factor)

    return wf.to_xarray(output_netcdf_path=output_netcdf_path, output_variables=output_variables)