pyqihou 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
pyqihou-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,45 @@
1
+ Metadata-Version: 2.4
2
+ Name: pyqihou
3
+ Version: 0.1.0
4
+ Summary: Python Package for Climate Analysis
5
+ Author-email: VVVictorZhou <ahme02147483647a@gmail.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/VVVICTORZHOU/
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Operating System :: OS Independent
11
+ Requires-Python: >=3.6
12
+ Description-Content-Type: text/markdown
13
+ Requires-Dist: numpy>=1.19.5
14
+ Requires-Dist: scipy>=1.5.4
15
+ Requires-Dist: windspharm>=1.7.0
16
+ Requires-Dist: xarray>=0.16.2
17
+
18
+ ## How to install the `pyqihou` package:
19
+
20
+ - Method 1: `npm install pyqihou`
21
+
22
+ - Method 2: `pip install pyqihou`
23
+
24
+
25
+ ## Functions in the `pyqihou` package:
26
+ ### `water.py`
27
+
28
+ - `MassIntegrationAlongPressure`: 沿著垂直氣壓層執行大氣變數的質量積分。
29
+ - `HorizontalMoistureAdvection`: 計算水平水氣平流的熱力學與動力學分解項,並進行氣壓層垂直積分。
30
+ - `VerticalMoistureAdvection`: 計算垂直水氣平流的熱力學與動力學分解項,並進行氣壓層垂直積分。
31
+ - `RelativeHumidity`: 依據溫度、比濕與氣壓計算大氣相對濕度百分比。
32
+ - `VaporPressureDeficit`: 依據溫度、比濕與氣壓計算水氣壓差 (VPD)。
33
+
34
+ ### `energy.py`
35
+
36
+ - `MixedLayerHeatBudget`: 計算混合層熱平衡的各項輻射、熱通量與物理分解項。
37
+ - `NetEnergyInput`: 計算大氣與地表的淨能量輸入 (NEI)。
38
+ - `EnergyFluxPotential`: 計算能量通量位勢 (EFP) 並自動處理標準網格內插與還原。
39
+ - `MeridionalMassStreamFunction`: 計算經向質量經流函數 (MSF)。
40
+ - `ZonalMassStreamFunction`: 計算緯向質量經流函數 (MSF)。
41
+ - `HorizontalTN01WaveActivityFlux`: 計算幾何校正版的 Takaya-Nakamura (2001) 水平波活動通量與其散度。
42
+
43
+
44
+
45
+
@@ -0,0 +1,28 @@
1
+ ## How to install the `pyqihou` package:
2
+
3
+ - Method 1: `npm install pyqihou`
4
+
5
+ - Method 2: `pip install pyqihou`
6
+
7
+
8
+ ## Functions in the `pyqihou` package:
9
+ ### `water.py`
10
+
11
+ - `MassIntegrationAlongPressure`: 沿著垂直氣壓層執行大氣變數的質量積分。
12
+ - `HorizontalMoistureAdvection`: 計算水平水氣平流的熱力學與動力學分解項,並進行氣壓層垂直積分。
13
+ - `VerticalMoistureAdvection`: 計算垂直水氣平流的熱力學與動力學分解項,並進行氣壓層垂直積分。
14
+ - `RelativeHumidity`: 依據溫度、比濕與氣壓計算大氣相對濕度百分比。
15
+ - `VaporPressureDeficit`: 依據溫度、比濕與氣壓計算水氣壓差 (VPD)。
16
+
17
+ ### `energy.py`
18
+
19
+ - `MixedLayerHeatBudget`: 計算混合層熱平衡的各項輻射、熱通量與物理分解項。
20
+ - `NetEnergyInput`: 計算大氣與地表的淨能量輸入 (NEI)。
21
+ - `EnergyFluxPotential`: 計算能量通量位勢 (EFP) 並自動處理標準網格內插與還原。
22
+ - `MeridionalMassStreamFunction`: 計算經向質量經流函數 (MSF)。
23
+ - `ZonalMassStreamFunction`: 計算緯向質量經流函數 (MSF)。
24
+ - `HorizontalTN01WaveActivityFlux`: 計算幾何校正版的 Takaya-Nakamura (2001) 水平波活動通量與其散度。
25
+
26
+
27
+
28
+
@@ -0,0 +1,28 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "pyqihou"
7
+ version = "0.1.0"
8
+ description = "Python Package for Climate Analysis"
9
+ readme = "README.md"
10
+ authors = [
11
+ { name = "VVVictorZhou", email = "ahme02147483647a@gmail.com" }
12
+ ]
13
+ license = { text = "MIT" }
14
+ classifiers = [
15
+ "Programming Language :: Python :: 3",
16
+ "License :: OSI Approved :: MIT License",
17
+ "Operating System :: OS Independent",
18
+ ]
19
+ requires-python = ">=3.6"
20
+ dependencies = [
21
+ "numpy>=1.19.5",
22
+ "scipy>=1.5.4",
23
+ "windspharm>=1.7.0",
24
+ "xarray>=0.16.2"
25
+ ]
26
+
27
+ [project.urls]
28
+ Homepage = "https://github.com/VVVICTORZHOU/"
File without changes
@@ -0,0 +1,497 @@
1
+ import numpy as np
2
+ import xarray as xr
3
+ from windspharm.tools import prep_data, recover_data
4
+ from windspharm.xarray import VectorWind
5
+ import spharm.spharm
6
+ from scipy.interpolate import RegularGridInterpolator
7
+
8
+ def MixedLayerHeatBudget(EXP_TS, EXP_FSNS, EXP_FSNSC, EXP_FLNS, EXP_SHFLX, EXP_LHFLX, EXP_U10, EXP_RHREFHT, EXP_TREFHT,
9
+ CTL_TS, CTL_LHFLX, CTL_U10, CTL_RHREFHT, CTL_TREFHT):
10
+ """
11
+ 計算混合層熱平衡(Mixed Layer Heat Budget)各項通量與分解項。
12
+
13
+ Parameters
14
+ ----------
15
+ EXP_TS : np.ndarray 或 xr.DataArray
16
+ 實驗組地表溫度 (Surface Temperature),單位:K,維度形狀:(time, lat, lon) 或通用網格。
17
+ EXP_FSNS : np.ndarray 或 xr.DataArray
18
+ 實驗組表面淨短波輻射 (Surface Net Shortwave Radiation),單位:W/m^2,維度形狀同上。
19
+ EXP_FSNSC : np.ndarray 或 xr.DataArray
20
+ 實驗組表面無雲淨短波輻射 (Clear-sky Surface Net Shortwave Radiation),單位:W/m^2,維度形狀同上。
21
+ EXP_FLNS : np.ndarray 或 xr.DataArray
22
+ 實驗組表面淨長波輻射 (Surface Net Longwave Radiation),單位:W/m^2,維度形狀同上。
23
+ EXP_SHFLX : np.ndarray 或 xr.DataArray
24
+ 實驗組表面感熱通量 (Surface Sensible Heat Flux),單位:W/m^2,維度形狀同上。
25
+ EXP_LHFLX : np.ndarray 或 xr.DataArray
26
+ 實驗組表面潛熱通量 (Surface Latent Heat Flux),單位:W/m^2,維度形狀同上。
27
+ EXP_U10 : np.ndarray 或 xr.DataArray
28
+ 實驗組 10 公尺風速 (10-meter Wind Speed),單位:m/s,維度形狀同上。
29
+ EXP_RHREFHT : np.ndarray 或 xr.DataArray
30
+ 實驗組參考高度相對濕度 (Relative Humidity at Reference Height),無因次 (0-1),維度形狀同上。
31
+ EXP_TREFHT : np.ndarray 或 xr.DataArray
32
+ 實驗組參考高度溫度 (Temperature at Reference Height),單位:K,維度形狀同上。
33
+ CTL_TS : np.ndarray 或 xr.DataArray
34
+ 對照組地表溫度,單位:K,維度形狀同上。
35
+ CTL_LHFLX : np.ndarray 或 xr.DataArray
36
+ 對照組表面潛熱通量,單位:W/m^2,維度形狀同上。
37
+ CTL_U10 : np.ndarray 或 xr.DataArray
38
+ 對照組 10 公尺風速,單位:m/s,維度形狀同上。
39
+ CTL_RHREFHT : np.ndarray 或 xr.DataArray
40
+ 對照組參考高度相對濕度,無因次 (0-1),維度形狀同上。
41
+ CTL_TREFHT : np.ndarray 或 xr.DataArray
42
+ 對照組參考高度溫度,單位:K,維度形狀同上。
43
+
44
+ Returns
45
+ -------
46
+ tuple of np.ndarray
47
+ 包含以下各項的計算結果陣列(維度形狀與輸入相同):
48
+ - TS_TERM : 地表溫度項
49
+ - FSNS_TERM : 淨短波輻射項
50
+ - FSNS_CLR_TERM : 無雲淨短波輻射項
51
+ - FSNS_CLD_TERM : 雲對短波輻射效應項
52
+ - FLNS_TERM : 淨長波輻射項
53
+ - SHFLX_TERM : 感熱通量項
54
+ - LHFLX_TERM : 潛熱通量項
55
+ - LHFLX_WIND_TERM : 潛熱通量風速分解項(若缺少參數則為 None)
56
+ - LHFLX_RH_TERM : 潛熱通量相對濕度分解項(若缺少參數則為 None)
57
+ - LHFLX_TGRAD_TERM : 潛熱通量溫度梯度分解項(若缺少參數則為 None)
58
+ - Residual_TERM : 殘差項
59
+ """
60
+
61
+ Alpha = 0.06
62
+
63
+ # Left Hand Side
64
+ TS_TERM = EXP_TS
65
+
66
+ EXP_DeltaT = EXP_TREFHT - EXP_TS
67
+ CTL_DeltaT = CTL_TREFHT - CTL_TS
68
+
69
+ # Right Hand Side
70
+ FSNS_TERM = EXP_FSNS / (Alpha * CTL_LHFLX)
71
+ FSNS_CLR_TERM = EXP_FSNSC / (Alpha * CTL_LHFLX)
72
+ FSNS_CLD_TERM = FSNS_TERM - FSNS_CLR_TERM
73
+ FLNS_TERM = - EXP_FLNS / (Alpha * CTL_LHFLX)
74
+ SHFLX_TERM = - EXP_SHFLX / (Alpha * CTL_LHFLX)
75
+ LHFLX_TERM = - EXP_LHFLX / (Alpha * CTL_LHFLX)
76
+
77
+ # Residual Term
78
+ Residual_TERM = TS_TERM - (FSNS_TERM + FLNS_TERM + SHFLX_TERM + LHFLX_TERM)
79
+
80
+ # Latent Heat Term Decomposition
81
+ if EXP_RHREFHT is not None and EXP_U10 is not None and EXP_DeltaT is not None:
82
+ LHFLX_WIND_TERM = - (CTL_LHFLX * EXP_U10) / (CTL_U10 * Alpha * CTL_LHFLX)
83
+ LHFLX_RH_TERM = (CTL_LHFLX * EXP_RHREFHT) / (Alpha * CTL_LHFLX * (np.exp(- Alpha * CTL_DeltaT) - CTL_RHREFHT))
84
+ LHFLX_TGRAD_TERM = (Alpha * CTL_LHFLX * CTL_RHREFHT * EXP_DeltaT) / (Alpha * CTL_LHFLX * (np.exp(- Alpha * CTL_DeltaT) - CTL_RHREFHT))
85
+
86
+ else:
87
+ LHFLX_WIND_TERM = None
88
+ LHFLX_RH_TERM = None
89
+ LHFLX_TGRAD_TERM = None
90
+
91
+ return TS_TERM, FSNS_TERM, FSNS_CLR_TERM, FSNS_CLD_TERM, FLNS_TERM, SHFLX_TERM, LHFLX_TERM, LHFLX_WIND_TERM, LHFLX_RH_TERM, LHFLX_TGRAD_TERM, Residual_TERM
92
+
93
+
94
+ def NetEnergyInput(FSNT, FLNT, FSNS, FLNS, LHFLX, SHFLX):
95
+ """
96
+ 計算大氣與地表的淨能量輸入 (Net Energy Input, NEI)。
97
+
98
+ Parameters
99
+ ----------
100
+ FSNT : np.ndarray 或 xr.DataArray
101
+ 大氣頂向下淨短波輻射 (TOA Net Shortwave Radiation),單位:W/m^2,維度形狀:(time, lat, lon) 或 (lat, lon)。
102
+ FLNT : np.ndarray 或 xr.DataArray
103
+ 大氣頂向上長波輻射 (TOA Net Longwave Radiation),單位:W/m^2,維度形狀同上。
104
+ FSNS : np.ndarray 或 xr.DataArray
105
+ 表面向下淨短波輻射 (Surface Net Shortwave Radiation),單位:W/m^2,維度形狀同上。
106
+ FLNS : np.ndarray 或 xr.DataArray
107
+ 表面向下淨長波輻射 (Surface Net Longwave Radiation),單位:W/m^2,維度形狀同上。
108
+ LHFLX : np.ndarray 或 xr.DataArray
109
+ 表面潛熱通量 (Surface Latent Heat Flux),單位:W/m^2,維度形狀同上。
110
+ SHFLX : np.ndarray 或 xr.DataArray
111
+ 表面感熱通量 (Surface Sensible Heat Flux),單位:W/m^2,維度形狀同上。
112
+
113
+ Returns
114
+ -------
115
+ NEI : np.ndarray 或 xr.DataArray
116
+ 淨能量輸入,單位:W/m^2,維度形狀與輸入相同。
117
+ """
118
+ # Calculate the net energy input
119
+ NEI = (FSNT - FLNT) - (FSNS - FLNS - LHFLX - SHFLX)
120
+ return NEI
121
+
122
+
123
+ def EnergyFluxPotential(NEI, lat=None, lon=None, rsphere=6.3712e6):
124
+ """
125
+ 計算能量通量位勢 (Energy Flux Potential, EFP),並自動內插回與輸入 NEI 相同的網格與座標。
126
+
127
+ Parameters
128
+ ----------
129
+ NEI : np.ndarray
130
+ 淨能量輸入,單位:W/m^2,維度形狀:(time, lat, lon)。
131
+ lat : np.ndarray, optional
132
+ 輸入的 1D 緯度座標,單位:度 (°),維度形狀:(nlat,)。若為 None 則自動產生。
133
+ lon : np.ndarray, optional
134
+ 輸入的 1D 經度座標,單位:度 (°),維度形狀:(nlon,)。若為 None 則自動產生。
135
+ rsphere : float, optional
136
+ 地球半徑,單位:m,預設值為 6.3712e6。
137
+
138
+ Returns
139
+ -------
140
+ efp_out : np.ndarray
141
+ 能量通量位勢 (EFP),維度形狀與輸入 NEI 相同:(time, lat, lon)。
142
+ """
143
+ nt, nlat, nlon = NEI.shape
144
+
145
+ # 1. 自動建立或接收輸入的經緯度座標
146
+ if lat is None:
147
+ lat = np.linspace(-90, 90, nlat)
148
+ if lon is None:
149
+ lon = np.linspace(0, 360, nlon, endpoint=False)
150
+
151
+ # 2. 建立輸入資料的 xarray.DataArray
152
+ year_coords = [1] if nt == 1 else list(range(1, nt + 1))
153
+ nei_da = xr.DataArray(
154
+ NEI,
155
+ coords=[('year', year_coords), ('lat', lat), ('lon', lon)],
156
+ name='NEI'
157
+ )
158
+
159
+ # 3. 核心計算所需的標準網格(spharm 通常需要特定或標準解析度,此處維持 193 點緯度)
160
+ nlat_calc = 193
161
+ lat_calc = np.linspace(-90, 90, nlat_calc)
162
+ lon_calc = lon # 經度可以保持與輸入一致
163
+
164
+ # 先將輸入內插至計算所需的網格
165
+ nei_calc = nei_da.interp(lat=lat_calc, lon=lon_calc, method='linear')
166
+
167
+ # 若只有 1 個時間點,仿原程式複製成 3 個 year 以符合計算模組需求
168
+ is_single_time = (nt == 1)
169
+ if is_single_time:
170
+ nei_calc = xr.concat([nei_calc, nei_calc, nei_calc], dim='year')
171
+ nei_calc['year'] = [1, 2, 3]
172
+
173
+ # 4. 執行頻譜計算 (Spherical harmonic inverse Laplacian)
174
+ scalar_field, shape_info = prep_data(nei_calc.data, "tyx")
175
+ vw = VectorWind(nei_calc, nei_calc)
176
+ S = vw._api.s # Spharmt instance
177
+
178
+ scalar_field_spec = S.grdtospec(scalar_field)
179
+ ilap_spec = spharm.spharm._spherepack.invlap(scalar_field_spec, S.rsphere)
180
+ ilap_grid = S.spectogrd(ilap_spec)
181
+ efp_calc = recover_data(ilap_grid, shape_info)
182
+
183
+ # 包成計算網格的 DataArray
184
+ efp_calc_da = xr.DataArray(efp_calc, coords=nei_calc.coords, dims=nei_calc.dims, name='EFP')
185
+
186
+ # 5. 【關鍵簡化】:直接將計算結果內插回使用者「原本輸入的網格」(lat, lon)
187
+ efp_final_da = efp_calc_da.interp(lat=lat, lon=lon, method='linear')
188
+
189
+ # 6. 恢復原本的時間維度形狀
190
+ if is_single_time:
191
+ # 如果原本時間維度只有 1,取第一筆並擴展軸回 (1, lat, lon)
192
+ efp_out = np.expand_dims(efp_final_da.isel(year=0).values, axis=0)
193
+ else:
194
+ efp_out = efp_final_da.isel(year=slice(0, nt)).values
195
+
196
+ return efp_out
197
+
198
+
199
+ def MeridionalMassStreamFunction(V, lev, lat):
200
+ """
201
+ 計算經向質量經流函數 (Meridional Mass Streamfunction, MSF)。
202
+
203
+ Parameters
204
+ ----------
205
+ V : np.ndarray
206
+ 經向風速 (Meridional Wind Speed),單位:m/s,維度形狀:(lev, lat)。
207
+ lev : np.ndarray
208
+ 氣壓高度層 (Pressure Levels),單位:hPa(程式碼內部會依此計算層厚度 dP),維度形狀:(lev,)。
209
+ lat : np.ndarray
210
+ 緯度座標,單位:度 (°),維度形狀:(lat,)。
211
+
212
+ Returns
213
+ -------
214
+ final_msf : np.ndarray
215
+ 經向質量經流函數,單位:kg/s,維度形狀:(lev, lat)。
216
+ """
217
+
218
+ # 1. 處理 NaN:將地形以下的 NaN 設為 0
219
+ V_safe = np.nan_to_num(V, nan=0.0)
220
+
221
+ # 2. 計算 dP (單位已轉換: hPa -> Pa)
222
+ # 假設 lev 是從地面到高空 [1000, 950, ..., 50]
223
+ # 計算各層厚度,這裡建議使用更精確的層界(bounds)
224
+ #! only foe evenly spaced levels, for unevenly spaced levels, we should calculate the layer thickness based on the actual level values
225
+ dP = np.abs(np.gradient(lev)) # 為 Pascal
226
+
227
+ # 3. 質量修正 (V_adj) - 確保垂直積分和為 0
228
+ total_Vdp = np.sum(V_safe * dP[:, None], axis=0)
229
+ total_dP = np.sum((~np.isnan(V)) * dP[:, None], axis=0)
230
+ V_adj = total_Vdp / total_dP
231
+
232
+ # 4. 積分 (從大氣頂部向下累加)
233
+ # 使用 np.cumsum 會比寫 for loop 快且安全
234
+ V_corrected = (V_safe - V_adj)
235
+ # Multiply V and dP first, then flip and cumsum
236
+ msf = np.cumsum((V_corrected * dP[:, None])[::-1, :], axis=0)[::-1, :]
237
+
238
+ # 5. 物理常數
239
+ re = 6.371e6 # 地球半徑
240
+ g = 9.81
241
+ cos_lat = np.cos(np.deg2rad(lat))
242
+
243
+ final_msf = (2 * np.pi * re * cos_lat / g) * msf
244
+ return final_msf
245
+
246
+ def ZonalMassStreamFunction(U_lonmean, lev, lat_bounds=(-10.0, 10.0), re=6.371e6, g=9.81):
247
+ """
248
+ 計算緯向質量經流函數 (Zonal Mass Streamfunction, MSF) 或稱為 Walker 環流。
249
+
250
+ Parameters
251
+ ----------
252
+ U_lonmean : np.ndarray
253
+ 經向平均的緯向風速 (Zonal Wind Speed),單位:m/s,維度形狀:(nlev, nlon)。
254
+ NaN 值表示地形以下的缺測值。
255
+ lev : np.ndarray
256
+ 氣壓高度層 (Pressure Levels),單位:hPa,維度形狀:(nlev,),遞減 (地面到高空)。
257
+ lat_bounds : tuple, optional
258
+ 緯度平均的邊界 (南緯, 北緯),單位:度 (°),預設為 (-10.0, 10.0)。
259
+ re : float, optional
260
+ 地球半徑,單位:m,預設值為 6.371e6。
261
+ g : float, optional
262
+ 重力加速度,單位:m/s^2,預設值為 9.81。
263
+
264
+ Returns
265
+ -------
266
+ final_msf : np.ndarray
267
+ 緯向質量經流函數 (Zonal Mass Streamfunction),單位:kg/s,維度形狀:(nlev, nlon)。
268
+ 返回的結果保留原始氣壓層順序,地形以下的層仍為 NaN。
269
+ """
270
+
271
+
272
+ U = np.asarray(U_lonmean, dtype=float)
273
+ p = np.asarray(lev, dtype=float) * 100.0 # hPa -> Pa
274
+
275
+ # --------------------------------------------------
276
+ # 1. Input validation
277
+ # --------------------------------------------------
278
+ if U.ndim != 2 or U.shape[0] != len(p):
279
+ raise ValueError("U_lonmean must have shape (nlev, nlon).")
280
+
281
+ if not np.all(np.isfinite(p)):
282
+ raise ValueError("Pressure levels must be finite.")
283
+
284
+ if not np.all(np.diff(p) > 0) and not np.all(np.diff(p) < 0):
285
+ raise ValueError("Pressure levels must be strictly monotonic.")
286
+
287
+ # Sort pressure from top to bottom (increasing pressure)
288
+ if p[0] > p[-1]:
289
+ order = np.arange(len(p) - 1, -1, -1)
290
+ else:
291
+ order = np.arange(len(p))
292
+
293
+ p_sorted = p[order]
294
+ U_sorted = U[order, :]
295
+
296
+ nlev, nlon = U.shape
297
+
298
+ # --------------------------------------------------
299
+ # 2. Meridional width
300
+ # --------------------------------------------------
301
+ phi_s, phi_n = np.deg2rad(lat_bounds)
302
+ delta_phi = phi_n - phi_s
303
+
304
+ if delta_phi <= 0:
305
+ raise ValueError("Invalid latitude boundaries.")
306
+
307
+ factor = re * delta_phi / g
308
+
309
+ # --------------------------------------------------
310
+ # 3. Allocate output
311
+ # --------------------------------------------------
312
+ psi_sorted = np.full((nlev, nlon), np.nan)
313
+
314
+ # --------------------------------------------------
315
+ # 4. Process individual longitude profiles
316
+ # --------------------------------------------------
317
+ for j in range(nlon):
318
+
319
+ u_col = U_sorted[:, j]
320
+
321
+ # Valid levels
322
+ valid = np.isfinite(u_col)
323
+
324
+ # Find the first missing level (usually terrain)
325
+ invalid_idx = np.where(~valid)[0]
326
+
327
+ if len(invalid_idx) > 0:
328
+ n_valid = invalid_idx[0]
329
+
330
+ # Do not interpolate across internal missing levels
331
+ if np.any(valid[n_valid:]):
332
+ raise ValueError(
333
+ "Non-contiguous NaNs at longitude index {}."
334
+ .format(j)
335
+ )
336
+ else:
337
+ n_valid = nlev
338
+
339
+ # At least two valid pressure levels are necessary
340
+ if n_valid < 2:
341
+ continue
342
+
343
+ # Extract the contiguous atmospheric column
344
+ p_col = p_sorted[:n_valid]
345
+ u_col = u_col[:n_valid]
346
+
347
+ # Actual pressure thickness between adjacent levels
348
+ dp = np.diff(p_col)
349
+
350
+ # --------------------------------------------------
351
+ # 5. Pressure-weighted vertical mean wind
352
+ # --------------------------------------------------
353
+ total_Udp = np.sum(
354
+ 0.5 * (u_col[:-1] + u_col[1:]) * dp
355
+ )
356
+
357
+ total_dP = p_col[-1] - p_col[0]
358
+
359
+ U_adj = total_Udp / total_dP
360
+
361
+ # Remove vertically averaged zonal wind
362
+ U_corrected = u_col - U_adj
363
+
364
+ # --------------------------------------------------
365
+ # 6. Cumulative vertical integration
366
+ # --------------------------------------------------
367
+ increments = (
368
+ 0.5 * (U_corrected[:-1] + U_corrected[1:])
369
+ * dp
370
+ )
371
+
372
+ msf = np.zeros(n_valid)
373
+
374
+ msf[1:] = np.cumsum(increments)
375
+
376
+ # Enforce exact zero at the lower boundary
377
+ msf[-1] = 0.0
378
+
379
+ # --------------------------------------------------
380
+ # 7. Convert to mass streamfunction (kg/s)
381
+ # --------------------------------------------------
382
+ psi_sorted[:n_valid, j] = factor * msf
383
+
384
+ # --------------------------------------------------
385
+ # 8. Restore original pressure ordering
386
+ # --------------------------------------------------
387
+ final_msf = np.empty_like(psi_sorted)
388
+ final_msf[order, :] = psi_sorted
389
+
390
+ return final_msf
391
+
392
+
393
+ def HorizontalTN01WaveActivityFlux(CTL_U, CTL_V, EXP_Z, lon=np.linspace(0, 358.75, 288), lat=np.linspace(-90, 90, 192), p_lev=500.0):
394
+ """
395
+ 幾何校正版:計算 Takaya and Nakamura (JAS, 2001) 水平波活動通量 (HOR-TN01-WAF)。
396
+ 直接在公尺 (meter) 尺度下進行偏微分,解決低緯度/高緯度幾何變形產生的假向量。
397
+
398
+ Parameters
399
+ ----------
400
+ CTL_U : np.ndarray
401
+ 對照組緯向風速 (Zonal Wind Speed),單位:m/s,維度形狀:(lat, lon)。
402
+ CTL_V : np.ndarray
403
+ 對照組經向風速 (Meridional Wind Speed),單位:m/s,維度形狀:(lat, lon)。
404
+ EXP_Z : np.ndarray
405
+ 實驗組位勢高度或擾動位勢高度 (Geopotential Height),單位:m,維度形狀:(lat, lon)。
406
+ lon : np.ndarray, optional
407
+ 經度座標,單位:度 (°),預設為 288 個點由 0 到 358.75,維度形狀:(lon,)。
408
+ lat : np.ndarray, optional
409
+ 緯度座標,單位:度 (°),預設為 192 個點由 -90 到 90,維度形狀:(lat,)。
410
+ p_lev : float, optional
411
+ 計算通量時所使用的氣壓高度層,單位:hPa,預設值為 500.0。
412
+
413
+ Returns
414
+ -------
415
+ px : np.ndarray
416
+ 水平波活動通量的經向/x 分量,單位:m^2/s^2,維度形狀:(lat, lon)。
417
+ py : np.ndarray
418
+ 水平波活動通量的緯向/y 分量,單位:m^2/s^2,維度形狀:(lat, lon)。
419
+ psi_p : np.ndarray
420
+ 擾動流函數 (Perturbation Streamfunction),單位:m^2/s,維度形狀:(lat, lon)。
421
+ waf_div : np.ndarray
422
+ 波活動通量散度 (WAF Divergence),單位:s^-1 相關,維度形狀:(lat, lon)。
423
+ """
424
+ # 常數設定
425
+ a = 6.37e6 # 地球半徑 (m)
426
+ omega = 7.292e-5 # 地球自轉角速度 (rad/s)
427
+
428
+ # 角度轉弧度
429
+ lon_rad = np.deg2rad(lon)
430
+ lat_rad = np.deg2rad(lat)
431
+
432
+ # 計算基本的弧度網格距
433
+ dlon_rad = np.gradient(lon_rad)
434
+ dlat_rad = np.gradient(lat_rad)
435
+
436
+ # 幾何參數 (2D 廣播化)
437
+ cos_lat = np.cos(lat_rad)[:, np.newaxis]
438
+ sin_lat = np.sin(lat_rad)[:, np.newaxis]
439
+
440
+ # 科氏參數 f (2D),避開赤道無窮大
441
+ f = 2 * omega * sin_lat
442
+ f[np.abs(f) < 1e-5] = np.nan
443
+
444
+ # 1. 計算擾動流函數 psi_p (單位: m^2/s)
445
+ psi_p = EXP_Z / f
446
+
447
+ # =====================================================================
448
+ # 核心幾何修正:計算真正對應「公尺」單位的網格距 dx, dy
449
+ # dy = a * dlat (緯度方向的實際距離,每個地方都一樣)
450
+ # dx = a * cos(lat) * dlon (經度方向的實際距離,隨緯度增高而縮小)
451
+ # =====================================================================
452
+ dy_2d = a * dlat_rad[:, np.newaxis]
453
+ dx_2d = a * cos_lat * dlon_rad[np.newaxis, :]
454
+
455
+ # 2. 計算流函數對實際距離 (m) 的一階偏微分
456
+ dpsi_dx = np.gradient(psi_p, axis=1) / dx_2d
457
+ dpsi_dy = np.gradient(psi_p, axis=0) / dy_2d
458
+
459
+ # 3. 計算實際距離 (m) 的二階偏微分
460
+ d2psi_dx2 = np.gradient(dpsi_dx, axis=1) / dx_2d
461
+ d2psi_dy2 = np.gradient(dpsi_dy, axis=0) / dy_2d
462
+ d2psi_dxdy = np.gradient(dpsi_dy, axis=1) / dx_2d # 混合偏微分
463
+
464
+ # 4. 計算波活動度矩陣項 (完全回歸標準 Cartesian 物理形式)
465
+ termxu = dpsi_dx * dpsi_dx - psi_p * d2psi_dx2
466
+ termxv = dpsi_dx * dpsi_dy - psi_p * d2psi_dxdy
467
+ termyv = dpsi_dy * dpsi_dy - psi_p * d2psi_dy2
468
+
469
+ # 5. 計算風速基本場
470
+ magU = np.sqrt(CTL_U**2 + CTL_V**2)
471
+ magU[magU == 0] = np.nan
472
+
473
+ # T-N01 公式核心係數: p_normalized / (2 * |U|)
474
+ p_normalized = p_lev / 1000.0
475
+ coeff = p_normalized / (2 * magU)
476
+
477
+ # 6. 計算 WAF 分量 (單位: m^2/s^2)
478
+ # 此時公式變得極度乾淨,再也不需要除以額外的 a^2 或 cos_lat
479
+ px = coeff * (CTL_U * termxu + CTL_V * termxv)
480
+ py = coeff * (CTL_U * termxv + CTL_V * termyv)
481
+
482
+ # 7. 計算散度 (Divergence)
483
+ # 既然 px, py 已經是標準米制分量,散度直接用標準的 d(px)/dx + d(py)/dy 即可!
484
+ dp_dx = np.gradient(px, axis=1) / dx_2d
485
+ dp_dy = np.gradient(py, axis=0) / dy_2d
486
+ waf_div = dp_dx + dp_dy
487
+
488
+ # 8. 設定科學合理的邊界遮罩 (Mask)
489
+ # 準地轉理論在南北緯 10 度以內、以及 80 度以上本身就不適用
490
+ lat_mask = (np.abs(lat) > 80) | (np.abs(lat) < 15)
491
+
492
+ px[lat_mask, :] = np.nan
493
+ py[lat_mask, :] = np.nan
494
+ waf_div[lat_mask, :] = np.nan
495
+
496
+ return px, py, psi_p, waf_div
497
+
File without changes
@@ -0,0 +1,260 @@
1
+ import numpy as np
2
+
3
+
4
+ def MassIntegrationAlongPressure(pressure, variable, pmin=None, pmax=None):
5
+ """
6
+ 沿著垂直氣壓層進行質量積分(Mass Integration Along Pressure)。
7
+
8
+ Parameters
9
+ ----------
10
+ pressure : np.ndarray
11
+ 氣壓高度層,單位:hPa,維度形狀:(lev,)。
12
+ variable : np.ndarray
13
+ 欲積分的大氣變數,單位:W/kg 或對應物理量,維度形狀:(lev, lat, lon)。
14
+ pmin : float, optional
15
+ 積分的氣壓下限(高空/低壓側),單位:hPa,預設為 None(從最頂層開始)。
16
+ pmax : float, optional
17
+ 積分的氣壓上限(地表/高壓側),單位:hPa,預設為 None(到最底層結束)。
18
+
19
+ Returns
20
+ -------
21
+ integrated_variable : np.ndarray
22
+ 經垂直質量積分後的 2D 變數,維度形狀:(lat, lon)。
23
+ """
24
+ # 1. 參數驗證
25
+ if pmin is not None and not isinstance(pmin, (int, float)):
26
+ raise ValueError("pmin must be a numeric value.")
27
+ if pmax is not None and not isinstance(pmax, (int, float)):
28
+ raise ValueError("pmax must be a numeric value.")
29
+ if pmin is not None and pmax is not None and pmin >= pmax:
30
+ raise ValueError("pmin must be less than pmax.")
31
+
32
+ # 2. 轉換壓力單位為 Pa
33
+ p_pa = np.asarray(pressure, dtype=float) * 100.0
34
+ Pa_to_kg_per_m2 = 0.1 # 1/g
35
+
36
+ # 3. 計算不等間距的 dp 與對應的 dm
37
+ dp_array = np.abs(np.gradient(p_pa)) # [lev,]
38
+ dm = dp_array * Pa_to_kg_per_m2 # [lev,]
39
+
40
+ # 4. 建立垂直層條件遮罩 (Mask)
41
+ mask = np.ones(p_pa.shape[0], dtype=bool)
42
+ pmin_pa = pmin * 100.0 if pmin is not None else None
43
+ pmax_pa = pmax * 100.0 if pmax is not None else None
44
+
45
+ for i, p in enumerate(p_pa):
46
+ if pmin_pa is not None and p < pmin_pa:
47
+ mask[i] = False
48
+ if pmax_pa is not None and p > pmax_pa:
49
+ mask[i] = False
50
+
51
+ # 套用遮罩:不符合範圍的層其 dm 設為 0
52
+ masked_dm = np.where(mask, dm, 0.0)
53
+
54
+ # 5. 處理變數中的 NaN 並進行廣播矩陣乘法
55
+ var_clean = np.nan_to_num(variable, nan=0.0)
56
+
57
+ # 利用 broadcasting 將 dm [lev] 擴展為 [lev, 1, 1] 與 variable 相乘後在 lev 軸(axis=0)加總
58
+ integrated_variable = np.sum(var_clean * masked_dm[:, None, None], axis=0)
59
+
60
+ return integrated_variable.astype(np.float32)
61
+
62
+
63
+ def HorizontalMoistureAdvection(pressure, CTL_u, CTL_v, CTL_q, EXP_u, EXP_v, EXP_q, pmin=None, pmax=None):
64
+ """
65
+ 計算水平水氣平流項的熱力學分解與動力學分解,並沿氣壓層垂直積分。
66
+
67
+ Parameters
68
+ ----------
69
+ pressure : np.ndarray
70
+ 氣壓高度層,單位:hPa,維度形狀:(lev,)。
71
+ CTL_u : np.ndarray
72
+ 對照組緯向風速 (Zonal Wind),單位:m/s,維度形狀:(lev, lat, lon)。
73
+ CTL_v : np.ndarray
74
+ 對照組經向風速 (Meridional Wind),單位:m/s,維度形狀:(lev, lat, lon)。
75
+ CTL_q : np.ndarray
76
+ 對照組比濕 (Specific Humidity),單位:kg/kg,維度形狀:(lev, lat, lon)。
77
+ EXP_u : np.ndarray
78
+ 實驗組緯向風速,單位:m/s,維度形狀:(lev, lat, lon)。
79
+ EXP_v : np.ndarray
80
+ 實驗組經向風速,單位:m/s,維度形狀:(lev, lat, lon)。
81
+ EXP_q : np.ndarray
82
+ 實驗組比濕,單位:kg/kg,維度形狀:(lev, lat, lon)。
83
+ pmin : float, optional
84
+ 垂直積分的氣壓下限,單位:hPa,預設為 None。
85
+ pmax : float, optional
86
+ 垂直積分的氣壓上限,單位:hPa,預設為 None。
87
+
88
+ Returns
89
+ -------
90
+ integrated_thermodynamic_term : np.ndarray
91
+ 積分後的水平水氣平流熱力學項,單位:W/m^2 (經潛熱轉換),維度形狀:(lat, lon)。
92
+ integrated_dynamic_term : np.ndarray
93
+ 積分後的水平水氣平流動力學項,單位:W/m^2 (經潛熱轉換),維度形狀:(lat, lon)。
94
+ """
95
+ assert CTL_u.shape == CTL_v.shape == CTL_q.shape == EXP_u.shape == EXP_v.shape == EXP_q.shape
96
+
97
+ # set up the grid
98
+ dx, dy = 1.25*110*1000, 180/192*110*1000 # m
99
+ thermodynamic_term = np.zeros_like(CTL_u)
100
+ dynamic_term = np.zeros_like(CTL_u)
101
+
102
+ # unit conversion for q
103
+ latent_heat = 2.5e6 # [J/kg]
104
+ CTL_q_energy = CTL_q * latent_heat
105
+ EXP_q_energy = EXP_q * latent_heat
106
+
107
+ # calculate the gradient of q
108
+ CTL_dqdx = np.gradient(CTL_q_energy, dx, axis=2)
109
+ CTL_dqdy = np.gradient(CTL_q_energy, dy, axis=1)
110
+ EXP_dqdx = np.gradient(EXP_q_energy, dx, axis=2)
111
+ EXP_dqdy = np.gradient(EXP_q_energy, dy, axis=1)
112
+
113
+ # 計算平流項
114
+ for lev in range(0, CTL_u.shape[0]):
115
+ thermodynamic_term[lev, :, :] = CTL_u[lev, :, :] * EXP_dqdx[lev, :, :] + CTL_v[lev, :, :] * EXP_dqdy[lev, :, :]
116
+ dynamic_term[lev, :, :] = CTL_dqdx[lev, :, :] * EXP_u[lev, :, :] + CTL_dqdy[lev, :, :] * EXP_v[lev, :, :]
117
+
118
+ # 呼叫積分函數
119
+ integrated_thermodynamic_term = -MassIntegrationAlongPressure(pressure, thermodynamic_term, pmin=pmin, pmax=pmax)
120
+ integrated_dynamic_term = -MassIntegrationAlongPressure(pressure, dynamic_term, pmin=pmin, pmax=pmax)
121
+
122
+ return integrated_thermodynamic_term, integrated_dynamic_term
123
+
124
+
125
+ def VerticalMoistureAdvection(pressure, CTL_omega, CTL_q, EXP_omega, EXP_q, pmin=None, pmax=None):
126
+ """
127
+ 計算垂直水氣平流項的熱力學分解與動力學分解,並沿氣壓層垂直積分。
128
+
129
+ Parameters
130
+ ----------
131
+ pressure : np.ndarray
132
+ 氣壓高度層,單位:hPa,維度形狀:(lev,)。
133
+ CTL_omega : np.ndarray
134
+ 對照組垂直p速度 (Pressure Velocity),單位:Pa/s,維度形狀:(lev, lat, lon)。
135
+ CTL_q : np.ndarray
136
+ 對照組比濕,單位:kg/kg,維度形狀:(lev, lat, lon)。
137
+ EXP_omega : np.ndarray
138
+ 實驗組垂直p速度,單位:Pa/s,維度形狀:(lev, lat, lon)。
139
+ EXP_q : np.ndarray
140
+ 實驗組比濕,單位:kg/kg,維度形狀:(lev, lat, lon)。
141
+ pmin : float, optional
142
+ 垂直積分的氣壓下限,單位:hPa,預設為 None。
143
+ pmax : float, optional
144
+ 垂直積分的氣壓上限,單位:hPa,預設為 None。
145
+
146
+ Returns
147
+ -------
148
+ integrated_thermodynamic_term : np.ndarray
149
+ 積分後的垂直水氣平流熱力學項,單位:W/m^2 (經潛熱轉換),維度形狀:(lat, lon)。
150
+ integrated_dynamic_term : np.ndarray
151
+ 積分後的垂直水氣平流動力學項,單位:W/m^2 (經潛熱轉換),維度形狀:(lat, lon)。
152
+ """
153
+ assert CTL_omega.shape == CTL_q.shape == EXP_omega.shape == EXP_q.shape
154
+
155
+ # --- 將 pressure 轉為 Pa 陣列,直接作為 np.gradient 的坐標軸 ---
156
+ p_pa = pressure * 100.0
157
+
158
+ # unit conversion for q
159
+ latent_heat = 2.5e6 # [J/kg]
160
+ CTL_q_energy = CTL_q * latent_heat
161
+ EXP_q_energy = EXP_q * latent_heat
162
+
163
+ # --- 使用非等間距的 p_pa 陣列進行垂直梯度計算 ---
164
+ # 當 np.gradient 的第二個參數傳入 1D array 時,它會自動依據該坐標計算非等間距差分
165
+ CTL_dqdp = np.gradient(CTL_q_energy, p_pa, axis=0)
166
+ EXP_dqdp = np.gradient(EXP_q_energy, p_pa, axis=0)
167
+
168
+ thermodynamic_term = np.zeros_like(CTL_omega)
169
+ dynamic_term = np.zeros_like(CTL_omega)
170
+
171
+ for lev in range(0, CTL_omega.shape[0]):
172
+ thermodynamic_term[lev, :, :] = CTL_omega[lev, :, :] * EXP_dqdp[lev, :, :]
173
+ dynamic_term[lev, :, :] = CTL_dqdp[lev, :, :] * EXP_omega[lev, :, :]
174
+
175
+ integrated_thermodynamic_term = MassIntegrationAlongPressure(pressure, thermodynamic_term, pmin=pmin, pmax=pmax)
176
+ integrated_dynamic_term = MassIntegrationAlongPressure(pressure, dynamic_term, pmin=pmin, pmax=pmax)
177
+
178
+ return integrated_thermodynamic_term, integrated_dynamic_term
179
+
180
+
181
+ def RelativeHumidity(T, Q, P):
182
+ """
183
+ 利用溫度、比濕與氣壓計算相對濕度 (Relative Humidity, RH)。
184
+
185
+ Parameters
186
+ ----------
187
+ T : float 或 np.ndarray
188
+ 溫度,單位:Kelvin (K),維度形狀:與輸入相符(純量或任意陣列)。
189
+ Q : float 或 np.ndarray
190
+ 比濕 (Specific Humidity),單位:kg/kg,維度形狀:與輸入相符。
191
+ P : float 或 np.ndarray
192
+ 氣壓 (Pressure),單位:Pa,維度形狀:與輸入相符。
193
+
194
+ Returns
195
+ -------
196
+ rh : np.ndarray
197
+ 相對濕度,單位:百分比 (%),已被限制在 0-100 之間,維度形狀與輸入相同。
198
+ """
199
+ # 1. 轉為攝氏溫度
200
+ T_c = T - 273.15
201
+
202
+ # 2. 計算飽和蒸氣壓 es (單位: Pa)
203
+ # 使用 Bolton (1980) 公式,精度高且適合大氣運算
204
+ es = 611.2 * np.exp((17.67 * T_c) / (T_c + 243.5))
205
+
206
+ # 3. 計算混合比 w (mixing ratio)
207
+ w = Q / (1.0 - Q)
208
+
209
+ # 4. 計算實際蒸氣壓 e (單位: Pa)
210
+ # epsilon (水氣與乾空氣分子量比) ≅ 0.622
211
+ epsilon = 0.622
212
+ e = (w * P) / (epsilon + w)
213
+
214
+ # 5. 計算 RH
215
+ rh = (e / es) * 100.0
216
+
217
+ # 限制 RH 在 0-100% 之間
218
+ rh = np.clip(rh, 0, 100)
219
+
220
+ return rh.astype(np.float32)
221
+
222
+
223
+
224
+ def VaporPressureDeficit(T, Q, P):
225
+ """
226
+ 利用溫度、比濕與氣壓計算水氣壓差 (Vapor Pressure Deficit, VPD)。
227
+
228
+ Parameters
229
+ ----------
230
+ T : float 或 np.ndarray
231
+ 溫度,單位:Kelvin (K),維度形狀:與輸入相符。
232
+ Q : float 或 np.ndarray
233
+ 比濕 (Specific Humidity),單位:kg/kg,維度形狀:與輸入相符。
234
+ P : float 或 np.ndarray
235
+ 氣壓 (Pressure),單位:Pa,維度形狀:與輸入相符。
236
+
237
+ Returns
238
+ -------
239
+ vpd : np.ndarray
240
+ 水氣壓差,單位:Pa,已確保不會出現負值,維度形狀與輸入相同。
241
+ """
242
+ # 1. 轉為攝氏溫度
243
+ T_c = T - 273.15
244
+
245
+ # 2. 計算飽和蒸氣壓 es (單位: Pa)
246
+ # 使用 Bolton (1980) 公式,精度高且適合大氣運算
247
+ es = 611.2 * np.exp((17.67 * T_c) / (T_c + 243.5))
248
+
249
+ # 3. 計算混合比 w (mixing ratio)
250
+ w = Q / (1.0 - Q)
251
+
252
+ # 4. 計算實際蒸氣壓 e (單位: Pa)
253
+ # epsilon (水氣與乾空氣分子量比) ≅ 0.622
254
+ epsilon = 0.622
255
+ e = (w * P) / (epsilon + w)
256
+
257
+ # 5. 計算 VPD
258
+ vpd = np.maximum(0, es - e) # 確保不會出現負值
259
+
260
+ return vpd.astype(np.float32)
@@ -0,0 +1,45 @@
1
+ Metadata-Version: 2.4
2
+ Name: pyqihou
3
+ Version: 0.1.0
4
+ Summary: Python Package for Climate Analysis
5
+ Author-email: VVVictorZhou <ahme02147483647a@gmail.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/VVVICTORZHOU/
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Operating System :: OS Independent
11
+ Requires-Python: >=3.6
12
+ Description-Content-Type: text/markdown
13
+ Requires-Dist: numpy>=1.19.5
14
+ Requires-Dist: scipy>=1.5.4
15
+ Requires-Dist: windspharm>=1.7.0
16
+ Requires-Dist: xarray>=0.16.2
17
+
18
+ ## How to install the `pyqihou` package:
19
+
20
+ - Method 1: `npm install pyqihou`
21
+
22
+ - Method 2: `pip install pyqihou`
23
+
24
+
25
+ ## Functions in the `pyqihou` package:
26
+ ### `water.py`
27
+
28
+ - `MassIntegrationAlongPressure`: 沿著垂直氣壓層執行大氣變數的質量積分。
29
+ - `HorizontalMoistureAdvection`: 計算水平水氣平流的熱力學與動力學分解項,並進行氣壓層垂直積分。
30
+ - `VerticalMoistureAdvection`: 計算垂直水氣平流的熱力學與動力學分解項,並進行氣壓層垂直積分。
31
+ - `RelativeHumidity`: 依據溫度、比濕與氣壓計算大氣相對濕度百分比。
32
+ - `VaporPressureDeficit`: 依據溫度、比濕與氣壓計算水氣壓差 (VPD)。
33
+
34
+ ### `energy.py`
35
+
36
+ - `MixedLayerHeatBudget`: 計算混合層熱平衡的各項輻射、熱通量與物理分解項。
37
+ - `NetEnergyInput`: 計算大氣與地表的淨能量輸入 (NEI)。
38
+ - `EnergyFluxPotential`: 計算能量通量位勢 (EFP) 並自動處理標準網格內插與還原。
39
+ - `MeridionalMassStreamFunction`: 計算經向質量經流函數 (MSF)。
40
+ - `ZonalMassStreamFunction`: 計算緯向質量經流函數 (MSF)。
41
+ - `HorizontalTN01WaveActivityFlux`: 計算幾何校正版的 Takaya-Nakamura (2001) 水平波活動通量與其散度。
42
+
43
+
44
+
45
+
@@ -0,0 +1,11 @@
1
+ README.md
2
+ pyproject.toml
3
+ pyqihou/__init__.py
4
+ pyqihou/energy.py
5
+ pyqihou/statistic.py
6
+ pyqihou/water.py
7
+ pyqihou.egg-info/PKG-INFO
8
+ pyqihou.egg-info/SOURCES.txt
9
+ pyqihou.egg-info/dependency_links.txt
10
+ pyqihou.egg-info/requires.txt
11
+ pyqihou.egg-info/top_level.txt
@@ -0,0 +1,4 @@
1
+ numpy>=1.19.5
2
+ scipy>=1.5.4
3
+ windspharm>=1.7.0
4
+ xarray>=0.16.2
@@ -0,0 +1 @@
1
+ pyqihou
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+