Sun, 26 Feb 2017 22:28:30 +0200
Licel2scc calibration measurement.
atmospheric_lidar/scripts/licel2scc_depol.py | file | annotate | diff | comparison | revisions |
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/atmospheric_lidar/scripts/licel2scc_depol.py Sun Feb 26 22:28:30 2017 +0200 @@ -0,0 +1,134 @@ +""" Command line tool to convert Licel binary files to SCC NetCDF format. +""" +import argparse +import glob +import importlib +import logging +import os +import sys + + +from ..licel_depol import LicelCalibrationMeasurement + + +def create_custom_class(custom_netcdf_parameter_path, use_id_as_name=False, temperature=25., pressure=1020.): + """ This funtion creates a custom LicelLidarMeasurement subclass, + based on the input provided by the users. + + Parameters + ---------- + custom_netcdf_parameter_path: str + The path to the custom channels parameters. + use_id_as_name: bool + Defines if channels names are descriptive or transient digitizer IDs. + temperature: float + The ground temperature in degrees C (default 25.0). + pressure: float + The ground pressure in hPa (default: 1020.0). + + Returns + ------- + CustomLidarMeasurement: + A custom sub-class of LicelLidarMeasurement + """ + + custom_netcdf_parameters = read_settings_file(custom_netcdf_parameter_path) + + class CustomLidarMeasurement(LicelCalibrationMeasurement): + extra_netcdf_parameters = custom_netcdf_parameters + + def __init__(self, filelist=None): + super(CustomLidarMeasurement, self).__init__(filelist, use_id_as_name) + + def get_PT(self): + ''' Sets the pressure and temperature at station level. This is used if molecular_calc parameter is + set to 0 (i.e. use US Standard atmosphere). + + The results are stored in the info dictionary. + ''' + + self.info['Temperature'] = temperature + self.info['Pressure'] = pressure + + return CustomLidarMeasurement + + +def read_settings_file(settings_path): + """ Read the settings file. + + The file should contain python code.""" + if not os.path.isfile(settings_path): + logging.error("The provided settings path does not correspond to a file.") + sys.exit(1) + + dirname, basename = os.path.split(settings_path) + sys.path.append(dirname) + + module_name, _ = os.path.splitext(basename) + settings = importlib.import_module(module_name) + return settings + + +def main(): + # Define the command line argument + parser = argparse.ArgumentParser(description="A program to convert Licel binary files to the SCC NetCDF format.") + parser.add_argument("parameter_file", help="The path to a parameter file linking licel and SCC channels.") + parser.add_argument("plus45_string", nargs='?', help="Search string for plus 45 degree files (default '*.*')", default="*.*") + parser.add_argument("minus45_string", nargs='?', help="Search string for minus 45 degree files (default '*.*')", default="*.*") + parser.add_argument("-i", '--id_as_name', + help="Use transient digitizer ids as channel names, instead of descriptive names", + action="store_true") + parser.add_argument("-m", "--measurement_id", help="The new measurement id", default=None) + parser.add_argument("-n", "--measurement_number", + help="The measurement number for the date from 00 to 99. Used if no id is provided", + default="00") + parser.add_argument("-t", "--temperature", type=float, + help="The temperature (in C) at lidar level, required if using US Standard atmosphere", + default="25") + parser.add_argument("-p", "--pressure", type=float, + help="The pressure (in hPa) at lidar level, required if using US Standard atmosphere", + default="1020") + # Verbosity settings from http://stackoverflow.com/a/20663028 + parser.add_argument('-d', '--debug', help="Print dubuging information.", action="store_const", + dest="loglevel", const=logging.DEBUG, default=logging.INFO, + ) + parser.add_argument('-s', '--silent', help="Show only warning and error messages.", action="store_const", + dest="loglevel", const=logging.WARNING + ) + + args = parser.parse_args() + + # Get the logger with the appropriate level + logging.basicConfig(format='%(levelname)s: %(message)s', level=args.loglevel) + logger = logging.getLogger(__name__) + + #coloredlogs.install(fmt='%(levelname)s: %(message)s', level=args.loglevel) + + # Get a list of files to convert + plus45_files = glob.glob(args.plus45_string) + minus45_files = glob.glob(args.minus45_string) + + if len(plus45_files)==0 or len(minus45_files)==0: + logger.error("No files found when searching for %s and %s." % (plus45_files, minus45_files)) + sys.exit(1) + + # Read the files + logger.info("Reading {0} files from {1}".format(len(plus45_files), args.plus45_string)) + logger.info("Reading {0} files from {1}".format(len(minus45_files), args.minus45_string)) + + CustomLidarMeasurement = create_custom_class(args.parameter_file, args.id_as_name, args.temperature, + args.pressure) + + measurement = CustomLidarMeasurement(plus45_files, minus45_files) + + try: + measurement = measurement.subset_by_scc_channels() + except ValueError as err: + logging.error(err) + sys.exit(1) + + # Save the netcdf + logger.info("Saving netcdf") + measurement.set_measurement_id(args.measurement_id, args.measurement_number) + measurement.save_as_netcdf() + logger.info("Created file %s" % measurement.scc_filename)