def __init__(self, setup, xrange): self.setup = setup self.v_bins = np.logspace((np.log10(xrange[0])), (np.log10(xrange[1])), num=64, endpoint=True) self.r_bins = phys.radius(volume=self.v_bins)
def __init__(self, kappa, xd: np.ndarray, n: np.ndarray, drhod_dt, dthd_dt, dqv_dt, m_d): self.kappa = kappa self.rd = phys.radius(volume=xd) self.n = n self.dqv_dt = dqv_dt self.dthd_dt = dthd_dt self.drhod_dt = drhod_dt self.m_d = m_d
def __init__(self, kappa, dry_volume: np.ndarray, n: np.ndarray, dthd_dt, dqv_dt, m_d_mean, rhod_mean, qt): self.kappa = kappa self.rd = phys.radius(volume=dry_volume) self.n = n self.dqv_dt = dqv_dt self.dthd_dt = dthd_dt self.rhod_mean = rhod_mean self.m_d_mean = m_d_mean self.qt = qt
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
def get(self): self.download_moment_to_buffer('volume', rank=1 / 3) self.buffer[:] *= phys.radius(volume=1) const.convert_to(self.buffer, const.si.micrometre) return self.buffer
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()