Flight plan - HALO-20240829a

Contents

Flight plan - HALO-20240829a#

ec_under ec_track c_north c_mid c_south c_atr

Crew#

The flight is planned to take off at 2024-08-29 12:20:00+00:00.

Job

Name

PI

Silke Gross

WALES

Georgios Dekoutsidis

HAMP

Christian Heske

Dropsondes

Nina Robbins

Smart/VELOX

Michael Schäfer

SpecMACS

Veronika Pörtge

Flight Documentation

Basile Poujol

Ground contact

Julia Windmiller

Flight plan#

Hide code cell source
from dataclasses import asdict
from datetime import datetime
import cartopy.crs as ccrs
import easygems.healpix as egh
import intake
import matplotlib.pyplot as plt
import numpy as np
import orcestra
import orcestra.flightplan as fp
import orcestra.sat
from orcestra.flightplan import LatLon, IntoCircle, bco, sal, mindelo, find_ec_lon, vertical_preview, to_kml\

def ec_time_at_lat(ec_track, lat):
    e = np.datetime64("2024-08-01")
    s = np.timedelta64(1, "ns")
    return (((ec_track.swap_dims({"time":"lat"}).time - e) / s).interp(lat=lat) * s + e)

# Global coordinates and definitions that should not change from flight to flight

lon_min, lon_max, lat_min, lat_max = -65, -5, -5, 25

radius = 130e3
atr_radius = 72e3

band = "east"
airport = sal if band == "east" else bco
natal = LatLon(-5 - 47/60. - 42.00/3600.,-35 - 12/60. - 33.98/3600., label = "natal")

# Basic information
lon_min, lon_max, lat_min, lat_max = -65, -5, -5, 25

# Define dates for forecast initialization and flight

issued_time = datetime(2024, 8, 27, 0, 0, 0)

flight_time = datetime(2024, 8, 29, 12, 0, 0)
flight_index = f"HALO-{flight_time.strftime('%Y%m%d')}a"

# adjust takeoff time to match EC overpass
takeoff_time = np.datetime64("2025-08-29T12:20:00")

print(
    f"Initalization date of IFS forecast: {issued_time}\n"
    f"Flight date: {flight_time:%Y-%m-%d}\n"
    f"Flight index: {flight_index}"
)

crew = {'Mission PI': 'Silke Gross',
        'DropSondes': 'Nina Robbins',
        'HAMP': 'Christian Heske',
        'SMART/VELOX': 'Michael Schäfer',
        'SpecMACS': 'Veronika Pörtge',
        'WALES' : 'Georgios Dekoutsidis',
        'Flight Documentation': 'Basile Poujol',
        'Ground Support': 'Julia Windmiller',
        }

# Load forecast data
cat = intake.open_catalog("https://tcodata.mpimet.mpg.de/internal.yaml")
ds = cat.HIFS(datetime = issued_time).to_dask().pipe(egh.attach_coords)

# Load ec satellite track for 
ec_track = orcestra.sat.SattrackLoader("EARTHCARE", "2024-08-26", kind="PRE").get_track_for_day(f"{flight_time:%Y-%m-%d}")
ec_track = ec_track.sel(time=slice(f"{flight_time:%Y-%m-%d} 06:00", None))
ec_lons, ec_lats = ec_track.lon.values, ec_track.lat.values

# Latitudes where we enter and leave the ec track (visually estimated)
lat_ec_north = 15.0
lat_ec_south = 2.5

# latitude of circle centers
lat_c_south_s = 3.5
lat_c_south = 4.5
lat_c_south_n = 5.5
lat_c_north = 13.0

lat_c_mid_s = 7.5
lat_c_mid = 8.5
lat_c_mid_n = 9.5

lat_ec_under = 5.0

c_atr_nw = LatLon(18.58125000,-24.27616667, label = "c_atr")
c_atr_se = LatLon(15.79318333,-24.82891944, label = "c_atr")


# create ec track
ec_north = LatLon(lat_ec_north, find_ec_lon(lat_ec_north, ec_lons, ec_lats), label = "ec_north")
ec_south = LatLon(lat_ec_south, find_ec_lon(lat_ec_south, ec_lons, ec_lats), label = "ec_south")

