| 1 | # Datasets/HYCOM.py - Grids representing HYCOM datasets.
|
|---|
| 2 | #
|
|---|
| 3 | # Copyright (C) 2010 Jason J. Roberts
|
|---|
| 4 | #
|
|---|
| 5 | # This program is free software; you can redistribute it and/or
|
|---|
| 6 | # modify it under the terms of the GNU General Public License
|
|---|
| 7 | # as published by the Free Software Foundation; either version 2
|
|---|
| 8 | # of the License, or (at your option) any later version.
|
|---|
| 9 | #
|
|---|
| 10 | # This program is distributed in the hope that it will be useful,
|
|---|
| 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|---|
| 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|---|
| 13 | # GNU General Public License (available in the file LICENSE.TXT)
|
|---|
| 14 | # for more details.
|
|---|
| 15 | #
|
|---|
| 16 | # You should have received a copy of the GNU General Public License
|
|---|
| 17 | # along with this program; if not, write to the Free Software
|
|---|
| 18 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|---|
| 19 |
|
|---|
| 20 | import datetime
|
|---|
| 21 |
|
|---|
| 22 | from GeoEco.Datasets import Dataset, QueryableAttribute, Grid
|
|---|
| 23 | from GeoEco.Datasets.OPeNDAP import THREDDSCatalog, OPeNDAPURL, OPeNDAPGrid
|
|---|
| 24 | from GeoEco.Datasets.Virtual import TimeSeriesGridStack, GridSliceCollection, MaskedGrid, ClippedGrid, RotatedGlobalGrid
|
|---|
| 25 | from GeoEco.DynamicDocString import DynamicDocString
|
|---|
| 26 | from GeoEco.Internationalization import _
|
|---|
| 27 | from GeoEco.Types import *
|
|---|
| 28 |
|
|---|
| 29 |
|
|---|
| 30 | class _HYCOMGridGOMl0043D(OPeNDAPGrid):
|
|---|
| 31 | __doc__ = DynamicDocString()
|
|---|
| 32 |
|
|---|
| 33 | def __init__(self, url, variableName, timeout, cacheDirectory):
|
|---|
| 34 | self._CachedTCenterCoords = None
|
|---|
| 35 | super(_HYCOMGridGOMl0043D, self).__init__(OPeNDAPURL(url, timeout=timeout, cacheDirectory=cacheDirectory),
|
|---|
| 36 | variableName,
|
|---|
| 37 | 'Grid',
|
|---|
| 38 | lazyPropertyValues={'SpatialReference': Dataset.ConvertSpatialReference('proj4', '+proj=merc +ellps=sphere +a=6371001 +b=6371001', 'obj'),
|
|---|
| 39 | 'Dimensions': 'tyx',
|
|---|
| 40 | 'CoordDependencies': (None, None, None),
|
|---|
| 41 | 'CoordIncrements': (None, 4447.7949713872476, 4447.7949713872476), # t increment is None because, sadly, HYCOM omits slices when their system occasionally fails to generate data for a day
|
|---|
| 42 | 'TCornerCoordType': 'center',
|
|---|
| 43 | 'PhysicalDimensions': 'tyx',
|
|---|
| 44 | 'PhysicalDimensionsFlipped': (False, False, False),
|
|---|
| 45 | 'UnscaledDataType': 'float32',
|
|---|
| 46 | 'UnscaledNoDataValue': 1.2676506002282294e+030,
|
|---|
| 47 | 'ScalingFunction': None})
|
|---|
| 48 |
|
|---|
| 49 | def _GetLazyPropertyPhysicalValue(self, name):
|
|---|
| 50 | if name == 'CornerCoords':
|
|---|
| 51 | return (self._GetCoords('t', 0, [0], [0], -0.5), 2045985.6431758059, -10897097.679898757) # Center of lower-left cell, in degrees: 98.0 W, 18.091648101806641 N
|
|---|
| 52 | return super(_HYCOMGridGOMl0043D, self)._GetLazyPropertyPhysicalValue(name)
|
|---|
| 53 |
|
|---|
| 54 | def _GetCoords(self, coord, coordNum, slices, sliceDims, fixedIncrementOffset):
|
|---|
| 55 | if coord != 't':
|
|---|
| 56 | raise RuntimeError(_('_HYCOMGridGOMl0043D._GetCoords() called with coord == \'%(coord)s\'. This should never happen. Please contact the author of this tool for assistance.') % {u'coord': coord})
|
|---|
| 57 | if self._CachedTCenterCoords is None:
|
|---|
| 58 | import numpy
|
|---|
| 59 | self._CachedTCenterCoords = numpy.array(map(lambda days: datetime.timedelta(days) + datetime.datetime(1900, 12, 31), list(self._GetOPeNDAPVariable()['MT'][:])), dtype='object')
|
|---|
| 60 | if slices is None:
|
|---|
| 61 | result = self._CachedTCenterCoords.copy()
|
|---|
| 62 | else:
|
|---|
| 63 | result = self._CachedTCenterCoords.__getitem__(*slices)
|
|---|
| 64 | if fixedIncrementOffset != 0:
|
|---|
| 65 | result += datetime.timedelta(fixedIncrementOffset)
|
|---|
| 66 | return result
|
|---|
| 67 |
|
|---|
| 68 |
|
|---|
| 69 | class HYCOMGOMl0043D(Grid):
|
|---|
| 70 | __doc__ = DynamicDocString()
|
|---|
| 71 |
|
|---|
| 72 | def _GetVariableName(self):
|
|---|
| 73 | return self._VariableName
|
|---|
| 74 |
|
|---|
| 75 | VariableName = property(_GetVariableName, doc=DynamicDocString())
|
|---|
| 76 |
|
|---|
| 77 | def _GetStartYear(self):
|
|---|
| 78 | return self._StartYear
|
|---|
| 79 |
|
|---|
| 80 | StartYear = property(_GetStartYear, doc=DynamicDocString())
|
|---|
| 81 |
|
|---|
| 82 | def _GetEndYear(self):
|
|---|
| 83 | return self._EndYear
|
|---|
| 84 |
|
|---|
| 85 | EndYear = property(_GetEndYear, doc=DynamicDocString())
|
|---|
| 86 |
|
|---|
| 87 | def __init__(self, variableName, startYear=None, endYear=None, timeout=600, cacheDirectory=None):
|
|---|
| 88 | self.__doc__.Obj.ValidateMethodInvocation()
|
|---|
| 89 |
|
|---|
| 90 | # Perform additional validation
|
|---|
| 91 |
|
|---|
| 92 | if startYear is None:
|
|---|
| 93 | startYear = 2003
|
|---|
| 94 | elif startYear > (datetime.datetime.now() + datetime.timedelta(5)).year:
|
|---|
| 95 | raise ValueError(_(u'The start year must be less than or equal to %(max)i.') % {u'max': (datetime.datetime.now() + datetime.timedelta(5)).year})
|
|---|
| 96 |
|
|---|
| 97 | if endYear is not None and endYear < startYear:
|
|---|
| 98 | raise ValueError(_(u'The end year must be greater than or equal to the start year. If the start year is not specified, the end year must be greater than or equal to 2003.'))
|
|---|
| 99 |
|
|---|
| 100 | # Initialize our properties.
|
|---|
| 101 |
|
|---|
| 102 | self._VariableName = variableName
|
|---|
| 103 | self._StartYear = startYear
|
|---|
| 104 | self._EndYear = endYear
|
|---|
| 105 | self._Timeout = timeout
|
|---|
| 106 | self._CacheDirectory = cacheDirectory
|
|---|
| 107 | self._DisplayName = _(u'%(name)s grid of the HYCOM + NCODA Gulf of Mexico 1/25 degree Analysis (GOMl0.04) aggregated OPeNDAP datasets') % {u'name': variableName}
|
|---|
| 108 | self._OpenURL = None
|
|---|
| 109 | self._OpenGrid = None
|
|---|
| 110 |
|
|---|
| 111 | # Initialize the base class.
|
|---|
| 112 |
|
|---|
| 113 | super(HYCOMGOMl0043D, self).__init__(queryableAttributes=(QueryableAttribute(u'VariableName', _(u'Dataset variable'), UnicodeStringTypeMetadata(allowedValues=[u'emp', u'mld', u'mlp', u'qtot', u'ssh', u'surface_salinity_trend', u'surface_temperature_trend'], makeLowercase=True)),),
|
|---|
| 114 | queryableAttributeValues={u'VariableName': variableName},
|
|---|
| 115 | lazyPropertyValues={'SpatialReference': Dataset.ConvertSpatialReference('proj4', '+proj=merc +ellps=sphere +a=6371001 +b=6371001', 'obj'),
|
|---|
| 116 | 'Dimensions': u'tyx',
|
|---|
| 117 | 'CoordDependencies': (None, None, None),
|
|---|
| 118 | 'CoordIncrements': (1.0, 4447.7949713872476, 4447.7949713872476),
|
|---|
| 119 | 'TIncrementUnit': u'day',
|
|---|
| 120 | 'TSemiRegularity': None,
|
|---|
| 121 | 'TCountPerSemiRegularPeriod': None,
|
|---|
| 122 | 'TCornerCoordType': u'center',
|
|---|
| 123 | 'CornerCoords': (datetime.datetime(startYear, 1, 1), 2045985.6431758059, -10897097.679898757), # Center of lower-left cell, in degrees: 98.0 W, 18.091648101806641 N
|
|---|
| 124 | 'PhysicalDimensions': u'tyx',
|
|---|
| 125 | 'PhysicalDimensionsFlipped': (False, False, False),
|
|---|
| 126 | 'UnscaledDataType': u'float32',
|
|---|
| 127 | 'UnscaledNoDataValue': 1.2676506002282294e+030,
|
|---|
| 128 | 'ScalingFunction': None})
|
|---|
| 129 |
|
|---|
| 130 | def _GetDisplayName(self):
|
|---|
| 131 | return self._DisplayName
|
|---|
| 132 |
|
|---|
| 133 | def _GetLazyPropertyPhysicalValue(self, name):
|
|---|
| 134 |
|
|---|
| 135 | # The only property that we can retrieve here is the shape.
|
|---|
| 136 | # For the t axis, add the number of days in the years leading
|
|---|
| 137 | # up to the final year to the number of days available from
|
|---|
| 138 | # HYCOM in the final year. For the x and y axes, just use
|
|---|
| 139 | # hardcoded values.
|
|---|
| 140 |
|
|---|
| 141 | if name == 'Shape':
|
|---|
| 142 | if self._EndYear is not None and self._EndYear < datetime.datetime.now().year:
|
|---|
| 143 | return ((datetime.datetime(self._EndYear + 1, 1, 1) - datetime.datetime(self._StartYear, 1, 1)).days, 385, 541)
|
|---|
| 144 |
|
|---|
| 145 | endYearGrid = _HYCOMGridGOMl0043D('http://tds.hycom.org/thredds/dodsC/GOMl0.04/expt_30.1/%i' % datetime.datetime.now().year, self._VariableName, self._Timeout, self._CacheDirectory)
|
|---|
| 146 | endDay = endYearGrid.CenterCoords['t', -1]
|
|---|
| 147 |
|
|---|
| 148 | if endDay.month == 12 and endDay.day == 31:
|
|---|
| 149 | endYearGrid = _HYCOMGridGOMl0043D('http://tds.hycom.org/thredds/dodsC/GOMl0.04/expt_30.1/%i' % datetime.datetime.now().year + 1, self._VariableName, self._Timeout, self._CacheDirectory)
|
|---|
| 150 | endDay = endYearGrid.CenterCoords['t', -1]
|
|---|
| 151 |
|
|---|
| 152 | return ((endDay - datetime.datetime(self._StartYear, 1, 1)).days + 1, 385, 541)
|
|---|
| 153 |
|
|---|
| 154 | raise AttributeError(_(u'\'%(class)s\' object has no lazy property named \'%(name)s\'') % {u'class': self.__class__.__name__, u'name': name})
|
|---|
| 155 |
|
|---|
| 156 | def _ReadNumpyArray(self, sliceList):
|
|---|
| 157 |
|
|---|
| 158 | # For many OPeNDAP datasets, we would be able to request the
|
|---|
| 159 | # entire 3D slab directly. This won't work for the HYCOM
|
|---|
| 160 | # GOMl0.04 dataset, for two reasons: 1) The dataset is split
|
|---|
| 161 | # OPeNDAP URLs for each year, and 2) HYCOM omits slices when
|
|---|
| 162 | # their system occasionally fails to generate data for a day,
|
|---|
| 163 | # so most years do not have a full 365 (or 366) slices. To
|
|---|
| 164 | # deal with this, we have to loop over the requested range of
|
|---|
| 165 | # time indices and issue OPeNDAP requests to the proper URLs
|
|---|
| 166 | # and per-URL time indices.
|
|---|
| 167 | #
|
|---|
| 168 | # First, allocate the array we will return. We'll populate
|
|---|
| 169 | # this as we go along. (I prefer this approach rather than
|
|---|
| 170 | # growing an array through concatenation because it avoids
|
|---|
| 171 | # repeatedly allocating and copying memory.)
|
|---|
| 172 |
|
|---|
| 173 | import numpy
|
|---|
| 174 | result = numpy.zeros((sliceList[0].stop - sliceList[0].start, sliceList[1].stop - sliceList[1].start, sliceList[2].stop - sliceList[2].start), dtype=str(self.UnscaledDataType))
|
|---|
| 175 |
|
|---|
| 176 | # Loop over the requested t indices, populating the result
|
|---|
| 177 | # array.
|
|---|
| 178 |
|
|---|
| 179 | i = 0
|
|---|
| 180 | tCoords = self.CenterCoords['t', sliceList[0]]
|
|---|
| 181 |
|
|---|
| 182 | while i < len(tCoords):
|
|---|
| 183 |
|
|---|
| 184 | # Open the _HYCOMGridGOMl0043D for the next block of t
|
|---|
| 185 | # coordinates. These grids are 1 year long, except in 2010
|
|---|
| 186 | # when HYCOM switched to an improved configuration after
|
|---|
| 187 | # five months.
|
|---|
| 188 |
|
|---|
| 189 | if tCoords[i] < datetime.datetime(2010, 6, 1):
|
|---|
| 190 | url = 'http://tds.hycom.org/thredds/dodsC/GOMl0.04/expt_20.1/%i' % tCoords[i].year
|
|---|
| 191 | else:
|
|---|
| 192 | url = 'http://tds.hycom.org/thredds/dodsC/GOMl0.04/expt_30.1/%i' % tCoords[i].year
|
|---|
| 193 |
|
|---|
| 194 | if self._OpenURL != url:
|
|---|
| 195 | self._OpenGrid = _HYCOMGridGOMl0043D(url, self._VariableName, self._Timeout, self._CacheDirectory)
|
|---|
| 196 | self._OpenURL = url
|
|---|
| 197 |
|
|---|
| 198 | if tCoords[i] >= datetime.datetime(2010, 1, 1) and tCoords[i] <= datetime.datetime(2010, 5, 31):
|
|---|
| 199 | lastDayOfDataset = datetime.datetime(2010, 5, 31)
|
|---|
| 200 | else:
|
|---|
| 201 | lastDayOfDataset = datetime.datetime(tCoords[i].year, 12, 31)
|
|---|
| 202 |
|
|---|
| 203 | # Read the necessary data from this grid as one 3D slab.
|
|---|
| 204 |
|
|---|
| 205 | import bisect
|
|---|
| 206 |
|
|---|
| 207 | gridTStart = bisect.bisect_left(self._OpenGrid.CenterCoords['t'].tolist(), tCoords[i])
|
|---|
| 208 | gridTStop = bisect.bisect_right(self._OpenGrid.CenterCoords['t'].tolist(), tCoords[-1])
|
|---|
| 209 | gridTCoords = self._OpenGrid.CenterCoords['t', gridTStart:gridTStop]
|
|---|
| 210 | data = self._OpenGrid.UnscaledData.__getitem__((slice(gridTStart, gridTStop), sliceList[1], sliceList[2]))
|
|---|
| 211 |
|
|---|
| 212 | # Iterate through the t indices, copying out time slices
|
|---|
| 213 | # when they are available, otherwise setting slices to the
|
|---|
| 214 | # UnscaledNoDataValue.
|
|---|
| 215 |
|
|---|
| 216 | j = 0
|
|---|
| 217 |
|
|---|
| 218 | while i < len(tCoords) and tCoords[i] <= lastDayOfDataset:
|
|---|
| 219 | if j < len(gridTCoords) and gridTCoords[j] == tCoords[i]:
|
|---|
| 220 | result[i] = data[j]
|
|---|
| 221 | j += 1
|
|---|
| 222 | else:
|
|---|
| 223 | result[i] = self.UnscaledNoDataValue
|
|---|
| 224 | i += 1
|
|---|
| 225 |
|
|---|
| 226 | # Return successfully.
|
|---|
| 227 |
|
|---|
| 228 | return result, self.UnscaledNoDataValue
|
|---|
| 229 |
|
|---|
| 230 | @classmethod
|
|---|
| 231 | def CreateArcGISRasters(cls, variableName,
|
|---|
| 232 | outputWorkspace, mode=u'add', rasterNameExpressions=['%(VariableName)s', '%%Y', '%(VariableName)s_%%Y%%j.img'],
|
|---|
| 233 | spatialExtent=None, linearUnit=u'Degrees', startDate=None, endDate=None,
|
|---|
| 234 | timeout=600, cacheDirectory=None,
|
|---|
| 235 | calculateStatistics=True, buildPyramids=False):
|
|---|
| 236 | cls.__doc__.Obj.ValidateMethodInvocation()
|
|---|
| 237 |
|
|---|
| 238 | # Construct a HYCOMGOMl0043D and clip it if requested.
|
|---|
| 239 |
|
|---|
| 240 | if startDate is not None:
|
|---|
| 241 | startYear = startDate.year
|
|---|
| 242 | else:
|
|---|
| 243 | startYear = None
|
|---|
| 244 |
|
|---|
| 245 | if endDate is not None:
|
|---|
| 246 | endYear = endDate.year
|
|---|
| 247 | else:
|
|---|
| 248 | endYear = None
|
|---|
| 249 |
|
|---|
| 250 | grid = HYCOMGOMl0043D(variableName, startYear=startYear, endYear=endYear, timeout=timeout, cacheDirectory=cacheDirectory)
|
|---|
| 251 |
|
|---|
| 252 | xMin, yMin, xMax, yMax = None, None, None, None
|
|---|
| 253 | if spatialExtent is not None:
|
|---|
| 254 | from GeoEco.Types import EnvelopeTypeMetadata
|
|---|
| 255 | xMin, yMin, xMax, yMax = EnvelopeTypeMetadata.ParseFromArcGISString(spatialExtent)
|
|---|
| 256 |
|
|---|
| 257 | # TODO: Project the spatialExtent, if necessary.
|
|---|
| 258 |
|
|---|
| 259 | cls._LogWarning(_(u'The HYCOM OPeNDAP server often requires five to ten minutes to return the first time slice. Please be patient. This tool cannot be cancelled until the first one is returned. After the first one is returned, the rest will go much faster and you will be able to cancel the tool, if desired. If this tool fails with to a timeout error, increase the timeout value and try again.'))
|
|---|
| 260 |
|
|---|
| 261 | if spatialExtent is not None or startDate is not None or endDate is not None:
|
|---|
| 262 | grid = ClippedGrid(grid, u'Map coordinates', xMin=xMin, xMax=xMax, yMin=yMin, yMax=yMax, tMin=startDate, tMax=endDate)
|
|---|
| 263 |
|
|---|
| 264 | # Construct an ArcGISWorkspace instance and import time slices
|
|---|
| 265 | # from the HYCOMGOMl0043D instance.
|
|---|
| 266 |
|
|---|
| 267 | from GeoEco.Datasets.ArcGIS import ArcGISWorkspace, ArcGISRaster
|
|---|
| 268 |
|
|---|
| 269 | workspace = ArcGISWorkspace(outputWorkspace,
|
|---|
| 270 | ArcGISRaster,
|
|---|
| 271 | pathCreationExpressions=rasterNameExpressions,
|
|---|
| 272 | cacheTree=True,
|
|---|
| 273 | queryableAttributes=(QueryableAttribute(u'VariableName', _(u'Variable'), UnicodeStringTypeMetadata(allowedValues=[u'emp', u'mld', u'mlp', u'qtot', u'ssh', u'surface_salinity_trend', u'surface_temperature_trend'], makeLowercase=True)),
|
|---|
| 274 | QueryableAttribute(u'DateTime', _(u'Date'), DateTimeTypeMetadata())))
|
|---|
| 275 |
|
|---|
| 276 | workspace.ImportDatasets(GridSliceCollection(grid, tQACoordType=u'center').QueryDatasets(), mode, calculateStatistics=calculateStatistics, buildPyramids=buildPyramids)
|
|---|
| 277 |
|
|---|
| 278 | # Return successfully.
|
|---|
| 279 |
|
|---|
| 280 | return outputWorkspace
|
|---|
| 281 |
|
|---|
| 282 |
|
|---|
| 283 | class _HYCOMGridGOMl0044D(OPeNDAPGrid):
|
|---|
| 284 | __doc__ = DynamicDocString()
|
|---|
| 285 |
|
|---|
| 286 | def __init__(self, url, variableName, timeout, cacheDirectory):
|
|---|
| 287 | self._CachedTCenterCoords = None
|
|---|
| 288 | super(_HYCOMGridGOMl0044D, self).__init__(OPeNDAPURL(url, timeout=timeout, cacheDirectory=cacheDirectory),
|
|---|
| 289 | variableName,
|
|---|
| 290 | 'Grid',
|
|---|
| 291 | lazyPropertyValues={'SpatialReference': Dataset.ConvertSpatialReference('proj4', '+proj=merc +ellps=sphere +a=6371001 +b=6371001', 'obj'),
|
|---|
| 292 | 'Dimensions': 'tzyx',
|
|---|
| 293 | 'CoordDependencies': (None, None, None, None),
|
|---|
| 294 | 'CoordIncrements': (None, None, 4447.7949713872476, 4447.7949713872476), # t increment is None because, sadly, HYCOM omits slices when their system occasionally fails to generate data for a day
|
|---|
| 295 | 'TCornerCoordType': 'center',
|
|---|
| 296 | 'PhysicalDimensions': 'tzyx',
|
|---|
| 297 | 'PhysicalDimensionsFlipped': (False, False, False, False),
|
|---|
| 298 | 'UnscaledDataType': 'float32',
|
|---|
| 299 | 'UnscaledNoDataValue': 1.2676506002282294e+030,
|
|---|
| 300 | 'ScalingFunction': None})
|
|---|
| 301 |
|
|---|
| 302 | def _GetLazyPropertyPhysicalValue(self, name):
|
|---|
| 303 | if name == 'CornerCoords':
|
|---|
| 304 | return (self._GetCoords('t', 0, [0], [0], -0.5), 0.0, 2045985.6431758059, -10897097.679898757) # Center of lower-left cell, in degrees: 98.0 W, 18.091648101806641 N
|
|---|
| 305 | return super(_HYCOMGridGOMl0044D, self)._GetLazyPropertyPhysicalValue(name)
|
|---|
| 306 |
|
|---|
| 307 | def _GetCoords(self, coord, coordNum, slices, sliceDims, fixedIncrementOffset):
|
|---|
| 308 | if coord not in ['t', 'z']:
|
|---|
| 309 | raise RuntimeError(_('_HYCOMGridGOMl0044D._GetCoords() called with coord == \'%(coord)s\'. This should never happen. Please contact the author of this tool for assistance.') % {u'coord': coord})
|
|---|
| 310 |
|
|---|
| 311 | if coord == 't':
|
|---|
| 312 | if self._CachedTCenterCoords is None:
|
|---|
| 313 | import numpy
|
|---|
| 314 | self._CachedTCenterCoords = numpy.array(map(lambda days: datetime.timedelta(days) + datetime.datetime(1900, 12, 31), list(self._GetOPeNDAPVariable()['MT'][:])), dtype='object')
|
|---|
| 315 | if slices is None:
|
|---|
| 316 | result = self._CachedTCenterCoords.copy()
|
|---|
| 317 | else:
|
|---|
| 318 | result = self._CachedTCenterCoords.__getitem__(*slices)
|
|---|
| 319 | if fixedIncrementOffset != 0:
|
|---|
| 320 | result += datetime.timedelta(fixedIncrementOffset)
|
|---|
| 321 | return result
|
|---|
| 322 |
|
|---|
| 323 | zCoords = [0.0, 5.0, 10.0, 15.0, 20.0, 25.0, 30.0, 40.0, 50.0, 60.0, 70.0, 80.0, 90.0, 100.0, 125.0, 150.0, 200.0, 250.0, 300.0, 400.0, 500.0, 600.0, 700.0, 800.0, 900.0, 1000.0, 1100.0, 1200.0, 1300.0, 1400.0, 1500.0, 1750.0, 2000.0, 2500.0, 3000.0, 3500.0, 4000.0, 4500.0, 5000.0, 5500.0]
|
|---|
| 324 | if fixedIncrementOffset == -0.5:
|
|---|
| 325 | zCoords = [0.0] + map(lambda a, b: (a+b)/2., zCoords[:-1], zCoords[1:])
|
|---|
| 326 | elif fixedIncrementOffset == 0.5:
|
|---|
| 327 | zCoords = map(lambda a, b: (a+b)/2., zCoords[:-1], zCoords[1:]) + [11000.0]
|
|---|
| 328 | return numpy.array(zCoords)
|
|---|
| 329 |
|
|---|
| 330 |
|
|---|
| 331 | class HYCOMGOMl0044D(Grid):
|
|---|
| 332 | __doc__ = DynamicDocString()
|
|---|
| 333 |
|
|---|
| 334 | def _GetVariableName(self):
|
|---|
| 335 | return self._VariableName
|
|---|
| 336 |
|
|---|
| 337 | VariableName = property(_GetVariableName, doc=DynamicDocString())
|
|---|
| 338 |
|
|---|
| 339 | def _GetStartYear(self):
|
|---|
| 340 | return self._StartYear
|
|---|
| 341 |
|
|---|
| 342 | StartYear = property(_GetStartYear, doc=DynamicDocString())
|
|---|
| 343 |
|
|---|
| 344 | def _GetEndYear(self):
|
|---|
| 345 | return self._EndYear
|
|---|
| 346 |
|
|---|
| 347 | EndYear = property(_GetEndYear, doc=DynamicDocString())
|
|---|
| 348 |
|
|---|
| 349 | def __init__(self, variableName, startYear=None, endYear=None, timeout=600, cacheDirectory=None):
|
|---|
| 350 | self.__doc__.Obj.ValidateMethodInvocation()
|
|---|
| 351 |
|
|---|
| 352 | # Perform additional validation
|
|---|
| 353 |
|
|---|
| 354 | if startYear is None:
|
|---|
| 355 | startYear = 2003
|
|---|
| 356 | elif startYear > (datetime.datetime.now() + datetime.timedelta(5)).year:
|
|---|
| 357 | raise ValueError(_(u'The start year must be less than or equal to %(max)i.') % {u'max': (datetime.datetime.now() + datetime.timedelta(5)).year})
|
|---|
| 358 |
|
|---|
| 359 | if endYear is not None and endYear < startYear:
|
|---|
| 360 | raise ValueError(_(u'The end year must be greater than or equal to the start year. If the start year is not specified, the end year must be greater than or equal to 2003.'))
|
|---|
| 361 |
|
|---|
| 362 | # Initialize our properties.
|
|---|
| 363 |
|
|---|
| 364 | self._VariableName = variableName
|
|---|
| 365 | self._StartYear = startYear
|
|---|
| 366 | self._EndYear = endYear
|
|---|
| 367 | self._Timeout = timeout
|
|---|
| 368 | self._CacheDirectory = cacheDirectory
|
|---|
| 369 | self._DisplayName = _(u'%(name)s grid of the HYCOM + NCODA Gulf of Mexico 1/25 degree Analysis (GOMl0.04) aggregated OPeNDAP datasets') % {u'name': variableName}
|
|---|
| 370 | self._OpenURL = None
|
|---|
| 371 | self._OpenGrid = None
|
|---|
| 372 |
|
|---|
| 373 | # Initialize the base class.
|
|---|
| 374 |
|
|---|
| 375 | super(HYCOMGOMl0044D, self).__init__(queryableAttributes=(QueryableAttribute(u'VariableName', _(u'Dataset variable'), UnicodeStringTypeMetadata(allowedValues=[u'salinity', u'temperature', u'u', u'v', u'w'], makeLowercase=True)),),
|
|---|
| 376 | queryableAttributeValues={u'VariableName': variableName},
|
|---|
| 377 | lazyPropertyValues={'SpatialReference': Dataset.ConvertSpatialReference('proj4', '+proj=merc +ellps=sphere +a=6371001 +b=6371001', 'obj'),
|
|---|
| 378 | 'Dimensions': u'tzyx',
|
|---|
| 379 | 'CoordDependencies': (None, None, None, None),
|
|---|
| 380 | 'CoordIncrements': (1.0, None, 4447.7949713872476, 4447.7949713872476),
|
|---|
| 381 | 'TIncrementUnit': u'day',
|
|---|
| 382 | 'TSemiRegularity': None,
|
|---|
| 383 | 'TCountPerSemiRegularPeriod': None,
|
|---|
| 384 | 'TCornerCoordType': u'center',
|
|---|
| 385 | 'CornerCoords': (datetime.datetime(startYear, 1, 1), 0.0, 2045985.6431758059, -10897097.679898757), # Center of lower-left cell, in degrees: 98.0 W, 18.091648101806641 N
|
|---|
| 386 | 'PhysicalDimensions': u'txyx',
|
|---|
| 387 | 'PhysicalDimensionsFlipped': (False, False, False, False),
|
|---|
| 388 | 'UnscaledDataType': u'float32',
|
|---|
| 389 | 'UnscaledNoDataValue': 1.2676506002282294e+030,
|
|---|
| 390 | 'ScalingFunction': None})
|
|---|
| 391 |
|
|---|
| 392 | def _GetDisplayName(self):
|
|---|
| 393 | return self._DisplayName
|
|---|
| 394 |
|
|---|
| 395 | def _GetLazyPropertyPhysicalValue(self, name):
|
|---|
| 396 |
|
|---|
| 397 | # The only property that we can retrieve here is the shape.
|
|---|
| 398 | # For the t axis, add the number of days in the years leading
|
|---|
| 399 | # up to the final year to the number of days available from
|
|---|
| 400 | # HYCOM in the final year. For the x and y axes, just use
|
|---|
| 401 | # hardcoded values.
|
|---|
| 402 |
|
|---|
| 403 | if name == 'Shape':
|
|---|
| 404 | if self._EndYear is not None and self._EndYear < datetime.datetime.now().year:
|
|---|
| 405 | return ((datetime.datetime(self._EndYear + 1, 1, 1) - datetime.datetime(self._StartYear, 1, 1)).days, 40, 385, 541)
|
|---|
| 406 |
|
|---|
| 407 | endYearGrid = _HYCOMGridGOMl0044D('http://tds.hycom.org/thredds/dodsC/GOMl0.04/expt_30.1/%i' % datetime.datetime.now().year, self._VariableName, self._Timeout, self._CacheDirectory)
|
|---|
| 408 | endDay = endYearGrid.CenterCoords['t', -1]
|
|---|
| 409 |
|
|---|
| 410 | if endDay.month == 12 and endDay.day == 31:
|
|---|
| 411 | endYearGrid = _HYCOMGridGOMl0044D('http://tds.hycom.org/thredds/dodsC/GOMl0.04/expt_30.1/%i' % datetime.datetime.now().year + 1, self._VariableName, self._Timeout, self._CacheDirectory)
|
|---|
| 412 | endDay = endYearGrid.CenterCoords['t', -1]
|
|---|
| 413 |
|
|---|
| 414 | return ((endDay - datetime.datetime(self._StartYear, 1, 1)).days + 1, 40, 385, 541)
|
|---|
| 415 |
|
|---|
| 416 | raise AttributeError(_(u'\'%(class)s\' object has no lazy property named \'%(name)s\'') % {u'class': self.__class__.__name__, u'name': name})
|
|---|
| 417 |
|
|---|
| 418 | def _GetCoords(self, coord, coordNum, slices, sliceDims, fixedIncrementOffset):
|
|---|
| 419 | if coord == 'z':
|
|---|
| 420 | raise RuntimeError(_('HYCOMGOMl0044D._GetCoords() called with coord == \'%(coord)s\'. This should never happen. Please contact the author of this tool for assistance.') % {u'coord': coord})
|
|---|
| 421 | zCoords = [0.0, 5.0, 10.0, 15.0, 20.0, 25.0, 30.0, 40.0, 50.0, 60.0, 70.0, 80.0, 90.0, 100.0, 125.0, 150.0, 200.0, 250.0, 300.0, 400.0, 500.0, 600.0, 700.0, 800.0, 900.0, 1000.0, 1100.0, 1200.0, 1300.0, 1400.0, 1500.0, 1750.0, 2000.0, 2500.0, 3000.0, 3500.0, 4000.0, 4500.0, 5000.0, 5500.0]
|
|---|
| 422 | if fixedIncrementOffset == -0.5:
|
|---|
| 423 | zCoords = [0.0] + map(lambda a, b: (a+b)/2., zCoords[:-1], zCoords[1:])
|
|---|
| 424 | elif fixedIncrementOffset == 0.5:
|
|---|
| 425 | zCoords = map(lambda a, b: (a+b)/2., zCoords[:-1], zCoords[1:]) + [11000.0]
|
|---|
| 426 | return numpy.array(zCoords)
|
|---|
| 427 |
|
|---|
| 428 | def _ReadNumpyArray(self, sliceList):
|
|---|
| 429 |
|
|---|
| 430 | # For many OPeNDAP datasets, we would be able to request the
|
|---|
| 431 | # entire 4D slab directly. This won't work for the HYCOM
|
|---|
| 432 | # GOMl0.04 dataset, for two reasons: 1) The dataset is split
|
|---|
| 433 | # OPeNDAP URLs for each year, and 2) HYCOM omits slices when
|
|---|
| 434 | # their system occasionally fails to generate data for a day,
|
|---|
| 435 | # so most years do not have a full 365 (or 366) slices. To
|
|---|
| 436 | # deal with this, we have to loop over the requested range of
|
|---|
| 437 | # time indices and issue OPeNDAP requests to the proper URLs
|
|---|
| 438 | # and per-URL time indices.
|
|---|
| 439 | #
|
|---|
| 440 | # First, allocate the array we will return. We'll populate
|
|---|
| 441 | # this as we go along. (I prefer this approach rather than
|
|---|
| 442 | # growing an array through concatenation because it avoids
|
|---|
| 443 | # repeatedly allocating and copying memory.)
|
|---|
| 444 |
|
|---|
| 445 | import numpy
|
|---|
| 446 | result = numpy.zeros((sliceList[0].stop - sliceList[0].start, sliceList[1].stop - sliceList[1].start, sliceList[2].stop - sliceList[2].start, sliceList[3].stop - sliceList[3].start), dtype=str(self.UnscaledDataType))
|
|---|
| 447 |
|
|---|
| 448 | # Loop over the requested t indices, populating the result
|
|---|
| 449 | # array.
|
|---|
| 450 |
|
|---|
| 451 | i = 0
|
|---|
| 452 | tCoords = self.CenterCoords['t', sliceList[0]]
|
|---|
| 453 |
|
|---|
| 454 | while i < len(tCoords):
|
|---|
| 455 |
|
|---|
| 456 | # Open the _HYCOMGridGOMl0044D for the next block of t
|
|---|
| 457 | # coordinates. These grids are 1 year long, except in 2010
|
|---|
| 458 | # when HYCOM switched to an improved configuration after
|
|---|
| 459 | # five months.
|
|---|
| 460 |
|
|---|
| 461 | if tCoords[i] < datetime.datetime(2010, 6, 1):
|
|---|
| 462 | url = 'http://tds.hycom.org/thredds/dodsC/GOMl0.04/expt_20.1/%i' % tCoords[i].year
|
|---|
| 463 | else:
|
|---|
| 464 | url = 'http://tds.hycom.org/thredds/dodsC/GOMl0.04/expt_30.1/%i' % tCoords[i].year
|
|---|
| 465 |
|
|---|
| 466 | if self._OpenURL != url:
|
|---|
| 467 | self._OpenGrid = _HYCOMGridGOMl0044D(url, self._VariableName, self._Timeout, self._CacheDirectory)
|
|---|
| 468 | self._OpenURL = url
|
|---|
| 469 |
|
|---|
| 470 | if tCoords[i] >= datetime.datetime(2010, 1, 1) and tCoords[i] <= datetime.datetime(2010, 5, 31):
|
|---|
| 471 | lastDayOfDataset = datetime.datetime(2010, 5, 31)
|
|---|
| 472 | else:
|
|---|
| 473 | lastDayOfDataset = datetime.datetime(tCoords[i].year, 12, 31)
|
|---|
| 474 |
|
|---|
| 475 | # Read the necessary data from this grid as one 4D slab.
|
|---|
| 476 |
|
|---|
| 477 | import bisect
|
|---|
| 478 |
|
|---|
| 479 | gridTStart = bisect.bisect_left(self._OpenGrid.CenterCoords['t'].tolist(), tCoords[i])
|
|---|
| 480 | gridTStop = bisect.bisect_right(self._OpenGrid.CenterCoords['t'].tolist(), tCoords[-1])
|
|---|
| 481 | gridTCoords = self._OpenGrid.CenterCoords['t', gridTStart:gridTStop]
|
|---|
| 482 | data = self._OpenGrid.UnscaledData.__getitem__((slice(gridTStart, gridTStop), sliceList[1], sliceList[2], sliceList[3]))
|
|---|
| 483 |
|
|---|
| 484 | # Iterate through the t indices, copying out time slices
|
|---|
| 485 | # when they are available, otherwise setting slices to the
|
|---|
| 486 | # UnscaledNoDataValue.
|
|---|
| 487 |
|
|---|
| 488 | j = 0
|
|---|
| 489 |
|
|---|
| 490 | while i < len(tCoords) and tCoords[i] <= lastDayOfDataset:
|
|---|
| 491 | if j < len(gridTCoords) and gridTCoords[j] == tCoords[i]:
|
|---|
| 492 | result[i] = data[j]
|
|---|
| 493 | j += 1
|
|---|
| 494 | else:
|
|---|
| 495 | result[i] = self.UnscaledNoDataValue
|
|---|
| 496 | i += 1
|
|---|
| 497 |
|
|---|
| 498 | # Return successfully.
|
|---|
| 499 |
|
|---|
| 500 | return result, self.UnscaledNoDataValue
|
|---|
| 501 |
|
|---|
| 502 | @classmethod
|
|---|
| 503 | def CreateArcGISRasters(cls, variableName,
|
|---|
| 504 | outputWorkspace, mode=u'add', rasterNameExpressions=['%(VariableName)s', '%%Y', 'Depth_%(Depth)04.0fm', '%(VariableName)s_%%Y%%j_%(Depth)04.0fm.img'],
|
|---|
| 505 | spatialExtent=None, linearUnit=u'Degrees', minDepth=None, maxDepth=None, startDate=None, endDate=None,
|
|---|
| 506 | timeout=600, cacheDirectory=None,
|
|---|
| 507 | calculateStatistics=True, buildPyramids=False):
|
|---|
| 508 | cls.__doc__.Obj.ValidateMethodInvocation()
|
|---|
| 509 |
|
|---|
| 510 | # Construct a HYCOMGOMl0044D and clip it if requested.
|
|---|
| 511 |
|
|---|
| 512 | if startDate is not None:
|
|---|
| 513 | startYear = startDate.year
|
|---|
| 514 | else:
|
|---|
| 515 | startYear = None
|
|---|
| 516 |
|
|---|
| 517 | if endDate is not None:
|
|---|
| 518 | endYear = endDate.year
|
|---|
| 519 | else:
|
|---|
| 520 | endYear = None
|
|---|
| 521 |
|
|---|
| 522 | grid = HYCOMGOMl0044D(variableName, startYear=startYear, endYear=endYear, timeout=timeout, cacheDirectory=cacheDirectory)
|
|---|
| 523 |
|
|---|
| 524 | xMin, yMin, xMax, yMax = None, None, None, None
|
|---|
| 525 | if spatialExtent is not None:
|
|---|
| 526 | from GeoEco.Types import EnvelopeTypeMetadata
|
|---|
| 527 | xMin, yMin, xMax, yMax = EnvelopeTypeMetadata.ParseFromArcGISString(spatialExtent)
|
|---|
| 528 |
|
|---|
| 529 | # TODO: Project the spatialExtent, if necessary.
|
|---|
| 530 |
|
|---|
| 531 | cls._LogWarning(_(u'The HYCOM OPeNDAP server often requires five to ten minutes to return the first time slice. Please be patient. This tool cannot be cancelled until the first one is returned. After the first one is returned, the rest will go much faster and you will be able to cancel the tool, if desired. If this tool fails with to a timeout error, increase the timeout value and try again.'))
|
|---|
| 532 |
|
|---|
| 533 | if spatialExtent is not None or minDepth is not None or maxDepth is not None or startDate is not None or endDate is not None:
|
|---|
| 534 | grid = ClippedGrid(grid, u'Map coordinates', xMin=xMin, xMax=xMax, yMin=yMin, yMax=yMax, zMin=minDepth, zMax=maxDepth, tMin=startDate, tMax=endDate)
|
|---|
| 535 |
|
|---|
| 536 | # Construct an ArcGISWorkspace instance and import time slices
|
|---|
| 537 | # from the HYCOMGOMl0044D instance.
|
|---|
| 538 |
|
|---|
| 539 | from GeoEco.Datasets.ArcGIS import ArcGISWorkspace, ArcGISRaster
|
|---|
| 540 |
|
|---|
| 541 | workspace = ArcGISWorkspace(outputWorkspace,
|
|---|
| 542 | ArcGISRaster,
|
|---|
| 543 | pathCreationExpressions=rasterNameExpressions,
|
|---|
| 544 | cacheTree=True,
|
|---|
| 545 | queryableAttributes=(QueryableAttribute(u'VariableName', _(u'Variable'), UnicodeStringTypeMetadata(allowedValues=[u'salinity', u'temperature', u'u', u'v', u'w'], makeLowercase=True)),
|
|---|
| 546 | QueryableAttribute(u'DateTime', _(u'Date'), DateTimeTypeMetadata()),
|
|---|
| 547 | QueryableAttribute(u'Depth', _(u'Depth'), FloatTypeMetadata())))
|
|---|
| 548 |
|
|---|
| 549 | workspace.ImportDatasets(GridSliceCollection(grid, tQACoordType=u'center').QueryDatasets(), mode, calculateStatistics=calculateStatistics, buildPyramids=buildPyramids)
|
|---|
| 550 |
|
|---|
| 551 | # Return successfully.
|
|---|
| 552 |
|
|---|
| 553 | return outputWorkspace
|
|---|
| 554 |
|
|---|
| 555 |
|
|---|
| 556 | ###############################################################################
|
|---|
| 557 | # Metadata: module
|
|---|
| 558 | ###############################################################################
|
|---|
| 559 |
|
|---|
| 560 | from GeoEco.ArcGIS import ArcGISDependency
|
|---|
| 561 | from GeoEco.Dependencies import PythonAggregatedModuleDependency
|
|---|
| 562 | from GeoEco.Datasets.ArcGIS import _UseUnscaledDataDescription, _CalculateStatisticsDescription, _BuildRATDescription, _BuildPyramidsDescription
|
|---|
| 563 | from GeoEco.Metadata import *
|
|---|
| 564 | from GeoEco.Types import *
|
|---|
| 565 |
|
|---|
| 566 | AddModuleMetadata(shortDescription=_(u'Grids representing HYCOM datasets.')) # TODO: Better description
|
|---|
| 567 |
|
|---|
| 568 | ###############################################################################
|
|---|
| 569 | # Metadata: _HYCOMGridGOMl0043D class
|
|---|
| 570 | ###############################################################################
|
|---|
| 571 |
|
|---|
| 572 | AddClassMetadata(_HYCOMGridGOMl0043D,
|
|---|
| 573 | shortDescription=_(u'TODO: Description.'))
|
|---|
| 574 |
|
|---|
| 575 | # TODO: Add metadata
|
|---|
| 576 |
|
|---|
| 577 | ###############################################################################
|
|---|
| 578 | # Metadata: HYCOMGOMl0043D class
|
|---|
| 579 | ###############################################################################
|
|---|
| 580 |
|
|---|
| 581 | AddClassMetadata(HYCOMGOMl0043D,
|
|---|
| 582 | shortDescription=_(u'TODO: Description.'))
|
|---|
| 583 |
|
|---|
| 584 | # Constructor
|
|---|
| 585 |
|
|---|
| 586 | AddMethodMetadata(HYCOMGOMl0043D.__init__,
|
|---|
| 587 | shortDescription=_(u'Constructs a new HYCOMGOMl0043D instance.'),
|
|---|
| 588 | isExposedToPythonCallers=True,
|
|---|
| 589 | dependencies=[PythonAggregatedModuleDependency('numpy')])
|
|---|
| 590 |
|
|---|
| 591 | AddArgumentMetadata(HYCOMGOMl0043D.__init__, u'self',
|
|---|
| 592 | typeMetadata=ClassInstanceTypeMetadata(cls=HYCOMGOMl0043D),
|
|---|
| 593 | description=_(u'HYCOMGOMl0043D instance.'))
|
|---|
| 594 |
|
|---|
| 595 | AddArgumentMetadata(HYCOMGOMl0043D.__init__, u'variableName',
|
|---|
| 596 | typeMetadata=UnicodeStringTypeMetadata(allowedValues=[u'emp', u'mld', u'mlp', u'qtot', u'ssh', u'surface_salinity_trend', u'surface_temperature_trend'], makeLowercase=True),
|
|---|
| 597 | description=_(u"""TODO: Description."""),
|
|---|
| 598 | arcGISDisplayName=_(u'Dataset variable'))
|
|---|
| 599 |
|
|---|
| 600 | AddArgumentMetadata(HYCOMGOMl0043D.__init__, u'startYear',
|
|---|
| 601 | typeMetadata=IntegerTypeMetadata(canBeNone=True, minValue=2003),
|
|---|
| 602 | description=_(u"""TODO: Description."""))
|
|---|
| 603 |
|
|---|
| 604 | AddArgumentMetadata(HYCOMGOMl0043D.__init__, u'endYear',
|
|---|
| 605 | typeMetadata=IntegerTypeMetadata(canBeNone=True),
|
|---|
| 606 | description=_(u"""TODO: Description."""))
|
|---|
| 607 |
|
|---|
| 608 | CopyArgumentMetadata(THREDDSCatalog.__init__, u'timeout', HYCOMGOMl0043D.__init__, u'timeout')
|
|---|
| 609 | CopyArgumentMetadata(THREDDSCatalog.__init__, u'cacheDirectory', HYCOMGOMl0043D.__init__, u'cacheDirectory')
|
|---|
| 610 |
|
|---|
| 611 | AddResultMetadata(HYCOMGOMl0043D.__init__, u'grid',
|
|---|
| 612 | typeMetadata=ClassInstanceTypeMetadata(cls=HYCOMGOMl0043D),
|
|---|
| 613 | description=_(u'HYCOMGOMl0043D instance.'))
|
|---|
| 614 |
|
|---|
| 615 | # Public method: HYCOMGOMl0043D.CreateArcGISRasters
|
|---|
| 616 |
|
|---|
| 617 | AddMethodMetadata(HYCOMGOMl0043D.CreateArcGISRasters,
|
|---|
| 618 | shortDescription=_(u'Downloads a HYCOM GOMl0.04 surface variable and creates ArcGIS rasters.'),
|
|---|
| 619 | isExposedByCOM=True,
|
|---|
| 620 | isExposedAsArcGISTool=True,
|
|---|
| 621 | arcGISDisplayName=_(u'Download HYCOM GOMl0.04 Surface Variable to ArcGIS Rasters'),
|
|---|
| 622 | arcGISToolCategory=_(u'Data Products\\HYCOM Consortium\\HYCOM + NCODA Gulf of Mexico 1/25 Degree Analysis (GLMl0.04)'),
|
|---|
| 623 | dependencies=[ArcGISDependency(9, 1), PythonAggregatedModuleDependency('numpy')])
|
|---|
| 624 |
|
|---|
| 625 | AddArgumentMetadata(HYCOMGOMl0043D.CreateArcGISRasters, u'cls',
|
|---|
| 626 | typeMetadata=ClassOrClassInstanceTypeMetadata(cls=HYCOMGOMl0043D),
|
|---|
| 627 | description=_(u'HYCOMGOMl0043D class or instance.'))
|
|---|
| 628 |
|
|---|
| 629 | CopyArgumentMetadata(HYCOMGOMl0043D.__init__, u'variableName', HYCOMGOMl0043D.CreateArcGISRasters, u'variableName')
|
|---|
| 630 |
|
|---|
| 631 | AddArgumentMetadata(HYCOMGOMl0043D.CreateArcGISRasters, u'outputWorkspace', # TODO: Centralize descriptiont text
|
|---|
| 632 | typeMetadata=ArcGISWorkspaceTypeMetadata(createParentDirectories=True),
|
|---|
| 633 | description=_(
|
|---|
| 634 | u"""Directory or geodatabase to receive the rasters.
|
|---|
| 635 |
|
|---|
| 636 | Unless you have a specific reason to store the rasters in a
|
|---|
| 637 | geodatabase, we recommend you store them in a directory because it
|
|---|
| 638 | will be much faster and allows the rasters to be organized in a tree.
|
|---|
| 639 | If you do store the rasters in a geodatabase, you must change the
|
|---|
| 640 | Raster Name Expressions parameter; see below for more
|
|---|
| 641 | information."""),
|
|---|
| 642 | arcGISDisplayName=_(u'Output workspace'))
|
|---|
| 643 |
|
|---|
| 644 | AddArgumentMetadata(HYCOMGOMl0043D.CreateArcGISRasters, u'mode',
|
|---|
| 645 | typeMetadata=UnicodeStringTypeMetadata(allowedValues=[u'Add', u'Replace'], makeLowercase=True),
|
|---|
| 646 | description=_(
|
|---|
| 647 | u"""Overwrite mode, one of:
|
|---|
| 648 |
|
|---|
| 649 | * Add - create rasters that do not exist and skip those that already
|
|---|
| 650 | exist. This is the default.
|
|---|
| 651 |
|
|---|
| 652 | * Replace - create rasters that do not exist and overwrite those that
|
|---|
| 653 | already exist.
|
|---|
| 654 |
|
|---|
| 655 | 'Add' is appropriate when working with HYCOM data older than five days
|
|---|
| 656 | from the current date. When working with newer data, consider using
|
|---|
| 657 | 'Replace'. Each day, HYCOM provides a five day forecast and five day
|
|---|
| 658 | hindcast from the current date. Every day, all of the data between
|
|---|
| 659 | five days into the past and five days into the future are revised by
|
|---|
| 660 | HYCOM using the latest readings assimilated from buoys, satellites,
|
|---|
| 661 | and other sensors. By using 'Replace', you will be sure to overwrite
|
|---|
| 662 | obsolete data with the latest estimates.
|
|---|
| 663 |
|
|---|
| 664 | The ArcGIS Overwrite Outputs geoprocessing setting has no effect on
|
|---|
| 665 | this tool. If 'Replace' is selected the rasters will be overwritten,
|
|---|
| 666 | regardless of the ArcGIS Overwrite Outputs setting."""),
|
|---|
| 667 | arcGISDisplayName=_(u'Overwrite mode'))
|
|---|
| 668 |
|
|---|
| 669 | AddArgumentMetadata(HYCOMGOMl0043D.CreateArcGISRasters, u'rasterNameExpressions', # TODO: Centralize descriptiont text
|
|---|
| 670 | typeMetadata=ListTypeMetadata(elementType=UnicodeStringTypeMetadata(), minLength=1),
|
|---|
| 671 | description=_(
|
|---|
| 672 | u"""List of expressions specifying how the output rasters should be
|
|---|
| 673 | named.
|
|---|
| 674 |
|
|---|
| 675 | The default expression assumes you are storing rasters in a file
|
|---|
| 676 | system directory and creates them in a tree structure with names that
|
|---|
| 677 | imitate those used by the original data provider. When storing rasters
|
|---|
| 678 | in a directory, the final expression specifies the file name of the
|
|---|
| 679 | raster and any preceding expressions specify subdirectories. The
|
|---|
| 680 | extension of the final expression determines the output raster format:
|
|---|
| 681 | .asc for ArcInfo ASCII Grid, .bmp for BMP, .gif for GIF, .img for an
|
|---|
| 682 | ERDAS IMAGINE file, .jpg for JPEG, .jp2 for JPEG 2000, .png for PNG,
|
|---|
| 683 | .tif for GeoTIFF, or no extension for ArcInfo Binary Grid. The default
|
|---|
| 684 | expression uses .img.
|
|---|
| 685 |
|
|---|
| 686 | When storing rasters in a geodatabase, you should provide only one
|
|---|
| 687 | expression. That expression specifies the raster's name.
|
|---|
| 688 |
|
|---|
| 689 | Each expression may contain any sequence of characters permitted by
|
|---|
| 690 | the output workspace. Each expression may optionally contain one or
|
|---|
| 691 | more of the following case-sensitive codes. The tool replaces the
|
|---|
| 692 | codes with appropriate values when creating each raster:
|
|---|
| 693 |
|
|---|
| 694 | * %(VariableName)s - dataset variable represented in the output
|
|---|
| 695 | raster.
|
|---|
| 696 |
|
|---|
| 697 | * %%Y - four-digit year of the raster.
|
|---|
| 698 |
|
|---|
| 699 | * %%m - two-digit month of the first day of the raster.
|
|---|
| 700 |
|
|---|
| 701 | * %%d - two-digit day of the month of the first day of the raster.
|
|---|
| 702 |
|
|---|
| 703 | * %%j - three-digit day of the year of the first day of the raster.
|
|---|
| 704 | """),
|
|---|
| 705 | arcGISDisplayName=_(u'Raster name expressions'))
|
|---|
| 706 |
|
|---|
| 707 | AddArgumentMetadata(HYCOMGOMl0043D.CreateArcGISRasters, u'spatialExtent',
|
|---|
| 708 | typeMetadata=EnvelopeTypeMetadata(canBeNone=True),
|
|---|
| 709 | description=_(
|
|---|
| 710 | u"""Spatial extent of the output rasters, in the units specified by
|
|---|
| 711 | the Linear Units parameter.
|
|---|
| 712 |
|
|---|
| 713 | If you do not specify a spatial extent, it will default to
|
|---|
| 714 | approximately 98 to 76 W, 18 to 32 N. The rasters can only be clipped
|
|---|
| 715 | in whole grid cells. The values you provide will be rounded off to the
|
|---|
| 716 | closest cell."""),
|
|---|
| 717 | arcGISDisplayName=_(u'Spatial extent'),
|
|---|
| 718 | arcGISCategory=_(u'Spatiotemporal extent'))
|
|---|
| 719 |
|
|---|
| 720 | AddArgumentMetadata(HYCOMGOMl0043D.CreateArcGISRasters, u'linearUnit',
|
|---|
| 721 | typeMetadata=UnicodeStringTypeMetadata(allowedValues=[u'Degrees', u'Meters'], makeLowercase=True),
|
|---|
| 722 | description=_(
|
|---|
| 723 | u"""Specifies the unit of the Spatial Extent parameter, one of:
|
|---|
| 724 |
|
|---|
| 725 | * Degrees - Decimal degrees.
|
|---|
| 726 |
|
|---|
| 727 | * Meters - Meters, in the coordinate system of the output rasters.
|
|---|
| 728 | """),
|
|---|
| 729 | arcGISDisplayName=_(u'Linear unit'),
|
|---|
| 730 | arcGISCategory=_(u'Spatiotemporal extent'))
|
|---|
| 731 |
|
|---|
| 732 | AddArgumentMetadata(HYCOMGOMl0043D.CreateArcGISRasters, u'startDate',
|
|---|
| 733 | typeMetadata=DateTimeTypeMetadata(canBeNone=True),
|
|---|
| 734 | description=_(
|
|---|
| 735 | u"""Start date for the rasters to create.
|
|---|
| 736 |
|
|---|
| 737 | Rasters will be created for images that occur on or after the start
|
|---|
| 738 | date and on or before the end date. The HYCOM GOMl0.04 dataset
|
|---|
| 739 | provides a five-day forecast; its temporal extent ranges from 1
|
|---|
| 740 | January 2003 to today's date plus five days. If you do not specify a
|
|---|
| 741 | start date, 1 January 2003 will be used."""),
|
|---|
| 742 | arcGISDisplayName=_(u'Start date'),
|
|---|
| 743 | arcGISCategory=_(u'Spatiotemporal extent'))
|
|---|
| 744 |
|
|---|
| 745 | AddArgumentMetadata(HYCOMGOMl0043D.CreateArcGISRasters, u'endDate',
|
|---|
| 746 | typeMetadata=DateTimeTypeMetadata(canBeNone=True),
|
|---|
| 747 | description=_(
|
|---|
| 748 | u"""End date for the rasters to create.
|
|---|
| 749 |
|
|---|
| 750 | Rasters will be created for images that occur on or after the start
|
|---|
| 751 | date and on or before the end date. The HYCOM GOMl0.04 dataset
|
|---|
| 752 | provides a five-day forecast; its temporal extent ranges from 1
|
|---|
| 753 | January 2003 to today's date plus five days. If you do not specify an
|
|---|
| 754 | end date, the most recent day available will be used (typically
|
|---|
| 755 | today's date plus five days)."""),
|
|---|
| 756 | arcGISDisplayName=_(u'End date'),
|
|---|
| 757 | arcGISCategory=_(u'Spatiotemporal extent'))
|
|---|
| 758 |
|
|---|
| 759 | CopyArgumentMetadata(THREDDSCatalog.__init__, u'timeout', HYCOMGOMl0043D.CreateArcGISRasters, u'timeout')
|
|---|
| 760 | CopyArgumentMetadata(THREDDSCatalog.__init__, u'cacheDirectory', HYCOMGOMl0043D.CreateArcGISRasters, u'cacheDirectory')
|
|---|
| 761 |
|
|---|
| 762 | AddArgumentMetadata(HYCOMGOMl0043D.CreateArcGISRasters, u'calculateStatistics',
|
|---|
| 763 | typeMetadata=BooleanTypeMetadata(),
|
|---|
| 764 | description=_CalculateStatisticsDescription,
|
|---|
| 765 | arcGISDisplayName=_(u'Calculate statistics'),
|
|---|
| 766 | arcGISCategory=_(u'Additional raster processing options'))
|
|---|
| 767 |
|
|---|
| 768 | AddArgumentMetadata(HYCOMGOMl0043D.CreateArcGISRasters, u'buildPyramids',
|
|---|
| 769 | typeMetadata=BooleanTypeMetadata(),
|
|---|
| 770 | description=_BuildPyramidsDescription,
|
|---|
| 771 | arcGISDisplayName=_(u'Build pyramids'),
|
|---|
| 772 | arcGISCategory=_(u'Additional raster processing options'))
|
|---|
| 773 |
|
|---|
| 774 | AddResultMetadata(HYCOMGOMl0043D.CreateArcGISRasters, u'updatedOutputWorkspace',
|
|---|
| 775 | typeMetadata=ArcGISWorkspaceTypeMetadata(),
|
|---|
| 776 | description=_(u'Updated output workspace.'),
|
|---|
| 777 | arcGISDisplayName=_(u'Updated output workspace'),
|
|---|
| 778 | arcGISParameterDependencies=[u'outputWorkspace'])
|
|---|
| 779 |
|
|---|
| 780 | ###############################################################################
|
|---|
| 781 | # Metadata: _HYCOMGridGOMl0044D class
|
|---|
| 782 | ###############################################################################
|
|---|
| 783 |
|
|---|
| 784 | AddClassMetadata(_HYCOMGridGOMl0044D,
|
|---|
| 785 | shortDescription=_(u'TODO: Description.'))
|
|---|
| 786 |
|
|---|
| 787 | # TODO: Add metadata
|
|---|
| 788 |
|
|---|
| 789 | ###############################################################################
|
|---|
| 790 | # Metadata: HYCOMGOMl0044D class
|
|---|
| 791 | ###############################################################################
|
|---|
| 792 |
|
|---|
| 793 | AddClassMetadata(HYCOMGOMl0044D,
|
|---|
| 794 | shortDescription=_(u'TODO: Description.'))
|
|---|
| 795 |
|
|---|
| 796 | # Constructor
|
|---|
| 797 |
|
|---|
| 798 | AddMethodMetadata(HYCOMGOMl0044D.__init__,
|
|---|
| 799 | shortDescription=_(u'Constructs a new HYCOMGOMl0044D instance.'),
|
|---|
| 800 | isExposedToPythonCallers=True,
|
|---|
| 801 | dependencies=[PythonAggregatedModuleDependency('numpy')])
|
|---|
| 802 |
|
|---|
| 803 | AddArgumentMetadata(HYCOMGOMl0044D.__init__, u'self',
|
|---|
| 804 | typeMetadata=ClassInstanceTypeMetadata(cls=HYCOMGOMl0044D),
|
|---|
| 805 | description=_(u'HYCOMGOMl0044D instance.'))
|
|---|
| 806 |
|
|---|
| 807 | AddArgumentMetadata(HYCOMGOMl0044D.__init__, u'variableName',
|
|---|
| 808 | typeMetadata=UnicodeStringTypeMetadata(allowedValues=[u'salinity', u'temperature', u'u', u'v', u'w'], makeLowercase=True),
|
|---|
| 809 | description=_(u"""TODO: Description."""),
|
|---|
| 810 | arcGISDisplayName=_(u'Dataset variable'))
|
|---|
| 811 |
|
|---|
| 812 | CopyArgumentMetadata(HYCOMGOMl0043D.__init__, u'startYear', HYCOMGOMl0044D.__init__, u'startYear')
|
|---|
| 813 | CopyArgumentMetadata(HYCOMGOMl0043D.__init__, u'endYear', HYCOMGOMl0044D.__init__, u'endYear')
|
|---|
| 814 | CopyArgumentMetadata(HYCOMGOMl0043D.__init__, u'timeout', HYCOMGOMl0044D.__init__, u'timeout')
|
|---|
| 815 | CopyArgumentMetadata(HYCOMGOMl0043D.__init__, u'cacheDirectory', HYCOMGOMl0044D.__init__, u'cacheDirectory')
|
|---|
| 816 |
|
|---|
| 817 | CopyResultMetadata(HYCOMGOMl0043D.__init__, u'grid', HYCOMGOMl0044D.__init__, u'grid')
|
|---|
| 818 |
|
|---|
| 819 | # Public method: HYCOMGOMl0044D.CreateArcGISRasters
|
|---|
| 820 |
|
|---|
| 821 | AddMethodMetadata(HYCOMGOMl0044D.CreateArcGISRasters,
|
|---|
| 822 | shortDescription=_(u'Downloads a HYCOM GOMl0.04 4D variable and creates ArcGIS rasters.'),
|
|---|
| 823 | isExposedByCOM=True,
|
|---|
| 824 | isExposedAsArcGISTool=True,
|
|---|
| 825 | arcGISDisplayName=_(u'Download HYCOM GOMl0.04 4D Variable to ArcGIS Rasters'),
|
|---|
| 826 | arcGISToolCategory=_(u'Data Products\\HYCOM Consortium\\HYCOM + NCODA Gulf of Mexico 1/25 Degree Analysis (GLMl0.04)'),
|
|---|
| 827 | dependencies=[ArcGISDependency(9, 1), PythonAggregatedModuleDependency('numpy')])
|
|---|
| 828 |
|
|---|
| 829 | AddArgumentMetadata(HYCOMGOMl0044D.CreateArcGISRasters, u'cls',
|
|---|
| 830 | typeMetadata=ClassOrClassInstanceTypeMetadata(cls=HYCOMGOMl0044D),
|
|---|
| 831 | description=_(u'HYCOMGOMl0044D class or instance.'))
|
|---|
| 832 |
|
|---|
| 833 | CopyArgumentMetadata(HYCOMGOMl0044D.__init__, u'variableName', HYCOMGOMl0044D.CreateArcGISRasters, u'variableName')
|
|---|
| 834 | CopyArgumentMetadata(HYCOMGOMl0043D.CreateArcGISRasters, u'outputWorkspace', HYCOMGOMl0044D.CreateArcGISRasters, u'outputWorkspace')
|
|---|
| 835 | CopyArgumentMetadata(HYCOMGOMl0043D.CreateArcGISRasters, u'mode', HYCOMGOMl0044D.CreateArcGISRasters, u'mode')
|
|---|
| 836 |
|
|---|
| 837 | AddArgumentMetadata(HYCOMGOMl0044D.CreateArcGISRasters, u'rasterNameExpressions',
|
|---|
| 838 | typeMetadata=ListTypeMetadata(elementType=UnicodeStringTypeMetadata(), minLength=1),
|
|---|
| 839 | description=_(
|
|---|
| 840 | u"""List of expressions specifying how the output rasters should be
|
|---|
| 841 | named.
|
|---|
| 842 |
|
|---|
| 843 | The default expression assumes you are storing rasters in a file
|
|---|
| 844 | system directory and creates them in a tree structure with names that
|
|---|
| 845 | imitate those used by the original data provider. When storing rasters
|
|---|
| 846 | in a directory, the final expression specifies the file name of the
|
|---|
| 847 | raster and any preceding expressions specify subdirectories. The
|
|---|
| 848 | extension of the final expression determines the output raster format:
|
|---|
| 849 | .asc for ArcInfo ASCII Grid, .bmp for BMP, .gif for GIF, .img for an
|
|---|
| 850 | ERDAS IMAGINE file, .jpg for JPEG, .jp2 for JPEG 2000, .png for PNG,
|
|---|
| 851 | .tif for GeoTIFF, or no extension for ArcInfo Binary Grid. The default
|
|---|
| 852 | expression uses .img.
|
|---|
| 853 |
|
|---|
| 854 | When storing rasters in a geodatabase, you should provide only one
|
|---|
| 855 | expression. That expression specifies the raster's name.
|
|---|
| 856 |
|
|---|
| 857 | Each expression may contain any sequence of characters permitted by
|
|---|
| 858 | the output workspace. Each expression may optionally contain one or
|
|---|
| 859 | more of the following case-sensitive codes. The tool replaces the
|
|---|
| 860 | codes with appropriate values when creating each raster:
|
|---|
| 861 |
|
|---|
| 862 | * %(VariableName)s - dataset variable represented in the output
|
|---|
| 863 | raster.
|
|---|
| 864 |
|
|---|
| 865 | * %(Depth)f - depth of the output raster. The f may be preceded by
|
|---|
| 866 | Python's string formatting codes. Please see the Python
|
|---|
| 867 | documentation for more information.
|
|---|
| 868 |
|
|---|
| 869 | * %%Y - four-digit year of the raster.
|
|---|
| 870 |
|
|---|
| 871 | * %%m - two-digit month of the first day of the raster.
|
|---|
| 872 |
|
|---|
| 873 | * %%d - two-digit day of the month of the first day of the raster.
|
|---|
| 874 |
|
|---|
| 875 | * %%j - three-digit day of the year of the first day of the raster.
|
|---|
| 876 | """),
|
|---|
| 877 | arcGISDisplayName=_(u'Raster name expressions'))
|
|---|
| 878 |
|
|---|
| 879 | CopyArgumentMetadata(HYCOMGOMl0043D.CreateArcGISRasters, u'spatialExtent', HYCOMGOMl0044D.CreateArcGISRasters, u'spatialExtent')
|
|---|
| 880 | CopyArgumentMetadata(HYCOMGOMl0043D.CreateArcGISRasters, u'linearUnit', HYCOMGOMl0044D.CreateArcGISRasters, u'linearUnit')
|
|---|
| 881 |
|
|---|
| 882 | AddArgumentMetadata(HYCOMGOMl0044D.CreateArcGISRasters, u'minDepth',
|
|---|
| 883 | typeMetadata=FloatTypeMetadata(minValue=0.0, maxValue=5500.0, canBeNone=True),
|
|---|
| 884 | description=_(
|
|---|
| 885 | u"""Minimum depth, in meters, for the rasters to create.
|
|---|
| 886 |
|
|---|
| 887 | The value must be between 0 and 5500, inclusive. Rasters will be
|
|---|
| 888 | created for images with depths that are greater than or equal to the
|
|---|
| 889 | minimum depth and less than or equal to the maximum depth. If you do
|
|---|
| 890 | not specify a minimum depth, 0 will be used."""),
|
|---|
| 891 | arcGISDisplayName=_(u'Minimum depth'),
|
|---|
| 892 | arcGISCategory=_(u'Spatiotemporal extent'))
|
|---|
| 893 |
|
|---|
| 894 | AddArgumentMetadata(HYCOMGOMl0044D.CreateArcGISRasters, u'maxDepth',
|
|---|
| 895 | typeMetadata=FloatTypeMetadata(minValue=0.0, maxValue=5500.0, canBeNone=True),
|
|---|
| 896 | description=_(
|
|---|
| 897 | u"""Maximum depth, in meters, for the rasters to create.
|
|---|
| 898 |
|
|---|
| 899 | The value must be between 0 and 5500, inclusive. Rasters will be
|
|---|
| 900 | created for images with depths that are greater than or equal to the
|
|---|
| 901 | minimum depth and less than or equal to the maximum depth. If you do
|
|---|
| 902 | not specify a maximum depth, 5500 will be used. This depth encompasses
|
|---|
| 903 | the deepest HYCOM layer."""),
|
|---|
| 904 | arcGISDisplayName=_(u'Maximum depth'),
|
|---|
| 905 | arcGISCategory=_(u'Spatiotemporal extent'))
|
|---|
| 906 |
|
|---|
| 907 | CopyArgumentMetadata(HYCOMGOMl0043D.CreateArcGISRasters, u'startDate', HYCOMGOMl0044D.CreateArcGISRasters, u'startDate')
|
|---|
| 908 | CopyArgumentMetadata(HYCOMGOMl0043D.CreateArcGISRasters, u'endDate', HYCOMGOMl0044D.CreateArcGISRasters, u'endDate')
|
|---|
| 909 | CopyArgumentMetadata(HYCOMGOMl0043D.CreateArcGISRasters, u'timeout', HYCOMGOMl0044D.CreateArcGISRasters, u'timeout')
|
|---|
| 910 | CopyArgumentMetadata(HYCOMGOMl0043D.CreateArcGISRasters, u'cacheDirectory', HYCOMGOMl0044D.CreateArcGISRasters, u'cacheDirectory')
|
|---|
| 911 | CopyArgumentMetadata(HYCOMGOMl0043D.CreateArcGISRasters, u'calculateStatistics', HYCOMGOMl0044D.CreateArcGISRasters, u'calculateStatistics')
|
|---|
| 912 | CopyArgumentMetadata(HYCOMGOMl0043D.CreateArcGISRasters, u'buildPyramids', HYCOMGOMl0044D.CreateArcGISRasters, u'buildPyramids')
|
|---|
| 913 |
|
|---|
| 914 | CopyResultMetadata(HYCOMGOMl0043D.CreateArcGISRasters, u'updatedOutputWorkspace', HYCOMGOMl0044D.CreateArcGISRasters, u'updatedOutputWorkspace')
|
|---|
| 915 |
|
|---|
| 916 | ###############################################################################
|
|---|
| 917 | # Names exported by this module
|
|---|
| 918 | ###############################################################################
|
|---|
| 919 |
|
|---|
| 920 | __all__ = ['HYCOMGOMl0043D', 'HYCOMGOMl0044D']
|
|---|