def getCloudFreeModis(bounds, targetDate, maxRangeDays=10, maxCloudPercentage=0.05,
                      searchMethod='spiral'):
    '''Search for the closest cloud-free MODIS image near the target date.
       The result preference is determined by searchMethod and can be  set to:
       spiral, increasing, or decreasing'''
    
    # Get the date range to search
    if searchMethod == 'spiral':
        dateStart = targetDate.advance(-1*maxRangeDays, 'day')
        dateEnd   = targetDate.advance(   maxRangeDays, 'day')
    else:
        dateStart = targetDate
        dateEnd   = targetDate.advance(   maxRangeDays, 'day')
    
    # Get a list of candidate images
    imageCollection = get_image_collection_modis(bounds, dateStart, dateEnd)
    imageList       = imageCollection.toList(100)
    imageInfo       = imageList.getInfo()
    
    # Find the first image with a low cloud percentage
    numFound = len(imageInfo)
    if searchMethod == 'spiral':
        searchIndices = miscUtilities.getExpandingIndices(numFound)
    elif searchMethod == 'increasing':
        searchIndices = range(0,numFound)
    else:
        searchIndices = range(numFound-1, -1, -1)
    for i in searchIndices:
        thisImage       = ee.Image(imageList.get(i)).resample('bicubic')
        cloudPercentage = cmt.modis.modis_utilities.getCloudPercentage(thisImage, bounds)
        print 'Detected MODIS cloud percentage: ' + str(cloudPercentage)
        if cloudPercentage < maxCloudPercentage:
            return thisImage

    raise Exception('Could not find a nearby cloud-free MODIS image for date ' + str(targetDate.getInfo()))
def getCloudFreeLandsat(bounds,
                        targetDate,
                        maxRangeDays=10,
                        maxCloudPercentage=0.05,
                        searchMethod='spiral'):
    '''Search for the closest cloud-free Landsat image near the target date.
       The result preference is determined by searchMethod and can be  set to:
       spiral, increasing, or decreasing'''

    # Get the date range to search
    if searchMethod == 'spiral':
        dateStart = targetDate.advance(-1 * maxRangeDays, 'day')
        dateEnd = targetDate.advance(maxRangeDays, 'day')
    else:
        dateStart = targetDate
        dateEnd = targetDate.advance(maxRangeDays, 'day')

    # Try each of the satellites in decreasing order of quality
    collectionNames = ['LC8_L1T_TOA', 'LT5_L1T_TOA', 'LE7_L1T_TOA']
    for name in collectionNames:

        # Get candidate images for this sensor
        imageCollection = get_image_collection_landsat(bounds, dateStart,
                                                       dateEnd, name)
        imageList = imageCollection.toList(100)
        imageInfo = imageList.getInfo()

        # Find the first image with a low cloud percentage
        numFound = len(imageInfo)
        if searchMethod == 'spiral':
            searchIndices = miscUtilities.getExpandingIndices(numFound)
        elif searchMethod == 'increasing':
            searchIndices = range(0, numFound)
        else:
            searchIndices = range(numFound - 1, -1, -1)
        for i in searchIndices:
            thisImage = ee.Image(imageList.get(i)).resample('bicubic')
            cloudPercentage = cmt.util.landsat_functions.getCloudPercentage(
                thisImage, bounds)
            print 'Detected Landsat cloud percentage: ' + str(cloudPercentage)
            if cloudPercentage < maxCloudPercentage:
                return thisImage
        # If we got here this satellite did not produce a good image, try the next satellite.

    raise Exception(
        'Could not find a nearby cloud-free Landsat image for date ' +
        str(targetDate.getInfo()))
