Ejemplo n.º 1
0
    def __init__(self, settings, backend=CPU):
        t_half = settings.z_half / settings.w_avg

        dt_output = (2 * t_half) / settings.n_output
        self.n_substeps = 1
        while dt_output / self.n_substeps >= settings.dt_max:  # TODO #334 dt_max
            self.n_substeps += 1

        builder = Builder(backend=backend(formulae=settings.formulae), n_sd=1)
        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,
            ))

        builder.add_dynamic(AmbientThermodynamics())
        builder.add_dynamic(
            Condensation(
                rtol_x=settings.rtol_x,
                rtol_thd=settings.rtol_thd,
                dt_cond_range=settings.dt_cond_range,
            ))
        attributes = {}
        r_dry = np.array([settings.r_dry])
        attributes["dry volume"] = settings.formulae.trivia.volume(
            radius=r_dry)
        attributes["kappa times dry volume"] = attributes[
            "dry volume"] * settings.kappa
        attributes["n"] = np.array([settings.n_in_dv], dtype=np.int64)
        environment = builder.particulator.environment
        r_wet = equilibrate_wet_radii(
            r_dry=r_dry,
            environment=environment,
            kappa_times_dry_volume=attributes["kappa times dry volume"],
        )
        attributes["volume"] = settings.formulae.trivia.volume(radius=r_wet)
        products = [
            PySDM_products.MeanRadius(name="radius_m1", unit="um"),
            PySDM_products.CondensationTimestepMin(name="dt_cond_min"),
            PySDM_products.ParcelDisplacement(name="z"),
            PySDM_products.AmbientRelativeHumidity(name="RH", unit="%"),
            PySDM_products.Time(name="t"),
            PySDM_products.ActivatingRate(unit="s^-1 mg^-1",
                                          name="activating_rate"),
            PySDM_products.DeactivatingRate(unit="s^-1 mg^-1",
                                            name="deactivating_rate"),
            PySDM_products.RipeningRate(unit="s^-1 mg^-1",
                                        name="ripening_rate"),
            PySDM_products.PeakSupersaturation(unit="%", name="S_max"),
        ]

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

        self.n_output = settings.n_output
Ejemplo n.º 2
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
Ejemplo n.º 3
0
    def __init__(
        self, settings, products=None, scipy_solver=False, rtol_thd=1e-10, rtol_x=1e-10
    ):
        env = Parcel(
            dt=settings.timestep,
            p0=settings.initial_pressure,
            q0=settings.initial_vapour_mixing_ratio,
            T0=settings.initial_temperature,
            w=settings.vertical_velocity,
            mass_of_dry_air=44 * si.kg,
        )
        n_sd = sum(settings.n_sd_per_mode)
        builder = Builder(n_sd=n_sd, backend=CPU(formulae=settings.formulae))
        builder.set_environment(env)
        builder.add_dynamic(AmbientThermodynamics())
        builder.add_dynamic(Condensation(rtol_thd=rtol_thd, rtol_x=rtol_x))

        volume = env.mass_of_dry_air / settings.initial_air_density
        attributes = {
            k: np.empty(0) for k in ("dry volume", "kappa times dry volume", "n")
        }
        for i, (kappa, spectrum) in enumerate(settings.aerosol_modes_by_kappa.items()):
            sampling = ConstantMultiplicity(spectrum)
            r_dry, n_per_volume = sampling.sample(settings.n_sd_per_mode[i])
            v_dry = settings.formulae.trivia.volume(radius=r_dry)
            attributes["n"] = np.append(attributes["n"], n_per_volume * volume)
            attributes["dry volume"] = np.append(attributes["dry volume"], v_dry)
            attributes["kappa times dry volume"] = np.append(
                attributes["kappa times dry volume"], v_dry * kappa
            )
        r_wet = equilibrate_wet_radii(
            r_dry=settings.formulae.trivia.radius(volume=attributes["dry volume"]),
            environment=env,
            kappa_times_dry_volume=attributes["kappa times dry volume"],
        )
        attributes["volume"] = settings.formulae.trivia.volume(radius=r_wet)

        super().__init__(
            particulator=builder.build(attributes=attributes, products=products)
        )
        if scipy_solver:
            bdf.patch_particulator(self.particulator)

        self.output_attributes = {
            "volume": tuple([] for _ in range(self.particulator.n_sd))
        }
        self.settings = settings

        self.__sanity_checks(attributes, volume)
Ejemplo n.º 4
0
    def __init__(self, settings, backend=CPU):
        t_half = settings.z_half / settings.w_avg

        dt_output = (2 * t_half) / settings.n_output
        self.n_substeps = 1
        while dt_output / self.n_substeps >= settings.dt_max:  # TODO #334 dt_max
            self.n_substeps += 1

        builder = Builder(backend=backend, n_sd=1, formulae=settings.formulae)
        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
        ))

        builder.add_dynamic(AmbientThermodynamics())
        builder.add_dynamic(Condensation(
            kappa=settings.kappa,
            rtol_x=settings.rtol_x,
            rtol_thd=settings.rtol_thd,
            dt_cond_range=settings.dt_cond_range
        ))
        attributes = {}
        r_dry = np.array([settings.r_dry])
        attributes['dry volume'] = settings.formulae.trivia.volume(radius=r_dry)
        attributes['n'] = np.array([settings.n_in_dv], dtype=np.int64)
        environment = builder.core.environment
        r_wet = r_wet_init(r_dry, environment, kappa=settings.kappa)
        attributes['volume'] = settings.formulae.trivia.volume(radius=r_wet)
        products = [
            PySDM_products.ParticleMeanRadius(),
            PySDM_products.CondensationTimestepMin(),
            PySDM_products.ParcelDisplacement(),
            PySDM_products.RelativeHumidity(),
            PySDM_products.Time(),
            PySDM_products.ActivatingRate(),
            PySDM_products.DeactivatingRate(),
            PySDM_products.RipeningRate(),
            PySDM_products.PeakSupersaturation()
        ]

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

        self.n_output = settings.n_output
