def radiance_to_brightness_temperature(outname, radiance,
                                       temperature_expression):
    """
    Convert Spectral Radiance to At-Satellite Brightness Temperature. For
    details see Landsat8 class.
    """
    temperature_expression = replace_dummies(
        temperature_expression,
        instring=DUMMY_MAPCALC_STRING_RADIANCE,
        outstring=radiance)

    msg = "\n|i Converting spectral radiance to at-Satellite Temperature "
    if info:
        msg += "| Expression: " + str(temperature_expression)
    g.message(msg)

    temperature_equation = equation.format(result=outname,
                                           expression=temperature_expression)

    grass.mapcalc(temperature_equation, overwrite=True)

    if info:
        run('r.info', map=outname, flags='r')
        #run('r.univar', map=outname)

    del (temperature_expression)
    del (temperature_equation)
def main():
    """
    RichDEM depression filling
    """
    # lazy import RICHDEM
    try:
        import richdem as rd
    except:
        g.message(flags='e',
                  message=('RichDEM not detected. Install pip3 and ' +
                           'then type at the command prompt: ' +
                           '"pip3 install richdem".'))

    _input = options['input']
    _output = options['output']
    _epsilon = options['epsilon']
    _topology = options['topology']

    if _epsilon == 'true':
        epsilon = True
    else:
        epsilon = False

    dem = garray.array()
    dem.read(_input, null=np.nan)

    rd_inout = rd.rdarray(dem, no_data=np.nan)
    rd.FillDepressions(dem=rd_inout,
                       epsilon=epsilon,
                       in_place=True,
                       topology=_topology)

    dem[:] = rd_inout[:]
    dem.write(_output, overwrite=gscript.overwrite())
Example #3
0
def radiance_to_brightness_temperature(
    outname,
    radiance,
    temperature_expression,
    quiet=False,
):
    """
    Convert Spectral Radiance to At-Satellite Brightness Temperature. For
    details see Landsat8 class.
    """
    temperature_expression = replace_dummies(
        temperature_expression,
        instring=DUMMY_MAPCALC_STRING_RADIANCE,
        outstring=radiance,
    )

    msg = "\n|i Converting spectral radiance to at-Satellite Temperature "
    if not quiet:
        msg += "| Expression: " + str(temperature_expression)
    g.message(msg)

    temperature_equation = EQUATION.format(result=outname,
                                           expression=temperature_expression)

    grass.mapcalc(temperature_equation, overwrite=True)

    if not quiet:
        run("r.info", map=outname, flags="r")
def main():
    g.message("Pocitam NDVI...")

    # nastavit region
    g.region(rast=options['tm4'])

    # vypocitat NDVI
    r.mapcalc('ndvi = float({y} - {x}) / ({y} + {x})'.format(x=options['tm3'],
                                                             y=options['tm4']),
              overwrite=True)

    # r.reclass podporuje pouze datovy typ CELL
    r.mapcalc('temp1 = 100 * ndvi', overwrite=True)
    g.message("Reklasifikuji data...")

    # reklasifikovat data
    reclass_rules = """-100 thru 5   = 1 bez vegetace, vodni plochy
5   thru 35  = 2 plochy s minimalni vegetaci
35  thru 100  = 3 plochy pokryte vegetaci"""
    r.reclass(overwrite=True,
              rules='-',
              input='temp1',
              output='r_ndvi',
              stdin_=reclass_rules)

    # nastavit tabulku barev
    color_rules = """1 red
2 yellow
3 0 136 26"""
    r.colors(quiet=True, map='r_ndvi', rules='-', stdin_=color_rules)

    # vytiskout zakladni charakteristiku dat
    r.report(map='r_ndvi', units=['c', 'p', 'h'])
def determine_average_emissivity(
    outname,
    emissivity_output,
    landcover_map,
    avg_lse_expression,
    quiet=True,
):
    """
    Produce an average emissivity map based on FROM-GLC map covering the region
    of interest.
    """
    msg = (
        '\n|i Determining average land surface emissivity based on a look-up table '
    )
    if not quiet:
        msg += ('| Expression:\n\n {exp}')
        msg = msg.format(exp=avg_lse_expression)
    g.message(msg)
    avg_lse_expression = replace_dummies(
        avg_lse_expression,
        instring=DUMMY_MAPCALC_STRING_FROM_GLC,
        outstring=landcover_map,
    )
    avg_lse_equation = EQUATION.format(
        result=outname,
        expression=avg_lse_expression,
    )
    grass.mapcalc(avg_lse_equation, overwrite=True)

    if not quiet:
        run('r.info', map=outname, flags='r')

    # save land surface emissivity map?
    if emissivity_output:
        run('g.rename', raster=(outname, emissivity_output))
def determine_delta_emissivity(outname, landcover_map, delta_lse_expression):
    """
    Produce a delta emissivity map based on the FROM-GLC map covering the
    region of interest.
    """
    msg = ('\n|i Determining delta land surface emissivity based on a '
           'look-up table ')
    if info:
        msg += ('| Expression:\n\n {exp}')
        msg = msg.format(exp=delta_lse_expression)
    g.message(msg)

    delta_lse_expression = replace_dummies(
        delta_lse_expression,
        instring=DUMMY_MAPCALC_STRING_FROM_GLC,
        outstring=landcover_map)

    delta_lse_equation = equation.format(result=outname,
                                         expression=delta_lse_expression)

    grass.mapcalc(delta_lse_equation, overwrite=True)

    if info:
        run('r.info', map=outname, flags='r')

    del (delta_lse_expression)
    del (delta_lse_equation)

    # save delta land surface emissivity map?
    if delta_emissivity_output:
        run('g.rename', raster=(outname, delta_emissivity_output))
def estimate_column_water_vapor(outname, ratio, cwv_expression):
    """

    ***
    This function is NOT used.  It was part of an initial step-by-step approach,
    while coding and testing.  Kept for future plans!?
    ***

    """
    msg = "\n|i Estimating atmospheric column water vapor "
    msg += '| Mapcalc expression: '
    msg += cwv_expression
    g.message(msg)

    cwv_expression = replace_dummies(cwv_expression,
                                     instring=DUMMY_Rji,
                                     outstring=ratio)

    cwv_equation = equation.format(result=outname, expression=cwv_expression)

    grass.mapcalc(cwv_equation, overwrite=True)

    if info:
        run('r.info', map=outname, flags='r')

    # save Column Water Vapor map?
    if cwv_output:
        run('g.rename', raster=(outname, cwv_output))
def estimate_ratio_ji(outname, tmp_ti_mean, tmp_tj_mean, ratio_expression):
    """

    ***
    This function is NOT used.  It was part of an initial step-by-step approach,
    while coding and testing.  Kept for future plans!?
    ***

    Estimate Ratio ji for the Column Water Vapor retrieval equation.
    """
    msg = '\n |i Estimating ratio Rji...'
    msg += '\n' + ratio_expression
    g.message(msg)

    ratio_expression = replace_dummies(ratio_expression,
                                       in_ti=DUMMY_Ti_MEAN, out_ti=tmp_ti_mean,
                                       in_tj=DUMMY_Tj_MEAN, out_tj=tmp_tj_mean)

    ratio_equation = equation.format(result=outname,
                                     expression=ratio_expression)

    grass.mapcalc(ratio_equation, overwrite=True)

    if info:
        run('r.info', map=outname, flags='r')
Example #9
0
def determine_delta_emissivity(
    outname,
    delta_emissivity_output,
    landcover_map,
    delta_lse_expression,
    quiet=True,
):
    """
    Produce a delta emissivity map based on the FROM-GLC map covering the
    region of interest.
    """
    msg = "\n|i Determining delta land surface emissivity based on a " "look-up table "
    if not quiet:
        msg += "| Expression:\n\n {exp}"
        msg = msg.format(exp=delta_lse_expression)
    g.message(msg)

    delta_lse_expression = replace_dummies(
        delta_lse_expression,
        instring=DUMMY_MAPCALC_STRING_FROM_GLC,
        outstring=landcover_map,
    )

    delta_lse_equation = EQUATION.format(result=outname,
                                         expression=delta_lse_expression)

    grass.mapcalc(delta_lse_equation, overwrite=True)

    if not quiet:
        run("r.info", map=outname, flags="r")

    # save delta land surface emissivity map?
    if delta_emissivity_output:
        run("g.rename", raster=(outname, delta_emissivity_output))
def main():
    """
    RichDEM flat resolution: give a gentle slope
    """
    # lazy import RICHDEM
    try:
        import richdem as rd
    except:
        g.message(flags='e',
                  message=('RichDEM not detected. Install pip3 and ' +
                           'then type at the command prompt: ' +
                           '"pip3 install richdem".'))

    _input = options['input']
    _output = options['output']

    # Check for overwrite
    _rasters = np.array(gscript.parse_command('g.list', type='raster').keys())
    if (_rasters == _output).any():
        g.message(flags='e', message="output would overwrite " + _output)

    dem = garray.array()
    dem.read(_input, null=np.nan)

    rd_input = rd.rdarray(dem, no_data=np.nan)
    rd_output = rd.ResolveFlats(rd_input)

    dem[:] = rd_output[:]
    dem.write(_output, overwrite=gscript.overwrite())
def extract_tgz(tgz):
    """
    Decompress and unpack a .tgz file
    """

    g.message(_('Extracting files from tar.gz file'))

    # open tar.gz file in read mode
    tar = tarfile.TarFile.open(name=tgz, mode='r')

    # get the scene's (base)name
    tgz_base = os.path.basename(tgz).split('.tar.gz')[0]

    # try to create a directory with the scene's (base)name
    # source: <http://stackoverflow.com/a/14364249/1172302>
    try:
        os.makedirs(tgz_base)

    # if something went wrong, raise an error
    except OSError:
        if not os.path.isdir(tgz_base):
            raise

    # extract files indide the scene directory
    tar.extractall(path=tgz_base)
Example #12
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 identify_product_collection(scene):
    """
    Identify the collection and the validity of a Landsat scene product
    identifier by trying to match it against pre-defined regular expression
    templates.

    Parameters
    ----------
    scene :
        A Landsat product identifier string

    template :
        A list of regular expression templates against which to validate the
        'scene' string

    Returns
    -------
    ...

    Raises
    ------
    ...
    """
    for template_key in LANDSAT_IDENTIFIERS['scene_template']:
        template = LANDSAT_IDENTIFIERS['scene_template'][template_key]
        try:
            # re.match(pattern, string, flags=0)
            if re.match(template, scene):
                return template_key
        except:
            g.message(_("No match"))
def main():
    g.message("Pocitam NDVI...")

    # nastavit region
    g.region(rast=options['tm4'])
    
    # vypocitat NDVI
    r.mapcalc('ndvi = float({y} - {x}) / ({y} + {x})'.format(x=options['tm3'], y=options['tm4']), overwrite = True)
    
    # r.reclass podporuje pouze datovy typ CELL
    r.mapcalc('temp1 = 100 * ndvi', overwrite = True)
    g.message("Reklasifikuji data...")
    
    # reklasifikovat data
    reclass_rules = """-100 thru 5   = 1 bez vegetace, vodni plochy
5   thru 35  = 2 plochy s minimalni vegetaci
35  thru 100  = 3 plochy pokryte vegetaci"""
    r.reclass(overwrite = True, rules = '-',
              input = 'temp1', output = 'r_ndvi', stdin_ = reclass_rules)
    
# nastavit tabulku barev
    color_rules = """1 red
2 yellow
3 0 136 26"""
    r.colors(quiet = True,
             map = 'r_ndvi', rules = '-', stdin_ = color_rules)
    
    # vytiskout zakladni charakteristiku dat 
    r.report(map = 'r_ndvi', units = ['c', 'p', 'h'])
Example #15
0
def main():
    """
    RichDEM depression breaching
    """
    # lazy import RICHDEM
    try:
        import richdem as rd
    except:
        g.message(
            flags="e",
            message=("RichDEM not detected. Install pip3 and " +
                     "then type at the command prompt: " +
                     '"pip3 install richdem".'),
        )

    _input = options["input"]
    _output = options["output"]
    _topology = options["topology"]

    dem = garray.array()
    dem.read(_input, null=np.nan)

    rd_inout = rd.rdarray(dem, no_data=np.nan)
    rd.BreachDepressions(dem=rd_inout, in_place=True, topology=_topology)

    dem[:] = rd_inout[:]
    dem.write(_output, overwrite=gscript.overwrite())
def estimate_column_water_vapor(outname, ratio, cwv_expression):
    """

    ***
    This function is NOT used.  It was part of an initial step-by-step approach,
    while coding and testing.  Kept for future plans!?
    ***

    """
    msg = "\n|i Estimating atmospheric column water vapor "
    msg += '| Mapcalc expression: '
    msg += cwv_expression
    g.message(msg)

    cwv_expression = replace_dummies(cwv_expression,
                                     instring=DUMMY_Rji,
                                     outstring=ratio)

    cwv_equation = equation.format(result=outname, expression=cwv_expression)

    grass.mapcalc(cwv_equation, overwrite=True)

    if info:
        run('r.info', map=outname, flags='r')

    # save Column Water Vapor map?
    if cwv_output:
        run('g.rename', raster=(outname, cwv_output))
