Beispiel #1
0
    def __init__(self, Acc_Forg: float = 0.2, Acc_N2: float = 134):
        Aitken = {
            "palmitic": 0.2,
            "(NH4)2SO4": 0.8,
            "NaCl": 0,
        }
        Accumulation = {
            "palmitic": Acc_Forg,
            "(NH4)2SO4": 0,
            "NaCl": (1 - Acc_Forg),
        }

        super().__init__(
            ionic_dissociation_phi={
                "palmitic": 1,
                "(NH4)2SO4": 3,
                "NaCl": 2,
            },
            is_soluble={
                "palmitic": False,
                "(NH4)2SO4": True,
                "NaCl": True,
            },
            densities={
                "palmitic": 0.852 * si.g / si.cm**3,
                "(NH4)2SO4": 1.77 * si.g / si.cm**3,
                "NaCl": 2.16 * si.g / si.cm**3,
            },
            compounds=("palmitic", "(NH4)2SO4", "NaCl"),
            molar_masses={
                "palmitic": 256.4 * si.g / si.mole,
                "(NH4)2SO4": Substance.from_formula("(NH4)2SO4").mass
                * si.gram
                / si.mole,
                "NaCl": Substance.from_formula("NaCl").mass * si.gram / si.mole,
            },
        )
        self.modes = (
            {
                "f_org": 1 - self.f_soluble_volume(Aitken),
                "kappa": self.kappa(Aitken),
                "nu_org": self.nu_org(Aitken),
                "spectrum": spectra.Lognormal(
                    norm_factor=226 / si.cm**3, m_mode=19.6 * si.nm, s_geom=1.71
                ),
            },
            {
                "f_org": 1 - self.f_soluble_volume(Accumulation),
                "kappa": self.kappa(Accumulation),
                "nu_org": self.nu_org(Accumulation),
                "spectrum": spectra.Lognormal(
                    norm_factor=Acc_N2 / si.cm**3, m_mode=69.5 * si.nm, s_geom=1.7
                ),
            },
        )
Beispiel #2
0
 def __init__(self, Acc_Forg: float = 0.3, Acc_N2: float = 30):
     Ultrafine = {
         "SOA1": 0.52,
         "SOA2": 0,
         "(NH4)2SO4": 0.48,
     }
     Accumulation = {
         "SOA1": 0,
         "SOA2": Acc_Forg,
         "(NH4)2SO4": (1 - Acc_Forg),
     }
     super().__init__(
         ionic_dissociation_phi={
             "SOA1": 1,
             "SOA2": 1,
             "(NH4)2SO4": 3,
         },
         molar_masses={
             "SOA1": 190 * si.g / si.mole,
             "SOA2": 368.4 * si.g / si.mole,
             "(NH4)2SO4": Substance.from_formula("(NH4)2SO4").mass
             * si.gram
             / si.mole,
         },
         densities={
             "SOA1": 1.24 * si.g / si.cm**3,
             "SOA2": 1.2 * si.g / si.cm**3,
             "(NH4)2SO4": 1.77 * si.g / si.cm**3,
         },
         compounds=("SOA1", "SOA2", "(NH4)2SO4"),
         is_soluble={
             "SOA1": False,
             "SOA2": False,
             "(NH4)2SO4": True,
         },
     )
     self.modes = (
         {
             "f_org": 1 - self.f_soluble_volume(Ultrafine),
             "kappa": self.kappa(Ultrafine),
             "nu_org": self.nu_org(Ultrafine),
             "spectrum": spectra.Lognormal(
                 norm_factor=2000 / si.cm**3, m_mode=11.5 * si.nm, s_geom=1.71
             ),
         },
         {
             "f_org": 1 - self.f_soluble_volume(Accumulation),
             "kappa": self.kappa(Accumulation),
             "nu_org": self.nu_org(Accumulation),
             "spectrum": spectra.Lognormal(
                 norm_factor=Acc_N2 / si.cm**3, m_mode=100 * si.nm, s_geom=1.70
             ),
         },
     )