Ejemplo n.º 5
0
    def __init__(self, settings, backend=CPU):
        dt_output = settings.total_time / settings.n_steps  # TODO #334 overwritten in jupyter example
        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, n_sd=settings.n_sd, formulae=self.formulae)
        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.core.environment
        builder.add_dynamic(AmbientThermodynamics())
        condensation = Condensation(
            kappa=settings.kappa,
            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.ParticlesWetSizeSpectrum(v_bins=self.formulae.trivia.volume(settings.r_bins_edges)),
            PySDM_products.CondensationTimestepMin(),
            PySDM_products.CondensationTimestepMax(),
            PySDM_products.RipeningRate()
        ]

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

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

        self.n_steps = settings.n_steps
Ejemplo n.º 6
0
    def __init__(self, setup):

        dt_output = setup.total_time / setup.n_steps  # TODO: overwritten in jupyter example
        self.n_substeps = 1  # TODO
        while (dt_output / self.n_substeps >= setup.dt_max):
            self.n_substeps += 1
        self.bins_edges = phys.volume(setup.r_bins_edges)
        particles_builder = Builder(backend=setup.backend, n_sd=setup.n_sd)
        particles_builder.set_environment(
            MoistLagrangianParcelAdiabatic(
                dt=dt_output / self.n_substeps,
                mass_of_dry_air=setup.mass_of_dry_air,
                p0=setup.p0,
                q0=setup.q0,
                T0=setup.T0,
                w=setup.w,
                z0=setup.z0))

        environment = particles_builder.core.environment
        r_wet = r_wet_init(setup.r_dry, environment, np.zeros_like(setup.n),
                           setup.kappa)
        condensation = Condensation(kappa=setup.kappa,
                                    coord=setup.coord,
                                    adaptive=setup.adaptive,
                                    rtol_x=setup.rtol_x,
                                    rtol_thd=setup.rtol_thd)
        particles_builder.add_dynamic(condensation)
        attributes = {
            'n': setup.n,
            'dry volume': phys.volume(radius=setup.r_dry),
            'volume': phys.volume(radius=r_wet)
        }
        products = [
            ParticlesWetSizeSpectrum(v_bins=phys.volume(setup.r_bins_edges)),
            CondensationTimestep(),
            RipeningRate()
        ]
        self.particles = particles_builder.build(attributes, products)

        self.n_steps = setup.n_steps
