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()) )
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 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
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
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
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)
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
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)
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)
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)
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()
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
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])
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()
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)
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)
def __init__(self): self.items = defaultdict(PanelStrip) self.width = Raster.image_width(PanelVisual.background_image)
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))
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')
# -*- 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)
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()
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
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, \
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 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 update(self, text): self.text = text self.width = Raster.text_width(text)
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
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
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'
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
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
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()
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