/*******************************************************************************
* This file is part of SWIFT.
* Copyright (c) 2017 Matthieu Schaller (schaller@strw.leidenuniv.nl).
* Peter W. Draper (p.w.draper@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 .
*
******************************************************************************/
/* Config parameters. */
#include
/* Some standard headers. */
#include
#include
#include
/* This object's header. */
#include "xmf.h"
/* Local headers. */
#include "common_io.h"
#include "error.h"
/**
* @brief Return the basename of an HDF5 path.
*
* Need basename as XML paths are relative to the container, and XMF file is
* written with the same baseName as the HDF5 snapshots.
*
* Note since the XMF file is written in the subdir (if it exists) we don't
* want that as part of the name. But for distributed snapshots we need that
* that directory.
*
* @param hdfFileName The full path to the HDF5 file
* @param distributed Are we playing with a distributed snapshot?
* @return the basename part of hdfFileName.
*/
static const char* xmf_basename(const char* hdfFileName,
const int distributed) {
int pos_last_slash = strlen(hdfFileName) - 1;
/* Find last slash */
for (/* */; pos_last_slash >= 0; --pos_last_slash)
if (hdfFileName[pos_last_slash] == '/') break;
if (distributed) {
/* Find one-before-last slash */
for (pos_last_slash--; pos_last_slash >= 0; --pos_last_slash)
if (hdfFileName[pos_last_slash] == '/') break;
}
static char buffer[FILENAME_BUFFER_SIZE];
strcpy(buffer, &hdfFileName[pos_last_slash + 1]);
return buffer;
}
/**
* @brief Prepare the XMF file corresponding to a snapshot.
*
* @param fileName The name of the file.
*/
FILE* xmf_prepare_file(const char* fileName) {
char buffer[1024];
char tempFileName[FILENAME_BUFFER_SIZE];
snprintf(tempFileName, FILENAME_BUFFER_SIZE, "%s.temp", fileName);
FILE* xmfFile = fopen(fileName, "r");
FILE* tempFile = fopen(tempFileName, "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(fileName, "w");
tempFile = fopen(tempFileName, "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(tempFileName);
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.
*
* @param fileName The name of the file.
*/
void xmf_create_file(const char* fileName) {
FILE* xmfFile = fopen(fileName, "w");
if (xmfFile == NULL) error("Unable to create XMF file.");
fprintf(xmfFile, " \n");
fprintf(xmfFile, " \n");
fprintf(
xmfFile,
"\n");
fprintf(xmfFile, "\n");
fprintf(xmfFile,
"\n\n");
fprintf(xmfFile, "\n");
fprintf(xmfFile, "\n");
fprintf(xmfFile, "\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 hdfFileName The name of the HDF5 file corresponding to this output.
* @param time The current simulation time.
*/
void xmf_write_outputheader(FILE* xmfFile, const char* hdfFileName,
float time) {
/* Write end of file */
fprintf(xmfFile, "\n", hdfFileName);
fprintf(xmfFile,
"\n");
fprintf(xmfFile, " \n",
output, time);
fprintf(xmfFile, "\n \n");
fprintf(xmfFile, "\n");
fprintf(xmfFile, "\n");
fclose(xmfFile);
}
/**
* @brief Writes the header of an XMF group for a given particle type.
*
* @param xmfFile The file to write to.
* @param hdfFileName The name of the corresponding HDF5 file.
* @param N The number of particles to write.
* @param ptype The particle type we are writing.
*/
void xmf_write_groupheader(FILE* xmfFile, const char* hdfFileName,
const int distributed, size_t N,
enum part_type ptype) {
fprintf(xmfFile, "\n\n",
part_type_names[ptype]);
fprintf(xmfFile,
"\n", N);
fprintf(xmfFile, "\n");
fprintf(xmfFile,
"%s:/PartType%d/Coordinates\n",
N, xmf_basename(hdfFileName, distributed), (int)ptype);
fprintf(xmfFile,
"\n \n",
part_type_names[ptype]);
}
/**
* @brief Writes the footer of an XMF group for a given particle type.
*
* @param xmfFile The file to write to.
* @param ptype The particle type we are writing.
*/
void xmf_write_groupfooter(FILE* xmfFile, enum part_type ptype) {
fprintf(xmfFile, " \n",
part_type_names[ptype]);
}
/**
* @brief Returns the precision of a given dataset type
*/
int xmf_precision(enum IO_DATA_TYPE type) {
switch (type) {
case INT:
case FLOAT:
return 4;
break;
case DOUBLE:
return 8;
break;
case ULONGLONG:
case LONGLONG:
return 8;
break;
case UINT8:
case CHAR:
return 1;
break;
default:
error("Unsupported type");
}
return 0;
}
/**
* @brief Returns the Xdmf type name of a given dataset type
*/
const char* xmf_type(enum IO_DATA_TYPE type) {
switch (type) {
case FLOAT:
case DOUBLE:
return "Float";
break;
case INT:
case ULONGLONG:
case LONGLONG:
return "Int";
break;
case UINT8:
case CHAR:
return "Char";
break;
default:
error("Unsupported type");
}
return "";
}
/**
* @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 partTypeGroupName The name of the group containing the particles in
* the HDF5 file.
* @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 xmf_write_line(FILE* xmfFile, const char* fileName, const int distributed,
const char* partTypeGroupName, const char* name, size_t N,
int dim, enum IO_DATA_TYPE type) {
fprintf(xmfFile,
"\n",
name, dim == 1 ? "Scalar" : "Vector");
if (dim == 1)
fprintf(xmfFile,
"%s:%s/%s\n",
N, xmf_type(type), xmf_precision(type),
xmf_basename(fileName, distributed), partTypeGroupName, name);
else
fprintf(xmfFile,
"%s:%s/%s\n",
N, dim, xmf_type(type), xmf_precision(type),
xmf_basename(fileName, distributed), partTypeGroupName, name);
fprintf(xmfFile, "\n");
}