diff --git a/configure.ac b/configure.ac index ac4a3e8f19c27b157ab0522862de645d2882e03d..9a287fdeee304274d084ace0457da2fe022f1132 100644 --- a/configure.ac +++ b/configure.ac @@ -1129,6 +1129,7 @@ if test "x$with_python" != "xno"; then AC_MSG_RESULT([$PYTHON_INCS]) ]) have_python="yes" + AC_DEFINE([HAVE_PYTHON],1,[Python appears to be present.]) fi AC_SUBST([PYTHON_INCS]) AM_CONDITIONAL([HAVEPYTHON],[test -n "$PYTHON_INCS"]) diff --git a/examples/main.c b/examples/main.c index 63a7aa511559282e5e68406673132927e7770b4b..cb9b0b273cc0cd759831805ead7dfcf2e83b92ff 100644 --- a/examples/main.c +++ b/examples/main.c @@ -1362,7 +1362,7 @@ int main(int argc, char *argv[]) { /* Write the state of the system before starting time integration. */ #ifdef WITH_LOGGER if (e.policy & engine_policy_logger) { - logger_log_all(e.logger, &e); + logger_log_all_particles(e.logger, &e); engine_dump_index(&e); } #endif @@ -1568,7 +1568,7 @@ int main(int argc, char *argv[]) { } #ifdef WITH_LOGGER if (e.policy & engine_policy_logger) { - logger_log_all(e.logger, &e); + logger_log_all_particles(e.logger, &e); /* Write a final index file */ engine_dump_index(&e); diff --git a/logger/logger_python_wrapper.c b/logger/logger_python_wrapper.c index 48973daf969b605b1deed4c55739ad008dbe6df6..b8fd89b17e555cbc0ed6b03c2e46c645a5780da1 100644 --- a/logger/logger_python_wrapper.c +++ b/logger/logger_python_wrapper.c @@ -22,6 +22,7 @@ #include "logger_reader.h" #include "logger_time.h" +#ifdef HAVE_PYTHON #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION #include <Python.h> @@ -447,3 +448,5 @@ PyMODINIT_FUNC PyInit_liblogger(void) { return m; } + +#endif // HAVE_PYTHON diff --git a/logger/logger_tools.h b/logger/logger_tools.h index 21a59e42fca144a0381b15e8771ca14ceed46b33..6974f9888d3ebbd9a8f2922ff24d23db4d68f6aa 100644 --- a/logger/logger_tools.h +++ b/logger/logger_tools.h @@ -29,6 +29,7 @@ #include "../src/error.h" #include "../src/inline.h" #include "../src/logger.h" +#include "../src/logger_io.h" #include "../src/part_type.h" #ifdef HAVE_PYTHON diff --git a/src/Makefile.am b/src/Makefile.am index 80ee17d5f03d6b00dd769c5e500a66520026d465..50dc74ce1df54426d79a9d58a881b27c91c4ab03 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -135,7 +135,8 @@ nobase_noinst_HEADERS = align.h approx_math.h atomic.h barrier.h cycle.h error.h gravity/Potential/gravity.h gravity/Potential/gravity_iact.h gravity/Potential/gravity_io.h \ gravity/Potential/gravity_debug.h gravity/Potential/gravity_part.h \ gravity/MultiSoftening/gravity.h gravity/MultiSoftening/gravity_iact.h gravity/MultiSoftening/gravity_io.h \ - gravity/MultiSoftening/gravity_debug.h gravity/MultiSoftening/gravity_part.h \ + gravity/MultiSoftening/gravity_debug.h gravity/MultiSoftening/gravity_part.h \ + gravity/MultiSoftening/gravity_logger.h \ equation_of_state.h \ equation_of_state/ideal_gas/equation_of_state.h equation_of_state/isothermal/equation_of_state.h \ hydro.h hydro_io.h hydro_parameters.h \ @@ -147,7 +148,7 @@ nobase_noinst_HEADERS = align.h approx_math.h atomic.h barrier.h cycle.h error.h hydro/Default/hydro_parameters.h \ hydro/Gadget2/hydro.h hydro/Gadget2/hydro_iact.h hydro/Gadget2/hydro_io.h \ hydro/Gadget2/hydro_debug.h hydro/Gadget2/hydro_part.h \ - hydro/Gadget2/hydro_parameters.h \ + hydro/Gadget2/hydro_parameters.h hydro/Gadget2/hydro_logger.h \ hydro/PressureEntropy/hydro.h hydro/PressureEntropy/hydro_iact.h hydro/PressureEntropy/hydro_io.h \ hydro/PressureEntropy/hydro_debug.h hydro/PressureEntropy/hydro_part.h \ hydro/PressureEntropy/hydro_parameters.h \ @@ -209,7 +210,7 @@ nobase_noinst_HEADERS = align.h approx_math.h atomic.h barrier.h cycle.h error.h riemann/riemann_checks.h \ stars.h stars_io.h \ stars/Default/stars.h stars/Default/stars_iact.h stars/Default/stars_io.h \ - stars/Default/stars_debug.h stars/Default/stars_part.h \ + stars/Default/stars_debug.h stars/Default/stars_part.h stars/Default/stars_logger.h \ stars/EAGLE/stars.h stars/EAGLE/stars_iact.h stars/EAGLE/stars_io.h \ stars/EAGLE/stars_debug.h stars/EAGLE/stars_part.h \ stars/GEAR/stars.h stars/GEAR/stars_iact.h stars/GEAR/stars_io.h \ @@ -293,7 +294,7 @@ nobase_noinst_HEADERS = align.h approx_math.h atomic.h barrier.h cycle.h error.h pressure_floor/GEAR/pressure_floor_iact.h pressure_floor/none/pressure_floor_iact.h \ pressure_floor/GEAR/pressure_floor_struct.h pressure_floor/none/pressure_floor_struct.h \ task_order/GEAR/task_order.h task_order/EAGLE/task_order.h task_order/default/task_order.h \ - sink/Default/sink.h sink/Default/sink_io.h sink/Default/sink_part.h \ + sink/Default/sink.h sink/Default/sink_io.h sink/Default/sink_part.h \ sink.h sink_io.h diff --git a/src/cell.c b/src/cell.c index fdc787a21a2caf178c5bbfd91ee6a5c4d7a51e01..784d9e08aa5cee81a89658644c59dd6807840101 100644 --- a/src/cell.c +++ b/src/cell.c @@ -4883,6 +4883,15 @@ void cell_drift_part(struct cell *c, const struct engine *e, int force) { * by another thread before we do the deed. */ if (!part_is_inhibited(p, e)) { +#ifdef WITH_LOGGER + if (e->policy & engine_policy_logger) { + /* Log the particle one last time. */ + logger_log_part( + e->logger, p, xp, e, /* log_all */ 1, + logger_pack_flags_and_data(logger_flag_delete, 0)); + } +#endif + /* One last action before death? */ hydro_remove_part(p, xp); @@ -5053,6 +5062,17 @@ void cell_drift_gpart(struct cell *c, const struct engine *e, int force) { /* Remove the particle entirely */ if (gp->type == swift_type_dark_matter) { + +#ifdef WITH_LOGGER + if (e->policy & engine_policy_logger) { + /* Log the particle one last time. */ + logger_log_gpart( + e->logger, gp, e, /* log_all */ 1, + logger_pack_flags_and_data(logger_flag_delete, 0)); + } +#endif + + /* Remove the particle */ cell_remove_gpart(e, c, gp); } } @@ -5194,6 +5214,15 @@ void cell_drift_spart(struct cell *c, const struct engine *e, int force) { * by another thread before we do the deed. */ if (!spart_is_inhibited(sp, e)) { +#ifdef WITH_LOGGER + if (e->policy & engine_policy_logger) { + /* Log the particle one last time. */ + logger_log_spart( + e->logger, sp, e, /* log_all */ 1, + logger_pack_flags_and_data(logger_flag_delete, 0)); + } +#endif + /* Remove the particle entirely */ cell_remove_spart(e, c, sp); } @@ -5365,6 +5394,12 @@ void cell_drift_bpart(struct cell *c, const struct engine *e, int force) { * by another thread before we do the deed. */ if (!bpart_is_inhibited(bp, e)) { +#ifdef WITH_LOGGER + if (e->policy & engine_policy_logger) { + error("Logging of black hole particles is not yet implemented."); + } +#endif + /* Remove the particle entirely */ cell_remove_bpart(e, c, bp); } diff --git a/src/engine.c b/src/engine.c index 2786a62a5daf108a3eb71c58b1e2f4fdaacd2382..cf37c80c9090568d9f626002c18ff6e6b31512ad 100644 --- a/src/engine.c +++ b/src/engine.c @@ -562,14 +562,11 @@ void engine_exchange_strays(struct engine *e, const size_t offset_parts, #ifdef WITH_LOGGER if (e->policy & engine_policy_logger) { - const uint32_t logger_flag = - logger_pack_flags_and_data(logger_flag_mpi_exit, node_id); - /* Log the particle when leaving a rank. */ logger_log_part( e->logger, &s->parts[offset_parts + k], &s->xparts[offset_parts + k], - logger_masks_all_part | logger_mask_data[logger_special_flags].mask, - logger_flag); + e, /* log_all_fields */ 1, + logger_pack_flags_and_data(logger_flag_mpi_exit, node_id)); } #endif } @@ -610,14 +607,11 @@ void engine_exchange_strays(struct engine *e, const size_t offset_parts, #ifdef WITH_LOGGER if (e->policy & engine_policy_logger) { - const uint32_t logger_flag = - logger_pack_flags_and_data(logger_flag_mpi_exit, node_id); - /* Log the particle when leaving a rank. */ logger_log_spart( - e->logger, &s->sparts[offset_sparts + k], - logger_masks_all_spart | logger_mask_data[logger_special_flags].mask, - logger_flag); + e->logger, &s->sparts[offset_sparts + k], e, + /* log_all_fields */ 1, + logger_pack_flags_and_data(logger_flag_mpi_exit, node_id)); } #endif } @@ -696,14 +690,11 @@ void engine_exchange_strays(struct engine *e, const size_t offset_parts, if ((e->policy & engine_policy_logger) && s->gparts[offset_gparts + k].type == swift_type_dark_matter) { - const uint32_t logger_flag = - logger_pack_flags_and_data(logger_flag_mpi_exit, node_id); - /* Log the particle when leaving a rank. */ logger_log_gpart( - e->logger, &s->gparts[offset_gparts + k], - logger_masks_all_gpart | logger_mask_data[logger_special_flags].mask, - logger_flag); + e->logger, &s->gparts[offset_gparts + k], e, + /* log_all_fields */ 1, + logger_pack_flags_and_data(logger_flag_mpi_exit, node_id)); } #endif } @@ -937,22 +928,16 @@ void engine_exchange_strays(struct engine *e, const size_t offset_parts, struct gpart *gparts = &s->gparts[offset_gparts + count_gparts]; /* Log the gas particles */ - logger_log_parts( - e->logger, parts, xparts, prox->nr_parts_in, - logger_masks_all_part | logger_mask_data[logger_special_flags].mask, - flag); + logger_log_parts(e->logger, parts, xparts, prox->nr_parts_in, e, + /* log_all_fields */ 1, flag); /* Log the stellar particles */ - logger_log_sparts(e->logger, sparts, prox->nr_sparts_in, - logger_masks_all_spart | - logger_mask_data[logger_special_flags].mask, - flag); + logger_log_sparts(e->logger, sparts, prox->nr_sparts_in, e, + /* log_all_fields */ 1, flag); /* Log the gparts */ - logger_log_gparts(e->logger, gparts, prox->nr_gparts_in, - logger_masks_all_gpart | - logger_mask_data[logger_special_flags].mask, - flag); + logger_log_gparts(e->logger, gparts, prox->nr_gparts_in, e, + /* log_all_fields */ 1, flag); /* Log the bparts */ if (prox->nr_bparts_in > 0) { @@ -3980,7 +3965,7 @@ void engine_init(struct engine *e, struct space *s, struct swift_params *params, #if defined(WITH_LOGGER) if (e->policy & engine_policy_logger) { e->logger = (struct logger_writer *)malloc(sizeof(struct logger_writer)); - logger_init(e->logger, params); + logger_init(e->logger, e, params); } #endif diff --git a/src/engine_redistribute.c b/src/engine_redistribute.c index 7246f71ee0a0d7620e6750c3706069720acce7ac..35354ec848d8890b9157c5c3a6825f84094cdd89 100644 --- a/src/engine_redistribute.c +++ b/src/engine_redistribute.c @@ -1004,22 +1004,16 @@ void engine_redistribute(struct engine *e) { const uint32_t flag = logger_pack_flags_and_data(logger_flag_mpi_exit, i); /* Log the hydro parts. */ - logger_log_parts( - e->logger, &parts[part_offset], &xparts[part_offset], counts[c_ind], - logger_masks_all_part | logger_mask_data[logger_special_flags].mask, - flag); + logger_log_parts(e->logger, &parts[part_offset], &xparts[part_offset], + counts[c_ind], e, /* log_all_fields */ 1, flag); /* Log the stellar parts. */ - logger_log_sparts( - e->logger, &sparts[spart_offset], s_counts[c_ind], - logger_masks_all_spart | logger_mask_data[logger_special_flags].mask, - flag); + logger_log_sparts(e->logger, &sparts[spart_offset], s_counts[c_ind], e, + /* log_all_fields */ 1, flag); /* Log the gparts */ - logger_log_gparts( - e->logger, &gparts[gpart_offset], g_counts[c_ind], - logger_masks_all_gpart | logger_mask_data[logger_special_flags].mask, - flag); + logger_log_gparts(e->logger, &gparts[gpart_offset], g_counts[c_ind], e, + /* log_all_fields */ 1, flag); /* Log the bparts */ if (b_counts[c_ind] > 0) { @@ -1110,23 +1104,17 @@ void engine_redistribute(struct engine *e) { logger_pack_flags_and_data(logger_flag_mpi_enter, i); /* Log the hydro parts. */ - logger_log_parts( - e->logger, &s->parts[part_offset], &s->xparts[part_offset], - counts[c_ind], - logger_masks_all_part | logger_mask_data[logger_special_flags].mask, - flag); + logger_log_parts(e->logger, &s->parts[part_offset], + &s->xparts[part_offset], counts[c_ind], e, + /* log_all_fields */ 1, flag); /* Log the stellar parts. */ - logger_log_sparts( - e->logger, &s->sparts[spart_offset], s_counts[c_ind], - logger_masks_all_spart | logger_mask_data[logger_special_flags].mask, - flag); + logger_log_sparts(e->logger, &s->sparts[spart_offset], s_counts[c_ind], e, + /* log_all_fields */ 1, flag); /* Log the gparts */ - logger_log_gparts( - e->logger, &s->gparts[gpart_offset], g_counts[c_ind], - logger_masks_all_gpart | logger_mask_data[logger_special_flags].mask, - flag); + logger_log_gparts(e->logger, &s->gparts[gpart_offset], g_counts[c_ind], e, + /* log_all_fields */ 1, flag); /* Log the bparts */ if (b_counts[c_ind] > 0) { diff --git a/src/gravity/MultiSoftening/gravity_logger.h b/src/gravity/MultiSoftening/gravity_logger.h new file mode 100644 index 0000000000000000000000000000000000000000..65035aceac081cdb6c84282e34eca16142b43db0 --- /dev/null +++ b/src/gravity/MultiSoftening/gravity_logger.h @@ -0,0 +1,180 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Coypright (c) 2020 Loic Hausammann (loic.hausammann@epfl.ch) + * + * 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 <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ +#ifndef SWIFT_MULTISOFTENING_GRAVITY_LOGGER_H +#define SWIFT_MULTISOFTENING_GRAVITY_LOGGER_H + +#include "logger_io.h" + +#ifdef WITH_LOGGER + +/* + * List of all possible mask. + * Outside the module, only logger_gravity_count is used. + */ +enum gravity_logger_fields { + gravity_logger_field_coordinates = 0, + gravity_logger_field_velocities, + gravity_logger_field_accelerations, + gravity_logger_field_masses, + gravity_logger_field_particle_ids, + gravity_logger_field_count, +}; + +/* Name of each possible mask. */ +static const char *gravity_logger_field_names[gravity_logger_field_count] = { + "Coordinates", "Velocities", "Accelerations", "Masses", "ParticleIDs", +}; + +/** + * @brief Initialize the logger. + * + * WARNING: this should be done in the same order than + * #gravity_logger_write_particle. + * + * @param mask_data Data for each type of mask. + * + * @return Number of masks used. + */ +INLINE static int gravity_logger_populate_mask_data( + struct mask_data *mask_data) { + mask_data[gravity_logger_field_coordinates] = logger_create_mask_entry( + gravity_logger_field_names[gravity_logger_field_coordinates], + 3 * sizeof(double)); + + mask_data[gravity_logger_field_velocities] = logger_create_mask_entry( + gravity_logger_field_names[gravity_logger_field_velocities], + 3 * sizeof(float)); + + mask_data[gravity_logger_field_accelerations] = logger_create_mask_entry( + gravity_logger_field_names[gravity_logger_field_accelerations], + 3 * sizeof(float)); + + mask_data[gravity_logger_field_masses] = logger_create_mask_entry( + gravity_logger_field_names[gravity_logger_field_masses], sizeof(float)); + + mask_data[gravity_logger_field_particle_ids] = logger_create_mask_entry( + gravity_logger_field_names[gravity_logger_field_particle_ids], + sizeof(long long)); + + return gravity_logger_field_count; +} + +/** + * @brief Generates the mask and compute the size of the record. + * + * @param masks The list of masks (same order than in #gravity_logger_init). + * @param part The #gpart that will be written. + * @param write_all Are we forcing to write all the fields? + * + * @param buffer_size (out) The requested size for the buffer. + * @param mask (out) The mask that will be written. + */ +INLINE static void gravity_logger_compute_size_and_mask( + const struct mask_data *masks, const struct gpart *part, + const int write_all, size_t *buffer_size, unsigned int *mask) { + + /* Here you can decide your own writing logic */ + + /* Add the coordinates. */ + *mask |= logger_add_field_to_mask( + masks[gravity_logger_field_coordinates], + gravity_logger_field_names[gravity_logger_field_coordinates], + buffer_size); + + /* Add the velocities. */ + *mask |= logger_add_field_to_mask( + masks[gravity_logger_field_velocities], + gravity_logger_field_names[gravity_logger_field_velocities], buffer_size); + + /* Add the accelerations. */ + *mask |= logger_add_field_to_mask( + masks[gravity_logger_field_accelerations], + gravity_logger_field_names[gravity_logger_field_accelerations], + buffer_size); + + /* Add the masses. */ + *mask |= logger_add_field_to_mask( + masks[gravity_logger_field_masses], + gravity_logger_field_names[gravity_logger_field_masses], buffer_size); + + /* Add the ID. */ + *mask |= logger_add_field_to_mask( + masks[gravity_logger_field_particle_ids], + gravity_logger_field_names[gravity_logger_field_particle_ids], + buffer_size); +} + +/** + * @brief Write a particle to the logger. + * + * @param masks The list of masks (same order than in #gravity_logger_init). + * @param p The #gpart to write. + * @param mask The mask to use for this record. + * @param buff The buffer where to write the particle. + * + * @return The buffer after the data. + */ +INLINE static char *gravity_logger_write_particle( + const struct mask_data *mask_data, const struct gpart *p, + unsigned int *mask, char *buff) { + + /* Write the coordinate. */ + if (logger_should_write_field( + mask_data[gravity_logger_field_coordinates], mask, + gravity_logger_field_names[gravity_logger_field_coordinates])) { + memcpy(buff, p->x, 3 * sizeof(double)); + buff += 3 * sizeof(double); + } + + /* Write the velocity. */ + if (logger_should_write_field( + mask_data[gravity_logger_field_velocities], mask, + gravity_logger_field_names[gravity_logger_field_velocities])) { + memcpy(buff, p->v_full, 3 * sizeof(float)); + buff += 3 * sizeof(float); + } + + /* Write the acceleration. */ + if (logger_should_write_field( + mask_data[gravity_logger_field_accelerations], mask, + gravity_logger_field_names[gravity_logger_field_accelerations])) { + memcpy(buff, p->a_grav, 3 * sizeof(float)); + buff += 3 * sizeof(float); + } + + /* Write the mass. */ + if (logger_should_write_field( + mask_data[gravity_logger_field_masses], mask, + gravity_logger_field_names[gravity_logger_field_masses])) { + memcpy(buff, &p->mass, sizeof(float)); + buff += sizeof(float); + } + + /* Write the Id. */ + if (logger_should_write_field( + mask_data[gravity_logger_field_particle_ids], mask, + gravity_logger_field_names[gravity_logger_field_particle_ids])) { + memcpy(buff, &p->id_or_neg_offset, sizeof(long long)); + buff += sizeof(long long); + } + + return buff; +} +#endif // WITH_LOGGER +#endif // SWIFT_MULTISOFTENING_GRAVITY_LOGGER_H diff --git a/src/gravity_io.h b/src/gravity_io.h index 44f392ee06d43228f7aa46faa5c7d9015fde790b..b5d8f1ec2d2fc8a3a65cc42ae22acf720e04e322 100644 --- a/src/gravity_io.h +++ b/src/gravity_io.h @@ -32,6 +32,7 @@ #include "./gravity/Potential/gravity_io.h" #elif defined(MULTI_SOFTENING_GRAVITY) #include "./gravity/MultiSoftening/gravity_io.h" +#include "./gravity/MultiSoftening/gravity_logger.h" #else #error "Invalid choice of gravity variant" #endif diff --git a/src/hydro/Gadget2/hydro_logger.h b/src/hydro/Gadget2/hydro_logger.h new file mode 100644 index 0000000000000000000000000000000000000000..17f1a702e6095c16e189fe93daf1a83e9d3b3490 --- /dev/null +++ b/src/hydro/Gadget2/hydro_logger.h @@ -0,0 +1,240 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Coypright (c) 2020 Loic Hausammann (loic.hausammann@epfl.ch) + * + * 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 <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ +#ifndef SWIFT_GADGET2_HYDRO_LOGGER_H +#define SWIFT_GADGET2_HYDRO_LOGGER_H + +#include "logger_io.h" + +#ifdef WITH_LOGGER + +/* + * List of all possible mask. + * Outside the module, only hydro_logger_field_count is used. + */ +enum hydro_logger_fields_mask { + hydro_logger_field_coordinates = 0, + hydro_logger_field_velocities, + hydro_logger_field_accelerations, + hydro_logger_field_masses, + hydro_logger_field_smoothing_lengths, + hydro_logger_field_entropies, + hydro_logger_field_particle_ids, + hydro_logger_field_densities, + hydro_logger_field_count, +}; + +/* Name of each possible mask. */ +static const char *hydro_logger_field_names[hydro_logger_field_count] = { + "Coordinates", "Velocities", "Accelerations", "Masses", + "SmoothingLengths", "Entropies", "ParticleIDs", "Densities"}; + +/** + * @brief Initialize the logger. + * + * WARNING: this should be done in the same order than + * #hydro_logger_write_particle. + * + * @param mask_data Data for each type of mask. + * + * @return Number of masks used. + */ +INLINE static int hydro_logger_populate_mask_data(struct mask_data *mask_data) { + mask_data[hydro_logger_field_coordinates] = logger_create_mask_entry( + hydro_logger_field_names[hydro_logger_field_coordinates], + 3 * sizeof(double)); + + mask_data[hydro_logger_field_velocities] = logger_create_mask_entry( + hydro_logger_field_names[hydro_logger_field_velocities], + 3 * sizeof(float)); + + mask_data[hydro_logger_field_accelerations] = logger_create_mask_entry( + hydro_logger_field_names[hydro_logger_field_accelerations], + 3 * sizeof(float)); + + mask_data[hydro_logger_field_masses] = logger_create_mask_entry( + hydro_logger_field_names[hydro_logger_field_masses], sizeof(float)); + + mask_data[hydro_logger_field_smoothing_lengths] = logger_create_mask_entry( + hydro_logger_field_names[hydro_logger_field_smoothing_lengths], + sizeof(float)); + + mask_data[hydro_logger_field_entropies] = logger_create_mask_entry( + hydro_logger_field_names[hydro_logger_field_entropies], sizeof(float)); + + mask_data[hydro_logger_field_particle_ids] = logger_create_mask_entry( + hydro_logger_field_names[hydro_logger_field_particle_ids], + sizeof(long long)); + + mask_data[hydro_logger_field_densities] = logger_create_mask_entry( + hydro_logger_field_names[hydro_logger_field_densities], sizeof(float)); + + return hydro_logger_field_count; +} + +/** + * @brief Generates the mask and compute the size of the record. + * + * @param masks The list of masks (same order than in #hydro_logger_init). + * @param part The #part that will be written. + * @param xpart The #xpart that will be written. + * @param write_all Are we forcing to write all the fields? + * + * @param buffer_size (out) The requested size for the buffer. + * @param mask (out) The mask that will be written. + */ +INLINE static void hydro_logger_compute_size_and_mask( + const struct mask_data *masks, const struct part *part, + const struct xpart *xpart, const int write_all, size_t *buffer_size, + unsigned int *mask) { + + /* Here you can decide your own writing logic */ + + /* Add the coordinates. */ + *mask |= logger_add_field_to_mask( + masks[hydro_logger_field_coordinates], + hydro_logger_field_names[hydro_logger_field_coordinates], buffer_size); + + /* Add the velocities. */ + *mask |= logger_add_field_to_mask( + masks[hydro_logger_field_velocities], + hydro_logger_field_names[hydro_logger_field_velocities], buffer_size); + + /* Add the accelerations. */ + *mask |= logger_add_field_to_mask( + masks[hydro_logger_field_accelerations], + hydro_logger_field_names[hydro_logger_field_accelerations], buffer_size); + + /* Add the masses. */ + *mask |= logger_add_field_to_mask( + masks[hydro_logger_field_masses], + hydro_logger_field_names[hydro_logger_field_masses], buffer_size); + + /* Add the smoothing lengths. */ + *mask |= logger_add_field_to_mask( + masks[hydro_logger_field_smoothing_lengths], + hydro_logger_field_names[hydro_logger_field_smoothing_lengths], + buffer_size); + + /* Add the entropies. */ + *mask |= logger_add_field_to_mask( + masks[hydro_logger_field_entropies], + hydro_logger_field_names[hydro_logger_field_entropies], buffer_size); + + /* Add the ID. */ + *mask |= logger_add_field_to_mask( + masks[hydro_logger_field_particle_ids], + hydro_logger_field_names[hydro_logger_field_particle_ids], buffer_size); + + /* Add the density. */ + *mask |= logger_add_field_to_mask( + masks[hydro_logger_field_densities], + hydro_logger_field_names[hydro_logger_field_densities], buffer_size); +} + +/** + * @brief Write a particle to the logger. + * + * @param masks The list of masks (same order than in #hydro_logger_init). + * @param p The #part to write. + * @param xp The #xpart to write. + * @param mask The mask to use for this record. + * @param buff The buffer where to write the particle. + * + * @return The buffer after the data. + */ +INLINE static char *hydro_logger_write_particle( + const struct mask_data *mask_data, const struct part *p, + const struct xpart *xp, unsigned int *mask, char *buff) { + + /* Write the coordinate. */ + if (logger_should_write_field( + mask_data[hydro_logger_field_coordinates], mask, + hydro_logger_field_names[hydro_logger_field_coordinates])) { + memcpy(buff, p->x, 3 * sizeof(double)); + buff += 3 * sizeof(double); + } + + /* Write the velocity. */ + if (logger_should_write_field( + mask_data[hydro_logger_field_velocities], mask, + hydro_logger_field_names[hydro_logger_field_velocities])) { + memcpy(buff, p->v, 3 * sizeof(float)); + buff += 3 * sizeof(float); + } + + /* Write the acceleration. */ + if (logger_should_write_field( + mask_data[hydro_logger_field_accelerations], mask, + hydro_logger_field_names[hydro_logger_field_accelerations])) { + + /* Compute the acceleration due to hydro and gravity */ + float *acc = (float *)buff; + acc[0] = p->a_hydro[0] + xp->a_grav[0]; + acc[1] = p->a_hydro[1] + xp->a_grav[1]; + acc[2] = p->a_hydro[2] + xp->a_grav[2]; + + memcpy(buff, acc, 3 * sizeof(float)); + buff += 3 * sizeof(float); + } + + /* Write the mass. */ + if (logger_should_write_field( + mask_data[hydro_logger_field_masses], mask, + hydro_logger_field_names[hydro_logger_field_masses])) { + memcpy(buff, &p->mass, sizeof(float)); + buff += sizeof(float); + } + + /* Write the smoothing length. */ + if (logger_should_write_field( + mask_data[hydro_logger_field_smoothing_lengths], mask, + hydro_logger_field_names[hydro_logger_field_smoothing_lengths])) { + memcpy(buff, &p->h, sizeof(float)); + buff += sizeof(float); + } + + /* Write the entropy. */ + if (logger_should_write_field( + mask_data[hydro_logger_field_entropies], mask, + hydro_logger_field_names[hydro_logger_field_entropies])) { + memcpy(buff, &p->entropy, sizeof(float)); + buff += sizeof(float); + } + + /* Write the Id. */ + if (logger_should_write_field( + mask_data[hydro_logger_field_particle_ids], mask, + hydro_logger_field_names[hydro_logger_field_particle_ids])) { + memcpy(buff, &p->id, sizeof(long long)); + buff += sizeof(long long); + } + + /* Write the density. */ + if (logger_should_write_field( + mask_data[hydro_logger_field_densities], mask, + hydro_logger_field_names[hydro_logger_field_densities])) { + memcpy(buff, &p->rho, sizeof(float)); + buff += sizeof(float); + } + + return buff; +} + +#endif // WITH_LOGGER +#endif // SWIFT_GADGET2_HYDRO_LOGGER_H diff --git a/src/hydro_io.h b/src/hydro_io.h index d3e98771898f6cfdd8b7758932fd65b8534b5f27..dc0bf3af054f2751c9a9198da8893f15bed17b69 100644 --- a/src/hydro_io.h +++ b/src/hydro_io.h @@ -27,6 +27,7 @@ #include "./hydro/Minimal/hydro_io.h" #elif defined(GADGET2_SPH) #include "./hydro/Gadget2/hydro_io.h" +#include "./hydro/Gadget2/hydro_logger.h" #elif defined(HOPKINS_PE_SPH) #include "./hydro/PressureEntropy/hydro_io.h" #elif defined(HOPKINS_PU_SPH) diff --git a/src/logger.c b/src/logger.c index c970385e27b561dc466c89bcf41a4845843f69bb..349ccf02d24fce973382260ec65e6926447a81ac 100644 --- a/src/logger.c +++ b/src/logger.c @@ -30,6 +30,9 @@ #include <stdlib.h> #include <string.h> +/* Define the particles first */ +#include "part.h" + /* This object's header. */ #include "logger.h" @@ -38,7 +41,9 @@ #include "dump.h" #include "engine.h" #include "error.h" -#include "part.h" +#include "gravity_io.h" +#include "hydro_io.h" +#include "stars_io.h" #include "units.h" /* @@ -48,7 +53,7 @@ // TODO change this to number of bits #define logger_mask_size 2 -/* Number of bits for chunk header. */ +/* Number of bits for record header. */ #define logger_header_bytes 8 /* Number bytes for an offset. */ @@ -62,43 +67,30 @@ char logger_file_format[logger_format_size] = "SWIFT_LOGGER"; -const struct mask_data logger_mask_data[logger_count_mask] = { - /* Particle's position. */ - {3 * sizeof(double), 1 << logger_x, "positions"}, - /* Particle's velocity. */ - {3 * sizeof(float), 1 << logger_v, "velocities"}, - /* Particle's acceleration. */ - {3 * sizeof(float), 1 << logger_a, "accelerations"}, - /* Particle's entropy. */ - {sizeof(float), 1 << logger_u, "entropy"}, - /* Particle's smoothing length. */ - {sizeof(float), 1 << logger_h, "smoothing length"}, - /* Particle's density. */ - {sizeof(float), 1 << logger_rho, "density"}, - /* Particle's constants: mass (float) and ID (long long). */ - {sizeof(float) + sizeof(long long), 1 << logger_consts, "consts"}, - /* Flag for special cases (e.g. change of MPI rank, star formation, ...) */ - {sizeof(uint32_t), 1 << logger_special_flags, "special flags"}, - /* Simulation time stamp: integertime and double time (e.g. scale - factor or time). */ - {sizeof(integertime_t) + sizeof(double), 1 << logger_timestamp, - "timestamp"}, -}; +/* + * The two following defines need to correspond to the list's order + * in logger_init_masks. + */ +/* Index of the special flags in the list of masks */ +#define logger_index_special_flags 0 +/* Index of the timestamp in the list of masks */ +#define logger_index_timestamp 1 /** - * @brief Write the header of a chunk (offset + mask). + * @brief Write the header of a record (offset + mask). * * This is maybe broken for big(?) endian. * - * @param buff The writing buffer - * @param mask The mask to write - * @param offset The old offset - * @param offset_new The new offset + * @param buff The buffer where to write the mask and offset. + * @param mask The mask to write inside the buffer. + * @param offset The offset of the previous record. + * @param offset_new The offset of the current record. * * @return updated buff */ -char *logger_write_chunk_header(char *buff, const unsigned int *mask, - const size_t *offset, const size_t offset_new) { +char *logger_write_record_header(char *buff, const unsigned int *mask, + const size_t *offset, + const size_t offset_new) { /* write mask. */ memcpy(buff, mask, logger_mask_size); buff += logger_mask_size; @@ -127,51 +119,18 @@ void logger_write_data(struct dump *d, size_t *offset, size_t size, /* write data to the buffer. */ memcpy(buff, p, size); - /* Update offset to end of chunk. */ + /* Update offset to end of record. */ *offset += size; } -/** - * @brief Compute the size of a message given its mask. - * - * @param mask The mask that will be used to dump a #part or #gpart. - * - * @return The size of the logger message in bytes. - */ -int logger_compute_chunk_size(unsigned int mask) { - - /* Start with 8 bytes for the header. */ - int size = logger_mask_size + logger_offset_size; - - /* Is this a particle or a timestep? */ - if (mask & logger_mask_data[logger_timestamp].mask) { - - /* The timestamp should not contain any other bits. */ - if (mask != logger_mask_data[logger_timestamp].mask) - error("Timestamps should not include any other data."); - - /* A timestamp consists of an unsigned long long int. */ - size += logger_mask_data[logger_timestamp].size; - - } else { - - for (int i = 0; i < logger_count_mask; i++) { - if (mask & logger_mask_data[i].mask) { - size += logger_mask_data[i].size; - } - } - } - - return size; -} - /** * @brief log all particles in the engine. * * @param log The #logger_writer * @param e The #engine */ -void logger_log_all(struct logger_writer *log, const struct engine *e) { +void logger_log_all_particles(struct logger_writer *log, + const struct engine *e) { /* Ensure that enough space is available. */ logger_ensure_size(log, e->s->nr_parts, e->s->nr_gparts, e->s->nr_sparts); @@ -179,26 +138,17 @@ void logger_log_all(struct logger_writer *log, const struct engine *e) { /* some constants. */ const struct space *s = e->s; - /* loop over all parts. */ - for (size_t i = 0; i < s->nr_parts; i++) { - logger_log_part(log, &s->parts[i], &s->xparts[i], logger_masks_all_part, - /* Special flags */ 0); - } + /* log the parts. */ + logger_log_parts(log, s->parts, s->xparts, s->nr_parts, e, + /* log_all_fields */ 1, /* Special flags */ 0); - /* loop over all gparts */ - for (size_t i = 0; i < s->nr_gparts; i++) { - /* Log only the dark matter */ - if (s->gparts[i].type != swift_type_dark_matter) continue; + /* log the gparts */ + logger_log_gparts(log, s->gparts, s->nr_gparts, e, + /* log_all_fields */ 1, /* Special flags */ 0); - logger_log_gpart(log, &s->gparts[i], logger_masks_all_gpart, - /* Special flags */ 0); - } - - /* loop over all sparts */ - for (size_t i = 0; i < s->nr_sparts; i++) { - logger_log_spart(log, &s->sparts[i], logger_masks_all_spart, - /* Special flags */ 0); - } + /* log the parts */ + logger_log_sparts(log, s->sparts, s->nr_sparts, e, + /* log_all_fields */ 1, /* Special flags */ 0); if (e->total_nr_bparts > 0) error("Not implemented"); } @@ -206,81 +156,41 @@ void logger_log_all(struct logger_writer *log, const struct engine *e) { /** * @brief Copy the particle fields into a given buffer. * + * @param log The #logger_writer * @param p The #part to copy. + * @param xp The #xpart to copy. + * @param e The #engine. * @param mask The mask for the fields to write. * @param offset The offset to the previous log. * @param offset_new The offset of the current record. * @param buff The buffer to use when writing. * @param special_flags The data for the special flags. */ -void logger_copy_part_fields(const struct part *p, unsigned int mask, +void logger_copy_part_fields(const struct logger_writer *log, + const struct part *p, const struct xpart *xp, + const struct engine *e, unsigned int mask, size_t *offset, size_t offset_new, char *buff, const uint32_t special_flags) { - /* Write the header. */ - buff = logger_write_chunk_header(buff, &mask, offset, offset_new); - - /* Particle position as three doubles. */ - if (mask & logger_mask_data[logger_x].mask) { - memcpy(buff, p->x, logger_mask_data[logger_x].size); - buff += logger_mask_data[logger_x].size; - mask &= ~logger_mask_data[logger_x].mask; - } - - /* Particle velocity as three floats. */ - if (mask & logger_mask_data[logger_v].mask) { - memcpy(buff, p->v, logger_mask_data[logger_v].size); - buff += logger_mask_data[logger_v].size; - mask &= ~logger_mask_data[logger_v].mask; - } - - /* Particle accelleration as three floats. */ - if (mask & logger_mask_data[logger_a].mask) { - memcpy(buff, p->a_hydro, logger_mask_data[logger_a].size); - buff += logger_mask_data[logger_a].size; - mask &= ~logger_mask_data[logger_a].mask; - } - -#if defined(GADGET2_SPH) - - /* Particle internal energy as a single float. */ - if (mask & logger_mask_data[logger_u].mask) { - memcpy(buff, &p->entropy, logger_mask_data[logger_u].size); - buff += logger_mask_data[logger_u].size; - mask &= ~logger_mask_data[logger_u].mask; +#ifdef SWIFT_DEBUG_CHECKS + if (mask == 0) { + error("You should always log at least one field."); } #endif - /* Particle smoothing length as a single float. */ - if (mask & logger_mask_data[logger_h].mask) { - memcpy(buff, &p->h, logger_mask_data[logger_h].size); - buff += logger_mask_data[logger_h].size; - mask &= ~logger_mask_data[logger_h].mask; - } - - /* Particle density as a single float. */ - if (mask & logger_mask_data[logger_rho].mask) { - memcpy(buff, &p->rho, logger_mask_data[logger_rho].size); - buff += logger_mask_data[logger_rho].size; - mask &= ~logger_mask_data[logger_rho].mask; - } + /* Write the header. */ + buff = logger_write_record_header(buff, &mask, offset, offset_new); - /* Particle constants, which is a bit more complicated. */ - if (mask & logger_mask_data[logger_consts].mask) { - // TODO make it dependent of logger_mask_data - memcpy(buff, &p->mass, sizeof(float)); - buff += sizeof(float); - const int64_t id = p->id; - memcpy(buff, &id, sizeof(int64_t)); - buff += sizeof(int64_t); - mask &= ~logger_mask_data[logger_consts].mask; - } + /* Write the hydro fields */ + buff = hydro_logger_write_particle(log->mask_data_pointers.hydro, p, xp, + &mask, buff); /* Special flags */ - if (mask & logger_mask_data[logger_special_flags].mask) { - memcpy(buff, &special_flags, logger_mask_data[logger_special_flags].size); - buff += logger_mask_data[logger_special_flags].size; - mask &= ~logger_mask_data[logger_special_flags].mask; + if (mask & log->logger_mask_data[logger_index_special_flags].mask) { + memcpy(buff, &special_flags, + log->logger_mask_data[logger_index_special_flags].size); + buff += log->logger_mask_data[logger_index_special_flags].size; + mask &= ~log->logger_mask_data[logger_index_special_flags].mask; } #ifdef SWIFT_DEBUG_CHECKS @@ -296,39 +206,67 @@ void logger_copy_part_fields(const struct part *p, unsigned int mask, * @param log The #logger_writer * @param p The #part to dump. * @param xp The #xpart to dump. - * @param mask The mask of the data to dump. + * @param e The #engine. + * @param log_all_fields Should we log all the fields? * @param special_flags The value of the special flag. */ void logger_log_part(struct logger_writer *log, const struct part *p, - struct xpart *xp, unsigned int mask, - const uint32_t special_flags) { + struct xpart *xp, const struct engine *e, + const int log_all_fields, const uint32_t special_flags) { - logger_log_parts(log, p, xp, /* count */ 1, mask, special_flags); + logger_log_parts(log, p, xp, /* count */ 1, e, log_all_fields, special_flags); } /** * @brief Dump a group of #part to the log. * - * @param log The #logger_writer - * @param sp The #part to dump. - * @param mask The mask of the data to dump. + * @param log The #logger_writer. + * @param p The #part to dump. + * @param xp The #xpart to dump. * @param count The number of particle to dump. + * @param e The #engine. + * @param log_all_fields Should we log all the fields? * @param special_flags The value of the special flags. */ void logger_log_parts(struct logger_writer *log, const struct part *p, - struct xpart *xp, int count, unsigned int mask, - const uint32_t special_flags) { - /* Start by computing the size of the message. */ - const int size = logger_compute_chunk_size(mask); + struct xpart *xp, int count, const struct engine *e, + const int log_all_fields, const uint32_t special_flags) { + + /* Compute the size of the buffer. */ + size_t size_total = 0; + if (log_all_fields) { + size_total = count * (log->max_size_record_part + logger_header_bytes); + } else { + for (int i = 0; i < count; i++) { + unsigned int mask = 0; + size_t size = 0; + hydro_logger_compute_size_and_mask(log->mask_data_pointers.hydro, &p[i], + &xp[i], log_all_fields, &size, &mask); + size_total += size + logger_header_bytes; + } + } /* Allocate a chunk of memory in the dump of the right size. */ size_t offset_new; - char *buff = (char *)dump_get(&log->dump, count * size, &offset_new); + char *buff = (char *)dump_get(&log->dump, size_total, &offset_new); + /* Write the particles */ for (int i = 0; i < count; i++) { + /* Get the masks */ + size_t size = 0; + unsigned int mask = 0; + hydro_logger_compute_size_and_mask(log->mask_data_pointers.hydro, &p[i], + &xp[i], log_all_fields, &size, &mask); + size += logger_header_bytes; + + if (special_flags != 0) { + mask |= log->logger_mask_data[logger_index_special_flags].mask; + } + /* Copy everything into the buffer */ - logger_copy_part_fields(&p[i], mask, &xp[i].logger_data.last_offset, - offset_new, buff, special_flags); + logger_copy_part_fields(log, &p[i], &xp[i], e, mask, + &xp[i].logger_data.last_offset, offset_new, buff, + special_flags); /* Update the pointers */ xp[i].logger_data.last_offset = offset_new; @@ -341,50 +279,40 @@ void logger_log_parts(struct logger_writer *log, const struct part *p, /** * @brief Copy the particle fields into a given buffer. * + * @param log The #logger_writer. * @param sp The #spart to copy. + * @param e The #engine. * @param mask The mask for the fields to write. * @param offset The offset to the previous log. * @param offset_new The offset of the current record. * @param buff The buffer to use when writing. * @param special_flags The data for the special flags. */ -void logger_copy_spart_fields(const struct spart *sp, unsigned int mask, - size_t *offset, size_t offset_new, char *buff, +void logger_copy_spart_fields(const struct logger_writer *log, + const struct spart *sp, const struct engine *e, + unsigned int mask, size_t *offset, + size_t offset_new, char *buff, const uint32_t special_flags) { - /* Write the header. */ - buff = logger_write_chunk_header(buff, &mask, offset, offset_new); - - /* Particle position as three doubles. */ - if (mask & logger_mask_data[logger_x].mask) { - memcpy(buff, sp->x, logger_mask_data[logger_x].size); - buff += logger_mask_data[logger_x].size; - mask &= ~logger_mask_data[logger_x].mask; +#ifdef SWIFT_DEBUG_CHECKS + if (mask == 0) { + error("You should always log at least one field."); } +#endif - /* Particle velocity as three floats. */ - if (mask & logger_mask_data[logger_v].mask) { - memcpy(buff, sp->v, logger_mask_data[logger_v].size); - buff += logger_mask_data[logger_v].size; - mask &= ~logger_mask_data[logger_v].mask; - } + /* Write the header. */ + buff = logger_write_record_header(buff, &mask, offset, offset_new); - /* Particle constants, which is a bit more complicated. */ - if (mask & logger_mask_data[logger_consts].mask) { - // TODO make it dependent of logger_mask_data - memcpy(buff, &sp->mass, sizeof(float)); - buff += sizeof(float); - const int64_t id = sp->id; - memcpy(buff, &id, sizeof(int64_t)); - buff += sizeof(int64_t); - mask &= ~logger_mask_data[logger_consts].mask; - } + /* Write the stellar fields */ + buff = stars_logger_write_particle(log->mask_data_pointers.stars, sp, &mask, + buff); /* Special flags */ - if (mask & logger_mask_data[logger_special_flags].mask) { - memcpy(buff, &special_flags, logger_mask_data[logger_special_flags].size); - buff += logger_mask_data[logger_special_flags].size; - mask &= ~logger_mask_data[logger_special_flags].mask; + if (mask & log->logger_mask_data[logger_index_special_flags].mask) { + memcpy(buff, &special_flags, + log->logger_mask_data[logger_index_special_flags].size); + buff += log->logger_mask_data[logger_index_special_flags].size; + mask &= ~log->logger_mask_data[logger_index_special_flags].mask; } #ifdef SWIFT_DEBUG_CHECKS @@ -399,13 +327,15 @@ void logger_copy_spart_fields(const struct spart *sp, unsigned int mask, * * @param log The #logger_writer * @param sp The #spart to dump. - * @param mask The mask of the data to dump. + * @param e The #engine. + * @param log_all_fields Should we log all the fields? * @param special_flags The value of the special flag. */ void logger_log_spart(struct logger_writer *log, struct spart *sp, - unsigned int mask, const uint32_t special_flags) { + const struct engine *e, const int log_all_fields, + const uint32_t special_flags) { - logger_log_sparts(log, sp, /* count */ 1, mask, special_flags); + logger_log_sparts(log, sp, /* count */ 1, e, log_all_fields, special_flags); } /** @@ -413,23 +343,49 @@ void logger_log_spart(struct logger_writer *log, struct spart *sp, * * @param log The #logger_writer * @param sp The #spart to dump. - * @param mask The mask of the data to dump. + * @param e The #engine. + * @param log_all_fields Should we log all the fields? * @param count The number of particle to dump. * @param special_flags The value of the special flags. */ void logger_log_sparts(struct logger_writer *log, struct spart *sp, int count, - unsigned int mask, const uint32_t special_flags) { - /* Start by computing the size of the message. */ - const int size = logger_compute_chunk_size(mask); + const struct engine *e, const int log_all_fields, + const uint32_t special_flags) { + + /* Compute the size of the buffer. */ + size_t size_total = 0; + if (log_all_fields) { + size_total = count * (log->max_size_record_spart + logger_header_bytes); + } else { + for (int i = 0; i < count; i++) { + unsigned int mask = 0; + size_t size = 0; + stars_logger_compute_size_and_mask(log->mask_data_pointers.stars, &sp[i], + log_all_fields, &size, &mask); + size_total += size + logger_header_bytes; + } + } /* Allocate a chunk of memory in the dump of the right size. */ size_t offset_new; - char *buff = (char *)dump_get(&log->dump, count * size, &offset_new); + char *buff = (char *)dump_get(&log->dump, size_total, &offset_new); for (int i = 0; i < count; i++) { + /* Get the masks */ + size_t size = 0; + unsigned int mask = 0; + stars_logger_compute_size_and_mask(log->mask_data_pointers.stars, &sp[i], + log_all_fields, &size, &mask); + size += logger_header_bytes; + + if (special_flags != 0) { + mask |= log->logger_mask_data[logger_index_special_flags].mask; + } + /* Copy everything into the buffer */ - logger_copy_spart_fields(&sp[i], mask, &sp[i].logger_data.last_offset, - offset_new, buff, special_flags); + logger_copy_spart_fields(log, &sp[i], e, mask, + &sp[i].logger_data.last_offset, offset_new, buff, + special_flags); /* Update the pointers */ sp[i].logger_data.last_offset = offset_new; @@ -442,57 +398,40 @@ void logger_log_sparts(struct logger_writer *log, struct spart *sp, int count, /** * @brief Copy the particle fields into a given buffer. * + * @param log The #logger_writer. * @param gp The #gpart to copy. + * @param e The #engine. * @param mask The mask for the fields to write. * @param offset The offset to the previous log. * @param offset_new The offset of the current record. * @param buff The buffer to use when writing. * @param special_flags The data of the special flag. */ -void logger_copy_gpart_fields(const struct gpart *gp, unsigned int mask, - size_t *offset, size_t offset_new, char *buff, +void logger_copy_gpart_fields(const struct logger_writer *log, + const struct gpart *gp, const struct engine *e, + unsigned int mask, size_t *offset, + size_t offset_new, char *buff, const uint32_t special_flags) { - /* Write the header. */ - buff = logger_write_chunk_header(buff, &mask, offset, offset_new); - - /* Particle position as three doubles. */ - if (mask & logger_mask_data[logger_x].mask) { - memcpy(buff, gp->x, logger_mask_data[logger_x].size); - buff += logger_mask_data[logger_x].size; - mask &= ~logger_mask_data[logger_x].mask; - } - - /* Particle velocity as three floats. */ - if (mask & logger_mask_data[logger_v].mask) { - memcpy(buff, gp->v_full, logger_mask_data[logger_v].size); - buff += logger_mask_data[logger_v].size; - mask &= ~logger_mask_data[logger_v].mask; +#ifdef SWIFT_DEBUG_CHECKS + if (mask == 0) { + error("You should always log at least one field."); } +#endif - /* Particle accelleration as three floats. */ - if (mask & logger_mask_data[logger_a].mask) { - memcpy(buff, gp->a_grav, logger_mask_data[logger_a].size); - buff += logger_mask_data[logger_a].size; - mask &= ~logger_mask_data[logger_a].mask; - } + /* Write the header. */ + buff = logger_write_record_header(buff, &mask, offset, offset_new); - /* Particle constants, which is a bit more complicated. */ - if (mask & logger_mask_data[logger_consts].mask) { - // TODO make it dependent of logger_mask_data. - memcpy(buff, &gp->mass, sizeof(float)); - buff += sizeof(float); - const int64_t id = gp->id_or_neg_offset; - memcpy(buff, &id, sizeof(int64_t)); - buff += sizeof(int64_t); - mask &= ~logger_mask_data[logger_consts].mask; - } + /* Write the hydro fields */ + buff = gravity_logger_write_particle(log->mask_data_pointers.gravity, gp, + &mask, buff); /* Special flags */ - if (mask & logger_mask_data[logger_special_flags].mask) { - memcpy(buff, &special_flags, logger_mask_data[logger_special_flags].size); - buff += logger_mask_data[logger_special_flags].size; - mask &= ~logger_mask_data[logger_special_flags].mask; + if (mask & log->logger_mask_data[logger_index_special_flags].mask) { + memcpy(buff, &special_flags, + log->logger_mask_data[logger_index_special_flags].size); + buff += log->logger_mask_data[logger_index_special_flags].size; + mask &= ~log->logger_mask_data[logger_index_special_flags].mask; } #ifdef SWIFT_DEBUG_CHECKS @@ -507,12 +446,14 @@ void logger_copy_gpart_fields(const struct gpart *gp, unsigned int mask, * * @param log The #logger_writer * @param p The #gpart to dump. - * @param mask The mask of the data to dump. + * @param e The #engine. + * @param log_all_fields Should we log all the fields? * @param special_flags The value of the special flags. */ void logger_log_gpart(struct logger_writer *log, struct gpart *p, - unsigned int mask, const uint32_t special_flags) { - logger_log_gparts(log, p, /* count */ 1, mask, special_flags); + const struct engine *e, const int log_all_fields, + const uint32_t special_flags) { + logger_log_gparts(log, p, /* count */ 1, e, log_all_fields, special_flags); } /** @@ -520,25 +461,53 @@ void logger_log_gpart(struct logger_writer *log, struct gpart *p, * * @param log The #logger_writer * @param p The #gpart to dump. - * @param mask The mask of the data to dump. * @param count The number of particle to dump. + * @param e The #engine. + * @param log_all_fields Should we log all the fields? * @param special_flags The value of the special flags. */ void logger_log_gparts(struct logger_writer *log, struct gpart *p, int count, - unsigned int mask, const uint32_t special_flags) { - /* Start by computing the size of the message. */ - const int size = logger_compute_chunk_size(mask); + const struct engine *e, const int log_all_fields, + const uint32_t special_flags) { + + /* Compute the size of the buffer. */ + size_t size_total = 0; + if (log_all_fields) { + size_total = count * (log->max_size_record_gpart + logger_header_bytes); + } else { + for (int i = 0; i < count; i++) { + /* Log only the dark matter */ + if (p[i].type != swift_type_dark_matter) continue; + + unsigned int mask = 0; + size_t size = 0; + gravity_logger_compute_size_and_mask(log->mask_data_pointers.gravity, + &p[i], log_all_fields, &size, &mask); + size_total += size + logger_header_bytes; + } + } /* Allocate a chunk of memory in the dump of the right size. */ size_t offset_new; - char *buff = (char *)dump_get(&log->dump, count * size, &offset_new); + char *buff = (char *)dump_get(&log->dump, size_total, &offset_new); for (int i = 0; i < count; i++) { /* Log only the dark matter */ if (p[i].type != swift_type_dark_matter) continue; + /* Get the masks */ + size_t size = 0; + unsigned int mask = 0; + gravity_logger_compute_size_and_mask(log->mask_data_pointers.gravity, &p[i], + log_all_fields, &size, &mask); + size += logger_header_bytes; + + if (special_flags != 0) { + mask |= log->logger_mask_data[logger_index_special_flags].mask; + } + /* Copy everything into the buffer */ - logger_copy_gpart_fields(&p[i], mask, &p[i].logger_data.last_offset, + logger_copy_gpart_fields(log, &p[i], e, mask, &p[i].logger_data.last_offset, offset_new, buff, special_flags); /* Update the pointers */ @@ -561,21 +530,19 @@ void logger_log_gparts(struct logger_writer *log, struct gpart *p, int count, void logger_log_timestamp(struct logger_writer *log, integertime_t timestamp, double time, size_t *offset) { struct dump *dump = &log->dump; - /* Start by computing the size of the message. */ const int size = - logger_compute_chunk_size(logger_mask_data[logger_timestamp].mask); + log->logger_mask_data[logger_index_timestamp].size + logger_header_bytes; /* Allocate a chunk of memory in the dump of the right size. */ size_t offset_new; char *buff = (char *)dump_get(dump, size, &offset_new); /* Write the header. */ - unsigned int mask = logger_mask_data[logger_timestamp].mask; - buff = logger_write_chunk_header(buff, &mask, offset, offset_new); + unsigned int mask = log->logger_mask_data[logger_index_timestamp].mask; + buff = logger_write_record_header(buff, &mask, offset, offset_new); /* Store the timestamp. */ - // TODO make it dependent of logger_mask_data. memcpy(buff, ×tamp, sizeof(integertime_t)); buff += sizeof(integertime_t); @@ -613,7 +580,7 @@ void logger_ensure_size(struct logger_writer *log, size_t total_nr_parts, limit += total_nr_sparts; // TODO improve estimate with the size of each particle - limit *= log->max_chunk_size; + limit *= log->max_record_size; /* ensure enough space in dump */ dump_ensure(&log->dump, limit, log->buffer_scale * limit); @@ -628,13 +595,200 @@ void logger_get_dump_name(struct logger_writer *log, char *filename) { sprintf(filename, "%s_%04i.dump", log->base_name, engine_rank); } +/** + * @brief Initialize the variable logger_mask_data. + * + * @param log The #logger_writer. + * @param e The #engine. + */ +void logger_init_masks(struct logger_writer *log, const struct engine *e) { + /* Set the pointers to 0 */ + log->mask_data_pointers.hydro = NULL; + log->mask_data_pointers.stars = NULL; + log->mask_data_pointers.gravity = NULL; + + /* Get the policies */ + const int with_hydro = e->policy & engine_policy_hydro; + const int with_grav = (e->policy & engine_policy_self_gravity) || + (e->policy & engine_policy_external_gravity); + const int with_stars = e->policy & engine_policy_stars; + + struct mask_data list[100]; + int num_fields = 0; + + /* The next fields must be the two first ones. */ + /* Add the special flags (written manually => no need of offset) */ + if (logger_index_special_flags != 0) { + error("Expecting the special flags to be the first element."); + } + list[logger_index_special_flags] = + logger_create_mask_entry("SpecialFlags", sizeof(int)); + num_fields += 1; + + /* Add the timestamp */ + if (logger_index_timestamp != 1) { + error("Expecting the timestamp to be the first element."); + } + list[logger_index_timestamp] = logger_create_mask_entry( + "Timestamp", sizeof(integertime_t) + sizeof(double)); + list[num_fields].type = mask_type_timestep; // flag it as timestamp + num_fields += 1; + + // TODO add chemistry, cooling, ... + xpart + spart + + /* Get all the fields that need to be written for the hydro. */ + if (with_hydro) { + struct mask_data *tmp = &list[num_fields]; + + /* Set the mask_data_pointers */ + log->mask_data_pointers.hydro = tmp; + + /* Set the masks */ + num_fields = hydro_logger_populate_mask_data(tmp); + /* Set the particle type */ + for (int i = 0; i < num_fields; i++) { + tmp[i].type = mask_type_gas; + } + } + + /* Get all the fields that need to be written for the stars. */ + if (with_stars) { + struct mask_data *tmp = &list[num_fields]; + + /* Set the mask_data_pointers */ + log->mask_data_pointers.stars = tmp; + + /* Set the masks */ + int tmp_num_fields = stars_logger_populate_mask_data(tmp); + /* Set the particle type */ + for (int i = 0; i < tmp_num_fields; i++) { + tmp[i].type = mask_type_stars; + } + num_fields += tmp_num_fields; + } + + /* Get all the fields that need to be written for the gravity. */ + if (with_grav) { + struct mask_data *tmp = &list[num_fields]; + + /* Set the mask_data_pointers */ + log->mask_data_pointers.gravity = tmp; + + /* Set the masks */ + int tmp_num_fields = gravity_logger_populate_mask_data(tmp); + /* Set the particle type */ + for (int i = 0; i < tmp_num_fields; i++) { + tmp[i].type = mask_type_dark_matter; + } + num_fields += tmp_num_fields; + } + + /* Set the masks and ensure to have only one for the common fields + (e.g. Coordinates). + Initially we have (Name, mask, part_type): + - Coordinates, 0, 0 + - Velocity, 0, 0 + - Coordinates, 0, 1 + + And get: + - Coordinates, 1, 0 + - Velocity, 2, 0 + - Coordinates, 1, 1 + */ + int mask = 0; + for (int i = 0; i < num_fields; i++) { + /* Skip the elements already processed. */ + if (list[i].mask != 0) { + continue; + } + const char *name = list[i].name; + list[i].mask = 1 << mask; + + /* Check if the field exists in the other particle type. */ + for (int j = i + 1; j < num_fields; j++) { + /* Check if the name is the same */ + if (strcmp(name, list[j].name) == 0) { + /* Check if the data are the same */ + if (list[i].size != list[j].size) { + error("Found two same fields but with different data size (%s).", + name); + } + + list[j].mask = 1 << mask; + } + } + mask += 1; + } + + /* Check that we have enough available flags. */ + if (mask >= 8 * logger_mask_size) { + error( + "Not enough available flags for all the fields. " + "Please reduce the number of output fields."); + } + + /* Save the data */ + size_t size_list = sizeof(struct mask_data) * num_fields; + log->logger_mask_data = (struct mask_data *)malloc(size_list); + memcpy(log->logger_mask_data, list, size_list); + + /* Update the pointers */ + if (log->mask_data_pointers.hydro != NULL) { + log->mask_data_pointers.hydro = + log->logger_mask_data + (log->mask_data_pointers.hydro - list); + } + if (log->mask_data_pointers.stars != NULL) { + log->mask_data_pointers.stars = + log->logger_mask_data + (log->mask_data_pointers.stars - list); + } + if (log->mask_data_pointers.gravity != NULL) { + log->mask_data_pointers.gravity = + log->logger_mask_data + (log->mask_data_pointers.gravity - list); + } + + /* Compute the maximal size of the records. */ + log->max_size_record_part = 0; + if (with_hydro) { + for (int i = 0; i < hydro_logger_field_count; i++) { + log->max_size_record_part += log->mask_data_pointers.hydro[i].size; + } + } + + log->max_size_record_gpart = 0; + if (with_grav) { + for (int i = 0; i < gravity_logger_field_count; i++) { + log->max_size_record_gpart += log->mask_data_pointers.gravity[i].size; + } + } + + log->max_size_record_spart = 0; + if (with_stars) { + for (int i = 0; i < stars_logger_field_count; i++) { + log->max_size_record_spart += log->mask_data_pointers.stars[i].size; + } + } + + /* Set the counter */ + log->logger_count_mask = num_fields; + +#ifdef SWIFT_DEBUG_CHECKS + message("The logger contains the following masks:"); + for (int i = 0; i < log->logger_count_mask; i++) { + message("%20s:\t mask=%03u\t size=%i", log->logger_mask_data[i].name, + log->logger_mask_data[i].mask, log->logger_mask_data[i].size); + } +#endif +} + /** * @brief intialize the logger structure * * @param log The #logger_writer + * @param e The #engine. * @param params The #swift_params */ -void logger_init(struct logger_writer *log, struct swift_params *params) { +void logger_init(struct logger_writer *log, const struct engine *e, + struct swift_params *params) { /* read parameters. */ log->delta_step = parser_get_param_int(params, "Logger:delta_step"); size_t buffer_size = @@ -647,6 +801,9 @@ void logger_init(struct logger_writer *log, struct swift_params *params) { log->index.mem_frac = parser_get_opt_param_float(params, "Logger:index_mem_frac", 0.05); + /* Initialize the logger_mask_data */ + logger_init_masks(log, e); + /* set initial value of parameters. */ log->timestamp_offset = 0; log->index.dump_size_last_output = 0; @@ -655,14 +812,17 @@ void logger_init(struct logger_writer *log, struct swift_params *params) { char logger_name_file[PARSER_MAX_LINE_SIZE]; logger_get_dump_name(log, logger_name_file); - /* Compute max size for a particle chunk. */ + /* Compute max size for a particle record. */ int max_size = logger_offset_size + logger_mask_size; /* Loop over all fields except timestamp. */ - for (int i = 0; i < logger_count_mask - 1; i++) { - max_size += logger_mask_data[i].size; + for (int i = 0; i < log->logger_count_mask; i++) { + /* Skip the timestamp */ + if (i == logger_index_timestamp) continue; + + max_size += log->logger_mask_data[i].size; } - log->max_chunk_size = max_size; + log->max_record_size = max_size; /* init dump. */ dump_init(&log->dump, logger_name_file, buffer_size); @@ -673,7 +833,13 @@ void logger_init(struct logger_writer *log, struct swift_params *params) { * * @param log The #logger_writer */ -void logger_free(struct logger_writer *log) { dump_close(&log->dump); } +void logger_free(struct logger_writer *log) { + dump_close(&log->dump); + + free(log->logger_mask_data); + log->logger_mask_data = NULL; + log->logger_count_mask = 0; +} /** * @brief Write a file header to a logger file @@ -716,37 +882,53 @@ void logger_write_file_header(struct logger_writer *log) { const unsigned int label_size = logger_label_size; logger_write_data(dump, &file_offset, sizeof(unsigned int), &label_size); - /* write number of masks. */ - const unsigned int count_mask = logger_count_mask; - logger_write_data(dump, &file_offset, sizeof(unsigned int), &count_mask); + /* placeholder to write the number of unique masks. */ + char *skip_unique_masks = dump_get(dump, sizeof(unsigned int), &file_offset); /* write masks. */ // loop over all mask type. - for (int i = 0; i < logger_count_mask; i++) { + unsigned int unique_mask = 0; + for (int i = 0; i < log->logger_count_mask; i++) { + /* Check if the mask was not already written */ + int is_written = 0; + for (int j = 0; j < i; j++) { + if (log->logger_mask_data[i].mask == log->logger_mask_data[j].mask) { + is_written = 1; + break; + } + } + + if (is_written) { + continue; + } + + unique_mask += 1; + // mask name. logger_write_data(dump, &file_offset, logger_label_size, - &logger_mask_data[i].name); + &log->logger_mask_data[i].name); // mask size. logger_write_data(dump, &file_offset, sizeof(unsigned int), - &logger_mask_data[i].size); + &log->logger_mask_data[i].size); } + memcpy(skip_unique_masks, &unique_mask, sizeof(unsigned int)); /* last step: write first offset. */ memcpy(skip_header, &file_offset, logger_offset_size); } /** - * @brief read chunk header + * @brief read record header * * @param buff The reading buffer * @param mask The mask to read - * @param offset (return) the offset pointed by this chunk (absolute) - * @param cur_offset The current chunk offset + * @param offset (return) the offset pointed by this record (absolute) + * @param cur_offset The current record offset * * @return Number of bytes read */ -__attribute__((always_inline)) INLINE static int logger_read_chunk_header( +__attribute__((always_inline)) INLINE static int logger_read_record_header( const char *buff, unsigned int *mask, size_t *offset, size_t cur_offset) { memcpy(mask, buff, logger_mask_size); buff += logger_mask_size; @@ -768,7 +950,8 @@ __attribute__((always_inline)) INLINE static int logger_read_chunk_header( * * @return The mask containing the values read. */ -int logger_read_part(struct part *p, size_t *offset, const char *buff) { +int logger_read_part(const struct logger_writer *log, struct part *p, + size_t *offset, const char *buff) { /* Jump to the offset. */ buff = &buff[*offset]; @@ -776,62 +959,46 @@ int logger_read_part(struct part *p, size_t *offset, const char *buff) { /* Start by reading the logger mask for this entry. */ const size_t cur_offset = *offset; unsigned int mask = 0; - buff += logger_read_chunk_header(buff, &mask, offset, cur_offset); - - /* We are only interested in particle data. */ - if (mask & logger_mask_data[logger_timestamp].mask) - error("Trying to read timestamp as particle."); - - /* Particle position as three doubles. */ - if (mask & logger_mask_data[logger_x].mask) { - memcpy(p->x, buff, logger_mask_data[logger_x].size); - buff += logger_mask_data[logger_x].size; - } - - /* Particle velocity as three floats. */ - if (mask & logger_mask_data[logger_v].mask) { - memcpy(p->v, buff, logger_mask_data[logger_v].size); - buff += logger_mask_data[logger_v].size; - } - - /* Particle accelleration as three floats. */ - if (mask & logger_mask_data[logger_a].mask) { - memcpy(p->a_hydro, buff, logger_mask_data[logger_a].size); - buff += logger_mask_data[logger_a].size; - } - + buff += logger_read_record_header(buff, &mask, offset, cur_offset); + + for (int i = 0; i < log->logger_count_mask; i++) { + if ((mask & log->logger_mask_data[i].mask) && + (log->logger_mask_data[i].type == mask_type_gas)) { + + const char *name = log->logger_mask_data[i].name; + if (strcmp("Coordinates", name) == 0) { + memcpy(p->x, buff, 3 * sizeof(double)); + buff += 3 * sizeof(double); + } else if (strcmp("Velocities", name) == 0) { + memcpy(p->v, buff, 3 * sizeof(float)); + buff += 3 * sizeof(float); + } else if (strcmp("Accelerations", name) == 0) { + memcpy(p->a_hydro, buff, 3 * sizeof(float)); + buff += 3 * sizeof(float); + } else if (strcmp("SmoothingLengths", name) == 0) { + memcpy(&p->h, buff, sizeof(float)); + buff += sizeof(float); + } #if defined(GADGET2_SPH) - - /* Particle internal energy as a single float. */ - if (mask & logger_mask_data[logger_u].mask) { - memcpy(&p->entropy, buff, logger_mask_data[logger_u].size); - buff += logger_mask_data[logger_u].size; - } - - /* Particle smoothing length as a single float. */ - if (mask & logger_mask_data[logger_h].mask) { - memcpy(&p->h, buff, logger_mask_data[logger_h].size); - buff += logger_mask_data[logger_h].size; - } - - /* Particle density as a single float. */ - if (mask & logger_mask_data[logger_rho].mask) { - memcpy(&p->rho, buff, logger_mask_data[logger_rho].size); - buff += logger_mask_data[logger_rho].size; - } - - /* Particle constants, which is a bit more complicated. */ - if (mask & logger_mask_data[logger_rho].mask) { - // TODO make it dependent of logger_mask_data. - memcpy(&p->mass, buff, sizeof(float)); - buff += sizeof(float); - int64_t id = 0; - memcpy(&id, buff, sizeof(int64_t)); - p->id = id; - buff += sizeof(int64_t); - } - + else if (strcmp("Entropies", name) == 0) { + memcpy(&p->entropy, buff, sizeof(float)); + buff += sizeof(float); + } else if (strcmp("Masses", name) == 0) { + memcpy(&p->mass, buff, sizeof(float)); + buff += sizeof(float); + } else if (strcmp("Densities", name) == 0) { + memcpy(&p->rho, buff, sizeof(float)); + buff += sizeof(float); + } else if (strcmp("ParticleIDs", name) == 0) { + memcpy(&p->id, buff, sizeof(long long)); + buff += sizeof(long long); + } #endif + else { + error("Field '%s' not found", name); + } + } + } /* Finally, return the mask of the values we just read. */ return mask; @@ -847,7 +1014,8 @@ int logger_read_part(struct part *p, size_t *offset, const char *buff) { * * @return The mask containing the values read. */ -int logger_read_gpart(struct gpart *p, size_t *offset, const char *buff) { +int logger_read_gpart(const struct logger_writer *log, struct gpart *p, + size_t *offset, const char *buff) { /* Jump to the offset. */ buff = &buff[*offset]; @@ -855,43 +1023,32 @@ int logger_read_gpart(struct gpart *p, size_t *offset, const char *buff) { /* Start by reading the logger mask for this entry. */ const size_t cur_offset = *offset; unsigned int mask = 0; - buff += logger_read_chunk_header(buff, &mask, offset, cur_offset); - - /* We are only interested in particle data. */ - if (mask & logger_mask_data[logger_timestamp].mask) - error("Trying to read timestamp as particle."); - - /* We can't store all part fields in a gpart. */ - if (mask & - (logger_mask_data[logger_u].mask | logger_mask_data[logger_rho].mask)) - error("Trying to read SPH quantities into a gpart."); - - /* Particle position as three doubles. */ - if (mask & logger_mask_data[logger_x].mask) { - memcpy(p->x, buff, logger_mask_data[logger_x].size); - buff += logger_mask_data[logger_x].size; - } - - /* Particle velocity as three floats. */ - if (mask & logger_mask_data[logger_v].mask) { - memcpy(p->v_full, buff, logger_mask_data[logger_v].size); - buff += logger_mask_data[logger_v].size; - } - - /* Particle accelleration as three floats. */ - if (mask & logger_mask_data[logger_a].mask) { - memcpy(p->a_grav, buff, logger_mask_data[logger_a].size); - buff += logger_mask_data[logger_a].size; - } - - /* Particle constants, which is a bit more complicated. */ - if (mask & logger_mask_data[logger_rho].mask) { - // TODO make it dependent of logger_mask_data - memcpy(&p->mass, buff, sizeof(float)); - buff += sizeof(float); - int64_t id = p->id_or_neg_offset; - memcpy(&id, buff, sizeof(int64_t)); - buff += sizeof(int64_t); + buff += logger_read_record_header(buff, &mask, offset, cur_offset); + + for (int i = 0; i < log->logger_count_mask; i++) { + if ((mask & log->logger_mask_data[i].mask) && + (log->logger_mask_data[i].type == mask_type_dark_matter)) { + + const char *name = log->logger_mask_data[i].name; + if (strcmp("Coordinates", name) == 0) { + memcpy(p->x, buff, 3 * sizeof(double)); + buff += 3 * sizeof(double); + } else if (strcmp("Velocities", name) == 0) { + memcpy(p->v_full, buff, 3 * sizeof(float)); + buff += 3 * sizeof(float); + } else if (strcmp("Accelerations", name) == 0) { + memcpy(p->a_grav, buff, 3 * sizeof(float)); + buff += 3 * sizeof(float); + } else if (strcmp("ParticleIDs", name) == 0) { + memcpy(&p->id_or_neg_offset, buff, sizeof(long long)); + buff += sizeof(long long); + } else if (strcmp("Masses", name) == 0) { + memcpy(&p->mass, buff, sizeof(float)); + buff += sizeof(float); + } else { + error("Field '%s' not found", name); + } + } } /* Finally, return the mask of the values we just read. */ @@ -901,6 +1058,7 @@ int logger_read_gpart(struct gpart *p, size_t *offset, const char *buff) { /** * @brief Read a logger message for a timestamp. * + * @param log The #logger_writer. * @param t The timestamp in which to store the value. * @param time The time in which to store the value. * @param offset Pointer to the offset of the logger message in the buffer, @@ -909,8 +1067,8 @@ int logger_read_gpart(struct gpart *p, size_t *offset, const char *buff) { * * @return The mask containing the values read. */ -int logger_read_timestamp(unsigned long long int *t, double *time, - size_t *offset, const char *buff) { +int logger_read_timestamp(const struct logger_writer *log, integertime_t *t, + double *time, size_t *offset, const char *buff) { /* Jump to the offset. */ buff = &buff[*offset]; @@ -918,20 +1076,19 @@ int logger_read_timestamp(unsigned long long int *t, double *time, /* Start by reading the logger mask for this entry. */ const size_t cur_offset = *offset; unsigned int mask = 0; - buff += logger_read_chunk_header(buff, &mask, offset, cur_offset); + buff += logger_read_record_header(buff, &mask, offset, cur_offset); /* We are only interested in timestamps. */ - if (!(mask & logger_mask_data[logger_timestamp].mask)) + if (!(mask & log->logger_mask_data[logger_index_timestamp].mask)) error("Trying to read timestamp from a particle."); /* Make sure we don't have extra fields. */ - if (mask != logger_mask_data[logger_timestamp].mask) + if (mask != log->logger_mask_data[logger_index_timestamp].mask) error("Timestamp message contains extra fields."); /* Copy the timestamp value from the buffer. */ - // TODO make it dependent of logger_mask_data. - memcpy(t, buff, sizeof(unsigned long long int)); - buff += sizeof(unsigned long long int); + memcpy(t, buff, sizeof(integertime_t)); + buff += sizeof(integertime_t); /* Copy the timestamp value from the buffer. */ memcpy(time, buff, sizeof(double)); @@ -949,6 +1106,11 @@ int logger_read_timestamp(unsigned long long int *t, double *time, void logger_struct_dump(const struct logger_writer *log, FILE *stream) { restart_write_blocks((void *)log, sizeof(struct logger_writer), 1, stream, "logger", "logger"); + + /* Write the masks */ + restart_write_blocks((void *)log->logger_mask_data, sizeof(struct mask_data), + log->logger_count_mask, stream, "logger_masks", + "logger_masks"); } /** @@ -963,6 +1125,13 @@ void logger_struct_restore(struct logger_writer *log, FILE *stream) { restart_read_blocks((void *)log, sizeof(struct logger_writer), 1, stream, NULL, "logger"); + /* Read the masks */ + log->logger_mask_data = (struct mask_data *)malloc(sizeof(struct mask_data) * + log->logger_count_mask); + + restart_read_blocks((void *)log->logger_mask_data, sizeof(struct mask_data), + log->logger_count_mask, stream, NULL, "logger_masks"); + /* generate dump filename */ char logger_name_file[PARSER_MAX_LINE_SIZE]; logger_get_dump_name(log, logger_name_file); diff --git a/src/logger.h b/src/logger.h index 036106cead6ef2c9057ff785348fc1c6fcbab386..78d8bbeabeaca191de1ec3dc928f5a7cc1a2a96f 100644 --- a/src/logger.h +++ b/src/logger.h @@ -39,7 +39,9 @@ struct part; struct engine; #define logger_major_version 0 -#define logger_minor_version 3 +#define logger_minor_version 4 +/* Size of the strings. */ +#define logger_string_length 200 /** * Logger entries contain messages representing the particle data at a given @@ -75,35 +77,10 @@ struct engine; * The offset refers to the relative location of the previous message for the * same particle or for the previous timestamp (if mask bit 7 is set). I.e. * the previous log entry will be at the address of the current mask byte minus - * the unsigned value stored in the offset. An offset equal to the chunk offset + * the unsigned value stored in the offset. An offset equal to the record offset * indicated that this is the first message for the given particle/timestamp. */ -/* Some constants. */ -enum logger_masks_number { - logger_x = 0, - logger_v = 1, - logger_a = 2, - logger_u = 3, - logger_h = 4, - logger_rho = 5, - logger_consts = 6, - logger_special_flags = 7, /* Flag for special cases */ - logger_timestamp = 8, /* expect it to be before count. */ - logger_count_mask = 9, /* Need to be the last. */ -} __attribute__((packed)); - -/* Defines some mask for logging all the fields */ -enum logger_masks_all { - logger_masks_all_part = (1 << logger_x) | (1 << logger_v) | (1 << logger_a) | - (1 << logger_u) | (1 << logger_h) | - (1 << logger_rho) | (1 << logger_consts), - logger_masks_all_gpart = (1 << logger_x) | (1 << logger_v) | (1 << logger_a) | - (1 << logger_consts), - logger_masks_all_spart = - (1 << logger_x) | (1 << logger_v) | (1 << logger_consts), -} __attribute__((packed)); - enum logger_special_flags { logger_flag_change_type = 1, /* Flag for a change of particle type */ logger_flag_mpi_enter, /* Flag for a particle received from another MPI rank @@ -113,27 +90,11 @@ enum logger_special_flags { logger_flag_create, /* Flag for a created particle */ } __attribute__((packed)); -struct mask_data { - /* Number of bytes for a mask. */ - int size; - - /* Mask value. */ - unsigned int mask; - - /* Name of the mask. */ - char name[100]; -}; - -extern const struct mask_data logger_mask_data[logger_count_mask]; - -/* Size of the strings. */ -#define logger_string_length 200 - /** * @brief structure containing global data for the particle logger. */ struct logger_writer { - /* Number of particle steps between dumping a chunk of data. */ + /* Number of particle updates between log entries. */ short int delta_step; /* Logger basename. */ @@ -157,8 +118,35 @@ struct logger_writer { /* scaling factor when buffer is too small. */ float buffer_scale; - /* Size of a chunk if every mask are activated. */ - int max_chunk_size; + /* Size of a record if every mask are activated. */ + int max_record_size; + + /* Description of all the fields that can be written. */ + struct mask_data *logger_mask_data; + + /* Pointer to the variable logger_mask_data for each module. */ + struct { + /* pointer for the hydro */ + struct mask_data *hydro; + + /* pointer for the gravity */ + struct mask_data *gravity; + + /* pointer for the stars */ + struct mask_data *stars; + } mask_data_pointers; + + /* Number of elements in logger_mask_data. */ + int logger_count_mask; + + /* Maximum size for a hydro record. */ + int max_size_record_part; + + /* Maximum size for a gravity record. */ + int max_size_record_gpart; + + /* Maximum size for a star record. */ + int max_size_record_spart; } SWIFT_STRUCT_ALIGN; @@ -172,23 +160,28 @@ struct logger_part_data { }; /* Function prototypes. */ -int logger_compute_chunk_size(unsigned int mask); -void logger_log_all(struct logger_writer *log, const struct engine *e); +void logger_log_all_particles(struct logger_writer *log, + const struct engine *e); void logger_log_part(struct logger_writer *log, const struct part *p, - struct xpart *xp, unsigned int mask, - const uint32_t special_flags); + struct xpart *xp, const struct engine *e, + const int log_all_fields, const uint32_t special_flags); void logger_log_parts(struct logger_writer *log, const struct part *p, - struct xpart *xp, int count, unsigned int mask, - const uint32_t special_flags); + struct xpart *xp, int count, const struct engine *e, + const int log_all_fields, const uint32_t special_flags); void logger_log_spart(struct logger_writer *log, struct spart *p, - unsigned int mask, const uint32_t special_flags); + const struct engine *e, const int log_all_fields, + const uint32_t special_flags); void logger_log_sparts(struct logger_writer *log, struct spart *sp, int count, - unsigned int mask, const uint32_t special_flags); + const struct engine *e, const int log_all_fields, + const uint32_t special_flags); void logger_log_gpart(struct logger_writer *log, struct gpart *p, - unsigned int mask, const uint32_t special_flags); + const struct engine *e, const int log_all_fields, + const uint32_t special_flags); void logger_log_gparts(struct logger_writer *log, struct gpart *gp, int count, - unsigned int mask, const uint32_t special_flags); -void logger_init(struct logger_writer *log, struct swift_params *params); + const struct engine *e, const int log_all_fields, + const uint32_t special_flags); +void logger_init(struct logger_writer *log, const struct engine *e, + struct swift_params *params); void logger_free(struct logger_writer *log); void logger_log_timestamp(struct logger_writer *log, integertime_t t, double time, size_t *offset); @@ -196,10 +189,12 @@ void logger_ensure_size(struct logger_writer *log, size_t total_nr_parts, size_t total_nr_gparts, size_t total_nr_sparts); void logger_write_file_header(struct logger_writer *log); -int logger_read_part(struct part *p, size_t *offset, const char *buff); -int logger_read_gpart(struct gpart *p, size_t *offset, const char *buff); -int logger_read_timestamp(unsigned long long int *t, double *time, - size_t *offset, const char *buff); +int logger_read_part(const struct logger_writer *log, struct part *p, + size_t *offset, const char *buff); +int logger_read_gpart(const struct logger_writer *log, struct gpart *p, + size_t *offset, const char *buff); +int logger_read_timestamp(const struct logger_writer *log, integertime_t *t, + double *time, size_t *offset, const char *buff); void logger_struct_dump(const struct logger_writer *log, FILE *stream); void logger_struct_restore(struct logger_writer *log, FILE *stream); diff --git a/src/logger_io.h b/src/logger_io.h index f1a0415ab6967f04e85375f26dd9b080530cc05e..495e4754202ac9969a46e6697b1a8a421740c5c4 100644 --- a/src/logger_io.h +++ b/src/logger_io.h @@ -30,6 +30,104 @@ #include "part.h" #include "units.h" +/* This enum defines the type of particle to use + with a given mask. + The values should be the same than in part_type.h. */ +enum mask_type { + mask_type_gas = 0, + mask_type_dark_matter = 1, + /* Only need a single type of dm. */ + mask_type_stars = 4, + mask_type_black_hole = 5, + mask_type_timestep = -1, +} __attribute__((packed)); + +struct mask_data { + /* Number of bytes for a mask. */ + int size; + + /* Mask value. */ + unsigned int mask; + + /* Type of particle (follow part_type.h and -1 for timestamp). */ + enum mask_type type; + + /* Name of the mask. */ + char name[100]; +}; + +/** + * @brief Initialize the mask_data with a given field. + * + * @param name The name of the field. + * @param size The size of the field. + * + * @return The new mask_data. + */ +INLINE static struct mask_data logger_create_mask_entry(const char* name, + int size) { + struct mask_data mask; + /* Copy the fields */ + strcpy(mask.name, name); + mask.size = size; + mask.mask = 0; + + return mask; +} + +/** + * @brief Add a given field to the current mask. + * + * @param mask_data The mask_data corresponding to the field that we wish to + * write. + * @param name The name of the field. + * @param buffer_size (in) The current size of the future buffer. (out) The + * updated size. + * + * @return The mask of the current field. + */ +INLINE static size_t logger_add_field_to_mask(struct mask_data mask_data, + const char* name, + size_t* buffer_size) { +#ifdef SWIFT_DEBUG_CHECKS + /* Check that we are writing the requested field. */ + if (strcmp(name, mask_data.name) != 0) { + error("Mismatch between the requested field (%s) and the mask (%s)", name, + mask_data.name); + } +#endif + + *buffer_size += mask_data.size; + return mask_data.mask; +} + +/** + * @brief Check if a field should be written according to the mask set in + * #logger_add_field_to_mask. + * + * @param mask_data The mask_data corresponding to the current field. + * @param name The name of the field that we are checking. + * @param mask The mask used for the current record. + */ +INLINE static int logger_should_write_field(struct mask_data mask_data, + unsigned int* mask, + const char* name) { +#ifdef SWIFT_DEBUG_CHECKS + /* Check that we are writing the requested field. */ + if (strcmp(name, mask_data.name) != 0) { + error("Mismatch between the requested field (%s) and the mask (%s)", name, + mask_data.name); + } +#endif + + const int test = mask_data.mask & *mask; + if (test) { + *mask &= ~mask_data.mask; + } + + return test; +} + void logger_write_index_file(struct logger_writer* log, struct engine* e); void logger_write_description(struct logger_writer* log, struct engine* e); diff --git a/src/runner_others.c b/src/runner_others.c index 324b0ccf97ce9f9fc95c2094ff619ddbe8bb9a69..083a73069c9f92b41eb35d2c28855e8714ee8ed6 100644 --- a/src/runner_others.c +++ b/src/runner_others.c @@ -49,6 +49,7 @@ #include "gravity.h" #include "hydro.h" #include "logger.h" +#include "logger_io.h" #include "pressure_floor.h" #include "space.h" #include "star_formation.h" @@ -328,15 +329,7 @@ void runner_do_star_formation(struct runner *r, struct cell *c, int timer) { /* Write the particle */ /* Logs all the fields request by the user */ // TODO select only the requested fields - logger_log_part(e->logger, p, xp, - logger_mask_data[logger_x].mask | - logger_mask_data[logger_v].mask | - logger_mask_data[logger_a].mask | - logger_mask_data[logger_u].mask | - logger_mask_data[logger_h].mask | - logger_mask_data[logger_rho].mask | - logger_mask_data[logger_consts].mask | - logger_mask_data[logger_special_flags].mask, + logger_log_part(e->logger, p, xp, e, /* log_all */ 1, logger_pack_flags_and_data(logger_flag_change_type, swift_type_stars)); #endif @@ -396,10 +389,8 @@ void runner_do_star_formation(struct runner *r, struct cell *c, int timer) { sp->logger_data = xp->logger_data; /* Write the s-particle */ - logger_log_spart(e->logger, sp, - logger_mask_data[logger_x].mask | - logger_mask_data[logger_v].mask | - logger_mask_data[logger_consts].mask, + logger_log_spart(e->logger, sp, e, + /* log_all */ 1, /* special flags */ 0); #endif } else { @@ -689,14 +680,7 @@ void runner_do_logger(struct runner *r, struct cell *c, int timer) { if (logger_should_write(&xp->logger_data, e->logger)) { /* Write particle */ /* Currently writing everything, should adapt it through time */ - logger_log_part(e->logger, p, xp, - logger_mask_data[logger_x].mask | - logger_mask_data[logger_v].mask | - logger_mask_data[logger_a].mask | - logger_mask_data[logger_u].mask | - logger_mask_data[logger_h].mask | - logger_mask_data[logger_rho].mask | - logger_mask_data[logger_consts].mask, + logger_log_part(e->logger, p, xp, e, /* log_all */ 0, /* special flags */ 0); } else /* Update counter */ @@ -719,11 +703,7 @@ void runner_do_logger(struct runner *r, struct cell *c, int timer) { if (logger_should_write(&gp->logger_data, e->logger)) { /* Write particle */ /* Currently writing everything, should adapt it through time */ - logger_log_gpart(e->logger, gp, - logger_mask_data[logger_x].mask | - logger_mask_data[logger_v].mask | - logger_mask_data[logger_a].mask | - logger_mask_data[logger_consts].mask, + logger_log_gpart(e->logger, gp, e, /* log_all */ 0, /* Special flags */ 0); } else @@ -744,10 +724,7 @@ void runner_do_logger(struct runner *r, struct cell *c, int timer) { if (logger_should_write(&sp->logger_data, e->logger)) { /* Write particle */ /* Currently writing everything, should adapt it through time */ - logger_log_spart(e->logger, sp, - logger_mask_data[logger_x].mask | - logger_mask_data[logger_v].mask | - logger_mask_data[logger_consts].mask, + logger_log_spart(e->logger, sp, e, /* Log_all */ 0, /* Special flags */ 0); } else /* Update counter */ diff --git a/src/stars/Default/stars_io.h b/src/stars/Default/stars_io.h index 88444726329bad9baf797aaa8437c48d4fbc1516..02538449191a24bf2f9dd82a928fe51d3b883245 100644 --- a/src/stars/Default/stars_io.h +++ b/src/stars/Default/stars_io.h @@ -265,5 +265,4 @@ INLINE static void stars_props_struct_restore(const struct stars_props *p, restart_read_blocks((void *)p, sizeof(struct stars_props), 1, stream, NULL, "stars props"); } - #endif /* SWIFT_DEFAULT_STAR_IO_H */ diff --git a/src/stars/Default/stars_logger.h b/src/stars/Default/stars_logger.h new file mode 100644 index 0000000000000000000000000000000000000000..4f6e07060f10095cdbd86ae7ecf87b4930853e26 --- /dev/null +++ b/src/stars/Default/stars_logger.h @@ -0,0 +1,195 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Coypright (c) 2020 Loic Hausammann (loic.hausammann@epfl.ch) + * + * 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 <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ +#ifndef SWIFT_DEFAULT_STARS_LOGGER_H +#define SWIFT_DEFAULT_STARS_LOGGER_H + +#ifdef WITH_LOGGER + +/* + * List of all possible mask. + * Outside the module, only stars_logger_field_count is used. + */ +enum stars_logger_fields_mask { + stars_logger_field_coordinates = 0, + stars_logger_field_velocities, + stars_logger_field_accelerations, + stars_logger_field_masses, + stars_logger_field_smoothing_lengths, + stars_logger_field_particle_ids, + stars_logger_field_count, +}; + +/* Name of each possible mask. */ +static const char *stars_logger_field_names[stars_logger_field_count] = { + "Coordinates", "Velocities", "Accelerations", + "Masses", "SmoothingLengths", "ParticleIDs", +}; + +/** + * @brief Initialize the logger. + * + * WARNING: this should be done in the same order than + * #stars_logger_write_particle. + * + * @param mask_data Data for each type of mask. + * + * @return Number of masks used. + */ +INLINE static int stars_logger_populate_mask_data(struct mask_data *mask_data) { + mask_data[stars_logger_field_coordinates] = logger_create_mask_entry( + stars_logger_field_names[stars_logger_field_coordinates], + 3 * sizeof(double)); + + mask_data[stars_logger_field_velocities] = logger_create_mask_entry( + stars_logger_field_names[stars_logger_field_velocities], + 3 * sizeof(float)); + + mask_data[stars_logger_field_accelerations] = logger_create_mask_entry( + stars_logger_field_names[stars_logger_field_accelerations], + 3 * sizeof(float)); + + mask_data[stars_logger_field_masses] = logger_create_mask_entry( + stars_logger_field_names[stars_logger_field_masses], sizeof(float)); + + mask_data[stars_logger_field_smoothing_lengths] = logger_create_mask_entry( + stars_logger_field_names[stars_logger_field_smoothing_lengths], + sizeof(float)); + + mask_data[stars_logger_field_particle_ids] = logger_create_mask_entry( + stars_logger_field_names[stars_logger_field_particle_ids], + sizeof(long long)); + + return stars_logger_field_count; +} + +/** + * @brief Generates the mask and compute the size of the record. + * + * @param masks The list of masks (same order than in #stars_logger_init). + * @param part The #spart that will be written. + * @param write_all Are we forcing to write all the fields? + * + * @param buffer_size (out) The requested size for the buffer. + * @param mask (out) The mask that will be written. + */ +INLINE static void stars_logger_compute_size_and_mask( + const struct mask_data *masks, const struct spart *part, + const int write_all, size_t *buffer_size, unsigned int *mask) { + + /* Here you can decide your own writing logic */ + + /* Add the coordinates. */ + *mask |= logger_add_field_to_mask( + masks[stars_logger_field_coordinates], + stars_logger_field_names[stars_logger_field_coordinates], buffer_size); + + /* Add the velocities. */ + *mask |= logger_add_field_to_mask( + masks[stars_logger_field_velocities], + stars_logger_field_names[stars_logger_field_velocities], buffer_size); + + /* Add the accelerations. */ + *mask |= logger_add_field_to_mask( + masks[stars_logger_field_accelerations], + stars_logger_field_names[stars_logger_field_accelerations], buffer_size); + + /* Add the masses. */ + *mask |= logger_add_field_to_mask( + masks[stars_logger_field_masses], + stars_logger_field_names[stars_logger_field_masses], buffer_size); + + /* Add the smoothing lengths. */ + *mask |= logger_add_field_to_mask( + masks[stars_logger_field_smoothing_lengths], + stars_logger_field_names[stars_logger_field_smoothing_lengths], + buffer_size); + + /* Add the ID. */ + *mask |= logger_add_field_to_mask( + masks[stars_logger_field_particle_ids], + stars_logger_field_names[stars_logger_field_particle_ids], buffer_size); +} + +/** + * @brief Write a particle to the logger. + * + * @param masks The list of masks (same order than in #stars_logger_init). + * @param p The #spart to write. + * @param mask The mask to use for this record. + * @param buff The buffer where to write the particle. + * + * @return The buffer after the data. + */ +INLINE static char *stars_logger_write_particle( + const struct mask_data *mask_data, const struct spart *p, + unsigned int *mask, char *buff) { + + /* Write the coordinate. */ + if (logger_should_write_field( + mask_data[stars_logger_field_coordinates], mask, + stars_logger_field_names[stars_logger_field_coordinates])) { + memcpy(buff, p->x, 3 * sizeof(double)); + buff += 3 * sizeof(double); + } + + /* Write the velocity. */ + if (logger_should_write_field( + mask_data[stars_logger_field_velocities], mask, + stars_logger_field_names[stars_logger_field_velocities])) { + memcpy(buff, p->v, 3 * sizeof(float)); + buff += 3 * sizeof(float); + } + + /* Write the acceleration. */ + if (logger_should_write_field( + mask_data[stars_logger_field_accelerations], mask, + stars_logger_field_names[stars_logger_field_accelerations])) { + memcpy(buff, p->gpart->a_grav, 3 * sizeof(float)); + buff += 3 * sizeof(float); + } + + /* Write the mass. */ + if (logger_should_write_field( + mask_data[stars_logger_field_masses], mask, + stars_logger_field_names[stars_logger_field_masses])) { + memcpy(buff, &p->mass, sizeof(float)); + buff += sizeof(float); + } + + /* Write the smoothing length. */ + if (logger_should_write_field( + mask_data[stars_logger_field_smoothing_lengths], mask, + stars_logger_field_names[stars_logger_field_smoothing_lengths])) { + memcpy(buff, &p->h, sizeof(float)); + buff += sizeof(float); + } + + /* Write the Id. */ + if (logger_should_write_field( + mask_data[stars_logger_field_particle_ids], mask, + stars_logger_field_names[stars_logger_field_particle_ids])) { + memcpy(buff, &p->id, sizeof(long long)); + buff += sizeof(long long); + } + + return buff; +} + +#endif // WITH_LOGGER +#endif // SWIFT_DEFAULT_STARS_LOGGER_H diff --git a/src/stars_io.h b/src/stars_io.h index 18224b1ef9a189c719d3674a037eb4b26cd14d4e..6cf92eac91c2eca09070864a8410ac720cc2ee5b 100644 --- a/src/stars_io.h +++ b/src/stars_io.h @@ -27,6 +27,7 @@ #include "./stars/const/stars_io.h" #elif defined(STARS_NONE) #include "./stars/Default/stars_io.h" +#include "./stars/Default/stars_logger.h" #elif defined(STARS_EAGLE) #include "./stars/EAGLE/stars_io.h" #elif defined(STARS_GEAR) diff --git a/tests/testLogger.c b/tests/testLogger.c index 5976597054c639a65f827876f1f244bc1a6024ce..d0f40522ed3a4df5de9d25a314dec85d01f6093b 100644 --- a/tests/testLogger.c +++ b/tests/testLogger.c @@ -34,45 +34,38 @@ void test_log_parts(struct logger_writer *log) { struct dump *d = &log->dump; + struct engine e; /* Write several copies of a part to the dump. */ struct part p; + struct xpart xp; bzero(&p, sizeof(struct part)); + bzero(&xp, sizeof(struct xpart)); p.x[0] = 1.0; p.v[0] = 0.1; - - /* Start with an offset at the end of the dump. */ - size_t offset = d->count; + xp.logger_data.last_offset = 0; /* Write the full part. */ - logger_log_part( - log, &p, - logger_mask_data[logger_x].mask | logger_mask_data[logger_v].mask | - logger_mask_data[logger_a].mask | logger_mask_data[logger_u].mask | - logger_mask_data[logger_h].mask | logger_mask_data[logger_rho].mask | - logger_mask_data[logger_consts].mask, - &offset, /* special flags */ 0); - printf("Wrote part at offset %#016zx.\n", offset); + logger_log_part(log, &p, &xp, &e, /* log_all */ 1, /* special flags */ 0); + printf("Wrote part at offset %#016zx.\n", xp.logger_data.last_offset); /* Write only the position. */ p.x[0] = 2.0; - logger_log_part(log, &p, logger_mask_data[logger_x].mask, &offset, - /* special flags */ 0); - printf("Wrote part at offset %#016zx.\n", offset); + p.v[0] = 0.; + logger_log_part(log, &p, &xp, &e, /* log_all */ 0, /* special flags */ 0); + printf("Wrote part at offset %#016zx.\n", xp.logger_data.last_offset); /* Write the position and velocity. */ p.x[0] = 3.0; p.v[0] = 0.3; - logger_log_part( - log, &p, - logger_mask_data[logger_x].mask | logger_mask_data[logger_v].mask, - &offset, /* special flags */ 0); - printf("Wrote part at offset %#016zx.\n", offset); + logger_log_part(log, &p, &xp, &e, /* log_all */ 0, /* special flags */ 0); + printf("Wrote part at offset %#016zx.\n", xp.logger_data.last_offset); /* Recover the last part from the dump. */ bzero(&p, sizeof(struct part)); + size_t offset = xp.logger_data.last_offset; size_t offset_old = offset; - int mask = logger_read_part(&p, &offset, (const char *)d->data); + unsigned int mask = logger_read_part(log, &p, &offset, (const char *)d->data); printf( "Recovered part at offset %#016zx with mask %#04x: p.x[0]=%e, " "p.v[0]=%e.\n", @@ -85,7 +78,7 @@ void test_log_parts(struct logger_writer *log) { /* Recover the second part from the dump (only position). */ bzero(&p, sizeof(struct part)); offset_old = offset; - mask = logger_read_part(&p, &offset, (const char *)d->data); + mask = logger_read_part(log, &p, &offset, (const char *)d->data); printf( "Recovered part at offset %#016zx with mask %#04x: p.x[0]=%e, " "p.v[0]=%e.\n", @@ -98,7 +91,7 @@ void test_log_parts(struct logger_writer *log) { /* Recover the first part from the dump. */ bzero(&p, sizeof(struct part)); offset_old = offset; - mask = logger_read_part(&p, &offset, (const char *)d->data); + mask = logger_read_part(log, &p, &offset, (const char *)d->data); printf( "Recovered part at offset %#016zx with mask %#04x: p.x[0]=%e, " "p.v[0]=%e.\n", @@ -111,44 +104,37 @@ void test_log_parts(struct logger_writer *log) { void test_log_gparts(struct logger_writer *log) { struct dump *d = &log->dump; + struct engine e; /* Write several copies of a part to the dump. */ struct gpart p; bzero(&p, sizeof(struct gpart)); p.x[0] = 1.0; p.v_full[0] = 0.1; - - /* Start with an offset at the end of the dump. */ - size_t offset = d->count; + p.type = swift_type_dark_matter; + p.logger_data.last_offset = 0; /* Write the full part. */ - logger_log_gpart( - log, &p, - logger_mask_data[logger_x].mask | logger_mask_data[logger_v].mask | - logger_mask_data[logger_a].mask | logger_mask_data[logger_h].mask | - logger_mask_data[logger_consts].mask, - &offset, /* special flags */ 0); - printf("Wrote gpart at offset %#016zx.\n", offset); + logger_log_gpart(log, &p, &e, /* log_all */ 1, /* special flags */ 0); + printf("Wrote gpart at offset %#016zx.\n", p.logger_data.last_offset); /* Write only the position. */ p.x[0] = 2.0; - logger_log_gpart(log, &p, logger_mask_data[logger_x].mask, &offset, - /* special flags */ 0); - printf("Wrote gpart at offset %#016zx.\n", offset); + p.v_full[0] = 0.; + logger_log_gpart(log, &p, &e, /* log_all */ 0, /* special flags */ 0); + printf("Wrote gpart at offset %#016zx.\n", p.logger_data.last_offset); /* Write the position and velocity. */ p.x[0] = 3.0; p.v_full[0] = 0.3; - logger_log_gpart( - log, &p, - logger_mask_data[logger_x].mask | logger_mask_data[logger_v].mask, - &offset, /* special flags */ 0); - printf("Wrote gpart at offset %#016zx.\n", offset); + logger_log_gpart(log, &p, &e, /* log_all */ 0, /* special flags */ 0); + printf("Wrote gpart at offset %#016zx.\n", p.logger_data.last_offset); /* Recover the last part from the dump. */ + size_t offset = p.logger_data.last_offset; bzero(&p, sizeof(struct gpart)); size_t offset_old = offset; - int mask = logger_read_gpart(&p, &offset, (const char *)d->data); + int mask = logger_read_gpart(log, &p, &offset, (const char *)d->data); printf( "Recovered gpart at offset %#016zx with mask %#04x: p.x[0]=%e, " "p.v[0]=%e.\n", @@ -161,7 +147,7 @@ void test_log_gparts(struct logger_writer *log) { /* Recover the second part from the dump. */ bzero(&p, sizeof(struct gpart)); offset_old = offset; - mask = logger_read_gpart(&p, &offset, (const char *)d->data); + mask = logger_read_gpart(log, &p, &offset, (const char *)d->data); printf( "Recovered gpart at offset %#016zx with mask %#04x: p.x[0]=%e, " "p.v[0]=%e.\n", @@ -174,7 +160,7 @@ void test_log_gparts(struct logger_writer *log) { /* Recover the first part from the dump. */ bzero(&p, sizeof(struct gpart)); offset_old = offset; - mask = logger_read_gpart(&p, &offset, (const char *)d->data); + mask = logger_read_gpart(log, &p, &offset, (const char *)d->data); printf( "Recovered gpart at offset %#016zx with mask %#04x: p.x[0]=%e, " "p.v[0]=%e.\n", @@ -189,7 +175,7 @@ void test_log_timestamps(struct logger_writer *log) { struct dump *d = &log->dump; /* The timestamp to log. */ - unsigned long long int t = 10; + integertime_t t = 10; double time = 0.1; /* Start with an offset at the end of the dump. */ @@ -211,24 +197,29 @@ void test_log_timestamps(struct logger_writer *log) { size_t offset_old = offset; t = 0; time = 0; - int mask = logger_read_timestamp(&t, &time, &offset, (const char *)d->data); - printf("Recovered timestamp %020llu at offset %#016zx with mask %#04x.\n", t, - offset_old, mask); + int mask = + logger_read_timestamp(log, &t, &time, &offset, (const char *)d->data); + printf( + "Recovered timestamp %020llu with time %g at offset %#016zx with mask " + "%#04x.\n", + t, time, offset_old, mask); if (t != 30) { printf("FAIL: could not recover correct timestamp.\n"); abort(); } if (time != 0.3) { - printf("FAIL: could not recover correct time %g.\n", time); + printf("FAIL: could not recover correct time.\n"); abort(); } offset_old = offset; t = 0; time = 0; - mask = logger_read_timestamp(&t, &time, &offset, (const char *)d->data); - printf("Recovered timestamp %020llu at offset %#016zx with mask %#04x.\n", t, - offset_old, mask); + mask = logger_read_timestamp(log, &t, &time, &offset, (const char *)d->data); + printf( + "Recovered timestamp %020llu with time %g at offset %#016zx with mask " + "%#04x.\n", + t, time, offset_old, mask); if (t != 20) { printf("FAIL: could not recover correct timestamp.\n"); abort(); @@ -241,9 +232,11 @@ void test_log_timestamps(struct logger_writer *log) { offset_old = offset; t = 0; time = 0; - mask = logger_read_timestamp(&t, &time, &offset, (const char *)d->data); - printf("Recovered timestamp %020llu at offset %#016zx with mask %#04x.\n", t, - offset_old, mask); + mask = logger_read_timestamp(log, &t, &time, &offset, (const char *)d->data); + printf( + "Recovered timestamp %020llu with time %g at offset %#016zx with mask " + "%#04x.\n", + t, time, offset_old, mask); if (t != 10) { printf("FAIL: could not recover correct timestamp.\n"); abort(); @@ -259,8 +252,11 @@ int main(int argc, char *argv[]) { /* Prepare a logger. */ struct logger_writer log; struct swift_params params; + struct engine e; + e.policy = engine_policy_hydro | engine_policy_self_gravity; + parser_read_file("logger.yml", ¶ms); - logger_init(&log, ¶ms); + logger_init(&log, &e, ¶ms); /* Test writing/reading parts. */ test_log_parts(&log);