Wind Climate Formats#

.tab - Binned Wind Climate#

Text format storing wind speed frequency distributions per sector.

Functions: read_tab(), write_tab(), format_tab()

Normalization: read_tab returns frequencies normalized to 0-1. write_tab and format_tab accept 0-1 values and convert to per-mille (wsfreq) and percent (wdfreq) for the file format.

Return structure:

{
    "wsfreq": np.ndarray,    # (n_wsbins, n_sectors) - wind speed frequencies (0-1)
    "wdfreq": np.ndarray,    # (n_sectors,) - direction frequencies (0-1)
    "wsbins": np.ndarray,    # (n_wsbins + 1,) - bin edges
    "coords": {
        "south_north": float,
        "west_east": float,
        "height": float,
    },
    "metadata": {"description": str},
}

Example:

from windkit.io.wasp import read_tab, write_tab, format_tab

# Read
data = read_tab("measurements.tab")
print(data["wsfreq"].shape)  # (30, 12) for 30 bins, 12 sectors
print(data["wdfreq"].sum())  # Close to 1.0

# Write
write_tab("output.tab",
          data["wsfreq"], data["wdfreq"], data["wsbins"],
          data["coords"], data["metadata"])

# Format as string (without writing to file)
tab_string = format_tab(
    data["wsfreq"], data["wdfreq"], data["wsbins"],
    data["coords"], data["metadata"])

.owc / .omwc - Observed Wind Climate#

XML format for observed wind climate data from measurements. Stores wind speed frequency distributions per sector, similar to .tab but in XML.

Functions: read_owc(), parse_owc_element()

Normalization: read_owc returns frequencies as stored in the XML (0-1).

Return structure:

{
    "wsfreq": np.ndarray,    # (n_wsbins, n_sectors) - wind speed frequencies (0-1)
    "wdfreq": np.ndarray,    # (n_sectors,) - direction frequencies (0-1)
    "wsbins": np.ndarray,    # (n_wsbins + 1,) - bin edges
    "coords": {
        "south_north": float,
        "west_east": float,
        "height": float,
    },
    "metadata": {"description": str},
}

Example:

from windkit.io.wasp import read_owc

# Read
data = read_owc("observed.omwc")
print(data["wsfreq"].shape)  # (30, 12) for 30 bins, 12 sectors
print(data["wdfreq"].sum())  # Close to 1.0

Note

The .owc and .omwc formats are read-only. There is no write_owc function; use write_tab() to export binned wind climate data.

.lib - Generalized Wind Climate Library#

Text format for generalized wind climate with Weibull parameters across multiple roughness classes and heights.

Functions: read_lib(), write_lib(), format_lib()

Normalization: read_lib returns wdfreq normalized to 0-1. write_lib and format_lib accept 0-1 values and convert to percent for the file format. A and k are raw Weibull parameters.

Return structure:

{
    "A": np.ndarray,              # (n_sectors, n_heights, n_roughnesses) - Weibull scale
    "k": np.ndarray,              # (n_sectors, n_heights, n_roughnesses) - Weibull shape
    "wdfreq": np.ndarray,         # (n_sectors, n_roughnesses) - direction freq (0-1)
    "gen_roughness": np.ndarray,  # (n_roughnesses,) - roughness classes
    "gen_height": np.ndarray,     # (n_heights,) - generalized heights
    "coords": {
        "south_north": float or None,
        "west_east": float or None,
        "height": float or None,
    },
    "metadata": {"description": str},
}

Example:

from windkit.io.wasp import read_lib, write_lib, format_lib

# Read
data = read_lib("climate.lib")
print(data["A"].shape)       # (12, 5, 5) for 12 sectors, 5 heights, 5 roughnesses
print(data["wdfreq"].sum(axis=0))  # Close to 1.0 per roughness class

# Write
write_lib("output.lib",
          data["A"], data["k"], data["wdfreq"],
          data["gen_roughness"], data["gen_height"],
          data["coords"], data["metadata"])

# Format as string (without writing to file)
lib_string = format_lib(
    data["A"], data["k"], data["wdfreq"],
    data["gen_roughness"], data["gen_height"],
    data["coords"], data["metadata"])

.rsf / .wrg - Resource Grid#

Fixed-width text format storing, for each site in a set of sites, the location, height, sector-wise and combined Weibull wind climate, and a power column. A .wrg file is a .rsf file with one extra header line describing the regular grid (Nx Ny Xmin Ymin cell_size); both are handled by the same functions, and the header is detected automatically on read.

Functions: read_rsf(), write_rsf(), format_rsf()

Normalization: the sector-wise values are descaled on read and rescaled on write by the format’s fixed factors — A by 10, k by 100 and wdfreq by 1000 (per mille to 0-1 fractions). The power column is returned raw: the file does not record whether it holds power density [W/m2] or power production [Wh/y], so interpreting it is left to the caller.