Beispiel #3
0
 def __init__(
     self,
     M2_sol: float = 0,
     M2_N: float = 100 / si.cm**3,
     M2_rad: float = 50 * si.nm,
 ):
     super().__init__(
         compounds=("(NH4)2SO4", "insoluble"),
         molar_masses={
             "(NH4)2SO4": 132.14 * si.g / si.mole,
             "insoluble": 44 * si.g / si.mole,
         },
         densities={
             "(NH4)2SO4": 1.77 * si.g / si.cm**3,
             "insoluble": 1.77 * si.g / si.cm**3,
         },
         is_soluble={
             "(NH4)2SO4": True,
             "insoluble": False
         },
         ionic_dissociation_phi={
             "(NH4)2SO4": 3,
             "insoluble": 0
         },
     )
     self.modes = (
         {
             "kappa":
             self.kappa({
                 "(NH4)2SO4": 1.0,
                 "insoluble": 0.0
             }),
             "spectrum":
             spectra.Lognormal(norm_factor=100.0 / si.cm**3,
                               m_mode=50.0 * si.nm,
                               s_geom=2.0),
         },
         {
             "kappa":
             self.kappa({
                 "(NH4)2SO4": M2_sol,
                 "insoluble": (1 - M2_sol)
             }),
             "spectrum":
             spectra.Lognormal(norm_factor=M2_N, m_mode=M2_rad, s_geom=2.0),
         },
     )
Beispiel #4
0
    def __init__(self):
        nuclei = {"(NH4)2SO4": 1.0}
        accum = {"(NH4)2SO4": 1.0}
        coarse = {"(NH4)2SO4": 1.0}

        super().__init__(
            ionic_dissociation_phi={"(NH4)2SO4": 3},
            molar_masses={
                "(NH4)2SO4":
                Substance.from_formula("(NH4)2SO4").mass * si.gram / si.mole
            },
            densities={"(NH4)2SO4": 1.77 * si.g / si.cm**3},
            compounds=("(NH4)2SO4", ),
            is_soluble={"(NH4)2SO4": True},
        )
        self.modes = (
            {
                "kappa":
                self.kappa(nuclei),
                "spectrum":
                spectra.Lognormal(norm_factor=1000.0 / si.cm**3,
                                  m_mode=0.008 * si.um,
                                  s_geom=1.6),
            },
            {
                "kappa":
                self.kappa(accum),
                "spectrum":
                spectra.Lognormal(norm_factor=800 / si.cm**3,
                                  m_mode=0.034 * si.um,
                                  s_geom=2.1),
            },
            {
                "kappa":
                self.kappa(coarse),
                "spectrum":
                spectra.Lognormal(norm_factor=0.72 / si.cm**3,
                                  m_mode=0.46 * si.um,
                                  s_geom=2.2),
            },
        )
Beispiel #5
0
    def __init__(
        self,
        n_sd: int = 100,
        dt_output: float = 1 * si.second,
        dt_max: float = 1 * si.second,
    ):
        self.total_time = 3 * si.hours
        self.mass_of_dry_air = (1000 * si.kilogram
                                )  # TODO #335 doubled with jupyter si unit

        self.n_steps = int(self.total_time /
                           (5 * si.second))  # TODO #334 rename to n_output
        self.n_sd = n_sd
        self.r_dry, self.n = spectral_sampling.Logarithmic(
            spectrum=spectra.Lognormal(
                norm_factor=1000 / si.milligram * self.mass_of_dry_air,
                m_mode=50 * si.nanometre,
                s_geom=1.4,
            ),
            size_range=(10.633 * si.nanometre, 513.06 * si.nanometre),
        ).sample(n_sd)
        self.dt_max = dt_max

        self.dt_output = dt_output
        self.r_bins_edges = np.linspace(0 * si.micrometre,
                                        20 * si.micrometre,
                                        101,
                                        endpoint=True)

        self.backend = CPU
        self.coord = "VolumeLogarithm"
        self.adaptive = True
        self.rtol_x = condensation.DEFAULTS.rtol_x
        self.rtol_thd = condensation.DEFAULTS.rtol_thd
        self.dt_cond_range = condensation.DEFAULTS.cond_range

        self.T0 = 284.3 * si.kelvin
        self.q0 = 7.6 * si.grams / si.kilogram
        self.p0 = 938.5 * si.hectopascals
        self.z0 = 600 * si.metres
        self.kappa = 0.53  # Petters and S. M. Kreidenweis mean growth-factor derived

        self.t0 = 1200 * si.second
        self.f0 = 1 / 1000 * si.hertz
