climate-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From huiky...@apache.org
Subject [2/4] climate git commit: CLIMATE-827 - Adding spatial masking options
Date Wed, 03 Aug 2016 15:40:07 GMT
CLIMATE-827 - Adding spatial masking options

- new masking options, CORDEX, us_states, countires and user have been added
- dataset_processor.subset will be updated later.


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

Branch: refs/heads/master
Commit: 02dfdec65adb81cdc659764008045e99f61bbf4d
Parents: 0cc4b1e
Author: huikyole <huikyole@argo.jpl.nasa.gov>
Authored: Tue Aug 2 16:35:28 2016 -0700
Committer: huikyole <huikyole@argo.jpl.nasa.gov>
Committed: Tue Aug 2 16:35:28 2016 -0700

----------------------------------------------------------------------
 RCMES/cli_app.py                              |   2 +-
 RCMES/run_RCMES.py                            |   2 +-
 RCMES/test/test.py                            |   2 +-
 examples/knmi_to_cru31_full_bias.py           |   2 +-
 examples/model_ensemble_to_rcmed.py           |   2 +-
 examples/multi_model_evaluation.py            |   2 +-
 examples/multi_model_taylor_diagram.py        |   2 +-
 examples/taylor_diagram_example.py            |   2 +-
 examples/time_series_with_regions.py          |   2 +-
 ocw/dataset.py                                | 176 +++++++--------------
 ocw/dataset_processor.py                      | 113 ++++++-------
 ocw/tests/test_dataset.py                     | 126 ++++-----------
 ocw/tests/test_dataset_processor.py           |  62 ++++----
 ocw/tests/test_evaluation.py                  |  18 +--
 ocw_config_runner/tests/test_config_writer.py |   4 +-
 15 files changed, 201 insertions(+), 316 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/climate/blob/02dfdec6/RCMES/cli_app.py
