# 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] =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)