def determine_delta_emissivity(outname, landcover_map, delta_lse_expression):
    """
    Produce a delta emissivity map based on the FROM-GLC map covering the
    region of interest.
    """
    msg = ('\n|i Determining delta land surface emissivity based on a '
           'look-up table ')
    if info:
        msg += ('| Expression:\n\n {exp}')
        msg = msg.format(exp=delta_lse_expression)
    g.message(msg)

    delta_lse_expression = replace_dummies(delta_lse_expression,
                                           instring=DUMMY_MAPCALC_STRING_FROM_GLC,
                                           outstring=landcover_map)

    delta_lse_equation = equation.format(result=outname,
                                         expression=delta_lse_expression)

    grass.mapcalc(delta_lse_equation, overwrite=True)

    if info:
        run('r.info', map=outname, flags='r')

    del(delta_lse_expression)
    del(delta_lse_equation)

    # save delta land surface emissivity map?
    if delta_emissivity_output:
        run('g.rename', raster=(outname, delta_emissivity_output))
def estimate_ratio_ji(outname, tmp_ti_mean, tmp_tj_mean, ratio_expression):
    """

    ***
    This function is NOT used.  It was part of an initial step-by-step approach,
    while coding and testing.  Kept for future plans!?
    ***

    Estimate Ratio ji for the Column Water Vapor retrieval equation.
    """
    msg = '\n |i Estimating ratio Rji...'
    msg += '\n' + ratio_expression
    g.message(msg)

    ratio_expression = replace_dummies(ratio_expression,
                                       in_ti=DUMMY_Ti_MEAN,
                                       out_ti=tmp_ti_mean,
                                       in_tj=DUMMY_Tj_MEAN,
                                       out_tj=tmp_tj_mean)

    ratio_equation = equation.format(result=outname,
                                     expression=ratio_expression)

    grass.mapcalc(ratio_equation, overwrite=True)

    if info:
        run('r.info', map=outname, flags='r')
Example #19
0
def main():
    """
    RichDEM flat resolution: give a gentle slope
    """
    # lazy import RICHDEM
    try:
        import richdem as rd
    except:
        g.message(
            flags="e",
            message=("RichDEM not detected. Install pip3 and " +
                     "then type at the command prompt: " +
                     '"pip3 install richdem".'),
        )

    _input = options["input"]
    _output = options["output"]
    _attribute = options["attribute"]
    _zscale = float(options["zscale"])

    dem = garray.array()
    dem.read(_input, null=np.nan)

    rd_input = rd.rdarray(dem, no_data=np.nan)
    del dem
    rd_output = rd.TerrainAttribute(dem=rd_input,
                                    attrib=_attribute,
                                    zscale=_zscale)

    outarray = garray.array()
    outarray[:] = rd_output[:]
    outarray.write(_output, overwrite=gscript.overwrite())
def digital_numbers_to_radiance(outname, band, radiance_expression):
    """
    Convert Digital Number values to TOA Radiance. For details, see in Landsat8
    class.  Zero (0) DNs set to NULL here (not via the class' function).
    """
    if null:
        msg = "\n|i Setting zero (0) Digital Numbers in {band} to NULL"
        msg = msg.format(band=band)
        g.message(msg)
        run('r.null', map=band, setnull=0)

    msg = "\n|i Rescaling {band} digital numbers to spectral radiance "
    msg = msg.format(band=band)

    if info:
        msg += '| Expression: '
        msg += radiance_expression
    g.message(msg)
    radiance_expression = replace_dummies(radiance_expression,
                                          instring=DUMMY_MAPCALC_STRING_DN,
                                          outstring=band)
    radiance_equation = equation.format(result=outname,
                                        expression=radiance_expression)

    grass.mapcalc(radiance_equation, overwrite=True)

    if info:
        run('r.info', map=outname, flags='r')
        #run('r.univar', map=outname)

    del(radiance_expression)
    del(radiance_equation)
def radiance_to_brightness_temperature(outname, radiance, temperature_expression):
    """
    Convert Spectral Radiance to At-Satellite Brightness Temperature. For
    details see Landsat8 class.
    """
    temperature_expression = replace_dummies(temperature_expression,
                                             instring=DUMMY_MAPCALC_STRING_RADIANCE,
                                             outstring=radiance)

    msg = "\n|i Converting spectral radiance to at-Satellite Temperature "
    if info:
        msg += "| Expression: " + str(temperature_expression)
    g.message(msg)

    temperature_equation = equation.format(result=outname,
                                           expression=temperature_expression)

    grass.mapcalc(temperature_equation, overwrite=True)

    if info:
        run('r.info', map=outname, flags='r')
        #run('r.univar', map=outname)

    del(temperature_expression)
    del(temperature_equation)
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 digital_numbers_to_radiance(outname, band, radiance_expression):
    """
    Convert Digital Number values to TOA Radiance. For details, see in Landsat8
    class.  Zero (0) DNs set to NULL here (not via the class' function).
    """
    if null:
        msg = "\n|i Setting zero (0) Digital Numbers in {band} to NULL"
        msg = msg.format(band=band)
        g.message(msg)
        run('r.null', map=band, setnull=0)

    msg = "\n|i Rescaling {band} digital numbers to spectral radiance "
    msg = msg.format(band=band)

    if info:
        msg += '| Expression: '
        msg += radiance_expression
    g.message(msg)
    radiance_expression = replace_dummies(radiance_expression,
                                          instring=DUMMY_MAPCALC_STRING_DN,
                                          outstring=band)
    radiance_equation = equation.format(result=outname,
                                        expression=radiance_expression)

    grass.mapcalc(radiance_equation, overwrite=True)

    if info:
        run('r.info', map=outname, flags='r')
        #run('r.univar', map=outname)

    del (radiance_expression)
    del (radiance_equation)
def estimate_lst(outname, t10, t11, avg_lse_map, delta_lse_map, cwv_map, lst_expression):
    """
    Produce a Land Surface Temperature map based on a mapcalc expression
    returned from a SplitWindowLST object.

    Inputs are:

    - brightness temperature maps t10, t11
    - column water vapor map
    - a temporary filename
    - a valid mapcalc expression
    """
    msg = '\n|i Estimating land surface temperature '
    if info:
        msg += "| Expression:\n"
    g.message(msg)

    if info:
        msg = lst_expression
        msg += '\n'
        print msg

    # replace the "dummy" string...
    if landcover_map:
        split_window_expression = replace_dummies(lst_expression,
                                                  in_avg_lse=DUMMY_MAPCALC_STRING_AVG_LSE,
                                                  out_avg_lse=avg_lse_map,
                                                  in_delta_lse=DUMMY_MAPCALC_STRING_DELTA_LSE,
                                                  out_delta_lse=delta_lse_map,
                                                  in_cwv=DUMMY_MAPCALC_STRING_CWV,
                                                  out_cwv=cwv_map,
                                                  in_ti=DUMMY_MAPCALC_STRING_T10,
                                                  out_ti=t10,
                                                  in_tj=DUMMY_MAPCALC_STRING_T11,
                                                  out_tj=t11)
    elif emissivity_class:
        split_window_expression = replace_dummies(lst_expression,
                                                  in_cwv=DUMMY_MAPCALC_STRING_CWV,
                                                  out_cwv=cwv_map,
                                                  in_ti=DUMMY_MAPCALC_STRING_T10,
                                                  out_ti=t10,
                                                  in_tj=DUMMY_MAPCALC_STRING_T11,
                                                  out_tj=t11)
    # Convert to Celsius?
    if celsius:
        split_window_expression = '({swe}) - 273.15'.format(swe=split_window_expression)
        split_window_equation = equation.format(result=outname,
                                            expression=split_window_expression)
    else:
        split_window_equation = equation.format(result=outname,
                                            expression=split_window_expression)

    grass.mapcalc(split_window_equation, overwrite=True)

    if info:
        run('r.info', map=outname, flags='r')

    del(split_window_expression)
    del(split_window_equation)
def estimate_lst(outname, t10, t11, avg_lse_map, delta_lse_map, cwv_map, lst_expression):
    """
    Produce a Land Surface Temperature map based on a mapcalc expression
    returned from a SplitWindowLST object.

    Inputs are:

    - brightness temperature maps t10, t11
    - column water vapor map
    - a temporary filename
    - a valid mapcalc expression
    """
    msg = '\n|i Estimating land surface temperature '
    if info:
        msg += "| Expression:\n"
    g.message(msg)

    if info:
        msg = lst_expression
        msg += '\n'
        print(msg)

    # replace the "dummy" string...
    if landcover_map:
        split_window_expression = replace_dummies(lst_expression,
                                                  in_avg_lse=DUMMY_MAPCALC_STRING_AVG_LSE,
                                                  out_avg_lse=avg_lse_map,
                                                  in_delta_lse=DUMMY_MAPCALC_STRING_DELTA_LSE,
                                                  out_delta_lse=delta_lse_map,
                                                  in_cwv=DUMMY_MAPCALC_STRING_CWV,
                                                  out_cwv=cwv_map,
                                                  in_ti=DUMMY_MAPCALC_STRING_T10,
                                                  out_ti=t10,
                                                  in_tj=DUMMY_MAPCALC_STRING_T11,
                                                  out_tj=t11)
    elif emissivity_class:
        split_window_expression = replace_dummies(lst_expression,
                                                  in_cwv=DUMMY_MAPCALC_STRING_CWV,
                                                  out_cwv=cwv_map,
                                                  in_ti=DUMMY_MAPCALC_STRING_T10,
                                                  out_ti=t10,
                                                  in_tj=DUMMY_MAPCALC_STRING_T11,
                                                  out_tj=t11)
    # Convert to Celsius?
    if celsius:
        split_window_expression = '({swe}) - 273.15'.format(swe=split_window_expression)
        split_window_equation = equation.format(result=outname,
                                            expression=split_window_expression)
    else:
        split_window_equation = equation.format(result=outname,
                                            expression=split_window_expression)

    grass.mapcalc(split_window_equation, overwrite=True)

    if info:
        run('r.info', map=outname, flags='r')

    del(split_window_expression)
    del(split_window_equation)
Example #26
0
def main():
    """
    RichDEM flat resolution: give a gentle slope
    """
    # lazy import RICHDEM
    try:
        import richdem as rd
    except:
        g.message(
            flags="e",
            message=("RichDEM not detected. Install pip3 and " +
                     "then type at the command prompt: " +
                     '"pip3 install richdem".'),
        )

    _input = options["input"]
    _output = options["output"]
    _method = options["method"]
    _exponent = options["exponent"]
    _weights = options["weights"]

    if (_method == "Holmgren") or (_method == "Freeman"):
        if _exponent == "":
            g.message(
                flags="w",
                message=("Exponent must be defined for " +
                         "Holmgren or Freeman methods. " + "Exiting."),
            )
            return
        else:
            _exponent = float(_exponent)
    else:
        _exponent = None

    if _weights == "":
        rd_weights = None
    else:
        g_weights = garray.array(_weights, null=np.nan)
        rd_weights = rd.rdarray(g_weights, no_data=np.nan)

    dem = garray.array(_input, null=np.nan)

    mask = dem * 0 + 1

    rd_input = rd.rdarray(dem, no_data=np.nan)
    del dem
    rd_output = rd.FlowAccumulation(
        dem=rd_input,
        method=_method,
        exponent=_exponent,
        weights=rd_weights,
        in_place=False,
    )

    rd_output *= mask

    accum = garray.array()
    accum[:] = rd_output[:]
    accum.write(_output, overwrite=gscript.overwrite())
def estimate_cwv_big_expression(
    outname,
    cwv_output,
    t10,
    t11,
    cwv_expression,
    quiet=True,
):
    """
    Derive a column water vapor map using a single mapcalc expression based on
    eval.

            *** To Do: evaluate -- does it work correctly? *** !
    """
    msg = "\n|i Estimating atmospheric column water vapor "
    if quiet:
        msg += "| Expression:\n"
    g.message(msg)

    if quiet:
        msg = replace_dummies(cwv_expression,
                              in_ti=t10,
                              out_ti="T10",
                              in_tj=t11,
                              out_tj="T11")
        msg += "\n"
        g.message(msg)

    cwv_equation = EQUATION.format(result=outname, expression=cwv_expression)
    grass.mapcalc(cwv_equation, overwrite=True)

    if quiet:
        run("r.info", map=outname, flags="r")

    # save Column Water Vapor map?
    if cwv_output:

        # strings for metadata
        history_cwv = "FixMe -- Column Water Vapor model: "
        history_cwv += "FixMe -- Add equation?"
        title_cwv = "Column Water Vapor"
        description_cwv = "Column Water Vapor"
        units_cwv = "g/cm^2"
        source1_cwv = "FixMe"
        source2_cwv = "FixMe"

        # history entry
        run(
            "r.support",
            map=outname,
            title=title_cwv,
            units=units_cwv,
            description=description_cwv,
            source1=source1_cwv,
            source2=source2_cwv,
            history=history_cwv,
        )
        run("g.rename", raster=(outname, cwv_output))
