177 lines
6.1 KiB
Cython
177 lines
6.1 KiB
Cython
# distutils: language = c++
|
||
# cython: boundscheck = False
|
||
# cython: wraparound = False
|
||
# cython: cdivision = True
|
||
|
||
import numpy as np
|
||
cimport numpy as cnp
|
||
from libc.math cimport exp, cos, tanh, log10, pow,atan2,sqrt
|
||
from cython.parallel import prange
|
||
|
||
cdef double windspeedcmd5n(double angle, double incidenceangle, double sigma0) nogil:
|
||
"""
|
||
CMOD5N模型计算风速 - Cython优化版本
|
||
|
||
输入参数:
|
||
angle - 风向角度(度)
|
||
incidenceangle - 入射角(度)
|
||
sigma0 - 后向散射系数(dB)
|
||
输出参数:
|
||
U - 计算得到的风速(m/s)
|
||
"""
|
||
# 声明C类型变量
|
||
# cdef double U=0
|
||
cdef int i=0
|
||
cdef double y0, n, a, b, x, a0, a1, a2, gamma, s0, s, g, alpha, f
|
||
cdef double b0, b1, b2, angle_rad, sigma0_model, v0, d1, d2, y, v2
|
||
|
||
# CMOD5N模型系数 - 使用C数组存储以提高性能
|
||
cdef double[29] cmod5_c = [
|
||
0, -0.6878, -0.7957, 0.3380, -0.1728, 0.0000, 0.0040, 0.1103, 0.0159,
|
||
6.7329, 2.7713, -2.2885, 0.4971, -0.7250, 0.0450,
|
||
0.0066, 0.3222, 0.0120, 22.7000, 2.0813, 3.0000, 8.3659,
|
||
-3.3428, 1.3236, 6.2437, 2.3893, 0.3249, 4.1590, 1.6930
|
||
]
|
||
|
||
# 确保入射角不小于16度
|
||
if incidenceangle <= 16.0:
|
||
incidenceangle = 16.0
|
||
|
||
i=0
|
||
cdef int start = 0
|
||
cdef int end = 2601
|
||
# 在0-26m/s范围内搜索风速
|
||
for i in range(start, end): # 0到26.0,步长0.01,共2601次迭代
|
||
U_actual = i * 0.01
|
||
|
||
# 计算归一化参数
|
||
y0 = cmod5_c[19] # 索引从0开始
|
||
n = cmod5_c[20]
|
||
a = y0 - (y0 - 1.0) / n
|
||
b = 1.0 / (n * pow(y0 - 1.0, n - 1.0))
|
||
|
||
# 归一化入射角
|
||
x = (incidenceangle - 40.0) / 25.0
|
||
|
||
# 计算基础后向散射系数
|
||
a0 = (cmod5_c[1] + cmod5_c[2] * x + cmod5_c[3] * x * x +
|
||
cmod5_c[4] * x * x * x)
|
||
a1 = cmod5_c[5] + cmod5_c[6] * x
|
||
a2 = cmod5_c[7] + cmod5_c[8] * x
|
||
gamma = (cmod5_c[9] + cmod5_c[10] * x +
|
||
cmod5_c[11] * x * x)
|
||
s0 = cmod5_c[12] + cmod5_c[13] * x
|
||
s = a2 * U_actual
|
||
|
||
# 计算饱和函数
|
||
if s < s0:
|
||
g = 1.0 / (1.0 + exp(-s0))
|
||
alpha = s0 * (1.0 - g)
|
||
f = pow(s / s0, alpha) * g
|
||
else:
|
||
f = 1.0 / (1.0 + exp(-s))
|
||
|
||
# 计算各向同性部分
|
||
b0 = pow(f, gamma) * pow(10.0, a0 + a1 * U_actual)
|
||
|
||
# 计算一阶调和系数
|
||
b1 = (cmod5_c[15] * U_actual *
|
||
(0.5 + x - tanh(4.0 * (x + cmod5_c[16] + cmod5_c[17] * U_actual))))
|
||
b1 = ((cmod5_c[14] * (1.0 + x) - b1) /
|
||
(exp(0.34 * (U_actual - cmod5_c[18])) + 1.0))
|
||
|
||
# 计算二阶调和系数
|
||
v0 = cmod5_c[21] + cmod5_c[22] * x + cmod5_c[23] * x * x
|
||
d1 = cmod5_c[24] + cmod5_c[25] * x + cmod5_c[26] * x * x
|
||
d2 = cmod5_c[27] + cmod5_c[28] * x
|
||
y = (U_actual / v0 + 1.0)
|
||
|
||
if y < y0:
|
||
v2 = a + b * pow(y - 1.0, n)
|
||
else:
|
||
v2 = y
|
||
|
||
b2 = (-d1 + d2 * v2) * exp(-v2)
|
||
|
||
# 计算模拟后向散射系数并与实测值比较
|
||
angle_rad = angle * 3.141592653589793 / 180.0
|
||
sigma0_model = (10.0 * log10(b0 *
|
||
pow(1.0 + b1 * cos(angle_rad) + b2 * cos(2.0 * angle_rad), 1.6)))
|
||
|
||
if (sigma0_model - sigma0) >= 0.0: # 函数为单调的
|
||
return U_actual
|
||
|
||
# 如果未找到匹配的风速,返回最大值
|
||
return 26.0
|
||
|
||
|
||
|
||
cdef void windspeedCmod5n_parallel(float[:, :] wind_dir,
|
||
float[:, :] inc_angle,
|
||
float[:, :] sigma0,
|
||
double[:, :] out_wind_speed) nogil:
|
||
cdef int rowcount = wind_dir.shape[0]
|
||
cdef int colcount = wind_dir.shape[1]
|
||
cdef int rowid, colid
|
||
|
||
for rowid in prange(rowcount, nogil=True, schedule='static'): # 使用prange
|
||
for colid in range(colcount):
|
||
# 通过内存视图访问数据是纯C操作,无需GIL
|
||
out_wind_speed[rowid, colid] = windspeedcmd5n(
|
||
wind_dir[rowid, colid],
|
||
inc_angle[rowid, colid],
|
||
sigma0[rowid, colid]
|
||
)
|
||
|
||
cdef void ERA5_windAngle_parallel(float[:, :] wind_U10,
|
||
float[:, :] wind_V10,
|
||
float[:, :] out_wind_angle) nogil:
|
||
cdef int rowcount = wind_U10.shape[0]
|
||
cdef int colcount = wind_U10.shape[1]
|
||
cdef int rowid, colid
|
||
cdef double V=0;
|
||
cdef double sinValue=0;
|
||
cdef double cosValue=0;
|
||
cdef double U10=0
|
||
cdef double V10=0
|
||
for rowid in prange(rowcount, nogil=True, schedule='static'):
|
||
for colid in range(colcount):
|
||
U10=wind_U10[rowid,colid]
|
||
V10=wind_V10[rowid,colid]
|
||
V=sqrt(U10*U10+V10*V10)
|
||
sinValue=-U10/V
|
||
cosValue=-V10/V
|
||
out_wind_angle[rowid, colid] =<float>atan2(sinValue,cosValue)
|
||
|
||
|
||
|
||
|
||
|
||
def python_ERA5_windAngle(cnp.ndarray[float,ndim=2] wind_U10, cnp.ndarray[float,ndim=2] wind_V10):
|
||
cdef float[:, :] out_wind_angle = np.empty((wind_U10.shape[0], wind_U10.shape[1]), dtype=np.float32)
|
||
cdef float[:, :] wind_U10_view = wind_U10
|
||
cdef float[:, :] wind_V10_view = wind_V10
|
||
with nogil:
|
||
ERA5_windAngle_parallel(wind_U10_view, wind_V10_view,out_wind_angle)
|
||
return np.asarray(out_wind_angle)
|
||
|
||
|
||
# 4. 提供一个Python包装函数(如果需要从Python调用)
|
||
def python_windspeedCmod5n(cnp.ndarray[float,ndim=2] wind_dir, cnp.ndarray[float,ndim=2] inc_angle, cnp.ndarray[float,ndim=2] sigma0):
|
||
# 1. 创建输出数组
|
||
cdef double[:, :] out_speed = np.empty((wind_dir.shape[0], wind_dir.shape[1]), dtype=np.float64)
|
||
|
||
# 2. 将输入的numpy数组转换为内存视图
|
||
cdef float[:, :] wind_dir_view = wind_dir
|
||
cdef float[:, :] inc_angle_view = inc_angle
|
||
cdef float[:, :] sigma0_view = sigma0
|
||
|
||
# 3. 在nogil上下文中执行核心计算
|
||
with nogil:
|
||
windspeedCmod5n_parallel(wind_dir_view, inc_angle_view, sigma0_view, out_speed)
|
||
|
||
# 4. 将结果内存视图转换回numpy数组并返回
|
||
return np.asarray(out_speed)
|
||
|
||
|