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)
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
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)
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)
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!')
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
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
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))
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
class Particulator: formulae = Formulae(surface_tension='CompressedFilm_Ovadnevaite')
def __init__(self, formulae=None): self.formulae = formulae or Formulae() PhysicsMethods.__init__(self) ChemistryMethods.__init__(self) FreezingMethods.__init__(self)
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]
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
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)))
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
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)
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
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