source: palm/trunk/SCRIPTS/palm_csd @ 4746

Last change on this file since 4746 was 4746, checked in by maronga, 4 years ago

support for backyard trees in palm_csd

  • Property svn:executable set to *
  • Property svn:keywords set to Id
File size: 58.3 KB
RevLine 
[3567]1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3#--------------------------------------------------------------------------------#
4# This file is part of the PALM model system.
5#
6# PALM is free software: you can redistribute it and/or modify it under the terms
7# of the GNU General Public License as published by the Free Software Foundation,
8# either version 3 of the License, or (at your option) any later version.
9#
10# PALM is distributed in the hope that it will be useful, but WITHOUT ANY
11# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License along with
15# PALM. If not, see <http://www.gnu.org/licenses/>.
16#
[4481]17# Copyright 1997-2020  Leibniz Universitaet Hannover
[3567]18#--------------------------------------------------------------------------------#
19#
20# Current revisions:
21# -----------------
[4746]22#
23#
[3567]24# Former revisions:
25# -----------------
26# $Id: palm_csd 4746 2020-10-15 17:16:30Z maronga $
[4746]27# Add support for backyard high vegetation, which is commonly classified as
28# short grass
29#
30# 4490 2020-04-10 05:32:45Z maronga
[4490]31# Bugfix: call of canopy generator was not made if tree heights were only
32# available via patch_height, but not in tree_height
33#
34# 4481 2020-03-31 18:55:54Z maronga
[4311]35# Bugfix: green roofs were assigned to all available roofs when switched on
36#
37# 4149 2019-08-08 14:02:18Z suehring
[4149]38# Bugfix, nbuilding_pars was 1 element to small
39#
40# 3955 2019-05-07 09:55:25Z maronga
[3955]41# Bugfix in preparaing of green roofs
42# Bugfix: remove LAI for bare soils
43#
44# 3859 2019-04-03 20:30:31Z maronga
[3859]45# Bugfix: wrong variable naming for 'y'
46#
47# 3773 2019-03-01 08:56:57Z maronga
[3773]48# Unspecificed changes
49#
50# 3726 2019-02-07 18:22:49Z maronga
[3726]51# Removed some more bugs
52#
53# 3688 2019-01-22 10:44:20Z maronga
[3688]54# Some unspecified bugfixes
55#
56# 3668 2019-01-14 12:49:24Z maronga
[3668]57# Various improvements and bugfixes
58#
59# 3629 2018-12-13 12:18:54Z maronga
[3629]60# Added canopy generator calls. Some improvements
61#
62# 3567 2018-11-27 13:59:21Z maronga
[3567]63# Initial revisions
64#
65# Description:
66# ------------
67# Processing tool for creating PIDS conform static drivers from rastered NetCDF
68# input
69#
70# @Author Bjoern Maronga (maronga@muk.uni-hannover.de)
71#
72# @todo Make input files optional
73# @todo Allow for ASCII input of terrain height and building height
74# @todo Modularize reading config file
[3688]75# @todo Convert to object-oriented treatment (buidings, trees)
76# @todo Automatically shift child domains so that their origin lies intersects
77#       a edge note of the parent grid
[3567]78#------------------------------------------------------------------------------#
79
80from palm_csd_files.palm_csd_netcdf_interface import *
81from palm_csd_files.palm_csd_tools import *
[3629]82from palm_csd_files.palm_csd_canopy_generator import *
[3567]83import numpy as np
84
85   
86def read_config_file():
87   
88   import configparser
89   from math import floor
90   import numpy as np
91   import os
92   import subprocess as sub
93   import sys
94
95#  Check if configuration files exists and quit otherwise
96   input_config = ".csd.config"
97   for i in range(1,len(sys.argv)): 
98      input_config = str(sys.argv[i])
99       
100   config = configparser.RawConfigParser(allow_no_value=True)
101
102   if ( os.path.isfile(input_config) == False ):
103      print ("Error. No configuration file " + input_config + " found.")
104      raise SystemExit   
105
106   config.read(input_config)
107
108
109#  Definition of settings
[3668]110
[3567]111   global settings_bridge_width
[3629]112   global settings_lai_roof_intensive
113   global settings_lai_roof_extensive
114   global settings_season
115   global settings_lai_low_default
116   global settings_lai_high_default
117   global settings_patch_height_default
118   global settings_lai_alpha
119   global settings_lai_beta
[3955]120   global settings_veg_type_below_trees
[3567]121   global ndomains
122
123#  Definition of global configuration parameters
124   global global_acronym
125   global global_angle
126   global global_author
127   global global_campaign
128   global global_comment
129   global global_contact
130   global global_data_content 
131   global global_dependencies
132   global global_institution
133   global global_keywords
134   global global_location
135   global global_palm_version
136   global global_references
137   global global_site
138   global global_source
139
[3668]140   global  path_out
141   global filename_out
142   global version_out
[3567]143
[3668]144
[3567]145#  Definition of domain parameters
146   global domain_names
147   global domain_px
148   global domain_x0
149   global domain_y0
150   global domain_x1
151   global domain_y1
152   global domain_nx
153   global domain_ny
154   global domain_dz
155   global domain_3d
[3629]156   global domain_high_vegetation
[3567]157   global domain_ip
158   global domain_za
159   global domain_parent
[3629]160   global domain_green_roofs
161   global domain_street_trees
162   global domain_canopy_patches
[3567]163
164#  Definition of input data parameters
165   global input_names
166   global input_px
167 
168       
169   global input_file_x
170   global input_file_y
171   global input_file_x_UTM
172   global input_file_y_UTM   
173   global input_file_lat
174   global input_file_lon 
175   global input_file_zt
176   global input_file_buildings_2d
177   global input_file_bridges_2d
178   global input_file_building_id
179   global input_file_bridges_id   
180   global input_file_building_type
181   global input_file_building_type
[3629]182   global input_file_lai 
[3567]183   global input_file_vegetation_type
184   global input_file_vegetation_height
185   global input_file_pavement_type
186   global input_file_water_type
187   global input_file_street_type
188   global input_file_street_crossings
189   global input_file_soil_type
[3629]190   global input_file_vegetation_on_roofs
191   global input_file_tree_crown_diameter
192   global input_file_tree_height
193   global input_file_tree_trunk_diameter
194   global input_file_tree_type
195   global input_file_patch_height
[3567]196
197   global zt_all
198   global zt_min
199
200   settings_bridge_width = 3.0
[3955]201   settings_lai_roof_intensive = 2.5
202   settings_lai_roof_extensive = 0.8
[3629]203   settings_season = "summer"
204   settings_lai_high_default = 6.0
205   settings_lai_low_default = 1.0
206   settings_patch_height_default = 10.0
207   settings_lai_alpha = 5.0
208   settings_lai_beta = 3.0
[3955]209   settings_veg_type_below_trees = 3
[3567]210   ndomains = 0
211
212   global_acronym = ""
213   global_angle = ""
214   global_author = ""
215   global_campaign = ""
216   global_comment = ""
217   global_contact = ""
218   global_data_content = ""
219   global_dependencies = ""
220   global_institution = ""
221   global_keywords = ""
222   global_location = ""
223   global_palm_version = 6.0
224   global_references = ""
225   global_site = ""
226   global_source = ""
227
[3668]228   path_out = ""
229   version_out = 1
230   filename_out = "default"
231   
[3567]232   domain_names = []
233   domain_px = []
234   domain_x0 = []
235   domain_y0 = []
236   domain_x1 = []
237   domain_y1 = []
238   domain_nx = []
239   domain_ny = []
240   domain_dz = []
241   domain_3d = []
[3629]242   domain_high_vegetation = []
[3567]243   domain_ip = []
244   domain_za = []
245   domain_parent = []
[3629]246   domain_green_roofs = []
247   domain_street_trees = []
248   domain_canopy_patches = []
[3567]249
250   zt_min = 0.0
251   zt_all = []
252
253   input_names = []
254   input_px = []
255
256   input_file_x = []
257   input_file_y = [] 
258   input_file_x_UTM = []
259   input_file_y_UTM = [] 
260   input_file_lat = []
261   input_file_lon = [] 
262   
263   input_file_zt = []
264   input_file_buildings_2d = []
265   input_file_bridges_2d = []
266   input_file_building_id = []
267   input_file_bridges_id = []   
268   input_file_building_type = []
[3629]269   input_file_lai = []
[3567]270   input_file_vegetation_type = []
271   input_file_vegetation_height = []   
272   input_file_pavement_type = []
273   input_file_water_type = []
274   input_file_street_type = [] 
275   input_file_street_crossings = []     
276   input_file_soil_type = []
[3629]277   input_file_vegetation_on_roofs = []
278   input_file_tree_crown_diameter = []
279   input_file_tree_height = []
280   input_file_tree_trunk_diameter = []
281   input_file_tree_type = []
282   input_file_patch_height = []
[3567]283   
284# Load all user parameters from config file
285   for i in range(0,len(config.sections())):
286
287      read_tmp = config.sections()[i]
288     
289      if ( read_tmp == 'global' ):
290         global_acronym = config.get(read_tmp, 'acronym')
291         global_angle = float(config.get(read_tmp, 'rotation_angle'))
292         global_author = config.get(read_tmp, 'author')
293         global_campaign = config.get(read_tmp, 'campaign')
294         global_comment = config.get(read_tmp, 'comment')
295         global_contact = config.get(read_tmp, 'contact_person')
296         global_data_content = config.get(read_tmp, 'data_content')   
297         global_dependencies = config.get(read_tmp, 'dependencies')
298         global_institution = config.get(read_tmp, 'institution')
299         global_keywords = config.get(read_tmp, 'keywords')
300         global_location = config.get(read_tmp, 'location')
301         global_palm_version = float(config.get(read_tmp, 'palm_version'))
302         global_references = config.get(read_tmp, 'references')
303         global_site = config.get(read_tmp, 'site')
304         global_source = config.get(read_tmp, 'source')
305
[3668]306
[3567]307      if ( read_tmp == 'settings' ):
[3629]308         settings_lai_roof_intensive = config.get(read_tmp, 'lai_roof_intensive')
309         settings_lai_roof_extensive = config.get(read_tmp, 'lai_roof_extensive') 
310         settings_bridge_width = float(config.get(read_tmp, 'bridge_width'))   
311         settings_season = config.get(read_tmp, 'season')   
312         settings_lai_high_default = float(config.get(read_tmp, 'lai_high_vegetation_default'))
313         settings_lai_low_default = float(config.get(read_tmp, 'lai_low_vegetation_default'))         
314         settings_patch_height_default = float(config.get(read_tmp, 'patch_height_default')) 
315         settings_lai_alpha = float(config.get(read_tmp, 'lai_alpha')) 
316         settings_lai_beta = float(config.get(read_tmp, 'lai_beta')) 
[3955]317         settings_veg_type_below_trees = config.get(read_tmp, 'vegetation_type_below_trees') 
[3629]318
[3668]319      if ( read_tmp == 'output' ):
320         path_out = config.get(read_tmp, 'path')         
321         filename_out = config.get(read_tmp, 'file_out')
322         version_out = float(config.get(read_tmp, 'version'))
323
[3567]324      if ( read_tmp.split("_")[0] == 'domain' ):
325         ndomains = ndomains + 1
326         domain_names.append(read_tmp.split("_")[1])
327         domain_px.append(float(config.get(read_tmp, 'pixel_size')))
328         domain_nx.append(int(config.get(read_tmp, 'nx')))
329         domain_ny.append(int(config.get(read_tmp, 'ny')))
330         domain_dz.append(float(config.get(read_tmp, 'dz')))       
331         domain_3d.append(config.getboolean(read_tmp, 'buildings_3d'))
[3629]332         domain_high_vegetation.append(config.getboolean(read_tmp, 'allow_high_vegetation'))
333         domain_canopy_patches.append(config.getboolean(read_tmp, 'generate_vegetation_patches'))       
[3567]334         domain_ip.append(config.getboolean(read_tmp, 'interpolate_terrain'))
335         domain_za.append(config.getboolean(read_tmp, 'use_palm_z_axis')) 
336         if domain_ip[ndomains-1] and not domain_za[ndomains-1]:
337            domain_za[ndomains-1] = True
338            print("+++ Overwrite user setting for use_palm_z_axis")
339         
340         domain_parent.append(config.get(read_tmp, 'domain_parent'))
341
342         domain_x0.append(int(floor(float(config.get(read_tmp, 'origin_x'))/float(config.get(read_tmp, 'pixel_size')))))
343         domain_y0.append(int(floor(float(config.get(read_tmp, 'origin_y'))/float(config.get(read_tmp, 'pixel_size')))))       
344         domain_x1.append(int(floor(float(config.get(read_tmp, 'origin_x'))/float(config.get(read_tmp, 'pixel_size'))) + int(config.get(read_tmp, 'nx'))))
345         domain_y1.append(int(floor(float(config.get(read_tmp, 'origin_y'))/float(config.get(read_tmp, 'pixel_size'))) + int(config.get(read_tmp, 'ny'))))
[3629]346         domain_green_roofs.append(config.getboolean(read_tmp, 'vegetation_on_roofs')) 
347         domain_street_trees.append(config.getboolean(read_tmp, 'street_trees')) 
348         
[3567]349      if ( read_tmp.split("_")[0] == 'input' ):
350         input_names.append(read_tmp.split("_")[1])
351         input_px.append(float(config.get(read_tmp, 'pixel_size')))
352         input_file_x.append(config.get(read_tmp, 'path') + "/" + config.get(read_tmp, 'file_x'))
353         input_file_y.append(config.get(read_tmp, 'path') + "/" + config.get(read_tmp, 'file_y')) 
354         input_file_lat.append(config.get(read_tmp, 'path') + "/" + config.get(read_tmp, 'file_lat'))
355         input_file_lon.append(config.get(read_tmp, 'path') + "/" + config.get(read_tmp, 'file_lon'))   
356         input_file_x_UTM.append(config.get(read_tmp, 'path') + "/" + config.get(read_tmp, 'file_x_UTM'))
357         input_file_y_UTM.append(config.get(read_tmp, 'path') + "/" + config.get(read_tmp, 'file_y_UTM')) 
358         input_file_zt.append(config.get(read_tmp, 'path') + "/" + config.get(read_tmp, 'file_zt'))
359         input_file_buildings_2d.append(config.get(read_tmp, 'path') + "/" + config.get(read_tmp, 'file_buildings_2d'))
360         input_file_bridges_2d.append(config.get(read_tmp, 'path') + "/" + config.get(read_tmp, 'file_bridges_2d'))
361         input_file_building_id.append(config.get(read_tmp, 'path') + "/" + config.get(read_tmp, 'file_building_id')) 
362         input_file_bridges_id.append(config.get(read_tmp, 'path') + "/" + config.get(read_tmp, 'file_bridges_id')) 
[3629]363         input_file_building_type.append(config.get(read_tmp, 'path') + "/" + config.get(read_tmp, 'file_building_type'))
364         input_file_lai.append(config.get(read_tmp, 'path') + "/" + config.get(read_tmp, 'file_lai'))         
[3567]365         input_file_vegetation_type.append(config.get(read_tmp, 'path') + "/" + config.get(read_tmp, 'file_vegetation_type')) 
366         input_file_vegetation_height.append(config.get(read_tmp, 'path') + "/" + config.get(read_tmp, 'file_vegetation_height'))         
367         input_file_pavement_type.append(config.get(read_tmp, 'path') + "/" + config.get(read_tmp, 'file_pavement_type'))   
368         input_file_water_type.append(config.get(read_tmp, 'path') + "/" + config.get(read_tmp, 'file_water_type'))
369         input_file_street_type.append(config.get(read_tmp, 'path') + "/" + config.get(read_tmp, 'file_street_type'))   
[3629]370         input_file_street_crossings.append(config.get(read_tmp, 'path') + "/" + config.get(read_tmp, 'file_street_crossings')) 
371         input_file_patch_height.append(config.get(read_tmp, 'path') + "/" + config.get(read_tmp, 'file_patch_height')) 
[3668]372         
373         tmp = config.get(read_tmp, 'file_tree_crown_diameter')
374         if tmp is not None:
375            input_file_tree_crown_diameter.append(config.get(read_tmp, 'path') + "/" + tmp) 
376         else:
377            input_file_tree_crown_diameter.append(None)
[3629]378         input_file_tree_height.append(config.get(read_tmp, 'path') + "/" + config.get(read_tmp, 'file_tree_height')) 
379         input_file_tree_trunk_diameter.append(config.get(read_tmp, 'path') + "/" + config.get(read_tmp, 'file_tree_trunk_diameter')) 
380         input_file_tree_type.append(config.get(read_tmp, 'path') + "/" + config.get(read_tmp, 'file_tree_type')) 
381         input_file_vegetation_on_roofs.append(config.get(read_tmp, 'path') + "/" + config.get(read_tmp, 'file_vegetation_on_roofs'))           
[3567]382         #input_file_soil_type.append(config.get(read_tmp, 'path') + "/" + config.get(read_tmp, 'file_soil_type'))   
383   return 0
384
385
386############################################################
387
388# Start of main program
389datatypes = {
390   "x": "f4", 
391   "y": "f4", 
392   "z": "f4", 
393   "lat": "f4", 
394   "lon": "f4",   
395   "E_UTM": "f4", 
396   "N_UTM": "f4", 
397   "zt": "f4",
398   "buildings_2d": "f4",
399   "buildings_3d": "b",
400   "bridges_2d": "f4",
401   "building_id": "i",
402   "bridges_id": "i",
403   "building_type": "b",
404   "nsurface_fraction": "i",
405   "vegetation_type": "b",
406   "vegetation_height": "f4",
407   "pavement_type": "b", 
408   "water_type": "b", 
409   "street_type": "b", 
410   "street_crossings": "b",     
411   "soil_type": "b",
[3629]412   "surface_fraction": "f4",
413   "building_pars": "f4",
414   "vegetation_pars": "f4",
415   "tree_data": "f4",
416   "tree_type": "b",
417   "nbuilding_pars": "i",
418   "nvegetation_pars": "i",
419   "zlad": "f4"
[3567]420   }
421
422fillvalues = {
423   "lat": float(-9999.0),
424   "lon": float(-9999.0),
425   "E_UTM": float(-9999.0),
426   "N_UTM": float(-9999.0),   
427   "zt": float(-9999.0),
428   "buildings_2d": float(-9999.0),
429   "buildings_3d": np.byte(-127),
430   "bridges_2d": float(-9999.0),
431   "building_id": int(-9999),
432   "bridges_id": int(-9999),
433   "building_type": np.byte(-127),
434   "nsurface_fraction": int(-9999),
435   "vegetation_type": np.byte(-127),
436   "vegetation_height": float(-9999.0),
437   "pavement_type": np.byte(-127),
438   "water_type": np.byte(-127),
439   "street_type": np.byte(-127), 
440   "street_crossings": np.byte(-127),   
441   "soil_type": np.byte(-127),
[3629]442   "surface_fraction": float(-9999.0),
443   "building_pars": float(-9999.0),
444   "vegetation_pars": float(-9999.0),
445   "tree_data": float(-9999.0),
446   "tree_type": np.byte(-127)
[3567]447   }
448
449defaultvalues = {
450   "lat": float(-9999.0),
451   "lon": float(-9999.0),
452   "E_UTM": float(-9999.0),
453   "N_UTM": float(-9999.0), 
454   "zt": float(0.0),
455   "buildings_2d": float(0.0),
456   "buildings_3d": 0,   
457   "bridges_2d": float(0.0),
458   "building_id": int(0),
459   "bridges_id": int(0),
460   "building_type": 1,
461   "nsurface_fraction": int(-9999),
462   "vegetation_type": 3,
463   "vegetation_height": float(-9999.0),
464   "pavement_type": 1, 
465   "water_type": 1, 
466   "street_type": 1, 
467   "street_crossings": 0,   
468   "soil_type": 1,
[3629]469   "surface_fraction": float(0.0),
470   "buildings_pars": float(-9999.0),
471   "tree_data": float(-9999.0),
472   "tree_type": 0,
473   "vegetation_pars": float(-9999.0)   
[3567]474   }
475 
476# Read configuration file and set parameters accordingly
477read_config_file()
478
479
480filename = []
481ii = []
482ii_parent = []
483# Define indices and filenames for all domains and create netCDF files
484for i in range(0,ndomains):
485
486#  Calculate indices and input files
487   ii.append(input_px.index(domain_px[i]))
[3668]488   filename.append(path_out + "/" + filename_out + "_" + domain_names[i])
[3567]489   if domain_parent[i] is not None:
[3726]490      ii_parent.append(input_px.index(domain_px[domain_names.index(domain_parent[i])]))
[3567]491   else:
492      ii_parent.append(None)
493
494
[3726]495   x_UTM = nc_read_from_file_2d(input_file_x[ii[i]], "Band1", domain_x0[i], domain_x0[i]+1, domain_y0[i], domain_y0[i]+1)
496   y_UTM = nc_read_from_file_2d(input_file_y[ii[i]], "Band1", domain_x0[i], domain_x0[i]+1, domain_y0[i], domain_y0[i]+1)
497   lat = nc_read_from_file_2d(input_file_lat[ii[i]], "Band1", domain_x0[i], domain_x0[i]+1, domain_y0[i], domain_y0[i]+1)
498   lon = nc_read_from_file_2d(input_file_lon[ii[i]], "Band1", domain_x0[i], domain_x0[i]+1, domain_y0[i], domain_y0[i]+1) 
[3567]499   
[3726]500#  Calculate position of origin
501   x_UTM_origin = float(x_UTM[0,0]) - 0.5 * (float(x_UTM[0,1]) - float(x_UTM[0,0]))
502   y_UTM_origin = float(y_UTM[0,0]) - 0.5 * (float(y_UTM[1,0]) - float(y_UTM[0,0])) 
503   x_origin = float(lon[0,0]) - 0.5 * (float(lon[0,1]) - float(lon[0,0]))
504   y_origin = float(lat[0,0]) - 0.5 * (float(lat[1,0]) - float(lat[0,0]))   
505   
[3567]506#  Create NetCDF output file and set global attributes
507   nc_create_file(filename[i])
[3726]508   nc_write_global_attributes(filename[i],x_UTM_origin,y_UTM_origin,y_origin,x_origin,"",global_acronym,global_angle,global_author,global_campaign,global_comment,global_contact,global_data_content,global_dependencies,global_institution,global_keywords,global_location,global_palm_version,global_references,global_site,global_source,version_out)
[3567]509
[3688]510   del x_UTM, y_UTM, lat, lon
[3567]511   
512# Process terrain height
513for i in range(0,ndomains):
514
515#  Read and write terrain height (zt)
516   zt = nc_read_from_file_2d(input_file_zt[ii[i]], 'Band1', domain_x0[i], domain_x1[i], domain_y0[i], domain_y1[i])
517
518#  Final step: add zt array to the global array   
519   zt_all.append(zt)
520   del zt
521 
522#  Calculate the global (all domains) minimum of the terrain height. This value will be substracted for all
523#  data sets
524zt_min = min(zt_all[0].flatten()) 
525for i in range(0,ndomains):
526   zt_min = min(zt_min,min(zt_all[i].flatten()))
527   
528del zt_all[:]
529
[3726]530print( "Shift terrain heights by -" + str(zt_min))
[3567]531for i in range(0,ndomains):
532
533#  Read and write terrain height (zt)
534   zt = nc_read_from_file_2d(input_file_zt[ii[i]], 'Band1', domain_x0[i], domain_x1[i], domain_y0[i], domain_y1[i])
535   x = nc_read_from_file_1d(input_file_x[ii[i]], "x", domain_x0[i], domain_x1[i])
536   y = nc_read_from_file_1d(input_file_y[ii[i]], "y", domain_y0[i], domain_y1[i])
537
[3726]538 
[3567]539   zt = zt - zt_min
[3668]540   
541   nc_write_global_attribute(filename[i], 'origin_z', float(zt_min))
[3567]542
543#  If necessary, interpolate parent domain terrain height on child domain grid and blend the two
544   if domain_ip[i]:
[3726]545      parent_id = domain_names.index(domain_parent[i])
546      tmp_x0 = int( domain_x0[i] * domain_px[i] / domain_px[parent_id] ) - 1
547      tmp_y0 = int( domain_y0[i] * domain_px[i] / domain_px[parent_id] ) - 1
548      tmp_x1 = int( domain_x1[i] * domain_px[i] / domain_px[parent_id] ) + 1
549      tmp_y1 = int( domain_y1[i] * domain_px[i] / domain_px[parent_id] ) + 1
550
[3567]551      tmp_x = nc_read_from_file_1d(input_file_x[ii_parent[i]], "x", tmp_x0, tmp_x1)
552      tmp_y = nc_read_from_file_1d(input_file_y[ii_parent[i]], "y", tmp_y0, tmp_y1)
553
554      zt_parent = nc_read_from_file_2d(input_file_zt[ii_parent[i]], 'Band1', tmp_x0, tmp_x1, tmp_y0, tmp_y1)
555
556      zt_parent = zt_parent - zt_min
557
558#     Interpolate array and bring to PALM grid of child domain
559      zt_ip = interpolate_2d(zt_parent,tmp_x,tmp_y,x,y)
[3726]560      zt_ip = bring_to_palm_grid(zt_ip,x,y,domain_dz[parent_id])
561     
562     
563#     Shift the child terrain height according to the parent mean terrain height
[3773]564      print("shifting: -" + str(np.mean(zt)) + " +" + str(np.mean(zt_ip)))
565      #zt = zt - np.min(zt) + np.min(zt_ip)
[3726]566      zt = zt - np.mean(zt) + np.mean(zt_ip)
[3567]567 
568 
569#     Blend over the parent and child terrain height within a radius of 50 px 
570      zt = blend_array_2d(zt,zt_ip,50)
[3773]571     # zt = zt_ip
[3567]572   
573#  Final step: add zt array to the global array   
[3726]574
[3567]575   zt_all.append(zt)
576   del zt
577 
578
579# Read and shift x and y coordinates, shift terrain height according to its minimum value and write all data
580# to file 
581for i in range(0,ndomains):   
582#  Read horizontal grid variables from zt file and write them to output file
583   x = nc_read_from_file_1d(input_file_x[ii[i]], "x", domain_x0[i], domain_x1[i])
584   y = nc_read_from_file_1d(input_file_y[ii[i]], "y", domain_y0[i], domain_y1[i]) 
585   x = x - min(x.flatten()) + domain_px[i]/2.0
586   y = y - min(y.flatten()) + domain_px[i]/2.0 
587   nc_write_dimension(filename[i], 'x', x, datatypes["x"])
588   nc_write_dimension(filename[i], 'y', y, datatypes["y"]) 
589   nc_write_attribute(filename[i], 'x', 'long_name', 'x')
590   nc_write_attribute(filename[i], 'x', 'standard_name','projection_x_coordinate')   
591   nc_write_attribute(filename[i], 'x', 'units', 'm')
[3859]592   nc_write_attribute(filename[i], 'y', 'long_name', 'y')
[3567]593   nc_write_attribute(filename[i], 'y', 'standard_name', 'projection_y_coordinate')   
594   nc_write_attribute(filename[i], 'y', 'units', 'm')
595
596   lat = nc_read_from_file_2d(input_file_lat[ii[i]], "Band1", domain_x0[i], domain_x1[i], domain_y0[i], domain_y1[i])
597   lon = nc_read_from_file_2d(input_file_lon[ii[i]], "Band1", domain_x0[i], domain_x1[i], domain_y0[i], domain_y1[i]) 
598
599   nc_write_to_file_2d(filename[i], 'lat', lat, datatypes["lat"],'y','x',fillvalues["lat"])
600   nc_write_to_file_2d(filename[i], 'lon', lon, datatypes["lon"],'y','x',fillvalues["lon"]) 
601   
602   nc_write_attribute(filename[i], 'lat', 'long_name', 'latitude')
603   nc_write_attribute(filename[i], 'lat', 'standard_name','latitude')   
604   nc_write_attribute(filename[i], 'lat', 'units', 'degrees_north')
605 
606   nc_write_attribute(filename[i], 'lon', 'long_name', 'longitude')
607   nc_write_attribute(filename[i], 'lon', 'standard_name','longitude')   
608   nc_write_attribute(filename[i], 'lon', 'units', 'degrees_east') 
609   
610   x_UTM = nc_read_from_file_2d(input_file_x_UTM[ii[i]], "Band1", domain_x0[i], domain_x1[i], domain_y0[i], domain_y1[i])
611   y_UTM = nc_read_from_file_2d(input_file_y_UTM[ii[i]], "Band1", domain_x0[i], domain_x1[i], domain_y0[i], domain_y1[i]) 
[3726]612
[3567]613   
614   nc_write_to_file_2d(filename[i], 'E_UTM', x_UTM, datatypes["E_UTM"],'y','x',fillvalues["E_UTM"])
615   nc_write_to_file_2d(filename[i], 'N_UTM', y_UTM, datatypes["N_UTM"],'y','x',fillvalues["N_UTM"]) 
616   
617   nc_write_attribute(filename[i], 'E_UTM', 'long_name', 'easting')
618   nc_write_attribute(filename[i], 'E_UTM', 'standard_name','projection_x_coorindate')   
619   nc_write_attribute(filename[i], 'E_UTM', 'units', 'm')
620 
621   nc_write_attribute(filename[i], 'N_UTM', 'long_name', 'northing')
622   nc_write_attribute(filename[i], 'N_UTM', 'standard_name','projection_y_coorindate')   
623   nc_write_attribute(filename[i], 'N_UTM', 'units', 'm') 
624 
625   nc_write_crs(filename[i])
626   
627 
628 
629#  If necessary, bring terrain height to PALM's vertical grid. This is either forced by the user or implicitly
630#  by using interpolation for a child domain       
631   if domain_za[i]:
632      zt_all[i] = bring_to_palm_grid(zt_all[i],x,y,domain_dz[i])
633
634   nc_write_to_file_2d(filename[i], 'zt', zt_all[i], datatypes["zt"],'y','x',fillvalues["zt"])
635   nc_write_attribute(filename[i], 'zt', 'long_name', 'orography')
636   nc_write_attribute(filename[i], 'zt', 'units', 'm')
637   nc_write_attribute(filename[i], 'zt', 'res_orig', domain_px[i]) 
638   nc_write_attribute(filename[i], 'zt', 'coordinates', 'E_UTM N_UTM lon lat') 
639   nc_write_attribute(filename[i], 'zt', 'grid_mapping', 'E_UTM N_UTM lon lat')   
640
641del zt_all
642
643
644#  Process building height, id, and type
645for i in range(0,ndomains): 
646   buildings_2d = nc_read_from_file_2d(input_file_buildings_2d[ii[i]], 'Band1', domain_x0[i], domain_x1[i], domain_y0[i], domain_y1[i])
[3688]647
[3567]648   building_id = nc_read_from_file_2d(input_file_building_id[ii[i]], 'Band1', domain_x0[i], domain_x1[i], domain_y0[i], domain_y1[i]) 
649 
650   building_type = nc_read_from_file_2d(input_file_building_type[ii[i]], 'Band1', domain_x0[i], domain_x1[i], domain_y0[i], domain_y1[i]) 
[3668]651   building_type[building_type >= 254] = fillvalues["building_type"]
[3567]652   building_type = np.where(building_type < 1,defaultvalues["building_type"],building_type)
653 
654   check = check_arrays_2(buildings_2d,building_id,fillvalues["buildings_2d"],fillvalues["building_id"])
655   if not check:
656      buildings_2d = np.where(building_id != fillvalues["building_id"],buildings_2d,fillvalues["buildings_2d"])
657      building_id = np.where(buildings_2d == fillvalues["buildings_2d"],fillvalues["building_id"],building_id)
658      print("Data check #1 " + str(check_arrays_2(buildings_2d,building_id,fillvalues["buildings_2d"],fillvalues["building_id"])))
659
660   check = check_arrays_2(buildings_2d,building_type,fillvalues["buildings_2d"],fillvalues["building_type"])
661   if not check:
662      building_type = np.where(buildings_2d == fillvalues["buildings_2d"],fillvalues["building_type"],building_type)
663      building_type = np.where((building_type == fillvalues["building_type"]) & (buildings_2d != fillvalues["buildings_2d"]),defaultvalues["building_type"],building_type)
664      print("Data check #2 " + str(check_arrays_2(buildings_2d,building_type,fillvalues["buildings_2d"],fillvalues["building_type"])))
665 
[3688]666
[3567]667   nc_write_to_file_2d(filename[i], 'buildings_2d', buildings_2d, datatypes["buildings_2d"],'y','x',fillvalues["buildings_2d"])
668   nc_write_attribute(filename[i], 'buildings_2d', 'long_name', 'buildings')
669   nc_write_attribute(filename[i], 'buildings_2d', 'units', 'm')
670   nc_write_attribute(filename[i], 'buildings_2d', 'res_orig', domain_px[i]) 
671   nc_write_attribute(filename[i], 'buildings_2d', 'lod', 1) 
672   nc_write_attribute(filename[i], 'buildings_2d', 'coordinates', 'E_UTM N_UTM lon lat') 
673   nc_write_attribute(filename[i], 'buildings_2d', 'grid_mapping', 'E_UTM N_UTM lon lat')   
674   
675   nc_write_to_file_2d(filename[i], 'building_id', building_id, datatypes["building_id"],'y','x',fillvalues["building_id"])
676   nc_write_attribute(filename[i], 'building_id', 'long_name', 'building id')
677   nc_write_attribute(filename[i], 'building_id', 'units', '')
[3668]678   nc_write_attribute(filename[i], 'building_id', 'res _orig', domain_px[i]) 
[3567]679   nc_write_attribute(filename[i], 'building_id', 'coordinates', 'E_UTM N_UTM lon lat') 
680   nc_write_attribute(filename[i], 'building_id', 'grid_mapping', 'E_UTM N_UTM lon lat')   
681   
682   nc_write_to_file_2d(filename[i], 'building_type', building_type, datatypes["building_type"],'y','x',fillvalues["building_type"])
683   nc_write_attribute(filename[i], 'building_type', 'long_name', 'building type')
684   nc_write_attribute(filename[i], 'building_type', 'units', '')
685   nc_write_attribute(filename[i], 'building_type', 'res_orig', domain_px[i]) 
686   nc_write_attribute(filename[i], 'building_type', 'coordinates', 'E_UTM N_UTM lon lat') 
687   nc_write_attribute(filename[i], 'building_type', 'grid_mapping', 'E_UTM N_UTM lon lat')   
688 
689del buildings_2d
690del building_id
691del building_type
692
693# Create 3d buildings if necessary. In that course, read bridge objects and add them to building layer
694for i in range(0,ndomains): 
695   
696   if domain_3d[i]:
697      x = nc_read_from_file_2d_all(filename[i], 'x')
698      y = nc_read_from_file_2d_all(filename[i], 'y') 
699      buildings_2d = nc_read_from_file_2d_all(filename[i], 'buildings_2d') 
700      building_id = nc_read_from_file_2d_all(filename[i], 'building_id') 
701     
702      bridges_2d = nc_read_from_file_2d(input_file_bridges_2d[ii[i]], 'Band1', domain_x0[i], domain_x1[i], domain_y0[i], domain_y1[i])
703      bridges_id = nc_read_from_file_2d(input_file_bridges_id[ii[i]], 'Band1', domain_x0[i], domain_x1[i], domain_y0[i], domain_y1[i])
704     
705      bridges_2d = np.where(bridges_2d == 0.0,fillvalues["bridges_2d"],bridges_2d)
706      building_id = np.where(bridges_2d == fillvalues["bridges_2d"],building_id,bridges_id)
707     
708      if np.any(buildings_2d != fillvalues["buildings_2d"]):
709         buildings_3d, z = make_3d_from_2d(buildings_2d,x,y,domain_dz[i])
710         if np.any(bridges_2d != fillvalues["bridges_2d"]):
711            buildings_3d = make_3d_from_bridges_2d(buildings_3d,bridges_2d,x,y,domain_dz[i],settings_bridge_width,fillvalues["bridges_2d"])
712         else:
713            print("Skipping creation of 3D bridges (no bridges in domain)")
714           
715           
716         nc_write_dimension(filename[i], 'z', z, datatypes["z"]) 
717         nc_write_attribute(filename[i], 'z', 'long_name', 'z') 
718         nc_write_attribute(filename[i], 'z', 'units', 'm')
[3726]719         
720         nc_overwrite_to_file_2d(filename[i], 'building_id', building_id) 
[3567]721 
722         nc_write_to_file_3d(filename[i], 'buildings_3d', buildings_3d, datatypes["buildings_3d"],'z','y','x',fillvalues["buildings_3d"])   
723         nc_write_attribute(filename[i], 'buildings_3d', 'long_name', 'buildings 3d')
724         nc_write_attribute(filename[i], 'buildings_3d', 'units', '')
725         nc_write_attribute(filename[i], 'buildings_3d', 'res_orig', domain_px[i]) 
726         nc_write_attribute(filename[i], 'buildings_3d', 'lod', 2) 
727         
728         del buildings_3d
729         
730      else:
731         print("Skipping creation of 3D buildings (no buildings in domain)")
732
733
[3629]734      del bridges_2d, bridges_id, building_id, buildings_2d
[3567]735
736
737
738# Read vegetation type, water_type, pavement_type, soil_type and make fields consistent
739for i in range(0,ndomains): 
740
741   building_type = nc_read_from_file_2d_all(filename[i], 'building_type') 
[3773]742   
[3567]743   vegetation_type = nc_read_from_file_2d(input_file_vegetation_type[ii[i]], 'Band1', domain_x0[i], domain_x1[i], domain_y0[i], domain_y1[i])   
744   vegetation_type[vegetation_type == 255] = fillvalues["vegetation_type"]
745   vegetation_type = np.where((vegetation_type < 1) & (vegetation_type != fillvalues["vegetation_type"]),defaultvalues["vegetation_type"],vegetation_type)
746   
747   pavement_type = nc_read_from_file_2d(input_file_pavement_type[ii[i]], 'Band1', domain_x0[i], domain_x1[i], domain_y0[i], domain_y1[i])   
748   pavement_type[pavement_type == 255] = fillvalues["pavement_type"]
749   pavement_type = np.where((pavement_type < 1) & (pavement_type != fillvalues["pavement_type"]),defaultvalues["pavement_type"],pavement_type)
750
751   water_type = nc_read_from_file_2d(input_file_water_type[ii[i]], 'Band1', domain_x0[i], domain_x1[i], domain_y0[i], domain_y1[i])   
752   water_type[water_type == 255] = fillvalues["water_type"]
753   water_type = np.where((water_type < 1) & (water_type != fillvalues["water_type"]),defaultvalues["water_type"],water_type)
754 
755#  to do: replace by real soil input data
756   soil_type = nc_read_from_file_2d(input_file_vegetation_type[ii[i]], 'Band1', domain_x0[i], domain_x1[i], domain_y0[i], domain_y1[i]) 
757   soil_type[soil_type == 255] = fillvalues["soil_type"]
758   soil_type = np.where((soil_type < 1) & (soil_type != fillvalues["soil_type"]),defaultvalues["soil_type"],soil_type)
759
760#  Make arrays consistent
761#  #1 Set vegetation type to missing for pixel where a pavement type is set
762   vegetation_type = np.where((vegetation_type != fillvalues["vegetation_type"]) & (pavement_type != fillvalues["pavement_type"]),fillvalues["vegetation_type"],vegetation_type)
763
764#  #2 Set vegetation type to missing for pixel where a building type is set
765   vegetation_type = np.where((vegetation_type != fillvalues["vegetation_type"]) & (building_type != fillvalues["building_type"]) ,fillvalues["vegetation_type"],vegetation_type)
766
767#  #3 Set vegetation type to missing for pixel where a building type is set
768   vegetation_type = np.where((vegetation_type != fillvalues["vegetation_type"]) & (water_type != fillvalues["water_type"]),fillvalues["vegetation_type"],vegetation_type)   
769
770#  #4 Remove pavement for pixels with buildings
771   pavement_type = np.where((pavement_type != fillvalues["pavement_type"]) & (building_type != fillvalues["building_type"]),fillvalues["pavement_type"],pavement_type) 
772
[3773]773#  #5 Remove pavement for pixels with water.
774   pavement_type = np.where((pavement_type != fillvalues["pavement_type"]) & (water_type != fillvalues["water_type"]),fillvalues["pavement_type"],pavement_type) 
775   
[3567]776#  #6 Remove water for pixels with buildings
777   water_type = np.where((water_type != fillvalues["water_type"]) & (building_type != fillvalues["building_type"]),fillvalues["water_type"],water_type) 
[3773]778
[3668]779#  Correct vegetation_type when a vegetation height is available and is indicative of low vegeetation
780   vegetation_height = nc_read_from_file_2d(input_file_vegetation_height[ii[i]], 'Band1', domain_x0[i], domain_x1[i], domain_y0[i], domain_y1[i])   
781         
782   vegetation_type = np.where((vegetation_height != fillvalues["vegetation_height"]) & (vegetation_height == 0.0) & ((vegetation_type == 4) | (vegetation_type == 5) | (vegetation_type == 6) |(vegetation_type == 7) | (vegetation_type == 17) | (vegetation_type == 18)), 3, vegetation_type)
783   vegetation_height = np.where((vegetation_height != fillvalues["vegetation_height"]) & (vegetation_height == 0.0) & ((vegetation_type == 4) | (vegetation_type == 5) | (vegetation_type == 6) |(vegetation_type == 7) | (vegetation_type == 17) | (vegetation_type == 18)), fillvalues["vegetation_height"],vegetation_height)
[3567]784 
785#  Check for consistency and fill empty fields with default vegetation type
786   consistency_array, test = check_consistency_4(vegetation_type,building_type,pavement_type,water_type,fillvalues["vegetation_type"],fillvalues["building_type"],fillvalues["pavement_type"],fillvalues["water_type"])
787   
788   if test:
789      vegetation_type = np.where(consistency_array == 0,defaultvalues["vegetation_type"],vegetation_type)
790      consistency_array, test = check_consistency_4(vegetation_type,building_type,pavement_type,water_type,fillvalues["vegetation_type"],fillvalues["building_type"],fillvalues["pavement_type"],fillvalues["water_type"])
[3668]791
792#  #7 to be removed: set default soil type everywhere
793   soil_type = np.where((vegetation_type != fillvalues["vegetation_type"]) | (pavement_type != fillvalues["pavement_type"]),defaultvalues["soil_type"],fillvalues["soil_type"]) 
794       
[3567]795   
[3668]796#  Check for consistency and fill empty fields with default vegetation type
797   consistency_array, test = check_consistency_3(vegetation_type,pavement_type,soil_type,fillvalues["vegetation_type"],fillvalues["pavement_type"],fillvalues["soil_type"])
798       
[3567]799#  Create surface_fraction array
800   x = nc_read_from_file_2d_all(filename[i], 'x')
801   y = nc_read_from_file_2d_all(filename[i], 'y') 
802   nsurface_fraction = np.arange(0,3)
803   surface_fraction = np.ones((len(nsurface_fraction),len(y),len(x)))
804   
805   surface_fraction[0,:,:] = np.where(vegetation_type != fillvalues["vegetation_type"], 1.0, 0.0)
806   surface_fraction[1,:,:] = np.where(pavement_type != fillvalues["pavement_type"], 1.0, 0.0)
807   surface_fraction[2,:,:] = np.where(water_type != fillvalues["water_type"], 1.0, 0.0)
808   
809   nc_write_dimension(filename[i], 'nsurface_fraction', nsurface_fraction, datatypes["nsurface_fraction"]) 
810   nc_write_to_file_3d(filename[i], 'surface_fraction', surface_fraction, datatypes["surface_fraction"],'nsurface_fraction','y','x',fillvalues["surface_fraction"])     
811   nc_write_attribute(filename[i], 'surface_fraction', 'long_name', 'surface fraction')
812   nc_write_attribute(filename[i], 'surface_fraction', 'units', '')
813   nc_write_attribute(filename[i], 'surface_fraction', 'res_orig', domain_px[i])     
814   del surface_fraction   
815
816   nc_write_to_file_2d(filename[i], 'vegetation_type', vegetation_type, datatypes["vegetation_type"],'y','x',fillvalues["vegetation_type"])     
817   nc_write_attribute(filename[i], 'vegetation_type', 'long_name', 'vegetation type')
818   nc_write_attribute(filename[i], 'vegetation_type', 'units', '')
819   nc_write_attribute(filename[i], 'vegetation_type', 'res_orig', domain_px[i]) 
820   nc_write_attribute(filename[i], 'vegetation_type', 'coordinates', 'E_UTM N_UTM lon lat') 
821   nc_write_attribute(filename[i], 'vegetation_type', 'grid_mapping', 'E_UTM N_UTM lon lat')   
822   del vegetation_type
823
824   nc_write_to_file_2d(filename[i], 'pavement_type', pavement_type, datatypes["pavement_type"],'y','x',fillvalues["pavement_type"])   
825   nc_write_attribute(filename[i], 'pavement_type', 'long_name', 'pavement type')
826   nc_write_attribute(filename[i], 'pavement_type', 'units', '')
827   nc_write_attribute(filename[i], 'pavement_type', 'res_orig', domain_px[i]) 
828   nc_write_attribute(filename[i], 'pavement_type', 'coordinates', 'E_UTM N_UTM lon lat') 
829   nc_write_attribute(filename[i], 'pavement_type', 'grid_mapping', 'E_UTM N_UTM lon lat')   
830   del pavement_type
831
832   nc_write_to_file_2d(filename[i], 'water_type', water_type, datatypes["water_type"],'y','x',fillvalues["water_type"]) 
833   nc_write_attribute(filename[i], 'water_type', 'long_name', 'water type')
834   nc_write_attribute(filename[i], 'water_type', 'units', '')
835   nc_write_attribute(filename[i], 'water_type', 'res_orig', domain_px[i]) 
836   nc_write_attribute(filename[i], 'water_type', 'coordinates', 'E_UTM N_UTM lon lat') 
837   nc_write_attribute(filename[i], 'water_type', 'grid_mapping', 'E_UTM N_UTM lon lat')   
838   del water_type
839
840   nc_write_to_file_2d(filename[i], 'soil_type', soil_type, datatypes["soil_type"],'y','x',fillvalues["soil_type"]) 
841   nc_write_attribute(filename[i], 'soil_type', 'long_name', 'soil type')
842   nc_write_attribute(filename[i], 'soil_type', 'units', '')
843   nc_write_attribute(filename[i], 'soil_type', 'res_orig', domain_px[i])   
844   nc_write_attribute(filename[i], 'soil_type', 'coordinates', 'E_UTM N_UTM lon lat') 
845   nc_write_attribute(filename[i], 'soil_type', 'grid_mapping', 'E_UTM N_UTM lon lat')   
846   del soil_type
847
[3629]848   del x
849   del y
[3567]850
851#  pixels with bridges get building_type = 7 = bridge. This does not change the _type setting for the under-bridge
[3668]852#  area NOTE: when bridges are present the consistency check will fail at the moment
[3567]853   if domain_3d[i]:
854      if np.any(building_type != fillvalues["building_type"]):
855 
856         bridges_2d = nc_read_from_file_2d(input_file_bridges_2d[ii[i]], 'Band1', domain_x0[i], domain_x1[i], domain_y0[i], domain_y1[i])         
857         bridges_2d = np.where(bridges_2d == 0.0,fillvalues["bridges_2d"],bridges_2d)
858         building_type = np.where(bridges_2d != fillvalues["bridges_2d"],7,building_type)
859         nc_overwrite_to_file_2d(filename[i], 'building_type', building_type) 
860 
861         del building_type 
862         del bridges_2d
863
[3629]864# Read/write street type and street crossings
[3567]865for i in range(0,ndomains): 
866
867   street_type = nc_read_from_file_2d(input_file_street_type[ii[i]], 'Band1', domain_x0[i], domain_x1[i], domain_y0[i], domain_y1[i])   
868   street_type[street_type == 255] = fillvalues["street_type"]
869   street_type = np.where((street_type < 1) & (street_type != fillvalues["street_type"]),defaultvalues["street_type"],street_type)
[3773]870
871   pavement_type = nc_read_from_file_2d_all(filename[i], 'pavement_type') 
872   street_type = np.where((pavement_type == fillvalues["pavement_type"]),fillvalues["street_type"],street_type) 
873
[3567]874   nc_write_to_file_2d(filename[i], 'street_type', street_type, datatypes["street_type"],'y','x',fillvalues["street_type"]) 
875   nc_write_attribute(filename[i], 'street_type', 'long_name', 'street type')
876   nc_write_attribute(filename[i], 'street_type', 'units', '')
877   nc_write_attribute(filename[i], 'street_type', 'res_orig', domain_px[i]) 
878   nc_write_attribute(filename[i], 'street_type', 'coordinates', 'E_UTM N_UTM lon lat') 
879   nc_write_attribute(filename[i], 'street_type', 'grid_mapping', 'E_UTM N_UTM lon lat')   
880   del street_type
881   
882   street_crossings = nc_read_from_file_2d(input_file_street_crossings[ii[i]], 'Band1', domain_x0[i], domain_x1[i], domain_y0[i], domain_y1[i])   
883   street_crossings[street_crossings == 255] = fillvalues["street_crossings"]
884   street_crossings = np.where((street_crossings < 1) & (street_crossings != fillvalues["street_crossings"]),defaultvalues["street_crossings"],street_crossings)
885   
[3726]886   nc_write_to_file_2d(filename[i], 'street_crossing', street_crossings, datatypes["street_crossings"],'y','x',fillvalues["street_crossings"]) 
887   nc_write_attribute(filename[i], 'street_crossing', 'long_name', 'street crossings')
888   nc_write_attribute(filename[i], 'street_crossing', 'units', '')
889   nc_write_attribute(filename[i], 'street_crossing', 'res_orig', domain_px[i]) 
890   nc_write_attribute(filename[i], 'street_crossing', 'coordinates', 'E_UTM N_UTM lon lat') 
891   nc_write_attribute(filename[i], 'street_crossing', 'grid_mapping', 'E_UTM N_UTM lon lat')   
[3567]892   del street_crossings
[3629]893
894
895# Read/write vegetation on roofs
896for i in range(0,ndomains): 
897   if domain_green_roofs[i]: 
898      green_roofs = nc_read_from_file_2d(input_file_vegetation_on_roofs[ii[i]], 'Band1', domain_x0[i], domain_x1[i], domain_y0[i], domain_y1[i])   
899      buildings_2d = nc_read_from_file_2d_all(filename[i], 'buildings_2d') 
900
901
902      x = nc_read_from_file_2d_all(filename[i], 'x')
903      y = nc_read_from_file_2d_all(filename[i], 'y') 
[4149]904      nbuilding_pars = np.arange(0,47)
[3629]905      building_pars = np.ones((len(nbuilding_pars),len(y),len(x)))
906      building_pars[:,:,:] = fillvalues["building_pars"]
907
908#     assign green fraction on roofs
[3955]909      building_pars[3,:,:] = np.where( ( buildings_2d != fillvalues["buildings_2d"] ) & ( green_roofs != fillvalues["building_pars"] ) & ( green_roofs != 0.0 ),1,fillvalues["building_pars"] )
[3629]910
911#     assign leaf area index for vegetation on roofs
[4311]912      building_pars[4,:,:] = np.where( ( building_pars[3,:,:] != fillvalues["building_pars"] ) & ( green_roofs >= 0.5 ),settings_lai_roof_intensive,fillvalues["building_pars"])
913      building_pars[4,:,:] = np.where( ( building_pars[3,:,:] != fillvalues["building_pars"] ) & ( green_roofs < 0.5 ),settings_lai_roof_extensive,building_pars[4,:,:])
[3629]914   
915   
916      nc_write_dimension(filename[i], 'nbuilding_pars', nbuilding_pars, datatypes["nbuilding_pars"]) 
917      nc_write_to_file_3d(filename[i], 'building_pars', building_pars, datatypes["building_pars"],'nbuilding_pars','y','x',fillvalues["building_pars"]) 
918      nc_write_attribute(filename[i], 'building_pars', 'long_name', 'building_pars')
919      nc_write_attribute(filename[i], 'building_pars', 'units', '')
920      nc_write_attribute(filename[i], 'building_pars', 'res_orig', domain_px[i]) 
921      nc_write_attribute(filename[i], 'building_pars', 'coordinates', 'E_UTM N_UTM lon lat') 
922      nc_write_attribute(filename[i], 'building_pars', 'grid_mapping', 'E_UTM N_UTM lon lat')   
923         
924      del building_pars, buildings_2d, x, y
925
926
927# Read tree data and create LAD and BAD arrays using the canopy generator
928for i in range(0,ndomains): 
[3668]929   lai = nc_read_from_file_2d(input_file_lai[ii[i]], 'Band1', domain_x0[i], domain_x1[i], domain_y0[i], domain_y1[i])   
930     
931   vegetation_type = nc_read_from_file_2d_all(filename[i], 'vegetation_type')
932     
933   lai = np.where(vegetation_type == fillvalues["vegetation_type"],fillvalues["vegetation_pars"],lai)
934
[3629]935     
[3668]936   x = nc_read_from_file_2d_all(filename[i], 'x')
937   y = nc_read_from_file_2d_all(filename[i], 'y') 
938   nvegetation_pars = np.arange(0,12)
939   vegetation_pars = np.ones((len(nvegetation_pars),len(y),len(x)))
940   vegetation_pars[:,:,:] = fillvalues["vegetation_pars"] 
[3629]941     
[3668]942   vegetation_pars[1,:,:] = lai
[3629]943     
[3668]944
945#  Write out first version of LAI. Will later be overwritten.
946   nc_write_dimension(filename[i], 'nvegetation_pars', nvegetation_pars, datatypes["nvegetation_pars"]) 
947   nc_write_to_file_3d(filename[i], 'vegetation_pars', vegetation_pars, datatypes["vegetation_pars"],'nvegetation_pars','y','x',fillvalues["vegetation_pars"]) 
948   nc_write_attribute(filename[i], 'vegetation_pars', 'long_name', 'vegetation_pars')
949   nc_write_attribute(filename[i], 'vegetation_pars', 'units', '')
950   nc_write_attribute(filename[i], 'vegetation_pars', 'res_orig', domain_px[i]) 
951   nc_write_attribute(filename[i], 'vegetation_pars', 'coordinates', 'E_UTM N_UTM lon lat') 
952   nc_write_attribute(filename[i], 'vegetation_pars', 'grid_mapping', 'E_UTM N_UTM lon lat')   
953
954   del lai, vegetation_pars, vegetation_type
955
956# Read tree data and create LAD and BAD arrays using the canopy generator
957for i in range(0,ndomains): 
958   if domain_street_trees[i]: 
959
960      vegetation_pars =  nc_read_from_file_2d_all(filename[i], 'vegetation_pars')
961
962      lai = np.copy(vegetation_pars[1,:,:])
963
[3629]964      x = nc_read_from_file_2d_all(filename[i], 'x')
965      y = nc_read_from_file_2d_all(filename[i], 'y') 
966
[3668]967#     Save lai data as default for low and high vegetation
968      lai_low = lai
969      lai_high = lai
970   
971#     Read all tree parameters from file
972      tree_height = nc_read_from_file_2d(input_file_tree_height[ii[i]], 'Band1', domain_x0[i], domain_x1[i], domain_y0[i], domain_y1[i])   
[3629]973
[3668]974      if (input_file_tree_crown_diameter[ii[i]] is not None):
975         tree_crown_diameter = nc_read_from_file_2d(input_file_tree_crown_diameter[ii[i]], 'Band1', domain_x0[i], domain_x1[i], domain_y0[i], domain_y1[i])   
976         tree_crown_diameter = np.where( (tree_crown_diameter == 0.0) | (tree_crown_diameter == -1.0) ,fillvalues["tree_data"],tree_crown_diameter)
977      else:
978         tree_crown_diameter = np.ones((len(y),len(x)))
979         tree_crown_diameter[:,:] = fillvalues["tree_data"]
[3629]980
[3668]981
[3629]982      tree_trunk_diameter = nc_read_from_file_2d(input_file_tree_trunk_diameter[ii[i]], 'Band1', domain_x0[i], domain_x1[i], domain_y0[i], domain_y1[i])         
983      tree_type = nc_read_from_file_2d(input_file_tree_type[ii[i]], 'Band1', domain_x0[i], domain_x1[i], domain_y0[i], domain_y1[i]) 
984      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]) 
985     
986#     Remove missing values from the data. Reasonable values will be set by the tree generator   
987      tree_height = np.where( (tree_height == 0.0) | (tree_height == -1.0) ,fillvalues["tree_data"],tree_height)
988      tree_trunk_diameter = np.where( (tree_trunk_diameter == 0.0) | (tree_trunk_diameter == -1.0) ,fillvalues["tree_data"],tree_trunk_diameter)
989      tree_type = np.where( (tree_type == 0.0) | (tree_type == -1.0) ,fillvalues["tree_data"],tree_type)
990      patch_height = np.where( patch_height == -1.0 ,fillvalues["tree_data"],patch_height)     
991
992#     Convert trunk diameter from cm to m
993      tree_trunk_diameter = np.where(tree_trunk_diameter != fillvalues["tree_data"], tree_trunk_diameter * 0.01,tree_trunk_diameter)
994
995
996#     Temporarily change missing value for tree_type
997      tree_type = np.where( (tree_type == fillvalues["tree_type"]),fillvalues["tree_data"],tree_type)   
998
999#     Compare patch height array with vegetation type and correct accordingly
1000      vegetation_type = nc_read_from_file_2d_all(filename[i], 'vegetation_type') 
1001
1002
1003#     For zero-height patches, set vegetation_type to short grass and remove these pixels from the patch height array
1004      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)
[3668]1005      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)   
1006     
[3629]1007
1008      max_tree_height = max(tree_height.flatten())
1009      max_patch_height = max(patch_height.flatten())
1010     
[4490]1011#     Call canopy generator for single trees only if there is any tree height available in the domain.
1012#     This does not guarantee that there are street trees that can be processed. This is checked in the
1013#     canopy generator.
1014      if ( (max_tree_height != fillvalues["tree_data"]) | (max_patch_height != fillvalues["tree_data"]) ):
[3668]1015
[3629]1016         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"])
1017 
1018 
1019#        Remove LAD volumes that are inside buildings
1020         buildings_2d = nc_read_from_file_2d_all(filename[i], 'buildings_2d') 
1021         for k in range(0,len(zlad)-1):
1022 
1023            lad[k,:,:] = np.where(buildings_2d == fillvalues["buildings_2d"],lad[k,:,:],fillvalues["tree_data"])
1024            bad[k,:,:] = np.where(buildings_2d == fillvalues["buildings_2d"],bad[k,:,:],fillvalues["tree_data"])
1025            tree_ids[k,:,:] = np.where(buildings_2d == fillvalues["buildings_2d"],tree_ids[k,:,:],fillvalues["tree_data"])     
[3668]1026
1027         del buildings_2d
[3629]1028 
1029         nc_write_dimension(filename[i], 'zlad', zlad, datatypes["tree_data"]) 
1030         nc_write_to_file_3d(filename[i], 'lad', lad, datatypes["tree_data"],'zlad','y','x',fillvalues["tree_data"]) 
1031         nc_write_attribute(filename[i], 'lad', 'long_name', 'leaf area density')
1032         nc_write_attribute(filename[i], 'lad', 'units', '')
1033         nc_write_attribute(filename[i], 'lad', 'res_orig', domain_px[i]) 
1034         nc_write_attribute(filename[i], 'lad', 'coordinates', 'E_UTM N_UTM lon lat') 
1035         nc_write_attribute(filename[i], 'lad', 'grid_mapping', 'E_UTM N_UTM lon lat') 
1036 
1037         nc_write_to_file_3d(filename[i], 'bad', bad, datatypes["tree_data"],'zlad','y','x',fillvalues["tree_data"]) 
1038         nc_write_attribute(filename[i], 'bad', 'long_name', 'basal area density')
1039         nc_write_attribute(filename[i], 'bad', 'units', '')
1040         nc_write_attribute(filename[i], 'bad', 'res_orig', domain_px[i]) 
1041         nc_write_attribute(filename[i], 'bad', 'coordinates', 'E_UTM N_UTM lon lat') 
1042         nc_write_attribute(filename[i], 'bad', 'grid_mapping', 'E_UTM N_UTM lon lat')
1043           
1044         nc_write_to_file_3d(filename[i], 'tree_id', tree_ids, datatypes["tree_data"],'zlad','y','x',fillvalues["tree_data"]) 
1045         nc_write_attribute(filename[i], 'tree_id', 'long_name', 'tree id')
1046         nc_write_attribute(filename[i], 'tree_id', 'units', '')
1047         nc_write_attribute(filename[i], 'tree_id', 'res_orig', domain_px[i]) 
1048         nc_write_attribute(filename[i], 'tree_id', 'coordinates', 'E_UTM N_UTM lon lat') 
1049         nc_write_attribute(filename[i], 'tree_id', 'grid_mapping', 'E_UTM N_UTM lon lat')           
1050           
[3668]1051         del lai, lad, bad, tree_ids, zlad
[3629]1052
[3668]1053      del vegetation_pars, tree_height, tree_crown_diameter, tree_trunk_diameter, tree_type, patch_height, x, y
[3629]1054
1055
1056# Create vegetation patches for locations with high vegetation type
1057for i in range(0,ndomains): 
1058   if domain_canopy_patches[i]: 
1059
1060#     Load vegetation_type and lad array (at level z = 0) for re-processing
1061      vegetation_type = nc_read_from_file_2d_all(filename[i], 'vegetation_type') 
1062      lad = nc_read_from_file_3d_all(filename[i], 'lad') 
[3668]1063      zlad = nc_read_from_file_1d_all(filename[i], 'zlad') 
[3629]1064      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]) 
1065      vegetation_pars = nc_read_from_file_3d_all(filename[i], 'vegetation_pars') 
1066      lai = vegetation_pars[1,:,:]
[3726]1067     
[3629]1068
[3726]1069#     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
[3668]1070      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"])
[3629]1071
[4746]1072
1073#     Treat all pixels where short grass is defined, but where a patch_height >= dz is found, as high vegetation (often the case in backyards)
1074      lai_high = np.where( (lai_high == fillvalues["tree_data"]) & (patch_height >= domain_dz[i]) & (vegetation_type == 3), 1.0, lai_high)
1075                         
[3726]1076#     Now, assign either the default LAI for high vegetation or keep 1.0 from the lai_high array.
1077      lai_high = np.where( (lai_high != fillvalues["tree_data"]) & (lai == fillvalues["tree_data"]), settings_lai_high_default, lai_high)
[3668]1078
[4746]1079#     If LAI values are available in the LAI array, write them on the lai_high array
[3726]1080      lai_high = np.where( (lai_high != fillvalues["tree_data"]) & (lai != fillvalues["tree_data"]), lai, lai_high)
1081
[4746]1082
[3668]1083#     Define a patch height wherever it is missing, but where a high vegetation LAI was set
[3629]1084      patch_height = np.where ( (lai_high != fillvalues["tree_data"]) & (patch_height == fillvalues["tree_data"]), settings_patch_height_default, patch_height)
1085
[4746]1086
[3629]1087#     Remove pixels where street trees were already set
1088      patch_height = np.where ( (lad[0,:,:] != fillvalues["tree_data"]), fillvalues["tree_data"], patch_height)
1089
[3668]1090#     Remove patch heights that have no lai_high value
1091      patch_height = np.where ( (lai_high == fillvalues["tree_data"]), fillvalues["tree_data"], patch_height)
1092
[3629]1093#     For missing LAI values, set either the high vegetation default or the low vegetation default   
[3668]1094      lai_high = np.where( (patch_height > 2.0) & (patch_height != fillvalues["tree_data"]) & (lai_high == fillvalues["tree_data"]),settings_lai_high_default,lai_high)
1095      lai_high = np.where( (patch_height <= 2.0) & (patch_height != fillvalues["tree_data"]) & (lai_high == fillvalues["tree_data"]),settings_lai_low_default,lai_high)
1096         
[3629]1097      if ( max(patch_height.flatten()) >= (2.0 * domain_dz[i]) ):
[3726]1098         print("    start calculating LAD (this might take some time)")       
1099
1100         
[3668]1101         lad_patch, patch_nz, status = process_patch(domain_dz[i],patch_height,max(zlad),lai_high,settings_lai_alpha,settings_lai_beta)
[3629]1102
[4746]1103#        2D loop in order to avoid memory problems with large arrays
1104         for ii in range(0,domain_nx[i]):
1105            for jj in range(0,domain_ny[i]):           
[3629]1106
[4746]1107               lad[0:patch_nz+1,jj,ii] = np.where( (lad[0:patch_nz+1,jj,ii] == fillvalues["tree_data"]),lad_patch[0:patch_nz+1,jj,ii], lad[0:patch_nz+1,jj,ii] )
1108
[3629]1109#     Remove high vegetation wherever it is replaced by a leaf area density. This should effectively remove all high vegetation pixels
[3955]1110      vegetation_type = np.where((lad[0,:,:] != fillvalues["tree_data"]) & (vegetation_type != fillvalues["vegetation_type"]),settings_veg_type_below_trees,vegetation_type)
[3668]1111             
[3629]1112#     If desired, remove all high vegetation. TODO: check if this is still necessary
[3688]1113      if not domain_high_vegetation[i]:
[3629]1114         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)   
1115
1116 
[3668]1117#     Set default low LAI for pixels with an LAD (short grass below trees)
1118      lai_low = np.where( (lad[0,:,:] == fillvalues["tree_data"]), lai, settings_lai_low_default)
[3629]1119   
[3668]1120#     Fill low vegetation pixels without LAI set or with LAI = 0 with default value
1121      lai_low = np.where( ( (lai_low == fillvalues["tree_data"]) | (lai_low == 0.0) ) & (vegetation_type != fillvalues["vegetation_type"] ), settings_lai_low_default, lai_low)
[3629]1122
[3668]1123#     Remove lai for pixels that have no vegetation_type
[3955]1124      lai_low = np.where( ( (vegetation_type != fillvalues["vegetation_type"]) & (vegetation_type != 1) ), lai_low, fillvalues["tree_data"])
[3668]1125       
[3629]1126#     Overwrite lai in vegetation_parameters 
[3668]1127      vegetation_pars[1,:,:] = np.copy(lai_low)
[3629]1128      nc_overwrite_to_file_3d(filename[i], 'vegetation_pars', vegetation_pars) 
1129
1130#     Overwrite lad array
1131      nc_overwrite_to_file_3d(filename[i], 'lad', lad) 
[3668]1132           
1133      nc_overwrite_to_file_2d(filename[i], 'vegetation_type', vegetation_type) 
1134
[3629]1135     
[3668]1136      del vegetation_type, lad, lai, patch_height, vegetation_pars, zlad
1137
[3955]1138
1139# Final adjustment of vegetation parameters: remove LAI where a bare soil was set
1140for i in range(0,ndomains): 
1141   
1142      vegetation_type = nc_read_from_file_2d_all(filename[i], 'vegetation_type') 
1143      vegetation_pars = nc_read_from_file_3d_all(filename[i], 'vegetation_pars') 
1144      lai = vegetation_pars[1,:,:]   
1145     
1146     
1147#     Remove lai for pixels that have no vegetation_type
1148      lai = np.where( ( (vegetation_type != fillvalues["vegetation_type"]) & (vegetation_type != 1) ), lai, fillvalues["tree_data"])
1149       
1150#     Overwrite lai in vegetation_parameters 
1151      vegetation_pars[1,:,:] = np.copy(lai)
1152      nc_overwrite_to_file_3d(filename[i], 'vegetation_pars', vegetation_pars) 
1153     
1154      del vegetation_type, lai, vegetation_pars
1155
1156
[3668]1157# Final consistency check
1158for i in range(0,ndomains): 
1159   vegetation_type = nc_read_from_file_2d_all(filename[i], 'vegetation_type') 
1160   pavement_type = nc_read_from_file_2d_all(filename[i], 'pavement_type') 
1161   building_type = nc_read_from_file_2d_all(filename[i], 'building_type') 
1162   water_type = nc_read_from_file_2d_all(filename[i], 'water_type')     
1163   soil_type = nc_read_from_file_2d_all(filename[i], 'soil_type') 
1164
1165#  Check for consistency and fill empty fields with default vegetation type
1166   consistency_array, test = check_consistency_4(vegetation_type,building_type,pavement_type,water_type,fillvalues["vegetation_type"],fillvalues["building_type"],fillvalues["pavement_type"],fillvalues["water_type"])
1167
1168#  Check for consistency and fill empty fields with default vegetation type
1169   consistency_array, test = check_consistency_3(vegetation_type,pavement_type,soil_type,fillvalues["vegetation_type"],fillvalues["pavement_type"],fillvalues["soil_type"])
1170
1171   surface_fraction = nc_read_from_file_3d_all(filename[i], 'surface_fraction')       
1172   surface_fraction[0,:,:] = np.where(vegetation_type != fillvalues["vegetation_type"], 1.0, 0.0)
1173   surface_fraction[1,:,:] = np.where(pavement_type != fillvalues["pavement_type"], 1.0, 0.0)
1174   surface_fraction[2,:,:] = np.where(water_type != fillvalues["water_type"], 1.0, 0.0)
1175   nc_overwrite_to_file_3d(filename[i], 'surface_fraction', surface_fraction) 
1176       
1177   del vegetation_type, pavement_type, building_type, water_type, soil_type
Note: See TracBrowser for help on using the repository browser.