def test_thd_initialisation(settings_idx):
     setup = setups[settings_idx]
     pv0 = setup.p0 / (1 + const.eps / setup.q0)
     pd0 = setup.p0 - pv0
     phys = Formulae().trivia
     thd0 = phys.th_std(pd0, setup.T0)
     TestInitialisation.simulation_test('thd', thd0, setup)
Esempio n. 2
0
    def get_displacement(self, backend, scheme):
        formulae = Formulae(particle_advection=scheme)
        particulator = DummyParticulator(backend,
                                         n_sd=len(self.n),
                                         formulae=formulae)
        particulator.environment = DummyEnvironment(
            dt=self.dt,
            grid=self.grid,
            courant_field_data=self.courant_field_data)
        positions = np.array(self.positions)
        cell_id, cell_origin, position_in_cell = particulator.mesh.cellular_attributes(
            positions)
        attributes = {
            'n': self.n,
            'volume': self.volume,
            'cell id': cell_id,
            'cell origin': cell_origin,
            'position in cell': position_in_cell
        }
        particulator.build(attributes)
        sut = Displacement(enable_sedimentation=self.sedimentation)
        sut.register(particulator)
        sut.upload_courant_field(self.courant_field_data)

        return sut, particulator
Esempio n. 3
0
    def __init__(self):
        self.formulae = Formulae()
        self.init_x_min = self.formulae.trivia.volume(radius=3.94 *
                                                      si.micrometre)
        self.init_x_max = self.formulae.trivia.volume(radius=25 *
                                                      si.micrometres)

        self.n_sd = 2**13
        self.n_part = 239 / si.cm**3
        self.X0 = self.formulae.trivia.volume(radius=10 * si.micrometres)
        self.dv = 1e1 * si.metres**3  # TODO #336 1e6 do not work with ThrustRTC (overflow?)
        self.norm_factor = self.n_part * self.dv
        self.rho = 1000 * si.kilogram / si.metre**3
        self.dt = 1 * si.seconds
        self.adaptive = False
        self.seed = 44
        self._steps = [200 * i for i in range(10)]
        self.kernel = coalescence_kernels.Geometric(collection_efficiency=1)
        self.spectrum = spectra.Exponential(norm_factor=self.norm_factor,
                                            scale=self.X0)

        # Note 220 instead of 200 for smoothing
        self.radius_bins_edges = np.logspace(np.log10(3.94 * si.um),
                                             np.log10(220 * si.um),
                                             num=100,
                                             endpoint=True)
Esempio n. 4
0
def test_moments_range(Backend, min_x, max_x, value, expected):
    # Arrange
    backend = Backend(Formulae())
    arr = lambda x: backend.Storage.from_ndarray(np.asarray((x, )))

    moment_0 = arr(0)
    moments = backend.Storage.from_ndarray(np.full((1, 1), 0))
    n = arr(1)
    attr_data = arr(0)
    cell_id = arr(0)
    idx = arr(0)
    length = 1
    ranks = arr(0)
    x_attr = arr(value)
    weighting_attribute = arr(0)
    weighting_rank = 0

    # Act
    backend.moments(moment_0=moment_0,
                    moments=moments,
                    n=n,
                    attr_data=attr_data,
                    cell_id=cell_id,
                    idx=idx,
                    length=length,
                    ranks=ranks,
                    min_x=min_x,
                    max_x=max_x,
                    x_attr=x_attr,
                    weighting_attribute=weighting_attribute,
                    weighting_rank=weighting_rank)

    # Assert
    assert moment_0.to_ndarray()[:] == moments.to_ndarray()[:] == expected
