Flight plan - HALO-20240831a

Contents

Flight plan - HALO-20240831a#

ec_under ec_track c_north c_mid c_south c_atr

Crew#

The flight is planned to take off at 2024-08-31 08:45:00+00:00.

Job

Name

PI

Silke Groß

WALES

Julia Windmiller

HAMP

Lutz Hirsch

Dropsondes

Theresa Mieslinger

Smart/VELOX

Sophie Rosenburg

SpecMACS

Lea Volkmer

Flight Documentation

Elina Plesca

Ground contact

Romain Fiévet

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, 30, 0, 0, 0)

flight_time = datetime(2024, 8, 31, 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-31T08:45")

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

# 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-30", 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_in = sal.lat
lat_ec_south = 1.0
lat_ec_shuttle_in = 16.0
lat_ec_shuttle_out = 14.0

# latitude of circle centers
lat_c_north = 11.5
lat_c_north_n = lat_c_north + 1.0

lat_c_south = 4.0
lat_c_south_n = lat_c_south + 1.0
lat_c_south_s = lat_c_south - 1.0

lat_c_mid = lat_c_south + (lat_c_north-lat_c_south)/2.0
lat_c_mid_n = lat_c_mid + 1.0
lat_c_mid_s = lat_c_mid - 1.0

lat_ec_under = 13.0

lat_c_atr = lat_ec_shuttle_out + atr_radius/111e3
#c_atr_nw = LatLon(17.433,-23.500, label = "c_atr")
#c_atr_se = LatLon(16.080,-21.715, label = "c_atr")

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_in, find_ec_lon(lat_ec_north_in, 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 shuttle track
ec_shuttle_in = LatLon(lat_ec_shuttle_in, find_ec_lon(lat_ec_shuttle_in, ec_lons, ec_lats), label = "ec_shuttle_in")
ec_shuttle_out = LatLon(lat_ec_shuttle_out, find_ec_lon(lat_ec_shuttle_out, ec_lons, ec_lats), label = "ec_shuttle_out")

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

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

c_atr = LatLon(lat_c_atr, find_ec_lon(lat_c_atr, ec_lons, ec_lats), label = "c_atr")

# 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.assign(fl=0),
     ec_north.assign(fl=410),
     ec_south.assign(fl=410),
     ]

ec_legs = [
     c_south_s.assign(fl=410),
     IntoCircle(c_south.assign(fl=410), radius, 360), 
     c_south_n.assign(fl=410),
     c_mid_s.assign(fl=430),
     IntoCircle(c_mid.assign(fl=430), radius, 360), 
     c_mid_n.assign(fl=430),
     IntoCircle(c_north.assign(fl=430), radius, 360), 
     c_north_n.assign(fl=430),
     ec_under.assign(fl=430),
     ]
inbound_legs = [
     ec_shuttle_out.assign(fl=450),
     ec_shuttle_in.assign(fl=450),
     ec_shuttle_out.assign(fl=350),
     IntoCircle(c_atr.assign(fl=350), atr_radius, 360), 
#     IntoCircle(c_atr_nw.assign(fl=350), atr_radius, 360),
#     IntoCircle(c_atr_se.assign(fl=350), atr_radius, 360),
     airport.assign(fl=0),
     ]

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 on track

# extra way points off track

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

extra_waypoints = []

notes = {'c_south_in':f' {radius/1852:2.0f} nm circle centered at {c_south.format_pilot()}',
        'c_mid_in':f' {radius/1852:2.0f} nm circle centered at {c_mid.format_pilot()}',
        'c_north_in':f' {radius/1852:2.0f} nm circle centered at {c_north.format_pilot()}',
        'c_atr_in':f' {atr_radius/1852:2.0f} nm circle centered at {c_atr_se.format_pilot()}',
        '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, ax, levels = [50.0, 52.0, 54.0, 56.0, 58.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-30 00:00:00
Flight date: 2024-08-31
Flight index: HALO-20240831a
/home/runner/miniconda3/envs/orcestra_book/lib/python3.12/site-packages/orcestra/sat.py:183: UserWarning: You are using an old forecast (issued on 2024-08-30) for EARTHCARE on 2024-08-31! The newest forecast issued so far was issued on 2024-08-31. It's a RES forecast.
  warnings.warn(
../_images/6972eed638b87b8d7333726886b87c87f628d2ffedfd12ccc2faa780a71219ce.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,'')}' )
SAL          N16 44.07, W022 56.64, FL000, 08:45:00, 
ec_north     N16 44.07, W021 56.47, FL410, 08:54:05, 
ec_south     N01 00.00, W024 55.88, FL410, 11:00:00, 
c_south_s    N03 00.00, W024 33.52, FL410, 11:16:00, 
c_south_in   N02 50.67, W024 35.26, FL410, 11:17:15,  70 nm circle centered at N04 00.00, W024 22.33
c_south_n    N05 00.00, W024 11.11, FL410, 12:32:34, 
c_mid_s      N06 45.00, W023 51.43, FL430, 12:46:30, 
c_mid_in     N06 35.68, W023 53.17, FL430, 12:47:44,  70 nm circle centered at N07 45.00, W023 40.14
c_mid_n      N08 45.00, W023 28.81, FL430, 14:02:21, 
c_north_in   N10 20.71, W023 10.68, FL430, 14:15:00,  70 nm circle centered at N11 30.00, W022 57.44
c_north_n    N12 30.00, W022 45.93, FL430, 15:29:38, 
ec_under     N13 00.00, W022 40.15, FL430, 15:33:36, 
ec_shuttle_out N14 00.00, W022 28.56, FL450, 15:41:30, 
ec_shuttle_in N16 00.00, W022 05.15, FL450, 15:57:15, 
ec_shuttle_out N14 00.00, W022 28.56, FL350, 16:13:23, 
c_atr_in     N14 00.56, W022 28.45, FL350, 16:13:27,  39 nm circle centered at N15 47.59, W024 49.74
SAL          N16 44.07, W022 56.64, FL000, 17:13:29, 

-- circle centers:
c_south      N04 00.00, W024 22.33
c_mid        N07 45.00, W023 40.14
c_north      N11 30.00, W022 57.44
c_atr        N14 38.92, W022 21.00

-- extra waypoints:
Hide code cell source
vertical_preview(waypoints)
plt.title("Profile")
Text(0.5, 1.0, 'Profile')
../_images/ee48f965d7791fc3c66db03e85e603ca3db60da111ce7da5e602ea4a8850d5df.png
import os

localdir = "/Users/juliawindmiller/Downloads/"
if os.path.isdir(localdir):
    print (localdir)
    with open(f"{localdir}{flight_index}.kml", "w") as f:
        f.write(to_kml(path))
        
    with open( f"{localdir}{flight_index}_waypoints.txt", "w") as file:
        file.write(f"Flight {flight_index}\n\n")
        #
        # DM Format
        file.write("------------------------------------------------------------\n")
        file.write("\nDM Format:\n")
        file.write(" ".join(wp.format_1min() for wp in waypoint_centers) + "\n")
        for point in extra_waypoints:
            file.write(f"Extra waypoint: {point.format_1min()}\n")
        #
        # DM.mm format
        file.write("\n------------------------------------------------------------\n")
        file.write("\nDMmm Format:\n")
        for point in waypoint_centers:
            file.write(f"{point.format_pilot()}, {point.label}\n")
        file.write("\n-- extra waypoints:\n")
        for point in extra_waypoints:
            file.write(f"{point.format_pilot()}, {notes.get(point.label,'')}\n")
        #
        # Detailed overview with notes
        file.write("\n------------------------------------------------------------\n")
        file.write(f"\n\nDetailed Overview:\n")
        for index, row in plan.iterrows():
            if (index[0]+index[-4:]!='c_out'):
                file.write(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,'')}\n" )
        file.write ('\n -- circle centers:')
        for point in waypoints:
            if isinstance(point, IntoCircle):
                point = point.center
                file.write (f'\n{point.label:12s} {point.format_pilot()}')
        file.write ('\n\n -- extra waypoints:')
        for point in extra_waypoints:
            file.write (f'\n{point.label:12s} {point.format_pilot()}, {notes.get(point.label,'')}' )
Hide code cell source
from orcestra.flightplan import export_flightplan

export_flightplan("HALO-20240831a", path)