Beispiel #1
0
def main(heat_density_map,
         region,
         pix_threshold,
         DH_threshold,
         output_dir,
         in_orig=None,
         only_return_areas=False):
    DH_Regions, clipped_hdm, rasterOrigin = DHP.DHReg(heat_density_map, region,
                                                      pix_threshold,
                                                      DH_threshold, in_orig)
    if only_return_areas:
        clipped_hdm = rasterOrigin = None
        return DH_Regions
    """
    Outputs:
        DH_Regions: contains binary values (no units) showing coherent areas
        clipped_hdm: hdm after applying pixel threshold [MWh/ha]
        rasterOrigin: Coordination of the top-left corner of raster
    """
    outRasterPath1 = output_dir + os.sep + 'F13_' + 'Pot_areas.tif'
    outRasterPath2 = output_dir + os.sep + 'F13_' + 'labels.tif'
    outShapefilePath = output_dir + os.sep + 'F13_' + 'Pot_AT_TH30.shp'
    DHPot, labels = DHP.DHPotential(DH_Regions, clipped_hdm)
    """potential of each coherent area in GWh is assigned to its pixels"""
    geo_transform = [rasterOrigin[0], 100, 0, rasterOrigin[1], 0, -100]
    CM19.main(outRasterPath1, geo_transform, 'float64', DH_Regions)
    CM19.main(outRasterPath2, geo_transform, 'int32', labels)
    polygonize(outRasterPath1, outRasterPath2, outShapefilePath, DHPot)
    return outRasterPath1, outShapefilePath
Beispiel #2
0
def scaling(hdm_cut, hdm_cut_gt, updated_demand, outRasterPath):
    '''
    This module gets a demand value and uses the default distribution of heat
    density map for distributing this value between pixels. The module returns
    a numpy array.
    hdm_cut:          numpy array showing demand in MWh/ha
    hdm_cut_gt:       raster geo-transform
    updated_demand:   in GWh/a
    outRasterPath:    path for saving the updated hdm
    '''
    # Sum over pixel values in MWh/ha and return in GWh
    sum_demand_cut = np.sum(hdm_cut) * 0.001
    new_HDM_cut = updated_demand / sum_demand_cut * hdm_cut
    rm_file(outRasterPath)
    CM19.main(outRasterPath, hdm_cut_gt, "float32", new_HDM_cut)
    return outRasterPath
Beispiel #3
0
def distribuition_costs(pixT,
                        DH_threshold,
                        dist_grid_cost,
                        out_raster_hdm_last_year,
                        out_raster_maxDHdem,
                        out_raster_invest_Euro,
                        out_raster_coh_area_bool,
                        out_raster_labels,
                        struct=np.ones((3, 3))):
    rm_file(out_raster_coh_area_bool, out_raster_labels)
    invest_Euro_arr = raster_array(out_raster_invest_Euro)
    maxDHdem_arr = raster_array(out_raster_maxDHdem)
    heat_density_map_last_year, geo_transform = raster_array(
        out_raster_hdm_last_year, return_gt=True)
    rast_origin = geo_transform[0], geo_transform[3]
    coh_areas = np.zeros_like(maxDHdem_arr, 'int8')
    reg_filter = maxDHdem_arr.astype(bool).astype('int8')
    # DH_threshold in MWH
    DH_threshold_MWh = DH_threshold * 1000
    for pix_threshold in pixT:
        # calculate coherent regions with given thresholds and cut them to
        # LAU2 levels
        # DH_Regions: boolean array showing DH regions
        DH_Regions, gt = DHP.DHReg(heat_density_map_last_year, pix_threshold,
                                   DH_threshold, rast_origin)
        # multiplication with reg_filter required to follow out_raster_maxDHdem
        # pattern and separate connection of regions with pixels that have
        # value of zero in out_raster_maxDHdem
        result = DH_Regions.astype(int) * reg_filter
        labels, nr_coherent = measurements.label(result, structure=struct)
        if nr_coherent == 0:
            break
        for i in range(1, nr_coherent + 1):
            temp = labels == i
            q = np.sum(maxDHdem_arr[temp])
            q_inv = np.sum(invest_Euro_arr[temp])
            q_spec_cost = q_inv / q
            if q_spec_cost <= dist_grid_cost and q >= DH_threshold_MWh:
                coh_areas[temp] = 1
                heat_density_map_last_year[temp] = 0
        labels = None
        nr_coherent = None
    labels, numLabels = measurements.label(coh_areas, structure=struct)
    CM19.main(out_raster_coh_area_bool, geo_transform, 'int8', coh_areas)
    CM19.main(out_raster_labels, geo_transform, "int16", labels)
    return numLabels