Example #28
0
def main():
    """
    RichDEM flat resolution: give a gentle slope
    """
    # lazy import RICHDEM
    try:
        import richdem as rd
    except:
        g.message(flags='e',
                  message=('RichDEM not detected. Install pip3 and ' +
                           'then type at the command prompt: ' +
                           '"pip3 install richdem".'))

    options, flags = gscript.parser()
    _input = options['input']
    _output = options['output']
    _method = options['method']
    _exponent = options['exponent']
    _weights = options['weights']

    if (_method == 'Holmgren') or (_method == 'Freeman'):
        if _exponent == '':
            g.message(flags='w',
                      message=('Exponent must be defined for ' +
                               'Holmgren or Freeman methods. ' + 'Exiting.'))
            return
        else:
            _exponent = float(_exponent)
    else:
        _exponent = None

    if _weights == '':
        rd_weights = None
    else:
        g_weights = garray.array()
        g_weights.read(_weights, null=np.nan)
        rd_weights = rd.rdarray(g_weights, no_data=np.nan)

    dem = garray.array()
    dem.read(_input, null=np.nan)

    mask = dem * 0 + 1

    rd_input = rd.rdarray(dem, no_data=np.nan)
    del dem
    rd_output = rd.FlowAccumulation(dem=rd_input,
                                    method=_method,
                                    exponent=_exponent,
                                    weights=rd_weights,
                                    in_place=False)

    rd_output *= mask

    accum = garray.array()
    accum[:] = rd_output[:]
    accum.write(_output, overwrite=gscript.overwrite())
def hpf_ascii(center, filter, tmpfile, second_pass):
    """Exporting a High Pass Filter in a temporary ASCII file"""
    # structure informative message
    msg = "   > {m}Filter Properties: center: {c}"
    msg_pass = '******' if second_pass else ''
    msg = msg.format(m=msg_pass, c=center)
    g.message(msg, flags='v')

    # open, write and close file
    with open(tmpfile, 'w') as asciif:
        asciif.write(filter)
Example #30
0
def hpf_ascii(center, filter, tmpfile, second_pass):
    """Exporting a High Pass Filter in a temporary ASCII file"""
    # structure informative message
    msg = "   > {m}Filter Properties: center: {c}"
    msg_pass = '******' if second_pass else ''
    msg = msg.format(m=msg_pass, c=center)
    g.message(msg, flags='v')

    # open, write and close file
    with open(tmpfile, 'w') as asciif:
        asciif.write(filter)
def list_files_in_tar(tgz):
    """List files in tar.gz file"""
    g.message(_('Listing files in tar.gz file'))

    # open tar.gz file in read mode
    tar = tarfile.TarFile.open(name=tgz, mode='r')

    # get names
    members = tar.getnames()

    # print out
    g.message(_(members))
def estimate_cwv_big_expression(outname, t10, t11, cwv_expression):
    """
    Derive a column water vapor map using a single mapcalc expression based on
    eval.

            *** To Do: evaluate -- does it work correctly? *** !
    """
    msg = "\n|i Estimating atmospheric column water vapor "
    if info:
        msg += '| Expression:\n'
    g.message(msg)

    if info:
        msg = replace_dummies(cwv_expression,
                              in_ti=t10,
                              out_ti='T10',
                              in_tj=t11,
                              out_tj='T11')
        msg += '\n'
        print msg

    cwv_equation = equation.format(result=outname, expression=cwv_expression)
    grass.mapcalc(cwv_equation, overwrite=True)

    if info:
        run('r.info', map=outname, flags='r')

    # save Column Water Vapor map?
    if cwv_output:

        # strings for metadata
        history_cwv = 'FixMe -- Column Water Vapor model: '
        history_cwv += 'FixMe -- Add equation?'
        title_cwv = 'Column Water Vapor'
        description_cwv = 'Column Water Vapor'
        units_cwv = 'g/cm^2'
        source1_cwv = 'FixMe'
        source2_cwv = 'FixMe'

        # history entry
        run("r.support",
            map=outname,
            title=title_cwv,
            units=units_cwv,
            description=description_cwv,
            source1=source1_cwv,
            source2=source2_cwv,
            history=history_cwv)

        run('g.rename', raster=(outname, cwv_output))

    del (cwv_expression)
    del (cwv_equation)
Example #33
0
def unlink_directory(directory, elements_to_unlink, dry_run=True, force=False):
    """
    """
    if (pathlib.PurePosixPath(directory).joinpath('r.InternalLink')
            in pathlib.Path(directory).glob('**/r.InternalLink')):
        if not os.path.islink(directory):
            if not force:
                review_unlinking_directory = MESSAGE_REVIEW_UNLINKING_DIRECTORY.format(
                    directory=directory)
                g.message(review_unlinking_directory, flags='w')
                g.message('\n')
            elements_to_unlink.append(directory)
Example #34
0
def list_files_in_tar(tgz):
    """List files in tar.gz file"""
    compressed_scene = os.path.basename(tgz)
    g.message(_(f'Reading compressed scene \'{compressed_scene}\'...'))
    tar = tarfile.TarFile.open(name=tgz, mode='r')
    members = tar.getnames()
    members = """
    {}
    """.format('\n'.join(members[1:]))
    index_of_dot = compressed_scene.index('.')
    scene = compressed_scene[:index_of_dot]
    message = f'List of files in {scene}'
    message += members
    g.message(_(message))
def hpf_weight(low_sd, hpf_sd, mod, pss):
    """Returning an appropriate weighting value for the
    High Pass Filtered image. The required inputs are:
    - low_sd:   StdDev of Low resolution image
    - hpf_sd:   StdDev of High Pass Filtered image
    - mod:      Appropriate Modulating Factor determining image crispness
    - pss:      Number of Pass (1st or 2nd)"""
    wgt = low_sd / hpf_sd * mod  # mod: modulator
    msg = '   >> '
    if pss == 2:
        msg += '2nd Pass '
    msg += 'Weighting = {l:.{dec}f} / {h:.{dec}f} * {m:.{dec}f} = {w:.{dec}f}'
    msg = msg.format(l=low_sd, h=hpf_sd, m=mod, w=wgt, dec=3)
    g.message(msg, flags='v')
    return wgt
Example #36
0
def hpf_weight(low_sd, hpf_sd, mod, pss):
    """Returning an appropriate weighting value for the
    High Pass Filtered image. The required inputs are:
    - low_sd:   StdDev of Low resolution image
    - hpf_sd:   StdDev of High Pass Filtered image
    - mod:      Appropriate Modulating Factor determining image crispness
    - pss:      Number of Pass (1st or 2nd)"""
    wgt = low_sd / hpf_sd * mod  # mod: modulator
    msg = '   >> '
    if pss == 2:
        msg += '2nd Pass '
    msg += 'Weighting = {l:.{dec}f} / {h:.{dec}f} * {m:.{dec}f} = {w:.{dec}f}'
    msg = msg.format(l=low_sd, h=hpf_sd, m=mod, w=wgt, dec=3)
    g.message(msg, flags='v')
    return wgt
Example #37
0
def remove_temporary_maps(save_temporary_maps=False):
    """Clean up temporary maps"""
    # options, flags = grass.parser()
    # if not flags['s']:  # 's' for save temporary maps
    if not save_temporary_maps:
        g.message("Removing temporary maps")
        g.remove(
            flags="f",
            type="raster",
            pattern="tmp.{pid}*".format(pid=os.getpid()),
            quiet=True,
        )
    else:
        msg = "I will not remove temporary maps in order to support your debugging!"
        msg += "Take care to remove them, i.e. via `g.remove raster pattern=tmp.*`"
        grass.warning(_(msg))
def estimate_cwv_big_expression(outname, t10, t11, cwv_expression):
    """
    Derive a column water vapor map using a single mapcalc expression based on
    eval.

            *** To Do: evaluate -- does it work correctly? *** !
    """
    msg = "\n|i Estimating atmospheric column water vapor "
    if info:
        msg += '| Expression:\n'
    g.message(msg)

    if info:
        msg = replace_dummies(cwv_expression,
                              in_ti=t10, out_ti='T10',
                              in_tj=t11, out_tj='T11')
        msg += '\n'
        print msg

    cwv_equation = equation.format(result=outname, expression=cwv_expression)
    grass.mapcalc(cwv_equation, overwrite=True)

    if info:
        run('r.info', map=outname, flags='r')

    # save Column Water Vapor map?
    if cwv_output:

        # strings for metadata
        history_cwv = 'FixMe -- Column Water Vapor model: '
        history_cwv += 'FixMe -- Add equation?'
        title_cwv = 'Column Water Vapor'
        description_cwv = 'Column Water Vapor'
        units_cwv = 'g/cm^2'
        source1_cwv = 'FixMe'
        source2_cwv = 'FixMe'

        # history entry
        run("r.support", map=outname, title=title_cwv,
            units=units_cwv, description=description_cwv,
            source1=source1_cwv, source2=source2_cwv,
            history=history_cwv)

        run('g.rename', raster=(outname, cwv_output))

    del(cwv_expression)
    del(cwv_equation)
def print_timestamp(scene, timestamp, tgis=False):
    """
    Print out the timestamp
    """
    date = timestamp['date']
    date_Ymd = datetime.strptime(date, "%Y-%m-%d")
    date_tgis = datetime.strftime(date_Ymd, "%d %b %Y")

    hours = str(timestamp['hours'])
    minutes = str(timestamp['minutes'])
    seconds = str(timestamp['seconds'])
    timezone = timestamp['timezone']

    time = ':'.join((hours, minutes, seconds))
    string_parse_time = "%H:%M:%S"
    if '.' not in time:
        time += '.000000'
    if '.' in time:
        string_parse_time += ".%f"
    time = datetime.strptime(time, string_parse_time)
    time = datetime.strftime(time, string_parse_time)

    message = 'Date\t\tTime\n'
    message += '\t{date}\t{time} {timezone}\n\n'

    # if -t requested
    if tgis:

        # verbose if -t instructed
        os.environ['GRASS_VERBOSE'] = GRASS_VERBOSITY_LELVEL_3

        # timezone = timezone.replace('+', '')
        prefix = '<Prefix>'
        if prefix:
            prefix = options['prefix']
        # message = '{p}{s}|{d} {t} {tz}'.format(s=scene, p=prefix, d=date, t=time, tz=timezone)
        message = '{p}{s}|{d} {t}'.format(s=scene, p=prefix, d=date_tgis, t=time)

        # add to timestamps
        if tgis_output:
            global timestamps
            timestamps.append(message)

    if not tgis:
        message = message.format(date=date, time=time, timezone=timezone)
    g.message(_(message))
Example #40
0
def remove_temporary_maps():
    """Clean up temporary maps"""

    # get list of temporary maps
    # temporary_raster_maps = grass.list_strings(
    #     type="raster", pattern="tmp.{pid}*".format(pid=os.getpid())
    # )

    # # remove temporary maps
    # if temporary_raster_maps:
    g.message("Removing temporary maps")
    g.remove(
        flags="f",
        type="raster",
        pattern="tmp.{pid}*".format(pid=os.getpid()),
        quiet=True,
    )
def kelvin_to_celsius(outname, lst_map):
    """
    Convert Kelvin to Celsius
    """
    msg = '\n|i Converting LST output from Kelvin to Celsius degrees'
    #g.message(msg)

    kelvin_to_celsius_expression = '{lst} - 273.15'.format(lst=lst_map)
    kelvin_to_celsius_equation = equation.format(result=lst_map,
            expression=kelvin_to_celsius_expression)
    grass.mapcalc(kelvin_to_celsius_equation, overwrite=True)

    msg += '\n|i Applying the "Celsius" color table'
    g.message(msg)
    run('r.colors', map=lst_map, color='celsius')

    del(kelvin_to_celsius_expression)
    del(kelvin_to_celsius_equation)
Example #42
0
def link_to_target(target, link, dry_run=True, softlinking='', relative=False):
    """
    This function creates the requested 'link' to the 'target' file.
    This function does not return anything.

    Parameters
    ----------
    target :
        The target file to link to

    link :
        The link file to create

    dry_run :
        A boolean flag on whether to actually perform the linking or not

    softlinking :
        An empty string or the '-s' string passed to the actual command's
        'flags' option to define whether linking softly or not.

    relative :
        A boolean flag to define whether to create relative links
    """
    linking_message = MESSAGE_LINKING
    if softlinking:
        linking_message = MESSAGE_SOFT_LINKING
        if relative:
            linking_message = MESSAGE_RELATIVE_LINKING
    g.message(
        linking_message.format(target=target, link=link),
        flags='v',
    )
    if not dry_run:
        flags = ''
        if softlinking:
            flags += '-s'
            if relative:
                flags += 'r'
        command = f'ln {flags} {target} {link}'
        command = shlex.split(command)
        try:
            subprocess.run(command)
        except subprocess.CalledProcessError as e:
            grass.fatal(e.output)
Example #43
0
def digital_numbers_to_radiance(
    outname,
    band,
    radiance_expression,
    null=False,
    info=False,
):
    """
    Convert Digital Number values to TOA Radiance. For details, see in Landsat8
    class.  Zero (0) DNs set to NULL here (not via the class' function).
    """
    if null:
        msg = f'\n|i Setting zero (0) Digital Numbers in {band} to NULL'
        g.message(msg)
        run(
            'r.null',
            map=band,
            setnull=0,
        )

    msg = f'\n|i Rescaling {band} digital numbers to spectral radiance'

    if info:
        msg += f'\n   {radiance_expression}'

    g.message(msg)
    radiance_expression = replace_dummies(
        radiance_expression,
        instring=DUMMY_MAPCALC_STRING_DN,
        outstring=band,
    )
    radiance_equation = EQUATION.format(
        result=outname,
        expression=radiance_expression,
    )
    grass.mapcalc(radiance_equation, overwrite=True)

    if info:
        run(
            'r.info',
            map=outname,
            flags='r',
        )
