Add Interface to change coordinate file info
authorPaul Bauer <paul.bauer.q@gmail.com>
Tue, 13 Nov 2018 10:36:33 +0000 (11:36 +0100)
committerMark Abraham <mark.j.abraham@gmail.com>
Thu, 25 Apr 2019 11:46:12 +0000 (13:46 +0200)
Adds the IOutputAdapter interface to organize coordinate output file
writing, as well as enum flags to communicate requirements between output
modules and output filetypes, as well as the outputadaptercontainer storage
object to keep track of modules derived from the IOutputAdapter
interface.

IOutputAdapter can be used to communicate what requirements are specific
file writing method has on the meta information contained in t_trxframe.

Change-Id: I0011c852eb54bd551230dd8c4971292dd4edc7e5

13 files changed:
docs/doxygen/user/analysisframework.md
src/gromacs/CMakeLists.txt
src/gromacs/coordinateio.h [new file with mode: 0644]
src/gromacs/coordinateio/CMakeLists.txt [new file with mode: 0644]
src/gromacs/coordinateio/enums.h [new file with mode: 0644]
src/gromacs/coordinateio/ioutputadapter.h [new file with mode: 0644]
src/gromacs/coordinateio/outputadaptercontainer.cpp [new file with mode: 0644]
src/gromacs/coordinateio/outputadaptercontainer.h [new file with mode: 0644]
src/gromacs/coordinateio/outputadapters.h [new file with mode: 0644]
src/gromacs/coordinateio/tests/CMakeLists.txt [new file with mode: 0644]
src/gromacs/coordinateio/tests/outputadaptercontainer.cpp [new file with mode: 0644]
src/gromacs/coordinateio/tests/testmodule.cpp [new file with mode: 0644]
src/gromacs/coordinateio/tests/testmodule.h [new file with mode: 0644]

index 46ce511fca362c23385e45f0cde1a1eae9552347..841e2b93694d4a1acd259a2c98f8dd31485f60c3 100644 (file)
@@ -125,3 +125,17 @@ gmx::IOptionsContainer object are also used to provide help to the user (also
 handled by the framework).
 See the documentation for gmx::TrajectoryAnalysisModule and the
 [options module documentation](\ref module_options) for more details.
+
+Coordinate data output
+======================
+
+The \ref module_coordinateio module allows modules to output coordinate data
+used or generated during the analysis. It provides two main components:
+
+ - An OutputManager for handling the file opening, writing, closing and
+   registration of modules to change metainformation.
+ - A set of modules to change the metainformation in coordinate data frames
+   and to cross check the requirements for data output and file formats.
+
+More detailed information, as well as an interaction diagram can be found in the
+[module documentation](\ref module_coordinateio).
index 15ae002aa74bcff3214dc00fa53af5fa061bdeb4..6563e3c5ce24206e3449ef5c1e8e8c0e54bdee37 100644 (file)
@@ -136,6 +136,7 @@ if (NOT GMX_BUILD_MDRUN_ONLY)
     add_subdirectory(correlationfunctions)
     add_subdirectory(statistics)
     add_subdirectory(analysisdata)
+    add_subdirectory(coordinateio)
     add_subdirectory(selection)
     add_subdirectory(trajectoryanalysis)
     add_subdirectory(energyanalysis)
