diff --git a/examples/SmallCosmoVolume/SmallCosmoVolume_cooling/small_cosmo_volume.yml b/examples/SmallCosmoVolume/SmallCosmoVolume_cooling/small_cosmo_volume.yml index 286b7591dd110616ff2f21d711469daf5317641a..0d93406eebc903c880a53ffa15f874e21902675b 100644 --- a/examples/SmallCosmoVolume/SmallCosmoVolume_cooling/small_cosmo_volume.yml +++ b/examples/SmallCosmoVolume/SmallCosmoVolume_cooling/small_cosmo_volume.yml @@ -51,6 +51,8 @@ Statistics: Scheduler: max_top_level_cells: 8 cell_split_size: 50 + cell_extra_gparts: 100 # (Optional) Number of spare gparts per top-level allocated at rebuild time for on-the-fly creation. + cell_extra_sparts: 100 # (Optional) Number of spare sparts per top-level allocated at rebuild time for on-the-fly creation. # Parameters related to the initial conditions InitialConditions: @@ -96,22 +98,40 @@ EAGLEEntropyFloor: Cool_over_density_threshold: 10. # Overdensity above which the EAGLE Cool limiter entropy floor can kick in. Cool_temperature_norm_K: 8000 # Temperature of the EAGLE Cool limiter entropy floor at the density threshold expressed in Kelvin. Cool_gamma_effective: 1. # Slope the of the EAGLE Cool limiter entropy floor - + +GEARPressureFloor: + jeans_factor: 10. # Number of particles required to suppose a resolved clump and avoid the pressure floor. + + # Cooling with Grackle 3.0 GrackleCooling: - cloudy_table: CloudyData_UVB=HM2012.h5 # Name of the Cloudy Table (available on the grackle bitbucket repository) - with_UV_background: 1 # Enable or not the UV background - redshift: -1 # Redshift to use (-1 means time based redshift) - with_metal_cooling: 1 # Enable or not the metal cooling - provide_volumetric_heating_rates: 0 # (optional) User provide volumetric heating rates - provide_specific_heating_rates: 0 # (optional) User provide specific heating rates - self_shielding_method: 0 # (optional) Grackle (<= 3) or Gear self shielding method - max_steps: 10000 # (optional) Max number of step when computing the initial composition - convergence_limit: 1e-2 # (optional) Convergence threshold (relative) for initial composition - thermal_time_myr: 5 + cloudy_table: CloudyData_UVB=HM2012.h5 # Name of the Cloudy Table (available on the grackle bitbucket repository) + with_UV_background: 1 # Enable or not the UV background + redshift: 0 # Redshift to use (-1 means time based redshift) + with_metal_cooling: 1 # Enable or not the metal cooling + provide_volumetric_heating_rates: 0 # (optional) User provide volumetric heating rates + provide_specific_heating_rates: 0 # (optional) User provide specific heating rates + max_steps: 10000 # (optional) Max number of step when computing the initial composition + convergence_limit: 1e-2 # (optional) Convergence threshold (relative) for initial composition + thermal_time_myr: 5 # (optional) Time (in Myr) for adiabatic cooling after a feedback event. + self_shielding_method: -1 # (optional) Grackle (1->3 for Grackle's ones, 0 for none and -1 for GEAR) + self_shielding_threshold_atom_per_cm3: 0.007 # Required only with GEAR's self shielding. Density threshold of the self shielding + +# GEAR chemistry model (Revaz and Jablonka 2018) GEARChemistry: - initial_metallicity: 0.01295 + initial_metallicity: 1 # Initial metallicity of the gas (mass fraction) + scale_initial_metallicity: 1 # Should we scale the initial metallicity with the solar one? -GEARPressureFloor: - jeans_factor: 10. # Number of particles required to suppose a resolved clump and avoid the pressure floor. + # GEAR star formation model (Revaz and Jablonka 2018) +GEARStarFormation: + star_formation_efficiency: 0.01 # star formation efficiency (c_*) + maximal_temperature: 3e4 # Upper limit to the temperature of a star forming particle + n_stars_per_particle: 4 + min_mass_frac: 0.5 + +# GEAR feedback model +GEARFeedback: + supernovae_energy_erg: 0.1e51 # Energy released by a single supernovae. + yields_table: chemistry-AGB+OMgSFeZnSrYBaEu-16072013.h5 # Table containing the yields. + discrete_yields: 0 # Should we use discrete yields or the IMF integrated one? diff --git a/src/cell.c b/src/cell.c index fceaed8ac83a7754114179d35c7c8f91ad6cf262..802ce7dbf6e00893fafd02aedc65ca84da3b058c 100644 --- a/src/cell.c +++ b/src/cell.c @@ -233,6 +233,7 @@ int cell_link_gparts(struct cell *c, struct gpart *gparts) { #endif c->grav.parts = gparts; + c->grav.parts_rebuild = gparts; /* Fill the progeny recursively, depth-first. */ if (c->split) { @@ -1154,7 +1155,12 @@ int cell_pack_sf_counts(struct cell *restrict c, pcells[0].stars.count = c->stars.count; pcells[0].stars.dx_max_part = c->stars.dx_max_part; + /* Pack this cell's data. */ + pcells[0].grav.delta_from_rebuild = c->grav.parts - c->grav.parts_rebuild; + pcells[0].grav.count = c->grav.count; + #ifdef SWIFT_DEBUG_CHECKS + /* Stars */ if (c->stars.parts_rebuild == NULL) error("Star particles array at rebuild is NULL! c->depth=%d", c->depth); @@ -1163,6 +1169,16 @@ int cell_pack_sf_counts(struct cell *restrict c, if (pcells[0].stars.delta_from_rebuild > 0 && c->depth == 0) error("Shifting the top-level pointer is not allowed!"); + + /* Grav */ + if (c->grav.parts_rebuild == NULL) + error("Grav. particles array at rebuild is NULL! c->depth=%d", c->depth); + + if (pcells[0].grav.delta_from_rebuild < 0) + error("Grav part pointer moved in the wrong direction!"); + + if (pcells[0].grav.delta_from_rebuild > 0 && c->depth == 0) + error("Shifting the top-level pointer is not allowed!"); #endif /* Fill in the progeny, depth-first recursion. */ @@ -1198,6 +1214,8 @@ int cell_unpack_sf_counts(struct cell *restrict c, #ifdef SWIFT_DEBUG_CHECKS if (c->stars.parts_rebuild == NULL) error("Star particles array at rebuild is NULL!"); + if (c->grav.parts_rebuild == NULL) + error("Grav particles array at rebuild is NULL!"); #endif /* Unpack this cell's data. */ @@ -1205,6 +1223,9 @@ int cell_unpack_sf_counts(struct cell *restrict c, c->stars.parts = c->stars.parts_rebuild + pcells[0].stars.delta_from_rebuild; c->stars.dx_max_part = pcells[0].stars.dx_max_part; + c->grav.count = pcells[0].grav.count; + c->grav.parts = c->grav.parts_rebuild + pcells[0].grav.delta_from_rebuild; + /* Fill in the progeny, depth-first recursion. */ int count = 1; for (int k = 0; k < 8; k++) @@ -1967,6 +1988,7 @@ void cell_split(struct cell *c, ptrdiff_t parts_offset, ptrdiff_t sparts_offset, c->progeny[k]->grav.count = bucket_count[k]; c->progeny[k]->grav.count_total = c->progeny[k]->grav.count; c->progeny[k]->grav.parts = &c->grav.parts[bucket_offset[k]]; + c->progeny[k]->grav.parts_rebuild = c->progeny[k]->grav.parts; } } @@ -5593,11 +5615,12 @@ struct spart *cell_add_spart(struct engine *e, struct cell *const c) { lock_lock(&top->stars.star_formation_lock); /* Are there any extra particles left? */ - if (top->stars.count == top->stars.count_total - 1) { + if (top->stars.count >= top->stars.count_total - 1) { /* Release the local lock before exiting. */ if (lock_unlock(&top->stars.star_formation_lock) != 0) error("Failed to unlock the top-level cell."); - message("We ran out of star particles!"); + if (top->stars.count == top->stars.count_total - 1) + message("We ran out of star particles!"); atomic_inc(&e->forcerebuild); return NULL; } @@ -5725,11 +5748,12 @@ struct gpart *cell_add_gpart(struct engine *e, struct cell *c) { lock_lock(&top->grav.star_formation_lock); /* Are there any extra particles left? */ - if (top->grav.count == top->grav.count_total - 1) { + if (top->grav.count >= top->grav.count_total - 1) { /* Release the local lock before exiting. */ if (lock_unlock(&top->grav.star_formation_lock) != 0) error("Failed to unlock the top-level cell."); - message("We ran out of gravity particles!"); + if (top->grav.count == top->grav.count_total - 1) + message("We ran out of gravity particles!"); atomic_inc(&e->forcerebuild); return NULL; } diff --git a/src/cell.h b/src/cell.h index a17b2a8e5794d0b092ca47acd9e6b87877820fa5..e84e00bcd77972be5e2a89d89b7d180a96bd637a 100644 --- a/src/cell.h +++ b/src/cell.h @@ -273,6 +273,17 @@ struct pcell_sf { float dx_max_part; } stars; + + /*! Grav. variables */ + struct { + + /* Distance by which the gpart pointer has moved since the last rebuild */ + ptrdiff_t delta_from_rebuild; + + /* Number of particles in the cell */ + int count; + + } grav; }; /** @@ -461,6 +472,9 @@ struct cell { /*! Pointer to the #gpart data. */ struct gpart *parts; + /*! Pointer to the #spart data at rebuild time. */ + struct gpart *parts_rebuild; + /*! This cell's multipole. */ struct gravity_tensors *multipole; diff --git a/src/runner_others.c b/src/runner_others.c index 0a496a6443c0993327be410a127f3a117e801517..5db756ac2b859d473fa9f07538e53d2ad6b31332 100644 --- a/src/runner_others.c +++ b/src/runner_others.c @@ -267,6 +267,14 @@ void runner_do_star_formation(struct runner *r, struct cell *c, int timer) { /* Update current cell using child cells */ star_formation_logger_add(&c->stars.sfh, &cp->stars.sfh); + + /* Update the dx_max */ + if (star_formation_need_update_dx_max) { + c->hydro.dx_max_part = + max(cp->hydro.dx_max_part, c->hydro.dx_max_part); + c->hydro.dx_max_sort = + max(cp->hydro.dx_max_sort, c->hydro.dx_max_sort); + } } } else { @@ -359,6 +367,25 @@ void runner_do_star_formation(struct runner *r, struct cell *c, int timer) { /* Update the Star formation history */ star_formation_logger_log_new_spart(sp, &c->stars.sfh); + /* Update the displacement information */ + if (star_formation_need_update_dx_max) { + const float dx2_part = xp->x_diff[0] * xp->x_diff[0] + + xp->x_diff[1] * xp->x_diff[1] + + xp->x_diff[2] * xp->x_diff[2]; + const float dx2_sort = xp->x_diff_sort[0] * xp->x_diff_sort[0] + + xp->x_diff_sort[1] * xp->x_diff_sort[1] + + xp->x_diff_sort[2] * xp->x_diff_sort[2]; + + const float dx_part = sqrtf(dx2_part); + const float dx_sort = sqrtf(dx2_sort); + + /* No need to climb up the tree as the star formation starts + higher in the hierarchy than the hydro and goes to the bottom + */ + c->hydro.dx_max_part = max(c->hydro.dx_max_part, dx_part); + c->hydro.dx_max_sort = max(c->hydro.dx_max_sort, dx_sort); + } + #ifdef WITH_LOGGER /* Copy the properties back to the stellar particle */ sp->logger_data = xp->logger_data; diff --git a/src/space.c b/src/space.c index 765d1d69decb1f59411642cd9a52cb29af32c678..a625b48346670b2983cded7cd9db35a364ec1d94 100644 --- a/src/space.c +++ b/src/space.c @@ -265,6 +265,7 @@ void space_rebuild_recycle_mapper(void *map_data, int num_elements, c->hydro.parts = NULL; c->hydro.xparts = NULL; c->grav.parts = NULL; + c->grav.parts_rebuild = NULL; c->stars.parts = NULL; c->stars.parts_rebuild = NULL; c->black_holes.parts = NULL; @@ -1954,6 +1955,7 @@ void space_rebuild(struct space *s, int repartitioned, int verbose) { /* Store the state at rebuild time */ c->stars.parts_rebuild = c->stars.parts; + c->grav.parts_rebuild = c->grav.parts; c->hydro.count_total = c->hydro.count + space_extra_parts; c->grav.count_total = c->grav.count + space_extra_gparts; diff --git a/src/star_formation/EAGLE/star_formation.h b/src/star_formation/EAGLE/star_formation.h index f8c42436f3f5b40941718f33e0e22a2b9eef9556..9c9c20b2616ea4c04e19ad6cf4ce07ac9ab389e9 100644 --- a/src/star_formation/EAGLE/star_formation.h +++ b/src/star_formation/EAGLE/star_formation.h @@ -41,6 +41,8 @@ * @brief Star formation model used in the EAGLE model */ +#define star_formation_need_update_dx_max 0 + /** * @brief Properties of the EAGLE star formation model. */ diff --git a/src/star_formation/GEAR/star_formation.h b/src/star_formation/GEAR/star_formation.h index 82a43c9e1ff2ce58f766a1c5e38f837093176987..3ef57147567d6b9d7ef150ffba5893ef9abd0929 100644 --- a/src/star_formation/GEAR/star_formation.h +++ b/src/star_formation/GEAR/star_formation.h @@ -34,6 +34,8 @@ #include "star_formation_struct.h" #include "units.h" +#define star_formation_need_update_dx_max 1 + /** * @brief Calculate if the gas has the potential of becoming * a star. @@ -207,6 +209,77 @@ INLINE static void star_formation_update_part_not_SFR( struct part* p, struct xpart* xp, const struct engine* e, const struct star_formation* starform, const int with_cosmology) {} +/** + * @brief Separate the #spart and #part by randomly moving both of them. + * + * @param e The #engine. + * @param p The #part generating a star. + * @param xp The #xpart generating a star. + * @param sp The new #spart. + */ +INLINE static void star_formation_separate_particles(const struct engine* e, + struct part* p, + struct xpart* xp, + struct spart* sp) { +#ifdef SWIFT_DEBUG_CHECKS + if (p->x[0] != sp->x[0] || p->x[1] != sp->x[1] || p->x[2] != sp->x[2]) { + error( + "Moving particles that are not at the same location." + " (%g, %g, %g) - (%g, %g, %g)", + p->x[0], p->x[1], p->x[2], sp->x[0], sp->x[1], sp->x[2]); + } +#endif + + /* Move a bit the particle in order to avoid + division by 0. + */ + const float max_displacement = 0.2; + const double delta_x = + 2.f * random_unit_interval(p->id, e->ti_current, + (enum random_number_type)0) - + 1.f; + const double delta_y = + 2.f * random_unit_interval(p->id, e->ti_current, + (enum random_number_type)1) - + 1.f; + const double delta_z = + 2.f * random_unit_interval(p->id, e->ti_current, + (enum random_number_type)2) - + 1.f; + + sp->x[0] += delta_x * max_displacement * p->h; + sp->x[1] += delta_y * max_displacement * p->h; + sp->x[2] += delta_z * max_displacement * p->h; + + /* Copy the position to the gpart */ + sp->gpart->x[0] = sp->x[0]; + sp->gpart->x[1] = sp->x[1]; + sp->gpart->x[2] = sp->x[2]; + + /* Do the gas particle. */ + const double mass_ratio = sp->mass / hydro_get_mass(p); + const double dx[3] = {mass_ratio * delta_x * max_displacement * p->h, + mass_ratio * delta_y * max_displacement * p->h, + mass_ratio * delta_z * max_displacement * p->h}; + + p->x[0] -= dx[0]; + p->x[1] -= dx[1]; + p->x[2] -= dx[2]; + + /* Compute offsets since last cell construction */ + xp->x_diff[0] += dx[0]; + xp->x_diff[1] += dx[1]; + xp->x_diff[1] += dx[2]; + xp->x_diff_sort[0] += dx[0]; + xp->x_diff_sort[1] += dx[1]; + xp->x_diff_sort[2] += dx[2]; + + /* Copy the position to the gpart */ + p->gpart->x[0] = p->x[0]; + p->gpart->x[1] = p->x[1]; + p->gpart->x[2] = p->x[2]; +} + /** * @brief Copies the properties of the gas particle over to the * star particle. @@ -225,10 +298,9 @@ INLINE static void star_formation_update_part_not_SFR( * @param convert_part Did we convert a part (or spawned one)? */ INLINE static void star_formation_copy_properties( - struct part* p, const struct xpart* xp, struct spart* sp, - const struct engine* e, const struct star_formation* starform, - const struct cosmology* cosmo, const int with_cosmology, - const struct phys_const* phys_const, + struct part* p, struct xpart* xp, struct spart* sp, const struct engine* e, + const struct star_formation* starform, const struct cosmology* cosmo, + const int with_cosmology, const struct phys_const* phys_const, const struct hydro_props* restrict hydro_props, const struct unit_system* restrict us, const struct cooling_function_data* restrict cooling, @@ -247,6 +319,8 @@ INLINE static void star_formation_copy_properties( /* Update the part */ hydro_set_mass(p, new_mass_gas); p->gpart->mass = new_mass_gas; + + star_formation_separate_particles(e, p, xp, sp); } else { sp->mass = mass_gas; } diff --git a/src/star_formation/QLA/star_formation.h b/src/star_formation/QLA/star_formation.h index aa9421220830df556bf0b56f50e251cbab8c8a7d..5f8a36f2103256464d7a3f469da09fc43a4b5b2a 100644 --- a/src/star_formation/QLA/star_formation.h +++ b/src/star_formation/QLA/star_formation.h @@ -34,6 +34,8 @@ * @brief Star formation model used in the EAGLE model */ +#define star_formation_need_update_dx_max 0 + /** * @brief Properties of the EAGLE star formation model. */ diff --git a/src/star_formation/none/star_formation.h b/src/star_formation/none/star_formation.h index 78f8a7c61789ce0075bf62a2c099e2cc534a5914..c40a2f93b6e2e6aa6cd873a3220d4c4c48c90919 100644 --- a/src/star_formation/none/star_formation.h +++ b/src/star_formation/none/star_formation.h @@ -32,6 +32,11 @@ /* Starformation struct */ struct star_formation {}; +/* Does the star formation model move the hydro particles? + This will update the c->hydro.dx_max_part and + c->hydro.dx_max_sort after forming a star. */ +#define star_formation_need_update_dx_max 0 + /** * @brief Calculate if the gas has the potential of becoming * a star.