diff --git a/doc/RTD/source/ParameterFiles/parameter_description.rst b/doc/RTD/source/ParameterFiles/parameter_description.rst index 45b68c9e9c490df52de675ba3d37011d4b48222b..3dfb42fc1ed544c0e45dbdbd0d2aecc76de54ecf 100644 --- a/doc/RTD/source/ParameterFiles/parameter_description.rst +++ b/doc/RTD/source/ParameterFiles/parameter_description.rst @@ -686,6 +686,12 @@ creation of a compact range of IDs beyond which the new IDs generated by splitting can be safely drawn from. Note that, when ``remap_ids`` is switched on the ICs do not need to contain a ``ParticleIDs`` field. +* Name of a HDF5 group to copy from the ICs file(s): ``metadata_group_name`` (default: ``ICs_parameters``) + +If the initial conditions generator writes a HDF5 group with the parameters +used to make the initial conditions, this group can be copied through to +the output snapshots by specifying its name. + The full section to start a DM+hydro run from Gadget DM-only ICs would be: @@ -698,7 +704,7 @@ be: cleanup_velocity_factors: 1 generate_gas_in_ics: 1 cleanup_smoothing_lengths: 1 - + metadata_group_name: ICs_parameters .. _Parameters_constants: diff --git a/examples/main.c b/examples/main.c index 66bd9405ca6f3f543a641049da8caf33309fff50..d93ad058916098672010097315470e39b4356bef 100644 --- a/examples/main.c +++ b/examples/main.c @@ -111,6 +111,7 @@ int main(int argc, char *argv[]) { struct sink *sinks = NULL; struct unit_system us; struct los_props los_properties; + struct ic_info ics_metadata; int nr_nodes = 1, myrank = 0; @@ -1140,6 +1141,9 @@ int main(int argc, char *argv[]) { size_t Nspart = 0, Nbpart = 0, Nsink = 0; double dim[3] = {0., 0., 0.}; + /* Prepare struct to store metadata from ICs */ + ic_info_init(&ics_metadata, params); + if (myrank == 0) clocks_gettime(&tic); #if defined(HAVE_HDF5) #if defined(WITH_MPI) @@ -1150,7 +1154,7 @@ int main(int argc, char *argv[]) { with_gravity, with_sink, with_stars, with_black_holes, with_cosmology, cleanup_h, cleanup_sqrt_a, cosmo.h, cosmo.a, myrank, nr_nodes, MPI_COMM_WORLD, MPI_INFO_NULL, - nr_threads, dry_run, remap_ids); + nr_threads, dry_run, remap_ids, &ics_metadata); #else read_ic_serial(ICfileName, &us, dim, &parts, &gparts, &sinks, &sparts, &bparts, &Ngas, &Ngpart, &Ngpart_background, &Nnupart, @@ -1158,7 +1162,7 @@ int main(int argc, char *argv[]) { with_gravity, with_sink, with_stars, with_black_holes, with_cosmology, cleanup_h, cleanup_sqrt_a, cosmo.h, cosmo.a, myrank, nr_nodes, MPI_COMM_WORLD, MPI_INFO_NULL, nr_threads, - dry_run, remap_ids); + dry_run, remap_ids, &ics_metadata); #endif #else read_ic_single(ICfileName, &us, dim, &parts, &gparts, &sinks, &sparts, @@ -1166,7 +1170,7 @@ int main(int argc, char *argv[]) { &Nsink, &Nspart, &Nbpart, &flag_entropy_ICs, with_hydro, with_gravity, with_sink, with_stars, with_black_holes, with_cosmology, cleanup_h, cleanup_sqrt_a, cosmo.h, cosmo.a, - nr_threads, dry_run, remap_ids); + nr_threads, dry_run, remap_ids, &ics_metadata); #endif #endif @@ -1424,7 +1428,7 @@ int main(int argc, char *argv[]) { &black_holes_properties, &sink_properties, &neutrino_properties, &feedback_properties, &rt_properties, &mesh, &potential, &cooling_func, &starform, &chemistry, &fof_properties, - &los_properties); + &los_properties, &ics_metadata); engine_config(/*restart=*/0, /*fof=*/0, &e, params, nr_nodes, myrank, nr_threads, nr_pool_threads, with_aff, talking, restart_file); diff --git a/examples/parameter_example.yml b/examples/parameter_example.yml index c0f3ae565ff970a74b591f3607149a5ff264ff61..be79c2fd669562aa9d89a2fe1c2c171d4e081026 100644 --- a/examples/parameter_example.yml +++ b/examples/parameter_example.yml @@ -208,6 +208,7 @@ InitialConditions: shift: [0.0,0.0,0.0] # (Optional) A shift to apply to all particles read from the ICs (in internal units). replicate: 2 # (Optional) Replicate all particles along each axis a given integer number of times. Default 1. remap_ids: 0 # (Optional) Remap all the particle IDs to the range [1, NumPart]. + metadata_group_name: ICs_parameters # (Optional) Copy this HDF5 group from the initial conditions file to all snapshots, if found # Parameters controlling restarts Restarts: diff --git a/src/Makefile.am b/src/Makefile.am index 6c66de50ffea822d7dbc3a1debf22fdf474fcb66..eb745ec04e90bd95f92670bf563dbda1ee42d08f 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -66,6 +66,7 @@ include_HEADERS += rays.h rays_struct.h include_HEADERS += particle_splitting.h particle_splitting_struct.h include_HEADERS += chemistry_csds.h star_formation_csds.h include_HEADERS += mesh_gravity.h mesh_gravity_mpi.h mesh_gravity_patch.h mesh_gravity_sort.h row_major_id.h +include_HEADERS += hdf5_object_to_blob.h ic_info.h # source files for QLA (Ploeckinger+20) cooling QLA_COOLING_SOURCES = @@ -147,6 +148,7 @@ AM_SOURCES += mesh_gravity.c mesh_gravity_mpi.c mesh_gravity_patch.c mesh_gravit AM_SOURCES += runner_neutrino.c AM_SOURCES += neutrino/Default/fermi_dirac.c neutrino/Default/neutrino.c AM_SOURCES += rt_parameters.c +AM_SOURCES += hdf5_object_to_blob.c ic_info.c AM_SOURCES += $(QLA_COOLING_SOURCES) $(QLA_EAGLE_COOLING_SOURCES) AM_SOURCES += $(EAGLE_COOLING_SOURCES) $(EAGLE_FEEDBACK_SOURCES) AM_SOURCES += $(GRACKLE_COOLING_SOURCES) $(GEAR_FEEDBACK_SOURCES) diff --git a/src/distributed_io.c b/src/distributed_io.c index 4569fe47fceadc2b40d41f2b0f48b8c3cc20295e..2510eb156d10a48feac0880680c34f833fcac108 100644 --- a/src/distributed_io.c +++ b/src/distributed_io.c @@ -594,6 +594,9 @@ void write_virtual_file(struct engine* e, const char* fileName_base, /* Close header */ H5Gclose(h_grp); + /* Copy metadata from ICs to the file */ + ic_info_write_hdf5(e->ics_metadata, h_file); + /* Write all the meta-data */ io_write_meta_data(h_file, e, internal_units, snapshot_units); @@ -1057,6 +1060,9 @@ void write_output_distributed(struct engine* e, /* Close header */ H5Gclose(h_grp); + /* Copy metadata from ICs to the file */ + ic_info_write_hdf5(e->ics_metadata, h_file); + /* Write all the meta-data */ io_write_meta_data(h_file, e, internal_units, snapshot_units); diff --git a/src/engine.c b/src/engine.c index a53746b3324a07cfb6523b54b815bdba861cb09c..9f514e8d00383b298e6cdcdf3478538348d7e5f6 100644 --- a/src/engine.c +++ b/src/engine.c @@ -2755,6 +2755,7 @@ void engine_unpin(void) { * @param chemistry The chemistry information. * @param fof_properties The #fof_props of this run. * @param los_properties the #los_props of this run. + * @param ics_metadata metadata read from the simulation ICs */ void engine_init( struct engine *e, struct space *s, struct swift_params *params, @@ -2773,7 +2774,8 @@ void engine_init( struct cooling_function_data *cooling_func, const struct star_formation *starform, const struct chemistry_global_data *chemistry, - struct fof_props *fof_properties, struct los_props *los_properties) { + struct fof_props *fof_properties, struct los_props *los_properties, + struct ic_info *ics_metadata) { struct clocks_time tic, toc; if (engine_rank == 0) clocks_gettime(&tic); @@ -2890,6 +2892,7 @@ void engine_init( e->output_options = output_options; e->stf_this_timestep = 0; e->los_properties = los_properties; + e->ics_metadata = ics_metadata; #ifdef WITH_MPI e->usertime_last_step = 0.0; e->systime_last_step = 0.0; @@ -3260,6 +3263,8 @@ void engine_clean(struct engine *e, const int fof, const int restart) { output_options_clean(e->output_options); + ic_info_clean(e->ics_metadata); + swift_free("links", e->links); #if defined(WITH_CSDS) if (e->policy & engine_policy_csds) { @@ -3322,6 +3327,7 @@ void engine_clean(struct engine *e, const int fof, const int restart) { free((void *)e->fof_properties); #endif free((void *)e->los_properties); + free((void *)e->ics_metadata); #ifdef WITH_MPI free((void *)e->reparttype); #endif @@ -3381,6 +3387,7 @@ void engine_struct_dump(struct engine *e, FILE *stream) { fof_struct_dump(e->fof_properties, stream); #endif los_struct_dump(e->los_properties, stream); + ic_info_struct_dump(e->ics_metadata, stream); parser_struct_dump(e->parameter_file, stream); output_options_struct_dump(e->output_options, stream); @@ -3528,6 +3535,11 @@ void engine_struct_restore(struct engine *e, FILE *stream) { los_struct_restore(los_properties, stream); e->los_properties = los_properties; + struct ic_info *ics_metadata = + (struct ic_info *)malloc(sizeof(struct ic_info)); + ic_info_struct_restore(ics_metadata, stream); + e->ics_metadata = ics_metadata; + struct swift_params *parameter_file = (struct swift_params *)malloc(sizeof(struct swift_params)); parser_struct_restore(parameter_file, stream); diff --git a/src/engine.h b/src/engine.h index 73180940cb0be3af92167301c4e9d4e1c90d8cb4..745a1ad691c35f282c09fdddd20f7b2f72371d26 100644 --- a/src/engine.h +++ b/src/engine.h @@ -36,6 +36,7 @@ #include "barrier.h" #include "clocks.h" #include "collectgroup.h" +#include "ic_info.h" #include "mesh_gravity.h" #include "output_options.h" #include "parser.h" @@ -331,6 +332,9 @@ struct engine { double snapshot_delta_from_edge; int snapshot_output_count; + /* Metadata from the ICs */ + struct ic_info *ics_metadata; + /* Structure finding information */ double a_first_stf_output; double time_first_stf_output; @@ -613,7 +617,8 @@ void engine_init( struct cooling_function_data *cooling_func, const struct star_formation *starform, const struct chemistry_global_data *chemistry, - struct fof_props *fof_properties, struct los_props *los_properties); + struct fof_props *fof_properties, struct los_props *los_properties, + struct ic_info *ics_metadata); void engine_config(int restart, int fof, struct engine *e, struct swift_params *params, int nr_nodes, int nodeID, int nr_task_threads, int nr_pool_threads, int with_aff, diff --git a/src/hdf5_object_to_blob.c b/src/hdf5_object_to_blob.c new file mode 100644 index 0000000000000000000000000000000000000000..6243dd125f751a5340ef402a89ebe1ac497aea3c --- /dev/null +++ b/src/hdf5_object_to_blob.c @@ -0,0 +1,167 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (c) 2021 John Helly (j.c.helly@durham.ac.uk) + * + * 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/>. + * + ******************************************************************************/ + +/* Config parameters. */ +#include "../config.h" + +/* Some standard headers. */ +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> + +/* Local headers */ +#include "error.h" + +/* This object's header */ +#include "hdf5_object_to_blob.h" + +#ifdef HAVE_HDF5 +#include <hdf5.h> + +#define MAX_FILENAME_LENGTH 500 + +/** + * @brief Generates a file name using the process ID and host name + * + * @param prefix Prefix to add to the file name + * @param name Buffer to write the file name to + * @param len Length of the buffer + * + */ +static void unique_filename(char *prefix, char *name, size_t len) { + + /* Get our process ID */ + long pid = (long) getpid(); + + /* Get our host name. May be truncated or empty. */ + char hostname[MAX_FILENAME_LENGTH]; + if(gethostname(hostname, MAX_FILENAME_LENGTH) != 0) { + /* gethostname() call failed. Make hostname an empty string. */ + hostname[0] = (char) 0; + } else { + /* gethostname() successful. Add null terminator in case of truncation . */ + hostname[MAX_FILENAME_LENGTH-1] = (char) 0; + } + + /* Try to create a unique name. If truncated, try to use it anyway. */ + int ret = snprintf(name, len, "%s.%s.%ld.tmp", prefix, hostname, pid); + if(ret < 0) { + error("snprintf call failed generating filename"); + } else if (((size_t) ret) >= len) { + /* Output has been truncated */ + name[len-1] = (char) 0; + } +} + + +/** + * @brief Copy a HDF5 object and its members to a byte array + * + * @param group_id Group containing the object to copy + * @param name Name of the object + * @param len Returns the size of the output array + * @param data Returns a pointer to the output array + * + * This creates a HDF5 file image in memory, copies the required + * object to the file image, then returns a copy of the image as + * a newly allocated array. + * + */ +void hdf5_object_to_blob(hid_t group_id, char *name, size_t *len, void **data) { + + /* Set up property list */ + hid_t fapl_id = H5Pcreate(H5P_FILE_ACCESS); + const size_t increment = 1024*1024; + const hbool_t backing_store = 0; + if(H5Pset_fapl_core(fapl_id, increment, backing_store) < 0) + error("Unable to set core driver"); + + /* Generate a file name which (hopefully!) doesn't exist */ + char filename[MAX_FILENAME_LENGTH]; + unique_filename("/tmp/__SWIFT_HDF5_CORE_WRITE", filename, MAX_FILENAME_LENGTH); + + /* Create the file image in memory (file with this name must not exist) */ + hid_t file_id = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id); + H5Pclose(fapl_id); + if(file_id < 0) + error("Failed to create HDF5 file in memory"); + + /* Copy the input object to the file image */ + if(H5Ocopy(group_id, name, file_id, name, H5P_DEFAULT, H5P_DEFAULT) < 0) + error("Failed to copy HDF5 object %s", name); + H5Fflush(file_id, H5F_SCOPE_GLOBAL); + + /* Store the size of the file image */ + ssize_t size = H5Fget_file_image(file_id, NULL, 0); + if(size < 0) + error("Failed to get HDF5 file image size"); + *len = (size_t) size; + + /* Copy the file image to a new data array */ + *data = malloc(*len); + if(H5Fget_file_image(file_id, *data, *len) < 0) + error("Failed to copy HDF5 file image to array"); + + /* Close the file image */ + H5Fclose(file_id); +} + + +/** + * @brief Copy a HDF5 object from a byte array to a HDF5 file + * + * @param len Size of the input byte array + * @param data Pointer to the input byte array + * @param dest_id HDF5 group in which to write the object + * @param name Name of the object + * + * This opens the HDF5 file image supplied in data and copies + * the named object to the HDF5 group specified by dest_id. + * + */ +void blob_to_hdf5_object(size_t len, void *data, hid_t dest_id, char *name) { + + /* Set up property list */ + hid_t fapl_id = H5Pcreate(H5P_FILE_ACCESS); + const size_t increment = 1024*1024; + const hbool_t backing_store = 0; + if(H5Pset_fapl_core(fapl_id, increment, backing_store) < 0) + error("Unable to set core driver"); + if(H5Pset_file_image(fapl_id, data, len) < 0) + error("Unable to set file image"); + + /* Generate a file name which (hopefully!) doesn't exist */ + char filename[MAX_FILENAME_LENGTH]; + unique_filename("/tmp/__SWIFT_HDF5_CORE_READ", filename, MAX_FILENAME_LENGTH); + + /* Open the file image (file with this name must not exist) */ + hid_t file_id = H5Fopen(filename, H5F_ACC_RDONLY, fapl_id); + if(file_id < 0) + error("Opening HDF5 file image failed, possibly because file %s already exists", filename); + H5Pclose(fapl_id); + + /* Copy the object from the file image to the destination */ + if(H5Ocopy(file_id, name, dest_id, name, H5P_DEFAULT, H5P_DEFAULT) < 0) + error("Failed to copy HDF5 object %s", name); + + /* Close the file image */ + H5Fclose(file_id); +} + +#endif diff --git a/src/hdf5_object_to_blob.h b/src/hdf5_object_to_blob.h new file mode 100644 index 0000000000000000000000000000000000000000..733a623eb2d806b37e6d38332b0c126489441bc8 --- /dev/null +++ b/src/hdf5_object_to_blob.h @@ -0,0 +1,35 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (c) 2021 John Helly (j.c.helly@durham.ac.uk) + * + * 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_HDF5_OBJECT_TO_BLOB_H +#define SWIFT_HDF5_OBJECT_TO_BLOB_H + +/* Config parameters. */ +#include "../config.h" + +#ifdef HAVE_HDF5 + +#include <hdf5.h> + +void hdf5_object_to_blob(hid_t group_id, char *name, size_t *len, void **data); +void blob_to_hdf5_object(size_t len, void *data, hid_t dest_id, char *name); + +#endif /* HAVE_HDF5 */ + +#endif /* SWIFT_HDF5_OBJECT_TO_BLOB_H */ diff --git a/src/ic_info.c b/src/ic_info.c new file mode 100644 index 0000000000000000000000000000000000000000..432a8effa0fa386e03f44c4035ed3e577f9131ab --- /dev/null +++ b/src/ic_info.c @@ -0,0 +1,188 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (c) 2021 John Helly (j.c.helly@durham.ac.uk) + * + * 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/>. + * + ******************************************************************************/ + +/* Config parameters. */ +#include "../config.h" + +/* Some standard headers. */ +#include <stdlib.h> +#include <stdio.h> +#ifdef WITH_MPI +#include <mpi.h> +#endif + +/* Local headers */ +#include "error.h" + +/* This object's header */ +#include "ic_info.h" + +/* Includes */ +#include "hdf5_object_to_blob.h" +#include "restart.h" + +extern int engine_rank; + +/** + * @brief Initialize the ic_info struct + * + * @param ics Pointer to the struct + * @param params The Swift parameter set + */ +void ic_info_init(struct ic_info *ics, struct swift_params *params) { + + /* Initially we have no file image */ + ics->file_image_length = 0; + ics->file_image_data = NULL; + + /* Store the name of the HDF5 group to copy */ + parser_get_opt_param_string(params, + "InitialConditions:metadata_group_name", + ics->group_name, "ICs_parameters"); +} + +/** + * @brief Clean up the ic_info struct + * + * @param ics Pointer to the struct + */ +void ic_info_clean(struct ic_info *ics) { + + /* Deallocate file image, if it exists */ + if(ics->file_image_data) { + free(ics->file_image_data); + ics->file_image_data = NULL; + } + ics->file_image_length = 0; + +} + +/** + * @brief Dump the ic_info struct to the supplied file + * + * @param ics Pointer to the struct + * @param stream The file to write to + */ +void ic_info_struct_dump(struct ic_info *ics, FILE *stream) { + + /* Write the struct */ + restart_write_blocks(ics, sizeof(struct ic_info), 1, stream, + "ic_info", "ic_info struct"); + + /* Write the HDF5 file image if there is one */ + if(ics->file_image_data) { + restart_write_blocks(ics->file_image_data, ics->file_image_length, + 1, stream, "ic_info", "ic_info file image"); + } +} + +/** + * @brief Restore the ic_info struct from the supplied file + * + * @param ics Pointer to the struct + * @param stream The file to read from + */ +void ic_info_struct_restore(struct ic_info *ics, FILE *stream) { + + /* Read in the struct */ + restart_read_blocks(ics, sizeof(struct ic_info), 1, stream, + NULL, "ic_info struct"); + + /* Read in the HDF5 file image, if there is one */ + if(ics->file_image_data) { + ics->file_image_data = malloc(ics->file_image_length); + restart_read_blocks(ics->file_image_data, ics->file_image_length, + 1, stream, NULL, "ic_info file image"); + } +} + +/** + * @brief Broadcast the ic_info struct to all MPI ranks + * + * @param ics Pointer to the struct + * @param root The root rank for the broadcast operation + */ +void ic_info_struct_broadcast(struct ic_info *ics, int root) { + +#ifdef WITH_MPI + + int rank; + MPI_Comm_rank(MPI_COMM_WORLD, &rank); + + /* Broadcast the struct */ + MPI_Bcast(ics, sizeof(struct ic_info), MPI_BYTE, root, MPI_COMM_WORLD); + if(ics->file_image_data) { + + /* Allocate file image data on other ranks */ + if(rank != root) + ics->file_image_data = malloc(ics->file_image_length); + + /* Broadcast the file image data */ + MPI_Bcast(ics->file_image_data, ics->file_image_length, + MPI_BYTE, root, MPI_COMM_WORLD); + } +#endif +} + + +#ifdef HAVE_HDF5 +/** + * @brief Read the ICs metadata from a HDF5 file + * + * @param ics Pointer to the struct + * @param file_id The HDF5 file (or group) to write to + */ +void ic_info_read_hdf5(struct ic_info *ics, hid_t file_id) { + + /* Check that the named group exists as a link in the ICs file */ + if(H5Lexists(file_id, ics->group_name, H5P_DEFAULT) > 0) { + /* Check that the link resolves to an object */ + if(H5Oexists_by_name(file_id, ics->group_name, H5P_DEFAULT) > 0) { + /* Read the HDF5 object into memory */ + hdf5_object_to_blob(file_id, ics->group_name, &(ics->file_image_length), + &(ics->file_image_data)); + if(engine_rank==0) + message("Read metadata group %s from ICs file", ics->group_name); + } else { + if(engine_rank==0) + message("Metadata group %s in ICs file appears to be a broken link", + ics->group_name); + } + } else { + if(engine_rank==0) + message("Metadata group %s not found in ICs file", ics->group_name); + } +} + + +/** + * @brief Write the ICs metadata to a HDF5 file + * + * @param ics Pointer to the struct + * @param file_id The HDF5 file (or group) to read from + */ +void ic_info_write_hdf5(struct ic_info *ics, hid_t file_id) { + + if(ics->file_image_data) { + blob_to_hdf5_object(ics->file_image_length, ics->file_image_data, file_id, + ics->group_name); + } +} +#endif + diff --git a/src/ic_info.h b/src/ic_info.h new file mode 100644 index 0000000000000000000000000000000000000000..8885d7cda29f211cd4888fad8c822b119e4e26bf --- /dev/null +++ b/src/ic_info.h @@ -0,0 +1,50 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Copyright (c) 2021 John Helly (j.c.helly@durham.ac.uk) + * + * 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_IC_INFO_H +#define SWIFT_IC_INFO_H + +/* Config parameters. */ +#include "../config.h" + +/* Some standard headers. */ +#include <stdlib.h> +#include <stdio.h> + +/* Includes. */ +#include "parser.h" + +struct ic_info { + char group_name[PARSER_MAX_LINE_SIZE]; + size_t file_image_length; + void *file_image_data; +}; + +void ic_info_init(struct ic_info *ics, struct swift_params *params); +void ic_info_clean(struct ic_info *ics); +void ic_info_struct_dump(struct ic_info *ics, FILE *stream); +void ic_info_struct_restore(struct ic_info *ics, FILE *stream); +void ic_info_struct_broadcast(struct ic_info *ics, int root); + +#ifdef HAVE_HDF5 +void ic_info_read_hdf5(struct ic_info *ics, hid_t file_id); +void ic_info_write_hdf5(struct ic_info *ics, hid_t file_id); +#endif + +#endif /* SWIFT_IC_INFO_H */ diff --git a/src/parallel_io.c b/src/parallel_io.c index cf566a8c06bfea0b2af6cde3ea2f571675d1ff27..2d4b0d242a3363be06df0be1ca9d5e7995e2fad2 100644 --- a/src/parallel_io.c +++ b/src/parallel_io.c @@ -47,6 +47,7 @@ #include "gravity_properties.h" #include "hydro_io.h" #include "hydro_properties.h" +#include "ic_info.h" #include "io_properties.h" #include "memuse.h" #include "output_list.h" @@ -750,6 +751,8 @@ void write_array_parallel(struct engine* e, hid_t grp, char* fileName, * @param info The MPI information object * @param n_threads The number of threads to use for local operations. * @param dry_run If 1, don't read the particle. Only allocates the arrays. + * @param remap_ids Are we ignoring the ICs' IDs and remapping them to [1, N[ ? + * @param ics_metadata Will store metadata group copied from the ICs file * */ void read_ic_parallel(char* fileName, const struct unit_system* internal_units, @@ -763,7 +766,7 @@ void read_ic_parallel(char* fileName, const struct unit_system* internal_units, int with_cosmology, int cleanup_h, int cleanup_sqrt_a, double h, double a, int mpi_rank, int mpi_size, MPI_Comm comm, MPI_Info info, int n_threads, int dry_run, - int remap_ids) { + int remap_ids, struct ic_info *ics_metadata) { hid_t h_file = 0, h_grp = 0; /* GADGET has only cubic boxes (in cosmological mode) */ @@ -905,6 +908,9 @@ void read_ic_parallel(char* fileName, const struct unit_system* internal_units, } } + /* Read metadata from ICs file */ + ic_info_read_hdf5(ics_metadata, h_file); + /* Convert the dimensions of the box */ for (int j = 0; j < 3; j++) dim[j] *= @@ -1271,6 +1277,9 @@ void prepare_file(struct engine* e, const char* fileName, /* Close header */ H5Gclose(h_grp); + /* Copy metadata from ICs to the file */ + ic_info_write_hdf5(e->ics_metadata, h_file); + /* Write all the meta-data */ io_write_meta_data(h_file, e, internal_units, snapshot_units); diff --git a/src/parallel_io.h b/src/parallel_io.h index 647301e7639f6008539724a157a09d201575b894..dd1d4697d054cd39f4dc5a4cdb718474bec1aca2 100644 --- a/src/parallel_io.h +++ b/src/parallel_io.h @@ -29,6 +29,7 @@ /* Includes. */ #include "part.h" +#include "ic_info.h" struct engine; struct unit_system; @@ -44,7 +45,7 @@ void read_ic_parallel(char* fileName, const struct unit_system* internal_units, int with_cosmology, int cleanup_h, int cleanup_sqrt_a, double h, double a, int mpi_rank, int mpi_size, MPI_Comm comm, MPI_Info info, int nr_threads, int dry_run, - int remap_ids); + int remap_ids, struct ic_info *ics_metadata); void write_output_parallel(struct engine* e, const struct unit_system* internal_units, diff --git a/src/serial_io.c b/src/serial_io.c index a5863b6782e452c3dabcf61de31707ea405caf68..0d3e0414d1afab0632ecb70563badac7932426f4 100644 --- a/src/serial_io.c +++ b/src/serial_io.c @@ -515,6 +515,7 @@ void write_array_serial(const struct engine* e, hid_t grp, char* fileName, * @param n_threads The number of threads to use for local operations. * @param dry_run If 1, don't read the particle. Only allocates the arrays. * @param remap_ids Are we ignoring the ICs' IDs and remapping them to [1, N[ ? + * @param ics_metadata Will store metadata group copied from the ICs file * * Opens the HDF5 file fileName and reads the particles contained * in the parts array. N is the returned number of particles found @@ -535,7 +536,7 @@ void read_ic_serial(char* fileName, const struct unit_system* internal_units, int with_cosmology, int cleanup_h, int cleanup_sqrt_a, double h, double a, int mpi_rank, int mpi_size, MPI_Comm comm, MPI_Info info, int n_threads, int dry_run, - int remap_ids) { + int remap_ids, struct ic_info *ics_metadata) { hid_t h_file = 0, h_grp = 0; /* GADGET has only cubic boxes (in cosmological mode) */ @@ -672,6 +673,9 @@ void read_ic_serial(char* fileName, const struct unit_system* internal_units, internal_units->UnitTemperature_in_cgs); } + /* Read metadata from ICs file */ + ic_info_read_hdf5(ics_metadata, h_file); + /* Close file */ H5Fclose(h_file); } @@ -686,6 +690,7 @@ void read_ic_serial(char* fileName, const struct unit_system* internal_units, MPI_Bcast(N_total, swift_type_count, MPI_LONG_LONG_INT, 0, comm); MPI_Bcast(dim, 3, MPI_DOUBLE, 0, comm); MPI_Bcast(ic_units, sizeof(struct unit_system), MPI_BYTE, 0, comm); + ic_info_struct_broadcast(ics_metadata, 0); /* Divide the particles among the tasks. */ for (int ptype = 0; ptype < swift_type_count; ++ptype) { @@ -1226,6 +1231,9 @@ void write_output_serial(struct engine* e, /* Close header */ H5Gclose(h_grp); + /* Copy metadata from ICs to the file */ + ic_info_write_hdf5(e->ics_metadata, h_file); + /* Write all the meta-data */ io_write_meta_data(h_file, e, internal_units, snapshot_units); diff --git a/src/serial_io.h b/src/serial_io.h index f89d901799433c1173f92f9cb7faf8e3838fc145..b7d906d0dcbecef5b14a94d54b6c9a87a030e348 100644 --- a/src/serial_io.h +++ b/src/serial_io.h @@ -31,6 +31,7 @@ /* Includes. */ #include "part.h" +#include "ic_info.h" struct engine; struct unit_system; @@ -46,7 +47,7 @@ void read_ic_serial(char* fileName, const struct unit_system* internal_units, int with_cosmology, int cleanup_h, int cleanup_sqrt_a, double h, double a, int mpi_rank, int mpi_size, MPI_Comm comm, MPI_Info info, int n_threads, int dry_run, - int remap_ids); + int remap_ids, struct ic_info *ics_metadata); void write_output_serial(struct engine* e, const struct unit_system* internal_units, diff --git a/src/single_io.c b/src/single_io.c index 133f0010716c593b815f97b82f32836def62d74d..32a9f9a3db72aa5b96aae4bd536c79d26f585ea0 100644 --- a/src/single_io.c +++ b/src/single_io.c @@ -418,6 +418,8 @@ void write_array_single(const struct engine* e, hid_t grp, char* fileName, * @param a The current value of the scale-factor. * @prarm n_threads The number of threads to use for the temporary threadpool. * @param dry_run If 1, don't read the particle. Only allocates the arrays. + * @param remap_ids Are we ignoring the ICs' IDs and remapping them to [1, N[ ? + * @param ics_metadata Will store metadata group copied from the ICs file * * Opens the HDF5 file fileName and reads the particles contained * in the parts array. N is the returned number of particles found @@ -434,7 +436,8 @@ void read_ic_single( size_t* Nsinks, size_t* Nstars, size_t* Nblackholes, int* flag_entropy, int with_hydro, int with_gravity, int with_sink, int with_stars, int with_black_holes, int with_cosmology, int cleanup_h, int cleanup_sqrt_a, - double h, double a, int n_threads, int dry_run, int remap_ids) { + double h, double a, int n_threads, int dry_run, int remap_ids, + struct ic_info *ics_metadata) { hid_t h_file = 0, h_grp = 0; /* GADGET has only cubic boxes (in cosmological mode) */ @@ -563,6 +566,9 @@ void read_ic_single( internal_units->UnitTemperature_in_cgs); } + /* Read metadata from ICs file */ + ic_info_read_hdf5(ics_metadata, h_file); + /* Convert the dimensions of the box */ for (int j = 0; j < 3; j++) dim[j] *= @@ -1057,6 +1063,9 @@ void write_output_single(struct engine* e, /* Close header */ H5Gclose(h_grp); + /* Copy metadata from ICs to the file */ + ic_info_write_hdf5(e->ics_metadata, h_file); + /* Write all the meta-data */ io_write_meta_data(h_file, e, internal_units, snapshot_units); diff --git a/src/single_io.h b/src/single_io.h index a2b423562589d2a577a6a4817b18b68cc1fb86a9..da769be602323f0ba29c50d250c6a161d4e95cdb 100644 --- a/src/single_io.h +++ b/src/single_io.h @@ -26,6 +26,7 @@ /* Local includes */ #include "part.h" +#include "ic_info.h" struct engine; struct unit_system; @@ -40,7 +41,8 @@ void read_ic_single(const char* fileName, int with_hydro, int with_gravity, int with_sinks, int with_stars, int with_black_holes, int with_cosmology, int cleanup_h, int cleanup_sqrt_a, double h, double a, - int nr_threads, int dry_run, int remap_ids); + int nr_threads, int dry_run, int remap_ids, + struct ic_info *ics_metadata); void write_output_single(struct engine* e, const struct unit_system* internal_units, diff --git a/src/swift.h b/src/swift.h index 2365cc175dabcd5adbf0b492401975766426919c..b112766b5fbc09bd2ef6f0fdf47242e8eecd84f7 100644 --- a/src/swift.h +++ b/src/swift.h @@ -51,6 +51,7 @@ #include "hashmap.h" #include "hydro.h" #include "hydro_properties.h" +#include "ic_info.h" #include "line_of_sight.h" #include "lock.h" #include "map.h"