Commit d25d8a23 authored by Yannick Bahé's avatar Yannick Bahé Committed by Matthieu Schaller
Browse files

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

parent d8f091e8
......@@ -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
......@@ -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) {