Changeset 4793 for palm/trunk/SCRIPTS
- Timestamp:
- Nov 24, 2020 9:48:21 AM (4 years ago)
- Location:
- palm/trunk/SCRIPTS
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
palm/trunk/SCRIPTS/.csd.config.default
r4641 r4793 212 212 vegetation_on_roofs = False 213 213 street_trees = True 214 overhanging_trees = False 214 215 215 216 [domain_N02] … … 228 229 vegetation_on_roofs = False 229 230 street_trees = True 231 overhanging_trees = False -
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 -
palm/trunk/SCRIPTS/palm_csd_files/palm_csd_canopy_generator.py
r4481 r4793 20 20 # Current revisions: 21 21 # ----------------- 22 # 23 # 22 # 23 # 24 24 # Former revisions: 25 25 # ----------------- 26 26 # $Id: palm_csd_canopy_generator.py 3773 2019-03-01 08:56:57Z maronga $ 27 # Bugfix: do not allow BAD < 0, revised treatment of tree trunks 28 # 29 # 3773 2019-03-01 08:56:57Z maronga 27 30 # Added support for tree shape 28 31 # … … 46 49 import math 47 50 import scipy.integrate as integrate 51 import scipy.ndimage as nd 48 52 49 53 def generate_single_tree_lad(x,y,dz,max_tree_height,max_patch_height,tree_type,tree_height,tree_dia,trunk_dia,tree_lai,season,fill): … … 64 68 ids = np.ones((len(zlad),len(y),len(x))) 65 69 ids[:,:,:] = fill 66 70 71 types = np.ones((len(zlad),len(y),len(x))) 72 types[:,:,:] = np.byte(-127) 67 73 68 74 # Calculating the number of trees in the arrays and a boolean array storing the location of trees which is used for convenience in the following loop environment … … 107 113 bad[0:lad_loc_nz,ind_l_y:ind_r_y+1,ind_l_x:ind_r_x+1] = np.where(bad_loc[0:lad_loc_nz,out_l_y:out_r_y+1,out_l_x:out_r_x+1] != fill,bad_loc[0:lad_loc_nz,out_l_y:out_r_y+1,out_l_x:out_r_x+1],bad[0:lad_loc_nz,ind_l_y:ind_r_y+1,ind_l_x:ind_r_x+1]) 108 114 ids[0:lad_loc_nz,ind_l_y:ind_r_y+1,ind_l_x:ind_r_x+1] = np.where(lad_loc[0:lad_loc_nz,out_l_y:out_r_y+1,out_l_x:out_r_x+1] != fill,tree_id_counter,ids[0:lad_loc_nz,ind_l_y:ind_r_y+1,ind_l_x:ind_r_x+1]) 115 types[0:lad_loc_nz,ind_l_y:ind_r_y+1,ind_l_x:ind_r_x+1] = np.where(lad_loc[0:lad_loc_nz,out_l_y:out_r_y+1,out_l_x:out_r_x+1] != fill,np.byte(tree_type[j,i]),types[0:lad_loc_nz,ind_l_y:ind_r_y+1,ind_l_x:ind_r_x+1]) 109 116 110 117 … … 116 123 117 124 del lad_loc, x_loc, y_loc, z_loc, status 118 return lad, bad, ids, zlad125 return lad, bad, ids, types, zlad 119 126 120 127 … … 230 237 fillvalues = { 231 238 "tree_data": float(-9999.0), 239 "tree_type": np.byte(-127) 232 240 } 233 241 234 242 235 243 # Check for missing data in the input and set default values if needed 236 if ( tree_type == fillvalues["tree_ data"] ):244 if ( tree_type == fillvalues["tree_type"] ): 237 245 tree_type = int(0) 238 246 else: … … 295 303 nx = int(tree_dia / dx) + 2 296 304 nz = int(tree_height / dz) + 2 297 305 306 307 298 308 # Add one grid point if diameter is an odd value 299 309 if ( (tree_dia % 2.0) != 0.0 ): 300 310 nx = nx + 1 301 302 311 303 312 # Create local domain of the tree's LAD … … 459 468 460 469 # Create BAD array and populate. TODO: revise as low LAD inside the foliage does not result in low BAD values. 461 bad_loc = np.where(lad_loc != fillvalues["tree_data"],(1.0 - lad_loc)*0.1,lad_loc)470 bad_loc = np.where(lad_loc != fillvalues["tree_data"],(1.0 - (lad_loc/(max(lad_loc.flatten())+0.01)))*0.1,lad_loc) 462 471 463 472 … … 469 478 if ( z[k] <= crown_center ): 470 479 r_test = np.sqrt( (x[i] - tree_location_x)**(2) + (y[j] - tree_location_y)**(2) ) 471 if ( r_test <= radius ): 472 bad_loc[k,j,i] = 1.0 473 if ( (r_test == 0.0) & (trunk_dia <= dx) ): 474 bad_loc[k,j,i] = radius**(2) * 3.14159265359 480 if ( r_test == 0.0 ): 481 if ( trunk_dia <= dx ): 482 bad_loc[k,j,i] = radius**2 * 3.14159265359 483 else: 484 # WORKAROUND: divide remaining circle area over the 8 surrounding valid_pixels 485 bad_loc[k,j-1:j+2,i-1:i+2] = radius**2 * 3.14159265359 / 8.0 486 # for the central pixel fill the pixel 487 bad_loc[k,j,i] = dx**2 488 #elif ( r_test <= radius ): 489 # TODO: calculate circle segment of grid points cut by the grid 490 475 491 476 492 return lad_loc, bad_loc, x, y, z, 0 477 493 478 494 479 def process_patch(dz,patch_height, max_height_lad,patch_lai,alpha,beta):495 def process_patch(dz,patch_height,vegetation_type,max_height_lad,patch_lai,alpha,beta): 480 496 481 497 # Define fill values 482 498 fillvalues = { 483 499 "tree_data": float(-9999.0), 484 "pch_index": int(-9999), 500 "tree_id": int(-9999), 501 "tree_type": np.byte(-127), 502 "pch_index": int(-9999) 485 503 } 486 504 505 487 506 phdz = patch_height[:,:] / dz 488 507 pch_index = np.where( (patch_height[:,:] != fillvalues["tree_data"]),phdz.astype(int)+1,int(-1)) … … 520 539 lad_loc[k,j,i] = 0.5 * ( pre_lad[k-1] + pre_lad[k] ) 521 540 522 return lad_loc, nz, 0 541 542 patch_id_2d = np.where(lad_loc[0,:,:] != fillvalues["tree_data"], 1, 0) 543 patch_id = np.where(lad_loc != fillvalues["tree_data"], 1, 0) 544 patch_type = np.where(lad_loc != fillvalues["tree_data"], np.byte(1), np.byte(-127)) 545 546 num_ids = nd.label(patch_id_2d, output=patch_id_2d) 547 548 for k in range(0,nz): 549 550 vegetation_type_int = vegetation_type.astype(int) 551 patch_id[k,:,:] = np.where((patch_id_2d != 0) & (lad_loc[k,:,:] != fillvalues["tree_data"]), patch_id_2d, fillvalues["tree_id"]) 552 patch_type[k,:,:] = np.where((patch_id_2d != 0) & (lad_loc[k,:,:] != fillvalues["tree_data"]), np.byte(100+vegetation_type), fillvalues["tree_type"]) 553 554 return lad_loc, patch_id, patch_type, nz, 0 523 555 524 556 … … 559 591 self.bad_scale = bad_scale 560 592 self.dbh = dbh 593
Note: See TracChangeset
for help on using the changeset viewer.