Generic handling for multiple cmd-line modules.
authorTeemu Murtola <teemu.murtola@gmail.com>
Mon, 7 May 2012 09:36:43 +0000 (12:36 +0300)
committerTeemu Murtola <teemu.murtola@gmail.com>
Mon, 7 May 2012 10:16:23 +0000 (13:16 +0300)
Added generic methods for multiple independent modules within a single
command-line tool, and modified g_ana to use this.

By itself, does not change the external behavior significantly, but
makes it easier to implement parts of #666 and #672.
The wrapper binary in #685 should also be easy to implement using this
approach.

Change-Id: I3058bf5db2cbb7c7a1f9e4c87dd2db8f9727fe82

16 files changed:
src/gromacs/commandline/cmdlinemodule.h [new file with mode: 0644]
src/gromacs/commandline/cmdlinemodulemanager.cpp [new file with mode: 0644]
src/gromacs/commandline/cmdlinemodulemanager.h [new file with mode: 0644]
src/gromacs/commandline/tests/CMakeLists.txt
src/gromacs/commandline/tests/cmdlinemodulemanager.cpp [new file with mode: 0644]
src/gromacs/trajectoryanalysis/cmdlinerunner.cpp
src/gromacs/trajectoryanalysis/cmdlinerunner.h
src/gromacs/trajectoryanalysis/modules.cpp
src/gromacs/trajectoryanalysis/modules.h
src/gromacs/trajectoryanalysis/modules/angle.cpp
src/gromacs/trajectoryanalysis/modules/angle.h
src/gromacs/trajectoryanalysis/modules/distance.cpp
src/gromacs/trajectoryanalysis/modules/distance.h
src/gromacs/trajectoryanalysis/modules/select.cpp
src/gromacs/trajectoryanalysis/modules/select.h
src/programs/g_ana/g_ana.cpp