def test_freezing_temperature_spectra(model, plot=False):
    # Arrange
    bigg_1953.DT_median = 33
    niemand_et_al_2012.a = -0.517
    niemand_et_al_2012.b = 8.934
    niemand_et_al_2012.A_insol = 1 * si.um**2

    formulae = Formulae(freezing_temperature_spectrum=model)
    T = np.linspace(const.T0, const.T0 - 40, num=100)

    # Act
    pdf = formulae.freezing_temperature_spectrum.pdf(T, A)
    cdf = formulae.freezing_temperature_spectrum.cdf(T, A)

    # Plot
    pylab.plot(T, pdf, linestyle='-', marker='o', label='pdf')
    pdfax = pylab.gca()
    cdfax = pdfax.twinx()
    cdfax.plot(T, cdf, linestyle='--', marker='x', label='cdf')
    pylab.xlabel('T [K]')
    pylab.xlim(np.amax(T), np.amin(T))
    pdfax.set_ylabel('pdf [K$^{-1}$]')
    cdfax.set_ylabel('cdf [1]')
    pylab.grid()
    pylab.title(model)
    if plot:
        pylab.show()

    # Assert
    dT = abs(T[1] - T[0])
    np.testing.assert_approx_equal(np.sum(pdf * dT), 1, significant=3)
    np.testing.assert_approx_equal(cdf[0] + 1, 1, significant=3)
    np.testing.assert_approx_equal(cdf[-1], 1, significant=3)
    def test_freeze_time_dependent(plot=False):
        # Arrange
        cases = (
            {'dt': 5e5, 'N':  1},
            {'dt': 1e6, 'N':  1},
            {'dt': 5e5, 'N':  8},
            {'dt': 1e6, 'N':  8},
            {'dt': 5e5, 'N': 32},
            {'dt': 1e6, 'N': 32},
        )
        rate = 1e-9
        immersed_surface_area = 1
        constant.J_het = rate / immersed_surface_area

        number_of_real_droplets = 1024
        total_time = 2e9  # effectively interpretted here as seconds, i.e. cycle = 1 * si.s

        # dummy (but must-be-set) values
        vol = 44  # just to enable sign flipping (ice water uses negative volumes), actual value does not matter
        dv = 666  # products use concentration, just dividing there and multiplying back here, actual value does not matter

        hgh = lambda t: np.exp(-0.8 * rate * (t - total_time / 10))
        low = lambda t: np.exp(-1.2 * rate * (t + total_time / 10))

        # Act
        output = {}

        for case in cases:
            n_sd = int(number_of_real_droplets // case['N'])
            assert n_sd == number_of_real_droplets / case['N']
            assert total_time // case['dt'] == total_time / case['dt']

            key = f"{case['dt']}:{case['N']}"
            output[key] = {'unfrozen_fraction': [], 'dt': case['dt'], 'N': case['N']}

            formulae = Formulae(heterogeneous_ice_nucleation_rate='Constant')
            builder = Builder(n_sd=n_sd, backend=CPU(formulae=formulae))
            env = Box(dt=case['dt'], dv=dv)
            builder.set_environment(env)
            builder.add_dynamic(Freezing(singular=False))
            attributes = {
                'n': np.full(n_sd, int(case['N'])),
                'immersed surface area': np.full(n_sd, immersed_surface_area),
                'volume': np.full(n_sd, vol)
            }
            products = (IceWaterContent(specific=False),)
            particulator = builder.build(attributes=attributes, products=products)

            env['a_w_ice'] = np.nan

            cell_id = 0
            for i in range(int(total_time / case['dt']) + 1):
                particulator.run(0 if i == 0 else 1)

                ice_mass_per_volume = particulator.products['qi'].get()[cell_id]
                ice_mass = ice_mass_per_volume * dv
                ice_number = ice_mass / (const.rho_w * vol)
                unfrozen_fraction = 1 - ice_number / number_of_real_droplets
                output[key]['unfrozen_fraction'].append(unfrozen_fraction)
Esempio n. 7
0
    def __init__(self, formulae=None):
        self.formulae = formulae or Formulae()
        PhysicsMethods.__init__(self)
        CondensationMethods.__init__(self)
        AlgorithmicMethods.__init__(self)
        MomentsMethods.__init__(self)

        if not ThrustRTC.ENABLE \
           and 'CI' not in os.environ:
            warnings.warn('CUDA is not available, using FakeThrustRTC!')
Esempio n. 8
0
    def test_kink_location(constants, aerosol, cutoff):
        # arrange
        formulae = Formulae(surface_tension='CompressedFilm_Ovadnevaite')

        # act
        sigma = formulae.surface_tension.sigma(
            np.nan, v_wet, v_dry, aerosol.aerosol_modes_per_cc[0]['f_org'])

        # assert
        cutoff_idx = (np.abs(r_wet - cutoff)).argmin()
        assert (
            sigma[:cutoff_idx] == compressed_film_Ovadnevaite.sgm_org).all()
        assert sigma[cutoff_idx] > compressed_film_Ovadnevaite.sgm_org
        assert .98 * const.sgm_w < sigma[-1] <= const.sgm_w
Esempio n. 9
0
    def test_bulk_surface_tension_is_sgm_w():
        # arrange
        formulae = Formulae(surface_tension='Constant')
        r_wet = np.logspace(np.log(150 * si.nm),
                            np.log(3000 * si.nm),
                            base=np.e,
                            num=100)
        v_wet = formulae.trivia.volume(r_wet)

        # act
        sigma = formulae.surface_tension.sigma(np.nan, v_wet, np.nan, np.nan)

        # assert
        assert sigma == const.sgm_w
    def test_temperature_pressure_RH(backend):
        # Arrange
        sut = backend(Formulae()).temperature_pressure_RH
        rhod = backend.Storage.from_ndarray(np.asarray((1, 1.1)))
        thd = backend.Storage.from_ndarray(np.asarray((300., 301)))
        qv = backend.Storage.from_ndarray(np.asarray((.01, .02)))

        T = backend.Storage.from_ndarray(np.zeros_like(qv))
        p = backend.Storage.from_ndarray(np.zeros_like(qv))
        RH = backend.Storage.from_ndarray(np.zeros_like(qv))

        # Act
        sut(rhod, thd, qv, T, p, RH)

        # Assert
        assert 282 * si.K < T.amin() < 283 * si.K
        assert 820 * si.hPa < p.amin() < 830 * si.hPa
        assert 1.10 < RH.amin() < 1.11
Esempio n. 11
0
 def __init__(self):
     self.formulae = Formulae()
     self.n_sd = 2**13
     self.n_part = 2**23 / si.metre**3
     self.X0 = self.formulae.trivia.volume(radius=30.531 * si.micrometres)
     self.dv = 1e6 * si.metres**3
     self.norm_factor = self.n_part * self.dv
     self.rho = 1000 * si.kilogram / si.metre**3
     self.dt = 1 * si.seconds
     self.adaptive = False
     self.seed = 44
     self._steps = [0, 1200, 2400, 3600]
     self.kernel = Golovin(b=1.5e3 / si.second)
     self.spectrum = spectra.Exponential(norm_factor=self.norm_factor,
                                         scale=self.X0)
     self.radius_bins_edges = np.logspace(np.log10(10 * si.um),
                                          np.log10(5e3 * si.um),
                                          num=128,
                                          endpoint=True)
def test_saturation_vapour_pressures(plot=False):
    # Arrange
    formulae = {
        k: Formulae(saturation_vapour_pressure=k)
        for k in ('FlatauWalkoCotton', 'AugustRocheMagnus')
    }
    T = np.linspace(-.2, .4)

    # Plot
    if plot:
        pylab.axhline(const.p_tri, label='triple point', color='red')
        pylab.axvline(const.T_tri - const.T0, color='red')
        for k, v in formulae.items():
            for name, func in inspect.getmembers(v.saturation_vapour_pressure):
                if not name.startswith('__'):
                    pylab.plot(T, func(T), label=f"{k}::{name}")
        pylab.grid()
        pylab.legend()
        pylab.xlabel('T [C]')
        pylab.ylabel('p [Pa]')
        pylab.show()

    # Assert
    T = np.linspace(-20, 20, 100)
    np.testing.assert_allclose(
        Formulae(saturation_vapour_pressure='FlatauWalkoCotton'
                 ).saturation_vapour_pressure.pvs_Celsius(T),
        Formulae(saturation_vapour_pressure='AugustRocheMagnus'
                 ).saturation_vapour_pressure.pvs_Celsius(T),
        rtol=1e-2)
    T = np.linspace(-20, 0.3, 100)
    np.testing.assert_array_less(
        Formulae(saturation_vapour_pressure='FlatauWalkoCotton'
                 ).saturation_vapour_pressure.ice_Celsius(T),
        Formulae(saturation_vapour_pressure='FlatauWalkoCotton').
        saturation_vapour_pressure.pvs_Celsius(T))
    T = np.linspace(0.35, 20, 100)
    np.testing.assert_array_less(
        Formulae(saturation_vapour_pressure='FlatauWalkoCotton'
                 ).saturation_vapour_pressure.pvs_Celsius(T),
        Formulae(saturation_vapour_pressure='FlatauWalkoCotton').
        saturation_vapour_pressure.ice_Celsius(T))
Esempio n. 13
0
    def test_koehler_maxima(constants, aerosol, surface_tension, maximum_x,
                            maximum_y, bimodal):
        # arrange
        label = {
            'CompressedFilm_Ovadnevaite': 'film',
            'Constant': 'bulk'
        }[surface_tension]
        formulae = Formulae(surface_tension=surface_tension)
        sigma = formulae.surface_tension.sigma(
            np.nan, v_wet, v_dry, aerosol.aerosol_modes_per_cc[0]['f_org'])
        RH_eq = formulae.hygroscopicity.RH_eq(
            r_wet, T, aerosol.aerosol_modes_per_cc[0]['kappa'][label],
            r_dry**3, sigma)

        # act
        peaks = signal.find_peaks(RH_eq)

        # assert
        assert np.argmax(RH_eq) == (np.abs(r_wet - maximum_x)).argmin()
        np.testing.assert_approx_equal((np.amax(RH_eq) - 1) * 100,
                                       maximum_y,
                                       significant=3)
        assert len(peaks) == 2 if bimodal else 1
Esempio n. 14
0
 class Particulator:
     formulae = Formulae(surface_tension='CompressedFilm_Ovadnevaite')
Esempio n. 15
0
 def __init__(self, formulae=None):
     self.formulae = formulae or Formulae()
     PhysicsMethods.__init__(self)
     ChemistryMethods.__init__(self)
     FreezingMethods.__init__(self)
Esempio n. 16
0
    def __init__(self,
                 n_sd_per_gridbox: int,
                 w_1: float = 2 * si.m / si.s,
                 dt: float = 1 * si.s,
                 dz: float = 25 * si.m,
                 precip: bool = True):
        self.formulae = Formulae()
        self.n_sd_per_gridbox = n_sd_per_gridbox
        self.kappa = .9  # TODO #414: not in the paper
        self.wet_radius_spectrum_per_mass_of_dry_air = spectra.Lognormal(
            norm_factor=50 / si.cm**3,  # TODO #414: / self.rho,
            m_mode=.08 / 2 * si.um,
            s_geom=1.4)

        self.dt = dt
        self.dz = dz
        self.precip = precip

        self.z_max = 3000 * si.metres
        self.t_max = 60 * si.minutes

        t_1 = 600 * si.s
        self.w = lambda t: w_1 * np.sin(np.pi * t / t_1) if t < t_1 else 0

        self._th = interp1d((0, 740, 3260), (297.9, 297.9, 312.66))
        self.qv = interp1d(
            (0, 740, 3260), (.015, .0138, .0024)
        )  # TODO #414: is initial particle water included in initial qv? (q1 logic)
        self.thd = lambda z: self.formulae.state_variable_triplet.th_dry(
            self._th(z), self.qv(z))

        p0 = 975 * si.hPa  # TODO #414: not in the paper?
        g = const.g_std
        self.rhod0 = self.formulae.state_variable_triplet.rho_d(
            p0, self.qv(0), self._th(0))

        def drhod_dz(z, rhod):
            T = self.formulae.state_variable_triplet.T(rhod[0], self.thd(z))
            p = self.formulae.state_variable_triplet.p(rhod[0], T, self.qv(z))
            lv = self.formulae.latent_heat.lv(T)
            return self.formulae.hydrostatics.drho_dz(g, p, T, self.qv(z), lv)

        z_points = np.arange(0, self.z_max, self.dz / 2)
        rhod_solution = solve_ivp(fun=drhod_dz,
                                  t_span=(0, self.z_max),
                                  y0=np.asarray((self.rhod0, )),
                                  t_eval=z_points)
        assert rhod_solution.success
        self.rhod = interp1d(z_points, rhod_solution.y[0])

        self.mpdata_settings = {
            'n_iters': 3,
            'iga': True,
            'fct': True,
            'tot': True
        }
        self.condensation_rtol_x = condensation.default_rtol_x
        self.condensation_rtol_thd = condensation.default_rtol_thd
        self.condensation_adaptive = True
        self.coalescence_adaptive = True

        self.v_bin_edges = self.formulae.trivia.volume(
            np.logspace(np.log10(0.001 * si.um),
                        np.log10(100 * si.um),
                        101,
                        endpoint=True))
        self.cloud_water_radius_range = [1 * si.um, 50 * si.um]
        self.rain_water_radius_range = [50 * si.um, np.inf * si.um]
Esempio n. 17
0
from PySDM.initialisation import spectral_sampling, spectro_glacial
from PySDM.physics.spectra import Lognormal
from PySDM.physics import Formulae, constants as const
from PySDM.physics.freezing_temperature_spectrum import niemand_et_al_2012
import numpy as np
import pytest

niemand_et_al_2012.a = -0.517
niemand_et_al_2012.b = 8.934

m_mode = .5e-5
n_part = 256 * 16
s_geom = 1.5
spectrum = Lognormal(n_part, m_mode, s_geom)
m_range = (.1e-6, 100e-6)
formulae = Formulae(freezing_temperature_spectrum='Niemand_et_al_2012',
                    seed=const.default_random_seed)


@pytest.mark.parametrize(
    "discretisation",
    [
        pytest.param(spectral_sampling.Linear(spectrum, m_range)),
        pytest.param(spectral_sampling.Logarithmic(spectrum, m_range)),
        pytest.param(spectral_sampling.ConstantMultiplicity(spectrum,
                                                            m_range)),
        pytest.param(spectral_sampling.UniformRandom(spectrum, m_range)),
        # TODO #599
    ])
def test_spectral_discretisation(discretisation):
    # Arrange
    n_sd = 100000
Esempio n. 18
0
import numpy as np
from PySDM.backends.numba.impl._chemistry_methods import ChemistryMethods
from PySDM.backends.numba.storage import Storage
from PySDM.physics import si, Formulae
from PySDM.physics.aqueous_chemistry.support import KineticConsts, EquilibriumConsts, \
    DISSOCIATION_FACTORS, k4
from PySDM.physics.constants import T_STP, pi_4_3
import pytest

formulae = Formulae()


class SUT(ChemistryMethods):
    def __init__(self):
        self.formulae = formulae
        super().__init__()


kinetic_consts = KineticConsts(formulae)
equilibrium_consts = EquilibriumConsts(formulae)

T = T_STP

k0 = Storage.from_ndarray(np.full(1, kinetic_consts.KINETIC_CONST['k0'].at(T)))
k1 = Storage.from_ndarray(np.full(1, kinetic_consts.KINETIC_CONST['k1'].at(T)))
k2 = Storage.from_ndarray(np.full(1, kinetic_consts.KINETIC_CONST['k2'].at(T)))
k3 = Storage.from_ndarray(np.full(1, kinetic_consts.KINETIC_CONST['k3'].at(T)))
K_SO2 = Storage.from_ndarray(
    np.full(1, equilibrium_consts.EQUILIBRIUM_CONST['K_SO2'].at(T)))
K_HSO3 = Storage.from_ndarray(
    np.full(1, equilibrium_consts.EQUILIBRIUM_CONST['K_HSO3'].at(T)))
Esempio n. 19
0
    def __init__(self,
                 dt: float,
                 n_sd: int,
                 n_substep: int,
                 spectral_sampling: spec_sampling.
                 SpectralSampling = spec_sampling.Logarithmic):
        self.formulae = Formulae(
            saturation_vapour_pressure='AugustRocheMagnus')

        self.DRY_RHO = 1800 * si.kg / (si.m**3)
        self.dry_molar_mass = Substance.from_formula(
            "NH4HSO4").mass * si.gram / si.mole

        self.system_type = 'closed'

        self.t_max = (2400 + 196) * si.s
        self.output_interval = 10 * si.s
        self.dt = dt

        self.w = .5 * si.m / si.s
        self.g = 10 * si.m / si.s**2

        self.n_sd = n_sd
        self.n_substep = n_substep

        self.p0 = 950 * si.mbar
        self.T0 = 285.2 * si.K
        pv0 = .95 * self.formulae.saturation_vapour_pressure.pvs_Celsius(
            self.T0 - const.T0)
        self.q0 = const.eps * pv0 / (self.p0 - pv0)
        self.kappa = .61

        self.cloud_radius_range = (.5 * si.micrometre, 25 * si.micrometre)

        self.mass_of_dry_air = 44

        # note: rho is not specified in the paper
        rho0 = 1

        self.r_dry, self.n_in_dv = spectral_sampling(
            spectrum=spectra.Lognormal(norm_factor=566 / si.cm**3 / rho0 *
                                       self.mass_of_dry_air,
                                       m_mode=.08 * si.um / 2,
                                       s_geom=2)).sample(n_sd)

        self.ENVIRONMENT_MOLE_FRACTIONS = {
            "SO2": 0.2 * const.ppb,
            "O3": 50 * const.ppb,
            "H2O2": 0.5 * const.ppb,
            "CO2": 360 * const.ppm,
            "HNO3": 0.1 * const.ppb,
            "NH3": 0.1 * const.ppb,
        }

        self.starting_amounts = {
            "moles_" + k:
            self.formulae.trivia.volume(self.r_dry) * self.DRY_RHO /
            self.dry_molar_mass if k in ("N_mIII",
                                         "S_VI") else np.zeros(self.n_sd)
            for k in AQUEOUS_COMPOUNDS.keys()
        }

        self.dry_radius_bins_edges = np.logspace(
            np.log10(.01 * si.um), np.log10(1 * si.um), 51, endpoint=True) / 2
Esempio n. 20
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.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+'],
                                 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)
