예제 #1
0
 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)
예제 #2
0
def test_latent_heats(plot=False):
    # Arrange
    formulae = {k: Formulae(latent_heat=k) for k in ('Kirchhoff', 'Lowe2019')}
    temperature = np.linspace(-20, 20) + const.T_tri

    # Plot
    pyplot.axhline(const.l_tri, label='triple point', color='red')
    pyplot.axvline(const.T_tri, color='red')
    for key, val in formulae.items():
        for name, func in inspect.getmembers(val.latent_heat):
            if name[:2] not in ('__', 'a_'):
                pyplot.plot(temperature,
                            func(temperature),
                            label=f"{key}::{name}")
    pyplot.grid()
    pyplot.legend()
    pyplot.xlabel('T [K]')
    pyplot.ylabel('Lv [J/kg]')
    if plot:
        pyplot.show()

    # Assert
    temperature = np.linspace(-20, 20, 100) + const.T_tri
    np.testing.assert_allclose(
        Formulae(latent_heat='Kirchhoff').latent_heat.lv(temperature),
        Formulae(latent_heat='Lowe2019').latent_heat.lv(temperature),
        rtol=1e-2)
예제 #3
0
def test_moments_range(backend_class, min_x, max_x, value, expected):
    # Arrange
    backend = backend_class(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.))

    kw_args = {
        'multiplicity': 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,
        'skip_division_by_m0': False
    }

    # Act
    backend.moments(moment_0=moment_0,
                    moments=moments,
                    min_x=min_x,
                    max_x=max_x,
                    **kw_args)

    # Assert
    assert moment_0.to_ndarray()[:] == moments.to_ndarray()[:] == expected
