예제 #1
0
def main():
    """
    FlowFill
    """
    # netCDF4
    try:
        from netCDF4 import Dataset
    except:
        g.fatal(
            _("netCDF4 not detected. Install pip3 and "
              "then type at the command prompt: "
              '"pip3 install netCDF4".'))

    options, flags = gscript.parser()
    _input = options["input"]
    _np = options["np"]
    _threshold = options["threshold"]
    _h_runoff = options["h_runoff"]
    _h_runoff_raster = options["h_runoff_raster"]
    _ties = options["ties"]
    _ffpath = options["ffpath"]
    _output = options["output"]
    _water = options["water"]
    """
    import os
    import numpy as np
    from netCDF4 import Dataset
    # GRASS
    from grass import script as gscript
    from grass.script import array as garray
    from grass.pygrass.modules.shortcuts import raster as r
    from grass.pygrass.modules.shortcuts import general as g

    # FOR TESTING:
    _input = 'DEM_MODFLOW'
    _np = 4
    _threshold = 0.001
    #_h_runoff = 1.
    _h_runoff = ''
    #_h_runoff_raster = ''
    _h_runoff_raster = 'DEM_MODFLOW'
    _ties = 'PREF'
    _ffpath = 'flowfill'
    _output = 'tmpout'
    _water = 'tmpout_water'
    """

    # Check for overwrite -- should be unnecessary thanks to GRASS parser
    _rasters = np.array(gscript.parse_command("g.list", type="raster").keys())
    if (_rasters == _output).any() or (_water == _output).any():
        if gscript.overwrite() is False:
            g.fatal(_("output would overwrite " + _output))

    # Check for proper number of processors
    try:
        _np = int(_np)
    except:
        g.fatal(_("Number of processors must be an integer."))

    if _np < 3:
        g.fatal(_("FlowFill requires 3 or more processors."))

    # Check for proper option set
    if _h_runoff is not "":  # ????? possible ?????
        if _h_runoff_raster is not "":
            g.fatal(
                _('Only one of "h_runoff" and "h_runoff_raster" may be set'))
    elif _h_runoff_raster is "":
        g.fatal(_('Either "h_runoff" or "h_runoff_raster" must be set'))

    if _output is "" and _water is "":
        g.warning(_("No output is set."))

    # Set up runoff options
    if _h_runoff_raster is not "":
        _runoff_bool = "Y"
    else:
        _h_runoff = float(_h_runoff)
        _runoff_bool = "N"

    # Get computational region
    n_columns = gscript.region()["cols"]
    n_rows = gscript.region()["rows"]

    # Output DEM as temporary file for FORTRAN
    temp_FlowFill_input_file = gscript.tempfile(create=False)
    dem = garray.array(_input, null=-999999)
    dem_array = np.array(dem[:]).astype(np.float32)
    del dem
    newnc = Dataset(temp_FlowFill_input_file, "w", format="NETCDF4")
    newnc.createDimension("x", n_columns)
    newnc.createDimension("y", n_rows)
    newnc.createVariable("value", "f4", ("y", "x"))  # z
    newnc.variables["value"][:] = dem_array
    newnc.close()
    del newnc
    # r.out_gdal(input=_input, output=temp_DEM_input_file, format='netCDF',
    #           overwrite=True)

    # Output runoff raster as temporary file for FORTRAN
    if _h_runoff_raster is not "":
        temp_FlowFill_runoff_file = gscript.tempfile(create=False)
        rr = garray.array(_h_runoff_raster, null=0.0)
        rr_array = np.array(rr[:]).astype(np.float32)
        del rr
        newnc = Dataset(temp_FlowFill_runoff_file, "w", format="NETCDF4")
        newnc.createDimension("x", n_columns)
        newnc.createDimension("y", n_rows)
        newnc.createVariable("value", "f4", ("y", "x"))  # z
        newnc.variables["value"][:] = rr_array
        newnc.close()
        # Get the mean value for the floating-point depressions correction
        _h_runoff = np.mean(rr_array[dem_array != -999999])
    else:
        _h_runoff_raster = "NoRaster"  # A dummy value for the parser
        temp_FlowFill_runoff_file = ""

    # Run FlowFill
    temp_FlowFill_output_file = gscript.tempfile(create=False)
    mpirunstr = ("mpirun -np " + str(_np) + " " + _ffpath + " " +
                 str(_h_runoff) + " " + temp_FlowFill_input_file + " " +
                 str(n_columns) + " " + str(n_rows) + " " + str(_threshold) +
                 " " + temp_FlowFill_output_file + " " + _runoff_bool + " " +
                 temp_FlowFill_runoff_file + " " + _ties)
    print("")
    print("Sending command to FlowFill:")
    print(mpirunstr)
    print("")

    _mpirun_error_flag = False

    popen = subprocess.Popen(mpirunstr,
                             stdout=subprocess.PIPE,
                             shell=True,
                             universal_newlines=True)
    for stdout_line in iter(popen.stdout.readline, ""):
        print(stdout_line),
        if "mpirun was unable to find the specified executable file" in stdout_line:
            _mpirun_error_flag = True
    popen.stdout.close()
    if _mpirun_error_flag:
        print("")
        g.fatal(
            _("FlowFill executable not found.\n"
              "If you have not installed FlowFill, please download it "
              "from https://github.com/KCallaghan/FlowFill, "
              "and follow the directions in the README to compile and "
              "install it on your system.\n"
              'This should then work with the default "ffpath". '
              "Otherwise, you may simply have typed in an incorrect "
              '"ffpath".'))

    # _stdout = subprocess.Popen(mpirunstr, shell=True, stdout=subprocess.PIPE)
    #
    # if 'mpirun was unable to find the specified executable file' in \
    #                              ''.join(_stdout.stdout.readlines()):
    # else:
    #    g.message('FlowFill Executable Found.')
    #    print('')

    # subprocess.Popen(mpirunstr, shell=True).wait()
    # os.system(mpirunstr)
    # subprocess.Popen(mpirunstr, shell=True)

    # Import the output -- padded by two cells (remove these)
    outrast = np.fromfile(temp_FlowFill_output_file + ".dat", dtype=np.float32)
    outrast_water = np.fromfile(temp_FlowFill_output_file + "_water.dat",
                                dtype=np.float32)
    outrast = outrast.reshape(n_rows + 2, n_columns + 2)[:-2, 1:-1]
    outrast_water = outrast_water.reshape(n_rows + 2, n_columns + 2)[:-2, 1:-1]

    # Mask to return NAN to NAN in GRASS -- FIX SHIFT ISSUE WITH KERRY
    dem_array_mask = dem_array.copy()
    dem_array_mask[dem_array_mask == -999999] = np.nan
    dem_array_mask = dem_array_mask * 0 + 1
    outrast *= dem_array_mask
    outrast_water *= dem_array_mask

    # Save the output to GRASS GIS
    dem = garray.array()
    dem[:] = outrast
    dem.write(_output, overwrite=gscript.overwrite())
    dem[:] = outrast_water
    dem.write(_water, overwrite=gscript.overwrite())
    del dem
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 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