Skip to content

Commit ce0377c

Browse files
committed
Further updates to zoom and pan stuff.
1 parent 9104feb commit ce0377c

1 file changed

Lines changed: 188 additions & 9 deletions

File tree

python/herbie_datagrab.py

Lines changed: 188 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -53,30 +53,67 @@ def process_wind_data(lat, lon, date, level=850):
5353
target_date_utc = target_date_utc.astimezone(ZoneInfo('UTC'))
5454
print(f"Converted to UTC: {target_date_utc}")
5555

56+
# Check if target date is in the future - adjust to latest available data
57+
now_utc = datetime.datetime.now(ZoneInfo('UTC'))
58+
if target_date_utc > now_utc:
59+
print(f"Target date {target_date_utc} is in the future, using current time: {now_utc}")
60+
target_date_utc = now_utc
61+
5662
# Find the appropriate GFS initialization time and forecast hour
5763
# GFS runs every 6 hours: 00, 06, 12, 18 UTC
5864
gfs_init_hours = [0, 6, 12, 18]
5965

66+
# For future dates or very recent dates, we need to account for GFS processing delay
67+
# GFS data typically becomes available 3-4 hours after initialization time
68+
processing_delay_hours = 4
69+
latest_available_time = now_utc - datetime.timedelta(hours=processing_delay_hours)
70+
71+
# If target date is too recent, adjust it
72+
if target_date_utc > latest_available_time:
73+
print(f"Target date {target_date_utc} may not have GFS data yet, using {latest_available_time}")
74+
target_date_utc = latest_available_time
75+
6076
# Find the most recent GFS initialization time before or at the target time
6177
target_hour = target_date_utc.hour
6278

63-
# Find the closest GFS init time (floor)
64-
init_hour = max([h for h in gfs_init_hours if h <= target_hour], default=18)
79+
# Find the closest GFS init time (floor) for the target date
80+
suitable_init_hours = [h for h in gfs_init_hours if h <= target_hour]
6581

66-
# If no suitable init hour found for today, use the last run from yesterday
67-
if init_hour > target_hour:
68-
init_date_utc = (target_date_utc - datetime.timedelta(days=1)).replace(hour=18, minute=0, second=0, microsecond=0)
69-
fxx = target_hour + 6 # Hours from yesterday 18Z
70-
else:
82+
if suitable_init_hours:
83+
init_hour = max(suitable_init_hours)
7184
init_date_utc = target_date_utc.replace(hour=init_hour, minute=0, second=0, microsecond=0)
7285
fxx = target_hour - init_hour
86+
else:
87+
# If no suitable init hour found for today, use the last run from yesterday
88+
init_date_utc = (target_date_utc - datetime.timedelta(days=1)).replace(hour=18, minute=0, second=0, microsecond=0)
89+
fxx = target_hour + 6 # Hours from yesterday 18Z
90+
91+
# Ensure the initialization time is not in the future considering processing delay
92+
if init_date_utc + datetime.timedelta(hours=processing_delay_hours) > now_utc:
93+
print(f"Calculated init time {init_date_utc} is too recent, falling back to previous run")
94+
# Fall back to previous 6-hour cycle
95+
if init_hour > 0:
96+
prev_init_hour = max([h for h in gfs_init_hours if h < init_hour])
97+
init_date_utc = target_date_utc.replace(hour=prev_init_hour, minute=0, second=0, microsecond=0)
98+
fxx = target_hour - prev_init_hour
99+
else:
100+
# Fall back to yesterday's 18Z run
101+
init_date_utc = (target_date_utc - datetime.timedelta(days=1)).replace(hour=18, minute=0, second=0, microsecond=0)
102+
fxx = target_hour + 6
73103

