a531b5a1b5957b0c8f3a28a2a3c974aa667dc155
[alexxy/gromacs.git] / docs / doxygen / lib / mdmodules.md
1 mdrun modules {#page_mdmodules}
2 =============
3
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.
7
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.
14
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.
20
21 Structure of a module
22 ---------------------
23
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.
29
30 See documentation of the individual interfaces for details of what they
31 support.
32
33 Implementation of a module
34 --------------------------
35
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.
41
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 behavior 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.
55
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).
63
64 Handling mdp input
65 ------------------
66
67 To accept parameters from an mdp file, a module needs to implement
68 gmx::IMdpOptionProvider.
69
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).
78
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.
84
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:
87
88 * When grompp reads the mdp file, it will first construct a flat
89   KeyValueTreeObject, where each input option is set as a property.
90
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
97   It calls initMdpOptions() for the module(s), initializing a single Options
98   object that has the input options.
99
100   It processes the structured tree using the options in two steps:
101
102   * For any option that is not specified in the input, it adds a property to
103     the tree with a default value.  For options specified in the input, the
104     values in the tree are converted to native values for the options (e.g.,
105     from string to int for integer options).
106   * It assigns the values from the tree to the Options object.  This will make
107     the values available in the local variables the module defined in
108     initMdpOptions().
109
110   Note that currently, the module(s) cannot use storeIsSet() in options to know
111   whether a particular option has been provided from the mdp file.  This will
112   always return true for all the options.  This is a limitation in the current
113   implementation, but it also, in part, enforces that the mdp file written out
114   by `gmx grompp -po` cannot produce different behavior because of set/not-set
115   differences.
116
117 * grompp -po writes an mdp file that was equivalent to the input,
118   which is implemented by calling buildMdpOutput() for each module, to
119   prepare a builder object that is used with writeKeyValueTreeAsMdp().
120   As with the old flat tree, the values given by the user's input are
121   preserved, but not the ordering of options, or their formatting.
122
123 * When grompp writes the tpr file, it writes the structured tree (after the
124   default value and native value conversion) into the tpr file.
125
126 * When mdrun reads the tpr file, it reads the structured tree.
127   It then broadcasts the structure to all ranks.  Each rank calls
128   initMdpOptions() for the modules, and assigns the values from the tree to the
129   Options object.  After this, the modules will be exactly in the same state as
130   in grompp.
131
132 * When other tools (gmx dump or gmx check in particular) read the tpr file,
133   they read the structured tree.  In principle, they could operate directly on
134   this tree (and `gmx dump` in particular does, with the `-orgir` option).
135   However, in the future with proper tpr backward compatibility support, they
136   need to call to the modules to ensure that the tree has the structure that
137   this version expects, instead of what the original version that wrote the
138   file had.  Currently, these tools only call initMdpOptions() and do the basic
139   default+native value conversion.
140
141 * Any code that is not interested in the parameters for these modules can just
142   read the t_inputrec from the tpr file and ignore the tree.
143
144 * For compatibility with old tpr files that did not yet have the structured
145   tree, the I/O code converts old values for the modules to parameters in the
146   structured tree (in tpxio.cpp).
147
148 Currently, there is no mechanism for changing the mdp input parameters (adding
149 new or removing old ones) that would maintain tpr and mdp backward
150 compatibility.  The vision for this is to use the same transformation engine as
151 for initMdpTransform() to support specifying version-to-version conversions for
152 any changed options, and applying the necessary conversions in sequence.  The
153 main challenge is keeping track of the versions to know which conversions to
154 apply.
155
156 Callbacks to modules during setup and simulation
157 ------------------------------------------------
158
159 During setup and simulation, modules receive required information like topologies
160 and local atom sets by subscribing to callback functions.
161
162 To include a notification for your module,  
163
164 * Add the function signature for the callback function to the `notifier_type`
165   in the MdModules class
166
167   ```C++
168     notifier_type = registerMdModuleNotification<...,
169                       YourCallbackSignature,
170                       ...,
171   ```
172
173   (keep alphabetical order for ease of git merge)
174
175 * Hand the notifier_ member of the MdModules Implementation class to your
176   builder createYourModule(&notifier_)
177
178 * Add the function you want to subscribe with in the builder,
179   `notifier->subscribe(yourFunction)`
180   
181   * To subscribe class member functions of your module, you can use lambda expressions
182
183   ```C++
184     notifier->subscribe([modulePointer = yourModule.get()]
185       (YourCallbackSignature argument){modulePointer(argument);});
186   ```
187
188 * During setup in , e.g., within `Mdrunner` use
189
190   ```C++
191     YourCallbackSignature argument();
192     mdModules_.notifier().notify(argument);
193   ```
194
195 Storing non-mdp option module parameters
196 ----------------------------------------
197
198 Some mdrun modules want to store data that is non-mdp input, e.g., the result of
199 computation during setup. Atom indices of index groups are one example:
200 they are evaluated from strings during grompp time and stored as list of
201 integers in the run input file. During the mdrun setup the information to
202 evaluate the index groups is no longer available.
203
204 To store parameters, subscribe to the `KeyValueTreeBuilder*` notification that
205 provides a handle to a KeyValueTreeBuilder that allows adding own information to
206 that tree.
207
208 To restore parameters, subscribe to the `const KeyValueTreeObject &`
209 notification that returns the tree that is build by the KeyValueTreeBuilder*.