Newer
Older

Mads M. Pedersen
committed
import numpy as np
from abc import ABC, abstractmethod
class SuperpositionModel(ABC):
@abstractmethod

Mads M. Pedersen
committed
def calc_effective_WS(self, WS_xxx, deficit_jxxx):

Mads M. Pedersen
committed
"""Calculate effective wind speed
This method must be overridden by subclass
Parameters
----------

Mads M. Pedersen
committed
WS_xxx : array_like
Local wind speed. xxx optionally includes destination turbine/site, wind directions, wind speeds
deficit_jxxx : array_like
deficit caused by source turbines(j) on xxx (see above)

Mads M. Pedersen
committed
Returns
-------

Mads M. Pedersen
committed
WS_eff_xxx : array_like
Effective wind speed for xxx (see WS_xxx)

Mads M. Pedersen
committed
"""
class SquaredSum(SuperpositionModel):

Mads M. Pedersen
committed
def calc_effective_WS(self, WS_xxx, deficit_jxxx):
return WS_xxx - np.sqrt(np.sum(deficit_jxxx**2, 0))

Mads M. Pedersen
committed
class LinearSum(SuperpositionModel):

Mads M. Pedersen
committed
def calc_effective_WS(self, WS_xxx, deficit_jxxx):
return WS_xxx - np.sum(deficit_jxxx, 0)

Mads M. Pedersen
committed
class MaxSum(SuperpositionModel):

Mads M. Pedersen
committed
def calc_effective_WS(self, WS_xxx, deficit_jxxx):
return WS_xxx - np.max(deficit_jxxx, 0)
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
class WeightedSum(SuperpositionModel):
"""
Implemented according to the paper by:
Haohua Zong and Fernando Porté-Agel
A momentum-conserving wake superposition method for wind farm power prediction
J. Fluid Mech. (2020), vol. 889, A8; doi:10.1017/jfm.2020.77
"""
def calc_effective_WS(self, WS_xxx, centerline_deficit_jxxx,
convection_velocity_jxxx,
sigma_sqr_jxxx, cw_jxxx, hcw_jxxx, dh_jxxx):
Ws = WS_xxx
usc = centerline_deficit_jxxx
uc = convection_velocity_jxxx
sigma_sqr = sigma_sqr_jxxx
cw = cw_jxxx
hcw = hcw_jxxx
dh = dh_jxxx
# Determine non-centreline deficit ratio
# Local deficit
us = usc * np.exp(-1 / (2 * sigma_sqr) * cw**2)
# Total cross-wind integrated deficit
us_int = usc * 2 * np.pi * sigma_sqr
# Combined qunatities
Uc = Ws.copy()
Uc_star = Ws.copy()
Us = np.zeros_like(Ws)
Us_int = np.zeros_like(Ws)
# Initialize
count = 0
Uc_star = 10 * Uc
# Iterate until combined convection velocity converges
while (np.max(np.abs((Uc - Uc_star) / Uc_star)) > 1e-3) and (count < 10):
# Initialize combined convection velocity
if count == 0:
Uc = np.max(uc, 0)
else:
Uc = Uc_star
# Initialize and avoid division by zero
ucn = np.ones_like(uc)
Inz = Uc != 0
ucn[:, Inz] = uc[:, Inz] / Uc[Inz]
# Combined local deficit
Us = np.sum(ucn * us, 0)
# Combined deficit integrated to infinity in cross-wind direction
Us_int = np.sum(ucn * us_int, 0)
# Calculate the integral of Us**2
sum1, sum2 = np.zeros_like(Us), np.zeros_like(Us)
n_wt = us.shape[0]
for j in np.arange(0, n_wt):
sum1 += (ucn[j] * usc[j])**2 * np.pi * sigma_sqr[j]
if n_wt > 0:
sum2 = np.zeros_like(Us)
for j in range(n_wt):
for k in np.arange(j + 1, n_wt):
cross_sigma_jk = np.zeros_like(Ws)
s1, s2 = sigma_sqr[j], sigma_sqr[k]
# Distance between turbines
w2w_hcw = np.abs(hcw[j] - hcw[k])
w2w_dh = np.abs(dh[j] - dh[k])
cross_sigma_jk = 2 * np.exp(-(w2w_hcw**2 + w2w_dh**2) /
(2 * (s1 + s2))) * np.pi * s1 * s2 / (s1 + s2)
sum2 += 2 * (ucn[j] * usc[j]) * (ucn[k] * usc[k]) * cross_sigma_jk
# Avoid division by zero
Us_int[Us_int == 0] = 1
# Update combined convection velocity
Uc_star = Ws - (sum1 + sum2) / Us_int
count += 1
return Ws - Us