示例#1
0
    def trimmed(self, width):
        separator = PanelStrip().icon('split')

        if width < separator.width:
            return PanelStrip()

        if PanelVisual.char_width:
            side_chars = (width - separator.width) // (2 * PanelVisual.char_width)
            left_text = self.text[:side_chars]
            right_text = self.text[len(self.text) - side_chars:]
        else:
            left_text = self.text
            right_text = self.text
            fragment_width = (width - separator.width) // 2

            while Raster.text_width(left_text) > fragment_width:
                left_text = left_text[len(left_text) - 1:]
            while Raster.text_width(right_text) > fragment_width:
                right_text = right_text[1:]

        return (
            PanelStrip().text(left_text.rstrip())
            + separator
            + PanelStrip().text(right_text.lstrip())
        )
示例#2
0
 def propagateFromRidges(self, valleyDepthsFile, dirRaster, accRaster):
     """
     Propagate relative heights of nearest ridge points along flow paths, starting from points with accumulation 1.
     
     Heights are put into ridgeHeightsRaster.  
     Distances from ridge are put into ridgeDistancesRaster  If a point already has a height, 
     but the new path is shorter, the new height overwrites the old.
     """
     time1 = time.process_time()
     self.valleyDepthsRaster = Raster(valleyDepthsFile,
                                      self._gv,
                                      canWrite=False,
                                      isInt=False)
     res = self.valleyDepthsRaster.open(self.chunkCount)
     if not res:
         return
     reportFailure = True
     pathLength = 0  # path length counted in pixels (horizontal and vertical assumed same, so 1)
     diag = math.sqrt(2)
     for row in range(self.numRows):
         for col in range(self.numCols):
             if accRaster.read(row, col) == 1:
                 elevation, pathLength = self.getRidgeElevation(
                     row, col, reportFailure)
                 if pathLength < 0:
                     if reportFailure:
                         reportFailure = False
                     elevation = self.demRaster.read(row, col)
                     pathLength = 0
                 nextRow, nextCol = row, col
                 while True:
                     nextElev = self.demRaster.read(nextRow, nextCol)
                     if nextElev == self.demNoData:
                         break
                     currentPathLength = self.ridgeDistancesRaster.read(
                         nextRow, nextCol)
                     if currentPathLength >= 0:
                         # have a previously stored value
                         if pathLength < currentPathLength:
                             # new path length from ridge is shorter: update heights raster
                             self.ridgeHeightsRaster.write(
                                 nextRow, nextCol, elevation - nextElev)
                             self.ridgeDistancesRaster.write(
                                 nextRow, nextCol, pathLength)
                         else:  # already had shorter path from ridge - no point in continuing down flow path
                             break
                     else:  # no value stored yet
                         self.ridgeHeightsRaster.write(
                             nextRow, nextCol, elevation - nextElev)
                         self.ridgeDistancesRaster.write(
                             nextRow, nextCol, pathLength)
                     pt, isDiag = self.alongDirPoint(
                         nextRow, nextCol, dirRaster)
                     if pt is None:
                         break
                     pathLength += diag if isDiag else 1
                     nextRow, nextCol = pt
     time2 = time.process_time()
     QSWATUtils.loginfo('Propagating ridge points took {0} seconds'.format(
         int(time2 - time1)))
示例#3
0
def make_tiles(r_analytic, images_path, output_filepath, window_size, idx,
               overlap, dtype, scaling_type):
    """Create tiles from satellite image, save to file and return number of tiles created."""
    meta_data_filename = get_meta_data_filename(images_path, r_analytic.name)
    r_visual_rgb_filename = get_rgb_filename(images_path, r_analytic.name)
    # instantiate raster class
    raster = Raster(r_analytic, r_visual_rgb_filename, meta_data_filename)
    # ** create tiles **
    num_tiles = raster.to_tiles(output_path=output_filepath,
                                window_size=window_size,
                                idx=idx,
                                overlap=overlap,
                                dtype=dtype,
                                scaling_type=scaling_type)
    return num_tiles
示例#4
0
def _calc_cost_of_per_ton_inputs(vars_dict, crop, lulc_raster):
    '''
    Implements the following equations provided in the User Guide:

    sum_across_fert(FertAppRate_fert * LULCCropCellArea * CostPerTon_fert)
    '''

    economics_table_crop = vars_dict['economics_table_dict'][crop]
    fert_maps_dict = vars_dict['fertilizer_maps_dict']

    masked_lulc_raster = _get_masked_lulc_raster(vars_dict, crop, lulc_raster)
    masked_lulc_raster_float = masked_lulc_raster.set_datatype_and_nodata(
        gdal.GDT_Float64, NODATA_FLOAT)

    CostPerTonInputTotal_raster = masked_lulc_raster_float.zeros()

    try:
        cost_nitrogen_per_kg = economics_table_crop['cost_nitrogen_per_kg']
        Nitrogen_raster = Raster.from_file(
            fert_maps_dict['nitrogen']).set_nodata(NODATA_FLOAT)
        NitrogenCost_raster = Nitrogen_raster * cost_nitrogen_per_kg
        CostPerTonInputTotal_raster += NitrogenCost_raster
    except KeyError:
        LOGGER.warning("Skipping nitrogen cost because insufficient amount "
                       "of information provided.")
    try:
        cost_phosphorous_per_kg = economics_table_crop[
            'cost_phosphorous_per_kg']
        Phosphorous_raster = Raster.from_file(
            fert_maps_dict['phosphorous']).set_nodata(NODATA_FLOAT)
        PhosphorousCost_raster = Phosphorous_raster * cost_phosphorous_per_kg
        CostPerTonInputTotal_raster += PhosphorousCost_raster
    except KeyError:
        LOGGER.warning("Skipping phosphorous cost because insufficient amount "
                       "of information provided.")
    try:
        cost_potash_per_kg = economics_table_crop['cost_potash_per_kg']
        Potash_raster = Raster.from_file(
            fert_maps_dict['potash']).set_nodata(NODATA_FLOAT)
        PotashCost_raster = Potash_raster * cost_potash_per_kg
        CostPerTonInputTotal_raster += PotashCost_raster
    except KeyError:
        LOGGER.warning("Skipping potash cost because insufficient amount of "
                       "information provided.")

    CostPerTonInputTotal_masked_raster = CostPerTonInputTotal_raster * masked_lulc_raster_float

    return CostPerTonInputTotal_masked_raster
def create_crops_in_aoi_list(vars_dict):
    '''
    Example Returns::

        vars_dict = {
            # ...
            'crops_in_aoi_list': ['corn', 'rice', 'soy']
        }
    '''
    lulc_raster = Raster.from_file(vars_dict['lulc_map_uri'])
    crop_lookup_dict = vars_dict['crop_lookup_dict']
    # array = np.unique(lulc_raster.get_band(1).data)
    array = lulc_raster.unique()

    crops_in_aoi_list = []
    for crop_num in array:
        try:
            crops_in_aoi_list.append(crop_lookup_dict[crop_num])
        except KeyError:
            LOGGER.warning("Land Use Map contains values not listed in the "
                           "Crop Lookup Table")

    vars_dict['crops_in_aoi_list'] = convert_dict_to_unicode(
        crops_in_aoi_list)
    return vars_dict
示例#6
0
def _get_climate_bin_over_lulc(vars_dict, crop, aoi_vector, base_raster_float):
    '''
    Clips the climate bin values in the global dataset, reprojects and
        resamples those values to a new raster aligned to the given LULC raster
        that is then returned to the user.
    '''
    climate_bin_raster = Raster.from_file(
        vars_dict['climate_bin_maps_dict'][crop])

    reproj_aoi_vector = aoi_vector.reproject(
        climate_bin_raster.get_projection())

    clipped_climate_bin_raster = climate_bin_raster.clip(
        reproj_aoi_vector.uri).set_nodata(NODATA_INT)

    if clipped_climate_bin_raster.get_shape() == (1, 1):
        climate_bin_val = float(clipped_climate_bin_raster.get_band(
            1)[0, 0])
        aligned_climate_bin_raster = base_raster_float.ones() * climate_bin_val
    else:
        # note: this reprojection could result in very long computation times
        reproj_climate_bin_raster = clipped_climate_bin_raster.reproject(
            base_raster_float.get_projection(),
            'nearest',
            base_raster_float.get_affine().a)

        aligned_climate_bin_raster = reproj_climate_bin_raster.align_to(
            base_raster_float, 'nearest')

    return aligned_climate_bin_raster
示例#7
0
    def add_rasters(self, path, indexdict=None, qv=None):
        """
		Add any raster bands from raster-file as Raster

		Parameters
		----------
		path : str
			Path to raster-file
		indexdict : dict, optional
			Contains names for raster-indices, where key is GDAL-Band index
			and value is the key for the Raster in Collection.rasters
		qv : int, optional
			Quantification value
		"""
        # open GDAL-Dataset
        dataset = gdal.Open(path)
        ct = transformation_from_dataset(dataset)

        if indexdict == None:
            # add all rasters to indexdict
            keys = range(1, dataset.RasterCount + 1)
            rc = len(self.rasters)
            names = range(len(self.rasters),
                          len(self.rasters) + dataset.RasterCount)
            indexdict = dict(zip(keys, names))

        for index, name in indexdict.items():
            # add raster-band as Raster to Collection.rasters
            self.rasters[name] = Raster(dataset, index, qv, ct)

        self._datasets.append(dataset)
示例#8
0
def _get_observed_yield_from_dataset(vars_dict, crop, aoi_vector, base_raster_float):
    '''
    Clips the observed crop yield values in the global dataset, reprojects and
        resamples those values to a new raster aligned to the given LULC raster
        that is then returned to the user.
    '''
    crop_observed_yield_raster = Raster.from_file(
        vars_dict['observed_yields_maps_dict'][crop])

    reproj_aoi_vector = aoi_vector.reproject(
        crop_observed_yield_raster.get_projection())

    clipped_crop_raster = crop_observed_yield_raster.clip(
        reproj_aoi_vector.uri).set_nodata(NODATA_FLOAT)

    if clipped_crop_raster.get_shape() == (1, 1):
        observed_yield_val = float(clipped_crop_raster.get_band(1)[0, 0])
        aligned_crop_raster = observed_yield_val * base_raster_float.ones()
    else:
        # this reprojection could result in very long computation times
        reproj_crop_raster = clipped_crop_raster.reproject(
            base_raster_float.get_projection(),
            'nearest',
            base_raster_float.get_affine().a)

        aligned_crop_raster = reproj_crop_raster.align_to(
            base_raster_float, 'nearest')

    return aligned_crop_raster
示例#9
0
    def __init__(self, year_list, data_dir):
        '''
        year_list: a numeric list of years which are took into account when calculating
                   climatic covariates
        '''
        def GetRefRaster(data_dir):
            for (subdirpath, subdirname, filenames) in walk(data_dir):
                for f in filenames:
                    if f.split('.')[-1].lower()[:3] == 'tif':
                        return join(subdirpath, f)

        self.years = year_list
        self.dir = data_dir
        self.raster = Raster()
        self.ref_raster = GetRefRaster(self.dir)
        self.ref_array = self.raster.getRasterArray(self.ref_raster)
        self.no_data = self.raster.getNoDataValue(self.ref_raster)
