Skip to content

Commit

Permalink
added some structure to the project
Browse files Browse the repository at this point in the history
  • Loading branch information
lewisjared committed Jan 9, 2018
1 parent 623bc0f commit 2c7b525
Show file tree
Hide file tree
Showing 18 changed files with 8,308 additions and 0 deletions.
3 changes: 3 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
include README.rst
include wrfconf/conf/README.namelist
include wrfconf/conf/wrfconf_params.yml
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# wrfconf

A commandline tool for generating WRF configuration from structured YAML files

174 changes: 174 additions & 0 deletions examples/run.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
---
meta:
owner: Jared Lewis
email: [email protected]
run_name: test

wps:
share:
wrf_core: ARW
max_dom: 2
start_date: ['2006-08-16_12:00:00','2006-08-16_12:00:00']
end_date: ['2006-08-16_18:00:00','2006-08-16_12:00:00']
interval_seconds: 21600
active_grid: True, True,
subgrid_ratio_x: 1
subgrid_ratio_y: 1
io_form_geogrid: 2
opt_output_from_geogrid_path: './'
debug_level: 0

start_date: ['2000-01-24_12:00:00','2000-01-24_12:00:00']
end_date: ['2000-01-25_12:00:00','2000-01-24_12:00:00']
start_year: [2006, 2006]
start_month: [08, 08]
start_day: [16, 16]
start_hour: [12, 12]
start_minute: [00, 00]
start_second: [00, 00]
end_year: [2006, 2006]
end_month: [08, 08]
end_day: [16, 16]
end_hour: [18, 18]
end_minute: [00, 00]
end_second: [00, 00]

geogrid:
parent_id: [1, 1]
parent_grid_ratio: 1, 3,
i_parent_start: 1, 31,
j_parent_start: 1, 17,
s_we: [1, 1]
e_we: [ 74, 112]
s_sn: [ 1, 1]
e_sn: [ 61, 97]
geog_data_res: ['default','default']
dx: 30000
dy: 30000
map_proj: 'lambert'
ref_lat: 34.83
ref_lon: -81.03
ref_x: 37.0
ref_y: 30.5
truelat1: 30.0
truelat2: 60.0
stand_lon: -98.0
geog_data_path: '/glade/p/work/wrfhelp/WPS_GEOG/'
opt_geogrid_tbl_path: 'geogrid/'

ungrib:
out_format: 'WPS'
prefix: 'FILE'

metgrid:
fg_name: 'FILE'
constants_name: './TAVGSFC'
io_form_metgrid: 2
opt_output_from_metgrid_path: './'
opt_metgrid_tbl_path: 'metgrid/'
process_only_bdy: 5

mod_levs:
press_pa: [201300 , 200100 , 100000 , 95000 , 90000 , 85000 , 80000 , 75000 , 70000 , 65000 , 60000 , 55000 , 50000 , 45000 , 40000 , 35000 , 30000 , 25000 , 20000 , 15000 , 10000 , 5000 , 1000]

plotfmt:
ix: 100
jx: 100
ioff: 30
joff: 30


namelist:
time_control:
run_days: 0
run_hours: 36

start_year: [2017, 2017, 2017, 2017]
start_month: [1, 1, 1, 1]
start_day: [30, 30, 30, 30]
end_year: [2017, 2017, 2017, 2017]
end_month: [1, 1, 1, 1]
end_day: [30, 30, 30, 30]
end_hour: [12, 12, 12, 12]
interval_seconds: 10800
input_from_file: [True, True, True, True]
history_interval: [ 60, 60, 60, 60]
frames_per_outfile: [ 1000, 1000, 1000, 1000]
restart: False,
restart_interval: 5000,
io_form_history: 2
io_form_restart: 2
io_form_input: 2
io_form_boundary: 2
debug_level: 0


domains:
time_step: 180,
time_step_fract_num: 0,
time_step_fract_den: 1,
max_dom: 4,
e_we: [ 79, 70, 121, 70]
e_sn: [ 61, 79, 79, 67]
e_vert: [ 30, 30, 30, 30]
p_top_requested: 5000,
num_metgrid_levels: 32,
num_metgrid_soil_levels: 4,
dx: [30000, 10000, 3333.33, 1111.11]
dy: [30000, 10000, 3333.33, 1111.11]
grid_id: [ 1, 2, 3, 4]
parent_id: [ 0, 1, 2, 3]
i_parent_start: [ 1, 31, 13, 60]
j_parent_start: [ 1, 7, 10, 45]
parent_grid_ratio: [ 1, 3, 3, 3]
parent_time_step_ratio: [ 1, 3, 3, 3]
feedback: 1,
smooth_option: 0


