File size: 12,843 Bytes
100edb4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
import streamlit as st
import torch
# from Pangu-Weather import *
import numpy as np
from datetime import datetime
import numpy as np
import onnx
import onnxruntime as ort
import matplotlib.pyplot as plt
import cartopy.crs as ccrs
import io

def fengwu_config_data():
    st.subheader("FengWu Model Data Input")

    # Detailed data description section
    st.markdown("""
    **Input Data Requirements (FengWu):**  
    FengWu takes **two consecutive six-hour atmospheric states** as input:
    1. **First Input (input1.npy)**: Atmospheric data at the initial time.  
    2. **Second Input (input2.npy)**: Atmospheric data 6 hours later.

    **Shape & Variables:**  
    Each input is a NumPy array with shape `(69, 721, 1440)`:
    - **Dimension 0 (69 features):**  
      The first 4 features are surface variables:  
      1. U10 (10-meter Eastward Wind)  
      2. V10 (10-meter Northward Wind)  
      3. T2M (2-meter Temperature)  
      4. MSL (Mean Sea Level Pressure)

      These are followed by non-surface variables, each with 13 pressure levels:  
      - Z (Geopotential)  
      - Q (Specific Humidity)  
      - U (Eastward Wind)  
      - V (Northward Wind)  
      - T (Temperature)  

      The 13 vertical levels are: [50, 100, 150, 200, 250, 300, 400, 500, 600, 700, 850, 925, 1000] hPa

      The total count is:  
      - Surface vars: 4  
      - For each non-surface var (Z, Q, U, V, T): 13 levels = 65 vars  
      4 (surface) + 65 (5 vars * 13 levels) = 69 total features.

    **Spatial & Coordinate Details:**  
    - Latitude dimension (721 points) ranges from 90°N to -90°S with ~0.25° spacing.
    - Longitude dimension (1440 points) ranges from 0° to 360°E with ~0.25° spacing.
    - Ensure data is single precision floats (`.astype(np.float32)`).

    **Data Frequency & Forecasting Scheme:**  
    - `input1.npy` corresponds to a given time (e.g., 06:00 UTC Jan 1, 2018).
    - `input2.npy` corresponds to 6 hours later (e.g., 12:00 UTC Jan 1, 2018).
    - The model predicts future states at subsequent 6-hour intervals.

    **Converting Your Data:**  
    - ERA5 `.nc` files or ECMWF `.grib` files can be converted to `.npy` using appropriate Python packages (`netCDF4` or `pygrib`).
    - Ensure you follow the exact variable and level ordering as described.


    """)

    # File uploaders for FengWu input data (two consecutive time steps)
    st.markdown("### Upload Your FengWu Input Data Files")
    input1_file = st.file_uploader(
        "Upload input1.npy (Initial Time)",
        type=["npy"],
        key="fengwu_input1"
    )

    input2_file = st.file_uploader(
        "Upload input2.npy (6 Hours Later)",
        type=["npy"],
        key="fengwu_input2"
    )

    st.markdown("---")
    st.markdown("### References & Resources")
    st.markdown("""
    - **Research Paper:** [FengWu: Pushing the Skillful Global Medium-range Weather Forecast beyond 10 Days Lead](https://arxiv.org/abs/2304.02948)
                
    - **GitHub Source Code:** [Fengwu on GitHub](https://github.com/OpenEarthLab/FengWu?tab=readme-ov-file)
    """)

    return input1_file, input2_file


@st.cache_resource
def inference_6hrs_fengwu(input1, input2):
    model_6 = onnx.load('FengWu/fengwu_v2.onnx')

    # Set the behavier of onnxruntime
    options = ort.SessionOptions()
    options.enable_cpu_mem_arena=False
    options.enable_mem_pattern = False
    options.enable_mem_reuse = False
    # Increase the number for faster inference and more memory consumption
    options.intra_op_num_threads = 1

    # Set the behavier of cuda provider
    cuda_provider_options = {'arena_extend_strategy':'kSameAsRequested',}

    # Initialize onnxruntime session for Pangu-Weather Models
    ort_session_6 = ort.InferenceSession('FengWu/fengwu_v2.onnx', sess_options=options, providers=[('CUDAExecutionProvider', cuda_provider_options)])


    data_mean = np.load("FengWu/data_mean.npy")[:, np.newaxis, np.newaxis]
    data_std = np.load("FengWu/data_std.npy")[:, np.newaxis, np.newaxis]

    input1_after_norm = (input1 - data_mean) / data_std
    input2_after_norm = (input2 - data_mean) / data_std
    input = np.concatenate((input1_after_norm, input2_after_norm), axis=0)[np.newaxis, :, :, :]
    input = input.astype(np.float32)

    output = ort_session_6.run(None, {'input':input})[0]
    output = (output[0, :69] * data_std) + data_mean

    return output