----------------------------------------------------------------------
diff --git a/RCMES/cli_app.py b/RCMES/cli_app.py
index 9894a35..22572db 100644
--- a/RCMES/cli_app.py
+++ b/RCMES/cli_app.py
@@ -634,7 +634,7 @@ def run_screen(model_datasets, models_info, observations_info,
              screen.addstr(4, 4, "--> Data retrieved.")
              screen.refresh()
 
-             EVAL_BOUNDS = Bounds(overlap_min_lat, overlap_max_lat, overlap_min_lon, overlap_max_lon,
overlap_start_time, overlap_end_time)
+             EVAL_BOUNDS = Bounds(lat_min=overlap_min_lat, lat_max=overlap_max_lat, lon_min=overlap_min_lon,
lon_max=overlap_max_lon, start=overlap_start_time, end=overlap_end_time)
 
              screen.addstr(5, 4, "Temporally regridding...")
              screen.refresh()

http://git-wip-us.apache.org/repos/asf/climate/blob/02dfdec6/RCMES/run_RCMES.py
----------------------------------------------------------------------
diff --git a/RCMES/run_RCMES.py b/RCMES/run_RCMES.py
index cd69bc4..d026ec3 100644
--- a/RCMES/run_RCMES.py
+++ b/RCMES/run_RCMES.py
@@ -144,7 +144,7 @@ if ref_data_info['data_source'] == 'rcmed':
     max_lat = np.min([max_lat, ref_dataset.lats.max()])
     min_lon = np.max([min_lon, ref_dataset.lons.min()])
     max_lon = np.min([max_lon, ref_dataset.lons.max()])
-bounds = Bounds(min_lat, max_lat, min_lon, max_lon, start_time, end_time)
+bounds = Bounds(lat_min=min_lat, lat_max=max_lat, lon_min=min_lon, lon_max=max_lon, start=start_time,
end=end_time)
 
 ref_dataset = dsp.subset(ref_dataset, bounds)
 if ref_dataset.temporal_resolution() != temporal_resolution:

http://git-wip-us.apache.org/repos/asf/climate/blob/02dfdec6/RCMES/test/test.py
----------------------------------------------------------------------
diff --git a/RCMES/test/test.py b/RCMES/test/test.py
index 677a13f..a62d781 100644
--- a/RCMES/test/test.py
+++ b/RCMES/test/test.py
@@ -111,7 +111,7 @@ print("KNMI_Dataset.values shape: (times, lats, lons) - %s" % (knmi_dataset.valu
 print("Our two datasets have a mis-match in time. We will subset on time to %s years\n" %
YEARS)
 
 # Create a Bounds object to use for subsetting
-new_bounds = Bounds(min_lat, max_lat, min_lon, max_lon, start_time, end_time)
+new_bounds = Bounds(lat_min=min_lat, lat_max=max_lat, lon_min=min_lon, lon_max=max_lon, start=start_time,
end=end_time)
 knmi_dataset = dsp.subset(knmi_dataset, new_bounds)
 
 print("CRU31_Dataset.values shape: (times, lats, lons) - %s" % (cru31_dataset.values.shape,))

http://git-wip-us.apache.org/repos/asf/climate/blob/02dfdec6/examples/knmi_to_cru31_full_bias.py
----------------------------------------------------------------------
diff --git a/examples/knmi_to_cru31_full_bias.py b/examples/knmi_to_cru31_full_bias.py
index 4c0abd9..dd70341 100644
--- a/examples/knmi_to_cru31_full_bias.py
+++ b/examples/knmi_to_cru31_full_bias.py
@@ -111,7 +111,7 @@ print("KNMI_Dataset.values shape: (times, lats, lons) - %s" % (knmi_dataset.valu
 print("Our two datasets have a mis-match in time. We will subset on time to %s years\n" %
YEARS)
 
 # Create a Bounds object to use for subsetting
-new_bounds = Bounds(min_lat, max_lat, min_lon, max_lon, start_time, end_time)
+new_bounds = Bounds(lat_min=min_lat, lat_max=max_lat, lon_min=min_lon, lon_max=max_lon, start=start_time,
end=end_time)
 knmi_dataset = dsp.subset(knmi_dataset, new_bounds)
 
 print("CRU31_Dataset.values shape: (times, lats, lons) - %s" % (cru31_dataset.values.shape,))

http://git-wip-us.apache.org/repos/asf/climate/blob/02dfdec6/examples/model_ensemble_to_rcmed.py
----------------------------------------------------------------------
diff --git a/examples/model_ensemble_to_rcmed.py b/examples/model_ensemble_to_rcmed.py
index fef1f9d..7b82197 100644
--- a/examples/model_ensemble_to_rcmed.py
+++ b/examples/model_ensemble_to_rcmed.py
@@ -128,7 +128,7 @@ cru31_dataset = dsp.temporal_rebin(cru31_dataset, temporal_resolution
= 'annual'
 # Running Temporal Rebin early helps negate the issue of datasets being on different 
 # days of the month (1st vs. 15th)
 # Create a Bounds object to use for subsetting
-new_bounds = Bounds(min_lat, max_lat, min_lon, max_lon, start_time, end_time)
+new_bounds = Bounds(lat_min=min_lat, lat_max=max_lat, lon_min=min_lon, lon_max=max_lon, start=start_time,
end=end_time)
 
 # Subset our model datasets so they are the same size
 knmi_dataset = dsp.subset(knmi_dataset, new_bounds)

http://git-wip-us.apache.org/repos/asf/climate/blob/02dfdec6/examples/multi_model_evaluation.py
----------------------------------------------------------------------
diff --git a/examples/multi_model_evaluation.py b/examples/multi_model_evaluation.py
index 0755279..97c96d9 100644
--- a/examples/multi_model_evaluation.py
+++ b/examples/multi_model_evaluation.py
@@ -50,7 +50,7 @@ LON_MIN = -24.0
 LON_MAX = 60.0 
 START = datetime.datetime(2000, 1, 1)
 END = datetime.datetime(2007, 12, 31)
-EVAL_BOUNDS = Bounds(LAT_MIN, LAT_MAX, LON_MIN, LON_MAX, START, END)
+EVAL_BOUNDS = Bounds(lat_min=LAT_MIN, lat_max=LAT_MAX, lon_min=LON_MIN, lon_max=LON_MAX,
start=START, end=END)
 
 #regridding parameters
 gridLonStep=0.5

http://git-wip-us.apache.org/repos/asf/climate/blob/02dfdec6/examples/multi_model_taylor_diagram.py
----------------------------------------------------------------------
diff --git a/examples/multi_model_taylor_diagram.py b/examples/multi_model_taylor_diagram.py
index 9ba8746..b7daf61 100644
--- a/examples/multi_model_taylor_diagram.py
+++ b/examples/multi_model_taylor_diagram.py
@@ -34,7 +34,7 @@ LON_MIN = -24.0
 LON_MAX = 60.0 
 START = datetime.datetime(2000, 01, 1)
 END = datetime.datetime(2007, 12, 31)
-EVAL_BOUNDS = Bounds(LAT_MIN, LAT_MAX, LON_MIN, LON_MAX, START, END)
+EVAL_BOUNDS = Bounds(lat_min=LAT_MIN, lat_max=LAT_MAX, lon_min=LON_MIN, lon_max=LON_MAX,
start=START, end=END)
 
 #variable that we are analyzing
 varName = 'pr' 

http://git-wip-us.apache.org/repos/asf/climate/blob/02dfdec6/examples/taylor_diagram_example.py
----------------------------------------------------------------------
diff --git a/examples/taylor_diagram_example.py b/examples/taylor_diagram_example.py
index 66ca175..bae85be 100644
--- a/examples/taylor_diagram_example.py
+++ b/examples/taylor_diagram_example.py
@@ -61,7 +61,7 @@ wrf_dataset = dsp.normalize_dataset_datetimes(wrf_dataset, 'monthly')
 # We're only going to run this evaluation over a years worth of data. We'll
 # make a Bounds object and use it to subset our datasets.
 ################################################################################
-subset = Bounds(-45, 42, -24, 60, datetime.datetime(1989, 1, 1), datetime.datetime(1989,
12, 1))
+subset = Bounds(lat_min=-45, lat_max=42, lon_min=-24, lon_max=60, start=datetime.datetime(1989,
1, 1), end=datetime.datetime(1989, 12, 1))
 knmi_dataset = dsp.subset(knmi_dataset, subset)
 wrf_dataset = dsp.subset(wrf_dataset, subset)
 

http://git-wip-us.apache.org/repos/asf/climate/blob/02dfdec6/examples/time_series_with_regions.py
----------------------------------------------------------------------
diff --git a/examples/time_series_with_regions.py b/examples/time_series_with_regions.py
index 8d9e5c0..15e2ee2 100644
--- a/examples/time_series_with_regions.py
+++ b/examples/time_series_with_regions.py
@@ -32,7 +32,7 @@ LON_MAX = 60.0
 START = datetime.datetime(2000, 01, 1)
 END = datetime.datetime(2007, 12, 31)
 
-EVAL_BOUNDS = Bounds(LAT_MIN, LAT_MAX, LON_MIN, LON_MAX, START, END)
+EVAL_BOUNDS = Bounds(lat_min=LAT_MIN, lat_max=LAT_MAX, lon_min=LON_MIN, lon_max=LON_MAX,
start=START, end=END)
 
 varName = 'pr' 
 gridLonStep=0.44

http://git-wip-us.apache.org/repos/asf/climate/blob/02dfdec6/ocw/dataset.py
----------------------------------------------------------------------
diff --git a/ocw/dataset.py b/ocw/dataset.py
index 509c04a..52e610a 100644
--- a/ocw/dataset.py
+++ b/ocw/dataset.py
@@ -28,6 +28,7 @@ import datetime as dt
 from mpl_toolkits.basemap import Basemap
 import netCDF4
 
+import ocw
 import ocw.utils as utils
 
 logger = logging.getLogger(__name__)
@@ -295,32 +296,6 @@ class Bounds(object):
         else:
             self._end = None
 
-        @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':
@@ -331,91 +306,62 @@ class Bounds(object):
             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)
+                self.mask_longitude, self.mask_latitude = numpy.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,
-                )
-
+        if boundary_type == 'rectangular':
+            if not (-90 <= float(lat_min) <=90) or float(lat_min) > float(lat_max):
+                error = "Attempted to set lat_min to invalid value: %s" % (lat_min)
+                logger.error(error)
+                raise ValueError(error)
+            if not (-90 <= float(lat_max) <=90):
+                error = "Attempted to set lat_max to invalid value: %s" % (lat_max)
+                logger.error(error)
+                raise ValueError(error)
+            if not (-180 <= float(lon_min) <=180) or float(lon_min) > float(lon_max):
+                error = "Attempted to set lon_min to invalid value: %s" % (lon_min)
+                logger.error(error)
+                raise ValueError(error)
+            if not (-180 <= float(lon_max) <=180):
+                error = "Attempted to set lat_max to invalid value: %s" % (lon_max)
+                logger.error(error)
+                raise ValueError(error)
+ 
+            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 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 shapefile_boundary(boundary_type, region_names):
     '''
@@ -426,22 +372,22 @@ def shapefile_boundary(boundary_type, region_names):
     :type region_names: :mod:'list'
     '''
 
-    map_read = Basemap
+    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')
+        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]))
+                    regions.append(numpy.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')
+        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]))
+                    regions.append(numpy.array(map_read.countries[iregion]))
     return regions
 
 def CORDEX_boundary(domain_name):

