diff --git a/src/engine.c b/src/engine.c index c14f5c1af5ac72364fe71cc55c2b7323db2cc177..7560771b2ffb4e05562a61b505b64a2a58cdc889 100644 --- a/src/engine.c +++ b/src/engine.c @@ -4283,7 +4283,7 @@ void engine_init_particles(struct engine *e, int flag_entropy_ICs, prev_id = &s->parts[k].id; } if (failed > 0) - error( + message( "Have %d particle pairs with the same locations.\n" "Cannot continue", failed); @@ -5038,7 +5038,7 @@ void engine_dump_snapshot(struct engine *e) { e->dump_snapshot = 0; clocks_gettime(&time2); - if (e->verbose) + //if (e->verbose) message("writing particle properties took %.3f %s.", (float)clocks_diff(&time1, &time2), clocks_getunit()); } diff --git a/src/parallel_io.c b/src/parallel_io.c index 3e8cadf18a9468d52c0b32c6cb054d668ad5c37d..057f0220b26b049fff7138f6181b8f53ff5bc711 100644 --- a/src/parallel_io.c +++ b/src/parallel_io.c @@ -57,7 +57,7 @@ #define HDF5_PARALLEL_IO_MAX_BYTES 2000000000LL /* Are we timing the i/o? */ -//#define IO_SPEED_MEASUREMENT +#define IO_SPEED_MEASUREMENT /** * @brief Reads a chunk of data from an open HDF5 dataset @@ -252,6 +252,82 @@ void readArray(hid_t grp, struct io_props props, size_t N, long long N_total, * @param internal_units The #unit_system used internally. * @param snapshot_units The #unit_system used in the snapshots. */ +void prepareArray(struct engine* e, hid_t grp, char* fileName, FILE* xmfFile, + char* partTypeGroupName, struct io_props props, + long long N_total, + const struct unit_system* snapshot_units) { + + /* Create data space */ + const hid_t h_space = H5Screate(H5S_SIMPLE); + if (h_space < 0) + error("Error while creating data space for field '%s'.", props.name); + + int rank = 0; + hsize_t shape[2]; + hsize_t chunk_shape[2]; + if (props.dimension > 1) { + rank = 2; + shape[0] = N_total; + shape[1] = props.dimension; + chunk_shape[0] = 1 << 16; /* Just a guess...*/ + chunk_shape[1] = props.dimension; + } else { + rank = 1; + shape[0] = N_total; + shape[1] = 0; + chunk_shape[0] = 1 << 16; /* Just a guess...*/ + chunk_shape[1] = 0; + } + + /* Make sure the chunks are not larger than the dataset */ + if (chunk_shape[0] > N_total) chunk_shape[0] = N_total; + + + /* Change shape of data space */ + hid_t h_err = H5Sset_extent_simple(h_space, rank, shape, NULL); + if (h_err < 0) + error("Error while changing data space shape for field '%s'.", props.name); + + /* Create property list for collective dataset write. */ + const hid_t h_plist_id = H5Pcreate(H5P_DATASET_XFER); + H5Pset_dxpl_mpio(h_plist_id, H5FD_MPIO_COLLECTIVE); + + /* Set chunk size */ + /* h_err = H5Pset_chunk(h_prop, rank, chunk_shape); */ + /* if (h_err < 0) { */ + /* error("Error while setting chunk size (%llu, %llu) for field '%s'.", */ + /* chunk_shape[0], chunk_shape[1], props.name); */ + /* } */ + + /* Create dataset */ + const hid_t h_data = H5Dcreate(grp, props.name, io_hdf5_type(props.type), + h_space, H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); + if (h_data < 0) + error("Error while creating dataspace '%s'.", props.name); + + /* Write unit conversion factors for this data set */ + char buffer[FIELD_BUFFER_SIZE]; + units_cgs_conversion_string(buffer, snapshot_units, props.units); + io_write_attribute_d( + h_data, "CGS conversion factor", + units_cgs_conversion_factor(snapshot_units, props.units)); + io_write_attribute_f(h_data, "h-scale exponent", + units_h_factor(snapshot_units, props.units)); + io_write_attribute_f(h_data, "a-scale exponent", + units_a_factor(snapshot_units, props.units)); + io_write_attribute_s(h_data, "Conversion factor", buffer); + + /* Add a line to the XMF */ + xmf_write_line(xmfFile, fileName, partTypeGroupName, props.name, N_total, + props.dimension, props.type); + + /* Close everything */ + H5Pclose(h_plist_id); + H5Dclose(h_data); + H5Sclose(h_space); +} + + void writeArray_chunk(struct engine* e, hid_t h_data, hid_t h_plist_id, const struct io_props props, size_t N, long long offset, const struct unit_system* internal_units, @@ -361,6 +437,7 @@ void writeArray_chunk(struct engine* e, hid_t h_data, hid_t h_plist_id, H5Sclose(h_filespace); } + /** * @brief Writes a data array in given HDF5 group. * @@ -378,7 +455,7 @@ void writeArray_chunk(struct engine* e, hid_t h_data, hid_t h_plist_id, * @param internal_units The #unit_system used internally. * @param snapshot_units The #unit_system used in the snapshots. */ -void writeArray(struct engine* e, hid_t grp, char* fileName, FILE* xmfFile, +void writeArray(struct engine* e, hid_t grp, char* fileName, char* partTypeGroupName, struct io_props props, size_t N, long long N_total, int mpi_rank, long long offset, const struct unit_system* internal_units, @@ -390,62 +467,10 @@ void writeArray(struct engine* e, hid_t grp, char* fileName, FILE* xmfFile, const ticks tic = getticks(); #endif - /* Work out properties of the array in the file */ - int rank; - hsize_t shape_total[2]; - hsize_t chunk_shape[2]; - if (props.dimension > 1) { - rank = 2; - shape_total[0] = N_total; - shape_total[1] = props.dimension; - chunk_shape[0] = 1 << 16; /* Just a guess...*/ - chunk_shape[1] = props.dimension; - } else { - rank = 1; - shape_total[0] = N_total; - shape_total[1] = 0; - chunk_shape[0] = 1 << 16; /* Just a guess...*/ - chunk_shape[1] = 0; - } - - /* Make sure the chunks are not larger than the dataset */ - if (chunk_shape[0] > (hsize_t)N_total) chunk_shape[0] = N_total; - - /* Create the space in the file */ - hid_t h_filespace = H5Screate(H5S_SIMPLE); - if (h_filespace < 0) { - error("Error while creating data space (file) for field '%s'.", props.name); - } - - /* Change shape of file data space */ - hid_t h_err = H5Sset_extent_simple(h_filespace, rank, shape_total, NULL); - if (h_err < 0) { - error("Error while changing data space (file) shape for field '%s'.", - props.name); - } - - /* Dataset properties */ - const hid_t h_prop = H5Pcreate(H5P_DATASET_CREATE); - - /* Set chunk size */ - /* h_err = H5Pset_chunk(h_prop, rank, chunk_shape); */ - /* if (h_err < 0) { */ - /* error("Error while setting chunk size (%llu, %llu) for field '%s'.", */ - /* chunk_shape[0], chunk_shape[1], props.name); */ - /* } */ - - /* Create dataset */ - const hid_t h_data = H5Dcreate(grp, props.name, io_hdf5_type(props.type), - h_filespace, H5P_DEFAULT, h_prop, H5P_DEFAULT); - if (h_data < 0) { - error("Error while creating dataset '%s'.", props.name); - } - - H5Sclose(h_filespace); - - /* Create property list for collective dataset write. */ - const hid_t h_plist_id = H5Pcreate(H5P_DATASET_XFER); - H5Pset_dxpl_mpio(h_plist_id, H5FD_MPIO_COLLECTIVE); + /* Open dataset */ + const hid_t h_data = H5Dopen(grp, props.name, H5P_DEFAULT); + if (h_data < 0) + error("Error while opening dataset '%s'.", props.name); /* Given the limitations of ROM-IO we will need to write the data in chunk of HDF5_PARALLEL_IO_MAX_BYTES bytes per node until all the nodes are done. */ @@ -458,7 +483,7 @@ void writeArray(struct engine* e, hid_t grp, char* fileName, FILE* xmfFile, /* Write the first chunk */ const size_t this_chunk = (N > max_chunk_size) ? max_chunk_size : N; - writeArray_chunk(e, h_data, h_plist_id, props, this_chunk, offset, + writeArray_chunk(e, h_data, H5P_DEFAULT, props, this_chunk, offset, internal_units, snapshot_units); /* Compute how many items are left */ @@ -482,27 +507,9 @@ void writeArray(struct engine* e, hid_t grp, char* fileName, FILE* xmfFile, message("Need to redo one iteration for array '%s'", props.name); } - /* Write XMF description for this data set */ - if (mpi_rank == 0) - xmf_write_line(xmfFile, fileName, partTypeGroupName, props.name, N_total, - props.dimension, props.type); - - /* Write unit conversion factors for this data set */ - char buffer[FIELD_BUFFER_SIZE]; - units_cgs_conversion_string(buffer, snapshot_units, props.units); - io_write_attribute_d( - h_data, "CGS conversion factor", - units_cgs_conversion_factor(snapshot_units, props.units)); - io_write_attribute_f(h_data, "h-scale exponent", - units_h_factor(snapshot_units, props.units)); - io_write_attribute_f(h_data, "a-scale exponent", - units_a_factor(snapshot_units, props.units)); - io_write_attribute_s(h_data, "Conversion factor", buffer); - /* Close everything */ - H5Pclose(h_prop); H5Dclose(h_data); - H5Pclose(h_plist_id); + //H5Pclose(h_plist_id); #ifdef IO_SPEED_MEASUREMENT MPI_Barrier(MPI_COMM_WORLD); @@ -796,130 +803,43 @@ void read_ic_parallel(char* fileName, const struct unit_system* internal_units, H5Fclose(h_file); } -/** - * @brief Writes an HDF5 output file (GADGET-3 type) with - *its XMF descriptor - * - * @param e The engine containing all the system. - * @param baseName The common part of the snapshot file name. - * @param internal_units The #unit_system used internally - * @param snapshot_units The #unit_system used in the snapshots - * @param mpi_rank The MPI rank of this node. - * @param mpi_size The number of MPI ranks. - * @param comm The MPI communicator. - * @param info The MPI information object - * - * Creates an HDF5 output file and writes the particles - * contained in the engine. If such a file already exists, it is - * erased and replaced by the new one. - * The companion XMF file is also updated accordingly. - * - * Calls #error() if an error occurs. - * - */ -void write_output_parallel(struct engine* e, const char* baseName, - const struct unit_system* internal_units, - const struct unit_system* snapshot_units, - int mpi_rank, int mpi_size, MPI_Comm comm, - MPI_Info info) { +void prepare_file(struct engine* e, const char* baseName, + int outputCount, long long N_total[6], + const struct unit_system* internal_units, + const struct unit_system* snapshot_units) { - hid_t h_file = 0, h_grp = 0; - const size_t Ngas = e->s->nr_parts; - const size_t Nstars = e->s->nr_sparts; - const size_t Ntot = e->s->nr_gparts; - int periodic = e->s->periodic; - int numFiles = 1; struct part* parts = e->s->parts; struct gpart* gparts = e->s->gparts; - struct gpart* dmparts = NULL; struct spart* sparts = e->s->sparts; - static int outputCount = 0; + FILE* xmfFile = 0; - - /* Number of unassociated gparts */ - const size_t Ndm = Ntot > 0 ? Ntot - (Ngas + Nstars) : 0; - - /* File name */ - char fileName[FILENAME_BUFFER_SIZE]; - snprintf(fileName, FILENAME_BUFFER_SIZE, "%s_%04i.hdf5", baseName, - outputCount); + int periodic = e->s->periodic; + int numFiles = 1; /* First time, we need to create the XMF file */ - if (outputCount == 0 && mpi_rank == 0) xmf_create_file(baseName); + if (outputCount == 0) xmf_create_file(baseName); /* Prepare the XMF file for the new entry */ - if (mpi_rank == 0) xmfFile = xmf_prepare_file(baseName); - - /* Prepare some file-access properties */ - hid_t plist_id = H5Pcreate(H5P_FILE_ACCESS); - - /* Set some MPI-IO parameters */ - // MPI_Info_set(info, "IBM_largeblock_io", "true"); - MPI_Info_set(info, "romio_cb_write", "enable"); - MPI_Info_set(info, "romio_ds_write", "disable"); - - /* Activate parallel i/o */ - hid_t h_err = H5Pset_fapl_mpio(plist_id, comm, info); - if (h_err < 0) error("Error setting parallel i/o"); - - /* Align on 4k pages. */ - h_err = H5Pset_alignment(plist_id, 1024, 4096); - if (h_err < 0) error("Error setting Hdf5 alignment"); - - /* Disable meta-data cache eviction */ - H5AC_cache_config_t mdc_config; - mdc_config.version = H5AC__CURR_CACHE_CONFIG_VERSION; - h_err = H5Pget_mdc_config(plist_id, &mdc_config); - if (h_err < 0) error("Error getting the MDC config"); + xmfFile = xmf_prepare_file(baseName); - mdc_config.evictions_enabled = 0; /* false */ - mdc_config.incr_mode = H5C_incr__off; - mdc_config.decr_mode = H5C_decr__off; - mdc_config.flash_incr_mode = H5C_flash_incr__off; - h_err = H5Pset_mdc_config(plist_id, &mdc_config); - if (h_err < 0) error("Error setting the MDC config"); - -/* Use parallel meta-data writes */ -#if H5_VERSION_GE(1, 10, 0) - h_err = H5Pset_all_coll_metadata_ops(plist_id, 1); - if (h_err < 0) error("Error setting collective meta-data on all ops"); - h_err = H5Pset_coll_metadata_write(plist_id, 1); - if (h_err < 0) error("Error setting collective meta-data writes"); -#endif + /* HDF5 File name */ + char fileName[FILENAME_BUFFER_SIZE]; + snprintf(fileName, FILENAME_BUFFER_SIZE, "%s_%04i.hdf5", baseName, + outputCount); /* Open HDF5 file with the chosen parameters */ - h_file = H5Fcreate(fileName, H5F_ACC_TRUNC, H5P_DEFAULT, plist_id); - if (h_file < 0) { + hid_t h_file = H5Fcreate(fileName, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT); + if (h_file < 0) error("Error while opening file '%s'.", fileName); - } - - /* Compute offset in the file and total number of particles */ - size_t N[swift_type_count] = {Ngas, Ndm, 0, 0, Nstars, 0}; - long long N_total[swift_type_count] = {0}; - long long offset[swift_type_count] = {0}; - MPI_Exscan(&N, &offset, swift_type_count, MPI_LONG_LONG_INT, MPI_SUM, comm); - for (int ptype = 0; ptype < swift_type_count; ++ptype) - N_total[ptype] = offset[ptype] + N[ptype]; - - /* The last rank now has the correct N_total. Let's - * broadcast from there */ - MPI_Bcast(&N_total, 6, MPI_LONG_LONG_INT, mpi_size - 1, comm); - - /* Now everybody konws its offset and the total number of - * particles of each type */ /* Write the part of the XMF file corresponding to this * specific output */ - if (mpi_rank == 0) xmf_write_outputheader(xmfFile, fileName, e->time); + xmf_write_outputheader(xmfFile, fileName, e->time); -#ifdef IO_SPEED_MEASUREMENT - MPI_Barrier(MPI_COMM_WORLD); - ticks tic = getticks(); -#endif /* Open header to write simulation properties */ /* message("Writing runtime parameters..."); */ - h_grp = + hid_t h_grp = H5Gcreate(h_file, "/RuntimePars", H5P_DEFAULT, H5P_DEFAULT, H5P_DEFAULT); if (h_grp < 0) error("Error while creating runtime parameters group\n"); @@ -1002,17 +922,209 @@ void write_output_parallel(struct engine* e, const char* baseName, if (h_grp < 0) error("Error while creating parameters group"); parser_write_params_to_hdf5(e->parameter_file, h_grp); H5Gclose(h_grp); - + /* Print the system of Units used in the spashot */ io_write_unit_system(h_file, snapshot_units, "Units"); - + /* Print the system of Units used internally */ io_write_unit_system(h_file, internal_units, "InternalCodeUnits"); + /* 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; + + /* Add the global information for that particle type to + * the XMF meta-file */ + xmf_write_groupheader(xmfFile, fileName, N_total[ptype], + (enum part_type)ptype); + + /* Create the particle group in the file */ + char partTypeGroupName[PARTICLE_GROUP_BUFFER_SIZE]; + snprintf(partTypeGroupName, PARTICLE_GROUP_BUFFER_SIZE, "/PartType%d", + ptype); + h_grp = H5Gcreate(h_file, partTypeGroupName, H5P_DEFAULT, H5P_DEFAULT, + H5P_DEFAULT); + if (h_grp < 0) + error("Error while opening particle group %s.", partTypeGroupName); + + int num_fields = 0; + struct io_props list[100]; + + /* Write particle fields from the particle structure */ + switch (ptype) { + + case swift_type_gas: + hydro_write_particles(parts, list, &num_fields); + num_fields += chemistry_write_particles(parts, list + num_fields); + break; + + case swift_type_dark_matter: + darkmatter_write_particles(gparts, list, &num_fields); + break; + + case swift_type_star: + star_write_particles(sparts, list, &num_fields); + break; + + default: + error("Particle Type %d not yet supported. Aborting", ptype); + } + + /* Prepare everything */ + for (int i = 0; i < num_fields; ++i) + prepareArray(e, h_grp, fileName, xmfFile, partTypeGroupName, list[i], + N_total[ptype], snapshot_units); + + /* Close particle group */ + H5Gclose(h_grp); + + /* Close this particle group in the XMF file as well */ + xmf_write_groupfooter(xmfFile, (enum part_type)ptype); + } + ///// + + /* Write LXMF file descriptor */ + xmf_write_outputfooter(xmfFile, outputCount, e->time); + + /* Close the file for now */ + H5Fclose(h_file); +} + +/** + * @brief Writes an HDF5 output file (GADGET-3 type) with + *its XMF descriptor + * + * @param e The engine containing all the system. + * @param baseName The common part of the snapshot file name. + * @param internal_units The #unit_system used internally + * @param snapshot_units The #unit_system used in the snapshots + * @param mpi_rank The MPI rank of this node. + * @param mpi_size The number of MPI ranks. + * @param comm The MPI communicator. + * @param info The MPI information object + * + * Creates an HDF5 output file and writes the particles + * contained in the engine. If such a file already exists, it is + * erased and replaced by the new one. + * The companion XMF file is also updated accordingly. + * + * Calls #error() if an error occurs. + * + */ +void write_output_parallel(struct engine* e, const char* baseName, + const struct unit_system* internal_units, + const struct unit_system* snapshot_units, + int mpi_rank, int mpi_size, MPI_Comm comm, + MPI_Info info) { + + const size_t Ngas = e->s->nr_parts; + const size_t Nstars = e->s->nr_sparts; + const size_t Ntot = e->s->nr_gparts; + struct part* parts = e->s->parts; + struct gpart* gparts = e->s->gparts; + struct gpart* dmparts = NULL; + struct spart* sparts = e->s->sparts; + static int outputCount = 0; + + /* Number of unassociated gparts */ + const size_t Ndm = Ntot > 0 ? Ntot - (Ngas + Nstars) : 0; + + /* Compute offset in the file and total number of particles */ + size_t N[swift_type_count] = {Ngas, Ndm, 0, 0, Nstars, 0}; + long long N_total[swift_type_count] = {0}; + long long offset[swift_type_count] = {0}; + MPI_Exscan(&N, &offset, swift_type_count, MPI_LONG_LONG_INT, MPI_SUM, comm); + for (int ptype = 0; ptype < swift_type_count; ++ptype) + N_total[ptype] = offset[ptype] + N[ptype]; + + /* The last rank now has the correct N_total. Let's + * broadcast from there */ + MPI_Bcast(&N_total, 6, MPI_LONG_LONG_INT, mpi_size - 1, comm); + + /* Now everybody konws its offset and the total number of + * particles of each type */ + +#ifdef IO_SPEED_MEASUREMENT + ticks tic = getticks(); +#endif + + /* Rank 0 prepares the file */ + if(mpi_rank == 0) + prepare_file(e, baseName, outputCount, N_total, internal_units, snapshot_units); + + MPI_Barrier(MPI_COMM_WORLD); + +#ifdef IO_SPEED_MEASUREMENT + if (engine_rank == 0) + message("Preparing file on rank 0 took %.3f %s.", + clocks_from_ticks(getticks() - tic), clocks_getunit()); + + tic = getticks(); +#endif + + /* HDF5 File name */ + char fileName[FILENAME_BUFFER_SIZE]; + snprintf(fileName, FILENAME_BUFFER_SIZE, "%s_%04i.hdf5", baseName, + outputCount); + + /* Prepare some file-access properties */ + hid_t plist_id = H5Pcreate(H5P_FILE_ACCESS); + + /* Set some MPI-IO parameters */ + // MPI_Info_set(info, "IBM_largeblock_io", "true"); + MPI_Info_set(info, "romio_cb_write", "enable"); + MPI_Info_set(info, "romio_ds_write", "disable"); + + /* Activate parallel i/o */ + hid_t h_err = H5Pset_fapl_mpio(plist_id, comm, info); + if (h_err < 0) error("Error setting parallel i/o"); + + /* Align on 4k pages. */ + h_err = H5Pset_alignment(plist_id, 1024, 4096); + if (h_err < 0) error("Error setting Hdf5 alignment"); + + /* Disable meta-data cache eviction */ + H5AC_cache_config_t mdc_config; + mdc_config.version = H5AC__CURR_CACHE_CONFIG_VERSION; + h_err = H5Pget_mdc_config(plist_id, &mdc_config); + if (h_err < 0) error("Error getting the MDC config"); + + mdc_config.evictions_enabled = 0; /* false */ + mdc_config.incr_mode = H5C_incr__off; + mdc_config.decr_mode = H5C_decr__off; + mdc_config.flash_incr_mode = H5C_flash_incr__off; + h_err = H5Pset_mdc_config(plist_id, &mdc_config); + if (h_err < 0) error("Error setting the MDC config"); + +/* Use parallel meta-data writes */ +#if H5_VERSION_GE(1, 10, 0) + h_err = H5Pset_all_coll_metadata_ops(plist_id, 1); + if (h_err < 0) error("Error setting collective meta-data on all ops"); + h_err = H5Pset_coll_metadata_write(plist_id, 1); + if (h_err < 0) error("Error setting collective meta-data writes"); +#endif + +#ifdef IO_SPEED_MEASUREMENT + MPI_Barrier(MPI_COMM_WORLD); + if (engine_rank == 0) + message("Setting parallel HDF5 access properties took %.3f %s.", + clocks_from_ticks(getticks() - tic), clocks_getunit()); + + tic = getticks(); +#endif + + /* Open HDF5 file with the chosen parameters */ + hid_t h_file = H5Fopen(fileName, H5F_ACC_RDWR, plist_id); + if (h_file < 0) { + error("Error while opening file '%s'.", fileName); + } + #ifdef IO_SPEED_MEASUREMENT MPI_Barrier(MPI_COMM_WORLD); if (engine_rank == 0) - message("Writing HDF5 header took %.3f %s.", + message("Opening HDF5 file took %.3f %s.", clocks_from_ticks(getticks() - tic), clocks_getunit()); tic = getticks(); @@ -1057,21 +1169,13 @@ void write_output_parallel(struct engine* e, const char* baseName, /* Don't do anything if no particle of this kind */ if (N_total[ptype] == 0) continue; - /* Add the global information for that particle type to - * the XMF meta-file */ - if (mpi_rank == 0) - xmf_write_groupheader(xmfFile, fileName, N_total[ptype], - (enum part_type)ptype); - /* Open the particle group in the file */ char partTypeGroupName[PARTICLE_GROUP_BUFFER_SIZE]; snprintf(partTypeGroupName, PARTICLE_GROUP_BUFFER_SIZE, "/PartType%d", ptype); - h_grp = H5Gcreate(h_file, partTypeGroupName, H5P_DEFAULT, H5P_DEFAULT, - H5P_DEFAULT); - if (h_grp < 0) { + hid_t h_grp = H5Gopen(h_file, partTypeGroupName, H5P_DEFAULT); + if (h_grp < 0) error("Error while opening particle group %s.", partTypeGroupName); - } int num_fields = 0; struct io_props list[100]; @@ -1114,7 +1218,7 @@ void write_output_parallel(struct engine* e, const char* baseName, /* Write everything */ for (int i = 0; i < num_fields; ++i) - writeArray(e, h_grp, fileName, xmfFile, partTypeGroupName, list[i], + writeArray(e, h_grp, fileName, partTypeGroupName, list[i], Nparticles, N_total[ptype], mpi_rank, offset[ptype], internal_units, snapshot_units); @@ -1140,16 +1244,6 @@ void write_output_parallel(struct engine* e, const char* baseName, tic = getticks(); #endif - - /* Close this particle group in the XMF file as well */ - if (mpi_rank == 0) xmf_write_groupfooter(xmfFile, (enum part_type)ptype); - -#ifdef IO_SPEED_MEASUREMENT - MPI_Barrier(MPI_COMM_WORLD); - if (engine_rank == 0) - message("Writing XMF group footer took %.3f %s.", - clocks_from_ticks(getticks() - tic), clocks_getunit()); -#endif } #ifdef IO_SPEED_MEASUREMENT @@ -1157,18 +1251,6 @@ void write_output_parallel(struct engine* e, const char* baseName, tic = getticks(); #endif - /* Write LXMF file descriptor */ - if (mpi_rank == 0) xmf_write_outputfooter(xmfFile, outputCount, e->time); - -#ifdef IO_SPEED_MEASUREMENT - MPI_Barrier(MPI_COMM_WORLD); - if (engine_rank == 0) - message("Writing XMF output footer took %.3f %s.", - clocks_from_ticks(getticks() - tic), clocks_getunit()); - - tic = getticks(); -#endif - /* message("Done writing particles..."); */ /* Close property descriptor */