# create circles
c_north = LatLon(lat_c_north, find_ec_lon(lat_c_north, ec_lons, ec_lats), label = "c_north")

c_south = LatLon(lat_c_south, find_ec_lon(lat_c_south, ec_lons, ec_lats), label = "c_south")
c_south_s = LatLon(lat_c_south_s, find_ec_lon(lat_c_south_s, ec_lons, ec_lats), label = "c_south_s")
c_south_n = LatLon(lat_c_south_n, find_ec_lon(lat_c_south_n, ec_lons, ec_lats), label = "c_south_n")

c_mid = LatLon(lat_c_mid, find_ec_lon(lat_c_mid, ec_lons, ec_lats), label = "c_mid")
c_mid_s = LatLon(lat_c_mid_s, find_ec_lon(lat_c_mid_s, ec_lons, ec_lats), label = "c_mid_s")
c_mid_n = LatLon(lat_c_mid_n, find_ec_lon(lat_c_mid_n, ec_lons, ec_lats), label = "c_mid_n")

# ec underpass
ec_under = LatLon(lat_ec_under, find_ec_lon(lat_ec_under, ec_lons, ec_lats), label = "ec_under")
ec_under = ec_under.assign(time=str(ec_time_at_lat(ec_track, ec_under.lat).values)+"Z")

# Define flight track
outbound_legs = [
     airport,
     mindelo,
     ec_north.assign(fl=410),
     ]

ec_legs = [
     IntoCircle(c_south.assign(fl=430), radius, 360),   
     ec_south.assign(fl=410),
     ec_under.assign(fl=450),
     IntoCircle(c_mid.assign(fl=430), radius, 360), 
     IntoCircle(c_north.assign(fl=450), radius, 360),   
     ]
inbound_legs = [
     ec_north.assign(fl=450),
     IntoCircle(c_atr_nw.assign(fl=350), atr_radius, 360),
     IntoCircle(c_atr_se.assign(fl=350), atr_radius, 360),
     airport,
     ]

waypoints = outbound_legs + ec_legs + inbound_legs 

waypoint_centers = []
for point in waypoints:
    if isinstance(point, IntoCircle):
        point = point.center
    waypoint_centers.append(point)

path = fp.expand_path(waypoints, dx=10e3)

plan = path.isel(distance = path.waypoint_indices).to_dataframe().set_index("waypoint_labels")


xwp_2 = LatLon(lat_c_south-1, find_ec_lon(lat_c_south-1, ec_lons, ec_lats), label = "xwp2")
xwp_3 = LatLon(c_atr_nw.lat,c_atr_nw.lon, label = "xwp3")
extra_waypoints = [xwp_2,xwp_3]

notes = {'c_south_in':f' {radius/1852:2.0f} nm circle centered at {c_south.format_pilot()}, enter from north, CCW',
        'c_mid_in':f' {radius/1852:2.0f} nm circle centered at {c_mid.format_pilot()}, enter from north, CCW',
        'c_north_in':f' {radius/1852:2.0f} nm circle centered at {c_north.format_pilot()}, enter from south, CCW',
        'c_atr_in':f' {atr_radius/1852:2.0f} nm circle centered at {c_atr_se.format_pilot()}, enter from west, CW',
        'xwp2':'Alternative center for c_south',
        'xwp3':'Alternative center for c_atr',
         }

plt.figure(figsize = (14, 8))
ax = plt.axes(projection=ccrs.PlateCarree())
ax.set_extent([lon_min, lon_max, lat_min, lat_max], crs=ccrs.PlateCarree())
ax.coastlines(alpha=1.0)
ax.gridlines(draw_labels=True, dms=True, x_inline=False, y_inline=False, alpha = 0.25)

cwv_flight_time = ds["tcwv"].sel(time=flight_time, method = "nearest")
fp.plot_cwv(cwv_flight_time, levels = [50.0, 60.0])
plt.title(f"{flight_time}\n(CWV forecast issued on {issued_time})")

plt.plot(ec_lons, ec_lats, c='k', ls='dotted')

if (False):
    plt.plot([natal.lon,sal.lon], [natal.lat,sal.lat], c='purple', ls='dashed')