diff --git a/src/gromacs/commandline/cmdlinemodule.h b/src/gromacs/commandline/cmdlinemodule.h
new file mode 100644 (file)
index 0000000..c62a097
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, 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 www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \file
+ * \brief
+ * Declares gmx::CommandLineModuleInterface.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \inpublicapi
+ * \ingroup module_commandline
+ */
+#ifndef GMX_COMMANDLINE_CMDLINEMODULE_H
+#define GMX_COMMANDLINE_CMDLINEMODULE_H
+
+namespace gmx
+{
+
+/*! \brief
+ * Module that can be run from command line using CommandLineModuleManager.
+ *
+ * \see CommandLineModuleManager
+ *
+ * \inpublicapi
+ * \ingroup module_commandline
+ */
+class CommandLineModuleInterface
+{
+    public:
+        virtual ~CommandLineModuleInterface() {}
+
+        //! Returns the name of the module.
+        virtual const char *name() const = 0;
+
+        /*! \brief
+         * Runs the module with the given arguments.
+         *
+         * \param[in] argc  Number of elements in \p argv.
+         * \param[in] argv  Command-line arguments.
+         * \throws   unspecified  May throw exceptions to indicate errors.
+         * \returns  Exit code for the program.
+         * \retval   0 on successful termination.
+         *
+         * \p argv[0] is the name of the module, i.e., the arguments are as if
+         * the module was run as a standalone executable.
+         */
+        virtual int run(int argc, char *argv[]) = 0;
+};
+
+} // namespace gmx
+
+#endif
diff --git a/src/gromacs/commandline/cmdlinemodulemanager.cpp b/src/gromacs/commandline/cmdlinemodulemanager.cpp
new file mode 100644 (file)
index 0000000..bcd7736
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, 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 www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Implements gmx::CommandLineModuleManager.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_commandline
+ */
+#include "cmdlinemodulemanager.h"
+
+#include <cstdio>
+
+#include <map>
+#include <string>
+#include <utility>
+
+#include "gromacs/legacyheaders/statutil.h"
+
+#include "gromacs/commandline/cmdlinemodule.h"
+#include "gromacs/utility/gmxassert.h"
+
+namespace gmx
+{
+
+/********************************************************************
+ * CommandLineModuleManager::Impl
+ */
+
+/*! \internal \brief
+ * Private implementation class for CommandLineModuleManager.
+ *
+ * \ingroup module_commandline
+ */
+class CommandLineModuleManager::Impl
+{
+    public:
+        //! Container for mapping module names to module objects.
+        typedef std::map<std::string, CommandLineModulePointer> ModuleMap;
+
+        //! Prints usage message to stderr.
+        void printUsage() const;
+
+        /*! \brief
+         * Maps module names to module objects.
+         *
+         * Owns the contained modules.
+         */
+        ModuleMap               modules_;
+};
+
+void CommandLineModuleManager::Impl::printUsage() const
+{
+    fprintf(stderr, "Usage: %s <command> [<args>]\n",
+            ShortProgram());
+}
+
+/********************************************************************
+ * CommandLineModuleManager
+ */
+
+CommandLineModuleManager::CommandLineModuleManager()
+    : impl_(new Impl)
+{
+}
+
+CommandLineModuleManager::~CommandLineModuleManager()
+{
+}
+
+void CommandLineModuleManager::addModule(CommandLineModulePointer module)
+{
+    GMX_ASSERT(impl_->modules_.find(module->name()) == impl_->modules_.end(),
+               "Attempted to register a duplicate module name");
+    impl_->modules_.insert(std::make_pair(std::string(module->name()),
+                                          move(module)));
+}
+
+int CommandLineModuleManager::run(int argc, char *argv[])
+{
+    if (argc < 2)
+    {
+        fprintf(stderr, "\n");
+        impl_->printUsage();
+        return 2;
+    }
+    // TODO: Accept unambiguous prefixes?
+    Impl::ModuleMap::const_iterator module = impl_->modules_.find(argv[1]);
+    if (module == impl_->modules_.end())
+    {
+        fprintf(stderr, "\n");
+        fprintf(stderr, "Unknown command: %s\n", argv[1]);
+        impl_->printUsage();
+        return 2;
+    }
+    return module->second->run(argc - 1, argv + 1);
+}
+
+} // namespace gmx
diff --git a/src/gromacs/commandline/cmdlinemodulemanager.h b/src/gromacs/commandline/cmdlinemodulemanager.h
new file mode 100644 (file)
index 0000000..6e3f7e3
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, 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 www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \file
+ * \brief
+ * Declares gmx::CommandLineModuleManager.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \inpublicapi
+ * \ingroup module_commandline
+ */
+#ifndef GMX_COMMANDLINE_CMDLINEMODULEMANAGER_H
+#define GMX_COMMANDLINE_CMDLINEMODULEMANAGER_H
+
+#include "../utility/common.h"
+#include "../utility/uniqueptr.h"
+
+namespace gmx
+{
+
+class CommandLineModuleInterface;
+
+//! Smart pointer type for managing a CommandLineModuleInterface.
+typedef gmx_unique_ptr<CommandLineModuleInterface>::type
+        CommandLineModulePointer;
+
+/*! \brief
+ * Implements a wrapper command-line interface for multiple modules.
+ *
+ * Typical usage:
+ * \code
+int
+main(int argc, char *argv[])
+{
+    CopyRight(stderr, argv[0]);
+    try
+    {
+        gmx::CommandLineModuleManager manager;
+        // <register all necessary modules>
+        return manager.run(argc, argv);
+    }
+    catch (const std::exception &ex)
+    {
+        fprintf(stderr, "%s", gmx::formatErrorMessage(ex).c_str());
+        return 1;
+    }
+}
+ * \endcode
+ *
+ * \inpublicapi
+ * \ingroup module_commandline
+ */
+class CommandLineModuleManager
+{
+    public:
+        CommandLineModuleManager();
+        ~CommandLineModuleManager();
+
+        /*! \brief
+         * Adds a given module to this manager.
+         *
+         * \param   module  Module to add.
+         * \throws  std::bad_alloc if out of memory.
+         *
+         * The manager takes ownership of the object.
+         *
+         * This method is public mostly for testing purposes; for typical uses,
+         * registerModule() is a more convenient way of adding modules.
+         *
+         * \see registerModule()
+         */
+        void addModule(CommandLineModulePointer module);
+        /*! \brief
+         * Registers a module of a certain type to this manager.
+         *
+         * \tparam  Module  Type of module to register.
+         * \throws  std::bad_alloc if out of memory.
+         *
+         * \p Module must be default-constructible and implement
+         * CommandLineModuleInterface.
+         *
+         * This method is provided as a convenient alternative to addModule()
+         * for cases where each module is implemented by a different type
+         * (which should be the case for typical situations outside unit
+         * tests).
+         */
+        template <class Module>
+        void registerModule()
+        {
+            addModule(CommandLineModulePointer(new Module));
+        }
+
+        /*! \brief
+         * Runs a module based on given command line.
+         *
+         * \param[in] argc  Number of elements in \p argv.
+         * \param[in] argv  Command-line arguments.
+         * \throws   unspecified  Throws any exception that the selected module
+         *      throws.
+         * \returns  Exit code for the program.
+         * \retval   0 on successful termination.
+         * \retval   2 if no module is specified, or if the module is not found.
+         *
+         * Runs the module whose name matches \p argv[1].
+         */
+        int run(int argc, char *argv[]);
+
+    private:
+        class Impl;
+
+        PrivateImplPointer<Impl> impl_;
+};
+
+} // namespace gmx
+
+#endif
index 007275c3ece97a1ea19a655234892dd1fe2dd2ae..fd5105a83ba23e47b20d0e0a518ca7e1b0b692c5 100644 (file)
@@ -1,6 +1,8 @@
 if (TESTUTILS_HAVE_REFDATA)