示例#10
0
def write_raster_data(data, projection, geotransform, filename, keywords=None):
    """Write array to raster file with specified metadata and one data layer

    Input:
        data: Numpy array containing grid data
        projection: WKT projection information
        geotransform: 6 digit vector
                      (top left x, w-e pixel resolution, rotation,
                       top left y, rotation, n-s pixel resolution).
                       See e.g. http://www.gdal.org/gdal_tutorial.html
        filename: Output filename
        keywords: Optional dictionary

    Note: The only format implemented is GTiff and the extension must be .tif
    """

    R = Raster(data, projection, geotransform, keywords=keywords)
    R.write_to_file(filename)
示例#11
0
def write_raster_data(data, projection, geotransform, filename, keywords=None):
    """Write array to raster file with specified metadata and one data layer

    Input:
        data: Numpy array containing grid data
        projection: WKT projection information
        geotransform: 6 digit vector
                      (top left x, w-e pixel resolution, rotation,
                       top left y, rotation, n-s pixel resolution).
                       See e.g. http://www.gdal.org/gdal_tutorial.html
        filename: Output filename
        keywords: Optional dictionary

    Note: The only format implemented is GTiff and the extension must be .tif
    """

    R = Raster(data, projection, geotransform, keywords=keywords)
    R.write_to_file(filename)
示例#12
0
def read_layer(filename):
    """Read spatial layer from file.
    This can be either raster or vector data.
    """

    _, ext = os.path.splitext(filename)
    if ext in ['.asc', '.tif', '.nc']:
        return Raster(filename)
    elif ext in ['.shp', '.sqlite']:
        return Vector(filename)
    else:
        msg = ('Could not read %s. '
               'Extension "%s" has not been implemented' % (filename, ext))
        raise ReadLayerError(msg)
示例#13
0
def testRaster():
    print("Testing Raster:")

    print('Reading data...')
    test_dir = os.path.dirname(os.path.abspath(__file__)) + os.path.sep + 'test_data' + os.path.sep
    test_file = 'test.dep'
    raster = Raster.from_file(test_dir + test_file)
    new_raster = Raster.create_from_other(test_dir + 'delete_me.dep', raster)
    lower_limit = raster.minimum + 0.00*(raster.maximum - raster.minimum)
    upper_limit = raster.minimum + 0.9*(raster.maximum - raster.minimum)
    old_progress = 1
    for row in range(raster.rows):
        for col in range(raster.columns):
            z = raster[row, col]
            if z == raster.nodata:
                new_raster[row, col] = new_raster.nodata
            elif z < lower_limit:
                new_raster[row, col] = lower_limit
            elif z > upper_limit:
                new_raster[row, col] = upper_limit
            else:
                new_raster[row, col] = z

        progress = int(100.0 * (row+1) / raster.rows)
        if progress != old_progress:
            print('progress: {}%'.format(progress))
            old_progress = progress

    new_raster *= 2.0
    new_raster[100, 100] += 275.6

    print('Saving data...')
    new_raster.calculate_min_and_max()
    new_raster.display_minimum = new_raster.minimum + 0.1*(new_raster.maximum - new_raster.minimum)
    new_raster.display_maximum = new_raster.minimum + 0.8*(new_raster.maximum - new_raster.minimum)
    new_raster.write()
示例#14
0
def raster_test():
    doc = Document("Untitled-1")

    width = 100
    height = 100
    image = Image.new("L", (width, height))
    draw = ImageDraw.Draw(image)
    draw_circle(draw, width / 2, height / 2, width / 2 - 10, 255)
    draw_circle(draw, width * 3 / 4, height / 4, width / 5, 0)
    image.save("prntest.png")

    raster = Raster(image, 100, 100, 100, 100)
    doc.addRaster(raster)

    return doc
示例#15
0
 def start(self):
     laser_width = self.args.kerf[0]
     border_size = self.args.border[0]
     output_file = self.args.output[0] if self.args.output else None
     layer_height = self.args.height[0]
     back_and_forth = self.args.alternate_raster
     if self.args.file:
         raster = Raster(laser_width, border_size, output_file, layer_height, back_and_forth=back_and_forth)
         raster.process_file(self.args.file[0])
     else:
         raster = Raster(laser_width, border_size, output_file, layer_height, back_and_forth=back_and_forth)
         raster.process_folder(self.args.directory[0])
示例#16
0
 def start(self):
     laser_width = self.args.kerf[0]
     border_size = self.args.border[0]
     output_file = self.args.output[0] if self.args.output else None
     layer_height = self.args.height[0]
     back_and_forth = self.args.alternate_raster
     if self.args.file:
         raster = Raster(laser_width,
                         border_size,
                         output_file,
                         layer_height,
                         back_and_forth=back_and_forth)
         raster.process_file(self.args.file[0])
     else:
         raster = Raster(laser_width,
                         border_size,
                         output_file,
                         layer_height,
                         back_and_forth=back_and_forth)
         raster.process_folder(self.args.directory[0])
示例#17
0
 def makeRidgeRaster(self):
     """Make raster  to show ridges."""
     ridgeFile = QSWATUtils.join(self._gv.demDir,
                                 'ridge' + str(self.branchThresh) + '.tif')
     ridgeRaster = Raster(ridgeFile, self._gv, canWrite=True, isInt=True)
     res = ridgeRaster.open(self.chunkCount,
                            numRows=self.numRows,
                            numCols=self.numCols,
                            transform=self.demTransform,
                            projection=self.demProjection,
                            noData=self.noData)
     if not res:
         return
     for row in range(self.numRows):
         for col in range(self.numCols):
             if self.demRaster.read(row, col) != self.demNoData:
                 val, _ = self.ridgePoints.get((row, col), (-1, -1))
                 ridgeRaster.write(row, col, 0 if val == -1 else 1)
     ridgeRaster.close()
示例#18
0
 def writeFloodPlain(self, valleyDepthsFile, mustRun):
     """Calculate slope positions from valleyDepths and ridgeHeights, and write floodplain raster ."""
     method = 'inv' if self.useInversion else 'branch'
     thresh = '{0:.2F}'.format(self.floodThresh).replace('.', '_')
     flood = QSWATUtils.join(self._gv.floodDir,
                             method + 'flood' + thresh + '.tif')
     root = QgsProject.instance().layerTreeRoot()
     if mustRun or \
         not QSWATUtils.isUpToDate(valleyDepthsFile, flood) or \
         not QSWATUtils.isUpToDate(self.ridgeHeightsFile, flood):
         if os.path.exists(flood):
             QSWATUtils.tryRemoveLayerAndFiles(flood, root)
         self._gv.clearOpenRasters()
         completed = False
         while not completed:
             try:
                 completed = True  # only gets set on MemoryError exception
                 self.ridgeHeightsRaster = Raster(self.ridgeHeightsFile,
                                                  self._gv,
                                                  canWrite=False,
                                                  isInt=False)
                 res = self.ridgeHeightsRaster.open(self.chunkCount)
                 if not res:
                     self._gv.closeOpenRasters()
                     return
                 if self.valleyDepthsRaster is None:
                     # may have been opened when calculating ridge heights by branch length
                     self.valleyDepthsRaster = Raster(valleyDepthsFile,
                                                      self._gv,
                                                      canWrite=False,
                                                      isInt=False)
                     res = self.valleyDepthsRaster.open(self.chunkCount)
                     if not res:
                         self._gv.closeOpenRasters()
                         return
                 self._progress('Flood plain...')
                 self.floodplainRaster = Raster(flood,
                                                self._gv,
                                                canWrite=True,
                                                isInt=True)
                 OK = self.floodplainRaster.open(
                     self.chunkCount,
                     numRows=self.numRows,
                     numCols=self.numCols,
                     transform=self.demTransform,
                     projection=self.demProjection,
                     noData=self.noData)
                 if OK:
                     self.calcFloodPlain1()
                     self.floodplainRaster.close()
                     ## fixing aux.xml file seems unnecessary in QGIS 2.16
                     #                         # now fix maximum value to 1 instead of zero in aux.xml file
                     #                         # else if loaded has legend 0 to nan and display is all black
                     #                         xmlFile = self.floodplainRaster.fileName + '.aux.xml'
                     #                         ok, err = QSWATUtils.setXMLValue(xmlFile, u'MDI', u'key', u'STATISTICS_MAXIMUM', u'1')
                     #                         if not ok:
                     #                             QSWATUtils.error(err, self._gv.isBatch)
                     QSWATUtils.copyPrj(self.demRaster.fileName,
                                        self.floodplainRaster.fileName)
                     # load flood above DEM
                     layers = root.findLayers()
                     demLayer = QSWATUtils.getLayerByLegend(
                         FileTypes.legend(FileTypes._DEM), layers)
                     ft = FileTypes._INVFLOOD if self.useInversion else FileTypes._BRANCHFLOOD
                     floodLayer, _ = QSWATUtils.getLayerByFilename(
                         layers, self.floodplainRaster.fileName, ft,
                         self._gv, demLayer,
                         QSWATUtils._WATERSHED_GROUP_NAME)
                     if floodLayer is None:
                         QSWATUtils.error('Failed to load floodplain raster {0}' \
                                          .format(self.floodplainRaster.fileName), self._gv.isBatch)
                 self.valleyDepthsRaster.close()
                 self.ridgeHeightsRaster.close()
                 self._progress('Flood plain done')
             except MemoryError:
                 QSWATUtils.loginfo(
                     'Out of memory for flood plain with chunk count {0}'.
                     format(self.chunkCount))
                 self._gv.closeOpenRasters()
                 completed = False
                 self.chunkCount += 1
     else:  # already have uptodate flood file: make sure it is loaded
         # load flood above DEM
         layers = root.findLayers()
         demLayer = QSWATUtils.getLayerByLegend(
             FileTypes.legend(FileTypes._DEM), layers)
         ft = FileTypes._INVFLOOD if self.useInversion else FileTypes._BRANCHFLOOD
         floodLayer, _ = QSWATUtils.getLayerByFilename(
             layers, flood, ft, self._gv, demLayer,
             QSWATUtils._WATERSHED_GROUP_NAME)
         if floodLayer is None:
             QSWATUtils.error('Failed to load floodplain raster {0}' \
                              .format(self.floodplainRaster.fileName), self._gv.isBatch)
示例#19
0
from shapely.geometry import Point
from raster import Raster

"""
USAGE:
./reachID_grid_to_vector_points.py <flows_grid_IDs raster file> <flows_points vector file> <reachID or featureID>

"""

path = sys.argv[1]
outputFileName = sys.argv[2]
writeOption = sys.argv[3]

#r = gdal.Open(path)
#band = r.GetRasterBand(1)
boolean=Raster(path)

#(upper_left_x, x_size, x_rotation, upper_left_y, y_rotation, y_size) = r.GetGeoTransform()
(upper_left_x, x_size, x_rotation, upper_left_y, y_rotation, y_size) = boolean.gt

#a = band.ReadAsArray().astype(np.float)

# indices = np.nonzero(a != band.GetNoDataValue())
indices = np.nonzero(boolean.array >= 1)

# Init the shapefile stuff..
#srs = osgeo.osr.SpatialReference()
#srs.ImportFromWkt(r.GetProjection())

#driver = osgeo.ogr.GetDriverByName('GPKG')
#shapeData = driver.CreateDataSource(outputFileName)
示例#20
0
文件: panel.py 项目: DexterLB/ui
 def __init__(self):
     self.items = defaultdict(PanelStrip)
     self.width = Raster.image_width(PanelVisual.background_image)