@st.cache_resource
def inference_12hrs_fengwu(input1, input2):
    model_6 = onnx.load('FengWu/fengwu_v2.onnx')

    # Set the behavier of onnxruntime
    options = ort.SessionOptions()
    options.enable_cpu_mem_arena=False
    options.enable_mem_pattern = False
    options.enable_mem_reuse = False
    # Increase the number for faster inference and more memory consumption
    options.intra_op_num_threads = 1

    # Set the behavier of cuda provider
    cuda_provider_options = {'arena_extend_strategy':'kSameAsRequested',}

    # Initialize onnxruntime session for Pangu-Weather Models
    ort_session_6 = ort.InferenceSession('FengWu/fengwu_v2.onnx', sess_options=options, providers=[('CUDAExecutionProvider', cuda_provider_options)])


    data_mean = np.load("FengWu/data_mean.npy")[:, np.newaxis, np.newaxis]
    data_std = np.load("FengWu/data_std.npy")[:, np.newaxis, np.newaxis]

    input1_after_norm = (input1 - data_mean) / data_std
    input2_after_norm = (input2 - data_mean) / data_std
    input = np.concatenate((input1_after_norm, input2_after_norm), axis=0)[np.newaxis, :, :, :]
    input = input.astype(np.float32)

    for i in range(2):
        output = ort_session_6.run(None, {'input':input})[0]
        input = np.concatenate((input[:, 69:], output[:, :69]), axis=1)
        output = (output[0, :69] * data_std) + data_mean
        # print(output.shape)

    return output

@st.cache_resource
def inference_custom_hrs_fengwu(input1, input2, forecast_hours):
    model_6 = onnx.load('FengWu/fengwu_v2.onnx')

    # Set the behavier of onnxruntime
    options = ort.SessionOptions()
    options.enable_cpu_mem_arena=False
    options.enable_mem_pattern = False
    options.enable_mem_reuse = False
    # Increase the number for faster inference and more memory consumption
    options.intra_op_num_threads = 1

    # Set the behavier of cuda provider
    cuda_provider_options = {'arena_extend_strategy':'kSameAsRequested',}

    # Initialize onnxruntime session for Pangu-Weather Models
    ort_session_6 = ort.InferenceSession('FengWu/fengwu_v2.onnx', sess_options=options, providers=[('CUDAExecutionProvider', cuda_provider_options)])


    data_mean = np.load("FengWu/data_mean.npy")[:, np.newaxis, np.newaxis]
    data_std = np.load("FengWu/data_std.npy")[:, np.newaxis, np.newaxis]

    input1_after_norm = (input1 - data_mean) / data_std
    input2_after_norm = (input2 - data_mean) / data_std
    input = np.concatenate((input1_after_norm, input2_after_norm), axis=0)[np.newaxis, :, :, :]
    input = input.astype(np.float32)

    for i in range(forecast_hours/6):
        output = ort_session_6.run(None, {'input':input})[0]
        input = np.concatenate((input[:, 69:], output[:, :69]), axis=1)
        output = (output[0, :69] * data_std) + data_mean
        # print(output.shape)

    return output

