def processShapes(x): # Reaging Geometry shape = shapes[x] p = shape.points p = np.array(p) lon_g = p[:, 0] lat_g = p[:, 1] # Reading the Record records = sf.record(x) rec1 = records[-1] # # Calculating the angle # seg = length.dist(p) # ang = angle.alpha(seg) # rec2 = round(ang,1) # Caluculating the vertical surface area perim = perimeter.per(p) area = perim * rec1 # Tranforming the coordinates [lon_r, lat_r] = geo2rot.g2r(lon_g, lat_g) # Calculating the Area rec3 = 0.5 * np.abs( np.dot(lon_r, np.roll(lat_r, 1)) - np.dot(lat_r, np.roll(lon_r, 1))) # Caluculating the vertical surface area perim = perimeter.per(p) rec2 = perim * rec1 # Defining back the Geometry p_r = [lon_r, lat_r] p_r = np.transpose(p_r) p_r = np.array(p_r).tolist() # Writing the Geometry w.poly(parts=[p_r]) w.record(rec1, rec2, rec3)
def wgs(ufrac_path, threshold, thr_val, rlat_v, rlon_v, FR_URBAN): # Inizializations FR_URBAN_count = copy.deepcopy(FR_URBAN) # Read the dataset ufrac = gdal.Open(ufrac_path) # Create lat and lon arrays lon_res = ufrac.GetGeoTransform()[1] lon_l = ufrac.GetGeoTransform()[0] lon_r = ufrac.GetGeoTransform()[0] + ufrac.RasterXSize * lon_res lon = np.arange(lon_l, lon_r, lon_res) lat_res = ufrac.GetGeoTransform()[5] lat_l = ufrac.GetGeoTransform()[3] + lat_res lat_r = ufrac.GetGeoTransform()[3] + ufrac.RasterYSize * lat_res lat = np.arange(lat_l, lat_r, lat_res) lon_s_1 = np.zeros((len(lat), len(lon))) lat_s_1 = np.zeros((len(lat), len(lon))) for j in range(0, len(lat)): lon_s_1[j, :] = lon for j in range(0, len(lon)): lat_s_1[:, j] = lat # Read band data1 = ufrac.ReadAsArray() data1 = data1.astype(float) # Write FR_URB into cosmo output for j in range(0, len(lon)): for k in range(0, len(lat)): data1_tmp = data1[k, j] # Identify corresponding grid cell [lonC, latC] = np.array(geo2rot.g2r(lon_s_1[k, j], lat_s_1[k, j])) lon_idx = np.abs(rlon_v - lonC).argmin() lat_idx = np.abs(rlat_v - latC).argmin() # Calculate urban fraction contribution data1_tmp = data1_tmp / 100. FR_URBAN_count[0, lat_idx, lon_idx] += 1. if threshold == 1: if data1_tmp >= thr_val: FR_URBAN[0, lat_idx, lon_idx] += 1. elif threshold == 0: FR_URBAN[0, lat_idx, lon_idx] += data1_tmp # Disable division by 0 error np.seterr(divide='ignore') FR_URBAN = FR_URBAN / FR_URBAN_count return FR_URBAN, data1, lat_s_1, lon_s_1
def lidar(veg_path, thr_val, data1, rlat_v, rlon_v, lat_s_1, lon_s_1, \ LAD_C, OMEGA, LAI_URB, greening): # Inizializations # Read the dataset print('Reading tree dataset') veg = gdal.Open(veg_path) # Create lat and lon arrays lon_res = veg.GetGeoTransform()[1] lon_l = veg.GetGeoTransform()[0] lon_r = veg.GetGeoTransform()[0] + veg.RasterXSize * lon_res lon = np.arange(lon_l, lon_r, lon_res) lat_res = veg.GetGeoTransform()[5] lat_l = veg.GetGeoTransform()[3] + lat_res lat_r = veg.GetGeoTransform()[3] + veg.RasterYSize * lat_res lat = np.arange(lat_l, lat_r, lat_res) lon_s_2 = np.zeros((len(lat), len(lon))) lat_s_2 = np.zeros((len(lat), len(lon))) for j in range(0, len(lat)): lon_s_2[j, :] = lon for j in range(0, len(lon)): lat_s_2[:, j] = lat # Read band data2 = veg.ReadAsArray() data2 = data2.astype(float) # Remove anomalous values data2[data2 > 20] = 20 # no trees taller than 20 m # Calculations print('Calculating LAD') # status info OMEGA[0, :, :] = 0.5 # more relistic value for now # Write LAD into cosmo output for j in range(0, len(lon)): for k in range(0, len(lat)): h_veg_tmp = data2[k, j] if h_veg_tmp > 0.: # Identify corresponding grid cell [lonV, latV] = np.array(geo2rot.g2r(lon_s_2[k, j], lat_s_2[k, j])) lon_idx = np.abs(rlon_v - lonV).argmin() lat_idx = np.abs(rlat_v - latV).argmin() # Calculate LAD from Lidar canopy height area_lidar = 1. # m2 mesured in GIS LAD_spec = 1. # m2 m-3 (Klingberg et al., 2017) area_grid = 278.93 * 278.93 # m2 h_ug = 5. # m, height urban grida h_cbase = 3. # m, height of the canopy base # Check if in-canyon vegetation lon_urb_idx = np.abs(lon_s_1[0, :] - lon_s_2[k, j]).argmin() lat_urb_idx = np.abs(lat_s_1[:, 0] - lat_s_2[k, j]).argmin() data1_tmp = data1[lat_urb_idx, lon_urb_idx] if data1_tmp >= thr_val: # In-canyon vegetation if h_veg_tmp >= h_cbase: LAD_C[0,:,0,lat_idx,lon_idx] += LAD_spec * area_lidar * \ (min(h_veg_tmp,h_ug) - h_cbase) / area_grid / h_ug if h_veg_tmp >= 5: LAD_C[0,:,1,lat_idx,lon_idx] += LAD_spec * (min(h_veg_tmp,10)-5)/h_ug \ * area_lidar / area_grid if h_veg_tmp >= 10: LAD_C[0,:,2,lat_idx,lon_idx] += LAD_spec * (min(h_veg_tmp,15)-10)/h_ug \ * area_lidar / area_grid if h_veg_tmp >= 15: LAD_C[0,:,3,lat_idx,lon_idx] += LAD_spec * (min(h_veg_tmp,20)-15)/h_ug \ * area_lidar / area_grid if h_veg_tmp >= 20: LAD_C[0,:,4,lat_idx,lon_idx] += LAD_spec * (min(h_veg_tmp,25)-20)/h_ug \ * area_lidar / area_grid if h_veg_tmp >= 25: LAD_C[0,:,5,lat_idx,lon_idx] += LAD_spec * (min(h_veg_tmp,30)-25)/h_ug \ * area_lidar / area_grid if h_veg_tmp >= 30: LAD_C[0,:,6,lat_idx,lon_idx] += LAD_spec * (min(h_veg_tmp,35)-30)/h_ug \ * area_lidar / area_grid if h_veg_tmp >= 35: LAD_C[0,:,7,lat_idx,lon_idx] += LAD_spec * (min(h_veg_tmp,40)-35)/h_ug \ * area_lidar / area_grid if h_veg_tmp >= 40: LAD_C[0,:,8,lat_idx,lon_idx] += LAD_spec * (min(h_veg_tmp,45)-40)/h_ug \ * area_lidar / area_grid if h_veg_tmp >= 45: LAD_C[0,:,9,lat_idx,lon_idx] += LAD_spec * (min(h_veg_tmp,50)-45)/h_ug \ * area_lidar / area_grid if h_veg_tmp >= 50: LAD_C[0,:,10,lat_idx,lon_idx] += LAD_spec * (min(h_veg_tmp,55)-50)/h_ug \ * area_lidar / area_grid if h_veg_tmp >= 55: LAD_C[0,:,11,lat_idx,lon_idx] += LAD_spec * (min(h_veg_tmp,60)-55)/h_ug \ * area_lidar / area_grid else: # Out-canyon vegetation LAI_URB[0,lat_idx,lon_idx] += LAD_spec * area_lidar * (h_veg_tmp-h_cbase) \ / area_grid if greening == True: # use greening scenario print('greeing scenario active') LAD_C_tmp = np.ma.masked_where(LAD_C == 0, LAD_C) LAD_C = LAD_C * (1 + 2.33 * np.exp(-1 * LAD_C_tmp / LAD_C_tmp.mean())) LAD_C = np.ma.filled(LAD_C, 0) return LAD_C, OMEGA, LAI_URB
def shp(sf_path, rlat_d, rlon_d, udir_d, uheight1_d, rlat_v, rlon_v, \ FR_URBAN, FR_ROOF, norm_vert): # Inizializations AREA_BLD = np.zeros((1, rlat_d, rlon_d)) BUILD_W = np.zeros((1, udir_d, rlat_d, rlon_d)) FR_STREETD = np.zeros((1, udir_d, rlat_d, rlon_d)) LAMBDA_F = np.zeros((1, udir_d, rlat_d, rlon_d)) LAMBDA_P = np.zeros((1, rlat_d, rlon_d)) MEAN_HEIGHT = np.zeros((1, rlat_d, rlon_d)) STREET_W = np.zeros((1, udir_d, rlat_d, rlon_d)) VERT_AREA = np.zeros((1, udir_d, rlat_d, rlon_d)) # Read the dataset sf = shapefile.Reader(sf_path) shapes = sf.shapes() # Calculations N = len(shapes) for x in range(0, N): # Reading Geometry shape = shapes[x] p = shape.points p = np.array(p) # Reading the Area (horizontal) area = sf.record(x)[4] # Calculating the coordinates of the centroid of the polygon lonC = np.mean(p[:, 0]) latC = np.mean(p[:, 1]) # Converting centroid to rotated coordinates [lonC_r, latC_r] = geo2rot.g2r(lonC, latC) # Calculating the index of the correspoding grid point lon_idx = np.abs(rlon_v - lonC_r).argmin() lat_idx = np.abs(rlat_v - latC_r).argmin() # Allocating the total building area AREA_BLD[0, lat_idx, lon_idx] += area # Clustering the geomerty heights hgt = sf.record(x)[0] MEAN_HEIGHT[0, lat_idx, lon_idx] += hgt * area hgt_class = cluster.height_old(hgt) # Looping over building segments (facades) for k in range(1, len(p)): vert_area = geometry.distWGS(p, k) * hgt ang = geometry.angle(p, k) ang_class = cluster.angle(ang) # VERT_AREA[0, ang_class, lat_idx, lon_idx] += vert_area # Allocating the building area by direction and height FR_ROOF[0, ang_class, hgt_class, lat_idx, lon_idx] += vert_area # Calculating the area densities (Grimmond and Oke, 1998) np.seterr(divide='ignore') # disabled division by 0 warning area_grid = 77970 # m2, calculated in GIS. TO DO: calculate from grid lambda_p = AREA_BLD[0, :, :] / (area_grid * FR_URBAN[0, :, :]) lambda_p[lambda_p > 0.9] = 0.9 # upper limit lambda_p[lambda_p < 0.1] = 0.1 # lower limit lambda_f = VERT_AREA[0, :, :, :] / (area_grid * FR_URBAN[0, :, :]) lambda_f[lambda_f > 0.9] = 0.9 # upper limit lambda_f[lambda_f < 0.1] = 0.1 # lower limit LAMBDA_P[0, :, :] = lambda_p LAMBDA_F[0, :, :, :] = lambda_f # Calculating the street and building widths (Martilli, 2009) h_m = MEAN_HEIGHT[0, :, :] / AREA_BLD[0, :, :] h_m[h_m == 15] = 10. BUILD_W[0, :, :, :] = lambda_p[np.newaxis, :, :] / lambda_f[:, :, :] * h_m STREET_W[0,:,:,:] = (1 / lambda_p[np.newaxis,:,:] - 1) * lambda_p[np.newaxis,:,:] \ / lambda_f * h_m #STREET_W[STREET_W<5] = 5 # min aspect ration LCZ 2 #STREET_W[STREET_W>100] = 100 # max aspect ration LCZ 9 # Calculating and normalizing the canyon direction distribution FR_STREETD = np.sum(FR_ROOF, 2) norm_streetd = np.sum(FR_STREETD, 1) FR_STREETD = FR_STREETD / norm_streetd # Normalizing FR_ROOF if norm_vert == True: norm_fr_roof = np.sum(FR_ROOF, 2) else: norm_fr_roof = np.sum(FR_ROOF, 1) for j in range(0, udir_d): for k in range(0, uheight1_d): for o in range(0, rlat_d): for z in range(0, rlon_d): if norm_vert == True: if norm_fr_roof[0, j, o, z] != 0: FR_ROOF[0, j, k, o, z] = FR_ROOF[0, j, k, o, z] / norm_fr_roof[0, j, o, z] else: if norm_fr_roof[0, k, o, z] != 0: FR_ROOF[0, j, k, o, z] = FR_ROOF[0, j, k, o, z] / norm_fr_roof[0, k, o, z] FR_ROOF[FR_ROOF < 0.001] = 0 # to avoid negative values return BUILD_W, STREET_W, FR_ROOF, FR_STREETD, shapes
def point(ncd_name, lon, lat): ########################## # Inputs # ncd = path to netcdf file # lon = geographical longitude # lat = geographical latitude # Outputs # dq = convective heat flux [W m-2] ############################# # constants cps = 1000 # J kg-1 K-1 heat capacity of the air # read grid variables ncd = Dataset(ncd_name, 'r') rlon = ncd.variables['rlon'][:] rlat = ncd.variables['rlat'][:] vcoord = ncd.variables['vcoord'] # indexes from lon and lat [lon_r, lat_r] = geo2rot.g2r(lon, lat) idx = np.abs(rlon - (lon_r)).argmin() idy = np.abs(rlat - (lat_r)).argmin() # read variables u = ncd.variables['U'][0, -1, :, :] v = ncd.variables['V'][0, -1, :, :] t = ncd.variables['T'][0, -1, :, :] #w = ncd.variables['W'][0,-1,:,:] only horizontal tup = ncd.variables['T'][0, -2, :, :] rho = ncd.variables['RHO'][0, -1, :, :] rhoup = ncd.variables['RHO'][0, -2, :, :] # additional variables lat = ncd.variables['lat'][:, :] lon = ncd.variables['lon'][:, :] # cell size dx1 = abs( geom.dist(lon[idy, idx], lat[idy, idx], lon[idy, idx - 1], lat[idy, idx - 1])) dx2 = abs( geom.dist(lon[idy, idx], lat[idy, idx], lon[idy, idx + 1], lat[idy, idx + 1])) dx = (dx1 + dx2) / 2 dy1 = abs( geom.dist(lon[idy, idx], lat[idy, idx], lon[idy - 1, idx], lat[idy - 1, idx])) dy2 = abs( geom.dist(lon[idy, idx], lat[idy, idx], lon[idy + 1, idx], lat[idy + 1, idx])) dy = (dy1 + dy2) / 2 # convert to horizontal h = vcoord[-2] - vcoord[-1] Ax1 = dx1 * h Ax2 = dx2 * h Ay1 = dy1 * h Ay2 = dy2 * h # advective flux q_in_x = Ax1 * cps * ((rho[idy,idx]+rho[idy,idx-1])/2) * \ u[idy,idx] * ((t[idy,idx]+t[idy,idx-1])/2) q_out_x = Ax2 * cps * ((rho[idy,idx]+rho[idy,idx+1])/2) * \ u[idy,idx+1] * ((t[idy,idx]+t[idy,idx+1])/2) q_in_y = Ay1 * cps * ((rho[idy,idx]+rho[idy-1,idx])/2) * \ v[idy,idx] * ((t[idy,idx]+t[idy-1,idx])/2) q_out_y = Ay2 * cps * ((rho[idy,idx]+rho[idy+1,idx])/2) * \ v[idy+1,idx] * ((t[idy,idx]+t[idy+1,idx])/2) Dq_tot = q_in_x - q_out_x + q_in_y - q_out_y # in W Dq_flux = Dq_vol * (dx * dy ) # W / m2 as other turbulent (unresolved) fluxes # vertical component not considered #q_out_z = cps * ((rhoup[idy,idx]+rho[idy,idx])/2) * \ # w[idy+1,idx] * ((tup[idy,idx]+t[idy,idx])/2) return Dq_flux