예제 #1
0
    def create_state_2d(self, extensive, intensive, spatial_discretisation,
                        spectral_discretisation, spectrum_per_mass_of_dry_air,
                        r_range, kappa, radius_threshold):
        assert_not_none(self.particles.mesh, self.particles.environment)
        assert_none(self.particles.state)

        with np.errstate(all='raise'):
            positions = spatial_discretisation(self.particles.mesh.grid,
                                               self.particles.n_sd)
            cell_id, cell_origin, position_in_cell = self.particles.mesh.cellular_attributes(
                positions)
            r_dry, n_per_kg = spectral_discretisation(
                self.particles.n_sd, spectrum_per_mass_of_dry_air, r_range)
            r_wet = r_wet_init(r_dry, self.particles.environment, cell_id,
                               kappa)
            n_per_m3 = n_init(n_per_kg, self.particles.environment,
                              self.particles.mesh, cell_id)
            n = discretise_n(n_per_m3)

        extensive['volume'] = phys.volume(radius=r_wet)
        extensive['dry volume'] = phys.volume(radius=r_dry)

        self.particles.state = StateFactory.state(n, intensive, extensive,
                                                  cell_id, cell_origin,
                                                  position_in_cell,
                                                  self.particles)
        for product in [
                TotalParticleConcentration(self.particles),
                TotalParticleSpecificConcentration(self.particles),
                AerosolConcentration(self.particles, radius_threshold),
                AerosolSpecificConcentration(self.particles, radius_threshold),
                ParticleMeanRadius(self.particles),
                SuperDropletCount(self.particles)
        ]:
            self.register_product(product)
예제 #2
0
파일: example.py 프로젝트: huangynj/PySDM
    def __init__(self, setup):
        t_half = setup.z_half / setup.w_avg
        dt = (2 * t_half) / setup.n_steps

        self.particles = Particles(backend=setup.backend, n_sd=1, dt=dt)
        self.particles.set_mesh_0d()
        self.particles.set_environment(
            MoistLagrangianParcelAdiabatic, {
                "mass_of_dry_air": setup.mass_of_dry_air,
                "p0": setup.p0,
                "q0": setup.q0,
                "T0": setup.T0,
                "w": setup.w
            })

        r_dry = np.array([setup.r_dry])
        x_dry = phys.volume(radius=r_dry)
        n = np.array([setup.n_in_dv], dtype=np.int64)
        r_wet = r_wet_init(r_dry, self.particles.environment, np.zeros_like(n),
                           setup.kappa)
        v_wet = phys.volume(radius=r_wet)
        self.particles.create_state_0d(n=n,
                                       extensive={
                                           'dry volume': x_dry,
                                           'volume': v_wet
                                       },
                                       intensive={})
        self.particles.add_dynamic(Condensation, {"kappa": setup.kappa})

        self.n_steps = setup.n_steps
예제 #3
0
파일: example.py 프로젝트: cycle13/PySDM
    def __init__(self, setup):
        t_half = setup.z_half / setup.w_avg

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

        particles_builder = ParticlesBuilder(backend=setup.backend, n_sd=1, dt=dt_output / self.n_substeps)
        particles_builder.set_mesh_0d()
        particles_builder.set_environment(MoistLagrangianParcelAdiabatic, {
            "mass_of_dry_air": setup.mass_of_dry_air,
            "p0": setup.p0,
            "q0": setup.q0,
            "T0": setup.T0,
            "w": setup.w
        })

        r_dry = np.array([setup.r_dry])
        x_dry = phys.volume(radius=r_dry)
        n = np.array([setup.n_in_dv], dtype=np.int64)
        r_wet = r_wet_init(r_dry, particles_builder.particles.environment, np.zeros_like(n), setup.kappa)
        v_wet = phys.volume(radius=r_wet)
        particles_builder.create_state_0d(n=n, extensive={'dry volume': x_dry, 'volume': v_wet}, intensive={})
        particles_builder.register_dynamic(Condensation, {
            "kappa": setup.kappa,
            "scheme": setup.scheme,
            "rtol_lnv": setup.rtol_lnv,
            "rtol_thd": setup.rtol_thd,
        })
        self.particles = particles_builder.get_particles()

        self.n_steps = setup.n_steps