-    add_gtest_test(CommandLineUnitTests commandline-test
-                   cmdlinehelpwriter.cpp
-                   cmdlineparser.cpp
-                   cmdlinetest.cpp)
+    add_gtest_or_gmock_test(CommandLineUnitTests commandline-test
+                            cmdlinehelpwriter.cpp
+                            cmdlineparser.cpp
+                            cmdlinetest.cpp
+                            GMOCK_ONLY
+                            cmdlinemodulemanager.cpp)
 endif ()
diff --git a/src/gromacs/commandline/tests/cmdlinemodulemanager.cpp b/src/gromacs/commandline/tests/cmdlinemodulemanager.cpp
new file mode 100644 (file)
index 0000000..0f427c8
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ *
+ *                This source code is part of
+ *
+ *                 G   R   O   M   A   C   S
+ *
+ *          GROningen MAchine for Chemical Simulations
+ *
+ * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
+ * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
+ * Copyright (c) 2001-2009, The GROMACS development team,
+ * check out http://www.gromacs.org for more information.
+
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * If you want to redistribute modifications, 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 www.gromacs.org.
+ *
+ * To help us fund GROMACS development, we humbly ask that you cite
+ * the papers on the package - you can find them in the top README file.
+ *
+ * For more info, check our website at http://www.gromacs.org
+ */
+/*! \internal \file
+ * \brief
+ * Tests gmx::CommandLineModuleManager.
+ *
+ * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \ingroup module_commandline
+ */
+#include <vector>
+
+#include <gmock/gmock.h>
+
+#include "gromacs/commandline/cmdlinemodule.h"
+#include "gromacs/commandline/cmdlinemodulemanager.h"
+
+#include "cmdlinetest.h"
+
+namespace
+{
+
+/********************************************************************
+ * MockModule
+ */
+
+/*! \internal \brief
+ * Mock implementation of gmx::CommandLineModuleInterface.
+ *
+ * \ingroup module_commandline
+ */
+class MockModule : public gmx::CommandLineModuleInterface
+{
+    public:
+        //! Creates a mock module with the given name.
+        explicit MockModule(const char *name);
+
+        virtual const char *name() const { return name_; }
+
+        MOCK_METHOD2(run, int(int argc, char *argv[]));
+
+    private:
+        const char             *name_;
+};
+
+MockModule::MockModule(const char *name)
+    : name_(name)
+{
+}
+
+/********************************************************************
+ * Test fixture for the tests
+ */
+
+class CommandLineModuleManagerTest : public ::testing::Test
+{
+    public:
+        MockModule &addModule(const char *name);
+
+        gmx::CommandLineModuleManager manager_;
+};
+
+MockModule &
+CommandLineModuleManagerTest::addModule(const char *name)
+{
+    MockModule *module = new MockModule(name);
+    manager_.addModule(gmx::CommandLineModulePointer(module));
+    return *module;
+}
+
+/********************************************************************
+ * Actual tests
+ */
+
+TEST_F(CommandLineModuleManagerTest, RunsModule)
+{
+    const char *const cmdline[] = {
+        "test", "module", "-flag", "yes"
+    };
+    gmx::test::CommandLine args(cmdline);
+    MockModule &mod1 = addModule("module");
+    addModule("other");
+    using ::testing::_;
+    using ::testing::Args;
+    using ::testing::ElementsAreArray;
+    EXPECT_CALL(mod1, run(_, _))
+        .With(Args<1, 0>(ElementsAreArray(args.argv() + 1, args.argc() - 1)));
+    int rc = 0;
+    ASSERT_NO_THROW(rc = manager_.run(args.argc(), args.argv()));
+    ASSERT_EQ(0, rc);
+}
+
+} // namespace
index d1a0f62dadf4a943707e6d63abe1fbd573eb412b..aa18c392e2e899fedb588cc75fbd79b26949f999 100644 (file)
@@ -81,12 +81,13 @@ class TrajectoryAnalysisCommandLineRunner::Impl
 
         TrajectoryAnalysisModule *_module;
         int                     _debugLevel;
