# HG changeset patch # User Iannis # Date 1513072497 -7200 # Node ID 3e97bd360eda23d51cc0706ee9b943602d8d0f17 # Parent b20b59b350d52668b54c8c131c8f60938d066692 First attempt to support timezones in licel files. diff -r b20b59b350d5 -r 3e97bd360eda atmospheric_lidar/generic.py --- a/atmospheric_lidar/generic.py Thu Dec 07 18:16:24 2017 +0200 +++ b/atmospheric_lidar/generic.py Tue Dec 12 11:54:57 2017 +0200 @@ -10,6 +10,8 @@ NETCDF_FORMAT = 'NETCDF4' # choose one of 'NETCDF3_CLASSIC', 'NETCDF3_64BIT', 'NETCDF4_CLASSIC' and 'NETCDF4' +logger = logging.getLogger(__name__) + class BaseLidarMeasurement(object): """ diff -r b20b59b350d5 -r 3e97bd360eda atmospheric_lidar/licel.py --- a/atmospheric_lidar/licel.py Thu Dec 07 18:16:24 2017 +0200 +++ b/atmospheric_lidar/licel.py Tue Dec 12 11:54:57 2017 +0200 @@ -2,12 +2,16 @@ import logging import numpy as np +import pytz from .systems.musa import musa_2009_netcdf_parameters from .systems.musa import musa_netcdf_parameters from generic import BaseLidarMeasurement, LidarChannel +logger = logging.getLogger(__name__) + + licel_file_header_format = ['Filename', 'StartDate StartTime EndDate EndTime Altitude Longtitude Latitude ZenithAngle', # Appart from Site that is read manually @@ -16,13 +20,14 @@ class LicelFile: - def __init__(self, filename, use_id_as_name=False): + def __init__(self, filename, use_id_as_name=False, licel_timezone="UTC"): self.filename = filename self.use_id_as_name = use_id_as_name self.start_time = None self.stop_time = None self.import_file(filename) self.calculate_physical() + self.licel_timezone=licel_timezone def calculate_physical(self): for channel in self.channels.itervalues(): @@ -40,7 +45,7 @@ self.read_header(f) # Check the complete header is read - a = f.readline() + f.readline() # Import the data for current_channel_info in self.channel_info: @@ -98,8 +103,20 @@ stop_string = '%s %s' % (raw_info['EndDate'], raw_info['EndTime']) date_format = '%d/%m/%Y %H:%M:%S' - self.start_time = datetime.datetime.strptime(start_string, date_format) - self.stop_time = datetime.datetime.strptime(stop_string, date_format) + try: + logger.debug('Creating timezone object %s' % self.licel_timezone) + timezone = pytz.timezone(self.licel_timezone) + except: + raise ValueError("Cloud not create time zone object %s" % self.licel_timezone) + + # According to pytz docs, timezones do not work with default datetime constructor. + local_start_time = timezone.localize(datetime.datetime.strptime(start_string, date_format)) + local_stop_time = timezone.localize(datetime.datetime.strptime(stop_string, date_format)) + + # Only save UTC time. + self.start_time = local_start_time.astimezone(pytz.utc) + self.stop_time = local_stop_time.astimezone(pytz.utc) + self.latitude = float(raw_info['Latitude']) self.longitude = float(raw_info['Longtitude']) @@ -197,15 +214,16 @@ durations = {} # Keep the duration of the files laser_shots = [] - def __init__(self, file_list=None, use_id_as_name=False): + def __init__(self, file_list=None, use_id_as_name=False, licel_timezone='UTC'): self.use_id_as_name = use_id_as_name + self.licel_timezone = licel_timezone super(LicelLidarMeasurement, self).__init__(file_list) def _import_file(self, filename): if filename in self.files: logging.warning("File has been imported already: %s" % filename) else: - current_file = LicelFile(filename, use_id_as_name=self.use_id_as_name) + current_file = LicelFile(filename, use_id_as_name=self.use_id_as_name, licel_timezone=self.licel_timezone) self.raw_info[current_file.filename] = current_file.raw_info self.durations[current_file.filename] = current_file.duration() diff -r b20b59b350d5 -r 3e97bd360eda atmospheric_lidar/licel_depol.py --- a/atmospheric_lidar/licel_depol.py Thu Dec 07 18:16:24 2017 +0200 +++ b/atmospheric_lidar/licel_depol.py Tue Dec 12 11:54:57 2017 +0200 @@ -1,5 +1,3 @@ -import datetime - import numpy as np from licel import LicelLidarMeasurement @@ -7,9 +5,9 @@ class LicelCalibrationMeasurement(LicelLidarMeasurement): - def __init__(self, plus45_files=None, minus45_files=None, use_id_as_name=False): + def __init__(self, plus45_files=None, minus45_files=None, use_id_as_name=False, licel_timezone='UTC'): # Setup the empty class - super(LicelCalibrationMeasurement, self).__init__(use_id_as_name=use_id_as_name) + super(LicelCalibrationMeasurement, self).__init__(use_id_as_name=use_id_as_name, licel_timezone=licel_timezone) self.plus45_files = plus45_files self.minus45_files = minus45_files @@ -39,10 +37,10 @@ def read_channel_data(self): # Read plus and minus 45 measurements - self.plus45_measurement = LicelLidarMeasurement(self.plus45_files, self.use_id_as_name) + self.plus45_measurement = LicelLidarMeasurement(self.plus45_files, self.use_id_as_name, self.licel_timezone) self.plus45_measurement.rename_channels(suffix='_p45') - self.minus45_measurement = LicelLidarMeasurement(self.minus45_files, self.use_id_as_name) + self.minus45_measurement = LicelLidarMeasurement(self.minus45_files, self.use_id_as_name, self.licel_timezone) self.minus45_measurement.rename_channels(suffix='_m45') # Combine them in this object diff -r b20b59b350d5 -r 3e97bd360eda atmospheric_lidar/scripts/licel2scc.py --- a/atmospheric_lidar/scripts/licel2scc.py Thu Dec 07 18:16:24 2017 +0200 +++ b/atmospheric_lidar/scripts/licel2scc.py Tue Dec 12 11:54:57 2017 +0200 @@ -12,20 +12,23 @@ from ..__init__ import __version__ -def create_custom_class(custom_netcdf_parameter_path, use_id_as_name=False, temperature=25., pressure=1020.): +def create_custom_class(custom_netcdf_parameter_path, use_id_as_name=False, temperature=25., pressure=1020., + licel_timezone='UTC'): """ This funtion creates a custom LicelLidarMeasurement subclass, based on the input provided by the users. Parameters ---------- - custom_netcdf_parameter_path: str + custom_netcdf_parameter_path : str The path to the custom channels parameters. - use_id_as_name: bool + use_id_as_name : bool Defines if channels names are descriptive or transient digitizer IDs. - temperature: float + temperature : float The ground temperature in degrees C (default 25.0). - pressure: float + pressure : float The ground pressure in hPa (default: 1020.0). + licel_timezone : str + String describing the timezone according to the tz database. Returns ------- @@ -39,7 +42,7 @@ extra_netcdf_parameters = custom_netcdf_parameters def __init__(self, file_list=None): - super(CustomLidarMeasurement, self).__init__(file_list, use_id_as_name) + super(CustomLidarMeasurement, self).__init__(file_list, use_id_as_name, licel_timezone=licel_timezone) def set_PT(self): ''' Sets the pressure and temperature at station level. This is used if molecular_calc parameter is @@ -89,6 +92,12 @@ parser.add_argument("-p", "--pressure", type=float, help="The pressure (in hPa) at lidar level, required if using US Standard atmosphere", default="1020") + parser.add_argument('-D', '--dark_measurements', help="Location of files containing dark measurements. Use relative path and filename wildcars, see 'files' parameter for example.", + default="", dest="dark_files" + ) + parser.add_argument('--licel_timezone', help="String describing the timezone according to the tz database.", + default="UTC", dest="licel_timezone", + ) # 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, @@ -96,9 +105,6 @@ parser.add_argument('-s', '--silent', help="Show only warning and error messages.", action="store_const", dest="loglevel", const=logging.WARNING ) - parser.add_argument('-D', '--dark_measurements', help="Location of files containing dark measurements. Use relative path and filename wildcars, see 'files' parameter for example.", - default="", dest="dark_files" - ) parser.add_argument('--version', help="Show current version.", action='store_true') args = parser.parse_args() @@ -107,7 +113,7 @@ logging.basicConfig(format='%(levelname)s: %(message)s', level=args.loglevel) logger = logging.getLogger(__name__) - #coloredlogs.install(fmt='%(levelname)s: %(message)s', level=args.loglevel) + # coloredlogs.install(fmt='%(levelname)s: %(message)s', level=args.loglevel) # Check for version if args.version: @@ -125,7 +131,7 @@ # If everything OK, proceed logger.info("Found {0} files matching {1}".format(len(files), os.path.abspath(args.files))) CustomLidarMeasurement = create_custom_class(args.parameter_file, args.id_as_name, args.temperature, - args.pressure) + args.pressure, args.licel_timezone) measurement = CustomLidarMeasurement(files) # Get a list of files containing dark measurements diff -r b20b59b350d5 -r 3e97bd360eda atmospheric_lidar/scripts/licel2scc_depol.py --- a/atmospheric_lidar/scripts/licel2scc_depol.py Thu Dec 07 18:16:24 2017 +0200 +++ b/atmospheric_lidar/scripts/licel2scc_depol.py Tue Dec 12 11:54:57 2017 +0200 @@ -12,7 +12,8 @@ from ..__init__ import __version__ -def create_custom_class(custom_netcdf_parameter_path, use_id_as_name=False, temperature=25., pressure=1020.): +def create_custom_class(custom_netcdf_parameter_path, use_id_as_name=False, temperature=25., pressure=1020., + licel_timezone='UTC'): """ This funtion creates a custom LicelLidarMeasurement subclass, based on the input provided by the users. @@ -26,6 +27,8 @@ The ground temperature in degrees C (default 25.0). pressure: float The ground pressure in hPa (default: 1020.0). + licel_timezone : str + String describing the timezone according to the tz database. Returns ------- @@ -39,7 +42,8 @@ extra_netcdf_parameters = custom_netcdf_parameters def __init__(self, plus45_files=None, minus45_files=None): - super(CustomLidarMeasurement, self).__init__(plus45_files, minus45_files, use_id_as_name) + super(CustomLidarMeasurement, self).__init__(plus45_files, minus45_files, use_id_as_name, + licel_timezone=licel_timezone) def set_PT(self): ''' Sets the pressure and temperature at station level. This is used if molecular_calc parameter is @@ -89,6 +93,9 @@ parser.add_argument("-p", "--pressure", type=float, help="The pressure (in hPa) at lidar level, required if using US Standard atmosphere", default="1020") + parser.add_argument('--licel_timezone', help="String describing the timezone according to the tz database.", + default="UTC", dest="licel_timezone", + ) # 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, @@ -123,7 +130,7 @@ 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) + args.pressure, args.licel_timezone) measurement = CustomLidarMeasurement(plus45_files, minus45_files) diff -r b20b59b350d5 -r 3e97bd360eda setup.py --- a/setup.py Thu Dec 07 18:16:24 2017 +0200 +++ b/setup.py Tue Dec 12 11:54:57 2017 +0200 @@ -52,6 +52,7 @@ "numpy", "matplotlib", "sphinx", + "pytz", ], entry_points={ 'console_scripts': ['licel2scc = atmospheric_lidar.scripts.licel2scc:main',