예제 #4
0
파일: setup.py 프로젝트: cycle13/PySDM
class SetupA:
    x_min = phys.volume(radius=10 * si.micrometres)  # not given in the paper
    x_max = phys.volume(radius=100 * si.micrometres)  # not given in the paper

    n_sd = 2 ** 13
    n_part = 2 ** 23 / si.metre**3
    X0 = 4 / 3 * np.pi * 30.531e-6 ** 3
    dv = 1e6 * si.metres**3
    norm_factor = n_part * dv
    rho = 1000 * si.kilogram / si.metre**3
    dt = 1 * si.seconds
    seed = 44
    steps = [0, 1200, 2400, 3600]

    kernel = Golovin(b=1.5e3 / si.second)
    spectrum = Exponential(norm_factor=norm_factor, scale=X0)

    backend = Default

    # TODO: rename?
    # TODO: as backend method?
    def check(self, state, step):
        check_LWC = 1e-3  * si.kilogram / si.metre**3
        check_ksi = self.n_part * self.dv / self.n_sd

        # multiplicities
        if step == 0:
            np.testing.assert_approx_equal(np.amin(state['n']), np.amax(state['n']), 1)
            np.testing.assert_approx_equal(state['n'][0], check_ksi, 1)

        # liquid water content
        LWC = self.rho * np.dot(state['n'], state['volume']) / self.dv
        np.testing.assert_approx_equal(LWC, check_LWC, 3)
예제 #5
0
파일: example.py 프로젝트: huangynj/PySDM
    def __init__(self, setup):

        self.particles = Particles(backend=setup.backend,
                                   n_sd=setup.n_sd,
                                   dt=setup.dt)
        self.particles.set_mesh_0d()
        self.particles.set_environment(
            MoistLagrangianParcelAdiabatic, {
                "mass_of_dry_air": setup.mass_of_dry_air,
                "p0": setup.p0,
                "q0": setup.q0,
                "T0": setup.T0,
                "w": setup.w,
                "z0": setup.z0
            })

        v_dry = phys.volume(radius=setup.r_dry)
        r_wet = r_wet_init(setup.r_dry, self.particles.environment,
                           np.zeros_like(setup.n), setup.kappa)
        v_wet = phys.volume(radius=r_wet)
        self.particles.create_state_0d(n=setup.n,
                                       extensive={
                                           'dry volume': v_dry,
                                           'volume': v_wet
                                       },
                                       intensive={})
        self.particles.add_dynamic(Condensation, {"kappa": setup.kappa})

        self.n_steps = setup.n_steps
예제 #6
0
파일: particles.py 프로젝트: huangynj/PySDM
    def create_state_2d(self, extensive, intensive, spatial_discretisation, spectral_discretisation,
                        spectrum_per_mass_of_dry_air, r_range, kappa):
        assert_not_none(self.mesh, self.environment)
        assert_none(self.state)

        with np.errstate(all='raise'):
            positions = spatial_discretisation(self.mesh.grid, self.n_sd)
            cell_id, cell_origin, position_in_cell = self.mesh.cellular_attributes(positions)
            r_dry, n_per_kg = spectral_discretisation(self.n_sd, spectrum_per_mass_of_dry_air, r_range)
            r_wet = r_wet_init(r_dry, self.environment, cell_id, kappa)
            n_per_m3 = n_init(n_per_kg, self, cell_id)
            n = discretise_n(n_per_m3)

        extensive['volume'] = phys.volume(radius=r_wet)
        extensive['dry volume'] = phys.volume(radius=r_dry)

        self.state = StateFactory.state(n, intensive, extensive, cell_id, cell_origin, position_in_cell, self)