예제 #4
0
    def test_koehler_maxima(constants, aerosol, surface_tension, maximum_x,
                            maximum_y, bimodal):
        # arrange
        label = {
            'CompressedFilmOvadnevaite': 'film',
            'Constant': 'bulk'
        }[surface_tension]
        formulae = Formulae(surface_tension=surface_tension,
                            constants={
                                'sgm_org': 40 * si.mN / si.m,
                                'delta_min': 0.1 * si.nm
                            })
        sigma = formulae.surface_tension.sigma(
            np.nan, V_WET, V_DRY, aerosol.aerosol_modes[0]['f_org'])
        RH_eq = formulae.hygroscopicity.RH_eq(
            R_WET, TEMPERATURE, aerosol.aerosol_modes[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
예제 #5
0
    def __init__(
        self,
        w_avg: float,
        N_STP: float,
        r_dry: float,
        mass_of_dry_air: float,
        coord: str = "VolumeLogarithm",
    ):
        self.formulae = Formulae(
            saturation_vapour_pressure="AugustRocheMagnus",
            condensation_coordinate=coord,
        )
        const = self.formulae.constants
        self.p0 = 1000 * si.hectopascals
        self.RH0 = 0.98
        self.kappa = 0.2  # TODO #441
        self.T0 = 300 * si.kelvin
        self.z_half = 150 * si.metres

        pvs = self.formulae.saturation_vapour_pressure.pvs_Celsius(self.T0 -
                                                                   const.T0)
        self.q0 = const.eps / (self.p0 / self.RH0 / pvs - 1)
        self.w_avg = w_avg
        self.r_dry = r_dry
        self.N_STP = N_STP
        self.n_in_dv = N_STP / const.rho_STP * mass_of_dry_air
        self.mass_of_dry_air = mass_of_dry_air
        self.n_output = 500

        self.rtol_x = condensation.DEFAULTS.rtol_x
        self.rtol_thd = condensation.DEFAULTS.rtol_thd
        self.coord = "volume logarithm"
        self.dt_cond_range = condensation.DEFAULTS.cond_range
예제 #6
0
    def __init__(
        self,
        dz: float,
        n_sd_per_mode: int,
        aerosol: DryAerosolMixture,
        model: str,
        spectral_sampling: type(spec_sampling.SpectralSampling),
        w: float = 0.32 * si.m / si.s,
        delta_min: float = 0.1,  # 0.2 in paper, but 0.1 matches plot fig 1c/d
        MAC: float = 1,
        HAC: float = 1,
        c_pd: float = 1005 * si.joule / si.kilogram / si.kelvin,
        g_std: float = sci.g * si.metre / si.second**2,
        BDF: bool = False,
    ):
        assert model in ("Constant", "CompressedFilmOvadnevaite")
        self.model = model
        self.n_sd_per_mode = n_sd_per_mode
        self.BDF = BDF
        self.formulae = Formulae(
            surface_tension=model,
            constants={
                "sgm_org": 40 * si.mN / si.m,
                "delta_min": delta_min * si.nm,
                "MAC": MAC,
                "HAC": HAC,
                "c_pd": c_pd,
                "g_std": g_std,
            },
            diffusion_kinetics="LoweEtAl2019",
            diffusion_thermics="LoweEtAl2019",
            latent_heat="Lowe2019",
            saturation_vapour_pressure="Lowe1977",
        )
        const = self.formulae.constants
        self.aerosol = aerosol
        self.spectral_sampling = spectral_sampling

        max_altitude = 200 * si.m
        self.w = w
        self.t_max = max_altitude / self.w
        self.dt = dz / self.w
        self.output_interval = 1 * self.dt

        self.g = 9.81 * si.m / si.s**2

        self.p0 = 980 * si.mbar
        self.T0 = 280 * si.K
        pv0 = 0.99 * self.formulae.saturation_vapour_pressure.pvs_Celsius(
            self.T0 - const.T0)
        self.q0 = const.eps * pv0 / (self.p0 - pv0)

        self.cloud_radius_range = (0.5 * si.micrometre, np.inf)

        self.mass_of_dry_air = 44

        self.wet_radius_bins_edges = np.logspace(np.log10(4 * si.um),
                                                 np.log10(12 * si.um),
                                                 128 + 1,
                                                 endpoint=True)
예제 #7
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(
            timestep=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
예제 #8
0
    def __init__(self, steps: Optional[list] = None):
        steps = steps or [200 * i for i in range(10)]

        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
        )  # 1e6 -> overflows on ThrustRTC (32-bit int multiplicities)
        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 = steps
        self.kernel = collision_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_bulk_surface_tension_is_sgm_w():
        # arrange
        formulae = Formulae(surface_tension='Constant')

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

        # assert
        assert sigma == const.sgm_w
예제 #10
0
def make_particulator(
    *,
    constants,
    n_sd,
    dt,
    initial_temperature,
    singular,
    seed,
    shima_T_fz,
    ABIFM_spec,
    droplet_volume,
    total_particle_number,
    volume
):
    attributes = {"volume": np.ones(n_sd) * droplet_volume}

    formulae_ctor_args = {"seed": seed, "constants": constants}
    if singular:
        formulae_ctor_args["freezing_temperature_spectrum"] = shima_T_fz
    else:
        formulae_ctor_args["heterogeneous_ice_nucleation_rate"] = "ABIFM"
    formulae = Formulae(**formulae_ctor_args)

    if singular:
        sampling = SpectroGlacialSampling(
            freezing_temperature_spectrum=formulae.freezing_temperature_spectrum,
            insoluble_surface_spectrum=ABIFM_spec,
            seed=formulae.seed,
        )
        attributes["freezing temperature"], _, attributes["n"] = sampling.sample(n_sd)
    else:
        sampling = ConstantMultiplicity(
            spectrum=ABIFM_spec,
            # seed=formulae.seed
        )
        attributes["immersed surface area"], attributes["n"] = sampling.sample(n_sd)
    attributes["n"] *= total_particle_number

    builder = Builder(n_sd, CPU(formulae))

    env = Box(dt, volume)
    builder.set_environment(env)
    env["T"] = initial_temperature
    env["RH"] = A_VALUE_LARGER_THAN_ONE

    builder.add_dynamic(Freezing(singular=singular))

    return builder.build(
        attributes=attributes,
        products=(
            PySDM_products.Time(name="t"),
            PySDM_products.AmbientTemperature(name="T"),
            PySDM_products.SpecificIceWaterContent(name="qi"),
        ),
    )
예제 #11
0
    def __init__(self, settings, backend=CPU):
        dt_output = (settings.total_time / settings.n_steps
                     )  # TODO #334 overwritten in notebook
        self.n_substeps = 1  # TODO #334 use condensation substeps
        while dt_output / self.n_substeps >= settings.dt_max:
            self.n_substeps += 1
        self.formulae = Formulae(
            condensation_coordinate=settings.coord,
            saturation_vapour_pressure="AugustRocheMagnus",
        )
        self.bins_edges = self.formulae.trivia.volume(settings.r_bins_edges)
        builder = Builder(backend=backend(formulae=self.formulae),
                          n_sd=settings.n_sd)
        builder.set_environment(
            Parcel(
                dt=dt_output / self.n_substeps,
                mass_of_dry_air=settings.mass_of_dry_air,
                p0=settings.p0,
                q0=settings.q0,
                T0=settings.T0,
                w=settings.w,
                z0=settings.z0,
            ))

        environment = builder.particulator.environment
        builder.add_dynamic(AmbientThermodynamics())
        condensation = Condensation(
            adaptive=settings.adaptive,
            rtol_x=settings.rtol_x,
            rtol_thd=settings.rtol_thd,
            dt_cond_range=settings.dt_cond_range,
        )
        builder.add_dynamic(condensation)

        products = [
            PySDM_products.ParticleSizeSpectrumPerVolume(
                name="Particles Wet Size Spectrum",
                radius_bins_edges=settings.r_bins_edges,
            ),
            PySDM_products.CondensationTimestepMin(name="dt_cond_min"),
            PySDM_products.CondensationTimestepMax(name="dt_cond_max"),
            PySDM_products.RipeningRate(),
        ]

        attributes = environment.init_attributes(n_in_dv=settings.n,
                                                 kappa=settings.kappa,
                                                 r_dry=settings.r_dry)

        self.particulator = builder.build(attributes, products)

        self.n_steps = settings.n_steps
예제 #12
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
예제 #13
0
def main():
    settings = Settings(Formulae())

    settings.n_sd_per_gridbox = 25
    settings.grid = (25, 25)
    settings.simulation_time = 5400 * si.second

    storage = Storage()
    simulation = Simulation(settings, storage, SpinUp)
    simulation.reinit()
    simulation.run()
    temp_file = TemporaryFile(".nc")
    exporter = NetCDFExporter(storage, settings, simulation, temp_file.absolute_path)
    exporter.run(controller=DummyController())
    def test_SL_surface_tension():
        # arrange
        formulae = Formulae(
            surface_tension='SzyszkowskiLangmuir',
            constants={
                'RUEHL_nu_org': aer.aerosol_modes[0]['nu_org'],
                'RUEHL_A0': 115e-20 * si.m * si.m,
                'RUEHL_C0': 6e-7,
                'RUEHL_sgm_min': 40.0 * si.mN / si.m
            }
        )

        # act
        sigma = formulae.surface_tension.sigma.py_func(
            TEMPERATURE,
            V_WET,
            V_DRY,
            aer.aerosol_modes[0]['f_org']
        )

        # assert
        test = np.array([
            0.04170545235068712,0.04207589632089122,0.04244962961646187,0.0428269485292672,
            0.04320818372912586,0.043593705564928045,0.04398393042681806,0.044379328434762944,
            0.04478043279935583,0.0451878513103144,0.04560228055915656,0.04602452371335611,
            0.046455512957773316,0.046896338148322336,0.047348283850285854,0.04781287786790929,
            0.048291955790905984,0.04878774828646771,0.049303001368475236,0.04984114559483559,
            0.05040653975448352,0.05100483126948219,0.05164350541293351,0.05233275085500362,
            0.0530868749743816,0.05392670762306413,0.05488381111799955,0.056007799064006464,
            0.0573767511936752,0.059091334616161374,0.06113470871082447,0.0630992101730827,
            0.06461657500220883,0.06572817193513107,0.06656632645301724,0.067223028931838,
            0.06775426559459131,0.0681947966802138,0.06856720046770072,0.06888681108136241,
            0.06916445633257737,0.06940803880572587,0.06962348937406575,0.06981536583363962,
            0.06998724243835744,0.07014197148608561,0.07028186391110573,0.07040881703533021,
            0.07052440690758358,0.0706299563370761,0.07072658588354233,0.07081525266495645,
            0.07089678030539454,0.0709718823377164,0.07104118070169195,0.07110522051890375,
            0.07116448200738978,0.07121939017482383,0.07127032276888652,0.07131761684754595,
            0.07136157424698915,0.07140246616194773,0.07144053700595183,0.07147600768332182,
            0.0715090783774165,0.07153993093863077,0.07156873093930102,0.07159562944989181,
            0.07162076458075536,0.07164426282575462,0.07166624023764522,0.07168680345997547,
            0.07170605063610594,0.0717240722125759,0.07174095165128262,0.071756766062675,
            0.07177158677029272,0.0717854798154341,0.07179850640944603,0.07181072334005235,
            0.0718221833372332,0.07183293540340689,0.07184302511202303,0.07185249487812974,
            0.07186138420401451,0.07186972990262169,0.07187756630111092,0.0718849254266297,
            0.07189183717612246,0.07189832947178237,0.07190442840356441,0.07191015836001612,
            0.07191554214854026,0.07192060110608092,0.07192535520111608,0.07192982312774573,
            0.0719340223925809,0.07193796939506661,0.07194167950180663,0.07194516711540175
        ])
        assert np.allclose(sigma, test, atol=1e-8)
예제 #15
0
    def __init__(
        self,
        formulae=None,
        rhod_w_max: float = 0.6 * si.metres / si.seconds *
        (si.kilogram / si.metre**3),
    ):
        super().__init__(formulae or Formulae(), rhod_w_max=rhod_w_max)

        self.grid = (25, 25)
        self.size = (1500 * si.metres, 1500 * si.metres)

        # output steps
        self.simulation_time = 90 * si.minute
        self.dt = 5 * si.second
        self.spin_up_time = 1 * si.hour
예제 #16
0
    def test_kink_location(constants, aerosol, cutoff):
        # arrange
        formulae = Formulae(surface_tension='CompressedFilmOvadnevaite',
                            constants={
                                'sgm_org': 40 * si.mN / si.m,
                                'delta_min': 0.1 * si.nm
                            })

        # act
        sigma = formulae.surface_tension.sigma(
            np.nan, V_WET, V_DRY, aerosol.aerosol_modes[0]['f_org'])

        # assert
        cutoff_idx = (np.abs(R_WET - cutoff)).argmin()
        assert (sigma[:cutoff_idx] == formulae.constants.sgm_org).all()
        assert sigma[cutoff_idx] > formulae.constants.sgm_org
        assert .98 * const.sgm_w < sigma[-1] <= const.sgm_w
def test_saturation_vapour_pressures(plot=False):
    # Arrange
    choices = _choices(saturation_vapour_pressure)
    formulae = {k: Formulae(saturation_vapour_pressure=k) for k in choices}
    temperature = np.linspace(-.2, .4)

    # Plot
    pyplot.axhline(const.p_tri, label='triple point', color='red')
    pyplot.axvline(const.T_tri - const.T0, color='red')
    for key, val in formulae.items():
        for name, func in inspect.getmembers(val.saturation_vapour_pressure):
            if name[:2] not in ('__', 'a_'):
                if not (key == "AugustRocheMagnus" and name == "ice_Celsius"):
                    pyplot.plot(temperature,
                                func(temperature),
                                label=f"{key}::{name}")
    pyplot.grid()
    pyplot.legend()
    pyplot.xlabel('T [C]')
    pyplot.ylabel('p [Pa]')
    if plot:
        pyplot.show()

    # Assert
    temperature = np.linspace(-20, 20, 100)
    choices_keys = tuple(choices.keys())
    for choice in choices_keys[1:]:
        np.testing.assert_allclose(
            Formulae(saturation_vapour_pressure=choices_keys[0]
                     ).saturation_vapour_pressure.pvs_Celsius(temperature),
            Formulae(saturation_vapour_pressure=choice
                     ).saturation_vapour_pressure.pvs_Celsius(temperature),
            rtol=2e-2)

    for choice in choices_keys[1:]:
        if choice != 'AugustRocheMagnus':
            temperature = np.linspace(-20, 0, 100)
            np.testing.assert_array_less(
                Formulae(saturation_vapour_pressure=choices_keys[0]
                         ).saturation_vapour_pressure.ice_Celsius(temperature),
                Formulae(saturation_vapour_pressure=choice).
                saturation_vapour_pressure.pvs_Celsius(temperature))
            temperature = np.linspace(1, 1, 100)
            np.testing.assert_array_less(
                Formulae(saturation_vapour_pressure=choices_keys[0]
                         ).saturation_vapour_pressure.pvs_Celsius(temperature),
                Formulae(saturation_vapour_pressure=choice).
                saturation_vapour_pressure.ice_Celsius(temperature))
def test_accomodation_coefficients(constants):
    # arrange
    formulae = Formulae(constants=constants)
    D = 1
    K = 2
    r = 3
    lmbd = 4

    # act
    D_dk = formulae.diffusion_kinetics.D(D, r, lmbd)
    K_dk = formulae.diffusion_kinetics.K(K, r, lmbd)

    # assert
    Kn = lmbd / r
    xx_D = 4 / 3 / constants['MAC']
    np.testing.assert_almost_equal(D_dk, D * (1 + Kn) / (1 + (xx_D + .377) * Kn + xx_D * Kn**2))
    xx_K = 4 / 3 / constants['HAC']
    np.testing.assert_almost_equal(K_dk, K * (1 + Kn) / (1 + (xx_K + .377) * Kn + xx_K * Kn**2))
예제 #19
0
def test_freezing(singular):
    # Arrange
    settings = Settings(
        Formulae(seed=44,
                 condensation_coordinate='VolumeLogarithm',
                 fastmath=True,
                 freezing_temperature_spectrum='Niemand_et_al_2012',
                 heterogeneous_ice_nucleation_rate='ABIFM',
                 constants={
                     'NIEMAND_A': -0.517,
                     'NIEMAND_B': 8.934,
                     'ABIFM_M': 28.13797,
                     'ABIFM_C': -2.92414
                 }))
    settings.dt = .5 * si.second
    settings.grid = (5, 15)
    settings.n_sd_per_gridbox = 64

    settings.simulation_time = 100 * settings.dt
    settings.spin_up_time = 10 * settings.dt

    settings.output_interval = settings.dt  # settings.simulation_time

    settings.processes['freezing'] = True
    settings.processes['coalescence'] = False

    settings.freezing_singular = singular
    settings.th_std0 -= 35 * si.K
    settings.qv0 -= 7.15 * si.g / si.kg

    storage = DummyStorage()
    simulation = Simulation(settings,
                            storage,
                            SpinUp=SpinUp,
                            backend_class=CPU)
    simulation.reinit()

    # Act
    simulation.run()

    # Assert
    assert (simulation.products['ice water content'].get() > 0).any()
예제 #20
0
 def __init__(self, steps: Optional[list] = None):
     steps = steps or [0, 1200, 2400, 3600]
     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 = steps
     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_ovad_surface_tension():
        # arrange
        formulae = Formulae(
            surface_tension='CompressedFilmOvadnevaite',
            constants={
                'sgm_org': 40 * si.mN / si.m,
                'delta_min': 0.1 * si.nm
            }
        )

        # act
        sigma = formulae.surface_tension.sigma.py_func(
            np.nan,
            V_WET,
            V_DRY,
            aer.aerosol_modes[0]['f_org']
        )

        # assert
        test = np.array([
                    0.04,0.04,0.04,0.04,0.04,0.04,0.04,0.04,0.04,0.04,0.04,0.04,0.04,
                    0.04,0.04,0.04,0.04,0.04,0.04,0.04,0.04,0.04,0.04,0.04,0.04,0.04,
                    0.04,0.04,0.04,0.04,0.04,0.04,0.04,0.04,0.04,0.04,0.04,0.04,0.04,
                    0.04,0.04,0.04,0.04,0.04,0.04145185206190185,0.043245940200403225,
                    0.04493465757799464,0.04652419321971498,0.04802037260212956,
                    0.049428679011056784,0.05075427364458418,0.05200201453477719,
                    0.053176474357604905,0.054281957196414696,0.055322514320391286,
                    0.056301959036044666,0.05722388066615342,0.05809165770721892,
                    0.05890847021403533,0.059677311456651734,0.06040099889241329,
                    0.06108218449344455,0.061723364467315724,0.06232688840684634,
                    0.06289496790207844,0.06342968464658641,0.06393299806742464,0.06440675250688739,
                    0.06485268398238773,0.06527242654921248,0.06566751828951929,0.06603940694949924,
                    0.06638945524541608,0.06671894585794522,0.06702908613316425,0.06732101250732575,
                    0.0675957946718376,0.06785443949346634,0.06809789470435344,0.06832705237523176,
                    0.06854275218466818,0.06874578449624996,0.06893689325503628,0.06911677871385602,
                    0.06928609999950004,0.06944547752817445,0.06959549527907691,0.06973670293439409,
                    0.06986961789368958,0.06999472716988156,0.0701124891739247,0.07022333539465174,
                    0.07032767197991878,0.07042588122494463,0.07051832297317082,0.07060533593488776,
                    0.0706872389283801,0.07076433204821643,0.07083689776487583,0.0709052019598351
                ])
        assert np.allclose(sigma, test, atol=1e-8)
예제 #22
0
def test_Arabas_et_al_2015_export():
    # Arrange
    settings = GUISettings(Settings(Formulae()))
    settings.ui_nz.value += 1
    settings.ui_simulation_time = IntSlider(value=10)
    settings.ui_dt = IntSlider(value=10)
    settings.ui_output_options["interval"] = IntSlider(
        value=settings.ui_dt.value)
    assert settings.n_steps == 1
    assert len(settings.output_steps) == 2 and settings.output_steps[-1] == 1

    storage = Storage()
    simulator = Simulation(settings=settings,
                           storage=storage,
                           SpinUp=SpinUp,
                           backend_class=CPU)
    file = TemporaryFile()
    ncdf_exporter = NetCDFExporter(
        storage=storage,
        settings=settings,
        simulator=simulator,
        filename=file.absolute_path,
    )
    tempdir = TemporaryDirectory()
    vtk_exporter = VTKExporter(path=tempdir.name)

    # Act
    simulator.reinit()
    simulator.run(vtk_exporter=vtk_exporter)
    ncdf_exporter.run(controller=DummyController())
    vtk_exporter.write_pvd()

    # Assert
    versions = netcdf.netcdf_file(  # pylint: disable=no-member
        file.absolute_path).versions
    assert "PyMPDATA" in str(versions)

    filenames_list = os.listdir(os.path.join(tempdir.name, "output"))
    assert len(list(filter(lambda x: x.endswith(".pvd"), filenames_list))) == 2
    assert len(list(filter(lambda x: x.endswith(".vts"), filenames_list))) == 2
    assert len(list(filter(lambda x: x.endswith(".vtu"), filenames_list))) == 2
예제 #23
0
    def test_supersaturation_and_temperature_profile(s_max, s_250m, T_250m):
        # arrange
        settings = Settings(
            dz = 1 * si.m,
            n_sd_per_mode = (5, 5),
            aerosol_modes_by_kappa = {
                .54: Lognormal(
                    norm_factor=850 / si.cm ** 3,
                    m_mode=15 * si.nm,
                    s_geom=1.6
                ),
                1.2: Lognormal(
                    norm_factor=10 / si.cm ** 3,
                    m_mode=850 * si.nm,
                    s_geom=1.2
                )
            },
            vertical_velocity = 1.0 * si.m / si.s,
            initial_pressure = 775 * si.mbar,
            initial_temperature = 274 * si.K,
            initial_relative_humidity = .98,
            displacement = 250 * si.m,
            formulae = Formulae(constants={'MAC': .3})
        )
        simulation = Simulation(settings, products=(
            ParcelDisplacement(
                name='z'),
            PeakSupersaturation(
                name='S_max', unit='%'),
            AmbientTemperature(
                name='T'),
        ))

        # act
        output = simulation.run()

        # assert
        np.testing.assert_approx_equal(np.nanmax(output['products']['S_max']), s_max, significant=2)
        np.testing.assert_approx_equal(output['products']['S_max'][-1], s_250m, significant=2)
        np.testing.assert_approx_equal(output['products']['T'][-1], T_250m, significant=2)
    def test_ruehl_surface_tension():
        # arrange
        formulae = Formulae(
            surface_tension='CompressedFilmRuehl',
            constants={
                'RUEHL_nu_org': aer.aerosol_modes[0]['nu_org'],
                'RUEHL_A0': 115e-20 * si.m * si.m,
                'RUEHL_C0': 6e-7,
                'RUEHL_m_sigma': 0.3e17 * si.J / si.m**2,
                'RUEHL_sgm_min': 40.0 * si.mN / si.m
            }
        )

        # act
        sigma = np.zeros(len(V_WET))
        for i,vw in enumerate(V_WET):
            sigma[i] = formulae.surface_tension.sigma.py_func(
                TEMPERATURE,
                vw,
                V_DRY,
                aer.aerosol_modes[0]['f_org']
            )

        # assert
        test = np.array([
            0.04318990388863848,0.04355416769160859,0.0439421778272239,0.04435543913070772,
            0.04479551672881958,0.04526402672640544,0.045762623781862244,0.04629298561514597,
            0.04685679492085086,0.04745571976463471,0.048091394314671604,0.04876540264111237,
            0.04947926918577529,0.05023446017823065,0.05103240053506651,0.051874510426880245,
            0.052762264625474335,0.05369727599685779,0.054681402290397516,0.05571687298813886,
            0.056806430668716615,0.057953479146781645,0.05916222830454722,0.06043782250688807,
            0.06178643524956695,0.06321530723603938,0.06473269985853751,0.06634773509867063,
            0.0680701033701799,0.06990965125952682,0.07187591399036536,0.072,0.072,0.072,0.072,
            0.072,0.072,0.072,0.072,0.072,0.072,0.072,0.072,0.072,0.072,
            0.072,0.072,0.072,0.072,0.072,0.072,0.072,0.072,0.072,0.072,0.072,0.072,0.072,0.072,
            0.072,0.072,0.072,0.072,0.072,0.072,0.072,0.072,0.072,0.072,0.072,0.072,0.072,0.072,
            0.072,0.072,0.072,0.072,0.072,0.072,0.072,0.072,0.072,0.072,0.072,0.072,0.072,0.072,
            0.072,0.072,0.072,0.072,0.072,0.072,0.072,0.072,0.072,0.072,0.072,0.072,0.072
        ])
        assert np.allclose(sigma, test, atol=1e-8)
예제 #25
0
def main():
    settings = Settings(Formulae())

    settings.grid = (25, 25)
    settings.simulation_time = settings.dt * 100
    settings.output_interval = settings.dt * 10
    settings.processes = {
        "particle advection": True,
        "fluid advection": True,
        "coalescence": True,
        "condensation": False,
        "sedimentation": True,
        "freezing": False,
    }

    n_sd = range(14, 16, 1)

    times = {}
    backends = [(CPU, "sync"), (CPU, "async")]
    if GPU.ENABLE:
        backends.append((GPU, "async"))
    for backend, mode in backends:
        if backend is CPU:
            PySDM.backends.impl_numba.conf.NUMBA_PARALLEL = mode
            reload_cpu_backend()
        key = f"{backend} (mode={mode})"
        times[key] = []
        for sd in n_sd:
            settings.n_sd_per_gridbox = sd
            storage = Storage()
            simulation = Simulation(settings, storage, None, backend)
            simulation.reinit(products=[WallTime()])
            simulation.run()
            times[key].append(storage.load("wall time")[-1])

    for parallelization, t in times.items():
        plt.plot(n_sd, t, label=parallelization)
    plt.legend()
    plt.loglog()
    plt.savefig("benchmark.pdf", format="pdf")
예제 #26
0
def test_freezing_temperature_spectra(model, plot=False):
    # Arrange
    formulae = Formulae(freezing_temperature_spectrum=model,
                        constants={
                            'NIEMAND_A': -0.517,
                            'NIEMAND_B': 8.934,
                            'BIGG_DT_MEDIAN': 33
                        })
    temperature = np.linspace(const.T0, const.T0 - 40, num=100)

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

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

    # Assert
    dT = abs(temperature[1] - temperature[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)

    if hasattr(formulae.freezing_temperature_spectrum, 'invcdf'):
        invcdf = formulae.freezing_temperature_spectrum.invcdf(cdf, A)
        np.testing.assert_allclose(invcdf, temperature)
예제 #27
0
    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': 16},
            {'dt': 1e6, 'N': 16},
        )
        rate = 1e-9
        immersed_surface_area = 1

        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  # for sign flip (ice water has negative volumes), value does not matter
        d_v = 666  # products use conc., dividing there, multiplying here, 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',
                constants={
                    'J_HET': rate / immersed_surface_area
                }
            )
            builder = Builder(n_sd=n_sd, backend=CPU(formulae=formulae))
            env = Box(dt=case['dt'], dv=d_v)
            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(name='qi'),)
            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 * d_v
                ice_number = ice_mass / (const.rho_w * vol)
                unfrozen_fraction = 1 - ice_number / number_of_real_droplets
                output[key]['unfrozen_fraction'].append(unfrozen_fraction)
