예제 #1
0
    def test_at_t_0(spectral_sampling, plot=False):
        # Arrange
        settings = Settings(n_sd=64, dt=1 * si.s, n_substep=1, spectral_sampling=spectral_sampling)
        settings.t_max = 0
        simulation = Simulation(settings)

        # Act
        output = simulation.run()

        # Plot
        if plot:
            from matplotlib import pyplot
            pyplot.step(
                2e6 * settings.dry_radius_bins_edges[:-1],
                output['dm_S_VI/dlog_10(dry diameter)'][-1]
            )
            pyplot.ylabel('dS(VI)/dlog_10(D)')
            pyplot.xlabel('dry diameter [µm]')
            pyplot.xscale('log')
            pyplot.yscale('log')
            pyplot.ylim([.01, 12])
            pyplot.show()

        # Assert
        key = 'S_VI'
        spectrum = output[f'dm_{key}/dlog_10(dry diameter)'][0][0]
        peaks, props = find_peaks(spectrum)
        assert len(peaks) == 1
        assert 3 < np.amax(spectrum) < 5
예제 #2
0
    def test_at_cloud_base():
        # Arrange
        settings = Settings(n_sd=50, dt=1 * si.s, n_substep=5)
        settings.t_max = 196 * si.s
        settings.output_interval = settings.dt
        simulation = Simulation(settings)

        # Act
        output = simulation.run()

        # Assert
        assert round(output['z'][-1]) == (698 - 600) * si.m
        np.testing.assert_allclose(output['p_env'][-1],
                                   939 * si.mbar,
                                   rtol=.005)
        np.testing.assert_allclose(output['T_env'][-1],
                                   284.2 * si.K,
                                   rtol=.005)
        np.testing.assert_allclose(
            settings.formulae.state_variable_triplet.rho_of_rhod_qv(
                rhod=output['rhod_env'][-1],
                qv=output['qv_env'][-1] * si.g / si.kg),
            1.15 * si.kg / si.m**3,
            rtol=.005)
        assert output['ql'][-2] < .00055
        assert output['ql'][-1] > .0004
        assert output['RH_env'][-1] > 100
        assert output['RH_env'][-8] < 100
예제 #3
0
    def test_at_t_0(spectral_sampling, plot=False):
        # Arrange
        settings = Settings(n_sd=64,
                            dt=1 * si.s,
                            n_substep=5,
                            spectral_sampling=spectral_sampling)
        settings.t_max = 0
        simulation = Simulation(settings)

        # Act
        output = simulation.run()

        # Plot
        if plot:
            from matplotlib import pyplot
            pyplot.step(2e6 * settings.dry_radius_bins_edges[:-1],
                        output['dm_S_VI/dlog_10(dry diameter)'][-1])
            pyplot.ylabel('dS(VI)/dlog_10(D)')
            pyplot.xlabel('dry diameter [µm]')
            pyplot.xscale('log')
            pyplot.yscale('log')
            pyplot.ylim([.01, 12])
            pyplot.show()

        # Assert
        key = 'S_VI'
        # TODO #481 : better than >0 (we do have analytic formula)
        assert (output[f'dm_{key}/dlog_10(dry diameter)'][0] > 0).any()
예제 #4
0
    def test_at_t_0():
        # Arrange
        settings = Settings(n_sd=100, dt=1 * si.s, n_substep=5)
        settings.t_max = 0
        simulation = Simulation(settings)
        specific_gravities = SpecificGravities(
            simulation.particulator.formulae.constants)

        # Act
        output = simulation.run()

        # Assert
        np.testing.assert_allclose(output['RH'][0], 95)
        np.testing.assert_allclose(output['gas_S_IV_ppb'][0], 0.2)
        np.testing.assert_allclose(output['gas_N_mIII_ppb'][0], 0.1)
        np.testing.assert_allclose(output['gas_H2O2_ppb'], 0.5)
        np.testing.assert_allclose(output['gas_N_V_ppb'], 0.1)
        np.testing.assert_allclose(output['gas_O3_ppb'], 50)
        np.testing.assert_allclose(output['gas_C_IV_ppb'], 360 * 1000)

        rtol = 0.15

        mass_conc_SO4mm = 2
        mass_conc_NH4p = 0.375
        num_conc_SO4mm = mass_conc_SO4mm / Substance.from_formula(
            "SO4").mass * si.gram / si.mole
        num_conc_NH4p = mass_conc_NH4p / Substance.from_formula(
            "NH4").mass * si.gram / si.mole
        np.testing.assert_allclose(num_conc_NH4p, num_conc_SO4mm, rtol=.005)
        mass_conc_H = num_conc_NH4p * Substance.from_formula(
            "H").mass * si.gram / si.mole
        np.testing.assert_allclose(
            actual=np.asarray(output['q_dry']) * np.asarray(output['rhod']),
            desired=mass_conc_NH4p + mass_conc_SO4mm + mass_conc_H,
            rtol=rtol)

        expected = {k: 0 for k in AQUEOUS_COMPOUNDS}
        expected['S_VI'] = mass_conc_SO4mm * si.ug / si.m**3
        expected['N_mIII'] = mass_conc_NH4p * si.ug / si.m**3

        for key in expected:
            mole_fraction = np.asarray(output[f"aq_{key}_ppb"])
            convert_to(mole_fraction, 1 / PPB)
            compound = AQUEOUS_COMPOUNDS[key][0]  # sic!
            np.testing.assert_allclose(
                actual=(settings.formulae.trivia.mole_fraction_2_mixing_ratio(
                    mole_fraction,
                    specific_gravity=specific_gravities[compound]) *
                        np.asarray(output['rhod'])),
                desired=expected[key],
                rtol=rtol)
