diff --git a/README.txt b/README.txt index e2e9722b52e976c07f0c4e093f85177e3a3b534e..19ba79d1262323479c003529c88d88ddd99c13f5 100644 --- a/README.txt +++ b/README.txt @@ -116,8 +116,9 @@ origin_z origin of the domain in the vertical direction # Changes from wrf + CAMx scripts made to wrf_chem_for_palm -Proj future warning resolved -Chemical species are read from wrf-chem files and interpolated at the same time as the dynamic variables --interpolated files are saved to a different directory than the wrf-chem data files +-Interpolated files are saved to a different directory than the wrf-chem data files -# Latest update (Feb 2022) --any chemical specie from wrf-chem can be selected in the configuration file and will be included in the dynamic driver --extensive changes were made to palm_dynamic_output and palm_dynamic_config to accomdate the changes above +# Latest update (Feb/March 2022) +-Any chemical specie from wrf-chem can be selected in the configuration file and will be included in the dynamic driver. +-Extensive changes were made to palm_dynamic_output and palm_dynamic_config to accomdate the changes above. +-Resolved issue: missing horizontal interpolation of chemical species has been resolved. diff --git a/configurations/augsburg_validation_summer_10.conf b/configurations/augsburg_validation_summer_10.conf index 3eea84dce9dd8a2c22f023bb2a2c052399bc3583..26d0b71c601c27f17dc4328347550f60716d93e3 100644 --- a/configurations/augsburg_validation_summer_10.conf +++ b/configurations/augsburg_validation_summer_10.conf @@ -1,4 +1,4 @@ -# Simulation for summer validation in Prague-Dejvice +# Test case for developing WRF-CHEM for PALM # see GMD: https://doi.org/10.5194/gmd-2020-175 # PALM case, domain, and configuration parameters @@ -37,7 +37,7 @@ vinterp_terrain_smoothing = None interp_dir_name = '/cfs/home/d/u/dupreeda/MBEES/PALM/wrf_chem_data/interp' # WRF-chem species need for chemical reaction -wrfchem_spec = ['no','no2','o3','PM10'] +wrfchem_spec = ['no','no2','o3'] # possible species: no, no2, no3, pm10,PM2_5_DRY, o3, co, hno3, ho, h2o2 # radiation diff --git a/dynamic/palm_dynamic.py b/dynamic/palm_dynamic.py index a19102d060d2c114e19e252bd7252d708eb635e7..83e1799951da45eeda248e6e804ca31d16bfed7d 100644 --- a/dynamic/palm_dynamic.py +++ b/dynamic/palm_dynamic.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- - #------------------------------------------------------------------------------# # # Scripts for processing of WRF-CHEM files to PALM dynamic driver. @@ -30,11 +29,9 @@ from datetime import datetime, timedelta import numpy as np from pyproj import Proj,Transformer,transform, CRS import glob - import netCDF4 import palm_dynamic_config - ################################## # read configuration from command # line and parse it @@ -52,7 +49,6 @@ if sys.argv[0].endswith('pydevconsole.py'): else: try: opts, args = getopt.getopt(sys.argv[1:],"hc:w)",["help=","config=","write="]) - #print(opts) except getopt.GetoptError as err: print("Error:", err) print_help() @@ -77,15 +73,12 @@ if configname == '': palm_dynamic_config.configure(configname) # Import values (including loaded) from config module into globals from palm_dynamic_config import * - # Other modules are imported *AFTER* the config module has been filled with # values (so that they can correctly import * from palm_dynamic_config). import palm_wrf_utils from palm_dynamic_output import palm_dynamic_output - -print('') -print('Domain name: ', domain) +print('\nDomain name: ', domain) print('Resolution name: ', resolution) print('Scenario name: ', scenario) print('Read domain from static:', grid_from_static) @@ -95,12 +88,9 @@ print('WRF-CHEM file path:', wrf_dir_name) print('WRF-CHEM: dynamics file mask:', wrf_file_mask) print('Simulation start time:', origin_time) print('Simulation hours:', simulation_hours) - - ########################### # domain parameters -print('') -print('Domain parameters') +print('\nDomain parameters:') if grid_from_static: # get parameters of the horizontal domain from PALM STATIC driver try: @@ -197,7 +187,6 @@ terrain = terrain_rel + origin_z # print domain parameters and check ist existence in caso of setup from config try: - print('Domain parameters:') print('nx, ny, nz:', nx, ny, nz) print('dx, dy, dz:', dx, dy, dz) print('origin_x, origin_y:', origin_x, origin_y) @@ -248,28 +237,23 @@ for i in range(nz-1): if z_levels[i+1] + dzs >= dz_stretch_level: dzs = min(dzs * dz_stretch_factor, dz_max) ztop = z_levels[-1] + dzs / 2. -#print('z:',z_levels) -#print('zw:',z_levels_stag) - ###################################### # get time extent of the PALM simulation ###################################### -print('') # get complete list of wrf files wrf_file_list = glob.glob(os.path.join(wrf_dir_name, wrf_file_mask)) # get simulation origin and final time as datetime start_time = datetime.strptime(origin_time, '%Y-%m-%d %H:%M:%S') end_time = start_time + timedelta(hours=simulation_hours) end_time_rad = end_time -print('PALM simulation extent', start_time, end_time, simulation_hours) +print('\nPALM simulation extent', start_time, end_time, simulation_hours) if nested_domain: print('Nested domain - process only initialization.') print('Set end_time = start_time') end_time = start_time # get wrf times and sort wrf files by time -print('') -print('Analyse WRF files dates:') +print('\nAnalyse WRF files dates:') file_times = [] for wrf_file in wrf_file_list: #print('WRF file',wrf_file) @@ -313,7 +297,6 @@ for wf in wrf_files[start_index:end_index+1]: wrf_files_proc.append(wf) # id of process files simul_id = domain + "_d" + resolution - ###################################### #VERTICAL AND HORIZONTAL INTERPOLATION ###################################### @@ -331,8 +314,7 @@ finally: nc_wrf.close() print('Hydro variables in wrf files:', '+'.join(shvars)) -print(" ") -print('Start of vertical and horizontal interpolation of inputs to the PALM domain.') +print('\nStart of vertical and horizontal interpolation of inputs to the PALM domain.') interp_files = [] regridder = None for wrf_file in wrf_files_proc: @@ -375,7 +357,9 @@ for wrf_file in wrf_files_proc: f_out.createDimension('south_north', len(jrange)) # copied vars - for varname in 'PH PHB HGT T W TSLB SMOIS MU MUB P PB PSFC no no2 o3 PM10 PM2_5_DRY'.split(): + wrfchem_dynamic = ['PH', 'PHB', 'HGT', 'T', 'W', 'TSLB', 'SMOIS', 'MU', 'MUB','P', 'PB', 'PSFC'] + wrfchem_variables = wrfchem_dynamic + wrfchem_spec + for varname in wrfchem_variables: v_wrf = f_wrf.variables[varname] v_out = f_out.createVariable(varname, 'f4', v_wrf.dimensions) v_out[:] = regridder.regrid(v_wrf[...,regridder.ys,regridder.xs]) @@ -493,7 +477,6 @@ if radiation_from_wrf: else: rad_times_proc = [] rad_values_proc = [] - # ===================== CREATE NETCDF DRIVER ============================== # calculate relative times from simulation start times_sec = [] diff --git a/dynamic/palm_dynamic_config.py b/dynamic/palm_dynamic_config.py index a483430d24c8511c8925928dd7ec07a2e250bcb5..fd9fd561e1810089f6b3636a040b66c1cfc3662d 100644 --- a/dynamic/palm_dynamic_config.py +++ b/dynamic/palm_dynamic_config.py @@ -1,21 +1,17 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- - #------------------------------------------------------------------------------# # # Scripts for processing of WRF-CHEM files to PALM dynamic driver. # #------------------------------------------------------------------------------# '''Configuration module. - Configuration options are sourced into this module's globals. ''' - import os.path from pathlib import Path import inspect - # Just for PyCharm and similar IDEs to allow autocompletion from config values if False: from palm_dynamic_defaults import * @@ -25,7 +21,7 @@ def configure(configname): global dir_scripts # get path of the palm_dynamic script to source default config and init dir_scripts = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) - print('Running palm_dynamic from:', dir_scripts) + print('\nRunning palm_dynamic from:', dir_scripts) # use config defaults configdefaultsfile = os.path.join(dir_scripts, "palm_dynamic_defaults.py") print('Default case config: ', configdefaultsfile) @@ -35,7 +31,6 @@ def configure(configname): # initialization of standard parameters done in script standardinitfile = os.path.join(dir_scripts, "palm_dynamic_init.py") print('Standard initialization: ', standardinitfile) - print('') # check existence of the supplied config file if not os.path.isfile(configfile): print("Config file " + configfile + " does not exists!") diff --git a/dynamic/palm_dynamic_output.py b/dynamic/palm_dynamic_output.py index 443b260b8775606d254b5f6d8813813250758ea9..c9fdfbe48feedae643dd87b554a44d042dd4eb17 100644 --- a/dynamic/palm_dynamic_output.py +++ b/dynamic/palm_dynamic_output.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- - #------------------------------------------------------------------------------# # # Scripts for processing of WRF-CHEM files to PALM dynamic driver. @@ -10,7 +9,6 @@ This file creates and writes the dynamic driver netcdf file based on preprepared transformed and interpolated wrf-chem files. ''' - import os import time import numpy as np @@ -115,32 +113,44 @@ def palm_dynamic_output(wrf_files, interp_files, dynamic_driver_file, times_sec, for side in boundary: if (side == 'left' or side == 'right'): if var == 'u': - _val_ls_forcing = outfile.createVariable('ls_forcing_'+ side +'_'+var, "f4", ("time", "z", "y"),fill_value=fillvalue_float) + _val_ls_forcing = outfile.createVariable('ls_forcing_'+ side +'_'+var, "f4", ("time", "z", "y"), + fill_value=fillvalue_float) elif var == 'v': - _val_ls_forcing = outfile.createVariable('ls_forcing_'+ side +'_'+var, "f4", ("time", "z", "yv"),fill_value=fillvalue_float) + _val_ls_forcing = outfile.createVariable('ls_forcing_'+ side +'_'+var, "f4", ("time", "z", "yv"), + fill_value=fillvalue_float) elif var == 'w': - _val_ls_forcing = outfile.createVariable('ls_forcing_'+ side +'_'+var, "f4", ("time", "zw", "y"),fill_value=fillvalue_float) + _val_ls_forcing = outfile.createVariable('ls_forcing_'+ side +'_'+var, "f4", ("time", "zw", "y"), + fill_value=fillvalue_float) else: - _val_ls_forcing = outfile.createVariable('ls_forcing_'+ side +'_'+var, "f4", ("time", "z", "y"),fill_value=fillvalue_float) + _val_ls_forcing = outfile.createVariable('ls_forcing_'+ side +'_'+var, "f4", ("time", "z", "y"), + fill_value=fillvalue_float) elif (side == 'south' or side == 'north'): if var == 'u': - _val_ls_forcing = outfile.createVariable('ls_forcing_'+ side +'_'+var, "f4", ("time", "z", "xu"),fill_value=fillvalue_float) + _val_ls_forcing = outfile.createVariable('ls_forcing_'+ side +'_'+var, "f4", ("time", "z", "xu"), + fill_value=fillvalue_float) elif var == 'v': - _val_ls_forcing = outfile.createVariable('ls_forcing_'+ side +'_'+var, "f4", ("time", "z", "x"),fill_value=fillvalue_float) + _val_ls_forcing = outfile.createVariable('ls_forcing_'+ side +'_'+var, "f4", ("time", "z", "x"), + fill_value=fillvalue_float) elif var == 'w': - _val_ls_forcing = outfile.createVariable('ls_forcing_'+ side +'_'+var, "f4", ("time", "zw", "x"),fill_value=fillvalue_float) + _val_ls_forcing = outfile.createVariable('ls_forcing_'+ side +'_'+var, "f4", ("time", "zw", "x"), + fill_value=fillvalue_float) else: - _val_ls_forcing = outfile.createVariable('ls_forcing_'+ side +'_'+var, "f4", ("time", "z", "x"),fill_value=fillvalue_float) + _val_ls_forcing = outfile.createVariable('ls_forcing_'+ side +'_'+var, "f4", ("time", "z", "x"), + fill_value=fillvalue_float) else: if var == 'u': - _val_ls_forcing = outfile.createVariable('ls_forcing_'+ side +'_'+var, "f4", ("time", "y", "xu"),fill_value=fillvalue_float) + _val_ls_forcing = outfile.createVariable('ls_forcing_'+ side +'_'+var, "f4", ("time", "y", "xu"), + fill_value=fillvalue_float) elif var == 'v': - _val_ls_forcing = outfile.createVariable('ls_forcing_'+ side +'_'+var, "f4", ("time", "yv", "x"),fill_value=fillvalue_float) + _val_ls_forcing = outfile.createVariable('ls_forcing_'+ side +'_'+var, "f4", ("time", "yv", "x"), + fill_value=fillvalue_float) elif var == 'w': - _val_ls_forcing = outfile.createVariable('ls_forcing_'+ side +'_'+var, "f4", ("time", "y", "x"),fill_value=fillvalue_float) + _val_ls_forcing = outfile.createVariable('ls_forcing_'+ side +'_'+var, "f4", ("time", "y", "x"), + fill_value=fillvalue_float) else: - _val_ls_forcing = outfile.createVariable('ls_forcing_'+ side +'_'+var, "f4", ("time", "y", "x"),fill_value=fillvalue_float) + _val_ls_forcing = outfile.createVariable('ls_forcing_'+ side +'_'+var, "f4", ("time", "y", "x"), + fill_value=fillvalue_float) # atrributes _val_ls_forcing.setncattr('lod', 2) if var not in atmos_var: @@ -148,7 +158,6 @@ def palm_dynamic_output(wrf_files, interp_files, dynamic_driver_file, times_sec, _val_ls_forcing.setncattr('units', 'kg/m3') else: _val_ls_forcing.setncattr('units', 'ppm') - # close output file outfile.close() # create all other variables in outout file add_interpDim(all_variables)