Example #44
0
def hpf_weight(lo_sd, hpf_sd, mod, pss):
    """Returning an appropriate weighting value for the
    High Pass Filtered image. The required inputs are:
    - StdDev of Low resolution image
    - StdDev of High Pass Filtered image
    - Appropriate Modulating Factor determining image crispness
    - Number of Pass (1st or 2nd)"""
    if pss == 1:
        wgt = lo_sd / hpf_sd * mod  # mod: modulator
        msg = "   >> Weighting = %.2f / %.2f * %.2f = %.2f" % \
            (lo_sd, hpf_sd, mod, wgt)
        g.message(msg, flags='v')

    if pss == 2:
        wgt = lo_sd / hpf_sd * mod  # mod: modulator
        msg = "   >> 2nd Pass Weighting = %.3f / %.3f * %.3f = %.3f" % \
            (lo_sd, hpf_sd, mod, wgt)
        g.message(msg, flags='v')

    return wgt
Example #45
0
def main():

    method    = options['method']  # algorithm for speckle removal
    img       = options['input']   # name of input image
    img_out   = options['output']  # name of output image 
    size      = options['size']    # size of neighborhood

    out = grass.core.find_file(img_out)

    if (out['name'] != '') and not grass.overwrite():
        grass.warning(_('Output map name already exists. '
                        'Delete it or use overwrite flag'))

    if method == 'lee':
        g.message(_('Applying Lee Filter'))
        img_out = lee_filter(img, size, img_out)
        g.message(_('Done.'))
        
    else:
        grass.fatal(_("The requested speckle filter is not yet implemented."))
Example #46
0
def extract_tgz(tgz):
    """
    Decompress and unpack a .tgz file
    """
    tar = tarfile.TarFile.open(name=tgz, mode='r')
    tgz_base = os.path.basename(tgz).split('.tar.gz')[0]

    # try to create a directory with the scene's (base)name
    # source: <http://stackoverflow.com/a/14364249/1172302>
    try:
        os.makedirs(tgz_base)

    except OSError:
        if not os.path.isdir(tgz_base):
            raise

    # extract files indide the scene directory
    compressed_scene = os.path.basename(tgz)
    g.message(_(f'Extracting files from compressed_scene {compressed_scene}'))
    tar.extractall(path=tgz_base)
Example #47
0
def hpf_ascii(center, filter, tmpfile, pss):
    """Exporting a High Pass Filter in a temporary ASCII file"""
    if pss == 1:
        global modulator
        modulator = filter.modulator
        msg_ps2 = ''

    elif pss == 2:
        global modulator_2
        modulator_2 = filter.modulator_2
        msg_ps2 = '2nd Pass '

    # structure informative message
    msg = "   > %sFilter Properties: size: %s, center: %s" % \
        (msg_ps2, filter.size, center)
    g.message(msg, flags='v')

    # open, write and close file
    asciif = open(tmpfile, 'w')
    asciif.write(filter.filter)
    asciif.close()
Example #48
0
def main():

    method = options["method"]  # algorithm for speckle removal
    img = options["input"]  # name of input image
    img_out = options["output"]  # name of output image
    size = options["size"]  # size of neighborhood

    out = grass.core.find_file(img_out)

    if (out["name"] != "") and not grass.overwrite():
        grass.warning(
            _("Output map name already exists. "
              "Delete it or use overwrite flag"))

    if method == "lee":
        g.message(_("Applying Lee Filter"))
        img_out = lee_filter(img, size, img_out)
        g.message(_("Done."))

    else:
        grass.fatal(_("The requested speckle filter is not yet implemented."))
def get_cwv_window_means(outname, t1x, t1x_mean_expression):
    """

    ***
    This function is NOT used.  It was part of an initial step-by-step approach,
    while coding and testing.  Kept for future plans!?
    ***

    Get window means for T1x
    """
    msg = ('\n |i Deriving window means from {Tx} ')
    msg += ('using the expression:\n {exp}')
    msg = msg.format(Tx=t1x, exp=t1x_mean_expression)
    g.message(msg)

    tx_mean_equation = equation.format(result=outname,
                                       expression=t1x_mean_expression)
    grass.mapcalc(tx_mean_equation, overwrite=True)

    if info:
        run('r.info', map=outname, flags='r')

    del(t1x_mean_expression)
    del(tx_mean_equation)
def copy_mtl_in_cell_misc(scene, mapset, tgis, copy_mtl=True) :
    """
    Copies the *MTL.txt metadata file in the cell_misc directory inside
    the Landsat scene's independent Mapset or in else the requested single
    Mapset
    """

    if one_mapset:
        mapset = mapset

    path_to_cell_misc = get_path_to_cell_misc(mapset)

    if is_mtl_in_cell_misc(mapset):
        message = HORIZONTAL_LINE
        message += ' MTL exists in: {d}\n'.format(d=path_to_cell_misc)
        message += HORIZONTAL_LINE
        g.message(_(message))
        pass

    else:

        if copy_mtl:

            metafile = get_metafile(scene, tgis)

            # copy the metadata file -- Better: check if really copied!
            message = HORIZONTAL_LINE
            message += ' MTL file copied at <{directory}>.'
            message = message.format(directory=path_to_cell_misc)
            g.message(_(message))
            shutil.copy(metafile, path_to_cell_misc)

        else:
            message = HORIZONTAL_LINE
            message += ' MTL not transferred to {m}/cell_misc'.format(m=scene)
            g.message(_(message))
def main():

    global acq_time, esd

    """1st, get input, output, options and flags"""

    spectral_bands = options['band'].split(',')
    outputsuffix = options['outputsuffix']
    utc = options['utc']
    doy = options['doy']
    sea = options['sea']

    radiance = flags['r']
    if radiance and outputsuffix == 'toar':
        outputsuffix = 'rad'
        g.message("Output-suffix set to %s" % outputsuffix)

    keep_region = flags['k']
    info = flags['i']

    # -----------------------------------------------------------------------
    # Equations
    # -----------------------------------------------------------------------

    if info:
        # conversion to Radiance based on (1)
        msg = "|i Spectral Radiance = K * DN / Effective Bandwidth | " \
              "Reflectance = ( Pi * Radiance * ESD^2 ) / BAND_Esun * cos(SZA)"
        g.message(msg)

    # -----------------------------------------------------------------------
    # List images and their properties
    # -----------------------------------------------------------------------

    mapset = grass.gisenv()['MAPSET']  # Current Mapset?

#    imglst = [pan]
#    imglst.extend(msxlst)  # List of input imagery

    images = {}
    for img in spectral_bands:  # Retrieving Image Info
        images[img] = Info(img, mapset)
        images[img].read()

    # -----------------------------------------------------------------------
    # Temporary Region and Files
    # -----------------------------------------------------------------------

    if not keep_region:
        grass.use_temp_region()  # to safely modify the region
    tmpfile = grass.tempfile()  # Temporary file - replace with os.getpid?
    tmp = "tmp." + grass.basename(tmpfile)  # use its basename

    # -----------------------------------------------------------------------
    # Global Metadata: Earth-Sun distance, Sun Zenith Angle
    # -----------------------------------------------------------------------

    # Earth-Sun distance
    if doy:
        g.message("|! Using Day of Year to calculate Earth-Sun distance.")
        esd = jd_to_esd(int(doy))

    elif (not doy) and utc:
        acq_utc = AcquisitionTime(utc)  # will hold esd (earth-sun distance)
        esd = acq_utc.esd

    else:
        grass.fatal(_("Either the UTC string or "
                      "the Day-of-Year (doy) are required!"))

    sza = 90 - float(sea)  # Sun Zenith Angle based on Sun Elevation Angle

    # -----------------------------------------------------------------------
    # Loop processing over all bands
    # -----------------------------------------------------------------------
    for band in spectral_bands:

        global tmp_rad

        # -------------------------------------------------------------------
        # Match bands region if... ?
        # -------------------------------------------------------------------

        if not keep_region:
            run('g.region', rast=band)   # ## FixMe?
            msg = "\n|! Region matching the %s spectral band" % band
            g.message(msg)

        elif keep_region:
            msg = "|! Operating on current region"
            g.message(msg)

        # -------------------------------------------------------------------
        # Band dependent metadata for Spectral Radiance
        # -------------------------------------------------------------------

        g.message("\n|* Processing the %s band" % band, flags='i')

        # Why is this necessary?  Any function to remove the mapsets name?
        if '@' in band:
            band = (band.split('@')[0])

        # get absolute calibration factor
        acf = float(CF_BW_ESUN[band][2])
        acf_msg = "K=" + str(acf)

        # effective bandwidth
        bw = float(CF_BW_ESUN[band][0])

        # -------------------------------------------------------------------
        # Converting to Spectral Radiance
        # -------------------------------------------------------------------

        msg = "\n|> Converting to Spectral Radiance " \
              "| Conversion Factor %s, Bandwidth=%.3f" % (acf_msg, bw)
        g.message(msg)

        # convert
        tmp_rad = "%s.Radiance" % tmp  # Temporary Map
        rad = "%s = %f * %s / %f" \
            % (tmp_rad, acf, band, bw)  # Attention: 32-bit calculations requ.
        grass.mapcalc(rad, overwrite=True)

        # strings for metadata
        history_rad = rad
        history_rad += "Conversion Factor=%f; Effective Bandwidth=%.3f" \
            % (acf, bw)
        title_rad = ""
        description_rad = "Top-of-Atmosphere %s band spectral Radiance " \
                          "[W/m^2/sr/μm]" % band
        units_rad = "W / sq.m. / μm / ster"

        if not radiance:

            # ---------------------------------------------------------------
            # Converting to Top-of-Atmosphere Reflectance
            # ---------------------------------------------------------------

            global tmp_toar

            msg = "\n|> Converting to Top-of-Atmosphere Reflectance"
            g.message(msg)

            esun = float(CF_BW_ESUN[band][1])
            msg = "   %s band mean solar exoatmospheric irradiance=%.2f" \
                % (band, esun)
            g.message(msg)

            # convert
            tmp_toar = "%s.Reflectance" % tmp  # Spectral Reflectance
            toar = "%s = %f * %s * %f^2 / %f * cos(%f)" \
                % (tmp_toar, math.pi, tmp_rad, esd, esun, sza)
            grass.mapcalc(toar, overwrite=True)

            # report range? Using a flag and skip actual conversion?
            # todo?

            # strings for metadata
            title_toar = "%s band (Top of Atmosphere Reflectance)" % band
            description_toar = "Top of Atmosphere %s band spectral Reflectance" \
                % band
            units_toar = "Unitless planetary reflectance"
            history_toar = "K=%f; Bandwidth=%.1f; ESD=%f; Esun=%.2f; SZA=%.1f" \
                % (acf, bw, esd, esun, sza)

        if tmp_toar:

            # history entry
            run("r.support", map=tmp_toar, title=title_toar,
                units=units_toar, description=description_toar,
                source1=source1_toar, source2=source2_toar,
                history=history_toar)

            # add suffix to basename & rename end product
            toar_name = ("%s.%s" % (band.split('@')[0], outputsuffix))
            run("g.rename", rast=(tmp_toar, toar_name))

        elif tmp_rad:

            # history entry
            run("r.support", map=tmp_rad,
                title=title_rad, units=units_rad, description=description_rad,
                source1=source1_rad, source2=source2_rad, history=history_rad)

            # add suffix to basename & rename end product
            rad_name = ("%s.%s" % (band.split('@')[0], outputsuffix))
            run("g.rename", rast=(tmp_rad, rad_name))

    # visualising-related information
    if not keep_region:
        grass.del_temp_region()  # restoring previous region settings
    g.message("\n|! Region's resolution restored!")
    g.message("\n>>> Hint: rebalancing colors "
              "(i.colors.enhance) may improve appearance of RGB composites!",
              flags='i')
def main():

    global acq_time, esd
    """1st, get input, output, options and flags"""

    spectral_bands = options['band'].split(',')
    outputsuffix = options['outputsuffix']
    utc = options['utc']
    doy = options['doy']
    sea = options['sea']

    radiance = flags['r']
    keep_region = flags['k']

#    mapset = grass.gisenv()['MAPSET']  # Current Mapset?
#    imglst = [spectral_bands]
#    images = {}
#    for img in imglst:  # Retrieving Image Info
#        images[img] = Info(img, mapset)
#        images[img].read()

    # -----------------------------------------------------------------------
    # Temporary Region and Files
    # -----------------------------------------------------------------------

    if not keep_region:
        grass.use_temp_region()  # to safely modify the region
    tmpfile = grass.tempfile()  # Temporary file - replace with os.getpid?
    tmp = "tmp." + grass.basename(tmpfile)  # use its basename

    # -----------------------------------------------------------------------
    # Global Metadata: Earth-Sun distance, Sun Zenith Angle
    # -----------------------------------------------------------------------

    # Earth-Sun distance
    if doy:
        esd = jd_to_esd(int(doy))

    elif utc:
        acq_utc = AcquisitionTime(utc)  # will hold esd (earth-sun distance)
        acq_dat = datetime(acq_utc.year, acq_utc.month, acq_utc.day)
        esd = acq_utc.esd

    else:
        grass.fatal(_("Either the UTC string or "
                      "the Day-of-Year (doy) are required!"))

    sza = 90 - float(sea)  # Sun Zenith Angle based on Sun Elevation Angle

    # -----------------------------------------------------------------------
    # Loop processing over all bands
    # -----------------------------------------------------------------------
    for band in spectral_bands:

        global tmp_rad

        g.message("|* Processing the %s spectral band" % band, flags='i')

        if not keep_region:
            g.message("\n|! Matching region to %s" % band)  # set region
            run('g.region', rast=band)   # ## FixMe

        # -------------------------------------------------------------------
        # Converting to Spectral Radiance
        # -------------------------------------------------------------------

        msg = "\n|> Converting to Spectral Radiance: " \