diff --git a/src/gromacs/coordinateio.h b/src/gromacs/coordinateio.h
new file mode 100644 (file)
index 0000000..be3016a
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2019, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS 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 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \defgroup module_coordinateio Handling of writing new coordinate files
+ * \ingroup group_analysismodules
+ * \brief
+ * Provides basic functions to handle writing of new coordinate files.
+ *
+ * The methods included in the coordinateio module implement the basics
+ * for manipulating and writing coordinate trajectory files
+ * and changing metadata in the underlying datastructures. Included are a container for storing
+ * modules that change trajectory data, as well as a manager to write output files that uses
+ * those methods. It can be used from within \ref module_trajectoryanalysis, and uses
+ * methods from:
+ * - \ref module_options
+ * - \ref module_selection
+ *
+ * <H3>Overview</H3>
+ * The methods in coordinateio provide the infrastructure to perform operations on coordinate data files
+ * and structures during data analysis. It implements ways to change the information
+ * in coordinate data structures as well as checking that both input data and output
+ * method are matching for a given coordinate file writing operation. For this
+ * components verify first that all the requirements can be satisfied. Then
+ * components are build that will change the coordinate information accordingly.
+ *
+ * The main parts are the outputadapters implemented using the
+ * IOutputAdapter interface to change information in a local (deep) copy of t_trxframes
+ * stored in the outputmanager.
+ *
+ * <H3>Outputadapter</H3>
+ * Each OutputAdapter module implements the same IOutputAdapter interface and
+ * has to set its requirements for final
+ * processing as a flag from the enum in requirementflags. During processing, they implement a custom
+ * version of the processFrame directive that modifies the stored trajectory data before writing
+ * a new file to disk.
+ *
+ *
+ * The interaction between the OutputManager and the OutputAdapter modules derived from
+ * IOutputAdapter is shown in the diagram below.
+ *
+ * \msc
+   wordwraparcs=true,
+   hscale="2";
+
+   analysistool,
+   builder [ label="OutputManagerBuilder" ],
+   outputmanager [ label="OutputManager" ],
+   container [ label="OutputAdapterStorage" ],
+   outputadapters [ label="OutputAdapters" ];
+
+   analysistool => builder [ label="Requests new coordinate output" ];
+   analysistool => builder [ label="Specifies required OutputAdapters" ];
+   builder => outputadapters [ label="Tries to construct new outputadapters" ];
+   outputadapters => builder [ label="Return or give error for wrong preconditions" ];
+   outputadapters => container [ label="Outputadapters are stored" ];
+   container => builder [ label="Gives error if storage conditions are violated" ];
+   builder => outputmanager [ label="Constructs new manager according to specifications" ];
+   builder => container [ label="Requests storage object with registered outputadapters" ];
+   container => builder [ label="Gives ownership of stored outputadapters" ];
+   builder box builder [ label="Tests preconditions of storage object and new outputmanager" ];
+   builder => analysistool [ label="Raise error if preconditions don't match" ];
+   builder => outputmanager [ label="Add storage object to new outputmanager" ];
+   outputmanager => analysistool [ label="Returns finished outputmanager" ];
+   builder box builder [ label="outputmanager created, can start to work on input data" ];
+
+ * \endmsc
+ *
+ * Once the OutputManager object and its registered modules are created, they can be used to
+ * iterate over input data to write new coordinate frames.
+ *
+ * \msc
+   wordwraparcs=true,
+   hscale="2";
+
+   analysistool,
+   analysisloop,
+   outputmanager [ label="OutputManager" ],
+   outputadapters [ label="OutputAdapters" ] ,
+   filewriting;
+
+   --- [ label="Setup of outputmanager complete, analysis phase begins" ];
+    analysistool   => analysisloop [ label="Starts iteration over frames" ];
+    analysisloop   => outputmanager [ label="Provides coordinates" ];
+    outputmanager  => outputadapters [ label="Provide coordinate frames for changing" ];
+    outputadapters => outputmanager [ label="Return after changing data" ];
+    outputmanager  => filewriting [ label="Send new coordinates for writing" ];
+    filewriting    => outputmanager [ label="Continue after writing to disk" ];
+    outputmanager  => analysisloop [ label="Returns after writing" ];
+    analysisloop box analysisloop [ label="Iterates over frames" ];
+    --- [ label="Analysis complete, object is destructed and files are closed" ];
+
+ *  \endmsc
+ *
+ *
+ *
+ * \if libapi
+ * <H3>Preparing new OutputAdapters</H3>
+ *
+ * If additional methods are needed to perform changes to the t_trxframe metadata,
+ * new OutputAdapters can be written that again implement the IOutputAdapter interface.
+ * The new method should follow the approach of the other modules that are present
+ * in changing a minimal set of t_trxframe data.
+ * \endif
+ *
+ * \author Paul Bauer <paul.bauer.q@gmail.com>
+ */
+/*! \file
+ * \libinternal
+ * \brief
+ * Public API convenience header for coordinate file output.
+ *
+ * \author Paul Bauer <paul.bauer.q@gmail.com>
+ * \inlibraryapi
+ * \ingroup module_coordinateio
+ */
+#ifndef GMX_COORDINATEIO_H
+#define GMX_COORDINATEIO_H
+
+#include "gromacs/coordinateio/enums.h"
+#include "gromacs/coordinateio/ioutputadapter.h"
+#include "gromacs/coordinateio/outputadaptercontainer.h"
+#include "gromacs/coordinateio/outputadapters.h"
+
+#endif
diff --git a/src/gromacs/coordinateio/CMakeLists.txt b/src/gromacs/coordinateio/CMakeLists.txt
new file mode 100644 (file)
index 0000000..00b8762
--- /dev/null
@@ -0,0 +1,48 @@
+#
+# This file is part of the GROMACS molecular simulation package.
+#
+# Copyright (c) 2019, by the GROMACS development team, led by
+# Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+# and including many others, as listed in the AUTHORS file in the
+# top-level source directory and at http://www.gromacs.org.
+#
+# GROMACS 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 2.1
+# of the License, or (at your option) any later version.
+#
+# GROMACS 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with GROMACS; if not, see
+# http://www.gnu.org/licenses, or write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+#
+# If you want to redistribute modifications to GROMACS, please
+# consider that scientific software is very special. Version
+# control is crucial - bugs must be traceable. We will be happy to
+# consider code for inclusion in the official distribution, but
+# derived work must not be called official GROMACS. Details are found
+# in the README & COPYING files - if they are missing, get the
+# official version at http://www.gromacs.org.
+#
+# To help us fund GROMACS development, we humbly ask that you cite
+# the research papers on the package. Check out http://www.gromacs.org.
+
+file(GLOB COORDINATEIO_SOURCES *.cpp outputadapters/*.cpp)
+
+set(LIBGROMACS_SOURCES ${LIBGROMACS_SOURCES} ${COORDINATEIO_SOURCES} PARENT_SCOPE)
+
+gmx_install_headers(
+    ioutputadapter.h
+    outputadaptercontainer.h
+    outputadapters.h
+    enums.h
+    )
+
+if (BUILD_TESTING)
+     add_subdirectory(tests)
+endif()
diff --git a/src/gromacs/coordinateio/enums.h b/src/gromacs/coordinateio/enums.h
new file mode 100644 (file)
index 0000000..9325713
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2019, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS 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 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \file
+ * \brief
+ * Enum class defining the different requirements that outputadapters
+ * have for the output file type. OutputManager objects can only be built
+ * with OutputAdapters whose requirements can be implemented with the available input.
+ *
+ * \author Paul Bauer <paul.bauer.q@gmail.com>
+ * \libinternal
+ * \ingroup module_coordinateio
+ */
+#ifndef GMX_COORDINATEIO_ENUMS_H
+#define GMX_COORDINATEIO_ENUMS_H
+
+namespace gmx
+{
+
+/*!\brief
+ * The enums here define the flags specifying the requirements
+ * of different outputadapter modules.
+ *
+ * When building the object for deciding on the output to a new coordinate file,
+ * the CoordinateFile object needs to be able to validate that the dependencies of
+ * attached IOutputAdapters are fulfilled. Classes and interfaces that use
+ * the enum can check their dependencies against the information encoded in the
+ * flags and can then perform an appropriate reaction if there is a mismatch.
+ * \todo Use std::bitset<16> for the entries.
+ *
+ * \libinternal
+ * \ingroup module_coordinateio
+ *
+ */
+enum class CoordinateFileFlags : unsigned long
+{
+    /*! \brief
+     * Base setting that says that the module has no requirements.
+     *
+     * Sets the flags to default setting to make sure all output methods
+     * are supported.
+     */
+    Base = 1<<0,
+    /*! \brief
+     * Requires output method to support force output.
+     *
+     * If set, only output methods supporting writing of forces will work,
+     * others will generate an invalid input error.
+     */
+    RequireForceOutput     = 1<<1,
+    /*! \brief
+     * Requires output method to support velocity output.
+     *
+     * If set, only writing to files that support velocity output will succeed.
+     * Other writing methods will generate an error.
+     */
+    RequireVelocityOutput = 1<<2,
+    /*! \brief
+     * Requires support for connection information in output format.
+     *
+     * If set, only file output that supports writing of connection information will succeed.
+     * This means for now that only PDB and TNG files can be written. Other file writing
+     * methods will fail.
+     */
+    RequireAtomConnections = 1<<3,
+    /*! \brief
+     * Requires that output format supports the writing of atom information to the file.
+     *
+     * If set, files will only be written if they can output the information from t_atoms
+     * and otherwise create an error while writing.
+     */
+    RequireAtomInformation = 1<<4,
+    /*! \brief
+     * Requires that output format supports writing user-specified output precision.
+     *
+     * If set, output will only be written if the format supports the writing
+     * of custom precision of the included data.
+     */
+    RequireChangedOutputPrecision = 1<<5,
+    /*! \brief
+     * Requires that output format supports writing time to the file.
+     */
+    RequireNewFrameTime = 1<<6,
+    /*! \brief
+     * Requires that output format supports writing box information.
+     */
+    RequireNewBox = 1<<7,
+    /*! \brief
+     * Requires output to support changes to selection of coordinates.
+     *
+     * Default for most methods, will need to be able to write coordinates to
+     * output file or generate an error.
+     */
+    RequireCoordianteSelection = 1<<8,
+    //! Needed for enumeration array.
+    Count
+};
+
+//! Conversion of flag to its corresponding unsigned long value.
+inline unsigned long convertFlag(CoordinateFileFlags flag)
+{
+    return static_cast<unsigned long>(flag);
+}
+
+//! Enum class for setting basic flags in a t_trxframe
+enum class ChangeSettingType
+{
+    PreservedIfPresent,
+    Always,
+    Never
+};
+//! Mapping for enums from \ref ChangeSettingType.
+const char *const cChangeSettingTypeEnum[] = {
+    "preserved-if-present", "always", "never"
+};
+
+//! Enum class for t_atoms settings
+enum class ChangeAtomsType
+{
+    PreservedIfPresent,
+    AlwaysFromStructure,
+    Never,
+    Always
+};
+
+//! Mapping for enums from \ref ChangeAtomsType.
+const char *const cChangeAtomsTypeEnum[] = {
+    "preserved-if-present", "always-from-structure", "never", "always"
+};
+
+//! Enum class for setting fields new or not.
+enum class ChangeFrameInfoType
+{
+    PreservedIfPresent,
+    Always
+};
+//! Mapping for enums from \ref ChangeFrameInfoType.
+const char *const cChangeFrameInfoTypeEnum[] = {
+    "preserved-if-present", "always"
+};
+
+//! Enum class for setting frame time from user input.
+enum class ChangeFrameTimeType
+{
+    PreservedIfPresent,
+    StartTime,
+    TimeStep,
+    Both
+};
+
+//! Mapping for values from \ref ChangeFrameTimeType.
+const char *const cChangeFrameTimeTypeEnum[] = {
+    "preserved-if-present", "starttime", "timestep", "both"
+};
+
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/coordinateio/ioutputadapter.h b/src/gromacs/coordinateio/ioutputadapter.h
new file mode 100644 (file)
index 0000000..30121cf
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2019, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS 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 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \file
+ * \brief
+ * Declares gmx::IOutputAdapter interface for modifying coordinate
+ * file structures before writing them to disk.
+ *
+ * \author Paul Bauer <paul.bauer.q@gmail.com>
+ * \inlibraryapi
+ * \ingroup module_coordinateio
+ */
+#ifndef GMX_COORDINATEIO_IOUTPUTADAPTER_H
+#define GMX_COORDINATEIO_IOUTPUTADAPTER_H
+
+#include <memory>
+
+#include "gromacs/coordinateio/enums.h"
+#include "gromacs/utility/classhelpers.h"
+
+struct t_trxframe;
+
+namespace gmx
+{
+
+/*!\brief
+ * OutputAdapter class for handling trajectory file flag setting and processing.
+ *
+ * This interface provides the base point upon which modules that modify trajectory frame
+ * datastructures should be build. The interface itself does not provide any direct means
+ * to modify the data, but only gives the virtual method to perform work on a
+ * t_trxframe object. Classes that modify trajectory frames should implement this interface.
+ *
+ * \inlibraryapi
+ * \ingroup module_coordinateio
+ *
+ */
+class IOutputAdapter
+{
+    public:
+        /*! \brief
+         * Default constructor for IOutputAdapter interface.
+         */
+        IOutputAdapter()
+        {
+        }
+        virtual ~IOutputAdapter()
+        {
+        }
+        //! Move constructor for old object.
+        explicit IOutputAdapter(IOutputAdapter &&old) noexcept = default;
+
+        /*! \brief
+         * Change t_trxframe according to user input.
+         *
+         * \param[in] framenumber Frame number as reported from the
+         *                        trajectoryanalysis framework or set by user.
+         * \param[in,out] input   Pointer to trajectory analysis frame that will
+         *                        be worked on.
+         */
+        virtual void processFrame(int framenumber, t_trxframe *input) = 0;
+
+        /*! \brief
+         * Checks that the abilities of the output writer are sufficient for this adapter.
+         *
+         * It can happen that a method to write coordinate files does not match with
+         * a requested operation on the input data (e.g. the user requires velocities or
+         * forces to be written to a PDB file).
+         * To check those dependencies, derived classes need to implement a version of this
+         * function to make sure that only matching methods can be used.
+         *
+         * \param[in] abilities The abilities of an output method that need to be checked against
+         *                      the dependencies created by using the derived method.
+         * \throws InconsistentInputError If dependencies can not be matched to abilities.
+         */
+        virtual void checkAbilityDependencies(unsigned long abilities) const = 0;
+
+        GMX_DISALLOW_COPY_AND_ASSIGN(IOutputAdapter);
+
+};
+
+//! Smart pointer to manage the frame adapter object.
+using OutputAdapterPointer = std::unique_ptr<IOutputAdapter>;
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/coordinateio/outputadaptercontainer.cpp b/src/gromacs/coordinateio/outputadaptercontainer.cpp
new file mode 100644 (file)
index 0000000..aa0137e
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2019, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS 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 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*!\file
+ * \internal
+ * \brief
+ * Implements gmx::OutputAdapterContainer.
+ *
+ * \author Paul Bauer <paul.bauer.q@gmail.com>
+ * \ingroup module_coordinateio
+ */
+
+#include "gmxpre.h"
+
+#include "outputadaptercontainer.h"
+
+#include <algorithm>
+
+#include "gromacs/utility/exceptions.h"
+
+namespace gmx
+{
+
+void
+OutputAdapterContainer::addAdapter(OutputAdapterPointer adapter,
+                                   CoordinateFileFlags  type)
+{
+    if (outputAdapters_[type] != nullptr)
+    {
+        GMX_THROW(InternalError("Trying to add adapter that has already been added"));
+    }
+    adapter->checkAbilityDependencies(abilities_);
+    outputAdapters_[type] = std::move(adapter);
+}
+
+bool
+OutputAdapterContainer::isEmpty() const
+{
+    return std::none_of(outputAdapters_.begin(), outputAdapters_.end(),
+                        [](const auto &adapter){ return adapter != nullptr; });
+}
+} // namespace gmx
diff --git a/src/gromacs/coordinateio/outputadaptercontainer.h b/src/gromacs/coordinateio/outputadaptercontainer.h
new file mode 100644 (file)
index 0000000..1029dd0
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2019, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS 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 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \file
+ * \brief
+ * Declares gmx::OutputAdapterContainer, a storage object for
+ * multiple outputadapters derived from the IOutputadaper interface.
+ *
+ * \author Paul Bauer <paul.bauer.q@gmail.com>
+ * \inlibraryapi
+ * \ingroup module_coordinateio
+ */
+#ifndef GMX_COORDINATEIO_OUTPUTADAPTERCONTAINER_H
+#define GMX_COORDINATEIO_OUTPUTADAPTERCONTAINER_H
+
+#include <memory>
+#include <vector>
+
+#include "gromacs/coordinateio/ioutputadapter.h"
+#include "gromacs/utility/arrayref.h"
+#include "gromacs/utility/classhelpers.h"
+#include "gromacs/utility/enumerationhelpers.h"
+
+namespace gmx
+{
+
+/*! \libinternal \brief
+ * Storage for output adapters that modify the state of a t_trxframe object.
+ *
+ * The OutputAdapterContainer is responsible for storing the number of
+ * OutputAdapters, as well as the bitmask representing the current requirements
+ * for constructing an CoordinateFile object with the modules registered. It is responsible
+ * for ensuring that no module can be registered multiple times, and that the
+ * correct order for some modifications is observed (e.g. we can not reduce the
+ * number of coordinates written to a file before we have set all the other flags).
+ * Any other behaviour indicates a programming error and triggers an assertion.
+ *
+ * The abilities that need to be cross checked for the container are usually constrained
+ * by the file format the coordinate data will be written to. When declaring new abilities,
+ * these must match the file type for the output.
+ *
+ * \todo Keeping track of those abilities has to be the responsibility of an object
+ *       implementing and interface that declares it capabilities and will execute the
+ *       the function of writing to a file.
+ * \todo This could be changed to instead construct the container with a pointer to an
+ *       ICoordinateOutputWriter that can be passed to the IOutputAdapter modules to check
+ *       their cross-dependencies.
+ */
+class OutputAdapterContainer
+{
+    public:
+        //! Only allow constructing the container with defined output abilities.
+        explicit OutputAdapterContainer(unsigned long abilities)
+            : abilities_(abilities)
+        {}
+        //! Allow abilities to be also defined using the enum class.
+        explicit OutputAdapterContainer(CoordinateFileFlags abilities)
+            : abilities_(convertFlag(abilities))
+        {}
+
+        /*! \brief
+         * Add an adapter of a type not previously added.
+         *
+         * Only one adapter of each type can be registered, and the order of adapters
+         * is predefined in the underlying storage object.
+         * Calls internal checks to make sure that the new adapter does not violate
+         * any of the preconditions set to make an CoordinateFile object containing
+         * the registered modules.
+         *
+         * \param[in] adapter unique_ptr to adapter, with container taking ownership here.
+         * \param[in] type What kind of adapter is being added.
+         * \throws InternalError When registering an adapter of a type already registered .
+         * \throws InconsistentInputError When incompatible modules are added.
+         */
+        void addAdapter(OutputAdapterPointer adapter,
+                        CoordinateFileFlags  type);
+
+        //! Get vector of all registered adapters.
+        ArrayRef<const OutputAdapterPointer> getAdapters() { return outputAdapters_; }
+        //! Get info if we have any registered adapters.
+        bool isEmpty() const;
+
+    private:
+        //! Array of registered modules.
+        EnumerationArray<CoordinateFileFlags, OutputAdapterPointer> outputAdapters_;
+        //! Construction time bitmask declaring what the OutputManager can do.
+        unsigned long                     abilities_ = convertFlag(CoordinateFileFlags::Base);
+};
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/coordinateio/outputadapters.h b/src/gromacs/coordinateio/outputadapters.h
new file mode 100644 (file)
index 0000000..eca1554
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2019, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS 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 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*! \file
+ * \brief
+ * Public API convenience header for accessing outputadapters.
+ *
+ * \author Paul Bauer <paul.bauer.q@gmail.com>
+ * \inpublicapi
+ * \ingroup module_coordinateio
+ */
+#ifndef GMX_COORDINATEIO_OUTPUTADAPTERS_H
+#define GMX_COORDINATEIO_OUTPUTADAPTERS_H
+
+#endif
diff --git a/src/gromacs/coordinateio/tests/CMakeLists.txt b/src/gromacs/coordinateio/tests/CMakeLists.txt
new file mode 100644 (file)
index 0000000..2b63678
--- /dev/null
@@ -0,0 +1,39 @@
+#
+# This file is part of the GROMACS molecular simulation package.
+#
+# Copyright (c) 2019, by the GROMACS development team, led by
+# Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+# and including many others, as listed in the AUTHORS file in the
+# top-level source directory and at http://www.gromacs.org.
+#
+# GROMACS 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 2.1
+# of the License, or (at your option) any later version.
+#
+# GROMACS 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with GROMACS; if not, see
+# http://www.gnu.org/licenses, or write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+#
+# If you want to redistribute modifications to GROMACS, please
+# consider that scientific software is very special. Version
+# control is crucial - bugs must be traceable. We will be happy to
+# consider code for inclusion in the official distribution, but
+# derived work must not be called official GROMACS. Details are found
+# in the README & COPYING files - if they are missing, get the
+# official version at http://www.gromacs.org.
+#
+# To help us fund GROMACS development, we humbly ask that you cite
+# the research papers on the package. Check out http://www.gromacs.org.
+
+set(test_sources
+    outputadaptercontainer.cpp
+    testmodule.cpp
+    )
+gmx_add_unit_test(CoordinateIOTests coordinateio-test ${test_sources})
diff --git a/src/gromacs/coordinateio/tests/outputadaptercontainer.cpp b/src/gromacs/coordinateio/tests/outputadaptercontainer.cpp
new file mode 100644 (file)
index 0000000..557d6c9
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2019, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS 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 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*!\file
+ * \internal
+ * \brief
+ * Tests for outputadaptercontainer.
+ *
+ * \author Paul Bauer <paul.bauer.q@gmail.com>
+ * \ingroup module_coordinateio
+ */
+
+
+#include "gmxpre.h"
+
+#include "gromacs/coordinateio/outputadaptercontainer.h"
+
+#include <algorithm>
+#include <memory>
+
+#include <gtest/gtest.h>
+
+#include "gromacs/utility/exceptions.h"
+
+#include "testmodule.h"
+
+namespace gmx
+{
+
+namespace test
+{
+
+TEST(OutputAdapterContainer, MakeEmpty)
+{
+    OutputAdapterContainer container(CoordinateFileFlags::Base);
+    EXPECT_TRUE(container.isEmpty());
+}
+
+TEST(OutputAdapterContainer, AddAdapter)
+{
+    OutputAdapterContainer container(CoordinateFileFlags::Base);
+    container.addAdapter(
+            std::make_unique<DummyOutputModule>(CoordinateFileFlags::Base),
+            CoordinateFileFlags::RequireNewFrameTime);
+    EXPECT_FALSE(container.isEmpty());
+}
+
+TEST(OutputAdapterContainer, RejectBadAdapter)
+{
+    OutputAdapterContainer container(CoordinateFileFlags::Base);
+    EXPECT_THROW(container.addAdapter(
+                         std::make_unique<DummyOutputModule>(CoordinateFileFlags::RequireVelocityOutput),
+                         CoordinateFileFlags::RequireVelocityOutput),
+                 InconsistentInputError);
+    EXPECT_TRUE(container.isEmpty());
+}
+
+TEST(OutputAdapterContainer, RejectDuplicateAdapter)
+{
+    OutputAdapterContainer container(CoordinateFileFlags::Base);
+    EXPECT_NO_THROW(container.addAdapter(
+                            std::make_unique<DummyOutputModule>(CoordinateFileFlags::Base),
+                            CoordinateFileFlags::RequireNewFrameTime));
+    EXPECT_FALSE(container.isEmpty());
+    EXPECT_THROW(container.addAdapter(
+                         std::make_unique<DummyOutputModule>(CoordinateFileFlags::Base),
+                         CoordinateFileFlags::RequireNewFrameTime),
+                 InternalError);
+}
+
+TEST(OutputAdapterContainer, AcceptMultipleAdapters)
+{
+    OutputAdapterContainer container(CoordinateFileFlags::Base);
+    EXPECT_NO_THROW(container.addAdapter(
+                            std::make_unique<DummyOutputModule>(CoordinateFileFlags::Base),
+                            CoordinateFileFlags::RequireForceOutput));
+    EXPECT_FALSE(container.isEmpty());
+    EXPECT_NO_THROW(container.addAdapter(
+                            std::make_unique<DummyOutputModule>(CoordinateFileFlags::Base),
+                            CoordinateFileFlags::RequireVelocityOutput));
+    EXPECT_FALSE(container.isEmpty());
+}
+
+} // namespace test
+
+} // namespace gmx
diff --git a/src/gromacs/coordinateio/tests/testmodule.cpp b/src/gromacs/coordinateio/tests/testmodule.cpp
new file mode 100644 (file)
index 0000000..c0834f4
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2019, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS 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 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*!\file
+ * \internal
+ * \brief
+ * Implements test module.
+ *
+ * \author Paul Bauer <paul.bauer.q@gmail.com>
+ * \ingroup module_coordinateio
+ */
+
+
+#include "gmxpre.h"
+
+#include "testmodule.h"
+
+#include <gtest/gtest.h>
+
+#include "gromacs/utility/exceptions.h"
+#include "gromacs/utility/stringutil.h"
+
+namespace gmx
+{
+
+namespace test
+{
+
+void DummyOutputModule::checkAbilityDependencies(const unsigned long abilities) const
+{
+    if ((abilities & convertFlag(moduleRequirements_)) == 0u)
+    {
+        std::string errorMessage = "Unhandled module requirements.";
+        GMX_THROW(InconsistentInputError(errorMessage.c_str()));
+    }
+}
+
+} // namespace test
+
+} // namespace gmx
diff --git a/src/gromacs/coordinateio/tests/testmodule.h b/src/gromacs/coordinateio/tests/testmodule.h
new file mode 100644 (file)
index 0000000..db5c04c
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * This file is part of the GROMACS molecular simulation package.
+ *
+ * Copyright (c) 2019, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
+ *
+ * GROMACS 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 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * GROMACS 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
+ *
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the research papers on the package. Check out http://www.gromacs.org.
+ */
+/*!\file
+ * \internal
+ * \brief
+ * Dummy module used for tests and as an implementation example.
+ *
+ * \author Paul Bauer <paul.bauer.q@gmail.com>
+ * \libinternal
+ * \ingroup module_coordinateio
+ */
+
+#ifndef GMX_COORDINATEIO_TESTMODULE_H
+#define GMX_COORDINATEIO_TESTMODULE_H
+
+#include "gromacs/coordinateio/ioutputadapter.h"
+
+namespace gmx
+{
+
+namespace test
+{
+
+class DummyOutputModule : public IOutputAdapter
+{
+    public:
+        explicit DummyOutputModule(CoordinateFileFlags requirementsFlag) :
+            moduleRequirements_(requirementsFlag)
+        {}
+
+        DummyOutputModule(DummyOutputModule &&old) noexcept = default;
+
+        ~DummyOutputModule() override {}
+
+        void processFrame(int /*framenumber*/, t_trxframe * /*input*/) override
+        {}
+
+        void checkAbilityDependencies(unsigned long abilities) const override;
+
+    private:
+        //! Local requirements
+        CoordinateFileFlags moduleRequirements_;
+};
+
+} // namespace test
+
+} // namespace gmx
+
+#endif