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')