def bb79_cloud_evolve(N=50000, Mcloud=1. | units.MSun, Rcloud=3.2e16 | units.cm, omega=1.56e-12 | units.rad / units.s, density_perturb=0.5, t_total=8.3e11 | units.s): # mean density of the cloud rho_uni = Mcloud / (4. / 3. * numpy.pi * Rcloud**3) print(" ** mean density = ", rho_uni.in_(units.g / units.cm**3)) # free fall time of the cloud t_ff = numpy.sqrt(3. * numpy.pi / (32. * units.constants.G * rho_uni)) print(" ** free-fall time = ", t_ff.in_(units.yr)) conv = nbody_system.nbody_to_si(Mcloud, Rcloud) sph = Fi(conv) # the initial conditions of BB79 parts_bb79 = bb79_cloud(targetN=N, omega=omega, rho_perturb=0.5, ethep_ratio=0.25, convert_nbody=conv, base_grid=body_centered_grid_unit_cube).result sph.gas_particles.add_particles(parts_bb79) sph.parameters.use_hydro_flag = True sph.parameters.isothermal_flag = True sph.parameters.integrate_entropy_flag = False sph.parameters.gamma = 1 sph.parameters.verbosity = 0 sph.parameters.timestep = 0.1 * t_ff print( "**evolving to time: (end time = ~ {0:.3f} t_ff)".format(t_total / t_ff)) # setting snapshots to be plotted nplot = 10 if nplot > 1: plot_timestep = t_total / (nplot - 1) else: plot_timestep = t_total # evolution of the cloud for i in range(nplot): ttarget = i * plot_timestep t_tff = ttarget / t_ff sph.evolve_model(ttarget) plot_i = "bb79_rho_{0:03d}.png".format(i) tt_tff = "{0:.3f}".format(t_tff) title_i = "$%s\,t_{\mathrm{ff}}$" % (tt_tff) print("\t {0:.3f} t_ff -> {1}".format(t_tff, plot_i)) plot_sph_rho(sph, N=300, grid_size=0.025 | units.parsec, plot_name=plot_i, plot_title=title_i) sph.stop()
def evolve(cluster,cloud, converter_grav,converter_sph, t_end, dt_sph, dt_diag,\ sink=True, merge=False): with open(printout_file, 'a') as pf: pf.write('Setting up the gravity code and the hydro code...\n') '''# Initialising the direct N-body integrator gravity = ph4(converter_grav) gravity.particles.add_particles(cluster)''' # Initialising the hydro code sph = Fi(converter_sph, mode="openmp") sph.gas_particles.add_particles(cloud) sph.dm_particles.add_particles(cluster) sph.parameters.radiation_flag = False #sph.parameters.isothermal_flag = True #sph.parameters.integrate_entropy_flag = False #should we consider isothermal process or adiabatic one? sph.parameters.timestep = dt_sph #sph.parameters.eps_is_h_flag = False # h_smooth is constant #eps = 0.1 | units.parsec #sph.parameters.gas_epsilon = eps #sph.parameters.sph_h_const = eps #cloud.h_smooth= eps '''# Building a bridge between hydro and grav with open(printout_file, 'a') as pf: pf.write('Bridging...\n') grav_sph = bridge.Bridge(use_threading=False) grav_sph.add_system(gravity, (sph,)) grav_sph.add_system(sph, (gravity,)) grav_sph.timestep = dt_bridge''' # Setting up channels from code to cloud and cluster #channel_from_grav_to_cluster = gravity.particles.new_channel_to(cluster) channel_from_sph_to_cloud = sph.gas_particles.new_channel_to(cloud) channel_from_sph_to_cluster = sph.dm_particles.new_channel_to(cluster) # consider star formation if sink == True: with open(printout_file, 'a') as pf: pf.write('[Star formation is considered.]\n') stars = Particles(0) sph.dm_particles.add_particles(stars) density_threshold = Jeans_density(M=sph.gas_particles.mass.max()) sph.parameters.stopping_condition_maximum_density = density_threshold density_limit_detection = sph.stopping_conditions.density_limit_detection density_limit_detection.enable() if merge == True: merge_radius = 1e-4 | units.parsec # 1 pc = 206265 AU with open(printout_file, 'a') as pf: pf.write('[Star merging is considered.]\n') # Initialize data lists (Lagrangian radii and relative total energy) lr_cloud_list = [Lagrange_radii(cloud, converter_sph)] lr_cluster_list = [Lagrange_radii(cluster, converter_grav)] E0_cloud = get_energy(cloud) Etot0_cloud = E0_cloud[-1] E_cloud_list = [E0_cloud / Etot0_cloud] E0_cluster = get_energy(cluster) Etot0_cluster = E0_cluster[-1] E_cluster_list = [E0_cluster / Etot0_cluster] n_formed_star = [0] # Start Evolving! # unify the unit of times unit_time = units.Myr t_end = t_end.in_(unit_time) dt_diag = dt_diag.in_(unit_time) dt_sph = dt_sph.in_(unit_time) times = quantities.arange(0. | unit_time, t_end + dt_diag, dt_diag) with open(printout_file, 'a') as pf: pf.write('\nStart evolving the molecular cloud...\n') pf.write( f'End time = {t_end}; Diagnostic timestep = {dt_diag}; sph code timestep = {dt_sph}.\n' ) for i, t in enumerate(times): with open(printout_file, 'a') as pf: pf.write(f'---------- Time = {t.in_(units.Myr)} ----------\n') # calculate the dynamical(dyn), half-mass relaxation(rh), and free-fall(ff) timescales # of both the cloud and the cluster systems t_dyn_cloud, t_rh_cloud, t_ff_cloud = timescale(cloud, unit_time) t_dyn_cluster, t_rh_cluster, t_ff_cluster = timescale( cluster, unit_time) all_timescales = [ t_dyn_cloud, t_rh_cloud, t_ff_cloud, t_dyn_cluster, t_rh_cluster, t_ff_cluster ] | unit_time # check if the bridge timestep should be reduced if all_timescales.amax() < 10 * dt_sph: dt_sph_old = dt_sph dt_sph = all_timescales.amax() / 10. with open(printout_file, 'a') as pf: pf.write( f'Change the bridge timestep from {dt_sph_old} to {dt_sph}.\n' ) if sink == True: # make sure at this time, elements in 'stars' and 'sph.gas_particles' are the same resolve_sinks(sph, stars, cloud, density_threshold, t) # evolve for one diagnostic timestep #grav_sph.evolve_model(t, timestep=dt_bridge) sph.evolve_model(t, timestep=dt_sph) #channel_from_grav_to_cluster.copy() channel_from_sph_to_cloud.copy() channel_from_sph_to_cluster.copy() if len(stars) > 0: newstars = cluster.select_array( lambda birth_age: birth_age >= 0. | unit_time, ["birth_age"]) cluster.remove_particles(newstars) # merge two stars if they are too close to each other (distance < merge_radius) # typically we don't consider merging event since it is very rare given a reasonable merge radius if merge == True: merge_stars(sph, stars, merge_radius) with open(printout_file, 'a') as pf: pf.write('Number of stars in `cluster`= %d; in `stars` = %d; in `sph.dm_particles`= %d.\n'\ %(len(cluster), len(stars), len(sph.dm_particles))) # make snapshots plot_cloud_cluster(cluster, sph, stars, title='{0}'.format(float(t.value_in(units.Myr))),\ vrange=[-5,3]) # save data (energy will be added afterwards) lr_cloud = Lagrange_radii(cloud, converter_sph) lr_cloud_list.append(lr_cloud) lr_cluster = Lagrange_radii(cluster, converter_grav) lr_cluster_list.append(lr_cluster) E_cloud = get_energy(cloud, norm=Etot0_cloud) E_cloud_list.append(E_cloud) E_cluster = get_energy(cluster, norm=Etot0_cluster) E_cluster_list.append(E_cluster) n_formed_star.append(len(stars)) # save data instantaneously lr_data = np.concatenate( ([t.value_in(unit_time)], lr_cloud, lr_cluster)) E_data = np.concatenate(([t.value_in(unit_time)], E_cloud, E_cluster)) with open('lr_data.txt', 'a') as f_lr_data: f_lr_data.write(','.join(str(x) for x in lr_data) + '\n') with open('E_data.txt', 'a') as f_E_data: f_E_data.write(','.join(str(x) for x in E_data) + '\n') with open('formed_star_data.txt', 'a') as f_fs_data: f_fs_data.write('%f,%d\n' % (t.value_in(unit_time), len(stars))) with open(printout_file, 'a') as pf: pf.write(f'Finished.\n') #gravity.stop() sph.stop() return times.value_in( unit_time ), n_formed_star, lr_cloud_list, lr_cluster_list, E_cloud_list, E_cluster_list
N_particles = 1000 # Number of SPH particles disk = ProtoPlanetaryDisk(N_particles, convert_nbody=converter, densitypower=1.5, Rmin=0.5, Rmax=100, q_out=1.) # Rmin and Rmax in AU disk_particles = disk.result # Disk particles disk_particles.h_smooth = 0.06 | units.au # Smoothing length # Rotate the disk 90 degrees around x axis disk = rotate(disk_particles, 90, 0, 0) # Start SPH code and add particles sph = Fi(converter) sph.gas_particles.add_particles( disk_particles) # Disk particles are added as gas particles sph.dm_particles.add_particles( stars[0]) # Star is added as dark matter particle # Evolve code in time steps t_end = 100 | units.yr dt = 1 | units.yr t = 0 | units.yr while t < t_end: t += dt print t sph.evolve_model(t)
def run_molecular_cloud(N=100, Mcloud=100. | units.MSun, Rcloud=1. | units.parsec): conv = nbody_system.nbody_to_si(Mcloud, Rcloud) rho_cloud = 3. * Mcloud / (4. * numpy.pi * Rcloud**3) print rho_cloud tff = 0.5427 / numpy.sqrt(constants.G * rho_cloud) print "t_ff=", tff.value_in(units.Myr), 'Myr' dt = 5.e-2 | units.Myr tend = 1.0 | units.Myr # tend=2.0 | units.Myr parts = molecular_cloud(targetN=N, convert_nbody=conv, base_grid=body_centered_grid_unit_cube, seed=100).result sph = Fi(conv, number_of_workers=3) sph.parameters.use_hydro_flag = True sph.parameters.radiation_flag = False sph.parameters.gamma = 1 sph.parameters.isothermal_flag = True sph.parameters.integrate_entropy_flag = False sph.parameters.timestep = dt sph.parameters.verbosity = 0 sph.parameters.eps_is_h_flag = False # h_smooth is constant eps = 0.1 | units.parsec sph.parameters.gas_epsilon = eps sph.parameters.sph_h_const = eps parts.h_smooth = eps print 'eps-h flag', sph.get_eps_is_h(), sph.get_consthsm() expected_dt = 0.2 * numpy.pi * numpy.power(eps, 1.5) / numpy.sqrt( constants.G * Mcloud / N) print "dt_exp=", expected_dt.value_in(units.Myr) print "dt=", dt print "eps=", sph.parameters.gas_epsilon.in_(units.parsec) sph.gas_particles.add_particles(parts) #grav=copycat(Fi, sph, conv) #sys=bridge(verbose=False) #sys.add_system(sph,(grav,),False) channel_from_sph_to_parts = sph.gas_particles.new_channel_to(parts) channel_from_parts_to_sph = parts.new_channel_to(sph.gas_particles) i = 0 L = 6 E0 = 0.0 ttarget = 0.0 | units.Myr plot_hydro(ttarget, sph, i, L) while ttarget < tend: ttarget = float(i) * dt print ttarget sph.evolve_model(ttarget, timestep=dt) E = sph.gas_particles.kinetic_energy( ) + sph.gas_particles.potential_energy( ) + sph.gas_particles.thermal_energy() E_th = sph.gas_particles.thermal_energy() if i == 0: E0 = E Eerr = (E - E0) / E0 print 'energy=', E, 'energy_error=', Eerr, 'e_th=', E_th channel_from_sph_to_parts.copy() """ filename = 'm400k_r10pc_e01_'+ str(i).zfill(2) + '.dat' print filename parts_sorted = parts.sorted_by_attribute('rho') write_output(filename, parts_sorted, conv) """ plot_hydro(ttarget, sph, i, L) i = i + 1 plot_hydro_and_stars(ttarget, sph, L) sph.stop() return parts