Add a few sequence diagrams to Doxygen docs.
authorTeemu Murtola <teemu.murtola@gmail.com>
Sun, 10 Mar 2013 18:48:02 +0000 (20:48 +0200)
committerGerrit Code Review <gerrit@gerrit.gromacs.org>
Wed, 22 May 2013 21:10:30 +0000 (23:10 +0200)
- Add detection for mscgen to be used with Doxygen.  If the tool is not
  found, the diagrams are simply not generated (missing images on the
  HTML pages).
- Add a separate wrapper script for running Doxygen to show warnings
  more clearly (in particular errors from mscgen were difficult to spot
  otherwise).  This script also prints a note if mscgen is not available
  when the documentation is built.
- Add a few sequence diagrams for the analysis framework to clarify
  interactions between parts and illustrate the parallelization design
  (although parallelization itself isn't implemented yet, it is useful
  to see the plan to fully understand the design).  Added some text to
  describe the diagrams; this could perhaps be better integrated into
  the other documentation (currently, more or less the same text may
  also be found elsewhere).
- Fix a few Doxygen issues (missing links etc.) noticed while adding the
  diagrams.

Change-Id: If26049560b8db3be1e202d0aef6e08f0db7d5e73

doxygen/CMakeLists.txt
doxygen/Doxyfile-common.cmakein
doxygen/Doxyfile-full.cmakein
doxygen/Doxyfile-lib.cmakein
doxygen/Doxyfile-user.cmakein
doxygen/RunDoxygen.cmake.cmakein [new file with mode: 0644]
src/gromacs/analysisdata.h
src/gromacs/options.h
src/gromacs/trajectoryanalysis.h

index 8b16a2866b66b278bde478a36fb03d101ef5f45a..9225a76bb201959e6cbea13df255a72223775817 100644 (file)
@@ -1,4 +1,50 @@
+#
+# This file is part of the GROMACS molecular simulation package.
+#
+# Copyright (c) 2012,2013, by the GROMACS development team, led by
+# David van der Spoel, Berk Hess, 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.
+
 find_package(Doxygen)
+if (DOXYGEN_FOUND)
+    # This logic closely follows that found in FindDoxygen.cmake for dot,
+    # except that the PATH variable is not cached.
+    FIND_PROGRAM(DOXYGEN_MSCGEN_EXECUTABLE
+        NAMES mscgen
+        DOC "Message sequence chart renderer tool (http://www.mcternan.me.uk/mscgen/)")
+    if (DOXYGEN_MSCGEN_EXECUTABLE)
+        set(DOXYGEN_MSCGEN_FOUND TRUE)
+        get_filename_component(DOXYGEN_MSCGEN_PATH "${DOXYGEN_MSCGEN_EXECUTABLE}" PATH)
+    endif (DOXYGEN_MSCGEN_EXECUTABLE)
+    mark_as_advanced(DOXYGEN_MSCGEN_EXECUTABLE)
+endif (DOXYGEN_FOUND)
 
 ########################################################################
 # Doxygen configuration
@@ -12,21 +58,24 @@ if (DOXYGEN_FOUND)
         SET(NB_KERNEL_DIRS_TO_IGNORE_IN_DOXYGEN
             "${NB_KERNEL_DIRS_TO_IGNORE_IN_DOXYGEN} \\\n                         ${NB_KERNEL_DIR}")
     ENDFOREACH(NB_KERNEL_DIR)
+    set(DOXYGEN_SECTIONS "")
     CONFIGURE_FILE(Doxyfile-common.cmakein Doxyfile-common)
     CONFIGURE_FILE(Doxyfile-full.cmakein Doxyfile-full)
     CONFIGURE_FILE(Doxyfile-lib.cmakein Doxyfile-lib)
     CONFIGURE_FILE(Doxyfile-user.cmakein Doxyfile-user)
