From 79ccbc51b0ef8f27243dd2a52ee4fd7c9e33b241 Mon Sep 17 00:00:00 2001 From: Dustin Swales Date: Tue, 7 May 2024 02:14:20 +0000 Subject: [PATCH 01/25] Stash for port --- scm/etc/scripts/UFS_IC_generator.py | 278 +++++++++++++++--- .../scripts/UFS_forcing_ensemble_generator.py | 2 + 2 files changed, 242 insertions(+), 38 deletions(-) diff --git a/scm/etc/scripts/UFS_IC_generator.py b/scm/etc/scripts/UFS_IC_generator.py index cac0d2773..0e2d12039 100755 --- a/scm/etc/scripts/UFS_IC_generator.py +++ b/scm/etc/scripts/UFS_IC_generator.py @@ -68,6 +68,7 @@ parser.add_argument('-lam', '--lam', help='flag to signal that the ICs and forcing is from a limited-area model run', action='store_true') parser.add_argument('-sc', '--save_comp', help='flag to create UFS reference file for comparison', action='store_true') parser.add_argument('-near','--use_nearest', help='flag to indicate using the nearest UFS history file gridpoint',action='store_true') +parser.add_argument('-ext', '--exact_mode', help='flag to indicate using dynamic tendencies from UFS history files', action='store_true') ######################################################################################## # @@ -88,6 +89,7 @@ def parse_arguments(): lam = args.lam save_comp = args.save_comp use_nearest = args.use_nearest + exact_mode = args.exact_mode #validate args if not os.path.exists(in_dir): @@ -127,7 +129,7 @@ def parse_arguments(): raise Exception(message) return (location, index, date_dict, in_dir, grid_dir, forcing_dir, tile, \ - area, case_name, old_chgres, lam, save_comp, use_nearest) + area, case_name, old_chgres, lam, save_comp, use_nearest, exact_mode) ######################################################################################## # @@ -1492,7 +1494,7 @@ def search_in_dict(listin,name): # ######################################################################################## def get_UFS_forcing_data(nlevs, state_IC, location, use_nearest, forcing_dir, grid_dir, - tile, i, j, lam, save_comp_data): + tile, i, j, lam, save_comp_data, exact_mode): """Get the horizontal and vertical advective tendencies for the given tile and indices""" # Determine UFS history file format (tiled/quilted) @@ -1502,17 +1504,21 @@ def get_UFS_forcing_data(nlevs, state_IC, location, use_nearest, forcing_dir, gr else: atm_ftag = 'atmf*.nc' sfc_ftag = 'sfcf*.nc' - + # end if + # Get list of UFS history files with 3D ATMospheric state variables. atm_filenames = [] for f_name in os.listdir(forcing_dir): if fnmatch.fnmatch(f_name, atm_ftag): atm_filenames.append(f_name) + # end if + # end for if not atm_filenames: message = 'No filenames matching the pattern {0} found in {1}'. \ format(atm_ftag,forcing_dir) logging.critical(message) raise Exception(message) + # end if atm_filenames = sorted(atm_filenames) n_filesA = len(atm_filenames) @@ -1521,11 +1527,14 @@ def get_UFS_forcing_data(nlevs, state_IC, location, use_nearest, forcing_dir, gr for f_name in os.listdir(forcing_dir): if fnmatch.fnmatch(f_name, sfc_ftag): sfc_filenames.append(f_name) + # end if + # end fo if not sfc_filenames: message = 'No filenames matching the pattern {0} found in {1}'. \ format(sfc_ftag,forcing_dir) logging.critical(message) raise Exception(message) + # end if sfc_filenames = sorted(sfc_filenames) n_filesS = len(sfc_filenames) @@ -1535,7 +1544,8 @@ def get_UFS_forcing_data(nlevs, state_IC, location, use_nearest, forcing_dir, gr message = 'Number of UFS 2D/3D history files is inconsistent' logging.critical(message) raise Exception(message) - + # end if + # Physical constants (used by FV3 remapping functions) kord_tm = -9 kord_tr = 9 @@ -1545,7 +1555,7 @@ def get_UFS_forcing_data(nlevs, state_IC, location, use_nearest, forcing_dir, gr #################################################################################### # - # Read in atmospheric state, atmf*.nc history files. + # Read in 3D UFS history files # #################################################################################### @@ -1555,8 +1565,9 @@ def get_UFS_forcing_data(nlevs, state_IC, location, use_nearest, forcing_dir, gr print('The closest point has indices [{0},{1}]'.format(tile_ii,tile_jj)) print('This index has a central longitude/latitude of [{0},{1}]'.format(point_lon,point_lat)) print('This grid cell is approximately {0} km away from the desired location of {1} {2}'.format(dist_min/1.0E3,location[0],location[1])) - - # + # end if + + # Initialize ps = [] p_lev = [] p_lay = [] @@ -1582,12 +1593,15 @@ def get_UFS_forcing_data(nlevs, state_IC, location, use_nearest, forcing_dir, gr except: data_grid_lon = nc_file['grid_xt'][:,:] data_grid_lat = nc_file['grid_yt'][:,:] + # end try equal_grids = False if (ic_grid_lon.shape == data_grid_lon.shape and \ ic_grid_lat.shape == ic_grid_lat.shape): if (np.equal(ic_grid_lon,data_grid_lon).all() and \ np.equal(ic_grid_lat,data_grid_lat).all()): equal_grids = True + # end if + # end if # If necessary, remap history file (data_grid) to IC file (ic_grid). if (not equal_grids): @@ -1614,6 +1628,7 @@ def get_UFS_forcing_data(nlevs, state_IC, location, use_nearest, forcing_dir, gr v_data = nc_file['vgrd'][0,::-1,:,:] i_get = i j_get = j + # end if else: print('Using nearest UFS point {} progress = {}%'.format(filename, 100.0*count/(2*n_files))) ps_data = nc_file['pressfc'][0,:,:] @@ -1623,21 +1638,30 @@ def get_UFS_forcing_data(nlevs, state_IC, location, use_nearest, forcing_dir, gr v_data = nc_file['vgrd'][0,::-1,:,:] j_get = tile_jj i_get = tile_ii + # end if - # Compute and store vertical grid information. - ak = getattr(nc_file, "ak")[::-1] - bk = getattr(nc_file, "bk")[::-1] + # Store surface pressure. ps.append(ps_data[j_get,i_get]) + + # Compute and store vertical grid information. + ak = getattr(nc_file, "ak")[::-1] + bk = getattr(nc_file, "bk")[::-1] nlevs = len(nc_file.dimensions['pfull']) + + # Compute and store pressure at layer-interfaces (nlev+1). p_interface = np.zeros(nlevs+1) for k in range(nlevs+1): p_interface[k]=ak[k]+ps[-1]*bk[k] + # end for p_lev.append(p_interface) + + # Compute and store pressure at layer-centers (nlev). p_layer = np.zeros(nlevs) for k in range(nlevs): p_layer[k] = ((1.0/(rocp+1.0))*(p_interface[k]**(rocp+1.0) - \ p_interface[k+1]**(rocp+1.0))/(p_interface[k] - \ p_interface[k+1]))**(1.0/rocp) + # end for p_lay.append(p_layer) # Store state variables. @@ -1646,9 +1670,10 @@ def get_UFS_forcing_data(nlevs, state_IC, location, use_nearest, forcing_dir, gr u_lay.append(u_data[:,j_get,i_get]) v_lay.append(v_data[:,j_get,i_get]) time_hr.append(nc_file['time'][0]) - + # Close file nc_file.close() + # end for # Convert from python list to numpy array ps = np.asarray(ps) @@ -1658,19 +1683,38 @@ def get_UFS_forcing_data(nlevs, state_IC, location, use_nearest, forcing_dir, gr qv_lay = np.asarray(qv_lay) u_lay = np.asarray(u_lay) v_lay = np.asarray(v_lay) - tv_lay = t_lay*(1.0 + zvir*qv_lay) time_hr = np.asarray(time_hr) + # Compute virtual temperature. + tv_lay = t_lay*(1.0 + zvir*qv_lay) + + #################################################################################### + # # Read in 2D UFS history files - vars2d =[{"name":"spfh2m"}, {"name":"tmp2m"}, \ - {"name":"dswrf_ave"}, {"name":"ulwrf_ave"},\ - {"name":"lhtfl_ave"}, {"name":"shtfl_ave"},\ - {"name":"dswrf"}, {"name":"ulwrf"},\ - {"name":"lhtfl"}, {"name":"shtfl"},\ - {"name":"pwat"}, {"name":"vgrd10m"},\ + # + # Comments: + # These files contain the 3D (diagnostic) dynamic tendencies needed to create "exact" + # UFS forcings. These are stored in the python dictionary "dyntends". + # + # Additionally, a limited set of two-dimensionsal variables, python dictionary "vars2d", + # are output to the "case comparison file". + # + #################################################################################### + + # Variable sneeded for "exact" UFS case generation. + dyntends = [{"name":"dtend_temp_nophys"}, {"name":"dtend_u_nophys"}, \ + {"name":"dtend_v_nophys"}, {"name":"dtend_qv_nophys"}] + for dyntend in dyntends: dyntend["values"] = [] + + # Variables to be added to "UFS comparison file" + vars2d =[{"name":"spfh2m"}, {"name":"tmp2m"}, {"name":"dswrf_ave"}, \ + {"name":"ulwrf_ave"}, {"name":"lhtfl_ave"}, {"name":"shtfl_ave"}, \ + {"name":"dswrf"}, {"name":"ulwrf"}, {"name":"lhtfl"}, \ + {"name":"shtfl"}, {"name":"pwat"}, {"name":"vgrd10m"}, \ {"name":"ugrd10m"}] for var2d in vars2d: var2d["values"] = [] + # Read in 2D UFS history files for count, filename in enumerate(sfc_filenames, start=1): nc_file = Dataset('{0}/{1}'.format(forcing_dir,filename)) nc_file.set_always_mask(False) @@ -1683,12 +1727,15 @@ def get_UFS_forcing_data(nlevs, state_IC, location, use_nearest, forcing_dir, gr except: data_grid_lon = nc_file['grid_xt'][:,:] data_grid_lat = nc_file['grid_yt'][:,:] + # end try equal_grids = False if (ic_grid_lon.shape == data_grid_lon.shape and \ ic_grid_lat.shape == ic_grid_lat.shape): if (np.equal(ic_grid_lon,data_grid_lon).all() and \ np.equal(ic_grid_lat,data_grid_lat).all()): equal_grids = True + # end if + # endif # If necessary, remap history file (data_grid) to IC file (ic_grid). if (not equal_grids): @@ -1705,29 +1752,55 @@ def get_UFS_forcing_data(nlevs, state_IC, location, use_nearest, forcing_dir, gr else: i_get = i j_get = j + # end if else: print('Using nearest UFS point {} progress = {}%'.format(filename, 50+50.0*count/(n_files))) j_get = tile_jj i_get = tile_ii - + # end if + for var2d in vars2d: if not use_nearest: data = regridder(nc_file[var2d["name"]][0,:,:]) else: data = nc_file[var2d["name"]][0,:,:] + # end if var2d["values"].append(data[j_get,i_get]) var2d["units"] = nc_file[var2d["name"]].getncattr(name="units") var2d["long_name"] = nc_file[var2d["name"]].getncattr(name="long_name") - + # end for + + for dyntend in dyntends: + try: + if not use_nearest: + data = regridder(nc_file[dyntend["name"]][0,::-1,:,:]) + else: + data = nc_file[dyntend["name"]][0,::-1,:,:] + # end if + dyntend["values"].append(data[:,j_get,i_get]) + dyntend["units"] = nc_file[dyntend["name"]].getncattr(name="units") + dyntend["long_name"] = nc_file[dyntend["name"]].getncattr(name="long_name") + except: + print("Could not find ",dyntend["name"]," in ",nc_file) + # end try + # end for + nc_file.close() - + # end for + # Convert to numpy arrays for var2d in vars2d: var2d["values"] = np.asarray(var2d["values"]) + # end for + for dyntend in dyntends: + dyntend["values"] = np.asarray(dyntend["values"]) + # end for + #################################################################################### # # Create dictionary with full "Native" state (IC@t=0,ATMF*@t>0) # + #################################################################################### ps_IC = np.zeros([1]) ps_IC[0] = state_IC["ps"] pi_IC = np.zeros([1,nlevs+1]) @@ -1753,6 +1826,16 @@ def get_UFS_forcing_data(nlevs, state_IC, location, use_nearest, forcing_dir, gr "v_lay": np.concatenate((v_IC, v_lay), axis=0), \ "tv_lay": np.concatenate((tv_IC, tv_lay), axis=0)} + print("DJS2024: WHAT DOES THE NATIVE STATE LOOK LIKE, at the surface?") + print('{0: <4} {1: >8} {2: >8} {3: >8} {4: >8} {5: >6} {6: >6} {7: >6} {8: >8}'. + format('Time','sfcP','pi','p','t','qv','u','v','tv')) + for ij in range(0,len(stateNATIVE["time"])): + print('{0:4d} {1:8.2f} {2:8.2f} {3:8.2f} {4:8.2f} {5:6.2f} {6:6.2f} {7:6.2f} {8:8.2f}'. + format(int(stateNATIVE["time"][ij]),stateNATIVE["ps"][ij]*0.01,stateNATIVE["p_lev"][ij,0]*0.01,\ + stateNATIVE["p_lay"][ij,0]*0.01,stateNATIVE["t_lay"][ij,0],stateNATIVE["qv_lay"][ij,0]*100.,\ + stateNATIVE["u_lay"][ij,0],stateNATIVE["v_lay"][ij,0],stateNATIVE["tv_lay"][ij,0])) + # end for + #################################################################################### # # The "total" advection, where "total" = "advective + remapping", can be computed @@ -1775,8 +1858,8 @@ def get_UFS_forcing_data(nlevs, state_IC, location, use_nearest, forcing_dir, gr # #################################################################################### - # - nlevs = len(p_lay[0,:]) + # Initialize +# nlevs = len(p_lay[0,:]) dummy = np.zeros(1) from_p = np.zeros([1,nlevs+1]) to_p = np.zeros([1,nlevs+1]) @@ -1826,7 +1909,7 @@ def get_UFS_forcing_data(nlevs, state_IC, location, use_nearest, forcing_dir, gr v_init_rev = state_IC["va"][::-1] v_rev_new = fv3_remap.map1_ppm(nlevs, from_p, v_init_rev[np.newaxis, :], 0.0, \ nlevs, to_p, 0, 0, -1, kord_tm ) - + # Store p_layr[0,:] = p_lay[0,:] p_levr[0,:] = p_lev[0,:] @@ -1834,20 +1917,18 @@ def get_UFS_forcing_data(nlevs, state_IC, location, use_nearest, forcing_dir, gr u_layr[0,:] = u_rev_new[0,::-1] tv_layr[0,:] = tv_rev_new[0,::-1] qv_layr[0,:] = qv_rev_new[0,::-1] - + # # Subsequent timestep(s)... # (current state on vertical grid of subsequent time-step(s). Used for differencing) - # - # for t in range(n_files-1): - # + # Interpolation range from_p[0,:] = p_lev[t,::-1] to_p[0,:] = p_lev[t+1,::-1] log_from_p[0,:] = np.log(p_lev[t,::-1]) log_to_p[0,:] = np.log(p_lev[t+1,::-1]) - + # Virtual Temperature @ time > 0 tv_rev[0,:] = tv_lay[t,::-1] tv_rev_new = fv3_remap.map_scalar(nlevs, log_from_p, tv_rev, dummy, nlevs, \ @@ -1865,7 +1946,6 @@ def get_UFS_forcing_data(nlevs, state_IC, location, use_nearest, forcing_dir, gr v_rev[0,:] = v_lay[t,::-1] v_rev_new = fv3_remap.map1_ppm(nlevs, from_p, v_rev, 0.0, nlevs, to_p, \ 0, 0, -1, kord_tm ) - # Store p_layr[t+1,:] = p_lay[t+1,:] p_levr[t+1,:] = p_lev[t+1,:] @@ -1873,7 +1953,8 @@ def get_UFS_forcing_data(nlevs, state_IC, location, use_nearest, forcing_dir, gr qv_layr[t+1,:] = qv_rev_new[0,::-1] u_layr[t+1,:] = u_rev_new[0,::-1] v_layr[t+1,:] = v_rev_new[0,::-1] - + # end for + # p_layr[t+2,:] = p_layr[t+1,:] p_levr[t+2,:] = p_levr[t+1,:] @@ -1895,6 +1976,15 @@ def get_UFS_forcing_data(nlevs, state_IC, location, use_nearest, forcing_dir, gr "u_lay": u_layr, \ "v_lay": v_layr, \ "tv_lay": tv_layr } + print("DJS2024: WHAT DOES THE REGRIDDED STATE LOOK LIKE, at the surface?") + print('{0: <4} {1: >8} {2: >8} {3: >8} {4: >8} {5: >6} {6: >6} {7: >6} {8: >8}'. + format('Time','sfcP','pi','p','t','qv','u','v','tv')) + for ij in range(0,len(stateREGRID["time"])): + print('{0:4d} {1:8.2f} {2:8.2f} {3:8.2f} {4:8.2f} {5:6.2f} {6:6.2f} {7:6.2f} {8:8.2f}'. + format(int(stateREGRID["time"][ij]),stateREGRID["ps"][ij]*0.01,stateREGRID["p_lev"][ij,0]*0.01,\ + stateREGRID["p_lay"][ij,0]*0.01,stateREGRID["t_lay"][ij,0],stateREGRID["qv_lay"][ij,0]*100.,\ + stateREGRID["u_lay"][ij,0],stateREGRID["v_lay"][ij,0],stateREGRID["tv_lay"][ij,0])) + # end for #################################################################################### # @@ -1923,15 +2013,15 @@ def get_UFS_forcing_data(nlevs, state_IC, location, use_nearest, forcing_dir, gr tend_total[0,:] = stateREGRID["t_lay"][t+1,:] - stateREGRID["t_lay"][t,:] tend_remap[0,:] = stateREGRID["t_lay"][t,:] - stateNATIVE["t_lay"][t,:] dtdt_adv[t,:] = (tend_total[0,:] - tend_remap[0,:]) / dtime_sec - # + tend_total[0,:] = stateREGRID["qv_lay"][t+1,:] - stateREGRID["qv_lay"][t,:] tend_remap[0,:] = stateREGRID["qv_lay"][t,:] - stateNATIVE["qv_lay"][t,:] dqvdt_adv[t,:] = (tend_total[0,:] - tend_remap[0,:]) / dtime_sec - # + tend_total[0,:] = stateREGRID["u_lay"][t+1,:] - stateREGRID["u_lay"][t,:] tend_remap[0,:] = stateREGRID["u_lay"][t,:] - stateNATIVE["u_lay"][t,:] dudt_adv[t,:] = (tend_total[0,:] - tend_remap[0,:]) / dtime_sec - # + tend_total[0,:] = stateREGRID["v_lay"][t+1,:] - stateREGRID["v_lay"][t,:] tend_remap[0,:] = stateREGRID["v_lay"][t,:] - stateNATIVE["v_lay"][t,:] dvdt_adv[t,:] = (tend_total[0,:] - tend_remap[0,:]) / dtime_sec @@ -1943,6 +2033,119 @@ def get_UFS_forcing_data(nlevs, state_IC, location, use_nearest, forcing_dir, gr dvdt_adv[t+1,:] = dvdt_adv[t,:] pres_adv[t+1,:] = pres_adv[t,:] pres_i_adv[t+1,:] = pres_i_adv[t,:] + + #################################################################################### + # + # Exact mode + # + #################################################################################### + # Initialize tendencies. + dtdt_adv = np.zeros([n_files+1,nlevs]) + dqvdt_adv = np.zeros([n_files+1,nlevs]) + dudt_adv = np.zeros([n_files+1,nlevs]) + dvdt_adv = np.zeros([n_files+1,nlevs]) + pres_adv = np.zeros([n_files+1,nlevs]) + pres_i_adv = np.zeros([n_files+1,nlevs+1]) + + # First timestep... + dtdtr = np.zeros([1,nlevs]) + dqdtr = np.zeros([1,nlevs]) + dudtr = np.zeros([1,nlevs]) + dvdtr = np.zeros([1,nlevs]) + # + pres_adv[0,:] = state_IC["pa"] + pres_i_adv[0,:] = state_IC["pa_i"] + dt = 3600.0*(time_hr[0]) + #dqdtr[0,:] = qv_layr[0,:] - state_IC["qv"][:] # Do we need to do this? + dqdtt = qv_lay[0,:] - state_IC["qv"][:] + dqvdt_adv[0,:] = (dqdtt - dqdtr[0,:])/dt + #dudtr[0,:] = u_layr[0,:] - state_IC["ua"][:] # Do we need to do this? + dudtt = u_lay[0,:] - state_IC["ua"][:] + dudt_adv[0,:] = (dudtt - dudtr[0,:])/dt + #dvdtr[0,:] = v_layr[0,:] - state_IC["va"][:] # Do we need to do this? + dvdtt = v_lay[0,:] - state_IC["va"][:] + dvdt_adv[0,:] = (dvdtt - dvdtr[0,:])/dt + #dtdtr[0,:] = t_layr[0,:] - state_IC["ta"][:] # Do we need to do this? + dtdtt = t_lay[0,:] - state_IC["ta"][:] + dtdt_adv[0,:] = (dtdtt - dtdtr[0,:])/dt + + # Subsequent timesteps... + dtdtr = np.zeros([n_files-1,nlevs]) + dqdtr = np.zeros([n_files-1,nlevs]) + dudtr = np.zeros([n_files-1,nlevs]) + dvdtr = np.zeros([n_files-1,nlevs]) + dtdtt = np.zeros([n_files-1,nlevs]) + dqdtt = np.zeros([n_files-1,nlevs]) + dudtt = np.zeros([n_files-1,nlevs]) + dvdtt = np.zeros([n_files-1,nlevs]) + for t in range(n_files-1): + dt = (stateNATIVE["time"][t+2] - stateNATIVE["time"][t+1])*3600. + pres_adv[t+1,:] = p_lay[t] + pres_i_adv[t+1,:] = p_lev[t] + if exact_mode: + for dyntend in dyntends: + if (dyntend["name"] == "dtend_qv_nophys"): + dqdtr[t,:] = (qv_layr[t+1,:] - qv_lay[t,:])/dt # Do we need to do this? + dqvdt_adv[t+1,:] = dyntend["values"][t,:] - dqdtr[t,:] + # end if + if (dyntend["name"] == "dtend_temp_nophys"): + dtdtr[t,:] = (t_layr[t+1,:] - t_lay[t,:])/dt # Do we need to do this? + dtdt_adv[t+1,:] = dyntend["values"][t,:] - dtdtr[t,:] + # end if + if (dyntend["name"] == "dtend_u_nophys"): + dudtr[t,:] = (u_layr[t+1,:] - u_lay[t,:])/dt # Do we need to do this? + dudt_adv[t+1,:] = dyntend["values"][t,:] - dudtr[t,:] + # endif + if (dyntend["name"] == "dtend_v_nophys"): + dvdtr[t,:] = (v_layr[t+1,:] - v_lay[t,:])/dt # Do we need to do this? + dvdt_adv[t+1,:] = dyntend["values"][t,:] - dvdtr[t,:] + # end if + # end for + else: + #dqdtr[t,:] = qv_layr[t+1,:] - qv_lay[t,:] + dqdtt = qv_lay[t+1,:] - qv_lay[t,:] + dqvdt_adv[t+1,:] = (dqdtt - dqdtr[t,:])/dt + + #dudtr[t,:] = u_layr[t+1,:] - u_lay[t,:] + dudtt = u_lay[t+1,:] - u_lay[t,:] + dudt_adv[t+1,:] = (dudtt - dudtr[t,:])/dt + + #dvdtr[t,:] = v_layr[t+1,:] - v_lay[t,:] + dvdtt = v_lay[t+1,:] - v_lay[t,:] + dvdt_adv[t+1,:] = (dvdtt - dvdtr[t,:])/dt + + #dtdtr[t,:] = t_layr[t+1,:] - t_lay[t,:] + dtdtt = t_lay[t+1,:] - t_lay[t,:] + dtdt_adv[t+1,:] = (dtdtt - dtdtr[t,:])/dt + # end if + # end for + dtdt_adv[t+2,:] = dtdt_adv[t+1,:] + dqvdt_adv[t+2,:] = dqvdt_adv[t+1,:] + dudt_adv[t+2,:] = dudt_adv[t+1,:] + dvdt_adv[t+2,:] = dvdt_adv[t+1,:] + pres_adv[t+2,:] = pres_adv[t+1,:] + pres_i_adv[t+2,:] = pres_i_adv[t+1,:] + + lev2display = 0 + + print("DJS2024: HOW WELL DO THE COMPUTATIONS MATCH THE INPUT STATE?") + if exact_mode: + print(" Using Exact mode") + else: + print(" Using Approximate mode") + # end if + + + a1 = '{0: <4} {1: >8} {2: >8} {3: >8} {4: >8} {5: >8} {6: >8} {7: >8} {8: >8} {9: >8} {10: >8} {11: >8} {12: >8} {13: >8} {14: >8} {15: >8} {16: >8} {17: >8}' + b1 = 'Time', 'q(t)', 'calc', 'q(t+1)', 'dqdt', 'u(t)', 'calc', 'u(t+1)', 'dudt', 'v(t)', 'calc', 'v(t+1)', 'dvdt', 'T(t)', 'calc', 'T(t+1)', 'dTdt', 'dt' + a2 = '{0:4.2f} {1:8.2e} {2:8.2e} {3:8.2e} {4:8.1e} {5:8.2f} {6:8.2f} {7:8.2f} {8:8.1e} {9:8.2f} {10:8.2f} {11:8.2f} {12:8.1e} {13:8.2f} {14:8.2f} {15:8.2f} {16:8.1e} {17:8.2f}' + print(a1.format('Time', 'q(t)', 'calc', 'q(t+1)', 'dqdt', 'u(t)', 'calc', 'u(t+1)', 'dudt', 'v(t)', 'calc', 'v(t+1)', 'dvdt', 'T(t)', 'calc', 'T(t+1)', 'dTdt', 'dt')) + for t in range(0,n_files): + dt = (stateNATIVE["time"][t+1] - stateNATIVE["time"][t])*3600. + print(a2.format(stateNATIVE["time"][t],stateNATIVE["qv_lay"][t,lev2display],stateNATIVE["qv_lay"][t,lev2display]+dqvdt_adv[t,lev2display]*dt,stateNATIVE["qv_lay"][t+1,lev2display],dqvdt_adv[t,lev2display], \ + stateNATIVE["u_lay"][t,lev2display],stateNATIVE["u_lay"][t,lev2display]+dudt_adv[t,lev2display]*dt,stateNATIVE["u_lay"][t+1,lev2display],dudt_adv[t,lev2display],\ + stateNATIVE["v_lay"][t,lev2display],stateNATIVE["v_lay"][t,lev2display]+dvdt_adv[t,lev2display]*dt,stateNATIVE["v_lay"][t+1,lev2display],dvdt_adv[t,lev2display],\ + stateNATIVE["t_lay"][t,lev2display],stateNATIVE["t_lay"][t,lev2display]+dtdt_adv[t,lev2display]*dt,stateNATIVE["t_lay"][t+1,lev2display],dtdt_adv[t,lev2display],dt)) #################################################################################### # @@ -2684,7 +2887,7 @@ def main(): #read in arguments (location, indices, date, in_dir, grid_dir, forcing_dir, tile, area, case_name, - old_chgres, lam, save_comp, use_nearest) = parse_arguments() + old_chgres, lam, save_comp, use_nearest, exact_mode) = parse_arguments() #find tile containing the point using the supergrid if no tile is specified #if not tile and not lam: @@ -2715,8 +2918,7 @@ def main(): (state_data, surface_data, oro_data, error_msg) = get_UFS_IC_data(in_dir, grid_dir, tile, tile_i,\ tile_j, old_chgres, lam) if (error_msg): - print(error_msg) - print("STOPPING") + print("ERROR: unknown grid orintation") exit() if not date: @@ -2735,7 +2937,7 @@ def main(): (forcing_data, comp_data, stateREGRID) = get_UFS_forcing_data(state_data["nlevs"], state_data, \ location, use_nearest, forcing_dir, \ grid_dir, tile, tile_i, tile_j, lam,\ - save_comp) + save_comp, exact_mode) # Write SCM case file fileOUT = write_SCM_case_file(state_data, surface_data, oro_data, forcing_data, case_name, date, \ diff --git a/scm/etc/scripts/UFS_forcing_ensemble_generator.py b/scm/etc/scripts/UFS_forcing_ensemble_generator.py index c4a533127..abb19dac2 100755 --- a/scm/etc/scripts/UFS_forcing_ensemble_generator.py +++ b/scm/etc/scripts/UFS_forcing_ensemble_generator.py @@ -27,6 +27,7 @@ parser.add_argument('-sdf', '--suite', help='CCPP suite definition file to use for ensemble', default = 'SCM_GFS_v16') parser.add_argument('-sc', '--save_comp', help='flag to save a file with UFS data for comparisons', action='store_true') parser.add_argument('-near', '--use_nearest', help='flag to indicate using the nearest UFS history file gridpoint, no regridding',action='store_true') +parser.add_argument('-ext', '--exact_mode', help='flag to indicate using dynamic tendencies from UFS history files', action='store_true') ############################################################################### # Main program @@ -138,6 +139,7 @@ def main(): com_config = '' if args.save_comp: com_config = com_config + ' -sc' if args.use_nearest: com_config = com_config + ' -near' + if args.exact_mode: com_config = com_config + ' -ext' # Create inputs to SCM case_list = "" From 50cb4a3672652ce3b1de2ff793a501b117505133 Mon Sep 17 00:00:00 2001 From: Dustin Swales Date: Tue, 14 May 2024 17:35:23 +0000 Subject: [PATCH 02/25] Working --- scm/etc/scripts/UFS_IC_generator.py | 525 ++++++++---------- .../scripts/UFS_forcing_ensemble_generator.py | 10 +- 2 files changed, 249 insertions(+), 286 deletions(-) diff --git a/scm/etc/scripts/UFS_IC_generator.py b/scm/etc/scripts/UFS_IC_generator.py index 0e2d12039..cb74197ee 100755 --- a/scm/etc/scripts/UFS_IC_generator.py +++ b/scm/etc/scripts/UFS_IC_generator.py @@ -66,9 +66,10 @@ parser.add_argument('-a', '--area', help='area of grid cell in m^2', type=float) parser.add_argument('-oc', '--old_chgres', help='flag to denote that the initial conditions use an older data format (pre-chgres_cube)', action='store_true') parser.add_argument('-lam', '--lam', help='flag to signal that the ICs and forcing is from a limited-area model run', action='store_true') -parser.add_argument('-sc', '--save_comp', help='flag to create UFS reference file for comparison', action='store_true') -parser.add_argument('-near','--use_nearest', help='flag to indicate using the nearest UFS history file gridpoint',action='store_true') -parser.add_argument('-ext', '--exact_mode', help='flag to indicate using dynamic tendencies from UFS history files', action='store_true') +parser.add_argument('-sc', '--save_comp', help='flag to create UFS reference file for comparison', action='store_true') +parser.add_argument('-near','--use_nearest', help='flag to indicate using the nearest UFS history file gridpoint', action='store_true') +parser.add_argument('-ext', '--exact_mode', help='flag to indicate using dynamic tendencies from UFS history files', action='store_true') +parser.add_argument('-tott','--total_tend', help='flag to indicate forcing to derive', action='store_true') ######################################################################################## # @@ -90,6 +91,7 @@ def parse_arguments(): save_comp = args.save_comp use_nearest = args.use_nearest exact_mode = args.exact_mode + total_tend = args.total_tend #validate args if not os.path.exists(in_dir): @@ -129,7 +131,7 @@ def parse_arguments(): raise Exception(message) return (location, index, date_dict, in_dir, grid_dir, forcing_dir, tile, \ - area, case_name, old_chgres, lam, save_comp, use_nearest, exact_mode) + area, case_name, old_chgres, lam, save_comp, use_nearest, exact_mode, total_tend) ######################################################################################## # @@ -1494,7 +1496,7 @@ def search_in_dict(listin,name): # ######################################################################################## def get_UFS_forcing_data(nlevs, state_IC, location, use_nearest, forcing_dir, grid_dir, - tile, i, j, lam, save_comp_data, exact_mode): + tile, i, j, lam, save_comp_data, exact_mode, cmp_total_tendency): """Get the horizontal and vertical advective tendencies for the given tile and indices""" # Determine UFS history file format (tiled/quilted) @@ -1638,7 +1640,7 @@ def get_UFS_forcing_data(nlevs, state_IC, location, use_nearest, forcing_dir, gr v_data = nc_file['vgrd'][0,::-1,:,:] j_get = tile_jj i_get = tile_ii - # end if + # end if (use-nearest) # Store surface pressure. ps.append(ps_data[j_get,i_get]) @@ -1701,9 +1703,11 @@ def get_UFS_forcing_data(nlevs, state_IC, location, use_nearest, forcing_dir, gr # #################################################################################### - # Variable sneeded for "exact" UFS case generation. - dyntends = [{"name":"dtend_temp_nophys"}, {"name":"dtend_u_nophys"}, \ - {"name":"dtend_v_nophys"}, {"name":"dtend_qv_nophys"}] + # Variables needed for "exact" UFS case generation. + dyntends = [{"name":"dtend_temp_nophys", "diag_table":'"gfs_dyn", "dtend_temp_nophys", "dtend_temp_nophys", "fv3_history", "all", .false., "none", 2'},\ + {"name":"dtend_u_nophys", "diag_table":'"gfs_dyn", "dtend_u_nophys", "dtend_u_nophys", "fv3_history", "all", .false., "none", 2'},\ + {"name":"dtend_v_nophys", "diag_table":'"gfs_dyn", "dtend_v_nophys", "dtend_v_nophys", "fv3_history", "all", .false., "none", 2'},\ + {"name":"dtend_qv_nophys", "diag_table":'"gfs_dyn", "dtend_qv_nophys", "dtend_qv_nophys", "fv3_history", "all", .false., "none", 2'}] for dyntend in dyntends: dyntend["values"] = [] # Variables to be added to "UFS comparison file" @@ -1769,72 +1773,80 @@ def get_UFS_forcing_data(nlevs, state_IC, location, use_nearest, forcing_dir, gr var2d["units"] = nc_file[var2d["name"]].getncattr(name="units") var2d["long_name"] = nc_file[var2d["name"]].getncattr(name="long_name") # end for - for dyntend in dyntends: - try: + if dyntend["name"] in nc_file.variables.keys(): if not use_nearest: data = regridder(nc_file[dyntend["name"]][0,::-1,:,:]) else: data = nc_file[dyntend["name"]][0,::-1,:,:] - # end if + # end if (use-nearest) dyntend["values"].append(data[:,j_get,i_get]) dyntend["units"] = nc_file[dyntend["name"]].getncattr(name="units") dyntend["long_name"] = nc_file[dyntend["name"]].getncattr(name="long_name") - except: - print("Could not find ",dyntend["name"]," in ",nc_file) - # end try + dyntend["missing"] = False + else: + dyntend["missing"] = True + # end if # end for - nc_file.close() # end for - + + # Handle the case that "exact-mode" was requested, but the UFS history files do not contains + # the necessary fields. + # In this scenario, create warning/message that informs the users how to rerun the UFS with + # the correct configuration. + # Revert to "approximate-mode" + if exact_mode: + missing_dtend_names = [] + missing_diag_tables = [] + for dyntend in dyntends: + if dyntend["missing"]: + missing_dtend_names.append(dyntend["name"]) + missing_diag_tables.append(dyntend["diag_table"]) + exact_mode = False + # end if + # end for + if missing_dtend_names: + print("#"*128) + print("#"*59,"WARNING","#"*60) + print("#"*128) + print("Could not find the following fields required for ",'"exact-mode"',':') + for missing_dtend_name in missing_dtend_names: + print(" -",missing_dtend_name) + # end for + print("Using ",'"approximate mode"',' instead') + print("") + print(" *NOTE*") + print(" You selected to create the UFS case using ",'"exact-mode"'," which requires additional (diagnostic)") + print(" fields in the UFS history files.") + print("") + print(" These optional diagnostics tendencies can be output from any UFS forecast by:") + print(" a) Modifying the physics namelist, gfs_phys_nml, so that:") + print(" *) ldiag3d = .true. ") + print(" *) qdiag3d = .true. ") + print(" b) Addding the following lines to the UFS diag_table:") + for missing_diag_table in missing_diag_tables: + print(' *) ',missing_diag_table ) + # end for + print("") + print("#"*128) + print("#"*128) + # end if + # end if (exact-mode) + # Convert to numpy arrays for var2d in vars2d: var2d["values"] = np.asarray(var2d["values"]) # end for - for dyntend in dyntends: - dyntend["values"] = np.asarray(dyntend["values"]) - # end for - - #################################################################################### - # - # Create dictionary with full "Native" state (IC@t=0,ATMF*@t>0) - # - #################################################################################### - ps_IC = np.zeros([1]) - ps_IC[0] = state_IC["ps"] - pi_IC = np.zeros([1,nlevs+1]) - pi_IC[0,:] = state_IC["pa_i"] - p_IC = np.zeros([1,nlevs]) - p_IC[0,:] = state_IC["pa"] - t_IC = np.zeros([1,nlevs]) - t_IC[0,:] = state_IC["ta"] - qv_IC = np.zeros([1,nlevs]) - qv_IC[0,:] = state_IC["qv"] - u_IC = np.zeros([1,nlevs]) - u_IC[0,:] = state_IC["ua"] - v_IC = np.zeros([1,nlevs]) - v_IC[0,:] = state_IC["va"] - tv_IC = t_IC*(1.0 + zvir*qv_IC) - stateNATIVE = {"time": np.concatenate((np.asarray([0.]), time_hr[:])), \ - "ps": np.concatenate((ps_IC, ps), axis=0), \ - "p_lev": np.concatenate((pi_IC, p_lev), axis=0), \ - "p_lay": np.concatenate((p_IC, p_lay), axis=0), \ - "t_lay": np.concatenate((t_IC, t_lay), axis=0), \ - "qv_lay": np.concatenate((qv_IC, qv_lay), axis=0), \ - "u_lay": np.concatenate((u_IC, u_lay), axis=0), \ - "v_lay": np.concatenate((v_IC, v_lay), axis=0), \ - "tv_lay": np.concatenate((tv_IC, tv_lay), axis=0)} - - print("DJS2024: WHAT DOES THE NATIVE STATE LOOK LIKE, at the surface?") - print('{0: <4} {1: >8} {2: >8} {3: >8} {4: >8} {5: >6} {6: >6} {7: >6} {8: >8}'. - format('Time','sfcP','pi','p','t','qv','u','v','tv')) - for ij in range(0,len(stateNATIVE["time"])): - print('{0:4d} {1:8.2f} {2:8.2f} {3:8.2f} {4:8.2f} {5:6.2f} {6:6.2f} {7:6.2f} {8:8.2f}'. - format(int(stateNATIVE["time"][ij]),stateNATIVE["ps"][ij]*0.01,stateNATIVE["p_lev"][ij,0]*0.01,\ - stateNATIVE["p_lay"][ij,0]*0.01,stateNATIVE["t_lay"][ij,0],stateNATIVE["qv_lay"][ij,0]*100.,\ - stateNATIVE["u_lay"][ij,0],stateNATIVE["v_lay"][ij,0],stateNATIVE["tv_lay"][ij,0])) - # end for + if exact_mode: + for dyntend in dyntends: + dyntend["values"] = np.asarray(dyntend["values"]) + # end for + dtend_temp_nophys = dyntends[0]["values"] + dtend_u_nophys = dyntends[1]["values"] + dtend_v_nophys = dyntends[2]["values"] + dtend_qv_nophys = dyntends[3]["values"] + # end if (exact-mode) #################################################################################### # @@ -1859,7 +1871,7 @@ def get_UFS_forcing_data(nlevs, state_IC, location, use_nearest, forcing_dir, gr #################################################################################### # Initialize -# nlevs = len(p_lay[0,:]) + #nlevs = len(p_lay[0,:]) dummy = np.zeros(1) from_p = np.zeros([1,nlevs+1]) to_p = np.zeros([1,nlevs+1]) @@ -1879,6 +1891,7 @@ def get_UFS_forcing_data(nlevs, state_IC, location, use_nearest, forcing_dir, gr # # First timestep... + # (Same for Exact-mode or Approximate mode) # # Interpolation range @@ -1893,7 +1906,7 @@ def get_UFS_forcing_data(nlevs, state_IC, location, use_nearest, forcing_dir, gr tv_rev_new = fv3_remap.map_scalar(nlevs, log_from_p, tv_init_rev[np.newaxis, :], \ dummy, nlevs, log_to_p, 0, 0, 1, \ np.abs(kord_tm), t_min) - + # IC Specific humidity on vertical-grid of first UFS history file. qv_init_rev = state_IC["qv"][::-1] for k in range(0,nlevs): dp2[0,k] = from_p[0,k+1] - from_p[0,k] @@ -1918,125 +1931,63 @@ def get_UFS_forcing_data(nlevs, state_IC, location, use_nearest, forcing_dir, gr tv_layr[0,:] = tv_rev_new[0,::-1] qv_layr[0,:] = qv_rev_new[0,::-1] - # - # Subsequent timestep(s)... - # (current state on vertical grid of subsequent time-step(s). Used for differencing) - # - for t in range(n_files-1): - # Interpolation range - from_p[0,:] = p_lev[t,::-1] - to_p[0,:] = p_lev[t+1,::-1] - log_from_p[0,:] = np.log(p_lev[t,::-1]) - log_to_p[0,:] = np.log(p_lev[t+1,::-1]) - - # Virtual Temperature @ time > 0 - tv_rev[0,:] = tv_lay[t,::-1] - tv_rev_new = fv3_remap.map_scalar(nlevs, log_from_p, tv_rev, dummy, nlevs, \ - log_to_p, 0, 0, 1, np.abs(kord_tm), t_min) - # Specific humidity @ time > 0 - qv_rev[0,:] = qv_lay[t,::-1] - for k in range(0,nlevs): dp2[0,k] = to_p[0,k+1] - to_p[0,k] - qv_rev_new = fv3_remap.map1_q2(nlevs, from_p, qv_rev, nlevs, to_p, dp2, \ - 0, 0, 0, kord_tr, q_min) - # Zonal wind @ time > 0 - u_rev[0,:] = u_lay[t,::-1] - u_rev_new = fv3_remap.map1_ppm(nlevs, from_p, u_rev, 0.0, nlevs, to_p, \ - 0, 0, -1, kord_tm ) - # Meridional wind @ time > 0 - v_rev[0,:] = v_lay[t,::-1] - v_rev_new = fv3_remap.map1_ppm(nlevs, from_p, v_rev, 0.0, nlevs, to_p, \ - 0, 0, -1, kord_tm ) - # Store - p_layr[t+1,:] = p_lay[t+1,:] - p_levr[t+1,:] = p_lev[t+1,:] - tv_layr[t+1,:] = tv_rev_new[0,::-1] - qv_layr[t+1,:] = qv_rev_new[0,::-1] - u_layr[t+1,:] = u_rev_new[0,::-1] - v_layr[t+1,:] = v_rev_new[0,::-1] - # end for + # Subsequent timestep(s). (exact-mode only) + if exact_mode: + for t in range(n_files-1): + # Interpolation range + from_p[0,:] = p_lev[t,::-1] + to_p[0,:] = p_lev[t+1,::-1] + log_from_p[0,:] = np.log(p_lev[t,::-1]) + log_to_p[0,:] = np.log(p_lev[t+1,::-1]) + + # Virtual Temperature @ time > 0 + tv_rev[0,:] = tv_lay[t,::-1] + tv_rev_new = fv3_remap.map_scalar(nlevs, log_from_p, tv_rev, dummy, nlevs, \ + log_to_p, 0, 0, 1, np.abs(kord_tm), t_min) + # Specific humidity @ time > 0 + qv_rev[0,:] = qv_lay[t,::-1] + for k in range(0,nlevs): dp2[0,k] = to_p[0,k+1] - to_p[0,k] + qv_rev_new = fv3_remap.map1_q2(nlevs, from_p, qv_rev, nlevs, to_p, dp2, \ + 0, 0, 0, kord_tr, q_min) + # Zonal wind @ time > 0 + u_rev[0,:] = u_lay[t,::-1] + u_rev_new = fv3_remap.map1_ppm(nlevs, from_p, u_rev, 0.0, nlevs, to_p, \ + 0, 0, -1, kord_tm ) + # Meridional wind @ time > 0 + v_rev[0,:] = v_lay[t,::-1] + v_rev_new = fv3_remap.map1_ppm(nlevs, from_p, v_rev, 0.0, nlevs, to_p, \ + 0, 0, -1, kord_tm ) + # Store + p_layr[t+1,:] = p_lay[t+1,:] + p_levr[t+1,:] = p_lev[t+1,:] + tv_layr[t+1,:] = tv_rev_new[0,::-1] + qv_layr[t+1,:] = qv_rev_new[0,::-1] + u_layr[t+1,:] = u_rev_new[0,::-1] + v_layr[t+1,:] = v_rev_new[0,::-1] + # end for + + # + p_layr[t+2,:] = p_layr[t+1,:] + p_levr[t+2,:] = p_levr[t+1,:] + tv_layr[t+2,:] = tv_layr[t+1,:] + qv_layr[t+2,:] = qv_layr[t+1,:] + u_layr[t+2,:] = u_layr[t+1,:] + v_layr[t+2,:] = v_layr[t+1,:] + # end if (exact-mode) - # - p_layr[t+2,:] = p_layr[t+1,:] - p_levr[t+2,:] = p_levr[t+1,:] - tv_layr[t+2,:] = tv_layr[t+1,:] - qv_layr[t+2,:] = qv_layr[t+1,:] - u_layr[t+2,:] = u_layr[t+1,:] - v_layr[t+2,:] = v_layr[t+1,:] - # Temperature t_layr = tv_layr/(1.0 + zvir*qv_layr) - # Create dictionary with "Regridded" state - stateREGRID = {"time": np.concatenate((np.asarray([0.]), time_hr[:])), \ - "ps": np.concatenate((ps[0:1], ps), axis=0), \ - "p_lev": p_levr, \ - "p_lay": p_layr, \ - "t_lay": t_layr, \ - "qv_lay": qv_layr, \ - "u_lay": u_layr, \ - "v_lay": v_layr, \ - "tv_lay": tv_layr } - print("DJS2024: WHAT DOES THE REGRIDDED STATE LOOK LIKE, at the surface?") - print('{0: <4} {1: >8} {2: >8} {3: >8} {4: >8} {5: >6} {6: >6} {7: >6} {8: >8}'. - format('Time','sfcP','pi','p','t','qv','u','v','tv')) - for ij in range(0,len(stateREGRID["time"])): - print('{0:4d} {1:8.2f} {2:8.2f} {3:8.2f} {4:8.2f} {5:6.2f} {6:6.2f} {7:6.2f} {8:8.2f}'. - format(int(stateREGRID["time"][ij]),stateREGRID["ps"][ij]*0.01,stateREGRID["p_lev"][ij,0]*0.01,\ - stateREGRID["p_lay"][ij,0]*0.01,stateREGRID["t_lay"][ij,0],stateREGRID["qv_lay"][ij,0]*100.,\ - stateREGRID["u_lay"][ij,0],stateREGRID["v_lay"][ij,0],stateREGRID["tv_lay"][ij,0])) - # end for + # Save regridded initial state. + stateInit = {"p_lay": p_lay[0,:], \ + "t_lay": t_lay[0,:], \ + "qv_lay": qv_lay[0,:], \ + "u_lay": u_lay[0,:], \ + "v_lay": v_lay[0,:]} #################################################################################### # - # Compute tendencies advective = total - remapping - # - #################################################################################### - - # - dtdt_adv = np.zeros([n_files+1,nlevs]) - dqvdt_adv = np.zeros([n_files+1,nlevs]) - dudt_adv = np.zeros([n_files+1,nlevs]) - dvdt_adv = np.zeros([n_files+1,nlevs]) - pres_adv = np.zeros([n_files+1,nlevs]) - pres_i_adv = np.zeros([n_files+1,nlevs+1]) - tend_remap = np.zeros([1,nlevs]) - tend_total = np.zeros([1,nlevs]) - - # - for t in range(n_files): - # - dtime_sec = (stateNATIVE["time"][t+1] - stateNATIVE["time"][t])*sec_in_hr - # - pres_adv[t,:] = stateNATIVE["p_lay"][t,:] - pres_i_adv[t,:] = stateNATIVE["p_lev"][t,:] - # - tend_total[0,:] = stateREGRID["t_lay"][t+1,:] - stateREGRID["t_lay"][t,:] - tend_remap[0,:] = stateREGRID["t_lay"][t,:] - stateNATIVE["t_lay"][t,:] - dtdt_adv[t,:] = (tend_total[0,:] - tend_remap[0,:]) / dtime_sec - - tend_total[0,:] = stateREGRID["qv_lay"][t+1,:] - stateREGRID["qv_lay"][t,:] - tend_remap[0,:] = stateREGRID["qv_lay"][t,:] - stateNATIVE["qv_lay"][t,:] - dqvdt_adv[t,:] = (tend_total[0,:] - tend_remap[0,:]) / dtime_sec - - tend_total[0,:] = stateREGRID["u_lay"][t+1,:] - stateREGRID["u_lay"][t,:] - tend_remap[0,:] = stateREGRID["u_lay"][t,:] - stateNATIVE["u_lay"][t,:] - dudt_adv[t,:] = (tend_total[0,:] - tend_remap[0,:]) / dtime_sec - - tend_total[0,:] = stateREGRID["v_lay"][t+1,:] - stateREGRID["v_lay"][t,:] - tend_remap[0,:] = stateREGRID["v_lay"][t,:] - stateNATIVE["v_lay"][t,:] - dvdt_adv[t,:] = (tend_total[0,:] - tend_remap[0,:]) / dtime_sec - - # - dtdt_adv[t+1,:] = dtdt_adv[t,:] - dqvdt_adv[t+1,:] = dqvdt_adv[t,:] - dudt_adv[t+1,:] = dudt_adv[t,:] - dvdt_adv[t+1,:] = dvdt_adv[t,:] - pres_adv[t+1,:] = pres_adv[t,:] - pres_i_adv[t+1,:] = pres_i_adv[t,:] - - #################################################################################### - # - # Exact mode + # Compute forcing. # #################################################################################### # Initialize tendencies. @@ -2046,30 +1997,37 @@ def get_UFS_forcing_data(nlevs, state_IC, location, use_nearest, forcing_dir, gr dvdt_adv = np.zeros([n_files+1,nlevs]) pres_adv = np.zeros([n_files+1,nlevs]) pres_i_adv = np.zeros([n_files+1,nlevs+1]) + dtdtr = np.zeros([1,nlevs]) + dqdtr = np.zeros([1,nlevs]) + dudtr = np.zeros([1,nlevs]) + dvdtr = np.zeros([1,nlevs]) - # First timestep... - dtdtr = np.zeros([1,nlevs]) - dqdtr = np.zeros([1,nlevs]) - dudtr = np.zeros([1,nlevs]) - dvdtr = np.zeros([1,nlevs]) - # + # First timestep. pres_adv[0,:] = state_IC["pa"] pres_i_adv[0,:] = state_IC["pa_i"] - dt = 3600.0*(time_hr[0]) - #dqdtr[0,:] = qv_layr[0,:] - state_IC["qv"][:] # Do we need to do this? - dqdtt = qv_lay[0,:] - state_IC["qv"][:] - dqvdt_adv[0,:] = (dqdtt - dqdtr[0,:])/dt - #dudtr[0,:] = u_layr[0,:] - state_IC["ua"][:] # Do we need to do this? - dudtt = u_lay[0,:] - state_IC["ua"][:] - dudt_adv[0,:] = (dudtt - dudtr[0,:])/dt - #dvdtr[0,:] = v_layr[0,:] - state_IC["va"][:] # Do we need to do this? - dvdtt = v_lay[0,:] - state_IC["va"][:] - dvdt_adv[0,:] = (dvdtt - dvdtr[0,:])/dt - #dtdtr[0,:] = t_layr[0,:] - state_IC["ta"][:] # Do we need to do this? - dtdtt = t_lay[0,:] - state_IC["ta"][:] - dtdt_adv[0,:] = (dtdtt - dtdtr[0,:])/dt - - # Subsequent timesteps... + dt = 3600.0*(time_hr[0]) + if exact_mode: + dqdtr[0,:] = (qv_layr[0,:] - state_IC["qv"][:])/dt + dqvdt_adv[0,:] = dtend_qv_nophys[0,:] - dqdtr[0,:] + dudtr[0,:] = (u_layr[0,:] - state_IC["ua"][:])/dt + dudt_adv[0,:] = (dtend_u_nophys[0,:] - dudtr[0,:]) + dvdtr[0,:] = (v_layr[0,:] - state_IC["va"][:])/dt + dvdt_adv[0,:] = (dtend_v_nophys[0,:] - dvdtr[0,:]) + dtdtr[0,:] = (t_layr[0,:] - state_IC["ta"][:])/dt + dtdt_adv[0,:] = (dtend_temp_nophys[0,:] - dtdtr[0,:]) + elif cmp_total_tendency: + print("DJS ASKS GF: Is this where you will compute something like? dqvdt_tot = dqdtt/dt + u*dudx/dt + v*dvdy/dt") + else: + dqdtt = qv_lay[0,:] - state_IC["qv"][:] + dqvdt_adv[0,:] = dqdtt/dt + dudtt = u_lay[0,:] - state_IC["ua"][:] + dudt_adv[0,:] = dudtt/dt + dvdtt = v_lay[0,:] - state_IC["va"][:] + dvdt_adv[0,:] = dvdtt/dt + dtdtt = t_lay[0,:] - state_IC["ta"][:] + dtdt_adv[0,:] = dtdtt/dt + + # Subsequent timestep(s). dtdtr = np.zeros([n_files-1,nlevs]) dqdtr = np.zeros([n_files-1,nlevs]) dudtr = np.zeros([n_files-1,nlevs]) @@ -2079,46 +2037,31 @@ def get_UFS_forcing_data(nlevs, state_IC, location, use_nearest, forcing_dir, gr dudtt = np.zeros([n_files-1,nlevs]) dvdtt = np.zeros([n_files-1,nlevs]) for t in range(n_files-1): - dt = (stateNATIVE["time"][t+2] - stateNATIVE["time"][t+1])*3600. + dt = (time_hr[t+1] - time_hr[t])*3600. pres_adv[t+1,:] = p_lay[t] pres_i_adv[t+1,:] = p_lev[t] if exact_mode: - for dyntend in dyntends: - if (dyntend["name"] == "dtend_qv_nophys"): - dqdtr[t,:] = (qv_layr[t+1,:] - qv_lay[t,:])/dt # Do we need to do this? - dqvdt_adv[t+1,:] = dyntend["values"][t,:] - dqdtr[t,:] - # end if - if (dyntend["name"] == "dtend_temp_nophys"): - dtdtr[t,:] = (t_layr[t+1,:] - t_lay[t,:])/dt # Do we need to do this? - dtdt_adv[t+1,:] = dyntend["values"][t,:] - dtdtr[t,:] - # end if - if (dyntend["name"] == "dtend_u_nophys"): - dudtr[t,:] = (u_layr[t+1,:] - u_lay[t,:])/dt # Do we need to do this? - dudt_adv[t+1,:] = dyntend["values"][t,:] - dudtr[t,:] - # endif - if (dyntend["name"] == "dtend_v_nophys"): - dvdtr[t,:] = (v_layr[t+1,:] - v_lay[t,:])/dt # Do we need to do this? - dvdt_adv[t+1,:] = dyntend["values"][t,:] - dvdtr[t,:] - # end if - # end for + dqdtr[t,:] = (qv_layr[t+1,:] - qv_lay[t,:])/dt + dqvdt_adv[t+1,:] = dtend_qv_nophys[t+1,:] - dqdtr[t,:] + dtdtr[t,:] = (t_layr[t+1,:] - t_lay[t,:])/dt + dtdt_adv[t+1,:] = dtend_temp_nophys[t+1,:] - dtdtr[t,:] + dudtr[t,:] = (u_layr[t+1,:] - u_lay[t,:])/dt + dudt_adv[t+1,:] = dtend_u_nophys[t+1,:] - dudtr[t,:] + dvdtr[t,:] = (v_layr[t+1,:] - v_lay[t,:])/dt + dvdt_adv[t+1,:] = dtend_v_nophys[t+1,:] - dvdtr[t,:] else: - #dqdtr[t,:] = qv_layr[t+1,:] - qv_lay[t,:] - dqdtt = qv_lay[t+1,:] - qv_lay[t,:] + dqdtt = qv_lay[t+1,:] - qv_lay[t,:] dqvdt_adv[t+1,:] = (dqdtt - dqdtr[t,:])/dt - - #dudtr[t,:] = u_layr[t+1,:] - u_lay[t,:] - dudtt = u_lay[t+1,:] - u_lay[t,:] - dudt_adv[t+1,:] = (dudtt - dudtr[t,:])/dt - - #dvdtr[t,:] = v_layr[t+1,:] - v_lay[t,:] - dvdtt = v_lay[t+1,:] - v_lay[t,:] - dvdt_adv[t+1,:] = (dvdtt - dvdtr[t,:])/dt - - #dtdtr[t,:] = t_layr[t+1,:] - t_lay[t,:] - dtdtt = t_lay[t+1,:] - t_lay[t,:] - dtdt_adv[t+1,:] = (dtdtt - dtdtr[t,:])/dt - # end if - # end for + dudtt = u_lay[t+1,:] - u_lay[t,:] + dudt_adv[t+1,:] = (dudtt - dudtr[t,:])/dt + dvdtt = v_lay[t+1,:] - v_lay[t,:] + dvdt_adv[t+1,:] = (dvdtt - dvdtr[t,:])/dt + dtdtt = t_lay[t+1,:] - t_lay[t,:] + dtdt_adv[t+1,:] = (dtdtt - dtdtr[t,:])/dt + # end if (exact-mode) + # end for (ufs history files) + + # Last timestep. dtdt_adv[t+2,:] = dtdt_adv[t+1,:] dqvdt_adv[t+2,:] = dqvdt_adv[t+1,:] dudt_adv[t+2,:] = dudt_adv[t+1,:] @@ -2126,26 +2069,50 @@ def get_UFS_forcing_data(nlevs, state_IC, location, use_nearest, forcing_dir, gr pres_adv[t+2,:] = pres_adv[t+1,:] pres_i_adv[t+2,:] = pres_i_adv[t+1,:] - lev2display = 0 - - print("DJS2024: HOW WELL DO THE COMPUTATIONS MATCH THE INPUT STATE?") - if exact_mode: - print(" Using Exact mode") - else: - print(" Using Approximate mode") - # end if - - - a1 = '{0: <4} {1: >8} {2: >8} {3: >8} {4: >8} {5: >8} {6: >8} {7: >8} {8: >8} {9: >8} {10: >8} {11: >8} {12: >8} {13: >8} {14: >8} {15: >8} {16: >8} {17: >8}' - b1 = 'Time', 'q(t)', 'calc', 'q(t+1)', 'dqdt', 'u(t)', 'calc', 'u(t+1)', 'dudt', 'v(t)', 'calc', 'v(t+1)', 'dvdt', 'T(t)', 'calc', 'T(t+1)', 'dTdt', 'dt' - a2 = '{0:4.2f} {1:8.2e} {2:8.2e} {3:8.2e} {4:8.1e} {5:8.2f} {6:8.2f} {7:8.2f} {8:8.1e} {9:8.2f} {10:8.2f} {11:8.2f} {12:8.1e} {13:8.2f} {14:8.2f} {15:8.2f} {16:8.1e} {17:8.2f}' - print(a1.format('Time', 'q(t)', 'calc', 'q(t+1)', 'dqdt', 'u(t)', 'calc', 'u(t+1)', 'dudt', 'v(t)', 'calc', 'v(t+1)', 'dvdt', 'T(t)', 'calc', 'T(t+1)', 'dTdt', 'dt')) - for t in range(0,n_files): - dt = (stateNATIVE["time"][t+1] - stateNATIVE["time"][t])*3600. - print(a2.format(stateNATIVE["time"][t],stateNATIVE["qv_lay"][t,lev2display],stateNATIVE["qv_lay"][t,lev2display]+dqvdt_adv[t,lev2display]*dt,stateNATIVE["qv_lay"][t+1,lev2display],dqvdt_adv[t,lev2display], \ - stateNATIVE["u_lay"][t,lev2display],stateNATIVE["u_lay"][t,lev2display]+dudt_adv[t,lev2display]*dt,stateNATIVE["u_lay"][t+1,lev2display],dudt_adv[t,lev2display],\ - stateNATIVE["v_lay"][t,lev2display],stateNATIVE["v_lay"][t,lev2display]+dvdt_adv[t,lev2display]*dt,stateNATIVE["v_lay"][t+1,lev2display],dvdt_adv[t,lev2display],\ - stateNATIVE["t_lay"][t,lev2display],stateNATIVE["t_lay"][t,lev2display]+dtdt_adv[t,lev2display]*dt,stateNATIVE["t_lay"][t+1,lev2display],dtdt_adv[t,lev2display],dt)) + #################################################################################### + # Save UFS data for comparison with SCM output. + #################################################################################### + if (save_comp_data): + # Initialize + t_layers_at_pres1_rev = np.zeros([t_lay.shape[0],1,t_lay.shape[1]]) + qv_layers_at_pres1_rev = np.zeros([qv_lay.shape[0],1,qv_lay.shape[1]]) + u_layers_at_pres1_rev = np.zeros([u_lay.shape[0],1,u_lay.shape[1]]) + v_layers_at_pres1_rev = np.zeros([v_lay.shape[0],1,u_lay.shape[1]]) + p_layers_at_pres1_rev = np.zeros([v_lay.shape[0],1,u_lay.shape[1]]) + from_log_pres_rev = np.zeros([1,p_lev.shape[1]]) + to_log_pres_rev = np.zeros([1,p_lev.shape[1]]) + from_pres_rev = np.zeros([1,p_lev.shape[1]]) + to_pres_rev = np.zeros([1,p_lev.shape[1]]) + dp2 = np.zeros([1,qv_lay.shape[1]]) + + # First timestep... + t_layers_at_pres1_rev[0,0,:] = t_lay[0,::-1] + qv_layers_at_pres1_rev[0,0,:] = qv_lay[0,::-1] + u_layers_at_pres1_rev[0,0,:] = u_lay[0,::-1] + v_layers_at_pres1_rev[0,0,:] = v_lay[0,::-1] + p_layers_at_pres1_rev[0,0,:] = p_lay[0,::-1] + + # Subsequent timestpes... + for t in range(1,t_lay.shape[0]): + from_log_pres_rev[0,:] = np.log(p_lev[t,::-1]) + to_log_pres_rev[0,:] = np.log(p_lev[0,::-1]) + from_pres_rev[0,:] = p_lev[t,::-1] + to_pres_rev[0,:] = p_lev[0,::-1] + for k in range(0,qv_lay.shape[1]): + dp2[0,k] = to_pres_rev[0,k+1] - to_pres_rev[0,k] + # end for + t_layers_at_pres1_rev[t,:,:] = fv3_remap.map_scalar(p_lay.shape[1], from_log_pres_rev, t_lay[t,np.newaxis,::-1], dummy, p_lay.shape[1], to_log_pres_rev, 0, 0, 1, np.abs(kord_tm), t_min) + qv_layers_at_pres1_rev[t,:,:] = fv3_remap.map1_q2(p_lay.shape[1], from_pres_rev, qv_lay[t,np.newaxis,::-1], p_lay.shape[1], to_pres_rev, dp2, 0, 0, 0, kord_tr, q_min) + u_layers_at_pres1_rev[t,:,:] = fv3_remap.map1_ppm(p_lay.shape[1], from_pres_rev, u_lay[t,np.newaxis,::-1], 0.0, p_lay.shape[1], to_pres_rev, 0, 0, -1, kord_tm) + v_layers_at_pres1_rev[t,:,:] = fv3_remap.map1_ppm(p_lay.shape[1], from_pres_rev, v_lay[t,np.newaxis,::-1], 0.0, p_lay.shape[1], to_pres_rev, 0, 0, -1, kord_tm) + p_layers_at_pres1_rev[t,:,:] = p_lay[0,::-1] + # end for + t_layers_at_pres1 = t_layers_at_pres1_rev[:,0,::-1] + qv_layers_at_pres1 = qv_layers_at_pres1_rev[:,0,::-1] + u_layers_at_pres1 = u_layers_at_pres1_rev[:,0,::-1] + v_layers_at_pres1 = v_layers_at_pres1_rev[:,0,::-1] + p_layers_at_pres1 = p_layers_at_pres1_rev[:,0,::-1] + # end if (save_comp_data) #################################################################################### # @@ -2161,8 +2128,8 @@ def get_UFS_forcing_data(nlevs, state_IC, location, use_nearest, forcing_dir, gr # step) # #################################################################################### - time_method = 'constant_simple' #this is not implemented in the SCM code yet - #time_method = 'constant_interp' + #time_method = 'constant_simple' #this is not implemented in the SCM code yet + time_method = 'constant_interp' #time_method = 'gradient' #this produced wonky results in the SCM; avoid until investigated more if (time_method == 'constant_simple'): @@ -2192,6 +2159,7 @@ def get_UFS_forcing_data(nlevs, state_IC, location, use_nearest, forcing_dir, gr tot_advec_qv[:,t] = dqvdt_adv[t,:] tot_advec_u[:,t] = dudt_adv[t,:] tot_advec_v[:,t] = dvdt_adv[t,:] + # end for elif (time_method == 'constant_interp'): print('Forcing can be interpolated in time, but the time values are chosen such that forcing will effectively be held consant during a diagnostic time interval.') ntimes = 2*n_files @@ -2236,15 +2204,7 @@ def get_UFS_forcing_data(nlevs, state_IC, location, use_nearest, forcing_dir, gr tot_advec_u[:,2*t+1] = tot_advec_u[:,2*t] tot_advec_v[:,2*t] = dvdt_adv[t,:] tot_advec_v[:,2*t+1] = tot_advec_v[:,2*t] - # - #p_s[2*t-1] = 0.5*(p_s[2*t] + p_s[2*t-1]) - #pressure_forc[:,2*t-1] = 0.5*(pressure_forc[:,2*t] + pressure_forc[:,2*t-1]) - #tot_advec_T[:,2*t-1] = 0.5*(tot_advec_T[:,2*t] + tot_advec_T[:,2*t-1]) - #tot_advec_qv[:,2*t-1] = 0.5*(tot_advec_qv[:,2*t] + tot_advec_qv[:,2*t-1]) - #tot_advec_u[:,2*t-1] = 0.5*(tot_advec_u[:,2*t] + tot_advec_u[:,2*t-1]) - #tot_advec_v[:,2*t-1] = 0.5*(tot_advec_v[:,2*t] + tot_advec_v[:,2*t-1]) - - + # end for elif (time_method == 'gradient'): #this produced wonky results in the SCM; avoid until investigated more print('Forcing can be interpolated in time since the forcing terms are assumed to follow a constant time-gradient.') @@ -2293,7 +2253,8 @@ def get_UFS_forcing_data(nlevs, state_IC, location, use_nearest, forcing_dir, gr else: print('Unrecognized forcing time method. Exiting.') exit() - + # end if + # w_ls = np.zeros((nlevs,ntimes),dtype=float) omega = np.zeros((nlevs,ntimes),dtype=float) @@ -2313,23 +2274,24 @@ def get_UFS_forcing_data(nlevs, state_IC, location, use_nearest, forcing_dir, gr } if (save_comp_data): + time_hr[0] = 0.0 comp_data = { - "time": stateNATIVE["time"]*sec_in_hr, - "pa" : stateNATIVE["p_lay"][:,:], - "ta" : stateNATIVE["t_lay"][:,:], - "qv" : stateNATIVE["qv_lay"][:,:], - "ua" : stateNATIVE["u_lay"][:,:], - "va" : stateNATIVE["v_lay"][:,:], - "vars2d":vars2d} + "time" : time_hr*sec_in_hr, + "pa" : p_layers_at_pres1, + "ta" : t_layers_at_pres1, + "qv" : qv_layers_at_pres1, + "ua" : u_layers_at_pres1, + "va" : v_layers_at_pres1, + "vars2d":[]} else: comp_data = {} - return (forcing, comp_data, stateREGRID) + return (forcing, comp_data, stateInit) ######################################################################################## # ######################################################################################## -def write_SCM_case_file(state, surface, oro, forcing, case, date, stateREGRID): +def write_SCM_case_file(state, surface, oro, forcing, init, case, date): """Write all data to a netCDF file in the DEPHY-SCM format""" # Working types @@ -2534,21 +2496,21 @@ def write_SCM_case_file(state, surface, oro, forcing, case, date, stateREGRID): var_dict = [{"name": "orog", "type":wp, "dimd": ('t0' ), "units": "m", "desc": "surface_altitude"},\ {"name": "zh", "type":wp, "dimd": ('t0', 'lev'), "units": "m", "desc": "height"},\ {"name": "pa", "type":wp, "dimd": ('t0', 'lev'), "units": "Pa", "desc": "air_ressure"}, \ - {"name": "ta", "type":wp, "dimd": ('t0', 'lev'), "units": "K", "desc": "air_temperature","default_value": stateREGRID["t_lay"][1,:], "override": True}, \ + {"name": "ta", "type":wp, "dimd": ('t0', 'lev'), "units": "K", "desc": "air_temperature","default_value": init["t_lay"][:], "override": True}, \ {"name": "theta", "type":wp, "dimd": ('t0', 'lev'), "units": "K", "desc": "air_potential_temperature"}, \ {"name": "thetal", "type":wp, "dimd": ('t0', 'lev'), "units": "K", "desc": "air_liquid_potential_temperature"}, \ {"name": "rv", "type":wp, "dimd": ('t0', 'lev'), "units": "kg kg-1", "desc": "humidity_mixing_ratio"}, \ {"name": "rl", "type":wp, "dimd": ('t0', 'lev'), "units": "kg kg-1", "desc": "cloud_liquid_water_mixing_ratio"}, \ {"name": "ri", "type":wp, "dimd": ('t0', 'lev'), "units": "kg kg-1", "desc": "cloud_ice_water_mixing_ratio"}, \ {"name": "rt", "type":wp, "dimd": ('t0', 'lev'), "units": "kg kg-1", "desc": "water_mixing_ratio"}, \ - {"name": "qv", "type":wp, "dimd": ('t0', 'lev'), "units": "kg kg-1", "desc": "specific_humidity","default_value": stateREGRID["qv_lay"][1,:], "override": True}, \ + {"name": "qv", "type":wp, "dimd": ('t0', 'lev'), "units": "kg kg-1", "desc": "specific_humidity","default_value": init["qv_lay"][:], "override": True}, \ {"name": "ql", "type":wp, "dimd": ('t0', 'lev'), "units": "kg kg-1", "desc": "mass_fraction_of_cloud_liquid_water_in_air"}, \ {"name": "qi", "type":wp, "dimd": ('t0', 'lev'), "units": "kg kg-1", "desc": "mass_fraction_of_cloud_ice_water_in_air", "default_value": 0.0}, \ {"name": "qt", "type":wp, "dimd": ('t0', 'lev'), "units": "kg kg-1", "desc": "mass_fraction_of_water_in_air"}, \ {"name": "hur", "type":wp, "dimd": ('t0', 'lev'), "units": "%", "desc": "relative_humidity"}, \ {"name": "tke", "type":wp, "dimd": ('t0', 'lev'), "units": "m2 s-2", "desc": "specific_turbulen_kinetic_energy", "default_value": 0.0}, \ - {"name": "ua", "type":wp, "dimd": ('t0', 'lev'), "units": "m s-1", "desc": "eastward_wind", "default_value": stateREGRID["u_lay"][1,:], "override": True}, \ - {"name": "va", "type":wp, "dimd": ('t0', 'lev'), "units": "m s-1", "desc": "northward_wind", "default_value": stateREGRID["v_lay"][1,:], "override": True}, \ + {"name": "ua", "type":wp, "dimd": ('t0', 'lev'), "units": "m s-1", "desc": "eastward_wind","default_value": init["u_lay"][:], "override": True}, \ + {"name": "va", "type":wp, "dimd": ('t0', 'lev'), "units": "m s-1", "desc": "northward_wind","default_value": init["v_lay"][:], "override": True}, \ {"name": "ts", "type":wp, "dimd": ('t0' ), "units": "K", "desc": "surface_temperature"},\ {"name": "tskin", "type":wp, "dimd": ('t0' ), "units": "K", "desc": "surface_skin_pressure"}, \ {"name": "ps", "type":wp, "dimd": ('t0' ), "units": "Pa", "desc": "surface_air_pressure"}, \ @@ -2887,7 +2849,7 @@ def main(): #read in arguments (location, indices, date, in_dir, grid_dir, forcing_dir, tile, area, case_name, - old_chgres, lam, save_comp, use_nearest, exact_mode) = parse_arguments() + old_chgres, lam, save_comp, use_nearest, exact_mode, cmp_total_tendency) = parse_arguments() #find tile containing the point using the supergrid if no tile is specified #if not tile and not lam: @@ -2934,14 +2896,13 @@ def main(): surface_data["lat"] = point_lat # Get UFS forcing data - (forcing_data, comp_data, stateREGRID) = get_UFS_forcing_data(state_data["nlevs"], state_data, \ - location, use_nearest, forcing_dir, \ - grid_dir, tile, tile_i, tile_j, lam,\ - save_comp, exact_mode) + (forcing_data, comp_data, stateInit) = get_UFS_forcing_data(state_data["nlevs"], state_data, \ + location, use_nearest, forcing_dir, \ + grid_dir, tile, tile_i, tile_j, lam,\ + save_comp, exact_mode, cmp_total_tendency) # Write SCM case file - fileOUT = write_SCM_case_file(state_data, surface_data, oro_data, forcing_data, case_name, date, \ - stateREGRID) + fileOUT = write_SCM_case_file(state_data, surface_data, oro_data, forcing_data, stateInit, case_name, date) # read in and remap the state variables to the first history file pressure profile and # write them out to compare SCM output to (atmf for state variables and sfcf for physics diff --git a/scm/etc/scripts/UFS_forcing_ensemble_generator.py b/scm/etc/scripts/UFS_forcing_ensemble_generator.py index abb19dac2..8409786a4 100755 --- a/scm/etc/scripts/UFS_forcing_ensemble_generator.py +++ b/scm/etc/scripts/UFS_forcing_ensemble_generator.py @@ -25,9 +25,10 @@ parser.add_argument('-dt', '--timestep', help='SCM timestep, in seconds', type=int, default = 3600) parser.add_argument('-cres', '--C_RES', help='UFS spatial resolution', type=int, default = 96) parser.add_argument('-sdf', '--suite', help='CCPP suite definition file to use for ensemble', default = 'SCM_GFS_v16') -parser.add_argument('-sc', '--save_comp', help='flag to save a file with UFS data for comparisons', action='store_true') +parser.add_argument('-sc', '--save_comp', help='flag to save a file with UFS data for comparisons', action='store_true') parser.add_argument('-near', '--use_nearest', help='flag to indicate using the nearest UFS history file gridpoint, no regridding',action='store_true') -parser.add_argument('-ext', '--exact_mode', help='flag to indicate using dynamic tendencies from UFS history files', action='store_true') +parser.add_argument('-ext', '--exact_mode', help='flag to indicate using dynamic tendencies from UFS history files', action='store_true') +parser.add_argument('-tott', '--total_tend', help='flag to indicate forcing to derive', action='store_true') ############################################################################### # Main program @@ -140,6 +141,7 @@ def main(): if args.save_comp: com_config = com_config + ' -sc' if args.use_nearest: com_config = com_config + ' -near' if args.exact_mode: com_config = com_config + ' -ext' + if args.total_tend: com_config = com_config + ' -tott' # Create inputs to SCM case_list = "" @@ -213,12 +215,12 @@ def main(): # Display run commands # ########################################################################### - print("-------------------------------------------------------------------------------------------") + print("#"*128) print("Command(s) to execute in ccpp-scm/scm/bin/: ") print(" ") print("./run_scm.py --npz_type gfs --file " + fileOUT + " --timestep " + str(args.timestep)) print("") - print("-------------------------------------------------------------------------------------------") + print("#"*128) if __name__ == '__main__': main() From 8b2f4de084ee5421c70ad1d46e3592efe6949115 Mon Sep 17 00:00:00 2001 From: Grant Firl Date: Tue, 28 May 2024 17:08:30 -0400 Subject: [PATCH 03/25] Feature/ufs case gen exact mode gjf (#12) * rename UFS_IC_generator.py to UFS_case_gen.py * merge UFS_case_gen.py methods * add wind nudging option to UFS_case_gen.py --- scm/doc/TechGuide/chap_cases.rst | 6 +- .../{UFS_IC_generator.py => UFS_case_gen.py} | 931 ++++++++++++++++-- .../scripts/UFS_forcing_ensemble_generator.py | 6 +- 3 files changed, 848 insertions(+), 95 deletions(-) rename scm/etc/scripts/{UFS_IC_generator.py => UFS_case_gen.py} (78%) diff --git a/scm/doc/TechGuide/chap_cases.rst b/scm/doc/TechGuide/chap_cases.rst index b6bd183dd..89dd019cb 100644 --- a/scm/doc/TechGuide/chap_cases.rst +++ b/scm/doc/TechGuide/chap_cases.rst @@ -409,16 +409,16 @@ Activate environment: .. _`ufsicgenerator`: -UFS_IC_generator.py +UFS_case_gen.py ~~~~~~~~~~~~~~~~~~~ -A script exists in ``scm/etc/scripts/UFS_IC_generator.py`` to read in UFS history (output) files and their +A script exists in ``scm/etc/scripts/UFS_case_gen.py`` to read in UFS history (output) files and their initial conditions to generate a SCM case input data file, in DEPHY format. .. code:: bash - ./UFS_IC_generator.py [-h] (-l LOCATION LOCATION | -ij INDEX INDEX) -d + ./UFS_case_gen.py [-h] (-l LOCATION LOCATION | -ij INDEX INDEX) -d DATE -i IN_DIR -g GRID_DIR -f FORCING_DIR -n CASE_NAME [-t {1,2,3,4,5,6,7}] [-a AREA] [-oc] [-lam] [-sc] [-near] diff --git a/scm/etc/scripts/UFS_IC_generator.py b/scm/etc/scripts/UFS_case_gen.py similarity index 78% rename from scm/etc/scripts/UFS_IC_generator.py rename to scm/etc/scripts/UFS_case_gen.py index 7c8d7d1a9..7799dd640 100755 --- a/scm/etc/scripts/UFS_IC_generator.py +++ b/scm/etc/scripts/UFS_case_gen.py @@ -14,6 +14,8 @@ import fv3_remap import xesmf from datetime import datetime, timedelta +from pylab import plot, ylim, xlim, show, xlabel, ylabel, grid + ############################################################################### # Global settings # @@ -21,6 +23,7 @@ #Physical constants earth_radius = 6371000.0 #m +Omega = 7.292E-5 rdgas = 287.05 rvgas = 461.50 cp = 1004.6 @@ -30,11 +33,22 @@ deg_to_rad = math.pi/180.0 kappa = rdgas/cp p0 = 100000.0 +one_twelfth = 1.0/12.0 +two_thirds = 2.0/3.0 missing_value = -9999.0 #9.99e20 +top_pres_for_forcing = 20000.0 + +const_nudging_time = 3600.0 + n_lam_halo_points = 3 +n_forcing_halo_points = 2 #number of points in each direction used to retrieve forcing (1 = 3x3, 2 = 5x5, 3 = 7x7); must be >=1 + +#dist_method = 'euclidean' +dist_method = 'haversine' #faster + missing_variable_snow_layers = 3 missing_variable_soil_layers = 4 missing_variable_ice_layers = 2 @@ -68,8 +82,10 @@ parser.add_argument('-lam', '--lam', help='flag to signal that the ICs and forcing is from a limited-area model run', action='store_true') parser.add_argument('-sc', '--save_comp', help='flag to create UFS reference file for comparison', action='store_true') parser.add_argument('-near','--use_nearest', help='flag to indicate using the nearest UFS history file gridpoint', action='store_true') -parser.add_argument('-ext', '--exact_mode', help='flag to indicate using dynamic tendencies from UFS history files', action='store_true') -parser.add_argument('-tott','--total_tend', help='flag to indicate forcing to derive', action='store_true') +parser.add_argument('-fm', '--forcing_method', help='method used to calculate forcing (1=total tendencies from UFS dycore, 2=advective terms calculated from UFS history files, 3=total time tendency terms calculated)', type=int, choices=range(1,4), default=2) +parser.add_argument('-vm', '--vertical_method', help='method used to calculate vertical advective forcing (1=vertical advective terms calculated from UFS history files and added to total, 2=smoothed vertical velocity provided)', type=int, choices=range(1,3), default=2) +parser.add_argument('-wn', '--wind_nudge', help='flag to turn on wind nudging to UFS profiles', action='store_true') +parser.add_argument('-geos','--geostrophic', help='flag to turn on geostrophic wind forcing', action='store_true') ######################################################################################## # @@ -90,8 +106,10 @@ def parse_arguments(): lam = args.lam save_comp = args.save_comp use_nearest = args.use_nearest - exact_mode = args.exact_mode - total_tend = args.total_tend + forcing_method = args.forcing_method + vertical_method = args.vertical_method + geos_wind_forcing = args.geostrophic + wind_nudge = args.wind_nudge #validate args if not os.path.exists(in_dir): @@ -131,7 +149,8 @@ def parse_arguments(): raise Exception(message) return (location, index, date_dict, in_dir, grid_dir, forcing_dir, tile, \ - area, case_name, old_chgres, lam, save_comp, use_nearest, exact_mode, total_tend) + area, case_name, old_chgres, lam, save_comp, use_nearest, forcing_method, \ + vertical_method, geos_wind_forcing, wind_nudge) ######################################################################################## # @@ -140,6 +159,74 @@ def setup_logging(): """Sets up the logging module.""" logging.basicConfig(format='%(levelname)s: %(message)s', level=LOGLEVEL) +######################################################################################## +# +######################################################################################## +def haversine_distance(lat1, lon1, lat2, lon2): + #lats and lons in degrees + p = 0.017453292519943295 + hav = 0.5 - math.cos((lat2-lat1)*p)/2 + math.cos(lat1*p)*math.cos(lat2*p) * (1-math.cos((lon2-lon1)*p)) / 2 + return 12742 * math.asin(math.sqrt(hav)) #km + +######################################################################################## +# +######################################################################################## +def sph2cart(az, el, r): + """Calculate the Cartesian coordiates from spherical coordinates""" + + rcos_theta = r * np.cos(el) + x = rcos_theta * np.cos(az) + y = rcos_theta * np.sin(az) + z = r * np.sin(el) + + return (x, y, z) + +######################################################################################## +# +######################################################################################## +def moving_average(interval, window_size): + convolve_mode = 'same' + window= np.ones(int(window_size))/float(window_size) + + output = np.zeros((interval.shape[0])) + if (convolve_mode == 'same'): + convolution = np.convolve(interval, window, mode='same') + output = convolution + elif (convolve_mode == 'valid'): + convolution = np.convolve(interval, window, mode='valid') + num_not_valid_points = interval.shape[0] - (max(interval.shape[0], window_size) - min(interval.shape[0], window_size) + 1) + output[num_not_valid_points:] = convolution + for k in range(num_not_valid_points): + output[k] = interval[k] + output[-1-k] = interval[-1-k] + + return output + +######################################################################################## +# +######################################################################################## +def centered_diff_derivative(y, dx): + #y is the variable of interest, dx is the space between contiguous points (starting from the first point) + cent_diff_coef_three = [-0.5, 0.0, 0.5] #second-order accuracy in space (assuming constant grid) + cent_diff_coef_five = [one_twelfth, -two_thirds, 0.0, two_thirds, -one_twelfth] #fourth-order accuracy in space (assuming constant grid) + + if y.shape[0] % 2: + center = int((y.shape[0]-1)/2) + if y.shape[0] == 3: + deriv = np.sum(cent_diff_coef_three*y)/np.mean(dx) + elif y.shape[0] == 5: + deriv = np.sum(cent_diff_coef_five*y)/np.mean(dx) + else: + message = 'centered_diff_derivative can only use n_forcing_halo_points = 1 or 2' + logging.exception(message) + raise Exception(message) + else: + message = 'An even number of points was passed into centered_diff_derivative' + logging.exception(message) + raise Exception(message) + + return deriv + ######################################################################################## # ######################################################################################## @@ -295,24 +382,32 @@ def find_loc_indices(loc, dir, tile, lam): if loc[0] < 180: temp_loc[0] += 360 - #set up an array to hold the euclidean distance between the given point and every grid cell - eucl_dist = np.zeros((longitude.shape[0],longitude.shape[1])) - - #get the Cartesian location of the given point - cart_loc = np.asarray(sph2cart(math.radians(temp_loc[0]), math.radians(temp_loc[1]), earth_radius)) - - for i in range(len(longitude)): - for j in range(len(longitude[i])): - #get the Cartesian location of all grid points - cart_cell = np.asarray(sph2cart(math.radians(longitude[i,j]), math.radians(latitude[i,j]), earth_radius)) - - #calculate the euclidean distance from the given point to the current grid cell - eucl_dist[i,j] = np.linalg.norm(cart_loc - cart_cell) - + #set up an array to hold the distance between the given point and every grid cell + dist = np.zeros((longitude.shape[0],longitude.shape[1])) + if (dist_method == 'euclidean'): + + #get the Cartesian location of the given point + cart_loc = np.asarray(sph2cart(math.radians(loc[0]), math.radians(loc[1]), earth_radius)) + + for i in range(len(longitude)): + for j in range(len(longitude[i])): + #get the Cartesian location of all grid points + cart_cell = np.asarray(sph2cart(math.radians(longitude[i,j]), math.radians(latitude[i,j]), earth_radius)) + + #calculate the euclidean distance from the given point to the current grid cell + dist[i,j] = np.linalg.norm(cart_loc - cart_cell) + else: + for i in range(len(longitude)): + for j in range(len(longitude[i])): + dist[i,j] = haversine_distance(latitude[i,j],longitude[i,j],loc[1],loc[0]) #get the indices of the grid point with the minimum euclidean distance to the given point - i,j = np.unravel_index(eucl_dist.argmin(), eucl_dist.shape) + i,j = np.unravel_index(dist.argmin(), dist.shape) + + #get the direction of the closest point from the given point + theta = math.atan2(math.sin(math.radians(longitude[i,j] - loc[0]))*math.cos(math.radians(latitude[i,j])), math.cos(math.radians(loc[1]))*math.sin(math.radians(latitude[i,j])) - math.sin(math.radians(loc[1]))*math.cos(math.radians(latitude[i,j]))*math.cos(math.radians(longitude[i,j] - loc[0]))) + theta_deg = math.fmod((math.degrees(theta) + 360.0), 360.0) - return (i,j,longitude[i,j]%360.0, latitude[i,j], eucl_dist[i,j]) + return (i,j,longitude[i,j]%360.0, latitude[i,j], dist[i,j], theta_deg) ######################################################################################## # @@ -357,6 +452,148 @@ def find_lon_lat_of_indices(indices, dir, tile, lam): return (longitude[indices[1],indices[0]], latitude[indices[1],indices[0]]) +######################################################################################## +# +######################################################################################## +def find_loc_indices_UFS_history(loc, dir): + """Find the nearest neighbor UFS history file grid point given a lon/lat pair""" + #returns the indices of the nearest neighbor point in the given tile, the lon/lat of the nearest neighbor, + #and the distance (m) from the given point to the nearest neighbor grid cell + + filename_pattern = 'atmf000.nc' + + for f_name in os.listdir(dir): + if fnmatch.fnmatch(f_name, filename_pattern): + filename = f_name + if not filename: + message = 'No filenames matching the pattern {0} found in {1}'.format(filename_pattern,dir) + logging.critical(message) + raise Exception(message) + + nc_file = Dataset('{0}/{1}'.format(dir,filename)) + + longitude = np.asarray(nc_file['lon']) + latitude = np.asarray(nc_file['lat']) + + nc_file.close() + + #set up an array to hold the distance between the given point and every grid cell + dist = np.zeros((longitude.shape[0],longitude.shape[1])) + if (dist_method == 'euclidean'): + + #get the Cartesian location of the given point + cart_loc = np.asarray(sph2cart(math.radians(loc[0]), math.radians(loc[1]), earth_radius)) + + for i in range(len(longitude)): + for j in range(len(longitude[i])): + #get the Cartesian location of all grid points + cart_cell = np.asarray(sph2cart(math.radians(longitude[i,j]), math.radians(latitude[i,j]), earth_radius)) + + #calculate the euclidean distance from the given point to the current grid cell + dist[i,j] = np.linalg.norm(cart_loc - cart_cell) + else: + for i in range(len(longitude)): + for j in range(len(longitude[i])): + dist[i,j] = haversine_distance(latitude[i,j],longitude[i,j],loc[1],loc[0]) + #get the indices of the grid point with the minimum euclidean distance to the given point + i,j = np.unravel_index(dist.argmin(), dist.shape) + + #get the direction of the closest point from the given point + theta = math.atan2(math.sin(math.radians(longitude[i,j] - loc[0]))*math.cos(math.radians(latitude[i,j])), math.cos(math.radians(loc[1]))*math.sin(math.radians(latitude[i,j])) - math.sin(math.radians(loc[1]))*math.cos(math.radians(latitude[i,j]))*math.cos(math.radians(longitude[i,j] - loc[0]))) + theta_deg = math.fmod((math.degrees(theta) + 360.0), 360.0) + + halo_indices = np.zeros((1+2*n_forcing_halo_points,1+2*n_forcing_halo_points)) + if i < n_forcing_halo_points or i > latitude.shape[0]-1-n_forcing_halo_points: + message = 'Chosen point too close to the poles for this algorithm' + logging.critical(message) + raise Exception(message) + else: + #longitude = (n rows of latitude, 2*n columns of longitude), i index increases toward EAST; rows are circles of latitude, columns are meridians + #latitude = (n rows of latitude, 2*n columns of longitude), j index increases toward NORTH; rows are circles of latitude, columns are meridians + neighbors = np.mgrid[-n_forcing_halo_points:n_forcing_halo_points+1,-n_forcing_halo_points:n_forcing_halo_points+1] + neighbors[0,:,:] = neighbors[0,:,:] + i + neighbors[1,:,:] = neighbors[1,:,:] + j + + + # the closest point is near the western edge of the prime meridian, but longitude should be cyclic, so get neighbors on the eastern/western side of the prime meridian as necessary + neighbors[1,:,:] = neighbors[1,:,:]%longitude.shape[1] + + # if j > n_forcing_halo_points: + # if j < latitude.shape[1]-1-n_forcing_halo_points: + # neighbors[1,:,:] = neighbors[1,:,:] + j + # else: + # + # n_points_on_eastern_side = (j + n_forcing_halo_points)%latitude.shape[1] + + + + message = 'nearest history file indices (i,j): ({},{})'.format(i, j) + message += '\n lon/lat : {},{}'.format(longitude[i,j], latitude[i,j]) + message += '\n distance between history file point and desired point: {} km'.format(dist[i,j]) + message += '\n bearing from desired point to history file point: {} degrees'.format(theta_deg) + logging.debug(message) + + message = 'neighboring points' + for ii in neighbors[0,:,0]: + for jj in neighbors[1,0,:]: + message += '\n (i,j,lon,lat,dist): ({:>},{:>},{:f},{:f},{:f})'.format(ii,jj,longitude[ii,jj], latitude[ii,jj], dist[ii,jj]) + logging.debug(message) + + #calc dx, dy (n_forcing_halo_points*2 x n_forcing_halo_points*2) + dx = np.zeros((n_forcing_halo_points*2+1,n_forcing_halo_points*2)) + dy = np.zeros((n_forcing_halo_points*2,n_forcing_halo_points*2+1)) + for ii in range(2*n_forcing_halo_points+1): + for jj in range(2*n_forcing_halo_points): + current_ii_index = neighbors[0,ii,jj] + current_jj_index = neighbors[1,ii,jj] + eastern_jj_index = neighbors[1,ii,jj+1] + dx[ii,jj] = haversine_distance(latitude[current_ii_index,current_jj_index],longitude[current_ii_index,current_jj_index],latitude[current_ii_index,eastern_jj_index],longitude[current_ii_index,eastern_jj_index]) + + for ii in range(2*n_forcing_halo_points): + for jj in range(2*n_forcing_halo_points+1): + current_ii_index = neighbors[0,ii,jj] + northern_ii_index = neighbors[0,ii+1,jj] + current_jj_index = neighbors[1,ii,jj] + dy[ii,jj] = haversine_distance(latitude[current_ii_index,current_jj_index],longitude[current_ii_index,current_jj_index],latitude[northern_ii_index,current_jj_index],longitude[northern_ii_index,current_jj_index]) + + return (i,j,longitude[i,j], latitude[i,j], dist[i,j], theta_deg, neighbors, dx, dy) + +######################################################################################## +# +######################################################################################## +def find_loc_indices_UFS_IC(loc, dir, lam, tile, indices): + + #find tile containing the point using the supergrid if no tile is specified + #if not tile and not lam: + if not tile: + tile = int(find_tile(loc, dir, lam)) + if tile < 0: + message = 'No tile was found for location {0}'.format(location) + logging.critical(message) + raise Exception(message) + message = 'Tile found: {0}'.format(tile) + logging.debug(message) + + #find index of closest point in the tile if indices are not specified + theta = 0.0 + if not indices: + (tile_j, tile_i, point_lon, point_lat, dist_min, theta) = find_loc_indices(loc, dir, tile, lam) + message = 'nearest IC file indices in tile {} - (i,j): ({},{})'.format(tile, tile_i, tile_j) + message += '\n lon/lat : {},{}'.format(point_lon, point_lat) + message += '\n distance between history file point and desired point: {} km'.format(dist_min) + message += '\n bearing from desired point to history file point: {} degrees'.format(theta) + logging.debug(message) + else: + tile_i = indices[0] + tile_j = indices[1] + #still need to grab the lon/lat if the tile and indices are supplied + (point_lon, point_lat) = find_lon_lat_of_indices(indices, grid_dir, tile, lam) + + message = 'This index has a central longitude/latitude of [{0},{1}]'.format(point_lon,point_lat) + logging.debug(message) + + return (tile_i, tile_j, tile, point_lon, point_lat, dist_min, theta) + ######################################################################################## # ######################################################################################## @@ -396,20 +633,59 @@ def get_initial_lon_lat_grid(dir, tile, lam): nc_file.close() - return (longitude, latitude) + return (longitude, latitude) -######################################################################################## -# -######################################################################################## -def sph2cart(az, el, r): - """Calculate the Cartesian coordiates from spherical coordinates""" +def compare_hist_and_IC_points(location, hist_lon, hist_lat, IC_lon, IC_lat, hist_dist, angle_to_hist_point, IC_dist, angle_to_IC_point): + #determine distance and angle from IC point to hist point + dist = haversine_distance(IC_lat,IC_lon,hist_lat,hist_lon) + theta = math.atan2(math.sin(math.radians(hist_lon - IC_lon))*math.cos(math.radians(hist_lat)), math.cos(math.radians(IC_lat))*math.sin(math.radians(hist_lat)) - math.sin(math.radians(IC_lat))*math.cos(math.radians(hist_lat))*math.cos(math.radians(hist_lon - IC_lon))) + theta_deg = math.fmod((math.degrees(theta) + 360.0), 360.0) - rcos_theta = r * np.cos(el) - x = rcos_theta * np.cos(az) - y = rcos_theta * np.sin(az) - z = r * np.sin(el) + message = 'Location summary' + message += '\n The location as entered is {} deg E {} deg N'.format(location[0],location[1]) + message += '\n The closest point in the UFS history file is {} deg E {} deg N, or {} km away at a bearing of {} deg'.format(hist_lon, hist_lat, hist_dist, angle_to_hist_point) + message += '\n The closest point in the UFS IC files (native grid) is {} deg E {} deg N, or {} km away at a bearing of {} deg'.format(IC_lon, IC_lat, IC_dist, angle_to_IC_point) + message += '\n Therefore, the history point (used to define the SCM grid column) is {} km away from the closest UFS native grid poing at a bearing of {} deg'.format(dist, theta_deg) + logging.info(message) + + return + +def check_IC_hist_surface_compatibility(dir, i, j, surface_data, lam, old_chgres, tile): + + # Determine UFS history file format (tiled/quilted) + if lam: + filename_pattern = '*sfcf000.tile{}.nc'.format(tile) + else: + filename_pattern = '*sfcf000.nc' + + for f_name in os.listdir(dir): + if fnmatch.fnmatch(f_name, filename_pattern): + filename = f_name + if not filename: + message = 'No filenames matching the pattern {0} found in {1}'.format(filename_pattern,dir) + logging.critical(message) + raise Exception(message) + + nc_file = Dataset('{0}/{1}'.format(dir,filename)) + + #doublecheck this is correct point + #lon_in = read_NetCDF_var(nc_file, "lon", j, i) + #lat_in = read_NetCDF_var(nc_file, "lat", j, i) + #logging.debug('check_IC_hist_surface_compatibility lon/lat: {}/{}'.format(lon_in, lat_in)) + + slmsk_hist = read_NetCDF_surface_var(nc_file, "land", j, i, old_chgres, 0) + + if (slmsk_hist != surface_data["slmsk"]): + message = 'There is a mismatch between the UFS IC file and history file land masks: IC={}, history={}'.format(surface_data["slmsk"],slmsk_hist) + logging.critical(message) + raise Exception(message) + else: + message = 'UFS IC file and history file land masks match: IC={}, history={}'.format(surface_data["slmsk"],slmsk_hist) + logging.info(message) + + nc_file.close() - return (x, y, z) + return ######################################################################################## # @@ -460,19 +736,82 @@ def read_NetCDF_surface_var(nc_file, var_name, i, j, old_chgres, vert_dim): var = missing_value return var +def get_IC_data_from_UFS_history(dir, i, j, lam, tile): + + # Determine UFS history file format (tiled/quilted) + if lam: + filename_pattern = '*atmf000.tile{}.nc'.format(tile) + else: + filename_pattern = '*atmf000.nc' + + for f_name in os.listdir(dir): + if fnmatch.fnmatch(f_name, filename_pattern): + filename = f_name + if not filename: + message = 'No filenames matching the pattern {0} found in {1}'.format(filename_pattern,dir) + logging.critical(message) + raise Exception(message) + + nc_file = Dataset('{0}/{1}'.format(dir,filename)) + + pfull = nc_file['pfull'][::-1]*100.0 + phalf = nc_file['phalf'][::-1]*100.0 + nlevs = len(pfull) + time = nc_file['time'][0] #model hours since being initialized + lon = nc_file['lon'][i,j] + lat = nc_file['lat'][i,j] + logging.debug('Grabbing data from history file point with lon/lat: {}/{}'.format(lon,lat)) + delz = -1*nc_file['delz'][0,::-1,i,j] #derive zh + ugrd = nc_file['ugrd'][0,::-1,i,j] + vgrd = nc_file['vgrd'][0,::-1,i,j] + spfh = nc_file['spfh'][0,::-1,i,j] + o3mr = nc_file['o3mr'][0,::-1,i,j] + clwmr = nc_file['clwmr'][0,::-1,i,j] + icmr = nc_file['icmr'][0,::-1,i,j] + pressfc = nc_file['pressfc'][0,i,j] + tmp = nc_file['tmp'][0,::-1,i,j] + + delz = np.asarray(delz) + zh = np.zeros(nlevs) + zh[0] = 0.5*delz[0] + for k in range(1,nlevs): + zh[k] = zh[k-1] + 0.5*delz[k-1] + 0.5*delz[k] + + dz = np.zeros(nlevs-1) + for k in range(nlevs-1): + dz[k] = zh[k+1]-zh[k] + + state = { + "nlevs": nlevs, + "zh": zh, + "dz": dz, + "ua": np.asarray(ugrd), + "va": np.asarray(vgrd), + "qv": np.asarray(spfh), + "o3": np.asarray(o3mr), + "ql": np.asarray(clwmr), + "qi": np.asarray(icmr), + "ps": pressfc, + "ta": np.asarray(tmp), + "pa": np.asarray(pfull), + "pa_i": np.asarray(phalf) + } + + nc_file.close() + + return state + ######################################################################################## # ######################################################################################## -def get_UFS_IC_data(dir, grid_dir, tile, i, j, old_chgres, lam): +def get_IC_data_from_UFS_ICs(dir, grid_dir, tile, i, j, old_chgres, lam): """Get the state, surface, and orographic data for the given tile and indices""" #returns dictionaries with the data vgrid_data = get_UFS_vgrid_data(grid_dir) #only needed for ak, bk to calculate pressure (state_data, error_msg) = get_UFS_state_data(vgrid_data, dir, tile, i, j, old_chgres, lam) - surface_data = get_UFS_surface_data(dir, tile, i, j, old_chgres, lam) - oro_data = get_UFS_oro_data(dir, tile, i, j, lam) - return (state_data, surface_data, oro_data, error_msg) + return (state_data, error_msg) ######################################################################################## # @@ -1492,11 +1831,390 @@ def search_in_dict(listin,name): if dictionary["name"] == name: return count +def get_UFS_forcing_data_advective_tendency(dir, i, j, tile, neighbors, dx, dy, nlevs, lam, save_comp_data, vertical_method, geos_wind_forcing, wind_nudge): + + # Determine UFS history file format (tiled/quilted) + if lam: + atm_ftag = 'atmf*.tile{0}.nc'.format(tile) + sfc_ftag = 'sfcf*.tile{0}.nc'.format(tile) + else: + atm_ftag = '*atmf*.nc' + sfc_ftag = '*sfcf*.nc' + + # Get list of UFS history files with 3D ATMospheric state variables. + atm_filenames = [] + for f_name in os.listdir(dir): + if fnmatch.fnmatch(f_name, atm_ftag): + atm_filenames.append(f_name) + if not atm_filenames: + message = 'No filenames matching the pattern {0} found in {1}'. \ + format(atm_ftag,dir) + logging.critical(message) + raise Exception(message) + atm_filenames = sorted(atm_filenames) + n_filesA = len(atm_filenames) + + npts = 2*n_forcing_halo_points+1 + + lon = np.zeros((n_filesA,npts,npts)) + lat = np.zeros((n_filesA,npts,npts)) + time = np.zeros((n_filesA)) + u_wind = np.zeros((n_filesA,nlevs,npts,npts)) + v_wind = np.zeros((n_filesA,nlevs,npts,npts)) + w_wind = np.zeros((n_filesA,nlevs,npts,npts)) + temp = np.zeros((n_filesA,nlevs,npts,npts)) + qv = np.zeros((n_filesA,nlevs,npts,npts)) + pres = np.zeros((n_filesA,nlevs)) + pressfc = np.zeros((n_filesA,npts,npts)) + delz = np.zeros((n_filesA,nlevs,npts,npts)) + + # Read in 3D UFS history files + for count, filename in enumerate(atm_filenames, start=1): + nc_file = Dataset('{0}/{1}'.format(dir,filename)) + nc_file.set_always_mask(False) + + time[count-1] = nc_file['time'][0] + + for ii in range(2*n_forcing_halo_points+1): + for jj in range(2*n_forcing_halo_points+1): + current_ii_index = neighbors[0,ii,jj] + current_jj_index = neighbors[1,ii,jj] + + lon[count-1,ii,jj] = nc_file['lon'][current_ii_index,current_jj_index] + lat[count-1,ii,jj] = nc_file['lat'][current_ii_index,current_jj_index] + u_wind[count-1,:,ii,jj] = nc_file['ugrd'][0,::-1,current_ii_index,current_jj_index] + v_wind[count-1,:,ii,jj] = nc_file['vgrd'][0,::-1,current_ii_index,current_jj_index] + w_wind[count-1,:,ii,jj] = nc_file['dzdt'][0,::-1,current_ii_index,current_jj_index] + temp[count-1,:,ii,jj] = nc_file['tmp'][0,::-1,current_ii_index,current_jj_index] + qv[count-1,:,ii,jj] = nc_file['spfh'][0,::-1,current_ii_index,current_jj_index] + pressfc[count-1,ii,jj] = nc_file['pressfc'][0,current_ii_index,current_jj_index] + delz[count-1,:,ii,jj] = -1*nc_file['delz'][0,::-1,current_ii_index,current_jj_index] #derive zh + pres[count-1,:] = nc_file['pfull'][::-1]*100.0 + + #This only works for points with longitude far enough away from the prime meridian + # lon_data = nc_file['lon'][neighbors[0,0,0]:neighbors[0,-1,-1]+1,neighbors[1,0,0]:neighbors[1,-1,-1]+1] + # lat_data = nc_file['lat'][neighbors[0,0,0]:neighbors[0,-1,-1]+1,neighbors[1,0,0]:neighbors[1,-1,-1]+1] + # u_data = nc_file['ugrd'][0,::-1,neighbors[0,0,0]:neighbors[0,-1,-1]+1,neighbors[1,0,0]:neighbors[1,-1,-1]+1] + # v_data = nc_file['vgrd'][0,::-1,neighbors[0,0,0]:neighbors[0,-1,-1]+1,neighbors[1,0,0]:neighbors[1,-1,-1]+1] + # w_data = nc_file['dzdt'][0,::-1,neighbors[0,0,0]:neighbors[0,-1,-1]+1,neighbors[1,0,0]:neighbors[1,-1,-1]+1] + # temp_data = nc_file['tmp'][0,::-1,neighbors[0,0,0]:neighbors[0,-1,-1]+1,neighbors[1,0,0]:neighbors[1,-1,-1]+1] + # qv_data = nc_file['spfh'][0,::-1,neighbors[0,0,0]:neighbors[0,-1,-1]+1,neighbors[1,0,0]:neighbors[1,-1,-1]+1] + # pres_data = nc_file['pfull'][::-1]*100.0 + # pressfc_data = nc_file['pressfc'][0,neighbors[0,0,0]:neighbors[0,-1,-1]+1,neighbors[1,0,0]:neighbors[1,-1,-1]+1] + + # time.append(time_data) + # lon.append(lon_data) + # lat.append(lat_data) + # u_wind.append(u_data) + # v_wind.append(v_data) + # w_wind.append(w_data) + # temp.append(temp_data) + # qv.append(qv_data) + # pres.append(pres_data) + # pressfc.append(pressfc_data) + + # time = np.asarray(time) + # lon = np.asarray(lon) + # lat = np.asarray(lat) + # u_wind = np.asarray(u_wind) + # v_wind = np.asarray(v_wind) + # w_wind = np.asarray(w_wind) + # temp = np.asarray(temp) + # qv = np.asarray(qv) + # pres = np.asarray(pres) + # pressfc = np.asarray(pressfc) + + #check for poor time resolution (e.g. if mean number of grid points traversed by the wind between data intervals is much larger than the number of grid points used for calculating the advective terms) + # t=0 + # for k in range(u_wind.shape[1]): + # mean_u = np.mean(np.sqrt(u_wind[t,k,:,:]*u_wind[t,k,:,:])) + # mean_dist = 43200*mean_u*1.0E-3 + # print("k, mean_dist, dx, grid points traversed in timestep: ",k, mean_dist, np.mean(dx), mean_dist/np.mean(dx)) + + center = n_forcing_halo_points + smoothed_u = np.zeros((n_filesA,nlevs,npts,npts)) + smoothed_v = np.zeros((n_filesA,nlevs,npts,npts)) + smoothed_w = np.zeros((n_filesA,nlevs)) + smoothed_T = np.zeros((n_filesA,nlevs,npts,npts)) + smoothed_qv = np.zeros((n_filesA,nlevs,npts,npts)) + h_advec_u = np.zeros((n_filesA,nlevs)) + h_advec_v = np.zeros((n_filesA,nlevs)) + h_advec_T = np.zeros((n_filesA,nlevs)) + h_advec_qv = np.zeros((n_filesA,nlevs)) + v_advec_u = np.zeros((n_filesA,nlevs)) + v_advec_v = np.zeros((n_filesA,nlevs)) + v_advec_T = np.zeros((n_filesA,nlevs)) + v_advec_qv = np.zeros((n_filesA,nlevs)) + for t in range(n_filesA): + #velocities gets very noisy in the UFS above the tropopause; define a linear return-to-zero profile above some pressure + k_p_top = np.where(pres[t,:] <= top_pres_for_forcing)[0][0] + + #smooth velocity profile + n_smooth_points = 5 + for ii in range(npts): + for jj in range(npts): + #the last argument defines the averaging "window" in grid layers; greater numbers results in greater smoothing + smoothed_u[t,:,ii,jj] = moving_average(u_wind[t,:,ii,jj], n_smooth_points) + smoothed_v[t,:,ii,jj] = moving_average(v_wind[t,:,ii,jj], n_smooth_points) + smoothed_T[t,:,ii,jj] = moving_average(temp [t,:,ii,jj], n_smooth_points) + smoothed_qv[t,:,ii,jj] = moving_average(qv [t,:,ii,jj], n_smooth_points) + + #velocities gets very noisy in the UFS above the tropopause; define a linear return-to-zero profile above some pressure + for k in range(k_p_top+1,nlevs): + lifrac = pres[t,k]/pres[t,k_p_top] + smoothed_u[t,k,ii,jj] = lifrac*smoothed_u[t,k_p_top,ii,jj] + smoothed_v[t,k,ii,jj] = lifrac*smoothed_v[t,k_p_top,ii,jj] + + smoothed_w[t,:] = moving_average(w_wind[t,:,center,center], n_smooth_points) + + for k in range(k_p_top+1,nlevs): + lifrac = pres[t,k]/pres[t,k_p_top] + smoothed_w[t,k] = lifrac*smoothed_w[t,k_p_top] + + for k in range(nlevs): + dTdx = centered_diff_derivative(smoothed_T[t,k,center,:],dx[center,:]*1.0E3) + dTdy = centered_diff_derivative(smoothed_T[t,k,:,center],dy[:,center]*1.0E3) + dqdx = centered_diff_derivative(smoothed_qv[t,k,center,:],dx[center,:]*1.0E3) + dqdy = centered_diff_derivative(smoothed_qv[t,k,:,center],dy[:,center]*1.0E3) + dudx = centered_diff_derivative(smoothed_u[t,k,center,:],dx[center,:]*1.0E3) + dudy = centered_diff_derivative(smoothed_u[t,k,:,center],dy[:,center]*1.0E3) + dvdx = centered_diff_derivative(smoothed_v[t,k,center,:],dx[center,:]*1.0E3) + dvdy = centered_diff_derivative(smoothed_v[t,k,:,center],dy[:,center]*1.0E3) + mean_u = np.mean(smoothed_u[t,k,center,center-1:center+1+1]) + mean_v = np.mean(smoothed_v[t,k,center-1:center+1+1,center]) + + h_advec_T[t,k] = -mean_u*dTdx - mean_v*dTdy #K s-1 + h_advec_qv[t,k] = -mean_u*dqdx - mean_v*dqdy #kg kg-1 s-1 + h_advec_u[t,k] = -mean_u*dudx - mean_v*dudy #m s-1 s-1 + h_advec_v[t,k] = -mean_u*dvdx - mean_v*dvdy #m s-1 s-1 + + + + # plot(w_wind[t,:,center,center],pres[t,:],"k.") + # #y_av = movingaverage(y, 10) + # plot(w_wind_smoothed_ma, pres[t,:],"r") + # #plot(w_wind_smoothed_sf, pres[t,:],"b") + # xlim(np.min(w_wind[t,:,center,center]),np.max(w_wind[t,:,center,center])) + # xlabel("w") + # ylabel("p") + # grid(True) + # show() + + if (vertical_method == 1): + v_advec_u[t,0] = 0.0 + v_advec_u[t,nlevs-1] = 0.0 + v_advec_v[t,0] = 0.0 + v_advec_v[t,nlevs-1] = 0.0 + v_advec_T[t,0] = 0.0 + v_advec_T[t,nlevs-1] = 0.0 + v_advec_qv[t,0] = 0.0 + v_advec_qv[t,nlevs-1] = 0.0 + for k in range(1, nlevs-1): + w_asc = max(smoothed_w[t,k], 0.0) + w_des = min(smoothed_w[t,k], 0.0) + gradient_T_asc = (temp[t,k,center,center] - temp[t,k-1,center,center])/(pres[t,k]-pres[t,k-1]) + gradient_T_des = (temp[t,k+1,center,center] - temp[t,k,center,center])/(pres[t,k+1]-pres[t,k]) + #gradient_T_asc = (smoothed_T[t,k,center,center] - smoothed_T[t,k-1,center,center])/(pres[t,k]-pres[t,k-1]) + #gradient_T_des = (smoothed_T[t,k+1,center,center] - smoothed_T[t,k,center,center])/(pres[t,k+1]-pres[t,k]) + gradient_qv_asc = (qv[t,k,center,center] - qv[t,k-1,center,center])/(pres[t,k]-pres[t,k-1]) + gradient_qv_des = (qv[t,k+1,center,center] - qv[t,k,center,center])/(pres[t,k+1]-pres[t,k]) + #gradient_qv_asc = (smoothed_qv[t,k,center,center] - smoothed_qv[t,k-1,center,center])/(pres[t,k]-pres[t,k-1]) + #gradient_qv_des = (smoothed_qv[t,k+1,center,center] - smoothed_qv[t,k,center,center])/(pres[t,k+1]-pres[t,k]) + #gradient_u_asc = (u_wind[t,k,center,center] - u_wind[t,k-1,center,center])/(pres[t,k]-pres[t,k-1]) + #gradient_u_des = (u_wind[t,k+1,center,center] - u_wind[t,k,center,center])/(pres[t,k+1]-pres[t,k]) + gradient_u_asc = (smoothed_u[t,k,center,center] - smoothed_u[t,k-1,center,center])/(pres[t,k]-pres[t,k-1]) + gradient_u_des = (smoothed_u[t,k+1,center,center] - smoothed_u[t,k,center,center])/(pres[t,k+1]-pres[t,k]) + #gradient_v_asc = (v_wind[t,k,center,center] - v_wind[t,k-1,center,center])/(pres[t,k]-pres[t,k-1]) + #gradient_v_des = (v_wind[t,k+1,center,center] - v_wind[t,k,center,center])/(pres[t,k+1]-pres[t,k]) + gradient_v_asc = (smoothed_v[t,k,center,center] - smoothed_v[t,k-1,center,center])/(pres[t,k]-pres[t,k-1]) + gradient_v_des = (smoothed_v[t,k+1,center,center] - smoothed_v[t,k,center,center])/(pres[t,k+1]-pres[t,k]) + + rho = pres[t,k]/(rdgas*temp[t,k,center,center]) + adiabatic_exp_comp_term = -(w_asc + w_des)*grav/cp + v_advec_u[t,k] = rho*grav*(w_asc*gradient_u_asc + w_des*gradient_u_des) + v_advec_v[t,k] = rho*grav*(w_asc*gradient_v_asc + w_des*gradient_v_des) + v_advec_T[t,k] = rho*grav*(w_asc*gradient_T_asc + w_des*gradient_T_des) + adiabatic_exp_comp_term + v_advec_qv[t,k] = rho*grav*(w_asc*gradient_qv_asc + w_des*gradient_qv_des) + + + u_g = np.zeros((n_filesA,nlevs)) + v_g = np.zeros((n_filesA,nlevs)) + if (geos_wind_forcing): + #first calc height at the pressure levels (ignore variation in gravity for typical model levels; height ~= geopotential height) + zh = np.zeros((n_filesA,nlevs,npts,npts)) + for ii in range(npts): + for jj in range(npts): + + zh[t,0,ii,jj] = 0.5*delz[t,0,ii,jj] + for k in range(1,nlevs): + zh[t,k,ii,jj] = zh[t,k-1,ii,jj] + 0.5*delz[t,k-1,ii,jj] + 0.5*delz[t,k,ii,jj] + + mean_lat = np.mean(lat[t,:,:]) + coriolis = 2.0*Omega*np.sin(mean_lat*deg_to_rad) + for k in range(1,nlevs): + dZdx = centered_diff_derivative(zh[t,k,center,:],dx[center,:]*1.0E3) + dZdy = centered_diff_derivative(zh[t,k,:,center],dy[:,center]*1.0E3) + + u_g[t,k] = -grav/coriolis*dZdy + v_g[t,k] = grav/coriolis*dZdx + + # plot(u_g[t,:],pres[t,:],"r") + # plot(u_wind[t,:,center,center],pres[t,:],"b") + # xlabel("m/s") + # ylabel("p") + # grid(True) + # show() + # + # plot(v_g[t,:],pres[t,:],"r") + # plot(v_wind[t,:,center,center],pres[t,:],"b") + # xlabel("m/s") + # ylabel("p") + # grid(True) + # show() + + + if (False): + plot(h_advec_T[t,:]*86400.0,pres[t,:],"r") + # #y_av = movingaverage(y, 10) + plot(v_advec_T[t,:]*86400.0,pres[t,:],"b") + # #plot(w_wind_smoothed_sf, pres[t,:],"b") + xlim(86400.0*np.min(h_advec_T[t,:] + v_advec_T[t,:]),86400.0*np.max(h_advec_T[t,:] + v_advec_T[t,:])) + xlabel("K day-1") + ylabel("p") + grid(True) + show() + + plot(h_advec_qv[t,:]*86400.0*1.0E3,pres[t,:],"r") + # #y_av = movingaverage(y, 10) + plot(v_advec_qv[t,:]*86400.0*1.0E3,pres[t,:],"b") + # #plot(w_wind_smoothed_sf, pres[t,:],"b") + xlim(86400.0*1.0E3*np.min(h_advec_qv[t,:] + v_advec_qv[t,:]),86400.0*1.0E3*np.max(h_advec_qv[t,:] + v_advec_qv[t,:])) + xlabel("g kg-1 day-1") + ylabel("p") + grid(True) + show() + + plot(h_advec_u[t,:]*86400.0,pres[t,:],"r") + # #y_av = movingaverage(y, 10) + plot(v_advec_u[t,:]*86400.0,pres[t,:],"b") + # #plot(w_wind_smoothed_sf, pres[t,:],"b") + xlim(86400.0*np.min(h_advec_u[t,:] + v_advec_u[t,:]),86400.0*np.max(h_advec_u[t,:] + v_advec_u[t,:])) + xlabel("u: m s-1 day-1") + ylabel("p") + grid(True) + show() + + plot(h_advec_v[t,:]*86400.0,pres[t,:],"r") + # #y_av = movingaverage(y, 10) + plot(v_advec_v[t,:]*86400.0,pres[t,:],"b") + # #plot(w_wind_smoothed_sf, pres[t,:],"b") + xlim(86400.0*np.min(h_advec_v[t,:] + v_advec_v[t,:]),86400.0*np.max(h_advec_v[t,:] + v_advec_v[t,:])) + xlabel("v: m s-1 day-1") + ylabel("p") + grid(True) + show() + + + # grad_t = np.gradient(temp[t,:,:,:]) #grad_t output is list of components (z, y, x); each axis array has dimensions of (levs,2*n_forcing_halo_points+1,2*n_forcing_halo_points+1); we're interested in middle point for each level + # grad_qv = np.gradient(qv[t,:,:,:]) + # grad_u = np.gradient(u_wind[t,:,:,:]) + # grad_v = np.gradient(v_wind[t,:,:,:]) + #grad_t_x = np.gradient(temp[t,0,:,:], axis=1) + #grad_t_y = np.gradient(temp[t,0,:,:], axis=0) + #print(temp[t,0,:,:]) + #print(grad_t[0][0]) #dT in z direction at level 0 + #print(grad_t[1][0]) #dT in y direction at level 0 + #print(grad_t[2][0]) #dT in x direction at level 0 + #exit() + #print('dx tot',grad_t[1]) + #print('dy tot',grad_t[0]) + + #print('dx',grad_t_x) + #print('dy',grad_t_y) + + #exit() + + if (save_comp_data): + # Read in 2D UFS history files + vars2d =[{"name":"spfh2m"}, {"name":"tmp2m"}, \ + {"name":"dswrf_ave"}, {"name":"ulwrf_ave"},\ + {"name":"lhtfl_ave"}, {"name":"shtfl_ave"},\ + {"name":"dswrf"}, {"name":"ulwrf"},\ + {"name":"lhtfl"}, {"name":"shtfl"},\ + {"name":"pwat"}, {"name":"vgrd10m"},\ + {"name":"ugrd10m"}] + for var2d in vars2d: var2d["values"] = [] + + # Get list of UFS history files with 2D fields. + sfc_filenames = [] + for f_name in os.listdir(dir): + if fnmatch.fnmatch(f_name, sfc_ftag): + sfc_filenames.append(f_name) + if not sfc_filenames: + message = 'No filenames matching the pattern {0} found in {1}'. \ + format(sfc_ftag,dir) + logging.critical(message) + raise Exception(message) + sfc_filenames = sorted(sfc_filenames) + n_filesS = len(sfc_filenames) + + if (n_filesS == n_filesA): + n_files = n_filesA + else: + message = 'Number of UFS 2D/3D history files is inconsistent' + logging.critical(message) + raise Exception(message) + + for count, filename in enumerate(sfc_filenames, start=1): + nc_file = Dataset('{0}/{1}'.format(dir,filename)) + nc_file.set_always_mask(False) + + for var2d in vars2d: + data = nc_file[var2d["name"]][0,:,:] + var2d["values"].append(data[i,j]) + var2d["units"] = nc_file[var2d["name"]].getncattr(name="units") + var2d["long_name"] = nc_file[var2d["name"]].getncattr(name="long_name") + + nc_file.close() + + # Convert to numpy arrays + for var2d in vars2d: + var2d["values"] = np.asarray(var2d["values"]) + sec_in_hr = 3600. + time[0] = 0. + forcing = { + "time": time*sec_in_hr, + "wa": smoothed_w, + "ps_forc": pressfc[:,center,center], + "pa_forc": pres, + "tnta_adv": h_advec_T[:,:] + v_advec_T[:,:], + "tnqv_adv": h_advec_qv[:,:] + v_advec_qv[:,:], + "tnua_adv": h_advec_u[:,:] + v_advec_u[:,:], + "tnva_adv": h_advec_v[:,:] + v_advec_v[:,:], + "ug" : u_g[:,:], + "vg" : v_g[:,:], + "ua_nud" : u_wind[:,:,center,center], + "va_nud" : v_wind[:,:,center,center] + } + + if (save_comp_data): + comp_data = { + "time": time*sec_in_hr, + "pa" : pres, + "ta" : temp [:,:,center,center], + "qv" : qv [:,:,center,center], + "ua" : u_wind[:,:,center,center], + "va" : v_wind[:,:,center,center], + "vars2d":vars2d} + + + return (forcing, comp_data) + ######################################################################################## # ######################################################################################## def get_UFS_forcing_data(nlevs, state_IC, location, use_nearest, forcing_dir, grid_dir, - tile, i, j, lam, save_comp_data, exact_mode, cmp_total_tendency): + tile, i, j, lam, save_comp_data, exact_mode): """Get the horizontal and vertical advective tendencies for the given tile and indices""" # Determine UFS history file format (tiled/quilted) @@ -1563,7 +2281,7 @@ def get_UFS_forcing_data(nlevs, state_IC, location, use_nearest, forcing_dir, gr # Find nearest point on UFS history file (quilted) grid. if use_nearest: - (tile_jj, tile_ii, point_lon, point_lat, dist_min) = find_loc_indices(location, forcing_dir, -999, lam) + (tile_jj, tile_ii, point_lon, point_lat, dist_min, theta) = find_loc_indices(location, forcing_dir, -999, lam) print('The closest point has indices [{0},{1}]'.format(tile_ii,tile_jj)) print('This index has a central longitude/latitude of [{0},{1}]'.format(point_lon,point_lat)) print('This grid cell is approximately {0} km away from the desired location of {1} {2}'.format(dist_min/1.0E3,location[0],location[1])) @@ -2015,8 +2733,6 @@ def get_UFS_forcing_data(nlevs, state_IC, location, use_nearest, forcing_dir, gr dvdt_adv[0,:] = (dtend_v_nophys[0,:] - dvdtr[0,:]) dtdtr[0,:] = (t_layr[0,:] - state_IC["ta"][:])/dt dtdt_adv[0,:] = (dtend_temp_nophys[0,:] - dtdtr[0,:]) - elif cmp_total_tendency: - print("DJS ASKS GF: Is this where you will compute something like? dqvdt_tot = dqdtt/dt + u*dudx/dt + v*dvdy/dt") else: dqdtt = qv_lay[0,:] - state_IC["qv"][:] dqvdt_adv[0,:] = dqdtt/dt @@ -2291,7 +3007,7 @@ def get_UFS_forcing_data(nlevs, state_IC, location, use_nearest, forcing_dir, gr ######################################################################################## # ######################################################################################## -def write_SCM_case_file(state, surface, oro, forcing, init, case, date): +def write_SCM_case_file(state, surface, oro, forcing, init, case, date, forcing_method, vertical_method, geos_wind_forcing, wind_nudge): """Write all data to a netCDF file in the DEPHY-SCM format""" # Working types @@ -2306,7 +3022,7 @@ def write_SCM_case_file(state, surface, oro, forcing, init, case, date): com = 'mkdir -p ' + PROCESSED_CASE_DIR print(com) os.system(com) - fileOUT = os.path.join(PROCESSED_CASE_DIR, case + '_SCM_driver.nc') + fileOUT = os.path.join(PROCESSED_CASE_DIR, case + '_fm_{}'.format(forcing_method) + ('_vm_{}'.format(vertical_method) if forcing_method == 2 else '') + ('_geos' if geos_wind_forcing else '') + ('_wind_nudge' if wind_nudge else '') + '_SCM_driver.nc') nc_file = Dataset(fileOUT, 'w', format='NETCDF3_CLASSIC') nc_file.description = "FV3GFS model profile input (UFS forcings)" @@ -2358,11 +3074,21 @@ def write_SCM_case_file(state, surface, oro, forcing, init, case, date): nc_file.adv_qt = forcing_off nc_file.adv_rv = forcing_off nc_file.adv_rt = forcing_off - nc_file.forc_wa = forcing_off + if (vertical_method == 2): + nc_file.forc_wa = forcing_on + else: + nc_file.forc_wa = forcing_off nc_file.forc_wap = forcing_off - nc_file.forc_geo = forcing_off - nc_file.nudging_ua = forcing_off - nc_file.nudging_va = forcing_off + if (geos_wind_forcing): + nc_file.forc_geo = forcing_on + else: + nc_file.forc_geo = forcing_off + if (wind_nudge): + nc_file.nudging_ua = forcing_on*const_nudging_time + nc_file.nudging_va = forcing_on*const_nudging_time + else: + nc_file.nudging_ua = forcing_off + nc_file.nudging_va = forcing_off nc_file.nudging_ta = forcing_off nc_file.nudging_theta = forcing_off nc_file.nudging_thetal = forcing_off @@ -2393,8 +3119,9 @@ def write_SCM_case_file(state, surface, oro, forcing, init, case, date): # nc_file.adv_ta = forcing_on nc_file.adv_qv = forcing_on - nc_file.adv_ua = forcing_on - nc_file.adv_va = forcing_on + if (not geos_wind_forcing): + nc_file.adv_ua = forcing_on + nc_file.adv_va = forcing_on # nc_file.surface_forcing_temp = 'none' nc_file.surface_forcing_moisture = 'none' @@ -2495,24 +3222,20 @@ def write_SCM_case_file(state, surface, oro, forcing, init, case, date): ######################################################################################## var_dict = [{"name": "orog", "type":wp, "dimd": ('t0' ), "units": "m", "desc": "surface_altitude"},\ {"name": "zh", "type":wp, "dimd": ('t0', 'lev'), "units": "m", "desc": "height"},\ - {"name": "pa", "type":wp, "dimd": ('t0', 'lev'), "units": "Pa", "desc": "air_ressure"}, \ - {"name": "ta", "type":wp, "dimd": ('t0', 'lev'), "units": "K", "desc": "air_temperature","default_value": init["t_lay"][:], "override": True}, \ + {"name": "pa", "type":wp, "dimd": ('t0', 'lev'), "units": "Pa", "desc": "air_pressure"}, \ {"name": "theta", "type":wp, "dimd": ('t0', 'lev'), "units": "K", "desc": "air_potential_temperature"}, \ {"name": "thetal", "type":wp, "dimd": ('t0', 'lev'), "units": "K", "desc": "air_liquid_potential_temperature"}, \ {"name": "rv", "type":wp, "dimd": ('t0', 'lev'), "units": "kg kg-1", "desc": "humidity_mixing_ratio"}, \ {"name": "rl", "type":wp, "dimd": ('t0', 'lev'), "units": "kg kg-1", "desc": "cloud_liquid_water_mixing_ratio"}, \ {"name": "ri", "type":wp, "dimd": ('t0', 'lev'), "units": "kg kg-1", "desc": "cloud_ice_water_mixing_ratio"}, \ {"name": "rt", "type":wp, "dimd": ('t0', 'lev'), "units": "kg kg-1", "desc": "water_mixing_ratio"}, \ - {"name": "qv", "type":wp, "dimd": ('t0', 'lev'), "units": "kg kg-1", "desc": "specific_humidity","default_value": init["qv_lay"][:], "override": True}, \ {"name": "ql", "type":wp, "dimd": ('t0', 'lev'), "units": "kg kg-1", "desc": "mass_fraction_of_cloud_liquid_water_in_air"}, \ {"name": "qi", "type":wp, "dimd": ('t0', 'lev'), "units": "kg kg-1", "desc": "mass_fraction_of_cloud_ice_water_in_air", "default_value": 0.0}, \ {"name": "qt", "type":wp, "dimd": ('t0', 'lev'), "units": "kg kg-1", "desc": "mass_fraction_of_water_in_air"}, \ {"name": "hur", "type":wp, "dimd": ('t0', 'lev'), "units": "%", "desc": "relative_humidity"}, \ {"name": "tke", "type":wp, "dimd": ('t0', 'lev'), "units": "m2 s-2", "desc": "specific_turbulen_kinetic_energy", "default_value": 0.0}, \ - {"name": "ua", "type":wp, "dimd": ('t0', 'lev'), "units": "m s-1", "desc": "eastward_wind","default_value": init["u_lay"][:], "override": True}, \ - {"name": "va", "type":wp, "dimd": ('t0', 'lev'), "units": "m s-1", "desc": "northward_wind","default_value": init["v_lay"][:], "override": True}, \ {"name": "ts", "type":wp, "dimd": ('t0' ), "units": "K", "desc": "surface_temperature"},\ - {"name": "tskin", "type":wp, "dimd": ('t0' ), "units": "K", "desc": "surface_skin_pressure"}, \ + {"name": "tskin", "type":wp, "dimd": ('t0' ), "units": "K", "desc": "surface_skin_temperature"}, \ {"name": "ps", "type":wp, "dimd": ('t0' ), "units": "Pa", "desc": "surface_air_pressure"}, \ {"name": "beta", "type":wp, "dimd": ('t0' ), "units": "m", "desc": "soil_water_stress_factor"}, \ {"name": "mrsos", "type":wp, "dimd": ('t0' ), "units": "kg m-2", "desc": "mass_content_of_water_in_soil_layer"}, \ @@ -2522,6 +3245,17 @@ def write_SCM_case_file(state, surface, oro, forcing, init, case, date): {"name": "alb", "type":wp, "dimd": ('t0' ), "units": "1", "desc": "surface_albedo"}, \ {"name": "emis", "type":wp, "dimd": ('t0' ), "units": "1", "desc": "surface_longwave_emissivity"}, \ {"name": "slmsk", "type":wp, "dimd": ('t0' ), "units": "none", "desc": "land_sea_ice_mask"}] + if (forcing_method == 1 or forcing_method == 3): + var_dict.insert(3, {"name": "ta", "type":wp, "dimd": ('t0', 'lev'), "units": "K", "desc": "air_temperature","default_value": init["t_lay"][:], "override": True}) + var_dict.insert(10,{"name": "qv", "type":wp, "dimd": ('t0', 'lev'), "units": "kg kg-1", "desc": "specific_humidity","default_value": init["qv_lay"][:], "override": True}) + var_dict.insert(16,{"name": "ua", "type":wp, "dimd": ('t0', 'lev'), "units": "m s-1", "desc": "eastward_wind","default_value": init["u_lay"][:], "override": True}) + var_dict.insert(17,{"name": "va", "type":wp, "dimd": ('t0', 'lev'), "units": "m s-1", "desc": "northward_wind","default_value": init["v_lay"][:], "override": True}) + else: + var_dict.insert(3, {"name": "ta", "type":wp, "dimd": ('t0', 'lev'), "units": "K", "desc": "air_temperature"}) + var_dict.insert(10,{"name": "qv", "type":wp, "dimd": ('t0', 'lev'), "units": "kg kg-1", "desc": "specific_humidity"}) + var_dict.insert(16,{"name": "ua", "type":wp, "dimd": ('t0', 'lev'), "units": "m s-1", "desc": "eastward_wind"}) + var_dict.insert(17,{"name": "va", "type":wp, "dimd": ('t0', 'lev'), "units": "m s-1", "desc": "northward_wind"}) + # var_frc = [{"name": "zh_forc", "type":wp, "dimd": ('time', 'lev'), "units": "m", "desc": "height_forcing","default_value": 1.},\ {"name": "pa_forc", "type":wp, "dimd": ('time', 'lev'), "units": "Pa", "desc": "air_pressure_forcing"}, \ @@ -2758,7 +3492,8 @@ def write_comparison_file(comp_data, case_name, date, surface): # Dimensions lev_dim = nc_file.createDimension('lev', size=nlevs) time_dim = nc_file.createDimension('time', size=ntime) - time_ufs_history_dim = nc_file.createDimension('time_ufs_history', size=ntime-1) + #time_ufs_history_dim = nc_file.createDimension('time_ufs_history', size=ntime-1) #GJF why are we ignoring the first history file? + time_ufs_history_dim = nc_file.createDimension('time_ufs_history', size=ntime) # Varaibles time_var = nc_file.createVariable('time', wp, ('time',)) @@ -2769,7 +3504,7 @@ def write_comparison_file(comp_data, case_name, date, surface): time2_var = nc_file.createVariable('time_ufs_history', wp, ('time_ufs_history',)) time2_var.units = 'second' time2_var.long_name = 'UFS history file time' - time2_var[:] = comp_data['time'][1::] + time2_var[:] = comp_data['time'] lev_var = nc_file.createVariable('levs', wp, ('time','lev',)) lev_var.units = 'Pa' @@ -2849,36 +3584,39 @@ def main(): #read in arguments (location, indices, date, in_dir, grid_dir, forcing_dir, tile, area, case_name, - old_chgres, lam, save_comp, use_nearest, exact_mode, cmp_total_tendency) = parse_arguments() + old_chgres, lam, save_comp, use_nearest, forcing_method, vertical_method, geos_wind_forcing, wind_nudge) = parse_arguments() + + #find indices corresponding to both UFS history files and initial condition (IC) files + (hist_i, hist_j, hist_lon, hist_lat, hist_dist_min, angle_to_hist_point, neighbors, dx, dy) = find_loc_indices_UFS_history(location, forcing_dir) + + (IC_i, IC_j, tile, IC_lon, IC_lat, IC_dist_min, angle_to_IC_point) = find_loc_indices_UFS_IC(location, grid_dir, lam, tile, indices) - #find tile containing the point using the supergrid if no tile is specified - #if not tile and not lam: - if not tile: - tile = int(find_tile(location, grid_dir, lam)) - if tile < 0: - message = 'No tile was found for location {0}'.format(location) - logging.critical(message) - raise Exception(message) - print('Tile found: {0}'.format(tile)) + #compare the locations of the found history file point and UFS IC point + compare_hist_and_IC_points(location, hist_lon, hist_lat, IC_lon, IC_lat, hist_dist_min, angle_to_hist_point, IC_dist_min, angle_to_IC_point) - #find index of closest point in the tile if indices are not specified - if not indices: - (tile_j, tile_i, point_lon, point_lat, dist_min) = find_loc_indices(location, grid_dir, tile, lam) - print('The closest point in tile {0} has indices [{1},{2}]'.format(tile,tile_i,tile_j)) - print('This index has a central longitude/latitude of [{0},{1}]'.format(point_lon,point_lat)) - print('This grid cell is approximately {0} km away from the desired location of {1} {2}'.format(dist_min/1.0E3,location[0],location[1])) + #read in surface data for the intial conditions at the IC point + surface_data = get_UFS_surface_data(in_dir, tile, IC_i, IC_j, old_chgres, lam) + + #when using the advective forcing methods, initial conditions are taken from the history files; check that the history file surface type is the same as the UFS IC point from which data is read + check_IC_hist_surface_compatibility(forcing_dir, hist_i, hist_j, surface_data, lam, old_chgres, tile) + + #read in orographic data for the initial conditions at the IC point + oro_data = get_UFS_oro_data(in_dir, tile, IC_i, IC_j, lam) + + #read in the initial condition profiles + + if (forcing_method == 1 or forcing_method == 4): + #read initial condition profiles from UFS IC files + (state_data, error_msg) = get_IC_data_from_UFS_ICs(in_dir, grid_dir, tile, IC_i,\ + IC_j, old_chgres, lam) else: - tile_i = indices[0] - tile_j = indices[1] - #still need to grab the lon/lat if the tile and indices are supplied - (point_lon, point_lat) = find_lon_lat_of_indices(indices, grid_dir, tile, lam) - - print('This index has a central longitude/latitude of [{0},{1}]'.format(point_lon,point_lat)) + #read initial condition profiles from UFS history files (not true "initial" conditions, but after first UFS timestep) + state_data = get_IC_data_from_UFS_history(forcing_dir, hist_i, hist_j, lam, tile) + error_msg = '' # get UFS IC data (TODO: flag to read in RESTART data rather than IC data and implement # different file reads) - (state_data, surface_data, oro_data, error_msg) = get_UFS_IC_data(in_dir, grid_dir, tile, tile_i,\ - tile_j, old_chgres, lam) + if (error_msg): print("ERROR: unknown grid orintation") exit() @@ -2887,22 +3625,37 @@ def main(): # date was not included on command line; look in atmf* file for initial date date = find_date(forcing_dir) - #get grid cell area if not given if not area: - area = get_UFS_grid_area(grid_dir, tile, tile_i, tile_j, lam) + area = get_UFS_grid_area(grid_dir, tile, IC_i, IC_j, lam) surface_data["area"] = area - surface_data["lon"] = point_lon - surface_data["lat"] = point_lat + surface_data["lon"] = hist_lon + surface_data["lat"] = hist_lat # Get UFS forcing data - (forcing_data, comp_data, stateInit) = get_UFS_forcing_data(state_data["nlevs"], state_data, \ - location, use_nearest, forcing_dir, \ - grid_dir, tile, tile_i, tile_j, lam,\ - save_comp, exact_mode, cmp_total_tendency) + stateInit = {} + if forcing_method == 1: + exact_mode = True + (forcing_data, comp_data, stateInit) = get_UFS_forcing_data(state_data["nlevs"], state_data, \ + location, use_nearest, forcing_dir, \ + grid_dir, tile, IC_i, IC_j, lam,\ + save_comp, exact_mode) + elif forcing_method == 2: + (forcing_data, comp_data) = get_UFS_forcing_data_advective_tendency(forcing_dir, hist_i, hist_j, tile, neighbors, dx, dy, state_data["nlevs"], lam, save_comp, vertical_method, geos_wind_forcing, wind_nudge) + elif forcing_method == 3: + exact_mode = False + (forcing_data, comp_data, stateInit) = get_UFS_forcing_data(state_data["nlevs"], state_data, \ + location, use_nearest, forcing_dir, \ + grid_dir, tile, IC_i, IC_j, lam,\ + save_comp, exact_mode) + else: + message = "Unsupported forcing_method chosen" + logging.critical(message) + raise Exception(message) + # Write SCM case file - fileOUT = write_SCM_case_file(state_data, surface_data, oro_data, forcing_data, stateInit, case_name, date) + fileOUT = write_SCM_case_file(state_data, surface_data, oro_data, forcing_data, stateInit, case_name, date, forcing_method, vertical_method, geos_wind_forcing, wind_nudge) # read in and remap the state variables to the first history file pressure profile and # write them out to compare SCM output to (atmf for state variables and sfcf for physics diff --git a/scm/etc/scripts/UFS_forcing_ensemble_generator.py b/scm/etc/scripts/UFS_forcing_ensemble_generator.py index 8409786a4..e054dede6 100755 --- a/scm/etc/scripts/UFS_forcing_ensemble_generator.py +++ b/scm/etc/scripts/UFS_forcing_ensemble_generator.py @@ -136,7 +136,7 @@ def main(): {"name": "dt", "values": str(args.timestep)}, \ {"name": "C_RES", "values": str(args.C_RES)}] - # What, if any, options neeed to be passsed to UFS_IC_generator.py? + # What, if any, options neeed to be passsed to UFS_case_gen.py? com_config = '' if args.save_comp: com_config = com_config + ' -sc' if args.use_nearest: com_config = com_config + ' -near' @@ -149,10 +149,10 @@ def main(): count = 0 run_list = [] for pt in range(0,npts): - # Call UFS_IC_generator.py + # Call UFS_case_gen.py case_name = args.case_name +"_n" + str(pt).zfill(3) file_scminput = "../../data/processed_case_input/"+case_name+"_SCM_driver.nc" - com = "./UFS_IC_generator.py -l " +str(lons[pt]) + " " + str(lats[pt]) + \ + com = "./UFS_case_gen.py -l " +str(lons[pt]) + " " + str(lats[pt]) + \ " -i " + args.dir_ic + " -g " + args.dir_grid + " -f " + args.dir_forcing + " -n " + case_name + com_config print(com) os.system(com) From 53b039d9ebde5d2ee0ef9ee838a22beedf3855f6 Mon Sep 17 00:00:00 2001 From: Dustin Swales Date: Fri, 7 Jun 2024 16:12:13 +0000 Subject: [PATCH 04/25] Add more diagnostics. Add bug in bugfix that was removed! --- scm/etc/scripts/UFS_IC_generator.py | 42 +++++++++++++++++++++++++++-- scm/src/scm_input.F90 | 1 + 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/scm/etc/scripts/UFS_IC_generator.py b/scm/etc/scripts/UFS_IC_generator.py index 7c8d7d1a9..5c296bd93 100755 --- a/scm/etc/scripts/UFS_IC_generator.py +++ b/scm/etc/scripts/UFS_IC_generator.py @@ -1710,6 +1710,15 @@ def get_UFS_forcing_data(nlevs, state_IC, location, use_nearest, forcing_dir, gr {"name":"dtend_qv_nophys", "diag_table":'"gfs_dyn", "dtend_qv_nophys", "dtend_qv_nophys", "fv3_history", "all", .false., "none", 2'}] for dyntend in dyntends: dyntend["values"] = [] + # Optional diagnostic to be copied into UFS comparison file + phystends = [{"name":"dtend_temp_lw"}, {"name":"dtend_temp_sw"}, {"name":"dtend_temp_pbl"}, {"name":"dtend_temp_deepcnv"},\ + {"name":"dtend_temp_shalcnv"},{"name":"dtend_temp_mp"}, {"name":"dtend_temp_orogwd"},{"name":"dtend_temp_phys"}, \ + {"name":"dtend_u_pbl"}, {"name":"dtend_v_pbl"}, {"name":"dtend_u_orogwd"}, {"name":"dtend_v_orogwd"}, \ + {"name":"dtend_u_deepcnv"}, {"name":"dtend_v_deepcnv"},{"name":"dtend_u_shalcnv"}, {"name":"dtend_v_shalcnv"}, \ + {"name":"dtend_u_phys"}, {"name":"dtend_v_phys"}, {"name":"dtend_qv_pbl"}, {"name":"dtend_qv_deepcnv"}, \ + {"name":"dtend_qv_shalcnv"}, {"name":"dtend_qv_mp"}, {"name":"dtend_qv_phys"}, {"name":"dtend_poop"}] + for phystend in phystends: phystend["values"] = [] + # Variables to be added to "UFS comparison file" vars2d =[{"name":"spfh2m"}, {"name":"tmp2m"}, {"name":"dswrf_ave"}, \ {"name":"ulwrf_ave"}, {"name":"lhtfl_ave"}, {"name":"shtfl_ave"}, \ @@ -1788,6 +1797,21 @@ def get_UFS_forcing_data(nlevs, state_IC, location, use_nearest, forcing_dir, gr dyntend["missing"] = True # end if # end for + for phystend in phystends: + if phystend["name"] in nc_file.variables.keys(): + if not use_nearest: + data = regridder(nc_file[phystend["name"]][0,::-1,:,:]) + else: + data = nc_file[phystend["name"]][0,::-1,:,:] + # end if (use-nearest) + phystend["values"].append(data[:,j_get,i_get]) + phystend["units"] = nc_file[phystend["name"]].getncattr(name="units") + phystend["long_name"] = nc_file[phystend["name"]].getncattr(name="long_name") + phystend["missing"] = False + else: + phystend["missing"] = True + # end if + # end for nc_file.close() # end for @@ -1847,7 +1871,12 @@ def get_UFS_forcing_data(nlevs, state_IC, location, use_nearest, forcing_dir, gr dtend_v_nophys = dyntends[2]["values"] dtend_qv_nophys = dyntends[3]["values"] # end if (exact-mode) - + for phystend in phystends: + if (not phystend["missing"]): + phystend["values"] = np.asarray(phystend["values"]) + # end if + # end for + #################################################################################### # # The "total" advection, where "total" = "advective + remapping", can be computed @@ -2282,7 +2311,8 @@ def get_UFS_forcing_data(nlevs, state_IC, location, use_nearest, forcing_dir, gr "qv" : qv_layers_at_pres1, "ua" : u_layers_at_pres1, "va" : v_layers_at_pres1, - "vars2d":[]} + "vars2d":[], + "phystends":phystends} else: comp_data = {} @@ -2802,6 +2832,14 @@ def write_comparison_file(comp_data, case_name, date, surface): tempVar.long_name = var2d["long_name"] tempVar[:] = var2d["values"] + for phystend in comp_data["phystends"]: + if (not phystend["missing"]): + tempVar = nc_file.createVariable(phystend["name"], wp, ('time', 'lev',)) + tempVar.units = phystend["units"] + tempVar.long_name = phystend["long_name"] + tempVar[:] = phystend["values"] + # end if + # end for nc_file.close() return diff --git a/scm/src/scm_input.F90 b/scm/src/scm_input.F90 index cc3effcd5..12d055f3c 100644 --- a/scm/src/scm_input.F90 +++ b/scm/src/scm_input.F90 @@ -1969,6 +1969,7 @@ subroutine get_case_init_DEPHY(scm_state, scm_input) if (trim(input_surfaceForcingLSM) == "lsm") then scm_input%input_ozone = input_ozone(:,active_init_time) scm_input%input_area = input_area(active_init_time) + scm_state%area = input_area(active_init_time) scm_input%input_stddev = input_stddev(active_init_time) scm_input%input_convexity= input_convexity(active_init_time) From f9e75d00a018871ab22991264a9f27a91d3bd050 Mon Sep 17 00:00:00 2001 From: Dustin Swales Date: Fri, 7 Jun 2024 18:23:55 +0000 Subject: [PATCH 05/25] Update wrapper interface --- scm/etc/scripts/UFS_case_gen.py | 83 +++++++++---------- .../scripts/UFS_forcing_ensemble_generator.py | 36 ++++---- 2 files changed, 58 insertions(+), 61 deletions(-) diff --git a/scm/etc/scripts/UFS_case_gen.py b/scm/etc/scripts/UFS_case_gen.py index 80fd04ee5..cc544cba1 100755 --- a/scm/etc/scripts/UFS_case_gen.py +++ b/scm/etc/scripts/UFS_case_gen.py @@ -14,8 +14,7 @@ import fv3_remap import xesmf from datetime import datetime, timedelta -from pylab import plot, ylim, xlim, show, xlabel, ylabel, grid - +#from matplotlib import plot, ylim, xlim, show, xlabel, ylabel, grid ############################################################################### # Global settings # @@ -2073,46 +2072,46 @@ def get_UFS_forcing_data_advective_tendency(dir, i, j, tile, neighbors, dx, dy, # show() - if (False): - plot(h_advec_T[t,:]*86400.0,pres[t,:],"r") - # #y_av = movingaverage(y, 10) - plot(v_advec_T[t,:]*86400.0,pres[t,:],"b") - # #plot(w_wind_smoothed_sf, pres[t,:],"b") - xlim(86400.0*np.min(h_advec_T[t,:] + v_advec_T[t,:]),86400.0*np.max(h_advec_T[t,:] + v_advec_T[t,:])) - xlabel("K day-1") - ylabel("p") - grid(True) - show() - - plot(h_advec_qv[t,:]*86400.0*1.0E3,pres[t,:],"r") - # #y_av = movingaverage(y, 10) - plot(v_advec_qv[t,:]*86400.0*1.0E3,pres[t,:],"b") - # #plot(w_wind_smoothed_sf, pres[t,:],"b") - xlim(86400.0*1.0E3*np.min(h_advec_qv[t,:] + v_advec_qv[t,:]),86400.0*1.0E3*np.max(h_advec_qv[t,:] + v_advec_qv[t,:])) - xlabel("g kg-1 day-1") - ylabel("p") - grid(True) - show() - - plot(h_advec_u[t,:]*86400.0,pres[t,:],"r") - # #y_av = movingaverage(y, 10) - plot(v_advec_u[t,:]*86400.0,pres[t,:],"b") - # #plot(w_wind_smoothed_sf, pres[t,:],"b") - xlim(86400.0*np.min(h_advec_u[t,:] + v_advec_u[t,:]),86400.0*np.max(h_advec_u[t,:] + v_advec_u[t,:])) - xlabel("u: m s-1 day-1") - ylabel("p") - grid(True) - show() - - plot(h_advec_v[t,:]*86400.0,pres[t,:],"r") - # #y_av = movingaverage(y, 10) - plot(v_advec_v[t,:]*86400.0,pres[t,:],"b") - # #plot(w_wind_smoothed_sf, pres[t,:],"b") - xlim(86400.0*np.min(h_advec_v[t,:] + v_advec_v[t,:]),86400.0*np.max(h_advec_v[t,:] + v_advec_v[t,:])) - xlabel("v: m s-1 day-1") - ylabel("p") - grid(True) - show() +# if (False): +# plot(h_advec_T[t,:]*86400.0,pres[t,:],"r") +# # #y_av = movingaverage(y, 10) +# plot(v_advec_T[t,:]*86400.0,pres[t,:],"b") +# # #plot(w_wind_smoothed_sf, pres[t,:],"b") +# xlim(86400.0*np.min(h_advec_T[t,:] + v_advec_T[t,:]),86400.0*np.max(h_advec_T[t,:] + v_advec_T[t,:])) +# xlabel("K day-1") +# ylabel("p") +# grid(True) +# show() +# +# plot(h_advec_qv[t,:]*86400.0*1.0E3,pres[t,:],"r") +# # #y_av = movingaverage(y, 10) +# plot(v_advec_qv[t,:]*86400.0*1.0E3,pres[t,:],"b") +# # #plot(w_wind_smoothed_sf, pres[t,:],"b") +# xlim(86400.0*1.0E3*np.min(h_advec_qv[t,:] + v_advec_qv[t,:]),86400.0*1.0E3*np.max(h_advec_qv[t,:] + v_advec_qv[t,:])) +# xlabel("g kg-1 day-1") +# ylabel("p") +# grid(True) +# show() +# +# plot(h_advec_u[t,:]*86400.0,pres[t,:],"r") +# # #y_av = movingaverage(y, 10) +# plot(v_advec_u[t,:]*86400.0,pres[t,:],"b") +# # #plot(w_wind_smoothed_sf, pres[t,:],"b") +# xlim(86400.0*np.min(h_advec_u[t,:] + v_advec_u[t,:]),86400.0*np.max(h_advec_u[t,:] + v_advec_u[t,:])) +# xlabel("u: m s-1 day-1") +# ylabel("p") +# grid(True) +# show() +# +# plot(h_advec_v[t,:]*86400.0,pres[t,:],"r") +# # #y_av = movingaverage(y, 10) +# plot(v_advec_v[t,:]*86400.0,pres[t,:],"b") +# # #plot(w_wind_smoothed_sf, pres[t,:],"b") +# xlim(86400.0*np.min(h_advec_v[t,:] + v_advec_v[t,:]),86400.0*np.max(h_advec_v[t,:] + v_advec_v[t,:])) +# xlabel("v: m s-1 day-1") +# ylabel("p") +# grid(True) +# show() # grad_t = np.gradient(temp[t,:,:,:]) #grad_t output is list of components (z, y, x); each axis array has dimensions of (levs,2*n_forcing_halo_points+1,2*n_forcing_halo_points+1); we're interested in middle point for each level diff --git a/scm/etc/scripts/UFS_forcing_ensemble_generator.py b/scm/etc/scripts/UFS_forcing_ensemble_generator.py index e054dede6..c84472cf5 100755 --- a/scm/etc/scripts/UFS_forcing_ensemble_generator.py +++ b/scm/etc/scripts/UFS_forcing_ensemble_generator.py @@ -14,21 +14,20 @@ # Argument list ############################################################################### parser = argparse.ArgumentParser() -parser.add_argument('-d', '--dir', help='path to UFS Regression Test output', required=True) -parser.add_argument('-n', '--case_name', help='name of case', required=True) -parser.add_argument('-lonl', '--lon_limits', help='longitude range, separated by a space', nargs=2, type=float, required=False) -parser.add_argument('-latl', '--lat_limits', help='latitude range, separated by a space', nargs=2, type=float, required=False) -parser.add_argument('-lons', '--lon_list', help='longitudes, separated by a space', nargs='*', type=float, required=False) -parser.add_argument('-lats', '--lat_list', help='latitudes, separated by a space', nargs='*', type=float, required=False) -parser.add_argument('-fxy', '--lonlat_file', help='file containing longitudes and latitude',nargs=1, required=False) -parser.add_argument('-nens', '--nensmembers', help='number of SCM UFS ensemble memebers to create', type=int, required=False) -parser.add_argument('-dt', '--timestep', help='SCM timestep, in seconds', type=int, default = 3600) -parser.add_argument('-cres', '--C_RES', help='UFS spatial resolution', type=int, default = 96) -parser.add_argument('-sdf', '--suite', help='CCPP suite definition file to use for ensemble', default = 'SCM_GFS_v16') -parser.add_argument('-sc', '--save_comp', help='flag to save a file with UFS data for comparisons', action='store_true') -parser.add_argument('-near', '--use_nearest', help='flag to indicate using the nearest UFS history file gridpoint, no regridding',action='store_true') -parser.add_argument('-ext', '--exact_mode', help='flag to indicate using dynamic tendencies from UFS history files', action='store_true') -parser.add_argument('-tott', '--total_tend', help='flag to indicate forcing to derive', action='store_true') +parser.add_argument('-d', '--dir', help='path to UFS Regression Test output', required=True) +parser.add_argument('-n', '--case_name', help='name of case', required=True) +parser.add_argument('-lonl', '--lon_limits', help='longitude range, separated by a space', nargs=2, type=float, required=False) +parser.add_argument('-latl', '--lat_limits', help='latitude range, separated by a space', nargs=2, type=float, required=False) +parser.add_argument('-lons', '--lon_list', help='longitudes, separated by a space', nargs='*', type=float, required=False) +parser.add_argument('-lats', '--lat_list', help='latitudes, separated by a space', nargs='*', type=float, required=False) +parser.add_argument('-fxy', '--lonlat_file', help='file containing longitudes and latitude',nargs=1, required=False) +parser.add_argument('-nens', '--nensmembers', help='number of SCM UFS ensemble memebers to create', type=int, required=False) +parser.add_argument('-dt', '--timestep', help='SCM timestep, in seconds', type=int, default = 3600) +parser.add_argument('-cres', '--C_RES', help='UFS spatial resolution', type=int, default = 96) +parser.add_argument('-sdf', '--suite', help='CCPP suite definition file to use for ensemble', default = 'SCM_GFS_v16') +parser.add_argument('-sc', '--save_comp', help='flag to save a file with UFS data for comparisons', action='store_true') +parser.add_argument('-near', '--use_nearest', help='flag to indicate using the nearest UFS history file gridpoint, no regridding',action='store_true') +parser.add_argument('-fm', '--forcing_method', help='method used to calculate forcing (1=total tendencies from UFS dycore, 2=advective terms calculated from UFS history files, 3=total time tendency terms calculated)', type=int, choices=range(1,4), default=2) ############################################################################### # Main program @@ -138,10 +137,9 @@ def main(): # What, if any, options neeed to be passsed to UFS_case_gen.py? com_config = '' - if args.save_comp: com_config = com_config + ' -sc' - if args.use_nearest: com_config = com_config + ' -near' - if args.exact_mode: com_config = com_config + ' -ext' - if args.total_tend: com_config = com_config + ' -tott' + if args.save_comp: com_config = com_config + ' -sc' + if args.use_nearest: com_config = com_config + ' -near' + if args.forcing_method: com_config = com_config + ' -fm ' + str(args.forcing_method) # Create inputs to SCM case_list = "" From 64334bb32289bd3bcb157cbd5d62d7da38fd7c56 Mon Sep 17 00:00:00 2001 From: Grant Firl Date: Fri, 7 Jun 2024 14:56:46 -0400 Subject: [PATCH 06/25] fix IC bug for fm=3 --- scm/etc/scripts/UFS_case_gen.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scm/etc/scripts/UFS_case_gen.py b/scm/etc/scripts/UFS_case_gen.py index cc544cba1..5cb15f93c 100755 --- a/scm/etc/scripts/UFS_case_gen.py +++ b/scm/etc/scripts/UFS_case_gen.py @@ -3642,7 +3642,7 @@ def main(): #read in the initial condition profiles - if (forcing_method == 1 or forcing_method == 4): + if (forcing_method == 1 or forcing_method == 3): #read initial condition profiles from UFS IC files (state_data, error_msg) = get_IC_data_from_UFS_ICs(in_dir, grid_dir, tile, IC_i,\ IC_j, old_chgres, lam) From ca969249f1e75c58b19d79a03833a47716145e02 Mon Sep 17 00:00:00 2001 From: Dustin Swales Date: Fri, 7 Jun 2024 20:00:59 +0000 Subject: [PATCH 07/25] Last fixes to harmonize two scripts. Revert name change to proccessed_case_input file name (This was inconsistent with the comparision file name and config file) --- scm/etc/scripts/UFS_case_gen.py | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/scm/etc/scripts/UFS_case_gen.py b/scm/etc/scripts/UFS_case_gen.py index 5cb15f93c..9405927b7 100755 --- a/scm/etc/scripts/UFS_case_gen.py +++ b/scm/etc/scripts/UFS_case_gen.py @@ -2435,7 +2435,7 @@ def get_UFS_forcing_data(nlevs, state_IC, location, use_nearest, forcing_dir, gr {"name":"dtend_u_phys"}, {"name":"dtend_v_phys"}, {"name":"dtend_qv_pbl"}, {"name":"dtend_qv_deepcnv"}, \ {"name":"dtend_qv_shalcnv"}, {"name":"dtend_qv_mp"}, {"name":"dtend_qv_phys"}, {"name":"dtend_poop"}] for phystend in phystends: phystend["values"] = [] - + # Variables to be added to "UFS comparison file" vars2d =[{"name":"spfh2m"}, {"name":"tmp2m"}, {"name":"dswrf_ave"}, \ {"name":"ulwrf_ave"}, {"name":"lhtfl_ave"}, {"name":"shtfl_ave"}, \ @@ -3051,7 +3051,7 @@ def write_SCM_case_file(state, surface, oro, forcing, init, case, date, forcing_ com = 'mkdir -p ' + PROCESSED_CASE_DIR print(com) os.system(com) - fileOUT = os.path.join(PROCESSED_CASE_DIR, case + '_fm_{}'.format(forcing_method) + ('_vm_{}'.format(vertical_method) if forcing_method == 2 else '') + ('_geos' if geos_wind_forcing else '') + ('_wind_nudge' if wind_nudge else '') + '_SCM_driver.nc') + fileOUT = os.path.join(PROCESSED_CASE_DIR, case + '_SCM_driver.nc') nc_file = Dataset(fileOUT, 'w', format='NETCDF3_CLASSIC') nc_file.description = "FV3GFS model profile input (UFS forcings)" @@ -3491,7 +3491,7 @@ def write_SCM_case_file(state, surface, oro, forcing, init, case, date, forcing_ return(fileOUT) ######################################################################################## -def write_comparison_file(comp_data, case_name, date, surface): +def write_comparison_file(comp_data, case_name, date, surface, forcing_method): """Write UFS history file data to netCDF file for comparison""" wp = np.float64 @@ -3566,14 +3566,16 @@ def write_comparison_file(comp_data, case_name, date, surface): tempVar.long_name = var2d["long_name"] tempVar[:] = var2d["values"] - for phystend in comp_data["phystends"]: - if (not phystend["missing"]): - tempVar = nc_file.createVariable(phystend["name"], wp, ('time', 'lev',)) - tempVar.units = phystend["units"] - tempVar.long_name = phystend["long_name"] - tempVar[:] = phystend["values"] - # end if - # end for + if (forcing_method == 1 or forcing_method == 3): + for phystend in comp_data["phystends"]: + if (not phystend["missing"]): + tempVar = nc_file.createVariable(phystend["name"], wp, ('time', 'lev',)) + tempVar.units = phystend["units"] + tempVar.long_name = phystend["long_name"] + tempVar[:] = phystend["values"] + # end if + # end for + # end if nc_file.close() return @@ -3698,7 +3700,7 @@ def main(): # write them out to compare SCM output to (atmf for state variables and sfcf for physics # tendencies) if (save_comp): - write_comparison_file(comp_data, case_name, date, surface_data) + write_comparison_file(comp_data, case_name, date, surface_data, forcing_method) if __name__ == '__main__': main() From be8d415a2da9121fe19ae4010daf24b8e99fd9ff Mon Sep 17 00:00:00 2001 From: Dustin Swales Date: Fri, 7 Jun 2024 20:35:58 +0000 Subject: [PATCH 08/25] Pass through all configuration options from wrapper script to case generation script. --- scm/etc/scripts/UFS_forcing_ensemble_generator.py | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/scm/etc/scripts/UFS_forcing_ensemble_generator.py b/scm/etc/scripts/UFS_forcing_ensemble_generator.py index c84472cf5..26b15e89a 100755 --- a/scm/etc/scripts/UFS_forcing_ensemble_generator.py +++ b/scm/etc/scripts/UFS_forcing_ensemble_generator.py @@ -28,6 +28,9 @@ parser.add_argument('-sc', '--save_comp', help='flag to save a file with UFS data for comparisons', action='store_true') parser.add_argument('-near', '--use_nearest', help='flag to indicate using the nearest UFS history file gridpoint, no regridding',action='store_true') parser.add_argument('-fm', '--forcing_method', help='method used to calculate forcing (1=total tendencies from UFS dycore, 2=advective terms calculated from UFS history files, 3=total time tendency terms calculated)', type=int, choices=range(1,4), default=2) +parser.add_argument('-vm', '--vertical_method',help='method used to calculate vertical advective forcing (1=vertical advective terms calculated from UFS history files and added to total, 2=smoothed vertical velocity provided)', type=int, choices=range(1,3), default=2) +parser.add_argument('-wn', '--wind_nudge', help='flag to turn on wind nudging to UFS profiles', action='store_true') +parser.add_argument('-geos', '--geostrophic', help='flag to turn on geostrophic wind forcing', action='store_true') ############################################################################### # Main program @@ -137,9 +140,12 @@ def main(): # What, if any, options neeed to be passsed to UFS_case_gen.py? com_config = '' - if args.save_comp: com_config = com_config + ' -sc' - if args.use_nearest: com_config = com_config + ' -near' - if args.forcing_method: com_config = com_config + ' -fm ' + str(args.forcing_method) + if args.save_comp: com_config = com_config + ' -sc' + if args.use_nearest: com_config = com_config + ' -near' + if args.forcing_method: com_config = com_config + ' -fm ' + str(args.forcing_method) + if args.vertical_method: com_config = com_config + ' -vm ' + str(args.vertical_method) + if args.wind_nudge: com_config = com_config + ' -wn' + if args.geostrophic: com_config = com_config + ' -geos' # Create inputs to SCM case_list = "" From 69a99be0c7cf4849a2e0aee96fe843a4aa8bb566 Mon Sep 17 00:00:00 2001 From: Dustin Swales Date: Fri, 7 Jun 2024 21:40:53 +0000 Subject: [PATCH 09/25] Use unregridded data in UFS comparison file for fm=1=3 (same as fm=2) --- scm/etc/scripts/UFS_case_gen.py | 57 ++++----------------------------- 1 file changed, 6 insertions(+), 51 deletions(-) diff --git a/scm/etc/scripts/UFS_case_gen.py b/scm/etc/scripts/UFS_case_gen.py index 9405927b7..99f935776 100755 --- a/scm/etc/scripts/UFS_case_gen.py +++ b/scm/etc/scripts/UFS_case_gen.py @@ -2813,51 +2813,6 @@ def get_UFS_forcing_data(nlevs, state_IC, location, use_nearest, forcing_dir, gr pres_adv[t+2,:] = pres_adv[t+1,:] pres_i_adv[t+2,:] = pres_i_adv[t+1,:] - #################################################################################### - # Save UFS data for comparison with SCM output. - #################################################################################### - if (save_comp_data): - # Initialize - t_layers_at_pres1_rev = np.zeros([t_lay.shape[0],1,t_lay.shape[1]]) - qv_layers_at_pres1_rev = np.zeros([qv_lay.shape[0],1,qv_lay.shape[1]]) - u_layers_at_pres1_rev = np.zeros([u_lay.shape[0],1,u_lay.shape[1]]) - v_layers_at_pres1_rev = np.zeros([v_lay.shape[0],1,u_lay.shape[1]]) - p_layers_at_pres1_rev = np.zeros([v_lay.shape[0],1,u_lay.shape[1]]) - from_log_pres_rev = np.zeros([1,p_lev.shape[1]]) - to_log_pres_rev = np.zeros([1,p_lev.shape[1]]) - from_pres_rev = np.zeros([1,p_lev.shape[1]]) - to_pres_rev = np.zeros([1,p_lev.shape[1]]) - dp2 = np.zeros([1,qv_lay.shape[1]]) - - # First timestep... - t_layers_at_pres1_rev[0,0,:] = t_lay[0,::-1] - qv_layers_at_pres1_rev[0,0,:] = qv_lay[0,::-1] - u_layers_at_pres1_rev[0,0,:] = u_lay[0,::-1] - v_layers_at_pres1_rev[0,0,:] = v_lay[0,::-1] - p_layers_at_pres1_rev[0,0,:] = p_lay[0,::-1] - - # Subsequent timestpes... - for t in range(1,t_lay.shape[0]): - from_log_pres_rev[0,:] = np.log(p_lev[t,::-1]) - to_log_pres_rev[0,:] = np.log(p_lev[0,::-1]) - from_pres_rev[0,:] = p_lev[t,::-1] - to_pres_rev[0,:] = p_lev[0,::-1] - for k in range(0,qv_lay.shape[1]): - dp2[0,k] = to_pres_rev[0,k+1] - to_pres_rev[0,k] - # end for - t_layers_at_pres1_rev[t,:,:] = fv3_remap.map_scalar(p_lay.shape[1], from_log_pres_rev, t_lay[t,np.newaxis,::-1], dummy, p_lay.shape[1], to_log_pres_rev, 0, 0, 1, np.abs(kord_tm), t_min) - qv_layers_at_pres1_rev[t,:,:] = fv3_remap.map1_q2(p_lay.shape[1], from_pres_rev, qv_lay[t,np.newaxis,::-1], p_lay.shape[1], to_pres_rev, dp2, 0, 0, 0, kord_tr, q_min) - u_layers_at_pres1_rev[t,:,:] = fv3_remap.map1_ppm(p_lay.shape[1], from_pres_rev, u_lay[t,np.newaxis,::-1], 0.0, p_lay.shape[1], to_pres_rev, 0, 0, -1, kord_tm) - v_layers_at_pres1_rev[t,:,:] = fv3_remap.map1_ppm(p_lay.shape[1], from_pres_rev, v_lay[t,np.newaxis,::-1], 0.0, p_lay.shape[1], to_pres_rev, 0, 0, -1, kord_tm) - p_layers_at_pres1_rev[t,:,:] = p_lay[0,::-1] - # end for - t_layers_at_pres1 = t_layers_at_pres1_rev[:,0,::-1] - qv_layers_at_pres1 = qv_layers_at_pres1_rev[:,0,::-1] - u_layers_at_pres1 = u_layers_at_pres1_rev[:,0,::-1] - v_layers_at_pres1 = v_layers_at_pres1_rev[:,0,::-1] - p_layers_at_pres1 = p_layers_at_pres1_rev[:,0,::-1] - # end if (save_comp_data) - #################################################################################### # # if we had atmf,sfcf files at every timestep (and the SCM timestep is made to match @@ -3021,12 +2976,12 @@ def get_UFS_forcing_data(nlevs, state_IC, location, use_nearest, forcing_dir, gr time_hr[0] = 0.0 comp_data = { "time" : time_hr*sec_in_hr, - "pa" : p_layers_at_pres1, - "ta" : t_layers_at_pres1, - "qv" : qv_layers_at_pres1, - "ua" : u_layers_at_pres1, - "va" : v_layers_at_pres1, - "vars2d":[], + "pa" : p_lay,#[:,::-1], + "ta" : t_lay,#[:,::-1], + "qv" : qv_lay,#[:,::-1], + "ua" : u_lay,#[:,::-1], + "va" : v_lay,#[:,::-1], + "vars2d":vars2d, "phystends":phystends} else: comp_data = {} From 805438582898865738a7f81ee28436030fd1ba32 Mon Sep 17 00:00:00 2001 From: Grant Firl Date: Mon, 8 Jul 2024 14:55:00 -0400 Subject: [PATCH 10/25] fix geostrophic winds in UFS_case_gen.py and enable writing out more comparison variables for fm==2 --- scm/etc/scripts/UFS_case_gen.py | 215 ++++++++++---------------------- 1 file changed, 63 insertions(+), 152 deletions(-) diff --git a/scm/etc/scripts/UFS_case_gen.py b/scm/etc/scripts/UFS_case_gen.py index 99f935776..02aac678c 100755 --- a/scm/etc/scripts/UFS_case_gen.py +++ b/scm/etc/scripts/UFS_case_gen.py @@ -14,7 +14,7 @@ import fv3_remap import xesmf from datetime import datetime, timedelta -#from matplotlib import plot, ylim, xlim, show, xlabel, ylabel, grid +import matplotlib.pyplot as plt ############################################################################### # Global settings # @@ -1864,8 +1864,10 @@ def get_UFS_forcing_data_advective_tendency(dir, i, j, tile, neighbors, dx, dy, temp = np.zeros((n_filesA,nlevs,npts,npts)) qv = np.zeros((n_filesA,nlevs,npts,npts)) pres = np.zeros((n_filesA,nlevs)) + presi = np.zeros((n_filesA,nlevs+1)) pressfc = np.zeros((n_filesA,npts,npts)) delz = np.zeros((n_filesA,nlevs,npts,npts)) + #hgtsfc = np.zeros((n_filesA,npts,npts)) # Read in 3D UFS history files for count, filename in enumerate(atm_filenames, start=1): @@ -1888,40 +1890,9 @@ def get_UFS_forcing_data_advective_tendency(dir, i, j, tile, neighbors, dx, dy, qv[count-1,:,ii,jj] = nc_file['spfh'][0,::-1,current_ii_index,current_jj_index] pressfc[count-1,ii,jj] = nc_file['pressfc'][0,current_ii_index,current_jj_index] delz[count-1,:,ii,jj] = -1*nc_file['delz'][0,::-1,current_ii_index,current_jj_index] #derive zh + #hgtsfc[count-1,ii,jj] = nc_file['hgtsfc'][0,current_ii_index,current_jj_index] pres[count-1,:] = nc_file['pfull'][::-1]*100.0 - - #This only works for points with longitude far enough away from the prime meridian - # lon_data = nc_file['lon'][neighbors[0,0,0]:neighbors[0,-1,-1]+1,neighbors[1,0,0]:neighbors[1,-1,-1]+1] - # lat_data = nc_file['lat'][neighbors[0,0,0]:neighbors[0,-1,-1]+1,neighbors[1,0,0]:neighbors[1,-1,-1]+1] - # u_data = nc_file['ugrd'][0,::-1,neighbors[0,0,0]:neighbors[0,-1,-1]+1,neighbors[1,0,0]:neighbors[1,-1,-1]+1] - # v_data = nc_file['vgrd'][0,::-1,neighbors[0,0,0]:neighbors[0,-1,-1]+1,neighbors[1,0,0]:neighbors[1,-1,-1]+1] - # w_data = nc_file['dzdt'][0,::-1,neighbors[0,0,0]:neighbors[0,-1,-1]+1,neighbors[1,0,0]:neighbors[1,-1,-1]+1] - # temp_data = nc_file['tmp'][0,::-1,neighbors[0,0,0]:neighbors[0,-1,-1]+1,neighbors[1,0,0]:neighbors[1,-1,-1]+1] - # qv_data = nc_file['spfh'][0,::-1,neighbors[0,0,0]:neighbors[0,-1,-1]+1,neighbors[1,0,0]:neighbors[1,-1,-1]+1] - # pres_data = nc_file['pfull'][::-1]*100.0 - # pressfc_data = nc_file['pressfc'][0,neighbors[0,0,0]:neighbors[0,-1,-1]+1,neighbors[1,0,0]:neighbors[1,-1,-1]+1] - - # time.append(time_data) - # lon.append(lon_data) - # lat.append(lat_data) - # u_wind.append(u_data) - # v_wind.append(v_data) - # w_wind.append(w_data) - # temp.append(temp_data) - # qv.append(qv_data) - # pres.append(pres_data) - # pressfc.append(pressfc_data) - - # time = np.asarray(time) - # lon = np.asarray(lon) - # lat = np.asarray(lat) - # u_wind = np.asarray(u_wind) - # v_wind = np.asarray(v_wind) - # w_wind = np.asarray(w_wind) - # temp = np.asarray(temp) - # qv = np.asarray(qv) - # pres = np.asarray(pres) - # pressfc = np.asarray(pressfc) + presi[count-1,:] = nc_file['phalf'][::-1]*100.0 #check for poor time resolution (e.g. if mean number of grid points traversed by the wind between data intervals is much larger than the number of grid points used for calculating the advective terms) # t=0 @@ -1986,19 +1957,7 @@ def get_UFS_forcing_data_advective_tendency(dir, i, j, tile, neighbors, dx, dy, h_advec_qv[t,k] = -mean_u*dqdx - mean_v*dqdy #kg kg-1 s-1 h_advec_u[t,k] = -mean_u*dudx - mean_v*dudy #m s-1 s-1 h_advec_v[t,k] = -mean_u*dvdx - mean_v*dvdy #m s-1 s-1 - - - - # plot(w_wind[t,:,center,center],pres[t,:],"k.") - # #y_av = movingaverage(y, 10) - # plot(w_wind_smoothed_ma, pres[t,:],"r") - # #plot(w_wind_smoothed_sf, pres[t,:],"b") - # xlim(np.min(w_wind[t,:,center,center]),np.max(w_wind[t,:,center,center])) - # xlabel("w") - # ylabel("p") - # grid(True) - # show() - + if (vertical_method == 1): v_advec_u[t,0] = 0.0 v_advec_u[t,nlevs-1] = 0.0 @@ -2011,6 +1970,7 @@ def get_UFS_forcing_data_advective_tendency(dir, i, j, tile, neighbors, dx, dy, for k in range(1, nlevs-1): w_asc = max(smoothed_w[t,k], 0.0) w_des = min(smoothed_w[t,k], 0.0) + #noisy wind profiles necessitate using smoothed profiles; this doesn't appear to be needed for T and qv gradient_T_asc = (temp[t,k,center,center] - temp[t,k-1,center,center])/(pres[t,k]-pres[t,k-1]) gradient_T_des = (temp[t,k+1,center,center] - temp[t,k,center,center])/(pres[t,k+1]-pres[t,k]) #gradient_T_asc = (smoothed_T[t,k,center,center] - smoothed_T[t,k-1,center,center])/(pres[t,k]-pres[t,k-1]) @@ -2039,108 +1999,42 @@ def get_UFS_forcing_data_advective_tendency(dir, i, j, tile, neighbors, dx, dy, u_g = np.zeros((n_filesA,nlevs)) v_g = np.zeros((n_filesA,nlevs)) if (geos_wind_forcing): - #first calc height at the pressure levels (ignore variation in gravity for typical model levels; height ~= geopotential height) - zh = np.zeros((n_filesA,nlevs,npts,npts)) + #calc geopotential at interface levels, starting from surface, convert to full pressure levels + phii = np.zeros((n_filesA,nlevs+1,npts,npts)) + phil = np.zeros((n_filesA,nlevs,npts,npts)) for ii in range(npts): for jj in range(npts): + phii[t,0,ii,jj] = 0.0#hgtsfc[t,ii,jj]*grav #don't need to include orography -- geostrophic winds should assume geopotential over the geoid + for k in range(1,nlevs+1): + phii[t,k,ii,jj] = phii[t,k-1,ii,jj] - rdgas*temp[t,k-1,ii,jj]*(1.0 + zvir*qv[t,k-1,ii,jj])*np.log(presi[t,k]/presi[t,k-1]) - zh[t,0,ii,jj] = 0.5*delz[t,0,ii,jj] - for k in range(1,nlevs): - zh[t,k,ii,jj] = zh[t,k-1,ii,jj] + 0.5*delz[t,k-1,ii,jj] + 0.5*delz[t,k,ii,jj] + for k in range(0,nlevs): + phil[t,k,ii,jj] = 0.5*(phii[t,k,ii,jj] + phii[t,k+1,ii,jj]) mean_lat = np.mean(lat[t,:,:]) coriolis = 2.0*Omega*np.sin(mean_lat*deg_to_rad) for k in range(1,nlevs): - dZdx = centered_diff_derivative(zh[t,k,center,:],dx[center,:]*1.0E3) - dZdy = centered_diff_derivative(zh[t,k,:,center],dy[:,center]*1.0E3) - - u_g[t,k] = -grav/coriolis*dZdy - v_g[t,k] = grav/coriolis*dZdx - - # plot(u_g[t,:],pres[t,:],"r") - # plot(u_wind[t,:,center,center],pres[t,:],"b") - # xlabel("m/s") - # ylabel("p") - # grid(True) - # show() - # - # plot(v_g[t,:],pres[t,:],"r") - # plot(v_wind[t,:,center,center],pres[t,:],"b") - # xlabel("m/s") - # ylabel("p") - # grid(True) - # show() - - -# if (False): -# plot(h_advec_T[t,:]*86400.0,pres[t,:],"r") -# # #y_av = movingaverage(y, 10) -# plot(v_advec_T[t,:]*86400.0,pres[t,:],"b") -# # #plot(w_wind_smoothed_sf, pres[t,:],"b") -# xlim(86400.0*np.min(h_advec_T[t,:] + v_advec_T[t,:]),86400.0*np.max(h_advec_T[t,:] + v_advec_T[t,:])) -# xlabel("K day-1") -# ylabel("p") -# grid(True) -# show() -# -# plot(h_advec_qv[t,:]*86400.0*1.0E3,pres[t,:],"r") -# # #y_av = movingaverage(y, 10) -# plot(v_advec_qv[t,:]*86400.0*1.0E3,pres[t,:],"b") -# # #plot(w_wind_smoothed_sf, pres[t,:],"b") -# xlim(86400.0*1.0E3*np.min(h_advec_qv[t,:] + v_advec_qv[t,:]),86400.0*1.0E3*np.max(h_advec_qv[t,:] + v_advec_qv[t,:])) -# xlabel("g kg-1 day-1") -# ylabel("p") -# grid(True) -# show() -# -# plot(h_advec_u[t,:]*86400.0,pres[t,:],"r") -# # #y_av = movingaverage(y, 10) -# plot(v_advec_u[t,:]*86400.0,pres[t,:],"b") -# # #plot(w_wind_smoothed_sf, pres[t,:],"b") -# xlim(86400.0*np.min(h_advec_u[t,:] + v_advec_u[t,:]),86400.0*np.max(h_advec_u[t,:] + v_advec_u[t,:])) -# xlabel("u: m s-1 day-1") -# ylabel("p") -# grid(True) -# show() -# -# plot(h_advec_v[t,:]*86400.0,pres[t,:],"r") -# # #y_av = movingaverage(y, 10) -# plot(v_advec_v[t,:]*86400.0,pres[t,:],"b") -# # #plot(w_wind_smoothed_sf, pres[t,:],"b") -# xlim(86400.0*np.min(h_advec_v[t,:] + v_advec_v[t,:]),86400.0*np.max(h_advec_v[t,:] + v_advec_v[t,:])) -# xlabel("v: m s-1 day-1") -# ylabel("p") -# grid(True) -# show() - - - # grad_t = np.gradient(temp[t,:,:,:]) #grad_t output is list of components (z, y, x); each axis array has dimensions of (levs,2*n_forcing_halo_points+1,2*n_forcing_halo_points+1); we're interested in middle point for each level - # grad_qv = np.gradient(qv[t,:,:,:]) - # grad_u = np.gradient(u_wind[t,:,:,:]) - # grad_v = np.gradient(v_wind[t,:,:,:]) - #grad_t_x = np.gradient(temp[t,0,:,:], axis=1) - #grad_t_y = np.gradient(temp[t,0,:,:], axis=0) - #print(temp[t,0,:,:]) - #print(grad_t[0][0]) #dT in z direction at level 0 - #print(grad_t[1][0]) #dT in y direction at level 0 - #print(grad_t[2][0]) #dT in x direction at level 0 - #exit() - #print('dx tot',grad_t[1]) - #print('dy tot',grad_t[0]) - - #print('dx',grad_t_x) - #print('dy',grad_t_y) - - #exit() + dphidx = centered_diff_derivative(phil[t,k,center,:],dx[center,:]*1.0E3) + dphidy = centered_diff_derivative(phil[t,k,:,center],dy[:,center]*1.0E3) + + u_g[t,k] = -dphidy/coriolis + v_g[t,k] = dphidx/coriolis if (save_comp_data): # Read in 2D UFS history files - vars2d =[{"name":"spfh2m"}, {"name":"tmp2m"}, \ - {"name":"dswrf_ave"}, {"name":"ulwrf_ave"},\ - {"name":"lhtfl_ave"}, {"name":"shtfl_ave"},\ - {"name":"dswrf"}, {"name":"ulwrf"},\ - {"name":"lhtfl"}, {"name":"shtfl"},\ - {"name":"pwat"}, {"name":"vgrd10m"},\ + phystends = [{"name":"dtend_temp_lw"}, {"name":"dtend_temp_sw"}, {"name":"dtend_temp_pbl"}, {"name":"dtend_temp_deepcnv"},\ + {"name":"dtend_temp_shalcnv"},{"name":"dtend_temp_mp"}, {"name":"dtend_temp_orogwd"},{"name":"dtend_temp_phys"}, \ + {"name":"dtend_u_pbl"}, {"name":"dtend_v_pbl"}, {"name":"dtend_u_orogwd"}, {"name":"dtend_v_orogwd"}, \ + {"name":"dtend_u_deepcnv"}, {"name":"dtend_v_deepcnv"},{"name":"dtend_u_shalcnv"}, {"name":"dtend_v_shalcnv"}, \ + {"name":"dtend_u_phys"}, {"name":"dtend_v_phys"}, {"name":"dtend_qv_pbl"}, {"name":"dtend_qv_deepcnv"}, \ + {"name":"dtend_qv_shalcnv"}, {"name":"dtend_qv_mp"}, {"name":"dtend_qv_phys"}, {"name":"dtend_poop"}] + for phystend in phystends: phystend["values"] = [] + + # Variables to be added to "UFS comparison file" + vars2d =[{"name":"spfh2m"}, {"name":"tmp2m"}, {"name":"dswrf_ave"}, \ + {"name":"ulwrf_ave"}, {"name":"lhtfl_ave"}, {"name":"shtfl_ave"}, \ + {"name":"dswrf"}, {"name":"ulwrf"}, {"name":"lhtfl"}, \ + {"name":"shtfl"}, {"name":"pwat"}, {"name":"vgrd10m"}, \ {"name":"ugrd10m"}] for var2d in vars2d: var2d["values"] = [] @@ -2164,21 +2058,36 @@ def get_UFS_forcing_data_advective_tendency(dir, i, j, tile, neighbors, dx, dy, logging.critical(message) raise Exception(message) + center_ii_index = neighbors[0,center,center] + center_jj_index = neighbors[1,center,center] for count, filename in enumerate(sfc_filenames, start=1): nc_file = Dataset('{0}/{1}'.format(dir,filename)) nc_file.set_always_mask(False) for var2d in vars2d: - data = nc_file[var2d["name"]][0,:,:] - var2d["values"].append(data[i,j]) + data = nc_file[var2d["name"]][0,center_ii_index,center_jj_index] + var2d["values"].append(data) var2d["units"] = nc_file[var2d["name"]].getncattr(name="units") var2d["long_name"] = nc_file[var2d["name"]].getncattr(name="long_name") + + for phystend in phystends: + if phystend["name"] in nc_file.variables.keys(): + data = nc_file[phystend["name"]][0,::-1,center_ii_index,center_jj_index] + phystend["values"].append(data[:]) + phystend["units"] = nc_file[phystend["name"]].getncattr(name="units") + phystend["long_name"] = nc_file[phystend["name"]].getncattr(name="long_name") + phystend["missing"] = False + else: + phystend["missing"] = True nc_file.close() # Convert to numpy arrays for var2d in vars2d: var2d["values"] = np.asarray(var2d["values"]) + for phystend in phystends: + if (not phystend["missing"]): + phystend["values"] = np.asarray(phystend["values"]) sec_in_hr = 3600. time[0] = 0. forcing = { @@ -2204,7 +2113,10 @@ def get_UFS_forcing_data_advective_tendency(dir, i, j, tile, neighbors, dx, dy, "qv" : qv [:,:,center,center], "ua" : u_wind[:,:,center,center], "va" : v_wind[:,:,center,center], - "vars2d":vars2d} + "vars2d":vars2d, + "phystends":phystends} + else: + comp_data = {} return (forcing, comp_data) @@ -3446,7 +3358,7 @@ def write_SCM_case_file(state, surface, oro, forcing, init, case, date, forcing_ return(fileOUT) ######################################################################################## -def write_comparison_file(comp_data, case_name, date, surface, forcing_method): +def write_comparison_file(comp_data, case_name, date, surface): """Write UFS history file data to netCDF file for comparison""" wp = np.float64 @@ -3521,13 +3433,12 @@ def write_comparison_file(comp_data, case_name, date, surface, forcing_method): tempVar.long_name = var2d["long_name"] tempVar[:] = var2d["values"] - if (forcing_method == 1 or forcing_method == 3): - for phystend in comp_data["phystends"]: - if (not phystend["missing"]): - tempVar = nc_file.createVariable(phystend["name"], wp, ('time', 'lev',)) - tempVar.units = phystend["units"] - tempVar.long_name = phystend["long_name"] - tempVar[:] = phystend["values"] + for phystend in comp_data["phystends"]: + if (not phystend["missing"]): + tempVar = nc_file.createVariable(phystend["name"], wp, ('time', 'lev',)) + tempVar.units = phystend["units"] + tempVar.long_name = phystend["long_name"] + tempVar[:] = phystend["values"] # end if # end for # end if @@ -3612,7 +3523,7 @@ def main(): # different file reads) if (error_msg): - print("ERROR: unknown grid orintation") + print("ERROR: unknown grid orientation") exit() if not date: @@ -3655,7 +3566,7 @@ def main(): # write them out to compare SCM output to (atmf for state variables and sfcf for physics # tendencies) if (save_comp): - write_comparison_file(comp_data, case_name, date, surface_data, forcing_method) + write_comparison_file(comp_data, case_name, date, surface_data) if __name__ == '__main__': main() From 4ea5f36579c22633ec39e2530768a0460f9d9844 Mon Sep 17 00:00:00 2001 From: Grant Firl Date: Thu, 11 Jul 2024 10:46:21 -0400 Subject: [PATCH 11/25] move initialization of geostrophic arrays (bugfix) --- scm/etc/scripts/UFS_case_gen.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/scm/etc/scripts/UFS_case_gen.py b/scm/etc/scripts/UFS_case_gen.py index 02aac678c..7345e956a 100755 --- a/scm/etc/scripts/UFS_case_gen.py +++ b/scm/etc/scripts/UFS_case_gen.py @@ -1915,6 +1915,10 @@ def get_UFS_forcing_data_advective_tendency(dir, i, j, tile, neighbors, dx, dy, v_advec_v = np.zeros((n_filesA,nlevs)) v_advec_T = np.zeros((n_filesA,nlevs)) v_advec_qv = np.zeros((n_filesA,nlevs)) + u_g = np.zeros((n_filesA,nlevs)) + v_g = np.zeros((n_filesA,nlevs)) + phii = np.zeros((n_filesA,nlevs+1,npts,npts)) + phil = np.zeros((n_filesA,nlevs,npts,npts)) for t in range(n_filesA): #velocities gets very noisy in the UFS above the tropopause; define a linear return-to-zero profile above some pressure k_p_top = np.where(pres[t,:] <= top_pres_for_forcing)[0][0] @@ -1995,13 +1999,8 @@ def get_UFS_forcing_data_advective_tendency(dir, i, j, tile, neighbors, dx, dy, v_advec_T[t,k] = rho*grav*(w_asc*gradient_T_asc + w_des*gradient_T_des) + adiabatic_exp_comp_term v_advec_qv[t,k] = rho*grav*(w_asc*gradient_qv_asc + w_des*gradient_qv_des) - - u_g = np.zeros((n_filesA,nlevs)) - v_g = np.zeros((n_filesA,nlevs)) if (geos_wind_forcing): #calc geopotential at interface levels, starting from surface, convert to full pressure levels - phii = np.zeros((n_filesA,nlevs+1,npts,npts)) - phil = np.zeros((n_filesA,nlevs,npts,npts)) for ii in range(npts): for jj in range(npts): phii[t,0,ii,jj] = 0.0#hgtsfc[t,ii,jj]*grav #don't need to include orography -- geostrophic winds should assume geopotential over the geoid From e98c44edcefcf07ee39355a573590d207a1cda01 Mon Sep 17 00:00:00 2001 From: Dustin Swales Date: Mon, 15 Jul 2024 20:34:16 +0000 Subject: [PATCH 12/25] Update SDF names/nmls/etc... --- .../input_GFS_v17_HR3_RRTMGP.nml | 171 ------------------ .../input_GFS_v17_HR3_RRTMGP_ps.nml | 171 ------------------ ...FS_v17_HR3.nml => input_GFS_v17_p8_ugwpv1} | 0 ..._ps.nml => input_GFS_v17_p8_ugwpv1_ps.nml} | 0 ccpp/suites/suite_SCM_GFS_v17_HR3_RRTMGP.xml | 89 --------- .../suite_SCM_GFS_v17_HR3_RRTMGP_ps.xml | 70 ------- ...R3.xml => suite_SCM_GFS_v17_p8_ugwpv1.xml} | 2 +- ...xml => suite_SCM_GFS_v17_p8_ugwpv1_ps.xml} | 2 +- scm/doc/TechGuide/chap_quick.rst | 2 +- scm/src/suite_info.py | 10 +- scm/src/supported_suites.py | 2 +- 11 files changed, 8 insertions(+), 511 deletions(-) delete mode 100644 ccpp/physics_namelists/input_GFS_v17_HR3_RRTMGP.nml delete mode 100644 ccpp/physics_namelists/input_GFS_v17_HR3_RRTMGP_ps.nml rename ccpp/physics_namelists/{input_GFS_v17_HR3.nml => input_GFS_v17_p8_ugwpv1} (100%) rename ccpp/physics_namelists/{input_GFS_v17_HR3_ps.nml => input_GFS_v17_p8_ugwpv1_ps.nml} (100%) delete mode 100644 ccpp/suites/suite_SCM_GFS_v17_HR3_RRTMGP.xml delete mode 100644 ccpp/suites/suite_SCM_GFS_v17_HR3_RRTMGP_ps.xml rename ccpp/suites/{suite_SCM_GFS_v17_HR3.xml => suite_SCM_GFS_v17_p8_ugwpv1.xml} (98%) rename ccpp/suites/{suite_SCM_GFS_v17_HR3_ps.xml => suite_SCM_GFS_v17_p8_ugwpv1_ps.xml} (97%) diff --git a/ccpp/physics_namelists/input_GFS_v17_HR3_RRTMGP.nml b/ccpp/physics_namelists/input_GFS_v17_HR3_RRTMGP.nml deleted file mode 100644 index f7cf90973..000000000 --- a/ccpp/physics_namelists/input_GFS_v17_HR3_RRTMGP.nml +++ /dev/null @@ -1,171 +0,0 @@ -&gfs_physics_nml - fhzero = 6 - h2o_phys = .true. - ldiag3d = .true. - qdiag3d = .true. - print_diff_pgr = .false. - fhcyc = 24 - use_ufo = .true. - pre_rad = .false. - imp_physics = 8 - iovr = 3 - ltaerosol = .false. - lradar = .true. - ttendlim = -999 - dt_inner = 150 - sedi_semi = .true. - decfl = 10 - oz_phys = .false. - oz_phys_2015 = .true. - lsoil_lsm = 4 - do_mynnedmf = .false. - do_mynnsfclay = .false. - icloud_bl = 1 - bl_mynn_edmf = 1 - bl_mynn_tkeadvect = .true. - bl_mynn_edmf_mom = 1 - do_ugwp = .false. - do_tofd = .false. - gwd_opt = 2 - do_ugwp_v0 = .false. - do_ugwp_v1 = .true. - do_ugwp_v0_orog_only = .false. - do_ugwp_v0_nst_only = .false. - do_gsl_drag_ls_bl = .true. - do_gsl_drag_ss = .true. - do_gsl_drag_tofd = .true. - do_ugwp_v1_orog_only = .false. - min_lakeice = 0.15 - min_seaice = 1.0e-6 - use_cice_alb = .true. - pdfcld = .false. - fhswr = 1200. - fhlwr = 1200. - progsigma = .true. - betascu = 8.0 - betamcu = 1.0 - betadcu = 2.0 - ialb = 2 - iems = 2 - iaer = 1011 - icliq_sw = 2 - ico2 = 2 - isubc_sw = 2 - isubc_lw = 2 - isol = 2 - lwhtr = .true. - swhtr = .true. - cnvgwd = .true. - shal_cnv = .true. - cal_pre = .false. - redrag = .true. - dspheat = .true. - hybedmf = .false. - satmedmf = .true. - isatmedmf = 1 - lheatstrg = .true. - lseaspray = .true. - random_clds = .false. - trans_trac = .true. - cnvcld = .true. - imfshalcnv = 2 - imfdeepcnv = 2 - ras = .false. - cdmbgwd = 2.5,7.5,1.0,1.0 - prslrd0 = 0. - ivegsrc = 1 - isot = 1 - lsoil = 4 - lsm = 2 - iopt_dveg = 4 - iopt_crs = 2 - iopt_btr = 1 - iopt_run = 1 - iopt_sfc = 3 - iopt_trs = 2 - iopt_frz = 1 - iopt_inf = 1 - iopt_rad = 3 - iopt_alb = 1 - iopt_snf = 4 - iopt_tbot = 2 - iopt_stc = 3 - debug = .false. - nstf_name = 2,0,0,0,0 - nst_anl = .true. - psautco = 0.0008,0.0005 - prautco = 0.00015,0.00015 - lgfdlmprad = .false. - effr_in = .true. - ldiag_ugwp = .false. - do_sppt = .false. - do_shum = .false. - do_skeb = .false. - do_RRTMGP = .true. - doGP_cldoptics_LUT = .true. - doGP_lwscat = .true. - active_gases = 'h2o_co2_o3_n2o_ch4_o2' - ngases = 6 - rrtmgp_root = '../../ccpp/physics/physics/Radiation/RRTMGP/rte-rrtmgp/' - lw_file_gas = 'rrtmgp/data/rrtmgp-data-lw-g128-210809.nc' - lw_file_clouds = 'extensions/cloud_optics/rrtmgp-cloud-optics-coeffs-lw.nc' - sw_file_gas = 'rrtmgp/data/rrtmgp-data-sw-g112-210809.nc' - sw_file_clouds = 'extensions/cloud_optics/rrtmgp-cloud-optics-coeffs-reordered-sw.nc' - rrtmgp_nGptsSW = 112 - rrtmgp_nGptsLW = 128 - rrtmgp_nBandsLW = 16 - rrtmgp_nBandsSW = 14 - frac_grid = .true. - cplchm = .false. - cplflx = .false. - cplice = .false. - cplwav = .false. - cplwav2atm = .false. - do_ca = .false. - ca_global = .false. - ca_sgs = .true. - nca = 1 - ncells = 5 - nlives = 12 - nseed = 1 - nfracseed = 0.5 - nthresh = 18 - ca_trigger = .true. - nspinup = 1 - iseed_ca = 1448371824 -/ - -&cires_ugwp_nml - knob_ugwp_solver = 2 - knob_ugwp_version = 1 - knob_ugwp_source = 1,1,0,0 - knob_ugwp_wvspec = 1,25,25,25 - knob_ugwp_azdir = 2,4,4,4 - knob_ugwp_stoch = 0,0,0,0 - knob_ugwp_effac = 1,1,1,1 - knob_ugwp_doaxyz = 1 - knob_ugwp_doheat = 1 - knob_ugwp_dokdis = 2 - knob_ugwp_ndx4lh = 4 - knob_ugwp_palaunch = 275.0e2 - knob_ugwp_nslope = 1 - knob_ugwp_lzmax = 15.750e3 - knob_ugwp_lzmin = 0.75e3 - knob_ugwp_lzstar = 2.0e3 - knob_ugwp_taumin = 0.25e-3 - knob_ugwp_tauamp = 0.5e-3 - knob_ugwp_lhmet = 200.0e3 - knob_ugwp_orosolv = 'pss-1986' -/ - -&ccpp_suite_sim_nml - suite_sim_file = '' - nprc_sim = 7 - prc_LWRAD_cfg = 0, 0, 1 - prc_SWRAD_cfg = 0, 0, 2 - prc_PBL_cfg = 1, 0, 3 - prc_GWD_cfg = 1, 0, 4 - prc_SCNV_cfg = 1, 1, 5 - prc_DCNV_cfg = 1, 1, 6 - prc_cldMP_cfg = 1, 1, 7 -/ diff --git a/ccpp/physics_namelists/input_GFS_v17_HR3_RRTMGP_ps.nml b/ccpp/physics_namelists/input_GFS_v17_HR3_RRTMGP_ps.nml deleted file mode 100644 index c562957f2..000000000 --- a/ccpp/physics_namelists/input_GFS_v17_HR3_RRTMGP_ps.nml +++ /dev/null @@ -1,171 +0,0 @@ -&gfs_physics_nml - fhzero = 6 - h2o_phys = .true. - ldiag3d = .true. - qdiag3d = .true. - print_diff_pgr = .false. - fhcyc = 24 - use_ufo = .true. - pre_rad = .false. - imp_physics = 8 - iovr = 3 - ltaerosol = .False. - lradar = .true. - ttendlim = -999 - dt_inner = 150 - sedi_semi = .true. - decfl = 10 - oz_phys = .false. - oz_phys_2015 = .true. - lsoil_lsm = 4 - do_mynnedmf = .false. - do_mynnsfclay = .false. - icloud_bl = 1 - bl_mynn_edmf = 1 - bl_mynn_tkeadvect = .true. - bl_mynn_edmf_mom = 1 - do_ugwp = .false. - do_tofd = .false. - gwd_opt = 2 - do_ugwp_v0 = .false. - do_ugwp_v1 = .true. - do_ugwp_v0_orog_only = .false. - do_ugwp_v0_nst_only = .false. - do_gsl_drag_ls_bl = .true. - do_gsl_drag_ss = .true. - do_gsl_drag_tofd = .true. - do_ugwp_v1_orog_only = .false. - min_lakeice = 0.15 - min_seaice = 1.0e-6 - use_cice_alb = .true. - pdfcld = .false. - fhswr = 1200. - fhlwr = 1200. - progsigma = .true. - betascu = 8.0 - betamcu = 1.0 - betadcu = 2.0 - ialb = 2 - iems = 2 - iaer = 1011 - icliq_sw = 2 - ico2 = 2 - isubc_sw = 2 - isubc_lw = 2 - isol = 2 - lwhtr = .true. - swhtr = .true. - cnvgwd = .true. - shal_cnv = .true. - cal_pre = .false. - redrag = .true. - dspheat = .true. - hybedmf = .false. - satmedmf = .true. - isatmedmf = 1 - lheatstrg = .false. - lseaspray = .true. - random_clds = .false. - trans_trac = .true. - cnvcld = .true. - imfshalcnv = 2 - imfdeepcnv = 2 - ras = .false. - cdmbgwd = 2.5,7.5,1.0,1.0 - prslrd0 = 0. - ivegsrc = 1 - isot = 1 - lsoil = 4 - lsm = 2 - iopt_dveg = 4 - iopt_crs = 2 - iopt_btr = 1 - iopt_run = 1 - iopt_sfc = 3 - iopt_trs = 2 - iopt_frz = 1 - iopt_inf = 1 - iopt_rad = 3 - iopt_alb = 1 - iopt_snf = 4 - iopt_tbot = 2 - iopt_stc = 3 - debug = .false. - nstf_name = 2,0,0,0,0 - nst_anl = .true. - psautco = 0.0008,0.0005 - prautco = 0.00015,0.00015 - lgfdlmprad = .false. - effr_in = .true. - ldiag_ugwp = .false. - do_sppt = .false. - do_shum = .false. - do_skeb = .false. - do_RRTMGP = .true. - doGP_cldoptics_LUT = .true. - doGP_lwscat = .true. - active_gases = 'h2o_co2_o3_n2o_ch4_o2' - ngases = 6 - rrtmgp_root = '../../ccpp/physics/physics/Radiation/RRTMGP/rte-rrtmgp/' - lw_file_gas = 'rrtmgp/data/rrtmgp-data-lw-g128-210809.nc' - lw_file_clouds = 'extensions/cloud_optics/rrtmgp-cloud-optics-coeffs-lw.nc' - sw_file_gas = 'rrtmgp/data/rrtmgp-data-sw-g112-210809.nc' - sw_file_clouds = 'extensions/cloud_optics/rrtmgp-cloud-optics-coeffs-reordered-sw.nc' - rrtmgp_nGptsSW = 112 - rrtmgp_nGptsLW = 128 - rrtmgp_nBandsLW = 16 - rrtmgp_nBandsSW = 14 - frac_grid = .true. - cplchm = .false. - cplflx = .false. - cplice = .false. - cplwav = .false. - cplwav2atm = .false. - do_ca = .false. - ca_global = .false. - ca_sgs = .true. - nca = 1 - ncells = 5 - nlives = 12 - nseed = 1 - nfracseed = 0.5 - nthresh = 18 - ca_trigger = .true. - nspinup = 1 - iseed_ca = 1448371824 -/ - -&cires_ugwp_nml - knob_ugwp_solver = 2 - knob_ugwp_version = 1 - knob_ugwp_source = 1,1,0,0 - knob_ugwp_wvspec = 1,25,25,25 - knob_ugwp_azdir = 2,4,4,4 - knob_ugwp_stoch = 0,0,0,0 - knob_ugwp_effac = 1,1,1,1 - knob_ugwp_doaxyz = 1 - knob_ugwp_doheat = 1 - knob_ugwp_dokdis = 2 - knob_ugwp_ndx4lh = 4 - knob_ugwp_palaunch = 275.0e2 - knob_ugwp_nslope = 1 - knob_ugwp_lzmax = 15.750e3 - knob_ugwp_lzmin = 0.75e3 - knob_ugwp_lzstar = 2.0e3 - knob_ugwp_taumin = 0.25e-3 - knob_ugwp_tauamp = 0.5e-3 - knob_ugwp_lhmet = 200.0e3 - knob_ugwp_orosolv = 'pss-1986' -/ - -&ccpp_suite_sim_nml - suite_sim_file = '' - nprc_sim = 7 - prc_LWRAD_cfg = 0, 0, 1 - prc_SWRAD_cfg = 0, 0, 2 - prc_PBL_cfg = 1, 0, 3 - prc_GWD_cfg = 1, 0, 4 - prc_SCNV_cfg = 1, 1, 5 - prc_DCNV_cfg = 1, 1, 6 - prc_cldMP_cfg = 1, 1, 7 -/ diff --git a/ccpp/physics_namelists/input_GFS_v17_HR3.nml b/ccpp/physics_namelists/input_GFS_v17_p8_ugwpv1 similarity index 100% rename from ccpp/physics_namelists/input_GFS_v17_HR3.nml rename to ccpp/physics_namelists/input_GFS_v17_p8_ugwpv1 diff --git a/ccpp/physics_namelists/input_GFS_v17_HR3_ps.nml b/ccpp/physics_namelists/input_GFS_v17_p8_ugwpv1_ps.nml similarity index 100% rename from ccpp/physics_namelists/input_GFS_v17_HR3_ps.nml rename to ccpp/physics_namelists/input_GFS_v17_p8_ugwpv1_ps.nml diff --git a/ccpp/suites/suite_SCM_GFS_v17_HR3_RRTMGP.xml b/ccpp/suites/suite_SCM_GFS_v17_HR3_RRTMGP.xml deleted file mode 100644 index 09bcbfa64..000000000 --- a/ccpp/suites/suite_SCM_GFS_v17_HR3_RRTMGP.xml +++ /dev/null @@ -1,89 +0,0 @@ - - - - - - - GFS_time_vary_pre - GFS_rrtmgp_setup - GFS_rad_time_vary - GFS_phys_time_vary - - - - - GFS_suite_interstitial_rad_reset - GFS_rrtmgp_pre - GFS_radiation_surface - GFS_rrtmgp_cloud_mp - GFS_rrtmgp_cloud_overlap - GFS_cloud_diagnostics - rrtmgp_aerosol_optics - rrtmgp_sw_main - rrtmgp_lw_main - GFS_rrtmgp_post - - - - - GFS_suite_interstitial_phys_reset - GFS_suite_stateout_reset - get_prs_fv3 - GFS_suite_interstitial_1 - GFS_surface_generic_pre - GFS_surface_composites_pre - dcyc2t3 - GFS_surface_composites_inter - GFS_suite_interstitial_2 - - - - sfc_diff - GFS_surface_loop_control_part1 - sfc_nst_pre - sfc_nst - sfc_nst_post - noahmpdrv - sfc_sice - GFS_surface_loop_control_part2 - - - - GFS_surface_composites_post - sfc_diag - sfc_diag_post - GFS_surface_generic_post - GFS_PBL_generic_pre - satmedmfvdifq - GFS_PBL_generic_post - GFS_GWD_generic_pre - ugwpv1_gsldrag - ugwpv1_gsldrag_post - GFS_GWD_generic_post - GFS_suite_stateout_update - h2ophys - get_phi_fv3 - GFS_suite_interstitial_3 - GFS_DCNV_generic_pre - samfdeepcnv - GFS_DCNV_generic_post - GFS_SCNV_generic_pre - samfshalcnv - GFS_SCNV_generic_post - GFS_suite_interstitial_4 - cnvc90 - GFS_MP_generic_pre - mp_thompson_pre - - - mp_thompson - - - mp_thompson_post - GFS_MP_generic_post - maximum_hourly_diagnostics - GFS_physics_post - - - - diff --git a/ccpp/suites/suite_SCM_GFS_v17_HR3_RRTMGP_ps.xml b/ccpp/suites/suite_SCM_GFS_v17_HR3_RRTMGP_ps.xml deleted file mode 100644 index 0ba77dff3..000000000 --- a/ccpp/suites/suite_SCM_GFS_v17_HR3_RRTMGP_ps.xml +++ /dev/null @@ -1,70 +0,0 @@ - - - - - - - GFS_time_vary_pre - GFS_rrtmgp_setup - GFS_rad_time_vary - GFS_phys_time_vary - - - - - GFS_suite_interstitial_rad_reset - GFS_rrtmgp_pre - GFS_radiation_surface - GFS_rrtmgp_cloud_mp - GFS_rrtmgp_cloud_overlap - GFS_cloud_diagnostics - rrtmgp_aerosol_optics - rrtmgp_sw_main - rrtmgp_lw_main - GFS_rrtmgp_post - - - - - GFS_suite_interstitial_phys_reset - GFS_suite_stateout_reset - get_prs_fv3 - GFS_suite_interstitial_1 - GFS_surface_generic_pre - scm_sfc_flux_spec - dcyc2t3 - GFS_suite_interstitial_2 - GFS_PBL_generic_pre - satmedmfvdifq - GFS_PBL_generic_post - GFS_GWD_generic_pre - ugwpv1_gsldrag - ugwpv1_gsldrag_post - GFS_GWD_generic_post - GFS_suite_stateout_update - h2ophys - get_phi_fv3 - GFS_suite_interstitial_3 - GFS_DCNV_generic_pre - samfdeepcnv - GFS_DCNV_generic_post - GFS_SCNV_generic_pre - samfshalcnv - GFS_SCNV_generic_post - GFS_suite_interstitial_4 - cnvc90 - GFS_MP_generic_pre - mp_thompson_pre - - - mp_thompson - - - mp_thompson_post - GFS_MP_generic_post - maximum_hourly_diagnostics - GFS_physics_post - - - - diff --git a/ccpp/suites/suite_SCM_GFS_v17_HR3.xml b/ccpp/suites/suite_SCM_GFS_v17_p8_ugwpv1.xml similarity index 98% rename from ccpp/suites/suite_SCM_GFS_v17_HR3.xml rename to ccpp/suites/suite_SCM_GFS_v17_p8_ugwpv1.xml index 92effe13c..6c823ece3 100644 --- a/ccpp/suites/suite_SCM_GFS_v17_HR3.xml +++ b/ccpp/suites/suite_SCM_GFS_v17_p8_ugwpv1.xml @@ -1,6 +1,6 @@ - + diff --git a/ccpp/suites/suite_SCM_GFS_v17_HR3_ps.xml b/ccpp/suites/suite_SCM_GFS_v17_p8_ugwpv1_ps.xml similarity index 97% rename from ccpp/suites/suite_SCM_GFS_v17_HR3_ps.xml rename to ccpp/suites/suite_SCM_GFS_v17_p8_ugwpv1_ps.xml index d9e833936..2c080fb93 100644 --- a/ccpp/suites/suite_SCM_GFS_v17_HR3_ps.xml +++ b/ccpp/suites/suite_SCM_GFS_v17_p8_ugwpv1_ps.xml @@ -1,6 +1,6 @@ - + diff --git a/scm/doc/TechGuide/chap_quick.rst b/scm/doc/TechGuide/chap_quick.rst index f1524079e..78a8b7155 100644 --- a/scm/doc/TechGuide/chap_quick.rst +++ b/scm/doc/TechGuide/chap_quick.rst @@ -448,7 +448,7 @@ contents in the directory ``scm/data``. Similarly, do the same for ``thompson_tables.tar.gz`` and ``MG_INCCN_data.tar.gz`` and extract to ``scm/data/physics_input_data/``. -New with the SCM v7 release, static data is available for running cases with GOCART climatological aerosols (where the value of ``iaer`` in the ``&gfs_physics_nml`` namelist starts with 1; see the `CCPP Scientific Documentation `__ for more information); one example of this is with the default namelist settings for the GFS_v17_HR3 scheme. This dataset is very large (~12 GB), so it is recommended only to download it if you will be using it. +New with the SCM v7 release, static data is available for running cases with GOCART climatological aerosols (where the value of ``iaer`` in the ``&gfs_physics_nml`` namelist starts with 1; see the `CCPP Scientific Documentation `__ for more information); one example of this is with the default namelist settings for the GFS_v17_p8_ugwpv1 suite. This dataset is very large (~12 GB), so it is recommended only to download it if you will be using it. .. code:: bash diff --git a/scm/src/suite_info.py b/scm/src/suite_info.py index 5564287f2..290b8cbf3 100755 --- a/scm/src/suite_info.py +++ b/scm/src/suite_info.py @@ -43,15 +43,14 @@ def timestep(self, value): suite_list = [] suite_list.append(suite('SCM_GFS_v16', 'tracers_GFS_v16.txt', 'input_GFS_v16.nml', 600.0, 1800.0, True )) -suite_list.append(suite('SCM_GFS_v17_p8', 'tracers_GFS_v17_p8.txt', 'input_GFS_v17_p8.nml', 600.0, 600.0, True )) -suite_list.append(suite('SCM_GFS_v17_HR3', 'tracers_GFS_v17_HR3.txt', 'input_GFS_v17_HR3.nml', 600.0, 600.0, True )) -suite_list.append(suite('SCM_GFS_v17_HR3_RRTMGP','tracers_GFS_v17_HR3.txt', 'input_GFS_v17_HR3_RRTMGP.nml', 600.0, 600.0, True )) +suite_list.append(suite('SCM_GFS_v17_p8_ugwpv1', 'tracers_GFS_v17_p8.txt', 'input_GFS_v17_p8_ugwpv1.nml', 600.0, 600.0, True )) suite_list.append(suite('SCM_RAP', 'tracers_RAP.txt', 'input_RAP.nml', 600.0, 600.0 , True )) suite_list.append(suite('SCM_RRFS_v1', 'tracers_RRFS_v1.txt', 'input_RRFS_v1.nml', 600.0, 600.0 , True )) -suite_list.append(suite('SCM_RRFS_v1beta', 'tracers_RRFS_v1beta.txt', 'input_RRFS_v1beta.nml', 600.0, 600.0 , True )) suite_list.append(suite('SCM_WoFS_v0', 'tracers_WoFS_v0.txt', 'input_WoFS_v0.nml', 600.0, 600.0 , True )) -suite_list.append(suite('SCM_HRRR', 'tracers_HRRR.txt', 'input_HRRR.nml', 600.0, 600.0 , True )) +suite_list.append(suite('SCM_GFS_v16_RRTMGP', 'tracers_GFS_v16.txt', 'input_GFS_v16_RRTMGP.nml', 600.0, 1800.0, True )) +suite_list.append(suite('SCM_HRRR', 'tracers_HRRR.txt', 'input_HRRR.nml', 600.0, 600.0 , False)) +suite_list.append(suite('SCM_RRFS_v1beta', 'tracers_RRFS_v1beta.txt', 'input_RRFS_v1beta.nml', 600.0, 600.0 , False)) suite_list.append(suite('SCM_GFS_v15p2', 'tracers_GFS_v15p2.txt', 'input_GFS_v15p2.nml', 600.0, 1800.0, False)) suite_list.append(suite('SCM_GFS_v15p2_RRTMGP', 'tracers_GFS_v15p2.txt', 'input_GFS_v15p2_RRTMGP.nml', 600.0, 1800.0, False)) suite_list.append(suite('SCM_GFS_v15p2_no_nsst', 'tracers_GFS_v15p2.txt', 'input_GFS_v15p2.nml', 600.0, 1800.0, False)) @@ -60,7 +59,6 @@ def timestep(self, value): suite_list.append(suite('SCM_GFS_v15p2_YSU', 'tracers_GFS_v15p2.txt', 'input_GFS_v15p2_YSU.nml', 600.0, 1800.0, False)) suite_list.append(suite('SCM_GFS_v15p2_saYSU', 'tracers_GFS_v15p2.txt', 'input_GFS_v15p2_saYSU.nml', 600.0, 1800.0, False)) suite_list.append(suite('SCM_GFS_v15p2_ACM', 'tracers_GFS_v15p2.txt', 'input_GFS_v15p2_ACM.nml', 600.0, 1800.0, False)) -suite_list.append(suite('SCM_GFS_v16_RRTMGP', 'tracers_GFS_v16.txt', 'input_GFS_v16_RRTMGP.nml', 600.0, 1800.0, False)) suite_list.append(suite('SCM_GFS_v16_no_nsst', 'tracers_GFS_v16.txt', 'input_GFS_v16.nml', 600.0, 1800.0, False)) suite_list.append(suite('HAFS_v0_hwrf', 'tracers_HAFS_v0_hwrf.txt', 'input_HAFS_v0_hwrf.nml', 600.0, 1800.0, False)) suite_list.append(suite('HAFS_v0_hwrf_thompson', 'tracers_HAFS_v0_hwrf_thompson.txt', 'input_HAFS_v0_hwrf_thompson.nml', 600.0, 600.0 , False)) diff --git a/scm/src/supported_suites.py b/scm/src/supported_suites.py index aee06a705..5c067af46 100644 --- a/scm/src/supported_suites.py +++ b/scm/src/supported_suites.py @@ -1 +1 @@ -suites = ["SCM_GFS_v16","SCM_GFS_v17_p8","SCM_GFS_v17_HR3","SCM_HRRR","SCM_RAP","SCM_RRFS_v1beta","SCM_WoFS_v0"] +suites = ["SCM_GFS_v16","SCM_GFS_v16_RRTMGP","SCM_GFS_v17_p8_ugwpv1","SCM_RAP","SCM_RRFS_v1beta","SCM_WoFS_v0"] From f4fba4236e63b6a6aa1db7adc21357ab1cf76ead Mon Sep 17 00:00:00 2001 From: Dustin Swales Date: Mon, 15 Jul 2024 22:02:17 +0000 Subject: [PATCH 13/25] Bugfixes --- .../{input_GFS_v17_p8_ugwpv1 => input_GFS_v17_p8_ugwpv1.nml} | 0 ccpp/suites/suite_SCM_GFS_v17_p8_ugwpv1.xml | 2 +- ccpp/suites/suite_SCM_GFS_v17_p8_ugwpv1_ps.xml | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename ccpp/physics_namelists/{input_GFS_v17_p8_ugwpv1 => input_GFS_v17_p8_ugwpv1.nml} (100%) diff --git a/ccpp/physics_namelists/input_GFS_v17_p8_ugwpv1 b/ccpp/physics_namelists/input_GFS_v17_p8_ugwpv1.nml similarity index 100% rename from ccpp/physics_namelists/input_GFS_v17_p8_ugwpv1 rename to ccpp/physics_namelists/input_GFS_v17_p8_ugwpv1.nml diff --git a/ccpp/suites/suite_SCM_GFS_v17_p8_ugwpv1.xml b/ccpp/suites/suite_SCM_GFS_v17_p8_ugwpv1.xml index 6c823ece3..865fe47f6 100644 --- a/ccpp/suites/suite_SCM_GFS_v17_p8_ugwpv1.xml +++ b/ccpp/suites/suite_SCM_GFS_v17_p8_ugwpv1.xml @@ -1,6 +1,6 @@ - + diff --git a/ccpp/suites/suite_SCM_GFS_v17_p8_ugwpv1_ps.xml b/ccpp/suites/suite_SCM_GFS_v17_p8_ugwpv1_ps.xml index 2c080fb93..cd62b628e 100644 --- a/ccpp/suites/suite_SCM_GFS_v17_p8_ugwpv1_ps.xml +++ b/ccpp/suites/suite_SCM_GFS_v17_p8_ugwpv1_ps.xml @@ -1,6 +1,6 @@ - + From 9c7d13e39cede6282a6663ead1eadf9f9dbe60d9 Mon Sep 17 00:00:00 2001 From: Dustin Swales Date: Mon, 15 Jul 2024 22:22:50 +0000 Subject: [PATCH 14/25] Update SDFs in CI RT script --- .github/workflows/ci_run_scm_rts.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci_run_scm_rts.yml b/.github/workflows/ci_run_scm_rts.yml index 89db8a0a6..31c991549 100644 --- a/.github/workflows/ci_run_scm_rts.yml +++ b/.github/workflows/ci_run_scm_rts.yml @@ -1,3 +1,4 @@ + name: CI test to build and run SCM regression tests on: [pull_request, workflow_dispatch] @@ -21,8 +22,8 @@ jobs: sp_ROOT: /home/runner/NCEPLIBS-sp w3emc_ROOT: /home/runner/myw3emc SCM_ROOT: /home/runner/work/ccpp-scm/ccpp-scm - suites: SCM_GFS_v15p2,SCM_GFS_v16,SCM_GFS_v17_p8,SCM_HRRR,SCM_RRFS_v1beta,SCM_RAP,SCM_WoFS_v0,SCM_RRFS_v1,SCM_GFS_v17_HR3,SCM_GFS_v17_HR3_RRTMGP - suites_ps: SCM_GFS_v15p2_ps,SCM_GFS_v16_ps,SCM_GFS_v17_p8_ps,SCM_HRRR_ps,SCM_RRFS_v1beta_ps,SCM_RAP_ps,SCM_WoFS_v0_ps,SCM_RRFS_v1_ps,SCM_GFS_v17_HR3_ps,SCM_GFS_v17_HR3_RRTMGP_ps + suites: SCM_GFS_v15p2,SCM_GFS_v16,SCM_GFS_v17_p8,SCM_HRRR,SCM_RRFS_v1beta,SCM_RAP,SCM_WoFS_v0,SCM_RRFS_v1,SCM_GFS_v17_p8_ugwpv1 + suites_ps: SCM_GFS_v15p2_ps,SCM_GFS_v16_ps,SCM_GFS_v17_p8_ps,SCM_HRRR_ps,SCM_RRFS_v1beta_ps,SCM_RAP_ps,SCM_WoFS_v0_ps,SCM_RRFS_v1_ps,SCM_GFS_v17_p8_ugwpv1_ps dir_rt: /home/runner/work/ccpp-scm/ccpp-scm/test/artifact-${{matrix.build-type}} dir_bl: /home/runner/work/ccpp-scm/ccpp-scm/test/BL-${{matrix.build-type}} From 804758fdfb20b06b035af5de5cd6fb391d15cd31 Mon Sep 17 00:00:00 2001 From: dustinswales Date: Tue, 16 Jul 2024 08:33:27 -0600 Subject: [PATCH 15/25] Update SDF names in test_cases --- test/rt_test_cases.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/test/rt_test_cases.py b/test/rt_test_cases.py index 0a2bd76d0..70750a213 100644 --- a/test/rt_test_cases.py +++ b/test/rt_test_cases.py @@ -2,28 +2,28 @@ #---------------------------------------------------------------------------------------------------------------------------------------------- # Supported suites for CCPP Version 7 release #---------------------------------------------------------------------------------------------------------------------------------------------- - {"case": "arm_sgp_summer_1997_A", "suite": "SCM_GFS_v17_HR3"}, \ - {"case": "arm_sgp_summer_1997_A", "suite": "SCM_GFS_v17_HR3_RRTMGP"}, \ + {"case": "arm_sgp_summer_1997_A", "suite": "SCM_GFS_v17_p8_ugwpv1"}, \ + {"case": "arm_sgp_summer_1997_A", "suite": "SCM_GFS_v16_RRTMGP"}, \ {"case": "arm_sgp_summer_1997_A", "suite": "SCM_GFS_v16"}, \ {"case": "arm_sgp_summer_1997_A", "suite": "SCM_WoFS_v0"}, \ {"case": "arm_sgp_summer_1997_A", "suite": "SCM_RRFS_v1"}, \ - {"case": "twpice", "suite": "SCM_GFS_v17_HR3"}, \ - {"case": "twpice", "suite": "SCM_GFS_v17_HR3_RRTMGP"}, \ + {"case": "twpice", "suite": "SCM_GFS_v17_p8_ugwpv1"}, \ + {"case": "twpice", "suite": "SCM_GFS_v16_RRTMGP"}, \ {"case": "twpice", "suite": "SCM_GFS_v16"}, \ {"case": "twpice", "suite": "SCM_WoFS_v0"}, \ {"case": "twpice", "suite": "SCM_RRFS_v1"}, \ - {"case": "bomex", "suite": "SCM_GFS_v17_HR3"}, \ - {"case": "bomex", "suite": "SCM_GFS_v17_HR3_RRTMGP"}, \ + {"case": "bomex", "suite": "SCM_GFS_v17_p8_ugwpv1"}, \ + {"case": "bomex", "suite": "SCM_GFS_v16_RRTMGP"}, \ {"case": "bomex", "suite": "SCM_GFS_v16"}, \ {"case": "bomex", "suite": "SCM_WoFS_v0"}, \ {"case": "bomex", "suite": "SCM_RRFS_v1"}, \ - {"case": "astex", "suite": "SCM_GFS_v17_HR3"}, \ - {"case": "astex", "suite": "SCM_GFS_v17_HR3_RRTMGP"}, \ + {"case": "astex", "suite": "SCM_GFS_v17_p8_ugwpv1"}, \ + {"case": "astex", "suite": "SCM_GFS_v16_RRTMGP"}, \ {"case": "astex", "suite": "SCM_GFS_v16"}, \ {"case": "astex", "suite": "SCM_WoFS_v0"}, \ {"case": "astex", "suite": "SCM_RRFS_v1"}, \ - {"case": "LASSO_2016051812", "suite": "SCM_GFS_v17_HR3"}, \ - {"case": "LASSO_2016051812", "suite": "SCM_GFS_v17_HR3_RRTMGP"}, \ + {"case": "LASSO_2016051812", "suite": "SCM_GFS_v17_p8_ugwpv1"}, \ + {"case": "LASSO_2016051812", "suite": "SCM_GFS_v16_RRTMGP"}, \ {"case": "LASSO_2016051812", "suite": "SCM_GFS_v16"}, \ {"case": "LASSO_2016051812", "suite": "SCM_WoFS_v0"}, \ {"case": "LASSO_2016051812", "suite": "SCM_RRFS_v1"}, \ From f8d81d8696102f3dbc05fbe2f8649edfad08de51 Mon Sep 17 00:00:00 2001 From: dustinswales Date: Tue, 16 Jul 2024 09:01:33 -0600 Subject: [PATCH 16/25] Another missed change --- scm/src/suite_info.py | 1 + scm/src/supported_suites.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/scm/src/suite_info.py b/scm/src/suite_info.py index 290b8cbf3..dbb8cbeff 100755 --- a/scm/src/suite_info.py +++ b/scm/src/suite_info.py @@ -49,6 +49,7 @@ def timestep(self, value): suite_list.append(suite('SCM_WoFS_v0', 'tracers_WoFS_v0.txt', 'input_WoFS_v0.nml', 600.0, 600.0 , True )) suite_list.append(suite('SCM_GFS_v16_RRTMGP', 'tracers_GFS_v16.txt', 'input_GFS_v16_RRTMGP.nml', 600.0, 1800.0, True )) +suite_list.append(suite('SCM_GFS_v17_p8', 'tracers_GFS_v17_p8.txt', 'input_GFS_v17_p8.nml', 600.0, 600.0, False)) suite_list.append(suite('SCM_HRRR', 'tracers_HRRR.txt', 'input_HRRR.nml', 600.0, 600.0 , False)) suite_list.append(suite('SCM_RRFS_v1beta', 'tracers_RRFS_v1beta.txt', 'input_RRFS_v1beta.nml', 600.0, 600.0 , False)) suite_list.append(suite('SCM_GFS_v15p2', 'tracers_GFS_v15p2.txt', 'input_GFS_v15p2.nml', 600.0, 1800.0, False)) diff --git a/scm/src/supported_suites.py b/scm/src/supported_suites.py index 5c067af46..80055d21e 100644 --- a/scm/src/supported_suites.py +++ b/scm/src/supported_suites.py @@ -1 +1 @@ -suites = ["SCM_GFS_v16","SCM_GFS_v16_RRTMGP","SCM_GFS_v17_p8_ugwpv1","SCM_RAP","SCM_RRFS_v1beta","SCM_WoFS_v0"] +suites = ["SCM_GFS_v16","SCM_GFS_v16_RRTMGP","SCM_GFS_v17_p8_ugwpv1","SCM_RAP","SCM_RRFS_v1","SCM_WoFS_v0"] From 8cb9d5dbd0da493ca03c40ae019348d5674ac9b1 Mon Sep 17 00:00:00 2001 From: Grant Firl Date: Tue, 16 Jul 2024 15:37:22 -0400 Subject: [PATCH 17/25] update UFS_case_gen.py with expanded stencil method for calculating geostrophic winds; add flags to control whether actual geostrophic winds are used vs. mean modeled wind profiles, whether surface geopotential is used to calculate horizontal geopotential derivatives --- scm/etc/scripts/UFS_case_gen.py | 264 +++++++++++++++++++++++++++----- 1 file changed, 225 insertions(+), 39 deletions(-) diff --git a/scm/etc/scripts/UFS_case_gen.py b/scm/etc/scripts/UFS_case_gen.py index 7345e956a..9d44e4f6e 100755 --- a/scm/etc/scripts/UFS_case_gen.py +++ b/scm/etc/scripts/UFS_case_gen.py @@ -35,9 +35,15 @@ one_twelfth = 1.0/12.0 two_thirds = 2.0/3.0 +use_oro_for_geos_wind = False #use surface geopotential in the calculation of geostrophic winds (if True, the gradient of geopotential will include the surface geopotential height gradient) +use_actual_geos_wind = False #use geostrophic winds calculated from the large-scale UFS-modeled geopotential (the scale is determined by the modeled winds and the choice of critical Rossby number for which geostrophic balance is assumed to hold) +critical_Rossby = 0.1 #the Rossby number under which geostrophic balance is assumed to be valid (a lower number means a larger horizontal area is required for a given wind speed); geostrophic balance can be assumed when Ro << 1. + +PBL_top_for_geos = 85000.0 # (Pa) when using the mean UFS-modeled winds as geostrophic winds, below this pressure, geostrophic winds return linearly to 0 at the surface + missing_value = -9999.0 #9.99e20 -top_pres_for_forcing = 20000.0 +top_pres_for_forcing = 20000.0 # (Pa) pressure above which to vertically smooth wind profiles to handle noisy model output at upper UFS levels const_nudging_time = 3600.0 @@ -501,7 +507,6 @@ def find_loc_indices_UFS_history(loc, dir): theta = math.atan2(math.sin(math.radians(longitude[i,j] - loc[0]))*math.cos(math.radians(latitude[i,j])), math.cos(math.radians(loc[1]))*math.sin(math.radians(latitude[i,j])) - math.sin(math.radians(loc[1]))*math.cos(math.radians(latitude[i,j]))*math.cos(math.radians(longitude[i,j] - loc[0]))) theta_deg = math.fmod((math.degrees(theta) + 360.0), 360.0) - halo_indices = np.zeros((1+2*n_forcing_halo_points,1+2*n_forcing_halo_points)) if i < n_forcing_halo_points or i > latitude.shape[0]-1-n_forcing_halo_points: message = 'Chosen point too close to the poles for this algorithm' logging.critical(message) @@ -667,11 +672,6 @@ def check_IC_hist_surface_compatibility(dir, i, j, surface_data, lam, old_chgres nc_file = Dataset('{0}/{1}'.format(dir,filename)) - #doublecheck this is correct point - #lon_in = read_NetCDF_var(nc_file, "lon", j, i) - #lat_in = read_NetCDF_var(nc_file, "lat", j, i) - #logging.debug('check_IC_hist_surface_compatibility lon/lat: {}/{}'.format(lon_in, lat_in)) - slmsk_hist = read_NetCDF_surface_var(nc_file, "land", j, i, old_chgres, 0) if (slmsk_hist != surface_data["slmsk"]): @@ -1830,7 +1830,7 @@ def search_in_dict(listin,name): if dictionary["name"] == name: return count -def get_UFS_forcing_data_advective_tendency(dir, i, j, tile, neighbors, dx, dy, nlevs, lam, save_comp_data, vertical_method, geos_wind_forcing, wind_nudge): +def expand_neighbors_for_geostrophic_balance(dir, hist_i, hist_j, neighbors, dx, dy, nlevs, lam): # Determine UFS history file format (tiled/quilted) if lam: @@ -1855,6 +1855,130 @@ def get_UFS_forcing_data_advective_tendency(dir, i, j, tile, neighbors, dx, dy, npts = 2*n_forcing_halo_points+1 + lon = np.zeros((n_filesA,npts,npts)) + lat = np.zeros((n_filesA,npts,npts)) + time = np.zeros((n_filesA)) + u_wind = np.zeros((n_filesA,nlevs,npts,npts)) + v_wind = np.zeros((n_filesA,nlevs,npts,npts)) + wind_speed = np.zeros((n_filesA,nlevs)) + wind_speed_time_mean = np.zeros((nlevs)) + + nc_file = Dataset('{0}/{1}'.format(dir,atm_filenames[0])) + nc_file.set_always_mask(False) + longitude_all = np.asarray(nc_file['lon']) + latitude_all = np.asarray(nc_file['lat']) + nc_file.close() + + #determine average wind speeds in the existing forcing stencil + + # Read in 3D UFS history files + for count, filename in enumerate(atm_filenames, start=1): + nc_file = Dataset('{0}/{1}'.format(dir,filename)) + nc_file.set_always_mask(False) + + time[count-1] = nc_file['time'][0] + + for ii in range(2*n_forcing_halo_points+1): + for jj in range(2*n_forcing_halo_points+1): + current_ii_index = neighbors[0,ii,jj] + current_jj_index = neighbors[1,ii,jj] + + lon[count-1,ii,jj] = nc_file['lon'][current_ii_index,current_jj_index] + lat[count-1,ii,jj] = nc_file['lat'][current_ii_index,current_jj_index] + u_wind[count-1,:,ii,jj] = nc_file['ugrd'][0,::-1,current_ii_index,current_jj_index] + v_wind[count-1,:,ii,jj] = nc_file['vgrd'][0,::-1,current_ii_index,current_jj_index] + + for k in range(nlevs): + wind_speed[count-1,k] = np.sqrt(np.mean(u_wind[count-1,k,:,:])**2 + np.mean(v_wind[count-1,k,:,:]**2)) + + nc_file.close() + + critical_geos_scale_npts = np.zeros((nlevs)) + mean_lat = np.mean(lat[:,:,:]) + coriolis = 2.0*Omega*np.sin(mean_lat*deg_to_rad) + grid_length_scale = np.sqrt(np.mean(dx)**2 + np.mean(dy)**2)*1.0E3 + for k in range(nlevs): + wind_speed_time_mean[k] = np.mean(wind_speed[:,k]) + critical_geos_scale = wind_speed_time_mean[k]/(coriolis*critical_Rossby) + critical_geos_scale_npts[k] = critical_geos_scale/grid_length_scale + floor = np.floor(np.mean(critical_geos_scale_npts)) + ceiling = np.ceil(np.mean(critical_geos_scale_npts)) + if (floor%2 == 1): + odd_pts = int(floor) + else: + odd_pts = int(ceiling) + + message = 'Need {} points for approximate geostrophic balance assuming a Rossby number of {}'.format(odd_pts, critical_Rossby) + logging.debug(message) + + n_geo_halo_points = int((odd_pts - 1)/2) + + if hist_i < n_geo_halo_points or hist_i > latitude_all.shape[0]-1-n_geo_halo_points: + message = 'There are not enough neighboring grid cells between the chosen point and the poles for calculation of geostrophic winds' + logging.critical(message) + raise Exception(message) + else: + #longitude = (n rows of latitude, 2*n columns of longitude), i index increases toward EAST; rows are circles of latitude, columns are meridians + #latitude = (n rows of latitude, 2*n columns of longitude), j index increases toward NORTH; rows are circles of latitude, columns are meridians + new_neighbors = np.mgrid[-n_geo_halo_points:n_geo_halo_points+1,-n_geo_halo_points:n_geo_halo_points+1] + new_neighbors[0,:,:] = new_neighbors[0,:,:] + hist_i + new_neighbors[1,:,:] = new_neighbors[1,:,:] + hist_j + + + # the closest point is near the western edge of the prime meridian, but longitude should be cyclic, so get neighbors on the eastern/western side of the prime meridian as necessary + new_neighbors[1,:,:] = new_neighbors[1,:,:]%longitude_all.shape[1] + + new_neighbors = new_neighbors.astype(int) + #message = 'orig neighbors',neighbors,latitude_all[neighbors[0,:,0],neighbors[1,0,:]],longitude_all[neighbors[0,:,0],neighbors[1,0,:]] + #logging.debug(message) + #message = 'new neighbors',new_neighbors,latitude_all[new_neighbors[0,:,0],new_neighbors[1,0,:]],longitude_all[new_neighbors[0,:,0],new_neighbors[1,0,:]] + #logging.debug(message) + + #calc dx, dy (n_forcing_halo_points*2 x n_forcing_halo_points*2) + new_dx = np.zeros((n_geo_halo_points*2+1,n_geo_halo_points*2)) + new_dy = np.zeros((n_geo_halo_points*2,n_geo_halo_points*2+1)) + for ii in range(2*n_geo_halo_points+1): + for jj in range(2*n_geo_halo_points): + current_ii_index = new_neighbors[0,ii,jj] + current_jj_index = new_neighbors[1,ii,jj] + eastern_jj_index = new_neighbors[1,ii,jj+1] + new_dx[ii,jj] = haversine_distance(latitude_all[current_ii_index,current_jj_index],longitude_all[current_ii_index,current_jj_index],latitude_all[current_ii_index,eastern_jj_index],longitude_all[current_ii_index,eastern_jj_index]) + + for ii in range(2*n_geo_halo_points): + for jj in range(2*n_geo_halo_points+1): + current_ii_index = new_neighbors[0,ii,jj] + northern_ii_index = new_neighbors[0,ii+1,jj] + current_jj_index = new_neighbors[1,ii,jj] + new_dy[ii,jj] = haversine_distance(latitude_all[current_ii_index,current_jj_index],longitude_all[current_ii_index,current_jj_index],latitude_all[northern_ii_index,current_jj_index],longitude_all[northern_ii_index,current_jj_index]) + + return (n_geo_halo_points, new_neighbors, new_dx, new_dy) + +def get_UFS_forcing_data_advective_tendency(dir, i, j, tile, neighbors, dx, dy, nlevs, lam, save_comp_data, vertical_method, geos_wind_forcing, wind_nudge, geo_pts, geo_neighbors, geo_dx, geo_dy, use_actual_geos_wind): + + # Determine UFS history file format (tiled/quilted) + if lam: + atm_ftag = 'atmf*.tile{0}.nc'.format(tile) + sfc_ftag = 'sfcf*.tile{0}.nc'.format(tile) + else: + atm_ftag = '*atmf*.nc' + sfc_ftag = '*sfcf*.nc' + + # Get list of UFS history files with 3D ATMospheric state variables. + atm_filenames = [] + for f_name in os.listdir(dir): + if fnmatch.fnmatch(f_name, atm_ftag): + atm_filenames.append(f_name) + if not atm_filenames: + message = 'No filenames matching the pattern {0} found in {1}'. \ + format(atm_ftag,dir) + logging.critical(message) + raise Exception(message) + atm_filenames = sorted(atm_filenames) + n_filesA = len(atm_filenames) + + npts = 2*n_forcing_halo_points+1 + npts_geo = 2*geo_pts+1 + lon = np.zeros((n_filesA,npts,npts)) lat = np.zeros((n_filesA,npts,npts)) time = np.zeros((n_filesA)) @@ -1867,7 +1991,10 @@ def get_UFS_forcing_data_advective_tendency(dir, i, j, tile, neighbors, dx, dy, presi = np.zeros((n_filesA,nlevs+1)) pressfc = np.zeros((n_filesA,npts,npts)) delz = np.zeros((n_filesA,nlevs,npts,npts)) - #hgtsfc = np.zeros((n_filesA,npts,npts)) + if(geos_wind_forcing and use_actual_geos_wind): + temp_geo = np.zeros((n_filesA,nlevs,npts_geo,npts_geo)) + qv_geo = np.zeros((n_filesA,nlevs,npts_geo,npts_geo)) + hgtsfc = np.zeros((n_filesA,npts,npts)) # Read in 3D UFS history files for count, filename in enumerate(atm_filenames, start=1): @@ -1890,7 +2017,16 @@ def get_UFS_forcing_data_advective_tendency(dir, i, j, tile, neighbors, dx, dy, qv[count-1,:,ii,jj] = nc_file['spfh'][0,::-1,current_ii_index,current_jj_index] pressfc[count-1,ii,jj] = nc_file['pressfc'][0,current_ii_index,current_jj_index] delz[count-1,:,ii,jj] = -1*nc_file['delz'][0,::-1,current_ii_index,current_jj_index] #derive zh - #hgtsfc[count-1,ii,jj] = nc_file['hgtsfc'][0,current_ii_index,current_jj_index] + + if (geos_wind_forcing and use_actual_geos_wind): + for ii in range(npts_geo): + for jj in range(npts_geo): + current_ii_index = geo_neighbors[0,ii,jj] + current_jj_index = geo_neighbors[1,ii,jj] + temp_geo[count-1,:,ii,jj] = nc_file['tmp'][0,::-1,current_ii_index,current_jj_index] + qv_geo[count-1,:,ii,jj] = nc_file['spfh'][0,::-1,current_ii_index,current_jj_index] + hgtsfc[count-1,ii,jj] = nc_file['hgtsfc'][0,current_ii_index,current_jj_index] + pres[count-1,:] = nc_file['pfull'][::-1]*100.0 presi[count-1,:] = nc_file['phalf'][::-1]*100.0 @@ -1915,10 +2051,15 @@ def get_UFS_forcing_data_advective_tendency(dir, i, j, tile, neighbors, dx, dy, v_advec_v = np.zeros((n_filesA,nlevs)) v_advec_T = np.zeros((n_filesA,nlevs)) v_advec_qv = np.zeros((n_filesA,nlevs)) + t_advec_u = np.zeros((n_filesA,nlevs)) + t_advec_v = np.zeros((n_filesA,nlevs)) + t_advec_T = np.zeros((n_filesA,nlevs)) + t_advec_qv = np.zeros((n_filesA,nlevs)) u_g = np.zeros((n_filesA,nlevs)) v_g = np.zeros((n_filesA,nlevs)) - phii = np.zeros((n_filesA,nlevs+1,npts,npts)) - phil = np.zeros((n_filesA,nlevs,npts,npts)) + if(geos_wind_forcing and use_actual_geos_wind): + phii = np.zeros((n_filesA,nlevs+1,npts_geo,npts_geo)) + phil = np.zeros((n_filesA,nlevs,npts_geo,npts_geo)) for t in range(n_filesA): #velocities gets very noisy in the UFS above the tropopause; define a linear return-to-zero profile above some pressure k_p_top = np.where(pres[t,:] <= top_pres_for_forcing)[0][0] @@ -1998,26 +2139,65 @@ def get_UFS_forcing_data_advective_tendency(dir, i, j, tile, neighbors, dx, dy, v_advec_v[t,k] = rho*grav*(w_asc*gradient_v_asc + w_des*gradient_v_des) v_advec_T[t,k] = rho*grav*(w_asc*gradient_T_asc + w_des*gradient_T_des) + adiabatic_exp_comp_term v_advec_qv[t,k] = rho*grav*(w_asc*gradient_qv_asc + w_des*gradient_qv_des) - + if (geos_wind_forcing): - #calc geopotential at interface levels, starting from surface, convert to full pressure levels - for ii in range(npts): - for jj in range(npts): - phii[t,0,ii,jj] = 0.0#hgtsfc[t,ii,jj]*grav #don't need to include orography -- geostrophic winds should assume geopotential over the geoid - for k in range(1,nlevs+1): - phii[t,k,ii,jj] = phii[t,k-1,ii,jj] - rdgas*temp[t,k-1,ii,jj]*(1.0 + zvir*qv[t,k-1,ii,jj])*np.log(presi[t,k]/presi[t,k-1]) - - for k in range(0,nlevs): - phil[t,k,ii,jj] = 0.5*(phii[t,k,ii,jj] + phii[t,k+1,ii,jj]) + coriolis = 2.0*Omega*np.sin(lat[t,center,center]*deg_to_rad) + + if (use_actual_geos_wind): + #calc geopotential at interface levels, starting from surface, convert to full pressure levels + for ii in range(npts_geo): + for jj in range(npts_geo): + if (use_oro_for_geos_wind): + phii[t,0,ii,jj] = hgtsfc[t,ii,jj]*grav + else: + phii[t,0,ii,jj] = 0.0 #don't need to include orography -- geostrophic winds should assume geopotential over the geoid + for k in range(1,nlevs+1): + phii[t,k,ii,jj] = phii[t,k-1,ii,jj] - rdgas*temp_geo[t,k-1,ii,jj]*(1.0 + zvir*qv_geo[t,k-1,ii,jj])*np.log(presi[t,k]/presi[t,k-1]) + + for k in range(0,nlevs): + phil[t,k,ii,jj] = 0.5*(phii[t,k,ii,jj] + phii[t,k+1,ii,jj]) + + for k in range(1,nlevs): + dphidx = np.zeros((npts_geo,npts_geo)) + dphidy = np.zeros((npts_geo,npts_geo)) + #valid points: + #dphidx = np.zeros((npts_geo,npts_geo-2)) + #dphidy = np.zeros((npts_geo-2,npts_geo)) + for ii in range(0,npts_geo): + for jj in range(1,npts_geo-1): + dphidx[ii,jj] = centered_diff_derivative(phil[t,k,ii,jj-1:jj+2],geo_dx[ii,jj-1:jj+1]*1.0E3) + mean_dphidx = np.mean(dphidx[0:npts_geo,1:npts_geo-1]) + + for ii in range(1,npts_geo-1): + for jj in range(0,npts_geo): + dphidy[ii,jj] = centered_diff_derivative(phil[t,k,ii-1:ii+2,jj],geo_dy[ii-1:ii+1,jj]*1.0E3) + mean_dphidy = np.mean(dphidy[1:npts_geo-1,0:npts_geo]) + + u_g[t,k] = -mean_dphidy/coriolis + v_g[t,k] = mean_dphidx/coriolis + else: + for k in range(0,nlevs): + u_g[t,k] = np.mean(u_wind[t,k,:,:]) + v_g[t,k] = np.mean(v_wind[t,k,:,:]) + k_pbl_top = np.where(pres[t,:] <= PBL_top_for_geos)[0][0] + u_g[t,0] = 0.0 + v_g[t,0] = 0.0 + for k in range(1,k_pbl_top): + lifrac = (pres[t,k] - pres[t,0])/(pres[t,k_pbl_top] - pres[t,0]) + u_g[t,k] = lifrac*u_g[t,k_pbl_top] + v_g[t,k] = lifrac*v_g[t,k_pbl_top] - mean_lat = np.mean(lat[t,:,:]) - coriolis = 2.0*Omega*np.sin(mean_lat*deg_to_rad) - for k in range(1,nlevs): - dphidx = centered_diff_derivative(phil[t,k,center,:],dx[center,:]*1.0E3) - dphidy = centered_diff_derivative(phil[t,k,:,center],dy[:,center]*1.0E3) - - u_g[t,k] = -dphidy/coriolis - v_g[t,k] = dphidx/coriolis + + if (vertical_method == 1): + t_advec_T[:,:] = h_advec_T[:,:] + v_advec_T[:,:] + t_advec_qv[:,:] = h_advec_qv[:,:] + v_advec_qv[:,:] + t_advec_u[:,:] = h_advec_u[:,:] + v_advec_u[:,:] + t_advec_v[:,:] = h_advec_v[:,:] + v_advec_v[:,:] + else: + t_advec_T[:,:] = h_advec_T[:,:] + t_advec_qv[:,:] = h_advec_qv[:,:] + t_advec_u[:,:] = h_advec_u[:,:] + t_advec_v[:,:] = h_advec_v[:,:] if (save_comp_data): # Read in 2D UFS history files @@ -2094,10 +2274,10 @@ def get_UFS_forcing_data_advective_tendency(dir, i, j, tile, neighbors, dx, dy, "wa": smoothed_w, "ps_forc": pressfc[:,center,center], "pa_forc": pres, - "tnta_adv": h_advec_T[:,:] + v_advec_T[:,:], - "tnqv_adv": h_advec_qv[:,:] + v_advec_qv[:,:], - "tnua_adv": h_advec_u[:,:] + v_advec_u[:,:], - "tnva_adv": h_advec_v[:,:] + v_advec_v[:,:], + "tnta_adv": t_advec_T[:,:], + "tnqv_adv": t_advec_qv[:,:], + "tnua_adv": t_advec_u[:,:], + "tnva_adv": t_advec_v[:,:], "ug" : u_g[:,:], "vg" : v_g[:,:], "ua_nud" : u_wind[:,:,center,center], @@ -3014,10 +3194,8 @@ def write_SCM_case_file(state, surface, oro, forcing, init, case, date, forcing_ # nc_file.adv_ta = forcing_on nc_file.adv_qv = forcing_on - if (not geos_wind_forcing): - nc_file.adv_ua = forcing_on - nc_file.adv_va = forcing_on - # + nc_file.adv_ua = forcing_on + nc_file.adv_va = forcing_on nc_file.surface_forcing_temp = 'none' nc_file.surface_forcing_moisture = 'none' nc_file.surface_forcing_wind = 'none' @@ -3545,7 +3723,15 @@ def main(): grid_dir, tile, IC_i, IC_j, lam,\ save_comp, exact_mode) elif forcing_method == 2: - (forcing_data, comp_data) = get_UFS_forcing_data_advective_tendency(forcing_dir, hist_i, hist_j, tile, neighbors, dx, dy, state_data["nlevs"], lam, save_comp, vertical_method, geos_wind_forcing, wind_nudge) + geo_pts = n_forcing_halo_points + geo_neighbors = '' + geo_dx = '' + geo_dy = '' + if (geos_wind_forcing and use_actual_geos_wind): + #need to check and potentially get more neighboring data for geostrophic wind (for low enough Rossby numbers where geostrophic balance can be assumed) + (geo_pts, geo_neighbors, geo_dx, geo_dy) = expand_neighbors_for_geostrophic_balance(forcing_dir, hist_i, hist_j, neighbors, dx, dy, state_data["nlevs"], lam) + (forcing_data, comp_data) = get_UFS_forcing_data_advective_tendency(forcing_dir, hist_i, hist_j, tile, neighbors, dx, dy, state_data["nlevs"], lam, save_comp, vertical_method, \ + geos_wind_forcing, wind_nudge, geo_pts, geo_neighbors, geo_dx, geo_dy, use_actual_geos_wind) elif forcing_method == 3: exact_mode = False (forcing_data, comp_data, stateInit) = get_UFS_forcing_data(state_data["nlevs"], state_data, \ From 9d5adc9db7a5ac3602d29a787a750d4865f55a1d Mon Sep 17 00:00:00 2001 From: Grant Firl Date: Wed, 17 Jul 2024 15:29:24 -0400 Subject: [PATCH 18/25] update GFS_typedefs for PR#207 --- .gitmodules | 6 ++++-- ccpp/framework | 2 +- ccpp/physics | 2 +- scm/src/GFS_typedefs.F90 | 41 ++++++++++++++++++++++++++++++++++----- scm/src/GFS_typedefs.meta | 20 +++++++++++++++++++ 5 files changed, 62 insertions(+), 9 deletions(-) diff --git a/.gitmodules b/.gitmodules index dc0798c32..265e5673c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,8 +4,10 @@ branch = main [submodule "ccpp-physics"] path = ccpp/physics - url = https://github.com/NCAR/ccpp-physics - branch = main + #url = https://github.com/NCAR/ccpp-physics + #branch = main + url = https://github.com/grantfirl/ccpp-physics + branch = ufs-dev-PR207 [submodule "CMakeModules"] path = CMakeModules url = https://github.com/noaa-emc/CMakeModules diff --git a/ccpp/framework b/ccpp/framework index ccfefcd0b..0f8232724 160000 --- a/ccpp/framework +++ b/ccpp/framework @@ -1 +1 @@ -Subproject commit ccfefcd0b426e011f94137031d5f7c2a4dda2659 +Subproject commit 0f8232724975c13289cad390c9a71fa2c6a9bff4 diff --git a/ccpp/physics b/ccpp/physics index 3a1969102..38f3f49db 160000 --- a/ccpp/physics +++ b/ccpp/physics @@ -1 +1 @@ -Subproject commit 3a19691021b779748f4b448d3f21ab381fcc6c6e +Subproject commit 38f3f49db734a345126446fc929db97358467646 diff --git a/scm/src/GFS_typedefs.F90 b/scm/src/GFS_typedefs.F90 index d1218b8da..d8fe5f446 100644 --- a/scm/src/GFS_typedefs.F90 +++ b/scm/src/GFS_typedefs.F90 @@ -703,7 +703,9 @@ module GFS_typedefs !< for use with internal file reads integer :: input_nml_file_length !< length (number of lines) in namelist for internal reads integer :: logunit - real(kind=kind_phys) :: fhzero !< hours between clearing of diagnostic buckets + real(kind=kind_phys) :: fhzero !< hours between clearing of diagnostic buckets (current bucket) + real(kind=kind_phys) :: fhzero_array(2) !< array to hold the the hours between clearing of diagnostic buckets + real(kind=kind_phys) :: fhzero_fhour(2) !< the maximum forecast length for the hours between clearing of diagnostic buckets logical :: ldiag3d !< flag for 3d diagnostic fields logical :: qdiag3d !< flag for 3d tracer diagnostic fields logical :: flag_for_gwd_generic_tend !< true if GFS_GWD_generic should calculate tendencies @@ -1121,6 +1123,7 @@ module GFS_typedefs logical :: do_gsl_drag_ls_bl !< flag for GSL drag (mesoscale GWD and blocking only) logical :: do_gsl_drag_ss !< flag for GSL drag (small-scale GWD only) logical :: do_gsl_drag_tofd !< flag for GSL drag (turbulent orog form drag only) + logical :: do_gwd_opt_psl !< flag for PSL drag (mesoscale GWD and blocking only) logical :: do_ugwp_v1 !< flag for version 1 ugwp GWD logical :: do_ugwp_v1_orog_only !< flag for version 1 ugwp GWD (orographic drag only) logical :: do_ugwp_v1_w_gsldrag !< flag for version 1 ugwp with OGWD of GSL @@ -1205,6 +1208,8 @@ module GFS_typedefs real(kind=kind_phys) :: ccwf(2) !< multiplication factor for critical cloud !< workfunction for RAS real(kind=kind_phys) :: cdmbgwd(4) !< multiplication factors for cdmb, gwd and NS gwd, tke based enhancement + real(kind=kind_phys) :: alpha_fd !< alpha coefficient for turbulent orographic form drag + real(kind=kind_phys) :: psl_gwd_dx_factor !< multiplication factors for grid spacing real(kind=kind_phys) :: sup !< supersaturation in pdf cloud when t is very low real(kind=kind_phys) :: ctei_rm(2) !< critical cloud top entrainment instability criteria !< (used if mstrat=.true.) @@ -3317,6 +3322,8 @@ subroutine control_initialize (Model, nlunit, fn_nml, me, master, & !--- BEGIN NAMELIST VARIABLES real(kind=kind_phys) :: fhzero = 0.0 !< hours between clearing of diagnostic buckets + real(kind=kind_phys) :: fhzero_array(1:2) = 0.0 !< array with hours between clearing of diagnostic buckets + real(kind=kind_phys) :: fhzero_fhour(1:2) = 0.0 !< the maximum forecast length for the hours between clearing of diagnostic buckets logical :: ldiag3d = .true. !< flag for 3d diagnostic fields logical :: qdiag3d = .true. !< flag for 3d tracer diagnostic fields logical :: lssav = .false. !< logical flag for storing diagnostics @@ -3638,6 +3645,7 @@ subroutine control_initialize (Model, nlunit, fn_nml, me, master, & logical :: do_gsl_drag_ls_bl = .false. !< flag for GSL drag (mesoscale GWD and blocking only) logical :: do_gsl_drag_ss = .false. !< flag for GSL drag (small-scale GWD only) logical :: do_gsl_drag_tofd = .false. !< flag for GSL drag (turbulent orog form drag only) + logical :: do_gwd_opt_psl = .false. !< flag for PSL drag (mesoscale GWD and blocking only) logical :: do_ugwp_v1 = .false. !< flag for version 1 ugwp GWD logical :: do_ugwp_v1_orog_only = .false. !< flag for version 1 ugwp GWD (orographic drag only) logical :: do_ugwp_v1_w_gsldrag = .false. !< flag for version 1 ugwp GWD (orographic drag only) @@ -3742,6 +3750,8 @@ subroutine control_initialize (Model, nlunit, fn_nml, me, master, & real(kind=kind_phys) :: ccwf(2) = (/1.0d0,1.0d0/) !< multiplication factor for critical cloud !< workfunction for RAS real(kind=kind_phys) :: cdmbgwd(4) = (/2.0d0,0.25d0,1.0d0,1.0d0/) !< multiplication factors for cdmb, gwd, and NS gwd, tke based enhancement + real(kind=kind_phys) :: alpha_fd = 12.0 !< alpha coefficient for turbulent orographic form drag + real(kind=kind_phys) :: psl_gwd_dx_factor = 6.0 !< multiplication factors for grid spacing real(kind=kind_phys) :: sup = 1.0 !< supersaturation in pdf cloud (IMP_physics=98) when t is very low !< or ice super saturation in SHOC (when do_shoc=.true.) real(kind=kind_phys) :: ctei_rm(2) = (/10.0d0,10.0d0/) !< critical cloud top entrainment instability criteria @@ -3987,9 +3997,9 @@ subroutine control_initialize (Model, nlunit, fn_nml, me, master, & NAMELIST /gfs_physics_nml/ & !--- general parameters - fhzero, ldiag3d, qdiag3d, lssav, naux2d, dtend_select, & - naux3d, aux2d_time_avg, aux3d_time_avg, fhcyc, & - thermodyn_id, sfcpress_id, & + fhzero, fhzero_array, fhzero_fhour, ldiag3d, qdiag3d, lssav, & + naux2d, dtend_select, naux3d, aux2d_time_avg, & + aux3d_time_avg, fhcyc, thermodyn_id, sfcpress_id, & !--- coupling parameters cplflx, cplice, cplocn2atm, cplwav, cplwav2atm, cplaqm, & cplchm, cpllnd, cpllnd2atm, cpl_imp_mrg, cpl_imp_dbg, & @@ -4065,6 +4075,7 @@ subroutine control_initialize (Model, nlunit, fn_nml, me, master, & gwd_opt, do_ugwp_v0, do_ugwp_v0_orog_only, & do_ugwp_v0_nst_only, & do_gsl_drag_ls_bl, do_gsl_drag_ss, do_gsl_drag_tofd, & + do_gwd_opt_psl, & do_ugwp_v1, do_ugwp_v1_orog_only, do_ugwp_v1_w_gsldrag, & ugwp_seq_update, var_ric, coef_ric_l, coef_ric_s, hurr_pbl, & do_myjsfc, do_myjpbl, & @@ -4073,7 +4084,9 @@ subroutine control_initialize (Model, nlunit, fn_nml, me, master, & shinhong, do_ysu, dspheat, lheatstrg, lseaspray, cnvcld, & xr_cnvcld, random_clds, shal_cnv, imfshalcnv, imfdeepcnv, & isatmedmf, do_deep, jcap, & - cs_parm, flgmin, cgwf, ccwf, cdmbgwd, sup, ctei_rm, crtrh, & + cs_parm, flgmin, cgwf, ccwf, cdmbgwd, alpha_fd, & + psl_gwd_dx_factor, & + sup, ctei_rm, crtrh, & dlqf, rbcr, shoc_parm, psauras, prauras, wminras, & do_sppt, do_shum, do_skeb, & do_spp, n_var_spp, & @@ -4206,6 +4219,11 @@ subroutine control_initialize (Model, nlunit, fn_nml, me, master, & Model%fn_nml = fn_nml Model%logunit = logunit Model%fhzero = fhzero + Model%fhzero_array = fhzero_array + Model%fhzero_fhour = fhzero_fhour + if( Model%fhzero_array(1) > 0. ) then + Model%fhzero = Model%fhzero_array(1) + endif Model%ldiag3d = ldiag3d Model%qdiag3d = qdiag3d if (qdiag3d .and. .not. ldiag3d) then @@ -4964,6 +4982,8 @@ subroutine control_initialize (Model, nlunit, fn_nml, me, master, & Model%cgwf = cgwf Model%ccwf = ccwf Model%cdmbgwd = cdmbgwd + Model%alpha_fd = alpha_fd + Model%psl_gwd_dx_factor = psl_gwd_dx_factor Model%sup = sup Model%ctei_rm = ctei_rm Model%crtrh = crtrh @@ -5011,6 +5031,7 @@ subroutine control_initialize (Model, nlunit, fn_nml, me, master, & Model%do_gsl_drag_ls_bl = do_gsl_drag_ls_bl Model%do_gsl_drag_ss = do_gsl_drag_ss Model%do_gsl_drag_tofd = do_gsl_drag_tofd + Model%do_gwd_opt_psl = do_gwd_opt_psl Model%do_ugwp_v1 = do_ugwp_v1 Model%do_ugwp_v1_orog_only = do_ugwp_v1_orog_only Model%do_ugwp_v1_w_gsldrag = do_ugwp_v1_w_gsldrag @@ -5026,6 +5047,7 @@ subroutine control_initialize (Model, nlunit, fn_nml, me, master, & Model%do_gsl_drag_tofd = .true. Model%do_gsl_drag_ss = .true. Model%do_ugwp_v1_orog_only = .false. + Model%do_gwd_opt_psl = .true. endif Model%do_myjsfc = do_myjsfc @@ -5676,6 +5698,10 @@ subroutine control_initialize (Model, nlunit, fn_nml, me, master, & Model%restart = restart Model%lsm_cold_start = .not. restart Model%hydrostatic = hydrostatic + if (Model%me == Model%master) then + print *,'in atm phys init, phour=',Model%phour,'fhour=',Model%fhour,'zhour=',Model%zhour,'kdt=',Model%kdt + endif + if(Model%hydrostatic .and. Model%lightning_threat) then write(0,*) 'Turning off lightning threat index for hydrostatic run.' @@ -6469,6 +6495,8 @@ subroutine control_print(Model) print *, ' nlunit : ', Model%nlunit print *, ' fn_nml : ', trim(Model%fn_nml) print *, ' fhzero : ', Model%fhzero + print *, ' fhzero_array : ', Model%fhzero_array + print *, ' fhzero_fhour : ', Model%fhzero_fhour print *, ' ldiag3d : ', Model%ldiag3d print *, ' qdiag3d : ', Model%qdiag3d print *, ' lssav : ', Model%lssav @@ -6824,6 +6852,8 @@ subroutine control_print(Model) print *, ' cgwf : ', Model%cgwf print *, ' ccwf : ', Model%ccwf print *, ' cdmbgwd : ', Model%cdmbgwd + print *, ' alpha_fd : ', Model%alpha_fd + print *, ' psl_gwd_dx_factor : ', Model%psl_gwd_dx_factor print *, ' sup : ', Model%sup print *, ' ctei_rm : ', Model%ctei_rm print *, ' crtrh : ', Model%crtrh @@ -6844,6 +6874,7 @@ subroutine control_print(Model) print *, ' do_gsl_drag_ls_bl : ', Model%do_gsl_drag_ls_bl print *, ' do_gsl_drag_ss : ', Model%do_gsl_drag_ss print *, ' do_gsl_drag_tofd : ', Model%do_gsl_drag_tofd + print *, ' do_gwd_opt_psl : ', Model%do_gwd_opt_psl print *, ' do_ugwp_v1 : ', Model%do_ugwp_v1 print *, ' do_ugwp_v1_orog_only : ', Model%do_ugwp_v1_orog_only print *, ' do_ugwp_v1_w_gsldrag : ', Model%do_ugwp_v1_w_gsldrag diff --git a/scm/src/GFS_typedefs.meta b/scm/src/GFS_typedefs.meta index 617a109e1..2e74c0e7a 100644 --- a/scm/src/GFS_typedefs.meta +++ b/scm/src/GFS_typedefs.meta @@ -5640,6 +5640,13 @@ dimensions = (4) type = real kind = kind_phys +[alpha_fd] + standard_name = alpha_coefficient_for_turbulent_orographic_form_drag + long_name = alpha coefficient for Beljaars et al turbulent orographic form drag + units = 1 + dimensions = () + type = real + kind = kind_phys [ccwf] standard_name = tunable_parameter_for_critical_cloud_workfunction_in_relaxed_arakawa_schubert_deep_convection long_name = multiplication factor for tical_cloud_workfunction @@ -7538,6 +7545,19 @@ units = flag dimensions = () type = logical +[do_gwd_opt_psl] + standard_name = do_gsl_drag_suite_with_psl_gwd_option + long_name = flag to activate PSL drag suite - mesoscale GWD and blocking + units = flag + dimensions = () + type = logical +[psl_gwd_dx_factor] + standard_name = effective_grid_spacing_of_psl_gwd_suite + long_name = multiplication of grid spacing + units = 1 + dimensions = () + type = real + kind = kind_phys [do_ugwp_v1] standard_name = flag_for_ugwp_version_1 long_name = flag to activate ver 1 CIRES UGWP From d4b1c1f8112980f836731b20a7c2e81b079a6677 Mon Sep 17 00:00:00 2001 From: Dustin Swales Date: Wed, 17 Jul 2024 21:16:46 +0000 Subject: [PATCH 19/25] Change RRFS_v1 to HRRR_gf SDF --- .github/workflows/ci_build_scm_ubuntu_22.04.yml | 2 +- .github/workflows/ci_run_scm_rts.yml | 4 ++-- .../{input_RRFS_v1.nml => input_HRRR_gf.nml} | 0 .../{suite_SCM_RRFS_v1.xml => suite_SCM_HRRR_gf.xml} | 4 ++-- ...ite_SCM_RRFS_v1_ps.xml => suite_SCM_HRRR_gf_ps.xml} | 4 ++-- .../{tracers_RRFS_v1.txt => tracers_HRRR_gf.txt} | 0 scm/src/suite_info.py | 2 +- scm/src/supported_suites.py | 2 +- test/rt_test_cases.py | 10 +++++----- 9 files changed, 14 insertions(+), 14 deletions(-) rename ccpp/physics_namelists/{input_RRFS_v1.nml => input_HRRR_gf.nml} (100%) rename ccpp/suites/{suite_SCM_RRFS_v1.xml => suite_SCM_HRRR_gf.xml} (98%) rename ccpp/suites/{suite_SCM_RRFS_v1_ps.xml => suite_SCM_HRRR_gf_ps.xml} (97%) rename scm/etc/tracer_config/{tracers_RRFS_v1.txt => tracers_HRRR_gf.txt} (100%) diff --git a/.github/workflows/ci_build_scm_ubuntu_22.04.yml b/.github/workflows/ci_build_scm_ubuntu_22.04.yml index e89dcb50c..21f9bb702 100644 --- a/.github/workflows/ci_build_scm_ubuntu_22.04.yml +++ b/.github/workflows/ci_build_scm_ubuntu_22.04.yml @@ -21,7 +21,7 @@ jobs: sp_ROOT: /home/runner/NCEPLIBS-sp w3emc_ROOT: /home/runner/myw3emc SCM_ROOT: /home/runner/work/ccpp-scm/ccpp-scm - suites: SCM_GFS_v15p2,SCM_GFS_v16,SCM_GFS_v17_p8,SCM_HRRR,SCM_RRFS_v1beta,SCM_RAP,SCM_WoFS_v0,SCM_GFS_v15p2_ps,SCM_GFS_v16_ps,SCM_GFS_v17_p8_ps,SCM_HRRR_ps,SCM_RRFS_v1beta_ps,SCM_RAP_ps,SCM_WoFS_v0_ps + suites: SCM_GFS_v15p2,SCM_GFS_v16,SCM_GFS_v16_RRTMGP,SCM_GFS_v17_p8,SCM_HRRR,SCM_RRFS_v1beta,SCM_RAP,SCM_WoFS_v0,SCM_GFS_v15p2_ps,SCM_GFS_v16_ps,SCM_GFS_v16_RRTMGP_ps,SCM_GFS_v17_p8_ps,SCM_HRRR_ps,SCM_RRFS_v1beta_ps,SCM_RAP_ps,SCM_WoFS_v0_ps,SCM_HRRR_gf,SCM_HRRR_gf_ps # Workflow steps steps: diff --git a/.github/workflows/ci_run_scm_rts.yml b/.github/workflows/ci_run_scm_rts.yml index 31c991549..b8247142a 100644 --- a/.github/workflows/ci_run_scm_rts.yml +++ b/.github/workflows/ci_run_scm_rts.yml @@ -22,8 +22,8 @@ jobs: sp_ROOT: /home/runner/NCEPLIBS-sp w3emc_ROOT: /home/runner/myw3emc SCM_ROOT: /home/runner/work/ccpp-scm/ccpp-scm - suites: SCM_GFS_v15p2,SCM_GFS_v16,SCM_GFS_v17_p8,SCM_HRRR,SCM_RRFS_v1beta,SCM_RAP,SCM_WoFS_v0,SCM_RRFS_v1,SCM_GFS_v17_p8_ugwpv1 - suites_ps: SCM_GFS_v15p2_ps,SCM_GFS_v16_ps,SCM_GFS_v17_p8_ps,SCM_HRRR_ps,SCM_RRFS_v1beta_ps,SCM_RAP_ps,SCM_WoFS_v0_ps,SCM_RRFS_v1_ps,SCM_GFS_v17_p8_ugwpv1_ps + suites: SCM_GFS_v15p2,SCM_GFS_v16,SCM_GFS_v17_p8,SCM_HRRR,SCM_RRFS_v1beta,SCM_RAP,SCM_WoFS_v0,SCM_HRRR_gf,SCM_GFS_v17_p8_ugwpv1,SCM_GFS_v16_RRTMGP + suites_ps: SCM_GFS_v15p2_ps,SCM_GFS_v16_ps,SCM_GFS_v17_p8_ps,SCM_HRRR_ps,SCM_RRFS_v1beta_ps,SCM_RAP_ps,SCM_WoFS_v0_ps,SCM_HRRR_gf_ps,SCM_GFS_v17_p8_ugwpv1_ps,SCM_GFS_v16_RRTMGP_ps dir_rt: /home/runner/work/ccpp-scm/ccpp-scm/test/artifact-${{matrix.build-type}} dir_bl: /home/runner/work/ccpp-scm/ccpp-scm/test/BL-${{matrix.build-type}} diff --git a/ccpp/physics_namelists/input_RRFS_v1.nml b/ccpp/physics_namelists/input_HRRR_gf.nml similarity index 100% rename from ccpp/physics_namelists/input_RRFS_v1.nml rename to ccpp/physics_namelists/input_HRRR_gf.nml diff --git a/ccpp/suites/suite_SCM_RRFS_v1.xml b/ccpp/suites/suite_SCM_HRRR_gf.xml similarity index 98% rename from ccpp/suites/suite_SCM_RRFS_v1.xml rename to ccpp/suites/suite_SCM_HRRR_gf.xml index ef1c73157..f80ab4c7c 100644 --- a/ccpp/suites/suite_SCM_RRFS_v1.xml +++ b/ccpp/suites/suite_SCM_HRRR_gf.xml @@ -1,6 +1,6 @@ - + GFS_time_vary_pre @@ -76,4 +76,4 @@ GFS_physics_post - \ No newline at end of file + diff --git a/ccpp/suites/suite_SCM_RRFS_v1_ps.xml b/ccpp/suites/suite_SCM_HRRR_gf_ps.xml similarity index 97% rename from ccpp/suites/suite_SCM_RRFS_v1_ps.xml rename to ccpp/suites/suite_SCM_HRRR_gf_ps.xml index 91918a6b8..3fc25cc5b 100644 --- a/ccpp/suites/suite_SCM_RRFS_v1_ps.xml +++ b/ccpp/suites/suite_SCM_HRRR_gf_ps.xml @@ -1,6 +1,6 @@ - + GFS_time_vary_pre @@ -60,4 +60,4 @@ GFS_physics_post - \ No newline at end of file + diff --git a/scm/etc/tracer_config/tracers_RRFS_v1.txt b/scm/etc/tracer_config/tracers_HRRR_gf.txt similarity index 100% rename from scm/etc/tracer_config/tracers_RRFS_v1.txt rename to scm/etc/tracer_config/tracers_HRRR_gf.txt diff --git a/scm/src/suite_info.py b/scm/src/suite_info.py index 290b8cbf3..bc7905601 100755 --- a/scm/src/suite_info.py +++ b/scm/src/suite_info.py @@ -45,7 +45,7 @@ def timestep(self, value): suite_list.append(suite('SCM_GFS_v16', 'tracers_GFS_v16.txt', 'input_GFS_v16.nml', 600.0, 1800.0, True )) suite_list.append(suite('SCM_GFS_v17_p8_ugwpv1', 'tracers_GFS_v17_p8.txt', 'input_GFS_v17_p8_ugwpv1.nml', 600.0, 600.0, True )) suite_list.append(suite('SCM_RAP', 'tracers_RAP.txt', 'input_RAP.nml', 600.0, 600.0 , True )) -suite_list.append(suite('SCM_RRFS_v1', 'tracers_RRFS_v1.txt', 'input_RRFS_v1.nml', 600.0, 600.0 , True )) +suite_list.append(suite('SCM_HRRR_gf', 'tracers_HRRR_gf.txt', 'input_HRRR_gf.nml', 600.0, 600.0 , True )) suite_list.append(suite('SCM_WoFS_v0', 'tracers_WoFS_v0.txt', 'input_WoFS_v0.nml', 600.0, 600.0 , True )) suite_list.append(suite('SCM_GFS_v16_RRTMGP', 'tracers_GFS_v16.txt', 'input_GFS_v16_RRTMGP.nml', 600.0, 1800.0, True )) diff --git a/scm/src/supported_suites.py b/scm/src/supported_suites.py index 5c067af46..bfe10f64e 100644 --- a/scm/src/supported_suites.py +++ b/scm/src/supported_suites.py @@ -1 +1 @@ -suites = ["SCM_GFS_v16","SCM_GFS_v16_RRTMGP","SCM_GFS_v17_p8_ugwpv1","SCM_RAP","SCM_RRFS_v1beta","SCM_WoFS_v0"] +suites = ["SCM_GFS_v16","SCM_GFS_v16_RRTMGP","SCM_GFS_v17_p8_ugwpv1","SCM_HRRR_gf"😚,"SCM_WoFS_v0"] diff --git a/test/rt_test_cases.py b/test/rt_test_cases.py index 0a2bd76d0..11f1adaf3 100644 --- a/test/rt_test_cases.py +++ b/test/rt_test_cases.py @@ -6,27 +6,27 @@ {"case": "arm_sgp_summer_1997_A", "suite": "SCM_GFS_v17_HR3_RRTMGP"}, \ {"case": "arm_sgp_summer_1997_A", "suite": "SCM_GFS_v16"}, \ {"case": "arm_sgp_summer_1997_A", "suite": "SCM_WoFS_v0"}, \ - {"case": "arm_sgp_summer_1997_A", "suite": "SCM_RRFS_v1"}, \ + {"case": "arm_sgp_summer_1997_A", "suite": "SCM_HRRR_gf"}, \ {"case": "twpice", "suite": "SCM_GFS_v17_HR3"}, \ {"case": "twpice", "suite": "SCM_GFS_v17_HR3_RRTMGP"}, \ {"case": "twpice", "suite": "SCM_GFS_v16"}, \ {"case": "twpice", "suite": "SCM_WoFS_v0"}, \ - {"case": "twpice", "suite": "SCM_RRFS_v1"}, \ + {"case": "twpice", "suite": "SCM_HRRR_gf"}, \ {"case": "bomex", "suite": "SCM_GFS_v17_HR3"}, \ {"case": "bomex", "suite": "SCM_GFS_v17_HR3_RRTMGP"}, \ {"case": "bomex", "suite": "SCM_GFS_v16"}, \ {"case": "bomex", "suite": "SCM_WoFS_v0"}, \ - {"case": "bomex", "suite": "SCM_RRFS_v1"}, \ + {"case": "bomex", "suite": "SCM_HRRR_gf"}, \ {"case": "astex", "suite": "SCM_GFS_v17_HR3"}, \ {"case": "astex", "suite": "SCM_GFS_v17_HR3_RRTMGP"}, \ {"case": "astex", "suite": "SCM_GFS_v16"}, \ {"case": "astex", "suite": "SCM_WoFS_v0"}, \ - {"case": "astex", "suite": "SCM_RRFS_v1"}, \ + {"case": "astex", "suite": "SCM_HRRR_gf"}, \ {"case": "LASSO_2016051812", "suite": "SCM_GFS_v17_HR3"}, \ {"case": "LASSO_2016051812", "suite": "SCM_GFS_v17_HR3_RRTMGP"}, \ {"case": "LASSO_2016051812", "suite": "SCM_GFS_v16"}, \ {"case": "LASSO_2016051812", "suite": "SCM_WoFS_v0"}, \ - {"case": "LASSO_2016051812", "suite": "SCM_RRFS_v1"}, \ + {"case": "LASSO_2016051812", "suite": "SCM_HRRR_gf"}, \ #---------------------------------------------------------------------------------------------------------------------------------------------- # Unsupported suites (w/ supported cases) #---------------------------------------------------------------------------------------------------------------------------------------------- From 8b9bfcf31cfdf2a7fd5a8709f30bb63027f3240f Mon Sep 17 00:00:00 2001 From: Grant Firl Date: Wed, 17 Jul 2024 17:31:01 -0400 Subject: [PATCH 20/25] fix seg-fault causing sigmab output statements --- scm/src/scm_output.F90 | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/scm/src/scm_output.F90 b/scm/src/scm_output.F90 index 3458da3c9..b41347c19 100644 --- a/scm/src/scm_output.F90 +++ b/scm/src/scm_output.F90 @@ -101,7 +101,7 @@ subroutine output_init(scm_state, physics) call NetCDF_def_var(ncid, 'time_rad', NF90_FLOAT, "model elapsed time for either LW or SW radiation variables", "s", time_rad_var_id, (/ time_rad_id /)) !> - Define the state variables - CALL output_init_state(ncid, time_inst_id, hor_dim_id, vert_dim_id, vert_dim_i_id) + CALL output_init_state(ncid, time_inst_id, hor_dim_id, vert_dim_id, vert_dim_i_id, scm_state) !> - Define the forcing variables CALL output_init_forcing(ncid, time_inst_id, hor_dim_id, vert_dim_id) @@ -165,10 +165,12 @@ subroutine output_init(scm_state, physics) !> @} end subroutine output_init -subroutine output_init_state(ncid, time_inst_id, hor_dim_id, vert_dim_id, vert_dim_i_id) +subroutine output_init_state(ncid, time_inst_id, hor_dim_id, vert_dim_id, vert_dim_i_id, scm_state) + use scm_type_defs, only: scm_state_type use NetCDF_def, only : NetCDF_def_var integer, intent(in) :: ncid, time_inst_id, hor_dim_id, vert_dim_id, vert_dim_i_id + type(scm_state_type), intent(in) :: scm_state integer :: dummy_id @@ -187,7 +189,9 @@ subroutine output_init_state(ncid, time_inst_id, hor_dim_id, vert_dim_id, vert_d call NetCDF_def_var(ncid, 'ql', NF90_FLOAT, "suspended resolved liquid cloud water on model layer centers", "kg kg-1", dummy_id, (/ hor_dim_id, vert_dim_id, time_inst_id /)) call NetCDF_def_var(ncid, 'qi', NF90_FLOAT, "suspended resolved ice cloud water on model layer centers", "kg kg-1", dummy_id, (/ hor_dim_id, vert_dim_id, time_inst_id /)) call NetCDF_def_var(ncid, 'qc', NF90_FLOAT, "suspended (resolved + SGS) total cloud water on model layer centers", "kg kg-1", dummy_id, (/ hor_dim_id, vert_dim_id, time_inst_id /)) - call NetCDF_def_var(ncid, 'sigmab', NF90_FLOAT, "updraft area fraction on model layer centers", "frac", dummy_id, (/ hor_dim_id, time_inst_id /)) + if (scm_state%sigmab_index > 0) then + call NetCDF_def_var(ncid, 'sigmab', NF90_FLOAT, "updraft area fraction at lowest model layer", "frac", dummy_id, (/ hor_dim_id, time_inst_id /)) + end if end subroutine output_init_state @@ -498,7 +502,9 @@ subroutine output_append_state(ncid, scm_state, physics) call NetCDF_put_var(ncid, "v", scm_state%state_v(:,:,1), scm_state%itt_out) call NetCDF_put_var(ncid, "ql", scm_state%state_tracer(:,:,scm_state%cloud_water_index,1), scm_state%itt_out) call NetCDF_put_var(ncid, "qi", scm_state%state_tracer(:,:,scm_state%cloud_ice_index,1), scm_state%itt_out) - call NetCDF_put_var(ncid, "sigmab", scm_state%state_tracer(:,1,scm_state%sigmab_index,1), scm_state%itt_out) + if (scm_state%sigmab_index > 0) then + call NetCDF_put_var(ncid, "sigmab", scm_state%state_tracer(:,1,scm_state%sigmab_index,1), scm_state%itt_out) + endif if (physics%model%do_mynnedmf) then call NetCDF_put_var(ncid, "qc", scm_state%state_tracer(:,:,scm_state%cloud_water_index,1) + & scm_state%state_tracer(:,:,scm_state%cloud_ice_index,1) + & From 47d917249948e27f09aa45d9ebc739defa6f806e Mon Sep 17 00:00:00 2001 From: Dustin Swales Date: Wed, 24 Jul 2024 14:54:37 +0000 Subject: [PATCH 21/25] Revert change to scm_input.F90 --- scm/src/scm_input.F90 | 1 - 1 file changed, 1 deletion(-) diff --git a/scm/src/scm_input.F90 b/scm/src/scm_input.F90 index 12d055f3c..cc3effcd5 100644 --- a/scm/src/scm_input.F90 +++ b/scm/src/scm_input.F90 @@ -1969,7 +1969,6 @@ subroutine get_case_init_DEPHY(scm_state, scm_input) if (trim(input_surfaceForcingLSM) == "lsm") then scm_input%input_ozone = input_ozone(:,active_init_time) scm_input%input_area = input_area(active_init_time) - scm_state%area = input_area(active_init_time) scm_input%input_stddev = input_stddev(active_init_time) scm_input%input_convexity= input_convexity(active_init_time) From bf48c9495555698c44131109dbbeb8a7f02a36da Mon Sep 17 00:00:00 2001 From: Dustin Swales Date: Wed, 24 Jul 2024 18:22:40 +0000 Subject: [PATCH 22/25] Update working SP RT cases --- test/rt_test_cases_sp.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/rt_test_cases_sp.py b/test/rt_test_cases_sp.py index a9a888642..a52ed1562 100644 --- a/test/rt_test_cases_sp.py +++ b/test/rt_test_cases_sp.py @@ -2,9 +2,9 @@ #---------------------------------------------------------------------------------------------------------------------------------------------- # CCPP-SCM single precision supported suites #---------------------------------------------------------------------------------------------------------------------------------------------- - {"case": "arm_sgp_summer_1997_A", "suite": "SCM_RAP"}, \ - {"case": "twpice", "suite": "SCM_RAP"}, \ - {"case": "bomex", "suite": "SCM_RAP"}, \ - {"case": "astex", "suite": "SCM_RAP"}, \ - {"case": "LASSO_2016051812", "suite": "SCM_RAP"}, \ +# {"case": "arm_sgp_summer_1997_A", "suite": "SCM_HRRR_gf"}, \ + {"case": "twpice", "suite": "SCM_HRRR_gf"}, \ + {"case": "bomex", "suite": "SCM_HRRR_gf"}, \ + {"case": "astex", "suite": "SCM_HRRR_gf"}, \ + {"case": "LASSO_2016051812", "suite": "SCM_HRRR_gf"}, \ ] From c84b3a740d3516717070331aabd640f484c73f03 Mon Sep 17 00:00:00 2001 From: Grant Firl Date: Wed, 24 Jul 2024 16:55:29 -0400 Subject: [PATCH 23/25] update ccpp/physics pointer --- .gitmodules | 6 ++---- ccpp/physics | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/.gitmodules b/.gitmodules index 265e5673c..dc0798c32 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,10 +4,8 @@ branch = main [submodule "ccpp-physics"] path = ccpp/physics - #url = https://github.com/NCAR/ccpp-physics - #branch = main - url = https://github.com/grantfirl/ccpp-physics - branch = ufs-dev-PR207 + url = https://github.com/NCAR/ccpp-physics + branch = main [submodule "CMakeModules"] path = CMakeModules url = https://github.com/noaa-emc/CMakeModules diff --git a/ccpp/physics b/ccpp/physics index 38f3f49db..160aa0359 160000 --- a/ccpp/physics +++ b/ccpp/physics @@ -1 +1 @@ -Subproject commit 38f3f49db734a345126446fc929db97358467646 +Subproject commit 160aa0359cf28b7f2f05ec23f3ac2fed59afad8b From 64221ffe942920819021e672da0678f8ca71787d Mon Sep 17 00:00:00 2001 From: Soren Rasmussen Date: Thu, 6 Jun 2024 12:49:16 -0600 Subject: [PATCH 24/25] Updating scripts and documentation to reflect NCAR's move from Cheyenne to Derecho clusters --- scm/doc/TechGuide/chap_cases.rst | 14 +- scm/etc/scm_qsub_example.py | 15 +- scm/etc/scripts/GABLS3_LSM.ncl | 202 +++++++++---------- scm/etc/scripts/GABLS3_LSM_NoahMP.ncl | 202 +++++++++---------- scm/etc/scripts/GABLS3_LSM_RUC.ncl | 266 +++++++++++++------------- test/README.md | 9 +- test/rt.sh | 12 +- 7 files changed, 362 insertions(+), 358 deletions(-) diff --git a/scm/doc/TechGuide/chap_cases.rst b/scm/doc/TechGuide/chap_cases.rst index b6bd183dd..ff97454d7 100644 --- a/scm/doc/TechGuide/chap_cases.rst +++ b/scm/doc/TechGuide/chap_cases.rst @@ -146,7 +146,7 @@ are included in ``ccpp-scm/scm/data/processed_case_input/fv3_model_point_noah[mp .. literalinclude:: arm_case_header.txt :name: lst_case_input_netcdf_header_arm :caption: example NetCDF file (CCPP-SCM format) header for case initialization and forcing data - + Case input data file (DEPHY format) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -505,10 +505,10 @@ Optional arguments: Examples to run from within the ``scm/etc/scripts`` directory to create SCM cases starting with the output from a UFS Weather Model regression test(s): -On the supported platforms Cheyenne (NCAR) and Hera (NOAA), there are +On the supported platforms Derecho (NCAR) and Hera (NOAA), there are staged UWM RTs located at: -- Cheyenne ``/glade/scratch/epicufsrt/GMTB/CCPP-SCM/UFS_RTs`` +- Derecho ``/glade/derecho/scratch/epicufsrt/FV3_RT/`` - Hera ``/scratch1/BMC/gmtb/CCPP-SCM/UFS_RTs`` .. _`example1`: @@ -520,7 +520,7 @@ UFS regression test, ``control_c192``, for single point. .. code:: bash - ./UFS_forcing_ensemble_generator.py -d /glade/scratch/epicufsrt/GMTB/CCPP-SCM/UFS_RTs/control_c192/ -sc --C_RES 192 -dt 360 -n control_c192 -lons 300 -lats 34 + ./UFS_forcing_ensemble_generator.py -d [path_to_regression_tests_output]/control_c192_intel/ -sc --C_RES 192 -dt 360 -n control_c192 -lons 300 -lats 34 Upon successful completion of the script, the command to run the case(s) will print to the screen. For example, @@ -540,7 +540,7 @@ UFS regression test, ``control_c384``, for multiple points. .. code:: bash - ./UFS_forcing_ensemble_generator.py -d /glade/scratch/epicufsrt/GMTB/CCPP-SCM/UFS_RTs/control_c384/ -sc --C_RES 384 -dt 225 -n control_c384 -lons 300 300 300 300 -lats 34 35 35 37 + ./UFS_forcing_ensemble_generator.py -d /glade/derecho/scratch/epicufsrt/ufs-weather-model/RT/NEMSfv3gfs/develop-20240607/control_c384_intel/ -sc --C_RES 384 -dt 225 -n control_c384 -lons 300 300 300 300 -lats 34 35 35 37 Upon successful completion of the script, the command to run the case(s) will print to the screen. For example, @@ -578,14 +578,14 @@ for more details. For the purposes of this example the ``control_p8`` test has already been rerun, but if starting from your own UWM RTs, you can rerun the UWM regression test, -on Cheyenne for example, by running the following command in the RT +on Derecho for example, by running the following command in the RT directory: ``qsub job_card`` Now the cases can be generated with the following command: .. code:: bash - ./UFS_forcing_ensemble_generator.py -d /glade/scratch/epicufsrt/GMTB/CCPP-SCM/UFS_RTs/control_p8/ -sc --C_RES 96 -dt 720 -n control_p8 -lonl 300 320 -latl 40 50 -nens 10 -sdf SCM_GFS_v17_p8 + ./UFS_forcing_ensemble_generator.py -d /glade/derecho/scratch/epicufsrt/ufs-weather-model/RT/NEMSfv3gfs/develop-20240607/control_p8_intel -sc --C_RES 96 -dt 720 -n control_p8 -lonl 300 320 -latl 40 50 -nens 10 -sdf SCM_GFS_v17_p8 Upon successful completion of the script, the command to run the case(s) will print to the screen. For example, diff --git a/scm/etc/scm_qsub_example.py b/scm/etc/scm_qsub_example.py index 457013dff..e34d80ab4 100755 --- a/scm/etc/scm_qsub_example.py +++ b/scm/etc/scm_qsub_example.py @@ -3,10 +3,15 @@ ----------------------------------------------------------------------- Description: Example script to submit a job through the HPC batch system - Assumptions: For use on Cheyenne. This script must be copied to the bin directory. + Assumptions: For use on Derecho. This script must be copied to the bin directory. The user should edit the JOB_NAME, ACCOUNT, etc. - ./scm/etc/Cheyenne_setup_intel.sh or - ./scm/etc/Cheyenne_setup_gnu.sh must be run before submitting this script + Before running this script the environment must be setup. + The following are instructions for that: + $ module purge + $ module use scm/etc/modules + $ module load derecho_gnu + or + $ module load derecho_intel Command line arguments: none @@ -25,10 +30,10 @@ ### Begin User-editable section ### JOB_NAME = "test_job" -ACCOUNT = "p48503002" +ACCOUNT = "ENTER_ACCOUNT_NUMBER" WALLTIME = "walltime=00:20:00" PROCESSORS = "select=1:ncpus=1" -QUEUE = "share" +QUEUE = "develop" COMMAND = "./run_scm.py -c twpice" EMAIL_ADDR = MY_EMAIL SERIAL_MEM = "512M" diff --git a/scm/etc/scripts/GABLS3_LSM.ncl b/scm/etc/scripts/GABLS3_LSM.ncl index 85f4dc2a9..4330c1563 100644 --- a/scm/etc/scripts/GABLS3_LSM.ncl +++ b/scm/etc/scripts/GABLS3_LSM.ncl @@ -5,7 +5,7 @@ load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/contributed.ncl" begin ;Define constants - + missing_value = -9999.0 g = 9.80665 ;gravity (m s-2) R_dry = 287. ;ideal gas dry air constant (J kg-1 K-1) @@ -24,7 +24,7 @@ begin ; Time, 01Jul2006 12:00:00 UTC - 02Jul2006 12:00:00 UTC ; Must be in seconds time = fspan(0,86400,145) - time@long_name = "elapsed time since the beginning of the simulation" + time@long_name = "elapsed time since the beginning of the simulation" time@units = "s" ; timb = fspan(0,86400,145) @@ -52,7 +52,7 @@ begin ; Total water specific humidity (q) at heights listed above qt = (/ 9.3e-3, 9.3e-3, 8.5e-3, 8.4e-3, 8.3e-3, 8.2e-3, 8.1e-3, \ - 8.0e-3, 7.5e-3, 2.0e-3, 0.3e-3, 0.01e-3, 0.003e-3, 0. /) + 8.0e-3, 7.5e-3, 2.0e-3, 0.3e-3, 0.01e-3, 0.003e-3, 0. /) qt@long_name = "initial profile of total water specific humidity" qt@units = "kg kg^-1" @@ -96,7 +96,7 @@ begin end do ; Solve the hypsometric equation for p2 to attain each new pressure level -; and fill the array (the variable to fill is levels, created above.) +; and fill the array (the variable to fill is levels, created above.) ; The value for levels(0) = p_surf(0) levels(0) = p_surf(0) do i=1,dimsizes(levels)-1,1 @@ -113,7 +113,7 @@ begin ; Calculate thetail. Because ql and qi are not given, this is not possible, ; so the initial profile of thetail will be assumed theta. -; The remainder of the equation used in the gmtb-scm user's guide would be +; The remainder of the equation used in the gmtb-scm user's guide would be ; zero, leaving you with only theta. thetail = theta thetail@long_name = "initial profile of ice-liquid water potential "+ \ @@ -135,10 +135,10 @@ begin v@long_name = "initial profile of N-S horizontal wind" v@units = "m s^-1" -; Use GLDAS to derive the sensible and latent heat flux for the Cabauw -; location, then you can compare the GLDAS H/Le to the given intial Bowen +; Use GLDAS to derive the sensible and latent heat flux for the Cabauw +; location, then you can compare the GLDAS H/Le to the given intial Bowen ; ratio. Begin by reading in the data from each file. -; gl_dir = "/glade/scratch/damico/GLDAS_GABLS3/" +; gl_dir = "/path/to/GLDAS_GABLS3/" ; gl_00 = addfile(gl_dir+"GLDAS_NOAH025_3H.A20060701.0000.021.nc4.SUB.nc4", \ ; "r") @@ -249,7 +249,7 @@ begin w_ls@units = "m s^-1" ; Geostrophic winds are given at certain times but only at the surface. -; Instructions from GABLS suggest interpolation to surface winds up to +; Instructions from GABLS suggest interpolation to surface winds up to ; 2000 m, and then constant from that point. This should be done for each ; time step. Starting with time. u_geo_spec = (/ -7.8, -7.8, -6.5, -5.0, -5.0, -6.5 /) @@ -260,7 +260,7 @@ begin v_geo_t = (/ 0, 21600, 39600, 54000, 64800, 86400 /) v_geo = linint1(v_geo_t,v_geo_spec,False,time,0) -; Interpolate with height, linearly, from the surface values above to -2.0 +; Interpolate with height, linearly, from the surface values above to -2.0 ; m s^-1 for u and 2.0 m s^-1 for v. Above 2000 m, geostrophic wind is ; constant with height (according to GABLS guide). u_g = new((/ dimsizes(levels),dimsizes(time) /),float) @@ -287,10 +287,10 @@ begin u_g@units = "m s^-1" v_g@unit = "m s^-1" -; Horizontal temperature tendency due to advection, which can be converted to -; thetail tendency. The values are give; between 200-1000m, decreasing -; to zero down towards the surface and decreasing to zero from 1000m to -; 1500m, with zero entirely above. Once again, there needs to be +; Horizontal temperature tendency due to advection, which can be converted to +; thetail tendency. The values are give; between 200-1000m, decreasing +; to zero down towards the surface and decreasing to zero from 1000m to +; 1500m, with zero entirely above. Once again, there needs to be ; interpolation in time and with height. T_advec_spec = (/ -2.5e-5,7.5e-5, 0., 0. /) T_advec_time = (/ 0, 46800,64800,86400 /) @@ -316,10 +316,10 @@ begin "horizontal advection" h_advec_thetail@units = "K s^-1" -; The last remaining variable given in the data that the gmtb-scm can -; use is horizontal specific humidity tendency. The values are given +; The last remaining variable given in the data that the gmtb-scm can +; use is horizontal specific humidity tendency. The values are given ; between 200-1000m, decreasing to zero down towards the surface and -; decreasing to zero from 1000m to 1500, with zero entirely above. Once +; decreasing to zero from 1000m to 1500, with zero entirely above. Once ; again, there needs to be interpolation in time and with height. h_advec_spec = (/ 0., 8.e-8, 0., -8.e-8, 0., 0. /) h_advec_time = (/ 0, 32400, 43200, 50400, 61200, 86400 /) @@ -407,7 +407,7 @@ begin v_advec_thetail = 0. v_advec_thetail@long_name = "prescribed theta_il tendency due to " + \ "vertical advection" - v_advec_thetail@units = "K s^-1" + v_advec_thetail@units = "K s^-1" v_advec_qt = new((/ dimsizes(levels),dimsizes(time) /),float) v_advec_qt = 0. @@ -418,141 +418,141 @@ begin ; Noah LSM initialization slmsk = 1.0 ;corresponds to land from the UFS ICs slmsk@long_name = "land-sea-ice mask" - - tsfco = 305.0 + + tsfco = 305.0 tsfco@long_name = "sea surface temperature OR surface skin temperature over land OR sea ice surface skin temperature (depends on value of slmsk)" tsfco@units = "K" - + weasd = 0.0 weasd@long_name = "water equivalent accumulated snow depth" weasd@units = "mm" - + tg3 = 283.15 ;corresponds to case specs tg3@units = "K" tg3@long_name = "deep soil temperature" - + zorl = 15.0 ;(cm) from case specs zorl@long_name = "composite surface roughness length" zorl@units = "cm" - + zorlw = zorl ;(cm) from case specs zorlw@long_name = "surface roughness length over ocean" zorlw@units = "cm" - + alvsf = 0.23 ;corresponds to case specs alvsf@long_name = "60 degree vis albedo with strong cosz dependency" - + alnsf = 0.23 ;corresponds to case specs alnsf@long_name = "60 degree nir albedo with strong cosz dependency" - + alvwf = 0.23 ;corresponds to case specs alvwf@long_name = "60 degree vis albedo with weak cosz dependency" - + alnwf = 0.23 ;corresponds to case specs alnwf@long_name = "60 degree nir albedo with weak cosz dependency" - + facsf = 0.50556319952 ;corresponds to value from UFS ICs (static from fix files for C768) facsf@long_name = "fractional coverage with strong cosz dependency" - + facwf = 0.49443680048 ;corresponds to value from UFS ICs (static from fix files for C768) facwf@long_name = "fractional coverage with weak cosz dependency" - - vegfrac = 0.75 ; the value of 100% specified in the case + + vegfrac = 0.75 ; the value of 100% specified in the case ; specifications clashes with the maximum value ; for this gridpoint from UFS ICs vegfrac@long_name = "vegetation fraction" - + canopy = 0.5 ;corresponds to typical value for grassland in the growing season canopy@units = "kg m-2" canopy@long_name = "amount of water stored in canopy" - + f10m = missing_value ;this is not required f10m@long_name = "ratio of sigma level 1 wind and 10m wind" - + t2m = missing_value; this is not required t2m@long_name = "2-meter absolute temperature" t2m@units = "K" - + q2m = missing_value; this is not required q2m@long_name = "2-meter specific humidity" q2m@units = "kg kg-1" - - vegtyp = 10 ;corresponds to the "grasslands" type for the IGBP (vegsrc=1) + + vegtyp = 10 ;corresponds to the "grasslands" type for the IGBP (vegsrc=1) ;dataset vegtyp@long_name = "vegetation type (1-12)" - + soiltyp = 12 ;corresponds to "clay" soil type soiltyp@long_name = "soil type (1-12)" - + ;derive friction velocity from known values wind1 = sqrt(u_specified(1)^2 + v_specified(1)^2) uustar = von_K*wind1/log(u_h(1)/(0.01*zorl)) uustar@units = "m s-1" uustar@long_name = "friction velocity" - + ffmm = missing_value ;this is not required ffmm@long_name = "Monin-Obukhov similarity function for momentum" - + ffhh = missing_value ;this is not required ffhh@long_name = "Monin-Obukhov similarity function for heat" - + hice = 0.0 ;corresponds to value from UFS ICs hice@units = "m" hice@long_name = "sea ice thickness" - + fice = 0.0 ;corresponds to value from UFS ICs fice@long_name = "ice fraction" - + tisfc = tsfco ; there is no ice, but this corresponds to the surface skin temperature tisfc@units = "K" tisfc@long_name = "ice surface temperature" - + tprcp = missing_value; not required tprcp@units = "m" tprcp@long_name = "instantaneous total precipitation amount" - + srflag = missing_value; not required srflag@long_name = "snow/rain flag for precipitation" - + snwdph = 0.0 ;corresponds to case specs snwdph@units = "mm" snwdph@long_name = "water equivalent snow depth" - + shdmin = 0.01 ; corresponds to minimum vegetation fraction from surface fixed data (is not actually used in Noah LSM) shdmin@long_name = "minimum vegetation fraction" - + shdmax = 0.8 ; the maximum value from the surface fixed data is closer to 0.75 (is not actually used in Noah LSM) shdmax@long_name = "maximum vegetation fraction" - + slopetyp = 1 slopetyp@long_name = "slope type (1-9)" - + snoalb = 0.728796124458 ;corresponds to value from UFS ICs (static from fix files for C768) snoalb@long_name = "maximum snow albedo" - + sncovr = 0.0 ;corresponds to case specs sncovr@long_name = "snow area fraction" - + tsfcl = tsfco tsfcl@long_name = "surface skin temperature over land" tsfcl@units = "K" - + zorll = zorl ;(cm) from case specs zorll@long_name = "surface roughness length over land" zorll@units = "cm" - + zorli = zorl ;(cm) from case specs zorli@long_name = "surface roughness length over ice" zorli@units = "cm" - + stc = (/ 292.55, 289.9, 285.35, 283.15 /) stc@units = "K" stc@long_name = "initial profile of soil temperature" - + smc = (/ 0.203, 0.203, 0.203, 0.203 /) smc@units = "m3 m-3" smc@long_name = "initial profile of soil moisture" - + slc = smc ;all liquid (no ice) slc@units = "m3 m-3" slc@long_name = "initial profile of soil liquid moisture" @@ -594,7 +594,7 @@ begin filevardef(fo,"levels",typeof(levels),"levels") filevarattdef(fo,"levels",levels) fo->levels = (/ levels /) - + filevardef(fo,"soil_depth",typeof(soil_depth),"nsoil") filevarattdef(fo,"soil_depth",soil_depth) fo->soil_depth = (/ soil_depth /) @@ -615,7 +615,7 @@ begin filedimdef(g2,dimNames,dimSizes,dimUnlim) filedimdef(g3,dimNames,dimSizes,dimUnlim) - + filevardef(g1,"lat",typeof(lat),"ncl_scalar") filevarattdef(g1,"lat",lat) g1->lat = lat @@ -623,151 +623,151 @@ begin filevardef(g1,"lon",typeof(lon),"ncl_scalar") filevarattdef(g1,"lon",lon) g1->lon = lon - + filevardef(g1,"slmsk",typeof(slmsk),"ncl_scalar") filevarattdef(g1,"slmsk",slmsk) g1->slmsk = slmsk - + filevardef(g1,"tsfco",typeof(tsfco),"ncl_scalar") filevarattdef(g1,"tsfco",tsfco) g1->tsfco = tsfco - + filevardef(g1,"weasd",typeof(weasd),"ncl_scalar") filevarattdef(g1,"weasd",weasd) g1->weasd = weasd - + filevardef(g1,"tg3",typeof(tg3),"ncl_scalar") filevarattdef(g1,"tg3",tg3) g1->tg3 = tg3 - + filevardef(g1,"zorl",typeof(zorl),"ncl_scalar") filevarattdef(g1,"zorl",zorl) g1->zorl = zorl - + filevardef(g1,"zorlw",typeof(zorlw),"ncl_scalar") filevarattdef(g1,"zorlw",zorlw) g1->zorlw = zorlw - + filevardef(g1,"alvsf",typeof(alvsf),"ncl_scalar") filevarattdef(g1,"alvsf",alvsf) g1->alvsf = alvsf - + filevardef(g1,"alnsf",typeof(alnsf),"ncl_scalar") filevarattdef(g1,"alnsf",alnsf) g1->alnsf = alnsf - + filevardef(g1,"alvwf",typeof(alvwf),"ncl_scalar") filevarattdef(g1,"alvwf",alvwf) g1->alvwf = alvwf - + filevardef(g1,"alnwf",typeof(alnwf),"ncl_scalar") filevarattdef(g1,"alnwf",alnwf) g1->alnwf = alnwf - + filevardef(g1,"facsf",typeof(facsf),"ncl_scalar") filevarattdef(g1,"facsf",facsf) g1->facsf = facsf - + filevardef(g1,"facwf",typeof(facwf),"ncl_scalar") filevarattdef(g1,"facwf",facwf) g1->facwf = facwf - + filevardef(g1,"vegfrac",typeof(vegfrac),"ncl_scalar") filevarattdef(g1,"vegfrac",vegfrac) g1->vegfrac = vegfrac - + filevardef(g1,"canopy",typeof(canopy),"ncl_scalar") filevarattdef(g1,"canopy",canopy) g1->canopy = canopy - + filevardef(g1,"f10m",typeof(f10m),"ncl_scalar") filevarattdef(g1,"f10m",f10m) g1->f10m = f10m - + filevardef(g1,"t2m",typeof(t2m),"ncl_scalar") filevarattdef(g1,"t2m",t2m) g1->t2m = t2m - + filevardef(g1,"q2m",typeof(q2m),"ncl_scalar") filevarattdef(g1,"q2m",q2m) g1->q2m = q2m - + filevardef(g1,"vegtyp",typeof(vegtyp),"ncl_scalar") filevarattdef(g1,"vegtyp",vegtyp) g1->vegtyp = vegtyp - + filevardef(g1,"soiltyp",typeof(soiltyp),"ncl_scalar") filevarattdef(g1,"soiltyp",soiltyp) g1->soiltyp = soiltyp - + filevardef(g1,"uustar",typeof(uustar),"ncl_scalar") filevarattdef(g1,"uustar",uustar) g1->uustar = uustar - + filevardef(g1,"ffmm",typeof(ffmm),"ncl_scalar") filevarattdef(g1,"ffmm",ffmm) g1->ffmm = ffmm - + filevardef(g1,"ffhh",typeof(ffhh),"ncl_scalar") filevarattdef(g1,"ffhh",ffhh) g1->ffhh = ffhh - + filevardef(g1,"hice",typeof(hice),"ncl_scalar") filevarattdef(g1,"hice",hice) g1->hice = hice - + filevardef(g1,"fice",typeof(fice),"ncl_scalar") filevarattdef(g1,"fice",fice) g1->fice = fice - + filevardef(g1,"tisfc",typeof(tisfc),"ncl_scalar") filevarattdef(g1,"tisfc",tisfc) g1->tisfc = tisfc - + filevardef(g1,"tprcp",typeof(tprcp),"ncl_scalar") filevarattdef(g1,"tprcp",tprcp) g1->tprcp = tprcp - + filevardef(g1,"srflag",typeof(srflag),"ncl_scalar") filevarattdef(g1,"srflag",srflag) g1->srflag = srflag - + filevardef(g1,"snwdph",typeof(snwdph),"ncl_scalar") filevarattdef(g1,"snwdph",snwdph) g1->snwdph = snwdph - + filevardef(g1,"shdmin",typeof(shdmin),"ncl_scalar") filevarattdef(g1,"shdmin",shdmin) g1->shdmin = shdmin - + filevardef(g1,"shdmax",typeof(shdmax),"ncl_scalar") filevarattdef(g1,"shdmax",shdmax) g1->shdmax = shdmax - + filevardef(g1,"slopetyp",typeof(slopetyp),"ncl_scalar") filevarattdef(g1,"slopetyp",slopetyp) g1->slopetyp = slopetyp - + filevardef(g1,"snoalb",typeof(snoalb),"ncl_scalar") filevarattdef(g1,"snoalb",snoalb) g1->snoalb = snoalb - + filevardef(g1,"sncovr",typeof(sncovr),"ncl_scalar") filevarattdef(g1,"sncovr",sncovr) g1->sncovr = sncovr - + filevardef(g1,"tsfcl",typeof(tsfcl),"ncl_scalar") filevarattdef(g1,"tsfcl",tsfcl) g1->tsfcl = tsfcl - + filevardef(g1,"zorll",typeof(zorll),"ncl_scalar") filevarattdef(g1,"zorll",zorll) g1->zorll = zorll - + filevardef(g1,"zorli",typeof(zorli),"ncl_scalar") filevarattdef(g1,"zorli",zorli) g1->zorli = zorli - + filevardef(g2,"height",typeof(height),"levels") filevarattdef(g2,"height",height) g2->height = (/height/) @@ -803,15 +803,15 @@ begin filevardef(g2,"ozone",typeof(ozone),"levels") filevarattdef(g2,"ozone",ozone) g2->ozone = (/ozone/) - + filevardef(g2,"stc",typeof(stc),"nsoil") filevarattdef(g2,"stc",stc) g2->stc = (/stc/) - + filevardef(g2,"smc",typeof(smc),"nsoil") filevarattdef(g2,"smc",smc) g2->smc = (/smc/) - + filevardef(g2,"slc",typeof(slc),"nsoil") filevarattdef(g2,"slc",slc) g2->slc = (/slc/) diff --git a/scm/etc/scripts/GABLS3_LSM_NoahMP.ncl b/scm/etc/scripts/GABLS3_LSM_NoahMP.ncl index aa956aebf..ad2570875 100644 --- a/scm/etc/scripts/GABLS3_LSM_NoahMP.ncl +++ b/scm/etc/scripts/GABLS3_LSM_NoahMP.ncl @@ -5,7 +5,7 @@ load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/contributed.ncl" begin ;Define constants - + missing_value = -9999.0 g = 9.80665 ;gravity (m s-2) R_dry = 287. ;ideal gas dry air constant (J kg-1 K-1) @@ -24,7 +24,7 @@ begin ; Time, 01Jul2006 12:00:00 UTC - 02Jul2006 12:00:00 UTC ; Must be in seconds time = fspan(0,86400,145) - time@long_name = "elapsed time since the beginning of the simulation" + time@long_name = "elapsed time since the beginning of the simulation" time@units = "s" ; timb = fspan(0,86400,145) @@ -52,7 +52,7 @@ begin ; Total water specific humidity (q) at heights listed above qt = (/ 9.3e-3, 9.3e-3, 8.5e-3, 8.4e-3, 8.3e-3, 8.2e-3, 8.1e-3, \ - 8.0e-3, 7.5e-3, 2.0e-3, 0.3e-3, 0.01e-3, 0.003e-3, 0. /) + 8.0e-3, 7.5e-3, 2.0e-3, 0.3e-3, 0.01e-3, 0.003e-3, 0. /) qt@long_name = "initial profile of total water specific humidity" qt@units = "kg kg^-1" @@ -96,7 +96,7 @@ begin end do ; Solve the hypsometric equation for p2 to attain each new pressure level -; and fill the array (the variable to fill is levels, created above.) +; and fill the array (the variable to fill is levels, created above.) ; The value for levels(0) = p_surf(0) levels(0) = p_surf(0) do i=1,dimsizes(levels)-1,1 @@ -113,7 +113,7 @@ begin ; Calculate thetail. Because ql and qi are not given, this is not possible, ; so the initial profile of thetail will be assumed theta. -; The remainder of the equation used in the gmtb-scm user's guide would be +; The remainder of the equation used in the gmtb-scm user's guide would be ; zero, leaving you with only theta. thetail = theta thetail@long_name = "initial profile of ice-liquid water potential "+ \ @@ -135,10 +135,10 @@ begin v@long_name = "initial profile of N-S horizontal wind" v@units = "m s^-1" -; Use GLDAS to derive the sensible and latent heat flux for the Cabauw -; location, then you can compare the GLDAS H/Le to the given intial Bowen +; Use GLDAS to derive the sensible and latent heat flux for the Cabauw +; location, then you can compare the GLDAS H/Le to the given intial Bowen ; ratio. Begin by reading in the data from each file. -; gl_dir = "/glade/scratch/damico/GLDAS_GABLS3/" +; gl_dir = "/path/to/GLDAS_GABLS3/" ; gl_00 = addfile(gl_dir+"GLDAS_NOAH025_3H.A20060701.0000.021.nc4.SUB.nc4", \ ; "r") @@ -249,7 +249,7 @@ begin w_ls@units = "m s^-1" ; Geostrophic winds are given at certain times but only at the surface. -; Instructions from GABLS suggest interpolation to surface winds up to +; Instructions from GABLS suggest interpolation to surface winds up to ; 2000 m, and then constant from that point. This should be done for each ; time step. Starting with time. u_geo_spec = (/ -7.8, -7.8, -6.5, -5.0, -5.0, -6.5 /) @@ -260,7 +260,7 @@ begin v_geo_t = (/ 0, 21600, 39600, 54000, 64800, 86400 /) v_geo = linint1(v_geo_t,v_geo_spec,False,time,0) -; Interpolate with height, linearly, from the surface values above to -2.0 +; Interpolate with height, linearly, from the surface values above to -2.0 ; m s^-1 for u and 2.0 m s^-1 for v. Above 2000 m, geostrophic wind is ; constant with height (according to GABLS guide). u_g = new((/ dimsizes(levels),dimsizes(time) /),float) @@ -287,10 +287,10 @@ begin u_g@units = "m s^-1" v_g@unit = "m s^-1" -; Horizontal temperature tendency due to advection, which can be converted to -; thetail tendency. The values are give; between 200-1000m, decreasing -; to zero down towards the surface and decreasing to zero from 1000m to -; 1500m, with zero entirely above. Once again, there needs to be +; Horizontal temperature tendency due to advection, which can be converted to +; thetail tendency. The values are give; between 200-1000m, decreasing +; to zero down towards the surface and decreasing to zero from 1000m to +; 1500m, with zero entirely above. Once again, there needs to be ; interpolation in time and with height. T_advec_spec = (/ -2.5e-5,7.5e-5, 0., 0. /) T_advec_time = (/ 0, 46800,64800,86400 /) @@ -316,10 +316,10 @@ begin "horizontal advection" h_advec_thetail@units = "K s^-1" -; The last remaining variable given in the data that the gmtb-scm can -; use is horizontal specific humidity tendency. The values are given +; The last remaining variable given in the data that the gmtb-scm can +; use is horizontal specific humidity tendency. The values are given ; between 200-1000m, decreasing to zero down towards the surface and -; decreasing to zero from 1000m to 1500, with zero entirely above. Once +; decreasing to zero from 1000m to 1500, with zero entirely above. Once ; again, there needs to be interpolation in time and with height. h_advec_spec = (/ 0., 8.e-8, 0., -8.e-8, 0., 0. /) h_advec_time = (/ 0, 32400, 43200, 50400, 61200, 86400 /) @@ -407,7 +407,7 @@ begin v_advec_thetail = 0. v_advec_thetail@long_name = "prescribed theta_il tendency due to " + \ "vertical advection" - v_advec_thetail@units = "K s^-1" + v_advec_thetail@units = "K s^-1" v_advec_qt = new((/ dimsizes(levels),dimsizes(time) /),float) v_advec_qt = 0. @@ -418,141 +418,141 @@ begin ; Noah LSM initialization slmsk = 1.0 ;corresponds to land from the UFS ICs slmsk@long_name = "land-sea-ice mask" - - tsfco = 305.0 + + tsfco = 305.0 tsfco@long_name = "sea surface temperature OR surface skin temperature over land OR sea ice surface skin temperature (depends on value of slmsk)" tsfco@units = "K" - + weasd = 0.0 weasd@long_name = "water equivalent accumulated snow depth" weasd@units = "mm" - + tg3 = 283.15 ;corresponds to case specs tg3@units = "K" tg3@long_name = "deep soil temperature" - + zorl = 15.0 ;(cm) from case specs zorl@long_name = "composite surface roughness length" zorl@units = "cm" - + zorlw = zorl ;(cm) from case specs zorlw@long_name = "surface roughness length over ocean" zorlw@units = "cm" - + alvsf = 0.23 ;corresponds to case specs alvsf@long_name = "60 degree vis albedo with strong cosz dependency" - + alnsf = 0.23 ;corresponds to case specs alnsf@long_name = "60 degree nir albedo with strong cosz dependency" - + alvwf = 0.23 ;corresponds to case specs alvwf@long_name = "60 degree vis albedo with weak cosz dependency" - + alnwf = 0.23 ;corresponds to case specs alnwf@long_name = "60 degree nir albedo with weak cosz dependency" - + facsf = 0.50556319952 ;corresponds to value from UFS ICs (static from fix files for C768) facsf@long_name = "fractional coverage with strong cosz dependency" - + facwf = 0.49443680048 ;corresponds to value from UFS ICs (static from fix files for C768) facwf@long_name = "fractional coverage with weak cosz dependency" - - vegfrac = 0.75 ; the value of 100% specified in the case + + vegfrac = 0.75 ; the value of 100% specified in the case ; specifications clashes with the maximum value ; for this gridpoint from UFS ICs vegfrac@long_name = "vegetation fraction" - + canopy = 0.5 ;corresponds to typical value for grassland in the growing season canopy@units = "kg m-2" canopy@long_name = "amount of water stored in canopy" - + f10m = missing_value ;this is not required f10m@long_name = "ratio of sigma level 1 wind and 10m wind" - + t2m = missing_value; this is not required t2m@long_name = "2-meter absolute temperature" t2m@units = "K" - + q2m = missing_value; this is not required q2m@long_name = "2-meter specific humidity" q2m@units = "kg kg-1" - - vegtyp = 10 ;corresponds to the "grasslands" type for the IGBP (vegsrc=1) + + vegtyp = 10 ;corresponds to the "grasslands" type for the IGBP (vegsrc=1) ;dataset vegtyp@long_name = "vegetation type (1-12)" - + soiltyp = 12 ;corresponds to "clay" soil type soiltyp@long_name = "soil type (1-12)" - + ;derive friction velocity from known values wind1 = sqrt(u_specified(1)^2 + v_specified(1)^2) uustar = von_K*wind1/log(u_h(1)/(0.01*zorl)) uustar@units = "m s-1" uustar@long_name = "friction velocity" - + ffmm = missing_value ;this is not required ffmm@long_name = "Monin-Obukhov similarity function for momentum" - + ffhh = missing_value ;this is not required ffhh@long_name = "Monin-Obukhov similarity function for heat" - + hice = 0.0 ;corresponds to value from UFS ICs hice@units = "m" hice@long_name = "sea ice thickness" - + fice = 0.0 ;corresponds to value from UFS ICs fice@long_name = "ice fraction" - + tisfc = tsfco ; there is no ice, but this corresponds to the surface skin temperature tisfc@units = "K" tisfc@long_name = "ice surface temperature" - + tprcp = missing_value; not required tprcp@units = "m" tprcp@long_name = "instantaneous total precipitation amount" - + srflag = missing_value; not required srflag@long_name = "snow/rain flag for precipitation" - + snwdph = 0.0 ;corresponds to case specs snwdph@units = "mm" snwdph@long_name = "water equivalent snow depth" - + shdmin = 0.01 ; corresponds to minimum vegetation fraction from surface fixed data (is not actually used in Noah LSM) shdmin@long_name = "minimum vegetation fraction" - + shdmax = 0.8 ; the maximum value from the surface fixed data is closer to 0.75 (is not actually used in Noah LSM) shdmax@long_name = "maximum vegetation fraction" - + slopetyp = 1 slopetyp@long_name = "slope type (1-9)" - + snoalb = 0.728796124458 ;corresponds to value from UFS ICs (static from fix files for C768) snoalb@long_name = "maximum snow albedo" - + sncovr = 0.0 ;corresponds to case specs sncovr@long_name = "snow area fraction" - + tsfcl = tsfco tsfcl@long_name = "surface skin temperature over land" tsfcl@units = "K" - + zorll = zorl ;(cm) from case specs zorll@long_name = "surface roughness length over land" zorll@units = "cm" - + zorli = zorl ;(cm) from case specs zorli@long_name = "surface roughness length over ice" zorli@units = "cm" - + stc = (/ 292.55, 289.9, 285.35, 283.15 /) stc@units = "K" stc@long_name = "initial profile of soil temperature" - + smc = (/ 0.33, 0.33, 0.33, 0.33 /) smc@units = "m3 m-3" smc@long_name = "initial profile of soil moisture" - + slc = smc ;all liquid (no ice) slc@units = "m3 m-3" slc@long_name = "initial profile of soil liquid moisture" @@ -594,7 +594,7 @@ begin filevardef(fo,"levels",typeof(levels),"levels") filevarattdef(fo,"levels",levels) fo->levels = (/ levels /) - + filevardef(fo,"soil_depth",typeof(soil_depth),"nsoil") filevarattdef(fo,"soil_depth",soil_depth) fo->soil_depth = (/ soil_depth /) @@ -615,7 +615,7 @@ begin filedimdef(g2,dimNames,dimSizes,dimUnlim) filedimdef(g3,dimNames,dimSizes,dimUnlim) - + filevardef(g1,"lat",typeof(lat),"ncl_scalar") filevarattdef(g1,"lat",lat) g1->lat = lat @@ -623,151 +623,151 @@ begin filevardef(g1,"lon",typeof(lon),"ncl_scalar") filevarattdef(g1,"lon",lon) g1->lon = lon - + filevardef(g1,"slmsk",typeof(slmsk),"ncl_scalar") filevarattdef(g1,"slmsk",slmsk) g1->slmsk = slmsk - + filevardef(g1,"tsfco",typeof(tsfco),"ncl_scalar") filevarattdef(g1,"tsfco",tsfco) g1->tsfco = tsfco - + filevardef(g1,"weasd",typeof(weasd),"ncl_scalar") filevarattdef(g1,"weasd",weasd) g1->weasd = weasd - + filevardef(g1,"tg3",typeof(tg3),"ncl_scalar") filevarattdef(g1,"tg3",tg3) g1->tg3 = tg3 - + filevardef(g1,"zorl",typeof(zorl),"ncl_scalar") filevarattdef(g1,"zorl",zorl) g1->zorl = zorl - + filevardef(g1,"zorlw",typeof(zorlw),"ncl_scalar") filevarattdef(g1,"zorlw",zorlw) g1->zorlw = zorlw - + filevardef(g1,"alvsf",typeof(alvsf),"ncl_scalar") filevarattdef(g1,"alvsf",alvsf) g1->alvsf = alvsf - + filevardef(g1,"alnsf",typeof(alnsf),"ncl_scalar") filevarattdef(g1,"alnsf",alnsf) g1->alnsf = alnsf - + filevardef(g1,"alvwf",typeof(alvwf),"ncl_scalar") filevarattdef(g1,"alvwf",alvwf) g1->alvwf = alvwf - + filevardef(g1,"alnwf",typeof(alnwf),"ncl_scalar") filevarattdef(g1,"alnwf",alnwf) g1->alnwf = alnwf - + filevardef(g1,"facsf",typeof(facsf),"ncl_scalar") filevarattdef(g1,"facsf",facsf) g1->facsf = facsf - + filevardef(g1,"facwf",typeof(facwf),"ncl_scalar") filevarattdef(g1,"facwf",facwf) g1->facwf = facwf - + filevardef(g1,"vegfrac",typeof(vegfrac),"ncl_scalar") filevarattdef(g1,"vegfrac",vegfrac) g1->vegfrac = vegfrac - + filevardef(g1,"canopy",typeof(canopy),"ncl_scalar") filevarattdef(g1,"canopy",canopy) g1->canopy = canopy - + filevardef(g1,"f10m",typeof(f10m),"ncl_scalar") filevarattdef(g1,"f10m",f10m) g1->f10m = f10m - + filevardef(g1,"t2m",typeof(t2m),"ncl_scalar") filevarattdef(g1,"t2m",t2m) g1->t2m = t2m - + filevardef(g1,"q2m",typeof(q2m),"ncl_scalar") filevarattdef(g1,"q2m",q2m) g1->q2m = q2m - + filevardef(g1,"vegtyp",typeof(vegtyp),"ncl_scalar") filevarattdef(g1,"vegtyp",vegtyp) g1->vegtyp = vegtyp - + filevardef(g1,"soiltyp",typeof(soiltyp),"ncl_scalar") filevarattdef(g1,"soiltyp",soiltyp) g1->soiltyp = soiltyp - + filevardef(g1,"uustar",typeof(uustar),"ncl_scalar") filevarattdef(g1,"uustar",uustar) g1->uustar = uustar - + filevardef(g1,"ffmm",typeof(ffmm),"ncl_scalar") filevarattdef(g1,"ffmm",ffmm) g1->ffmm = ffmm - + filevardef(g1,"ffhh",typeof(ffhh),"ncl_scalar") filevarattdef(g1,"ffhh",ffhh) g1->ffhh = ffhh - + filevardef(g1,"hice",typeof(hice),"ncl_scalar") filevarattdef(g1,"hice",hice) g1->hice = hice - + filevardef(g1,"fice",typeof(fice),"ncl_scalar") filevarattdef(g1,"fice",fice) g1->fice = fice - + filevardef(g1,"tisfc",typeof(tisfc),"ncl_scalar") filevarattdef(g1,"tisfc",tisfc) g1->tisfc = tisfc - + filevardef(g1,"tprcp",typeof(tprcp),"ncl_scalar") filevarattdef(g1,"tprcp",tprcp) g1->tprcp = tprcp - + filevardef(g1,"srflag",typeof(srflag),"ncl_scalar") filevarattdef(g1,"srflag",srflag) g1->srflag = srflag - + filevardef(g1,"snwdph",typeof(snwdph),"ncl_scalar") filevarattdef(g1,"snwdph",snwdph) g1->snwdph = snwdph - + filevardef(g1,"shdmin",typeof(shdmin),"ncl_scalar") filevarattdef(g1,"shdmin",shdmin) g1->shdmin = shdmin - + filevardef(g1,"shdmax",typeof(shdmax),"ncl_scalar") filevarattdef(g1,"shdmax",shdmax) g1->shdmax = shdmax - + filevardef(g1,"slopetyp",typeof(slopetyp),"ncl_scalar") filevarattdef(g1,"slopetyp",slopetyp) g1->slopetyp = slopetyp - + filevardef(g1,"snoalb",typeof(snoalb),"ncl_scalar") filevarattdef(g1,"snoalb",snoalb) g1->snoalb = snoalb - + filevardef(g1,"sncovr",typeof(sncovr),"ncl_scalar") filevarattdef(g1,"sncovr",sncovr) g1->sncovr = sncovr - + filevardef(g1,"tsfcl",typeof(tsfcl),"ncl_scalar") filevarattdef(g1,"tsfcl",tsfcl) g1->tsfcl = tsfcl - + filevardef(g1,"zorll",typeof(zorll),"ncl_scalar") filevarattdef(g1,"zorll",zorll) g1->zorll = zorll - + filevardef(g1,"zorli",typeof(zorli),"ncl_scalar") filevarattdef(g1,"zorli",zorli) g1->zorli = zorli - + filevardef(g2,"height",typeof(height),"levels") filevarattdef(g2,"height",height) g2->height = (/height/) @@ -803,15 +803,15 @@ begin filevardef(g2,"ozone",typeof(ozone),"levels") filevarattdef(g2,"ozone",ozone) g2->ozone = (/ozone/) - + filevardef(g2,"stc",typeof(stc),"nsoil") filevarattdef(g2,"stc",stc) g2->stc = (/stc/) - + filevardef(g2,"smc",typeof(smc),"nsoil") filevarattdef(g2,"smc",smc) g2->smc = (/smc/) - + filevardef(g2,"slc",typeof(slc),"nsoil") filevarattdef(g2,"slc",slc) g2->slc = (/slc/) diff --git a/scm/etc/scripts/GABLS3_LSM_RUC.ncl b/scm/etc/scripts/GABLS3_LSM_RUC.ncl index 167cb5023..1d096c3c3 100644 --- a/scm/etc/scripts/GABLS3_LSM_RUC.ncl +++ b/scm/etc/scripts/GABLS3_LSM_RUC.ncl @@ -5,7 +5,7 @@ load "$NCARG_ROOT/lib/ncarg/nclscripts/csm/contributed.ncl" begin ;Define constants - + missing_value = -9999.0 g = 9.80665 ;gravity (m s-2) R_dry = 287. ;ideal gas dry air constant (J kg-1 K-1) @@ -24,7 +24,7 @@ begin ; Time, 01Jul2006 12:00:00 UTC - 02Jul2006 12:00:00 UTC ; Must be in seconds time = fspan(0,86400,145) - time@long_name = "elapsed time since the beginning of the simulation" + time@long_name = "elapsed time since the beginning of the simulation" time@units = "s" ; timb = fspan(0,86400,145) @@ -52,7 +52,7 @@ begin ; Total water specific humidity (q) at heights listed above qt = (/ 9.3e-3, 9.3e-3, 8.5e-3, 8.4e-3, 8.3e-3, 8.2e-3, 8.1e-3, \ - 8.0e-3, 7.5e-3, 2.0e-3, 0.3e-3, 0.01e-3, 0.003e-3, 0. /) + 8.0e-3, 7.5e-3, 2.0e-3, 0.3e-3, 0.01e-3, 0.003e-3, 0. /) qt@long_name = "initial profile of total water specific humidity" qt@units = "kg kg^-1" @@ -96,7 +96,7 @@ begin end do ; Solve the hypsometric equation for p2 to attain each new pressure level -; and fill the array (the variable to fill is levels, created above.) +; and fill the array (the variable to fill is levels, created above.) ; The value for levels(0) = p_surf(0) levels(0) = p_surf(0) do i=1,dimsizes(levels)-1,1 @@ -113,7 +113,7 @@ begin ; Calculate thetail. Because ql and qi are not given, this is not possible, ; so the initial profile of thetail will be assumed theta. -; The remainder of the equation used in the gmtb-scm user's guide would be +; The remainder of the equation used in the gmtb-scm user's guide would be ; zero, leaving you with only theta. thetail = theta thetail@long_name = "initial profile of ice-liquid water potential "+ \ @@ -135,10 +135,10 @@ begin v@long_name = "initial profile of N-S horizontal wind" v@units = "m s^-1" -; Use GLDAS to derive the sensible and latent heat flux for the Cabauw -; location, then you can compare the GLDAS H/Le to the given intial Bowen +; Use GLDAS to derive the sensible and latent heat flux for the Cabauw +; location, then you can compare the GLDAS H/Le to the given intial Bowen ; ratio. Begin by reading in the data from each file. -; gl_dir = "/glade/scratch/damico/GLDAS_GABLS3/" +; gl_dir = "/path/to/GLDAS_GABLS3/" ; gl_00 = addfile(gl_dir+"GLDAS_NOAH025_3H.A20060701.0000.021.nc4.SUB.nc4", \ ; "r") @@ -249,7 +249,7 @@ begin w_ls@units = "m s^-1" ; Geostrophic winds are given at certain times but only at the surface. -; Instructions from GABLS suggest interpolation to surface winds up to +; Instructions from GABLS suggest interpolation to surface winds up to ; 2000 m, and then constant from that point. This should be done for each ; time step. Starting with time. u_geo_spec = (/ -7.8, -7.8, -6.5, -5.0, -5.0, -6.5 /) @@ -260,7 +260,7 @@ begin v_geo_t = (/ 0, 21600, 39600, 54000, 64800, 86400 /) v_geo = linint1(v_geo_t,v_geo_spec,False,time,0) -; Interpolate with height, linearly, from the surface values above to -2.0 +; Interpolate with height, linearly, from the surface values above to -2.0 ; m s^-1 for u and 2.0 m s^-1 for v. Above 2000 m, geostrophic wind is ; constant with height (according to GABLS guide). u_g = new((/ dimsizes(levels),dimsizes(time) /),float) @@ -287,10 +287,10 @@ begin u_g@units = "m s^-1" v_g@unit = "m s^-1" -; Horizontal temperature tendency due to advection, which can be converted to -; thetail tendency. The values are give; between 200-1000m, decreasing -; to zero down towards the surface and decreasing to zero from 1000m to -; 1500m, with zero entirely above. Once again, there needs to be +; Horizontal temperature tendency due to advection, which can be converted to +; thetail tendency. The values are give; between 200-1000m, decreasing +; to zero down towards the surface and decreasing to zero from 1000m to +; 1500m, with zero entirely above. Once again, there needs to be ; interpolation in time and with height. T_advec_spec = (/ -2.5e-5,7.5e-5, 0., 0. /) T_advec_time = (/ 0, 46800,64800,86400 /) @@ -316,10 +316,10 @@ begin "horizontal advection" h_advec_thetail@units = "K s^-1" -; The last remaining variable given in the data that the gmtb-scm can -; use is horizontal specific humidity tendency. The values are given +; The last remaining variable given in the data that the gmtb-scm can +; use is horizontal specific humidity tendency. The values are given ; between 200-1000m, decreasing to zero down towards the surface and -; decreasing to zero from 1000m to 1500, with zero entirely above. Once +; decreasing to zero from 1000m to 1500, with zero entirely above. Once ; again, there needs to be interpolation in time and with height. h_advec_spec = (/ 0., 8.e-8, 0., -8.e-8, 0., 0. /) h_advec_time = (/ 0, 32400, 43200, 50400, 61200, 86400 /) @@ -407,7 +407,7 @@ begin v_advec_thetail = 0. v_advec_thetail@long_name = "prescribed theta_il tendency due to " + \ "vertical advection" - v_advec_thetail@units = "K s^-1" + v_advec_thetail@units = "K s^-1" v_advec_qt = new((/ dimsizes(levels),dimsizes(time) /),float) v_advec_qt = 0. @@ -418,199 +418,199 @@ begin ; Noah LSM initialization slmsk = 1.0 ;corresponds to land from the UFS ICs slmsk@long_name = "land-sea-ice mask" - - tsfco = 305.0 + + tsfco = 305.0 tsfco@long_name = "sea surface temperature OR surface skin temperature over land OR sea ice surface skin temperature (depends on value of slmsk)" tsfco@units = "K" - + weasd = 0.0 weasd@long_name = "water equivalent accumulated snow depth" weasd@units = "mm" - + tg3 = 283.15 ;corresponds to case specs tg3@units = "K" tg3@long_name = "deep soil temperature" - + zorl = 15.0 ;(cm) from case specs zorl@long_name = "composite surface roughness length" zorl@units = "cm" - + zorlw = zorl ;(cm) from case specs zorlw@long_name = "surface roughness length over ocean" zorlw@units = "cm" - + alvsf = 0.23 ;corresponds to case specs alvsf@long_name = "60 degree vis albedo with strong cosz dependency" - + alnsf = 0.23 ;corresponds to case specs alnsf@long_name = "60 degree nir albedo with strong cosz dependency" - + alvwf = 0.23 ;corresponds to case specs alvwf@long_name = "60 degree vis albedo with weak cosz dependency" - + alnwf = 0.23 ;corresponds to case specs alnwf@long_name = "60 degree nir albedo with weak cosz dependency" - + facsf = 0.50556319952 ;corresponds to value from UFS ICs (static from fix files for C768) facsf@long_name = "fractional coverage with strong cosz dependency" - + facwf = 0.49443680048 ;corresponds to value from UFS ICs (static from fix files for C768) facwf@long_name = "fractional coverage with weak cosz dependency" - - vegfrac = 0.75 ; the value of 100% specified in the case + + vegfrac = 0.75 ; the value of 100% specified in the case ; specifications clashes with the maximum value ; for this gridpoint from UFS ICs vegfrac@long_name = "vegetation fraction" - + canopy = 0.5 ;corresponds to typical value for grassland in the growing season canopy@units = "kg m-2" canopy@long_name = "amount of water stored in canopy" - + f10m = missing_value ;this is not required f10m@long_name = "ratio of sigma level 1 wind and 10m wind" - + t2m = missing_value; this is not required t2m@long_name = "2-meter absolute temperature" t2m@units = "K" - + q2m = missing_value; this is not required q2m@long_name = "2-meter specific humidity" q2m@units = "kg kg-1" - - vegtyp = 10 ;corresponds to the "grasslands" type for the IGBP (vegsrc=1) + + vegtyp = 10 ;corresponds to the "grasslands" type for the IGBP (vegsrc=1) ;dataset vegtyp@long_name = "vegetation type (1-12)" - + soiltyp = 12 ;corresponds to "clay" soil type soiltyp@long_name = "soil type (1-12)" - + ;derive friction velocity from known values wind1 = sqrt(u_specified(1)^2 + v_specified(1)^2) uustar = von_K*wind1/log(u_h(1)/(0.01*zorl)) uustar@units = "m s-1" uustar@long_name = "friction velocity" - + ffmm = missing_value ;this is not required ffmm@long_name = "Monin-Obukhov similarity function for momentum" - + ffhh = missing_value ;this is not required ffhh@long_name = "Monin-Obukhov similarity function for heat" - + hice = 0.0 ;corresponds to value from UFS ICs hice@units = "m" hice@long_name = "sea ice thickness" - + fice = 0.0 ;corresponds to value from UFS ICs fice@long_name = "ice fraction" - + tisfc = tsfco ; there is no ice, but this corresponds to the surface skin temperature tisfc@units = "K" tisfc@long_name = "ice surface temperature" - + tprcp = missing_value; not required tprcp@units = "m" tprcp@long_name = "instantaneous total precipitation amount" - + srflag = missing_value; not required srflag@long_name = "snow/rain flag for precipitation" - + snwdph = 0.0 ;corresponds to case specs snwdph@units = "mm" snwdph@long_name = "water equivalent snow depth" - + shdmin = 0.01 ; corresponds to minimum vegetation fraction from surface fixed data (is not actually used in Noah LSM) shdmin@long_name = "minimum vegetation fraction" - + shdmax = 0.8 ; the maximum value from the surface fixed data is closer to 0.75 (is not actually used in Noah LSM) shdmax@long_name = "maximum vegetation fraction" - + slopetyp = 1 slopetyp@long_name = "slope type (1-9)" - + snoalb = 0.728796124458 ;corresponds to value from UFS ICs (static from fix files for C768) snoalb@long_name = "maximum snow albedo" - + sncovr = 0.0 ;corresponds to case specs sncovr@long_name = "snow area fraction" - + tsfcl = tsfco tsfcl@long_name = "surface skin temperature over land" tsfcl@units = "K" - + zorll = zorl ;(cm) from case specs zorll@long_name = "surface roughness length over land" zorll@units = "cm" - + zorli = zorl ;(cm) from case specs zorli@long_name = "surface roughness length over ice" zorli@units = "cm" - + wetness = 0.37; from rucinit using Noah ICs wetness@long_name = "normalized soil wetness for land surface model" - + clw_surf_land = 0.0 clw_surf_land@long_name = "moist cloud water mixing ratio at surface over land" clw_surf_land@units = "kg kg-1" - + clw_surf_ice = 0.0 clw_surf_ice@long_name = "moist cloud water mixing ratio at surface over ice" clw_surf_ice@units = "kg kg-1" - + qwv_surf_land = qt(0)/(1.0 - qt(0)) qwv_surf_land@long_name = "water vapor mixing ratio at surface over land" qwv_surf_land@units = "kg kg-1" - + qwv_surf_ice = qwv_surf_land qwv_surf_ice@long_name = "water vapor mixing ratio at surface over ice" qwv_surf_ice@units = "kg kg-1" - + tsnow_land = 273.14 tsnow_land@long_name = "snow temperature at the bottom of the first snow layer over land" tsnow_land@units = "K" - + tsnow_ice = tsnow_land tsnow_ice@long_name = "snow temperature at the bottom of the first snow layer over ice" tsnow_ice@units = "K" - + snowfallac_land = 0.0 snowfallac_land@long_name = "run-total snow accumulation on the ground" snowfallac_land@units = "kg m-2" - + snowfallac_ice = 0.0 snowfallac_ice@long_name = "run-total snow accumulation on the ice" snowfallac_ice@units = "kg m-2" - + sncovr_ice = 0.0 sncovr_ice@long_name = "surface snow area fraction over ice" - + sfalb_lnd = 0.23 sfalb_lnd@long_name = "mean surface diffused sw albedo over land" - + sfalb_lnd_bck = 0.23 sfalb_lnd_bck@long_name = "surface snow-free albedo over ice" - + sfalb_ice = 0.6 sfalb_ice@long_name = "mean surface diffused sw albedo over ice" - + emis_ice = 0.97 emis_ice@long_name = "surface lw emissivity in fraction over ice" - + tslb = (/ 296.55, 295.95, 294.55, 292.55, 290.65, 288.39, 285.35, 284.03, 283.15/) tslb@units = "K" tslb@long_name = "initial profile of soil temperature for RUC LSM" - + smois = (/ 0.31, 0.31, 0.31, 0.31, 0.31, 0.31, 0.31, 0.31, 0.31/) smois@units = "fraction" smois@long_name = "volumetric fraction of soil moisture for RUC LSM" - + sh2o = smois sh2o@units = "fraction" sh2o@long_name = "volume fraction of unfrozen soil moisture for RUC LSM" - + smfr = (/ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0/) smfr@units = "fraction" smfr@long_name = "volume fraction of frozen soil moisture for RUC LSM" - + flfr = (/ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0/) flfr@long_name = "flag for frozen soil physics for RUC LSM" @@ -651,7 +651,7 @@ begin filevardef(fo,"levels",typeof(levels),"levels") filevarattdef(fo,"levels",levels) fo->levels = (/ levels /) - + filevardef(fo,"soil_depth",typeof(soil_depth),"nsoil") filevarattdef(fo,"soil_depth",soil_depth) fo->soil_depth = (/ soil_depth /) @@ -672,7 +672,7 @@ begin filedimdef(g2,dimNames,dimSizes,dimUnlim) filedimdef(g3,dimNames,dimSizes,dimUnlim) - + filevardef(g1,"lat",typeof(lat),"ncl_scalar") filevarattdef(g1,"lat",lat) g1->lat = lat @@ -680,207 +680,207 @@ begin filevardef(g1,"lon",typeof(lon),"ncl_scalar") filevarattdef(g1,"lon",lon) g1->lon = lon - + filevardef(g1,"slmsk",typeof(slmsk),"ncl_scalar") filevarattdef(g1,"slmsk",slmsk) g1->slmsk = slmsk - + filevardef(g1,"tsfco",typeof(tsfco),"ncl_scalar") filevarattdef(g1,"tsfco",tsfco) g1->tsfco = tsfco - + filevardef(g1,"weasd",typeof(weasd),"ncl_scalar") filevarattdef(g1,"weasd",weasd) g1->weasd = weasd - + filevardef(g1,"tg3",typeof(tg3),"ncl_scalar") filevarattdef(g1,"tg3",tg3) g1->tg3 = tg3 - + filevardef(g1,"zorl",typeof(zorl),"ncl_scalar") filevarattdef(g1,"zorl",zorl) g1->zorl = zorl - + filevardef(g1,"zorlw",typeof(zorlw),"ncl_scalar") filevarattdef(g1,"zorlw",zorlw) g1->zorlw = zorlw - + filevardef(g1,"alvsf",typeof(alvsf),"ncl_scalar") filevarattdef(g1,"alvsf",alvsf) g1->alvsf = alvsf - + filevardef(g1,"alnsf",typeof(alnsf),"ncl_scalar") filevarattdef(g1,"alnsf",alnsf) g1->alnsf = alnsf - + filevardef(g1,"alvwf",typeof(alvwf),"ncl_scalar") filevarattdef(g1,"alvwf",alvwf) g1->alvwf = alvwf - + filevardef(g1,"alnwf",typeof(alnwf),"ncl_scalar") filevarattdef(g1,"alnwf",alnwf) g1->alnwf = alnwf - + filevardef(g1,"facsf",typeof(facsf),"ncl_scalar") filevarattdef(g1,"facsf",facsf) g1->facsf = facsf - + filevardef(g1,"facwf",typeof(facwf),"ncl_scalar") filevarattdef(g1,"facwf",facwf) g1->facwf = facwf - + filevardef(g1,"vegfrac",typeof(vegfrac),"ncl_scalar") filevarattdef(g1,"vegfrac",vegfrac) g1->vegfrac = vegfrac - + filevardef(g1,"canopy",typeof(canopy),"ncl_scalar") filevarattdef(g1,"canopy",canopy) g1->canopy = canopy - + filevardef(g1,"f10m",typeof(f10m),"ncl_scalar") filevarattdef(g1,"f10m",f10m) g1->f10m = f10m - + filevardef(g1,"t2m",typeof(t2m),"ncl_scalar") filevarattdef(g1,"t2m",t2m) g1->t2m = t2m - + filevardef(g1,"q2m",typeof(q2m),"ncl_scalar") filevarattdef(g1,"q2m",q2m) g1->q2m = q2m - + filevardef(g1,"vegtyp",typeof(vegtyp),"ncl_scalar") filevarattdef(g1,"vegtyp",vegtyp) g1->vegtyp = vegtyp - + filevardef(g1,"soiltyp",typeof(soiltyp),"ncl_scalar") filevarattdef(g1,"soiltyp",soiltyp) g1->soiltyp = soiltyp - + filevardef(g1,"uustar",typeof(uustar),"ncl_scalar") filevarattdef(g1,"uustar",uustar) g1->uustar = uustar - + filevardef(g1,"ffmm",typeof(ffmm),"ncl_scalar") filevarattdef(g1,"ffmm",ffmm) g1->ffmm = ffmm - + filevardef(g1,"ffhh",typeof(ffhh),"ncl_scalar") filevarattdef(g1,"ffhh",ffhh) g1->ffhh = ffhh - + filevardef(g1,"hice",typeof(hice),"ncl_scalar") filevarattdef(g1,"hice",hice) g1->hice = hice - + filevardef(g1,"fice",typeof(fice),"ncl_scalar") filevarattdef(g1,"fice",fice) g1->fice = fice - + filevardef(g1,"tisfc",typeof(tisfc),"ncl_scalar") filevarattdef(g1,"tisfc",tisfc) g1->tisfc = tisfc - + filevardef(g1,"tprcp",typeof(tprcp),"ncl_scalar") filevarattdef(g1,"tprcp",tprcp) g1->tprcp = tprcp - + filevardef(g1,"srflag",typeof(srflag),"ncl_scalar") filevarattdef(g1,"srflag",srflag) g1->srflag = srflag - + filevardef(g1,"snwdph",typeof(snwdph),"ncl_scalar") filevarattdef(g1,"snwdph",snwdph) g1->snwdph = snwdph - + filevardef(g1,"shdmin",typeof(shdmin),"ncl_scalar") filevarattdef(g1,"shdmin",shdmin) g1->shdmin = shdmin - + filevardef(g1,"shdmax",typeof(shdmax),"ncl_scalar") filevarattdef(g1,"shdmax",shdmax) g1->shdmax = shdmax - + filevardef(g1,"slopetyp",typeof(slopetyp),"ncl_scalar") filevarattdef(g1,"slopetyp",slopetyp) g1->slopetyp = slopetyp - + filevardef(g1,"snoalb",typeof(snoalb),"ncl_scalar") filevarattdef(g1,"snoalb",snoalb) g1->snoalb = snoalb - + filevardef(g1,"sncovr",typeof(sncovr),"ncl_scalar") filevarattdef(g1,"sncovr",sncovr) g1->sncovr = sncovr - + filevardef(g1,"tsfcl",typeof(tsfcl),"ncl_scalar") filevarattdef(g1,"tsfcl",tsfcl) g1->tsfcl = tsfcl - + filevardef(g1,"zorll",typeof(zorll),"ncl_scalar") filevarattdef(g1,"zorll",zorll) g1->zorll = zorll - + filevardef(g1,"zorli",typeof(zorli),"ncl_scalar") filevarattdef(g1,"zorli",zorli) g1->zorli = zorli - + filevardef(g1,"wetness",typeof(wetness),"ncl_scalar") filevarattdef(g1,"wetness",wetness) g1->wetness = wetness - + filevardef(g1,"clw_surf_land",typeof(clw_surf_land),"ncl_scalar") filevarattdef(g1,"clw_surf_land",clw_surf_land) g1->clw_surf_land = clw_surf_land - + filevardef(g1,"clw_surf_ice",typeof(clw_surf_ice),"ncl_scalar") filevarattdef(g1,"clw_surf_ice",clw_surf_ice) g1->clw_surf_ice = clw_surf_ice - + filevardef(g1,"qwv_surf_land",typeof(qwv_surf_land),"ncl_scalar") filevarattdef(g1,"qwv_surf_land",qwv_surf_land) g1->qwv_surf_land = qwv_surf_land - + filevardef(g1,"qwv_surf_ice",typeof(qwv_surf_ice),"ncl_scalar") filevarattdef(g1,"qwv_surf_ice",qwv_surf_ice) g1->qwv_surf_ice = qwv_surf_ice - + filevardef(g1,"tsnow_land",typeof(tsnow_land),"ncl_scalar") filevarattdef(g1,"tsnow_land",tsnow_land) g1->tsnow_land = tsnow_land - + filevardef(g1,"tsnow_ice",typeof(tsnow_ice),"ncl_scalar") filevarattdef(g1,"tsnow_ice",tsnow_ice) g1->tsnow_ice = tsnow_ice - + filevardef(g1,"snowfallac_land",typeof(snowfallac_land),"ncl_scalar") filevarattdef(g1,"snowfallac_land",snowfallac_land) g1->snowfallac_land = snowfallac_land - + filevardef(g1,"snowfallac_ice",typeof(snowfallac_ice),"ncl_scalar") filevarattdef(g1,"snowfallac_ice",snowfallac_ice) g1->snowfallac_ice = snowfallac_ice - + filevardef(g1,"sncovr_ice",typeof(sncovr_ice),"ncl_scalar") filevarattdef(g1,"sncovr_ice",sncovr_ice) g1->sncovr_ice = sncovr_ice - + filevardef(g1,"sfalb_lnd",typeof(sfalb_lnd),"ncl_scalar") filevarattdef(g1,"sfalb_lnd",sfalb_lnd) g1->sfalb_lnd = sfalb_lnd - + filevardef(g1,"sfalb_lnd_bck",typeof(sfalb_lnd_bck),"ncl_scalar") filevarattdef(g1,"sfalb_lnd_bck",sfalb_lnd_bck) g1->sfalb_lnd_bck = sfalb_lnd_bck - + filevardef(g1,"sfalb_ice",typeof(sfalb_ice),"ncl_scalar") filevarattdef(g1,"sfalb_ice",sfalb_ice) g1->sfalb_ice = sfalb_ice - + filevardef(g1,"emis_ice",typeof(emis_ice),"ncl_scalar") filevarattdef(g1,"emis_ice",emis_ice) g1->emis_ice = emis_ice - + filevardef(g2,"height",typeof(height),"levels") filevarattdef(g2,"height",height) g2->height = (/height/) @@ -916,23 +916,23 @@ begin filevardef(g2,"ozone",typeof(ozone),"levels") filevarattdef(g2,"ozone",ozone) g2->ozone = (/ozone/) - + filevardef(g2,"tslb",typeof(tslb),"nsoil") filevarattdef(g2,"tslb",tslb) g2->tslb = (/tslb/) - + filevardef(g2,"smois",typeof(smois),"nsoil") filevarattdef(g2,"smois",smois) g2->smois = (/smois/) - + filevardef(g2,"sh2o",typeof(sh2o),"nsoil") filevarattdef(g2,"sh2o",sh2o) g2->sh2o = (/sh2o/) - + filevardef(g2,"smfr",typeof(smfr),"nsoil") filevarattdef(g2,"smfr",smfr) g2->smfr = (/smfr/) - + filevardef(g2,"flfr",typeof(flfr),"nsoil") filevarattdef(g2,"flfr",flfr) g2->flfr = (/flfr/) diff --git a/test/README.md b/test/README.md index ebc4cfc5d..91878deae 100644 --- a/test/README.md +++ b/test/README.md @@ -7,11 +7,11 @@ and suites. It consists of the following scripts: * ``rt.sh`` - Driver for the regresion test that builds, runs and calls the summarize.sh script * ``rt_test_cases.py``- list of all supported cases and suites -* ``summarize.sh`` - Called by ``rt.sh`` to parse the output of each test to determine pass/fail +* ``summarize.sh`` - Called by ``rt.sh`` to parse the output of each test to determine pass/fail Currently, the following configurations are supported: -Machine | Cheyenne | Hera | Desktop | +Machine | Derecho | Hera | Desktop | ------------| ---------------|----------------|----------------| Compiler(s) | Intel, GNU | Intel | gfortran | Build Types | Release, Debug | Release, Debug | Release, Debug | @@ -39,11 +39,11 @@ The debug tests use a reduced runtime for faster turnaround and to conserve comp # To run the tests (no baseline generation or comparison): -On Cheyenne: +On Derecho: ``` cd test -./rt.sh cheyenne >& test.out & +./rt.sh derecho >& test.out & ``` On Hera: @@ -76,4 +76,3 @@ A useful workflow might consist of the following steps: 2. Run ``rt.sh ${machine} -g `` to generate a baseline and verify build/run 3. Make changes to your working copy 4. Run ``rt.sh ${machine} -c `` to verify your changes - diff --git a/test/rt.sh b/test/rt.sh index d8c3259fc..e5772d70a 100755 --- a/test/rt.sh +++ b/test/rt.sh @@ -8,7 +8,7 @@ # # Assumptions: # -# Command line arguments: machine name (hera or cheyenne) +# Command line arguments: machine name (hera or derecho) # -g run tests, generate baseline in # -c run tests, compare to baseline in # -h display usage @@ -35,7 +35,7 @@ function usage() { } function wait_for_criteria() { - + # Function that iteratively checks the return code of a given Unix command # and returns 0 when the command is successful or 1 if not @@ -67,7 +67,7 @@ function wait_for_criteria() { fi } -machines=( hera cheyenne desktop ) +machines=( hera derecho desktop ) executable_name=scm [[ $# -eq 0 ]] && usage # Display usage if no command-line arguments @@ -138,7 +138,7 @@ run_it=0 # Set to 1 to skip run (for t build_types=( Release Debug ) # Set all instances of CMAKE_BUILD_TYPE -if [ "${machine}" == "Cheyenne" ] ; then +if [ "${machine}" == "Derecho" ] ; then users=( $USER@ucar.edu ) compilers=( intel gnu ) use_batch_system=true @@ -298,13 +298,13 @@ done # End compiler loop n_tests=0 for compiler in "${compilers[@]}"; do for build_type in "${build_types[@]}"; do - + echo "-------------------------------------------------------" >> ${TEST_OUTPUT} echo "Monitoring ${compiler} ${build_type} run..." >> ${TEST_OUTPUT} echo "-------------------------------------------------------" >> ${TEST_OUTPUT} build_type_lc=$(echo "${build_type}" | tr '[A-Z]' '[a-z]') # Make build_type all lower case - RUN_DIR=$TOP_DIR/scm/run_${compiler}_${build_type_lc} + RUN_DIR=$TOP_DIR/scm/run_${compiler}_${build_type_lc} batch_out=${job_prefix}_${compiler}_${build_type_lc}.o* # Without PID extension #----------------------------------------------------------------------- From 48e6fe882c42b6226f2dbb9f6e34643861182ac2 Mon Sep 17 00:00:00 2001 From: Dustin Swales Date: Thu, 25 Jul 2024 22:15:25 +0000 Subject: [PATCH 25/25] Bug fix in origraphical file extension --- scm/etc/scripts/UFS_case_gen.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/scm/etc/scripts/UFS_case_gen.py b/scm/etc/scripts/UFS_case_gen.py index 02aac678c..e2d189ee9 100755 --- a/scm/etc/scripts/UFS_case_gen.py +++ b/scm/etc/scripts/UFS_case_gen.py @@ -14,7 +14,6 @@ import fv3_remap import xesmf from datetime import datetime, timedelta -import matplotlib.pyplot as plt ############################################################################### # Global settings # @@ -1693,7 +1692,7 @@ def get_UFS_oro_data(dir, tile, i, j, lam): if lam: nc_file = Dataset('{0}/{1}'.format(dir,'oro_data.nc')) else: - filename_pattern = 'oro*.tile{0}.nc'.format(tile) + filename_pattern = 'oro_data.tile{0}.nc'.format(tile) for f_name in os.listdir(dir): if fnmatch.fnmatch(f_name, filename_pattern): filename = f_name