#            "L(λ) = 10^4 x DN(λ) / CalCoef(λ) x Bandwidth(λ)"  # Unicode? ##
        g.message(msg)

        # -------------------------------------------------------------------
        # Band dependent metadata for Spectral Radiance
        # -------------------------------------------------------------------

        # Why is this necessary?  Any function to remove the mapsets name?
        if '@' in band:
            band_key = (band.split('@')[0])
        else:
            band_key = band

        # get coefficients
        if acq_dat < cc_update:
            g.message("\n|! Using Pre-2001 Calibration Coefficient values",
                      flags='i')
            cc = float(CC[band_key][0])
        else:
            cc = float(CC[band_key][1])

        # get bandwidth
        bw = float(CC[band_key][2])

        # inform
        msg = "   [Calibration Coefficient=%d, Bandwidth=%.1f]" \
            % (cc, bw)
        g.message(msg)

        # convert
        tmp_rad = "%s.Radiance" % tmp  # Temporary Map
        rad = "%s = 10^4 * %s / %f * %f" \
            % (tmp_rad, band, cc, bw)
        grass.mapcalc(rad, overwrite=True)

        # string for metadata
        history_rad = rad
        history_rad += "Calibration Coefficient=%d; Effective Bandwidth=%.1f" \
            % (cc, bw)
        title_rad = "%s band (Spectral Radiance)" % band
        units_rad = "W / m2 / μm / ster"
        description_rad = "At-sensor %s band spectral Radiance (W/m2/μm/sr)" \
            % band

        if not radiance:

            # ---------------------------------------------------------------
            # Converting to Top-of-Atmosphere Reflectance
            # ---------------------------------------------------------------

            global tmp_toar

            msg = "\n|> Converting to Top-of-Atmosphere Reflectance" \
                  # "ρ(p) = π x L(λ) x d^2 / ESUN(λ) x cos(θ(S))"  # Unicode?
            g.message(msg)

            # ---------------------------------------------------------------
            # Band dependent metadata for Spectral Radiance
            # ---------------------------------------------------------------

            # get esun
            esun = CC[band_key][3]

            # inform
            msg = "   [Earth-Sun distane=%f, Mean solar exoatmospheric " \
                "irradiance=%.1f]" % (esd, esun)
            g.message(msg)

            # convert
            tmp_toar = "%s.Reflectance" % tmp  # Spectral Reflectance
            toar = "%s = %f * %s * %f^2 / %f * cos(%f)" \
                % (tmp_toar, math.pi, tmp_rad, esd, esun, sza)
            grass.mapcalc(toar, overwrite=True)

            # strings for output's metadata
            history_toar = toar
            history_toar += "ESD=%f; BAND_Esun=%f; SZA=%f" % (esd, esun, sza)
            title_toar = "%s band (Top of Atmosphere Reflectance)" % band
            units_toar = "Unitless planetary reflectance"
            description_toar = "Top of Atmosphere `echo ${BAND}` band spectral"
            " Reflectance (unitless)"

        if tmp_toar:

            # history entry
            run("r.support", map=tmp_toar, title=title_toar,
                units=units_toar, description=description_toar,
                source1=source1_toar, source2=source2_toar,
                history=history_toar)

            # add suffix to basename & rename end product
            toar_name = ("%s.%s" % (band.split('@')[0], outputsuffix))
            run("g.rename", rast=(tmp_toar, toar_name))

        elif tmp_rad:

            # history entry
            run("r.support", map=tmp_rad,
                title=title_rad, units=units_rad, description=description_rad,
                source1=source1_rad, source2=source2_rad, history=history_rad)

            # add suffix to basename & rename end product
            rad_name = ("%s.%s" % (band.split('@')[0], outputsuffix))
            run("g.rename", rast=(tmp_rad, rad_name))

    # visualising-related information
    if not keep_region:
        grass.del_temp_region()  # restoring previous region settings
    g.message("\n|! Region's resolution restored!")
    g.message("\n>>> Hint: rebalancing colors "
              "(i.colors.enhance) may improve appearance of RGB composites!",
              flags='i')
def main():

    pan = options['pan']
    msxlst = options['msx'].split(',')
    outputsuffix = options['suffix']
    custom_ratio = options['ratio']
    center = options['center']
    center2 = options['center2']
    modulation = options['modulation']
    modulation2 = options['modulation2']

    if options['trim']:
        trimming_factor = float(options['trim'])
    else:
        trimming_factor = False

    histogram_match = flags['l']
    second_pass = flags['2']
    color_match = flags['c']

#    # Check & warn user about "ns == ew" resolution of current region ======
#    region = grass.region()
#    nsr = region['nsres']
#    ewr = region['ewres']
#
#    if nsr != ewr:
#        msg = ('>>> Region's North:South ({ns}) and East:West ({ew}) '
#               'resolutions do not match!')
#        msg = msg.format(ns=nsr, ew=ewr)
#        g.message(msg, flags='w')

    mapset = grass.gisenv()['MAPSET']  # Current Mapset?
    region = grass.region()  # and region settings

    # List images and their properties

    imglst = [pan]
    imglst.extend(msxlst)  # List of input imagery

    images = {}
    for img in imglst:  # Retrieving Image Info
        images[img] = Info(img, mapset)
        images[img].read()

    panres = images[pan].nsres  # Panchromatic resolution

    grass.use_temp_region()  # to safely modify the region
    run('g.region', res=panres)  # Respect extent, change resolution
    g.message("|! Region's resolution matched to Pan's ({p})".format(p=panres))

    # Loop Algorithm over Multi-Spectral images

    for msx in msxlst:
        g.message("\nProcessing image: {m}".format(m=msx))

        # Tracking command history -- Why don't do this all r.* modules?
        cmd_history = []

        #
        # 1. Compute Ratio
        #

        g.message("\n|1 Determining ratio of low to high resolution")

        # Custom Ratio? Skip standard computation method.
        if custom_ratio:
            ratio = float(custom_ratio)
            g.message('Using custom ratio, overriding standard method!',
                      flags='w')

        # Multi-Spectral resolution(s), multiple
        else:
            # Image resolutions
            g.message("   > Retrieving image resolutions")

            msxres = images[msx].nsres

            # check
            if panres == msxres:
                msg = ("The Panchromatic's image resolution ({pr}) "
                       "equals to the Multi-Spectral's one ({mr}). "
                       "Something is probably not right! "
                       "Please check your input images.")
                msg = msg.format(pr=panres, mr=msxres)
                grass.fatal(_(msg))

            # compute ratio
            ratio = msxres / panres
            msg_ratio = ('   >> Resolution ratio '
                         'low ({m:.{dec}f}) to high ({p:.{dec}f}): {r:.1f}')
            msg_ratio = msg_ratio.format(m=msxres, p=panres, r=ratio, dec=3)
            g.message(msg_ratio)

        # 2nd Pass requested, yet Ratio < 5.5
        if second_pass and ratio < 5.5:
            g.message("   >>> Resolution ratio < 5.5, skipping 2nd pass.\n"
                      "   >>> If you insist, force it via the <ratio> option!",
                      flags='i')
            second_pass = bool(0)

        #
        # 2. High Pass Filtering
        #

        g.message('\n|2 High Pass Filtering the Panchromatic Image')

        tmpfile = grass.tempfile()  # Temporary file - replace with os.getpid?
        tmp = 'tmp.' + grass.basename(tmpfile)  # use its basenam
        tmp_pan_hpf = '{tmp}_pan_hpf'.format(tmp=tmp)  # HPF image
        tmp_msx_blnr = '{tmp}_msx_blnr'.format(tmp=tmp)  # Upsampled MSx
        tmp_msx_hpf = '{tmp}_msx_hpf'.format(tmp=tmp)  # Fused image
        tmp_hpf_matrix = grass.tempfile()  # ASCII filter

        # Construct and apply Filter
        hpf = get_high_pass_filter(ratio, center)
        hpf_ascii(center, hpf, tmp_hpf_matrix, second_pass)
        run('r.mfilter', input=pan, filter=tmp_hpf_matrix,
            output=tmp_pan_hpf,
            title='High Pass Filtered Panchromatic image',
            overwrite=True)

        # 2nd pass
        if second_pass and ratio > 5.5:
            # Temporary files
            tmp_pan_hpf_2 = '{tmp}_pan_hpf_2'.format(tmp=tmp)  # 2nd Pass HPF image
            tmp_hpf_matrix_2 = grass.tempfile()  # 2nd Pass ASCII filter
            # Construct and apply 2nd Filter
            hpf_2 = get_high_pass_filter(ratio, center2)
            hpf_ascii(center2, hpf_2, tmp_hpf_matrix_2, second_pass)
            run('r.mfilter',
                input=pan,
                filter=tmp_hpf_matrix_2,
                output=tmp_pan_hpf_2,
                title='2-High-Pass Filtered Panchromatic Image',
                overwrite=True)

        #
        # 3. Upsampling low resolution image
        #

        g.message("\n|3 Upsampling (bilinearly) low resolution image")

        run('r.resamp.interp',
            method='bilinear', input=msx, output=tmp_msx_blnr, overwrite=True)

        #
        # 4. Weighting the High Pass Filtered image(s)
        #

        g.message("\n|4 Weighting the High-Pass-Filtered image (HPFi)")

        # Compute (1st Pass) Weighting
        msg_w = "   > Weighting = StdDev(MSx) / StdDev(HPFi) * " \
            "Modulating Factor"
        g.message(msg_w)

        # StdDev of Multi-Spectral Image(s)
        msx_avg = avg(msx)
        msx_sd = stddev(msx)
        g.message("   >> StdDev of <{m}>: {sd:.3f}".format(m=msx, sd=msx_sd))

        # StdDev of HPF Image
        hpf_sd = stddev(tmp_pan_hpf)
        g.message("   >> StdDev of HPFi: {sd:.3f}".format(sd=hpf_sd))

        # Modulating factor
        modulator = get_modulator_factor(modulation, ratio)
        g.message("   >> Modulating Factor: {m:.2f}".format(m=modulator))

        # weighting HPFi
        weighting = hpf_weight(msx_sd, hpf_sd, modulator, 1)

        #
        # 5. Adding weighted HPF image to upsampled Multi-Spectral band
        #

        g.message("\n|5 Adding weighted HPFi to upsampled image")
        fusion = '{hpf} = {msx} + {pan} * {wgt}'
        fusion = fusion.format(hpf=tmp_msx_hpf, msx=tmp_msx_blnr,
                               pan=tmp_pan_hpf, wgt=weighting)
        grass.mapcalc(fusion)

        # command history
        hst = 'Weigthing applied: {msd:.3f} / {hsd:.3f} * {mod:.3f}'
        cmd_history.append(hst.format(msd=msx_sd, hsd=hpf_sd, mod=modulator))

        if second_pass and ratio > 5.5:

            #
            # 4+ 2nd Pass Weighting the High Pass Filtered image
            #

            g.message("\n|4+ 2nd Pass Weighting the HPFi")

            # StdDev of HPF Image #2
            hpf_2_sd = stddev(tmp_pan_hpf_2)
            g.message("   >> StdDev of 2nd HPFi: {h:.3f}".format(h=hpf_2_sd))

            # Modulating factor #2
            modulator_2 = get_modulator_factor2(modulation2)
            msg = '   >> 2nd Pass Modulating Factor: {m:.2f}'
            g.message(msg.format(m=modulator_2))

            # 2nd Pass weighting
            weighting_2 = hpf_weight(msx_sd, hpf_2_sd, modulator_2, 2)

            #
            # 5+ Adding weighted HPF image to upsampled Multi-Spectral band
            #

            g.message("\n|5+ Adding small-kernel-based weighted 2nd HPFi "
                      "back to fused image")

            add_back = '{final} = {msx_hpf} + {pan_hpf} * {wgt}'
            add_back = add_back.format(final=tmp_msx_hpf, msx_hpf=tmp_msx_hpf,
                                       pan_hpf=tmp_pan_hpf_2, wgt=weighting_2)
            grass.mapcalc(add_back)

            # 2nd Pass history entry
            hst = "2nd Pass Weighting: {m:.3f} / {h:.3f} * {mod:.3f}"
            cmd_history.append(hst.format(m=msx_sd, h=hpf_2_sd, mod=modulator_2))

        if color_match:
            g.message("\n|* Matching output to input color table")
            run('r.colors', map=tmp_msx_hpf, raster=msx)

        #
        # 6. Stretching linearly the HPF-Sharpened image(s) to match the Mean
        #     and Standard Deviation of the input Multi-Sectral image(s)
        #

        if histogram_match:

            # adapt output StdDev and Mean to the input(ted) ones
            g.message("\n|+ Matching histogram of Pansharpened image "
                      "to %s" % (msx), flags='v')

            # Collect stats for linear histogram matching
            msx_hpf_avg = avg(tmp_msx_hpf)
            msx_hpf_sd = stddev(tmp_msx_hpf)

            # expression for mapcalc
            lhm = '{out} = ({hpf} - {hpfavg}) / {hpfsd} * {msxsd} + {msxavg}'
            lhm = lhm.format(out=tmp_msx_hpf, hpf=tmp_msx_hpf,
                             hpfavg=msx_hpf_avg, hpfsd=msx_hpf_sd,
                             msxsd=msx_sd, msxavg=msx_avg)

            # compute
            grass.mapcalc(lhm, quiet=True, overwrite=True)

            # update history string
            cmd_history.append("Linear Histogram Matching: %s" % lhm)

        #
        # Optional. Trim to remove black border effect (rectangular only)
        #

        if trimming_factor:

            tf = trimming_factor

            # communicate
            msg = '\n|* Trimming output image border pixels by '
            msg += '{factor} times the low resolution\n'.format(factor=tf)
            nsew = '   > Input extent: n: {n}, s: {s}, e: {e}, w: {w}'
            nsew = nsew.format(n=region.n, s=region.s, e=region.e, w=region.w)
            msg += nsew

            g.message(msg)

            # re-set borders
            region.n -= tf * images[msx].nsres
            region.s += tf * images[msx].nsres
            region.e -= tf * images[msx].ewres
            region.w += tf * images[msx].ewres

            # communicate and act
            msg = '   > Output extent: n: {n}, s: {s}, e: {e}, w: {w}'
            msg = msg.format(n=region.n, s=region.s, e=region.e, w=region.w)
            g.message(msg)

            # modify only the extent
            run('g.region',
                n=region.n, s=region.s, e=region.e, w=region.w)
            trim = "{out} = {input}".format(out=tmp_msx_hpf, input=tmp_msx_hpf)
            grass.mapcalc(trim)

        #
        # End of Algorithm

        # history entry
        run("r.support", map=tmp_msx_hpf, history="\n".join(cmd_history))

        # add suffix to basename & rename end product
        msx_name = "{base}.{suffix}"
        msx_name = msx_name.format(base=msx.split('@')[0], suffix=outputsuffix)
        run("g.rename", raster=(tmp_msx_hpf, msx_name))

        # remove temporary files
        cleanup()

    # visualising-related information
    grass.del_temp_region()  # restoring previous region settings
    g.message("\n|! Original Region restored")
    g.message("\n>>> Hint, rebalancing colors (via i.colors.enhance) "
              "may improve appearance of RGB composites!",
              flags='i')