Beispiel #4
0
def main(heat_density_map, pix_threshold, DH_threshold, output_raster1,
         output_raster2, output_shp1, output_shp2, in_orig=None,
         only_return_areas=False):
    # DH_Regions: boolean array showing DH regions
    DH_Regions, hdm_dh_region_cut, geo_transform, total_heat_demand = DHP.DHReg(heat_density_map,
                                                                                 pix_threshold,
                                                                                 DH_threshold,
                                                                                 in_orig)
    if only_return_areas:
        geo_transform = None
        return DH_Regions
    DHPot, labels = DHP.DHPotential(DH_Regions, heat_density_map)
    total_potential = np.around(np.sum(DHPot),2)
    total_heat_demand = np.around(total_heat_demand, 2)
    if total_potential == 0:
        dh_area_flag = False
    else:
        dh_area_flag = True
    graphics  = [
            {
                    "type": "bar",
                    "xLabel": "DH Area Label",
                    "yLabel": "Potential (GWh/year)",
                    "data": {
                            "labels": [str(x) for x in range(1, 1+len(DHPot))],
                            "datasets": [{
                                    "label": "Potential in coherent areas",
                                    "backgroundColor": ["#3e95cd"]*len(DHPot),
                                    "data": list(np.around(DHPot,2))
                                    }]
                    }
                },{
                    "type": "bar",
                    "xLabel": "",
                    "yLabel": "Demand / Potential (GWh/year)",
                    "data": {
                            "labels": ["Annual heat demand", "DH potential"],
                            "datasets": [{
                                    "label": "Heat Demand Vs. DH Potential (GWh/year)",
                                    "backgroundColor": ["#fe7c60", "#3e95cd"],
                                    "data": [total_heat_demand, total_potential]
                                    }]
                    }
                }]
    symbol_vals_str = []
    if dh_area_flag:
        CM19.main(output_raster1, geo_transform, 'int8', DH_Regions)
        temp_raster = os.path.dirname(output_raster2) + '/temp.tif'
        CM19.main(temp_raster, geo_transform, 'int32', labels)
        symbol_vals_str = polygonize(output_raster1, temp_raster,
                                     output_shp1, output_shp2, DHPot)
        rm_file(temp_raster, temp_raster[:-4] + '.tfw')
        CM19.main(output_raster2, geo_transform, 'float32', hdm_dh_region_cut)

    return total_potential, total_heat_demand, graphics, symbol_vals_str
def zonStat_selectedArea(inputCSV, hdm_outRasterPath, gfa_outRasterPath,
                         population=0, resolution=100):
    '''
    This function calculates the sum of demand within a pixels with given
    resolution. The pixel will also overlay to the standard fishnet used for
    the hotmaps toolbox since the multiplying factor matches to distances from
    the origin of the standard fishnet. The code assumes a resolution of
    100x100 m for the output.
    annual building demand must be in kWh/a
    output heat density map raster is in MWh/ha
    '''
    if isinstance(inputCSV, pd.DataFrame):
        ifile = inputCSV
    else:
        if not os.path.isfile(inputCSV):
            raise InputError('The input csv file does not exist!')
        ifile = pd.read_csv(inputCSV)
    demand = ifile['demand'].values
    GFA = ifile['GFA'].values
    if np.sum(GFA):
        GFA_valid = True
    else:
        GFA_valid = False
    X = ifile['X_3035'].values
    Y = ifile['Y_3035'].values
    x0 = resolution * np.floor(np.min(X)/resolution).astype(int)
    y0 = resolution * np.ceil(np.max(Y)/resolution).astype(int)
    rasterOrigin = (x0, y0)
    xIndex = np.floor((X-x0)/resolution).astype(int)
    yIndex = np.floor((y0-Y)/resolution).astype(int)
    xWidth = np.max(xIndex) - np.min(xIndex) + 1
    yWidth = np.max(yIndex) - np.min(yIndex) + 1
    index = xIndex + xWidth * yIndex
    # The number of rows of "index" and "demand" must be equal.
    sortedData = np.asarray(sorted(zip(index, demand), key=lambda x: x[0]))
    sortedData_GFA = np.asarray(sorted(zip(index, GFA), key=lambda x: x[0]))
    unique, counts = np.unique(index, return_counts=True)
    end = np.cumsum(counts)
    st = np.concatenate((np.zeros((1)), end[0:end.size-1]))
    # xIndex and yIndex start from 0. So they should be added by 1
    sumDem = np.zeros((np.max(xIndex)+1)*(np.max(yIndex)+1))
    item_location = 0
    if GFA_valid:
        sumGFA = np.zeros_like(sumDem)
        for item in unique:
            # sum of demand for each index
            startIndex = int(st[item_location])
            endIndex = int(end[item_location])
            sumDem[item] = np.sum(sortedData[startIndex:endIndex, 1])
            sumGFA[item] = np.sum(sortedData_GFA[startIndex:endIndex, 1])
            item_location += 1
    else:
        for item in unique:
            # sum of demand for each index
            startIndex = int(st[item_location])
            endIndex = int(end[item_location])
            sumDem[item] = np.sum(sortedData[startIndex:endIndex, 1])
            item_location += 1
    '''
    xWidth and yWidth in the following refer to columns and rows,
    respectively and should not wrongly be considered as coordination!
    '''
    # kWh/ha = 10^(-3) * MWh/ha
    sumDem = 0.001 * sumDem.reshape((yWidth, xWidth))
    geo_transform = [rasterOrigin[0], resolution, 0
                     , rasterOrigin[1], 0, -resolution]
    CM19.main(hdm_outRasterPath, geo_transform, str(sumDem.dtype), sumDem)
    abs_heat_demand = np.sum(demand)
    if GFA_valid:
        # gross floor area density map
        sumGFA = sumGFA.reshape((yWidth, xWidth))
        CM19.main(gfa_outRasterPath, geo_transform, str(sumGFA.dtype), sumGFA)
        mean_spec_demand = abs_heat_demand/np.sum(GFA)
    else:
        mean_spec_demand = np.nan
    if population:
        mean_dem_perCapita = abs_heat_demand/float(population)
    else:
        mean_dem_perCapita = np.nan
