diff --git a/examples/EAGLE_ICs/EAGLE_12/eagle_12.yml b/examples/EAGLE_ICs/EAGLE_12/eagle_12.yml index 41da31e93a963155ec011a950a8c773f7703ce30..a7362bf88a3898f687667ea110153ece4a8ade08 100644 --- a/examples/EAGLE_ICs/EAGLE_12/eagle_12.yml +++ b/examples/EAGLE_ICs/EAGLE_12/eagle_12.yml @@ -57,7 +57,8 @@ FOF: min_group_size: 256 # The minimum no. of particles required for a group. linking_length_ratio: 0.2 # Linking length in units of the main inter-particle separation. black_hole_seed_halo_mass_Msun: 1.5e10 # Minimal halo mass in which to seed a black hole (in solar masses). - run_freq: 256 + scale_factor_first: 0.01 # Scale-factor of first FoF black hole seeding calls. + delta_time: 1.005 # Scale-factor ratio between consecutive FoF black hole seeding calls. Scheduler: max_top_level_cells: 16 diff --git a/examples/EAGLE_ICs/EAGLE_25/eagle_25.yml b/examples/EAGLE_ICs/EAGLE_25/eagle_25.yml index cbdc44e8486d997ec0e45cc993565f0c9b865b15..ed1782127f7d80ba6d6802c256eeb9db9724d04f 100644 --- a/examples/EAGLE_ICs/EAGLE_25/eagle_25.yml +++ b/examples/EAGLE_ICs/EAGLE_25/eagle_25.yml @@ -57,7 +57,8 @@ FOF: min_group_size: 256 # The minimum no. of particles required for a group. linking_length_ratio: 0.2 # Linking length in units of the main inter-particle separation. black_hole_seed_halo_mass_Msun: 1.5e10 # Minimal halo mass in which to seed a black hole (in solar masses). - run_freq: 256 + scale_factor_first: 0.01 # Scale-factor of first FoF black hole seeding calls. + delta_time: 1.005 # Scale-factor ratio between consecutive FoF black hole seeding calls. Scheduler: max_top_level_cells: 16 diff --git a/examples/EAGLE_ICs/EAGLE_50/eagle_50.yml b/examples/EAGLE_ICs/EAGLE_50/eagle_50.yml index ebb2e37f048b455d4b8c4a3f08aa5943bc9ce13d..ca8eec7246bc0d3a0d6b10f8f75f0db6741f4f5b 100644 --- a/examples/EAGLE_ICs/EAGLE_50/eagle_50.yml +++ b/examples/EAGLE_ICs/EAGLE_50/eagle_50.yml @@ -57,7 +57,8 @@ FOF: min_group_size: 256 # The minimum no. of particles required for a group. linking_length_ratio: 0.2 # Linking length in units of the main inter-particle separation. black_hole_seed_halo_mass_Msun: 1.5e10 # Minimal halo mass in which to seed a black hole (in solar masses). - run_freq: 256 + scale_factor_first: 0.01 # Scale-factor of first FoF black hole seeding calls. + delta_time: 1.005 # Scale-factor ratio between consecutive FoF black hole seeding calls. Scheduler: max_top_level_cells: 32 diff --git a/examples/EAGLE_low_z/EAGLE_12/eagle_12.yml b/examples/EAGLE_low_z/EAGLE_12/eagle_12.yml index 951de51ca0df5d46f1f16aff6781918795da665e..434840636aceca6f6372cecfc5529a743a5cdc57 100644 --- a/examples/EAGLE_low_z/EAGLE_12/eagle_12.yml +++ b/examples/EAGLE_low_z/EAGLE_12/eagle_12.yml @@ -57,7 +57,8 @@ FOF: min_group_size: 256 # The minimum no. of particles required for a group. linking_length_ratio: 0.2 # Linking length in units of the main inter-particle separation. black_hole_seed_halo_mass_Msun: 1.5e10 # Minimal halo mass in which to seed a black hole (in solar masses). - run_freq: 256 + scale_factor_first: 0.91 # Scale-factor of first FoF black hole seeding calls. + delta_time: 1.005 # Scale-factor ratio between consecutive FoF black hole seeding calls. # Parameters related to the initial conditions InitialConditions: diff --git a/examples/EAGLE_low_z/EAGLE_25/eagle_25.yml b/examples/EAGLE_low_z/EAGLE_25/eagle_25.yml index 720f344c1b761dbcbe0392216e4b789f1b6962cb..484eb885c4a47d92ebc82a978b1fe0d3973a00ff 100644 --- a/examples/EAGLE_low_z/EAGLE_25/eagle_25.yml +++ b/examples/EAGLE_low_z/EAGLE_25/eagle_25.yml @@ -64,7 +64,8 @@ FOF: min_group_size: 256 # The minimum no. of particles required for a group. linking_length_ratio: 0.2 # Linking length in units of the main inter-particle separation. black_hole_seed_halo_mass_Msun: 1.5e10 # Minimal halo mass in which to seed a black hole (in solar masses). - run_freq: 256 + scale_factor_first: 0.91 # Scale-factor of first FoF black hole seeding calls. + delta_time: 1.005 # Scale-factor ratio between consecutive FoF black hole seeding calls. # Parameters related to the initial conditions InitialConditions: diff --git a/examples/EAGLE_low_z/EAGLE_50/eagle_50.yml b/examples/EAGLE_low_z/EAGLE_50/eagle_50.yml index bed82619414415f8e63782e09e8daed62b2da073..66df7929b9432eaad153dcd1a9b55da396f2e8be 100644 --- a/examples/EAGLE_low_z/EAGLE_50/eagle_50.yml +++ b/examples/EAGLE_low_z/EAGLE_50/eagle_50.yml @@ -59,7 +59,8 @@ FOF: min_group_size: 256 # The minimum no. of particles required for a group. linking_length_ratio: 0.2 # Linking length in units of the main inter-particle separation. black_hole_seed_halo_mass_Msun: 1.5e10 # Minimal halo mass in which to seed a black hole (in solar masses). - run_freq: 256 + scale_factor_first: 0.91 # Scale-factor of first FoF black hole seeding calls. + delta_time: 1.005 # Scale-factor ratio between consecutive FoF black hole seeding calls. # Parameters related to the initial conditions InitialConditions: diff --git a/examples/EAGLE_low_z/EAGLE_6/eagle_6.yml b/examples/EAGLE_low_z/EAGLE_6/eagle_6.yml index 556276f326912303de1af6d13db1f4b6f19b7f95..5506ad242bff579ac4f6ec6ef23dbb8597eb65a9 100644 --- a/examples/EAGLE_low_z/EAGLE_6/eagle_6.yml +++ b/examples/EAGLE_low_z/EAGLE_6/eagle_6.yml @@ -68,10 +68,8 @@ FOF: min_group_size: 256 # The minimum no. of particles required for a group. linking_length_ratio: 0.2 # Linking length in units of the main inter-particle separation. black_hole_seed_halo_mass_Msun: 1.5e10 # Minimal halo mass in which to seed a black hole (in solar masses). - absolute_linking_length: -1. # (Optional) Absolute linking length (in internal units) - run_freq: 10 # (Optional) The no. of steps between each FOF search. - group_id_default: 2147483647 # (Optional) Sets the group ID of particles in groups below the minimum size. Defaults to 2^31 - 1 if unspecified. Has to be positive. - group_id_offset: 1 # (Optional) Sets the offset of group ID labeling. Defaults to 1 if unspecified. + scale_factor_first: 0.91 # Scale-factor of first FoF black hole seeding calls. + delta_time: 1.005 # Scale-factor ratio between consecutive FoF black hole seeding calls. # Parameters related to the initial conditions InitialConditions: diff --git a/examples/parameter_example.yml b/examples/parameter_example.yml index a948ac62a5deb24cdfa73565ed067851d561bf38..176508f5c514b79515f3955679414ec99043b653 100644 --- a/examples/parameter_example.yml +++ b/examples/parameter_example.yml @@ -63,12 +63,14 @@ Gravity: # Parameters for the Friends-Of-Friends algorithm FOF: - basename: fof_output # Filename for the FOF outputs. + basename: fof_output # Filename for the FOF outputs (Unused when FoF is only run to seed BHs). + scale_factor_first: 0.91 # Scale-factor of first FoF black hole seeding calls (needed for cosmological runs). + time_first: 0.2 # Time of first FoF black hole seeding calls (needed for non-cosmological runs). + delta_time: 1.005 # Time between consecutive FoF black hole seeding calls. min_group_size: 256 # The minimum no. of particles required for a group. linking_length_ratio: 0.2 # Linking length in units of the main inter-particle separation. black_hole_seed_halo_mass_Msun: 1.5e10 # Minimal halo mass in which to seed a black hole (in solar masses). - absolute_linking_length: -1. # (Optional) Absolute linking length (in internal units) - run_freq: 10 # (Optional) The no. of steps between each FOF search. + absolute_linking_length: -1. # (Optional) Absolute linking length (in internal units). When not set to -1, this will overwrite the linking length computed from 'linking_length_ratio'. group_id_default: 2147483647 # (Optional) Sets the group ID of particles in groups below the minimum size. Defaults to 2^31 - 1 if unspecified. Has to be positive. group_id_offset: 1 # (Optional) Sets the offset of group ID labeling. Defaults to 1 if unspecified. diff --git a/src/engine.c b/src/engine.c index 007822474ec8d8b96d1c56d9e2ccc472794e2ec6..55b3346c3bdc30505e6bb53ef14edea7562301c8 100644 --- a/src/engine.c +++ b/src/engine.c @@ -3786,10 +3786,12 @@ void engine_step(struct engine *e) { ((double)e->total_nr_gparts) * e->gravity_properties->rebuild_frequency)) e->forcerebuild = 1; - /* Trigger a FOF search every N steps. */ - if (e->policy & engine_policy_fof && - (e->step % e->fof_properties->run_freq == 1)) - e->run_fof = 1; + /* Trigger a FOF black hole seeding? */ + if (e->policy & engine_policy_fof) { + if (e->ti_end_min > e->ti_next_fof && e->ti_next_fof > 0) { + e->run_fof = 1; + } + } #ifdef WITH_LOGGER /* Mark the current time step in the particle logger file. */ @@ -4971,6 +4973,8 @@ void engine_init(struct engine *e, struct space *s, struct swift_params *params, e->delta_time_statistics = parser_get_param_double(params, "Statistics:delta_time"); e->ti_next_stats = 0; + e->ti_next_stf = 0; + e->ti_next_fof = 0; e->verbose = verbose; e->wallclock_time = 0.f; e->physical_constants = physical_constants; @@ -5051,6 +5055,17 @@ void engine_init(struct engine *e, struct space *s, struct swift_params *params, parser_get_opt_param_double(params, "StructureFinding:delta_time", -1.); } + /* Initialise FoF calls frequency. */ + if (e->policy & engine_policy_fof) { + + e->time_first_fof_call = + parser_get_opt_param_double(params, "FOF:time_first", 0.); + e->a_first_fof_call = + parser_get_opt_param_double(params, "FOF:scale_factor_first", 0.1); + e->delta_time_fof = + parser_get_opt_param_double(params, "FOF:delta_time", -1.); + } + engine_init_output_lists(e, params); } @@ -5420,6 +5435,18 @@ void engine_config(int restart, struct engine *e, struct swift_params *params, "simulation start a=%e.", e->a_first_stf_output, e->cosmology->a_begin); } + + if (e->policy & engine_policy_fof) { + + if (e->delta_time_fof <= 1.) + error("Time between FOF (%e) must be > 1.", e->delta_time_fof); + + if (e->a_first_fof_call < e->cosmology->a_begin) + error( + "Scale-factor of first fof call (%e) must be after the " + "simulation start a=%e.", + e->a_first_fof_call, e->cosmology->a_begin); + } } else { if (e->delta_time_snapshot <= 0.) @@ -5455,6 +5482,16 @@ void engine_config(int restart, struct engine *e, struct swift_params *params, error("Time of first STF (%e) must be after the simulation start t=%e.", e->time_first_stf_output, e->time_begin); } + + if (e->policy & engine_policy_structure_finding) { + + if (e->delta_time_fof <= 0.) + error("Time between FOF (%e) must be positive.", e->delta_time_fof); + + if (e->time_first_fof_call < e->time_begin) + error("Time of first FOF (%e) must be after the simulation start t=%e.", + e->time_first_fof_call, e->time_begin); + } } /* Get the total mass */ @@ -5486,6 +5523,11 @@ void engine_config(int restart, struct engine *e, struct swift_params *params, engine_compute_next_stf_time(e); } + /* Find the time of the first stf output */ + if (e->policy & engine_policy_fof) { + engine_compute_next_fof_time(e); + } + /* Check that we are invoking VELOCIraptor only if we have it */ if (e->snapshot_invoke_stf && !(e->policy & engine_policy_structure_finding)) { @@ -5896,6 +5938,67 @@ void engine_compute_next_stf_time(struct engine *e) { } } +/** + * @brief Computes the next time (on the time line) for FoF black holes seeding + * + * @param e The #engine. + */ +void engine_compute_next_fof_time(struct engine *e) { + + /* Find upper-bound on last output */ + double time_end; + if (e->policy & engine_policy_cosmology) + time_end = e->cosmology->a_end * e->delta_time_fof; + else + time_end = e->time_end + e->delta_time_fof; + + /* Find next snasphot above current time */ + double time; + if (e->policy & engine_policy_cosmology) + time = e->a_first_fof_call; + else + time = e->time_first_fof_call; + + int found_fof_time = 0; + while (time < time_end) { + + /* Output time on the integer timeline */ + if (e->policy & engine_policy_cosmology) + e->ti_next_fof = log(time / e->cosmology->a_begin) / e->time_base; + else + e->ti_next_fof = (time - e->time_begin) / e->time_base; + + /* Found it? */ + if (e->ti_next_fof > e->ti_current) { + found_fof_time = 1; + break; + } + + if (e->policy & engine_policy_cosmology) + time *= e->delta_time_fof; + else + time += e->delta_time_fof; + } + + /* Deal with last snapshot */ + if (!found_fof_time) { + e->ti_next_fof = -1; + if (e->verbose) message("No further FoF time."); + } else { + + /* Be nice, talk... */ + if (e->policy & engine_policy_cosmology) { + const float next_fof_time = + exp(e->ti_next_fof * e->time_base) * e->cosmology->a_begin; + // if (e->verbose) + message("Next FoF time set to a=%e.", next_fof_time); + } else { + const float next_fof_time = e->ti_next_fof * e->time_base + e->time_begin; + if (e->verbose) message("Next FoF time set to t=%e.", next_fof_time); + } + } +} + /** * @brief Initialize all the output_list required by the engine * @@ -6419,6 +6522,9 @@ void engine_fof(struct engine *e) { /* Flag that a FOF has taken place */ e->step_props |= engine_step_prop_fof; + /* ... and find the next FOF time */ + engine_compute_next_fof_time(e); + if (engine_rank == 0) message("Complete FOF search took: %.3f %s.", clocks_from_ticks(getticks() - tic), clocks_getunit()); diff --git a/src/engine.h b/src/engine.h index 579adf8a8f4e02567ff83815b312267e0a144051..f6de893ca23cc995d1ff9646b79e14c2faf8761b 100644 --- a/src/engine.h +++ b/src/engine.h @@ -307,6 +307,14 @@ struct engine { char stf_base_name[PARSER_MAX_LINE_SIZE]; int stf_output_count; + /* FoF black holes seeding information */ + double a_first_fof_call; + double time_first_fof_call; + double delta_time_fof; + + /* Integer time of the next FoF black holes seeding call */ + integertime_t ti_next_fof; + /* FOF information */ int run_fof; @@ -470,6 +478,7 @@ void engine_addlink(struct engine *e, struct link **l, struct task *t); void engine_barrier(struct engine *e); void engine_compute_next_snapshot_time(struct engine *e); void engine_compute_next_stf_time(struct engine *e); +void engine_compute_next_fof_time(struct engine *e); void engine_compute_next_statistics_time(struct engine *e); void engine_recompute_displacement_constraint(struct engine *e); void engine_unskip(struct engine *e); diff --git a/src/fof.c b/src/fof.c index 048155280cacb6deabd80092e6a8c43959376876..5ed57ba6c2bc3916e3d69589963af884f1ae6815 100644 --- a/src/fof.c +++ b/src/fof.c @@ -42,7 +42,6 @@ #include "proxy.h" #include "threadpool.h" -#define fof_props_default_run_freq 2000 #define fof_props_default_group_id 2147483647 #define fof_props_default_group_id_offset 1 #define fof_props_default_group_link_size 20000 @@ -100,10 +99,6 @@ void fof_init(struct fof_props *props, struct swift_params *params, strerror(errno)); } - /* Read the FOF search frequency. */ - props->run_freq = parser_get_opt_param_int(params, "FOF:run_freq", - fof_props_default_run_freq); - /* Read the minimum group size. */ props->min_group_size = parser_get_param_int(params, "FOF:min_group_size"); diff --git a/src/fof.h b/src/fof.h index 93d3a0beb2ecf22adcd808fe4879a86806301e5a..160f7c0af8f7f6f7a589c6978cd107b7ffbff1fc 100644 --- a/src/fof.h +++ b/src/fof.h @@ -69,9 +69,6 @@ struct fof_props { /*! The minimum halo mass for black hole seeding. */ double seed_halo_mass; - /*! The no. of steps between each FOF search. */ - int run_freq; - /*! Minimal number of particles in a group */ size_t min_group_size;