def getCloudFreeModis(bounds, targetDate, maxRangeDays=10, maxCloudPercentage=0.05,
                      minCoverage=0.8, searchMethod='spiral'):
    '''Search for the closest cloud-free MODIS image near the target date.
       The result preference is determined by searchMethod and can be  set to:
       spiral, increasing, or decreasing'''
    
    # Get the date range to search
    if searchMethod == 'spiral':
        dateStart = targetDate.advance(-1*maxRangeDays, 'day')
        dateEnd   = targetDate.advance(   maxRangeDays, 'day')
    else:
        dateStart = targetDate
        dateEnd   = targetDate.advance(   maxRangeDays, 'day')
    
    # Get a list of candidate images
    imageCollection = get_image_collection_modis(bounds, dateStart, dateEnd)
    imageList       = imageCollection.toList(100)
    imageInfo       = imageList.getInfo()
    
    #print 'Modis dates:'
    #print dateStart.format().getInfo()
    #print dateEnd.format().getInfo()
    #print imageInfo
    
    # Find the first image that meets the requirements
    numFound = len(imageInfo)
    if searchMethod == 'spiral':
        searchIndices = miscUtilities.getExpandingIndices(numFound)
    elif searchMethod == 'increasing':
        searchIndices = range(0,numFound)
    else:
        searchIndices = range(numFound-1, -1, -1)
    #print searchIndices
    for i in searchIndices:
        COVERAGE_RES = 250
        thisImage       = ee.Image(imageList.get(i)).resample('bicubic')
        percentCoverage = thisImage.mask().reduceRegion(ee.Reducer.mean(), bounds, COVERAGE_RES).getInfo().values()[0]
        #print 'percentCoverage = ' + str(percentCoverage)
        if percentCoverage < minCoverage: # MODIS has high coverage, but there are gaps.
            continue
        cloudPercentage = cmt.modis.modis_utilities.getCloudPercentage(thisImage, bounds)
        print 'Detected MODIS cloud percentage: ' + str(cloudPercentage)
        if cloudPercentage < maxCloudPercentage:
            return thisImage

    raise Exception('Could not find a nearby cloud-free MODIS image for date ' + str(targetDate.getInfo()))
def getCloudFreeLandsat(bounds, targetDate, maxRangeDays=10, maxCloudPercentage=0.05,
                        minCoverage=0.8, searchMethod='spiral'):
    '''Search for the closest cloud-free Landsat image near the target date.
       The result preference is determined by searchMethod and can be  set to:
       spiral, increasing, or decreasing'''

    # Get the date range to search
    if searchMethod == 'spiral':
        dateStart = targetDate.advance(-1*maxRangeDays, 'day')
        dateEnd   = targetDate.advance(   maxRangeDays, 'day')
    else:
        dateStart = targetDate
        dateEnd   = targetDate.advance(   maxRangeDays, 'day')

    # Try each of the satellites in decreasing order of quality
    collectionNames = ['LC8_L1T_TOA', 'LT5_L1T_TOA', 'LE7_L1T_TOA']
    for name in collectionNames:

        # Get candidate images for this sensor
        imageCollection = get_image_collection_landsat(bounds, dateStart, dateEnd, name)
        imageList       = imageCollection.toList(100)
        imageInfo       = imageList.getInfo()
        
        # Find the first image that meets the requirements
        numFound = len(imageInfo)
        if searchMethod == 'spiral':
            searchIndices = miscUtilities.getExpandingIndices(numFound)
        elif searchMethod == 'increasing':
            searchIndices = range(0,numFound)
        else:
            searchIndices = range(numFound-1, -1, -1)
            
        for i in searchIndices:
            COVERAGE_RES = 60
            thisImage       = ee.Image(imageList.get(i)).resample('bicubic')
            percentCoverage = thisImage.mask().reduceRegion(ee.Reducer.mean(), bounds, COVERAGE_RES).getInfo().values()[0]
            if percentCoverage < minCoverage:
                continue
            cloudPercentage = cmt.util.landsat_functions.getCloudPercentage(thisImage, bounds)
            print 'Detected Landsat cloud percentage: ' + str(cloudPercentage)
            if cloudPercentage < maxCloudPercentage:
                return thisImage
        # If we got here this satellite did not produce a good image, try the next satellite.

    raise Exception('Could not find a nearby cloud-free Landsat image for date ' + str(targetDate.getInfo()))