physics:
mp_physics: [ 3, 3, 3, 3]
ra_lw_physics: [ 1, 1, 1, 1]
ra_sw_physics: [ 1, 1, 1, 1]
radt: [ 30, 30, 30, 30]
sf_sfclay_physics: [ 1, 1, 1, 1]
sf_surface_physics: [ 2, 2, 2, 2]
bl_pbl_physics: [ 1, 1, 1, 1]
bldt: [ 0, 0, 0, 0]
cu_physics: [ 1, 1, 0, 0]
cudt: [ 5, 5, 5, 5]
isfflx: 1,
ifsnow: 1,
icloud: 1,
surface_input_source: 3,
num_soil_layers: 4
num_land_cat: 21
sf_urban_physics: [ 0, 0, 0, 0]

dynamics:
w_damping: 0,
diff_opt: [ 1, 1, 1, 1]
km_opt: [ 4, 4, 4, 4]
diff_6th_opt: [ 0, 0, 0, 0]
diff_6th_factor: 0.12, 0.12, 0.12, 0.12
base_temp: 290.
damp_opt: 0,
zdamp: [5000., 5000., 5000., 5000.]
dampcoef: [0.2, 0.2, 0.2, 0.2]
khdif: [ 0, 0, 0, 0]
kvdif: [ 0, 0, 0, 0]
non_hydrostatic: [ True, True, True, True]
moist_adv_opt: [ 1, 1, 1, 1]
scalar_adv_opt: [ 1, 1, 1, 0]

bdy_control:
spec_bdy_width: 5,
spec_zone: 1,
relax_zone: 4,
specified: [True, False,False,False]
nested: [False, True, True,True]

namelist_quilt:
nio_tasks_per_group: 0,
nio_groups: 1,

33 changes: 33 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
from os import path

from setuptools import setup, find_packages

from wrfconf import __version__

with open(path.join(path.abspath(path.dirname(__file__)), 'README.md')) as f:
long_description = f.read()

setup(name='wrfconf',
version=__version__,
description='Configuration generator for WRF',
long_description=long_description,
author='Jared Lewis',
author_email='[email protected]',
license='MIT',
keywords='wrf config generate generator science forecast',
classifiers=[
'Development Status :: 3 - Alpha',
'Intended Audience :: System Administrators',
'License :: OSI Approved :: MIT License',
'Programming Language :: Python :: 2'
'Programming Language :: Python :: 3'
],
install_requires=[
'pyyaml'
],
packages=find_packages(exclude='tests'),
entry_points={
'console_scripts':
['wrfconf = wrfconf.cli:main']
},
zip_safe=False)
Empty file added tests/__init__.py
Empty file.
Empty file added tests/conf/__init__.py
Empty file.
78 changes: 78 additions & 0 deletions tests/conf/test_parse_namelist.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
from unittest import TestCase

from wrfconf.conf.parse_namelist import ConfigItem, get_next_item


class TestGetNextItem(TestCase):

def get_lines(self, t):
lines = t.split('\n')
return [l + '\n' for l in lines]

def test_basic(self):
lines = self.get_lines(""" end_day (max_dom) = 12, ; two digit day of ending time
end_hour (max_dom) = 12, ; two digit hour of ending time
end_minute (max_dom) = 00, ; two digit minute of ending time""")
self.assertEqual(get_next_item(lines), 'end_day (max_dom) = 12, ; two digit day of ending time')

def test_basic_2(self):
lines = self.get_lines(""" end_second (max_dom) = 00, ; two digit second of ending time
It also controls when the nest domain integrations end
All start and end times are used by real.exe.
Note that one may use either run_days/run_hours etc. or
end_year/month/day/hour etc. to control the length of
model integration. But run_days/run_hours
takes precedence over the end times.
Program real.exe uses start and end times only.
interval_seconds = 10800, ; time interval between incoming real data, which will be the interval
between the lateral boundary condition file
input_from_file (max_dom) = T, ; whether nested run will have input files for domains other than 1
fine_input_stream (max_dom) = 0, ; field selection from nest input for its initialization
0: all fields are used; 2: only static and time-varying, masked land
surface fields are used. In V3.2, this requires the use of
io_form_auxinput2""")
self.assertEqual(get_next_item(lines), """end_second (max_dom) = 00, ; two digit second of ending time
It also controls when the nest domain integrations end
All start and end times are used by real.exe.""")

