diff --git a/doc/RTD/source/ParameterFiles/parameter_description.rst b/doc/RTD/source/ParameterFiles/parameter_description.rst index 8dee7b7790e09722878f0ea1adbd58adb5095257..93b85311b0d07d432ffdd7338bf68b7b3afe8cbe 100644 --- a/doc/RTD/source/ParameterFiles/parameter_description.rst +++ b/doc/RTD/source/ParameterFiles/parameter_description.rst @@ -65,6 +65,15 @@ The rest of this page describes all the SWIFT parameters, split by section. A list of all the possible parameters is kept in the file ``examples/parameter_examples.yml``. +.. _Parameters_meta_data: + +Meta Data +--------- + +The ``MetaData`` section contains basic information about the simulation. It +currently only contains one parameter: ``run_name``. This is a string of +characters describing the simulation. It is written to the snapshots' headers. + .. _Parameters_units: Internal Unit System @@ -73,7 +82,7 @@ Internal Unit System The ``InternalUnitSystem`` section describes the units used internally by the code. This is the system of units in which all the equations are solved. All physical constants are converted to this system and if the ICs use a different -system (see the snapshots' ref:`ICs_units_label` section of the documentation) +system (see the snapshots' :ref:`ICs_units_label` section of the documentation) the particle quantities will be converted when read in. The system of units is described using the value of the 5 basic units diff --git a/doc/RTD/source/Snapshots/index.rst b/doc/RTD/source/Snapshots/index.rst index a7f2bf50fc2355770ac78458a4bf102e2ac8dee0..e2de7c40138290e2fda5e6e17a746f887b7c00eb 100644 --- a/doc/RTD/source/Snapshots/index.rst +++ b/doc/RTD/source/Snapshots/index.rst @@ -15,6 +15,24 @@ of the simulation volume. Header ------ +The header group (``/Header``) contains basic information about the simulation +and the number of particles. For compatibility reasons, the SWIFT snapshot's +header format is identical to the Gadget-2 one with small additions. + +In addition to the standard quantities, the header contains a field ``Code`` +that is always set to the string ``SWIFT``, which can be used to identify +SWIFT-generated snapshots and hence make use of all the extensions to the file +format described below. + +The most important quantity of the header is the array ``NumPart_ThisFile`` +which contains the number of particles of each type in this snapshot. This is an +array of 6 numbers; one for each of the 5 supported types and a dummy "type 3" +field only used for compatibility reasons but always containing a zero. + +The ``RunName`` field contains the name of the simulation that was specified as +the ``run_name`` in the :ref:`Parameters_meta_data` section of the YAML +parameter file. + Meta-data about the code and run -------------------------------- @@ -105,21 +123,23 @@ Structure of the particle arrays There are several groups that contain 'auxiliary' information, such as ``Header``. Particle data is placed in separate groups depending of the type of the particles. The type use the naming convention of Gadget-2 (with -the OWLS and EAGLE extensions). - -+---------------------+------------------------+----------------------------------------+ -| HDF5 Group Name | Physical Particle Type | In code ``enum part_type`` | -+=====================+========================+========================================+ -| ``/PartType0/`` | Gas | ``swift_type_gas`` | -+---------------------+------------------------+----------------------------------------+ -| ``/PartType1/`` | Dark Matter | ``swift_type_dark_matter`` | -+---------------------+------------------------+----------------------------------------+ -| ``/PartType2/`` | Background Dark Matter | ``swift_type_dark_matter_background`` | -+---------------------+------------------------+----------------------------------------+ -| ``/PartType4/`` | Stars | ``swift_type_star`` | -+---------------------+------------------------+----------------------------------------+ -| ``/PartType5/`` | Black Holes | ``swift_type_black_hole`` | -+---------------------+------------------------+----------------------------------------+ +the OWLS and EAGLE extensions). A more intuitive naming convention is +given in the form of aliases within the file. The aliases are shown in +the third column of the table. + ++---------------------+------------------------+-----------------------------+----------------------------------------+ +| HDF5 Group Name | Physical Particle Type | HDF5 alias | In code ``enum part_type`` | ++=====================+========================+=============================+========================================+ +| ``/PartType0/`` | Gas | ``/GasParticles/`` | ``swift_type_gas`` | ++---------------------+------------------------+-----------------------------+----------------------------------------+ +| ``/PartType1/`` | Dark Matter | ``/DMParticles/`` | ``swift_type_dark_matter`` | ++---------------------+------------------------+-----------------------------+----------------------------------------+ +| ``/PartType2/`` | Background Dark Matter | ``/DMBackgroundParticles/`` | ``swift_type_dark_matter_background`` | ++---------------------+------------------------+-----------------------------+----------------------------------------+ +| ``/PartType4/`` | Stars | ``/StarsParticles/`` | ``swift_type_star`` | ++---------------------+------------------------+-----------------------------+----------------------------------------+ +| ``/PartType5/`` | Black Holes | ``/BHParticles/`` | ``swift_type_black_hole`` | ++---------------------+------------------------+-----------------------------+----------------------------------------+ The last column in the table gives the ``enum`` value from ``part_type.h`` corresponding to a given entry in the files. @@ -158,7 +178,7 @@ we encourage users to use this meta-data directly in their automated tools. As an example, the fluid densities (which are written in the co-moving -frame) have the following conversion factors: +frame) have the following (non-zero) conversion factors: * ``U_L exponent``: -3 * ``U_M exponent``: 1 diff --git a/src/chemistry/EAGLE/chemistry_io.h b/src/chemistry/EAGLE/chemistry_io.h index 02420e1932205faf1f2827473b33a5ec8f41794c..abd517d49fdb52a3bcab49bfce3594c36e111b39 100644 --- a/src/chemistry/EAGLE/chemistry_io.h +++ b/src/chemistry/EAGLE/chemistry_io.h @@ -279,19 +279,37 @@ INLINE static int chemistry_write_bparticles(const struct bpart* bparts, /** * @brief Writes the current model of SPH to the file * @param h_grp The HDF5 group in which to write + * @param h_grp_columns The HDF5 group containing named columns */ -INLINE static void chemistry_write_flavour(hid_t h_grp) { +INLINE static void chemistry_write_flavour(hid_t h_grp, hid_t h_grp_columns) { + /* Write the chemistry model */ io_write_attribute_s(h_grp, "Chemistry Model", "EAGLE"); - io_write_attribute_d(h_grp, "Chemistry element count", - chemistry_element_count); + + /* Create an array of element names */ + const int element_name_length = 32; + char element_names[chemistry_element_count][element_name_length]; for (int elem = 0; elem < chemistry_element_count; ++elem) { - char buffer[20]; - sprintf(buffer, "Element %d", elem); - io_write_attribute_s( - h_grp, buffer, - chemistry_get_element_name((enum chemistry_element)elem)); + sprintf(element_names[elem], "%s", + chemistry_get_element_name((enum chemistry_element)elem)); } + + /* Add to the named columns */ + hsize_t dims[1] = {chemistry_element_count}; + hid_t type = H5Tcopy(H5T_C_S1); + H5Tset_size(type, element_name_length); + hid_t space = H5Screate_simple(1, dims, NULL); + hid_t dset = H5Dcreate(h_grp_columns, "ElementMassFractions", type, space, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + H5Dwrite(dset, type, H5S_ALL, H5S_ALL, H5P_DEFAULT, element_names[0]); + H5Dclose(dset); + dset = H5Dcreate(h_grp_columns, "SmoothedElementMassFractions", type, space, + H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + H5Dwrite(dset, type, H5S_ALL, H5S_ALL, H5P_DEFAULT, element_names[0]); + H5Dclose(dset); + + H5Tclose(type); + H5Sclose(space); } #endif diff --git a/src/chemistry/GEAR/chemistry_io.h b/src/chemistry/GEAR/chemistry_io.h index 531765d313cd656b2627ac46c5fb28621db58f89..e8f3989c56b6d40ac500bd746793577e29fc97f7 100644 --- a/src/chemistry/GEAR/chemistry_io.h +++ b/src/chemistry/GEAR/chemistry_io.h @@ -112,8 +112,9 @@ INLINE static int chemistry_write_bparticles(const struct bpart* bparts, /** * @brief Writes the current model of SPH to the file * @param h_grp The HDF5 group in which to write + * @param h_grp_columns The HDF5 group containing named columns */ -INLINE static void chemistry_write_flavour(hid_t h_grp) { +INLINE static void chemistry_write_flavour(hid_t h_grp, hid_t h_grp_columns) { io_write_attribute_s(h_grp, "Chemistry Model", "GEAR"); io_write_attribute_d(h_grp, "Chemistry element count", diff --git a/src/chemistry/QLA/chemistry.h b/src/chemistry/QLA/chemistry.h index 69139ea6320b228df5b9990e93fb0377490839b9..b578a4a87782da74c73c5613040da44ebb014309 100644 --- a/src/chemistry/QLA/chemistry.h +++ b/src/chemistry/QLA/chemistry.h @@ -45,7 +45,7 @@ __attribute__((always_inline)) INLINE static const char* chemistry_get_element_name(enum chemistry_element elem) { static const char* chemistry_element_names[chemistry_element_count] = {}; - + error("Attempting to get non-existing element!"); return chemistry_element_names[elem]; } diff --git a/src/chemistry/QLA/chemistry_io.h b/src/chemistry/QLA/chemistry_io.h index 8a7b78cbfc5795ce93cc71f0a6772131af090f05..7d9d44d244735d2afd32592bfd612e8d516810da 100644 --- a/src/chemistry/QLA/chemistry_io.h +++ b/src/chemistry/QLA/chemistry_io.h @@ -94,11 +94,12 @@ INLINE static int chemistry_write_bparticles(const struct bpart* bparts, /** * @brief Writes the current model of chemistry to the file * @param h_grp The HDF5 group in which to write + * @param h_grp_columns The HDF5 group containing named columns */ -INLINE static void chemistry_write_flavour(hid_t h_grp) { +INLINE static void chemistry_write_flavour(hid_t h_grp, hid_t h_grp_columns) { - io_write_attribute_s(h_grp, "Chemistry Model", "Quick Lyman-alpha"); - io_write_attribute_d(h_grp, "Chemistry element count", 0); + io_write_attribute_s(h_grp, "Chemistry Model", + "Quick Lyman-alpha (constant primordial)"); } #endif diff --git a/src/chemistry/none/chemistry_io.h b/src/chemistry/none/chemistry_io.h index 80657726fe552695cddf3607c8df144c8076e1af..0aed6d4ff2e57f1ac44a17d22a3e9d30e02e19b2 100644 --- a/src/chemistry/none/chemistry_io.h +++ b/src/chemistry/none/chemistry_io.h @@ -94,11 +94,11 @@ INLINE static int chemistry_write_bparticles(const struct bpart* bparts, /** * @brief Writes the current model of chemistry to the file * @param h_grp The HDF5 group in which to write + * @param h_grp_columns The HDF5 group containing named columns */ -INLINE static void chemistry_write_flavour(hid_t h_grp) { +INLINE static void chemistry_write_flavour(hid_t h_grp, hid_t h_grp_columns) { io_write_attribute_s(h_grp, "Chemistry Model", "None"); - io_write_attribute_d(h_grp, "Chemistry element count", 0); } #endif diff --git a/src/parallel_io.c b/src/parallel_io.c index 31d307de681bfcf3b61b91521a215ecf8ed34e93..208fa3872d682a16c3c4acc709c72317da1674ed 100644 --- a/src/parallel_io.c +++ b/src/parallel_io.c @@ -1117,10 +1117,15 @@ void prepare_file(struct engine* e, const char* baseName, long long N_total[6], io_write_attribute(h_grp, "Redshift", DOUBLE, &e->cosmology->z, 1); io_write_attribute(h_grp, "Scale-factor", DOUBLE, &e->cosmology->a, 1); io_write_attribute_s(h_grp, "Code", "SWIFT"); - time_t tm = time(NULL); - io_write_attribute_s(h_grp, "Snapshot date", ctime(&tm)); io_write_attribute_s(h_grp, "RunName", e->run_name); + /* Store the time at which the snapshot was written */ + time_t tm = time(NULL); + struct tm* timeinfo = localtime(&tm); + char snapshot_date[64]; + strftime(snapshot_date, 64, "%T %F %Z", timeinfo); + io_write_attribute_s(h_grp, "Snapshot date", snapshot_date); + /* GADGET-2 legacy values */ /* Number of particles of each type */ unsigned int numParticles[swift_type_count] = {0}; @@ -1169,11 +1174,15 @@ void prepare_file(struct engine* e, const char* baseName, long long N_total[6], h_grp = H5Gcreate(h_file, "/SubgridScheme", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); if (h_grp < 0) error("Error while creating subgrid group"); + hid_t h_grp_columns = + H5Gcreate(h_grp, "NamedColumns", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + if (h_grp_columns < 0) error("Error while creating named columns group"); entropy_floor_write_flavour(h_grp); cooling_write_flavour(h_grp, e->cooling_func); - chemistry_write_flavour(h_grp); + chemistry_write_flavour(h_grp, h_grp_columns); tracers_write_flavour(h_grp); feedback_write_flavour(e->feedback_props, h_grp); + H5Gclose(h_grp_columns); H5Gclose(h_grp); /* Print the gravity parameters */ @@ -1243,7 +1252,18 @@ void prepare_file(struct engine* e, const char* baseName, long long N_total[6], h_grp = H5Gcreate(h_file, partTypeGroupName, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); if (h_grp < 0) - error("Error while opening particle group %s.", partTypeGroupName); + error("Error while creating particle group %s.", partTypeGroupName); + + /* Add an alias name for convenience */ + char aliasName[PARTICLE_GROUP_BUFFER_SIZE]; + snprintf(aliasName, PARTICLE_GROUP_BUFFER_SIZE, "/%sParticles", + part_type_names[ptype]); + hid_t h_err = H5Lcreate_soft(partTypeGroupName, h_grp, aliasName, + H5P_DEFAULT, H5P_DEFAULT); + if (h_err < 0) error("Error while creating alias for particle group.\n"); + + /* Write the number of particles as an attribute */ + io_write_attribute_l(h_grp, "NumberOfParticles", N_total[ptype]); int num_fields = 0; struct io_props list[100]; diff --git a/src/part_type.c b/src/part_type.c index 5a2eee2ee2e4296f4abdd1dd3ae4927748484b15..9cc8c35e7413e28d518289ccfcdd00d302ce8a28 100644 --- a/src/part_type.c +++ b/src/part_type.c @@ -21,4 +21,4 @@ #include "part_type.h" const char* part_type_names[swift_type_count] = { - "Gas", "DM", "DM_background", "Dummy", "Stars", "BH"}; + "Gas", "DM", "DMBackground", "Dummy", "Stars", "BH"}; diff --git a/src/serial_io.c b/src/serial_io.c index c8d821e3dfba90baaf967d406cb84cd4b532274d..f4ee75a813933b3b801df4da329026df223b0d15 100644 --- a/src/serial_io.c +++ b/src/serial_io.c @@ -982,10 +982,15 @@ void write_output_serial(struct engine* e, const char* baseName, io_write_attribute(h_grp, "Redshift", DOUBLE, &e->cosmology->z, 1); io_write_attribute(h_grp, "Scale-factor", DOUBLE, &e->cosmology->a, 1); io_write_attribute_s(h_grp, "Code", "SWIFT"); - time_t tm = time(NULL); - io_write_attribute_s(h_grp, "Snapshot date", ctime(&tm)); io_write_attribute_s(h_grp, "RunName", e->run_name); + /* Store the time at which the snapshot was written */ + time_t tm = time(NULL); + struct tm* timeinfo = localtime(&tm); + char snapshot_date[64]; + strftime(snapshot_date, 64, "%T %F %Z", timeinfo); + io_write_attribute_s(h_grp, "Snapshot date", snapshot_date); + /* GADGET-2 legacy values */ /* Number of particles of each type */ unsigned int numParticles[swift_type_count] = {0}; @@ -1034,11 +1039,15 @@ void write_output_serial(struct engine* e, const char* baseName, h_grp = H5Gcreate(h_file, "/SubgridScheme", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); if (h_grp < 0) error("Error while creating subgrid group"); + hid_t h_grp_columns = + H5Gcreate(h_grp, "NamedColumns", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + if (h_grp_columns < 0) error("Error while creating named columns group"); entropy_floor_write_flavour(h_grp); cooling_write_flavour(h_grp, e->cooling_func); - chemistry_write_flavour(h_grp); + chemistry_write_flavour(h_grp, h_grp_columns); tracers_write_flavour(h_grp); feedback_write_flavour(e->feedback_props, h_grp); + H5Gclose(h_grp_columns); H5Gclose(h_grp); /* Print the gravity parameters */ @@ -1139,6 +1148,17 @@ void write_output_serial(struct engine* e, const char* baseName, /* Close particle group */ H5Gclose(h_grp); + + /* Add an alias name for convenience */ + char aliasName[PARTICLE_GROUP_BUFFER_SIZE]; + snprintf(aliasName, PARTICLE_GROUP_BUFFER_SIZE, "/%sParticles", + part_type_names[ptype]); + hid_t h_err = H5Lcreate_soft(partTypeGroupName, h_grp, aliasName, + H5P_DEFAULT, H5P_DEFAULT); + if (h_err < 0) error("Error while creating alias for particle group.\n"); + + /* Write the number of particles as an attribute */ + io_write_attribute_l(h_grp, "NumberOfParticles", N_total[ptype]); } /* Close file */ diff --git a/src/single_io.c b/src/single_io.c index ca8f071496eb5f41d2cb55427bcba718377dbd22..9a3a9e7ec37f8af06192ec20e71bab52cdf0057c 100644 --- a/src/single_io.c +++ b/src/single_io.c @@ -827,10 +827,15 @@ void write_output_single(struct engine* e, const char* baseName, io_write_attribute(h_grp, "Redshift", DOUBLE, &e->cosmology->z, 1); io_write_attribute(h_grp, "Scale-factor", DOUBLE, &e->cosmology->a, 1); io_write_attribute_s(h_grp, "Code", "SWIFT"); - time_t tm = time(NULL); - io_write_attribute_s(h_grp, "Snapshot date", ctime(&tm)); io_write_attribute_s(h_grp, "RunName", e->run_name); + /* Store the time at which the snapshot was written */ + time_t tm = time(NULL); + struct tm* timeinfo = localtime(&tm); + char snapshot_date[64]; + strftime(snapshot_date, 64, "%T %F %Z", timeinfo); + io_write_attribute_s(h_grp, "Snapshot date", snapshot_date); + /* GADGET-2 legacy values */ /* Number of particles of each type */ unsigned int numParticles[swift_type_count] = {0}; @@ -879,11 +884,15 @@ void write_output_single(struct engine* e, const char* baseName, h_grp = H5Gcreate(h_file, "/SubgridScheme", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); if (h_grp < 0) error("Error while creating subgrid group"); + hid_t h_grp_columns = + H5Gcreate(h_grp, "NamedColumns", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + if (h_grp_columns < 0) error("Error while creating named columns group"); entropy_floor_write_flavour(h_grp); cooling_write_flavour(h_grp, e->cooling_func); - chemistry_write_flavour(h_grp); + chemistry_write_flavour(h_grp, h_grp_columns); tracers_write_flavour(h_grp); feedback_write_flavour(e->feedback_props, h_grp); + H5Gclose(h_grp_columns); H5Gclose(h_grp); /* Print the gravity parameters */ @@ -998,6 +1007,17 @@ void write_output_single(struct engine* e, const char* baseName, H5P_DEFAULT); if (h_grp < 0) error("Error while creating particle group.\n"); + /* Add an alias name for convenience */ + char aliasName[PARTICLE_GROUP_BUFFER_SIZE]; + snprintf(aliasName, PARTICLE_GROUP_BUFFER_SIZE, "/%sParticles", + part_type_names[ptype]); + hid_t h_err = H5Lcreate_soft(partTypeGroupName, h_grp, aliasName, + H5P_DEFAULT, H5P_DEFAULT); + if (h_err < 0) error("Error while creating alias for particle group.\n"); + + /* Write the number of particles as an attribute */ + io_write_attribute_l(h_grp, "NumberOfParticles", numParticles[ptype]); + int num_fields = 0; struct io_props list[100]; size_t N = 0; diff --git a/src/tracers/none/tracers_io.h b/src/tracers/none/tracers_io.h index b58e5f74aea211214b45c07668c03b461c088a99..f81c142fa8f828dcaa2a29b6040a81c0eca3c740 100644 --- a/src/tracers/none/tracers_io.h +++ b/src/tracers/none/tracers_io.h @@ -37,7 +37,7 @@ __attribute__((always_inline)) INLINE static void tracers_write_flavour( hid_t h_grp) { - io_write_attribute_s(h_grp, "Tracers", "none"); + io_write_attribute_s(h_grp, "Tracers", "None"); } #endif