Source code for act.io.mpl

"""
This module contains I/O operations for loading MPL files.

"""

import os
import shutil
import subprocess
import tempfile
import dask
import xarray as xr
from act.io.arm import check_arm_standards

if shutil.which('mpl2nc') is not None:
    MPLIMPORT = True
else:
    MPLIMPORT = False


[docs]def read_sigma_mplv5( filename, save_nc=False, out_nc_path=None, afterpulse=None, dead_time=None, overlap=None, **kwargs, ): """ Returns `xarray.Dataset` with stored data and metadata from a user-defined SIGMA MPL V5 files. File is converted to netCDF using mpl2nc an optional dependency. Parameters ---------- filename : str Name of file(s) to read. If multiple, ensure that they are sorted, otherwise they will not concat properly save_nc : bool Whether or not to save intermediate step nc file. out_nc_path : str Path to save intermediate step nc file. afterpulse : str File with afterpulse correction (.bin) dead_time : str File with dead time correction (.bin) overlap : str File with overlap correction (.bin) **kwargs : keywords Keywords to pass through to xarray.open_dataset(). """ if not MPLIMPORT: raise ImportError( 'The module mpl2nc is not installed and is needed to read mpl binary files!' ) if isinstance(filename, str): filename = [filename] task = [] for f in filename: task.append( dask.delayed(proc_sigma_mplv5_read)( f, save_nc=save_nc, out_nc_path=out_nc_path, afterpulse=afterpulse, dead_time=dead_time, overlap=overlap, **kwargs, ) ) results_ds = dask.compute(*task) ds = xr.concat(results_ds, 'time') return ds
[docs]def proc_sigma_mplv5_read( f, save_nc=False, out_nc_path=None, afterpulse=None, dead_time=None, overlap=None, **kwargs ): """ Returns `xarray.Dataset` with stored data and metadata from a user-defined SIGMA MPL V5 files. File is converted to netCDF using mpl2nc an optional dependency. Dask sub-routine for processing Parameters ---------- filename : str Name of file to read. save_nc : bool Whether or not to save intermediate step nc file. out_nc_path : str Path to save intermediate step nc file. afterpulse : str File with afterpulse correction (.bin) dead_time : str File with dead time correction (.bin) overlap : str File with overlap correction (.bin) **kwargs : keywords Keywords to pass through to xarray.open_dataset(). """ datastream_name = '.'.join(f.split('/')[-1].split('.')[0:2]) if '.bin' not in f: mpl = True tmpfile1 = tempfile.mkstemp(suffix='.bin', dir='.')[1] shutil.copyfile(f, tmpfile1) f = tmpfile1 else: mpl = False # Set up call for mpl2nc to add in correction files call = 'mpl2nc' if afterpulse is not None: call += ' -a ' + afterpulse if dead_time is not None: call += ' -d ' + dead_time if overlap is not None: call += ' -o ' + overlap call += ' ' + f # Specify the output, will use a temporary file if no output specified if save_nc: if out_nc_path is None: raise ValueError('You are using save_nc, please specify ' 'an out_nc_path') subprocess.call(call + ' ' + out_nc_path, shell=True) ds = xr.open_dataset(out_nc_path, **kwargs) else: tmpfile2 = tempfile.mkstemp(suffix='.nc', dir='.')[1] subprocess.call(call + ' ' + tmpfile2, shell=True) ds = xr.open_dataset(tmpfile2, **kwargs) os.remove(tmpfile2) # Calculate range in meters ds['range'] = 0.5 * ds.bin_time[0] * ds.c * (ds.range + 0.5) # Swap the coordinates to be time and range ds = ds.swap_dims({'profile': 'time'}) ds = ds.assign_coords({'time': ds.time, 'range': ds.range}) # Add metadata is_arm_file_flag = check_arm_standards(ds) if is_arm_file_flag == 0: ds.attrs['_datastream'] = datastream_name ds.attrs['_arm_standards_flag'] = is_arm_file_flag if mpl: os.remove(tmpfile1) return ds