Return structure:

{
    "name": np.ndarray,        # (n_points,) - site names
    "coords": {
        "west_east": np.ndarray,    # (n_points,)
        "south_north": np.ndarray,  # (n_points,)
        "height": np.ndarray,       # (n_points,)
    },
    "site_elev": np.ndarray,   # (n_points,) - site elevation [m]
    "A": np.ndarray,           # (n_points, n_sectors) - Weibull scale [m/s]
    "k": np.ndarray,           # (n_points, n_sectors) - Weibull shape
    "wdfreq": np.ndarray,      # (n_points, n_sectors) - direction freq (0-1)
    "A_combined": np.ndarray,  # (n_points,) - total-distribution Weibull scale
    "k_combined": np.ndarray,  # (n_points,) - total-distribution Weibull shape
    "power": np.ndarray,       # (n_points,) - power column, raw
    "header": dict or None,    # {"nx", "ny", "xmin", "ymin", "cell_size"}
}

Example:

from windkit.io.wasp import read_rsf, write_rsf, format_rsf

# Read (.rsf and .wrg alike)
data = read_rsf("resource.wrg")
print(data["A"].shape)   # (n_points, n_sectors)
print(data["header"])    # grid header dict, or None for a plain .rsf

# Write (pass header=... to produce a .wrg grid header line)
write_rsf("output.wrg",
          data["A"], data["k"], data["wdfreq"],
          data["A_combined"], data["k_combined"],
          data["power"], data["site_elev"], data["coords"],
          name=data["name"], header=data["header"])

# Format as string (without writing to file)
rsf_string = format_rsf(
    data["A"], data["k"], data["wdfreq"],
    data["A_combined"], data["k_combined"],
    data["power"], data["site_elev"], data["coords"])

.gwc - Generalized Wind Climate (XML)#

XML format for a generalized wind climate at one location: Weibull parameters and sector frequencies on a grid of reference roughness lengths and reference heights. WAsP writes the RveaGeneralisedMeanWindClimate element either as the document root or nested inside a WaspHierarchyMember, and identifies a wind rose’s grid cell by number, by value, or by number with the values listed once in a StandardConditions element; all of these are read. The grid must be complete: a cell without a wind rose, a cell with two, or a rose missing a sector raises ValueError rather than coming out as zeros.

Functions: read_gwc(), parse_gwc_element()

Normalization: read_gwc returns wdfreq normalized to 0-1 along the sector axis, like read_lib. Unlike .lib, the format stores a sector frequency per (height, roughness) cell, so wdfreq is 3-D. A and k are raw Weibull parameters.

Coordinates: the element may embed a RveaLatitudeLongitudeCoordinate and a Description; read_gwc also falls back to a RveaAnemometerSiteDetails element anywhere in the file, which is where a WAsP-exported hierarchy keeps the mast position and height. Anything still unknown is None. parse_gwc_element reads the element only.

Return structure:

{
    "A": np.ndarray,              # (n_sectors, n_heights, n_roughnesses) - Weibull scale
    "k": np.ndarray,              # (n_sectors, n_heights, n_roughnesses) - Weibull shape
    "wdfreq": np.ndarray,         # (n_sectors, n_heights, n_roughnesses) - direction freq (0-1)
    "sector": np.ndarray,         # (n_sectors,) - sector centre angles in degrees
    "gen_roughness": np.ndarray,  # (n_roughnesses,) - roughness classes
    "gen_height": np.ndarray,     # (n_heights,) - generalized heights
    "coords": {
        "south_north": float or None,
        "west_east": float or None,
        "height": float or None,
    },
    "metadata": {"description": str or None},
    # The mesoscale climate the generalization used; None when absent
    "barometric_reference": dict or None,  # reference air density conditions
    "stability_inputs": dict or None,      # (n_sectors,) arrays, WAsP 12.8+
    "geostrophic_shear": dict or None,     # (n_sectors,) arrays, WAsP 12.8+
}

The keys of the three mesoscale climate dicts are listed in parse_gwc_element() and use the variable names PyWAsP uses. For a generalized wind climate in a WAsP workspace, windkit.Workspace.get_mesoclimate() returns the stability inputs and geostrophic shear as a dataset ready to pass to PyWAsP, and windkit.Workspace.get_air_density_reference() returns the barometric reference.

Example:

from windkit.io.wasp import read_gwc

data = read_gwc("climate.gwc")
print(data["A"].shape)             # (12, 5, 5) for 12 sectors, 5 heights, 5 roughnesses
print(data["wdfreq"].sum(axis=0))  # 1.0 in every (height, roughness) cell

Note

The .gwc format is read-only. There is no write_gwc function. To export as .lib, pass write_lib() a 2-D wdfreq – one height’s slice, e.g. data["wdfreq"][:, 0, :] – since .lib stores one frequency per roughness.