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

Revision 862, 96.9 KB (checked in by jjr8, 18 months ago)

Continuing work on NOAA OSCAR. Also added HYCOM GLBa0.08 to connectivity tool.

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