예제 #5
0
    def test_at_1200m_above_cloud_base():
        # Arrange
        settings = Settings(n_sd=10, dt=1 * si.s, n_substep=5)
        simulation = Simulation(settings)

        # Act
        output = simulation.run()

        # Assert
        np.testing.assert_allclose(output['z'][-1], (1.2 + .1) * si.km,
                                   rtol=.005)
        np.testing.assert_allclose(output['ql'][-1], 2.17, rtol=.02)
예제 #6
0
def example_output():
    settings = Settings(n_sd=16, dt=1 * si.s, n_substep=5)
    simulation = Simulation(settings)
    output = simulation.run()
    return output
예제 #7
0
def test_calc_ionic_strength(nt, n_sd):
    formulae = Formulae()
    const = formulae.constants
    EQUILIBRIUM_CONST = EquilibriumConsts(formulae).EQUILIBRIUM_CONST

    K = _K(NH3=EQUILIBRIUM_CONST["K_NH3"].at(const.ROOM_TEMP),
           SO2=EQUILIBRIUM_CONST["K_SO2"].at(const.ROOM_TEMP),
           HSO3=EQUILIBRIUM_CONST["K_HSO3"].at(const.ROOM_TEMP),
           HSO4=EQUILIBRIUM_CONST["K_HSO4"].at(const.ROOM_TEMP),
           HCO3=EQUILIBRIUM_CONST["K_HCO3"].at(const.ROOM_TEMP),
           CO2=EQUILIBRIUM_CONST["K_CO2"].at(const.ROOM_TEMP),
           HNO3=EQUILIBRIUM_CONST["K_HNO3"].at(const.ROOM_TEMP))

    settings = Settings(dt=1, n_sd=n_sd, n_substep=5)
    settings.t_max = nt * settings.dt
    simulation = Simulation(settings)

    simulation.run()

    H = simulation.particulator.attributes['conc_N_mIII'].data
    conc = {
        'H+': H,
        'N-3': simulation.particulator.attributes['conc_N_mIII'].data,
        'N+5': simulation.particulator.attributes['conc_N_V'].data,
        'S+4': simulation.particulator.attributes['conc_S_IV'].data,
        'S+6': simulation.particulator.attributes['conc_S_VI'].data,
        'C+4': simulation.particulator.attributes['conc_C_IV'].data,
    }

    alpha_C = (1 + K.CO2 / conc['H+'] + K.CO2 * K.HCO3 / conc['H+']**2)
    alpha_S = (1 + K.SO2 / conc['H+'] + K.SO2 * K.HSO3 / conc['H+']**2)
    alpha_N3 = (1 + conc['H+'] * K.NH3 / K_H2O)
    alpha_N5 = (1 + K.HNO3 / conc['H+'])

    actual = calc_ionic_strength(H=conc['H+'],
                                 conc=_conc(
                                     N_mIII=conc['N-3'],
                                     N_V=conc['N+5'],
                                     C_IV=conc['C+4'],
                                     S_IV=conc['S+4'],
                                     S_VI=conc['S+6'],
                                 ),
                                 K=K)

    expected = ionic_strength(
        {
            'H+':
            conc['H+'] / const.rho_w,
            'HCO3-':
            K.CO2 / conc['H+'] * conc['C+4'] / alpha_C / const.rho_w,
            'CO3-2':
            K.CO2 / conc['H+'] * K.HCO3 / conc['H+'] * conc['C+4'] / alpha_C /
            const.rho_w,
            'HSO3-':
            K.SO2 / conc['H+'] * conc['S+4'] / alpha_S / const.rho_w,
            'SO3-2':
            K.SO2 / conc['H+'] * K.HSO3 / conc['H+'] * conc['S+4'] / alpha_S /
            const.rho_w,
            'NH4+':
            K.NH3 / K_H2O * conc['H+'] * conc['N-3'] / alpha_N3 / const.rho_w,
            'NO3-':
            K.HNO3 / conc['H+'] * conc['N+5'] / alpha_N5 / const.rho_w,
            'HSO4-':
            conc['H+'] * conc['S+6'] / (conc['H+'] + K.HSO4) / const.rho_w,
            'SO4-2':
            K.HSO4 * conc['S+6'] / (conc['H+'] + K.HSO4) / const.rho_w,
            'OH-':
            K_H2O / conc['H+'] / const.rho_w
        },
        warn=False) * const.rho_w

    np.testing.assert_allclose(actual, expected, rtol=1e-15)