def main():
    """ """
    sensor = options['sensor']

    mapsets = options['mapsets']
    prefix = options['input_prefix']
    suffix = options['output_suffix']

    metafile = grass.basename(options['metafile'])

    # 6S parameter names shortened following i.atcorr's manual
    atm = int(options['atmospheric_model'])  # Atmospheric model [index]
    aer = int(options['aerosols_model'])  # Aerosols model [index]

    vis = options['visibility_range']  # Visibility [km]
    aod = options['aerosol_optical_depth']  # Aerosol Optical Depth at 550nm

    xps = options['altitude']  # Mean Target Altitude [negative km]
    if not xps:
        msg = "Note, this value will be overwritten if a DEM raster has been "\
              "defined as an input!"
        g.message(msg)

    elevation_map = options['elevation']
    visibility_map = options['visibility']

    radiance = flags['r']
    if radiance:
        global rad_flg
        radiance_flag = 'r'
    else:
        radiance_flag = ''

    # If the scene to be processed was imported via the (custom) python
    # Landsat import script, then, Mapset name == Scene identifier

    mapset = grass.gisenv()['MAPSET']
    if mapset == 'PERMANENT':
        grass.fatal(_('Please change to another mapset than the PERMANENT'))

#    elif 'L' not in mapset:
#        msg = "Assuming the Landsat scene(s) ha-s/ve been imported using the "\
#              "custom python import script, the Mapset's name *should* begin "\
#              "with the letter L!"
#        grass.fatal(_(msg))

    else:
        result = grass.find_file(element='cell_misc',
                                 name=metafile,
                                 mapset='.')
        if not result['file']:
            grass.fatal("The metadata file <%s> is not in GRASS' data base!"
                        % metafile)
        else:
            metafile = result['file']

    #
    # Acquisition's metadata
    #

    msg = "Acquisition metadata for 6S code (line 2 in Parameters file)\n"

    # Month, day
    date = grass.parse_command('i.landsat.toar', flags='p',
                               input='dummy', output='dummy',
                               metfile=metafile, lsatmet='date')
    mon = int(date['date'][5:7])  # Month of acquisition
    day = int(date['date'][8:10])  # Day of acquisition

    # GMT in decimal hours
    gmt = grass.read_command('i.landsat.toar', flags='p',
                             input='dummy', output='dummy',
                             metfile=metafile, lsatmet='time')
    gmt = float(gmt.rstrip('\n'))

    # Scene's center coordinates
    cll = grass.parse_command('g.region', flags='clg')
    lon = float(cll['center_long'])  # Center Longitude [decimal degrees]
    lat = float(cll['center_lat'])  # Center Latitude [decimal degrees]

    msg += str(mon) + ' ' + str(day) + ' ' + str(gmt) + ' ' + \
        str(lon) + ' ' + str(lat)
    g.message(msg)
   
    # 
    # AOD
    #
    if aod:
        aod = float(options['aerosol_optical_depth'])

    else:
        # sane defaults
        if 4 < mon < 10:
            aod = float(0.222)  # summer
        else:
            aod = float(0.111)  # winter

    #
    # Mapsets are Scenes. Read'em all!
    #

    if mapsets == 'all':
        scenes = grass.mapsets()

    elif mapsets == 'current':
        scenes = [mapset]

    else:
        scenes = mapsets.split(',')

    if 'PERMANENT' in scenes:
        scenes.remove('PERMANENT')

    # access only to specific mapsets!
    msg = "\n|* Performing atmospheric correction for scenes:  %s" % scenes
    g.message(msg)

    for scene in scenes:

        # ensure access only to *current* mapset
        run('g.mapsets', mapset='.', operation='set')

        # scene's basename as in GRASS' db
        basename = grass.read_command('g.mapset', flags='p')
        msg = "   | Processing scene:  %s" % basename
        g.message(msg)

        # loop over Landsat bands in question
        for band in sensors[sensor].keys():

            inputband = prefix + str(band)
            msg = '\n>>> Processing band: {band}'.format(band=inputband)
            g.message(msg)


            # Generate 6S parameterization file
            p6s = Parameters(geo=geo[sensor],
                             mon=mon, day=day, gmt=gmt, lon=lon, lat=lat,
                             atm=atm,
                             aer=aer,
                             vis=vis,
                             aod=aod,
                             xps=xps, xpp=xpp,
                             bnd=sensors[sensor][band])
            
            #
            # Temporary files
            #
            tmpfile = grass.tempfile()
            tmp = "tmp." + grass.basename(tmpfile)  # use its basename

            tmp_p6s = grass.tempfile()  # 6S Parameters ASCII file
            tmp_atm_cor = "%s_cor_out" % tmp  # Atmospherically Corrected Img

            p6s.export_ascii(tmp_p6s)

            # Process band-wise atmospheric correction with 6s
            msg = "6S parameters:\n\n"
            msg += p6s.parameters
            g.message(msg)

            # inform about input's range?
            input_range = grass.parse_command('r.info', flags='r', map=inputband)
            input_range['min'] = float(input_range['min'])
            input_range['max'] = float(input_range['max'])
            msg = "Input range: %.2f ~ %.2f" % (input_range['min'], input_range['max'])
            g.message(msg)

            #
            # Applying 6S Atmospheric Correction algorithm
            #
            run_i_atcorr(radiance_flag,
                         inputband,
                         input_range,
                         elevation_map,
                         visibility_map,
                         tmp_p6s,
                         tmp_atm_cor,
                         (0,1))
        
            # inform about output's range?
            output_range = grass.parse_command('r.info', flags='r', map=tmp_atm_cor)
            output_range['min'] = float(output_range['min'])
            output_range['max'] = float(output_range['max'])
            msg = "Output range: %.2f ~ %.2f" \
                % (output_range['min'], output_range['max'])
            g.message(msg)

            # add suffix to basename & rename end product
            atm_cor_nam = ("%s%s.%s" % (prefix, suffix, band))
            run('g.rename', rast=(tmp_atm_cor, atm_cor_nam))
# constants -----------------------------------------------------------------
geo = {'tm': 7, 'mss': 7, 'etm': 8, 'oli': 18}  # Geometrical conditions
xpp = -1000  # Satellite borne [-1000]

# Spectral conditions index
sensors = {
'mss': {1: 31, 2: 32, 3: 33, 4: 34},
'tm':  {1: 25, 2: 26, 3: 27, 4: 28, 5: 29, 7: 30},
'etm': {1: 61, 2: 62, 3: 63, 4: 64, 5: 65, 7: 66, 8: 67},
'oli': {1: 115, 2: 116, 3: 117, 4: 118, 8: 119, 5: 120, 9: 121, 6: 122, 7: 123}
}


# globals
g.message(msg)
radiance_flag = ''


# helper functions
def cleanup():
    """Clean up temporary maps"""
    grass.run_command('g.remove', flags='f', type="raster",
                      pattern='tmp.%s*' % os.getpid(), quiet=True)


def run(cmd, **kwargs):
    """
    Pass quiet flag to grass commands
    """
    grass.run_command(cmd, quiet=True, **kwargs)
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
def import_geotiffs(scene, bands, mapset, memory, list_bands, tgis = False):
    """
    Imports all bands (GeoTIF format) of a Landsat scene be it Landsat 5,
    7 or 8.  All known naming conventions are respected, such as "VCID" and
    "QA" found in newer Landsat scenes for temperature channels and Quality
    respectively.

    Parameters
    ----------
    scene :
        Input scene name string

    bands :
        Bands to import

    mapset :
        Name of mapset to import to

    memory :
        See options for r.in.gdal

    list_bands :
        Boolean True or False

    tgis :
        Boolean True or False
    """

    timestamp = get_timestamp(scene, tgis)
    print_timestamp(os.path.basename(scene), timestamp, tgis)

    if not one_mapset:
        # set mapset from scene name
        mapset = os.path.basename(scene)

    message = str()  # a string holder

    # verbosity: target Mapset
    if not any(x for x in (list_bands, tgis)):
        message = 'Target Mapset\n@{mapset}\n\n'.format(mapset=mapset)

    # communicate input band name
    if not tgis:
        message += 'Band\tFilename\n'
        g.message(_(message))

    # loop over files inside a "Landsat" directory
    # sort band numerals, source: https://stackoverflow.com/a/2669523/1172302

    if bands == 'all':
        filenames = sort_list_of_bands(os.listdir(scene))
        # filenames = sorted(os.listdir(scene), key=lambda item:
        #         (int(item.partition('_B')[2].partition('.')[0])
        #             if item.partition('_B')[2].partition('.')[0].isdigit()
        #             else float('inf'), item))

    else:
        filenames = sort_list_of_bands(bands)

    for filename in filenames:

        # if not GeoTIFF, keep on working
        if os.path.splitext(filename)[-1] != GEOTIFF_EXTENSION:
            continue

        # use the full path name to the file
        name, band = get_name_band(scene, filename)
        band_title = 'band {band}'.format(band = band)

        if not tgis:

            message_overwriting = '\t [ Exists, overwriting]'

            # communicate input band and source file name
            message = '{band}'.format(band = band)
            message += '\t{filename}'.format(filename = filename)
            if not skip_import:
                g.message(_(message))

            else:
                # message for skipping import
                message_skipping = '\t [ Exists, skipping ]'

        if not any(x for x in (list_bands, tgis)):

            # get absolute filename
            absolute_filename = os.path.join(scene, filename)

            # srt import parameters
            parameters = dict(input = absolute_filename,
                    output = name,
                    flags = '',
                    title = band_title,
                    quiet = True)

            if override_projection:
                parameters['flags'] += 'o'

            # create Mapset of interest, if it doesn't exist
            devnull = open(os.devnull, 'w')
            run('g.mapset',
                    flags='c',
                    mapset=mapset,
                    stderr = devnull)
            # g.mapset(flags='c', mapset=mapset)

            if (skip_import
                    and find_existing_band(name)
                    and not grass.overwrite()):

                if force_timestamp:
                    set_timestamp(name, timestamp)
                    g.message(_('   >>> Forced timestamping for {b}'.format(b=name)))

                message_skipping = message + message_skipping
                g.message(_(message_skipping))
                pass

            else:
                if (grass.overwrite() and find_existing_band(name)):
                    if force_timestamp:
                        set_timestamp(name, timestamp)
                        g.message(_('   >>> Forced timestamping for {b}'.format(b=name)))

                    message_overwriting = message + message_overwriting
                    g.message(_(message_overwriting))
                    pass

                if (skip_import and not find_existing_band(name)):
                    # FIXME
                    # communicate input band and source file name
                    message = '{band}'.format(band = band)
                    message += '\t{filename}'.format(filename = filename)
                    grass.message(_(message))

                if link_geotiffs:
                    # What happens with the '--overwrite' flag?
                    # Check if it can be retrieved.

                    r.external(**parameters)

                else:
                    if memory:
                        parameters['memory'] = memory
                    # try:
                    r.in_gdal(**parameters)

                    # except CalledModuleError:
                        # grass.fatal(_("Unable to read GDAL dataset {s}".format(s=scene)))

                if not do_not_timestamp:
                    set_timestamp(name, timestamp)

        else:
            pass

    # copy MTL
    if not list_bands and not tgis:
        copy_mtl_in_cell_misc(scene, mapset, tgis, copy_mtl)
