Flight plan - HALO-20240827a

Contents

Flight plan - HALO-20240827a#

ec_under ec_track c_north c_mid c_south c_atr

Crew#

The flight is planned to take off at 2024-08-27 10:15:00+00:00.

Job

Name

PI

Bjorn Stvens

WALES

Georgios Dekoutsidis

HAMP

Clara Bayley

Dropsondes

Helene Glöckner

Smart/VELOX

Kevin Wolf

SpecMACS

Zekican Demiralay

Flight Documentation

Nicolas Rochetin

Ground contact

Marius Rixen

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")

# Define dates for forecast initialization and flight

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

flight_time = datetime(2024, 8, 27, 16, 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-27T10:15")

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': 'Bjorn Stevens',
        'DropSondes': 'Helene Glöckner',
        'HAMP': 'Clara Bayley',
        'SMART/VELOX': 'Kevin Wolf',
        'SpecMACS': 'Zekican Demiralay',
        'WALES' : 'Georgios Dekoutsidis',
        'Flight Documentation': 'Nicola Rochetin',
        'Ground Support': 'Marius Rixen',
        }

# 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} 14: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 = 13.0
lat_ec_south = 5.75

# latitude of circle centers
lat_c_south = 4.0
lat_c_north = 11.25

c_atr_nw = LatLon(17.433,-23.500, label = "c_atr")
c_atr_se = LatLon(14.500,-22.500, label = "c_atr")
meteor   = LatLon(13.000,-22.500, label = "after-meteor")
xsonde   = LatLon(meteor.lat, -23.500, label = "x-sonde")
atr_turn = LatLon(sal.lat-0.2, -22.500, label = "after-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_mid = c_south.towards(c_north).assign(label = "c_mid")

# extra way point on track
x_wp1  = c_mid.towards(c_north,fraction=2/5.).assign(label = "x_wp1")

# ec underpass
ec_under = c_north.towards(ec_north,fraction=1./3.).assign(label = "ec_under")
ec_under = LatLon(ec_under.lat, find_ec_lon(ec_under.lat, ec_lons, ec_lats), label = ec_under.label)

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

ec_legs = [
     ec_south.assign(fl=410),
     IntoCircle(c_south.assign(fl=430), radius, -330,enter=220),   
     ec_south.assign(fl=430),
     IntoCircle(c_mid.assign(fl=430), radius, 360), 
     x_wp1.assign(fl=450),
     IntoCircle(c_north.assign(fl=450), radius, 360),   
     ec_under.assign(fl=450),
     ]

inbound_legs = [
     ec_north.assign(fl=450),
     xsonde.assign(fl=450),
     meteor.assign(fl=450),
     c_atr_se.assign(fl=350),
     IntoCircle(c_atr_se.assign(fl=350), atr_radius, 360, enter=90),
     atr_turn.assign(fl=350),
     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)

# extra way points off track

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 south, 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',
        'ec_under':f'EarthCARE at this point at {str(ec_time_at_lat(ec_track, ec_under.lat).values)[11:19]} UTC',
         }

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')

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-26 00:00:00
Flight date: 2024-08-27
Flight index: HALO-20240827a
/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-27! The newest forecast issued so far was issued on 2024-08-27. It's a PRE forecast.
  warnings.warn(
../_images/4d1fb8590938914c0607cbd0881a2c76d6eea49666d07ec60cd41f262586ea98.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, 10:15:00, 
ec_north     N13 00.00, W028 08.92, FL410, 11:14:07, 
c_north      N11 15.00, W028 29.06, FL410, 11:28:08, 
c_mid        N07 37.55, W029 10.42, FL410, 11:57:08, 
ec_south     N05 45.00, W029 31.44, FL410, 12:12:09, 
c_south_in   N05 09.67, W030 02.10, FL430, 12:18:15, 70 nm circle centered at N04 00.00, W029 51.09, enter from north, CCW
ec_south     N05 45.00, W029 31.44, FL430, 13:16:08, 
c_mid_in     N06 28.22, W029 23.39, FL430, 13:21:51, 70 nm circle centered at N07 37.55, W029 10.42, enter from south, CCW
x_wp1        N09 04.55, W028 53.98, FL450, 14:39:57, 
c_north_in   N10 05.72, W028 42.34, FL450, 14:47:58, 70 nm circle centered at N11 15.00, W028 29.06, enter from south, CCW
ec_under     N11 50.00, W028 22.37, FL450, 15:58:44, EarthCARE at this point at 16:00:56 UTC
ec_north     N13 00.00, W028 08.92, FL450, 16:07:55, 
x-sonde      N13 00.00, W023 30.00, FL450, 16:43:09, 
after-meteor N13 00.00, W022 30.00, FL450, 16:50:44, 
c_atr        N14 30.00, W022 30.00, FL350, 17:02:37, 
c_atr_in     N15 09.04, W022 30.00, FL350, 17:07:56, 39 nm circle centered at N14 30.00, W022 30.00, enter from west, CW
after-atr    N16 32.07, W022 30.00, FL350, 17:52:38, 
SAL          N16 44.07, W022 56.64, FL000, 17:57:11, 

-- circle centers:
c_south      N04 00.00, W029 51.09
c_mid        N07 37.55, W029 10.42
c_north      N11 15.00, W028 29.06
c_atr        N14 30.00, W022 30.00

-- extra waypoints:
xwp2         N03 00.00, W030 02.29, Alternative center for c_south
xwp3         N17 25.98, W023 30.00, Alternative center for c_atr

Crew:
Mission PI             Bjorn Stevens
DropSondes             Helene Glöckner
HAMP                   Clara Bayley
SMART/VELOX            Kevin Wolf
SpecMACS               Zekican Demiralay
WALES                  Georgios Dekoutsidis
Flight Documentation   Nicola Rochetin
Ground Support         Marius Rixen
Hide code cell source
vertical_preview(waypoints)
plt.title("Profile")
Text(0.5, 1.0, 'Profile')
../_images/faa74df07a114cf19a30feb92df5d92679697930849a78b0f8c1d78748072faf.png
Hide code cell source
from orcestra.flightplan import export_flightplan

export_flightplan("HALO-20240827a", path)