+        bool                    _bPrintCopyright;
 };
 
 
 TrajectoryAnalysisCommandLineRunner::Impl::Impl(
         TrajectoryAnalysisModule *module)
-    : _module(module), _debugLevel(0)
+    : _module(module), _debugLevel(0), _bPrintCopyright(true)
 {
 }
 
@@ -181,6 +182,13 @@ TrajectoryAnalysisCommandLineRunner::~TrajectoryAnalysisCommandLineRunner()
 }
 
 
+void
+TrajectoryAnalysisCommandLineRunner::setPrintCopyright(bool bPrint)
+{
+    _impl->_bPrintCopyright = bPrint;
+}
+
+
 void
 TrajectoryAnalysisCommandLineRunner::setSelectionDebugLevel(int debuglevel)
 {
@@ -193,7 +201,10 @@ TrajectoryAnalysisCommandLineRunner::run(int argc, char *argv[])
 {
     TrajectoryAnalysisModule *module = _impl->_module;
 
-    CopyRight(stderr, argv[0]);
+    if (_impl->_bPrintCopyright)
+    {
+        CopyRight(stderr, argv[0]);
+    }
 
     SelectionCollection  selections;
     selections.setDebugLevel(_impl->_debugLevel);
index a93c91f1caa23d1a3233f4182361a0b32c8a2579..97622541e576d8dd3a102d43e0a93926b8390023 100644 (file)
@@ -73,6 +73,18 @@ class TrajectoryAnalysisCommandLineRunner
         TrajectoryAnalysisCommandLineRunner(TrajectoryAnalysisModule *module);
         ~TrajectoryAnalysisCommandLineRunner();
 
+        /*! \brief
+         * Sets whether the runner will print the copyright header.
+         *
+         * \param[in] bPrint  Whether to print the copyright header.
+         *
+         * By default, the copyright header is printed.
+         * This is used internally when executing the runner in a context where
+         * the copyright has already been printed at a higher level.
+         *
+         * Does not throw.
+         */
+        void setPrintCopyright(bool bPrint);
         /*! \brief
          * Sets the default debugging level for selections.
          *
index 258876fe869897ba4870cbe534398cf974c54966..e1ede11265b969453c95daa214fbd0873db9aa19 100644 (file)
  */
 /*! \internal \file
  * \brief
- * Implements createTrajectoryAnalysisModule().
+ * Implements registerTrajectoryAnalysisModules().
  *
  * \author Teemu Murtola <teemu.murtola@cbr.su.se>
  * \ingroup module_trajectoryanalysis
  */
 #include "gromacs/trajectoryanalysis/modules.h"
 
-#include "string2.h"
-
-#include "gromacs/utility/exceptions.h"
-#include "gromacs/utility/format.h"
+#include "gromacs/commandline/cmdlinemodule.h"
+#include "gromacs/commandline/cmdlinemodulemanager.h"
+#include "gromacs/trajectoryanalysis/cmdlinerunner.h"
 
 #include "modules/angle.h"
 #include "modules/distance.h"
 #include "modules/select.h"
 
-namespace
+namespace gmx
 {
 
-using namespace gmx::analysismodules;
-
-struct module_map_t
+namespace
 {
-    const char                            *name;
-    gmx::TrajectoryAnalysisModulePointer (*creator)(void);
-};
 
-const module_map_t modules[] =
+/*! \internal \brief
+ * Base class for trajectory analysis module command-line wrappers.
+ *
+ * This class exists to avoid multiple identical copies of the \p run() method
+ * to be generated for the TrajAnalysisCmdLineWrapper template classes.
+ *
+ * \ingroup module_trajectoryanalysis
+ */
+class AbstractTrajAnalysisCmdLineWrapper : public CommandLineModuleInterface
 {
-    {gmx::analysismodules::angle,    Angle::create},
-    {gmx::analysismodules::distance, Distance::create},
-    {gmx::analysismodules::select,   Select::create},
-    {NULL,                           NULL},
-};
+    public:
+        virtual const char *name() const = 0;
 
-} // namespace
+        virtual int run(int argc, char *argv[]);
 
-namespace gmx
-{
+    protected:
+        //! Creates the analysis module for this wrapper.
+        virtual TrajectoryAnalysisModulePointer createModule() = 0;
+};
 
-TrajectoryAnalysisModulePointer
-createTrajectoryAnalysisModule(const char *name)
+int AbstractTrajAnalysisCmdLineWrapper::run(int argc, char *argv[])
 {
-    size_t len = strlen(name);
-    int match_i = -1;
+    TrajectoryAnalysisModulePointer module(createModule());
+    TrajectoryAnalysisCommandLineRunner runner(module.get());
+    runner.setPrintCopyright(false);
+    return runner.run(argc, argv);
+}
 
-    for (int i = 0; modules[i].name != NULL; ++i)
-    {
-        if (gmx_strncasecmp(name, modules[i].name, len) == 0)
+/*! \internal \brief
+ * Template for command-line wrapper of a trajectory analysis module.
+ *
+ * \tparam Module  Trajectory analysis module to wrap.
+ *
+ * \p Module should be default-constructible, derive from
+ * TrajectoryAnalysisModule, and have a static public member
+ * \c "const char name[]".
+ *
+ * \ingroup module_trajectoryanalysis
+ */
+template <class Module>
+class TrajAnalysisCmdLineWrapper : public AbstractTrajAnalysisCmdLineWrapper
+{
+    public:
+        virtual const char *name() const
         {
-            if (strlen(modules[i].name) == len)
-            {
-                match_i = i;
-                break;
-            }
-            else if (match_i == -1)
-            {
-                match_i = i;
-            }
-            else
-            {
-                GMX_THROW(InvalidInputError(
-                            gmx::formatString("Requested analysis module '%s' is ambiguous", name)));
-            }
+            return Module::name;
         }
-    }
-    if (match_i != -1)
-    {
-        return modules[match_i].creator();
-    }
-    GMX_THROW(InvalidInputError(
-                gmx::formatString("Unknown analysis module: %s", name)));
+        virtual TrajectoryAnalysisModulePointer createModule()
+        {
+            return TrajectoryAnalysisModulePointer(new Module);
+        }
+};
+
+} // namespace
+
+void registerTrajectoryAnalysisModules(CommandLineModuleManager *manager)
+{
+    using namespace gmx::analysismodules;
+    manager->registerModule<TrajAnalysisCmdLineWrapper<Angle> >();
+    manager->registerModule<TrajAnalysisCmdLineWrapper<Distance> >();
+    manager->registerModule<TrajAnalysisCmdLineWrapper<Select> >();
 }
 
 } // namespace gmx