http://git-wip-us.apache.org/repos/asf/climate/blob/02dfdec6/ocw/dataset_processor.py
----------------------------------------------------------------------
diff --git a/ocw/dataset_processor.py b/ocw/dataset_processor.py
index 2b5dc9b..8b817a2 100755
--- a/ocw/dataset_processor.py
+++ b/ocw/dataset_processor.py
@@ -383,57 +383,58 @@ def subset(target_dataset, subregion, subregion_name=None):
     if not subregion.start:
         subregion.start = target_dataset.times[0]
         subregion.end = target_dataset.times[-1]
-
-    # Ensure that the subregion information is well formed
-    _are_bounds_contained_by_dataset(target_dataset, subregion)
-
+    
     if not subregion_name:
         subregion_name = target_dataset.name
 
-    if target_dataset.lats.ndim == 2 and target_dataset.lons.ndim == 2:
-        start_time_index = np.where(
-            target_dataset.times == subregion.start)[0][0]
-        end_time_index = np.where(target_dataset.times == subregion.end)[0][0]
-        target_dataset = temporal_slice(
-            target_dataset, start_time_index, end_time_index)
-        nt, ny, nx = target_dataset.values.shape
-        y_index, x_index = np.where(
-            (target_dataset.lats >= subregion.lat_max) | (
-                target_dataset.lats <= subregion.lat_min) |
-            (target_dataset.lons >= subregion.lon_max) | (
-                target_dataset.lons <= subregion.lon_min))
-        for it in np.arange(nt):
-            target_dataset.values[it, y_index, x_index] = 1.e+20
-        target_dataset.values = ma.masked_equal(target_dataset.values, 1.e+20)
-        return target_dataset
-
-    elif target_dataset.lats.ndim == 1 and target_dataset.lons.ndim == 1:
-        # Get subregion indices into subregion data
-        dataset_slices = _get_subregion_slice_indices(target_dataset,
-                                                      subregion)
-        # Slice the values array with our calculated slice indices
-        if target_dataset.values.ndim == 2:
-            subset_values = ma.zeros([len(target_dataset.values[
-                dataset_slices["lat_start"]:dataset_slices["lat_end"]]),
-                len(target_dataset.values[
-                    dataset_slices["lon_start"]:dataset_slices["lon_end"]])])
-
-            subset_values = target_dataset.values[
-                dataset_slices["lat_start"]:dataset_slices["lat_end"] + 1,
-                dataset_slices["lon_start"]:dataset_slices["lon_end"] + 1]
-
-        elif target_dataset.values.ndim == 3:
-            subset_values = ma.zeros([len(target_dataset.values[
-                dataset_slices["time_start"]:dataset_slices["time_end"]]),
-                len(target_dataset.values[
+    if subregion.lat_min:
+        # If boundary_type is 'rectangular' or 'CORDEX ***', ensure that the subregion information
is well formed
+        _are_bounds_contained_by_dataset(target_dataset, subregion)
+
+        if target_dataset.lats.ndim == 2 and target_dataset.lons.ndim == 2:
+            start_time_index = np.where(
+                target_dataset.times == subregion.start)[0][0]
+            end_time_index = np.where(target_dataset.times == subregion.end)[0][0]
+            target_dataset = temporal_slice(
+                target_dataset, start_time_index, end_time_index)
+            nt, ny, nx = target_dataset.values.shape
+            y_index, x_index = np.where(
+                (target_dataset.lats >= subregion.lat_max) | (
+                    target_dataset.lats <= subregion.lat_min) |
+                (target_dataset.lons >= subregion.lon_max) | (
+                    target_dataset.lons <= subregion.lon_min))
+            for it in np.arange(nt):
+                target_dataset.values[it, y_index, x_index] = 1.e+20
+            target_dataset.values = ma.masked_equal(target_dataset.values, 1.e+20)
+            return target_dataset
+
+        elif target_dataset.lats.ndim == 1 and target_dataset.lons.ndim == 1:
+            # Get subregion indices into subregion data
+            dataset_slices = _get_subregion_slice_indices(target_dataset,
+                                                          subregion)
+            # Slice the values array with our calculated slice indices
+            if target_dataset.values.ndim == 2:
+                subset_values = ma.zeros([len(target_dataset.values[
                     dataset_slices["lat_start"]:dataset_slices["lat_end"]]),
-                len(target_dataset.values[
-                    dataset_slices["lon_start"]:dataset_slices["lon_end"]])])
-
-            subset_values = target_dataset.values[
-                dataset_slices["time_start"]:dataset_slices["time_end"] + 1,
-                dataset_slices["lat_start"]:dataset_slices["lat_end"] + 1,
-                dataset_slices["lon_start"]:dataset_slices["lon_end"] + 1]
+                    len(target_dataset.values[
+                        dataset_slices["lon_start"]:dataset_slices["lon_end"]])])
+
+                subset_values = target_dataset.values[
+                    dataset_slices["lat_start"]:dataset_slices["lat_end"] + 1,
+                    dataset_slices["lon_start"]:dataset_slices["lon_end"] + 1]
+
+            elif target_dataset.values.ndim == 3:
+                subset_values = ma.zeros([len(target_dataset.values[
+                    dataset_slices["time_start"]:dataset_slices["time_end"]]),
+                    len(target_dataset.values[
+                        dataset_slices["lat_start"]:dataset_slices["lat_end"]]),
+                    len(target_dataset.values[
+                        dataset_slices["lon_start"]:dataset_slices["lon_end"]])])
+
+                subset_values = target_dataset.values[
+                    dataset_slices["time_start"]:dataset_slices["time_end"] + 1,
+                    dataset_slices["lat_start"]:dataset_slices["lat_end"] + 1,
+                    dataset_slices["lon_start"]:dataset_slices["lon_end"] + 1]
 
         # Build new dataset with subset information
         return ds.Dataset(
@@ -505,18 +506,18 @@ def safe_subset(target_dataset, subregion, subregion_name=None):
 
     lat_min, lat_max, lon_min, lon_max = target_dataset.spatial_boundaries()
     start, end = target_dataset.temporal_boundaries()
+    if subregion.lat_min:
+        if subregion.lat_min < lat_min:
+            subregion.lat_min = lat_min
 
-    if subregion.lat_min < lat_min:
-        subregion.lat_min = lat_min
-
-    if subregion.lat_max > lat_max:
-        subregion.lat_max = lat_max
+        if subregion.lat_max > lat_max:
+            subregion.lat_max = lat_max
 
-    if subregion.lon_min < lon_min:
-        subregion.lon_min = lon_min
+        if subregion.lon_min < lon_min:
+            subregion.lon_min = lon_min
 
-    if subregion.lon_max > lon_max:
-        subregion.lon_max = lon_max
+        if subregion.lon_max > lon_max:
+            subregion.lon_max = lon_max
 
     if subregion.start:
         if subregion.start < start:

http://git-wip-us.apache.org/repos/asf/climate/blob/02dfdec6/ocw/tests/test_dataset.py
----------------------------------------------------------------------
diff --git a/ocw/tests/test_dataset.py b/ocw/tests/test_dataset.py
index 8b666c1..9d77400 100644
--- a/ocw/tests/test_dataset.py
+++ b/ocw/tests/test_dataset.py
@@ -214,120 +214,58 @@ class TestDatasetFunctions(unittest.TestCase):
 
 class TestBounds(unittest.TestCase):
     def setUp(self):
-        self.bounds = Bounds(-80, 80,                # Lats
-                             -160, 160,               # Lons
-                             dt.datetime(2000, 1, 1),  # Start time
-                             dt.datetime(2002, 1, 1))  # End time
-        self.another_bounds = Bounds(-80, 80,                # Lats
-                                     -160, 160)
-
-    def test_setter_methods(self):
-        self.bounds.lat_min = -10
-        self.bounds.lat_max = 10
-        self.bounds.lon_min = -120
-        self.bounds.lon_max = 120
-        self.bounds.start = dt.datetime(2000, 1, 2)
-        self.bounds.end = dt.datetime(2002, 1, 4)
-
-        self.assertEqual(self.bounds.lat_min, -10)
-        self.assertEqual(self.bounds.lat_max, 10)
-        self.assertEqual(self.bounds.lon_min, -120)
-        self.assertEqual(self.bounds.lon_max, 120)
-        self.assertEqual(self.bounds.start, dt.datetime(2000, 1, 2))
-        self.assertEqual(self.bounds.end, dt.datetime(2002, 1, 4))
-
-    # Latitude tests
-    def test_inverted_min_max_lat(self):
-        with self.assertRaises(ValueError):
-            self.bounds.lat_min = 81
-
-        with self.assertRaises(ValueError):
-            self.bounds.lat_max = -81
-
-    # Lat Min
-    def test_out_of_bounds_lat_min(self):
-        with self.assertRaises(ValueError):
-            self.bounds.lat_min = -91
-
-        with self.assertRaises(ValueError):
-            self.bounds.lat_min = 91
-
-    # Lat Max
-    def test_out_of_bounds_lat_max(self):
-        with self.assertRaises(ValueError):
-            self.bounds.lat_max = -91
-
-        with self.assertRaises(ValueError):
-            self.bounds.lat_max = 91
-
-    # Longitude tests
-    def test_inverted_max_max_lon(self):
-        with self.assertRaises(ValueError):
-            self.bounds.lon_min = 161
-
-        with self.assertRaises(ValueError):
-            self.bounds.lon_max = -161
-
-    # Lon Min
-    def test_out_of_bounds_lon_min(self):
-        with self.assertRaises(ValueError):
-            self.bounds.lon_min = -181
-
-        with self.assertRaises(ValueError):
-            self.bounds.lon_min = 181
-
-    # Lon Max
-    def test_out_of_bounds_lon_max(self):
-        with self.assertRaises(ValueError):
-            self.bounds.lon_max = -181
-
-        with self.assertRaises(ValueError):
-            self.bounds.lon_max = 181
+        self.bounds_rectangular = Bounds(lat_min=-80, lat_max=80,                # Lats
+                             lon_min=-160, lon_max=160,               # Lons
+                             start=dt.datetime(2000, 1, 1),  # Start time
+                             end=dt.datetime(2002, 1, 1))  # End time
+        self.bounds_CORDEX = Bounds(boundary_type='CORDEX South Asia')
+        self.bounds_us_states = Bounds(boundary_type='us_states', us_states=['CA','NV','AZ'])
+        self.bounds_countries = Bounds(boundary_type='countries', countries=['United States','Canada','Mexico'])
+
+    def test_keywords(self):
+        self.assertEqual(self.bounds_rectangular.boundary_type, 'rectangular')
+        self.assertEqual(self.bounds_rectangular.lat_min, -80)
+        self.assertEqual(self.bounds_rectangular.lat_max, 80)
+        self.assertEqual(self.bounds_rectangular.lon_min, -160)
+        self.assertEqual(self.bounds_rectangular.lon_max, 160)
+        self.assertEqual(self.bounds_rectangular.start, dt.datetime(2000,1,1))
+        self.assertEqual(self.bounds_rectangular.end, dt.datetime(2002,1,1))
+
+        self.assertEqual(self.bounds_CORDEX.boundary_type, 'CORDEX South Asia')
+        self.assertEqual(self.bounds_CORDEX.lat_min, -15.23)
+        self.assertEqual(self.bounds_CORDEX.lat_max, 45.07)
+        self.assertEqual(self.bounds_CORDEX.lon_min, 19.88)
+        self.assertEqual(self.bounds_CORDEX.lon_max, 115.55)
+        
+        self.assertEqual(self.bounds_us_states.boundary_type, 'us_states')
+        
+        self.assertEqual(self.bounds_countries.boundary_type, 'countries')
 
     # Temporal tests
     def test_inverted_start_end_times(self):
         with self.assertRaises(ValueError):
-            self.bounds.start = dt.datetime(2003, 1, 1)
+            self.bounds_rectangular.start = dt.datetime(2003, 1, 1)
 
         with self.assertRaises(ValueError):
-            self.bounds.end = dt.datetime(1999, 1, 1)
+            self.bounds_rectangular.end = dt.datetime(1999, 1, 1)
 
     # Start tests
     def test_invalid_start(self):
         with self.assertRaises(ValueError):
-            self.bounds.start = "This is not a date time object"
+            self.bounds_rectangular.start = "This is not a date time object"
 
     # End tests
     def test_invalid_end(self):
         with self.assertRaises(ValueError):
-            self.bounds.end = "This is not a date time object"
+            self.bounds_rectangular.end = "This is not a date time object"
 
     # Start tests
     def test_none_value_start(self):
-        self.assertEqual(self.another_bounds.start, None)
+        self.assertEqual(self.bounds_CORDEX.start, None)
 
     # End tests
     def test_none_value_end(self):
-        self.assertEqual(self.another_bounds.end, None)
-
-    def test__str__(self):
-        lat_range = "({}, {})".format(self.bounds.lat_min, self.bounds.lat_max)
-        lon_range = "({}, {})".format(self.bounds.lon_min, self.bounds.lon_max)
-        temporal_boundaries = "({}, {})".format(self.bounds.start, self.bounds.end)
-
-        formatted_repr = (
-            "<Bounds - "
-            "lat-range: {}, "
-            "lon-range: {}, "
-            "temporal_boundaries: {}> "
-        )
-
-        output = formatted_repr.format(
-            lat_range,
-            lon_range,
-            temporal_boundaries,
-        )
-        self.assertEqual(str(self.bounds), output)
+        self.assertEqual(self.bounds_CORDEX.end, None)
 
 if __name__ == '__main__':
     unittest.main()

http://git-wip-us.apache.org/repos/asf/climate/blob/02dfdec6/ocw/tests/test_dataset_processor.py
----------------------------------------------------------------------
diff --git a/ocw/tests/test_dataset_processor.py b/ocw/tests/test_dataset_processor.py
index 627955a..0f8131e 100644
--- a/ocw/tests/test_dataset_processor.py
+++ b/ocw/tests/test_dataset_processor.py
@@ -431,22 +431,22 @@ class TestSubset(unittest.TestCase):
         self.name = 'foo'
 
         self.subregion = ds.Bounds(
-            -81, 81,
-            -161, 161,
-            datetime.datetime(2001, 1, 1),
-            datetime.datetime(2004, 1, 1)
+            lat_min=-81, lat_max=81,
+            lon_min=-161, lon_max=161,
+            start=datetime.datetime(2001, 1, 1),
+            end=datetime.datetime(2004, 1, 1)
         )
         self.non_exact_spatial_subregion = ds.Bounds(
-            -80.25, 80.5,
-            -160.25, 160.5,
-            datetime.datetime(2001, 1, 1),
-            datetime.datetime(2004, 1, 1)
+            lat_min=-80.25, lat_max=80.5,
+            lon_min=-160.25, lon_max=160.5,
+            start=datetime.datetime(2001, 1, 1),
+            end=datetime.datetime(2004, 1, 1)
         )
         self.non_exact_temporal_subregion = ds.Bounds(
-            -80.25, 80.5,
-            -160.25, 160.5,
-            datetime.datetime(2001, 1, 15),
-            datetime.datetime(2004, 2, 15)
+            lat_min=-80.25, lat_max=80.5,
+            lon_min=-160.25, lon_max=160.5,
+            start=datetime.datetime(2001, 1, 15),
+            end=datetime.datetime(2004, 2, 15)
         )
 
     def test_subset(self):
@@ -491,8 +491,8 @@ class TestSubset(unittest.TestCase):
 
     def test_subset_without_start_index(self):
         self.subregion = ds.Bounds(
-            -81, 81,
-            -161, 161,
+            lat_min=-81, lat_max=81,
+            lon_min=-161, lon_max=161,
         )
         subset = dp.subset(self.target_dataset, self.subregion)
         times = np.array([datetime.datetime(year, month, 1)
@@ -524,24 +524,24 @@ class TestSafeSubset(unittest.TestCase):
                                          name='foo')
 
         self.spatial_out_of_bounds = ds.Bounds(
-            -165, 165,
-            -180, 180,
-            datetime.datetime(2001, 1, 1),
-            datetime.datetime(2004, 1, 1)
+            lat_min=-65, lat_max=65,
+            lon_min=-180, lon_max=180,
+            start=datetime.datetime(2001, 1, 1),
+            end=datetime.datetime(2004, 1, 1)
         )
 
         self.temporal_out_of_bounds = ds.Bounds(
-            -40, 40,
-            -160.25, 160.5,
-            datetime.datetime(1999, 1, 15),
-            datetime.datetime(2222, 2, 15)
+            lat_min=-40, lat_max=40,
+            lon_min=-160.25, lon_max=160.5,
+            start=datetime.datetime(1999, 1, 15),
+            end=datetime.datetime(2222, 2, 15)
         )
 
         self.everything_out_of_bounds = ds.Bounds(
-            -165, 165,
-            -180, 180,
-            datetime.datetime(1999, 1, 15),
-            datetime.datetime(2222, 2, 15)
+            lat_min=-65, lat_max=65,
+            lon_min=-180, lon_max=180,
+            start=datetime.datetime(1999, 1, 15),
+            end=datetime.datetime(2222, 2, 15)
         )
 
     def test_partial_spatial_overlap(self):
@@ -556,7 +556,7 @@ class TestSafeSubset(unittest.TestCase):
     def test_partial_temporal_overlap(self):
         '''Ensure that safe_subset can handle out of bounds temporal values'''
         ds = dp.safe_subset(self.target_dataset, self.temporal_out_of_bounds)
-        temporal_bounds = ds.time_range()
+        temporal_bounds = ds.temporal_boundaries()
         start = datetime.datetime(2000, 1, 1)
         end = datetime.datetime(2009, 12, 1)
 
@@ -585,10 +585,10 @@ class TestFailingSubset(unittest.TestCase):
         self.target_dataset.lons = np.array(range(-179, 178, 2))
 
         self.subregion = ds.Bounds(
-            -81, 81,
-            -161, 161,
-            datetime.datetime(2001, 1, 1),
-            datetime.datetime(2004, 1, 1)
+            lat_min=-81, lat_max=81,
+            lon_min=-161, lon_max=161,
+            start=datetime.datetime(2001, 1, 1),
+            end=datetime.datetime(2004, 1, 1)
         )
 
     def test_out_of_dataset_bounds_lat_min(self):

http://git-wip-us.apache.org/repos/asf/climate/blob/02dfdec6/ocw/tests/test_evaluation.py
----------------------------------------------------------------------
diff --git a/ocw/tests/test_evaluation.py b/ocw/tests/test_evaluation.py
index e348fd9..9053e52 100644
--- a/ocw/tests/test_evaluation.py
+++ b/ocw/tests/test_evaluation.py
@@ -98,9 +98,9 @@ class TestEvaluation(unittest.TestCase):
 
     def test_valid_subregion(self):
         bound = Bounds(
-            -10, 10,
-            -20, 20,
-            dt.datetime(2000, 1, 1), dt.datetime(2001, 1, 1))
+            lat_min=-10, lat_max=10,
+            lon_min=-20, lon_max=20,
+            start=dt.datetime(2000, 1, 1), end=dt.datetime(2001, 1, 1))
 
         self.eval.subregions = [bound, bound]
         self.assertEquals(len(self.eval.subregions), 2)
@@ -198,9 +198,9 @@ class TestEvaluation(unittest.TestCase):
 
     def test_subregion_result_shape(self):
         bound = Bounds(
-            10, 18,
-            100, 108,
-            dt.datetime(2000, 1, 1), dt.datetime(2000, 3, 1))
+            lat_min=10, lat_max=18,
+            lon_min=100, lon_max=108,
+            start=dt.datetime(2000, 1, 1), end=dt.datetime(2000, 3, 1))
 
         bias_eval = Evaluation(
             self.test_dataset,
@@ -223,9 +223,9 @@ class TestEvaluation(unittest.TestCase):
 
     def test_subregion_unary_result_shape(self):
         bound = Bounds(
-            10, 18,
-            100, 108,
-            dt.datetime(2000, 1, 1), dt.datetime(2000, 3, 1))
+            lat_min=10, lat_max=18,
+            lon_min=100, lon_max=108,
+            start=dt.datetime(2000, 1, 1), end=dt.datetime(2000, 3, 1))
 
         new_eval = Evaluation(
             self.test_dataset,

http://git-wip-us.apache.org/repos/asf/climate/blob/02dfdec6/ocw_config_runner/tests/test_config_writer.py
----------------------------------------------------------------------
diff --git a/ocw_config_runner/tests/test_config_writer.py b/ocw_config_runner/tests/test_config_writer.py
index ed22417..ceaa2b1 100644
--- a/ocw_config_runner/tests/test_config_writer.py
+++ b/ocw_config_runner/tests/test_config_writer.py
@@ -652,8 +652,8 @@ class FullExportTest(unittest.TestCase):
         )
 
         self.subregions = [
-            Bounds(-10, 10, -20, 20),
-            Bounds(-5, 5, -15, 15)
+            Bounds(lat_min=-10, lat_max=10, lon_min=-20, lon_max=20),
+            Bounds(lat_min=-5, lat_max=5, lon_min=-15, lon_max=15)
         ]
 
         self.evaluation = Evaluation(


Mime
View raw message