for wp in waypoint_centers:
    plt.scatter(wp.lon,wp.lat,s=10.,color='k')
for wp in extra_waypoints:
    plt.scatter(wp.lon,wp.lat,s=10.,color='r',marker='o')
fp.plot_path(path, ax, color="C1")
Initalization date of IFS forecast: 2024-08-27 00:00:00
Flight date: 2024-08-29
Flight index: HALO-20240829a
/home/runner/miniconda3/envs/orcestra_book/lib/python3.12/site-packages/orcestra/sat.py:180: UserWarning: You are using an old forecast (issued on 2024-08-26) for EARTHCARE on 2024-08-29! The newest forecast issued so far was issued on 2024-08-29. It's a PRE forecast.
  warnings.warn(
../_images/3d8e330977525deabc78eec980bd1c73cc1afae97d512918b38dab8ccb5a19fe.png
Hide code cell source
# Detailed overview with notes
for index, row in plan.iterrows():
    if (index[0]+index[-4:]!='c_out'):
        print(f"{index:12s} {LatLon(row['lat'],row['lon']).format_pilot():20s}, FL{int(row['fl']):03d}, {takeoff_time+row['duration']:%H:%M:%S}, {notes.get(index,'')}" )
print ('\n-- circle centers:')
for point in waypoints:
    if isinstance(point, IntoCircle):
        point = point.center
        print (f'{point.label:12s} {point.format_pilot()}')
print ('\n-- extra waypoints:')
for point in extra_waypoints:
    print (f'{point.label:12s} {point.format_pilot()}, {notes.get(point.label,'')}' )
print ('\nCrew:')
for position,person in crew.items():
    print (f'{position:22s} {person}')
SAL          N16 44.07, W022 56.64, FL000, 12:20:00, 
MINDELO      N16 52.67, W024 59.70, FL000, 12:40:12, 
ec_north     N15 00.00, W025 00.45, FL410, 12:57:52, 
c_south_in   N05 39.34, W026 47.42, FL430, 14:12:19,  70 nm circle centered at N04 30.00, W027 00.29, enter from north, CCW
ec_south     N02 30.00, W027 22.68, FL410, 15:34:59, 
ec_under     N05 00.00, W026 54.67, FL450, 15:54:48, 
c_mid_in     N07 20.69, W026 28.30, FL430, 16:13:19,  70 nm circle centered at N08 30.00, W026 15.20, enter from north, CCW
c_north_in   N11 50.73, W025 37.10, FL450, 17:46:24,  70 nm circle centered at N13 00.00, W025 23.72, enter from south, CCW
ec_north     N15 00.00, W025 00.45, FL450, 19:08:18, 
c_atr_in     N17 56.59, W024 24.51, FL350, 19:32:04,  39 nm circle centered at N15 47.59, W024 49.74, enter from west, CW
c_atr_in     N16 25.96, W024 42.29, FL350, 20:18:01,  39 nm circle centered at N15 47.59, W024 49.74, enter from west, CW
SAL          N16 44.07, W022 56.64, FL000, 21:08:02, 

-- circle centers:
c_south      N04 30.00, W027 00.29
c_mid        N08 30.00, W026 15.20
c_north      N13 00.00, W025 23.72
c_atr        N18 34.88, W024 16.57
c_atr        N15 47.59, W024 49.74

-- extra waypoints:
xwp2         N03 30.00, W027 11.49, Alternative center for c_south
xwp3         N18 34.88, W024 16.57, Alternative center for c_atr

Crew:
Mission PI             Silke Gross
DropSondes             Nina Robbins
HAMP                   Christian Heske
SMART/VELOX            Michael Schäfer
SpecMACS               Veronika Pörtge
WALES                  Georgios Dekoutsidis
Flight Documentation   Basile Poujol
Ground Support         Julia Windmiller
Hide code cell source
vertical_preview(waypoints)
plt.title("Profile")
Text(0.5, 1.0, 'Profile')
../_images/16ffb74d1a52f5d2365c41b10f849167d34ecf0042e724ee612fa9819d3398f9.png
Hide code cell source
from orcestra.flightplan import export_flightplan

export_flightplan("HALO-20240829a", path)