Ejemplo n.º 7
0
    def __init__(self, settings, backend=CPU):

        dt_output = settings.total_time / settings.n_steps  # TODO: overwritten in jupyter example
        self.n_substeps = 1  # TODO
        while (dt_output / self.n_substeps >= settings.dt_max):
            self.n_substeps += 1
        self.bins_edges = phys.volume(settings.r_bins_edges)
        builder = Builder(backend=backend, 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.core.environment
        builder.add_dynamic(AmbientThermodynamics())
        condensation = Condensation(kappa=settings.kappa,
                                    coord=settings.coord,
                                    adaptive=settings.adaptive,
                                    rtol_x=settings.rtol_x,
                                    rtol_thd=settings.rtol_thd)
        builder.add_dynamic(condensation)

        products = [
            ParticlesWetSizeSpectrum(
                v_bins=phys.volume(settings.r_bins_edges)),
            CondensationTimestep(),
            RipeningRate()
        ]

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

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

        self.n_steps = settings.n_steps
Ejemplo n.º 8
0
    def __init__(self, setup):
        t_half = setup.z_half / setup.w_avg

        dt_output = (2 * t_half) / setup.n_output
        self.n_substeps = 1
        while dt_output / self.n_substeps >= setup.dt_max:  # TODO dt_max
            self.n_substeps += 1

        builder = Builder(backend=setup.backend, n_sd=1)
        builder.set_environment(
            MoistLagrangianParcelAdiabatic(
                dt=dt_output / self.n_substeps,
                mass_of_dry_air=setup.mass_of_dry_air,
                p0=setup.p0,
                q0=setup.q0,
                T0=setup.T0,
                w=setup.w))

        builder.add_dynamic(
            Condensation(
                kappa=setup.kappa,
                rtol_x=setup.rtol_x,
                rtol_thd=setup.rtol_thd,
            ))
        attributes = {}
        r_dry = np.array([setup.r_dry])
        attributes['dry volume'] = phys.volume(radius=r_dry)
        attributes['n'] = np.array([setup.n_in_dv], dtype=np.int64)
        environment = builder.core.environment
        r_wet = r_wet_init(r_dry, environment, np.zeros_like(attributes['n']),
                           setup.kappa)
        attributes['volume'] = phys.volume(radius=r_wet)
        products = [ParticleMeanRadius(), CondensationTimestep()]

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

        self.n_output = setup.n_output
Ejemplo n.º 9
0
    def __init__(self, settings, backend=CPU):
        self.nt = settings.nt

        builder = Builder(backend=backend,
                          n_sd=settings.n_sd,
                          formulae=settings.formulae)
        mesh = Mesh(grid=(settings.nz, ), size=(settings.z_max, ))
        env = Kinematic1D(dt=settings.dt,
                          mesh=mesh,
                          thd_of_z=settings.thd,
                          rhod_of_z=settings.rhod)

        mpdata = MPDATA_1D(
            nz=settings.nz,
            dt=settings.dt,
            mpdata_settings=settings.mpdata_settings,
            advector_of_t=lambda t: settings.w(t) * settings.dt / settings.dz,
            advectee_of_zZ_at_t0=lambda zZ: settings.qv(zZ * settings.dz),
            g_factor_of_zZ=lambda zZ: settings.rhod(zZ * settings.dz))

        builder.set_environment(env)
        builder.add_dynamic(AmbientThermodynamics())
        builder.add_dynamic(
            Condensation(adaptive=settings.condensation_adaptive,
                         rtol_thd=settings.condensation_rtol_thd,
                         rtol_x=settings.condensation_rtol_x,
                         kappa=settings.kappa))
        builder.add_dynamic(EulerianAdvection(mpdata))
        if settings.precip:
            builder.add_dynamic(
                Coalescence(kernel=Geometric(collection_efficiency=1),
                            adaptive=settings.coalescence_adaptive))
            builder.add_dynamic(
                Displacement(enable_sedimentation=True,
                             courant_field=(np.zeros(settings.nz +
                                                     1), )))  # TODO #414
        attributes = env.init_attributes(
            spatial_discretisation=spatial_sampling.Pseudorandom(),
            spectral_discretisation=spectral_sampling.ConstantMultiplicity(
                spectrum=settings.wet_radius_spectrum_per_mass_of_dry_air),
            kappa=settings.kappa)
        products = [
            PySDM_products.RelativeHumidity(),
            PySDM_products.Pressure(),
            PySDM_products.Temperature(),
            PySDM_products.WaterVapourMixingRatio(),
            PySDM_products.WaterMixingRatio(
                name='ql',
                description_prefix='cloud',
                radius_range=settings.cloud_water_radius_range),
            PySDM_products.WaterMixingRatio(
                name='qr',
                description_prefix='rain',
                radius_range=settings.rain_water_radius_range),
            PySDM_products.DryAirDensity(),
            PySDM_products.DryAirPotentialTemperature(),
            PySDM_products.ParticlesDrySizeSpectrum(
                v_bins=settings.v_bin_edges),
            PySDM_products.ParticlesWetSizeSpectrum(
                v_bins=settings.v_bin_edges),
            PySDM_products.CloudDropletConcentration(
                radius_range=settings.cloud_water_radius_range),
            PySDM_products.AerosolConcentration(
                radius_threshold=settings.cloud_water_radius_range[0]),
            PySDM_products.ParticleMeanRadius(),
            PySDM_products.RipeningRate(),
            PySDM_products.ActivatingRate(),
            PySDM_products.DeactivatingRate(),
            PySDM_products.CloudDropletEffectiveRadius(
                radius_range=settings.cloud_water_radius_range),
            PySDM_products.PeakSupersaturation()
        ]
        self.core = builder.build(attributes=attributes, products=products)
Ejemplo n.º 10
0
    def __init__(self, settings, products=None):
        env = Parcel(
            dt=settings.dt,
            mass_of_dry_air=settings.mass_of_dry_air,
            p0=settings.p0,
            q0=settings.q0,
            T0=settings.T0,
            w=settings.w,
        )

        builder = Builder(n_sd=settings.n_sd,
                          backend=CPU(formulae=settings.formulae))
        builder.set_environment(env)

        attributes = env.init_attributes(n_in_dv=settings.n_in_dv,
                                         kappa=settings.kappa,
                                         r_dry=settings.r_dry)
        attributes = {
            **attributes,
            **settings.starting_amounts,
            "pH": np.zeros(settings.n_sd),
        }

        builder.add_dynamic(AmbientThermodynamics())
        builder.add_dynamic(Condensation())
        builder.add_dynamic(
            AqueousChemistry(
                environment_mole_fractions=settings.ENVIRONMENT_MOLE_FRACTIONS,
                system_type=settings.system_type,
                n_substep=settings.n_substep,
                dry_rho=settings.DRY_RHO,
                dry_molar_mass=settings.dry_molar_mass,
            ))

        products = products or (
            PySDM_products.AmbientRelativeHumidity(name="RH", unit="%"),
            PySDM_products.WaterMixingRatio(
                name="ql", radius_range=[1 * si.um, np.inf], unit="g/kg"),
            PySDM_products.ParcelDisplacement(name="z"),
            PySDM_products.AmbientPressure(name="p"),
            PySDM_products.AmbientTemperature(name="T"),
            PySDM_products.AmbientDryAirDensity(name="rhod"),
            PySDM_products.AmbientWaterVapourMixingRatio(name="qv",
                                                         unit="g/kg"),
            PySDM_products.Time(name="t"),
            *(PySDM_products.AqueousMoleFraction(
                comp, unit="ppb", name=f"aq_{comp}_ppb")
              for comp in AQUEOUS_COMPOUNDS),
            *(PySDM_products.GaseousMoleFraction(
                comp, unit="ppb", name=f"gas_{comp}_ppb")
              for comp in GASEOUS_COMPOUNDS),
            PySDM_products.Acidity(
                name="pH_pH_number_weighted",
                radius_range=settings.cloud_radius_range,
                weighting="number",
                attr="pH",
            ),
            PySDM_products.Acidity(
                name="pH_pH_volume_weighted",
                radius_range=settings.cloud_radius_range,
                weighting="volume",
                attr="pH",
            ),
            PySDM_products.Acidity(
                name="pH_conc_H_number_weighted",
                radius_range=settings.cloud_radius_range,
                weighting="number",
                attr="conc_H",
            ),
            PySDM_products.Acidity(
                name="pH_conc_H_volume_weighted",
                radius_range=settings.cloud_radius_range,
                weighting="volume",
                attr="conc_H",
            ),
            PySDM_products.TotalDryMassMixingRatio(
                settings.DRY_RHO, name="q_dry", unit="ug/kg"),
            PySDM_products.PeakSupersaturation(unit="%", name="S_max"),
            PySDM_products.ParticleSpecificConcentration(
                radius_range=settings.cloud_radius_range,
                name="n_c_mg",
                unit="mg^-1"),
            PySDM_products.AqueousMassSpectrum(
                key="S_VI",
                dry_radius_bins_edges=settings.dry_radius_bins_edges,
                name="dm_S_VI/dlog_10(dry diameter)",
                unit='ug / m^3"',
            ),
        )

        particulator = builder.build(attributes=attributes, products=products)
        self.settings = settings
        super().__init__(particulator=particulator)
Ejemplo n.º 11
0
    def reinit(self, products=None):
        formulae = self.settings.formulae
        backend = self.backend_class(formulae=formulae)
        builder = Builder(n_sd=self.settings.n_sd, backend=backend)
        environment = Kinematic2D(
            dt=self.settings.dt,
            grid=self.settings.grid,
            size=self.settings.size,
            rhod_of=self.settings.rhod_of_zZ,
            mixed_phase=self.settings.processes["freezing"],
        )
        builder.set_environment(environment)

        if products is not None:
            products = list(products)
        else:
            products = make_default_product_collection(self.settings)

        if self.settings.processes["fluid advection"]:
            builder.add_dynamic(AmbientThermodynamics())
        if self.settings.processes["condensation"]:
            condensation = Condensation(
                rtol_x=self.settings.condensation_rtol_x,
                rtol_thd=self.settings.condensation_rtol_thd,
                adaptive=self.settings.condensation_adaptive,
                substeps=self.settings.condensation_substeps,
                dt_cond_range=self.settings.condensation_dt_cond_range,
                schedule=self.settings.condensation_schedule,
            )
            builder.add_dynamic(condensation)
        displacement = None
        if self.settings.processes["particle advection"]:
            displacement = Displacement(
                enable_sedimentation=self.settings.processes["sedimentation"],
                adaptive=self.settings.displacement_adaptive,
                rtol=self.settings.displacement_rtol,
            )
        if self.settings.processes["fluid advection"]:
            initial_profiles = {
                "th": self.settings.initial_dry_potential_temperature_profile,
                "qv": self.settings.initial_vapour_mixing_ratio_profile,
            }
            advectees = dict((
                key,
                np.repeat(
                    profile.reshape(1, -1), environment.mesh.grid[0], axis=0),
            ) for key, profile in initial_profiles.items())
            solver = MPDATA_2D(
                advectees=advectees,
                stream_function=self.settings.stream_function,
                rhod_of_zZ=self.settings.rhod_of_zZ,
                dt=self.settings.dt,
                grid=self.settings.grid,
                size=self.settings.size,
                displacement=displacement,
                n_iters=self.settings.mpdata_iters,
                infinite_gauge=self.settings.mpdata_iga,
                nonoscillatory=self.settings.mpdata_fct,
                third_order_terms=self.settings.mpdata_tot,
            )
            builder.add_dynamic(EulerianAdvection(solver))
        if self.settings.processes["particle advection"]:
            builder.add_dynamic(displacement)
        if self.settings.processes["coalescence"]:
            builder.add_dynamic(
                Coalescence(
                    collision_kernel=self.settings.kernel,
                    adaptive=self.settings.coalescence_adaptive,
                    dt_coal_range=self.settings.coalescence_dt_coal_range,
                    substeps=self.settings.coalescence_substeps,
                    optimized_random=self.settings.
                    coalescence_optimized_random,
                ))
        if self.settings.processes["freezing"]:
            builder.add_dynamic(
                Freezing(singular=self.settings.freezing_singular))

        attributes = environment.init_attributes(
            spatial_discretisation=spatial_sampling.Pseudorandom(),
            dry_radius_spectrum=self.settings.spectrum_per_mass_of_dry_air,
            kappa=self.settings.kappa,
        )

        if self.settings.processes["freezing"]:
            if self.settings.freezing_inp_spec is None:
                immersed_surface_area = formulae.trivia.sphere_surface(
                    diameter=2 *
                    formulae.trivia.radius(volume=attributes["dry volume"]))
            else:
                immersed_surface_area = self.settings.freezing_inp_spec.percentiles(
                    np.random.random(self.settings.n_sd),  # TODO #599: seed
                )

            if self.settings.freezing_singular:
                attributes[
                    "freezing temperature"] = formulae.freezing_temperature_spectrum.invcdf(
                        np.random.random(
                            self.settings.n_sd),  # TODO #599: seed
                        immersed_surface_area,
                    )
            else:
                attributes["immersed surface area"] = immersed_surface_area

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

        if self.SpinUp is not None:
            self.SpinUp(self.particulator, self.settings.n_spin_up)
        if self.storage is not None:
            self.storage.init(self.settings)
Ejemplo n.º 12
0
    def __init__(self, settings, products=None):
        env = Parcel(dt=settings.dt,
                     mass_of_dry_air=settings.mass_of_dry_air,
                     p0=settings.p0,
                     q0=settings.q0,
                     T0=settings.T0,
                     w=settings.w,
                     g=settings.g)

        builder = Builder(n_sd=settings.n_sd,
                          backend=CPU,
                          formulae=settings.formulae)
        builder.set_environment(env)

        attributes = env.init_attributes(n_in_dv=settings.n_in_dv,
                                         kappa=settings.kappa,
                                         r_dry=settings.r_dry)
        attributes = {
            **attributes,
            **settings.starting_amounts, 'pH': np.zeros(settings.n_sd)
        }

        builder.add_dynamic(AmbientThermodynamics())
        builder.add_dynamic(Condensation(kappa=settings.kappa))
        builder.add_dynamic(
            AqueousChemistry(settings.ENVIRONMENT_MOLE_FRACTIONS,
                             system_type=settings.system_type,
                             n_substep=settings.n_substep,
                             dry_rho=settings.DRY_RHO,
                             dry_molar_mass=settings.dry_molar_mass))

        products = products or (
            PySDM_products.RelativeHumidity(),
            PySDM_products.WaterMixingRatio(name='ql',
                                            description_prefix='liquid',
                                            radius_range=[1 * si.um, np.inf]),
            PySDM_products.ParcelDisplacement(), PySDM_products.Pressure(),
            PySDM_products.Temperature(), PySDM_products.DryAirDensity(),
            PySDM_products.WaterVapourMixingRatio(), PySDM_products.Time(), *[
                PySDM_products.AqueousMoleFraction(compound)
                for compound in AQUEOUS_COMPOUNDS.keys()
            ], *[
                PySDM_products.GaseousMoleFraction(compound)
                for compound in GASEOUS_COMPOUNDS.keys()
            ],
            PySDM_products.pH(radius_range=settings.cloud_radius_range,
                              weighting='number',
                              attr='pH'),
            PySDM_products.pH(radius_range=settings.cloud_radius_range,
                              weighting='volume',
                              attr='pH'),
            PySDM_products.pH(radius_range=settings.cloud_radius_range,
                              weighting='number',
                              attr='conc_H'),
            PySDM_products.pH(radius_range=settings.cloud_radius_range,
                              weighting='volume',
                              attr='conc_H'),
            PySDM_products.TotalDryMassMixingRatio(
                settings.DRY_RHO), PySDM_products.PeakSupersaturation(),
            PySDM_products.CloudDropletConcentration(
                radius_range=settings.cloud_radius_range),
            PySDM_products.AqueousMassSpectrum("S_VI",
                                               settings.dry_radius_bins_edges))

        self.core = builder.build(attributes=attributes, products=products)
        self.settings = settings
Ejemplo n.º 13
0
def run_parcel(
    w,
    sol2,
    N2,
    rad2,
    n_sd_per_mode,
    RH0=1.0,
    T0=294 * si.K,
    p0=1e5 * si.Pa,
    n_steps=50,
    mass_of_dry_air=1e3 * si.kg,
    dt=2 * si.s,
):
    products = (
        PySDM_products.WaterMixingRatio(unit="g/kg", name="ql"),
        PySDM_products.PeakSupersaturation(name="S max"),
        PySDM_products.AmbientRelativeHumidity(name="RH"),
        PySDM_products.ParcelDisplacement(name="z"),
    )

    formulae = Formulae()
    const = formulae.constants
    pv0 = RH0 * formulae.saturation_vapour_pressure.pvs_Celsius(T0 - const.T0)
    q0 = const.eps * pv0 / (p0 - pv0)

    env = Parcel(dt=dt,
                 mass_of_dry_air=mass_of_dry_air,
                 p0=p0,
                 q0=q0,
                 w=w,
                 T0=T0)

    aerosol = AerosolARG(M2_sol=sol2, M2_N=N2, M2_rad=rad2)
    n_sd = n_sd_per_mode * len(aerosol.modes)

    builder = Builder(backend=CPU(), n_sd=n_sd)
    builder.set_environment(env)
    builder.add_dynamic(AmbientThermodynamics())
    builder.add_dynamic(Condensation())
    builder.add_dynamic(Magick())

    attributes = {
        k: np.empty(0)
        for k in ("dry volume", "kappa times dry volume", "n")
    }
    for i, mode in enumerate(aerosol.modes):
        kappa, spectrum = mode["kappa"]["CompressedFilmOvadnevaite"], mode[
            "spectrum"]
        r_dry, concentration = ConstantMultiplicity(spectrum).sample(
            n_sd_per_mode)
        v_dry = builder.formulae.trivia.volume(radius=r_dry)
        specific_concentration = concentration / builder.formulae.constants.rho_STP
        attributes["n"] = np.append(
            attributes["n"], specific_concentration * env.mass_of_dry_air)
        attributes["dry volume"] = np.append(attributes["dry volume"], v_dry)
        attributes["kappa times dry volume"] = np.append(
            attributes["kappa times dry volume"], v_dry * kappa)

    r_wet = equilibrate_wet_radii(
        r_dry=builder.formulae.trivia.radius(volume=attributes["dry volume"]),
        environment=env,
        kappa_times_dry_volume=attributes["kappa times dry volume"],
    )
    attributes["volume"] = builder.formulae.trivia.volume(radius=r_wet)

    particulator = builder.build(attributes, products=products)
    bdf.patch_particulator(particulator)

    output = {product.name: [] for product in particulator.products.values()}
    output_attributes = {
        "n": tuple([] for _ in range(particulator.n_sd)),
        "volume": tuple([] for _ in range(particulator.n_sd)),
        "critical volume": tuple([] for _ in range(particulator.n_sd)),
        "critical supersaturation":
        tuple([] for _ in range(particulator.n_sd)),
    }

    for _ in range(n_steps):
        particulator.run(steps=1)
        for product in particulator.products.values():
            value = product.get()
            output[product.name].append(value[0])
        for key, attr in output_attributes.items():
            attr_data = particulator.attributes[key].to_ndarray()
            for drop_id in range(particulator.n_sd):
                attr[drop_id].append(attr_data[drop_id])

    error = np.zeros(len(aerosol.modes))
    activated_fraction_S = np.zeros(len(aerosol.modes))
    activated_fraction_V = np.zeros(len(aerosol.modes))
    for j, mode in enumerate(aerosol.modes):
        activated_drops_j_S = 0
        activated_drops_j_V = 0
        RHmax = np.nanmax(np.asarray(output["RH"]))
        for i, volume in enumerate(output_attributes["volume"]):
            if j * n_sd_per_mode <= i < (j + 1) * n_sd_per_mode:
                if output_attributes["critical supersaturation"][i][-1] < RHmax:
                    activated_drops_j_S += output_attributes["n"][i][-1]
                if output_attributes["critical volume"][i][-1] < volume[-1]:
                    activated_drops_j_V += output_attributes["n"][i][-1]
        Nj = np.asarray(output_attributes["n"])[j * n_sd_per_mode:(j + 1) *
                                                n_sd_per_mode, -1]
        max_multiplicity_j = np.max(Nj)
        sum_multiplicity_j = np.sum(Nj)
        error[j] = max_multiplicity_j / sum_multiplicity_j
        activated_fraction_S[j] = activated_drops_j_S / sum_multiplicity_j
        activated_fraction_V[j] = activated_drops_j_V / sum_multiplicity_j

    Output = namedtuple(
        "Output",
        [
            "profile",
            "attributes",
            "aerosol",
            "activated_fraction_S",
            "activated_fraction_V",
            "error",
        ],
    )
    return Output(
        profile=output,
        attributes=output_attributes,
        aerosol=aerosol,
        activated_fraction_S=activated_fraction_S,
        activated_fraction_V=activated_fraction_V,
        error=error,
    )
Ejemplo n.º 14
0
    def reinit(self):

        builder = Builder(n_sd=self.setup.n_sd, backend=self.setup.backend)
        builder.set_environment(
            MoistEulerian2DKinematic(
                dt=self.setup.dt,
                grid=self.setup.grid,
                size=self.setup.size,
                stream_function=self.setup.stream_function,
                field_values=self.setup.field_values,
                rhod_of=self.setup.rhod,
                mpdata_iga=self.setup.mpdata_iga,
                mpdata_tot=self.setup.mpdata_tot,
                mpdata_fct=self.setup.mpdata_fct,
                mpdata_iters=self.setup.mpdata_iters))

        condensation = Condensation(
            kappa=self.setup.kappa,
            rtol_x=self.setup.condensation_rtol_x,
            rtol_thd=self.setup.condensation_rtol_thd,
            coord=self.setup.condensation_coord,
            adaptive=self.setup.adaptive,
            do_advection=self.setup.
            processes["fluid advection"],  # TODO req. EulerianAdvection
            do_condensation=self.setup.processes["condensation"]
        )  # do somthing with that)
        builder.add_dynamic(condensation)
        builder.add_dynamic(EulerianAdvection())

        if self.setup.processes["particle advection"]:
            displacement = Displacement(
                scheme='FTBS',
                sedimentation=self.setup.processes["sedimentation"])
            builder.add_dynamic(displacement)
        if self.setup.processes["coalescence"]:
            builder.add_dynamic(Coalescence(kernel=self.setup.kernel))

        attributes = {}
        moist_environment_init(
            attributes,
            builder.core.environment,
            spatial_discretisation=spatial_sampling.pseudorandom,
            spectral_discretisation=spectral_sampling.constant_multiplicity,
            spectrum_per_mass_of_dry_air=self.setup.
            spectrum_per_mass_of_dry_air,
            r_range=(self.setup.r_min, self.setup.r_max),
            kappa=self.setup.kappa)
        products = [
            ParticlesWetSizeSpectrum(v_bins=self.setup.v_bins,
                                     normalise_by_dv=True),
            ParticlesDrySizeSpectrum(
                v_bins=self.setup.v_bins,
                normalise_by_dv=True),  # Note: better v_bins
            TotalParticleConcentration(),
            TotalParticleSpecificConcentration(),
            AerosolConcentration(
                radius_threshold=self.setup.aerosol_radius_threshold),
            CloudConcentration(
                radius_range=(self.setup.aerosol_radius_threshold,
                              self.setup.drizzle_radius_threshold)),
            DrizzleConcentration(
                radius_threshold=self.setup.drizzle_radius_threshold),
            AerosolSpecificConcentration(
                radius_threshold=self.setup.aerosol_radius_threshold),
            ParticleMeanRadius(),
            SuperDropletCount(),
            RelativeHumidity(),
            WaterVapourMixingRatio(),
            DryAirDensity(),
            DryAirPotentialTemperature(),
            CondensationTimestep(),
            # RipeningRate()
        ]
        self.core = builder.build(attributes, products)
        SpinUp(self.core, self.setup.n_spin_up)
        # TODO
        if self.storage is not None:
            self.storage.init(self.setup)
Ejemplo n.º 15
0
    def __init__(self, settings, backend=CPU):
        self.nt = settings.nt
        self.z0 = -settings.particle_reservoir_depth

        builder = Builder(n_sd=settings.n_sd,
                          backend=backend(formulae=settings.formulae))
        mesh = Mesh(
            grid=(settings.nz, ),
            size=(settings.z_max + settings.particle_reservoir_depth, ),
        )
        env = Kinematic1D(
            dt=settings.dt,
            mesh=mesh,
            thd_of_z=settings.thd,
            rhod_of_z=settings.rhod,
            z0=-settings.particle_reservoir_depth,
        )

        def zZ_to_z_above_reservoir(zZ):
            z_above_reservoir = zZ * (settings.nz * settings.dz) + self.z0
            return z_above_reservoir

        self.mpdata = MPDATA_1D(
            nz=settings.nz,
            dt=settings.dt,
            mpdata_settings=settings.mpdata_settings,
            advector_of_t=lambda t: settings.rho_times_w(t) * settings.dt /
            settings.dz,
            advectee_of_zZ_at_t0=lambda zZ: settings.qv(
                zZ_to_z_above_reservoir(zZ)),
            g_factor_of_zZ=lambda zZ: settings.rhod(zZ_to_z_above_reservoir(zZ)
                                                    ),
        )

        _extra_nz = settings.particle_reservoir_depth // settings.dz
        _z_vec = settings.dz * np.linspace(-_extra_nz, settings.nz - _extra_nz,
                                           settings.nz + 1)
        self.g_factor_vec = settings.rhod(_z_vec)

        builder.set_environment(env)
        builder.add_dynamic(AmbientThermodynamics())
        builder.add_dynamic(
            Condensation(
                adaptive=settings.condensation_adaptive,
                rtol_thd=settings.condensation_rtol_thd,
                rtol_x=settings.condensation_rtol_x,
            ))
        builder.add_dynamic(EulerianAdvection(self.mpdata))
        if settings.precip:
            if settings.breakup:
                builder.add_dynamic(
                    Collision(
                        collision_kernel=Geometric(collection_efficiency=1),
                        coalescence_efficiency=ConstEc(Ec=0.95),
                        breakup_efficiency=ConstEb(Eb=1.0),
                        fragmentation_function=ExponFrag(scale=100 * si.um),
                        adaptive=settings.coalescence_adaptive,
                    ))
            else:
                builder.add_dynamic(
                    Coalescence(
                        collision_kernel=Geometric(collection_efficiency=1),
                        adaptive=settings.coalescence_adaptive,
                    ))
        displacement = Displacement(
            enable_sedimentation=settings.precip,
            precipitation_counting_level_index=int(
                settings.particle_reservoir_depth / settings.dz),
        )
        builder.add_dynamic(displacement)
        attributes = env.init_attributes(
            spatial_discretisation=spatial_sampling.Pseudorandom(),
            spectral_discretisation=spectral_sampling.ConstantMultiplicity(
                spectrum=settings.wet_radius_spectrum_per_mass_of_dry_air),
            kappa=settings.kappa,
        )
        products = [
            PySDM_products.AmbientRelativeHumidity(name="RH", unit="%"),
            PySDM_products.AmbientPressure(name="p"),
            PySDM_products.AmbientTemperature(name="T"),
            PySDM_products.AmbientWaterVapourMixingRatio(name="qv"),
            PySDM_products.WaterMixingRatio(
                name="ql",
                unit="g/kg",
                radius_range=settings.cloud_water_radius_range),
            PySDM_products.WaterMixingRatio(
                name="qr",
                unit="g/kg",
                radius_range=settings.rain_water_radius_range),
            PySDM_products.AmbientDryAirDensity(name="rhod"),
            PySDM_products.AmbientDryAirPotentialTemperature(name="thd"),
            PySDM_products.ParticleSizeSpectrumPerVolume(
                name="dry spectrum",
                radius_bins_edges=settings.r_bins_edges,
                dry=True),
            PySDM_products.ParticleSizeSpectrumPerVolume(
                name="wet spectrum", radius_bins_edges=settings.r_bins_edges),
            PySDM_products.ParticleConcentration(
                name="nc", radius_range=settings.cloud_water_radius_range),
            PySDM_products.ParticleConcentration(
                name="na",
                radius_range=(0, settings.cloud_water_radius_range[0])),
            PySDM_products.MeanRadius(),
            PySDM_products.RipeningRate(),
            PySDM_products.ActivatingRate(),
            PySDM_products.DeactivatingRate(),
            PySDM_products.EffectiveRadius(
                radius_range=settings.cloud_water_radius_range),
            PySDM_products.PeakSupersaturation(unit="%"),
            PySDM_products.SuperDropletCountPerGridbox(),
        ]
        self.particulator = builder.build(attributes=attributes,
                                          products=products)
Ejemplo n.º 16
0
    def __init__(self, settings, products=None):
        env = Parcel(
            dt=settings.dt,
            mass_of_dry_air=settings.mass_of_dry_air,
            p0=settings.p0,
            q0=settings.q0,
            T0=settings.T0,
            w=settings.w,
        )
        n_sd = settings.n_sd_per_mode * len(settings.aerosol.modes)
        builder = Builder(n_sd=n_sd, backend=CPU(formulae=settings.formulae))
        builder.set_environment(env)

        attributes = {
            "dry volume": np.empty(0),
            "dry volume organic": np.empty(0),
            "kappa times dry volume": np.empty(0),
            "n": np.ndarray(0),
        }
        for mode in settings.aerosol.modes:
            r_dry, n_in_dv = settings.spectral_sampling(
                spectrum=mode["spectrum"]).sample(settings.n_sd_per_mode)
            V = settings.mass_of_dry_air / settings.rho0
            N = n_in_dv * V
            v_dry = settings.formulae.trivia.volume(radius=r_dry)
            attributes["n"] = np.append(attributes["n"], N)
            attributes["dry volume"] = np.append(attributes["dry volume"],
                                                 v_dry)
            attributes["dry volume organic"] = np.append(
                attributes["dry volume organic"], mode["f_org"] * v_dry)
            attributes["kappa times dry volume"] = np.append(
                attributes["kappa times dry volume"],
                v_dry * mode["kappa"][settings.model],
            )
        for attribute in attributes.values():
            assert attribute.shape[0] == n_sd

        np.testing.assert_approx_equal(
            np.sum(attributes["n"]) / V,
            Sum(
                tuple(
                    settings.aerosol.modes[i]["spectrum"]
                    for i in range(len(settings.aerosol.modes)))).norm_factor,
            significant=5,
        )
        r_wet = equilibrate_wet_radii(
            r_dry=settings.formulae.trivia.radius(
                volume=attributes["dry volume"]),
            environment=env,
            kappa_times_dry_volume=attributes["kappa times dry volume"],
            f_org=attributes["dry volume organic"] / attributes["dry volume"],
        )
        attributes["volume"] = settings.formulae.trivia.volume(radius=r_wet)

        if settings.model == "Constant":
            del attributes["dry volume organic"]

        builder.add_dynamic(AmbientThermodynamics())
        builder.add_dynamic(Condensation())

        products = products or (
            PySDM_products.ParcelDisplacement(name="z"),
            PySDM_products.Time(name="t"),
            PySDM_products.PeakSupersaturation(unit="%", name="S_max"),
            PySDM_products.AmbientRelativeHumidity(unit="%", name="RH"),
            PySDM_products.ParticleConcentration(
                name="n_c_cm3",
                unit="cm^-3",
                radius_range=settings.cloud_radius_range),
            PySDM_products.ParticleSizeSpectrumPerVolume(
                radius_bins_edges=settings.wet_radius_bins_edges),
            PySDM_products.ActivableFraction(),
        )

        particulator = builder.build(attributes=attributes, products=products)
        if settings.BDF:
            bdf.patch_particulator(particulator)
        self.settings = settings
        super().__init__(particulator=particulator)
Ejemplo n.º 17
0
    def reinit(self, products=None):

        builder = Builder(n_sd=self.settings.n_sd, backend=self.backend)
        environment = Kinematic2D(dt=self.settings.dt,
                                  grid=self.settings.grid,
                                  size=self.settings.size,
                                  rhod_of=self.settings.rhod,
                                  field_values=self.settings.field_values)
        builder.set_environment(environment)

        products = products or [
            ParticlesWetSizeSpectrum(v_bins=self.settings.v_bins,
                                     normalise_by_dv=True),
            ParticlesDrySizeSpectrum(
                v_bins=self.settings.v_bins,
                normalise_by_dv=True),  # Note: better v_bins
            TotalParticleConcentration(),
            TotalParticleSpecificConcentration(),
            AerosolConcentration(
                radius_threshold=self.settings.aerosol_radius_threshold),
            CloudConcentration(
                radius_range=(self.settings.aerosol_radius_threshold,
                              self.settings.drizzle_radius_threshold)),
            DrizzleConcentration(
                radius_threshold=self.settings.drizzle_radius_threshold),
            AerosolSpecificConcentration(
                radius_threshold=self.settings.aerosol_radius_threshold),
            ParticleMeanRadius(),
            SuperDropletCount(),
            RelativeHumidity(),
            Pressure(),
            Temperature(),
            WaterVapourMixingRatio(),
            DryAirDensity(),
            DryAirPotentialTemperature(),
            CPUTime(),
            WallTime()
        ]

        fields = Fields(environment, self.settings.stream_function)
        if self.settings.processes[
                'fluid advection']:  # TODO: ambient thermodynamics checkbox
            builder.add_dynamic(AmbientThermodynamics())
        if self.settings.processes["condensation"]:
            condensation = Condensation(
                kappa=self.settings.kappa,
                rtol_x=self.settings.condensation_rtol_x,
                rtol_thd=self.settings.condensation_rtol_thd,
                coord=self.settings.condensation_coord,
                adaptive=self.settings.adaptive)
            builder.add_dynamic(condensation)
            products.append(CondensationTimestep()
                            )  # TODO: and what if a user doesn't want it?
        if self.settings.processes['fluid advection']:
            solver = MPDATA(fields=fields,
                            n_iters=self.settings.mpdata_iters,
                            infinite_gauge=self.settings.mpdata_iga,
                            flux_corrected_transport=self.settings.mpdata_fct,
                            third_order_terms=self.settings.mpdata_tot)
            builder.add_dynamic(EulerianAdvection(solver))
        if self.settings.processes["particle advection"]:
            displacement = Displacement(
                courant_field=fields.courant_field,
                scheme='FTBS',
                enable_sedimentation=self.settings.processes["sedimentation"])
            builder.add_dynamic(displacement)
            products.append(SurfacePrecipitation())  # TODO: ditto
        if self.settings.processes["coalescence"]:
            builder.add_dynamic(Coalescence(kernel=self.settings.kernel))

        attributes = environment.init_attributes(
            spatial_discretisation=spatial_sampling.Pseudorandom(),
            spectral_discretisation=spectral_sampling.ConstantMultiplicity(
                spectrum=self.settings.spectrum_per_mass_of_dry_air),
            kappa=self.settings.kappa)

        self.core = builder.build(attributes, products)
        SpinUp(self.core, self.settings.n_spin_up)
        # TODO
        if self.storage is not None:
            self.storage.init(self.settings)
Ejemplo n.º 18
0
    def reinit(self, products=None):
        builder = Builder(n_sd=self.settings.n_sd,
                          backend=self.backend,
                          formulae=self.settings.formulae)
        environment = Kinematic2D(dt=self.settings.dt,
                                  grid=self.settings.grid,
                                  size=self.settings.size,
                                  rhod_of=self.settings.rhod,
                                  field_values=self.settings.field_values)
        builder.set_environment(environment)

        cloud_range = (self.settings.aerosol_radius_threshold,
                       self.settings.drizzle_radius_threshold)
        if products is not None:
            products = list(products)
        products = products or [
            PySDM_products.ParticlesWetSizeSpectrum(
                v_bins=self.settings.v_bins, normalise_by_dv=True),
            PySDM_products.ParticlesDrySizeSpectrum(
                v_bins=self.settings.v_bins,
                normalise_by_dv=True),  # Note: better v_bins
            PySDM_products.TotalParticleConcentration(),
            PySDM_products.TotalParticleSpecificConcentration(),
            PySDM_products.AerosolConcentration(
                radius_threshold=self.settings.aerosol_radius_threshold),
            PySDM_products.CloudDropletConcentration(radius_range=cloud_range),
            PySDM_products.WaterMixingRatio(name='qc',
                                            description_prefix='Cloud',
                                            radius_range=cloud_range),
            PySDM_products.WaterMixingRatio(
                name='qr',
                description_prefix='Rain',
                radius_range=(self.settings.drizzle_radius_threshold, np.inf)),
            PySDM_products.DrizzleConcentration(
                radius_threshold=self.settings.drizzle_radius_threshold),
            PySDM_products.AerosolSpecificConcentration(
                radius_threshold=self.settings.aerosol_radius_threshold),
            PySDM_products.ParticleMeanRadius(),
            PySDM_products.SuperDropletCount(),
            PySDM_products.RelativeHumidity(),
            PySDM_products.Pressure(),
            PySDM_products.Temperature(),
            PySDM_products.WaterVapourMixingRatio(),
            PySDM_products.DryAirDensity(),
            PySDM_products.DryAirPotentialTemperature(),
            PySDM_products.CPUTime(),
            PySDM_products.WallTime(),
            PySDM_products.CloudDropletEffectiveRadius(
                radius_range=cloud_range),
            PySDM_products.PeakSupersaturation(),
            PySDM_products.ActivatingRate(),
            PySDM_products.DeactivatingRate(),
            PySDM_products.RipeningRate()
        ]

        fields = Fields(environment, self.settings.stream_function)
        if self.settings.processes[
                'fluid advection']:  # TODO #37 ambient thermodynamics checkbox
            builder.add_dynamic(AmbientThermodynamics())
        if self.settings.processes["condensation"]:
            condensation = Condensation(
                kappa=self.settings.kappa,
                rtol_x=self.settings.condensation_rtol_x,
                rtol_thd=self.settings.condensation_rtol_thd,
                adaptive=self.settings.condensation_adaptive,
                substeps=self.settings.condensation_substeps,
                dt_cond_range=self.settings.condensation_dt_cond_range,
                schedule=self.settings.condensation_schedule)
            builder.add_dynamic(condensation)
            products.append(PySDM_products.CondensationTimestepMin()
                            )  # TODO #37 and what if a user doesn't want it?
            products.append(PySDM_products.CondensationTimestepMax())
        if self.settings.processes['fluid advection']:
            solver = MPDATA(fields=fields,
                            n_iters=self.settings.mpdata_iters,
                            infinite_gauge=self.settings.mpdata_iga,
                            flux_corrected_transport=self.settings.mpdata_fct,
                            third_order_terms=self.settings.mpdata_tot)
            builder.add_dynamic(EulerianAdvection(solver))
        if self.settings.processes["particle advection"]:
            displacement = Displacement(
                courant_field=fields.courant_field,
                enable_sedimentation=self.settings.processes["sedimentation"])
            builder.add_dynamic(displacement)
            products.append(
                PySDM_products.SurfacePrecipitation())  # TODO #37 ditto
        if self.settings.processes["coalescence"]:
            builder.add_dynamic(
                Coalescence(
                    kernel=self.settings.kernel,
                    adaptive=self.settings.coalescence_adaptive,
                    dt_coal_range=self.settings.coalescence_dt_coal_range,
                    substeps=self.settings.coalescence_substeps,
                    optimized_random=self.settings.coalescence_optimized_random
                ))
            products.append(PySDM_products.CoalescenceTimestepMean())
            products.append(PySDM_products.CoalescenceTimestepMin())
            products.append(PySDM_products.CollisionRate())
            products.append(PySDM_products.CollisionRateDeficit())

        attributes = environment.init_attributes(
            spatial_discretisation=spatial_sampling.Pseudorandom(),
            spectral_discretisation=spectral_sampling.ConstantMultiplicity(
                spectrum=self.settings.spectrum_per_mass_of_dry_air),
            kappa=self.settings.kappa)

        self.core = builder.build(attributes, products)
        SpinUp(self.core, self.settings.n_spin_up)
        if self.storage is not None:
            self.storage.init(self.settings)