#     print("Absolute heat demand: %0.1f GWh\a"
#           "Mean heat demand per capita: %0.2f kWh\n"
#           "Mean heat demand per heated surface (ave. specific demand): %0.2f"
#           " kWh/m2"
#           % (abs_heat_demand*10**(-6), mean_dem_perCapita, mean_spec_demand))
    return (abs_heat_demand*10**(-6), mean_dem_perCapita, mean_spec_demand)
Beispiel #6
0
def dh_demand(c1,
              c2,
              raster_plotratio,
              raster_hdm,
              start_year,
              last_year,
              accumulated_energy_saving,
              dh_connection_rate_1st_year,
              dh_connection_rate_last_year,
              depr_period,
              output_dir,
              interest,
              output_layers,
              dA_slope=0.0486,
              dA_intercept=0.0007,
              dataType='float32'):
    '''
    Important Note:
    1) Here, for the calculation of plot ratio, I used gross floor area raster
    in one hectar resolution (unit: m2). It should be divided by 1e4 to get the
    plot ratio.
    2) if you have plot ratio raster, remove the 1e4 factor.
    3) Distribution cost is calculated for those pixel that their corresponding
    pipe diameter is equal or greater than 0.
    the input heat density map should be in GWh/km2.
    '''
    horizon = last_year - start_year + 1
    if horizon > depr_period:
        raise Warning('Study horizon is longer than depr_period of district. '
                      'The calculation will be done only till the end of '
                      'depr_period!')
        horizon = depr_period
        remaining_years = 0
    else:
        remaining_years = depr_period - horizon

    energy_reduction_factor = (1 - accumulated_energy_saving)**(1 /
                                                                (horizon - 1))
    hdm_ds = gdal.Open(raster_hdm)
    hdm_band = hdm_ds.GetRasterBand(1)
    hdm = hdm_band.ReadAsArray().astype(float)
    geo_transform = hdm_ds.GetGeoTransform()
    plotRatio_ds = gdal.Open(raster_plotratio)
    plotRatio_band = plotRatio_ds.GetRasterBand(1)
    # gfa in hectar should be devided by 10000 to get right values for
    # plot ratio (m2/m2).
    plotRatio = plotRatio_band.ReadAsArray().astype(float) / 10000.0
    hdm_ds = plotRatio_ds = None
    row, col = np.nonzero(
        (hdm > 0).astype(int) * (plotRatio > 0.0).astype(int))
    # unit conversion from MWh/ha to GJ/m2
    sparseDemand = 0.00036 * hdm[row, col]
    PR_sparse = plotRatio[row, col]
    # the unit for L is m/m2
    # L is in m/m2: to get the value for each pixel (ha) you should multiply it
    # by 10000 because 1 pixel has 10000 m2
    L = 1 / (61.8 * PR_sparse**(-0.15))
    # initialize the variables
    q = 0
    # q_new = dh_connection_rate_1st_year * sparseDemand
    q_tot = np.copy(sparseDemand)
    q_max = np.zeros_like(q_tot)
    for i in range(horizon):
        q_tot = sparseDemand * energy_reduction_factor**i
        q_new = q_tot * (
            dh_connection_rate_1st_year + i *
            (dh_connection_rate_last_year - dh_connection_rate_1st_year) /
            (horizon - 1))
        # q_new is a non-zero sparse matrix. The development of demand can be
        # checked by comparing just one element of q_new with q_max.
        if q_new[0] > q_max[0]:
            q_max = np.copy(q_new)
        q += q_new / (1 + interest)**i
    if remaining_years > 0:
        alpha_horizon = annuity(interest, horizon - 1)
        alpha_depr = annuity(interest, depr_period)
        rest_annuity_factor = alpha_depr - alpha_horizon
        q = q + q_new * rest_annuity_factor
    linearHeatDensity = q_max / L
    # this step is performed to avoid negative effective pipe diameter
    LHD_THRESHOLD = -dA_intercept / dA_slope
    filtered_LHD = (np.log(linearHeatDensity) < LHD_THRESHOLD).astype(int)
    elements = np.nonzero(filtered_LHD)[0]
    dA = dA_slope * (np.log(linearHeatDensity)) + dA_slope
    cf1, cf2 = cost_factors(c1, c2, PR_sparse)
    dA[elements] = 0
    q_max[elements] = 0
    denominator = q / L
    divisor = cf1[1] + cf2[1] * dA
    divisor[elements] = 0
    investment = divisor / denominator
    finalInvestment = np.zeros_like(hdm, dtype=dataType)
    # from Euro/GJ/m2 to Euro/MWh/m2
    finalInvestment[row, col] = investment * 3.6
    maxDHdem_arr = np.zeros_like(finalInvestment, dtype=dataType)
    # max DH demand density in MWh within the study horizon
    maxDHdem_arr[row, col] = q_max * 10000 / 3.6

    invest_Euro_arr = maxDHdem_arr * finalInvestment
    hdm_last_year = np.zeros_like(finalInvestment, dtype=dataType)
    # total demand in the last year of study horizon in MWh/ha
    hdm_last_year[row, col] = q_tot * 10000 / 3.6
    # total demand in last year in GWh for pixels with Plot Ration > 0
    last_year_dem = np.sum(hdm_last_year) / 1000
    # Length of pipes (L)
    length = np.zeros_like(finalInvestment, dtype=dataType)
    length[row, col] = L
    length[row, col][elements] = 0
    maxDHdem, invest_Euro, hdm_cut_last_year, total_pipe_length = output_layers
    rm_file(maxDHdem, invest_Euro, hdm_cut_last_year, total_pipe_length)
    CM19.main(maxDHdem, geo_transform, dataType, maxDHdem_arr)
    CM19.main(invest_Euro, geo_transform, dataType, invest_Euro_arr)
    CM19.main(hdm_cut_last_year, geo_transform, dataType, hdm_last_year)
    CM19.main(total_pipe_length, geo_transform, dataType, length)
    # sum(MWh/ha) and convert to GWh
    first_year_dem_all = np.sum(hdm) / 1000
    # demand in GWh for pixels with Plot Ratio > 0
    first_year_dem = np.sum(sparseDemand) * 10000 / 3600
    return first_year_dem_all, first_year_dem, last_year_dem
