Latest Threat Research:SANDWORM_MODE: Shai-Hulud-Style npm Worm Hijacks CI Workflows and Poisons AI Toolchains.Details
Socket
Book a DemoInstallSign in
Socket

py-wake

Package Overview
Dependencies
Maintainers
2
Versions
40
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

py-wake - npm Package Compare versions

Comparing version
2.6.12
to
2.6.13
+40
py_wake/tests/test_utils/test_most.py
import pytest
from py_wake import np
from py_wake.tests import npt
from py_wake.utils.most import phi, psi, phi_eps
def test_phi():
zeta = np.linspace(-.1, .1, 11)
# print(list(np.round(phi(zeta), 3)))
if 0:
plt.plot(zeta, phi(zeta))
plt.show()
npt.assert_array_almost_equal(phi(zeta), [0.764, 0.792, 0.825, 0.867, 0.922, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5], 3)
def test_psi():
zeta = np.linspace(-.1, .1, 51)
# print(list(np.round(psi(zeta[::5]), 3)))
# print(list(np.round(psi(zeta[::5], 'Wilson'), 3)))
if 0:
plt.plot(zeta, psi(zeta))
plt.plot(zeta, psi(zeta, 'Wilson'), label='Wilson')
plt.legend()
plt.show()
npt.assert_array_almost_equal(psi(zeta[::5]),
[0.326, 0.276, 0.221, 0.159, 0.087, 0.0, -0.1, -0.2, -0.3, -0.4, -0.5], 3)
npt.assert_array_almost_equal(psi(zeta[::5], 'Wilson'),
[2.541, 2.488, 2.427, 2.355, 2.261, 0.0, -0.1, -0.2, -0.3, -0.4, -0.5], 3)
def test_phi_eps():
zeta = np.linspace(-.1, .1, 11)
# print(list(np.round(phi_eps(zeta), 3)))
if 0:
plt.plot(zeta, phi_eps(zeta))
plt.show()
npt.assert_array_almost_equal(phi_eps(zeta), [1.1, 1.08, 1.06, 1.04, 1.02, 1.0, 1.08, 1.16, 1.24, 1.32, 1.4], 3)
from py_wake import np
def phi(zeta, Cm1=5, Cm2=-19.3):
"""
Monin-Obukhov Similarity Theory function of normalized wind shear
"""
zeta = np.atleast_1d(zeta)
e = np.where((zeta <= 0), -.25, 1) # avoid warning when Cm2*zeta<-1
return np.where(zeta <= 0, (1 + Cm2 * zeta)**e, 1 + Cm1 * zeta)
def psi(zeta, unstable='', Cm1=5, Cm2=-19.3):
"""
Monin-Obukhov Similarity Theory function of integrated normalized wind shear
"""
zeta = np.atleast_1d(zeta)
aux = phi(zeta, Cm1=Cm1, Cm2=Cm2)**-1
if unstable == 'Wilson':
psi_n = np.where(
zeta < 0,
3 * np.log(1 + np.sqrt(1 + 3.6 * np.abs(zeta)**(2.0 / 3.0))),
1.0 - 1.0 / aux
)
else:
aux2 = (1.0 + aux)**2 * (1 + aux**2)
rhs = -np.log(8.0 / aux2) - 2.0 * np.arctan(Cm2 * zeta / aux2)
psi_n = np.where(zeta < 0, rhs, 1.0 - 1.0 / aux)
psi_n = np.where(zeta == 0, 0.0, psi_n)
return psi_n
def phi_eps(zeta, Cm1=5):
"""
Monin-Obukhov Similarity Theory function of normalized dissipation of turbulent kinetic energy
"""
zeta = np.atleast_1d(zeta)
return np.where(zeta <= 0, 1.0 - zeta, 1.0 + (Cm1 - 1) * zeta)
+1
-1
Metadata-Version: 2.4
Name: py_wake
Version: 2.6.12
Version: 2.6.13
Summary: Open source static wake modeling framework from DTU

@@ -5,0 +5,0 @@ Author: DTU Wind Energy

@@ -547,3 +547,3 @@ from numpy import newaxis as na

sigma_ijlk = self.sigma_ijlk(D_src_il=D_src_il, dw_ijlk=dw_ijlk, ct_ilk=ct_ilk, **kwargs)
return 2. * sigma_ijlk
return 2. * sigma_ijlk * D_src_il[:, na, :, na]

@@ -550,0 +550,0 @@

@@ -43,2 +43,4 @@ # -*- coding: utf-8 -*-

method=method,
ws_cutin=3.,
ws_cutout=25.,
),

@@ -52,3 +54,3 @@ )

print('Hub height', wt.hub_height())
ws = np.arange(3, 25)
ws = np.arange(0., 30.)
import matplotlib.pyplot as plt

@@ -55,0 +57,0 @@ plt.plot(ws, wt.power(ws), '.-', label='power [W]')

from py_wake import np
from py_wake.utils.most import phi, psi, phi_eps
from numpy import newaxis as na

@@ -38,7 +39,10 @@ from abc import abstractmethod, ABC

class LogShear(Shear):
def __init__(self, h_ref=100, z0=.03, interp_method='nearest'):
class MOSTShear(Shear):
def __init__(self, h_ref=100, z0=.03, h_zeta=0.0, Cm1=5.0, Cm2=-19.3, interp_method='nearest'):
self.h_ref = h_ref
from py_wake.site._site import get_sector_xr
self.z0 = get_sector_xr(z0, "Roughness length")
self.h_zeta = h_zeta
self.Cm1 = Cm1
self.Cm2 = Cm2
self.interp_method = interp_method

@@ -49,5 +53,10 @@

z0 = self.z0.interp_ilk(localWind.coords, interp_method=self.interp_method)
return np.log(h[:, na, na] / z0) / np.log(self.h_ref / z0) * WS_ilk
L_inv = self.h_zeta / self.h_ref # 1 / Obukhov length
return (np.log(h[:, na, na] / z0) - psi(h[:, na, na] * L_inv, Cm1=self.Cm1, Cm2=self.Cm2)) / (np.log(self.h_ref / z0) - psi(self.h_zeta, Cm1=self.Cm1, Cm2=self.Cm2)) * WS_ilk
class LogShear(MOSTShear):
def __init__(self, h_ref=100, z0=.03, interp_method='nearest'):
MOSTShear.__init__(self, h_ref=h_ref, z0=z0, interp_method=interp_method)
# ======================================================================================================================

@@ -54,0 +63,0 @@ # Potentially the code below can be used to implement power/log shear interpolation between grid layers

@@ -101,11 +101,11 @@ import pytest

(BlondelSuperGaussianDeficit2020(),
(338236.360935599, [8184.10433669, 7688.07418809, 11210.94605493, 13517.06684326,
18220.2151193, 24405.81513366, 38658.43467216, 39081.04378946,
20623.94292847, 12206.04086561, 14690.26714648, 31821.77172395,
61172.26772292, 17636.16264219, 12053.55253044, 7066.65523799])),
(338152.7016942268, [8189.0455, 7674.43768, 11216.04157, 13506.83034, 18220.11534,
24387.33256, 38676.00541, 39011.72486, 20636.39466, 12230.83007,
14672.93813, 31809.40211, 61171.95556, 17629.30719, 12039.33385,
7081.00688])),
(BlondelSuperGaussianDeficit2023(),
(355892.77826332045, [8979.31725425, 8180.44857196, 11292.09175721, 13964.6406542,
20066.69629875, 25213.93451452, 38938.24743865, 41583.94690748,
22627.8794807, 12933.21646472, 14824.4675625, 32363.56815599,
67336.57050905, 17936.43536356, 12163.66569231, 7487.65163747]))
(356158.2866576972, [9017.94626, 8157.37254, 11335.5033, 13956.83138, 20062.42899,
25199.83443, 39087.94241, 41466.64377, 22725.22458, 13069.53946,
14778.90386, 32362.67185, 67308.64964, 17935.93862, 12126.28009,
7566.57547]))
])

@@ -272,2 +272,3 @@ def test_IEA37_ex16(deficitModel, aep_ref):

(TurboGaussianDeficit(), [76.674176, 41.548202, 83.096405, 64.831198, 76.143396]),
(BlondelSuperGaussianDeficit2023(), [83.792707, 60.896354, 121.792707, 67.967813, 69.792707])
])

@@ -307,5 +308,8 @@ def test_wake_radius(deficitModel, wake_radius_ref):

dw_ijlk=np.reshape(x, (1, len(x), 1, 1)),
h_ilk=np.reshape(70, (1, 1, 1)),
ct_ilk=sim_res.CT.values,
TI_ilk=np.reshape(sim_res.TI.values, (1, 1, 1)),
TI_eff_ilk=sim_res.TI_eff.values)[0, :, 0, 0]
TI_eff_ilk=sim_res.TI_eff.values,
type_il=np.reshape(0, (1, 1))
)[0, :, 0, 0]
ax1.set_title(deficitModel.__class__.__name__)

@@ -639,3 +643,3 @@ ax1.plot(x, wr)