+
     FILE(COPY index.html DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
+    configure_file(RunDoxygen.cmake.cmakein RunDoxygen.cmake @ONLY)
     add_custom_target(doc-full
-        ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile-full
+        ${CMAKE_COMMAND} -DDOCTYPE=full -P RunDoxygen.cmake
         WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
         COMMENT "Generating full documentation with Doxygen" VERBATIM)
     add_custom_target(doc-lib
-        ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile-lib
+        ${CMAKE_COMMAND} -DDOCTYPE=lib -P RunDoxygen.cmake
         WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
         COMMENT "Generating library documentation with Doxygen" VERBATIM)
     add_custom_target(doc-user
-        ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile-user
+        ${CMAKE_COMMAND} -DDOCTYPE=user -P RunDoxygen.cmake
         WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
         COMMENT "Generating user documentation with Doxygen" VERBATIM)
     add_custom_target(doc-all)
index 10686353495149b7e5ecb7f9467c37c93b9681a0..ec6d4668b982521d3b3be4ccbbeb159351f13b59 100644 (file)
@@ -19,6 +19,9 @@ INCLUDE_PATH           = @CMAKE_SOURCE_DIR@/src \
                          @CMAKE_SOURCE_DIR@/src/gromacs/legacyheaders
 HAVE_DOT               = @DOXYGEN_DOT_FOUND@
 DOT_PATH               = @DOXYGEN_DOT_PATH@
+MSCGEN_PATH            = @DOXYGEN_MSCGEN_PATH@
+
+ENABLED_SECTIONS       = @DOXYGEN_SECTIONS@
 
 # This is for thread_mpi to #ifdef some code out that should not be documented.
 PREDEFINED             = DOXYGEN
index 670a7f46ab1a316d970a5ac6b10a8465c9bd17e8..8cf48a79a24c9476b3c5dc43b162f017ef825176 100644 (file)
@@ -4,7 +4,7 @@ MACRO_EXPANSION        = YES
 EXPAND_ONLY_PREDEF     = YES
 PREDEFINED            += F77_FUNC(name,NAME)=name
 
-ENABLED_SECTIONS       = libapi internal
+ENABLED_SECTIONS      += libapi internal
 INTERNAL_DOCS          = YES
 EXTRACT_STATIC         = YES
 EXTRACT_LOCAL_CLASSES  = YES
index fdec36907e46c157ccfb0b30d3595154f07503fe..3924070d579ea605c9626c476124a76574d40cea 100644 (file)
@@ -1,6 +1,6 @@
 @INCLUDE               = Doxyfile-common
 
-ENABLED_SECTIONS       = libapi
+ENABLED_SECTIONS      += libapi
 INTERNAL_DOCS          = NO
 HIDE_UNDOC_CLASSES     = YES
 WARN_LOGFILE           = doxygen-lib.log
index 891cfe847c6a6b71f615b5a3627bc108e8bab001..14f9da3b9827279b90793703fb1b25712fd66fb8 100644 (file)
@@ -1,6 +1,5 @@
 @INCLUDE               = Doxyfile-common
 
-ENABLED_SECTIONS       =
 INTERNAL_DOCS          = NO
 HIDE_UNDOC_CLASSES     = YES
 HIDE_FRIEND_COMPOUNDS  = YES
diff --git a/doxygen/RunDoxygen.cmake.cmakein b/doxygen/RunDoxygen.cmake.cmakein
new file mode 100644 (file)
index 0000000..e5dc3cd
--- /dev/null
@@ -0,0 +1,53 @@
+#
+# This file is part of the GROMACS molecular simulation package.
+#
+# Copyright (c) 2013, by the GROMACS development team, led by
+# David van der Spoel, Berk Hess, 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(DOXYGEN_EXECUTABLE   @DOXYGEN_EXECUTABLE@)
+set(DOXYGEN_MSCGEN_FOUND @DOXYGEN_MSCGEN_FOUND@)
+
+message("Running Doxygen...")
+# The standard output shows a lot of progress information, but obscures errors
+# that may appear.  CMake-introduced buffering also makes it appear sluggish,
+# so disable it.
+execute_process(COMMAND ${DOXYGEN_EXECUTABLE} Doxyfile-${DOCTYPE}
+                OUTPUT_QUIET)
+file(READ doxygen-${DOCTYPE}.log DOXYGEN_WARNINGS)
+string(STRIP "${DOXYGEN_WARNINGS}" DOXYGEN_WARNINGS)
+if (DOXYGEN_WARNINGS)
+    message("The following warnings were produced by Doxygen:")
+    message(${DOXYGEN_WARNINGS})
+endif ()
+if (NOT DOXYGEN_MSCGEN_FOUND)
+    message("NOTE: mscgen was not available. "
+            "Please install it to produce graphs in the documentation.")
+endif ()
index 88351b464e291a3c507b239e9c50912c34f483a2..e24be8b00f7cb25f988022b38319f7df2e1d4c60 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2012, by the GROMACS development team, led by
+ * Copyright (c) 2010,2012,2013, by the GROMACS development team, led by
  * David van der Spoel, Berk Hess, Erik Lindahl, and including many
  * others, as listed in the AUTHORS file in the top-level source
  * directory and at http://www.gromacs.org.
@@ -32,7 +32,7 @@
  * 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_analysisdata Parallelizable Handling of Output Data
+/*! \defgroup module_analysisdata Parallelizable Handling of Output Data (analysisdata)
  * \ingroup group_analysismodules
  * \brief
  * Provides functionality for handling and processing output data from
  * frames is collected and output in the correct order.
  *
  * This module consists of two main parts.  The first is formed by the
- * AbstractAnalysisData class and classes that derive from it:
- * AnalysisData and AnalysisArrayData.  These classes are used to process and
- * store raw data as produced by the analysis tool.  They also provide an
- * interface to attach data modules that implement AnalysisDataModuleInterface.
+ * gmx::AbstractAnalysisData class and classes that derive from it:
+ * gmx::AnalysisData and gmx::AnalysisArrayData.  These classes are used to
+ * process and store raw data as produced by the analysis tool.  They also
+ * provide an interface to attach data modules that implement
+ * gmx::AnalysisDataModuleInterface.
  * Modules that implement this interface form the second part of the module,
  * and they provide functionality to do processing operations on the data.
- * These modules can also derive from AbstractAnalysisData, allowing other
+ * These modules can also derive from gmx::AbstractAnalysisData, allowing other
  * modules to be attached to them to form a processing chain that best suits
  * the analysis tool.  Typically, such a processing chain ends in a plotting
  * module that writes the data into a file, but the final module can also
  * provide direct access to the processed data, allowing the analysis tool to
  * do custom postprocessing outside the module framework.
  *
+ * The sequence chart below shows an overview of how analysis data objects
+ * and modules interact (currently, multipoint data is an exception to this
+ * diagram).
+ * \msc
+ *     caller,
+ *     data [ label="AnalysisData", URL="\ref gmx::AnalysisData" ],
+ *     module1 [ label="data module", URL="\ref gmx::AnalysisDataModuleInterface" ];
+ *
+ *     caller box module1 [ label="caller creates and initializes all objects" ];
+ *     caller => data [ label="addModule(module1)",
+ *                      URL="\ref gmx::AbstractAnalysisData::addModule() " ];
+ *     caller => data [ label="startData()",
+ *                      URL="\ref gmx::AnalysisData::startData()" ];
+ *     data => module1 [ label="dataStarted()",
+ *                       URL="\ref gmx::AnalysisDataModuleInterface::dataStarted()" ];
+ *     caller << data [ label="handle",
+ *                      URL="\ref gmx::AnalysisDataHandle" ];
+ *     caller => data [ label="handle->startFrame(0)",
+ *                      URL="\ref gmx::AnalysisDataHandle::startFrame()" ];
+ *     caller => data [ label="add data for frame 0",
+ *                      URL="\ref gmx::AnalysisDataHandle" ];
+ *     caller => data [ label="handle->finishFrame() (frame 0)",
+ *                      URL="\ref gmx::AnalysisDataHandle::finishFrame()" ];
+ *     data => module1 [ label="frameStarted(0)",
+ *                       URL="\ref gmx::AnalysisDataModuleInterface::frameStarted()" ];
+ *     data => module1 [ label="pointsAdded()",
+ *                       URL="\ref gmx::AnalysisDataModuleInterface::pointsAdded()" ];
+ *     data => module1 [ label="frameFinished(0)",
+ *                       URL="\ref gmx::AnalysisDataModuleInterface::frameFinished()" ];
+ *     caller => data [ label="handle->startFrame(1)",
+ *                      URL="\ref gmx::AnalysisDataHandle::startFrame()" ];
+ *     caller => data [ label="add data for frame 1",
+ *                      URL="\ref gmx::AnalysisDataHandle" ];
+ *     caller => data [ label="handle2->finishFrame() (frame 1)",
+ *                      URL="\ref gmx::AnalysisDataHandle::finishFrame()" ];
+ *     data => module1 [ label="process frame 1" ];
+ *     ... [ label="add more frames" ];
+ *     caller => data [ label="handle->finishData()",
+ *                      URL="\ref gmx::AnalysisDataHandle::finishData()" ];
+ *     data => module1 [ label="dataFinished()",
+ *                       URL="\ref gmx::AnalysisDataModuleInterface::dataFinished()" ];
+ * \endmsc
+ *
+ * The second sequence chart below shows the interaction in the case of two
+ * gmx::AnalysisDataHandle objects, which can be used to insert data
+ * concurrently for multiple frames.  The gmx::AnalysisData object and the
+ * handles take care to notify the module such that it always receives the
+ * frames in the correct order.
+ * \msc
+ *     caller,
+ *     handle1 [ label="handle1", URL="\ref gmx::AnalysisDataHandle" ],
+ *     handle2 [ label="handle2", URL="\ref gmx::AnalysisDataHandle" ],
+ *     module1 [ label="data module", URL="\ref gmx::AnalysisDataModuleInterface" ];
+ *
+ *     caller box handle2 [ label="caller has created both handles using startData()" ];
+ *     caller => handle1 [ label="startFrame(0)",
+ *                         URL="\ref gmx::AnalysisDataHandle::startFrame()" ];
+ *     caller => handle2 [ label="startFrame(1)",
+ *                         URL="\ref gmx::AnalysisDataHandle::startFrame()" ];
+ *     caller => handle1 [ label="add data for frame 0",
+ *                         URL="\ref gmx::AnalysisDataHandle" ];
+ *     caller => handle2 [ label="add data for frame 1",
+ *                         URL="\ref gmx::AnalysisDataHandle" ];
+ *     caller => handle2 [ label="finishFrame() (frame 1)",
+ *                         URL="\ref gmx::AnalysisDataHandle::finishFrame()" ];
+ *     caller => handle2 [ label="startFrame(2)",
+ *                         URL="\ref gmx::AnalysisDataHandle::startFrame()" ];
+ *     caller => handle1 [ label="finishFrame() (frame 0)",
+ *                         URL="\ref gmx::AnalysisDataHandle::finishFrame()" ];
+ *     handle1 => module1 [ label="process frame 0" ];
+ *     handle1 => module1 [ label="process frame 1" ];
+ *     caller => handle2 [ label="add data for frame 2",
+ *                         URL="\ref gmx::AnalysisDataHandle" ];
+ *     caller => handle2 [ label="finishFrame() (frame 2)",
+ *                         URL="\ref gmx::AnalysisDataHandle::finishFrame()" ];
+ *     handle2 => module1 [ label="process frame 2" ];
+ *     ...;
+ *     caller => handle1 [ label="finishData()",
+ *                         URL="\ref gmx::AnalysisDataHandle::finishData()" ];
+ *     caller => handle2 [ label="finishData()",
+ *                         URL="\ref gmx::AnalysisDataHandle::finishData()" ];
+ *     handle2 => module1 [ label="dataFinished()",
+ *                          URL="\ref gmx::AnalysisDataModuleInterface::dataFinished()" ];
+ * \endmsc
+ *
  * <H3>Using Data Objects and Modules</H3>
  *
  * To use the functionality in this module, you typically declare one or more
  * AnalysisData objects and set its properties.  You then create some module
  * objects and set their properties (see the list of classes that implement
- * AnalysisDataModuleInterface) and attach them to the data objects or to one
- * another using AbstractAnalysisData::addModule().  Then you add the actual
- * data values to the AnalysisData object, which automatically passes it on to
- * the modules.  After all data is added, you may optionally access some
+ * gmx::AnalysisDataModuleInterface) and attach them to the data objects or to
+ * one another using gmx::AbstractAnalysisData::addModule().  Then you add the
+ * actual data values to the gmx::AnalysisData object, which automatically
+ * passes it on to the modules.
+ * After all data is added, you may optionally access some
  * results directly from the module objects.  However, in many cases it is
  * sufficient to initially add a plotting module to the processing chain, which
  * will then automatically write the results into a file.
  *
  * For simple processing needs with a small amount of data, an
- * AnalysisArrayData class is also provided, which keeps all the data in an
+ * gmx::AnalysisArrayData class is also provided, which keeps all the data in an
  * in-memory array and allows you to manipulate the data as you wish before you
  * pass the data to the attached modules.
  *
  *
  * New data modules can be implemented to perform custom operations that are
  * not supported by the modules provided in this module.  This is done by
- * creating a new class that implements AnalysisDataModuleInterface.
+ * creating a new class that implements gmx::AnalysisDataModuleInterface.
  * If the new module computes values that can be used as input for other
- * modules, the new class should also derive from AbstractAnalysisData, and
- * preferably use AnalysisDataStorage internally to implement storage of
+ * modules, the new class should also derive from gmx::AbstractAnalysisData, and
+ * preferably use gmx::AnalysisDataStorage internally to implement storage of
  * values.  See the documentation of the mentioned classes for more details on
  * how to implement custom modules.
  * When implementing a new module, it should be considered whether it can be of
  * more general use, and if so, it should be added to this module.
  *
  * It is also possible to implement new data source objects by deriving a class
- * from AbstractAnalysisData.  This should not normally be necessary, since
+ * from gmx::AbstractAnalysisData.  This should not normally be necessary, since
  * this module provides general data source objects for most typical uses.
  * If the classes in this module are not suitable for some specific use, it
  * should be considered whether a new generic class could be added (or an
index 1e2d48292a613a6f1969596481726ad0bee1c9d2..4f9fece659c9cc433bfb1faf4314c56455155e34 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2010,2011,2012, by the GROMACS development team, led by
+ * Copyright (c) 2010,2011,2012,2013, by the GROMACS development team, led by
  * David van der Spoel, Berk Hess, Erik Lindahl, and including many
  * others, as listed in the AUTHORS file in the top-level source
  * directory and at http://www.gromacs.org.
@@ -32,7 +32,7 @@
  * 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_options Extensible Handling of Options
+/*! \defgroup module_options Extensible Handling of Options (options)
  * \ingroup group_utilitymodules
  * \brief
  * Provides functionality for handling options.
  * descriptions for individual options as well as for the whole set of options.
  * These can then be used to write out help text.
  *
+ * The sequence charts below provides an overview of how the options work from
+ * usage perspective.  They include two fictional modules, A and B, that provide
+ * options, and a main routine that manages these.  The first chart shows a
+ * typical initialization sequence, where the main routine creates an options
+ * object, and calls an initOptions() method in each module that can provide
+ * options (the modules may also request their submodules to add their own
+ * options).  Each module uses gmx::Options::addOption() to add the options
+ * they require, and specify output variables into which the options values are
+ * stored.
+ * \msc
+ *     main,
+ *     options [ label="Options", URL="\ref gmx::Options" ],
+ *     A [ label="module A" ],
+ *     B [ label="module B" ];
+ *
+ *     main box B [ label="main owns all objects" ];
+ *     main => options [ label="create", URL="\ref gmx::Options::Options()" ];
+ *     main => A [ label="initOptions()" ];
+ *     A => options [ label="addOption()", URL="\ref gmx::Options::addOption()" ];
+ *     ...;
+ *     main << A;
+ *     main => B [ label="initOptions()" ];
+ *     B => options [ label="addOption()", URL="\ref gmx::Options::addOption()" ];
+ *     ...;
+ *     main << B;
+ * \endmsc
+ *
+ * After all options have been specified, they can be parsed.  A parser splits
+ * the input into option-value pairs (one option may have multiple values), and
+ * passes these into the gmx::Options object, which is responsible for
+ * converting them into the appropriate types and storing the values into the
+ * variables provided in the calls to gmx::Options::addOption().
+ * \msc
+ *     main,
+ *     parser [ label="parser" ],
+ *     options [ label="Options", URL="\ref gmx::Options" ],
+ *     A [ label="module A" ],
+ *     B [ label="module B" ];
+ *
+ *     main => parser [ label="parse()" ];
+ *     parser => options [ label="assign(string)" ];
+ *     options -> A [ label="set variable" ];
+ *     parser => options [ label="assign(string)" ];
+ *     options -> B [ label="set variable" ];
+ *     ...;
+ * \endmsc
+ *
+ * After all options have been parsed (possibly using multiple different
+ * parsers), gmx::Options::finish() is called.  This performs final
+ * validation of the options and may further adjust the values stored in the
+ * output variables (see documentation on individual option types on when this
+ * may happen).
+ * \msc
+ *     main,
+ *     options [ label="Options", URL="\ref gmx::Options" ],
+ *     A [ label="module A" ],
+ *     B [ label="module B" ];
+ *
+ *     main => options [ label="finish()", URL="\ref gmx::Options::finish()" ];
+ *     options -> A [ label="set variable" ];
+ *     options -> B [ label="set variable" ];
+ *     ...;
+ * \endmsc
+ *
  * Module \ref module_commandline implements classes that assign option values
  * from command line and produce help for programs that use the command line
  * parser.
index ccc8bc0544199817e4e268f2f59a6a05f86c310b..29194e851a37f50182d91a1997ccd8a9a9babe59 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * This file is part of the GROMACS molecular simulation package.
  *
- * Copyright (c) 2011,2012, by the GROMACS development team, led by
+ * Copyright (c) 2011,2012,2013, by the GROMACS development team, led by
  * David van der Spoel, Berk Hess, Erik Lindahl, and including many
  * others, as listed in the AUTHORS file in the top-level source
  * directory and at http://www.gromacs.org.
@@ -32,7 +32,7 @@
  * 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_trajectoryanalysis Framework for Trajectory Analysis
+/*! \defgroup module_trajectoryanalysis Framework for Trajectory Analysis (trajectoryanalysis)
  * \ingroup group_analysismodules
  * \brief
  * Provides functionality for implementing trajectory analysis modules.
  * be used in advanced scenarios where the tool requires custom thread-local
  * data for parallel analysis.
  *
+ * The sequence charts below provides an overview of how the trajectory
+ * analysis modules typically interact with other components.
+ * The first chart provides an overview of the call sequence of the most
+ * important methods in gmx::TrajectoryAnalysisModule.
+ * There is a runner, which is responsible for doing the work that is shared
+ * between all trajectory analysis (such as reading the trajectory and
+ * processing selections).  The runner then calls different methods in the
+ * analysis module at appropriate points to perform the module-specific tasks.
+ * The analysis module is responsible for creating and managing
+ * gmx::AnalysisData objects, and the chart shows the most important
+ * interactions with this module as well.  Interactions with options (for
+ * command-line option processing) and selections is not shown for brevity: see
+ * \ref module_options for an overview of how options work, and the second
+ * chart for a more detailed view of how selections are accessed from an
+ * analysis module.
+ * \msc
+ *     runner,
+ *     module [ URL="\ref gmx::TrajectoryAnalysisModule" ],
+ *     data [ label="analysis data", URL="\ref module_analysisdata" ];
+ *
+ *     runner box module [ label="caller owns runner and module objects" ];
+ *     module => data [ label="create (in constructor)" ];
+ *     runner => module [ label="initOptions()",
+ *                        URL="\ref gmx::TrajectoryAnalysisModule::initOptions()" ];
+ *     runner => runner [ label="parse user input" ];
+ *     runner => module [ label="optionsFinished()",
+ *                        URL="\ref gmx::TrajectoryAnalysisModule::optionsFinished()" ];
+ *     runner => runner [ label="initialize topology\nand selections" ];
+ *     runner => module [ label="initAnalysis()",
+ *                        URL="\ref gmx::TrajectoryAnalysisModule::initAnalysis()" ];
+ *     module => data [ label="initialize" ];
+ *     runner => runner [ label="read frame 0" ];
+ *     runner => module [ label="initAfterFirstFrame()",
+ *                        URL="\ref gmx::TrajectoryAnalysisModule::initAfterFirstFrame()" ];
+ *     --- [ label="loop over frames starts" ];
+ *     runner => runner [ label="initialize frame 0" ];
+ *     runner => module [ label="analyzeFrame(0)",
+ *                        URL="\ref gmx::TrajectoryAnalysisModule::analyzeFrame()" ];
+ *     module => data [ label="add data",
+ *                      URL="\ref gmx::AnalysisDataHandle" ];
+ *     module => data [ label="finishFrame()",
+ *                      URL="\ref gmx::AnalysisDataHandle::finishFrame()" ];
+ *     data => data [ label="process frame 0" ];
+ *     runner => runner [ label="read and initialize frame 1" ];
+ *     runner => module [ label="analyzeFrame(1)",
+ *                         URL="\ref gmx::TrajectoryAnalysisModule::analyzeFrame()" ];
+ *     ...;
+ *     --- [ label="loop over frames ends" ];
+ *     runner => module [ label="finishAnalysis()",
+ *                        URL="\ref gmx::TrajectoryAnalysisModule::finishAnalysis()" ];
+ *     module => data [ label="post-process data" ];
+ *     runner => module [ label="writeOutput()",
+ *                        URL="\ref gmx::TrajectoryAnalysisModule::writeOutput()" ];
+ * \endmsc
+ *
+ * The second chart below shows the interaction with selections and options
+ * with focus on selection options.  The gmx::TrajectoryAnalysisModule object
+ * creates one or more gmx::Selection variables, and uses gmx::SelectionOption
+ * to indicate them as the destination for selections.  This happens in
+ * gmx::TrajectoryAnalysisModule::initOptions().  After the options have been
+ * parsed (includes parsing any options present on the command-line or read
+ * from files, but not those provided interactively),
+ * gmx::TrajectoryAnalysisModule::optionsFinished() can adjust the selections
+ * using gmx::SelectionOptionInfo.  This is done like this to allow the
+ * analysis module to influence the interactive prompt of selections based on
+ * what command-line options were given.  After optionsFinished() returns, the
+ * interactive selection prompt is presented if necessary.  After this point,
+ * all access to selections from the analysis module is through the
+ * gmx::Selection variables: the runner is responsible for calling methods in
+ * the selection library, and these methods update the content referenced by
+ * the gmx::Selection variables.  See documentation of
+ * gmx::TrajectoryAnalysisModule for details of what the selections contain at
+ * each point.
+ * \msc
+ *     runner,
+ *     options [ label="Options", URL="\ref module_options" ],
+ *     selection [ label="selections", URL="\ref module_selection" ],
+ *     module [ label="module", URL="\ref gmx::TrajectoryAnalysisModule" ];
+ *
+ *     runner box selection [ label="all these objects are owned by the framework" ];
+ *     runner => module [ label="initOptions()",
+ *                        URL="\ref gmx::TrajectoryAnalysisModule::initOptions()" ];
+ *     module => options [ label="addOption(SelectionOption)",
+ *                         URL="\ref gmx::SelectionOption" ];
+ *     module => options [ label="addOption() (other options)",
+ *                         URL="\ref gmx::Options::addOption()" ];
+ *     ...;
+ *     runner << module;
+ *     runner => options [ label="parse command-line parameters" ];
+ *     options => selection [ label="parse selections" ];
+ *     selection -> module [ label="initialize Selection variables",
+ *                           URL="\ref gmx::Selection" ];
+ *     runner << options;
+ *     runner => module [ label="optionsFinished()",
+ *                        URL="\ref gmx::TrajectoryAnalysisModule::optionsFinished()" ];
+ *     module => selection [ label="adjust SelectionOptions",
+ *                           URL="\ref gmx::SelectionOptionInfo" ];
+ *     runner << module;
+ *     runner => selection [ label="prompt missing selections" ];
+ *     selection -> module [ label="initialize Selection variables",
+ *                         URL="\ref gmx::Selection" ];
+ *     runner => selection [ label="compile selections" ];
+ *     selection -> module [ label="change content referenced\nby Selection variables" ];
+ *     runner => module [ label="initAnalysis()",
+ *                        URL="\ref gmx::TrajectoryAnalysisModule::initAnalysis()" ];
+ *     ...;
+ *     --- [ label="loop over frames starts" ];
+ *     runner => runner [ label="read and initialize frame 0" ];
+ *     runner => selection [ label="evaluate selections for frame 0" ];
+ *     selection -> module [ label="change content referenced\nby Selection variables" ];
+ *     ...;
+ * \endmsc
+ *
+ * The final chart shows the flow within the frame loop in the case of parallel
+ * (threaded) execution and the interaction with the \ref module_analysisdata
+ * module in this case.  Although parallelization has not yet been implemented,
+ * it has influenced the design and needs to be understood if one wants to
+ * write modules that can take advantage of the parallelization once it gets
+ * implemented.  The parallelization takes part over frames: analyzing a single
+ * frame is one unit of work.  When the frame loop is started,
+ * gmx::TrajectoryAnalysisModule::startFrames() is called for each thread, and
+ * initializes an object that contains thread-local data needed during the
+ * analysis.  This includes selection information, gmx::AnalysisDataHandle
+ * objects, and possibly other module-specific variables.  Then, the runner
+ * reads the frames in sequence and passes the work into the different threads,
+ * together with the appropriate thread-local data object.
+ * The gmx::TrajectoryAnalysisModule::analyzeFrame() calls are only allowed to modify
+ * the thread-local data object; everything else is read-only.  For any output,
+ * they pass the information to gmx::AnalysisData, which takes care of ordering
+ * the data from different frames such that it gets processed in the right
+ * order.
+ * When all frames are analyzed, gmx::TrajectoryAnalysisModule::finishFrames()
+ * is called for each thread-local data object to destroy them and to
+ * accumulate possible results from them into the main
+ * gmx::TrajectoryAnalysisModule object.
+ * Note that in the diagram, some part of the work attributed for the runner
+ * (e.g., evaluating selections) will actually be carried out in the analysis
+ * threads before gmx::TrajectoryAnalysisModule::analyzeFrame() gets called.
+ * \msc
+ *     runner,
+ *     module [ label="module object" ],
+ *     thread1 [ label="analysis\nthread 1" ],
+ *     thread2 [ label="analysis\nthread 2" ],
+ *     data [ label="analysis data", URL="\ref module_analysisdata" ];
+ *
+ *     module box thread2 [ label="single TrajectoryAnalysisModule object",
+ *                          URL="\ref gmx::TrajectoryAnalysisModule" ];
+ *     ...;
+ *     --- [ label="loop over frames starts" ];
+ *     runner => thread1 [ label="startFrames()",
+ *                         URL="\ref gmx::TrajectoryAnalysisModule::startFrames()" ];
+ *     thread1 => data [ label="startData()",
+ *                       URL="\ref gmx::AnalysisData::startData()" ];
+ *     runner << thread1 [ label="pdata1" ];
+ *     runner => thread2 [ label="startFrames()",
+ *                         URL="\ref gmx::TrajectoryAnalysisModule::startFrames()" ];
+ *     thread2 => data [ label="startData()",
+ *                       URL="\ref gmx::AnalysisData::startData()" ];
+ *     runner << thread2 [ label="pdata2" ];
+ *     |||;
+ *     runner => runner [ label="initialize frame 0" ];
+ *     runner => thread1 [ label="analyzeFrame(0, pdata1)",
+ *                         URL="\ref gmx::TrajectoryAnalysisModule::analyzeFrame()" ];
+ *     runner => runner [ label="read and initialize frame 1" ];
+ *     runner => thread2 [ label="analyzeFrame(1, pdata2)",
+ *                         URL="\ref gmx::TrajectoryAnalysisModule::analyzeFrame()" ];
+ *     thread1 => data [ label="add data",
+ *                       URL="\ref gmx::AnalysisDataHandle" ];
+ *     thread2 => data [ label="add data",
+ *                       URL="\ref gmx::AnalysisDataHandle" ];
+ *     thread2 => data [ label="finishFrame(1)",
+ *                       URL="\ref gmx::AnalysisDataHandle::finishFrame()" ];
+ *     runner << thread2 [ label="analyzeFrame() (frame 1)" ];
+ *     runner => runner [ label="read and initialize frame 2" ];
+ *     runner => thread2 [ label="analyzeFrame(2)",
+ *                         URL="\ref gmx::TrajectoryAnalysisModule::analyzeFrame()" ];
+ *     thread1 => data [ label="finishFrame(0)",
+ *                       URL="\ref gmx::AnalysisDataHandle::finishFrame()" ];
+ *     data => data [ label="process frame 0" ];
+ *     data => data [ label="process frame 1" ];
+ *     runner << thread1 [ label="analyzeFrame() (frame 0)" ];
+ *     ...;
+ *     runner => thread1 [ label="finishFrames(pdata1)",
+ *                         URL="\ref gmx::TrajectoryAnalysisModule::finishFrames()" ];
+ *     thread1 => data [ label="finishData()",
+ *                       URL="\ref gmx::AnalysisData::finishData()" ];
+ *     thread1 -> module [ label="accumulate results" ];
+ *     runner << thread1;
+ *     runner => thread2 [ label="finishFrames(pdata2)",
+ *                         URL="\ref gmx::TrajectoryAnalysisModule::finishFrames()" ];
+ *     thread2 => data [ label="finishData()",
+ *                       URL="\ref gmx::AnalysisData::finishData()" ];
+ *     thread2 -> module [ label="accumulate results" ];
+ *     runner << thread2;
+ *     --- [ label="loop over frames ends" ];
+ *     ...;
+ * \endmsc
+ *
  * In addition to the framework for defining analysis modules, this module also
  * provides gmx::TrajectoryAnalysisCommandLineRunner, which implements a
  * command-line program that runs a certain analysis module.
  *
  * Internally, the module also defines a set of trajectory analysis modules that
- * can be instantiated using createTrajectoryAnalysisModule().
+ * can currently be accessed only through gmx::registerTrajectoryAnalysisModules.
  *
  * For an example of how to implement an analysis tool using the framework, see
  * \ref template.cpp.