Source code for act.io.icartt

"""
Modules for Reading/Writing the International Consortium for Atmospheric
Research on Transport and Transformation (ICARTT) file format standards V2.0

References:
    ICARTT V2.0 Standards/Conventions:
    - https://www.earthdata.nasa.gov/s3fs-public/imported/ESDS-RFC-029v2.pdf

"""
import xarray as xr

try:
    import icartt

    _ICARTT_AVAILABLE = True
    _format = icartt.Formats.FFI1001
except ImportError:
    _ICARTT_AVAILABLE = False
    _format = None


[docs]def read_icartt(filename, format=_format, return_None=False, **kwargs): """ Returns `xarray.Dataset` with stored data and metadata from a user-defined query of ICARTT from a single datastream. Has some procedures to ensure time is correctly fomatted in returned Dataset. Parameters ---------- filename : str Name of file to read. format : str ICARTT Format to Read: FFI1001 or FFI2110. return_None : bool, optional Catch IOError exception when file not found and return None. Default is False. **kwargs : keywords keywords to pass on through to icartt.Dataset. Returns ------- ds : xarray.Dataset (or None) ACT Xarray dataset (or None if no data file(s) found). Examples -------- This example will load the example sounding data used for unit testing. .. code-block :: python import act ds = act.io.icartt.read_icartt(act.tests.sample_files.AAF_SAMPLE_FILE) print(ds.attrs['_datastream']) """ if not _ICARTT_AVAILABLE: raise ImportError("ICARTT is required to use to read ICARTT files but is not installed") ds = None # Create an exception tuple to use with try statements. Doing it this way # so we can add the FileNotFoundError if requested. Can add more error # handling in the future. except_tuple = (ValueError,) if return_None: except_tuple = except_tuple + (FileNotFoundError, OSError) try: # Read data file with ICARTT dataset. ict = icartt.Dataset(filename, format=format, **kwargs) except except_tuple as exception: # If requested return None for File not found error if type(exception).__name__ == 'FileNotFoundError': return None # If requested return None for File not found error if type(exception).__name__ == 'OSError' and exception.args[0] == 'no files to open': return None # Define the Uncertainty for each variable. Note it may not be calculated. # If not calculated, assign 'N/A' to the attribute uncertainty = ict.normalComments[6].split(':')[1].split(',') # Define the Upper and Lower Limit of Detection Flags ulod_flag = ict.normalComments[7].split(':')[1] ulod_value = ict.normalComments[8].split(':')[1].split(',') llod_flag = ict.normalComments[9].split(':')[1] llod_value = ict.normalComments[10].split(':')[1].split(',') # Convert ICARTT Object to Xarray Dataset ds_container = [] # Counter for uncertainty/LOD values counter = 0 # Loop over ICART variables, convert to Xarray DataArray, Append. for key in ict.variables: # Note time is the only independent variable within ICARTT # Short name for time must be "Start_UTC" for ICARTT files. if key != 'Start_UTC': if key == 'qc_flag': key2 = 'quality_flag' else: key2 = key da = xr.DataArray(ict.data[key], coords=dict(time=ict.times), name=key2, dims=['time']) # Assume if Uncertainity does not match the number of variables, # values were not set within the file. Needs to be string! if len(uncertainty) != len(ict.variables): da.attrs['uncertainty'] = 'N/A' else: da.attrs['uncertainty'] = uncertainty[counter] # Assume if ULOD does not match the number of variables within the # the file, ULOD values were not set. if len(ulod_value) != len(ict.variables): da.attrs['ULOD_Value'] = 'N/A' else: da.attrs['ULOD_Value'] = ulod_value[counter] # Assume if LLOD does not match the number of variables within the # the file, LLOD values were not set. if len(llod_value) != len(ict.variables): da.attrs['LLOD_Value'] = 'N/A' else: da.attrs['LLOD_Value'] = llod_value[counter] # Define the meta data: da.attrs['units'] = ict.variables[key].units da.attrs['mvc'] = ict.variables[key].miss da.attrs['scale_factor'] = ict.variables[key].scale da.attrs['ULOD_Flag'] = ulod_flag da.attrs['LLOD_Flag'] = llod_flag # Append to ds container ds_container.append(da.to_dataset(name=key2)) # up the counter counter += 1 # Concatenate each of the Xarray DataArrays into a single Xarray DataSet ds = xr.merge(ds_container) # Assign ICARTT Meta data to Xarray DataSet ds.attrs['PI'] = ict.PIName ds.attrs['PI_Affiliation'] = ict.PIAffiliation ds.attrs['Platform'] = ict.dataSourceDescription ds.attrs['Mission'] = ict.missionName ds.attrs['DateOfCollection'] = ict.dateOfCollection ds.attrs['DateOfRevision'] = ict.dateOfRevision ds.attrs['Data_Interval'] = ict.dataIntervalCode ds.attrs['Independent_Var'] = str(ict.independentVariable) ds.attrs['Dependent_Var_Num'] = len(ict.dependentVariables) ds.attrs['PI_Contact'] = ict.normalComments[0].split('\n')[0].split(':')[-1] ds.attrs['Platform'] = ict.normalComments[1].split(':')[-1] ds.attrs['Location'] = ict.normalComments[2].split(':')[-1] ds.attrs['Associated_Data'] = ict.normalComments[3].split(':')[-1] ds.attrs['Instrument_Info'] = ict.normalComments[4].split(':')[-1] ds.attrs['Data_Info'] = ict.normalComments[5][11:] ds.attrs['DM_Contact'] = ict.normalComments[11].split(':')[-1] ds.attrs['Project_Info'] = ict.normalComments[12].split(':')[-1] ds.attrs['Stipulations'] = ict.normalComments[13].split(':')[-1] ds.attrs['Comments'] = ict.normalComments[14].split(':')[-1] ds.attrs['Revision'] = ict.normalComments[15].split(':')[-1] ds.attrs['Revision_Comments'] = ict.normalComments[15 + 1].split(':')[-1] # Assign Additional ARM meta data to Xarray DatatSet ds.attrs['_datastream'] = filename.split('/')[-1].split('_')[0] # Return Xarray Dataset return ds