sim_res = wfm([0, .1, .2], [0, 200, 400], wd=[270, 90], ws=10, type=[0, 1, 2])
fm = sim_res.flow_map(Points(x=[200, 200, 200], y=[0, 200, 400], h=[110, 110, 110]))
fm = sim_res.flow_map(Points(x=[200, 200, 200], y=[0, 200, 400], h=[110, 110, 110]), wd=sim_res.wd, ws=sim_res.ws)
npt.assert_allclose(fm.WS_eff[:, 1], [3.4, 6.1, 7.5], atol=.1)

@@ -642,0 +646,0 @@ if 0:

@@ -51,4 +51,4 @@ from py_wake import np

sim_res = wake_model(wt_x, wt_y, wd=[30], ws=[10])
flow_map70 = sim_res.flow_map(HorizontalGrid(x_j, y_j, h=70))
flow_map73 = sim_res.flow_map(HorizontalGrid(x_j, y_j, h=73))
flow_map70 = sim_res.flow_map(HorizontalGrid(x_j, y_j, h=70), memory_GB=0.5)
flow_map73 = sim_res.flow_map(HorizontalGrid(x_j, y_j, h=73), memory_GB=0.5)

@@ -131,4 +131,4 @@ X, Y = flow_map70.XY

sim_res = wake_model(wt_x, wt_y, wd=[30], ws=[10])
flow_map70 = sim_res.flow_map(HorizontalGrid(x_j, y_j, h=70))
flow_map73 = sim_res.flow_map(HorizontalGrid(x_j, y_j, h=73))
flow_map70 = sim_res.flow_map(HorizontalGrid(x_j, y_j, h=70), memory_GB=0.5)
flow_map73 = sim_res.flow_map(HorizontalGrid(x_j, y_j, h=73), memory_GB=0.5)

@@ -135,0 +135,0 @@ X, Y = flow_map70.XY

@@ -153,3 +153,30 @@ from py_wake import np

# Test MOST shear, stable.
# WS_eff_star does not change since we not change the actual simulation using Site with MOSTShear and LUTs with stability
aDControl2 = ADControl.from_lut([dataset, lut2], wts, ws_cutin=4, ws_cutout=25, dws=1.0, cal_TI=0.06, cal_zeta=0.5)
ellipsys_power, WS_eff_star, ct_star = get_Ellipsys_equivalent_output(simres, aDControl2)
# print(ct_star.flatten())
# print(ellipsys_power.flatten() * 1e-6)
CTstar_expected = [1.32895893, 1.33159161, 1.36637959, 1.32630388, 1.36116655, 1.36639816, 1.36463016]
power_expected = [1.34531419, 1.33329859, 0.72796236, 1.35150555, 1.060569, 0.72981311, 0.56473626]
npt.assert_array_almost_equal(ellipsys_power.flatten() * 1e-6, power_expected, 6)
npt.assert_array_almost_equal(WS_eff_star.flatten(), UAD_expected, 6)
npt.assert_array_almost_equal(ct_star.flatten(), CTstar_expected, 6)
# Test MOST shear, unstable
aDControl2 = ADControl.from_lut([dataset, lut2], wts, ws_cutin=4, ws_cutout=25, dws=1.0, cal_TI=0.06, cal_zeta=-0.5)
ellipsys_power, WS_eff_star, ct_star = get_Ellipsys_equivalent_output(simres, aDControl2)
# print(ct_star.flatten())
# print(ellipsys_power.flatten() * 1e-6)
CTstar_expected = [1.3254684, 1.32682915, 1.36065434, 1.32318215, 1.35620019, 1.36067278, 1.35891729]
power_expected = [1.33938202, 1.32595377, 0.72335257, 1.34597418, 1.05462423, 0.72519153, 0.56109148]
npt.assert_array_almost_equal(ellipsys_power.flatten() * 1e-6, power_expected, 6)
npt.assert_array_almost_equal(WS_eff_star.flatten(), UAD_expected, 6)
npt.assert_array_almost_equal(ct_star.flatten(), CTstar_expected, 6)
def test_rans_lut_multi_wd_ws():

@@ -156,0 +183,0 @@ # move turbine 1 600 300

@@ -22,4 +22,2 @@ from py_wake.flow_map import HorizontalGrid, YZGrid, Points, XYGrid, XZGrid

from py_wake.site._site import UniformSite
from py_wake.ground_models.ground_models import Mirror
from py_wake.deficit_models.selfsimilarity import SelfSimilarityDeficit2020

@@ -58,4 +56,4 @@