def getNearestSentinel1(bounds, targetDate, maxRangeDays=10, minCoverage=0.8, searchMethod='spiral'):
    '''Search for the closest Sentinel1 image near the target date.
       Sentinel1 images are radar and see through clouds!
       The result preference is determined by searchMethod and can be  set to:
       spiral, increasing, or decreasing'''

    # TODO: Some options to balance nearness and resolution preferences?

    # Get the date range to search
    if searchMethod == 'spiral':
        dateStart = targetDate.advance(-1*maxRangeDays, 'day')
        dateEnd   = targetDate.advance(   maxRangeDays, 'day')
    else:
        dateStart = targetDate
        dateEnd   = targetDate.advance(   maxRangeDays, 'day')
    
    # Get a list of candidate images
    imageCollection = get_image_collection_sentinel1(bounds, dateStart, dateEnd)
    imageList       = imageCollection.toList(100)
    imageInfo       = imageList.getInfo()
    
    if len(imageInfo) == 0:
        raise Exception('Could not find a nearby Sentinel1 image for date ' + str(targetDate.getInfo()))
  
    # Find the first image that meets the requirements
    numFound = len(imageInfo)
    if searchMethod == 'spiral':
        searchIndices = miscUtilities.getExpandingIndices(numFound)
    elif searchMethod == 'increasing':
        searchIndices = range(0,numFound)
    else:
        searchIndices = range(numFound-1, -1, -1)

    for i in searchIndices:
        COVERAGE_RES = 30
        thisImage       = ee.Image(imageList.get(i)).resample('bicubic')
        percentCoverage = thisImage.mask().reduceRegion(ee.Reducer.mean(), bounds, COVERAGE_RES).getInfo().values()[0]
        print 'S1 Coverage = ' + str(percentCoverage)
        if percentCoverage >= minCoverage: # MODIS has high coverage, but there are gaps.
            return thisImage

    raise Exception('Could not find a nearby Sentinel image with coverage for date ' + str(targetDate.getInfo()))
def getCloudFreeModis(bounds,
                      targetDate,
                      maxRangeDays=10,
                      maxCloudPercentage=0.05,
                      searchMethod='spiral'):
    '''Search for the closest cloud-free MODIS image near the target date.
       The result preference is determined by searchMethod and can be  set to:
       spiral, increasing, or decreasing'''

    # Get the date range to search
    if searchMethod == 'spiral':
        dateStart = targetDate.advance(-1 * maxRangeDays, 'day')
        dateEnd = targetDate.advance(maxRangeDays, 'day')
    else:
        dateStart = targetDate
        dateEnd = targetDate.advance(maxRangeDays, 'day')

    # Get a list of candidate images
    imageCollection = get_image_collection_modis(bounds, dateStart, dateEnd)
    imageList = imageCollection.toList(100)
    imageInfo = imageList.getInfo()

    # Find the first image with a low cloud percentage
    numFound = len(imageInfo)
    if searchMethod == 'spiral':
        searchIndices = miscUtilities.getExpandingIndices(numFound)
    elif searchMethod == 'increasing':
        searchIndices = range(0, numFound)
    else:
        searchIndices = range(numFound - 1, -1, -1)
    for i in searchIndices:
        thisImage = ee.Image(imageList.get(i)).resample('bicubic')
        cloudPercentage = cmt.modis.modis_utilities.getCloudPercentage(
            thisImage, bounds)
        print 'Detected MODIS cloud percentage: ' + str(cloudPercentage)
        if cloudPercentage < maxCloudPercentage:
            return thisImage

    raise Exception(
        'Could not find a nearby cloud-free MODIS image for date ' +
        str(targetDate.getInfo()))