示例#21
0
    def mapping(self, crop_id, covariate_rasters, conn, covariate_root_dir,
                suit_root_dir):

        raster = Raster()
        self.no_data = raster.getNoDataValue(covariate_rasters[-1])
        ref_rst = covariate_rasters[-1]
        covariate_id_list = []
        suit_array_stack = []

        filepath = strip_end(ref_rst, ref_rst.split('\\')[-1])
        out_dir = join(
            suit_root_dir,
            strip_start(filepath, covariate_root_dir)[1:]
        )  # the [1:] is for removing the first and the last '\' of string

        if not os.path.exists(out_dir):
            os.makedirs(out_dir, exist_ok=True)

        for rst in covariate_rasters:

            filename = rst.split('\\')[-1].split('.')[0]

            if len(filename.split('_')) == 1:
                covariate_id = filename
                covariate_id_list.append(covariate_id)
                out_raster = join(
                    out_dir,
                    'suitability_{}_{}.tif'.format(crop_id, covariate_id))
            else:
                covariate_id = filename.split('_')[1]
                covariate_id_list.append(covariate_id)
                time_span = '{}_{}'.format(
                    filename.split('_')[-2],
                    filename.split('_')[-1])
                out_raster = join(
                    out_dir,
                    'suitability_{}_{}_{}.tif'.format(crop_id, covariate_id,
                                                      time_span))

            with conn as cur:
                rows = cur.execute(
                    "select * from suitability_rule where crop_id=? and covariate_id=? order by suitability_level",
                    (
                        crop_id,
                        covariate_id,
                    )).fetchall()
                is_continual = cur.execute(
                    "select * from Covariate where id=?",
                    (covariate_id, )).fetchone()['iscontinual']

            # If the query returns none then move to the next covariate
            if rows:
                covariate_array = raster.getRasterArray(
                    rst)  # array of the covariate

                if is_continual == 1:
                    suit_array = self.__reclassify_contianual__(
                        covariate_array, rows)
                else:
                    suit_array = self.__reclassify_catorgorical__(
                        covariate_array, rows)

                suit_array[np.where(
                    covariate_array == self.no_data)] = self.no_data

                raster.array2Raster(suit_array, ref_rst, out_raster)

                suit_array_stack.append(suit_array)
            else:
                print(
                    'Warning! Suitability ruleset for {}, {} not found! Please check the database.'
                    .format(crop_id, covariate_id))

        if len(suit_array_stack) > 0:
            crop_suit_array = ExtractMaxValueOfStack(suit_array_stack)
            ref_array = homogenize_nodata_area(suit_array_stack, self.no_data)
            crop_suit_array[np.where(ref_array == self.no_data)] = self.no_data
            crop_suit_raster = join(out_dir,
                                    '{}_suitability.tif'.format(crop_id))
            raster.array2Raster(crop_suit_array, ref_rst, crop_suit_raster)

            print('create dominant worst covariate raster at {}...'.format(
                dt.datetime.now()))
            worst_dominant_array, worst_count_array, worst_dominant_legend_list = ExtractMaxValueIndexBinaryOfStack(
                suit_array_stack, covariate_id_list, 4)

            worst_dominant_array[np.where(
                ref_array == self.no_data)] = self.no_data
            worst_dominant_raster_file = join(
                out_dir, '{}_worst_dominant.tif'.format(crop_id))
            raster.array2Raster(worst_dominant_array, ref_rst,
                                worst_dominant_raster_file)

            worst_count_array[np.where(
                ref_array == self.no_data)] = self.no_data
            worst_count_raster_file = join(
                out_dir, '{}_worst_count.tif'.format(crop_id))
            raster.array2Raster(worst_count_array, ref_rst,
                                worst_count_raster_file)

            worst_dominant_legend_csv = join(
                out_dir, '{}_worst_dominant_legend.csv'.format(crop_id))
            csvw = CSVOperation.CSVWriting()
            headers = ['raster value', 'number of restriction', 'covariates']
            csvw.WriteLines(worst_dominant_legend_csv, headers,
                            worst_dominant_legend_list)
        else:
            print('Warning! No suitability map for {} was created!'.format(
                crop_id))
示例#22
0
def _calc_cost_of_per_hectare_inputs(vars_dict, crop, lulc_raster):
    '''
    CostPerHectareInputTotal_crop = Mask_raster * CostPerHectare_input *
        ha_per_cell
    '''

    # Determine the crop lucode based on its name
    crop_lucode = None
    for lucode, luname in vars_dict['crop_lookup_dict'].iteritems():
        if luname == crop:
            crop_lucode = lucode
            continue

    lulc_nodata = pygeoprocessing.get_nodata_from_uri(lulc_raster.uri)
    economics_table_crop = vars_dict['economics_table_dict'][crop]
    datatype_out = gdal.GDT_Float32
    nodata_out = NODATA_FLOAT
    pixel_size_out = pygeoprocessing.get_cell_size_from_uri(lulc_raster.uri)
    ha_per_m2 = 0.0001
    cell_area_ha = pixel_size_out**2 * ha_per_m2

    # The scalar cost is identical for all crop pixels of the current class,
    # and is based on the presence of absence of columns in the user-provided
    # economics table.  We only need to calculate this once.
    cost_scalar = 0.0
    for key in ['cost_labor_per_ha', 'cost_machine_per_ha', 'cost_seed_per_ha', 'cost_irrigation_per_ha']:
        try:
            cost_scalar += (economics_table_crop[key] * cell_area_ha)
        except KeyError:
            LOGGER.warning('Key missing from economics table: %s', key)

    def _calculate_cost(lulc_matrix):
        """
        Calculate the total cost on a single pixel.

        <pseudocode>
            If lulc_pixel is nodata:
                return nodata
            else:
                if lulc_pixel is of our crop type:
                    return the cost of this crop (in cost_scalar, above)
                else:
                    return 0.0
        </pseudocode>
        """
        return np.where(lulc_matrix == lulc_nodata, nodata_out,
                        np.where(lulc_matrix == crop_lucode, cost_scalar, 0.0))

    new_raster_uri = pygeoprocessing.geoprocessing.temporary_filename()
    pygeoprocessing.vectorize_datasets(
        [lulc_raster.uri],
        _calculate_cost,
        new_raster_uri,
        datatype_out,
        nodata_out,
        pixel_size_out,
        bounding_box_mode='intersection',
        vectorize_op=False,
        datasets_are_pre_aligned=True
    )

    return Raster.from_file(new_raster_uri, 'GTiff')
示例#23
0
# -*- coding: utf-8 -*-
"""
Created on Mon Jul  2 15:53:48 2018

@author: guoj
"""

from osgeo import gdal, ogr, osr
from os.path import join
import numpy as np
from raster import Raster

rst = Raster()

class GeoProcessing(object):
    def __init__(self, no_data):
        self.no_data = no_data
    
    def strip_end(self, text, suffix):
        if not text.endswith(suffix):
            return text
        return text[:len(text)-len(suffix)]
    
    def strip_start(self, text, suffix):
        if not text.startswith(suffix):
            return text
        return text[len(suffix):]        
    
    def reproject_raster2(self, dataset, refdataset, outrst):
    
        g = gdal.Open(dataset)
示例#24
0
def filter():
    test_dir = os.path.dirname(os.path.abspath(__file__)) + os.path.sep + 'test_data' + os.path.sep
    test_file = test_dir + 'test.dep'
    output_file = test_dir + 'delete_me.dep'

    print('Reading data...')
    raster = Raster.from_file(test_file)

    output = Raster.create_from_other(output_file, raster)

    filter_size = 7
    mid_point = int(filter_size / 2.0)
    dx = []
    dy = []
    for r in range(filter_size):
        for c in range(filter_size):
            dx.append(c - mid_point)
            dy.append(r - mid_point)

    num_neighbours = len(dx)
    threshold = 10.0

    values = [0.0]*num_neighbours
    w = [0.0]*num_neighbours

    old_progress = 1
    for row in range(raster.rows):
        for col in range(raster.columns):
            z = raster[row, col]
            if z != raster.nodata:
                sum_w = 0.0
                for n in range(num_neighbours):
                    xn = col + dx[n]
                    yn = row + dy[n]
                    zn = raster[yn, xn]
                    if zn != raster.nodata:
                        values[n] = zn
                        diff = math.fabs(zn - z)
                        if diff < threshold:
                            w[n] = 1.0 - diff / threshold
                            sum_w += w[n]
                        else:
                            values[n] = 0.0
                            w[n] = 0.0
                    else:
                        values[n] = 0.0
                        w[n] = 0.0

                if sum_w > 0.0:
                    z = 0.0
                    for n in range(num_neighbours):
                        z += values[n] * w[n] / sum_w

                output[row, col] = z


        progress = int(100.0 * (row+1) / raster.rows)
        if progress != old_progress:
            print('progress: {}%'.format(progress))
            old_progress = progress

    print('Saving data...')
    output.write()
示例#25
0
 def __init__(self, image_file, ignore_background=False, overlay=False):
     self.width = Raster.image_width(image_file)
     self.image_file = image_file
     self.ignore_background = ignore_background
     self.overlay = overlay
示例#26
0
timeSteps = []

Helios = helios.DAC()

try:
    """
    stats = {
        'frameNum': 0,
        'startTime': time.time(),
        'lastTime': time.time(),
        'curTime': time.time(),
        'timeStep': 0.01,
        '
        """
    clem = Raster('clementine.png')
    clock = Clock()
    frameNum = 0
    startTime = time.time()
    lastTime = startTime
    while True:
        curTime = time.time()
        timeStep = curTime - lastTime
        timeSteps.append(timeStep)
        elapsed = curTime - startTime
        frameNum += 1
        fps = 1 / timeStep

        if frameNum % msgOutputInterval == 0:
            print "\rFrame", frameNum, "Elapsed", elapsed, \
             "Time Step", timeStep, "Fps", fps, \
