def h2o_pro(self, p, tp_pro_moist): ''' calculate the local partial pressure of H2O for a local pressure for a atmosphere with a (partial) moist adiabat inputs: * self * p [Pa] - local pressure * tp_pro_moist [function] - a function that calculates temperature as a function of pressure within a given atmosphere's moist adiabat output: * p_h2o [Pa] - local partial pressure H2O (from given pressure) ''' #dry adiabat if p >= self.p_transition_moist: p_h2o = p * self.f_h2o_surf #isothermal elif p <= self.p_transition_strat: p_h2o = p * self.f_h2o_strat #moist adiabat else: p_h2o = h2o.p_sat(tp_pro_moist(p)) return p_h2o
def calc_dlnpdlnT(self, dT, T, p, p_h2o_last): ''' calculate d ln p / d ln T for a moist adiabat following Wordsworth & Pierrehumbert 2013b inputs: * dT [K] - change in local temperature * T [K] - local temperature * p [Pa] - local pressure * ph2o_last [Pa] - local partial pressure of water at last T step outputs: * dlnpdlnT [ln(Pa)/ln(K)] - derivative to advance moist adiabat * ph2o [Pa] - local partial pressure of water ''' p_h2o = h2o.p_sat(T) p_nonc = p - p_h2o rho_h2o = p_h2o / h2o.R / T rho_h2o_last = p_h2o_last / h2o.R / (T - dT) rho_nonc = p_nonc / self.R_air_dry / T alpha = rho_h2o / rho_nonc dlnph2odlnT = 1. / dT * T * (np.log(p_h2o) - np.log(p_h2o_last)) dlnrhoh2odlnT = 1. / dT * T * (np.log(rho_h2o) - np.log(rho_h2o_last)) dlnalphadlnT = T * ((alpha + self.ep) / T - self.calc_c_p(T) / h2o.L(T)) / (alpha + self.R_air_dry * T / h2o.L(T)) dlnpdlnT = p_h2o / p * dlnph2odlnT + p_nonc / p * (1 + dlnrhoh2odlnT - dlnalphadlnT) return dlnpdlnT, p_h2o
def __init__(self, pl, RH_surf, delta_T=0.1): ''' constructor for Atm class initialize Atm object inputs: * pl [Planet object] - Planet object containing planetary properties * RH_surf [] - relative humidity at the surface * delta_T [K] - temperature step size for integrate moist adiabat, optional ''' self.planet = pl # Planet object containing planetary properties # set average dry molar mass self.planet.calc_mu_dry(gas_properties) self.RH_surf = RH_surf # [] relative humidity at the surface # set water mixing ratio at surface from prescribed RH and T_surf p_h2o_surf = self.RH_surf * h2o.p_sat(self.planet.T_surf) self.planet.p_surf = self.planet.p_surf_dry + p_h2o_surf self.f_h2o_surf = p_h2o_surf / self.planet.p_surf # [vmr] water mixing ratio at surface # specific gas constant for dry air self.R_air_dry = R_gas / self.planet.mu_dry # [J/kg/K] # specific gas constant for air with surface f_h2o self.R_air_surf = ( 1 - self.f_h2o_surf ) * self.R_air_dry + self.f_h2o_surf * h2o.R # [J/kg/K] # used in moist adiabat calculation self.ep = h2o.mu / self.planet.mu_dry # [] # calculate specific heat at surface # used for dry adiabat self.c_p_surf = self.calc_c_p(self.planet.T_surf, 1 - self.f_h2o_surf) # [J/kg/K] # calculate kappa for dry adiabat self.kappa = self.R_air_surf / self.c_p_surf # temperature step for moist adiabat calculation self.delta_T = delta_T # [K] # check if troposphere is too dry or oversaturated self.isdry = False self.issatsurf = False if T_transition_moist0(self.planet.T_strat, self.planet.p_surf, self.planet.T_surf, self.f_h2o_surf, self.kappa) <= 0: self.isdry = True if T_transition_moist0(self.planet.T_surf, self.planet.p_surf, self.planet.T_surf, self.f_h2o_surf, self.kappa) > 0: self.issatsurf = True self.standard_ps = np.zeros(150) self.tp_pro_vec = np.vectorize(self.tp_pro) self.h2o_pro_vec = np.vectorize(self.h2o_pro)
def p2RH(self, p): ''' calculate relative humidity of air (RH) at local pressure level inputs: * self * p [Pa] - local pressure output: * RH [] - local relative humiduty ''' p_sat_loc = h2o.p_sat(self.p2T(p)) RH = self.p2p_h2o(p) / p_sat_loc return RH
def T_transition_moist0(T, p_surf, T_surf, f_h2o, kappa): ''' calculate temperature at which RH = 1 and atmosphere transitions to a moist adiabat inputs: * T [K] - local temperature * p_surf [Pa] - surface pressure * T_surf [K] - surface temperature * f_h2o [] - mixing ratio of H2O at the surface * kappa [J/kg/K] - R_air/c_p_air output: * difference between local pH2O and saturated pH2O at local T [Pa] ''' return f_h2o * p_surf * (T / T_surf)**(1. / kappa) - h2o.p_sat(T)
# WATER CONTENT # vary RH at surface print('\t surface relative humidity') axarr[2,1].set_title(r'$\mathrm{RH}_{\mathrm{surf}}$') axarr[2,1].set_xlabel(r'$\mathrm{RH}_{\mathrm{surf}}$') RH_h2o_surfs = np.logspace(-5,0,n) N_S_f_h2os = np.zeros((n,2)) for i,RH in enumerate(RH_h2o_surfs): pl = Planet(1,T_earth,T_strat,p_surf_earth,X,1) atm = atm_pro.Atm(pl,RH) atm.set_up_atm_pro() S_test_aero = sulfur.Sulfur_Cycle(atm,'aero') S_test_gas = sulfur.Sulfur_Cycle(atm,'gas') N_S_f_h2os[i,0] = S_test_aero.N_S_atm N_S_f_h2os[i,1] = S_test_gas.N_S_atm f_h2o_surfs = RH_h2o_surfs*h2o.p_sat(T_earth)/p_surf_earth # [] f_h2o_surf_b = RH_earth*h2o.p_sat(T_earth)/p_surf_earth # [] axarr[2,1].plot(f_h2o_surfs,N_S_f_h2os[:,0]/N_S_base0,c='#ff8c00',label='aerosol') axarr[2,1].plot(f_h2o_surfs,N_S_f_h2os[:,1]/N_S_base1,c='#002fa7',label='gas') axarr[2,1].axvline(f_h2o_surf_b,ls='--',c='0.8',label='Earth-like value') axarr[2,1].set_xscale('log') # plot logistics plt.ylim(1e-2,1e2) plt.yscale('log') for i in range(3): for j in range(2): axarr[i,j].axhspan(0.01,0.1,color='r',alpha=0.85,label='< 10% ' r'$N^\ast_{\mathrm{S}}/N^\ast_{\mathrm{S,}\oplus}$') fig.subplots_adjust(hspace=0.5,wspace=0.05) handles, labels = axarr[2,1].get_legend_handles_labels()
def set_up_atm_pro(self): ''' set up atmospheric profile input: * self ''' # calculate T at which RH first exceeds 100% if self.isdry: self.p_transition_strat = self.planet.p_surf * ( self.planet.T_strat / self.planet.T_surf)**(1. / self.kappa ) #[Pa] self.p_transition_moist = 0 # [Pa] tp_pro_moist = None # set up pressure levels that will resolve different regions of the atmosphere well # dry adiabat self.standard_ps[:100] = np.logspace( np.log10(self.planet.p_surf), np.log10(self.p_transition_strat + 0.1), 100) # stratosphere self.standard_ps[100:] = np.logspace( np.log10(self.p_transition_strat), np.log10(self.p_transition_strat * 0.1), 50) else: if self.issatsurf: self.T_transition_moist = self.planet.T_surf # [K] self.p_transition_moist = self.planet.p_surf # [Pa] else: self.T_transition_moist = brentq( T_transition_moist0, self.planet.T_surf, self.planet.T_strat, args=(self.planet.p_surf, self.planet.T_surf, self.f_h2o_surf, self.kappa)) # convert T transition to a pseudo moist adiabat to a p self.p_transition_moist = self.planet.p_surf * ( self.T_transition_moist / self.planet.T_surf)**(1. / self.kappa) # integrate to get moist adiabat T_Tspaced, p_Tspaced = self.calc_moist() #calculate T for a given p in moist adiabat by interpolating from diff eq solution tp_pro_moist = interp1d(p_Tspaced, T_Tspaced, fill_value='extrapolate') # fill_value='extrapolate' used to ensure small rounds errors in # log conversions don't cause interpolation to fail tp_pro_moist_tofp = interp1d(T_Tspaced, p_Tspaced) # calculate pressure level at which stratosphere begins self.p_transition_strat = tp_pro_moist_tofp(self.planet.T_strat) # set up pressure levels that will resolve different regions of the atmosphere well # dry adiabat self.standard_ps[:50] = np.logspace( np.log10(self.planet.p_surf), np.log10(self.p_transition_moist + 0.1), 50) # moist adiabat self.standard_ps[50:100] = np.logspace( np.log10(self.p_transition_moist), np.log10(self.p_transition_strat + 0.1), 50) # stratosphere self.standard_ps[100:] = np.logspace( np.log10(self.p_transition_strat), np.log10(self.p_transition_strat * 0.1), 50) # calculate mixing ratio of water in stratosphere self.f_h2o_strat = h2o.p_sat( self.planet.T_strat) / self.p_transition_strat # calculate mixing ratio of dry gases in stratosphere self.f_dry_strat = 1 - self.f_h2o_strat # calculate temperatures associated with these standard pressure levels standard_Ts = self.tp_pro_vec(self.standard_ps, tp_pro_moist) # create interpolating function from these standard values to # be able to calculate T from any p easily self.p2T = interp1d(self.standard_ps, standard_Ts, fill_value='extrapolate') # calculate partial pressures of H2O associated with standard pressure levels standard_p_h2o = self.h2o_pro_vec(self.standard_ps, tp_pro_moist) # create interpolating function from these standard values to # be able to calculate p_h2o from any p easily self.p2p_h2o = interp1d(self.standard_ps, standard_p_h2o, fill_value='extrapolate')