root/MGET/Branches/Jason/PythonPackage/src/GeoEco/Connectivity/CoralReefConnectivity.py @ 885

Revision 885, 112.1 KB (checked in by jjr8, 17 months ago)

Changed LoadOSCARCurrentsIntoSimulation to rotate currents to be aligned approximately on the Prime Meridian. This will make them cover the same spatial extent as GSHHS in ArcMap?. (In principle, it should not affect any analysis.)

Line 
1# CoralReefConnectivity.py - Implements Eric Treml's coral reef
2# connectivity analysis.
3#
4# Copyright (C) 2008 Jason J. Roberts and Eric A. Treml
5#
6# This program is free software; you can redistribute it and/or
7# modify it under the terms of the GNU General Public License
8# as published by the Free Software Foundation; either version 2
9# of the License, or (at your option) any later version.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14# GNU General Public License (available in the file LICENSE.TXT)
15# for more details.
16#
17# You should have received a copy of the GNU General Public License
18# along with this program; if not, write to the Free Software
19# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20
21import os
22
23from GeoEco.DataProducts.Aviso import AvisoGriddedGeostrophicCurrents, _AvisoGriddedProduct, _AvisoGriddedProduct_LongDescription
24from GeoEco.DataProducts.HYCOM import HYCOMGOMl0044D, _HYCOMGOMl004_LongDescription, HYCOMGLBa008Equatorial4D, _HYCOMGLBa008Equatorial_LongDescription
25from GeoEco.DataProducts.NOAA.OSCAR import OSCAR5DayThirdDegreeCurrents, _OSCAR_LongDescription
26from GeoEco.DataProducts.UMaineOMG import ROMSCoSiNE4D, _ROMS_CoSiNE_LongDescription
27from GeoEco.DynamicDocString import DynamicDocString
28from GeoEco.Internationalization import _
29from GeoEco.Logging import Logger, ProgressReporter
30from GeoEco.Types import EnvelopeTypeMetadata
31
32class CoralReefConnectivity(object):
33    __doc__ = DynamicDocString()
34
35    @classmethod
36    def CreateSimulationFromArcGISRasters(cls, simulationDirectory, reefIDsRaster, reefCoverRaster, waterMaskRaster, crosses180=False, overwriteExisting=False):
37        cls.__doc__.Obj.ValidateMethodInvocation()
38
39        # Validate the coordinate systems, extents, and cell sizes of
40        # the input rasters.
41
42        from GeoEco.ArcGIS import GeoprocessorManager
43        gp = GeoprocessorManager.GetWrappedGeoprocessor()
44
45        describeReefIDsRaster = gp.Describe(reefIDsRaster)
46        describereefCoverRaster = gp.Describe(reefCoverRaster)
47        describeWaterMaskRaster = gp.Describe(waterMaskRaster)
48
49        if describeReefIDsRaster.SpatialReference.Type.lower() != u'projected':
50            Logger.RaiseException(ValueError(_(u'ArcGIS reports that the reef IDs raster %(raster)s uses a %(type)s coordinate system. It must use a projected coordinate system. Please project it and try again.') % {u'raster': reefIDsRaster, u'type': describeReefIDsRaster.SpatialReference.Type.lower()}))
51        if describeReefIDsRaster.SpatialReference.LinearUnitName.lower() != u'meter':
52            Logger.RaiseException(ValueError(_(u'ArcGIS reports that the reef IDs raster %(raster)s uses the linear unit "%(unit)s". It must use a coordinate system that has meters as its linear unit.  Please project it to a coordinate system that uses meters and try again.') % {u'raster': reefIDsRaster, u'unit': describeReefIDsRaster.SpatialReference.LinearUnitName.lower()}))
53
54        reefIDsRasterCS = gp.CreateSpatialReference(describeReefIDsRaster.SpatialReference).split(';')[0]
55        reefCoverRasterCS = gp.CreateSpatialReference(describereefCoverRaster.SpatialReference).split(';')[0]
56        waterMaskRasterCS = gp.CreateSpatialReference(describeWaterMaskRaster.SpatialReference).split(';')[0]
57
58        if reefCoverRasterCS.lower() != reefIDsRasterCS.lower():
59            Logger.RaiseException(ValueError(_(u'The reef cover raster %(raster1)s uses a different coordinate system than the reef IDs raster, %(raster2)s. Please project the reef cover raster to the reef IDs raster\'s coordinate system and try again.') % {u'raster1': reefCoverRaster, u'raster2': reefIDsRaster}))
60        if waterMaskRasterCS.lower() != reefIDsRasterCS.lower():
61            Logger.RaiseException(ValueError(_(u'The water mask raster %(raster1)s uses a different coordinate system than the reef IDs raster, %(raster2)s. Please project the water mask raster to the reef IDs raster\'s coordinate system and try again.') % {u'raster1': waterMaskRaster, u'raster2': reefIDsRaster}))
62
63        reefIDsRasterLeft, reefIDsRasterBottom, reefIDsRasterRight, reefIDsRasterTop = EnvelopeTypeMetadata.ParseFromArcGISString(describeReefIDsRaster.Extent)
64        reefCoverRasterLeft, reefCoverRasterBottom, reefCoverRasterRight, reefCoverRasterTop = EnvelopeTypeMetadata.ParseFromArcGISString(describereefCoverRaster.Extent)
65        waterMaskRasterLeft, waterMaskRasterBottom, waterMaskRasterRight, waterMaskRasterTop = EnvelopeTypeMetadata.ParseFromArcGISString(describeWaterMaskRaster.Extent)
66
67        if abs(reefCoverRasterLeft - reefIDsRasterLeft) > 0.001 or abs(reefCoverRasterBottom - reefIDsRasterBottom) > 0.001 or abs(reefCoverRasterRight - reefIDsRasterRight) > 0.001 or abs(reefCoverRasterTop - reefIDsRasterTop) > 0.001 or abs(describereefCoverRaster.MeanCellWidth - describeReefIDsRaster.MeanCellWidth) > 0.001 or abs(describereefCoverRaster.MeanCellHeight - describeReefIDsRaster.MeanCellHeight) > 0.001:
68            Logger.RaiseException(ValueError(_(u'The reef cover raster %(raster1)s has a different extent or cell size than the reef IDs raster, %(raster2)s. Please prepare a reef cover raster that has the same extent and cell size as the reef IDs raster and try again.') % {u'raster1': reefCoverRaster, u'raster2': reefIDsRaster}))
69        if abs(waterMaskRasterLeft - reefIDsRasterLeft) > 0.001 or abs(waterMaskRasterBottom - reefIDsRasterBottom) > 0.001 or abs(waterMaskRasterRight - reefIDsRasterRight) > 0.001 or abs(waterMaskRasterTop - reefIDsRasterTop) > 0.001 or abs(describeWaterMaskRaster.MeanCellWidth - describeReefIDsRaster.MeanCellWidth) > 0.001 or abs(describeWaterMaskRaster.MeanCellHeight - describeReefIDsRaster.MeanCellHeight) > 0.001:
70            Logger.RaiseException(ValueError(_(u'The water mask raster %(raster1)s has a different extent or cell size than the reef IDs raster, %(raster2)s. Please prepare a water mask raster that has the same extent and cell size as the reef IDs raster and try again.') % {u'raster1': reefCoverRaster, u'raster2': waterMaskRaster}))
71
72        # Validate that 0 is not used as a reef ID. The MATLAB code
73        # uses 0 to represent cells where no reefs are present.
74
75        from GeoEco.DataManagement.ArcGISRasters import ArcGISRaster
76        from GeoEco.DataManagement.Directories import Directory, TemporaryDirectory
77        import numpy
78
79        tempDir = TemporaryDirectory()
80        reefIDsImage, reefIDsNoDataValue = ArcGISRaster.ToNumpyArray(reefIDsRaster, tempRasterPath=os.path.join(tempDir.Path, u'reef_ids'))
81        if numpy.any(reefIDsImage == 0) and reefIDsNoDataValue != 0:
82            Logger.RaiseException(ValueError(_(u'The reef IDs raster %(raster)s uses 0 as a reef ID. This is not allowed.  Please remove the value 0 from the reef IDs raster and try again.')  % {u'raster': reefIDsRaster}))
83
84        # Validate that reef cover raster ranges between 0.0 and 1.0.
85
86        reefCoverImage, noDataValue = ArcGISRaster.ToNumpyArray(reefCoverRaster, tempRasterPath=os.path.join(tempDir.Path, u'reef_areas'))
87        if noDataValue is not None:
88            reefCoverImage[reefCoverImage == noDataValue] = 0
89        if numpy.any(reefCoverImage < 0) or numpy.any(reefCoverImage > 1):
90            Logger.RaiseException(ValueError(_(u'The reef cover raster %(raster)s includes values that are less than 0 or are greater than 1. The values of a cell of this raster is supposed to represent the proportion of the cell\'s area that is occupied by reef, thus the value is supposed to be between 0 and 1. Please prepare a raster that has the correct values and try again.')  % {u'raster': reefCoverRaster}))
91
92        # Create the simulation directory and the ReefData
93        # subdirectory.
94
95        oldLogInfoAsDebug = Logger.LogInfoAndSetInfoToDebug(_(u'Creating and initializing the simulation directory %(dir)s...') % {u'dir': simulationDirectory})
96        Logger.SetLogInfoAsDebug(True)
97        try:
98            from GeoEco.DataManagement.Directories import Directory, TemporaryDirectory
99
100            Directory.Create(simulationDirectory)
101            Directory.Create(os.path.join(simulationDirectory, u'ReefData'))
102
103            # Copy the reef IDs raster into the ReefData directory.
104
105            ArcGISRaster.Copy(reefIDsRaster, os.path.join(simulationDirectory, u'ReefData', u'reef_ids'))
106
107            # Copy the reef cover raster into the ReefData directory,
108            # setting the NoData values and non-reef cells to 0 in the process.
109
110            if GeoprocessorManager.GetArcGISMajorVersion() >= 10:
111                mapAlgebraExpression = u'float(con(isnull( [%(raster1)s] ) == 1 || isnull( [%(raster2)s] ) == 1, 0.0, [%(raster1)s] ))' % {u'raster1': reefCoverRaster, u'raster2': reefIDsRaster}
112            else:
113                mapAlgebraExpression = u'float(con(isnull( %(raster1)s ) == 1 || isnull( %(raster2)s ) == 1, 0.0, %(raster1)s ))' % {u'raster1': reefCoverRaster, u'raster2': reefIDsRaster}
114            gp.SingleOutputMapAlgebra_sa(mapAlgebraExpression, os.path.join(tempDir.Path, u'reef_areas2'))
115            ArcGISRaster.Copy(os.path.join(tempDir.Path, u'reef_areas2'), os.path.join(simulationDirectory, u'ReefData', u'reef_areas'))
116
117            # Copy the water mask raster into the ReefData directory,
118            # normalizing it to integer values where 1 is water, 0 is
119            # land.
120
121            if GeoprocessorManager.GetArcGISMajorVersion() >= 10:
122                mapAlgebraExpression = u'con(isnull( [%(raster)s] ) || [%(raster)s] == 0, 0, 1)' % {u'raster': waterMaskRaster}
123            else:
124                mapAlgebraExpression = u'con(isnull( %(raster)s ) || %(raster)s == 0, 0, 1)' % {u'raster': waterMaskRaster}
125            gp.SingleOutputMapAlgebra_sa(mapAlgebraExpression, os.path.join(tempDir.Path, u'water_mask'))
126            ArcGISRaster.Copy(os.path.join(tempDir.Path, u'water_mask'), os.path.join(simulationDirectory, u'ReefData', u'water_mask'))
127
128            # Create the reef_geometry file by calling Spatial
129            # Analyst's Zonal Geometry As Table tool. (Note that this
130            # tool will create a .dbf file no matter what, even if we
131            # give it a .csv or .txt extension. This is very annoying,
132            # because we can't read it easily without going through a
133            # database API, which is slow.)
134
135            gp.ZonalGeometryAsTable_sa(os.path.join(simulationDirectory, u'ReefData', u'reef_ids'), u'Value', os.path.join(simulationDirectory, u'ReefData', u'reef_geometry.dbf'), describeReefIDsRaster.MeanCellWidth)
136
137            # Create the directories that will hold the currents
138            # rasters.
139
140            Directory.Create(os.path.join(simulationDirectory, u'Currents'))
141            Directory.Create(os.path.join(simulationDirectory, u'Currents', u'u'))
142            Directory.Create(os.path.join(simulationDirectory, u'Currents', u'v'))
143
144            # Create the config file that stores properties of the
145            # simulation.
146
147            from ConfigParser import SafeConfigParser
148
149            scp = SafeConfigParser()
150            scp.add_section(u'Simulation')
151            scp.set(u'Simulation', u'Crosses180', unicode(crosses180))
152            scp.set(u'Simulation', u'CurrentsLoaded', unicode(False))
153            scp.set(u'Simulation', u'CurrentsProduct', u'')
154            f = file(os.path.join(simulationDirectory, u'Simulation.ini'), 'w')
155            try:
156                scp.write(f)
157            finally:
158                try:
159                    f.close()
160                except:
161                    pass
162
163        finally:
164            Logger.SetLogInfoAsDebug(oldLogInfoAsDebug)
165
166    @classmethod
167    def LoadAvisoGeostrophicCurrentsIntoSimulation(cls, simulationDirectory, username, password, product, startDate, endDate, resamplingTechnique=u'CUBIC', interpolationMethod=None, timeout=60, maxRetryTime=120, cacheDirectory=None):
168        cls.__doc__.Obj.ValidateMethodInvocation()
169
170        # Parse and validate the Simulation.ini file.
171
172        scp, crosses180, currentsLoaded, currentsProduct = cls._ReadCurrentsInfoFromSimulationINI(simulationDirectory)
173
174        # If the simulation already has currents loaded in it from a
175        # different product, report an error.
176
177        thisCurrentsProduct = u'Aviso %s (resampling=%s, interpolation=%s)' % (product, resamplingTechnique.lower(), str(interpolationMethod).lower())
178
179        if currentsLoaded and currentsProduct != thisCurrentsProduct:
180            Logger.RaiseException(ValueError(_(u'Cannot load %(prod1)s currents data into the simulation in directory %(dir)s because that simulation already has %(prod2)s currents data loaded into it. You can load additional %(prod2)s data, if you like, but to use Aviso %(prod1)s data, you must create a new simulation.') % {u'dir': simulationDirectory, u'prod1': thisCurrentsProduct, u'prod2': currentsProduct}))
181
182        # First, download and create Aviso current rasters in an
183        # Aviso-specific directory. These will have the Aviso
184        # projection, extent, and cell size. We still need to project
185        # them to the simulation's projection, extent, and cell size.
186        #
187        # TODO: Need to handle rotation?
188
189        avisoCurrentsDirectory = os.path.join(simulationDirectory, 'OriginalAvisoCurrents')
190        _AvisoCurrentsInMetersPerSecond.CreateArcGISRasters(username, password, product, u'u', avisoCurrentsDirectory, rasterNameExpressions=['u', '%%Y', 'u%%Y%%j0000.img'], startDate=startDate, endDate=endDate, timeout=timeout, maxRetryTime=maxRetryTime, cacheDirectory=cacheDirectory)
191        _AvisoCurrentsInMetersPerSecond.CreateArcGISRasters(username, password, product, u'v', avisoCurrentsDirectory, rasterNameExpressions=['v', '%%Y', 'v%%Y%%j0000.img'], startDate=startDate, endDate=endDate, timeout=timeout, maxRetryTime=maxRetryTime, cacheDirectory=cacheDirectory)
192
193        # Record in the Simulation.ini file that we downloaded some
194        # currents and then project, snap, and clip them to the
195        # projection, extent, and cell size of the reef IDs raster.
196
197        grid = AvisoGriddedGeostrophicCurrents(product, u'u', username, password, timeout=timeout, maxRetryTime=maxRetryTime)
198        timeStep = grid.CenterCoords['t', 1] - grid.CenterCoords['t', 0]
199
200        cls._FinishLoadingCurrents(simulationDirectory, scp, thisCurrentsProduct, u'Center', timeStep.days * 86400 + timeStep.seconds, avisoCurrentsDirectory, resamplingTechnique, interpolationMethod)
201
202        # Return successfully.
203
204        return simulationDirectory
205
206    @classmethod
207    def LoadOSCARCurrentsIntoSimulation(cls, simulationDirectory, startDate, endDate, resamplingTechnique=u'CUBIC', interpolationMethod=None, timeout=60, maxRetryTime=120, cacheDirectory=None):
208        cls.__doc__.Obj.ValidateMethodInvocation()
209
210        # Parse and validate the Simulation.ini file.
211
212        scp, crosses180, currentsLoaded, currentsProduct = cls._ReadCurrentsInfoFromSimulationINI(simulationDirectory)
213
214        # If the simulation already has currents loaded in it from a
215        # different product, report an error.
216
217        thisCurrentsProduct = u'OSCAR (resampling=%s, interpolation=%s)' % (resamplingTechnique.lower(), str(interpolationMethod).lower())
218
219        if currentsLoaded and currentsProduct != thisCurrentsProduct:
220            Logger.RaiseException(ValueError(_(u'Cannot load %(prod1)s currents data into the simulation in directory %(dir)s because that simulation already has %(prod2)s currents data loaded into it. You can load additional %(prod2)s data, if you like, but to use Aviso %(prod1)s data, you must create a new simulation.') % {u'dir': simulationDirectory, u'prod1': thisCurrentsProduct, u'prod2': currentsProduct}))
221
222        # First, download and create OSCAR current rasters in an
223        # OSCAR-specific directory. These will have the OSCAR
224        # projection, extent, and cell size. We still need to project
225        # them to the simulation's projection, extent, and cell size.
226        #
227        # TODO: Need to handle rotation?
228
229        oscarCurrentsDirectory = os.path.join(simulationDirectory, 'OriginalOSCARCurrents')
230        OSCAR5DayThirdDegreeCurrents.CreateArcGISRasters(u'u', oscarCurrentsDirectory, rasterNameExpressions=['u', '%%Y', 'u%%Y%%j0000.img'], rotationOffset=-20., startDate=startDate, endDate=endDate, timeout=timeout, maxRetryTime=maxRetryTime, cacheDirectory=cacheDirectory)
231        OSCAR5DayThirdDegreeCurrents.CreateArcGISRasters(u'v', oscarCurrentsDirectory, rasterNameExpressions=['v', '%%Y', 'v%%Y%%j0000.img'], rotationOffset=-20., startDate=startDate, endDate=endDate, timeout=timeout, maxRetryTime=maxRetryTime, cacheDirectory=cacheDirectory)
232
233        # Record in the Simulation.ini file that we downloaded some
234        # currents and then project, snap, and clip them to the
235        # projection, extent, and cell size of the reef IDs raster.
236
237        cls._FinishLoadingCurrents(simulationDirectory, scp, thisCurrentsProduct, u'Center', 6*86400, oscarCurrentsDirectory, resamplingTechnique, interpolationMethod)
238
239        # Return successfully.
240
241        return simulationDirectory
242
243    @classmethod
244    def LoadHYCOMGOMl0044DCurrentsIntoSimulation(cls, simulationDirectory, startDate, endDate, depth=0., resamplingTechnique=u'CUBIC', interpolationMethod=None, timeout=600, maxRetryTime=None, cacheDirectory=None):
245        cls.__doc__.Obj.ValidateMethodInvocation()
246
247        # Parse and validate the Simulation.ini file.
248
249        scp, crosses180, currentsLoaded, currentsProduct = cls._ReadCurrentsInfoFromSimulationINI(simulationDirectory)
250
251        # If the simulation already has currents loaded in it from a
252        # different product, report an error.
253
254        thisCurrentsProduct = u'HYCOM GOMl0.04 %i m (resampling=%s, interpolation=%s)' % (int(depth), resamplingTechnique.lower(), str(interpolationMethod).lower())
255
256        if currentsLoaded and currentsProduct != thisCurrentsProduct:
257            Logger.RaiseException(ValueError(_(u'Cannot load %(prod1)s currents data into the simulation in directory %(dir)s because that simulation already has %(prod2)s currents data loaded into it. You can load additional %(prod2)s data, if you like, but to use Aviso %(prod1)s data, you must create a new simulation.') % {u'dir': simulationDirectory, u'prod1': thisCurrentsProduct, u'prod2': currentsProduct}))
258
259        # First, download and create HYCOM current rasters in a
260        # HYCOM-specific directory. These will have the HYCOM
261        # projection, extent, and cell size. We still need to project
262        # them to the simulation's projection, extent, and cell size.
263
264        hycomCurrentsDirectory = os.path.join(simulationDirectory, 'OriginalHYCOMCurrents')
265        HYCOMGOMl0044D.CreateArcGISRasters(u'u', hycomCurrentsDirectory, rasterNameExpressions=['%(VariableName)s', '%%Y', '%(VariableName)s%%Y%%j0000.img'], minDepth=depth, maxDepth=depth, startDate=startDate, endDate=endDate, timeout=timeout, maxRetryTime=maxRetryTime, cacheDirectory=cacheDirectory)
266        HYCOMGOMl0044D.CreateArcGISRasters(u'v', hycomCurrentsDirectory, rasterNameExpressions=['%(VariableName)s', '%%Y', '%(VariableName)s%%Y%%j0000.img'], minDepth=depth, maxDepth=depth, startDate=startDate, endDate=endDate, timeout=timeout, maxRetryTime=maxRetryTime, cacheDirectory=cacheDirectory)
267
268        # Record in the Simulation.ini file that we downloaded some
269        # currents and then project, snap, and clip them to the
270        # projection, extent, and cell size of the reef IDs raster.
271
272        cls._FinishLoadingCurrents(simulationDirectory, scp, thisCurrentsProduct, u'Center', 86400, hycomCurrentsDirectory, resamplingTechnique, interpolationMethod)
273
274        # Return successfully.
275
276        return simulationDirectory
277
278    @classmethod
279    def LoadHYCOMGLBa0084DEquatorialCurrentsIntoSimulation(cls, simulationDirectory, startDate, endDate, depth=0., extendYExtent=False, resamplingTechnique=u'CUBIC', interpolationMethod=None, timeout=60, maxRetryTime=120, cacheDirectory=None):
280        cls.__doc__.Obj.ValidateMethodInvocation()
281
282        # Parse and validate the Simulation.ini file.
283
284        scp, crosses180, currentsLoaded, currentsProduct = cls._ReadCurrentsInfoFromSimulationINI(simulationDirectory)
285
286        # If the simulation already has currents loaded in it from a
287        # different product, report an error.
288
289        thisCurrentsProduct = u'HYCOM GLBa0.08 Equatorial %i m (resampling=%s, interpolation=%s)' % (int(depth), resamplingTechnique.lower(), str(interpolationMethod).lower())
290
291        if currentsLoaded and currentsProduct != thisCurrentsProduct:
292            Logger.RaiseException(ValueError(_(u'Cannot load %(prod1)s currents data into the simulation in directory %(dir)s because that simulation already has %(prod2)s currents data loaded into it. You can load additional %(prod2)s data, if you like, but to use Aviso %(prod1)s data, you must create a new simulation.') % {u'dir': simulationDirectory, u'prod1': thisCurrentsProduct, u'prod2': currentsProduct}))
293
294        # First, download and create HYCOM current rasters in a
295        # HYCOM-specific directory. These will have the HYCOM
296        # projection, extent, and cell size. We still need to project
297        # them to the simulation's projection, extent, and cell size.
298
299        hycomCurrentsDirectory = os.path.join(simulationDirectory, 'OriginalHYCOMCurrents')
300        HYCOMGLBa008Equatorial4D.CreateArcGISRasters(u'u', hycomCurrentsDirectory, rasterNameExpressions=['%(VariableName)s', '%%Y', '%(VariableName)s%%Y%%j0000.img'], extendYExtent=extendYExtent, minDepth=depth, maxDepth=depth, startDate=startDate, endDate=endDate, timeout=timeout, maxRetryTime=maxRetryTime, cacheDirectory=cacheDirectory)
301        HYCOMGLBa008Equatorial4D.CreateArcGISRasters(u'v', hycomCurrentsDirectory, rasterNameExpressions=['%(VariableName)s', '%%Y', '%(VariableName)s%%Y%%j0000.img'], extendYExtent=extendYExtent, minDepth=depth, maxDepth=depth, startDate=startDate, endDate=endDate, timeout=timeout, maxRetryTime=maxRetryTime, cacheDirectory=cacheDirectory)
302
303        # Record in the Simulation.ini file that we downloaded some
304        # currents and then project, snap, and clip them to the
305        # projection, extent, and cell size of the reef IDs raster.
306
307        cls._FinishLoadingCurrents(simulationDirectory, scp, thisCurrentsProduct, u'Center', 86400, hycomCurrentsDirectory, resamplingTechnique, interpolationMethod)
308
309        # Return successfully.
310
311        return simulationDirectory
312
313    @classmethod
314    def LoadROMSCoSiNE4DCurrentsIntoSimulation(cls, simulationDirectory, startDate, endDate, depth=0., resamplingTechnique=u'CUBIC', interpolationMethod=None, url=u'http://viz.clusters.umaine.edu:8080/thredds/dodsC/pacific/1991-2008', timeout=60, maxRetryTime=120, cacheDirectory=None):
315        cls.__doc__.Obj.ValidateMethodInvocation()
316
317        # Parse and validate the Simulation.ini file.
318
319        scp, crosses180, currentsLoaded, currentsProduct = cls._ReadCurrentsInfoFromSimulationINI(simulationDirectory)
320
321        # If the simulation already has currents loaded in it from a
322        # different product, report an error.
323
324        thisCurrentsProduct = u'ROMS-CoSiNE %i m (resampling=%s, interpolation=%s)' % (int(depth), resamplingTechnique.lower(), str(interpolationMethod).lower())
325
326        if currentsLoaded and currentsProduct != thisCurrentsProduct:
327            Logger.RaiseException(ValueError(_(u'Cannot load %(prod1)s currents data into the simulation in directory %(dir)s because that simulation already has %(prod2)s currents data loaded into it. You can load additional %(prod2)s data, if you like, but to use Aviso %(prod1)s data, you must create a new simulation.') % {u'dir': simulationDirectory, u'prod1': thisCurrentsProduct, u'prod2': currentsProduct}))
328
329        # First, download and create ROMS-CoSiNE current rasters in a
330        # ROMS-CoSiNE-specific directory. These will have the
331        # ROMS-CoSiNE projection, extent, and cell size. We still need
332        # to project them to the simulation's projection, extent, and
333        # cell size.
334
335        romsCurrentsDirectory = os.path.join(simulationDirectory, 'OriginalROMSCurrents')
336        ROMSCoSiNE4D.CreateArcGISRasters(u'u', [depth], romsCurrentsDirectory, rasterNameExpressions=['%(VariableName)s', '%%Y', '%(VariableName)s%%Y%%j0000.img'], startDate=startDate, endDate=endDate, timeout=timeout, maxRetryTime=maxRetryTime, cacheDirectory=cacheDirectory)
337        ROMSCoSiNE4D.CreateArcGISRasters(u'v', [depth], romsCurrentsDirectory, rasterNameExpressions=['%(VariableName)s', '%%Y', '%(VariableName)s%%Y%%j0000.img'], startDate=startDate, endDate=endDate, timeout=timeout, maxRetryTime=maxRetryTime, cacheDirectory=cacheDirectory)
338
339        # Record in the Simulation.ini file that we downloaded some
340        # currents and then project, snap, and clip them to the
341        # projection, extent, and cell size of the reef IDs raster.
342
343        cls._FinishLoadingCurrents(simulationDirectory, scp, thisCurrentsProduct, u'Center', 73*3600, romsCurrentsDirectory, resamplingTechnique, interpolationMethod)
344
345        # Return successfully.
346
347        return simulationDirectory
348
349    @classmethod
350    def _FinishLoadingCurrents(cls, simulationDirectory, scp, currentsProduct, currentsDateType, maxSecondsBetweenCurrentsImages, originalCurrentsDirectory, resamplingTechnique, interpolationMethod):
351
352        # Write the Simulation.ini file, so that any new rasters
353        # loaded into the simulation must be from the same product and
354        # depth.
355           
356        scp.set(u'Simulation', u'CurrentsLoaded', unicode(True))
357        scp.set(u'Simulation', u'CurrentsProduct', currentsProduct)
358        scp.set(u'Simulation', u'CurrentsDateType', currentsDateType)
359        scp.set(u'Simulation', u'MaxSecondsBetweenCurrentsImages', unicode(maxSecondsBetweenCurrentsImages))
360        f = file(os.path.join(simulationDirectory, u'Simulation.ini'), 'w')
361        try:
362            scp.write(f)
363        finally:
364            try:
365                f.close()
366            except:
367                pass
368
369        # Create a temporary copy of the water mask with land set to
370        # No Data.
371
372        from GeoEco.DataManagement.Directories import TemporaryDirectory
373        tempDir = TemporaryDirectory()
374
375        from GeoEco.ArcGIS import GeoprocessorManager
376        gp = GeoprocessorManager.GetWrappedGeoprocessor()
377
378        waterMask = os.path.join(simulationDirectory, u'ReefData', u'water_mask')
379        newWaterMask = os.path.join(tempDir.Path, u'water_mask')
380        gp.SingleOutputMapAlgebra_sa('setnull(%s == 0, %s)' % (waterMask, waterMask), newWaterMask)
381
382        # Using the new water mask as a template, project and clip the
383        # current rasters to the reef rasters' coordinate system, cell
384        # size, and extent.
385
386        from GeoEco.DataManagement.ArcGISRasters import ArcGISRaster
387
388        ArcGISRaster.FindAndProjectRastersToTemplate(originalCurrentsDirectory,
389                                                     os.path.join(simulationDirectory, u'Currents'),
390                                                     newWaterMask,
391                                                     resamplingTechnique,
392                                                     wildcard=u'*.img',
393                                                     searchTree=True,
394                                                     interpolationMethod=interpolationMethod,
395                                                     mask=True,
396                                                     outputRasterPythonExpression=u'os.path.join(outputWorkspace, os.path.splitext(inputRaster[len(workspaceToSearch)+1:])[0])',
397                                                     modulesToImport=[u'os'],
398                                                     skipExisting=True)
399
400    @classmethod
401    def _ReadCurrentsInfoFromSimulationINI(cls, simulationDirectory):
402        if not os.path.isfile(os.path.join(simulationDirectory, u'Simulation.ini')):
403            Logger.RaiseException(ValueError(_(u'The directory %(dir)s does not appear to be a properly-initialized coral reef connectivity simulation directory: it does not contain a file called Simulation.ini. Please create a simulation directory using the Create Coral Reef Connectivity Simulation tool and try again.') % {u'dir': simulationDirectory}))
404
405        from ConfigParser import SafeConfigParser
406
407        scp = SafeConfigParser()
408        f = file(os.path.join(simulationDirectory, u'Simulation.ini'), 'r')
409        try:
410            try:
411                scp.readfp(f, os.path.join(simulationDirectory, u'Simulation.ini'))
412            except:
413                Logger.LogExceptionAsError(_(u'The directory %(dir)s does not appear to be a properly-initialized coral reef connectivity simulation directory: the file Simulation.ini in that directory could not be parsed. Please create a simulation directory using the Create Coral Reef Connectivity Simulation tool and try again.') % {u'dir': simulationDirectory})
414                raise
415        finally:
416            try:
417                f.close()
418            except:
419                pass
420
421        try:
422            crosses180 = scp.getboolean(u'Simulation', u'Crosses180')
423        except:
424            Logger.LogExceptionAsError(_(u'The directory %(dir)s does not appear to be a properly-initialized coral reef connectivity simulation directory: failed to parse a boolean option named Crosses180 from the file Simulation.ini in that directory. Please create a simulation directory using the Create Coral Reef Connectivity Simulation tool and try again.') % {u'dir': simulationDirectory})
425            raise
426
427        try:
428            currentsLoaded = scp.getboolean(u'Simulation', u'CurrentsLoaded')
429        except:
430            Logger.LogExceptionAsError(_(u'The directory %(dir)s does not appear to be a properly-initialized coral reef connectivity simulation directory: failed to parse a boolean option named CurrentsLoaded from the file Simulation.ini in that directory. Please create a simulation directory using the Create Coral Reef Connectivity Simulation tool and try again.') % {u'dir': simulationDirectory})
431            raise
432
433        try:
434            currentsProduct = unicode(scp.get(u'Simulation', u'CurrentsProduct'))
435        except:
436            Logger.LogExceptionAsError(_(u'The directory %(dir)s does not appear to be a properly-initialized coral reef connectivity simulation directory: failed to parse a string option named CurrentsProduct from the file Simulation.ini in that directory. Please create a simulation directory using the Create Coral Reef Connectivity Simulation tool and try again.') % {u'dir': simulationDirectory})
437            raise
438
439        return scp, crosses180, currentsLoaded, currentsProduct
440
441    @classmethod
442    def RunSimulation(cls, simulationDirectory, outputDirectory, startDate, duration=30.0, simulationTimeStep=2.4, summarizationPeriod=10, initialLarvaeDensity=10000.0, densityRasterCutoff=0.1, diffusivity=25.0, includeReefIDs=None, excludeReefIDs=None, overwriteExisting=False):
443        cls.__doc__.Obj.ValidateMethodInvocation()
444
445        # Parse and validate the Simulation.ini file.
446
447        if not os.path.isfile(os.path.join(simulationDirectory, u'Simulation.ini')):
448            Logger.RaiseException(ValueError(_(u'The directory %(dir)s does not appear to be a properly-initialized coral reef connectivity simulation directory: it does not contain a file called Simulation.ini. Please create a simulation directory using the Create Coral Reef Connectivity Simulation tool and try again.') % {u'dir': simulationDirectory}))
449
450        from ConfigParser import SafeConfigParser
451
452        scp = SafeConfigParser()
453        f = file(os.path.join(simulationDirectory, u'Simulation.ini'), 'r')
454        try:
455            try:
456                scp.readfp(f, os.path.join(simulationDirectory, u'Simulation.ini'))
457            except:
458                Logger.LogExceptionAsError(_(u'The directory %(dir)s does not appear to be a properly-initialized coral reef connectivity simulation directory: the file Simulation.ini in that directory could not be parsed. Please create a simulation directory using the Create Coral Reef Connectivity Simulation tool and try again.') % {u'dir': simulationDirectory})
459                raise
460        finally:
461            try:
462                f.close()
463            except:
464                pass
465
466        try:
467            crosses180 = scp.getboolean(u'Simulation', u'Crosses180')
468        except:
469            Logger.LogExceptionAsError(_(u'The directory %(dir)s does not appear to be a properly-initialized coral reef connectivity simulation directory: failed to parse a boolean option named Crosses180 from the file Simulation.ini in that directory. Please create a simulation directory using the Create Coral Reef Connectivity Simulation tool and try again.') % {u'dir': simulationDirectory})
470            raise
471
472        try:
473            currentsLoaded = scp.getboolean(u'Simulation', u'CurrentsLoaded')
474        except:
475            Logger.LogExceptionAsError(_(u'The directory %(dir)s does not appear to be a properly-initialized coral reef connectivity simulation directory: failed to parse a boolean option named CurrentsLoaded from the file Simulation.ini in that directory. Please create a simulation directory using the Create Coral Reef Connectivity Simulation tool and try again.') % {u'dir': simulationDirectory})
476            raise
477        if not currentsLoaded:
478            Logger.RaiseException(ValueError(_(u'The coral reef connectivity simulation in directory %(dir)s does not contain any ocean currents data. Please load ocean currents into it using a tool designed for this purpose, and try again.') % {u'dir': simulationDirectory}))
479
480        try:
481            currentsProduct = unicode(scp.get(u'Simulation', u'CurrentsProduct'))
482        except:
483            Logger.LogExceptionAsError(_(u'The directory %(dir)s does not appear to be a properly-initialized coral reef connectivity simulation directory: failed to parse a string option named CurrentsProduct from the file Simulation.ini in that directory. Please create a simulation directory using the Create Coral Reef Connectivity Simulation tool, load ocean currents into it using a tool designed for this purpose, and try again.') % {u'dir': simulationDirectory})
484            raise
485
486        try:
487            currentsDateType = unicode(scp.get(u'Simulation', u'CurrentsDateType'))
488        except:
489            Logger.LogExceptionAsError(_(u'The directory %(dir)s does not appear to be a properly-initialized coral reef connectivity simulation directory: failed to parse a string option named CurrentsProduct from the file Simulation.ini in that directory. Please create a simulation directory using the Create Coral Reef Connectivity Simulation tool, load ocean currents into it using a tool designed for this purpose, and try again.') % {u'dir': simulationDirectory})
490            raise
491        if currentsDateType.lower() not in [u'center']:
492            Logger.RaiseException(ValueError(_(u'The directory %(dir)s does not appear to be a properly-initialized coral reef connectivity simulation directory: the CurrentsDataType option in the Simulation.ini file has the unknown value %(val)s. Please create a simulation directory using the Create Coral Reef Connectivity Simulation tool, load ocean currents into it using a tool designed for this purpose, and try again.') % {u'dir': simulationDirectory, u'val': currentsDateType}))
493
494        try:
495            maxSecondsBetweenCurrentsImages = scp.getint(u'Simulation', u'MaxSecondsBetweenCurrentsImages')
496        except:
497            Logger.LogExceptionAsError(_(u'The directory %(dir)s does not appear to be a properly-initialized coral reef connectivity simulation directory: failed to parse an integer option named MaxSecondsBetweenCurrentsImages from the file Simulation.ini in that directory. Please create a simulation directory using the Create Coral Reef Connectivity Simulation tool, load ocean currents into it using a tool designed for this purpose, and try again.') % {u'dir': simulationDirectory})
498            raise
499        if maxSecondsBetweenCurrentsImages <= 0:
500            Logger.RaiseException(ValueError(_(u'The directory %(dir)s does not appear to be a properly-initialized coral reef connectivity simulation directory: the MaxSecondsBetweenCurrentsImages option in the Simulation.ini file is less than or equal to zero. It must be greater than zero. Please create a simulation directory using the Create Coral Reef Connectivity Simulation tool, load ocean currents into it using a tool designed for this purpose, and try again.') % {u'dir': simulationDirectory}))
501
502        # Validate other input parameters.
503
504        if duration <= 0:
505            Logger.RaiseException(ValueError(_(u'The simulation duration must be greater than zero.')))
506
507        if duration - simulationTimeStep/24 <= 0:
508            Logger.RaiseException(ValueError(_(u'The time step must be shorter than or equal to the simulation duration. For accurate results, the time step should be significantly shorter than the simulation duration. For example, if the simulation duration is 60 days, a time step of 1 hour would be appropriate.')))
509
510        if includeReefIDs is not None and excludeReefIDs is not None:
511            Logger.RaiseException(ValueError(_(u'You cannot specify both a list of reefs to include and a list of reefs to exclude. You must specify one, or the other, or neither.')))
512
513        # Build lists of the currents rasters that are loaded into the
514        # simulation, and validate that we have currents for the start
515        # date and duration specified by the caller.
516
517        import datetime
518        import glob
519
520        uRasters = glob.glob(os.path.join(simulationDirectory, u'Currents', u'u', u'*', u'u[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]'))
521        uRasters.sort()
522        vRasters = glob.glob(os.path.join(simulationDirectory, u'Currents', u'v', u'*', u'v[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]'))
523        vRasters.sort()
524
525        if len(uRasters) <= 0:
526            Logger.RaiseException(ValueError(_(u'The coral reef connectivity simulation in directory %(dir)s does not contain any ocean currents data. Please load ocean currents into it using a tool designed for this purpose, and try again.') % {u'dir': simulationDirectory}))
527        if len(uRasters) != len(vRasters):
528            Logger.RaiseException(ValueError(_(u'The ocean currents data in the coral reef connectivity simulation in directory %(dir)s appears to be incompletely loaded. The number of "u" rasters does not equal the number of "v" rasters, indicating that the load operation did not complete successfully. Please try loading ocean currents again, and then try to run the simulation.') % {u'dir': simulationDirectory}))
529
530        rasterDates = []
531
532        for i in range(len(uRasters)):
533            uRasterName = os.path.basename(uRasters[i])
534            if uRasterName[1:] != os.path.basename(vRasters[i])[1:]:
535                Logger.RaiseException(ValueError(_(u'The ocean currents data in the coral reef connectivity simulation in directory %(dir)s appears to be incompletely loaded. The "u" raster %(r1)s could not be matched up with a "v" raster with the same date (the next available "v" raster is %(r2)s). Please try loading ocean currents again, and then try to run the simulation.') % {u'dir': simulationDirectory, u'r1': uRasters[i], u'r2': vRasters[i]}))
536            rasterDates.append(datetime.datetime(int(uRasterName[1:5]), 1, 1) + datetime.timedelta(days=int(uRasterName[5:8]) - 1, hours=int(uRasterName[8:10]), minutes=int(uRasterName[10:12])))
537
538        if currentsDateType.lower() == u'center':
539            currentsDateStartDelta = datetime.timedelta(seconds=maxSecondsBetweenCurrentsImages / 2)
540            currentsDateEndDelta = datetime.timedelta(seconds=maxSecondsBetweenCurrentsImages / 2)
541        else:
542            Logger.RaiseException(NotImplementedError(_(u'This tool does not currently support a CurrentsDateType of "%(type)s". Please contact the author of this tool for assistance.') % {u'type': currentsDateType}))
543
544        if startDate < rasterDates[0] - currentsDateStartDelta:
545            Logger.RaiseException(ValueError(_(u'The start date of the simulation (%(start)s) occurs too far before the date of the first ocean currents image (%(date)s) that is loaded in the coral reef connectivity simulation in directory %(dir)s. To fix this problem, either move the start date forward or load some older ocean currents data into the simulation, so that the start date matches up with the currents data.') % {u'dir': simulationDirectory, u'start': str(startDate), u'date': str(rasterDates[0])}))
546
547        if startDate > rasterDates[-1] + currentsDateEndDelta:
548            Logger.RaiseException(ValueError(_(u'The start date of the simulation (%(start)s) occurs too far after the date of the last ocean currents image (%(date)s) that is loaded in the coral reef connectivity simulation in directory %(dir)s. To fix this problem, either move the start date backward or load some more recent ocean currents data into the simulation, so that the start date matches up with the currents data.') % {u'dir': simulationDirectory, u'start': str(startDate), u'date': str(rasterDates[-1])}))
549
550        endDate = startDate + datetime.timedelta(days=duration)
551
552        if endDate > rasterDates[-1] + currentsDateEndDelta:
553            Logger.RaiseException(ValueError(_(u'The end date of the simulation (%(end)s) occurs too far after the date of the last ocean currents image (%(date)s) that is loaded in the coral reef connectivity simulation in directory %(dir)s. To fix this problem, either move the start date backward, reduce the duration of the simulation, or load some more recent ocean currents data into the simulation, so that the end date matches up with the currents data.') % {u'dir': simulationDirectory, u'end': str(endDate), u'date': str(rasterDates[-1])}))
554
555        startRasterIndex = 0
556        while startDate > rasterDates[startRasterIndex] + currentsDateEndDelta:
557            startRasterIndex += 1
558
559        endRasterIndex = startRasterIndex
560        while endDate > rasterDates[endRasterIndex] + currentsDateEndDelta:
561            endRasterIndex += 1
562            if rasterDates[endRasterIndex] - rasterDates[endRasterIndex-1] > datetime.timedelta(seconds=maxSecondsBetweenCurrentsImages):
563                Logger.RaiseException(ValueError(_(u'The ocean currents data that is loaded in the coral reef connectivity simulation in directory %(dir)s has a data gap in the range of dates between the simulation start date (%(start)s) and end date (%(end)s). A gap of %(gap)s occurs between %(d1)s and %(d2)s, which is larger than the maximum time permitted between images (%(max)s) for %(prod)s data. To fix this problem, either adjust the start date or duration, or load ocean currents data into the simulation that fills the gap.') % {u'dir': simulationDirectory, u'start': str(startDate), u'end': str(endDate), u'gap': str(rasterDates[endRasterIndex] - rasterDates[endRasterIndex-1]), u'd1': rasterDates[endRasterIndex-1], u'd2': rasterDates[endRasterIndex], u'max': datetime.timedelta(seconds=maxSecondsBetweenCurrentsImages), u'prod': currentsProduct}))
564
565        # Read the reef rasters and geometry table into 2D numpy
566        # arrays.
567
568        Logger.Info(_(u'Reading coral reef data...'))
569
570        from GeoEco.DataManagement.ArcGISRasters import ArcGISRaster
571
572        reefIDsImage, reefIDsNoDataValue = ArcGISRaster.ToNumpyArray(os.path.join(simulationDirectory, u'ReefData', u'reef_ids'))
573        reefIDsNoDataValue = int(reefIDsNoDataValue)
574        reefCoverImage = ArcGISRaster.ToNumpyArray(os.path.join(simulationDirectory, u'ReefData', u'reef_areas'))[0]
575        waterMaskImage = ArcGISRaster.ToNumpyArray(os.path.join(simulationDirectory, u'ReefData', u'water_mask'))[0]
576
577        from GeoEco.DatabaseAccess.ArcGIS import ArcGIS91DatabaseConnection
578        from GeoEco.DatabaseAccess.InMemory import InMemoryDatabaseConnection
579
580        arcGISConn = ArcGIS91DatabaseConnection()
581        inMemoryConn = InMemoryDatabaseConnection()
582       
583        if includeReefIDs is not None:
584            inMemoryConn.ImportTable(arcGISConn, os.path.join(simulationDirectory, u'ReefData', u'reef_geometry.dbf'), u'reef_geometry', [u'VALUE', u'XCENTROID', u'YCENTROID'], where=u'"VALUE" IN (%s)' % u', '.join(map(unicode, includeReefIDs)), orderBy=[u'VALUE'], directions=[u'Ascending'])
585            if inMemoryConn.GetRowCount(u'reef_geometry') <= 0:
586                Logger.RaiseException(ValueError(_(u'The list of reefs IDs to include in the simulation does contain any IDs that also exist in the simulation directory %(dir)s. Please specify at least one existing reef ID.') % {u'dir': simulationDirectory}))
587               
588        elif excludeReefIDs is not None:
589            inMemoryConn.ImportTable(arcGISConn, os.path.join(simulationDirectory, u'ReefData', u'reef_geometry.dbf'), u'reef_geometry', [u'VALUE', u'XCENTROID', u'YCENTROID'], where=u'"VALUE" NOT IN (%s)' % u', '.join(map(unicode, excludeReefIDs)), orderBy=[u'VALUE'], directions=[u'Ascending'])
590            if inMemoryConn.GetRowCount(u'reef_geometry') <= 0:
591                Logger.RaiseException(ValueError(_(u'The list of reefs IDs to exclude from the simulation excluded all of the reefs in the simulation directory %(dir)s. Please remove some IDs from this list so that at least one reef will be included in the simulation.') % {u'dir': simulationDirectory}))
592
593        else:
594            inMemoryConn.ImportTable(arcGISConn, os.path.join(simulationDirectory, u'ReefData', u'reef_geometry.dbf'), u'reef_geometry', [u'VALUE', u'XCENTROID', u'YCENTROID'], orderBy=[u'VALUE'], directions=[u'Ascending'])
595            if inMemoryConn.GetRowCount(u'reef_geometry') <= 0:
596                Logger.RaiseException(ValueError(_(u'The reef data in simulation directory %(dir)s does not contain any reefs. Please recreate the simulation using input rasters that contain at least one reef.') % {u'dir': simulationDirectory}))
597
598        # Read the ocean currents into parallel lists of 2D numpy
599        # arrays.
600
601        import numpy
602
603        imagesToRead = (endRasterIndex - startRasterIndex + 1) * 2
604        Logger.Info(_(u'Reading %i ocean currents images...') % imagesToRead)
605        progressReporter = ProgressReporter(progressMessage1=_(u'Still reading: %(elapsed)s elapsed, %(opsCompleted)i images read, %(perOp)s per image, %(opsRemaining)i remaining, estimated completion time: %(etc)s.'),
606                                            completionMessage=_(u'Finished reading: %(elapsed)s elapsed, %(opsCompleted)i images read, %(perOp)s per image.'))
607        progressReporter.Start(imagesToRead)
608
609        uImageList = []
610        vImageList = []
611        uvDateList = []
612
613        i = startRasterIndex
614        while i >= startRasterIndex and i <= endRasterIndex:
615            imageDate = rasterDates[i]
616            uvDateList.append(imageDate)
617           
618            image, noDataValue = ArcGISRaster.ToNumpyArray(os.path.join(simulationDirectory, u'Currents', u'u', unicode(imageDate.year), imageDate.strftime('u%Y%j%H%M')))
619            image[image == noDataValue] = numpy.nan
620            uImageList.append(image)
621            progressReporter.ReportProgress()
622           
623            image, noDataValue = ArcGISRaster.ToNumpyArray(os.path.join(simulationDirectory, u'Currents', u'v', unicode(imageDate.year), imageDate.strftime('v%Y%j%H%M')))
624            image[image == noDataValue] = numpy.nan
625            vImageList.append(image)
626            progressReporter.ReportProgress()
627           
628            i += 1
629
630        # Stack the numpy arrays into two 3D arrays that we will pass
631        # to the MATLAB function.
632        #
633        # Note that with numpy, it appears that 2D arrays are
634        # traditionally indexed [y,x] but that 3D arrays are [y,x,t].
635        # This is what is output by numpy's dstack function. This is
636        # kind of screwy, because when you print a 3D numpy array, it
637        # looks much better if ordered [t,y,x] than [y,x,t]. But
638        # MATLAB was the inspiration for numpy and [y,x,t] is
639        # traditional in MATLAB as well. Finally, Eric Treml's
640        # original MATLAB code used [y,x,z].
641
642        uImages = numpy.dstack(tuple(uImageList))
643        del uImageList
644       
645        vImages = numpy.dstack(tuple(vImageList))
646        del vImageList
647
648        # Build a list that specifies the t index into the 3D arrays
649        # for each time step. Note that when we pass this list to
650        # MATLAB, we must increment all of the indices by 1, because
651        # MATLAB uses 1-based indexing (Python uses 0-based).
652
653        import math       
654
655        numTimeSteps = int(math.ceil(duration / (simulationTimeStep/24)))
656        uvIndexForTimestep = [0]
657        for i in range(1, numTimeSteps):
658            if startDate + datetime.timedelta(hours=simulationTimeStep*i) <= uvDateList[uvIndexForTimestep[-1]] + currentsDateEndDelta:
659                uvIndexForTimestep.append(uvIndexForTimestep[-1])
660            else:
661                uvIndexForTimestep.append(uvIndexForTimestep[-1] + 1)
662
663        # Look up the cell size of the rasters.
664
665        from GeoEco.ArcGIS import GeoprocessorManager
666        gp = GeoprocessorManager.GetWrappedGeoprocessor()
667        describeReefIDsRaster = gp.Describe(os.path.join(simulationDirectory, u'ReefData', u'reef_ids'))
668        cellSize = describeReefIDsRaster.MeanCellWidth
669
670        # Calculate and report the maximum Courant number. Issue a
671        # warning if it is greater than or equal to 1.0 because the
672        # simulation is likely to be unstable. Provide an estimate of
673        # the largest time step that would allow the Courant number to
674        # be less than 1.0.
675
676        hasData = numpy.logical_and(numpy.logical_not(numpy.isnan(uImages)), numpy.logical_not(numpy.isnan(vImages)))
677        maxVelocity = max(numpy.max(uImages[hasData]), numpy.max(vImages[hasData]))
678        maxCourant = maxVelocity * (simulationTimeStep*3600) / cellSize
679
680        if maxCourant <= 0.25:
681            Logger.Info(_(u'The maximum Courant number is %(mc)f, which is less than or equal to 0.25. The simulation is likely to be numerically stable.') % {u'mc': maxCourant})
682        else:
683            maxTimeStep = cellSize / maxVelocity / 3600 * 0.25
684            if maxCourant <= 0.5:
685                Logger.Warning(_(u'The maximum Courant number is %(mc)f, which is greater than 0.25 and less than or equal to 0.5. The simulation may exhibit some instability. Please review the results carefully. To improve the chance that the simulation will be stable, we recommend you reduce the time step to %(mts)g or less, so that the maximum Courant number is less than or equal to 0.25.') % {u'mc': maxCourant, u'mts': maxTimeStep})
686            else:
687                Logger.Warning(_(u'The maximum Courant number is %(mc)f, which is greater than 0.5. The simulation is likely to be unstable. Please review the results carefully. To improve the chance that the simulation will be stable, we recommend you reduce the time step to %(mts)g or less, so that the maximum Courant number is less than or equal to 0.25.') % {u'mc': maxCourant, u'mts': maxTimeStep})
688
689        # Create a temporary directory and write the arrays to it in
690        # binary format.
691
692        reefIDs = inMemoryConn.GetFieldValues(u'reef_geometry', u'VALUE')
693
694        from GeoEco.DataManagement.Directories import TemporaryDirectory
695        tempDir = TemporaryDirectory()
696
697        try:
698            reefIDsArray = numpy.array(reefIDs)
699            reefIDsDataType = reefIDsArray.dtype.name
700            reefIDsFile = os.path.join(tempDir.Path, 'ReefIDs.bin')
701            reefIDsArray.tofile(reefIDsFile)
702
703            reefIDsImageDataType = reefIDsImage.dtype.name
704            reefIDsImageFile = os.path.join(tempDir.Path, 'ReefIDsImage.bin')
705            reefIDsImage.tofile(reefIDsImageFile)
706
707            reefCoverImageDataType = reefCoverImage.dtype.name
708            reefCoverImageFile = os.path.join(tempDir.Path, 'ReefCoverImage.bin')
709            reefCoverImage.tofile(reefCoverImageFile)
710
711            waterMaskImageDataType = waterMaskImage.dtype.name
712            waterMaskImageFile = os.path.join(tempDir.Path, 'waterMaskImage.bin')
713            waterMaskImage.tofile(waterMaskImageFile)
714
715            uImagesDataType = uImages.dtype.name
716            uImagesFile = os.path.join(tempDir.Path, 'uImages.bin')
717            uImages.tofile(uImagesFile)
718
719            vImagesDataType = vImages.dtype.name
720            vImagesFile = os.path.join(tempDir.Path, 'vImages.bin')
721            vImages.tofile(vImagesFile)
722
723            uvIndexForTimestepArray = numpy.array(uvIndexForTimestep) + 1
724            uvIndexForTimestepDataType = uvIndexForTimestepArray.dtype.name
725            uvIndexForTimestepFile = os.path.join(tempDir.Path, 'UVIndexForTimestep.bin')
726            uvIndexForTimestepArray.tofile(uvIndexForTimestepFile)
727
728            # Execute RunLarvalDispersal.py to run the simulation.
729            # This script calls MATLAB functions. We prefer to call
730            # those functions directly right here but there is a
731            # continuing incompatibility between MATLAB DLLs and
732            # ArcGIS DLLs (they both try to load their own
733            # incompatible versions of xerces-c_2_7.dll) so we have to
734            # do it in a separate process.
735
736            dispersalMatrixFile = os.path.join(tempDir.Path, u'DispersalMatrix.bin')
737            densityImagesFile = os.path.join(tempDir.Path, u'DensityImages.bin')
738
739            from GeoEco.DataManagement.Processes import ChildProcess
740            import win32api
741
742            ChildProcess.ExecuteProgram(win32api.FindExecutable(os.path.join(os.path.dirname(__file__), 'RunLarvalDispersal.py'), os.path.dirname(__file__))[1],
743                                        arguments=[os.path.join(os.path.dirname(__file__), 'RunLarvalDispersal.py'),
744                                                   repr(uImages.shape[2]),      # t
745                                                   repr(uImages.shape[0]),      # y
746                                                   repr(uImages.shape[1]),      # x
747                                                   reefIDsFile,
748                                                   reefIDsDataType,
749                                                   reefIDsImageFile,
750                                                   reefIDsImageDataType,
751                                                   reefCoverImageFile,
752                                                   reefCoverImageDataType,
753                                                   waterMaskImageFile,
754                                                   waterMaskImageDataType,
755                                                   uImagesFile,
756                                                   uImagesDataType,
757                                                   vImagesFile,
758                                                   vImagesDataType,
759                                                   repr(cellSize),
760                                                   repr(simulationTimeStep * 3600.0),
761                                                   repr(initialLarvaeDensity / 1000000.0),
762                                                   repr(summarizationPeriod),
763                                                   repr(diffusivity),
764                                                   uvIndexForTimestepFile,
765                                                   uvIndexForTimestepDataType,
766                                                   dispersalMatrixFile,
767                                                   densityImagesFile],
768                                        stdoutLogLevel=u'Info',
769                                        windowState=u'invisible',
770                                        maxRunTime=None)
771
772            del uImages, vImages
773
774            # Read the output files.
775
776            dispersalMatrix = numpy.fromfile(dispersalMatrixFile, 'float32')
777            dispersalMatrix = dispersalMatrix.reshape(len(reefIDs), len(reefIDs), len(dispersalMatrix) / len(reefIDs) / len(reefIDs))
778
779            densityImages = numpy.fromfile(densityImagesFile, 'float32')
780            densityImages = densityImages.reshape(reefIDsImage.shape[0], reefIDsImage.shape[1], len(densityImages) / reefIDsImage.shape[0] / reefIDsImage.shape[1])
781
782        finally:
783            del tempDir
784
785        # The DisperseLarvae function returns densities in particles
786        # per square meter. Convert to particles per square km.
787
788        densityImages *= 1000000.0
789
790        # Mask cells that are land and that have a density that is
791        # below the threshold.
792
793        densityImages[waterMaskImage == 0, :] = 0
794        if densityRasterCutoff is not None:
795            densityImages[densityImages < initialLarvaeDensity * densityRasterCutoff / 100.0] = 0
796
797        # Create the output personal geodatabase in the output
798        # directory.
799
800        outputGDB = os.path.join(outputDirectory, u'ConnectivityGeodatabase.mdb')
801        if gp.Exists(outputGDB):
802            if not overwriteExisting:
803                Logger.RaiseException(ValueError(_(u'The output geodatabase %s already exists. Please delete it or specify that existing outputs should be overwritten and try again.') % outputGDB))
804            gp.Delete_management(outputGDB)
805
806        gp.CreatePersonalGDB_management(outputDirectory, u'ConnectivityGeodatabase.mdb')
807
808        # Create the edge list feature class.
809
810        gp.CreateFeatureClass_management(outputGDB, u'Edges', u'POLYLINE', None, u'DISABLED', u'DISABLED', gp.CreateSpatialReference(describeReefIDsRaster.SpatialReference).split(';')[0])
811        gp.AddField_management(os.path.join(outputGDB, u'Edges'), u'FromReefID', u'LONG')
812        gp.AddField_management(os.path.join(outputGDB, u'Edges'), u'ToReefID', u'LONG')
813        gp.AddField_management(os.path.join(outputGDB, u'Edges'), u'MaxDispersal', u'FLOAT')
814
815        # Populate the edge list feature class.
816
817        maxDispersal = dispersalMatrix[:,:,1:].max(2)
818        for fromReef in range(len(reefIDs)):
819            for toReef in range(len(reefIDs)):
820                if fromReef != toReef:
821                    maxDispersal[fromReef, toReef] /= dispersalMatrix[fromReef, fromReef, 0]
822                else:
823                    maxDispersal[fromReef, toReef] = 0
824
825        nonZeroEdges = sum(sum(maxDispersal > 0.0001))
826        xCentroids = inMemoryConn.GetFieldValues(u'reef_geometry', u'XCENTROID')
827        yCentroids = inMemoryConn.GetFieldValues(u'reef_geometry', u'YCENTROID')
828        shapeFieldName = gp.Describe(os.path.join(outputGDB, u'Edges')).ShapeFieldName
829
830        if nonZeroEdges > 0:
831            Logger.Info(_(u'Writing %i edges to the edge list in the output geodatabase...') % nonZeroEdges)
832            cur = arcGISConn.OpenInsertCursor(os.path.join(outputGDB, u'Edges'), rowCount=nonZeroEdges)
833            for fromReef in range(len(reefIDs)):
834                for toReef in range(len(reefIDs)):
835                    if maxDispersal[fromReef, toReef] > 0.0001:
836                        point = gp.CreateObject(u'Point')
837                        line = gp.CreateObject(u'Array')
838                        point.X = xCentroids[fromReef]
839                        point.Y = yCentroids[fromReef]
840                        line.Add(point)
841                        point.X = xCentroids[toReef]
842                        point.Y = yCentroids[toReef]
843                        line.Add(point)
844                        cur.SetValue(shapeFieldName, line)
845                        cur.SetValue(u'FromReefID', reefIDs[fromReef])
846                        cur.SetValue(u'ToReefID', reefIDs[toReef])
847                        cur.SetValue(u'MaxDispersal', float(maxDispersal[fromReef, toReef]))        # Must convert from numpy float to Python float
848                        cur.InsertRow()
849        else:
850            Logger.Warning(_(u'The edge list in the output geodatabase will be empty because none of the reefs are connected.'))
851
852        # Create the DensityRasters subdirectory, if it does not
853        # already exist.
854       
855        from GeoEco.DataManagement.Directories import Directory
856        from GeoEco.DataManagement.ArcGISRasters import ArcGISRaster
857             
858        if not Directory.Exists(os.path.join(outputDirectory, u'DensityRasters'))[0]:
859            Directory.Create(os.path.join(outputDirectory, u'DensityRasters'))
860
861        # If the directory already exists and the caller requested
862        # that we overwrite existing outputs, delete any existing
863        # density rasters.
864
865        elif overwriteExisting:
866            oldLogInfoAsDebug = Logger.GetLogInfoAsDebug()
867            Logger.SetLogInfoAsDebug(True)
868            try:
869                ArcGISRaster.FindAndDelete(os.path.join(outputDirectory, u'DensityRasters'), u'*')
870            finally:
871                Logger.SetLogInfoAsDebug(oldLogInfoAsDebug)
872
873        # Create the density rasters in the subdirectory.
874
875        coordinateSystem = gp.CreateSpatialReference(describeReefIDsRaster.SpatialReference).split(';')[0]
876
877        Logger.Info(_(u'Writing %i density rasters to the output directory...') % densityImages.shape[2])
878        progressReporter = ProgressReporter(progressMessage1=_(u'Still writing density rasters: %(elapsed)s elapsed, %(opsCompleted)i rasters written, %(perOp)s per raster, %(opsRemaining)i remaining, estimated completion time: %(etc)s.'),
879                                            completionMessage=_(u'Finished writing density rasters: %(elapsed)s elapsed, %(opsCompleted)i rasters written, %(perOp)s per raster.'))
880        progressReporter.Start(densityImages.shape[2])
881
882        for i in range(densityImages.shape[2]):
883            oldLogInfoAsDebug = Logger.GetLogInfoAsDebug()
884            Logger.SetLogInfoAsDebug(True)
885            try:
886                ArcGISRaster.FromNumpyArray(densityImages[:,:,i].copy(),    # Copy is currently needed because the current implementation of ArcGISRaster.FromNumpyArray requires the array to be in C order.
887                                            os.path.join(outputDirectory, u'DensityRasters', (startDate + datetime.timedelta(seconds=simulationTimeStep*3600.0*summarizationPeriod*i)).strftime('d%Y%j%H%M')),
888                                            EnvelopeTypeMetadata.ParseFromArcGISString(describeReefIDsRaster.Extent)[0],
889                                            EnvelopeTypeMetadata.ParseFromArcGISString(describeReefIDsRaster.Extent)[1],
890                                            cellSize,
891                                            nodataValue=0,
892                                            coordinateSystem=coordinateSystem,
893                                            buildPyramids=True,
894                                            overwriteExisting=overwriteExisting)
895            finally:
896                Logger.SetLogInfoAsDebug(oldLogInfoAsDebug)
897
898            progressReporter.ReportProgress()
899
900        # Create a raster catalog in the output geodatabase for
901        # the density rasters, so they can be easily animated. Add
902        # and populate StartTime and EndTime fields, which define
903        # the period for which the raster applies, as recommended
904        # by the ArcGIS documentation.
905
906        Logger.Info(_(u'Creating a raster catalog for the density rasters...'))
907
908        gp.CreateRasterCatalog_management(outputGDB, u'DensityRasters', coordinateSystem, coordinateSystem, None, None, None, None, u'Unmanaged')
909        gp.AddField_management(os.path.join(outputGDB, u'DensityRasters'), u'StartTime', u'DATE')
910        gp.AddField_management(os.path.join(outputGDB, u'DensityRasters'), u'EndTime', u'DATE')
911        gp.WorkspaceToRasterCatalog(os.path.join(outputDirectory, u'DensityRasters'), os.path.join(outputGDB, u'DensityRasters'))
912
913        # Populate the StartTime and EndTime fields of the raster
914        # catalog. Originally, I implemented this using the ArcGIS
915        # Calculate Fields tool, but it kept crashing in 9.3,
916        # regardless of whether I used Python or VB, and regardless of
917        # whether I created the geoprocessor using
918        # arcgisscripting.create or win32com.client.Dispatch. To work
919        # around this ArcGIS bug, I'm using the MGET Calculate Fields
920        # tool instead. It is slower (due to slow ArcGIS cursors) but
921        # does not crash.
922
923        from GeoEco.DataManagement.Fields import Field
924        Field.CalculateFields(arcGISConn, os.path.join(outputGDB, u'DensityRasters'), [u'StartTime', u'EndTime'], [u"(datetime.datetime(int(row.Name[1:5]), 1, 1, int(row.Name[8:10]), int(row.Name[10:12])) + datetime.timedelta(days=int(row.Name[5:8])-1)).strftime('%Y-%m-%d %H:%M:%S')", u"(datetime.datetime(int(row.Name[1:5]), 1, 1, int(row.Name[8:10]), int(row.Name[10:12])) + datetime.timedelta(days=int(row.Name[5:8])-1) + datetime.timedelta(seconds=" + unicode(simulationTimeStep*3600.0*summarizationPeriod) + u")).strftime('%Y-%m-%d %H:%M:%S')"], modulesToImport=[u'datetime'])
925
926        # Return successfully.
927
928        return outputDirectory
929
930
931class _AvisoCurrentsInMetersPerSecond(AvisoGriddedGeostrophicCurrents):
932    __doc__ = DynamicDocString()
933
934    def _ReadNumpyArray(self, sliceList):
935
936        # Aviso provides geostrophic currents in cm/s but we require
937        # them to be in m/s. Convert them.
938
939        data, noDataValue = super(_AvisoCurrentsInMetersPerSecond, self)._ReadNumpyArray(sliceList)
940        data[data != noDataValue] /= 100.
941        return data, noDataValue
942
943    @classmethod
944    def CreateArcGISRasters(cls, username, password, productName, vectorComponent,
945                            outputWorkspace, mode=u'add', rasterNameExpressions=['%(Region)s', '%(DataSeries)s', '%(Satellites)s', '%(Variable)s', '%%Y', '%(DataSeries)s_%(Satellites)s_%(Variable)s_%%Y%%j.img'],
946                            rotationOffset=None, spatialExtent=None, linearUnit=u'Degrees', startDate=None, endDate=None,
947                            timeout=60, maxRetryTime=120, cacheDirectory=None,
948                            calculateStatistics=True, buildPyramids=False):
949        grid = _AvisoCurrentsInMetersPerSecond(productName, vectorComponent, username, password, timeout, maxRetryTime, cacheDirectory)
950        _AvisoGriddedProduct.CreateArcGISRasters(grid, outputWorkspace, mode, rasterNameExpressions, rotationOffset, spatialExtent, linearUnit, startDate, endDate, calculateStatistics, buildPyramids)
951        return outputWorkspace
952
953
954###############################################################################
955# Metadata: module
956###############################################################################
957
958from GeoEco.ArcGIS import ArcGISDependency, ArcGISExtensionDependency
959from GeoEco.Dependencies import PythonAggregatedModuleDependency
960from GeoEco.Matlab import MatlabDependency
961from GeoEco.Metadata import *
962from GeoEco.Types import *
963
964AddModuleMetadata(shortDescription=_(u'Implements Eric Treml\'s coral reef connectivity analysis.'))
965
966###############################################################################
967# Metadata: CoralReefConnectivity class
968###############################################################################
969
970AddClassMetadata(CoralReefConnectivity,
971    shortDescription=_(u'Implements Eric Treml\'s coral reef connectivity analysis.'),
972    isExposedAsCOMServer=True,
973    comIID=u'{1B3A8B7F-8921-4A69-AF39-D209FAA0D588}',
974    comCLSID=u'{BAD2EBA8-1077-4A5B-B737-D4906466B60A}')
975
976# Public method: CoralReefConnectivity.CreateSimulationFromArcGISRasters
977
978AddMethodMetadata(CoralReefConnectivity.CreateSimulationFromArcGISRasters,
979    shortDescription=_(u'Creates a coral reef connectivity simulation and initializes it with reef data in ArcGIS rasters.'),
980    isExposedToPythonCallers=True,
981    isExposedByCOM=True,
982    isExposedAsArcGISTool=True,
983    arcGISDisplayName=_(u'Create Coral Reef Connectivity Simulation From ArcGIS Rasters'),
984    arcGISToolCategory=_(u'Connectivity Analysis\\Coral Reef Larval Connectivity'),
985    dependencies=[ArcGISDependency(9, 2), ArcGISExtensionDependency(u'spatial'), PythonAggregatedModuleDependency('numpy')])
986
987AddArgumentMetadata(CoralReefConnectivity.CreateSimulationFromArcGISRasters, u'cls',
988    typeMetadata=ClassOrClassInstanceTypeMetadata(cls=CoralReefConnectivity),
989    description=_(u'%s class or an instance of it.') % CoralReefConnectivity.__name__)
990
991AddArgumentMetadata(CoralReefConnectivity.CreateSimulationFromArcGISRasters, u'simulationDirectory',
992    typeMetadata=DirectoryTypeMetadata(deleteIfParameterIsTrue=u'overwriteExisting', createParentDirectories=True),
993    description=_(
994u"""Output directory to create to contain the simulation's data.
995
996After creating the simulation directory, you must load ocean currents
997data into it using other tools before you can run the simulation. Use
998the MGET tools designed for this purpose. Unless you know what you are
999doing, do not modify the contents of the simulation directory
1000yourself."""),
1001    direction=u'Output',
1002    arcGISDisplayName=_(u'Simulation directory to create'))
1003
1004AddArgumentMetadata(CoralReefConnectivity.CreateSimulationFromArcGISRasters, u'reefIDsRaster',
1005    typeMetadata=ArcGISRasterLayerTypeMetadata(mustExist=True, allowedPixelTypes=[u'S8', u'U8', u'S16', u'U16', u'S32', u'U32', u'S64', u'U64']),
1006    description=_(
1007u"""Integer raster specifying the locations and IDs of reefs.
1008
1009The raster value specifies the ID of the reef contained by that cell.
1010NoData indicates that the cell does not contain a reef. The value 0
1011may not be used as a reef ID.
1012
1013The raster also defines the coordinate system, extent, and cell size
1014for the analysis. The raster must use a projected coordinate system,
1015with meters as the linear unit. The reef cover and water mask rasters
1016must have the same coordinate system, extent, and cell size. When
1017ocean currents data are loaded into the simulation, they will be
1018automatically projected and clipped as needed into this coordinate
1019system, extent, and cell size."""),
1020    arcGISDisplayName=_(u'Reef IDs raster'))
1021
1022AddArgumentMetadata(CoralReefConnectivity.CreateSimulationFromArcGISRasters, u'reefCoverRaster',
1023    typeMetadata=ArcGISRasterLayerTypeMetadata(mustExist=True),
1024    description=_(
1025u"""Floating-point raster specifying the proportion of each cell's
1026area that is occupied by reef.
1027
1028This raster determines the density of coral larvae released into the
1029cell at the start of the simulation. The density for a cell is
1030determined by multiplying this raster's value by the larvae density
1031parameter you specify when you run the simulation.
1032
1033This raster must have the same coordinate system, extent, and cell
1034size as the reef IDs raster.
1035
1036The raster values must be greater than or equal to 0 and less than or
1037equal to 1. The value 1 indicates that the entire cell is occupied by
1038reef, while 0.5 indicates that only half of it is. If the cell size
1039was 25 km by 25 km, this would mean the cell contained either 625 or
1040312.5 square km of reef, respectively.
1041
1042If the value is 0 or NoData, it is assumed that the cell does not
1043contain any reef, even if the reef IDs raster indicates that a reef is
1044there. If the value is greater than 0 but the corresponding reef IDs
1045raster contains NoData, it is assumed that the cell does not contain
1046any reef."""),
1047    arcGISDisplayName=_(u'Reef cover raster'))
1048
1049AddArgumentMetadata(CoralReefConnectivity.CreateSimulationFromArcGISRasters, u'waterMaskRaster',
1050    typeMetadata=ArcGISRasterLayerTypeMetadata(mustExist=True),
1051    description=_(
1052u"""Raster specifying the locations of land and water. 0 or NoData
1053indicates land; any other value indicates water.
1054
1055This raster must have the same coordinate system, dimensions, and cell
1056size as the reef IDs raster."""),
1057    arcGISDisplayName=_(u'Water mask raster'))
1058
1059AddArgumentMetadata(CoralReefConnectivity.CreateSimulationFromArcGISRasters, u'crosses180',
1060    typeMetadata=BooleanTypeMetadata(),
1061    description=_(
1062u"""Set this option to True if your study area crosses the 180th
1063meridian (i.e. 180 W / 180 E). This will happen if you are studying
1064reefs in the tropical Pacific, for example."""),
1065    arcGISDisplayName=_(u'Study area crosses the 180th meridian'))
1066
1067AddArgumentMetadata(CoralReefConnectivity.CreateSimulationFromArcGISRasters, u'overwriteExisting',
1068    typeMetadata=BooleanTypeMetadata(),
1069    description=_(
1070u"""If True, the simulation directory will be deleted and recreated,
1071if it exists. If False, a ValueError will be raised if the simulation
1072directory exists."""),
1073    initializeToArcGISGeoprocessorVariable=u'OverwriteOutput')
1074
1075# Public method: CoralReefConnectivity.LoadAvisoGeostrophicCurrentsIntoSimulation
1076
1077AddMethodMetadata(CoralReefConnectivity.LoadAvisoGeostrophicCurrentsIntoSimulation,
1078    shortDescription=_(u'Downloads Aviso geostrophic currents into a coral reef connectivity simulation.'),
1079    longDescription=_AvisoGriddedProduct_LongDescription % {u'name': 'tool'},
1080    isExposedToPythonCallers=True,
1081    isExposedByCOM=True,
1082    isExposedAsArcGISTool=True,
1083    arcGISDisplayName=_(u'Load Aviso Geostrophic Currents Into Coral Reef Connectivity Simulation'),
1084    arcGISToolCategory=_(u'Connectivity Analysis\\Coral Reef Larval Connectivity'),
1085    dependencies=[ArcGISDependency(9, 2), ArcGISExtensionDependency(u'spatial'), PythonAggregatedModuleDependency('numpy')])
1086
1087CopyArgumentMetadata(CoralReefConnectivity.CreateSimulationFromArcGISRasters, u'cls', CoralReefConnectivity.LoadAvisoGeostrophicCurrentsIntoSimulation, u'cls')
1088
1089AddArgumentMetadata(CoralReefConnectivity.LoadAvisoGeostrophicCurrentsIntoSimulation, u'simulationDirectory',
1090    typeMetadata=DirectoryTypeMetadata(mustExist=True),
1091    description=_(
1092u"""Existing coral reef connectivity simulation directory that should
1093recieve the geostrophic currents data.
1094
1095The directory must have been created using the Create Coral Reef
1096Connectivity Simulation tool.
1097
1098If you have already loaded geostrophic currents data into the
1099simulation, you can use this tool to add data for an additional range
1100of dates so long as the data is from the same Aviso product. If you
1101try to add a different product to existing data, this tool will report
1102an error.
1103
1104If you try to load data for a range of dates that have been already
1105loaded into the simulation, the downloads for those dates will be
1106skipped. There is no way to delete or overwrite the data that has
1107already been loaded into the simulation. If you want to overwrite your
1108existing data (e.g. you want to switch to using a different Aviso
1109product), you must create a new simulation."""),
1110    arcGISDisplayName=_(u'Simulation directory to recieve geostrophic currents data'))
1111
1112CopyArgumentMetadata(AvisoGriddedGeostrophicCurrents.CreateArcGISRasters, u'username', CoralReefConnectivity.LoadAvisoGeostrophicCurrentsIntoSimulation, u'username')
1113CopyArgumentMetadata(AvisoGriddedGeostrophicCurrents.CreateArcGISRasters, u'password', CoralReefConnectivity.LoadAvisoGeostrophicCurrentsIntoSimulation, u'password')
1114
1115AddArgumentMetadata(CoralReefConnectivity.LoadAvisoGeostrophicCurrentsIntoSimulation, u'product',
1116    typeMetadata=UnicodeStringTypeMetadata(allowedValues=filter(lambda s: s.find(u'MADT') >= 0, AvisoGriddedGeostrophicCurrents.Products)),
1117    description=_(
1118u"""Aviso geostrophic currents product to load into the simulation.
1119Please see the Aviso web site (http://www.aviso.oceanobs.com) for
1120descriptions of the products.
1121
1122At the time of this writing, this tool supported all of the
1123geostrophic currents products that Aviso made available for download
1124over OPeNDAP. If you find that Aviso publishes a new product that is
1125not available using this tool, please contact the author of this tool
1126to have support for it added.
1127
1128The product name that you must pass for this parameter is case
1129sensitive. If you invoke this tool programmatically, be sure to
1130specify the product name using the proper case."""),
1131    arcGISDisplayName=_(u'Aviso geostrophic currents product to download'))
1132
1133AddArgumentMetadata(CoralReefConnectivity.LoadAvisoGeostrophicCurrentsIntoSimulation, u'startDate',
1134    typeMetadata=DateTimeTypeMetadata(),
1135    description=_(
1136u"""Start date for the data to load into the simulation. Data that
1137occurs on or after the start date and on or before the end date will
1138be loaded into the simulation."""),
1139    arcGISDisplayName=_(u'Start date'))
1140
1141AddArgumentMetadata(CoralReefConnectivity.LoadAvisoGeostrophicCurrentsIntoSimulation, u'endDate',
1142    typeMetadata=DateTimeTypeMetadata(),
1143    description=_(
1144u"""End date for the data to load into the simulation. Data that
1145occurs on or after the start date and on or before the end date will
1146be loaded into the simulation."""),
1147    arcGISDisplayName=_(u'End date'))
1148
1149AddArgumentMetadata(CoralReefConnectivity.LoadAvisoGeostrophicCurrentsIntoSimulation, u'resamplingTechnique',
1150    typeMetadata=UnicodeStringTypeMetadata(makeLowercase=True, allowedValues=[u'BILINEAR', u'CUBIC']),
1151    description=_(
1152u"""Resampling algorithm to be used when projecting the ocean currents
1153data to the coordinate system and cell size of the simulation. One of:
1154
1155* BILINEAR - `Bilinear interpolation
1156  <http://en.wikipedia.org/wiki/Bilinear_interpolation>`_.
1157
1158* CUBIC - Cubic convolution, also known as `bicubic interpolation
1159  <http://en.wikipedia.org/wiki/Bicubic_interpolation>`_. This method
1160  is slower but we believe it produces more accurate values.
1161
1162The projection is accomplished with the ArcGIS Project Raster tool.
1163Please see the documentation for that tool for more information."""),
1164    arcGISDisplayName=_(u'Resampling technique'))
1165
1166AddArgumentMetadata(CoralReefConnectivity.LoadAvisoGeostrophicCurrentsIntoSimulation, u'interpolationMethod',
1167    typeMetadata=UnicodeStringTypeMetadata(makeLowercase=True, allowedValues=[u'Del2a', u'Del2b', u'Del2c', u'Del4', u'Spring'], canBeNone=True),
1168    description=_(
1169u"""Method to use to guess ocean current values for cells marked as
1170water by the simulation's water mask but for which no estimate is
1171available in the currents data.
1172
1173By default, this option is disabled and cells marked as water that do
1174not have any currents data are assumed to have a current velocity of
1175zero. Larvae within these cells cannot exit by advection, only by
1176diffusion. Because diffusion typically disperses larvae much more
1177slowly than advection, these zero-velocity cells will act as larvae
1178sinks that appear to trap most larvae that enter them.
1179
1180That situation is usually urealistic and undesirable, and when it
1181happens the simulator will issue a warning describing the problem. If
1182you experience this problem you can instruct the tool to guess current
1183values using one of the following algorithms:
1184
1185* Del2a - Laplacian interpolation and linear extrapolation. We
1186  recommend you use this method unless you have a specific reason to
1187  select one of the others.
1188
1189* Del2b - Same as Del2a but does not build as large a linear system of
1190  equations. May be faster than Del2a at the cost of some accuracy.
1191
1192* Del2c - Same as Del2a but solves a direct linear system of equations
1193  for the No Data values. Faster than both Del2a and Del2b but is the
1194  least robust to noise on the boundaries of No Data cells and least
1195  able to interpolate accurately for smooth surfaces.
1196
1197* Del4 - Same as Del2a but instead of the Laplace operator (also
1198  called the del^2 operator) it uses the biharmonic operator (also
1199  called the del^4 operator). May result in more accurate
1200  interpolations, at some cost in speed.
1201
1202* Spring - Uses a spring metaphor. Assumes springs (with a nominal
1203  length of zero) connect each cell with every neighbor (horizontally,
1204  vertically and diagonally). Since each cell tries to be like its
1205  neighbors, extrapolation is as a constant function where this is
1206  consistent with the neighboring nodes.
1207
1208Be advised that this option should be considered a last resort. When
1209ocean current values are missing for a region, it is because the
1210original data provider does not know how to estimate or model the
1211currents in that region. If it was simply a matter of using one of the
1212methods above, they would have already done so. These methods produce
1213estimates that are likely to be inaccurate and should only be used
1214when you are willing to accept those inaccuracies because there is no
1215other way to proceed.
1216
1217Thanks to John D'Errico for providing the code that implements the
1218mathematical algorithms described here (click `here
1219<http://www.mathworks.com/matlabcentral/fileexchange/4551>`_ for more
1220information)."""),
1221    arcGISDisplayName=_(u'Method for estimating missing currents values'))
1222
1223CopyArgumentMetadata(AvisoGriddedGeostrophicCurrents.CreateArcGISRasters, u'timeout', CoralReefConnectivity.LoadAvisoGeostrophicCurrentsIntoSimulation, u'timeout')
1224CopyArgumentMetadata(AvisoGriddedGeostrophicCurrents.CreateArcGISRasters, u'maxRetryTime', CoralReefConnectivity.LoadAvisoGeostrophicCurrentsIntoSimulation, u'maxRetryTime')
1225CopyArgumentMetadata(AvisoGriddedGeostrophicCurrents.CreateArcGISRasters, u'cacheDirectory', CoralReefConnectivity.LoadAvisoGeostrophicCurrentsIntoSimulation, u'cacheDirectory')
1226
1227AddResultMetadata(CoralReefConnectivity.LoadAvisoGeostrophicCurrentsIntoSimulation, u'updatedSimulationDirectory',
1228    typeMetadata=DirectoryTypeMetadata(),
1229    description=_(u'Updated simulation directory.'),
1230    arcGISDisplayName=_(u'Updated simulation directory'))
1231
1232# Public method: CoralReefConnectivity.LoadOSCARCurrentsIntoSimulation
1233
1234AddMethodMetadata(CoralReefConnectivity.LoadOSCARCurrentsIntoSimulation,
1235    shortDescription=_(u'Downloads NOAA OSCAR 5-day unfiltered 1/3 degree ocean surface currents into a coral reef connectivity simulation.'),
1236    longDescription=_OSCAR_LongDescription % {u'name': 'tool'},
1237    isExposedToPythonCallers=True,
1238    isExposedByCOM=True,
1239    isExposedAsArcGISTool=True,
1240    arcGISDisplayName=_(u'Load OSCAR Currents Into Coral Reef Connectivity Simulation'),
1241    arcGISToolCategory=_(u'Connectivity Analysis\\Coral Reef Larval Connectivity'),
1242    dependencies=[ArcGISDependency(9, 2), ArcGISExtensionDependency(u'spatial'), PythonAggregatedModuleDependency('numpy')])
1243
1244CopyArgumentMetadata(CoralReefConnectivity.CreateSimulationFromArcGISRasters, u'cls', CoralReefConnectivity.LoadOSCARCurrentsIntoSimulation, u'cls')
1245
1246AddArgumentMetadata(CoralReefConnectivity.LoadOSCARCurrentsIntoSimulation, u'simulationDirectory',
1247    typeMetadata=DirectoryTypeMetadata(mustExist=True),
1248    description=_(
1249u"""Existing coral reef connectivity simulation directory that should
1250recieve the OSCAR currents data.
1251
1252The directory must have been created using the Create Coral Reef
1253Connectivity Simulation tool.
1254
1255If you have already loaded OSCAR currents data into the simulation,
1256you can use this tool to add data for an additional range of dates. If
1257you try to load data for a range of dates that have been already
1258loaded into the simulation, the downloads for those dates will be
1259skipped."""),
1260    arcGISDisplayName=_(u'Simulation directory to recieve OSCAR currents data'))
1261
1262CopyArgumentMetadata(CoralReefConnectivity.LoadAvisoGeostrophicCurrentsIntoSimulation, u'startDate', CoralReefConnectivity.LoadOSCARCurrentsIntoSimulation, u'startDate')
1263CopyArgumentMetadata(CoralReefConnectivity.LoadAvisoGeostrophicCurrentsIntoSimulation, u'endDate', CoralReefConnectivity.LoadOSCARCurrentsIntoSimulation, u'endDate')
1264CopyArgumentMetadata(CoralReefConnectivity.LoadAvisoGeostrophicCurrentsIntoSimulation, u'resamplingTechnique', CoralReefConnectivity.LoadOSCARCurrentsIntoSimulation, u'resamplingTechnique')
1265CopyArgumentMetadata(CoralReefConnectivity.LoadAvisoGeostrophicCurrentsIntoSimulation, u'interpolationMethod', CoralReefConnectivity.LoadOSCARCurrentsIntoSimulation, u'interpolationMethod')
1266CopyArgumentMetadata(OSCAR5DayThirdDegreeCurrents.CreateArcGISRasters, u'timeout', CoralReefConnectivity.LoadOSCARCurrentsIntoSimulation, u'timeout')
1267CopyArgumentMetadata(OSCAR5DayThirdDegreeCurrents.CreateArcGISRasters, u'maxRetryTime', CoralReefConnectivity.LoadOSCARCurrentsIntoSimulation, u'maxRetryTime')
1268CopyArgumentMetadata(OSCAR5DayThirdDegreeCurrents.CreateArcGISRasters, u'cacheDirectory', CoralReefConnectivity.LoadOSCARCurrentsIntoSimulation, u'cacheDirectory')
1269
1270CopyResultMetadata(CoralReefConnectivity.LoadAvisoGeostrophicCurrentsIntoSimulation, u'updatedSimulationDirectory', CoralReefConnectivity.LoadOSCARCurrentsIntoSimulation, u'updatedSimulationDirectory')
1271
1272# Public method: CoralReefConnectivity.LoadHYCOMGOMl0044DCurrentsIntoSimulation
1273
1274AddMethodMetadata(CoralReefConnectivity.LoadHYCOMGOMl0044DCurrentsIntoSimulation,
1275    shortDescription=_(u'Downloads HYCOM GOMl0.04 ocean currents into a coral reef connectivity simulation.'),
1276    longDescription=_HYCOMGOMl004_LongDescription % {u'name': 'tool'},
1277    isExposedToPythonCallers=True,
1278    isExposedByCOM=True,
1279    isExposedAsArcGISTool=True,
1280    arcGISDisplayName=_(u'Load HYCOM GOMl0.04 Currents Into Coral Reef Connectivity Simulation'),
1281    arcGISToolCategory=_(u'Connectivity Analysis\\Coral Reef Larval Connectivity'),
1282    dependencies=[ArcGISDependency(9, 2), ArcGISExtensionDependency(u'spatial'), PythonAggregatedModuleDependency('numpy')])
1283
1284CopyArgumentMetadata(CoralReefConnectivity.LoadAvisoGeostrophicCurrentsIntoSimulation, u'cls', CoralReefConnectivity.LoadHYCOMGOMl0044DCurrentsIntoSimulation, u'cls')
1285
1286AddArgumentMetadata(CoralReefConnectivity.LoadHYCOMGOMl0044DCurrentsIntoSimulation, u'simulationDirectory',
1287    typeMetadata=DirectoryTypeMetadata(mustExist=True),
1288    description=_(
1289u"""Existing coral reef connectivity simulation directory that should
1290recieve the currents.
1291
1292The directory must have been created using the Create Coral Reef
1293Connectivity Simulation tool.
1294
1295If you have already loaded HYCOM GOMl0.04 currents into the
1296simulation, you can use this tool to add currents for an additional
1297range of dates so long as they are for the same depth as the original
1298currents. If you try to add a different currents product to the
1299simulation (e.g. geostrophic currents from Aviso), or for a different
1300depth, this tool will report an error.
1301
1302If you try to load data for a range of dates that have been already
1303loaded into the simulation, the downloads for those dates will be
1304skipped. There is no way to delete or overwrite the data that has
1305already been loaded into the simulation. If you want to overwrite your
1306existing data (e.g. you want to switch to using a different depth),
1307you must create a new simulation."""),
1308    arcGISDisplayName=_(u'Simulation directory to recieve HYCOM currents'))
1309
1310CopyArgumentMetadata(CoralReefConnectivity.LoadAvisoGeostrophicCurrentsIntoSimulation, u'startDate', CoralReefConnectivity.LoadHYCOMGOMl0044DCurrentsIntoSimulation, u'startDate')
1311CopyArgumentMetadata(CoralReefConnectivity.LoadAvisoGeostrophicCurrentsIntoSimulation, u'endDate', CoralReefConnectivity.LoadHYCOMGOMl0044DCurrentsIntoSimulation, u'endDate')
1312
1313AddArgumentMetadata(CoralReefConnectivity.LoadHYCOMGOMl0044DCurrentsIntoSimulation, u'depth',
1314    typeMetadata=FloatTypeMetadata(allowedValues=[0., 5., 10., 15., 20., 25., 30., 40., 50., 60., 70., 80., 90., 100., 125., 150., 200., 250., 300., 400., 500., 600., 700., 800., 900., 1000., 1100., 1200., 1300., 1400., 1500., 1750., 2000., 2500., 3000., 3500., 4000., 4500., 5000., 5500.]),
1315    description=_(
1316u"""HYCOM depth layer to download currents from.
1317
1318This tool was designed primarily to study larvae that float at or near
1319the surface. The default depth is 0. If you are studying larvae that
1320stay submerged, you can choose a deeper depth, but be aware of two
1321important points:
1322
1323* This tool assumes the larvae remain at that depth for the entire
1324  simulation. It does not implement vertical migration or other
1325  behaviors that might be appropriate for your species. A newer
1326  version of this tool, to be released in 2012, will support vertical
1327  migration.
1328
1329* Be aware that the spatial extent of available currents data will
1330  shrink as depth increases. For example, if you choose a deep depth
1331  such as 250 m, there will be no data available for regions close to
1332  shore because the ocean is typically shallower than 250 m in those
1333  regions. Data for very deep depths will only be available near the
1334  center of the Gulf of Mexico.
1335"""),
1336    arcGISDisplayName=_(u'Depth'))
1337
1338CopyArgumentMetadata(CoralReefConnectivity.LoadAvisoGeostrophicCurrentsIntoSimulation, u'resamplingTechnique', CoralReefConnectivity.LoadHYCOMGOMl0044DCurrentsIntoSimulation, u'resamplingTechnique')
1339CopyArgumentMetadata(CoralReefConnectivity.LoadAvisoGeostrophicCurrentsIntoSimulation, u'interpolationMethod', CoralReefConnectivity.LoadHYCOMGOMl0044DCurrentsIntoSimulation, u'interpolationMethod')
1340CopyArgumentMetadata(HYCOMGOMl0044D.CreateArcGISRasters, u'timeout', CoralReefConnectivity.LoadHYCOMGOMl0044DCurrentsIntoSimulation, u'timeout')
1341CopyArgumentMetadata(HYCOMGOMl0044D.CreateArcGISRasters, u'maxRetryTime', CoralReefConnectivity.LoadHYCOMGOMl0044DCurrentsIntoSimulation, u'maxRetryTime')
1342CopyArgumentMetadata(HYCOMGOMl0044D.CreateArcGISRasters, u'cacheDirectory', CoralReefConnectivity.LoadHYCOMGOMl0044DCurrentsIntoSimulation, u'cacheDirectory')
1343
1344CopyResultMetadata(CoralReefConnectivity.LoadAvisoGeostrophicCurrentsIntoSimulation, u'updatedSimulationDirectory', CoralReefConnectivity.LoadHYCOMGOMl0044DCurrentsIntoSimulation, u'updatedSimulationDirectory')
1345
1346# Public method: CoralReefConnectivity.LoadHYCOMGLBa0084DEquatorialCurrentsIntoSimulation
1347
1348AddMethodMetadata(CoralReefConnectivity.LoadHYCOMGLBa0084DEquatorialCurrentsIntoSimulation,
1349    shortDescription=_(u'Downloads HYCOM GLBa0.08 ocean currents into a coral reef connectivity simulation.'),
1350    longDescription=_HYCOMGLBa008Equatorial_LongDescription % {u'name': 'tool'},
1351    isExposedToPythonCallers=True,
1352    isExposedByCOM=True,
1353    isExposedAsArcGISTool=True,
1354    arcGISDisplayName=_(u'Load HYCOM GLBa0.08 Currents Into Coral Reef Connectivity Simulation'),
1355    arcGISToolCategory=_(u'Connectivity Analysis\\Coral Reef Larval Connectivity'),
1356    dependencies=[ArcGISDependency(9, 2), ArcGISExtensionDependency(u'spatial'), PythonAggregatedModuleDependency('numpy')])
1357
1358CopyArgumentMetadata(CoralReefConnectivity.LoadAvisoGeostrophicCurrentsIntoSimulation, u'cls', CoralReefConnectivity.LoadHYCOMGLBa0084DEquatorialCurrentsIntoSimulation, u'cls')
1359
1360AddArgumentMetadata(CoralReefConnectivity.LoadHYCOMGLBa0084DEquatorialCurrentsIntoSimulation, u'simulationDirectory',
1361    typeMetadata=DirectoryTypeMetadata(mustExist=True),
1362    description=_(
1363u"""Existing coral reef connectivity simulation directory that should
1364recieve the currents.
1365
1366The directory must have been created using the Create Coral Reef
1367Connectivity Simulation tool.
1368
1369If you have already loaded HYCOM GLBa0.08 currents into the
1370simulation, you can use this tool to add currents for an additional
1371range of dates so long as they are for the same depth as the original
1372currents. If you try to add a different currents product to the
1373simulation (e.g. geostrophic currents from Aviso), or for a different
1374depth, this tool will report an error.
1375
1376If you try to load data for a range of dates that have been already
1377loaded into the simulation, the downloads for those dates will be
1378skipped. There is no way to delete or overwrite the data that has
1379already been loaded into the simulation. If you want to overwrite your
1380existing data (e.g. you want to switch to using a different depth),
1381you must create a new simulation."""),
1382    arcGISDisplayName=_(u'Simulation directory to recieve HYCOM currents'))
1383
1384CopyArgumentMetadata(CoralReefConnectivity.LoadAvisoGeostrophicCurrentsIntoSimulation, u'startDate', CoralReefConnectivity.LoadHYCOMGLBa0084DEquatorialCurrentsIntoSimulation, u'startDate')
1385CopyArgumentMetadata(CoralReefConnectivity.LoadAvisoGeostrophicCurrentsIntoSimulation, u'endDate', CoralReefConnectivity.LoadHYCOMGLBa0084DEquatorialCurrentsIntoSimulation, u'endDate')
1386
1387AddArgumentMetadata(CoralReefConnectivity.LoadHYCOMGLBa0084DEquatorialCurrentsIntoSimulation, u'depth',
1388    typeMetadata=FloatTypeMetadata(allowedValues=[0., 10., 20., 30., 50., 75., 100., 125., 150., 200., 250., 300., 400., 500., 600., 700., 800., 900., 1000., 1100., 1200., 1300., 1400., 1500., 1750., 2000., 2500., 3000., 3500., 4000., 4500., 5000., 5500.]),
1389    description=_(
1390u"""HYCOM depth layer to download currents from.
1391
1392This tool was designed primarily to study larvae that float at or near
1393the surface. The default depth is 0. If you are studying larvae that
1394stay submerged, you can choose a deeper depth, but be aware of two
1395important points:
1396
1397* This tool assumes the larvae remain at that depth for the entire
1398  simulation. It does not implement vertical migration or other
1399  behaviors that might be appropriate for your species. A newer
1400  version of this tool, to be released in 2012, will support vertical
1401  migration.
1402
1403* Be aware that the spatial extent of available currents data will
1404  shrink as depth increases. For example, if you choose a deep depth
1405  such as 250 m, there will be no data available for regions close to
1406  shore because the ocean is typically shallower than 250 m in those
1407  regions.
1408"""),
1409    arcGISDisplayName=_(u'Depth'))
1410
1411CopyArgumentMetadata(HYCOMGLBa008Equatorial4D.CreateArcGISRasters, u'extendYExtent', CoralReefConnectivity.LoadHYCOMGLBa0084DEquatorialCurrentsIntoSimulation, u'extendYExtent')
1412CopyArgumentMetadata(CoralReefConnectivity.LoadAvisoGeostrophicCurrentsIntoSimulation, u'resamplingTechnique', CoralReefConnectivity.LoadHYCOMGLBa0084DEquatorialCurrentsIntoSimulation, u'resamplingTechnique')
1413CopyArgumentMetadata(CoralReefConnectivity.LoadAvisoGeostrophicCurrentsIntoSimulation, u'interpolationMethod', CoralReefConnectivity.LoadHYCOMGLBa0084DEquatorialCurrentsIntoSimulation, u'interpolationMethod')
1414CopyArgumentMetadata(HYCOMGLBa008Equatorial4D.CreateArcGISRasters, u'timeout', CoralReefConnectivity.LoadHYCOMGLBa0084DEquatorialCurrentsIntoSimulation, u'timeout')
1415CopyArgumentMetadata(HYCOMGLBa008Equatorial4D.CreateArcGISRasters, u'maxRetryTime', CoralReefConnectivity.LoadHYCOMGLBa0084DEquatorialCurrentsIntoSimulation, u'maxRetryTime')
1416CopyArgumentMetadata(HYCOMGLBa008Equatorial4D.CreateArcGISRasters, u'cacheDirectory', CoralReefConnectivity.LoadHYCOMGLBa0084DEquatorialCurrentsIntoSimulation, u'cacheDirectory')
1417
1418CopyResultMetadata(CoralReefConnectivity.LoadAvisoGeostrophicCurrentsIntoSimulation, u'updatedSimulationDirectory', CoralReefConnectivity.LoadHYCOMGLBa0084DEquatorialCurrentsIntoSimulation, u'updatedSimulationDirectory')
1419
1420# Public method: CoralReefConnectivity.LoadROMSCoSiNE4DCurrentsIntoSimulation
1421
1422AddMethodMetadata(CoralReefConnectivity.LoadROMSCoSiNE4DCurrentsIntoSimulation,
1423    shortDescription=_(u'Downloads Pacific ROMS-CoSiNE ocean currents into a coral reef connectivity simulation.'),
1424    longDescription=_ROMS_CoSiNE_LongDescription % {u'name': 'tool'},
1425    isExposedToPythonCallers=True,
1426    isExposedByCOM=True,
1427    isExposedAsArcGISTool=True,
1428    arcGISDisplayName=_(u'Load Pacific ROMS-CoSiNE Currents Into Coral Reef Connectivity Simulation'),
1429    arcGISToolCategory=_(u'Connectivity Analysis\\Coral Reef Larval Connectivity'),
1430    dependencies=[ArcGISDependency(9, 2), ArcGISExtensionDependency(u'spatial'), PythonAggregatedModuleDependency('numpy')])
1431
1432CopyArgumentMetadata(CoralReefConnectivity.LoadAvisoGeostrophicCurrentsIntoSimulation, u'cls', CoralReefConnectivity.LoadROMSCoSiNE4DCurrentsIntoSimulation, u'cls')
1433
1434AddArgumentMetadata(CoralReefConnectivity.LoadROMSCoSiNE4DCurrentsIntoSimulation, u'simulationDirectory',
1435    typeMetadata=DirectoryTypeMetadata(mustExist=True),
1436    description=_(
1437u"""Existing coral reef connectivity simulation directory that should
1438recieve the currents.
1439
1440The directory must have been created using the Create Coral Reef
1441Connectivity Simulation tool.
1442
1443If you have already loaded Pacific ROMS-CoSiNE currents into the
1444simulation, you can use this tool to add currents for an additional
1445range of dates so long as they are for the same depth as the original
1446currents. If you try to add a different currents product to the
1447simulation (e.g. geostrophic currents from Aviso), or for a different
1448depth, this tool will report an error.
1449
1450If you try to load data for a range of dates that have been already
1451loaded into the simulation, the downloads for those dates will be
1452skipped. There is no way to delete or overwrite the data that has
1453already been loaded into the simulation. If you want to overwrite your
1454existing data (e.g. you want to switch to using a different depth),
1455you must create a new simulation."""),
1456    arcGISDisplayName=_(u'Simulation directory to recieve ROMS-CoSiNE currents'))
1457
1458CopyArgumentMetadata(CoralReefConnectivity.LoadAvisoGeostrophicCurrentsIntoSimulation, u'startDate', CoralReefConnectivity.LoadROMSCoSiNE4DCurrentsIntoSimulation, u'startDate')
1459CopyArgumentMetadata(CoralReefConnectivity.LoadAvisoGeostrophicCurrentsIntoSimulation, u'endDate', CoralReefConnectivity.LoadROMSCoSiNE4DCurrentsIntoSimulation, u'endDate')
1460
1461AddArgumentMetadata(CoralReefConnectivity.LoadROMSCoSiNE4DCurrentsIntoSimulation, u'depth',
1462    typeMetadata=FloatTypeMetadata(),
1463    description=_(
1464u"""Depth of currents layer to download.
1465
1466ROMS-CoSiNE uses a terrain-following vertical coordinate system
1467designed to maximize the accuracy of the simulation in coastal areas
1468and the open ocean simultaneously. There are 30 depth layers but their
1469depths vary on a per-cell basis with latitude, longitude, and time.
1470For example, coastal cells of the 10th depth layer might represent a
1471depth of 10 meters, while cells in the open ocean might represent a
1472depth of 200 meters. This tool interpolates a constant-depth layer
1473from ROMS-CoSiNE's varying-depth layers using a linear interpolation
1474algorithm.
1475
1476The depth 0 represents the surface. The sign of the depth coordinate
1477is ignored (e.g. the values 10 and -10 are both interpreted as 10 m
1478below the surface).
1479
1480This tool was designed primarily to study larvae that float at or near
1481the surface. The default depth is 0. If you are studying larvae that
1482stay submerged, you can choose a deeper depth, but be aware of two
1483important points:
1484
1485* This tool assumes the larvae remain at that depth for the entire
1486  simulation. It does not implement vertical migration or other
1487  behaviors that might be appropriate for your species. A newer
1488  version of this tool, to be released in 2012, will support vertical
1489  migration.
1490
1491* Be aware that the spatial extent of available currents data will
1492  shrink as depth increases. For example, if you choose a deep depth
1493  such as 250 m, there will be no data available for regions close to
1494  shore because the ocean is typically shallower than 250 m in those
1495  regions.
1496"""),
1497    arcGISDisplayName=_(u'Depth'))
1498
1499CopyArgumentMetadata(CoralReefConnectivity.LoadAvisoGeostrophicCurrentsIntoSimulation, u'resamplingTechnique', CoralReefConnectivity.LoadROMSCoSiNE4DCurrentsIntoSimulation, u'resamplingTechnique')
1500CopyArgumentMetadata(CoralReefConnectivity.LoadAvisoGeostrophicCurrentsIntoSimulation, u'interpolationMethod', CoralReefConnectivity.LoadROMSCoSiNE4DCurrentsIntoSimulation, u'interpolationMethod')
1501CopyArgumentMetadata(ROMSCoSiNE4D.CreateArcGISRasters, u'url', CoralReefConnectivity.LoadROMSCoSiNE4DCurrentsIntoSimulation, u'url')
1502CopyArgumentMetadata(ROMSCoSiNE4D.CreateArcGISRasters, u'timeout', CoralReefConnectivity.LoadROMSCoSiNE4DCurrentsIntoSimulation, u'timeout')
1503CopyArgumentMetadata(ROMSCoSiNE4D.CreateArcGISRasters, u'maxRetryTime', CoralReefConnectivity.LoadROMSCoSiNE4DCurrentsIntoSimulation, u'maxRetryTime')
1504CopyArgumentMetadata(ROMSCoSiNE4D.CreateArcGISRasters, u'cacheDirectory', CoralReefConnectivity.LoadROMSCoSiNE4DCurrentsIntoSimulation, u'cacheDirectory')
1505
1506CopyResultMetadata(CoralReefConnectivity.LoadAvisoGeostrophicCurrentsIntoSimulation, u'updatedSimulationDirectory', CoralReefConnectivity.LoadROMSCoSiNE4DCurrentsIntoSimulation, u'updatedSimulationDirectory')
1507
1508# Public method: CoralReefConnectivity.RunSimulation
1509
1510AddMethodMetadata(CoralReefConnectivity.RunSimulation,
1511    shortDescription=_(u'Executes a coral coral reef connectivity simulation.'),
1512    isExposedToPythonCallers=True,
1513    isExposedByCOM=True,
1514    isExposedAsArcGISTool=True,
1515    arcGISDisplayName=_(u'Run Coral Reef Connectivity Simulation'),
1516    arcGISToolCategory=_(u'Connectivity Analysis\\Coral Reef Larval Connectivity'),
1517    dependencies=[ArcGISDependency(9, 2), ArcGISExtensionDependency(u'spatial'), PythonAggregatedModuleDependency('numpy')])
1518
1519CopyArgumentMetadata(CoralReefConnectivity.CreateSimulationFromArcGISRasters, u'cls', CoralReefConnectivity.RunSimulation, u'cls')
1520
1521AddArgumentMetadata(CoralReefConnectivity.RunSimulation, u'simulationDirectory',
1522    typeMetadata=DirectoryTypeMetadata(mustExist=True),
1523    description=_(
1524u"""Existing coral reef connectivity simulation directory that has
1525been loaded with ocean currents data.
1526
1527The directory must have been created using the Create Coral Reef
1528Connectivity Simulation tool and then loaded with ocean currents data
1529using one of the tools provided for this purpose.
1530
1531The simulation may take hours to complete, due to the complex
1532mathematics involved. The run time is goverened by the size of your
1533study area, the number of reefs include in the simulation, and the
1534duration and time step of the simulation."""),
1535    arcGISDisplayName=_(u'Simulation directory'))
1536
1537AddArgumentMetadata(CoralReefConnectivity.RunSimulation, u'outputDirectory',
1538    typeMetadata=DirectoryTypeMetadata(mustExist=True),
1539    description=_(
1540u"""Output directory to receive the results of the simulation.
1541
1542The directory must already exist. Within it, the simulator creates:
1543
1544* DensityRasters - this subdirectory will contain a time series of
1545  rasters that represent snapshots of the larvae density throughout
1546  the study area, in particles per square km. A raster will be created
1547  each time the simulation is summarized; the summarization frequency
1548  is controlled by the Simulation Summarization Period parameter. The
1549  rasters' names will be of the form dYYYYDDDHHMM, where YYYY is the
1550  year, DDD is the day of the year (e.g. February 1 is day 032), HH is
1551  the hour, and MM is the minute.
1552
1553* DensityRasters raster catalog in ConnectivityGeodatabase.mdb - this
1554  catalog references the rasters created in the DensityRasters
1555  subdirectory. The StartDate and EndDate columns of the catalog
1556  specify the applicable timeframe for each raster, and may be used to
1557  animate the raster time series using the Animation toolbar available
1558  in ArcMap and other ArcGIS applications.
1559
1560* Edges feature class in ConnectivityGeodatabase.mdb - this line
1561  feature class shows which reefs are connected by larval dispersal.
1562  Each line represents a direction link between two reefs. The
1563  FromReefID and ToReefID fields specify the IDs of the source reef
1564  and sink reef, respectively. The MaxDispersal field shows the
1565  maximum quantity of larvae from the source reef found over the sink
1566  reef during the series of simulation summaries. The quantity is
1567  expressed as the fraction of larvae initially released from the
1568  source reef that are over the sink reef, and ranges from 0.0 to 1.0.
1569  For example, the value 0.01 means that 1% of the larvae initially
1570  released by the source reef were found over the sink reef, when
1571  dispersal from the source to the sink peaked.
1572"""),
1573    arcGISDisplayName=_(u'Output directory'))
1574
1575AddArgumentMetadata(CoralReefConnectivity.RunSimulation, u'startDate',
1576    typeMetadata=DateTimeTypeMetadata(),
1577    description=_(
1578u"""Start date of the simulation.
1579
1580The larvae are released from the reefs on this date. Selecting an
1581appropriate value requires knowledge of the reproductive biology of
1582the species you are studying."""),
1583    arcGISDisplayName=_(u'Start date'))
1584
1585AddArgumentMetadata(CoralReefConnectivity.RunSimulation, u'duration',
1586    typeMetadata=FloatTypeMetadata(minValue=0.0),
1587    description=_(
1588u"""Duration of the simulation, in days.
1589
1590Larger values require more computer memory and require more processing
1591time. To avoid extreme scenarios, this parameter can be no larger that
1592365 days."""),
1593    arcGISDisplayName=_(u'Duration'))
1594
1595AddArgumentMetadata(CoralReefConnectivity.RunSimulation, u'simulationTimeStep',
1596    typeMetadata=FloatTypeMetadata(minValue=0.0),
1597    description=_(
1598u"""Time step of the simulation, in hours.
1599
1600The time step defines the simulated time period at which larvae
1601density is recalculated using a Eulerian advection/diffusion model.
1602Smaller time steps increase the stability of the model and accuracy of
1603the results but also the run time and computer memory requirements of
1604the simulation. The original study from which this tool was developed
1605(Treml et al. 2008) used a time step of 2.4 hours.
1606
1607To check the model stability, this tool reports the effective Courant
1608number for the model, calculated from the simulation time step, grid
1609cell size, and average current velocity. The Courant number reflects
1610the portion of a cell that the larvae will traverse by advection in
1611one time step. If the Courant number is greater than 1, the model is
1612likely to be unstable and inaccurate. If it is significantly less than
16131 (e.g. 0.1), it is likely to be stable and accurate."""),
1614    arcGISDisplayName=_(u'Temp step'),
1615    arcGISCategory=_(u'Simulation options'))
1616
1617AddArgumentMetadata(CoralReefConnectivity.RunSimulation, u'summarizationPeriod',
1618    typeMetadata=IntegerTypeMetadata(minValue=1),
1619    description=_(
1620u"""Period, expressed as a number of simulation time steps, at which
1621the simulation should be summarized.
1622
1623The period specifies how frequently summarization should occur. The
1624first summarization will occur at the start of the simulation, and
1625subsequent summarizations will occur every time the period elapses.
1626For example, if the time step is 1 hour and the summarization period
1627is 24, summarizations will occur every 24 hours.
1628
1629The summarization procedure governs the production of simulation
1630outputs. Please see the documentation of the Output Directory
1631parameter for more information."""),
1632    arcGISDisplayName=_(u'Sumulation summarization period'),
1633    arcGISCategory=_(u'Simulation options'))
1634
1635AddArgumentMetadata(CoralReefConnectivity.RunSimulation, u'initialLarvaeDensity',
1636    typeMetadata=FloatTypeMetadata(minValue=1.0),
1637    description=_(
1638u"""Density of larvae, in particles per square km, released at the
1639start of the simulation.
1640
1641The original study from which this tool was developed (Treml et al.
16422008) used 10,000 particles per square km. This is consistent with
1643previous studies (Cowen et al. 2000; James et al. 2002; Largier 2003)
1644and was selected based on exploratory modeling efforts using densities
1645ranging from 1,000 to 100,000 particles per square km. For particular
1646taxa, these initial densities may need to be larger or smaller, based
1647on the specific fecundity and density characteristics of that species
1648of interest (Richmond 1987; Largier 2003)."""),
1649    arcGISDisplayName=_(u'Initial larvae density'),
1650    arcGISCategory=_(u'Simulation options'))
1651
1652AddArgumentMetadata(CoralReefConnectivity.RunSimulation, u'densityRasterCutoff',
1653    typeMetadata=FloatTypeMetadata(minValue=0.0, maxValue=100.0, canBeNone=True),
1654    description=_(
1655u"""Minimum larvae density, expressed as a percentage of the initial
1656larvae density, that a larvae density raster cell must be to not be
1657masked.
1658
1659This parameter is a percent of the initial larvae density. For
1660example, if the initial larvae density is 10000 particles per km and
1661this parameter is 1, a density of 100 particles per km will be used as
1662the cutoff. Larvae density cells that are less than this value will
1663set to NoData.
1664
1665This parameter does not affect the computations performed during the
1666simulation. It only affects the production of density rasters after
1667the simulation is complete, and is provided as a convenience for
1668visualization.
1669
1670If you set this parameter to 0, the density rasters will be produced
1671with no masking. The results may seem surprising. For most
1672simulations, larvae will have spread throughout the entire study area,
1673albeit in very small quantities for most cells. This is a surprising
1674effect of the diffusion component of the Eularian hydrodynamic
1675calculations. Diffiusion occurs equally in all directions at the rate
1676specified by the Diffusivity parameter. Given enough time, an
1677infinitesimal fraction of larvae from any given reef can theoretically
1678spread throughout the entire ocean simply by diffusion. To avoid a
1679confusing visualization, use this parameter to mask the extremely
1680density values that result from diffiusion."""),
1681    arcGISDisplayName=_(u'Cutoff percentage for larvae density rasters'),
1682    arcGISCategory=_(u'Simulation options'))
1683
1684##AddArgumentMetadata(CoralReefConnectivity.RunSimulation, u'deathRate',
1685##    typeMetadata=FloatTypeMetadata(minValue=0.0, maxValue=1.0, canBeNone=True),
1686##    description=_(
1687##u"""Death rate of the larvae, as proportion of the population that
1688##dies per day.
1689##
1690##Reliable mortality estimates for invertebrate larvae are rare due to
1691##the difficulty in sampling and identifying the same larval cohort in
1692##the plankton through time (Rumrill 1990; Morgan 1995). In a review of
1693##larval mortality rates, Rumrill (1990) showed that this parameter
1694##varied greatly between invertebrate species, from 0.016 to .357 per
1695##day, with an average of .223 per day. A recent study on several
1696##Pacific corals measuring larval survival, recruitment rates, and gene
1697##flow, reports the mortality of a broadcast-spawning coral to be around
1698##4 - 6% per day (Nishikawa et al. 2003; Nishikawa and Sakai 2005).  For
1699##this reason, the study from which this tool was developed (Treml et
1700##al. 2008) used a constant mortality of 6% per day. Although this rate
1701##is lower than the 18% per day reported for reef fish (Cowen et al.
1702##2000; James et al. 2002), it may be more representative of
1703##invertebrate taxa (Rumrill 1990, Ellien et al. 2004)."""),
1704##    arcGISDisplayName=_(u'Larvae death rate'),
1705##    arcGISCategory=_(u'Simulation options'))
1706
1707AddArgumentMetadata(CoralReefConnectivity.RunSimulation, u'diffusivity',
1708    typeMetadata=FloatTypeMetadata(minValue=0.0),
1709    description=_(
1710u"""The diffusion coefficent, in meters squared per second, to use in
1711the simulation.
1712
1713It is recommended that you consult an oceanographer to determine this
1714value. The original study from which this tool was developed (Treml et
1715al. 2008) used the value 25."""),
1716    arcGISDisplayName=_(u'Diffusivity'),
1717    arcGISCategory=_(u'Simulation options'))
1718
1719AddArgumentMetadata(CoralReefConnectivity.RunSimulation, u'includeReefIDs',
1720    typeMetadata=ListTypeMetadata(elementType=IntegerTypeMetadata(), canBeNone=True, minLength=1),
1721    description=_(
1722u"""List of IDs of the reefs to include in the simulation. If the list
1723is empty, all of the reefs will be included, unless some reefs are
1724listed in the "exclude reefs" parameter."""),
1725    arcGISDisplayName=_(u'IDs of reefs to include in the simulation'),
1726    arcGISCategory=_(u'Simulation options'))
1727
1728AddArgumentMetadata(CoralReefConnectivity.RunSimulation, u'excludeReefIDs',
1729    typeMetadata=ListTypeMetadata(elementType=IntegerTypeMetadata(), canBeNone=True, minLength=1),
1730    description=_(
1731u"""List of IDs of the reefs to exclude from the simulation. This list
1732may only be provided if the "include reefs" list is omitted (an error
1733will be reported if both lists are provided). If this list is
1734provided, all of the reefs will be included in the simulation except
1735those in this list."""),
1736    arcGISDisplayName=_(u'IDs of reefs to exclude from the simulation'),
1737    arcGISCategory=_(u'Simulation options'))
1738
1739AddArgumentMetadata(CoralReefConnectivity.RunSimulation, u'overwriteExisting',
1740    typeMetadata=BooleanTypeMetadata(),
1741    description=_(
1742u"""If True, the outputs will be overwritten, if it exists. If False,
1743a ValueError will be raised if the outputs exist."""),
1744    initializeToArcGISGeoprocessorVariable=u'OverwriteOutput')
1745
1746AddResultMetadata(CoralReefConnectivity.RunSimulation, u'updatedOutputDirectory',
1747    typeMetadata=DirectoryTypeMetadata(),
1748    description=_(u'Updated output directory.'),
1749    arcGISDisplayName=_(u'Updated output directory'))
1750
1751###############################################################################
1752# Metadata: _AvisoCurrentsInMetersPerSecond class
1753###############################################################################
1754
1755AddClassMetadata(_AvisoCurrentsInMetersPerSecond,
1756    shortDescription=_(u'A version of AvisoGriddedGeostrophicCurrents that gives current velocity in m/s rather than cm/s.'),
1757    longDescription=_(
1758u"""This class is intended for private use within GeoEco and is not
1759intended for external callers."""))
1760
1761###############################################################################
1762# Names exported by this module
1763###############################################################################
1764
1765__all__ = ['CoralReefConnectivity']
Note: See TracBrowser for help on using the browser.