예제 #7
0
파일: example.py 프로젝트: cycle13/PySDM
    def __init__(self, setup):

        dt_output = setup.total_time / setup.n_steps
        self.n_substeps = 1
        while (dt_output / self.n_substeps >= setup.dt_max):
            self.n_substeps += 1

        particles_builder = ParticlesBuilder(backend=setup.backend,
                                             n_sd=setup.n_sd,
                                             dt=dt_output / self.n_substeps)
        particles_builder.set_mesh_0d()
        particles_builder.set_environment(
            MoistLagrangianParcelAdiabatic, {
                "mass_of_dry_air": setup.mass_of_dry_air,
                "p0": setup.p0,
                "q0": setup.q0,
                "T0": setup.T0,
                "w": setup.w,
                "z0": setup.z0
            })

        v_dry = phys.volume(radius=setup.r_dry)
        r_wet = r_wet_init(setup.r_dry,
                           particles_builder.particles.environment,
                           np.zeros_like(setup.n), setup.kappa)
        v_wet = phys.volume(radius=r_wet)
        particles_builder.create_state_0d(n=setup.n,
                                          extensive={
                                              'dry volume': v_dry,
                                              'volume': v_wet
                                          },
                                          intensive={})
        particles_builder.register_dynamic(
            Condensation, {
                "kappa": setup.kappa,
                "scheme": setup.condensation_scheme,
                "rtol_lnv": setup.rtol_lnv,
                "rtol_thd": setup.rtol_thd,
            })
        self.particles = particles_builder.get_particles()

        self.n_steps = setup.n_steps
 def get(self):
     self.download_moment_to_buffer(
         'volume',
         rank=0,
         attr_range=[0, phys.volume(self.radius_threshold)])
     result = self.buffer.copy()  # TODO !!!
     self.download_to_buffer(self.particles.environment['rhod'])
     result[:] /= self.particles.mesh.dv
     result[:] /= self.buffer
     const.convert_to(result, const.si.milligram**-1)
     return result
예제 #9
0
파일: plotter.py 프로젝트: cycle13/PySDM
    def plot(self, state, t):
        s = self.setup

        if t == 0:
            analytic_solution = s.spectrum.size_distribution
        else:
            analytic_solution = lambda x: s.norm_factor * s.kernel.analytic_solution(
                x=x, t=t, x_0=s.X0, N_0=s.n_part)

        dm = np.diff(self.v_bins)
        dr = np.diff(self.r_bins)

        pdf_m_x = self.v_bins[:-1] + dm / 2
        pdf_m_y = analytic_solution(pdf_m_x)

        pdf_r_x = self.r_bins[:-1] + dr / 2
        pdf_r_y = pdf_m_y * dm / dr * pdf_r_x

        pyplot.plot(pdf_r_x * si.metres / si.micrometres,
                    pdf_r_y * phys.volume(radius=pdf_r_x) * s.rho / s.dv *
                    si.kilograms / si.grams,
                    color='black')

        vals = np.empty(len(self.r_bins) - 1)
        tmp = np.empty((1, 1))
        moment_0 = state.particles.backend.array(1, dtype=int)
        moments = state.particles.backend.array((1, 1), dtype=float)
        for i in range(len(vals)):
            state.moments(moment_0,
                          moments,
                          specs={'volume': (1, )},
                          attr_range=(self.v_bins[i], self.v_bins[i + 1]))
            state.particles.backend.download(moments, tmp)
            vals[i] = tmp[0, 0]
            state.particles.backend.download(moment_0, tmp)
            vals[i] *= tmp[0, 0]
            vals[i] *= s.rho / s.dv
            vals[i] /= (np.log(self.r_bins[i + 1]) - np.log(self.r_bins[i]))

        pyplot.step(self.r_bins[:-1] * si.metres / si.micrometres,
                    vals * si.kilograms / si.grams,
                    where='post',
                    label=f"t = {t}s")
        pyplot.grid()
        pyplot.xscale('log')
        pyplot.xlabel('particle radius [µm]')
        pyplot.ylabel('dm/dlnr [g/m^3/(unit dr/r)]')
        pyplot.legend()
