From: Paul Bauer Date: Thu, 13 Jun 2019 09:52:36 +0000 (+0200) Subject: Read TPR file body in buffer X-Git-Url: http://biod.pnpi.spb.ru/gitweb/?a=commitdiff_plain;h=3836f52778fe36d11e511c6c55a31b6cfb2375fc;p=alexxy%2Fgromacs.git Read TPR file body in buffer For now only reads the buffer and uses it to write new files. Refs #2971 Change-Id: I77a18ca50e96486d688db8b0d7acdbedf29d613d --- diff --git a/src/gromacs/fileio/gmxfio_xdr.cpp b/src/gromacs/fileio/gmxfio_xdr.cpp index 25b64556f4..2fe2217f1b 100644 --- a/src/gromacs/fileio/gmxfio_xdr.cpp +++ b/src/gromacs/fileio/gmxfio_xdr.cpp @@ -70,6 +70,15 @@ void gmx_fio_setprecision(t_fileio *fio, gmx_bool bDouble) gmx_fio_unlock(fio); } +bool gmx_fio_is_double(t_fileio *fio) +{ + bool isDouble = false; + gmx_fio_lock(fio); + isDouble = fio->bDouble; + gmx_fio_unlock(fio); + return isDouble; +} + XDR *gmx_fio_getxdr(t_fileio *fio) { XDR *ret = nullptr; diff --git a/src/gromacs/fileio/gmxfio_xdr.h b/src/gromacs/fileio/gmxfio_xdr.h index 2ba7a3e4b7..313d145e68 100644 --- a/src/gromacs/fileio/gmxfio_xdr.h +++ b/src/gromacs/fileio/gmxfio_xdr.h @@ -50,6 +50,8 @@ struct t_fileio; void gmx_fio_setprecision(struct t_fileio *fio, gmx_bool bDouble); /* Select the floating point precision for reading and writing files */ +bool gmx_fio_is_double(struct t_fileio *fio); + XDR *gmx_fio_getxdr(struct t_fileio *fio); /* Return the file pointer itself */ diff --git a/src/gromacs/fileio/tpxio.cpp b/src/gromacs/fileio/tpxio.cpp index 67a1284714..61214f2ace 100644 --- a/src/gromacs/fileio/tpxio.cpp +++ b/src/gromacs/fileio/tpxio.cpp @@ -72,6 +72,7 @@ #include "gromacs/utility/fatalerror.h" #include "gromacs/utility/futil.h" #include "gromacs/utility/gmxassert.h" +#include "gromacs/utility/inmemoryserializer.h" #include "gromacs/utility/keyvaluetreebuilder.h" #include "gromacs/utility/keyvaluetreeserializer.h" #include "gromacs/utility/smalloc.h" @@ -126,6 +127,7 @@ enum tpxv tpxv_PullAverage, /**< Added possibility to output average pull force and position */ tpxv_GenericInternalParameters, /**< Added internal parameters for mdrun modules*/ tpxv_VSite2FD, /**< Added 2FD type virtual site */ + tpxv_AddSizeField, /**< Added field with information about the size of the serialized tpr file in bytes, excluding the header */ tpxv_Count /**< the total number of tpxv versions */ }; @@ -155,8 +157,10 @@ static const int tpx_version = tpxv_Count - 1; * * In particular, it must be increased when adding new elements to * ftupd, so that old code can read new .tpr files. + * + * Updated for added field that contains the number of bytes of the tpr body, excluding the header. */ -static const int tpx_generation = 26; +static const int tpx_generation = 27; /* This number should be the most recent backwards incompatible version * I.e., if this number is 9, we cannot read tpx version 9 with this code. @@ -630,7 +634,7 @@ static void do_fepvals(gmx::ISerializer *serializer, fepvals->lambda_neighbors + 1); if (fepvals->lambda_start_n < 0) { - fepvals->lambda_start_n = 0;; + fepvals->lambda_start_n = 0; } if (fepvals->lambda_stop_n >= fepvals->n_lambda) { @@ -2761,6 +2765,15 @@ static void do_tpxheader(gmx::FileIOXdrSerializer *serializer, serializer->doBool(&tpx->bF); serializer->doBool(&tpx->bBox); + if (tpx->fileVersion >= tpxv_AddSizeField && tpx->fileGeneration >= 27) + { + if (!serializer->reading()) + { + GMX_RELEASE_ASSERT(tpx->sizeOfTprBody != 0, "Not possible to write new file with zero TPR body size"); + } + serializer->doInt64(&tpx->sizeOfTprBody); + } + if ((tpx->fileGeneration > tpx_generation)) { /* This can only happen if TopOnlyOK=TRUE */ @@ -3021,6 +3034,11 @@ static TpxFileHeader populateTpxHeader(const t_state &state, return header; } +static void doTpxBodyBuffer(gmx::ISerializer *topologySerializer, gmx::ArrayRef buffer) +{ + topologySerializer->doCharArray(buffer.data(), buffer.size()); +} + /************************************************************ * * The following routines are the exported ones @@ -3043,28 +3061,92 @@ TpxFileHeader readTpxHeader(const char *fileName, bool canReadTopologyOnly) void write_tpx_state(const char *fn, const t_inputrec *ir, const t_state *state, const gmx_mtop_t *mtop) { - t_fileio *fio; + /* To write a state, we first need to write the state information to a buffer before + * we append the raw bytes to the file. For this, the header information needs to be + * populated before we write the main body because it has some information that is + * otherwise not available. + */ - fio = open_tpx(fn, "w"); + t_fileio *fio; TpxFileHeader tpx = populateTpxHeader(*state, ir, mtop); + gmx::InMemorySerializer tprBodySerializer; + + do_tpx_body(&tprBodySerializer, + &tpx, + const_cast(ir), + const_cast(state), nullptr, nullptr, + const_cast(mtop)); + + std::vector tprBody = tprBodySerializer.finishAndGetBuffer(); + tpx.sizeOfTprBody = tprBody.size(); + + fio = open_tpx(fn, "w"); gmx::FileIOXdrSerializer serializer(fio); do_tpxheader(&serializer, &tpx, fn, fio, ir == nullptr); - do_tpx_body(&serializer, - &tpx, - const_cast(ir), - const_cast(state), nullptr, nullptr, - const_cast(mtop)); + doTpxBodyBuffer(&serializer, tprBody); + close_tpx(fio); } +/*! \brief + * Wraps reading of header before and after introduction of size field. + * + * \param[in] tpx The file header. + * \param[in] serializer The Serialization interface used to read the TPR. + * \param[in] isDouble Whether the file is double or single precision. + * \param[out] ir Input rec to populate. + * \param[out] state State vectors to populate. + * \param[out] x Coordinates to populate if needed. + * \param[out] v Velocities to populate if needed. + * \param[out] mtop Global topology to populate. + * + * \returns Flag for pbc. + */ +static int do_tpx_body_dispatcher(TpxFileHeader *tpx, + gmx::ISerializer *serializer, + bool isDouble, + t_inputrec *ir, + t_state *state, + rvec *x, rvec *v, + gmx_mtop_t *mtop) +{ + int ePBC; + if (tpx->fileVersion >= tpxv_AddSizeField && tpx->fileGeneration >= 27) + { + std::vector tprBody(tpx->sizeOfTprBody); + doTpxBodyBuffer(serializer, tprBody); + gmx::InMemoryDeserializer tprBodyDeserializer(tprBody, isDouble); + + ePBC = do_tpx_body(&tprBodyDeserializer, + tpx, + ir, + state, + x, + v, + mtop); + } + else + { + ePBC = do_tpx_body(serializer, + tpx, + ir, + state, + x, + v, + mtop); + } + return ePBC; +} + + void read_tpx_state(const char *fn, t_inputrec *ir, t_state *state, gmx_mtop_t *mtop) { @@ -3078,13 +3160,8 @@ void read_tpx_state(const char *fn, fn, fio, ir == nullptr); - do_tpx_body(&serializer, - &tpx, - ir, - state, - nullptr, - nullptr, - mtop); + do_tpx_body_dispatcher(&tpx, &serializer, gmx_fio_is_double(fio), + ir, state, nullptr, nullptr, mtop); close_tpx(fio); } @@ -3104,9 +3181,8 @@ int read_tpx(const char *fn, fn, fio, ir == nullptr); - ePBC = do_tpx_body(&serializer, - &tpx, - ir, &state, x, v, mtop); + ePBC = do_tpx_body_dispatcher(&tpx, &serializer, gmx_fio_is_double(fio), + ir, &state, x, v, mtop); close_tpx(fio); if (mtop != nullptr && natoms != nullptr) { @@ -3116,7 +3192,6 @@ int read_tpx(const char *fn, { copy_mat(state.box, box); } - return ePBC; } @@ -3161,5 +3236,7 @@ void pr_tpxheader(FILE *fp, int indent, const char *title, const TpxFileHeader * fprintf(fp, "natoms = %d\n", sh->natoms); pr_indent(fp, indent); fprintf(fp, "lambda = %e\n", sh->lambda); + pr_indent(fp, indent); + fprintf(fp, "buffer size = %" PRId64 "\n", sh->sizeOfTprBody); } } diff --git a/src/gromacs/fileio/tpxio.h b/src/gromacs/fileio/tpxio.h index eab992f7bb..4a08730c0a 100644 --- a/src/gromacs/fileio/tpxio.h +++ b/src/gromacs/fileio/tpxio.h @@ -82,6 +82,8 @@ struct TpxFileHeader vary through a simulation, and cannot be completely described though a single lambda variable, or even a single state index. Eventually, should probably be a vector. MRS*/ + //! Size of the TPR body in chars (equal to number of bytes) during I/O. + int64_t sizeOfTprBody = 0; //! File version. int fileVersion = 0; //! File generation.