# -*- coding: utf-8 -*-
"""Module for the ICON MIGHTI instrument.
Supports the Michelson Interferometer for Global High-resolution
Thermospheric Imaging (MIGHTI) instrument onboard the Ionospheric
CONnection Explorer (ICON) satellite. Accesses local data in
netCDF format.
Properties
----------
platform
'icon'
name
'mighti'
tag
Supports 'los_wind_green', 'los_wind_red', 'vector_wind_green',
'vector_wind_red', 'temperature'. Note that not every data product
available for every inst_id
inst_id
'vector', 'a', or 'b'
Warnings
--------
- The cleaning parameters for the instrument are still under development.
- Only supports level-2 data.
Example
-------
::
import pysat
mighti = pysat.Instrument('icon', 'mighti', tag='vector_wind_green',
inst_id='vector', clean_level='clean')
mighti.download(dt.datetime(2020, 1, 30), dt.datetime(2020, 1, 31))
mighti.load(2020, 2)
By default, pysat removes the ICON level tags from variable names, ie,
ICON_L27_Ion_Density becomes Ion_Density. To retain the original names, use
::
mighti = pysat.Instrument(platform='icon', name='mighti',
tag='vector_wind_green', inst_id='vector',
clean_level='clean',
keep_original_names=True)
Note
----
Currently red and green data products are bundled together in zip files on the
server. This results in 'double downloading'. This will be fixed once data is
transfered to SPDF.
"""
import datetime as dt
import functools
import pysat
from pysat.instruments.methods import general as mm_gen
from pysat import logger
from pysatNASA.instruments.methods import cdaweb as cdw
from pysatNASA.instruments.methods import icon as mm_icon
# ----------------------------------------------------------------------------
# Instrument attributes
platform = 'icon'
name = 'mighti'
tags = {'los_wind_green': 'Line of sight wind data -- Green Line',
'los_wind_red': 'Line of sight wind data -- Red Line',
'vector_wind_green': 'Vector wind data -- Green Line',
'vector_wind_red': 'Vector wind data -- Red Line',
'temperature': 'Neutral temperature data'}
inst_ids = {'vector': ['vector_wind_green', 'vector_wind_red'],
'a': ['los_wind_green', 'los_wind_red', 'temperature'],
'b': ['los_wind_green', 'los_wind_red', 'temperature']}
pandas_format = False
# ----------------------------------------------------------------------------
# Instrument test attributes
_test_dates = {jj: {kk: dt.datetime(2020, 1, 2) for kk in inst_ids[jj]}
for jj in inst_ids.keys()}
# ----------------------------------------------------------------------------
# Instrument methods
[docs]def init(self):
"""Initialize the Instrument object with instrument specific values.
Runs once upon instantiation.
Parameters
-----------
inst : pysat.Instrument
Instrument class object
"""
logger.info(mm_icon.ackn_str)
self.acknowledgements = mm_icon.ackn_str
self.references = ''.join((mm_icon.refs['mission'],
mm_icon.refs['mighti']))
return
[docs]def preprocess(self, keep_original_names=False):
"""Adjust epoch timestamps to datetimes and remove variable preambles.
Parameters
----------
keep_original_names : boolean
if True then the names as given in the netCDF ICON file
will be used as is. If False, a preamble is removed. (default=False)
"""
mm_gen.convert_timestamp_to_datetime(self, sec_mult=1.0e-3)
if not keep_original_names:
mm_icon.remove_preamble(self)
return
[docs]def clean(self):
"""Clean ICON MIGHTI data to the specified level.
Note
----
Supports 'clean', 'dusty', 'none'
"""
def _clean_vars(var_list, flag, min_level):
"""Clean parameters in a list according to standard flags.
Parameters
----------
var_list : list of strings
List of variables to be cleaned. Must match variables present in
the data set.
flag : string
The variable name to be used as the quality flag
min_level : float
The value at or above where we are confident in the data. For
MIGHTI, these are generally 0.5 or 1.0
"""
for var in var_list:
self[var] = self[var].where(self[flag] >= min_level)
return
if self.clean_level in ['clean', 'dusty']:
if self.tag.find('los') >= 0:
# Dealing with LOS winds
wind_flag = 'Wind_Quality'
ver_flag = 'VER_Quality'
wind_vars = ['Line_of_Sight_Wind', 'Line_of_Sight_Wind_Error']
ver_vars = ['Fringe_Amplitude', 'Fringe_Amplitude_Error',
'Relative_VER', 'Relative_VER_Error']
if wind_flag not in self.variables:
wind_flag = '_'.join(('ICON_L21', wind_flag))
ver_flag = '_'.join(('ICON_L21', ver_flag))
wind_vars = ['ICON_L21_' + var for var in wind_vars]
ver_vars = ['ICON_L21_' + var for var in ver_vars]
min_val = {'clean': 1.0, 'dusty': 0.5}
# Find location with any of the flags set
_clean_vars(wind_vars, wind_flag, min_val[self.clean_level])
_clean_vars(ver_vars, ver_flag, min_val[self.clean_level])
elif self.tag.find('vector') >= 0:
# Vector winds area
wind_flag = 'Wind_Quality'
ver_flag = 'VER_Quality'
wind_vars = ['Zonal_Wind', 'Zonal_Wind_Error',
'Meridional_Wind', 'Meridional_Wind_Error']
ver_vars = ['Fringe_Amplitude', 'Fringe_Amplitude_Error',
'Relative_VER', 'Relative_VER_Error']
if wind_flag not in self.variables:
wind_flag = '_'.join(('ICON_L22', wind_flag))
ver_flag = '_'.join(('ICON_L22', ver_flag))
wind_vars = ['ICON_L22_' + var for var in wind_vars]
ver_vars = ['ICON_L22_' + var for var in ver_vars]
min_val = {'clean': 1.0, 'dusty': 0.5}
# Find location with any of the flags set
_clean_vars(wind_vars, wind_flag, min_val[self.clean_level])
_clean_vars(ver_vars, ver_flag, min_val[self.clean_level])
elif self.tag.find('temp') >= 0:
# Neutral temperatures
var = 'Temperature'
saa_flag = 'Quality_Flag_South_Atlantic_Anomaly'
cal_flag = 'Quality_Flag_Bad_Calibration'
if saa_flag not in self.variables:
id_str = self.inst_id.upper()
saa_flag = '_'.join(('ICON_L1_MIGHTI', id_str, saa_flag))
cal_flag = '_'.join(('ICON_L1_MIGHTI', id_str, cal_flag))
var = '_'.join(('ICON_L23_MIGHTI', id_str, var))
# Filter out areas with bad calibration data
# as well as data marked in the SAA
self[var] = self[var].where((self[saa_flag] == 0)
& (self[cal_flag] == 0))
# Filter out negative temperatures
self[var] = self[var].where(self[var] > 0)
return
# ----------------------------------------------------------------------------
# Instrument functions
#
# Use the ICON and pysat methods
# Set the list_files routine
datestr = '{year:04d}{month:02d}{day:02d}_v{version:02d}r{revision:03d}'
fname1 = 'icon_l2-1_mighti-{id:s}_los-wind-{color:s}_{date:s}.nc'
fname2 = 'icon_l2-2_mighti_vector-wind-{color:s}_{date:s}.nc'
fname3 = 'icon_l2-3_mighti-{id:s}_temperature_{date:s}.nc'
supported_tags = {'vector': {'vector_wind_green': fname2.format(color='green',
date=datestr),
'vector_wind_red': fname2.format(color='red',
date=datestr)},
'a': {'los_wind_green': fname1.format(id='a', color='green',
date=datestr),
'los_wind_red': fname1.format(id='a', color='red',
date=datestr),
'temperature': fname3.format(id='a', date=datestr)},
'b': {'los_wind_green': fname1.format(id='b', color='green',
date=datestr),
'los_wind_red': fname1.format(id='b', color='red',
date=datestr),
'temperature': fname3.format(id='b', date=datestr)}}
list_files = functools.partial(mm_gen.list_files,
supported_tags=supported_tags)
# Set the download routine
dirstr1 = '/pub/data/icon/l2/l2-1_mighti-{{id:s}}_los-wind-{color:s}/'
dirstr2 = '/pub/data/icon/l2/l2-2_mighti_vector-wind-{color:s}/'
dirstr3 = '/pub/data/icon/l2/l2-3_mighti-{id:s}_temperature/'
dirnames = {'los_wind_green': dirstr1.format(color='green'),
'los_wind_red': dirstr1.format(color='red'),
'vector_wind_green': dirstr2.format(color='green'),
'vector_wind_red': dirstr2.format(color='red'),
'temperature': dirstr3}
download_tags = {}
for inst_id in supported_tags.keys():
download_tags[inst_id] = {}
for tag in supported_tags[inst_id].keys():
fname = supported_tags[inst_id][tag]
download_tags[inst_id][tag] = {
'remote_dir': ''.join((dirnames[tag].format(id=inst_id),
'{year:04d}/')),
'fname': fname}
download = functools.partial(cdw.download, supported_tags=download_tags)
# Set the list_remote_files routine
list_remote_files = functools.partial(cdw.list_remote_files,
supported_tags=download_tags)
[docs]def load(fnames, tag=None, inst_id=None, keep_original_names=False):
"""Load ICON MIGHTI data into `xarray.Dataset` and `pysat.Meta` objects.
This routine is called as needed by pysat. It is not intended
for direct user interaction.
Parameters
----------
fnames : array-like
iterable of filename strings, full path, to data files to be loaded.
This input is nominally provided by pysat itself.
tag : string
tag name used to identify particular data set to be loaded.
This input is nominally provided by pysat itself.
inst_id : string
Satellite ID used to identify particular data set to be loaded.
This input is nominally provided by pysat itself.
keep_original_names : boolean
if True then the names as given in the netCDF ICON file
will be used as is. If False, a preamble is removed.
Returns
-------
data : xr.Dataset
An xarray Dataset with data prepared for the pysat.Instrument
meta : pysat.Meta
Metadata formatted for a pysat.Instrument object.
Note
----
Any additional keyword arguments passed to pysat.Instrument
upon instantiation are passed along to this routine.
Examples
--------
::
inst = pysat.Instrument('icon', 'fuv')
inst.load(2020, 1)
"""
labels = {'units': ('Units', str), 'name': ('Long_Name', str),
'notes': ('Var_Notes', str), 'desc': ('CatDesc', str),
'min_val': ('ValidMin', float),
'max_val': ('ValidMax', float), 'fill_val': ('FillVal', float)}
data, meta = pysat.utils.load_netcdf4(fnames, epoch_name='Epoch',
pandas_format=pandas_format,
labels=labels)
# xarray can't merge if variable and dim names are the same
if 'Altitude' in data.dims:
data = data.rename_dims(dims_dict={'Altitude': 'Alt'})
return data, meta