Beispiel #6
0
    def __init__(self, Forg: float = 0.8, N: float = 400):
        mode = {
            "(NH4)2SO4": (1 - Forg),
            "apinene_dark": Forg,
        }

        super().__init__(
            compounds=("(NH4)2SO4", "apinene_dark"),
            molar_masses={
                "(NH4)2SO4":
                Substance.from_formula("(NH4)2SO4").mass * si.gram / si.mole,
                "apinene_dark":
                209 * si.gram / si.mole,
            },
            densities={
                "(NH4)2SO4": 1.77 * si.g / si.cm**3,
                "apinene_dark": 1.27 * si.g / si.cm**3,
            },
            is_soluble={
                "(NH4)2SO4": False,
                "apinene_dark": True,
            },
            ionic_dissociation_phi={
                "(NH4)2SO4": 3,
                "apinene_dark": 1,
            },
        )
        self.modes = ({
            "f_org":
            1 - self.f_soluble_volume(mode),
            "kappa":
            self.kappa(mode),
            "nu_org":
            self.nu_org(mode),
            "spectrum":
            spectra.Lognormal(norm_factor=N / si.cm**3,
                              m_mode=50.0 * si.nm,
                              s_geom=1.75),
        }, )
Beispiel #7
0
    def __init__(self, Acc_Forg: float = 0.668, Acc_N2: float = 540):
        # note: SOA1 or SOA2 unclear from the paper
        Aitken = {
            "SOA1": 0.668,
            "SOA2": 0,
            "(NH4)2SO4": 0.166,
            "NH4NO3": 0.166,
        }
        Accumulation = {
            "SOA1": 0,
            "SOA2": Acc_Forg,
            "(NH4)2SO4": (1 - Acc_Forg) / 2,
            "NH4NO3": (1 - Acc_Forg) / 2,
        }

        super().__init__(
            ionic_dissociation_phi={
                "SOA1": 1,
                "SOA2": 1,
                "(NH4)2SO4": 3,
                "NH4NO3": 2,
            },
            molar_masses={
                "(NH4)2SO4": Substance.from_formula("(NH4)2SO4").mass
                * si.gram
                / si.mole,
                "NH4NO3": Substance.from_formula("NH4NO3").mass * si.gram / si.mole,
                "SOA1": 190 * si.g / si.mole,
                "SOA2": 368.4 * si.g / si.mole,
            },
            densities={
                "SOA1": 1.24 * si.g / si.cm**3,
                "SOA2": 1.2 * si.g / si.cm**3,
                "(NH4)2SO4": 1.77 * si.g / si.cm**3,
                "NH4NO3": 1.72 * si.g / si.cm**3,
            },
            compounds=("SOA1", "SOA2", "(NH4)2SO4", "NH4NO3"),
            is_soluble={
                "SOA1": False,
                "SOA2": False,
                "(NH4)2SO4": True,
                "NH4NO3": True,
            },
        )
        self.modes = (
            {
                "f_org": 1 - self.f_soluble_volume(Aitken),
                "kappa": self.kappa(Aitken),
                "nu_org": self.nu_org(Aitken),
                "spectrum": spectra.Lognormal(
                    norm_factor=1100 / si.cm**3, m_mode=22.7 * si.nm, s_geom=1.75
                ),
            },
            {
                "f_org": 1 - self.f_soluble_volume(Accumulation),
                "kappa": self.kappa(Accumulation),
                "nu_org": self.nu_org(Accumulation),
                "spectrum": spectra.Lognormal(
                    norm_factor=Acc_N2 / si.cm**3,
                    m_mode=82.2 * si.nm,
                    s_geom=1.62,
                ),
            },
        )