def main():
    r_elevation = options['elevation']
    mrvbf = options['mrvbf'].split('@')[0]
    mrrtf = options['mrrtf'].split('@')[0]
    t_slope = float(options['t_slope'])
    t_pctl_v = float(options['t_pctl_v'])
    t_pctl_r = float(options['t_pctl_r'])
    t_vf = float(options['t_rf'])
    t_rf = float(options['t_rf'])
    p_slope = float(options['p_slope'])
    p_pctl = float(options['p_pctl'])
    moving_window_square = flags['s']
    levels = int(options['levels'])

    global TMP_RAST
    global current_region
    TMP_RAST = {k: [] for k in range(levels)}
    current_region = Region()

    ###########################################################################
    # Some checks
    if levels < 3:
        grass.fatal('Number of generalization steps (levels) cannot be < 3')
    if t_slope <=0 or t_pctl_v <=0 or t_pctl_r <=0 or t_vf <=0 or t_rf <=0 or \
        p_slope <=0 or p_pctl <=0:
        grass.fatal('Parameter values cannot be <= 0')
    if levels > 10:
        grass.warning('A large number (>10) processing steps are selected, recommended is between 3 to 8')
	
	###########################################################################
    # Intermediate outputs
    Xres_step, Yres_step, DEM = [], [], []
    slope, F, PCTL, PVF, PVF_RF = [0]*levels, [0]*levels, [0]*levels, [0]*levels, [0]*levels
    VF, VF_RF, MRVBF, MRRTF = [0]*levels, [0]*levels, [0]*levels, [0]*levels
	
	###########################################################################
	# Step 1 (L=0)
    # Base scale resolution
    L = 0
    Xres_step.append(current_region.ewres)
    Yres_step.append(current_region.nsres)
    DEM.append(r_elevation)
    radi = 3

    g.message(os.linesep)
    g.message("Step {L}".format(L=L+1))
    g.message("------")

    # Calculation of slope (S1) and calculation of flatness (F1) (Equation 2)
    grass.message("Calculation of slope and transformation to flatness F{L}...".format(L=L+1))
    slope[L] = get_slope(L, DEM[L])
    F[L] = get_flatness(L, slope[L], t_slope, p_slope)

    # Calculation of elevation percentile PCTL for step 1
    grass.message("Calculation of elevation percentile PCTL{L}...".format(L=L+1))
    PCTL[L] = get_percentile(L, DEM[L], radi, moving_window_square)

    # Transform elevation percentile to local lowness for step 1 (Equation 3)
    grass.message("Calculation of preliminary valley flatness index PVF{L}...".format(L=L+1))
    PVF[L] = get_prelim_flatness(L, F[L], PCTL[L], t_pctl_v, p_pctl)
    if mrrtf != '':
        grass.message("Calculation of preliminary ridge top flatness index PRF{L}...".format(L=L+1))
        PVF_RF[L] = get_prelim_flatness_rf(L, F[L], PCTL[L], t_pctl_r, p_pctl)

    # Calculation of the valley flatness step 1 VF1 (Equation 4)
    grass.message("Calculation of valley flatness VF{L}...".format(L=L+1))
    VF[L] = get_valley_flatness(L, PVF[L], t_vf, p_slope)
    if mrrtf != '':
        grass.message("Calculation of ridge top flatness RF{L}...".format(L=L+1))
        VF_RF[L] = get_valley_flatness(L, PVF_RF[L], t_rf, p_slope)

	##################################################################################
	# Step 2 (L=1)
    # Base scale resolution		
    L = 1
    Xres_step.append(current_region.ewres)
    Yres_step.append(current_region.nsres)
    DEM.append(r_elevation)
    t_slope /= 2.0
    radi = 6

    grass.message(os.linesep)
    grass.message("Step {L}".format(L=L+1))
    grass.message("------")
	
    # Calculation of flatness for step 2 (Equation 5)
    # The second step commences the same way with the original DEM at its base resolution,
    # using a slope threshold ts,2 half of ts,1:
    grass.message("Calculation of flatness F{L}...".format(L=L+1))
    F[L] = get_flatness(L, slope[L-1], t_slope, p_slope)

    # Calculation of elevation percentile PCTL for step 2 (radius of 6 cells)
    grass.message("Calculation of elevation percentile PCTL{L}...".format(L=L+1))
    PCTL[L] = get_percentile(L, r_elevation, radi, moving_window_square)

    # PVF for step 2 (Equation 6)
    grass.message("Calculation of preliminary valley flatness index PVF{L}...".format(L=L+1))
    PVF[L] = get_prelim_flatness(L, F[L], PCTL[L], t_pctl_v, p_pctl)
    if mrrtf != '':
        grass.message("Calculation of preliminary ridge top flatness index PRF{L}...".format(L=L+1))
        PVF_RF[L] = get_prelim_flatness_rf(L, F[L], PCTL[L], t_pctl_r, p_pctl)
    
    # Calculation of the valley flatness VF for step 2 (Equation 7)
    grass.message("Calculation of valley flatness VF{L}...".format(L=L+1))
    VF[L] = get_valley_flatness(L, PVF[L], t_vf, p_slope)
    if mrrtf != '':
        grass.message("Calculation of ridge top flatness RF{L}...".format(L=L+1))
        VF_RF[L] = get_valley_flatness(L, PVF_RF[L], t_rf, p_slope)
            
    # Calculation of MRVBF for step 2
    grass.message("Calculation of MRVBF{L}...".format(L=L+1))
    MRVBF[L] = get_mrvbf(L, VF_Lminus1=VF[L-1], VF_L=VF[L], t=t_pctl_v)
    if mrrtf != '':
        grass.message("Calculation of MRRTF{L}...".format(L=L+1))
        MRRTF[L] = get_mrvbf(L, VF_Lminus1=VF_RF[L-1], VF_L=VF_RF[L], t=t_pctl_r)

    # Update flatness for step 2 with combined flatness from F1 and F2 (Equation 10)
    grass.message("Calculation  of combined flatness index CF{L}...".format(L=L+1))
    F[L] = get_combined_flatness(L, F[L-1], F[L])
	
	##################################################################################
    # Remaining steps
    # DEM_1_1 refers to scale (smoothing) and resolution (cell size)
    # so that DEM_L1_L-1 refers to smoothing of current step,
    # but resolution of previous step 

    for L in range(2, levels):

        t_slope /= 2.0
        Xres_step.append(Xres_step[L-1] * 3)
        Yres_step.append(Yres_step[L-1] * 3)
        radi = 6

        # delete temporary maps from L-2
        for tmap in TMP_RAST[L-2]:
            g.remove(type='raster', name=tmap, flags='f', quiet=True)

        grass.message(os.linesep)
        grass.message("Step {L}".format(L=L+1))
        grass.message("------")
        
        # Coarsen resolution to resolution of prevous step (step L-1) and smooth DEM
        if L >= 3:
            grass.run_command('g.region', ewres = Xres_step[L-1], nsres = Yres_step[L-1])
            grass.message('Coarsening resolution to ew_res={e} and ns_res={n}...'.format(
                e=Xres_step[L-1], n=Yres_step[L-1]))
        
        grass.message("DEM smoothing 11 x 11 windows with Gaussian smoothing kernel (sigma) 3...")
        DEM.append(get_smoothed_dem(L, DEM[L-1]))

        # Calculate slope
        grass.message("Calculation of slope...")
        slope[L] = get_slope(L, DEM[L])

        # Refine slope to base resolution
        if L >= 3:
            grass.message('Resampling slope back to base resolution...')
            slope[L] = refine(L, slope[L], current_region, method='bilinear')

        # Coarsen resolution to current step L and calculate PCTL
        grass.run_command('g.region', ewres=Xres_step[L], nsres=Yres_step[L])
        DEM[L] = refine(L, DEM[L], Region(), method = 'average')
        grass.message("Calculation of elevation percentile PCTL{L}...".format(L=L+1))
        PCTL[L] = get_percentile(L, DEM[L], radi, moving_window_square)
        
        # Refine PCTL to base resolution
        grass.message("Resampling PCTL{L} to base resolution...".format(L=L+1))
        PCTL[L] = refine(L, PCTL[L], current_region, method='bilinear')

        # Calculate flatness F at the base resolution
        grass.message("Calculate F{L} at base resolution...".format(L=L+1))
        F[L] = get_flatness(L, slope[L], t_slope, p_slope)

        # Update flatness with combined flatness CF from the previous step
        grass.message("Calculate combined flatness CF{L} at base resolution...".format(L=L+1))
        F[L] = get_combined_flatness(L, F1=F[L-1], F2=F[L])

        # Calculate preliminary valley flatness index PVF at the base resolution
        grass.message("Calculate preliminary valley flatness index PVF{L} at base resolution...".format(L=L+1))
        PVF[L] = get_prelim_flatness(L, F[L], PCTL[L], t_pctl_v, p_pctl)
        if mrrtf != '':
            grass.message("Calculate preliminary ridge top flatness index PRF{L} at base resolution...".format(L=L+1))
            PVF_RF[L] = get_prelim_flatness_rf(L, F[L], PCTL[L], t_pctl_r, p_pctl)
        
        # Calculate valley flatness index VF
        grass.message("Calculate valley flatness index VF{L} at base resolution...".format(L=L+1))
        VF[L] = get_valley_flatness(L, PVF[L], t_vf, p_slope)
        if mrrtf != '':
            grass.message("Calculate ridge top flatness index RF{L} at base resolution...".format(L=L+1))
            VF_RF[L] = get_valley_flatness(L, PVF_RF[L], t_rf, p_slope)
            
        # Calculation of MRVBF
        grass.message("Calculation of MRVBF{L}...".format(L=L+1))
        MRVBF[L] = get_mrvbf(L, VF_Lminus1=MRVBF[L-1], VF_L=VF[L], t=t_pctl_v)
        if mrrtf != '':
            grass.message("Calculation of MRRTF{L}...".format(L=L+1))
            MRRTF[L] = get_mrvbf(L, VF_Lminus1=MRRTF[L-1], VF_L=VF_RF[L], t=t_pctl_r)

    # Output final MRVBF
    grass.mapcalc("$x = $y", x = mrvbf, y=MRVBF[L])

    if mrrtf != '':
        grass.mapcalc("$x = $y", x = mrrtf, y=MRRTF[L])
