From: Paul Bauer Date: Fri, 14 Jun 2019 09:42:28 +0000 (+0200) Subject: Change MPI setup to communicate TPR as buffer X-Git-Url: http://biod.pnpi.spb.ru/gitweb/?a=commitdiff_plain;h=6983f2be5af4c8a0839a1b26a1f4862241c672f0;p=alexxy%2Fgromacs.git Change MPI setup to communicate TPR as buffer Changed the initial setup of nodes to communicate the full tpr file buffer instead of using the individual calls for the fields. Now non-master nodes receive the inputrec and mtop and populate them themselves. Refs #2971 Change-Id: Id4f3739a978ca507dacc45c78a8a75368cfe86fd --- diff --git a/src/gromacs/fileio/tpxio.cpp b/src/gromacs/fileio/tpxio.cpp index 302af1dc5b..33279bd528 100644 --- a/src/gromacs/fileio/tpxio.cpp +++ b/src/gromacs/fileio/tpxio.cpp @@ -2651,7 +2651,6 @@ static void do_tpxheader(gmx::FileIOXdrSerializer *serializer, t_fileio *fio, bool TopOnlyOK) { - gmx_bool bDouble; int precision; int idum = 0; real rdum = 0; @@ -2670,24 +2669,28 @@ static void do_tpxheader(gmx::FileIOXdrSerializer *serializer, " Make a new one with grompp or use a gro or pdb file, if possible", filename); } + // We need to know the precision used to write the TPR file, to match it + // to the precision of the currently running binary. If the precisions match + // there is no problem, but mismatching precision needs to be accounted for + // by reading into temporary variables of the correct precision instead + // of the desired target datastructures. serializer->doInt(&precision); - bDouble = (precision == sizeof(double)); - if ((precision != sizeof(float)) && !bDouble) + tpx->isDouble = (precision == sizeof(double)); + if ((precision != sizeof(float)) && !tpx->isDouble) { gmx_fatal(FARGS, "Unknown precision in file %s: real is %d bytes " "instead of %zu or %zu", filename, precision, sizeof(float), sizeof(double)); } - gmx_fio_setprecision(fio, bDouble); + gmx_fio_setprecision(fio, tpx->isDouble); fprintf(stderr, "Reading file %s, %s (%s precision)\n", - filename, buf.c_str(), bDouble ? "double" : "single"); + filename, buf.c_str(), tpx->isDouble ? "double" : "single"); } else { buf = gmx::formatString("VERSION %s", gmx_version()); serializer->doString(&buf); - bDouble = (precision == sizeof(double)); - gmx_fio_setprecision(fio, bDouble); + gmx_fio_setprecision(fio, tpx->isDouble); serializer->doInt(&precision); fileTag = gmx::formatString("%s", tpx_tag); } @@ -2783,6 +2786,21 @@ static void do_tpxheader(gmx::FileIOXdrSerializer *serializer, #define do_test(serializer, b, p) if ((serializer)->reading() && ((p) != nullptr) && !(b)) gmx_fatal(FARGS, "No %s in input file",#p) +/*! \brief + * Process the first part of the TPR into the state datastructure. + * + * Due to the structure of the legacy code, it is necessary + * to split up the state reading into two parts, with the + * box and legacy temperature coupling processed before the + * topology datastructures. + * + * See the documentation for do_tpx_body for the correct order of + * the operations for reading a tpr file. + * + * \param[in] serializer Abstract serializer used to read/write data. + * \param[in] tpx The file header data. + * \param[in, out] state Global state data. + */ static void do_tpx_state_first(gmx::ISerializer *serializer, TpxFileHeader *tpx, t_state *state) @@ -2827,6 +2845,16 @@ static void do_tpx_state_first(gmx::ISerializer *serializer, } } +/*! \brief + * Process global topology data. + * + * See the documentation for do_tpx_body for the correct order of + * the operations for reading a tpr file. + * + * \param[in] serializer Abstract serializer used to read/write data. + * \param[in] tpx The file header data. + * \param[in,out] mtop Global topology. + */ static void do_tpx_mtop(gmx::ISerializer *serializer, TpxFileHeader *tpx, gmx_mtop_t *mtop) @@ -2847,7 +2875,20 @@ static void do_tpx_mtop(gmx::ISerializer *serializer, } } } - +/*! \brief + * Process coordinate vectors for state data. + * + * Main part of state gets processed here. + * + * See the documentation for do_tpx_body for the correct order of + * the operations for reading a tpr file. + * + * \param[in] serializer Abstract serializer used to read/write data. + * \param[in] tpx The file header data. + * \param[in,out] state Global state data. + * \param[in,out] x Individual coordinates for processing, deprecated. + * \param[in,out] v Individual velocities for processing, deprecated. + */ static void do_tpx_state_second(gmx::ISerializer *serializer, TpxFileHeader *tpx, t_state *state, @@ -2922,7 +2963,16 @@ static void do_tpx_state_second(gmx::ISerializer *serializer, serializer->doRvecArray(as_rvec_array(dummyForces.data()), tpx->natoms); } } - +/*! \brief + * Process simulation parameters. + * + * See the documentation for do_tpx_body for the correct order of + * the operations for reading a tpr file. + * + * \param[in] serializer Abstract serializer used to read/write data. + * \param[in] tpx The file header data. + * \param[in,out] ir Datastructure with simulation parameters. + */ static int do_tpx_ir(gmx::ISerializer *serializer, TpxFileHeader *tpx, t_inputrec *ir) @@ -2976,7 +3026,10 @@ static int do_tpx_ir(gmx::ISerializer *serializer, /*! \brief * Correct and finalize read information. * - * Moved here from previous code because this is done after reading files. + * If \p state is nullptr, skip the parts dependent on it. + * + * See the documentation for do_tpx_body for the correct order of + * the operations for reading a tpr file. * * \param[in] tpx The file header used to check version numbers. * \param[out] ir Input rec that needs correction. @@ -2988,13 +3041,13 @@ static void do_tpx_finalize(TpxFileHeader *tpx, t_state *state, gmx_mtop_t *mtop) { - if (tpx->fileVersion < 51) + if (tpx->fileVersion < 51 && state) { set_box_rel(ir, state); } if (tpx->bIr && ir) { - if (state->ngtc == 0) + if (state && state->ngtc == 0) { /* Reading old version without tcoupl state data: set it */ init_gtc_state(state, ir->opts.ngtc, 0, ir->opts.nhchainlength); @@ -3016,6 +3069,26 @@ static void do_tpx_finalize(TpxFileHeader *tpx, } } +/*! \brief + * Process TPR data for file reading/writing. + * + * The TPR file gets processed in in four stages due to the organization + * of the data within it. + * + * First, state data for the box is processed in do_tpx_state_first. + * This is followed by processing the topology in do_tpx_mtop. + * Coordinate and velocity vectors are handled next in do_tpx_state_second. + * The last file information processed is the collection of simulation parameters in do_tpx_ir. + * When reading, a final processing step is undertaken at the end. + * + * \param[in] serializer Abstract serializer used to read/write data. + * \param[in] tpx The file header data. + * \param[in,out] ir Datastructures with simulation parameters. + * \param[in,out] state Global state data. + * \param[in,out] x Individual coordinates for processing, deprecated. + * \param[in,out] v Individual velocities for processing, deprecated. + * \param[in,out] mtop Global topology. + */ static int do_tpx_body(gmx::ISerializer *serializer, TpxFileHeader *tpx, t_inputrec *ir, @@ -3024,9 +3097,15 @@ static int do_tpx_body(gmx::ISerializer *serializer, rvec *v, gmx_mtop_t *mtop) { - do_tpx_state_first(serializer, tpx, state); + if (state) + { + do_tpx_state_first(serializer, tpx, state); + } do_tpx_mtop(serializer, tpx, mtop); - do_tpx_state_second(serializer, tpx, state, x, v); + if (state) + { + do_tpx_state_second(serializer, tpx, state, x, v); + } int ePBC = do_tpx_ir(serializer, tpx, ir); if (serializer->reading()) { @@ -3035,6 +3114,22 @@ static int do_tpx_body(gmx::ISerializer *serializer, return ePBC; } +/*! \brief + * Overload for do_tpx_body that defaults to state vectors being nullptr. + * + * \param[in] serializer Abstract serializer used to read/write data. + * \param[in] tpx The file header data. + * \param[in,out] ir Datastructures with simulation parameters. + * \param[in,out] mtop Global topology. + */ +static int do_tpx_body(gmx::ISerializer *serializer, + TpxFileHeader *tpx, + t_inputrec *ir, + gmx_mtop_t *mtop) +{ + return do_tpx_body(serializer, tpx, ir, nullptr, nullptr, nullptr, mtop); +} + static t_fileio *open_tpx(const char *fn, const char *mode) { return gmx_fio_open(fn, mode); @@ -3073,13 +3168,100 @@ static TpxFileHeader populateTpxHeader(const t_state &state, header.bBox = true; header.fileVersion = tpx_version; header.fileGeneration = tpx_generation; + header.isDouble = (sizeof(real) == sizeof(double)); return header; } -static void doTpxBodyBuffer(gmx::ISerializer *topologySerializer, gmx::ArrayRef buffer) +/*! \brief + * Process the body of a TPR file as char buffer. + * + * Reads/writes the information in \p buffer from/to the \p serializer + * provided to the function. Does not interact with the actual + * TPR datastructures but with an in memory representation of the + * data, so that this data can be efficiently read or written from/to + * an original source. + * + * \param[in] serializer The abstract serializer used for reading or writing + * the information in \p buffer. + * \param[in,out] buffer Information from TPR file as char buffer. + */ +static void doTpxBodyBuffer(gmx::ISerializer *serializer, gmx::ArrayRef buffer) +{ + serializer->doCharArray(buffer.data(), buffer.size()); +} + +/*! \brief + * Populates simulation datastructures. + * + * Here the information from the serialization interface \p serializer + * is used to first populate the datastructures containing the simulation + * information. Depending on the version found in the header \p tpx, + * this is done using the new reading of the data as one block from disk, + * followed by complete deserialization of the information read from there. + * Otherwise, the datastructures are populated as before one by one from disk. + * The second version is the default for the legacy tools that read the + * coordinates and velocities separate from the state. + * + * After reading in the data, a separate buffer is populated from them + * containing only \p ir and \p mtop that can be communicated directly + * to nodes needing the information to set up a simulation. + * + * \param[in] tpx The file header. + * \param[in] serializer The Serialization interface used to read the TPR. + * \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 Partial de-serialized TPR used for communication to nodes. + */ +static PartialDeserializedTprFile readTpxBody(TpxFileHeader *tpx, + gmx::ISerializer *serializer, + t_inputrec *ir, + t_state *state, + rvec *x, rvec *v, + gmx_mtop_t *mtop) { - topologySerializer->doCharArray(buffer.data(), buffer.size()); + PartialDeserializedTprFile partialDeserializedTpr; + if (tpx->fileVersion >= tpxv_AddSizeField && tpx->fileGeneration >= 27) + { + partialDeserializedTpr.body.resize(tpx->sizeOfTprBody); + partialDeserializedTpr.header = *tpx; + doTpxBodyBuffer(serializer, partialDeserializedTpr.body); + + partialDeserializedTpr.ePBC = + completeTprDeserialization(&partialDeserializedTpr, + ir, + state, + x, v, + mtop); + } + else + { + partialDeserializedTpr.ePBC = + do_tpx_body(serializer, + tpx, + ir, + state, + x, + v, + mtop); + } + // Update header to system info for communication to nodes. + // As we only need to communicate the inputrec and mtop to other nodes, + // we prepare a new char buffer with the information we have already read + // in on master. + partialDeserializedTpr.header = populateTpxHeader(*state, ir, mtop); + gmx::InMemorySerializer tprBodySerializer; + do_tpx_body(&tprBodySerializer, + &partialDeserializedTpr.header, + ir, + mtop); + partialDeserializedTpr.body = tprBodySerializer.finishAndGetBuffer(); + + return partialDeserializedTpr; } /************************************************************ @@ -3139,73 +3321,54 @@ void write_tpx_state(const char *fn, 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 completeTprDeserialization(PartialDeserializedTprFile *partialDeserializedTpr, + 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; + gmx::InMemoryDeserializer tprBodyDeserializer(partialDeserializedTpr->body, + partialDeserializedTpr->header.isDouble); + return do_tpx_body(&tprBodyDeserializer, + &partialDeserializedTpr->header, + ir, + state, + x, + v, + mtop); } - -void read_tpx_state(const char *fn, - t_inputrec *ir, t_state *state, gmx_mtop_t *mtop) +int completeTprDeserialization(PartialDeserializedTprFile *partialDeserializedTpr, + t_inputrec *ir, + gmx_mtop_t *mtop) { - t_fileio *fio; + return completeTprDeserialization(partialDeserializedTpr, ir, nullptr, nullptr, nullptr, mtop); +} - TpxFileHeader tpx; +PartialDeserializedTprFile read_tpx_state(const char *fn, + t_inputrec *ir, + t_state *state, + gmx_mtop_t *mtop) +{ + t_fileio *fio; fio = open_tpx(fn, "r"); - gmx::FileIOXdrSerializer serializer(fio); + gmx::FileIOXdrSerializer serializer(fio); + PartialDeserializedTprFile partialDeserializedTpr; do_tpxheader(&serializer, - &tpx, + &partialDeserializedTpr.header, fn, fio, ir == nullptr); - do_tpx_body_dispatcher(&tpx, &serializer, gmx_fio_is_double(fio), - ir, state, nullptr, nullptr, mtop); + partialDeserializedTpr = readTpxBody(&partialDeserializedTpr.header, + &serializer, + ir, + state, + nullptr, + nullptr, + mtop); close_tpx(fio); + return partialDeserializedTpr; } int read_tpx(const char *fn, @@ -3214,7 +3377,6 @@ int read_tpx(const char *fn, { t_fileio *fio; t_state state; - int ePBC; TpxFileHeader tpx; fio = open_tpx(fn, "r"); @@ -3224,8 +3386,9 @@ int read_tpx(const char *fn, fn, fio, ir == nullptr); - ePBC = do_tpx_body_dispatcher(&tpx, &serializer, gmx_fio_is_double(fio), - ir, &state, x, v, mtop); + PartialDeserializedTprFile partialDeserializedTpr + = readTpxBody(&tpx, &serializer, + ir, &state, x, v, mtop); close_tpx(fio); if (mtop != nullptr && natoms != nullptr) { @@ -3235,7 +3398,7 @@ int read_tpx(const char *fn, { copy_mat(state.box, box); } - return ePBC; + return partialDeserializedTpr.ePBC; } int read_tpx_top(const char *fn, diff --git a/src/gromacs/fileio/tpxio.h b/src/gromacs/fileio/tpxio.h index 4a08730c0a..8d4b008fb0 100644 --- a/src/gromacs/fileio/tpxio.h +++ b/src/gromacs/fileio/tpxio.h @@ -39,7 +39,10 @@ #include +#include + #include "gromacs/math/vectypes.h" +#include "gromacs/utility/arrayref.h" #include "gromacs/utility/basedefinitions.h" #include "gromacs/utility/real.h" @@ -88,6 +91,25 @@ struct TpxFileHeader int fileVersion = 0; //! File generation. int fileGeneration = 0; + //! If the tpr file was written in double precision. + bool isDouble = false; +}; + +/*! \brief + * Contains the partly deserialized contents of a TPR file. + * + * Convenience struct that holds a fully deserialized TPR file header, + * and the body of the TPR file as char buffer that can be deserialized + * independently from the header. + */ +struct PartialDeserializedTprFile +{ + //! The file header. + TpxFileHeader header; + //! The file body. + std::vector body; + //! Flag for PBC needed by legacy implementation. + int ePBC = -1; }; /* @@ -118,9 +140,51 @@ void write_tpx_state(const char *fn, /* Write a file, and close it again. */ -void read_tpx_state(const char *fn, - t_inputrec *ir, t_state *state, - gmx_mtop_t *mtop); +/*! \brief + * Complete deserialization of TPR file into the individual data structures. + * + * If \p state is nullptr, only populates ir and mtop. + * + * \param[in] partialDeserializedTpr Struct with header and char buffer needed to populate system. + * \param[out] ir Input rec to populate. + * \param[out] state System state variables to populate. + * \param[out] x Separate vector for coordinates, deprecated. + * \param[out] v Separate vector for velocities, deprecated. + * \param[out] mtop Global topology to populate. + * + * \returns PBC flag. + */ +int completeTprDeserialization(PartialDeserializedTprFile *partialDeserializedTpr, + t_inputrec *ir, + t_state *state, + rvec *x, + rvec *v, + gmx_mtop_t *mtop); + +//! Overload for final TPR deserialization when not using state vectors. +int completeTprDeserialization(PartialDeserializedTprFile *partialDeserializedTpr, + t_inputrec *ir, + gmx_mtop_t *mtop); + +/*! \brief + * Read a file to set up a simulation and close it after reading. + * + * Main function used to initialize simulations. Reads the input \p fn + * to populate the \p state, \p ir and \p mtop needed to run a simulations. + * + * This function returns the partial deserialized TPR file + * that can then be communicated to set up non-master nodes to run simulations. + * + * \param[in] fn Input file name. + * \param[out] ir Input parameters to be set, or nullptr. + * \param[out] state State variables for the simulation. + * \param[out] mtop Global simulation topolgy. + * \returns Struct with header and body in char vector. + */ +PartialDeserializedTprFile read_tpx_state(const char *fn, + t_inputrec *ir, + t_state *state, + gmx_mtop_t *mtop); /*! \brief * Read a file and close it again. diff --git a/src/gromacs/mdlib/broadcaststructs.cpp b/src/gromacs/mdlib/broadcaststructs.cpp index 7d67cf00ff..a62979aa79 100644 --- a/src/gromacs/mdlib/broadcaststructs.cpp +++ b/src/gromacs/mdlib/broadcaststructs.cpp @@ -39,245 +39,10 @@ #include "broadcaststructs.h" -#include - -#include - +#include "gromacs/fileio/tpxio.h" #include "gromacs/gmxlib/network.h" -#include "gromacs/math/vec.h" -#include "gromacs/mdlib/tgroup.h" -#include "gromacs/mdtypes/awh_params.h" #include "gromacs/mdtypes/commrec.h" -#include "gromacs/mdtypes/inputrec.h" -#include "gromacs/mdtypes/md_enums.h" -#include "gromacs/mdtypes/pull_params.h" #include "gromacs/mdtypes/state.h" -#include "gromacs/topology/mtop_util.h" -#include "gromacs/topology/symtab.h" -#include "gromacs/topology/topology.h" -#include "gromacs/utility/fatalerror.h" -#include "gromacs/utility/inmemoryserializer.h" -#include "gromacs/utility/keyvaluetree.h" -#include "gromacs/utility/keyvaluetreeserializer.h" -#include "gromacs/utility/smalloc.h" - -static void bc_cstring(const t_commrec *cr, char **s) -{ - int size = 0; - - if (MASTER(cr) && *s != nullptr) - { - /* Size of the char buffer is string length + 1 for '\0' */ - size = strlen(*s) + 1; - } - block_bc(cr, size); - if (size > 0) - { - if (!MASTER(cr)) - { - srenew(*s, size); - } - nblock_bc(cr, size, *s); - } - else if (!MASTER(cr) && *s != nullptr) - { - sfree(*s); - *s = nullptr; - } -} - -static void bc_string(const t_commrec *cr, t_symtab *symtab, char ***s) -{ - int handle; - - if (MASTER(cr)) - { - handle = lookup_symtab(symtab, *s); - } - block_bc(cr, handle); - if (!MASTER(cr)) - { - *s = get_symtab_handle(symtab, handle); - } -} - -static void bc_strings(const t_commrec *cr, t_symtab *symtab, int nr, char ****nm) -{ - int i; - int *handle; - - snew(handle, nr); - if (MASTER(cr)) - { - for (i = 0; (i < nr); i++) - { - handle[i] = lookup_symtab(symtab, (*nm)[i]); - } - } - nblock_bc(cr, nr, handle); - - if (!MASTER(cr)) - { - snew_bc(cr, *nm, nr); - for (i = 0; (i < nr); i++) - { - (*nm)[i] = get_symtab_handle(symtab, handle[i]); - } - } - sfree(handle); -} - -static void bc_strings_container(const t_commrec *cr, - t_symtab *symtab, - int nr, - std::vector *nm) -{ - std::vector handle; - if (MASTER(cr)) - { - for (int i = 0; (i < nr); i++) - { - handle.emplace_back(lookup_symtab(symtab, (*nm)[i])); - } - } - block_bc(cr, nr); - nblock_abc(cr, nr, &handle); - - if (!MASTER(cr)) - { - nm->resize(nr); - for (int i = 0; (i < nr); i++) - { - (*nm)[i] = get_symtab_handle(symtab, handle[i]); - } - } -} - -static void bc_strings_resinfo(const t_commrec *cr, t_symtab *symtab, - int nr, t_resinfo *resinfo) -{ - int i; - int *handle; - - snew(handle, nr); - if (MASTER(cr)) - { - for (i = 0; (i < nr); i++) - { - handle[i] = lookup_symtab(symtab, resinfo[i].name); - } - } - nblock_bc(cr, nr, handle); - - if (!MASTER(cr)) - { - for (i = 0; (i < nr); i++) - { - resinfo[i].name = get_symtab_handle(symtab, handle[i]); - } - } - sfree(handle); -} - -static void bc_symtab(const t_commrec *cr, t_symtab *symtab) -{ - int i, nr, len; - t_symbuf *symbuf; - - block_bc(cr, symtab->nr); - nr = symtab->nr; - snew_bc(cr, symtab->symbuf, 1); - symbuf = symtab->symbuf; - symbuf->bufsize = nr; - snew_bc(cr, symbuf->buf, nr); - for (i = 0; i < nr; i++) - { - if (MASTER(cr)) - { - len = strlen(symbuf->buf[i]) + 1; - } - block_bc(cr, len); - snew_bc(cr, symbuf->buf[i], len); - nblock_bc(cr, len, symbuf->buf[i]); - } -} - -static void bc_block(const t_commrec *cr, t_block *block) -{ - block_bc(cr, block->nr); - snew_bc(cr, block->index, block->nr+1); - nblock_bc(cr, block->nr+1, block->index); -} - -static void bc_blocka(const t_commrec *cr, t_blocka *block) -{ - block_bc(cr, block->nr); - snew_bc(cr, block->index, block->nr+1); - nblock_bc(cr, block->nr+1, block->index); - block_bc(cr, block->nra); - if (block->nra) - { - snew_bc(cr, block->a, block->nra); - nblock_bc(cr, block->nra, block->a); - } -} - -static void bc_grps(const t_commrec *cr, gmx::ArrayRef grps) -{ - for (auto &group : grps) - { - int size = group.size(); - block_bc(cr, size); - nblock_abc(cr, size, &group); - } -} - -static void bc_atoms(const t_commrec *cr, t_symtab *symtab, t_atoms *atoms) -{ - block_bc(cr, atoms->nr); - snew_bc(cr, atoms->atom, atoms->nr); - nblock_bc(cr, atoms->nr, atoms->atom); - bc_strings(cr, symtab, atoms->nr, &atoms->atomname); - block_bc(cr, atoms->nres); - snew_bc(cr, atoms->resinfo, atoms->nres); - nblock_bc(cr, atoms->nres, atoms->resinfo); - bc_strings_resinfo(cr, symtab, atoms->nres, atoms->resinfo); - /* QMMM requires atomtypes to be known on all nodes as well */ - bc_strings(cr, symtab, atoms->nr, &atoms->atomtype); - bc_strings(cr, symtab, atoms->nr, &atoms->atomtypeB); -} - -static void bc_groups(const t_commrec *cr, t_symtab *symtab, - int natoms, SimulationGroups *groups) -{ - int n; - - bc_grps(cr, groups->groups); - bc_strings_container(cr, symtab, groups->groupNames.size(), &groups->groupNames); - for (auto group : gmx::keysOf(groups->groups)) - { - if (MASTER(cr)) - { - if (!groups->groupNumbers[group].empty()) - { - n = natoms; - } - else - { - n = 0; - } - } - block_bc(cr, n); - if (n != 0) - { - nblock_abc(cr, n, &groups->groupNumbers[group]); - } - } - if (debug) - { - fprintf(debug, "after bc_groups\n"); - } -} template static void bcastPaddedRVecVector(const t_commrec *cr, gmx::PaddedVector *v, int numAtoms) @@ -327,562 +92,43 @@ void broadcastStateWithoutDynamics(const t_commrec *cr, t_state *state) } } -static void bc_ilists(const t_commrec *cr, InteractionLists *ilist) -{ - int ftype; - - /* Here we only communicate the non-zero length ilists */ - if (MASTER(cr)) - { - for (ftype = 0; ftype < F_NRE; ftype++) - { - if ((*ilist)[ftype].size() > 0) - { - block_bc(cr, ftype); - int nr = (*ilist)[ftype].size(); - block_bc(cr, nr); - nblock_bc(cr, nr, (*ilist)[ftype].iatoms.data()); - } - } - ftype = -1; - block_bc(cr, ftype); - } - else - { - for (ftype = 0; ftype < F_NRE; ftype++) - { - (*ilist)[ftype].iatoms.clear(); - } - do - { - block_bc(cr, ftype); - if (ftype >= 0) - { - int nr; - block_bc(cr, nr); - (*ilist)[ftype].iatoms.resize(nr); - nblock_bc(cr, nr, (*ilist)[ftype].iatoms.data()); - } - } - while (ftype >= 0); - } - - if (debug) - { - fprintf(debug, "after bc_ilists\n"); - } -} - -static void bc_cmap(const t_commrec *cr, gmx_cmap_t *cmap_grid) -{ - int ngrid = cmap_grid->cmapdata.size(); - block_bc(cr, ngrid); - block_bc(cr, cmap_grid->grid_spacing); - - int nelem = cmap_grid->grid_spacing * cmap_grid->grid_spacing; - - if (ngrid > 0) - { - if (!MASTER(cr)) - { - cmap_grid->cmapdata.resize(ngrid); - } - - for (int i = 0; i < ngrid; i++) - { - nblock_abc(cr, 4*nelem, &cmap_grid->cmapdata[i].cmap); - } - } -} - -static void bc_ffparams(const t_commrec *cr, gmx_ffparams_t *ffp) -{ - int numTypes = ffp->numTypes(); - block_bc(cr, numTypes); - block_bc(cr, ffp->atnr); - nblock_abc(cr, numTypes, &ffp->functype); - nblock_abc(cr, numTypes, &ffp->iparams); - block_bc(cr, ffp->reppow); - block_bc(cr, ffp->fudgeQQ); - bc_cmap(cr, &ffp->cmap_grid); -} - -static void bc_grpopts(const t_commrec *cr, t_grpopts *g) -{ - int i, n; - - block_bc(cr, g->ngtc); - block_bc(cr, g->ngacc); - block_bc(cr, g->ngfrz); - block_bc(cr, g->ngener); - snew_bc(cr, g->nrdf, g->ngtc); - snew_bc(cr, g->tau_t, g->ngtc); - snew_bc(cr, g->ref_t, g->ngtc); - snew_bc(cr, g->acc, g->ngacc); - snew_bc(cr, g->nFreeze, g->ngfrz); - snew_bc(cr, g->egp_flags, g->ngener*g->ngener); - - nblock_bc(cr, g->ngtc, g->nrdf); - nblock_bc(cr, g->ngtc, g->tau_t); - nblock_bc(cr, g->ngtc, g->ref_t); - nblock_bc(cr, g->ngacc, g->acc); - nblock_bc(cr, g->ngfrz, g->nFreeze); - nblock_bc(cr, g->ngener*g->ngener, g->egp_flags); - snew_bc(cr, g->annealing, g->ngtc); - snew_bc(cr, g->anneal_npoints, g->ngtc); - snew_bc(cr, g->anneal_time, g->ngtc); - snew_bc(cr, g->anneal_temp, g->ngtc); - nblock_bc(cr, g->ngtc, g->annealing); - nblock_bc(cr, g->ngtc, g->anneal_npoints); - for (i = 0; (i < g->ngtc); i++) - { - n = g->anneal_npoints[i]; - if (n > 0) - { - snew_bc(cr, g->anneal_time[i], n); - snew_bc(cr, g->anneal_temp[i], n); - nblock_bc(cr, n, g->anneal_time[i]); - nblock_bc(cr, n, g->anneal_temp[i]); - } - } - - /* QMMM stuff, see inputrec */ - block_bc(cr, g->ngQM); - snew_bc(cr, g->QMmethod, g->ngQM); - snew_bc(cr, g->QMbasis, g->ngQM); - snew_bc(cr, g->QMcharge, g->ngQM); - snew_bc(cr, g->QMmult, g->ngQM); - snew_bc(cr, g->bSH, g->ngQM); - snew_bc(cr, g->CASorbitals, g->ngQM); - snew_bc(cr, g->CASelectrons, g->ngQM); - snew_bc(cr, g->SAon, g->ngQM); - snew_bc(cr, g->SAoff, g->ngQM); - snew_bc(cr, g->SAsteps, g->ngQM); - - if (g->ngQM) - { - nblock_bc(cr, g->ngQM, g->QMmethod); - nblock_bc(cr, g->ngQM, g->QMbasis); - nblock_bc(cr, g->ngQM, g->QMcharge); - nblock_bc(cr, g->ngQM, g->QMmult); - nblock_bc(cr, g->ngQM, g->bSH); - nblock_bc(cr, g->ngQM, g->CASorbitals); - nblock_bc(cr, g->ngQM, g->CASelectrons); - nblock_bc(cr, g->ngQM, g->SAon); - nblock_bc(cr, g->ngQM, g->SAoff); - nblock_bc(cr, g->ngQM, g->SAsteps); - /* end of QMMM stuff */ - } -} - -static void bc_awhBias(const t_commrec *cr, gmx::AwhBiasParams *awhBiasParams) -{ - block_bc(cr, *awhBiasParams); - - snew_bc(cr, awhBiasParams->dimParams, awhBiasParams->ndim); - nblock_bc(cr, awhBiasParams->ndim, awhBiasParams->dimParams); -} - -static void bc_awh(const t_commrec *cr, gmx::AwhParams *awhParams) -{ - int k; - - block_bc(cr, *awhParams); - snew_bc(cr, awhParams->awhBiasParams, awhParams->numBias); - for (k = 0; k < awhParams->numBias; k++) - { - bc_awhBias(cr, &awhParams->awhBiasParams[k]); - } -} - -static void bc_pull_group(const t_commrec *cr, t_pull_group *pgrp) -{ - block_bc(cr, *pgrp); - if (pgrp->nat > 0) - { - snew_bc(cr, pgrp->ind, pgrp->nat); - nblock_bc(cr, pgrp->nat, pgrp->ind); - } - if (pgrp->nweight > 0) - { - snew_bc(cr, pgrp->weight, pgrp->nweight); - nblock_bc(cr, pgrp->nweight, pgrp->weight); - } -} - -static void bc_pull(const t_commrec *cr, pull_params_t *pull) -{ - int g; - - block_bc(cr, *pull); - snew_bc(cr, pull->group, pull->ngroup); - for (g = 0; g < pull->ngroup; g++) - { - bc_pull_group(cr, &pull->group[g]); - } - snew_bc(cr, pull->coord, pull->ncoord); - nblock_bc(cr, pull->ncoord, pull->coord); - for (int c = 0; c < pull->ncoord; c++) - { - if (!MASTER(cr)) - { - pull->coord[c].externalPotentialProvider = nullptr; - } - if (pull->coord[c].eType == epullEXTERNAL) - { - bc_cstring(cr, &pull->coord[c].externalPotentialProvider); - } - } -} - -static void bc_rotgrp(const t_commrec *cr, t_rotgrp *rotg) -{ - block_bc(cr, *rotg); - if (rotg->nat > 0) - { - snew_bc(cr, rotg->ind, rotg->nat); - nblock_bc(cr, rotg->nat, rotg->ind); - snew_bc(cr, rotg->x_ref, rotg->nat); - nblock_bc(cr, rotg->nat, rotg->x_ref); - } -} - -static void bc_rot(const t_commrec *cr, t_rot *rot) -{ - int g; - - block_bc(cr, *rot); - snew_bc(cr, rot->grp, rot->ngrp); - for (g = 0; g < rot->ngrp; g++) - { - bc_rotgrp(cr, &rot->grp[g]); - } -} - -static void bc_imd(const t_commrec *cr, t_IMD *imd) -{ - block_bc(cr, *imd); - snew_bc(cr, imd->ind, imd->nat); - nblock_bc(cr, imd->nat, imd->ind); -} - -static void bc_fepvals(const t_commrec *cr, t_lambda *fep) -{ - int i; - - block_bc(cr, fep->nstdhdl); - block_bc(cr, fep->init_lambda); - block_bc(cr, fep->init_fep_state); - block_bc(cr, fep->delta_lambda); - block_bc(cr, fep->edHdLPrintEnergy); - block_bc(cr, fep->n_lambda); - if (fep->n_lambda > 0) - { - snew_bc(cr, fep->all_lambda, efptNR); - nblock_bc(cr, efptNR, fep->all_lambda); - for (i = 0; i < efptNR; i++) - { - snew_bc(cr, fep->all_lambda[i], fep->n_lambda); - nblock_bc(cr, fep->n_lambda, fep->all_lambda[i]); - } - } - block_bc(cr, fep->sc_alpha); - block_bc(cr, fep->sc_power); - block_bc(cr, fep->sc_r_power); - block_bc(cr, fep->sc_sigma); - block_bc(cr, fep->sc_sigma_min); - block_bc(cr, fep->bScCoul); - nblock_bc(cr, efptNR, &(fep->separate_dvdl[0])); - block_bc(cr, fep->dhdl_derivatives); - block_bc(cr, fep->dh_hist_size); - block_bc(cr, fep->dh_hist_spacing); - if (debug) - { - fprintf(debug, "after bc_fepvals\n"); - } -} - -static void bc_expandedvals(const t_commrec *cr, t_expanded *expand, int n_lambda) -{ - block_bc(cr, expand->nstexpanded); - block_bc(cr, expand->elamstats); - block_bc(cr, expand->elmcmove); - block_bc(cr, expand->elmceq); - block_bc(cr, expand->equil_n_at_lam); - block_bc(cr, expand->equil_wl_delta); - block_bc(cr, expand->equil_ratio); - block_bc(cr, expand->equil_steps); - block_bc(cr, expand->equil_samples); - block_bc(cr, expand->lmc_seed); - block_bc(cr, expand->minvar); - block_bc(cr, expand->minvar_const); - block_bc(cr, expand->c_range); - block_bc(cr, expand->bSymmetrizedTMatrix); - block_bc(cr, expand->nstTij); - block_bc(cr, expand->lmc_repeats); - block_bc(cr, expand->lmc_forced_nstart); - block_bc(cr, expand->gibbsdeltalam); - block_bc(cr, expand->wl_scale); - block_bc(cr, expand->wl_ratio); - block_bc(cr, expand->init_wl_delta); - block_bc(cr, expand->bInit_weights); - snew_bc(cr, expand->init_lambda_weights, n_lambda); - nblock_bc(cr, n_lambda, expand->init_lambda_weights); - block_bc(cr, expand->mc_temp); - if (debug) - { - fprintf(debug, "after bc_expandedvals\n"); - } -} - -static void bc_simtempvals(const t_commrec *cr, t_simtemp *simtemp, int n_lambda) -{ - block_bc(cr, simtemp->simtemp_low); - block_bc(cr, simtemp->simtemp_high); - block_bc(cr, simtemp->eSimTempScale); - snew_bc(cr, simtemp->temperatures, n_lambda); - nblock_bc(cr, n_lambda, simtemp->temperatures); - if (debug) - { - fprintf(debug, "after bc_simtempvals\n"); - } -} - - -static void bc_swapions(const t_commrec *cr, t_swapcoords *swap) -{ - block_bc(cr, *swap); - - /* Broadcast atom indices for split groups, solvent group, and for all user-defined swap groups */ - snew_bc(cr, swap->grp, swap->ngrp); - for (int i = 0; i < swap->ngrp; i++) - { - t_swapGroup *g = &swap->grp[i]; - - block_bc(cr, *g); - snew_bc(cr, g->ind, g->nat); - nblock_bc(cr, g->nat, g->ind); - - int len = 0; - if (MASTER(cr)) - { - len = strlen(g->molname); - } - block_bc(cr, len); - snew_bc(cr, g->molname, len); - nblock_bc(cr, len, g->molname); - } -} - - -static void bc_inputrec(const t_commrec *cr, t_inputrec *inputrec) +static void bc_tpxheader(const t_commrec *cr, TpxFileHeader *tpx) { - // Make sure to destruct all previously set internal parameters properly - // before the block_bc on the inputrec overwrites them. - // They are expected to be null anyway, but we can't guarantee this here. - if (!SIMMASTER(cr)) - { - // will call destructor on previously set parameters upon leaving this block - std::unique_ptr previouslySetInternalParametersOnNonMaster; - inputrec->internalParameters.swap(previouslySetInternalParametersOnNonMaster); - } - // Note that this overwrites pointers in inputrec, so all pointer fields - // Must be initialized separately below. - block_bc(cr, *inputrec); - if (SIMMASTER(cr)) - { - gmx::InMemorySerializer serializer; - gmx::serializeKeyValueTree(*inputrec->params, &serializer); - gmx::serializeKeyValueTree(*inputrec->internalParameters, &serializer); - std::vector buffer = serializer.finishAndGetBuffer(); - size_t size = buffer.size(); - block_bc(cr, size); - nblock_bc(cr, size, buffer.data()); - } - else - { - // block_bc() of inputrec above overwrites the old pointer, so set it to a - // reasonable value in case code below throws. - inputrec->params = nullptr; - std::vector buffer; - size_t size; - block_bc(cr, size); - nblock_abc(cr, size, &buffer); - gmx::InMemoryDeserializer serializer(buffer, false); - inputrec->params = new gmx::KeyValueTreeObject( - gmx::deserializeKeyValueTree(&serializer)); - // release is required because internalParameters' destructor will fail - // if block_bc() of inputrec overwrites the internalParameters pointer with garbage - auto gmx_unused releasedGarbagePointer = inputrec->internalParameters.release(); - inputrec->internalParameters = std::make_unique( - gmx::deserializeKeyValueTree(&serializer)); - } - - bc_grpopts(cr, &(inputrec->opts)); - - /* even if efep is efepNO, we need to initialize to make sure that - * n_lambda is set to zero */ - - snew_bc(cr, inputrec->fepvals, 1); - if (inputrec->efep != efepNO || inputrec->bSimTemp) - { - bc_fepvals(cr, inputrec->fepvals); - } - /* need to initialize this as well because of data checked for in the logic */ - snew_bc(cr, inputrec->expandedvals, 1); - if (inputrec->bExpanded) - { - bc_expandedvals(cr, inputrec->expandedvals, inputrec->fepvals->n_lambda); - } - snew_bc(cr, inputrec->simtempvals, 1); - if (inputrec->bSimTemp) - { - bc_simtempvals(cr, inputrec->simtempvals, inputrec->fepvals->n_lambda); - } - if (inputrec->bPull) - { - snew_bc(cr, inputrec->pull, 1); - bc_pull(cr, inputrec->pull); - } - if (inputrec->bDoAwh) - { - snew_bc(cr, inputrec->awhParams, 1); - bc_awh(cr, inputrec->awhParams); - } - - if (inputrec->bRot) - { - snew_bc(cr, inputrec->rot, 1); - bc_rot(cr, inputrec->rot); - } - if (inputrec->bIMD) - { - snew_bc(cr, inputrec->imd, 1); - bc_imd(cr, inputrec->imd); - } - if (inputrec->eSwapCoords != eswapNO) - { - snew_bc(cr, inputrec->swap, 1); - bc_swapions(cr, inputrec->swap); - } + block_bc(cr, tpx->bIr); + block_bc(cr, tpx->bBox); + block_bc(cr, tpx->bTop); + block_bc(cr, tpx->bX); + block_bc(cr, tpx->bV); + block_bc(cr, tpx->bF); + block_bc(cr, tpx->natoms); + block_bc(cr, tpx->ngtc); + block_bc(cr, tpx->lambda); + block_bc(cr, tpx->fep_state); + block_bc(cr, tpx->sizeOfTprBody); + block_bc(cr, tpx->fileVersion); + block_bc(cr, tpx->fileGeneration); + block_bc(cr, tpx->isDouble); } -static void bc_moltype(const t_commrec *cr, t_symtab *symtab, - gmx_moltype_t *moltype) +static void bc_tprCharBuffer(const t_commrec *cr, std::vector *charBuffer) { - bc_string(cr, symtab, &moltype->name); - bc_atoms(cr, symtab, &moltype->atoms); - if (debug) - { - fprintf(debug, "after bc_atoms\n"); - } + int elements = charBuffer->size(); + block_bc(cr, elements); - bc_ilists(cr, &moltype->ilist); - bc_block(cr, &moltype->cgs); - bc_blocka(cr, &moltype->excls); + nblock_abc(cr, elements, charBuffer); } -static void bc_vector_of_rvec(const t_commrec *cr, std::vector *vec) +void init_parallel(t_commrec *cr, + t_inputrec *inputrec, + gmx_mtop_t *mtop, + PartialDeserializedTprFile *partialDeserializedTpr) { - int numElements = vec->size(); - block_bc(cr, numElements); + bc_tpxheader(cr, &partialDeserializedTpr->header); + bc_tprCharBuffer(cr, &partialDeserializedTpr->body); if (!MASTER(cr)) { - vec->resize(numElements); - } - if (numElements > 0) - { - nblock_bc(cr, numElements, as_rvec_array(vec->data())); - } -} - -static void bc_molblock(const t_commrec *cr, gmx_molblock_t *molb) -{ - block_bc(cr, molb->type); - block_bc(cr, molb->nmol); - bc_vector_of_rvec(cr, &molb->posres_xA); - bc_vector_of_rvec(cr, &molb->posres_xB); - if (debug) - { - fprintf(debug, "after bc_molblock\n"); + completeTprDeserialization(partialDeserializedTpr, + inputrec, + mtop); } } - -static void bc_atomtypes(const t_commrec *cr, t_atomtypes *atomtypes) -{ - block_bc(cr, atomtypes->nr); -} - -/*! \brief Broadcasts ir and mtop from the master to all nodes in - * cr->mpi_comm_mygroup. */ -static -void bcast_ir_mtop(const t_commrec *cr, t_inputrec *inputrec, gmx_mtop_t *mtop) -{ - if (debug) - { - fprintf(debug, "in bc_data\n"); - } - bc_inputrec(cr, inputrec); - if (debug) - { - fprintf(debug, "after bc_inputrec\n"); - } - bc_symtab(cr, &mtop->symtab); - if (debug) - { - fprintf(debug, "after bc_symtab\n"); - } - bc_string(cr, &mtop->symtab, &mtop->name); - if (debug) - { - fprintf(debug, "after bc_name\n"); - } - - bc_ffparams(cr, &mtop->ffparams); - - int nmoltype = mtop->moltype.size(); - block_bc(cr, nmoltype); - mtop->moltype.resize(nmoltype); - for (gmx_moltype_t &moltype : mtop->moltype) - { - bc_moltype(cr, &mtop->symtab, &moltype); - } - - block_bc(cr, mtop->bIntermolecularInteractions); - if (mtop->bIntermolecularInteractions) - { - if (!MASTER(cr)) - { - mtop->intermolecular_ilist = std::make_unique(); - } - bc_ilists(cr, mtop->intermolecular_ilist.get()); - } - - int nmolblock = mtop->molblock.size(); - block_bc(cr, nmolblock); - mtop->molblock.resize(nmolblock); - for (gmx_molblock_t &molblock : mtop->molblock) - { - bc_molblock(cr, &molblock); - } - - block_bc(cr, mtop->natoms); - - bc_atomtypes(cr, &mtop->atomtypes); - - bc_groups(cr, &mtop->symtab, mtop->natoms, &mtop->groups); - - GMX_RELEASE_ASSERT(!MASTER(cr) || mtop->haveMoleculeIndices, "mtop should have valid molecule indices"); - if (!MASTER(cr)) - { - mtop->haveMoleculeIndices = true; - - gmx_mtop_finalize(mtop); - } -} - -void init_parallel(t_commrec *cr, t_inputrec *inputrec, - gmx_mtop_t *mtop) -{ - bcast_ir_mtop(cr, inputrec, mtop); -} diff --git a/src/gromacs/mdlib/broadcaststructs.h b/src/gromacs/mdlib/broadcaststructs.h index e4273078ba..3f8003d77b 100644 --- a/src/gromacs/mdlib/broadcaststructs.h +++ b/src/gromacs/mdlib/broadcaststructs.h @@ -55,6 +55,7 @@ struct gmx_mtop_t; struct t_commrec; struct t_inputrec; +struct PartialDeserializedTprFile; class t_state; //! Convenience wrapper for gmx_bcast of a single value. @@ -109,7 +110,9 @@ void nblock_abc(const t_commrec *cr, int numElements, std::vector *v) void broadcastStateWithoutDynamics(const t_commrec *cr, t_state *state); //! \brief Broadcast inputrec and mtop and allocate node-specific settings -void init_parallel(t_commrec *cr, t_inputrec *inputrec, - gmx_mtop_t *mtop); +void init_parallel(t_commrec *cr, + t_inputrec *inputrec, + gmx_mtop_t *mtop, + PartialDeserializedTprFile *partialDeserializedTpr); #endif diff --git a/src/gromacs/mdrun/runner.cpp b/src/gromacs/mdrun/runner.cpp index a46ded32e1..67d5ec5bf5 100644 --- a/src/gromacs/mdrun/runner.cpp +++ b/src/gromacs/mdrun/runner.cpp @@ -696,15 +696,18 @@ int Mdrunner::mdrunner() t_inputrec *inputrec = nullptr; std::unique_ptr globalState; + auto partialDeserializedTpr = std::make_unique(); + if (SIMMASTER(cr)) { /* Only the master rank has the global state */ globalState = std::make_unique(); - /* Read (nearly) all data required for the simulation */ - read_tpx_state(ftp2fn(efTPR, filenames.size(), filenames.data()), - &inputrecInstance, globalState.get(), &mtop); - inputrec = &inputrecInstance; + /* Read (nearly) all data required for the simulation + * and keep the partly serialized tpr contents to send to other ranks later + */ + *partialDeserializedTpr = read_tpx_state(ftp2fn(efTPR, filenames.size(), filenames.data()), &inputrecInstance, globalState.get(), &mtop); + inputrec = &inputrecInstance; } /* Check and update the hardware options for internal consistency */ @@ -766,9 +769,10 @@ int Mdrunner::mdrunner() { inputrec = &inputrecInstance; } - init_parallel(cr, inputrec, &mtop); + init_parallel(cr, inputrec, &mtop, partialDeserializedTpr.get()); } - GMX_RELEASE_ASSERT(inputrec != nullptr, "All range should have a valid inputrec now"); + GMX_RELEASE_ASSERT(inputrec != nullptr, "All ranks should have a valid inputrec now"); + partialDeserializedTpr.reset(nullptr); // Now each rank knows the inputrec that SIMMASTER read and used, // and (if applicable) cr->nnodes has been assigned the number of diff --git a/src/gromacs/utility/inmemoryserializer.cpp b/src/gromacs/utility/inmemoryserializer.cpp index f22bf37de2..d607c9849c 100644 --- a/src/gromacs/utility/inmemoryserializer.cpp +++ b/src/gromacs/utility/inmemoryserializer.cpp @@ -191,7 +191,7 @@ void InMemorySerializer::doString(std::string *value) class InMemoryDeserializer::Impl { public: - explicit Impl(const std::vector &buffer, bool sourceIsDouble) + explicit Impl(ArrayRef buffer, bool sourceIsDouble) : buffer_(buffer), sourceIsDouble_(sourceIsDouble), pos_(0) { } @@ -210,12 +210,12 @@ class InMemoryDeserializer::Impl pos_ += size; } - const std::vector &buffer_; + ArrayRef buffer_; bool sourceIsDouble_; size_t pos_; }; -InMemoryDeserializer::InMemoryDeserializer(const std::vector &buffer, bool sourceIsDouble) +InMemoryDeserializer::InMemoryDeserializer(ArrayRef buffer, bool sourceIsDouble) : impl_(new Impl(buffer, sourceIsDouble)) { } diff --git a/src/gromacs/utility/inmemoryserializer.h b/src/gromacs/utility/inmemoryserializer.h index a053e4198d..6e89b68091 100644 --- a/src/gromacs/utility/inmemoryserializer.h +++ b/src/gromacs/utility/inmemoryserializer.h @@ -45,6 +45,7 @@ #include +#include "gromacs/utility/arrayref.h" #include "gromacs/utility/classhelpers.h" #include "gromacs/utility/iserializer.h" @@ -84,7 +85,7 @@ class InMemorySerializer : public ISerializer class InMemoryDeserializer : public ISerializer { public: - explicit InMemoryDeserializer(const std::vector &buffer, bool sourceIsDouble); + explicit InMemoryDeserializer(ArrayRef buffer, bool sourceIsDouble); ~InMemoryDeserializer() override; //! Get if the source data was written in double precsion