Esempio n. 21
0
    def __init__(self, fastmath: bool = JIT_FLAGS['fastmath']):
        key_packages = (PySDM, PyMPDATA, numba, numpy, scipy)
        self.versions = {}
        for pkg in key_packages:
            try:
                self.versions[pkg.__name__] = pkg.__version__
            except AttributeError:
                pass
        self.versions = str(self.versions)

        self.formulae = Formulae(condensation_coordinate='VolumeLogarithm', fastmath=fastmath)

        self.condensation_rtol_x = condensation.default_rtol_x
        self.condensation_rtol_thd = condensation.default_rtol_thd
        self.condensation_adaptive = True
        self.condensation_substeps = -1
        self.condensation_dt_cond_range = condensation.default_cond_range
        self.condensation_schedule = condensation.default_schedule

        self.coalescence_adaptive = True
        self.coalescence_dt_coal_range = coalescence.default_dt_coal_range
        self.coalescence_optimized_random = True
        self.coalescence_substeps = 1

        self.grid = (25, 25)
        self.size = (1500 * si.metres, 1500 * si.metres)
        self.n_sd_per_gridbox = 20
        self.rho_w_max = .6 * si.metres / si.seconds * (si.kilogram / si.metre ** 3)

        # output steps
        self.simulation_time = 90 * si.minute
        self.output_interval = 1 * si.minute
        self.dt = 5 * si.second
        self.spin_up_time = 1 * si.hour

        self.v_bins = self.formulae.trivia.volume(
            np.logspace(np.log10(0.001 * si.micrometre), np.log10(100 * si.micrometre), 101, endpoint=True)
        )

        self.mode_1 = spectra.Lognormal(
            norm_factor=60 / si.centimetre ** 3 / const.rho_STP,
            m_mode=0.04 * si.micrometre,
            s_geom=1.4
        )
        self.mode_2 = spectra.Lognormal(
          norm_factor=40 / si.centimetre**3 / const.rho_STP,
          m_mode=0.15 * si.micrometre,
          s_geom=1.6
        )
        self.spectrum_per_mass_of_dry_air = spectra.Sum((self.mode_1, self.mode_2))

        self.processes = {
            "particle advection": True,
            "fluid advection": True,
            "coalescence": True,
            "condensation": True,
            "sedimentation": True,
            # "relaxation": False  # TODO #338
        }

        self.mpdata_iters = 2
        self.mpdata_iga = True
        self.mpdata_fct = True
        self.mpdata_tot = True

        self.th_std0 = 289 * si.kelvins
        self.qv0 = 7.5 * si.grams / si.kilogram
        self.p0 = 1015 * si.hectopascals
        self.kappa = 1  # TODO #441!
        self.g = const.g_std
        self.kernel = Geometric(collection_efficiency=1)
        self.aerosol_radius_threshold = .5 * si.micrometre
        self.drizzle_radius_threshold = 25 * si.micrometre
Esempio n. 22
0
from PySDM_examples.Lowe_et_al_2019 import aerosol
from PySDM.physics import si, Formulae, constants as const
from PySDM.physics.surface_tension import compressed_film_Ovadnevaite
from .constants import constants
from scipy import signal
import numpy as np
import pytest

trivia = Formulae().trivia
r_wet = np.logspace(np.log(150 * si.nm),
                    np.log(3000 * si.nm),
                    base=np.e,
                    num=100)
r_dry = 50 * si.nm
v_wet = trivia.volume(r_wet)
v_dry = trivia.volume(r_dry)
T = 300 * si.K


class TestFig1:
    @staticmethod
    def test_bulk_surface_tension_is_sgm_w():
        # arrange
        formulae = Formulae(surface_tension='Constant')
        r_wet = np.logspace(np.log(150 * si.nm),
                            np.log(3000 * si.nm),
                            base=np.e,
                            num=100)
        v_wet = formulae.trivia.volume(r_wet)

        # act