climate-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From huiky...@apache.org
Subject [1/4] climate git commit: Initial commit
Date Wed, 03 Aug 2016 15:40:06 GMT
Repository: climate
Updated Branches:
  refs/heads/master 8f3a16e2c -> d73c3c21c


Initial commit


Project: http://git-wip-us.apache.org/repos/asf/climate/repo
Commit: http://git-wip-us.apache.org/repos/asf/climate/commit/0cc4b1ea
Tree: http://git-wip-us.apache.org/repos/asf/climate/tree/0cc4b1ea
Diff: http://git-wip-us.apache.org/repos/asf/climate/diff/0cc4b1ea

Branch: refs/heads/master
Commit: 0cc4b1eac2eab8ffbc9a5ab20c6b2e8c2f34f17c
Parents: 7ab0141
Author: huikyole <huikyole@argo.jpl.nasa.gov>
Authored: Mon Aug 1 17:36:10 2016 -0700
Committer: huikyole <huikyole@argo.jpl.nasa.gov>
Committed: Mon Aug 1 17:36:10 2016 -0700

----------------------------------------------------------------------
 ocw/dataset.py | 308 ++++++++++++++++++++++++++++++++++------------------
 1 file changed, 204 insertions(+), 104 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/climate/blob/0cc4b1ea/ocw/dataset.py
----------------------------------------------------------------------
diff --git a/ocw/dataset.py b/ocw/dataset.py
index f9c344e..509c04a 100644
--- a/ocw/dataset.py
+++ b/ocw/dataset.py
@@ -25,6 +25,8 @@ Classes:
 import numpy
 import logging
 import datetime as dt
+from mpl_toolkits.basemap import Basemap
+import netCDF4
 
 import ocw.utils as utils
 
@@ -231,18 +233,35 @@ class Bounds(object):
     correct functioning. Bounds guarantees that a function receives well
     formed information without the need to do the validation manually.
 
-    Spatial and temporal bounds must follow the following guidelines.
+    boundary_type may be one of the following:
+    * 'rectangular'
+    * 'CORDEX (CORDEX region name)': pre-defined CORDEX boundary
+    * 'us_states': an array of US states abbreviation is required (ex) us_states = ['CA','NV'])

+    * 'countries': an array of county names is required (ex) countries = ['United States','Canada','Mexico']
+    * 'user': user_mask_file in a netCDF format with two dimensional mask variable is required.
 
+
+    If boundary_type == 'rectangular', spatial and temporal bounds must follow the following
guidelines.
 
     * Latitude values must be in the range [-90, 90]
     * Longitude values must be in the range [-180, 180]
     * Lat/Lon Min values must be less than the corresponding Lat/Lon Max
       values.
-    * Temporal bounds must a valid datetime object
+
+    Temporal bounds must a valid datetime object
     '''
 
-    def __init__(self, lat_min, lat_max, lon_min,
-                 lon_max, start=None, end=None):
+    def __init__(self, boundary_type='rectangular', 
+                       us_states=None, countries=None, 
+                       user_mask_file=None, mask_variable_name=None, longitude_name=None,
latitude_name=None, 
+                       lat_min=None, lat_max=None, lon_min=None, lon_max=None, 
+                       start=None, end=None):
         '''Default Bounds constructor
