Changeset 4793 for palm/trunk/SCRIPTS/palm_csd
- Timestamp:
- Nov 24, 2020 9:48:21 AM (4 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
palm/trunk/SCRIPTS/palm_csd
r4749 r4793 25 25 # ----------------- 26 26 # $Id$ 27 # Added output of tree_type (species or classification). Added tree_id for 28 # vegetation patches. Allow for overlapping vegetation with buildings 29 # 30 # 4749 2020-10-16 11:21:27Z maronga 27 31 # Bugfix: processing of patch height faulty for multiple domains 28 32 # … … 164 168 global domain_street_trees 165 169 global domain_canopy_patches 170 global domain_overhanging_trees 166 171 167 172 # Definition of input data parameters … … 250 255 domain_street_trees = [] 251 256 domain_canopy_patches = [] 257 domain_overhanging_trees = [] 252 258 253 259 zt_min = 0.0 … … 349 355 domain_green_roofs.append(config.getboolean(read_tmp, 'vegetation_on_roofs')) 350 356 domain_street_trees.append(config.getboolean(read_tmp, 'street_trees')) 351 357 domain_overhanging_trees.append(config.getboolean(read_tmp, 'overhanging_trees')) 358 352 359 if ( read_tmp.split("_")[0] == 'input' ): 353 360 input_names.append(read_tmp.split("_")[1]) … … 417 424 "vegetation_pars": "f4", 418 425 "tree_data": "f4", 419 "tree_type": "b", 426 "tree_id": "i", 427 "tree_type": "f4", 428 "tree_types": "b", 420 429 "nbuilding_pars": "i", 421 430 "nvegetation_pars": "i", … … 447 456 "vegetation_pars": float(-9999.0), 448 457 "tree_data": float(-9999.0), 449 "tree_type": np.byte(-127) 458 "tree_id": int(-9999), 459 "tree_type": float(-9999.0), 460 "tree_types": np.byte(-127) 450 461 } 451 462 … … 473 484 "buildings_pars": float(-9999.0), 474 485 "tree_data": float(-9999.0), 475 "tree_type": 0,486 "tree_type": np.byte(-127), 476 487 "vegetation_pars": float(-9999.0) 477 488 } … … 963 974 vegetation_pars = nc_read_from_file_2d_all(filename[i], 'vegetation_pars') 964 975 965 lai = n p.copy(vegetation_pars[1,:,:])976 lai = nc_read_from_file_2d(input_file_lai[ii[i]], 'Band1', domain_x0[i], domain_x1[i], domain_y0[i], domain_y1[i]) 966 977 967 978 x = nc_read_from_file_2d_all(filename[i], 'x') … … 991 1002 tree_trunk_diameter = np.where( (tree_trunk_diameter == 0.0) | (tree_trunk_diameter == -1.0) ,fillvalues["tree_data"],tree_trunk_diameter) 992 1003 tree_type = np.where( (tree_type == 0.0) | (tree_type == -1.0) ,fillvalues["tree_data"],tree_type) 993 patch_height = np.where( patch_height == -1.0 ,fillvalues["tree_data"],patch_height) 1004 1005 # For vegetation pixel with missing height information (-1), set default patch height 1006 patch_height = np.where( patch_height == -1.0 ,settings_patch_height_default,patch_height) 994 1007 995 1008 # Convert trunk diameter from cm to m … … 1005 1018 1006 1019 # For zero-height patches, set vegetation_type to short grass and remove these pixels from the patch height array 1007 vegetation_type = np.where( (patch_height == 0.0) & ( (vegetation_type == 4) | (vegetation_type == 5) | (vegetation_type == 6) |(vegetation_type == 7) | (vegetation_type == 17) | (vegetation_type == 18) ),3,vegetation_type) 1008 patch_type = np.where( (patch_height == 0.0) & ( (vegetation_type == 4) | (vegetation_type == 5) | (vegetation_type == 6) |(vegetation_type == 7) | (vegetation_type == 17) | (vegetation_type == 18) ),fillvalues["tree_data"],patch_height) 1009 1020 vegetation_type = np.where( (patch_height == 0.0) & ( (vegetation_type == 4) | (vegetation_type == 5) | (vegetation_type == 6) |(vegetation_type == 7) | (vegetation_type == 17) | (vegetation_type == 18) ),3,vegetation_type) 1021 patch_height = np.where( (patch_height == 0.0) & ( (vegetation_type == 4) | (vegetation_type == 5) | (vegetation_type == 6) |(vegetation_type == 7) | (vegetation_type == 17) | (vegetation_type == 18) ),fillvalues["tree_data"],patch_height) 1010 1022 1011 1023 max_tree_height = max(tree_height.flatten()) … … 1017 1029 if ( (max_tree_height != fillvalues["tree_data"]) | (max_patch_height != fillvalues["tree_data"]) ): 1018 1030 1019 lad, bad, tree_ids, zlad = generate_single_tree_lad(x,y,domain_dz[i],max_tree_height,max_patch_height,tree_type,tree_height,tree_crown_diameter,tree_trunk_diameter,lai,settings_season,fillvalues["tree_data"]) 1020 1031 lad, bad, tree_ids, tree_types, zlad = generate_single_tree_lad(x,y,domain_dz[i],max_tree_height,max_patch_height,tree_type,tree_height,tree_crown_diameter,tree_trunk_diameter,lai,settings_season,fillvalues["tree_data"]) 1021 1032 1022 1033 # Remove LAD volumes that are inside buildings 1023 buildings_2d = nc_read_from_file_2d_all(filename[i], 'buildings_2d') 1024 for k in range(0,len(zlad)-1): 1034 if not domain_overhanging_trees[i]: 1035 buildings_2d = nc_read_from_file_2d_all(filename[i], 'buildings_2d') 1036 for k in range(0,len(zlad)-1): 1025 1037 1026 lad[k,:,:] = np.where(buildings_2d == fillvalues["buildings_2d"],lad[k,:,:],fillvalues["tree_data"])1027 bad[k,:,:] = np.where(buildings_2d == fillvalues["buildings_2d"],bad[k,:,:],fillvalues["tree_data"])1028 tree_ids[k,:,:] = np.where(buildings_2d == fillvalues["buildings_2d"],tree_ids[k,:,:],fillvalues["tree_data"])1029 1030 del buildings_2d1038 lad[k,:,:] = np.where(buildings_2d == fillvalues["buildings_2d"],lad[k,:,:],fillvalues["tree_data"]) 1039 bad[k,:,:] = np.where(buildings_2d == fillvalues["buildings_2d"],bad[k,:,:],fillvalues["tree_data"]) 1040 tree_ids[k,:,:] = np.where(buildings_2d == fillvalues["buildings_2d"],tree_ids[k,:,:],fillvalues["tree_id"]) 1041 1042 del buildings_2d 1031 1043 1044 1032 1045 nc_write_dimension(filename[i], 'zlad', zlad, datatypes["tree_data"]) 1046 1033 1047 nc_write_to_file_3d(filename[i], 'lad', lad, datatypes["tree_data"],'zlad','y','x',fillvalues["tree_data"]) 1034 1048 nc_write_attribute(filename[i], 'lad', 'long_name', 'leaf area density') … … 1037 1051 nc_write_attribute(filename[i], 'lad', 'coordinates', 'E_UTM N_UTM lon lat') 1038 1052 nc_write_attribute(filename[i], 'lad', 'grid_mapping', 'E_UTM N_UTM lon lat') 1039 1053 1040 1054 nc_write_to_file_3d(filename[i], 'bad', bad, datatypes["tree_data"],'zlad','y','x',fillvalues["tree_data"]) 1041 1055 nc_write_attribute(filename[i], 'bad', 'long_name', 'basal area density') … … 1045 1059 nc_write_attribute(filename[i], 'bad', 'grid_mapping', 'E_UTM N_UTM lon lat') 1046 1060 1047 nc_write_to_file_3d(filename[i], 'tree_id', tree_ids, datatypes["tree_ data"],'zlad','y','x',fillvalues["tree_data"])1061 nc_write_to_file_3d(filename[i], 'tree_id', tree_ids, datatypes["tree_id"],'zlad','y','x',fillvalues["tree_id"]) 1048 1062 nc_write_attribute(filename[i], 'tree_id', 'long_name', 'tree id') 1049 1063 nc_write_attribute(filename[i], 'tree_id', 'units', '') … … 1051 1065 nc_write_attribute(filename[i], 'tree_id', 'coordinates', 'E_UTM N_UTM lon lat') 1052 1066 nc_write_attribute(filename[i], 'tree_id', 'grid_mapping', 'E_UTM N_UTM lon lat') 1067 1068 nc_write_to_file_3d(filename[i], 'tree_type', tree_types, datatypes["tree_types"],'zlad','y','x',fillvalues["tree_types"]) 1069 nc_write_attribute(filename[i], 'tree_type', 'long_name', 'tree type') 1070 nc_write_attribute(filename[i], 'tree_type', 'units', '') 1071 nc_write_attribute(filename[i], 'tree_type', 'res_orig', domain_px[i]) 1072 nc_write_attribute(filename[i], 'tree_type', 'coordinates', 'E_UTM N_UTM lon lat') 1073 nc_write_attribute(filename[i], 'tree_type', 'grid_mapping', 'E_UTM N_UTM lon lat') 1053 1074 1054 del lai, lad, bad, tree_ids, zlad 1055 1075 del lai, lad, bad, tree_ids, tree_types, zlad 1076 1077 else: 1078 print('No street trees generated in domain ' + str(i)) 1079 1056 1080 del vegetation_pars, tree_height, tree_crown_diameter, tree_trunk_diameter, tree_type, patch_height, x, y 1057 1081 … … 1061 1085 if domain_canopy_patches[i]: 1062 1086 1063 # Load vegetation_type and lad array (at level z = 0) for re-processing1064 vegetation_type = nc_read_from_file_2d_all(filename[i], 'vegetation_type')1065 lad = nc_read_from_file_3d_all(filename[i], 'lad')1066 zlad = nc_read_from_file_1d_all(filename[i], 'zlad')1067 1087 patch_height = nc_read_from_file_2d(input_file_patch_height[ii[i]], 'Band1', domain_x0[i], domain_x1[i], domain_y0[i], domain_y1[i]) 1068 vegetation_pars = nc_read_from_file_3d_all(filename[i], 'vegetation_pars') 1069 lai = vegetation_pars[1,:,:] 1070 1071 1072 # Determine all pixels that do not already have an LAD but which are high vegetation to a dummy value of 1.0 and remove all other pixels 1073 lai_high = np.where( (lad[0,:,:] == fillvalues["tree_data"]) & ( ( (vegetation_type == 4) | (vegetation_type == 5) | (vegetation_type == 6) |(vegetation_type == 7) | (vegetation_type == 17) | (vegetation_type == 18) ) & ( (patch_height == fillvalues["tree_data"]) | (patch_height >= domain_dz[i])) ),1.0,fillvalues["tree_data"]) 1074 1075 1076 # Treat all pixels where short grass is defined, but where a patch_height >= dz is found, as high vegetation (often the case in backyards) 1077 lai_high = np.where( (lai_high == fillvalues["tree_data"]) & (patch_height >= domain_dz[i]) & (vegetation_type == 3), 1.0, lai_high) 1088 1089 # For vegetation pixel with missing height information (-1), set default patch height 1090 patch_height = np.where( patch_height == -1.0 ,settings_patch_height_default,patch_height) 1091 1092 max_patch_height = max(patch_height.flatten()) 1093 if ( max_patch_height != fillvalues["tree_data"] ): 1094 # Call canopy generator for single trees only if there is any tree height available in the domain. 1095 # This does not guarantee that there are street trees that can be processed. This is checked in the 1096 # canopy generator. 1097 1098 # Load vegetation_type and lad array (at level z = 0) for re-processing 1099 vegetation_type = nc_read_from_file_2d_all(filename[i], 'vegetation_type') 1100 lad = nc_read_from_file_3d_all(filename[i], 'lad') 1101 tree_id = nc_read_from_file_3d_all(filename[i], 'tree_id') 1102 tree_types = nc_read_from_file_3d_all(filename[i], 'tree_type') 1103 zlad = nc_read_from_file_1d_all(filename[i], 'zlad') 1104 vegetation_pars = nc_read_from_file_3d_all(filename[i], 'vegetation_pars') 1105 lai = nc_read_from_file_2d(input_file_lai[ii[i]], 'Band1', domain_x0[i], domain_x1[i], domain_y0[i], domain_y1[i]) 1106 1107 nc_write_to_file_2d(filename[i], 'patch_height', patch_height, datatypes["tree_data"],'y','x',fillvalues["tree_data"]) 1108 nc_write_attribute(filename[i], 'patch_height', 'long_name', 'tree type') 1109 nc_write_attribute(filename[i], 'patch_height', 'units', '') 1110 nc_write_attribute(filename[i], 'patch_height', 'res_orig', domain_px[i]) 1111 nc_write_attribute(filename[i], 'patch_height', 'coordinates', 'E_UTM N_UTM lon lat') 1112 nc_write_attribute(filename[i], 'patch_height', 'grid_mapping', 'E_UTM N_UTM lon lat') 1113 1114 # Determine all pixels that do not already have an LAD but which are high vegetation to a dummy value of 1.0 and remove all other pixels 1115 lai_high = np.where( (lad[0,:,:] == fillvalues["tree_data"]) & ( ( (vegetation_type == 4) | (vegetation_type == 5) | (vegetation_type == 6) |(vegetation_type == 7) | (vegetation_type == 17) | (vegetation_type == 18) ) & ( (patch_height == fillvalues["tree_data"]) | (patch_height >= domain_dz[i])) ),1.0,fillvalues["tree_data"]) 1116 1117 1118 # Treat all pixels where short grass is defined, but where a patch_height >= dz is found, as high vegetation (often the case in backyards) 1119 lai_high = np.where( (lai_high == fillvalues["tree_data"]) & (patch_height >= domain_dz[i]) & (vegetation_type == 3), 1.0, lai_high) 1078 1120 1079 # Now, assign either the default LAI for high vegetation or keep 1.0 from the lai_high array. 1080 lai_high = np.where( (lai_high != fillvalues["tree_data"]) & (lai == fillvalues["tree_data"]), settings_lai_high_default, lai_high) 1081 1082 # If LAI values are available in the LAI array, write them on the lai_high array 1083 lai_high = np.where( (lai_high != fillvalues["tree_data"]) & (lai != fillvalues["tree_data"]), lai, lai_high) 1084 1085 1086 # Define a patch height wherever it is missing, but where a high vegetation LAI was set 1087 patch_height = np.where ( (lai_high != fillvalues["tree_data"]) & (patch_height == fillvalues["tree_data"]), settings_patch_height_default, patch_height) 1088 1089 1090 # Remove pixels where street trees were already set 1091 patch_height = np.where ( (lad[0,:,:] != fillvalues["tree_data"]), fillvalues["tree_data"], patch_height) 1092 1093 # Remove patch heights that have no lai_high value 1094 patch_height = np.where ( (lai_high == fillvalues["tree_data"]), fillvalues["tree_data"], patch_height) 1095 1096 # For missing LAI values, set either the high vegetation default or the low vegetation default 1097 lai_high = np.where( (patch_height > 2.0) & (patch_height != fillvalues["tree_data"]) & (lai_high == fillvalues["tree_data"]),settings_lai_high_default,lai_high) 1098 lai_high = np.where( (patch_height <= 2.0) & (patch_height != fillvalues["tree_data"]) & (lai_high == fillvalues["tree_data"]),settings_lai_low_default,lai_high) 1121 # If overhanging trees are allowed, assign pixels with patch_height > dz that are not included in vegetation_type to high 1122 if domain_overhanging_trees[i]: 1123 lai_high = np.where( (lai_high == fillvalues["tree_data"]) & (patch_height >= domain_dz[i]), 1.0, lai_high) 1124 1125 # Now, assign either the default LAI for high vegetation or keep 1.0 from the lai_high array. 1126 lai_high = np.where( (lai_high != fillvalues["tree_data"]) & (lai == fillvalues["tree_data"]), settings_lai_high_default, lai_high) 1127 1128 # If LAI values are available in the LAI array, write them on the lai_high array 1129 lai_high = np.where( (lai_high != fillvalues["tree_data"]) & (lai != fillvalues["tree_data"]), lai, lai_high) 1130 1131 1132 # Define a patch height wherever it is missing, but where a high vegetation LAI was set 1133 patch_height = np.where ( (lai_high != fillvalues["tree_data"]) & (patch_height == fillvalues["tree_data"]), settings_patch_height_default, patch_height) 1134 1135 1136 # Remove pixels where street trees were already se 1137 patch_height = np.where ( (lad[0,:,:] != fillvalues["tree_data"]), fillvalues["tree_data"], patch_height) 1138 1139 # Remove patch heights that have no lai_high value 1140 patch_height = np.where ( (lai_high == fillvalues["tree_data"]), fillvalues["tree_data"], patch_height) 1141 1142 1143 1144 1145 # For missing LAI values, set either the high vegetation default or the low vegetation default 1146 lai_high = np.where( (patch_height > 2.0) & (patch_height != fillvalues["tree_data"]) & (lai_high == fillvalues["tree_data"]),settings_lai_high_default,lai_high) 1147 lai_high = np.where( (patch_height <= 2.0) & (patch_height != fillvalues["tree_data"]) & (lai_high == fillvalues["tree_data"]),settings_lai_low_default,lai_high) 1099 1148 1100 if ( max(patch_height.flatten()) >= (2.0 * domain_dz[i]) ):1101 print(" start calculating LAD (this might take some time)")1149 if ( max(patch_height.flatten()) >= (2.0 * domain_dz[i]) ): 1150 print(" start calculating LAD (this might take some time)") 1102 1151 1103 1152 1104 lad_patch, patch_nz, status = process_patch(domain_dz[i],patch_height,max(zlad),lai_high,settings_lai_alpha,settings_lai_beta) 1105 1106 # 2D loop in order to avoid memory problems with large arrays 1107 for iii in range(0,domain_nx[i]): 1108 for jj in range(0,domain_ny[i]): 1109 1110 lad[0:patch_nz+1,jj,iii] = np.where( (lad[0:patch_nz+1,jj,iii] == fillvalues["tree_data"]),lad_patch[0:patch_nz+1,jj,iii], lad[0:patch_nz+1,jj,iii] ) 1111 1112 # Remove high vegetation wherever it is replaced by a leaf area density. This should effectively remove all high vegetation pixels 1113 vegetation_type = np.where((lad[0,:,:] != fillvalues["tree_data"]) & (vegetation_type != fillvalues["vegetation_type"]),settings_veg_type_below_trees,vegetation_type) 1153 lad_patch, patch_id, patch_types, patch_nz, status = process_patch(domain_dz[i],patch_height,vegetation_type,max(zlad),lai_high,settings_lai_alpha,settings_lai_beta) 1154 1155 # Increase the patch ids by the maximum id for street trees to avoid double ids 1156 max_id = max(tree_id.flatten()) 1157 patch_id = np.where( patch_id != fillvalues["tree_id"], patch_id+max_id, patch_id) 1158 1159 # 2D loop in order to avoid memory problems with large arrays 1160 for iii in range(0,domain_nx[i]): 1161 for jj in range(0,domain_ny[i]): 1162 1163 tree_id[0:patch_nz+1,jj,iii] = np.where( (lad[0:patch_nz+1,jj,iii] == fillvalues["tree_data"]),patch_id[0:patch_nz+1,jj,iii], tree_id[0:patch_nz+1,jj,iii] ) 1164 tree_types[0:patch_nz+1,jj,iii] = np.where( (lad[0:patch_nz+1,jj,iii] == fillvalues["tree_data"]),patch_types[0:patch_nz+1,jj,iii], tree_types[0:patch_nz+1,jj,iii] ) 1165 lad[0:patch_nz+1,jj,iii] = np.where( (lad[0:patch_nz+1,jj,iii] == fillvalues["tree_data"]),lad_patch[0:patch_nz+1,jj,iii], lad[0:patch_nz+1,jj,iii] ) 1166 1167 # Remove high vegetation wherever it is replaced by a leaf area density. This should effectively remove all high vegetation pixels 1168 vegetation_type = np.where((lad[0,:,:] != fillvalues["tree_data"]) & (vegetation_type != fillvalues["vegetation_type"]),settings_veg_type_below_trees,vegetation_type) 1114 1169 1115 # If desired, remove all high vegetation. TODO: check if this is still necessary1116 if not domain_high_vegetation[i]:1117 vegetation_type = np.where((vegetation_type != fillvalues["vegetation_type"]) & ( (vegetation_type == 4) | (vegetation_type == 5) | (vegetation_type == 6) |(vegetation_type == 7) | (vegetation_type == 17) | (vegetation_type == 18) ),3,vegetation_type)1170 # If desired, remove all high vegetation. TODO: check if this is still necessary 1171 if not domain_high_vegetation[i]: 1172 vegetation_type = np.where((vegetation_type != fillvalues["vegetation_type"]) & ( (vegetation_type == 4) | (vegetation_type == 5) | (vegetation_type == 6) |(vegetation_type == 7) | (vegetation_type == 17) | (vegetation_type == 18) ),3,vegetation_type) 1118 1173 1119 1174 1120 # Set default low LAI for pixels with an LAD (short grass below trees)1121 lai_low = np.where( (lad[0,:,:] == fillvalues["tree_data"]), lai, settings_lai_low_default)1175 # Set default low LAI for pixels with an LAD (short grass below trees) 1176 lai_low = np.where( (lad[0,:,:] == fillvalues["tree_data"]), lai, settings_lai_low_default) 1122 1177 1123 # Fill low vegetation pixels without LAI set or with LAI = 0 with default value1124 lai_low = np.where( ( (lai_low == fillvalues["tree_data"]) | (lai_low == 0.0) ) & (vegetation_type != fillvalues["vegetation_type"] ), settings_lai_low_default, lai_low)1125 1126 # Remove lai for pixels that have no vegetation_type1127 lai_low = np.where( ( (vegetation_type != fillvalues["vegetation_type"]) & (vegetation_type != 1) ), lai_low, fillvalues["tree_data"])1178 # Fill low vegetation pixels without LAI set or with LAI = 0 with default value 1179 lai_low = np.where( ( (lai_low == fillvalues["tree_data"]) | (lai_low == 0.0) ) & (vegetation_type != fillvalues["vegetation_type"] ), settings_lai_low_default, lai_low) 1180 1181 # Remove lai for pixels that have no vegetation_type 1182 lai_low = np.where( ( (vegetation_type != fillvalues["vegetation_type"]) & (vegetation_type != 1) ), lai_low, fillvalues["tree_data"]) 1128 1183 1129 # Overwrite lai in vegetation_parameters 1130 vegetation_pars[1,:,:] = np.copy(lai_low) 1131 nc_overwrite_to_file_3d(filename[i], 'vegetation_pars', vegetation_pars) 1132 1133 # Overwrite lad array 1134 nc_overwrite_to_file_3d(filename[i], 'lad', lad) 1135 1136 nc_overwrite_to_file_2d(filename[i], 'vegetation_type', vegetation_type) 1137 1138 1139 del vegetation_type, lad, lai, patch_height, vegetation_pars, zlad 1140 1184 # Overwrite lai in vegetation_parameters 1185 vegetation_pars[1,:,:] = np.copy(lai_low) 1186 nc_overwrite_to_file_3d(filename[i], 'vegetation_pars', vegetation_pars) 1187 1188 # Overwrite lad and id arrays 1189 nc_overwrite_to_file_3d(filename[i], 'lad', lad) 1190 nc_overwrite_to_file_3d(filename[i], 'tree_id', tree_id) 1191 nc_overwrite_to_file_3d(filename[i], 'tree_type', tree_types) 1192 1193 nc_overwrite_to_file_2d(filename[i], 'vegetation_type', vegetation_type) 1194 1195 1196 del vegetation_type, lad, lai, patch_height, vegetation_pars, zlad 1197 else: 1198 print('No tree patches found in domain ' + str(i)) 1141 1199 1142 1200 # Final adjustment of vegetation parameters: remove LAI where a bare soil was set
Note: See TracChangeset
for help on using the changeset viewer.