Example: convert DEPHY forcing to DHARMA LES and ModelE3 SCM formats#
This code reads the COMBLE-MIP LES/SCM forcing file that is supplied in the DEPHY format and writes input files that are formatted for the DHARMA LES (ASCII) and the ModelE3 ESM SCM (NetCDF)
Contributed by Ann Fridlind from NASA/GISS on 1/24/23
Import libraries#
import numpy as np
import pandas as pd
import xarray as xr
import netCDF4
from netCDF4 import Dataset
Specify local write directory#
If on the ARM JupyterHub, it is recommended to create and specify a local directory that is outside of the COMBLE-MIP repository to write input files in your model’s format
If on the ARM JupyterHub, these files can be conveniently downloaded to your local machine and will remain when you log out
my_write_dir = '../../../my_input_files/'
Specify wind forcing type#
do_geo = True
Read the COMBLE-MIP forcing file#
NOTE: ERROR 1 message can be ignored
dephy_filename = '../forcing/COMBLE_INTERCOMPARISON_FORCING_V2.3.nc'
dephy = xr.open_dataset(dephy_filename)
dephy = dephy.squeeze()
dephy
ERROR 1: PROJ: proj_create_from_database: Open of /opt/conda/share/proj failed
<xarray.Dataset> Dimensions: (time: 21, lev: 136, zw_grid: 160) Coordinates: t0 datetime64[ns] 2020-03-12T22:00:00 lat float32 74.5 lon float32 9.9 * time (time) datetime64[ns] 2020-03-12T22:00:00 ... 2020-03-13T1... * lev (lev) float64 18.17 37.83 59.35 ... 6.851e+04 7.117e+04 * zw_grid (zw_grid) float64 0.0 20.0 45.0 ... 6.89e+03 6.95e+03 7e+03 Data variables: (12/19) pressure (lev) float64 ... u (lev) float64 ... v (lev) float64 ... temp (lev) float64 ... theta (lev) float64 ... qv (lev) float64 ... ... ... theta_nudging (time, lev) float64 ... qv_nudging (time, lev) float64 ... w_nudging (time, lev) float64 ... ts (time) float64 ... lat_ref (time) float32 ... lon_ref (time) float32 ... Attributes: (12/25) title: Forcing and initial conditions for 13 Mar... reference: https://arm-development.github.io/comble-... authors: Timothy W. Juliano (NCAR/RAL, tjuliano@uc... version: Created on 2023-12-01 format_version: DEPHY SCM format version 2.0 script: create_comble_forcing_v2.3.ipynb ... ... lat: 74.5 deg N droplet_activation_diagnostic: droplet number concentration fixed to 20 ... ice_nucleation_diagnostic: total ice number concentration fixed to 2... droplet_activation_prognostic: time and space varying aerosol initialize... aerosol_surface_source: modal emissions based on Jaegle et al. (2... ice_nucleation_prognostic: assume that all sea spray mode and half o...
Create input files for DHARMA LES in ASCII format#
Write initial sounding, ozone profile, forcing and vertical grid files, and echo some values for manual entry to the input parameter file
Echo values for manual input#
# echo initial surface pressure to enter into DHARMA input parameter file manually
dephy.ps.values.round(1)
99544.5
# echo surface temperature hourly values to enter into DHARMA input parameter file manually
dephy.ts.round(1)
<xarray.DataArray 'ts' (time: 21)> array([247. , 247. , 249.9, 271.1, 275.4, 275.2, 275.5, 275.8, 276.3, 276.6, 276.8, 277.3, 277.8, 278. , 278.2, 278.5, 279.1, 279.4, 279.4, 279.3, 277.8]) Coordinates: t0 datetime64[ns] 2020-03-12T22:00:00 lat float32 74.5 lon float32 9.9 * time (time) datetime64[ns] 2020-03-12T22:00:00 ... 2020-03-13T18:00:00 Attributes: units: K long_name: surface temperature
dephy
<xarray.Dataset> Dimensions: (time: 21, lev: 136, zw_grid: 160) Coordinates: t0 datetime64[ns] 2020-03-12T22:00:00 lat float32 74.5 lon float32 9.9 * time (time) datetime64[ns] 2020-03-12T22:00:00 ... 2020-03-13T1... * lev (lev) float64 18.17 37.83 59.35 ... 6.851e+04 7.117e+04 * zw_grid (zw_grid) float64 0.0 20.0 45.0 ... 6.89e+03 6.95e+03 7e+03 Data variables: (12/19) pressure (lev) float64 ... u (lev) float64 ... v (lev) float64 ... temp (lev) float64 ... theta (lev) float64 ... qv (lev) float64 ... ... ... theta_nudging (time, lev) float64 ... qv_nudging (time, lev) float64 ... w_nudging (time, lev) float64 ... ts (time) float64 247.0 247.0 249.9 271.1 ... 279.4 279.3 277.8 lat_ref (time) float32 ... lon_ref (time) float32 ... Attributes: (12/25) title: Forcing and initial conditions for 13 Mar... reference: https://arm-development.github.io/comble-... authors: Timothy W. Juliano (NCAR/RAL, tjuliano@uc... version: Created on 2023-12-01 format_version: DEPHY SCM format version 2.0 script: create_comble_forcing_v2.3.ipynb ... ... lat: 74.5 deg N droplet_activation_diagnostic: droplet number concentration fixed to 20 ... ice_nucleation_diagnostic: total ice number concentration fixed to 2... droplet_activation_prognostic: time and space varying aerosol initialize... aerosol_surface_source: modal emissions based on Jaegle et al. (2... ice_nucleation_prognostic: assume that all sea spray mode and half o...
Write input sounding file#
# use a list to accumulate output ASCII lines
lines_sounding = []
# number of lines to be read
n_z = dephy.dims['lev']
str_firstline = str(n_z+1) # number of heights after adding surface point below
lines_sounding.append(str_firstline)
# arrays to be reported in columns
z_arr = dephy.coords['lev'].values
th_arr = dephy['theta'].values.squeeze() # K
qt_arr = dephy['qv'].values.squeeze()*1000. # g/kg
u_arr = dephy['u'].values.squeeze() # m/s
v_arr = dephy['v'].values.squeeze() # m/s
# add a surface point (required by DHARMA code)
z0_arr = np.array([0.,th_arr[0],qt_arr[0],u_arr[0],v_arr[0]]) # well-mixed assumption
str_z0 = np.array2string(z0_arr,formatter={'float_kind':lambda z0_arr:"%12.4f" % z0_arr})[1:-1]
lines_sounding.append(str_z0)
for kk in range(n_z):
vars_arr = np.array([z_arr[kk],th_arr[kk],qt_arr[kk],u_arr[kk],v_arr[kk]])
str_vars = np.array2string(vars_arr,formatter={'float_kind':lambda vars_arr:"%12.4f" % vars_arr})[1:-1]
lines_sounding.append(str_vars)
str_headline = str(' z(m) th(K) qt(g/kg) u(m/s) v(m/s)')
lines_sounding.append(str_headline)
# write list contents to ASCII file
filename_sounding_LES = my_write_dir + 'DHARMA_LES_ASCII_comble.input_sounding'
with open(filename_sounding_LES,mode='wt',encoding='utf-8') as sounding_file:
sounding_file.write('\n'.join(lines_sounding))
Write ozone profile#
# use a list to accumulate output ASCII lines
lines_sounding = []
# number of lines to be read
n_z = dephy.dims['lev']
str_firstline = str(n_z+1) # number of heights after adding surface point below
lines_sounding.append(str_firstline)
# arrays to be reported in columns
z_arr = dephy.coords['lev'].values
p_arr = dephy['pressure'].values.squeeze()/100. # mb
o3_arr = dephy['o3'].values.squeeze() # kg/kg
o3ppb_arr = o3_arr*28.96/48.*1e9 # convert with molecular weights
# add a surface point (required by DHARMA code)
z0_arr = np.array([0.,dephy.ps.values,o3ppb_arr[0],o3_arr[0]]) # well-mixed assumption
str_z0 = np.array2string(z0_arr,formatter={'float_kind':lambda z0_arr:"%12.4e" % z0_arr})[1:-1]
lines_sounding.append(str_z0)
for kk in range(n_z):
vars_arr = np.array([z_arr[kk],p_arr[kk],o3ppb_arr[kk],o3_arr[kk]])
str_vars = np.array2string(vars_arr,formatter={'float_kind':lambda vars_arr:"%12.4e" % vars_arr})[1:-1]
lines_sounding.append(str_vars)
str_headline = str(' z(m) P(mb) O3(ppbv) O3(kg/kg)')
lines_sounding.append(str_headline)
# write list contents to ASCII file
filename_o3_LES = my_write_dir + 'DHARMA_LES_ASCII_comble.input_o3'
with open(filename_o3_LES,mode='wt',encoding='utf-8') as sounding_file:
sounding_file.write('\n'.join(lines_sounding))
Write forcing file#
# create thermodynamic forcing file contents as list
lines_forcing = []
# limit to bottom 8 km for brevity
n_zf = np.max(np.where(dephy.lev<8000.))
n_t = dephy.dims['time']
str_firstline = str(n_zf+1)+' '+str(n_t) # extra line for z=0
lines_forcing.append(str_firstline) # number of heights, times
for tt in range(n_t):
if do_geo:
## for geostrophic wind
u_arr = dephy['ug'][tt,:].values # m/s, sensitivity test
v_arr = dephy['vg'][tt,:].values # m/s, sensitivity test
else:
## for nudging
u_arr = dephy['u_nudging'][tt,:].values # m/s, sensitivity test
v_arr = dephy['v_nudging'][tt,:].values # m/s, sensitivity test
om_arr = dephy['w_nudging'][tt,:].values # Pa/s
p_arr = dephy['pressure'].values # Pa
t_arr = dephy['temp'].values # K
qv_arr = dephy['qv'].values # kg/kg
rho_arr = p_arr/(t_arr*287.*(1.+0.608*qv_arr)) # kg/m3
w_arr = -om_arr/(9.81*rho_arr.squeeze())*100. # cm/s, sensitivity test
th_arr = -np.ones(n_zf) # no thermo forcing
qv_arr = -np.ones(n_zf)
z0_arr = np.array([0.,0.,-1.,-1.,u_arr[0],v_arr[0]])
str_z0 = np.array2string(z0_arr,formatter={'float_kind':lambda z0_arr:"%10.2f" % z0_arr})[1:-1]
lines_forcing.append(str_z0)
for kk in range(n_zf):
vars_arr = np.array([z_arr[kk],w_arr[kk],th_arr[kk],qv_arr[kk],u_arr[kk],v_arr[kk]])
str_vars = np.array2string(vars_arr,formatter={'float_kind':lambda vars_arr:"%10.2f" % vars_arr})[1:-1]
lines_forcing.append(str_vars)
lines_forcing.append(str(tt))
str_endlines1 = str(' z(m) w(cm/s) th(K) qv(kg/kg) ug(m/s) vg(m/s)')
lines_forcing.append(str_endlines1)
str_endlines2 = str('time(h)')
lines_forcing.append(str_endlines2)
# write list contents to ASCII file
filename_forcing_LES = my_write_dir + 'DHARMA_LES_ASCII_comble.input_forcing'
with open(filename_forcing_LES,mode='wt',encoding='utf-8') as forcing_file:
forcing_file.write('\n'.join(lines_forcing))
Write vertical grid file#
# create vertical grid file contents as list
lines_zw = []
n_zw = dephy.dims['zw_grid'] # number of heights
lines_zw.append(str(n_zw))
for kk in range(n_zw):
lines_zw.append(str(dephy['zw_grid'][kk].values))
# write vertical grid to ASCII file
filename_zw_LES = my_write_dir + 'DHARMA_LES_ASCII_comble.input_z'
with open(filename_zw_LES,mode='wt',encoding='utf-8') as zw_file:
zw_file.write('\n'.join(lines_zw))
Create input files for ModelE3 SCM#
Write initialization and forcing files in NetCDF format
Write initialization file#
# open file with all components at initial time only
filename_init_SCM = my_write_dir + 'SCM_COMBLE-MIP_init.nc'
scm_init = Dataset('./' + filename_init_SCM,mode='w',format='NETCDF3_CLASSIC')
# create dimensions
lev_dim = scm_init.createDimension('lev', n_z) # level axis is pressure for SCM
time_dim = scm_init.createDimension('time', 1) # initial time only
# create variables
lev = scm_init.createVariable('lev', np.float64, ('lev',))
lev.long_name = 'air pressure'
lev.units = 'mb'
lev[:] = dephy['pressure'].values/100.
Ps = scm_init.createVariable('Ps', np.float64, ('time',))
Ps.long_name = 'surface pressure'
Ps.units = 'mb'
Ps[:] = dephy.ps.values.round(1)/100.
T = scm_init.createVariable('T', np.float64, ('lev',))
T.long_name = 'air temperature'
T.units = 'K'
T[:] = dephy['temp'].values
Q = scm_init.createVariable('Q', np.float64, ('lev',))
Q.long_name = 'water vapor mixing ratio'
Q.units = 'kg kg-1'
Q[:] = dephy['qv'].values
# create time arrays
year = scm_init.createVariable('year', np.int16, ('time',))
year[:] = pd.to_datetime(dephy['time'].values[0]).year
month = scm_init.createVariable('month', np.int16, ('time',))
month[:] = pd.to_datetime(dephy['time'].values[0]).month
day = scm_init.createVariable('day', np.int16, ('time',))
day[:] = pd.to_datetime(dephy['time'].values[0]).day
hour = scm_init.createVariable('hour', np.int16, ('time',))
hour[:] = pd.to_datetime(dephy['time'].values[0]).hour
# close
scm_init.close()
Write forcing file#
# open forcing file with all components on same time dimension
filename_forcing_SCM = my_write_dir + 'SCM_COMBLE-MIP_force.nc'
scm_force = Dataset('./' + filename_forcing_SCM,mode='w',format='NETCDF3_CLASSIC')
# create dimensions
lev_dim = scm_force.createDimension('lev', n_z) # level axis is pressure for SCM
time_dim = scm_force.createDimension('time', n_t)
# create variables
lev = scm_force.createVariable('lev', np.float64, ('lev'))
lev.long_name = 'air pressure'
lev.units = 'mb'
lev[:] = dephy['pressure'].values/100.
ts = scm_force.createVariable('Tskin', np.float32, ('time'))
ts.long_name = 'surface temperature'
ts.units = 'K'
ts[:] = dephy['ts'].values
ug = scm_force.createVariable('Ug', np.float64, ('time','lev',))
ug.units = 'm s-1'
ug.long_name = 'geostrophic zonal wind'
ug[:] = dephy['ug'].values
vg = scm_force.createVariable('Vg', np.float64, ('time','lev',))
vg.units = 'm s-1'
vg.long_name = 'geostrophic meridional wind'
vg[:] = dephy['vg'].values
# create time arrays
year = scm_force.createVariable('year', np.int16, ('time',))
year[:] = pd.to_datetime(dephy['time'].values).year
month = scm_force.createVariable('month', np.int16, ('time',))
month[:] = pd.to_datetime(dephy['time'].values).month
day = scm_force.createVariable('day', np.int16, ('time',))
day[:] = pd.to_datetime(dephy['time'].values).day
hour = scm_force.createVariable('hour', np.int16, ('time',))
hour[:] = pd.to_datetime(dephy['time'].values).hour
# close
scm_force.close()