index 5659e89e034b853309e51d6ecbdec704dd326e1a..19377f22e617db2def1a61fce8eb7052b1d0e9e5 100644 (file)
@@ -30,7 +30,7 @@
  */
 /*! \file
  * \brief
- * Generic interface for creation of trajectory analysis modules.
+ * Generic interface for accessing trajectory analysis modules.
  *
  * \author Teemu Murtola <teemu.murtola@cbr.su.se>
  * \inpublicapi
 #ifndef GMX_TRAJECTORYANALYSIS_MODULES_H
 #define GMX_TRAJECTORYANALYSIS_MODULES_H
 
-#include "analysismodule.h"
-
 namespace gmx
 {
 
+class CommandLineModuleManager;
+
 /*! \brief
- * Creates a TrajectoryAnalysisModule object corresponding to a name.
+ * Registers all trajectory analysis command-line modules.
  *
- * \param[in]  name  Name of the module to create (recognized names are
- *      defined in modules.h).
- * \returns  An allocated TrajectoryAnalysisModule object.
- * \throws   InvalidInputError if \p name is not recognized.
+ * \param[in] manager  Command-line module manager to receive the modules.
+ * \throws    std::bad_alloc if out of memory.
  *
- * This function should be used to instantiate analysis methods defined in the
- * library.
- *
- * In addition to recognizing exact matches on \p name, the function also
- * identifies cases where \p name is a prefix of exactly one recognized name
- * (exact matches always take precedence).
+ * Registers all trajectory analysis modules declared in the library such that
+ * they can be run through \p manager.
  *
  * \inpublicapi
  */
