Sun, 26 Feb 2017 22:28:30 +0200
Licel2scc calibration measurement.
ulalume3@64 | 1 | """ Command line tool to convert Licel binary files to SCC NetCDF format. |
ulalume3@64 | 2 | """ |
ulalume3@64 | 3 | import argparse |
ulalume3@64 | 4 | import glob |
ulalume3@64 | 5 | import importlib |
ulalume3@64 | 6 | import logging |
ulalume3@64 | 7 | import os |
ulalume3@64 | 8 | import sys |
ulalume3@64 | 9 | |
ulalume3@64 | 10 | |
ulalume3@64 | 11 | from ..licel_depol import LicelCalibrationMeasurement |
ulalume3@64 | 12 | |
ulalume3@64 | 13 | |
ulalume3@64 | 14 | def create_custom_class(custom_netcdf_parameter_path, use_id_as_name=False, temperature=25., pressure=1020.): |
ulalume3@64 | 15 | """ This funtion creates a custom LicelLidarMeasurement subclass, |
ulalume3@64 | 16 | based on the input provided by the users. |
ulalume3@64 | 17 | |
ulalume3@64 | 18 | Parameters |
ulalume3@64 | 19 | ---------- |
ulalume3@64 | 20 | custom_netcdf_parameter_path: str |
ulalume3@64 | 21 | The path to the custom channels parameters. |
ulalume3@64 | 22 | use_id_as_name: bool |
ulalume3@64 | 23 | Defines if channels names are descriptive or transient digitizer IDs. |
ulalume3@64 | 24 | temperature: float |
ulalume3@64 | 25 | The ground temperature in degrees C (default 25.0). |
ulalume3@64 | 26 | pressure: float |
ulalume3@64 | 27 | The ground pressure in hPa (default: 1020.0). |
ulalume3@64 | 28 | |
ulalume3@64 | 29 | Returns |
ulalume3@64 | 30 | ------- |
ulalume3@64 | 31 | CustomLidarMeasurement: |
ulalume3@64 | 32 | A custom sub-class of LicelLidarMeasurement |
ulalume3@64 | 33 | """ |
ulalume3@64 | 34 | |
ulalume3@64 | 35 | custom_netcdf_parameters = read_settings_file(custom_netcdf_parameter_path) |
ulalume3@64 | 36 | |
ulalume3@64 | 37 | class CustomLidarMeasurement(LicelCalibrationMeasurement): |
ulalume3@64 | 38 | extra_netcdf_parameters = custom_netcdf_parameters |
ulalume3@64 | 39 | |
ulalume3@64 | 40 | def __init__(self, filelist=None): |
ulalume3@64 | 41 | super(CustomLidarMeasurement, self).__init__(filelist, use_id_as_name) |
ulalume3@64 | 42 | |
ulalume3@64 | 43 | def get_PT(self): |
ulalume3@64 | 44 | ''' Sets the pressure and temperature at station level. This is used if molecular_calc parameter is |
ulalume3@64 | 45 | set to 0 (i.e. use US Standard atmosphere). |
ulalume3@64 | 46 | |
ulalume3@64 | 47 | The results are stored in the info dictionary. |
ulalume3@64 | 48 | ''' |
ulalume3@64 | 49 | |
ulalume3@64 | 50 | self.info['Temperature'] = temperature |
ulalume3@64 | 51 | self.info['Pressure'] = pressure |
ulalume3@64 | 52 | |
ulalume3@64 | 53 | return CustomLidarMeasurement |
ulalume3@64 | 54 | |
ulalume3@64 | 55 | |
ulalume3@64 | 56 | def read_settings_file(settings_path): |
ulalume3@64 | 57 | """ Read the settings file. |
ulalume3@64 | 58 | |
ulalume3@64 | 59 | The file should contain python code.""" |
ulalume3@64 | 60 | if not os.path.isfile(settings_path): |
ulalume3@64 | 61 | logging.error("The provided settings path does not correspond to a file.") |
ulalume3@64 | 62 | sys.exit(1) |
ulalume3@64 | 63 | |
ulalume3@64 | 64 | dirname, basename = os.path.split(settings_path) |
ulalume3@64 | 65 | sys.path.append(dirname) |
ulalume3@64 | 66 | |
ulalume3@64 | 67 | module_name, _ = os.path.splitext(basename) |
ulalume3@64 | 68 | settings = importlib.import_module(module_name) |
ulalume3@64 | 69 | return settings |
ulalume3@64 | 70 | |
ulalume3@64 | 71 | |
ulalume3@64 | 72 | def main(): |
ulalume3@64 | 73 | # Define the command line argument |
ulalume3@64 | 74 | parser = argparse.ArgumentParser(description="A program to convert Licel binary files to the SCC NetCDF format.") |
ulalume3@64 | 75 | parser.add_argument("parameter_file", help="The path to a parameter file linking licel and SCC channels.") |
ulalume3@64 | 76 | parser.add_argument("plus45_string", nargs='?', help="Search string for plus 45 degree files (default '*.*')", default="*.*") |
ulalume3@64 | 77 | parser.add_argument("minus45_string", nargs='?', help="Search string for minus 45 degree files (default '*.*')", default="*.*") |
ulalume3@64 | 78 | parser.add_argument("-i", '--id_as_name', |
ulalume3@64 | 79 | help="Use transient digitizer ids as channel names, instead of descriptive names", |
ulalume3@64 | 80 | action="store_true") |
ulalume3@64 | 81 | parser.add_argument("-m", "--measurement_id", help="The new measurement id", default=None) |
ulalume3@64 | 82 | parser.add_argument("-n", "--measurement_number", |
ulalume3@64 | 83 | help="The measurement number for the date from 00 to 99. Used if no id is provided", |
ulalume3@64 | 84 | default="00") |
ulalume3@64 | 85 | parser.add_argument("-t", "--temperature", type=float, |
ulalume3@64 | 86 | help="The temperature (in C) at lidar level, required if using US Standard atmosphere", |
ulalume3@64 | 87 | default="25") |
ulalume3@64 | 88 | parser.add_argument("-p", "--pressure", type=float, |
ulalume3@64 | 89 | help="The pressure (in hPa) at lidar level, required if using US Standard atmosphere", |
ulalume3@64 | 90 | default="1020") |
ulalume3@64 | 91 | # Verbosity settings from http://stackoverflow.com/a/20663028 |
ulalume3@64 | 92 | parser.add_argument('-d', '--debug', help="Print dubuging information.", action="store_const", |
ulalume3@64 | 93 | dest="loglevel", const=logging.DEBUG, default=logging.INFO, |
ulalume3@64 | 94 | ) |
ulalume3@64 | 95 | parser.add_argument('-s', '--silent', help="Show only warning and error messages.", action="store_const", |
ulalume3@64 | 96 | dest="loglevel", const=logging.WARNING |
ulalume3@64 | 97 | ) |
ulalume3@64 | 98 | |
ulalume3@64 | 99 | args = parser.parse_args() |
ulalume3@64 | 100 | |
ulalume3@64 | 101 | # Get the logger with the appropriate level |
ulalume3@64 | 102 | logging.basicConfig(format='%(levelname)s: %(message)s', level=args.loglevel) |
ulalume3@64 | 103 | logger = logging.getLogger(__name__) |
ulalume3@64 | 104 | |
ulalume3@64 | 105 | #coloredlogs.install(fmt='%(levelname)s: %(message)s', level=args.loglevel) |
ulalume3@64 | 106 | |
ulalume3@64 | 107 | # Get a list of files to convert |
ulalume3@64 | 108 | plus45_files = glob.glob(args.plus45_string) |
ulalume3@64 | 109 | minus45_files = glob.glob(args.minus45_string) |
ulalume3@64 | 110 | |
ulalume3@64 | 111 | if len(plus45_files)==0 or len(minus45_files)==0: |
ulalume3@64 | 112 | logger.error("No files found when searching for %s and %s." % (plus45_files, minus45_files)) |
ulalume3@64 | 113 | sys.exit(1) |
ulalume3@64 | 114 | |
ulalume3@64 | 115 | # Read the files |
ulalume3@64 | 116 | logger.info("Reading {0} files from {1}".format(len(plus45_files), args.plus45_string)) |
ulalume3@64 | 117 | logger.info("Reading {0} files from {1}".format(len(minus45_files), args.minus45_string)) |
ulalume3@64 | 118 | |
ulalume3@64 | 119 | CustomLidarMeasurement = create_custom_class(args.parameter_file, args.id_as_name, args.temperature, |
ulalume3@64 | 120 | args.pressure) |
ulalume3@64 | 121 | |
ulalume3@64 | 122 | measurement = CustomLidarMeasurement(plus45_files, minus45_files) |
ulalume3@64 | 123 | |
ulalume3@64 | 124 | try: |
ulalume3@64 | 125 | measurement = measurement.subset_by_scc_channels() |
ulalume3@64 | 126 | except ValueError as err: |
ulalume3@64 | 127 | logging.error(err) |
ulalume3@64 | 128 | sys.exit(1) |
ulalume3@64 | 129 | |
ulalume3@64 | 130 | # Save the netcdf |
ulalume3@64 | 131 | logger.info("Saving netcdf") |
ulalume3@64 | 132 | measurement.set_measurement_id(args.measurement_id, args.measurement_number) |
ulalume3@64 | 133 | measurement.save_as_netcdf() |
ulalume3@64 | 134 | logger.info("Created file %s" % measurement.scc_filename) |