Beispiel #8
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)
Beispiel #9
0
    def __init__(self, formulae: Formulae):
        self.formulae = formulae
        const = formulae.constants

        self.condensation_rtol_x = condensation.DEFAULTS.rtol_x
        self.condensation_rtol_thd = condensation.DEFAULTS.rtol_thd
        self.condensation_adaptive = True
        self.condensation_substeps = -1
        self.condensation_dt_cond_range = condensation.DEFAULTS.cond_range
        self.condensation_schedule = condensation.DEFAULTS.schedule

        self.coalescence_adaptive = True
        self.coalescence_dt_coal_range = collisions.collision.DEFAULTS.dt_coal_range
        self.coalescence_optimized_random = True
        self.coalescence_substeps = 1
        self.kernel = Geometric(collection_efficiency=1)

        self.freezing_singular = True
        self.freezing_inp_spec = None

        self.displacement_adaptive = displacement.DEFAULTS.adaptive
        self.displacement_rtol = displacement.DEFAULTS.rtol

        self.n_sd_per_gridbox = 20

        self.aerosol_radius_threshold = 0.5 * si.micrometre
        self.drizzle_radius_threshold = 25 * si.micrometre

        self.r_bins_edges = np.logspace(
            np.log10(0.001 * si.micrometre),
            np.log10(100 * si.micrometre),
            64,
            endpoint=True,
        )
        self.T_bins_edges = np.linspace(const.T0 - 40,
                                        const.T0 - 20,
                                        64,
                                        endpoint=True)

        # TODO #599
        n_bins_per_phase = 25
        solid_phase_radii = (
            np.linspace(-n_bins_per_phase, -1, n_bins_per_phase + 1) * si.um)
        liquid_phase_radii = (
            np.linspace(0, n_bins_per_phase, n_bins_per_phase + 1) * si.um)
        self.terminal_velocity_radius_bin_edges = np.concatenate(
            [solid_phase_radii, liquid_phase_radii])

        self.output_interval = 1 * si.minute
        self.spin_up_time = 0

        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.kappa = 1  # TODO #441!

        self.processes = {
            "particle advection": True,
            "fluid advection": True,
            "coalescence": True,
            "condensation": True,
            "sedimentation": True,
            "freezing": False,
        }

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

        key_packages = [PySDM, PyMPDATA, numba, numpy, scipy]
        try:
            import ThrustRTC  # pylint: disable=import-outside-toplevel

            key_packages.append(ThrustRTC)
        except:  # pylint: disable=bare-except
            pass
        self.versions = {}
        for pkg in key_packages:
            try:
                self.versions[pkg.__name__] = pkg.__version__
            except AttributeError:
                pass
        self.versions = str(self.versions)

        self.dt = None
        self.simulation_time = None
        self.grid = None
        self.p0 = None
        self.qv0 = None
        self.th_std0 = None
        self.size = None
Beispiel #10
0
    def __init__(
        self,
        *,
        n_sd_per_gridbox: int,
        p0: float = 1007 * si.hPa,  # as used in Olesik et al. 2022 (GMD)
        particle_reservoir_depth: float = 0 * si.m,
        kappa: float = 1,
        rho_times_w_1: float = 2 * si.m / si.s * si.kg / si.m**3,
        dt: float = 1 * si.s,
        dz: float = 25 * si.m,
        precip: bool = True,
        breakup: bool = False
    ):
        self.formulae = Formulae()
        self.n_sd_per_gridbox = n_sd_per_gridbox
        self.kappa = kappa
        self.wet_radius_spectrum_per_mass_of_dry_air = spectra.Lognormal(
            norm_factor=50 / si.cm**3 / self.formulae.constants.rho_STP,
            m_mode=0.08 / 2 * si.um,
            s_geom=1.4,
        )
        self.particle_reservoir_depth = particle_reservoir_depth
        self.dt = dt
        self.dz = dz
        self.precip = precip
        self.breakup = breakup

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

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

        self._th = interp1d(
            (0.0 * si.m, 740.0 * si.m, 3260.00 * si.m),
            (297.9 * si.K, 297.9 * si.K, 312.66 * si.K),
            fill_value="extrapolate",
        )

        self.qv = interp1d(
            (-max(particle_reservoir_depth, 1), 0, 740, 3260),
            (0.015, 0.015, 0.0138, 0.0024),
            fill_value="extrapolate",
        )

        self.thd = (
            lambda z_above_reservoir: self.formulae.state_variable_triplet.th_dry(
                self._th(z_above_reservoir), self.qv(z_above_reservoir)
            )
        )

        g = self.formulae.constants.g_std
        self.rhod0 = self.formulae.state_variable_triplet.rho_d(
            p=p0,
            qv=self.qv(0 * si.m),
            theta_std=self._th(0 * si.m),
        )

        def drhod_dz(z_above_reservoir, rhod):
            if z_above_reservoir < 0:
                return 0
            qv = self.qv(z_above_reservoir)
            T = self.formulae.state_variable_triplet.T(
                rhod[0], self.thd(z_above_reservoir)
            )
            p = self.formulae.state_variable_triplet.p(rhod[0], T, qv)
            lv = self.formulae.latent_heat.lv(T)
            return self.formulae.hydrostatics.drho_dz(
                g, p, T, qv, lv
            )  # note: drho \approx drhod

        z_span = (-self.particle_reservoir_depth, self.z_max)
        z_points = np.linspace(*z_span, 2 * self.nz + 1)
        rhod_solution = solve_ivp(
            fun=drhod_dz,
            t_span=z_span,
            y0=np.asarray((self.rhod0,)),
            t_eval=z_points,
            max_step=dz / 2,
        )
        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.DEFAULTS.rtol_x
        self.condensation_rtol_thd = condensation.DEFAULTS.rtol_thd
        self.condensation_adaptive = True
        self.coalescence_adaptive = True

        self.r_bins_edges = 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]