예제 #28
0
 def formulae(self) -> Formulae:
     return Formulae(
         **{widget.description: widget.value for widget in self.ui_formulae_options}
     )
예제 #29
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",
            constants={"g_std": 10 * si.m / si.s**2},
        )
        const = self.formulae.constants
        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 = 0.5 * si.m / si.s

        self.n_sd = n_sd
        self.n_substep = n_substep

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

        self.cloud_radius_range = (0.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=0.08 * si.um / 2,
                s_geom=2,
            )).sample(n_sd)

        self.ENVIRONMENT_MOLE_FRACTIONS = {
            "SO2": 0.2 * PPB,
            "O3": 50 * PPB,
            "H2O2": 0.5 * PPB,
            "CO2": 360 * PPM,
            "HNO3": 0.1 * PPB,
            "NH3": 0.1 * 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
        }

        self.dry_radius_bins_edges = (np.logspace(
            np.log10(0.01 * si.um), np.log10(1 * si.um), 51, endpoint=True) /
                                      2)
import numpy as np
import pytest
from PySDM.initialisation.sampling import spectral_sampling, spectro_glacial_sampling
from PySDM.initialisation.spectra.lognormal import Lognormal
from PySDM import Formulae


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',
    constants={
        'NIEMAND_A': -0.517,
        'NIEMAND_B': 8.934
    }
)


@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