예제 #10
0
def test_initialisation(plot=False):
    # TODO: seed as a part of setup?
    setup = Setup()
    setup.steps = []
    setup.grid = (10, 5)
    setup.n_sd_per_gridbox = 2000

    simulation = Simulation(setup, None)

    n_bins = 32
    n_levels = setup.grid[1]
    n_cell = np.prod(np.array(setup.grid))
    n_moments = 1

    v_bins = np.logspace((np.log10(phys.volume(radius=setup.r_min))),
                         (np.log10(phys.volume(radius=10 * setup.r_max))),
                         num=n_bins,
                         endpoint=True)
    r_bins = phys.radius(volume=v_bins)

    histogram_dry = np.empty((len(r_bins) - 1, n_levels))
    histogram_wet = np.empty_like(histogram_dry)

    moment_0 = setup.backend.array(n_cell, dtype=int)
    moments = setup.backend.array((n_moments, n_cell), dtype=float)
    tmp = np.empty(n_cell)

    # Act (moments)
    simulation.run()
    particles = simulation.particles
    environment = simulation.particles.environment
    rhod = setup.backend.to_ndarray(environment["rhod"]).reshape(
        setup.grid).mean(axis=0)

    for i in range(len(histogram_dry)):
        particles.state.moments(moment_0,
                                moments,
                                specs={},
                                attr_name='dry volume',
                                attr_range=(v_bins[i], v_bins[i + 1]))
        particles.backend.download(moment_0, tmp)
        histogram_dry[i, :] = tmp.reshape(
            setup.grid).sum(axis=0) / (particles.mesh.dv * setup.grid[0])

        particles.state.moments(moment_0,
                                moments,
                                specs={},
                                attr_name='volume',
                                attr_range=(v_bins[i], v_bins[i + 1]))
        particles.backend.download(moment_0, tmp)
        histogram_wet[i, :] = tmp.reshape(
            setup.grid).sum(axis=0) / (particles.mesh.dv * setup.grid[0])

    # Plot
    if plot:
        for level in range(0, n_levels):
            color = str(.5 * (2 + (level / (n_levels - 1))))
            pyplot.step(r_bins[:-1] * si.metres / si.micrometres,
                        histogram_dry[:, level] / si.metre**3 *
                        si.centimetre**3,
                        where='post',
                        color=color,
                        label="level " + str(level))
            pyplot.step(r_bins[:-1] * si.metres / si.micrometres,
                        histogram_wet[:, level] / si.metre**3 *
                        si.centimetre**3,
                        where='post',
                        color=color,
                        linestyle='--')
        pyplot.grid()
        pyplot.xscale('log')
        pyplot.xlabel('particle radius [µm]')
        pyplot.ylabel('concentration per bin [cm^{-3}]')
        pyplot.legend()
        pyplot.show()

    # Assert - location of maximum
    for level in range(n_levels):
        real_max = setup.spectrum_per_mass_of_dry_air.distribution_params[2]
        idx_max_dry = np.argmax(histogram_dry[:, level])
        idx_max_wet = np.argmax(histogram_wet[:, level])
        assert r_bins[idx_max_dry] < real_max < r_bins[idx_max_dry + 1]
        assert idx_max_dry < idx_max_wet

    # Assert - total number
    for level in reversed(range(n_levels)):
        mass_conc_dry = np.sum(histogram_dry[:, level]) / rhod[level]
        mass_conc_wet = np.sum(histogram_wet[:, level]) / rhod[level]
        mass_conc_STP = setup.spectrum_per_mass_of_dry_air.norm_factor
        assert .5 * mass_conc_STP < mass_conc_dry < 1.5 * mass_conc_STP
        np.testing.assert_approx_equal(mass_conc_dry, mass_conc_wet)

    # Assert - decreasing number density
    total_above = 0
    for level in reversed(range(n_levels)):
        total_below = np.sum(histogram_dry[:, level])
        assert total_below > total_above
        total_above = total_below
