AWIPEV overflights#

The AWIPEV Base is a French-German Arctic Research Base at Ny-Ålesund, Svalbard, operated by the German Alfred Wegener Institute for Polar and Marine Research (AWI) and the French Polar Institute Paul Emile Victor (IPEV). At AWIPEV’s Atmosphere Observatory long-term observations of atmospheric thermodynamics, clouds, aerosols and trace gases are collected using various in-situ and remote sensing instrumentation.

To make use of the synergy between airborne and ground-based observations, Polar5 and Polar6 frequently overpassed the AWIPEV Base. The flight-phase-separation allows for a quick filtering of Ny-Ålesund overflights using the keywords listed under the kinds parameter of each segment. The use of the keyword will be presented here. Additionally, we will calculate the duration, Polar5 was within 15 km of AWIPEV for each research flight.

import cartopy.crs as ccrs
import matplotlib.pyplot as plt
import xarray as xr
import numpy as np
import ac3airborne
plt.style.use("../mplstyle/book")

At first we load the flight-phase separation and the intake catalog.

meta = ac3airborne.get_flight_segments()
cat = ac3airborne.get_intake_catalog()
flights = {}
for campaign in ['ACLOUD', 'AFLUX', 'MOSAiC-ACA','HALO-AC3']:
    flights.update(meta[campaign]['P5'])

Flights near AWIPEV Base#

With the help of meta information stored in flight-phase-separation, we can find the flights, which overpassed the AWIPEV Base.

for flight_id, flight in flights.items():
    awipev_remark = [event for event in flight['events'] 
                     if 'Ny-Alesund' in event]
    
    if len(awipev_remark) > 0:
        print(f'{flight_id}: {awipev_remark}')
ACLOUD_P5_RF04: ['Ny-Alesund overflight']
ACLOUD_P5_RF05: ['Ny-Alesund overflight']
ACLOUD_P5_RF08: ['Ny-Alesund overflight']
ACLOUD_P5_RF10: ['Ny-Alesund overflight']
ACLOUD_P5_RF11: ['Ny-Alesund overflight with cross pattern']
ACLOUD_P5_RF14: ['Ny-Alesund overflight with cross pattern']
ACLOUD_P5_RF18: ['Ny-Alesund overflight with cross pattern']
ACLOUD_P5_RF19: ['Ny-Alesund overflight with cross pattern']
ACLOUD_P5_RF21: ['Ny-Alesund overflight']
ACLOUD_P5_RF22: ['Ny-Alesund overflight with cross pattern']
AFLUX_P5_RF04: ['Ny-Alesund overflight']
AFLUX_P5_RF07: ['Ny-Alesund overflight']
AFLUX_P5_RF09: ['Ny-Alesund overflight']
AFLUX_P5_RF10: ['Ny-Alesund overflight']
AFLUX_P5_RF11: ['Ny-Alesund overflight']
AFLUX_P5_RF12: ['Ny-Alesund overflight']
AFLUX_P5_RF13: ['Ny-Alesund overflight']
AFLUX_P5_RF14: ['Ny-Alesund overflight']
MOSAiC-ACA_P5_RF05: ['Ny-Alesund overflight']
MOSAiC-ACA_P5_RF07: ['Ny-Alesund overflight']
MOSAiC-ACA_P5_RF08: ['Ny-Alesund overflight']
MOSAiC-ACA_P5_RF09: ['Ny-Alesund overflight']
MOSAiC-ACA_P5_RF11: ['Ny-Alesund overflight']
HALO-AC3_P5_RF05: ['Ny-Alesund overflight']
HALO-AC3_P5_RF08: ['Ny-Alesund overflight']
HALO-AC3_P5_RF09: ['Ny-Alesund overflight']

Two types of overflights are distinguished:

  • Ny-Alesund overflight: straight overflight

  • Ny-Alesund overflight with cross pattern: cross pattern over Ny-Alesund

Segments near AWIPEV Base#

Similarly, we can find the individual segments, which were within 15 km of the AWIPEV Base.

for flight_id, flight in flights.items():
    
    awipev_segment_id = [seg['segment_id'] for seg in flight['segments']
                         if seg.get('kinds') is not None
                         if 'nya_overflight' in seg['kinds']]
    
    if len(awipev_segment_id) > 0:
        segments = ', '.join([seg.split('_')[-1] for seg in awipev_segment_id])
        print(f'{flight_id}: {segments}')
