def tirs_to_at_satellite_temperature( tirs_1x, mtl_file, brightness_temperature_prefix=None, null=False, quiet=True): """ Helper function to convert TIRS bands 10 or 11 in to at-satellite temperatures. This function uses the pre-defined functions: - extract_number_from_string() - digital_numbers_to_radiance() - radiance_to_brightness_temperature() The inputs are: - a name for the input tirs band (10 or 11) - a Landsat8 MTL file The output is a temporary at-Satellite Temperature map. """ # which band number and MTL file band_number = extract_number_from_string(tirs_1x) tmp_radiance = tmp_map_name('radiance') + '.' + band_number tmp_brightness_temperature = tmp_map_name('brightness_temperature') + '.' + \ band_number landsat8 = Landsat8_MTL(mtl_file) # rescale DNs to spectral radiance radiance_expression = landsat8.toar_radiance(band_number) digital_numbers_to_radiance( tmp_radiance, tirs_1x, radiance_expression, null, quiet, ) # convert spectral radiance to at-satellite temperature temperature_expression = landsat8.radiance_to_temperature(band_number) radiance_to_brightness_temperature( tmp_brightness_temperature, tmp_radiance, temperature_expression, quiet, ) # save Brightness Temperature map? if brightness_temperature_prefix: bt_output = brightness_temperature_prefix + band_number run('g.rename', raster=(tmp_brightness_temperature, bt_output)) tmp_brightness_temperature = bt_output return tmp_brightness_temperature
def add_timestamp(mtl_filename, outname): """ Retrieve metadata from MTL file. """ import datetime metadata = Landsat8_MTL(mtl_filename) # required format is: day=integer month=string year=integer time=hh:mm:ss.dd acquisition_date = str(metadata.date_acquired) ### FixMe ### acquisition_date = datetime.datetime.strptime( acquisition_date, '%Y-%m-%d').strftime('%d %b %Y') acquisition_time = str(metadata.scene_center_time)[0:8] date_time_string = acquisition_date + ' ' + acquisition_time #msg = "Date and time of acquisition: " + date_time_string #grass.verbose(msg) run('r.timestamp', map=outname, date=date_time_string)
def test(mtlfile): """ Test the class. """ print("! No file defined, testing with default MTl file!") mtl = Landsat8_MTL(MTLFILE) print() print("| Test the object's __str__ method:", mtl) print("| Test method _get_mtl_lines:\n ", mtl._get_mtl_lines()) print() print("| Basic metadata:") print(" > id (original field name is 'LANDSAT_SCENE_ID'):", mtl.scene_id) print(" > WRS path:", mtl.wrs_path) print(" > WRS row:", mtl.wrs_row) print(" > Acquisition date:", mtl.date_acquired) print(" > Scene's center time:", mtl.scene_center_time) print(" > Upper left corner:", mtl.corner_ul) print(" > Lower right corner:", mtl.corner_lr) print(" > Upper left (projected):", mtl.corner_ul_projection) print(" > Lower right (projected):", mtl.corner_lr_projection) print(" > Cloud cover:", mtl.cloud_cover)
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(): # 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 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)