cesm_hawc.waccm¶
Read CESM2/WACCM history files and extract atmospheric columns.
Columns are interpolated onto a regular altitude grid, with the MAM4 accumulation and coarse sulfate modes described by lognormal number and median radius. Tested with the BWSSP245 and TSMLT compsets (MAM4 aerosol). The history file needs:
T,Q,PS,hyam,hybm: required;O3,NO2,H2O,SO2: gas mixing ratios [mol/mol];so4_a1,so4_a3: dry sulfate mass mixing ratios [kg/kg];num_a1,num_a3: aerosol number mixing ratios [#/kg];dgnumwet1,dgnumwet3: wet median diameters [m], giving the median radius including water uptake. Without them the radius is derived from dry sulfate mass (seemam4_lognormal()), which ignores water.
Attributes¶
MAM4_SIGMA(dict) — Geometric standard deviation of each MAM4 mode for WACCM stratospheric sulfate (Mills et al., 2016): 1.6 fora1anda2, 1.2 fora3.RHO_SULFATE(float) — Particle density [kg m⁻³] used to derive a median radius from dry sulfate mass when a file has no wet diameters.REQUIRED_VARS(set of str) — Variables without whichWACCMAtmosphereraisesValueError.RECOMMENDED_VARS(list of str) — VariablesWACCMAtmospherewarns about when missing. Missing gases are treated as zero, and a missing sulfate mode as having no particles.
hybrid_to_pressure¶
def hybrid_to_pressure(
hyam: np.ndarray,
hybm: np.ndarray,
p0: float,
ps: float,
) -> np.ndarrayPressure on hybrid sigma-pressure levels.
Parameters¶
hyam,hybm(numpy.ndarray) — Hybrid A and B coefficients at level midpoints.p0(float) — Reference pressure [Pa].ps(float) — Surface pressure [Pa].
Returns¶
numpy.ndarray — Pressure [Pa],
hyam * p0 + hybm * ps.
pressure_to_altitude¶
def pressure_to_altitude(
pressure: np.ndarray,
temperature: np.ndarray,
ps: float,
z_surface: float = 0.0,
) -> np.ndarrayHeight of each model level by hydrostatic integration.
Parameters¶
pressure(numpy.ndarray) — Pressure on model levels [Pa], in either vertical order.temperature(numpy.ndarray) — Temperature on model levels [K]; pass virtual temperature to account for humidity.ps(float) — Surface pressure [Pa].z_surface(float, optional) — Height of the surface [m]. Default 0.
Returns¶
numpy.ndarray — Height of each level [m], in the same order as
pressure.
Notes¶
Integrates the hypsometric equation layer by layer from the surface.
Interface pressures are the geometric means of adjacent levels, with
ps at the bottom and half the top level’s pressure at the top. Each
level sits at the midpoint of its layer. Gravity is the constant
standard value, so the result is geopotential height, slightly below
geometric altitude in the stratosphere (about 140 m at 30 km).
blend_h2o¶
def blend_h2o(
q_vmr: np.ndarray,
chem_h2o: np.ndarray,
pressure: np.ndarray,
join_pa: float = 10000.0,
) -> np.ndarrayBlend tropospheric humidity with stratospheric chemistry water vapour.
Parameters¶
q_vmr(numpy.ndarray) — Water vapour from the dynamics humidityQ[mol/mol].chem_h2o(numpy.ndarray) — Water vapour from the chemistry tracerH2O[mol/mol].pressure(numpy.ndarray) — Pressure on the same levels [Pa].join_pa(float, optional) — Centre of the transition [Pa]. Default 10000 (100 hPa, near the tropopause).
Returns¶
numpy.ndarray — Blended water vapour [mol/mol]:
q_vmrbelow the transition,chem_h2oabove, with a cosine taper one decade wide in log pressure.
mam4_lognormal¶
def mam4_lognormal(
so4_mmr: np.ndarray,
num_per_kg: np.ndarray,
n_air_cm3: np.ndarray,
sigma_g: float,
) -> tuple[np.ndarray, np.ndarray]Lognormal median radius and number from MAM4 mixing ratios.
Parameters¶
so4_mmr(numpy.ndarray) — Dry sulfate mass mixing ratio [kg/kg].num_per_kg(numpy.ndarray) — Number mixing ratio [#/kg].n_air_cm3(numpy.ndarray) — Air number density [cm⁻³].sigma_g(float) — Geometric standard deviation of the mode.
Returns¶
r_um(numpy.ndarray) — Lognormal median radius [μm], floored at 1 nm.N_cm3(numpy.ndarray) — Number concentration [cm⁻³], floored at 1 m⁻³.
Notes¶
Inverts the lognormal mass moment
M = N (4/3) π ρ r_m³ exp(4.5 ln²σ_g) with ρ =
RHO_SULFATE. The number concentration does not depend on ρ.
The radius is a dry-mass radius: it ignores water taken up by the
particles, so WACCMAtmosphere uses it only when the file has no
wet diameters.
WACCMAtmosphere¶
class WACCMAtmosphere(
filepath,
alt_grid_km=None,
z_surface=0.0,
h2o_join_hpa=100.0,
)A CESM2/WACCM history file, from which columns are extracted.
Parameters¶
filepath(str or list of str) — CAM history file, or several files to open as one dataset. Any stream (h0, h2, ...).alt_grid_km(array-like, optional) — Output altitude grid [km]. Default 0–65 km every 1 km.z_surface(float, optional) — Surface height [m] used in the hydrostatic integration. Default 0, so heights are relative to the local surface.h2o_join_hpa(float, optional) — Pressure [hPa] at which humidityQblends into chemistryH2O. Default 100.
Raises¶
ValueError— If any ofREQUIRED_VARSis missing. MissingRECOMMENDED_VARSonly produce a warning.
Attributes¶
ds(xarray.Dataset) — The opened history file(s).alt_grid_m(numpy.ndarray) — Output altitude grid [m].
Examples¶
>>> atm = WACCMAtmosphere("run.cam.h0.2035-02.nc")
>>> profiles = atm.get_column_profiles(lat=30.6, lon=180.0, time_index=0)
>>> burden = atm.sulfate_column_burden(lat=30.6, lon=180.0)WACCMAtmosphere.get_column_profiles¶
def get_column_profiles(lat: float, lon: float, time_index: int = 0) -> dictExtract one column and interpolate it onto the altitude grid.
Parameters¶
lat(float) — Latitude [degrees]; the nearest grid column is used.lon(float) — Longitude [degrees], −180–180 or 0–360; the nearest grid column is used.time_index(int, optional) — Time slice within the file. Default 0.
Returns¶
dict — Arrays on
alt_grid_munless noted:altitudes_m[m]: the altitude grid;pressure_pa[Pa];temperature_k[K];specific_humidity[kg/kg];vmr_o3,vmr_no2,vmr_so2[mol/mol]: zero if the variable is missing;vmr_h2o[mol/mol]: blended fromQandH2O(seeblend_h2o());n_air_cm3[cm⁻³]: air number density;sulfate_a1_N_cm3,sulfate_a3_N_cm3[cm⁻³]: accumulation and coarse mode number;sulfate_a1_r_um,sulfate_a3_r_um[μm]: accumulation and coarse mode wet median radius (see Notes);sulfate_a1_dry_mass_kg_m3,sulfate_a3_dry_mass_kg_m3[kg m⁻³]: dry sulfate mass concentration;sulfate_a1_sigma,sulfate_a3_sigma(float): each mode’s geometric standard deviation;sulfate_a1_radius_source,sulfate_a3_radius_source(str):"wet_diameter"or"dry_mass"(see Notes).
Notes¶
Longitudes are converted to 0–360, matching the CAM grid, before the nearest column is selected. Pressure, mixing ratios, air density, aerosol number and mass are interpolated in log space.
Each mode’s median radius is half its wet median diameter
(dgnumwet1, dgnumwet3) when the file has it. Otherwise it is
derived from dry sulfate mass and number with mam4_lognormal(),
which ignores water uptake and so underestimates the wet radius the
optical calculations assume.
WACCMAtmosphere.sulfate_column_burden¶
def sulfate_column_burden(
lat: float,
lon: float,
time_index: int = 0,
alt_range_km: tuple = (15.0, 35.0),
) -> dictSulfate column burden and peak properties over an altitude range.
Parameters¶
lat,lon(float) — Column location [degrees].time_index(int, optional) — Time slice within the file. Default 0.alt_range_km(tuple of float, optional) — Lower and upper altitude bounds [km]. Default (15, 35).
Returns¶
dict — -
burden_mg_m2[mg m⁻²]: dry sulfate burden of both modes;N_column_cm2[cm⁻²]: number column;peak_alt_km[km]: altitude of the peak number concentration;peak_r_um[μm]: dominant mode’s median radius at the peak;dominant_mode(str):"a1"or"a3", whichever has more particles at the peak;"none"if no grid level is in range.
WACCMAtmosphere.extract_cesm_extinction¶
def extract_cesm_extinction(
lat: float,
lon: float,
time_index: int,
alt_m: np.ndarray,
varnames: tuple = ('EXTINCTdn', 'EXTINCTUVdn', 'EXTINCTNIRdn'),
) -> dictCESM’s own aerosol extinction for a column, if the file has it.
CESM computes EXTINCTdn (550 nm), EXTINCTUVdn (350 nm) and
EXTINCTNIRdn (1020 nm) during the model run, over all aerosol
species. They give an independent check on the extinction cesm-hawc
computes from number and radius; 1020 nm is also an ALI wavelength.
Parameters¶
lat,lon(float) — Column location [degrees].time_index(int) — Time slice within the file.alt_m(numpy.ndarray) — Altitude grid [m] to interpolate onto.varnames(tuple of str, optional) — Variables to extract. Default the three above.
Returns¶
dict of str to numpy.ndarray — Extinction [m⁻¹] on
alt_mfor each ofvarnamespresent in the file; missing ones are left out. Zero outside the model’s altitude range.
WACCMAtmosphere.save_column_profiles¶
def save_column_profiles(
lat: float,
lon: float,
output_path: str,
time_index: int = 0,
) -> NoneSave one column’s profiles to a NetCDF file.
For a simulator-ready file, use
cesm_hawc.save_inputs.save_column_inputs() instead.
Parameters¶
lat,lon(float) — Column location [degrees].output_path(str) — NetCDF file to write.time_index(int, optional) — Time slice within the file. Default 0.
WACCMAtmosphere.list_variables¶
def list_variables() -> list[str]Print the chemistry and aerosol variables in the file.
Marks the variables cesm-hawc relies on and lists any of them that are missing.
Returns¶
list of str — The known chemistry and aerosol variables present.