def compute_mass_rate_derivative_AS_num(w_s, R_p, T_p, rho_p, T_amb, p_amb, S_amb, e_s_amb, L_v, K, D_v, sigma_p): m_p = mp.compute_mass_from_radius_jit(R_p, rho_p) m_s = w_s * m_p h = m_p * machine_epsilon_sqrt m_p1 = m_p + h w_s1 = m_s / m_p1 rho_p1 = mp.compute_density_AS_solution(w_s1, T_p) R_p1 = mp.compute_radius_from_mass_jit(m_p1, rho_p1) sigma_p1 = mp.compute_surface_tension_AS(w_s1, T) gamma = mp.compute_mass_rate_AS(w_s1, R_p1, T_p, rho_p1, T_amb, p_amb, S_amb, e_s_amb, L_v, K, D_v, sigma_p1) m_p2 = m_p - h w_s2 = m_s / m_p2 rho_p2 = mp.compute_density_AS_solution(w_s2, T_p) R_p2 = mp.compute_radius_from_mass_jit(m_p2, rho_p2) sigma_p2 = mp.compute_surface_tension_AS(w_s2, T) gamma -= mp.compute_mass_rate_AS(w_s2, R_p2, T_p, rho_p2, T_amb, p_amb, S_amb, e_s_amb, L_v, K, D_v, sigma_p2) return gamma / (m_p1 - m_p2)
def compute_kernel_Long_Bott_m(m_i, m_j, mass_density): R_i = compute_radius_from_mass_jit(m_i, mass_density) R_j = compute_radius_from_mass_jit(m_j, mass_density) return compute_kernel_Long_Bott_R(R_i, R_j)
def collision_step_Long_Bott_Ecol_const_2D_multicomp_np( xis, m_w, m_s, radii, vel, mass_densities, dt_over_dV, E_col_grid, no_cols): no_SIPs = xis.shape[0] rnd = np.random.rand((no_SIPs * (no_SIPs - 1)) // 2) # ind_kernel = create_kernel_index_array( # radii, no_SIPs, # R_kernel_low_log, bin_factor_R_log, no_kernel_bins) # check each i-j combination for a possible collection event cnt = 0 for i in range(0, no_SIPs - 1): for j in range(i + 1, no_SIPs): if xis[i] <= xis[j]: ind_min = i ind_max = j else: ind_min = j ind_max = i xi_min = xis[ind_min] # = nu_i in Unt xi_max = xis[ind_max] # = nu_j in Unt m_w_min = m_w[ind_min] # = mu_i in Unt, not necc. the smaller mass m_w_max = m_w[ind_max] # = mu_j in Unt, not necc. the larger mass m_s_min = m_s[ind_min] # = mu_i in Unt, not necc. the smaller mass m_s_max = m_s[ind_max] # = mu_j in Unt, not necc. the larger mass p_crit = xi_max * dt_over_dV \ * compute_kernel_hydro( radii[i], radii[j], E_col_grid, # abs difference of 2D vectors math.sqrt( (vel[0,i] - vel[0,j])**2 + (vel[1,i] - vel[1,j])**2 ) ) if p_crit > 1.0: # multiple collection xi_col = p_crit * xi_min # p_crit = xi_col / xi_min m_w[ind_min] = m_w_min + p_crit * m_w_max m_s[ind_min] = m_s_min + p_crit * m_s_max # mass changed: update radius # IMPORTANT: need to put (m_w + m_s) in paranthesis for jit radii[ind_min] =\ compute_radius_from_mass_jit((m_w[ind_min] + m_s[ind_min]), mass_densities[ind_min]) # radii[ind_min] =\ # compute_radius_from_mass_jit(m_w[ind_min] + m_s[ind_min], # mass_densities[ind_min]) xis[ind_max] -= xi_col # rad of ind_min changed -> update kernel index: # ind_kernel[ind_min] = \ # compute_kernel_index(radii[ind_min], R_kernel_low_log, # bin_factor_R_log, no_kernel_bins) no_cols[1] += 1 elif p_crit > rnd[cnt]: no_cols[0] += 1 xi_rel_dev = (xi_max - xi_min) / xi_max if xi_rel_dev < 1.0E-5: print("xi_i approx xi_j, xi_rel_dev =", xi_rel_dev, " in collision") xi_ges = xi_min + xi_max m_w[ind_min] = 2.0 * ( xi_min*m_w_min + xi_max*m_w_max ) \ / xi_ges m_s[ind_min] = 2.0 * ( xi_min*m_s_min + xi_max*m_s_max ) \ / xi_ges m_w[ind_max] = m_w[ind_min] m_s[ind_max] = m_s[ind_min] # IMPORTANT: need to put (m_w + m_s) in paranthesis for jit radii[ind_min] =\ compute_radius_from_mass_jit((m_w[ind_min] + m_s[ind_min]), mass_densities[ind_min]) # radii[ind_min] =\ # compute_radius_from_mass_jit(m_w[ind_min]+m_s[ind_min], # mass_densities[ind_min]) radii[ind_max] = radii[ind_min] xis[ind_max] = 0.5 * 0.7 * xi_ges xis[ind_min] = 0.5 * xi_ges - xis[ind_max] # radius of ind_min AND ind_max changed to same radii # -> update kernel ind: # ind_kernel[ind_min] = \ # compute_kernel_index(radii[ind_min], R_kernel_low_log, # bin_factor_R_log, no_kernel_bins) # ind_kernel[ind_max] = ind_kernel[ind_min] else: m_w[ind_min] += m_w_max m_s[ind_min] += m_s_max # IMPORTANT: need to put (m_w + m_s) in paranthesis for jit radii[ind_min] =\ compute_radius_from_mass_jit((m_w[ind_min] + m_s[ind_min]), mass_densities[ind_min]) # radii[ind_min] =\ # compute_radius_from_mass_jit(m_w[ind_min]+m_w[ind_min], # mass_densities[ind_min]) xis[ind_max] -= xi_min # rad of ind_min changed -> update kernel index: # ind_kernel[ind_min] = \ # compute_kernel_index(radii[ind_min], R_kernel_low_log, # bin_factor_R_log, no_kernel_bins) cnt += 1
def collision_step_Ecol_grid_R_np(xis, masses, radii, vel, mass_densities, dt_over_dV, E_col_grid, no_kernel_bins, R_kernel_low_log, bin_factor_R_log, no_cols): no_SIPs = xis.shape[0] rnd = np.random.rand((no_SIPs * (no_SIPs - 1)) // 2) ind_kernel = create_kernel_index_array(radii, no_SIPs, R_kernel_low_log, bin_factor_R_log, no_kernel_bins) # check each i-j combination for a possible collection event cnt = 0 for i in range(0, no_SIPs - 1): for j in range(i + 1, no_SIPs): if xis[i] <= xis[j]: ind_min = i ind_max = j else: ind_min = j ind_max = i xi_min = xis[ind_min] # = nu_i in Unt xi_max = xis[ind_max] # = nu_j in Unt m_min = masses[ ind_min] # = mu_i in Unt, not necc. the smaller mass m_max = masses[ind_max] # = mu_j in Unt, not necc. the larger mass p_crit = xi_max * dt_over_dV \ * compute_kernel_hydro( radii[i], radii[j], E_col_grid[ind_kernel[i], ind_kernel[j]], abs(vel[i]-vel[j])) if p_crit > 1.0: # multiple collection xi_col = p_crit * xi_min masses[ind_min] = (xi_min * m_min + xi_col * m_max) / xi_min # mass changed: update radius radii[ind_min] =\ compute_radius_from_mass_jit(masses[ind_min], mass_densities[ind_min]) xis[ind_max] -= xi_col # rad of ind_min changed -> update kernel index: ind_kernel[ind_min] = \ compute_kernel_index(radii[ind_min], R_kernel_low_log, bin_factor_R_log, no_kernel_bins) no_cols[1] += 1 elif p_crit > rnd[cnt]: no_cols[0] += 1 xi_rel_dev = (xi_max - xi_min) / xi_max if xi_rel_dev < 1.0E-5: print("xi_i approx xi_j, xi_rel_dev =", xi_rel_dev, " in collision") xi_ges = xi_min + xi_max masses[ind_min] = 2.0 * ( xi_min*m_min + xi_max*m_max ) \ / xi_ges masses[ind_max] = masses[ind_min] radii[ind_min] =\ compute_radius_from_mass_jit(masses[ind_min], mass_densities[ind_min]) radii[ind_max] = radii[ind_min] xis[ind_max] = 0.5 * 0.7 * xi_ges xis[ind_min] = 0.5 * xi_ges - xis[ind_max] # radius of ind_min AND ind_max changed to same radii # -> update kernel ind: ind_kernel[ind_min] = \ compute_kernel_index(radii[ind_min], R_kernel_low_log, bin_factor_R_log, no_kernel_bins) ind_kernel[ind_max] = ind_kernel[ind_min] else: masses[ind_min] += m_max radii[ind_min] =\ compute_radius_from_mass_jit(masses[ind_min], mass_densities[ind_min]) xis[ind_max] -= xi_min # rad of ind_min changed -> update kernel index: ind_kernel[ind_min] = \ compute_kernel_index(radii[ind_min], R_kernel_low_log, bin_factor_R_log, no_kernel_bins) cnt += 1
def analyze_sim_data(kappa, mass_density, dV, no_sims, start_seed, no_bins, load_dir): # f"/mnt/D/sim_data/col_box_mod/results/{kernel_name}/{gen_method}/kappa_{kappa}/dt_{int(dt)}/" # f"/mnt/D/sim_data/col_box_mod/results/{kernel_name}/{gen_method}/kappa_{kappa}/dt_{int(dt)}/perm/" save_times = np.load(load_dir + f"save_times_{start_seed}.npy") seed_list = np.arange(start_seed, start_seed + no_sims * 2, 2) masses_vs_time = [] xis_vs_time = [] for seed in seed_list: # convert to kg masses_vs_time.append(1E-18 * np.load(load_dir + f"masses_vs_time_{seed}.npy")) # masses_vs_time.append(np.load(load_dir + f"masses_vs_time_{seed}.npy")) xis_vs_time.append(np.load(load_dir + f"xis_vs_time_{seed}.npy")) masses_vs_time_T = [] xis_vs_time_T = [] no_times = len(save_times) for time_n in range(no_times): masses_ = [] xis_ = [] for i, m in enumerate(masses_vs_time): masses_.append(m[time_n]) xis_.append(xis_vs_time[i][time_n]) masses_vs_time_T.append(masses_) xis_vs_time_T.append(xis_) f_m_num_avg_vs_time = np.zeros((no_times, no_bins), dtype=np.float64) f_m_num_std_vs_time = np.zeros((no_times, no_bins), dtype=np.float64) g_m_num_avg_vs_time = np.zeros((no_times, no_bins), dtype=np.float64) g_m_num_std_vs_time = np.zeros((no_times, no_bins), dtype=np.float64) g_ln_r_num_avg_vs_time = np.zeros((no_times, no_bins), dtype=np.float64) g_ln_r_num_std_vs_time = np.zeros((no_times, no_bins), dtype=np.float64) bins_mass_vs_time = np.zeros((no_times, no_bins + 1), dtype=np.float64) bins_mass_width_vs_time = np.zeros((no_times, no_bins), dtype=np.float64) bins_rad_width_log_vs_time = np.zeros((no_times, no_bins), dtype=np.float64) bins_mass_centers = [] bins_rad_centers = [] m_max_vs_time = np.zeros(no_times, dtype=np.float64) m_min_vs_time = np.zeros(no_times, dtype=np.float64) bin_factors_vs_time = np.zeros(no_times, dtype=np.float64) moments_vs_time = np.zeros((no_times, 4, no_sims), dtype=np.float64) last_bin_factor = 1.0 # last_bin_factor = 1.5 first_bin_factor = 1.0 # first_bin_factor = 0.8 for time_n, masses in enumerate(masses_vs_time_T): xis = xis_vs_time_T[time_n] masses_sampled = np.concatenate(masses) xis_sampled = np.concatenate(xis) # print(time_n, xis_sampled.min(), xis_sampled.max()) m_min = masses_sampled.min() m_max = masses_sampled.max() # convert to microns R_min = compute_radius_from_mass_jit(1E18 * m_min, mass_density) R_max = compute_radius_from_mass_jit(1E18 * m_max, mass_density) xi_min = xis_sampled.min() xi_max = xis_sampled.max() print(kappa, time_n, f"{xi_max/xi_min:.3e}", xis_sampled.shape[0] / no_sims, R_min, R_max) m_min_vs_time[time_n] = m_min m_max_vs_time[time_n] = m_max bin_factor = (m_max / m_min)**(1.0 / no_bins) bin_factors_vs_time[time_n] = bin_factor # bin_log_dist = np.log(bin_factor) # bin_log_dist_half = 0.5 * bin_log_dist # add dummy bins for overflow # bins_mass = np.zeros(no_bins+3,dtype=np.float64) bins_mass = np.zeros(no_bins + 1, dtype=np.float64) bins_mass[0] = m_min # bins_mass[0] = m_min / bin_factor for bin_n in range(1, no_bins + 1): bins_mass[bin_n] = bins_mass[bin_n - 1] * bin_factor # the factor 1.01 is for numerical stability: to be sure # that m_max does not contribute to a bin larger than the # last bin # bins_mass[-1] *= 1.0001 bins_mass[-1] *= last_bin_factor # the factor 0.99 is for numerical stability: to be sure # that m_min does not contribute to a bin smaller than the # 0-th bin # bins_mass[0] *= 0.9999 bins_mass[0] *= first_bin_factor # m_0 = m_min / np.sqrt(bin_factor) # bins_mass_log = np.log(bins_mass) bins_mass_vs_time[time_n] = bins_mass # convert to microns bins_rad = compute_radius_from_mass_vec(1E18 * bins_mass, mass_density) bins_mass_log = np.log(bins_mass) bins_rad_log = np.log(bins_rad) bins_mass_width = (bins_mass[1:] - bins_mass[:-1]) bins_rad_width = (bins_rad[1:] - bins_rad[:-1]) bins_rad_width_log = (bins_rad_log[1:] - bins_rad_log[:-1]) bins_mass_width_vs_time[time_n] = bins_mass_width bins_rad_width_log_vs_time[time_n] = bins_rad_width_log f_m_counts = np.histogram(masses_sampled, bins_mass)[0] # define centers on lin scale bins_mass_center_lin = 0.5 * (bins_mass[:-1] + bins_mass[1:]) bins_rad_center_lin = 0.5 * (bins_rad[:-1] + bins_rad[1:]) # define centers on the logarithmic scale bins_mass_center_log = np.exp(0.5 * (bins_mass_log[:-1] + bins_mass_log[1:])) bins_rad_center_log = np.exp(0.5 * (bins_rad_log[:-1] + bins_rad_log[1:])) # bins_mass are not equally spaced on log scale because of scaling # of the first and last bin # bins_mass_center_log = bins_mass[:-1] * np.sqrt(bin_factor) # bins_rad_center_log = bins_rad[:-1] * np.sqrt(bin_factor) # bins_mass_center_log = bins_mass[:-1] * 10**(1.0/(2.0*kappa)) # bins_rad_center_log = bins_rad[:-1] * 10**(1.0/(2.0*kappa)) # define the center of mass for each bin and set it as the "bin center" # bins_mass_center_COM = g_m_num_sampled/f_m_num_sampled # bins_rad_center_COM =\ # compute_radius_from_mass(bins_mass_center_COM*1.0E18, # c.mass_density_water_liquid_NTP) # set the bin "mass centers" at the right spot such that # f_avg_i in bin in = f(mm_i), where mm_i is the "mass center" m_avg = masses_sampled.sum() / xis_sampled.sum() bins_mass_center_exact = bins_mass[:-1] \ + m_avg * np.log(bins_mass_width\ / (m_avg * (1-np.exp(-bins_mass_width/m_avg)))) # convert to microns bins_rad_center_exact =\ compute_radius_from_mass_vec(1E18*bins_mass_center_exact, mass_density) bins_mass_centers.append( np.array((bins_mass_center_lin, bins_mass_center_log, bins_mass_center_exact))) bins_rad_centers.append( np.array((bins_rad_center_lin, bins_rad_center_log, bins_rad_center_exact))) ### STATISTICAL ANALYSIS OVER no_sim runs # get f(m_i) curve for each "run" with same bins for all ensembles f_m_num = [] g_m_num = [] g_ln_r_num = [] for sim_n, mass in enumerate(masses): # convert to microns rad = compute_radius_from_mass_vec(1E18 * mass, mass_density) f_m_num.append(np.histogram(mass, bins_mass, weights=xis[sim_n])[0] \ / (bins_mass_width * dV)) g_m_num.append(np.histogram(mass, bins_mass, weights=xis[sim_n]*mass)[0] \ / (bins_mass_width * dV)) # build g_ln_r = 3*m*g_m DIRECTLY from data g_ln_r_num.append( np.histogram(rad, bins_rad, weights=xis[sim_n]*mass)[0] \ / (bins_rad_width_log * dV) ) moments_vs_time[time_n, 0, sim_n] = xis[sim_n].sum() / dV for n in range(1, 4): moments_vs_time[time_n, n, sim_n] = np.sum(xis[sim_n] * mass**n) / dV # f_m_num = np.array(f_m_num) # g_m_num = np.array(g_m_num) # g_ln_r_num = np.array(g_ln_r_num) f_m_num_avg_vs_time[time_n] = np.average(f_m_num, axis=0) f_m_num_std_vs_time[time_n] = \ np.std(f_m_num, axis=0, ddof=1) / np.sqrt(no_sims) g_m_num_avg_vs_time[time_n] = np.average(g_m_num, axis=0) g_m_num_std_vs_time[time_n] = \ np.std(g_m_num, axis=0, ddof=1) / np.sqrt(no_sims) g_ln_r_num_avg_vs_time[time_n] = np.average(g_ln_r_num, axis=0) g_ln_r_num_std_vs_time[time_n] = \ np.std(g_ln_r_num, axis=0, ddof=1) / np.sqrt(no_sims) # convert to microns R_min_vs_time = compute_radius_from_mass_vec(1E18 * m_min_vs_time, mass_density) R_max_vs_time = compute_radius_from_mass_vec(1E18 * m_max_vs_time, mass_density) moments_vs_time_avg = np.average(moments_vs_time, axis=2) moments_vs_time_std = np.std(moments_vs_time, axis=2, ddof=1) \ / np.sqrt(no_sims) moments_vs_time_Unt = np.zeros_like(moments_vs_time_avg) # mom_fac = math.log(10)/(3*kappa) for time_n in range(no_times): for n in range(4): moments_vs_time_Unt[time_n,n] =\ math.log(bin_factors_vs_time[time_n]) / 3.0 \ * np.sum( g_ln_r_num_avg_vs_time[time_n] * (bins_mass_centers[time_n][1])**(n-1) ) # np.sum( g_ln_r_num_avg_vs_time[time_n] # * (bins_mass_centers[time_n][1])**(n-1) # * bins_rad_width_log_vs_time[time_n] ) # mom_fac * np.sum( g_m_num_avg_vs_time[time_n] # * (bins_mass_centers[time_n][1])**(n-1) ) np.save( load_dir + f"moments_vs_time_avg_no_sims_{no_sims}_no_bins_{no_bins}.npy", moments_vs_time_avg) np.save( load_dir + f"moments_vs_time_std_no_sims_{no_sims}_no_bins_{no_bins}.npy", moments_vs_time_std) np.save( load_dir + f"f_m_num_avg_vs_time_no_sims_{no_sims}_no_bins_{no_bins}.npy", f_m_num_avg_vs_time) np.save( load_dir + f"f_m_num_std_vs_time_no_sims_{no_sims}_no_bins_{no_bins}.npy", f_m_num_std_vs_time) np.save( load_dir + f"g_m_num_avg_vs_time_no_sims_{no_sims}_no_bins_{no_bins}.npy", g_m_num_avg_vs_time) np.save( load_dir + f"g_m_num_std_vs_time_no_sims_{no_sims}_no_bins_{no_bins}.npy", g_m_num_std_vs_time) np.save( load_dir + f"g_ln_r_num_avg_vs_time_no_sims_{no_sims}_no_bins_{no_bins}.npy", g_ln_r_num_avg_vs_time) np.save( load_dir + f"g_ln_r_num_std_vs_time_no_sims_{no_sims}_no_bins_{no_bins}.npy", g_ln_r_num_std_vs_time) np.save(load_dir + f"bins_mass_centers_{no_sims}_no_bins_{no_bins}.npy", bins_mass_centers) np.save(load_dir + f"bins_rad_centers_{no_sims}_no_bins_{no_bins}.npy", bins_rad_centers)
#D_s = 6. # mu = 10 nm D_s = 10. # mu = 10 nm #D_s = 20. # mu = 10 nm #D_s = 30. # mu = 10 nm #D_s = 100. # mu = 10 nm w_s = np.logspace(-5., np.log10(0.78), 10000) D_s *= 1E-3 R_s = 0.5 * D_s m_s_AS = mp.compute_mass_from_radius_jit(R_s, c.mass_density_AS_dry) rho_AS = mp.compute_density_AS_solution(w_s, T_p) m_p_AS = m_s_AS / w_s m_w_AS = m_p_AS - m_s_AS R_p_AS = mp.compute_radius_from_mass_jit(m_p_AS, rho_AS) m_s_SC = mp.compute_mass_from_radius_jit(R_s, c.mass_density_NaCl_dry) rho_SC = mp.compute_density_NaCl_solution(w_s, T_p) m_p_SC = m_s_SC / w_s m_w_SC = m_p_SC - m_s_SC R_p_SC = mp.compute_radius_from_mass_jit(m_p_SC, rho_SC) sigma_AS = mp.compute_surface_tension_AS(w_s, T_p) sigma_SC = atm.compute_surface_tension_water(T_p) S_eq_AS = mp.compute_equilibrium_saturation_AS(w_s, R_p_AS, T_p, rho_AS, sigma_AS) S_eq_SC = mp.compute_equilibrium_saturation_NaCl(m_w_SC, m_s_SC, w_s, R_p_SC, T_p, rho_SC, sigma_SC)