示例#27
0
 def calRidgeHeghtsByBranchLength(self, subbasins, distances, slopeDir,
                                  flowAcc, valleyDepthsFile, root, mustRun):
     """
     Create the ridgeHeightsRaster with differences between the elevation at the point and 
     the elevation of the nearest ridge cell.
     
     subbasins is the subbasins raster, distances is the distances to outlet raster, 
     slopeDir is the D8 slope directions raster, flowAcc the flow accumulation raster, all four clipped 
     the same as the DEM.
     valleyDepthsFile is the existing raster  giving the depth of the valley flow below each point (as a positive number of metres).
     """
     self.ridgeHeightsFile = QSWATUtils.join(self._gv.demDir,
                                             'branchheights.tif')
     distancesFile = QSWATUtils.join(self._gv.demDir,
                                     'branchdistancess.tif')
     if mustRun or not QSWATUtils.isUpToDate(subbasins, self.ridgeHeightsFile) \
         or not QSWATUtils.isUpToDate(distances, self.ridgeHeightsFile) \
         or not QSWATUtils.isUpToDate(slopeDir, self.ridgeHeightsFile) \
         or not QSWATUtils.isUpToDate(flowAcc, self.ridgeHeightsFile):
         self._gv.clearOpenRasters()
         completed = False
         while not completed:
             try:
                 completed = True  # only gets set on MemoryError exception
                 if os.path.exists(self.ridgeHeightsFile):
                     QSWATUtils.tryRemoveLayerAndFiles(
                         self.ridgeHeightsFile, root)
                 if os.path.exists(distancesFile):
                     QSWATUtils.tryRemoveLayerAndFiles(distancesFile, root)
                 self.ridgeHeightsRaster = Raster(self.ridgeHeightsFile,
                                                  self._gv,
                                                  canWrite=True,
                                                  isInt=False)
                 res = self.ridgeHeightsRaster.open(
                     self.chunkCount,
                     numRows=self.numRows,
                     numCols=self.numCols,
                     transform=self.demTransform,
                     projection=self.demProjection,
                     noData=self.noData)
                 if not res:
                     return False
                 self.ridgeDistancesRaster = Raster(distancesFile,
                                                    self._gv,
                                                    canWrite=True,
                                                    isInt=False)
                 res = self.ridgeDistancesRaster.open(
                     self.chunkCount,
                     numRows=self.numRows,
                     numCols=self.numCols,
                     transform=self.demTransform,
                     projection=self.demProjection,
                     noData=self.noData)
                 if not res:
                     self._gv.closeOpenRasters()
                     return False
                 subbasinsRaster = Raster(subbasins,
                                          self._gv,
                                          canWrite=False,
                                          isInt=True)
                 res = subbasinsRaster.open(self.chunkCount)
                 if not res:
                     self._gv.closeOpenRasters()
                     return False
                 distRaster = Raster(distances,
                                     self._gv,
                                     canWrite=False,
                                     isInt=False)
                 res = distRaster.open(self.chunkCount)
                 if not res:
                     self._gv.closeOpenRasters()
                     return False
                 self.findRidges(subbasinsRaster, distRaster, root)
                 subbasinsRaster.close()
                 distRaster.close()
                 accRaster = Raster(flowAcc,
                                    self._gv,
                                    canWrite=False,
                                    isInt=True)
                 res = accRaster.open(self.chunkCount)
                 if not res:
                     self._gv.closeOpenRasters()
                     return False
                 dirRaster = Raster(slopeDir,
                                    self._gv,
                                    canWrite=False,
                                    isInt=True)
                 res = dirRaster.open(self.chunkCount)
                 if not res:
                     self._gv.closeOpenRasters()
                     return False
                 self.propagateFromRidges(valleyDepthsFile, dirRaster,
                                          accRaster)
                 dirRaster.close()
                 accRaster.close()
                 self.ridgeHeightsRaster.close()
                 self.ridgeDistancesRaster.close()
                 return True
             except MemoryError:
                 QSWATUtils.loginfo(
                     'Out of memory for ridge heights by branch length with chunk count {0}'
                     .format(self.chunkCount))
                 self._gv.closeOpenRasters()
                 completed = False
                 self.chunkCount += 1
                 if not self.demRaster.open(self.chunkCount):
                     return False
     else:
         return True
示例#28
0
 def calcRidgeHeightsByInversion(self, ridgep, ridges, root, mustRun):
     """
     Create the ridgeHeightsRaster with differences between the elevation at the point and 
     the elevation of the nearest ridge cell.
     
     ridgep is the D8 flow directions and ridges the flow accumulation raster , both calculated from an inverted DEM.
     """
     self.ridgeHeightsFile = QSWATUtils.join(self._gv.demDir,
                                             'invheights.tif')
     if mustRun or not QSWATUtils.isUpToDate(
             ridgep, self.ridgeHeightsFile) or not QSWATUtils.isUpToDate(
                 ridges, self.ridgeHeightsFile):
         self._gv.clearOpenRasters()
         completed = False
         while not completed:
             try:
                 completed = True  # only gets set on MemoryError exception
                 if os.path.exists(self.ridgeHeightsFile):
                     QSWATUtils.tryRemoveLayerAndFiles(
                         self.ridgeHeightsFile, root)
                 self.ridgeHeightsRaster = Raster(self.ridgeHeightsFile,
                                                  self._gv,
                                                  canWrite=True,
                                                  isInt=False)
                 res = self.ridgeHeightsRaster.open(
                     self.chunkCount,
                     numRows=self.numRows,
                     numCols=self.numCols,
                     transform=self.demTransform,
                     projection=self.demProjection,
                     noData=self.noData)
                 if not res:
                     return False
                 # ridgep obtained by inversion has float values, although these are in the range 1 to 8
                 ridgepRaster = Raster(ridgep,
                                       self._gv,
                                       canWrite=False,
                                       isInt=False)
                 res = ridgepRaster.open(self.chunkCount)
                 if not res:
                     self._gv.closeOpenRasters()
                     return False
                 ridgesRaster = Raster(ridges,
                                       self._gv,
                                       canWrite=False,
                                       isInt=True)
                 res = ridgesRaster.open(self.chunkCount)
                 if not res:
                     self._gv.closeOpenRasters()
                     return False
                 for row in range(self.numRows):
                     for col in range(self.numCols):
                         if self.demRaster.read(row, col) != self.demNoData:
                             (val, path) = self.valueAtNearest(
                                 row, col, ridgepRaster, ridgesRaster,
                                 self.ridgeThresh)
                             if path is not None:
                                 self.propagate(val, path)
                 ridgepRaster.close()
                 ridgesRaster.close()
                 self.ridgeHeightsRaster.close()
                 return True
             except MemoryError:
                 QSWATUtils.loginfo(
                     'Out of memory for ridge heights by inversion with chunk count {0}'
                     .format(self.chunkCount))
                 self._gv.closeOpenRasters()
                 completed = False
                 self.chunkCount += 1
                 if not self.demRaster.open(self.chunkCount):
                     return False
     else:
         return True
示例#29
0
 def update(self, text):
     self.text = text
     self.width = Raster.text_width(text)
示例#30
0
    def create_climate_covariates(self, climate_dir, start_year, end_year,
                                  key_min, key_max, key_pcp, out_dir):
        abstemp = 273.15

        year_list = cc.getYearList(start_year, end_year)
        climate_covariate = cc.ClimaticCovariates(year_list, climate_dir)
        ref_raster = climate_covariate.ref_raster

        out_raster = Raster()

        crops_id = []
        crops = []

        with self.conn as cur:
            rows = cur.execute("select * from crop").fetchall()

        if rows:
            print('Start to generate climate covariates...')
            for row in rows:
                crops_id.append(row['id'])
                crops.append(row['crop'])

            for crop_id, crop in zip(crops_id, crops):

                print(crop)
                with self.conn as cur:
                    covariates = cur.execute(
                        "select * from covariate_threshold where crop_id=?",
                        (crop_id, )).fetchall()

                if covariates:
                    for covariate in covariates:
                        with self.conn as cur:
                            covariate_name = cur.execute(
                                "select covariate from Covariate where id=?",
                                (covariate['covariate_id'],
                                 )).fetchone()['covariate']
                        print('Generate {} at {} ...'.format(
                            covariate_name, dt.datetime.now()))

                        if covariate['t_below'] is not None:
                            try:
                                t_below = float(covariate['t_below']) + abstemp
                            except ValueError:
                                t_below = None
                        else:
                            t_below = None

                        if covariate['t_above'] is not None:
                            try:
                                t_above = float(covariate['t_above']) + abstemp
                            except ValueError:
                                t_above = None
                        else:
                            t_above = None

                        if covariate['pcp_above'] is not None:
                            try:
                                pcp_above = float(covariate['pcp_above'])
                            except ValueError:
                                pcp_above = None
                        else:
                            pcp_above = None

                        if covariate['pcp_below'] is not None:
                            try:
                                pcp_below = float(covariate['pcp_below'])
                            except ValueError:
                                pcp_below = None
                        else:
                            pcp_below = None

                        out_sub_dir = join(out_dir, crop)
                        if not os.path.exists(out_sub_dir):
                            os.makedirs(out_sub_dir, exist_ok=True)

                        covariate_array = cc.generate(
                            covariate['covariate_id'], year_list, climate_dir,
                            covariate['start_date'], covariate['end_date'],
                            key_min, key_max, key_pcp, t_below, t_above,
                            pcp_above, pcp_below, out_sub_dir, crop_id,
                            covariate['covariate_id'], ref_raster)

                        try:
                            if covariate_array is not None:

                                out_raster_file = join(
                                    out_sub_dir, '{}_{}_{}_{}.tif'.format(
                                        crop_id, covariate['covariate_id'],
                                        start_year, end_year))
                                out_raster.array2Raster(
                                    covariate_array, ref_raster,
                                    out_raster_file)
                        except:
                            pass
示例#31
0
def calc_percentile_yield(vars_dict):
    '''
    Calculates yield using the percentile yield function

    Example Args::

        vars_dict = {
            'percentile_yield_dict': {
                ''
            },
            '': ''
        }
    '''
    vars_dict['crop_production_dict'] = {}
    vars_dict = _create_yield_func_output_folder(
        vars_dict, "climate_percentile_yield")

    lulc_raster = Raster.from_file(
        vars_dict['lulc_map_uri']).set_nodata(NODATA_INT)
    aoi_vector = Vector.from_shapely(
        lulc_raster.get_aoi(), lulc_raster.get_projection())
    percentile_yield_dict = vars_dict['percentile_yield_dict']

    # setup useful base rasters
    base_raster_float = lulc_raster.set_datatype_and_nodata(
        gdal.GDT_Float64, NODATA_FLOAT)

    crops = vars_dict['crops_in_aoi_list']
    crop = crops[0]
    climate_bin = percentile_yield_dict[crop].keys()[0]
    percentiles = percentile_yield_dict[crop][climate_bin].keys()

    percentile_count = 1
    for percentile in percentiles:
        vars_dict['crop_production_dict'] = {}
        if vars_dict['do_economic_returns']:
            economics_table = vars_dict['economics_table_dict']
            returns_raster = base_raster_float.zeros()

        for crop in crops:
            LOGGER.info('Calculating percentile yield for %s in %s' % (
                crop, percentile))
            # Wrangle Data...
            climate_bin_raster = _get_climate_bin_over_lulc(
                vars_dict, crop, aoi_vector, base_raster_float)

            reclass_dict = {}
            climate_bins = percentile_yield_dict[crop].keys()
            for climate_bin in climate_bins:
                reclass_dict[climate_bin] = percentile_yield_dict[
                    crop][climate_bin][percentile]

            # Find Yield and Production
            crop_yield_raster = climate_bin_raster.reclass(reclass_dict)

            masked_lulc_raster = _get_masked_lulc_raster(
                vars_dict, crop, lulc_raster).set_datatype_and_nodata(
                gdal.GDT_Float64, NODATA_FLOAT)

            yield_raster = crop_yield_raster.reclass_masked_values(
                masked_lulc_raster, 0)

            Production_raster = _calculate_production_for_crop(
                vars_dict, crop, yield_raster, percentile=percentile)

            total_production = float(round(
                Production_raster.sum(), 2))
            vars_dict['crop_production_dict'][crop] = total_production

            if vars_dict['do_economic_returns']:
                returns_raster_crop = _calc_crop_returns(
                    vars_dict,
                    crop,
                    lulc_raster,
                    Production_raster,
                    returns_raster,
                    economics_table[crop])
                returns_raster = returns_raster + returns_raster_crop

            # Clean Up Rasters...
            del climate_bin_raster
            del crop_yield_raster
            del masked_lulc_raster
            del yield_raster
            del Production_raster

        if vars_dict['do_nutrition']:
            vars_dict = _calc_nutrition(vars_dict)

        # Results Table
        if percentile_count == 1:
            io.create_results_table(vars_dict, percentile=percentile)
        else:
            io.create_results_table(
                vars_dict, percentile=percentile, first=False)
        percentile_count += 1

        if all([vars_dict['do_economic_returns'], vars_dict[
                'create_crop_production_maps']]):
            output_observed_yield_dir = vars_dict['output_yield_func_dir']
            returns_uri = os.path.join(
                output_observed_yield_dir,
                'economic_returns_map_' + percentile + '.tif')
            returns_raster.save_raster(returns_uri)

    return vars_dict