-TrajectoryAnalysisModulePointer
-createTrajectoryAnalysisModule(const char *name);
-
-namespace analysismodules
-{
-
-static const char * const angle    = "angle";
-static const char * const distance = "distance";
-static const char * const select   = "select";
-
-} // namespace modules
+void registerTrajectoryAnalysisModules(CommandLineModuleManager *manager);
 
 } // namespace gmx
 
index 8c708feb962a6c73bc9ae9d401045cf8cb3f70c3..66d6c9f1fbf2bd595cff0e65febfd5d1f92cd8cf 100644 (file)
@@ -63,8 +63,10 @@ namespace gmx
 namespace analysismodules
 {
 
+const char Angle::name[] = "angle";
+
 Angle::Angle()
-    : _options("angle", "Angle calculation"),
+    : _options(name, "Angle calculation"),
       _sel1info(NULL), _sel2info(NULL),
       _bSplit1(false), _bSplit2(false), _bMulti(false), _bAll(false),
       _bDumpDist(false), _natoms1(0), _natoms2(0), _vt0(NULL)
@@ -594,13 +596,6 @@ Angle::writeOutput()
 {
 }
 
-
-TrajectoryAnalysisModulePointer
-Angle::create()
-{
-    return TrajectoryAnalysisModulePointer(new Angle());
-}
-
 } // namespace modules
 
 } // namespace gmxana
index df91f4fad9d1c3a159c65c1b8092c67ad2937d05..6b67dbb257c2cbc1b3948c9c95a1a3a6553c771d 100644 (file)
@@ -56,11 +56,11 @@ namespace analysismodules
 class Angle : public TrajectoryAnalysisModule
 {
     public:
+        static const char name[];
+
         Angle();
         virtual ~Angle();
 
-        static TrajectoryAnalysisModulePointer create();
-
         virtual Options &initOptions(TrajectoryAnalysisSettings *settings);
         virtual void initOptionsDone(TrajectoryAnalysisSettings *settings);
         virtual void initAnalysis(const TrajectoryAnalysisSettings &settings,
index 9662fa51502acba917b48faaa51b696e5b533cda..5932d66aed7aba5d05fb9126859c3e454fc9fd2a 100644 (file)
@@ -61,8 +61,10 @@ namespace gmx
 namespace analysismodules
 {
 
+const char Distance::name[] = "distance";
+
 Distance::Distance()
-    : _options("distance", "Distance calculation"), _avem(new AnalysisDataAverageModule())
+    : _options(name, "Distance calculation"), _avem(new AnalysisDataAverageModule())
 {
 }
 
@@ -158,13 +160,6 @@ Distance::writeOutput()
     fprintf(stderr, "Std. deviation:   %f\n", _avem->stddev(0));
 }
 
-
-TrajectoryAnalysisModulePointer
-Distance::create()
-{
-    return TrajectoryAnalysisModulePointer(new Distance());
-}
-
 } // namespace analysismodules
 
 } // namespace gmx
