def mask_clouds(qa_band, qa_pixel): """ ToDo: - a better, independent mechanism for QA. --> see also Landsat8 class. - support for multiple qa_pixel values (eg. input as a list of values) Create and apply a cloud mask based on the Quality Assessment Band (BQA.) Source: <http://landsat.usgs.gov/L8QualityAssessmentBand.php See also: http://courses.neteler.org/processing-landsat8-data-in-grass-gis-7/#Applying_the_Landsat_8_Quality_Assessment_%28QA%29_Band """ msg = ('\n|i Masking for pixel values <{qap}> ' 'in the Quality Assessment band.'.format(qap=qa_pixel)) g.message(msg) #tmp_cloudmask = tmp_map_name('cloudmask') #qabits_expression = 'if({band} == {pixel}, 1, null())'.format(band=qa_band, # pixel=qa_pixel) #cloud_masking_equation = equation.format(result=tmp_cloudmask, # expression=qabits_expression) #grass.mapcalc(cloud_masking_equation) r.mask(raster=qa_band, maskcats=qa_pixel, flags='i', overwrite=True)
def cleanup(): """ Clean up temporary maps """ grass.run_command('g.remove', flags='f', type="rast", pattern='tmp.{pid}*'.format(pid=os.getpid()), quiet=True) if grass.find_file(name='MASK', element='cell')['file']: r.mask(flags='r', verbose=True)
def cleanup(): gs.message("Deleting intermediate files...") for f in TMP_RAST: gs.run_command( "g.remove", type="raster", name=f, flags='bf', quiet=True) g.region(**current_reg) if mask_test: r.mask(original_mask, overwrite=True, quiet=True)
def cleanup(): """ Clean up temporary maps """ grass.run_command( "g.remove", flags="f", type="rast", pattern="tmp.{pid}*".format(pid=os.getpid()), quiet=True, ) if grass.find_file(name="MASK", element="cell")["file"]: r.mask(flags="r", verbose=True)
def firsttimeGRASS(infiles, adminfile, maskfile): """ Run a maxlikelihood unsupervised classification on the data nclasses: number of expected classes infiles: list of raster files to import and process firstime: if firsttime, it will import all files in GRASS """ from grass_session import Session from grass.script import core as gcore from grass.pygrass.modules.shortcuts import raster as r from grass.pygrass.modules.shortcuts import vector as v from grass.pygrass.modules.shortcuts import general as g from grass.pygrass.modules.shortcuts import imagery as i # create a new location from EPSG code (can also be a GeoTIFF or SHP or ... file) with Session(gisdb="/tmp", location="loc", create_opts="EPSG:4326"): # First run, needs to import the files and create a mask # Import admin boundary #v.import_(input=adminfile,output="admin",quiet=True,superquiet=True) gcore.parse_command("v.import", input=adminfile, output="admin", quiet=True) # Set computational region to admin boundary g.region(flags="s", vector="admin", quiet=True) # Keep only file name for output outmf = maskfile.split("/")[-1] # Import Mask file r.in_gdal(input=maskfile, output=outmf, quiet=True) # Apply Mask r.mask(raster=outmf, maskcats="0", quiet=True) # Set computational resolution to mask pixel size g.region(flags="s", raster=outmf, quiet=True) # Import files for f in infiles: # Keep only file name for output outf = f.split("/")[-1] # Landsat files not in Geo lat long needs reproj on import #r.import_(input=f,output=outf,quiet=True) gcore.parse_command("r.import", input=f, output=outf, quiet=True) # Create group i.group(group="l8", subgroup="l8", input=outf, quiet=True)
def main(): # Temporary filenames tmp_avg_lse = tmp_map_name('avg_lse') tmp_delta_lse = tmp_map_name('delta_lse') tmp_cwv = tmp_map_name('cwv') #tmp_lst = tmp_map_name('lst') # user input mtl_file = options['mtl'] if not options['prefix']: b10 = options['b10'] b11 = options['b11'] t10 = options['t10'] t11 = options['t11'] if not options['clouds']: qab = options['qab'] cloud_map = False else: qab = False cloud_map = options['clouds'] elif options['prefix']: prefix = options['prefix'] b10 = prefix + '10' b11 = prefix + '11' if not options['clouds']: qab = prefix + 'QA' cloud_map = False else: cloud_map = options['clouds'] qab = False qapixel = options['qapixel'] lst_output = options['lst'] # save Brightness Temperature maps? if options['prefix_bt']: brightness_temperature_prefix = options['prefix_bt'] else: brightness_temperature_prefix = None cwv_window_size = int(options['window']) assertion_for_cwv_window_size_msg = ( 'A spatial window of size 5^2 or less is not ' 'recommended. Please select a larger window. ' 'Refer to the manual\'s notes for details.') assert cwv_window_size >= 7, assertion_for_cwv_window_size_msg cwv_output = options['cwv'] # optional maps average_emissivity_map = options['emissivity'] delta_emissivity_map = options['delta_emissivity'] # output for in-between maps? emissivity_output = options['emissivity_out'] delta_emissivity_output = options['delta_emissivity_out'] landcover_map = options['landcover'] landcover_class = options['landcover_class'] # flags info = flags['i'] scene_extent = flags['e'] timestamping = flags['t'] null = flags['n'] rounding = flags['r'] celsius = flags['c'] # # Pre-production actions # # Set Region if scene_extent: grass.use_temp_region() # safely modify the region msg = "\n|! Matching region extent to map {name}" # ToDo: check if extent-B10 == extent-B11? Unnecessary? # Improve below! if b10: run('g.region', rast=b10, align=b10) msg = msg.format(name=b10) elif t10: run('g.region', rast=t10, align=t10) msg = msg.format(name=t10) g.message(msg) elif not scene_extent: grass.warning(_('Operating on current region')) # # 1. Mask clouds # if cloud_map: # user-fed cloud map? msg = '\n|i Using {cmap} as a MASK'.format(cmap=cloud_map) g.message(msg) r.mask(raster=cloud_map, flags='i', overwrite=True) else: # using the quality assessment band and a "QA" pixel value mask_clouds(qab, qapixel) # # 2. TIRS > Brightness Temperatures # if mtl_file: # if MTL and b10 given, use it to compute at-satellite temperature t10 if b10: t10 = tirs_to_at_satellite_temperature( b10, mtl_file, brightness_temperature_prefix, null, quiet=info, ) # likewise for b11 -> t11 if b11: t11 = tirs_to_at_satellite_temperature( b11, mtl_file, brightness_temperature_prefix, null, quiet=info, ) # # Initialise a SplitWindowLST object # split_window_lst = SplitWindowLST(landcover_class) citation_lst = split_window_lst.citation # # 3. Land Surface Emissivities # # use given fixed class? if landcover_class: if split_window_lst.landcover_class is False: # replace with meaningful error grass.warning('Unknown land cover class string! Note, this string ' 'input option is case sensitive.') if landcover_class == 'Random': msg = "\n|! Random emissivity class selected > " + \ split_window_lst.landcover_class + ' ' if landcover_class == 'Barren_Land': msg = "\n|! For barren land, the last quadratic term of the Split-Window algorithm will be set to 0" + \ split_window_lst.landcover_class + ' ' else: msg = '\n|! Retrieving average emissivities *only* for {eclass} ' if info: msg += '| Average emissivities (channels 10, 11): ' msg += str(split_window_lst.emissivity_t10) + ', ' + \ str(split_window_lst.emissivity_t11) msg = msg.format(eclass=split_window_lst.landcover_class) g.message(msg) # use the FROM-GLC map elif landcover_map: if average_emissivity_map: tmp_avg_lse = average_emissivity_map if not average_emissivity_map: determine_average_emissivity( tmp_avg_lse, emissivity_output, landcover_map, split_window_lst.average_lse_mapcalc, quiet=info, ) if options['emissivity_out']: tmp_avg_lse = options['emissivity_out'] if delta_emissivity_map: tmp_delta_lse = delta_emissivity_map if not delta_emissivity_map: determine_delta_emissivity( tmp_delta_lse, delta_emissivity_output, landcover_map, split_window_lst.delta_lse_mapcalc, quiet=info, ) if options['delta_emissivity_out']: tmp_delta_lse = options['delta_emissivity_out'] # # 4. Modified Split-Window Variance-Covariance Matrix > Column Water Vapor # if info: msg = '\n|i Spatial window of size {n} for Column Water Vapor estimation: ' msg = msg.format(n=cwv_window_size) g.message(msg) cwv = Column_Water_Vapor(cwv_window_size, t10, t11) citation_cwv = cwv.citation estimate_cwv_big_expression( tmp_cwv, cwv_output, t10, t11, cwv._big_cwv_expression(), ) if cwv_output: tmp_cwv = cwv_output # # 5. Estimate Land Surface Temperature # if info and landcover_class == 'Random': msg = '\n|* Will pick a random emissivity class!' grass.verbose(msg) estimate_lst( lst_output, t10, t11, landcover_map, landcover_class, tmp_avg_lse, tmp_delta_lse, tmp_cwv, split_window_lst.sw_lst_mapcalc, rounding, celsius, quiet=info, ) # # Post-production actions # # remove MASK r.mask(flags='r', verbose=True) # time-stamping if timestamping: add_timestamp(mtl_file, lst_output) if cwv_output: add_timestamp(mtl_file, cwv_output) # Apply color table if celsius: run('r.colors', map=lst_output, color='celsius') else: # color table for kelvin run('r.colors', map=lst_output, color='kelvin') # ToDo: helper function for r.support # strings for metadata history_lst = '\n' + citation_lst history_lst += '\n\n' + citation_cwv history_lst += '\n\nSplit-Window model: ' history_lst += split_window_lst._equation # :wsw_lst_mapcalc description_lst = ( 'Land Surface Temperature derived from a split-window algorithm. ') if celsius: title_lst = 'Land Surface Temperature (C)' units_lst = 'Celsius' else: title_lst = 'Land Surface Temperature (K)' units_lst = 'Kelvin' landsat8_metadata = Landsat8_MTL(mtl_file) source1_lst = landsat8_metadata.scene_id source2_lst = landsat8_metadata.origin # history entry run( "r.support", map=lst_output, title=title_lst, units=units_lst, description=description_lst, source1=source1_lst, source2=source2_lst, history=history_lst, ) # restore region if scene_extent: grass.del_temp_region() # restoring previous region settings g.message("|! Original Region restored") # print citation if info: g.message('\nSource: ' + citation_lst)
def main(): """ Main program """ # Temporary filenames # The following three are meant for a test step-by-step cwv estimation, see # unused functions! # tmp_ti_mean = tmp_map_name('ti_mean') # for cwv # tmp_tj_mean = tmp_map_name('tj_mean') # for cwv # tmp_ratio = tmp_map_name('ratio') # for cwv tmp_avg_lse = tmp_map_name('avg_lse') tmp_delta_lse = tmp_map_name('delta_lse') tmp_cwv = tmp_map_name('cwv') #tmp_lst = tmp_map_name('lst') # basic equation for mapcalc global equation, citation_lst equation = "{result} = {expression}" # user input mtl_file = options['mtl'] if not options['prefix']: b10 = options['b10'] b11 = options['b11'] t10 = options['t10'] t11 = options['t11'] if not options['clouds']: qab = options['qab'] cloud_map = False else: qab = False cloud_map = options['clouds'] elif options['prefix']: prefix = options['prefix'] b10 = prefix + '10' b11 = prefix + '11' if not options['clouds']: qab = prefix + 'QA' cloud_map = False else: cloud_map = options['clouds'] qab = False qapixel = options['qapixel'] lst_output = options['lst'] # save Brightness Temperature maps? global brightness_temperature_prefix if options['prefix_bt']: brightness_temperature_prefix = options['prefix_bt'] else: brightness_temperature_prefix = None global cwv_output cwv_window_size = int(options['window']) assertion_for_cwv_window_size_msg = ('A spatial window of size 5^2 or less is not ' 'recommended. Please select a larger window. ' 'Refer to the manual\'s notes for details.') assert cwv_window_size >= 7, assertion_for_cwv_window_size_msg cwv_output = options['cwv'] # optional maps average_emissivity_map = options['emissivity'] delta_emissivity_map = options['delta_emissivity'] # output for in-between maps? global emissivity_output, delta_emissivity_output emissivity_output = options['emissivity_out'] delta_emissivity_output = options['delta_emissivity_out'] global landcover_map, emissivity_class landcover_map = options['landcover'] emissivity_class = options['emissivity_class'] # flags global info, null info = flags['i'] scene_extent = flags['e'] timestamping = flags['t'] null = flags['n'] global rounding rounding = flags['r'] global celsius celsius = flags['c'] # ToDo: # shell = flags['g'] # # Pre-production actions # # Set Region if scene_extent: grass.use_temp_region() # safely modify the region msg = "\n|! Matching region extent to map {name}" # ToDo: check if extent-B10 == extent-B11? Unnecessary? # Improve below! if b10: run('g.region', rast=b10, align=b10) msg = msg.format(name=b10) elif t10: run('g.region', rast=t10, align=t10) msg = msg.format(name=t10) g.message(msg) elif scene_extent: grass.warning(_('Operating on current region')) # # 1. Mask clouds # if cloud_map: # user-fed cloud map? msg = '\n|i Using {cmap} as a MASK'.format(cmap=cloud_map) g.message(msg) r.mask(raster=cloud_map, flags='i', overwrite=True) else: # using the quality assessment band and a "QA" pixel value mask_clouds(qab, qapixel) # # 2. TIRS > Brightness Temperatures # if mtl_file: # if MTL and b10 given, use it to compute at-satellite temperature t10 if b10: # convert DNs to at-satellite temperatures t10 = tirs_to_at_satellite_temperature(b10, mtl_file) # likewise for b11 -> t11 if b11: # convert DNs to at-satellite temperatures t11 = tirs_to_at_satellite_temperature(b11, mtl_file) # # Initialise a SplitWindowLST object # split_window_lst = SplitWindowLST(emissivity_class) citation_lst = split_window_lst.citation # # 3. Land Surface Emissivities # # use given fixed class? if emissivity_class: if split_window_lst.landcover_class is False: # replace with meaningful error g.warning('Unknown land cover class string! Note, this string ' 'input option is case sensitive.') if emissivity_class == 'Random': msg = "\n|! Random emissivity class selected > " + \ split_window_lst.landcover_class + ' ' else: msg = '\n|! Retrieving average emissivities *only* for {eclass} ' if info: msg += '| Average emissivities (channels 10, 11): ' msg += str(split_window_lst.emissivity_t10) + ', ' + \ str(split_window_lst.emissivity_t11) msg = msg.format(eclass=split_window_lst.landcover_class) g.message(msg) # use the FROM-GLC map elif landcover_map: if average_emissivity_map: tmp_avg_lse = average_emissivity_map if not average_emissivity_map: determine_average_emissivity(tmp_avg_lse, landcover_map, split_window_lst.average_lse_mapcalc) if options['emissivity_out']: tmp_avg_lse = options['emissivity_out'] if delta_emissivity_map: tmp_delta_lse = delta_emissivity_map if not delta_emissivity_map: determine_delta_emissivity(tmp_delta_lse, landcover_map, split_window_lst.delta_lse_mapcalc) if options['delta_emissivity_out']: tmp_delta_lse = options['delta_emissivity_out'] # # 4. Modified Split-Window Variance-Covariance Matrix > Column Water Vapor # if info: msg = '\n|i Spatial window of size {n} for Column Water Vapor estimation: ' msg = msg.format(n=cwv_window_size) g.message(msg) cwv = Column_Water_Vapor(cwv_window_size, t10, t11) citation_cwv = cwv.citation estimate_cwv_big_expression(tmp_cwv, t10, t11, cwv._big_cwv_expression()) if cwv_output: tmp_cwv = cwv_output # # 5. Estimate Land Surface Temperature # if info and emissivity_class == 'Random': msg = '\n|* Will pick a random emissivity class!' grass.verbose(msg) estimate_lst(lst_output, t10, t11, tmp_avg_lse, tmp_delta_lse, tmp_cwv, split_window_lst.sw_lst_mapcalc) # # Post-production actions # # remove MASK r.mask(flags='r', verbose=True) # time-stamping if timestamping: add_timestamp(mtl_file, lst_output) if cwv_output: add_timestamp(mtl_file, cwv_output) # Apply color table if celsius: run('r.colors', map=lst_output, color='celsius') else: # color table for kelvin run('r.colors', map=lst_output, color='kelvin') # ToDo: helper function for r.support # strings for metadata history_lst = '\n' + citation_lst history_lst += '\n\n' + citation_cwv history_lst += '\n\nSplit-Window model: ' history_lst += split_window_lst._equation # :wsw_lst_mapcalc description_lst = ('Land Surface Temperature derived from a split-window algorithm. ') if celsius: title_lst = 'Land Surface Temperature (C)' units_lst = 'Celsius' else: title_lst = 'Land Surface Temperature (K)' units_lst = 'Kelvin' landsat8_metadata = Landsat8_MTL(mtl_file) source1_lst = landsat8_metadata.scene_id source2_lst = landsat8_metadata.origin # history entry run("r.support", map=lst_output, title=title_lst, units=units_lst, description=description_lst, source1=source1_lst, source2=source2_lst, history=history_lst) # (re)name the LST product #run("g.rename", rast=(tmp_lst, lst_output)) # restore region if scene_extent: grass.del_temp_region() # restoring previous region settings g.message("|! Original Region restored") # print citation if info: print '\nSource: ' + citation_lst
map_for_define_region = 'Neotropic_Hansen_percenttreecoverd_2000_wgs84@PERMANENT' # input vector with buffers vector = 'buffers_5km_comm_data_neotro_checked_2020_d11_06' # For each buffer for i in buffer_index: print i, comm_code[i], years[i] # select feature v.extract(input = vector, output = 'vector_cat', where = 'cat = ' + str(i+1), flags = 't', overwrite = True, quiet = True) # define region g.region(vector = 'vector_cat', align = map_for_define_region, flags = 'p') # use vector as a mask r.mask(vector = 'vector_cat', overwrite = True, quiet = True) # Cut maps # tree cover with zero where there was deforestation expr = comm_code[i] + '_treecover_GFW_2000_deforestation = if(Neotropical_Hansen_treecoverlossperyear_wgs84_2017@PERMANENT > 0 && '+ \ 'Neotropical_Hansen_treecoverlossperyear_wgs84_2017@PERMANENT < ' + str(years[i]) + ', 0, Neotropic_Hansen_percenttreecoverd_2000_wgs84@PERMANENT)' r.mapcalc(expr, overwrite = True) # thresholds for binary values of natural vegetation thresholds = [70, 80, 90] # loop to cut for each one and account for deforestation for tr in thresholds: # Hansen bin
def compute_supply( base, recreation_spectrum, highest_spectrum, base_reclassification_rules, reclassified_base, reclassified_base_title, flow, flow_map_name, aggregation, ns_resolution, ew_resolution, print_only=False, flow_column_name=None, vector=None, supply_filename=None, use_filename=None, ): """ Algorithmic description of the "Contribution of Ecosysten Types" # FIXME ''' 1 B ← {0, .., m-1} : Set of aggregational boundaries 2 T ← {0, .., n-1} : Set of land cover types 3 WE ← 0 : Set of weighted extents 4 R ← 0 : Set of fractions 5 F ← 0 6 MASK ← HQR : High Quality Recreation 7 foreach {b} ⊆ B do : for each aggregational boundary 'b' 8 RB ← 0 9 foreach {t} ⊆ T do : for each Land Type 10 WEt ← Et * Wt : Weighted Extent = Extent(t) * Weight(t) 11 WE ← WE⋃{WEt} : Add to set of Weighted Extents 12 S ← ∑t∈WEt 13 foreach t ← T do 14 Rt ← WEt / ∑WE 15 R ← R⋃{Rt} 16 RB ← RB⋃{R} ''' # FIXME Parameters ---------- recreation_spectrum: Map scoring access to and quality of recreation highest_spectrum : Expected is a map of areas with highest recreational value (category 9 as per the report ... ) base : Base land types map for final zonal statistics. Specifically to ESTIMAP's recrceation mapping algorithm base_reclassification_rules : Reclassification rules for the input base map reclassified_base : Name for the reclassified base cover map reclassified_base_title : Title for the reclassified base map ecosystem_types : flow : Map of visits, derived from the mobility function, depicting the number of people living inside zones 0, 1, 2, 3. Used as a cover map for zonal statistics. flow_map_name : A name for the 'flow' map. This is required when the 'flow' input option is not defined by the user, yet some of the requested outputs required first the production of the 'flow' map. An example is the request for a supply table without requesting the 'flow' map itself. aggregation : ns_resolution : ew_resolution : statistics_filename : supply_filename : Name for CSV output file of the supply table use_filename : Name for CSV output file of the use table flow_column_name : Name for column to populate with 'flow' values vector : If 'vector' is given, a vector map of the 'flow' along with appropriate attributes will be produced. ? : Land cover class percentages in ROS9 (this is: relative percentage) output : Supply table (distribution of flow for each land cover class) Returns ------- This function produces a map to base the production of a supply table in form of CSV. Examples -------- """ # Inputs flow_in_base = flow + "_" + base base_scores = base + ".scores" # Define lists and dictionaries to hold intermediate data statistics_dictionary = {} weighted_extents = {} flows = [] # MASK areas of high quality recreation r.mask(raster=highest_spectrum, overwrite=True, quiet=True) # Reclassify land cover map to MAES ecosystem types r.reclass( input=base, rules=base_reclassification_rules, output=reclassified_base, quiet=True, ) # add to "remove_at_exit" after the reclassified maps! # Discard areas out of MASK copy_equation = EQUATION.format(result=reclassified_base, expression=reclassified_base) r.mapcalc(copy_equation, overwrite=True) # Count flow within each land cover category r.stats_zonal( base=base, flags="r", cover=flow_map_name, method="sum", output=flow_in_base, overwrite=True, quiet=True, ) # Set colors for "flow" map r.colors(map=flow_in_base, color=MOBILITY_COLORS, quiet=True) # Parse aggregation raster categories and labels categories = grass.parse_command("r.category", map=aggregation, delimiter="\t") for category in categories: # Intermediate names cells = highest_spectrum + ".cells" + "." + category remove_map_at_exit(cells) extent = highest_spectrum + ".extent" + "." + category remove_map_at_exit(extent) weighted = highest_spectrum + ".weighted" + "." + category remove_map_at_exit(weighted) fractions = base + ".fractions" + "." + category remove_map_at_exit(fractions) flow_category = "_flow_" + category flow = base + flow_category remove_map_at_exit(flow) flow_in_reclassified_base = reclassified_base + "_flow" flow_in_category = reclassified_base + flow_category flows.append(flow_in_category) # add to list for patching remove_map_at_exit(flow_in_category) # Output names msg = "Processing aggregation raster category: {r}" msg = msg.format(r=category) grass.debug(_(msg)) # g.message(_(msg)) # First, set region to extent of the aggregation map # and resolution to the one of the population map # Note the `-a` flag to g.region: ? # To safely modify the region: grass.use_temp_region() # FIXME g.region( raster=aggregation, nsres=ns_resolution, ewres=ew_resolution, flags="a", quiet=True, ) msg = "|! Computational resolution matched to {raster}" msg = msg.format(raster=aggregation) grass.debug(_(msg)) # Build MASK for current category & high quality recreation areas msg = "Setting category '{c}' of '{a}' as a MASK" grass.verbose(_(msg.format(c=category, a=aggregation))) masking = "if( {spectrum} == {highest_quality_category} && " masking += "{aggregation} == {category}, " masking += "1, null() )" masking = masking.format( spectrum=recreation_spectrum, highest_quality_category=HIGHEST_RECREATION_CATEGORY, aggregation=aggregation, category=category, ) masking_equation = EQUATION.format(result="MASK", expression=masking) grass.mapcalc(masking_equation, overwrite=True) # zoom to MASK g.region(zoom="MASK", nsres=ns_resolution, ewres=ew_resolution, quiet=True) # Count number of cells within each land category r.stats_zonal( flags="r", base=base, cover=highest_spectrum, method="count", output=cells, overwrite=True, quiet=True, ) cells_categories = grass.parse_command("r.category", map=cells, delimiter="\t") grass.debug(_("Cells: {c}".format(c=cells_categories))) # Build cell category and label rules for `r.category` cells_rules = "\n".join([ "{0}:{1}".format(key, value) for key, value in cells_categories.items() ]) # Discard areas out of MASK copy_equation = EQUATION.format(result=cells, expression=cells) r.mapcalc(copy_equation, overwrite=True) # Reassign cell category labels r.category(map=cells, rules="-", stdin=cells_rules, separator=":") # Compute extent of each land category extent_expression = "@{cells} * area()" extent_expression = extent_expression.format(cells=cells) extent_equation = EQUATION.format(result=extent, expression=extent_expression) r.mapcalc(extent_equation, overwrite=True) # Write extent figures as labels r.stats_zonal( flags="r", base=base, cover=extent, method="average", output=extent, overwrite=True, verbose=False, quiet=True, ) # Write land suitability scores as an ASCII file temporary_reclassified_base_map = temporary_filename( filename=reclassified_base) suitability_scores_as_labels = string_to_file( SUITABILITY_SCORES_LABELS, filename=temporary_reclassified_base_map) remove_files_at_exit(suitability_scores_as_labels) # Write scores as raster category labels r.reclass( input=base, output=base_scores, rules=suitability_scores_as_labels, overwrite=True, quiet=True, verbose=False, ) remove_map_at_exit(base_scores) # Compute weighted extents weighted_expression = "@{extent} * float(@{scores})" weighted_expression = weighted_expression.format(extent=extent, scores=base_scores) weighted_equation = EQUATION.format(result=weighted, expression=weighted_expression) r.mapcalc(weighted_equation, overwrite=True) # Write weighted extent figures as labels r.stats_zonal( flags="r", base=base, cover=weighted, method="average", output=weighted, overwrite=True, verbose=False, quiet=True, ) # Get weighted extents in a dictionary weighted_extents = grass.parse_command("r.category", map=weighted, delimiter="\t") # Compute the sum of all weighted extents and add to dictionary category_sum = sum([ float(x) if not math.isnan(float(x)) else 0 for x in weighted_extents.values() ]) weighted_extents["sum"] = category_sum # Create a map to hold fractions of each weighted extent to the sum # See also: # https://grasswiki.osgeo.org/wiki/LANDSAT#Hint:_Minimal_disk_space_copies r.reclass( input=base, output=fractions, rules="-", stdin="*=*", verbose=False, quiet=True, ) # Compute weighted fractions of land types fraction_category_label = { key: float(value) / weighted_extents["sum"] for (key, value) in weighted_extents.iteritems() if key is not "sum" } # Build fraction category and label rules for `r.category` fraction_rules = "\n".join([ "{0}:{1}".format(key, value) for key, value in fraction_category_label.items() ]) # Set rules r.category(map=fractions, rules="-", stdin=fraction_rules, separator=":") # Assert that sum of fractions is ~1 fraction_categories = grass.parse_command("r.category", map=fractions, delimiter="\t") fractions_sum = sum([ float(x) if not math.isnan(float(x)) else 0 for x in fraction_categories.values() ]) msg = "Fractions: {f}".format(f=fraction_categories) grass.debug(_(msg)) # g.message(_("Sum: {:.17g}".format(fractions_sum))) assert abs(fractions_sum - 1) < 1.0e-6, "Sum of fractions is != 1" # Compute flow flow_expression = "@{fractions} * @{flow}" flow_expression = flow_expression.format(fractions=fractions, flow=flow_in_base) flow_equation = EQUATION.format(result=flow, expression=flow_expression) r.mapcalc(flow_equation, overwrite=True) # Write flow figures as raster category labels r.stats_zonal( base=reclassified_base, flags="r", cover=flow, method="sum", output=flow_in_category, overwrite=True, verbose=False, quiet=True, ) # Parse flow categories and labels flow_categories = grass.parse_command("r.category", map=flow_in_category, delimiter="\t") grass.debug(_("Flow: {c}".format(c=flow_categories))) # Build flow category and label rules for `r.category` flow_rules = "\n".join([ "{0}:{1}".format(key, value) for key, value in flow_categories.items() ]) # Discard areas out of MASK # Check here again! # Output patch of all flow maps? copy_equation = EQUATION.format(result=flow_in_category, expression=flow_in_category) r.mapcalc(copy_equation, overwrite=True) # Reassign cell category labels r.category(map=flow_in_category, rules="-", stdin=flow_rules, separator=":") # Update title reclassified_base_title += " " + category r.support(flow_in_category, title=reclassified_base_title) # debugging # r.report( # flags='hn', # map=(flow_in_category), # units=('k','c','p'), # ) if print_only: r.stats( input=(flow_in_category), output="-", flags="nacpl", separator=COMMA, quiet=True, ) if not print_only: if flow_column_name: flow_column_prefix = flow_column_name + category else: flow_column_name = "flow" flow_column_prefix = flow_column_name + category # Produce vector map(s) if vector: # The following is wrong # update_vector(vector=vector, # raster=flow_in_category, # methods=METHODS, # column_prefix=flow_column_prefix) # What can be done? # Maybe update columns of an existing map from the columns of # the following vectorised raster map(s) # ? raster_to_vector(raster=flow_in_category, vector=flow_in_category, type="area") # get statistics dictionary = get_raster_statistics( map_one=aggregation, # reclassified_base map_two=flow_in_category, separator="|", flags="nlcap", ) # merge 'dictionary' with global 'statistics_dictionary' statistics_dictionary = merge_two_dictionaries( statistics_dictionary, dictionary) # It is important to remove the MASK! r.mask(flags="r", quiet=True) # FIXME # Add "reclassified_base" map to "remove_at_exit" here, so as to be after # all reclassified maps that derive from it # remove the map 'reclassified_base' # g.remove(flags='f', type='raster', name=reclassified_base, quiet=True) # remove_map_at_exit(reclassified_base) if not print_only: r.patch(flags="", input=flows, output=flow_in_reclassified_base, quiet=True) if vector: # Patch all flow vector maps in one v.patch( flags="e", input=flows, output=flow_in_reclassified_base, overwrite=True, quiet=True, ) # export to csv if supply_filename: supply_filename += CSV_EXTENSION nested_dictionary_to_csv(supply_filename, statistics_dictionary) if use_filename: use_filename += CSV_EXTENSION uses = compile_use_table(statistics_dictionary) dictionary_to_csv(use_filename, uses) # Maybe return list of flow maps? Requires unique flow map names return flows
def main(): elevation = options['elevation'] slope = options['slope'] flat_thres = float(options['flat_thres']) curv_thres = float(options['curv_thres']) filter_size = int(options['filter_size']) counting_size = int(options['counting_size']) nclasses = int(options['classes']) texture = options['texture'] convexity = options['convexity'] concavity = options['concavity'] features = options['features'] # remove mapset from output name in case of overwriting existing map texture = texture.split('@')[0] convexity = convexity.split('@')[0] concavity = concavity.split('@')[0] features = features.split('@')[0] # store current region settings global current_reg current_reg = parse_key_val(g.region(flags='pg', stdout_=PIPE).outputs.stdout) del current_reg['projection'] del current_reg['zone'] del current_reg['cells'] # check for existing mask and backup if found global mask_test mask_test = gs.list_grouped( type='rast', pattern='MASK')[gs.gisenv()['MAPSET']] if mask_test: global original_mask original_mask = temp_map('tmp_original_mask') g.copy(raster=['MASK', original_mask]) # error checking if flat_thres < 0: gs.fatal('Parameter thres cannot be negative') if filter_size % 2 == 0 or counting_size % 2 == 0: gs.fatal( 'Filter or counting windows require an odd-numbered window size') if filter_size >= counting_size: gs.fatal( 'Filter size needs to be smaller than the counting window size') if features != '' and slope == '': gs.fatal('Need to supply a slope raster in order to produce the terrain classification') # Terrain Surface Texture ------------------------------------------------- # smooth the dem gs.message("Calculating terrain surface texture...") gs.message( "1. Smoothing input DEM with a {n}x{n} median filter...".format( n=filter_size)) filtered_dem = temp_map('tmp_filtered_dem') gs.run_command("r.neighbors", input = elevation, method = "median", size = filter_size, output = filtered_dem, flags='c', quiet=True) # extract the pits and peaks based on the threshold pitpeaks = temp_map('tmp_pitpeaks') gs.message("2. Extracting pits and peaks with difference > thres...") r.mapcalc(expression='{x} = if ( abs({dem}-{median})>{thres}, 1, 0)'.format( x=pitpeaks, dem=elevation, thres=flat_thres, median=filtered_dem), quiet=True) # calculate density of pits and peaks gs.message("3. Using resampling filter to create terrain texture...") window_radius = (counting_size-1)/2 y_radius = float(current_reg['ewres'])*window_radius x_radius = float(current_reg['nsres'])*window_radius resample = temp_map('tmp_density') r.resamp_filter(input=pitpeaks, output=resample, filter=['bartlett','gauss'], radius=[x_radius,y_radius], quiet=True) # convert to percentage gs.message("4. Converting to percentage...") r.mask(raster=elevation, overwrite=True, quiet=True) r.mapcalc(expression='{x} = float({y} * 100)'.format(x=texture, y=resample), quiet=True) r.mask(flags='r', quiet=True) r.colors(map=texture, color='haxby', quiet=True) # Terrain convexity/concavity --------------------------------------------- # surface curvature using lacplacian filter gs.message("Calculating terrain convexity and concavity...") gs.message("1. Calculating terrain curvature using laplacian filter...") # grow the map to remove border effects and run laplacian filter dem_grown = temp_map('tmp_elevation_grown') laplacian = temp_map('tmp_laplacian') g.region(n=float(current_reg['n']) + (float(current_reg['nsres']) * filter_size), s=float(current_reg['s']) - (float(current_reg['nsres']) * filter_size), w=float(current_reg['w']) - (float(current_reg['ewres']) * filter_size), e=float(current_reg['e']) + (float(current_reg['ewres']) * filter_size)) r.grow(input=elevation, output=dem_grown, radius=filter_size, quiet=True) r.mfilter( input=dem_grown, output=laplacian, filter=string_to_rules(laplacian_matrix(filter_size)), quiet=True) # extract convex and concave pixels gs.message("2. Extracting convexities and concavities...") convexities = temp_map('tmp_convexities') concavities = temp_map('tmp_concavities') r.mapcalc( expression='{x} = if({laplacian}>{thres}, 1, 0)'\ .format(x=convexities, laplacian=laplacian, thres=curv_thres), quiet=True) r.mapcalc( expression='{x} = if({laplacian}<-{thres}, 1, 0)'\ .format(x=concavities, laplacian=laplacian, thres=curv_thres), quiet=True) # calculate density of convexities and concavities gs.message("3. Using resampling filter to create surface convexity/concavity...") resample_convex = temp_map('tmp_convex') resample_concav = temp_map('tmp_concav') r.resamp_filter(input=convexities, output=resample_convex, filter=['bartlett','gauss'], radius=[x_radius,y_radius], quiet=True) r.resamp_filter(input=concavities, output=resample_concav, filter=['bartlett','gauss'], radius=[x_radius,y_radius], quiet=True) # convert to percentages gs.message("4. Converting to percentages...") g.region(**current_reg) r.mask(raster=elevation, overwrite=True, quiet=True) r.mapcalc(expression='{x} = float({y} * 100)'.format(x=convexity, y=resample_convex), quiet=True) r.mapcalc(expression='{x} = float({y} * 100)'.format(x=concavity, y=resample_concav), quiet=True) r.mask(flags='r', quiet=True) # set colors r.colors_stddev(map=convexity, quiet=True) r.colors_stddev(map=concavity, quiet=True) # Terrain classification Flowchart----------------------------------------- if features != '': gs.message("Performing terrain surface classification...") # level 1 produces classes 1 thru 8 # level 2 produces classes 5 thru 12 # level 3 produces classes 9 thru 16 if nclasses == 8: levels = 1 if nclasses == 12: levels = 2 if nclasses == 16: levels = 3 classif = [] for level in range(levels): # mask previous classes x:x+4 if level != 0: min_cla = (4*(level+1))-4 clf_msk = temp_map('tmp_clf_mask') rules = '1:{0}:1'.format(min_cla) r.recode( input=classif[level-1], output=clf_msk, rules=string_to_rules(rules), overwrite=True) r.mask(raster=clf_msk, flags='i', quiet=True, overwrite=True) # image statistics smean = r.univar( map=slope, flags='g', stdout_=PIPE).outputs.stdout.split(os.linesep) smean = [i for i in smean if i.startswith('mean=') is True][0].split('=')[1] cmean = r.univar( map=convexity, flags='g', stdout_=PIPE).outputs.stdout.split(os.linesep) cmean = [i for i in cmean if i.startswith('mean=') is True][0].split('=')[1] tmean = r.univar( map=texture, flags='g', stdout_=PIPE).outputs.stdout.split(os.linesep) tmean = [i for i in tmean if i.startswith('mean=') is True][0].split('=')[1] classif.append(temp_map('tmp_classes')) if level != 0: r.mask(flags='r', quiet=True) classification(level+1, slope, smean, texture, tmean, convexity, cmean, classif[level]) # combine decision trees merged = [] for level in range(0, levels): if level > 0: min_cla = (4*(level+1))-4 merged.append(temp_map('tmp_merged')) r.mapcalc( expression='{x} = if({a}>{min}, {b}, {a})'.format( x=merged[level], min=min_cla, a=merged[level-1], b=classif[level])) else: merged.append(classif[level]) g.rename(raster=[merged[-1], features], quiet=True) del TMP_RAST[-1] # Write metadata ---------------------------------------------------------- history = 'r.terrain.texture ' for key,val in options.iteritems(): history += key + '=' + str(val) + ' ' r.support(map=texture, title=texture, description='generated by r.terrain.texture', history=history) r.support(map=convexity, title=convexity, description='generated by r.terrain.texture', history=history) r.support(map=concavity, title=concavity, description='generated by r.terrain.texture', history=history) if features != '': r.support(map=features, title=features, description='generated by r.terrain.texture', history=history) # write color and category rules to tempfiles r.category( map=features, rules=string_to_rules(categories(nclasses)), separator='pipe') r.colors( map=features, rules=string_to_rules(colors(nclasses)), quiet=True) return 0
def main(): # Temporary filenames tmp_avg_lse = tmp_map_name("avg_lse") tmp_delta_lse = tmp_map_name("delta_lse") tmp_cwv = tmp_map_name("cwv") # tmp_lst = tmp_map_name('lst') # user input mtl_file = options["mtl"] if not options["prefix"]: b10 = options["b10"] b11 = options["b11"] t10 = options["t10"] t11 = options["t11"] if not options["clouds"]: qab = options["qab"] cloud_map = False else: qab = False cloud_map = options["clouds"] elif options["prefix"]: prefix = options["prefix"] b10 = prefix + "10" b11 = prefix + "11" if not options["clouds"]: qab = prefix + "QA" cloud_map = False else: cloud_map = options["clouds"] qab = False qapixel = options["qapixel"] lst_output = options["lst"] # save Brightness Temperature maps? if options["prefix_bt"]: brightness_temperature_prefix = options["prefix_bt"] else: brightness_temperature_prefix = None cwv_window_size = int(options["window"]) assertion_for_cwv_window_size_msg = ( "A spatial window of size 5^2 or less is not " "recommended. Please select a larger window. " "Refer to the manual's notes for details.") assert cwv_window_size >= 7, assertion_for_cwv_window_size_msg cwv_output = options["cwv"] # optional maps average_emissivity_map = options["emissivity"] delta_emissivity_map = options["delta_emissivity"] # output for in-between maps? emissivity_output = options["emissivity_out"] delta_emissivity_output = options["delta_emissivity_out"] landcover_map = options["landcover"] landcover_class = options["landcover_class"] # flags info = flags["i"] scene_extent = flags["e"] timestamping = flags["t"] null = flags["n"] rounding = flags["r"] celsius = flags["c"] # ToDo: # shell = flags['g'] # # Pre-production actions # # Set Region if scene_extent: grass.use_temp_region() # safely modify the region msg = "\n|! Matching region extent to map {name}" # ToDo: check if extent-B10 == extent-B11? Unnecessary? # Improve below! if b10: run("g.region", rast=b10, align=b10) msg = msg.format(name=b10) elif t10: run("g.region", rast=t10, align=t10) msg = msg.format(name=t10) g.message(msg) elif not scene_extent: grass.warning(_("Operating on current region")) # # 1. Mask clouds # if cloud_map: # user-fed cloud map? msg = "\n|i Using {cmap} as a MASK".format(cmap=cloud_map) g.message(msg) r.mask(raster=cloud_map, flags="i", overwrite=True) else: # using the quality assessment band and a "QA" pixel value mask_clouds(qab, qapixel) # # 2. TIRS > Brightness Temperatures # if mtl_file: # if MTL and b10 given, use it to compute at-satellite temperature t10 if b10: # convert DNs to at-satellite temperatures t10 = tirs_to_at_satellite_temperature( b10, mtl_file, brightness_temperature_prefix, null, quiet=info, ) # likewise for b11 -> t11 if b11: # convert DNs to at-satellite temperatures t11 = tirs_to_at_satellite_temperature( b11, mtl_file, brightness_temperature_prefix, null, quiet=info, ) # # Initialise a SplitWindowLST object # split_window_lst = SplitWindowLST(landcover_class) citation_lst = split_window_lst.citation # # 3. Land Surface Emissivities # # use given fixed class? if landcover_class: if split_window_lst.landcover_class is False: # replace with meaningful error grass.warning("Unknown land cover class string! Note, this string " "input option is case sensitive.") if landcover_class == "Random": msg = ("\n|! Random emissivity class selected > " + split_window_lst.landcover_class + " ") if landcover_class == "Barren_Land": msg = ( "\n|! For barren land, the last quadratic term of the Split-Window algorithm will be set to 0" + split_window_lst.landcover_class + " ") else: msg = "\n|! Retrieving average emissivities *only* for {eclass} " if info: msg += "| Average emissivities (channels 10, 11): " msg += (str(split_window_lst.emissivity_t10) + ", " + str(split_window_lst.emissivity_t11)) msg = msg.format(eclass=split_window_lst.landcover_class) g.message(msg) # use the FROM-GLC map elif landcover_map: if average_emissivity_map: tmp_avg_lse = average_emissivity_map if not average_emissivity_map: determine_average_emissivity( tmp_avg_lse, emissivity_output, landcover_map, split_window_lst.average_lse_mapcalc, quiet=info, ) if options["emissivity_out"]: tmp_avg_lse = options["emissivity_out"] if delta_emissivity_map: tmp_delta_lse = delta_emissivity_map if not delta_emissivity_map: determine_delta_emissivity( tmp_delta_lse, delta_emissivity_output, landcover_map, split_window_lst.delta_lse_mapcalc, quiet=info, ) if options["delta_emissivity_out"]: tmp_delta_lse = options["delta_emissivity_out"] # # 4. Modified Split-Window Variance-Covariance Matrix > Column Water Vapor # if info: msg = "\n|i Spatial window of size {n} for Column Water Vapor estimation: " msg = msg.format(n=cwv_window_size) g.message(msg) cwv = Column_Water_Vapor(cwv_window_size, t10, t11) citation_cwv = cwv.citation estimate_cwv_big_expression( tmp_cwv, cwv_output, t10, t11, cwv._big_cwv_expression(), ) if cwv_output: tmp_cwv = cwv_output # # 5. Estimate Land Surface Temperature # if info and landcover_class == "Random": msg = "\n|* Will pick a random emissivity class!" grass.verbose(msg) estimate_lst( lst_output, t10, t11, landcover_map, landcover_class, tmp_avg_lse, tmp_delta_lse, tmp_cwv, split_window_lst.sw_lst_mapcalc, rounding, celsius, quiet=info, ) # # Post-production actions # # remove MASK r.mask(flags="r", verbose=True) # time-stamping if timestamping: add_timestamp(mtl_file, lst_output) if cwv_output: add_timestamp(mtl_file, cwv_output) # Apply color table if celsius: run("r.colors", map=lst_output, color="celsius") else: # color table for kelvin run("r.colors", map=lst_output, color="kelvin") # ToDo: helper function for r.support # strings for metadata history_lst = "\n" + citation_lst history_lst += "\n\n" + citation_cwv history_lst += "\n\nSplit-Window model: " history_lst += split_window_lst._equation # :wsw_lst_mapcalc description_lst = "Land Surface Temperature derived from a split-window algorithm. " if celsius: title_lst = "Land Surface Temperature (C)" units_lst = "Celsius" else: title_lst = "Land Surface Temperature (K)" units_lst = "Kelvin" landsat8_metadata = Landsat8_MTL(mtl_file) source1_lst = landsat8_metadata.scene_id source2_lst = landsat8_metadata.origin # history entry run( "r.support", map=lst_output, title=title_lst, units=units_lst, description=description_lst, source1=source1_lst, source2=source2_lst, history=history_lst, ) # (re)name the LST product # run("g.rename", rast=(tmp_lst, lst_output)) # restore region if scene_extent: grass.del_temp_region() # restoring previous region settings g.message("|! Original Region restored") # print citation if info: g.message("\nSource: " + citation_lst)
def compute_attractiveness(raster, metric, constant, kappa, alpha, mask=None, output_name=None): """ Compute a raster map whose values follow an (euclidean) distance function ( {constant} + {kappa} ) / ( {kappa} + exp({alpha} * {distance}) ), where: Source: http://publications.jrc.ec.europa.eu/repository/bitstream/JRC87585/lb-na-26474-en-n.pd Parameters ---------- constant : 1 kappa : A constant named 'K' alpha : A constant named 'a' distance : A distance map based on the input raster score : A score term to multiply the distance function mask : Optional raster MASK which is inverted to selectively exclude non-NULL cells from distance related computations. output_name : Name to pass to temporary_filename() to create a temporary map name Returns ------- tmp_output : A temporary proximity to features raster map. Examples -------- ... """ distance_terms = [ str(raster), str(metric), "distance", str(constant), str(kappa), str(alpha), ] if score: grass.debug(_( "Score for attractiveness equation: {s}".format(s=score))) distance_terms += str(score) # tmp_distance = temporary_filename('_'.join(distance_terms)) tmp_distance = temporary_filename(filename="_".join([raster, metric])) r.grow_distance(input=raster, distance=tmp_distance, metric=metric, quiet=True, overwrite=True) if mask: msg = "Inverted masking to exclude non-NULL cells " msg += "from distance related computations based on '{mask}'" msg = msg.format(mask=mask) grass.verbose(_(msg)) r.mask(raster=mask, flags="i", overwrite=True, quiet=True) # FIXME: use a parameters dictionary, avoid conditionals if score: distance_function = build_distance_function( constant=constant, kappa=kappa, alpha=alpha, variable=tmp_distance, score=score, ) # FIXME: use a parameters dictionary, avoid conditionals if not score: distance_function = build_distance_function(constant=constant, kappa=kappa, alpha=alpha, variable=tmp_distance) # temporary maps will be removed if output_name: tmp_distance_map = temporary_filename(filename=output_name) else: basename = "_".join([raster, "attractiveness"]) tmp_distance_map = temporary_filename(filename=basename) distance_function = EQUATION.format(result=tmp_distance_map, expression=distance_function) msg = "* Distance function: {f}".format(f=distance_function) grass.verbose(_(msg)) grass.mapcalc(distance_function, overwrite=True) r.null(map=tmp_distance_map, null=0) # Set NULLs to 0 compress_status = grass.read_command("r.compress", flags="g", map=tmp_distance_map) grass.verbose(_( "* Compress status: {s}".format(s=compress_status))) # REMOVEME return tmp_distance_map
def main(): # Temporary filenames tmp_avg_lse = tmp_map_name('avg_lse') tmp_delta_lse = tmp_map_name('delta_lse') #tmp_lst = tmp_map_name('lst') # user input mtl_file = options['mtl'] if not options['prefix']: b10 = options['b10'] b11 = options['b11'] t10 = options['t10'] t11 = options['t11'] if not options['clouds']: qab = options['qab'] cloud_map = False else: qab = False cloud_map = options['clouds'] elif options['prefix']: prefix = options['prefix'] b10 = prefix + '10' b11 = prefix + '11' if not options['clouds']: qab = prefix + 'QA' cloud_map = False else: cloud_map = options['clouds'] qab = False qapixel = options['qapixel'] lst_output = options['lst'] # save Brightness Temperature maps? if options['prefix_bt']: brightness_temperature_prefix = options['prefix_bt'] else: brightness_temperature_prefix = None if options['cwv']: tmp_cwv = options['cwv'] else: tmp_cwv = tmp_map_name('cwv') cwv_window_size = int(options['window']) assertion_for_cwv_window_size_msg = MSG_ASSERTION_WINDOW_SIZE assert cwv_window_size >= 7, assertion_for_cwv_window_size_msg cwv_output = options['cwv_out'] # optional maps average_emissivity_map = options['emissivity'] delta_emissivity_map = options['delta_emissivity'] # output for in-between maps? emissivity_output = options['emissivity_out'] delta_emissivity_output = options['delta_emissivity_out'] landcover_map = options['landcover'] landcover_class = options['landcover_class'] # flags info = flags['i'] null = flags['n'] scene_extent = flags['e'] median = flags['m'] accuracy = flags['a'] rounding = flags['r'] celsius = flags['c'] timestamping = flags['t'] # # Pre-production actions # if scene_extent: grass.use_temp_region() # safely modify the region, restore at end msg = WARNING_REGION_MATCHING # TODO: Check if extent-B10 == extent-B11? # if b10: run('g.region', rast=b10, align=b10) msg = msg.format(name=b10) elif t10: run('g.region', rast=t10, align=t10) msg = msg.format(name=t10) # ---------------------------------------- # grass.warning(_(msg)) # # 1. Mask clouds # if cloud_map: msg = f'\n|i Using user defined \'{cloud_map}\' as a MASK' g.message(msg) r.mask(raster=cloud_map, flags='i', overwrite=True) else: # using the quality assessment band and a "QA" pixel value mask_clouds(qab, qapixel) # # 2. TIRS > Brightness Temperatures # if mtl_file: # if MTL and b10 given, use it to compute at-satellite temperature t10 if b10: t10 = tirs_to_at_satellite_temperature( b10, mtl_file, brightness_temperature_prefix, null, info=info, ) # likewise for b11 -> t11 if b11: t11 = tirs_to_at_satellite_temperature( b11, mtl_file, brightness_temperature_prefix, null, info=info, ) # # 3. Land Surface Emissivities # split_window_lst = SplitWindowLST(landcover_class) if landcover_class: if split_window_lst.landcover_class is False: # replace with meaningful error grass.warning(MSG_UNKNOWN_LANDCOVER_CLASS) if landcover_class == 'Random': msg = MSG_RANDOM_EMISSIVITY_CLASS + \ split_window_lst.landcover_class + ' ' if landcover_class == 'Barren_Land': msg = MSG_BARREN_LAND + \ split_window_lst.landcover_class + ' ' else: msg = MSG_SINGLE_CLASS_AVERAGE_EMISSIVITY + f'{eclass} ' if info: msg += MSG_AVERAGE_EMISSIVITIES msg += str(split_window_lst.emissivity_t10) + ', ' + \ str(split_window_lst.emissivity_t11) g.message(msg) # use the FROM-GLC map elif landcover_map: if average_emissivity_map: tmp_avg_lse = average_emissivity_map if not average_emissivity_map: determine_average_emissivity( tmp_avg_lse, emissivity_output, landcover_map, split_window_lst.average_lse_mapcalc, info=info, ) if options['emissivity_out']: tmp_avg_lse = options['emissivity_out'] if delta_emissivity_map: tmp_delta_lse = delta_emissivity_map if not delta_emissivity_map: determine_delta_emissivity( tmp_delta_lse, delta_emissivity_output, landcover_map, split_window_lst.delta_lse_mapcalc, info=info, ) if options['delta_emissivity_out']: tmp_delta_lse = options['delta_emissivity_out'] # # 4. Estimate Column Water Vapor # if not options['cwv']: estimate_cwv( temporary_map=tmp_cwv, cwv_map=cwv_output, t10=t10, t11=t11, window_size=cwv_window_size, median=median, info=info, ) else: msg = f'\n|! User defined map \'{tmp_cwv}\' for atmospheric column water vapor' g.message(msg) if cwv_output: tmp_cwv = cwv_output # # 5. Estimate Land Surface Temperature # if info and landcover_class == 'Random': msg = MSG_PICK_RANDOM_CLASS grass.verbose(msg) estimate_lst( outname=lst_output, t10=t10, t11=t11, landcover_map=landcover_map, landcover_class=landcover_class, avg_lse_map=tmp_avg_lse, delta_lse_map=tmp_delta_lse, cwv_map=tmp_cwv, lst_expression=split_window_lst.sw_lst_mapcalc, rounding=rounding, celsius=celsius, info=info, ) # # Post-production actions # # remove MASK r.mask(flags='r', verbose=True) if timestamping: add_timestamp(mtl_file, lst_output) if cwv_output: add_timestamp(mtl_file, cwv_output) if celsius: run('r.colors', map=lst_output, color='celsius') else: run('r.colors', map=lst_output, color='kelvin') # metadata history_lst = '\n' + CITATION_SPLIT_WINDOW history_lst += '\n\n' + CITATION_COLUMN_WATER_VAPOR history_lst += '\n\nSplit-Window model: ' history_lst += split_window_lst._equation # :wsw_lst_mapcalc description_lst = DESCRIPTION_LST if celsius: title_lst = 'Land Surface Temperature (C)' units_lst = 'Celsius' else: title_lst = 'Land Surface Temperature (K)' units_lst = 'Kelvin' landsat8_metadata = Landsat8_MTL(mtl_file) source1_lst = landsat8_metadata.scene_id source2_lst = landsat8_metadata.origin run( "r.support", map=lst_output, title=title_lst, units=units_lst, description=description_lst, source1=source1_lst, source2=source2_lst, history=history_lst, ) if scene_extent: grass.del_temp_region() # restoring previous region grass.warning(WARNING_REGION_RESTORING) if info: g.message('\nSource: ' + CITATION_SPLIT_WINDOW)