Commit 6c0e6d31 authored by Matthieu Schaller's avatar Matthieu Schaller
Browse files

Merge branch 'default-ptype-compression-level' into 'master'

Add option for particle type level default output behaviour to new output list scheme

Closes #680

See merge request !1090
parents d8f091e8 d25d8a23
......@@ -68,6 +68,9 @@ CGS. Entries in the file look like:
SmoothingLengths_Gas: on # Co-moving smoothing lengths (FWHM of the kernel) of the particles : a U_L [ cm ]
...
For cosmological simulations, users can optionally add the ``--cosmology`` flag
to generate the field names appropriate for such a run.
Users can select the particle fields to output in snapshot using a (separate)
YAML parameter file. By default, you can define a section `Default` at the
top level of this file (in the exact same way as the file dumped by using the
......@@ -83,9 +86,9 @@ options:
select_output_on: 1
select_output: your_select_output_yaml.yml
This field is mostly used to remove unnecessary output by listing them with
0's. A classic use-case for this feature is a DM-only simulation (pure
n-body) where all particles have the same mass. Outputting the mass field in
This field is mostly used to remove unnecessary output by listing them as
"off". A classic use-case for this feature is a DM-only simulation (pure
N-body) where all particles have the same mass. Outputting the mass field in
the snapshots results in extra i/o time and unnecessary waste of disk space.
The corresponding section of the YAML file would look like:
......@@ -97,6 +100,21 @@ The corresponding section of the YAML file would look like:
Entries can simply be copied from the ``output.yml`` generated by the
``-o`` runtime flag.
For convenience, there is also the option to set a default output status for
all fields of a particular particle type. This can be used, for example, to
skip an entire particle type in certain snapshots (see below for how to define
per-snapshot output policies). This is achieved with the special ``Standard``
field for each particle type:
.. code:: YAML
BlackHolesOnly:
Standard_Gas: off
Standard_DM: off
Standard_DMBackground: off
Standard_Stars: off
Standard_BH: on # Not strictly necessary, on is already the default
Combining Output Lists and Output Selection
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
......
......@@ -1161,8 +1161,7 @@ int main(int argc, char *argv[]) {
/* Verify that the fields to dump actually exist - this must be done after
* space_init so we know whether or not we have gas particles. */
if (myrank == 0)
io_check_output_fields(output_options->select_output, N_total,
with_cosmology);
io_check_output_fields(output_options, N_total, with_cosmology);
/* Say a few nice things about the space we just created. */
if (myrank == 0) {
......
This diff is collapsed.
......@@ -21,11 +21,10 @@
#define SWIFT_COMMON_IO_H
/* Config parameters. */
#include "../config.h"
#include "config.h"
/* Local includes. */
#include "part_type.h"
#include "units.h"
#define FIELD_BUFFER_SIZE 64
#define DESCRIPTION_BUFFER_SIZE 512
......@@ -44,6 +43,8 @@ struct xpart;
struct io_props;
struct engine;
struct threadpool;
struct output_options;
struct unit_system;
/**
* @brief The different types of data used in the GADGET IC files.
......@@ -66,6 +67,9 @@ enum IO_DATA_TYPE {
#if defined(HAVE_HDF5)
/* Library header */
#include <hdf5.h>
hid_t io_hdf5_type(enum IO_DATA_TYPE type);
hsize_t io_get_number_element_in_attribute(hid_t attr);
......@@ -104,6 +108,7 @@ void io_write_cell_offsets(hid_t h_grp, const int cdim[3], const double dim[3],
const int distributed,
const long long global_counts[swift_type_count],
const long long global_offsets[swift_type_count],
const int num_fields[swift_type_count],
const struct unit_system* internal_units,
const struct unit_system* snapshot_units);
......@@ -118,7 +123,7 @@ void io_copy_temp_buffer(void* temp, const struct engine* e,
const struct unit_system* internal_units,
const struct unit_system* snapshot_units);
#endif /* defined HDF5 */
#endif /* HAVE_HDF5 */
size_t io_sizeof_type(enum IO_DATA_TYPE type);
int io_is_double_precision(enum IO_DATA_TYPE type);
......@@ -167,8 +172,9 @@ void io_duplicate_black_holes_gparts(struct threadpool* tp,
struct gpart* const gparts, size_t Nstars,
size_t Ndm);
void io_check_output_fields(struct swift_params* params,
const long long N_total[3], int with_cosmology);
void io_check_output_fields(struct output_options* output_options,
const long long N_total[swift_type_count],
const int with_cosmology);
void io_write_output_field_parameter(const char* filename, int with_cosmology);
......@@ -180,4 +186,8 @@ void io_get_snapshot_filename(char filename[1024], char xmf_filename[1024],
const int stf_count, const int snap_count,
const char* subdir, const char* basename);
int get_ptype_fields(const int ptype, struct io_props* list,
const int with_cosmology);
int get_param_ptype(const char* name);
#endif /* SWIFT_COMMON_IO_H */
......@@ -383,14 +383,21 @@ void write_output_distributed(struct engine* e,
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 */
/* GADGET-2 legacy values: Number of particles of each type */
unsigned int numParticles[swift_type_count] = {0};
unsigned int numParticlesHighWord[swift_type_count] = {0};
/* Total number of fields to write per ptype */
int numFields[swift_type_count] = {0};
for (int ptype = 0; ptype < swift_type_count; ++ptype) {
numParticles[ptype] = (unsigned int)N_total[ptype];
numParticlesHighWord[ptype] = (unsigned int)(N_total[ptype] >> 32);
numFields[ptype] = output_options_get_num_fields_to_write(
output_options, current_selection_name, ptype);
}
io_write_attribute(h_grp, "NumPart_ThisFile", LONGLONG, N, swift_type_count);
io_write_attribute(h_grp, "NumPart_Total", UINT, numParticles,
swift_type_count);
......@@ -424,15 +431,16 @@ void write_output_distributed(struct engine* e,
/* Write the location of the particles in the arrays */
io_write_cell_offsets(h_grp, e->s->cdim, e->s->dim, e->s->pos_dithering,
e->s->cells_top, e->s->nr_cells, e->s->width, mpi_rank,
/*distributed=*/1, N_total, global_offsets,
/*distributed=*/1, N_total, global_offsets, numFields,
internal_units, snapshot_units);
H5Gclose(h_grp);
/* Loop over all particle types */
for (int ptype = 0; ptype < swift_type_count; ptype++) {
/* Don't do anything if no particle of this kind */
if (numParticles[ptype] == 0) continue;
/* Don't do anything if there are (a) no particles of this kind, or (b)
* if we have disabled every field of this particle type. */
if (numParticles[ptype] == 0 || numFields[ptype] == 0) continue;
/* Open the particle group in the file */
char partTypeGroupName[PARTICLE_GROUP_BUFFER_SIZE];
......@@ -452,6 +460,7 @@ void write_output_distributed(struct engine* e,
/* Write the number of particles as an attribute */
io_write_attribute_l(h_grp, "NumberOfParticles", N[ptype]);
io_write_attribute_i(h_grp, "NumberOfFields", numFields[ptype]);
int num_fields = 0;
struct io_props list[100];
......@@ -717,19 +726,33 @@ void write_output_distributed(struct engine* e,
error("Particle Type %d not yet supported. Aborting", ptype);
}
/* Write everything that is not cancelled */
/* Did the user specify a non-standard default for the entire particle
* type? */
const enum compression_levels compression_level_current_default =
output_options_get_ptype_default(output_options->select_output,
current_selection_name,
(enum part_type)ptype);
/* Write everything that is not cancelled */
int num_fields_written = 0;
for (int i = 0; i < num_fields; ++i) {
/* Did the user cancel this field? */
const int should_write = output_options_should_write_field(
output_options, current_selection_name, list[i].name,
(enum part_type)ptype);
(enum part_type)ptype, compression_level_current_default);
if (should_write)
if (should_write) {
write_distributed_array(e, h_grp, fileName, partTypeGroupName, list[i],
Nparticles, internal_units, snapshot_units);
num_fields_written++;
}
}
#ifdef SWIFT_DEBUG_CHECKS
if (num_fields_written != numFields[ptype])
error("Wrote %d fields for particle type %s, but expected to write %d.",
num_fields_written, part_type_names[ptype], numFields[ptype]);
#endif
/* Free temporary arrays */
if (parts_written) swift_free("parts_written", parts_written);
......
......@@ -28,6 +28,9 @@
/* Config parameters. */
#include "../config.h"
/* Local includes */
#include "parser.h"
/* Import the right hydro header */
#if defined(MINIMAL_SPH)
#include "./hydro/Minimal/hydro_parameters.h"
......
......@@ -27,6 +27,7 @@
#include "error.h"
#include "inline.h"
#include "part.h"
#include "units.h"
/* Standard includes. */
#include <string.h>
......
......@@ -20,16 +20,19 @@
#define SWIFT_OUTPUT_LIST_H
/* Config parameters. */
#include "../config.h"
#include "config.h"
/* Local includes */
/* Local headers */
#include "common_io.h"
#include "cosmology.h"
#define OUTPUT_LIST_MAX_NUM_OF_SELECT_OUTPUT_STYLES 8
#include "timeline.h"
/* Pre-declarations */
struct cosmology;
struct engine;
/*! Maximal number of output lists */
#define OUTPUT_LIST_MAX_NUM_OF_SELECT_OUTPUT_STYLES 8
/**
* @brief the different output_list type
*/
......
......@@ -20,6 +20,7 @@
/* Some standard headers. */
#include <stdlib.h>
#include <string.h>
/* MPI headers. */
#ifdef WITH_MPI
......@@ -30,9 +31,9 @@
#include "output_options.h"
/* Local headers. */
#include "common_io.h"
#include "error.h"
#include "parser.h"
#include "part_type.h"
#include "swift.h"
/* Compression level names. */
const char* compression_level_names[compression_level_count] = {
......@@ -125,13 +126,17 @@ void output_options_struct_restore(struct output_options* output_options,
* @param field_name pointer to a char array containing the name of the
* relevant field.
* @param part_type integer particle type
* @param compression_level_current_default The default output strategy
*. based on the snapshot_type and part_type.
*
* @return should_write integer determining whether this field should be
* written
**/
int output_options_should_write_field(struct output_options* output_options,
char* snapshot_type, char* field_name,
enum part_type part_type) {
int output_options_should_write_field(
const struct output_options* output_options, const char* snapshot_type,
const char* field_name, const enum part_type part_type,
const enum compression_levels compression_level_current_default) {
/* Full name for the field path */
char field[PARSER_MAX_LINE_SIZE];
sprintf(field, "%.*s:%.*s_%s", FIELD_BUFFER_SIZE, snapshot_type,
......@@ -140,7 +145,7 @@ int output_options_should_write_field(struct output_options* output_options,
char compression_level[FIELD_BUFFER_SIZE];
parser_get_opt_param_string(
output_options->select_output, field, compression_level,
compression_level_names[compression_level_default]);
compression_level_names[compression_level_current_default]);
int should_write = strcmp(compression_level_names[compression_do_not_write],
compression_level);
......@@ -154,3 +159,102 @@ int output_options_should_write_field(struct output_options* output_options,
return should_write;
}
/**
* @brief Return the default output strategy of a given particle type.
*
* This can only be "on" or "off". No lossy compression strategy can be
* applied at the level of an entire particle type.
*
* @param output_params The parsed select output file.
* @param snapshot_type The type of snapshot we are writing
* @param part_type The #part_type we are considering.
*/
enum compression_levels output_options_get_ptype_default(
struct swift_params* output_params, const char* snapshot_type,
const enum part_type part_type) {
/* Full name for the default path */
char field[PARSER_MAX_LINE_SIZE];
sprintf(field, "%.*s:Standard_%s", FIELD_BUFFER_SIZE, snapshot_type,
part_type_names[part_type]);
char compression_level[FIELD_BUFFER_SIZE];
parser_get_opt_param_string(
output_params, field, compression_level,
compression_level_names[compression_level_default]);
/* Need to find out which of the entries this corresponds to... */
int level_index;
for (level_index = 0; level_index < compression_level_count; level_index++) {
if (!strcmp(compression_level_names[level_index], compression_level)) break;
}
/* Make sure that the supplied default option is either on or off, not a
* compression strategy (these should only be set on a per-field basis) */
if (!(level_index == compression_do_not_write ||
level_index == compression_write_lossless))
error(
"A lossy default compression strategy was specified for snapshot "
"type %s and particle type %d. This is not allowed, lossy "
"compression must be set on a field-by-field basis.",
snapshot_type, part_type);
#ifdef SWIFT_DEBUG_CHECKS
/* Check whether we could translate the level string to a known entry. */
if (level_index >= compression_level_count)
error(
"Could not resolve compression level \"%s\" as default compression "
"level of particle type %s in snapshot type %s.",
compression_level, part_type_names[part_type], snapshot_type);
message(
"Determined default compression level of %s in snapshot type %s "
"as \"%s\", corresponding to level code %d",
part_type_names[part_type], snapshot_type, compression_level,
level_index);
#endif
return (enum compression_levels)level_index;
}
/**
* @brief Return the number of fields to be written for a ptype.
*
* @param output_options The output_options struct.
* @param selection_name The current output selection name.
* @param ptype The particle type index.
*/
int output_options_get_num_fields_to_write(
const struct output_options* output_options, const char* selection_name,
const int ptype) {
/* Get the ID of the output selection in the structure */
int selection_id =
parser_get_section_id(output_options->select_output, selection_name);
#ifdef SWIFT_DEBUG_CHECKS
/* The only situation where we might legitimately not find the selection
* name is if it is the default. Everything else means trouble. */
if (strcmp(selection_name, select_output_header_default_name) &&
selection_id < 0)
error(
"Output selection '%s' could not be located in output_options "
"structure. Please investigate.",
selection_name);
/* While we're at it, make sure the selection ID is not impossibly high */
if (selection_id >= output_options->select_output->sectionCount)
error(
"Output selection '%s' was apparently located in index %d of the "
"output_options structure, but this only has %d sections.",
selection_name, selection_id,
output_options->select_output->sectionCount);
#endif
/* Special treatment for absent `Default` section */
if (selection_id < 0)
selection_id = output_options->select_output->sectionCount;
return output_options->num_fields_to_write[selection_id][ptype];
}
......@@ -19,11 +19,14 @@
#ifndef SWIFT_OUTPUT_OPTIONS_H
#define SWIFT_OUTPUT_OPTIONS_H
#include "config.h"
#include "parser.h"
/* Local headers. */
#include "output_list.h"
#include "part_type.h"
#include "restart.h"
/* Compression level names */
/**
* @brief Compression levels for snapshot fields
*/
enum compression_levels {
compression_do_not_write = 0,
compression_write_lossless,
......@@ -34,10 +37,10 @@ enum compression_levels {
compression_level_count,
};
/* Default value for SelectOutput */
/*! Default value for SelectOutput */
#define compression_level_default compression_write_lossless
/* Default name for the SelectOutput header */
/*! Default name for the SelectOutput header */
#define select_output_header_default_name "Default"
/**
......@@ -54,7 +57,11 @@ struct output_options {
/*! Select output file, parsed */
struct swift_params* select_output;
/* Pass-through struct for now but may need more later. */
/* Number of fields to write for each output selection and ptype.
* We need one more than max num of output styles, in case the Default
* output style is used but not specified. */
int num_fields_to_write[OUTPUT_LIST_MAX_NUM_OF_SELECT_OUTPUT_STYLES + 1]
[swift_type_count];
};
/* Create and destroy */
......@@ -69,8 +76,17 @@ void output_options_struct_restore(struct output_options* output_options,
FILE* stream);
/* Logic functions */
int output_options_should_write_field(struct output_options* output_options,
char* snapshot_type, char* field_name,
enum part_type part_type);
int output_options_should_write_field(
const struct output_options* output_options, const char* snapshot_type,
const char* field_name, const enum part_type part_type,
const enum compression_levels comp_level_current_default);
enum compression_levels output_options_get_ptype_default(
struct swift_params* output_params, const char* snapshot_type,
const enum part_type part_type);
int output_options_get_num_fields_to_write(
const struct output_options* output_options, const char* selection_name,
const int ptype);
#endif
\ No newline at end of file
#endif
......@@ -1044,11 +1044,14 @@ void read_ic_parallel(char* fileName, const struct unit_system* internal_units,
*
* @param e The #engine.
* @param N_total The total number of particles of each type to write.
* @param numFields The number of fields to write for each particle type.
* @param internal_units The #unit_system used internally.
* @param snapshot_units The #unit_system used in the snapshots.
*/
void prepare_file(struct engine* e, const char* fileName,
const char* xmfFileName, long long N_total[6],
const char* xmfFileName, long long N_total[swift_type_count],
const int numFields[swift_type_count],
char current_selection_name[FIELD_BUFFER_SIZE],
const struct unit_system* internal_units,
const struct unit_system* snapshot_units) {
......@@ -1058,7 +1061,6 @@ void prepare_file(struct engine* e, const char* fileName,
const struct spart* sparts = e->s->sparts;
const struct bpart* bparts = e->s->bparts;
struct output_options* output_options = e->output_options;
struct output_list* output_list = e->output_list_snapshots;
const int with_cosmology = e->policy & engine_policy_cosmology;
const int with_cooling = e->policy & engine_policy_cooling;
const int with_temperature = e->policy & engine_policy_temperature;
......@@ -1103,16 +1105,6 @@ void prepare_file(struct engine* e, const char* fileName,
e->s->dim[1] * factor_length,
e->s->dim[2] * factor_length};
/* Determine if we are writing a reduced snapshot, and if so which
* output selection type to use */
char current_selection_name[FIELD_BUFFER_SIZE] =
select_output_header_default_name;
if (output_list) {
/* Users could have specified a different Select Output scheme for each
* snapshot. */
output_list_get_current_select_output(output_list, current_selection_name);
}
/* Print the relevant information and print status */
io_write_attribute(h_grp, "BoxSize", DOUBLE, dim, 3);
io_write_attribute(h_grp, "Time", DOUBLE, &dblTime, 1);
......@@ -1164,8 +1156,9 @@ void prepare_file(struct engine* e, const char* fileName,
/* Loop over all particle types */
for (int ptype = 0; ptype < swift_type_count; ptype++) {
/* Don't do anything if no particle of this kind */
if (N_total[ptype] == 0) continue;
/* Don't do anything if there are (a) no particles of this kind, or (b)
* if we have disabled every field of this particle type. */
if (N_total[ptype] == 0 || numFields[ptype] == 0) continue;
/* Add the global information for that particle type to
* the XMF meta-file */
......@@ -1191,6 +1184,7 @@ void prepare_file(struct engine* e, const char* fileName,
/* Write the number of particles as an attribute */
io_write_attribute_l(h_grp, "NumberOfParticles", N_total[ptype]);
io_write_attribute_i(h_grp, "NumberOfFields", numFields[ptype]);
int num_fields = 0;
struct io_props list[100];
......@@ -1270,19 +1264,33 @@ void prepare_file(struct engine* e, const char* fileName,
error("Particle Type %d not yet supported. Aborting", ptype);
}
/* Prepare everything that is not cancelled */
/* Did the user specify a non-standard default for the entire particle
* type? */
const enum compression_levels compression_level_current_default =
output_options_get_ptype_default(output_options->select_output,
current_selection_name,
(enum part_type)ptype);
/* Prepare everything that is not cancelled */
int num_fields_written = 0;
for (int i = 0; i < num_fields; ++i) {
/* Did the user cancel this field? */
const int should_write = output_options_should_write_field(
output_options, current_selection_name, list[i].name,
(enum part_type)ptype);
(enum part_type)ptype, compression_level_current_default);
if (should_write)
if (should_write) {
prepare_array_parallel(e, h_grp, fileName, xmfFile, partTypeGroupName,
list[i], N_total[ptype], snapshot_units);
num_fields_written++;
}
}
#ifdef SWIFT_DEBUG_CHECKS
if (num_fields_written != numFields[ptype])
error("Wrote %d fields for particle type %s, but expected to write %d.",
num_fields_written, part_type_names[ptype], numFields[ptype]);
#endif
/* Close particle group */
H5Gclose(h_grp);
......@@ -1399,10 +1407,25 @@ void write_output_parallel(struct engine* e,
e->snapshot_output_count, e->snapshot_subdir,
e->snapshot_base_name);
char current_selection_name[FIELD_BUFFER_SIZE] =
select_output_header_default_name;
if (output_list) {
/* Users could have specified a different Select Output scheme for each
* snapshot. */
output_list_get_current_select_output(output_list, current_selection_name);
}
/* Total number of fields to write per ptype */
int numFields[swift_type_count] = {0};
for (int ptype = 0; ptype < swift_type_count; ++ptype) {
numFields[ptype] = output_options_get_num_fields_to_write(
output_options, current_selection_name, ptype);
}
/* Rank 0 prepares the file */
if (mpi_rank == 0)
prepare_file(e, fileName, xmfFileName, N_total, internal_units,
snapshot_units);
prepare_file(e, fileName, xmfFileName, N_total, numFields,
current_selection_name, internal_units, snapshot_units);
MPI_Barrier(MPI_COMM_WORLD);
......@@ -1432,8 +1455,8 @@ void write_output_parallel(struct engine* e,
/* Write the location of the particles in the arrays */
io_write_cell_offsets(h_grp_cells, e->s->cdim, e->s->dim, e->s->pos_dithering,
e->s->cells_top, e->s->nr_cells, e->s->width, mpi_rank,
/*distributed=*/0, N_total, offset, internal_units,
snapshot_units);
/*distributed=*/0, N_total, offset, numFields,
internal_units, snapshot_units);
/* Close everything */
if (mpi_rank == 0) {
......@@ -1781,21 +1804,20 @@ void write_output_parallel(struct engine* e,
error("Particle Type %d not yet supported. Aborting", ptype);
}
/* Did the user specify a non-standard default for the entire particle
* type? */
const enum compression_levels compression_level_current_default =
output_options_get_ptype_default(output_options->select_output,
current_selection_name,
(enum part_type)ptype);
/* Write everything that is not cancelled */
char current_selection_name[FIELD_BUFFER_SIZE] =
select_output_header_default_name;
if (output_list) {
/* Users could have specified a different Select Output scheme for each
* snapshot. */
output_list_get_current_select_output(output_list,
current_selection_name);
}
for (int i = 0; i < num_fields; ++i) {