First attempt to support timezones in licel files.

Tue, 12 Dec 2017 11:54:57 +0200

author
Iannis <i.binietoglou@impworks.gr>
date
Tue, 12 Dec 2017 11:54:57 +0200
changeset 101
3e97bd360eda
parent 100
b20b59b350d5
child 102
b71252bb7f87

First attempt to support timezones in licel files.

atmospheric_lidar/generic.py file | annotate | diff | comparison | revisions
atmospheric_lidar/licel.py file | annotate | diff | comparison | revisions
atmospheric_lidar/licel_depol.py file | annotate | diff | comparison | revisions
atmospheric_lidar/scripts/licel2scc.py file | annotate | diff | comparison | revisions
atmospheric_lidar/scripts/licel2scc_depol.py file | annotate | diff | comparison | revisions
setup.py file | annotate | diff | comparison | revisions
--- 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):
     """ 
--- 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()
             
--- 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
--- 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
--- 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)
 
--- 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',

mercurial