74-
print(f"GFS initialization: {init_date_utc}, forecast hour: {fxx}")
104+
# Cap forecast hours at reasonable limits (GFS forecasts go out to ~384 hours)
105+
if fxx > 120: # Use max 5-day forecast for better data availability
106+
print(f"Forecast hour {fxx} is too far out, adjusting to more recent data")
107+
# Adjust to use a more recent initialization with shorter forecast
108+
while fxx > 120 and init_date_utc > target_date_utc - datetime.timedelta(days=3):
109+
init_date_utc -= datetime.timedelta(hours=6)
110+
fxx += 6
111+
112+
print(f"Final GFS initialization: {init_date_utc}, forecast hour: {fxx}")
75113

76114
# Convert to naive datetime for Herbie (it expects naive UTC datetimes)
77115
init_date_naive = init_date_utc.replace(tzinfo=None)
78116

79-
# Create data directory relative to script location
80117
script_dir = os.path.dirname(os.path.abspath(__file__))
81118
data_dir = os.path.join(script_dir, '..', 'data')
82119
os.makedirs(data_dir, exist_ok=True)
@@ -106,6 +143,148 @@ def process_wind_data(lat, lon, date, level=850):
106143

107144
print("Fetching new GFS data...")
108145

146+
# Try multiple forecast hours if the exact one fails (for robustness)
147+
for attempt_fxx in [fxx, max(0, fxx-1), max(0, fxx-2), fxx+1, fxx+2]:
148+
try:
149+
print(f"Attempting to fetch GFS data with fxx={attempt_fxx}")
150+
gfs_data = fetch_gfs_data(lat, lon, init_date_naive, attempt_fxx, level)
151+
152+
if gfs_data is not None:
153+
print(f"Successfully fetched GFS data with fxx={attempt_fxx}, processing...")
154+
155+
# Check if we have the required variables
156+
if 'u' not in gfs_data or 'v' not in gfs_data:
157+
print("Error: GFS data missing u or v components")
158+
print(f"Available variables: {list(gfs_data.keys())}")
159+
continue
160+
161+
u = gfs_data['u']
162+
v = gfs_data['v']
163+
164+
lon_step = float(gfs_data.longitude[1] - gfs_data.longitude[0])
165+
lat_step = float(gfs_data.latitude[0] - gfs_data.latitude[1]) # lat is decreasing
166+
167+
velocity_u = convert_wind_to_velocity_json(u, "u", level, target_date_utc, init_date_utc, lon_step, lat_step)
168+
velocity_v = convert_wind_to_velocity_json(v, "v", level, target_date_utc, init_date_utc, lon_step, lat_step)
169+
170+
result = [velocity_u, velocity_v]
171+
172+
# Save to cache
173+
try:
174+
with open(filename, "w") as f:
175+
json.dump(result, f, indent=2)
176+
print(f"Saved weather data to: {filename}")
177+
except Exception as e:
178+
print(f"Warning: Could not save cached file: {e}")
179+
180+
print(f"Successfully processed wind data - returning {len(result)} components")
181+
return result
182+
183+
except Exception as e:
184+
print(f"Attempt with fxx={attempt_fxx} failed: {e}")
185+
continue
186+
187+
print("Failed to fetch GFS data with all attempted forecast hours")
188+
return None(__file__)
189+
data_dir = os.path.join(script_dir, '..', 'data')
190+
os.makedirs(data_dir, exist_ok=True)
191+
192+
# Generate filename
193+
date_str = init_date_naive.strftime("%Y%m%d%H")
194+
if fxx > 0:
195+
filename = os.path.join(data_dir, f"gfs_velocity_{date_str}_f{fxx:03d}_{level}mb.json")
196+
else:
197+
filename = os.path.join(data_dir, f"gfs_velocity_{date_str}_{level}mb.json")
198+
199+
print(f"Looking for cached file: {filename}")
200+
201+
# Check if file already exists and is recent
202+
if os.path.exists(filename):
203+
try:
204+
# Check if file is recent (less than 6 hours old)
205+
file_age = datetime.datetime.now() - datetime.datetime.fromtimestamp(os.path.getmtime(filename))
206+
if file_age < datetime.timedelta(hours=6):
207+
print(f"Loading recent cached file: {filename}")
208+
with open(filename, "r") as f:
209+
return json.load(f)
210+
else:
211+
print(f"Cached file is old ({file_age}), fetching new data...")
212+
except Exception as e:
213+
print(f"Error loading cached file: {e}")
214+
215+
print("Fetching new GFS data...")
216+
217+
# Try multiple forecast hours if the exact one fails (for robustness)
218+
for attempt_fxx in [fxx, max(0, fxx-1), max(0, fxx-2), fxx+1, fxx+2]:
219+
try:
220+
print(f"Attempting to fetch GFS data with fxx={attempt_fxx}")
221+
gfs_data = fetch_gfs_data(lat, lon, init_date_naive, attempt_fxx, level)
222+
223+
if gfs_data is not None:
224+
print(f"Successfully fetched GFS data with fxx={attempt_fxx}, processing...")
225+
226+
# Check if we have the required variables
227+
if 'u' not in gfs_data or 'v' not in gfs_data:
228+
print("Error: GFS data missing u or v components")
229+
print(f"Available variables: {list(gfs_data.keys())}")
230+
continue
231+
232+
u = gfs_data['u']
233+
v = gfs_data['v']
234+
235+
lon_step = float(gfs_data.longitude[1] - gfs_data.longitude[0])
236+
lat_step = float(gfs_data.latitude[0] - gfs_data.latitude[1]) # lat is decreasing
237+
238+
velocity_u = convert_wind_to_velocity_json(u, "u", level, target_date_utc, init_date_utc, lon_step, lat_step)
239+
velocity_v = convert_wind_to_velocity_json(v, "v", level, target_date_utc, init_date_utc, lon_step, lat_step)
240+
241+
result = [velocity_u, velocity_v]
242+
243+
# Save to cache
244+
try:
245+
with open(filename, "w") as f:
246+
json.dump(result, f, indent=2)
247+
print(f"Saved weather data to: {filename}")
248+
except Exception as e:
249+
print(f"Warning: Could not save cached file: {e}")
250+
251+
print(f"Successfully processed wind data - returning {len(result)} components")
252+
return result
253+
254+
except Exception as e:
255+
print(f"Attempt with fxx={attempt_fxx} failed: {e}")
256+
continue
257+
258+
print("Failed to fetch GFS data with all attempted forecast hours")
259+
return None(__file__)
260+
data_dir = os.path.join(script_dir, '..', 'data')
261+
os.makedirs(data_dir, exist_ok=True)
262+
263+
# Generate filename
264+
date_str = init_date_naive.strftime("%Y%m%d%H")
265+
if fxx > 0:
266+
filename = os.path.join(data_dir, f"gfs_velocity_{date_str}_f{fxx:03d}_{level}mb.json")
267+
else:
268+
filename = os.path.join(data_dir, f"gfs_velocity_{date_str}_{level}mb.json")
269+
270+
print(f"Looking for cached file: {filename}")
271+
272+
# Check if file already exists and is recent
273+
if os.path.exists(filename):
274+
try:
275+
# Check if file is recent (less than 6 hours old)
276+
file_age = datetime.datetime.now() - datetime.datetime.fromtimestamp(os.path.getmtime(filename))
277+
if file_age < datetime.timedelta(hours=6):
278+
print(f"Loading recent cached file: {filename}")
279+
with open(filename, "r") as f:
280+
return json.load(f)
281+
else:
282+
print(f"Cached file is old ({file_age}), fetching new data...")
283+
except Exception as e:
284+
print(f"Error loading cached file: {e}")
285+
286+
print("Fetching new GFS data...")
287+
109288
try:
110289
gfs_data = fetch_gfs_data(lat, lon, init_date_naive, fxx, level)
111290

0 commit comments

Comments
 (0)