Example #59
0
def main(resistancemap, stmap, stlist, output_prefix, output_folder, variability, scale, simulations, method):
    
    # Checking parameters and passing them to LSCorridors instance
    
    #---------------------
    # Initialize LSCorridors app class instance
    app = wx.PySimpleApp()
    frame = wx.Frame(None, -1, "LSCorridors", pos=(0,0), size=(560,450))
    corr = Corridors(frame, -1)    
    
    #---------------------
    # Define folder for output files
    if output_folder == '':
        output_folder = os.getcwd()
    # Try to change to output_folder
    try:
        os.chdir(output_folder)
        corr.path = os.getcwd()
        g.message('Folder for output files: '+corr.path)
    except:
        grass.fatal(_('GRASS GIS cannot access the folder '+output_folder+'. Please check if the folder exists'+
                      'and its access permissions.'))
    corr.OutDir_files_TXT = corr.path
    
    #---------------------
    # Check if the resistance map and ST map are inside the GRASS GIS mapset
    # If they are, define them as inputs for LSCorridors
    current_mapset = grass.read_command('g.mapset', flags = 'p').replace('\n','').replace('\r','')  
    maps=grass.list_grouped('rast')[current_mapset]
    # Resistance map
    if resistancemap in maps:
        # Name of the input resistance map
        corr.OutArqResist = resistancemap
        g.message('Input resistance map: '+resistancemap)
    else:
        grass.fatal(_('Input: resistance map. There is no raster map called '+resistancemap+
                      ' inside the GRASS GIS mapset '+current_mapset+
                      '. Please import the map into GRASS GIS.'))
    if stmap in maps:
        # Name of the input resistance map
        corr.OutArqST = stmap
        g.message('Input Source-Target (ST) map: '+stmap)
    else:
        grass.fatal(_('Input: ST map. There is no raster map called '+stmap+
                      ' inside the GRASS GIS mapset '+current_mapset+
                      '. Please import the map into GRASS GIS.'))
    
    #---------------------
    # Transforms stlist into a python list nad checks if the list is ok
    corr.patch_id_list = stlist.split(',')
    corr.patch_id_list_bkp = corr.patch_id_list
    lenlist = len(corr.patch_id_list)
    
    ##########################
    # include a flag with the possibility of being a txt file
    
    # Tests if the list has more than one element
    if lenlist <= 1: 
        grass.fatal(_("Incorrect ST list. List length is smaller than 2! "+
                      "Please check the list."))
    # Tests if the length of the ST list is even
    elif lenlist > 1 and int(lenlist)%2 == 1:
        grass.fatal(_("Incorrect ST list. List length cannot be odd. "+
                      "Please check the list."))
    else:
        g.message('ST list checked and OK.')
    
    #---------------------
    # Gets prefix for output files and puts that into output final names
    if output_prefix == '':
        corr.NEXPER_FINAL = corr.NEXPER_AUX+'_'+resistancemap
        corr.NEXPER_FINAL_txt = corr.NEXPER_AUX_txt+'_'+resistancemap
    else:
        corr.NEXPER_FINAL = corr.NEXPER_AUX+'_'+output_prefix
        corr.NEXPER_FINAL_txt = corr.NEXPER_AUX_txt+'_'+output_prefix
    g.message('Prefix of the output files: '+corr.NEXPER_FINAL)
    
    #---------------------
    # Variability parameter
    # Checks if the values are positive and real
    
    try:
        # If no varibility parameter was passed, use the standard option
        if variability == '' or variability == '2.0':
            # Define the LSCorridors variability list
            corr.ruidos_float = [2.0]
        # If values of variability were passed, check that
        else:
            varlist = [float(i) for i in variability.split(',')]
            
            if len(varlist) < 1:
                grass.fatal(_('The list has no elements. Please check it.'))
            elif any(i < 0.0 for i in varlist):
                grass.fatal(_('Incorrect variability parameter(s). Variability must be '+
                              'a number equal to or greater than zero! '+
                              'Please check the parameter(s).'))
            else:
                # Define the LSCorridors variability list
                corr.ruidos_float = varlist
        g.message("Variability parameter(s): "+', '.join(str(i) for i in corr.ruidos_float))
    except:
        grass.fatal(_('One or more of the variability values is not a real number. Check it.'))
    
    
    #---------------------
    # Methods and number of simulations

    # Checks if number of simulations is integer and positive
    try:
        if int(simulations) < 1:
            grass.fatal(_('The number of simulations must be a positive integer value.'))
    except:
        grass.fatal(_('The number of simulations must be numeric.'))
        
    # Checks if the methods are valid
    if method == '':
        # If not parameter was passed, used the standard 'MP'
        method = 'MP'
    else:
        possible_methods = ['MP', 'MLmin', 'MLavg', 'MLmax']
        method_list = method.split(',')
        if all(i in possible_methods for i in method_list):
            pass
        else:
            grass.fatal(_('At list one of the methods is not valid. They must be one of these:'+
                          'MP, MLmin, MLavg, or MLmax'))
        
    # Define number of simulations for each method
    if 'MP' in method_list:
        corr.Nsimulations1 = int(simulations)
        g.message('Number of simulations for method MP: '+simulations)
    else:
        corr.Nsimulations1 = 0
    if 'MLmin' in method_list:
        corr.Nsimulations2 = int(simulations)
        g.message('Number of simulations for method MLmin: '+simulations)
    else:
        corr.Nsimulations2 = 0
    if 'MLavg' in method_list:
        corr.Nsimulations3 = int(simulations)
        g.message('Number of simulations for method MLavg: '+simulations)
    else:
        corr.Nsimulations3 = 0
    if 'MLmax' in method_list:
        corr.Nsimulations4 = int(simulations)
        g.message('Number of simulations for method MLmax: '+simulations)
    else:
        corr.Nsimulations4 = 0
    
    #---------------------
    # Scale parameter
    # Checks if the values are positive and real
        
    try:
        # If no scale parameter was passed, use the standard option
        if scale == '' or scale == '100':
            # Define the LSCorridors scale list
            corr.escalas = [100]
        # If values of scale were passed, check that
        else:
            scalelist = [int(i) for i in scale.split(',')]
            
            # First, defining GRASS GIS region as output map region
            grass.run_command('g.region', rast=resistancemap)

            # Second, reading map resolution
            res = grass.read_command('g.region', rast=resistancemap, flags='m')
            res2 = res.split('\n')
            res3 = res2[5]
            res3 = float(res3.replace('ewres=',''))

            # Third, calculate window size (landscape scale x 2) in number of pixels
            escalas_pixels = [float(i)*2/res3 for i in scalelist]

            # Finally, tests if any of the scales are lower than the pixel size
            #  (this only matters if methods MLmin, MLavg, or MLmax are going to be simulated)
            if any(i < 2.0 for i in escalas_pixels) and (corr.Nsimulations2 > 0 or corr.Nsimulations3 > 0 or corr.Nsimulations4 > 0):
                #print 'oi '+res3
                grass.fatal(_("There may a problem with scale parameter. "+
                            "Input map resolution is "+`round(res3,1)`+" meters, scale should be greater than that! "+
                            "Please check the parameter(s)."))
            else:
                # Define the LSCorridors variability list
                corr.escalas = scalelist
        g.message("Scale parameter(s): "+', '.join(str(i) for i in corr.escalas))
    except:
        grass.fatal(_('One or more of the scale values is not a real number. Check it.'))
    
    # Tests are going to be performed; however, as one do not want dialog boxes to be 
    #  shown, we keep this option as True
    corr.perform_tests = True
    
    # Event to test RUN SIMULATIONS        
    evt10 = wx.PyCommandEvent(wx.EVT_BUTTON.typeId, 10)
    corr.OnClick(evt10)
             
    # Delete .pyc created
    #os.remove('LS_corridors_v1_0_0.pyc')
    os.remove('*.pyc')
    
    # call run START button

    return 0
Example #60
0
def main():
    global tmp_hpf_matrix

    pan = options['pan']
    msxlst = options['msx'].split(',')
    outputprefix = options['outputprefix']
    custom_ratio = options['ratio']
    center = options['center']
    center2 = options['center2']
    modulation = options['modulation']
    modulation2 = options['modulation2']
    histogram_match = flags['l']
    second_pass = flags['2']

    # Check & warn user about "ns == ew" resolution of current region ======
    region = grass.region()
    nsr = region['nsres']
    ewr = region['ewres']

    if nsr != ewr:
        g.message(">>> Region's North:South (%s) and East:West (%s)"
                  "resolutions do not match!" % (nsr, ewr), flags='w')
    # ======================================================================

    mapset = grass.gisenv()['MAPSET']  # Current Mapset?

    imglst = [pan]
    imglst.extend(msxlst)  # List of input imagery

    images = {}
    for img in imglst:  # Retrieving Image Info
        images[img] = Info(img, mapset)
        images[img].read()

    panres = images[pan].nsres  # Panchromatic resolution

    run('g.region', res=panres)  # Respect extent, change resolution
    g.message("|  Region's resolution set to %f" % panres)


    for msx in msxlst:  # Loop over Multi-Spectral images |||||||||||||||||||

        global tmp

        # Inform
        g.message("\nProcessing image: %s" % msx)

        # Tracking command history -- Why don't do this all r.* modules?
        cmd_history = ''

        # -------------------------------------------------------------------
        # 1. Compute Ratio
        # -------------------------------------------------------------------

        g.message("\n|1 Determining ratio of low to high resolution")

        # Custom Ratio? Skip standard computation method.
        if custom_ratio:
            global ratio
            ratio = float(custom_ratio)
            g.message('Using custom ratio, overriding standard method!',
                      flags='w')

        # Multi-Spectral resolution(s), multiple
        else:
            # Image resolutions
            g.message("   > Retrieving image resolutions")

            msxres = images[msx].nsres
            ratio = msxres / panres
            msg_ratio = '   >> Low (%.3f) to high resolution (%.3f) ratio: %.1f'\
                % (msxres, panres, ratio)
            g.message(msg_ratio)

        # 2nd Pass requested, yet Ratio < 5.5
        if second_pass and ratio < 5.5:
            g.message("   >>> Ratio < 5.5 -- WON'T perform 2nd pass! Use <ratio> option to override.",
                      flags='i')
            second_pass = bool(0)

        # -------------------------------------------------------------------
        # 2. High Pass Filtering
        # -------------------------------------------------------------------

        g.message('\n|2 High Pass Filtering the Panchromatic Image')

        # ========================================== end of Temporary files #
        tmpfile = grass.tempfile()  # Temporary file - replace with os.getpid?
        tmp = "tmp." + grass.basename(tmpfile)  # use its basenam
        tmp_pan_hpf = "%s_pan_hpf" % tmp  # HPF image
        tmp_msx_blnr = "%s_msx_blnr" % tmp  # Upsampled MSx
        tmp_msx_hpf = "%s_msx_hpf" % tmp  # Fused image

        tmp_hpf_matrix = grass.tempfile()  # ASCII filter

        if second_pass and ratio > 5.5:  # 2nd Pass?
            tmp_pan_hpf_2 = "%s_pan_hpf_2" % tmp  # 2nd Pass HPF image
            tmp_hpf_matrix_2 = grass.tempfile()  # 2nd Pass ASCII filter

        # Temporary files ===================================================

        # Construct Filter
        hpf = High_Pass_Filter(ratio, center, modulation, False, None)
        hpf_ascii(center, hpf, tmp_hpf_matrix, 1)

        # Construct 2nd Filter
        if second_pass and ratio > 5.5:
            hpf_2 = High_Pass_Filter(ratio, center2, None, True, modulation2)
            hpf_ascii(center2, hpf_2, tmp_hpf_matrix_2, 2)

        # Filtering
        run('r.mfilter', input=pan, filter=tmp_hpf_matrix,
            output=tmp_pan_hpf,
            title="High Pass Filtered Panchromatic image",
            overwrite=True)

        # 2nd Filtering
        if second_pass and ratio > 5.5:
            run('r.mfilter', input=pan, filter=tmp_hpf_matrix_2,
                output=tmp_pan_hpf_2,
                title="2-High-Pass Filtered Panchromatic Image",
                overwrite=True)

        # -------------------------------------------------------------------
        # 3. Upsampling low resolution image
        # -------------------------------------------------------------------

        g.message("\n|3 Upsampling (bilinearly) low resolution image")

        # resample -- named "linear" in G7
        run('r.resamp.interp',
            method='bilinear', input=msx, output=tmp_msx_blnr, overwrite=True)

        # -------------------------------------------------------------------
        # 4. Weighting the High Pass Filtered image(s)
        # -------------------------------------------------------------------

        g.message("\n|4 Weighting the High-Pass-Filtered image (HPFi)")

        # Compute (1st Pass) Weighting
        msg_w = "   > Weighting = StdDev(MSx) / StdDev(HPFi) * "
        "Modulating Factor"
        g.message(msg_w)

        # StdDev of Multi-Spectral Image(s)
        msx_avg = avg(msx)
        msx_sd = stddev(msx)
        g.message("   >> StdDev of <%s>: %.3f" % (msx, msx_sd))

        # StdDev of HPF Image
        hpf_sd = stddev(tmp_pan_hpf)
        g.message("   >> StdDev of HPFi: %.3f" % hpf_sd)

        # Modulating factor
        g.message("   >> Modulating Factor: %.2f" % modulator)

        # weighting HPFi
        weighting = hpf_weight(msx_sd, hpf_sd, modulator, 1)

        # -------------------------------------------------------------------
        # 5. Adding weighted HPF image to upsampled Multi-Spectral band
        # -------------------------------------------------------------------

        g.message("\n|5 Adding weighted HPFi to upsampled image")

        fusion = "%s = %s + %s * %f" \
            % (tmp_msx_hpf, tmp_msx_blnr, tmp_pan_hpf, weighting)
        grass.mapcalc(fusion)

        # history ***********************************************************
        cmd_history += "Weigthing applied: %.3f / %.3f * %.3f | " \
            % (msx_sd, hpf_sd, modulator)

        if second_pass and ratio > 5.5:
            # ---------------------------------------------------------------
            # 4+ 2nd Pass Weighting the High Pass Filtered image
            # ---------------------------------------------------------------
            g.message("\n|4+ 2nd Pass Weighting the HPFi")

            # Compute 2nd Pass Weighting
            # Formula? Don't inform again...

            # StdDev of HPF Image #2
            hpf_2_sd = stddev(tmp_pan_hpf_2)
            g.message("   >> StdDev of 2nd HPFi: %.3f" % hpf_2_sd)

            # Modulating factor #2
            g.message("   >> 2nd Pass Modulating Factor: %.2f" % modulator_2)

            # 2nd Pass weighting
            weighting_2 = hpf_weight(msx_sd, hpf_2_sd, modulator_2, 2)

            # ---------------------------------------------------------------
            # 5+ Adding weighted HPF image to upsampled Multi-Spectral band
            # ---------------------------------------------------------------

            g.message("\n|5+ Adding small-kernel-based weighted 2nd HPFi "
                      "back to fused image")

            add_back = "%s = %s + %s * %f" \
                % (tmp_msx_hpf, tmp_msx_hpf, tmp_pan_hpf_2, weighting_2)
            grass.mapcalc(add_back)

            # 2nd Pass history entry ****************************************
            cmd_history += "2nd Pass Weighting: %s / %s * %s | " \
                % (msx_sd, hpf_2_sd, modulator_2)

        # -------------------------------------------------------------------
        # 6. Stretching linearly the HPF-Sharpened image(s) to match the Mean
        #     and Standard Deviation of the input Multi-Sectral image(s)
        # -------------------------------------------------------------------

        if histogram_match:

            # adapt output StdDev and Mean to the input(ted) ones
            g.message("\n|  Matching histogram of Pansharpened image"
                      "to %s" % (msx), flags='v')

            # Collect stats for linear histogram matching
            msx_hpf_avg = avg(tmp_msx_hpf)
            msx_hpf_sd = stddev(tmp_msx_hpf)

            # expression for mapcalc
            lhm = "%s = (%s - %f) / %f * %f + %f" \
                % (tmp_msx_hpf,
                   tmp_msx_hpf, msx_hpf_avg,
                   msx_hpf_sd, msx_sd, msx_avg)

            # compute
            grass.mapcalc(lhm, quiet=True, overwrite=True)
            
            # update history string *****************************************
            cmd_history += "Linear Histogram Matching: %s |" % lhm

        # histogram matching - history entry ********************************
        run("r.support", map=tmp_msx_hpf, history=cmd_history)

        # Rename end product
        run("g.rename", rast=(tmp_msx_hpf, "%s_%s" % (msx, outputprefix)))

    # visualising output
    g.message("\n>>> Rebalance colors "
              "(e.g. via i.colors.enhance) before working on RGB composites!",
              flags='i')