def test_basic_3(self):
lines = self.get_lines(""" cycling = F, ; whether this run is a cycling run, if so, initializes look-up table for Thompson schemes only
restart_interval = 1440, ; restart output file interval in minutes
reset_simulation_start = F, ; whether to overwrite simulation_start_date with forecast start time
io_form_history = 2, ; 2 = netCDF """)
self.assertEqual(get_next_item(lines), 'cycling = F, ; whether this run is a cycling run, if so, initializes look-up table for Thompson schemes only')

def test_advanced(self):
lines = self.get_lines("""For additional regional climate surface fields
output_diagnostics = 1 ; adds 36 surface diagnostic arrays (max/min/mean/std)
auxhist3_outname = 'wrfxtrm_d<domain>_<date>' ; file name for added diagnostics
io_form_auxhist3 = 2 ; netcdf
auxhist3_interval = 1440 ; minutes between outputs (1440 gives daily max/min)
frames_per_auxhist3 = 1 ; output times per file
Note: do restart only at multiple of auxhist3_intervals
For observation nudging:
auxinput11_interval = 10 ; interval in minutes for observation data. It should be
set as or more frequently as obs_ionf (with unit of
coarse domain time step).
auxinput11_end_h = 6 ; end of observation time in hours""")
self.assertEqual(get_next_item(lines), """output_diagnostics = 1 ; adds 36 surface diagnostic arrays (max/min/mean/std)""")

class TestConfigItem(TestCase):
def test_basic_parse(self):
i = ConfigItem(' time_step_fract_num = 0, ; numerator for fractional time step\n')
self.assertFalse(i.is_section)
self.assertEqual(i.name, 'time_step_fract_num')
self.assertEqual(i.default, '0,')
self.assertEqual(i.description, 'numerator for fractional time step')

def test_multiline(self):
i = ConfigItem(" e_vert (max_dom) = 30, ; end index in z (vertical) direction (staggered dimension)\n Note: this refers to full levels including surface and top\n vertical dimensions need to be the same for all nests\n Note: most variables are unstaggered (= staggered dim - 1)\n")
self.assertFalse(i.is_section)
self.assertEqual(i.name, 'e_vert')
self.assertTrue(i.is_multi_dim)
self.assertEqual(i.default, '30,')
self.assertEqual(i.description, 'end index in z (vertical) direction (staggered dimension)\nNote: this refers to full levels including surface and top\nvertical dimensions need to be the same for all nests\nNote: most variables are unstaggered (= staggered dim - 1)')
1 change: 1 addition & 0 deletions wrfconf/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
__version__ = 0.1
37 changes: 37 additions & 0 deletions wrfconf/cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import argparse

from wrfconf.conf.parse_namelist import process_namelist
from wrfconf.process import create_namelists

def gen_params_parser(subparsers):
gen = subparsers.add_parser('gen_params', help='Generate a configuration file containing the valid WRF parameters')
gen.add_argument('input', help='input README.namelist filename')


def create_parser(subparsers):
create = subparsers.add_parser('create', help='Create new configuration files for a WRF run')
create.add_argument('input', help='YML configuration file for the run')
create.add_argument('-n', '--namelist', default='.', help='Folder to store the WRF namelist file')
create.add_argument('-w', '--wps', default='.', help='Folder to store the WPS file')


def run_command(args):
if args.cmd == 'gen_params':
print(process_namelist(args.input))
elif args.cmd == 'create':
create_namelists(args.input, args.namelist, args.wps)


def main():
parser = argparse.ArgumentParser(prog='wrfconf',
description="Generate WRF configuration from structured YAML files")
subparsers = parser.add_subparsers(dest='cmd')

create_parser(subparsers)
gen_params_parser(subparsers)

args = parser.parse_args()
run_command(args)


main()
Loading

0 comments on commit 2c7b525

Please sign in to comment.