superpositionModel=SquaredSum())
simulation_result = wind_farm_model(x, y, wd=[0, 270], ws=[6, 8, 10], mode=0)
fm = simulation_result.flow_map(XYGrid(resolution=3))
sim_res = wind_farm_model(x, y, wd=[0, 270], ws=[6, 8, 10], mode=0)
fm = sim_res.flow_map(XYGrid(resolution=3), wd=sim_res.wd, ws=sim_res.ws)
npt.assert_array_almost_equal(fm.power_xylk(mode=1).sum(['wd', 'ws']).isel(h=0),

@@ -319,2 +317,40 @@ [[7030000., 6378864., 7029974.],

def test_flow_map_point_chunks():
wfm = IEA37CaseStudy1(16)
x, y = wfm.site.initial_position.T
sim_res = wfm(x, y, wd=np.arange(0, 360, 30), ws=10)
# wfm.verbose = True
# j chunks
fm1 = sim_res.flow_map(XYGrid(resolution=500), wd=270)
fm2 = sim_res.flow_map(XYGrid(resolution=500), wd=270, memory_GB=0.005)
fm3 = sim_res.flow_map(XYGrid(resolution=500), wd=270, memory_GB=0.005, n_cpu=4)
npt.assert_array_equal(fm1.WS_eff, fm2.WS_eff)
npt.assert_array_equal(fm1.WS_eff, fm3.WS_eff)
# wd chunks
fm4 = sim_res.flow_map(XYGrid(resolution=50), wd=270)
fm5 = sim_res.flow_map(XYGrid(resolution=50), wd=sim_res.wd)
fm6 = sim_res.flow_map(XYGrid(resolution=50), wd=sim_res.wd, memory_GB=0.002)
fm7 = sim_res.flow_map(XYGrid(resolution=50), wd=sim_res.wd, memory_GB=0.002, n_cpu=4)
npt.assert_array_equal(fm4.WS_eff, fm5.WS_eff.sel(wd=[270]))
npt.assert_array_equal(fm5.WS_eff, fm6.WS_eff)
npt.assert_array_equal(fm5.WS_eff, fm7.WS_eff)
# both wd and j chunks
fm8 = sim_res.flow_map(XYGrid(resolution=50), wd=sim_res.wd, memory_GB=0.0005)
fm9 = sim_res.flow_map(XYGrid(resolution=50), wd=sim_res.wd, memory_GB=0.0005, n_cpu=4)
npt.assert_array_equal(fm5.WS_eff, fm8.WS_eff)
npt.assert_array_equal(fm5.WS_eff, fm9.WS_eff)
sim_res.flow_map(XYGrid(resolution=50), wd=sim_res.wd[:1], n_cpu=4)
sim_res.flow_map(XYGrid(resolution=50), wd=sim_res.wd[:2], n_cpu=4)
sim_res.flow_map(XYGrid(resolution=50), wd=sim_res.wd[:], n_cpu=4)
if 0:
fm1.plot_wake_map()
plt.show()
def test_aep_map():

@@ -327,3 +363,3 @@ wfm = IEA37CaseStudy1(16)

aep_map = sim_res.aep_map(grid, normalize_probabilities=True)
fm = sim_res.flow_map(grid)
fm = sim_res.flow_map(grid, wd=sim_res.wd, ws=sim_res.ws)
npt.assert_array_almost_equal(fm.aep_xy(normalize_probabilities=True).sel(h=110), aep_map)

@@ -363,3 +399,3 @@

fm = sim_res.flow_map(grid)
fm = sim_res.flow_map(grid, ws=sim_res.ws, wd=sim_res.wd)
npt.assert_array_almost_equal(fm.aep_xy(normalize_probabilities=True).sel(h=110), aep_map)

@@ -366,0 +402,0 @@

@@ -218,4 +218,5 @@ from numpy import nan

fm_ref = wfm([0, 0 + 1e-20], [0, 0 + 1e-20], wd=[0, 5], h=[50, -50]
).flow_map(YZGrid(x=0, y=np.arange(-100, 100, 1) + .1, z=np.arange(1, 100)))
sim_res_ref = wfm([0, 0 + 1e-20], [0, 0 + 1e-20], wd=[0, 5], h=[50, -50]
)
fm_ref = sim_res_ref.flow_map(YZGrid(x=0, y=np.arange(-100, 100, 1) + .1, z=np.arange(1, 100)), wd=sim_res_ref.wd)
fm_ref.plot_wake_map()

@@ -227,3 +228,4 @@ plt.title("Underground WT added manually")

superpositionModel=LinearSum())
fm_res = wfm([0], [0], wd=[0, 5], h=[50]).flow_map(YZGrid(x=0, y=np.arange(-100, 100, 1) + .1, z=np.arange(1, 100)))
sim_res = wfm([0], [0], wd=[0, 5], h=[50])
fm_res = sim_res.flow_map(YZGrid(x=0, y=np.arange(-100, 100, 1) + .1, z=np.arange(1, 100)), wd=sim_res.wd)
fm_res.plot_wake_map()

@@ -230,0 +232,0 @@ plt.title("With Mirror GroundModel")

@@ -1,2 +0,3 @@

from py_wake.site.shear import PowerShear, LogShear
from py_wake.site.shear import PowerShear, MOSTShear, LogShear
from py_wake.utils.most import psi
from py_wake import np

@@ -15,5 +16,5 @@ from py_wake.tests import npt

if 0:
plt.plot(WS.sel(wd=0, ws=10), WS.h, label='alpha=0.1')
plt.plot(WS.sel(wd=0, ws=10), h_lst, label='alpha=0.1')
plt.plot((h_lst / 70)**0.1 * 10, h_lst, ':')
plt.plot(WS.sel(wd=180, ws=12), WS.h, label='alpha=0.2')
plt.plot(WS.sel(wd=180, ws=12), h_lst, label='alpha=0.2')
plt.plot((h_lst / 70)**0.2 * 12, h_lst, ':')

@@ -26,2 +27,23 @@ plt.legend()

def test_most_shear():
h_lst = np.arange(10, 100, 10)
h_zetas = [-0.5, 0.0, 0.5]
for h_zeta in h_zetas:
L_inv = h_zeta / 70.0
site = UniformSite([1], .1, shear=MOSTShear(70, h_zeta=h_zeta, z0=[.02, 2], Cm1=5.0, Cm2=-16.0))
WS = site.local_wind(x=h_lst * 0, y=h_lst * 0, h=h_lst, wd=[0, 180], ws=[10, 12]).WS
if 0:
plt.plot(WS.sel(wd=0, ws=10), h_lst, label='z0=0.02, h_zeta=%g' % h_zeta)
plt.plot((np.log(h_lst / 0.02) - psi(h_lst * L_inv, Cm1=5.0, Cm2=-16.0)) / (np.log(70.0 / 0.02) - psi(h_zeta, Cm1=5.0, Cm2=-16.0)) * 10.0, h_lst, ':')
plt.plot(WS.sel(wd=180, ws=12), h_lst, label='z0=2, h_zeta=%g' % h_zeta)
plt.plot((np.log(h_lst / 2) - psi(h_lst * L_inv, Cm1=5.0, Cm2=-16.0)) / (np.log(70.0 / 2) - psi(h_zeta, Cm1=5.0, Cm2=-16.0)) * 12.0, h_lst, ':')
if h_zeta == h_zetas[-1]:
plt.legend()
plt.show()
npt.assert_array_equal(WS.sel(wd=0, ws=10), (np.log(h_lst / 0.02) - psi(h_lst * L_inv, Cm1=5.0, Cm2=-16.0)) / (np.log(70.0 / 0.02) - psi(h_zeta, Cm1=5.0, Cm2=-16.0)) * 10)
npt.assert_array_equal(WS.sel(wd=180, ws=12), (np.log(h_lst / 2) - psi(h_lst * L_inv, Cm1=5.0, Cm2=-16.0)) / (np.log(70.0 / 2) - psi(h_zeta, Cm1=5.0, Cm2=-16.0)) * 12)
def test_log_shear():

@@ -34,5 +56,5 @@

if 0:
plt.plot(WS.sel(wd=0, ws=10), WS.h, label='z0=0.02')
plt.plot(WS.sel(wd=0, ws=10), h_lst, label='z0=0.02')
plt.plot(np.log(h_lst / 0.02) / np.log(70 / 0.02) * 10, h_lst, ':')
plt.plot(WS.sel(wd=180, ws=12), WS.h, label='z0=2')
plt.plot(WS.sel(wd=180, ws=12), h_lst, label='z0=2')
plt.plot(np.log(h_lst / 2) / np.log(70 / 2) * 12, h_lst, ':')

@@ -39,0 +61,0 @@ plt.legend()

@@ -158,4 +158,4 @@ import pytest

npt.assert_array_almost_equal(sim_res_a2a.WS_eff.sel(wt=8), sim_res_pdw.WS_eff.sel(wt=8))
fm_a2a = sim_res_a2a.flow_map(Points(wt9_x[-1:], wt9_y[-1:], [70]))
fm_pdw = sim_res_a2a.flow_map(Points(wt9_x[-1:], wt9_y[-1:], [70]))
fm_a2a = sim_res_a2a.flow_map(Points(wt9_x[-1:], wt9_y[-1:], [70]), wd=sim_res_a2a.wd, ws=sim_res_a2a.ws)
fm_pdw = sim_res_a2a.flow_map(Points(wt9_x[-1:], wt9_y[-1:], [70]), wd=sim_res_pdw.wd, ws=sim_res_pdw.ws)
npt.assert_array_almost_equal(sim_res_a2a.WS_eff.sel(wt=8).squeeze(), fm_a2a.WS_eff)

@@ -162,0 +162,0 @@ npt.assert_array_almost_equal(sim_res_a2a.WS_eff.sel(wt=8).squeeze(), fm_pdw.WS_eff)

@@ -39,27 +39,2 @@ import os

def test_phi():
zeta = np.linspace(-.1, .1, 11)
# print(list(np.round(phi(zeta), 3)))
if 0:
plt.plot(zeta, phi(zeta))
plt.show()
npt.assert_array_almost_equal(phi(zeta), [0.764, 0.792, 0.825, 0.867, 0.922, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5], 3)
def test_psi():
zeta = np.linspace(-.1, .1, 51)
# print(list(np.round(psi(zeta[::5]), 3)))
# print(list(np.round(psi(zeta[::5], 'Wilson'), 3)))
if 0:
plt.plot(zeta, psi(zeta))
plt.plot(zeta, psi(zeta, 'Wilson'), label='Wilson')
plt.legend()
plt.show()
npt.assert_array_almost_equal(psi(zeta[::5]),
[0.326, 0.276, 0.221, 0.159, 0.087, 0.0, -0.1, -0.2, -0.3, -0.4, -0.5], 3)
npt.assert_array_almost_equal(psi(zeta[::5], 'Wilson'),
[2.541, 2.488, 2.427, 2.355, 2.261, 0.0, -0.1, -0.2, -0.3, -0.4, -0.5], 3)
def test_z0_from_TI():

@@ -66,0 +41,0 @@ if 0:

@@ -18,3 +18,3 @@ from numpy import newaxis as na

from py_wake.site.distance import StraightDistance
from py_wake.site.shear import LogShear, PowerShear, Shear
from py_wake.site.shear import LogShear, PowerShear, Shear, MOSTShear
from py_wake.superposition_models import SuperpositionModel, AddedTurbulenceSuperpositionModel

@@ -228,3 +228,4 @@ from py_wake.tests import npt

model = {PowerShear: PowerShear(h_ref=100, alpha=.1),
LogShear: LogShear(h_ref=100, z0=.03)}[model]
LogShear: LogShear(h_ref=100, z0=.03),
MOSTShear: MOSTShear(h_ref=100, z0=.03, h_zeta=0.0)}[model]
check_gradients(lambda site, wt, s=Hornsrev1Site(shear=model): PropagateDownwind(

@@ -231,0 +232,0 @@ s, wt, wake_deficitModel=BastankhahGaussianDeficit(),

import os
import warnings

@@ -7,9 +8,15 @@ from autograd.numpy.numpy_boxes import ArrayBox

import matplotlib.pyplot as plt
from py_wake import np
from py_wake.deficit_models.deficit_model import WakeDeficitModel, BlockageDeficitModel
from py_wake.deficit_models.gaussian import IEA37SimpleBastankhahGaussianDeficit
from py_wake.deficit_models.noj import NOJDeficit
from py_wake.deflection_models.deflection_model import DeflectionModel
from py_wake.examples.data.ParqueFicticio._parque_ficticio import ParqueFicticioSite
from py_wake.examples.data.hornsrev1 import Hornsrev1Site, V80
from py_wake.examples.data.iea37._iea37 import IEA37Site, IEA37_WindTurbines
from py_wake.flow_map import XYGrid
from py_wake.ground_models.ground_models import GroundModel
from py_wake.rotor_avg_models.area_overlap_model import AreaOverlapAvgModel
from py_wake.rotor_avg_models.gaussian_overlap_model import GaussianOverlapAvgModel
from py_wake.rotor_avg_models.rotor_avg_model import RotorAvgModel

@@ -28,13 +35,4 @@ from py_wake.site._site import Site

from py_wake.wind_farm_models.engineering_models import PropagateDownwind, All2AllIterative, EngineeringWindFarmModel
from py_wake.wind_farm_models.wind_farm_model import WindFarmModel
from py_wake.examples.data.hornsrev1 import Hornsrev1Site, V80
from py_wake.rotor_avg_models.gaussian_overlap_model import GaussianOverlapAvgModel
from py_wake.rotor_avg_models.area_overlap_model import AreaOverlapAvgModel
from py_wake.deficit_models.noj import NOJDeficit
import warnings
from py_wake.flow_map import XYGrid
import matplotlib.pyplot as plt
@pytest.mark.parametrize('v,dtype,dtype32', [(5., float, np.float32),

@@ -41,0 +39,0 @@ (5 + 0j, complex, np.complex64)])

@@ -99,7 +99,2 @@ import pytest

def test_when_ct_idle_fails():
wt = IEA34_130_1WT_Surrogate()
sim_res = All2AllIterative(Hornsrev1Site(), wt, NOJDeficit(), turbulenceModel=STF2017TurbulenceModel())([0], [0], )
def test_not_converge():

@@ -106,0 +101,0 @@ class RandomRathmann(Rathmann):

@@ -277,3 +277,3 @@ import pytest

warnings.simplefilter('ignore', UserWarning)
ws_eff = sim_res.flow_map().WS_eff.interp(
ws_eff = sim_res.flow_map(wd=sim_res.wd, ws=sim_res.ws).WS_eff.interp(
x=('z', [-100, -300, 100]), y=('z', [-300, 100, 300]), wd=('z', [0, 90, 180])).squeeze().values

@@ -290,3 +290,3 @@ npt.assert_array_equal(ws_eff[0], ws_eff)

sim_res = wfm(x=[[[0, 0, 0]], [[100, 200, 300]]], y=np.zeros((2, 1, 3)), wd=[270], ws=[8, 9, 10])
ws_eff = sim_res.flow_map().WS_eff.interp(x=400, y=0).squeeze()
ws_eff = sim_res.flow_map(wd=sim_res.wd, ws=sim_res.ws).WS_eff.interp(x=400, y=0).squeeze()
npt.assert_array_almost_equal(ws_eff, [4.06513, 4.117601, 3.830711])

@@ -293,0 +293,0 @@ if 0:

@@ -9,2 +9,3 @@ import os

from py_wake.utils import gradients
from py_wake.utils.most import phi, psi
from scipy.special import lambertw

@@ -307,28 +308,3 @@ from scipy.optimize import fsolve

Cm1 = 5
Cm2 = -19.3
def phi(zeta):
zeta = np.atleast_1d(zeta)
e = np.where((zeta <= 0), -.25, 1) # avoid warning when Cm2*zeta<-1
return np.where(zeta <= 0, (1 + Cm2 * zeta)**e, 1 + Cm1 * zeta)
def psi(zeta, unstable=''):
zeta = np.atleast_1d(zeta)
ind = zeta < 0
psi_n = np.zeros(zeta.shape)
aux = phi(zeta)**-1
if unstable == 'Wilson':
psi_n[ind] = 3 * np.log((1 + (1 + 3.6 * np.abs(zeta[ind])**(2 / 3))**.5))
else:
aux2 = (1.0 + aux[ind])**2 * (1 + aux[ind]**2)
psi_n[ind] = -np.log(8.0 / aux2) - 2.0 * np.arctan(Cm2 * zeta[ind] / aux2)
psi_n[~ind] = 1 - aux[~ind]**-1
psi_n[zeta == 0] = 0
return psi_n
def z0(TI, zref, zeta0, z0_limit=1e-5):
def z0(TI, zref, zeta0, z0_limit=1e-5, Cm1=5):
zeros = np.atleast_1d((np.asarray(TI) + np.asarray(zref) + np.asarray(zeta0)) * 0)

@@ -365,3 +341,3 @@ TI, zref, zeta0 = zeros + TI, zeros + zref, zeros + zeta0

def ti(z0, zref, zeta0):
def ti(z0, zref, zeta0, Cm1=5):
zeros = np.atleast_1d((np.asarray(z0) + np.asarray(zref) + np.asarray(zeta0)) * 0)

@@ -368,0 +344,0 @@ z0, zref, zeta0 = zeros + z0, zeros + zref, zeros + zeta0

@@ -5,3 +5,3 @@ import multiprocessing

import gc
import os
from itertools import starmap

@@ -56,2 +56,26 @@ pool_dict = {}

def get_map_func(n_cpu, verbose, desc='', unit='it'):
n_cpu = n_cpu or multiprocessing.cpu_count()
if n_cpu > 1:
map_func = get_pool_map(n_cpu)
else:
from tqdm import tqdm
def map_func(f, iter):
return tqdm(map(f, iter), desc=desc, unit=unit, total=len(iter), disable=not verbose)
return map_func
def get_starmap_func(n_cpu, verbose, desc='', unit='it', leave=True):
n_cpu = n_cpu or multiprocessing.cpu_count()
if n_cpu > 1:
map_func = get_pool_starmap(n_cpu)
else:
from tqdm import tqdm
def map_func(f, iter):
return starmap(f, tqdm(iter, desc=desc, unit=unit, total=len(iter), disable=not verbose, leave=leave))
return map_func
atexit.register(close_pools)

@@ -8,2 +8,3 @@ import xarray as xr

from pathlib import Path
from py_wake.utils.most import phi, psi, phi_eps

@@ -68,5 +69,5 @@

@staticmethod
def from_lut(lut, windTurbines, ws_cutin, ws_cutout, dws, cal_TI,
def from_lut(lut, windTurbines, ws_cutin, ws_cutout, dws, cal_TI, cal_zeta=0.0,
rotorAvgModel=EllipSysPolygonRotorAvg(n_r=9, n_theta=32),
density=1.225, cmu=0.03, kappa=0.4):
density=1.225, cmu=0.03, kappa=0.4, Cm1=5.0, Cm2=-16.0):
"""Calculcate ADControl object containing CPstar, CTstar = f(UAD) directly from single wake RANS-LUT

@@ -107,4 +108,6 @@

uStar_UH = cal_TI * np.sqrt(1.5 * np.sqrt(cmu))
# z0 = zRef / (np.exp(kappa / uStar_UH) - 1)
phim = phi(cal_zeta, Cm1=Cm1, Cm2=Cm2)
psim = psi(cal_zeta, Cm1=Cm1, Cm2=Cm2)
phieps = phi_eps(cal_zeta, Cm1=Cm1)
uStar_UH = cal_TI * np.sqrt(1.5 * np.sqrt(cmu)) * phieps ** -0.25 * phim ** 0.25

@@ -136,6 +139,6 @@ types = np.arange(len(lut_U))

# PWE: z0 is added to h_j and zH
# logshear = np.log(h_j / z0) / np.log(zRef / z0)
z0 = zH / (np.exp(kappa / uStar_UH) - 1)
logshear = np.log(h_j / z0) / np.log(zH / z0)
U = logshear[na, :] - 1.0 + Udata.interp(ct=cts, kwargs={"fill_value": "extrapolate"}).values
z0 = zH / (np.exp(kappa / uStar_UH + psim) - 1)
L_inv = cal_zeta / zH # 1 / Obukhov length
mostshear = (np.log(h_j / z0) - psi(h_j * L_inv, Cm1=Cm1, Cm2=Cm2)) / (np.log(zH / z0) - psim)
U = mostshear[na, :] - 1.0 + Udata.interp(ct=cts, kwargs={"fill_value": "extrapolate"}).values
UAD = ws * np.sum(np.reshape(U, (len(ws), -1)) * weights, axis=1)

@@ -142,0 +145,0 @@ ratio = ws / UAD

@@ -89,3 +89,4 @@ from py_wake.wind_farm_models.engineering_models import PropagateDownwind

windFarmModel.windTurbines = self.windTurbines
fm = windFarmModel([0], [0]).flow_map(XYGrid(y=-self.x, x=0))
sim_res = windFarmModel([0], [0])
fm = sim_res.flow_map(XYGrid(y=-self.x, x=0), wd=sim_res.wd, ws=sim_res.ws)
wd = (fm.wd.values + 180) % 360 - 180

@@ -92,0 +93,0 @@ ws = (fm.WS_eff / fm.ws).squeeze()

# file generated by setuptools-scm
# don't change, don't track in version control
__all__ = ["__version__", "__version_tuple__", "version", "version_tuple"]
__all__ = [
"__version__",
"__version_tuple__",
"version",
"version_tuple",
"__commit_id__",
"commit_id",
]

@@ -12,4 +19,6 @@ TYPE_CHECKING = False

VERSION_TUPLE = Tuple[Union[int, str], ...]
COMMIT_ID = Union[str, None]
else:
VERSION_TUPLE = object
COMMIT_ID = object

@@ -20,4 +29,8 @@ version: str

version_tuple: VERSION_TUPLE
commit_id: COMMIT_ID
__commit_id__: COMMIT_ID
__version__ = version = '2.6.12'
__version_tuple__ = version_tuple = (2, 6, 12)
__version__ = version = '2.6.13'
__version_tuple__ = version_tuple = (2, 6, 13)
__commit_id__ = commit_id = None

@@ -18,2 +18,4 @@ from abc import abstractmethod

from py_wake.deficit_models.no_wake import NoWakeDeficit
from py_wake.utils.parallelization import get_map_func, get_starmap_func
import multiprocessing

@@ -310,11 +312,8 @@

def _get_flow_l(self, model_kwargs, l, wt_x_ilk, wt_y_ilk, wt_h_ilk, lw_j, wd, WD_ilk):
def _get_flow_l(self, model_kwargs, wt_x_ilk, wt_y_ilk, wt_h_ilk, x_j, y_j, h_j, wd, WD_ilk, WS_jlk, TI_jlk):
wt_z_ilk = self.site.elevation(wt_x_ilk, wt_y_ilk)
z_j = self.site.elevation(lw_j.x, lw_j.y)
self.site.distance.setup(wt_x_ilk, wt_y_ilk, wt_h_ilk, wt_z_ilk, (lw_j.x, lw_j.y, lw_j.h, z_j))
z_j = self.site.elevation(x_j, y_j)
self.site.distance.setup(wt_x_ilk, wt_y_ilk, wt_h_ilk, wt_z_ilk, (x_j, y_j, h_j, z_j))
dw_ijlk, hcw_ijlk, dh_ijlk = self.site.distance(wd_l=wd, WD_ilk=WD_ilk)
WS_jlk = lw_j.WS_ilk[:, [l, slice(0, 1)][lw_j.WS_ilk.shape[1] == 1]]
TI_jlk = lw_j.TI_ilk[:, [l, slice(0, 1)][lw_j.TI_ilk.shape[1] == 1]]
if self.wec != 1:

@@ -384,6 +383,7 @@ hcw_ijlk = hcw_ijlk / self.wec

TI_eff_jlk = None
model_kwargs.clear()
return WS_eff_jlk, TI_eff_jlk
def _aep_map(self, x_j, y_j, h_j, type_j, sim_res_data):
lw_j, WS_eff_jlk, _ = self._flow_map(x_j, y_j, h_j, sim_res_data)
def _aep_map(self, x_j, y_j, h_j, type_j, sim_res_data, memory_GB=1, n_cpu=1):
lw_j, WS_eff_jlk, _ = self._flow_map(x_j, y_j, h_j, sim_res_data, memory_GB=memory_GB, n_cpu=n_cpu)
power_kwargs = {}

@@ -398,25 +398,39 @@ if 'type' in (self.windTurbines.powerCtFunction.required_inputs +

def _flow_map(self, x_j, y_j, h_j, sim_res_data, D_dst=0):
def _flow_map(self, x_j, y_j, h_j, sim_res_data, D_dst=0, memory_GB=1, n_cpu=1):
"""call this function via SimulationResult.flow_map"""
arg_funcs, lw_j, wd, WD_il = self.get_map_args(x_j, y_j, h_j, sim_res_data, D_dst=D_dst)
I, J, L, K = arg_funcs['IJLK']()
if I == 0:
return (lw_j, np.broadcast_to(lw_j.WS_ilk, (len(x_j), L, K)).astype(float),
np.broadcast_to(lw_j.TI_ilk, (len(x_j), L, K)).astype(float))
n_cpu = n_cpu or multiprocessing.cpu_count()
# *6=dx_ijlk, dy_ijlk, dz_ijlk, dh_ijlk, deficit, blockage
size_GB = I * J * L * K * np.array([]).itemsize * 6 * n_cpu / 1024**3
min_wd_chunks = np.minimum(n_cpu, L)
wd_chunks = int(np.clip(np.ceil(size_GB / memory_GB), min_wd_chunks, L))
min_j_chunks = np.minimum(int(np.ceil(n_cpu / wd_chunks)), J)
j_chunks = int(np.clip(np.ceil(size_GB / wd_chunks / memory_GB), min_j_chunks, J))
size_gb = I * J * L * K * 8 / 1024**3
wd_chunks = int(np.minimum(np.maximum(int(size_gb // 1), 1), L))
wd_i = np.round(np.linspace(0, L, wd_chunks + 1)).astype(int)
l_iter = tqdm([slice(i0, i1) for i0, i1 in zip(wd_i[:-1], wd_i[1:])], disable=L <= 1 or not self.verbose,
desc='Calculate flow map', unit='wd')
map_func = get_starmap_func(n_cpu=n_cpu, verbose=wd_chunks + j_chunks > 2 and self.verbose, desc='Calculate flow map',
unit='wd', leave=0)
wt_x_ilk, wt_y_ilk, wt_h_ilk = [sim_res_data[k].ilk() for k in ['x', 'y', 'h']]
WS_eff_jlk, TI_eff_jlk = zip(*[self._get_flow_l(
{k: arg_funcs[k](l) for k in arg_funcs},
l,
*[(v, v[:, l])[np.shape(v)[1] == L] for v in [wt_x_ilk, wt_y_ilk, wt_h_ilk]],
lw_j, wd[l], WD_il[:, l])
for l in l_iter])
WS_eff_jlk = np.concatenate(WS_eff_jlk, 1)
xyh_j_lst = list(zip(*[np.array_split(x_j, j_chunks),
np.array_split(y_j, j_chunks),
np.array_split(h_j, j_chunks)]))
l_iter = [({k: arg_funcs[k](l) for k in arg_funcs},
*[(v, v[:, slice(l[0], l[-1] + 1)])[np.shape(v)[1] == L] for v in [wt_x_ilk, wt_y_ilk, wt_h_ilk]],
x_j_, y_j_, h_j_, wd[l], WD_il[:, l],
lw_j.WS_ilk[:, (l, [0])[lw_j.WS_ilk.shape[1] == 1]],
lw_j.TI_ilk[:, (l, [0])[lw_j.TI_ilk.shape[1] == 1]])
for l in np.array_split(np.arange(L).astype(int), wd_chunks)
for x_j_, y_j_, h_j_ in xyh_j_lst]
WS_eff_jlk, TI_eff_jlk = zip(*map_func(self._get_flow_l, l_iter))
WS_eff_jlk = np.concatenate([np.concatenate(WS_eff_jlk[i * j_chunks:(i + 1) * j_chunks], 0)
for i in range(wd_chunks)], 1)
if self.turbulenceModel:
TI_eff_jlk = np.concatenate(TI_eff_jlk, 1)
TI_eff_jlk = np.concatenate([np.concatenate(TI_eff_jlk[i * j_chunks:(i + 1) * j_chunks], 0)
for i in range(wd_chunks)], 1)
else:

@@ -909,9 +923,13 @@ TI_eff_jlk = np.zeros_like(WS_eff_jlk) + lw_j.TI_ilk

ct_ilk = self.windTurbines.ct(ws=WS_eff_ilk, **wt_kwargs)
try:
if hasattr(self.windTurbines.powerCtFunction, 'ct_idle'):
ct_ilk_idle = np.ones_like(WS_ILK) * self.windTurbines.powerCtFunction.ct_idle
else:
ct_ilk_idle = self.windTurbines.ct(ws=0.1 * np.ones_like(WS_ILK), **wt_kwargs)
except BaseException:
ct_ilk_idle = 0
if hasattr(self.windTurbines.powerCtFunction, 'ct_idle') and \
self.windTurbines.powerCtFunction.ct_idle is not None:
ct_ilk_idle = np.ones_like(WS_ILK) * self.windTurbines.powerCtFunction.ct_idle
else:
def get_ct(ws):
return self.windTurbines.ct(ws=ws * np.ones_like(WS_ILK), **wt_kwargs)
ct_ilk_idle = np.min([get_ct(ws) for ws in np.arange(0, 26)], 0)
unstable_lk = np.zeros((L, K), dtype=bool)

@@ -918,0 +936,0 @@ ioff = np.broadcast_to(ct_ilk, (I, L, K)) < -1 # index of off/idling turbines

@@ -12,3 +12,3 @@ from abc import abstractmethod, ABC

import multiprocessing
from py_wake.utils.parallelization import get_pool_map, get_pool_starmap
from py_wake.utils.parallelization import get_pool_map, get_pool_starmap, get_map_func
from py_wake.utils.functions import arg2ilk

@@ -292,10 +292,3 @@ from py_wake.utils.gradients import autograd

ws_i = np.linspace(0, len(ws) + 1, ws_chunks + 1).astype(int)
if n_cpu > 1:
map_func = get_pool_map(n_cpu)
else:
from tqdm import tqdm
def map_func(f, iter):
return tqdm(map(f, iter), total=len(iter), disable=not self.verbose)
if time is False:

@@ -338,3 +331,3 @@ # (wd x ws) matrix

return map_func, arg_lst, wd_chunks, ws_chunks
return get_map_func(n_cpu, self.verbose), arg_lst, wd_chunks, ws_chunks

@@ -721,3 +714,3 @@ def _aep_chunk_wrapper(self, aep_function,

def aep_map(self, grid=None, wd=None, ws=None, type=0, normalize_probabilities=False, n_cpu=1, wd_chunks=None): # @ReservedAssignment
def aep_map(self, grid=None, wd=None, ws=None, type=0, normalize_probabilities=False, memory_GB=1, n_cpu=1): # @ReservedAssignment
X, Y, x_j, y_j, h_j, plane = self._get_grid(grid)

@@ -728,21 +721,3 @@ wd, ws = self._wd_ws(wd, ws)

setattr(sim_res, k, getattr(self, k))
n_cpu = n_cpu or multiprocessing.cpu_count()
wd_chunks = np.minimum(wd_chunks or n_cpu, len(wd))
if n_cpu != 1:
n_cpu = n_cpu or multiprocessing.cpu_count()
map = get_pool_starmap(n_cpu) # @ReservedAssignment
if len(wd) >= n_cpu:
# chunkification more efficient on wd than j
wd_i = np.linspace(0, len(wd), n_cpu + 1).astype(int)
args_lst = [[x_j, y_j, h_j, type, sim_res.sel(wd=wd[i0:i1])] for i0, i1 in zip(wd_i[:-1], wd_i[1:])]
aep_lst = map(self.windFarmModel._aep_map, args_lst)
aep_j = np.sum(aep_lst, 0)
else:
j_i = np.linspace(0, len(x_j), n_cpu + 1).astype(int)
args_lst = [[xyh_j[i0:i1] for xyh_j in [x_j, y_j, h_j]] + [type, sim_res]
for i0, i1 in zip(j_i[:-1], j_i[1:])]
aep_lst = map(self.windFarmModel._aep_map, args_lst)
aep_j = np.concatenate(aep_lst)
else:
aep_j = self.windFarmModel._aep_map(x_j, y_j, h_j, type, sim_res)
aep_j = self.windFarmModel._aep_map(x_j, y_j, h_j, type, sim_res, n_cpu, memory_GB)
if normalize_probabilities:

@@ -762,3 +737,3 @@ lw_j = self.windFarmModel.site.local_wind(x=x_j, y=y_j, h=h_j, wd=wd, ws=ws)

def flow_map(self, grid=None, wd=None, ws=None, time=None, D_dst=0):
def flow_map(self, grid=None, wd=None, ws=None, time=None, D_dst=0, memory_GB=1, n_cpu=1):
"""Return a FlowMap object with WS_eff and TI_eff of all grid points

@@ -773,3 +748,3 @@

The simulation result must include the requested wind directions.
If None, an weighted average of all wind directions from the simulation results will be computed.
If None, a flow map with only the first wind direction in the simulation results will be computed.
Note, computing a flow map with multiple wind directions may be slow

@@ -783,3 +758,12 @@ ws : int, float, array_like or None

at which the deficits will be averaged
memory_GB : int or float, optional
If the additional memory needed to compute the flow map is assumed to exceed `memory_GB` GB using
simple models, then the flow map is split into a number of wind direction and/or point chunks to
reduce the memory consumption.
The default is 1 GB
n_cpu : int or None, otional
Number of CPUs used to compute the flow map.
If None, all available CPUs are used.
Default is 1.
Note, that for in many cases 1 CPU are the faster option
See Also

@@ -790,6 +774,10 @@ --------

X, Y, x_j, y_j, h_j, plane = self._get_grid(grid)
wd, ws = self._wd_ws(wd, ws)
if 'time' in self:
sim_res = self.sel(time=(time, slice(time))[time is None])
else:
if wd is None:
wd = self.wd[[0]]
if ws is None:
ws = self.ws[[0]]
wd, ws = self._wd_ws(wd, ws)
sim_res = self.sel(wd=wd, ws=ws)

@@ -799,3 +787,4 @@ for k in self.__slots__:

lw_j, WS_eff_jlk, TI_eff_jlk = self.windFarmModel._flow_map(x_j, y_j, h_j, sim_res, D_dst=D_dst)
lw_j, WS_eff_jlk, TI_eff_jlk = self.windFarmModel._flow_map(
x_j, y_j, h_j, sim_res, D_dst=D_dst, memory_GB=memory_GB, n_cpu=n_cpu)
return FlowMap(sim_res, X, Y, lw_j, WS_eff_jlk, TI_eff_jlk, plane=plane)

@@ -802,0 +791,0 @@

@@ -8,4 +8,28 @@ from py_wake import np

from xarray.core.dataarray import DataArray
import matplotlib.pyplot as plt
from matplotlib.patches import Circle
# Create a qualitative color map for plotting the turbines.
# Play with the seed to change the order of the colors.
# Alternatively:
# - Select a metric from https://en.wikipedia.org/wiki/Color_difference, for example LAB.
# - Maximize distance between each color and the next.
# See https://matplotlib.org/stable/users/explain/colors/colormaps.html#qualitative
rng = np.random.default_rng(seed=99)
cmap = np.concatenate((
np.array([[0.0, 0.0, 0.0]]), # Black is always first.
np.array(plt.get_cmap("Dark2").colors), # This is already perceptually different.
rng.permutation(
np.concatenate((
np.array([[0.5, 0.5, 0.5]]), # grey
np.array(plt.get_cmap("tab20b").colors)[4:, :], # Skip the first colors because they are blue.
np.array(plt.get_cmap("tab20c").colors)[4:12, :]), # Keep orange and green.
axis=0),
axis=0)),
axis=0)
# Display the color map.
# from matplotlib.colors import ListedColormap
# ListedColormap(colors=cmap)
class WindTurbines():

@@ -148,3 +172,2 @@ """Set of multiple type wind turbines"""

"""
import matplotlib.pyplot as plt
if types is None:

@@ -159,7 +182,6 @@ types = np.zeros_like(x).astype(int)

markers = np.array(list("213v^<>o48spP*hH+xXDd|_"))
colors = ['k', 'gray', 'r', 'g'] * 5
from matplotlib.patches import Circle
assert len(x) == len(y)
# Yaw and tilt can be a scalar or wd-dependent vector, therefore we cannot use full_like.
yaw = np.zeros_like(x) + yaw

@@ -171,4 +193,6 @@ tilt = np.zeros_like(x) + tilt

for i, (x_, y_, r, t, yaw_, tilt_) in enumerate(zip(x, y, R, types, yaw, tilt)):
# Take the color for the current turbine type.
color = cmap[t % cmap.shape[0], :]
if wd is None or len(np.atleast_1d(wd)) > 1:
circle = Circle((x_, y_), r, ec=colors[t], fc="None")
circle = Circle((x_, y_), r, ec=color, fc="None")
ax.add_artist(circle)

@@ -179,9 +203,10 @@ ax.plot(x_, y_, 'None', )

circle = Ellipse((x_, y_), 2 * r * np.sin(np.deg2rad(tilt_)), 2 * r,
angle=90 - wd_ + yaw_, ec=colors[t], fc="None")
angle=90 - wd_ + yaw_, ec=color, fc="None")
ax.add_artist(circle)
ax.plot(x_, y_, '.', color=colors[t])
ax.plot(x_, y_, '.', color=color)
for t, m, c in zip(np.unique(types), markers, colors):
for t, m in zip(np.unique(types), markers):
color = cmap[t % cmap.shape[0], :]
# ax.plot(np.asarray(x)[types == t], np.asarray(y)[types == t], '%sk' % m, label=self._names[int(t)])
ax.plot([], [], '2', color=colors[t], label=self._names[int(t)])
ax.plot([], [], '2', color=color, label=self._names[int(t)])

@@ -208,3 +233,2 @@ for i, (x_, y_, r) in enumerate(zip(x, y, R)):

"""
import matplotlib.pyplot as plt
if z is None:

@@ -258,3 +282,2 @@ z = np.zeros_like(y)

def plot_power_ct(self, ax=None, ws=np.linspace(0, 25, 1000), **wt_kwargs):
import matplotlib.pyplot as plt
if ax is None:

@@ -406,3 +429,2 @@ ax = plt.gca().figure.axes[0]

import os.path
import matplotlib.pyplot as plt
from py_wake.examples.data import wtg_path

@@ -409,0 +431,0 @@

+30
-28

@@ -9,7 +9,7 @@ docs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0

py_wake/superposition_models.py,sha256=mlZSy-T6YiAhdSgAu-reP1YECRsPpgHh8GDCfPAsZ6w,10124
py_wake/version.py,sha256=OY-1DNhKffui4Swj0cq2tuFWkmx_rnd-2Lfa_jvuhjI,513
py_wake/version.py,sha256=Vi-fvuY4jNLmkjfsZxZ_bieoAIk2n0J8Fd96j6hAUrI,706
py_wake/deficit_models/__init__.py,sha256=w1S4F3FmAgtwqGO90fASYoqxOb6SsgjbasiD3V8_1uk,709
py_wake/deficit_models/deficit_model.py,sha256=BQ8vJ-Nlw4CDWHdqIkNtbAc52OOwfEi4n6P0Vmg8bLg,10255
py_wake/deficit_models/fuga.py,sha256=Jhi52MpvF7-KTk62dZfdLLUf4piCslwIBJTr7N17Hng,13863
py_wake/deficit_models/gaussian.py,sha256=CZ06AQbCLumKiIlbhlbrvV0MhmC24Q826kR81yNiLdc,36094
py_wake/deficit_models/gaussian.py,sha256=_ntryBrucuo9EMSLnyJH3dt9mM9SnB0DxP9wzH_w7Zo,36119
py_wake/deficit_models/gcl.py,sha256=o4b9NRe9rSUJ8PmD3OOD5gOpYY6LBY2OXQfrhh7EBns,8988

@@ -249,3 +249,3 @@ py_wake/deficit_models/hybridinduction.py,sha256=dtfO5Ms0-t2X16XsigiKovKKDnVHG2ntRe8Jmv6CahY,4864

py_wake/examples/data/iea22mw/__init__.py,sha256=gPlxM_vbhAU2JCls9szxXXgWGZZBSFHqTfx8eD1XREo,127
py_wake/examples/data/iea22mw/iea_22_rwt.py,sha256=whJtpu5I4wj4BkqLKG1WhELzpjRnNyMaiQVBq_j-iYI,1918
py_wake/examples/data/iea22mw/iea_22_rwt.py,sha256=PYj4tdkr1WWHcizB9GC0Ne3DRl4MaTFXHOHJLlSq0d0,1980
py_wake/examples/data/iea34_130rwt/__init__.py,sha256=fpJDB-Zu8PENaHqRHzqXnimryNwfrz5aom_gOylYb7Y,76

@@ -289,3 +289,3 @@ py_wake/examples/data/iea34_130rwt/_iea34_130rwt.py,sha256=sEn7pxZY_tU3Zq-Mp8-xV7rWmVizGZArD_3pIKyib24,11310

py_wake/site/jit_streamline_distance.py,sha256=a2FVowV8cjUb-U18riZ4k2NskGPP0KSyqL4w621A2X8,4925
py_wake/site/shear.py,sha256=B5zJZ72mZXEAJE2uVt1n22lGNAMBqz_7gOlzeDoIIUE,3708
py_wake/site/shear.py,sha256=OGU2eQCuZ7H3hAjAbATK9ZXqIWBFjDazp9dmKumDnSw,4213
py_wake/site/wasp_grid_site.py,sha256=81zqtUIwCAUHaZdgnNvzazBjEIPYk22Gr6r7IQzmsZk,10190

@@ -296,6 +296,6 @@ py_wake/site/xrsite.py,sha256=-Kr2LMx0dpKI-ke4z3hbRyv-GWulLntjkSU-nY1LWIA,19887

py_wake/tests/notebook.py,sha256=21RVNXcqRCy6b3GoRcKxR5E0IGV2d9U6BaqqOKZ8f8Y,6804
py_wake/tests/test_flow_map.py,sha256=eAfFrYUjYsSgVgyE92CgRVWAWcVXn1uExB41lbUx_gU,18766
py_wake/tests/test_flow_map.py,sha256=8lQzTxsQp4xUKkdRGkmdS80wYbN5QcwsYpOSJ0z_vhM,20290
py_wake/tests/test_main.py,sha256=aouzNZBMsqrRitG9HfEOCPx8Fe6IH0mM_eIyeQ_TqnM,1853
py_wake/tests/test_notebooks.py,sha256=805s9rBBr1dWEtapvK2BwrfWUPSWWiA48Dz-cwciObI,1956
py_wake/tests/test_superposition_models.py,sha256=y3PL7o5amDJEMYLRd8hbYvEYnFVxWAPxLdoBGMkAAKE,8683
py_wake/tests/test_superposition_models.py,sha256=dxcgeB_LXn1USv_4QNRuyjL83Cy0qhV1yPdJN6enRj4,8759
py_wake/tests/test_deficit_models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0

@@ -305,7 +305,7 @@ py_wake/tests/test_deficit_models/test_BastankhahGaussian.py,sha256=rXMkNTHirHBAKWhRtWCOpZqzX0KX5d2w1ACwAHlEXKo,1069

py_wake/tests/test_deficit_models/test_blockage_models.py,sha256=guS3PX7YdNfI1Po4JzEhGu6BT6ODSxEBR6fBIMUorko,11856
py_wake/tests/test_deficit_models/test_deficit_models.py,sha256=_0k0qy2sZ-0xtRe8L4ubTBxXVOEOdSxtQHJIZaDZKC8,33855
py_wake/tests/test_deficit_models/test_fuga.py,sha256=f1s3ow3-MalL-cc56tXdpHpkzOjEBEaRxhfyL7KFb9c,24709
py_wake/tests/test_deficit_models/test_deficit_models.py,sha256=vwwj3lSs_4kWCl55-qVs0-3bwdmUT7ZXICpVAuZSfRU,33990
py_wake/tests/test_deficit_models/test_fuga.py,sha256=zuWx-oAThjYGdubhX9c-dR8-wsnBJMTi7uA6R17_kos,24769
py_wake/tests/test_deficit_models/test_gcl.py,sha256=i2mIAoNUnGswJ8xXVjjHVw9Imgzhs6thfI8zkgLCt04,1189
py_wake/tests/test_deficit_models/test_noj.py,sha256=qJVv3q3Lp_QILFn-6xdslWevvR4Dmnx0AWj39XCIdXw,5495
py_wake/tests/test_deficit_models/test_rans_lut.py,sha256=BUeKMEs3A0cPBpwxA2UFSHT01M5rYPFr4HKuFCILtAk,16073
py_wake/tests/test_deficit_models/test_rans_lut.py,sha256=rfvT0178DfxA52wlscSDL56tJapBVI_BJu1CnWGkCQA,17738
py_wake/tests/test_deficit_models/test_selfsimilarity.py,sha256=mI5DUstBbaC36JQ-eCOMrE88jubvZjb3tp_DUQQzU2Y,4446

@@ -326,3 +326,3 @@ py_wake/tests/test_deflection_models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0

py_wake/tests/test_ground_models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
py_wake/tests/test_ground_models/test_mirror.py,sha256=J398XITtpQK3SBlb5McKdp65vr8fGZKuV7B_4LfEz1I,12316
py_wake/tests/test_ground_models/test_mirror.py,sha256=9iGzqUiAxA_LR8QpRUQEnmRUurP4HQFLItLlUWrMRxo,12407
py_wake/tests/test_input_modifier_models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0

@@ -342,3 +342,3 @@ py_wake/tests/test_input_modifier_models/test_input_modifier.py,sha256=di-von3D1MClAO8uOBYjqi6esOTkxLIJKyb1G6BEYbk,5473

py_wake/tests/test_sites/test_iea37_readers.py,sha256=nEoXISd3M7USxJe4PFBI2wUlLTjiL6NEnXMvFWHzwxo,1427
py_wake/tests/test_sites/test_shear_models.py,sha256=9ACZyKdrE8V-DAdn1cZa7f1drO1L15q-SBCldAPw-qY,2700
py_wake/tests/test_sites/test_shear_models.py,sha256=g4zg1QCvl2WQY6f10BiRlBAnyJyaaQRVpeiLnkNT4SU,4053
py_wake/tests/test_sites/test_site.py,sha256=NZ_gm8LvHwY0PYVeJbXjtUONjSGaoNCZQ8Q8Z938rrU,11267

@@ -353,3 +353,3 @@ py_wake/tests/test_sites/test_wasp_grid_site.py,sha256=8Swf470l8PdI9FRs-yF27S4pP7X08kXRFTZCK1YYNlU,15686

py_wake/tests/test_utils/test_elliptic.py,sha256=hxyfSIJcdmNgvFxMOqmAV383sO__-0B0sgAKeBBnTNA,1749
py_wake/tests/test_utils/test_fuga_utils.py,sha256=OfCoWhIMu29DPR2DUstbyKPjGfCd4Cx6OOJ8RH-TQVM,3165
py_wake/tests/test_utils/test_fuga_utils.py,sha256=6YYCrngD4bA9XJdIQqMxMTQ-GmwOybrKSll1IANLB6A,2260
py_wake/tests/test_utils/test_gpu_utils.py,sha256=vTVMTLrb9KKr7bHr-AbZZwytV9fhqABq0cn9K4-pt1I,1292

@@ -359,5 +359,6 @@ py_wake/tests/test_utils/test_gradient_utils.py,sha256=phZtdTCg64KgjTvyK4n_HHssPJCYAlJUUHUc9GRWBlU,15810

py_wake/tests/test_utils/test_layouts.py,sha256=9soiopXExIdV1jxSnoG6te_54qbxfRGEd3AdpoGmpNM,1199
py_wake/tests/test_utils/test_model_gradients.py,sha256=9m_qcK-12huEfGXXhVjgNhoE9qFD4P-ZmpvBROWAS0k,12506
py_wake/tests/test_utils/test_model_gradients.py,sha256=Rni1JhZWB_gOmK-aBNFR7bi8q5VlqKX3ftgA6Nbgmc0,12587
py_wake/tests/test_utils/test_model_utils.py,sha256=219lb_0_74xshlw2lKdEgTyPGSRXe8F-uplifqpRdnM,3847
py_wake/tests/test_utils/test_numpy.py,sha256=z2MLCUPg01IhsR3tO9H8rubsP9VzR1RBLt3elvsUHCw,7612
py_wake/tests/test_utils/test_most.py,sha256=WG2Ng8T1mcmIAsP23OnQeGCoVQ9D8NEX-2fmhH4tMd8,1311
py_wake/tests/test_utils/test_numpy.py,sha256=zcjmLyL19eQEW0uxRz81LueCceGm8zG0-wH6VxEIj5c,7544
py_wake/tests/test_utils/test_parallelization.py,sha256=VxxcU58DrwxNyXkl2R00ipf0TUwVJg4Qj7rz8JjEjFo,434

@@ -373,3 +374,3 @@ py_wake/tests/test_utils/test_plotting.py,sha256=tCmEUdvZinzcFMiBGRth8MbFKuVSxQFDuPNh762GBps,286

py_wake/tests/test_wind_farm_models/test_all2all.py,sha256=KCTignc2zVwIPcoJD2gU0fHqdwnppKmjDY-BsfKIa-M,1556
py_wake/tests/test_wind_farm_models/test_all2allIterative.py,sha256=efxyDoAP2U5BhVz0Om6D7ixyWvBISHgzkfVIC_OY9t8,5755
py_wake/tests/test_wind_farm_models/test_all2allIterative.py,sha256=P1e_7rMbCxeiSL8J-scZHux4UdPpWRec79yGayn5bok,5567
py_wake/tests/test_wind_farm_models/test_enginering_wind_farm_model.py,sha256=IvbRInNWqnC8FVk8A-IwmDiYOZ3oGNR4Z8drlRHHpnk,28773

@@ -381,3 +382,3 @@ py_wake/tests/test_wind_farm_models/test_memory_usage.py,sha256=nDGlWHDNVAUrZZD9BOOC-AluRWKuHCLiljp3m8ZofJs,2016

py_wake/tests/test_wind_farm_models/test_simulation_result.py,sha256=VoffAnO6EwA4J_4-AbgoCgrU5Lbj-3f_HbC-YeBVav8,1496
py_wake/tests/test_wind_farm_models/test_wind_farm_model.py,sha256=YkJeOdfgbE6FxYFMkkAJvTpfWatUej1w0taKoOLRQdc,14408
py_wake/tests/test_wind_farm_models/test_wind_farm_model.py,sha256=hsv11zdQD4X5p1aB09vOiJKJx1ZxlqqzZ1QnqBDoUB8,14464
py_wake/tests/test_windturbines/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0

@@ -398,3 +399,3 @@ py_wake/tests/test_windturbines/test_generic_wind_turbines.py,sha256=nIACFm-5iqM_bsIZxFpifGFp9S3zoF4CTwInPTmhz7I,5502

py_wake/utils/floris_wrapper.py,sha256=aEaDMo9kLtYyPGKkpwVjAV10iSC3GvhSkbr2rM7ndvE,1401
py_wake/utils/fuga_utils.py,sha256=WRAo0wcR1nuUAGtRv7cZAlQE3sAhUFQ1zYRhWxZx22s,15586
py_wake/utils/fuga_utils.py,sha256=2V49V9jjm0H7JC0ph1-0sgVcvCBiLGNjpZPxyRIkWfg,14955
py_wake/utils/functions.py,sha256=YiQTF-JBX00Oi8kvbYMeP8zGiCi90qbz8Zhc-N6lrEs,1966

@@ -408,8 +409,9 @@ py_wake/utils/generic_power_ct_curves.py,sha256=kY8z7a4qZ8fBxYBYS5ULC8j0wlE_LHxPxLPH5LDQO_Y,3957

py_wake/utils/model_utils.py,sha256=JYC1xYuJ5U720Tc7_jB_iDFvYaRZ_WlN-Py0JPOho_M,15389
py_wake/utils/most.py,sha256=9DEZ5C06qdttfGdfUCyaFCGt-YT8xPnQ3URIuHpbcdE,1208
py_wake/utils/notebook_extensions.py,sha256=E0UOiQ1AAMaIbnnzsyj-gGv8oRWD8wAvHsj2BN10LXU,704
py_wake/utils/numpy_utils.py,sha256=I9URsvF0ALXOFwdlkTK-mQLul0d-5wLjSWuEeAmE5ZU,3192
py_wake/utils/parallelization.py,sha256=5xl2TozyilPJJvNObd8hLTWALa0oYl_d2C1d1261ECQ,1321
py_wake/utils/parallelization.py,sha256=7eCsS-2A26N8P8dmdkX2d7eW4jy0jQoFOcPxA24DbcU,2082
py_wake/utils/plotting.py,sha256=zXharIIWIwl-E0Xh2JP3qAnYEEAKGJidQcldhRd0dRo,568
py_wake/utils/profiling.py,sha256=GuE0UcQaZ3KsVnklLHSDFpCc0jQ4fixh0VREwA3aHQ0,4618
py_wake/utils/rans_lut_utils.py,sha256=QRKW8yVmFmvqftbTDgJlkyc0r3WXQRayI3u4qSIeSvA,11129
py_wake/utils/rans_lut_utils.py,sha256=nQut0o1agTcP-vAumQ9DjITtO5oJUD0NB4S0nVhApoQ,11381
py_wake/utils/streamline.py,sha256=NSiA7acgkeh8iUepqalvSt7XhWS7U4POvoZq2LZCaIc,2172

@@ -422,10 +424,10 @@ py_wake/utils/tensorflow_surrogate_utils.py,sha256=QdIPqxoYiuXFvieHQyP-TE6gS8syXbxoUZ1liCBFil0,7198

py_wake/validation/lillgrund.py,sha256=WI0pWg9mvAvWqWKGL-YKbX8AoQTdb-8AglguYI6JiE8,4135
py_wake/validation/validation.py,sha256=V__7l8nOJhTB0gqc8aVQkzBEQilOBsgc3jMLAH1TKVM,20522
py_wake/validation/validation.py,sha256=jJBBlNSHlb49s4MI0THkMV3nhYVEUOSbr8afr3rX7Ho,20578
py_wake/validation/validation_lib.py,sha256=C_Rf-51ZjMlGdlDFha8JF4t0ByJY9zFrPtmDQU0t1Uo,27559
py_wake/wind_farm_models/__init__.py,sha256=cl0nC9vqhXgpRuaCFkQpDET2Yyzbwnd5Kv2wgZHUI6E,137
py_wake/wind_farm_models/engineering_models.py,sha256=rIWn0rbF7iWtygbTy4ksJYyieokZw6RQO_g4uaVKgjk,59553
py_wake/wind_farm_models/engineering_models.py,sha256=V9Ebkm2uMz0mo4iyzu_ELT4pEMn7qs-uRsJi-q_esbI,60738
py_wake/wind_farm_models/minimalistic_wind_farm_model.py,sha256=geyeFlxI71PPs19pDSWDaQgiSyxaJqNTcuXI1he93_0,11124
py_wake/wind_farm_models/wind_farm_model.py,sha256=uKfD3vVELU9e2Ys96M-u-xJIbk9WqJKBKCquY9GaG9Q,42251
py_wake/wind_farm_models/wind_farm_model.py,sha256=7_Bcwlca0Q-EmoFcsM8vFtlQhV-dEcByTtY5LLUlsA4,41812
py_wake/wind_turbines/__init__.py,sha256=w1D9rLfxk7m_UdrqbVVokWwAikxIzeRh6Wb9zVT2Mhs,145
py_wake/wind_turbines/_wind_turbines.py,sha256=8KpGPdAg7u3rgoYbj3TKq1illG_g9e7BzThHnb1eT7o,17950
py_wake/wind_turbines/_wind_turbines.py,sha256=IAIaERtPtRR6QwhHweKC1Vqi8IYqjBV2ebmaby2Mqqo,19010
py_wake/wind_turbines/generic_wind_turbines.py,sha256=SiV-hganUn9TO8ItM8ZPVuJ0BqKIuig5-vA6miSGJeY,9456

@@ -435,6 +437,6 @@ py_wake/wind_turbines/power_ct_functions.py,sha256=CjWKehvop9kMPclU54pFp_hRG7_3bqCx16cJlz5QduU,22663

py_wake/wind_turbines/wind_turbines_deprecated.py,sha256=HpNmBR8CJL4-8JBaygDI0t086qfw5bR2DOQI8Ox4AZ4,6250
py_wake-2.6.12.dist-info/licenses/LICENSE,sha256=XE2CGPqQgzSXqIajXpAVYJ5SRNmaWOIeMePK6MocsuY,1084
py_wake-2.6.12.dist-info/METADATA,sha256=HNp-tDeJKjgOZA7a3IBOUS1L3BOkSf6FDdsYcncg9I0,3596
py_wake-2.6.12.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
py_wake-2.6.12.dist-info/top_level.txt,sha256=GsaXU4YwyMkZZ6dkb4h0FMc5RaLIT2Qns_YoScKoXdk,20
py_wake-2.6.12.dist-info/RECORD,,
py_wake-2.6.13.dist-info/licenses/LICENSE,sha256=XE2CGPqQgzSXqIajXpAVYJ5SRNmaWOIeMePK6MocsuY,1084
py_wake-2.6.13.dist-info/METADATA,sha256=fpTWS7ZgV4KrfCqxIDfNfV-qTxPc295iQmBlADMgfpg,3596
py_wake-2.6.13.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
py_wake-2.6.13.dist-info/top_level.txt,sha256=GsaXU4YwyMkZZ6dkb4h0FMc5RaLIT2Qns_YoScKoXdk,20
py_wake-2.6.13.dist-info/RECORD,,