Generalize IForceProvider
[gromacs.git] / docs / doxygen / lib / mdmodules.md
blob761329d48fbdd3d35562ee15d368f507fe57b36c
1 mdrun modules {#page_mdmodules}
2 =============
4 Currently, most of mdrun is constructed as a set of C routines calling each
5 other, and sharing data through a couple of common data structures (t_inputrec,
6 t_forcerec, t_state etc.) that flow throughout the code.
8 The electric field code (in `src/gromacs/applied-forces/`) implements an
9 alternative concept that allows keeping everything related to the electric
10 field functionality in a single place.  At least for most special-purpose
11 functionality, this would hopefully provide a more maintainable approach that
12 would also support more easily adding new functionality.  Some core features
13 may still need stronger coupling than this provides.
15 The rest of the page documents those parts of the modularity mechanism that
16 have taken a clear form.  Generalizing and designing other parts may require
17 more code to be converted to modules to have clearer requirements on what the
18 mechanism needs to support and what is the best way to express that in a
19 generally usable form.
21 Structure of a module
22 ---------------------
24 Each module implements a factory that returns an instance of gmx::IMDModule.
25 This interface has methods that in turn refer to other interfaces:
26 gmx::IMdpOptionProvider, gmx::IMDOutputProvider, and gmx::IForceProvider.
27 The module also implements these interfaces (or a subset of them), and code
28 outside the module only calls methods in these interfaces.
30 See documentation of the individual interfaces for details of what they
31 support.
33 Implementation of a module
34 --------------------------
36 Modules are constructed by composition of interfaces (i.e. abstract classes,
37 general with pure virtual methods lacking implementations), so that e.g.
38 trajectory-writing code can loop over containers of pointers to
39 gmx::IMDOutputProvider without needing to know about all the concrete types
40 that might implement that interface.
42 The module classes should not be extended by using them as a base
43 class, which is expressed with the final keyword in the class
44 definition. Generally, modules will implement different flavours of
45 functionality, perhaps based on user choices, or available computing
46 resources. This should generally be implemented by providing variable
47 behaviour for the methods that are called through the above
48 interfaces. Either code should branch at run time upon some data
49 contained by the module (e.g. read from the mdp options), or that the
50 module class should contain a pointer to an internal interface class
51 whose concrete type might be chosen during setup from the set of
52 implementations of that internal interface. Such an approach keeps
53 separate the set of interfaces characteristic of "MD modules" from
54 those that are particular to flavours of any specific module.
56 The virtual methods that the module classes inherit from their
57 interfaces should be declared as `override`, to express the intent
58 that they implement a virtual function from the interface. This
59 permits the compiler to check that this is true, e.g. if the interface
60 class changes. The `virtual` keyword should not be specified,
61 because this is redundant when `override` is used. This follows
62 the Cpp Core Guidelines (guideline C.128).
64 Handling mdp input
65 ------------------
67 To accept parameters from an mdp file, a module needs to implement
68 gmx::IMdpOptionProvider.
70 initMdpOptions() should declare the required input parameters using the options
71 module.  In most cases, the parameters should be declared as nested sections
72 instead of a flat set of options.  The structure used should be such that in
73 the future, we can get the input values from a structured mdp file (e.g., JSON
74 or XML), where the structure matches the declared options.  As with other uses
75 of the options module, the module needs to declare local variables where the
76 values from the options will be assigned.  The defined structure will also be
77 used for storing in the tpr file (see below).
79 initMdpTransform() should declare the mapping from current flat mdp format to
80 the structured format defined in initMdpOptions().  For now, this makes it
81 possible to have an internal forward-looking structured representation while
82 the input is still a flat list of values, but in the future it also allows
83 supporting both formats side-by-side as long as that is deemed necessary.
85 On the implementation side, the framework (and other code that interacts with
86 the modules) will do the following things to make mdp input work:
88 * When grompp reads the mdp file, it will first construct a flat
89   KeyValueTreeObject, where each input option is set as a property.
91   It then calls initMdpTransform() for the module(s), and uses the produced
92   transform to convert the flat tree into a structured tree, performing any
93   defined conversions in the process.  This transformation is one-way only,
94   although the framework keeps track of the origin of each value to provide
95   sensible error messages that have the original mdp option name included.
96   Because the mapping is not two-way, there is some loss of functionality
97   related to mdp file handling in grompp (in particular, the `-po` option) for
98   options belonging to the new-style modules.
100   It calls initMdpOptions() for the module(s), initializing a single Options
101   object that has the input options.
103   It processes the structured tree using the options in two steps:
105   * For any option that is not specified in the input, it adds a property to
106     the tree with a default value.  For options specified in the input, the
107     values in the tree are converted to native values for the options (e.g.,
108     from string to int for integer options).
109   * It assigns the values from the tree to the Options object.  This will make
110     the values available in the local variables the module defined in
111     initMdpOptions().
113   Note that currently, the module(s) cannot use storeIsSet() in options to know
114   whether a particular option has been provided from the mdp file.  This will
115   always return true for all the options.  This is a limitation in the current
116   implementation, but it also, in part, enforces that the mdp file written out
117   by `gmx grompp -po` cannot produce different behavior because of set/not-set
118   differences.
120 * When grompp writes the tpr file, it writes the structured tree (after the
121   default value and native value conversion) into the tpr file.
123 * When mdrun reads the tpr file, it reads the structured tree.
124   It then broadcasts the structure to all ranks.  Each rank calls
125   initMdpOptions() for the modules, and assigns the values from the tree to the
126   Options object.  After this, the modules will be exactly in the same state as
127   in grompp.
129 * When other tools (gmx dump or gmx check in particular) read the tpr file,
130   they read the structured tree.  In principle, they could operate directly on
131   this tree (and `gmx dump` in particular does, with the `-orgir` option).
132   However, in the future with proper tpr backward compatibility support, they
133   need to call to the modules to ensure that the tree has the structure that
134   this version expects, instead of what the original version that wrote the
135   file had.  Currently, these tools only call initMdpOptions() and do the basic
136   default+native value conversion.
138 * Any code that is not interested in the parameters for these modules can just
139   read the t_inputrec from the tpr file and ignore the tree.
141 * For compatibility with old tpr files that did not yet have the structured
142   tree, the I/O code converts old values for the modules to parameters in the
143   structured tree (in tpxio.cpp).
145 Currently, there is no mechanism for changing the mdp input parameters (adding
146 new or removing old ones) that would maintain tpr and mdp backward
147 compatibility.  The vision for this is to use the same transformation engine as
148 for initMdpTransform() to support specifying version-to-version conversions for
149 any changed options, and applying the necessary conversions in sequence.  The
150 main challenge is keeping track of the versions to know which conversions to
151 apply.