index 78e3e2196d2a16b4142ebbac1532076fecf3156c..0a1d48d43edbe1952ebab47be86d0da9af5c16b7 100644 (file)
@@ -55,11 +55,11 @@ namespace analysismodules
 class Distance : public TrajectoryAnalysisModule
 {
     public:
+        static const char name[];
+
         Distance();
         virtual ~Distance();
 
-        static TrajectoryAnalysisModulePointer create();
-
         virtual Options &initOptions(TrajectoryAnalysisSettings *settings);
         virtual void initAnalysis(const TrajectoryAnalysisSettings &settings,
                                   const TopologyInformation &top);
index c0b28372d22d5983efe0eb0d66988ee8b52c502e..42659e01f9869f9762704839e0a7ddeb993c6d5f 100644 (file)
@@ -239,8 +239,10 @@ void IndexFileWriterModule::dataFinished()
  * Select
  */
 
+const char Select::name[] = "select";
+
 Select::Select()
-    : _options("select", "Selection information"),
+    : _options(name, "Selection information"),
       _bDump(false), _bTotNorm(false), _bFracNorm(false), _bResInd(false),
       _top(NULL)
 {
@@ -520,13 +522,6 @@ Select::writeOutput()
 {
 }
 
-
-TrajectoryAnalysisModulePointer
-Select::create()
-{
-    return TrajectoryAnalysisModulePointer(new Select());
-}
-
 } // namespace analysismodules
 
 } // namespace gmx
index a31410e7f10830aecff4f91d87dc54d48df8b09e..5ab4be95a2b999755bd8af35caf8dec82a22a834 100644 (file)
@@ -55,11 +55,11 @@ namespace analysismodules
 class Select : public TrajectoryAnalysisModule
 {
     public:
+        static const char name[];
+
         Select();
         virtual ~Select();
 
-        static TrajectoryAnalysisModulePointer create();
-
         virtual Options &initOptions(TrajectoryAnalysisSettings *settings);
         virtual void initAnalysis(const TrajectoryAnalysisSettings &settings,
                                   const TopologyInformation &top);
index 762640ff671cbdc1562eb9e7d448d9f1b3f19993..bb3021f9c2a67d9bb94c5ce9412dcb1fb7ccc0d1 100644 (file)
  */
 #include "gromacs/legacyheaders/copyrite.h"
 
-#include "gromacs/trajectoryanalysis/analysismodule.h"
-#include "gromacs/trajectoryanalysis/cmdlinerunner.h"
+#include "gromacs/commandline/cmdlinemodulemanager.h"
 #include "gromacs/trajectoryanalysis/modules.h"
 #include "gromacs/utility/exceptions.h"
 
 int
 main(int argc, char *argv[])
 {
-    bool bPrintCopyrightOnError = true;
-
+    CopyRight(stderr, argv[0]);
     try
     {
-        if (argc < 2)
-        {
-            GMX_THROW(gmx::InvalidInputError("Not enough command-line arguments"));
-        }
-
-        gmx::TrajectoryAnalysisModulePointer
-            mod(gmx::createTrajectoryAnalysisModule(argv[1]));
-        --argc;
-        ++argv;
-
-        gmx::TrajectoryAnalysisCommandLineRunner runner(mod.get());
-#ifndef __clang_analyzer__  //Clang BUG: 11722
-        bPrintCopyrightOnError = false;
-#endif
-        return runner.run(argc, argv);
+        gmx::CommandLineModuleManager manager;
+        registerTrajectoryAnalysisModules(&manager);
+        return manager.run(argc, argv);
     }
     catch (const std::exception &ex)
     {
-        if (bPrintCopyrightOnError)
-        {
-            CopyRight(stderr, argv[0]);
-        }
         fprintf(stderr, "%s", gmx::formatErrorMessage(ex).c_str());
         return 1;
     }