예제 #11
0
 def get(self):
     self.download_moment_to_buffer('volume', rank=0,
                                    attr_range=[0, phys.volume(self.radius_threshold)])
     self.buffer[:] /= self.particles.mesh.dv
     const.convert_to(self.buffer, const.si.centimetre**-3)
     return self.buffer
예제 #12
0
    def __call__(self):
        self.environment.sync()

        state = self.particles.state
        state.sort_by_cell_id(
        )  # TODO +what about droplets that precipitated out of the domain
        compute_cell_start(self.cell_start, state.cell_id, state.idx,
                           state.SD_num)

        v = state.get_backend_storage("volume")
        n = state.n
        vdry = state.get_backend_storage("dry volume")

        if self.scheme == 'scipy.odeint':
            for cell_id in range(self.particles.mesh.n_cell):
                cell_start = self.cell_start[cell_id]
                cell_end = self.cell_start[cell_id + 1]
                n_sd_in_cell = cell_end - cell_start
                if n_sd_in_cell == 0:
                    continue

                y0 = np.empty(n_sd_in_cell + idx_rw)
                y0[idx_rhod] = self.environment['rhod'][cell_id]
                y0[idx_thd] = self.environment['thd'][cell_id]
                y0[idx_qv] = self.environment['qv'][cell_id]
                y0[idx_rw:] = phys.radius(
                    volume=v[state.idx[cell_start:cell_end]])
                integ = ode.solve_ivp(
                    _ODESystem(
                        self.kappa, vdry[state.idx[cell_start:cell_end]],
                        n[state.idx[cell_start:cell_end]],
                        (self.environment.get_predicted("rhod")[cell_id] -
                         self.environment['rhod'][cell_id]) / self.dt,
                        (self.environment.get_predicted('thd')[cell_id] -
                         self.environment['thd'][cell_id]) / self.dt,
                        (self.environment.get_predicted('qv')[cell_id] -
                         self.environment['qv'][cell_id]) / self.dt,
                        self.environment.get_predicted("rhod")[cell_id] *
                        self.environment.dv),
                    (0., self.dt),
                    y0,
                    method='BDF',
                    # rtol=1e-6,
                    atol=1e-9,
                    # first_step=self.dt,
                    t_eval=[self.dt])
                assert integ.success, integ.message

                dm = 0
                for i in range(cell_end - cell_start):
                    x_new = phys.volume(radius=integ.y[idx_rw + i])
                    x_old = v[state.idx[cell_start + i]]
                    nd = n[state.idx[cell_start + i]]
                    dm += nd * (x_new - x_old) * rho_w
                    v[state.idx[cell_start + i]] = x_new

                m_d = self.environment.get_predicted(
                    'rhod')[cell_id] * self.environment.dv
                dq_sum = -dm / m_d
                dq_ode = integ.y[idx_qv] - self.environment.get_predicted(
                    'qv')[cell_id]

                #dth_sum =
                dth_ode = integ.y[idx_thd] - self.environment.get_predicted(
                    'thd')[cell_id]

                # TODO: move to a separate test
                #np.testing.assert_approx_equal(dq_ode, dq_sum, 4)
                #np.testing.assert_approx_equal(dth_ode, dth_sum)

                self.environment.get_predicted('qv')[cell_id] += dq_sum
                self.environment.get_predicted('thd')[cell_id] += dth_ode
        else:
            raise NotImplementedError()