Chris Parmer — home

A single turbine's wake, from the side

PyWake vertical flow map through one V80

Example from a field guide to quiver · shared helpers

A single turbine's wake, from the side — PyWake vertical flow map through one V80

Python Code

"""A single turbine's wake, from the side — PyWake vertical flow map through one V80."""
import warnings
from pathlib import Path

from _shared import save, themed_layout, TEXT, MUTED, VIOLET, PINK

import numpy as np

warnings.filterwarnings("ignore")
from py_wake.examples.data.hornsrev1 import Hornsrev1Site, V80
from py_wake.flow_map import XZGrid
from py_wake.literature.gaussian_models import Bastankhah_PorteAgel_2014
from py_wake.site.shear import PowerShear

CHART_NUM = 16

WS = 8.0          # m/s at hub height
HUB = 70.0        # V80 hub height (m)
D = 80.0          # rotor diameter (m)


def generate():
    print("running PyWake, single V80, vertical slice …")
    # Power-law shear: the sea slows the wind near the surface
    site = Hornsrev1Site(shear=PowerShear(h_ref=HUB, alpha=0.12))
    wfm = Bastankhah_PorteAgel_2014(site, V80(), k=0.0324555)
    sim = wfm([0], [0], wd=270, ws=WS)

    # Effective wind speed on a vertical plane through the rotor axis
    gx = np.arange(-240, 1020, 32.0)      # downwind distance (m)
    gz = np.arange(8, 214, 8.0)           # height above the sea (m)
    fm = sim.flow_map(XZGrid(y=0, x=gx, z=gz))
    ws_eff = np.asarray(fm.WS_eff).squeeze()      # shape (len(gz), len(gx))
    print(f"  flow map {ws_eff.shape} · {ws_eff.min():.1f}–{ws_eff.max():.1f} m/s")

    GX, GZ = np.meshgrid(gx, gz)
    arrows = {
        "type": "quiver",
        "x": GX.ravel().tolist(),
        "y": GZ.ravel().tolist(),
        "u": ws_eff.ravel().tolist(),     # purely horizontal flow
        "v": np.zeros(ws_eff.size).tolist(),
        "arrowref": "paper",
        "lengthmode": "scaled",
        # keep the longest arrow well under the column spacing, so arrows
        # never run tip-to-tail and the lengths stay readable
        "lengthfactor": 0.8,
        # no color array → arrows color by |(u,v)|, i.e. the wind speed:
        # pink in the wake hole, violet mid-recovery, slate at full speed
        "marker": {
            "colorscale": [[0.0, PINK], [0.55, VIOLET], [1.0, "#55616e"]],
            "cmin": 3.0,
            "cmax": float(np.ceil(ws_eff.max() * 10) / 10),
            "showscale": True,
            "colorbar": {"title": {"text": "m/s"}, "thickness": 12, "len": 0.7},
            "arrowsize": 0.6,   # smaller heads, so the shaft carries the length
            "line": {"width": 1.7},
        },
        "customdata": [
            f"{s:.1f} m/s · {z:.0f} m up" for s, z in zip(ws_eff.ravel(), GZ.ravel())
        ],
        "hovertemplate": "%{customdata}<extra></extra>",
        "showlegend": False,
    }

    # The machine itself: tower, nacelle, and the rotor swept area
    tower = {
        "type": "scatter",
        "x": [0, 0], "y": [0, HUB],
        "mode": "lines",
        "line": {"color": MUTED, "width": 3},
        "hoverinfo": "skip", "showlegend": False,
    }
    rotor = {
        "type": "scatter",
        "x": [0, 0], "y": [HUB - D / 2, HUB + D / 2],
        "mode": "lines",
        "line": {"color": TEXT, "width": 5},
        "customdata": ["Vestas V80 · rotor 30–110 m"] * 2,
        "hovertemplate": "%{customdata}<extra></extra>",
        "showlegend": False,
    }
    nacelle = {
        "type": "scatter",
        "x": [0], "y": [HUB],
        "mode": "markers",
        "marker": {"color": TEXT, "size": 9},
        "hoverinfo": "skip", "showlegend": False,
    }

    layout = themed_layout(
        xaxis={
            "title": {"text": "distance downwind (m)", "font": {"color": MUTED}},
            "zeroline": False,
            "range": [-260, 1030],
        },
        yaxis={
            "title": {"text": "height (m)", "font": {"color": MUTED}},
            "zeroline": False,
            "range": [-14, 224],
        },
        shapes=[
            # the sea surface
            {"type": "rect", "x0": -260, "x1": 1030, "y0": -14, "y1": 0,
             "fillcolor": "#e8f2f7", "line": {"width": 0}},
            {"type": "line", "x0": -260, "x1": 1030, "y0": 0, "y1": 0,
             "line": {"color": "#9db8c8", "width": 1.5}},
        ],
        annotations=[
            {"x": -240, "y": 212, "text": "sheared inflow →",
             "showarrow": False, "font": {"color": MUTED, "size": 12},
             "xanchor": "left"},
            {"x": 990, "y": 212, "text": "one rotor diameter = 80 m",
             "showarrow": False, "font": {"color": MUTED, "size": 12},
             "xanchor": "right"},
        ],
    )
    save(CHART_NUM, {"data": [arrows, tower, rotor, nacelle], "layout": layout})

Made with Plotly