ACLOUD_P5_RF04: hl08, md
ACLOUD_P5_RF05: ma, hl01, hl02
ACLOUD_P5_RF08: ma, hl03
ACLOUD_P5_RF10: ll01
ACLOUD_P5_RF11: ma, hl01, cr01, ho01, hl02, hl09, md
ACLOUD_P5_RF14: ma, hl01, cr02, md
ACLOUD_P5_RF18: hl08, cr02, hl09
ACLOUD_P5_RF19: ma, cr01
ACLOUD_P5_RF21: hl01
ACLOUD_P5_RF22: cr01, hl02, hl03, hl04, hl05, hl06, hl07, ld01, ll01, ma01, ml01
AFLUX_P5_RF04: hl01
AFLUX_P5_RF07: hl04, hl05
AFLUX_P5_RF09: hl02, hl04
AFLUX_P5_RF10: hl06
AFLUX_P5_RF11: hl01, hl05
AFLUX_P5_RF12: hl02, hl03, hl04
AFLUX_P5_RF13: hl08, hl09
AFLUX_P5_RF14: hl02, hl05
MOSAiC-ACA_P5_RF05: hl08
MOSAiC-ACA_P5_RF07: hl01
MOSAiC-ACA_P5_RF08: hl01, hl06, hl07
MOSAiC-ACA_P5_RF09: hl01, sd01, hl10, md
MOSAiC-ACA_P5_RF11: hl01, hl07, md
HALO-AC3_P5_RF02: hl01, hl03
HALO-AC3_P5_RF03: hl01, hl10, hl11
HALO-AC3_P5_RF04: hl05, hl06
HALO-AC3_P5_RF05: hl11
HALO-AC3_P5_RF08: hl01, hl02
HALO-AC3_P5_RF09: hl02, hl10

Many segments are found to intersect with a 15 km radius around the AWIPEV Base. In the following example, we want to look at the flight duration within the 15 km radius.

Flight duration near AWIPEV Base#

To calculate the distance in km between the aircraft and AWIPEV, we project the aircraft position to UTM 33N coordinates.

def dist2awipev(ds_gps):
    """
    Calculate distance of aircraft to AWIPEV Base in
    UTM 33 coordinates
    """
    
    # coordinate systems
    crs_g = ccrs.PlateCarree()
    crs_p = ccrs.UTM(zone='33')
            
    # awipev base: geographic --> projected
    awipev_g = np.array([[11.920833, 78.923333]])
    awipev_p = crs_p.transform_points(x=awipev_g[:, 0], 
                                      y=awipev_g[:, 1], 
                                      src_crs=crs_g)

    # aircraft: geographic --> projected
    aircraft_g = np.stack([ds_gps.lon.values,
                           ds_gps.lat.values], axis=1)
    ix = ~np.isnan(aircraft_g).any(axis=1)
    aircraft_g = aircraft_g[ix, :]
    aircraft_p = crs_p.transform_points(x=aircraft_g[:, 0], 
                                        y=aircraft_g[:, 1], 
                                        src_crs=crs_g)
    
    # distance between awipev base and aircraft in km
    d = np.linalg.norm(aircraft_p-awipev_p, axis=1) * 1e-3
    
    ds = xr.Dataset()
    ds['time'] = ds_gps.time[ix].values
    ds['dist'] = (('time'), d)
    
    return ds

Using the defined function, we calculate the time, Polar5 was flying within 15 km of the AWIPEV Base.

flights_awipev = np.array([])
times_awipev = np.array([])

for flight_id, flight in flights.items():
    
    # read gps data of flight
    ds_gps = cat[flight['mission']]['P5']['GPS_INS'][flight_id].to_dask()
    
    # calculate distance to AWIPEV
    ds_dist = dist2awipev(ds_gps)

    if ds_dist['dist'].min() < 15:
        
        time_sec = ds_dist['dist'].sel(time=ds_dist['dist'] < 15).count()
        times_awipev = np.append(times_awipev, time_sec/60)
        
        flights_awipev = np.append(flights_awipev, flight_id)

We display the overflight time for each research flight as bar plot.

fig, ax = plt.subplots(1, 1)
ix = np.argsort(times_awipev)
ax.barh(flights_awipev[ix], times_awipev[ix])
ax.set_xlabel('Overflight duration [min]')
plt.show()
../_images/awipev_overflights_16_0.png

Vertical cross section of overflights#

Using the altitude information stored in the GPS-INS dataset, we can plot a vertical cross section of the overflights as function of distance to AWIPEV.

fig, ax = plt.subplots(1, 1)

kwargs = dict(marker='_', alpha=0.75)

for flight_id, flight in flights.items():
    
    # read gps data of flight
    ds_gps = cat[flight['mission']]['P5']['GPS_INS'][flight_id].to_dask()
        
    # calculate distance to AWIPEV
    ds_dist = dist2awipev(ds_gps)
    
    if ds_dist['dist'].min() < 15:
        
        ax.scatter(ds_dist['dist'], ds_gps['alt'].sel(time=ds_dist.time)*1e-3, label=flight_id,
                   **kwargs)

ax.set_xlim(0, 15)
ax.set_ylim(0, 4.5)

ax.set_ylabel('Altitude [km]')
ax.set_xlabel('Distance to AWIPEV Base [km]')

ax.legend(bbox_to_anchor=(1, 0.5), loc='center left')
plt.show()
../_images/awipev_overflights_18_0.png