/******************************************************************************* * This file is part of SWIFT. * Copyright (c) 2016 Matthieu Schaller (schaller@strw.leidenuniv.nl) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * ******************************************************************************/ #ifndef SWIFT_BASIC_STARS_IO_H #define SWIFT_BASIC_STARS_IO_H #include "io_properties.h" #include "kick.h" #include "stars_part.h" /** * @brief Specifies which s-particle fields to read from a dataset * * @param sparts The s-particle array. * @param list The list of i/o properties to read. * @param num_fields The number of i/o fields to read. */ INLINE static void stars_read_particles(struct spart *sparts, struct io_props *list, int *num_fields) { /* Say how much we want to read */ *num_fields = 5; /* List what we want to read */ list[0] = io_make_input_field("Coordinates", DOUBLE, 3, COMPULSORY, UNIT_CONV_LENGTH, sparts, x); list[1] = io_make_input_field("Velocities", FLOAT, 3, COMPULSORY, UNIT_CONV_SPEED, sparts, v); list[2] = io_make_input_field("Masses", FLOAT, 1, COMPULSORY, UNIT_CONV_MASS, sparts, mass); list[3] = io_make_input_field("ParticleIDs", LONGLONG, 1, COMPULSORY, UNIT_CONV_NO_UNITS, sparts, id); list[4] = io_make_input_field("SmoothingLength", FLOAT, 1, OPTIONAL, UNIT_CONV_LENGTH, sparts, h); } INLINE static void convert_spart_pos(const struct engine *e, const struct spart *sp, double *ret) { const struct space *s = e->s; if (s->periodic) { ret[0] = box_wrap(sp->x[0], 0.0, s->dim[0]); ret[1] = box_wrap(sp->x[1], 0.0, s->dim[1]); ret[2] = box_wrap(sp->x[2], 0.0, s->dim[2]); } else { ret[0] = sp->x[0]; ret[1] = sp->x[1]; ret[2] = sp->x[2]; } if (e->snapshot_use_delta_from_edge) { ret[0] = min(ret[0], s->dim[0] - e->snapshot_delta_from_edge); ret[1] = min(ret[1], s->dim[1] - e->snapshot_delta_from_edge); ret[2] = min(ret[2], s->dim[2] - e->snapshot_delta_from_edge); } } INLINE static void convert_spart_vel(const struct engine *e, const struct spart *sp, float *ret) { const int with_cosmology = (e->policy & engine_policy_cosmology); const struct cosmology *cosmo = e->cosmology; const integertime_t ti_current = e->ti_current; const double time_base = e->time_base; const float dt_kick_grav_mesh = e->dt_kick_grav_mesh_for_io; const integertime_t ti_beg = get_integer_time_begin(ti_current, sp->time_bin); const integertime_t ti_end = get_integer_time_end(ti_current, sp->time_bin); /* Get time-step since the last kick */ const float dt_kick_grav = kick_get_grav_kick_dt(ti_beg, ti_current, time_base, with_cosmology, cosmo) - kick_get_grav_kick_dt(ti_beg, (ti_beg + ti_end) / 2, time_base, with_cosmology, cosmo); /* Extrapolate the velocites to the current time */ const struct gpart *gp = sp->gpart; ret[0] = gp->v_full[0] + gp->a_grav[0] * dt_kick_grav; ret[1] = gp->v_full[1] + gp->a_grav[1] * dt_kick_grav; ret[2] = gp->v_full[2] + gp->a_grav[2] * dt_kick_grav; /* Extrapolate the velocites to the current time (mesh forces) */ ret[0] += gp->a_grav_mesh[0] * dt_kick_grav_mesh; ret[1] += gp->a_grav_mesh[1] * dt_kick_grav_mesh; ret[2] += gp->a_grav_mesh[2] * dt_kick_grav_mesh; /* Conversion from internal units to peculiar velocities */ ret[0] *= cosmo->a_inv; ret[1] *= cosmo->a_inv; ret[2] *= cosmo->a_inv; } INLINE static void convert_spart_potential(const struct engine *e, const struct spart *sp, float *ret) { if (sp->gpart != NULL) ret[0] = gravity_get_comoving_potential(sp->gpart); else ret[0] = 0.f; } /** * @brief Specifies which s-particle fields to write to a dataset * * @param sparts The s-particle array. * @param list The list of i/o properties to write. * @param num_fields The number of i/o fields to write. * @param with_cosmology Are we running a cosmological simulation? */ INLINE static void stars_write_particles(const struct spart *sparts, struct io_props *list, int *num_fields, int with_cosmology) { /* Say how much we want to write */ *num_fields = 6; /* List what we want to write */ list[0] = io_make_output_field_convert_spart( "Coordinates", DOUBLE, 3, UNIT_CONV_LENGTH, 1.f, sparts, convert_spart_pos, "Co-moving position of the particles"); list[1] = io_make_output_field_convert_spart( "Velocities", FLOAT, 3, UNIT_CONV_SPEED, 0.f, sparts, convert_spart_vel, "Peculiar velocities of the particles. This is a * dx/dt where x is the " "co-moving position of the particles."); list[2] = io_make_output_field("Masses", FLOAT, 1, UNIT_CONV_MASS, 0.f, sparts, mass, "Masses of the particles"); list[3] = io_make_physical_output_field( "ParticleIDs", ULONGLONG, 1, UNIT_CONV_NO_UNITS, 0.f, sparts, id, /*can convert to comoving=*/0, "Unique ID of the particles"); list[4] = io_make_output_field( "SmoothingLengths", FLOAT, 1, UNIT_CONV_LENGTH, 1.f, sparts, h, "Co-moving smoothing lengths (FWHM of the kernel) of the particles"); list[5] = io_make_output_field_convert_spart( "Potentials", FLOAT, 1, UNIT_CONV_POTENTIAL, -1.f, sparts, convert_spart_potential, "Gravitational potentials of the particles"); #ifdef DEBUG_INTERACTIONS_STARS list += *num_fields; *num_fields += 4; list[0] = io_make_output_field("Num_ngb_density", INT, 1, UNIT_CONV_NO_UNITS, sparts, num_ngb_density); list[1] = io_make_output_field("Num_ngb_force", INT, 1, UNIT_CONV_NO_UNITS, sparts, num_ngb_force); list[2] = io_make_output_field("Ids_ngb_density", LONGLONG, MAX_NUM_OF_NEIGHBOURS_STARS, UNIT_CONV_NO_UNITS, sparts, ids_ngbs_density); list[3] = io_make_output_field("Ids_ngb_force", LONGLONG, MAX_NUM_OF_NEIGHBOURS_STARS, UNIT_CONV_NO_UNITS, sparts, ids_ngbs_force); #endif } /** * @brief Initialize the global properties of the stars scheme. * * By default, takes the values provided by the hydro. * * @param sp The #stars_props. * @param phys_const The physical constants in the internal unit system. * @param us The internal unit system. * @param params The parsed parameters. * @param p The already read-in properties of the hydro scheme. * @param cosmo The cosmological model. */ INLINE static void stars_props_init(struct stars_props *sp, const struct phys_const *phys_const, const struct unit_system *us, struct swift_params *params, const struct hydro_props *p, const struct cosmology *cosmo) { /* Kernel properties */ sp->eta_neighbours = parser_get_opt_param_float( params, "Stars:resolution_eta", p->eta_neighbours); /* Tolerance for the smoothing length Newton-Raphson scheme */ sp->h_tolerance = parser_get_opt_param_float(params, "Stars:h_tolerance", p->h_tolerance); /* Get derived properties */ sp->target_neighbours = pow_dimension(sp->eta_neighbours) * kernel_norm; const float delta_eta = sp->eta_neighbours * (1.f + sp->h_tolerance); sp->delta_neighbours = (pow_dimension(delta_eta) - pow_dimension(sp->eta_neighbours)) * kernel_norm; /* Number of iterations to converge h */ sp->max_smoothing_iterations = parser_get_opt_param_int( params, "Stars:max_ghost_iterations", p->max_smoothing_iterations); /* Time integration properties */ const float max_volume_change = parser_get_opt_param_float(params, "Stars:max_volume_change", -1); if (max_volume_change == -1) sp->log_max_h_change = p->log_max_h_change; else sp->log_max_h_change = logf(powf(max_volume_change, hydro_dimension_inv)); } /** * @brief Print the global properties of the stars scheme. * * @param sp The #stars_props. */ INLINE static void stars_props_print(const struct stars_props *sp) { /* Now stars */ message("Stars kernel: %s with eta=%f (%.2f neighbours).", kernel_name, sp->eta_neighbours, sp->target_neighbours); message("Stars relative tolerance in h: %.5f (+/- %.4f neighbours).", sp->h_tolerance, sp->delta_neighbours); message( "Stars integration: Max change of volume: %.2f " "(max|dlog(h)/dt|=%f).", pow_dimension(expf(sp->log_max_h_change)), sp->log_max_h_change); message("Maximal iterations in ghost task set to %d", sp->max_smoothing_iterations); } #if defined(HAVE_HDF5) INLINE static void stars_props_print_snapshot(hid_t h_grpstars, hid_t h_grp_columns, const struct stars_props *sp) { io_write_attribute_s(h_grpstars, "Kernel function", kernel_name); io_write_attribute_f(h_grpstars, "Kernel target N_ngb", sp->target_neighbours); io_write_attribute_f(h_grpstars, "Kernel delta N_ngb", sp->delta_neighbours); io_write_attribute_f(h_grpstars, "Kernel eta", sp->eta_neighbours); io_write_attribute_f(h_grpstars, "Smoothing length tolerance", sp->h_tolerance); io_write_attribute_f(h_grpstars, "Volume log(max(delta h))", sp->log_max_h_change); io_write_attribute_f(h_grpstars, "Volume max change time-step", pow_dimension(expf(sp->log_max_h_change))); io_write_attribute_i(h_grpstars, "Max ghost iterations", sp->max_smoothing_iterations); } #endif /** * @brief Free the memory allocated for the stellar properties. * * Nothing to do here. * * @param sp The #stars_props structure. */ INLINE static void stars_props_clean(struct stars_props *sp) {} /** * @brief Write a #stars_props struct to the given FILE as a stream of bytes. * * @param p the struct * @param stream the file stream */ INLINE static void stars_props_struct_dump(const struct stars_props *p, FILE *stream) { restart_write_blocks((void *)p, sizeof(struct stars_props), 1, stream, "starsprops", "stars props"); } /** * @brief Restore a stars_props struct from the given FILE as a stream of * bytes. * * @param p the struct * @param stream the file stream */ INLINE static void stars_props_struct_restore(const struct stars_props *p, FILE *stream) { restart_read_blocks((void *)p, sizeof(struct stars_props), 1, stream, NULL, "stars props"); } #endif /* SWIFT_BASIC_STAR_IO_H */