def mean_vertical_eddy_flux(cubelist, quantity, weight_by_density=True, coord=UM_HGT): vf = spatial(vertical_eddy_flux(cubelist, quantity, w_dens=True), "mean") if weight_by_density: weight_by = spatial(cubelist.extract_strict("air_density"), "mean") else: weight_by = None mean_vf = vertical_mean(vf, coord=coord, weight_by=weight_by) return mean_vf
def mean_dry_lapse_rate(cubelist, coord=UM_HGT): temp = cubelist.extract_strict("air_temperature") rho = cubelist.extract_strict("air_density") temp = spatial(temp, "mean") rho = spatial(rho, "mean") dtdz = differentiate(temp, coord) dtdz = dtdz.interpolate([(coord, rho.coord(coord).points)], iris.analysis.Linear()) res = vertical_mean(dtdz, coord=coord, weight_by=rho) return res
def vertical_eddy_flux(cubelist, quantity, w_dens=True): """Vertical flux.""" w = cubelist.extract_strict("upward_air_velocity") q = cubelist.extract_strict(quantity) w_eddy = w - spatial(w, "mean") q_eddy = q - spatial(q, "mean") vf = w_eddy * q_eddy if w_dens: vf *= cubelist.extract_strict("air_density") vf.rename(f"vertical_flux_of_{quantity}") return vf
def nondim_rossby_deformation_radius(cubelist, const=None, method="direct"): r""" Estimate the non-dimensional Rossby radius of deformation. Parameters ---------- cubelist: iris.cube.CubeList Input cubelist. const: aeolus.const.const.ConstContainer, optional If not given, constants are attempted to be retrieved from attributes of a cube in the cube list. method: str, optional Method of calculation. "direct" (default): estimate scale height and BV frequency from air temperature. "leconte2013": use isothermal approximation. Returns ------- iris.cube.Cube Cube with collapsed spatial dimensions. References ---------- * Leconte et al. (2013), https://doi.org/10.1051/0004-6361/201321042 (for `method=leconte2013`) .. math:: \lambda_{Rossby} = \sqrt{\frac{NH}{2\Omega R_p}} \approx \sqrt{\frac{R}{c_p^{1/2}} \frac{T^{1/2}}{2\Omega R_p}} """ if const is None: const = cubelist[0].attributes["planet_conf"] omega = (const.day / (2 * np.pi)) ** (-1) double_omega_radius = ScalarCube.from_cube(2 * omega * const.radius) if method == "direct": rho = cubelist.extract_strict("air_density").copy() bv_freq_proxy = spatial(vertical_mean(bv_freq_sq(cubelist), weight_by=rho), "mean") ** 0.5 temp_proxy = spatial( vertical_mean(cubelist.extract_strict("air_temperature"), weight_by=rho), "mean" ) scale_height = const.dry_air_gas_constant.asc * temp_proxy / const.gravity.asc nondim_rossby = (bv_freq_proxy * scale_height / double_omega_radius.asc) ** 0.5 elif method == "leconte2013": temp_proxy = toa_eff_temp(cubelist) _const_term = ScalarCube.from_cube(const.dry_air_gas_constant / double_omega_radius) sqrt_t_over_cp = (temp_proxy / const.dry_air_spec_heat_press.asc) ** 0.5 nondim_rossby = (sqrt_t_over_cp * _const_term.asc) ** 0.5 nondim_rossby.convert_units("1") nondim_rossby.rename("nondimensional_rossby_deformation_radius") return nondim_rossby
def mse_hdiv_mean(cubelist, zcoord=UM_HGT): rho = cubelist.extract_strict("air_density") ensure_bounds(rho, [zcoord]) u = cubelist.extract_strict("x_wind") ensure_bounds(u, [zcoord]) v = cubelist.extract_strict("y_wind") ensure_bounds(v, [zcoord]) mse_cmpnts = moist_static_energy(cubelist) mse_hdiv_cmpnts = {} for key, cmpnt in mse_cmpnts.items(): ensure_bounds(cmpnt, [zcoord]) flux_x = u * cmpnt flux_x.rename(f"eastward_{cmpnt.name()}_flux") flux_y = v * cmpnt flux_y.rename(f"northward_{cmpnt.name()}_flux") fluxes_vec = iris.cube.CubeList([flux_x, flux_y]) flux_div = hdiv(fluxes_vec, *[i.name() for i in fluxes_vec]) flux_div_vmean = integrate(rho * flux_div, zcoord) flux_div_mean = spatial(flux_div_vmean, "mean") try: flux_div_mean = flux_div_mean.collapsed(UM_TIME, iris.analysis.MEAN) except iris.exceptions.CoordinateCollapseError: pass flux_div_mean.rename(f"integrated_horizontal_divergence_of_{cmpnt.name()}") flux_div_mean.convert_units("W m^-2") mse_hdiv_cmpnts[key] = flux_div_mean return mse_hdiv_cmpnts
def _wspd_typical(cubelist, aggr="mean"): u = cubelist.extract_strict("x_wind") v = cubelist.extract_strict("y_wind") return spatial((u ** 2 + v ** 2) ** 0.5, aggr)
def wspd_typical(cubelist, aggr="median"): u = cubelist.extract_strict("x_wind") v = cubelist.extract_strict("y_wind") return spatial((u ** 2 + v ** 2) ** 0.5, aggr).collapsed( [UM_TIME, UM_HGT], getattr(iris.analysis, aggr.upper()) )
MODEL_TIMESTEP = 86400 / 72 FILE_REGEX = r"umglaa.p[a-z]{1}[0]{6}(?P<timestamp>[0-9]{2,4})_00" ONLY_GLOBAL = ["eta", "b_alb", "t_sfc_diff_dn", "nondim_rossby", "nondim_rhines"] ONLY_LAM = ["hflux_q", "hflux_t"] DIAGS = { "mse_hdiv": lambda cl: mse_hdiv_mean(cl)["mse"], "dse_hdiv": lambda cl: mse_hdiv_mean(cl)["dse"], "lse_hdiv": lambda cl: mse_hdiv_mean(cl)["lse"], "nondim_rossby": lambda cl: nondim_rossby_deformation_radius(cl), "nondim_rhines": lambda cl: nondim_rhines_number(cl.extract(hgt_cnstr_5_20km)), "e_net_toa": toa_net_energy, "eta": lambda cl: heat_redist_eff(cl, NIGHTSIDE, DAYSIDE), "b_alb": bond_albedo, "toa_olr": lambda cl: spatial(cl.extract_strict("toa_outgoing_longwave_flux"), "mean"), "toa_osr": lambda cl: spatial(cl.extract_strict("toa_outgoing_shortwave_flux"), "mean"), "cre_sw": lambda cl: toa_cloud_radiative_effect(cl, kind="sw"), "cre_lw": lambda cl: toa_cloud_radiative_effect(cl, kind="lw"), "cre_tot": lambda cl: toa_cloud_radiative_effect(cl, kind="total"), "gh_norm": ghe_norm, "e_net_sfc": sfc_net_energy, "t_sfc_diff_dn": lambda cl: region_mean_diff(cl, "surface_temperature", DAYSIDE, NIGHTSIDE), "t_sfc": lambda cl: spatial(cl.extract_strict("surface_temperature"), "mean"), "t_sfc_min": lambda cl: spatial(cl.extract_strict("surface_temperature"), "min"), "t_sfc_max": lambda cl: spatial(cl.extract_strict("surface_temperature"), "max"), "t_sfc_extremes": lambda cl: minmaxdiff(cl, name="surface_temperature"), "t_eff": toa_eff_temp, "wspd_rms": lambda cl: wspd_typical(cl, "rms"), "wspd_rms_0_15km": lambda cl: wspd_typical(cl.extract(hgt_cnstr_0_15km), "rms"), "wspd_mean": lambda cl: wspd_typical(cl, "mean"),
def main(): """Main function.""" # Create a subdirectory for processed data outdir = mypaths.nsdir / "_processed" outdir.mkdir(parents=True, exist_ok=True) for planet in PLANET_ALIASES.keys(): L.info(f"planet = {planet}") for run_key in NS_RUN_ALIASES.keys(): L.info(f"run_key = {run_key}") subdir = f"{planet}_{run_key}" for model_type, model_specs in NS_MODEL_TYPES.items(): L.info(f"model_type = {model_type}") label = f"{planet}_{run_key}_{model_type}" tmp_cl = iris.cube.CubeList() for i in range(NS_CYCLE_TIMES[subdir]["ndays"]): _cycle = (NS_CYCLE_TIMES[subdir]["start"] + timedelta(days=i)).strftime(DT_FMT) L.info(f"_cycle = {_cycle}") fpath = (mypaths.nsdir / subdir / _cycle / model_specs["path"].parent / "_processed" / f"{label}_{_cycle}.nc") L.info(f"fpath = {fpath}") # Initialise a `Run` by loading processed data run = Run( files=fpath, name=label, planet=planet, model_type=model_type, timestep=model_specs["timestep"], processed=True, ) # Derive additional fields run.add_data(calc_derived_cubes) for cube in run.proc.extract(DIM_CONSTR_ZYX): L.info(f"cube = {cube.name()}") ave_cube = spatial(cube.extract(SS_REGION.constraint), "mean") tmp_cl.append(ave_cube) for cube in tmp_cl: try: cube.attributes.pop("planet_conf") except KeyError: pass tmp_cl = tmp_cl.merge() L.debug(f"merged cubelist = {tmp_cl}") _dict = {} for cube in tmp_cl: # cube.attributes = { # k: v for k, v in cube.attributes.items() if k != "planet_conf" # } _dict[cube.name()] = xr.DataArray.from_iris(cube) ds = xr.merge([_dict], compat="override") L.debug(f"dataset = {ds}") ds.attrs.update( { "region": SS_REGION.to_str(), "model_type": run.model_type, "run_key": run_key, "planet": planet, }, ) fname_out = outdir / f"ns_area_mean_vprof_{run.name}.nc" ds.to_netcdf(fname_out) L.success(f"Saved to {fname_out}")