├── LICENSE ├── README.md ├── WRF_input_tools ├── DemoData │ ├── ETOPO1.0_1degree.nc.gz │ └── namelist.wps.2010Nash ├── README.md ├── Visualize_WPS_domain.ipynb ├── WRFDomainLib.py └── analyze_namelist.pl └── WRF_output_tools ├── Add_cdo_info_to_wrfout.d01.py ├── Add_cdo_info_to_wrfout.d0x.py ├── README.md └── collect_wrf_rainfall.pl /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Xiaodong Chen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WRF-tools 2 | -------------------------------------------------------------------------------- /WRF_input_tools/DemoData/ETOPO1.0_1degree.nc.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lucas-uw/WRF-tools/e6d34eba2ba92aa78b382c1ffce468a31fd86e00/WRF_input_tools/DemoData/ETOPO1.0_1degree.nc.gz -------------------------------------------------------------------------------- /WRF_input_tools/DemoData/namelist.wps.2010Nash: -------------------------------------------------------------------------------- 1 | &share 2 | wrf_core = 'ARW', 3 | max_dom = 3, 4 | start_date = '2010-05-01_00:00:00','2010-05-01_00:00:00','2010-05-01_00:00:00' 5 | end_date = '2010-05-03_00:00:00','2010-05-03_00:00:00','2010-05-03_00:00:00' 6 | interval_seconds = 21600, 7 | io_form_geogrid = 2, 8 | opt_output_from_geogrid_path = '/civil/shared/ganges/xiaodc/lulcc/data/sim.hist/2010Nash/ncep2/g2/wps_io/', 9 | debug_level = 0, 10 | / 11 | 12 | &geogrid 13 | parent_id = 1,1,2 14 | parent_grid_ratio = 1,3,3 15 | i_parent_start = 1,220,50 16 | j_parent_start = 1,80,50 17 | e_we = 403,391,751 18 | e_sn = 302,331,751 19 | geog_data_res = '2m', 20 | dx = 15000, 21 | dy = 15000, 22 | map_proj = 'lambert', 23 | ref_lat = 38.27, 24 | ref_lon = -101.96, 25 | truelat1 = 38.27, 26 | truelat2 = 38.27, 27 | stand_lon = -101.96, 28 | geog_data_path = '/civil/shared/ganges/xiaodc/lulcc/data/static_data', 29 | opt_geogrid_tbl_path = '/civil/shared/ganges/xiaodc/lulcc/data/sim.hist/2010Nash/ncep2/g2/control_files/', 30 | / 31 | 32 | &ungrib 33 | out_format = 'WPS', 34 | prefix = '/civil/shared/ganges/xiaodc/lulcc/data/sim.hist/2010Nash/ncep2/g2/wps_io/FILE', 35 | / 36 | 37 | &metgrid 38 | fg_name = '/civil/shared/ganges/xiaodc/lulcc/data/sim.hist/2010Nash/ncep2/g2/wps_io/FILE' 39 | io_form_metgrid = 2, 40 | opt_output_from_metgrid_path = '/civil/shared/ganges/xiaodc/lulcc/data/sim.hist/2010Nash/ncep2/g2/wps_io/', 41 | opt_metgrid_tbl_path = '/civil/shared/ganges/xiaodc/lulcc/data/sim.hist/2010Nash/ncep2/g2/control_files/', 42 | / 43 | 44 | &mod_levs 45 | press_pa = 201300 , 200100 , 100000 , 46 | 95000 , 90000 , 47 | 85000 , 80000 , 48 | 75000 , 70000 , 49 | 65000 , 60000 , 50 | 55000 , 50000 , 51 | 45000 , 40000 , 52 | 35000 , 30000 , 53 | 25000 , 20000 , 54 | 15000 , 10000 , 55 | 5000 , 1000 56 | / 57 | -------------------------------------------------------------------------------- /WRF_input_tools/README.md: -------------------------------------------------------------------------------- 1 | # WRF\_input\_tools 2 | 3 | ## 1. analyze\_namelist.pl 4 | This script helps to translate the parameterization schemes from the coded number to their names. Also it presents a short summary of the WRF configuration. To check the output, just run it with any namelist.input you have: 5 | ```sh 6 | $ analyze_namelist.pl -i 7 | ``` 8 | Below is an example output (for a two-way nested domain) 9 | ```sh 10 | [lucas.chen@localhost WRF_input_tools]$ analyze_namelist.pl -i /raid/lucas.chen/lulcc/data/sim.hist/1997CA/NARR/g5/wrf_io/namelist.input 11 | ===========================Time information=========================== 12 | Nest 0: 13 | start from : 1996-12-29 00:00:00 UTC 14 | run till : 1997-01-05 00:00:00 UTC 15 | time step : 90 s 16 | 17 | Nest 1: 18 | start from : 1996-12-29 00:00:00 UTC 19 | run till : 1997-01-05 00:00:00 UTC 20 | time step : 30 s 21 | 22 | Output time step: 60 minute(s) 23 | 24 | ===========================Space information========================== 25 | Horizontal Resolution: 26 | Nest 0: 27 | Grid size : 15000 m x 15000 m 28 | Grid dimension : 150 x 150 29 | Vertical Resolution: 35 layers 30 | 31 | Nest 1: 32 | Grid size : 5000 m x 5000 m 33 | Grid dimension : 211 x 211 34 | Vertical Resolution: 35 layers 35 | 36 | =======================Parameterication Schemes======================= 37 | Microphysics : WSM-5 WSM-5 38 | Longwave Radiation : RRTM RRTM 39 | Shortwave Radiation : Dudhia Dudhia 40 | Surface Layer : Rev. MM5 Rev. MM5 41 | Land Surface : Noah-MP Noah-MP 42 | Urban Surface : (not used) (not used) 43 | Lake : (Not turned on) 44 | Planetary Boundary Layer : Yonsei Univ. Yonsei Univ. 45 | Cumulus : Grell-Freitas (not used) 46 | Shallow Convection : (Not turned on) 47 | ``` 48 | 49 | Also you can find out more on its usage by running: 50 | ```sh 51 | $ analyze_namelist.pl 52 | ``` 53 | Note this version currently supports WRF v3.6.x. So you may want to double check the hashes in the script with WRF user guide to make sure the coding of each parameterization scheme has the same meaning, and modify them when different. I am not responsible for any mistakes from using this script to check your namelist.input. 54 | 55 | ## 2. Visualize\_WPS\_domain.ipynb 56 | This is to help visualize the WRF spatial domain from the WPS input (i.e. namelist.wps). You can find more on this script at [my blog post](https://wolfscie.wordpress.com/2017/10/05/visualizing-wrf-domain/). It contains some wheel functions that you can use for other purposes. 57 | 58 | 59 | -------------------------------------------------------------------------------- /WRF_input_tools/WRFDomainLib.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import cartopy.crs as ccrs 3 | import shapely.geometry as sgeom 4 | from copy import copy 5 | import re # regular expression 6 | 7 | def get_wps_param_value(wps_file, param_name, noutput, vartype): 8 | with open(wps_file, 'r') as file: 9 | for line in file.readlines(): 10 | words = re.split('=|\s+|,|\'', line) 11 | while '' in words: 12 | words.remove('') 13 | if param_name in words: 14 | if noutput==1: 15 | if vartype=='float': 16 | output = float(words[1]) 17 | elif vartype=='int': 18 | output = int(words[1]) 19 | else: 20 | output = words[1] 21 | if noutput>1: 22 | if vartype=='float': 23 | output = np.ones((noutput,1))*1.1 24 | for i in np.arange(noutput): 25 | output[i] = float(words[1+i]) 26 | elif vartype=='int': 27 | output = np.ones((noutput,1)) 28 | for i in np.arange(noutput): 29 | output[i] = int(words[1+i]) 30 | else: 31 | output = words[1:(1+noutput)] 32 | 33 | return output 34 | 35 | def get_proj_lcc(wps_file): 36 | ref_lat = get_wps_param_value(wps_file, 'ref_lat', 1, 'float') 37 | ref_lon = get_wps_param_value(wps_file, 'ref_lon', 1, 'float') 38 | par_lat1 = get_wps_param_value(wps_file, 'truelat1', 1, 'float') 39 | par_lat2 = get_wps_param_value(wps_file, 'truelat2', 1, 'float') 40 | standard_lon = get_wps_param_value(wps_file, 'stand_lon', 1, 'float') 41 | 42 | lccproj = ccrs.LambertConformal(central_longitude=ref_lon, central_latitude=ref_lat, 43 | standard_parallels=(par_lat1, par_lat2), globe=None, cutoff=10) 44 | return lccproj 45 | 46 | def calc_corner_point_latlon(center_lat, center_lon, e_we, e_ns, dx, dy, wpsproj, latlonproj, loc): 47 | center_x, center_y = wpsproj.transform_point(center_lon, center_lat, latlonproj) 48 | if loc=='ll': 49 | xpt = center_x - dx*e_we/2.0 50 | ypt = center_y - dy*e_ns/2.0 51 | elif loc=='lr': 52 | xpt = center_x + dx*e_we/2.0 53 | ypt = center_y - dy*e_ns/2.0 54 | elif loc=='ul': 55 | xpt = center_x - dx*e_we/2.0 56 | ypt = center_y + dy*e_ns/2.0 57 | elif loc=='ur': 58 | xpt = center_x + dx*e_we/2.0 59 | ypt = center_y + dy*e_ns/2.0 60 | corner_lon, corner_lat = latlonproj.transform_point(xpt, ypt, wpsproj) 61 | 62 | return corner_lon, corner_lat 63 | 64 | def calc_center_point_latlon(corner_lat_parent, corner_lon_parent, dx_parent, dy_parent, e_we, e_ns, dx, dy, i, j, wpsproj, latlonproj): 65 | corner_x_parent, corner_y_parent = wpsproj.transform_point(corner_lon_parent, corner_lat_parent, latlonproj) 66 | center_x_child = corner_x_parent + dx_parent*i + dx*e_we/2.0 67 | center_y_child = corner_y_parent + dy_parent*j + dy*e_ns/2.0 68 | center_lon_child, center_lat_child = latlonproj.transform_point(center_x_child, center_y_child, wpsproj) 69 | 70 | return center_lon_child, center_lat_child 71 | 72 | def calc_wps_domain_info(wps_file): 73 | ndomain = get_wps_param_value(wps_file, 'max_dom', 1, 'int') 74 | proj_name = get_wps_param_value(wps_file, 'map_proj', 1, '') 75 | 76 | grid_ratios = get_wps_param_value(wps_file, 'parent_grid_ratio', ndomain, 'int') 77 | i_parent_start_array = get_wps_param_value(wps_file, 'i_parent_start', ndomain, 'int') 78 | j_parent_start_array = get_wps_param_value(wps_file, 'j_parent_start', ndomain, 'int') 79 | e_we_array = get_wps_param_value(wps_file, 'e_we', ndomain, 'int') 80 | e_ns_array = get_wps_param_value(wps_file, 'e_sn', ndomain, 'int') 81 | dx_d01 = get_wps_param_value(wps_file, 'dx', 1, 'float') 82 | dy_d01 = get_wps_param_value(wps_file, 'dy', 1, 'float') 83 | cen_lat_d01 = get_wps_param_value(wps_file, 'ref_lat', 1, 'float') 84 | cen_lon_d01 = get_wps_param_value(wps_file, 'ref_lon', 1, 'float') 85 | 86 | center_lat_full = np.zeros((ndomain, 1)) 87 | center_lon_full = np.zeros((ndomain, 1)) 88 | half_size_ns_full = np.zeros((ndomain, 1)) 89 | half_size_we_full = np.zeros((ndomain, 1)) 90 | corner_lat_full = np.zeros((ndomain, 4)) # ll, lr, uf, ur 91 | corner_lon_full = np.zeros((ndomain, 4)) # ll, lr, uf, ur 92 | dx_full = np.zeros((ndomain, 1)) 93 | dy_full = np.zeros((ndomain, 1)) 94 | length_x = np.zeros((ndomain, 1)) 95 | length_y = np.zeros((ndomain, 1)) 96 | 97 | # get WPS projection info 98 | # LCC 99 | if proj_name=='lambert': 100 | wpsproj = get_proj_lcc(wps_file) 101 | 102 | # Geodetic, for lat/lon projection 103 | latlonproj = ccrs.Geodetic() 104 | 105 | # d01 106 | dx_full[0] = dx_d01 107 | dy_full[0] = dy_d01 108 | center_lat_full[0] = cen_lat_d01 109 | center_lon_full[0] = cen_lon_d01 110 | length_x[0] = dx_full[0]*e_we_array[0] 111 | length_y[0] = dy_full[0]*e_ns_array[0] 112 | if ndomain>1: 113 | e_we = int(e_we_array[0]) 114 | e_ns = int(e_ns_array[0]) 115 | else: 116 | e_we = e_we_array 117 | e_ns = e_ns_array 118 | corner_lon_full[0,0], corner_lat_full[0,0] = calc_corner_point_latlon(float(center_lat_full[0]), float(center_lon_full[0]), 119 | e_we, e_ns, 120 | float(dx_full[0]), float(dy_full[0]), 121 | wpsproj, latlonproj, 'll') 122 | corner_lon_full[0,1], corner_lat_full[0,1] = calc_corner_point_latlon(center_lat_full[0], center_lon_full[0], 123 | e_we, e_ns, 124 | dx_full[0], dy_full[0], 125 | wpsproj, latlonproj, 'lr') 126 | corner_lon_full[0,2], corner_lat_full[0,2] = calc_corner_point_latlon(center_lat_full[0], center_lon_full[0], 127 | e_we, e_ns, 128 | dx_full[0], dy_full[0], 129 | wpsproj, latlonproj, 'ul') 130 | corner_lon_full[0,3], corner_lat_full[0,3] = calc_corner_point_latlon(center_lat_full[0], center_lon_full[0], 131 | e_we, e_ns, 132 | dx_full[0], dy_full[0], 133 | wpsproj, latlonproj, 'ur') 134 | 135 | if ndomain>1: 136 | for i in np.arange(1,ndomain): 137 | dx_full[i] = dx_full[i-1]/float(grid_ratios[i]) 138 | dy_full[i] = dy_full[i-1]/float(grid_ratios[i]) 139 | length_x[i] = dx_full[i]*e_we_array[i] 140 | length_y[i] = dy_full[i]*e_ns_array[i] 141 | center_lon_full[i], center_lat_full[i] = calc_center_point_latlon(corner_lat_full[i-1,0], corner_lon_full[i-1,0], 142 | dx_full[i-1], dy_full[i-1], 143 | e_we_array[i], e_ns_array[i], 144 | dx_full[i], dy_full[i], 145 | i_parent_start_array[i], j_parent_start_array[i], 146 | wpsproj, latlonproj) 147 | corner_lon_full[i,0], corner_lat_full[i,0] = calc_corner_point_latlon(center_lat_full[i], center_lon_full[i], 148 | e_we_array[i], e_ns_array[i], 149 | dx_full[i], dy_full[i], 150 | wpsproj, latlonproj, 'll') 151 | corner_lon_full[i,1], corner_lat_full[i,1] = calc_corner_point_latlon(center_lat_full[i], center_lon_full[i], 152 | e_we_array[i], e_ns_array[i], 153 | dx_full[i], dy_full[i], 154 | wpsproj, latlonproj, 'lr') 155 | corner_lon_full[i,2], corner_lat_full[i,2] = calc_corner_point_latlon(center_lat_full[i], center_lon_full[i], 156 | e_we_array[i], e_ns_array[i], 157 | dx_full[i], dy_full[i], 158 | wpsproj, latlonproj, 'ul') 159 | corner_lon_full[i,3], corner_lat_full[i,3] = calc_corner_point_latlon(center_lat_full[i], center_lon_full[i], 160 | e_we_array[i], e_ns_array[i], 161 | dx_full[i], dy_full[i], 162 | wpsproj, latlonproj, 'ur') 163 | 164 | return wpsproj, latlonproj, corner_lat_full, corner_lon_full, length_x, length_y 165 | 166 | def reproject_corners(corner_lons, corner_lats, wpsproj, latlonproj): 167 | corner_x = np.zeros((4,1)) 168 | corner_y = np.zeros((4,1)) 169 | corner_x[0], corner_y[0] = wpsproj.transform_point(corner_lons[0], corner_lats[0], latlonproj) 170 | corner_x[1], corner_y[1] = wpsproj.transform_point(corner_lons[1], corner_lats[1], latlonproj) 171 | corner_x[2], corner_y[2] = wpsproj.transform_point(corner_lons[2], corner_lats[2], latlonproj) 172 | corner_x[3], corner_y[3] = wpsproj.transform_point(corner_lons[3], corner_lats[3], latlonproj) 173 | 174 | return corner_x, corner_y 175 | 176 | # all these functions below are necessary only when LCC projection is used. 177 | def find_side(ls, side): 178 | """ 179 | Given a shapely LineString which is assumed to be rectangular, return the 180 | line corresponding to a given side of the rectangle. 181 | 182 | """ 183 | minx, miny, maxx, maxy = ls.bounds 184 | points = {'left': [(minx, miny), (minx, maxy)], 185 | 'right': [(maxx, miny), (maxx, maxy)], 186 | 'bottom': [(minx, miny), (maxx, miny)], 187 | 'top': [(minx, maxy), (maxx, maxy)],} 188 | return sgeom.LineString(points[side]) 189 | 190 | 191 | def lambert_xticks(ax, ticks, size): 192 | """Draw ticks on the bottom x-axis of a Lambert Conformal projection.""" 193 | te = lambda xy: xy[0] 194 | lc = lambda t, n, b: np.vstack((np.zeros(n) + t, np.linspace(b[2], b[3], n))).T 195 | xticks, xticklabels = _lambert_ticks(ax, ticks, 'bottom', lc, te) 196 | ax.xaxis.tick_bottom() 197 | ax.set_xticks(xticks) 198 | ax.set_xticklabels([ax.xaxis.get_major_formatter()(xtick) for xtick in xticklabels], size=size) 199 | 200 | 201 | def lambert_yticks_left(ax, ticks, size): 202 | """Draw ricks on the left y-axis of a Lamber Conformal projection.""" 203 | te = lambda xy: xy[1] 204 | lc = lambda t, n, b: np.vstack((np.linspace(b[0], b[1], n), np.zeros(n) + t)).T 205 | yticks, yticklabels = _lambert_ticks(ax, ticks, 'left', lc, te) 206 | ax.yaxis.tick_left() 207 | ax.set_yticks(yticks) 208 | ax.set_yticklabels([ax.yaxis.get_major_formatter()(ytick) for ytick in yticklabels], size=size) 209 | 210 | 211 | def lambert_yticks_right(ax, ticks, size): 212 | """Draw ricks on the left y-axis of a Lamber Conformal projection.""" 213 | te = lambda xy: xy[1] 214 | lc = lambda t, n, b: np.vstack((np.linspace(b[0], b[1], n), np.zeros(n) + t)).T 215 | yticks, yticklabels = _lambert_ticks(ax, ticks, 'right', lc, te) 216 | ax.yaxis.tick_right() 217 | ax.set_yticks(yticks) 218 | ax.set_yticklabels([ax.yaxis.get_major_formatter()(ytick) for ytick in yticklabels], size=size) 219 | 220 | def _lambert_ticks(ax, ticks, tick_location, line_constructor, tick_extractor): 221 | """Get the tick locations and labels for an axis of a Lambert Conformal projection.""" 222 | outline_patch = sgeom.LineString(ax.outline_patch.get_path().vertices.tolist()) 223 | axis = find_side(outline_patch, tick_location) 224 | n_steps = 30 225 | extent = ax.get_extent(ccrs.PlateCarree()) 226 | _ticks = [] 227 | for t in ticks: 228 | xy = line_constructor(t, n_steps, extent) 229 | proj_xyz = ax.projection.transform_points(ccrs.Geodetic(), xy[:, 0], xy[:, 1]) 230 | xyt = proj_xyz[..., :2] 231 | ls = sgeom.LineString(xyt.tolist()) 232 | locs = axis.intersection(ls) 233 | if not locs: 234 | tick = [None] 235 | else: 236 | tick = tick_extractor(locs.xy) 237 | _ticks.append(tick[0]) 238 | # Remove ticks that aren't visible: 239 | ticklabels = copy(ticks) 240 | while True: 241 | try: 242 | index = _ticks.index(None) 243 | except ValueError: 244 | break 245 | _ticks.pop(index) 246 | ticklabels.pop(index) 247 | return _ticks, ticklabels 248 | -------------------------------------------------------------------------------- /WRF_input_tools/analyze_namelist.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | 3 | use Getopt::Long; 4 | 5 | %options_hash = ( 6 | h => \$help, 7 | i => \$namelist, 8 | c => \$coloropt, 9 | ); 10 | $status = &GetOptions(\%options_hash,"h","i=s","c"); 11 | 12 | if ($help || !-e $namelist) { 13 | &usage(); 14 | exit(0); 15 | } 16 | 17 | if ($coloropt) { 18 | use Term::ANSIColor; 19 | # Default color scheme is for up to 5 nesting. For more colors, edit the this array 20 | @colors = ('blue', 'red', 'green', 'yellow', 'magenta'); 21 | } 22 | 23 | 24 | # Building reference data for WRFV3.6.1 25 | %param_schemes = ( 26 | "mp_physics" => {"name"=>"Microphysics", 27 | "0"=>"(not used)", 28 | "1"=>"Kessler", 29 | "2"=>"Lin et al", 30 | "3"=>"WSM-3", 31 | "4"=>"WSM-5", 32 | "5"=>"Ferrier (new Eta)-fine", 33 | "6"=>"WSM-6", 34 | "7"=>"Goddard GCE", 35 | "8"=>"New Thompson", 36 | "9"=>"Milbrandt-Yau Double-Moment", 37 | "10"=>"Morrison double-moment", 38 | "11"=>"CAM 5.1", 39 | "13"=>"Stony Brook Univ.(Y. Lin)", 40 | "14"=>"WRF double-moment-5", 41 | "16"=>"WRF double-moment-6", 42 | "17"=>"NNSL 2-moment", 43 | "18"=>"NNSL 2-moment + CCN", 44 | "19"=>"NNSL single-moment", 45 | # "20"=>"NNSL Gilmore et al", 46 | "21"=>"NSSL-LFO 1-moment, 6 class", 47 | "28"=>"aerosol-aware Thompson", 48 | "30"=>"HUJI fast", 49 | "32"=>"HUJI full", 50 | "95"=>"Ferrier (old Eta)-coarse"}, 51 | "ra_lw_physics" => {"name"=>"Longwave Radiation", 52 | "0"=>"(not used)", 53 | "1"=>"RRTM", 54 | "2"=>"GFDL", 55 | "3"=>"CAM", 56 | "4"=>"RRTMG", 57 | "5"=>"New Goddard", 58 | "7"=>"Fu-Liou-Gu", 59 | "31"=>"Earch Held-Suarez", 60 | "99"=>"GFDL (Eta)"}, 61 | "ra_sw_physics" => {"name"=>"Shortwave Radiation", 62 | "1"=>"Dudhia", 63 | "2"=>"old Goddard", 64 | "3"=>"CAM", 65 | "4"=>"RRTMG", 66 | "5"=>"New Goddard", 67 | "7"=>"Fu-Liou-Gu", 68 | # "31"=>"Held-Suarez relx", 69 | "99"=>"GFDL"}, 70 | "sf_sfclay_physics" => {"name"=>"Surface Layer", 71 | "0"=>"(not used)", 72 | "1"=>"Rev. MM5", 73 | "2"=>"Monin-Obukhov (Janjic Eta)", 74 | "4"=>"QNSE", 75 | "5"=>"MYNN", 76 | "7"=>"Pleim-Xu", 77 | "10"=>"TEMF", 78 | "91"=>"old MM5"}, 79 | "sf_surface_physics" => {"name"=>"Land Surface", 80 | "0"=>"(not used)", 81 | "1"=>"5-layer thermal diffusion", 82 | "2"=>"Noah", 83 | "3"=>"RUC", 84 | "4"=>"Noah-MP", 85 | "5"=>"CLM4", 86 | "7"=>"Pleim-Xu", 87 | "8"=>"SSiB"}, 88 | "sf_urban_physics" => {"name"=>"Urban Surface", 89 | "0"=>"(not used)", 90 | "1"=>"Single-layer, urban canopy model", 91 | "2"=>"BEP", 92 | "3"=>"BEM"}, 93 | "sf_lake_physics" => {"name"=>"Lake", 94 | "1"=>"CLM4.5"}, 95 | "bl_pbl_physics" => {"name"=>"Planetary Boundary Layer", 96 | "0"=>"(not used)", 97 | "1"=>"Yonsei Univ.", 98 | "2"=>"Mellor-Yamada-Janjic (Eta) TKE", 99 | "4"=>"Quasi-Normal Scale Elimination", 100 | "5"=>"Mellor-Yamada Nakanishi and Niino Level 2.5", 101 | "6"=>"Mdllor-Yamada Nakanishi and Niino Level 3", 102 | "7"=>"ACM2 (Pleim)", 103 | "8"=>"BouLac", 104 | "9"=>"Bretherton-Park (UW)", 105 | "10"=>"Total Energy-Mass Flux (TEMF)", 106 | "12"=>"GBM TKE-type", 107 | "94"=>"Quasi-Normal Scale Elimination", 108 | "99"=>"MRF"}, 109 | "cu_physics" => {"name"=>"Cumulus", 110 | "1"=>"Kain-Fritsch (new Eta)", 111 | "2"=>"Betts-Miller-Janjic", 112 | "3"=>"Grell-Freitas", 113 | "4"=>"Simpf. Arakawa-Schubert", 114 | "5"=>"Grell 3D", 115 | "6"=>"Tiedtke", 116 | "7"=>"Zhang-McFarlane", 117 | "14"=>"New Simpf. Arakawa-Schubert (YSU)", 118 | "84"=>"New Simpf. Arakawa-Schubert (HWRF)", 119 | "93"=>"Grell-Devenyi", 120 | "99"=>"Old Kain-Fritsch"}, 121 | "shcu_physics" => {"name"=>"Shallow Convection", 122 | "2"=>"UW"}, 123 | # "" => {"name"=>""}, 124 | ); 125 | @schemes = ('mp_physics','ra_lw_physics','ra_sw_physics','sf_sfclay_physics','sf_surface_physics','sf_urban_physics','sf_lake_physics','bl_pbl_physics','cu_physics','shcu_physics'); 126 | 127 | 128 | 129 | # check the nesting info 130 | open(INFO,"grep max_dom $namelist | ") or die "$0: ERROR: no domain nesting info found. This is not good :)\n"; 131 | foreach() { 132 | chomp; 133 | s/\s+//; 134 | s/\=//; 135 | s/,/\ /; 136 | @fields = split/\s+/; 137 | $nest_layers = $fields[1]; 138 | } 139 | close(INFO); 140 | 141 | open(IN,$namelist) or die "$0: ERROR: cannot open namelist $namelist for reading\n"; 142 | foreach() { 143 | chomp; 144 | s/\s+//; 145 | s/\=//; 146 | @fields = split/\s+|,/; 147 | $ncols = @fields; 148 | if($ncols>1) { 149 | for($i=0; $i<$nest_layers; $i++) { 150 | $info{$fields[0]}{$i} = $fields[2*$i+1]; 151 | } 152 | } 153 | } 154 | close(IN); 155 | 156 | print "\n===========================Time information===========================\n"; 157 | for($nest=0; $nest<$nest_layers; $nest++) { 158 | if($coloropt) { 159 | print color($colors[$nest]), "Nest $nest:\n"; 160 | } 161 | else { 162 | print "Nest $nest:\n"; 163 | } 164 | $start_string = sprintf "%d-%02d-%02d %02d:%02d:%02d UTC",$info{'start_year'}{$nest},$info{'start_month'}{$nest},$info{'start_day'}{$nest},$info{'start_hour'}{$nest},$info{'start_minute'}{$nest},$info{'start_second'}{$nest}; 165 | printf " start from : %s\n",$start_string; 166 | $end_string = sprintf "%d-%02d-%02d %02d:%02d:%02d UTC",$info{'end_year'}{$nest},$info{'end_month'}{$nest},$info{'end_day'}{$nest},$info{'end_hour'}{$nest},$info{'end_minute'}{$nest},$info{'end_second'}{$nest}; 167 | printf " run till : %s\n",$end_string; 168 | $tmp = $info{'time_step'}{0}; 169 | for($i=1; $i<=$nest; $i++) { 170 | $tmp /= $info{'parent_time_step_ratio'}{$i}; 171 | } 172 | print " time step : $tmp s\n"; 173 | if($coloropt) {print color('reset'), "\n";} 174 | else{print "\n";} 175 | } 176 | print "Output time step: $info{'history_interval'}{'0'} minute(s)\n"; 177 | print "\n"; 178 | 179 | 180 | print "===========================Space information==========================\n"; 181 | print "Horizontal Resolution:\n"; 182 | for($nest=0; $nest<$nest_layers; $nest++) { 183 | if($coloropt) { 184 | print color($colors[$nest]), " Nest $nest:\n"; 185 | } 186 | else { 187 | print " Nest $nest:\n"; 188 | } 189 | printf " Grid size : %7s m x %7s m\n",$info{'dx'}{$nest},$info{'dy'}{$nest}; 190 | printf " Grid dimension : %4s x %4s\n",$info{'e_we'}{$nest},$info{'e_sn'}{$nest}; 191 | print " Vertical Resolution: $info{'e_vert'}{0} layers\n"; 192 | if($coloropt) {print color('reset'), "\n";} 193 | else{print "\n";} 194 | } 195 | 196 | print "=======================Parameterication Schemes=======================\n"; 197 | foreach $var(@schemes) { 198 | printf "%30s", "$param_schemes{$var}{'name'} :"; 199 | # print "test: $info{$var}{'0'}\n"; 200 | if($info{$var}{'0'} ne "") { 201 | for($nest=0; $nest<$nest_layers; $nest++) { 202 | printf "%-30s", " $param_schemes{$var}{$info{$var}{$nest}}"; 203 | } 204 | } 205 | else { 206 | printf "%-30s", " (Not turned on)"; 207 | } 208 | print "\n"; 209 | } 210 | 211 | print "\n"; 212 | 213 | 214 | 215 | 216 | 217 | sub usage() { 218 | print " analyze_namelist.pl: Interprate your WRF namalist.input\n"; 219 | print " Ver: 1.1.0\n"; 220 | print " Author: Xiaodong Chen\n"; 221 | print " Use: analyze_namelist.pl [-h] [-i ] [-c]\n\n"; 222 | 223 | print " -h Print this help\n"; 224 | print " -i namelist.input file to be analyzed\n"; 225 | print " -c Use color output. Needs support from Term::ANSIColor module\n\n"; 226 | 227 | print " This version works for WRFV3.6.x. Please check with the official user guide and modify the hash within the script for other versions.\n"; 228 | print " Reminder: This script works on WRFV3.6.1 namelist.input. For other versions, please double check the bash within the script before using it.\n"; 229 | exit; 230 | } 231 | -------------------------------------------------------------------------------- /WRF_output_tools/Add_cdo_info_to_wrfout.d01.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import numpy as np 4 | import netCDF4 as nc 5 | import sys 6 | 7 | def print_help(): 8 | print ' Add_cdo_info_to_wrfout.d01.py: Add necessary information to the WRF output, so that the coordinate system (LCC) can be recognized by CDO `cdo sinfo`. Only for d01 domain.' 9 | print ' Ver: 1.0.0' 10 | print ' Author: Xiaodong Chen \n' 11 | print ' Use: Add_cdo_info_to_wrfout.d01.py \n' 12 | print ' geogrid.exe output containing the half-resolution grids information' 13 | print ' e.g. For 15km grids WRF output, this file should contain the 7.5km grids info of the same domain' 14 | print ' Generate it from a seperate WPS/geogrid.exe run, with same namelist.wps but only half dx and dy, doubled e_we and e_sn\n' 15 | print ' WRF variable data after priliminary post-processing, or WRF output (i.e. wrfout_d01* file)' 16 | print ' Basic structure from `ncks -v XLAT,XLONG,RAINC,RAINNC wrfout_d01.xxxx yyyyR.nc;ncrcat yyyy1.nc yyyy2.nc `' 17 | print ' Should contain at least XLAT, XLONG, RAINC, RAINNC. Can be in single time snap or multiple snaps\n' 18 | print ' Output file name\n' 19 | print ' The first date in the .\n' 20 | print ' The first hour in the .\n' 21 | print ' Total time steps in the WRF output. Get the info from "ncdump -h"\n' 22 | print ' Note: For more detailed instructions and example, plesea check the README.md file in this folder\n' 23 | 24 | 25 | 26 | if len(sys.argv)==1: 27 | print_help() 28 | exit() 29 | 30 | geoinfo_file = sys.argv[1] # e.g. '/raid/xiaodong.chen/lulcc/data/sim.hist/1997CA/wps_io/geo_em.half_grids.d01.nc' 31 | 32 | 33 | wrffile = sys.argv[2] # e.g. '/raid/xiaodong.chen/lulcc/data/sim.hist/1997CA/rtot1h/rainfall_15km_1hr/regrid_test/rainfall_ncep2_1_1.nc' 34 | outfile = sys.argv[3] # e.g. '/raid/xiaodong.chen/lulcc/data/sim.hist/1997CA/rtot1h/rainfall_15km_1hr/regrid_test/rainfall_ncep2_1_1.cdo_ready.nc' 35 | start_date = sys.argv[4] # e.g. 1996-12-29 36 | start_hour = sys.argv[5] # e.g. 0 37 | frames = sys.argv[6] 38 | 39 | 40 | rootgroup = nc.Dataset(geoinfo_file,'r',format='NETCDF4') 41 | lat_matrix_half = rootgroup.variables['XLAT_M'][0,:] 42 | lon_matrix_half = rootgroup.variables['XLONG_M'][0,:] 43 | rootgroup.close() 44 | 45 | ingroup = nc.Dataset(wrffile,'r',format='NETCDF4') 46 | lat_matrix = ingroup.variables['XLAT'][0,:] 47 | lon_matrix = ingroup.variables['XLONG'][0,:] 48 | rainnc = ingroup.variables['RAINNC'][:] 49 | rainc = ingroup.variables['RAINC'][:] 50 | ingroup.close() 51 | nx = lat_matrix.shape[0] 52 | ny = lat_matrix.shape[1] 53 | 54 | outgroup = nc.Dataset(outfile,'w',format='NETCDF4') 55 | xdim = outgroup.createDimension('x',nx) 56 | ydim = outgroup.createDimension('y',ny) 57 | verdim = outgroup.createDimension('vertices',4) 58 | timedim = outgroup.createDimension('time',None) 59 | 60 | # Find the grid corner info 61 | lat_center = np.zeros((nx,ny)) 62 | lat_ll = np.zeros((nx,ny)) 63 | lat_lr = np.zeros((nx,ny)) 64 | lat_ur = np.zeros((nx,ny)) 65 | lat_ul = np.zeros((nx,ny)) 66 | 67 | lon_center = np.zeros((nx,ny)) 68 | lon_ll = np.zeros((nx,ny)) 69 | lon_lr = np.zeros((nx,ny)) 70 | lon_ur = np.zeros((nx,ny)) 71 | lon_ul = np.zeros((nx,ny)) 72 | 73 | for i in np.arange(nx): 74 | for j in np.arange(ny): 75 | lat_center[i,j] = lat_matrix[i,j] 76 | lat_ll[i,j] = lat_matrix_half[i*2,j*2] 77 | lat_lr[i,j] = lat_matrix_half[i*2,j*2+2] 78 | lat_ur[i,j] = lat_matrix_half[i*2+2,j*2+2] 79 | lat_ul[i,j] = lat_matrix_half[i*2+2,j*2] 80 | 81 | lon_center[i,j] = lon_matrix[i,j] 82 | lon_ll[i,j] = lon_matrix_half[i*2,j*2] 83 | lon_lr[i,j] = lon_matrix_half[i*2,j*2+2] 84 | lon_ur[i,j] = lon_matrix_half[i*2+2,j*2+2] 85 | lon_ul[i,j] = lon_matrix_half[i*2+2,j*2] 86 | 87 | 88 | # Add variables, notice the xxxxx.coordinates 89 | time_var = outgroup.createVariable('time','i4',('time')) 90 | time_var.units = 'hours since '+ start_date + ' ' + '%02d'%(int(start_hour)) + ':00:00 UTC' 91 | time_var.calendar = 'gregorian' 92 | 93 | lat_var = outgroup.createVariable('lat','f8',('x','y')) 94 | lat_var.stand_name = 'latitude' 95 | lat_var.long_name = 'latitude' 96 | lat_var.units = 'degrees_north' 97 | lat_var.bounds = 'lat_vertices' 98 | 99 | lon_var = outgroup.createVariable('lon','f8',('x','y')) 100 | lon_var.stand_name = 'longitude' 101 | lon_var.long_name = 'longitude' 102 | lon_var.units = 'degrees_east' 103 | lon_var.bounds = 'lon_vertices' 104 | 105 | rainnc_var = outgroup.createVariable('RAINNC','f8',('time','x','y')) 106 | rainnc_var.longname = 'ACCUMULATED TOTAL GRID SCALE PRECIPITATION' 107 | rainnc_var.units = 'mm' 108 | rainnc_var.coordinates = 'lat lon' 109 | 110 | rainc_var = outgroup.createVariable('RAINC','f8',('time','x','y')) 111 | rainc_var.longname = 'ACCUMULATED TOTAL CUMULUS PRECIPITATION' 112 | rainc_var.units = 'mm' 113 | rainc_var.coordinates = 'lat lon' 114 | 115 | latver_var = outgroup.createVariable('lat_vertices','f8',('x','y','vertices')) 116 | lonver_var = outgroup.createVariable('lon_vertices','f8',('x','y','vertices')) 117 | 118 | time_var[:] = np.arange(int(frames)) 119 | lat_var[:] = lat_center 120 | lon_var[:] = lon_center 121 | rainnc_var[:] = rainnc 122 | rainc_var[:] = rainc 123 | 124 | latver_var[:,:,0] = lat_ll 125 | latver_var[:,:,1] = lat_lr 126 | latver_var[:,:,2] = lat_ur 127 | latver_var[:,:,3] = lat_ul 128 | 129 | lonver_var[:,:,0] = lon_ll 130 | lonver_var[:,:,1] = lon_lr 131 | lonver_var[:,:,2] = lon_ur 132 | lonver_var[:,:,3] = lon_ul 133 | 134 | outgroup.close() 135 | -------------------------------------------------------------------------------- /WRF_output_tools/Add_cdo_info_to_wrfout.d0x.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import numpy as np 4 | import netCDF4 as nc 5 | import sys 6 | 7 | def print_help(): 8 | print ' Add_cdo_info_to_wrfout.d0x.py: Add necessary information to the WRF output, so that the coordinate system (LCC) can be recognized by CDO `cdo sinfo`. Only for nested domains.' 9 | print ' Ver: 1.0.0' 10 | print ' Author: Xiaodong Chen \n' 11 | print ' Use: Add_cdo_info_to_wrfout.d02.py \n' 12 | print ' geogrid.exe output containing the half-resolution grids information' 13 | print ' e.g. For 15km grids, it contains the 7.5km grids info' 14 | print ' Generate it from a seperate WPS/geogrid.exe run, with same namelist.wps but only half dx and dy, doubled e_we and e_sn\n' 15 | print ' WRF variable data after priliminary post-processing, or WRF output (i.e. wrfout_d02* file)' 16 | print ' Basic structure from `ncks -v XLAT,XLONG,RAINC,RAINNC wrfout_d01.xxxx yyyyR.nc;ncrcat yyyy1.nc yyyy2.nc `' 17 | print ' Should contain at least XLAT, XLONG, RAINC, RAINNC. Can be in single time snap or multiple snaps\n' 18 | print ' Output file name\n' 19 | print ' The first date in the .\n' 20 | print ' The first hour in the .\n' 21 | print ' Total time steps in the WRF output. Obtained by "ncdump -h"\n' 22 | 23 | 24 | 25 | if len(sys.argv)==1: 26 | print_help() 27 | exit() 28 | 29 | geoinfo_file = sys.argv[1] # e.g. '/raid/xiaodong.chen/lulcc/data/sim.hist/1997CA/wps_io/geo_em.half_grids.d01.nc' 30 | wrffile = sys.argv[2] # e.g. '/raid/xiaodong.chen/lulcc/data/sim.hist/1997CA/rtot1h/rainfall_15km_1hr/regrid_test/rainfall_ncep2_1_1.nc' 31 | outfile = sys.argv[3] # e.g. '/raid/xiaodong.chen/lulcc/data/sim.hist/1997CA/rtot1h/rainfall_15km_1hr/regrid_test/rainfall_ncep2_1_1.cdo_ready.nc' 32 | start_date = sys.argv[4] # e.g. 1996-12-29 33 | start_hour = sys.argv[5] # e.g. 0 34 | frames = sys.argv[5] 35 | 36 | offset = 4 # This is obtained by the "plot_WRF_lambert_points.ipynb" script 37 | 38 | rootgroup = nc.Dataset(geoinfo_file,'r',format='NETCDF4') 39 | lat_matrix_half = rootgroup.variables['XLAT_M'][0,:] 40 | lon_matrix_half = rootgroup.variables['XLONG_M'][0,:] 41 | rootgroup.close() 42 | 43 | ingroup = nc.Dataset(wrffile,'r',format='NETCDF4') 44 | lat_matrix = ingroup.variables['XLAT'][0,:] 45 | lon_matrix = ingroup.variables['XLONG'][0,:] 46 | rainnc = ingroup.variables['RAINNC'][:] 47 | rainc = ingroup.variables['RAINC'][:] 48 | ingroup.close() 49 | nx = lat_matrix.shape[0] 50 | ny = lat_matrix.shape[1] 51 | 52 | outgroup = nc.Dataset(outfile,'w',format='NETCDF4') 53 | xdim = outgroup.createDimension('x',nx) 54 | ydim = outgroup.createDimension('y',ny) 55 | verdim = outgroup.createDimension('vertices',4) 56 | timedim = outgroup.createDimension('time',None) 57 | 58 | # Find the grid corner info 59 | lat_center = np.zeros((nx,ny)) 60 | lat_ll = np.zeros((nx,ny)) 61 | lat_lr = np.zeros((nx,ny)) 62 | lat_ur = np.zeros((nx,ny)) 63 | lat_ul = np.zeros((nx,ny)) 64 | 65 | lon_center = np.zeros((nx,ny)) 66 | lon_ll = np.zeros((nx,ny)) 67 | lon_lr = np.zeros((nx,ny)) 68 | lon_ur = np.zeros((nx,ny)) 69 | lon_ul = np.zeros((nx,ny)) 70 | 71 | for i in np.arange(nx): 72 | for j in np.arange(ny): 73 | lat_center[i,j] = lat_matrix[i,j] 74 | lat_ll[i,j] = (lat_matrix_half[i*2+1+offset,j*2+1+offset] + lat_matrix_half[i*2+1+offset,j*2+2+offset] + lat_matrix_half[i*2+2+offset,j*2+2+offset] + lat_matrix_half[i*2+2+offset,j*2+1+offset])/4 # lat_matrix_half[i*2+offset,j*2] 75 | lat_lr[i,j] = (lat_matrix_half[i*2+1+offset,j*2+3+offset] + lat_matrix_half[i*2+1+offset,j*2+4+offset] + lat_matrix_half[i*2+2+offset,j*2+4+offset] + lat_matrix_half[i*2+2+offset,j*2+3+offset])/4 # lat_matrix_half[i*2+offset,j*2+2] 76 | lat_ur[i,j] = (lat_matrix_half[i*2+3+offset,j*2+3+offset] + lat_matrix_half[i*2+3+offset,j*2+4+offset] + lat_matrix_half[i*2+4+offset,j*2+4+offset] + lat_matrix_half[i*2+4+offset,j*2+3+offset])/4 # lat_matrix_half[i*2+2+offset,j*2+2] 77 | lat_ul[i,j] = (lat_matrix_half[i*2+3+offset,j*2+1+offset] + lat_matrix_half[i*2+3+offset,j*2+2+offset] + lat_matrix_half[i*2+4+offset,j*2+2+offset] + lat_matrix_half[i*2+4+offset,j*2+1+offset])/4 # lat_matrix_half[i*2+2+offset,j*2] 78 | 79 | lon_center[i,j] = lon_matrix[i,j] 80 | lon_ll[i,j] = (lon_matrix_half[i*2+1+offset,j*2+1+offset] + lon_matrix_half[i*2+1+offset,j*2+2+offset] + lon_matrix_half[i*2+2+offset,j*2+2+offset] + lon_matrix_half[i*2+2+offset,j*2+1+offset])/4 # lon_matrix_half[i*2+offset,j*2] 81 | lon_lr[i,j] = (lon_matrix_half[i*2+1+offset,j*2+3+offset] + lon_matrix_half[i*2+1+offset,j*2+4+offset] + lon_matrix_half[i*2+2+offset,j*2+4+offset] + lon_matrix_half[i*2+2+offset,j*2+3+offset])/4 # lon_matrix_half[i*2+offset,j*2+2] 82 | lon_ur[i,j] = (lon_matrix_half[i*2+3+offset,j*2+3+offset] + lon_matrix_half[i*2+3+offset,j*2+4+offset] + lon_matrix_half[i*2+4+offset,j*2+4+offset] + lon_matrix_half[i*2+4+offset,j*2+3+offset])/4 # lon_matrix_half[i*2+2+offset,j*2+2] 83 | lon_ul[i,j] = (lon_matrix_half[i*2+3+offset,j*2+1+offset] + lon_matrix_half[i*2+3+offset,j*2+2+offset] + lon_matrix_half[i*2+4+offset,j*2+2+offset] + lon_matrix_half[i*2+4+offset,j*2+1+offset])/4 # lon_matrix_half[i*2+2+offset,j*2] 84 | 85 | 86 | # Add variables, notice the xxxxx.coordinates 87 | time_var = outgroup.createVariable('time','i4',('time')) 88 | time_var.units = 'hours since '+ start_date + ' ' + '%02d'%(int(start_hour)) + ':00:00 UTC' 89 | time_var.calendar = 'gregorian' 90 | 91 | lat_var = outgroup.createVariable('lat','f8',('x','y')) 92 | lat_var.stand_name = 'latitude' 93 | lat_var.long_name = 'latitude' 94 | lat_var.units = 'degrees_north' 95 | lat_var.bounds = 'lat_vertices' 96 | 97 | lon_var = outgroup.createVariable('lon','f8',('x','y')) 98 | lon_var.stand_name = 'longitude' 99 | lon_var.long_name = 'longitude' 100 | lon_var.units = 'degrees_east' 101 | lon_var.bounds = 'lon_vertices' 102 | 103 | rainnc_var = outgroup.createVariable('RAINNC','f8',('time','x','y')) 104 | rainnc_var.longname = 'ACCUMULATED TOTAL GRID SCALE PRECIPITATION' 105 | rainnc_var.units = 'mm' 106 | rainnc_var.coordinates = 'lat lon' 107 | 108 | rainc_var = outgroup.createVariable('RAINC','f8',('time','x','y')) 109 | rainc_var.longname = 'ACCUMULATED TOTAL CUMULUS PRECIPITATION' 110 | rainc_var.units = 'mm' 111 | rainc_var.coordinates = 'lat lon' 112 | 113 | latver_var = outgroup.createVariable('lat_vertices','f8',('x','y','vertices')) 114 | lonver_var = outgroup.createVariable('lon_vertices','f8',('x','y','vertices')) 115 | 116 | time_var[:] = np.arange(int(frames)) 117 | lat_var[:] = lat_center 118 | lon_var[:] = lon_center 119 | rainnc_var[:] = rainnc 120 | rainc_var[:] = rainc 121 | 122 | latver_var[:,:,0] = lat_ll 123 | latver_var[:,:,1] = lat_lr 124 | latver_var[:,:,2] = lat_ur 125 | latver_var[:,:,3] = lat_ul 126 | 127 | lonver_var[:,:,0] = lon_ll 128 | lonver_var[:,:,1] = lon_lr 129 | lonver_var[:,:,2] = lon_ur 130 | lonver_var[:,:,3] = lon_ul 131 | 132 | outgroup.close() 133 | -------------------------------------------------------------------------------- /WRF_output_tools/README.md: -------------------------------------------------------------------------------- 1 | # README 2 | Disclaimer: All these scripts/codes are developped for use in my research project. I have tested them with various inputs in my cases. However, this does not guarantee that they would also work in your case. If you have any questions, please feel free to file an issue here, and I will try to help get it done. 3 | 4 | ### 1. collect_wrf_rainfall.pl 5 | This script collects total precipitation (i.e. RAINC+RAINNC) from WRF output files wrfout_d. Currently it only handles d01 domain. 6 | The total precipitation is stored as RAIN variable in the output file 7 | 8 | 9 | ### 2. Add_cdo_info_to_wrfout.d01.py 10 | 11 | Most of the remapping methods (presumably in Climate Data Operator CDO) uses only the distance info of target point to the reference point, so these remapping can be directly applied to the WRF output (wrfout_d). For __precipitation__, however, it is often required to do a conservation remapping. In this situation, along with the lat/lon info we also need to know the corner lat/lon of each grid (so the area of the grid can be calculated by CDO). This script extracts precipitation data, and adds the corner information to the WRF output. In my case, this script is required for Lambert Conformal Conic projection and Mercator projection. For other projections, I am not sure if CDO could recognize the projection (so this script is no longer needed). 12 | 13 | Before running this script, a special WPS run (more specifically, only geogrid.exe) is required. Below shows the modifications needed, basically we use half-size grids (i.e. 15km to 7.5km) to cover the same domain (so at each direction we need to double the grid number). 14 | - namelist.wps for the WRF simulation: 15 | 16 | e_we = 80, 17 | e_sn = 80, 18 | dx = 15000, 19 | dy = 15000, 20 | - namelist.wps for this special run: 21 | 22 | e_we = 160, 23 | e_sn = 160, 24 | dx = 7500, 25 | dy = 7500, 26 | 27 | Then supply the generated geo_em.d01.nc to this script. All other inputs are explained when you run the script without any input argument. 28 | 29 | ### 3. Add_cdo_info_to_wrfout.d0x.py 30 | This script provides the same function as its d01 brother. However, to accommodate the nested domain, the namelist.wps need to be modified in a different way: 31 | 32 | - note here it has only one nested domain. For multiple domains, just focus on the nested domain level you need and its parenet level. 33 | - namelist.wps for the WRF simulation: 34 | 35 | parent_id = 1,1 36 | parent_grid_ratio = 1,__3__ 37 | i_parent_start = 1,__40__ 38 | j_parent_start = 1,__35__ 39 | e_we = 150,__211__ 40 | e_sn = 140,__211__ 41 | geog_data_res = '2m','30s' 42 | dx = 15000, 43 | dy = 15000, 44 | 45 | - namelist.wps for the special run: 46 | 47 | parent_id = 1,1 48 | parent_grid_ratio = 1,__6__ 49 | i_parent_start = 1,__39__ 50 | j_parent_start = 1,__34__ 51 | e_we = 150,__481__ 52 | e_sn = 140,__481__ 53 | geog_data_res = '2m', '30s' 54 | dx = 15000, 55 | dy = 15000, 56 | 57 | The basic idea is to reduce the grid size in the desired domain (by doubling the grid_ratio). The grid number needs to be at least doubled (so here e_we needs to be larger than 211\*2=422), also it still needs to satisfy WPS requirement (i.e. 3\*int+1), so here I went with 481. You can alternatively use something like 451 here. Also reduce the i_parent and j_parent start index by 1. This has to always be 1, otherwise you will need to change the parameter in the script. 58 | -------------------------------------------------------------------------------- /WRF_output_tools/collect_wrf_rainfall.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env perl 2 | 3 | $start_time = shift; # e.g. 1970-2-16-0 4 | $end_time = shift; # e.g. 1970-2-18-0 5 | $wrfoutdir = shift; 6 | $wrfoutinterval = shift; 7 | $outfile = shift; 8 | 9 | if($start_time eq "") { 10 | print " collect_wrf_rainfall.pl Collect total precipitation from WRF output\n"; 11 | print " Ver: 1.0.0\n"; 12 | print " Author: Xiaodong Chen \n"; 13 | print " Use: collect_rainfall_adv.pl \n"; 14 | print " First timestamp in wrfout. e.g. 1970-2-16-0\n"; 15 | print " Last timestamp in wrfout. e.g. 1970-2-16-0\n"; 16 | print " Directory containing the wrfout_d* files\n"; 17 | print " Time interval in WRF output. Unit is in hour\n"; 18 | print " Output file name\n"; 19 | 20 | exit; 21 | } 22 | 23 | ($year, $month, $day, $hour) = split/-/, $start_time; 24 | ($syear, $smonth, $sday, $shour) = split/-/, $start_time; 25 | ($eyear, $emonth, $eday, $ehour) = split/-/, $end_time; 26 | 27 | @days = (31,28,31,30,31,30,31,31,30,31,30,31); 28 | 29 | `mkdir -p tmp`; 30 | `rm tmp/*`; 31 | 32 | # 1. collect necessary data 33 | @files = (); 34 | $count = 1; 35 | while ($year<$eyear || ($year==$eyear && $month<$emonth) || ($year==$eyear && $month==$emonth && $day<$eday) || ($year==$eyear && $month==$emonth && $day==$eday && $hour<=$ehour)) { 36 | $timestamp = sprintf "%04d-%02d-%02d_%02d",$year,$month,$day,$hour; 37 | $cmd = sprintf "ncks -v XLAT,XLONG,RAINC,RAINNC $wrfoutdir/wrfout_d01\_$timestamp:00:00 tmp/int.%03d.nc", $count; 38 | (system($cmd)==0) or die "$0: ERROR: $cmd failed\n"; 39 | $files[$count-1] = sprintf "tmp/int.%03d.nc", $count; 40 | $count++; 41 | $hour+=$wrfoutinterval; 42 | if($hour==24) { 43 | $hour=0; 44 | $day++; 45 | $days_in_month = $days[$month-1]; 46 | if (($year % 400 == 0 || ($year%4==0 && $year%100!=0)) && $month == 2) { 47 | $days_in_month++; 48 | } 49 | if($day==$days_in_month+1) { 50 | $day=1; 51 | $month++; 52 | if($month==13) { 53 | $month=1; 54 | $year++; 55 | } 56 | } 57 | } 58 | } 59 | $count = $count-1; 60 | 61 | # 2. concatenate files 62 | $cmd = "ncrcat @files tmp/wrfout.tmp1.nc"; 63 | (system($cmd)==0) or die "$0: ERROR: $cmd failed\n"; 64 | 65 | $cmd = "rm tmp/int.*.nc"; 66 | (system($cmd)==0) or die "$0: ERROR: $cmd failed\n"; 67 | 68 | # 3. clean file, set the calendar 69 | $cmd = "ncap -O -s RAIN=RAINC+RAINNC tmp/wrfout.tmp1.nc tmp/wrfout.tmp2.nc"; 70 | (system($cmd)==0) or die "$0: ERROR: $cmd failed\n"; 71 | 72 | $cmd = "ncks -v RAIN,XLAT,XLONG tmp/wrfout.tmp2.nc tmp/wrfout.tmp3.nc"; 73 | (system($cmd)==0) or die "$0: ERROR: $cmd failed\n"; 74 | 75 | $cmd = sprintf "cdo setreftime,1900-01-01,0,1s -settaxis,%04d-%02d-%02d,%02d:00:00,${wrfoutinterval}hour -setcalendar,standard tmp/wrfout.tmp3.nc tmp/wrfout.tmp4.nc", $syear, $smonth, $sday, $shour; 76 | (system($cmd)==0) or die "$0: ERROR: $cmd failed\n"; 77 | 78 | $cmd = "rm tmp/wrfout.tmp1.nc tmp/wrfout.tmp2.nc tmp/wrfout.tmp3.nc"; 79 | (system($cmd)==0) or die "$0: ERROR: $cmd failed\n"; 80 | 81 | # 4. calcuate the interval precipitation 82 | $tmpvar1 = $count-2; 83 | $tmpvar2 = $count-1; 84 | $cmd = "ncks -d time,0,$tmpvar1 tmp/wrfout.tmp4.nc tmp/data1.nc"; 85 | (system($cmd)==0) or die "$0: ERROR: $cmd failed\n"; 86 | 87 | $cmd = "ncks -d time,1,$tmpvar2 tmp/wrfout.tmp4.nc tmp/data2.nc"; 88 | (system($cmd)==0) or die "$0: ERROR: $cmd failed\n"; 89 | 90 | $cmd = "rm tmp/wrfout.tmp4.nc"; 91 | (system($cmd)==0) or die "$0: ERROR: $cmd failed\n"; 92 | 93 | $cmd = sprintf "cdo setreftime,1900-01-01,0,1s -settaxis,%04d-%02d-%02d,%02d:00:00,${wrfoutinterval}hour -setcalendar,standard tmp/data2.nc tmp/data2.set_calendar.nc",$syear, $smonth, $sday, $shour; 94 | (system($cmd)==0) or die "$0: ERROR: $cmd failed\n"; 95 | 96 | $cmd = "ncdiff tmp/data2.set_calendar.nc tmp/data1.nc tmp/tmp1.nc"; 97 | (system($cmd)==0) or die "$0: ERROR: $cmd failed\n"; 98 | 99 | # 5. adjust lat/lon info, making it to work with ncview 100 | 101 | $cmd = "ncks -v RAIN tmp/tmp1.nc $outfile"; 102 | (system($cmd)==0) or die "$0: ERROR: $cmd failed\n"; 103 | 104 | $cmd = "ncks -v XLAT,XLONG tmp/data1.nc tmp/tmp3.nc"; 105 | (system($cmd)==0) or die "$0: ERROR: $cmd failed\n"; 106 | 107 | $cmd = "ncwa -a time tmp/tmp3.nc tmp/tmp4.nc"; 108 | (system($cmd)==0) or die "$0: ERROR: $cmd failed\n"; 109 | 110 | $cmd = "ncks -v XLAT,XLONG tmp/tmp4.nc tmp/tmp5.nc"; 111 | (system($cmd)==0) or die "$0: ERROR: $cmd failed\n"; 112 | 113 | $cmd = "ncks -A tmp/tmp5.nc $outfile"; 114 | (system($cmd)==0) or die "$0: ERROR: $cmd failed\n"; 115 | 116 | 117 | $cmd = "ncrename -v XLAT,lat -v XLONG,lon $outfile"; 118 | (system($cmd)==0) or die "$0: ERROR: $cmd failed\n"; 119 | 120 | $cmd = "ncatted -O -a stand_name,lat,a,c,'latitude' -a stand_name,lon,a,c,'longitude' -a long_name,lat,a,c,'latitude' -a long_name,lon,a,c,'longitude' $outfile"; 121 | (system($cmd)==0) or die "$0: ERROR: $cmd failed\n"; 122 | 123 | $cmd = "ncatted -O -a long_name,RAIN,a,c,'Total precipitation for the next $wrfoutinterval hour(s)' -a units,RAIN,a,c,'mm/${wrfoutinterval}hr' -a coordinates,RAIN,a,c,'lat lon' $outfile"; 124 | (system($cmd)==0) or die "$0: ERROR: $cmd failed\n"; 125 | 126 | $cmd = "rm tmp/tmp1.nc tmp/tmp3.nc tmp/tmp4.nc tmp/tmp5.nc tmp/data1.nc tmp/data2.nc tmp/data2.set_calendar.nc"; 127 | (system($cmd)==0) or die "$0: ERROR: $cmd failed\n"; 128 | --------------------------------------------------------------------------------