diff --git a/examples/test.c b/examples/test.c index 8a044c1cb98536e04eda63aff30b70c021c8a171..8be5f449f628af6d210a6c24750715a50a2baf1c 100644 --- a/examples/test.c +++ b/examples/test.c @@ -925,7 +925,7 @@ int main ( int argc , char *argv[] ) { #ifdef WITH_MPI write_output_parallel(&e, &us, myrank, nr_nodes, MPI_COMM_WORLD, MPI_INFO_NULL); #else - write_output(&e); + write_output(&e, &us); #endif message( "writing particle properties took %.3f ms." , ((double)(getticks() - tic)) / CPU_TPS * 1000 ); fflush(stdout); @@ -974,7 +974,7 @@ int main ( int argc , char *argv[] ) { #ifdef WITH_MPI write_output_parallel(&e, &us, myrank, nr_nodes, MPI_COMM_WORLD, MPI_INFO_NULL); #else - write_output(&e); + write_output(&e, &us); #endif } @@ -1019,7 +1019,7 @@ int main ( int argc , char *argv[] ) { #ifdef WITH_MPI write_output_parallel( &e, &us, myrank, nr_nodes, MPI_COMM_WORLD, MPI_INFO_NULL ); #else - write_output( &e ); + write_output( &e , &us ); #endif #ifdef WITH_MPI diff --git a/src/Makefile.am b/src/Makefile.am index e05dad13afa92c557667ac55273c3072d5c501c0..8ea80c5b54e466e32b7fc5943222644e7fe6450c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -38,11 +38,11 @@ endif # List required headers include_HEADERS = space.h runner.h queue.h task.h lock.h cell.h part.h const.h \ - engine.h swift.h serial_io.h timers.h debug.h scheduler.h proxy.h parallel_io.h + engine.h swift.h serial_io.h timers.h debug.h scheduler.h proxy.h parallel_io.h common_io.h # Common source files AM_SOURCES = space.c runner.c queue.c task.c cell.c engine.c \ - serial_io.c timers.c debug.c scheduler.c proxy.c parallel_io.c units.c + serial_io.c timers.c debug.c scheduler.c proxy.c parallel_io.c units.c common_io.c # Sources and flags for regular library libswiftsim_la_SOURCES = $(AM_SOURCES) diff --git a/src/common_io.c b/src/common_io.c new file mode 100644 index 0000000000000000000000000000000000000000..0316ca0a140f62402e473a1450e620a35a321318 --- /dev/null +++ b/src/common_io.c @@ -0,0 +1,481 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Coypright (c) 2012 Pedro Gonnet (pedro.gonnet@durham.ac.uk), + * Matthieu Schaller (matthieu.schaller@durham.ac.uk). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ + +/* Config parameters. */ +#include "../config.h" + + +#if defined(HAVE_HDF5) + +/* Some standard headers. */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stddef.h> +#include <hdf5.h> +#include <math.h> + +#include "const.h" +#include "cycle.h" +#include "lock.h" +#include "task.h" +#include "part.h" +#include "space.h" +#include "scheduler.h" +#include "engine.h" +#include "error.h" +#include "kernel.h" +#include "common_io.h" + + + +/** + * @brief Converts a C data type to the HDF5 equivalent. + * + * This function is a trivial wrapper around the HDF5 types but allows + * to change the exact storage types matching the code types in a transparent way. + */ +hid_t hdf5Type(enum DATA_TYPE type) +{ + switch(type) + { + case INT: return H5T_NATIVE_INT; + case UINT: return H5T_NATIVE_UINT; + case LONG: return H5T_NATIVE_LONG; + case ULONG: return H5T_NATIVE_ULONG; + case LONGLONG: return H5T_NATIVE_LLONG; + case ULONGLONG: return H5T_NATIVE_ULLONG; + case FLOAT: return H5T_NATIVE_FLOAT; + case DOUBLE: return H5T_NATIVE_DOUBLE; + case CHAR: return H5T_C_S1; + default: error("Unknown type"); return 0; + } +} + +/** + * @brief Returns the memory size of the data type + */ +size_t sizeOfType(enum DATA_TYPE type) +{ + switch(type) + { + case INT: return sizeof(int); + case UINT: return sizeof(unsigned int); + case LONG: return sizeof(long); + case ULONG: return sizeof(unsigned long); + case LONGLONG: return sizeof(long long); + case ULONGLONG: return sizeof(unsigned long long); + case FLOAT: return sizeof(float); + case DOUBLE: return sizeof(double); + case CHAR: return sizeof(char); + default: error("Unknown type"); return 0; + } +} + + + +/** + * @brief Reads an attribute from a given HDF5 group. + * + * @param grp The group from which to read. + * @param name The name of the attribute to read. + * @param type The #DATA_TYPE of the attribute. + * @param data (output) The attribute read from the HDF5 group. + * + * Calls #error() if an error occurs. + */ +void readAttribute(hid_t grp, char* name, enum DATA_TYPE type, void* data) +{ + hid_t h_attr=0, h_err=0; + + h_attr = H5Aopen(grp, name, H5P_DEFAULT); + if(h_attr < 0) + { + error( "Error while opening attribute '%s'" , name ); + } + + h_err = H5Aread(h_attr, hdf5Type(type), data); + if(h_err < 0) + { + error( "Error while reading attribute '%s'" , name ); + } + + H5Aclose(h_attr); +} + +/** + * @brief Write an attribute to a given HDF5 group. + * + * @param grp The group in which to write. + * @param name The name of the attribute to write. + * @param type The #DATA_TYPE of the attribute. + * @param data The attribute to write. + * @param num The number of elements to write + * + * Calls #error() if an error occurs. + */ +void writeAttribute(hid_t grp, char* name, enum DATA_TYPE type, void* data, int num) +{ + hid_t h_space=0, h_attr=0, h_err=0; + hsize_t dim[1]={num}; + + h_space = H5Screate(H5S_SIMPLE); + if(h_space < 0) + { + error( "Error while creating dataspace for attribute '%s'." , name ); + } + + h_err = H5Sset_extent_simple(h_space, 1, dim, NULL); + if(h_err < 0) + { + error( "Error while changing dataspace shape for attribute '%s'." , name ); + } + + h_attr = H5Acreate1(grp, name, hdf5Type(type), h_space, H5P_DEFAULT); + if(h_attr < 0) + { + error( "Error while creating attribute '%s'.", name ); + } + + h_err = H5Awrite(h_attr, hdf5Type(type), data); + if(h_err < 0) + { + error( "Error while reading attribute '%s'." , name ); + } + + H5Sclose(h_space); + H5Aclose(h_attr); +} + +/** + * @brief Write a string as an attribute to a given HDF5 group. + * + * @param grp The group in which to write. + * @param name The name of the attribute to write. + * @param str The string to write. + * @param length The length of the string + * + * Calls #error() if an error occurs. + */ +void writeStringAttribute(hid_t grp, char* name, char* str, int length) +{ + hid_t h_space=0, h_attr=0, h_err=0, h_type=0; + + h_space = H5Screate(H5S_SCALAR); + if(h_space < 0) + { + error( "Error while creating dataspace for attribute '%s'." , name ); + } + + h_type = H5Tcopy(H5T_C_S1); + if(h_type < 0) + { + error( "Error while copying datatype 'H5T_C_S1'." ); + } + + h_err = H5Tset_size(h_type, length); + if(h_err < 0) + { + error( "Error while resizing attribute tyep to '%i'." , length ); + } + + h_attr = H5Acreate1(grp, name, h_type, h_space, H5P_DEFAULT); + if(h_attr < 0) + { + error( "Error while creating attribute '%s'." , name ); + } + + h_err = H5Awrite(h_attr, h_type, str ); + if(h_err < 0) + { + error( "Error while reading attribute '%s'." , name ); + } + + H5Tclose(h_type); + H5Sclose(h_space); + H5Aclose(h_attr); +} + +/** + * @brief Writes a double value as an attribute + * @param grp The groupm in which to write + * @param name The name of the attribute + * @param data The value to write + */ +void writeAttribute_d(hid_t grp, char* name, double data) +{ + writeAttribute(grp, name, DOUBLE, &data, 1); +} + +/** + * @brief Writes a float value as an attribute + * @param grp The groupm in which to write + * @param name The name of the attribute + * @param data The value to write + */ +void writeAttribute_f(hid_t grp, char* name, float data) +{ + writeAttribute(grp, name, FLOAT, &data, 1); +} + +/** + * @brief Writes an int value as an attribute + * @param grp The groupm in which to write + * @param name The name of the attribute + * @param data The value to write + */ + +void writeAttribute_i(hid_t grp, char* name, int data) +{ + writeAttribute(grp, name, INT, &data, 1); +} + +/** + * @brief Writes a long value as an attribute + * @param grp The groupm in which to write + * @param name The name of the attribute + * @param data The value to write + */ +void writeAttribute_l(hid_t grp, char* name, long data) +{ + writeAttribute(grp, name, LONG, &data, 1); +} + +/** + * @brief Writes a string value as an attribute + * @param grp The groupm in which to write + * @param name The name of the attribute + * @param str The string to write + */ +void writeAttribute_s(hid_t grp, char* name, char* str) +{ + writeStringAttribute(grp, name, str, strlen(str)); +} + + +/* ------------------------------------------------------------------------------------------------ + * This part writes the XMF file descriptor enabling a visualisation through ParaView + * ------------------------------------------------------------------------------------------------ */ +/** + * @brief Writes the current model of SPH to the file + * @param h_file The (opened) HDF5 file in which to write + */ +void writeSPHflavour(hid_t h_file) +{ + hid_t h_grpsph=0; + + h_grpsph = H5Gcreate1(h_file, "/SPH", 0); + if(h_grpsph < 0) + error("Error while creating SPH group"); + + writeAttribute_f(h_grpsph, "Kernel eta", const_eta_kernel); + writeAttribute_f(h_grpsph, "Weighted N_ngb", kernel_nwneigh); + writeAttribute_f(h_grpsph, "Delta N_ngb", const_delta_nwneigh); + writeAttribute_f(h_grpsph, "Hydro gamma", const_hydro_gamma); + +#ifdef LEGACY_GADGET2_SPH + writeAttribute_s(h_grpsph, "Thermal Conductivity Model", "(No treatment) Legacy Gadget-2 as in Springel (2005)"); + writeAttribute_s(h_grpsph, "Viscosity Model", "Legacy Gadget-2 as in Springel (2005)"); + writeAttribute_f(h_grpsph, "Viscosity alpha", const_viscosity_alpha); + writeAttribute_f(h_grpsph, "Viscosity beta", 3.f); +#else + writeAttribute_s(h_grpsph, "Thermal Conductivity Model", "Price (2008) without switch"); + writeAttribute_f(h_grpsph, "Thermal Conductivity alpha", const_conductivity_alpha); + writeAttribute_s(h_grpsph, "Viscosity Model", "Morris & Monaghan (1997), Rosswog, Davies, Thielemann & Piran (2000) with additional Balsara (1995) switch"); + writeAttribute_f(h_grpsph, "Viscosity alpha_min", const_viscosity_alpha_min); + writeAttribute_f(h_grpsph, "Viscosity alpha_max", const_viscosity_alpha_max); + writeAttribute_f(h_grpsph, "Viscosity beta", 2.f); + writeAttribute_f(h_grpsph, "Viscosity decay length", const_viscosity_length); +#endif + + writeAttribute_f(h_grpsph, "CFL parameter", const_cfl); + writeAttribute_f(h_grpsph, "Maximal ln(Delta h) change over dt", const_ln_max_h_change); + writeAttribute_f(h_grpsph, "Maximal Delta h change over dt", exp(const_ln_max_h_change)); + writeAttribute_f(h_grpsph, "Maximal Delta u change over dt", const_max_u_change); + writeAttribute_s(h_grpsph, "Kernel", kernel_name); + + H5Gclose(h_grpsph); +} + +/** + * @brief Writes the current Unit System + * @param h_file The (opened) HDF5 file in which to write + */ +void writeUnitSystem(hid_t h_file, struct UnitSystem* us) +{ + hid_t h_grpunit=0; + + h_grpunit = H5Gcreate1(h_file, "/Units", 0); + if(h_grpunit < 0) + error("Error while creating Unit System group"); + + writeAttribute_d(h_grpunit, "Unit mass in cgs", getBaseUnit(us, UNIT_MASS)); + writeAttribute_d(h_grpunit, "Unit length in cgs", getBaseUnit(us, UNIT_LENGTH)); + writeAttribute_d(h_grpunit, "Unit time in cgs", getBaseUnit(us, UNIT_TIME)); + writeAttribute_d(h_grpunit, "Unit current in cgs", getBaseUnit(us, UNIT_CURRENT)); + writeAttribute_d(h_grpunit, "Unit temperature in cgs", getBaseUnit(us, UNIT_TEMPERATURE)); + + H5Gclose(h_grpunit); +} + + + +/** + * @brief Prepares the XMF file for the new entry + * + * Creates a temporary file on the disk in order to copy the right lines. + * + * @todo Use a proper XML library to avoid stupid copies. + */ +FILE* prepareXMFfile() +{ + char buffer[1024]; + + FILE* xmfFile = fopen("output.xmf", "r"); + FILE* tempFile = fopen("output_temp.xmf", "w"); + + if(xmfFile == NULL) + error("Unable to open current XMF file."); + + if(tempFile == NULL) + error("Unable to open temporary file."); + + + /* First we make a temporary copy of the XMF file and count the lines */ + int counter = 0; + while (fgets(buffer, 1024, xmfFile) != NULL) + { + counter++; + fprintf(tempFile, "%s", buffer); + } + fclose(tempFile); + fclose(xmfFile); + + /* We then copy the XMF file back up to the closing lines */ + xmfFile = fopen("output.xmf", "w"); + tempFile = fopen("output_temp.xmf", "r"); + + if(xmfFile == NULL) + error("Unable to open current XMF file."); + + if(tempFile == NULL) + error("Unable to open temporary file."); + + int i = 0; + while (fgets(buffer, 1024, tempFile) != NULL && i < counter - 3) + { + i++; + fprintf(xmfFile, "%s", buffer); + } + fprintf(xmfFile, "\n"); + fclose(tempFile); + remove("output_temp.xmf"); + + return xmfFile; +} + +/** + * @brief Writes the begin of the XMF file + * + * @todo Exploit the XML nature of the XMF format to write a proper XML writer and simplify all the XMF-related stuff. + */ +void createXMFfile() +{ + FILE* xmfFile = fopen("output.xmf", "w"); + + fprintf(xmfFile, "<?xml version=\"1.0\" ?> \n"); + fprintf(xmfFile, "<!DOCTYPE Xdmf SYSTEM \"Xdmf.dtd\" []> \n"); + fprintf(xmfFile, "<Xdmf xmlns:xi=\"http://www.w3.org/2003/XInclude\" Version=\"2.1\">\n"); + fprintf(xmfFile, "<Domain>\n"); + fprintf(xmfFile, "<Grid Name=\"TimeSeries\" GridType=\"Collection\" CollectionType=\"Temporal\">\n\n"); + + fprintf(xmfFile, "</Grid>\n"); + fprintf(xmfFile, "</Domain>\n"); + fprintf(xmfFile, "</Xdmf>\n"); + + fclose(xmfFile); +} + + +/** + * @brief Writes the part of the XMF entry presenting the geometry of the snapshot + * + * @param xmfFile The file to write in. + * @param Nparts The number of particles. + * @param hdfFileName The name of the HDF5 file corresponding to this output. + * @param time The current simulation time. + */ +void writeXMFheader(FILE* xmfFile, long long Nparts, char* hdfFileName, float time) +{ + /* Write end of file */ + + fprintf(xmfFile, "<Grid GridType=\"Collection\" CollectionType=\"Spatial\">\n"); + fprintf(xmfFile, "<Time Type=\"Single\" Value=\"%f\"/>\n", time); + fprintf(xmfFile, "<Grid Name=\"Gas\" GridType=\"Uniform\">\n"); + fprintf(xmfFile, "<Topology TopologyType=\"Polyvertex\" Dimensions=\"%lld\"/>\n", Nparts); + fprintf(xmfFile, "<Geometry GeometryType=\"XYZ\">\n"); + fprintf(xmfFile, "<DataItem Dimensions=\"%lld 3\" NumberType=\"Double\" Precision=\"8\" Format=\"HDF\">%s:/PartType0/Coordinates</DataItem>\n", Nparts, hdfFileName); + fprintf(xmfFile, "</Geometry>"); +} + + +/** + * @brief Writes the end of the XMF file (closes all open markups) + * + * @param xmfFile The file to write in. + */ +void writeXMFfooter(FILE* xmfFile) +{ + /* Write end of the section of this time step */ + + fprintf(xmfFile, "\n</Grid>\n"); + fprintf(xmfFile, "</Grid>\n"); + fprintf(xmfFile, "\n</Grid>\n"); + fprintf(xmfFile, "</Domain>\n"); + fprintf(xmfFile, "</Xdmf>\n"); + + fclose(xmfFile); +} + + +/** + * @brief Writes the lines corresponding to an array of the HDF5 output + * + * @param xmfFile The file in which to write + * @param fileName The name of the HDF5 file associated to this XMF descriptor. + * @param name The name of the array in the HDF5 file. + * @param N The number of particles. + * @param dim The dimension of the quantity (1 for scalars, 3 for vectors). + * @param type The type of the data to write. + * + * @todo Treat the types in a better way. + */ +void writeXMFline(FILE* xmfFile, char* fileName, char* name, long long N, int dim, enum DATA_TYPE type ) +{ + fprintf(xmfFile, "<Attribute Name=\"%s\" AttributeType=\"%s\" Center=\"Node\">\n", name, dim == 1 ? "Scalar": "Vector"); + if(dim == 1) + fprintf(xmfFile, "<DataItem Dimensions=\"%lld\" NumberType=\"Double\" Precision=\"%d\" Format=\"HDF\">%s:/PartType0/%s</DataItem>\n", N, type==FLOAT ? 4:8, fileName, name); + else + fprintf(xmfFile, "<DataItem Dimensions=\"%lld %d\" NumberType=\"Double\" Precision=\"%d\" Format=\"HDF\">%s:/PartType0/%s</DataItem>\n", N, dim, type==FLOAT ? 4:8, fileName, name); + fprintf(xmfFile, "</Attribute>\n"); +} + + +#endif diff --git a/src/common_io.h b/src/common_io.h new file mode 100644 index 0000000000000000000000000000000000000000..0c098f597f7acd7f8a084becb1afaadda09c381a --- /dev/null +++ b/src/common_io.h @@ -0,0 +1,78 @@ +/******************************************************************************* + * This file is part of SWIFT. + * Coypright (c) 2012 Pedro Gonnet (pedro.gonnet@durham.ac.uk), + * Matthieu Schaller (matthieu.schaller@durham.ac.uk). + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + ******************************************************************************/ + +/* Config parameters. */ +#include "../config.h" + +#include "units.h" + +#if defined(HAVE_HDF5) + + +/** + * @brief The different types of data used in the GADGET IC files. + * + * (This is admittedly a poor substitute to C++ templates...) + */ +enum DATA_TYPE{INT, LONG, LONGLONG, UINT, ULONG, ULONGLONG, FLOAT, DOUBLE, CHAR}; + +/** + * @brief The two sorts of data present in the GADGET IC files: compulsory to start a run or optional. + * + */ +enum DATA_IMPORTANCE{COMPULSORY=1, OPTIONAL=0}; + + + + +hid_t hdf5Type(enum DATA_TYPE type); +size_t sizeOfType(enum DATA_TYPE type); + +void readAttribute(hid_t grp, char* name, enum DATA_TYPE type, void* data); + +void writeAttribute(hid_t grp, char* name, enum DATA_TYPE type, void* data, int num); + +void writeAttribute_d(hid_t grp, char* name, double data); +void writeAttribute_f(hid_t grp, char* name, float data); +void writeAttribute_i(hid_t grp, char* name, int data); +void writeAttribute_l(hid_t grp, char* name, long data); +void writeAttribute_s(hid_t grp, char* name, char* str); + +void createXMFfile(); +FILE* prepareXMFfile(); +void writeXMFfooter(FILE* xmfFile); +void writeXMFheader(FILE* xmfFile, long long N, char* hdfFileName, float time); +void writeXMFline(FILE* xmfFile, char* fileName, char* name, long long N, int dim, enum DATA_TYPE type); + + +/** + * @brief Writes the current model of SPH to the file + * @param h_file The (opened) HDF5 file in which to write + */ +void writeSPHflavour(hid_t h_file); + +/** + * @brief Writes the current Unit System + * @param h_file The (opened) HDF5 file in which to write + */ +void writeUnitSystem(hid_t h_file, struct UnitSystem* us); + + +#endif diff --git a/src/parallel_io.c b/src/parallel_io.c index 16b3e3321c3a3339192f0f68d74ea37a6572540e..43a4203661f9d44b104cc18e327436bde194e5eb 100644 --- a/src/parallel_io.c +++ b/src/parallel_io.c @@ -43,98 +43,7 @@ #include "engine.h" #include "error.h" #include "kernel.h" -#include "units.h" - -/** - * @brief The different types of data used in the GADGET IC files. - * - * (This is admittedly a poor substitute to C++ templates...) - */ -enum DATA_TYPE{INT, LONG, LONGLONG, UINT, ULONG, ULONGLONG, FLOAT, DOUBLE, CHAR}; - -/** - * @brief The two sorts of data present in the GADGET IC files: compulsory to start a run or optional. - * - */ -enum DATA_IMPORTANCE{COMPULSORY=1, OPTIONAL=0}; - -/** - * @brief Converts a C data type to the HDF5 equivalent. - * - * This function is a trivial wrapper around the HDF5 types but allows - * to change the exact storage types matching the code types in a transparent way. - */ -static hid_t hdf5Type(enum DATA_TYPE type) -{ - switch(type) - { - case INT: return H5T_NATIVE_INT; - case UINT: return H5T_NATIVE_UINT; - case LONG: return H5T_NATIVE_LONG; - case ULONG: return H5T_NATIVE_ULONG; - case LONGLONG: return H5T_NATIVE_LLONG; - case ULONGLONG: return H5T_NATIVE_ULLONG; - case FLOAT: return H5T_NATIVE_FLOAT; - case DOUBLE: return H5T_NATIVE_DOUBLE; - case CHAR: return H5T_C_S1; - default: error("Unknown type"); return 0; - } -} - -/** - * @brief Returns the memory size of the data type - */ -static size_t sizeOfType(enum DATA_TYPE type) -{ - switch(type) - { - case INT: return sizeof(int); - case UINT: return sizeof(unsigned int); - case LONG: return sizeof(long); - case ULONG: return sizeof(unsigned long); - case LONGLONG: return sizeof(long long); - case ULONGLONG: return sizeof(unsigned long long); - case FLOAT: return sizeof(float); - case DOUBLE: return sizeof(double); - case CHAR: return sizeof(char); - default: error("Unknown type"); return 0; - } -} - -/*----------------------------------------------------------------------------- - * Routines reading an IC file - *-----------------------------------------------------------------------------*/ - - -/** - * @brief Reads an attribute from a given HDF5 group. - * - * @param grp The group from which to read. - * @param name The name of the attribute to read. - * @param type The #DATA_TYPE of the attribute. - * @param data (output) The attribute read from the HDF5 group. - * - * Calls #error() if an error occurs. - */ -void readAttribute(hid_t grp, char* name, enum DATA_TYPE type, void* data) -{ - hid_t h_attr=0, h_err=0; - - h_attr = H5Aopen(grp, name, H5P_DEFAULT); - if(h_attr < 0) - { - error( "Error while opening attribute '%s'" , name ); - } - - h_err = H5Aread(h_attr, hdf5Type(type), data); - if(h_err < 0) - { - error( "Error while reading attribute '%s'" , name ); - } - - H5Aclose(h_attr); -} - +#include "common_io.h" /** * @brief Reads a data array from a given HDF5 group. @@ -385,226 +294,6 @@ void read_ic_parallel ( char* fileName, double dim[3], struct part **parts, int *-----------------------------------------------------------------------------*/ -/* File descriptor output routine */ -void createXMFfile(); -FILE* prepareXMFfile(); -void writeXMFfooter(FILE* xmfFile); -void writeXMFheader(FILE* xmfFile, long long N, char* hdfFileName, float time); -void writeXMFline(FILE* xmfFile, char* fileName, char* name, long long N, int dim, enum DATA_TYPE type); - - -/** - * @brief Write an attribute to a given HDF5 group. - * - * @param grp The group in which to write. - * @param name The name of the attribute to write. - * @param type The #DATA_TYPE of the attribute. - * @param data The attribute to write. - * @param num The number of elements to write - * - * Calls #error() if an error occurs. - */ -void writeAttribute(hid_t grp, char* name, enum DATA_TYPE type, void* data, int num) -{ - hid_t h_space=0, h_attr=0, h_err=0; - hsize_t dim[1]={num}; - - h_space = H5Screate(H5S_SIMPLE); - if(h_space < 0) - { - error( "Error while creating dataspace for attribute '%s'." , name ); - } - - h_err = H5Sset_extent_simple(h_space, 1, dim, NULL); - if(h_err < 0) - { - error( "Error while changing dataspace shape for attribute '%s'." , name ); - } - - h_attr = H5Acreate1(grp, name, hdf5Type(type), h_space, H5P_DEFAULT); - if(h_attr < 0) - { - error( "Error while creating attribute '%s'.", name ); - } - - h_err = H5Awrite(h_attr, hdf5Type(type), data); - if(h_err < 0) - { - error( "Error while reading attribute '%s'." , name ); - } - - H5Sclose(h_space); - H5Aclose(h_attr); -} - -/** - * @brief Write a string as an attribute to a given HDF5 group. - * - * @param grp The group in which to write. - * @param name The name of the attribute to write. - * @param str The string to write. - * @param length The length of the string - * - * Calls #error() if an error occurs. - */ -void writeStringAttribute(hid_t grp, char* name, char* str, int length) -{ - hid_t h_space=0, h_attr=0, h_err=0, h_type=0; - - h_space = H5Screate(H5S_SCALAR); - if(h_space < 0) - { - error( "Error while creating dataspace for attribute '%s'." , name ); - } - - h_type = H5Tcopy(H5T_C_S1); - if(h_type < 0) - { - error( "Error while copying datatype 'H5T_C_S1'." ); - } - - h_err = H5Tset_size(h_type, length); - if(h_err < 0) - { - error( "Error while resizing attribute tyep to '%i'." , length ); - } - - h_attr = H5Acreate1(grp, name, h_type, h_space, H5P_DEFAULT); - if(h_attr < 0) - { - error( "Error while creating attribute '%s'." , name ); - } - - h_err = H5Awrite(h_attr, h_type, str ); - if(h_err < 0) - { - error( "Error while reading attribute '%s'." , name ); - } - - H5Tclose(h_type); - H5Sclose(h_space); - H5Aclose(h_attr); -} - -/** - * @brief Writes a double value as an attribute - * @param grp The groupm in which to write - * @param name The name of the attribute - * @param data The value to write - */ -void writeAttribute_d(hid_t grp, char* name, double data) -{ - writeAttribute(grp, name, DOUBLE, &data, 1); -} - -/** - * @brief Writes a float value as an attribute - * @param grp The groupm in which to write - * @param name The name of the attribute - * @param data The value to write - */ -void writeAttribute_f(hid_t grp, char* name, float data) -{ - writeAttribute(grp, name, FLOAT, &data, 1); -} - -/** - * @brief Writes an int value as an attribute - * @param grp The groupm in which to write - * @param name The name of the attribute - * @param data The value to write - */ - -void writeAttribute_i(hid_t grp, char* name, int data) -{ - writeAttribute(grp, name, INT, &data, 1); -} - -/** - * @brief Writes a long value as an attribute - * @param grp The groupm in which to write - * @param name The name of the attribute - * @param data The value to write - */ -void writeAttribute_l(hid_t grp, char* name, long data) -{ - writeAttribute(grp, name, LONG, &data, 1); -} - -/** - * @brief Writes a string value as an attribute - * @param grp The groupm in which to write - * @param name The name of the attribute - * @param str The string to write - */ -void writeAttribute_s(hid_t grp, char* name, char* str) -{ - writeStringAttribute(grp, name, str, strlen(str)); -} - -/** - * @brief Writes the current model of SPH to the file - * @param h_file The (opened) HDF5 file in which to write - */ -void writeSPHflavour(hid_t h_file) -{ - hid_t h_grpsph=0; - - h_grpsph = H5Gcreate1(h_file, "/SPH", 0); - if(h_grpsph < 0) - error("Error while creating SPH group"); - - writeAttribute_f(h_grpsph, "Kernel eta", const_eta_kernel); - writeAttribute_f(h_grpsph, "Weighted N_ngb", kernel_nwneigh); - writeAttribute_f(h_grpsph, "Delta N_ngb", const_delta_nwneigh); - writeAttribute_f(h_grpsph, "Hydro gamma", const_hydro_gamma); - -#ifdef LEGACY_GADGET2_SPH - writeAttribute_s(h_grpsph, "Thermal Conductivity Model", "(No treatment) Legacy Gadget-2 as in Springel (2005)"); - writeAttribute_s(h_grpsph, "Viscosity Model", "Legacy Gadget-2 as in Springel (2005)"); - writeAttribute_f(h_grpsph, "Viscosity alpha", const_viscosity_alpha); - writeAttribute_f(h_grpsph, "Viscosity beta", 3.f); -#else - writeAttribute_s(h_grpsph, "Thermal Conductivity Model", "Price (2008) without switch"); - writeAttribute_f(h_grpsph, "Thermal Conductivity alpha", const_conductivity_alpha); - writeAttribute_s(h_grpsph, "Viscosity Model", "Morris & Monaghan (1997), Rosswog, Davies, Thielemann & Piran (2000) with additional Balsara (1995) switch"); - writeAttribute_f(h_grpsph, "Viscosity alpha_min", const_viscosity_alpha_min); - writeAttribute_f(h_grpsph, "Viscosity alpha_max", const_viscosity_alpha_max); - writeAttribute_f(h_grpsph, "Viscosity beta", 2.f); - writeAttribute_f(h_grpsph, "Viscosity decay length", const_viscosity_length); -#endif - - writeAttribute_f(h_grpsph, "CFL parameter", const_cfl); - writeAttribute_f(h_grpsph, "Maximal ln(Delta h) change over dt", const_ln_max_h_change); - writeAttribute_f(h_grpsph, "Maximal Delta h change over dt", exp(const_ln_max_h_change)); - writeAttribute_f(h_grpsph, "Maximal Delta u change over dt", const_max_u_change); - writeAttribute_s(h_grpsph, "Kernel", kernel_name); - - H5Gclose(h_grpsph); -} - -/** - * @brief Writes the current Unit System - * @param h_file The (opened) HDF5 file in which to write - */ -void writeUnitSystem(hid_t h_file, struct UnitSystem* us) -{ - hid_t h_grpunit=0; - - h_grpunit = H5Gcreate1(h_file, "/Units", 0); - if(h_grpunit < 0) - error("Error while creating Unit System group"); - - writeAttribute_d(h_grpunit, "Unit mass in cgs", getBaseUnit(us, UNIT_MASS)); - writeAttribute_d(h_grpunit, "Unit length in cgs", getBaseUnit(us, UNIT_LENGTH)); - writeAttribute_d(h_grpunit, "Unit time in cgs", getBaseUnit(us, UNIT_TIME)); - writeAttribute_d(h_grpunit, "Unit current in cgs", getBaseUnit(us, UNIT_CURRENT)); - writeAttribute_d(h_grpunit, "Unit temperature in cgs", getBaseUnit(us, UNIT_TEMPERATURE)); - - H5Gclose(h_grpunit); -} - - /** * @brief Writes a data array in given HDF5 group. * @@ -725,8 +414,7 @@ void writeArrayBackEnd(hid_t grp, char* fileName, FILE* xmfFile, char* name, enu writeAttribute_d( h_data, "h-scale exponant", hFactor( us, convFactor ) ); writeAttribute_d( h_data, "a-scale exponant", aFactor( us, convFactor ) ); writeAttribute_s( h_data, "Conversion factor", buffer ); - - + /* Free and close everything */ free(temp); H5Dclose(h_data); @@ -854,14 +542,14 @@ void write_output_parallel (struct engine *e, struct UnitSystem* us, int mpi_ra writeAttribute(h_grp, "Flag_Entropy_ICs", UINT, flagEntropy, 6); writeAttribute(h_grp, "NumFilesPerSnapshot", INT, &numFiles, 1); + /* Close header */ + H5Gclose(h_grp); + /* Print the SPH parameters */ writeSPHflavour(h_file); /* Print the system of Units */ writeUnitSystem(h_file, us); - - /* Close header */ - H5Gclose(h_grp); /* Create SPH particles group */ /* message("Writing particle arrays..."); */ @@ -896,150 +584,6 @@ void write_output_parallel (struct engine *e, struct UnitSystem* us, int mpi_ra } -/* ------------------------------------------------------------------------------------------------ - * This part writes the XMF file descriptor enabling a visualisation through ParaView - * ------------------------------------------------------------------------------------------------ */ - -/** - * @brief Writes the lines corresponding to an array of the HDF5 output - * - * @param xmfFile The file in which to write - * @param fileName The name of the HDF5 file associated to this XMF descriptor. - * @param name The name of the array in the HDF5 file. - * @param N The number of particles. - * @param dim The dimension of the quantity (1 for scalars, 3 for vectors). - * @param type The type of the data to write. - * - * @todo Treat the types in a better way. - */ -void writeXMFline(FILE* xmfFile, char* fileName, char* name, long long N, int dim, enum DATA_TYPE type ) -{ - fprintf(xmfFile, "<Attribute Name=\"%s\" AttributeType=\"%s\" Center=\"Node\">\n", name, dim == 1 ? "Scalar": "Vector"); - if(dim == 1) - fprintf(xmfFile, "<DataItem Dimensions=\"%lld\" NumberType=\"Double\" Precision=\"%d\" Format=\"HDF\">%s:/PartType0/%s</DataItem>\n", N, type==FLOAT ? 4:8, fileName, name); - else - fprintf(xmfFile, "<DataItem Dimensions=\"%lld %d\" NumberType=\"Double\" Precision=\"%d\" Format=\"HDF\">%s:/PartType0/%s</DataItem>\n", N, dim, type==FLOAT ? 4:8, fileName, name); - fprintf(xmfFile, "</Attribute>\n"); -} - - -/** - * @brief Prepares the XMF file for the new entry - * - * Creates a temporary file on the disk in order to copy the right lines. - * - * @todo Use a proper XML library to avoid stupid copies. - */ -FILE* prepareXMFfile() -{ - char buffer[1024]; - - FILE* xmfFile = fopen("output.xmf", "r"); - FILE* tempFile = fopen("output_temp.xmf", "w"); - - if(xmfFile == NULL) - error("Unable to open current XMF file."); - - if(tempFile == NULL) - error("Unable to open temporary file."); - - - /* First we make a temporary copy of the XMF file and count the lines */ - int counter = 0; - while (fgets(buffer, 1024, xmfFile) != NULL) - { - counter++; - fprintf(tempFile, "%s", buffer); - } - fclose(tempFile); - fclose(xmfFile); - - /* We then copy the XMF file back up to the closing lines */ - xmfFile = fopen("output.xmf", "w"); - tempFile = fopen("output_temp.xmf", "r"); - - if(xmfFile == NULL) - error("Unable to open current XMF file."); - - if(tempFile == NULL) - error("Unable to open temporary file."); - - int i = 0; - while (fgets(buffer, 1024, tempFile) != NULL && i < counter - 3) - { - i++; - fprintf(xmfFile, "%s", buffer); - } - fprintf(xmfFile, "\n"); - fclose(tempFile); - remove("output_temp.xmf"); - - return xmfFile; -} - -/** - * @brief Writes the begin of the XMF file - * - * @todo Exploit the XML nature of the XMF format to write a proper XML writer and simplify all the XMF-related stuff. - */ -void createXMFfile() -{ - FILE* xmfFile = fopen("output.xmf", "w"); - - fprintf(xmfFile, "<?xml version=\"1.0\" ?> \n"); - fprintf(xmfFile, "<!DOCTYPE Xdmf SYSTEM \"Xdmf.dtd\" []> \n"); - fprintf(xmfFile, "<Xdmf xmlns:xi=\"http://www.w3.org/2003/XInclude\" Version=\"2.1\">\n"); - fprintf(xmfFile, "<Domain>\n"); - fprintf(xmfFile, "<Grid Name=\"TimeSeries\" GridType=\"Collection\" CollectionType=\"Temporal\">\n\n"); - - fprintf(xmfFile, "</Grid>\n"); - fprintf(xmfFile, "</Domain>\n"); - fprintf(xmfFile, "</Xdmf>\n"); - - fclose(xmfFile); -} - - -/** - * @brief Writes the part of the XMF entry presenting the geometry of the snapshot - * - * @param xmfFile The file to write in. - * @param Nparts The number of particles. - * @param hdfFileName The name of the HDF5 file corresponding to this output. - * @param time The current simulation time. - */ -void writeXMFheader(FILE* xmfFile, long long Nparts, char* hdfFileName, float time) -{ - /* Write end of file */ - - fprintf(xmfFile, "<Grid GridType=\"Collection\" CollectionType=\"Spatial\">\n"); - fprintf(xmfFile, "<Time Type=\"Single\" Value=\"%f\"/>\n", time); - fprintf(xmfFile, "<Grid Name=\"Gas\" GridType=\"Uniform\">\n"); - fprintf(xmfFile, "<Topology TopologyType=\"Polyvertex\" Dimensions=\"%lld\"/>\n", Nparts); - fprintf(xmfFile, "<Geometry GeometryType=\"XYZ\">\n"); - fprintf(xmfFile, "<DataItem Dimensions=\"%lld 3\" NumberType=\"Double\" Precision=\"8\" Format=\"HDF\">%s:/PartType0/Coordinates</DataItem>\n", Nparts, hdfFileName); - fprintf(xmfFile, "</Geometry>"); -} - - -/** - * @brief Writes the end of the XMF file (closes all open markups) - * - * @param xmfFile The file to write in. - */ -void writeXMFfooter(FILE* xmfFile) -{ - /* Write end of the section of this time step */ - - fprintf(xmfFile, "\n</Grid>\n"); - fprintf(xmfFile, "</Grid>\n"); - fprintf(xmfFile, "\n</Grid>\n"); - fprintf(xmfFile, "</Domain>\n"); - fprintf(xmfFile, "</Xdmf>\n"); - - fclose(xmfFile); -} - #endif /* HAVE_HDF5 */ diff --git a/src/serial_io.c b/src/serial_io.c index 72542c10e6f02fc21a1348cf496d73cd8ef4eec3..9601f7e892ac146369d4d9d6c193f3f2d8e5e3ab 100644 --- a/src/serial_io.c +++ b/src/serial_io.c @@ -42,98 +42,14 @@ #include "engine.h" #include "error.h" #include "kernel.h" +#include "common_io.h" -/** - * @brief The different types of data used in the GADGET IC files. - * - * (This is admittedly a poor substitute to C++ templates...) - */ -enum DATA_TYPE{INT, LONG, LONGLONG, UINT, ULONG, ULONGLONG, FLOAT, DOUBLE, CHAR}; -/** - * @brief The two sorts of data present in the GADGET IC files: compulsory to start a run or optional. - * - */ -enum DATA_IMPORTANCE{COMPULSORY=1, OPTIONAL=0}; - -/** - * @brief Converts a C data type to the HDF5 equivalent. - * - * This function is a trivial wrapper around the HDF5 types but allows - * to change the exact storage types matching the code types in a transparent way. - */ -static hid_t hdf5Type(enum DATA_TYPE type) -{ - switch(type) - { - case INT: return H5T_NATIVE_INT; - case UINT: return H5T_NATIVE_UINT; - case LONG: return H5T_NATIVE_LONG; - case ULONG: return H5T_NATIVE_ULONG; - case LONGLONG: return H5T_NATIVE_LLONG; - case ULONGLONG: return H5T_NATIVE_ULLONG; - case FLOAT: return H5T_NATIVE_FLOAT; - case DOUBLE: return H5T_NATIVE_DOUBLE; - case CHAR: return H5T_C_S1; - default: error("Unknown type"); return 0; - } -} - -/** - * @brief Returns the memory size of the data type - */ -static size_t sizeOfType(enum DATA_TYPE type) -{ - switch(type) - { - case INT: return sizeof(int); - case UINT: return sizeof(unsigned int); - case LONG: return sizeof(long); - case ULONG: return sizeof(unsigned long); - case LONGLONG: return sizeof(long long); - case ULONGLONG: return sizeof(unsigned long long); - case FLOAT: return sizeof(float); - case DOUBLE: return sizeof(double); - case CHAR: return sizeof(char); - default: error("Unknown type"); return 0; - } -} /*----------------------------------------------------------------------------- * Routines reading an IC file *-----------------------------------------------------------------------------*/ - -/** - * @brief Reads an attribute from a given HDF5 group. - * - * @param grp The group from which to read. - * @param name The name of the attribute to read. - * @param type The #DATA_TYPE of the attribute. - * @param data (output) The attribute read from the HDF5 group. - * - * Calls #error() if an error occurs. - */ -void readAttribute(hid_t grp, char* name, enum DATA_TYPE type, void* data) -{ - hid_t h_attr=0, h_err=0; - - h_attr = H5Aopen(grp, name, H5P_DEFAULT); - if(h_attr < 0) - { - error( "Error while opening attribute '%s'" , name ); - } - - h_err = H5Aread(h_attr, hdf5Type(type), data); - if(h_err < 0) - { - error( "Error while reading attribute '%s'" , name ); - } - - H5Aclose(h_attr); -} - - /** * @brief Reads a data array from a given HDF5 group. * @@ -344,165 +260,6 @@ void read_ic ( char* fileName, double dim[3], struct part **parts, int* N, int* * Routines writing an output file *-----------------------------------------------------------------------------*/ - -/* File descriptor output routine */ -void createXMFfile(); -FILE* prepareXMFfile(); -void writeXMFfooter(FILE* xmfFile); -void writeXMFheader(FILE* xmfFile, int Nparts, char* hdfFileName, float time); -void writeXMFline(FILE* xmfFile, char* fileName, char* name, int N, int dim, enum DATA_TYPE type); - - -/** - * @brief Write an attribute to a given HDF5 group. - * - * @param grp The group in which to write. - * @param name The name of the attribute to write. - * @param type The #DATA_TYPE of the attribute. - * @param data The attribute to write. - * @param num The number of elements to write - * - * Calls #error() if an error occurs. - */ -void writeAttribute(hid_t grp, char* name, enum DATA_TYPE type, void* data, int num) -{ - hid_t h_space=0, h_attr=0, h_err=0; - hsize_t dim[1]={num}; - - h_space = H5Screate(H5S_SIMPLE); - if(h_space < 0) - { - error( "Error while creating dataspace for attribute '%s'." , name ); - } - - h_err = H5Sset_extent_simple(h_space, 1, dim, NULL); - if(h_err < 0) - { - error( "Error while changing dataspace shape for attribute '%s'." , name ); - } - - h_attr = H5Acreate1(grp, name, hdf5Type(type), h_space, H5P_DEFAULT); - if(h_attr < 0) - { - error( "Error while creating attribute '%s'.", name ); - } - - h_err = H5Awrite(h_attr, hdf5Type(type), data); - if(h_err < 0) - { - error( "Error while reading attribute '%s'." , name ); - } - - H5Sclose(h_space); - H5Aclose(h_attr); -} - -/** - * @brief Write a string as an attribute to a given HDF5 group. - * - * @param grp The group in which to write. - * @param name The name of the attribute to write. - * @param str The string to write. - * @param length The length of the string - * - * Calls #error() if an error occurs. - */ -void writeStringAttribute(hid_t grp, char* name, char* str, int length) -{ - hid_t h_space=0, h_attr=0, h_err=0, h_type=0; - - h_space = H5Screate(H5S_SCALAR); - if(h_space < 0) - { - error( "Error while creating dataspace for attribute '%s'." , name ); - } - - h_type = H5Tcopy(H5T_C_S1); - if(h_type < 0) - { - error( "Error while copying datatype 'H5T_C_S1'." ); - } - - h_err = H5Tset_size(h_type, length); - if(h_err < 0) - { - error( "Error while resizing attribute tyep to '%i'." , length ); - } - - h_attr = H5Acreate1(grp, name, h_type, h_space, H5P_DEFAULT); - if(h_attr < 0) - { - error( "Error while creating attribute '%s'." , name ); - } - - h_err = H5Awrite(h_attr, h_type, str ); - if(h_err < 0) - { - error( "Error while reading attribute '%s'." , name ); - } - - H5Tclose(h_type); - H5Sclose(h_space); - H5Aclose(h_attr); -} - -/** - * @brief Writes a double value as an attribute - * @param grp The groupm in which to write - * @param name The name of the attribute - * @param data The value to write - */ -void writeAttribute_d(hid_t grp, char* name, double data) -{ - writeAttribute(grp, name, DOUBLE, &data, 1); -} - -/** - * @brief Writes a float value as an attribute - * @param grp The groupm in which to write - * @param name The name of the attribute - * @param data The value to write - */ -void writeAttribute_f(hid_t grp, char* name, float data) -{ - writeAttribute(grp, name, FLOAT, &data, 1); -} - -/** - * @brief Writes an int value as an attribute - * @param grp The groupm in which to write - * @param name The name of the attribute - * @param data The value to write - */ - -void writeAttribute_i(hid_t grp, char* name, int data) -{ - writeAttribute(grp, name, INT, &data, 1); -} - -/** - * @brief Writes a long value as an attribute - * @param grp The groupm in which to write - * @param name The name of the attribute - * @param data The value to write - */ -void writeAttribute_l(hid_t grp, char* name, long data) -{ - writeAttribute(grp, name, LONG, &data, 1); -} - -/** - * @brief Writes a string value as an attribute - * @param grp The groupm in which to write - * @param name The name of the attribute - * @param str The string to write - */ -void writeAttribute_s(hid_t grp, char* name, char* str) -{ - writeStringAttribute(grp, name, str, strlen(str)); -} - - /** * @brief Writes a data array in given HDF5 group. * @@ -520,7 +277,7 @@ void writeAttribute_s(hid_t grp, char* name, char* str) * * Calls #error() if an error occurs. */ -void writeArrayBackEnd(hid_t grp, char* fileName, FILE* xmfFile, char* name, enum DATA_TYPE type, int N, int dim, char* part_c /*, struct UnitSystem* us, enum UnitConversionFactor convFact */) +void writeArrayBackEnd(hid_t grp, char* fileName, FILE* xmfFile, char* name, enum DATA_TYPE type, int N, int dim, char* part_c, struct UnitSystem* us, enum UnitConversionFactor convFactor) { hid_t h_data=0, h_err=0, h_space=0; void* temp = 0; @@ -530,6 +287,7 @@ void writeArrayBackEnd(hid_t grp, char* fileName, FILE* xmfFile, char* name, enu const size_t partSize = sizeof(struct part); char* temp_c = 0; hsize_t shape[2]; + char buffer[150]; /* message("Writing '%s' array...", name); */ @@ -585,6 +343,12 @@ void writeArrayBackEnd(hid_t grp, char* fileName, FILE* xmfFile, char* name, enu /* Write XMF description for this data set */ writeXMFline(xmfFile, fileName, name, N, dim, type); + /* Write unit conversion factors for this data set */ + conversionString( buffer, us, convFactor ); + writeAttribute_d( h_data, "CGS conversion factor", conversionFactor( us, convFactor ) ); + writeAttribute_d( h_data, "h-scale exponant", hFactor( us, convFactor ) ); + writeAttribute_d( h_data, "a-scale exponant", aFactor( us, convFactor ) ); + writeAttribute_s( h_data, "Conversion factor", buffer ); /* Free and close everything */ free(temp); @@ -604,9 +368,11 @@ void writeArrayBackEnd(hid_t grp, char* fileName, FILE* xmfFile, char* name, enu * @param dim The dimension of the data (1 for scalar, 3 for vector) * @param part A (char*) pointer on the first occurence of the field of interest in the parts array * @param field The name (code name) of the field to read from. + * @param us The UnitSystem currently in use + * @param convFactor The UnitConversionFactor for this array * */ -#define writeArray(grp, fileName, xmfFile, name, type, N, dim, part, field /*, us, unitConv */) writeArrayBackEnd(grp, fileName, xmfFile, name, type, N, dim, (char*)(&(part[0]).field)) +#define writeArray(grp, fileName, xmfFile, name, type, N, dim, part, field, us, convFactor) writeArrayBackEnd(grp, fileName, xmfFile, name, type, N, dim, (char*)(&(part[0]).field), us, convFactor) /** * @brief Writes an HDF5 output file (GADGET-3 type) with its XMF descriptor @@ -621,10 +387,10 @@ void writeArrayBackEnd(hid_t grp, char* fileName, FILE* xmfFile, char* name, enu * Calls #error() if an error occurs. * */ -void write_output (struct engine *e) +void write_output (struct engine *e, struct UnitSystem* us) { - hid_t h_file=0, h_grp=0, h_grpsph=0; + hid_t h_file=0, h_grp=0; int N = e->s->nr_parts; int periodic = e->s->periodic; int numParticles[6]={N,0}; @@ -688,40 +454,14 @@ void write_output (struct engine *e) writeAttribute(h_grp, "Flag_Entropy_ICs", UINT, numParticlesHighWord, 6); writeAttribute(h_grp, "NumFilesPerSnapshot", INT, &numFiles, 1); - /* Print the SPH parameters */ - h_grpsph = H5Gcreate1(h_file, "/Header/SPH", 0); - if(h_grpsph < 0) - error("Error while creating SPH header\n"); - - writeAttribute_f(h_grpsph, "Kernel eta", const_eta_kernel); - writeAttribute_f(h_grpsph, "Weighted N_ngb", kernel_nwneigh); - writeAttribute_f(h_grpsph, "Delta N_ngb", const_delta_nwneigh); - writeAttribute_f(h_grpsph, "Hydro gamma", const_hydro_gamma); - -#ifdef LEGACY_GADGET2_SPH - writeAttribute_s(h_grpsph, "Thermal Conductivity Model", "(No treatment) Legacy Gadget-2 as in Springel (2005)"); - writeAttribute_s(h_grpsph, "Viscosity Model", "Legacy Gadget-2 as in Springel (2005)"); - writeAttribute_f(h_grpsph, "Viscosity alpha", const_viscosity_alpha); - writeAttribute_f(h_grpsph, "Viscosity beta", 3.f); -#else - writeAttribute_s(h_grpsph, "Thermal Conductivity Model", "Price (2008) without switch"); - writeAttribute_f(h_grpsph, "Thermal Conductivity alpha", const_conductivity_alpha); - writeAttribute_s(h_grpsph, "Viscosity Model", "Morris & Monaghan (1997), Rosswog, Davies, Thielemann & Piran (2000) with additional Balsara (1995) switch"); - writeAttribute_f(h_grpsph, "Viscosity alpha_min", const_viscosity_alpha_min); - writeAttribute_f(h_grpsph, "Viscosity alpha_max", const_viscosity_alpha_max); - writeAttribute_f(h_grpsph, "Viscosity beta", 2.f); - writeAttribute_f(h_grpsph, "Viscosity decay length", const_viscosity_length); -#endif - - writeAttribute_f(h_grpsph, "CFL parameter", const_cfl); - writeAttribute_f(h_grpsph, "Maximal ln(Delta h) change over dt", const_ln_max_h_change); - writeAttribute_f(h_grpsph, "Maximal Delta h change over dt", exp(const_ln_max_h_change)); - writeAttribute_f(h_grpsph, "Maximal Delta u change over dt", const_max_u_change); - writeAttribute_s(h_grpsph, "Kernel", kernel_name); - - /* Close headers */ - H5Gclose(h_grpsph); + /* Close header */ H5Gclose(h_grp); + + /* Print the SPH parameters */ + writeSPHflavour(h_file); + + /* Print the system of Units */ + writeUnitSystem(h_file, us); /* Create SPH particles group */ /* message("Writing particle arrays..."); */ @@ -730,15 +470,15 @@ void write_output (struct engine *e) error( "Error while creating particle group.\n"); /* Write arrays */ - writeArray(h_grp, fileName, xmfFile, "Coordinates", DOUBLE, N, 3, parts, x); - writeArray(h_grp, fileName, xmfFile, "Velocities", FLOAT, N, 3, parts, v); - writeArray(h_grp, fileName, xmfFile, "Masses", FLOAT, N, 1, parts, mass); - writeArray(h_grp, fileName, xmfFile, "SmoothingLength", FLOAT, N, 1, parts, h); - writeArray(h_grp, fileName, xmfFile, "InternalEnergy", FLOAT, N, 1, parts, u); - writeArray(h_grp, fileName, xmfFile, "ParticleIDs", ULONGLONG, N, 1, parts, id); - writeArray(h_grp, fileName, xmfFile, "TimeStep", FLOAT, N, 1, parts, dt); - writeArray(h_grp, fileName, xmfFile, "Acceleration", FLOAT, N, 3, parts, a); - writeArray(h_grp, fileName, xmfFile, "Density", FLOAT, N, 1, parts, rho); + writeArray(h_grp, fileName, xmfFile, "Coordinates", DOUBLE, N, 3, parts, x, us, UNIT_CONV_LENGTH); + writeArray(h_grp, fileName, xmfFile, "Velocities", FLOAT, N, 3, parts, v, us, UNIT_CONV_SPEED); + writeArray(h_grp, fileName, xmfFile, "Masses", FLOAT, N, 1, parts, mass, us, UNIT_CONV_MASS); + writeArray(h_grp, fileName, xmfFile, "SmoothingLength", FLOAT, N, 1, parts, h, us, UNIT_CONV_LENGTH); + writeArray(h_grp, fileName, xmfFile, "InternalEnergy", FLOAT, N, 1, parts, u, us, UNIT_CONV_ENERGY_PER_UNIT_MASS); + writeArray(h_grp, fileName, xmfFile, "ParticleIDs", ULONGLONG, N, 1, parts, id, us, UNIT_CONV_NO_UNITS); + writeArray(h_grp, fileName, xmfFile, "TimeStep", FLOAT, N, 1, parts, dt, us, UNIT_CONV_TIME); + writeArray(h_grp, fileName, xmfFile, "Acceleration", FLOAT, N, 3, parts, a, us, UNIT_CONV_ACCELERATION); + writeArray(h_grp, fileName, xmfFile, "Density", FLOAT, N, 1, parts, rho, us, UNIT_CONV_DENSITY); /* Close particle group */ H5Gclose(h_grp); @@ -755,151 +495,6 @@ void write_output (struct engine *e) } - -/* ------------------------------------------------------------------------------------------------ - * This part writes the XMF file descriptor enabling a visualisation through ParaView - * ------------------------------------------------------------------------------------------------ */ - -/** - * @brief Writes the lines corresponding to an array of the HDF5 output - * - * @param xmfFile The file in which to write - * @param fileName The name of the HDF5 file associated to this XMF descriptor. - * @param name The name of the array in the HDF5 file. - * @param N The number of particles. - * @param dim The dimension of the quantity (1 for scalars, 3 for vectors). - * @param type The type of the data to write. - * - * @todo Treat the types in a better way. - */ -void writeXMFline(FILE* xmfFile, char* fileName, char* name, int N, int dim, enum DATA_TYPE type ) -{ - fprintf(xmfFile, "<Attribute Name=\"%s\" AttributeType=\"%s\" Center=\"Node\">\n", name, dim == 1 ? "Scalar": "Vector"); - if(dim == 1) - fprintf(xmfFile, "<DataItem Dimensions=\"%d\" NumberType=\"Double\" Precision=\"%d\" Format=\"HDF\">%s:/PartType0/%s</DataItem>\n", N, type==FLOAT ? 4:8, fileName, name); - else - fprintf(xmfFile, "<DataItem Dimensions=\"%d %d\" NumberType=\"Double\" Precision=\"%d\" Format=\"HDF\">%s:/PartType0/%s</DataItem>\n", N, dim, type==FLOAT ? 4:8, fileName, name); - fprintf(xmfFile, "</Attribute>\n"); -} - - -/** - * @brief Prepares the XMF file for the new entry - * - * Creates a temporary file on the disk in order to copy the right lines. - * - * @todo Use a proper XML library to avoid stupid copies. - */ -FILE* prepareXMFfile() -{ - char buffer[1024]; - - FILE* xmfFile = fopen("output.xmf", "r"); - FILE* tempFile = fopen("output_temp.xmf", "w"); - - if(xmfFile == NULL) - error("Unable to open current XMF file."); - - if(tempFile == NULL) - error("Unable to open temporary file."); - - - /* First we make a temporary copy of the XMF file and count the lines */ - int counter = 0; - while (fgets(buffer, 1024, xmfFile) != NULL) - { - counter++; - fprintf(tempFile, "%s", buffer); - } - fclose(tempFile); - fclose(xmfFile); - - /* We then copy the XMF file back up to the closing lines */ - xmfFile = fopen("output.xmf", "w"); - tempFile = fopen("output_temp.xmf", "r"); - - if(xmfFile == NULL) - error("Unable to open current XMF file."); - - if(tempFile == NULL) - error("Unable to open temporary file."); - - int i = 0; - while (fgets(buffer, 1024, tempFile) != NULL && i < counter - 3) - { - i++; - fprintf(xmfFile, "%s", buffer); - } - fprintf(xmfFile, "\n"); - fclose(tempFile); - remove("output_temp.xmf"); - - return xmfFile; -} - -/** - * @brief Writes the begin of the XMF file - * - * @todo Exploit the XML nature of the XMF format to write a proper XML writer and simplify all the XMF-related stuff. - */ -void createXMFfile() -{ - FILE* xmfFile = fopen("output.xmf", "w"); - - fprintf(xmfFile, "<?xml version=\"1.0\" ?> \n"); - fprintf(xmfFile, "<!DOCTYPE Xdmf SYSTEM \"Xdmf.dtd\" []> \n"); - fprintf(xmfFile, "<Xdmf xmlns:xi=\"http://www.w3.org/2003/XInclude\" Version=\"2.1\">\n"); - fprintf(xmfFile, "<Domain>\n"); - fprintf(xmfFile, "<Grid Name=\"TimeSeries\" GridType=\"Collection\" CollectionType=\"Temporal\">\n\n"); - - fprintf(xmfFile, "</Grid>\n"); - fprintf(xmfFile, "</Domain>\n"); - fprintf(xmfFile, "</Xdmf>\n"); - - fclose(xmfFile); -} - - -/** - * @brief Writes the part of the XMF entry presenting the geometry of the snapshot - * - * @param xmfFile The file to write in. - * @param Nparts The number of particles. - * @param hdfFileName The name of the HDF5 file corresponding to this output. - * @param time The current simulation time. - */ -void writeXMFheader(FILE* xmfFile, int Nparts, char* hdfFileName, float time) -{ - /* Write end of file */ - - fprintf(xmfFile, "<Grid GridType=\"Collection\" CollectionType=\"Spatial\">\n"); - fprintf(xmfFile, "<Time Type=\"Single\" Value=\"%f\"/>\n", time); - fprintf(xmfFile, "<Grid Name=\"Gas\" GridType=\"Uniform\">\n"); - fprintf(xmfFile, "<Topology TopologyType=\"Polyvertex\" Dimensions=\"%d\"/>\n", Nparts); - fprintf(xmfFile, "<Geometry GeometryType=\"XYZ\">\n"); - fprintf(xmfFile, "<DataItem Dimensions=\"%d 3\" NumberType=\"Double\" Precision=\"8\" Format=\"HDF\">%s:/PartType0/Coordinates</DataItem>\n", Nparts, hdfFileName); - fprintf(xmfFile, "</Geometry>"); -} - - -/** - * @brief Writes the end of the XMF file (closes all open markups) - * - * @param xmfFile The file to write in. - */ -void writeXMFfooter(FILE* xmfFile) -{ - /* Write end of the section of this time step */ - - fprintf(xmfFile, "\n</Grid>\n"); - fprintf(xmfFile, "</Grid>\n"); - fprintf(xmfFile, "\n</Grid>\n"); - fprintf(xmfFile, "</Domain>\n"); - fprintf(xmfFile, "</Xdmf>\n"); - - fclose(xmfFile); -} - #endif /* HAVE_HDF5 */ diff --git a/src/serial_io.h b/src/serial_io.h index b7d7a3e3ab59c49d1e837d23825e07ad827bb85a..a827a47373fdfbc01b5ff0e5d64faca39d316f6d 100644 --- a/src/serial_io.h +++ b/src/serial_io.h @@ -22,7 +22,7 @@ void read_ic ( char* fileName, double dim[3], struct part **parts, int* N, int* periodic); -void write_output ( struct engine* e); +void write_output ( struct engine* e, struct UnitSystem* us ); #endif