From 19265009165b9b644d66607b86bca1f2a72c93bc Mon Sep 17 00:00:00 2001 From: Matthieu Schaller <schaller@strw.leidenuniv.nl> Date: Tue, 31 Mar 2020 11:06:19 +0100 Subject: [PATCH] Add a more generic way of dealing with named columns for subgrid models --- .../ParameterFiles/parameter_description.rst | 11 +++- doc/RTD/source/Snapshots/index.rst | 52 +++++++++++++------ src/chemistry/EAGLE/chemistry_io.h | 34 +++++++++--- src/chemistry/GEAR/chemistry_io.h | 3 +- src/chemistry/QLA/chemistry.h | 2 +- src/chemistry/QLA/chemistry_io.h | 7 +-- src/chemistry/none/chemistry_io.h | 4 +- src/parallel_io.c | 28 ++++++++-- src/part_type.c | 2 +- src/serial_io.c | 26 ++++++++-- src/single_io.c | 26 ++++++++-- src/tracers/none/tracers_io.h | 2 +- 12 files changed, 153 insertions(+), 44 deletions(-) diff --git a/doc/RTD/source/ParameterFiles/parameter_description.rst b/doc/RTD/source/ParameterFiles/parameter_description.rst index 8dee7b7790..93b85311b0 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 a7f2bf50fc..e2de7c4013 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 02420e1932..abd517d49f 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 531765d313..e8f3989c56 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 69139ea632..b578a4a877 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 8a7b78cbfc..7d9d44d244 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 80657726fe..0aed6d4ff2 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 31d307de68..208fa3872d 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 5a2eee2ee2..9cc8c35e74 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 c8d821e3df..f4ee75a813 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 ca8f071496..9a3a9e7ec3 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 b58e5f74ae..f81c142fa8 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 -- GitLab