Beispiel #7
0
def distribuition_costs(invest_Euro,
                        maxDHdem,
                        features_path,
                        hdm_1st,
                        hdm_last,
                        MS_1st,
                        pixT,
                        DHT,
                        costT,
                        coh_area_raster,
                        hdm_dh_reg_last_year,
                        label_raster,
                        struct=np.ones((3, 3))):
    rm_file(coh_area_raster, hdm_dh_reg_last_year, label_raster)
    invest_Euro_arr = raster_array(invest_Euro)
    maxDHdem_arr = raster_array(maxDHdem)
    hdm_arr, geo_transform = raster_array(hdm_last, return_gt=True)
    rast_origin = geo_transform[0], geo_transform[3]
    coh_areas = np.zeros_like(maxDHdem_arr, 'int8')
    reg_filter = maxDHdem_arr.astype(bool).astype('int8')
    for pix_threshold in pixT:
        # calculate coherent regions with given thresholds and cut them to
        # LAU2 levels
        DH_Regions = CM4.main(hdm_arr,
                              features_path,
                              pix_threshold,
                              DHT,
                              None,
                              rast_origin,
                              only_return_areas=True)
        # multiplication with reg_filter required to follow maxDHdem
        # pattern and separate connection of regions with pixels that have
        # value of zero in maxDHdem
        result = DH_Regions.astype(int) * reg_filter
        labels, nr_coherent = measurements.label(result, structure=struct)
        if nr_coherent == 0:
            break
        for i in range(1, nr_coherent + 1):
            temp = labels == i
            q = np.sum(maxDHdem_arr[temp])
            q_inv = np.sum(invest_Euro_arr[temp])
            q_spec_cost = q_inv / q
            if q_spec_cost <= costT and q >= DHT:
                coh_areas[temp] = 1
                hdm_arr[temp] = 0
        labels = None
        nr_coherent = None
    hdm_last_arr = raster_array(hdm_last)
    hdm_1st_arr = raster_array(hdm_1st)
    labels, numLabels = measurements.label(coh_areas, structure=struct)
    if numLabels == 0:
        raise ValueError('For the provided grid cost ceiling, no district '
                         'heating potential area can be realized!')
    if numLabels > 100:
        raise ValueError('For the given scenario, we found more than 100 '
                         'coherent areas. Please reduce the size of your '
                         'selection and run the scenario again!')
    hdm_in_dh_reg = hdm_last_arr * coh_areas
    CM19.main(coh_area_raster, geo_transform, 'int8', coh_areas)
    CM19.main(hdm_dh_reg_last_year, geo_transform, "float64", hdm_in_dh_reg)
    CM19.main(label_raster, geo_transform, "int16", labels)
    # average demand in dh regions: sum_demand/sum_area_of_dhReg
    # MWh/ha
    ave_dem_dh_reg = np.sum(hdm_in_dh_reg) / np.sum(coh_areas)