예제 #8
0
def test_calc_ionic_strength(nt, n_sd):
    formulae = Formulae()
    EQUILIBRIUM_CONST = EquilibriumConsts(formulae).EQUILIBRIUM_CONST

    K_NH3 = EQUILIBRIUM_CONST["K_NH3"].at(ROOM_TEMP)
    K_SO2 = EQUILIBRIUM_CONST["K_SO2"].at(ROOM_TEMP)
    K_HSO3 = EQUILIBRIUM_CONST["K_HSO3"].at(ROOM_TEMP)
    K_HSO4 = EQUILIBRIUM_CONST["K_HSO4"].at(ROOM_TEMP)
    K_HCO3 = EQUILIBRIUM_CONST["K_HCO3"].at(ROOM_TEMP)
    K_CO2 = EQUILIBRIUM_CONST["K_CO2"].at(ROOM_TEMP)
    K_HNO3 = EQUILIBRIUM_CONST["K_HNO3"].at(ROOM_TEMP)

    settings = Settings(dt=1, n_sd=n_sd, n_substep=5)
    settings.t_max = nt * settings.dt
    simulation = Simulation(settings)

    simulation.run()

    H = simulation.core.particles['conc_N_mIII'].data
    conc = {
        'H+': H,
        'N-3': simulation.core.particles['conc_N_mIII'].data,
        'N+5': simulation.core.particles['conc_N_V'].data,
        'S+4': simulation.core.particles['conc_S_IV'].data,
        'S+6': simulation.core.particles['conc_S_VI'].data,
        'C+4': simulation.core.particles['conc_C_IV'].data,
    }

    alpha_C = (1 + K_CO2 / conc['H+'] + K_CO2 * K_HCO3 / conc['H+']**2)
    alpha_S = (1 + K_SO2 / conc['H+'] + K_SO2 * K_HSO3 / conc['H+']**2)
    alpha_N3 = (1 + conc['H+'] * K_NH3 / K_H2O)
    alpha_N5 = (1 + K_HNO3 / conc['H+'])

    actual = calc_ionic_strength(H=conc['H+'],
                                 N_mIII=conc['N-3'],
                                 N_V=conc['N+5'],
                                 C_IV=conc['C+4'],
                                 S_IV=conc['S+4'],
                                 S_VI=conc['S+6'],
                                 K_NH3=K_NH3,
                                 K_SO2=K_SO2,
                                 K_HSO3=K_HSO3,
                                 K_HSO4=K_HSO4,
                                 K_HCO3=K_HCO3,
                                 K_CO2=K_CO2,
                                 K_HNO3=K_HNO3)

    expected = ionic_strength(
        {
            'H+':
            conc['H+'] / rho_w,
            'HCO3-':
            K_CO2 / conc['H+'] * conc['C+4'] / alpha_C / rho_w,
            'CO3-2':
            K_CO2 / conc['H+'] * K_HCO3 / conc['H+'] * conc['C+4'] / alpha_C /
            rho_w,
            'HSO3-':
            K_SO2 / conc['H+'] * conc['S+4'] / alpha_S / rho_w,
            'SO3-2':
            K_SO2 / conc['H+'] * K_HSO3 / conc['H+'] * conc['S+4'] / alpha_S /
            rho_w,
            'NH4+':
            K_NH3 / K_H2O * conc['H+'] * conc['N-3'] / alpha_N3 / rho_w,
            'NO3-':
            K_HNO3 / conc['H+'] * conc['N+5'] / alpha_N5 / rho_w,
            'HSO4-':
            conc['H+'] * conc['S+6'] / (conc['H+'] + K_HSO4) / rho_w,
            'SO4-2':
            K_HSO4 * conc['S+6'] / (conc['H+'] + K_HSO4) / rho_w,
            'OH-':
            K_H2O / conc['H+'] / rho_w
        },
        warn=False) * rho_w

    np.testing.assert_allclose(actual, expected, rtol=1e-15)
