diff --git a/src/output.c b/src/output.c index 2fd715aa89a7b74547bfe9287e336a91b86a9992..d3827d08047f2454583a6d761f7b0e8b51131827 100644 --- a/src/output.c +++ b/src/output.c @@ -39,6 +39,12 @@ #include "io_types.h" +/* File descriptor output routine */ +void writeXMFheader(FILE** xmfFile, char* hdf5fileName, int N); +void writeXMFfooter(FILE* xmfFile); +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. * @@ -97,6 +103,8 @@ void writeAttribute(hid_t grp, char* name, enum DATA_TYPE type, void* data, int * @brief Writes a data array in given HDF5 group. * * @param grp The group in which to write. + * @param fileName The name of the file in which the data is written + * @param xmfFile The FILE used to write the XMF description * @param name The name of the array to write. * @param type The #DATA_TYPE of the array. * @param N The number of particles to write. @@ -108,7 +116,7 @@ void writeAttribute(hid_t grp, char* name, enum DATA_TYPE type, void* data, int * * Calls #error() if an error occurs. */ -void writeArrayBackEnd(hid_t grp, char* name, enum DATA_TYPE type, int N, int dim, char* part_c) +void writeArrayBackEnd(hid_t grp, char* fileName, FILE* xmfFile, char* name, enum DATA_TYPE type, int N, int dim, char* part_c) { hid_t h_data=0, h_err=0, h_space=0; void* temp = 0; @@ -177,6 +185,10 @@ void writeArrayBackEnd(hid_t grp, char* name, enum DATA_TYPE type, int N, int di sprintf(buf, "Error while reading data array '%s'\n", name); error(buf); } + + /* Write XMF description for this data set */ + writeXMFline(xmfFile, fileName, name, N, dim, type); + /* Free and close everything */ free(temp); @@ -188,6 +200,8 @@ void writeArrayBackEnd(hid_t grp, char* name, enum DATA_TYPE type, int N, int di * @brief A helper macro to call the readArrayBackEnd function more easily. * * @param grp The group in which to write. + * @param fileName The name of the file in which the data is written + * @param xmfFile The FILE used to write the XMF description * @param name The name of the array to write. * @param type The #DATA_TYPE of the array. * @param N The number of particles to write. @@ -195,10 +209,10 @@ void writeArrayBackEnd(hid_t grp, char* name, enum DATA_TYPE type, int N, int di * @param part_c A (char*) pointer on the first occurence of the field of interest in the parts array * */ -#define writeArray(grp, name, type, N, dim, part, field) writeArrayBackEnd(grp, name, type, N, dim, (char*)(&(part[0]).field)) +#define writeArray(grp, fileName, xmfFile, name, type, N, dim, part, field) writeArrayBackEnd(grp, fileName, xmfFile, name, type, N, dim, (char*)(&(part[0]).field)) /** - * @brief Writes an HDF5 output file (GADGET-3 type) + * @brief Writes an HDF5 output file (GADGET-3 type) with its XMF descriptor * * @param fileName The file to write. * @param dim The dimension of the volume written to the file. @@ -218,6 +232,9 @@ void write_output ( char* fileName, double dim[3], struct part *parts, int N, i { hid_t h_file=0, h_grp=0; int numParticles[6]={N,0}; + FILE* xmfFile; + + writeXMFheader(&xmfFile, fileName, N); /* Open file */ printf("write_output: Opening file '%s'.\n", fileName); @@ -263,25 +280,106 @@ void write_output ( char* fileName, double dim[3], struct part *parts, int N, i error( "Error while creating particle group.\n"); /* Write arrays */ - writeArray(h_grp, "Coordinates", DOUBLE, N, 3, parts, x); - writeArray(h_grp, "Velocity", FLOAT, N, 3, parts, v); - writeArray(h_grp, "Mass", FLOAT, N, 1, parts, mass); - writeArray(h_grp, "SmoothingLength", FLOAT, N, 1, parts, h); - writeArray(h_grp, "InternalEnergy", FLOAT, N, 1, parts, u); - writeArray(h_grp, "ParticleIDs", ULONGLONG, N, 1, parts, id); - writeArray(h_grp, "TimeStep", FLOAT, N, 1, parts, dt); - writeArray(h_grp, "Acceleration", FLOAT, N, 3, parts, a); - writeArray(h_grp, "Density", FLOAT, N, 1, parts, rho); + writeArray(h_grp, fileName, xmfFile, "Coordinates", DOUBLE, N, 3, parts, x); + writeArray(h_grp, fileName, xmfFile, "Velocity", FLOAT, N, 3, parts, v); + writeArray(h_grp, fileName, xmfFile, "Mass", 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); /* Close particle group */ H5Gclose(h_grp); + /* Write LXMF file descriptor */ + writeXMFfooter(xmfFile); + printf("write_output: Done writing particles...\n"); /* Close file */ H5Fclose(h_file); } + + +/* ------------------------------------------------------------------------------------------------ + * 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 Writes the begin of the XMF file + * + * @param xmfFile The file to write in. + * @param hdf5FileName The name of the HDF5 file associated to this XMF descriptor. + * @param N The number of particles to write. + * + * @todo Exploit the XML nature of the XMF format to write a proper XML writer and simplify all the XMF-related stuff. + */ +void writeXMFheader(FILE** xmfFile, char* hdf5FileName, int N) +{ + char buf[500]; + sprintf(buf, "%s.xmf", hdf5FileName); + *xmfFile = fopen(buf, "w"); + + /* Write header */ + 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 GridType=\"Collection\" CollectionType=\"Spatial\">\n"); + fprintf(*xmfFile, "<Time Type=\"Single\" Value=\"%f\"/>\n", 0.); + fprintf(*xmfFile, "<Grid Name=\"Gas\" GridType=\"Uniform\">\n"); + fprintf(*xmfFile, "<Topology TopologyType=\"Polyvertex\" Dimensions=\"%d\"/>\n", N); + + /* Write coordinates info */ + fprintf(*xmfFile, "<Geometry GeometryType=\"XYZ\">\n"); + fprintf(*xmfFile, "<DataItem Dimensions=\"%d 3\" NumberType=\"Double\" Precision=\"8\" Format=\"HDF\">%s:/PartType0/Coordinates</DataItem>\n", N, hdf5FileName); + fprintf(*xmfFile, "</Geometry>\n"); + +} + +/** + * @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 file */ + + fprintf(xmfFile, "</Grid>\n"); + fprintf(xmfFile, "</Grid>\n"); + fprintf(xmfFile, "</Domain>\n"); + fprintf(xmfFile, "</Xdmf>\n"); + + fclose(xmfFile); +} + + #endif /* HAVE_HDF5 */