Beispiel #8
0
def add_label_field(heat_dem_coh_last, heat_dem_spec_area, q, q_spec_cost,
                    economic_bool, area_coh_area, out_raster_coh_area_bool,
                    out_raster_labels, out_raster_maxDHdem,
                    out_raster_economic_maxDHdem, out_shp_prelabel,
                    out_shp_label, epsg=3035):
    color_map = ["#de2d26", "#2ca25f"]
    label_list = []
    
    outDriver = ogr.GetDriverByName("ESRI Shapefile")
    # Remove output shapefile if it already exists
    if os.path.exists(out_shp_label):
        outDriver.DeleteDataSource(out_shp_label)
    bool_arr, gt = RA(out_raster_coh_area_bool, return_gt=True)
    maxDHdem_arr = RA(out_raster_maxDHdem)
    economic_maxDHdem_arr = maxDHdem_arr * bool_arr.astype(int)
    CM19.main(out_raster_economic_maxDHdem, gt, "float64", economic_maxDHdem_arr)
    label_arr = RA(out_raster_labels)
    numLabels = np.max(label_arr)
    coords = measurements.center_of_mass(bool_arr, label_arr,
                                         index=np.arange(1, numLabels+1))
    x0, y0, w, h = gt[0], gt[3], gt[1], gt[5]
    X0 = x0 + w/2
    Y0 = y0 + h/2
    for item in coords:
        xl = round(X0 + 100 * item[1], 1)
        yl = round(Y0 - 100 * item[0], 1)
        label_list.append((xl, yl))
    inDriver = ogr.GetDriverByName("ESRI Shapefile")
    inDataSource = inDriver.Open(out_shp_prelabel, 0)
    inLayer = inDataSource.GetLayer()
    srs = osr.SpatialReference()
    srs.ImportFromEPSG(epsg)
    geom_typ = inLayer.GetGeomType()
    geom_typ_dict = {1: ogr.wkbPoint, 2: ogr.wkbLineString, 3: ogr.wkbPolygon}
    # Create the output Layer
    outDriver = ogr.GetDriverByName("ESRI Shapefile")
    outDataSource = outDriver.CreateDataSource(out_shp_label)
    outLayer = outDataSource.CreateLayer("newSHP", srs,
                                         geom_type=geom_typ_dict[geom_typ])
    Fields = ['Label', 'Economic', 'Dem_last', 'Spec_Dem', 'Potent_DH',
              'Distr_Cost', 'Area', 'color', 'fillColor', 'opacity']
    Fields_dtype = [ogr.OFTInteger, ogr.OFTString, ogr.OFTString, ogr.OFTString,
                    ogr.OFTString, ogr.OFTString, ogr.OFTString, ogr.OFTString,
                    ogr.OFTString, ogr.OFTString]
    for i, f in enumerate(Fields):
        Field = ogr.FieldDefn(f, Fields_dtype[i])
        outLayer.CreateField(Field)
    # Get the output Layer's Feature Definition
    outLayerDefn = outLayer.GetLayerDefn()
    econ_bool_dict = {0: " No", 1: " Yes"}
    for feature in inLayer:
        geom = feature.GetGeometryRef()
        centroid = geom.Centroid()
        x = round(centroid.GetX(), 1)
        y = round(centroid.GetY(), 1)
        outFeature = ogr.Feature(outLayerDefn)
        try:
            geom_label = label_list.index((x, y))
        except:
            nearest_dist = 1000
            for p, point in enumerate(label_list):
                x_temp, y_temp = point
                temp_dist = ((x-x_temp)**2 + (y-y_temp)**2)**0.5
                if temp_dist < nearest_dist:
                    geom_label = p
        outFeature.SetField(outLayerDefn.GetFieldDefn(0).GetNameRef(),
                            geom_label+1)
        outFeature.SetField(outLayerDefn.GetFieldDefn(1).GetNameRef(),
                            econ_bool_dict[int(economic_bool[geom_label])])
        # demand in GWh
        outFeature.SetField(outLayerDefn.GetFieldDefn(2).GetNameRef(),
                            str(round(heat_dem_coh_last[geom_label]/1000, 2)) + " GWh")
        outFeature.SetField(outLayerDefn.GetFieldDefn(3).GetNameRef(),
                            str(round(heat_dem_spec_area[geom_label], 2)) + " MWh/ha")
        # potential in GWh
        outFeature.SetField(outLayerDefn.GetFieldDefn(4).GetNameRef(),
                            str(round(q[geom_label]/1000, 2)) + " GWh")
        outFeature.SetField(outLayerDefn.GetFieldDefn(5).GetNameRef(),
                            str(round(q_spec_cost[geom_label], 2)) + " EUR/MWh")
        outFeature.SetField(outLayerDefn.GetFieldDefn(6).GetNameRef(),
                            str(area_coh_area[geom_label]) + " hectare")
        outFeature.SetField(outLayerDefn.GetFieldDefn(7).GetNameRef(),
                            color_map[int(economic_bool[geom_label])])
        outFeature.SetField(outLayerDefn.GetFieldDefn(8).GetNameRef(),
                            color_map[int(economic_bool[geom_label])])
        outFeature.SetField(outLayerDefn.GetFieldDefn(9).GetNameRef(),
                            "0.7")
        outFeature.SetGeometry(geom)
        # Add new feature to output Layer
        outLayer.CreateFeature(outFeature)
        outFeature = None
    # Save and close DataSources
    inDataSource = None
    outDataSource = None
    if os.path.exists(out_shp_prelabel):
        outDriver.DeleteDataSource(out_shp_prelabel)
