diff --git a/README.md b/README.md index 9425d50..aafac32 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,25 @@ -# ERFtools -A collection of scripts for facilitating the usage of ERF. +# ERF Tools +A collection of Python-based modules and scripts for facilitating the usage of +the Energy Research and Forecasting (ERF) model. + +## Installation + +Clone and create a conda (or mamba) environment: +```shell +git clone https://github.com/erf-model/erftools.git +cd erftools +conda create -n erftools python=3.9 +conda activate erftools +``` + +Then, install with: +```shell +pip install -e . # editable install +``` +or install with all optional dependencies: +```shell +pip install -e .[all] +``` ## Examples @@ -7,15 +27,24 @@ A collection of scripts for facilitating the usage of ERF. ```python from erftools.preprocessing import WRFInputDeck wrf = WRFInputDeck('namelist.input') +wrf.write_inputfile('inputs') + +# optional: extract data from wrfinput wrf.process_initial_conditions('wrfinput_d01', landuse_table_path='/Users/equon/WRF/run/LANDUSE.TBL', write_hgt='terrain_height.txt', write_z0='roughness_height.txt') -wrf.write_inputfile('inputs') +``` + +The namelist conversion may also be accomplished from the command line: +```bash +wrf_namelist_to_erf namelist.input inputs ``` ### Postprocessing data logs -Data logs are output with the `erf.data_log` param and can include time histories of surface conditions and planar averaged profiles (e.g., for idealized LES simulations) +Data logs are output with the `erf.data_log` param and can include time +histories of surface conditions and planar averaged profiles (e.g., for +idealized LES simulations) ```python from erftools.postprocessing import DataLog log = DataLog(f'{simdir}/surf_hist.dat', @@ -31,6 +60,8 @@ print(log.ds) # data are stored in an xarray dataset Some notes and recommendations: -* An aspirational goal is to contribute code that can be used as in the examples above, with clear, intuitive naming and following PEP-8 style as a set of guidelines rather than gospel. -* To avoid duplication, model constants are defined in `erf.constants`, which should replicate `ERF/Source/ERF_Constants.H`. -* In the same vein, equation of state evaluations are defined in `erf.EOS`, which should replicate `ERF/Source/Utils/ERF_EOS.H`. +* An aspirational goal is to contribute code that can be used as in the examples above, with clear, intuitive naming. +* To avoid duplication, model constants are defined in `erftools.constants`, which should replicate `ERF/Source/ERF_Constants.H`. +* In the same vein, equation of state evaluations are defined in `erftools.utils.EOS`, which should replicate `ERF/Source/Utils/ERF_EOS.H`. +* Other utilities for calculating/deriving/diagnosing quantities of interest are also in `erftools.utils.*` +* Please follow PEP-8 style--as a set of guidelines rather than gospel--to facilitate code usage and maintenance by the community. diff --git a/erftools/data/ozone_CAM.nc b/erftools/data/ozone_CAM.nc new file mode 100644 index 0000000..7810df1 Binary files /dev/null and b/erftools/data/ozone_CAM.nc differ diff --git a/erftools/parms.py b/erftools/erfparms.py similarity index 89% rename from erftools/parms.py rename to erftools/erfparms.py index fc9fc1e..eeb8a82 100644 --- a/erftools/parms.py +++ b/erftools/erfparms.py @@ -16,12 +16,23 @@ def check_unknown_params(data_dict, dataclass_type): provided_params = set(data_dict.keys()) unknown_params = list(provided_params - known_params) + # ignore MOST settings + unknown_params = [param for param in unknown_params + if not param.startswith('most.')] + + # ignore refinement indicators if 'refinement_indicators' in data_dict: - boxes = data_dict['refinement_indicators'].split() - for box in boxes: + refine_names = data_dict['refinement_indicators'] + if isinstance(refine_names, str): + refine_names = [refine_names] + for box in refine_names: unknown_params = [param for param in unknown_params if not param.startswith(f'{box}.')] + # ignore nc_init_file_* + unknown_params = [param for param in unknown_params + if not param.startswith('nc_init_file_')] + if unknown_params: warnings.warn(f'Non-standard {dataclass_type.__name__} ignored: {unknown_params}') @@ -33,7 +44,6 @@ class AMRParms: max_level: int = 0 ref_ratio: Union[int,List[int]] = 2 ref_ratio_vect: List[int] = field(default_factory=list) - regrid_int: int = -1 v: int = 0 # verbosity @@ -125,6 +135,7 @@ class ERFParms: # Refinement refinement_indicators: Union[str,List[str]] = field(default_factory=list) + regrid_int: int = -1 # Grid Stretching grid_stretching_ratio: float = 1. @@ -240,9 +251,6 @@ class ERFParms: rayleigh_dampcoef: float = 0.2 rayleigh_zdamp: float = 500. - # BCs - use_explicit_most: bool = False - # Initialization init_type: str = 'None' init_sounding_ideal: bool = False @@ -263,6 +271,27 @@ class ERFParms: # Radiation radiation_model: str = 'None' + rad_freq_in_steps: int = 1 + rad_write_fluxes: bool = False + #nswbands: int = 14 + #nlwbands: int = 16 + #nswgpts: int = 224 + #nlwgpts: int = 256 + co2vmr: float = 0.00036 # from DevTests/Radiation + o3vmr: Union[float,List[float]] = 1.887e-7 # default + n2ovmr: float = 3.2e-7 # from DevTests/Radiation + covmr: float = 1.5e-7 # from DevTests/Radiation + ch4vmr: float = 1.7e-6 # from DevTests/Radiation + o2vmr: float = 0.209 # default + n2vmr: float = 0.7906 # default + rrtmgp_file_path: str = './' + #rrtmgp_coeffs_sw: str = 'rrtmgp-data-sw-g224-2018-12-04.nc' + #rrtmgp_coeffs_lw: str = 'rrtmgp-data-lw-g256-2018-12-04.nc' + #rrtmgp_cloud_optics_sw: str = 'rrtmgp-cloud-optics-coeffs-sw.nc' + #rrtmgp_cloud_optics_lw: str = 'rrtmgp-cloud-optics-coeffs-lw.nc' + + # Land Surface + land_surface_model: str = 'None' def __post_init__(self): if self.anelastic: @@ -321,7 +350,7 @@ def __post_init__(self): les_types = self.les_type if isinstance(self.les_type,list) else [self.les_type] for turbmodel in les_types: - assert turbmodel in ['None','Smagorinsky','Deardorff'], \ + assert turbmodel in ['None','Smagorinsky','Smagorinsky2D','Deardorff'], \ f'Unexpected erf.les_type={turbmodel}' if any([turbmodel == 'Smagorinsky' for turbmodel in les_types]): smag_Cs = self.Cs if isinstance(self.Cs,list) else len(les_types)*[self.Cs] @@ -329,7 +358,7 @@ def __post_init__(self): pbl_types = self.pbl_type if isinstance(self.pbl_type,list) else [self.pbl_type] for pblscheme in pbl_types: - assert pblscheme in ['None','MYNN25','YSU'], \ + assert pblscheme in ['None','MYJ','MYNN25','MRF','YSU'], \ f'Unexpected erf.pbl_type={pblscheme}' assert self.abl_driver_type in \ diff --git a/erftools/inputs.py b/erftools/inputs.py index 8162af2..0fcc895 100644 --- a/erftools/inputs.py +++ b/erftools/inputs.py @@ -1,10 +1,14 @@ import sys import warnings +from datetime import datetime +from dateutil import parser + +import click import contextlib import numpy as np # parameters parsed by AMReX's ParmParse -from .parms import AMRParms, GeometryParms, ERFParms, check_unknown_params +from .erfparms import AMRParms, GeometryParms, ERFParms, check_unknown_params def parmparse(prefix, ppdata): @@ -37,6 +41,14 @@ def list_to_str(mylist,dtype=None): def strs_to_str(mylist): return ' '.join([s.strip('"').strip("'") for s in mylist]) +def to_datetime(dt): + # ensure that we have a datetime object, parse if needed + if isinstance(dt, datetime): + return dt + elif isinstance(dt, list): + assert len(dt) == 2, 'expected date string + time string' + dt = ' '.join(dt) + return parser.parse(dt) class ERFInputs(object): """Input data container with validation and output""" @@ -50,8 +62,13 @@ def __init__(self,inpfile=None,**ppdata): self.max_step = int(ppdata.get('max_step',-1)) self.start_time = float(ppdata.get('start_time',0.)) self.stop_time = float(ppdata.get('stop_time',1e34)) - self.start_date = ppdata.get('start_date',None) - self.stop_date = ppdata.get('stop_date',None) + + self.start_datetime = ppdata.get('start_datetime',None) + if self.start_datetime is not None: + self.start_datetime = to_datetime(self.start_datetime) + self.stop_datetime = ppdata.get('stop_datetime',None) + if self.stop_datetime is not None: + self.stop_datetime = to_datetime(self.stop_datetime) # read amr, geometry, and erf inputs amrparms = parmparse('amr',ppdata) @@ -128,7 +145,7 @@ def read_bcs(self,ppdata): assert 'zhi.type' in ppdata.keys() self.zlo = parmparse('zlo',ppdata) self.zhi = parmparse('zhi',ppdata) - if self.zlo['type'] == 'MOST': + if self.zlo['type'] == 'surface_layer': self.most = parmparse('erf.most',ppdata) def read_refinement(self,ppdata): @@ -164,7 +181,9 @@ def read_refinement(self,ppdata): self.refine[box][test] = thresh def validate(self): - # additional validation that depends on different parmparse types + """Additional validation (outside of what is performed in + erfparms.*) that depends on different parmparse tables + """ if self.erf.terrain_type.lower() != 'none': if self.erf.terrain_z_levels: nz = self.amr.n_cell[2] @@ -178,19 +197,22 @@ def validate(self): f' will be inactive with' f' amr.max_level={self.amr.max_level}') if 'field_name' in refineparams and \ - self.amr.regrid_int <= 0: + self.erf.regrid_int <= 0: warnings.warn(f'{box} dynamic refinement will be inactive' - f' with amr.regrid_int={self.amr.regrid_int}') + f' with erf.regrid_int={self.erf.regrid_int}') + + if isinstance(self.erf.o3vmr, list): + assert len(self.erf.o3vmr) == self.amr.n_cell[2] def write(self,fpath=None): with open_file_or_stdout(fpath) as f: f.write('# ------------------------------- INPUTS TO ERF -------------------------------\n') f.write('# written by erftools.inputs (https://github.com/erf-model/erftools)\n') - if self.start_date and self.stop_date: + if self.start_datetime and self.stop_datetime: f.write(f""" max_step = {self.max_step} -start_datetime = {self.start_date} # epoch time: {self.start_time} s -stop_datetime = {self.stop_date} # epoch time: {self.stop_time} s +start_datetime = {self.start_datetime} # epoch time: {self.start_time} s +stop_datetime = {self.stop_datetime} # epoch time: {self.stop_time} s """) else: f.write(f""" @@ -238,14 +260,15 @@ def write(self,fpath=None): if hasattr(self,'zlo'): f.write('\n') write_bc(f,'zlo',self.zlo) - if self.zlo['type'] == 'MOST': + if self.zlo['type'] == 'surface_layer': for key,val in self.most.items(): f.write(f'erf.most.{key} = {val}\n') write_bc(f,'zhi',self.zhi) ######################################## f.write('\n# TIME STEP CONTROL\n') - f.write(f'erf.substepping_type = {self.erf.substepping_type}\n') + if self.erf.substepping_type != 'implicit': + f.write(f'erf.substepping_type = {self.erf.substepping_type}\n') if self.erf.fixed_dt > 0: f.write(f'erf.fixed_dt = {self.erf.fixed_dt}\n') else: @@ -270,7 +293,7 @@ def write(self,fpath=None): ######################################## f.write('\n# REFINEMENT / REGRIDDING\n') f.write(f'amr.max_level = {self.amr.max_level}\n') - f.write(f'amr.regrid_int = {self.amr.regrid_int}\n') + f.write(f'erf.regrid_int = {self.erf.regrid_int}\n') if len(self.erf.refinement_indicators) > 0: if len(self.amr.ref_ratio_vect) > 0: f.write('amr.ref_ratio_vect = ' @@ -337,14 +360,15 @@ def write(self,fpath=None): f.write('\n# PLOTFILES\n') if self.erf.plotfile_type != 'amrex': f.write(f'erf.plotfile_type = {self.erf.plotfile_type}\n') - if (self.erf.plot_int_1 > 0) or (self.erf.plot_per_1 > 0): - f.write(f'erf.plot_file_1 = {self.erf.plot_file_1}\n') - if self.erf.plot_per_1 > 0: - f.write(f'erf.plot_per_1 = {self.erf.plot_per_1}\n') - else: - f.write(f'erf.plot_int_1 = {self.erf.plot_int_1}\n') - f.write('erf.plot_vars_1 = ' - f"{strs_to_str(self.erf.plot_vars_1)}\n") + + f.write(f'erf.plot_file_1 = {self.erf.plot_file_1}\n') + if self.erf.plot_per_1 > 0: + f.write(f'erf.plot_per_1 = {self.erf.plot_per_1}\n') + else: + f.write(f'erf.plot_int_1 = {self.erf.plot_int_1}\n') + f.write('erf.plot_vars_1 = ' + f"{strs_to_str(self.erf.plot_vars_1)}\n") + if (self.erf.plot_int_2 > 0) or (self.erf.plot_per_2 > 0): f.write(f'erf.plot_file_2 = {self.erf.plot_file_2}\n') if self.erf.plot_per_2 > 0: @@ -404,13 +428,14 @@ def write(self,fpath=None): lestypes = self.erf.les_type \ if isinstance(self.erf.les_type,list) \ else [self.erf.les_type] - have_smag = ('Smagorinsky' in lestypes) + have_smag = ('Smagorinsky' in lestypes) or ('Smagorinsky2D' in lestypes) have_dear = ('Deardorff' in lestypes) if have_smag or have_dear: f.write(f'\nerf.les_type = {strs_to_str(lestypes)}\n') if have_smag: Cs_list = self.erf.Cs if isinstance(self.erf.Cs,list) else [self.erf.Cs] - f.write(f'erf.Cs = {list_to_str(Cs_list)}\n') + comment = ' # Cs=0.25 is WRF default' if (0.25 in Cs_list) else '' + f.write(f'erf.Cs = {list_to_str(Cs_list)}{comment}\n') if have_dear: Ck_list = self.erf.Ck if isinstance(self.erf.Ck,list) else [self.erf.Ck] f.write(f'erf.Ck = {list_to_str(Ck_list)}\n') @@ -445,7 +470,28 @@ def write(self,fpath=None): ######################################## if self.erf.radiation_model != 'None': f.write(f"""\n# RADIATION -erf.radiation_model = {self.erf.radiation_model} +erf.radiation_model = {self.erf.radiation_model} +erf.rad_freq_in_steps = {self.erf.rad_freq_in_steps} +erf.rad_write_fluxes = {bool_to_str(self.erf.rad_write_fluxes)} +erf.co2vmr = {self.erf.co2vmr} +""") + if isinstance(self.erf.o3vmr, (list,np.ndarray)): + f.write(f'erf.o3vmr = {list_to_str(self.erf.o3vmr)}') + else: + f.write(f'erf.o3vmr = {self.erf.o3vmr}') + f.write(f""" +erf.n2ovmr = {self.erf.n2ovmr} +erf.covmr = {self.erf.covmr} +erf.ch4vmr = {self.erf.ch4vmr} +erf.o2vmr = {self.erf.o2vmr} +erf.n2vmr = {self.erf.n2vmr} +erf.rrtmgp_file_path = {self.erf.rrtmgp_file_path} +""") + + ######################################## + if self.erf.land_surface_model != 'None': + f.write(f"""\n# LAND SURFACE +erf.land_surface_model = {self.erf.land_surface_model} """) ######################################## @@ -516,12 +562,15 @@ def write(self,fpath=None): erf.init_sounding_ideal = {bool_to_str(self.erf.init_sounding_ideal)} """) elif self.erf.init_type.lower() == 'wrfinput': - f.write(f""" -erf.init_type = wrfinput -erf.use_real_bcs = {bool_to_str(self.erf.use_real_bcs)} -erf.nc_init_file_0 = {self.erf.nc_init_file_0}""") + f.write('\nerf.init_type = wrfinput\n') + nc_init_files = [ + param for param in dir(self.erf) + if param.startswith('nc_init_file_')] + for initfile in nc_init_files: + f.write(f'erf.{initfile} = {getattr(self.erf,initfile)}\n') if self.erf.use_real_bcs: f.write(f""" +erf.use_real_bcs = {bool_to_str(self.erf.use_real_bcs)} erf.nc_bdy_file = {self.erf.nc_bdy_file} erf.real_width = {self.erf.real_width} erf.real_set_width = {self.erf.real_set_width} @@ -557,3 +606,10 @@ def write_bc(f, bcname, bcdict): else: assert isinstance(val, list) f.write(f"{bcname}.{key} = {list_to_str(val,float)}\n") + + +@click.command() +@click.argument('input_file', type=click.Path(exists=True, readable=True)) +def check_erf_input(input_file): + """Validate ERF input file""" + ERFInputs(input_file) diff --git a/erftools/preprocessing/__init__.py b/erftools/preprocessing/__init__.py index 2e7de1c..14f882b 100644 --- a/erftools/preprocessing/__init__.py +++ b/erftools/preprocessing/__init__.py @@ -1,21 +1,26 @@ -from .wrf_inputs import WRFInputDeck +from ..wrf.inputdeck import WRFInputDeck from .grids import LambertConformalGrid -# ERA5 related funrcions -from .era5.IO import calculate_utm_zone -from .era5.IO import write_binary_simple_ERF -from .era5.IO import write_binary_vtk_structured_grid -from .era5.IO import write_binary_vtk_cartesian_file -from .era5.IO import find_latlon_indices -from .era5.IO import find_erf_domain_extents -from .era5.IO import write_binary_vtk_cartesian -from .era5.Plot_1D import plot_1d -from .era5.ReadERA5DataAndWriteERF_IC import ReadERA5_3DData -from .era5.ReadERA5DataAndWriteERF_SurfBC import Download_ERA5_SurfaceData -from .era5.ReadERA5DataAndWriteERF_SurfBC import Download_ERA5_ForecastSurfaceData -from .era5.ReadERA5DataAndWriteERF_SurfBC import ReadERA5_SurfaceData -from .era5.Download_ERA5Data import Download_ERA5_Data -from .era5.Download_ERA5Data import Download_ERA5_ForecastData +try: + import cdsapi +except ModuleNotFoundError: + print("Note: Need to install package 'cdsapi' to work with reanalysis data") +else: + # ERA5 related funrcions + from .era5.IO import calculate_utm_zone + from .era5.IO import write_binary_simple_ERF + from .era5.IO import write_binary_vtk_structured_grid + from .era5.IO import write_binary_vtk_cartesian_file + from .era5.IO import find_latlon_indices + from .era5.IO import find_erf_domain_extents + from .era5.IO import write_binary_vtk_cartesian + from .era5.Plot_1D import plot_1d + from .era5.ReadERA5DataAndWriteERF_IC import ReadERA5_3DData + from .era5.ReadERA5DataAndWriteERF_SurfBC import Download_ERA5_SurfaceData + from .era5.ReadERA5DataAndWriteERF_SurfBC import Download_ERA5_ForecastSurfaceData + from .era5.ReadERA5DataAndWriteERF_SurfBC import ReadERA5_SurfaceData + from .era5.Download_ERA5Data import Download_ERA5_Data + from .era5.Download_ERA5Data import Download_ERA5_ForecastData # GFS related funrcions from .gfs.Download_GFSData import Download_GFS_Data diff --git a/erftools/preprocessing/hrrr.py b/erftools/preprocessing/hrrr.py index 6aee911..10e2116 100644 --- a/erftools/preprocessing/hrrr.py +++ b/erftools/preprocessing/hrrr.py @@ -549,8 +549,8 @@ def to_wrfbdy(self,bdy_width,dtype=float): ds = xr.Dataset() # interpolate staggered velocity fields - Ugrid = self.interpxy('U', self.xg_u[*idxs], self.yg_u[*idxs], dtype=dtype) - Vgrid = self.interpxy('V', self.xg_v[*idxs], self.yg_v[*idxs], dtype=dtype) + Ugrid = self.interpxy('U', self.xg_u[idxs], self.yg_u[idxs], dtype=dtype) + Vgrid = self.interpxy('V', self.xg_v[idxs], self.yg_v[idxs], dtype=dtype) ds['U'] = Ugrid.rename(west_east='west_east_stag') ds['V'] = Vgrid.rename(south_north='south_north_stag') @@ -567,12 +567,12 @@ def to_wrfbdy(self,bdy_width,dtype=float): 'QRAIN', ] for varn in unstag_interp_vars: - ds[varn] = self.interpxy(varn, self.xg[*idxs], self.yg[*idxs], dtype=dtype) + ds[varn] = self.interpxy(varn, self.xg[idxs], self.yg[idxs], dtype=dtype) # setup map scale factors sn_ew_idxs = idxs[::-1] - msf_u = self.grid.calc_msf(lat_u[*sn_ew_idxs]) - msf_v = self.grid.calc_msf(lat_v[*sn_ew_idxs]) + msf_u = self.grid.calc_msf(lat_u[sn_ew_idxs]) + msf_v = self.grid.calc_msf(lat_v[sn_ew_idxs]) ds['MAPFAC_U'] = (('south_north', 'west_east_stag'), msf_u.astype(dtype)) ds['MAPFAC_V'] = (('south_north_stag', 'west_east'), msf_v.astype(dtype)) diff --git a/erftools/utils.py b/erftools/utils.py index 655edcd..c69ed54 100644 --- a/erftools/utils.py +++ b/erftools/utils.py @@ -1,7 +1,10 @@ import numpy as np import xarray as xr +import ussa1976 from .constants import CONST_GRAV +from .inputs import ERFInputs +from .input_sounding import InputSounding def get_stag_dims(ds_cc): stag_dims = {dim if dim != 'bottom_top' else 'bottom_top_stag': size @@ -40,3 +43,43 @@ def get_w_from_omega(omega_cc, rho_cc, stag_dims=None): da.loc[dict(bottom_top_stag=-1)] = w_top return da + + +def get_zcc(inp) -> np.array: + """Automatically get modeled heights at cell centers, which is exact + for const dz or stretched grids and approximate for general, + variable dz grids over terrain. + + `inp` may be an ERF input file path or an instance of ERFInputs. + """ + if not isinstance(inp, ERFInputs): + inp = ERFInputs(inp) + if len(inp.erf.terrain_z_levels) > 0: + zstag = np.array(inp.erf.terrain_z_levels) + zcc = 0.5 * (zstag[1:] + zstag[:-1]) + elif inp.erf.grid_stretching_ratio > 1: + s = inp.erf.grid_stretching_ratio + dz0 = inp.erf.initial_dz + nz = inp.amr.n_cell[2] + zstag = dz0 * (s**np.arange(nz+1) - 1) / (s - 1) # partial sum + zcc = 0.5 * (zstag[1:] + zstag[:-1]) + else: + nz = inp.amr.n_cell[2] + const_dz = (inp.geometry.prob_hi[2] - inp.geometry.prob_lo[2]) / nz + zcc = inp.geometry.prob_lo[2] + np.arange(0.5, nz) * const_dz + return zcc + +def est_p(z, soundingfile=None) -> np.array: + """Estimate air pressure [Pa] at a set of heights, using either the + US Standard Atmosphere (1976) or a WRF-style input_sounding. + """ + z = np.array(z) + if soundingfile is not None: + sound = InputSounding(soundingfile) + sound.interp_levels(z) + sound.integrate_column() + p = sound.pm + else: + ds = ussa1976.compute(z,'p') + p = ds['p'].values + return p diff --git a/erftools/wrf/__init__.py b/erftools/wrf/__init__.py index c545d20..27e23c0 100644 --- a/erftools/wrf/__init__.py +++ b/erftools/wrf/__init__.py @@ -1,3 +1,4 @@ from .real import (get_zlevels_auto, get_eta_levels) +from .namelist.tslist import TSList diff --git a/erftools/preprocessing/wrf_inputs.py b/erftools/wrf/inputdeck.py similarity index 69% rename from erftools/preprocessing/wrf_inputs.py rename to erftools/wrf/inputdeck.py index 783a497..ac60739 100644 --- a/erftools/preprocessing/wrf_inputs.py +++ b/erftools/wrf/inputdeck.py @@ -1,20 +1,28 @@ import logging import os + import numpy as np import pandas as pd import xarray as xr import f90nml import calendar from scipy.interpolate import RegularGridInterpolator +import click + +from .namelist.input import (TimeControl, + Domains, + Physics, + Dynamics, + BoundaryControl) +from .namelist.tslist import TSList +from .landuse import LandUseTable +from .real import RealInit, get_zlevels_auto +from .rad import interp_ozone -from ..wrf.namelist import (TimeControl, Domains, Physics, Dynamics, - BoundaryControl) -from ..wrf.tslist import TSList -from ..wrf.landuse import LandUseTable -from ..wrf.real import RealInit, get_zlevels_auto from ..constants import CONST_GRAV, p_0 from ..inputs import ERFInputs + class WRFInputDeck(object): """Class to parse inputs from WRF and convert to inputs for ERF WRF inputs include: @@ -23,12 +31,16 @@ class WRFInputDeck(object): This will instantiate WRFNamelist objects from a given namelist, with WRF defaults included. From the WRFNamelists, a WRFInputDeck.input_dict will be - populated with ERF input parameters. When WRFInputDec.write() is called, an + populated with ERF input parameters. When WRFInputDeck.write() is called, an ERFInputs object is instantiated--inside ERFInputs is where error checking occurs. ERFInputs.write() is used to finally output an ERF input file. """ - def __init__(self,nmlpath,tslist=None,verbosity=logging.DEBUG): + default_plot_vars = ['density','x_velocity','y_velocity','z_velocity', + 'pressure','theta','KE', + 'Kmh','Kmv','Khh','Khv','qv','qc'] + + def __init__(self,nmlpath,wrfinput=None,tslist=None,verbosity=logging.DEBUG): # setup logger self.log = logging.getLogger(__name__) if not self.log.hasHandlers(): @@ -51,6 +63,9 @@ def __init__(self,nmlpath,tslist=None,verbosity=logging.DEBUG): self.set_defaults() self.generate_inputs() + self.wrfinput = wrfinput + self.get_map_info() + if tslist is not None: self.tslist = TSList(tslist) else: @@ -74,10 +89,9 @@ def set_defaults(self): 'yhi.type': 'Outflow', 'zhi.type': 'SlipWall', 'erf.terrain_type': 'StaticFittedMesh', - 'erf.terrain_smoothing': 1, + 'erf.terrain_smoothing': 0, # only valid option with multilievel 'erf.init_type': 'wrfinput', 'erf.use_real_bcs': True, - 'erf.nc_init_file_0': 'wrfinput_d01', 'erf.nc_bdy_file': 'wrfbdy_d01', 'erf.dycore_horiz_adv_type': 'Upwind_5th', 'erf.dycore_vert_adv_type': 'Upwind_3rd', @@ -89,9 +103,8 @@ def set_defaults(self): 'erf.v': 1, # verbosity in ERF.cpp 'erf.sum_interval': 1, # timesteps between computing mass 'erf.plot_file_1': 'plt', - 'erf.plot_vars_1': ['density','x_velocity','y_velocity','z_velocity', - 'pressure','theta','KE', - 'Kmh','Kmv','Khh','Khv','qv','qc'], + 'erf.plot_vars_1': self.default_plot_vars, + 'erf.rad_freq_in_steps': -1, } def generate_inputs(self): @@ -111,9 +124,9 @@ def generate_inputs(self): startdate = self.time_control.start_datetimes[0] enddate = self.time_control.end_datetimes[0] tsim = (enddate - startdate).total_seconds() - inp['start_date'] = startdate - inp['stop_date'] = enddate - inp['start_time'] = calendar.timegm(startdate.timetuple()) + inp['start_datetime'] = startdate + inp['stop_datetime'] = enddate + inp['start_time'] = calendar.timegm(startdate.timetuple()) # epoch time inp['stop_time'] = calendar.timegm(enddate.timetuple()) self.log.info(f'Total simulation time: {tsim}') self.log.info(f"Start from {startdate.strftime('%Y-%m-%d %H:%M:%S')}" @@ -146,23 +159,17 @@ def generate_inputs(self): assert eta_levels[0] == 1 assert eta_levels[-1] == 0 - # get geopotential height from base state - real = RealInit(eta_stag=eta_levels, ptop=ptop) - #phb = real.phb.squeeze().values - # better match real.exe output... - alb = real.alb.squeeze().values - phb = np.zeros_like(eta_levels) - psurf = p_0 - mub = psurf - ptop - for k in range(len(eta_levels)-1): - phb[k+1] = phb[k] - (eta_levels[k+1]-eta_levels[k]) * mub * alb[k] - - z_levels = phb / CONST_GRAV + # get geopotential heights from base state + real = RealInit(eta_levels=eta_levels, ptop=ptop) + z_levels = real.zlevels.squeeze().values self.base_heights = z_levels inp['erf.terrain_z_levels'] = z_levels most_zref = 0.5*(z_levels[0] + z_levels[1]) inp['erf.most.zref'] = most_zref # need to specify for terrain + self.log.info('Reference height for MOST set to the average of the ' + 'first two base-state geopotential heights: ' + f'{z_levels[0]:g} {z_levels[1]:g}') ztop = z_levels[-1] self.log.info('Estimated domain ztop from domains.p_top_requested' @@ -186,12 +193,18 @@ def generate_inputs(self): dt = np.array(self.domains.parent_time_step_ratio) * self.domains.time_step inp['erf.fixed_dt'] = dt[0] - # refinements + # initial conditions max_dom = self.domains.max_dom + for i in range(max_dom): + inp[f'erf.nc_init_file_{i}'] = f'wrfinput_d{i+1:02d}' + + # refinements / nests inp['amr.max_level'] = max_dom - 1 # zero-based indexing if max_dom > 1: self.log.info('Assuming parent_time_step_ratio == parent_grid_ratio') + self.refinement_boxes = [] + refine_names = [f'nest{idom:d}' for idom in range(1,max_dom)] inp['erf.refinement_indicators'] = refine_names @@ -204,33 +217,58 @@ def generate_inputs(self): grid_ratio = self.domains.parent_grid_ratio[idom] ref_ratio_vect += [grid_ratio, grid_ratio, 1] - parent_ds = np.array([ dx[idom-1], dy[idom-1]], dtype=float) - child_ds = np.array([ dx[idom ], dy[idom ]], dtype=float) - parent_ext = np.array([imax[idom-1], jmax[idom-1]]) * parent_ds - child_ext = np.array([imax[idom ], jmax[idom ]]) * child_ds + parent_dx = np.array([ dx[idom-1] , dy[idom-1] ], dtype=float) + child_dx = np.array([ dx[idom ] , dy[idom ] ], dtype=float) + parent_ext = np.array([imax[idom-1]-1, jmax[idom-1]-1]) * parent_dx + child_ext = np.array([imax[idom ]-1, jmax[idom ]-1]) * child_dx lo_idx = np.array([ self.domains.i_parent_start[idom] - 1, self.domains.j_parent_start[idom] - 1]) - in_box_lo = lo_idx * parent_ds + in_box_lo = lo_idx * parent_dx in_box_hi = in_box_lo + child_ext assert (in_box_hi[0] <= parent_ext[0]) assert (in_box_hi[1] <= parent_ext[1]) + inp[f'erf.nest{idom:d}.max_level'] = idom inp[f'erf.nest{idom:d}.in_box_lo'] = in_box_lo inp[f'erf.nest{idom:d}.in_box_hi'] = in_box_hi + self.refinement_boxes.append((in_box_lo, in_box_hi)) inp['amr.ref_ratio_vect'] = ref_ratio_vect restart_interval = self.time_control.restart_interval * 60.0 # [s] - inp['erf.check_int'] = int(restart_interval / dt[0]) + if restart_interval <= 0: + inp['erf.check_int'] = -1 + else: + inp['erf.check_int'] = int(restart_interval / dt[0]) wrfout_interval = self.time_control.history_interval[0] * 60.0 # [s] - inp['erf.plot_int_1'] = int(wrfout_interval / dt[0]) + if wrfout_interval <= 0: + inp['erf.plot_int_1'] = -1 + else: + inp['erf_plot_file_1'] = 'plt' + #inp['erf.plot_int_1'] = int(wrfout_interval / dt[0]) + inp['erf.plot_per_1'] = wrfout_interval + inp['erf.plot_vars_1'] = self.default_plot_vars + self.log.info('Setting default plotting vars for history output: ' + f'{self.default_plot_vars}') + + auxhist2_interval = self.time_control.auxhist2_interval[0] * 60.0 # [s] + if auxhist2_interval <= 0: + inp['erf.plot_int_2'] = -1 + else: + inp['erf.plot_file_2'] = 'plt_aux' + #inp['erf.plot_int_2'] = int(auxhist2_interval / dt[0]) + inp['erf.plot_per_2'] = auxhist2_interval + inp['erf.plot_vars_2'] = self.default_plot_vars + self.log.info('Setting default plotting vars for auxhist output: ' + f'{self.default_plot_vars} -- need to manually specify ' + 'erf.plot_vars_2 to replicate auxhist2 output') sfclayscheme = self.physics.sf_sfclay_physics[0] if sfclayscheme == 'None': inp['zlo.type'] = 'SlipWall' - elif sfclayscheme == 'MOST': - inp['zlo.type'] = 'MOST' + elif sfclayscheme == 'SurfaceLayer': + inp['zlo.type'] = 'surface_layer' else: self.log.warning(f'Surface layer scheme {sfclayscheme} not implemented in ERF') inp['zlo.type'] = sfclayscheme @@ -254,9 +292,9 @@ def generate_inputs(self): inp['erf.dryscal_horiz_adv_type'] = h_sca_adv_order inp['erf.dryscal_vert_adv_type'] = v_sca_adv_order if not all([adv_opt == 'WENO5' for adv_opt in self.dynamics.moist_adv_opt]): - self.log.warning('Need to manually specify moist erf.moistscal_*_adv_type' - f' for WRF moist_adv_opt = {self.dynamics.moist_adv_opt}' - ' -- defaulting to 5th-order WENO') + self.log.warning(f'WRF moist_adv_opt = {self.dynamics.moist_adv_opt}' + ' not available -- defaulting to 5th-order WENO for' + ' erf.moistscal_*_adv_type') inp['erf.pbl_type'] = self.physics.bl_pbl_physics for idom in range(max_dom): @@ -296,10 +334,7 @@ def generate_inputs(self): inp['erf.num_diff_coeff'] = num_diff_coeff if any([opt != 'constant' for opt in self.dynamics.km_opt]): - # in ERF, Smagorinsky == 2D Smagorinsky - les_types = [turb if 'Smagorinsky' not in turb else 'Smagorinsky' - for turb in self.dynamics.km_opt] - les_types = les_types[:max_dom] + les_types = self.dynamics.km_opt[:max_dom] inp['erf.les_type'] = les_types smag_Cs = self.dynamics.c_s dear_Ck = self.dynamics.c_k @@ -324,6 +359,30 @@ def generate_inputs(self): self.log.warning(f'Applying the {rad_model} radiation scheme on all levels') inp['erf.radiation_model'] = rad_model + inp['erf.rad_freq_in_steps'] = self.physics.radt[0] + if inp['erf.rad_freq_in_steps'] < 0: + # rule of thumb: rad freq is "1 min per km of dx" + dx_km = self.domains.dx[0] / 1000. + radt = dx_km * 60. # [s] + rad_freq = int(radt / dt[0]) + inp['erf.rad_freq_in_steps'] = rad_freq + self.log.info('Calculated radiation update frequency to be ' + f'every {rad_freq} steps, corresponding to an ' + f'interval of {rad_freq * dt[0] / 60:g} min on ' + 'domain d01') + + if any([opt != 'None' for opt in self.physics.surface_physics]): + lsm_model = self.physics.surface_physics[0] + if len(set(self.physics.surface_physics)) > 1: + self.log.warning(f'Applying the {lsm_model} surface scheme on all levels') + if lsm_model == 'NoahMP': + #self.log.warning(f'&noah_mp was not parsed, additional options' + # ' need to be manually specified') + self.log.warning('NoahMP verification is ongoing; ' + 'reverting to simple land model (SLM) for now') + lsm_model = 'SLM' + inp['erf.land_surface_model'] = lsm_model + if any([opt != 'None' for opt in self.physics.cu_physics]): self.log.warning('ERF currently does not have any cumulus parameterizations') @@ -338,15 +397,42 @@ def generate_inputs(self): self.log.warning(f'Damping option {self.dynamics.damp_opt} not supported') self.input_dict = inp - - def process_initial_conditions(self,init_input='wrfinput_d01', + + def get_map_info(self,init_input=None): + if init_input is None: + init_input = self.wrfinput + if init_input is None: + self.cen_lat = None + self.cen_lon = None + self.truelat1 = None + self.truelat2 = None + self.moad_cen_lat = None + self.stand_lon = None + self.map_proj = None + return + + inp = xr.open_dataset(init_input) + self.cen_lat = inp.attrs['CEN_LAT'] + self.cen_lon = inp.attrs['CEN_LON'] + self.truelat1 = inp.attrs['TRUELAT1'] # standard parallels + self.truelat2 = inp.attrs['TRUELAT2'] + self.moad_cen_lat = inp.attrs['MOAD_CEN_LAT'] # "mother of all domains" + self.stand_lon = inp.attrs['STAND_LON'] + self.map_proj = inp.attrs['MAP_PROJ_CHAR'] + + def process_initial_conditions(self,init_input=None, calc_geopotential_heights=False, landuse_table_path=None, write_hgt=None, write_z0=None, write_albedo=None): + if init_input is None: + init_input = self.wrfinput wrfinp = xr.open_dataset(init_input) + idx = init_input.index('_d') + idom = int(init_input[idx+2:idx+4]) - 1 + # Get Coriolis parameters period = 4*np.pi / wrfinp['F'] * np.sin(np.radians(wrfinp.coords['XLAT'])) # F: "Coriolis sine latitude term" mean_lat = np.mean(wrfinp.coords['XLAT'].values) @@ -371,14 +457,22 @@ def process_initial_conditions(self,init_input='wrfinput_d01', inp['erf.most.zref'] = most_zref # need to specify for terrain # Grid data needed if hgt or z0 are written - dx = self.domains.dx[0] - dy = self.domains.dy[0] + dx = self.domains.dx[idom] + assert dx == wrfinp.attrs['DX'] + dy = self.domains.dy[idom] + assert dy == wrfinp.attrs['DY'] nx = wrfinp.sizes['west_east'] ny = wrfinp.sizes['south_north'] - west_east = np.arange(0.5,nx) * dx - south_north = np.arange(0.5,ny) * dy - west_east_stag = np.arange(nx+1) * dx - south_north_stag = np.arange(ny+1) * dy + + x0, y0 = 0.0, 0.0 + if idom > 0: + refine_box_lo, _ = self.refinement_boxes[idom-1] + x0, y0 = refine_box_lo[:2] + + west_east = x0 + np.arange(0.5,nx) * dx + south_north = y0 + np.arange(0.5,ny) * dy + west_east_stag = x0 + np.arange(nx+1) * dx + south_north_stag = y0 + np.arange(ny+1) * dy xg,yg = np.meshgrid(west_east_stag, south_north_stag, indexing='ij') hgt = wrfinp['HGT'].isel(Time=0) # terrain height @@ -398,15 +492,15 @@ def process_initial_conditions(self,init_input='wrfinput_d01', xyz = np.stack((xg.ravel(order='F'), yg.ravel(order='F'), hgt_nodes.ravel(order='F')),axis=-1) - print('Writing out',write_hgt) - np.savetxt(write_hgt, xyz, fmt='%.8g') + + write_ascii_table(write_hgt, xyz, names=['x','y','hgt']) self.input_dict['erf.terrain_file_name'] = \ os.path.split(write_hgt)[1] # Process land use information if landuse_table_path is None: - print('Need to specify `landuse_table_path` from your WRF installation' - 'land-use indices to estimate z0') + print('Need to specify `landuse_table_path` from your WRF ' + ' installation to determine z0, alb from land-use indices') if write_z0: print('Surface roughness map was not written') if write_albedo: @@ -460,8 +554,8 @@ def alfun(idx): xyz0 = np.stack((xg.ravel(order='F'), yg.ravel(order='F'), z0_nodes.ravel(order='F')),axis=-1) - print('Writing out',write_z0) - np.savetxt(write_z0, xyz0, fmt='%.8g') + + write_ascii_table(write_z0, xyz0, names=['x','y','z0']) self.input_dict['erf.most.roughness_file_name'] = \ os.path.split(write_z0)[1] else: @@ -483,24 +577,71 @@ def alfun(idx): xyz0 = np.stack((xg.ravel(order='F'), yg.ravel(order='F'), al_nodes.ravel(order='F')),axis=-1) - print('Writing out',write_albedo) - np.savetxt(write_albedo, xyz0, fmt='%.8g') + + write_ascii_table(write_albedo, xyz0, names=['x','y','alb']) self.input_dict['erf.rad_albedo_file_name'] = \ os.path.split(write_albedo)[1] def to_erf(self): + inp = ERFInputs(**self.input_dict) + + if inp.erf.radiation_model != 'None': + if self.cen_lat: + inp.erf.o3vmr = interp_ozone(inp, self.cen_lat) + else: + self.log.warning('Using a radiation model with a constant for ' + 'the entire column; need to set `cen_lat`, ' + 'e.g. by providing a wrfinput file') + if self.tslist: if self.tslist.have_ij: nz = self.input_dict['amr.n_cell'][2] lo_ijk, hi_ijk = self.tslist.get_ijk_lists(nz) - self.input_dict['erf.sample_line_lo'] = lo_ijk - self.input_dict['erf.sample_line_hi'] = hi_ijk + inp.erf.sample_line_lo = lo_ijk + inp.erf.sample_line_hi = hi_ijk else: self.log.info('A tslist was provided but lat,lon were not ' 'converted to i,j') - return ERFInputs(**self.input_dict) + + return inp def write_inputfile(self,fpath): inp = self.to_erf() inp.write(fpath) print('Wrote',fpath) + + +def write_ascii_table(fpath, xyz, names=None): + print('Writing out',fpath) + ext = os.path.splitext(fpath)[1] + if ext == '.csv': + columns = None + if names is not None: + columns = names + df = pd.DataFrame(xyz, columns=columns) + df.to_csv(fpath, index=False) + else: + header = '' + if names is not None: + header = ' '.join(names) + np.savetxt(fpath, xyz, header=header, fmt='%.8g') + + +@click.command() +@click.argument('namelist_input', type=click.Path(exists=True, readable=True)) +@click.argument('erf_input', type=click.Path(writable=True), required=False, + default='inputs') +@click.option('--init', + type=click.Path(exists=True, readable=True), + help='Path to a wrfinput_d01 file to provide additional ' + 'information about the simulation setup (optional)', + required=False) +@click.option('--tslist', + type=click.Path(exists=True, readable=True), + help='Path to a tslist file to convert into line sampling ' + 'inputs for ERF (optional)', + required=False) +def wrf_namelist_to_erf(namelist_input, erf_input, init=None, tslist=None): + """Convert a WRF namelist.input into an ERF input file""" + wrf = WRFInputDeck(namelist_input, wrfinput=init, tslist=tslist) + wrf.write_inputfile(erf_input) diff --git a/erftools/wrf/namelist.py b/erftools/wrf/namelist/input.py similarity index 83% rename from erftools/wrf/namelist.py rename to erftools/wrf/namelist/input.py index 58aab2d..d38fa72 100644 --- a/erftools/wrf/namelist.py +++ b/erftools/wrf/namelist/input.py @@ -4,7 +4,7 @@ import warnings from datetime import datetime, timedelta -from .namelist_mappings import * +from .mappings import * class WRFNamelist(object): def __init__(self,nmldict): @@ -60,6 +60,8 @@ def __init__(self,nmldict): if history_interval_s is not None: self.history_interval = [interval / 60. for interval in history_interval_s] + self.auxhist2_interval = self.getarrayvar('auxhist2_interval',default=[0]) # [min] + self.parse_datetime_range() def __str__(self): @@ -71,14 +73,23 @@ def parse_datetime_range(self): start_month = self.getarrayvar('start_month') start_day = self.getarrayvar('start_day') start_hour = self.getarrayvar('start_hour') - start_minute = self.getarrayvar('start_minute') - start_second = self.getarrayvar('start_second') + start_minute = self.getarrayvar('start_minute', optional=True) + start_second = self.getarrayvar('start_second', optional=True) end_year = self.getarrayvar('end_year') end_month = self.getarrayvar('end_month') end_day = self.getarrayvar('end_day') end_hour = self.getarrayvar('end_hour') - end_minute = self.getarrayvar('end_minute') - end_second = self.getarrayvar('end_second') + end_minute = self.getarrayvar('end_minute', optional=True) + end_second = self.getarrayvar('end_second', optional=True) + if start_minute is None: + start_minute = len(start_year) * [0] + if start_second is None: + start_second = len(start_year) * [0] + if end_minute is None: + end_minute = len(start_year) * [0] + if end_second is None: + end_second = len(start_year) * [0] + self.start_datetimes = [] self.end_datetimes = [] for idom in range(len(start_year)): @@ -105,10 +116,10 @@ def parse_datetime_range(self): self.start_datetimes.append(start_date) self.end_datetimes.append(end_date) - run_days = self.getvar('run_days') - run_hours = self.getvar('run_hours') - run_minutes = self.getvar('run_minutes') - run_seconds = self.getvar('run_seconds') + run_days = self.getvar('run_days', default=0) + run_hours = self.getvar('run_hours', default=0) + run_minutes = self.getvar('run_minutes', default=0) + run_seconds = self.getvar('run_seconds', default=0) spec_run_time = run_days * 86400 \ + run_hours * 3600 \ + run_minutes * 60 \ @@ -118,6 +129,8 @@ def parse_datetime_range(self): if spec_run_time != simtime.total_seconds(): new_end_datetime = self.start_datetimes[0] \ + timedelta(seconds=spec_run_time) + # From WRF user guide: run_days/run_hours takes precedence + # over the end times print(f'Specified run time {spec_run_time} s' f' differs from {simtime.total_seconds()} s' \ f' (from {self.start_datetimes[0]}' @@ -145,7 +158,7 @@ def __str__(self): def parse_time_integration(self): self.time_step = self.getvar('time_step') # seconds dt_num = self.getvar('time_step_fract_num',optional=True) - if dt_num is not None: + if dt_num is not None and dt_num > 0: dt_den = self.getvar('time_step_fract_den') self.time_step = dt_num / dt_den self.parent_time_step_ratio = self.getarrayvar( @@ -177,8 +190,18 @@ def parse_grid(self): assert self.i_parent_start[0] == 1 assert self.j_parent_start[0] == 1 for dom in range(1,self.max_dom): - assert (self.dx[dom-1]/self.dx[dom] == self.parent_grid_ratio[dom]) - assert (self.dy[dom-1]/self.dy[dom] == self.parent_grid_ratio[dom]) + if len(self.dx) >= self.max_dom: + assert (self.dx[dom-1]/self.dx[dom] == self.parent_grid_ratio[dom]) + else: + print(f'Note: dx on d{dom+1:02d} not found,' + ' setting from parent_grid_ratio') + self.dx.append(self.dx[dom-1] / self.parent_grid_ratio[dom]) + if len(self.dy) >= self.max_dom: + assert (self.dy[dom-1]/self.dy[dom] == self.parent_grid_ratio[dom]) + else: + print(f'Note: dy on d{dom+1:02d} not found' + ' setting from parent_grid_ratio') + self.dy.append(self.dy[dom-1] / self.parent_grid_ratio[dom]) self.eta_levels = self.getarrayvar('eta_levels',optional=True) self.etac = self.getvar('etac',default=0.2) self.auto_levels_opt = self.getvar('auto_levels_opt',default=2) @@ -213,6 +236,13 @@ def parse_all(self): self.bl_pbl_physics = [pbl_mapping.get(idx,'UNKNOWN') for idx in pbl_idx_list] for i in range(len(self.bl_pbl_physics)): if self.bl_pbl_physics[i] == 'MYNN': + if pbl_mynn_closure > 2.5: + pbl_mynn_closure = 2.5 + warnings.warn(f'MYNN level {pbl_mynn_closure} selected, but' + ' it is currently not available in ERF' + ' -- reverting to MYNN level 2.5.' + ' Note: A port of MYNN-EDMF is also available' + ' but it has not been fully verified.') lvlstr = str(pbl_mynn_closure).replace('.','') self.bl_pbl_physics[i] += lvlstr self.sf_sfclay_physics = [sfclay_mapping.get(idx,'UNKNOWN') for idx in sfclay_idx_list] @@ -227,6 +257,13 @@ def parse_all(self): 'Different longwave/shortwave radiation schemes not handled' self.ra_physics = [ra_physics_mapping.get(idx,'UNKNOWN') for idx in ra_lw_idx_list] + self.radt = self.getarrayvar('radt', default=-1) + assert all([t==self.radt[0] for t in self.radt]), \ + 'Different radiation call intervals not handled' + + lsm_idx_list = self.getarrayvar('sf_surface_physics') + self.surface_physics = [surface_physics_mapping.get(idx,'UNKNOWN') for idx in lsm_idx_list] + cu_idx_list = self.getarrayvar('cu_physics') self.cu_physics = [cu_physics_mapping.get(idx,'UNKNOWN') for idx in cu_idx_list] diff --git a/erftools/wrf/namelist_mappings.py b/erftools/wrf/namelist/mappings.py similarity index 58% rename from erftools/wrf/namelist_mappings.py rename to erftools/wrf/namelist/mappings.py index f2f6d10..8e1c25a 100644 --- a/erftools/wrf/namelist_mappings.py +++ b/erftools/wrf/namelist/mappings.py @@ -1,3 +1,5 @@ +# for reference, see WRF/run/README.namelist + pbl_mapping = { 0: 'None', 1: 'YSU', # YSU scheme @@ -16,9 +18,9 @@ sfclay_mapping = { 0: 'None', - 1: 'MOST', # Revised MM5 Monin-Obukhov scheme (Jimenez, renamed in v3.6) - 2: 'MOST', # Monin-Obukhov (Janjic) scheme - 5: 'MOST', # MYNN surface layer + 1: 'SurfaceLayer', # Revised MM5 Monin-Obukhov scheme (Jimenez, renamed in v3.6) + 2: 'SurfaceLayer', # Monin-Obukhov (Janjic) scheme + 5: 'SurfaceLayer', # MYNN surface layer } valid_sfclay = { # for each PBL scheme, based on acceptable WRF inputs @@ -39,9 +41,15 @@ 0: 'None', 1: 'Kessler', 2: 'SAM', # SAM is comparable to Lin et al. scheme - 3: 'Kessler', # WRF Single-Moment, 3-class scheme + 3: 'SAM', # WRF Single-Moment, 3-class scheme with ice + 4: 'SAM', # WRF Single-Moment, 5-class scheme + 5: 'SAM', # Ferrier (new Eta), operational High-Resolution Window version 6: 'SAM', # WRF Single-Moment, 6-class scheme - 28: 'SAM', # aerosol-aware Thompson scheme + 8: 'Morrison', # Thompson scheme + 10: 'Morrison', # Morrison (double moment) scheme + 14: 'Morrison', # WRF Double-Moment 5-class scheme + 16: 'Morrison', # WRF Double-Moment 6-class scheme + 28: 'Morrison', # aerosol-aware Thompson scheme } ra_physics_mapping = { @@ -49,6 +57,13 @@ 4: 'RRTMGP', } +surface_physics_mapping = { + 0: 'None', + 1: 'SLM', # thermal diffusion scheme (soil temperature only, 5 layers) + 2: 'NoahMP', # Unified Noah land-surface model + 4: 'NoahMP', # Noah-MP land-surface model +} + cu_physics_mapping = { 0: 'None', } @@ -77,9 +92,9 @@ 1: 'constant', 2: 'Deardorff', # 1.5 order TKE closure (3D) 3: 'Smagorinsky', # Smagorinsky first-order closure (3D) - 4: '2D Smagorinsky', # horizontal Smagorinsky closure (diagnosed from just - # horizontal deformation); vertical diffusion from - # PBL scheme + 4: 'Smagorinsky2D', # horizontal Smagorinsky closure (diagnosed from just + # horizontal deformation); vertical diffusion from + # PBL scheme } damp_opt_mapping = { diff --git a/erftools/wrf/tslist.py b/erftools/wrf/namelist/tslist.py similarity index 100% rename from erftools/wrf/tslist.py rename to erftools/wrf/namelist/tslist.py diff --git a/erftools/wrf/rad.py b/erftools/wrf/rad.py new file mode 100644 index 0000000..be94ffa --- /dev/null +++ b/erftools/wrf/rad.py @@ -0,0 +1,205 @@ +from datetime import datetime +from importlib import resources + +import numpy as np +import xarray as xr +import click + +from erftools.utils import get_zcc, est_p +from erftools.inputs import ERFInputs + + +# wrap Jan/Dec for a 365 day year +my_date_oz = np.array( + [-15, + 16, 45, 75, 105, 136, 166, 197, 228, 258, 289, 319, 350, + 381] +) + +def monthly_interp_weights_from_date(dt): + """Get interpolation weights to be applied to monthly data centered + on specific days of the year (hardcoded). + """ + # get decimal day of year (1-based) + jan1 = datetime(dt.year, 1, 1) + decimal_day = (dt - jan1).total_seconds() / 86400. + 1.0 + + # find months to interpolate between + idx_r = np.where(my_date_oz > decimal_day)[0][0] + idx_l = idx_r - 1 + + # calculate interpolation weights + tdelta = my_date_oz[idx_r] - my_date_oz[idx_l] + fac_l = (my_date_oz[idx_r] - decimal_day) / tdelta + fac_r = (decimal_day - my_date_oz[idx_l]) / tdelta + + # fill full array of monthly weights + weights = np.zeros(12) + if idx_l == 0 or idx_r == 13: + weights[-1] = fac_l + weights[0] = fac_r + else: + weights[idx_l-1] = fac_l + weights[idx_r-1] = fac_r + + return xr.DataArray(weights, dims='month') + +def interp_from_monthly_to_date(xdata,dt): + """Interpolate from monthly data `xdata` (an xarray Dataset or + DataArray) to a specific datetime `dt` + + The data should have the dimension 'month' + """ + weightedvals = monthly_interp_weights_from_date(dt) * xdata + return weightedvals.sum('month') + +def interp_from_monthly_to_date_heights(xdata,dt,heights,**kwargs): + """Interpolate from monthly data `xdata` (an xarray Dataset or + DataArray) to a specific datetime `dt` and an array of model heights + + The data should have the dimensions 'month' and 'plev' and the + pressure levels are in hPa. + """ + # get pressure levels from a standard atmosphere + plev = est_p(heights,**kwargs) / 100 # hPa + + # interpolate to pressure levels + plev_data = interp_from_monthly_to_date(xdata, dt) + interp_data = plev_data.interp(plev=plev) + + # create new dimension coordinate + interp_data = interp_data.rename(plev='height') + interp_data = interp_data.assign_coords(height=heights, + plev=('height',plev)) + + # fill in near-surface values + interp_data = interp_data.bfill('height') + + return interp_data + + +def interp_ozone(inp, latitude, dataset='CAM', verbose=False): + """Interpolate from climatological O3 data to the starting datetime + and height levels from the ERF inputfile. + + `inp` may be an input file or an ERFInputs object + + Ozone datasets are stored in erftools/data/ozone_*.nc + """ + dataname = f'ozone_{dataset}.nc' + with resources.files('erftools.data').joinpath(dataname) as fpath: + ds = xr.load_dataset(fpath) + + date = inp.start_datetime + if date is None: + raise ValueError(f'start_date not found in {inputfile}') + if verbose: + print('Interpolating to',date) + + heights = get_zcc(inp) + if verbose: + print('Model heights:',heights) + + plevels = est_p(heights) + if verbose: + print('Standard pressure levels:',plevels) + + ds = ds.interp(lat=latitude) + interpdata = interp_from_monthly_to_date_heights(ds, date, heights) + if verbose: + print('O3 [ppbv]: ', interpdata['o3vmr'].values / 1e-9) + + return interpdata['o3vmr'].values + + +@click.command() +@click.argument('inputfile', type=click.Path(writable=True)) +@click.option('--latitude', type=click.FloatRange(-90,90), + required=True) +@click.option('--dataset', default='CAM', + help='Name of O3 dataset [default=CAM]') +def generate_ozone_profile(inputfile, latitude, dataset): + """Interpolate from climatological O3 data to the starting datetime + and height levels from the ERF inputfile. + + Ozone datasets are stored in erftools/data/ozone_*.nc + """ + inp = ERFInputs(inputfile) + o3vmr = interp_ozone(inp, latitude, dataset, verbose=True) + erfstr = str(o3vmr).lstrip('[').rstrip(']') + print('erf.o3vmr = ', erfstr) + +''' +For verifying interpolator behavior + +date_oz = [16, 45, 75, 105, 136, 166, 197, 228, 258, 289, 319, 350] +daysperyear = 365 + +def ozn_time_int(julday, julian, ozmixm=None): + """Interpolate ozone concentration profile + + Port of ozn_time_int subroutine from WRF + phys/module_radiation_driver.F + + Parameters + ---------- + julday: int + Day of year + julian: float + Day of year, 0.0 at 0Z on 1 Jan + ozmixm: np.array + Ozone concentration (nlon, nlev, nlat, nmonth) + """ + ozncyc = True + intjulian = julian + 1.0 + # Jan 1st 00Z is julian=1.0 here + ijul = int(intjulian) + intjulian = intjulian - ijul + ijul = ijul % 365 + if ijul==0: + ijul = 365 + intjulian = intjulian + ijul + + np1 = 0 + datefound = False + for m in range(12): + if (date_oz[m] > intjulian) and not datefound: + np1 = m + datefound = True + cdayozp = date_oz[np1] + + if np1 > 0: + cdayozm = date_oz[np1-1] + np = np1 + nm = np - 1 + else: + cdayozm = date_oz[11] + np = np1 # ==0, jan + nm = 11 # dec + + if ozncyc and np1 == 0: + # Dec-Jan interpolation + deltat = cdayozp + daysperyear - cdayozm + if intjulian > cdayozp: + print('interp in dec',cdayozm,cdayozp) + # We are in December + fact1 = (cdayozp + daysperyear - intjulian) / deltat + fact2 = (intjulian - cdayozm) / deltat + else: + print('interp in jan',cdayozm,cdayozp) + # We are in January + fact1 = (cdayozp - intjulian) / deltat + fact2 = (intjulian + daysperyear - cdayozm) / deltat + else: + print('interp in general',cdayozm,cdayozp) + deltat = cdayozp - cdayozm + fact1 = (cdayozp - intjulian) / deltat + fact2 = (intjulian - cdayozm) / deltat + + if ozmixm is not None: + # WRF source has indices nm+1, np+1, which should be to account for + # module_ra_cam_suopport:oznini filling ozmixm starting from m=2... + return ozmixm[:,:,:,nm]*fact1 + ozmixm[:,:,:,np]*fact2 + else: + return fact1, fact2 +''' diff --git a/notebooks/read_CAM_ozone_data.ipynb b/notebooks/read_CAM_ozone_data.ipynb new file mode 100644 index 0000000..738815c --- /dev/null +++ b/notebooks/read_CAM_ozone_data.ipynb @@ -0,0 +1,686 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "4545ba45-299a-4092-a611-f96d8836287b", + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import xarray as xr\n", + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "2037da30-bc62-4df3-9212-0fbffd828cac", + "metadata": {}, + "outputs": [], + "source": [ + "wrfsrc = '/Users/equon/WRF/run'" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "497259e0-89a3-430b-9454-06d37334b18c", + "metadata": {}, + "outputs": [], + "source": [ + "lat = np.loadtxt(f'{wrfsrc}/ozone_lat.formatted')\n", + "plev = np.loadtxt(f'{wrfsrc}/ozone_plev.formatted')\n", + "o3vmr = np.loadtxt(f'{wrfsrc}/ozone.formatted')\n", + "\n", + "nlat = len(lat)\n", + "nz = len(plev)\n", + "o3vmr = o3vmr.reshape((nz, nlat, 12), order='F')" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "d84be422-bb42-4bec-ab6c-b5de2f6bbae6", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "
<xarray.Dataset>\n",
+       "Dimensions:  (plev: 59, lat: 64, month: 12)\n",
+       "Coordinates:\n",
+       "  * plev     (plev) float64 1.004e+03 959.0 849.5 750.4 ... 0.3719 0.3254 0.2842\n",
+       "  * lat      (lat) float64 -87.86 -85.1 -82.31 -79.53 ... 79.53 82.31 85.1 87.86\n",
+       "  * month    (month) int64 1 2 3 4 5 6 7 8 9 10 11 12\n",
+       "Data variables:\n",
+       "    o3vmr    (plev, lat, month) float64 1.43e-08 8.647e-09 ... 1.78e-06
" + ], + "text/plain": [ + "\n", + "Dimensions: (plev: 59, lat: 64, month: 12)\n", + "Coordinates:\n", + " * plev (plev) float64 1.004e+03 959.0 849.5 750.4 ... 0.3719 0.3254 0.2842\n", + " * lat (lat) float64 -87.86 -85.1 -82.31 -79.53 ... 79.53 82.31 85.1 87.86\n", + " * month (month) int64 1 2 3 4 5 6 7 8 9 10 11 12\n", + "Data variables:\n", + " o3vmr (plev, lat, month) float64 1.43e-08 8.647e-09 ... 1.78e-06" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "ozone = xr.Dataset(\n", + " {\n", + " 'o3vmr': (('plev','lat','month'), o3vmr),\n", + " },\n", + " coords={'plev': plev, 'lat': lat, 'month': np.arange(1,13)},\n", + ")\n", + "\n", + "ozone.coords['plev'].attrs = {\n", + " 'long_name': 'Pressure Levels',\n", + " 'units': 'mbar',\n", + "}\n", + "ozone.coords['lat'].attrs = {\n", + " 'long_name': 'Latitude',\n", + " 'units': 'deg',\n", + "}\n", + "ozone['o3vmr'].attrs = {\n", + " 'long_name': 'Ozone Volume Mixing Ratio',\n", + " 'units': 'mol O3 / mol air',\n", + "}\n", + "\n", + "ozone = ozone.sortby('plev', ascending=False)\n", + "ozone" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "642d020e-e6a8-4807-a59d-c7d9c0f5873a", + "metadata": {}, + "outputs": [], + "source": [ + "ozone.to_netcdf('data/ozone_CAM.nc')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8b065fcd-4d71-4975-beb4-0324efcf767c", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "id": "c0fb5e2c-e270-4a6e-8d22-d1464d6e8274", + "metadata": {}, + "source": [ + "## do some checks against literature" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "d782277e-c6fb-4191-9f96-b45718e68345", + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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De/UrGKAw+Fwdw6Pl5iYqMTERElSXFycoqOjVVhYSDGgBcqq65x/7hDU7DoUAOAUGmdbsfQKAFxrS0MxYFBy82ZGA+2R6WWuF198UYMGDVJERIQiIiI0atQoffLJJy59jq+//lqXXHKJkpKSZLFY9P7775/0vBdeeEHdunVTcHCwhg0bpm+++eak561bt04Oh0MpKSkuzentGosBHYKsrLsCABcoatiulaVXAOBaW7LriwEDO1MMgPcyvRjQuXNnPf7441q3bp3WrVun8847T5deeqm2bdt20vO//fZb1dbWnnB8586dys3NPenXVFRUaPDgwXruuedOmeOdd97R7Nmz9eCDD2rjxo06++yzdeGFF+rQoUNNzisoKNDVV1+tl19+uQWvEpJUWlX//y0imFkBAOAKjTMDaB4IAK5ztLRaeWU2+VmkfokUA+C9TC8GXHLJJbrooovUq1cv9erVS4899pg6dOig77///oRzHQ6HbrnlFs2YMaNJg8Ldu3fr3HPP1euvv37S57jwwgv16KOP6rLLLjtljqefflrXX3+9fvOb36hv376aP3++UlJS9OKLLzrPsdls+uUvf6kHHnhAo0ePbsWr9k2NMwPCg7mDBQCu0LhDSxQzAwDAZRqXCKTFhSsk0N/kNID7mF4M+DG73a5FixapoqJCo0aNOuFxPz8/ffzxx9q4caOuvvpqORwO7du3T+edd56mTp2q++6774yet6amRuvXr9ekSZOaHJ80aZJWr14tSTIMQ9dcc43OO+88zZw582e/3/PPP69+/fppxIgRZ5THW5VV188MCGdmAOCzGB9dp87uUGlDkTWKngFAu8f46Dk2s0QAPsIjigFbtmxRhw4dFBQUpBtvvFGLFy9Wv379TnpuUlKSvvjiC3377beaMWOGzjvvPE2YMEEvvfTSGT9/fn6+7Ha74uPjmxyPj493Lj349ttv9c477+j9999Xenq60tPTtWXLlpN+v1tuuUXbt2/X2rVrzziTNzo+M4BiAOCrGB9dp6Tq+JK5SHZoAdo9xkfPsbWxGEDzQHi5M7oq27dvn1599VXt27dPf/vb3xQXF6dly5YpJSVF/fv3b/H36927tzIyMlRcXKx3331Xs2bN0sqVK09ZEOjSpYtef/11jRs3Tt27d9eCBQtksbS+Id1Pv4dhGM5jY8eOZVeFVip1zgzgTSsAtFZj88CIYKus/h5R2weAds8wDOe2gswMgLdr8buHlStXauDAgfrhhx/03nvvqby8XJK0efNmPfTQQ2cUIjAwUD179tTw4cM1b948DR48WH/7299Oef7Ro0f1u9/9TpdccokqKyt15513ntHzNoqNjZW/v/8JDQjz8vJOmC2AM8fMAABwHZoHAoDrHS21Kb/cJn8/i/olRpgdB3CrFhcDfv/73+vRRx/V8uXLFRh4/A3Iueeeq++++84loQzDkM1mO+lj+fn5mjBhgvr27av33ntPX3zxhf7v//5P99xzzxk/X2BgoIYNG6bly5c3Ob58+XIaBbpQYzEggumsANBqjc0DO9IvAABcZvPhYklSWlwHBQfQPBDercW3aLds2aK33377hOOdOnVSQUFBiwP84Q9/0IUXXqiUlBSVlZVp0aJF+uqrr7Rs2bITznU4HLrggguUmpqqd955R1arVX379tWKFSt07rnnKjk5+aSzBMrLy7V3717n55mZmcrIyFB0dLS6dOkiSbrrrrs0c+ZMDR8+XKNGjdLLL7+sQ4cO6cYbb2zxa8LJldJAEABcprhhmUA0OwkAgMvQLwC+pMVXZR07dlROTo66devW5PjGjRuVnJzc4gBHjx7VzJkzlZOTo8jISA0aNEjLli3T+eeff8K5fn5+mjdvns4+++wmsxIGDhyoFStWKCYm5qTPsW7dOp177rnOz++66y5J0qxZs7Rw4UJJ0q9//WsVFBTokUceUU5OjgYMGKCPP/5YqampLX5NOLkyegYAgMs4lwkwMwAAXKZxJ4FB9AuAD2hxMWDGjBm6//779Z///EcWi0UOh0Pffvut7rnnHl199dUtDrBgwYIWnX+yIoEkpaenn/Jrxo8fL8MwTvu9b775Zt18880tyoPmcy4TYGYAALRaYwNBlgkAgGsYhqEtDc0DBzAzAD6gxT0DHnvsMXXp0kXJyckqLy9Xv379dM4552j06NH64x//6I6M8BI0EAQA12nsGRDFMgEAcImckmoVVNTI6mdRX5oHwge0+KosICBAb731lh555BFt3LhRDodDQ4YMUVpamjvywYuwTAAAXIfdBADAtRq3FEyLD6d5IHzCGd+i7dGjh3r06OHKLPByx5cJUAwAgNZqbCBIzwAAcI3G5oGDWCIAH9GsYkBjw73mePrpp884DLwbywQAwHWONxCkwAoA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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# c.f. Saiz-Lopez et al. 2012, ACP -- Fig. 3\n", + "\n", + "gala = ozone['o3vmr'].interp(lat=1. ).mean('month')\n", + "fiji = ozone['o3vmr'].interp(lat=18.).mean('month')\n", + "naha = ozone['o3vmr'].interp(lat=26.).mean('month')\n", + "\n", + "fig,axs = plt.subplots(ncols=3,sharex=True,sharey=True,figsize=(12,4))\n", + "axs[0].semilogy(gala/1e-9, ozone.plev)\n", + "axs[1].semilogy(fiji/1e-9, ozone.plev)\n", + "axs[2].semilogy(naha/1e-9, ozone.plev)\n", + "\n", + "axs[0].set_ylabel('Altitude [hPa]')\n", + "for ax in axs:\n", + " ax.set_xlabel\n", + "axs[0].set_ylim((100,1000))\n", + "axs[0].set_xlim((0,150))\n", + "axs[0].set_xticks(np.arange(0,150,20))\n", + "ylabels = [100,200,400,600,1000]\n", + "axs[0].set_yticks(ylabels)\n", + "axs[0].set_yticklabels(ylabels)\n", + "axs[0].invert_yaxis()" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "600aac0c-1006-4655-9248-e46ee8277318", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Text(0, 0.5, 'Pressure [hPa]')" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# c.f. Montornes et al. 2015, ACP -- Fig. 1\n", + "midlat_summer = ozone['o3vmr'].sel(lat=slice(30,60),month=[6,7,8]).mean(['lat','month'])\n", + "midlat_winter = ozone['o3vmr'].sel(lat=slice(30,60),month=[12,1,2]).mean(['lat','month'])\n", + "arctic_summer = ozone['o3vmr'].sel(lat=slice(60,90),month=[6,7,8]).mean(['lat','month'])\n", + "arctic_winter = ozone['o3vmr'].sel(lat=slice(60,90),month=[12,1,2]).mean(['lat','month'])\n", + "\n", + "fig,ax = plt.subplots()\n", + "ax.semilogy(midlat_summer, ozone.plev, 'tab:purple', label='mid lat summer')\n", + "ax.semilogy(midlat_winter, ozone.plev, 'tab:red', label='mid lat winter')\n", + "ax.semilogy(arctic_summer, ozone.plev, 'tab:green', label='arctic summer')\n", + "ax.semilogy(arctic_winter, ozone.plev, 'tab:orange', label='arctic winter')\n", + "ax.invert_yaxis()\n", + "ax.set_yticks(10.**np.arange(-4,4))\n", + "ax.grid(alpha=0.25)\n", + "ax.legend(loc='upper left',bbox_to_anchor=(1,1))\n", + "ax.set_xlabel('Ozone volume mixing ratio')\n", + "ax.set_ylabel('Pressure [hPa]')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "37453d55-d86b-40e6-ad5d-481ebc8fe747", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "forge", + "language": "python", + "name": "forge" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.10" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..991739a --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,74 @@ +[build-system] +requires = ["setuptools>=64", "wheel"] +build-backend = "setuptools.build_meta" + +[project] +name = "erftools" +version = "0.1.1" +description = "Python code to make life easier for users of the Energy Research & Forecasting model" +authors = [ + {name = "U.S. Department of Energy", email = "eliot.quon@nrel.gov"} +] +readme = "README.md" +license = "Apache-2.0" + +classifiers = [ + "Development Status :: 4 - Beta", + "Intended Audience :: Science/Research", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", +] + +requires-python = ">=3.9" + +dependencies = [ + "numpy>=2.0.2", + "scipy>=1.13.1", + "pandas>=2.3.2", + "xarray>=2024.7.0", + "netcdf4>=1.7.2", + "h5netcdf>=1.6.4", + "bottleneck>=1.5.0", + "pydantic", + "f90nml", + "click", + "ussa1976", +] + +[project.optional-dependencies] +dev = [ + "jupyter", + "matplotlib", +] +performance = [ + "dask>=2024.8.0", + "mpi4py>=4.1.0", +] +grib = [ + "pygrib>=2.1.6", + "cdsapi>=0.7.6", + "herbie-data>=2024.8.0", + "cartopy>=0.23.0", + "pyproj>=3.6.1", +] +all = [ + "erftools[dev,performance,grib]" +] + +[tool.setuptools] +packages = ["erftools"] + +# Console scripts -- creates command line tools +[project.scripts] +check_erf_input = "erftools.inputs:check_erf_input" +wrf_namelist_to_erf = "erftools.wrf.inputdeck:wrf_namelist_to_erf" +generate_ozone_profile = "erftools.wrf.rad:generate_ozone_profile" + +[project.urls] +Homepage = "https://erf.readthedocs.io/en/latest/" +Repository = "https://github.com/erf-model/erftools" +Issues = "https://github.com/erf-model/erftools/issues" + diff --git a/setup.py b/setup.py deleted file mode 100644 index fd343f0..0000000 --- a/setup.py +++ /dev/null @@ -1,98 +0,0 @@ -# This setup file is based on https://github.com/a2e-mmc/mmctools/blob/master/setup.py -# accessed on April 3, 2020. - -# Note: To use the 'upload' functionality of this file, you must: -# $ pip install twine - -import io -import os - -from setuptools import find_packages, setup - -# Package meta-data. -NAME = 'erftools' -DESCRIPTION = 'Scripts to make life easier for users of the Energy Research & Forecasting model' -URL = 'https://github.com/erf-model/erftools' -EMAIL = 'eliot.quon@nrel.gov' -AUTHOR = 'U.S. Department of Energy' -REQUIRES_PYTHON = '>=3.6.0' -VERSION = '0.1.1' - -# What packages are required for this module to be executed? -REQUIRED = [ - # core - 'numpy>=1.18.1', - 'pandas>=1.0.1', - 'xarray>=0.15.0', - 'netcdf4>=1.5.1', - 'pydantic', - 'f90nml', - 'cartopy', - #'matplotlib>=3', - #'scipy>=1.4.1', - #'dask>=2.10.1', - #'utm>=0.5.0', -] - -EXTRAS = { -} - -# The rest you shouldn't have to touch too much :) -# ------------------------------------------------ -# Except, perhaps the License and Trove Classifiers! -# If you do change the License, remember to change the Trove Classifier for that! - -here = os.path.abspath(os.path.dirname(__file__)) - -# Import the README and use it as the long-description. -# Note: this will only work if 'README.md' is present in your MANIFEST.in file! -try: - with io.open(os.path.join(here, 'README.md'), encoding='utf-8') as f: - long_description = '\n' + f.read() -except FileNotFoundError: - long_description = DESCRIPTION - -# Load the package's __version__.py module as a dictionary. -about = {} -if not VERSION: - project_slug = NAME.lower().replace("-", "_").replace(" ", "_") - with open(os.path.join(here, project_slug, '__version__.py')) as f: - exec(f.read(), about) -else: - about['__version__'] = VERSION - -# Where the magic happens: -setup( - name=NAME, - version=about['__version__'], - description=DESCRIPTION, - long_description=long_description, - long_description_content_type='text/markdown', - author=AUTHOR, - author_email=EMAIL, - python_requires=REQUIRES_PYTHON, - url=URL, - #packages=find_packages(exclude=["tests", "*.tests", "*.tests.*", "tests.*"]), - # If your package is a single module, use this instead of 'packages': - py_modules=[NAME], - # entry_points={ - # 'console_scripts': ['mycli=mymodule:cli'], - # }, - install_requires=REQUIRED, - extras_require=EXTRAS, - include_package_data=True, - license='Apache-2.0', - classifiers=[ - # Trove classifiers - # Full list: https://pypi.python.org/pypi?%3Aaction=list_classifiers - 'License :: OSI Approved :: Apache Software License', - 'Topic :: Scientific/Engineering', - 'Programming Language :: Python', - 'Programming Language :: Python :: 3', - 'Development Status :: 4 - Beta', - ], - # $ setup.py publish support. - #cmdclass={ - # 'upload': UploadCommand, - #}, -)