def plot_fengwu_output(initial_data, predicted_data):
    """
    Plot initial and predicted Fengwu model outputs.
    
    Parameters:
    - initial_data: np.ndarray of shape (69, 721, 1440) representing the initial or input state.
    - predicted_data: np.ndarray of shape (69, 721, 1440) representing the predicted state by Fengwu.
    """
    # Coordinate setup
    lat = np.linspace(90, -90, 721)   # Latitude from 90N to 90S
    lon = np.linspace(0, 360, 1440)   # Longitude from 0E to 360E

    # Surface and upper-level variable definitions
    surface_vars = ["U10", "V10", "T2M", "MSL"]
    upper_vars = ["Z (Geopotential)", "Q (Specific Humidity)", "U (Eastward Wind)", "V (Northward Wind)", "T (Temperature)"]
    upper_levels = [50,100,150,200,250,300,400,500,600,700,850,925,1000]

    # Mapping of upper variable groups to their starting indices
    # Each group has 13 levels, so indices shift by 13 for each subsequent group.
    var_group_start = {
        "Z (Geopotential)": 4,   # Z starts at index 4
        "Q (Specific Humidity)": 17,  # Q = 4+13=17
        "U (Eastward Wind)": 30, # U = 17+13=30
        "V (Northward Wind)": 43,# V = 30+13=43
        "T (Temperature)": 56    # T = 43+13=56
    }

    # --- Initial Data Visualization ---
    st.subheader("Initial Data Visualization (Fengwu)")
    init_col1, init_col2 = st.columns([1,1])

    with init_col1:
        init_data_choice = st.selectbox("Data Source", ["Upper-Air Data", "Surface Data"], key="fengwu_init_data_choice")
    with init_col2:
        if init_data_choice == "Upper-Air Data":
            init_var = st.selectbox("Variable", upper_vars, key="fengwu_init_upper_var")
        else:
            init_var = st.selectbox("Variable", surface_vars, key="fengwu_init_surface_var")

    # Select the data slice for initial data
    if init_data_choice == "Upper-Air Data":
        selected_level_hpa_init = st.select_slider(
            "Select Pressure Level (hPa)",
            options=upper_levels,
            value=850,  # Default to 850hPa
            help="Select the pressure level in hPa.",
            key="fengwu_init_level_hpa_slider"
        )
        level_index_init = upper_levels.index(selected_level_hpa_init)
        start_index_init = var_group_start[init_var]
        data_index_init = start_index_init + level_index_init
        data_to_plot_init = initial_data[data_index_init, :, :]
        title_init = f"Initial Upper-Air: {init_var} at {selected_level_hpa_init}hPa"
    else:
        # Surface variable
        var_index_init = surface_vars.index(init_var)
        data_to_plot_init = initial_data[var_index_init, :, :]
        title_init = f"Initial Surface: {init_var}"

    # Plot initial data
    fig_init, ax_init = plt.subplots(figsize=(10, 5), subplot_kw={'projection': ccrs.PlateCarree()})
    ax_init.set_title(title_init)
    im_init = ax_init.imshow(data_to_plot_init, extent=[lon.min(), lon.max(), lat.min(), lat.max()],
                             origin='lower', cmap='coolwarm', transform=ccrs.PlateCarree())
    ax_init.coastlines()
    plt.colorbar(im_init, ax=ax_init, orientation='horizontal', pad=0.05)
    st.pyplot(fig_init)

    # --- Predicted Data Visualization ---
    st.subheader("Predicted Data Visualization (Fengwu)")
    pred_col1, pred_col2 = st.columns([1,1])

    with pred_col1:
        pred_data_choice = st.selectbox("Data Source", ["Upper-Air Data", "Surface Data"], key="fengwu_pred_data_choice")
    with pred_col2:
        if pred_data_choice == "Upper-Air Data":
            pred_var = st.selectbox("Variable", upper_vars, key="fengwu_pred_upper_var")
        else:
            pred_var = st.selectbox("Variable", surface_vars, key="fengwu_pred_surface_var")

    # Select the data slice for predicted data
    if pred_data_choice == "Upper-Air Data":
        selected_level_hpa_pred = st.select_slider(
            "Select Pressure Level (hPa)",
            options=upper_levels,
            value=850,  # Default to 850hPa
            help="Select the pressure level in hPa.",
            key="fengwu_pred_level_hpa_slider"
        )
        level_index_pred = upper_levels.index(selected_level_hpa_pred)
        start_index_pred = var_group_start[pred_var]
        data_index_pred = start_index_pred + level_index_pred
        data_to_plot_pred = predicted_data[data_index_pred, :, :]
        title_pred = f"Predicted Upper-Air: {pred_var} at {selected_level_hpa_pred}hPa"
    else:
        # Surface variable for predicted data
        var_index_pred = surface_vars.index(pred_var)
        data_to_plot_pred = predicted_data[var_index_pred, :, :]
        title_pred = f"Predicted Surface: {pred_var}"

    # Plot predicted data
    fig_pred, ax_pred = plt.subplots(figsize=(10, 5), subplot_kw={'projection': ccrs.PlateCarree()})
    ax_pred.set_title(title_pred)
    im_pred = ax_pred.imshow(data_to_plot_pred, extent=[lon.min(), lon.max(), lat.min(), lat.max()],
                             origin='lower', cmap='coolwarm', transform=ccrs.PlateCarree())
    ax_pred.coastlines()
    plt.colorbar(im_pred, ax=ax_pred, orientation='horizontal', pad=0.05)
    st.pyplot(fig_pred)

    # --- Download Buttons ---
    st.subheader("Download Predicted Fengwu Data")

    # Convert predicted_data to binary format for download
    buffer_pred = io.BytesIO()
    np.save(buffer_pred, predicted_data)
    buffer_pred.seek(0)

    st.download_button(label="Download Predicted Fengwu Data",
                       data=buffer_pred,
                       file_name="predicted_fengwu.npy",
                       mime="application/octet-stream")