Beispiel #9
0
def dh_demand(c1, c2, raster_plotratio, raster_hdm, start_year, last_year,
              accumulated_energy_saving, dh_connection_rate_1st_year,
              dh_connection_rate_last_year, depr_period, interest,
              output_layers, dA_slope=0.0486, dA_intercept=0.0007,
              dataType='float32'):
    '''
    Important Note:
    1) Here, for the calculation of plot ratio, I used gross floor area raster
    in one hectar resolution (unit: m2). It should be divided by 1e4 to get the
    plot ratio.
    2) if you have plot ratio raster, remove the 1e4 factor.
    3) Distribution cost is calculated for those pixel that their corresponding
    pipe diameter is equal or greater than 0.
    the input heat density map should be in GWh/km2.
    '''
    horizon = int(last_year) - int(start_year) + 1
    horizon = int(horizon)
    if horizon > int(depr_period):
        horizon = depr_period
        remaining_years = 0
    else:
        remaining_years = int(depr_period) - int(horizon)

    energy_reduction_factor = (1-float(accumulated_energy_saving))**(1/(horizon-1))
    hdm_ds = gdal.Open(raster_hdm)
    hdm_band = hdm_ds.GetRasterBand(1)
    hdm = hdm_band.ReadAsArray().astype(float)
    geo_transform = hdm_ds.GetGeoTransform()
    plotRatio_ds = gdal.Open(raster_plotratio)
    plotRatio_band = plotRatio_ds.GetRasterBand(1)
    # gfa in hectar should be devided by 10000 to get right values for
    # plot ratio (m2/m2).
    plotRatio = plotRatio_band.ReadAsArray().astype(float)/10000.0
    hdm_ds = plotRatio_ds = None
    row, col = np.nonzero((hdm > 0).astype(int) * (plotRatio > 0.0).astype(int))
    # unit conversion from MWh/ha to GJ/m2
    sparseDemand = 0.00036*hdm[row, col]
    PR_sparse = plotRatio[row, col]
    # the unit for L is m however in each m2
    # L is in m: to get the value for each pixel (ha) you should multiply it
    # by 10000 because 1 pixel has 10000 m2
    # The following formulation of L comes from Persson et al. 2019 paper with
    # the title "Heat Roadmap Europe: Heat distribution costs"
    L = 1 / ((PR_sparse <= 0.4).astype(int) * (137.5*PR_sparse + 5) + (PR_sparse > 0.4).astype(int) * 60)
    # initialize the variables
    q = 0
    # q_new = dh_connection_rate_1st_year * sparseDemand
    q_tot = np.copy(sparseDemand)
    q_max = np.zeros_like(q_tot)
    for i in range(horizon):
        q_tot = sparseDemand * energy_reduction_factor**i
        q_new = q_tot * (float(dh_connection_rate_1st_year) + i * (float(dh_connection_rate_last_year) - float(dh_connection_rate_1st_year))/(horizon-1))
        # q_new is a non-zero sparse matrix. The development of demand can be
        # checked by comparing just one element of q_new with q_max.
        if q_new[0] > q_max[0]:
            q_max = np.copy(q_new)
        q += q_new / (1 + float(interest))**i
    if remaining_years > 0:
        if interest > 0:
            alpha_horizon = annuity(interest, horizon-1)
            alpha_depr = annuity(interest, depr_period)
            rest_annuity_factor = alpha_depr - alpha_horizon
            q = q + q_new * rest_annuity_factor
        else:
            q = q + q_new * remaining_years
    linearHeatDensity = q_max / L
    # this step is performed to avoid negative average pipe diameter
    LHD_THRESHOLD = -dA_intercept/dA_slope
    filtered_LHD = (np.log(linearHeatDensity) < LHD_THRESHOLD).astype(int)
    elements = np.nonzero(filtered_LHD)[0]
    dA = dA_slope * (np.log(linearHeatDensity)) + dA_slope
    dA[elements] = 0
    # lower limit of linear heat densities at 1.5 GJ/m was set. Below this
    # threshold, pipe diameters of 0.02m were applied uniformly for all hectare
    # grid cells with present heat density values above zero.
    # Note: linearHeatDensity is calculated for cells with heat demand above zero
    dA[((linearHeatDensity < 1.5).astype(int) * (dA > 0).astype(int)).astype(bool)] = 0.02
    q_max[elements] = 0
    denominator = q / L
    """ # old code
    cf1, cf2 = cost_factors(c1, c2, PR_sparse)
    divisor = cf1[1] + cf2[1]*dA
    """
    divisor = c1 + c2*dA
    divisor[elements] = 0
    investment = divisor/denominator
    finalInvestment = np.zeros_like(hdm, dtype=dataType)
    # from Euro/GJ/m2 to Euro/MWh/m2
    finalInvestment[row, col] = investment*3.6
    maxDHdem_arr = np.zeros_like(finalInvestment, dtype=dataType)
    # max DH demand density in MWh within the study horizon
    maxDHdem_arr[row, col] = q_max*10000/3.6

    invest_Euro_arr = maxDHdem_arr * finalInvestment
    hdm_last_year = np.zeros_like(finalInvestment, dtype=dataType)
    # total demand in the last year of study horizon in MWh/ha
    hdm_last_year[row, col] = q_tot*10000/3.6
    # Length of pipes (L)
    length = np.zeros_like(finalInvestment, dtype=dataType)
    length[row, col] = L
    length[row, col][elements] = 0
    maxDHdem, invest_Euro, hdm_cut_last_year, total_pipe_length = output_layers
    rm_file(maxDHdem, invest_Euro, hdm_cut_last_year, total_pipe_length)
    CM19.main(maxDHdem, geo_transform, dataType, maxDHdem_arr)
    CM19.main(invest_Euro, geo_transform, dataType, invest_Euro_arr)
    CM19.main(hdm_cut_last_year, geo_transform, dataType, hdm_last_year)
    CM19.main(total_pipe_length, geo_transform, dataType, length)
    """
Beispiel #10
0
def clip_raster(rast, features_path, output_dir, gt, nodata=-9999,
                save2csv=None, save2raster=None, save2shp=None,
                unit_multiplier=None, return_array=False, OutputSRS=3035,
                suffix_namefield=None, add_suffix=None):
    '''
    Clips a raster (given a numpy.array and its geo-transform array) to a
    polygon layer provided by a Shapefile (or other vector layer). Returns an
    array. Clip features can be multi-part geometry and with interior ring
    inside them.

    The code supports most of raster and clip vector arrangements; however,
    it does not support cases in which clip vector extent (envlope of it) goes
    beyond more than 2 sides of the raster.

    Arguments:
        rast               A NumPy array
        features_path      The path to the clipping layer
        gt                 GDAL GeoTransform array
        nodata             The NoData value; defaults to -9999
        save2csv           should the outputs be saved in a csv file as well?
        unit_multiplier    Factor to be multiplied into the summation to
                           output the desired unit.
        suffix_namefield   What to add at the end of the file name. must be field of shape file
    '''

    def image_to_array(i):
        '''
        Converts a Python Imaging Library (PIL) array to a gdalnumeric image.
        '''
        a = gdalnumeric.fromstring(i.tobytes(), 'b')
        a.shape = i.im.size[1], i.im.size[0]
        return a

    def world_to_pixel(geo_matrix, x, y):
        '''
        Uses a gdal geomatrix (gdal.GetGeoTransform()) to calculate
        the pixel location of a geospatial coordinate;
        '''
        ulX = geo_matrix[0]
        ulY = geo_matrix[3]
        xDist = geo_matrix[1]
        yDist = geo_matrix[5]
        rtnX = geo_matrix[2]
        rtnY = geo_matrix[4]
        pixel = int((x - ulX) / xDist)
        line = int((ulY - y) / xDist)
        return (pixel, line)

    clip_complete = None
    # get shapefile name
    shpName = features_path.replace('\\', '/')
    shpName = shpName.split('/')[-1][0:-4]
    # Create a data array for the output csv
    if save2csv:
        feat = []
        demand = []
    if unit_multiplier is None:
        unit_multiplier = 1.0
    xRes, yRes = rast.shape
    # Create an OGR layer from a boundary shapefile
    features = ogr.Open(features_path)
    if features.GetDriver().GetName() == 'ESRI Shapefile':
        temp = os.path.split(os.path.splitext(features_path)[0])
        lyr = features.GetLayer(temp[1])
    else:
        lyr = features.GetLayer()
    for fid in range(lyr.GetFeatureCount()):
        flag = np.zeros(4)
        '''
        if fid > 40:
            continue
        '''
        poly = lyr.GetFeature(fid)
        geom = poly.GetGeometryRef()
        if suffix_namefield is not None:
            suffix = poly.GetField(suffix_namefield)
            if add_suffix is not None:
                suffix = '_'+ add_suffix + '_'+ suffix
        else:
            suffix = 'feature_' + str(fid)  
        # Convert the feature extent to image pixel coordinates
        minX, maxX, minY, maxY = geom.GetEnvelope()
        ulX, ulY = world_to_pixel(gt, minX, maxY)
        lrX, lrY = world_to_pixel(gt, maxX, minY)
        # Calculate the pixel size of the new image
        pxWidth = int(lrX - ulX)
        pxHeight = int(lrY - ulY)
        # If the clipping features extend out-of-bounds and ABOVE the raster...
        if gt[3] < maxY:
            if gt[3] < minY:
                continue
            else:
                # In such a case. ulY ends up being negative--can't have that!
                ulY = 0
                flag[0] = 1
        if gt[0] > minX:
            if gt[0] > maxX:
                continue
            else:
                ulX = 0
                flag[1] = 1
        rastXmax = gt[0] + yRes * gt[1]
        if rastXmax < maxX:
            if rastXmax < minX:
                continue
            else:
                lrX = yRes
                flag[2] = 1
        rastYmin = gt[3] + xRes * gt[5]
        if rastYmin > minY:
            if rastYmin > maxY:
                continue
            else:
                lrY = xRes
                flag[3] = 1
        flag_sum = np.sum(flag)
        # Multi-band image?
        try:
            clip = rast[:, ulY:lrY, ulX:lrX]
        except IndexError:
            clip = rast[ulY:lrY, ulX:lrX]
        geometry_counts = geom.GetGeometryCount()
        clip_complete = np.zeros((pxHeight, pxWidth), clip.dtype)
        # perform the process for multi-part features
        for i in range(geometry_counts):
            # Do not delete this. Clip is set to None in each iteration and
            # should be initialized here again.
            try:
                clip = rast[:, ulY:lrY, ulX:lrX]
            except IndexError:
                clip = rast[ulY:lrY, ulX:lrX]
            # Create a new geomatrix for the image
            gt2 = list(gt)
            gt2[0] = gt2[1]*int(minX/gt2[1])
            gt2[3] = gt2[1]*int(maxY/gt2[1])
            if gt2[3] < maxY:
                gt2[3] = gt2[1] * int(maxY/gt2[1] + 1)
            # Map points to pixels for drawing the boundary on a blank 8-bit,
            # black and white, mask image.
            points = []
            pixels = []
            # check multi-part geometries
            if geometry_counts > 1:
                geom1 = geom.GetGeometryRef(i)
                # check multi-part geometry with interior ring
                if geom1.GetGeometryName() == 'LINEARRING':
                    pts = geom1
                else:
                    # get outer ring of polygon
                    pts = geom1.GetGeometryRef(0)
                # print(geom1.GetGeometryName() + ' ' + pts.GetGeometryName())
            else:
                # get outer ring of polygon
                pts = geom.GetGeometryRef(0)
            for p in range(pts.GetPointCount()):
                points.append((pts.GetX(p), pts.GetY(p)))
            for p in points:
                pixels.append(world_to_pixel(gt2, p[0], p[1]))
            raster_poly = Image.new('L', (pxWidth, pxHeight), 1)
            rasterize = ImageDraw.Draw(raster_poly)
            # Fill with zeroes
            rasterize.polygon(pixels, 0)
            premask = image_to_array(raster_poly)
            # with the calculated geotransform matrix gt2, clip matrix should
            # have the same dimension as premask
            clip_new = np.zeros_like(premask, clip.dtype)
            if flag_sum == 0:
                mask = premask
                clip_new = gdalnumeric.choose(mask, (clip, nodata))
            else:
                if flag_sum < 3:
                    row_clip, col_clip = clip.shape
                    index = np.array([-flag[0]*row_clip, flag[3]*row_clip,
                                      -flag[1]*col_clip, flag[2]*col_clip]
                                     ).astype(int)
                    mask_index = np.where(index == 0, None, index)
                    mask = premask[mask_index[0]:mask_index[1],
                                   mask_index[2]:mask_index[3]]
                    clip = gdalnumeric.choose(mask, (clip, nodata))
                    clip_new[mask_index[0]:mask_index[1],
                             mask_index[2]:mask_index[3]] = clip
                else:
                    s = 1
#                    raise InputError('Clip for the feature %d is not '
#                                     'supported' % fid)
            m1, n1 = np.nonzero(clip_new)
            clip_stack = set(list(zip(m1, n1)))
            m2, n2 = np.nonzero(clip_complete)
            clip_complete_stack = set(list(zip(m2, n2)))
            intersect_clip = clip_complete_stack.intersection(clip_stack)
            if len(intersect_clip) == 0:
                clip_complete = clip_complete + clip_new
            else:
                clip_complete = clip_complete - clip_new
            mask = None
            premask = None
            raster_poly = None
            rasterize = None
            geom1 = None
            pts = None
            gt3 = gt2
            gt2 = None
            clip = None
            clip_new = None
        if save2csv:
            nuts_region = str(poly.GetField(0))
            dem_sum = np.sum(clip_complete) * unit_multiplier
            if dem_sum > 0:
                feat.append(nuts_region)
                demand.append(dem_sum)
                print('The sum of values within the region %s is: %0.1f'
                      % (nuts_region, dem_sum))
        if save2raster:
            if not save2csv:
                dem_sum = np.sum(clip_complete) * unit_multiplier
            if dem_sum > 0:
                outRasterPath = output_dir + os.sep + shpName + '_feature_' + \
                                str(fid) + '.tif'
                outRasterPath = output_dir + os.sep + shpName + '_' + \
                                suffix + '.tif'
                CM19.main(outRasterPath, gt3, str(clip_complete.dtype),
                          clip_complete, 0)
    if save2csv or save2shp:
        saveCSVorSHP(feat, demand, features_path, output_dir, shpName,
                     save2csv, save2shp, OutputSRS=OutputSRS)
    if return_array:
        return clip_complete, gt3