示例#32
0
from matplotlib import pyplot as plt
from mpl_toolkits.axes_grid1 import host_subplot


#Spawn the grid with given visual dimensions:
x_dim = 70
y_dim = 70
spawn_probability = 10 #As in 1 in 4 cells spawn
limit = (x_dim*y_dim)/spawn_probability
quadrants = 4

ind = np.arange(quadrants)
width = 0.35


raster = Raster(x_dim, y_dim)
raster.random_spawn(spawn_probability)

#Block
raster.pop_form('Glider',2,2)
raster.pop_form('Toad',15,5)
raster.pop_form('Glider',10,10)
raster.pop_form('Toad', 24,24)
raster.pop_form('Glider', 30,5)
raster.pop_form('Glider', 40,60)


fig  = figure(facecolor='white')

#Add Axes to the figure
ax01 = fig.add_subplot(121, autoscale_on=True, label='Simulation') #Aspect='equal'
示例#33
0
class Floodplain(QObject):
    """
    Calculate floodplain raster  from DEM, stream threshold, ridge threshold, floodplain threshold,
    (optionally) D8 flow direction grid, flow accumulation grid, outlets shapefile.
     
    The slope position value is, for each point, (e - v) / (r - v) where e is the elevation, 
    v the nearest valley floor elevation, and r the nearest ridge elevation.  Nearest means along D8 flow path.
    Valley floor is points with flow accumulation above stream generation threshold.
    Ridge is similar, obtained by inverting DEM, then calculating D8 flow direction and accumulation.
    The floodplain raster  is zero for points with slope position value at most the floodplain threshold, else 1.
    """
    def __init__(self, gv, progress, chunkCount):
        """Initialise class variables."""
        QObject.__init__(self)
        self._gv = gv
        self._progress = progress
        ## raster  chunk count
        self.chunkCount = chunkCount
        ## ridge accumulation threshold
        self.ridgeThresh = 0
        ## floodplain accumulation threshold
        self.floodThresh = 0
        ## branch length threshold
        self.branchThresh = 0
        ## dem raster  dataset
        self.demDs = None
        ## dem raster  transform
        self.demTransform = None
        ## dem raster
        self.demRaster = None
        ## dem raster  no data value
        self.demNoData = -1
        ## dem raster  projection
        self.demProjection = None
        ## no data value for output rasters; must be negative
        self.noData = -1
        ## number of rows in input clipped DEM raster
        self.numRows = 0
        ## number of columns in input clipped DEM raster
        self.numCols = 0
        ## depths of valley floor below points
        self.valleyDepthsRaster = None
        ## file path for ridgeHeightsRaster
        self.ridgeHeightsFile = ''
        ## heights of ridge above points
        self.ridgeHeightsRaster = None
        ## distances of ridge from points
        self.ridgeDistancesRaster = None
        ## floodplain raster
        self.floodplainRaster = None
        ## flag to indicate if using inversion or branch length method
        self.useInversion = True
        ## map of (row, col) to (elevation, branch length) for ridge points
        self.ridgePoints = None

    def run(self, demRaster, valleyDepthsFile, ridgeThresh, floodThresh,
            branchThresh, subbasins, distances, slopeDir, flowAcc, ridgep,
            ridges, noData, mustRun):
        """
        Generate floodplain raster , with floodplain value 0 and upland value 1.
        
        valleyDepthsRaster is already calculated and stored in valleyDepthsFile
        ridgeThresh is the threshold in pixel counts for ridges (inverse accumulation).
        floodThresh is the critical ratio of relative depth of valley floor against height of ridge above valley floor.
        branchThresh is the threshold in metres for branch lengths.
        dem is clipped filled DEM
        The groups {subbasins, distances, slopeDir, flowAcc} and {ridgep, ridges} are either all None or all existing files,
        assumed to be clipped and with same pixel size as DEM (so (row, col|) coordinates may be shared across all of them).
        The second group is used to calculate ridges by DEM inversion if subbasins is None, else the first is used to 
        calculate ridges by branch lengths.
        """
        self.demRaster = demRaster
        self.ridgeThresh = ridgeThresh
        self.floodThresh = floodThresh
        self.branchThresh = branchThresh
        gdal.AllRegister()
        ds = self.demRaster.ds
        self.numRows = ds.RasterYSize
        self.numCols = ds.RasterXSize
        self.demTransform = ds.GetGeoTransform()
        self.demNoData = self.demRaster.band.GetNoDataValue()
        self.demProjection = ds.GetProjection()
        self.noData = noData
        self._progress('Ridge heights ...')
        root = QgsProject.instance().layerTreeRoot()
        if subbasins is None:
            # use inverted DEM method for ridges
            self.useInversion = True
            time1 = time.process_time()
            if not self.calcRidgeHeightsByInversion(ridgep, ridges, root,
                                                    mustRun):
                return
            time2 = time.process_time()
            QSWATUtils.loginfo(
                'Ridge heights by inversion took {0} seconds'.format(
                    int(time2 - time1)))
        else:
            self.useInversion = False
            time1 = time.process_time()
            if not self.calRidgeHeghtsByBranchLength(
                    subbasins, distances, slopeDir, flowAcc, valleyDepthsFile,
                    root, mustRun):
                return
            time2 = time.process_time()
            QSWATUtils.loginfo(
                'Ridge heights by branch length took {0} seconds'.format(
                    int(time2 - time1)))
        time1 = time.process_time()
        self.writeFloodPlain(valleyDepthsFile, mustRun)
        time2 = time.process_time()
        QSWATUtils.loginfo('Floodplain creation took {0} seconds'.format(
            int(time2 - time1)))
        self._progress('')

    def calcRidgeHeightsByInversion(self, ridgep, ridges, root, mustRun):
        """
        Create the ridgeHeightsRaster with differences between the elevation at the point and 
        the elevation of the nearest ridge cell.
        
        ridgep is the D8 flow directions and ridges the flow accumulation raster , both calculated from an inverted DEM.
        """
        self.ridgeHeightsFile = QSWATUtils.join(self._gv.demDir,
                                                'invheights.tif')
        if mustRun or not QSWATUtils.isUpToDate(
                ridgep, self.ridgeHeightsFile) or not QSWATUtils.isUpToDate(
                    ridges, self.ridgeHeightsFile):
            self._gv.clearOpenRasters()
            completed = False
            while not completed:
                try:
                    completed = True  # only gets set on MemoryError exception
                    if os.path.exists(self.ridgeHeightsFile):
                        QSWATUtils.tryRemoveLayerAndFiles(
                            self.ridgeHeightsFile, root)
                    self.ridgeHeightsRaster = Raster(self.ridgeHeightsFile,
                                                     self._gv,
                                                     canWrite=True,
                                                     isInt=False)
                    res = self.ridgeHeightsRaster.open(
                        self.chunkCount,
                        numRows=self.numRows,
                        numCols=self.numCols,
                        transform=self.demTransform,
                        projection=self.demProjection,
                        noData=self.noData)
                    if not res:
                        return False
                    # ridgep obtained by inversion has float values, although these are in the range 1 to 8
                    ridgepRaster = Raster(ridgep,
                                          self._gv,
                                          canWrite=False,
                                          isInt=False)
                    res = ridgepRaster.open(self.chunkCount)
                    if not res:
                        self._gv.closeOpenRasters()
                        return False
                    ridgesRaster = Raster(ridges,
                                          self._gv,
                                          canWrite=False,
                                          isInt=True)
                    res = ridgesRaster.open(self.chunkCount)
                    if not res:
                        self._gv.closeOpenRasters()
                        return False
                    for row in range(self.numRows):
                        for col in range(self.numCols):
                            if self.demRaster.read(row, col) != self.demNoData:
                                (val, path) = self.valueAtNearest(
                                    row, col, ridgepRaster, ridgesRaster,
                                    self.ridgeThresh)
                                if path is not None:
                                    self.propagate(val, path)
                    ridgepRaster.close()
                    ridgesRaster.close()
                    self.ridgeHeightsRaster.close()
                    return True
                except MemoryError:
                    QSWATUtils.loginfo(
                        'Out of memory for ridge heights by inversion with chunk count {0}'
                        .format(self.chunkCount))
                    self._gv.closeOpenRasters()
                    completed = False
                    self.chunkCount += 1
                    if not self.demRaster.open(self.chunkCount):
                        return False
        else:
            return True

    def calRidgeHeghtsByBranchLength(self, subbasins, distances, slopeDir,
                                     flowAcc, valleyDepthsFile, root, mustRun):
        """
        Create the ridgeHeightsRaster with differences between the elevation at the point and 
        the elevation of the nearest ridge cell.
        
        subbasins is the subbasins raster, distances is the distances to outlet raster, 
        slopeDir is the D8 slope directions raster, flowAcc the flow accumulation raster, all four clipped 
        the same as the DEM.
        valleyDepthsFile is the existing raster  giving the depth of the valley flow below each point (as a positive number of metres).
        """
        self.ridgeHeightsFile = QSWATUtils.join(self._gv.demDir,
                                                'branchheights.tif')
        distancesFile = QSWATUtils.join(self._gv.demDir,
                                        'branchdistancess.tif')
        if mustRun or not QSWATUtils.isUpToDate(subbasins, self.ridgeHeightsFile) \
            or not QSWATUtils.isUpToDate(distances, self.ridgeHeightsFile) \
            or not QSWATUtils.isUpToDate(slopeDir, self.ridgeHeightsFile) \
            or not QSWATUtils.isUpToDate(flowAcc, self.ridgeHeightsFile):
            self._gv.clearOpenRasters()
            completed = False
            while not completed:
                try:
                    completed = True  # only gets set on MemoryError exception
                    if os.path.exists(self.ridgeHeightsFile):
                        QSWATUtils.tryRemoveLayerAndFiles(
                            self.ridgeHeightsFile, root)
                    if os.path.exists(distancesFile):
                        QSWATUtils.tryRemoveLayerAndFiles(distancesFile, root)
                    self.ridgeHeightsRaster = Raster(self.ridgeHeightsFile,
                                                     self._gv,
                                                     canWrite=True,
                                                     isInt=False)
                    res = self.ridgeHeightsRaster.open(
                        self.chunkCount,
                        numRows=self.numRows,
                        numCols=self.numCols,
                        transform=self.demTransform,
                        projection=self.demProjection,
                        noData=self.noData)
                    if not res:
                        return False
                    self.ridgeDistancesRaster = Raster(distancesFile,
                                                       self._gv,
                                                       canWrite=True,
                                                       isInt=False)
                    res = self.ridgeDistancesRaster.open(
                        self.chunkCount,
                        numRows=self.numRows,
                        numCols=self.numCols,
                        transform=self.demTransform,
                        projection=self.demProjection,
                        noData=self.noData)
                    if not res:
                        self._gv.closeOpenRasters()
                        return False
                    subbasinsRaster = Raster(subbasins,
                                             self._gv,
                                             canWrite=False,
                                             isInt=True)
                    res = subbasinsRaster.open(self.chunkCount)
                    if not res:
                        self._gv.closeOpenRasters()
                        return False
                    distRaster = Raster(distances,
                                        self._gv,
                                        canWrite=False,
                                        isInt=False)
                    res = distRaster.open(self.chunkCount)
                    if not res:
                        self._gv.closeOpenRasters()
                        return False
                    self.findRidges(subbasinsRaster, distRaster, root)
                    subbasinsRaster.close()
                    distRaster.close()
                    accRaster = Raster(flowAcc,
                                       self._gv,
                                       canWrite=False,
                                       isInt=True)
                    res = accRaster.open(self.chunkCount)
                    if not res:
                        self._gv.closeOpenRasters()
                        return False
                    dirRaster = Raster(slopeDir,
                                       self._gv,
                                       canWrite=False,
                                       isInt=True)
                    res = dirRaster.open(self.chunkCount)
                    if not res:
                        self._gv.closeOpenRasters()
                        return False
                    self.propagateFromRidges(valleyDepthsFile, dirRaster,
                                             accRaster)
                    dirRaster.close()
                    accRaster.close()
                    self.ridgeHeightsRaster.close()
                    self.ridgeDistancesRaster.close()
                    return True
                except MemoryError:
                    QSWATUtils.loginfo(
                        'Out of memory for ridge heights by branch length with chunk count {0}'
                        .format(self.chunkCount))
                    self._gv.closeOpenRasters()
                    completed = False
                    self.chunkCount += 1
                    if not self.demRaster.open(self.chunkCount):
                        return False
        else:
            return True

    def valueAtNearest(self, row, col, d8Raster, accRaster, threshold):
        """
        Return the positive elevation of the nearest point in accRaster where it is at least threshold,
        plus path along d8Raster to that point.
        
        If a value is found in result, point already processed, return result - elevation for that point.
        We are working upslope, final height is ridge height,
        ridgeHeights contains ridge - elev, i.e. positive height of ridge above point, 
        so if result already exists, ridge is recovered as result + elev
        """
        path = []
        accNoData = accRaster.band.GetNoDataValue()
        while True:
            res = self.ridgeHeightsRaster.read(row, col)
            if res >= 0:  # already done this point
                # eg result is 60, this point's elevation is 100, return value (ridge elevation) is 160
                return (self.demRaster.read(row, col) + res, path)
            acc = accRaster.read(row, col)
            if acc >= threshold or acc == accNoData:  # found nearest stopping point
                path.append((row, col))
                return (self.demRaster.read(row, col), path)
            if (row, col) in path:
                (startRow, startCol) = path[0]
                startX, startY = QSWATTopology.cellToProj(
                    startCol, startRow, self.demTransform)
                x, y = QSWATTopology.cellToProj(col, row, self.demTransform)
                QSWATUtils.error(
                    'Loop to ({0}, {1}) from ({2}, {3})'.format(
                        x, y, startX, startY), self._gv.isBatch)
                return (0, None)
            path.append((row, col))
            pt, _ = self.alongDirPoint(row, col, d8Raster)
            if pt is None:
                # hit edge of clipped area = must be a ridge
                return (self.demRaster.read(row, col), path)
            (row, col) = pt

    def propagate(self, val, path):
        """
        For each point on path, set result to val (ridge elevation) - point elevation."""
        for (row, col) in path:
            self.ridgeHeightsRaster.write(row, col,
                                          val - self.demRaster.read(row, col))

    def writeFloodPlain(self, valleyDepthsFile, mustRun):
        """Calculate slope positions from valleyDepths and ridgeHeights, and write floodplain raster ."""
        method = 'inv' if self.useInversion else 'branch'
        thresh = '{0:.2F}'.format(self.floodThresh).replace('.', '_')
        flood = QSWATUtils.join(self._gv.floodDir,
                                method + 'flood' + thresh + '.tif')
        root = QgsProject.instance().layerTreeRoot()
        if mustRun or \
            not QSWATUtils.isUpToDate(valleyDepthsFile, flood) or \
            not QSWATUtils.isUpToDate(self.ridgeHeightsFile, flood):
            if os.path.exists(flood):
                QSWATUtils.tryRemoveLayerAndFiles(flood, root)
            self._gv.clearOpenRasters()
            completed = False
            while not completed:
                try:
                    completed = True  # only gets set on MemoryError exception
                    self.ridgeHeightsRaster = Raster(self.ridgeHeightsFile,
                                                     self._gv,
                                                     canWrite=False,
                                                     isInt=False)
                    res = self.ridgeHeightsRaster.open(self.chunkCount)
                    if not res:
                        self._gv.closeOpenRasters()
                        return
                    if self.valleyDepthsRaster is None:
                        # may have been opened when calculating ridge heights by branch length
                        self.valleyDepthsRaster = Raster(valleyDepthsFile,
                                                         self._gv,
                                                         canWrite=False,
                                                         isInt=False)
                        res = self.valleyDepthsRaster.open(self.chunkCount)
                        if not res:
                            self._gv.closeOpenRasters()
                            return
                    self._progress('Flood plain...')
                    self.floodplainRaster = Raster(flood,
                                                   self._gv,
                                                   canWrite=True,
                                                   isInt=True)
                    OK = self.floodplainRaster.open(
                        self.chunkCount,
                        numRows=self.numRows,
                        numCols=self.numCols,
                        transform=self.demTransform,
                        projection=self.demProjection,
                        noData=self.noData)
                    if OK:
                        self.calcFloodPlain1()
                        self.floodplainRaster.close()
                        ## fixing aux.xml file seems unnecessary in QGIS 2.16
                        #                         # now fix maximum value to 1 instead of zero in aux.xml file
                        #                         # else if loaded has legend 0 to nan and display is all black
                        #                         xmlFile = self.floodplainRaster.fileName + '.aux.xml'
                        #                         ok, err = QSWATUtils.setXMLValue(xmlFile, u'MDI', u'key', u'STATISTICS_MAXIMUM', u'1')
                        #                         if not ok:
                        #                             QSWATUtils.error(err, self._gv.isBatch)
                        QSWATUtils.copyPrj(self.demRaster.fileName,
                                           self.floodplainRaster.fileName)
                        # load flood above DEM
                        layers = root.findLayers()
                        demLayer = QSWATUtils.getLayerByLegend(
                            FileTypes.legend(FileTypes._DEM), layers)
                        ft = FileTypes._INVFLOOD if self.useInversion else FileTypes._BRANCHFLOOD
                        floodLayer, _ = QSWATUtils.getLayerByFilename(
                            layers, self.floodplainRaster.fileName, ft,
                            self._gv, demLayer,
                            QSWATUtils._WATERSHED_GROUP_NAME)
                        if floodLayer is None:
                            QSWATUtils.error('Failed to load floodplain raster {0}' \
                                             .format(self.floodplainRaster.fileName), self._gv.isBatch)
                    self.valleyDepthsRaster.close()
                    self.ridgeHeightsRaster.close()
                    self._progress('Flood plain done')
                except MemoryError:
                    QSWATUtils.loginfo(
                        'Out of memory for flood plain with chunk count {0}'.
                        format(self.chunkCount))
                    self._gv.closeOpenRasters()
                    completed = False
                    self.chunkCount += 1
        else:  # already have uptodate flood file: make sure it is loaded
            # load flood above DEM
            layers = root.findLayers()
            demLayer = QSWATUtils.getLayerByLegend(
                FileTypes.legend(FileTypes._DEM), layers)
            ft = FileTypes._INVFLOOD if self.useInversion else FileTypes._BRANCHFLOOD
            floodLayer, _ = QSWATUtils.getLayerByFilename(
                layers, flood, ft, self._gv, demLayer,
                QSWATUtils._WATERSHED_GROUP_NAME)
            if floodLayer is None:
                QSWATUtils.error('Failed to load floodplain raster {0}' \
                                 .format(self.floodplainRaster.fileName), self._gv.isBatch)

    def calcFloodPlain1(self):
        """Calculate the floodplain array elementwise."""
        old_settings = numpy.seterr(divide='raise')
        valleyTransform = self.valleyDepthsRaster.ds.GetGeoTransform()
        for row in range(self.numRows):
            for col in range(self.numCols):
                rh = self.ridgeHeightsRaster.read(row, col)
                if rh != self.noData:
                    vd = self.valleyDepthsRaster.read(row, col)
                    if vd != self.noData:
                        try:
                            sp = 0 if int(rh + vd) == 0 else vd / (rh + vd)
                        except Exception:
                            QSWATUtils.information('Problem in calculating slope position at {0}: numerator {1}; denominator {2}: {3}. Set to 0' \
                                               .format(QSWATTopology.cellToProj(col, row, valleyTransform), vd, rh+vd, traceback.format_exc()),
                                             self._gv.isBatch)
                            sp = 0
                        self.floodplainRaster.write(
                            row, col,
                            1 if sp <= self.floodThresh else self.noData)
        numpy.seterr(divide=old_settings['divide'])

    # TODO: deal with array access
    #===========================================================================
    # def calcFloodPlain2(self):
    #     """Calculate the floodplain array using numpy array methods."""
    #     for i in xrange(self.chunkCount):
    #         # if there is only one chunk we can avoid reading it again
    #         if i != self.ridgeHeightsRaster.currentIndex:
    #             heightsChunk = self.ridgeHeightsRaster.chunks[i]
    #             self.ridgeHeightsRaster.array = self.ridgeHeightsRaster.band.ReadAsArray(0, heightsChunk.rowOffset, self.ridgeHeightsRaster.numCols, heightsChunk.numRows)
    #             self.ridgeHeightsRaster.currentIndex = i
    #         if i != self.valleyDepthsRaster.currentIndex:
    #             depthsChunk = self.valleyDepthsRaster.chunks[i]
    #             self.valleyDepthsRaster.array = self.valleyDepthsRaster.band.ReadAsArray(0, depthsChunk.rowOffset, self.valleyDepthsRaster.numCols, depthsChunk.numRows)
    #             self.valleyDepthsRaster.currentIndex = i
    #         msk = (self.ridgeHeightsRaster.array != self.noData) & (self.valleyDepthsRaster.array() != self.noData)
    #         # start with array of right size for floodplain (since current size will be last initial chunk which may be small)
    #         # note also we have to initialize it to type float and correct to int later
    #         floodplainChunk = self.floodplainRaster.chunks[i]
    #         self.floodplainRaster.array = np.core.full((floodplainChunk.numRows, self.numCols), self.noData, np.float_)
    #         # the next line uses just one write but does not work
    #         #self.floodplainRaster.array[msk] = 1 if (self.valleyDepthsRaster.array[msk] / (self.valleyDepthsRaster.array[msk] + self.ridgeHeightsRaster.array[msk])) <= self.floodThresh else 0
    #         self.floodplainRaster.array[msk] = self.valleyDepthsRaster.array[msk] / (self.valleyDepthsRaster.array[msk] + self.ridgeHeightsRaster.array[msk])
    #         self.floodplainRaster.array[(self.floodplainRaster.array > self.floodThresh) & (self.ridgeHeightsRaster.array != self.noData) & (self.valleyDepthsRaster.array != self.noData)] = 1
    #         self.floodplainRaster.array[(self.floodplainRaster.array <= self.floodThresh) & (self.ridgeHeightsRaster.array != self.noData) & (self.valleyDepthsRaster.array != self.noData)] = 2
    #         self.floodplainRaster.array[msk] = self.floodplainRaster.array[msk] - 1
    #         self.floodplainRaster.array = self.floodplainRaster.array.astype(np.int_)
    #         self.floodplainRaster.array[self.floodplainRaster.array < 0] = self.noData
    #         self.floodplainRaster.band.WriteArray(self.floodplainRaster.array, 0, floodplainChunk.rowOffset)
    #===========================================================================

    def findRidges(self, subbasinsRaster, distRaster, root):
        """
        Create ridge points dictionary (row, col) -> (elevation, maximum branch length) for all cells on 
        subbasin boundaries.
        
        A cell is on a boundary if it has one or more adjacent cells in a different subbasin,
        or if it has an adjacent cell with nodata for its subbasin, ie it is on watershed boundary,
        when its branch length is set to the branch threshold.
        The maximum branch length is the maximum of the branch lengths for adjacent cells 
        that are in a different subbasin or outside the watershed.
        Assumes subbasins, outlet distance and dem rasters have same extents and cell sizes.
        """
        # check assumption about rasters:
        assert self.demTransform == subbasinsRaster.ds.GetGeoTransform(
        ), 'DEM and subbasins rasters not compatible'
        assert self.demTransform == distRaster.ds.GetGeoTransform(
        ), 'DEM and distance to outlet rasters not compatible'
        if len(self._gv.topo.subbasinToStream) == 0:
            # need to calculate some topology
            if self._gv.useGridModel:
                if os.path.exists(self._gv.delinStreamFile):
                    streamLayer = QgsVectorLayer(self._gv.delinStreamFile,
                                                 'Delineated streams', 'ogr')
                else:
                    QSWATUtils.error(
                        'Cannot use branch length algorithm without a delineated stream shapefile',
                        self._gv.isBatch)
                    return
            else:
                streamLayer = QSWATUtils.getLayerByFilename(
                    root.findLayers(), self._gv.streamFile, FileTypes._STREAMS,
                    None, None, None)[0]
                if streamLayer is None:
                    QSWATUtils.error(
                        'Streams layer not found: have you run TauDEM?',
                        self._gv.isBatch)
                    return
            if not self._gv.topo.setUp1(streamLayer):
                return
        self.makeRidges(subbasinsRaster, distRaster)
        time1 = time.process_time()
        self.makeRidgeRaster()
        time2 = time.process_time()
        QSWATUtils.loginfo('Writing ridge raster  took {0} seconds'.format(
            int(time2 - time1)))

    def makeRidges(self, subbasinsRaster, distRaster):
        """
        Set values of ridge points.
        """
        time1 = time.process_time()
        self.ridgePoints = dict()
        subbasinsNoData = subbasinsRaster.band.GetNoDataValue()
        for row in range(self.numRows):
            for col in range(self.numCols):
                subbasin = subbasinsRaster.read(row, col)
                if subbasin == subbasinsNoData:
                    continue
                maxBranchLength = 0
                finished = False
                for dy in [-1, 0, 1]:
                    row1 = row + dy
                    dxs = [-1, 1] if dy == 0 else [-1, 0, 1]
                    for dx in dxs:
                        col1 = col + dx
                        if self.pointInMap(row1, col1):
                            subbasin1 = subbasinsRaster.read(
                                row + dy, col + dx)
                        else:
                            subbasin1 = subbasinsNoData
                        if subbasin1 == subbasinsNoData:
                            maxBranchLength = self.branchThresh
                            finished = True
                            break
                        elif subbasin1 != subbasin:
                            distanceToJoin = self._gv.topo.getDistanceToJoin(
                                subbasin1, subbasin)
                            branchLength = distRaster.read(
                                row1, col1) + distanceToJoin
                            maxBranchLength = max(branchLength,
                                                  maxBranchLength)
                    if finished:
                        break
                if maxBranchLength >= self.branchThresh:
                    elevation = self.demRaster.read(row, col)
                    if elevation != self.demNoData:
                        self.ridgePoints[(row, col)] = (elevation,
                                                        maxBranchLength)
        time2 = time.process_time()
        QSWATUtils.loginfo('Making ridge points took {0} seconds'.format(
            int(time2 - time1)))

    def getRidgeElevation(self, row, col, reportFailure):
        """
        Find nearest ridge point to (row, col) and return its elevation and distance from (row, col).
        
        Distance is cartesian distance, in number of pixels (assumed square).
        Algorithm looks for first acceptable ridge  point on increasing square perimeter around original point,
        as an approximation to the nearest.
        Slope position algorithm for floodplain identification only depends on elevations, not distances, 
        so we don't worry too much about distances to ridge points, and interpret 'nearest' loosely for efficient execution.
        """
        # use view so that changes may be used later in iteration, and avoid repeated searches for adjacent unacceptable points
        n = 0
        while True:
            #=============version where square used has N-s and E-W sides=======
            # for dy in xrange(0-n, n+1):
            #     for dx in xrange(0-n, n+1):
            #         if abs(dy) == n or abs(dx) == n: # on boundary of square
            #             (e, l) = self.ridgePoints.get((row+dy, col+dx), (-1, -1))
            #             if l >= 0:
            #                 return e, math.sqrt(dx * dx + dy * dy)
            #===================================================================
            # version with diagonal sides to square - a little closer to circular maybe?
            if n == 0:
                (e, l) = self.ridgePoints.get((row, col), (-1, -1))
                if l >= 0:
                    return e, 0
            else:
                for dx in range(n + 1):
                    dy = n - dx
                    (e, l) = self.ridgePoints.get((row + dy, col + dx),
                                                  (-1, -1))
                    if l >= 0:
                        return e, math.sqrt(dx * dx + dy * dy)
                    if dx != 0:
                        (e, l) = self.ridgePoints.get((row + dy, col - dx),
                                                      (-1, -1))
                        if l >= 0:
                            return e, math.sqrt(dx * dx + dy * dy)
                    if dy != 0:
                        (e, l) = self.ridgePoints.get((row - dy, col + dx),
                                                      (-1, -1))
                        if l >= 0:
                            return e, math.sqrt(dx * dx + dy * dy)
                        if dx != 0:
                            (e, l) = self.ridgePoints.get((row - dy, col - dx),
                                                          (-1, -1))
                            if l >= 0:
                                return e, math.sqrt(dx * dx + dy * dy)
            n += 1
            if n > 1000:
                if reportFailure:
                    x, y = QSWATTopology.cellToProj(row, col,
                                                    self.demTransform)
                    QSWATUtils.information(
                        'No ridge point found within 1000 pixels of ({0}, {1}).  Is the branch threshold too high?'
                        .format(x, y), self._gv.isBatch)
                return 0, -1

    def propagateFromRidges(self, valleyDepthsFile, dirRaster, accRaster):
        """
        Propagate relative heights of nearest ridge points along flow paths, starting from points with accumulation 1.
        
        Heights are put into ridgeHeightsRaster.  
        Distances from ridge are put into ridgeDistancesRaster  If a point already has a height, 
        but the new path is shorter, the new height overwrites the old.
        """
        time1 = time.process_time()
        self.valleyDepthsRaster = Raster(valleyDepthsFile,
                                         self._gv,
                                         canWrite=False,
                                         isInt=False)
        res = self.valleyDepthsRaster.open(self.chunkCount)
        if not res:
            return
        reportFailure = True
        pathLength = 0  # path length counted in pixels (horizontal and vertical assumed same, so 1)
        diag = math.sqrt(2)
        for row in range(self.numRows):
            for col in range(self.numCols):
                if accRaster.read(row, col) == 1:
                    elevation, pathLength = self.getRidgeElevation(
                        row, col, reportFailure)
                    if pathLength < 0:
                        if reportFailure:
                            reportFailure = False
                        elevation = self.demRaster.read(row, col)
                        pathLength = 0
                    nextRow, nextCol = row, col
                    while True:
                        nextElev = self.demRaster.read(nextRow, nextCol)
                        if nextElev == self.demNoData:
                            break
                        currentPathLength = self.ridgeDistancesRaster.read(
                            nextRow, nextCol)
                        if currentPathLength >= 0:
                            # have a previously stored value
                            if pathLength < currentPathLength:
                                # new path length from ridge is shorter: update heights raster
                                self.ridgeHeightsRaster.write(
                                    nextRow, nextCol, elevation - nextElev)
                                self.ridgeDistancesRaster.write(
                                    nextRow, nextCol, pathLength)
                            else:  # already had shorter path from ridge - no point in continuing down flow path
                                break
                        else:  # no value stored yet
                            self.ridgeHeightsRaster.write(
                                nextRow, nextCol, elevation - nextElev)
                            self.ridgeDistancesRaster.write(
                                nextRow, nextCol, pathLength)
                        pt, isDiag = self.alongDirPoint(
                            nextRow, nextCol, dirRaster)
                        if pt is None:
                            break
                        pathLength += diag if isDiag else 1
                        nextRow, nextCol = pt
        time2 = time.process_time()
        QSWATUtils.loginfo('Propagating ridge points took {0} seconds'.format(
            int(time2 - time1)))

    def makeRidgeRaster(self):
        """Make raster  to show ridges."""
        ridgeFile = QSWATUtils.join(self._gv.demDir,
                                    'ridge' + str(self.branchThresh) + '.tif')
        ridgeRaster = Raster(ridgeFile, self._gv, canWrite=True, isInt=True)
        res = ridgeRaster.open(self.chunkCount,
                               numRows=self.numRows,
                               numCols=self.numCols,
                               transform=self.demTransform,
                               projection=self.demProjection,
                               noData=self.noData)
        if not res:
            return
        for row in range(self.numRows):
            for col in range(self.numCols):
                if self.demRaster.read(row, col) != self.demNoData:
                    val, _ = self.ridgePoints.get((row, col), (-1, -1))
                    ridgeRaster.write(row, col, 0 if val == -1 else 1)
        ridgeRaster.close()
        #QSWATUtils.getLayerByFilename(self._iface.legendInterface().layers(), ridgeFile, FileTypes._OTHER,
        #                                self._gv, None, QSWATUtils._WATERSHED_GROUP_NAME)

    def alongDirPoint(self, row, col, d8Raster):
        """Return next point (as pair or None) along d8Raster direction from (row, col) that has a data value in demRaster."""
        # d8Raster obtained by inverting the d8 flow directions raster has float values, so must cooerce to int
        dir0 = int(d8Raster.read(row, col) - 1)
        if 0 <= dir0 < 8:
            row1 = row + QSWATUtils._dY[dir0]
            col1 = col + QSWATUtils._dX[dir0]
            if self.pointInMap(row1, col1) and self.demRaster.read(
                    row1, col1) != self.demNoData:
                isDiag = (dir0 // 2 == 1)
                return (row1, col1), isDiag
            else:
                return None, False
        else:
            return None, False

    def pointInMap(self, row, col):
        """Return true if row and col are in the limits for the DEM array."""
        return 0 <= row < self.numRows and 0 <= col < self.numCols
示例#34
0
def calc_regression_yield(vars_dict):
    '''
    Calculates yield using the regression model yield function

    Example Args::

        vars_dict = {
            ...

            'fertilizer_maps_dict': {...},
            'modeled_irrigation_map_uri': '',
            'modeled_yield_dict': {...}
        }
    '''
    vars_dict = _create_yield_func_output_folder(
        vars_dict, "climate_regression_yield")

    lulc_raster = Raster.from_file(
        vars_dict['lulc_map_uri']).set_nodata(NODATA_INT)
    aoi_vector = Vector.from_shapely(
        lulc_raster.get_aoi(), lulc_raster.get_projection())

    # setup useful base rasters
    base_raster_float = lulc_raster.set_datatype_and_nodata(
        gdal.GDT_Float64, NODATA_FLOAT)

    vars_dict['crop_production_dict'] = {}
    if vars_dict['do_economic_returns']:
        economics_table = vars_dict['economics_table_dict']
        returns_raster = base_raster_float.zeros()

    crops = vars_dict['crops_in_aoi_list']
    for crop in crops:
        LOGGER.info('Calculating regression yield for %s' % crop)
        # Wrangle data...
        climate_bin_raster = _get_climate_bin_over_lulc(
            vars_dict, crop, aoi_vector, base_raster_float)

        masked_lulc_raster = _get_masked_lulc_raster(
            vars_dict, crop, lulc_raster).set_datatype_and_nodata(
            gdal.GDT_Float64, NODATA_FLOAT)

        # Operations as Noted in User's Guide...
        Yield_raster = _calc_regression_yield_for_crop(
            vars_dict,
            crop,
            climate_bin_raster)

        Yield_given_lulc_raster = Yield_raster * masked_lulc_raster

        Production_raster = _calculate_production_for_crop(
            vars_dict, crop, Yield_given_lulc_raster)

        total_production = float(round(
            Production_raster.sum(), 2))
        vars_dict['crop_production_dict'][crop] = total_production

        if vars_dict['do_economic_returns']:
            returns_raster_crop = _calc_crop_returns(
                vars_dict,
                crop,
                lulc_raster,
                Production_raster.set_nodata(NODATA_FLOAT),
                returns_raster,
                economics_table[crop])
            returns_raster = returns_raster + returns_raster_crop

        # Clean Up Rasters...
        del climate_bin_raster
        del Yield_raster
        del masked_lulc_raster
        del Yield_given_lulc_raster
        del Production_raster

    if vars_dict['do_nutrition']:
        vars_dict = _calc_nutrition(vars_dict)

    # Results Table
    io.create_results_table(vars_dict)

    if all([vars_dict['do_economic_returns'],
            vars_dict['create_crop_production_maps']]):
        output_observed_yield_dir = vars_dict['output_yield_func_dir']
        returns_uri = os.path.join(
            output_observed_yield_dir, 'economic_returns_map.tif')
        returns_raster.save_raster(returns_uri)

    return vars_dict
示例#35
0
def calc_observed_yield(vars_dict):
    '''
    Calculates yield using observed yield function

    Args:
        vars_dict (dict): descr

    Example Args::

        vars_dict = {
            # ...

            'lulc_map_uri': '/path/to/lulc_map_uri',
            'crop_lookup_dict': {
                'code': 'crop_name',
                ...
            },
            'observed_yields_maps_dict': {
                'crop': '/path/to/crop_climate_bin_map',
                ...
            },
            'economics_table_dict': {
                'crop': {
                    'price': <float>,
                    ...
                }
                ...
            },
        }
    '''
    vars_dict['crop_production_dict'] = {}
    vars_dict = _create_yield_func_output_folder(
        vars_dict, "observed_yield")

    lulc_raster = Raster.from_file(
        vars_dict['lulc_map_uri']).set_nodata(NODATA_INT)
    aoi_vector = Vector.from_shapely(
        lulc_raster.get_aoi(), lulc_raster.get_projection())

    # setup useful base rasters
    base_raster_float = lulc_raster.set_datatype_and_nodata(
        gdal.GDT_Float64, NODATA_FLOAT)

    if vars_dict['do_economic_returns']:
        returns_raster = base_raster_float.zeros()

    crops = vars_dict['crops_in_aoi_list']
    for crop in crops:
        LOGGER.info('Calculating observed yield for %s' % crop)
        # Wrangle Data...
        observed_yield_over_aoi_raster = _get_observed_yield_from_dataset(
            vars_dict,
            crop,
            aoi_vector,
            base_raster_float)

        ObservedLocalYield_raster = _get_yield_given_lulc(
            vars_dict,
            crop,
            lulc_raster,
            observed_yield_over_aoi_raster)

        # Operations as Noted in User's Guide...
        Production_raster = _calculate_production_for_crop(
            vars_dict,
            crop,
            ObservedLocalYield_raster)

        total_production = float(round(
            Production_raster.sum(), 2))
        vars_dict['crop_production_dict'][crop] = total_production

        if vars_dict['do_economic_returns']:
            returns_raster_crop = _calc_crop_returns(
                vars_dict,
                crop,
                lulc_raster,
                Production_raster,
                returns_raster,
                vars_dict['economics_table_dict'][crop])
            if not np.isnan(returns_raster_crop.sum()):
                returns_raster = returns_raster + returns_raster_crop

        # Clean Up Rasters...
        del observed_yield_over_aoi_raster
        del ObservedLocalYield_raster
        del Production_raster

    if vars_dict['do_nutrition']:
        vars_dict = _calc_nutrition(vars_dict)

    # Results Table
    io.create_results_table(vars_dict)

    if all([vars_dict['do_economic_returns'],
            vars_dict['create_crop_production_maps']]):
        output_observed_yield_dir = vars_dict['output_yield_func_dir']
        returns_uri = os.path.join(
            output_observed_yield_dir, 'economic_returns_map.tif')
        returns_raster.save_raster(returns_uri)

    return vars_dict
    def add_event_series(self, am_Model, road_width, deposition_pattern, power,
                         layer_break):
        self.write('#EVENT SERIES\n')
        part = am_Model.get_part()
        amModel_name = am_Model.get_amModel_name()
        AM_model_name = 'mdb.customData.am.amModels["' + amModel_name + '"]'

        add_element = part.get_features()['add_element']
        base_element = part.get_features()['base_element']

        #depth of add_element
        depth = add_element.get_depth()

        #thickness of each layer
        thickness = add_element.get_layer_thickness()

        #road_width
        am_Model.set_road_width(road_width)

        #corner coordinate
        point1 = add_element.get_point1()
        corner_x = point1[0]
        corner_y = point1[1]
        corner_z = base_element.get_depth()

        #x and y length of add_element
        point2 = add_element.get_point2()
        x_length = abs(point1[0] - point2[0])
        y_length = abs(point1[1] - point2[1])

        if deposition_pattern.lower() == 'raster':
            #__init__(self, z_length, thickness, x_length, y_length, corner_x, corner_y, corner_z, road_width,P):
            dp_object = Raster(depth, thickness, x_length, y_length, corner_x,
                               corner_y, corner_z, road_width, power,
                               layer_break)
        elif deposition_pattern.lower() == 'zigzag':
            #__init__(self, z_length, thickness, x_length, y_length, corner_x, corner_y, corner_z, road_width,P):
            dp_object = Zigzag(depth, thickness, x_length, y_length, corner_x,
                               corner_y, corner_z, road_width, power,
                               layer_break)
        else:
            raise NotImplementedError(
                'This deposition pattern is not implemented')

        dp_object.generate_heat_path()
        dp_object.generate_material_path()
        material_path = pathlib.Path('material_path.txt')
        material_path = material_path.resolve()
        heat_path = pathlib.Path('heat_path.txt')
        heat_path = heat_path.resolve()
        self.write(
            AM_model_name +
            '.addEventSeries(eventSeriesName="material_path", eventSeriesTypeName='
            + "'" + '"ABQ_AM.MaterialDeposition"' + "'" +
            ', timeSpan="TOTAL TIME", fileName="' + str(material_path) +
            '", isFile=ON)\n')
        self.write(
            AM_model_name +
            '.addEventSeries(eventSeriesName="heat_path", eventSeriesTypeName='
            + "'" + '"ABQ_AM.PowerMagnitude"' + "'" +
            ', timeSpan="TOTAL TIME", fileName="' + str(heat_path) +
            '", isFile=ON)\n')
        self.seperate_sec()
示例#37
0
def _calc_regression_yield_for_crop(vars_dict, crop, climate_bin_raster):
    '''
    Calculates yield for an individual crop using the percentile yield function
    '''

    # Fetch Fertilizer Maps
    fert_maps_dict = vars_dict['fertilizer_maps_dict']
    NitrogenAppRate_raster = Raster.from_file(
        fert_maps_dict['nitrogen']).set_nodata(NODATA_FLOAT)
    PhosphorousAppRate_raster = Raster.from_file(
        fert_maps_dict['phosphorous']).set_nodata(NODATA_FLOAT)
    PotashAppRate_raster = Raster.from_file(
        fert_maps_dict['potash']).set_nodata(NODATA_FLOAT)
    Irrigation_raster = Raster.from_file(
        vars_dict['modeled_irrigation_map_uri']).set_datatype_and_nodata(
        gdal.GDT_Int16, NODATA_INT)

    irrigated_lulc_mask = (Irrigation_raster).set_datatype_and_nodata(
        gdal.GDT_Float64, NODATA_FLOAT)
    rainfed_lulc_mask = ((Irrigation_raster * -1) + 1).set_datatype_and_nodata(
        gdal.GDT_Float64, NODATA_FLOAT)

    # Create Rasters of Yield Parameters
    yield_params = vars_dict['modeled_yield_dict'][crop]

    nodata = climate_bin_raster.get_nodata(1)

    b_K2O = _create_reg_yield_reclass_dict(
        yield_params, 'b_K2O', nodata)
    b_nut = _create_reg_yield_reclass_dict(
        yield_params, 'b_nut', nodata)
    c_N = _create_reg_yield_reclass_dict(
        yield_params, 'c_N', nodata)
    c_P2O5 = _create_reg_yield_reclass_dict(
        yield_params, 'c_P2O5', nodata)
    c_K2O = _create_reg_yield_reclass_dict(
        yield_params, 'c_K2O', nodata)
    yc = _create_reg_yield_reclass_dict(
        yield_params, 'yield_ceiling', nodata)
    yc_rf = _create_reg_yield_reclass_dict(
        yield_params, 'yield_ceiling_rf', nodata)

    b_K2O_raster = climate_bin_raster.reclass(b_K2O)
    b_nut_raster = climate_bin_raster.reclass(b_nut)
    c_N_raster = climate_bin_raster.reclass(c_N)
    c_P2O5_raster = climate_bin_raster.reclass(c_P2O5)
    c_K2O_raster = climate_bin_raster.reclass(c_K2O)
    YieldCeiling_raster = climate_bin_raster.reclass(yc)
    YieldCeilingRainfed_raster = climate_bin_raster.reclass(yc_rf)

    # Operations as Noted in User's Guide...
    PercentMaxYieldNitrogen_raster = 1 - (
        b_nut_raster * (np.e ** -c_N_raster) * NitrogenAppRate_raster)
    PercentMaxYieldPhosphorous_raster = 1 - (
        b_nut_raster * (np.e ** -c_P2O5_raster) * PhosphorousAppRate_raster)
    PercentMaxYieldPotassium_raster = 1 - (
        b_K2O_raster * (np.e ** -c_K2O_raster) * PotashAppRate_raster)

    PercentMaxYield_raster = (PercentMaxYieldNitrogen_raster.fminimum(
        PercentMaxYieldPhosphorous_raster.fminimum(
            PercentMaxYieldPotassium_raster)))

    MaxYield_raster = PercentMaxYield_raster * YieldCeiling_raster
    Yield_irrigated_raster = MaxYield_raster.reclass_masked_values(
        irrigated_lulc_mask, 0)
    Yield_rainfed_raster = YieldCeilingRainfed_raster.minimum(
        MaxYield_raster).reclass_masked_values(
        rainfed_lulc_mask, 0)

    Yield_raster = Yield_irrigated_raster + Yield_rainfed_raster

    return Yield_raster