+        :param boundary_type: The type of spatial subset boundary.
+        :type boundary_type: :mod:`string'
+
+
+        :param lat_min: The minimum latitude bound.
+        :type lat_min: :class:`float`
 
         :param lat_min: The minimum latitude bound.
         :type lat_min: :class:`float`
@@ -265,11 +284,7 @@ class Bounds(object):
 
         :raises: ValueError
         '''
-        self._lat_min = float(lat_min)
-        self._lat_max = float(lat_max)
-        self._lon_min = float(lon_min)
-        self._lon_max = float(lon_max)
-
+        self.boundary_type = boundary_type
         if start:
             self._start = start
         else:
@@ -280,100 +295,185 @@ class Bounds(object):
         else:
             self._end = None
 
-    @property
-    def lat_min(self):
-        return self._lat_min
-
-    @lat_min.setter
-    def lat_min(self, value):
-        if not (-90 <= value <= 90 and value < self._lat_max):
-            error = "Attempted to set lat_min to invalid value: %s" % (value)
-            logger.error(error)
-            raise ValueError(error)
-
-        self._lat_min = value
-
-    @property
-    def lat_max(self):
-        return self._lat_max
-
-    @lat_max.setter
-    def lat_max(self, value):
-        if not (-90 <= value <= 90 and value > self._lat_min):
-            error = "Attempted to set lat_max to invalid value: %s" % (value)
-            logger.error(error)
-            raise ValueError(error)
-
-        self._lat_max = value
-
-    @property
-    def lon_min(self):
-        return self._lon_min
-
-    @lon_min.setter
-    def lon_min(self, value):
-        if not (-180 <= value <= 180 and value < self._lon_max):
-            error = "Attempted to set lon_min to invalid value: %s" % (value)
-            logger.error(error)
-            raise ValueError(error)
-
-        self._lon_min = value
-
-    @property
-    def lon_max(self):
-        return self._lon_max
-
-    @lon_max.setter
-    def lon_max(self, value):
-        if not (-180 <= value <= 180 and value > self._lon_min):
-            error = "Attempter to set lon_max to invalid value: %s" % (value)
-            logger.error(error)
-            raise ValueError(error)
-
-        self._lon_max = value
-
-    @property
-    def start(self):
-        return self._start
-
-    @start.setter
-    def start(self, value):
-        if self._end:
-            if not (type(value) is dt.datetime and value < self._end):
-                error = "Attempted to set start to invalid value: %s" % (value)
-                logger.error(error)
-                raise ValueError(error)
-
-        self._start = value
-
-    @property
-    def end(self):
-        return self._end
-
-    @end.setter
-    def end(self, value):
-        if self._start:
-            if not (type(value) is dt.datetime and value > self._start):
-                error = "Attempted to set end to invalid value: %s" % (value)
-                logger.error(error)
-                raise ValueError(error)
-
-        self._end = value
-
-    def __str__(self):
-        lat_range = "({}, {})".format(self._lat_min, self._lat_max)
-        lon_range = "({}, {})".format(self._lon_min, self._lon_max)
-        temporal_boundaries = "({}, {})".format(self._start, self._end)
+        @property
+        def start(self):
+            return self._start
+
+        @start.setter
+        def start(self, value):
+            if self._end:
+                if not (type(value) is dt.datetime and value < self._end):
+                    error = "Attempted to set start to invalid value: %s" % (value)
+                    logger.error(error)
+                    raise ValueError(error)
+
+            self._start = value
+
+        @property
+        def end(self):
+            return self._end
+
+        @end.setter
+        def end(self, value):
+            if self._start:
+                if not (type(value) is dt.datetime and value > self._start):
+                    error = "Attempted to set end to invalid value: %s" % (value)
+                    logger.error(error)
+                    raise ValueError(error)
+
+        if boundary_type == 'us_states':
+            self.masked_regions = shapefile_boundary(boundary_type, us_states)
+        if boundary_type == 'countries':
+            self.masked_regions = shapefile_boundary(boundary_type, countries)
+        if boundary_type == 'user':
+            file_object = netCDF4.Dataset(user_mask_file)
+            self.mask_variable = file_object.variables[mask_variable_name][:]
+            mask_longitude = file_object.variables[longitude_name][:]
+            mask_latitude = file_object.variables[latitude_name][:]
+            if mask_longitude.ndim == 1 and mask_latitude.ndim == 1:
+                self.mask_longitude, self.mask_latitude = np.meshgrid(mask_longitude, mask_latitude)
+            elif mask_longitude.ndim == 2 and mask_latitude.ndim == 2:
+                self.mask_longitude = mask_longitude
+                self.mask_latitude = mask_latitude  
+        if boundary_type == 'rectangular' or boundary_type[:6].upper() == 'CORDEX':
+            if boundary_type == 'rectangular':
+                self._lat_min = float(lat_min)
+                self._lat_max = float(lat_max)
+                self._lon_min = float(lon_min)
+                self._lon_max = float(lon_max)
+            if boundary_type[:6].upper() == 'CORDEX':
+                self._lat_min, self._lat_max, self._lon_min, self._lon_max = CORDEX_boundary(boundary_type[6:].replace("
","").lower())
+
+
+            @property
+            def lat_min(self):
+                return self._lat_min
+
+            @lat_min.setter
+            def lat_min(self, value):
+                if not (-90 <= value <= 90 and value < self._lat_max):
+                    error = "Attempted to set lat_min to invalid value: %s" % (value)
+                    logger.error(error)
+                    raise ValueError(error)
+
+                self._lat_min = value
+
+            @property
+            def lat_max(self):
+                return self._lat_max
+
+            @lat_max.setter
+            def lat_max(self, value):
+                if not (-90 <= value <= 90 and value > self._lat_min):
+                    error = "Attempted to set lat_max to invalid value: %s" % (value)
+                    logger.error(error)
+                    raise ValueError(error)
+
+                self._lat_max = value
+
+            @property
+            def lon_min(self):
+                return self._lon_min
+
+            @lon_min.setter
+            def lon_min(self, value):
+                if not (-180 <= value <= 180 and value < self._lon_max):
+                    error = "Attempted to set lon_min to invalid value: %s" % (value)
+                    logger.error(error)
+                    raise ValueError(error)
+
+                self._lon_min = value
+
+            @property
+            def lon_max(self):
+                return self._lon_max
+
+            @lon_max.setter
+            def lon_max(self, value):
+                if not (-180 <= value <= 180 and value > self._lon_min):
+                    error = "Attempter to set lon_max to invalid value: %s" % (value)
+                    logger.error(error)
+                    raise ValueError(error)
+
+                self._lon_max = value
+
+
+            def __str__(self):
+                lat_range = "({}, {})".format(self._lat_min, self._lat_max)
+                lon_range = "({}, {})".format(self._lon_min, self._lon_max)
+                temporal_boundaries = "({}, {})".format(self._start, self._end)
+
+                formatted_repr = (
+                    "<Bounds - "
+                    "lat-range: {}, "
+                    "lon-range: {}, "
+                    "temporal_boundaries: {}> "
+                )
+
+                return formatted_repr.format(
+                    lat_range,
+                    lon_range,
+                    temporal_boundaries,
+                )
+
+
+def shapefile_boundary(boundary_type, region_names):
+    '''
+    :param boundary_type: The type of spatial subset boundary
+    :type boundary_type: :mod:'string'
 
-        formatted_repr = (
-            "<Bounds - "
-            "lat-range: {}, "
-            "lon-range: {}, "
-            "temporal_boundaries: {}> "
-        )
+    :param region_names: An array of regions for spatial subset
+    :type region_names: :mod:'list'
+    '''
 
-        return formatted_repr.format(
-            lat_range,
-            lon_range,
-            temporal_boundaries,
-        )
+    map_read = Basemap
+    regions =[]
+    if boundary_type == 'us_states':
+        #map_read.readshapefile(ocw.__path__[0]+'/shape/usa_states','usa_states')
+        map_read.readshapefile('/home/huikyole/climate/ocw'+'/shape/usa_states','usa_states')
+        for region_name in region_names:
+            for iregion, region_info in enumerate(map_read.usa_states_info):
+                if region_info['st'] == region_name:
+                    regions.append(np.array(map_read.usa_states[iregion]))
+    if boundary_type == 'countries':
+        #map_read.readshapefile(ocw.__path__[0]+'/shape/countries','countries')
+        map_read.readshapefile('/home/huikyole/climate/ocw'+'/shape/countries','countries')
+        for region_name in region_names:
+            for iregion, region_info in enumerate(map_read.countries_info):
+                if region_info['COUNTRY'] == region_name:
+                    regions.append(np.array(map_read.countries[iregion]))
+    return regions
+
+def CORDEX_boundary(domain_name):
+    '''
+    :param domain_name: CORDEX domain name (http://www.cordex.org/)
+    :type domain_name: :mod:'string'
+    '''
+    if domain_name =='southamerica':
+        return -57.61, 18.50, 254.28-360., 343.02-360.
+    if domain_name =='centralamerica':
+        return -19.46, 34.83, 235.74-360., 337.78-360.
+    if domain_name =='northamerica':
+        return  12.55, 75.88, 189.26-360., 336.74-360.
+    if domain_name =='europe':
+        return  22.20, 71.84, 338.23-360., 64.4      
+    if domain_name =='africa':
+        return -45.76, 42.24, 335.36-360., 60.28     
+    if domain_name =='southasia':
+        return -15.23, 45.07, 19.88, 115.55    
+    if domain_name =='eastasia':
+        return  -0.10, 61.90, 51.59, 179.99    
+    if domain_name =='centralasia':
+        return  18.34, 69.37, 11.05, 139.13    
+    if domain_name =='australasia':
+        return -52.36, 12.21, 89.25, 179.99    
+    if domain_name =='antartica':
+        return -89.48,-56.00, -179.00, 179.00    
+    if domain_name =='artic':
+        return 46.06, 89.50, -179.00, 179.00    
+    if domain_name =='mediterranean':
+        return  25.63, 56.66, 339.79-360.00, 50.85     
+    if domain_name =='middleeastnorthafrica':
+        return  -7.00, 45.00, 333.00-360.00, 76.00     
+    if domain_name =='southeastasia':
+        return  -15.14, 27.26, 89.26, 146.96     


Mime
View raw message