예제 #9
0
    def test_calc_ionic_strength(nt, n_sd):
        from chempy.electrolytes import ionic_strength
        from PySDM_examples.Kreidenweis_et_al_2003 import Settings, Simulation
        from PySDM.backends.numba.impl._chemistry_methods import calc_ionic_strength
        from PySDM.physics.constants import rho_w, ROOM_TEMP

        K_NH3 = EQUILIBRIUM_CONST["K_NH3"].at(ROOM_TEMP)
        K_SO2 = EQUILIBRIUM_CONST["K_SO2"].at(ROOM_TEMP)
        K_HSO3 = EQUILIBRIUM_CONST["K_HSO3"].at(ROOM_TEMP)
        K_HSO4 = EQUILIBRIUM_CONST["K_HSO4"].at(ROOM_TEMP)
        K_HCO3 = EQUILIBRIUM_CONST["K_HCO3"].at(ROOM_TEMP)
        K_CO2 = EQUILIBRIUM_CONST["K_CO2"].at(ROOM_TEMP)
        K_HNO3 = EQUILIBRIUM_CONST["K_HNO3"].at(ROOM_TEMP)

        settings = Settings(dt=1, n_sd=n_sd, n_substep=5)
        settings.t_max = nt * settings.dt
        simulation = Simulation(settings)
        simulation.run()

        H = simulation.core.particles['conc_N_mIII'].data
        conc = {
            'H+': H,
            'N-3': simulation.core.particles['conc_N_mIII'].data,
            'N+5': simulation.core.particles['conc_N_V'].data,
            'S+4': simulation.core.particles['conc_S_IV'].data,
            'S+6': simulation.core.particles['conc_S_VI'].data,
            'C+4': simulation.core.particles['conc_C_IV'].data,
        }

        alpha_C = (1 + K_CO2 / conc['H+'] + K_CO2 * K_HCO3 / conc['H+']**2)
        alpha_S = (1 + K_SO2 / conc['H+'] + K_SO2 * K_HSO3 / conc['H+']**2)
        alpha_N3 = (1 + conc['H+'] * K_NH3 / K_H2O)
        alpha_N5 = (1 + K_HNO3 / conc['H+'])

        actual = calc_ionic_strength(H=conc['H+'],
                                     N_mIII=conc['N-3'],
                                     N_V=conc['N+5'],
                                     C_IV=conc['C+4'],
                                     S_IV=conc['S+4'],
                                     S_VI=conc['S+6'],
                                     K_NH3=K_NH3,
                                     K_SO2=K_SO2,
                                     K_HSO3=K_HSO3,
                                     K_HSO4=K_HSO4,
                                     K_HCO3=K_HCO3,
                                     K_CO2=K_CO2,
                                     K_HNO3=K_HNO3)

        expected = ionic_strength(
            {
                'H+':
                conc['H+'] / rho_w,
                'HCO3-':
                K_CO2 / conc['H+'] * conc['C+4'] / alpha_C / rho_w,
                'CO3-2':
                K_CO2 / conc['H+'] * K_HCO3 / conc['H+'] * conc['C+4'] /
                alpha_C / rho_w,
                'HSO3-':
                K_SO2 / conc['H+'] * conc['S+4'] / alpha_S / rho_w,
                'SO3-2':
                K_SO2 / conc['H+'] * K_HSO3 / conc['H+'] * conc['S+4'] /
                alpha_S / rho_w,
                'NH4+':
                K_NH3 / K_H2O * conc['H+'] * conc['N-3'] / alpha_N3 / rho_w,
                'NO3-':
                K_HNO3 / conc['H+'] * conc['N+5'] / alpha_N5 / rho_w,
                'HSO4-':
                conc['H+'] * conc['S+6'] / (conc['H+'] + K_HSO4) / rho_w,
                'SO4-2':
                K_HSO4 * conc['S+6'] / (conc['H+'] + K_HSO4) / rho_w,
                'OH-':
                K_H2O / conc['H+'] / rho_w
            },
            warn=False) * rho_w

        np.testing.assert_allclose(actual, expected, rtol=1e-15)