Пример #1
0
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 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)
Пример #4
0
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)
Пример #5
0
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)
Пример #6
0
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)
Пример #7
0
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
Пример #11
0
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
Пример #12
0
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
Пример #13
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)
Пример #14
0
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
Пример #15
0
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)